/* ════════════════════════════════════════════════
   components.css  ─  ISMS 共用 UI 元件
   (依賴 global.css 中定義的 CSS 變數)
   ════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════
   BUTTONS
   ════════════════════════════════════════════════ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 16px; border-radius: var(--r-md);
  font-family: var(--font); font-size: 13.5px; font-weight: 500;
  border: 1px solid transparent; cursor: pointer;
  transition: background var(--tr), border-color var(--tr), color var(--tr), box-shadow var(--tr);
  white-space: nowrap; line-height: 1;
}
.btn svg { flex-shrink: 0; }

.btn-primary   { background: var(--clr-accent);   color: #fff; border-color: var(--clr-accent); }
.btn-primary:hover { background: var(--clr-accent-hover); border-color: var(--clr-accent-hover); }

.btn-secondary { background: var(--clr-surface); color: var(--clr-text-sec); border-color: var(--clr-border); }
.btn-secondary:hover { background: var(--clr-border-light); color: var(--clr-text); }

.btn-danger    { background: var(--clr-danger); color: #fff; border-color: var(--clr-danger); }
.btn-danger:hover { background: var(--clr-danger-hover); border-color: var(--clr-danger-hover); }

/* 2026-08-05 補：btn-warning 先前只被 JS 用、CSS 沒定義，
   AssetsView 的「改為停用」按鈕因此是裸的（無底色無框）。
   AssetAssessmentView 那顆有 inline style 兜底所以看不出問題，
   一併移除其 inline style 改用這裡的定義，避免同一個 class 兩種長相。
   用於「有後果但可復原」的操作（停用、批次覆寫），語意介於 primary 與 danger 之間。 */
/* 2026-08-10：原本 fallback 寫 #f59e0b、hover 寫 #d97706，而 --clr-warning 本身就是
   #d97706——等於 hover 跟 normal 同色、fallback 又是第三種黃。改成 token 後
   normal＝--clr-warning、hover＝--clr-warning-hover，這顆按鈕才真的有 hover 反應。 */
.btn-warning   { background: var(--clr-warning); color: #fff; border-color: var(--clr-warning); }
.btn-warning:hover { background: var(--clr-warning-hover); border-color: var(--clr-warning-hover); }

.btn-ghost     { background: transparent; color: var(--clr-text-sec); border-color: transparent; }
.btn-ghost:hover { background: var(--clr-border-light); color: var(--clr-text); }

.btn-sm { padding: 5px 11px; font-size: 12px; border-radius: var(--r-sm); }

/* ════════════════════════════════════════════════
   TOOLBAR
   ════════════════════════════════════════════════ */
.toolbar {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; margin-bottom: 16px;
}
.toolbar-spacer { flex: 1; }

/* 工具列右側的按鈕群（使用者 2026-08-20：「我要看到他們平行」）。
   為什麼要包一組：`margin-left:auto` 掛在單一顆按鈕上時，它只會被推到
   **當前那一列**的最右邊，後面的按鈕就被擠到下一列自己一個人——
   側邊欄展開、寬度變窄時就會發生。包成一組之後，空間夠就整組靠右，
   不夠就整組一起換行、彼此仍然並排。 */
.toolbar .toolbar-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
/* 在群組裡就不要再自己往右推了，不然兩顆之間會被撐開。 */
.toolbar .toolbar-actions .toolbar-reload { margin-left: 0; }

.toolbar .toolbar-reload {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.toolbar .toolbar-reload::before {
  content: '';
  width: 13px;
  height: 13px;
  flex-shrink: 0;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='23 4 23 10 17 10'/%3E%3Cpolyline points='1 20 1 14 7 14'/%3E%3Cpath d='M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15'/%3E%3C/svg%3E") no-repeat center / contain;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='23 4 23 10 17 10'/%3E%3Cpolyline points='1 20 1 14 7 14'/%3E%3Cpath d='M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15'/%3E%3C/svg%3E") no-repeat center / contain;
}

.toolbar .toolbar-reload svg {
  display: none;
}

/* ════════════════════════════════════════════════
   FORM CONTROLS
   ════════════════════════════════════════════════ */
.form-input,
.form-select {
  height: 38px; padding: 0 12px;
  border: 1px solid var(--clr-border); border-radius: var(--r-md);
  font-family: var(--font); font-size: 13.5px; color: var(--clr-text);
  background: var(--clr-surface); outline: none;
  transition: border-color var(--tr), box-shadow var(--tr);
}
.form-input:focus,
.form-select:focus {
  border-color: var(--clr-accent);
  box-shadow: 0 0 0 3px var(--clr-accent-ring);
}
.form-input::placeholder { color: var(--clr-text-muted); }

/* Search with icon */
.search-wrapper { position: relative; display: inline-flex; align-items: center; }
.search-wrapper .search-icon {
  position: absolute; left: 10px; pointer-events: none; color: var(--clr-text-muted);
}
.form-input.search-input { padding-left: 36px; }

.form-label {
  display: block; font-size: 12.5px; font-weight: 500;
  color: var(--clr-text-sec); margin-bottom: 6px;
}
.form-group { margin-bottom: 16px; }

.form-textarea {
  width: 100%; padding: 9px 12px;
  border: 1px solid var(--clr-border); border-radius: var(--r-md);
  font-family: var(--font); font-size: 13.5px; color: var(--clr-text);
  background: var(--clr-surface); resize: vertical; min-height: 80px; outline: none;
  transition: border-color var(--tr), box-shadow var(--tr);
}
.form-textarea:focus {
  border-color: var(--clr-accent);
  box-shadow: 0 0 0 3px var(--clr-accent-ring);
}

/* ════════════════════════════════════════════════
   CARD / PANEL
   ════════════════════════════════════════════════ */
.card {
  background: var(--clr-surface);
  border: 1px solid var(--clr-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
}
.card-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px; border-bottom: 1px solid var(--clr-border-light);
}
.card-title { font-size: 14px; font-weight: 600; color: var(--clr-text); }
.card-body  { padding: 20px; }
.card-badge {
  font-size: 11px; font-weight: 500;
  background: var(--clr-border-light); color: var(--clr-text-sec);
  padding: 3px 10px; border-radius: 100px;
}

/* ════════════════════════════════════════════════
   DATA TABLE
   ════════════════════════════════════════════════ */
.table-wrapper {
  width: 100%; overflow-x: auto;
  border-radius: var(--r-lg);
  border: 1px solid var(--clr-border);
  box-shadow: var(--shadow-sm);
}
.data-table {
  width: 100%; border-collapse: collapse;
  font-size: 13.5px; background: var(--clr-surface);
}
.data-table thead tr {
  background: var(--clr-border-light);
  border-bottom: 1px solid var(--clr-border);
}
.data-table th {
  padding: 11px 14px; text-align: left;
  font-size: 11.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .6px;
  color: var(--clr-text-muted); white-space: nowrap;
}
/* 表頭裡放的是「資料」而不是欄位名稱時，關掉大寫（2026-08-12）。
   .data-table th 的 text-transform: uppercase 是給欄位名稱用的裝飾，
   但通知設定的表頭放的是端點名稱——「系統網路組Discord頻道」被喊成
   「系統網路組DISCORD頻道」，在 TANET 論文圖上會被當成排版錯誤。
   使用者選 A：只關這兩頁，不動全站表頭外觀。 */
.data-table th.th-data {
  text-transform: none;
  letter-spacing: 0;
}
.data-table td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--clr-border-light);
  color: var(--clr-text); vertical-align: middle;
}
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr:hover { background: var(--clr-row-hover); }

/* Empty state */
.table-empty       { text-align: center; padding: 50px 20px; }
.table-empty-icon  {
  width: 48px; height: 48px; border-radius: var(--r-lg);
  background: var(--clr-border-light);
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto 12px;
}
.table-empty-title { font-size: 14px; font-weight: 600; color: var(--clr-text-sec); margin-bottom: 4px; }
.table-empty-sub   { font-size: 12.5px; color: var(--clr-text-muted); }

/* ════════════════════════════════════════════════
   BADGE
   ════════════════════════════════════════════════ */
.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 9px; border-radius: 100px;
  font-size: 11.5px; font-weight: 500; white-space: nowrap;
}
.badge-success { background: var(--clr-success-bg); color: var(--clr-success); }
.badge-danger  { background: var(--clr-danger-bg);  color: var(--clr-danger); }
.badge-warning { background: var(--clr-warning-bg); color: var(--clr-warning); }
.badge-info    { background: var(--clr-info-bg);    color: var(--clr-info); }
.badge-neutral { background: var(--clr-border-light); color: var(--clr-text-sec); }

/* ── 必填欄位的星號（Z0-27，2026-08-14 使用者：「強制填寫的欄位加上*　一律顯示紅色的」）──
   原本 `.req` 只定義在 rules-modal.css 的 `.rmodal .req` 底下，
   所以規則彈窗以外的 35 處 `class="req"` 星號**完全沒有顏色**，跟沒加一樣。
   提到這裡變成全站通用，任何地方寫 <span class="req">*</span> 都會是紅的。
   ⚠️ 不要再用 inline style 寫星號顏色，也不要直接在 label 文字裡打 " *"。 */
.req { color: var(--clr-danger); font-weight: 700; }

/* ── 停用列的淡化（Z0-19） ──
   原本只有資產清冊有淡化，而且寫死 opacity:.65 在 View 裡；其他 17 支清單頁一律沒有。
   靠 UI.statusBadge() 在停用的 badge 上加 data-inactive="1"，這裡一條規則就能覆蓋全站，
   不必逐頁重寫 <tr> 的 inline style（那正是「同一個規則散在各頁」的老問題）。
   `:has()` 不支援的舊瀏覽器只是不淡化，不會壞掉；需要手動指定時可直接加 .row-inactive。

   數值沿革（**不要再自己改，改了要有使用者的話當依據**）：
     2026-08-12 拍板 50% → 2026-08-14 會議一度改 25% → **同日看過並排比較後定為 65%**。
   65% 也正好是資產清冊原本的值，等於「以既有畫面為準，其餘 17 頁向它看齊」。 */
tr:has([data-inactive="1"]),
.row-inactive { opacity: .65; }

/* 例外（Z0-19，2026-08-14 會議）：清單上方的「狀態」篩選被選成「停用」時，取消淡化。
   那時整張表全是停用資料，再淡化只會看不清楚，也失去「用淡化區分停用列」的意義。
   做法是由清單元件在表格外層掛 data-filter="inactive"，各頁不必自己寫 JS。 */
[data-filter="inactive"] tr:has([data-inactive="1"]),
[data-filter="inactive"] .row-inactive { opacity: 1; }

/* 逐列發送時的「發送中」轉圈（Z4-04）。放這裡而不是各頁自己寫 keyframes，
   是因為 index.html 已經有一個 @keyframes spin，再寫一份就是同一個東西兩份定義。 */
.nt-spinner {
  display: inline-block; width: 13px; height: 13px; vertical-align: -2px;
  border: 2px solid var(--clr-border); border-top-color: var(--clr-accent);
  border-radius: 50%; animation: spin .7s linear infinite;
}

/* List enhancer: pagination + rule warning indicators */
.list-pagination {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 12px;
  font-size: 13px;
  color: #4b5563;
}

.list-pagination button {
  border: 1px solid #d1d5db;
  background: #fff;
  border-radius: 6px;
  padding: 4px 10px;
  cursor: pointer;
}

.list-pagination button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ── 可以點來排序的表頭（老師 2026-08-21 提）──
 *
 * 一般網頁的慣例（Excel、GitHub、Gmail 都一樣）：
 *
 *   沒在排序      只有欄位名，箭頭很淡（但**要存在**，不然沒人知道可以點）
 *   滑鼠移上去    箭頭變明顯，游標變手指
 *   正在排        欄位名變深、箭頭實心
 *
 * ⚠️ 箭頭不能「沒在排序時完全不顯示」。那樣使用者不會知道這一欄可以點，
 *    功能等於不存在。淡到幾乎看不見、但滑過去會浮出來，才是對的。
 *
 * ⚠️ 箭頭用 inline-block 固定寬度。不固定的話，
 *    ⇅ 換成 ▲ 的時候欄寬會抖一下——整張表跟著晃。
 */
.data-table th.th-sortable {
  cursor: pointer;
  user-select: none;                 /* 連點兩下不要選到文字 */
  white-space: nowrap;
}

.data-table th.th-sortable:hover,
.data-table th.th-sortable:focus-visible {
  color: var(--clr-text, #1e293b);
  background: var(--clr-border-light, #f1f5f9);
}

.data-table th.th-sortable:focus-visible {
  outline: 2px solid var(--clr-primary, #4f46e5);
  outline-offset: -2px;
}

.th-sort-mark {
  display: inline-block;
  width: 12px;                        /* 固定寬度，換箭頭時欄寬才不會抖 */
  margin-left: 4px;
  font-size: 10px;
  line-height: 1;
  color: #cbd5e1;                     /* 平常很淡 */
  transition: color .12s;
}

.data-table th.th-sortable:hover .th-sort-mark {
  color: #94a3b8;
}

/* ⚠️ 這裡要寫成 .th-sortable.is-sorted（兩個 class）而不是只有 .is-sorted。
 *
 * 上面 :hover 那條是 th.th-sortable:hover，優先度比 th.is-sorted 高。
 * 只寫 .is-sorted 的話，滑鼠移到「正在排序」的那一欄，
 * 主色高亮會被 hover 的一般深色蓋掉——
 * **想看清楚而把滑鼠移過去，反而看不出它正在排序。**
 *
 * 2026-08-26 實測到的：沒 hover 時 rgb(5,66,126)，hover 時 rgb(30,41,59)。
 * 功能完全正常，所以語法檢查與功能測試都抓不到，
 * 只有把 computed style 印出來比才看得見。
 */
.data-table th.th-sortable.is-sorted,
.data-table th.th-sortable.is-sorted:hover,
.data-table th.th-sortable.is-sorted:focus-visible {
  color: var(--clr-primary, #4f46e5);
}

.data-table th.th-sortable.is-sorted .th-sort-mark,
.data-table th.th-sortable.is-sorted:hover .th-sort-mark {
  color: var(--clr-primary, #4f46e5);
}

/* 筆數靠左、翻頁靠右。
 *
 * 一般網頁的慣例是「共幾筆」在左邊、翻頁按鈕在右邊
 * （Gmail、GitHub、後台樣板都是這樣）。理由是這兩件事不同性質：
 * 筆數是「現在看到什麼」，翻頁是「要去哪裡」，擠在一起會看不出哪個是按鈕。
 *
 * ⚠️ 專案裡本來就有兩種寫法：三頁是把四個元素平鋪、三頁已經分成
 *    list-pagination-left / -right 兩塊。但那兩個 class **完全沒有樣式**
 *    （2026-08-25 查證，css 裡一條都找不到），所以六頁看起來都一樣：
 *    全部擠在右邊。
 *
 * ⇒ 用 :first-child 一條規則同時修好兩種寫法，不必去動六個 JS 檔。
 *    兩種寫法的第一個子元素都是筆數。
 */
.list-pagination > :first-child {
  margin-right: auto;
}

/* 翻頁那一塊自己也要是 flex，不然裡面的按鈕之間沒有間距
   （父層的 gap 只作用在直接子元素上）。 */
.list-pagination-right {
  display: flex;
  align-items: center;
  gap: 8px;
}

.inactive-alert-icon {
  color: #d97706;
  font-weight: 700;
  margin-right: 6px;
}

.sidebar-warn-dot,
.sidebar-group-warn {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-left: 6px;
  border-radius: 50%;
  background: #dc2626;
  vertical-align: middle;
  font-size: 0;
  line-height: 0;
}

.rules-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 14px;
}

/* 頁籤與「整頁共用動作按鈕」擺同一列。
   給按鈕獨立一列會讓人以為那是上方標題區的一部分，跟頁籤同列才看得出
   「不管切到哪個頁籤，這兩顆都在」。窄畫面時 flex-wrap 讓按鈕自動掉到下一列。 */
.tabs-bar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-bottom: 14px;
}

/* 外層 .tabs-bar 已經負責與下方內容的間距，內層再留 14px 會變成 28px。 */
.tabs-bar > .rules-tabs {
  margin-bottom: 0;
}

.tabs-bar-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  flex-shrink: 0;
}

/* 2026-08-20：.rules-group-tabs／.rules-group-tab 已移除。

   那是一組圓角 999px 的膠囊頁籤，全站只有 RulesCenterView 一頁在用，
   放在畫面上跟旁邊的 .rules-tab（圓角 8px）格格不入。
   兩排頁籤現在都用 .rules-tab。留著不用的樣式，下次會有人沿用。 */


.rules-tab {
  border: 1px solid #dbe3ee;
  background: #fff;
  color: #334155;
  border-radius: 8px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 500;
}

/* 🔴 第二層頁籤（同一頁裡再切換內容）。Z3-88，使用者 2026-08-21 選「甲　底線」。
   使用者原話：「這兩個頁籤需要其他呈現，因為**不同層級的樣式我們沒討論過**」——
   他是對的：第一層（.rules-tab）與第二層長得一模一樣時，兩排堆在一起
   看不出誰管誰。第二層改成沒有框、只有一條底線，明顯比第一層輕。

   🔴 Z3-88a（使用者 2026-08-21：「樣式對齊頁籤，偏藍色？」）：選中態改用 --clr-accent。
      ⚠️ 我原本刻意用深色，理由是「藍色是第一層在用的，第二層再用一次等於兩層一樣重」。
         他看了實際畫面後決定要藍色——**顏色一致比層級對比重要**，
         全站「選中」就是藍色（.rules-tab.active、.nav-item.active 都是）。
         層級的差別由「有框 vs 只有底線」來表達，已經夠明顯了。
      ⇒ 不要再改回深色。
   ⚠️ 底線壓在容器的框線上（margin-bottom:-1px），少了它會有 1px 的斷差。 */
/* 🔴 **第三層頁籤的上下留白**（`Z3-88c`，使用者 2026-08-21：
   「這兩個頁籤(第三層)在上方多留點空間　和第二層區隔開　也和下面的選單
     留點距離　但距離不會比和上面的選單多」）。**這是全站第三層頁籤的標準。**

   上面 26px、下面 12px，**上面一定要比下面大**——
   間距小的那一邊看起來才「黏在一起」，頁籤才會像是**管著下面那塊內容**，
   而不是浮在兩塊中間、不知道屬於誰。

   ⚠️ 上面用 `margin-top:26px` 而不是靠上一個元素的 `margin-bottom`：
      第二層（`.rules-tabs`）的 `margin-bottom:14px` 會跟它**合併**（取大的），
      所以最後就是 26px。改小於 14px 的值會沒有效果。 */
.sub-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  border-bottom: 1px solid var(--clr-border);
  margin-top: 26px;
  margin-bottom: 12px;
}

/* 🔴 `Z3-88d`（使用者 2026-08-21：「**都改成藍色(可點擊的意象)　去掉未點擊頁籤的底線**」）：
   **兩顆都是藍色**，選中與否**只差在有沒有底線**。

   沿革（同一顆元件當天改過三次，看這裡就好，不必翻 git）：
   　b 版：兩顆都有底線、都加粗，只差顏色（灰／藍）
   　→ **d 版（現在）**：兩顆都藍色、都加粗，只差底線

   🔴 **為什麼沒選中的也要藍**：藍色在本站＝**可以點**。
      沒選中的那顆是「還沒被點、但點得下去」的東西，灰色會被讀成「不能點」。
      ⇒ **顏色負責講「可點」，底線負責講「現在在這一頁」**，兩件事分開表達。

   🔴 底線用 `currentColor`：字換色時線自動跟著換，
      不會有改了字忘了改線的情形。
   ⚠️ 沒選中的是 `transparent` **不是 `none`**——2px 的位置要留著，
      不然切換時兩顆會上下跳動。
   ⚠️ 底線壓在容器的框線上（margin-bottom:-1px），少了它會有 1px 的斷差。 */
.sub-tab {
  border: 0;
  background: none;
  padding: 0 0 9px;
  margin-bottom: -1px;
  font-size: 13px;
  font-weight: 600;
  color: var(--clr-accent);
  border-bottom: 2px solid transparent;
  cursor: pointer;
}

.sub-tab.active {
  border-bottom-color: currentColor;
}

.rules-tab.active {
  border-color: var(--clr-accent-border);
  background: var(--clr-accent-bg-strong);
  color: var(--clr-accent);
  font-weight: 600;
}

/* ════════════════════════════════════════════════
   MODAL
   ════════════════════════════════════════════════ */
.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, .45); backdrop-filter: blur(3px);
  z-index: 2000;
  display: flex; align-items: flex-start; justify-content: center;
  padding: 20px;
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0; pointer-events: none;
  transition: opacity .22s ease;
}
.modal-backdrop.open { opacity: 1; pointer-events: auto; }

body.modal-open {
  overflow: hidden;
  overscroll-behavior: none;
}

.modal {
  background: var(--clr-surface); border-radius: var(--r-lg);
  width: 100%; max-width: 520px;
  max-height: calc(100vh - 40px);
  margin: auto 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .2);
  transform: translateY(-12px) scale(.97);
  transition: transform .22s ease;
}
.modal-backdrop.open .modal { transform: translateY(0) scale(1); }

.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 22px 14px; border-bottom: 1px solid var(--clr-border-light);
}
.modal-title { font-size: 16px; font-weight: 700; color: var(--clr-text); }
.modal-close {
  background: none; border: none; color: var(--clr-text-muted);
  padding: 4px; border-radius: var(--r-sm);
  transition: color var(--tr), background var(--tr);
}
.modal-close:hover { background: var(--clr-border-light); color: var(--clr-text); }

.modal-body {
  padding: 20px 22px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.modal-footer {
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  padding: 14px 22px 18px; border-top: 1px solid var(--clr-border-light);
}

/* ════════════════════════════════════════════════
   INFO CALLOUT
   ════════════════════════════════════════════════ */
.info-callout {
  border: 1px solid var(--clr-accent-border);
  background: var(--clr-accent-bg);
  color: #1e3a8a;
  border-radius: var(--r-md);
  padding: 12px 14px;
  font-size: 12.5px;
  line-height: 1.6;
}

.info-callout-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 700;
  margin-bottom: 6px;
}

.info-callout-list {
  margin: 0;
  padding-left: 18px;
}

.info-callout-list li {
  margin-bottom: 4px;
}

.info-callout-muted {
  margin-top: 8px;
  color: var(--clr-accent);
  font-size: 12px;
}

/* ════════════════════════════════════════════════
   STAT CARDS  (首頁儀表板)
   ════════════════════════════════════════════════ */
.cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 18px; margin-bottom: 26px;
}
/* 2026-08-05 補：MonitoringStatusView 用了 .stat-cards（複數）當外層容器，
   但 CSS 只定義了單數的 .stat-card，那頁是靠 inline style 的 grid 撐住版面。
   補上容器樣式，之後別的頁面要放卡片列就不必再各自寫一次 inline grid。
   已存在的 inline style 會覆蓋這裡的值，所以不會改變現有頁面的外觀。 */
.stat-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}

.stat-card {
  background: var(--clr-surface); border-radius: var(--r-lg);
  padding: 22px 22px 18px;
  border: 1px solid var(--clr-border);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--tr), transform var(--tr);
}
.stat-card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
.stat-card-icon {
  width: 44px; height: 44px; border-radius: 11px;
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 14px;
}
.icon-blue   { background: var(--clr-accent-bg-strong); }
.icon-red    { background: var(--clr-danger-bg); }
.icon-amber  { background: var(--clr-warning-bg); }
.icon-green  { background: var(--clr-success-bg); }
.icon-purple { background: #ede9fe; }
.stat-card-label { font-size: 12.5px; color: var(--clr-text-sec); font-weight: 500; margin-bottom: 4px; }
.stat-card-value { font-size: 34px; font-weight: 700; color: var(--clr-text); line-height: 1; margin-bottom: 6px; }
.stat-card-sub   { font-size: 11.5px; color: var(--clr-text-muted); }
.stat-card.is-active {
  border-color: #0284c7;
  box-shadow: 0 0 0 2px rgba(2,132,199,.18), var(--shadow-sm);
  background: #f0f9ff;
}
.stat-card[data-filterable]:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }

/* ════════════════════════════════════════════════
   SECTION LABEL
   ════════════════════════════════════════════════ */
.section-label { font-size: 14px; font-weight: 600; color: var(--clr-text); margin-bottom: 14px; }

/* ════════════════════════════════════════════════
   ASSET RISK ITEM — ACCORDION GROUP TABLE
   ════════════════════════════════════════════════ */
.ari-group-header:hover { background: #f1f5f9 !important; }
.ari-expand-icon {
  user-select: none;
  color: #64748b;
  font-size: 10px;
  line-height: 1;
  transition: transform .2s ease;
}
.ari-expand-icon.expanded { transform: rotate(90deg) !important; }
.ari-group-detail td { background: var(--clr-row-hover); }
.ari-detail-table {
  font-size: 13px !important;
  border-radius: 0;
  border: none;
  box-shadow: none;
  table-layout: auto;
}
.ari-detail-table thead th {
  background: #e2e8f0;
  font-size: 12px;
  padding: 7px 10px;
  white-space: nowrap;
}
.ari-detail-table tbody td { padding: 7px 10px; font-size: 13px; }

/* ── 欄寬跟著內容、不跟著視窗（`Z3-105` 第二版，2026-08-21）─────────
   使用者：「將欄位大小設定為隨著內容變動但不要因為視窗變動而變動」。

   🔴 **`width:1px` 不是真的 1px**：在 `table-layout:auto` 底下，
      瀏覽器把它當「我要最小」，再撐到**內容不換行的寬度**為止。
      配上 `white-space:nowrap` 就等於 `max-content`，**而且與視窗寬度無關**。

   🔴 **最後一欄故意不加這個類別**：剩餘空間全給它吸收，
      表格才會填滿外框、右邊不留白，也不會沒事就橫向捲動。
      ⚠️ 想改欄位順序時記得：**吸空間的永遠是最後一欄**。

   ⚠️ 真的塞不下時由 `.table-wrapper` 的 `overflow-x:auto` 橫向捲動——
      這是刻意的，總比把圖示擠成兩行好。 */
.data-table th.col-fit, .data-table td.col-fit {
  width: 1px; white-space: nowrap;
}

/* 🔴 **管道欄：最小寬＝內容，有空間就六欄均分**（使用者 2026-08-21：
   「管道欄位寫最小欄寬(依照內容大小)　在頁面空間充足的情況還是可以均分一下」）。

   六個放圖示的欄（四個等級＋主辦＋備援）給**同一個百分比**：
   ・空間夠 → 六欄一樣寬，多的空間平均分掉
   ・空間不夠 → `white-space:nowrap` 讓內容寬變成**下限**，
     欄位不會再被壓下去，圖示也就不會被擠在一起；
     真的塞不下時由 `.table-wrapper` 橫向捲動（使用者選的「甲：捲軸留著」）

   🔴 **百分比只是「怎麼分多的空間」，不是實際寬度**。
      `table-layout:auto` 底下，內容的最小寬永遠贏過百分比——
      這正是我們要的：均分是好意，擠壞圖示是底線。
   ⚠️ 六欄的值**必須一模一樣**，不一樣就不是均分了。
   ⚠️ 這一版欄寬**會**隨視窗變（第二版曾經刻意不變）。差別在於**現在有下限**，
      當初他抱怨的「縮放時圖示擠在一起」是因為那時候欄位可以無限縮小。 */
.data-table th.col-flex, .data-table td.col-flex {
  width: 14%;
  white-space: nowrap;
}

/* ── 通報總覽：嚴重度徽章 ＋ 滑鼠展開明細（`Z3-122`，2026-08-21）─────────
   來源：陳美鐘老師在群組提的檢討（使用者 2026-08-21 轉來並拍板方案 B）。

   **原本的問題**：四個等級欄各自重複放 5 個全彩品牌圖示，
   22 筆資產最多會有 440 個彩色圖示同時出現。品牌色是「這是哪個平台」，
   不是「這一格要不要注意」，**該被強調的嚴重度反而只剩欄位標題在講**。

   **改法**：每格只留一個 `X/5` 徽章，明細收到滑鼠移上去才展開。

   🔴 **上不上色看「有沒有缺口」，不是看「屬於哪個等級欄」**（老師特別交代）：
   　 ・開齊（5/5）→ **不上底色**，中性灰
   　 ・沒開齊 → 才套等級色當底色跳出來提醒
   　 每格都上色等於繞回滿版顏色的老問題——色彩要留給「例外」，
   　 不是拿來標「一切正常」。

   ⚠️ 顏色**一律取自 `UI.LEVELS`**（全站等級藥丸同一份），
      不要在這裡寫死 hex，也不要另外發明一套。
   ⚠️ 分母固定 5（使用者 2026-08-21 選甲案）＝ `UI.CHANNEL_ORDER` 的長度。
      資料庫其實有 7 個管道，多的「簡訊／語音」**沒有發送程式**，
      算進分母會讓每一格都假性缺 2 個。 */
.ch-badge {
  display: inline-block;
  min-width: 40px;
  padding: 2px 9px;
  border-radius: var(--r-full);
  font-size: 12px;
  font-weight: 600;
  text-align: center;
  white-space: nowrap;
  cursor: default;
}
/* 開齊的：沒有底色、字也不搶眼。**這一格「正常」，不需要被看見。** */
.ch-badge--full {
  background: none;
  color: var(--clr-text-sec);
  font-weight: 500;
}
.ch-badge:focus-visible { outline: 2px solid var(--clr-accent); outline-offset: 2px; }

/* 主辦／備援：紅點＋人名（使用者 2026-08-21：「主辦跟備援可以採用紅色圓點標示
   或紅色圓點＋人名」）。管道改成滑鼠移上去才看。

   ⚠️ `.owner-cell` 本來只寫在 JS 裡、沒有對應的 CSS——
      `check-frontend.sh` 第 3 項當場抓到「用了不存在的 class」。
      它需要的是「圓點與名字同一條基線、不要折行」，這幾行就是那件事。 */
.owner-cell {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  cursor: default;
}
.owner-cell:focus-visible { outline: 2px solid var(--clr-accent); outline-offset: 2px; }

.owner-dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--clr-danger);
  margin-right: 6px;
  vertical-align: 1px;
  flex: 0 0 auto;
}

/* 展開的明細。
   🔴 **掛在 `<body>` 上、用 `position:fixed`**：表格外框是 `overflow-x:auto`，
      浮層放在儲存格裡會被裁掉一半。這是刻意的，不要改成 absolute。 */
.nov-pop {
  position: fixed;
  z-index: 1500;
  background: var(--clr-surface);
  border: 1px solid var(--clr-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
  padding: 10px 12px;
  font-size: 12.5px;
  max-width: 340px;
  pointer-events: none;
}
.nov-pop-title {
  color: var(--clr-text-muted);
  font-size: 11.5px;
  margin-bottom: 6px;
  white-space: nowrap;
}
.nov-pop-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 3px 0;
  white-space: nowrap;
}
.nov-pop-row .channel-icon { margin-right: 0; }
/* 主辦／備援那幾列的圖示槽（使用者 2026-08-25：浮層裡的紅點換成管道 logo）。
   ⚠️ 要給**最小寬度**：一個人可能只有一個管道、另一個人有三個，
      不釘住的話同一個浮層裡的人名會左右參差。
   ⚠️ 寬度抓「兩顆 18px ＋ 中間 4px」；再多就往右長，人名跟著往後，
      那是刻意的——寧可寬一點，也不要把圖示疊在一起。 */
.nov-pop-icons {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-width: 40px;
  flex: 0 0 auto;
}
.nov-pop-name { min-width: 62px; }
.nov-pop-dest { color: var(--clr-text-sec); }
/* 沒開通的：圖示轉灰淡出，**但仍然列出來**——
   老師的重點就是「一眼看得出少了哪一個」，藏起來就看不出來了。 */
.nov-pop-row--off .channel-icon { filter: grayscale(1); opacity: .38; }
.nov-pop-row--off .nov-pop-name,
.nov-pop-row--off .nov-pop-dest { color: var(--clr-text-muted); }

/* ── 管道小圖示（Z3-108，2026-08-21）─────────────────────────────────
   使用者：「藥丸改為小icon」，並選乙案「只有平台圖示，沒有文字（滑鼠移上去才顯示名稱）」。

   🔴 **前一版的 .channel-pill（淡底藥丸＋文字，Z3-97）已經整組移除**——
      沒有任何 View 還在用它，留著只會讓下一個人以為那是現行做法。
      要找回來看 git（Z3-97 的 commit）。

   顏色由 UI.channelIcon() 用 --brand-* 直接寫在 style 上（那是品牌色、不是主題色），
   這裡只管排列：圖示之間留一點距離，並與同一格的文字對齊。
   ⚠️ vertical-align 一定要給——SVG 預設是 baseline 對齊，
      不設定的話圖示會比同一列的文字低半個字高。 */
.channel-icon {
  /* 🔴 **一個管道 ＝ 一顆平台的 app 圖示**（`Z3-108`，2026-08-21 第八版）。

     這顆圖示當天改了八次，**只看這裡就好，不必回頭翻 git**：
     ① 描邊小圖示 → ② 單色商標放大 → ③ 彩色 logo（被退）→ ④ 降飽和
     → ⑤ 改用變淡 → ⑥ 實心品牌色方塊＋白線 logo → ⑦ 縮小拉開變淺
     → **⑧（現在）換成使用者指定的「真實 app 圖示」**

     🔴 **這裡不再畫底色方塊**：第八版的圖示**自己帶底色**
        （Telegram 藍圓、Discord 藍紫圓、LINE 綠角方、Slack 深紫角方），
        再畫一層會變成**兩層底**。⚠️ 想加底色前先看圖示本身有沒有。

     ⚠️ 寬高由 UI.channelIcon() 寫在 style 上（跟著 size 參數走，現在 20px），這裡不要寫死。
     ⚠️ 間距在這裡（margin-right 8px）、邊長在 ui.js，**兩個要一起看**。 */
  display: inline-flex; align-items: center; justify-content: center;
  vertical-align: middle;
  flex: 0 0 auto;
  margin-right: 8px;
}
.channel-icon:last-child { margin-right: 0; }
.channel-icon svg { stroke-width: 1.8; }
