/* 2026-09-04 起這個網站要陸續統一風格，先在這裡定義色彩/間距/圓角/陰影規範，
   之後其他頁面要跟進時直接引用這些變數，不要在各頁面各自硬寫顏色。目前定案：
   底色中性淡灰（不偏任何色相）、主色調深藍（跟 header 標題原本的顏色一致，
   避開 LINE 品牌綠——網站上到處都是「已處理/待處理」這類綠/紅狀態標籤，
   主色調用綠色會混淆）。這次先套用到首頁，其他頁面之後再陸續跟進。 */
:root {
  --color-bg: #f7f8fa;
  --color-surface: #fff;
  --color-primary: #163b63;
  --color-primary-hover: #0f2c4c;
  --color-primary-tint: rgba(22, 59, 99, .07);
  --color-primary-tint-strong: rgba(22, 59, 99, .14);
  --color-text: #1f2328;
  --color-text-muted: #57606a;
  --color-border: #d8dee5;
  --radius-md: 10px;
  --radius-lg: 14px;
  --shadow-sm: 0 1px 2px rgba(20, 24, 33, .05);
  --shadow-md: 0 6px 16px rgba(20, 24, 33, .08);
}

/* 工程團隊管理的手機版刻意使用一般區塊元素，而不是將 table 元素偽裝成卡片。
   這樣滑動時只有單一內容層需要 transform，圓角裁切不會落在 tr/td 合成層上。 */
#engineering-team-mobile-list,
#et-mobile-add-row-btn {
  display: none;
}

@media (max-width: 768px) {
  #engineering-team-form > .table-scroll,
  #engineering-team-table {
    display: none;
  }

  #engineering-team-mobile-list {
    display: grid;
    gap: 10px;
  }

  #engineering-team-form #add-row-btn {
    display: none;
  }

  #et-mobile-add-row-btn {
    display: inline-block;
    margin-top: 12px;
  }

  .et-mobile-card {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: #cf222e;
    box-shadow: var(--shadow-sm);
  }

  .et-mobile-card-content {
    position: relative;
    z-index: 1;
    background: var(--color-surface);
    transform: translateX(-3%);
    transition: transform .2s ease;
  }

  .et-mobile-card-swiped .et-mobile-card-content {
    transform: translateX(-25%);
  }

  /* 閉合時留出右側紅邊作為滑動提示；資料本身反向位移，位置不變。
     展開後取消反向位移，讓內容剛好跟原本一樣左移 25%。 */
  .et-mobile-card-content > .et-mobile-field > *,
  .et-mobile-card-content > .et-mobile-actions > * {
    transform: translateX(3%);
    transition: transform .2s ease;
  }

  .et-mobile-card-swiped .et-mobile-card-content > .et-mobile-field > *,
  .et-mobile-card-swiped .et-mobile-card-content > .et-mobile-actions > * {
    transform: none;
  }

  .et-mobile-delete-btn {
    position: absolute;
    z-index: 0;
    top: 0;
    right: 0;
    bottom: 0;
    width: 25%;
    border: 0;
    border-radius: 0;
    background: #cf222e;
    color: #fff;
    font-weight: 700;
    pointer-events: none;
  }

  .et-mobile-card-swiped .et-mobile-delete-btn {
    pointer-events: auto;
  }

  .et-mobile-field {
    display: grid;
    grid-template-columns: 84px minmax(0, 1fr);
    gap: 10px;
    padding: 8px 14px;
    border-bottom: 1px solid var(--color-border);
  }

  .et-mobile-label {
    padding-top: 2px;
    color: var(--color-text-muted);
    font-size: .76rem;
  }

  .et-mobile-value,
  .et-mobile-field .edit-input,
  .et-mobile-field .password-input {
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .et-mobile-actions {
    display: flex;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 8px;
    padding: 10px 14px;
  }

  .et-mobile-empty {
    margin: 0;
  }
}

/* 帳號管理：list-only 卡片，保留列內編輯、密碼變更與左滑單筆刪除。 */
#admin-users-mobile-list {
  display: none;
}

@media (max-width: 768px) {
  #admin-users-table,
  #bulk-delete-btn {
    display: none;
  }

  #admin-users-mobile-list {
    display: grid;
    gap: 10px;
  }

  .admin-users-mobile-card {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: #cf222e;
    box-shadow: var(--shadow-sm);
  }

  .admin-users-mobile-card-content {
    position: relative;
    z-index: 1;
    background: var(--color-surface);
    transform: translateX(-3%);
    transition: transform .2s ease;
  }

  .admin-users-mobile-card-swiped .admin-users-mobile-card-content {
    transform: translateX(-25%);
  }

  .admin-users-mobile-card-content > .admin-users-mobile-field > *,
  .admin-users-mobile-card-content > .admin-users-mobile-actions > * {
    transform: translateX(3%);
    transition: transform .2s ease;
  }

  .admin-users-mobile-card-swiped .admin-users-mobile-card-content > .admin-users-mobile-field > *,
  .admin-users-mobile-card-swiped .admin-users-mobile-card-content > .admin-users-mobile-actions > * {
    transform: none;
  }

  .admin-users-mobile-field {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 45px;
    padding: 8px 14px;
  }

  .admin-users-mobile-field + .admin-users-mobile-field {
    border-top: 1px solid var(--color-border);
  }

  .admin-users-mobile-label {
    flex: 0 0 88px;
    color: var(--color-text-muted);
    font-size: .8rem;
  }

  .admin-users-mobile-value,
  .admin-users-mobile-field .edit-input,
  .admin-users-mobile-field .username-input {
    min-width: 0;
    flex: 1;
    overflow-wrap: anywhere;
  }

  .admin-users-mobile-input-wrap {
    min-width: 0;
    flex: 1;
  }

  .admin-users-mobile-input-wrap .username-input {
    width: 100%;
  }

  .admin-users-mobile-actions {
    display: flex;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 8px;
    padding: 10px 14px;
    border-top: 1px solid var(--color-border);
  }

  .admin-users-mobile-actions .new-password-wrap {
    display: flex;
    flex: 1 0 100%;
    gap: 6px;
  }

  .admin-users-mobile-actions .new-password-input {
    min-width: 0;
    flex: 1;
  }

  .admin-users-mobile-delete-btn {
    position: absolute;
    z-index: 0;
    inset: 0 0 0 auto;
    width: 25%;
    border: 0;
    border-radius: 0;
    background: #cf222e;
    color: #fff;
    font-weight: 700;
    pointer-events: none;
  }

  .admin-users-mobile-card-swiped .admin-users-mobile-delete-btn {
    pointer-events: auto;
  }

  .admin-users-mobile-empty {
    margin: 0;
    padding: 16px;
    text-align: center;
  }

  #add-row-btn {
    margin-top: 12px;
  }
}

.username-validation-error {
  margin-top: 4px;
  color: #cf222e;
  font-size: .8rem;
}

/* LINE ID 同步異常：本頁只有兩組清單與處理按鈕，不建立 form 或滑動刪除。 */
.odoo-line-id-sync-mobile-list {
  display: none;
}

@media (max-width: 768px) {
  .odoo-line-id-sync-table {
    display: none;
  }

  .odoo-line-id-sync-mobile-list {
    display: grid;
    gap: 10px;
  }

  .odoo-line-id-sync-card {
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
  }

  .odoo-line-id-sync-field {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    min-height: 45px;
    padding: 8px 14px;
  }

  .odoo-line-id-sync-field + .odoo-line-id-sync-field,
  .odoo-line-id-sync-actions {
    border-top: 1px solid var(--color-border);
  }

  .odoo-line-id-sync-label {
    flex: 0 0 88px;
    padding-top: 2px;
    color: var(--color-text-muted);
    font-size: .8rem;
  }

  .odoo-line-id-sync-value {
    min-width: 0;
    flex: 1;
    overflow-wrap: anywhere;
  }

  .odoo-line-id-sync-actions {
    display: flex;
    justify-content: flex-end;
    padding: 10px 14px;
  }

  .odoo-line-id-sync-empty {
    margin: 0;
    padding: 16px;
    text-align: center;
  }
}

* {
  box-sizing: border-box;
}

body {
  font-family: "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", -apple-system, "Segoe UI", sans-serif;
  margin: 0;
  padding: 24px 32px;
  color: var(--color-text);
  background-color: var(--color-bg);
  /* 雲紋質感紋理：SVG feTurbulence 產生柔和的不規則雲霧狀變化，用主色調染色，
     低頻率＋多層疊加做出雲朵般的柔和明暗變化，不是機械式的規則網格。 */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320'%3E%3Cfilter id='n' x='0' y='0' width='100%25' height='100%25' primitiveUnits='userSpaceOnUse'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.01' numOctaves='4' stitchTiles='stitch' result='t'/%3E%3CfeColorMatrix in='t' type='matrix' values='0 0 0 0 0.086  0 0 0 0 0.231  0 0 0 0 0.388  0 0 0 0.22 0'/%3E%3C/filter%3E%3Crect width='320' height='320' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 320px 320px;
  line-height: 1.55;
}

header h1 {
  margin: 0 0 4px;
  color: var(--color-primary);
  letter-spacing: 0.02em;
  font-size: 1.65rem;
  font-weight: 750;
}

.header-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}

.user-info {
  margin: 0;
}

.hint {
  color: #57606a;
  font-size: 0.9rem;
  margin: 4px 0;
}

.error {
  color: #cf222e;
}

.home-section-title {
  margin: 0 0 12px;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--color-primary);
}

/* 分類本身橫向並排（一個分類一欄），分類底下的卡片直向堆疊——見 home.html 的
   .home-columns（橫向）／.function-grid（直向）。 */
.home-columns {
  display: flex;
  gap: 24px;
  align-items: flex-start;
  margin-top: 24px;
}

.home-section {
  flex: 1 1 0;
  min-width: 0;
}

.function-grid {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* 卡片三層結構，卡片高度固定不隨 hover 變動：
   第 1 層（最底）.function-card-hint  —— 說明文字，平常寬度 0、被第 2 層完全蓋住
   第 2 層（中間）.function-card-photo —— 底圖照片，平常滿版顯示
   第 3 層（最上）.function-card-title —— 卡片名稱，隨時可見，蓋在照片上，不受 hover 影響
   滑鼠移上卡片時，第 1 層從左邊往右滑開成卡片寬度 70% 的不透明色塊蓋掉第 2 層
   （此時照片只剩右側 30% 看得到），露出說明文字；動的是寬度不是高度，卡片本身
   高度全程固定。 */
.function-card {
  position: relative;
  display: block;
  height: 163px;
  overflow: hidden;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  color: inherit;
  transition: box-shadow .15s ease, border-color .15s ease, transform .15s ease;
}

.function-card:hover {
  border-color: var(--color-primary);
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}

.function-card-photo {
  position: absolute;
  inset: 0;
  z-index: 1;
  /* 平常（非 hover）狀態下照片本身就由左到右漸淡出（左側淡、右側完整），
     不是只有 hover 展開的白底面板才蓋住左側——這兩個是分開的效果。 */
  background-image:
    linear-gradient(to right, var(--color-surface) 0%, rgba(255, 255, 255, .15) 45%, rgba(255, 255, 255, 0) 70%),
    var(--card-photo);
  background-size: 100% 100%, cover;
  /* 第二層（照片本身）的裁切位置預設「靠右置中」，個別照片重要主體不在正中央時
     （例如 FAQ 管理那張，問號在頭頂上方）可以用 --card-photo-position 覆寫。 */
  background-position: 0 0, var(--card-photo-position, right center);
  background-repeat: no-repeat, no-repeat;
}

.function-card-hint {
  display: block;
  position: absolute;
  inset: 0 auto 0 0;
  z-index: 2;
  width: 0;
  overflow: hidden;
  background: var(--color-surface);
  transition: width .2s ease;
  /* 右邊界加一點陰影，讓白底面板看起來是「疊」在照片上滑出來的一層，不是硬切的
     平面色塊，展開時才有層次感。 */
  box-shadow: 10px 0 24px -8px rgba(20, 24, 33, .25);
  /* 上方留白避開最上層的標題貼紙（約 56px 高）——這個位移要放在外層容器，不能
     跟下面 <p> 的 max-height 放在同一個元素：`* { box-sizing: border-box }` 會讓
     max-height 把 padding 也算進去，56px 的 padding-top 會直接把 max-height 吃光，
     導致文字整個被壓扁只剩一行（踩過這個坑）。 */
  padding-top: 56px;
}

.function-card:hover .function-card-hint,
.function-card:focus-visible .function-card-hint {
  width: 70%;
}

.function-card-hint p {
  margin: 0;
  /* 卡片固定 163px（量測自正式站台現有「LINE ID 同步異常」卡片 hover 展開後的
     實際渲染尺寸）。文字較長時要截斷——原本想用 -webkit-line-clamp，但實測
     `display: -webkit-box` 在這個環境沒有被瀏覽器辨識（computed style 算出來是
     flow-root，不是 -webkit-box），line-clamp 完全沒作用。改用 max-height 搭配
     overflow:hidden 硬性裁掉（雖然沒有「…」省略號，但保證不會有殘影），三行的
     line-height 要重新量測校準，不能只用算的（見下方 debug 腳本量出來的實際值）。 */
  padding: 2px 20px 14px 16px;
  font-size: .82rem;
  line-height: 1.6;
  letter-spacing: .01em;
  color: var(--color-text-muted);
  max-height: 68px;
  overflow: hidden;
}

.function-card-title {
  display: block;
  position: absolute;
  inset: 0 auto auto 0;
  z-index: 3;
  padding: 12px 16px;
  pointer-events: none;
}

.function-card-title h2 {
  display: inline-block;
  margin: 0;
  font-size: .95rem;
  color: var(--color-text);
  /* 不再用白底色塊當貼紙——第一層照片本身在左側就有淡化效果，標題本來就疊在
     偏白的區域上，靠這層淡化加一點文字陰影就夠可讀，不需要額外的白框。 */
  text-shadow: 0 1px 3px rgba(255, 255, 255, .8), 0 0 8px rgba(255, 255, 255, .6);
}

.login-box {
  max-width: 360px;
  margin: 80px auto;
  padding: 24px;
  border: 1px solid #d0d7de;
  border-radius: 8px;
}

.login-box label {
  display: block;
  margin-bottom: 12px;
}

.login-box input {
  display: block;
  width: 100%;
  margin-top: 4px;
  padding: 6px 8px;
}

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: end;
  margin: 16px 0;
  padding: 14px 16px;
  background: linear-gradient(135deg, #f6f8fa 0%, #eef6ff 100%);
  border: 1px solid #d8e2ef;
  border-radius: 10px;
  box-shadow: 0 2px 8px rgba(31, 35, 40, 0.05);
}

.filter-bar label {
  display: flex;
  flex-direction: column;
  font-size: 0.85rem;
  gap: 4px;
  color: #57606a;
  font-weight: 600;
}

.filter-bar input,
.filter-bar select {
  min-width: 145px;
  padding: 7px 9px;
  border: 1px solid #b6c2cf;
  border-radius: 6px;
  background: #fff;
  color: #1f2328;
  font: inherit;
}

.filter-bar input:focus,
.filter-bar select:focus {
  outline: 2px solid rgba(9, 105, 218, 0.2);
  border-color: #0969da;
}

.filter-bar button {
  padding: 7px 16px;
  border: 0;
  border-radius: 6px;
  background: #0969da;
  color: #fff;
  font-weight: 600;
  cursor: pointer;
}

.filter-bar button:hover { background: #0757b5; }

.status-badge {
  display: inline-block;
  min-width: 4.5em;
  padding: 4px 9px;
  border-radius: 999px;
  text-align: center;
  font-size: 0.85rem;
  font-weight: 700;
  line-height: 1.3;
}

button.status-badge {
  appearance: none;
  border: 1px solid transparent;
  cursor: pointer;
  font-family: inherit;
}

.status-pending {
  background: #fff0d5;
  color: #9a6700;
  border: 1px solid #eacb8a;
}

.status-done {
  background: #dafbe1;
  color: #1a7f37;
  border: 1px solid #9bd9b5;
}

.status-unknown {
  background: #f6f8fa;
  color: #57606a;
  border: 1px solid #d0d7de;
}

.status-failed {
  background: #ffebe9;
  color: #cf222e;
  border: 1px solid #ffb3ac;
}

.status-ai-flag {
  background: #ffe0e0;
  color: #b42318;
  border: 1px solid #f3a9a9;
}

/* 「重複維修單」頁「紀錄處理方式」按鈕彈出的浮動視窗，固定定位在按鈕下方，
   跟頁面其餘表格內容無關，所以獨立寫在這裡，不掛在某個特定表格的樣式底下。 */
.planned-action-popover {
  position: fixed;
  z-index: 100;
  width: 280px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 10px;
}

.planned-action-popover textarea {
  width: 100%;
  resize: vertical;
  font-family: inherit;
  font-size: .85rem;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 6px 8px;
}

.planned-action-popover-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 8px;
}

/* 「帳號管理」頁「變更密碼」按鈕彈出的浮動視窗，跟上面的 planned-action-popover
   是同一種「點按鈕跳出浮動視窗」機制，各自獨立寫一份樣式方便之後各自調整。 */
.password-popover {
  position: fixed;
  z-index: 100;
  width: 260px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 12px;
  font-size: .85rem;
}

.password-popover label {
  display: block;
  margin-bottom: 8px;
}

.password-popover input {
  width: 100%;
  font-family: inherit;
  font-size: .85rem;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 6px 8px;
  margin-top: 2px;
}

.password-popover input:disabled {
  background: var(--color-bg);
  color: var(--color-text-muted);
}

.eye-toggle-btn {
  margin-left: 6px;
  font-size: .78rem;
  padding: 2px 8px;
}

.popover-warning {
  color: #b42318;
  font-size: .8rem;
  margin-bottom: 8px;
}

.password-popover-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

td select.status-select {
  width: auto;
  min-width: 5.5em;
  appearance: none;
  padding: 4px 8px;
  border-radius: 999px;
  font-weight: 700;
  text-align: center;
}

/* 動態新增列在尚未儲存的編輯狀態，也維持與既有狀態標籤一致。 */
#customer-service-logs-table td[data-field="status"] select.edit-input {
  width: auto !important;
  min-width: 5.5em;
  padding: 4px 8px;
  border-radius: 999px;
  text-align: center;
  font-weight: 700;
}

td select.status-select.status-pending { border-color: #eacb8a; background: #fff0d5; color: #9a6700; }
td select.status-select.status-done { border-color: #9bd9b5; background: #dafbe1; color: #1a7f37; }
td select.status-select.status-ai-flag { border-color: #f3a9a9; background: #ffe0e0; color: #b42318; }

table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  background: #fff;
  border: 1px solid #c9d7e6;
  border-radius: 8px;
  /* 不能加 overflow: hidden——會讓這個 table 自己變成 position:sticky 表頭的
     scroll container，而它自己永遠不會內部捲動，結果 sticky 完全失效（thead
     照樣跟著頁面捲走）。圓角外觀改靠 border-radius 本身撐，不靠 overflow 裁切。 */
}

th, td {
  border: 1px solid #dbe4ee;
  padding: 8px 9px;
  vertical-align: top;
  text-align: left;
  font-size: 0.92rem;
}

td {
  overflow: hidden;
}

.group-id-cell {
  overflow-wrap: anywhere;
  word-break: break-all;
}

th {
  background: linear-gradient(180deg, #eaf3fc 0%, #dfeefa 100%);
  color: #234b73;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1.35;
  position: relative;
  overflow: visible;
}

.customer-service-logs-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
}

/* 「新增列」是 type=button、「刪除選取項目」是 type=submit，兩個 id 原本各自
   只有零星的 margin 規則（分別給別的頁面用），拼在同一個 flex 列時，margin
   不對稱會讓 flex 的預設 stretch 把兩顆鈕撐出不同高度。這裡用 id+class 的組合
   選擇器（specificity 比單獨的 #add-row-btn 高）整個重設，確保兩顆鈕的
   padding/margin/border 完全一致，視覺高度才會真的一樣。 */
.customer-service-logs-toolbar #add-row-btn,
.customer-service-logs-toolbar #bulk-delete-btn {
  margin: 0;
  padding: 7px 16px;
  border: 0;
  border-radius: 6px;
  font-weight: 600;
  font: inherit;
  line-height: 1.4;
  cursor: pointer;
  color: #fff;
}

.customer-service-logs-toolbar #add-row-btn { background: #0969da; }
.customer-service-logs-toolbar #add-row-btn:hover { background: #0757b5; }
.customer-service-logs-toolbar #bulk-delete-btn { background: #cf222e; }
.customer-service-logs-toolbar #bulk-delete-btn:hover { background: #a8212a; }

/* 新增案件面板：獨立卡片外觀（視覺上跟 .filter-bar 類似，但不直接套用那個
   class）。版面是使用者指定的四欄分組，用真正的 CSS grid（每個欄位在樣板裡
   用 inline style 標明 grid-column/grid-row），不是 flex column 疊欄位：
     第 1 列：群組/租客、問題時間、處理時間、待處理/已處理
     第 2 列：客訴類型、問題簡述、回覆、預計處理方式
     第 3 列：維修單號（只有第 1 欄有，其餘欄位這一列空著）
     第 4 列：操作按鈕（橫跨全部欄位）
   用 grid 而不是 flex column 疊的理由：flex column 讓每一欄自己往下疊，
   欄位控制項種類不同（input/textarea/狀態切換按鈕）高度本來就不一樣，疊起來
   之後「下一列」的起始高度會因為上面那一列在哪一欄而跑掉，導致同一列的
   欄位上緣對不齊（踩過這個問題才改成 grid）；grid 的列高是「這一列裡最高的
   欄位」，同一個 grid row 的所有欄位永遠共用同一條上緣線，跟其他列的內容
   完全無關。 */
.customer-service-logs-new-entry {
  display: grid;
  grid-template-columns: repeat(4, minmax(160px, 1fr));
  align-items: start;
  gap: 12px 16px;
  margin: 0 0 16px;
  padding: 14px 16px;
  background: linear-gradient(135deg, #f6f8fa 0%, #eef6ff 100%);
  border: 1px solid #d8e2ef;
  border-radius: 10px;
  box-shadow: 0 2px 8px rgba(31, 35, 40, 0.05);
}

/* .filter-bar 本身有 display: flex，[hidden] 屬性的 UA 預設 display:none
   贏不過它（跟 FAQ 管理手機版 #faq-filter-bar[hidden] 同一個已知坑）；這裡
   同樣要明確蓋掉才會真的隱藏。 */
#customer-service-logs-new-entry[hidden] {
  display: none;
}

.customer-service-logs-new-entry label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.85rem;
  color: #57606a;
  font-weight: 600;
}

.customer-service-logs-new-entry input,
.customer-service-logs-new-entry select,
.customer-service-logs-new-entry textarea.edit-input {
  min-width: 0;
  padding: 7px 9px;
  border: 1px solid #b6c2cf;
  border-radius: 6px;
  background: #fff;
  color: #1f2328;
  font: inherit;
}

/* 拖曳調整大小的把手讓每個欄位存檔前的高度完全看使用者有沒有手動拉過，
   同一個面板裡的欄位高度參差不齊——固定高度＋不給拖曳，欄位之間才會齊。
   內容變長時仍會靠既有的 autoSizeTextareas()（JS）自動長高，不是完全鎖死。 */
.customer-service-logs-new-entry textarea.edit-input {
  height: 60px;
  resize: none;
}

.customer-service-logs-new-entry input:focus,
.customer-service-logs-new-entry select:focus,
.customer-service-logs-new-entry textarea:focus {
  outline: 2px solid rgba(9, 105, 218, 0.2);
  border-color: #0969da;
}

.customer-service-logs-new-entry-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.customer-service-logs-new-entry-actions #new-entry-save-btn {
  padding: 7px 16px;
  border: 0;
  border-radius: 6px;
  background: #0969da;
  color: #fff;
  font-weight: 600;
  cursor: pointer;
}

.customer-service-logs-new-entry-actions #new-entry-save-btn:hover { background: #0757b5; }

.customer-service-logs-new-entry-cancel {
  padding: 7px 16px;
  border: 1px solid #b6c2cf;
  border-radius: 6px;
  background: #fff;
  color: #57606a;
  font-weight: 600;
  cursor: pointer;
}

.customer-service-logs-new-entry-cancel:hover { background: #f6f8fa; }

#customer-service-logs-table tbody tr:nth-child(even) { background: #fbfdff; }
#customer-service-logs-table tbody tr:hover { background: #eef6ff; }
#customer-service-logs-table tbody tr.editing { background: #fff8e8; }

/* 主列表往下捲動時固定欄名列，避免長表失去欄位辨識。 */
#customer-service-logs-table thead th {
  position: sticky;
  top: 0;
  z-index: 3;
  background: #f6f8fa;
  box-shadow: 0 1px 0 #d0d7de;
}

.center {
  text-align: center;
}

.view-text {
  white-space: pre-wrap;
  word-break: break-word;
  min-height: 1.4em;
  line-height: 1.55;
}

#customer-service-logs-table td[data-field="issue_summary"] .view-text,
#customer-service-logs-table td[data-field="reply"] .view-text {
  color: #34495e;
  font-size: 0.9rem;
}

/* 內容框：高度依內容自動長高（JS 控制），故意不給 resize 手把，不能手動拖高度 */
td textarea.edit-input {
  display: block;
  width: 100%;
  min-height: 4.5em;
  resize: none;
  overflow: hidden;
  font: inherit;
  border: 1px solid #0969da;
  border-radius: 4px;
  padding: 2px 4px;
}

td textarea.edit-input:focus {
  outline: none;
}

/* 欄寬拖曳手把：放在 th 右側邊界，游標變成左右拉伸提示這裡可以調整寬度 */
.col-resize-handle {
  position: absolute;
  top: 0;
  right: -3px;
  width: 6px;
  height: 100%;
  cursor: col-resize;
  user-select: none;
  z-index: 1;
}

.col-resize-handle:hover {
  background: #0969da;
  opacity: 0.4;
}

tr.editing {
  background: #f6f8fa;
}

.actions-cell button {
  margin: 2px;
}

.chat-content {
  white-space: pre-wrap;
  word-break: break-word;
}

.chat-image {
  max-width: 100%;
  max-height: 320px;
  border-radius: 4px;
}

/* 維修單列表的報修/完工照片：桌面版故意只顯示小縮圖，不展成大圖，不然整個
   表格會被拉得很長；影片等非圖片格式（目前實際上傳限制只有 mp4/mov/webm）
   改成固定的播放圖示，不是文字連結（跟 engineer_app 的 _attachments() 同一套
   「圖片可以直接顯示、其他格式另外處理」判斷邏輯，各自獨立實作）。點縮圖／
   圖示一樣會在新分頁開原始檔案。手機版會把同一批 <a> 直接複製過去，用
   media query 調整排列（見下方 .repair-tickets-mobile-card-photos）。 */
.rt-photos-cell {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: flex-start;
}

.rt-photo-thumb {
  display: block;
  width: 48px;
  height: 48px;
  object-fit: cover;
  border-radius: 4px;
}

/* 影片/檔案圖示跟縮圖同樣尺寸，維持格線對齊。 */
.rt-attachment-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-bg);
  color: var(--color-text-muted);
}

/* 連結預設的底線顏色（瀏覽器內建藍色）會顯示在 <img>／圖示底下——因為 <a> 是
   inline 元素，包住區塊內容後仍保留文字底線該有的那條線，看起來像縮圖之間
   卡了一條不明的藍線；圖片跟圖示現在都是純圖形內容，不需要底線這個「可點擊」
   的視覺提示。 */
.rt-attachment-link {
  display: block;
  text-decoration: none;
}

.chat-video {
  max-width: 100%;
  max-height: 320px;
  border-radius: 4px;
  display: block;
}

/* 水電／匯款回報：數值欄精簡，讓 LINE ID 與原始資料保留足夠閱讀寬度。 */
.utility-payment-reports-table .report-time-col { width: 12%; }
.utility-payment-reports-table .report-name-col { width: 8%; }
.utility-payment-reports-table .report-line-id-col { width: 24%; }
.utility-payment-reports-table .report-meter-col { width: 8%; }
.utility-payment-reports-table .report-amount-col { width: 10%; }
.utility-payment-reports-table .report-source-col { width: 30%; }
.utility-payment-reports-table td {
  overflow-wrap: anywhere;
  word-break: break-word;
}
.utility-payment-reports-table .report-source-cell .chat-content {
  overflow-wrap: anywhere;
}

.pager {
  display: flex;
  gap: 16px;
  align-items: center;
  margin-top: 16px;
}

.pager .disabled {
  color: #8c959f;
}

#add-row-btn, #faq-form button[type="submit"] {
  margin-top: 12px;
  margin-right: 8px;
}

.link-button {
  background: none;
  border: none;
  color: #0969da;
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
  font: inherit;
}

.inline-form {
  display: inline;
}

button {
  cursor: pointer;
}

.calendar-card {
  background: #fff;
  border-radius: 16px;
  padding: 18px 20px 22px;
  box-shadow: 0 4px 20px rgba(20, 24, 33, .06);
  border: 1px solid #eee;
}

.calendar-nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; }
.calendar-nav-title { font-size: 19px; font-weight: 800; letter-spacing: .01em; color: #222; }
.calendar-nav-today { font-size: 12px; font-weight: 700; color: #06c755; text-decoration: none; margin-left: 10px; }
.calendar-nav-btn {
  text-decoration: none; color: #444; font-size: 13px; font-weight: 700;
  padding: 6px 12px; border-radius: 999px; border: 1px solid #ddd; background: #fbfbfc;
  transition: background .15s;
}
.calendar-nav-btn:hover { background: #f1f2f4; }

.calendar-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px; }
.calendar-weekday {
  text-align: center; font-size: 11px; font-weight: 700; letter-spacing: .05em;
  color: #999; padding-bottom: 6px; text-transform: uppercase;
}
.calendar-weekday.weekend { color: #d34b4b; }
.calendar-day {
  min-width: 0;
  min-height: 116px;
  border-radius: 12px;
  background: #fbfbfc;
  border: 1px solid #eee;
  padding: 8px;
  display: flex;
  flex-direction: column;
  transition: box-shadow .15s;
}
.calendar-day:hover { box-shadow: 0 2px 10px rgba(20, 24, 33, .08); }
.calendar-day.outside { background: transparent; border-color: transparent; }
.calendar-day.has-schedule { background: linear-gradient(180deg, #f3fdf7, #eafaf0); border-color: #cdeedb; }
.calendar-day.today { border: 2px solid #06c755; box-shadow: 0 0 0 3px rgba(6, 199, 85, .1); }
.calendar-day-link { color: inherit; cursor: pointer; text-decoration: none; }
.calendar-day-link:focus-visible { outline: 3px solid rgba(6, 199, 85, .45); outline-offset: 2px; }
.calendar-day-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.calendar-day-num { font-size: 13px; font-weight: 600; color: #444; }
.calendar-day.today .calendar-day-num { color: #06c755; font-weight: 800; }
.calendar-day-list { display: flex; flex-direction: column; gap: 3px; overflow: hidden; }
.calendar-day-list-mobile { display: none; }
.calendar-day-entry {
  font-size: 11px;
  background: #fff;
  border: 1px solid #dcefe2;
  border-left: 3px solid #06c755;
  border-radius: 5px;
  padding: 2px 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.calendar-day-entry.hint { border-left-color: transparent; background: transparent; border-color: transparent; padding-left: 4px; }

.calendar-legend { display: flex; gap: 18px; margin-top: 16px; font-size: 12px; color: #888; }
.calendar-legend span { display: inline-flex; align-items: center; gap: 6px; }
.calendar-legend .dot { width: 9px; height: 9px; border-radius: 999px; display: inline-block; }
.calendar-legend .dot.today { background: #06c755; }
.calendar-legend .dot.busy { background: #cdeedb; border: 1px solid #9bd9b5; }

/* 行程表單日明細：桌面保留表格，手機改用唯讀卡片清單。 */
.schedule-day-mobile-list { display: none; }

/* 報修表單連結：桌面表格保留，手機以唯讀卡片呈現並保留重設操作。 */
#repair-form-tokens-mobile-list { display: none; }

.statistics-card {
  max-width: 820px;
  margin-top: 20px;
  border: 1px solid #d0d7de;
  border-radius: 10px;
  /* 同上：不能 overflow: hidden，會讓這層 wrapper 變成裡面 .statistics-table
     sticky 表頭的 scroll container，導致表頭捲動時完全不會固定。 */
}

.statistics-table {
  table-layout: auto;
}

/* 歷史週次改為直向延伸；捲動長表時保留欄名。 */
.statistics-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: #f6f8fa;
  box-shadow: 0 1px 0 #d0d7de;
}

.statistics-table th:first-child,
.statistics-table td:first-child {
  width: 34%;
}

.statistics-total td {
  background: #f6f8fa;
  font-weight: 700;
}

.statistics-week-heading th {
  padding: 9px 10px;
  background: #eaf3fc;
  color: #234b73;
  text-align: left;
  font-weight: 700;
}

/* 重複維修單：同一張維修單整組維持同色，下一組輪替，方便在長表格中辨識群組邊界。 */
.duplicate-group-0 td { background: #eefbf3; }
.duplicate-group-1 td { background: #eff6ff; }
.duplicate-group-2 td { background: #fff8e8; }
.duplicate-group-3 td { background: #fbf0f7; }

/* FAQ 管理手機版的 list／form 兩層畫面（見 faq.html／faq_mobile.js）。預設隱藏，
   只有進到下面的窄螢幕 @media 才顯示——這條規則刻意寫在 media query 外面、
   不寫成「桌面版另外覆寫成 none」，讓「桌面版絕對不會看到這個區塊」不依賴
   media query 的寬度判斷順序，本身就是預設值。 */
.faq-mobile {
  display: none;
}

/* 客服對話記錄手機版的卡片列表（見 history_list.html／history_mobile.js），
   同一個道理：預設隱藏，只有窄螢幕 @media 才顯示。 */
.history-mobile {
  display: none;
}

/* 工程對話記錄手機版的卡片列表（見 engineering_history_list.html／
   engineering_history_mobile.js），同一個道理：預設隱藏。 */
.engineering-history-mobile {
  display: none;
}

/* 水電／匯款回報紀錄手機版的卡片列表（見 utility_payment_reports.html／
   utility_payment_reports_mobile.js），同一個道理：預設隱藏。 */
.utility-payment-reports-mobile {
  display: none;
}

/* 客服狀況記錄手機版的卡片列表（見 customer_service_logs.html／
   customer_service_logs_mobile.js），同一個道理：預設隱藏。 */
.customer-service-logs-mobile {
  display: none;
}

/* 重複維修單手機版的卡片列表（見 customer_service_duplicate_repair_tickets.html／
   customer_service_duplicate_repair_tickets_mobile.js），同一個道理：預設隱藏。 */
.duplicate-repair-tickets-mobile {
  display: none;
}

/* 客服項目統計手機版的轉置表格（見 customer_service_log_statistics.html／
   customer_service_log_statistics_mobile.js），同一個道理：預設隱藏。 */
.customer-service-log-statistics-mobile {
  display: none;
}

/* 維修單列表手機版的卡片列表（見 repair_tickets_list.html／
   repair_tickets_mobile.js），同一個道理：預設隱藏。 */
.repair-tickets-mobile {
  display: none;
}

/* 工程團隊管理手機版單筆滑動刪除鈕：桌面版完全不用這個功能（維持勾選+批次
   刪除），這個欄位預設隱藏，只有窄螢幕 @media 才會顯示。 */
.delete-cell {
  display: none;
}

/* 2026-09-09 起加窄螢幕（手機）響應式規則。桌面版行為完全不變——以下規則全部包在
   @media (max-width: 768px) 裡，過了這個寬度視覺跟原本一模一樣。 */

/* 每個 <table> 都被 responsive.js 包了一層 .table-scroll（桌面寬度下這層沒有套用
   任何樣式，等於透明）。手機上刻意讓這層變成有邊框、自己捲動的框，不讓表格繼續用
   「整頁往下捲、表頭固定在畫面頂端」這招——這兩件事在 CSS 裡互斥（見下方說明），
   兩個做法二選一之後選了「表格自己是一個獨立捲動區塊，捲動時表頭固定在框頂」，
   讓長表格在窄螢幕上不會捲到後面忘記欄位是什麼。
   注意：不能只給 overflow-x，overflow-y 會被瀏覽器強制跟著變成 auto（CSS 規範：
   兩軸只要有一軸不是 visible，另一軸的 visible 會被算成 auto）——這正是這個網站
   之前踩過的坑（table { overflow: hidden } 讓 table 自己變成 sticky 表頭的捲動
   容器，導致表頭固定失效，見 2026-09-04 的修正記錄）。這裡乾脆兩軸都明確設定，
   讓 .table-scroll 正式變成一個有邊界高度的捲動容器，表頭改成相對這個容器固定
   （不是相對整個頁面），效果跟桌面版「捲頁面、頭固定在畫面頂」不同，但在窄螢幕
   上是必要的取捨。 */
@media (max-width: 768px) {
  body {
    padding: 16px;
  }

  .table-scroll {
    overflow: auto;
    max-height: 65vh;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    -webkit-overflow-scrolling: touch;
  }

  .table-scroll table {
    table-layout: auto;
    width: max-content;
    min-width: 100%;
    border: none;
    border-radius: 0;
  }

  .table-scroll th,
  .table-scroll td {
    white-space: nowrap;
  }

  /* 這些欄位本來就是為了長內容特別設定要換行/斷字，手機版維持原意，不要因為上面
     的 nowrap 規則被蓋掉變成看不到全部內容。 */
  .table-scroll .group-id-cell,
  .table-scroll .view-text,
  .table-scroll .chat-content,
  #customer-service-logs-table.public-readonly td,
  .utility-payment-reports-table td {
    white-space: normal;
  }

  /* 篩選列在手機上改成整欄堆疊、輸入框全寬、按鈕全寬好點——桌面版的橫向排列＋
     flex-wrap 在窄螢幕會擠成兩欄鋸齒狀，字都很小，觸控範圍也不夠大。 */
  .filter-bar {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }

  .filter-bar label {
    width: 100%;
  }

  .filter-bar input,
  .filter-bar select {
    width: 100%;
    min-width: 0;
    /* 16px 是刻意的：iOS Safari 對小於 16px 的 input 會在點擊時自動放大整頁面，
       體驗很差，這裡直接用不會觸發自動放大的字級。 */
    font-size: 16px;
    padding: 10px 12px;
  }

  .filter-bar button {
    width: 100%;
    padding: 11px 16px;
    font-size: 1rem;
  }

  .filter-bar > a {
    text-align: center;
  }

  /* 首頁分類原本橫向並排（一欄一個分類），手機版改直向堆疊，不然每欄只剩幾十
     像素寬，卡片上的照片跟文字都會被壓得無法辨識。
     align-items 也要一起覆寫：原本的 flex-start 是給「橫向排列、卡片各欄頂端
     對齊」用的，方向改成直向後同一個屬性意義完全不同（變成控制卡片要不要撐滿
     欄寬），沒蓋掉的話卡片會整個縮到只剩內容寬度，變成又窄又高的長條。 */
  .home-columns {
    flex-direction: column;
    align-items: stretch;
    gap: 20px;
  }

  /* 卡片高度只在手機版砍半（原本 163px 是桌面版量測值，維持不變）。改用另外
     裁切好的 --card-photo-mobile（見 home.html 的 card() macro，兩個圖網址都
     寫在同一個 style 屬性上，這裡再依螢幕寬度決定要用哪一個）——單純把
     background-image 兩層再宣告一次，第二層換成手機版圖，第一層的漸層淡化
     維持跟桌面版一致。 */
  .function-card {
    height: 82px;
  }

  .function-card-photo {
    background-image:
      linear-gradient(to right, var(--color-surface) 0%, rgba(255, 255, 255, .15) 45%, rgba(255, 255, 255, 0) 70%),
      var(--card-photo-mobile, var(--card-photo));
  }

  .function-card-title {
    padding: 6px 12px;
  }

  .function-card-title h2 {
    font-size: .85rem;
  }

  /* 說明文字面板本來是滑鼠 hover 才展開，手機上沒有 hover 這回事——完全不動作，
     是純粹沒用到的死狀態；某些手機瀏覽器碰到「整張卡片是連結、同時又監聽
     hover」還會把第一次點擊吃掉當成觸發 hover，要點第二次才真的跳轉連結。
     手機版乾脆整個關掉，卡片維持照片＋標題，點下去直接跳轉。 */
  .function-card:hover .function-card-hint,
  .function-card:focus-visible .function-card-hint {
    width: 0;
  }

  /* 七欄月曆在手機上優先保留行程的 HH:MM；縮的是留白與標籤內距，不縮字級。 */
  .calendar-card {
    padding: 12px 8px 14px;
    border-radius: 12px;
  }

  .calendar-nav {
    margin-bottom: 12px;
  }

  .calendar-day {
    min-height: 72px;
    padding: 2px;
    border-radius: 7px;
  }

  .calendar-grid {
    gap: 2px;
  }

  .calendar-day-header {
    margin-bottom: 3px;
  }

  .calendar-day-list {
    gap: 2px;
  }

  .calendar-day-entry {
    border-left-width: 2px;
    border-radius: 3px;
    padding: 2px 1px;
  }

  /* 月曆手機版限定顯示前兩筆行程，第三行摘要其餘筆數；桌面版維持前四筆。 */
  .calendar-day-list:not(.calendar-day-list-mobile) {
    display: none;
  }

  .calendar-day-list-mobile {
    display: flex;
  }

  .schedule-day-desktop-table-wrap {
    overflow: visible;
  }

  #schedule-day-desktop-table {
    display: none;
  }

  .schedule-day-mobile-list {
    display: grid;
    gap: 10px;
  }

  .schedule-day-mobile-card {
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
  }

  .schedule-day-mobile-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    background: #f3fdf7;
  }

  .schedule-day-mobile-status {
    flex: none;
    padding: 3px 9px;
    border: 1px solid #9bd9b5;
    border-radius: 999px;
    color: #167a3f;
    font-size: .78rem;
  }

  .schedule-day-mobile-field {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    min-height: 42px;
    padding: 8px 14px;
  }

  .schedule-day-mobile-field + .schedule-day-mobile-field {
    border-top: 1px solid var(--color-border);
  }

  .schedule-day-mobile-label {
    flex: 0 0 64px;
    padding-top: 2px;
    color: var(--color-text-muted);
    font-size: .8rem;
  }

  .schedule-day-mobile-value {
    min-width: 0;
    flex: 1;
    overflow-wrap: anywhere;
  }

  .schedule-day-mobile-empty {
    margin: 0;
    padding: 16px;
    text-align: center;
  }

  #repair-form-tokens-table {
    display: none;
  }

  #repair-form-tokens-mobile-list {
    display: grid;
    gap: 10px;
  }

  .repair-form-tokens-mobile-card {
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
  }

  .repair-form-tokens-mobile-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    background: #f3fdf7;
  }

  .repair-form-tokens-mobile-card-head strong {
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .repair-form-tokens-mobile-status {
    flex: none;
    padding: 3px 9px;
    border: 1px solid #9bd9b5;
    border-radius: 999px;
    color: #167a3f;
    font-size: .78rem;
  }

  .repair-form-tokens-mobile-field {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    min-height: 42px;
    padding: 8px 14px;
  }

  .repair-form-tokens-mobile-field + .repair-form-tokens-mobile-field,
  .repair-form-tokens-mobile-actions {
    border-top: 1px solid var(--color-border);
  }

  .repair-form-tokens-mobile-label {
    flex: 0 0 72px;
    padding-top: 2px;
    color: var(--color-text-muted);
    font-size: .8rem;
  }

  .repair-form-tokens-mobile-value {
    min-width: 0;
    flex: 1;
    overflow-wrap: anywhere;
  }

  .repair-form-tokens-mobile-actions {
    display: flex;
    justify-content: flex-end;
    padding: 10px 14px;
  }

  .repair-form-tokens-mobile-empty {
    margin: 0;
    padding: 16px;
    text-align: center;
  }

  #manual-create-result input {
    width: calc(100% - 72px) !important;
  }

  /* FAQ 管理手機版：Odoo 風格的 list／form。#faq-form 是桌面版整個表格＋
     新增列／刪除選取項目按鈕的容器（id 只有這頁在用），手機版直接藏起來，
     改顯示 .faq-mobile 這個獨立的卡片列表／單筆詳情畫面（見 faq_mobile.js，
     資料直接讀藏起來的桌面版 <table>，不重複要一次資料）。 */
  #faq-form {
    display: none;
  }

  /* 手機版不需要「每頁筆數」／換頁列，改用捲到底自動載入下一批（見
     faq_mobile.js 的 IntersectionObserver）。#faq-pager 只有 FAQ 這頁在用這個
     id，不影響其他頁面沿用 .pager class 的一般換頁列。
     選擇器故意寫 .filter-bar .desktop-only-field（兩個 class）而不是單一
     class：基礎規則 .filter-bar label 的 specificity 是 (0,1,1)，單一 class
     的 .desktop-only-field 只有 (0,1,0)，比不過會被蓋掉，要疊高一個 class
     才贏得過。 */
  .filter-bar .desktop-only-field,
  #faq-pager,
  #history-desktop-table,
  #history-pager,
  #engineering-history-desktop-table,
  #utility-payment-reports-desktop-table,
  #customer-service-logs-desktop-table,
  #duplicate-repair-tickets-desktop-table,
  #customer-service-log-statistics-desktop-table,
  #repair-tickets-desktop-table {
    display: none;
  }

  .faq-mobile {
    display: block;
  }

  /* faq_mobile.js 用 `.hidden = true/false` 切換 list／form 顯示；瀏覽器對
     [hidden] 屬性的預設 `display: none` 是 UA 樣式，優先權低於任何一般作者
     樣式，所以下面這行 `display: flex` 光靠一般 specificity 規則就會贏過
     [hidden]，導致「隱藏」完全沒作用。要靠 .faq-mobile-list[hidden] 這條規則
     明確蓋掉才會真的隱藏（見下面）。 */
  .faq-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .faq-mobile-list[hidden],
  .faq-mobile-form[hidden] {
    display: none;
  }

  /* 進到單筆詳情（form view）時，faq_mobile.js 會把篩選列也設成 hidden——
     `.filter-bar` 有自己的 `display: flex`（給桌面版橫向排列用），一樣要靠
     [hidden] 版本明確蓋掉才會真的消失，原因跟上面 .faq-mobile-list 一樣。
     只在 #faq-filter-bar 這個 id 生效，不影響其他頁面的 .filter-bar。 */
  #faq-filter-bar[hidden] {
    display: none;
  }

  .faq-mobile-card {
    display: block;
    width: 100%;
    text-align: left;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 12px 14px;
    font: inherit;
    color: inherit;
    cursor: pointer;
  }

  .faq-mobile-card:hover,
  .faq-mobile-card:focus-visible {
    border-color: var(--color-primary);
  }

  .faq-mobile-card-no {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: .72rem;
    font-weight: 700;
    color: var(--color-primary);
    margin-bottom: 6px;
  }

  .faq-mobile-card-row {
    display: flex;
    gap: 8px;
    padding: 3px 0;
    font-size: .88rem;
  }

  .faq-mobile-card-row .k {
    flex: 0 0 68px;
    color: var(--color-text-muted);
    font-weight: 600;
  }

  .faq-mobile-card-row .v {
    flex: 1;
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .faq-mobile-loading {
    text-align: center;
    margin: 10px 0;
  }

  #faq-mobile-sentinel {
    height: 1px;
  }

  .faq-mobile-add-btn {
    display: block;
    width: 100%;
    margin-top: 12px;
    padding: 12px 16px;
    border: 1px dashed var(--color-primary);
    border-radius: var(--radius-md);
    background: var(--color-primary-tint);
    color: var(--color-primary);
    font-weight: 700;
    font-size: 1rem;
  }

  .faq-mobile-add-btn[hidden] {
    display: none;
  }

  /* 單筆詳情（Odoo 的「form view」）：跟卡片列表同一個容器互斥顯示，
     由 faq_mobile.js 切換 hidden 屬性。 */
  .faq-mobile-form {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 14px 16px;
  }

  .faq-mobile-back-btn {
    background: none;
    border: none;
    color: var(--color-primary);
    font-weight: 700;
    font-size: .92rem;
    padding: 0 0 12px;
    cursor: pointer;
  }

  .faq-mobile-field {
    margin-bottom: 14px;
  }

  .faq-mobile-field label {
    display: block;
    font-size: .78rem;
    font-weight: 700;
    color: var(--color-text-muted);
    margin-bottom: 4px;
  }

  .faq-mobile-field .view-text {
    white-space: pre-wrap;
    word-break: break-word;
    min-height: 1.4em;
  }

  .faq-mobile-field .edit-input {
    display: block;
    width: 100%;
    min-height: 4.5em;
    resize: none;
    overflow: hidden;
    font: inherit;
    font-size: 16px;
    border: 1px solid var(--color-primary);
    border-radius: 6px;
    padding: 6px 8px;
  }

  .faq-mobile-field-readonly .view-text {
    color: var(--color-text-muted);
    font-size: .88rem;
  }

  .faq-mobile-form-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 8px;
  }

  .faq-mobile-form-actions button {
    flex: 1 1 auto;
    padding: 10px 14px;
    font-size: .92rem;
  }

  .faq-mobile-form-actions .delete-btn {
    background: #ffebe9;
    border: 1px solid #ffb3ac;
    color: #cf222e;
    border-radius: 6px;
  }

  /* 客服對話記錄手機版：只有卡片列表，沒有單筆詳情頁（跟 FAQ 管理不同）。
     「角色」欄故意不獨立顯示文字，改用卡片底色表示——user 淡綠、assistant
     粉黃，先用這組配色，使用者確認不喜歡再換。 */
  .history-mobile {
    display: block;
  }

  .history-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .history-mobile-card {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 12px 14px;
    /* 預設（角色不明時）中性色，不誤導成 user 或 assistant 任一邊。 */
    background: var(--color-surface);
  }

  .history-mobile-card.role-user {
    background: #eaf7ec;
    border-color: #bfe3c4;
  }

  .history-mobile-card.role-assistant {
    background: #fff8de;
    border-color: #ecdf9e;
  }

  .history-mobile-card-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
  }

  .history-mobile-card-who {
    font-weight: 700;
    color: var(--color-text);
    text-decoration: none;
    overflow-wrap: anywhere;
  }

  .history-mobile-card-time {
    flex: none;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: .72rem;
    color: var(--color-text-muted);
  }

  .history-mobile-card-sub {
    font-size: .76rem;
    color: var(--color-text-muted);
    margin-top: 2px;
    overflow-wrap: anywhere;
  }

  .history-mobile-refresh-btn {
    display: inline-block;
    margin-top: 4px;
    font-size: .76rem;
  }

  .history-mobile-card-body {
    margin-top: 8px;
  }

  .history-mobile-card-body .chat-content {
    font-size: .9rem;
  }

  .history-mobile-loading {
    text-align: center;
    margin: 10px 0;
  }

  #history-mobile-sentinel {
    height: 1px;
  }

  /* 工程對話記錄手機版：欄位少，全部直接上卡片，沒有詳情頁也不用分頁。 */
  .engineering-history-mobile {
    display: block;
  }

  .engineering-history-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .engineering-history-mobile-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 12px 14px;
  }

  .engineering-history-mobile-card-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
  }

  .engineering-history-mobile-card-sender {
    font-weight: 700;
    color: var(--color-text);
  }

  .engineering-history-mobile-card-time {
    flex: none;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: .72rem;
    color: var(--color-text-muted);
  }

  .engineering-history-mobile-card-group {
    font-size: .76rem;
    color: var(--color-text-muted);
    margin-top: 2px;
    overflow-wrap: anywhere;
    word-break: break-all;
  }

  .engineering-history-mobile-card-body {
    margin-top: 8px;
  }

  .engineering-history-mobile-card-body .chat-content {
    font-size: .9rem;
  }

  /* 水電／匯款回報紀錄手機版：欄位少，全部直接上卡片，沒有詳情頁也不用分頁
     （沿用工程對話記錄同一套模式）。 */
  .utility-payment-reports-mobile {
    display: block;
  }

  .utility-payment-reports-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .utility-payment-reports-mobile-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 12px 14px;
  }

  .utility-payment-reports-mobile-card-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
  }

  .utility-payment-reports-mobile-card-name {
    font-weight: 700;
    color: var(--color-text);
  }

  .utility-payment-reports-mobile-card-time {
    flex: none;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: .72rem;
    color: var(--color-text-muted);
  }

  .utility-payment-reports-mobile-card-line-id {
    font-size: .76rem;
    color: var(--color-text-muted);
    margin-top: 2px;
    overflow-wrap: anywhere;
    word-break: break-all;
  }

  .utility-payment-reports-mobile-card-readings {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 8px;
  }

  .utility-payment-reports-mobile-card-reading {
    display: flex;
    flex-direction: column;
    background: var(--color-surface-muted, #f4f5f7);
    border-radius: var(--radius-sm, 6px);
    padding: 4px 10px;
  }

  .utility-payment-reports-mobile-card-reading-label {
    font-size: .68rem;
    color: var(--color-text-muted);
  }

  .utility-payment-reports-mobile-card-reading-value {
    font-weight: 700;
  }

  .utility-payment-reports-mobile-card-source {
    margin-top: 8px;
    font-size: .9rem;
  }

  .utility-payment-reports-mobile-card-source .chat-content {
    font-size: .9rem;
  }

  .utility-payment-reports-mobile-card-foot {
    /* 租戶編號跟徽章改成各自獨立一行（不再共用一個 flex row）——曾經試過在同一行用
       flex:1/min-width:0 讓文字項目撐滿可用寬度，但實測在手機上換行位置依然不對
       （UUID 只有最後幾碼被硬換到第二行、第一行卻還有大片空白），换行判斷背後的
       實際成因沒有把握完全查清楚，與其繼續在 flex 版面細節裡猜，不如直接讓租戶編號
       跟卡片裡運作正常的 LineID 那行一樣，用純 block 元素天生撐滿卡片全寬，
       結構上就不會再有「跟旁邊項目搶寬度」這個問題。 */
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    font-size: .76rem;
    color: var(--color-text-muted);
  }

  .utility-payment-reports-mobile-card-sync-id {
    display: block;
    width: 100%;
    overflow-wrap: anywhere;
    word-break: break-all;
  }

  /* 客服狀況記錄手機版：先做唯讀卡片列表，欄位跟桌面版一樣直接讀藏起來的表格，
     沒有新增/編輯/刪除的手機版互動。 */
  .customer-service-logs-mobile {
    display: block;
  }

  .customer-service-logs-mobile-list,
  .customer-service-logs-mobile-form {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  /* customer_service_logs_mobile.js 用 `.hidden = true/false` 切換 list／form
     顯示；瀏覽器對 [hidden] 屬性的預設 `display: none` 是 UA 樣式，優先權低於
     上面這兩個 class 自己宣告的 `display: flex`，要靠這條規則明確蓋掉才會真的
     隱藏（跟 FAQ 管理手機版 .faq-mobile-list[hidden] 同一個道理）。 */
  .customer-service-logs-mobile-list[hidden],
  .customer-service-logs-mobile-form[hidden] {
    display: none;
  }

  /* 進到單一筆詳情（form view）時，篩選列跟這張卡片無關，會被 JS 設成
     hidden——`.filter-bar` 有自己的 `display: flex`，一樣要靠 [hidden] 版本
     明確蓋掉才會真的消失，原因同上。只在這個 id 生效，不影響其他頁面的
     .filter-bar。 */
  #processed-date-filter[hidden] {
    display: none;
  }

  .customer-service-logs-mobile-back-btn {
    align-self: flex-start;
    padding: 7px 14px;
    border: 1px solid #0969da;
    border-radius: var(--radius-md);
    background: #fff;
    color: #0969da;
    font-weight: 600;
    font-size: .88rem;
  }

  .customer-service-logs-mobile-card,
  .customer-service-logs-mobile-list-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 12px 14px;
  }

  .customer-service-logs-mobile-list-card {
    display: block;
    width: 100%;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
  }

  .customer-service-logs-mobile-list-card:hover,
  .customer-service-logs-mobile-list-card:focus-visible {
    border-color: #0969da;
  }

  .customer-service-logs-mobile-card-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
  }

  .customer-service-logs-mobile-card-head-right {
    display: flex;
    align-items: center;
    gap: 6px;
  }

  .customer-service-logs-mobile-card-case-no {
    font-weight: 700;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    color: var(--color-text);
  }

  /* 客訴類型放在待處理/已處理左邊，字級比狀態徽章（.85rem）小一階、用框線圍住，
     跟按鈕同一種藍（#0969da）呼應下面問題簡述/回覆的框線風格。 */
  .customer-service-logs-mobile-card-complaint-type {
    display: inline-block;
    padding: 3px 9px;
    border: 1px solid #0969da;
    border-radius: 999px;
    font-size: .76rem;
    font-weight: 600;
    color: #0969da;
    line-height: 1.3;
  }

  .customer-service-logs-mobile-card-body {
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .customer-service-logs-mobile-card-field-label {
    font-size: .68rem;
    color: var(--color-text-muted);
  }

  .customer-service-logs-mobile-card-field-value {
    font-size: .9rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
  }

  /* 問題時間／處理時間不顯示欄名、字級比一般欄位值小一階、靠右對齊，省版面。 */
  .customer-service-logs-mobile-card-field-time {
    font-size: .8rem;
    text-align: right;
  }

  /* 問題簡述＋問題時間、回覆＋處理時間分別框成一個圓角方框，框線把兩組內容
     跟卡片其他部分（群組/租客、卡片邊界）隔開；框線顏色跟按鈕同一種藍
     （#0969da，見 .filter-bar button），比預設的淺灰邊框深，跟客訴類型徽章
     的框線色一致。 */
  .customer-service-logs-mobile-card-group {
    border: 1px solid #0969da;
    border-radius: var(--radius-md);
    padding: 8px 10px;
    display: flex;
    flex-direction: column;
    gap: 4px;
  }

  /* form 卡片欄位裡的 .edit-input 是直接複製桌面版節點過來的，桌面版
     input/textarea 是給寬表格欄位用的尺寸，手機版要撐滿卡片寬度才好操作。 */
  .customer-service-logs-mobile-card-field .edit-input {
    width: 100%;
    box-sizing: border-box;
    font: inherit;
  }

  .customer-service-logs-mobile-form-actions {
    margin-top: 12px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
  }

  /* 刪除是破壞性操作，靠右擺、用跟 .status-failed 同一組警示色區隔，避免
     跟旁邊的編輯/儲存/放棄按鈕混在一起太容易誤按。 */
  .customer-service-logs-mobile-form-actions .delete-btn {
    margin-left: auto;
    color: #cf222e;
    border: 1px solid #ffb3ac;
    background: #fff;
    border-radius: var(--radius-md);
    padding: 7px 14px;
  }

  /* 重複維修單手機版：Odoo 風格 list／form 兩層畫面。list 卡片是摘要（一組
     維修單號一張），點進去才看到 form 卡片（組內每筆客訴編號各自一個子區塊，
     子區塊之間用上框線隔開）。 */
  .duplicate-repair-tickets-mobile {
    display: block;
  }

  .duplicate-repair-tickets-mobile-list,
  .duplicate-repair-tickets-mobile-form {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  /* customer_service_duplicate_repair_tickets_mobile.js 用 `.hidden = true/false`
     切換 list／form 顯示；瀏覽器對 [hidden] 屬性的預設 `display: none` 是 UA
     樣式，優先權低於上面這兩個 class 自己宣告的 `display: flex`，要靠這條規則
     明確蓋掉才會真的隱藏（跟 FAQ 管理手機版 .faq-mobile-list[hidden] 同一個
     道理）。個別 form 卡片（.duplicate-repair-tickets-mobile-card）沒有自己宣告
     display，不受這個問題影響，不需要另外的 [hidden] 覆寫規則。 */
  .duplicate-repair-tickets-mobile-list[hidden],
  .duplicate-repair-tickets-mobile-form[hidden] {
    display: none;
  }

  /* 進到單一維修單號的詳情（form view）時，篩選列跟這張卡片無關，會被 JS 設成
     hidden——`.filter-bar` 有自己的 `display: flex`，一樣要靠 [hidden] 版本
     明確蓋掉才會真的消失，原因同上。只在這個 id 生效，不影響其他頁面的
     .filter-bar（跟 FAQ 管理手機版 #faq-filter-bar[hidden] 同一個道理）。 */
  #duplicate-repair-tickets-filter-bar[hidden] {
    display: none;
  }

  .duplicate-repair-tickets-mobile-back-btn {
    align-self: flex-start;
    padding: 7px 14px;
    border: 1px solid #0969da;
    border-radius: var(--radius-md);
    background: #fff;
    color: #0969da;
    font-weight: 600;
    font-size: .88rem;
  }

  .duplicate-repair-tickets-mobile-list-card {
    display: block;
    width: 100%;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
    padding: 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
  }

  .duplicate-repair-tickets-mobile-list-card:hover,
  .duplicate-repair-tickets-mobile-list-card:focus-visible {
    border-color: #0969da;
  }

  .duplicate-repair-tickets-mobile-list-card-summary {
    padding: 10px 14px;
    border-bottom: 1px solid var(--color-border);
  }

  /* 群組/租客在 list 卡片不加欄名，直接黑體明顯顯示（取組內問題時間最晚那筆
     的值），跟底下有欄名的「預計處理方式」做出視覺上的主副之分。 */
  .duplicate-repair-tickets-mobile-list-card-group {
    font-weight: 700;
    font-size: .95rem;
    color: var(--color-text);
  }

  .duplicate-repair-tickets-mobile-list-card-summary .duplicate-repair-tickets-mobile-entry-field {
    margin-top: 8px;
  }

  .duplicate-repair-tickets-mobile-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
  }

  /* 卡頭是這張卡片代表的維修單號本身，用跟按鈕同一種藍當底色強調「這是分組
     依據」，跟底下客訴編號子區塊的白底做出層次區隔。 */
  .duplicate-repair-tickets-mobile-card-head {
    background: #0969da;
    color: #fff;
    font-weight: 700;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    padding: 8px 14px;
  }

  .duplicate-repair-tickets-mobile-entry {
    padding: 10px 14px;
  }

  .duplicate-repair-tickets-mobile-entry + .duplicate-repair-tickets-mobile-entry {
    border-top: 1px solid var(--color-border);
  }

  .duplicate-repair-tickets-mobile-entry-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
  }

  .duplicate-repair-tickets-mobile-entry-case-no {
    font-weight: 700;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    color: var(--color-text);
  }

  .duplicate-repair-tickets-mobile-entry-field {
    margin-top: 6px;
  }

  .duplicate-repair-tickets-mobile-entry-field-label {
    font-size: .68rem;
    color: var(--color-text-muted);
  }

  .duplicate-repair-tickets-mobile-entry-field-value {
    font-size: .9rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
  }

  .duplicate-repair-tickets-mobile-entry-time {
    margin-top: 4px;
    font-size: .8rem;
    text-align: right;
  }

  .duplicate-repair-tickets-mobile-entry-planned {
    margin-top: 8px;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 8px;
  }

  .duplicate-repair-tickets-mobile-entry-planned .planned-action-btn {
    flex: none;
  }

  /* 客服項目統計手機版：桌面版是「列＝週次、欄＝客訴類型」，手機版轉置成
     「列＝客訴類型、欄＝週次」，並凍結最左欄（客訴類型名稱）——橫向捲動很多
     週次時，仍看得到目前這一列是哪個類型。 */
  .customer-service-log-statistics-mobile {
    display: block;
  }

  .customer-service-log-statistics-mobile-table {
    width: max-content;
    min-width: 100%;
  }

  /* 最左欄（客訴類型名稱）用 sticky 固定在捲動容器左側；.table-scroll 是
     responsive.js 自動包上去的捲動容器（見該檔案說明）。z-index 需要比一般
     內容高，背景要不透明，不然橫向捲動時右側內容會透到底下。表頭那一格
     （thead 的 th:first-child）同時要固定在頂端跟左側兩個方向，z-index 再疊高
     一階蓋過純左側固定的其他列。 */
  .customer-service-log-statistics-mobile-table th:first-child,
  .customer-service-log-statistics-mobile-table td:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--color-surface);
    border-right: 1px solid var(--color-border);
    width: auto;
    white-space: nowrap;
  }

  .customer-service-log-statistics-mobile-table thead th:first-child {
    z-index: 3;
    background: #f6f8fa;
  }

  /* 「每週總和」那一列（轉置後排在最後一列）整列加粗跟淺底色，呼應桌面版
     .statistics-total 的視覺重量。 */
  .customer-service-log-statistics-mobile-table .statistics-mobile-total-row td {
    background: #f6f8fa;
    font-weight: 700;
  }

  /* 「全部歷史總和」那一週（轉置後排在最後一欄）整欄加粗跟淺底色，呼應桌面版
     那一列 tr.statistics-total 的視覺重量——這裡只套在單一欄的每個儲存格，
     不是整列，所以另外用一個 class 而不是沿用 .statistics-total（tr 層級）。 */
  .customer-service-log-statistics-mobile-table .statistics-mobile-total-col {
    background: #f6f8fa;
    font-weight: 700;
  }

  /* 維修單列表手機版：先做唯讀卡片列表，欄位跟桌面版一樣直接讀藏起來的表格。 */
  .repair-tickets-mobile {
    display: block;
  }

  .repair-tickets-mobile-list,
  .repair-tickets-mobile-form {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  /* repair_tickets_mobile.js 用 `.hidden = true/false` 切換 list／form 顯示；
     瀏覽器對 [hidden] 屬性的預設 `display: none` 是 UA 樣式，優先權低於上面
     這兩個 class 自己宣告的 `display: flex`，要靠這條規則明確蓋掉才會真的
     隱藏（跟其他頁面的 list/form 兩層畫面同一個道理）。個別 form 卡片
     （.repair-tickets-mobile-card）沒有自己宣告 display，不受這個問題影響。 */
  .repair-tickets-mobile-list[hidden],
  .repair-tickets-mobile-form[hidden] {
    display: none;
  }

  /* 進到單一筆詳情（form view）時，篩選列跟這張卡片無關，會被 JS 設成
     hidden——`.filter-bar` 有自己的 `display: flex`，一樣要靠 [hidden] 版本
     明確蓋掉才會真的消失，原因同上。只在這個 id 生效，不影響其他頁面的
     .filter-bar。 */
  #repair-tickets-filter-bar[hidden] {
    display: none;
  }

  .repair-tickets-mobile-back-btn {
    align-self: flex-start;
    padding: 7px 14px;
    border: 1px solid #0969da;
    border-radius: var(--radius-md);
    background: #fff;
    color: #0969da;
    font-weight: 600;
    font-size: .88rem;
  }

  .repair-tickets-mobile-card,
  .repair-tickets-mobile-list-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 12px 14px;
  }

  .repair-tickets-mobile-list-card {
    display: block;
    width: 100%;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
  }

  .repair-tickets-mobile-list-card:hover,
  .repair-tickets-mobile-list-card:focus-visible {
    border-color: #0969da;
  }

  .repair-tickets-mobile-card-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
  }

  .repair-tickets-mobile-card-ticket-no {
    font-weight: 700;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    color: var(--color-text);
  }

  .repair-tickets-mobile-card-status {
    flex: none;
    padding: 3px 9px;
    border: 1px solid #0969da;
    border-radius: 999px;
    font-size: .76rem;
    font-weight: 600;
    color: #0969da;
    line-height: 1.3;
  }

  .repair-tickets-mobile-card-body {
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .repair-tickets-mobile-card-field-label {
    font-size: .68rem;
    color: var(--color-text-muted);
  }

  .repair-tickets-mobile-card-field-value {
    font-size: .9rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
  }

  /* form 卡片欄位裡的 .edit-input 是直接複製桌面版節點過來的，撐滿卡片寬度
     才好操作（跟客服狀況記錄手機版同一個道理）。 */
  .repair-tickets-mobile-card-field .edit-input {
    width: 100%;
    box-sizing: border-box;
    font: inherit;
  }

  .repair-tickets-mobile-form-actions {
    margin-top: 12px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
  }

  /* 刪除是破壞性操作（真的從資料庫刪除，不是改狀態），靠右擺、用跟
     .status-failed 同一組警示色區隔，避免跟旁邊的編輯/儲存/放棄按鈕混在
     一起太容易誤按。 */
  .repair-tickets-mobile-form-actions .delete-btn {
    margin-left: auto;
    color: #cf222e;
    border: 1px solid #ffb3ac;
    background: #fff;
    border-radius: var(--radius-md);
    padding: 7px 14px;
  }

  /* list 卡片（摘要）沿用桌面版的小縮圖尺寸即可，不需要放大——大圖留給之後
     要做的 form 詳情卡片。非圖片格式（影片等）還是純文字連結，跟桌面版一樣
     不內嵌播放器。
     white-space 一定要蓋回 normal：這個容器是從桌面版 .rt-photos-cell 直接
     複製 <a> 節點過來的，Jinja 樣板 {% for %} 迴圈之間留下的換行/縮排空白
     文字節點也會一起被複製進來；共用的 .repair-tickets-mobile-card-field-value
     設了 white-space: pre-wrap（給問題簡述那類需要保留換行的文字用），這裡如果
     不蓋掉，那些空白文字節點的換行會被真的渲染出來，變成縮圖之間看起來間隔
     異常大的空白。 */
  .repair-tickets-mobile-card-photos {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    white-space: normal;
  }

  /* form 卡片的報修/完工照片改用大圖（手機是卡片，沒有表格列被拉長的問題），
     蓋掉縮圖固定 48x48 的尺寸，改成撐滿卡片寬度、依序往下堆疊；影片圖示維持
     原尺寸置中，不需要放大成方塊。 */
  .repair-tickets-mobile-card-photos-large {
    flex-direction: column;
  }

  .repair-tickets-mobile-card-photos-large .rt-photo-thumb {
    width: 100%;
    height: auto;
    object-fit: contain;
    border-radius: var(--radius-md);
  }

  /* 工程團隊管理手機版：欄位少，且需要保留編輯/儲存/放棄——不做另一份唯讀
     卡片列表，改成純 CSS 把「同一份」表格轉成卡片外觀，DOM 跟 engineering_
     team.js 的編輯/儲存/放棄/新增/批次刪除邏輯完全共用。表頭視覺上隱藏（用
     裁掉尺寸的方式而不是 display:none，螢幕報讀器仍讀得到欄名），每個 td
     前面用 data-label 顯示欄名，跟原本「橫向捲動很寬的表格」互斥，這裡選
     擇卡片外觀，不需要 .table-scroll 的橫向捲動行為，一併覆寫蓋掉。 */
  #engineering-team-table,
  #engineering-team-table tbody,
  #engineering-team-table tr {
    display: block;
    width: 100%;
  }

  #engineering-team-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  #engineering-team-table tbody tr {
    position: relative;
    overflow: hidden;
    margin-bottom: 10px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
  }

  #engineering-team-table tbody tr.empty-row {
    background: none;
    border: none;
    box-shadow: none;
  }

  /* 內距改放在每個 td 上（原本放在 tr 身上）——這樣 tr 的框就是它真正看得到
     的邊界，刪除鈕（.delete-cell）才能用單純的 top:0/right:0/bottom:0 對齊
     這個邊界，不需要用負值把自己撐出 tr 的內距範圍。曾經試過負值撐出去的
     寫法，實測 `overflow: hidden` 在 `<tr>`（即使用 `display:block` 蓋過）上
     對「超出邊界的負位移子元素」裁切不可靠，滑動時卡片外還是看得到刪除鈕
     的紅色矩形，這是已經踩過的坑，不要再用負值定位。 */
  #engineering-team-table td {
    position: relative;
    z-index: 1;
    background: var(--color-surface);
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px 14px;
    border: none;
    white-space: normal;
    /* 平常（沒有滑開）就先往左偏移 3%，讓刪除鈕的紅色邊緣稍微露出來一點，
       當作「這張卡片可以滑動」的提示；滑開時蓋成 -25%（見 .et-swiped 那條
       規則，specificity 比這裡高）。 */
    transform: translateX(-3%);
    transition: transform .2s ease;
  }

  /* 刪除鈕本身要固定貼齊右邊界，不能被上面那條 td 的通用位移規則帶著跑。 */
  #engineering-team-table td.delete-cell {
    transform: none;
  }

  #engineering-team-table td + td {
    border-top: 1px solid var(--color-border);
  }

  #engineering-team-table td::before {
    content: attr(data-label);
    flex: 0 0 84px;
    font-size: .76rem;
    color: var(--color-text-muted);
    padding-top: 2px;
  }

  /* 選取用的核取方塊、操作按鈕不需要欄名，蓋掉 ::before。 */
  #engineering-team-table td.center:first-child::before,
  #engineering-team-table td.actions-cell::before {
    content: none;
  }

  #engineering-team-table td.actions-cell {
    justify-content: flex-end;
    flex-wrap: wrap;
    /* 這是卡片最後一列，左下角要跟卡片本身的圓角對齊——直接在這個 td 自己
       的背景上套圓角，不要指望 tr 的 overflow:hidden 幫忙裁切。實測 tr 上的
       overflow:hidden＋border-radius 對底部兩個角裁切不乾淨（會看到方形直角
       凸出來，跟撐出負值邊界那次是同一種「不可靠」但不同觸發情境），乾脆
       每個真正貼在卡片四個角落的元素都自己直接套圓角，不依賴任何祖先層的
       裁切。 */
    border-bottom-left-radius: var(--radius-md);
  }

  /* 手機版單筆滑動刪除，取代原本的勾選欄＋全域「刪除選取項目」（桌面版
     維持原樣不變）。 */

  /* 勾選欄整個藏起來——不是只藏欄名，這欄手機版完全不需要。桌面版桌面版
     維持原本用勾選+批次刪除操作。 */
  #engineering-team-table td.center:first-child {
    display: none;
  }

  /* 勾選欄隱藏後，緊接在它後面的姓名欄變成視覺上的第一欄，但 CSS 的
     `td + td` 選擇器判斷「有沒有上一個手足元素」不看 display，勾選欄雖然
     不顯示、在 DOM 上仍然存在，姓名欄還是會被那條規則加上不該有的上框線，
     這裡用比 `td + td` 更高的 specificity（多疊一個 class）蓋掉。 */
  #engineering-team-table td:first-child + td {
    border-top: none;
    /* 這是卡片第一列（勾選欄隱藏後視覺上的第一欄），左上角要跟卡片本身的
       圓角對齊，原因跟 .actions-cell 的 border-bottom-left-radius 一樣：
       直接在這個 td 自己的背景套圓角，不依賴 tr 的 overflow:hidden 裁切。 */
    border-top-left-radius: var(--radius-md);
  }

  #bulk-delete-btn {
    display: none;
  }

  /* 刪除鈕貼在卡片右側、寬度 25%，z-index 比其他欄位低——平常被前面欄位的
     不透明背景蓋住看不到，只有 tr 加上 .et-swiped（見
     engineering_team_swipe.js）讓其他欄位一起往左滑出 25% 寬度後，才會從
     右側露出來。top/right/bottom 現在對齊 tr 自己的邊界（tr 的內距已經改放
     到每個 td 上，tr 本身 padding:0，見上面），右側兩個角套一樣的圓角＋
     overflow:hidden 讓刪除鈕跟卡片本身的圓角邊界對齊。
     這裡刻意不用負值把這塊撐出 tr 的範圍——實測 `overflow: hidden` 在
     `<tr>`（即使用 `display:block` 蓋過）上對「超出邊界的負位移子元素」
     裁切不可靠，滑動時卡片外還是看得到刪除鈕的紅色矩形，是踩過的坑。 */
  #engineering-team-table td.delete-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 25%;
    z-index: 0;
    border-top: none;
    padding: 0;
    overflow: hidden;
    border-top-right-radius: var(--radius-md);
    border-bottom-right-radius: var(--radius-md);
  }

  #engineering-team-table td.delete-cell::before {
    content: none;
  }

  #engineering-team-table tbody tr.et-swiped td:not(.delete-cell) {
    transform: translateX(-25%);
  }

  .et-delete-btn {
    width: 100%;
    height: 100%;
    border: none;
    background: #cf222e;
    color: #fff;
    font-weight: 700;
    font-size: .85rem;
    /* 右上/右下角要跟卡片本身的圓角對齊，直接套在按鈕自己身上——不要指望
       .delete-cell 的 overflow:hidden 幫忙裁切成圓角，原因見上面 .actions-cell
       的註解，同一個坑，這裡索性都改成每個角自己負責。 */
    border-top-right-radius: var(--radius-md);
    border-bottom-right-radius: var(--radius-md);
  }
}

/* Must follow the legacy table-to-card rules above: hide that implementation
   completely once the dedicated mobile-card markup is available. */
@media (max-width: 768px) {
  #engineering-team-form #engineering-team-table {
    display: none;
  }

  #engineering-team-form #engineering-team-mobile-list {
    display: grid;
  }
}

/* 客戶資料：手機端採獨立 list 卡片，桌面 table 繼續保留。 */
#customers-mobile-list {
  display: none;
}

@media (max-width: 768px) {
  #customers-form #customers-table,
  #customers-form #bulk-delete-btn {
    display: none;
  }

  #customers-mobile-list {
    display: grid;
    gap: 10px;
  }

  .customers-mobile-card {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    background: #cf222e;
  }

  .customers-mobile-card-content {
    position: relative;
    z-index: 1;
    background: var(--color-surface);
    /* 比照工程團隊範本：資料層左移露出 3% 紅邊，內容再反向補償。 */
    transform: translateX(-3%);
    transition: transform .2s ease;
  }

  .customers-mobile-card-swiped .customers-mobile-card-content {
    transform: translateX(-25%);
  }

  /* 文字、輸入框和按鈕在閉合時維持原本相對位置；欄位分隔線不補償，
     因此會跟著資料層一起往左 3%。左滑展開後取消補償，內容整體左移 25%。 */
  .customers-mobile-card-content > .customers-mobile-field > *,
  .customers-mobile-card-content > .customers-mobile-actions > * {
    transform: translateX(3%);
    transition: transform .2s ease;
  }

  .customers-mobile-card-swiped .customers-mobile-card-content > .customers-mobile-field > *,
  .customers-mobile-card-swiped .customers-mobile-card-content > .customers-mobile-actions > * {
    transform: none;
  }

  .customers-mobile-field {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 45px;
    padding: 8px 14px;
  }

  .customers-mobile-field + .customers-mobile-field {
    border-top: 1px solid var(--color-border);
  }

  .customers-mobile-label {
    flex: 0 0 88px;
    color: var(--color-text-muted);
    font-size: .8rem;
  }

  .customers-mobile-value,
  .customers-mobile-field .edit-input,
  .customers-mobile-field .line-id-input {
    min-width: 0;
    flex: 1;
  }

  .customers-mobile-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 10px 14px;
    border-top: 1px solid var(--color-border);
  }

  .reply-mode-toggle {
    border-color: #1f6feb;
    color: #1f6feb;
  }

  .reply-mode-toggle.is-human {
    border-color: #cf222e;
    color: #cf222e;
  }

  .customers-mobile-delete-btn {
    position: absolute;
    z-index: 0;
    inset: 0 0 0 auto;
    width: 25%;
    border: 0;
    border-radius: 0;
    background: #cf222e;
    color: #fff;
    font-weight: 700;
    pointer-events: none;
  }

  .customers-mobile-card-swiped .customers-mobile-delete-btn {
    pointer-events: auto;
  }

  .customers-mobile-empty {
    margin: 0;
    padding: 16px;
    text-align: center;
  }

  #customers-form #add-row-btn {
    margin-top: 12px;
  }
}

/* 租客合約資訊：list/form 共用桌面資料與路由，手機端只改為卡片版型。 */
#tenants-mobile-list {
  display: none;
}

.tenant-mobile-delete-btn {
  display: none;
}

@media (max-width: 768px) {
  #tenants-form #tenants-table {
    display: none;
  }

  #tenants-mobile-list {
    display: grid;
    gap: 10px;
  }

  .tenants-mobile-card {
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
  }

  .tenants-mobile-field {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    min-height: 45px;
    padding: 8px 14px;
  }

  .tenants-mobile-field + .tenants-mobile-field,
  .tenants-mobile-actions {
    border-top: 1px solid var(--color-border);
  }

  .tenants-mobile-label {
    flex: 0 0 88px;
    padding-top: 2px;
    color: var(--color-text-muted);
    font-size: .8rem;
  }

  .tenants-mobile-value {
    min-width: 0;
    flex: 1;
    overflow-wrap: anywhere;
  }

  .tenants-mobile-actions {
    display: flex;
    justify-content: flex-end;
    padding: 10px 14px;
  }

  .tenants-mobile-actions .button-link {
    display: inline-block;
    padding: 6px 10px;
    border: 1px solid var(--color-primary);
    border-radius: var(--radius-sm);
    color: var(--color-primary);
    text-decoration: none;
  }

  .tenants-mobile-empty {
    margin: 0;
    padding: 16px;
    text-align: center;
  }

  /* 手機版刪除收在完整編輯表單內，不在清單上提供勾選／批次刪除。 */
  .tenant-mobile-delete-btn {
    display: inline-block;
    margin-left: 8px;
    border-color: #cf222e;
    color: #cf222e;
  }

  /* 完整合約表單仍使用相同 DOM/欄位；手機僅把每個原有 section 顯示成卡片。 */
  .contract-form .form-section {
    padding: 14px;
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
  }

  .contract-form input[type="text"],
  .contract-form input[type="number"],
  .contract-form input[type="date"],
  .contract-form select,
  .contract-form textarea {
    max-width: none;
  }
}
