/* ============================================================
 *  專案自訂樣式（載入順序在 styles.css 之後）
 *
 *  ★ 為什麼要獨立成一個檔：
 *    assets/css/styles.css 是 design/shared/css/styles.css 的**副本**，
 *    日後可能會從 design 重新複製一份過來。
 *    把自己加的規則寫在那裡，重新複製時就會被蓋掉。
 *    凡是 design 沒有、屬於正式系統才需要的樣式，一律寫在本檔。
 * ============================================================ */


/* ------------------------------------------------------------
 *  表單欄位對齊
 *
 *  問題：.form-grid 是兩欄格線，列高由該列最高的欄位決定；
 *       而 .form-field 自己是 display:grid，預設 align-content:stretch，
 *       會把 label / input 拉伸去填滿整個列高。
 *       結果：同一列中，只要有一欄多了說明文字（.field-help），
 *       另一欄的輸入框就會被撐高，兩個輸入框上下對不齊。
 *
 *  修法：內容靠上排列，不隨列高拉伸。
 *       這樣不論哪一欄有沒有說明文字，label 與 input 的位置都一致。
 * ------------------------------------------------------------ */
.form-field {
    align-content: start;
}

/* 說明文字固定貼在輸入框下方，不被格線推開 */
.form-field .field-help {
    margin-top: -1px;
    line-height: 1.5;
}


/* ------------------------------------------------------------
 *  圖形驗證碼欄位（登入視窗）
 *  design 沒有這個元件 —— 驗證碼是正式系統才加的。
 * ------------------------------------------------------------ */
.authcode-row {
    display: flex;
    gap: 10px;
    align-items: stretch;
}

.authcode-row input {
    flex: 1;
    min-width: 0;
    letter-spacing: 2px;
}

.authcode-row img {
    flex: none;
    width: 120px;
    height: auto;
    align-self: stretch;
    object-fit: cover;
    border: 1px solid #d5ded8;
    border-radius: 10px;
    cursor: pointer;
    background: #f5f7f5;
}

.authcode-row img:hover {
    border-color: #1b7546;
}

/* ------------------------------------------------------------
 *  後台的共用確認視窗（審核通過、駁回都走這一份）
 *  版型在 &Maint_Vege2026/admin.php，元件沒有的兩個行為補在這裡。
 * ------------------------------------------------------------ */

/* ★ 這條不能拿掉：styles.css 的 .modal-backdrop 是 display:grid，
 *   作者樣式會蓋過瀏覽器預設的 [hidden]{display:none}，
 *   沒有這條的話視窗在 hidden 狀態下依然會整片蓋住畫面。
 *   design 不需要這條，是因為它的視窗是用 JS 當場插入 / 移除的。 */
.modal-backdrop[hidden] {
    display: none;
}

/* 視窗打開時鎖住背後的捲軸 */
body.modal-open {
    overflow: hidden;
}

/* ★ .form-field 也是 display:grid（理由同上）——
 *   確認視窗的「原因」欄位是用 hidden 控制顯示的，不補這條
 *   就會在「通過」這種不需要填原因的場合也跟著出現。 */
.form-field[hidden] {
    display: none;
}

/* 確認視窗：「即將通過／駁回…」那一行 */
.confirm-message {
    margin: 0 0 18px;
    color: var(--muted);
    font-size: 14px;
    line-height: 1.7;
}

.confirm-message strong {
    color: var(--ink);
}

/* 錯誤訊息在視窗裡需要上方間距，沒錯誤時不佔位置 */
#adminConfirmError:not(:empty) {
    margin-top: 14px;
}

/* ------------------------------------------------------------
 *  等待遮罩（前後台共用，行為在 assets/js/loading.js）
 *
 *  註冊要同步寄兩封信，實測約 5 秒才回應；
 *  沒有遮罩的話畫面完全沒反應，使用者會以為當機而重複送出。
 * ------------------------------------------------------------ */
.qn-loading {
    position: fixed;
    inset: 0;
    z-index: 900;          /* 要蓋在 .modal-backdrop（500）之上 */
    display: grid;
    place-items: center;
    padding: 24px;
    background: rgba(9, 27, 18, .42);
}

/* ★ 同 .modal-backdrop 的理由：作者樣式的 display 會蓋過
 *   瀏覽器預設的 [hidden]{display:none}，不補這條就永遠蓋住畫面。 */
.qn-loading[hidden] {
    display: none;
}

/* ★ toast 要浮在遮罩之上。
 *   styles.css 給 .toast-root 的 z-index 是 900，和 .qn-loading 一樣；
 *   而遮罩是 loading.js 後來 append 到 body 的，同分時後者贏 ——
 *   結果遮罩期間出現的提示訊息完全看不到。 */
.toast-root {
    z-index: 950;
}

.qn-loading-box {
    display: grid;
    justify-items: center;
    gap: 14px;
    min-width: 210px;
    padding: 28px 36px;
    background: #fff;
    border-radius: 18px;
    box-shadow: 0 30px 80px rgba(9, 27, 18, .25);
    text-align: center;
}

.qn-spinner {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    border: 3px solid var(--green-100, #eaf5ed);
    border-top-color: var(--green-700, #1b7546);
    animation: qn-spin .8s linear infinite;
}

@keyframes qn-spin {
    to { transform: rotate(360deg); }
}

/* 有前庭需求的使用者不要快速旋轉，但仍需看得出「還在跑」 */
@media (prefers-reduced-motion: reduce) {
    .qn-spinner { animation-duration: 2.4s; }
}

.qn-loading-text {
    color: var(--green-900, #0f4a30);
    font-size: 15.5px;
    font-weight: 700;
}

.qn-loading-note {
    margin-top: -6px;
    color: var(--muted, #68746d);
    font-size: 13px;
    line-height: 1.6;
}

.qn-loading-note[hidden] {
    display: none;
}


/* ------------------------------------------------------------
 *  註冊完成的提示視窗
 *  design 是把成功訊息鐵在表單下方、把送出鈕停用；
 *  這裡改成單獨一個視窗 —— 申請送出後表單已經沒有用了，
 *  繼續顯示一大堆欄位只會讓人以為還要再填一次。
 * ------------------------------------------------------------ */
.register-done {
    display: grid;
    justify-items: center;
    gap: 14px;
    padding: 8px 4px 4px;
    text-align: center;
}

.register-done-icon {
    display: grid;
    place-items: center;
    width: 66px;
    height: 66px;
    border-radius: 50%;
    background: var(--green-100, #eaf5ed);
    color: var(--green-700, #1b7546);
}

.register-done-icon .icon {
    width: 34px;
    height: 34px;
}

.register-done h3 {
    margin: 0;
    font-size: 20px;
    font-weight: 900;
    color: var(--green-950, #0a3523);
}

.register-done p {
    margin: 0;
    max-width: 42ch;
    color: var(--muted, #68746d);
    font-size: 14px;
    line-height: 1.8;
}

.register-done-count {
    font-size: 13px;
    color: var(--muted, #68746d);
}

.register-done-count b {
    color: var(--green-700, #1b7546);
    font-variant-numeric: tabular-nums;
}

.register-done .btn {
    margin-top: 4px;
    min-width: 160px;
}

/* ------------------------------------------------------------
 *  可收合面板（後台商品管理的「商品分類」）
 *
 *  ★ 用原生的 <details>／<summary>：不必寫 JS，
 *    鍵盤操作、aria-expanded 狀態、預設收起都是瀏覽器已經做好的。
 *  ★ 收合條要一眼看得出「可以點」：
 *    給它深色底 + 手指游標 + 會轉的箭頭 + hover 變色，
 *    四個線索加起來才不會被當成一行普通標題。
 * ------------------------------------------------------------ */
.admin-fold {
    overflow: hidden;
}

.admin-fold-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 15px 20px;
    background: var(--green-050, #f5faf6);
    border-bottom: 1px solid transparent;
    cursor: pointer;
    user-select: none;
    list-style: none;            /* 拿掉瀏覽器預設的三角標記 */
    transition: background .15s ease;
}

.admin-fold-head::-webkit-details-marker { display: none; }

.admin-fold-head:hover {
    background: var(--green-100, #eaf5ed);
}

.admin-fold-head:focus-visible {
    outline: 2px solid var(--green-700, #1b7546);
    outline-offset: -2px;
}

/* 展開時才出現分隔線，收起時不要多一條 */
.admin-fold[open] .admin-fold-head {
    border-bottom-color: var(--line, #dce6df);
}

.admin-fold-icon {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    flex: none;
    border-radius: 50%;
    background: var(--green-700, #1b7546);
    color: #fff;
    transition: transform .18s ease;
}

.admin-fold-icon .icon {
    width: 15px;
    height: 15px;
}

.admin-fold[open] .admin-fold-icon {
    transform: rotate(90deg);
}

@media (prefers-reduced-motion: reduce) {
    .admin-fold-icon { transition: none; }
}

.admin-fold-title {
    font-size: 16px;
    font-weight: 800;
    color: var(--green-950, #0a3523);
}

/* 分類數量，收起時也看得到裡面有幾筆 */
.admin-fold-count {
    min-width: 24px;
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--green-700, #1b7546);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------
 *  商品分類：卡片格線（後台商品管理的收合面板裡）
 *
 *  ★ 為什麼不用表格：原本每一列是 4 個輸入框 + 一個原生的
 *    <input type="file">，6 個分類就有 24 個邊框與 6 行
 *    「選擇檔案／未選擇任何檔案」的灰字，畫面全是方格子，
 *    而且分類是「有圖的東西」，40px 的縮圖等於看不到。
 *    列表只負責「看」，要改哪一筆才把表單叫出來（#typeEdit）。
 * ------------------------------------------------------------ */
.type-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(178px, 1fr));
    gap: 14px;
    padding: 18px 20px 20px;
}

.type-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--surface, #fff);
    border: 1px solid var(--line, #dce6df);
    border-radius: var(--radius-md, 13px);
    overflow: hidden;
    transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}

.type-card:hover {
    border-color: var(--green-500, #48a56a);
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
}

.type-card-media {
    position: relative;
    aspect-ratio: 1.6 / 1;
    background: var(--green-050, #f5faf6);
}

/* ★ img 要脫離文件流（position:absolute），否則卡片圖片會高矮不齊。
 *   原因：.type-card 是 flex column，.type-card-media 是它的項目；
 *   項目的 aspect-ratio 要靠「內容不決定高度」才算得出來，
 *   而 img 的 height:100% 在高度未定的父層上會退回 auto、改用圖片自己的比例，
 *   於是直式的照片就把整個 media 撐高（實測 135px vs 應有的 116px）。
 *   讓 img 絕對定位，media 的高度就只由 aspect-ratio 決定。 */
.type-card-media img {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* 排序：直接標在圖上，不必為了看一個數字多開一欄 */
.type-card-sort {
    position: absolute;
    top: 8px;
    left: 8px;
    min-width: 24px;
    height: 24px;
    display: grid;
    place-items: center;
    padding: 0 6px;
    border-radius: 999px;
    background: rgba(10, 53, 35, .72);
    color: #fff;
    font-size: 12.5px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* 數字與握把疊在同一格，靠 visibility 互換 —— 用 display 切換的話
   徽章寬度會在 hover 時跳一下。 */
.type-card-sort-num,
.type-card-sort-grip {
    grid-area: 1 / 1;
}

.type-card-sort-num { font-weight: 700; }

.type-card-sort-grip {
    display: grid;
    place-items: center;
    visibility: hidden;
}

.type-card-sort-grip .icon {
    width: 15px;
    height: 15px;
    fill: currentColor;
}

.type-card:hover .type-card-sort-num { visibility: hidden; }
.type-card:hover .type-card-sort-grip { visibility: visible; }

/* 停用的分類整張退成灰階，掃一眼就看得出來 */
.type-card.is-off .type-card-media img {
    filter: grayscale(1);
    opacity: .55;
}

.type-card-body {
    display: grid;
    gap: 3px;
    padding: 10px 12px 12px;
}

.type-card-name {
    margin: 0;
    font-size: 15.5px;
    font-weight: 800;
    line-height: 1.35;
    color: var(--green-950, #0a3523);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.type-card-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-height: 28px;
    font-size: 12px;
    color: var(--muted, #68746d);
}

.type-card-count {
    font-variant-numeric: tabular-nums;
}

/* 滑鼠移過去時把圖壓暗，是給滑鼠使用者的即時回饋（沒有也不影響操作） */
.type-card-media::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(10, 53, 35, .04), rgba(10, 53, 35, .24));
    opacity: 0;
    transition: opacity .15s ease;
}

.type-card:hover .type-card-media::after {
    opacity: 1;
}

/* 角標與「編輯」要壓在上面那層漸層之上 */
.type-card-sort,
.type-card-pin {
    z-index: 1;
}

/* 卡片右上角的刪除鈕（與左上角的序號徽章對稱）。
 *
 * ★ 常駐顯示，不是 hover 才出現 —— 理由同下面的「編輯」提示。
 * ★ z-index 不能拿掉：整張卡都被 .type-card-edit（inset:0）蓋住，
 *   要浮到它上面才點得到（同 .adm-switch）。
 * ★ 平常是中性的灰，不是一片紅 —— 每張卡都掛一顆紅按鈕太吵，
 *   而且刪除本來就不該是最顯眼的動作。hover／focus 才轉紅。
 */
.type-card-del {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 2;
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    padding: 0;
    border-radius: 999px;
    background: #fff;
    border: 1px solid var(--line, #dce6df);
    color: var(--muted, #68746d);
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(10, 53, 35, .16);
    transition: color .15s ease, border-color .15s ease;
}

.type-card-del .icon {
    width: 17px;
    height: 17px;
}

.type-card-del:hover,
.type-card-del:focus-visible {
    color: var(--danger, #c0392b);
    border-color: var(--danger, #c0392b);
}

.type-card-del:focus-visible {
    outline: 2px solid var(--danger, #c0392b);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .type-card-del { transition: none; }
}

/* ★ 「編輯」是常駐的，不是 hover 才出現。
 *   hover 才浮出來的提示，對不習慣操作滑鼠的人等於看不到「這裡可以點」——
 *   他們得先把游標準確移到卡片上才知道有這個功能。 */
.type-card-pin {
    position: absolute;
    right: 8px;
    bottom: 8px;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    min-height: 34px;
    padding: 0 12px;
    border-radius: 999px;
    background: #fff;
    border: 1px solid var(--line, #dce6df);
    color: var(--green-800, #145f3a);
    font-size: 13px;
    font-weight: 800;
    box-shadow: 0 2px 8px rgba(10, 53, 35, .18);
    pointer-events: none;        /* 點擊交給底下那顆覆蓋整張卡的按鈕 */
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}

.type-card-pin .icon {
    width: 15px;
    height: 15px;
}

.type-card:hover .type-card-pin {
    background: var(--green-700, #1b7546);
    border-color: var(--green-700, #1b7546);
    color: #fff;
}

/* 整張卡都是按鈕 —— 目標大，不必瞄準那顆小小的「編輯」。
 * ★ 游標用 grab 不用 pointer：整張卡同時是「點了會開編輯視窗」與
 *   「按住可以拖動排序」。「可以點」已經由常駐的「編輯」標籤講清楚了，
 *   游標就留給比較不明顯的那件事 —— 拖曳。 */
.type-card-edit {
    position: absolute;
    inset: 0;
    border: 0;
    background: transparent;
    font: inherit;
    cursor: grab;
}

.type-card-edit:focus-visible {
    outline: 2px solid var(--green-700, #1b7546);
    outline-offset: -3px;
}

.type-card:focus-within .type-card-pin {
    background: var(--green-700, #1b7546);
    border-color: var(--green-700, #1b7546);
    color: #fff;
}

/* 新增：虛線佔位卡，跟現有分類明顯不同，不必再放一顆「新增」按鈕 */
.type-card-add {
    display: grid;
    place-items: center;
    align-content: center;
    gap: 8px;
    min-height: 100%;
    padding: 24px 12px;
    border: 1.5px dashed var(--line, #dce6df);
    border-radius: var(--radius-md, 13px);
    background: var(--green-050, #f5faf6);
    color: var(--green-700, #1b7546);
    font: inherit;
    font-size: 14px;
    font-weight: 800;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease;
}

.type-card-add:hover {
    border-color: var(--green-500, #48a56a);
    background: var(--green-100, #eaf5ed);
}

.type-card-add .type-add-icon {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: var(--surface, #fff);
    border: 1px solid var(--line, #dce6df);
}

.type-card-add .icon {
    width: 19px;
    height: 19px;
}

@media (prefers-reduced-motion: reduce) {
    .type-card,
    .type-card-media::after,
    .type-card-pin,
    .type-card-add { transition: none; }
    .type-card:hover { transform: none; }
}


/* ------------------------------------------------------------
 *  商品分類的編輯視窗（#typeEdit）
 *  版型沿用 design 的 .modal-*，只補這裡才需要的三件事。
 * ------------------------------------------------------------ */
.type-modal .modal {
    max-width: 520px;
}

/* 圖片本身就是上傳按鈕 —— 原生的 <input type="file"> 已用 hidden 藏起來，
 * 它的「選擇檔案／未選擇任何檔案」是整個舊版面最醜的一塊，而且無法改樣式。 */
.type-form-media {
    position: relative;
    aspect-ratio: 2.4 / 1;
    margin-bottom: 16px;
    border-radius: var(--radius-md, 13px);
    overflow: hidden;
    background: var(--green-050, #f5faf6);
    border: 1px solid var(--line, #dce6df);
}

.type-form-media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* 新分類還沒有圖：不要顯示破圖，直接把上傳提示常駐 */
.type-form-media.is-empty img {
    display: none;
}

.type-form-upload {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    cursor: pointer;
    background: linear-gradient(180deg, rgba(10, 53, 35, 0), rgba(10, 53, 35, .34));
    opacity: 0;
    transition: opacity .15s ease;
}

.type-form-media:hover .type-form-upload,
.type-form-upload:focus-within,
.type-form-media.is-empty .type-form-upload {
    opacity: 1;
}

.type-form-media.is-empty .type-form-upload {
    background: none;
}

.type-form-upload span {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 16px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .96);
    color: var(--green-800, #145f3a);
    font-size: 13.5px;
    font-weight: 800;
    box-shadow: 0 4px 14px rgba(10, 53, 35, .2);
}

.type-form-upload em {
    font-style: normal;
}

.type-form-upload .icon {
    width: 16px;
    height: 16px;
}

@media (prefers-reduced-motion: reduce) {
    .type-form-upload { transition: none; }
}

/* 把「取消／儲存」推到視窗右側（#adminEdit、#myAccount 都在用）。
   ★ 原本是為了把分類視窗的刪除鈕隔到最左邊，那顆鈕已經移到卡片上了，
     但這條仍然有用：沒有它，兩顆鈕會靠左擠在一起。 */
.type-modal-spacer {
    flex: 1;
}

/* ★ 同 .form-field[hidden] 的理由：.modal-actions 是 flex，裡面的 .btn 又是
 *   inline-flex，作者樣式會蓋過瀏覽器預設的 [hidden]{display:none}。
 *   不補這條的話：「新增分類」會出現刪除鈕、
 *   純警告的視窗也會出現多餘的「取消」。
 *   ★ 是所有 .modal-actions，不只分類那一個 —— 共用確認視窗也要。 */
.modal-actions [hidden] {
    display: none;
}


/* ============================================================
 *  操作尺寸：把太小的按鈕與文字放大
 *
 *  起因：後台表格裡的操作按鈕只有 46×32px、12px 字，
 *  加上一堆 11～12px 的說明文字，對不習慣操作滑鼠的人很難點、也很難讀。
 *
 *  ★ 為什麼寫在這裡，而不是直接改 admin.css / styles.css：
 *    那兩份都是 design 的副本（見 CLAUDE.md §10），日後可能整份重新複製過來，
 *    改在那裡會被蓋掉。這是「正式系統的可用性調整」，design 原稿刻意不跟進。
 *
 *  ★ 因此 site.css 在 admin.php 已改成**最後**載入 ——
 *    .btn-sm 等規則定義在 admin.css，不排在它後面就蓋不掉。
 *
 *  ★ 基準：可點的東西至少 40px 高（原本 32px），
 *    正文與說明文字不低於 12.5px（原本有 11px）。
 * ------------------------------------------------------------ */

/* 後台表格裡的主力按鈕：編輯／上架／下架／儲存／刪除／指派 */
.btn-sm {
    min-height: 40px;          /* 原 32px */
    padding: 8px 15px;         /* 原 5px 10px */
    border-radius: 9px;
    font-size: 14px;           /* 原 12px */
}

/* 同一格裡的按鈕要有間隔，手抖才不會按到隔壁那顆 */
.table-actions,
.admin-form-actions {
    gap: 10px;                 /* 原 6px */
}

/* 純圖示的按鈕（視窗的關閉鈕、手機版選單）：40 → 44，補到常見的最小點擊目標 */
.icon-btn {
    width: 44px;
    height: 44px;
}

/* 狀態徽章：雖然不能點，但它是表格裡最常要讀的一欄 */
.status {
    padding: 6px 11px;
    font-size: 13px;           /* 原 11～12px */
}

/* 表格標題列 */
.admin-table th {
    font-size: 14px;           /* 原 13px */
}

/* ---- 以下都是原本 11～12px 的說明性文字 ---- */
.field-help,
.panel-caption,
.admin-detail-summary-item > span,
.admin-status-count span,
.admin-chart-label,
.admin-order-period-label {
    font-size: 13px;           /* 原 12px */
}

.metric-note,
.admin-alert-row div > span,
.admin-shortcut small,
.admin-person small,
.admin-cell-sub,
.admin-level-badge,
.table-product small,
.admin-product-preview > span {
    font-size: 12.5px;         /* 原 11px */
}

/* 頁面標題底下那行說明 */
.page-sub {
    font-size: 14px;           /* 原 13px */
}


/* ------------------------------------------------------------
 *  商品分類：拖曳排序（行為在 &Maint_Vege2026/js/admin.js 的 bindTypeSort()）
 * ------------------------------------------------------------ */

/* 拖曳進行中：整片格線都維持「抓著」的游標，
   不然游標移到卡片之間的空隙時會變回箭頭，像是拖曳斷掉了。 */
.type-grid.is-sorting,
.type-grid.is-sorting .type-card-edit {
    cursor: grabbing;
}

/* 拖曳中的那張卡：淡化 + 虛線框，讓人看得出「這張正在被搬」。
   ★ pointer-events:none 不能拿掉 —— elementFromPoint() 要靠它才拿得到
     「游標底下那張卡」，否則永遠只會拿到正在拖的自己，卡片就換不了位置。 */
.type-card.is-dragging {
    opacity: .45;
    pointer-events: none;
    outline: 2px dashed var(--green-500, #48a56a);
    outline-offset: -2px;
}

/* 拖曳中不要有位移動畫，否則卡片換位時會整片抖動 */
.type-grid.is-sorting .type-card {
    transition: none;
}

.type-grid.is-sorting .type-card:hover {
    transform: none;
}

/* 拖曳時整片文字容易被反白選取，看起來很髒 */
.type-grid.is-sorting {
    user-select: none;
}


/* ------------------------------------------------------------
 *  開關（分類卡片的啟用／停用、商品列表的上下架，共用同一個元件）
 *
 *  ★ 商品列表原本是一顆 .btn-muted 的「下架」按鈕 —— 灰灰的，
 *    看起來像是停用中、按不下去。而且它和旁邊的「狀態」欄講的是同一件事：
 *    一欄顯示現況、一欄放反向動作，要讀兩次才知道現在到底是上架還是下架。
 *    改成開關之後，一個東西同時表達「現在的狀態」與「可以切換」。
 *
 *  ★ 分類卡片上為什麼也是開關：分類底下還有商品時**不能刪除**，
 *    這時唯一的手段就是停用 —— 把最常用的動作藏進編輯視窗不合理。
 * ------------------------------------------------------------ */
.adm-switch {
    /* ★ z-index 不能拿掉：整張卡都被 .type-card-edit（inset:0）蓋住，
     *   而且它在 DOM 裡比較後面、本來就畫在上層。
     *   開關要浮到它上面才點得到。 */
    position: relative;
    z-index: 2;

    flex: none;
    display: grid;
    place-items: center;
    /* 開關本體只有 38×22，但點擊範圍撐到 44px 寬、28px 高 —— 
       小小的滑桿對手不穩的人很難點。 */
    width: 44px;
    height: 28px;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
}

.adm-switch-track {
    display: block;
    width: 38px;
    height: 22px;
    border-radius: 999px;
    background: var(--green-700, #1b7546);
    transition: background .15s ease;
}

.adm-switch-knob {
    display: block;
    width: 16px;
    height: 16px;
    margin: 3px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(10, 53, 35, .35);
    transform: translateX(16px);
    transition: transform .15s ease;
}

/* 停用 */
.adm-switch[aria-checked="false"] .adm-switch-track {
    background: #c2ccc6;
}

.adm-switch[aria-checked="false"] .adm-switch-knob {
    transform: translateX(0);
}

.adm-switch:disabled {
    opacity: .5;
    cursor: default;
}

.adm-switch:focus-visible .adm-switch-track {
    outline: 2px solid var(--green-700, #1b7546);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .adm-switch-track,
    .adm-switch-knob { transition: none; }
}

/* 停用的分類：圖片轉灰階（.type-card.is-off 已有規則），
   文字也一起淡下來，掃一眼就分得出來 */
.type-card.is-off .type-card-name {
    color: var(--muted, #68746d);
}

/* ------------------------------------------------------------
 *  必填欄位的紅色星號
 *
 *  ★ 用 :has(:required) 自動判斷，不是手動加 class ——
 *    星號代表的是「不填的話瀏覽器會擋下來」，
 *    手動標記遲早會跟實際的 required 屬性對不起來，那就變成誤導。
 *    這樣寫，星號永遠等於真實狀態。
 *
 *  ★ 涵蓋兩種欄位容器：.form-field（多數表單）與 .field（後台登入頁）。
 *  ★ 沒有標星號的欄位有兩類，都不是漏掉：
 *    一是真的可以不填（配送地址、產地、產銷履歷、商品介紹…）；
 *    二是下拉選單本來就一定有值（商品分類、上下架…），不可能空著送出。
 * ------------------------------------------------------------ */
.form-field:has(:required) > label::after,
.field:has(:required) > label::after {
    content: '＊';
    margin-left: 2px;
    color: var(--danger, #b13e3e);
    font-weight: 900;
}


/* 上傳欄位下方的規則提示（會擋人的限制要先講，不要等被退回才知道） */
.type-form-hint {
    margin: -8px 0 16px;
    color: var(--muted, #68746d);
    font-size: 13px;
    line-height: 1.6;
    text-align: center;
}


/* ------------------------------------------------------------
 *  分頁列（後端分頁）—— 前後台共用這一份樣式，版型元件各有一支：
 *    後台 &Maint_Vege2026/inc/helpers.php 的 adm_pager()
 *    前台 includes/render.php 的 pager()
 *  ★ class 名稱沿用 adm- 開頭（前台也是），是為了不要再複製一份一模一樣的樣式 ——
 *    複製遲早會漂移，而兩邊的分頁列本來就該長得一樣。
 *
 *  ★ 頁碼是最容易被做得太小的東西 —— 它就是一排數字，
 *    很自然會想把它縮小。這裡沿用本專案的基準：
 *    可點的東西至少 40px 高、字不小於 14px。
 * ------------------------------------------------------------ */
.adm-pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 16px 20px 20px;
}

.adm-pager-num,
.adm-pager-step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    height: 40px;
    padding: 0 12px;
    border: 1px solid var(--line, #dce6df);
    border-radius: 9px;
    background: var(--surface, #fff);
    color: var(--ink, #18231d);
    font-size: 14px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-decoration: none;
    transition: border-color .15s ease, background .15s ease;
}

a.adm-pager-num:hover,
a.adm-pager-step:hover {
    border-color: var(--green-500, #48a56a);
    background: var(--green-050, #f5faf6);
}

.adm-pager-num.is-current {
    background: var(--green-700, #1b7546);
    border-color: var(--green-700, #1b7546);
    color: #fff;
}

/* 已經在第一／最後一頁：留著佔位但不能點，
   讓「上一頁／下一頁」的位置不會跳來跳去 */
.adm-pager-step.is-disabled {
    opacity: .45;
    cursor: default;
}

.adm-pager-gap {
    padding: 0 2px;
    color: var(--muted, #68746d);
}

.adm-pager :focus-visible {
    outline: 2px solid var(--green-700, #1b7546);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .adm-pager-num,
    .adm-pager-step { transition: none; }
}

/* 「第 X / Y 頁」—— 只有一頁時分頁列就只剩這一行 */
.adm-pager-info {
    margin-left: 8px;
    color: var(--muted, #68746d);
    font-size: 13px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* 篩選列裡的「每頁 N 筆」 */
.adm-per-page {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
    color: var(--muted, #68746d);
    font-size: 13px;
    font-weight: 700;
}

.adm-per-page select {
    min-width: 72px;
}

/* ★ 下架的商品「不要」把整列淡化。
 *   一度是這樣做的，但淡掉的列看起來像是唯讀的，
 *   會讓人以為下架之後就不能編輯了 —— 其實下架的商品照樣可以改。
 *   狀態由開關本身表達（灰=下架、綠=上架）就夠了。
 *   分類卡片的淡化保留：那裡淡的是「圖片」，不是整張卡的可操作性。 */


/* 商品編輯頁的規格／份量：數字 + 單位排成一列 */
.spec-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.spec-row input[type="number"] {
    width: 110px;
    flex: none;
}

.spec-row select {
    width: auto;
    min-width: 92px;
    flex: none;
}

.spec-sep {
    color: var(--muted, #68746d);
    font-size: 14px;
    font-weight: 700;
    white-space: nowrap;
}

/* 商品編輯頁：「上下架」移到預覽底下（見 admin_ProductEdit.php 的說明） */
.preview-publish {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--line, #dce6df);
}

/* ------------------------------------------------------------
 *  後台人員管理（?P=Master）
 * ------------------------------------------------------------ */

/* 權限視窗：一頁一列，右邊一個開關 */
.fun-list {
    border: 1px solid var(--line, #dce6df);
    border-radius: var(--radius-sm, 10px);
    overflow: hidden;
}

.fun-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 9px 14px;
    border-bottom: 1px solid var(--line, #dce6df);
    background: #fff;
}

.fun-row:last-child { border-bottom: 0; }
.fun-row:nth-child(even) { background: var(--surface-2, #f8faf8); }

.fun-row-name {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--ink, #18231d);
}

/* 超級管理員時開關會被鎖住 —— 讓它看得出「不能動」但仍看得出狀態 */
.fun-row .adm-switch:disabled {
    opacity: .5;
    cursor: default;
}

/* 「超級管理員不受權限設定影響」的說明 */
.fun-note {
    margin: 0 0 14px;
    padding: 11px 14px;
    border-radius: 10px;
    background: var(--accent-soft, #f8edd2);
    color: #6d5316;
    font-size: 13.5px;
    line-height: 1.7;
}

.fun-note[hidden] { display: none; }

/* ★ 不能拿掉：.form-field 是 display:grid，作者樣式會蓋過瀏覽器預設的
 *   [hidden]{display:none}。選成超級管理員時要把整個勾選區收起來，
 *   沒有這條的話它還是會出現。（與 .form-field[hidden] 同一個道理） */
.admin-modal .form-field[hidden] {
    display: none;
}

/* ------------------------------------------------------------
 *  系統訊息頁（includes/functions.php 的 sys_message_page）
 *
 *  ★ 取代原本的 alert()。原生 alert 沒辦法排版，
 *    而且瀏覽器會加上「這個網頁顯示」那一行，看起來像出錯不像提示。
 * ------------------------------------------------------------ */
.sys-msg-body {
    display: grid;
    place-items: center;
    min-height: 100vh;
    margin: 0;
    padding: 24px;
    background: var(--green-050, #f5faf6);
}

.sys-msg-card {
    display: grid;
    justify-items: center;
    gap: 14px;
    width: min(460px, 100%);
    padding: 34px 32px 28px;
    background: #fff;
    border-radius: var(--radius-lg, 16px);
    box-shadow: 0 20px 60px rgba(9, 27, 18, .12);
    text-align: center;
}

.sys-msg-icon {
    display: grid;
    place-items: center;
    width: 62px;
    height: 62px;
    border-radius: 50%;
    background: var(--danger-soft, #fff1f1);
    color: var(--danger, #b13e3e);
}

.sys-msg-icon .icon {
    width: 30px;
    height: 30px;
}

.sys-msg-title {
    margin: 0;
    font-size: 21px;
    font-weight: 900;
    color: var(--green-950, #0a3523);
}

.sys-msg-text {
    margin: 0;
    color: var(--muted, #68746d);
    font-size: 15px;
    line-height: 1.8;
}

/* 一次退回多個錯誤時（例如系統設定）逐條列出，比擠成一段好讀 */
.sys-msg-list {
    margin: 0;
    padding: 0 0 0 20px;
    text-align: left;
    color: var(--muted, #68746d);
    font-size: 15px;
    line-height: 1.9;
}

.sys-msg-actions {
    margin-top: 6px;
}

.sys-msg-actions .btn {
    min-width: 150px;
}

/* ------------------------------------------------------------
 *  QNDialog —— 全站共用的提示對話框（行為在 assets/js/dialog.js）
 *
 *  ★ 取代原生 alert()／confirm()。外觀比照 SweetAlert：
 *    壓暗的背景 + 置中卡片 + 依類型上色的圖示 + 明確的按鈕。
 *    元件本身沿用專案既有的 .btn 與色票，不引第三方檔案。
 * ------------------------------------------------------------ */
.qn-dialog {
    position: fixed;
    inset: 0;
    z-index: 960;            /* 要高於 .modal-backdrop(500) 與 .qn-loading(900) */
    display: grid;
    place-items: center;
    padding: 24px;
    background: rgba(9, 27, 18, .48);
    animation: qn-dialog-fade .16s ease;
}

/* ★ 不能拿掉：作者樣式的 display:grid 會蓋過瀏覽器預設的 [hidden]{display:none}，
 *   沒有這條的話對話框在關閉狀態仍會整片蓋住畫面。
 *   （與 .modal-backdrop[hidden] / .qn-loading[hidden] 同一個道理） */
.qn-dialog[hidden] {
    display: none;
}

.qn-dialog-card {
    display: grid;
    justify-items: center;
    gap: 13px;
    width: min(430px, 100%);
    padding: 30px 30px 24px;
    background: #fff;
    border-radius: var(--radius-lg, 16px);
    box-shadow: 0 26px 70px rgba(9, 27, 18, .3);
    text-align: center;
    animation: qn-dialog-pop .18s ease;
}

.qn-dialog-icon {
    display: grid;
    place-items: center;
    width: 62px;
    height: 62px;
    border-radius: 50%;
}

.qn-dialog-icon svg {
    width: 30px;
    height: 30px;
}

.qn-dialog-icon.is-error   { background: var(--danger-soft, #fff1f1); color: var(--danger, #b13e3e); }
.qn-dialog-icon.is-success { background: var(--green-100, #eaf5ed);   color: var(--green-700, #1b7546); }
.qn-dialog-icon.is-warning { background: var(--accent-soft, #f8edd2); color: var(--accent, #b38a3e); }
.qn-dialog-icon.is-info    { background: var(--info-soft, #edf6fd);   color: var(--info, #346e9d); }

.qn-dialog-title {
    margin: 0;
    font-size: 20px;
    font-weight: 900;
    color: var(--green-950, #0a3523);
}

.qn-dialog-text {
    margin: 0;
    color: var(--muted, #68746d);
    font-size: 15px;
    line-height: 1.8;
}

/* 一次退回多個錯誤時逐條列出，比擠成一段好對照著改 */
.qn-dialog-list {
    margin: 0;
    padding: 0 0 0 20px;
    text-align: left;
    color: var(--muted, #68746d);
    font-size: 14.5px;
    line-height: 1.9;
}

.qn-dialog-actions {
    display: flex;
    gap: 10px;
    margin-top: 6px;
}

.qn-dialog-actions .btn {
    min-width: 118px;
}

.qn-dialog-actions [hidden] {
    display: none;      /* .btn 是 inline-flex，會蓋過瀏覽器預設的 [hidden] */
}

@keyframes qn-dialog-fade { from { opacity: 0; } }
@keyframes qn-dialog-pop  { from { opacity: 0; transform: translateY(10px) scale(.97); } }

@media (prefers-reduced-motion: reduce) {
    .qn-dialog,
    .qn-dialog-card { animation: none; }
}

/* 停用的按鈕要看得出來不能按（.btn 本身沒有處理 :disabled） */
.btn:disabled,
.btn[disabled] {
    opacity: .45;
    cursor: default;
    box-shadow: none;
}

/* 停用的開關（例如自己那一列的狀態）：看得出狀態，但按不動 */
.adm-switch:disabled {
    opacity: .45;
    cursor: default;
}

/* ============================================================
   我的帳號（右上角人名 → 改自己的姓名與密碼）
   design 沒有這個元件，是正式系統才需要的，所以寫在這裡。
   ============================================================ */

/* 右上角的人名：原本是純文字 <span>，改成按鈕之後要看得出「可以點」。
   刻意做得很輕（沒有外框、沒有底色），它是次要入口，
   不該跟頁面裡真正的操作按鈕搶注意力 —— 但 hover 與鍵盤 focus 都要有回饋。 */
.work-header-me {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-height: 40px;          /* 與後台其他可點元素同一個下限（見 CLAUDE.md §10） */
    padding: 6px 12px;
    border: 1px solid transparent;
    border-radius: 999px;
    background: none;
    color: inherit;
    font: inherit;
    font-size: 13.5px;
    cursor: pointer;
    transition: background-color .15s, border-color .15s;
}

.work-header-me:hover {
    background: rgba(0, 0, 0, .05);
    border-color: rgba(0, 0, 0, .08);
}

.work-header-me:focus-visible {
    outline: 2px solid var(--green-600);
    outline-offset: 2px;
}

.work-header-me svg {
    width: 17px;
    height: 17px;
    flex: none;
    opacity: .7;
}

/* 手機上只留圖示 —— 表頭空間本來就很擠，名字在側邊選單裡也看得到 */
@media (max-width: 720px) {
    .work-header-me span { display: none; }
    .work-header-me { padding: 6px 9px; }
}

/* 視窗裡「不能編輯」的欄位值（登入帳號）。
   ★ 用 <p> 不用 disabled 的 <input>：停用的輸入框看起來像「壞掉的欄位」，
     會讓人一直想點它。這裡要表達的是「這是資料，不是欄位」。 */
.field-static {
    margin: 0;
    padding: 9px 0 0;
    font-weight: 600;
    font-size: 14.5px;
    word-break: break-all;     /* 帳號可以含任何可列印字元，不折行會撐破視窗 */
}

/* 「變更密碼」那一段的分隔標題 */
.me-section {
    margin: 18px 0 2px;
    padding-top: 16px;
    border-top: 1px solid var(--line);
    font-weight: 600;
}

/* ============================================================
   商品分類列：單行「輪轉」+ 左右箭頭（不換行）
   design 沒有這個行為（它是 grid 換行），是正式系統的調整。

   ★ 為什麼不換行：分類列是首頁最上面那條快速入口，換到第二行之後
     下面的「推薦商品」就被擠掉了。分類本來就是「掃過去挑一個」的東西。

   ★ 是**輪轉**不是捲動。假設有 7 個、一排放得下 6 個：
       目前      1 2 3 4 5 6
       按右      2 3 4 5 6 7   ← 1 從左邊出去、7 從右邊進來
       按左      7 1 2 3 4 5   ← 7 從左邊進來
     做法是真的把卡片在 DOM 裡重新排序（site.js 的 categoryScroller），
     不是把捲軸拉到最右邊 —— 那樣第 7 項會「從右邊冒出來」，很奇怪。
   ============================================================ */

.category-scroller {
    position: relative;

    /* ⚠️ 這一層**不能有 overflow** —— 箭頭刻意凸出容器 14px，
       一加 overflow:hidden 就會被切掉。裁切交給 .category-viewport。 */

    /* ★ 一排放得下幾個。這幾個數字是**對照 styles.css 的
       .category-grid 斷點**抄過來的（6 / 3 / 2）——
       那邊用 grid-template-columns，這裡改成一列往右長之後
       要自己算每格寬度，所以需要知道「幾個」。
       ⚠️ styles.css 的斷點若有變動，這裡要跟著改。 */
    --cat-visible: 6;
    --cat-gap: 9px;
}

@media (max-width: 1080px) { .category-scroller { --cat-visible: 3; } }
@media (max-width: 760px)  { .category-scroller { --cat-visible: 2; --cat-gap: 10px; } }

/* 看得到的範圍：超出的卡片裁掉。
   ★ touch-action: pan-y —— 把**橫向**手勢留給我們自己處理（輪轉），
     直向仍然交給瀏覽器捲頁面。不設的話手機上會變成
     「想滑分類卻整頁跟著晃」，或是我們的 pointermove 收不到。
   ★ cursor: grab —— 桌機要看得出「這排可以拖」。 */
.category-viewport {
    overflow: hidden;
    touch-action: pan-y;
    cursor: grab;
}

.category-viewport.is-dragging { cursor: grabbing; }

/* 拖曳中不要選到文字（滑鼠拖過去會把分類名稱反白，很醜） */
.category-viewport.is-dragging,
.category-viewport.is-dragging * { user-select: none; }

/* 圖片預設可以被瀏覽器原生拖走，那會蓋掉我們的拖曳（JS 另外也擋了 dragstart） */
.category-scroller .category-grid img {
    -webkit-user-drag: none;
    user-drag: none;
}

.category-scroller .category-grid {
    /* 蓋掉 styles.css 的 grid-template-columns：改成一列往右長 */
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: calc(
        (100% - (var(--cat-visible) - 1) * var(--cat-gap)) / var(--cat-visible)
    );
    gap: var(--cat-gap);
    will-change: transform;
}

/* 輪轉時的滑動動畫：JS 先把整列位移到「換之前」的位置，再放掉讓它滑回來。
   .is-sliding 只在那一瞬間掛著，平常沒有 transition —— 否則位移的那一步
   也會被動畫化，看起來會是來回抖一下。 */
.category-scroller .category-grid.is-sliding {
    transition: transform .26s ease;
}

/* ---- 左右箭頭 ---- */
.category-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;

    /* 44px：一般建議的最小可點範圍，與 §10「可點的東西至少 40px」一致 */
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;

    border: 1px solid var(--line);
    border-radius: 50%;
    background: #fff;
    color: var(--green-800);
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(25, 48, 35, .16);
    transition: background-color .15s, box-shadow .15s;
}

.category-arrow:hover  { background: var(--green-050); }
.category-arrow:active { box-shadow: 0 2px 8px rgba(25, 48, 35, .18); }
.category-arrow:focus-visible { outline: 2px solid var(--green-600); outline-offset: 2px; }

/* 箭頭壓在卡片邊緣上（一半在外），才不會遮住分類圖 */
.category-arrow.prev { left: -14px; }
.category-arrow.next { right: -14px; }

/* icon sprite 的 chevron 是朝右的，往前那顆轉 180° */
.category-arrow.prev svg { transform: rotate(180deg); }
.category-arrow svg { width: 20px; height: 20px; }

/* ★ 不能拿掉：.category-arrow 是 display:grid，
   作者樣式會蓋過瀏覽器預設的 [hidden]{display:none}
   —— 沒有這一條，卡片不夠多的時候那兩顆按鈕還是會出現。
   （與 site.css 其他幾個 [hidden] 規則同一個原因。） */
.category-arrow[hidden] { display: none; }

/* 視窗很窄時箭頭改貼齊邊緣，不要凸出去被切掉 */
@media (max-width: 520px) {
    .category-arrow { width: 38px; height: 38px; }
    .category-arrow.prev { left: 2px; }
    .category-arrow.next { right: 2px; }
}

@media (prefers-reduced-motion: reduce) {
    .category-scroller .category-grid.is-sliding { transition: none; }
}

/* ============================================================
   購物車與結帳 —— design 沒有的幾個元件
   （儲值金折抵是本專案才有的：可以與其他付款方式搭配）
   ============================================================ */

/* 購物車列裡的提醒（缺貨、已下架、庫存不足） */
.cart-warn {
    margin-top: 4px;
    color: var(--danger);
    font-size: 13px;
    font-weight: 600;
}

/* 已下架／缺貨的那一列：淡化但**不要遮住** ——
   它仍然要看得見（不然使用者會覺得東西莫名其妙不見了），
   只是要一眼看出「這個結不了帳」。移除鈕維持正常，才點得下去。 */
.cart-row.is-unavailable > img,
.cart-row.is-unavailable > div:first-of-type { opacity: .55; }
.cart-row.is-unavailable .qty button { opacity: .45; cursor: default; }

/* 結帳頁的儲值金折抵。
   ★ 金額欄位直接放出來（不藏在勾選框後面），而且**預設就填到可折抵的上限** ——
     餘額夠付整筆時，打開結帳頁就已經是「全部用儲值金付」，不必再按任何東西。 */
.wallet-amount-row input { max-width: 180px; }

/* ★ 不能拿掉：#paymentField（.form-field）與那兩列金額都是靠 hidden 控制的，
   而 .form-field 在前面被設成 display:grid、.summary-row 是 flex ——
   作者樣式會蓋過瀏覽器預設的 [hidden]{display:none}。
   沒有這幾條的話，「全額用儲值金折抵」時付款方式還是會出現。 */
.form-field[hidden]  { display: none !important; }
.summary-row[hidden] { display: none !important; }

/* 結帳頁右側的商品清單 */
.checkout-items {
    list-style: none;
    margin: 16px 0 0;
    padding: 14px 0 0;
    border-top: 1px solid var(--line);
    font-size: 14px;
}
.checkout-items li {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 4px 0;
    color: var(--muted);
}
.checkout-items strong { color: var(--ink); }


/* ------------------------------------------------------------
 *  缺貨的標示（design 沒有缺貨狀態：它的商品卡永遠是「加入購物車」）
 *
 *  ★ 用紅色而不是灰色 —— 這一行要在掃過整片商品格線時跳出來，
 *    灰字會直接被當成旁邊的產地一起略過。
 * ------------------------------------------------------------ */
/* ⚠️ 第二個選擇器不能省：styles.css 的 `.detail-meta-item strong` 是
 *   （class + 元素）＝ specificity 0,1,1，單靠 `.stock-out`（0,1,0）蓋不過它 ——
 *   載入順序在後面也沒用，specificity 先比。商品卡那邊則沒這個問題
 *   （.product-origin 只設在外層的 div，span 拿到的是繼承值，一定輸給任何宣告）。 */
.stock-out,
.detail-meta-item strong.stock-out {
    color: var(--danger);
    font-weight: 700;
}


/* 結帳明細裡「庫存只剩 N 份，已從 M 份調整」那一行。
   ★ .checkout-items 的 li 是左右兩欄，這行要自己佔一行 ——
     不然它會接在品名後面，被當成商品名稱的一部分讀過去。 */
.checkout-items .cart-warn {
    display: block;
    font-weight: 600;
}


/* ============================================================
 *  前台的可讀性字級（★ design 原稿刻意不跟進，只在正式系統放大）
 *
 *  問題：styles.css 是設計稿的副本，裡面有 62 處字級在 13px 以下
 *       （其中 11px 有 15 處、12px 有 23 處）——
 *       商品卡的規格與產地、訂單表格的內文、狀態徽章、頁尾整區都是。
 *       買菜的人不一定年輕，那個大小在筆電上就已經要瞇眼睛了。
 *
 *  規則（比照 §10 後台那一區的做法）：
 *      一般內文、可點的東西  ≥ 14px
 *      次要說明、徽章        ≥ 13px
 *      **不再出現 11px、12px**
 *
 *  ⚠️ 選擇器一律照抄 styles.css 的原樣（含 `.a .b` 這種兩段的），
 *    specificity 要相同，這一份才蓋得過去（site.css 載入順序在後面）。
 *    少寫一段就會出現「改了沒反應」，而且畫面上看不出原因。
 *
 *  ⚠️ 有幾條原本寫在 @media 裡（手機版更小）。媒體查詢不影響 specificity，
 *    所以這裡的覆寫在所有寬度都有效 —— 那正是要的：手機上更需要看得清楚。
 *
 *  ⚠️ `.status`、`.field-help`、`.page-sub` **不要再寫一次** ——
 *    上面「後台的操作尺寸」那一區早就調過了，而 site.css 是前後台共用的，
 *    那幾條本來就已經套在前台。在這裡重寫一次只會變成兩個地方各有一份，
 *    以後改了其中一個會出現「改了沒反應」。
 * ------------------------------------------------------------ */

/* ---- 商品卡：規格、產地、價格單位、按鈕 ---- */
.product-spec,
.product-origin,
.visitor-price,
.product-price small,
.product-tag,
.qty-label {
    font-size: 14px;
}

.product-actions .btn {
    font-size: 14.5px;
}

/* ---- 商品詳情：分類、欄位標籤與補充說明 ---- */
.detail-category,
.detail-meta-item > span {
    font-size: 13.5px;
}

.detail-meta-item small,
.trust-item small {
    font-size: 13px;
}

/* ---- 訂單表格（購買紀錄、訂單詳情）----
   ★ 整張表原本是 12px、操作鈕 11px —— 這是最難讀的一塊。 */
.order-panel th,
.order-panel td {
    font-size: 14.5px;
}

.order-panel .btn {
    font-size: 14px;
    min-height: 38px;          /* 可點的東西不要比一行字高不了多少 */
}

th {
    font-size: 14px;
}

/* ---- 頁面與區塊的說明行 ---- */
.section-sub,
.member-level,
.side-link small,
.order-item span,
.detail-list > div > span,
.wallet-hero > div > span {
    font-size: 14px;
}

/* ---- 表頭 ---- */
.brand-sub {
    font-size: 12.5px;
}

.count-badge {
    font-size: 13px;
}

/* ---- 頁尾整區（原本 11～13px）---- */
.footer-intro,
.footer-contact,
.footer-nav a,
.footer-nav button,
.footer-nav span,
.footer-links,
.footer-links span,
.footer-links .text-btn,
.footer-login-link {
    font-size: 14px;
}

.footer-payment-title,
.footer-payment-list span,
.footer-service-item small,
.footer-logo small,
.footer-policy span,
.footer-policy a,
.footer-bottom p,
.copyright {
    font-size: 13px;
}

/* 後台表頭那個站名副標原本只有 9px */
.work-brand .brand-sub {
    font-size: 12px;
}


/* ============================================================
 *  內容區塊列表（後台 ?P=PageFaq —— 前台客服中心那一頁的內容）
 *
 *  design 沒有這個畫面（那四段說明原本寫死在 visitor.js 裡），
 *  所以樣式全部寫在這裡。
 * ============================================================ */

/* 順序欄：固定窄欄，裡面是一個數字輸入框。
   ★ 原本是拖曳握把。拖曳在表格上有三個問題（會反白、游標滑出表格就放不開、
     平板手機完全拖不動），2026-09-16 改成打數字，理由見 js/admin.js
     的 bindContentPage()。商品分類那邊仍是拖曳卡片。 */
.pc-col-sort {
    width: 92px;
}

.pc-sort-input {
    width: 64px;
    padding: 6px 8px;
    border: 1px solid var(--line, #dce6df);
    border-radius: 8px;
    font: inherit;
    font-size: 14px;
    text-align: center;
    background: #fff;
    color: inherit;
}

.pc-sort-input:focus-visible {
    outline: 2px solid var(--green-500, #48a56a);
    outline-offset: 1px;
}

/* 送出期間會 disabled —— 別讓它看起來像壞掉的欄位，只是暫時不能動 */
.pc-sort-input:disabled {
    opacity: .55;
}

/* 內容摘要：次要資訊，但仍維持 14px（見上面「前台的可讀性字級」同一個理由） */
.pc-col-body {
    color: var(--muted, #5d6f63);
    font-size: 14px;
}

/* 內容區塊的編輯視窗：內文要打得下一整段，給高一點 */
#contentEdit .modal {
    max-width: 560px;
}

#contentEdit textarea {
    min-height: 180px;
    line-height: 1.7;
    resize: vertical;
}


/* ============================================================
 *  送出中的按鈕：標籤前面長出一個轉圈
 *
 *  ★ 取代前台原本的「整片等待遮罩」（2026-09-16 使用者要求）。
 *    遮罩把整個畫面壓暗，對一個幾百毫秒的動作來說太重；
 *    回饋長在「剛剛按下去的那顆按鈕」上，位置也最自然 ——
 *    使用者的視線本來就在那裡。
 *    （後台仍然用遮罩：那邊是 ajax，做完多半整頁重新整理。）
 * ============================================================ */

.btn.is-loading {
    /* 不能再按第二次。site.js 另外還有一道旗標擋鍵盤送出 */
    pointer-events: none;
}

/* ★ .btn 是 inline-flex 且有 gap，所以這個 ::before 會變成一個 flex 項目，
     自然排在標籤前面、間距也跟圖示一樣，不必自己算位置。 */
.btn.is-loading::before {
    content: '';
    flex: none;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    border: 2px solid currentColor;
    border-top-color: transparent;     /* 缺一角才看得出在轉 */
    animation: qn-spin .7s linear infinite;
}

/* ★ 送出中的按鈕會一併 disabled（避免鍵盤重複送出），但**不要跟著變淡** ——
     .btn[disabled] 的 opacity:.45 會讓轉圈幾乎看不見，
     而這顆按鈕不是「不能按」，是「正在做」。 */
.btn.is-loading[disabled],
.btn.is-loading:disabled {
    opacity: 1;
}

/* 有前庭需求的使用者不要快速旋轉，但仍要看得出「還在跑」（同 .qn-spinner） */
@media (prefers-reduced-motion: reduce) {
    .btn.is-loading::before { animation-duration: 2.1s; }
}


/* 訂單詳情的送達照片縮圖（?P=OrderDetail）。
   design 的 admin.js 有這一塊但沒有樣式 —— 不限制大小的話，
   一張手機拍的照片會把整個「會員與配送資料」面板撐開。 */
.admin-order-photo {
    display: block;
    width: 120px;
    height: 120px;
    object-fit: cover;
    border-radius: 10px;
    border: 1px solid var(--line, #dce6df);
}


/* ============================================================
 *  送菜員工作台的可讀性字級（★ design 原稿刻意不跟進，只在正式系統放大）
 *
 *  起因：使用者反映「送菜員的畫面的字應該要再大一點，太小會不好操作」。
 *
 *  driver.css 是 design 的副本，裡面有 14 處字級在 13px 以下
 *  （11px 七處、12px 七處）—— 而且正好都是最需要讀的那幾個：
 *  收件人／地址／電話的欄位標籤（11px）、任務卡的操作按鈕（12px）、
 *  商品明細與金額（11／13px）。
 *
 *  ★ 基準比前台再高一級（前台那一區見上面）：
 *      任務卡最主要的值（收件人、地址、電話）  16px
 *      一般內文、可點的東西                    ≥ 15px（前台 14px）
 *      欄位標籤、次要說明                      ≥ 14px（前台 13px）
 *      **不再出現 11、12、13px**
 *
 *    為什麼比前台再大一級：送菜員是**在路邊、拿著手機、常常只有一隻手**在看，
 *    而且看的當下多半在走動。那個情境比坐在筆電前面嚴苛得多。
 *
 *  ⚠️ 選擇器一律照抄 driver.css 的原樣（含 `.a .b` 這種兩段的），
 *    specificity 要相同，這一份才蓋得過去（site.css 載入順序排在它後面）。
 *
 *  ⚠️ 共用的 class 要加 `[data-role="driver"]` 限定 ——
 *    `.step`、`.quick-action`、`.panel-head p`、`.work-profile span` 的本體
 *    住在 styles.css，而後台的 admin.php 也是同一套 .work-shell 版型。
 *    不限定的話會連後台一起放大，但後台是坐著用滑鼠操作的，
 *    已經另外調過了（見上面「操作尺寸」那一區），兩邊的基準本來就不一樣。
 *    本體住在 driver.css 的（`.driver-*`、`.quick-action small`）不必限定 ——
 *    那支只有送菜員頁載入。
 * ------------------------------------------------------------ */

/* ---- 基準字級：手機上不要跟著全站降到 15px ----
   ★ styles.css 在 760px 以下把 `body` 調成 15px。送菜員的頁面正好**只在手機上看**，
     等於他永遠拿到比桌機還小的字 —— 跟這次要解決的問題完全相反。

   ★ 更實際的一點：`.form-field input` 與 `.driver-filter-bar input` 都是 `font: inherit`，
     於是在手機上是 15px —— 而 **iOS Safari 只要輸入框小於 16px，點下去就會自動放大整頁**，
     使用者得自己再縮回來。送菜員要填的是異常原因與送達備註，每張單都可能碰到。
     把基準補回 16px，這件事就一起解決了（不必逐個欄位去寫 font-size）。

   ⚠️ 選擇器要 `body.work-page[data-role="driver"]` 這麼長 ——
     媒體查詢裡那條是 `body`，不夠specific 就蓋不掉。
   ⚠️ `.btn` 是 `white-space: nowrap`，字級變大不會折行、只會變寬。
     已量過最長的那顆「確認取貨並開始配送」在 390px 寬的手機上是 197px，
     而它那時是整行寬（約 332px），還有餘裕。 */
body.work-page[data-role="driver"] {
    font-size: 16px;           /* 手機上原為 15px */
}

/* ---- 任務卡：收件人／地址／電話（整個工作台最常讀的一塊）---- */
.driver-task-eyebrow,
.driver-task-info span,
.driver-detail-list>div>span {
    font-size: 14px;           /* 原 11px */
}

.driver-task-info strong {
    font-size: 16px;           /* 原 14px */
    line-height: 1.5;
}

.driver-task-info small {
    font-size: 14px;           /* 原 11px */
}

/* ---- 任務卡的操作鈕：開始配送／確認送達／回報異常／收款 ----
   ★ 這幾顆是站在人家門口用拇指按的，高度一起從 38 拉到 46px。 */
.driver-task-actions .btn,
.driver-detail-actions .btn {
    min-height: 46px;          /* 原 38px */
    padding: 9px 14px;         /* 原 7px 11px */
    font-size: 16px;           /* 原 12px */
}

/* ---- 異常備註（紅色那一條）---- */
.driver-task-issue {
    font-size: 14.5px;         /* 原 12px */
}

/* ★ 這一條原本沒有 font-size，吃的是 <small> 的 UA 預設 0.8em ≈ 12.8px。
     專案沒有 small 的全域重置，所以要自己補一個值。 */
.driver-issue-box small {
    font-size: 14px;
}

/* ---- 儀表板的統計卡與面板標頭 ---- */
.driver-metric-note {
    font-size: 14px;           /* 原 12px */
}

.driver-panel-head p {
    font-size: 14px;           /* 原 12px */
}

[data-role="driver"] .panel-head p {
    font-size: 14px;           /* 原 12px，與 .driver-panel-head p 同一條規則 */
}

.driver-panel-count {
    font-size: 14px;           /* 原 12px */
}

.driver-proof-badge {
    font-size: 14px;           /* 原 11px */
}

/* ---- 工作台的快速處理與提醒 ---- */
[data-role="driver"] .quick-action {
    font-size: 15px;           /* 原 13px（styles.css）*/
}

.quick-action small {
    font-size: 14px;           /* 原 11px */
}

.driver-reminders>div {
    font-size: 14.5px;         /* 原 12px */
}

/* ---- 三個列表頁的篩選列 ---- */
.driver-filter-bar label>span {
    font-size: 14px;           /* 原 11px */
}

/* ---- 個人頁上方的三張摘要卡 ---- */
.driver-profile-summary span {
    font-size: 14px;           /* 原 12px */
}

/* ---- 訂單商品明細與金額 ---- */
.driver-order-item span,
.driver-order-item small {
    font-size: 14px;           /* 原 11px */
}

.driver-total-row {
    font-size: 15px;           /* 原 13px */
}

.driver-proof figcaption {
    font-size: 14px;           /* 原 11px */
}

/* ---- 配送進度的五個步驟 ----
   ★ 標籤最長四個字（「接收派單」），14px 約 56px 寬；
     手機上 .driver-steps 每欄約 58px，剛好容得下，再大就會折行。 */
[data-role="driver"] .step {
    font-size: 14px;           /* 原 12px */
}

/* ---- 左側選單的身分列（姓名底下那行「送菜員」）---- */
[data-role="driver"] .work-profile span {
    font-size: 14px;           /* 原 13px */
}


/* ============================================================
 *  配送任務詳情的進度條（?P= 無，前台 driver_task.php）
 *
 *  起因：使用者要「配送任務詳情可以有像進度條一樣」的東西。
 *
 *  ★ 五個步驟圓圈本來就有（design 的 progressSteps()），問題是**看不出進度**：
 *    styles.css 只有 .step.done / .step.current 是綠的、其餘是灰的，
 *    但 driver.css 又把 `.driver-detail-steps .step-circle` **全部**改成同一個
 *    green-100 + 邊框，於是「已完成／進行中／還沒到」三種長得一模一樣 ——
 *    只有目前那一個多一圈很淡的外框。
 *    實際渲染四種狀態並排看過：completed 與 ready 幾乎分不出來。
 *
 *  ★ 兩件事一起補，缺一個都還是讀不出來：
 *      ① 圓圈之間補一條軌道，**填到目前這一步為止** ← 這就是「進度條」
 *      ② 還沒到的步驟改回灰色（不然填到哪裡還是看不出來）
 *
 *  ⚠️ 只做詳情頁的 `.driver-detail-steps`，**儀表板的 `.driver-steps` 不做** ——
 *    那一個是寫死的流程說明（driver_index.php 的註解寫得很清楚），
 *    不跟著單子變。把它畫得更像真的進度，只會讓人以為那是某一張單的狀態。
 * ------------------------------------------------------------ */

.driver-detail-steps .step {
    position: relative;
}

/* 軌道：左右各半段，接在圓圈的水平中心線上。
   ★ 圓圈實際是 38px（styles.css 後面那段 compact 的 .step-circle 蓋過前面的 42px），
     所以半徑 19 → 線粗 4 的話 top = 19 - 2 = 17。
   ★ 往左右各多長 3px 補掉 .steps 的 gap（同樣是 compact 那段的 3px），
     兩段才會接起來、不會看起來像虛線。 */
.driver-detail-steps .step::before,
.driver-detail-steps .step::after {
    content: '';
    position: absolute;
    top: 17px;
    height: 4px;
    border-radius: 2px;
    background: #e4ebe6;
}

.driver-detail-steps .step::before { left: -3px; right: calc(50% + 22px); }
.driver-detail-steps .step::after  { right: -3px; left:  calc(50% + 22px); }

/* 頭尾不要有往外伸出去的半截 */
.driver-detail-steps .step:first-child::before,
.driver-detail-steps .step:last-child::after {
    display: none;
}

/* 走過的塗綠：**到達**這一步 → 左半段綠；**離開**這一步 → 右半段綠。
   ★ current 的右半段刻意留白 —— 這一步還沒做完，進度就該停在這個圓圈上。 */
.driver-detail-steps .step.done::before,
.driver-detail-steps .step.current::before,
.driver-detail-steps .step.done::after {
    background: var(--green-600);
}

/* 還沒到的步驟改回灰色（蓋掉 driver.css 那條「全部都是 green-100」）。
   ⚠️ 選擇器要四段才蓋得過去：driver.css 的是 `.driver-detail-steps .step-circle`。 */
.driver-detail-steps .step:not(.done):not(.current) .step-circle {
    color: #8b968f;
    background: #f2f5f3;
    border-color: #e4ebe6;
}

.driver-detail-steps .step:not(.done):not(.current) {
    color: var(--muted);
    font-weight: 700;
}

/* 已完成：淺綠底 + **綠色外圈**（2026-09-17 使用者要求）。
   ★ driver.css 給所有圓圈的邊框是 #cfe0d3（很淡的灰綠），
     已完成與還沒到的差別只剩底色 —— 外圈描成主綠之後，掃過去就數得出來走了幾步。
   ⚠️ 邊框從 1px 變 2px 不會動到版面：全站 box-sizing 是 border-box，
     38px 的圓圈還是 38px，只有裡面的圖示縮 1px。 */
.driver-detail-steps .step.done .step-circle {
    border-width: 2px;
    border-color: var(--green-600);
}

/* 目前這一步：實心綠，一眼看得到人在哪裡。
   ★ driver.css 的註解寫「目前步驟只用外框強調，不改變主色」，那是**沒有軌道**時的作法 ——
     五個圓圈都一樣時，改主色會讓人以為那一格是「錯誤」或「特別」。
     現在有了軌道，填色的終點就是進度的終點，實心才對得上。 */
.driver-detail-steps .step.current .step-circle {
    color: #fff;
    background: var(--green-600);
    border-color: var(--green-600);
}

/* 手機上讓五格全部進得來，不要橫向捲動。
   driver.css 在 ≤760px 是 `overflow-x:auto` + `minmax(72px,1fr)` ——
   五格要 372px，而 390px 的手機扣掉內距只剩約 332px，
   於是**最後兩格被切在畫面外**，而且沒有任何東西告訴使用者那裡可以撥。
   進度條看不到終點就失去意義了，所以這一頁改成全部塞進來。
   ★ 每格約 64px，標籤最長四個字（14px 約 56px）放得下。 */
@media (max-width: 760px) {
    .driver-detail-steps {
        overflow-x: visible;
        grid-template-columns: repeat(5, minmax(0, 1fr));
    }
}


/* ============================================================
 *  密碼欄位的「眼睛」（行為在 assets/js/password-eye.js）
 *
 *  ★ 前台、後台、送菜員三邊共用 —— 密碼欄位散在四個地方，
 *    樣式跟行為一樣只留一份（同 loading.js／.qn-loading 的做法）。
 *
 *  ⚠️ `.pw-wrap` 是 JS 包上去的，包在**原本的 input 外面**，
 *    所以它要接手 input 原本的版面角色：`.form-field` 與後台登入頁的
 *    `.field` 都是 label 一行、input 一行，因此這裡是 display:block + 滿寬。
 * ------------------------------------------------------------ */

.pw-wrap {
    position: relative;
    display: block;
    width: 100%;
}

/* 空出右邊給按鈕，字才不會跑到眼睛底下。
   ★ 用 !important 是因為各層對 input 的 padding 寫法不一（styles.css 的
     `.form-field input`、admin.css、後台登入頁自己的 `.field input`），
     而這條必須每一處都成立 —— 少一處就會有欄位的字被眼睛蓋住。 */
.pw-wrap > input {
    width: 100%;
    padding-right: 46px !important;
}

.pw-eye {
    position: absolute;
    top: 50%;
    right: 4px;
    transform: translateY(-50%);
    width: 40px;              /* 可點的東西至少 40px（同「操作尺寸」那一區） */
    height: 40px;
    display: grid;
    place-items: center;
    padding: 0;
    border: 0;
    border-radius: 8px;
    color: var(--muted, #68746d);
    background: transparent;
    cursor: pointer;
    transition: color .15s ease, background-color .15s ease;
}

.pw-eye:hover {
    color: var(--green-800, #145f3a);
    background: var(--green-100, #eaf5ed);
}

.pw-eye:focus-visible {
    outline: 3px solid rgba(44, 138, 85, .28);
    outline-offset: -2px;
}

.pw-eye-icon {
    width: 21px;
    height: 21px;
    display: block;
}

@media (prefers-reduced-motion: reduce) {
    .pw-eye { transition: none; }
}


/* ------------------------------------------------------------
 *  條款文件視窗（includes/doc_modal.php）
 *
 *  版型本體用既有的 .modal（styles.css）—— 它本來就有 max-height
 *  與 overflow:auto，標題列也是 sticky 的，長條款捲起來剛好。
 *
 *  ★ 這一頁的內容是**後台用編輯器排出來的 HTML**（其餘說明頁是純文字），
 *    所以這裡要把 h2/h3/h4、ul/ol、blockquote 這些都定義好 ——
 *    管理者排出來的版面要真的呈現得出來。
 *    可以出現哪些標籤由 includes/functions.php 的 privacy_allowed_tags() 決定，
 *    那邊加標籤的話這裡要補樣式，否則會掉回瀏覽器預設值（跟站台格格不入）。
 *
 *  ★ design 沒有這個視窗，所以規則寫在 site.css（本專案的覆寫層），
 *    不寫進 styles.css —— 那是 design 的副本，日後可能整份重新複製。
 * ------------------------------------------------------------ */
.doc-body {
    color: var(--ink, #23312a);
    /* 條款是要一行一行讀完的東西，行距與字級都比一般內文再寬一點 */
    font-size: 15px;
    line-height: 1.9;
}

.doc-body > :first-child { margin-top: 0; }
.doc-body > :last-child  { margin-bottom: 0; }

.doc-body p {
    margin: 0 0 14px;
}

.doc-body h2,
.doc-body h3,
.doc-body h4 {
    margin: 26px 0 10px;
    color: var(--green-950, #0b2417);
    font-weight: 800;
    line-height: 1.5;
}

.doc-body h2 { font-size: 19px; }
.doc-body h3 { font-size: 17px; }
.doc-body h4 { font-size: 15.5px; }

.doc-body ul,
.doc-body ol {
    margin: 0 0 14px;
    padding-left: 1.6em;
}

.doc-body li {
    margin-bottom: 6px;
}

.doc-body blockquote {
    margin: 0 0 14px;
    padding: 12px 16px;
    border-left: 3px solid var(--green-500, #48a56a);
    background: var(--green-050, #f5faf6);
    border-radius: 0 10px 10px 0;
}

.doc-body hr {
    margin: 22px 0;
    border: 0;
    border-top: 1px solid var(--line, #e3ebe5);
}

.doc-body a {
    color: var(--green-800, #145f3a);
    text-decoration: underline;
    /* 條款裡的網址可能很長，手機上不斷行會把視窗撐寬 */
    word-break: break-word;
}


/* ------------------------------------------------------------
 *  合作廠商卡片（partners.php）
 *
 *  版型本體是 design 的 .partner-*（在 styles.css）。這裡只補兩件
 *  design 沒有的事：
 *    1. 真的放圖片（design 是「廠商圖片」四個字的佔位方塊）
 *    2. 滑鼠移上去時的上浮效果
 * ------------------------------------------------------------ */
.partner-image {
    width: 100%;
    min-height: 118px;
    display: grid;
    place-items: center;
    overflow: hidden;
}

.partner-image img {
    width: 100%;
    height: 118px;
    /* 廠商圖的長寬比不會統一，裁切比變形好看 */
    object-fit: cover;
    display: block;
}

/* ★ **每一張卡都會上浮**，不分有沒有連結（2026-09-18 使用者決定）。
 *
 *   ⚠️ 代價寫在這裡免得日後有人當成 bug：**沒有連結的卡片也會浮**，
 *     看起來像可以點、但點下去不會有任何反應。
 *     為了把誤導降到最低，游標只有在「真的可以點」時才變成手指
 *     （見下面的 .partner-card-link），沒連結的維持一般箭頭。
 *
 *   ★ 幅度 -2px 與商品卡、分類卡、metric 卡一致 —— 同一個站不該有兩種浮起來的高度。 */
.partner-card {
    transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}

.partner-card:hover {
    transform: translateY(-2px);
    border-color: var(--green-500, #48a56a);
    /* ⚠️ 這裡要用 --shadow-md 不是 --shadow-sm：
         .partner-card 本身的陰影是 0 10px 24px，比 --shadow-sm（0 6px 18px）**還大** ——
         用 sm 的話卡片浮起來、陰影反而縮小，看起來像陷下去。
         商品卡 hover 用的也是 --shadow-md。 */
    box-shadow: var(--shadow-md, 0 16px 44px rgba(26, 49, 36, .1));
}

/* ★ 只有「有連結」的卡片拿得到這個 class（沒連結的連 <a> 都不是）。
     游標與鍵盤 focus 外框只給它們 —— 那才是真的可以按的東西。 */
.partner-card-link {
    text-decoration: none;
    cursor: pointer;
}

.partner-card-link:focus-visible {
    transform: translateY(-2px);
    border-color: var(--green-500, #48a56a);
    box-shadow: var(--shadow-md, 0 16px 44px rgba(26, 49, 36, .1));
    outline: 3px solid rgba(44, 138, 85, .28);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .partner-card { transition: none; }
    .partner-card:hover,
    .partner-card-link:focus-visible { transform: none; }
}

/* ------------------------------------------------------------
 *  後台側邊選單：主功能／次功能 + 可收合（2026-09-18）
 *
 *  ★ design 沒有這個元件 —— 它的 workspaceShell() 是一整排平的選單，
 *    因為當時後台只有 9 頁；現在 19 頁，不分組要從頭掃到尾才找得到東西。
 *    版型在 &Maint_Vege2026/menu.php，清單在 inc/nav.php，
 *    收合的行為在 js/admin.js 的 bindNavGroups()。
 *
 *  ★ **主次的差別靠「色塊」，不靠字級**（2026-09-18 使用者要求：
 *    「字要一樣大，然後是色塊上的明顯」）：
 *
 *        主功能（儀表板、報表統計，與五個群組標題）  → 有底色的色塊
 *        次功能（群組底下的項目）                    → 沒有底色，縮排 + 直軌
 *
 *    ⚠️ **兩邊的字一樣大**（都是繼承 body 的 16px）。
 *      第一版是把次功能縮到 15px，使用者立刻反映「為甚麼字變小了」——
 *      買菜這個站的使用者不一定年輕，縮字級換來的層次並不划算（同 §10 的可讀性調整）。
 *      層次全部交給色塊與縮排。
 * ------------------------------------------------------------ */

/* ---- 主功能：色塊 ----
 *  ⚠️ `.work-nav > .work-nav-link` 送菜員工作台也吃得到
 *     （driver_header.php 的選單長得一樣），所以一定要用 [data-role="admin"] 限定，
 *     不然他那邊整排選單都會變成綠色色塊（§10 對 driver.css 的覆寫也是同一套作法）。
 *
 *  ⚠️ 群組標題那一條**一定要帶 `.work-nav` 前綴**：styles.css 有一條
 *     `.work-nav button`（design 時代的選單項目，specificity 0,1,1），
 *     比 `.work-nav-group-btn`（0,1,0）高 —— 不加前綴的話 padding、圓角、
 *     顏色會被它蓋掉，而且下面那個斷點的 `display: none` 完全不會生效（實測踩過）。
 */
[data-role="admin"] .work-nav > .work-nav-link,
.work-nav .work-nav-group-btn {
    width: 100%;
    min-height: 46px;
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 11px 13px;
    border: 0;
    border-radius: 10px;
    background: var(--green-100, #eaf5ed);
    color: var(--green-900, #0f4a30);
    font: inherit;
    font-weight: 850;
    text-align: left;
    text-decoration: none;
}

.work-nav .work-nav-group-btn:hover {
    /* 比色塊本身再深一階。沒有現成的色票，這是 green-100 往 green-500 方向壓一點。 */
    background: #d9ebe0;
}

/* ---- 儀表板與報表統計：白底 + 綠框，與群組標題分開（2026-09-21）----
 *
 *  使用者：「儀表板跟報表統計可不可以用另外一個顏色，因為他沒有次功能」。
 *
 *  ★ 這兩個與群組標題**是兩種不同的東西**，原本卻長得一模一樣
 *    （都是 green-100 的色塊）：
 *      群組標題  → 點下去**展開**（右邊有箭頭，但那個提示太小）
 *      這兩個    → 點下去**換頁**
 *
 *  ★ 用「實心 vs 外框」而不是換一個色系 —— 這正是本專案既有的分法：
 *    `.btn-primary` 實心、`.btn-outline` 白底綠字綠框（§14「一眼看得出可以按」）。
 *    三種狀態因此完全分得開：
 *      群組標題（軟綠實心）／可點的頁面（白底綠框）／目前這一頁（深綠實心白字）
 *
 *  ⚠️ 只吃**直接子層**（`>`）—— 次功能在 `.work-nav-items` 裡面，不會被選到。
 *  ⚠️ 用 `inset box-shadow` 不用 `border`：border 會把盒子撐大 3px，
 *     與旁邊群組標題的高度和左右邊緣就對不齊了。 */
[data-role="admin"] .work-nav > .work-nav-link {
    background: #fff;
    /* 沒有現成的色票，這是 green-100 與 green-500 之間 */
    box-shadow: inset 0 0 0 1.5px #bcdcc8;
}

[data-role="admin"] .work-nav > .work-nav-link:hover {
    background: var(--green-050, #f5faf6);
    box-shadow: inset 0 0 0 1.5px var(--green-500, #48a56a);
}

.work-nav .work-nav-group-btn {
    cursor: pointer;
}

.work-nav .work-nav-group-btn:focus-visible {
    outline: 2px solid var(--green-600, #2c8a55);
    outline-offset: 1px;
}

/* ★ 選單太長時要能捲（2026-09-21 使用者：「主功能都點開，側選單不能往下滑，
     這樣我就點不到下面的頁面了」）。
 *
 *  `.work-sidebar` 是 `position: sticky; height: 100vh`（styles.css），
 *  而 `.work-nav` 沒有任何 overflow —— 19 頁全部展開就比一個畫面高，
 *  多出來的部分**畫得出來卻捲不到**（側邊欄是 sticky，不跟著頁面捲）。
 *
 *  ⚠️ `min-height: 0` 不能省：flex 項目預設是 `min-height: auto`
 *     （不會縮到比內容小），少了它 `overflow-y` 永遠不會生效
 *     —— 與 `.work-nav-items` 那個 0fr 是同一個坑。
 *
 *  ★ 捲的是**選單本身**不是整條側邊欄：這樣站台名稱與「登出系統」
 *    （`.work-logout` 有 `margin-top: auto`）會留在原位，不會跟著捲走。
 *
 *  ★ 這一條**不限定 `[data-role="admin"]`** —— 送菜員工作台是同一套版型，
 *    它現在只有 6 項所以捲軸不會出現，但那是「剛好還夠」，不是不會發生。 */
.work-nav {
    min-height: 0;
    overflow-y: auto;
    scrollbar-width: thin;
}

/* 群組之間留一點距離，讓每一塊色塊自己成一段 */
.work-nav-group {
    margin-top: 6px;
}

/* ★ 主功能的色塊與第一個次功能之間要留距離（2026-09-21 使用者：「有點太貼了」）。
 *
 *  ⚠️ 這個留白**一定要放在會被收合掉的那一層裡面**（第一個項目的 margin），
 *     不能放在 `.work-nav-items` 的 padding —— padding 不會被 `overflow` 裁掉，
 *     收起來之後每一組都會留下一條空隙（同一天實測踩過，量到 6px）。
 *     子元素的 margin 算在格線項目的內容高度裡，所以會跟著一起收掉。 */
.work-nav-items > :first-child {
    margin-top: 6px;
}

/* 箭頭。sprite 裡的 chevron 是**朝右**的，所以展開時轉 90 度朝下。 */
.work-nav-chev {
    margin-left: auto;
    width: 15px;
    height: 15px;
    flex: none;
    transform: rotate(90deg);
    transition: transform .18s ease;
}

.work-nav-group.is-closed .work-nav-chev {
    transform: rotate(0deg);
}

/* ---- 開闔的動畫（2026-09-21）----
 *  ★ 原本是 .is-closed 直接 `display: none` —— 沒有過場，底下的項目是「跳」上來的，
 *    使用者反映「開闔在畫面上沒有那麼順暢」。
 *
 *  ★ 改用 **grid-template-rows: 1fr → 0fr**：這是目前唯一能對
 *    「高度未知的內容」做 CSS 過場的做法（每一組的項目數不一樣，2～8 個都有，
 *    所以 max-height 猜一個值不會準 —— 猜太大時動畫會「先快後停」）。
 *    外層 .work-nav-items-wrap 當格線容器負責過場，
 *    內層 .work-nav-items 負責 overflow:hidden 把內容裁掉。
 *
 *  ⚠️ 內層一定要 `min-height: 0` —— 格線項目的預設是 `min-height: auto`
 *     （不會小於內容），少了它 0fr 完全收不起來。
 *  ⚠️ 上下的留白改用 **padding** 不用 margin：margin 不會被 overflow 裁掉，
 *     收起來之後會留下一條 6px 的空隙。 */
.work-nav-items-wrap {
    display: grid;
    grid-template-rows: 1fr;
    overflow: hidden;
    transition: grid-template-rows .22s ease;
}

.work-nav-group.is-closed .work-nav-items-wrap {
    grid-template-rows: 0fr;
}

/* ---- 次功能：沒有底色，縮排 + 一條直軌 ---- */
.work-nav-items {
    display: grid;
    gap: 3px;
    min-height: 0;
    overflow: hidden;
    margin-left: 16px;
    padding-left: 10px;
    border-left: 2px solid var(--line, #dce6df);
}

/* ⚠️ `.work-nav-items` 是 `overflow: hidden`（收合動畫要用），
     而瀏覽器預設的焦點框畫在元素**外面** —— 會被裁掉，用鍵盤操作的人
     就看不出游標在哪一項。改成畫在裡面（與本檔其他 focus-visible 同一個做法）。 */
.work-nav-items .work-nav-link:focus-visible {
    outline: 2px solid var(--green-700, #1b7546);
    outline-offset: -2px;
}

/* 目前所在的那一組，直軌變綠色 —— 一眼看得出自己在哪一個主功能底下。 */
.work-nav-group.has-active > .work-nav-items {
    border-left-color: var(--green-500, #48a56a);
}

/* ---- 目前這一頁：實心深綠，與「主功能色塊」分得開 ----
 *  ⚠️ 主功能的色塊已經是 green-100 了，而 styles.css 的 `.work-nav-link.active`
 *     也是 green-100 —— 不換一個更重的樣子，「現在在哪一頁」就看不出來。 */
[data-role="admin"] .work-nav .work-nav-link.active,
[data-role="admin"] .work-nav .work-nav-link.active:hover {
    background: var(--green-800, #145f3a);
    color: #fff;
    /* ⚠️ 儀表板／報表統計平常有一圈綠框（見上），目前這一頁要把它收掉 ——
         深綠實心外面再描一圈淺綠會像沒對齊的雙框。 */
    box-shadow: none;
}

@media (prefers-reduced-motion: reduce) {
    .work-nav-chev,
    .work-nav-items-wrap { transition: none; }
}

/* ★ 側邊欄收成「只剩圖示」時（≤1080px，規則在 styles.css）：
     **標題整個收起來，收合也不適用** ——
     一排圖示配一行中文字很奇怪，而且那時候按標題也看不出收了什麼。
     分組改由群組之間的分隔線表示。 */
@media (max-width: 1080px) {
    .work-nav .work-nav-group-btn {
        display: none;
    }

    .work-nav-group {
        margin-top: 8px;
        padding-top: 8px;
        border-top: 1px solid var(--line, #dce6df);
    }

    .work-nav-group.is-closed .work-nav-items-wrap {
        grid-template-rows: 1fr;  /* 收合在這個寬度不生效 */
    }

    .work-nav-items {
        margin-left: 0;
        padding: 0;
        border-left: 0;           /* 只剩圖示時直軌沒有意義 */
    }
}

/* ≤760px 用漢堡把側邊欄展開時，文字會回來（styles.css 的
   `.work-sidebar.open .work-nav-link span`），標題、直軌與收合也要跟著回來。 */
@media (max-width: 760px) {
    .work-sidebar.open .work-nav .work-nav-group-btn {
        display: flex;
    }

    .work-sidebar.open .work-nav-group {
        margin-top: 6px;
        padding-top: 0;
        border-top: 0;
    }

    .work-sidebar.open .work-nav-items {
        margin-left: 16px;
        padding-left: 10px;
        border-left: 2px solid var(--line, #dce6df);
    }

    .work-sidebar.open .work-nav-group.is-closed .work-nav-items-wrap {
        grid-template-rows: 0fr;
    }
}


/* ------------------------------------------------------------
 *  側邊欄收起來／攤開：右上角那顆按鈕（2026-09-18）
 *
 *  ⚠️ **那顆按鈕原本是壞的**：design 給它的 class 是 `.mobile-menu-btn`，
 *    styles.css 也寫了 `.mobile-menu-btn { display: none }`（第 266 行）想在寬螢幕藏起來，
 *    但同一個檔第 951 行的 `.icon-btn { display: grid }` specificity 一樣（0,1,0）
 *    而且排在後面 —— 後者贏，所以它在桌機一直看得到，按下去卻什麼也不會發生。
 *    2026-09-18 使用者問「右上角這個是做什麼用的」才發現。
 *    **與其把它藏起來，不如給它一件真正該做的事**：收合整條側邊欄。
 *    ⚠️ 那兩行在 styles.css，是 design 的副本，**不要去改它**（§10）。
 *
 *  ★ 狀態寫在 <body data-nav>，行為在 js/admin.js 的 setNavWidth()：
 *      narrow  只剩圖示的窄條
 *      wide    完整的側邊欄
 *    沒有這個屬性時就照 styles.css 的斷點走。
 *
 *  ★ **包在 min-width: 761px 裡**：≤760px 時側邊欄是抽屜（fixed + 移到畫面外），
 *    那顆按鈕在那裡的工作是把抽屜滑出來，寬窄這一套不適用。
 *
 *  ⚠️ **下面每一個還原值都是用 getComputedStyle 量出來的，不是照著讀 CSS 猜的。**
 *    第一版是照 styles.css 的 ≤1080px 那一段抄，結果三個值都錯 ——
 *    因為那個檔**後面還有一段沒有包在任何 @media 裡的覆寫**（第 2459 行起，
 *    註解寫 "Workspaces: match supplied driver/admin mockups"），
 *    它比前面的斷點晚出現，所以贏：
 *
 *      `.work-shell`   兩種寬度**都是 198px**（斷點裡那條 76px 是死碼）
 *      `.work-sidebar` padding 兩種寬度**都是 14px 10px**（斷點裡那條 18px 10px 也是死碼）
 *      `.work-profile` **全站一律 display:none** —— 千萬不要「還原」它，
 *                      那個灰底的人名方塊本來就不該出現
 * ------------------------------------------------------------ */
@media (min-width: 761px) {

    /* ---- 收起來 ----
     *  ★ 這裡用 **76px**，比 ≤1080px 的內建圖示模式（198px）**更窄** ——
     *    那個 198px 是上面講的死碼造成的：標籤都藏起來了，卻還留著 198px 的空白。
     *    76px 才是 design 原本想要的寬度（斷點裡那條沒生效的規則就是寫 76px）。 */
    body[data-nav="narrow"] .work-shell {
        grid-template-columns: 76px minmax(0, 1fr);
    }

    body[data-nav="narrow"] .work-brand .brand-copy,
    body[data-nav="narrow"] .work-nav span,
    body[data-nav="narrow"] .work-logout span {
        display: none;
    }

    body[data-nav="narrow"] .work-brand .brand,
    body[data-nav="narrow"] .work-nav-link,
    body[data-nav="narrow"] .work-logout {
        justify-content: center;
    }

    /* 群組的部分（這幾條 styles.css 沒有，是我們自己的元件） */
    body[data-nav="narrow"] .work-nav .work-nav-group-btn {
        display: none;
    }

    body[data-nav="narrow"] .work-nav-group {
        margin-top: 8px;
        padding-top: 8px;
        border-top: 1px solid var(--line, #dce6df);
    }

    body[data-nav="narrow"] .work-nav-group.is-closed .work-nav-items-wrap {
        grid-template-rows: 1fr;       /* 只剩圖示時收合不適用 */
    }

    body[data-nav="narrow"] .work-nav-items {
        margin-left: 0;
        padding: 0;
        border-left: 0;
    }

    /* ---- 攤開：把 ≤1080px 自動收起來那一套蓋回去 ----
     *  ⚠️ **沒有 `.work-profile`**（見上，那個方塊全站都是隱藏的）。
     *  ⚠️ `display: inline` 是對的：`.brand-copy` 與那兩個 span 身上沒有任何
     *    display 規則，而它們的容器是 flex，所以實際算出來會是 block ——
     *    量過 1600px 的值就是 block／inline，這樣還原後完全一樣。 */
    body[data-nav="wide"] .work-shell {
        grid-template-columns: 198px minmax(0, 1fr);
    }

    body[data-nav="wide"] .work-brand .brand-copy,
    body[data-nav="wide"] .work-nav span,
    body[data-nav="wide"] .work-logout span {
        display: inline;
    }

    body[data-nav="wide"] .work-brand .brand,
    body[data-nav="wide"] .work-nav-link,
    body[data-nav="wide"] .work-logout {
        justify-content: normal;
    }

    body[data-nav="wide"] .work-nav .work-nav-group-btn {
        display: flex;
    }

    body[data-nav="wide"] .work-nav-group {
        margin-top: 6px;
        padding-top: 0;
        border-top: 0;
    }

    body[data-nav="wide"] .work-nav-group.is-closed .work-nav-items-wrap {
        grid-template-rows: 0fr;
    }

    body[data-nav="wide"] .work-nav-items {
        margin-left: 16px;
        padding-left: 10px;
        border-left: 2px solid var(--line, #dce6df);
    }
}

/* ★ 順手修掉上面講的那條死碼：≤1080px 自動收起來時，側邊欄本來應該是 76px，
     但被第 2459 行那段無條件覆寫蓋成 198px —— 標籤都藏起來了，卻留著一大片空白。
     ⚠️ 只修後台（`[data-role="admin"]`），送菜員工作台維持原樣；
        使用者按過「攤開」時也不要動它。 */
@media (max-width: 1080px) {
    [data-role="admin"]:not([data-nav="wide"]) .work-shell {
        grid-template-columns: 76px minmax(0, 1fr);
    }
}
