@charset "UTF-8";
/* ============================================
   攤位卡片元件樣式
   依賴字體：Noto Serif TC / Work Sans / JetBrains Mono
   若 index.html 尚未引入，請在 <head> 加上：
   <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+TC:wght@600;900&family=Work+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
   ============================================ */

:root {
  --nm-night: #17130f;
  --nm-lantern: #d6472e;
  --nm-lantern-deep: #9c2f1b;
  --nm-gold: #e8b23c;
  --nm-paper: #f4ead3;
  --nm-paper-dim: #e6d8b8;
  --nm-ink: #2a2016;
  --nm-ink-soft: #6b5d47;
}

/* ---------- Modal ---------- */
.backdrop {
  position: fixed;
  inset: 0;
  background: rgba(8, 6, 4, 0.72);
  backdrop-filter: blur(3px);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 20px;
}
.backdrop.show {
  display: flex;
}

/* 開啟：淡入+卡片本身輕微往上滑；關閉對稱淡出+往下滑，跟彈窗系統
   （style/main.css的.modal-overlay）同一套動畫語言。關閉動畫靠
   js/stall-card.js的hideCard()加.closing class、動畫跑完才真的清空
   DOM，不是瞬間消失 */
@keyframes card-backdrop-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes card-fade-in {
  from { transform: translateY(24px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
.backdrop.show {
  animation: card-backdrop-fade-in 0.2s ease;
}
.backdrop.show .card {
  animation: card-fade-in 0.25s ease;
}
/* 上一攤/下一攤切換時（js/stall-card.js的renderCardShell()會多加這個
   class），整個卡片DOM還是會被重新建立一次，但這次不是「開啟卡片」
   這個動作本身，不該重播上面這組開場淡入動畫——不然每切換一次就會
   再淡入一次，疊加上左右滑動動畫，才是畫面看起來一直閃爍的真正原因 */
.backdrop.show.nav-swap,
.backdrop.show.nav-swap .card {
  animation: none;
}
@keyframes card-backdrop-fade-out {
  from { opacity: 1; }
  to { opacity: 0; }
}
@keyframes card-fade-out {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(24px); opacity: 0; }
}
.backdrop.closing {
  animation: card-backdrop-fade-out 0.2s ease forwards;
}
.backdrop.closing .card {
  animation: card-fade-out 0.2s ease forwards;
}

/* 手機版三張卡片（上一攤/目前/下一攤）疊在同一個空間裡，.card-stack
   負責原本.card要有的寬高限制，三張.card都改成絕對定位、疊滿整個
   .card-stack，實際露出哪一截／疊在誰上面完全靠transform（js/stall-card.js
   的applyIdleStackTransforms/bindTwoFingerSwipe）跟下面的z-index決定。
   桌機版只會渲染一張（見renderCardShell），效果等同以前只有.card本身 */
.card-stack {
  position: relative;
  width: 100%;
  max-width: 380px;
  height: 88vh;
  max-height: 88vh;
}
.card {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* 底色維持原本的--nm-paper，上面疊一層用feTurbulence產生的雜訊紋理
     （純CSS+SVG，不用另外準備圖片素材），opacity壓得很低（0.05）只是
     增加一點紙纖維的顆粒感，不會讓底色看起來髒或明顯變暗。SVG本身給
     明確的width/height（120px）＋下面明確的background-size，逼瀏覽器
     只在這個小尺寸內運算一次濾鏡、再平舖鋪滿整張卡片——沒有這兩個
     的話SVG會被拉伸成跟卡片一樣大（可能到6-700px高）才運算，濾鏡本身
     不便宜，卡片一大就會在切換/拖曳動畫時卡頓（實測踩到的真bug） */
  background-color: var(--nm-paper);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
  background-repeat: repeat;
  background-size: 120px 120px;
  border-radius: 18px;
  overflow: hidden;
  box-shadow: 0 30px 60px rgba(0, 0, 0, 0.5);
  /* 很淡的金色細框，呼應網站既有的燈籠金配色（跟.card-nav-arrow-shape、
     .stall-number-badge同一個--nm-gold），只是給卡片邊緣一點「被裝裱
     起來」的精緻感，透明度壓低不會搶走內容本身的視覺重點 */
  border: 1px solid rgba(232, 178, 60, 0.35);
  color: var(--nm-ink);
  overflow-y: auto;
  font-family: "Work Sans", "PingFang TC", "Microsoft JhengHei", sans-serif;
  /* 提示瀏覽器提前把每張卡片準備成獨立的合成層，兩指拖曳一開始就是
     GPU合成、不用等到第一次transform變化時才臨時升級圖層，降低手勢
     剛開始那一瞬間的頓挫感。filter也要列進來——待命卡片的亮度
     (brightness)會跟著拖曳即時變化，跟transform是同一組動畫節奏，
     沒列進來的話這部分變化不一定吃得到同樣的合成層優化 */
  will-change: transform, filter;
}
/* 目前這張永遠疊最上面，上一攤/下一攤都疊在它後面——兩者都只有在
   current自己滑開讓出空間時才會露出來（current同尺寸、完全不透明，
   光靠z-index差距就能讓兩張待命卡片平常只透出一小截邊緣，不會反過來
   蓋住current）。下一攤疊在上一攤前面（z-index較高）：兩者待命時都往
   右偏移，下一攤偏移量較小、離current較近，理論上會先被上一攤蓋住，
   這裡故意讓下一攤蓋回去，露出「下一攤在近層、上一攤在遠層」兩層
   分明的堆疊效果，不是疊成同一層看不出層次。完全不能被點擊/捲動，
   在被滑到、正式成為current之前只是純視覺預覽 */
.card-slot-current {
  z-index: 3;
}
.card-slot-next {
  z-index: 2;
}
.card-slot-prev {
  z-index: 1;
}
.card-slot-prev,
.card-slot-next {
  pointer-events: none;
  /* 待命中的卡片統一變暗一點，搭配current自己既有的.box-shadow自然
     疊上去，看起來像「藏在陰影裡、退到後面」，跟最前面清楚明亮的
     current做出區隔 */
  filter: brightness(0.82);
}

/* 圓角方形+立體感，跟照片左右箭頭同一套光澤陰影做法（都是疊在
   內容不固定的區域上的深色控制項），維持深色半透明，不管疊在照片
   還是畫面2的米色底上，對比度都夠 */
.card-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  border-radius: 10px;
  background: linear-gradient(180deg, rgba(70, 65, 58, 0.75) 0%, rgba(0, 0, 0, 0.55) 60%, rgba(0, 0, 0, 0.7) 100%);
  box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.35), inset 0 -2px 3px rgba(0, 0, 0, 0.35),
    0 3px 8px rgba(0, 0, 0, 0.4);
  color: #fff;
  border: none;
  font-size: 16px;
  cursor: pointer;
  z-index: 5;
  transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s ease;
}
.card-close:hover {
  background: linear-gradient(180deg, #e2624a 0%, var(--nm-lantern) 55%, #a8301c 100%);
  transform: scale(1.08);
}
.card-close:active {
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.5);
  transform: scale(0.92);
}

/* 上一攤/下一攤：只在桌機版顯示（手機版拿掉，跟照片區已經有的
   .photo-nav左右切換擠在一起、視覺上太吵）。按鈕本身（.card-nav-btn）
   只負責定位跟「點擊範圍」，本身透明無背景；實際看得到的箭頭造型
   是裡面的.card-nav-arrow-shape，用clip-path畫成有厚度的實心箭頭，
   不是細線字元，點擊範圍（按鈕本身56px）刻意比箭頭造型本身還大一圈，
   滑鼠不用完全對準箭頭尖端也點得到 */
.card-nav-btn {
  display: none;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 68px;
  height: 68px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  align-items: center;
  justify-content: center;
}
.card-nav-arrow-shape {
  display: block;
  width: 36px;
  height: 46px;
  /* 預設就是金色（跟收藏/按讚「已觸發」同一套配色），不是深色——深色
     疊在同樣偏暗的.backdrop上幾乎看不見，箭頭本來就該隨時看得清楚，
     不用等使用者滑過去或點下去才有顏色 */
  background: linear-gradient(180deg, #f3e0a8 0%, var(--nm-gold) 55%, #b58420 100%);
  filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.45));
  transition: transform 0.15s ease, background 0.15s ease, filter 0.15s ease;
}
/* 有厚度的箭頭造型：中間往內凹一個缺角，做出「兩道筆畫夾出一個尖角」
   的粗體箭頭感，跟細細的‹›字元不同，是紮實的實心色塊 */
.card-nav-arrow-left {
  clip-path: polygon(100% 15%, 45% 15%, 0% 50%, 45% 85%, 100% 85%, 55% 50%);
}
.card-nav-arrow-right {
  clip-path: polygon(0% 15%, 55% 15%, 100% 50%, 55% 85%, 0% 85%, 45% 50%);
}
.card-nav-btn-prev {
  left: 8px;
}
.card-nav-btn-next {
  right: 8px;
}
/* 箭頭下方的小字提示（「上一攤」/「下一攤」）：左右切換箭頭很容易被
   誤會成「看這攤的上一張/下一張照片」（圖庫、相簿最常見的用法），
   實際上是換到完全不同的攤位，加這行字提前講清楚，避免預期落差。
   絕對定位、脫離.card-nav-btn的flex排版，不會影響裡面箭頭造型本身
   置中的邏輯；文字用金色系但降低不透明度，明確是輔助說明、不跟
   箭頭本身搶視覺重量 */
.card-nav-label {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-top: 4px;
  font-size: 12px;
  white-space: nowrap;
  color: var(--nm-gold);
  opacity: 0.8;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
/* 桌機版：卡片本身固定600px寬（見下方 @media min-width:769px 的
   .card），跟.backdrop（整個瀏覽器視窗）比起來窄很多，箭頭改成跟著
   卡片本身的邊緣定位，不再是貼齊整個視窗邊緣，不然視窗越寬、箭頭跟
   卡片就離越遠。50%是視窗中心，600px卡片一半是300px，再加16px間距、
   68px是按鈕點擊範圍本身的寬度 */
@media (min-width: 769px) {
  .card-nav-btn {
    display: flex;
  }
  .card-nav-btn-prev {
    left: calc(50% - 300px - 16px - 68px);
  }
  .card-nav-btn-next {
    right: calc(50% - 300px - 16px - 68px);
  }
}
/* 滑過去：維持金色系但放大、加亮一點，屬於同一個顏色家族的強調，
   不换成另一個顏色（換色留給「點下去」那個更明確的動作用） */
.card-nav-btn:hover .card-nav-arrow-shape {
  filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.45)) brightness(1.12);
  transform: scale(1.1);
}
.card-nav-btn:active .card-nav-arrow-shape {
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
  transform: scale(0.9);
}
/* 切換動畫進行中：節流用。刻意不用pointer-events:none擋點擊——按鈕
   若整個失去互動性，滑鼠點擊會直接穿透按鈕落到底下的.backdrop，被
   誤判成「點擊遮罩要關閉卡片」（實測會發生的真bug）。改成按鈕維持
   可點擊，靠JS的navInProgress判斷來忽略這段期間的點擊，視覺上則換成
   燈籠紅（跟.card-close的hover同一套配色，這裡拿來表示「已經點下去、
   處理中」），跟預設的金色明確區分開來。只加在使用者實際點的那一顆
   上（見js/stall-card.js），另一顆維持原本金色不變——不是兩邊都變色 */
.card-nav-btn.nav-locked .card-nav-arrow-shape {
  background: linear-gradient(180deg, #e2624a 0%, var(--nm-lantern) 55%, #a8301c 100%);
  opacity: 0.9;
}
.card-nav-btn.nav-locked {
  cursor: default;
}
.card-nav-btn.nav-locked:hover .card-nav-arrow-shape {
  filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.45));
  transform: none;
}

/* 上一攤/下一攤的卡片切換動畫：新卡片跟舊卡片的視覺分身（.card-ghost，
   見js/stall-card.js的createCardGhost）各自往反方向飄動，兩者用同一份
   時間長度／速度曲線同時播放，是兩個連續動作同時發生，不是同一個
   東西中途瞬間跳位置。實際的transform/opacity/transition時間值都是
   JS直接寫inline style（CARD_NAV_TRANSITION_CSS等常數），這裡不重複
   定義一份，避免兩邊數字沒對齊；.card-ghost只負責「這是純視覺分身」
   該有的基本設定 */
.card-ghost {
  pointer-events: none;
}

/* 兩指滑動教學提示（js/stall-card.js的setupSwipeHint）：純文字、輕量、
   半透明微微閃爍（呼吸燈效果），不是整頁蓋黑那種強迫看的做法、也不用
   圖示——pointer-events:none讓使用者的手指可以直接穿過這層去操作
   底下的卡片，不會變成要先點掉才能滑動 */
.swipe-hint {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 6;
  opacity: 0;
  transition: opacity 0.4s ease;
}
.swipe-hint.show {
  animation: swipe-hint-pulse 1s ease-in-out infinite;
}
@keyframes swipe-hint-pulse {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}
.swipe-hint-text {
  display: inline-block;
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  text-align: center;
  white-space: nowrap;
  line-height: 1.5;
  /* 純文字疊在照片上，沒有底色框/光暈襯托，靠文字陰影確保在任何亮度的
     照片背景上都看得清楚，不會被淺色照片吃掉看不見 */
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7), 0 0 10px rgba(0, 0, 0, 0.45);
}
/* 保持一行不換行（white-space:nowrap）的代價：英文版文字（"Swipe with
   two fingers to switch stalls"）比中文版長很多，實測在370px以下的
   窄螢幕手機（例如320px的iPhone SE）寬度會超過卡片本身，被.card的
   overflow:hidden左右切掉；375px（iPhone標準寬度）以上實測是安全的，
   不用跟著縮小，斷點抓在370px、不是隨便抓寬一點，兩者都是實測量出來
   的數字，不是憑感覺 */
@media (max-width: 370px) {
  .swipe-hint-text {
    font-size: 13.5px;
  }
}

/* ---------- 兩畫面卡片結構 ----------
   桌機（預設）：純粹是DOM分層方式的改變，畫面上照樣是「照片 → 名稱 →
   詳細內容」由上到下一路排下去、單一捲動，跟改版前視覺一致，
   詳細資訊／返回這兩顆手機版才用得到的按鈕直接隱藏。
   手機（下面 @media）：兩個 .card-screen 左右並排成橫向滑動的兩畫面，
   詳見下方 mobile 區塊 */
.card-screen-photo {
  display: flex;
  flex-direction: column;
}
.photo-screen-footer {
  padding: 16px 20px 0;
  background: var(--nm-paper);
}
.btn-detail,
.card-back-btn,
.name-block-desktop,
.name-block-mobile-detail,
.mobile-detail-header-row {
  display: none;
}

.card-media {
  height: 180px;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--nm-lantern), var(--nm-lantern-deep));
  overflow: hidden;
}
/* 沒照片時的分類封面底色：偏離中心的柔和光暈（radial-gradient）取代
   死板的直線漸層，色系照分類換（跟地圖標記/攤位清單/分類標籤同一套
   顏色），沒有分類或找不到對照顏色時就用上面.card-media本身那組
   燈籠色當保底，不會沒有背景色可用。這層background只有在照片沒能
   顯示出來時看得到——有照片的話.card-photo-strip會整個蓋在上面 */
.card-media[data-category="savory"]      { background: radial-gradient(circle at 30% 25%, #f0805c 0%, #a83a1e 75%); }
.card-media[data-category="dessert"]     { background: radial-gradient(circle at 30% 25%, #ea85a8 0%, #a13a5c 75%); }
.card-media[data-category="drink"]       { background: radial-gradient(circle at 30% 25%, #7098d8 0%, #2a4f8f 75%); }
.card-media[data-category="clothing"]    { background: radial-gradient(circle at 30% 25%, #ad8ada 0%, #63408f 75%); }
.card-media[data-category="accessories"] { background: radial-gradient(circle at 30% 25%, #5cbf9f 0%, #1f6f56 75%); }
.card-media[data-category="toys_games"]  { background: radial-gradient(circle at 30% 25%, #7cbf7c 0%, #356f35 75%); }
.card-media[data-category="other"]       { background: radial-gradient(circle at 30% 25%, #c0b090 0%, #6f6048 75%); }
/* 多張候選照片(1~5)橫向排成一列，用瀏覽器原生捲動+snap左右滑動查看，
   不用JS自己刻輪播/圓點；讀取失敗的圖片會在js/stall-card.js裡自動
   從DOM移除，不會留下空白格 */
.card-photo-strip {
  position: absolute;
  inset: 0;
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}
/* 預設先隱藏，讀取成功（js/stall-card.js的<img onload>加上.photo-loaded）
   才顯示——不能等失敗了才移除，瀏覽器判定讀取失敗的當下就會先畫出
   原生的「圖片壞掉」小圖示＋alt文字，等JS的onerror把它移除中間會有
   一瞬間閃過那個壞圖示，尤其現在待命中的上一攤/下一攤也會提前載入
   照片，更容易被使用者看到。用visibility而不是display，失敗的圖片
   還沒被移除前也不會佔用/影響版面 */
.card-photo {
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  scroll-snap-align: start;
  visibility: hidden;
}
.card-photo.photo-loaded {
  visibility: visible;
}
/* 預設隱藏，全部候選照片都讀取失敗時才由JS顯示出來，避免一般情況
   （照片正常存在）短暫閃過分類佔位封面 */
/* 填滿整個.card-media(position:absolute; inset:0)，內容(emoji+分類標籤)
   靠flex置中——一定要填滿整個媒體區域，.no-photo-watermark角落浮水印
   才能相對於「整個封面」定位，而不是只相對於中間那一小坨emoji+標籤
   自己的範圍（曾經踩到的bug：浮水印疊在畫面正中央而不是角落） */
.no-photo-glyph {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 1;
  align-items: center;
  justify-content: center;
}
.no-photo-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.no-photo-emoji {
  font-size: 56px;
  line-height: 1;
  filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.3));
}
/* 分類文字標籤：直接借用攤位清單/搜尋結果那顆分類藥丸(.search-category-tag)
   的視覺語言（深色半透明底+白字），封面同時有顏色＋圖示＋文字三重提示 */
.no-photo-category-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: #fff;
  background: rgba(0, 0, 0, 0.28);
  padding: 4px 12px;
  border-radius: 20px;
}
/* 角落一顆很淡的燈籠浮水印：不管換到哪個分類色，都有這個統一的品牌
   識別元素，讓所有沒照片的封面看起來還是同一個網站的一部分，不會因為
   顏色分類換來換去而顯得七拼八湊。跟emoji/分類標籤是手足元素、共用
   .no-photo-glyph的display切換，不用另外處理顯示/隱藏 */
.no-photo-watermark {
  position: absolute;
  right: 14px;
  bottom: 10px;
  font-size: 40px;
  line-height: 1;
  opacity: 0.16;
  pointer-events: none;
}
/* 照片左右切換按鈕：預設隱藏，只有偵測到2張以上照片才由JS顯示出來
   （見js/stall-card.js的updatePhotoNavState），跟.card-close同一種
   半透明深色圓形風格，滑到底/滑到頭時自動變暗停用 */
/* 維持深色（疊在照片上，照片亮暗不一定，深色半透明才能在任何照片上
   都維持清楚對比，換成鮮豔色遇到相近色調的照片反而不明顯），厚度感
   借用跟.stall-browse-open同一套光澤陰影做法 */
.photo-nav {
  display: none;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: linear-gradient(180deg, rgba(70, 65, 58, 0.75) 0%, rgba(0, 0, 0, 0.55) 60%, rgba(0, 0, 0, 0.7) 100%);
  box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.35), inset 0 -2px 3px rgba(0, 0, 0, 0.35),
    0 3px 8px rgba(0, 0, 0, 0.4);
  color: #fff;
  border: none;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  align-items: center;
  justify-content: center;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.photo-nav-prev {
  left: 10px;
}
.photo-nav-next {
  right: 10px;
}
.photo-nav:hover {
  filter: brightness(1.2);
  transform: translateY(-50%) scale(1.08);
}
.photo-nav:active {
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.5);
  transform: translateY(-50%) scale(0.92);
}
.photo-nav:disabled {
  opacity: 0.35;
  cursor: default;
}
.badge-hot {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 2;
  background: var(--nm-gold);
  color: var(--nm-ink);
  font-size: 11px;
  font-weight: 700;
  padding: 5px 10px 5px 8px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 4px;
}

.card-body {
  /* 上方留白改由 .photo-screen-footer 提供（見上方兩畫面卡片結構），
     這裡不用再重複留一次，不然桌機版名稱下方會多一段空白 */
  padding: 0 20px 20px;
  /* 資訊欄是固定高度（見.card-screen-info），內容不夠長時（多數攤位
     資料還不齊全）用flex column + 下面.action-row的margin-top:auto，
     讓動作按鈕貼齊卡片底部，不會卡在短短幾行文字後面留一大片空白 */
  display: flex;
  flex-direction: column;
  min-height: 100%;
}

.name-block {
  margin-bottom: 12px;
}
/* 攤位編號：給遊客對照用（例如跟朋友回報「這攤是幾號」、跟現場QR碼/
   攤位牌對照），刻意做成低調的小藥丸標籤而不是大字報，不會搶走店名
   本身的視覺重點 */
.stall-number-badge {
  display: inline-block;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: var(--nm-lantern-deep);
  background: var(--nm-paper-dim);
  border: 1px solid var(--nm-gold);
  border-radius: 8px;
  padding: 3px 10px;
  margin-bottom: 6px;
}
.name-zh {
  font-family: "Noto Serif TC", serif;
  font-weight: 900;
  font-size: 23px;
  line-height: 1.25;
  margin: 0 0 2px;
  /* 攤位名稱套用漸層文字（這次對話討論，跟頂部logo/地圖告示牌同一
     個處理概念），這裡背景是淺色米白（跟其他兩處深色背景不同），
     用深墨到燈籠紅的漸層取代金黃色系，維持在淺底上的可讀對比，
     不加光暈——淺底加同色系光暈效果不明顯，反而容易變模糊 */
  background: linear-gradient(180deg, var(--nm-ink) 0%, var(--nm-lantern-deep) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.name-en {
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--nm-ink-soft);
  margin: 0;
}

/* 統一規格的區塊標題樣式：底下配一條固定同色的細線，讓「這是標題、
   不是內文」一眼就看得出來，所有區塊共用同一種樣式、同一個顏色，
   不是每個標籤各自配色 */
.tag-row-label {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--nm-ink);
  text-transform: uppercase;
  letter-spacing: 0.8px;
  margin: 0 0 8px;
  padding-bottom: 3px;
  border-bottom: 2px solid var(--nm-gold);
}
.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 14px;
}
/* 跟付款方式/辣度/素食標示同一種藥丸樣式（統一成同一套資訊型標籤的
   視覺語言，不要每種標籤各自一種底色），外送平台的彩色連結藥丸是
   刻意的例外（那個真的是可點擊的外部連結，性質不同） */
.sig-tag {
  background: var(--nm-paper-dim);
  border-radius: 20px;
  padding: 5px 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--nm-ink);
}

/* 營業資訊/付款方式/外送平台合併進同一個框框（.info-box），裡面用
   輕量的.info-row分行，取代原本三個各自獨立、各自有大標籤的區塊——
   減少「獨立區塊」數量，資訊份量也跟主要內容（招牌品項/介紹文字/
   老闆的話）明確分出主次 */
.info-box {
  background: var(--nm-paper-dim);
  border-radius: 10px;
  padding: 10px 12px;
  margin: 0 0 14px;
}
.info-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 7px 0;
}
.info-row + .info-row {
  border-top: 1px dashed rgba(0, 0, 0, 0.08);
}
.info-row-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--nm-ink-soft);
  flex: 0 0 auto;
}
/* 付款方式藥丸原本跟.info-box同一個米褐色，疊在一起會分不出界線，
   這裡框內的藥丸改白底，才看得出「這是一顆藥丸」而不是背景的一部分 */
.info-row .icon-pill:not(.icon-pill-link) {
  background: #fff;
}
/* 「多元行動支付」這種籠統標籤底下的細節說明——不是每攤都有，只有
   標籤概括了好幾種App時才需要，字級刻意比標籤小、顏色淡一點，
   不跟標籤本身搶視覺重點，但還是完整列出來，不是藏起來要點開才看得到 */
.payment-note {
  font-size: 11px;
  color: var(--nm-ink-soft);
  margin: -2px 0 0;
  padding: 0 0 7px;
  line-height: 1.5;
}
.meta-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}
.meta-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--nm-ink);
}
.meta-item .ic {
  font-size: 14px;
}
.meta-item .price {
  font-family: "JetBrains Mono", monospace;
  font-weight: 700;
  color: var(--nm-lantern-deep);
}

/* ---------- 訪客建議營業時間 ---------- */
/* 這次對話討論：使用者認為營業時間不該是price/closedDays那排裡的
   附屬品，要獨立出來才顯得重要——左側色條+比.meta-item大一號的
   圖示/字級，讓它讀起來是「這張卡片特別在意的一項資訊」，不是隨手
   列出的其中一條。有資料/沒資料兩種狀態刻意維持同樣的位置跟份量，
   不會因為沒資料就自動縮小——沒資料時只是虛線邀請樣式，字級/位置
   跟有資料時一致 */
.hours-block {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  margin: 0 0 14px;
  background: var(--nm-paper-dim);
  border-left: 4px solid var(--nm-lantern-deep);
  border-radius: 8px;
}
.hours-block .ic {
  font-size: 22px;
  flex-shrink: 0;
}
.hours-block-text {
  flex: 1;
  min-width: 0;
}
.hours-block-label {
  margin: 0 0 2px;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--nm-ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.6px;
}
.hours-block-value {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--nm-ink);
  font-family: "JetBrains Mono", monospace;
}
.hours-block.empty {
  background: transparent;
  border: 1.5px dashed var(--nm-lantern-deep);
  border-left: 1.5px dashed var(--nm-lantern-deep);
}
.hours-block.empty .hours-block-value {
  font-family: "Noto Serif TC", serif;
  font-size: 14px;
  font-weight: 700;
  color: var(--nm-lantern-deep);
}
.hours-block.empty .ic {
  opacity: 0.75;
}
.hours-block.cooldown {
  opacity: 0.6;
}
.hours-block.cooldown .hours-block-action {
  text-decoration: none;
  color: var(--nm-ink-soft);
}
/* 動作連結刻意比照Google地圖「提供營業時間修改建議」那種低調文字
   連結的做法（這次對話討論才確認的方向）：資料本身要顯眼，但編輯
   這個動作不搶戲，用青色小字連結，不是色塊按鈕 */
.hours-block-action.subtle {
  flex-shrink: 0;
  border: none;
  background: none;
  padding: 6px 4px;
  color: #0f7a6e;
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
.hours-block-action.subtle:active {
  opacity: 0.7;
}
.hours-success-text {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  color: var(--nm-ink);
}
.hours-success-sub {
  margin: 2px 0 0;
  font-size: 11px;
  font-weight: 400;
  color: var(--nm-ink-soft);
}

.hours-suggest-form {
  width: 100%;
}
.hours-suggest-label {
  margin: 0 0 8px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--nm-ink);
}
.hours-suggest-input {
  width: 100%;
  padding: 9px 10px;
  border: 1.5px solid var(--nm-lantern-deep);
  border-radius: 8px;
  background: var(--nm-paper);
  color: var(--nm-ink);
  font-size: 13px;
  font-family: "JetBrains Mono", monospace;
  margin: 0 0 6px;
}
.hours-suggest-input::placeholder {
  color: var(--nm-ink-soft);
  opacity: 0.6;
}
.hours-suggest-input.err {
  border-color: var(--nm-lantern);
}
.hours-suggest-error {
  margin: -2px 0 8px;
  font-size: 11px;
  color: var(--nm-lantern);
  font-weight: 700;
}
.hours-suggest-hint {
  margin: 0 0 10px;
  font-size: 11px;
  color: var(--nm-ink-soft);
  line-height: 1.5;
}
.hours-suggest-actions {
  display: flex;
  gap: 8px;
}
.hours-suggest-cancel,
.hours-suggest-submit {
  flex: 1;
  padding: 8px;
  border-radius: 8px;
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
  font-family: inherit;
}
.hours-suggest-cancel {
  border: 1.5px solid var(--nm-ink-soft);
  background: transparent;
  color: var(--nm-ink-soft);
}
.hours-suggest-submit {
  border: none;
  background: var(--nm-lantern-deep);
  color: var(--nm-paper);
}
.hours-suggest-submit:disabled,
.hours-suggest-cancel:disabled {
  opacity: 0.6;
  cursor: default;
}
/* 桌機版資訊欄實測發現的真問題（這次對話討論才抓到）：桌機卡片雖然
   放大到600px，但資訊欄只分到45%（270px），扣掉左右padding實際內容
   只有230px，比手機版整張卡的340px還窄——動作連結跟時間數字擠在
   同一行會把數字擠到自己先換行。改成這個寬度以下動作連結掉到
   label/value欄位下面自己一行，時間數字才能保證完整顯示在同一行 */
@media (min-width: 769px) {
  .hours-block {
    flex-wrap: wrap;
  }
  .hours-block-action {
    flex-basis: 100%;
    padding-left: 32px;
    margin-top: -2px;
    text-align: right;
  }
}

.desc {
  font-size: 13px;
  line-height: 1.6;
  color: #4a3d2a;
  margin: 0 0 14px;
}
.desc-estimated-note {
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--nm-ink-soft);
  font-style: italic;
  margin: -8px 0 14px;
}

/* 老闆自己的話：刻意跟上面的.desc（介紹文字，可能是概略推測內容）
   用視覺區隔開來，加個底色框，讓讀者知道這段是老闆本人的原話、不是
   網站整理的介紹；標籤文字統一搬到框外，跟其他區塊用同一套.tag-row-label */
.owner-words {
  background: var(--nm-paper-dim);
  border-radius: 10px;
  padding: 10px 12px;
  margin: 0 0 14px;
}

/* 網站站長的話（資料還在補齊中的說明），刻意跟老闆想說的話（實心底、
   斜體，比較像個人語氣的引言）做出區隔——用虛線框、不填滿底色、
   語氣也偏中性，讓人一眼分得出這不是攤位老闆本人講的話 */
.site-note {
  border: 1px dashed var(--nm-paper-dim);
  border-radius: 10px;
  padding: 10px 12px;
  margin: 0 0 14px;
}
.site-note-label {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--nm-ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin: 0 0 4px;
}
.site-note-text {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--nm-ink-soft);
  margin: 0;
}
.owner-words-text {
  font-size: 13px;
  line-height: 1.6;
  color: var(--nm-ink);
  font-style: italic;
  margin: 0;
}

.icon-row {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
  flex-wrap: wrap;
  align-items: center;
}
/* 圖示+文字放同一顆藥丸裡，跟辣度/素食標示同一種視覺語言，避免純圖示
   在手機上看不出意思（觸控裝置沒有滑鼠停留可以看title提示文字） */
.icon-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--nm-paper-dim);
  border-radius: 20px;
  padding: 5px 10px;
  font-size: 12px;
  color: var(--nm-ink);
}
/* 外送平台連結：用各平台官方品牌色當底色（不是重畫他們的商標圖案，
   只是借用顏色，讓人一眼認出是哪個平台），白字，跟付款方式的純資訊
   藥丸做出區隔（這個點下去會離開網站） */
.icon-pill-link {
  color: #fff;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: filter 0.15s ease;
}
.icon-pill-link:hover {
  filter: brightness(0.92);
}
.icon-pill-foodpanda {
  background: #d70f64;
}
.icon-pill-ubereats {
  background: #06c167;
}

.spicy-tag,
.veg-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--nm-paper-dim);
  border-radius: 20px;
  padding: 5px 10px;
  font-size: 12px;
  color: var(--nm-ink);
}
.spicy-tag {
  letter-spacing: 1px;
}
.spicy-label {
  font-size: 10.5px;
  color: var(--nm-ink-soft);
  letter-spacing: normal;
}
.veg-tag {
  background: #e3ead0;
}

.action-row {
  display: flex;
  justify-content: center;
  gap: 26px;
  /* 貼齊底部：資料少時靠上面.card-body的flex column撐到底；資料多、
     內容要捲動時改靠sticky，捲動中按鈕列還是黏在可視範圍最下面，
     不用捲到最底才按得到「收藏/按讚/地圖」 */
  margin-top: auto;
  position: sticky;
  bottom: 0;
  background: var(--nm-paper);
  padding: 12px 0 4px;
  box-shadow: 0 -8px 10px -8px rgba(0, 0, 0, 0.12);
}

/* 三顆動作按鈕統一改成「圓形圖示+小字說明」，取代原本兩顆實色長方形+
   一顆裸圖示的混搭，文字統一縮到2-4字，桌機版較窄的資訊欄也不會斷行。
   三個顏色刻意都用飽和實色（不用淡色調），維持原本按鈕該有的清楚對比度 */
.action-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font-family: "Work Sans", "PingFang TC", "Microsoft JhengHei", sans-serif;
}
.action-icon {
  width: 44px;
  height: 44px;
  border-radius: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 19px;
  /* 立體/有厚度的按鈕感，跟站內既有的.stall-browse-open同一套做法：
     上緣內陰影模擬打光、下緣內陰影模擬凹陷、外層陰影模擬懸浮厚度 */
  box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.5), inset 0 -3px 4px rgba(0, 0, 0, 0.25),
    0 4px 8px rgba(0, 0, 0, 0.35);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.action-label {
  font-size: 11px;
  font-weight: 700;
  color: var(--nm-ink);
  /* 數字本身固定預留寬度（最多抓3位數的空間），避免0→1→10→100
     這種位數變化時，版面跟著跳動 */
  min-width: 1.6em;
  text-align: center;
}

/* 點擊當下的回饋：縮小＋變暗一下再彈回，三顆按鈕統一都有，滑鼠/觸控都適用 */
/* 按下當下的回饋：改用「按鈕被壓下去」的立體感（內凹陰影+下移1px），
   跟.stall-browse-open同一套語言，比單純縮小更符合這裡要的「厚度」 */
.action-btn:active .action-icon {
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.35);
  transform: translateY(1px);
}

/* 地圖：本身是「做一次動作」不是開關，沒有天生的前/後兩種狀態，
   固定用燈籠紅、跟另外兩顆的「未觸發」色（米褐）明確不同 */
/* 三顆按鈕統一同一套顏色系統，不個別配色：地圖本身沒有「點過/沒點過」
   這種可以記錄的狀態（每次點都只是重新做同一件事），所以固定停在這個
   中性色；收藏／讚兩顆有真的狀態（有沒有收藏/讚過），觸發後統一變成
   同一種金色——三顆顏色一致，靠圖示+文字分辨功能，不是靠顏色分功能，
   避免每顆按鈕各自配色反而顯得亂 */
.action-btn-map .action-icon,
.action-btn-save .action-icon,
.action-btn-like .action-icon {
  background: linear-gradient(180deg, #f3e9d0 0%, var(--nm-paper-dim) 55%, #c9b98f 100%);
  color: var(--nm-ink);
}
.action-btn-map:hover .action-icon,
.action-btn-save:hover .action-icon,
.action-btn-like:hover .action-icon {
  background: linear-gradient(180deg, #e8dab4 0%, #dbcba1 55%, #b8a578 100%);
}
.action-btn-save.saved .action-icon,
.action-btn-like.liked .action-icon {
  background: linear-gradient(180deg, #f3c765 0%, var(--nm-gold) 55%, #b58420 100%);
  color: var(--nm-ink);
}
/* 按讚失敗（後端連不到）時短暫變色提示，1.5秒後 stall-card.js 會自動拿掉 */
.action-btn-like.like-failed .action-icon {
  background: linear-gradient(180deg, #e2624a 0%, var(--nm-lantern) 55%, #a8301c 100%);
  color: #fff;
}

/* 點擊當下的回饋：放大跳動一下再彈回，不管是按讚還是收回讚都會跑，
   stall-card.js 點擊時加上這個 class，動畫跑完（animationend）自動拿掉 */
@keyframes v6-like-bounce {
  0% { transform: scale(1); }
  35% { transform: scale(1.35); }
  60% { transform: scale(0.92); }
  80% { transform: scale(1.08); }
  100% { transform: scale(1); }
}
.action-btn-like.bouncing .action-icon {
  animation: v6-like-bounce 0.4s ease;
}

/* 手機置底彈窗風格（選用）：若希望手機上從底部滑出，取消下面註解 */
/*
@media (max-width: 480px) {
  .backdrop { align-items: flex-end; padding: 0; }
  .card { max-width: 100%; border-radius: 18px 18px 0 0; max-height: 85vh; }
}
*/

/* ---------- 手機版：兩畫面橫向滑動卡片 ----------
   解決照片被壓在固定180px小框裡、直式照片容易被裁切的問題：
   拿掉這裡的原因、改法討論見 memory project_planned_new_features。
   畫面1（照片+名稱+按鈕）／畫面2（其餘所有內容+動作按鈕）左右並排成
   200%寬的軌道，用 transform 橫向滑動切換，取代單頁上下捲動 */
@media (max-width: 768px) {
  .card-screen-track {
    display: flex;
    width: 200%;
    height: 100%;
    transition: transform 0.3s ease;
  }
  .card-screen-track.show-info {
    transform: translateX(-50%);
  }
  .card-screen {
    display: flex;
    flex-direction: column;
    width: 50%;
    flex: 0 0 50%;
    height: 100%;
    min-height: 0;
  }
  /* 照片畫面：照片盡量吃滿剩餘空間，底下名稱+按鈕維持自身內容高度，
     不用寫死70/30，兩塊各自撐開自然就接近這個比例 */
  .card-screen-photo .card-media {
    flex: 1 1 auto;
    min-height: 0;
    height: auto;
  }
  /* 詳細資訊畫面：內容如果比卡片高，自己捲動，不影響照片畫面 */
  .card-screen-info {
    overflow-y: auto;
  }

  .photo-screen-footer {
    padding: 16px 20px 18px;
  }

  .btn-detail {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    min-height: 46px;
    margin-top: 12px;
    border-radius: 14px;
    border: none;
    background: linear-gradient(180deg, #ec6b4a 0%, var(--nm-lantern) 50%, #a8301c 100%);
    box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.5), inset 0 -3px 4px rgba(0, 0, 0, 0.25),
      0 4px 10px rgba(0, 0, 0, 0.45);
    color: #fff;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s ease;
  }
  .btn-detail:active {
    box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.35);
    transform: translateY(1px);
    filter: brightness(0.85);
  }
  .btn-detail-arrow {
    font-size: 15px;
  }

  /* 返回鍵：主要靠手機返回鍵/手勢（BackButtonStack）操作，這顆是給不知道
     要用返回鍵的人一個看得到的退路，避免畫面2變成不知道怎麼離開的死路。
     跟編號徽章（見下面.mobile-detail-header-row）放同一排左右對齊，
     不要兩個藥丸形狀的東西直接上下疊在一起，那樣看起來會很像重複的
     兩個導覽元件 */
  .card-back-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--nm-paper-dim);
    border: none;
    border-radius: 20px;
    padding: 6px 14px 6px 10px;
    color: var(--nm-ink);
    font-size: 12.5px;
    font-weight: 700;
    cursor: pointer;
    transition: filter 0.15s ease;
  }
  .card-back-btn:active {
    filter: brightness(0.92);
  }
  .card-back-arrow {
    font-size: 14px;
  }

  .mobile-detail-header-row {
    display: flex;
    align-items: center;
    
    gap: 10px;
    margin: 14px 0 10px;
    /* 右側預留關閉鈕(.card-close，32px寬+right:12px)的空間，不然編號
       徽章會被蓋到（實測踩到的真bug，跟desktop版.name-block-desktop的
       padding-right是同一個道理） */
    padding-right: 46px;
  }
  /* 這顆編號徽章樣式跟.stall-number-badge共用，這裡只補位置需要的
     margin歸零（原本的樣式是設計給店名正下方那種上下排版用的） */
  .mobile-detail-badge {
    margin-bottom: 0;
    flex-shrink: 0;
  }

  /* 手機版詳細資訊畫面最上方（返回鍵那一排右側）補一份編號、店名下面
   * 補一份完整店名，畫面1的店名區塊滑到畫面2就看不到了，內容看久/
   * 捲久了容易忘記自己在看哪一攤，尤其現在有左右切換攤位功能後更需要
   * 隨時看得到。編號已經在上面那排顯示過了，這裡的.name-block自己的
   * 徽章要藏起來，不然同一個編號會重複出現兩次 */
  .name-block-mobile-detail {
    display: block;
    margin-bottom: 4px;
  }
  .name-block-mobile-detail .name-block {
    margin-bottom: 8px;
  }
  .name-block-mobile-detail .stall-number-badge {
    display: none;
  }
}

/* ---------- 桌機版：左照片右資訊的兩欄卡片 ----------
   跟手機版共用同一份 .card-screen-track / .card-screen-photo /
   .card-screen-info 結構，這裡改成左右並排（flex-direction:row）取代
   手機版的橫向滑動；.btn-detail / .card-back-btn 維持隱藏（見上方
   base規則），沒有畫面切換的概念，兩欄同時顯示 */
@media (min-width: 769px) {
  .card-stack {
    max-width: 600px;
  }
  .card-screen-track {
    display: flex;
    flex-direction: row;
    height: 100%;
  }
  .card-screen-photo {
    flex: 0 0 55%;
    width: 55%;
    height: 100%;
  }
  .card-screen-photo .card-media {
    height: 100%;
  }
  /* 名稱搬到右側資訊欄最上方顯示（.name-block-desktop），照片下面
     不再接名稱/按鈕，讓照片可以貼滿整欄高度 */
  .photo-screen-footer {
    display: none;
  }
  .card-screen-info {
    flex: 0 0 45%;
    width: 45%;
    height: 100%;
    overflow-y: auto;
  }
  .name-block-desktop {
    display: block;
    margin-top: 20px;
    /* 右側預留關閉鈕(.card-close，32px寬+right:12px)的空間，攤名文字
       提前換行、繞開右上角，不管名字多長、換成幾行都不會被蓋到，
       比把整塊往下推更能一次解決所有長度（實測踩到的真bug：長店名
       換兩行時，第二行最後一個字會被關閉鈕蓋住） */
    padding-right: 50px;
  }
}