/* components.css — buttons · cards · badges · tables · forms · tiles · tabs · chat · steps · modal · toast
   浪花旅遊顧問平台 · 設計系統（依《品牌風格指南 — 中高齡友善》）

   規則：
   · 所有可點目標 ≥ var(--tap) 48px；主要按鈕 var(--tap-lg) 54px。
   · 字級一律 rem，最小 .82rem（≈15px @標準）；指南禁用 12px 以下小字。
   · 亮橘只作按鈕底（其上配深炭字）；當文字用一律 --orange-deep。
   ===================================================================== */

/* =====================================================================
   Buttons — 大而清楚（指南 §06）
   ===================================================================== */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  border-radius:12px;font-size:1.02rem;font-weight:700;
  min-height:var(--tap-lg);padding:14px 30px;
  cursor:pointer;border:2px solid transparent;line-height:1;
  white-space:nowrap;text-decoration:none;
  transition:transform var(--dur-hover) var(--ease-out),box-shadow var(--dur-hover),background var(--dur-ui),border-color var(--dur-ui);
}
.btn:hover{text-decoration:none}
.btn:active{transform:translateY(1px)}

/* 主要行動：亮橘底 + 深炭字 = 5.54:1 ✓（切勿改白字，僅 2.61:1） */
.btn-primary{background:var(--orange);color:var(--ink);box-shadow:var(--sh1)}
.btn-primary:hover{background:var(--orange-hover);color:var(--ink);transform:translateY(-3px);box-shadow:var(--sh2)}

.btn-secondary{background:var(--card);border-color:var(--line);color:var(--ink);box-shadow:var(--sh1)}
.btn-secondary:hover{background:var(--card-hi);border-color:var(--ink-3);color:var(--ink);transform:translateY(-3px);box-shadow:var(--sh2)}

.btn-ghost{background:transparent;color:var(--orange-deep);padding:12px var(--s2);box-shadow:none}

/* 第三方登入按鈕（LINE / Google）— 中性底 + 品牌 logo 帶色。
   為何不用品牌色滿版：登入頁的主要行動是橘底「登入」。再放一塊飽和綠，
   兩塊高彩度色塊互搶，層級就沒了 —— 這是原本綠按鈕最大的問題，不在綠本身。
   中性底把彩度全留給 logo：辨識度由 logo 負責（使用者認的是圖不是色塊），
   文字 --ink on --card-hi = 14.46:1，遠優於原本深炭配綠的 6.41:1。
   邊框用 --ink-3 而非 --line：--line 對頁面底只有 1.36:1，按鈕輪廓會糊掉；
   --ink-3 是 4.56:1，過 1.4.11 的 3:1。（同理原本綠按鈕才要配深綠邊框。） */
.btn-social{background:var(--card-hi);border-color:var(--ink-3);color:var(--ink);box-shadow:var(--sh1)}
.btn-social:hover{background:var(--card);border-color:var(--ink);color:var(--ink);transform:translateY(-3px);box-shadow:var(--sh2)}
.btn-social img{width:24px;height:24px;flex:none}

/* 「或使用以下方式」分隔：線從文字兩側長出，不是一條線再壓一段文字上去。
   線用 --line（純裝飾、非唯一識別，不受 3:1 規範）；文字用 --ink-2 才讀得到。 */
.or-sep{display:flex;align-items:center;gap:var(--s2);margin:var(--s3) 0 var(--s2)}
.or-sep::before,.or-sep::after{content:"";flex:1;height:1px;background:var(--line)}
.or-sep span{font-size:.85rem;color:var(--ink-2);white-space:nowrap}
.btn-ghost:hover{color:var(--orange-deep);text-decoration:underline;background:var(--orange-soft)}

/* 破壞性操作：預設只有外框，不是實心紅。
   實心紅會跟主要行動（橘底「儲存變更」）在視覺重量上打平，
   讓「刪除」看起來跟「儲存」一樣理所當然。要按下去才變實心。
   hover 的白字在 --warn 上是 7.27:1 ✓ AA。 */
.btn-danger{background:transparent;border-color:var(--warn);color:var(--warn)}
.btn-danger:hover{background:var(--warn);color:#fff;transform:translateY(-3px);box-shadow:var(--sh2)}


.btn-sm{min-height:var(--tap);padding:10px 20px;font-size:.9rem}
.btn-lg{min-height:60px;padding:18px 36px;font-size:1.1rem}
.btn-block{width:100%}
.btn[disabled],.btn.disabled{opacity:.45;cursor:not-allowed;pointer-events:none;transform:none;box-shadow:none}
.btn-row{display:flex;gap:var(--s2);flex-wrap:wrap;align-items:center}

/* =====================================================================
   Grid helpers — grid 是對齊基礎建設，不是構圖本身
   ===================================================================== */
.grid{display:grid;gap:var(--s3)}
.g2{grid-template-columns:1fr 1fr}
.g3{grid-template-columns:repeat(3,1fr)}
.g4{grid-template-columns:repeat(4,1fr)}
.g-sidebar{grid-template-columns:1fr 340px}
.g-aside{grid-template-columns:320px 1fr}
.stack{display:flex;flex-direction:column;gap:var(--s2)}
.rowflex{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap}

/* =====================================================================
   Cards / panels — 四級景深（指南 §04）
   ===================================================================== */
.panel{border:1px solid var(--line);border-radius:var(--r);background:var(--card);box-shadow:var(--sh1)}
.panel .p-head{padding:var(--s2) var(--s3);border-bottom:1px solid var(--line);display:flex;align-items:center;gap:12px}
.panel .p-head h3{font-size:1.25rem}
.panel .p-head .sp{flex:1}
.panel .p-body{padding:var(--s3)}
.panel .p-body.tight{padding:0}
.panel .p-foot{padding:var(--s2) var(--s3);border-top:1px solid var(--line);display:flex;gap:12px;align-items:center;flex-wrap:wrap}

/* 危險區：與日常操作的卡片明確區隔。
   底用極淡的警示色而非實心紅 —— 它是「注意」不是「警報」，
   進到這一頁不該像出事了。
   必須定義在 .panel 之後：兩者特異性相同，先定義的 .panel 會蓋掉 border-color。 */
.danger-zone{
  border-color:var(--warn);
  background:linear-gradient(0deg, var(--warn-wash), var(--warn-wash)), var(--card);
  margin-top:var(--s4);
}

.card{
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden;
  background:var(--card);display:flex;flex-direction:column;box-shadow:var(--sh1);
  transition:transform var(--dur-hover) var(--ease-out),box-shadow var(--dur-hover),border-color var(--dur-ui);
}
.card.click{cursor:pointer}
.card.click:hover{transform:translateY(-8px);box-shadow:var(--sh3)}
.card .ph{background:linear-gradient(135deg,#e7e2db,#dcd6ce);position:relative;border-bottom:1px solid var(--line);overflow:hidden}
.card .ph.r169{aspect-ratio:16/10}
.card .ph.r43{aspect-ratio:4/3}
.card .ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.card .ph .badge{position:absolute;left:14px;top:14px;z-index:1}
.card .body{padding:var(--s3);flex:1;display:flex;flex-direction:column}
.card .ov{font-size:.72rem;letter-spacing:.14em;text-transform:uppercase;color:var(--orange-deep);font-weight:700}
.card h4{font-size:1.2rem;margin:9px 0 7px}
.card .meta{font-size:.9rem;color:var(--ink-2);margin-bottom:var(--s2)}
.card .price{display:flex;gap:var(--s3);align-items:baseline;border-top:1px solid var(--line);padding-top:var(--s2);margin-top:auto}
.card .price .p{font-size:1.05rem;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.card .price .k{font-size:.72rem;color:var(--ink-3);display:block;letter-spacing:.05em}

/* =====================================================================
   Status badges — 統一色語意（訂單/審核/購物金/佣金）
   ===================================================================== */
.badge{
  display:inline-flex;align-items:center;gap:6px;border-radius:999px;
  padding:5px 12px;font-size:.78rem;font-weight:700;line-height:1.5;
  border:1px solid transparent;white-space:nowrap;
}
.badge .d{width:7px;height:7px;border-radius:50%;background:currentColor;flex-shrink:0}
.badge-neutral{background:var(--neutral-wash);color:var(--ink-2)}
.badge-info{background:var(--info-wash);color:var(--info)}
.badge-accent{background:var(--orange-soft);color:var(--orange-deep)}
.badge-success{background:var(--success-wash);color:var(--success)}
.badge-warn{background:var(--warn-wash);color:var(--warn)}
.badge-ink{background:var(--ink);color:var(--bg)}
.badge-outline{background:transparent;border-color:var(--line-strong);color:var(--ink-2)}

/* =====================================================================
   Tables — 中高齡友善：列高寬鬆、標頭不縮小、數字表格化對齊
   ===================================================================== */
.table-wrap{border:1px solid var(--line);border-radius:var(--r);overflow-x:auto;background:var(--card);box-shadow:var(--sh1)}
table.data{width:100%;border-collapse:collapse;font-size:.95rem;min-width:600px}
table.data th{
  text-align:left;font-size:.78rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-2);font-weight:700;padding:var(--s2);
  border-bottom:1px solid var(--line);background:var(--muted);white-space:nowrap;
}
table.data td{padding:var(--s2);border-bottom:1px solid var(--line-2);color:var(--ink-2);vertical-align:middle}
table.data tr:last-child td{border-bottom:0}
table.data tbody tr:hover td{background:var(--muted)}
table.data td.num{text-align:right;font-variant-numeric:tabular-nums;color:var(--ink)}
table.data td .strong{color:var(--ink);font-weight:700}
table.data .row-click{cursor:pointer}

/* =====================================================================
   Forms — 54px 高、標籤在上、2px 可辨識邊界（指南 §05/§06）
   ===================================================================== */
.field{margin-bottom:var(--s3)}
.field label{display:block;font-size:1.05rem;color:var(--ink);margin-bottom:9px;font-weight:600}
.field label .req{color:var(--warn);margin-left:3px}
.input,.select,.textarea{
  width:100%;background:var(--card-hi);
  border:2px solid var(--line-strong);   /* 3.42:1 ✓ 邊界是控制項的唯一識別 */
  border-radius:12px;padding:14px 15px;
  font-size:1.05rem;color:var(--ink);min-height:var(--tap-lg);
  transition:border-color var(--dur-ui),box-shadow var(--dur-ui);
}
.input:focus,.select:focus,.textarea:focus{
  outline:none;border-color:var(--orange-deep);
  box-shadow:0 0 0 4px var(--orange-ring);
}
.input::placeholder,.textarea::placeholder{color:var(--ink-3)}
.input:disabled,.select:disabled,.textarea:disabled{background:var(--muted);color:var(--ink-3);cursor:not-allowed;border-color:var(--line)}
.textarea{min-height:120px;resize:vertical;line-height:1.7}
.help{font-size:.95rem;color:var(--ink-2);margin-top:8px}

/* 錯誤：不只靠顏色，另有 ✕ 記號與文字（指南：勿以顏色作為唯一資訊） */
.field .err{font-size:.95rem;color:var(--warn);margin-top:8px;font-weight:600;display:flex;gap:6px;align-items:flex-start}
.field .err::before{content:"\2715";flex-shrink:0}  /* ✕ CSS 轉義：避免無 charset 時被當 Latin-1 解成亂碼 */
.field.invalid .input,.field.invalid .select,.field.invalid .textarea{border-color:var(--warn)}

.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 var(--s3)}
.inline-row{display:flex;gap:var(--s2);align-items:flex-end;flex-wrap:wrap}
.checkline{
  display:flex;align-items:flex-start;gap:12px;font-size:.95rem;color:var(--ink-2);
  cursor:pointer;padding:10px 0;min-height:var(--tap);
}
.checkline input{margin-top:3px;accent-color:var(--orange-deep);width:22px;height:22px;flex-shrink:0;cursor:pointer}

/* Segmented control */
.seg{display:inline-flex;border:1px solid var(--line);border-radius:999px;padding:4px;background:var(--muted);gap:2px}
.seg button{
  border:0;background:transparent;color:var(--ink-2);font-size:.9rem;font-weight:600;
  padding:0 var(--s2);min-height:44px;border-radius:999px;cursor:pointer;
  transition:background var(--dur-ui),color var(--dur-ui);
}
.seg button:hover:not(.on){color:var(--ink)}
.seg button.on{background:var(--orange);color:var(--ink);font-weight:700;box-shadow:var(--sh1)}

/* =====================================================================
   Tags / chips — 可點者 ≥44px
   ===================================================================== */
.tags{display:flex;flex-wrap:wrap;gap:11px}
.tag{
  border:1.5px solid var(--line);border-radius:999px;padding:9px 17px;
  font-size:.9rem;color:var(--ink-2);background:var(--card);
  min-height:44px;display:inline-flex;align-items:center;
}
.tag.click{cursor:pointer;transition:border-color var(--dur-ui),background var(--dur-ui)}
.tag.click:hover{border-color:var(--ink-3);background:var(--card-hi)}
.tag.on{background:var(--orange);color:var(--ink);border-color:var(--orange);font-weight:700}
.tag.acc{border-color:var(--orange-deep);color:var(--orange-deep)}

/* =====================================================================
   Stat tiles + mini bar chart
   ===================================================================== */
.tiles{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s2)}
.tile{border:1px solid var(--line);border-radius:var(--r);padding:var(--s3);background:var(--card);box-shadow:var(--sh1)}
.tile .k{font-size:.78rem;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);font-weight:700}
.tile .v{font-size:1.8rem;font-weight:800;letter-spacing:-.02em;margin:8px 0 2px;font-variant-numeric:tabular-nums;color:var(--ink)}
.tile .sub{font-size:.85rem;color:var(--ink-2)}
/* 漲跌不只用顏色，另帶 ▲▼ 記號 */
.tile .sub .up{color:var(--success);font-weight:700}
.tile .sub .up::before{content:"\25B2  "}  /* ▲ + 空格（第一個空格是轉義結束符會被吃掉，故留兩個） */
.tile .sub .down{color:var(--warn);font-weight:700}
.tile .sub .down::before{content:"\25BC  "}  /* ▼ + 空格，同上 */

.bars{display:flex;align-items:flex-end;gap:12px;height:170px;padding-top:12px}
.bars .bar{flex:1;display:flex;flex-direction:column;align-items:center;gap:10px;justify-content:flex-end;height:100%}
.bars .bar .fill{width:100%;max-width:42px;background:var(--orange);border-radius:6px 6px 0 0;min-height:3px}
.bars .bar .fill.alt{background:var(--ink-3)}
.bars .bar .lbl{font-size:.78rem;color:var(--ink-2);white-space:nowrap}
.legend{display:flex;gap:var(--s3);margin-top:var(--s2);font-size:.85rem;color:var(--ink-2);flex-wrap:wrap}
.legend .k{display:inline-flex;align-items:center;gap:8px}
.legend .k .sw{width:12px;height:12px;border-radius:3px;display:inline-block;flex-shrink:0}

/* =====================================================================
   Tabs
   ===================================================================== */
/* overflow-y 必須明寫成 hidden：依 CSS 規範，overflow-x 是 auto 而 overflow-y 是
   visible 時，overflow-y 會被計算成 auto —— 頁籤的 margin-bottom:-1px（用來讓
   底線壓在容器邊框上）就會溢出 1px，右側因此長出一條沒有用的垂直捲軸。
   只留橫向捲動：頁籤多到裝不下時要能滑，但永遠不需要上下捲。 */
.tabs{display:flex;gap:4px;border-bottom:1px solid var(--line);margin-bottom:var(--s4);overflow-x:auto;overflow-y:hidden}
/* 頁籤同時支援 <button>（前端切換）與 <a>（伺服器端切換，各自一個網址）。
   系統紀錄的兩個頁籤是各自查詢的，用連結才能被收藏、被上一頁回到。 */
.tabs button,.tabs a{
  border:0;background:transparent;color:var(--ink-2);font-size:.95rem;font-weight:600;
  padding:0 var(--s2);min-height:var(--tap);cursor:pointer;
  display:inline-flex;align-items:center;text-decoration:none;
  border-bottom:3px solid transparent;margin-bottom:-1px;white-space:nowrap;
  transition:color var(--dur-ui),border-color var(--dur-ui);
}
.tabs button:hover,.tabs a:hover{color:var(--ink);text-decoration:none}
.tabs button.on,.tabs a.on{color:var(--orange-deep);border-bottom-color:var(--orange);font-weight:700}

/* =====================================================================
   Chat
   ===================================================================== */
.chat{
  display:flex;flex-direction:column;height:calc(100vh - var(--topbar-h) - 140px);min-height:480px;
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--card);box-shadow:var(--sh1);
}
.chat .c-head{padding:var(--s2) var(--s3);border-bottom:1px solid var(--line);display:flex;align-items:center;gap:12px}
.chat .c-body{flex:1;overflow-y:auto;padding:var(--s3);display:flex;flex-direction:column;gap:var(--s2);background:var(--surface)}
.bubble{max-width:74%;padding:12px 16px;border-radius:var(--r);font-size:.95rem;line-height:1.65;position:relative}
.bubble .t{display:block;font-size:.72rem;color:var(--ink-3);margin-top:5px;letter-spacing:.03em}
.bubble.them{align-self:flex-start;background:var(--card-hi);border:1px solid var(--line);border-bottom-left-radius:4px}
/* 自己的訊息：深炭底白字 14.5:1 ✓（亮橘底白字僅 2.61:1，不可用） */
.bubble.me{align-self:flex-end;background:var(--ink);color:#fff;border-bottom-right-radius:4px}
.bubble.me .t{color:rgba(255,255,255,.72)}
.bubble.sys{align-self:center;background:transparent;border:1px dashed var(--line-strong);color:var(--ink-2);font-size:.85rem;max-width:90%}

/* 收款連結卡片（type=payment） */
.bubble.pay{background:transparent;border:none;padding:0;max-width:84%}
.bubble.pay.me{align-self:flex-end}
.bubble.pay.them{align-self:flex-start}
.pay-card{border:1.5px solid var(--orange);border-radius:var(--r);background:var(--card-hi);padding:14px 16px;min-width:200px}
.pay-h{font-size:.78rem;font-weight:700;color:var(--orange-deep);letter-spacing:.04em}
.pay-amt{font-size:1.35rem;font-weight:800;color:var(--ink);margin-top:2px;font-variant-numeric:tabular-nums}
.pay-note{font-size:.85rem;color:var(--ink-2);margin-top:4px}
.pay-card .pay-btn{margin-top:10px;width:100%}
.pay-done{margin-top:10px;font-weight:700;color:var(--success);font-size:.9rem}
.pay-pending{margin-top:10px;color:var(--ink-3);font-size:.85rem}

/* 已結單封存的對話：唯讀提示條，取代輸入框 */
.c-archived-bar{padding:14px var(--s2);border-top:1px solid var(--line);background:var(--card-hi);
  color:var(--ink-2);font-size:.88rem;line-height:1.6;text-align:center}
.c-archived-bar a{color:var(--orange-deep);font-weight:600}
.chat-archived .c-head{opacity:.85}

/* 可拖曳的浮動小彈窗（後台聊天用：收款連結、發放購物金） */
.pop{position:fixed;z-index:1200;width:340px;max-width:calc(100vw - 24px);
  background:var(--card);border:1px solid var(--line-strong);border-radius:14px;
  box-shadow:0 20px 55px rgba(0,0,0,.28);overflow:hidden}
.pop-head{display:flex;justify-content:space-between;align-items:center;gap:10px;
  padding:12px 14px;background:var(--card-hi);border-bottom:1px solid var(--line);
  cursor:move;user-select:none;touch-action:none;font-weight:700;font-size:.9rem;color:var(--ink)}
.pop-close{background:none;border:none;font-size:15px;line-height:1;cursor:pointer;color:var(--ink-3);padding:4px}
.pop-close:hover{color:var(--ink)}
.pop-body{padding:14px 16px 16px}
.pop-body label{display:block;font-size:12.5px;color:var(--ink-2);margin:10px 0 4px}
.pop-body label:first-child{margin-top:0}
/* 付款彈窗的應收金額：唯讀顯示，不是輸入框。
   金額由訂單決定，顧問改不了 —— 長得像可以填的欄位反而會讓人想去改。 */
.pop-amount{font-size:1.35rem;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums;
  background:var(--muted,#f3f4f5);border-radius:8px;padding:10px 12px}
.pop-body .input,.pop-body .select{width:100%}
/* 快速回覆列：輸入框上方，按一下就送出。
   橫向捲動而非換行：句子完整所以每顆都寬，換行會把輸入框一路往下推，
   訊息區被壓到只剩幾行。捲動列固定一行高，版面不會因為改幾句文案而位移。 */
.chat .c-quick{
  display:flex;gap:10px;align-items:center;
  padding:10px var(--s2);border-top:1px solid var(--line);background:var(--card);
  overflow-x:auto;
  /* 捲到盡頭不要把捲動傳給訊息區 */
  overscroll-behavior-x:contain;
  scrollbar-width:thin;
}
.chat .c-quick-lbl{
  flex:none;font-size:.8rem;color:var(--ink-3);font-weight:700;
  letter-spacing:.06em;padding-right:2px;
}
/* 沿用 .tag.click 的外觀，只補按鈕該有的收斂：不換行、不被 flex 壓扁 */
.chat .c-quick .tag{flex:none;white-space:nowrap;font-size:.88rem;padding:8px 15px}
.chat .c-quick .tag:active{background:var(--orange-soft);border-color:var(--orange)}

.chat .c-input{padding:12px var(--s2);border-top:1px solid var(--line);display:flex;gap:12px;align-items:center;background:var(--card)}
.chat .c-input input{
  flex:1;border:2px solid var(--line-strong);border-radius:999px;padding:12px 18px;
  font-size:.95rem;background:var(--card-hi);color:var(--ink);min-height:var(--tap);
}
.chat .c-input input:focus{outline:none;border-color:var(--orange-deep);box-shadow:0 0 0 4px var(--orange-ring)}

/* ── 彈窗裡的聊天（後台「開啟對話」）────────────────────────────
   輸入框釘在底部，只有訊息區捲動。

   必須放在 .chat .c-body 之後、且用 .modal 前綴拉高特異度：
   先前寫在前面且同特異度，被 .chat .c-body{flex:1} 蓋掉 ——
   而 flex:1 隱含 flex-basis:0%，連帶把行內的 height 也一起蓋掉，
   於是訊息區無限長高、把輸入框推出視野，變成整個彈窗在捲。 */
.modal .chat-modal{
  height:66vh;                  /* 有界高度，內部 flex 才有東西可分配 */
  min-height:280px;
  border:0;box-shadow:none;background:transparent;
}
.modal .chat-modal .c-body{
  flex:1 1 auto;
  /* min-height:0 是 flexbox 能捲動的關鍵：不加的話 flex 子元素不會縮到
     比內容小，overflow 永遠不觸發，內容直接把容器撐爆。 */
  min-height:0;
  height:auto;
  overflow-y:auto;
  /* 捲到盡頭時不要把捲動傳給彈窗 */
  overscroll-behavior:contain;
  border-radius:var(--r-sm) var(--r-sm) 0 0;
}
/* 輸入列不參與伸縮，永遠留在底部 */
.modal .chat-modal .c-input{
  flex:0 0 auto;
  border-radius:0 0 var(--r-sm) var(--r-sm);
  border:1px solid var(--line);border-top-color:var(--line);
}

/* 對話列表的可收合外殼（會員平台聊天）。
   桌機是兩欄並排、列表本來就該一直在，所以那裡完全不顯示 summary，
   只有窄螢幕（列表被排到聊天室上方）才需要收合。 */
.conv-collapse-sum{display:none}
.conv-list{display:flex;flex-direction:column;gap:2px}
.conv-item{display:flex;gap:12px;padding:12px 14px;border-radius:var(--r-sm);cursor:pointer;align-items:center;min-height:var(--tap);transition:background var(--dur-ui)}
.conv-item:hover{background:var(--muted)}
.conv-item.on{background:var(--orange-soft)}
.conv-item .av{
  width:42px;height:42px;border-radius:50%;background:var(--muted);flex-shrink:0;display:flex;
  align-items:center;justify-content:center;font-size:.9rem;font-weight:700;color:var(--ink-2);border:1px solid var(--line);
}
.conv-item .info{flex:1;min-width:0}
.conv-item .info .nm{font-size:.95rem;font-weight:700;color:var(--ink);display:flex;justify-content:space-between;gap:8px}
.conv-item .info .nm .tm{font-size:.72rem;color:var(--ink-3);font-weight:400}
.conv-item .info .pv{font-size:.85rem;color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.conv-item .unread{width:10px;height:10px;border-radius:50%;background:var(--orange);flex-shrink:0}

/* =====================================================================
   Step indicator
   ===================================================================== */
.steps{display:flex;align-items:center;gap:0;margin-bottom:var(--s4);flex-wrap:wrap}
.steps .step{display:flex;align-items:center;gap:10px;color:var(--ink-3)}
.steps .step .n{
  width:32px;height:32px;border-radius:50%;border:2px solid var(--line-strong);display:flex;
  align-items:center;justify-content:center;font-size:.85rem;font-weight:700;flex-shrink:0;
}
.steps .step .t{font-size:.9rem;white-space:nowrap}
/* 已完成：橘底深炭字 + ✓ 記號（不只靠顏色分辨狀態） */
.steps .step.done{color:var(--orange-deep)}
.steps .step.done .n{background:var(--orange);border-color:var(--orange);color:var(--ink)}
.steps .step.on{color:var(--ink);font-weight:700}
.steps .step.on .n{border-color:var(--ink);color:var(--ink);background:var(--card-hi)}
.steps .bar{flex:1;height:2px;background:var(--line-strong);margin:0 var(--s2);min-width:24px;transform-origin:left center}
.steps .step .n{transform-origin:center}

/* =====================================================================
   Empty / loading
   ===================================================================== */
.empty{text-align:center;padding:var(--s8) var(--s3);color:var(--ink-2)}
.empty .ico{font-size:2.2rem;margin-bottom:var(--s2);color:var(--ink-3)}
.empty h4{font-size:1.15rem;color:var(--ink);margin-bottom:8px}
.empty p{font-size:.95rem;margin:0 auto var(--s3);max-width:44ch}

.skeleton{
  background:linear-gradient(90deg,var(--muted) 25%,var(--line-2) 37%,var(--muted) 63%);
  background-size:400% 100%;animation:sk 1.4s ease infinite;border-radius:var(--r-sm);
}
@keyframes sk{0%{background-position:100% 0}100%{background-position:-100% 0}}
.spinner{
  width:26px;height:26px;border:3px solid var(--line);border-top-color:var(--orange-deep);
  border-radius:50%;animation:spin .7s linear infinite;display:inline-block;
}
@keyframes spin{to{transform:rotate(360deg)}}
.loading-block{display:flex;flex-direction:column;align-items:center;gap:var(--s2);padding:var(--s8);color:var(--ink-2);font-size:.95rem}

/* =====================================================================
   Modal
   ===================================================================== */
.modal-scrim{
  position:fixed;inset:0;background:rgba(44,41,38,.5);backdrop-filter:blur(2px);z-index:60;
  display:flex;align-items:center;justify-content:center;padding:var(--s3);
  opacity:0;pointer-events:none;transition:opacity var(--dur-ui);
}
.modal-scrim.on{opacity:1;pointer-events:auto}
/* 彈窗開著時鎖住背景（由 ui.js 的 lockScroll 加上）。
   position:fixed 而非 overflow:hidden —— iOS Safari 不理會 body 的 overflow。
   top 由 JS 設成 -捲動位置，才不會跳回頂端。 */
body.modal-open{position:fixed;width:100%;overflow:hidden}
.modal{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--sh3);
  width:100%;max-width:520px;max-height:90vh;overflow-y:auto;
  /* 捲到彈窗盡頭時不把捲動傳給後面（body 已鎖，但觸控板的橡皮筋效果仍會抖） */
  overscroll-behavior:contain;
  transform:translateY(8px);transition:transform var(--dur-ui);
}
.modal-scrim.on .modal{transform:translateY(0)}
.modal.wide{max-width:760px}
/* 更寬：給欄數多的表格（如 §3.3 權限矩陣：權限項 + 5 個角色 = 6 欄）。
   760px 塞 6 欄中文標題會擠成兩行。 */
.modal.xwide{max-width:980px}
/* 表格在 modal 裡要能自己橫向捲，不能讓整個 modal 長出橫捲軸 */
.modal .m-body .table-wrap{max-width:100%}
/* 標題列釘住：.modal 整塊 overflow-y:auto，內容一長（權限矩陣、新增規則表單）
   標題和 ✕ 就一起捲出視野 —— 想關掉還得先捲回頂端。
   要蓋住捲上來的內容，所以需要不透明底色。 */
.modal .m-head{
  padding:var(--s3) var(--s3) var(--s2);display:flex;align-items:flex-start;gap:12px;
  position:sticky;top:0;z-index:1;background:var(--card);
  border-bottom:1px solid var(--line-2);
}
.modal .m-head h3{font-size:1.25rem;flex:1}
.modal .m-close{
  border:0;background:transparent;color:var(--ink-2);font-size:1.3rem;cursor:pointer;line-height:1;
  min-width:var(--tap);min-height:var(--tap);border-radius:var(--r-sm);
  display:inline-flex;align-items:center;justify-content:center;
}
.modal .m-close:hover{background:var(--muted);color:var(--ink)}
.modal .m-body{padding:var(--s2) var(--s3) var(--s3)}
.modal .m-body p{color:var(--ink-2);font-size:.98rem;margin:0 0 12px}
.modal .m-foot{padding:0 var(--s3) var(--s3);display:flex;gap:12px;justify-content:flex-end;flex-wrap:wrap}

/* =====================================================================
   Toast
   ===================================================================== */
.toast-wrap{
  position:fixed;top:calc(var(--topbar-h) + 14px);right:var(--s3);z-index:80;
  display:flex;flex-direction:column;gap:12px;max-width:min(380px,calc(100vw - 40px));
}
.toast{
  background:var(--card);border:1px solid var(--line);border-left:4px solid var(--ink);
  border-radius:var(--r-sm);padding:var(--s2);box-shadow:var(--sh3);
  font-size:.95rem;color:var(--ink);display:flex;gap:12px;align-items:flex-start;
  animation:toastin .25s var(--ease-out);
}
.toast.success{border-left-color:var(--success)}
.toast.warn{border-left-color:var(--warn)}
.toast.info{border-left-color:var(--info)}
.toast .tx{flex:1}
.toast .tx b{display:block;font-weight:700;font-size:.95rem}
.toast .tx span{color:var(--ink-2);font-size:.85rem}
@keyframes toastin{from{opacity:0;transform:translateX(16px)}to{opacity:1;transform:translateX(0)}}

/* =====================================================================
   分頁 Pagination（指南 §15.2）
   規則：頁碼按鈕 ≥44px、當前頁亮橘、上一頁/下一頁附文字。
   「附文字」不是裝飾：只有 ‹ › 兩個箭頭，對讀螢幕的人與不熟網路的長者是謎題。
   ===================================================================== */
.pager{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:var(--s3)}
.pg-nums{display:flex;gap:4px;flex-wrap:wrap}
.pg{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:var(--tap);min-height:var(--tap);padding:0 14px;
  border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--card);color:var(--ink-2);
  font-size:.95rem;font-weight:600;text-decoration:none;white-space:nowrap;
  transition:background var(--dur-ui),border-color var(--dur-ui),color var(--dur-ui);
}
a.pg:hover{background:var(--card-hi);border-color:var(--ink-3);color:var(--ink);text-decoration:none}
/* 當前頁：亮橘底 + 深炭字 = 5.05:1 ✓（橘不可當文字色，§2.3） */
.pg.on{background:var(--orange);border-color:var(--orange);color:var(--ink);font-weight:700}
.pg.disabled{opacity:.4;cursor:not-allowed;background:transparent;border-style:dashed}
.pg.dots{border:0;background:transparent;min-width:auto;padding:0 4px;color:var(--ink-3)}
.pg-count{margin-left:auto;font-size:.85rem;color:var(--ink-2)}
@media(max-width:600px){
  .pg-count{margin-left:0;width:100%;text-align:center}
}

/* 權限矩陣的可點格子（§3.3）。
   符號本身表意（✔／✗），顏色只是輔助 —— 色盲者也分得出（指南 §7.2）。
   ≥44px 觸控下限：它是可點目標，不因為在表格裡就例外（指南 §04）。 */
.perm-cell{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;padding:0;
  border:1px solid transparent;border-radius:var(--r-sm);
  background:transparent;color:var(--ink-3);
  font-size:1.05rem;font-weight:700;cursor:pointer;
  transition:background var(--dur-ui),border-color var(--dur-ui),color var(--dur-ui);
}
.perm-cell.on{color:var(--success)}
button.perm-cell:hover{background:var(--muted);border-color:var(--line-strong)}
button.perm-cell:hover.on{color:var(--warn)}      /* 已授予 → hover 暗示「點了會移除」 */
button.perm-cell:hover:not(.on){color:var(--success)}
/* 固定欄（super_admin）：不可點，游標也要說出來 */
.perm-cell.fixed{cursor:not-allowed;opacity:.75}

/* ── 右側抽屜（聊天室的「客戶資料」）────────────────────────────
   z-index 高於彈窗（60）：它是開在彈窗之上的輔助面板，不是取代它。
   位移用 transform 而非 right/left —— 那是合成層屬性，不觸發版面重排。 */
.side-drawer{
  position:fixed;top:0;right:0;height:100vh;z-index:70;
  width:min(360px, 92vw);
  background:var(--card);border-left:1px solid var(--line);box-shadow:var(--sh3);
  display:flex;flex-direction:column;
  transform:translateX(100%);
}
/* 開合狀態由 class 決定，不由動畫決定。
   先前 .side-drawer 只有 translateX(100%)，全靠 GSAP 補間把它推進來 ——
   補間一旦沒推進（某些環境 rAF 不跑），面板就永遠卡在畫面外，等於功能壞掉。
   motion.js 的原則寫得很清楚：「GSAP 沒載到 → 直接把內容顯示出來」。
   動畫是修飾，不能是「看不看得見」的唯一依據。 */
.side-drawer.on{transform:translateX(0)}
.side-drawer .d-head{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:var(--s2) var(--s3);border-bottom:1px solid var(--line-2);
  flex:0 0 auto;
}
.side-drawer .d-head h3{font-size:1.05rem;margin:0;color:var(--ink)}
.side-drawer .d-body{
  flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  padding:var(--s3);
}
.side-drawer .d-close{
  border:0;background:transparent;cursor:pointer;color:var(--ink-2);
  font-size:1.1rem;line-height:1;padding:8px 10px;border-radius:var(--r-sm);
  min-width:40px;min-height:40px;
}
.side-drawer .d-close:hover{background:var(--muted);color:var(--ink)}

/* 客服備註：後台限定，用底色跟其他欄位區隔 —— 別讓人誤以為是客戶自己填的 */
.note-box{
  background:var(--orange-soft);border:1px solid var(--line-2);
  border-radius:var(--r-sm);padding:12px 14px;
}

/* 後台備註的就地編輯（x-note-editor）：會員備註與訂單備註共用。
   底色沿用 .note-box 的暖橘，一眼看得出「這是內部註記、不是給會員看的」。 */
.note-editor{
  background:var(--orange-soft);border:1px solid var(--line-2);
  border-radius:var(--r-sm);padding:12px 14px;
}
.note-editor .textarea{width:100%;background:var(--card-hi)}
.note-editor-foot{display:flex;align-items:center;gap:12px;margin-top:10px;flex-wrap:wrap}
.note-editor-msg{font-size:.85rem;color:var(--ink-3)}
.note-editor-msg.ok{color:var(--success);font-weight:700}
.note-editor-msg.bad{color:var(--warn);font-weight:700}

/* 需求單詳情（訂單管理的「看內容」彈窗）：兩欄定義清單 */
.req-detail{display:grid;grid-template-columns:auto 1fr;gap:8px 18px;margin:0}
.req-detail dt{color:var(--ink-2);font-weight:600;font-size:.9rem}
.req-detail dd{margin:0;color:var(--ink);font-size:.95rem}

/* ── 身分組看板（§3.2 五角色 ＋ 未分配）──────────────────────── */
.boards{
  display:grid;gap:var(--s2);
  /* 六個板塊。auto-fit + minmax：窄螢幕自己減欄，不必逐級寫 media query。
     280px 是下限：卡片裡要放得下頭像＋中文姓名，再窄姓名就只剩兩三個字。 */
  grid-template-columns:repeat(auto-fit, minmax(280px, 1fr));
  align-items:start;
}
.board{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  transition:border-color var(--dur-ui),background var(--dur-ui);
}
/* 位階擋下的板塊（與自己同級或在自己之上）：整塊壓暗，說明它不參與拖放。
   不用 opacity 壓整塊 —— 那會把裡面的文字一起弄到不合對比度。 */
.board.locked{background:var(--muted);border-style:dashed}
.board.locked .board-head h3{color:var(--ink-2)}
/* 拖曳中：可放的板塊亮起來，一眼看出哪裡放得下 */
.board.droppable{border-color:var(--orange);border-style:dashed}
.board.over{border-color:var(--orange);background:var(--orange-soft);border-style:solid}

.board-head{
  display:flex;align-items:flex-start;justify-content:space-between;gap:10px;
  padding:14px 16px;border-bottom:1px solid var(--line-2);
}
.board-head h3{font-size:1rem;margin:0;color:var(--ink);font-weight:600}
.board-list{list-style:none;margin:0;padding:10px;display:flex;flex-direction:column;gap:8px;min-height:76px}
.board-empty{padding:18px 6px;text-align:center;font-size:.85rem}

.staff-card{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:10px;border:1px solid var(--line-2);border-radius:var(--r-sm);
  background:var(--card-hi);
}
/* 只有搬得動的卡片給抓手游標：游標是承諾，拖不動就別說可以拖 */
.staff-card.movable{cursor:grab}
.staff-card.movable:active{cursor:grabbing}
.staff-card.dragging{opacity:.4}
.sc-main{flex:1;min-width:0}
/* 中文沒有詞邊界：欄寬一擠，瀏覽器就逐字斷行，「系統管理員」會變成直書。
   一律不換行，放不下就截尾 —— 全名在 title 裡。 */
.sc-name{
  color:var(--ink);font-weight:600;font-size:.92rem;
  display:flex;align-items:center;gap:6px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.sc-name > span{flex-shrink:0}                    /* 「你」的標籤不參與截尾 */
.sc-mail{font-size:10.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* 動作固定排第二列。六個看板並排時單欄只有 ~260px，
   頭像＋姓名＋編輯鈕＋選單擠在同一列必定把姓名壓成直書。 */
.sc-act{display:flex;align-items:center;gap:6px;width:100%;justify-content:flex-end}
.sc-move{font-size:.78rem;padding:5px 8px;min-width:96px}
.sc-lock{font-size:.9rem;opacity:.6}

/* 搬進標題列的動作鈕（如聊天彈窗的「客戶資料」）：
   .m-head 的 h3 是 flex:1，所以按鈕自然被推到右邊、關閉鈕左側。
   align-self 讓它與標題基線對齊而非被拉伸。 */
.modal .m-head .btn{flex:0 0 auto;align-self:flex-start}

/* 會員 ID ＋ 複製鈕：ID 與按鈕同一行、按鈕不要撐開行高 */
.id-copy{display:inline-flex;align-items:center;gap:8px}
.id-copy .btn{min-height:32px;padding:5px 10px;font-size:.8rem}

/* =====================================================================
   站內通知（小鈴鐺）
   ===================================================================== */
.bell-btn{position:relative;color:var(--ink-2)}
.bell-btn:hover{color:var(--ink)}
/* 有未讀時鈴鐺本身轉成強調色：角落那顆紅點在小尺寸下很容易被忽略，
   讓整個圖示也帶訊號，兩層提示（顏色＋數字）而不是只靠一個小點。 */
.bell-btn.has-unread{color:var(--orange-deep)}
.bell-btn svg{display:block}
/* 面板比一般選單寬：通知有標題＋內文＋時間三行，太窄會每則都折成五行 */
.notify-panel{min-width:min(340px,calc(100vw - 32px));max-height:min(70vh,520px)}
.notify-item-form{display:block}
.notify-item{
  display:flex;gap:10px;width:100%;text-align:left;align-items:flex-start;
  padding:11px 12px;border:0;background:transparent;border-radius:var(--r-sm);
  cursor:pointer;color:var(--ink-2);min-height:var(--tap);
  transition:background var(--dur-ui);
}
.notify-item:hover{background:var(--muted)}
/* 未讀用「圓點＋較深的字」兩種訊號，不只靠顏色（指南 §7.2） */
.notify-dot{width:8px;height:8px;border-radius:50%;background:transparent;flex:none;margin-top:7px}
.notify-item.unread .notify-dot{background:var(--orange)}
.notify-item.unread .notify-title{color:var(--ink);font-weight:700}
.notify-body{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.notify-title{font-size:.92rem;font-weight:600;color:var(--ink-2);line-height:1.4}
.notify-text{font-size:.82rem;color:var(--ink-3);line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.notify-time{font-size:.72rem;color:var(--ink-3);font-variant-numeric:tabular-nums}
.notify-all{justify-content:center;border-top:1px solid var(--line);margin-top:4px;font-weight:700}

/* =====================================================================
   工作台（顧問／客服的快速檢視面板）
   ===================================================================== */
/* 一列一件事：左邊是「是什麼」，右邊是「能做什麼」。
   用列而不是表格：每列的動作按鈕寬度不一，表格欄寬會被最寬的那個綁死。 */
.ws-row{
  display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;
  padding:14px var(--s3);border-bottom:1px solid var(--line-2);
}
.ws-row:last-child{border-bottom:0}
.ws-row:hover{background:var(--surface)}
.ws-main{flex:1;min-width:0}
.ws-main .strong{color:var(--ink);font-weight:600}
.ws-sub{color:var(--ink-2);font-size:.85rem;margin-top:3px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ws-side{display:flex;align-items:center;gap:10px;flex:none;flex-wrap:wrap}
.ws-empty{padding:22px var(--s3);color:var(--ink-3);font-size:.9rem;text-align:center}

/* =====================================================================
   會員選擇器（購物金發放）
   ===================================================================== */
.mpick{position:relative}
/* 已選的會員：標籤排在輸入框上方，一眼看得出「這次要發給誰」 */
.mpick-chips{display:flex;flex-wrap:wrap;gap:8px}
.mpick-chips:not(:empty){margin-bottom:8px}
.mpick-chip{
  display:inline-flex;align-items:center;gap:8px;
  background:var(--orange-soft);color:var(--orange-deep);
  border-radius:999px;padding:6px 8px 6px 14px;
  font-size:.88rem;font-weight:700;max-width:100%;
}
.mpick-chip>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mpick-x{
  border:0;background:transparent;color:inherit;cursor:pointer;
  /* 觸控下限：標籤本身不高，但移除鍵仍要按得到 */
  min-width:28px;min-height:28px;border-radius:50%;font-size:.8rem;line-height:1;
}
.mpick-x:hover{background:var(--orange);color:var(--ink)}

/* 下拉結果：固定高度可捲，滑鼠滾輪與鍵盤都能在裡面移動 */
.mpick-list{
  position:absolute;z-index:30;left:0;right:0;top:100%;margin:6px 0 0;padding:6px;
  list-style:none;max-height:280px;overflow-y:auto;overscroll-behavior:contain;
  background:var(--card-hi);border:1px solid var(--line-strong);
  border-radius:var(--r-sm);box-shadow:var(--sh3);
}
.mpick-opt{
  display:flex;flex-direction:column;gap:2px;
  padding:10px 12px;border-radius:var(--r-sm);cursor:pointer;min-height:var(--tap);
  justify-content:center;
}
.mpick-opt:hover,.mpick-opt.on{background:var(--orange-soft)}
.mpick-name{font-weight:700;color:var(--ink);font-size:.95rem}
/* Email 與電話用小字：它們是用來分辨同名同姓的人，不是主要資訊 */
.mpick-meta{font-size:.78rem;color:var(--ink-3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mpick-none{padding:14px 12px;color:var(--ink-3);font-size:.9rem;text-align:center}
