/* Design tokens — Linear 設計語言 × CRA 識別。
   深色＝暖炭黑 canvas＋亮金 #e8be06 為唯一彩色重點；淺色＝冷灰白＋薰衣草藍 #5e6ad2
   （2026-09-01：淺色金色版偏費力，回退回藍白）。層次靠 hairline 邊框而非陰影，標題負字距。 */
:root {
  color-scheme: dark;              /* 讓 select/checkbox/scrollbar/dialog 原生走深色 */

  /* Surface ladder（canvas → surface-1..3）— 暖炭黑而非冷藍黑，維持 ~+7 明度階梯。
     暖中性刻意偏向品牌金（暖色），讓金黃重點色坐得住＝法遵儀表的權威感（非 AI 慣用冷黑）。 */
  --bg: #17150f;
  --panel: #201d16;
  --panel-2: #29251c;             /* hover / featured 抬升 */
  --panel-3: #322d22;             /* 下拉 / 巢狀 */

  /* Text（ink 階梯）— 暖米白，非冷白 */
  --text: #f4f1ea;
  --muted: #a49b88;               /* ink-subtle（暖灰，灰底上對比 ~5.9:1） */
  --muted-2: #ddd6c7;             /* ink-muted（次級強調） */
  --line: #37322a;                /* hairline（暖面板上需更亮才看得見） */
  --line-strong: #4a4335;

  /* 深色模式品牌色＝政勤 logo 金黃（唯一彩色重點：品牌/CTA/focus/連結）。淺色模式改回薰衣草藍。 */
  --primary: #e8be06;
  --primary-dark: #c9a406;         /* pressed / focus tint */
  --primary-hover: #f5cf3a;
  --primary-bg: rgba(232,190,6,.14);
  --on-primary: #17150f;           /* 疊在 --primary 上的文字色：金黃底用深暖墨（淺色藍底則覆寫為白） */

  /* 語意色（Linear 產品調色盤，深色微調）。狀態三色＝正常 --green／注意 --amber／錯誤 --red（未知＝--muted），
     深淺兩組都要彼此分得開（CIEDE2000：深色 綠↔橘 46、橘↔紅 28、橘↔品牌金 19；淺色 綠↔琥珀 36、琥珀↔紅 26）。 */
  --green: #4cb782;  --green-bg: rgba(39,166,68,.14);
  --red: #eb5757;    --red-bg: rgba(235,87,87,.13);
  /* 注意＝橘（2026-10-02）。原本為了不跟品牌金「兩黃相撞」改成藍綠 #2dd4bf，結果跟正常的綠只差 ΔE 13＝
     系統健康「Gemini 金鑰 注意」看起來像正常（2026-10-01 管理員實測）。橘離金、紅、綠都夠遠；名稱沿用免動呼叫端。 */
  --amber: #ff9f43;  --amber-bg: rgba(255,159,67,.13);
  /* AML 語意色：深色＝政勤 logo 藍（提亮以在深底可見）；淺色主題覆寫回原本的紅（見下） */
  --aml: #4a9fd8;  --aml-bg: rgba(74,159,216,.14);
  --amber-line: rgba(255,159,67,.38);   /* 警示邊框：深色＝橘邊、淺色覆寫回原黃 */

  /* Type scale — rem 化以支援 Dynamic Type / 瀏覽器字型縮放（÷16；16px 預設下像素等值）。
     字級一律走這些 token，讓使用者放大字型時整站文字隨之縮放；版面 spacing/radius 仍用 px。 */
  --fs-display: 2.125rem;   /* 34px */
  --fs-h1: 1.75rem;         /* 28px */
  --fs-h2: 1.375rem;        /* 22px */
  --fs-h3: 1.125rem;        /* 18px */
  --fs-body: 1rem;          /* 16px（Notion-lean：提升 body 讀感，2026-09-14） */
  --fs-md: 0.875rem;        /* 14px（卡片／面板小標、次要說明。2026-09-23 補這一階＝原本 13→16 中間是空的，
                               大家只好各寫 .85/.875/.88/.9rem，全站因此飄出 23 種字級） */
  --fs-sm: 0.8125rem;       /* 13px */
  --fs-xs: 0.75rem;         /* 12px（body 文字下限） */

  /* Spacing (4/8px grid) */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 16px; --sp-4: 24px; --sp-5: 32px; --sp-6: 48px;

  /* Radius 階梯（Notion-lean 收緊 2026-09-14：tiny 4、button/input 6、card/menu 8、dialog 12、pill）。
     Notion 是方中帶柔、小圓角的塊感；由 12/16 收到 8/12＝更 Notion，仍在 preflight #6 允許集（4/6/8/12）。
     一律用 token 別散寫 7/9/10 這種 off-scale 值，否則同區塊圓角對不上會顯得尷尬。 */
  --r-xs: 4px; --r-sm: 6px; --r-md: 8px; --r-lg: 12px; --r-pill: 999px;

  /* Elevation — 深色下不用陰影堆層次，改用頂緣微高光 + 深黑投影 */
  /* --sh-1＝卡片「靜止」的那層（.panel/.project-card/.card/.stat…）。原本深色只有 inset 頂光、
     淺色只有 1px 微影 → 整頁像「一張紙上畫格線」。補一層真正的投影給層次，hover 再換 --sh-2。 */
  --sh-1: inset 0 1px 0 rgba(255,255,255,.04), 0 1px 3px rgba(0,0,0,.36);
  --sh-2: 0 2px 6px rgba(0,0,0,.35), 0 12px 28px rgba(0,0,0,.5);      /* 分層陰影（Open Props 風）：更柔更真實的浮起感 */
  --sh-3: 0 4px 10px rgba(0,0,0,.4), 0 24px 56px rgba(0,0,0,.62);

  --ring: 0 0 0 3px rgba(232,190,6,.4);   /* 文字欄位聚焦的光暈（欄位才用；按鈕／卡片的鍵盤焦點用下面的 --focus-ring） */
  /* 鍵盤焦點環（2026-10-01）：outline＋間距，全站一份。outline 會跟著元件圓角，也不會蓋掉元件自己的陰影
     （box-shadow 光暈會：卡片一聚焦就沒了投影；在主色鈕上光暈跟鈕同色＝看不出焦點）。 */
  --focus-ring: 2px solid var(--primary);
  --focus-offset: 2px;

  /* 動效 token（2026-10-01 蘋果質感輪；規則見 DESIGN.md「Motion」）。時長三階：
     1＝按下／hover／顏色（即時回饋）、2＝浮層進出與淡入淡出、3＝位移（彈簧有尾巴，視覺上約等於 ease-out 的第 2 階）。
     曲線：顏色／透明度／退場一律 --ease-out（不回彈）；位移與縮放的「進場」用彈簧。
     彈簧＝WWDC23「Animate with springs」的 duration＋bounce 參數化（阻尼比＝1−bounce、從靜止出發的步階響應），
     取樣到誤差 <0.1% 為止再用 linear() 逐點近似：--spring＝bounce .15（Apple 的 snappy，過衝 0.6%）、
     --spring-soft＝bounce 0（smooth，不過衝；抽屜、變形轉場）。 */
  --dur-1: 120ms;
  --dur-2: 200ms;
  --dur-3: 320ms;
  --ease-out: cubic-bezier(.2,.8,.2,1);
  --spring: linear(0, 0.054, 0.176, 0.322, 0.467, 0.598, 0.707, 0.795, 0.862, 0.912, 0.947, 0.971, 0.987, 0.997, 1.003, 1.005, 1.006, 1.006, 1.005, 1.005, 1.004, 1.003, 1.002, 1.001, 1);
  --spring-soft: linear(0, 0.058, 0.18, 0.321, 0.455, 0.573, 0.671, 0.75, 0.812, 0.86, 0.897, 0.924, 0.944, 0.96, 0.971, 0.979, 0.985, 0.989, 0.992, 0.994, 0.996, 0.997, 0.998, 0.999, 1);
  /* 舊名沿用（呼叫端不必改）：改成引用上面的 token，全站既有 transition 一起換上新節奏。 */
  --ease: var(--ease-out);
  --tr: var(--dur-1) var(--ease-out);
  --tr-fast: var(--dur-1);
  --tr-slow: var(--dur-3);
  /* 按下回饋：按下 --dur-1 縮到 --press-scale、放開用彈簧回彈。列狀按鈕／分頁把 --press-scale 設 1（見檔尾）。 */
  --press-scale: .97;
  --press-tr: var(--dur-3) var(--spring);
  --lift-y: -2px;                  /* 可點卡片 hover 浮起的位移 */
  --lift-bg: var(--panel-2);       /* 浮起＝往上一層：深色越上層越亮（surface ladder），淺色維持白、靠陰影（見淺色覆寫） */

  /* 材質（2026-10-01）：半透明底＋背景模糊＋細邊＝浮在內容上的那一層。厚度對應 Apple 的 thin／regular／thick：
     越常放長文的越不透明（HIG：thicker materials … better contrast for text）。 */
  --mat-blur: saturate(180%) blur(20px);
  --mat-bar: rgba(32,29,22,.72);     /* 頂欄 */
  --mat-pop: rgba(41,37,28,.82);     /* 下拉選單／通知（以 --panel-2 為底＝深色的抬升層） */
  --mat-thick: rgba(32,29,22,.9);    /* 抽屜（整片長文） */
  --mat-edge: rgba(255,255,255,.08); /* 材質的細邊：深色用一條極淡的亮線 */

  /* 底線頁籤的細底軌（.seg-bar，2026-10-01 方案 A）。深色不能沿用 --line-strong：它比面板亮 ΔL*≈22，
     淺色的同一條只亮/暗 ΔL*≈12–17 ⇒ 深色下那條軌會比字還搶眼。取 --line（ΔL*≈12）＝與淺色同一級。 */
  --tab-line: var(--line);
  /* 分段切換（.seg-pill）的軌道與滑動底塊。軌道用疊色＝放在畫布、卡片、對話框上都比底下那一層再深一階；
     深色的底塊要比軌道「亮」（越上層越亮），借 --panel 會比軌道暗＝看起來是凹下去的洞。 */
  --seg-track: rgba(0,0,0,.24);
  --seg-thumb: var(--panel-3);
  --seg-thumb-sh: 0 1px 2px rgba(0,0,0,.45);
  /* AI 搜尋鈕的「未啟用」態（啟用態的霓虹是刻意的品牌色，不走 token）。深色下要沉下去，
     不然一塊發亮的淺藍方塊會比畫面上任何東西都搶眼（2026-09-23 回饋）。 */
  --ai-face: linear-gradient(180deg, rgba(74,159,216,.16), rgba(74,159,216,.10));
  --ai-line: rgba(122,190,240,.42);
  --ai-ink: #9fd0f2;
  --ai-glow: rgba(96,181,255,.32);

  --noise: .035;                  /* 紙面噪點強度（body::before）。原寫死 .028＝在淺色幾乎看不見，
                                      等於白付一層 fixed 元素；改 token 後淺色另給更高值。 */

  /* 版面寬度＝全站唯一值。原本有三種（一般 1200／專案列表 1500／裁罰·簡報·資料治理 1440），
     在寬螢幕上切頁時內容左緣會左右跳最多 150px＝「每頁邊界不一樣」。**不要再為單頁放寬 .view**
     （preflight #16 會擋 :has 例外與寫死值）；某頁真的需要更寬＝調這個值，全站一起動。 */
  --page-max: 1440px;

  /* 等寬資料字（代號/字號/法條/金額/覆核率）＝法遵「卷宗」精確感。
     2026-09-23 已套進 .data-table td.num／通用 .mono class（見 DESIGN.md）；.stat 的大數字 2026-10-02 改回內文字型＋tabular-nums
     （Geist Mono 的 0 帶斜線，大字像「Ø」）。
     中文黑體排在泛用 monospace 前面：等寬字型都沒有中文字形，落到泛用 monospace 時 Chrome 繁中預設是細明體（襯線），
     prompt／紀錄這類 <pre> 裡的中文就整段變成明體（2026-10-01 二輪體檢）。 */
  --mono: "Geist Mono", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, "Noto Sans TC", "Microsoft JhengHei", monospace;

  /* 標籤（.tag/.badge）的底：半透明墨色，不是某一階 surface。原本借 --panel-2，正好就是表格列 hover 與深色對話框的底色
     ⇒ 一滑過列、一進對話框，標籤的底就消失只剩字（2026-10-01 二輪體檢）。疊色＝放在哪一層都比那一層再深（淺色）／再亮（深色）一階。 */
  --tag-bg: rgba(244,241,234,.07);
}

/* 淺色主題（Linear inverse）：白底、深字、保留薰衣草藍重點。切換由右上角按鈕 + localStorage 控制。
   2026-09-01：曾試暖米白＋brass 金統一，但淺色下金字/暖紙看起來費力（尤其資料庫頁），回退回此藍白版。 */
:root[data-theme="light"] {
  color-scheme: light;
  /* canvas 略深＋轉冷灰，白卡片才浮得起來（原 #f7f8f8 對白卡明度差僅 ~3%＝偏平）；panel-2/3、line 同步下移保住 hover 對比與 hairline 俐落度。深色不動。 */
  --bg: #eef0f4;
  --panel: #ffffff;
  --panel-2: #e3e7ee;
  --panel-3: #d9dde6;
  --text: #16171a;
  --muted: #616873;               /* AA：bg 4.93 / panel 5.62 / panel-2 4.53（原 #6b7280 在畫布上只有 4.24） */
  --muted-2: #3a3d44;
  --line: #e6e9ef;                 /* Notion-lean：淺色 hairline 更淡（原 #dce0e7），邊框克制 */
  --line-strong: #cbd0d6;
  --primary: #5e6ad2;
  --primary-dark: #4b56c9;
  --primary-hover: #4b56c9;        /* 淺色下 hover 加深而非變亮 */
  --primary-bg: rgba(94,106,210,.10);
  --on-primary: #fff;              /* 淺色藍底上用白字 */
  --ring: 0 0 0 3px rgba(94,106,210,.4);  /* 淺色 focus 環維持藍（--ring 只定義於 :root，需在此覆寫） */
  --green: #0f7a3d; --green-bg: rgba(15,122,61,.10);
  --red: #c0362c;   --red-bg: rgba(192,54,44,.09);
  --amber: #8a5a00; --amber-bg: rgba(138,90,0,.10);          /* 淺色照舊：維持原本的琥珀黃 */
  --aml: var(--red); --aml-bg: var(--red-bg);                 /* 淺色照舊：AML 維持原本的紅 */
  --amber-line: rgba(242,201,76,.35);                          /* 淺色照舊：警示邊框維持原本黃 */
  --sh-1: 0 1px 2px rgba(16,24,40,.05), 0 4px 12px rgba(16,24,40,.07);
  --sh-2: 0 1px 3px rgba(16,24,40,.06), 0 6px 16px rgba(16,24,40,.10);   /* 分層陰影（Open Props 風）：更柔更真實的浮起感 */
  --sh-3: 0 4px 10px rgba(16,24,40,.08), 0 18px 40px rgba(16,24,40,.16);
  --tab-line: var(--line-strong);   /* 淺色：--line 太淡（對畫布 ΔL*≈3）＝底軌看不見 */
  --seg-track: rgba(30,42,70,.07);
  --seg-thumb: var(--panel);
  --seg-thumb-sh: 0 1px 2px rgba(16,24,40,.10), 0 0 0 1px rgba(16,24,40,.04);
  --ai-face: linear-gradient(180deg, #f2f9ff, #e6f3ff);
  --ai-line: #7cc4ff; --ai-ink: #2b6cb0; --ai-glow: rgba(96,181,255,.5);
  --noise: .05;                    /* 淺色底噪點要更強才看得出「紙」；深色本來就有 canvas 明度幫忙 */
  --tag-bg: rgba(30,42,70,.11);    /* 白底上≈原本的 --panel-2，hover 列（--panel-2）上再深一階 */
  --lift-bg: var(--panel);         /* 淺色的抬升面是白底加陰影；變灰（--panel-2）反而像被按下去 */
  --mat-bar: rgba(255,255,255,.72);
  --mat-pop: rgba(255,255,255,.82);
  --mat-thick: rgba(255,255,255,.9);
  --mat-edge: rgba(16,24,40,.1);
}

* { box-sizing: border-box; }
/* 作者樣式的 display（flex／grid／inline-flex…）會蓋過瀏覽器的 [hidden] ⇒ 設了 hidden 還看得見。
   頂欄、吐司、裁罰下載鈕、deck 表單都各自補過一條 X[hidden]{display:none}；根因是同一個，全站一條收掉。 */
[hidden] { display: none !important; }

/* 永遠保留垂直捲軸溝槽：否則篩選/換頁使清單長短變化時，捲軸忽隱忽現會讓整頁內容左右抖動。 */
/* font-size:100%＝沿用瀏覽器/使用者預設(通常 16px)，讓 rem 型級隨使用者字型設定縮放（Dynamic Type）。 */
/* text-size-adjust：iPhone 橫放時 Safari 會自己把字放大（版面跟著爆）；tap-highlight：點一下閃一塊灰底方框，
   不是原生 App 的手感——按下回饋改由 :active 的縮放／底色給（見檔尾「按下回饋」）。 */
html { overflow-y: scroll; font-size: 100%; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  /* 拉丁與數字一律 Geist（自帶字檔）。中文：有裝 Noto Sans TC 就用它（開發機與視覺回歸基準都是它，標點比微軟正黑緊），
     沒裝就明確落到各平台的系統黑體——Mac／iPhone＝蘋方、Windows＝微軟正黑體 UI。原本 Noto 之後直接是 sans-serif，
     多數同仁電腦沒裝 Noto，中文字型交給瀏覽器預設（使用者改過預設字型就跟著變）。 */
  font-family: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans TC", "PingFang TC", "Microsoft JhengHei UI", "Microsoft JhengHei", sans-serif;
  font-size: var(--fs-body);
  line-height: 1.6;          /* Notion-lean：段落更鬆、好讀 */
  letter-spacing: normal;    /* Notion-lean：body 不收緊字距（標題仍保留略負，見下） */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* 捲軸：全站細軌＋隨主題的把手色。原本是 OS 原生捲軸（Windows 上是帶上下箭頭的粗灰軌），
   對話框／表格／抽屜裡一出現就整塊變廉價。`scrollbar-width` 是標準屬性，不需 ::-webkit-*。
   把手用 --line-strong（hairline 的強化版）＝深淺主題都自動對，軌道透明＝不切出一條灰帶。 */
* { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }

/* 標題字距用 em（2026-10-01）：跟著字級等比例（使用者放大字型時一起放大），同一級標題各處一致。
   原本寫 px，h3 在卡片／許願／Skill 各寫一個值（-.2／-.3px）。中文標題只能「略」負——收太緊字會黏在一起。 */
h1 { font-size: var(--fs-h1); line-height: 1.2; letter-spacing: -.01em; }   /* Notion-lean：字距放鬆一階，仍保留略負 */
h2 { font-size: var(--fs-h2); line-height: 1.25; letter-spacing: -.01em; }

/* 細噪點紙面質感（Notion/編輯風，2026-09-14）：固定全屏、極淡、灰階、不吃點擊。
   inline SVG feTurbulence data-URI＝自足、零外連（CSP img-src data: 允許；data: 非外部 url→圖表匯出內嵌 styles.css 也不 canvas taint）。
   opacity 是唯一強度旋鈕。
   **必須待在所有內容後面**（z-index:-1；html 沒有背景 ⇒ body 的背景傳遞到 canvas，噪點仍看得見）：
   原本是 z-index:1＝一層蓋在頁面上的 fixed 元素，它蓋得到「沒有 position 的」內容面
   （.panel／.penalty-view＝一般流排版），卻蓋不到「有 position+z-index 的」分頁列
   ⇒ 目前那張頁籤是乾淨的 --panel，接縫下面那張紙被噪點提亮約 3 階 ⇒ 兩個面顏色不一樣，
   接縫就變成一條「明顯的線」（2026-09-29 回報；前兩輪調 --tab-back／--tab-line 都沒打到這個）。
   **別再把它放到內容上面**——任何 positioned 元素都會逃掉噪點、在交界處長出同一條線。
   注意：視覺回歸的 calm() 會關掉噪點，所以這個問題截圖測試看不到，只有真的開著噪點才看得出來。 */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none; opacity: var(--noise);
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

button, select, textarea, input { font: inherit; }
/* 程式碼類元素沒給字型＝瀏覽器的泛用 monospace，Chrome 繁中預設是細明體（襯線）：模型 ID、金鑰、JSON 一律長成明體。
   泛用 monospace 還會讓 Chrome 把字縮成 13/16（行內 code 原本就比旁邊小一號），換成具名字型後這個縮放就沒了 ⇒ 行內的自己縮 .9em。 */
code, kbd, samp, pre { font-family: var(--mono); }
code, kbd, samp { font-size: .9em; }
::placeholder { color: var(--muted); }
input[type=checkbox], input[type=radio] { accent-color: var(--primary); }
/* 沒有自己樣式的連結＝品牌色。原本全站沒有這條，表格裡的「跳轉」「原文」、新聞標題是瀏覽器預設藍（深色模式淡紫）。
   :where() 特異度 0：任何有 class 的連結樣式（.navlink／.btnlink／.back-link…）照樣贏。penalty 自己有一條同義的。 */
:where(a) { color: var(--primary); }

/* Smooth micro-interactions on all interactive elements（scale＝按下回饋：按下快、放開彈回，見 :root --press-tr） */
button, .navlink, .btnlink, a, input, select, textarea {
  transition: border-color var(--tr), background var(--tr), box-shadow var(--tr), color var(--tr), transform var(--tr), scale var(--press-tr);
}

/* 鍵盤焦點環（WCAG 2.4.7）：全站同一圈 outline＋間距，圓角自動跟著元件（2026-10-01；原本是貼著元件的 box-shadow 光暈，
   會蓋掉卡片／浮動鈕自己的陰影，在主色鈕上又跟鈕同色看不出來）。只掛 :focus-visible＝滑鼠點擊不出現。
   文字欄位不吃這圈：聚焦＝正在輸入，由下方欄位規則給主色邊框＋光暈。tabindex="-1"＝程式移過去的焦點，不畫。
   清單列／分頁的環畫在裡面（outline-offset 負值，見檔尾「按下回饋」那段）：列與列之間沒有空隙，外擴會壓到鄰居、被捲動區切掉。 */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible,
summary:focus-visible, [tabindex]:not([tabindex="-1"]):focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

button {
  min-height: 40px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
  padding: 0 var(--sp-3);
  /* 按鈕字不折行：flex 工具列被擠窄時，中文按鈕的最小寬度是「一個字」，會被壓成一字一行
     （「新增型/號」「立即爬取 Google/模型」，2026-10-01 二輪體檢）。原本靠各處零星補 nowrap。 */
  white-space: nowrap;
}
/* 例外：按鈕本身裝的是「一則內容」而不是動作字（清單列、領域說明、節點說明、追問句、檔名、選項）＝照常折行。
   分頁列（.seg）不在這裡：頁籤字不折、放不下就整顆換到下一列（.seg 一律 flex-wrap，2026-10-01 改底線頁籤後）。 */
.help-row, .add-domain-item, .wf-panel-item, .ai-fu, .law-timeline-pen, .fd-file, .sh-main { white-space: normal; }
button:hover { border-color: var(--line-strong); background: var(--panel-2); }
/* 按下＝縮一點（2026-10-01；原本 translateY(1px)）。用獨立的 scale 屬性不用 transform：
   浮動鈕／拖曳中的元素自己的 transform（置中、位移）不會被蓋掉（原本按下覆核跳題鈕會往下跳半顆，得逐一補例外）。 */
button:active, .btnlink:active { scale: var(--press-scale); --press-tr: var(--dur-1) var(--ease-out); }
button:disabled { opacity: .5; cursor: not-allowed; scale: none; }
/* 進行中（aria-busy）≠ 不能用：停用只是防連點，「產生中 12/60」「儲存中…」要看得清楚——不吃上面的半透明、游標轉圈；
   帶圖示的鈕（.btn-ic）圖示換成轉圈（見 .spinner）。modal() 的送出鈕自動掛；自己鎖按鈕的，disabled 時一併設 aria-busy="true"。 */
button[aria-busy="true"] { opacity: 1; cursor: progress; }
button.small { min-height: 30px; padding: 0 10px; font-size: var(--fs-sm); }
button.block { width: 100%; }

.primary { border-color: var(--primary); background: var(--primary); color: var(--on-primary,#fff); box-shadow: none; }
.primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
.primary:active { background: var(--primary-dark); border-color: var(--primary-dark); }
.ghost { border: 0; background: transparent; color: var(--muted-2); padding: 6px 8px; min-height: 0; box-shadow: none; }
.ghost:hover { background: var(--panel-2); color: var(--text); }
.ghost.danger:hover { background: var(--red-bg); color: var(--red); }
/* toggle 圖示鈕（如 Bug 回報模式）開啟中的高亮 */
.ghost[aria-pressed="true"] { background: var(--primary-bg); color: var(--primary); }
.danger { color: var(--red); }
.icon { border: 0; background: transparent; color: var(--red); min-height: 0; padding: 2px 6px; font-size: var(--fs-sm); }
.icon:hover { background: var(--red-bg); }

/* 欄位外觀。型別要列全：沒列到的 number／url／date… 就是瀏覽器預設的小方框（2026-10-01 二輪體檢：AI 模型費率、
   寄信設定的抓取天數、MCP 的 URL）。type=search 刻意不列：搜尋框都包在 searchBox()（.filter-search）或 penalty 的
   .serp-input 複合列裡、各自有樣式，列進來會把 serp 那條搜尋列撐高。
   單行欄位剛好 40px＝與按鈕、日期選取器、搜尋膠囊同高（篩選列才對得齊）：行高 1.25 × 16px＋上下 9px＋邊框 2px。
   原本吃 body 的 1.6 行高＝45.6px，比同一列的按鈕高一截；多行的 textarea 在下面拿回 body 行高。 */
input[type=text], input[type=password], input[type=email], input[type=number], input[type=url], input[type=tel],
input[type=date], input[type=datetime-local], input[type=time], input[type=month], input[type=week], textarea, select {
  width: 100%;
  min-height: 40px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel);
  color: var(--text);
  padding: 9px 11px;
  line-height: 1.25;
}
/* 數字欄多半是行內小格（費率、金額、年份、天數）：照內容寬，不撐滿整列；放在 .field 裡（grid）照樣撐滿欄寬。 */
input[type=number] { width: auto; }
input:hover, textarea:hover, select:hover { border-color: var(--line-strong); }
/* 只給文字類欄位：勾選框／單選鈕原本也吃 :focus（不是 :focus-visible）＝滑鼠點一下就出一圈光暈。它們改走上面的鍵盤焦點環。 */
:is(input:not([type=checkbox], [type=radio], [type=range], [type=color], [type=file]), textarea, select):focus { border-color: var(--primary); outline: none; box-shadow: var(--ring); }
/* 出錯的欄位（toast(msg,'error',{field}) 標上 aria-invalid，一打字就拿掉）：紅框，聚焦時紅色光暈。
   聚焦那條也要寫紅框：上面那條欄位聚焦規則特異度與它相同，靠排在後面才蓋得過它的主色框。 */
input[aria-invalid="true"], textarea[aria-invalid="true"], select[aria-invalid="true"] { border-color: var(--red); }
input[aria-invalid="true"]:focus, textarea[aria-invalid="true"]:focus, select[aria-invalid="true"]:focus { border-color: var(--red); box-shadow: 0 0 0 3px var(--red-bg); }
/* 頁面上（不在對話框裡）的表單錯誤：紅字寫在欄位與送出鈕之間（登入頁）。浮動提示在畫面最底，手機鍵盤升起時剛好被蓋住
   （2026-10-01 手機實測）。對話框裡的錯誤由 util.js toast() 寫進 .dialog-error。 */
.form-error { margin: 0; color: var(--red); font-size: var(--fs-sm); line-height: 1.45; }
/* 多行輸入一律隨內容長高（`rows` 變成「最少幾行」），不在框內出現捲軸——框內捲軸＝看不到自己
   打的字、還多一條難看的軌道。上限 50vh 後才交給框內捲動（不設上限會把對話框撐爆）。
   原本 domains.js／penalty/ai_ask.js 各自用 JS 量 scrollHeight 手動長高，已改由這一行統一。
   resize:none——會自己長高就不需要右下角那個拖曳把手（工作日誌週表一格一個，滿版都是斜線）。
   line-height:inherit＝拿回段落行高（上面那條 1.25 只給單行欄位）。 */
textarea { resize: none; field-sizing: content; max-height: 50vh; line-height: inherit; }
/* 自訂 select 下拉箭頭：appearance:none 收掉 OS 原生箭頭，改嵌一顆灰 chevron（SVG 描邊＝
   DESIGN.md 允許的寫死色例外）→ 跨平台一致、擺脫「未美化 <select>」的廉價感。背景色仍由上方 var(--panel)。 */
select { appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 30px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23949aa4' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 11px center; }
/* 下拉展開時 chevron 翻向上，與 header 導覽下拉（.nav-dd-caret 隨 aria-expanded 旋轉）一致。
   原生 <select> 不支援偽元素/背景旋轉 → 用 :open 換成向上 chevron（現代瀏覽器 baseline；
   不支援者維持向下＝現行行為、無回歸）。全站 <select> 一次到位。見 DESIGN.md「下拉箭頭方向」。 */
select:open {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23949aa4' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 15 6-6 6 6'/%3E%3C/svg%3E");
}

/* `*` 選不到偽元素：登入頁的 mesh 漸層（::before）與對話框遮罩（::backdrop）原本都漏在外面照動。
   scale／translate（獨立變形屬性）全站只拿來做互動回饋——按下縮放、卡片浮起、浮層從 .96 放大進場——
   減少動態＝這些一律不做，只留顏色與陰影的變化（MDN：縮放、平移是前庭誘發的典型）。 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after, ::backdrop { transition: none !important; animation: none !important; scroll-behavior: auto !important;
    scale: none !important; translate: none !important; }
}

/* ---------- Topbar ---------- */
.topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 20;
}
/* 頂欄的毛玻璃畫在 ::before，**不要放回 .topbar 本身**（2026-10-01）：元素自己有 backdrop-filter／filter／transform，
   就會①成為 position:fixed 子孫的容器塊（手機抽屜當年因此塌成一條，才改成 absolute）②成為 backdrop root——
   裡面的下拉選單、通知面板自己的 backdrop-filter 只模糊得到頂欄這一條，選單底下的頁面內容反而清清楚楚透上來。
   畫在偽元素上兩個副作用都沒有。z-index:-1 落在頂欄自己的疊層裡（sticky＋z-index 已成疊層）＝內容後面、頁面前面。 */
.topbar::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: var(--mat-bar); -webkit-backdrop-filter: var(--mat-blur); backdrop-filter: var(--mat-blur);
}
/* .topbar{display:flex} 會蓋過 [hidden] 的 display:none → 未登入(登入頁)時 header 仍露出。
   明確讓 hidden 生效（特異度高於 .topbar），登入頁就不顯示 header。 */
.topbar[hidden] { display: none; }
/* 頁面捲動後頂欄才浮起一層影子（捲動驅動，0–64px 之間漸出）；停在頂端＝跟內容同一張紙。 */
@supports (animation-timeline: scroll()) {
  .topbar { animation: topbar-lift linear both; animation-timeline: scroll(root); animation-range: 0 64px; }
  @keyframes topbar-lift { to { box-shadow: var(--sh-1); } }
}
/* 品牌名 --fs-h3：原本 h2 粗體＝整條頂欄最重的東西，比頁面自己的標題還搶眼。 */
.topbar h1 { margin: 2px 0 0; font-size: var(--fs-h3); letter-spacing: -.4px; }
.eyebrow { margin: 0; color: var(--muted); font-size: var(--fs-xs); letter-spacing: .4px; }
.brand { min-width: 220px; text-decoration: none; color: inherit; cursor: pointer; display: flex; align-items: center; gap: 12px; }
/* logo「填滿的圓角磚」：cover 填滿不留白、同 nav active 圓角；底色用政勤 logo 自身藏藍(#003e65)，
   讓透明角落無縫延伸成完整藏藍磚（取自 favicon 主色）。 */
.brand-logo { width: 42px; height: 42px; object-fit: cover; flex: none; border-radius: var(--r-sm); background: #003e65; }
.brand-text { display: block; }
.brand:hover h1 { color: var(--primary-hover); }
.mainnav { display: flex; gap: 4px; flex: 1; }
/* <details> 用全站 chevron（.dd-caret）當展開記號時，藏掉瀏覽器自己的三角形（Safari 用 ::-webkit-details-marker，其餘用 list-style）。 */
summary:has(> .dd-caret) { list-style: none; }
summary:has(> .dd-caret)::-webkit-details-marker { display: none; }
/* 漢堡鈕：桌面隱藏、≤720px 由檔尾 RWD 區塊顯示。**別用 hidden 屬性藏它**——全站 [hidden] 是
   display:none !important，媒體查詢再也蓋不回來（2026-10-01 手機版因此整個沒有導覽可點）。 */
.nav-toggle { display: none; }
/* nowrap：中文導覽項寬度吃緊時(100% 縮放)別在字中間斷行；配合上面縮小的 gap/padding 讓整列一行放得下。 */
.navlink { padding: 8px 12px; border-radius: var(--r-sm); text-decoration: none; color: var(--muted); font-size: var(--fs-sm); font-weight: 500; white-space: nowrap; }
.navlink:hover { background: var(--panel-2); color: var(--text); }
.navlink.active { background: var(--primary-bg); color: var(--primary-hover); font-weight: 600; }

/* 管理員工具下拉 */
.nav-dd { position: relative; display: inline-flex; }
.nav-dd-btn { display: inline-flex; align-items: center; gap: 5px; background: transparent; border: 0; cursor: pointer; min-height: 0; }
.nav-dd-caret { transition: transform var(--dur-2) var(--ease-out); }
.nav-dd-btn[aria-expanded="true"] .nav-dd-caret { transform: rotate(180deg); }
/* 底色／邊框／陰影與進出場動畫＝全站浮層共用的材質，見下方「浮層」段（.nav-dd-menu／.notif-pop／.rp-menu／.exports-pop） */
.nav-dd-menu { display: none; position: absolute; top: calc(100% + 6px); left: 0; min-width: 150px;
  border-radius: var(--r-md); padding: 6px; z-index: 70; transform-origin: top left; }
.nav-dd-item { display: block; padding: 8px 12px; border-radius: var(--r-sm); color: var(--muted);
  text-decoration: none; font-size: var(--fs-sm); font-weight: 500; white-space: nowrap; }
.nav-dd-item:hover { background: var(--panel-2); color: var(--text); }
.nav-dd-item.active { background: var(--primary-bg); color: var(--primary-hover); font-weight: 600; }
.userbox { display: flex; align-items: center; gap: 12px; }
/* 深淺色切換＝單一 .ghost 圖示鈕（與鈴鐺同款），顯示「目前模式」的圖示，點一下翻面。見 main.js themeToggleBtn。 */
/* 頂欄右側的文字鈕（登出／個人資料）共用這一條：原本登出是 .ghost（16px、深灰）、個人資料 14px 淡灰，
   並排像兩種東西。字級字重對齊左側導覽連結；hover 走中性底，品牌色留給「目前所在的導覽項」。 */
.who { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: var(--fs-sm); font-weight: 500;
  border: 0; background: transparent; padding: 6px 8px; min-height: 0; box-shadow: none; cursor: pointer; border-radius: var(--r-sm); }
.who:hover { background: var(--panel-2); color: var(--text); }
/* 小提示（util.js initTooltips；元素掛 data-tip）：取代原生 title（OS 樣式、慢半拍、深色主題下一塊白）。
   popover＝top layer，不被 overflow 切掉、蓋得過對話框；位置交給 anchor positioning（下方放不下就翻到上方），
   不支援的瀏覽器由 JS 量位置寫 left/top。反色＝兩個主題都跟底色拉得開。 */
.tip { inset: auto; margin: 6px 0 0; padding: 4px 8px; max-width: 280px; overflow: visible; border: 0; border-radius: var(--r-sm);
  background: var(--text); color: var(--bg); font-size: var(--fs-xs); font-weight: 500; line-height: 1.5;
  box-shadow: var(--sh-2); pointer-events: none; transition: opacity var(--dur-1) var(--ease-out);
  position-anchor: --cra-tip; position-area: bottom; position-try-fallbacks: flip-block, flip-inline; }
@starting-style { .tip:popover-open { opacity: 0; } }

/* ---------- Generic layout ---------- */
/* 所有頁面共用同一個外框：同寬、同左右留白（--sp-4）、同上下留白（--sp-6），切頁時內容不位移。 */
.view { max-width: var(--page-max); margin: 0 auto; padding: var(--sp-6) var(--sp-4); }
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: var(--sp-5); }
/* 標題被分頁列去重掉、只剩動作列的頁首（見 util.js pageHead）：收緊上下留白，別讓那排鈕浮在一片空地中間。 */
.page-head:has(> div:empty) { margin-top: calc(-1 * var(--sp-2)); margin-bottom: var(--sp-3); }
.page-head h2 { margin: 0 0 4px; }
/* 返回上一層（util.js backLink）：標題上方的灰色小字，hover 才轉實色。<a> 與 <button> 兩種都長這樣。 */
.back-link { display: inline-flex; align-items: center; gap: 4px; margin: 0 0 6px -4px; padding: 2px 6px 2px 4px; min-height: 0;
  border: 0; border-radius: var(--r-xs); background: none; box-shadow: none; color: var(--muted); font-size: var(--fs-sm);
  font-weight: 500; text-decoration: none; cursor: pointer; }
.back-link:hover { color: var(--text); background: var(--panel-2); }
.back-link-ic { display: inline-flex; }
/* 圖示＋文字的按鈕（匯出／下載…）：圖示與字垂直置中、固定間距。<a class="btnlink btn-ic"> 同樣適用。 */
.btn-ic { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.btn-ic > svg { flex: none; }
.head-actions { display: flex; gap: 8px; flex-wrap: wrap; }
/* 左上角「目前正在覆核」人員列：頭貼＋名字整顆 chip 上下微幅浮動表示存在感 */
.reviewers-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 6px 0 0; }
.reviewers-bar:empty { display: none; }
.reviewer-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--r-pill); padding: 2px 11px 2px 3px; font-size: var(--fs-sm); line-height: 1.2; animation: reviewer-bob 1.6s ease-in-out infinite; }
.reviewer-name { color: var(--text); white-space: nowrap; }
.reviewer-av { width: 22px; height: 22px; flex: 0 0 auto; display: inline-block; }
.reviewer-av-img, .reviewer-av-def { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; display: block; }
.reviewer-av-def { display: flex; align-items: center; justify-content: center; color: #fff; font-size: var(--fs-xs); font-weight: 700; }
@keyframes reviewer-bob { 0%, 100% { transform: translateY(-2px); } 50% { transform: translateY(2px); } }
/* 該使用者畫面不在覆核頁（切分頁/最小化）→ 停止跳動、淡化，表示「在場但沒在看」 */
.reviewer-chip.away { animation: none; opacity: .5; transform: none; }
@media (prefers-reduced-motion: reduce) { .reviewer-chip { animation: none; } }
.muted { color: var(--muted); }
.small { font-size: var(--fs-sm); }
.xsmall { font-size: var(--fs-xs); }
.nowrap { white-space: nowrap; }

.panel { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--sp-4); box-shadow: var(--sh-1); }
.error-panel { color: var(--red); }
/* 全站空狀態/無資料訊息（置中灰字）。.penalty-view .empty 有自己的版本、specificity 較高會覆蓋；
   避免 deck／ask_votes 等在 penalty-view 外用 .empty 時無樣式（原本只 .penalty-view .empty 有定義）。 */
.empty { text-align: center; color: var(--muted); padding: 30px 0; }
/* 空狀態的淡圖示（util.js empty()/emptyRow() 產生）。刻意很淡＝提示而非主角。 */
.empty-ic { display: flex; justify-content: center; margin-bottom: 8px; color: var(--muted); opacity: .45; }
.empty-tx { font-size: var(--fs-md); }
/* 有外框的空狀態／提示（`class:'panel muted'`：「還沒有任何許願」「尚無專案」「僅限管理員使用」）。
   原本靠左，跟置中的 .empty 並存＝同一種「這裡沒東西」在不同頁長不一樣；統一置中。
   刻意不加 .empty 那顆圖示——這個變體也拿來放權限提示，收件匣圖示在那裡是錯的語意。 */
.panel.muted { text-align: center; }

.btnlink {
  display: inline-flex; align-items: center; min-height: 40px; padding: 0 14px;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--panel); color: var(--text); text-decoration: none;
}
.btnlink:hover { border-color: var(--line-strong); background: var(--panel-2); }
/* <a> 版的小鈕（匯出／下載連結擺在一排 button.small 旁邊）：與 button.small 同尺寸，原本只有 lab 自己補過一條。 */
.btnlink.small { min-height: 30px; padding: 0 10px; font-size: var(--fs-sm); }

/* 語意標籤（靜態）。`.tag` 與 `.badge` 原本是兩份幾乎一樣的規則，但 `.badge` 忘了設 font-size
   ⇒ 吃 body 的 16px、整整大 `.tag` 一圈（許願池分類籤 vs 表格 tag 並排就看得出來）。合成同一條。
   可互動的 chip（含 × 鈕）見 `.chip`：只有內距與字級高一階，圓角/底色同源。 */
.tag, .badge {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: var(--r-pill);
  background: var(--tag-bg); font-size: var(--fs-xs); line-height: 1.6; color: var(--muted-2); white-space: nowrap;   /* 底色為何是疊色見 :root --tag-bg */
}
.tag-admin { background: var(--primary-bg); color: var(--primary-hover); }

/* ---------- Auth ---------- */
/* 登入頁：純平底 → 加品牌金的柔和頂部光暈給深度（theme-aware var(--primary-bg)），卡片淡入上浮進場。 */
/* 高度扣掉 .view 上下各 --sp-6 內距＝剛好一個視窗高：原本扣 40px，整頁多出 56px 可捲、卡片也偏下。 */
.auth-wrap { min-height: calc(100vh - 2 * var(--sp-6)); min-height: calc(100dvh - 2 * var(--sp-6)); display: grid; place-items: center; padding: 24px; position: relative; }
/* 登入頁環境光 mesh 漸層（純 CSS 動畫、自足、無 WebGL/相依）＝Paper Shaders 氛圍的克制版：
   單一品牌色多團緩慢漂移＋模糊。prefers-reduced-motion 由全域 blanket 自動轉靜態。
   position:fixed＝鋪滿整個視窗：absolute 會被 .view 的內距框住，四周留一圈沒有光暈的邊（2026-09-30 體檢）。
   fixed 不受 .auth-wrap 的 overflow 裁切 → .auth-wrap 不要再寫 overflow:hidden：它只剩把卡片陰影切出一道硬邊（手機上最明顯）。 */
.auth-wrap::before {
  content: ""; position: fixed; inset: -25%; z-index: 0; pointer-events: none; filter: blur(36px);
  background:
    radial-gradient(38% 46% at 22% 26%, var(--primary-bg), transparent 60%),
    radial-gradient(42% 50% at 78% 22%, var(--primary-bg), transparent 62%),
    radial-gradient(46% 54% at 58% 88%, var(--primary-bg), transparent 64%);
  animation: auth-mesh 24s var(--ease) infinite alternate;
}
@keyframes auth-mesh { from { transform: translate3d(-3%,-2%,0) scale(1.06) rotate(-3deg); } to { transform: translate3d(3%,3%,0) scale(1.16) rotate(3deg); } }
/* 寬度對「容器」算、不對視窗算：92vw 沒扣掉 .view 與 .auth-wrap 的左右內距（手機 390px 寬時卡片 359px、可用只有 310px），
   卡片把格線欄撐寬、靠左、右邊被 overflow:hidden 切掉＝手機登入頁沒置中（2026-10-01 回報）。 */
.auth-card { width: min(420px, 100%); position: relative; z-index: 1; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 32px; box-shadow: var(--sh-1), var(--sh-3); animation: auth-in .42s var(--ease) both; }
@keyframes auth-in { from { opacity: 0; transform: translateY(10px) scale(.985); } to { opacity: 1; transform: none; } }
/* 事務所 logo：滿卡寬橫幅（圖自帶深藍底＋金字），圓角與卡片一致，下方留白後接標題。 */
.auth-logo { display: block; width: 100%; height: auto; border-radius: var(--r-sm); margin: 0 0 20px; }
.auth-card h2 { margin: 0 0 6px; }
/* 手機：外圈不再多墊 24px（.view 已有左右 16px）、卡片內距收窄——iPhone SE 寬時帳號欄的提示字才不會被切掉。 */
@media (max-width: 720px) { .auth-wrap { padding: 16px 0; } .auth-card { padding: 24px 20px; } }
.auth-form { display: grid; gap: 12px; margin-top: 18px; }
.auth-form > .field + .field { margin-top: 0; }   /* 開通頁的欄位帶標籤（.field）：間距已由 grid gap 給，別再疊全站的 12px */
/* 表單下方的輔助行（忘記密碼／登入·申請切換）：同一個置中頁尾、同字級（原本一行置中小字、一行靠左大字）。 */
.auth-foot { display: grid; justify-items: center; gap: 8px; margin-top: 16px; font-size: var(--fs-sm); }
.auth-foot .link-button { margin: 0; }

/* ---------- Projects ---------- */
/* auto-fit（非 auto-fill）＝空欄位塌陷不留白；justify-content:start＝卡片從左緣排起、對齊上方靠左的區段標題
   （2026-09-30 體檢：原本置中，只有一張卡時懸在畫面中間、標題卻在左邊；Skill 庫／問卷的網格也都靠左）。
   坑：固定 minmax(min,MAX) 的欄數是用「MAX」算 floor((寬+gap)/(MAX+gap))——MAX 太大(400)在 ~1250px 只排 2 張。
   MAX 330＝在全站共用的 --page-max(1440) 內仍排得下 4 張（1392+16）/(330+16)=4；1200 視窗 3 張。
   （原本靠「專案頁專屬的 .view 寬度例外（1500）」撐出第 4 欄，那個例外已移除＝各頁邊界一致。） */
.project-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 330px)); gap: 16px; justify-content: start; grid-auto-rows: 1fr; }
/* 卡片＝直向 flex（原為 grid）：①`grid-auto-rows:1fr` 讓每張卡一樣高（同列本來就等高，但列與列之間
   會因描述長短差一截＝「卡片大小不一致」）；②flex 才能讓動作列 `margin-top:auto` 貼底，短卡的按鈕
   不會浮在半空。內容仍靠 gap 排列，視覺與原 grid 相同。 */
.project-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--sp-3); display: flex; flex-direction: column; gap: 8px; box-shadow: var(--sh-1); transition: border-color var(--tr), background var(--tr), box-shadow var(--dur-2) var(--ease-out), translate var(--dur-3) var(--spring), scale var(--press-tr); }
/* 描述最多 3 行：一張話多的卡不該把整個網格撐高（等高網格下所有卡都會跟著長）。 */
.pc-desc { display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; min-height: 1lh; }   /* 固定一行：沒描述也占位，卡片才一樣高 */
/* 可點的卡片 hover＝浮起（全站同一組：--lift-y 位移＋--sh-2 陰影＋--line-strong 邊，深色再亮一階 --lift-bg）。
   只給整張可點的（role="button"）：問卷範本卡是同一個 class 但整張不可點，浮起＝假的「可以點」記號。 */
.project-card[role="button"]:hover { border-color: var(--line-strong); background: var(--lift-bg); translate: 0 var(--lift-y); box-shadow: var(--sh-2); }
/* 分析實驗室可展開卡片：整卡 hover 提亮邊框、可點表頭 hover 反白 → 明示可點區域（比照 .project-card；見 lab.js） */
.lab-card { transition: border-color var(--tr), background var(--tr); }
.lab-card:hover { border-color: var(--line-strong); }
.lab-row { border-radius: var(--r-sm); margin: -2px -6px; padding: 2px 6px; transition: background var(--tr); }
.lab-row:hover { background: var(--panel-2); }
/* 展開箭頭（lab.js caretIcon）：chevron 圖示，展開時 JS 轉 90° */
.lab-caret { display: inline-flex; align-items: center; justify-content: center; width: 1em; flex: none; transition: transform var(--tr-fast) var(--ease); }
.project-card h3 { margin: 0; font-size: var(--fs-h3); line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 2lh; }   /* 固定兩行高 */
/* 卡片四層：①識別（類型膠囊＋公司）②專案名 ③進度數字 ④動作／後設資料。
   2026-09-30 回饋「層級不清楚」＝原本四層都長得差不多（膠囊與公司都是灰小字、三顆按鈕等寬、
   負責人那行整串灰字）。現在：公司是實色粗體（它跟類型一樣是「這張卡是誰的」）、進度數字右靠等寬
   當主角、只有一顆主 CTA、後設資料用「標籤｜值」兩欄並以細線隔開。 */
.pc-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
.pc-top-l { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1 1 auto; }   /* 不換行：公司太長就省略號（title 帶全名），識別列固定一行高 */
.pc-top > button { flex: none; white-space: nowrap; }   /* 否則長公司名會把「刪除」擠成兩行，整列高度從 25 變 46 */
.pc-kind { color: var(--text); }   /* 類型與公司同為「這張卡是什麼／誰的」，不該是卡上最淡的字 */
.pc-company { font-size: var(--fs-sm); color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc-stat { display: flex; align-items: baseline; gap: 8px; font-size: var(--fs-sm); min-height: 22px; }
.pc-stat .tag { padding: 0 7px; }   /* 待重覆核那顆不得把這一列撐高，否則有/無它的卡片差 23px */
.pc-stat-k { color: var(--muted-2); }
.pc-stat-v { margin-left: auto; color: var(--text); }
.pc-mine { display: flex; flex-direction: column; gap: 4px; }
.pc-mine .pc-stat-k, .pc-mine .pc-stat-v { color: var(--amber); }
.pc-mine.is-none .pc-stat-k, .pc-mine.is-none .pc-stat-v { color: var(--muted-2); }   /* 沒被指派：同一列、但不點亮 */
.pc-mine-bar { height: 5px; }
.pc-meta { display: grid; grid-template-columns: auto 1fr; gap: 2px 12px; margin: 0; padding-top: 8px; border-top: 1px solid var(--line); font-size: var(--fs-xs); }
/* 唯讀「標籤｜值」清單（專案詳情等）。表單欄位用 util.js 的 field()，這個是純呈現。 */
.kv { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; margin: 0; font-size: var(--fs-sm); }
.kv dt { color: var(--muted-2); }
.kv dd { margin: 0; color: var(--text); font-weight: 400; }
.pi-h { margin: 18px 0 8px; font-size: var(--fs-sm); color: var(--muted-2); font-weight: 500; }
.pi-h:first-child { margin-top: 0; }
.pi-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 10px; }
.pi-stats .stat strong { font-size: var(--fs-h2); }
.pc-meta dt { color: var(--muted-2); }
.pc-meta dd { margin: 0; color: var(--text); font-weight: 400;   /* 全域 dd 是 700，卡片上一整排粗體太重 */
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }   /* 「最後覆核 時間（誰）」名字長也不折行（卡片等高） */
/* 日期選取器放進已有標籤的欄位（建立專案的期間、分析實驗室）：選取器自帶的「期間」小標就重複了 */
.field .ymp > .tl-label { display: none; }

/* 設定中(stage 1)：整卡品牌金黃 tint（與 logo 同色系），一眼區分未定案專案。
   仍保留 .pc-setup-flag 文字，避免「只靠顏色傳達狀態」(WCAG 1.4.1)。 */
/* Notion-lean 去金：setup 態去金色填底、只留金框 accent（bg 交回一般卡片/hover 規則）。 */
.project-card.is-setup { border-color: var(--primary); }
.project-card.is-setup:hover { border-color: var(--primary); }
.pc-setup-flag { display: inline-flex; align-items: center; gap: 5px; color: var(--primary-hover); font-size: var(--fs-xs); font-weight: 600; white-space: nowrap; }
.pc-setup-flag::before { content: ""; width: 6px; height: 6px; border-radius: var(--r-pill); background: currentColor; flex: none; }
.pc-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: auto; padding-top: 4px; }
.pc-actions button.primary { flex: 1 1 auto; min-width: 96px; }   /* 主 CTA 撐開，次要動作縮到自己的字寬＝一列放得下 */

.progress { height: 8px; overflow: hidden; border-radius: var(--r-pill); background: var(--line); }
.progress > div { width: 0; height: 100%; background: var(--primary); }
.pc-mine-bar > div { background: var(--amber); }   /* 須排在 .progress > div 之後：同特異性、後者勝 */

/* ---------- Tables ---------- */
.table-wrap { padding: 0; overflow: auto; }
/* --cell-px＝格子左右內距（手機 720px 區塊改 10px）。動作欄靠它算「鈕的字對齊表頭字」，見下方 td.row-actions。 */
.data-table { width: 100%; border-collapse: collapse; font-size: var(--fs-md); --cell-px: 16px; }
/* 列距 10/14 → 12/16：14px 字在 10px 內距下偏擠，掃讀一長串裁罰/稽核列會累。 */
.data-table th, .data-table td { text-align: left; padding: 12px var(--cell-px); border-bottom: 1px solid var(--line); vertical-align: top; }
/* 表頭不填色：原本整條 --panel-2 實色在淺色是 #e3e7ee，比內容還重、把表格壓成 Excel。
   改成與卡片同底＋較強的下緣 hairline＋小字微字距＝表頭退成「欄位標示」，資料才是主角。
   sticky 需要不透明底，故用 --panel（不是 transparent），捲動時列不會透上來。
   nowrap：隔壁欄是長文字時，中文表頭會被擠成一字一行（「法/遵/領/域」）。 */
.data-table th {
  background: var(--panel); color: var(--muted); font-weight: 600; position: sticky; top: 0;
  font-size: var(--fs-sm); letter-spacing: .04em; border-bottom: 1px solid var(--line-strong); white-space: nowrap;
}
/* 空狀態列（util.js emptyRow）：`.data-table td` 的 text-align:left 特異度比 .empty 高，圖示置中、字卻靠左。 */
.data-table td.empty { text-align: center; }
/* 格子最少 4 個字寬：中文可以在任兩字之間斷行，旁邊有長文字欄時，短欄（人名、狀態、套用）會被壓到剩一兩個字寬
   （「測試/帳號」「成/功」，手機上更慘）。有了下限，真的擠不下就整張表橫捲（.table-wrap），不再折字。
   全站 border-box：min-width 含左右內距，所以要加回 2 × --cell-px，否則 4em 扣掉 32px 內距只剩不到兩個字。
   .num 本來就不折行、.col-ctl 刻意最窄，不套。 */
.data-table td:not(.num, .col-ctl) { min-width: calc(4em + 2 * var(--cell-px)); }
/* 列裡有表單控件（下拉／單行輸入／開關）就整列垂直置中：文字格貼頂、40px 高的控件卻在格子中間，
   看起來錯開半行（帳號與稽核的角色下拉）。純文字的多行表維持貼頂，長內容才好從第一行讀起。
   :where() 把特異度壓回與上面那條同級：各表自己寫的 vertical-align:top（.tr-slots 的合併格、議題表）照樣贏。 */
.data-table :where(tr:has(select, .switch, input:not([type=checkbox], [type=radio], [type=hidden], [type=file]))) > td { vertical-align: middle; }
/* 數字欄一律 .num（右對齊＋不換行＋等寬數字對齊）；控制/動作欄 .col-ctl（固定窄寬、置中）。
   讓各表數字欄比例/對齊一致（見 DESIGN.md：所有表用 .data-table，數字欄標 .num）。 */
.data-table th.num, .data-table td.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* 資料數字一律等寬（Geist Mono）：金額、罰鍰、字號、比率直欄對得齊，且數字更新時不會左右晃。
   中文沒有 Mono 字形會逐字 fallback 回 Noto Sans TC＝混排安全。表頭是中文標籤，刻意不套。
   `.mono` 是給表格外的代號／字號／ID 用的通用 class（別再逐處 inline font-family）。 */
.data-table td.num, .mono { font-family: var(--mono); }
/* .num 欄裡的輸入框（AI 模型的單價）：框靠右了、框裡的數字卻靠左＝同一欄兩種對齊。 */
.data-table td.num input { text-align: right; }
.data-table th.col-ctl, .data-table td.col-ctl { width: 1%; white-space: nowrap; text-align: center; }
/* 表格內的下拉：全站 select 預設 width:100%，在窄欄位裡會把選項文字截斷（「已完成修正」被切掉）
   → 表格內改成隨內容寬，欄位再窄也讀得完整。 */
.data-table td select { width: auto; max-width: 100%; }
.data-table td.detail { color: var(--muted-2); max-width: 460px; }
/* 列首格（tbody 裡的 th，工作日誌／使用者工作紀錄的「日期」那一欄）：上面那條 th 規則是給表頭的，
   它的 --line-strong 下緣會讓每一列的分隔線在標籤欄與資料欄之間一深一淺斷開（2026-10-01 二輪體檢）。 */
.data-table tbody th { border-bottom-color: var(--line); }
/* 合併格（rowspan）不吃列 hover：它屬於群組第一列的 <tr>，滑到第一列就會整塊（含底下幾列旁邊）一起反白
   （2026-10-01 回饋：當週議題的日期格、Time Report 合併時段同病）。 */
/* 空狀態列（td.empty）也不吃：那一列不能點，反白等於暗示能點。 */
.data-table tr:hover td:not([rowspan], .empty), .data-table tbody tr:hover th:not([rowspan]) { background: var(--panel-2); }
/* 停用的列（tr.is-off）：只淡化資料格的內容，不淡化格子本身——opacity 掛在 td 會連列底色一起變淡，
   沒淡化的狀態欄／操作欄就成了兩大塊深色反白（2026-10-02 使用者管理回報）。 */
.data-table tr.is-off td.fade > * { opacity: .5; }
/* 列尾動作格：30px 小鈕＋上下 2px 外距＝34px，比一行字（22.4px）高，貼頂時鈕裡的字比同列文字低約 6px。
   上下內距收成 6px＝鈕的中線對齊第一行字、列高也跟純文字列一樣（6+34+6≈12+22.4+12）。 */
.data-table td.row-actions, .data-table td:has(> .row-actions) { padding-block: 6px; }
/* 大表（操作紀錄/稽核軌跡近千列）原生視窗化：畫面外的列略過 layout/paint，列全留在 DOM。
   時間/操作欄 nowrap、詳細欄有 max-width，捲動時欄寬幾乎不跳。 */
.data-table tbody tr { content-visibility: auto; contain-intrinsic-size: auto 44px; }
/* 使用者管理表：列可展開常用 IP（高列＋內嵌子表）→ 關掉視窗化，避免 44px 估高對高列造成跑版（同 .mirror-view）。列數少不需視窗化。 */
.users-table tbody tr { content-visibility: visible; contain-intrinsic-size: auto; }
/* 列展開鈕（使用者表、操作稽核紀錄）：chevron-right，展開時依 aria-expanded 轉 90° 朝下。取代文字 ▸／▾。 */
.row-caret { display: inline-flex; align-items: center; justify-content: center; flex: none; vertical-align: middle; min-height: 0; padding: 2px;
  border: 0; border-radius: var(--r-xs); background: none; color: var(--muted-2); }
.row-caret:hover { background: var(--panel-2); color: var(--text); }
.row-caret svg { transition: transform var(--tr); }
.row-caret[aria-expanded="true"] svg { transform: rotate(90deg); }
/* 動作按鈕列：<td> 一律保持 table-cell——別在 <td> 上用 display:flex。本表 border-collapse:collapse，
   flex cell 會脫離邊框合併模型 → 該欄的列分隔線／邊框不連續，右側整欄看起來「凹進一塊」。
   按鈕改 inline-block＋間距水平排列，必要時自動換行（取代原 flex gap/wrap）。 */
.row-actions > * { display: inline-block; vertical-align: middle; margin: 2px 6px 2px 0; }
/* <a class="btnlink">（下載）與帶圖示的 .btn-ic 本來就是 inline-flex（字／圖示垂直置中）：被上一條壓成 inline-block 的話，
   30px 高的 <a> 字會貼頂，跟旁邊 <button> 的字對不上。 */
.row-actions > :is(.btnlink, .btn-ic) { display: inline-flex; }
.row-actions > *:last-child { margin-right: 0; }
/* 列內動作鈕一律「無框次要」：呼叫端歷來一半寫 `small`（描邊）一半寫 `ghost small`（無框），
   同一格兩顆長不一樣。這裡用 CSS 收斂，比逐一改 150 多個呼叫點可靠（且不會再飄回去）。
   只收「已宣告 small/ghost 變體」的鈕＝表格裡自帶樣式的小工具（展開鈕、狀態切換）不受影響。
   連尺寸也收：框 0、左右 10px（原本 small 帶 1px 透明框、ghost 是 8px＝同一欄每顆鈕的字起點都不同），
   下面的動作欄才能用固定的 10px 把字拉回表頭那條線。<a class="btnlink">（下載）算同一種鈕。
   .primary 不吃灰字與 hover 灰底：原本兩條都比 .primary 那條特異，填色小鈕在表格裡變成灰字、hover 變灰底白字。 */
.data-table td button.small, .data-table td button.ghost, .data-table td a.btnlink, .row-actions > :is(button, a.btnlink) {
  border-width: 0; background: transparent; box-shadow: none; padding-inline: 10px;
}
.data-table td button.small:not(.danger, .primary), .data-table td button.ghost:not(.danger, .primary),
.data-table td a.btnlink:not(.danger, .primary), .row-actions > :is(button, a.btnlink):not(.danger, .primary) {
  color: var(--muted-2);
}
.data-table td button.small:not(.primary):hover, .data-table td button.ghost:not(.primary):hover,
.data-table td a.btnlink:not(.primary):hover, .row-actions > :is(button, a.btnlink):not(.primary):hover {
  background: var(--panel-2);
}
.data-table td button.danger:not(.primary):hover, .row-actions > button.danger:not(.primary):hover { background: var(--red-bg); }
.data-table td button.primary, .row-actions > button.primary {
  border-color: var(--primary); background: var(--primary); color: var(--on-primary,#fff);
}
/* 動作欄的鈕字對齊表頭字（2026-10-01 回報：機器開關「操作」標題跟「編輯／停用／刪除」對不齊、
   假日表的「刪除」看起來置中）：無框鈕的字離鈕緣 10px，鈕又貼著格子內距排 ⇒ 字比表頭右縮 10px。
   動作格的左內距少給這 10px＝每一排第一顆鈕的字都落在表頭字那條線上（折到第二排也一樣），hover 底色仍是整顆鈕。
   第一顆是填色鈕（.primary）就不收——它的框本身就是看得見的左緣。置中的 .col-ctl 不在此列。 */
.data-table td.row-actions:not(.col-ctl):not(:has(> .primary:first-child)) { padding-inline-start: calc(var(--cell-px) - 10px); }
.data-table td:not(.col-ctl) > .row-actions:not(:has(> .primary:first-child)) { margin-inline-start: -10px; }

/* ---------- Review ---------- */
.review-wrap { display: grid; gap: 8px; }
.layout { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 24px; }
.sidebar { align-self: start; display: grid; gap: 12px; }
.stat { border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--panel); padding: 14px; }
/* 統計卡（canonical metric card，見 DESIGN.md）：大數字在上、灰字標籤在下、置中。
   全站 metric 一律用 .stat（DOM 順序＝[<strong>數字, <span>標籤]）；容器可 .stat-row(2 欄) 或 flex 列(3+ 欄)。 */
.stat-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.stat { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 3px; }
/* 統計磚的大數字＝內文字型（Geist）＋tabular-nums：等寬對齊照樣有，但 0 是一般的 0。原本用 --mono（Geist Mono），
   它的 0 中間帶斜線，放到 28px 就像「Ø」（2026-10-02 回報）。表格數字欄、字號、代號維持等寬字（.num／.mono）。 */
.stat strong { font-size: var(--fs-h1); color: var(--text); letter-spacing: -.5px; font-variant-numeric: tabular-nums; }
.stat span { color: var(--muted); font-size: var(--fs-md); }
/* 覆核頁側欄篩選：狀態／領域／只看我負責的收在同一張卡（原本三張各自有框＝疊成一串碎卡）。
   欄位標籤＝field() 的灰字、再縮一階成小標；勾選列用一條 hairline 與上面的下拉隔開。 */
.filters { display: grid; gap: 12px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--panel); padding: var(--sp-3); }
.filters .field { font-size: var(--fs-sm); }
/* 側欄的篩選選單撐滿欄寬（同原本的下拉），值靠左、箭頭靠右 */
.filters .fm, .filters .fm-btn { width: 100%; }
.filters .fm-btn > .fm-tx { flex: 1; text-align: left; }
.filter-check { display: flex; align-items: center; gap: 8px; padding-top: 12px; border-top: 1px solid var(--line);
  color: var(--muted-2); font-size: var(--fs-md); cursor: pointer; }

/* 快速跳題清單（現只用於懸浮導覽抽屜；標題列沿用 .jump-title） */
.jump-title { display: flex; align-items: center; gap: 6px; }
/* flex 直欄，非 grid：grid + max-height 會把每列 track 壓成 16px、文字溢出盒子（反白框對不上字）。 */
.jump-list { display: flex; flex-direction: column; gap: 4px; max-height: 320px; overflow: auto; }
/* content-visibility：瀏覽器原生「視窗化」——清單全部列都留在 DOM（可捲動/跳題/搜尋不變），
   但畫面外的列略過 layout/paint。contain-intrinsic-size 給估高，讓捲軸長度與捲動仍正確。
   3000+ 筆時進頁的首次渲染成本大幅下降，且零 UX 改變（免自寫虛擬清單）。 */
.jump-item { flex: none; display: grid; grid-template-columns: 18px auto 1fr; align-items: center; gap: 8px; width: 100%; text-align: left; border: 1px solid transparent; border-radius: var(--r-xs); background: transparent; padding: 7px 8px; min-height: 0; font-size: var(--fs-sm); color: var(--text); content-visibility: auto; contain-intrinsic-size: auto 32px; }
.jump-item:hover { background: var(--panel-2); }
.jump-item.done:not(.active) { opacity: .6; }
.jump-item.active { border-color: var(--primary); background: var(--panel-3); font-weight: 700; }
.jump-mark { text-align: center; color: var(--muted); }
.jump-mark.confirmed { color: var(--green); }
.jump-mark.changed { color: var(--primary-hover); }
.jump-mark.pending { color: var(--amber); }
.jump-id { color: var(--muted); white-space: nowrap; }
.jump-cp { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* cp_update 更新覆核「二、法令雖有修正但管控重點無須更新」「三、無須覆核」的清單視圖。
   這兩類是掃視型工作（多數不必動內容），逐條翻頁的資訊密度是錯的 → 一頁看很多條、
   點列才就地展開完整卡片（重用 cardFor，編輯能力不變）。欄：記號／編號／《法規》內容／狀態。
   坑：列是 <button>，全站 tap-target min-height:40px 會把它撐高 → 必須 min-height:0。 */
/* 管控重點更新覆核頁「只看我負責的」（setup.js renderLaw paintOverall）：有被指派條目才出現。 */
.cp-mine { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 16px; margin: 8px 0 0; }
.cp-mine label { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: var(--fs-md); }
.cpl-list { display: flex; flex-direction: column; gap: 4px; }
.cpl-row { display: grid; grid-template-columns: 18px auto 1fr auto; align-items: center; gap: 8px; width: 100%;
  text-align: left; border: 1px solid transparent; border-radius: var(--r-xs); background: transparent;
  padding: 8px; min-height: 0; font-size: var(--fs-sm); color: var(--text); cursor: pointer;
  content-visibility: auto; contain-intrinsic-size: auto 36px; }
.cpl-row:hover { background: var(--panel-2); }
.cpl-row.done { opacity: .65; }
.cpl-row.open { border-color: var(--primary); background: var(--panel-3); opacity: 1; }
.cpl-cp { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cpl-detail { padding: 0 0 .6rem; }
.cpl-row .lc-rowtail { display: inline-flex; align-items: center; gap: 6px; }

/* 管控重點更新覆核頁「本期法規異動」卡（setup.js renderLaw）：五格數字卡＝.pi-stats/.stat，點格展開依法規分組的清單。 */
.lc-card { margin-bottom: .6rem; display: flex; flex-direction: column; gap: 10px; }
.lc-head { display: flex; align-items: center; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; }
.lc-since { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; color: var(--amber); font-size: var(--fs-sm); }
.lc-stats { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.lc-stat { font: inherit; color: inherit; min-height: 0; cursor: pointer; }
.lc-stat:hover { border-color: var(--line-strong); }
.lc-stat[aria-pressed="true"] { border-color: var(--primary); background: var(--panel-3); }
.lc-impact { margin: 0; font-size: var(--fs-md); color: var(--muted-2); }
.lc-link { min-height: 0; padding: 0; border: 0; background: none; color: var(--primary-hover); font: inherit; cursor: pointer; --press-scale: 1; }
.lc-link:hover { background: none; text-decoration: underline; }
.lc-uploads { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.lc-err, .lc-fail { display: flex; align-items: center; gap: 8px 12px; flex-wrap: wrap; }
.lc-err > span { color: var(--red); }
.lc-fail { margin-bottom: .6rem; }
.lc-fail > strong { color: var(--red); }
.lc-list { display: flex; flex-direction: column; gap: 2px; border-top: 1px solid var(--line); padding-top: 8px; }
.lc-law { display: flex; align-items: center; gap: 8px; padding: 8px; border-radius: var(--r-xs); cursor: pointer; font-size: var(--fs-md); }
.lc-law:hover { background: var(--panel-2); }
.lc-caret { flex: none; color: var(--muted); transition: transform var(--dur-1) var(--ease-out); }
.lc-law[aria-expanded="true"] .lc-caret { transform: rotate(90deg); }
.lc-law > span:last-child { flex: none; white-space: nowrap; }   /* 「修正 3 處」：手機上法規名長，別被擠成兩行 */
.lc-unit { display: flex; align-items: center; gap: 8px 12px; padding: 6px 8px; font-size: var(--fs-sm); }
.lc-unit.lc-sub { padding-left: 31px; }
.lc-unit-l { flex: 1; min-width: 0; }
.lc-unit-r { flex: none; display: inline-flex; align-items: center; gap: 6px; }
.lc-reason { margin-top: 2px; }
.lc-cps { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.lc-cp { cursor: pointer; min-height: 0; }   /* 按鈕全站 40px 觸控高度會把 chip 撐成圓餅 */
.lc-preview { margin-top: .35rem; min-height: 1lh; }

/* 懸浮跳題導覽（覆核頁；跟法條頁條文目錄同款）。側欄清單會隨頁面捲離視野，
   此鈕 position:fixed 常駐右緣中段，覆核到任何位置都能開抽屜跳題。
   規格與 penalty 的 .law-fab 共用：44px 正圓、右 16px 垂直置中、品牌色、--sh-2（在 corner-shape:round 清單裡）。 */
.review-jump-fab { position: fixed; right: 16px; top: 50%; transform: translateY(-50%); z-index: 60;
  width: 44px; height: 44px; min-height: 0; padding: 0; border-radius: 50%; border: 1px solid transparent;
  background: var(--primary); color: var(--on-primary, #fff); cursor: pointer;
  display: flex; align-items: center; justify-content: center; box-shadow: var(--sh-2); }
/* 全域 button:hover 會換成 --panel-2 底：不蓋掉的話 hover 變灰鈕。按下＝全域的 scale（獨立屬性，不碰這顆用來垂直置中的 transform）。 */
.review-jump-fab:hover { background: var(--primary); border-color: transparent; filter: brightness(1.08); }
.review-jump-fab.active { background: var(--panel-2); color: var(--text); border-color: var(--primary); }
/* ── 右側抽屜共用：材質＋進出場（覆核跳題／使用說明／Skill 內容／簡報詳情；2026-10-01 使用說明抽屜先做，其餘 10-02 跟進）──
   材質＝厚（--mat-thick）：抽屜裡是要讀的字，只透一點點背後的頁面＝知道自己還在原頁（HIG：thicker materials 給文字）。
   打開＝不過衝的彈簧滑入（--dur-3 --spring-soft），收起＝較短的 --dur-2 ease-out；從右緣進、回右緣出（開它的鈕都在右邊）。
   收起要 visibility:hidden：只推出畫面外的話，影子還會畫進視窗右緣一條，裡面的連結也還能被 Tab 走進去。
   打開時 visibility 立刻生效（開完馬上 focus 搜尋框才找得到），收起時等滑出結束才藏。
   @starting-style＝抽屜在打開的同一拍才被建出來時也有起點可以滑（使用說明第一次開原本是直接跳出來的）。
   位置／寬度／z-index 各自寫在下面；penalty 的法條目錄／沿革／裁罰內文在 views/penalty/styles.js 有同一套。 */
:is(.review-jump-drawer, .help-drawer, .skill-drawer, .deck-drawer) {
  background: var(--mat-thick); -webkit-backdrop-filter: var(--mat-blur); backdrop-filter: var(--mat-blur);
  border-left: 1px solid var(--mat-edge); box-shadow: var(--sh-3);
  transform: translateX(100%); visibility: hidden;
  transition: transform var(--dur-2) var(--ease-out), visibility 0s linear var(--dur-2);
}
:is(.review-jump-drawer, .help-drawer, .skill-drawer, .deck-drawer)[aria-hidden="false"] {
  transform: none; visibility: visible; transition: transform var(--dur-3) var(--spring-soft), visibility 0s;
}
@starting-style { :is(.review-jump-drawer, .help-drawer, .skill-drawer, .deck-drawer)[aria-hidden="false"] { transform: translateX(100%); } }
.review-jump-drawer { position: fixed; top: 0; right: 0; height: 100vh; height: 100dvh; width: 320px; max-width: 86vw; z-index: 61;
  display: flex; flex-direction: column; }
.review-jump-drawer .rjd-head { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 14px 16px; border-bottom: 1px solid var(--line); font-weight: 650; color: var(--text); }
.review-jump-drawer .rjd-search { padding: 10px 12px; border-bottom: 1px solid var(--line); }
.review-jump-drawer .rjd-search input { width: 100%; }
.review-jump-drawer .jump-list { max-height: none; flex: 1 1 auto; min-height: 0; padding: 8px; }
.review-jump-scrim { position: fixed; inset: 0; z-index: 60; background: rgba(0, 0, 0, .35); opacity: 0; pointer-events: none; transition: opacity var(--dur-2) var(--ease-out); }
.review-jump-scrim.show { opacity: 1; pointer-events: auto; }

/* ---- 使用說明抽屜（右上角 (i)；見 help_drawer.js）---------------------------
   與上面的跳題抽屜同款右側滑入，但**桌面刻意不加遮罩**：抽屜開著時左邊頁面照常
   可點可填，價值就是「一邊看教學一邊照著做」。手機才由 .help-scrim.show 蓋上遮罩。 */
/* 材質與進出場＝上面「右側抽屜共用」那段（從右上角那顆 (i) 的方向進來、回同一個方向出去）。 */
:root { --help-w: 420px; }
.help-drawer { position: fixed; top: 0; right: 0; height: 100dvh; width: var(--help-w); max-width: 92vw; z-index: 71;
  display: flex; flex-direction: column; padding-top: env(safe-area-inset-top, 0px); }
.help-scrim { position: fixed; inset: 0; z-index: 70; background: rgba(0, 0, 0, .35); opacity: 0; pointer-events: none; transition: opacity var(--dur-2) var(--ease-out); }
.help-scrim.show { opacity: 1; pointer-events: auto; }
/* 桌面「邊看邊做」（2026-10-02；原本從視窗最上緣蓋下來，(i)／鈴鐺／個人資料與頁面右上的「＋ 新增」全被蓋住）：
   ①抽屜從頂欄下緣開始（頂欄高度由 help_drawer.js 量給 --topbar-h）；頂欄在抽屜開著時抬到抽屜上面，
     它的下拉（專案、鈴鐺）才不會開在抽屜底下。②寬螢幕把頁面往左推出抽屜的寬度（推開，不是蓋住）；
     再窄就照舊疊在頁面上。手機（≤720px）維持全幅＋遮罩，見檔尾。body.help-open 由 help_drawer.js 切。 */
@media (min-width: 721px) {
  .help-drawer { top: var(--topbar-h, 0px); bottom: 0; height: auto; }
  body.help-open .topbar { z-index: 72; }
}
@media (min-width: 1100px) {
  body.help-open .view { margin-right: var(--help-w); }
}
/* 頭列／分頁列／搜尋／底部求助列都不可被壓縮：視窗矮時 flex 預設 shrink 會把分頁列壓成一條
   （實測 575px 高的視窗：clientHeight 17 vs scrollHeight 38，文字被切一半）。只有內容區可伸縮。 */
.help-drawer > .help-head, .help-drawer > .seg, .help-drawer > .help-search, .help-drawer > .help-foot { flex: 0 0 auto; }
.help-head { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 14px 16px; border-bottom: 1px solid var(--line); }
.help-title { font-weight: 650; color: var(--text); }
.help-search { padding: 10px 12px; border-bottom: 1px solid var(--line); }
.help-search input { width: 100%; }
.help-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 8px 6px 8px 8px; }   /* 捲到底不連動背後的頁面 */
.help-foot { border-top: 1px solid var(--line); padding: 10px 14px calc(10px + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: var(--fs-sm); }   /* 提示字與連結同一級（連結 font:inherit，原本吃到抽屜本文的字級＝比提示字大一截） */

/* 三層目錄列：一律 <button>＋顯式 display（本站全域 CSS 讓原生 <details> 不收合） */
.help-row { display: flex; align-items: center; gap: 6px; width: 100%; min-height: 0;
  background: none; border: none; border-radius: var(--r-sm); cursor: pointer; text-align: left;
  color: var(--text); padding: 7px 8px; font: inherit; }
.help-row:hover { background: var(--panel-2); }
.help-caret { display: flex; color: var(--muted); transition: transform var(--tr-fast) var(--ease); flex: 0 0 auto; }
.help-row[aria-expanded="true"] > .help-caret { transform: rotate(90deg); }
.help-label { flex: 1 1 auto; min-width: 0; }
.help-g > .help-label { font-weight: 650; letter-spacing: -.01em; }
.help-f { padding-left: 18px; }
.help-f.cur { border-left: 2px solid var(--primary); background: var(--primary-bg); }
.help-s { padding-left: 34px; color: var(--muted-2); font-size: var(--fs-sm); }
.help-badge { flex: 0 0 auto; font-size: var(--fs-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
.help-here { flex: 0 0 auto; font-size: var(--fs-xs); }

/* 就地展開的內容 */
.help-meta { margin: 2px 0 6px 34px; color: var(--muted); font-size: var(--fs-xs); }
.help-text, .help-muted { margin: 0 8px 10px 34px; font-size: var(--fs-sm); line-height: 1.75; }
.help-muted { color: var(--muted); }
.help-steps { margin: 0 8px 10px 34px; padding-left: 1.2em; font-size: var(--fs-sm); line-height: 1.75; }
.help-steps li { margin-bottom: 10px; }
.help-shot { display: block; margin-top: 6px; max-width: 100%; border: 1px solid var(--line); border-radius: var(--r-sm); cursor: zoom-in; }
.help-shot:hover { border-color: var(--primary); }
.help-dl { margin: 0 8px 10px 34px; font-size: var(--fs-sm); }
.help-dl dt { font-weight: 600; color: var(--text); margin-top: 8px; }
.help-dl dd { margin: 2px 0 0; color: var(--muted-2); line-height: 1.7; font-weight: 400; }   /* 全域 dd 是 700：說明內文不該整段粗體 */
.help-log { list-style: none; margin: 0 8px 10px 34px; padding: 0; font-size: var(--fs-sm); }
.help-log li { display: flex; gap: 8px; flex-wrap: wrap; padding: 4px 0; color: var(--muted-2); }
.help-log-all { margin-left: 8px; }
.help-ver { color: var(--primary); font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.help-date { color: var(--muted); font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.help-link { background: none; border: none; padding: 0; min-height: 0; color: var(--primary); cursor: pointer;
  font: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* space-between：側邊欄比卡片高時，多出的高度進 gap（不灌進 .actions 那列），
   否則 .actions 會被拉伸、按鈕高度隨每題內容長短跳動。卡片置頂、動作列固定貼底。 */
.review { display: grid; gap: 16px; align-content: space-between; }
.card { min-height: 520px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel); padding: 28px; box-shadow: var(--sh-1); }
/* 覆核換題回饋（2026-09-30）：覆核卡的內容是就地換掉的（DOM 不重建），所以連續按「下一筆」
   時畫面只有文字無聲替換、沒有任何「我換題了」的訊號——而這是這個產品一天按上百次的動作。
   補一個 140ms 的方向性淡入：下一筆從右邊進、上一筆從左邊進。
   ①只動 transform/opacity（合成層），不碰 layout；②`.actions` 是 .card 的**兄弟節點**、
   不在動畫裡，所以按鈕不會跟著位移＝連續快速點擊不會誤點；③reduced-motion 由本檔最底下的
   全域 blanket 關掉。位移只有 10px 是刻意的：要的是方向感，不是表演。 */
@keyframes card-in-next { from { opacity: 0; transform: translateX(10px); } }
@keyframes card-in-prev { from { opacity: 0; transform: translateX(-10px); } }
.card-in-next { animation: card-in-next .14s var(--ease); }
.card-in-prev { animation: card-in-prev .14s var(--ease); }
.card-head { display: flex; justify-content: space-between; gap: 12px; color: var(--muted); font-size: var(--fs-md); }
/* .badge 的外形規則已與 .tag 合併（見上）；這裡只留語意變體。 */
/* 覆核備註標記：本條有人工註記（如法規廢止/修正）時亮起。 */
.note-badge { background: var(--amber-bg); color: var(--amber); border: 1px solid var(--amber-line); }
.reviewer-line { margin: 8px 0 0; }
.meta { margin: 22px 0 8px; color: var(--muted); line-height: 1.5; }
.control-point { margin: 0 0 24px; font-size: var(--fs-h1); line-height: 1.4; letter-spacing: -.6px; white-space: pre-wrap; }
.recheck-banner { margin: 0 0 6px; padding: 8px 12px; border-radius: var(--r-sm); font-size: var(--fs-sm); font-weight: 600; color: var(--amber); background: var(--amber-bg); border: 1px solid var(--amber-line); }
/* 管控重點編號／條文號碼參照：麵包屑（.meta）下方一列 key–value——值只有幾個字，原本各佔一個大框＝框比字大。 */
.details { display: flex; flex-wrap: wrap; gap: 4px 24px; margin: 0 0 12px; font-size: var(--fs-md); }
.details div { display: flex; align-items: baseline; gap: 8px; }
.details dd { margin: 0; font-weight: 500; color: var(--text); }
dt { color: var(--muted); font-size: var(--fs-sm); }
dd { margin: 4px 0 0; font-weight: 700; }
h3 { margin: 0 0 10px; font-size: var(--fs-body); letter-spacing: -.01em; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip { display: inline-flex; align-items: center; gap: 5px; border-radius: var(--r-pill); background: var(--panel-2); padding: 4px 6px 4px 10px; font-size: var(--fs-sm); line-height: 1.6; color: var(--text); }
.chip.added { background: var(--green-bg); color: var(--green); }
.chip.removed { background: var(--red-bg); color: var(--red); }
.chip.removed .chip-label { text-decoration: line-through; }
/* chip 內的 ×／＋ 小鈕：無邊框透明、繼承 chip 顏色、圓形；覆蓋全域 button 的 40px tap target */
.chip-x { display: inline-flex; align-items: center; justify-content: center; min-height: 0; width: 18px; height: 18px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: inherit; opacity: .6; }
.chip-x:hover { opacity: 1; background: color-mix(in srgb, currentColor 20%, transparent); }
.chip-add { min-height: 0; padding: 5px 10px 5px 8px; border: 1px dashed var(--line); background: transparent; color: var(--muted); }
.chip-add:hover { color: var(--text); border-color: var(--muted); background: transparent; }
.chip-add-ic { display: inline-flex; align-items: center; }
.add-domain-list { display: flex; flex-direction: column; gap: 4px; max-height: 56vh; overflow: auto; padding: 2px; margin-top: 8px; }
/* flex-shrink:0：清單是 max-height 的 flex column，不加會被壓扁到內容溢出、與下一列重疊 */
.add-domain-item { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; flex-shrink: 0; text-align: left; min-height: 0; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--panel); }
.add-domain-item:hover { border-color: var(--primary-hover); background: var(--panel-2); }
.add-domain-item small { color: var(--muted); font-size: var(--fs-xs, 0.75rem); }
.link-button { margin-top: 20px; min-height: 0; border: 0; background: transparent; color: var(--primary-hover); padding: 0; }
.reference { display: grid; gap: 10px; margin-top: 14px; max-height: 260px; overflow: auto; }
.reference-item { border: 1px solid var(--line); border-radius: var(--r-sm); padding: 12px; }
.reference-item strong { display: block; margin-bottom: 4px; }
.reference-item p { margin: 4px 0; color: var(--muted); line-height: 1.45; }
.hidden { display: none; }
/* 改 flex（原 7 等分格）＝按鈕依內容寬、不再是「7 顆等寬牆」；上/下一筆用 margin-auto 推到兩端分組，
   中間 5 顆聚攏、確認無誤(primary)為視覺焦點（見 review.js 的 margin-inline-*）。 */
/* 黏底列＝材質（--mat-bar＋--mat-blur，同頂欄）：捲動時卡片內容從它後面模糊地滑過，知道下面還有東西。 */
.actions {
  position: sticky; bottom: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding: 12px; border: 1px solid var(--mat-edge); border-radius: var(--r-sm);
  background: var(--mat-bar); -webkit-backdrop-filter: var(--mat-blur); backdrop-filter: var(--mat-blur);
}
.actions button { padding: 0 14px; }

/* ---------- 個人資料 header ---------- */
/* 頭貼可點擊更換：上半＝照片(點放大)，下方 ≈41.4% 灰色半透明帶＋相機 icon(點上傳)；上:下≈√2:1。 */
.pf-header { display: flex; align-items: center; gap: 14px; }
.pf-namecol { display: grid; gap: .4rem; min-width: 0; }
.pf-nameline { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.pf-name { font-size: var(--fs-h3); font-weight: 600; letter-spacing: -.2px; color: var(--text); }
.ava-edit { position: relative; width: 84px; height: 84px; flex: 0 0 auto; border-radius: 50%; overflow: hidden; border: 1px solid var(--line); background: var(--panel-2); }
.ava-edit img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ava-edit-ph { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: var(--fs-h1); font-weight: 600; }
.ava-edit-ovl { position: absolute; left: 0; right: 0; bottom: 0; height: 41.4%; display: flex; align-items: center; justify-content: center;
  padding: 0; min-height: 0; border: 0; border-radius: 0; background: rgba(0,0,0,.42); color: #fff; cursor: pointer; box-shadow: none; transition: background var(--tr); }
.ava-edit-ovl:hover { background: rgba(0,0,0,.62); }
.ava-edit-ovl:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--primary); }
.ava-edit-ovl svg { width: 15px; height: 15px; display: block; }

/* ---------- Dialog ---------- */
/* 對話框底色：深色＝往上抬一階（--panel-2）；淺色的「浮起來」靠白底＋陰影，借 --panel-2 會是一塊灰泥
   （2026-09-30 體檢：建立專案／發布公告／個人資料都灰撲撲的）。 */
:root { --dialog-bg: var(--panel-2); }
:root[data-theme="light"] { --dialog-bg: var(--panel); }
/* 進出場（2026-10-02 蘋果質感地基）：transition＋@starting-style，不用 @keyframes——被打斷（剛開就關）會從當下的樣子轉回去，不會跳。
   進場＝透明度 --dur-2 ease-out＋從 .98 放大走彈簧（--dur-3 --spring）；退場＝兩者都 --dur-2 ease-out（下方 @supports 段）。
   縮放用獨立的 scale 屬性：減少動態的全站 blanket 會把它設 none。圖片檢視器只淡入淡出——它的 JS 用 getBoundingClientRect
   算縮放夾限，dialog 本身一縮放就量歪（見下方 .img-viewer）。 */
.app-dialog { width: min(820px, calc(100vw - 24px)); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 0; background: var(--dialog-bg); color: var(--text); box-shadow: var(--sh-3);
  transition: opacity var(--dur-2) var(--ease-out), scale var(--dur-3) var(--spring); }
/* 遮罩＝淡版材質：比原本的 .6 黑淺一截、多一點模糊——知道後面還是原頁，又不會透出字來搶注意力。淺色另給偏冷的墨色（見下）。 */
.app-dialog::backdrop { background: var(--scrim, rgba(0,0,0,.5)); -webkit-backdrop-filter: blur(6px) saturate(140%); backdrop-filter: blur(6px) saturate(140%);
  transition: opacity var(--dur-2) var(--ease-out); }
:root { --scrim: rgba(0,0,0,.5); }
:root[data-theme="light"] { --scrim: rgba(16,24,40,.38); }
@starting-style {
  .app-dialog[open], .app-dialog[open]::backdrop { opacity: 0; }
  .app-dialog[open]:not(.img-viewer) { scale: .98; }
}
/* 退場（2026-09-30；原本一關就瞬間消失）：關閉後 overlay／display 以 allow-discrete 多留 --dur-2 在 top layer，
   淡出並縮回進場的起點；util.js mountDialog 讀同一個 --dur-2 才拆節點（JS 不另寫數字）。遮罩同樣淡出。
   沒有 overlay 屬性的瀏覽器不做——關閉當下就離開 top layer，還留著 display 會閃在頁尾（mountDialog 也照舊立刻拆）。
   關閉那一刻 :modal 就不成立，UA 給 modal 的定位與尺寸上限跟著消失，退場途中會跳位 → 這裡先寫死同一組值。 */
@supports (overlay: auto) {
  .app-dialog { position: fixed; inset-block: 0; max-width: calc(100% - 6px - 2em); max-height: calc(100% - 6px - 2em); overflow: auto; }
  .app-dialog:not([open]), .app-dialog:not([open])::backdrop {
    opacity: 0; pointer-events: none;
    transition: opacity var(--dur-2) var(--ease-out), scale var(--dur-2) var(--ease-out),
      overlay var(--dur-2) allow-discrete, display var(--dur-2) allow-discrete;
  }
  .app-dialog:not([open], .img-viewer) { scale: .98; }
}
/* 對話框裡的多行輸入至少三行高：field-sizing:content 沒字時只有一行，看起來像單行欄位（公告內容／許願內容／備註）。 */
.app-dialog textarea { min-height: calc(3lh + 20px); }
/* 內距：form（modal()）與 .dialog-wrap（dialog() 的非 form 外殼）同款，別再逐處 inline padding:22px。
   只給「直接掛在 dialog 下」的 form：外殼裡再包一層 form（個人資料的改密碼頁）原本也吃到 22px＝整張表單往內縮一截、跟標題對不齊。 */
.app-dialog > form, .app-dialog > .dialog-wrap { padding: 22px; }
.dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* 動作列一律右對齊（原本 space-between＝單顆鈕靠左，各頁再 inline 覆寫成 flex-end＝同一顆鈕左右不一）。
   要把某顆鈕推到左緣（如刪除）就給它 margin-inline-end:auto。 */
.dialog-actions { display: flex; align-items: center; justify-content: flex-end; gap: 12px; }
/* 對話框開著時的錯誤（util.js toast(msg,'error') 自動寫進來）：動作列左側紅字，佔掉剩下的寬度把按鈕留在右邊。 */
.dialog-error { flex: 1 1 auto; min-width: 0; margin: 0; color: var(--red); font-size: var(--fs-sm); line-height: 1.45; text-align: left; }
.dialog-head h2 { margin: 0; font-size: var(--fs-h2); }
/* 內容區可捲。上限原本是 66vh＝1000px 高的視窗白留 200px、表單一長就得捲；改成「扣掉頭列＋動作列＋內距」
   的實際可用高度（約 200px），同樣不會超出視窗，但少捲很多。dvh 為手機網址列收合準備，vh 為舊瀏覽器 fallback。 */
.dialog-body { margin: 16px 0; max-height: calc(100vh - 200px); max-height: calc(100dvh - 200px); overflow: auto; display: grid; gap: 12px; }
/* 對話框本文裡的分頁列（segTabs 直接放進 dialog()／modal() 的 body，例：問卷產製「範本管理」）：本文已用 gap 隔開（12px），
   分頁列自己那段給頁面用的下距（--sp-4）再疊上去＝分頁列與內容之間空 36px。在對話框裡一律只留 gap。
   寫在對話框這一側、特異度壓過分頁列自己的外距規則（含二級 .seg-sub），不必逐個對話框補（原本範本管理是拿掉表格的上距）。 */
.app-dialog .dialog-body > .seg.seg-bar { margin-bottom: 0; }
/* 修改標註對話框頂端：唯讀管控重點預覽，sticky 釘在可視上緣，捲領域清單時本文仍在。 */
.cp-preview { position: sticky; top: 0; z-index: 1; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 10px 12px; max-height: 30vh; overflow: auto; }
.cp-preview-id { display: block; color: var(--muted); font-size: var(--fs-xs); margin-bottom: 4px; }
.cp-preview p { margin: 0; white-space: pre-wrap; line-height: 1.5; color: var(--text); }
/* 確認對話框：比一般 app-dialog 窄；破壞性動作的確定鈕填紅。 */
.confirm-dialog { width: min(420px, calc(100vw - 24px)); }
/* 個人資料（main.js openProfile）：兩頁（個人資料／修改密碼）疊在同一格，沒顯示的那頁只是看不見（visibility）、照樣佔位
   ⇒ 對話框一直是兩頁中較高的那個尺寸，切頁時不會一下長一下短（2026-10-01 二輪體檢）。 */
.profile-dialog { width: min(480px, calc(100vw - 24px)); }
.pf-stack { display: grid; }
.pf-page { grid-area: 1 / 1; min-width: 0; }
.btn-danger { background: var(--red); border-color: var(--red); color: #fff; }
.btn-danger:hover { background: var(--red); border-color: var(--red); filter: brightness(1.08); }

/* ---------- 圖片檢視彈窗（util.js imageViewer）----------
   滿版無框 dialog：**dialog 本身就是「圖片外的空白區」**，所以「點圖外關閉」直接由 mountDialog 既有的
   `e.target === dlg` 收掉，元件零關閉邏輯；控件是 dialog 的子節點，點到它們 target 就不是 dialog＝不會關。
   ⚠️ border 必須是 0：JS 的錨點／夾限把 offsetLeft 與 getBoundingClientRect().left 當同一原點，有邊框就差一個邊框寬。
   ⚠️ 縮放的 transform 掛在內層 .iv-img，**不能掛在 dialog 上**；dialog 本身也不縮放（上面 .app-dialog 的進出場
      縮放排除了 .img-viewer，只淡入淡出）：一縮放 getBoundingClientRect 就跟版面座標對不上。 */
.app-dialog.img-viewer { inset: 0; width: auto; height: auto; max-width: none; max-height: none; margin: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 60px 12px; box-sizing: border-box;      /* 上下留白＝×與工具列的位置，圖片不被壓住 */
  border: 0; border-radius: 0; background: transparent; box-shadow: none;
  overflow: hidden;                                 /* 放大溢出的部分裁在視窗邊＝夾限算式的可視區 */
  overscroll-behavior: contain;
  touch-action: none;                               /* 觸控交給 pointer events 自己做雙指縮放／拖曳 */ }
.app-dialog.img-viewer::backdrop { background: rgba(0,0,0,.82); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
/* flex 置中的 **static** 元素：元素盒恰好等於可見像素（沒有透明留白吃掉「點圖外關閉」），
   且 max-width/height:100% 是相對 **content box** ⇒ 上面的 padding 真的被讓出來、圖片不會鑽到
   ×／工具列底下。（曾用 `position:absolute; inset:0; margin:auto`，但 abs 定位的百分比是相對
   padding box，padding 等於沒作用 → 圖片頂到畫面上緣。） */
.iv-img { max-width: 100%; max-height: 100%; flex: 0 0 auto;
  transform-origin: center center; will-change: transform;
  user-select: none; -webkit-user-drag: none; }
.iv-img.zoomed { cursor: grab; }
.iv-img.dragging { cursor: grabbing; }
/* 控件＝疊在圖片／遮罩上的半透明黑藥丸（同 .ava-edit-ovl 的做法）。遮罩兩個主題下都是黑的，
   故這裡刻意用固定 rgba 黑而非 surface token（同 penalty 的 AI 霓虹＝token 規則的 exempt）。 */
.iv-btn { position: absolute; display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; min-height: 40px; padding: 0;
  border: 0; border-radius: var(--r-pill); background: rgba(0,0,0,.55); backdrop-filter: blur(6px);
  color: #fff; cursor: pointer; transition: background var(--tr); }
.iv-btn:hover { background: rgba(0,0,0,.78); }
.iv-btn svg { display: block; }   /* 鍵盤焦點＝全站焦點環（原本是 --ring 淡光暈，黑遮罩上幾乎看不見） */
.iv-close { top: 12px; right: 12px; }
.iv-nav { top: 50%; margin-top: -20px; }
.iv-nav.prev { left: 12px; }
.iv-nav.next { right: 12px; }
/* 工具列：− ／ 百分比（點＝還原）／ ＋。百分比即讀數＝免一顆「原尺寸」圖示又有即時回饋。 */
.iv-bar { position: absolute; left: 50%; bottom: 12px; transform: translateX(-50%);
  display: flex; align-items: center; gap: 2px; padding: 4px;
  border-radius: var(--r-pill); background: rgba(0,0,0,.55); backdrop-filter: blur(6px); }
.iv-bar .iv-btn { position: static; background: transparent; backdrop-filter: none; }
.iv-bar .iv-btn:hover { background: rgba(255,255,255,.18); }
.iv-pct { width: auto; min-width: 58px; padding: 0 10px; font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.iv-count { position: absolute; top: 12px; left: 12px; padding: 7px 12px;
  border-radius: var(--r-pill); background: rgba(0,0,0,.55); backdrop-filter: blur(6px);
  color: #fff; font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.field { display: grid; gap: 6px; color: var(--muted); font-size: var(--fs-md); }
/* 連續兩個欄位之間留 12px（＝.dialog-body 的 gap）：一般區塊（form、.panel、包一層的 div）裡，標籤原本直接貼著上一個輸入框
   （2026-10-01 二輪體檢：寄信範本、建立專案的子區塊、問卷 ICRA 選項）。
   本身已用 gap 排版的容器不加（會變兩倍），橫向並排的列更不能加（第二欄會往下掉一截）：對話框本文、覆核篩選卡、Skill 表單、
   領域編輯雙欄、問卷進階欄位，以及行內寫 display:grid／display:flex 的列。:where＝零特異度，任何地方要自己定間距都蓋得掉。 */
:where(:not(.dialog-body, .filters, .skill-form, .de-fields, .qn-adv, [style*="display:grid"], [style*="display:flex"]) > .field + .field) { margin-top: 12px; }
.note { display: grid; gap: 8px; color: var(--muted); font-size: var(--fs-md); }
.domain-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.domain-choice { display: flex; align-items: flex-start; gap: 10px; border: 1px solid var(--line); border-radius: var(--r-sm); padding: 10px; }
.domain-choice input { margin-top: 3px; width: auto; min-height: 0; }
.domain-choice.added { border-color: rgba(39,166,68,.5); background: var(--green-bg); }
.domain-choice.removed { border-color: rgba(235,87,87,.5); background: var(--red-bg); }
.domain-choice small { display: block; margin-top: 4px; color: var(--muted); line-height: 1.35; }

/* ---------- Domain editor ---------- */
.domain-edit-row { display: grid; grid-template-columns: 60px 1fr; gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--line); }
.de-key { font-weight: 700; color: var(--muted); }
/* align-items:start：同一列的 .field 不被拉成等高。被拉高時，多出的高度會平分給 .field 內「標籤列」與「輸入框列」
   ⇒ 內容較短的那一格（例：空的「法規參照」）輸入框被往下推約 22px，跟隔壁「關鍵字」的框對不齊。 */
.de-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; align-items: start; }

/* ---------- Toast ---------- */
/* #toast＝堆疊容器（util.js toast()/undoToast()）：一則一個 .toast-item，最多 3 則、最新的在最下面。
   原本是單一欄位：新的 toast() 會把還沒到期的「復原」蓋掉＝那筆刪除再也救不回來。
   2026-10-01 起是 popover（top layer，蓋得過 showModal 的對話框）：inset／margin／border／padding／background／overflow
   要蓋掉瀏覽器給 [popover] 的預設（滿版置中＋白底框）。
   置中靠左右各 16px＋margin auto，不靠 left:50%＋translate：後者的可用寬度只剩半個視窗，長一點的錯誤在手機上
   被擠成 195px 寬的一長條。 */
.toast { position: fixed; inset: auto 16px 28px; width: fit-content; margin: 0 auto; z-index: 50; padding: 0;
  border: 0; background: none; color: inherit; overflow: visible;
  display: flex; flex-direction: column; align-items: center; gap: 8px; pointer-events: none; }
.toast[hidden] { display: none; }
/* 進場＝從下方 12px 彈上來（--spring）＋淡入；退場在 util.js pushToast（WAAPI，讀同一組 --dur-2／--ease-out token）。 */
.toast-item { pointer-events: auto; display: flex; align-items: center; gap: 16px; padding: 12px 20px; border-radius: var(--r-sm); background: #26272c; border: 1px solid #3a3d44; color: #f7f8f8; box-shadow: var(--sh-3); font-size: var(--fs-sm);
  transition: opacity var(--dur-2) var(--ease-out), translate var(--dur-2) var(--spring); }
@starting-style { .toast-item { opacity: 0; translate: 0 12px; } }
.toast-item.error { background: var(--red); border-color: var(--red); color: #fff; }
/* undoToast 的「復原」：吐司底色固定深色，故字色跟著吐司走、不吃主題 token。 */
.toast-undo { padding: 2px 8px; min-height: 0; background: transparent; border: 0; color: inherit; font: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.toast-undo:hover { background: rgba(255,255,255,.1); }
/* 吐司讓開右側的浮層（2026-10-02）：吐司在 top layer、永遠蓋在 Bug 回報面板（body 層 z 60）與使用說明抽屜上面——不讓開就壓住
   面板的「送出」。桌機：改在面板左邊那塊置中（面板 340＋右距 18＋吐司自己的 16）；使用說明抽屜開著時改讓抽屜（排後面＝蓋過前一條）。
   貼在視窗底部、跟吐司左右重疊的（手機的膠囊／底部抽屜、黏底列、切換身分橫幅）由 util.js liftToast() 把吐司墊上去；
   漢堡選單開著時改到頂欄下方（檔尾 720px 區塊）。 */
@media (min-width: 721px) {
  body:has(> .bugpanel) .toast { right: calc(340px + 18px + 16px); }
  body.help-open .toast { right: calc(var(--help-w) + 16px); }
}

/* iOS 風格 toggle（主題切換旁的開關、裁罰資料來源頁）；原 AI 開關卡片已移除。 */
.switch { position: relative; display: inline-block; width: 44px; height: 24px; flex-shrink: 0; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .slider { position: absolute; inset: 0; background: var(--line-strong); border-radius: var(--r-pill); transition: background var(--tr); }
.switch .slider::before { content: ''; position: absolute; width: 18px; height: 18px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: transform var(--tr); box-shadow: 0 1px 2px rgba(0,0,0,.4); }
.switch input:checked + .slider { background: var(--primary); }
.switch input:checked + .slider::before { transform: translateX(20px); }
.switch input:focus-visible + .slider { outline: var(--focus-ring); outline-offset: var(--focus-offset); }   /* 同全站鍵盤焦點環（input 本身是 0×0 透明的） */

.idle-dialog { width: min(420px, calc(100vw - 24px)); }
.idle-body { padding: 24px; display: grid; gap: 10px; }
.idle-body h2 { margin: 0; }
.idle-body p { margin: 0; line-height: 1.6; }
.idle-count { font-variant-numeric: tabular-nums; color: var(--red); font-size: 1.1em; }

.wish-list { display: grid; gap: 14px; }
/* 許願卡整張不可點（動作都在卡內的按鈕上）：不浮起、不變色——浮起是「這張可以點」的記號，只給真的可點的卡（見 .project-card）。 */
.wish-card { display: grid; gap: 10px; }
.wish-imgs img { transition: transform var(--tr); }
.wish-imgs a:hover img { transform: scale(1.04); }
.wish-top { display: flex; flex-direction: column; gap: 8px; }
.wish-top h3 { margin: 0; font-size: var(--fs-h3); }
.wish-head-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
/* 手機：標題吃滿整列，日期與分類標籤換到標題下一行（原本並排＝標題只剩左半寬、一個標題斷成 4～5 行，2026-10-01 UX 實測） */
@media (max-width: 720px) { .wish-head-row { flex-direction: column; gap: 6px; } }
.wish-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; flex-shrink: 0; }
.wish-people { display: flex; flex-direction: column; gap: 4px; }
.wish-person { display: flex; align-items: center; gap: 8px; }
.wish-person-label { flex: 0 0 auto; width: 2.4em; }        /* 「發文」「覆核」對齊 */
.wish-person-name { font-size: var(--fs-sm); }
.wish-ava { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.wish-ava-ph { display: inline-flex; align-items: center; justify-content: center; background: var(--panel-3); color: var(--muted-2); font-size: var(--fs-xs); font-weight: 600; }
.wish-body { margin: 0; white-space: pre-wrap; line-height: 1.6; }
.wish-badges { display: flex; gap: 6px; flex-wrap: wrap; flex-shrink: 0; }
.wish-imgs { display: flex; gap: 8px; flex-wrap: wrap; }
.wish-imgs img { height: 96px; width: auto; border-radius: var(--r-sm); border: 1px solid var(--line); object-fit: cover; }
.wish-imgs a { cursor: zoom-in; }   /* 點＝就地開檢視彈窗（util.js bindImageViewer）；Ctrl/⌘+click 仍另開原圖 */
.wish-thumb { position: relative; display: inline-block; line-height: 0; }
.thumb-x { position: absolute; top: -6px; right: -6px; width: 20px; height: 20px; min-height: 0; padding: 0; border-radius: var(--r-pill); border: 0; background: var(--red); color: #fff; cursor: pointer; }
.wish-review { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; border-top: 1px solid var(--line); padding-top: 10px; }
.wish-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 8px; }   /* 許願卡與公告卡的動作列（編輯／釘選／刪除）同一個 */
.badge.cat-bug { background: var(--red-bg); color: var(--red); }
.badge.cat-feature { background: var(--green-bg); color: var(--green); }
.badge.cat-wontdo { background: var(--tag-bg); color: var(--muted); }
.badge.pri-p0 { background: var(--red); color: #fff; }
.badge.pri-p1 { background: var(--amber); color: #2a2300; }
.badge.pri-p2 { background: var(--tag-bg); color: var(--muted-2); }

/* ── 篩選列：篩選膠囊（util.js filterMenu）＋搜尋框（searchBox）＋期間（ympicker）─────────── */
.filter-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 4px 0 18px; }
/* 篩選列裡的勾選項（「只看失敗」）與膠囊、搜尋框同一個字級（原本吃 body 16px，比旁邊的膠囊大一號） */
.filter-bar > label { font-size: var(--fs-md); }

/* 篩選膠囊（2026-10-01 方案 A）：「分類：全部 ▾」，點開是選單；選了非預設值＝已套用（實色）。
   40px 高＝與同一列的搜尋框、期間選取器、按鈕齊高（全站單行控制項同高）。
   選單一律從膠囊正下方開（原生 <select> 的方向由作業系統決定，同一列兩個下拉一個往上一個往下）。 */
.fm-group { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.fm-group:not(:has(.fm-btn.on)) > .fm-clear { display: none; }
.fm-clear { min-height: 40px; padding: 0 10px; font-size: var(--fs-md); }
.fm { position: relative; display: inline-flex; max-width: 100%; }
.fm-btn {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
  min-height: 40px; padding: 0 12px 0 16px; border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--panel); color: var(--text); font-size: var(--fs-md); font-weight: 500;
}
.fm-btn:hover { border-color: var(--line-strong); background: var(--panel); }
.fm-btn > .fm-tx { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.fm-btn .fm-k { color: var(--muted); }
.fm-caret { display: inline-flex; color: var(--muted); transition: transform var(--dur-2) var(--ease-out); }
.fm-btn[aria-expanded="true"] .fm-caret { transform: rotate(180deg); }
/* 已套用：品牌色疊色底＋品牌色框（同 .ghost[aria-pressed=true] 的「開著」語彙），一眼看得出清單被篩過 */
.fm-btn.on { background: var(--primary-bg); border-color: var(--primary); }
.fm-btn.on .fm-k, .fm-btn.on .fm-caret { color: var(--primary); }
.fm .dot { width: 8px; height: 8px; border-radius: var(--r-pill); flex: none; }
/* 底色／邊框／陰影與進出場＝全站浮層共用的材質，見檔尾「浮層」段（同 .nav-dd-menu／.rp-menu） */
.fm-menu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 45; transform-origin: top left;
  min-width: max(100%, 200px); max-width: min(360px, calc(100vw - 32px)); max-height: min(360px, 60vh); overflow: auto;
  padding: 4px; border-radius: var(--r-md);
}
/* 膠囊靠右、選單會超出視窗時改靠右對齊（util.js 打開時量），也改從右上角長出來 */
.fm-menu.fm-menu-r { left: auto; right: 0; transform-origin: top right; }
.fm-opt {
  display: flex; align-items: center; gap: 8px; width: 100%; min-height: 34px; padding: 0 10px;
  border: 0; border-radius: var(--r-sm); background: transparent; color: var(--muted-2);
  font-size: var(--fs-md); text-align: left;
}
.fm-opt:hover, .fm-opt:focus-visible { background: var(--panel-2); color: var(--text); }
.fm-opt .fm-t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.fm-opt .fm-n { color: var(--muted); font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
.fm-check { display: inline-flex; color: var(--primary); opacity: 0; }
.fm-opt[aria-checked="true"] { color: var(--text); }
.fm-opt[aria-checked="true"] .fm-check { opacity: 1; }
.dot.cat-bug, .dot.pri-p0 { background: var(--red); }
.dot.cat-feature { background: var(--green); }
.dot.cat-wontdo, .dot.pri-p2 { background: var(--muted); }
.dot.pri-p1 { background: var(--amber); }

/* 區塊層級＋width:100%：放進一般區塊（面板、包一層的 div）也撐到 340px。原本 inline-flex＝縮成 input 的
   預設寬（約 240px），自動化「新增節點」面板的 placeholder 只剩半句。flex-basis 260px：篩選列這一行擠不下
   就整顆換行，不會被壓到 placeholder 看不完（15 個中文字放得下）。 */
.filter-search { position: relative; display: flex; align-items: center; flex: 1 1 260px; width: 100%; max-width: 340px; }
.filter-search-icon { position: absolute; left: 12px; display: inline-flex; color: var(--muted); pointer-events: none; }
/* 搜尋框＝Google 那種膠囊（2026-09-24 定案；先前一度改成矩形系，使用者要的是 Google 形狀）。
   全站搜尋框都照這條，並且要在 corner-shape: round 清單裡（膠囊兩端是半圓，不能被 squircle 壓平）。 */
.filter-search input {
  width: 100%; min-height: 40px; padding: 8px 16px 8px 36px; border-radius: var(--r-pill);   /* 40px＝與同列的下拉、按鈕同高（原本 38.8px） */
  border: 1px solid var(--line); background: var(--panel); color: var(--text); font-size: var(--fs-sm);
}
.filter-search input:hover { border-color: var(--line-strong); }
.filter-search input:focus { border-color: var(--primary); outline: none; box-shadow: var(--ring); }
.filter-search input::placeholder { color: var(--muted); }
/* 清除 ×（util.js searchBox）：與主搜尋列 .serp-input 的 .usearch-clear 同一顆、同一個位置感。原生 type=search 的 ×
   由瀏覽器畫（各平台長得不一樣、只在 hover 出現）→ 藏掉。有沒有字看 :placeholder-shown（呼叫端直接改 value 也跟得上）；
   有字時右內距讓出 × 的位置，沒字時 placeholder 照舊吃滿。 */
.filter-search input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; display: none; }
.filter-search-clear { position: absolute; right: 10px; display: inline-flex; align-items: center; justify-content: center;
  min-height: 0; padding: 2px; border: 0; border-radius: var(--r-xs); background: none; color: var(--muted); }
.filter-search-clear:hover { color: var(--text); background: none; }
.filter-search input:placeholder-shown ~ .filter-search-clear { display: none; }
.filter-search input:not(:placeholder-shown) { padding-right: 36px; }
/* 抽屜／對話框裡的搜尋框吃滿整列（340px 上限是給篩選列上「跟其他篩選並排」用的）。 */
.help-search .filter-search, .rjd-search .filter-search, .dialog-body > .filter-search { max-width: none; width: 100%; }

/* .vault-val：管理員在使用者管理頁擷取使用者登入密碼的明文顯示（login_credentials，非已移除的密碼庫）。 */
.vault-val { flex: 1; word-break: break-all; }
.vault-val.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing: .02em; background: var(--panel-3); padding: 4px 8px; border-radius: var(--r-xs); }

@media (max-width: 900px) {
  .topbar { flex-wrap: wrap; padding: 12px 16px; }
  .layout { grid-template-columns: 1fr; }
  .details, .domain-grid, .de-fields { grid-template-columns: 1fr; }
  .actions { grid-template-columns: repeat(2, 1fr); }
  .control-point { font-size: var(--fs-h2); }
}

/* 頂層分頁「拖曳/點兩側切換」導覽層（tabswipe.js）；可用 localStorage cra_tabswipe=0 停用。
   低調設計：靜止時只露一個小箭頭把手、每隔幾秒輕微晃動暗示可點；hover 才展開分頁名。 */
.ts-pill { --ts-in: 0; position: fixed; top: 50%; z-index: 40; transform: translateY(-50%);
  display: flex; align-items: center; gap: 0; min-height: 0; padding: 12px 3px;
  background: transparent; border: 0; cursor: pointer; }
.ts-pill[hidden] { display: none; }
.ts-prev { left: 2px; }
.ts-next { right: 2px; flex-direction: row-reverse; }
/* 把手＝小圓角方塊裝一個箭頭（材質同頂欄：--mat-bar＋--mat-blur）；靜止低透明、hover 提亮 */
.ts-chev { flex: none; width: 20px; height: 38px; display: grid; place-items: center;
  font-size: var(--fs-h3); line-height: 1; color: var(--muted); border-radius: var(--r-md);
  background: var(--mat-bar); border: 1px solid var(--mat-edge); -webkit-backdrop-filter: var(--mat-blur); backdrop-filter: var(--mat-blur);
  opacity: calc(.3 + var(--ts-in) * .7); transition: opacity .2s, color .2s, border-color .2s; }
.ts-pill:hover .ts-chev, .ts-pill:focus-visible .ts-chev { opacity: 1; color: var(--text); border-color: var(--amber); }
.ts-pill:focus-visible { outline: none; }
.ts-pill:focus-visible .ts-chev { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
/* 分頁名預設收合（max-width 0），hover 才滑出 */
.ts-name { max-width: 0; overflow: hidden; white-space: nowrap; opacity: 0; color: var(--text);
  font-size: var(--fs-sm); transition: max-width .26s ease, opacity .2s, padding .26s; }
.ts-pill:hover .ts-name, .ts-pill:focus-visible .ts-name { max-width: 170px; opacity: 1; padding: 0 8px; }
body.ts-dragging { cursor: grabbing; user-select: none; }
/* 每隔幾秒輕微晃動一下（把手朝畫面中心 nudge）；prev 錯開時間，避免同時晃。
   **提示要有終點**（2026-09-30）：原本是 `infinite`＝每 2.5 秒畫面邊緣就抖一下、永遠不停。
   這是一個每天盯八小時的工具，餘光一直有東西在動很耗人，而且 DESIGN.md 自己寫「不自動播放」。
   改成播 3 輪（約 15 秒）就安靜；而且**用過一次就永久不再提示**（tabswipe.js 寫
   localStorage `cra_ts_hinted`＋掛 body.ts-used）——提示的功能是教會你，教會了就該閉嘴。 */
@keyframes ts-wobble-next { 0%,86%,100% { transform: translateX(0); } 90% { transform: translateX(-4px); } 95% { transform: translateX(-1px); } }
@keyframes ts-wobble-prev { 0%,86%,100% { transform: translateX(0); } 90% { transform: translateX(4px); } 95% { transform: translateX(1px); } }
.ts-next .ts-chev { animation: ts-wobble-next 5s ease-in-out 3; }
.ts-prev .ts-chev { animation: ts-wobble-prev 5s ease-in-out 2.5s 3; }
/* 滑鼠裝置：把手靜止時隱形——常駐 30% 的淡灰小方塊，看起來像兩顆多出來的輪播箭頭（2026-09-30 體檢）。
   游標移到那一側邊緣的把手上才浮出；拖曳中照 --ts-in 漸顯。上面那 3 輪教學晃動改成跟著節奏「探頭」
   一下再退回，播完（或用過一次）就不見。觸控裝置（hover:none）維持原樣。 */
@media (hover: hover) {
  .ts-chev { opacity: var(--ts-in); }
  .ts-next .ts-chev { animation: ts-wobble-next 5s ease-in-out 3, ts-peek 5s ease-in-out 3; }
  .ts-prev .ts-chev { animation: ts-wobble-prev 5s ease-in-out 2.5s 3, ts-peek 5s ease-in-out 2.5s 3; }
}
@keyframes ts-peek { 0%, 80%, 100% { opacity: 0; } 86%, 95% { opacity: .7; } }
.ts-pill:hover .ts-chev, body.ts-dragging .ts-chev, body.ts-used .ts-chev { animation: none; }
@media (prefers-reduced-motion: reduce) { .ts-chev { animation: none; transition: none; } .ts-name { transition: none; } }

/* ── 分頁、切換與篩選（2026-10-01 方案 A：依用途分三種長相，每種全站只有一種；規則見 DESIGN.md「分頁、切換與篩選」）──
   換頁       segTabs()               底線頁籤 .seg-bar：細底軌＋目前那頁一條品牌色底線，切換時滑過去
   二級分頁   segTabs({sub:true})     次級底線頁籤 .seg-bar.seg-sub：字小一階、底線改中性色
   切換檢視   segTabs({inline:true})  分段切換 .seg-pill：軌道＋會滑的白色底塊，全站同一尺寸（40px＝與同列控制項齊高）
   篩選       filterMenu()            篩選膠囊（見上方 .fm-*）
   原本頁面級分頁是「互相重疊的資料夾頁籤」＋自動把下一塊畫成內容面（.view > .seg-bar + *），同站其他地方又是
   灰底按鈕段、膠囊列＝同一種東西三種長相（2026-10-01 使用者回報）。底線頁籤坐在畫布上、不需要接一張紙，
   下面的內容照全站慣例自己是卡片；重疊補償（--tab-lap／--pad-l／--pad-r）與內容面規則一併刪除。 */
.seg { display: inline-flex; flex-wrap: wrap; align-items: center; max-width: 100%; position: relative; }
/* 中文字墨在行盒裡偏高 2.33px（Geist 定行盒高度、中文走 Noto Sans TC 的 em box）：text-box-trim 修到 −0.33px。
   **只給單行、固定／最小高度的控制項**（頁籤、分段、chip）——段落用了會把行距一起剪掉。 */
.seg button, .seg [role="tab"] { text-box: trim-both cap alphabetic; }
.seg > button {
  position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--r-sm); background: transparent; box-shadow: none; font-weight: 500;
  transition: color var(--tr);
}
.seg > button:hover { background: transparent; }
/* 「選到了」的那一塊（底線或底塊）＝不會被重建的獨立元素，util.js 量目前按鈕的位置用 transform 移過去；
   第一次定位不播（.ready 之後才有 transition）。不靠按鈕自己的 border／font-weight 標示 active＝切換時寬度不變、不抖。 */
.seg-ind { position: absolute; top: 0; left: 0; z-index: 0; pointer-events: none; opacity: 0; }
/* 筆數（segTabs 的 [key, label, n]）：分段切換裡是灰字；底線頁籤裡是灰色小圓章（Primer UnderlineNav 的 Counter） */
.seg-n { margin-left: 6px; color: var(--muted); font-size: var(--fs-xs); font-weight: 500; font-variant-numeric: tabular-nums; }

/* ① 底線頁籤 */
.seg.seg-bar {
  --seg-pad: 12px;
  display: flex; margin: 0 0 var(--sp-4);
  box-shadow: inset 0 -1px 0 var(--tab-line);      /* 細底軌畫在列上＝貫穿整列；放不下換行時手機版改畫在每顆按鈕上 */
}
.seg.seg-bar > button { min-height: 40px; padding: 0 var(--seg-pad); color: var(--muted); font-size: var(--fs-md); }
/* 第一顆往左吃回自己的內距：字的左緣對齊頁首標題與下方內容（底線也從那裡開始） */
.seg.seg-bar > .seg-ind + button { margin-left: calc(-1 * var(--seg-pad)); }
.seg.seg-bar > button:hover, .seg.seg-bar > button.seg-on { color: var(--text); }
/* hover 預覽：沒選到的那顆底下浮出一條中性色底線（Fluent 2 的作法）；點下去，品牌色那條才滑過來 */
.seg.seg-bar > button::after {
  content: ""; position: absolute; left: var(--seg-pad); right: var(--seg-pad); bottom: 0; height: 2px;
  background: var(--line-strong); opacity: 0; transition: opacity var(--tr);
}
.seg.seg-bar > button:not(.seg-on):hover::after { opacity: 1; }
/* 原始寬 100px、JS 用 scaleX(字寬/100) 縮放：1px 的條在 150% 縮放下會先被吸附成 1.33px 再放大＝底線超出字（見 util.js segTabs） */
.seg.seg-bar > .seg-ind { z-index: 2; width: 100px; height: 2px; background: var(--primary); transform-origin: 0 0; }
.seg.seg-bar > .seg-ind.ready { transition: transform 260ms var(--ease), opacity 120ms; }
.seg.seg-bar .seg-n {
  min-width: 20px; padding: 0 6px; line-height: 18px; text-align: center;
  border-radius: var(--r-pill); background: var(--tag-bg); color: var(--muted-2);
}
/* hub 頁首與它的分頁列是同一個頁首：拉近一點（原本 32px＋標題下距，分頁列看起來跟標題沒關係） */
.view > .page-head + .seg.seg-bar:not(.seg-sub) { margin-top: calc(-1 * var(--sp-3)); }

/* ② 次級底線頁籤：字小一階、底線中性色＝層級一眼分得出來（品牌色只留給頁面級那一條） */
.seg.seg-bar.seg-sub { --seg-pad: 10px; margin: 0 0 var(--sp-3); }
.seg.seg-bar.seg-sub > button { min-height: 34px; font-size: var(--fs-sm); }
.seg.seg-bar.seg-sub > .seg-ind { background: var(--muted-2); }

/* ③ 分段切換：軌道（疊色，放在畫布／卡片／對話框上都比底下深一階）＋白色底塊 */
.seg.seg-pill { gap: 2px; padding: 4px; border-radius: var(--r-md); background: var(--seg-track); }
.seg.seg-pill > button { min-height: 32px; padding: 0 12px; color: var(--muted-2); font-size: var(--fs-md); }
.seg.seg-pill > button:hover, .seg.seg-pill > button.seg-on { color: var(--text); }
.seg.seg-pill > .seg-ind { border-radius: var(--r-sm); background: var(--seg-thumb); box-shadow: var(--seg-thumb-sh); }
/* 動寬高是 Motion「只動 transform/opacity」的例外：底塊有圓角，scaleX 會把圓角壓扁；它是 absolute、改寬高不推動任何東西 */
.seg.seg-pill > .seg-ind.ready { transition: transform 260ms var(--ease), width 260ms var(--ease), height 260ms var(--ease), opacity 120ms; }

/* 換頁轉場（配合 main.js 的 renderRouted）：只讓內容區 #view 動，頂欄與導覽不動——
   給 #view 自己的 view-transition-name 就會從 root 快照裡獨立出來，root 仍會交叉淡入
   但那一區沒有變化＝看不出來。時長比照 --tr 系列，短而不拖。
   包在 prefers-reduced-motion: no-preference 裡：要求減少動態的人連 name 都不掛，
   瀏覽器就完全不會為它做轉場（JS 那邊也有一道，兩邊都擋）。 */
@media (prefers-reduced-motion: no-preference) {
  /* 只在轉場期間掛（util.js viewTransition 加 .vt-live）：常駐的話 #view 會自成疊層，裡面的抽屜蓋不過頂欄。 */
  #view.vt-live { view-transition-name: cra-view; }
  /* 等長、同曲線、加法混色＝兩張的不透明度相加恆為 1：兩頁同一個位置都是白卡時，轉場中途不會透出灰底。
     原本舊頁 110ms 淡出、新頁 190ms 淡入，而且自訂 animation 會蓋掉瀏覽器預設的 plus-lighter
     ⇒ 中途兩張都半透明、白卡變灰再變白＝「切頁閃一下」（2026-10-01 回報；放慢 10 倍實測白卡 255→249、
     深色 27.7→24.3）。也不再上下位移：兩頁同位置的標題會跟著抖。 */
  ::view-transition-old(cra-view), ::view-transition-new(cra-view) {
    animation-duration: var(--dur-2); animation-timing-function: var(--ease-out); animation-fill-mode: both;
    mix-blend-mode: plus-lighter; }
  ::view-transition-old(cra-view) { animation-name: cra-vt-out; }
  ::view-transition-new(cra-view) { animation-name: cra-vt-in; }
}
/* 就地轉場（util.js viewTransition）：from 節點「長成」to 節點，例：專案卡片 → 專案詳情摘要。
   group 管位置與大小、old/new 交叉淡入；比換頁略長，因為真的有東西在移動——位移走不過衝的彈簧（--spring-soft）。 */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-group(cra-morph) { animation-duration: var(--dur-3); animation-timing-function: var(--spring-soft); }
  ::view-transition-old(cra-morph), ::view-transition-new(cra-morph) { animation-duration: var(--dur-3); height: 100%; }
}
@keyframes cra-vt-out { to { opacity: 0; } }
@keyframes cra-vt-in { from { opacity: 0; } }

/* 中文折行：末行只剩一兩個字（孤字）在中文裡特別難看。桌面寬度下標題幾乎不折行＝無作用，
   但手機 390px 實測：結果標題孤字 1/12 → 0、末行平均 15.8 → 21.3 字（行長更均勻）；
   摘要孤字 3/20 → 0。balance 只給短文字（瀏覽器對行數有上限，長文會自動忽略），
   pretty 給段落（成本低，專門處理孤行）。不支援的瀏覽器忽略它＝維持現狀。
   **一定要寫 longhand text-wrap-style**：簡寫 text-wrap 會順便把 text-wrap-mode 設回 wrap，
   同一個元素上的 .nowrap（white-space:nowrap）就被取消——資料品質表的日期折成「2026-07-／30」（2026-10-01 二輪體檢）。 */
.view h1, .view h2, .view h3, .view h4, .page-head .ph-title { text-wrap-style: balance; }
.view p, .empty, .muted { text-wrap-style: pretty; }

/* 狀態標籤＝全站一套（2026-10-02）：正常／成功 .tag.ok、注意 .tag.warn、失敗／錯誤 .tag.err，中性（執行中、停用、未知）＝不加修飾的 .tag。
   原本同一種「成功／失敗／啟用中」有純文字、彩色字、膠囊三種寫法，lab 拿 .tag.warn 標「失敗」（只因為沒有 .tag.err）。字要寫出來，不只靠顏色。 */
.tag.ok { background: var(--green-bg); color: var(--green); }
.tag.warn { background: var(--amber-bg); color: var(--amber); }
/* 字往 --text 混兩成：深色的紅疊在自己的淡紅底上只有 4.1:1（12px 字要 4.5），混了 4.9；淺色反而更深、更清楚。綠與橘本身就夠（5.6／6.4）。 */
.tag.err { background: var(--red-bg); color: color-mix(in srgb, var(--red) 80%, var(--text)); }
/* 頁首 meta（公司 · 負責人 · 變更負責人）對齊成一列 */
.setup-meta { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; margin-top: .35rem; }
/* 每顆 chip 整體為單位換行：中文 flex item 的 min-content=單一字元，不 nowrap 會被壓成
   「變更負／責人」「更／新」直排。nowrap＋不收縮 → 空間不足時靠 .setup-meta 的 flex-wrap 整顆換行。*/
.setup-meta > span, .setup-meta > button { white-space: nowrap; flex-shrink: 0; }
.setup-dot { color: var(--muted); }
/* 變更負責人＝一組小控件：標籤＋下拉＋「更新」同高（30px）同一條中線 */
.setup-owner { display: inline-flex; align-items: center; gap: 8px; flex-shrink: 0; }
/* 右內距留給 select 的 chevron（全站 select 是 padding-right:30px；只寫 0 8px 會讓長名字壓到箭頭上） */
.setup-owner-sel { width: auto; min-width: 9rem; min-height: 30px; padding: 0 30px 0 10px; font-size: var(--fs-sm); flex-shrink: 0; }

/* ---- AI 法規影響：依「本期間有修正的法規」分組的垂直 feed（由上往下滑） ---- */
.li-feed { display: flex; flex-direction: column; gap: 12px; margin-top: .6rem; }
.li-lawgroup-h { display: flex; align-items: center; gap: 8px; padding: 10px 4px 4px; position: sticky; top: 0;
  background: var(--bg); z-index: 1; font-size: var(--fs-body); }
.li-lawgroup-h:first-child { padding-top: 0; }
.li-lawglyph { display: inline-flex; color: var(--muted-2); flex: none; }
.li-card { border: 1px solid var(--line); border-radius: var(--r-md); padding: 14px; background: var(--panel); min-width: 0; }
.li-dhead { margin-bottom: .6rem; }
.li-field { margin: .7rem 0; }
.li-flabel { font-size: var(--fs-xs); letter-spacing: .04em; color: var(--muted); margin-bottom: 4px; }
.li-cp { width: 100%; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--bg); color: var(--text); font: inherit; line-height: 1.6; }
.li-cp:disabled { opacity: .6; cursor: default; }
.li-ai { margin: .7rem 0; padding: 10px 12px; border: 1px dashed var(--line-strong); border-radius: var(--r-sm); }
.li-aitext { font-size: var(--fs-md); line-height: 1.7; white-space: pre-wrap; }
.li-diff-add { color: var(--red); font-weight: 600; background: var(--red-bg); border-radius: 3px; padding: 0 2px; }

/* 指派工具列：左（計數＋挑人＋動作）右（全選/取消）兩簇對齊，控制項等高 */
.setup-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: .75rem;
  position: sticky; top: 0; z-index: 2; }
.setup-tb-left { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; }
.setup-tb-right { display: flex; align-items: center; gap: .5rem; margin-left: auto; }

/* 依法規指派清單：每列＝一部法規，欄位對齊（勾選 / 法規名 / 條數 / 負責人） */
.setup-list { margin-top: .6rem; max-height: 60vh; overflow: auto; padding: 0; }
.setup-row { display: flex; align-items: center; gap: .75rem; padding: .55rem .8rem;
  border-bottom: 1px solid var(--line); cursor: pointer; user-select: none; }
.setup-row:last-child { border-bottom: 0; }
.setup-row:hover { background: var(--panel-2); }
.setup-row.sel { background: var(--primary-bg); }
.lawpick { flex: none; width: 1.15rem; height: 1.15rem; display: inline-flex; align-items: center;
  justify-content: center; color: var(--primary-hover); }
.law-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.law-count { flex: none; min-width: 6.5rem; text-align: right; white-space: nowrap; }
.law-assignees { flex: none; width: 16rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted-2); }
@media (max-width: 720px) { .law-assignees { display: none; } }
.setup-run { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }

/* 依法規類型指派：卡片格＋長按拖曳連選＋選取動畫（卡片感） */
.lawtype-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: .7rem; margin-top: .6rem; user-select: none; }
.lawtype-card { position: relative; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: .85rem .9rem; cursor: pointer; box-shadow: var(--sh-1);
  transition: translate var(--dur-3) var(--spring), scale var(--press-tr), box-shadow var(--dur-2) var(--ease-out), border-color var(--tr), background var(--tr); }
.lawtype-card:hover { translate: 0 var(--lift-y); box-shadow: var(--sh-2); border-color: var(--line-strong); }   /* 浮起＝全站可點卡片同一組（見 .project-card） */
.lawtype-card.sel { border-color: var(--primary); background: var(--panel-3); }
.lawtype-card.pop { animation: ltc-pop .22s cubic-bezier(.2,1.4,.4,1); }
@keyframes ltc-pop { 0% { transform: scale(.96); } 60% { transform: scale(1.03); } 100% { transform: scale(1); } }
.ltc-check { position: absolute; top: .55rem; right: .6rem; display: inline-flex; color: var(--primary-hover);
  opacity: 0; transform: scale(.4); transition: opacity .14s ease, transform .14s ease; }
.lawtype-card.sel .ltc-check { opacity: 1; transform: scale(1); }
.ltc-name { font-weight: 600; padding-right: 1.4rem; line-height: 1.3; }
.ltc-meta { margin-top: .25rem; }
.ltc-assignees { margin-top: .45rem; color: var(--primary-hover); }
.ltc-assignees.muted { color: var(--muted); }
@media (prefers-reduced-motion: reduce) { .lawtype-card, .lawtype-card.pop { transition: none; animation: none; } }

/* 覆核人員多選下拉（reviewerPicker）— 打勾＋彈入動畫，仿法條頁挑選 */
.rp { position: relative; display: inline-flex; }
.rp-btn { display: inline-flex; align-items: center; justify-content: space-between; gap: 8px;
  min-width: 13rem; min-height: 30px; padding: 0 10px; background: var(--panel); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--r-sm); font-size: var(--fs-sm); }
/* 外觀＝全站原生 <select>（--panel 底、hover 只換邊框色）；原本灰底，跟同一列、同一站的其他下拉長不一樣 */
.rp-btn:hover { border-color: var(--line-strong); background: var(--panel); }
.rp-caret { display: inline-flex; color: var(--muted); transition: transform .16s ease; }
.rp-btn[aria-expanded="true"] .rp-caret { transform: rotate(180deg); }
.rp-menu { position: absolute; top: calc(100% + 6px); left: 0; z-index: 40; min-width: 100%;
  /* 夠高以一次列完全所的人（~12 列）：15rem 只容得下 7 列，後面的人得在選單內再捲一次＝看起來「少了人」。 */
  max-height: min(26rem, 55vh); overflow: auto; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--sh-2); padding: 5px; }
.rp-empty { padding: 10px 12px; color: var(--muted); font-size: var(--fs-sm); }
.rp-item { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%;
  min-height: 34px; padding: 0 10px; border: 0; background: transparent; color: var(--muted-2);
  border-radius: var(--r-sm); font-size: var(--fs-sm); cursor: pointer; }
.rp-item:hover { background: var(--panel-2); color: var(--text); }
.rp-item.on { color: var(--primary-hover); font-weight: 600; }
.rp-check { display: inline-flex; color: var(--primary-hover); opacity: 0; transform: scale(.4);
  transition: opacity .14s ease, transform .14s ease; }
.rp-item.on .rp-check { opacity: 1; transform: scale(1); }
.rp-item.pop .rp-check { animation: rp-pop .22s cubic-bezier(.2,1.5,.4,1); }
@keyframes rp-pop { 0% { transform: scale(.2); } 60% { transform: scale(1.25); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .rp-item.pop .rp-check { animation: none; } }

/* 逐項移除鈕（util.js removeX）：只管「那顆 × 長得一樣」＋置中，位置樣式由 .chip-x/.thumb-x/.ghost 給。 */
.rm-x { display: inline-flex; align-items: center; justify-content: center; }
.rm-x svg { display: block; }

/* 關閉鈕（util.js closeX）：對話框頭列／抽屜／浮動面板右上角那顆 ×，全站同一顆。
   min-height:0 是必要的——全站 button 有 40px tap-target 下限，不歸零會被拉成高橢圓。 */
.close-x { flex: none; display: flex; align-items: center; justify-content: center;
  min-height: 0; padding: 4px; border: 0; background: none; color: var(--muted);
  border-radius: var(--r-xs); cursor: pointer; }
.close-x:hover { color: var(--text); background: var(--panel-2); }

/* 選檔（util.js filePicker）：迴紋針／資料夾鈕＋已選檔名。裸 <input type=file> 的原生鈕
   文案與圖示都改不了、各頁長相不一 → 全站一律走這顆（preflight #12 擋新的裸 file input）。 */
.fp { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fp-btn { display: inline-flex; align-items: center; gap: 6px; }
.fp-ic { display: inline-flex; color: var(--muted-2); }
.fp-btn:hover .fp-ic { color: var(--text); }
.fp-name { font-size: var(--fs-sm); word-break: break-all; }

/* ── Bug 回報（浮動面板 + 紀錄頁；前身：平台鏡像）──────────────────── */
.mv-item { display: flex; align-items: center; gap: 8px; padding: 3px 0; font-size: var(--fs-md); cursor: pointer; }
.mv-item span { flex: 1; }
.mv-prob { display: flex; align-items: center; gap: 8px; padding: 4px 0; }
.mv-prob-t { min-width: 90px; font-size: var(--fs-sm); }
/* 紀錄頁列內編輯器 */
.mirror-view .mv-edit-row td { background: var(--panel-2); }
.mirror-view .mv-editor { padding: 6px 4px; }
.mirror-view .mv-editor h4 { margin: 10px 0 4px; font-size: var(--fs-sm); color: var(--muted); font-weight: 650; }
.mirror-view .mv-editor h4:first-child { margin-top: 0; }
/* 浮動回報面板：右下角固定面板；開關由頂欄 Bug 圖示切換（開＝顯示、關＝移除），面板內「關閉」鈕也是關掉模式。 */
.bugpanel { position: fixed; right: 18px; bottom: 18px; z-index: 60; width: 340px; max-width: calc(100vw - 36px); max-height: 600px; display: flex; flex-direction: column; background: var(--panel); border: 1px solid var(--line-strong, var(--line)); border-radius: var(--r-md, 12px); box-shadow: var(--sh-2); overflow: hidden; }
.bugpanel-head { flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; padding: 10px 14px; border-bottom: 1px solid var(--line); }
.bugpanel-head .bp-my { margin-left: auto; font-size: var(--fs-sm); text-decoration: none; }   /* 工具列上的連結靠顏色辨識；底線會拖過全形括號的留白 */
.bugpanel-head .bp-my:hover { text-decoration: underline; }
/* 面板裡的連結（我的回報／查看我的回報／查看紀錄）：全站沒有 a 的顏色規則＝瀏覽器預設藍紫色，深色底上幾乎看不見。 */
.bugpanel a { color: var(--primary); text-underline-offset: 3px; }
/* 送出結果／錯誤寫在標題列第二行（bugpanel.js say()）：手機上吐司會被面板或漢堡選單蓋住。 */
.bugpanel-status { flex-basis: 100%; font-size: var(--fs-sm); color: var(--green); }
.bugpanel-status.error { color: var(--red); }
.bugpanel-body { padding: 10px 14px; overflow-y: auto; max-height: min(58vh, 460px); }
.bugpanel-sec { margin-bottom: 12px; }
.bugpanel-sec h4 { margin: 0 0 4px; font-size: var(--fs-sm); color: var(--muted); font-weight: 650; }
/* 問題類型：類型名是固定標籤、補充說明在它下一行（勾了才出現）——原本類型名只是輸入框的 placeholder，一打字就看不出是哪一類。 */
.bugpanel .bp-prob-in { display: block; width: calc(100% - 24px); margin: 2px 0 6px 24px; }
.bugpanel textarea { min-height: calc(2lh + 20px); }   /* 筆記：field-sizing:content 沒字時只有一行高，看起來像單行欄位（同 .app-dialog textarea） */
.bugpanel .fp { margin-bottom: 6px; }
.bugpanel-foot { flex: none; display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-top: 1px solid var(--line); }
/* 「收起」＝收成同一角落的膠囊「Bug 回報（已勾 N）」，點膠囊再展開（桌機手機同一套；手機預設收合，見檔尾 720px 區塊）。 */
.bugpanel .bp-collapse { display: inline-flex; align-items: center; justify-content: center; min-height: 0; padding: 4px; color: var(--muted); }
.bugpanel-pill { display: none; align-items: center; gap: 6px; min-height: 40px; padding: 0 16px; border: 0; background: transparent; box-shadow: none; color: var(--text); font-size: var(--fs-md); font-weight: 600; }
.bugpanel-pill svg { display: block; color: var(--muted-2); }
.bugpanel.bp-collapsed { width: auto; border-radius: var(--r-pill); corner-shape: round; }
.bugpanel.bp-collapsed > :not(.bugpanel-pill) { display: none; }
.bugpanel.bp-collapsed > .bugpanel-pill { display: inline-flex; }
/* 紀錄頁：點列展開的原始 JSON 檢視 */
.mirror-view .mv-json-row td { background: var(--panel-2); }
/* pre-wrap + overflow-wrap:anywhere：JSON 內含截圖 base64 data-URL 這種超長單詞，white-space:pre 會把表格撐爆，改為換行且長字強制斷。 */
.mirror-view .mv-json { margin: 0; padding: 10px 12px; max-height: 420px; overflow: auto; font-family: var(--mono); font-size: var(--fs-xs); line-height: 1.5; background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-sm); white-space: pre-wrap; overflow-wrap: anywhere; }
.mirror-view tr[data-expandable] { cursor: pointer; }

/* 紀錄表整體穩固：欄寬固定＋內容換行，避免內容/截圖/JSON 把表格撐爆或窄螢幕擠壓；
   紀錄數量少 → 關閉 .data-table 的 content-visibility 視窗化（其 44px 估高對高列會造成捲動亂跳）。 */
.mirror-view .data-table { table-layout: fixed; width: 100%; min-width: 980px; }
.mirror-view .data-table tbody tr { content-visibility: visible; contain-intrinsic-size: auto; }
/* 欄寬：狀態要放得下「已完成修正」＋下拉箭頭（104px 會把選項文字切掉）；
   操作有 5 顆鈕（JSON／編輯／回覆／複製／刪除），150px 會擠成三行。 */
.mirror-view .data-table thead th:nth-child(1) { width: 76px; }    /* 編號 */
.mirror-view .data-table thead th:nth-child(2) { width: 164px; }   /* 時間 */
.mirror-view .data-table thead th:nth-child(3) { width: 96px; }    /* 回報人 */
.mirror-view .data-table thead th:nth-child(5) { width: 148px; }   /* 狀態 */
.mirror-view .data-table thead th:nth-child(6) { width: 236px; }   /* 操作 */
/* 內容欄（第 4 欄，未指定寬→吃剩餘）強制換行，長 URL/字串不撐欄 */
.mirror-view .data-table td:nth-child(4) { overflow-wrap: anywhere; word-break: break-word; }

/* ── 條文比對面板（law_detail <details>）＋通用文字 diff（diff.js）─────────
   顏色一律走 token（DESIGN.md 硬規則）；綠＝新增、紅＝刪除；雙欄在窄螢幕收合成單欄。 */
.law-compare { margin: 0 0 var(--sp-4); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel); }
.law-compare > summary { padding: 10px 14px; cursor: pointer; font-weight: 600; color: var(--muted-2); }
.law-compare[open] > summary { border-bottom: 1px solid var(--line); }
.law-compare-ctl { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; padding: 12px 14px; }
.law-compare-ctl label { display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-sm); color: var(--muted); }
.law-compare-tas { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; padding: 0 14px 12px; }
.law-compare-ta { min-height: 60px; }
.law-compare-out { padding: 0 14px 14px; }
.diff { overflow-x: auto; }
.diff-split { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.diff-pane { min-width: 0; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--panel-2); white-space: pre-wrap; word-break: break-word; line-height: 1.6; }
.diff-inline { white-space: pre-wrap; word-break: break-word; line-height: 1.6; }
ins.diff-add { background: var(--green-bg); color: var(--green); text-decoration: none; border-radius: 3px; padding: 0 1px; }
del.diff-del { background: var(--red-bg); color: var(--red); border-radius: 3px; padding: 0 1px; }
@media (max-width: 720px) { .diff-split, .law-compare-tas { grid-template-columns: 1fr; } }
/* 更新覆核卡：管控重點內容（左，可編輯）與 AI 建議（右）左右並列；窄螢幕改上下堆疊。 */
.cp-ai-split { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: start; }
@media (max-width: 860px) { .cp-ai-split { grid-template-columns: 1fr; } }

/* ── 精緻化：載入骨架 / 專案卡刪除鈕收斂 / 覆核頁匯出選單 ───────────────── */
/* 載入骨架 shimmer（取代「載入中…」純文字；reduced-motion 由全域 blanket 停用動畫）。 */
.skeleton { display: grid; gap: 10px; }
.skeleton-row { height: 14px; border-radius: var(--r-xs);
  background: linear-gradient(90deg, var(--panel-2) 25%, var(--panel-3) 37%, var(--panel-2) 63%);
  background-size: 400% 100%; animation: skeleton-shimmer 1.4s ease-in-out infinite; }
@keyframes skeleton-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
/* 進行中的小轉圈（只給「正在跑」的狀態，DESIGN.md Motion：infinite 只准給載入中）：吃 currentColor，放在文字旁。
   帶圖示的鈕忙碌時（.btn-ic[aria-busy]）前面那顆圖示換成同尺寸的轉圈＝字不位移，呼叫端只要設 aria-busy、換字。 */
.spinner, .btn-ic[aria-busy="true"]::before { display: inline-block; flex: none; width: 12px; height: 12px; border-radius: 50%; vertical-align: -1px;
  border: 2px solid color-mix(in srgb, currentColor 22%, transparent); border-top-color: currentColor; animation: cra-spin .8s linear infinite; }
.btn-ic[aria-busy="true"]::before { content: ""; box-sizing: border-box; width: 15px; height: 15px; }   /* 15px＝圖示尺寸（::before 不吃全站 * 的 border-box） */
.btn-ic[aria-busy="true"] > svg:first-child { display: none; }
@keyframes cra-spin { to { transform: rotate(360deg); } }
.crawl-running { border-color: color-mix(in srgb, var(--primary) 45%, var(--line)); }

/* 專案卡「刪除」：可 hover 的桌面平時隱藏，hover 卡片或鍵盤 focus 才現，降低誤點；觸控裝置維持常顯。 */
@media (hover: hover) {
  .project-card .pc-top .icon.danger { opacity: 0; transition: opacity var(--tr); }
  .project-card:hover .pc-top .icon.danger,
  .project-card .pc-top .icon.danger:focus-visible { opacity: 1; }
  /* Skills 卡動作列：Notion 式「乾淨卡片、動作滑過才現」——桌面平時隱藏整列動作，hover 卡片或鍵盤 focus 進來才浮出（focus-within 覆蓋整列，非只 danger 鈕）；觸控裝置維持常顯。
     動作列與狀態列疊在 .sk-foot 同一格、滑過時互換：原本動作列自己佔一條（隱形），卡底就多一條空帶。用 opacity 不用 display＝格子高度不變、hover 時卡片不跳高。 */
  .skill-card2 .sk-foot > * { grid-area: 1 / 1; }
  .skill-card2 .sk-actions,
  .skill-card2 .sk-track { transition: opacity var(--tr); }
  .skill-card2 .sk-actions { opacity: 0; }
  .skill-card2:hover .sk-actions,
  .skill-card2:focus-within .sk-actions { opacity: 1; }
  /* 藏起來的狀態列一定要 pointer-events:none：opacity<1 會讓它自成疊層、畫在「不透明的動作列」上面，
     透明但照樣攔點擊——滑過卡片後點「檢視內容／複製／編輯」正中央沒反應，只剩按鈕頂端露出的 3px 點得到（2026-10-01 UX 實測）。 */
  .skill-card2:hover .sk-track,
  .skill-card2:focus-within .sk-track { opacity: 0; pointer-events: none; }
  /* 刪除鈕同專案卡：滑過才現。原本寫在這個區塊外面＝手機上永遠透明、卻照樣點得到（右上角一塊看不見的刪除）。 */
  .skill-card2 .icon.danger { opacity: 0; transition: opacity var(--tr); }
  .skill-card2:hover .icon.danger, .skill-card2 .icon.danger:focus-visible { opacity: 1; }
}

/* 覆核頁「匯出」下拉（<details>）：把 4 顆匯出鈕收成一顆。 */
.exports-menu { position: relative; }
.exports-menu > summary { list-style: none; cursor: pointer; }
.exports-menu > summary::-webkit-details-marker { display: none; }
/* 按鈕內的下拉箭頭（圖示 chevron-down）：展開時翻向上（DESIGN.md「下拉箭頭方向」）。
   <button> 觸發鈕看 aria-expanded（設定頁「重新執行 AI 判斷」）；<details> 看原生 [open]（覆核頁「匯出」，
   summary 的展開狀態瀏覽器本來就會報給輔助技術，不必再手動同步 aria-expanded）。 */
.dd-caret { transition: transform var(--tr-fast) var(--ease); }
[aria-expanded="true"] > .dd-caret, details[open] > summary > .dd-caret { transform: rotate(180deg); }
.exports-pop { position: absolute; right: 0; top: calc(100% + 6px); min-width: 160px; z-index: 30;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md); box-shadow: var(--sh-2); padding: 6px; display: grid; gap: 2px; }
.exports-pop .menu-item { display: block; padding: 8px 12px; border-radius: var(--r-sm); color: var(--text); text-decoration: none; font-size: var(--fs-sm); }
.exports-pop .menu-item:hover { background: var(--panel-2); }

/* ── 專案管理 hub（#/planner 四分頁）共用 ───────────────────────────
   期間切換列（planner_calendar.js periodNav）：[‹] 目前期間／選取器 [›] [今天]，四個分頁同一個長相
   （2026-09-30 體檢前：專案總覽是小小的 ‹ › 文字、工作日誌／當週議題是「‹ 上一週 週次 […] 下一週 ›」文字連結）。
   方形圖示鈕與選取器同高（全站 button 的 40px）＋次要鈕的框線底色；「今天／本週／本月」用小鈕退到次要。 */
.pm-nav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pm-ic-btn { flex: none; width: 40px; padding: 0; display: inline-flex; align-items: center; justify-content: center; color: var(--muted-2); }
.pm-ic-btn:hover { color: var(--text); }
/* 週／月選取器自帶的「週次／月份」小標：按鈕上已經寫著期間，再標一次只是雜訊 */
.pm-nav .tl-label { display: none; }
/* 週標題（工作日誌／當週議題共用）：「2026 年 9 月 W5 · 9/28（一）– 10/2（五）」 */
.pm-week { margin: 0 0 var(--sp-3); font-size: var(--fs-h3); }
/* 工作日誌跨月週提示（diary.js splitNote，只在週一與週五不同月時出現）：是這一週的狀態、不是頁面說明，所以實色字＋淡底框。 */
.pm-split-note { display: flex; align-items: flex-start; gap: 8px; margin: 0 0 var(--sp-3); padding: 8px 12px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--panel-2); font-size: var(--fs-sm); color: var(--text); }
.pm-split-note svg { flex: none; margin-top: 2px; color: var(--muted-2); }
/* 「今天」小標籤（diary.js todayTag：工作日誌欄頭／手機卡片、當週議題的日期）：品牌色字＋同色細框，跟在日期後面 */
.tag.pm-today { margin-inline-start: 6px; padding: 0 7px; background: transparent; color: var(--primary); box-shadow: inset 0 0 0 1px currentColor; font-weight: 600; }
/* reviewerPicker 放在表單欄位（field()）裡＝它就是一個下拉欄位：跟 select 同一個長相——全寬、40px、
   白底框線、右側 chevron。原本是灰底小按鈕，放在灰底對話框裡像一行沒有框的字（新增專案對話框四個欄位
   四種長相）。只有專案管理／當週議題／寄信管理的對話框這樣用；設定頁工具列的小型用法不在 .field 裡、不受影響。 */
.field .rp { display: flex; }
.field .rp-btn { width: 100%; min-height: 40px; padding: 0 11px; background: var(--panel); font-size: inherit; }   /* 上下內距 0＝跟 select 一樣剛好 40px */
.field .rp-btn:hover { background: var(--panel); }
/* 日期區間選取器在表單欄位裡同樣撐滿整欄、箭頭靠右（按鈕的框線／高度／底色由 ympicker 的全站樣式給，這裡不碰） */
.field .ymp-btn { width: 100%; }
.field .ymp-btn-label { flex: 1; text-align: left; }

/* ── Time Report（工時日報）月曆 ───────────────────────────────────
   版面與專案總覽月曆同一套（planner_calendar.js 注入的 .pm-cal-*：hairline 格線、日期在左上、今天圈起來、
   非本月退到畫布色）——體檢前是一整面灰底方塊、日期靠右，跟同一個 hub 的專案總覽像兩個產品。
   這裡只補 Time Report 自己的：格子較矮（沒有事件條）、日格是 <button>、選到的那天、已填寫的小圓點、當日工時。
   特異度刻意多一層 .tr-cal：注入的 .pm-cal-* 排在 styles.css 之後，同特異度會蓋過這裡。 */
.pm-cal.tr-cal { --pm-cell: 64px; }
/* flex：<button> 的內容預設垂直置中（display:block 也一樣），日期要貼左上角得靠 flex 對齊 */
.tr-cal .tr-cal-day { position: relative; width: 100%; display: flex; align-items: flex-start; }
.tr-cal .tr-cal-day:hover { background: var(--panel-2); }
.tr-cal .tr-cal-day.sel { background: var(--panel-3); box-shadow: inset 0 0 0 1px var(--primary); }
/* 已填寫（時段／待辦／Others 任一有字）：原本是格子底部的品牌色粗邊，改成右上角一顆小圓點（形狀＋色） */
.tr-cal .tr-cal-day.filled::after { content: ""; position: absolute; top: 10px; right: 8px; width: 6px; height: 6px;
  border-radius: 50%; background: var(--primary); }
.tr-editor .data-table input { width: 100%; box-sizing: border-box; }
/* 點日期後編輯器捲進畫面（scrollIntoView）：扣掉黏在上方的頂欄，「2026-10-01（四）工時填寫」不再被頂欄蓋住（手機頂欄 60px、桌面約 72px） */
.tr-editor { scroll-margin-top: 84px; }
/* 時段的時間欄＝開始／結束兩顆下拉（半小時一階），兩顆得編在同一行、
   窄表格裡也要縮得下來（select 預設 width:100%＋padding-right:30px 放鼓箭頭，兩顆並排會爆欄）。 */
.tr-editor .tr-time { display: inline-flex; align-items: center; gap: 4px; min-width: 8.5rem; }
.tr-editor .tr-time select { width: auto; min-width: 0; flex: 1 1 auto; padding-left: 8px; padding-right: 24px;
  background-position: right 7px center; }
.tr-slots td { vertical-align: top; }   /* 合併(rowspan)內容格靠上對齊，不置中於高格 */
.tr-slots td.col-ctl { vertical-align: middle; }   /* 「併／×」每列一格（不跨列）：對齊同列 40px 下拉的中線，貼頂會高出半截 */
.tr-merge-lbl { display: inline-flex; align-items: center; gap: 3px; margin-inline-end: 6px;
  font-size: var(--fs-xs); color: var(--muted); cursor: pointer; white-space: nowrap; }

/* 工作日誌（週誌）：本週待辦區塊＋週一～週五 × 工作項目／備註 表格 */
.diary-label { display: block; font-weight: 600; margin: .2rem 0 .4rem; }
.diary-todos { width: 100%; box-sizing: border-box; margin-bottom: 1.2rem; }
.diary-scroll { overflow-x: auto; }   /* 5 天欄在窄螢幕可橫捲，頁面本體不橫捲 */
.diary-grid { table-layout: fixed; min-width: 720px; }
.diary-grid th, .diary-grid td { vertical-align: top; }
.diary-grid .diary-rowhdr { width: 8.5rem; text-align: start; white-space: normal; color: var(--muted); }
.diary-cell { width: 100%; box-sizing: border-box; }

/* 儲存列（工作日誌／Time Report，js/dirty.js）：儲存鈕旁常駐「有未儲存的修改／已儲存 21:14」——即時狀態，不是說明灰字。
   帳號開通信（tcf.js）只用 .save-state。手機版這一列釘在畫面底，見檔尾 720px 區塊。 */
.save-bar { display: flex; align-items: center; justify-content: flex-end; gap: 12px; margin-top: var(--sp-4); }
.save-state { font-size: var(--fs-sm); color: var(--muted); font-variant-numeric: tabular-nums; }
.save-state.dirty { color: var(--text); }
.save-state.dirty::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-inline-end: 6px;
  border-radius: 50%; corner-shape: round; background: var(--amber); vertical-align: 1px; }   /* round：全站 squircle 會把正圓壓成方圓 */

/* 當週議題：同一天的多則議題把「日期」欄以 rowspan 合併成一格（垂直置中、不換行）。 */
/* 日期格：議題多時垂直置中會讓日期飄到中間 → 靠上對齊，一眼看得到哪天從哪列開始。 */
/* 合併的日期欄：原本整格灰底（--panel-2），在白內容面上就是一塊突兀的灰（2026-09-23 回饋
   「為甚麼日期那邊灰灰的」）。改用字重＋右側一條 hairline 表示「這幾列同一天」。 */
.data-table td.issue-day { vertical-align: top; padding-top: 12px; white-space: nowrap; font-weight: 600;
  border-right: 1px solid var(--line); color: var(--text); }

/* 當週議題「時程」檢視：週一～週五 × 09:00–19:00 的 30 分格線，卡片以絕對定位落在時間上，可拖拉改時間/改天。
   每小時 96px＝JS 的 PX_MIN(1.6)×60，改一邊就要改另一邊。 */
.isch-wrap { overflow-x: auto; padding: 12px; }
.isch-grid { display: flex; min-width: 720px; }
.isch-col { flex: 1 1 0; min-width: 0; border-inline-start: 1px solid var(--line); }
.isch-col.isch-axis { flex: 0 0 56px; border-inline-start: 0; }
/* 手機上時間軸橫捲時，時間那一欄黏在左邊不跟著捲走（打開時會捲到今天那一欄，見 planner_issues.js paintSchedule）；
   陰影往左補滿 .isch-wrap 的 12px 內距，捲過去的卡片不會從時間軸左邊露出來。 */
.isch-axis { position: sticky; left: 0; z-index: 1; background: var(--panel); box-shadow: -12px 0 0 var(--panel); }
.isch-col.is-today > .isch-head { color: var(--primary); }
.isch-head { height: 30px; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: var(--fs-sm); border-bottom: 1px solid var(--line-strong); white-space: nowrap; }
/* 時間格線用背景漸層畫：整點實線、每 15 分淡虛線。間距吃 --hour-h（由 JS 依 PX_MIN 帶進來）＝
   兩邊必然同步，卡片可落在任意 5 分位置、不受格子切割。 */
.isch-lane { position: relative; --hour-h: 144px; background-image:
  repeating-linear-gradient(to bottom, var(--line) 0 1px, transparent 1px var(--hour-h)),
  repeating-linear-gradient(to bottom, color-mix(in srgb, var(--line) 45%, transparent) 0 1px, transparent 1px calc(var(--hour-h) / 4)); }
.isch-lane.isch-over { background-color: var(--panel-2); }
.isch-hourlbl { position: absolute; right: 6px; transform: translateY(-2px); color: var(--muted); font-size: var(--fs-xs); }
.isch-axis .isch-lane { background-image: none; }
.isch-head-st { margin-inline-start: 6px; }
/* 每天的「會議開始時間」下拉：表格日期格與時程表頭共用。要壓成行內小控制項，但仍得留右側
   chevron 的空間（全站 select 的箭頭是背景圖，padding-right 被吃掉就會變成一顆沒箭頭的白方塊），
   底色也改吃所在格的底色，不要在淺色模式浮出一塊白。 */
.isch-head-st select, .issue-daystart {
  width: auto; min-height: 26px; font-size: var(--fs-xs); font-weight: 400;
  padding: 2px 22px 2px 8px; background-position: right 6px center; background-size: 11px;
  background-color: transparent; border-color: var(--line-strong); color: var(--text);
}
.isch-head-st select:hover, .issue-daystart:hover { background-color: var(--panel); }
/* 當週議題「參考資料」附件：圖片出小縮圖（點開 util.js 圖片檢視器），其他檔案出檔名連結（點＝下載）。 */
.issue-files { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
/* 對話框的參考資料列：一行輸入框（可打字／貼圖）＋旁邊「上傳檔案」鈕，貼上有明確落點。 */
.issue-ref-row { display: flex; gap: 8px; align-items: center; }
.issue-ref-row input[type="text"] { flex: 1; min-width: 0; }
.issue-ref-row button { flex-shrink: 0; }
.issue-thumb { line-height: 0; }
.issue-thumb img { height: 36px; width: 36px; object-fit: cover; border-radius: var(--r-sm); border: 1px solid var(--line); }
/* 表格那一欄要「窄」：9 欄表格裡最不該吃寬度的一欄，檔名一律省略號截斷，別把討論議題擠成一字一行。 */
.issue-file, .issue-file-chip { display: inline-flex; align-items: center; gap: 4px; padding: 3px 8px;
  border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--panel-2);
  font-size: var(--fs-sm); color: var(--muted-2); white-space: nowrap; }
.issue-file { max-width: 8rem; overflow: hidden; text-overflow: ellipsis; }
.issue-file:hover { color: var(--text); border-color: var(--line-strong); }
/* 對話框裡的附件籤：檔名長就在「檔名本身」省略，× 永遠不縮（曾因籤 overflow:hidden 把 × 整顆裁掉＝刪不掉）。 */
.issue-file-chip { max-width: min(22rem, 100%); }
.issue-file-chip > a, .issue-file-chip > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.issue-file-chip > button { flex-shrink: 0; }
/* 議題表：表頭一律不折行——欄位被擠窄時「編號」會斷成「編/號」兩行、與其他表頭高低不一（2026-09-22 修）。
   不折行＝瀏覽器把表頭文字寬當成該欄最小寬，窄視窗改由 .table-wrap 橫向捲動處理。 */
.issue-table th { white-space: nowrap; }
/* ④ 拖曳握把與編號同一條基線：原本 span 與文字節點各自對齊，點點會比數字高半行。 */
.issue-no { display: inline-flex; align-items: center; gap: 6px; font-variant-numeric: tabular-nums; }
.issue-no .issue-grip { display: inline-flex; align-items: center; line-height: 0; }
/* ② 視覺層級：表頭與資料拉開（表頭小字距＋較淡），列 hover 才浮起來；同一天用左側細線群組。 */
.issue-table td { vertical-align: top; }
/* 抓手游標只給拖得動的（JS 在可修改時才掛 draggable；當週議題唯讀的人看到的是一般游標） */
.issue-row[draggable="true"], .isch-card[draggable="true"] { cursor: grab; }
/* 日期格是整天合併的一格（rowspan，掛在當天第一則那一列）：不是拖曳把手，游標維持一般箭頭（JS 也不讓從這裡起拖，2026-10-05 回報） */
.issue-row > .issue-day { cursor: default; }
.issue-row.isch-dragging { opacity: .45; }
.issue-row.issue-row-over > td { box-shadow: inset 0 2px 0 var(--primary); }   /* 拖到此列上方的插入提示 */
.isch-card { box-sizing: border-box; overflow: hidden; border-radius: 6px; padding: 2px 6px;
  background: var(--primary-bg); border: 1px solid var(--primary-dark); font-size: var(--fs-xs); line-height: 1.35; }
/* 卡片矮到放不下兩行時只留客戶名（JS 依實際高度掛 isch-card-1line）——
   用降級而不是加高，加高就會蓋到下一張卡（2026-09-30 回報的重疊）。 */
.isch-card-1line .isch-card-2 { display: none; }
.isch-card:hover { border-color: var(--primary); }
.isch-card.isch-dragging { opacity: .45; }
/* 時程卡片＝客戶名／討論議題上下兩行、垂直置中、超出用省略號（時間看左側軸，細節看 tooltip／點開編輯）。
   原本是只放客戶名那時的 flex 橫排，加上第二行後兩段變成左右各半（議題只剩半寬），2026-10-02 改直排。
   兩行高＝12px×1.15×2＋上下內距 4＋框 2＝33.6 ≤ issue_sched.js TWO_LINE_PX(34)；放不下時 .isch-card-1line 只留客戶名。 */
.isch-card { display: flex; flex-direction: column; justify-content: center; }
/* Time Report：當日／本週工時（自動算，見 js/worklog_hours.mjs；怎麼算的寫在使用說明，不在頁面上）。 */
.tr-hours { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-4);
  padding-top: var(--sp-3); border-top: 1px solid var(--line); font-size: var(--fs-md); }
.tr-hours-val { font-family: inherit; font-variant-numeric: tabular-nums; font-size: var(--fs-h3); }   /* 同 .stat：Geist Mono 的 0 帶斜線，放大像「Ø」 */
.tr-hours-sep { color: var(--muted); }
/* 分隔點跟後一項同一個不折行的 span（worklog.js sepDot）：換行只會發生在「·」之前，不會掛在行尾 */
.tr-sum-item { white-space: nowrap; }
.tr-sum-item > .tr-hours-sep { margin-inline-end: 8px; }
/* Time Report 頁首的本月小結（在期間切換列下面） */
.tr-summary { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-2); font-size: var(--fs-md); }
/* 大數字同 .stat：內文字型＋tabular-nums（Geist Mono 的 0 帶斜線，放大就像「Ø」） */
.tr-summary .mono { font-family: inherit; font-variant-numeric: tabular-nums; font-size: var(--fs-h3); }
/* 月曆格子右下角的當日工時 */
.tr-cal-h { position: absolute; right: 6px; bottom: 4px; font-size: var(--fs-xs); color: var(--muted); }
.tr-cal-day.sel .tr-cal-h { color: var(--text); }

.isch-card-1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 600; line-height: 1.15; width: 100%; }
/* 第二行＝討論議題（2026-09-23 回饋）。卡片高度下限 MIN_CARD_H 保證這行放得下。 */
.isch-card-2 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.15;
  width: 100%; font-size: var(--fs-xs); color: var(--muted); }
/* 新增／編輯完那一則閃一下（planner_issues.js flash）：議題表的列、手機卡片、時程卡片都吃這一條 */
@keyframes issue-flash { from { background-color: color-mix(in srgb, var(--primary) 22%, transparent); } }
.issue-row.issue-flash > td, .issue-card.issue-flash, .isch-card.issue-flash { animation: issue-flash 1.6s var(--ease-out); }
/* 手機的議題卡片（paintCards，只在 ≤720px 產生）：依日期分組，卡片上直接放編輯／刪除 */
.issue-cards { display: flex; flex-direction: column; gap: 10px; }
.issue-card-day { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 6px; font-weight: 600; }
.issue-card-day:first-child { margin-top: 0; }
.issue-card { display: flex; flex-direction: column; gap: 6px; padding: 12px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel); }
.issue-card-hd { display: flex; align-items: baseline; gap: 10px; }
.issue-card-hd .issue-no { color: var(--muted); }
.issue-card-acts { text-align: right; }
.isch-un { display: flex; flex-wrap: wrap; gap: 8px; min-height: 46px; padding: 6px; border: 1px dashed var(--line-strong); border-radius: 8px; }
.isch-un.isch-over { background: var(--panel-2); }
.isch-card-un { width: 190px; }

/* ── 蘋果質感地基（2026-10-01）：浮層材質與進出場、按下回饋、列狀控件、等寬數字 ─────────────
   規則與出處見 DESIGN.md「Motion」「Materials」；token 在 :root（--dur-*／--ease-out／--spring*／--mat-*／--press-*／--lift-*）。
   這一段排在各元件自己的規則之後：同特異度靠順序蓋過它們原本寫死的底色／邊框／陰影。 */

/* 浮層（下拉選單／通知／人員挑選／匯出選單／日期選取器）：同一種半透明材質＋細邊＋陰影，同一套進出場——
   打開＝從 .96 放大淡入（縮放走彈簧、透明度走 ease-out），收起＝淡出縮回，不再「啪」一下出現／消失。
   display 由 JS 切（inline style 或 hidden 屬性）；transition 的 allow-discrete 讓 display 撐到淡出結束才真的消失，
   @starting-style 給「從 display:none 出來」的那一格起點。收起後那 200ms 不吃點擊，否則淡出中的選單會擋住下一下。
   overlay＝日期選取器的面板是 popover（top layer）：沒有它，hidePopover() 當下就掉出 top layer、淡出畫在對話框底下。 */
.nav-dd-menu, .notif-pop, .rp-menu, .exports-pop, .fm-menu, .ymp-pop {
  background: var(--mat-pop); -webkit-backdrop-filter: var(--mat-blur); backdrop-filter: var(--mat-blur);
  border: 1px solid var(--mat-edge); box-shadow: var(--sh-2);
  transition: opacity var(--dur-2) var(--ease-out), scale var(--dur-3) var(--spring), display var(--dur-2) allow-discrete,
    overlay var(--dur-2) allow-discrete;
}
@starting-style { .nav-dd-menu, .notif-pop, .rp-menu, .exports-pop, .fm-menu, .ymp-pop { opacity: 0; scale: .96; } }
[aria-expanded="false"] + :is(.nav-dd-menu, .notif-pop, .rp-menu, .fm-menu, .ymp-pop) { opacity: 0; scale: .96; pointer-events: none; }
.rp-menu { transform-origin: top left; }        /* 從觸發鈕那一側長出來（空間連續：從哪來、回哪去） */
.exports-pop { transform-origin: top right; }

/* 通知鈴鐺的下拉（main.js renderBell；原本是一串 inline style 加 .panel）。頭列捲動時釘住，底下的列從它後面模糊地滑過。 */
.notif-wrap { position: relative; }
.notif-pop { position: absolute; top: 130%; right: 0; z-index: 60; width: 300px; max-height: 360px; overflow: auto;
  overscroll-behavior: contain; border-radius: var(--r-md); transform-origin: top right; }
.notif-head { position: sticky; top: 0; z-index: 1; padding: .55rem .6rem; border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm); font-weight: 600; background: var(--mat-pop); -webkit-backdrop-filter: var(--mat-blur); backdrop-filter: var(--mat-blur); }
.notif-row { padding: .5rem .6rem; border-bottom: 1px solid var(--line); font-size: var(--fs-md); transition: background var(--tr); }
.notif-row.is-link { cursor: pointer; }
.notif-row.is-link:hover { background: var(--tag-bg); }

/* 列狀控件（清單列、選單項、分頁、月曆格）：按下不縮放——整列縮 3% 是一大塊在晃，Apple 的清單是「整列反白」；
   鍵盤焦點環畫在列裡面（HIG：清單用反白、欄位用環；列與列之間沒空隙，外擴的環會壓到鄰居、被捲動區切掉）。
   分頁不縮：底線／滑動底塊是量按鈕位置另外畫的、不跟著縮，按鈕一縮字就跟它錯開。 */
:is(.seg button, .seg [role="tab"], .nav-dd-item, .help-row, .jump-item, .cpl-row, .rp-item, .fm-opt, .add-domain-item,
  .exports-pop .menu-item, .tr-cal-day, .sh-main) {
  --press-scale: 1; outline-offset: calc(-1 * var(--focus-offset));
}
/* 長得像連結／導覽項／欄位的鈕：按下也不縮（旁邊的 <a> 連結、原生下拉都不會縮，同一列裡只有它縮就不一致）。焦點環照常在外面。 */
:is(.nav-dd-btn, .back-link, .help-link, .link-button, .toast-undo, .rp-btn, .ymp-btn, .fm-btn) { --press-scale: 1; }
/* 可點的卡片按下縮得比按鈕少（面積大，縮 3% 太晃）。按的是卡片裡的按鈕時卡片不跟著縮（:active 會一路套到祖先）。 */
.project-card[role="button"]:active:not(:has(:is(button, a, input, select, textarea):active)), .lawtype-card:active {
  scale: .985; --press-tr: var(--dur-1) var(--ease-out);
}
/* 看起來可以點的東西一律手指游標：整張可點的卡片是 div[role=button]（專案卡片原本沒有，滑上去是箭頭）。 */
[role="button"]:not([aria-disabled="true"]), summary { cursor: pointer; }
/* 會變動、要上下對齊的數字用等寬數字（Geist 預設是比例寬：1 比 0 窄，計數一變整串左右晃、表格日期欄對不齊）。 */
.tag, .badge, .nav-badge, .data-table, .kv dd, .pc-meta dd { font-variant-numeric: tabular-nums; }

/* ── G2 連續曲率圓角（Apple squircle）──────────────────────────────────
   支援 corner-shape 的瀏覽器（Chromium 139+）全站圓角改連續曲率，其餘瀏覽器優雅退回圓弧。
   正圓元素（頭像/圓點/knob/圓形 FAB）維持 round——squircle 會把正圓變方圓。 */
@supports (corner-shape: squircle) {
  *, *::before, *::after { corner-shape: squircle; }
  [style*="border-radius:50%"], [style*="border-radius: 50%"], .chip-x, .thumb-x, .iv-btn, .iv-bar, .iv-count,
  .theme-knob, .reviewer-av-img, .reviewer-av-def, .li-nav-dot, .switch .slider::before, .spinner, .btn-ic[aria-busy="true"]::before,
  .review-jump-fab, .ava-edit, .wish-ava,
  .penalty-view .pill::before, .penalty-view .kg-zoom-thumb,
  .penalty-view .lg-dot, .penalty-view .kg-tab .dot, .penalty-view .kg-link .dot,
  .penalty-view .law-fab,
  .penalty-view .law-timeline-node, .penalty-view .law-timeline-dot { corner-shape: round; }
  /* **膠囊（--r-pill / 999px）也一律 round**：pill 的兩端定義上就是半圓，squircle 會把它壓成
     平頭橢圓 → 旁邊再擺一顆真正圓的 knob（開關）就明顯不搭（2026-09-23 回饋「裡面的圓形跟外面的
     圓角矩形不一致」）。squircle 是給「有圓角的矩形」用的（卡片／按鈕／輸入框／頁籤），不是給
     pill 和正圓用的。**新增任何 --r-pill 元素請一併加進這串。** */
  .switch .slider, .progress, .progress > div, .tag, .badge, .chip, .fm-btn, .fm .dot, .seg-n,
  .reviewer-chip, .skill-tag, .skill-card2 .sk-track-dot, .pc-setup-flag::before, .filter-search input,
  .deck-pill, .deck-tag, .deck-open, .deck-spinner, .deck-row .rbar,
  .penalty-view .pill, .penalty-view .bartrack, .penalty-view .bar,
  .penalty-view .split, .penalty-view .li-badge, .penalty-view .serp-input,
  .penalty-view .serp-input .go, .penalty-view .serp-input .ai-ask, .penalty-view .serp-go,
  /* 2026-09-23 第二輪：靠 tools/shape_check.mjs 掃出來的漏網（grep --r-pill 抓不到，
     因為它們寫在各自的 styles.js 或 inline style 裡）。 */
  .nav-badge, .pm-cal-daynum, .qn-pill, .deck-view .dot, .issue-file, .issue-file-chip,
  /* 2026-09-30 第三輪：inline style 寫的膠囊（進度條、模擬身分橫幅）與 planner／workflow 注入樣式裡的漏網。 */
  [style*="border-radius:var(--r-pill)"], [style*="border-radius:999px"], .pm-cat-tag, .pm-col-dot, .wf-test, .wf-chip-pick button,
  .penalty-view .kg-tab .dot, .penalty-view .kg-link .dot, .penalty-view .dot { corner-shape: round; }
}

/* Skill／Prompt 模板分享庫 */
.skills-list { display: flex; flex-direction: column; gap: .75rem; }
.skill-card-head { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; }
.skill-tag { font-size: var(--fs-xs); padding: .1rem .5rem; border-radius: 999px; background: var(--panel-3); color: var(--muted-2); border: 1px solid var(--border, transparent); }
.skill-tag.accent { background: color-mix(in srgb, var(--accent, #c9a44a) 22%, var(--panel-3)); color: var(--text); }
.skill-body { display: block; margin-top: .6rem; padding: .75rem; background: var(--panel-3); border-radius: 8px; max-height: 420px; overflow: auto; white-space: pre-wrap; word-break: break-word; font-size: var(--fs-md); }
/* 新增／編輯表單：欄位是共用 .field，這裡只給欄與欄的間距（同 .dialog-body）。 */
.skill-form { display: grid; gap: 12px; scroll-margin-top: 88px; }   /* 88px＝讓開 sticky 頂欄（skills.js 按「編輯」會捲到表單頂端） */
.skill-form h3 { margin: 0; }
/* 「內容」是整份模板：field-sizing:content 只有一行字時框也只有一行高＝像單行欄位（rows 被忽略），給個編輯區的高度。 */
.skill-form textarea { min-height: calc(6lh + 20px); }

/* v2：依標籤分區（由上往下）＋卡片＋檢視內容右側抽屜 */
.skill-sections { display: flex; flex-direction: column; gap: 26px; }
.skill-section-head { display: flex; align-items: baseline; gap: 8px; margin: 0 0 12px; padding-bottom: 6px; border-bottom: 1px solid var(--line); }
.skill-section-title { font-weight: 600; font-size: var(--fs-body); letter-spacing: -.2px; }
.skill-section-count { color: var(--muted); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.skill-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 340px)); grid-auto-rows: 1fr; gap: 14px; }   /* 等高（同 .project-grid）：一區超過一列時，兩行標題的卡不會讓那一列比下一列高 */
/* 整張卡不可點（動作都在卡裡的按鈕上）：滑過只加深邊框、配合動作列浮現（見 @media (hover:hover) 那段），
   不浮起也不變灰——浮起是「整張可點」的記號（.project-card[role="button"]），變灰在淺色下把白底的下載鈕襯成一塊白補丁。 */
.skill-card2 { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md); padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; box-shadow: var(--sh-1); transition: border-color var(--tr); }
.skill-card2:hover { border-color: var(--line-strong); }
/* 定位到的那一則亮一下框（util.js revealHit）：Skill 庫存檔後的那張卡、鈴鐺連結 ?id= 帶到的許願／留言／公告／回報列。
   只動偽元素的 opacity；延遲 .3s＝等平滑捲動停下再亮，亮著停約 0.6s 才看得到（太短的閃一下在捲動途中就結束了）。 */
.skill-card2, .hit-flash { position: relative; }
.hit-flash::after { content: ""; position: absolute; inset: -1px; border-radius: inherit; pointer-events: none; opacity: 0;
  box-shadow: 0 0 0 2px var(--primary), 0 0 0 6px color-mix(in srgb, var(--primary) 22%, transparent); animation: hit-flash 1.6s ease .3s; }
@keyframes hit-flash { 20%, 60% { opacity: 1; } }
.wish-comment.hit-flash::after { inset: -4px -8px; border-radius: var(--r-sm); }   /* 留言沒有內距與圓角：框往外讓一點，別貼著字 */
.skill-card2 .sk-top { display: flex; align-items: center; gap: 6px; }
.skill-card2 .sk-title { margin: 0; font-size: var(--fs-body); letter-spacing: -.2px; overflow-wrap: anywhere; }
.skill-card2 .sk-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.skill-card2 .sk-track { display: flex; align-items: center; gap: 6px; font-size: var(--fs-xs); color: var(--muted); }
.skill-card2 .sk-track--manual { color: var(--muted-2); }
.skill-card2 .sk-track-dot { width: 7px; height: 7px; border-radius: var(--r-pill); background: var(--green); flex: none; }
.skill-card2 .sk-foot { margin-top: auto; display: grid; gap: 10px; align-items: end; }   /* 貼卡底：同列卡片被 grid 拉成等高時，狀態／動作都落在底緣 */
.skill-card2 .sk-actions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.sk-dl { text-decoration: none; display: inline-flex; align-items: center; justify-content: center; gap: 2px; min-height: 30px; padding: 0 13px; border: 1px solid var(--primary); border-radius: var(--r-sm); font-size: var(--fs-sm); }   /* 小尺寸 <a> 鈕（a 不吃 button 的 radius/padding，這裡補齊）：自動化的「開啟預覽／前往確認」。下載鈕改走全站 .btnlink.btn-ic */

/* 材質、進出場、收起要藏起來（visibility）：見「右側抽屜共用」（.review-jump-drawer 那段）。 */
.skill-drawer { position: fixed; top: 0; right: 0; height: 100vh; height: 100dvh; width: 460px; max-width: 92vw; z-index: 61; display: flex; flex-direction: column; }
.skill-drawer .skd-head { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--line); }
.skill-drawer .skd-head h3 { margin: 0; flex: 1; min-width: 0; font-size: var(--fs-body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.skill-drawer .skd-meta { padding: 10px 16px; border-bottom: 1px solid var(--line); display: flex; flex-direction: column; gap: 8px; }
.skill-drawer .skd-actions { display: flex; gap: 6px; align-items: center; }
.skill-drawer .skd-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 14px 16px; }
.skill-drawer .skd-content { white-space: pre-wrap; word-break: break-word; font-size: var(--fs-sm); margin: 0; }
.skill-scrim { position: fixed; inset: 0; z-index: 60; background: rgba(0, 0, 0, .35); opacity: 0; pointer-events: none; transition: opacity var(--dur-2) var(--ease-out); }
.skill-scrim.show { opacity: 1; pointer-events: auto; }

/* 搜尋紀錄（views/search_history.js）：依台北日期分組，一天一張卡、列與列之間 hairline。
   列＝整列可點的主區 .sh-main（AI 搜尋＝展開問題的按鈕、關鍵字檢索＝回到那次檢索的連結）＋列尾 .row-actions。
   窄螢幕時動作自己換到下一行（flex-wrap＋主區 260px 起跳），不另寫手機規則。 */
.sh-day + .sh-day { margin-top: var(--sp-4); }
.sh-day-h { margin: 0 0 8px; font-size: var(--fs-sm); font-weight: 600; color: var(--muted-2); }
.panel.sh-items { padding: 4px 8px; }
.sh-item { display: flex; flex-wrap: wrap; align-items: center; column-gap: 8px; padding: 4px 0; border-bottom: 1px solid var(--line); }
.sh-item:last-child { border-bottom: 0; }
.sh-main { flex: 1 1 260px; min-width: 0; display: flex; align-items: center; gap: 10px; min-height: 0; padding: 8px;
  border: 0; border-radius: var(--r-sm); background: none; box-shadow: none; color: var(--text); text-align: left; text-decoration: none; }
.sh-main:hover { background: var(--panel-2); }
.sh-ic, .sh-caret { display: inline-flex; flex: none; color: var(--muted-2); }
.sh-caret { transition: transform var(--tr); }
.sh-main[aria-expanded="true"] .sh-caret { transform: rotate(90deg); }
.sh-text { display: grid; gap: 2px; flex: 1 1 auto; min-width: 0; }
.sh-title { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.sh-meta { color: var(--muted); font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
.sh-acts { flex: none; margin-left: auto; }
/* 展開的問題清單：獨佔一行、字與標題對齊（8px 內距＋16px 圖示＋10px 間距），編號落在圖示那一欄 */
.sh-qs { flex-basis: 100%; margin: 0 0 8px; padding: 0 8px 0 34px; font-size: var(--fs-sm); color: var(--muted-2); overflow-wrap: anywhere; }
.sh-qs li + li { margin-top: 4px; }
.sh-more { margin-top: var(--sp-3); text-align: center; }

/* ================================================================
   手機（≤720px）— 單一斷點集中在此，別再各處零散加 media query。
   原則：①頂欄導覽收進漢堡抽屜 ②多欄一律塌成單欄 ③橫向不溢出（表格包 .table-wrap、
   分頁列可橫捲）④tap target ≥40px。桌面完全不受影響（全部包在 max-width 內）。
   ≤900/860/820/760px 的既有斷點維持原狀，此區塊只補手機寬度。
   ================================================================ */
@media (max-width: 720px) {
  /* ---- 頂欄：品牌縮小，導覽收進漢堡，右側只留鈴鐺（其餘工具由 main.js 移進抽屜） ---- */
  /* 固定 60px 高：抽屜靠它算高度（見 .mainnav）。 */
  .topbar { flex-wrap: nowrap; gap: 8px; padding: 10px 12px; height: 60px; box-sizing: border-box; }
  .brand { min-width: 0; gap: 8px; flex: 1; overflow: hidden; }
  .brand-logo { width: 32px; height: 32px; }
  .brand-text { min-width: 0; }
  .topbar h1 { font-size: var(--fs-body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .eyebrow { display: none; }
  .userbox { gap: 2px; flex: none; }
  /* 觸控目標 44×44（HIG）：頂欄的 (i)／鈴鐺原本是 34×30 的桌面尺寸 */
  .userbox > button, .userbox .notif-wrap > button { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; }

  .nav-toggle { display: inline-flex; align-items: center; justify-content: center; flex: none;
    width: 40px; min-height: 40px; padding: 0; border: 0; background: transparent; color: var(--text); box-shadow: none; }
  .nav-toggle:hover { background: var(--panel-2); }
  body.nav-open .nav-toggle { background: var(--panel-2); color: var(--primary-hover); }

  /* 抽屜＝頂欄下方整片，左滑入。visibility 讓收合時不吃點擊。
     坑：.topbar 有 backdrop-filter → 它會成為 position:fixed 子元素的容器塊，
     fixed + bottom:0 會被算成「頂欄內」而塌成一條（38px）。故用相對頂欄的 absolute + 明確高度。 */
  /* 高度扣 59 不是 60：absolute 的 top:100% 量的是頂欄的 padding box（60px 扣掉 1px 下框線），扣 60 會差 1px、
     抽屜底下露出一條頁面（2026-10-01 手機實測：底緣 663、畫面 664）。抽屜自己的上框線剛好疊在頂欄那條上。 */
  .mainnav { position: absolute; left: 0; right: 0; top: 100%; z-index: 65;
    height: calc(100vh - 59px); height: calc(100dvh - 59px);
    flex-direction: column; align-items: stretch; gap: 2px; padding: 10px 12px 28px;
    background: var(--bg); border-top: 1px solid var(--line);
    overflow-y: auto; overscroll-behavior: contain;
    transform: translateX(-100%); visibility: hidden; transition: transform .2s var(--ease), visibility .2s; }
  body.nav-open .mainnav { transform: none; visibility: visible; }
  .navlink { min-height: 44px; display: flex; align-items: center; font-size: var(--fs-body); }
  /* 下拉在抽屜內改為就地展開（不浮出），維持原本 aria-expanded 行為 */
  .nav-dd { display: block; }
  .nav-dd-btn { width: 100%; justify-content: space-between; min-height: 44px; }
  /* 抽屜裡是就地展開的子清單，不是浮層：不要材質、也不要縮放進出場（展開／收起會推動下面的項目，淡出期間佔著位置更怪）。 */
  .nav-dd-menu { position: static; min-width: 0; padding: 2px 0 6px 14px;
    border: 0; border-left: 1px solid var(--line); border-radius: 0; background: transparent; box-shadow: none;
    -webkit-backdrop-filter: none; backdrop-filter: none; transition: none; }
  .nav-dd-item { min-height: 40px; display: flex; align-items: center; }
  /* 抽屜最底：切換身分／Bug／主題／個人資料／登出（桌面時這些在頂欄右上）。每顆 44px 高、間距 8px（原本 34×30、間距 6px）；
     登出排最後並推到最右邊（main.js），不再夾在主題與個人資料中間、一碰就登出。 */
  .nav-userbox { display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
  .nav-userbox > button { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; }
  .nav-userbox > .nav-logout { margin-left: auto; }

  /* ---- 版面骨架 ---- */
  .view { padding: var(--sp-4) 16px calc(var(--sp-5) + env(safe-area-inset-bottom)); }
  .page-head { flex-direction: column; align-items: stretch; gap: 10px; margin-bottom: var(--sp-4); }
  .head-actions > * { flex: 1 1 auto; }
  /* 覆核頁「匯出」是 <details>：撐寬的是外層、裡面的 summary 鈕仍是內容寬 ⇒ 鈕跟右邊那顆中間空一大段。讓鈕吃滿外層。 */
  .head-actions > .exports-menu > summary { display: flex; justify-content: center; }
  .layout { gap: 16px; }
  .card { min-height: 0; padding: 18px 16px; }
  .panel, .card { overflow-wrap: anywhere; }   /* 長字號／URL 不撐破版面 */
  /* 表格例外：它會一路繼承進格子，email 被拆成一個字元一行、整張表硬塞進 390px（使用者管理的帳號欄）。
     表格本來就在 .table-wrap 裡橫捲，長字讓它撐寬就好。 */
  .data-table { overflow-wrap: normal; }
  .control-point { font-size: var(--fs-h3); }
  .project-grid { grid-template-columns: 1fr; }
  .stat-row { grid-template-columns: 1fr 1fr; }
  .stat strong { font-size: var(--fs-h2); }

  /* ---- 分頁列／篩選列：換行，不橫捲 ----
     原本做成「橫捲＋隱藏捲軸」，看起來是完整一列、其實第 4 個分頁在畫面外，
     使用者不會知道要滑（2026-09-22 回報「沒有完整秀出畫面」的其中一項）。
     手機寧可多佔一行也要全部看得到。 */
  /* 分頁列與分段切換都撐滿整列、平均分寬（Material 3 fixed tabs／iOS 分段控制）：
     ①底線頁籤放不下就整顆換到下一列；細底軌改畫在每顆按鈕上，換行後每一列底下都有軌、
       目前那一頁的底線落在它自己那一列（只畫在列上的話，第一列的頁籤底下是空的）。
     ②第一顆不再往左吃內距（頁籤從邊緣排滿，字已經各自置中）。 */
  .seg { display: flex; }
  .seg > button { flex: 1 1 auto; white-space: nowrap; }
  .seg.seg-bar { box-shadow: none; }
  .seg.seg-bar { --seg-pad: 8px; }
  .seg.seg-bar > button { box-shadow: inset 0 -1px 0 var(--tab-line); border-radius: 0; }   /* 圓角會把底軌兩端往上彎 */
  .seg.seg-bar > .seg-ind + button { margin-left: 0; }
  .filter-bar { gap: 6px; }
  .filter-bar .filter-search { flex: 1 1 100%; max-width: none; }

  /* ---- 表格：一律橫捲（.table-wrap），不縮字到看不清 ---- */
  .table-wrap { -webkit-overflow-scrolling: touch; }
  .data-table { --cell-px: 10px; }   /* 動作欄的「左內距少給 10px」跟著變 0 */
  .data-table th, .data-table td { padding: 8px var(--cell-px); }
  .data-table td.row-actions, .data-table td:has(> .row-actions) { padding-block: 2px; }   /* 同桌面那條的算法：列距 8px 時收成 2px */
  .data-table td.detail { max-width: 60vw; }

  /* ---- 對話框：近全幅，內距收緊 ---- */
  .app-dialog { width: calc(100vw - 16px); max-height: 88vh; max-height: 88dvh; }
  /* 本文上限要扣在 88dvh 的框裡（桌面那條是 100dvh-200px）：不扣的話整個對話框自己變成可捲，聚焦到下面的欄位時
     標題列被捲出框外（2026-10-01）。190＝內距 32＋標題 34＋本文上下外距 32＋動作列（錯誤一列＋按鈕一列）約 90。 */
  .dialog-body { max-height: calc(88vh - 190px); max-height: calc(88dvh - 190px); }
  .app-dialog > form, .app-dialog > .dialog-wrap { padding: 16px; }
  .dialog-actions { flex-wrap: wrap; }
  .dialog-actions > * { flex: 1 1 auto; }
  .dialog-actions > .dialog-error { flex-basis: 100%; }   /* 錯誤字獨佔一列，按鈕在下一列對半 */
  /* 關閉 ×（對話框頭列、抽屜）：圖示照舊 18px，觸控範圍撐到 44×44；負外距吃回多出來的內距＝頭列高度與位置不變
     （原本 26×26，全幅的使用說明抽屜只有這一顆能關，2026-10-01 手機實測） */
  .close-x { padding: 13px; margin: -9px; }
  /* iPhone Safari 對字級小於 16px 的欄位一聚焦就把整頁放大、而且不縮回：對話框的欄位吃 .field 的 14px、搜尋框 13px
     （2026-10-01 手機實測）。手機一律 ≥16px；比 16 大的維持原樣。!important＝各元件自己的欄位字級（篩選搜尋框、
     裁罰主搜尋列…）特異度都比這條高，要全部壓過才不會漏一個。 */
  input:not([type=checkbox], [type=radio], [type=range], [type=color], [type=file]), select, textarea { font-size: max(var(--fs-body), 1em) !important; }
  /* 漢堡選單開著＝吐司改到頂欄下方（底部是深淺色／登出那一列）。其餘貼在底部的東西（Bug 回報膠囊／底部抽屜、黏底列、
     切換身分橫幅）由 util.js liftToast() 量它們的上緣、把吐司墊上去。 */
  body.nav-open .toast { top: 72px; bottom: auto; }

  /* ---- 圖片檢視彈窗：側邊留白收掉換取寬度、控件 44px 觸控尺寸、翻頁鈕沉到底避開拇指與圖片。
     （.app-dialog.img-viewer 是 0,2,0 特異度，上面 .app-dialog 的 calc(100vw-16px)/88vh 吃不進來。）---- */
  .app-dialog.img-viewer { padding: 56px 0 calc(76px + env(safe-area-inset-bottom)); }
  .iv-btn { width: 44px; height: 44px; min-height: 44px; }
  .iv-close { top: calc(10px + env(safe-area-inset-top)); right: 10px; }
  .iv-count { top: calc(10px + env(safe-area-inset-top)); left: 10px; }
  .iv-nav { top: auto; margin-top: 0; bottom: calc(14px + env(safe-area-inset-bottom)); }
  .iv-nav.prev { left: 10px; }
  .iv-nav.next { right: 10px; }
  .iv-bar { bottom: calc(14px + env(safe-area-inset-bottom)); }

  /* ---- 覆核頁動作列：sticky 底列避開 home indicator ---- */
  .actions { padding: 10px; padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
  .actions button { flex: 1 1 auto; }
  /* 跳題 FAB：手機內容貼著 16px 邊距排滿，右緣中段那顆 44px 圓鈕會壓在統計卡上（2026-10-01 二輪體檢「330 剩餘」被蓋住）。
     收成貼齊右緣的半圓把手：寬 32px＝16px 邊距＋16px 卡片內距，只壓到卡片的框，不壓字也不壓控件。 */
  .review-jump-fab { right: 0; width: 32px; height: 48px; border-radius: var(--r-pill) 0 0 var(--r-pill); }


  /* 使用說明抽屜：手機沒有並排空間 → 全幅＋遮罩（桌面刻意無遮罩，可邊看邊操作） */
  .help-drawer { width: 100%; max-width: none; }

  /* Bug 回報面板＝底部抽屜（滿寬貼底、只圓上兩角），預設收成右下角膠囊（bugpanel.js 建立時看 isNarrow()），點開才展開。
     原本 340×485 的浮動面板蓋住 64% 畫面（2026-10-01 UX 實測）。 */
  .bugpanel { left: 0; right: 0; bottom: 0; width: auto; max-width: none; max-height: 72vh; max-height: 72dvh;
    border-width: 1px 0 0; border-radius: var(--r-lg) var(--r-lg) 0 0; }
  .bugpanel-body { flex: 1 1 auto; min-height: 0; max-height: none; }
  .bugpanel-foot { padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
  .bugpanel .mv-item { min-height: 36px; }
  .bugpanel.bp-collapsed { left: auto; right: 12px; bottom: calc(12px + env(safe-area-inset-bottom)); border-width: 1px; }
  .bp-paste-hint { display: none; }   /* 手機沒有 Ctrl+V，改用「選擇圖片」 */
  /* 漢堡抽屜開著就整個藏起來：面板在 body 層（z 60），抽屜困在頂欄的疊層（頂欄 z 20）裡，原本整片被面板蓋住、
     底部的深淺色／登出／個人資料都點不到。打開漢堡時 bugpanel.js 另會把面板收回膠囊。 */
  body.nav-open .bugpanel { display: none; }

  /* 頂層分頁拖曳把手在手機會與邊緣滑動手勢打架 → 收起（抽屜已可導覽） */
  .ts-pill { display: none; }
}

/* 手機專屬版面（節點由 JS 在 isNarrow() 時才產生，桌面完全不會出現這些 class）：
   工作日誌逐日卡片、Time Report 時段卡片。兩者都是「表格欄太多、手機排不下」才改堆疊。 */
@media (max-width: 720px) {
  /* 專案管理 hub 頁首（工作日誌／Time Report）：期間切換列與匯出放同一列，匯出縮成 40px 圖示鈕；週選取器只留圖示
     （週別就寫在正下方的週標題）。原本「‹ 週 ›」「本週」「匯出」各佔一列，正文到第二個畫面才開始（2026-10-02 手機實測）。 */
  .page-head:has(> .head-actions > .pm-export) { flex-direction: row; align-items: flex-start; }
  .page-head:has(> .head-actions > .pm-export) > :first-child { flex: 1 1 auto; min-width: 0; }
  .head-actions > .pm-export { flex: none; width: 40px; padding: 0; }
  .pm-export-label { display: none; }
  .pm-nav[data-unit="週"] .ymp-btn-label { display: none; }
  /* 月份字改成「2026 年 10 月」後變長，「本月」被擠到第二列：手機的月份選取器拿掉日曆圖示（約 24px）就排得下 */
  .pm-nav[data-unit="月"] .ymp-btn-ico { display: none; }
  /* 本月小結折行時「·」會掛在第二行開頭：手機拿掉分隔點，改用間距分開 */
  .tr-summary .tr-hours-sep { display: none; }
  .tr-summary { column-gap: 16px; }

  .diary-days { display: flex; flex-direction: column; gap: 14px; }
  .diary-day { border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel); padding: 12px; scroll-margin-top: 72px; }   /* 打開時捲到今天那張卡：別停在頂欄底下 */
  .diary-day-hd { font-weight: 600; margin-bottom: 8px; }
  .diary-day-f { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; color: var(--muted); font-size: var(--fs-sm); }
  .diary-day-f:last-child { margin-bottom: 0; }
  .diary-day-f textarea { color: var(--text); font-size: var(--fs-body); }

  .tr-slot-cards { display: flex; flex-direction: column; gap: 10px; }
  .tr-slot-card { border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel); padding: 12px; }
  .tr-slot-card.tr-slot-covered { background: var(--panel-2); }
  .tr-slot-top { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
  /* 開始／結束下拉不准縮到看不完 HH:MM（原本 min-width:0，有「併」的卡片被擠成「10:3」「18:3」，
     還比第一張沒有「併」的卡片窄一截）。下拉不伸不縮＝每張卡一樣寬；真的放不下（約 360px 以下）才讓「併／×」換到下一行。 */
  .tr-slot-top .tr-time { flex: 1 1 auto; min-width: auto; }
  .tr-slot-top .tr-time select { flex: 0 0 auto; min-width: 4.75rem; }
  /* 編輯器已經在分頁的內容面裡：手機不再包一層卡（卡中卡＝兩層 24px 內距，時段卡只剩 230px 寬）。
     :has(.save-bar)＝只動本人的編輯器，不動「使用者與稽核 › 工作紀錄」那個唯讀面板（也用 .tr-editor）。 */
  .tr-editor > .panel:has(> .save-bar) { margin-top: var(--sp-4); padding: 0; border: 0; background: none; box-shadow: none; }
  .tr-slot-acts { display: flex; align-items: center; gap: 4px; flex: none; }
  .tr-slot-f { display: flex; flex-direction: column; gap: 4px; margin-top: 10px; color: var(--muted); font-size: var(--fs-sm); }
  .tr-slot-f input { color: var(--text); font-size: var(--fs-body); }
  .tr-slot-note { margin: 8px 0 0; font-size: var(--fs-sm); }
  /* 空的時段卡只露出「工作內容摘要」：點進卡片（focus-within）或打了字（.has-content，worklog.js 維護）才展開客戶／產物／備註。
     預設 8 張空卡原本每張 360px、整頁 4,000 多 px。待辦卡（.tr-todo-card）不收。 */
  .tr-slot-card:not(.tr-todo-card, .has-content):not(:focus-within) .tr-slot-f + .tr-slot-f { display: none; }
  /* 待辦也是卡片（原本 5 欄表格要橫捲、應完成日被切成「yyyy/」）：× 在右上角 */
  .tr-todo-card { position: relative; }
  .tr-todo-card > .rm-x { position: absolute; top: 6px; right: 6px; }
  .tr-todo-card > .tr-slot-f:first-of-type { margin-top: 0; }
  /* 當週議題時程：每欄要放得下「10/2（五）」＋開始時間下拉（約 137px）；720px 的格線分到每欄只有 133px，日期被折成兩行 */
  .isch-grid { min-width: 780px; }

  /* 儲存列釘在畫面底（日誌要捲過 5 張卡才摸得到儲存）。sticky 而非 fixed：捲到最底時回到原本位置、
     接在最後一張卡後面，不會蓋住最後一列，也不必另外給內容墊底部留白。外觀同覆核頁的 .actions（材質 --mat-bar＋--mat-blur）。 */
  .save-bar { position: sticky; bottom: 0; z-index: 2; justify-content: space-between;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
    border: 1px solid var(--mat-edge); border-radius: var(--r-sm);
    background: var(--mat-bar); -webkit-backdrop-filter: var(--mat-blur); backdrop-filter: var(--mat-blur); }
  .save-bar > button { flex: none; min-width: 7rem; }

  /* 更新覆核「本期法規異動」：五格排成兩欄三列；清單每列的標籤與編號 chip 換到第二行 */
  .lc-stats { grid-template-columns: 1fr 1fr; }
  .lc-unit { flex-wrap: wrap; }
  .lc-unit-r { flex: 1 1 100%; flex-wrap: wrap; }
}
