/* ============================================================================
   styles.css — 索引與編輯須知
   ----------------------------------------------------------------------------
   ⚠️ 這份檔案是「一層層往後疊」長出來的：每次改版都在檔尾新增一個帶日期的
      區塊來覆蓋前面的規則。後果是同一個選擇器常被定義三次以上
      （.topbar、.panel、.view-head h1 …），而且「改了卻沒效果」很常見。

   編輯之前務必做這兩件事：
     1. grep 一次選擇器名，確認它有沒有在後面被再定義一次。
        改到前面那份、被後面蓋掉，是本檔最常見的浪費。
     2. 改完跑 `python3 scripts/cascade-check.py --allow ff8000,548c00`。
        它會模擬特異性＋檔案順序，抓出「疊起來才會錯」的問題：
        對比不足、以及 hover 被同特異性的 .active 蓋掉而失效。

   為什麼不直接合併重複定義：
      合併會改變該選擇器相對於「其他也命中同一元素的同級選擇器」的順序。
      例如 .topbar 若從第 100 行併到第 4000 行，中間那些 .web-shell .topbar
      的勝負關係就變了。要安全合併必須逐屬性分析，風險大於收益，
      因此現階段選擇「標示清楚 + 工具把關」而不是重排。

   區塊索引（行號會隨編輯浮動，以標題為準）：
     檔頭        :root — 色彩與尺度 token（全檔唯一一組，不要另開）
     ~1165       網頁版外框：導覽列在上方
     ~2246       上架要件相關樣式
     ~2396       功能修補樣式
     ~2641       版面修正
     ~2742       商品詳情彈窗修正
     ~2887       聊天室修正
     ~2948       首頁位置列改版
     ~3026       網頁版專屬版面
     ~3422       商品詳情：區塊節奏
     ~3483       篩選側欄：控制項形狀與高度
     ~3561       商品詳情的照片與影片
     ~3719       篩選側欄自己捲
     ~3844       滑鼠移過去的回饋
     ~4669       排版與視覺整理
     ~4879       聊天室標題列的窄螢幕版面
     ~4910       來源商品浮卡
   ============================================================================ */

:root {
  color-scheme: light;

  /* ══════════════════════════════════════════════════════════════
     色彩識別：錨點取自參考 style guide 的三色 + 四階灰，
     其餘各階由同色相推導。規則只有三條：
       400 原色 → 大面積底，字用 --n-900 近黑（藍6.58 綠7.07 珊瑚5.38）
       600/800  → 要放白字的底一律用這兩階（4.5 / 7.0）
       050/100  → 淡底，配同族 800 深字，不得跨色族配
     400 不得承載白字（藍只有 1.26:1）。
     ══════════════════════════════════════════════════════════════ */

  /* 藍 Cyan — 全平台只有兩種藍，而且要一淺一深
       淺 #d3e9ef（明度 .88）：識別。logo、選中狀態、狀態邊框、地圖範圍圈。
                  配 --n-900 近黑字 12.30；不得承載白字（1.26）。
                  2026-09-14 Ann 指定由 #22b6e7 改為灰藍 #87b4c6，同日再改 #b6d0d8、再改 #d3e9ef。
       深 #0d607c（明度 .27）：介面。主要按鈕、連結、藍字。
                  白字 7.04、當字在白底 7.04。
     兩者相互對比 5.59——原本深階是 #1280a5（明度 .36），跟淺階只差 1.91，
     放一起看不出「一淺一深」，所以壓到 #0d607c。
     原本的 050／100／200 淡藍底全部改中性灰（見 --bg-soft／--mint），
     原本的 800 深階退場，其職責併入 --c-600。
     按下／hover 不再用第三個藍，改疊 --press。 */
  --c-400: #d3e9ef;   /* Ann 指定（原參考圖原色 #22b6e7） */
  --c-600: #0d607c;

  /* 疊一層半透明深色來做「按下去更深」，不必為每個色族各養一個深階。
     只影響底色，不影響文字，所以白字按鈕的對比不會被拉低。 */
  --press: linear-gradient(rgba(32, 37, 39, .16), rgba(32, 37, 39, .16));

  /* 青綠 Teal — 贈送／認證／良好 */
  --t-050: #eef9f7;
  /* 以下三階目前介面沒有落點，只留在色盤裡：
     --t-400 #4fc1b0 是參考 style guide 的原色，實際只出現在 App icon；
     100／200 是它的淡階，留著是日後要用時不必重推。
     真正在用的是 --t-600 與 --t-800。 */
  --t-100: #dbf2ef;
  --t-200: #b0e3db;
  --t-400: #4fc1b0;   /* ★ 參考圖原色，未使用 */
  --t-600: #2e8377;
  --t-800: #236259;

  /* 黃橘 Amber — 只給「中風險」。
     風險是三級量表，需要綠／黃／紅三個能一眼分開的色相；
     珊瑚(14°)與青綠已經佔了兩端，中間這一階非有不可。
     只保留亮階：它配近黑字 7.47（AAA），配白字只有 2.07 不得使用。 */
  /* 草綠 #548C00 給「低風險」——Ann 指定的值。
     色相 84°，跟青綠族(172°)是不同色相，所以獨立成一個 token，
     不硬塞進 --t-*。這也順便解掉「低風險跟資深賣家同色」的語意混淆。
     ⚠️ 配白字 4.10:1，略低於 AA 的 4.5（配近黑字更差，只有 3.78）。
     白字是兩者中較好的選擇。 */
  --g-500: #548C00;

  /* 橘 #FF8000 給「中風險」——Ann 指定的值。
     ⚠️ 配白字只有 2.52:1，低於 WCAG AA 的 4.5（配近黑字是 6.15）。
     這是明知的取捨：Ann 兩次都選了亮橘，優先要這個顏色。
     若日後要補回可讀性，把字改 --n-900 即可，不必動底色。 */
  --a-400: #FF8000;

  /* 珊瑚 Coral — 提醒／警示／危險（接手原本的黃／琥珀值） */
  --o-050: #fdeeea;
  --o-100: #fcdbd2;
  --o-200: #f8af9b;
  --o-400: #f2724f;   /* ★ 參考圖原色 */
  --o-600: #db3c10;
  --o-800: #a52d0c;

  /* 灰階 Neutral — ★ 為參考圖原色 */
  --n-900: #202527;
  --n-800: #414a4e;   /* ★ 正文 9.07 */
  /* 次要文字。必須在「白、頁面地、淡卡片底」三種底色上都過 AA：
       #ffffff 5.26 / #f5f6f7 4.86 / #eceeef 4.52
     原本是 #6a7980——只驗了白底的 4.51，但頁面地是 #f5f6f7 不是純白，
     在上面只有 4.17，所有坐在頁面底色上的次要文字都不合格。 */
  --n-600: #616e75;
  /* 白字底能用的最淺灰。再淺一階（#74848b）白字就只有 3.88 不合格，
     所以這是硬上限，不是隨手挑的。--n-600 是給「文字」用的（要更深才夠），
     兩者用途不同故分開。 */
  --n-550: #6a7980;
  /* 這兩階是參考 style guide 的原色，但目前介面沒有落點：
     --n-500 當正文只有 3.88 不合格（所以補了 --n-600），
     --n-400 配白字只有 2.57（先前當「新帳號」底色時已改深）。 */
  --n-500: #74848b;   /* ★ 未使用 */
  --n-400: #a1aaae;   /* ★ 未使用 */
  --n-300: #d3d9dc;   /* ★ */
  --n-200: #eceeef;
  --n-100: #f5f6f7;
  --n-000: #ffffff;

  /* ── 舊 token 一律改成別名，既有 300+ 處引用不用動 ── */
  /* --bg-soft 只給 hover／選中／有語意的藍。
     靜止的卡片、面板、圖片佔位底一律用 --surface-soft，
     兩者混用就會變成「整頁藍底一片、層級看不出來」。 */
  --bg-soft: var(--n-100);
  --surface-soft: var(--n-100);
  --ink: var(--n-800);
  --muted: var(--n-600);
  --line: var(--n-300);
  --panel: var(--n-000);
  --brand: var(--c-600);
  /* 與 --brand 同值：藍只有兩種，「按下去更深」改由 --press 疊色負責，
     不再養第三個藍。留這個別名只是為了不用改既有的 28 處引用。 */
  --brand-strong: var(--brand);
  --mint: var(--n-100);
  --mint-strong: var(--c-400);
  --warn: var(--o-400);
  --danger: var(--o-600);
  --danger-strong: var(--o-800);
  --blue: var(--c-600);
  --page-bg: var(--n-100);

  /* 陰影一律中性，不帶色（見使用規則第 8 條） */
  /* 陰影一律中性。原本是藍偏 rgba(18,128,165,…)，散在 21 個元素上，
     一堆淡藍光暈疊起來整片就泛藍——那是實際存在的第三個藍色調。 */
  --shadow: 0 12px 32px rgba(32, 37, 39, .10);
  --shadow-soft: 0 6px 20px rgba(32, 37, 39, .07);

  /* 圓角尺度：全站統一，走 LINE 那種很圓的親切感 */
  --r-sm: 14px;
  --r-md: 18px;
  --r-pill: 999px;
  --page-title: 32px;
  --h2: 24px;
  --h3: 20px;
  --body: 16px;
  --caption: 14px;
  --tiny: 12px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-width: 320px;
  background: var(--bg-soft);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Noto Sans TC", "Segoe UI", sans-serif;
  font-size: var(--body);
  letter-spacing: 0;
}

button,
input,
select,
textarea {
  font: inherit;
}

button {
  border: 0;
  cursor: pointer;
  touch-action: manipulation;
}

button:disabled {
  cursor: not-allowed;
  opacity: .5;
}

:focus-visible {
  outline: 3px solid rgba(13, 96, 124, .45);
  outline-offset: 2px;
}

.app-shell {
  min-height: 100vh;
  background: var(--bg-soft);
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
  padding: 16px clamp(16px, 3vw, 32px);
  border-bottom: 1px solid var(--line);
  background: rgba(255, 255, 255, .9);
  backdrop-filter: blur(16px);
}

.brand {
  display: flex;
  min-width: 0;
  gap: 8px;
  align-items: center;
  font-weight: 800;
}

.brand-mark {
  display: grid;
  width: 36px;
  height: 36px;
  place-items: center;
  flex: 0 0 auto;
  border-radius: var(--r-sm);
  /* 識別落點：logo 用 400 原色 + 近黑字（12.30:1），
     這是 #d3e9ef 在介面上最主要的露出位置。 */
  background: var(--c-400);
  color: var(--n-900);
  box-shadow: 0 8px 16px rgba(32, 37, 39, .14);
}

/* 左上角的品牌 logo（Ann 2026-09-17 指定統一放這張）。
   原圖四角是白底、中間才是圓角深綠方塊，所以這裡不再自己加圓角或裁切——
   加了反而會把它本來的圓角切掉一圈。放在白色列上白邊看不出來。 */
/* 橫式 logo（方塊＋FaceTrade 字樣），比例約 3.86:1，已去背。
   用固定高度＋width:auto，換圖或微調高度時比例都不會跑掉。 */
.brand-logo {
  display: block;
  height: 30px;
  width: auto;
  flex: 0 0 auto;
}

/* 登入頁的 logo：置中、放大，第一眼就知道這是哪個 App */
.login-logo {
  display: block;
  height: 56px;
  width: auto;
  margin: 0 auto 12px;
}

.brand-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--n-800);
}

.nav {
  display: flex;
  gap: 8px;
  align-items: center;
  overflow-x: auto;
}

.nav button,
.ghost-button,
.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--ink);
}

.nav button {
  min-height: 48px;
  padding: 0 24px;
  white-space: nowrap;
  transition: background-color .16s ease, border-color .16s ease, color .16s ease;
}

.nav button.active {
  border-color: var(--brand);
  background: var(--brand);
  color: #fff;
}

.nav button.install-button {
  border-color: var(--brand);
  background: var(--brand);
  color: #fff;
}

[hidden] {
  display: none !important;
}

.icon-button {
  width: 48px;
  min-height: 48px;
  font-weight: 800;
}

.main {
  width: min(600px, 100%);
  margin: 0 auto;
  padding: 24px clamp(16px, 3vw, 24px) 64px;
}

.login-wrap {
  display: grid;
  min-height: 100vh;
  place-items: center;
  padding: 24px;
  background: var(--bg-soft);
}

.auth-card,
.panel,
.modal-card {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
  box-shadow: var(--shadow);
}

.auth-card {
  width: min(440px, 100%);
  padding: 24px;
}

/* 彈窗標題（.modal-head h2）原本沒被清掉瀏覽器預設的 margin（0.83em ≈ 20px），
   所以「賣家 123A」下面會多出一行空白。它只在別處被設了 font-size，
   邊距一直是預設值。 */
.auth-card h1,
.view-head h1,
.panel h2,
.modal-head h2 {
  margin: 0;
  line-height: 1.15;
}

.view-head h1,
.auth-card h1 {
  font-size: var(--page-title);
}

.panel h2,
.modal-head h2,
.chat-list-copy h2,
.chat-modal-product h2 {
  font-size: var(--h2);
}

h3,
.detail-section h3 {
  font-size: var(--h3);
}

.auth-card p,
.empty,
.muted {
  color: var(--muted);
}

.form-grid {
  display: grid;
  gap: 16px;
}

.field {
  display: grid;
  gap: 8px;
}

.field label {
  font-size: var(--caption);
  font-weight: 700;
  color: var(--c-600);
}

.field input,
.field select,
.field textarea,
.searchbar input,
.searchbar select {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: #ffffff;
  color: var(--ink);
}

.field input,
.field select,
.searchbar input,
.searchbar select {
  min-height: 48px;
  padding: 0 16px;
}

.field input:focus,
.field select:focus,
.field textarea:focus,
.searchbar input:focus,
.searchbar select:focus {
  border-color: var(--brand);
}

.field textarea {
  min-height: 112px;
  padding: 16px;
  resize: vertical;
}

.primary-button,
.danger-button,
.warn-button,
.blue-button,
.ghost-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 0 28px;
  border-radius: var(--r-pill);
  font-weight: 800;
  font-size: var(--body);
  transition: transform .16s ease, background-color .16s ease, border-color .16s ease, color .16s ease, box-shadow .16s ease;
}

.primary-button:active,
.danger-button:active,
.warn-button:active,
.blue-button:active,
.ghost-button:active,
.icon-button:active {
  transform: translateY(1px) scale(.99);
}

.primary-button {
  min-height: 52px;
  background: var(--brand);
  color: #fff;
  box-shadow: 0 8px 18px rgba(32, 37, 39, .16);
}

.primary-button:hover {
  background-image: var(--press);
}

.danger-button {
  min-height: 52px;
  background: var(--danger);
  color: #fff;
}

.warn-button {
  min-height: 52px;
  /* 白字底一律用 600 階：--o-400 配白字只有 2.88:1 */
  background: var(--o-600);
  color: #fff;
}

.blue-button {
  min-height: 52px;
  background: var(--blue);
  color: #fff;
  box-shadow: 0 8px 18px rgba(32, 37, 39, .16);
}

.view-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: end;
  margin-bottom: 24px;
  color: var(--n-800);
}

.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

.home-summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin-bottom: 16px;
}

.summary-card {
  display: grid;
  gap: 4px;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: #fff;
  box-shadow: var(--shadow-soft);
}

.summary-card span {
  color: var(--muted);
  font-size: var(--caption);
  font-weight: 700;
}

.summary-card strong {
  color: var(--ink);
  font-size: var(--h2);
  line-height: 1;
}

.searchbar {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) 160px 140px 150px auto;
  gap: 16px;
  align-items: end;
  margin-bottom: 24px;
  padding: 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: #ffffff;
  box-shadow: var(--shadow-soft);
}

.search-field {
  display: grid;
  gap: 8px;
}

.search-field label {
  color: var(--c-600);
  font-size: var(--caption);
  font-weight: 800;
}

/* ===== 首頁：hero + 搜尋膠囊 + 分類 chips ===== */
.home-hero {
  margin-bottom: 16px;
}

.home-hero h1 {
  margin: 0 0 4px;
  font-size: var(--page-title);
  line-height: 1.1;
}

.home-hero p {
  margin: 0;
  line-height: 1.5;
}

.home-hero strong {
  color: var(--brand);
}

.search-pill {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 52px;
  padding: 0 18px;
  margin-bottom: 14px;
  border-radius: var(--r-pill);
  background: #fff;
  box-shadow: var(--shadow-soft);
}

.search-pill .search-ico {
  flex: 0 0 auto;
  color: var(--muted);
}

.search-pill input {
  flex: 1;
  min-width: 0;
  height: 100%;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-size: var(--body);
}

/* 沒指定的話會用瀏覽器預設 #757575，那個值不在色盤裡 */
.search-pill input::placeholder {
  color: var(--muted);
}

.search-pill input:focus {
  outline: none;
}

.search-clear {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  border-radius: var(--r-pill);
  background: var(--surface-soft);
  color: var(--muted);
  font-size: 13px;
  font-weight: 800;
}

.cat-chips {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
  padding-bottom: 4px;
  overflow-x: auto;
  scrollbar-width: none;
}

.cat-chips::-webkit-scrollbar {
  display: none;
}

.cat-chip {
  flex: 0 0 auto;
  min-height: 40px;
  padding: 0 18px;
  border-radius: var(--r-pill);
  background: #fff;
  color: var(--ink);
  font-weight: 700;
  font-size: var(--caption);
  box-shadow: var(--shadow-soft);
  transition: background-color .16s ease, color .16s ease, transform .12s ease;
}

.cat-chip.active {
  /* 識別落點：選中狀態用 400 原色 + 近黑字。
     語意上「selected」本來就適合亮色，且避開 400 配白字的禁令。 */
  background: var(--c-400);
  color: var(--n-900);
}

.cat-chip:active {
  transform: scale(.96);
}

.area-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 20px;
}

.mini-select {
  flex: 1 1 calc(50% - 5px);
  min-width: 0;
  height: 46px;
  padding: 0 38px 0 14px;
  border: 0;
  border-radius: var(--r-sm);
  color: var(--ink);
  font-size: var(--caption);
  font-weight: 700;
  box-shadow: var(--shadow-soft);
  appearance: none;
  -webkit-appearance: none;
  background: #fff url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='8'%20viewBox='0%200%2012%208'%20fill='none'%20stroke='%236a7980'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M1%201.5%206%206.5%2011%201.5'/%3E%3C/svg%3E") no-repeat right 14px center;
}

.mini-select:disabled {
  color: var(--muted);
  opacity: .7;
}

/* ===== 商品卡片：圖片為主、價格壓在圖上 ===== */
.product-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.product-card {
  overflow: hidden;
  border-radius: var(--r-md);
  background: var(--panel);
  box-shadow: var(--shadow-soft);
  transition: transform .18s ease, box-shadow .18s ease;
}

.product-card:hover,
.product-card:focus-within {
  box-shadow: var(--shadow);
  transform: translateY(-3px);
}

.product-card button,
.product-card > .product-link {
  display: grid;
  width: 100%;
  min-height: 100%;
  padding: 0;
  background: transparent;
  color: inherit;
  text-align: left;
  text-decoration: none;
}
/* 卡片改成 <a>（網站版要能右鍵開新分頁），鍵盤 Tab 到時要看得到在哪一張 */
.product-card > .product-link:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

.product-photo-wrap {
  position: relative;
}

.product-photo {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: var(--n-100);
}

.price-badge {
  position: absolute;
  left: 10px;
  bottom: 10px;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .94);
  color: var(--brand);
  font-size: 15px;
  font-weight: 900;
  box-shadow: 0 4px 12px rgba(32, 37, 39, .16);
  backdrop-filter: blur(4px);
}

.card-risk {
  position: absolute;
  top: 10px;
  left: 10px;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 800;
  color: #fff;
}

/* 風險三級量表：低=青綠、中=黃橘、高=珊瑚紅。
   .card-risk 基底是 color:#fff，所以用亮階當底時必須連字色一起改成近黑。 */
/* 標籤一律白字，所以底色都用能承載白字的深階 */
.card-risk.mild {
  background: var(--g-500);
  color: #fff;
}
.card-risk.warn {
  background: var(--a-400);
  color: #fff;
}

.card-risk.danger {
  background: var(--o-600);
  color: #fff;
}

.product-body {
  display: grid;
  gap: 6px;
  padding: 12px 14px 14px;
}

.product-title {
  display: -webkit-box;
  min-height: 42px;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  font-weight: 700;
  font-size: var(--caption);
  line-height: 1.4;
  color: var(--ink);
}

.card-meta {
  display: flex;
  gap: 8px;
  align-items: center;
  color: var(--muted);
  font-size: var(--tiny);
}

.card-loc {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-dist {
  flex: 0 0 auto;
  margin-left: auto;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--bg-soft);
  color: var(--brand-strong);
  font-weight: 700;
}

.price {
  color: var(--brand);
  font-size: var(--h3);
  font-weight: 900;
}

.meta-row,
.pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

.pill {
  display: inline-flex;
  min-height: 26px;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 0 10px;
  /* 透明邊框：稱號（.badge-tag）有 1px 實邊，標籤沒有。
     不補這條，兩者外框就差 2px，並排時看起來一大一小。 */
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--n-100);
  color: var(--c-600);
  font-size: 12px;
  font-weight: 800;
  line-height: 1;
}

.seller-line {
  color: var(--muted);
  font-size: var(--caption);
  line-height: 1.45;
}

.empty-state {
  display: grid;
  grid-column: 1 / -1;
  justify-items: center;
  gap: 16px;
  padding: 40px 24px;
  border: 1px dashed var(--n-300);
  border-radius: var(--r-md);
  background: #fff;
  color: var(--muted);
  text-align: center;
}

.empty-state h2 {
  margin: 0 0 8px;
  color: var(--ink);
  font-size: var(--h3);
}

.empty-state p {
  max-width: 420px;
  margin: 0;
  line-height: 1.6;
}

.empty-mark {
  display: grid;
  width: 48px;
  height: 48px;
  place-items: center;
  border-radius: var(--r-sm);
  background: var(--n-100);
  color: var(--brand);
  font-weight: 900;
}

.pill.ok {
  background: var(--t-050);
  color: var(--t-800);
}

.pill.warn {
  background: var(--a-400);
  color: #fff;
}

.pill.danger {
  background: var(--o-600);
  color: #fff;
}

.layout-two {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 16px;
}

.panel {
  padding: 24px;
}

.stack {
  display: grid;
  gap: 16px;
}

.media-strip {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 8px;
}

.media-strip img,
.media-strip video {
  width: 100%;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  object-fit: cover;
  background: var(--n-100);
}

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(32, 37, 39, .38);
}

.modal-card {
  width: min(940px, 100%);
  max-height: min(860px, 92vh);
  overflow: auto;
  padding: 24px;
}

.modal-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
  margin-bottom: 16px;
}

.chat-box {
  display: grid;
  grid-template-rows: minmax(260px, 46vh) auto;
  gap: 16px;
}

.chat-list-item {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
}

.chat-list-copy {
  min-width: 0;
}

.chat-list-copy h2 {
  margin: 0 0 8px;
}

.chat-thumb,
.chat-modal-thumb {
  width: 72px;
  aspect-ratio: 1;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  object-fit: cover;
  background: var(--n-100);
}

.chat-modal-product {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  gap: 16px;
  align-items: center;
  min-width: 0;
}

.chat-modal-product h2 {
  margin: 0;
}

.chat-modal-thumb {
  width: 64px;
}

.messages {
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow: auto;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-soft);
}

.message {
  max-width: 76%;
  padding: 10px 16px;
  border-radius: 20px 20px 20px 6px;
  background: #fff;
  border: 1px solid var(--line);
  line-height: 1.45;
}

.message.mine {
  align-self: flex-end;
  border-radius: 20px 20px 6px 20px;
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}

.message small {
  display: block;
  margin-top: 4px;
  color: var(--muted);
}

.message.mine small {
  color: rgba(255, 255, 255, .82);
}

.chat-compose {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
}

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: #fff;
  box-shadow: var(--shadow-soft);
}

table {
  width: 100%;
  border-collapse: collapse;
  min-width: 760px;
  background: var(--panel);
}

th,
td {
  height: 56px;
  padding: 16px;
  border-bottom: 1px solid var(--n-300);
  text-align: left;
  vertical-align: top;
}

th {
  background: var(--surface-soft);
  color: var(--ink);
  font-size: var(--caption);
  letter-spacing: 0;
}

tbody tr:hover {
  background: var(--n-100);
}

tbody tr:last-child td {
  border-bottom: 0;
}

td:first-child {
  color: var(--c-600);
  font-weight: 800;
}

.admin-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}

.notice {
  padding: 16px;
  border: 1px solid var(--n-300);
  border-radius: var(--r-sm);
  background: var(--n-100);
  color: var(--c-600);
}

.file-note {
  color: var(--muted);
  font-size: var(--tiny);
}

/* 隱私提醒。跟 .file-note（純功能說明）刻意分開：這句是要人真的看到並改行為，
   混在灰色小字裡會被跳過。用珊瑚族的淡底＋深字，語意是「提醒」不是「錯誤」。 */
.field-warn {
  margin-top: 6px;
  padding: 8px 10px;
  border-left: 3px solid var(--o-400);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: var(--o-050);
  color: var(--o-800);
  font-size: var(--tiny);
  line-height: 1.65;
}

.req-mark,
.opt-mark {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 8px;
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 800;
  vertical-align: middle;
}

.req-mark {
  background: var(--o-050);
  /* --danger（#db3c10）在這個淡珊瑚底上只有 3.99，低於 AA。
     淡底要配同族的 800 深階（6.24），不是 600。 */
  color: var(--o-800);
}

.opt-mark {
  background: var(--bg-soft);
  color: var(--muted);
}

/* ===== 上傳區塊（取代原生選擇檔案按鈕） ===== */
.file-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* 上面那條會被 `.field input`（width: 100%）蓋掉——它的特異性是 0,1,1，
   而 .file-input 只有 0,1,0。結果這個「應該只有 1px 的隱藏 input」實際是
   滿寬，加上 position: absolute 落在 left: 40px，就把手機版的頁面撐到
   415px（視窗 375px），整頁變成可以橫向捲。
   提高特異性讓隱藏設定確實生效，並補 left: 0 避免它被推到容器外。 */
input.file-input,
.field input.file-input {
  width: 1px;
  height: 1px;
  left: 0;
}

.upload-zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 24px 16px;
  border: 2px dashed var(--mint-strong);
  border-radius: var(--r-md);
  background: var(--surface-soft);
  text-align: center;
  cursor: pointer;
  transition: border-color .16s ease, background-color .16s ease, transform .12s ease;
}

.upload-zone:hover {
  border-color: var(--brand);
  background: var(--n-100);
}

.upload-zone:active {
  transform: scale(.99);
}

/* has-files 與 :hover 特異性相同又寫在後面，會把 hover 整條蓋掉，
   所以已選檔案的狀態要單獨補 hover。 */
.upload-zone.has-files:hover { background: var(--n-200); }
.upload-zone.has-files {
  border-style: solid;
  border-color: var(--brand);
  background: var(--n-100);
}

.upload-zone.is-disabled {
  opacity: .55;
  cursor: not-allowed;
  pointer-events: none;
}

.upload-icon {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: var(--r-pill);
  background: #fff;
  color: var(--brand);
  box-shadow: var(--shadow-soft);
}

.upload-title {
  color: var(--ink);
  font-weight: 800;
  font-size: var(--body);
}

.upload-hint {
  color: var(--muted);
  font-size: var(--tiny);
}

.upload-zone.has-files .upload-hint {
  color: var(--brand-strong);
  font-weight: 700;
}

.settings-section {
  margin-top: 16px;
}

.ghost-link {
  display: inline-flex;
  min-height: 48px;
  align-items: center;
  padding: 0 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--ink);
  font-weight: 800;
  text-decoration: none;
}

/* ============================================================
   網頁版外框：導覽列在「上方」
   原本導覽是左側直欄，但首頁的篩選欄也在左邊，變成兩個直欄並排很怪。
   改成上方橫向導覽 + 左側只留篩選欄。
   ============================================================ */
.web-shell {
  display: block;
}

.web-shell .topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  min-height: auto;
  flex-direction: row;
  align-items: center;
  gap: 28px;
  padding: 0 32px;
  border-right: 0;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}

.web-shell .brand {
  justify-content: flex-start;
  flex: 0 0 auto;
}

.web-shell .nav {
  display: flex;
  flex-direction: row;
  align-items: center;
  /* 整排靠右：品牌留在最左，分頁與登出都推到右邊 */
  justify-content: flex-end;
  gap: 4px;
  flex: 1;
  overflow: visible;
}

/* 上方導覽：圖示 + 文字橫排的小分頁 */
.web-shell .nav button[data-route] {
  position: relative;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: auto;
  min-height: 58px;
  padding: 0 16px;
  border-radius: 0;
  /* 可點的字一律 --ink。選中態已經有「藍字＋底線」兩個訊號，
     未選不需要再降成 --muted——那會讓它跟不可點的標籤同色。 */
  color: var(--ink);
  transition: color .14s ease, box-shadow .14s ease;
}

.web-shell .nav button[data-route] .nav-ico {
  width: 20px;
  height: 20px;
}

.web-shell .nav button[data-route] .nav-label {
  font-size: var(--caption);
  font-weight: 700;
  line-height: 1.2;
}

.web-shell .nav button[data-route]:hover { color: var(--brand-strong); }

/* 目前所在的分頁用底線標示，不用整塊底色（橫向導覽比較適合） */
.web-shell .nav button[data-route].active {
  background: transparent;
  color: var(--brand-strong);
  box-shadow: inset 0 -3px 0 var(--brand);
}

.web-shell .nav button[data-route].active .nav-label {
  font-weight: 800;
}

/* 未讀徽章改貼在圖示右上角 */
.web-shell .nav .nav-badge {
  top: 12px;
  right: auto;
  left: 26px;
}

/* 安裝與登出推到最右邊 */
.web-shell .nav button[data-action="install-app"] { margin-left: 12px; }
.web-shell .nav button[data-action="logout"] {
  margin-left: 12px;
  min-height: 38px;
  padding: 0 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  font-size: var(--caption);
  font-weight: 700;
  /* 可點的字一律 --ink；hover 才轉珊瑚（登出是離開性動作） */
  color: var(--ink);
}
.web-shell .nav button[data-action="logout"]:hover {
  background: var(--bg-soft);
  color: var(--danger);
  border-color: var(--danger);
}

.web-shell .main {
  width: min(1280px, 100%);
  padding: 32px clamp(24px, 4vw, 48px) 64px;
}

/* 網站版：商品格自動排滿多欄（像 FB Marketplace，一排約 4~5 個）*/
.web-shell .product-grid {
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 16px;
}

.product-detail-modal {
  width: min(1040px, 100%);
  padding: 0;
  overflow: hidden;
}

.product-detail-modal .modal-head {
  margin: 0;
  padding: 24px;
  border-bottom: 1px solid var(--line);
}

.detail-kicker {
  display: block;
  margin-bottom: 4px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
}

.product-detail-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(340px, .92fr);
  gap: 0;
}

.product-detail-media {
  padding: 24px;
  background: var(--surface-soft);
}

.detail-media-strip {
  grid-template-columns: 1fr;
}

.detail-media-strip img,
.detail-media-strip video {
  aspect-ratio: 4 / 3;
  border: 0;
  box-shadow: var(--shadow-soft);
}

.product-detail-info {
  display: grid;
  align-content: start;
  gap: 16px;
  padding: 24px;
}

.detail-summary {
  display: grid;
  gap: 16px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}

.detail-price {
  color: var(--brand);
  font-size: clamp(30px, 4vw, 42px);
  font-weight: 950;
  line-height: 1;
}

.detail-location {
  display: grid;
  gap: 4px;
  color: var(--muted);
}

.detail-location strong {
  color: var(--ink);
  font-size: var(--body);
}

.detail-map-link {
  width: fit-content;
}

.detail-section {
  display: grid;
  gap: 8px;
}

.detail-section h3 {
  margin: 0;
  font-size: var(--h3);
}

.detail-section p {
  margin: 0;
  color: var(--n-800);
  line-height: 1.7;
}

.detail-seller-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

.detail-status-row {
  padding-bottom: 64px;
}

.detail-action-bar {
  position: sticky;
  right: 0;
  bottom: 0;
  left: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 16px;
  align-items: center;
  padding: 16px 24px max(16px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: rgba(255, 255, 255, .94);
  backdrop-filter: blur(16px);
}

.detail-chat-button {
  min-height: 48px;
  font-size: 16px;
}

.plain-report-button {
  min-height: 48px;
  padding: 0 8px;
  background: transparent;
  color: var(--muted);
  font-weight: 800;
}

.map-panel {
  gap: 16px;
}

.map-place-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.map-frame {
  width: 100%;
  min-height: 520px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-soft);
}

.map-stage {
  position: relative;
  min-height: 560px;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-soft);
}

.map-stage .map-frame {
  display: block;
  height: 560px;
  min-height: 560px;
  border: 0;
  border-radius: 0;
}

.map-product-overlay {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  gap: 16px;
  overflow-x: auto;
  padding: 48px 16px 16px;
  background: rgba(255, 255, 255, .96);
  scroll-snap-type: x mandatory;
}

.map-product-card,
.map-empty-card {
  flex: 0 0 min(320px, 82vw);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: #fff;
  box-shadow: var(--shadow-soft);
  scroll-snap-align: start;
}

.map-product-card button {
  display: grid;
  width: 100%;
  grid-template-columns: 86px minmax(0, 1fr);
  gap: 16px;
  padding: 16px;
  border: 0;
  background: transparent;
  color: inherit;
  text-align: left;
}

.map-product-thumb {
  width: 86px;
  aspect-ratio: 1;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--n-100);
  object-fit: cover;
}

.map-product-copy {
  display: grid;
  min-width: 0;
  gap: 4px;
  align-content: center;
}

.map-product-copy strong {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.map-product-copy .price {
  font-size: 16px;
}

.map-product-meta {
  display: flex;
  min-width: 0;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  color: var(--muted);
  font-size: var(--caption);
}

.map-empty-card {
  padding: 16px;
  color: var(--muted);
  font-weight: 700;
}

@media (max-width: 768px) {
  .web-shell {
    display: block;
  }

  .topbar,
  .view-head,
  .layout-two,
  .product-detail-layout,
  .home-summary,
  .searchbar {
    grid-template-columns: 1fr;
  }

  .topbar,
  .web-shell .topbar {
    position: sticky;
    display: grid;
    min-height: auto;
    grid-template-columns: 1fr;
    padding: 16px;
    border-right: 0;
    border-bottom: 1px solid var(--line);
    /* 手機上刻意關掉毛玻璃（吃效能），但背景就不能再留半透明，
       否則往下捲的時候後面的內容會直接透出來變成髒髒一片。 */
    backdrop-filter: none;
    background: var(--panel);
  }

  .brand {
    justify-content: flex-start;
  }

  .nav,
  .web-shell .nav {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 40;
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 4px;
    padding: 8px 8px max(8px, env(safe-area-inset-bottom));
    border-top: 1px solid var(--line);
    background: rgba(255, 255, 255, .97);
    box-shadow: 0 -4px 16px rgba(32, 37, 39, .06);
    backdrop-filter: blur(16px);
    overflow: visible;
  }

  .nav.admin-nav {
    grid-template-columns: minmax(0, 1fr);
  }

  .nav.user-nav {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  .nav button,
  .web-shell .nav button {
    min-width: 0;
    min-height: 48px;
    padding: 0 4px;
    border-color: transparent;
    background: transparent;
    font-size: var(--caption);
    line-height: 1.1;
    white-space: normal;
    text-align: center;
    justify-content: center;
  }

  .nav button.active {
    border-color: transparent;
    background: var(--brand);
  }

  .nav button[data-action="logout"],
  .nav button.install-button {
    display: none;
  }

  .main,
  .web-shell .main {
    padding-top: 16px;
    padding-bottom: calc(92px + env(safe-area-inset-bottom));
  }

  .view-head {
    align-items: start;
    gap: 12px;
    margin-bottom: 16px;
  }

  /* .home-hero h1 也要一起。少了它，這個寬度以下就會變成
     首頁 32px、聊天／發布／我的 28px，四個分頁的標題不一樣重。 */
  .view-head h1,
  .home-hero h1,
  .auth-card h1 {
    font-size: 28px;
  }

  .home-summary {
    gap: 8px;
  }

  .summary-card {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    padding: 16px;
  }

  .searchbar {
    gap: 12px;
    padding: 16px;
  }

  .searchbar .ghost-button {
    width: 100%;
  }

  .product-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
  }

  .product-card:hover,
  .product-card:focus-within {
    transform: none;
  }

  .product-body {
    gap: 6px;
    padding: 12px;
  }

  .product-title {
    min-height: 40px;
    font-size: var(--caption);
    line-height: 1.3;
  }

  .price {
    font-size: var(--body);
  }

  .product-body .pill {
    font-size: 11px;
  }

  .seller-line {
    font-size: var(--tiny);
  }

  .empty-state {
    padding: 32px 16px;
  }

  .product-detail-modal {
    width: 100%;
    max-height: 94vh;
    border-radius: 16px 16px 0 0;
  }

  .product-detail-modal .modal-head {
    padding: 16px;
  }

  .product-detail-media,
  .product-detail-info {
    padding: 16px;
  }

  .detail-price {
    font-size: var(--page-title);
  }

  .detail-action-bar {
    grid-template-columns: minmax(0, 1fr) auto;
    padding: 16px max(16px, env(safe-area-inset-bottom));
  }

  .detail-action-bar .primary-button {
    grid-column: 1 / -1;
  }

  .plain-report-button {
    min-width: 64px;
  }

  .chat-compose {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .chat-list-item {
    grid-template-columns: 64px minmax(0, 1fr);
  }

  .chat-list-item .blue-button {
    grid-column: 1 / -1;
    width: 100%;
  }

  .map-stage {
    min-height: 500px;
  }

  .map-stage .map-frame {
    height: 500px;
    min-height: 500px;
  }

  .map-product-overlay {
    padding: 40px 12px 12px;
  }

}

/* ===== 互動地圖（Leaflet）===== */
.map-view {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 12px;
}

.map-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  position: relative;
  z-index: 30;
  /* 原本鋪一塊白底，但沒有內距也沒有圓角，文字貼著左邊緣看起來像被切掉，
     而且跟下面「找面交點」那排的淺藍底不一致。拿掉，跟其他頁面統一。 */
  background: transparent;
}

.map-count {
  font-weight: 700;
  color: var(--n-800);
  font-size: 16px;
}

.map-count strong {
  color: var(--brand);
}

.map-jump {
  display: flex;
  gap: 8px;
}

.map-jump select {
  height: 44px;
  border-radius: var(--r-sm);
  border: 1px solid var(--n-300);
  padding: 0 14px;
  background: #fff;
  font-size: 15px;
  color: var(--n-800);
}

.map-stage-live {
  position: relative;
}

.leaflet-stage {
  position: relative;
  height: 68vh;
  min-height: 420px;
  max-height: 700px;
  border-radius: var(--r-md);
  overflow: hidden;
  z-index: 1;
  background: var(--n-200);
}

/* 價格泡泡標記（像 591） */
.map-pin-wrap {
  width: 0;
  height: 0;
}

.map-pin {
  position: absolute;
  left: 0;
  top: 0;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  background: var(--brand);
  color: #fff;
  font-weight: 700;
  font-size: 13px;
  line-height: 1;
  padding: 6px 11px;
  border-radius: 999px;
  border: 2px solid #fff;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.28);
  cursor: pointer;
}

/* 群聚圓圈 */
.map-cluster-wrap {
  background: transparent;
}

.map-cluster {
  width: 46px;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--brand);
  color: #fff;
  font-weight: 700;
  font-size: 15px;
  border-radius: 50%;
  border: 3px solid #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

/* 底部浮動商品卡片 */
.map-card-slot {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 14px;
  z-index: 1000;
}

.map-float-card {
  position: relative;
  background: #fff;
  border-radius: var(--r-md);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.18);
  padding: 12px 14px;
}

.map-card-open {
  display: flex;
  gap: 12px;
  width: 100%;
  align-items: center;
  text-align: left;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}

.map-float-thumb {
  width: 62px;
  height: 62px;
  border-radius: var(--r-sm);
  object-fit: cover;
  flex: 0 0 auto;
}

.map-float-copy {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.map-float-copy strong {
  font-size: 16px;
  color: var(--n-800);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.map-float-copy .price {
  color: var(--brand);
  font-weight: 800;
  font-size: 18px;
}

.map-float-tags {
  display: flex;
  gap: 6px;
  align-items: center;
}

.map-float-meta {
  font-size: 12px;
  color: var(--n-600);
}

.map-card-close {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: none;
  background: var(--n-200);
  color: var(--n-600);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  z-index: 2;
}

.map-hint {
  font-size: 13px;
}

/* ===== 免費贈送：發布勾選 + 卡片標籤 ===== */
.field-label-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
}

.field-label-row .gift-check {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px 5px 8px;
  border-radius: var(--r-pill);
  background: var(--bg-soft);
  color: var(--brand-strong);
  font-size: var(--caption);
  font-weight: 800;
  cursor: pointer;
}

.field-label-row .gift-check input {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--brand);
  cursor: pointer;
}

.price-badge.is-gift,
.detail-price.is-gift {
  color: var(--t-600);
}

/* ===== 底部導覽列：圖示 + 文字 ===== */
.nav button[data-route] {
  flex-direction: column;
  gap: 3px;
  padding: 6px 16px;
  border-color: transparent;
  background: transparent;
  color: var(--muted);
}

.nav button[data-route] .nav-ico {
  flex: 0 0 auto;
}

.nav button[data-route] .nav-label {
  font-size: var(--tiny);
  font-weight: 700;
  line-height: 1;
}

.nav button[data-route].active {
  background: transparent;
  color: var(--brand);
}

.nav button[data-route].active .nav-ico {
  stroke-width: 2.3;
}

/* ===== 商品卡片：賣家細節 ===== */
.card-seller {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: var(--tiny);
  min-width: 0;
}

.card-seller .risk-tag {
  flex: 0 0 auto;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  color: #fff;
  font-size: 10px;
  font-weight: 800;
}

.card-seller .risk-tag.warn {
  background: var(--a-400);
  color: #fff;
}

.card-seller .risk-tag.danger {
  background: var(--o-600);
  color: #fff;
}

.card-seller-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}


@media (max-width: 768px) {
  .nav button[data-route] {
    padding: 4px 2px;
  }
}

/* ===== 收藏 / 商品狀況 / 賣家檔案 / 封鎖名單（v13 新增功能）===== */
.product-card { position: relative; }

/* 卡片左上角愛心（.product-card .fav-btn 特異性 0,2,0 蓋過 .product-card button 0,1,1）*/
.product-card .fav-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 34px;
  height: 34px;
  min-height: 0;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  color: var(--danger);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 3px 10px rgba(32, 37, 39, .18);
  backdrop-filter: blur(4px);
  z-index: 2;
  transition: transform .12s ease;
}
.product-card .fav-btn:hover { transform: scale(1.1); }
.product-card .fav-btn.is-fav { color: #fff; background: var(--danger); }

/* 商品狀況 小標 */
.card-tags { margin: 2px 0 6px; }
.cond-tag {
  display: inline-block;
  padding: 2px 9px;
  border-radius: var(--r-pill);
  background: var(--bg-soft);
  color: var(--brand-strong);
  font-size: var(--tiny);
  font-weight: 800;
}
.pill.cond-pill { background: var(--bg-soft); color: var(--brand-strong); }

/* 首頁「只看收藏」toggle（與 mini-select 併成 2×2）*/
.fav-toggle {
  flex: 1 1 calc(50% - 5px);
  min-width: 0;
  padding: 0 14px;
  height: 46px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel);
  color: var(--ink);
  font-size: var(--caption);
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}
.fav-toggle.active { background: var(--danger); border-color: var(--danger); color: #fff; }

/* 商品詳情動作列的收藏鈕（文字版）*/
.fav-btn.detail-fav {
  position: static;
  width: auto;
  height: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--r-pill);
  padding: 0 16px;
  min-height: 44px;
  font-size: var(--caption);
  font-weight: 800;
  line-height: 1;
  cursor: pointer;
  background: var(--bg-soft);
  color: var(--danger);
  box-shadow: none;
}
.fav-btn.detail-fav.is-fav { background: var(--danger); color: #fff; }

/* 賣家操作列 */
.seller-actions {
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}

/* 賣家檔案 modal 內的商品格 */
.seller-grid { margin-top: 14px; }

/* 封鎖名單 */
.blocked-list { display: flex; flex-direction: column; gap: 8px; }
.blocked-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}

/* ===== 「我的」頁：我在賣的清單 ===== */
.listing-list { display: flex; flex-direction: column; gap: 8px; }
.listing-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: #fff;
  text-align: left;
  cursor: pointer;
  transition: background .14s ease;
}
.listing-row:hover { background: var(--bg-soft); }
.listing-thumb {
  width: 52px;
  height: 52px;
  border-radius: 10px;
  object-fit: cover;
  flex: 0 0 auto;
  background: var(--n-100);
}
.listing-info { flex: 1; min-width: 0; }
.listing-name {
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.listing-sub { margin-top: 2px; font-size: var(--caption); color: var(--muted); }
.listing-row .pill { flex: 0 0 auto; }
.pill.sold-pill { background: var(--surface-soft); color: var(--muted); }
.listing-row.is-sold { opacity: .72; }
.listing-row.is-sold .listing-thumb { filter: grayscale(.4); }

/* ============================================================
   上架要件相關樣式（2026-08-25 新增）
   ── 定位列、刪除帳號、面交安全守則
   ============================================================ */

/* ---------- 首頁：定位與中心點 ---------- */
.locate-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
}
.locate-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 46px;
  padding: 0 18px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--brand);
  color: #fff;
  font-size: var(--caption);
  font-weight: 800;
  box-shadow: var(--shadow-soft);
  cursor: pointer;
  transition: background-color .16s ease, transform .16s ease;
}
.locate-button:hover { background-image: var(--press); }
.locate-button:active { transform: translateY(1px) scale(.99); }
.locate-button:disabled { cursor: default; opacity: .75; }
.locate-button.is-busy { background: var(--mint-strong); color: var(--n-900); }
.pin-ico { flex: none; }
.locate-or {
  color: var(--muted);
  font-size: var(--tiny);
  font-weight: 700;
}
/* 這兩顆選單擠在定位鈕旁邊，不要吃掉整行 */
.locate-row .mini-select {
  flex: 1 1 auto;
  min-width: 92px;
  max-width: 150px;
  height: 46px;
}

/* ---------- 我的：刪除帳號區塊 ---------- */
.danger-zone .toolbar { margin-top: 4px; }

/* ---------- 刪除帳號確認 ---------- */
.danger-modal { width: min(560px, 100%); }
.danger-kicker { color: var(--danger); }
.danger-lead {
  margin: 4px 0 16px;
  font-size: var(--body);
  line-height: 1.7;
}
.danger-list {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
  border-top: 1px solid var(--line);
}
.danger-list li {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 11px 2px;
  border-bottom: 1px solid var(--line);
  font-size: var(--caption);
}
.danger-list-label { font-weight: 800; }
.danger-list-num {
  margin-left: auto;
  color: var(--danger);
  font-size: var(--h3);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.danger-list-unit { color: var(--muted); font-size: var(--tiny); }
.danger-note {
  margin: 0 0 18px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  background: var(--surface-soft);
  color: var(--muted);
  font-size: var(--tiny);
  line-height: 1.7;
}
#deleteAccountSubmit:disabled {
  opacity: .45;
  cursor: not-allowed;
}

/* ---------- 面交安全守則 ---------- */
.safety-modal { width: min(560px, 100%); }
.safety-list {
  list-style: none;
  counter-reset: safety;
  margin: 8px 0 18px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.safety-list li {
  counter-increment: safety;
  position: relative;
  padding-left: 40px;
}
.safety-list li::before {
  content: counter(safety);
  position: absolute;
  left: 0;
  top: 1px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--mint);
  color: var(--brand-strong);
  font-size: var(--tiny);
  font-weight: 800;
}
.safety-title {
  display: block;
  font-size: var(--body);
  font-weight: 800;
  line-height: 1.6;
}
.safety-body {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--caption);
  line-height: 1.7;
}
.safety-foot {
  margin: 0 0 18px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  background: var(--surface-soft);
  color: var(--muted);
  font-size: var(--tiny);
  line-height: 1.7;
}

/* ============================================================
   功能修補樣式（2026-08-25）
   ── 未讀訊息、商品管理、照片放大、信用等級
   ============================================================ */

/* ---------- 信用等級新增的兩種 ---------- */
.pill.good  { background: var(--t-600); color: #fff; }
.pill.fresh { background: var(--n-550); color: #fff; }
.card-seller .risk-tag.good  { background: var(--t-600); }
.card-seller .risk-tag.fresh { background: var(--n-550); }

/* ---------- 導覽列未讀數 ---------- */
.nav .nav-badge {
  position: absolute;
  top: 2px;
  right: calc(50% - 20px);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
/* 徽章要相對於按鈕定位，按鈕本身得是定位脈絡 */
.nav button { position: relative; }

/* ---------- 聊天列表：未讀 ---------- */
.panel.has-unread { border-color: var(--mint-strong); }
.chat-thumb-wrap { position: relative; flex: 0 0 auto; }
.unread-dot {
  position: absolute;
  top: -5px;
  right: -5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border: 2px solid #fff;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
}
.chat-preview {
  margin: 2px 0 0;
  overflow: hidden;
  color: var(--muted);
  font-size: var(--caption);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chat-preview.is-unread { color: var(--ink); font-weight: 700; }
.chat-sub { margin: 2px 0 0; font-size: var(--tiny); }

/* ---------- 我在賣的：每列的操作 ---------- */
/* 整列原本是一顆 button，為了塞編輯／刪除改成 div，樣式要跟著搬 */
.listing-row { flex-direction: column; align-items: stretch; gap: 6px; cursor: default; }
.listing-row:hover { background: #fff; }
.listing-open {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 4px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  text-align: left;
  cursor: pointer;
  transition: background .14s ease;
}
.listing-open:hover { background: var(--bg-soft); }
.listing-actions {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
  padding: 0 4px 2px;
}
.tiny-button {
  min-height: 34px;
  padding: 0 14px;
  font-size: var(--tiny);
  font-weight: 800;
}
.danger-text { color: var(--danger); }

/* ---------- 「我的」頁清單分頁 ‹ 1 2 3 › ---------- */
.pager {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 6px;
  margin-top: 12px;
}
.pager-btn {
  display: inline-grid;
  place-items: center;
  min-width: 36px;
  height: 36px;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--n-000);
  color: var(--ink);
  font: inherit;
  font-size: var(--caption);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.pager-btn:hover:not(:disabled) { border-color: var(--c-600); }
.pager-btn.is-current { border-color: var(--c-600); background: var(--c-600); color: var(--n-000); }
.pager-btn:disabled { opacity: .35; cursor: default; }
.pager-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.pager-gap { min-width: 20px; color: var(--muted); text-align: center; }

/* ---------- 我的收藏（App 版一行一件）---------- */
.listing-row.fav-row { flex-direction: row; align-items: center; gap: 4px; }
.fav-row .listing-open { flex: 1 1 auto; min-width: 0; }
.fav-row-seller { display: flex; align-items: center; gap: 6px; }
.fav-row-seller .pill { min-height: 20px; padding: 0 8px; font-size: 11px; }
.fav-row-heart {
  display: grid;
  flex: none;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--danger);
  cursor: pointer;
}
.fav-row-heart:hover { background: var(--o-050); }
.fav-row-heart svg { width: 20px; height: 20px; }

/* ---------- 最近買到的（App 版）----------
   原本 .listing-row.is-purchase 強制橫排，按鈕把名稱擠成「I…」（Ann）。
   App 版改回上下排：商品資訊一行、評價／異議按鈕在下一行靠右。 */
.mobile-shell .listing-row.is-purchase { flex-direction: column; align-items: stretch; }

/* ---------- 我送出的檢舉：手機卡片（Ann：排版怪）----------
   1. td 是 space-between 的 flex，「類型」裡的文字＋「1 小時以上」標籤變成兩個 flex 項目，
      被平均分散、文字跑到正中間 → 內容包成 .cell-value 一組，靠右、彼此緊貼。
   2. 表格原本「最後一列不畫底線」，卡片化後最後一張卡整張沒有分隔線，跟前面的卡不一致
      → 每張卡每行都畫線，只有卡內最後一行不畫。 */
@media (max-width: 768px) {
  .table-wrap td { align-items: center; }
  .table-wrap td > .cell-value,
  .table-wrap td > .cell-actions {
    display: inline-flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    gap: 6px;
    min-width: 0;
  }
  .table-wrap tr:last-child td { border-bottom: 1px solid var(--line); }
  .table-wrap tr td:last-child { border-bottom: 0; }
}

/* ---------- 編輯商品：現有媒體預覽 ---------- */
.existing-strip {
  display: flex;
  gap: 6px;
  margin-top: 8px;
  overflow-x: auto;
  padding-bottom: 4px;
}
.existing-strip img {
  width: 56px;
  height: 56px;
  flex: 0 0 auto;
  border-radius: 10px;
  object-fit: cover;
  background: var(--n-100);
}

/* ---------- 商品照片：可點放大 ---------- */
.photo-thumb-btn {
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  line-height: 0;
}
.photo-thumb-btn img { display: block; }

/* ---------- 照片放大檢視 ---------- */
.photo-backdrop { background: rgba(32, 37, 39, .92); }
.photo-viewer {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 1100px;
  height: 100%;
  max-height: 88vh;
}
.photo-full {
  max-width: 100%;
  max-height: 100%;
  border-radius: var(--r-sm);
  object-fit: contain;
}
.photo-close {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  background: rgba(255, 255, 255, .92);
}
.photo-nav {
  position: absolute;
  top: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-top: -22px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  color: var(--ink);
  cursor: pointer;
}
.photo-nav.prev { left: 6px; }
.photo-nav.next { right: 6px; }
.photo-nav:hover { background: #fff; }
.photo-count {
  position: absolute;
  bottom: 10px;
  left: 50%;
  transform: translateX(-50%);
  padding: 4px 12px;
  border-radius: 999px;
  background: rgba(32, 37, 39, .7);
  color: #fff;
  font-size: var(--tiny);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ── 登入兩步驟流程（OTP_DESIGN.md 4.1）───────────────────────── */
.auth-sent {
  margin: 0;
  font-size: var(--tiny);
  color: var(--muted);
}

.auth-error {
  margin: 0 0 16px;
  padding: 10px 12px;
  border: 1px solid var(--danger);
  border-radius: var(--r-sm);
  background: rgba(219, 60, 16, 0.08);
  color: var(--danger);
  font-size: var(--tiny);
  line-height: 1.5;
}

/* 反釣魚提示。刻意放在表單下方、用警示色，但不做成 alert——它要一直在，不是跳一次。 */
.auth-warning {
  margin: 20px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: var(--tiny);
  line-height: 1.6;
}

.auth-warning strong { color: var(--warn); }

/* 登入頁的同意告知（個資法 8 條要在「蒐集當下」告知，所以放在送出鈕正下方）。
   刻意做小、不搶焦點：它是必要的法律揭露，不是要嚇退使用者。 */
.auth-consent {
  margin: 10px 0 0;
  font-size: var(--tiny);
  line-height: 1.6;
  color: var(--muted);
  text-align: center;
}
.auth-consent a { color: var(--brand-strong); }

.auth-dev-hint {
  margin: 0;
  font-size: var(--tiny);
  color: var(--muted);
  opacity: 0.75;
}

.auth-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  justify-content: space-between;
}

/* 文字按鈕。用 :where() 把特異性歸零，避免被其他 button 規則蓋掉（全站規範）。 */
:where(.link-button) {
  padding: 0;
  border: 0;
  min-height: 0;
  background: none;
  color: var(--brand);
  font-size: var(--tiny);
  font-family: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}

:where(.link-button:disabled) {
  color: var(--muted);
  cursor: default;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   版面修正（2026-08-31）
   ── 面交地點標籤、我在賣的每列、手機版表格
   ============================================================ */

/* 面交地點從商品卡的地區那行搬過來，跟成色標籤並排，
   地區才不會被截成「信義區 · 咖...」 */
.card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.place-tag {
  display: inline-block;
  padding: 2px 9px;
  border-radius: var(--r-pill);
  background: var(--mint);
  color: var(--brand-strong);
  font-size: var(--tiny);
  font-weight: 800;
}

/* 「我在賣的」每一列：副標原本會折成兩行，撞到右邊的「上架中」標籤。
   改成單行加省略號——但這樣會踩到一個陷阱：.listing-list 是 .panel（grid）
   的項目，grid 項目預設 min-width:auto，會被「最小內容寬」撐開。副標一旦
   不能換行，最小內容寬就變成整串文字的寬度，整列就衝出面板外面去。
   所以要同時把 min-width 歸零，才允許它縮回來。 */
.listing-list { min-width: 0; }
.listing-open { align-items: center; }
/* 狀態跟按鈕排在一起，並拿掉底色——它是說明不是動作，
   長得像可點的標籤反而會讓人想去點它 */
.listing-status {
  background: transparent;
  color: var(--muted);
  padding: 0 4px;
}
.listing-status.sold-pill { background: transparent; color: var(--muted); }
.listing-sub {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 768px) {
  /* 6 欄的表格在 375px 寬的手機上一定看不完（原本要橫向捲，
     「被檢舉人」直接跑出畫面外）。改成一筆一張卡片，欄名用
     data-label 顯示在左邊。 */
  .table-wrap {
    overflow-x: visible;
    border: 0;
    background: transparent;
    box-shadow: none;
  }
  .table-wrap table,
  .table-wrap tbody,
  .table-wrap tr,
  .table-wrap td {
    display: block;
    width: 100%;
    /* 表格本體設了 min-width: 760px，不解掉的話還是會撐爆 375px 的畫面 */
    min-width: 0;
  }
  .table-wrap thead { display: none; }
  .table-wrap tr {
    margin-bottom: 10px;
    padding: 4px 14px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: #fff;
    box-shadow: var(--shadow-soft);
  }
  .table-wrap tr:last-child { margin-bottom: 0; }
  .table-wrap th,
  .table-wrap td { height: auto; }
  .table-wrap td {
    display: flex;
    gap: 12px;
    align-items: baseline;
    justify-content: space-between;
    padding: 9px 0;
    border-bottom: 1px solid var(--line);
    text-align: right;
  }
  .table-wrap tr td:last-child { border-bottom: 0; }
  .table-wrap td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    color: var(--muted);
    font-size: var(--tiny);
    font-weight: 800;
    text-align: left;
  }
  /* 「尚無檢舉紀錄」這種佔滿整列的訊息不要套上面的兩欄排版 */
  .table-wrap td[colspan] {
    display: block;
    text-align: center;
    color: var(--muted);
  }
  .table-wrap td[colspan]::before { content: none; }
}

/* ============================================================
   商品詳情彈窗修正（2026-08-31）
   ============================================================ */

/* 標籤原本是 .detail-summary（grid）的直接子項，每個都被拉成整行寬。
   包一層讓它們並排。 */
/* .detail-summary 是 grid，直接放進去的標籤會各佔一列（變成上下排）。
   包一層 flex 讓它們並排，窄的時候再自動換行。 */
.detail-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

@media (max-width: 768px) {
  /* 嚴重問題：.product-detail-modal 寫死 overflow:hidden。桌面版是左右兩欄
     放得下，手機版堆疊成一欄後內容有 1200px 以上，被裁掉又捲不動——
     「商品描述」和「賣家」兩整段在手機上完全看不到。
     改成：標題列固定、中間內容可捲、底部動作列固定。 */
  .product-detail-modal {
    display: flex;
    flex-direction: column;
  }
  .product-detail-modal .modal-head,
  .product-detail-modal .detail-action-bar {
    flex: 0 0 auto;
  }
  .product-detail-layout {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  /* 已經固定在 flex 底部，不需要再 sticky */
  .product-detail-modal .detail-action-bar { position: static; }
}

@media (max-width: 768px) {
  /* 底部動作列原本三欄，實際排出來是「收藏＋聊天」一行、「檢舉」自己
     佔一整行置中，很奇怪也很佔高度。改成：收藏＋聊天約面交同一行，
     檢舉縮到第二行靠右當次要動作。 */
  .detail-action-bar {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 10px;
    padding: 12px 16px max(12px, env(safe-area-inset-bottom));
  }
  .detail-action-bar .detail-fav { grid-column: 1; }
  .detail-action-bar .detail-chat-button { grid-column: 2; }
  .detail-action-bar .primary-button { grid-column: 1 / -1; }
  .detail-action-bar .plain-report-button {
    grid-column: 1 / -1;
    justify-self: end;
    min-height: 36px;
    padding: 0 12px;
    font-size: var(--caption);
  }

  /* 賣家那兩顆按鈕各佔一整行太浪費高度，並排就好 */
  .seller-actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }
  .seller-actions .ghost-button {
    min-height: 44px;
    padding: 0 12px;
    font-size: var(--caption);
  }
}

/* 安全守則／刪除確認這類短彈窗，當初沿用了商品詳情的 .detail-action-bar，
   但那個是 position:sticky（給長內容用的）。在這裡會變成按鈕浮在半空中、
   下面還露出一截內容，而且黏底時卡在彈窗的 24px 內距上方，很醜。
   這幾個彈窗內容不長，按鈕就放在結尾即可。 */
.safety-modal .detail-action-bar,
.danger-modal .detail-action-bar {
  position: static;
  padding: 0;
  border-top: 0;
  background: transparent;
  backdrop-filter: none;
}

@media (max-width: 768px) {
  /* 手機上把主要按鈕拉寬比較好按 */
  .safety-modal .detail-action-bar { display: block; }
  .safety-modal .detail-action-bar .blue-button { width: 100%; }
  .danger-modal .detail-action-bar {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }
  .danger-modal .detail-action-bar .ghost-button,
  .danger-modal .detail-action-bar .danger-button {
    width: 100%;
    padding: 0 12px;
    font-size: var(--caption);
  }
}

@media (max-width: 768px) {
  /* 「名稱／數字／單位」三欄擠在一行，名稱會被折成「你刊登的商 / 品」，
     而且單位長短不一時數字位置會忽左忽右。改成兩行：
     第一行「名稱 ——— 數字」，第二行放單位說明。 */
  .danger-list li {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 2px 10px;
  }
  .danger-list-label { grid-column: 1; }
  .danger-list-num { grid-column: 2; margin-left: 0; }
  .danger-list-unit {
    grid-column: 1 / -1;
    line-height: 1.6;
  }
}

/* 聊天列表：整列可點（原本右邊掛一顆「查看」按鈕，手機上會被擠到
   第二行佔掉一整行高度）。改成整列是一顆按鈕，右邊放箭頭當提示。 */
.chat-panel { padding: 0; overflow: hidden; }

/* ===== 手機版聊天滿版（Ann 2026-09-14）=====
   列表：拿掉兩側留白與卡片的框線／圓角／陰影，改成貼齊螢幕的通欄列表，列與列之間一條分隔線。
   對話：原本是四周留半透明邊的彈窗，改成整個螢幕，訊息區吃掉剩下的高度。
   網站版是左右兩欄（LINE 電腦版樣式）不受影響。彈窗畫在 .app-shell 外面，
   吃不到 .mobile-shell，所以手機版由 renderChatModal 加 .chat-fullscreen 來分辨。 */
.mobile-shell .main-chats { padding-inline: 0; }
.mobile-shell .main-chats .view-head { padding-inline: 16px; }
.mobile-shell .main-chats .chat-notice { margin-inline: 16px; }
.mobile-shell .main-chats .stack { gap: 0; }
.mobile-shell .main-chats .chat-panel { border-radius: 0; border-inline: 0; box-shadow: none; }
.mobile-shell .main-chats .chat-panel + .chat-panel { border-top: 0; }
/* 底部導覽列要露出來（Ann）：讓出導覽列的高度＝上內距 8＋按鈕 50＋底部安全區（至少 8），
   跟 .nav 的 padding: 8px 8px max(8px, env(safe-area-inset-bottom)) 同一套算法，iPhone 有 Home 條也對得上 */
.chat-fullscreen { padding: 0; place-items: stretch; bottom: calc(58px + max(8px, env(safe-area-inset-bottom))); }
.chat-fullscreen .chat-modal-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  max-height: none;
  padding: 16px;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.chat-fullscreen .chat-box { flex: 1 1 auto; min-height: 0; grid-template-rows: minmax(0, 1fr) auto; }
.chat-fullscreen .messages { min-height: 0; overflow-y: auto; }

/* ===== 通知頁 =====
   一則一列：左圓形圖示、中間標題＋說明、右邊時間。
   這次打開之前沒看過的：外框用深藍、時間前掛「新」，一眼分得出哪些是新的。 */
.notification-list { gap: 10px; }
.notification-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: start;
  width: 100%;
  padding: 14px 16px;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background .14s ease;
}
.notification-item:hover { background: var(--bg-soft); }
.notification-item:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.notification-item.is-new { border-color: var(--c-600); }
.notification-icon {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: var(--r-pill);
  background: var(--n-100);
  color: var(--c-600);
}
.notification-copy { display: grid; gap: 2px; min-width: 0; }
.notification-copy strong { color: var(--ink); font-size: var(--caption); font-weight: 700; }
.notification-body { color: var(--muted); font-size: var(--caption); overflow-wrap: anywhere; }
.notification-time { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: var(--tiny); white-space: nowrap; }
.notification-new {
  padding: 0 6px;
  border-radius: var(--r-pill);
  background: var(--c-600);
  color: var(--n-000);
  font-weight: 800;
}
.chat-panel .chat-list-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  width: 100%;
  padding: 14px 16px;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
  transition: background .14s ease;
}
.chat-panel .chat-list-item:hover { background: var(--bg-soft); }
.chat-go {
  display: inline-flex;
  color: var(--muted);
  flex: 0 0 auto;
}
.chat-list-copy h2 {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ============================================================
   聊天室修正（2026-08-31）
   ============================================================ */

/* 輸入框沒有左右內距，文字直接貼著邊框（全站規範：輸入框要有內距） */
.chat-compose input {
  min-height: 48px;
  padding: 0 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: #fff;
  font-size: var(--body);
  color: var(--ink);
}
.chat-compose input::placeholder { color: var(--muted); }
.chat-compose .primary-button {
  min-height: 48px;
  padding: 0 20px;
}

/* 「檢舉對方」是少用的次要動作，原本用橘色大按鈕，視覺權重跟「送出」一樣重。
   縮成低調的文字鈕。 */
.chat-report-row {
  display: flex;
  justify-content: flex-end;
  margin-top: 10px;
}
.chat-report-row .warn-button {
  min-height: 34px;
  padding: 0 14px;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: var(--tiny);
  font-weight: 700;
}
.chat-report-row .warn-button:hover {
  border-color: var(--warn);
  color: var(--warn);
}

/* 訊息時間每則都印完整日期太吵，縮小並降低對比 */
.message small {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  opacity: .7;
}

@media (max-width: 768px) {
  /* 標題列：縮圖 + 標題 + 關閉鈕擠在一起，標題會折成兩行 */
  .chat-modal-thumb { width: 44px; height: 44px; }
  .chat-modal-product h2 {
    font-size: var(--h3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .chat-box { grid-template-rows: minmax(200px, 52vh) auto; }
}

/* ============================================================
   首頁位置列改版（2026-08-31）
   原本有兩組縣市／鄉鎮區選單：一組決定距離的中心點、一組做篩選。
   功能不同但長得一樣，使用者分不出來，而且要滑過 500px 才看得到商品。
   現在只留一組，並且直接嵌在句子裡（「以 ○○ ○○ 為中心」），
   篩選那組改成距離範圍——對面交來說「離我幾公里」比「哪個行政區」有用。
   ============================================================ */

.here-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 6px 0 4px;
  color: var(--muted);
  font-size: var(--caption);
}

/* 兩個選單要看起來像句子裡的一個詞，不是一般的表單控制項 */
.here-picks {
  display: inline-flex;
  gap: 4px;
}
.inline-select {
  height: 36px;
  padding: 0 30px 0 12px;
  border: 0;
  border-radius: var(--r-pill);
  /* 下拉「值」是內容不是選中狀態，與側欄的 .mini-select 一致用 --ink。
     原本是 --brand-strong 藍字 w800，同一種元件在兩處不同色。 */
  color: var(--ink);
  font-size: var(--caption);
  font-weight: 700;
  box-shadow: var(--shadow-soft);
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  background: #fff url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='8'%20viewBox='0%200%2012%208'%20fill='none'%20stroke='%23414a4e'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M1%201.5%206%206.5%2011%201.5'/%3E%3C/svg%3E") no-repeat right 11px center;
}
.inline-select:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* 定位縮成一顆小圖示鈕，跟在句子後面 */
.locate-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 36px;
  padding: 0 12px;
  /* 原本是淡藍底。藍色收成兩種後 --mint 改中性，值剛好等於頁面地
     （#f5f6f7），膠囊就變隱形了。改成跟旁邊縣市／區下拉同款的
     白底＋灰邊框，深藍字在白底 4.51 過 AA。 */
  border: 1px solid var(--n-300);
  border-radius: var(--r-pill);
  background: var(--n-000);
  color: var(--brand-strong);
  font-size: var(--tiny);
  font-weight: 800;
  cursor: pointer;
  transition: background .16s ease;
}
.locate-chip:hover { background: var(--n-100); border-color: var(--c-600); }
.locate-chip:disabled { opacity: .7; cursor: default; }
.locate-chip .pin-ico { flex: none; }

.count-line { margin: 0; font-size: var(--caption); }

/* 篩選那行剩三個控制項，平均分配 */
.area-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.area-row .mini-select { flex: 1 1 0; min-width: 110px; max-width: 260px; }
.area-row .fav-toggle { flex: 0 0 auto; }

/* ============================================================
   網頁版專屬版面（2026-08-31）
   目標：不要只是「手機版拉寬」，而是真正用到桌面的空間。
   .main 原本被限制在 600px，網頁版整片內容因此被綁在中間一條。
   ============================================================ */

.web-shell .main {
  width: 100%;
  max-width: 1440px;
  margin: 0 auto;
  padding: 28px 32px 64px;
}

/* 左側固定篩選欄 + 右側商品格 */
.home-web-layout {
  display: grid;
  grid-template-columns: 268px minmax(0, 1fr);
  gap: 28px;
  align-items: start;
}

.filter-rail {
  position: sticky;
  top: 28px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
  box-shadow: var(--shadow-soft);
}
.rail-group { display: flex; flex-direction: column; gap: 8px; }
.rail-title {
  margin: 0;
  color: var(--muted);
  font-size: var(--tiny);
  font-weight: 800;
  letter-spacing: .04em;
}
/* 分類在側欄改成直排清單，比橫向滑動好用 */
.rail-chips {
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow: visible;
  padding: 0;
  margin: 0;
}
.rail-chips .cat-chip {
  width: 100%;
  justify-content: flex-start;
  text-align: left;
  padding: 0 12px;
  min-height: 38px;
}
.filter-rail .mini-select { width: 100%; max-width: none; }
.filter-rail .search-pill { margin: 0; }
.rail-clear { min-height: 40px; font-size: var(--caption); }

/* 商品格：手機兩欄，桌面依寬度自動排到 4～5 欄 */
.web-shell .product-grid {
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 18px;
}

/* 網頁版的首頁抬頭可以更大方一點 */
.web-shell .home-hero { margin-bottom: 20px; }
/* 字級交給共用的 .view-head h1／--page-title 管，這裡不再另外指定 */

/* 篩選欄在窄一點的筆電上就不要固定寬度了 */
@media (max-width: 1080px) {
  .home-web-layout { grid-template-columns: 228px minmax(0, 1fr); gap: 20px; }
}

/* ---------- 網頁版：商品詳情改成右側抽屜 ---------- */
/* 手機版是蓋滿全螢幕的彈窗；桌面版沒必要遮住整片列表。
   底板只佔右半邊，左邊的商品格仍可點選，能連續看好幾件。 */
.detail-backdrop.is-web-drawer {
  left: auto;
  width: min(560px, 46vw);
  padding: 0;
  background: transparent;
  place-items: stretch;
  box-shadow: -18px 0 48px rgba(32, 37, 39, .16);
}
.detail-backdrop.is-web-drawer .product-detail-modal {
  width: 100%;
  max-width: none;
  max-height: 100vh;
  height: 100vh;
  border-radius: 0;
  border-right: 0;
  border-top: 0;
  border-bottom: 0;
  display: flex;
  flex-direction: column;
}
.detail-backdrop.is-web-drawer .modal-head,
.detail-backdrop.is-web-drawer .detail-action-bar { flex: 0 0 auto; }
.detail-backdrop.is-web-drawer .product-detail-layout {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* 抽屜寬度不夠放兩欄，改成單欄由上往下 */
  grid-template-columns: minmax(0, 1fr);
}
.detail-backdrop.is-web-drawer .detail-action-bar { position: static; }

/* ---------- 網頁版：聊天左右兩欄 ---------- */
/* 手機版是「列表 → 點開彈窗」；桌面版沒必要遮住列表，
   左邊對話列表、右邊對話內容，可以直接切換不同對話。 */
.chat-web-layout {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 20px;
  align-items: stretch;
  height: calc(100vh - 190px);
  min-height: 460px;
}

.chat-web-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
  padding-right: 4px;
}
.chat-web-list .panel { flex: 0 0 auto; }

.chat-web-thread {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 20px 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
  box-shadow: var(--shadow-soft);
}
/* 對話區要吃掉剩餘高度，訊息才會在自己的區塊裡捲動 */
.chat-web-thread .chat-box {
  flex: 1 1 auto;
  min-height: 0;
  grid-template-rows: minmax(0, 1fr) auto;
}
.chat-web-thread .messages { min-height: 0; }
.chat-web-thread .modal-head { flex: 0 0 auto; }
.chat-web-thread .chat-report-row { flex: 0 0 auto; }

.chat-web-empty {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
}
.chat-web-empty h2 { margin: 0; font-size: var(--h3); }
.chat-web-empty p { margin: 0; }

/* 被選到的那則對話要標示出來 */
.chat-web-list .panel.is-open {
  border-color: var(--brand);
  box-shadow: 0 0 0 2px var(--mint);
}

/* 網頁版的頁面寬度要分兩種：
   ── 首頁／聊天／地圖：本來就是多欄或兩欄版面，用滿寬度才對
   ── 發布／我的：是由上而下閱讀與填寫的內容，拉到 1200px 只會變得
      稀疏難讀（按鈕被推到天邊），收窄成一欄比較好看也好操作 */
.web-shell .main-post,
.web-shell .main-profile {
  max-width: 860px;
}

/* ---------- 價格區間與「只看免費贈送」 ---------- */
.price-range {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 100%;
  min-width: 0;
}
.price-input {
  flex: 1 1 0;
  min-width: 0;
  height: 46px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--ink);
  font-size: var(--caption);
  font-weight: 700;
  box-shadow: var(--shadow-soft);
}
.price-input::placeholder { color: var(--muted); font-weight: 500; }
/* 數字輸入框右邊那對小箭頭在這裡只會擠壓空間 */
.price-input::-webkit-outer-spin-button,
.price-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.price-input { -moz-appearance: textfield; }
.price-dash { flex: 0 0 auto; color: var(--muted); font-weight: 700; }

.gift-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 46px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--ink);
  font-size: var(--caption);
  font-weight: 700;
  box-shadow: var(--shadow-soft);
  cursor: pointer;
  transition: background .14s ease, color .14s ease;
}
.gift-toggle:hover { background: var(--bg-soft); }
/* 啟用狀態一定要單獨寫 hover。.gift-toggle.active 就在下一行、特異性相同，
   會蓋掉上面那條 :hover——結果是啟用時滑過去完全沒反應（隔壁的
   .fav-toggle 有寫 .active:hover 所以會變色，兩顆行為不一致）。 */
.gift-toggle.active:hover { background: var(--t-800); }
.gift-toggle.active {
  /* 贈送＝青綠。原本用 --warn（琥珀），在新色系裡珊瑚代表「要小心」，
     用在贈送篩選會傳達反過來的意思。 */
  background: var(--t-600);
  color: #fff;
}

/* 側欄裡的價格欄與贈送鈕都佔滿整欄 */
.filter-rail .price-range { flex: 1 1 auto; }
.filter-rail .gift-toggle { width: 100%; }

/* ---------- 清單／地圖切換 ---------- */
/* 「逛逛」與「地圖」本來是兩個分頁，但它們是同一份篩選結果的兩種呈現，
   所以合併成一頁，用這組切換鈕換呈現方式。 */
.hero-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.hero-top h1 { margin: 0; }

.view-switch {
  position: relative;
  display: inline-flex;
  padding: 3px;
  border-radius: var(--r-pill);
  background: var(--surface-soft);
  box-shadow: inset 0 0 0 1px var(--line);
}
/* 白色滑塊。原本是「選中的那顆自己有白底」，切換時是瞬間跳過去；
   改成一塊獨立的滑塊在兩顆之間滑動，才看得出是同一個東西移動。
   用 :has() 判斷選中的是第幾顆，不必動 JS。 */
.view-switch::before {
  content: "";
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  width: calc(50% - 3px);
  border-radius: var(--r-pill);
  background: var(--n-000);
  box-shadow: var(--shadow-soft);
  transition: transform .26s cubic-bezier(.4, 0, .2, 1);
}
.view-switch:has(.view-switch-btn:last-of-type.active)::before {
  transform: translateX(100%);
}
/* 兩顆等寬，滑塊的 50% 才會剛好對齊 */
.view-switch-btn { flex: 1 1 0; justify-content: center; }
/* 文字要浮在滑塊上面 */
.view-switch-btn { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  .view-switch::before { transition: none; }
}
.view-switch-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 36px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink);
  font-size: var(--caption);
  font-weight: 700;
  cursor: pointer;
  transition: background .16s ease, color .16s ease;
}
/* 未選中滑過去給回饋（原本 hover 設的顏色跟未選一樣，等於沒反應） */
.view-switch-btn:hover { color: var(--brand-strong); }
.view-switch-btn.active {
  /* 白底與陰影都交給 .view-switch::before 那塊滑塊，這裡只管文字 */
  background: transparent;
  color: var(--brand-strong);
  box-shadow: none;
}
.view-switch-btn svg { flex: none; }

/* 地圖檢視時內容要吃滿高度，不要跟著篩選欄縮 */
.home-web-layout .map-view { margin-top: 0; }

/* 「低風險」：成立檢舉滿 3 次但交易量大。用比「需注意」更淡的琥珀色，
   讀起來是「同一類但強度較低」，而不是另一種東西。 */
.pill.mild { background: var(--g-500); color: #fff; }
.card-seller .risk-tag.mild { background: var(--g-500); color: #fff; }

/* ---------- 帳號狀態（管理員處置＋自動推算，合併成一個）---------- */
/* 已停權／受限中是管理員的人為處置，用實心底色跟自動推算的風險等級區隔，
   一眼看得出「這是人判的」而不是「系統算的」。 */
.pill.suspended { background: var(--o-800); color: #fff; }
.pill.restricted { background: var(--o-600); color: #fff; }
.card-seller .risk-tag.suspended { background: var(--o-800); }
.card-seller .risk-tag.restricted { background: var(--o-600); }

/* 後台表格裡狀態下方的補充說明 */
.status-note {
  display: block;
  margin-top: 3px;
  color: var(--muted);
  font-size: var(--tiny);
  line-height: 1.5;
}

/* ---------- 後台：狀態分級對照表 ---------- */
.status-legend {
  margin-bottom: 16px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
}
.status-legend summary {
  cursor: pointer;
  font-weight: 800;
  color: var(--brand-strong);
  font-size: var(--caption);
}
.status-legend > p { margin: 10px 0; font-size: var(--tiny); line-height: 1.7; }
.legend-foot { margin-bottom: 0; }
.legend-wrap { box-shadow: none; }
.legend-table { min-width: 0; }
.legend-table th,
.legend-table td {
  height: auto;
  padding: 8px 10px;
  font-size: var(--tiny);
  text-align: center;
  white-space: nowrap;
}
.legend-table thead th { color: var(--muted); font-weight: 700; }
.legend-table th[scope="row"] {
  text-align: left;
  color: var(--muted);
  font-weight: 700;
}

/* 「專業賣家」是最高一級，用實心深綠跟「資深賣家」拉開差距 */
.pill.pro { background: var(--t-800); color: #fff; }
.card-seller .risk-tag.pro { background: var(--t-800); }

/* 商品卡上的面交地點。買家掃視時最想知道「約在哪」，
   所以直接寫出詳細地點，而不是只給「超商」這種類型。
   地點可能很長，限制兩行、超出以省略號收尾。 */
.card-meet {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--line);
  color: var(--ink);
  font-size: var(--tiny);
  line-height: 1.6;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.card-meet-label { color: var(--muted); }

/* 商品詳情的面交地點：跟商品卡用同一個講法 */
.detail-location-label {
  color: var(--muted);
  font-size: var(--tiny);
  font-weight: 700;
}

/* ============================================================
   商品詳情：簡約清楚的區塊節奏（2026-08-31）
   原本所有內容用同一種視覺重量堆在一起，區塊之間沒有分界，
   還混了幾個對買家沒意義的標籤。改成統一的「小標 + 內容」，
   用細線分隔，每一區的間距一致。
   ============================================================ */

.detail-block {
  padding: 20px 0;
  border-top: 1px solid var(--line);
}
.detail-block:first-child { border-top: 0; padding-top: 4px; }
.detail-block:last-child { padding-bottom: 4px; }

/* 每一區的小標：低調、不搶戲，只負責告訴你這一區是什麼 */
.detail-label {
  margin: 0 0 8px;
  color: var(--muted);
  font-size: var(--tiny);
  font-weight: 800;
  letter-spacing: .06em;
}

/* 價格是這一頁的主角，其他都往後退 */
.detail-head { display: flex; flex-direction: column; gap: 12px; }
.detail-price { line-height: 1.1; }

/* 面交地點：地址是重點，行政區是補充 */
.detail-place {
  margin: 0;
  font-size: var(--h3);
  font-weight: 800;
  line-height: 1.5;
}
.detail-place-sub {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: var(--caption);
}
.detail-map-link { margin-top: 12px; }

.detail-desc {
  margin: 0;
  color: var(--n-800);
  line-height: 1.8;
}

/* 賣家：帳號與狀態同一行，數據當補充說明而不是又一顆標籤 */
.seller-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.seller-name { font-size: var(--body); font-weight: 700; }
.seller-stat {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: var(--caption);
}

/* ============================================================
   篩選側欄：統一所有控制項的形狀與高度（2026-08-31）
   原本下拉是圓角方框、按鈕是膠囊形，高度也不一樣（46 / 52），
   擠在一起就顯得凌亂，框也顯得窄。
   ============================================================ */

/* 側欄裡的每一個控制項：同高、同圓角、同寬 */
.filter-rail .mini-select,
.filter-rail .price-input,
.filter-rail .gift-toggle,
.filter-rail .fav-toggle,
.filter-rail .rail-clear,
.filter-rail .search-pill {
  width: 100%;
  min-height: 44px;
  height: 44px;
  border-radius: var(--r-sm);
  font-size: var(--caption);
  box-sizing: border-box;
}

/* 按鈕不要用膠囊形，跟下拉對齊 */
.filter-rail .gift-toggle,
.filter-rail .fav-toggle,
.filter-rail .rail-clear {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 0 12px;
  border: 1px solid var(--line);
  background: var(--panel);
  box-shadow: none;
  font-weight: 700;
}
.filter-rail .gift-toggle.active {
  border-color: var(--t-600);
  background: var(--t-600);
  color: #fff;
}
.filter-rail .fav-toggle.active {
  border-color: var(--danger);
  background: var(--danger);
  color: #fff;
}

/* 下拉與輸入框改成一致的描邊，不要用陰影撐出深淺不一的感覺 */
.filter-rail .mini-select,
.filter-rail .price-input {
  border: 1px solid var(--line);
  box-shadow: none;
}

/* 價格那兩格：側欄變寬後有空間了，中間的破折號縮小佔位 */
.filter-rail .price-range { gap: 6px; }
.filter-rail .price-dash { flex: 0 0 auto; font-size: var(--caption); }

/* 區塊之間的節奏：有小標的群組靠緊，獨立按鈕之間留多一點 */
.filter-rail { gap: 16px; }
.filter-rail .rail-group { gap: 6px; }
.filter-rail .rail-clear { margin-top: 4px; }

/* ---------- 首頁抬頭：三行擠在一起 ---------- */
/* 標題、位置列、件數三行原本只靠 4~6px 的邊距分開，而位置列裡還有
   36px 高的下拉選單，看起來就很擠。改用一致的 flex 間距。 */
.home-hero {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 20px;
}
.home-hero h1 { margin: 0; }
.home-hero .here-line { margin: 0; }
.home-hero .count-line { margin: 0; }
/* 件數已移進 .here-line、排在「定位」右邊，所以要跟該行其他項目垂直置中，
   而不是像原本自成一段那樣靠上。 */
.here-line .count-line {
  flex: 0 0 auto;
  margin: 0;
  white-space: nowrap;
}
.hero-top { margin-bottom: 2px; }

.web-shell .home-hero { gap: 12px; margin-bottom: 24px; }

/* ============================================================
   商品詳情的照片與影片：大圖 + 縮圖列
   原本是每個媒體都用全尺寸往下疊，五個媒體就要滑近 2000px
   才看得到商品資訊。
   ============================================================ */

.media-main {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface-soft);
}
.media-photo-btn {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}
.media-main img,
.media-main .media-video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.media-main .media-video {
  object-fit: contain;
  background: var(--n-900);
}

.media-thumbs {
  display: flex;
  gap: 8px;
  margin-top: 10px;
  overflow-x: auto;
  padding-bottom: 4px;
}
.media-thumb {
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--surface-soft);
  cursor: pointer;
  transition: border-color .14s ease;
}
.media-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.media-thumb.active { border-color: var(--brand); }
.media-thumb:hover { border-color: var(--mint-strong); }

/* 影片的縮圖沒有畫面可用，放一個播放記號 */
.media-thumb-video {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: var(--n-900);
  color: #fff;
}

/* ---------- 大圖區的左右箭頭與計數 ---------- */
.media-nav {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin-top: -20px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  color: var(--ink);
  box-shadow: 0 2px 10px rgba(32, 37, 39, .18);
  cursor: pointer;
  transition: background .14s ease, transform .14s ease;
}
.media-nav:hover { background: #fff; }
.media-nav:active { transform: scale(.94); }
.media-nav.prev { left: 10px; }
.media-nav.next { right: 10px; }

.media-count {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 2;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: rgba(32, 37, 39, .68);
  color: #fff;
  font-size: var(--tiny);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* 影片本身有播放控制列在下緣，計數往上讓開免得疊在一起 */
.media-main:has(.media-video) .media-count { bottom: 46px; }

/* 報警資訊獨立一行並加重——緊急時要能一眼看到，不能混在責任聲明裡 */
.safety-emergency {
  margin: 0 0 18px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  background: var(--o-050);
  color: var(--o-800);
  font-size: var(--caption);
  font-weight: 700;
  line-height: 1.7;
}
.safety-emergency strong { font-size: var(--body); }

/* 中分類：比大分類低一階，用比較小、比較淡的樣子表示「更細一層」 */
.sub-chips { margin-top: 6px; }
.sub-chip {
  min-height: 32px;
  padding: 0 12px;
  font-size: var(--tiny);
  font-weight: 700;
  background: var(--surface-soft);
  color: var(--muted);
}
.sub-chip.active {
  background: var(--mint);
  color: var(--brand-strong);
}
.filter-rail .sub-chips .sub-chip { justify-content: flex-start; }

/* 巢狀的中分類：縮排 + 左側細線，一眼看出是隸屬上面那個大分類 */
.sub-chips.nested {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 4px 0 6px 10px;
  padding-left: 10px;
  border-left: 2px solid var(--mint);
}
.sub-chips.nested .sub-chip {
  width: 100%;
  justify-content: flex-start;
  text-align: left;
}

/* ============================================================
   篩選側欄要能自己捲（2026-08-31）
   sticky 只是把側欄釘住，並不會讓它能獨立捲動。側欄比螢幕高的時候，
   使用者只能靠捲整頁去看它的下半部——而那會把右邊的商品一起捲掉。
   改成自己的捲動容器：黏在頂列下方，最高不超過剩下的視窗高度。
   ============================================================ */
.filter-rail {
  /* 58px 是網頁版頂列的高度，再留 20px 空隙 */
  top: 79px;
  /* 高度＝貼住之後可用的空間（100vh − 頂列 79px − 底部留 20px）。
     原本用「還沒捲動時的位置」保守算成 100vh − 260px，結果貼住之後底下空出一大塊，
     內容卻擠在小框裡捲（Ann 回報「側欄下方還有空位」）。
     還沒捲時側欄底部會超出畫面，但整頁一定捲得動（側欄本身就撐高了頁面），
     捲一點就貼住、整條露出來，側欄內也仍可捲。 */
  max-height: max(360px, calc(100vh - 99px));
  overflow-y: auto;
  overscroll-behavior: contain;   /* 側欄捲到底時不要把整頁一起帶著捲 */
  scrollbar-width: thin;
}

/* 分類清單本身自己捲。這才是側欄變高的主因（10 個大分類還可能展開細分類），
   讓它自己捲，下面的距離／價格／幾成新就永遠看得到，不用先捲側欄。 */
.filter-rail .rail-chips {
  max-height: 216px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  padding-right: 4px;
}
/* 側欄自己的捲軸低調一點，不要跟內容搶注意力 */
.filter-rail::-webkit-scrollbar { width: 8px; }
.filter-rail::-webkit-scrollbar-thumb {
  border: 2px solid var(--panel);
  border-radius: 999px;
  background: var(--line);
}
.filter-rail::-webkit-scrollbar-thumb:hover { background: var(--muted); }

/* ---------- 完成交易：選買家 ---------- */
.buyer-list {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.buyer-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  width: 100%;
  min-height: 52px;
  padding: 10px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel);
  cursor: pointer;
  transition: border-color .14s ease, background .14s ease;
}
.buyer-row:hover { border-color: var(--brand); background: var(--bg-soft); }
.buyer-name { font-weight: 700; }

/* 完成交易彈窗的另外兩個出口：都不算成交，但意義不同 */
.close-options {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  margin-bottom: 16px;
}
/* 上下兩排是不同層級的動作，中間拉開一點，
   不然看起來像同一組三選一 */
.danger-modal .close-options + .detail-action-bar {
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.close-options .ghost-button {
  min-height: 46px;
  padding: 0 12px;
  font-size: var(--caption);
}

/* 「已完成交易」是上架中商品的主要動作，比旁邊的編輯／刪除搶眼一點 */
.done-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--brand);
  color: #fff;
  font-weight: 800;
  cursor: pointer;
  transition: background .14s ease;
}
.done-button:hover { background-image: var(--press); }

/* 聊天室標題列右側：檢舉對方 + 關閉 */
.chat-head-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}
.chat-report {
  min-height: 34px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--muted);
  font-size: var(--tiny);
  font-weight: 700;
  white-space: nowrap;
}
.chat-report:hover {
  border-color: var(--danger);
  color: var(--danger);
  background: var(--o-050);
}
/* 檢舉是動作不是標籤。原本它跟風險等級、稱號排在同一列（.chat-modal-meta），
   長得就像另一個標籤；移到右側 .chat-head-actions 跟「完成交易」「關閉」
   同一區，動作與標籤才分得開。 */
.chat-head-actions .chat-report { flex: 0 0 auto; }

/* ============================================================
   滑鼠移過去的回饋（2026-09-01）
   幾個主要的按鈕類別原本完全沒有 hover，游標移上去毫無反應，
   使用者會不確定那到底能不能點。
   原則：實心鈕加深、外框鈕上底色，都很輕微，不要跳來跳去。
   ============================================================ */

/* 實心鈕：稍微加深 */
.danger-button:hover { background: var(--danger-strong); }
.warn-button:hover { background: var(--o-800); }
.blue-button:hover {
  background-image: var(--press);
  box-shadow: 0 10px 22px rgba(32, 37, 39, .20);
}

/* 外框／淺色鈕：上一層淡底色 */
.ghost-button:hover { background: var(--bg-soft); }
.ghost-button.danger-text:hover {
  background: var(--o-050);
  color: var(--danger);
}
.icon-button:hover { background: var(--bg-soft); border-color: var(--muted); }
.cat-chip:hover { background: var(--bg-soft); }
.cat-chip.active:hover { background: var(--c-600); color: #fff; }
.sub-chip:hover { background: var(--mint); color: var(--brand-strong); }
.fav-toggle:hover { background: var(--bg-soft); color: var(--ink); }
/* 必須連 color 一起寫。.fav-toggle.active 的白字跟 .fav-toggle:hover 的
   深灰字特異性相同（都 0,2,0），檔案位置晚的 :hover 會贏，
   只改 background 的話就是深紅底＋深灰字（1.29:1）。 */
.fav-toggle.active:hover { background: var(--danger-strong); color: #fff; }
.mini-select:hover, .inline-select:hover { background-color: var(--bg-soft); }
.price-input:hover { background: var(--bg-soft); }
.search-clear:hover { color: var(--ink); }
.tiny-button:hover { background: var(--bg-soft); }
.media-photo-btn:hover img { opacity: .92; }

/* 鍵盤操作也要看得出焦點在哪（不只滑鼠） */
button:focus-visible,
select:focus-visible,
input:focus-visible,
a:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* 系統設定「減少動態效果」時就不要做位移動畫 */
@media (prefers-reduced-motion: reduce) {
  * { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* 聊天列表：同一件商品可能有好幾個人來問，標題全都一樣，
   真正能分辨的是「跟誰」——所以帳號要看得見。 */
.chat-who {
  color: var(--brand-strong);
  font-size: var(--caption);
  font-weight: 800;
}

/* 更正買家時標出目前記錄的那一位 */
.buyer-row.is-current { border-color: var(--brand); background: var(--bg-soft); }
/* is-current 與 .buyer-row:hover 同為 --bg-soft，滑過去看不出反應 */
.buyer-row.is-current:hover { background: var(--n-200); }
.buyer-right { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 7px; justify-content: flex-end; }

/* 「這是你買的嗎？」確認彈窗 */
.confirm-modal { max-width: 380px; }
.confirm-lead { margin: 0 0 14px; line-height: 1.6; color: var(--muted); }
.confirm-product {
  display: flex; align-items: center; gap: 12px;
  padding: 12px; margin-bottom: 18px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--surface-soft);
}
/* 一定要用 > 只吃直接子層。用後代選擇器（.confirm-product img）的話，
   稱號裡的小圖示也會被套成 56px——那條特異性 0,1,1 贏過 .badge-tag-img
   的 0,1,0，於是「守護者」的盾牌變成 56px 把整塊版面推歪。 */
.confirm-product > img { width: 56px; height: 56px; border-radius: 10px; object-fit: cover; flex: none; }
.confirm-product > div { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
/* 狀態標籤與稱號排成一行、可換行，不要被 .muted 的行內流擠在一起 */
.confirm-product .muted {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.confirm-product strong { font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.confirm-actions { display: grid; gap: 10px; }
.confirm-actions button { width: 100%; }
.confirm-later { width: 100%; margin-top: 10px; border: none; color: var(--muted); font-size: 13px; }

/* 最近買到的：只有一顆按鈕，跟商品並排在右邊比較好讀，
   不必像「我在賣的」那樣（那邊按鈕多，換行才排得下） */
.listing-row.is-purchase { flex-direction: row; align-items: center; }
.listing-row.is-purchase .listing-open { flex: 1 1 auto; min-width: 0; }
.listing-row.is-purchase .listing-actions { flex: 0 0 auto; padding: 0; }

/* 聊天頁的法律提醒 */
.chat-notice { margin-bottom: 14px; }
.chat-notice-head { display: block; margin-bottom: 8px; }
.chat-notice p { margin: 0 0 6px; font-size: 13px; line-height: 1.7; }
.chat-notice p:last-child { margin-bottom: 0; }

/* 檢舉鈕跟「與 XXX 約定面交」同一行、切齊右邊，
   不要垂直置中在整個標題區塊（那樣看起來會浮在中間） */
.chat-modal-product { align-items: start; }
.chat-modal-copy { min-width: 0; }
.chat-modal-meta {
  display: flex;
  align-items: center;
  justify-content: flex-start;   /* 緊鄰那句話，不要推到最右邊 */
  gap: 10px;
  margin-top: 4px;
}
.chat-modal-meta p { margin: 0; min-width: 0; }

/* 疑似要求先匯款的警告。顏色刻意用警示紅，跟一般 .notice 分開，
   放在訊息底下常駐——關掉彈窗不代表那句話消失了 */
.bank-warning {
  margin: 8px 0 12px;
  padding: 12px 14px;
  border: 1px solid var(--o-200);
  border-radius: var(--r-sm);
  background: var(--o-050);
  color: var(--o-800);
}
.bank-warning-head { display: block; margin-bottom: 6px; font-size: 13px; }
.bank-warning p { margin: 0 0 4px; font-size: 13px; line-height: 1.7; }
.bank-warning p:last-child { margin-bottom: 0; }
.message.is-risky { box-shadow: 0 0 0 2px var(--o-200); }
.bank-modal { max-width: 400px; }
.bank-modal .bank-warning { margin-top: 4px; }
.bank-modal-tail { margin: 12px 0 16px; font-size: 13px; line-height: 1.7; }
.bank-modal .primary-button { width: 100%; }

/* 站外聯絡的提醒。用琥珀色跟「先匯款」的紅色分開——
   兩種風險程度不同，長一樣的話會分不出哪個比較嚴重 */
.offsite-warning {
  margin: 8px 0 12px;
  padding: 12px 14px;
  border: 1px solid var(--o-200);
  border-radius: var(--r-sm);
  background: var(--o-050);
  color: var(--o-800);
}
.offsite-warning-head { display: block; margin-bottom: 6px; font-size: 13px; }
.offsite-warning p { margin: 0 0 6px; font-size: 13px; line-height: 1.75; }
.offsite-warning p:last-child { margin-bottom: 0; }
.offsite-warning strong { color: var(--o-800); }
.bank-modal .offsite-warning { margin-bottom: 16px; }

/* 貼連結被擋下來的說明。放在輸入框正上方，
   使用者打的字不會被清掉，改一改就能重送 */
.link-blocked {
  margin: 0 0 8px;
  padding: 12px 14px;
  border: 1px solid var(--o-200);
  border-radius: var(--r-sm);
  background: var(--o-050);
  color: var(--o-800);
}
.link-blocked p { margin: 0 0 6px; font-size: 13px; line-height: 1.75; }
.link-blocked p:last-child { margin-bottom: 0; }
.chat-compose.is-blocked input { border-color: var(--o-200); }

/* 議價方式：可議是中性灰，不可殺價才上警示色——
   大部分商品都可議，全部染色等於沒有重點 */
.nego-tag { background: var(--surface-soft); color: var(--muted); }
.nego-tag.is-firm { background: var(--o-100); color: var(--o-800); }
.pill.nego-tag.is-firm { background: var(--o-100); color: var(--o-800); }

/* 二選一的膠囊選項 */
.radio-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.radio-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 38px;
  padding: 0 13px;
  border: 1px solid var(--line);
  border-radius: 10px;          /* 膠囊在這個高度看起來會腫，方一點才收得住 */
  background: #fff;
  font-size: var(--caption);
  font-weight: 700;
  color: var(--ink);
  cursor: pointer;
}
.radio-chip input { width: 15px; height: 15px; margin: 0; accent-color: var(--brand); }
/* 勾選態靠「灰框→藍框、灰字→藍字、勾選框變藍」三個訊號，夠明顯了。
   不要加粗邊框（會讓膠囊寬高各多 2px、勾選時跳動），也不要加淡色底
   （淡色底被飽和藍框圍住會讀成淡藍，等於多一個藍）。 */
.radio-chip:has(input:checked) { border-color: var(--brand); background: var(--n-000); color: var(--brand-strong); }
.radio-chip:hover { border-color: var(--brand); }

.is-hidden { display: none !important; }

/* 檢舉：遲到區間與佐證照片 */
.late-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--o-050);
  color: var(--o-800);
  font-size: 12px;
  font-weight: 700;
}
.report-shots { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.report-shots img {
  width: 56px;
  height: 56px;
  border-radius: 8px;
  object-fit: cover;
  border: 1px solid var(--line);
}
.upload-zone-slim { padding: 14px; }

/* 遲到鬼。獨立標籤，不屬於風險分級——
   風險講的是「可不可信」，這個講的是「會不會準時到」，所以顏色也分開 */
.late-ghost {
  background: var(--o-100);
  color: var(--o-800);
  border: 1px solid var(--o-200);
}
.risk-tag.late-ghost { border: none; }

/* 交易後的好評標籤 */
.praise-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }
.praise-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: #fff;
  font-size: var(--caption);
  font-weight: 700;
  color: var(--ink);
  cursor: pointer;
}
.praise-chip input { width: 16px; height: 16px; margin: 0; accent-color: var(--brand); }
/* 勾選態靠「灰框→藍框、灰字→藍字、勾選框變藍」三個訊號，夠明顯了。
   不要加粗邊框（會讓膠囊寬高各多 2px、勾選時跳動），也不要加淡色底
   （淡色底被飽和藍框圍住會讀成淡藍，等於多一個藍）。 */
.praise-chip:has(input:checked) { border-color: var(--brand); background: var(--n-000); color: var(--brand-strong); }
.praise-chip:hover { border-color: var(--brand); }
.praise-modal .confirm-actions { display: grid; gap: 10px; }
.praise-report { width: 100%; margin-top: 10px; border: none; font-size: 13px; }
.praise-pill { background: var(--t-050); color: var(--t-800); }
.praise-row { margin-top: 8px; }

/* 「你曾經跟他聊天過」的清單 */
.past-modal { max-width: 420px; }
.past-list { list-style: none; margin: 0 0 18px; padding: 0; display: grid; gap: 8px; max-height: 300px; overflow-y: auto; }
.past-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  text-align: left;
  cursor: pointer;
}
.past-row:hover { border-color: var(--brand); background: var(--bg-soft); }
.past-thumb { width: 44px; height: 44px; border-radius: 9px; object-fit: cover; flex: none; }
.past-copy { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; }
.past-copy strong { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.past-copy .muted { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.past-right { display: flex; align-items: center; gap: 6px; flex: none; font-size: 12px; }

/* 測試帳號清單（開發模式）。上線前跟 SMS_CODE 一起拿掉 */
.demo-accounts {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px dashed var(--line);
}
.demo-accounts > strong { font-size: 13px; }
.demo-accounts > p { margin: 4px 0 10px; font-size: 12px; }
.demo-accounts ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.demo-account {
  display: grid;
  gap: 2px;
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
  text-align: left;
  cursor: pointer;
}
.demo-account:hover { border-color: var(--brand); background: var(--bg-soft); }
.demo-phone { font-weight: 800; font-size: 13px; }
.demo-name { font-size: 12px; color: var(--brand-strong); font-weight: 700; }
.demo-note { font-size: 11px; line-height: 1.5; }

/* 我的紀錄：三個數字一排 */
.stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 12px; }
.stat-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 14px 8px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-soft);
}
.stat-box strong { font-size: 22px; line-height: 1.2; color: var(--brand-strong); }
.stat-box .muted { font-size: 12px; }

/* 最重要的那一句給多一點呼吸與重量 */
.bank-warning-punch { margin-top: 8px; font-size: 13.5px; }

.sub-head { margin: 4px 0 8px; font-size: 14px; }
.sub-head + .table-wrap { margin-bottom: 18px; }
.stat-note {
  margin: 4px 0 10px;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--muted);
}

/* 對話右上角的完成交易。這是不可逆的動作（會下架、會算成交次數），
   所以用紅底、也做得大一點——不該跟旁邊的次要按鈕長得一樣 */
.chat-done-button {
  min-height: 42px;
  padding: 0 20px;
  font-size: var(--caption);
  font-weight: 800;
  white-space: nowrap;
}

/* 交易完成後的對話：還看得到，但要一眼分得出來。
   只調透明度太弱——縮圖、底色、左側標記一起下，才不會跟進行中的混在一起 */
.chat-panel.is-closed {
  /* 原本用 --bg-soft。舊值 #eef4fb 在偏藍的舊頁面地上讀起來像中性淺灰，
     換成中性灰頁面地後同一個藍變成「被強調」，跟本段註解的意圖相反。
     已結束＝要往後退，所以用中性凹陷灰。 */
  background: var(--n-200);
  border-color: var(--line);
  box-shadow: none;
  position: relative;
  overflow: hidden;
}
.chat-panel.is-closed::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 4px;
  background: var(--line-strong, var(--n-300));
}
.chat-panel.is-closed .chat-thumb { filter: grayscale(1); opacity: .65; }
.chat-panel.is-closed .chat-list-copy h2 { color: var(--muted); font-weight: 700; }
.chat-panel.is-closed .chat-preview { color: var(--muted); }
.chat-panel.is-closed .chat-who { color: var(--muted); }
/* 已結束的對話，標籤與稱號要退到跟整張卡一樣淡。
   一開始只用 filter: grayscale(1)，但灰階會「保留亮度」——高風險的紅變成
   深灰，在已經淡化的卡片上反而成了對比最強的東西，看起來還是特別突出。
   所以實心標籤直接換成中性淡底＋次要文字色，跟同一列的「已結束」膠囊
   （.closed-pill）用同一組灰，整列的灰度才一致。
   特異性 0,3,0 蓋得過 .pill.danger 那類 0,2,0，不需要 !important。 */
.chat-panel.is-closed .pill,
.chat-panel.is-closed .risk-tag,
.chat-panel.is-closed .badge-tag {
  background: var(--n-200);
  color: var(--n-600);
  border-color: var(--n-300);
  box-shadow: none;
}
/* 稱號的圖示是彩色圖片／emoji，只能靠濾鏡；跟縮圖用同一組參數才一致 */
.chat-panel.is-closed .badge-icons,
.chat-panel.is-closed .badge-tag-img,
.chat-panel.is-closed .badge-icon-only { filter: grayscale(1); opacity: .65; }
.chat-panel.is-closed:hover { background: var(--n-300); }
.closed-pill {
  background: var(--n-200);
  color: var(--n-600);
  font-weight: 800;
}
.chat-closed-note {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px;
  border-top: 1px solid var(--line);
  background: var(--surface-soft);
  font-size: 13px;
  line-height: 1.7;
}

/* 稱號。金色系，跟等級（風險分級）分開——兩套是不同的東西 */
/* 稱號是「榮譽」不是狀態警示，不該用珊瑚底（珊瑚在本色系代表要小心）。
   白底＋灰線，讓稱號本身的圖示去帶顏色。 */
.badge-tag {
  background: var(--n-000);
  color: var(--ink);
  border: 1px solid var(--n-300);
}
/* 負面稱號（例如常遲到）才用珊瑚，而且只上邊框與文字，不填底 */
.badge-tag.is-negative { background: var(--n-000); color: var(--o-800); border-color: var(--o-200); }
.risk-tag.badge-tag { border: none; }

/* 我的稱號一覽 */
.badge-list { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 8px; }
.badge-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  opacity: .55;
}
.badge-item.is-got { opacity: 1; border-color: var(--o-200); background: var(--o-050); }
.badge-item.is-got.is-negative { border-color: var(--o-200); background: var(--o-050); }
.badge-icon { font-size: 22px; flex: none; }
.badge-copy { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; }
.badge-copy strong { font-size: 14px; }
.badge-copy .muted { font-size: 12px; line-height: 1.6; }

/* 聊天列表：帳號旁邊的等級與稱號縮小一點，不要蓋過商品名 */
/* 帳號、等級、稱號、時間排成一列，各自留呼吸空間——
   原本全部貼在一起，「444新帳號」看起來像同一個詞 */
.chat-sub {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
}
.chat-sub .pill { padding: 1px 8px; font-size: 11px; }

/* 上架很久了，還在嗎 */
.stale-modal { max-width: 420px; }
.stale-list { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 8px; max-height: 320px; overflow-y: auto; }
.stale-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 12px;
}
.stale-thumb { width: 44px; height: 44px; border-radius: 9px; object-fit: cover; flex: none; }
.stale-copy { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; }
.stale-copy strong { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stale-copy .muted { font-size: 12px; }
.stale-actions { display: flex; gap: 6px; flex: none; }
/* App 版：「還在／下架」從商品右邊移到下面、「稍後再說」上面（Ann）。
   按鈕仍留在各自商品那一格裡，有好幾件時才分得出按的是哪一件；兩顆平分整排，手指好按。
   彈窗畫在 .app-shell 外面吃不到 .mobile-shell，所以由 renderStaleModal 加 .is-app 分辨。 */
.stale-modal.is-app .stale-list li { flex-wrap: wrap; }
.stale-modal.is-app .stale-actions { flex: 1 1 100%; }
.stale-modal.is-app .stale-actions .tiny-button { flex: 1 1 0; }
/* App 版上架提醒的比例（Ann：比例怪怪的）：
   ✕ 是共用的 48px 帶框方塊，比標題還搶眼；說明文字偏大；商品框到「稍後再說」空一大塊。
   → ✕ 縮成 36px 無框淡灰圓鈕、標題與說明各縮一級、段距收緊。 */
.stale-modal.is-app { padding: 20px; }
.stale-modal.is-app .modal-head { margin-bottom: 8px; }
.stale-modal.is-app .modal-head h2 { font-size: 20px; }
.stale-modal.is-app .modal-head .icon-button {
  width: 36px;
  height: 36px;
  min-height: 36px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--n-100);
}
.stale-modal.is-app .modal-head .icon-button svg { width: 18px; height: 18px; }
.stale-modal.is-app .confirm-lead { margin-bottom: 12px; font-size: var(--caption); line-height: 1.55; }
.stale-modal.is-app .stale-list { margin-bottom: 4px; }
.stale-modal.is-app .confirm-later { min-height: 40px; margin-top: 4px; }


/* 分類與上架時間是資訊不是標籤，不用底色 */
.detail-meta {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--muted);
}

/* 加入日期是資訊不是標籤，不用底色 */
.pill.time-pill { background: transparent; color: var(--muted); padding-left: 2px; padding-right: 2px; }

/* 檢舉商品時，把被檢舉的商品放在最上面——確認檢舉的是哪一件 */
.report-subject {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  margin-bottom: 4px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-soft);
}
/* 同樣用 > 只吃直接子層。這裡目前沒有稱號所以還沒出問題，但形狀跟
   .confirm-product 一模一樣——後代選擇器的 48px 會蓋過 .badge-tag-img
   的 16px，哪天在這裡加一個稱號就會複製同一個 bug。 */
.report-subject > img { width: 48px; height: 48px; border-radius: 10px; object-fit: cover; flex: none; }
.report-subject > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.report-subject strong { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.report-subject .muted { font-size: 12px; }

/* 縣市／鄉鎮區並排。原本沒有樣式，兩個欄位直接黏在一起 */
.split-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
@media (max-width: 560px) {
  .split-fields { grid-template-columns: 1fr; }
}

/* 我的收藏的分類列 */
.fav-chips { margin-bottom: 12px; }

/* 後台看得到的申訴內容 */
.appeal-note {
  margin-top: 6px;
  padding: 8px 10px;
  border-left: 3px solid var(--warn);
  background: var(--o-050);
  border-radius: 0 8px 8px 0;
  font-size: 12.5px;
  line-height: 1.7;
}

/* 主要動作放第一個、佔大格：這頁的目的就是約面交，
   收藏只是順手，不該跟它一樣大 */
.detail-action-bar .detail-chat-button { min-width: 0; }
.detail-action-bar .detail-fav {
  min-height: 48px;
  padding: 0 18px;
  white-space: nowrap;
}

/* 議價方式跟在商品名稱後面——聊到一半才想「這個能不能殺價」，
   不用退回去看商品頁 */
.chat-modal-title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.chat-modal-title .pill { font-size: 11px; padding: 2px 9px; font-weight: 700; }

/* 表格裡的時間不換行，數字對齊比較好掃 */
td[data-label="時間"], .table-wrap td:first-child {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* 排序跟「以 ○○ 為中心」同一行、靠最右邊 */
.here-line { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.here-sort { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; }
.here-sort-label { color: var(--muted); font-size: var(--tiny); white-space: nowrap; }
.here-sort .mini-select { min-height: 34px; }
@media (max-width: 560px) {
  .here-sort { margin-left: 0; width: 100%; }
  .here-sort .mini-select { width: 100%; }
}

/* 系統設定的開關列 */
.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 0;
  cursor: pointer;
}
.setting-copy { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.setting-copy strong { font-size: 15px; }
.setting-copy .muted { font-size: 12.5px; line-height: 1.65; }
.setting-row input[type="checkbox"] {
  flex: none;
  appearance: none;
  width: 46px;
  height: 27px;
  margin: 0;
  border-radius: 99px;
  background: var(--line-strong, var(--n-300));
  position: relative;
  cursor: pointer;
  transition: background .18s ease;
}
.setting-row input[type="checkbox"]::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 21px;
  height: 21px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
  transition: transform .18s ease;
}
.setting-row input[type="checkbox"]:checked { background: var(--brand); }
.setting-row input[type="checkbox"]:checked::after { transform: translateX(19px); }
.setting-row input[type="checkbox"]:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .setting-row input[type="checkbox"],
  .setting-row input[type="checkbox"]::after { transition: none; }
}

/* 買家提出異議時，賣家那一列要看得懂發生了什麼事 */
.dispute-note {
  margin: 6px 4px 0;
  padding: 8px 10px;
  border-left: 3px solid var(--warn);
  background: var(--o-050);
  border-radius: 0 8px 8px 0;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--o-800);
}
.pill.ok { background: var(--t-800); color: #fff; }

/* 地圖卡片：橫的小長方形，等級／帳號／稱號排一行 */
.map-float-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.map-float-tags { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.map-float-card .price.is-gift { color: var(--t-800); }

/* 稱號一多就會擠成一團，給膠囊之間與上下都留呼吸空間 */
.card-seller,
.map-float-meta,
.pill-row,
.detail-pills,
.chat-sub {
  row-gap: 7px;
}
/* 內距與行高都交給 .pill 統一管，這裡不再另設——
   原本的 line-height: 1.9 會把稱號撐得比標籤高。 */
.badge-tag { padding-inline: 10px; }
.pill-row .badge-tag,
.card-seller .badge-tag { margin: 0; }

/* 「我的」標題那行帶上帳號資訊，不另外開一個區塊 */
.profile-head { align-items: flex-start; }
.profile-head > div { display: flex; flex-direction: column; gap: 10px; }
/* 這排在頁面底色上，原本的淺藍膠囊會糊掉，改成白底加框才看得出是標籤 */
.profile-id { margin: 0; }
.profile-id .pill {
  background: #fff;
  border: 1px solid var(--line);
  padding: 3px 12px;
}

/* 地圖卡片浮在地圖上，越高就擋掉越多地圖。
   每一行都不換行、超出就省略，高度固定住 */
.map-float-card { padding: 10px 12px; }
.map-float-copy {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1 1 auto;
}
.map-float-copy > * {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.map-float-copy strong { font-size: 14px; }
.map-float-copy .price { font-size: 15px; font-weight: 800; color: var(--brand); }
.map-float-copy .muted { font-size: 12px; }
.map-float-tags,
.map-float-meta {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 6px;
  font-size: 12px;
}
.map-float-tags .pill,
.map-float-meta .pill {
  flex: 0 0 auto;
  padding: 1px 8px;
  font-size: 11px;
}

/* 點群組時會有好幾張卡並排。單張時不要撐滿整個地圖寬度 */
.map-card-slot { pointer-events: none; }
.map-card-slot > * { pointer-events: auto; }
.map-card-row {
  display: flex;
  gap: 10px;
  align-items: stretch;
  overflow-x: auto;
  padding-bottom: 2px;
}
.map-card-row .map-float-card {
  flex: 1 1 0;
  min-width: 240px;
  max-width: 380px;
}

/* ===== 地圖小卡修正（Ann 2026-09-15 iPhone 實測排版怪）=====
   1. 小卡區 z-index 1000 高過底部導覽 40，頁面沒捲到底時小卡直接蓋在導覽列上。
      → 地圖外框自成一層（isolation），裡面再高的 z-index 都只在地圖範圍內疊。
   2. ✕ 原本絕對定位壓在第二張卡上 → 改成卡片列上方一排（左件數、右 ✕）。
   3. 卡片列左右滑動時一張一張停好；App 版每張 84% 寬，露出下一張的邊暗示可以滑。 */
.map-stage-live { isolation: isolate; }
.map-card-slot { display: flex; flex-direction: column; gap: 6px; }
.map-card-bar { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.map-card-count {
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .94);
  box-shadow: var(--shadow-soft);
  color: var(--ink);
  font-size: var(--tiny);
  font-weight: 700;
}
.map-card-count:empty { visibility: hidden; }
.map-card-slot .map-card-close {
  position: static;
  display: grid;
  flex: none;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: var(--n-000);
  color: var(--ink);
  box-shadow: var(--shadow-soft);
}
.map-card-row {
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.map-card-row::-webkit-scrollbar { display: none; }
.map-card-row .map-float-card { scroll-snap-align: start; }
html.surface-app .map-card-row .map-float-card { flex: 0 0 84%; min-width: 0; max-width: none; }
html.surface-app .map-card-row .map-float-card:only-child { flex-basis: 100%; }

/* ===== App 版首頁：捲動時自動收起上方（Ann 選的做法）=====
   往下滑：整塊捲走，頂端浮出細搜尋列（.home-mini-bar，fixed、不佔版面）。
   往上滑一點：原本整塊 sticky 固定在頂端並從上方滑下（原位置保留，列表不跳）。
   z-index 30：低於底部導覽 40、彈窗 50、搜尋頁 60、抽屜 70。 */
.home-mini-bar { display: none; }
html.surface-app .home-mini-bar {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: calc(env(safe-area-inset-top) + 8px) 16px 8px;
  background: var(--page-bg);
  box-shadow: 0 6px 16px rgba(32, 37, 39, .10);
  transform: translateY(-110%);
  pointer-events: none;
  transition: transform .2s ease;
}
html.surface-app.home-mini-shown .home-mini-bar { transform: none; pointer-events: auto; }
.home-mini-search {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: 10px;
  min-width: 0;
  height: 40px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--n-000);
  box-shadow: var(--shadow-soft);
  color: var(--muted);
  font: inherit;
  font-size: var(--caption);
  text-align: left;
  cursor: pointer;
}
.home-mini-search span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.home-mini-search span.has-query { color: var(--ink); font-weight: 700; }
html.surface-app.home-hero-pinned .mobile-shell .home-hero {
  position: sticky;
  top: 0;
  z-index: 30;
  /* 加了上下內距看起來才像工具列，但內距會讓這塊變高、把下面的商品推下去（實測會跳）。
     所以用等量的負邊距抵銷：-(12＋安全區) ＋ (安全區＋12) ＋ 內容 ＋ 12 ＋ 8 ＝ 內容 ＋ 原本的 margin-bottom 20，
     佔的總高度跟沒固定時一模一樣，列表不動。 */
  margin: calc(-12px - env(safe-area-inset-top)) -16px 8px;
  padding: calc(env(safe-area-inset-top) + 12px) 16px 12px;
  background: var(--page-bg);
  box-shadow: 0 6px 16px rgba(32, 37, 39, .10);
  animation: home-hero-drop .22s ease-out;
}
@keyframes home-hero-drop { from { transform: translateY(-100%); } to { transform: none; } }

/* ===== App 版地圖滿版（Ann：地圖在下半部，點數字後商品卡在底下要捲才看得到，長輩不會用）=====
   地圖佔滿「頂端 → 底部導覽列上緣」，頁面本身不捲；上方浮一條工具列（搜尋／清單地圖／☰）＋位置膠囊，
   點數字後商品卡貼在地圖底部＝就在導覽列正上方，一定在畫面裡。
   導覽列高度同 .chat-fullscreen 的算法：58px ＋ max(8px, 安全區)。 */
.map-full { display: none; }
html.surface-app .map-full {
  position: fixed;
  /* 2026-09-21：從「上方 logo 列的下緣」開始，不要從畫面最頂端開始。
     原本 top:0 會讓地圖工具列（它在裡面 top:16px）跟 logo 列重疊 22px（實測）。
     讓位之後還有一個剛好的好處：工具列裡的切換鈕落在 38+16=54px，
     正好等於清單狀態時切換鈕的位置（實測 54px）——按下去就不會跳了。 */
  top: var(--app-topbar-h);
  right: 0;
  bottom: calc(58px + max(8px, env(safe-area-inset-bottom)));
  left: 0;
  z-index: 5;
  display: block;
  background: var(--n-200);
}
html.surface-app .map-full .map-stage-live { position: absolute; inset: 0; }
html.surface-app .map-full .leaflet-stage {
  height: 100%;
  min-height: 0;
  max-height: none;
  border-radius: 0;
}
.map-full-top {
  position: absolute;
  top: calc(env(safe-area-inset-top) + 10px);
  right: 12px;
  left: 12px;
  z-index: 1100;
  display: grid;
  gap: 8px;
  pointer-events: none;
}
.map-full-top > * { pointer-events: auto; }
.map-full-bar { display: flex; align-items: center; gap: 8px; }
.map-full-bar .home-mini-search { flex: 1 1 auto; }
.map-full-bar .view-switch { flex: none; box-shadow: var(--shadow-soft); background: var(--n-000); }
.map-full-bar .category-menu-btn { flex: none; background: var(--n-000); box-shadow: var(--shadow-soft); }
.map-full-where {
  display: flex;
  align-items: center;
  justify-self: start;
  gap: 8px;
  max-width: 100%;
  padding: 4px 4px 4px 12px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .95);
  box-shadow: var(--shadow-soft);
  color: var(--ink);
  font-size: var(--caption);
}
.map-full-where span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.map-full-where strong { color: var(--c-600); }
.map-full-where .locate-chip { height: 30px; min-height: 30px; flex: none; }
/* 工具列與位置膠囊不能超出螢幕（實測：可用 366px，內容排出 395px，☰ 與「定位」被切掉）。
   grid 欄位預設 min-width:auto 會被內容撐開，限制成 minmax(0,1fr) 搜尋列才會真的縮；
   清單／地圖按鈕內距 14→10 省約 16px；位置文字太長就「…」，定位鈕永遠留在畫面內。 */
.map-full-top { grid-template-columns: minmax(0, 1fr); }
.map-full-bar,
.map-full-where { min-width: 0; }
.map-full-bar .home-mini-search { min-width: 0; }
.map-full-bar .view-switch-btn { gap: 4px; padding: 0 10px; }
.map-full-where span { flex: 1 1 auto; min-width: 0; }
/* 位置膠囊裡的縣市／鄉鎮選單（Ann：不想被定位的人要能手動選地點）。
   跟清單版同一組 .inline-select，只是收進膠囊：拿掉自己的陰影、改淡底、矮一點。 */
.map-full-where { padding-left: 4px; }
.map-full-where .here-picks { flex: none; gap: 2px; overflow: visible; }
.map-full-where .inline-select {
  height: 30px;
  padding: 0 24px 0 10px;
  box-shadow: none;
  background-color: var(--bg-soft);
  background-position: right 8px center;
  color: var(--c-600);
  font-weight: 800;
}
.map-full-where .map-where-count { flex: 1 1 auto; min-width: 0; white-space: nowrap; }
/* Leaflet 放大縮小鈕原本在左上，會被浮動工具列擋住，往下移 */
html.surface-app .map-full .leaflet-top { top: calc(env(safe-area-inset-top) + 112px); }
/* 商品卡貼在地圖底部（就在導覽列上方）並留一點邊 */
html.surface-app .map-full .map-card-slot { right: 12px; bottom: 12px; left: 12px; }

/* ===== 清單 ↔ 地圖切換不跳（Ann：變動感很強、按鈕位置會動）=====
   原因：清單模式的切換鈕在標題列（內距 14、離邊 16px、灰底），地圖模式在浮動工具列（內距 10、離邊 12px、白底），
   整頁重畫時按鈕從一個位置瞬移到另一個位置。
   → 兩種模式的「清單／地圖」與 ☰ 同尺寸、同樣離頂 16px／離邊 16px、同白底，切換時只有左邊標題↔搜尋列在換。 */
/* 頂端空白列拿掉後，加到主畫面的 iPhone 內容會頂到瀏海；補回安全區，也讓兩種模式的起點一致 */
html.surface-app .mobile-shell .main { padding-top: calc(16px + env(safe-area-inset-top)); }
html.surface-app .map-full-top { top: calc(env(safe-area-inset-top) + 16px); right: 16px; left: 16px; }
html.surface-app .view-switch-btn { gap: 4px; padding: 0 10px; }
html.surface-app .hero-actions .view-switch,
html.surface-app .map-full-bar .view-switch { background: var(--n-000); box-shadow: var(--shadow-soft), inset 0 0 0 1px var(--line); }
html.surface-app .hero-actions .category-menu-btn,
html.surface-app .map-full-bar .category-menu-btn { background: var(--n-000); box-shadow: var(--shadow-soft); }
html.surface-app .map-full .leaflet-top { top: calc(env(safe-area-inset-top) + 118px); }
/* 滑塊先停在舊位置（.from-other），JS 下兩個畫格拿掉 class，滑塊就滑到新位置 */
.view-switch.from-other:has(.view-switch-btn:last-of-type.active)::before { transform: translateX(0); transition: none; }
.view-switch.from-other:not(:has(.view-switch-btn:last-of-type.active))::before { transform: translateX(100%); transition: none; }
/* 內容淡入；上方按鈕不參與，保持穩定 */
@keyframes view-fade-in { from { opacity: 0; } to { opacity: 1; } }
html.surface-app .view-enter { animation: view-fade-in .22s ease-out; }
@media (prefers-reduced-motion: reduce) {
  html.surface-app .view-enter { animation: none; }
}
@media (prefers-reduced-motion: reduce) {
  html.surface-app .home-mini-bar { transition: none; }
  html.surface-app.home-hero-pinned .mobile-shell .home-hero { animation: none; }
}
.map-card-slot > .map-card-close {
  position: absolute;
  top: -10px;
  right: -6px;
  z-index: 2;
}

/* 補充內容很長的時候，表格會把整頁撐寬到出現橫向捲動。
   grid／flex 的子元素預設 min-width:auto，內容多寬它就多寬，
   要歸零才會乖乖待在容器裡、讓表格自己捲。 */
.main,
.panel,
.settings-section,
.table-wrap { min-width: 0; }

/* 長文字要斷行，不要一路推寬欄位 */
td { overflow-wrap: anywhere; }
td[data-label="補充內容"],
.table-wrap td:nth-child(4) { max-width: 380px; white-space: normal; }

/* 搜尋、免費贈送、收藏、排序全部收到「以 ○○ 為中心」那一行的右半邊 */
.here-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}
.here-tools .search-pill {
  flex: 0 1 220px;
  width: 220px;
  height: 38px;
  margin: 0;
  padding: 0 14px;
}
.here-tools .search-pill input { font-size: var(--caption); }
.here-tools .gift-toggle,
.here-tools .fav-toggle {
  flex: 0 0 auto;
  width: auto;
  height: 38px;
  min-height: 38px;
  padding: 0 14px;
  white-space: nowrap;
}
.here-tools .here-sort { margin-left: 0; }

/* App 版的分類鈕：只有三條線（Ann 指定），放在首頁「附近好物」那一排、清單／地圖切換的右邊。
   展開時底色轉淡灰表示「按下中」；選了分類時右上掛深藍小圓點，沒有文字也知道有在篩。
   篩選條件不在首頁了：點搜尋框開整頁搜尋畫面，篩選在那裡（見 .search-screen）。 */
.category-menu-btn {
  position: relative;
  display: grid;
  place-items: center;
  justify-self: end;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}
/* 手機寬度（@media max-width:768px 那段）把 .topbar 改成單欄 1fr，☰ 會被擠到品牌下面一行。
   App 版要它跟品牌同一行、貼在最右上角（Ann），所以把兩欄還回來。網站版窄螢幕不受影響。 */
/* App 版頂端列的來龍去脈（改這裡前先看完，不然會來回改）：
   1. 原本什麼都不放：品牌拿掉（Ann），☰ 搬到「附近好物」那一排（Ann：跟清單／地圖同一排），
      所以收成 0 高、無內距、無底線。頂端列不能整個不畫——底部導覽 .nav 寫在它裡面，
      是 fixed 所以不佔高度。
   2. 2026-09-17 Ann 指定「左上角統一放 logo」，手機版也要，所以這條列重新給了高度。
      ⚠️ 代價是頂端多一條列（約 40px），而那正是第 1 點當初想省掉的空間。
      若之後覺得佔位，替代做法是把 logo 移到「附近好物」那一排的最左邊，不另開一條列。 */
.mobile-shell .topbar {
  min-height: 0;
  /* Ann 2026-09-17：手機版左上角也要放 logo，所以這條列不再整個收合，
     只給剛好容納 logo 的高度。導覽列是固定在畫面底部的，不受這裡影響。
     2026-09-21 補上安全區：加了 viewport-fit=cover 之後畫面會延伸到瀏海底下，
     不補的話 logo 會被瀏海／狀態列吃掉。
     這條列的總高度 = 安全區 + 10 + logo 26 + 2 = 安全區 + 38px，
     下面的 --app-topbar-h 就是同一個值，地圖層靠它讓位。 */
  padding: calc(env(safe-area-inset-top) + 10px) 16px 2px;
  border-bottom: 0;
}
/* 手機版上方列的總高度，給地圖層讓位用。改上面的內距時這裡要一起改。 */
html.surface-app { --app-topbar-h: calc(env(safe-area-inset-top) + 38px); }
/* 手機版的 logo 比網站版矮一點：上方空間寶貴 */
.mobile-shell .brand-logo {
  height: 26px;
  width: auto;
}
/* 首頁標題列右邊那組：清單／地圖切換 ＋ ☰ 並排 */
.hero-actions { display: flex; flex: none; align-items: center; gap: 8px; }
.category-menu-btn:hover,
.category-menu-btn.is-open { background: var(--n-200); }
.category-menu-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.category-menu-dot {
  position: absolute;
  top: 7px;
  right: 7px;
  width: 8px;
  height: 8px;
  border-radius: var(--r-pill);
  background: var(--c-600);
  box-shadow: 0 0 0 2px var(--n-000);
}
/* ===== App 版分類抽屜（一般 App 漢堡選單的做法）=====
   從右邊滑出、整個畫面高、寬約八成（最寬 320px），左邊留一條看得到原畫面；後面整片變暗，點暗處收起。
   清單長相照網站側欄：一行一個、行間細線、選中淺藍底；細分類縮排＋左側細線。
   z-index 70：蓋過頂端列 20、底部導覽 40、彈窗 50、搜尋畫面 60。 */
.category-drawer-layer { position: fixed; inset: 0; z-index: 70; }
.category-drawer-backdrop {
  position: absolute;
  inset: 0;
  width: 100%;
  padding: 0;
  border: 0;
  background: rgba(32, 37, 39, .38);
  cursor: pointer;
}
.category-drawer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  width: min(82vw, 320px);
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--panel);
  box-shadow: -12px 0 32px rgba(32, 37, 39, .18);
}
.category-drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 12px 12px 20px;
  border-bottom: 1px solid var(--line);
}
.category-drawer-head h2 { margin: 0; color: var(--ink); font-size: var(--h3); }
.category-drawer-list {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 8px 12px 16px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.category-drawer-list > .cat-chip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: 50px;
  padding: 0 12px;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  color: var(--ink);
  font-size: var(--body);
  font-weight: 600;
  text-align: left;
}
/* 右側小箭頭：表示點了會進去／展開。用 SVG 背景圖，不用文字字元 */
.category-drawer-list > .cat-chip::after {
  content: "";
  flex: none;
  width: 8px;
  height: 14px;
  background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='8'%20height='14'%20viewBox='0%200%208%2014'%20fill='none'%20stroke='%23616e75'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M1.5%201.5%206.5%207l-5%205.5'/%3E%3C/svg%3E") no-repeat center;
}
.category-drawer-list > .cat-chip:hover { background: var(--n-100); }
.category-drawer-list > .cat-chip.active,
.category-drawer-list > .cat-chip.active:hover {
  border-bottom-color: transparent;
  border-radius: 8px;
  background: var(--c-400);
  color: var(--n-900);
  font-weight: 800;
}
/* 選中而且有細分類時，箭頭轉朝下，表示底下展開了 */
.category-drawer-list > .cat-chip.active:has(+ .sub-chips.nested)::after { transform: rotate(90deg); }
.category-drawer-list .sub-chips.nested {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin: 4px 0 8px 12px;
  padding-left: 10px;
  border-left: 2px solid var(--line);
}
.category-drawer-list .sub-chips.nested .cat-chip {
  width: 100%;
  min-height: 44px;
  justify-content: flex-start;
  padding: 0 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  box-shadow: none;
  color: var(--muted);
  font-size: var(--caption);
  font-weight: 600;
}
.category-drawer-list .sub-chips.nested .cat-chip.active,
.category-drawer-list .sub-chips.nested .cat-chip.active:hover {
  background: var(--mint);
  color: var(--brand-strong);
  font-weight: 800;
}
/* 滑入：只在剛打開時（.is-entering）播；滑出：關閉前加 .is-leaving，JS 等 200ms 再真的移除 */
@keyframes category-drawer-in { from { transform: translateX(100%); } to { transform: translateX(0); } }
@keyframes category-drawer-fade { from { opacity: 0; } to { opacity: 1; } }
.category-drawer-layer.is-entering .category-drawer { animation: category-drawer-in .26s cubic-bezier(.2, .8, .2, 1); }
.category-drawer-layer.is-entering .category-drawer-backdrop { animation: category-drawer-fade .26s ease; }
.category-drawer-layer.is-leaving .category-drawer { transform: translateX(100%); transition: transform .2s ease-in; }
.category-drawer-layer.is-leaving .category-drawer-backdrop { opacity: 0; transition: opacity .2s ease-in; }
@media (prefers-reduced-motion: reduce) {
  .category-drawer-layer .category-drawer,
  .category-drawer-layer .category-drawer-backdrop { animation: none; transition: none; }
}

/* ===== App 版搜尋畫面（參考蝦皮）=====
   蓋住整個畫面但底部導覽列要露出來（Ann）：底部讓出導覽列高度，算法同 .chat-fullscreen。
   上面固定一條搜尋列，下面內容自己捲。按導覽列換頁時會順手關掉搜尋畫面。
   輸入框字級 16px：iOS 小於 16px 聚焦時會自動放大整頁。 */
.search-screen {
  position: fixed;
  inset: 0 0 calc(58px + max(8px, env(safe-area-inset-bottom))) 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  background: var(--page-bg);
}
.search-screen-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 8px;
  align-items: center;
  padding: max(12px, env(safe-area-inset-top)) 16px 12px 8px;
  border-bottom: 1px solid var(--line);
  background: var(--n-000);
}
.search-back {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}
.search-back:hover { background: var(--n-100); }
.search-screen-input {
  width: 100%;
  height: 42px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--n-100);
  color: var(--ink);
  font: inherit;
  font-size: 16px;
}
.search-screen-input:focus { outline: none; border-color: var(--c-600); background: var(--n-000); }
.search-go {
  height: 42px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--c-600);
  color: var(--n-000);
  font: inherit;
  font-size: var(--caption);
  font-weight: 700;
  cursor: pointer;
}
.search-screen-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  align-content: start;
  gap: 20px;
  padding: 16px 16px 24px;
}
.search-section-title { margin: 0 0 10px; color: var(--ink); font-size: var(--caption); font-weight: 800; }
.recent-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.recent-chip,
.recent-clear {
  height: 34px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--n-000);
  box-shadow: var(--shadow-soft);
  font: inherit;
  cursor: pointer;
}
.recent-chip {
  max-width: 100%;
  padding: 0 14px;
  overflow: hidden;
  color: var(--ink);
  font-size: var(--caption);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.recent-clear { display: grid; place-items: center; width: 34px; padding: 0; color: var(--muted); }
.recent-chip:hover,
.recent-clear:hover { background: var(--n-100); }
.search-filters {
  display: grid;
  gap: 10px;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
}
.search-filters .area-row { margin: 0; }

/* ===== App 版彈窗排版修正（Ann 2026-09-14 回報「排版跑掉」）=====
   這些彈窗畫在 .app-shell 外面吃不到 .mobile-shell，用 .is-app / .chat-fullscreen 分辨。
   特異性刻意高過 @media 裡的 .modal-head／.chat-head-actions 覆蓋，不靠檔案先後順序。 */

/* 商品詳情：窄螢幕原本做成「從底部滑上來」只圓上面兩角（16px 16px 0 0），
   但 App 版它是浮在中間的卡片，下面兩角也要圓（Ann）。overflow:hidden 讓底部動作列的白底跟著被圓角裁掉。 */
.product-detail-modal.is-app {
  border-radius: 16px;
  overflow: hidden;
}

/* 商品詳情：窄螢幕的 .modal-head 被改成單欄，✕ 掉到商品名稱下面。還回「標題左、✕ 右」 */
.product-detail-modal.is-app .modal-head {
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
}

/* 商品詳情底部：程式裡「聊天約面交」寫在「收藏」前面，格子先把聊天放進第 2 欄，
   不會回頭補第 1 欄的空位，收藏就被推到下一行、檢舉再掉一行。
   dense 讓收藏回頭補位：收藏＋聊天約面交同一行，檢舉在下一行靠右。 */
.product-detail-modal.is-app .detail-action-bar {
  grid-template-columns: auto minmax(0, 1fr);
  grid-auto-flow: row dense;
}

/* 全螢幕對話的標題區（App），照一般 App 聊天室的頂端列排（Ann：原本「←」與商品資訊散成好幾行很怪）：
     第一排：← ｜ 40px 商品圖 ｜ 名稱（一行，太長變…）＋價錢可議 / 與 xxx 約定面交＋標籤
     第二排：完成交易、檢舉對方，從最左邊開始、按鈕縮小
   底下一條細線跟訊息區分開。
   選擇器多掛 .chat-modal-card：@media 620px 裡的 .modal-head:has(.chat-head-actions) 寫在檔案後面、
   特異性相同會蓋過來，多一層才穩。 */
.chat-fullscreen .chat-modal-card .modal-head {
  position: static;
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr);
  grid-template-areas:
    "back product"
    "actions actions";
  align-items: center;
  column-gap: 6px;
  row-gap: 12px;
  margin: 0 0 12px;
  padding: 0 0 12px;
  border-bottom: 1px solid var(--line);
}
.chat-fullscreen .chat-back { grid-area: back; margin-left: -8px; }
.chat-fullscreen .chat-modal-card .chat-modal-product {
  grid-area: product;
  grid-template-columns: 40px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
}
.chat-fullscreen .chat-modal-card .chat-modal-thumb { width: 40px; height: 40px; border-radius: 10px; }
.chat-fullscreen .chat-modal-card .chat-modal-title {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 6px;
  min-width: 0;
  margin: 0;
  font-size: 16px;
  line-height: 1.3;
}
.chat-fullscreen .chat-modal-card .chat-modal-title > span:first-child {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chat-fullscreen .chat-modal-card .chat-modal-title .pill { flex: none; }
.chat-fullscreen .chat-modal-card .chat-modal-meta { gap: 6px; margin-top: 2px; font-size: var(--caption); }
.chat-fullscreen .chat-modal-card .chat-head-actions {
  grid-area: actions;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 8px;
}
.chat-fullscreen .chat-modal-card .chat-head-actions button {
  min-height: 36px;
  padding: 0 14px;
  font-size: var(--caption);
}
.chat-back {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}
.chat-back:hover { background: var(--n-100); }

/* 對方是高風險用戶的常駐提醒：放在對話標題與訊息之間，網站與 App 共用。
   珊瑚族警示配色：底 --o-050、框 --o-200、字 --o-800（白底 7.05，淡珊瑚底上也過 AA）。 */
.chat-risk-notice {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0 0 12px;
  padding: 10px 14px;
  border: 1px solid var(--o-200);
  border-radius: var(--r-sm);
  background: var(--o-050);
  color: var(--o-800);
}
.chat-risk-icon { flex: none; margin-top: 1px; }
.chat-risk-notice p { display: grid; gap: 2px; margin: 0; font-size: var(--caption); line-height: 1.5; }
.chat-risk-notice strong { font-weight: 800; }
.chat-fullscreen .chat-risk-notice { flex: none; }
/* 中風險：橘色系（跟 --a-400 標籤同色相）。亮橘配字不夠清楚，
   所以字用深橘褐 #8a4500，在淡橘底 #fff3e6 上約 6.9:1（過 AA）。 */
.chat-risk-notice.is-medium { border-color: #ffc58a; background: #fff3e6; color: #8a4500; }
.chat-back:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
/* 排序的下拉要跟旁邊的搜尋框、按鈕一樣高 */
.here-tools .mini-select {
  height: 38px;
  min-height: 38px;
  padding-top: 0;
  padding-bottom: 0;
}
@media (max-width: 900px) {
  .here-tools { margin-left: 0; width: 100%; }
  .here-tools .search-pill { flex: 1 1 100%; width: 100%; }
}

/* 免費贈送改用紅字（Ann 指定），跟一般價格的藍字分得更開 */
.price-badge.is-gift,
.detail-price.is-gift,
.map-float-card .price.is-gift { color: var(--danger); }

/* 分類清單捲軸要看得到。
   它同時掛著 .cat-chips，而 .cat-chips::-webkit-scrollbar 是 display:none
   （那是給手機版橫向捲的分類列用的），所以這裡要明確把捲軸叫回來。 */
/* macOS 預設是「浮動捲軸」——平常整條是隱形的，只有捲的時候才冒出來。
   -webkit-appearance: none 才會切回一直看得到的傳統捲軸。 */
.filter-rail .rail-chips {
  scrollbar-gutter: stable;
  scrollbar-color: var(--line-strong, var(--n-300)) var(--surface-soft);
}
.filter-rail .rail-chips::-webkit-scrollbar {
  display: block;
  -webkit-appearance: none;
  width: 8px;
}
.filter-rail .rail-chips::-webkit-scrollbar-track {
  background: var(--surface-soft);
  border-radius: 999px;
}
.filter-rail .rail-chips::-webkit-scrollbar-thumb {
  background: var(--line-strong, var(--n-300));
  border-radius: 999px;
}
.filter-rail .rail-chips::-webkit-scrollbar-thumb:hover { background: var(--muted); }

/* 自己畫的捲軸。系統的浮動捲軸平常是隱形的，
   ::-webkit-scrollbar 在這個環境叫不回來，只好自己來。 */
.rail-chips-wrap { position: relative; }
.filter-rail .rail-chips { padding-right: 12px; scrollbar-width: none; }
.filter-rail .rail-chips::-webkit-scrollbar { display: none; }
.rail-scroll {
  position: absolute;
  top: 2px;
  right: 0;
  bottom: 2px;
  width: 6px;
  border-radius: 999px;
  background: var(--surface-soft);
}
.rail-scroll-thumb {
  display: block;
  width: 100%;
  border-radius: 999px;
  background: var(--line-strong, var(--n-300));
  transition: transform .06s linear;
}
.rail-scroll-thumb:hover { background: var(--muted); }
/* 拖得動就要看起來拖得動：手把游標＋關掉觸控捲動接管，
   否則手機上按住 thumb 會變成捲整頁。 */
.rail-scroll { cursor: pointer; }
.rail-scroll-thumb { cursor: grab; touch-action: none; }
.rail-scroll-thumb.is-dragging {
  cursor: grabbing;
  background: var(--muted);
  /* 拖曳時要跟著手指走，不能有過場動畫，否則會有延遲感 */
  transition: none;
}
@media (prefers-reduced-motion: reduce) {
  .rail-scroll-thumb { transition: none; }
}

/* 勾選式的篩選項 */
.check-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.check-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 36px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
  font-size: var(--caption);
  font-weight: 700;
  color: var(--ink);
  cursor: pointer;
}
.check-chip input { width: 15px; height: 15px; margin: 0; accent-color: var(--brand); }
/* 勾選態靠「灰框→藍框、灰字→藍字、勾選框變藍」三個訊號，夠明顯了。
   不要加粗邊框（會讓膠囊寬高各多 2px、勾選時跳動），也不要加淡色底
   （淡色底被飽和藍框圍住會讀成淡藍，等於多一個藍）。 */
.check-chip:has(input:checked) { border-color: var(--brand); background: var(--n-000); color: var(--brand-strong); }
.check-chip:hover { border-color: var(--brand); }
.filter-rail .check-chips { display: grid; grid-template-columns: 1fr; gap: 6px; }

/* 賣家篩選：信用狀態（勾了＝要看）＋排除遲到鬼（勾了＝不看）。
   側欄只有約 220px 寬：信用狀態都是三個字，排兩欄放得下、也不會拉太長；
   「排除 🐌 遲到鬼」較長，維持一欄。 */
.exclude-group { display: grid; gap: 6px; width: 100%; }
.exclude-sub { margin: 4px 0 0; font-size: var(--tiny); font-weight: 700; color: var(--muted); }
.exclude-group .exclude-sub:first-child { margin-top: 0; }
.filter-rail .check-chips.exclude-chips.is-2col { grid-template-columns: 1fr 1fr; }
.exclude-chips .check-chip span { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }

/* 信用狀態勾起來時用各自標籤的顏色（Ann 指定）：整格填滿、白字，跟卡片上的標籤同色。
   打勾框改白色（勾號自動變深），不然會跟底色糊成一塊。
   中風險亮橘配白字只有 2.52，跟卡片標籤是同一個已知取捨（見 --a-400 註解）。 */
.check-chip.status-fresh  { --status-c: var(--n-550); }
.check-chip.status-good   { --status-c: var(--t-600); }
.check-chip.status-pro    { --status-c: var(--t-800); }
.check-chip.status-mild   { --status-c: var(--g-500); }
.check-chip.status-warn   { --status-c: var(--a-400); }
.check-chip.status-danger { --status-c: var(--o-600); }
/* 普通賣家（正常）卡片上不顯示標籤，沒有自己的標籤色；.pill.ok 的深青綠又跟專業賣家撞色，
   所以用介面深藍，勾起來跟其他六格分得開。 */
.check-chip.status-ok     { --status-c: var(--c-600); }
.exclude-chips .check-chip.is-status:hover { border-color: var(--status-c); }
.exclude-chips .check-chip.is-status:has(input:checked) {
  background: var(--status-c);
  border-color: var(--status-c);
  color: #fff;
}
.exclude-chips .check-chip.is-status input { accent-color: var(--status-c); }
.exclude-chips .check-chip.is-status:has(input:checked) input { accent-color: #fff; }
/* 標題在上、內容在下。.area-row 本身帶 flex-wrap: wrap，直向排時要關掉——
   不然 .price-range 的 flex-basis 100% 會被當成「整欄高」，換到旁邊另一欄，
   「金額」就跟最低／最高並排了（2026-09-14 實測踩到）。 */
.exclude-row,
.titled-row { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
.titled-row .price-range { flex: none; }
/* 「金額」跟「賣家」同一種小標題：光看「最低－最高」兩格不知道在填什麼（Ann） */
.exclude-title,
.filter-title { margin: 0; font-size: var(--caption); font-weight: 700; color: var(--c-600); }

/* 側欄的文字階層只有兩層，同一層就要完全一致：
     區塊標題（.rail-title）  12px / w800 / --muted
     選項層（分類、下拉值、勾選項）14px / w600 / --ink
   原本分類選項是 600、下拉值與勾選項是 700，同一層卻不同字重，
   看起來就會覺得「這一區的字沒有一致」。 */
.filter-rail .mini-select,
.filter-rail .inline-select,
.filter-rail .check-chip,
.filter-rail .radio-chip,
.filter-rail .price-input { font-weight: 600; }

/* 商品名稱原本固定佔兩行的高度（min-height: 42px），
   一行的名稱下面就空一整行。改成有多少寫多少，最多兩行還是會截斷。 */
.product-title { min-height: 0; }
.card-tags { margin-top: 6px; }

/* 列表卡片的稱號：只有圖示，名稱靠 title 提示 */
.badge-icons { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; }
.badge-icon-only {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--o-100);
  border: 1px solid var(--o-200);
  font-size: 12px;
  line-height: 1;
}
.badge-icon-only.is-negative { background: var(--o-100); border-color: var(--o-200); }

/* ============================================================
   排版與視覺整理（2026-09-04）
   規格來源：Ann「優化介面排版設計」六點。
   原則：功能、商品圖片、資料內容一律不動，只調排版與視覺。
   放在檔尾是沿用本檔既有做法——前面已疊了好幾層日期修正區，
   在原處改會被後面的區塊蓋掉。
   ============================================================ */

/* ---------- 1. 整體背景：整頁不要再泛藍 ---------- */
/* --bg-soft 同時被標籤底、切換鈕、距離膠囊用著，直接改掉會把那些
   一起洗白，所以 --page-bg 是只管「頁面地」的獨立 token。 */
/* token 已上移到檔頭唯一的 :root。
   下面這條 body/.app-shell 必須留在原地——它要覆蓋檔頭的 body 背景。 */
body,
.app-shell { background: var(--page-bg); }

/* ---------- 2. 上方資訊分層 ---------- */
/* 上方留白收掉，商品區整體往上 */
.web-shell .main { padding-top: 20px; }
.web-shell .home-hero { margin-bottom: 16px; }
/* 首頁標題原本被放大成 36px/800，但聊天／發布／我的都是 28px/700，
   四個分頁的標題應該一樣重。以其他三頁為準，這裡不再另外放大。 */
.web-shell .home-hero h1 {
  letter-spacing: -.01em;
}
/* 地區／定位在標題下方自成一行（搜尋等工具靠右已由 .here-tools 處理） */
.web-shell .here-line { margin: 8px 0 0; }

/* ---------- 3. 左側篩選欄 ---------- */
/* 各組之間拉開，層級才看得出來（8pt grid） */
.filter-rail { gap: 24px; padding: 24px; }

/* 分類從「一堆大膠囊」改成簡潔列表：白底、深色字、淡分隔線。
   用 > 只吃第一層，巢狀的細分類不受影響。 */
.filter-rail .rail-chips { gap: 0; }
.filter-rail .rail-chips > .cat-chip {
  min-height: 40px;
  padding: 0 12px;
  border-radius: 8px;
  background: transparent;
  box-shadow: none;
  color: var(--ink);
  font-weight: 600;
  border-bottom: 1px solid var(--line);
}
.filter-rail .rail-chips > .cat-chip:last-child { border-bottom: 0; }
.filter-rail .rail-chips > .cat-chip:hover { background: var(--n-100); }
/* 只有目前選中的用藍底白字 */
.filter-rail .rail-chips > .cat-chip.active {
  background: var(--c-400);
  color: var(--n-900);
  font-weight: 800;
  border-bottom-color: transparent;
}
/* 細分類縮排一格、再淡一階，不跟主分類搶 */
.filter-rail .sub-chips.nested {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin: 2px 0 6px 12px;
  padding-left: 10px;
  border-left: 2px solid var(--line);
}
.filter-rail .sub-chips.nested .cat-chip {
  min-height: 34px;
  padding: 0 10px;
  border-radius: 8px;
  background: transparent;
  box-shadow: none;
  color: var(--muted);
  font-weight: 600;
  font-size: var(--tiny);
}
.filter-rail .sub-chips.nested .cat-chip.active {
  background: var(--mint);
  color: var(--brand-strong);
  font-weight: 800;
}

/* ---------- 4. 商品卡片 ---------- */
/* 圓角縮小、陰影變淡（商品圖片本身完全不動） */
.product-card {
  border-radius: 14px;
  box-shadow: 0 1px 3px rgba(32, 37, 39, .06), 0 1px 2px rgba(32, 37, 39, .04);
}
.product-card:hover,
.product-card:focus-within {
  box-shadow: 0 6px 16px rgba(32, 37, 39, .10);
  transform: translateY(-2px);
}
/* 商品名稱字重加強 */
.product-title {
  font-weight: 800;
  font-size: 15px;
}
/* 愛心明確釘在圖片右上角 */
.product-photo-wrap { position: relative; }
.product-card .fav-btn { top: 10px; right: 10px; }

/* ---------- 5. 標籤顏色收斂 ---------- */
/* 一般資訊（成色、議價）改灰，不再用高彩度藍搶畫面。
   兩個值都取自 DESIGN_SYSTEM.md：Header gray / Muted text。 */
.cond-tag {
  background: var(--n-100);
  color: var(--n-600);
}
/* 商品狀態等級保留黃／綠語意，但降飽和度 */
.card-seller .risk-tag.warn { background: var(--a-400); color: #fff; }
.card-seller .risk-tag.good { background: var(--t-600); }
/* 距離、主要操作維持品牌藍（.card-dist 既有設定即是，不改） */

/* ---------- 6. 商品 Grid ---------- */
/* 一排固定 4 個，間距統一；窄螢幕才遞減 */
.web-shell .product-grid {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px;
  align-items: stretch;
  /* 每一列都取最高的那張為準，否則只有「同一列」等高，
     列與列之間仍會差幾十 px，整片看起來還是不齊。 */
  grid-auto-rows: 1fr;
}
/* 每張卡等高：圖片列自動、內文列吃滿，賣家那行推到底部，
   文字起始位置與卡片高度才會整齊。
   :not(.fav-btn) 是必要的——愛心也是 .product-card 的直接子 button，
   沒排除掉會被 height:100% 拉成整張卡高，♡ 就垂直置中掉到卡片中間。 */
.web-shell .product-card > button:not(.fav-btn),
.web-shell .product-card > .product-link {
  grid-template-rows: auto 1fr;
  height: 100%;
}
.web-shell .product-body { align-content: start; }
.web-shell .card-seller { margin-top: auto; }

/* 左側篩選欄與商品第一欄切齊 */
.home-web-layout > .filter-rail,
.home-web-layout > .product-grid { margin-top: 0; }

@media (max-width: 1180px) {
  .web-shell .product-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 860px) {
  .web-shell .product-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---------- 稱號圖示改用畫好的圖（2026-09-04）---------- */
/* 這版圖示是去背的純物件（皇冠、椰子樹、閃電…），沒有自帶圓框，
   所以保留 .badge-icon-only 原本的米色圓底與細框，圖放在圓裡面。
   內距讓圖不要頂到圓邊；object-fit:contain 保持原比例不裁切
   —— 皇冠是寬的、閃電是窄的，用 cover 會把它們切掉。 */
/* Ann 決定：稱號不要圓圈框。圖本身是去背的，直接放在卡片上，
   不套底色也不套邊框。
   .is-negative 也要一起蓋掉——它另外設了自己的底色與框色，
   只蓋 .has-img 的話遲到鬼那顆會單獨留著一圈橘框。 */
.badge-icon-only.has-img,
.badge-icon-only.has-img.is-negative {
  /* 22 → 18px（Ann 要求再小一點）。沒有圓框之後圖是直接裸露的，
     視覺上比包在框裡時大一號，所以縮小才跟旁邊的文字配得起來。 */
  width: 18px;
  height: 18px;
  padding: 0;
  background: transparent;
  border: 0;
}
.badge-icon-only.has-img img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
/* 守護者（盾牌）是實心的一整塊：外框跟其他圖一樣大，但塗色面積 7855px²，
   皇冠只有 5086、遲到鬼 6826，縮到同尺寸後盾牌看起來大一號（Ann 2026-09-14 回報）。
   只縮這一張，不改圖檔。 */
.badge-icon-only.has-img img[src$="guardian.png"],
.badge-tag-img[src$="guardian.png"] {
  transform: scale(.85);
}

/* 帶名稱的稱號標籤裡，圖要跟文字對齊 */
.badge-tag-img {
  width: 16px;
  height: 16px;
  object-fit: contain;
  vertical-align: -3px;
}

/* ---------- 禮物／收藏改用 SVG 後的對齊（2026-09-04）---------- */
/* .fav-toggle 原本靠文字字元 ♡ 自然跟文字排在一起，不需要 flex；
   換成 SVG 之後就要明確對齊，參數跟隔壁的 .gift-toggle 對齊，
   兩顆按鈕才會真的一致。 */
.fav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.gift-toggle svg,
.fav-toggle svg,
.fav-btn svg { flex: none; }

/* 商品卡右上角那顆愛心比工具列的大一點，維持原本的視覺份量 */
.product-card .fav-btn svg { width: 18px; height: 18px; }

/* 本機版本標記：只有 localhost 會由 app.js 產生這個節點。
   存在的理由是「改了卻看不到」時，從截圖就能判斷對方拿到哪一版 CSS。 */
.build-stamp {
  flex: 0 0 auto;
  padding: 2px 7px;
  border: 1px solid var(--n-300);
  border-radius: var(--r-pill);
  background: var(--n-100);
  color: var(--n-600);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .02em;
}

/* ============================================================
   聊天室標題列的窄螢幕版面
   .chat-modal-meta 原本是 flex 但沒有 flex-wrap，項目只能被壓縮，
   壓到低於內容寬度時中文就變成一個字一行。加了「查看商品」之後
   這一列剛好越過臨界點，整塊爆掉。
   ============================================================ */
.chat-modal-meta { flex-wrap: wrap; }
/* 「與 ○○ 約定面交」自己佔一行，不跟按鈕搶寬度 */
.chat-modal-meta > p {
  flex: 1 1 100%;
  margin: 0;
  min-width: 0;
}
.chat-modal-meta > .pill,
.chat-modal-meta > .badge-icons,
.chat-modal-meta > button {
  flex: 0 0 auto;
  white-space: nowrap;
}

@media (max-width: 620px) {
  /* 只有對話的標題（商品資訊＋完成交易／檢舉／關閉一整排）要分兩行，橫向才不會互相擠壓。
     原本寫成所有 .modal-head 都單欄，連只有「標題＋✕」的彈窗（上架提醒、確認視窗）
     ✕ 都掉到標題下面（Ann 回報）。其他彈窗維持兩欄，✕ 留在右上角、跟標題頂端對齊。 */
  .modal-head:has(.chat-head-actions) {
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
  }
  .modal-head { align-items: start; }
  .chat-head-actions { justify-content: flex-end; }
  .chat-modal-product { grid-template-columns: 48px minmax(0, 1fr); gap: 12px; }
  .chat-modal-thumb { width: 48px; }
}

/* ============================================================
   來源商品浮卡
   從「你曾經跟他聊天過」點進舊對話後，那段對話講的是別件東西。
   把原本在看的商品縮成小卡釘在右下角，才回得去。
   用 fixed 是因為聊天室在手機版是彈窗、桌機版是右欄，
   兩種容器的定位脈絡不同，貼著視窗右下角才兩邊都對。
   ============================================================ */
.origin-product {
  position: fixed;
  right: 16px;
  /* 墊高避開輸入框與手機版底部導覽列 */
  bottom: calc(88px + env(safe-area-inset-bottom, 0px));
  z-index: 60;
  display: flex;
  align-items: stretch;
  max-width: min(430px, calc(100vw - 32px));
  border: 1px solid var(--n-300);
  border-radius: var(--r-sm);
  background: var(--n-000);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.origin-product-main {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
  padding: 14px 16px;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
}
.origin-product-main:hover { background: var(--n-100); }
.origin-product-thumb {
  width: 68px;
  height: 68px;
  flex: 0 0 auto;
  border-radius: 12px;
  background: var(--n-100);
  object-fit: cover;
}
.origin-product-copy {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.origin-product-kicker {
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
}
.origin-product-copy strong {
  overflow: hidden;
  font-size: 18px;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink);
}
.origin-product-price {
  color: var(--brand-strong);
  font-size: 17px;
  font-weight: 800;
}
/* 免費贈送用珊瑚色，跟站上其他地方一致（Ann 指定要跟一般價格分開） */
.origin-product-price.is-gift { color: var(--danger); }
.origin-product-close {
  display: grid;
  place-items: center;
  width: 48px;
  flex: 0 0 auto;
  border: 0;
  border-left: 1px solid var(--n-200);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.origin-product-close:hover { background: var(--n-100); color: var(--ink); }
.origin-product-close svg { width: 20px; height: 20px; }

@media (max-width: 620px) {
  .origin-product {
    right: 12px;
    bottom: calc(140px + env(safe-area-inset-bottom, 0px));
    max-width: calc(100vw - 24px);
  }
}

/* 聊天列表的每一列本來就擠（縮圖＋標題＋預覽＋時間），
   標籤與稱號用全站的 26px 會太搶。這裡縮一階，
   但兩者仍然等高——縮的是尺寸，不是一致性。 */
.chat-panel .pill {
  min-height: 20px;
  padding: 0 7px;
  font-size: 10.5px;
  gap: 3px;
}
.chat-panel .badge-tag { padding-inline: 7px; }
.chat-panel .badge-tag-img { width: 13px; height: 13px; }

/* 表格裡「文字 + 按鈕」同一格的對齊。
   <td> 是 display: table-cell，不能直接改成 flex（欄寬會壞掉），
   所以在裡面包一層 .cell-actions。
   原本的問題：那格是 vertical-align: top，文字行高 19px、按鈕 34px，
   兩者靠上對齊就會看起來歪，而且整列被撐成 66px（其他列 56px）。 */
.cell-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

/* 表單型的動作列（取消 + 主要動作）。
   .detail-action-bar 原本是為商品頁設計的三欄（1fr auto auto），
   套到只有兩顆按鈕的表單時，「取消」會掉進那個 1fr 而撐滿整條，
   主要動作反而被擠成最窄——輕重剛好相反。
   這裡改成「取消照內容寬、主要動作吃掉剩下」。 */
.form-action-bar {
  grid-template-columns: auto minmax(0, 1fr);
}
.form-action-bar > .ghost-button {
  padding-inline: 24px;
}
@media (max-width: 480px) {
  /* 窄螢幕改上下排，主要動作在上面比較好按 */
  .form-action-bar {
    grid-template-columns: minmax(0, 1fr);
  }
  .form-action-bar > .ghost-button { order: 2; }
}

/* Leaflet 的縮放鈕預設 30×30，手機上偏小（Apple 的建議是 44×44）。
   套件自己的 CSS 從 unpkg 載入，不能直接改，所以在這裡覆蓋。
   只在觸控裝置放大——滑鼠使用者 30px 本來就夠準。 */
@media (hover: none) and (pointer: coarse) {
  .leaflet-control-zoom-in,
  .leaflet-control-zoom-out {
    width: 44px;
    height: 44px;
    line-height: 44px;
    font-size: 22px;
  }
}

/* 賣家檔案的幾個數字（成交／被檢舉／上架／加入）。
   原本每個都做成膠囊，其中「被檢舉」還加了橘底特別標出來——但這些是
   中性的事實敘述，不是狀態標籤。做成膠囊會跟旁邊真正有語意的
   狀態標籤與稱號搶同一種視覺語言，橘底更是把一個中性數字講成警告。
   改成一句一般文字，用「·」分隔。 */
.seller-facts {
  flex: 1 1 100%;
  color: var(--muted);
  font-size: var(--caption);
  line-height: 1.7;
}

/* 聊天室標題列的「與 ○○ 約定面交」是進賣家檔案的入口。
   長得像一般文字（原本就是），但要看得出可點：滑過去加底線。 */
.chat-other-link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.chat-other-link:hover,
.chat-other-link:focus-visible { color: var(--brand-strong); text-decoration: underline; }

/* ===== App 版手感（Ann 2026-09-15：「使用的觸感可以再流暢一點」）=====
   全部掛在 html.surface-app 底下（app.js markAppLayer 只在 App 版加），網站版完全不受影響。 */

/* 1. 點擊：拿掉點下去那塊灰色閃爍、雙擊放大的等待；按鈕和卡片長按不要選到字 */
html.surface-app { -webkit-tap-highlight-color: transparent; overscroll-behavior-y: none; }
html.surface-app a,
html.surface-app button,
html.surface-app label,
html.surface-app summary,
html.surface-app [role="button"] { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
html.surface-app button,
html.surface-app .product-link { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }

/* 2. 捲動：蓋著彈窗／詳情／對話／搜尋頁／抽屜時，後面那頁鎖住；
      裡面的清單捲到底不要把力道傳出去帶著別的東西彈 */
html.surface-app.app-layer-open { overflow: hidden; }
html.surface-app .modal-card,
html.surface-app .product-detail-layout,
html.surface-app .messages,
html.surface-app .search-screen-body,
html.surface-app .category-drawer-list { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }

/* 3. 按下態：手指按住就看得到反應（hover 在觸控上會「黏住」，所以卡片的浮起效果在 App 版拿掉）
      依規範：按下一律比底色更深；實心鈕疊 --press；淺色列用 --n-200（hover 是 --n-100） */
html.surface-app .product-card:hover,
html.surface-app .product-card:focus-within {
  transform: none;
  box-shadow: 0 1px 3px rgba(32, 37, 39, .06), 0 1px 2px rgba(32, 37, 39, .04);
}
html.surface-app .product-card { transition: transform .14s ease, box-shadow .14s ease; }
html.surface-app .product-card:has(.product-link:active) { transform: scale(.97); }
html.surface-app .fav-btn svg { transition: transform .12s ease; }
html.surface-app .fav-btn:active svg { transform: scale(.82); }
html.surface-app .nav button[data-route] .nav-ico { transition: transform .12s ease; }
html.surface-app .nav button[data-route]:active .nav-ico { transform: scale(.86); }
html.surface-app .chat-panel .chat-list-item:active,
html.surface-app .notification-item:active,
html.surface-app .listing-row:active,
html.surface-app .search-back:active,
html.surface-app .chat-back:active,
html.surface-app .category-menu-btn:active,
html.surface-app .recent-chip:active,
html.surface-app .recent-clear:active { background: var(--n-200); }
html.surface-app .category-drawer-list > .cat-chip:not(.active):active { background: var(--n-200); }
html.surface-app .primary-button:active,
html.surface-app .blue-button:active,
html.surface-app .danger-button:active,
html.surface-app .warn-button:active,
html.surface-app .search-go:active { background-image: var(--press); }
html.surface-app .view-switch-btn:active,
html.surface-app .locate-chip:active,
html.surface-app .gift-toggle:active,
html.surface-app .fav-toggle:active { transform: scale(.96); }
html.surface-app .view-switch-btn,
html.surface-app .locate-chip,
html.surface-app .gift-toggle,
html.surface-app .fav-toggle { transition: transform .12s ease, background-color .16s ease, color .16s ease; }

/* 收藏成功「彈一下」（只換愛心不整頁重畫時才會加 .fav-pop） */
@keyframes app-fav-pop { 0% { transform: scale(1); } 40% { transform: scale(1.28); } 100% { transform: scale(1); } }
html.surface-app .fav-btn.fav-pop svg { animation: app-fav-pop .32s cubic-bezier(.2, .8, .2, 1); }

/* 4. 進場轉場：只在剛出現那一次播（app.js 加 .app-enter），整頁重畫不會重播
      彈窗／商品詳情：背景淡入、卡片從下方浮上；全螢幕對話：從右邊推進來；搜尋頁：淡入、內容微浮上 */
@keyframes app-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes app-rise-in { from { opacity: 0; transform: translateY(20px) scale(.98); } to { opacity: 1; transform: none; } }
@keyframes app-push-in { from { opacity: .4; transform: translateX(40%); } to { opacity: 1; transform: none; } }
html.surface-app .modal-backdrop.app-enter { animation: app-fade-in .18s ease-out; }
html.surface-app .modal-backdrop.app-enter > .modal-card { animation: app-rise-in .26s cubic-bezier(.2, .8, .2, 1); }
html.surface-app .modal-backdrop.chat-fullscreen.app-enter { animation: none; }
html.surface-app .modal-backdrop.chat-fullscreen.app-enter > .chat-modal-card { animation: app-push-in .24s cubic-bezier(.2, .8, .2, 1); }
html.surface-app .search-screen.app-enter { animation: app-fade-in .16s ease-out; }
html.surface-app .search-screen.app-enter .search-screen-body { animation: app-rise-in .22s cubic-bezier(.2, .8, .2, 1); }

@media (prefers-reduced-motion: reduce) {
  html.surface-app .app-enter,
  html.surface-app .app-enter > .modal-card,
  html.surface-app .app-enter .search-screen-body,
  html.surface-app .fav-btn.fav-pop svg { animation: none !important; }
  html.surface-app .product-card,
  html.surface-app .fav-btn svg,
  html.surface-app .nav button[data-route] .nav-ico { transition: none; }
  html.surface-app .product-card:has(.product-link:active),
  html.surface-app .fav-btn:active svg,
  html.surface-app .nav button[data-route]:active .nav-ico,
  html.surface-app .view-switch-btn:active,
  html.surface-app .locate-chip:active,
  html.surface-app .gift-toggle:active,
  html.surface-app .fav-toggle:active { transform: none; }
}

/* 檢舉的補充內容（Ann：描述很多會怎麼呈現——實測 500 字卡片高 1066px、字擠在右半邊）。
   長文先顯示 3 行，按「看全文」展開；手機卡片裡這一行改成欄名在上、內容在下靠左，整張卡寬都拿來放字。 */
.report-note {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  white-space: pre-line;
}
.report-note-cell.is-open .report-note { display: block; -webkit-line-clamp: unset; }
.note-more {
  padding: 0;
  border: 0;
  background: none;
  color: var(--c-600);
  font-size: var(--caption);
  font-weight: 800;
  cursor: pointer;
}
.note-more:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
@media (max-width: 768px) {
  .table-wrap td.report-note-cell { flex-direction: column; align-items: stretch; gap: 6px; text-align: left; }
  .table-wrap td.report-note-cell > .cell-value { display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-start; }
}

/* ===== App 版聊天標題第二版（Ann：「最上面這個很亂」、「排版怪怪的」）=====
   原本 ←、商品圖、名稱、與 xxx、信用標籤、四個稱號標籤擠在同一格裡換成三四行，檢舉還自己佔一行。
   改成一般聊天 App 的兩條，每條都只有一行：
     第一條 .chat-app-head：← ｜ 對方帳號＋信用標籤＋稱號小圖示 ｜ 檢舉
     第二條 .chat-app-product：商品圖＋名稱／價格 ｜ 完成交易（賣家才有）
   選擇器掛 .chat-app-head，高過前面 .chat-fullscreen .chat-modal-card .modal-head 那組三欄格線。 */
.chat-fullscreen .chat-modal-card .modal-head.chat-app-head {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0;
  padding: 0 0 8px;
  border-bottom: 0;
}
.chat-app-head .chat-back { flex: none; margin-left: -10px; }
.chat-app-who {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: 8px;
  min-width: 0;
  overflow: hidden;
}
.chat-app-account {
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 17px;
  font-weight: 800;
  cursor: pointer;
}
.chat-app-account:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 4px; }
.chat-app-who .pill { flex: none; white-space: nowrap; }
.chat-app-who .badge-icons { flex: none; }
.chat-fullscreen .chat-app-head .chat-report {
  flex: none;
  min-height: 32px;
  padding: 0 12px;
  font-size: var(--caption);
}
.chat-app-product {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-soft);
}
.chat-app-product-main {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: 10px;
  min-width: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
div.chat-app-product-main { cursor: default; }
.chat-app-thumb { flex: none; width: 40px; height: 40px; border-radius: 8px; object-fit: cover; }
.chat-app-product-copy { display: grid; gap: 1px; min-width: 0; }
.chat-app-product-name,
.chat-app-product-price { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-app-product-name { font-size: var(--caption); font-weight: 800; color: var(--ink); }
.chat-app-product-price { font-size: var(--tiny); color: var(--muted); }
.chat-app-product .chat-done-button { flex: none; min-height: 34px; padding: 0 14px; font-size: var(--caption); }

/* 客服信件（Ann：寄信給客服改成視窗直接送出、像檢舉一樣看得到回覆）
   「我的 → 聯繫客服」底下的紀錄沿用 .table-wrap（手機一筆一張卡）；狀態用小標籤分待回覆／已回覆。 */
.support-list-title { margin: 8px 0 0; font-size: 15px; }
.support-status {
  display: inline-block;
  padding: 2px 10px;
  border-radius: var(--r-pill);
  background: var(--o-050);
  color: var(--o-800);
  font-size: var(--tiny);
  font-weight: 800;
  white-space: nowrap;
}
.support-status.is-replied { background: #e3f1ee; color: var(--t-800); }
.support-reply-input { width: 100%; min-width: 180px; min-height: 72px; padding: 8px 10px; }

/* 網站版聊天標題：商品圖與名稱可以點開商品（跟 App 版同步）。外觀維持原樣，只加游標與滑過底線。 */
.chat-thumb-link,
.chat-title-link {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.chat-thumb-link { display: block; border-radius: var(--r-sm); }
.chat-title-link:hover { text-decoration: underline; }
.chat-thumb-link:focus-visible,
.chat-title-link:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* 清單／地圖切換：選到哪邊要一眼看得出來（Ann：「變色感覺不明顯，我會不知道我在哪」）。
   原因：App 版外框底色改成白（見 html.surface-app .hero-actions .view-switch），滑塊也是白 → 滑塊等於隱形，
   只剩文字從近黑變深藍，差異太小。
   改成：滑塊實心深藍、選到的字與圖示白色；沒選的字灰。網站與 App 共用。 */
.view-switch::before { background: var(--brand-strong); box-shadow: 0 2px 6px rgba(13, 96, 124, .28); }
.view-switch-btn { color: var(--muted); }
.view-switch-btn:hover { color: var(--brand-strong); }
.view-switch-btn.active,
.view-switch-btn.active:hover { color: #fff; }

/* App 聊天標題的稱號小圖示：點一下浮出說明小視窗（Ann）。
   按鈕外觀跟原本的小圖示一模一樣；18px 太小不好點，用透明 ::after 把可點範圍往外撐。 */
.badge-tip-btn { position: relative; margin: 0; color: inherit; font: inherit; cursor: pointer; }
.badge-tip-btn::after { content: ""; position: absolute; inset: -9px -5px; }
.badge-tip-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 50%; }
.chat-fullscreen .chat-modal-card .modal-head.chat-app-head { position: relative; }
.badge-tip {
  position: absolute;
  top: calc(100% - 2px);
  z-index: 20;
  display: grid;
  gap: 4px;
  width: min(260px, 100%);
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--n-000);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .14);
  color: var(--ink);
  font-size: var(--caption);
  line-height: 1.5;
  text-align: left;
  animation: badge-tip-in .14s ease-out;
}
.badge-tip::before {
  content: "";
  position: absolute;
  top: -6px;
  left: calc(var(--arrow-x, 24px) - 5px);
  width: 10px;
  height: 10px;
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
  background: var(--n-000);
  transform: rotate(45deg);
}
.badge-tip-title { display: flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 800; }
.badge-tip-title .badge-tag-img { width: 20px; height: 20px; }
.badge-tip.is-negative .badge-tip-title { color: var(--o-800); }
@keyframes badge-tip-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .badge-tip { animation: none; } }

/* 加到主畫面的提示。只在手機版面、首頁、還沒安裝、也還沒按過「知道了」時出現。
   導覽列那顆「安裝 App」按鈕在手機尺寸是隱藏的（底部導覽塞不下），這條是它在手機上的替代。 */
.install-hint {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 14px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--n-000);
}
.install-hint-copy { display: flex; flex-direction: column; gap: 3px; flex: 1 1 200px; }
.install-hint-copy strong { font-size: 14px; }
.install-hint-copy span { font-size: 13px; line-height: 1.6; opacity: 0.75; }
.install-hint-actions { display: flex; gap: 8px; flex-shrink: 0; }

/* 後台商品詳情：看清楚「這件商品哪裡有問題」再決定要不要下架 */
.admin-detail {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: 20px;
  padding: 14px 4px 18px;
  text-align: left;
}
.admin-detail h4 { margin: 0 0 8px; font-size: 14px; }
.admin-detail-main h4:not(:first-child),
.admin-detail-side h4:not(:first-child) { margin-top: 16px; }
.admin-detail-photos { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.admin-detail-photo { width: 92px; height: 92px; object-fit: cover; border-radius: 10px; border: 1px solid var(--line); }
.admin-detail-desc { white-space: pre-wrap; line-height: 1.7; margin: 0 0 8px; }
.risk-flags { margin: 0; padding-left: 18px; line-height: 1.8; }
.risk-flags li { color: var(--o-800, #9a3412); }
.admin-report-card { border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; margin-bottom: 10px; }
.admin-report-card.is-pending { border-color: var(--brand); }
.admin-report-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 6px; }
.admin-detail-row > td { background: var(--n-000); }
.report-count.is-pending { font-weight: 700; color: var(--brand-strong, var(--brand)); }
@media (max-width: 900px) {
  .admin-detail { grid-template-columns: 1fr; }
}

.report-risk {
  margin: 6px 0;
  padding: 6px 10px;
  border-radius: 8px;
  background: var(--o-050, #fff4ed);
  color: var(--o-800, #9a3412);
  font-size: 13px;
  line-height: 1.6;
}

/* 後台：檢舉分頁的商品／帳號切換，與商品列表上的小標記 */
.report-kind-switch { display: flex; gap: 8px; margin: 0 0 14px; flex-wrap: wrap; }
.report-flag {
  display: inline-block;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 12px;
  white-space: nowrap;
}
.report-flag.is-pending { border-color: var(--brand); color: var(--brand-strong, var(--brand)); font-weight: 700; }
.detail-report-hint { margin-top: 14px; font-size: 13px; line-height: 1.7; opacity: .8; }
tr.is-pending > td { background: var(--n-000); }

/* ============================================================
   訪客模式（Ann 2026-09-16）：沒登入點進商品，內容整片馬賽克
   遮罩是呈現方式，不是安全機制——敏感欄位根本沒傳到訪客瀏覽器。
   ============================================================ */
.nav-login-button {
  background: var(--brand);
  color: #fff;
  border-color: var(--brand);
  font-weight: 700;
}
.guest-browse-link { display: block; margin: 14px auto 0; }

.guest-detail-body { position: relative; }
.guest-detail-blur {
  filter: blur(14px) saturate(.7);
  opacity: .55;
  pointer-events: none;
  user-select: none;
  max-height: 60vh;
  overflow: hidden;
  padding: 16px;
}
/* 手機上模糊半徑要小一點，不然整片糊成一團看不出是商品 */
@media (max-width: 900px) {
  .guest-detail-blur { filter: blur(10px) saturate(.7); max-height: 55vh; }
}
.guest-detail-gate {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  padding: 24px;
  background: color-mix(in srgb, var(--n-000, #fff) 72%, transparent);
}
.guest-gate-title { margin: 0; font-size: 18px; font-weight: 800; }
.guest-gate-sub { margin: 0; font-size: 14px; line-height: 1.7; opacity: .75; max-width: 22em; }
.guest-detail-gate .primary-button { margin-top: 6px; }
