/* tenant/review.css：店家後台樣式第 6／6 支「UI 評審第 5 輪、付費功能鎖頭、資料列表卡片檢視、手機行事曆精簡、拖曳排序、觸控 44px、營業額遮蔽、全站目視檢查收尾」（2026-10-12 由 tenant.css 第 4569～5372 行逐字切出；依 tenant/layout.html 的 link 順序串接＝原檔）---- 以下逐字搬自拆分前的 tenant.css ---- */
/* ========================================
   UI 評審第 5 輪（2026-08-02）：兩軌評審共同指出的四類問題
   ① AI 客服 FAB 壓住列表最後一列的操作鈕
   ② 手機版表格右緣被硬切，沒有「還有內容」的提示
   ③ reports 四色左邊框 + 全藍卡片標題（色彩不承載語意）
   ④ 工具列殘留彩虹（products/services 排序模式列）
   ======================================== */

/* ① FAB 遮擋：內容區底部預留 FAB 直徑 + 安全距離，最後一列不會被壓住。
      桌機 FAB 56px + bottom 24px → 需要 88px；手機再多留一點給捲動慣性。 */
#content {
    padding-bottom: 96px;
}
@media (max-width: 768px) {
    #content { padding-bottom: 104px; }
    /* FAB 位置改由下方「⑨ 手機 FAB 移左下角」統一處理，此處不再調 bottom（避免兩條 !important 打架）*/
}

/* ② 手機版表格捲動提示：右緣淡出，讓「右邊還有欄位」看得出來。
      只在真的溢出時才淡出（用 scroll-shadow 背景技法，不遮住沒溢出的表格）。 */
@media (max-width: 991px) {
    .table-responsive,
    .data-table-scroll {
        background:
            linear-gradient(to right, #fff 30%, rgba(255, 255, 255, 0)) left center,
            linear-gradient(to left, #fff 30%, rgba(255, 255, 255, 0)) right center,
            linear-gradient(to right, rgba(16, 24, 40, 0.10), rgba(16, 24, 40, 0)) left center,
            linear-gradient(to left, rgba(16, 24, 40, 0.10), rgba(16, 24, 40, 0)) right center;
        background-repeat: no-repeat;
        background-size: 32px 100%, 32px 100%, 14px 100%, 14px 100%;
        background-attachment: local, local, scroll, scroll;
    }
    /* 頁籤列同理：settings 的「通知設…」被切邊時要看得出可橫捲 */
    .nav-tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
    }
    .nav-tabs::-webkit-scrollbar { display: none; }
    .nav-tabs .nav-link { white-space: nowrap; }
}

/* ③ reports：拿掉裝飾性四色左邊框，卡片標題回到中性深灰。
      數字本身才是重點，色條不承載語意只會分散注意力。 */
#content .card[class*="border-left"],
#content .stat-card,
#content .report-card {
    border-left-width: 1px !important;
    border-left-color: rgba(0, 0, 0, 0.06) !important;
}
#content .card-header h5,
#content .card-header h6,
#content .card-title {
    color: #1c2033;
}

/* ④ 排序模式列做成真正的 segmented control（取代橘/藍/綠三色並排） */
.sort-mode-group {
    background: #f1f3f9;
    border-radius: 10px;
    padding: 3px;
    display: inline-flex;
    gap: 2px;
}
.sort-mode-group .btn {
    border: 0;
    background: transparent;
    color: #5b6076;
    border-radius: 8px;
    box-shadow: none;
}
.sort-mode-group .btn.active,
.sort-mode-group .btn:active {
    background: #fff;
    color: var(--primary-color);
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.08);
}

/* ⑤ 手機版操作欄（2026-08-02 第 5 輪原本「固定在右側」；⚠️ 2026-09-30 起已改成不釘，理由見區塊內註解，
      下面這段是當年為什麼要釘的歷史紀錄）
      實測 390px 下 staff/products/block-times/services 的操作欄整個在畫面外
      （actionLeft 424~524px > 視窗 390px），店家在手機上根本按不到編輯/刪除。

      ⚠️ 這裡跟 2026-08-01 移除的舊手機 sticky 不同：
      舊版沒有替前一欄讓位，捲到底時最後一欄資料會永久躲在固定欄底下
      （$450 被截成「$4」、徽章被截成「已確」）。這版用
      `td:nth-last-child(2) { padding-right }` 預留固定欄寬度，
      捲到最右時前一欄仍能完整露出。 */
@media (max-width: 991px) {
    /* ⚠️ 2026-09-30：≤991 也「不釘」操作欄了（與 992~1199 帶 2026-09-25 的決定同一個理由）。
       原本這裡釘住最後一欄，再用 `td:nth-last-child(2){padding-right:156px}` 讓位——
       但讓位只有「捲到最右」才有效，預設捲動位置（最左）釘住的操作欄一定壓在容器右緣、
       蓋住當下排在那裡的欄位：平板直向商品訂單的數量／金額、定期預約的「服務」「週期」、
       行銷活動的「已結束」徽章、顧客表格的表頭「操作」只剩「作」（2026-09-30 全站目視實測）。
       只要表格會溢出又釘住最後一欄，預設位置就必然蓋到東西，沒有 padding 值能解。
       現在整張表自然橫捲＋「表格較寬，可左右滑動」提示（tenant.js initTableScrollHints），
       操作欄捲過去一定點得到；手機多數列表另有卡片檢視。
       ≥1200 的釘住行為不變。 */
    .data-table-body th:last-child:not([colspan]),
    .data-table-body td:last-child:not([colspan]) {
        position: static;
        box-shadow: none;
    }

    /* 名稱欄允許折行：products 的商品名稱在 390px 下永久被切掉（表格可捲範圍只有 5px，
       捲到底也救不回來，「哥倫比亞 蜜處理 半磅」被吃掉 27px）。手機上寧可折成兩行，
       也不要讓店家永遠看不到完整品名。
       ⚠️ 不能只寫 `td:first-child`：products/staff 等表的第一欄是**手機隱藏的拖曳欄**
       （`d-none d-md-table-cell`），規則會落在看不見的格子上完全沒作用（2026-08-02 實測）。
       所以同時命中「第一欄」與「緊接在隱藏欄之後的那一欄」＝畫面上真正的第一欄。 */
    .data-table-body td:first-child,
    .data-table-body td.d-none + td,
    .data-table-body th.d-none + th {
        white-space: normal;
        word-break: normal;
        overflow-wrap: break-word;
    }
    /* 名稱欄最小寬：中文逐字可斷，不給下限會被擠成「一字一行」（2026-09-25，同 992~1199 帶） */
    .data-table-body td:first-child:not(:has(> input[type="checkbox"], > .form-check)),
    .data-table-body td.d-none + td:not(:has(> input[type="checkbox"], > .form-check)) {
        min-width: 6.5rem;
    }

    /* （2026-09-30 刪除「固定欄不吃 hover 底色」：這一帶已不釘操作欄，留著反而 hover 時整列變灰、最後一格仍是白的） */
}

/* ⑥ 手機列表列高一致：最後一欄（操作欄）內的 icon 鈕排成單列。
      ⚠️ common.css 有一條更早的手機規則 `.table .btn-group { display: inline-grid !important;
      grid-template-columns: repeat(2,1fr) }`（2×2 網格，省寬度用）。2×2 的缺點是撐高列（90↔116px 交錯）、
      看起來像硬塞，這裡用同等 !important 覆蓋回單列（.data-table-body 以外的表格仍沿用 common.css 的 2×2）。
      2026-09-30 起這一帶的操作欄已不釘（跟著整張表橫捲），選擇器仍然成立、只是不再是「固定欄」。 */
@media (max-width: 991px) {
    .data-table-body td:last-child:not([colspan]) .btn-group,
    .data-table-body td:last-child:not([colspan]) > div {
        display: inline-flex !important;
        flex-wrap: nowrap !important;
        gap: 1px;
    }
    /* 部分頁在 th 寫死 inline min-width（bookings 190px / products 200px），
       手機會讓操作欄佔掉半個螢幕 → 一律讓它依內容收縮 */
    .data-table-body th:last-child:not([colspan]),
    .data-table-body td:last-child:not([colspan]) {
        min-width: 0 !important;
        width: auto !important;
    }
    .data-table-body td:last-child:not([colspan]) .btn {
        padding-left: 0.3rem;
        padding-right: 0.3rem;
    }
}

/* ⑦ LINE 設定頁兩欄高度失衡（左欄 ~1300px、右欄 ~5900px → 左側留 4600px 死白）
      右欄是狀態/預覽/說明的長卡片堆，短時間內不打算重排 HTML；
      改讓左欄設定表單在桌機黏住視窗，捲動右欄時左側不再是一片空白。 */
/* 2026-08-02：Rich Menu / Flex 主選單 / 使用說明三張長卡片已改滿寬（col-12），
   右欄不再是 5900px 的高瘦柱、左欄也不再留大片空白 → 原本的 sticky 補償已無必要，
   留著反而會讓表單在捲到滿寬區時浮在旁邊。 */

/* ⑧ 手機操作欄收尾（第 7 輪評審 B1/B2；當年操作欄是釘住的「固定欄」，2026-09-30 起已不釘）
      問題一：操作欄內 4 顆 icon 折成 2×2，把列撐高且看起來像硬塞。
      問題二（只在釘住時會發生，現在已不成立）：緊鄰固定欄的內容右半被壓掉，
              變成「已發」「拉花課程（」這種看不懂的殘字。
      下面的排版規則仍然需要（按鈕折行、不被裁），只是不再有「固定欄壓到前一欄」這回事。 */
@media (max-width: 991px) {
    /* 操作欄本身：一列排開不換行，寬度隨內容但不再撐高列 */
    .data-table-body th:last-child:not([colspan]),
    .data-table-body td:last-child:not([colspan]) {
        white-space: nowrap;
    }
    /* 操作鈕排版：每列最多 3 顆，超過折行。
       ⚠️ 2026-08-02 實測修正：原本寫 `nowrap` + `width:25px`，但 25px 從來沒生效過——
       common.css:654「觸控裝置 .btn { min-width:44px }」的 min-width 贏過 width，
       實際渲染是 44px。bookings 有 5 顆鈕 → 內容 245px 硬塞進 max-width:160px 且 overflow:hidden
       的格子，第 5 顆「詳情」整顆在畫面外（rect 399~443，畫面只有 390），而且因為這格是釘住的，
       兩個捲軸捲到底都救不回來＝永遠點不到。
       390px 螢幕放不下 5 顆 44px 按鈕，這是物理限制；折成兩行可以全部點得到，
       代價是那幾列變高。「按鈕點不到」比「列變高」嚴重，所以選折行。
       不縮小按鈕是刻意的——先前稽核已認定列表操作鈕 30px 不可點屬 HIGH。 */
    .data-table-body td:last-child:not([colspan]) .btn-group,
    .data-table-body td:last-child:not([colspan]) .btn-group-sm {
        display: inline-flex !important;
        flex-wrap: wrap !important;
        justify-content: flex-end;
        gap: 1px;
        max-width: 136px;   /* 3 × 44 + 2 × 1 gap，確保一列最多 3 顆 */
    }
    /* 折行後每顆仍是完整圓角按鈕（Bootstrap btn-group 只把首尾去圓角，折行會很醜）*/
    .data-table-body td:last-child:not([colspan]) .btn-group > .btn {
        border-radius: var(--radius-sm, 6px) !important;
    }
    /* 這格不受 max-width:160px + overflow:hidden 限制，否則折行後仍會被裁 */
    .data-table-body td:last-child:not([colspan]) {
        max-width: none !important;
        overflow: visible !important;
    }
    /* 徽章不被壓斷：整顆徽章不換行，寧可整欄橫捲也不要顯示半個字 */
    .data-table-body td .badge {
        white-space: nowrap;
    }
}

/* ⑨ AI 客服按鈕已於 2026-08-02 從「右下浮動氣泡」改為「頂端工具列按鈕」
      （見 layout.html 的 #aiSupportBubble 註解）。原本這裡有一整組手機專用的
      「移到左下 + 捲動時讓路 + 開 modal 時隱藏」規則，全部隨之移除——
      量測證實浮動氣泡在手機/平板/桌機都會蓋住可點的控制項，換角落只是換受害者。
      按鈕現在跟著工具列走，不再覆蓋任何內容。 */


/* ⑩ 原本是「短頁面時 FAB 蓋住 footer」→ 手機／平板頁尾 padding-bottom: 72px。
      FAB 已於 2026-08-02 移到頂端工具列（見上方 ⑨），這 72px 從此只剩「頁尾下方一大塊白」
      （09-30 後台報告：手機／平板頁尾下方約 100px 空白）。2026-10-01 UX 改版 1A 改成只留
      一般內距＋瀏海機底部安全區。安裝／推播橫幅（.pwa-install-banner）另由 tenant.js
      syncBottomBannerSpace 替 body 讓出高度，不靠這一條。 */
@media (max-width: 991px) {
    footer, .app-footer, #content + footer {
        padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
    }
}

/* ⑪ 滿寬卡片內的單行短輸入不要拉到 1140px（2026-08-02 第 11 輪評審）
      line-settings 的 Rich Menu / Flex 區塊改滿寬後，像「Header 標題」這種單行文字欄
      被拉成與卡片等寬，視覺過度空曠且與旁邊色票區不對稱。長文字（textarea）不受限。 */
@media (min-width: 992px) {
    .col-12 > .card .card-body input[type="text"]:not(.form-control-lg),
    .col-12 > .card .card-body input[type="url"] {
        max-width: 420px;
    }
}

/* ⑫ 分類篩選 chip（2026-08-02 第 12 輪評審）
      原本用 .btn-group.flex-wrap，btn-group 的子項會被拉伸，390px 下第 4 個分類
      （如「沖煮器材」）獨佔一整行且被拉滿寬 → 孤行。改成可換行的膠囊 chip。 */
.filter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}
.filter-chips .btn {
    flex: 0 0 auto;
    border-radius: 999px;
    font-size: 0.8125rem;
    padding: 0.2rem 0.7rem;
}

/* ===== 側邊欄付費功能鎖頭（2026-08-07）=====
   未訂閱的付費功能改成「顯示 + 灰階 + 鎖頭」而不是整項隱藏——
   隱藏會讓店家永遠不知道有這功能可以買（見 tenant.js decorateSidebarFeatureItem 註解）。
   視覺重量刻意壓低：比正常項目淡，不搶走已訂閱功能的注意力。 */
#sidebar .nav-item.feature-locked .nav-link {
    opacity: 0.55;
}
#sidebar .nav-item.feature-locked .nav-link:hover {
    opacity: 0.85;
}
#sidebar .feature-lock-icon {
    font-size: 11px;
    flex-shrink: 0;
    opacity: 0.7;
}
#sidebar .feature-expiry-badge {
    font-size: 10px;
    font-weight: 600;
    flex-shrink: 0;
    padding: 2px 6px;
}

/* ========================================
   資料列表卡片檢視（2026-08-25，先上顧客頁）
   ≤991 的表格佈局把名稱/時間折成一字一行、操作鈕直排撐到 204px（8/2 手機規則的取捨）。
   改成一筆一張卡：資訊全露、操作鈕橫排 44px；表格保留可切回（鴻瑞「改回來」教訓）。
   桌機（≥992）切換列隱藏、永遠表格，JS applyListView 也只在 ≤991 才顯示卡片。
   ======================================== */
.list-view-toggle {
    display: none;
    gap: 0.25rem;
    padding: 0.5rem 1rem 0;
    justify-content: flex-end;
}
.list-view-toggle .btn {
    border: 1px solid rgba(0, 0, 0, 0.12);
    color: var(--text-secondary);
    background: transparent;
}
.list-view-toggle .btn.active {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: #fff;
}
@media (max-width: 991.98px) {
    .list-view-toggle { display: flex; }
}
.data-cards {
    display: grid;
    gap: 0.6rem;
    padding: 0.75rem 1rem 1rem;
}
.data-cards-empty {
    text-align: center;
    color: var(--text-secondary);
    padding: 2.5rem 1rem;
}
/* 空狀態句子裡的連結（例如「顯示全部訂單」）跟周圍文字只差顏色＝axe link-in-text-block（2026-10-15），補底線 */
.data-cards-empty a {
    text-decoration: underline;
}
.data-card {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 0.4rem 0.75rem;
    align-items: center;
    background: #fff;
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 0.625rem;
    padding: 0.75rem 0.9rem;
}
.data-card-main { min-width: 0; display: grid; gap: 0.25rem; }
.data-card-title { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; min-width: 0; }
/* overflow-wrap:anywhere 不可拿掉（2026-08-27）：主標題原本沒有任何斷詞規則，長且不可斷的名稱
   （英數顧客名／服務名／商品名）在手機會直接溢出卡片，而卡片檢視沒有橫捲容器可救
   （表格檢視還有 .table-responsive 可以橫捲讀完）——實測 iPhone 13：卡片 clientWidth 330，
   名稱右緣 553 而 document.scrollWidth 仍是 390 ⇒ 後段永久看不到也捲不到。
   .data-card-sub 早就有同一條規則，主標題是唯一漏掉的。min-width:0 讓它在 flex 內能被壓縮換行。 */
.data-card-name { font-weight: 700; font-size: 1rem; overflow-wrap: anywhere; min-width: 0; }
.data-card-status { margin-left: auto; }
.data-card-avatar {
    width: 32px; height: 32px; border-radius: 50%; object-fit: cover;
    border: 1px solid #e0e0e0; flex-shrink: 0;
}
.data-card-avatar-line {
    background: #06C755; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 14px;
}
.data-card-sub {
    display: flex; flex-wrap: wrap; gap: 0.25rem 1rem;
    color: var(--text-secondary); font-size: 0.85rem;
    overflow-wrap: anywhere;
}
.data-card-stats {
    display: flex; gap: 1rem; font-size: 0.85rem; color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.data-card-tags { display: flex; flex-wrap: wrap; gap: 0.25rem; }
.data-card-thumb { width: 40px; height: 40px; border-radius: 6px; object-fit: cover; flex-shrink: 0; }
.data-card-stats .btn-sm { padding: 0 0.3rem; min-height: 0; min-width: 0; line-height: 1.2; vertical-align: middle; }
/* 觸控裝置把觸控目標還給它（2026-08-27）：上面那條為了讓統計列不被撐高，把 min-height/min-width 歸零，
   結果連 common.css `@media(pointer:coarse){.btn-sm{min-height:44px}}` 一起蓋掉——
   實測 iPhone 13 的「LINE 精選」星星只有 22.8×15.4、員工「專屬頁連結」只有 110×16.4（表格檢視反而是 40×27），
   而卡片檢視正是手機／平板直向的**預設**檢視，且這兩顆都是會寫進 DB 的操作鈕（切換是否出現在 LINE 選單、複製員工連結）。
   ⚠️ 不要改回 min-height:0——手指縮小到 15px 目標比切回表格還難按；要壓縮統計列請只動 padding／font-size。
   ⚠️ 也不要改用「負 margin 撐大熱區」：熱區會溢出去蓋到上一列，變成誤觸切換 LINE 精選（更糟）。 */
@media (pointer: coarse) {
    .data-card-stats .btn-sm {
        min-height: 44px;
        min-width: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}
.data-card-tags .badge { font-size: 0.7rem; }
/* 操作鈕橫排；≤575 手機空間不夠時移到卡片底部整排 */
.data-card-actions .btn-group { display: inline-flex; flex-wrap: nowrap; }
/* 卡片操作鈕（2026-10-01 UI 稽核 M6）：
   ① 同一排一律同高——<a class="btn"> 與 <button class="btn"> 的行高不同，顧客卡片的「詳情」曾比其他高半行；
   ② 鈕少（≤4 顆、字短）的頁面在卡片檢視直接把字印出來（.act-label；表格檢視照舊只有圖示＋title／aria-label），
      無字圖示要猜（員工頁兩個行事曆圖示意義不明）。票券那排最多 5 顆，刻意不印字（390px 會擠出卡片）。 */
.data-card-actions .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 36px;
    min-width: 36px;
}
.data-card-actions .act-label {
    display: inline !important;
}
@media (max-width: 575.98px) {
    .data-card { grid-template-columns: 1fr; }
    .data-card-actions { justify-self: end; }
}

/* ========================================
   手機行事曆精簡模式（2026-08-25，calendar-compact.js；後台 + 員工專屬頁共用）
   ≤767 月檢視只畫狀態色點、月曆下方掛當日清單。
   ⚠️ FullCalendar v6 的 CSS 由 JS 動態注入、永遠排在本檔之後 → 所有規則以 .fc.calendar-compact 起頭
      （specificity ≥ 0,4,0）才蓋得過 FC 的 .fc-direction-ltr .fc-daygrid-event.fc-event-start{margin} 等 (0,3,0) 規則。
   ⚠️ 全部包在 ≤767 媒體查詢裡；桌機零影響。
   ======================================== */
.cal-hint-compact { display: none; }
@media (max-width: 767.98px) {
    .cal-compact .cal-hint-desktop { display: none; }
    .cal-compact .cal-hint-compact { display: inline; }
    /* 圖例改單列橫捲，別再折成兩三行把月曆推到第二屏 */
    /* 2026-08-28 X1：橫捲在 375px 把「爽約／封鎖」切到畫面外且沒有任何可捲提示（隱藏狀態切不回來）→
       改折行但縮小間距字級，7 顆 chip 兩行放得下，不會把月曆推太遠 */
    .cal-compact .calendar-legend { flex-wrap: wrap; gap: 0.35rem 0.6rem; padding: 0.5rem 0.75rem; }
    .cal-compact .calendar-legend-item { white-space: nowrap; font-size: 0.72rem; }

    /* 月格：只留色點 */
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-day-events { display: flex; flex-wrap: wrap; gap: 2px; justify-content: center; align-items: center; padding: 0 2px 3px; min-height: 12px; margin: 0; }
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-day-events::before,
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-day-events::after { display: none; content: none; }
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-event-harness { margin: 0 !important; flex: 0 0 auto; }
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-event-harness-abs { visibility: hidden; pointer-events: none; }
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-event {
        width: 8px; height: 8px; min-height: 8px !important; max-height: 8px;
        padding: 0 !important; margin: 0 !important; border: 0 !important; border-radius: 50%;
        overflow: hidden; font-size: 0; line-height: 0; pointer-events: none; box-shadow: none;
    }
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-event .fc-event-title,
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-event .fc-event-time,
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-event .fc-daygrid-event-dot,
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-event .fc-event-main { display: none; }
    /* 「+N」數字 chip：pointer-events:none 讓點擊穿透到日期格（moreLinkClick 回 undefined 一定彈 popover） */
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-day-bottom { margin: 0 !important; padding: 0; }
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-day-bottom:empty { display: none; }
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-more-link {
        display: inline-flex !important; align-items: center; font-size: 0.65rem; line-height: 14px; min-height: 14px !important;
        padding: 0 4px !important; margin: 0 !important; border-radius: 7px; background: #e9ecef; color: #495057; pointer-events: none;
    }
    .fc.calendar-compact .fc-more-popover { display: none; }
    /* 日期數字：壓縮列高（pointer:coarse 原本 6px 8px !important） */
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-day-number { padding: 2px 6px !important; min-height: 24px; display: inline-flex; align-items: center; font-size: 0.9rem; }
    .fc.calendar-compact .fc-dayGridMonth-view .fc-daygrid-day-frame { min-height: 46px; }
    /* 選中日 / 已隱藏灰圈 */
    .fc.calendar-compact .fc-daygrid-day.cal-day-selected .fc-daygrid-day-frame { box-shadow: inset 0 0 0 2px var(--primary-color); background: rgba(67, 97, 238, 0.06); }
    .fc.calendar-compact .fc-daygrid-day.cal-has-hidden .fc-daygrid-day-events::after { content: ''; display: block; width: 8px; height: 8px; border-radius: 50%; border: 1.5px solid #adb5bd; }

    /* 當日清單 */
    .cal-agenda { margin-top: 0.75rem; padding: 0; }
    .cal-agenda-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; flex-wrap: wrap; padding: 0.25rem 0.25rem 0.5rem; }
    .cal-agenda-date { font-weight: 700; margin-right: 0.4rem; }
    .cal-agenda-head small { color: var(--text-secondary); }
    .cal-agenda-actions { display: flex; gap: 0.4rem; }
    .cal-agenda-empty { color: var(--text-secondary); text-align: center; padding: 1.25rem; background: #fff; border: 1px dashed rgba(0, 0, 0, 0.12); border-radius: 0.625rem; }
    .cal-agenda-row { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; background: #fff; border: 1px solid rgba(0, 0, 0, 0.08); border-radius: 0.625rem; padding: 0.6rem 0.9rem; }
    .cal-agenda-row-block { background: #f5f5f7; color: #6e6e73; }
    .cal-agenda-card { border-left: 4px solid #4361ee; }
    .cal-agenda-card.st-pending { border-left-color: #ff9f0a; }
    .cal-agenda-card.st-completed { border-left-color: #34c759; }
    .cal-agenda-card.st-cancelled { border-left-color: #86868b; }
    .cal-agenda-card.st-no-show { border-left-color: #6f42c1; }
}

/* ========================================
   拖曳排序：卡片檢視把手 + 觸控拖曳狀態（2026-08-27 謙豐三星平板回報）
   ======================================== */
.data-card.has-handle { grid-template-columns: auto minmax(0, 1fr) auto; }
/* ⚠️ ≤575.98 必須覆寫回「把手 + 內容」兩欄、操作鈕另起一列（2026-08-27 對抗審查抓到）：
   上面那條 .data-card.has-handle 特異度 (0,2,0) 勝過 8/25 建立的 @media(max-width:575.98px) .data-card{1fr} (0,1,0)，
   手機上會變成「把手 34px + 內容 41px + 固定寬 173px 操作鈕」三欄 —— 電話折成一字一行、徽章壓在按鈕上。
   實測 360px：內容欄 41px（無把手的顧客頁是 271px）。加把手時忘了同步手機分支，這條不可刪。 */
@media (max-width: 575.98px) {
    .data-card.has-handle { grid-template-columns: auto minmax(0, 1fr); }
    .data-card.has-handle .data-card-actions { grid-column: 1 / -1; justify-self: end; }
}
.data-card .drag-handle { color: #adb5bd; cursor: grab; user-select: none; -webkit-user-select: none; padding: 10px 6px; font-size: 1.35rem; touch-action: none; align-self: center; }
.data-card.dragging { opacity: 0.4; }
.data-card.drop-target { outline: 2px solid var(--bs-primary); outline-offset: -2px; }
/* 觸控合成拖曳（tenant.js initTouchDragAndDrop）：來源跟著手指，pointer-events:none 讓 elementFromPoint 打到底下的目標 */
/* ⚠️ transition: none 是必要的、不是美化（2026-08-27 真觸控實測）：
   合成拖曳在派 drop 之前會把 src.style.transform 清空，讓既有 drop handler 用
   getBoundingClientRect() 讀到「歸位後」的位置來判斷插在目標前或後。
   但 .data-table-body table > tbody > tr 帶 transform 0.15s ease —— 清掉的只是 inline 值，
   實際 rendered transform 還停在完整位移上，於是方向判錯：相鄰互換變成沒動、跨兩列只移一格、
   往上拖甚至完全不送請求，畫面卻照樣跳「順序已更新」＝假成功。
   選擇器要 !important：.data-table-body table > tbody > tr 的權重高過單一 class。 */
/* ⚠️ 這裡的 pointer-events: none 是整個觸控拖曳層的承重契約，不是視覺效果：
   tenant.js 的 initTouchDragAndDrop 全靠 elementFromPoint(手指) 找落點，
   而被拖的那一張就釘在手指底下（translate3d）——它必須退出 hit-test，
   否則 elementFromPoint 永遠回自己 → over === src → 【drop 事件根本不會派】
   → 卡片會跟著手指、放開彈回原位、沒有 toast、沒有錯誤，順序一個字都沒存。 */
.touch-drag-src { pointer-events: none; position: relative; z-index: 5; user-select: none; -webkit-user-select: none;
    transition: none !important; }
/* 把手在「不被拖的時候」可能需要自己開 pointer-events（例如 portfolio 的把手長在
   pointer-events:none 的順序徽章裡），但那條規則的選擇器比 .touch-drag-src 更具體，
   拖曳期間會把上面那道契約蓋掉 ⇒ 必須在這裡收回來。
   2026-09-10 實際發生：作品展示加了把手之後，觸控排序從「長按可用」變成「100% 存不了」
   （有可見把手時 hasVisibleHandle 會關掉長按那條退路，等於連舊路都沒了）。
   收在共用層而不是 portfolio 頁內，未來任何把手設了 pointer-events 都自動免疫。 */
.touch-drag-src .drag-handle,
.touch-drag-src .bi-grip-vertical,
.touch-drag-src [data-drag-handle] { pointer-events: none !important; }
[draggable="true"] .drag-handle, [draggable="true"] .bi-grip-vertical { touch-action: none; }

/* LINE 設定頁「Flex 主選單按鈕」的排序把手（2026-09-10）。
   那一列左右全是 checkbox／color／text 輸入框，而觸控合成層的 IGNORE_SEL 含 input
   ⇒ 把手本身必須夠大、而且與相鄰的輸入框拉開距離，手指才碰得到。
   （該頁沒有頁內 <style> 區塊——照樣板慣例頁內樣式要寫在 body，寫進 head 會被
     `<head th:replace>` 整塊換掉；與其為一條規則新開一個區塊，收在這裡與其他把手同一處。） */
.flex-btn-drag-handle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    min-height: 28px;
    font-size: 16px;
    cursor: grab;
    user-select: none;
    -webkit-user-select: none;
}
.flex-btn-drag-handle:active { cursor: grabbing; }
@media (hover: none) {
    /* 手指的目標要夠大（Apple/Google 都建議 ≥44px） */
    .flex-btn-drag-handle { min-width: 44px; min-height: 44px; font-size: 20px; }
}

/* ========================================
   觸控目標 ≥44px（2026-09-11 QA-J 平板體檢）
   只作用在 (hover: none) 或 (pointer: coarse)——桌機滑鼠逐位元不變。
   ======================================== */
@media (hover: none), (pointer: coarse) {
    /* ① 商品／員工列表「表格檢視」的拖曳把手：平板實測 14×17px（就是那個圖示本身的大小），
          而把手是觸控拖曳合成層「零延遲開始拖」的唯一入口（沒點中就退回長按 400ms）。
          services.html 頁內早就有同一件事（.service-row .drag-handle），這裡收成共用、三頁一致。
          卡片檢視的把手原本 padding 10px 6px（約 34px 寬），一併補足。
          ⚠️ 不動 pointer-events：拖曳期間 .touch-drag-src 那條「把手退出 hit-test」的契約要照樣生效。 */
    .data-table-body tr[draggable="true"] .drag-handle,
    .data-card[draggable="true"] .drag-handle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 44px;
        min-height: 44px;
        font-size: 1.35rem;
        touch-action: none;
    }
    /* ② 頂列「當前店家」chip（點開切換店家，每一頁都有）：平板直向實測 35px。
          舊的 max-width 規則寫 padding 被 inline `padding:6px 14px` 蓋掉、舊的 pointer:coarse 規則又限 ≥992，
          <992 的平板直向兩頭落空。那顆 button 沒有 inline height，只加 min-height 不會拉壞版面。 */
    #currentTenantChip {
        min-height: 44px;
    }
}

/* ========================================
   營業額遮蔽（眼睛，2026-09-30）
   只是畫面遮蔽不是權限；tenant.js initRevenueMask 切 body.revenue-hidden
   ======================================== */
body.revenue-hidden [data-revenue-mask]:not(input):not(textarea) {
    visibility: hidden;
    position: relative;
    user-select: none;
    /* 遮住時不可點：金額上的 title 提示（滑過去會秀原價／折扣）與「點一下切換實收／折扣／原價」都關掉；
       點擊會穿透到外層那一列，整列點開詳情照常可用 */
    pointer-events: none;
}
/* 行內短金額（$0）：圓點比原文寬，給最小寬度免得蓋到旁邊的字 */
body.revenue-hidden span[data-revenue-mask]:not([data-revenue-mask="block"]),
body.revenue-hidden strong[data-revenue-mask]:not([data-revenue-mask="block"]) {
    display: inline-block;
    min-width: 3.2em;
}
/* 輸入框（調整金額、儲值金金額…）：::after 畫不上 input，改成字透明——仍可點、可打字、可送出；
   要看數字按視窗頂端「顯示金額」（只對該視窗暫時顯示） */
body.revenue-hidden input[data-revenue-mask] {
    color: transparent !important;
    caret-color: var(--dark-color, #212529);
    text-shadow: none;
}
body.revenue-hidden input[data-revenue-mask]::placeholder { color: transparent; }
/* 文字型：換成圓點 */
/* :not(:empty)：還沒填值的空 span（例如沒有折抵時的說明）不要冒出一串孤零零的圓點 */
body.revenue-hidden [data-revenue-mask]:not([data-revenue-mask="block"]):not(input):not(:empty)::after {
    content: "••••";
    visibility: visible;
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-secondary);
    font-weight: 600;
    letter-spacing: 2px;
    white-space: nowrap;
}
body.revenue-hidden td[data-revenue-mask]:not([data-revenue-mask="block"])::after,
body.revenue-hidden .text-end[data-revenue-mask]:not([data-revenue-mask="block"])::after {
    left: auto;
    right: 0.5rem;
}
/* 整塊（表格／圖表）：換成「已隱藏」 */
body.revenue-hidden [data-revenue-mask="block"] {
    min-height: 3.5rem;
}
body.revenue-hidden [data-revenue-mask="block"]::after {
    content: "🔒 金額已隱藏（點右上角「顯示金額」）";
    visibility: visible;
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 0.5rem;
    background: var(--light-color);
    border-radius: var(--border-radius);
    color: var(--text-secondary);
    font-size: 0.9rem;
    /* 手機（≤767）有一條 `.table-responsive::after { width:24px; opacity:.6; 漸層 }` 的橫捲提示，
       它的 width 會蓋掉 inset:0 的右緣 ⇒ 遮罩縮成左邊 24px 一條、字一個一個直排（2026-09-30 抽成頁 390px 實測）。
       這裡把那三個屬性明確還原，所有 table-responsive 上的整塊遮罩（儀表板員工業績、報表 TOP 表）一起修好 */
    width: auto;
    opacity: 1;
    pointer-events: auto;
}
.revenue-toggle-btn { white-space: nowrap; }
/* 圓點前面要留的固定字（例：列表可切換金額的「實收 」，booking-amounts.js bookingNetAmountHtml） */
body.revenue-hidden [data-revenue-mask][data-mask-prefix]:not([data-revenue-mask="block"]):not(input):not(:empty)::after {
    content: attr(data-mask-prefix) "••••";
}
/* 上面那條的權重比「視窗內顯示金額」高，視窗解開時要明確拿掉（行事曆預約詳情就用這種金額） */
body.revenue-hidden .modal.revenue-revealed [data-revenue-mask][data-mask-prefix]::after { content: none !important; }

/* 視窗內就地「顯示金額」（tenant.js ensureModalRevenueBar）：只在遮蔽中出現；
   按下去 .modal 加 revenue-revealed，只解開這個視窗裡的金額，關掉視窗自動恢復 */
.revenue-modal-bar { display: none; }
body.revenue-hidden .revenue-modal-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    background: var(--light-color);
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    color: var(--text-secondary);
    font-size: 0.875rem;
}
body.revenue-hidden .modal.revenue-revealed [data-revenue-mask]:not(input):not(textarea) {
    visibility: visible;
    pointer-events: auto;
    user-select: auto;
}
/* !important：上面「換成圓點」那條加了 :not(:empty) 之後權重是 (0,4,3)，比這條 (0,4,2) 高——
   不加的話按了「顯示金額」數字出來了、圓點卻還疊在上面（2026-09-30 第三批）。守衛 behaviourHooksArePresent 鎖住 */
body.revenue-hidden .modal.revenue-revealed [data-revenue-mask]::after { content: none !important; }
body.revenue-hidden .modal.revenue-revealed input[data-revenue-mask] { color: inherit !important; }
body.revenue-hidden .modal.revenue-revealed input[data-revenue-mask]::placeholder { color: var(--secondary-color); }

/* ========================================
   2026-09-30 全站目視檢查（P0 共用排版）的小項收尾
   ======================================== */

/* 全螢幕視窗要真的全螢幕：上面 `.modal-content{max-height:calc(100dvh - 3.5rem)}` 與 common.css ≤991 的
   `.modal-dialog{margin:.5rem}` 蓋過了 Bootstrap modal-fullscreen-*-down 的 height:100%／margin:0，
   底部露出一條後面頁面的按鈕（選單設計「自訂文字與功能」視窗，平板與手機），兩層按鈕疊在一起容易按錯。 */
@media (max-width: 991.98px) {
    .modal-fullscreen-lg-down {
        margin: 0;
    }
    .modal-fullscreen-lg-down .modal-content {
        max-height: none;
        height: 100%;
    }
}
@media (max-width: 575.98px) {
    .modal-fullscreen-sm-down {
        margin: 0;
    }
    .modal-fullscreen-sm-down .modal-content {
        max-height: none;
        height: 100%;
    }
}

/* 卡片標頭「標題＋右側說明」放不下時，說明換到下一行，不要把標題從中間切斷
   （報表「員工業績 TOP 5（預約・原／價）」、手機上說明被擠成一條窄欄）。 */
#content .card-header.d-flex.justify-content-between {
    flex-wrap: wrap;
    column-gap: 0.75rem;
    row-gap: 0.25rem;
}

/* 顧客詳情的票券／點數紀錄表：平板右欄只有 col-md-8（約 460px），表頭被擠成「點／數」「餘／額」一兩個字一行。
   表頭不折行，放不下交給外層 table-responsive 橫捲。 */
#cdMainRow .table > thead th {
    white-space: nowrap;
}

/* 班表「編輯週排班」：Bootstrap 的 modal-lg 要 ≥992 才生效，平板（768~991）視窗只有 500px，
   6 欄時間表寬 560px ⇒「休息結束」整欄在畫面外、「星期」被擠成直排。平板直接給夠寬的視窗。 */
@media (min-width: 768px) and (max-width: 991.98px) {
    #weeklyScheduleModal .modal-dialog {
        max-width: 720px;
    }
}
/* 週排班視窗（#weeklyScheduleModal）的手機卡片版（2026-10-01 UI 稽核 H3）與「左右滑動」提示，
   2026-10-21 起由 templates/tenant/shifts.html 頁內樣式取代：任何寬度都是一天一列摘要、點「調整」展開。 */

/* 「服務 ↔ 服務人員」能力名單的捲動高度：單一來源（2026-10-01，鏡像收口）
   同一份設定有兩個編輯入口——員工管理「可承接的服務項目」（staff.html #staffCapabilityList）與
   服務項目「可承接的服務人員」（services.html #capabilityStaffList）。2026-09-30 只把員工那邊從 150px 加高，
   服務那邊仍是 150px＝同一份名單一邊看得到全部、一邊被切一半。
   services.html 目前仍帶 inline `max-height:150px`（不屬於本批可改的檔案），所以用 id＋!important 蓋過它；
   ⚠️ 之後改 services.html 的人：請改成 class="capability-picker-list" 並拿掉 inline style，再把下面的 id 選擇器刪掉。
   守衛：tests/capability-list-height-check.js（離線，掃兩個樣板＋本檔）。 */
.capability-picker-list,
#capabilityStaffList {
    max-height: min(320px, 40vh) !important;
    overflow-y: auto;
}

/* 服務項目「可承接的服務人員」每一列＝勾選框＋名字｜加價欄（2026-10-01 UI 稽核 M4）：
   原本是 flex，名字長短不同、加價欄就左右不齊。改成兩欄 grid（名字吃剩下的寬度、加價欄固定 130px）；
   列本身帶 d-flex（display:flex !important），所以這裡也要 !important 且選擇器比 .d-flex 具體。
   捲動框底部留一點空間，最後一列不會貼著下方的說明文字（iPad 直式實測被蓋掉半列）。 */
#capabilityStaffList {
    padding-bottom: 0.25rem;
    margin-bottom: 0.5rem;
}
#capabilityStaffList > div {
    display: grid !important;
    grid-template-columns: minmax(0, 1fr) 130px;
    align-items: center;
    column-gap: 0.75rem;
    min-width: 0 !important;
}
#capabilityStaffList > div > .form-check {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* 平板（768～991.98）的 modal-lg（2026-10-01 UI 稽核 M4）：Bootstrap 的 modal-lg 要 ≥992 才生效，
   iPad 直式 820 上所有「大視窗」都退回 500px，兩欄表單（服務編輯、週排班…）擠在裡面。
   改的是 Bootstrap 的寬度變數而不是 max-width——modal-fullscreen-lg-down 直接寫 max-width:none，
   兩者不會打架（寫 max-width 會把全螢幕視窗也夾回 720px）。上面週排班那條 720px 規則保留。 */
@media (min-width: 768px) and (max-width: 991.98px) {
    .modal-dialog.modal-lg,
    .modal-dialog.modal-xl {
        --bs-modal-width: min(720px, 92vw);
    }
}

