/*
 * UscChat.Web site.css
 * Single source of truth for design tokens + components.
 * 依 ~/.claude/skills/usc-ui-guidelines (v3.3.0) 實作 — 不自創樣式，值取自該 skill §2/§3。
 *
 * 範圍決策（詳見 .superpowers/sdd/task-15-report.md）：
 * - C6（詳見 .superpowers/sdd/task-c6-report.md）新增 light/dark 雙主題：無 cookie 跟隨
 *   系統（prefers-color-scheme media query）、UscChatTheme cookie 存在時明確釘選（見
 *   §1.1 dark 覆寫塊）。色彩一律走 token，元件層不得寫死 [data-theme] 顏色特例
 *   （SweetAlert2 覆寫除外，見 §20 — 它自己注入 <style>、不吃我們的 CSS variable）。
 * - 不載入 Google Fonts / Font Awesome CDN（CSP 為 script-src 'self' / font-src 'self'，
 *   無 CDN origin 可用）；改用系統字型堆疊。C6 主題切換鈕是本站首個 icon-only 按鈕
 *   需求，比照 Login.cshtml 用內嵌 SVG（非 Font Awesome）+ aria-label，不違反此決策
 * - 不建立 sidebar navigation（本系統僅一個後台功能「機器人管理」，無多分頁導覽需求）
 */

/* ============================================================
   §1 Design Tokens
   ============================================================ */
:root {
  /* --- Page width（navbar/main/footer 三區共線）---
     全站單一寬（2026-09-02 二次定案，收錄 usc-ui-guidelines §2.7）：一律 1200
     （對齊 UscClub 公開頁容器寬），前後台零例外——曾試過後台 1280 兩層制，
     使用者對照截圖仍嫌 40px 邊界跳動，收斂為單一值。資料表塞不下時在頁框內
     用 .table-wrap 橫向捲動，不開第二種頁寬。 */
  --page-width: 1200px;

  /* --- Brand --- */
  --primary: #0891B2;
  --primary-hover: #0E7490;
  --primary-glow: rgba(8, 145, 178, 0.2);
  --primary-strong: #0E7490;
  --link: #0E7490;
  --link-hover: #155E75;
  --primary-gradient-to: #3B82F6;
  /* Review fix（.superpowers/sdd/task-c6-report.md §「Fix：solid-fill 白字對比」）：
     --primary 等 token 是「文字/邊框用」語意——dark 模式為了讓文字在深底上維持對比而調
     亮（#0891B2 → #06B6D4）。但 .btn-primary／.chat-bubble-user 是「白字疊實心底色」，
     底色被調亮後白字對比反而變差（dark #06B6D4 對白字僅 2.43:1，比 light #0891B2 的
     3.68:1 還差）。改吃獨立 fill token，dark 覆寫值刻意「加深」而非「調亮」，
     光/暗兩態獨立達 AA（見下方 dark 覆寫塊 a11y 註解）。 */
  --primary-fill: #0891B2;
  --primary-fill-hover: #0E7490;
  --primary-fill-to: #3B82F6;

  /* --- Layout --- */
  --content-bg: #F1F5F9;

  /* --- Cards & Surfaces --- */
  --card-bg: #FFFFFF;
  --surface-solid: #FFFFFF; /* 彈窗/浮層專用不透明表面（dark 的 --card-bg 是 3% 玻璃、浮層會透底） */
  --card-border: rgba(15, 23, 42, 0.08);
  --card-hover: #F8FAFC;
  --bubble-ai-bg: #F1F7F9; /* AI 泡泡面：白卡上需與卡片區分的淡青面（造型樣張 --ai-surface） */

  /* --- Inputs (推導自 §4.9.1 row 30 login form-input 邊框值，全站沿用同一組) --- */
  --input-bg: #FFFFFF;
  --input-border: rgba(15, 23, 42, 0.12);

  /* --- Text --- */
  --text-primary: #0F172A;
  --text-secondary: #475569;
  --text-muted: #475569;
  /* UI 規範 audit fix 1（.superpowers/sdd/task-root-theme-audit-report.md 發現①）：
     .badge-secondary（§9）／.chat-citation-chip（§17.2）原本各自寫死同一個
     rgba(100,116,139,0.15) 中性淡底，收成一個 token 讓兩處共用同一個 single source。
     跟 --success/--warning/--error/--info 的 15% tint 一樣不需要 dark 覆寫——alpha-blend
     底色疊在 --card-bg／--content-bg 上兩色階都夠低調，真正需要換色的只有疊在它上面的
     文字（此處是 --text-muted，該 token 已自帶 dark 覆寫值），故本 token 不進 §1.1 兩個
     dark 覆寫塊。 */
  --neutral-tint: rgba(100, 116, 139, 0.15);

  /* --- Status --- */
  --success: #16A34A;
  --warning: #D97706;
  --error: #DC2626;
  --info: #2563EB;
  /* C6：badge/alert 的「淡底＋深字」文字色收編成 token（原本寫死 hex）——
     淡底 tint 背景本身是半透明疊色、跨主題不用換；深字在 dark 覆寫塊裡換成對應的
     300-tone 淺字，維持 §5.4 authoritative a11y 對比表。 */
  --success-strong: #166534;  /* a11y: green-800 8.4:1 on tint */
  --warning-strong: #92400E;  /* a11y: amber-800 8.9:1 on tint */
  --error-strong: #991B1B;    /* a11y: red-800 on tint */
  --info-strong: #1E40AF;     /* a11y: blue-800 on tint */
  /* Review fix：同上 --primary-fill 理由——.btn-success／.btn-danger 是白字疊實心底色，
     改吃獨立 fill token（非 badge/alert 用的 *-strong，那組是深字疊淡底，語意不同）。 */
  --success-fill: #16A34A;
  --error-fill: #DC2626;

  /* --- Spacing (12 levels) --- */
  --spacing-0: 0;
  --spacing-1: 0.25rem;
  --spacing-2: 0.375rem;
  --spacing-3: 0.5rem;
  --spacing-4: 0.625rem;
  --spacing-5: 0.75rem;
  --spacing-6: 0.875rem;
  --spacing-7: 1rem;
  --spacing-8: 1.25rem;
  --spacing-9: 1.5rem;
  --spacing-10: 2rem;
  --spacing-11: 3rem;

  /* --- Border Radius --- */
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 10px;
  --radius-xl: 12px;
  --radius-pill: 9999px;

  /* --- Shadow --- */
  --shadow-none: none;
  --shadow-focus: 0 0 0 3px var(--primary-glow);
  --shadow-focus-error: 0 0 0 3px rgba(239, 68, 68, 0.2);
  --shadow-button-hover: 0 4px 15px var(--primary-glow);
  --shadow-card: 0 1px 3px rgba(15, 23, 42, 0.06);
  --shadow-elevated: 0 8px 30px rgba(15, 23, 42, 0.15);
  /* C6：SweetAlert2 backdrop 專用 token（§20）——SweetAlert2 預設 rgba(0,0,0,.4) 在 light
     可用、dark 覆寫改深；只在 dark 覆寫塊裡實際被 §20 的 [data-theme="dark"] 選擇器引用，
     light 值本身不用（light 沿用 SweetAlert2 內建 backdrop，不覆寫）。 */
  --backdrop: rgba(15, 23, 42, 0.4);

  /* --- Typography --- */
  --font-size-xs: 0.6875rem;
  --font-size-sm: 0.75rem;
  --font-size-sm2: 0.8125rem;
  --font-size-base: 0.875rem;
  --font-size-base2: 0.9375rem;
  --font-size-md: 1rem;
  --font-size-lg: 1.125rem;
  --font-size-xl: 1.25rem;
  --font-size-2xl: 1.5rem;
  --font-size-3xl: 2rem;
  --font-size-4xl: 3rem;

  --font-weight-regular: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;

  --line-height-tight: 1.25;
  --line-height-normal: 1.5;
  --line-height-loose: 1.75;

  /* --- Transition --- */
  --transition-fast: 0.15s ease;
  --transition-base: 0.2s ease;
  --transition-slow: 0.3s ease;
}

/* ============================================================
   §1.1 Dark Mode Tokens（C6 — 後台＋/chat 深色模式）

   三態語意（見 .superpowers/sdd/task-c6-report.md 完整 hand-trace）：
   - 無 UscChatTheme cookie ＝跟隨系統 → 只有 @media (prefers-color-scheme: dark) 命中，
     用 :root:not([data-theme="light"]) 排除「明確釘選 light」的情況（否則系統深色 +
     使用者釘選淺色會被 media query 蓋回深色，三態就失靈）。
   - cookie 釘選 light → 兩塊 dark 覆寫都不命中（:not([data-theme="light"]) 被排除、
     [data-theme="dark"] attribute 不符），維持 :root 預設 light 值，不需另立 light 覆寫塊。
   - cookie 釘選 dark → :root[data-theme="dark"] 直接命中，不論系統偏好一律套深色。

   雙寫（media query 塊 + attribute 塊）內容刻意保持一致——兩塊都要換上同一份深色值，
   差別只在「觸發條件」不同，見上。色階來源：usc-ui-guidelines §2.1/§5.4 authoritative
   dark 值（近黑 slate 底 #020617、卡片/輸入用低 alpha 白疊層、cyan #06B6D4 家族 accent、
   badge/alert 深字換成對應 300-tone 淺字維持 WCAG AA）。
   ============================================================ */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* --- Brand --- */
    --primary: #06B6D4;
    --primary-hover: #0891B2;
    --primary-glow: rgba(6, 182, 212, 0.3);
    --link: #06B6D4;
    --link-hover: #0891B2;
    /* Face-lift (task-face-lift)：--primary-strong 先前只有 light 值、從未被任何規則引用，
       未進 §1.1 兩塊 dark 覆寫——現在 chat.js showTicketSuccess() 案號要用它（mock 指定
       token），第一次真的在 dark 可見的位置出現，補齊 dark 值。跟 --link dark 值同一顏色
       （guideline 本身註記兩者「內頁連結改用 --link」語意相近，light 值本來就已相同
       #0E7490），沿用其已驗證的 8.31:1 對比（§5.4）。 */
    --primary-strong: #06B6D4;      /* a11y: mirrors --link dark, 8.31:1 on dark surfaces */
    /* Review fix：白字疊實心底色的 fill token 反向「加深」（非跟 --primary 一樣調亮）——
       cyan-700／cyan-800，白字對比 5.36:1／7.27:1（算法：WCAG relative luminance，
       見 task-c6-report.md fix 章節完整表）。 */
    --primary-fill: #0E7490;        /* a11y: cyan-700, white text 5.36:1 */
    --primary-fill-hover: #155E75;  /* a11y: cyan-800, white text 7.27:1 */
    --primary-fill-to: #1D4ED8;     /* a11y: blue-700, white text 6.70:1（gradient 端點） */

    /* --- Layout --- */
    --content-bg: #020617;

    /* --- Cards & Surfaces --- */
    --card-bg: rgba(255, 255, 255, 0.03);
    --surface-solid: #16233A;
    --card-border: rgba(255, 255, 255, 0.08);
    --card-hover: rgba(255, 255, 255, 0.05);
    --bubble-ai-bg: rgba(255, 255, 255, 0.06);

    /* --- Inputs --- */
    --input-bg: rgba(255, 255, 255, 0.05);
    --input-border: rgba(255, 255, 255, 0.12);

    /* --- Text --- */
    --text-primary: #F1F5F9;
    --text-secondary: #94A3B8;
    --text-muted: #94A3B8;

    /* --- Status --- */
    --success: #22C55E;
    --success-strong: #86EFAC;  /* a11y: green-300 8.1:1 */
    --warning: #F59E0B;
    --warning-strong: #FCD34D;  /* a11y: amber-300 9.2:1 */
    --error: #EF4444;
    --error-strong: #FCA5A5;    /* a11y: red-300 */
    --info: #3B82F6;
    --info-strong: #93C5FD;     /* a11y: blue-300 */
    /* Review fix：同上 --primary-fill 理由，.btn-success／.btn-danger 白字疊實心底色。 */
    --success-fill: #15803D;  /* a11y: green-700, white text 5.02:1 */
    --error-fill: #B91C1C;    /* a11y: red-700, white text 6.47:1 */

    /* --- Shadow（近黑底上淺色陰影幾乎不可見，改用更不透明的純黑撐出層次） --- */
    --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.3);
    --shadow-elevated: 0 8px 30px rgba(0, 0, 0, 0.5);

    /* --- SweetAlert2 backdrop（§20） --- */
    --backdrop: rgba(2, 6, 23, 0.72);
  }
}
:root[data-theme="dark"] {
  /* --- Brand --- */
  --primary: #06B6D4;
  --primary-hover: #0891B2;
  --primary-glow: rgba(6, 182, 212, 0.3);
  --link: #06B6D4;
  --link-hover: #0891B2;
  /* Face-lift (task-face-lift)：同上 media-query 覆寫塊，byte-identical pair——
     --primary-strong 補 dark 值，理由見該塊註解。 */
  --primary-strong: #06B6D4;      /* a11y: mirrors --link dark, 8.31:1 on dark surfaces */
  /* Review fix：白字疊實心底色的 fill token 反向「加深」（非跟 --primary 一樣調亮）——
     cyan-700／cyan-800，白字對比 5.36:1／7.27:1（算法：WCAG relative luminance，
     見 task-c6-report.md fix 章節完整表）。 */
  --primary-fill: #0E7490;        /* a11y: cyan-700, white text 5.36:1 */
  --primary-fill-hover: #155E75;  /* a11y: cyan-800, white text 7.27:1 */
  --primary-fill-to: #1D4ED8;     /* a11y: blue-700, white text 6.70:1（gradient 端點） */

  /* --- Layout --- */
  --content-bg: #020617;

  /* --- Cards & Surfaces --- */
  --card-bg: rgba(255, 255, 255, 0.03);
  /* Face-lift (task-face-lift) 修復既有 byte-identical pair 缺口：--surface-solid 只在
     上面 @media (prefers-color-scheme: dark) 覆寫塊有值，這個「明確 cookie 釘選 dark」
     attribute 塊漏補——後果是使用者裝置系統偏好仍是 light、但手動切成 dark 主題時，
     §20 SweetAlert2 .swal2-popup dark 覆寫吃到這裡的 --surface-solid 會 fallback 回
     :root 的 light 值 #FFFFFF（彈窗背景仍是白的，文字色卻已經是 dark 版
     --text-primary，白底白字/低對比）。Task B3 轉單成功彈窗走查截圖時發現，補齊維持
     §1.1 開頭註解要求的雙寫一致。 */
  --surface-solid: #16233A;
  --card-border: rgba(255, 255, 255, 0.08);
  --card-hover: rgba(255, 255, 255, 0.05);
  --bubble-ai-bg: rgba(255, 255, 255, 0.06);

  /* --- Inputs --- */
  --input-bg: rgba(255, 255, 255, 0.05);
  --input-border: rgba(255, 255, 255, 0.12);

  /* --- Text --- */
  --text-primary: #F1F5F9;
  --text-secondary: #94A3B8;
  --text-muted: #94A3B8;

  /* --- Status --- */
  --success: #22C55E;
  --success-strong: #86EFAC;
  --warning: #F59E0B;
  --warning-strong: #FCD34D;
  --error: #EF4444;
  --error-strong: #FCA5A5;
  --info: #3B82F6;
  --info-strong: #93C5FD;
  /* Review fix：同上 --primary-fill 理由，.btn-success／.btn-danger 白字疊實心底色。 */
  --success-fill: #15803D;  /* a11y: green-700, white text 5.02:1 */
  --error-fill: #B91C1C;    /* a11y: red-700, white text 6.47:1 */

  /* --- Shadow --- */
  --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.3);
  --shadow-elevated: 0 8px 30px rgba(0, 0, 0, 0.5);

  /* --- SweetAlert2 backdrop（§20） --- */
  --backdrop: rgba(2, 6, 23, 0.72);
}

/* ============================================================
   §2 Base / Reset
   ============================================================ */
*, *::before, *::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--content-bg);
  color: var(--text-primary);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang TC",
               "Microsoft JhengHei", "Noto Sans TC", sans-serif;
  font-size: var(--font-size-base);
  line-height: var(--line-height-normal);
}

h1, h2, h3, h4, h5, h6 {
  color: var(--text-primary);
  font-weight: var(--font-weight-semibold);
}

p {
  margin: 0 0 var(--spacing-7) 0;
}

a {
  color: var(--link);
  text-decoration: none;
}
a:hover {
  color: var(--link-hover);
  text-decoration: underline;
}

/* Keyboard focus 必須可見（§5.3）：不移除 outline 又不補替代樣式 */
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
  outline: none;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-focus);
}

/* Mobile readability：input/button 在 ≤768px 用 16px 避免 iOS 自動縮放 */
@media (max-width: 768px) {
  .form-input, .form-select, .form-textarea, .btn {
    font-size: var(--font-size-md);
  }
}

/* 尊重 prefers-reduced-motion（§5.6） */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================
   §3 Skip Link（§3.9 / §5.7 — layout 必備）
   ============================================================ */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--primary-fill);
  color: #fff;
  padding: var(--spacing-3) var(--spacing-5);
  z-index: 2000;
  border-radius: 0 0 var(--radius-md) 0;
  font-weight: var(--font-weight-medium);
}
.skip-link:focus {
  left: 0;
}

/* ============================================================
   §4 Layout shell（無 sidebar；單一後台功能，簡潔頂列）
   ============================================================ */
.site-header {
  background: var(--card-bg);
  border-bottom: 1px solid var(--card-border);
}
.navbar {
  max-width: var(--page-width);
  margin: 0 auto;
  padding: var(--spacing-5) var(--spacing-9);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-7);
}
.navbar-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-3);
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  color: var(--text-primary);
}
.navbar-brand:hover {
  color: var(--text-primary);
  text-decoration: none;
}
/* Face-lift (task-face-lift)：品牌標記——header／聊天室身分卡／選單卡片／訊息串 avatar
   共用同一組「漸層圓角方塊＋首字」語彙（mock 造型樣張的視覺核心），全部吃既有
   --primary-fill/--primary-fill-to（白字疊實心底色 token，dark 已有覆寫，見 §1），
   不需要新增顏色 token。這裡是 header 品牌標記，34px 對應 mock .brand-mark。 */
.brand-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: var(--radius-lg);
  background: linear-gradient(135deg, var(--primary-fill), var(--primary-fill-to));
  color: #fff;
  font-size: var(--font-size-base2);
  font-weight: var(--font-weight-bold);
  flex-shrink: 0;
}
/* C6：header 右側容器（主題切換鈕＋登出鈕，/chat 版只有前者）——單純 flex 排版，
   無顏色宣告，不屬於 Global Constraints 講的「元件層顏色特例」。 */
.navbar-actions {
  display: flex;
  align-items: center;
  gap: var(--spacing-5);
}
/* Face-lift (task-face-lift)：後台導覽分頁列（機器人管理／報修案件／用量統計，僅登入後
   顯示，見 _Layout.cshtml）——pill 語彙延續 mock 的 chip/composer 圓角風格，
   active 態直接吃 .switch-btn.active 同一顆 --primary-fill 白字組合，不另立顏色。 */
.admin-tabs {
  /* 跟 navbar/main/footer 同一條頁寬變數——寫死 960 曾讓這排分頁在 1280 後台頁上
     既沒對齊 logo 也不置中（使用者截圖回報）。 */
  max-width: var(--page-width);
  margin: 0 auto;
  padding: 0 var(--spacing-9) var(--spacing-5);
  display: flex;
  gap: var(--spacing-3);
  flex-wrap: wrap;
}
.admin-tab {
  padding: var(--spacing-3) var(--spacing-6);
  border-radius: var(--radius-pill);
  font-size: var(--font-size-sm2);
  font-weight: var(--font-weight-medium);
  color: var(--text-secondary);
  transition: background-color var(--transition-base), color var(--transition-base);
}
.admin-tab:hover {
  background: var(--card-hover);
  color: var(--text-primary);
  text-decoration: none;
}
.admin-tab.active {
  background: var(--primary-fill);
  color: #fff;
}
.site-main {
  max-width: var(--page-width);
  margin: 0 auto;
  padding: var(--spacing-10) var(--spacing-9);
}
.site-footer {
  max-width: var(--page-width);
  margin: 0 auto;
  padding: var(--spacing-7) var(--spacing-9) var(--spacing-9);
}

/* ============================================================
   §5 Buttons（§3.1）
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-3);
  min-height: 40px;
  padding: 0.625rem 1rem;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  font-family: inherit;
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-medium);
  line-height: var(--line-height-normal);
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--transition-base), border-color var(--transition-base),
              box-shadow var(--transition-base), filter var(--transition-base);
}
.btn:hover {
  text-decoration: none;
}
.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.btn-sm {
  min-height: 32px;
  padding: 0.375rem 0.75rem;
  font-size: var(--font-size-sm2);
}
.btn-primary {
  /* Review fix：白字疊實心底色改吃 --primary-fill/-to（非 --primary/-gradient-to），
     理由見 §1 token 定義旁註解 + task-c6-report.md fix 章節。 */
  background: linear-gradient(135deg, var(--primary-fill), var(--primary-fill-to));
  color: #fff;
}
.btn-primary:hover:not(:disabled) {
  background: linear-gradient(135deg, var(--primary-fill-hover), var(--primary-fill-to));
  box-shadow: var(--shadow-button-hover);
}

.btn-secondary {
  background: var(--input-bg);
  border-color: var(--input-border);
  color: var(--text-primary);
}
.btn-secondary:hover:not(:disabled) {
  background: var(--card-hover);
}

.btn-danger {
  /* Review fix：白字疊實心底色改吃 --error-fill（非 --error），理由同 .btn-primary。 */
  background: var(--error-fill);
  color: #fff;
}
.btn-danger:hover:not(:disabled) {
  filter: brightness(0.9);
}

.btn-success {
  /* Review fix：白字疊實心底色改吃 --success-fill（非 --success），理由同 .btn-primary。 */
  background: var(--success-fill);
  color: #fff;
}
.btn-success:hover:not(:disabled) {
  filter: brightness(0.9);
}

/* UI 規範 audit fix 5（usc-ui-guidelines §10.1「emoji 當 icon」anti-pattern + §7 icon
   system）：按鈕內嵌 SVG icon（同 §19 .switch-btn svg 慣例、非 Font Awesome——CSP 無 CDN
   origin，見檔頭決策）的共用尺寸 class，供 .btn 內任何 <svg class="btn-icon"> 重用
   （目前用在 Room.cshtml #chat-ticket 的 wrench icon），不必逐個按鈕各自宣告一次。 */
.btn-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

/* ============================================================
   §6 Cards（§3.2）
   ============================================================ */
.card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-card);
}
.card-header {
  padding: var(--spacing-9);
  border-bottom: 1px solid var(--card-border);
}
.card-title {
  margin: 0;
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-semibold);
}
.card-body {
  padding: var(--spacing-9);
}

/* ============================================================
   §7 Forms（§3.3）
   ============================================================ */
.form-group {
  margin-bottom: var(--spacing-9);
}
.form-label {
  display: block;
  margin-bottom: var(--spacing-3);
  font-weight: var(--font-weight-medium);
  color: var(--text-primary);
}
.required {
  color: var(--error);
  margin-left: 0.125rem;
}
.form-input,
.form-select,
.form-textarea {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 0.625rem 0.75rem;
  font-family: inherit;
  font-size: var(--font-size-base);
  color: var(--text-primary);
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: var(--radius-md);
  transition: border-color var(--transition-base), box-shadow var(--transition-base);
}
.form-input:focus,
.form-select:focus,
.form-textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: var(--shadow-focus);
}
.form-input[readonly] {
  background: var(--card-hover);
  cursor: not-allowed;
}
.form-textarea {
  min-height: 96px;
  resize: vertical;
}
.form-error {
  display: block;
  margin-top: var(--spacing-2);
  color: var(--error);
  font-size: var(--font-size-sm);
}
.form-error:empty {
  display: none;
}
.form-hint {
  margin: var(--spacing-2) 0 0 0;
  color: var(--text-muted);
  font-size: var(--font-size-sm);
}
/* C7：checkbox＋label 同一列（Admin/Bots/Edit 的 ClearApiKey／RequiresLogin／Enabled
   三個布林欄位重複用同一組 inline style，收攏成一個可重用的表單列元件）。 */
.form-check-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-3);
}
.form-check-row input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  cursor: pointer;
}
.form-check-row .form-label {
  margin: 0;
}
/* C7：窄版數字欄位（Admin/Bots/Edit 的排序欄），限制寬度避免撐滿整列。 */
.form-input-narrow {
  max-width: 160px;
}
/* C7：表單送出列（儲存／取消按鈕並排），用在後台表單。（UI 規範 audit fix 3：原本註解
   提到跟 §17.2 .chat-login-actions 同構，該規則已隨登入面板改走 SweetAlert2 modal 移除，
   註解一併更新。） */
.form-actions {
  display: flex;
  gap: var(--spacing-3);
  margin-top: var(--spacing-9);
}
/* Server-side ModelState 錯誤（Input Tag Helper 自動加） */
.form-input.input-validation-error,
.form-select.input-validation-error,
.form-textarea.input-validation-error {
  border-color: var(--error);
}
.form-input.input-validation-error:focus,
.form-select.input-validation-error:focus,
.form-textarea.input-validation-error:focus {
  box-shadow: var(--shadow-focus-error);
}

/* ============================================================
   §8 Tables（§3.4）
   ============================================================ */
.table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--font-size-base);
}
.table th,
.table td {
  padding: var(--spacing-5);
  text-align: left;
  border-bottom: 1px solid var(--card-border);
  vertical-align: middle;
}
.table th {
  color: var(--text-secondary);
  font-weight: var(--font-weight-semibold);
  font-size: var(--font-size-sm2);
}
.table tbody tr {
  transition: background-color var(--transition-fast);
}
.table tbody tr:hover {
  background: var(--card-hover);
}
.table .text-right {
  text-align: right;
}
.table-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--spacing-3);
  flex-wrap: wrap;
}
.table-actions form {
  margin: 0;
}

/* ============================================================
   §9 Status Badge（§3.10 — 值皆為 §5.4 權威 a11y contrast 表）
   ============================================================ */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-2);
  padding: 0.125rem 0.5rem;
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm2);
  font-weight: var(--font-weight-medium);
  line-height: 1.4;
}
.badge-success {
  background: rgba(34, 197, 94, 0.15);
  color: var(--success-strong); /* a11y: light green-800 8.4:1／dark green-300 8.1:1（§5.4 權威值、見 :root token） */
}
.badge-warning {
  background: rgba(245, 158, 11, 0.15);
  color: var(--warning-strong); /* a11y: light amber-800 8.9:1／dark amber-300 9.2:1 */
}
.badge-danger {
  background: rgba(239, 68, 68, 0.15);
  color: var(--error-strong); /* a11y: light red-800／dark red-300 */
}
.badge-info {
  background: rgba(59, 130, 246, 0.15);
  color: var(--info-strong); /* a11y: light blue-800／dark blue-300 */
}
.badge-secondary {
  background: var(--neutral-tint);
  color: var(--text-muted);
}

/* ============================================================
   §10 Alerts（§3.5 — ARIA role/aria-live 由 markup 加，文字色見下方註解）
   ============================================================ */
.alert {
  padding: var(--spacing-7) var(--spacing-8);
  border-radius: var(--radius-md);
  border-left: 4px solid transparent;
  font-size: var(--font-size-base);
  line-height: var(--line-height-normal);
  margin-bottom: var(--spacing-9);
}
/*
 * 文字色刻意沿用 badge 的「800-tone 深字（dark 覆寫換 300-tone 淺字）」token 而非 raw
 * --error/--warning/--info/--success token：raw token（如 #D97706）疊在 15% tint 背景上
 * 實測僅 ~2.9:1、不過 WCAG AA 4.5:1；*-strong token 是 §5.4 已驗證 8+:1 的配色，重用之
 * 維持 mandatory a11y 合規（C6：兩色階皆吃 token，不再寫死 hex）。
 */
.alert-error {
  background: rgba(239, 68, 68, 0.15);
  border-left-color: var(--error);
  color: var(--error-strong); /* a11y: 同 badge-danger */
}
.alert-warning {
  background: rgba(245, 158, 11, 0.15);
  border-left-color: var(--warning);
  color: var(--warning-strong); /* a11y: 同 badge-warning */
}
.alert-success {
  background: rgba(34, 197, 94, 0.15);
  border-left-color: var(--success);
  color: var(--success-strong); /* a11y: 同 badge-success */
}
.alert-info {
  background: rgba(59, 130, 246, 0.15);
  border-left-color: var(--info);
  color: var(--info-strong); /* a11y: 同 badge-info */
}

/* ============================================================
   §11 Page Header（§4.1）
   ============================================================ */
.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--spacing-7);
  flex-wrap: wrap;
  margin-bottom: var(--spacing-9);
}
.page-header h1 {
  margin: 0;
  font-size: var(--font-size-2xl);
}
.page-header .actions {
  display: flex;
  gap: var(--spacing-5);
  align-items: center;
  flex-wrap: wrap;
}
/* C7：頁面副標（h1 底下那行 .text-muted 說明文字）三個頁面（Chat/Index、Admin/Stats、
   Admin/Bots/Index）重複用同一組 inline margin，收攏成一條選取器。 */
.page-header p {
  margin: 0.25rem 0 0 0;
}

/* ============================================================
   §12 Empty State（§3.7）
   ============================================================ */
.empty-title {
  margin: var(--spacing-5) 0 var(--spacing-3) 0;
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  color: var(--text-primary);
}
/* C7：空狀態置中容器（Chat/Index、Admin/Stats、Admin/Bots/Index 三處重複的
   text-align:center + 大內距 wrapper，原本各自用 inline style 寫）。 */
.empty-state {
  text-align: center;
  padding: var(--spacing-11);
}

/* ============================================================
   §13（移除，fix/immersive-login）：舊「site-main 內置中卡片」登入樣式已隨
   Pages/Auth/Login.cshtml 改為 Layout=null 沉浸式全頁（page-local <style>，
   承 usc-ui-guidelines §4.9 視覺語彙）而汰除。頁面本身不再連結 site.css，
   樣式全部搬進頁面自己的 <style> 區塊，理由與細節見
   .superpowers/sdd/task-login-report.md。
   ============================================================ */

/* ============================================================
   §14 App Alert Dialog — 已改用 SweetAlert2 (AppAlert wrapper，
   usc-ui-guidelines §4.6)。SweetAlert2 自帶樣式（style-src
   'unsafe-inline' 已涵蓋其注入的 <style>），本檔不自訂 light mode 的
   modal CSS，按鈕外觀改由 app-alert.js 的 customClass 對應既有 .btn 元件。
   C6：dark mode 下 SweetAlert2 預設白底黑字不可用，§20 補了範圍極小、僅
   dark 生效的 popup/title/html-container/backdrop 覆寫（Global Constraints
   明訂唯一允許的元件級 [data-theme] 顏色特例）。
   ============================================================ */

/* ============================================================
   §15 Utilities
   ============================================================ */
.text-muted {
  color: var(--text-muted);
}
.text-right {
  text-align: right;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
   §16 Stats Dashboard（Phase 3-B — /admin/stats 用量儀表板）

   長條圖高度刻意不用 inline style="height:NN%"：雖然本站 CSP 的
   style-src 已含 'unsafe-inline'、技術上可行，但比照 C7 精神改用
   「預算好的階梯 class」（bar-h0…bar-h100，5% 級距、21 個），
   由後端把百分比量化到最近的級距後只吐出 class 名——樣式規則
   固定寫死在這裡，頁面不會依資料內容產生任意字串。
   ============================================================ */
.stats-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--spacing-7);
  margin-bottom: var(--spacing-9);
}
.stats-card-label {
  margin: 0 0 var(--spacing-2) 0;
  color: var(--text-secondary);
  font-size: var(--font-size-sm2);
  font-weight: var(--font-weight-medium);
}
.stats-card-value {
  margin: 0;
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
}
.stats-card-breakdown {
  margin: var(--spacing-2) 0 0 0;
  font-size: var(--font-size-sm2);
}
.stats-section {
  margin-bottom: var(--spacing-9);
}
.stats-footnote {
  font-size: var(--font-size-sm);
  margin-top: var(--spacing-7);
}

.stats-bars {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 120px;
}
.stats-bar {
  position: relative;
  flex: 1;
  background: var(--primary);
  min-height: 2px;
  border-radius: 2px 2px 0 0;
  transition: background-color var(--transition-base);
}
.stats-bar:hover {
  background: var(--primary-hover);
}

/* 5% 級距、21 個階梯 class（0 / 5 / 10 / … / 100） */
.bar-h0   { height: 2px; }
.bar-h5   { height: 5%; }
.bar-h10  { height: 10%; }
.bar-h15  { height: 15%; }
.bar-h20  { height: 20%; }
.bar-h25  { height: 25%; }
.bar-h30  { height: 30%; }
.bar-h35  { height: 35%; }
.bar-h40  { height: 40%; }
.bar-h45  { height: 45%; }
.bar-h50  { height: 50%; }
.bar-h55  { height: 55%; }
.bar-h60  { height: 60%; }
.bar-h65  { height: 65%; }
.bar-h70  { height: 70%; }
.bar-h75  { height: 75%; }
.bar-h80  { height: 80%; }
.bar-h85  { height: 85%; }
.bar-h90  { height: 90%; }
.bar-h95  { height: 95%; }
.bar-h100 { height: 100%; }

/* ============================================================
   §17 Chat（Phase 3-C — /chat 選單 ＋ /chat/{botKey} 聊天室）

   任何用 [hidden] 屬性切換顯示的 chat-* 元素都靠這條規則保證真的隱藏——
   author stylesheet 對同 specificity 的宣告一律贏過瀏覽器內建 UA stylesheet
   的 [hidden]{display:none}，若下面各元件各自宣告 display（如 .chat-input-row
   的 flex）卻沒有明確處理 [hidden]，會出現「有 hidden 屬性但視覺仍顯示」的 bug。
   用 descendant selector 拉高 specificity、統一在這裡守住，元件規則不必逐一加註。
   ============================================================ */
.chat-room [hidden] {
  display: none !important;
}

/* --- §17.1 Bot 選單（/chat） ---
   UI polish Job B（2026-09-02）：卡片從「標題＋muted 說明＋optional badge」加一顆 avatar，
   hover 從純 background 換色升級成 lift（shadow＋border 色調），維持既有 token／不動任何
   顏色 hex——所有新規則吃既有 var()，不需要新增 §1.1 兩塊 dark 覆寫（皆已涵蓋 --primary／
   --primary-fill／--card-border 等）。 */
.chat-bot-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); /* auto-fit：空軌收合、卡片均分（測試庫3隻/正式站4隻都滿版） */
  gap: var(--spacing-9);
}
.chat-bot-card {
  display: block;
  color: inherit;
  cursor: pointer;
  transition: background-color var(--transition-base), box-shadow var(--transition-base),
              border-color var(--transition-base);
}
.chat-bot-card:hover {
  background: var(--card-hover);
  border-color: var(--primary);
  text-decoration: none;
  box-shadow: var(--shadow-elevated);
}
/* 卡片內容區走 flex column＋min-height：1 行/2 行說明文字的卡片視覺高度對齊，不靠
   grid 同列自動 stretch（不同列筆數不同時仍可能高度不一）。min-height 是 layout
   dimension（§10.3 例外，非顏色/字級/間距 token 可表達的值）——約略等於
   avatar(40px)+標題+兩行說明+上下 padding 的內容高度，讓短說明的卡片不顯得過扁。 */
.chat-bot-card .card-body {
  display: flex;
  flex-direction: column;
  min-height: 176px; /* layout dimension（§10.3 例外）：容納 avatar+標題+兩行說明 */
}
.chat-bot-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin-bottom: var(--spacing-5);
  border-radius: var(--radius-lg);
  /* Face-lift (task-face-lift) Task D：flat fill → 漸層語彙，跟品牌標記／聊天室身分卡／
     訊息串 avatar 統一（見 .brand-mark 註解），純換 background、不動尺寸/間距。 */
  background: linear-gradient(135deg, var(--primary-fill), var(--primary-fill-to));
  color: #fff;
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  flex-shrink: 0;
}
.chat-bot-name {
  margin: 0 0 var(--spacing-3) 0;
  font-size: var(--font-size-lg);
}
.chat-bot-desc {
  margin: 0 0 var(--spacing-5) 0;
}
/* .card-body 的 flex column 預設 align-items: stretch 會把 .badge（本身 display:inline-flex，
   §9）撐成滿版寬度長條、破壞 pill 形狀——只需要這一個子元素不 stretch，比起整個容器改
   align-items: flex-start（會連帶影響 h2/p 的 shrink-to-fit 寬度）更精準、風險更低。 */
.chat-bot-card .badge {
  align-self: flex-start;
}

/* --- §17.2 聊天室（/chat/{botKey}） ---
   Face-lift (task-face-lift)：對齊 ui-demo-聊天室新造型.html 造型樣張（brand header／
   機器人身分卡／泡泡語言／引用晶片／浮動輸入區）。收斂閱讀寬從 760px 加寬到 860px
   （mock .chat-wrap），其餘沿用既有 token，見各子區塊註解。 */
.chat-room {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-7);
  /* 頁寬吃 .site-main 的 --page-width（全站單一 1200，navbar/footer 共線） */
  max-width: 100%;
}
.chat-back-link {
  display: inline-block;
  font-size: var(--font-size-sm2);
}

/* 機器人身分卡（取代原本純標題列 .chat-room-header/.chat-room-title/.chat-room-actions）：
   漸層 avatar＋名稱＋簡介（Bot.Description，可能為 null，Room.cshtml 已 empty-safe）＋
   右側操作鈕，對應 mock .bot-header。 */
.chat-bot-header {
  display: flex;
  align-items: center;
  gap: var(--spacing-6);
  padding: var(--spacing-7) var(--spacing-8);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-card);
  flex-wrap: wrap;
}
.chat-bot-header-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: var(--radius-lg);
  background: linear-gradient(135deg, var(--primary-fill), var(--primary-fill-to));
  color: #fff;
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-bold);
  flex-shrink: 0;
}
.chat-bot-header-info {
  flex: 1 1 auto;
  min-width: 0;
}
.chat-bot-header-info h1 {
  margin: 0;
  font-size: var(--font-size-lg);
}
.chat-bot-header-info p {
  margin: var(--spacing-1) 0 0 0;
  color: var(--text-muted);
  font-size: var(--font-size-sm2);
}
.chat-bot-header-actions {
  display: flex;
  gap: var(--spacing-3);
  flex-wrap: wrap;
  margin-left: auto;
}

/* UI 規範 audit fix 3：登入面板改走 SweetAlert2 modal（見 chat.js openLoginModal()／
   Room.cshtml <template id="chat-login-template">），原本行內卡片用的 .chat-login-panel／
   .chat-login-actions 兩條規則隨之移除；彈窗內欄位只需要蓋掉 SweetAlert2 預設置中對齊，
   欄位本身沿用 .form-group／.form-label／.form-select／.form-input（§7，已 token 驅動）。 */
.chat-login-swal-fields {
  text-align: left;
}
/* 轉單雛形 Task 2：報修表單彈窗，同上——蓋掉 SweetAlert2 htmlContainer 預設置中對齊，
   欄位一樣沿用 .form-group／.form-label／.form-select／.form-input／.form-textarea。 */
.chat-ticket-swal-fields {
  text-align: left;
}
.chat-ticket-beta-note {
  font-size: var(--font-size-sm);
  color: var(--text-muted);
  margin-top: var(--spacing-3);
}
/* Face-lift Task B2：底線連結 → mock 的 pill 按鈕（邊框 --primary、hover 填色、圈圈重試
   icon 用內嵌 SVG 取代文字符號 ⟳，見 chat.js showAiNoteRetry()）——狀態機邏輯不動，
   純換皮。 */
.chat-ticket-ai-retry {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-2);
  background: none;
  border: 1.5px solid var(--primary);
  border-radius: var(--radius-pill);
  padding: 0.125rem var(--spacing-5);
  font: inherit;
  font-size: var(--font-size-sm);
  color: var(--primary-strong);
  cursor: pointer;
  transition: background-color var(--transition-base), color var(--transition-base);
}
.chat-ticket-ai-retry:hover:not(:disabled) {
  background: var(--primary-fill);
  color: #fff;
  border-color: transparent;
}
.chat-ticket-ai-retry:disabled {
  color: var(--text-muted);
  border-color: var(--card-border);
  cursor: default;
}
.chat-ticket-ai-retry svg {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}
/* AI 預判分類註記（競賽 demo 前一天新增）：緊貼在類別 <select> 底下（同一個
   form-group 內），同 .chat-ticket-beta-note 的 muted/small token 組合，margin 用
   --spacing-1（4px）而非 beta-note 的 --spacing-3——這則是同一欄位的補充說明、不是整份
   表單底部的獨立提示，間距該更緊貼來源欄位。預設 hidden（見 Room.cshtml template），
   chat.js 只切換 hidden 屬性，不靠這條規則做顯示/隱藏。 */
.chat-ticket-ai-note {
  font-size: var(--font-size-sm);
  color: var(--text-muted);
  margin-top: var(--spacing-1);
}
/* UI 規範 audit fix 5：等待態 leading spinner（chat.js setAiNoteToPending() 動態插入的
   <span class="btn-spinner">）——§21 .btn-spinner 原生給 .btn 內用、vertical-align 對齊
   基準不同，這裡另補一點右邊距與微調對齊，範圍限定在 .chat-ticket-ai-note 底下，不動
   §21 共用規則本身。 */
.chat-ticket-ai-note .btn-spinner {
  margin-right: var(--spacing-2);
  vertical-align: -0.1em;
}
/* Face-lift Task B3：轉單成功畫面（chat.js showTicketSuccess()）——綠色圓環＋SVG 勾勾
   （非 emoji）＋大案號（tabular-nums、--primary-strong，見 §1 dark 覆寫新增）＋
   「已自動指派：」承辦人列，取代原本純文字兩行段落。 */
.chat-ticket-success {
  text-align: center;
}
.chat-ticket-success-ring {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin: 0 auto var(--spacing-5);
  border-radius: 50%;
  /* 沿用 §9 .badge-success 同一組「15% tint + *-strong 深字」組合（既有 rgba 字面值、
     全站已有多處先例，不需要新 token；alpha-blend 淡底跨主題不用換，見 §1 --neutral-tint
     旁註解同理）。 */
  background: rgba(34, 197, 94, 0.15);
  color: var(--success-strong);
}
.chat-ticket-success-ring svg {
  width: 28px;
  height: 28px;
}
.chat-ticket-success-caseno {
  margin: 0 0 var(--spacing-2) 0;
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-bold);
  color: var(--primary-strong);
  font-variant-numeric: tabular-nums;
}
.chat-ticket-success-assignee {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--font-size-base);
}
.chat-login-required {
  margin: 0;
}
/* C7：登入引導文案段落（Room.cshtml），原本用 inline style 蓋掉 §2 全域 p 底邊距
   （spacing-7）改成 spacing-5，讓下面的登入按鈕貼近一點。 */
.chat-login-required-text {
  margin: 0 0 var(--spacing-5) 0;
}

/* 訊息區：固定視窗高度、內部捲動，輸入列留在 flex column 尾端——
   在既有 site-header/site-main/site-footer 版型內達成「訊息可捲動＋輸入列常駐可見」，
   不需要 position:sticky 或吃滿 100vh（會跟既有 layout 版面衝突）。
   Face-lift (task-face-lift) 文件化偏離：mock 造型樣張整頁走 body 捲動、訊息直接鋪在
   頁面背景上、輸入區 sticky 到 viewport 底——這裡刻意保留「固定高度＋內部捲動」的
   既有架構（chat.js 全部的 messagesEl.scrollTop 捲到底邏輯都假設 #chat-messages
   本身是捲動容器，改成整頁捲動要重寫這些呼叫點，demo 前一天風險過高）。改用
   background: var(--content-bg)（非 --card-bg）讓這個區塊讀成「頁面底色的凹陷區」而非
   卡片本身——AI 訊息泡泡（見下方 .chat-bubble-assistant）改用 --card-bg，兩者對比後視覺
   效果等同 mock「泡泡浮在頁面底色上」，只是捲動模型不同。 */
.chat-messages {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-7);
  height: 60vh;
  min-height: 360px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--spacing-7);
  /* 公約裁決（usc-ui-guidelines §3.2）：內容區＝白卡浮在 --content-bg 頁面上。先前
     「透明幽靈盒」的根因是誤用 --content-bg 當面板底（與頁面同色）——正解是 --card-bg。
     AI 泡泡同步改 --bubble-ai-bg 淡青面，避免白疊白。 */
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-xl);
}

/* 一則訊息「回合」：avatar（僅 assistant）＋泡泡，對應 mock .turn／.msg-avatar。
   .chat-messages 是 flex column，align-self 從泡泡本身移到這裡（泡泡不再是直接子層）。 */
.chat-turn {
  display: flex;
  gap: var(--spacing-4);
  /* 頁寬升到 1200 後 86% 會逼近千 px 行長；760px 上限保住可讀行寬（±65 字）。 */
  max-width: min(86%, 760px);
}
.chat-turn-user {
  align-self: flex-end;
  flex-direction: row-reverse;
}
.chat-turn-assistant {
  align-self: flex-start;
}
.chat-msg-avatar {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-lg);
  margin-top: 2px;
  flex-shrink: 0;
  background: linear-gradient(135deg, var(--primary-fill), var(--primary-fill-to));
  color: #fff;
  font-size: var(--font-size-sm2);
  font-weight: var(--font-weight-bold);
  display: flex;
  align-items: center;
  justify-content: center;
}
.chat-turn-body {
  display: flex;
  flex-direction: column;
  min-width: 0; /* flex item 預設 min-width:auto 會擋住泡泡內文字換行，見 §17.3 RWD 同理 */
}

.chat-bubble {
  padding: var(--spacing-5) var(--spacing-7);
  border-radius: var(--radius-xl);
  font-size: var(--font-size-base);
  line-height: var(--line-height-normal);
  white-space: pre-wrap;
  word-break: break-word;
}
.chat-bubble-user {
  /* Review fix：白字疊實心底色改吃 --primary-fill/-to（非 --primary/-gradient-to），
     理由同 .btn-primary。無 hover 互動狀態，不需要 -fill-hover。 */
  background: linear-gradient(135deg, var(--primary-fill), var(--primary-fill-to));
  color: #fff;
  border-bottom-right-radius: var(--radius-sm);
  box-shadow: var(--shadow-card);
}
.chat-bubble-assistant {
  /* Face-lift：flat --content-bg → --card-bg（「surface card」語彙，見上方 .chat-messages
     偏離說明）；不對稱圓角從 bottom-left 改 top-left（mock：泡泡頂角對齊左側 avatar
     位置，非底角）。 */
  background: var(--bubble-ai-bg);
  color: var(--text-primary);
  border: 1px solid var(--card-border);
  border-top-left-radius: var(--radius-sm);
  box-shadow: var(--shadow-card);
}
/* 串流游標：閃爍的短豎線接在文字後面，respect prefers-reduced-motion（見 §2 全域規則，
   animation-duration 會被壓到 0.01ms、視覺上等同不閃爍但不影響 layout）。 */
.chat-bubble-assistant.chat-streaming::after {
  content: '';
  display: inline-block;
  width: 2px;
  height: 1em;
  margin-left: 2px;
  vertical-align: text-bottom;
  background: var(--text-primary);
  animation: chat-cursor-blink 1s steps(1) infinite;
}
@keyframes chat-cursor-blink {
  50% { opacity: 0; }
}

/* Face-lift：citations 現在是 assistant 泡泡的最後一個子節點（chat.js renderCitations()
   append 進 node 本身，不再 insertAdjacentElement('afterend')）——視覺上鑲在卡片裡，對應
   mock .bubble > .cites，不再需要 align-self/max-width（泡泡寬度已經是它的容器）。 */
.chat-citations {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-3);
  margin-top: var(--spacing-5);
}
.chat-citation-chip {
  /* UI 規範 audit fix 1：0.625rem 剛好等於 --spacing-4、改走 token；0.125rem（2px）維持
     寫死——guideline §3.10 badge 元件本身的 padding 也是 0.125rem 起手、12 級 spacing
     token 最小階是 --spacing-1 (4px)，沒有對應 2px 的階、全站 badge/chip 這個垂直內距皆同
     此既有慣例（見 §9 .badge），不是本次修的範圍。 */
  padding: 0.125rem var(--spacing-4);
  border-radius: var(--radius-pill);
  background: var(--neutral-tint);
  border: 1px solid var(--card-border); /* Face-lift：mock pill 晶片帶邊框 */
  color: var(--text-muted);
  font-size: var(--font-size-sm);
}
/* C13 Task 2：citation 帶合法 http(s) 來源網址時晶片渲染成 <a>（見 chat.js renderCitations）——
   只加可點樣態，底色/字級沿用上面 .chat-citation-chip、不引入新設計語彙。
   Face-lift：link 變體邊框改用 --primary-glow（既有 dark 感知 token）上色，呼應 mock
   「可點晶片＝彩色邊框」的視覺區分，不需要新 token。 */
.chat-citation-chip-link {
  color: var(--link);
  border-color: var(--primary-glow);
  text-decoration: none;
  cursor: pointer;
}
.chat-citation-chip-link::after {
  content: " ↗"; /* 可點/不可點晶片視覺區分（2026-09-01 使用者回饋：分不出連結跟檔案） */
}
.chat-citation-chip-link:hover,
.chat-citation-chip-link:focus-visible {
  text-decoration: underline;
}

/* Markdown 渲染（chat.js renderMarkdownInto）：assistant bubble 內 <p>/<ul>/<ol>/<a> 的
   最小樣式補丁。<strong> 故意不覆寫——瀏覽器預設粗體已經是要的效果（inherit）。<a> 也不
   另外覆寫——§2 全域 a { color: var(--link) } / a:hover { color: var(--link-hover) } /
   a:focus-visible（§2 outline+shadow-focus）已經套用，不需要在這裡重複一份。這裡只補
   瀏覽器預設沒有 token 化、會在氣泡裡看起來不對的兩塊：
   1) §2 全域 p { margin-bottom: var(--spacing-7) } 對單段落訊息（絕大多數情況、無空行）
      會在氣泡 padding 之外疊出一圈多餘留白，改用較窄的 spacing-3、且最後一段清零；
   2) ul/ol 瀏覽器預設 1em/40px 縮排改用 spacing token，緊貼氣泡字級。 */
.chat-bubble-assistant p {
  margin: 0 0 var(--spacing-3) 0;
}
.chat-bubble-assistant p:last-child {
  margin-bottom: 0;
}
.chat-bubble-assistant ul,
.chat-bubble-assistant ol {
  margin: 0 0 var(--spacing-3) 0;
  padding-left: var(--spacing-9);
}
.chat-bubble-assistant ul:last-child,
.chat-bubble-assistant ol:last-child {
  margin-bottom: 0;
}
.chat-bubble-assistant li + li {
  margin-top: var(--spacing-1);
}

.chat-error {
  margin: 0;
}

/* 浮動輸入區（對應 mock .composer）：圓角容器＋無邊框 textarea＋漸層 icon-only 送出鈕，
   sticky 貼在版面底（頁面本身不因此改變捲動模型，見 .chat-messages 偏離說明——這裡
   sticky 是相對正常文件流 bottom，沒有 100vh/fixed 這類會跟既有 layout 衝突的寫法）。 */
.chat-input-row {
  display: flex;
  align-items: flex-end;
  gap: var(--spacing-3);
  padding: var(--spacing-3) var(--spacing-3) var(--spacing-3) var(--spacing-7);
  background: var(--surface-solid) /* 深色 --card-bg 是 3% 玻璃、sticky 浮層會透底（同 swal 修法） */;
  border: 1px solid var(--card-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-elevated);
  position: sticky;
  bottom: var(--spacing-7);
}
/* 無邊框 textarea 本身不再自己畫 focus ring（蓋掉 §7 .form-textarea:focus 的
   border-color/box-shadow）——鍵盤可見焦點改由容器 :focus-within 承接（§5.3 mandatory：
   不可 outline:none 又不補替代樣式，這裡的替代樣式就是下面這條）。 */
.chat-textarea {
  flex: 1 1 auto;
  min-height: 44px;
  max-height: 160px;
  border: none;
  background: transparent;
}
.chat-textarea:focus {
  border-color: transparent;
  box-shadow: none;
}
.chat-input-row:focus-within {
  box-shadow: var(--shadow-elevated), var(--shadow-focus);
}
.chat-send-btn {
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  min-height: 42px;
  padding: 0;
  border-radius: var(--radius-xl);
}
.chat-send-btn svg {
  width: 18px;
  height: 18px;
}
/* 免責提示（Task A5）：常駐輸入區下方，不隨登入闖關隱藏（一般說明文字，非敏感狀態）。 */
.chat-composer-hint {
  margin: var(--spacing-3) 0 0 0;
  text-align: center;
  font-size: var(--font-size-sm);
  color: var(--text-muted);
}

/* 轉單彈窗（Task B1）：聯絡方式＋位置兩欄，窄螢幕收成一欄（見 §17.3 RWD）。 */
.chat-ticket-field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 var(--spacing-7);
}

/* --- §17.3 RWD（手機瀏覽器） --- */
@media (max-width: 768px) {
  .chat-bot-grid {
    grid-template-columns: 1fr;
  }
  .chat-messages {
    height: 55vh;
    min-height: 320px;
    padding: var(--spacing-5);
  }
  .chat-turn {
    max-width: 92%;
  }
  .chat-input-row {
    flex-direction: column;
    align-items: stretch;
  }
  .chat-send-btn {
    width: 100%;
    border-radius: var(--radius-md);
  }
  .chat-ticket-field-row {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   §18 Error Pages（C7 — Pages/Errors/*.cshtml 共用的置中卡片版型；
   目前只有 403.cshtml，之後新增 404／500 等錯誤頁沿用同一組 class）
   ============================================================ */
.error-page {
  max-width: 600px;
  margin: 4rem auto;
}
.error-page .card-body {
  padding: var(--spacing-11) var(--spacing-10);
  text-align: center;
}
.error-page .btn {
  margin-top: var(--spacing-7);
}

/* ============================================================
   §19 Theme Toggle（C6 — 後台 _Layout ＋ /chat _ChatLayout header 共用的 segmented
   control；標記結構＋class 命名比照 Login.cshtml 的 .theme-btn，承
   usc-ui-guidelines §4.9.3「全站 segmented control」。純 token 驅動、無 [data-theme]
   元件級色特例——active 狀態的 background 走 --primary-fill、在 dark 覆寫塊改吃「加深」
   而非「調亮」的值（見 §1 token 定義旁 review fix 註解），不需要另外覆寫這裡的規則。
   ============================================================ */
.switcher-group {
  display: flex;
  gap: 0.25rem;
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: var(--radius-lg);
  padding: 0.25rem;
}
.switch-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background-color var(--transition-base), color var(--transition-base);
}
.switch-btn:hover {
  background: var(--card-hover);
  color: var(--text-primary);
}
.switch-btn.active {
  /* Review fix：原註解「兩主題 --primary 皆鮮豔 cyan、白字皆達標」未經計算、實測 dark
     --primary #06B6D4 對白字僅 2.43:1（fail AA）——改吃 --primary-fill，dark 覆寫值
     為 cyan-700 #0E7490，白字 5.36:1（算法見 task-c6-report.md fix 章節）。 */
  background: var(--primary-fill);
  color: #fff;
}
.switch-btn svg {
  width: 16px;
  height: 16px;
}

/* ============================================================
   §20 SweetAlert2 Dark Mode Override（C6 — Global Constraints 明訂的唯一元件級
   [data-theme] 顏色特例：SweetAlert2（wwwroot/vendor/sweetalert2）注入自己的
   <style>、.swal2-popup/.swal2-title/.swal2-html-container/backdrop 是寫死
   background:#fff／color:hsl(0,0%,33%)／backdrop rgba(0,0,0,.4)，不吃我們的 CSS
   variable，只能用選擇器覆寫——但覆寫「值」仍一律用 var(token)，不额外寫死顏色。
   按鈕已由 app-alert.js／chat.js 的 buttonsStyling:false + customClass 對應 .btn/.btn-primary/
   .btn-secondary/.btn-danger（皆已 token 化），dark 下隨 :root[data-theme="dark"] 自動
   變色，這裡不需要再覆寫按鈕。UI 規範 audit fix 3（chat.js openLoginModal()）在彈窗內放了
   表單欄位，但刻意重用 .form-select／.form-input（§7）而不是 SweetAlert2 原生的
   .swal2-input／.swal2-select——前者本來就是 :root token 驅動、在 dark 下自動正確，
   後者才需要額外覆寫（且原生 .swal2-input 也不吃我們的 border-radius／spacing 慣例）。
   故本節仍然不需要 .swal2-input／.swal2-select 覆寫規則；如果未來真的有地方改用原生
   SweetAlert2 input（而非 .form-input），屆時要在這裡補一組。
   選擇器特異度：SweetAlert2 全用 :where() 包自己的 class（特異度歸零），我們的
   `:root[data-theme="dark"] .swal2-xxx` 特異度必贏，不需要 !important。Review fix：
   plain attribute 版本原本漏了 :root 前綴（(0,0,2,0) vs media-query 版的 (0,0,3,0)），
   跟 sibling 選擇器特異度不對稱——即使目前不影響行為（vendor 選擇器歸零特異度、兩邊
   都贏），仍補上 :root 對齊，避免未來疊加其他 [data-theme] 規則時特異度不可預期。
   ============================================================ */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .swal2-popup {
    background: var(--surface-solid);
    color: var(--text-primary);
    border: 1px solid var(--card-border);
    box-shadow: var(--shadow-elevated);
  }
  :root:not([data-theme="light"]) .swal2-title,
  :root:not([data-theme="light"]) .swal2-html-container {
    color: var(--text-primary);
  }
  :root:not([data-theme="light"]) .swal2-container.swal2-backdrop-show {
    background: var(--backdrop);
  }
}
:root[data-theme="dark"] .swal2-popup {
  background: var(--surface-solid);
  color: var(--text-primary);
  border: 1px solid var(--card-border);
  box-shadow: var(--shadow-elevated);
}
:root[data-theme="dark"] .swal2-title,
:root[data-theme="dark"] .swal2-html-container {
  color: var(--text-primary);
}
:root[data-theme="dark"] .swal2-container.swal2-backdrop-show {
  background: var(--backdrop);
}

/* ============================================================
   §21 Form Submit Feedback（UI 規範 audit fix 4 — usc-ui-guidelines §6.1，
   wwwroot/js/form-submit-feedback.js 全站 submit 委派監聽器共用的 spinner 視覺）。

   不用 Font Awesome（site.css 檔頭決策：CSP 無 CDN origin），用純 CSS 圈圈 spinner；
   border-color 吃 currentColor，自動跟著所在按鈕的文字色（.btn-primary/-danger/-success
   白字、.btn-secondary 深字）走，不寫死顏色、light/dark 兩態不需要另外覆寫。動畫時長
   0.6s 在 §2 全域 prefers-reduced-motion 規則（*, *::before, *::after 一律壓到 0.01ms）
   涵蓋範圍內，不需要在這裡重複宣告。
   ============================================================ */
.btn-spinner {
  display: inline-block;
  width: 0.9em;
  height: 0.9em;
  vertical-align: -0.15em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  opacity: 0.85;
  animation: btn-spinner-spin 0.6s linear infinite;
}
@keyframes btn-spinner-spin {
  to { transform: rotate(360deg); }
}

/* ============================================================
   §22 Table Page Polish（Admin/Tickets/Index — 案號/類別/描述/聯絡/承辦/
   狀態/建立時間 共 7 欄，前台標準頁寬太窄，長案號「LIS-20260902-001」
   跟「網路連線問題」類別逐字換行、兩側留白反而過大；狀態欄 badge/select/按鈕
   直向堆疊像座塔。這裡收斂成 4 條可重用的 table 修飾 class（非 Tickets 專屬命
   名），供其他表格頁面日後需要同樣加寬/不換行/兩行截斷/inline 狀態列時直接
   套用，不必重新發明。
   ============================================================ */

/* 22.1（已收斂）全站單一頁寬 1200（見 :root --page-width 註解），不再有
   per-page 加寬 modifier；表格塞不下一律 .table-wrap 橫向捲動。 */

/* 22.2 欄位不換行 —— 案號／類別／承辦／建立時間等短欄位，換行比留白更難讀。 */
.table-nowrap {
  white-space: nowrap;
}

/* 22.3 描述欄兩行截斷 + fallback —— 有 line-clamp 支援的瀏覽器顯示兩行後省略
   號截斷；標準屬性 line-clamp 與 -webkit-line-clamp 都聲明（前者是後者的標準
   化版本，寫法上互不相容需分開宣告，同時保留兩者以涵蓋新舊瀏覽器）。不支援
   line-clamp 的瀏覽器（@supports 測不到）退化成單行 + text-overflow: ellipsis
   ——不是完美的兩行呈現，但比毫無省略、直接被裁切一半文字更可讀，符合「CSS
   line-clamp with fallback」要求。max-width 搭配 §8 .table-wrap 的橫向捲動，
   欄寬本身不會被長字串撐開。完整文字另外放 title attribute（Razor 自動
   HTML-encode，不需要在這裡處理跳脫）。 */
.table-desc {
  max-width: 420px; /* layout dimension（§10.3 例外）：描述是本表資訊主體，給最大份額 */
}
/* 描述文字放在 <button> 裡（鍵盤可操作的展開/收合），按鈕歸零成純文字外觀；
   全文只有這裡能看，所以展開是正式功能不是彩蛋。 */
.desc-toggle {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  line-height: 1.55; /* 明確定死：clamp 的 max-height 以此為基準，否則繼承行高不同會切出半截字 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@supports (-webkit-line-clamp: 2) or (line-clamp: 2) {
  .desc-toggle {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    max-height: calc(2 * 1.55em); /* clamp 保險：避免第三行殘影露出（與上方 line-height 同值） */
  }
}
.desc-toggle[aria-expanded="true"] {
  display: block;
  -webkit-line-clamp: unset;
  line-clamp: none;
  max-height: none;
  white-space: normal;
}

/* 22.4 狀態欄 inline 排列 —— 原本 badge（span）+ form（區塊元素）直向堆疊成一
   座塔；.table-status-row 把兩者收進同一個 flex row。form 內部（隱藏 input +
   sr-only label + select + 按鈕）另外自己也是 flex row（.table-status-form），
   兩層 flex 皆 align-items:center，視覺上呈現成單一橫列。sr-only label／hidden
   input 本身不佔版面（§15 .sr-only 用 absolute + clip，input[type=hidden] 瀏覽
   器原生不渲染），不影響排列。.form-select 預設 width:100%（§7，表單直向欄位
   慣例）在這裡覆寫成 width:auto + min-width，避免下拉選單被拉伸成滿版寬。 */
.table-status-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-3);
  flex-wrap: nowrap;
}
.table-status-form {
  display: flex;
  white-space: nowrap; /* 「更新」鈕與選項文字禁止折行（驗貨回饋：窄欄下折成兩行） */
  align-items: center;
  gap: var(--spacing-3);
  margin: 0;
}
.table-status-form .form-select {
  width: auto;
  min-width: 108px; /* layout dimension（§10.3 例外）：容納「處理中」3 字選項不擁擠 */
}
