/* tenant/components.css：店家後台樣式第 2／6 支「資料表格與易讀性、詳情頁、快速操作、設定頁、功能商店、側邊欄設定進度與店家 footer、新手引導卡片」（2026-10-12 由 tenant.css 第 996～1967 行逐字切出；依 tenant/layout.html 的 link 順序串接＝原檔）---- 以下逐字搬自拆分前的 tenant.css ---- */
/* ========================================
   資料表格
   ======================================== */

.data-table-container {
    background: white;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    max-width: 100%;
}

.data-table-header {
    padding: 1rem 1.25rem;
    border-bottom: 1px solid rgba(0, 0, 0, 0.04);
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
}

.data-table-title {
    font-weight: 700;
    color: var(--dark-color);
    margin: 0;
}

.data-table-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    /* 允許換行：1024 實測 bookings 的搜尋列整組寬 737 塞進 724 的內容區 →
       3 個元素（容器、input-group、搜尋鈕）右緣 1032 超出畫面 8px。
       換行後擠不下就往下排，不再溢出。 */
    flex-wrap: wrap;
}

.data-table-body {
    padding: 0;
}

.data-table-footer {
    padding: 1rem 1.25rem;
    border-top: 1px solid rgba(0, 0, 0, 0.04);
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
}

.data-table-info {
    font-size: 0.8rem;
    color: var(--text-secondary);
}

/* 防止表格內容溢出 — 手機版可水平滾動 */
.data-table-body {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* 右側漸層陰影提示可滾動 */
    position: relative;
}

.data-table-body td {
    max-width: 300px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (max-width: 1200px) {
    .data-table-body td {
        max-width: 200px;
    }
}

@media (max-width: 768px) {
    .data-table-body td {
        max-width: 150px;
    }
}

/* 庫存異動「原因」欄（2026-10-01 UI 稽核 M12）：原因常是「訂單取消回補 P2026…」這種長字串，
   td 的 max-width 在自動表格版面下不保證生效，實測被 overflow:hidden 直接切掉、沒有「…」。
   改由格子裡那個 block 元素自己截斷（寬度與 ≥992 的 td 上限同為 150px），全文放在 td 的 title。 */
.inventory-reason-cell {
    max-width: 150px;
}

/* 放按鈕列／篩選列（不是表格）的 .data-table-body 要有內距（2026-10-01 UI 稽核 M2）：
   上面的 padding:0 是給表格用的，表格儲存格自己有內距；按鈕列直接放進來就會貼著卡片左緣、
   右邊的日期欄頂到畫面邊（班表管理工具列實例）。 */
.data-table-body.toolbar-card-body {
    padding: 0.75rem 1rem;
}
/* 手機篩選列撐滿（2026-10-01 UI 稽核 M14）：預約／顧客的篩選列各自帶 inline 寬度（120／140／220px），
   在 390px 上一個個靠左排、右邊留一截空白，搜尋框 placeholder 也被截斷。
   opt-in（.toolbar-fill／.toolbar-fill-row），不套到其他用 .data-table-actions 放按鈕的頁面。
   ≤575.98：兩欄 grid，搜尋框／日期區間／批次操作整列；只剩一個下拉配一個搜尋框（顧客頁）時下拉也整列。 */
@media (max-width: 575.98px) {
    .data-table-actions.toolbar-fill {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        gap: 0.5rem;
        width: 100%;
    }
    .data-table-actions.toolbar-fill > * {
        width: auto !important;   /* 蓋過 inline style 的固定寬度 */
        min-width: 0;
        margin: 0 !important;
    }
    .data-table-actions.toolbar-fill > .input-group,
    .data-table-actions.toolbar-fill > #batchActions,
    .data-table-actions.toolbar-fill > .d-flex:not(.form-check),
    .data-table-actions.toolbar-fill > :first-child:nth-last-child(2) {
        grid-column: 1 / -1;
    }
    .data-table-actions.toolbar-fill > .d-flex:not(.form-check) > input[type="date"] {
        flex: 1 1 0;
        width: auto !important;
        min-width: 0;
    }
    .toolbar-fill-row > .col-auto:has(> select) {
        flex: 1 1 0;
    }
    .toolbar-fill-row > .col-auto:has(.input-group),
    .toolbar-fill-row > .col-auto.ms-auto {
        flex: 1 1 100%;
        margin-top: 0.5rem;
    }
    .toolbar-fill-row .input-group {
        width: 100% !important;
    }
}

/* 班表管理「班別範本」那一排：手機上範本 chip 一多就折成好幾行把整張表推下去。
   只讓 chip 那一段橫向捲動、按鈕照常換行——按鈕整個捲到畫面外會找不到「管理範本」。 */
@media (max-width: 575.98px) {
    .toolbar-card-body .shift-tpl-row #tplBadges {
        flex: 1 1 100%;
        flex-wrap: nowrap !important;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        padding-bottom: 0.25rem;
    }
    .toolbar-card-body .shift-tpl-row #tplBadges > * {
        flex: 0 0 auto;
    }
}

/* ========================================
   表格易讀性強化（2026-08-01 UX 評審）
   問題：1440px 下 bookings 右側「狀態/操作」欄被切掉、金額欄左對齊無法目視比大小、
        表頭與資料列同色難分、列高過鬆一屏看不到幾筆。
   做法全為視覺層（不動 DOM/id/class），套在既有 .data-table-body 結構上。
   ======================================== */

/* 1) 長文字欄收窄：顧客/服務/員工這類長名稱不要各佔 300px 把右側欄擠出畫面。
   ⚠️ 數值由實測反推：bookings 在 200px 時表格自然寬 1210px > 容器 1124px，
   溢出 86px 讓 sticky 操作欄整欄蓋掉「狀態」（複評放大 2.5x 證實 10 列全空）。
   收到 170px 後三個長欄各省 30px，總寬回到約 1120px 落在容器內。 */
@media (min-width: 992px) {
    /* ⚠️ 2026-08-02 再收窄 170→150px：操作欄補到 190px（容納 5 顆動作鈕）後表格又變寬，
       實測第 5 顆「詳情」右緣 1423 > 卡片右緣 1408，溢出 15px 仍點不到。
       長文字欄每欄再省 20px（三欄共 60px）足以吸收，且不影響可讀性（本就是省略號顯示）。 */
    .data-table-body td {
        max-width: 150px;
    }
}

/* 2) 操作欄釘在右側：橫捲時「確認/取消/完成」永遠看得到（最後一欄慣例為操作欄）
      ⚠️ 釘住的儲存格必須「繼承列底色」，否則 hover／斑馬／選取列會在列尾露出一塊
      比列身淺的方塊，看起來像渲染壞掉（2026-08-01 複評抓到）。 */
@media (min-width: 992px) {
    /* ⚠️ 用 CSS 變數傳遞列底色，不要用 `background: inherit`：
       inherit 取的是父層「指定值」，在 hover 態下實測沒有跟著更新，
       導致釘住的儲存格與列身出現淺一階的雙色接縫（看起來像渲染壞掉，複評抓到）。
       改用 --row-bg 變數後，hover/斑馬/選取列都能正確傳遞。 */
    /* ⚠️ 必須關掉 Bootstrap 自己的 hover 上色再統一由 --row-bg 供色：
       `.table-hover` 是把 hover 底色畫在【td】的 --bs-table-bg-state（#ececec），
       而我們設在 tr 上的 --row-bg 只有那顆 sticky td 讀得到，兩者值又不同
       → hover 時列身與釘住格呈現兩種灰，出現一條硬邊接縫（第三輪複評取樣證實：
       列身 #ECECEC vs 釘住格 #F7F8FB）。讓所有 cell 讀同一個變數才會真正一致。 */
    .data-table-body table > tbody > tr {
        --row-bg: #fff;
    }
    .data-table-body table > tbody > tr:hover {
        --row-bg: #f2f3f7;
    }
    .data-table-body table.table-hover > tbody > tr > *,
    .data-table-body table > tbody > tr > * {
        --bs-table-bg-state: transparent;
        background-color: var(--row-bg);
    }
    /* ⚠️ 2026-08-02 補 `:not(#shiftsTable)`：作者在另外兩條同類規則（tenant.css 的
       pointer:coarse 版與 ≤991px 版）都寫了排除班表並註明「班表最後一欄是週日不是操作欄」，
       唯獨這條漏掉。iPad 橫向（1024×768）實測：週日欄被釘住後週六被蓋 180px、週五 66px。 */
    .data-table-body table:not(#shiftsTable) > thead > tr > th:last-child,
    .data-table-body table:not(#shiftsTable) > tbody > tr > td:last-child {
        position: sticky;
        right: 0;
        z-index: 2;
        box-shadow: -6px 0 8px -6px rgba(0, 0, 0, 0.12);
    }
    .data-table-body table:not(#shiftsTable) > thead > tr > th:last-child {
        z-index: 3;
        background: #fafafa;
    }
}

/* 992~1199px（iPad 橫向、小筆電視窗）：這個帶寬會溢出，但 2026-08-02 為手機加的
   「讓位 padding」寫在 @media (max-width:991px) 裡完全到不了這裡 →
   釘住的操作欄直接蓋在資料上。實測 1024×768 /tenant/bookings：整個「狀態」欄
   （已確認/待確認徽章）被蓋 130px＝100% 看不到，金額 $1,200 被蓋 60px，共 22 格。
   雖然橫捲到底可以救回來（捲到最右 covN=0），但預設狀態整欄消失且沒有任何提示。
   ≥1200px 不套用：那裡表格多半塞得下，硬加 padding 反而製造不必要的橫捲。 */
@media (min-width: 992px) and (max-width: 1199.98px) {
    /* 2026-09-25 改：這個帶寬「不釘」操作欄。
       ⚠️ 讓位 padding 只在「捲到最右」時有效——預設捲動位置（最左）表格溢出時，
       釘住的操作欄一定落在容器右緣，蓋住當下剛好排在那裡的欄位（bookings／product-orders
       的「狀態」、recurring-bookings、inventory 1100 都被蓋，padding 救不了）。
       只要表格會溢出又釘住最後一欄，預設位置就必然蓋到東西，沒有 padding 值能解。
       這帶改成整張表自然橫捲＋「表格較寬，可左右滑動」提示（tenant.js initTableScrollHints），
       操作欄捲過去一定點得到（2b 已保證不被 overflow:hidden 裁掉）。
       ≥1200 的釘住行為不變；≤991 自 2026-09-30 起同樣不釘（見下方 ⑤）。
       觸控裝置在這一帶也不釘（2026-09-30 把 pointer:coarse 那條改成 ≥1200）；
       守衛 tests/suite/240「觸控平板橫向」1024／1180。 */
    .data-table-body table:not(#shiftsTable) > thead > tr > th:last-child,
    .data-table-body table:not(#shiftsTable) > tbody > tr > td:last-child {
        position: static;
        box-shadow: none;
    }
    /* 同一帶寬也要有手機那條「名稱欄可折行」的逃生口，否則 1024 拿到 max-width:150px 的
       壓縮卻沒有折行 → products 有 5 個品名被切且表格 0 捲動空間（「哥倫比亞 蜜處理 半磅」
       被吃 51px），永遠看不到完整名稱。
       ⚠️ 折行要用 overflow-wrap:break-word（不影響 min-content），不可用 word-break:break-word
       （等同 anywhere，min-content 變成一個字元）；中文本來就逐字可斷，所以另給 min-width，
       否則 staff／services 在 1024 被表格自動版面擠成「一字一行」（2026-09-25）。
       含勾選框的欄（批次勾選）不給 min-width。 */
    .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;
    }
    .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;
    }

    /* 操作欄折行：這個帶寬多半是觸控裝置（iPad 橫向），按鈕被 common.css 的
       `.btn{min-width:44px}` 撐到 44px，四顆就 176px，需要折行才塞得下。
       ⚠️ 「解除寬度上限」那兩行已於 2026-09-04 提升成 `@media (min-width:992px)` 全域
       （見下方區塊），這裡只留窄帶專屬的折行處理，不要再重複宣告。 */
    .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;
    }
    .data-table-body td:last-child:not([colspan]) .btn-group > .btn {
        border-radius: var(--radius-sm, 6px) !important;
    }
}

/* 2b) 操作欄（最後一欄）永遠不受 max-width:150px 與 overflow:hidden 限制
   ────────────────────────────────────────────────────────────────
   ⚠️ 這是同一個 bug 的第三次修：≤991px（2026-08-02）→ 992~1199.98px（同批補）
   → **≥1200px 仍然漏掉**，直到 2026-09-04 全尺寸打點體檢才量出來。
   當時的理由寫著「≥1200px 不套用：那裡表格多半塞得下」——對票券頁是錯的：
   票券列有「檢視/恢復/編輯/刪除」四顆文字鈕（各 57px＝228px）＞ 上面那條 max-width:150px。
   實測（elementFromPoint 在鈕上打 5×5 網格，看最上層是不是它自己）：
     1199 → 25/25 命中（窄帶逃生口生效）
     1280 →  0/15 命中，「刪除」整顆超出儲存格 56px 被 overflow:hidden 永久裁掉
     1366 →  5/25（最常見的筆電解析度）
     1440 → 15/25
     1536 → 25/25（表格自然夠寬）
   顧客列表則是在**觸控** 1280 中招（圖示鈕被 `.btn{min-width:44px}` 撐大後溢出 35px，5/25）。
   店家的症狀是「操作欄只看得到檢視/恢復/編輯，刪除不見了」——沒有捲軸、沒有提示。
   ⚠️ 不可用 isVisible() 驗這條：被裁掉的元素 isVisible() 仍回 true（221 spec 踩過）。
   ⚠️ 刻意只解除「最後一欄」的寬度上限，不動其他欄的 150px（那條是為了把表格總寬
      壓回容器內、避免釘住的操作欄蓋掉「狀態」欄，2026-08-01/02 兩次量測的結果）。
      解除後表格可能變寬，但祖先 `.table-responsive` 是 overflow:auto，使用者捲得到＝救得回來；
      而 overflow:hidden 裁掉是永久失效。兩害相權。
   守衛：tests/suite/240-rwd-list-action-clipped.spec.ts（含 1199／1536 兩個「必須綠」對照組） */
@media (min-width: 992px) {
    .data-table-body td:last-child:not([colspan]) {
        max-width: none !important;
        overflow: visible !important;
    }
}

/* 2c) ≥1200px：操作鈕群超過 190px 就折行——修掉 2b 自己造成的回歸
   ────────────────────────────────────────────────────────────────
   2b 解除上限後票券頁的操作欄從 167px 長到 306px，表格溢出容器 65px，
   而「幫釘住的操作欄讓位」那條 `td:nth-last-child(2){padding-right:200px}` 只寫在
   992~1199.98 窄帶（理由「≥1200px 表格多半塞得下」——解除上限後就不成立了）
   → 1200~1265px 這一帶「狀態」欄被 sticky 操作欄 100% 蓋掉（實測 8 列全部 0/15 命中）。

   ⚠️ 修法刻意**不是**把那條 padding 延伸到 ≥1200。實測（生產頁面套候選 CSS 逐寬度量）：
        延伸 padding → 狀態被蓋 16→32 列、表格溢出 100→766px（更糟）
        本方案       → 狀態被蓋 0、鈕被裁 0、首欄截斷 0、表格溢出 0
   正是原註解警告過的「硬加 padding 反而製造不必要的橫捲」。

   ⚠️ `width: max-content` 不可省：`flex-wrap:wrap` 會讓群組的最小內容寬退化成「一顆鈕」，
      表格自動版面因此把該欄縮窄 → 連本來就塞得下的顧客頁（4 顆圖示鈕共 112px）都被迫折行、
      列高 54→90px。加上它之後只有真的超過 190px 的票券／員工頁（226px）會折，
      顧客／商品／服務／庫存逐位元不變。
   ⚠️ `gap: 1px` 不可省（與窄帶同理）：Bootstrap `.btn-group > .btn` 有負邊距，
      折行後上下兩排會互相重疊 → 最後一顆鈕變成不可點（拿掉重跑：鈕被裁 0→7）。
   ⚠️ 首欄折行不可省：操作欄變寬後票券名稱在 1366/1440 被新截斷且那些格沒有 title，
      hover 也救不回。改成可折行後截斷歸零，而且**列高零成本**（實測只加這條：列高不變）。
   守衛：tests/suite/240-rwd-list-action-clipped.spec.ts「狀態」欄那組（1200/1240 對修前驗紅） */
@media (min-width: 1200px) {
    .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;
        width: max-content;
        max-width: 190px;
    }
    .data-table-body td:last-child:not([colspan]) .btn-group > .btn {
        border-radius: var(--radius-sm, 6px) !important;
    }
    .data-table-body td:first-child,
    .data-table-body td.d-none + td {
        white-space: normal;
        word-break: break-word;
    }
}

/* 3) 數字欄可比大小：等寬數字 + 右對齊（用既有 Bootstrap 的 text-end 或 .num 標記） */
.data-table-body td.text-end,
.data-table-body th.text-end,
.data-table-body .num {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

/* 4) 表頭與資料列拉開層級：淺灰底 + 小字大寫間距，跨頁一致 */
.data-table-body table > thead > tr > th {
    background: #fafafa;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--text-secondary);
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    white-space: nowrap;
}

/* 4b) 長清單表頭吸頂（2026-08-01 複評）：票券頁一次渲染 110+ 列（頁高 5800px），
   捲到中段就忘了哪一欄是什麼。表頭跟著捲動固定在容器頂端。
   ⚠️ sticky 需要捲動容器有明確高度上限才生效，故與下面的 max-height 搭配。 */
.data-table-body table > thead > tr > th {
    position: sticky;
    top: 0;
    z-index: 4;
}

/* 4c) 超長清單給捲動容器高度上限：避免整頁被單一表格拉到數千 px，
   分頁列/頁尾永遠在視窗外。65vh 讓表格自己捲，頁面骨架保持可掌握。
   只在「列數多到值得」時啟用——用 .data-table-scroll 標記，預設不影響既有頁面。
   ⚠️ 高度上限必須掛在 .table-responsive（Bootstrap 給它 overflow-x:auto，
   依規範 overflow-y 連帶變成 auto ⇒ 它才是真正的捲動容器）。掛在外層 .data-table-body
   會讓 thead 的 sticky 相對錯誤的容器計算，視覺上完全不吸頂。 */
/* ⚠️ 僅桌機啟用：手機上「頁面捲動裡再包一層垂直捲動」會吃掉慣性捲動，
   且最後一列被硬切在卡片底緣看起來像渲染壞掉（2026-08-02 複評 mb-coupons 實證）。 */
@media (min-width: 992px) {
    .data-table-body.data-table-scroll > .table-responsive {
        max-height: 65vh;
        overflow-y: auto;
    }
}

/* 4d) 列內動作鈕收緊（2026-08-02）：實測表格本身沒溢出（1124 = 容器寬），
   是「動作鈕群組撐破自己的儲存格」造成最後一顆被畫到卡片外（bookings 5 顆溢 3px、
   customers 4 顆溢 18px）。收緊每顆的左右內距即可回收足夠寬度，不必再犧牲文字欄。 */
@media (min-width: 992px) {
    .data-table-body td .btn-group .btn,
    .data-table-body td .btn-sm {
        padding-left: 0.4rem;
        padding-right: 0.4rem;
    }
    .data-table-body td .btn-group {
        white-space: nowrap;
    }
}

/* 5) 列高收斂：一屏多看 2-3 筆（觸控裝置另有 44px 規則，不受此影響） */
@media (min-width: 992px) and (pointer: fine) {
    .data-table-body table > tbody > tr > td {
        padding-top: 0.55rem;
        padding-bottom: 0.55rem;
    }
}

/* 6) 橫捲提示（2026-08-02 修正掛載對象）：
   ⚠️ 原本掛在 .data-table-body 完全無效，兩個原因：
   ① 真正的捲動容器是子層 .table-responsive（Bootstrap 給它 overflow-x:auto），
      background-attachment:local 掛在非捲動元素上不會隨捲動更新；
   ② 表格 cell 有不透明底色（--row-bg），會把父層的漸層整片蓋掉。
   改用 sticky 偽元素疊在 cell 之上，才是真的「右邊還有，滑一下」的提示。 */
.data-table-body > .table-responsive {
    position: relative;
}

/* 右緣提示：sticky 讓它固定在可視區右側、z-index 高於 cell 背景 */
.data-table-body > .table-responsive::after {
    content: "";
    position: sticky;
    top: 0;
    right: 0;
    float: right;
    width: 28px;
    height: 100%;
    margin-left: -28px;
    pointer-events: none;
    z-index: 3;
    background: linear-gradient(to left, rgba(0, 0, 0, 0.10), rgba(0, 0, 0, 0));
}

/* 捲到最右時不需要提示（用 scroll-driven 不易做，改以「內容未溢出就不顯示」近似：
   表格寬度 ≤ 容器時 sticky 偽元素仍在但視覺影響極小，可接受） */
.data-table-body {
    background:
        linear-gradient(to right, white 30%, rgba(255, 255, 255, 0)) left center / 40px 100% no-repeat,
        linear-gradient(to left, white 30%, rgba(255, 255, 255, 0)) right center / 40px 100% no-repeat,
        radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, 0.1), transparent) left center / 14px 100% no-repeat,
        radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, 0.1), transparent) right center / 14px 100% no-repeat;
    background-attachment: local, local, scroll, scroll;
}

/* ========================================
   詳情頁面
   ======================================== */

.detail-header {
    background: white;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    padding: 1.5rem;
    margin-bottom: 1.5rem;
}

.detail-title {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--dark-color);
    margin-bottom: 0.5rem;
}

.detail-subtitle {
    font-size: 0.875rem;
    color: var(--text-secondary);
}

.detail-section {
    background: white;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    margin-bottom: 1.5rem;
}

.detail-section-header {
    padding: 1rem 1.25rem;
    border-bottom: 1px solid rgba(0, 0, 0, 0.04);
}

.detail-section-title {
    font-weight: 700;
    color: var(--dark-color);
    margin: 0;
}

.detail-section-body {
    padding: 1.25rem;
}

/* 資訊列表 */
.info-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.info-list li {
    display: flex;
    padding: 0.75rem 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.04);
}

.info-list li:last-child {
    border-bottom: none;
}

.info-label {
    flex: 0 0 40%;
    font-weight: 600;
    color: var(--text-secondary);
}

.info-value {
    flex: 1;
    color: var(--dark-color);
}

/* ========================================
   快速操作
   ======================================== */

.quick-actions {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 1rem;
}

.quick-action-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background: white;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    text-decoration: none;
    color: var(--dark-color);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.quick-action-btn:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
    color: var(--primary-color);
}

.quick-action-btn i {
    font-size: 2rem;
    margin-bottom: 0.5rem;
    color: var(--primary-color);
}

.quick-action-btn span {
    font-weight: 600;
    font-size: 0.875rem;
}

/* ========================================
   設定頁面
   ======================================== */

.settings-nav {
    background: white;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    padding: 0.5rem;
}

.settings-nav .nav-link {
    color: var(--dark-color);
    padding: 0.75rem 1rem;
    border-radius: var(--border-radius);
}

.settings-nav .nav-link:hover {
    background-color: var(--light-color);
}

.settings-nav .nav-link.active {
    background-color: var(--primary-color);
    color: white;
}

.settings-content {
    background: white;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    padding: 1.5rem;
}

/* ========================================
   功能商店
   ======================================== */

.feature-card {
    background: white;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.feature-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

.feature-card-header {
    padding: 1.25rem;
    border-bottom: 1px solid rgba(0, 0, 0, 0.04);
}

.feature-card-body {
    padding: 1.25rem;
}

.feature-card-footer {
    padding: 1rem 1.25rem;
    background: rgba(0, 0, 0, 0.02);
    border-top: 1px solid rgba(0, 0, 0, 0.04);
}

.feature-icon {
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    color: white;
}

.feature-price {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--primary-color);
}

.feature-price-unit {
    font-size: 0.75rem;
    color: var(--text-secondary);
}

/* ========================================
   側邊欄設定進度環
   ======================================== */

.sidebar-setup-progress {
    padding: 0.75rem 1rem;
    flex-shrink: 0;
}

.setup-progress-link {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    text-decoration: none;
    color: rgba(255, 255, 255, 0.8);
    padding: 0.5rem;
    border-radius: 0.5rem;
    transition: background 0.15s ease;
}

.setup-progress-link:hover {
    background: rgba(255, 255, 255, 0.1);
    color: white;
}

.progress-ring {
    flex-shrink: 0;
}

.progress-ring-fill {
    transition: stroke-dashoffset 0.6s ease;
}

.setup-progress-label {
    font-size: 0.8rem;
    font-weight: 600;
}

#sidebar.collapsed .setup-progress-label {
    display: none;
}

#sidebar.collapsed .setup-progress-link {
    justify-content: center;
}

/* ========================================
   側邊欄店家 footer
   ======================================== */

.sidebar-footer {
    padding: 0.5rem 1rem;
    flex-shrink: 0;
}

.sidebar-footer-content {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: rgba(255, 255, 255, 0.5);
    font-size: 0.75rem;
}

/* 店家切換器實測只有 21px 高（inline style 寫死 padding:0），而它出現在每一頁。
   用 min-height 拉高——不改 padding 是因為 inline style 的優先權高於 CSS，改 padding 沒用。 */
.tenant-switcher-btn {
    min-height: 36px;
}
@media (pointer: coarse) {
    .tenant-switcher-btn {
        min-height: 44px;
    }
}

.sidebar-footer-icon {
    font-size: 0.875rem;
    flex-shrink: 0;
}

.sidebar-footer-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

#sidebar.collapsed .sidebar-footer-name {
    display: none;
}

#sidebar.collapsed .sidebar-footer-content {
    justify-content: center;
}

/* ========================================
   側邊欄注意圓點
   ======================================== */

.setup-attention-dot {
    position: absolute;
    top: 50%;
    right: 10px;
    transform: translateY(-50%);
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: #f59e0b;
    animation: pulse-dot 2s ease-in-out infinite;
}

/* 下一步：同樣是「還沒完成」的警示色（2026-09-25 由綠色改掉——綠色讀起來像「已完成」），
   用外框與較快的脈動區分「建議先做這一項」 */
.setup-attention-dot.next-step {
    background-color: var(--warning-color, #ff9f0a);
    box-shadow: 0 0 0 2px rgba(255, 159, 10, 0.35);
    animation: pulse-dot-green 1.5s ease-in-out infinite;
}

@keyframes pulse-dot {
    0%, 100% { opacity: 1; transform: translateY(-50%) scale(1); }
    50% { opacity: 0.6; transform: translateY(-50%) scale(1.3); }
}

@keyframes pulse-dot-green {
    0%, 100% { opacity: 1; transform: translateY(-50%) scale(1); }
    50% { opacity: 0.7; transform: translateY(-50%) scale(1.4); }
}

#sidebar.collapsed .setup-attention-dot {
    right: 6px;
    top: 8px;
    transform: none;
}

/* ========================================
   新手引導卡片
   ======================================== */

.onboarding-card {
    /* 2026-08-25：卡內有長 URL（預約頁連結），手機上會把整張卡撐出水平捲軸。
       min-width:0 讓它能被 grid/flex 父層壓縮；子層另有 overflow-wrap 負責斷行。 */
    min-width: 0;
    max-width: 100%;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border-radius: var(--border-radius-lg, 0.75rem);
    margin-bottom: 1.5rem;
    overflow: hidden;
    box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3);
}

.onboarding-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding: 1.25rem 1.5rem 0.75rem;
    color: white;
}

.onboarding-title {
    font-size: 1.1rem;
    font-weight: 700;
    margin: 0;
    color: white;
}

.onboarding-subtitle {
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.8);
    margin-top: 0.25rem;
}

.onboarding-close {
    background: rgba(255, 255, 255, 0.15);
    border: none;
    color: white;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 0.15s;
    flex-shrink: 0;
}

.onboarding-close:hover {
    background: rgba(255, 255, 255, 0.3);
}

.onboarding-progress-bar {
    height: 4px;
    background: rgba(255, 255, 255, 0.2);
    margin: 0 1.5rem;
    border-radius: 2px;
    overflow: hidden;
}

.onboarding-progress-fill {
    height: 100%;
    background: white;
    border-radius: 2px;
    transition: width 0.6s ease;
}

.onboarding-body {
    padding: 1rem 1.5rem 1.25rem;
}

/* 排不下就換行，永遠不橫捲（2026-08-27 修）。
   2026-08-25 只把 ≤991 改成 wrap，992~1199 仍是「捲軸被藏起來的橫捲條」：實測 992px 第 5 步
   「連接 LINE Bot」露 0%、1024px 露 0%、1100/1150/1200 露 41/73/94%，1280 起才全露——
   而 scrollbar-width:none + ::-webkit-scrollbar{display:none} 讓畫面上完全沒有「右邊還有」的提示，
   店家看不到也不知道要捲，偏偏被藏掉的正是這張卡最關鍵的一步。
   ⚠️ 不要改回 overflow-x:auto——捲軸藏起來的橫捲＝把內容藏死；要橫捲就得留捲軸或漸層提示。
   wrap 對「排得下的寬度」零影響（≥1280 仍是一列五張）。
   ⚠️ 也不要在 media query 裡覆寫 .onboarding-step 的 flex：8/25 寫的
   `.onboarding-step{flex:1 1 calc(50% - .75rem)}` 是死碼——同特異度 (0,1,0) 的基底規則
   `.onboarding-step{flex:1}` 在原始碼順序上排在它後面直接蓋掉（768px 實測 computed flex-basis: 0%），
   實際排版一直是靠 wrap + min-width:160px 自然折成 3+2。要覆寫請提高特異度並重新實測每個斷點。 */
.onboarding-steps {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    padding-bottom: 0.25rem;
}

.onboarding-step {
    flex: 1;
    min-width: 160px;
    background: rgba(255, 255, 255, 0.12);
    border-radius: 0.625rem;
    padding: 1rem;
    text-decoration: none;
    color: white;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    transition: background 0.15s, transform 0.15s;
    position: relative;
}

.onboarding-step:hover {
    background: rgba(255, 255, 255, 0.2);
    transform: translateY(-2px);
    color: white;
}

.onboarding-step .step-icon {
    font-size: 1.5rem;
    line-height: 1;
}

.onboarding-step .step-title {
    font-weight: 700;
    font-size: 0.875rem;
}

.onboarding-step .step-desc {
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.7);
    line-height: 1.3;
}

.onboarding-step .step-status {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    font-size: 1rem;
    opacity: 0.7;
}

.onboarding-step.completed {
    opacity: 0.55;
}

.onboarding-step.completed .step-status {
    opacity: 1;
    color: #a7f3d0;
}

.onboarding-step.next-step {
    background: rgba(255, 255, 255, 0.22);
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.3);
}

.onboarding-step.next-step .step-status {
    opacity: 1;
    color: white;
}

.onboarding-complete {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    padding: 1.5rem;
    color: white;
}

.onboarding-complete .complete-icon {
    font-size: 2.5rem;
    color: #a7f3d0;
}

.onboarding-complete .complete-text strong {
    font-size: 1.1rem;
}

.onboarding-complete .complete-text p {
    color: rgba(255, 255, 255, 0.7);
}

.onboarding-next-actions {
    width: 100%;
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 4px;
}

.onboarding-next-actions .btn-light {
    color: #4a3b8f;
    font-weight: 600;
    border: none;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.onboarding-next-actions .btn-light:hover {
    background: #fff;
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

