/* 2026-08-24 骨架重構（v=20260823-7）：版面哲學改成 ChatGPT 的「一條置中對話欄 ＋ 可收合側欄 ＋ 可滑入畫布」。
   對話欄寬度由 --col 決定，空狀態、訊息流、輸入膠囊三者共用同一個寬度；行程與地圖從常駐右欄變成 body[data-canvas] 控制的畫布；
   對話紀錄、App 行程、開新對話與帳號從頂欄與抽屜全部搬進左側欄。元件本身（工作流、時間軸、地圖、彈層）逐字沿用，只是換了位置與寬度。 */
/* 旅尋網頁版智能體 — 2026-08-23 融合版：現行視覺 + 重設計的 UX 與頁面邏輯。
   使用者裁決（2026-08-23）：「融合重設計版的 UX 與頁面邏輯，UI 視覺保留現行版」。
   所以色票、字體、圓角、陰影、按鈕殼、訊息氣泡、執行過程軌道、App 式時間軸（檔尾 v2 區塊逐字沿用）全部是現行版；
   新的是版面邏輯：兩欄欄寬由任務階段驅動（body[data-phase]）、工作列計時與步數、步驟種類標籤、原位追問卡、
   寫入列跳站、抽屜雙分頁、衝突並排比較、手機三分頁、斷線細列。狀態一律掛在 body 的 data-* 上由 CSS 切版面。 */
/* 2026-08-25 視覺系統收斂（Wave B）：色票、字級、圓角、陰影收成一套可查的系統。
   --hint 從 #a8a29e 調深成 #8a8580：舊值對白底只有 2.52:1，19 處在用、含首屏最大那段 placeholder，
   使用者看不清楚自己還沒打字的那一格在寫什麼。新值 3.65:1，仍比 --muted（4.80:1）淺一階，層級沒有塌掉。
   --soft2 併掉 #efedeb 與 #e9e7e5 兩個肉眼分不出的淺灰（hover 底與選取底本來就該是同一個值）。
   --blue-mid 收掉手打六次的 #93c5fd（focus 框、連結卡 hover、地圖候選標記、圖例、版本比較欄、剛改過的站點）。
   --shadow-sm 給小型懸浮元件（工具列、下拉、提示浮層），--shadow-lg 給大型彈層（對話框、地點彈層、抽屜），
   原本每個地方各寫一組手調值，全檔數得出 30 種獨立配方。 */
:root{--ink:#1c1917;--ink2:#57534e;--muted:#78716c;--hint:#8a8580;--paper:#fafaf9;--card:#fff;--soft:#f5f5f4;--soft2:#eceae8;--line:#e7e5e4;--line2:#d6d3d1;--blue:#1d4ed8;--blue-soft:#dbeafe;--blue-mid:#93c5fd;--green:#15803d;--green-soft:#dcfce7;--red:#b91c1c;--red-soft:#fee2e2;--amber:#b45309;--amber-soft:#fef3c7;--shadow:0 12px 40px rgba(28,25,23,.10);--shadow-sm:0 4px 16px rgba(28,25,23,.10);--shadow-lg:0 24px 64px rgba(28,25,23,.22)}
/* --col 是對話欄的唯一寬度來源：空狀態、訊息流、狀態行與輸入膠囊全部讀它，
   四者才會永遠對齊在同一條 760px 的置中欄上。 */
/* 自訂屬性預設是「無型別的字串」，760px 換成 560px 時瀏覽器只會瞬間換值，中間沒有任何一格。
   評審量到的結果是畫布滑出去的 250ms 裡，膠囊先往右彈 100px 再往左走 286px——它跟著瞬跳的欄寬
   被推來推去。註冊成 <length> 之後 --col 自己就是可以內插的動畫屬性，兩邊才是同一件事一起走。
   不支援 @property 的瀏覽器會整條忽略，退回現在這種瞬跳，其餘行為不變。 */
@property --col{syntax:"<length>";inherits:true;initial-value:760px}
:root{--col:760px}
/* --tripw 是行程畫布的唯一寬度來源：畫布自己的寬、對話欄的右界、把手與底部工具列的右界全部讀它，
   兩邊才不會各算各的而互相蓋住（1024 寬時舊版的 44% 與 min-width:380px 會差出 44px 的重疊）。
   使用者拖動分隔軸時 JS 只覆寫這一個 inline 值，其餘位置自動跟上。 */
:root{--tripw:clamp(420px,52%,760px)}
/* --dockh 是底部工具列（分頁列、狀態列、提示行、輸入膠囊）的實際高度，由 JS 量完寫回來。
   對話欄與行程畫布用它把自己的下緣抬到工具列上方，內容才不會被壓在膠囊底下。 */
:root{--dockh:0px}
*{box-sizing:border-box}[hidden]{display:none!important}html{color-scheme:light;background:var(--paper)}
body{margin:0;color:var(--ink);background:var(--paper);font:500 14px/1.6 Inter,"Noto Sans TC","Microsoft JhengHei",system-ui,sans-serif;-webkit-font-smoothing:antialiased;overflow:hidden;height:100%;transition:--col .25s cubic-bezier(.4,0,.2,1)}
html{height:100%}
button,textarea,select{font:inherit}button,a{touch-action:manipulation}button{color:inherit;cursor:pointer}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* 鍵盤使用者按第一下 Tab 停在這裡，按下去直接跳進他真正要用的那個輸入框；滑鼠使用者永遠看不到它。 */
.skip-link{left:12px;top:12px;z-index:70}
.skip-link:focus{width:auto;height:auto;margin:0;padding:9px 14px;overflow:visible;clip:auto;border-radius:8px;background:var(--ink);color:#fff;font-size:13px;font-weight:700;text-decoration:none}
/* 時間軸的站點卡是 role="button" 的 <article>，不是 <button>，只認標籤名的舊選擇器讓鍵盤使用者
   逐站 Tab 時完全看不到焦點在哪。配方不動，只把選擇器擴到帶 role="button" 的節點。 */
button:focus-visible,a:focus-visible,textarea:focus-visible,select:focus-visible,[role="button"]:focus-visible,summary:focus-visible{outline:3px solid var(--blue-mid);outline-offset:3px}
.sprite{display:none}.num{font-variant-numeric:tabular-nums}
/* 2026-08-26 克制化（Wave E）：介面預設只有中性灰階，彩色收成三種用途——錯誤與警告用紅、
   需要立刻處理的狀況用琥珀、連結與鍵盤焦點用藍。步驟種類、寫入列、摘要卡、時間錨定、日分頁、
   營業中、地圖標記全部改成靠圖示、文字與字重區分，不再靠色相區分。
   字重上限降到 700（品牌字與點數大數字例外）、圓角收成 12／8／99 三階（99 只留真正的 chip）、
   圖示線寬降一階、最小字級提到 11px。理由是同一畫面上同時出現四個色系與大量 900 字重的小字，
   使用者的原話是「太花花綠綠」「太像幼兒版本」。 */
/* 線寬降一階（16px 圖示 1.75）：粗線條是幼兒感的第二個來源，第一個是大量的 900 字重小字。 */
svg.ic{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;flex:none}
svg.ic.fill{fill:currentColor;stroke:none}
/* 2026-08-24 骨架重構：最外層從「縱向殼」改成「左側欄 ＋ 右工作殼」的橫向兩件式。
   舊版側欄只是蓋在畫面上的抽屜，收合與否不影響版面；現在側欄是常駐版面的一部分，
   頂欄與工作台一起縮進 .shell，側欄收合時右邊會真的讓出寬度而不是被遮住。 */
.app{position:relative;width:100%;height:100%;height:100dvh;display:flex;background:var(--paper);overflow:hidden}
/* 側欄在 DOM 裡排在 .shell 後面（Tab 才會先走到輸入框），視覺位置靠這一條擺回最左邊。 */
.side{order:-1}
.shell{position:relative;flex:1;min-width:0;min-height:0;display:flex;flex-direction:column}

/* ---------- 頂欄（現行殼：64px、品牌 34px、藥丸按鈕） ---------- */
/* 高度從 60px 收到 52px：這一列同時擠著側欄開關、品牌、標題、存檔徽章、點數、登入與下載鈕，
   把「智能體 Web」那顆標籤收掉並壓低高度，換給下面的對話欄。padding-top 吃 safe-area，
   手機瀏海底下才不會壓到品牌。 */
.topbar{flex:none;z-index:20;height:calc(52px + env(safe-area-inset-top,0px));display:flex;align-items:center;gap:10px;padding:env(safe-area-inset-top,0px) 18px 0;border-bottom:1px solid rgba(231,229,228,.9);background:rgba(250,250,249,.9);backdrop-filter:blur(18px)}
/* 側欄開關固定在頂欄最左邊：桌機按它把側欄收成圖示欄，手機按它把側欄滑進來。 */
.tb-menu{flex:none;display:grid;place-items:center;width:34px;height:34px;border:0;border-radius:8px;background:transparent;color:var(--ink2)}
.tb-menu:hover{background:var(--soft2);color:var(--ink)}
.tb-menu .ic{width:18px;height:18px}
.brand{display:flex;align-items:center;gap:9px;color:inherit;text-decoration:none;flex:none}
.brand-icon{display:block;width:34px;height:34px;border-radius:8px}
.brand b{font-size:19px;font-weight:900}
/* 「智能體 Web」這顆標籤沒有告訴使用者任何他不知道的事（他就在這一頁），
   卻在最擠的一列佔掉約 70px，一律收掉。 */
.brand small{display:none}
.tb-title{display:flex;align-items:center;gap:8px;min-width:0;color:var(--ink2);font-size:13px;font-weight:700}
.tb-title #conversationTitle{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:34ch}
.tb-title em{font-style:normal;color:var(--hint);font-weight:600;flex:none}
.tb-sep{width:1px;height:20px;background:var(--line2);flex:none}
body[data-phase="first"] .tb-title{display:none}
.tb-right{margin-left:auto;display:flex;align-items:center;gap:8px;flex:none}
.account{display:flex;align-items:center;gap:9px;color:var(--ink2);font-size:12px}
.credits{padding:5px 10px;border:1px solid var(--line);border-radius:99px;background:#fff;font-size:12px;color:var(--ink2)}
.credits b{color:var(--ink)}
body[data-points="low"] .credits{border-color:#fecaca;background:var(--red-soft);color:var(--red)}
body[data-points="low"] .credits b{color:var(--red)}
.avatar{width:30px;height:30px;border-radius:50%;background:var(--ink);color:#fff;display:grid;place-items:center;font-size:12px;font-weight:700;flex:none}
.avatar.lg{width:38px;height:38px;font-size:16px}
.auth-checking{color:var(--muted);font-size:12px;white-space:nowrap}
/* 按鈕殼吃圓角第二階（8px）。舊版每一顆按鈕都是 99px 藥丸，整個介面看起來像一排糖果；
   藥丸從此只留給真正的 chip（步驟徽章、建議晶片、站點徽章、範例晶片這一類）。 */
.pill{min-height:42px;padding:8px 16px;border:0;border-radius:8px;text-decoration:none;font-weight:700;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:6px;white-space:nowrap}
.primary{background:var(--ink);color:#fff}.primary:hover{background:#34302d}
.secondary{background:#fff;border:1px solid var(--line2);color:var(--ink)}.secondary:hover{border-color:var(--muted)}
.small{min-height:34px;padding:5px 11px;font-size:12px}
.pill[disabled],.pill:disabled{opacity:.45;pointer-events:none}
.danger{border:1px solid #fecaca;border-radius:8px;background:#fff;color:var(--red);padding:6px 11px;font-weight:600;cursor:pointer;font-size:12px}
.icon-button{flex:none;display:grid;place-items:center;width:32px;height:32px;border:1px solid var(--line2);border-radius:8px;background:#fff;color:var(--ink2);font-size:14px;line-height:1;cursor:pointer}
.icon-button:hover{border-color:var(--muted);color:var(--ink)}
.linkish{border:0;background:none;padding:0;color:var(--blue);font-weight:700;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
body[data-auth="in"] .only-out,body[data-auth="in"] .only-pending{display:none}
body[data-auth="out"] .only-in,body[data-auth="out"] .only-pending{display:none}
body[data-auth="pending"] .only-in,body[data-auth="pending"] .only-out{display:none}

/* ---------- 連線中斷細列 ---------- */
/* 舊版它是版面裡的一列，出現時把整個工作台往下推 34px：使用者正在看的那一行內容當場跳走，
   而斷線本身已經夠讓人分心了。改成疊在頂欄下緣、從上面滑進來，版面高度完全不變。
   z-index 比頂欄低一階，收起來時它就藏在頂欄後面滑出去。 */
.netbar{position:absolute;z-index:19;top:calc(52px + env(safe-area-inset-top,0px));left:0;right:0;display:flex;align-items:center;gap:10px;padding:8px 18px;background:var(--amber-soft);border-bottom:1px solid #fde68a;color:var(--amber);font-size:12px;font-weight:700;transform:translateY(-100%);visibility:hidden;transition:transform .25s cubic-bezier(.4,0,.2,1),visibility 0s linear .25s}
body[data-net="off"] .netbar{transform:translateY(0);visibility:visible;transition:transform .25s cubic-bezier(.4,0,.2,1),visibility 0s}
.netbar .rt{margin-left:auto;display:flex;gap:8px}

/* ---------- 工作台：對話欄是整個頁面，行程畫布是可滑入的第二層 ---------- */
/* 這兩片工作台一律寫成 .pane.agent 與 .pane.trip，不可以寫成裸的 .agent。
   訊息流裡智能體那則訊息的類別正好也叫 .message.agent，裸選擇器會一起套到它身上，
   把每一則智能體回覆都變成絕對定位、蓋在整條對話上——2026-08-25 實測到的就是這個。 */
/* 舊版是兩欄 grid，欄寬被任務階段推著變，對話永遠只有一條窄縫；新版對話欄佔滿整個工作台，
   行程畫布用 transform 從右邊滑進來蓋掉 44%，對話欄同步把右界縮回來，內容靠 --col 保持置中感。
   兩邊用同一條 250ms 曲線，看起來才是一件事分兩邊動，不是兩個各走各的動畫。 */
.wb{position:relative;flex:1;min-height:0;overflow:hidden}
.pane{display:flex;flex-direction:column;min-width:0;min-height:0}
.pane.agent{position:absolute;top:0;left:0;bottom:var(--dockh,0px);right:0;background:var(--paper);transition:right .25s cubic-bezier(.4,0,.2,1)}
/* container-type 讓下面那段 @container 量得到「畫布自己有多寬」。舊版守門看的是視窗寬度，
   所以使用者把畫布拖窄到 500px 時，只要視窗還夠寬就仍然判定並排成立，地圖卡被擠到只剩 101px。 */
.pane.trip{position:absolute;top:0;right:0;bottom:0;width:var(--tripw);container-type:inline-size;background:#fff;border-left:1px solid var(--line);transform:translateX(101%);transition:transform .25s cubic-bezier(.4,0,.2,1);will-change:transform}
body[data-canvas="on"] .pane.agent{right:var(--tripw)}
body[data-canvas="on"] .pane.trip{transform:translateX(0)}
/* 畫布展開之後對話欄只剩一半寬，760px 的閱讀欄再也放不進去，訊息與膠囊會整個貼到邊。
   把目標欄寬降到 560px，留白公式才有餘裕算得出兩邊的內距，版面也不會突然變成一條窄縫。 */
body[data-canvas="on"]{--col:560px}
/* 拖動分隔軸時要跟著手指走，250ms 的過場曲線會讓它慢半拍像橡皮筋，所以拖曳期間整組關掉過場。 */
body[data-drag="tripw"] .pane.agent,body[data-drag="tripw"] .pane.trip,body[data-drag="tripw"] .canvas-handle,body[data-drag="tripw"] .canvas-grip,body[data-drag="tripw"] .dock{transition:none}
body[data-drag="tripw"]{cursor:col-resize;user-select:none}
/* 開新對話回到首屏、從入口點開舊對話：這兩次版面要一次到位。走過場的話使用者會看到內容先畫在
   錯的寬度裡再被推開（評審量到還原時整份對話先全寬出現再被壓窄）。沿用上面那條拖曳寫法。 */
body[data-restore],body[data-restore] .pane.agent,body[data-restore] .pane.trip,body[data-restore] .canvas-handle,body[data-restore] .canvas-grip,body[data-restore] .dock,body[data-restore] .side{transition:none}
/* 把手用 right 過場而不是 transform：它要停在畫布左緣，那是一個百分比位置，
   而 transform 的百分比算的是元素自己的寬度，表達不出這個位置。
   收合狀態把它加寬到 28px 並補上完整邊框與直排站數：舊版是一片 15px 的白底白邊小舌頭，
   在白色畫面上幾乎看不見，也沒有告訴使用者按下去會出現什麼。 */
/* 邊框與底色（評審量到白底白邊只有 1.04:1，等於畫面最右緣有一片看不見的按鈕）：
   邊框升到 --muted、底色改用既有的 --soft2，兩個都是代幣系統裡已經有的值，沒有新色。
   尺寸也進過場：收合態 28x92、展開態 16x56，舊版是瞬間換值，看起來像按鈕被抽掉再貼一顆新的。 */
.canvas-handle{position:absolute;z-index:16;top:50%;right:0;margin-top:-46px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;width:28px;height:92px;padding:0;border:1px solid var(--muted);border-right:0;border-radius:8px 0 0 8px;background:var(--soft2);color:var(--ink2);box-shadow:-2px 0 10px rgba(28,25,23,.10);transition:right .25s cubic-bezier(.4,0,.2,1),width .25s cubic-bezier(.4,0,.2,1),height .25s cubic-bezier(.4,0,.2,1),margin-top .25s cubic-bezier(.4,0,.2,1),background-color .15s,border-color .15s,color .15s}
.canvas-handle:hover{color:var(--ink);border-color:var(--ink2);background:#fff}
.canvas-handle .ic{width:13px;height:13px;transform:rotate(90deg)}
/* 直排站數：收起畫布之後仍看得出行程長到幾站，不必先展開才知道裡面有沒有東西。 */
.canvas-handle .ch-n{writing-mode:vertical-rl;color:var(--muted);font-size:11px;font-weight:600;letter-spacing:1px;line-height:1}
.canvas-handle .ch-n:empty{display:none}
/* 未儲存小點：畫布收起來之後儲存鈕整顆看不到，這是唯一還看得見的提醒。
   顏色從紅改成琥珀——還沒存不是錯誤，是一件等著使用者處理的事。 */
.canvas-handle .ch-dot{display:none;flex:none;width:7px;height:7px;border-radius:50%;background:var(--amber)}
.canvas-handle.unsaved .ch-dot{display:block}
body[data-canvas="on"] .canvas-handle{right:var(--tripw);width:16px;height:56px;margin-top:-28px;cursor:col-resize}
body[data-canvas="on"] .canvas-handle .ch-n,body[data-canvas="on"] .canvas-handle .ch-dot{display:none}
body[data-canvas="on"] .canvas-handle .ic{transform:rotate(-90deg)}
/* 分隔軸的抓取帶：把手只有 16px 高 56px，要求使用者精準點在上面才拖得動太苛刻，
   所以沿著整條邊界鋪一條 10px 的透明帶，滑過去就變成 col-resize。 */
.canvas-grip{display:none;position:absolute;z-index:15;top:0;bottom:0;right:var(--tripw);width:10px;margin-right:-5px;padding:0;border:0;background:transparent;cursor:col-resize;transition:right .25s cubic-bezier(.4,0,.2,1)}
body[data-canvas="on"] .canvas-grip{display:block}
.canvas-grip:hover,body[data-drag="tripw"] .canvas-grip{background:rgba(28,25,23,.12)}
body[data-vp="mobile"] .canvas-grip{display:none}

/* ---------- 底部座艙：分頁列、狀態列、提示行與輸入膠囊住在一起 ---------- */
/* 舊版把輸入膠囊放在對話欄內部，手機切到行程或地圖分頁時整條輸入條與停止鈕跟著消失；
   狀態列則釘在對話欄最上面，離正在生成的內容好幾百像素。改成一個絕對定位在工作台底部的座艙：
   桌機只覆蓋對話欄那一側（右界同樣讀 --tripw），手機橫跨整個寬度讓三個分頁共用同一條輸入條。
   對話欄與行程畫布用 --dockh 把下緣抬到座艙上方，內容不會被壓在膠囊底下。 */
.dock{position:absolute;z-index:14;left:0;right:0;bottom:0;display:flex;flex-direction:column;background:var(--paper);pointer-events:none;transition:right .25s cubic-bezier(.4,0,.2,1)}
.dock>*{pointer-events:auto}
body[data-canvas="on"] .dock{right:var(--tripw)}
/* 空狀態沒有進行中的對話，座艙整組收起來，首屏只留置中的歡迎與輸入膠囊。 */
body[data-phase="first"] .dock{display:none}
/* 畫布被壓窄時，時間軸與地圖並排會互相擠到不能用（評審實測地圖卡只剩 91px、拖窄後復發成 101px）。
   窄幅一律退回單欄，並把「並排」那顆按鈕收掉，不留一顆選得到卻沒有用的選項；
   手機不套用這一段，那裡的地圖分頁本來就是單欄全螢幕。
   門檻 620px 與 JS 的 splitAllowed() 讀同一個數字，CSS 已經收掉按鈕而 JS 還把檢視設成並排的情況才不會發生。 */
@container (max-width:540px){
  body:not([data-vp="mobile"]) .trip-body{grid-template-columns:1fr}
  body:not([data-vp="mobile"]) .trip-body[data-view="split"] .visual{display:none}
  body:not([data-vp="mobile"]) .seg [data-v="split"]{display:none}
}

/* ---------- 空狀態：置中的一句歡迎 ＋ 輸入膠囊 ＋ 範例晶片 ---------- */
/* 舊版是一整片有點陣底、超大標題與 trust-grid 的行銷首屏；新版它就是對話欄的空狀態，
   寬度與訊息流、輸入膠囊完全一致（--col），使用者送出第一句之後畫面不會整個跳位。 */
/* 置中用子元素的 margin:auto 而不是 justify-content:center：內容比容器高時，
   後者會把最上面那一段推到捲動範圍外剪掉，前者不會。 */
.hero{flex:1;min-height:0;overflow:auto;padding:24px 20px 28px;display:flex;flex-direction:column}
/* 矮視窗（多數手機橫向與小筆電）首屏會自己捲動，但畫面上沒有任何訊號說下面還有東西。
   內容真的溢出而且還沒捲到底時，底部淡出一段，讓那條邊界看起來是「被切住」而不是「到此為止」。 */
.hero.has-more{-webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 40px),transparent);mask-image:linear-gradient(180deg,#000 calc(100% - 40px),transparent)}
body:not([data-phase="first"]) #hero{display:none}
.hero-in{width:min(var(--col),100%);margin:auto;display:flex;flex-direction:column;align-items:stretch}
.hero-copy{text-align:center}
h1{font-size:clamp(26px,3.4vw,38px);line-height:1.3;letter-spacing:-1px;margin:0 0 10px;font-weight:700}
.hero-copy p{max-width:560px;margin:0 auto;color:var(--muted);font-size:14px;line-height:1.7}
.composer{background:#fff;border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow)}
.hero-composer{width:100%;margin-top:18px;padding:14px 14px 10px}
/* 輸入框改成跟著內容長高（JS 每次輸入把 height 歸零再設成 scrollHeight）：
   舊版兩個框都是固定高度，短句時下面空一大片、長文時反而擠在 45px 的小窗裡自己捲。
   max-height 是上限，超過才由 overflow-y:auto 接手，不會無限長高把畫面吃光。 */
.composer textarea{width:100%;border:0;outline:0;resize:none;background:transparent;color:var(--ink);font-size:16px;line-height:1.7;min-height:36px;max-height:240px;overflow-y:auto}
.composer textarea::placeholder{color:var(--muted)}
.composer-foot{display:flex;align-items:center;justify-content:flex-end;gap:10px;color:var(--hint);font-size:12px}
.composer-foot .cost{color:var(--hint);font-size:12px}
/* 靠左的那一個元素吃掉所有剩餘空間，計數與送出鈕就永遠貼在膠囊右下角。
   舊版把 margin-left:auto 放在送出鈕上，一旦計數出現就會被推到左邊跟成本說明黏在一起。 */
.composer-foot .cost,.composer-foot .tool{margin-right:auto}
.composer-foot .count{font-size:12px}
/* 膠囊內的工具位（目前是「載入 App 行程」）：ChatGPT 把附件鈕放在輸入框左下角，
   這裡沿用同一個位置與圓形幽靈按鈕的份量，讓它明顯次於送出鈕。 */
.composer-foot .tool{flex:none;display:grid;place-items:center;width:34px;height:34px;padding:0;border:1px solid var(--line);border-radius:50%;background:#fff;color:var(--ink2);cursor:pointer}
.composer-foot .tool:hover{border-color:var(--line2);background:var(--soft);color:var(--ink)}
/* 首屏的「我的 App 行程」是帶文字的寬版工具鈕：空狀態的人看不出「接續既有行程」這條路存在，
   一顆純圖示的圓鈕不足以說明它。登入後才顯示（未登入時它按了也沒有東西可載）。 */
.composer-foot .tool-wide{width:auto;gap:6px;padding:0 12px;border-radius:8px;font-size:12px;font-weight:600;display:inline-flex;align-items:center}
/* 送出方式必須寫在使用者按 Enter 之前看得到的地方，不能靠他自己試出來。手機沒有這個規則所以不顯示。 */
.composer-foot .kbd-hint{margin-left:auto;color:var(--hint);font-size:11px;white-space:nowrap}
body[data-vp="mobile"] .composer-foot .kbd-hint{display:none}
/* 成本說明從膠囊裡搬出來：它佔的是 GPT 放附件鈕的位置，而那個位置該留給「我的 App 行程」。
   搬到範例晶片下方之後還放得下真正有用的第二句「你目前有幾點」。 */
.cost-note{margin:10px 0 0;text-align:center;color:var(--muted);font-size:12px;line-height:1.6}
/* 點數可能不夠是要在送出之前就講的話，不是失敗之後才補的說明，所以它用警示色而不是提示灰。 */
.cost-note.warn{color:var(--amber);font-weight:700}
.count{font-size:12px;color:var(--hint);font-variant-numeric:tabular-nums}.count.warn{color:var(--amber)}.count.over{color:var(--red);font-weight:700}
.send{width:44px;height:44px;border:0;border-radius:50%;color:#fff;background:var(--ink);font-size:24px;cursor:pointer;display:grid;place-items:center;flex:none}
.send:disabled{background:var(--line2)}
/* 串流中送出鈕原位換成停止鈕（GPT 慣例：同一顆圓鈕、方塊圖示），所以它沿用 .send 的全部尺寸與位置，
   只換掉裡面的圖示。舊版那顆漂浮在工作列右側的「停止」文字鈕已經移除，避免同一個動作有兩個入口。 */
.send.stop .ic{width:15px;height:15px}
/* 1：點數為 0 時送出鈕仍然按得下去——200 只是估價，硬擋會誤傷真的排得動的小行程；
   按下去由 JS 說明為什麼開不了，而不是給一顆點了毫無反應的死鈕。 */
body[data-points="low"] .hero .send{background:var(--line2)}
/* 已經有對話或行程的人，最想按的是「接回上次那一份」而不是範例。這一組 order 把 .quick 提到範例之上，
   範例則收成一顆「看範例」文字鈕，需要的人才展開。第一次來的人看到的順序完全不變。 */
body[data-returning="1"] .hero-in>.message:not(.hero-notice){order:1}
body[data-returning="1"] .hero-copy{order:1}
body[data-returning="1"] #heroForm{order:2}
body[data-returning="1"] .quick{order:3;margin-top:18px}
body[data-returning="1"] .ex-toggle{order:4}
body[data-returning="1"] #ex-list{order:5;margin-top:10px}
body[data-returning="1"] .cost-note{order:6}
body[data-returning="1"] .hero-notice{order:7}
.ex-toggle{align-self:center;margin-top:14px;padding:6px 12px;border:0;border-radius:8px;background:transparent;color:var(--muted);font-size:12px;font-weight:600;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.ex-toggle:hover{color:var(--ink2)}
.examples{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-top:14px}
.examples button{min-width:0;border:1px solid var(--line);border-radius:99px;padding:8px 14px;background:#fff;color:var(--ink2);font-size:12px;cursor:pointer}
.examples button:hover{border-color:var(--line2);color:var(--ink)}
/* 按下去有沒有生效必須看得出來：舊版點完晶片只有輸入框悄悄變了字，晶片自己毫無反應。 */
.examples button[aria-pressed="true"]{border-color:var(--ink2);background:var(--soft);color:var(--ink);font-weight:700}
.hero-notice{width:100%;margin-top:16px;max-width:none;align-self:auto}
.hero-notice b{display:block;margin-bottom:2px}
.hero-notice .acts{margin-top:10px;display:flex;gap:8px;flex-wrap:wrap}
#bootError{width:100%;margin:16px 0 0;max-width:none}
/* 空狀態下方的兩顆快速入口：左邊接回最近的對話、右邊接回手機 App 裡的行程。
   完整清單住在側欄，這裡只放最前面幾筆，讓剛進站的人有東西可以直接按。 */
/* auto-fit：兩塊都在時各佔一半，只剩一塊時它自己撐滿整條欄，不會孤零零靠在左邊。 */
.quick{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:10px;margin-top:22px}
.recent{display:flex;flex-direction:column;align-items:stretch;gap:6px;min-width:0}
.recent .qh{display:flex;align-items:center;gap:8px}
.recent .qh b{color:var(--muted);font-size:12px;font-weight:600;letter-spacing:.02em}
.recent-list{display:flex;flex-direction:column;justify-content:flex-start;width:100%;gap:6px}
.recent-item{position:relative;width:100%;max-width:none;padding:9px 26px 9px 11px;border:1px solid var(--line);border-radius:8px;background:#fff;color:var(--ink2);text-align:left;font-size:12px;cursor:pointer;display:flex;align-items:center;gap:7px}
.recent-item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.recent-item svg{color:var(--hint)}
/* 右側的時間與「已存回 App」：光看標題分不出哪一則是剛剛那一則，也看不出哪幾份已經同步回 App。 */
.recent-item .rmeta{flex:none;margin-left:auto;color:var(--hint);font-size:12px;font-weight:600;white-space:nowrap}
.recent-item .rmeta .ok{color:var(--ink2)}
.recent-item::after{content:"›";position:absolute;right:11px;top:50%;margin-top:-9px;color:var(--hint);font-size:16px;line-height:1}
.recent-item:hover{border-color:var(--line2);box-shadow:var(--shadow-sm)}
.recent-item:hover::after{color:var(--ink2)}
.recent-all{margin-left:auto;padding:0;border:0;background:transparent;color:var(--muted);font-size:12px;font-weight:600;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.recent-all:hover{color:var(--ink2)}

/* ---------- 智能體工作列（現行 chat-head 殼 + 計時與步數） ---------- */
#workspace{flex:1;min-height:0;display:flex;flex-direction:column;position:relative}
/* 狀態列搬到輸入膠囊正上方（2026-08-25）：舊版釘在對話欄最頂端，離正在生成的內容 270px、
   離計時器 700px，使用者必須把視線拉到畫面另一端才知道現在跑到哪一步。現在它就貼在使用者
   打字的地方上面，狀態、已完成步數與計時器排在同一行讀完。 */
.chat-head{display:flex;align-items:center;gap:8px;width:min(var(--col),100% - 48px);margin:0 auto;padding:4px 6px 2px;background:transparent;flex:none}
.chat-head .live{min-width:0;flex:1;display:flex;align-items:baseline;gap:8px}
.chat-head .live b{flex:none;font-size:12px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chat-head .live span{min-width:0;color:var(--muted);font-size:12px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chat-actions{flex:none;display:flex;align-items:center;gap:6px}
.clock{color:var(--ink2);font-size:12px;font-weight:600;font-variant-numeric:tabular-nums;padding:0 2px}
/* 狀態燈只保留一種需要辨識的顏色：正在跑的時候是實心墨色加脈動，不用藍。
   完成不再是綠色——「已經排好了」這件事由旁邊那句話與摘要卡負責說，不需要再多一個色相。
   等你回答與斷線維持琥珀，那兩個是真的需要使用者立刻處理的狀況。 */
.beacon{width:10px;height:10px;border-radius:50%;background:var(--ink);flex:none;box-shadow:0 0 0 0 rgba(28,25,23,.35);animation:pulse 1.5s infinite}
@keyframes pulse{70%{box-shadow:0 0 0 7px rgba(28,25,23,0)}100%{box-shadow:0 0 0 0 rgba(28,25,23,0)}}
body[data-phase="clarify"] .beacon{animation:none;background:var(--amber)}
body[data-phase="done"] .beacon{animation:none;background:var(--ink2)}
body[data-phase="idle"] .beacon{animation:none;background:var(--line2)}
body[data-net="off"] .beacon{animation:none;background:var(--amber)}

/* ---------- 訊息流（現行氣泡） ---------- */
/* 訊息直接躺在背景上，靠左右內距把內容夾成一條 --col 寬的置中欄，不再包一層卡片。
   內距用 max() 算：欄寬夠時兩邊各留 (100%-col)/2，不夠時退回 16px。 */
/* 內距與膠囊寬度必須是同一組數字算出來的，否則兩者的左緣會差幾個像素（評審量到 9px）。
   欄寬夠時兩邊各留 (100%-col)/2、膠囊拿滿 col；欄寬不夠時兩邊各留 24px、膠囊拿 100%-48px。
   兩種情況下左緣都對得起來。 */
/* 區塊之間的留白從 12px 拉到 20px：使用者那句、智能體的回答、工作過程、摘要卡是四種不同的東西，
   舊版靠底色與邊框把它們分開，改成靠留白與小標分開之後，顏色才有辦法整批收掉。 */
.messages{flex:1;min-height:0;overflow:auto;padding:16px max(24px,(100% - var(--col))/2) 4px;display:flex;flex-direction:column;gap:20px;scroll-behavior:smooth}
/* 訊息層級（2026-08-25 修正）：舊版把使用者那句排成黑底白字的實心塊，智能體的回答反而是最淺的白卡，
   結果整條對話裡最搶眼的永遠是使用者自己剛打的字。改成 GPT 的作法——使用者是灰底的引言，
   智能體的話直接躺在背景上、沒有卡片框，讓內容自己當主角。 */
.message{max-width:92%;padding:12px 14px;border-radius:12px;white-space:pre-wrap;overflow-wrap:anywhere}
.message.user{align-self:flex-end;max-width:72%;color:var(--ink);background:var(--soft);border-bottom-right-radius:4px}
/* 區塊小標的統一規格：12px、600、--muted、字距 .02em，不用全大寫。
   工作過程的標題、建議晶片的標題、側欄的日期分組、設定面板的區塊標題都跟著這一組走。 */
.message.user .who{display:block;margin-bottom:3px;color:var(--muted);font-size:12px;font-weight:600;letter-spacing:.02em}
.message.agent{align-self:flex-start;max-width:92%;background:transparent;border:0;padding-left:0;padding-right:0;color:var(--ink);font-size:14px;line-height:1.75}
.message.progress{align-self:stretch;max-width:none;background:var(--soft);border:1px solid var(--line);color:var(--ink2)}
/* error 是四個系統訊息（progress／warn／info／error）裡唯一漏掉 stretch 的，
   評審量到它的右緣比三個兄弟短 61px，看起來像排版壞掉。描邊也一起補齊。 */
.message.error{background:var(--red-soft);border:1px solid #fecaca;color:var(--red);align-self:stretch;max-width:none}
.message.warn{background:var(--amber-soft);border:1px solid #fde68a;color:var(--amber);align-self:stretch;max-width:none}
.message.info{background:var(--soft);border:1px solid var(--line);color:var(--ink2);align-self:stretch;max-width:none}
/* 排隊卡：執行中送出的那一句不再被靜默吃掉，它會變成這張卡等在對話串裡，任務結束自動送出。
   「排隊中」不是錯誤也不是警告，所以它跟其他系統訊息一樣走中性底，靠卡上那句話說明自己在等什麼。 */
.message.queued{background:var(--soft);border:1px solid var(--line);color:var(--ink2)}
.message.queued.cancelled{opacity:.7;color:var(--muted)}
.message.queued b{display:block;margin-bottom:2px}
.message .acts{margin-top:9px;display:flex;gap:8px;flex-wrap:wrap}
/* 這顆鈕改成排在訊息流後面的一般元素，再用「負上緣＝自己的高度」把自己疊回訊息流底部：
   它對版面的淨貢獻是 0，所以出現與消失都不會把下面的提示行與輸入膠囊推來推去，
   也不會像絕對定位那版一樣壓在提示行上（絕對定位算不出膠囊多高，只能猜一個 bottom）。 */
/* 17：送出之後第一個事件回來之前的那一秒，這張卡站在工作過程將要長出來的位置，
   讓使用者看得出「送出去了、正在讀」，而不是對著六成空白猜。 */
.message.skeleton b{display:block;margin-bottom:9px;font-size:13px;font-weight:700}
.sk-rows{display:flex;flex-direction:column;gap:7px}
.sk-rows span{display:block;height:9px;border-radius:8px;background:linear-gradient(90deg,var(--line) 25%,var(--soft2) 37%,var(--line) 63%);background-size:400% 100%;animation:sk 1.4s ease-in-out infinite}
.sk-rows span:nth-child(2){width:78%}
.sk-rows span:nth-child(3){width:52%}
@keyframes sk{0%{background-position:100% 50%}100%{background-position:0 50%}}
.latest-button{position:relative;z-index:5;align-self:center;height:30px;margin:-30px auto 0;padding:0 12px;border:1px solid var(--line2);border-radius:8px;background:#fff;color:var(--ink2);box-shadow:var(--shadow-sm);font-size:11px;font-weight:600;cursor:pointer}
@media(prefers-reduced-motion:no-preference){.message{animation:rise .25s ease-out}@keyframes rise{from{opacity:0;transform:translateY(8px)}}}
/* 16：首屏與工作區換場時，輸入膠囊由 JS 用 FLIP 從舊位置飛到新位置，另一側的內容則淡進來，
   兩件事同一條 250ms 曲線，看起來是一片畫面換過去而不是硬切。 */
@media(prefers-reduced-motion:no-preference){.phase-in{animation:phase-in .25s cubic-bezier(.4,0,.2,1)}@keyframes phase-in{from{opacity:0}}}

/* 追問卡：長在訊息流原位，選項是現行的 secondary small 藥丸 */
.askcard{align-self:stretch;max-width:none;padding:12px 14px;border:1px solid var(--line);border-left:4px solid var(--amber);border-radius:12px;background:#fff}
.askcard h4{margin:0 0 4px;font-size:14px;font-weight:700;white-space:pre-wrap;overflow-wrap:anywhere}
.askcard p{margin:0 0 10px;color:var(--muted);font-size:12px}
.opts{display:flex;flex-wrap:wrap;gap:7px}
.opt{display:inline-flex;align-items:center;gap:7px;min-height:34px;padding:5px 12px;border:1px solid var(--line2);border-radius:8px;background:#fff;font-size:12px;font-weight:600;color:var(--ink);text-align:left}
.opt:hover{border-color:var(--muted)}
.opt[disabled]{opacity:.5;pointer-events:none}
.opt .kx{flex:none;width:20px;height:20px;border-radius:50%;background:var(--soft);color:var(--muted);font-size:11px;font-weight:600;display:grid;place-items:center}
.opt b{font-weight:600}
.opt.other{border-style:dashed;color:var(--ink2);font-weight:600}
/* 35：回答完之後這張卡只需要說「當時問了什麼、你選了什麼」。六顆選項留在畫面上佔 116px，
   而且看起來還可以按。收成兩行之後它就是一筆紀錄，不再假裝自己是一個入口。 */
.askcard.answered{opacity:.75;padding:9px 12px;border-left-color:var(--line2)}
.askcard.answered h4{font-size:13px;font-weight:600}
.askcard.answered p{margin:2px 0 0}

/* 摘要卡：白底、四邊同一條 1px 線框。綠色左條與綠色標題全部拿掉，只留標題前那顆打勾——
   那是整個畫面上唯一需要一眼看到的成功訊號，其餘的成功資訊由文字自己說。 */
.summary-card{align-self:stretch;max-width:none;padding:14px;border:1px solid var(--line);border-radius:12px;background:var(--card);color:var(--ink);box-shadow:0 1px 3px rgba(28,25,23,.05)}
.summary-title{display:flex;align-items:center;gap:7px;color:var(--ink);font-size:14px;font-weight:700}
.summary-title::before{content:"✓";flex:none;display:grid;place-items:center;width:18px;height:18px;border-radius:50%;background:var(--green-soft);color:var(--green);font-size:11px;line-height:1;font-weight:700}
.summary-title .ok{margin-left:auto;color:var(--muted);font-size:12px;font-weight:600}
.summary-row{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-top:6px;padding-top:6px;border-top:1px solid var(--line);color:var(--ink2);font-size:12px;font-variant-numeric:tabular-nums}
.summary-row span{color:var(--muted)}.summary-row b{flex:none;color:var(--ink);font-weight:700;text-align:right}
/* 收合畫布之後儲存鈕整顆跑到視窗外（評審量到 x=1844），完成摘要卡因此要自己帶一個儲存入口。
   它與 #saveButton 共用同一個 handler 與同一組三態文字，兩顆永遠說同一件事。 */
.summary-acts{margin-top:10px;padding-top:10px;border-top:1px solid var(--line);display:flex;gap:8px;flex-wrap:wrap}
.qc{margin-top:8px;border-top:1px solid var(--line)}
.qc>summary{padding:8px 0 0;font-size:12px;font-weight:600;color:var(--ink2);cursor:pointer;display:flex;align-items:center;gap:6px;list-style:none}
.qc>summary::-webkit-details-marker{display:none}
.qc>summary .cv{margin-left:auto;width:13px;height:13px;transition:transform .15s}
.qc[open]>summary .cv{transform:rotate(180deg)}
.qc ol{margin:6px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:5px}
.qc li{display:flex;gap:7px;font-size:12px;color:var(--ink2);align-items:flex-start;overflow-wrap:anywhere}
/* 通過的項目用中性打勾，沒有通過的才是琥珀：一整排綠色打勾等於把「正常」也標成需要注意的事。 */
.qc li svg{color:var(--muted);margin-top:3px;width:12px;height:12px;stroke-width:2;flex:none}
.qc li.bad svg{color:var(--amber)}
.qc li b{color:var(--ink);font-weight:600}
.chips-wrap{align-self:stretch}
.chips-label{font-size:12px;color:var(--muted);margin-bottom:6px;font-weight:600;letter-spacing:.02em}
.chips{display:flex;flex-wrap:wrap;gap:7px}
.chip{display:inline-flex;align-items:center;gap:6px;min-height:32px;padding:5px 12px;border:1px solid var(--line);border-radius:99px;background:#fff;font-size:12px;color:var(--ink2);font-weight:600}
.chip:hover{border-color:var(--line2);color:var(--ink)}
/* 36：只有最新那一組建議按得下去，舊的那幾組留著當紀錄。停用的樣式沿用 .opt[disabled] 那一組。 */
.chip[disabled]{opacity:.5;pointer-events:none}

/* 工作過程：藍色左軌條拿掉，標題降成與其他區塊同一款 12px 中性小標，
   讓這一整段回到「附在對話旁邊的過程紀錄」的份量，而不是畫面上最搶眼的那一塊。 */
.wl-wrap{align-self:stretch;padding:0}
.wl-top{width:100%;display:flex;align-items:center;gap:8px;margin-bottom:8px;padding:0;border:0;background:transparent;color:var(--muted);font-size:12px;font-weight:600;letter-spacing:.02em;text-align:left;cursor:pointer}
.wl-top:hover{color:var(--ink2)}
.wl-top .lb{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wl-top .n{margin-left:auto;color:var(--hint);font-size:11px;font-weight:600;white-space:nowrap;flex:none}
.wl-top .cv{width:14px;height:14px;color:var(--hint);transition:transform .15s;flex:none}
.wl-top>svg:first-child{display:none}
.wl-wrap.collapsed .wl-body{display:none}
/* 展開之後整段可以長到 2000px 以上，把摘要與追問框全部推出畫面。改成在自己的框裡捲：
   上限 60vh，收合鈕留在框外，使用者不必捲到底才找得到把它關起來的地方。
   進行中的那一輪由 JS 每次重畫把它捲到底，最新一步永遠看得見。 */
/* 32：展開之後整段可以長到 60vh，收合鈕跟著被推出畫面（評審量到它跑到畫面上方 777px），
   使用者必須先往回捲很遠才找得到把它關起來的地方。釘在對話欄頂端，展開多長都按得到。 */
.wl-wrap:not(.collapsed) .wl-top{position:sticky;top:0;z-index:2;padding:6px 0;background:var(--paper)}
/* 33：內層捲到底之後再捲，不要把外層的整條對話一起帶走 */
.wl-wrap:not(.collapsed) .wl-body{max-height:60vh;overflow-y:auto;overscroll-behavior:contain}
.wl-wrap.collapsed .wl-top .cv{transform:rotate(-90deg)}
.wl-wrap.frozen{opacity:.92}
.wl-wrap.frozen .wl-top{color:var(--muted)}
.wl{display:flex;flex-direction:column}
/* 乙1：把連續的步驟依「回合」分組。分組只讀既有的步驟種類，不新增任何後端欄位：
   讀題是一組、搜尋與比較是一組、檢查與驗證是一組、寫入行程是一組，連續同一類的步驟併成同一組。
   組與組之間畫一條 1px 的中性線，同一組內部只有軌道那條線，不再多畫分隔。
   分不出段落時（只成一組、或平均每組不到 1.5 步）JS 會退回原本的單一長流，不硬分。 */
.wl-group+.wl-group{margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}
.wl-glab{margin:0 0 6px;color:var(--muted);font-size:12px;font-weight:600;letter-spacing:.02em}
.wl-gsteps{display:flex;flex-direction:column}
.step{--dot:var(--card);--dot-border:var(--line2);--rail:var(--line);position:relative;display:grid;grid-template-columns:22px minmax(0,1fr);min-height:34px}
.step::before,.step::after{content:"";position:absolute;z-index:0;left:10.3px;width:1.4px;background:var(--rail)}
.step::before{top:0;height:12px}.step::after{top:12px;bottom:0}
.step:first-child::before,.step:last-child::after{display:none}
.step .dot{z-index:1;grid-column:1;grid-row:1;align-self:start;justify-self:center;width:11px;height:11px;margin-top:6.5px;border:1.4px solid var(--dot-border);border-radius:50%;background:var(--dot)}
.step.is-run{--dot-border:var(--ink)}
.step.is-run .dot{width:13px;height:13px;margin-top:5.5px;border:2px solid var(--line2);border-top-color:var(--ink);background:var(--card);animation:spin .8s linear infinite}
.step.is-done{--dot:var(--line2);--dot-border:var(--line2)}
.step.is-stop{--dot:var(--red);--dot-border:var(--red)}
.step.is-warn{--dot:var(--amber);--dot-border:var(--amber)}
.wl-wrap.frozen .step.is-run .dot{animation:none;border-color:var(--line2);border-top-color:var(--line2)}
/* 任務停掉之後，沒有收到終態的那一步不能再用「進行中」的藍字說話：
   使用者按了停止，畫面上就不該有任何一個地方看起來還在跑。 */
.wl-wrap.frozen .step.is-run .step-t{color:var(--ink2);font-weight:400}
@keyframes spin{to{transform:rotate(1turn)}}
/* 不換行：flex-wrap 會把右邊那個耗時甩到下一行，貼在下一步的標題上方，看起來像下一步跑了那麼久。
   標題自己吃掉剩餘空間並在過長時省略，耗時就永遠留在同一行的最右邊。 */
.step-h{grid-column:2;display:flex;align-items:baseline;gap:6px;flex-wrap:nowrap;padding:4px 0 0}
/* 徽章高度 18→20px、字級 10→11px，擠在一起的小字是「幼兒版本」印象的來源之一。 */
.kind{display:inline-flex;align-items:center;gap:4px;height:20px;padding:0 8px;border-radius:99px;font-size:11px;font-weight:600;letter-spacing:.02em;flex:none;background:var(--soft);color:var(--muted)}
.kind svg{width:10px;height:10px;stroke-width:2.25}
/* 甲2：五種步驟徽章原本是灰、藍、琥珀、綠、實心藍五個顏色，光是這一排就讓同一個畫面出現四個色系。
   全部改成同一個中性底，讀題／搜尋／決策／檢查／寫入靠自己的圖示與名稱區分。
   寫入是這一排裡唯一改動了行程的一步，用比較深的字色與 700 字重讓它稍微重一點，仍然不用顏色。 */
.k-read,.k-search,.k-decide,.k-check{background:var(--soft);color:var(--muted)}
.k-write{background:var(--soft2);color:var(--ink2);font-weight:700}
/* 提問與中止留著顏色：一個是「等你回答才走得下去」，一個是「這一輪被停掉了」，
   兩個都是使用者必須立刻看到的狀況，符合本檔的用色紀律。 */
.k-ask{background:var(--amber-soft);color:var(--amber)}
.k-stop{background:var(--red-soft);color:var(--red)}
.step-t{flex:1;font-size:12px;line-height:1.4;color:var(--ink2);font-weight:400;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.step.is-run .step-t{color:var(--ink);font-weight:600}
.step.is-done .step-t{color:var(--ink);font-weight:600}
.step.is-stop .step-t{color:var(--red);font-weight:600}
.step.is-warn .step-t{color:var(--amber);font-weight:600}
.step-ms{margin-left:auto;color:var(--hint);font-size:11px;font-weight:600;white-space:nowrap;flex:none;padding-left:6px}
.step-m{grid-column:2;margin-top:1px;color:var(--muted);font-size:11px;line-height:1.4;white-space:pre-wrap;overflow-wrap:anywhere}
.step>*:not(.dot):not(.step-h){grid-column:2}
.mini-list{margin:4px 0 2px;padding:0;list-style:none;display:flex;flex-direction:column;gap:2px}
.mini-list li{display:flex;gap:6px;font-size:11px;color:var(--muted);overflow-wrap:anywhere}
.mini-list svg{color:var(--muted);margin-top:3px;width:11px;height:11px;stroke-width:2;flex:none}
.mini-list li.bad svg{color:var(--amber)}
.step-more{margin:2px 0 4px;padding:0;border:0;background:none;color:var(--hint);font-size:11px;font-weight:600;display:flex;align-items:center;gap:4px;cursor:pointer}
.step-more .cv{width:11px;height:11px;transition:transform .15s}
.step.open .step-more .cv{transform:rotate(180deg)}
.step .detail{display:none}.step.open .detail{display:block}
.cmp{margin:4px 0 6px;border:1px solid var(--line);border-radius:8px;overflow:hidden;background:#fff}
.cmp-row{display:flex;gap:8px;padding:8px 12px;font-size:12px;align-items:flex-start}
.cmp-row .mk{flex:none;height:20px;padding:0 8px;border-radius:8px;font-size:11px;font-weight:600;display:grid;place-items:center;margin-top:1px;background:var(--soft);color:var(--ink2)}
.cmp-row .rs{color:var(--ink2);min-width:0;white-space:pre-wrap;overflow-wrap:anywhere}
.sd-card{margin:2px 0 7px;padding:10px 12px;border:1px solid var(--line);border-radius:8px;background:#fff}
.sd-card b{display:block;color:var(--ink2);font-size:12px;line-height:1.4;font-weight:600}
.sd-card .sub{margin-top:2px;color:var(--muted);font-size:11px}
.chip-group{margin-top:7px}
.chip-group>b{display:block;margin-bottom:4px;color:var(--muted);font-size:12px;font-weight:600;letter-spacing:.02em}
.detail-chips{display:flex;flex-wrap:wrap;gap:5px}
.detail-chip{max-width:100%;padding:3px 7px;border:1px solid var(--line);border-radius:99px;background:var(--soft);color:var(--ink2);font-size:11px;line-height:1.4;text-decoration:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.detail-chip:is(a):hover{border-color:var(--blue);color:var(--blue)}
/* 甲3：寫入列原本是藍底藍字加一條藍左條，在一段灰階的工作過程裡整條亮起來。
   改成中性底加一條 --line2 的左條，「這一步真的動到了行程」由圖釘圖示與那句話說明。 */
.wrote{margin:3px 0 6px;display:flex;align-items:center;gap:8px;width:100%;text-align:left;padding:8px 12px;border:1px solid var(--line);border-left:4px solid var(--line2);border-radius:8px;background:var(--soft);color:var(--ink2);font-size:12px;font-weight:600;cursor:pointer}
.wrote:hover{border-color:var(--line2);border-left-color:var(--muted)}
.wrote .wt{flex:1;min-width:0;line-height:1.4;overflow-wrap:anywhere}
.wrote .go{margin-left:auto;font-size:11px;font-weight:600;opacity:.75;display:flex;align-items:center;gap:2px;flex:none;white-space:nowrap}
.wrote svg{flex:none}

/* 追問膠囊（2026-08-24 照 ChatGPT 排版重整）：
   舊版把輸入框、載入 App 行程、送出鈕擠成同一橫列，字數計數又是浮在膠囊外面下方的獨立節點，
   三種份量不同的東西並排，使用者反映按鈕位置不合理。改成 GPT 的兩段式膠囊：
   上段只有輸入框，下段一條工具列（左工具、右送出），字數計數縮進工具列右側當小字。
   膠囊自包含之後，串流中的停止鈕才有「原位取代送出鈕」的位置可用。 */
.cmp-hint{flex:none;display:flex;align-items:center;gap:6px;width:min(var(--col),100% - 48px);margin:0 auto;padding:2px 6px 0;color:var(--muted);font-size:12px;font-weight:600}
.cmp-hint.bad{color:var(--red)}
.compact{width:min(var(--col),100% - 48px);margin:6px auto calc(14px + env(safe-area-inset-bottom,0px));border-radius:12px;padding:12px 12px 10px 16px;box-shadow:var(--shadow-sm);flex:none}
.compact textarea{display:block;width:100%;font-size:16px;min-height:26px;max-height:200px;overflow-y:auto}
.compact .composer-foot{margin-top:4px}
.compact .send{width:36px;height:36px;flex:none;font-size:20px}
.compact-count{margin:0;text-align:right}
body[data-points="low"] .compact{opacity:.5;pointer-events:none}
/* 點數不足會把整顆膠囊停用，但「停止目前任務」不能跟著被鎖住：跑到一半才把點數用完的人
   必須還按得下停止，否則他只剩重新整理頁面這一條路。 */
body[data-points="low"] .compact .send.stop{pointer-events:auto}

/* ---------- 行程區（現行 trip-head 殼 + 日分頁藥丸 + 視圖切換） ---------- */
.trip-head{display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--line);background:#fff;flex:none;min-height:56px}
.day-tabs{display:flex;gap:5px;overflow-x:auto;scrollbar-width:none;min-width:0}
.day-tabs::-webkit-scrollbar{display:none}
.day-tabs button{flex:none;padding:5px 10px;border:1px solid var(--line);border-radius:8px;background:var(--soft);color:var(--muted);font-size:12px;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:5px;white-space:nowrap}
/* 甲7：選中態全站統一成「--ink 底白字」，日分頁、檢視切換、側欄分頁、手機分頁四組都照這一條，
   不再由藍色代表「我選的是這一個」。 */
.day-tabs button.on{border-color:var(--ink);background:var(--ink);color:#fff}
.day-tabs button[disabled]{opacity:.45;pointer-events:none}
.day-tabs button .dd{font-weight:600;opacity:.85}
.day-tabs button .dq svg{width:11px;height:11px}
/* 檢視切換是次要動作、儲存是主要動作，兩者同在右欄頂欄就必須一眼分得出主次：
   切換維持線框膠囊組、儲存維持實心並固定在最右。高度統一成 34px（與 .pill.small 同高），
   舊版切換組比儲存鈕矮一截，看起來像兩排東西擠在同一列。 */
.seg{margin-left:auto;display:flex;align-items:center;gap:3px;padding:2px;border:1px solid var(--line);border-radius:8px;background:var(--soft);flex:none;height:34px}
.seg button{min-height:28px;padding:5px 13px;border:0;border-radius:6px;background:transparent;color:var(--muted);font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}
.seg button.on{background:var(--ink);color:#fff;box-shadow:none}
/* 使用者按過「先只看時間軸」之後，含地圖的兩個檢視要標出來：按下去會回到一片載不出來的地圖，
   先讓他看見警示點與提示，再自己決定要不要試。 */
.seg button{position:relative}
.seg button.map-blocked::after{content:"";position:absolute;top:3px;right:5px;width:6px;height:6px;border-radius:50%;background:var(--amber)}
#saveButton{flex:none;min-height:34px}
/* 畫布的正規關閉鍵：舊版桌機收合畫布之後，唯一的回頭路是畫面最右緣一片 15px 的白舌頭。 */
.trip-close{flex:none}
body[data-vp="mobile"] .trip-close{display:none}
/* 儲存狀態一句話講完，太長就省略並把全文放 title，手機上才不會被它推掉半個畫面。 */
.trip-status{flex:none;display:flex;align-items:center;gap:10px;padding:8px 16px;border-bottom:1px solid var(--line);background:#fff;color:var(--muted);font-size:12px;line-height:1.5}
.trip-status #saveStatus{min-width:0;white-space:pre-line}
/* 「已同步 App」是一句陳述而不是一個要提醒使用者的狀況，改成中性底色，字面自己說得清楚。 */
.saved{color:var(--ink2)!important;background:var(--soft);border-radius:8px;padding:3px 8px;font-weight:600;flex:none;font-size:12px}
.trip-body{flex:1;min-height:0;display:grid;grid-template-columns:minmax(260px,42%) 1fr}
.trip-body[data-view="timeline"]{grid-template-columns:1fr}
.trip-body[data-view="timeline"] .visual{display:none}
.trip-body[data-view="map"]{grid-template-columns:1fr}
.trip-body[data-view="map"] .timeline{display:none}
.timeline{flex:1;min-height:0;overflow:auto;overscroll-behavior:contain;padding:16px}
.timeline .empty{height:100%;display:grid;place-items:center;text-align:center;color:var(--hint);padding:24px;border:1px dashed var(--line2);border-radius:12px}
/* 這一條原本寫成裸的 .day，而日分頁的按鈕類別也叫 .day（renderDays 給的），
   結果行程頭那一列的日分頁各自帶著 24px 的下緣間距，整排比旁邊的檢視切換與儲存鈕高了一截。
   限定在時間軸裡面之後，兩件事各自成立：分頁回到與同列元件對齊，日區塊的間距也拉大到 28px。 */
.timeline .day{margin-bottom:28px}
.day-heading{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.day-heading h3{margin:0;font-size:16px}
.day-heading span{color:var(--muted);font-size:11px;font-weight:600}
.day-heading .day-anchor{flex:none;padding:3px 9px;border-radius:8px;background:var(--soft);color:var(--ink2);font-size:11px;font-weight:600;white-space:nowrap}
.day-empty{padding:34px 14px;border:1px dashed var(--line2);border-radius:12px;color:var(--muted);text-align:center}
.growing{margin:4px 0 0 96px;padding:12px 14px;border:1px dashed var(--line2);border-radius:12px;background:#fff;color:var(--muted);font-size:12px;font-weight:600;display:flex;align-items:center;gap:8px}
.growing .bar{height:8px;border-radius:8px;background:var(--line2);flex:1;max-width:110px;animation:br 1.4s ease-in-out infinite}
@keyframes br{0%,100%{opacity:.45}50%{opacity:.9}}
.stop{cursor:pointer}
.stop.sel .stop-body{border-color:var(--ink2);box-shadow:0 0 0 3px var(--soft2)}
.stop-badges{display:flex;flex-wrap:wrap;gap:4px}
.stop-badges span{display:inline-flex;align-items:center;gap:4px;min-height:20px;padding:2px 7px;border-radius:99px;background:var(--soft);color:var(--ink2);font-size:11px;font-weight:600}
.stop-badges span svg{width:10px;height:10px;stroke-width:2.25;flex:none}
.stop-badges span.lock{background:var(--soft);color:var(--ink2)}
/* 甲5：時間錨定原本是綠底、硬錨定還反白成實心綠，在一張白卡上是整個畫面最亮的一塊。
   它是使用者自己下的硬約束沒錯，但「已經照著排」是常態不是警訊，所以改成中性底，
   硬錨定用深一階的底色與字色表示份量，鎖頭圖示跟著文字走。 */
.stop-badges span.anchor{background:var(--soft);color:var(--ink2);font-weight:600;box-shadow:inset 0 0 0 1px var(--line2)}
.stop-badges span.anchor.hard{background:var(--soft2);color:var(--ink);font-weight:700;box-shadow:inset 0 0 0 1px var(--line2)}
/* 營業狀態：「營業中」是常態，改成不帶底色的中性文字；「即將打烊」與「已打烊」維持琥珀與紅，
   那兩個才是使用者非看到不可的異常。左邊那顆小圓點跟著文字顏色走，不需要再多一個色。 */
.stop-badges span.oh::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.stop-badges span.oh.ok{background:transparent;color:var(--muted);padding-left:0}
.stop-badges span.oh.warn{background:var(--amber-soft);color:var(--amber)}
.stop-badges span.oh.bad{background:var(--red-soft);color:var(--red)}
.stop-meta{margin-top:4px;color:var(--muted);font-size:12px}
.stop-note{margin-top:7px;padding-top:7px;border-top:1px solid var(--line);color:var(--ink2);font-size:12px;line-height:1.5}

/* ---------- 地圖（現行 map-card 殼：圓角卡片、浮動工具列、藍色圓形標記） ---------- */
.visual{padding:14px;background:var(--soft);min-width:0;min-height:0}
.map-card{position:relative;height:100%;overflow:hidden;border:1px solid var(--line);border-radius:16px;background:var(--soft);box-shadow:var(--shadow-sm)}
.map-toolbar{position:absolute;z-index:3;top:12px;left:12px;right:12px;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 14px;border:1px solid rgba(231,229,228,.8);border-radius:12px;background:#fff;box-shadow:var(--shadow-sm)}
.pane-heading{flex:1;min-width:0}
.pane-heading b{display:block;font-size:14px}
.pane-heading span{display:block;color:var(--muted);font-size:12px}
/* 這一條原本寫成 display:inline-flex!important，因為它要蓋過上面 .pane-heading span 的 display:block。
   但檔頭第 7 行的 [hidden]{display:none!important} 特異性跟它一樣（都是一個 class、都帶 !important），
   同分時後寫的贏，結果 JS 把 #map-live 設成 hidden 也關不掉，「智能體考慮中 0 個候選」永遠掛在地圖上。
   改用特異性解決：.pane-heading .map-live 是兩個 class，贏得過 .pane-heading span，也就不需要 !important，
   [hidden] 的 !important 自然又蓋得回來。 */
/* 「智能體考慮中」是進度不是警告，改成中性徽章加一顆脈動的中性圓點。 */
.pane-heading .map-live{display:inline-flex;align-items:center;gap:6px;margin-top:3px;padding:2px 8px;border-radius:99px;background:var(--soft);color:var(--ink2);font-size:11px;font-weight:600}
.map-live i{width:7px;height:7px;border-radius:50%;background:var(--ink2);animation:pulse-amber 1.5s infinite}
@keyframes pulse-amber{70%{box-shadow:0 0 0 6px rgba(28,25,23,0)}100%{box-shadow:0 0 0 0 rgba(28,25,23,0)}}
.map-live span{display:inline;color:inherit;font-size:inherit}
.map-canvas{position:absolute;inset:0}
#map{height:100%;min-height:320px}
.map-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:5px;text-align:center;padding:30px;background:linear-gradient(145deg,#f0efe9,#ece9e2);color:var(--ink2)}
.map-empty span{color:var(--muted);font-size:12px}
/* 地圖標記本來就要在圖磚上站得住，但它不必是藍的：墨色系一樣看得清楚，而且與路線同色，
   圖例上那三格因此說得出真話（舊版圖例畫的是藍線，實際畫在地圖上的路線是深綠色）。 */
.map-marker{display:grid;place-items:center;width:30px;height:30px;border:3px solid #fff;border-radius:50%;background:var(--ink2);color:#fff;font-weight:700;font-size:12px;cursor:pointer;box-shadow:0 1px 2px rgba(28,25,23,.28),0 4px 12px rgba(28,25,23,.22),0 8px 22px rgba(28,25,23,.10);transition:transform .15s}
.map-marker.sel,.map-marker:hover{transform:scale(1.18);background:var(--ink)}
.map-marker.node{background:var(--line2);color:var(--ink2);font-size:11px}
.map-marker.anchor-pin{background:var(--ink)}
.map-marker.candidate{width:15px;height:15px;border-width:2px;border-color:var(--line2);background:var(--card);color:transparent;font-size:0;opacity:.95;box-shadow:0 0 0 3px rgba(28,25,23,.10),0 1px 3px rgba(28,25,23,.22);animation:cand 1.9s infinite;cursor:default}
.map-marker.candidate>span{display:none}
@keyframes cand{0%{box-shadow:0 0 0 3px rgba(28,25,23,.10)}70%{box-shadow:0 0 0 9px rgba(28,25,23,0)}100%{box-shadow:0 0 0 3px rgba(28,25,23,.10)}}
.legend{position:absolute;left:12px;bottom:12px;z-index:3;background:rgba(255,255,255,.94);border:1px solid var(--line);border-radius:8px;padding:8px 11px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:5px}
.legend div{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--ink2);font-weight:600}
.legend .lsw{display:inline-block;width:13px;height:13px;border-radius:50%;flex:none;background:var(--ink2);border:2px solid #fff;box-shadow:0 0 0 1px var(--line2);box-sizing:border-box}
.legend .lsw.line{border:none;height:0;border-top:3px solid var(--ink);border-radius:0;width:18px;box-shadow:none;background:none}
.legend .lsw.cd{background:#fff;border:2px solid var(--line2);box-shadow:none}
.map-fail{position:absolute;inset:0;z-index:8;background:#fff;display:none;flex-direction:column;padding:18px;overflow:auto}
body[data-map="fail"] .map-fail{display:flex}
body[data-map="fail"] .map-toolbar,body[data-map="fail"] .legend{display:none}
.map-fail .fh{padding-bottom:12px;border-bottom:1px solid var(--line)}
.map-fail .fh b{display:block;font-size:14px;color:var(--red)}
.map-fail .fh p{margin:3px 0 0;font-size:12px;color:var(--ink2)}
.map-fail ol{margin:12px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:2px}
/* 三欄 grid 取代 nowrap：舊版整列 nowrap＋overflow:hidden 會把站名與時間一起攔腰切掉
   （評審實測「臺北101水舞廣場(信義21號廣…」連時間都不見了）。
   現在編號與時間各自固定一欄，站名獨吃中間那一欄並在自己欄內省略，全名放 title。 */
.map-fail ol li{display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:9px;align-items:center;font-size:13px;padding:7px 0;border-bottom:1px dashed var(--line)}
.map-fail ol li .i{width:20px;height:20px;border-radius:50%;background:var(--ink2);color:#fff;font-size:11px;font-weight:700;display:grid;place-items:center;flex:none}
.map-fail ol li .nm{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.map-fail ol li .tm{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
.map-fail .acts{margin-top:14px;display:flex;gap:8px;flex-wrap:wrap}

/* ---------- 手機分頁（現行：頂欄下方一排藥丸，選取為黑） ---------- */
/* 分頁列從畫面頂端搬到底部座艙的最上面一列（2026-08-25）：舊版分頁鈕中心在 y=80、輸入框在 y=770，
   兩個最常用的東西被放在螢幕的兩個極端。現在它就疊在輸入條上方，拇指一次搆得到。 */
.mobile-tabs{display:none;flex:none;height:48px;padding:6px 10px;gap:7px;border-top:1px solid var(--line);background:rgba(250,250,249,.94)}
body[data-vp="mobile"] .mobile-tabs{display:flex}
body[data-vp="mobile"][data-phase="first"] .mobile-tabs{display:none}
.mobile-tabs button{flex:1;border:1px solid var(--line);border-radius:8px;background:#fff;font-weight:600;position:relative;font-size:13px}
.mobile-tabs button.on{background:var(--ink);color:#fff;border-color:var(--ink)}
/* 「這個分頁有新東西」不是錯誤，紅點換成中性圓點；選中的那一顆底色是墨色，圓點跟著翻白才看得見。 */
.mobile-tabs button.has-update::after{content:"";position:absolute;top:7px;right:10px;width:7px;height:7px;border-radius:50%;background:var(--ink);box-shadow:0 0 0 2px #fff}
.mobile-tabs button.on.has-update::after{background:#fff;box-shadow:0 0 0 2px var(--ink)}

/* ---------- 側欄：頂部開新對話、中段紀錄與 App 行程、底部帳號 ---------- */
/* 桌機常駐 260px、可一鍵收成 58px 的圖示欄；手機退回滑入抽屜，開闔時機與舊版逐條相同。 */
.side{position:relative;z-index:41;flex:none;width:260px;display:flex;flex-direction:column;gap:9px;padding:12px 12px 10px;border-right:1px solid var(--line);background:var(--soft);overflow:hidden;transition:width .25s cubic-bezier(.4,0,.2,1)}
body[data-side="off"] .side{width:58px}
/* 遮罩要跟抽屜一起淡進來。display:none 換成 block 的那一格沒有前一個可以內插的狀態，
   所以它在手機上一律 display:block，只是平常 opacity 是 0 且不吃點擊，開闔時只動透明度。 */
.side-scrim{display:none;position:absolute;inset:0;z-index:40;background:rgba(28,25,23,.42);opacity:0;pointer-events:none;transition:opacity .25s cubic-bezier(.4,0,.2,1)}
body[data-vp="mobile"] .side-scrim{display:block}
/* 側欄頂列的兩顆都是純圖示：文字入口在下面的分頁列，這裡再寫一次「對話紀錄」會變成同一句話擠在一起。 */
.side-top{display:flex;align-items:center;gap:6px;min-height:34px}
.side-top .side-icon{width:34px;padding:0;justify-content:center}
/* 收成 58px 圖示欄之後只剩三顆鈕，而「我的 App 行程」這條路整個消失。
   收合態把頂列改直排，時鐘（對話紀錄）下面補一顆手機（App 行程），兩條路都留著。 */
body[data-side="off"] .side-top{flex-direction:column;gap:4px}
body:not([data-side="off"]) #sideTripsButton{display:none}
/* 桌機側欄展開時，左邊常駐的「對話紀錄」分頁就是同一個動作的入口，頂列這顆時鐘按了畫面完全不變。
   寫法比照既有的 #chatHistoryButton：只在真的需要它的狀態顯示。 */
body:not([data-vp="mobile"])[data-side="on"] #historyButton{display:none}
.side-icon{flex:none;display:inline-flex;align-items:center;gap:7px;height:34px;padding:0 10px;border:0;border-radius:8px;background:transparent;color:var(--ink2);font-size:12px;font-weight:600}
.side-icon:hover{background:var(--soft2);color:var(--ink)}
.side-icon .ic{width:16px;height:16px}
.side-close{margin-left:auto;display:none;width:34px;padding:0;place-content:center;font-size:20px;line-height:1}
.side-new{display:flex;align-items:center;gap:8px;width:100%;min-height:38px;padding:8px 11px;border:1px solid var(--line2);border-radius:8px;background:#fff;color:var(--ink);font-size:13px;font-weight:700;text-align:left}
.side-new:hover{border-color:var(--muted)}
.side-new[disabled]{opacity:.45;cursor:default}
.side-new .ic{width:15px;height:15px;flex:none}
/* 未登入時側欄中段是六百多像素的純白，連一句說明都沒有。放一段佔位文字說清楚登入之後這裡會有什麼。 */
/* .dnote 在檔案後面才宣告虛線框，特異性同分時後寫的贏，所以這一條要帶著 .dnote 才蓋得掉。 */
.dnote.side-empty{flex:none;align-self:flex-start;display:block;margin:2px 0;padding:6px 2px;border:0;background:transparent;text-align:left}
body[data-side="off"] .side-empty{display:none}
/* margin-top:auto 讓帳號那一塊永遠貼著側欄底部：登入時中段的清單是 flex:1 本來就撐得滿，
   未登入時清單整個收起來，沒有這一條它會跟著浮到上面去，位置一輪一輪跳。 */
.side-foot{flex:none;margin-top:auto;padding-top:9px;border-top:1px solid var(--line)}
.side-user{display:flex;align-items:center;gap:9px;width:100%;padding:7px 8px;border:0;border-radius:8px;background:transparent;text-align:left}
.side-user:hover{background:var(--soft2)}
.side-user .who{min-width:0;display:flex;flex-direction:column}
.side-user .nm{font-size:13px;font-weight:700;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.side-user .pt{color:var(--muted);font-size:11px;font-weight:600}
body[data-points="low"] .side-user .pt{color:var(--red)}
/* 未登入時側欄只剩這一塊：一句「登入後才會保留」加一顆登入鈕，紀錄與行程一列都不顯示。 */
.loginwall{display:flex;flex-direction:column;align-items:stretch;gap:9px;padding:11px 12px;border:1px dashed var(--line2);border-radius:12px;background:#fff}
.loginwall p{margin:0;color:var(--muted);font-size:12px;line-height:1.6}
.loginwall b{display:block;color:var(--ink);font-size:12px;margin-bottom:2px}
body[data-auth="in"] .loginwall,body[data-auth="pending"] .loginwall{display:none}
/* 未登入時側欄只留登入那一塊：分頁與清單一起收起來，畫面上一列紀錄都不會出現。 */
body:not([data-auth="in"]) #dtabs,body:not([data-auth="in"]) #dlist{display:none}
/* 收合成圖示欄時只留得下圖示：文字、分頁、清單與帳號姓名全部收起來，寬度才真的省得下來。 */
body[data-side="off"] .side .tx,body[data-side="off"] .dtabs,body[data-side="off"] .dlist,body[data-side="off"] .side-user .who,body[data-side="off"] .loginwall p{display:none}
body[data-side="off"] .side-new{justify-content:center;padding:8px 0}
body[data-side="off"] .side-icon{padding:0 9px}
body[data-side="off"] .side-user{justify-content:center;padding:7px 0}
body[data-side="off"] .loginwall{padding:8px;border-style:solid}
.dtabs{display:flex;gap:3px;padding:3px;background:var(--soft2);border:1px solid var(--line);border-radius:8px}
.dtabs button{flex:1;display:flex;align-items:center;justify-content:center;gap:5px;padding:6px;border:0;border-radius:6px;background:transparent;font-size:12px;font-weight:600;color:var(--muted)}
.dtabs button.on{background:var(--ink);color:#fff;box-shadow:none}
.dtabs .num{color:var(--hint);font-weight:600}
.dtabs button.on .num{color:rgba(255,255,255,.72)}
.drawer-list{flex:1;overflow:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:6px;margin:0 -4px;padding:2px 4px}
.dgroup{font-size:12px;font-weight:600;color:var(--muted);letter-spacing:.02em;padding:8px 4px 2px}
.conv{display:flex;align-items:center;gap:6px}
.conv .tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;padding:8px 10px 8px 13px;border:1px solid var(--line);border-radius:8px;background:#fff;text-align:left;cursor:pointer}
.conv .tx:hover{background:var(--soft);border-color:var(--line2)}
/* 品牌藍在這一頁已經同時代表「進行中」「寫入行程」「連結」「時間錨定」「地圖標記」，
   再讓它代表「選中的這一列」就完全失去指涉力。選取改用中性的加深底色。 */
.conv.on .tx{border-color:transparent;background:var(--soft2);box-shadow:none}
.conv .t1{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600}
.conv .t2{color:var(--muted);font-size:11px;display:flex;gap:8px}
/* 刪除鈕不該常駐：它是唯一一個按下去會永久少掉東西的按鈕，卻在每一列都掛著。
   桌機改成滑過或鍵盤聚焦才出現；觸控沒有 hover，維持常駐但放大到 40×40 才點得準。 */
.conv .del{flex:none;width:30px;height:30px;display:grid;place-items:center;border:1px solid var(--line);border-radius:8px;background:#fff;color:var(--muted);cursor:pointer}
body:not([data-vp="mobile"]) .conv .del{opacity:0}
body:not([data-vp="mobile"]) .conv:hover .del,body:not([data-vp="mobile"]) .conv:focus-within .del{opacity:1}
body[data-vp="mobile"] .conv .del{width:40px;height:40px;opacity:1}
.conv .del:hover{border-color:#fecaca;color:var(--red)}
.conv .del svg{width:13px;height:13px}
.dnote{margin:2px 0;padding:12px 14px;border:1px dashed var(--line2);border-radius:12px;background:var(--paper);color:var(--hint);font-size:12px;line-height:1.6;text-align:center}
/* 整列可點：舊版只有列尾那顆實心藥丸能載入，而列上其他地方看起來也像可以按。 */
.trip-row{display:flex;flex-direction:column;gap:7px;padding:10px 11px;border:1px solid var(--line);border-radius:8px;background:#fff;cursor:pointer}
.trip-row:hover{border-color:var(--line2);background:var(--soft)}
.trip-row.on{border-color:var(--line2);box-shadow:inset 4px 0 0 var(--line2)}
.trip-row[data-disabled="1"]{cursor:default}
.trip-row[data-disabled="1"]:hover{border-color:var(--line);background:#fff}
.trip-row .r1{display:flex;align-items:center;gap:8px}
.trip-row .nm{font-size:13px;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.trip-row .src{font-size:11px;font-weight:600;color:var(--ink2);background:var(--soft);padding:1px 7px;border-radius:99px;flex:none;white-space:nowrap}
.trip-row .r3{display:flex;gap:7px}
.trip-row .pill{min-height:30px;padding:4px 11px;font-size:12px}

/* ---------- 衝突對話框（現行 dialog 殼） ---------- */
.modal{position:absolute;inset:0;z-index:50;display:none;align-items:center;justify-content:center;padding:22px}
body[data-modal] #modal{display:flex}
/* 確認框疊在衝突對話框之上：破壞性選項按下去先問一次，兩層都看得見才知道自己在確認什麼。 */
.confirm-modal{z-index:56}
body[data-confirm] #confirmModal{display:flex}
.confirm-modal .mbox{max-width:420px}
.confirm-modal .mh{border-bottom:0;padding:22px 22px 6px}
.confirm-modal .mh p{margin-top:8px;font-size:14px;line-height:1.7}
.confirm-modal .mfoot{border-top:0}
/* 站點彈層的遮罩以前一條規則都沒有，那個節點的尺寸是 0x0：畫面不會變暗、後面不會模糊，
   「點外面關掉」那條既有的監聽也永遠不會被觸發。三件事其實是同一個原因，補上尺寸就一起好了。 */
.modal .scrim,.sheet .scrim{position:absolute;inset:0;background:rgba(28,25,23,.38);backdrop-filter:blur(4px)}
/* 30：確認框疊在衝突對話框上面時，兩層遮罩會把底下那份版本比較糊成一片，使用者正要對照的東西不見了。
   第二層改用更淡的底、也不再模糊，底下那一份仍然讀得到。 */
.confirm-modal .scrim{background:rgba(28,25,23,.18);backdrop-filter:none}
.mbox{position:relative;width:100%;max-width:640px;max-height:100%;background:#fff;border-radius:12px;box-shadow:var(--shadow-lg);display:flex;flex-direction:column;overflow:hidden}
.mbox .mh{padding:20px 22px 14px;border-bottom:1px solid var(--line)}
.mbox .mh .tag{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:600;color:var(--amber);background:var(--amber-soft);padding:3px 9px;border-radius:8px;margin-bottom:8px}
.mbox h2{margin:0;font-size:19px;font-weight:700;letter-spacing:-.3px}
.mbox .mh p{margin:5px 0 0;font-size:13px;color:var(--ink2)}
.mbody{padding:16px 22px;overflow:auto;flex:1;min-height:0}
.vs{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.vcol{border:1px solid var(--line);border-radius:12px;overflow:hidden;min-width:0}
/* 兩份版本的差別靠標題那一句與底色深淺分，不靠色相分：藍色在這一頁已經是連結與焦點的意思。 */
.vcol.mine{border-color:var(--line2)}
.vcol .vh{padding:8px 11px;font-size:12px;font-weight:600;background:var(--soft);display:flex;align-items:center;gap:6px}
.vcol.mine .vh{background:var(--soft2);color:var(--ink)}
.vcol .vh .ago{margin-left:auto;font-weight:600;color:var(--muted);font-size:11px}
.vcol ul{margin:0;padding:9px 11px;list-style:none;display:flex;flex-direction:column;gap:5px}
.vcol li{font-size:12px;color:var(--ink2);display:flex;gap:6px;overflow-wrap:anywhere}
.vcol li svg{margin-top:4px;width:11px;height:11px;color:var(--hint);flex:none;stroke-width:2}
.diffs{margin-top:14px;border:1px solid var(--line);border-radius:12px;overflow:hidden}
.diffs .dt{padding:8px 11px;background:var(--soft);font-size:12px;font-weight:600;color:var(--ink2)}
.diffs .dr{display:flex;gap:9px;padding:9px 11px;font-size:12px;border-top:1px solid var(--line);align-items:flex-start;overflow-wrap:anywhere}
.diffs .dr .sd{font-size:11px;font-weight:600;padding:1px 7px;border-radius:99px;flex:none;margin-top:2px}
.diffs .dr .sd.cloud{background:var(--soft);color:var(--muted)}
.diffs .dr .sd.web{background:var(--soft2);color:var(--ink)}
/* 三個選項改成同寬直排（2026-08-25）：最破壞性的「改用雲端版本」原本是一條貼著主按鈕的全寬細字連結，
   份量看起來比另外兩顆輕，位置卻最近，按下去還沒有任何確認。現在它跟另外兩顆一樣是一顆按鈕，
   上方多留 20px 把它與安全選項隔開，按下去再跳一次確認。 */
.mfoot{padding:13px 22px 16px;border-top:1px solid var(--line);display:flex;flex-direction:column;gap:9px;align-items:stretch;background:var(--paper)}
.mfoot .pill{width:100%}
.mfoot #conflictCloud{margin-top:20px}
/* 破壞性次要鈕：白底紅字紅框，跟主按鈕與一般次要鈕都分得出來，也不會搶走主按鈕的份量。 */
.danger-outline{border-color:#fecaca;color:var(--red)}
.danger-outline:hover{border-color:var(--red)}
.mfoot .sp{width:100%;text-align:left;margin-top:2px;color:var(--muted);font-size:12px}

/* ---------- 設定面板（2026-08-25 Wave D） ---------- */
/* 殼與確認框共用同一組類別（.modal / .scrim / .mbox / .mh / .mfoot），這裡只補分區與列的排版，
   顏色、圓角、陰影、按鈕殼一律沿用既有代幣，沒有為這一片面板新增任何色票。
   z-index 52 夾在衝突對話框（50）與確認框（56）之間：清除紀錄按下去的那一次確認要疊在它上面。 */
.settings-modal{z-index:52}
body[data-settings] #settingsModal{display:flex}
.settings-modal .mbox{max-width:480px}
/* 面板一打開焦點就落在這個框上，讀屏軟體會念出標題，Tab 再依序走進四個區塊；
   它不是一顆按鈕，所以不要畫出鍵盤焦點框，免得看起來像有東西被選中。 */
.settings-modal .mbox:focus{outline:none}
.sbody{display:flex;flex-direction:column}
.sgroup{padding:14px 0}
/* 區塊之間就是既有的那條 1px 分隔線，不另外畫卡片邊框，四個區塊才讀起來像同一張表 */
.sgroup+.sgroup{border-top:1px solid var(--line)}
.sgroup:first-child{padding-top:2px}
.sgroup:last-child{padding-bottom:2px}
.sgroup h3{margin:0 0 8px;font-size:12px;font-weight:600;color:var(--muted);letter-spacing:.02em}
.snote{margin:0 0 10px;font-size:12px;line-height:1.7;color:var(--muted)}
/* 接在某一列底下的補充說明：貼著上面那一列，不要看起來像下一段的開頭 */
.snote.sub{margin:6px 0 0}
.sme{display:flex;align-items:center;gap:10px;margin-bottom:8px;min-width:0}
.sme-t{min-width:0}
.sme-t b{display:block;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sme-t span{display:block;font-size:12px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.srow{display:flex;align-items:center;gap:12px;min-height:30px;font-size:13px}
.srow .slab{flex:1;min-width:0;color:var(--ink2)}
.srow .sval{color:var(--ink);font-weight:600;text-align:right}
.sacts{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
/* 檢視切換那組膠囊本來靠 margin-left:auto 貼在行程頭的最右邊，這裡它是一列的右半邊，不需要那個推力 */
.sseg{margin-left:0;flex:none}
.slink{display:inline-flex;align-items:center;min-height:34px;margin-top:8px;font-size:13px;font-weight:600;color:var(--blue);text-decoration:underline}

/* ---------- 帳號浮層 ---------- */
/* 帳號入口搬進側欄底部，浮層就跟著從左下角長出來，而不是留在右上角指著一個已經不在那裡的按鈕。 */
.pop{position:absolute;left:14px;bottom:66px;z-index:45;width:272px;max-width:calc(100vw - 28px);background:#fff;border:1px solid var(--line2);border-radius:12px;box-shadow:var(--shadow-sm);padding:13px;display:none}
body[data-pop="account"] .pop{display:block}
.pop .u{display:flex;gap:10px;align-items:center;padding-bottom:11px;border-bottom:1px solid var(--line)}
.pop .u>div{min-width:0}
.pop .u b{display:block;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pop .u>div span{font-size:12px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}
.pop .pts{padding:11px 0;border-bottom:1px solid var(--line)}
.pop .pts .r{display:flex;align-items:baseline;gap:7px}
.pop .pts .r b{font-size:20px;font-weight:900;font-variant-numeric:tabular-nums}
.pop .pts .r span{font-size:12px;color:var(--muted)}
.pop .pts p{margin:3px 0 0;font-size:12px;color:var(--muted)}
.pop .acts{display:flex;flex-direction:column;gap:4px;padding-top:9px}
.pop .acts button,.pop .acts a{text-align:left;padding:8px 9px;border:0;border-radius:8px;background:transparent;font-size:13px;font-weight:600;color:var(--ink2);display:flex;align-items:center;gap:8px;text-decoration:none;cursor:pointer}
.pop .acts button:hover,.pop .acts a:hover{background:var(--soft);color:var(--ink)}

/* ---------- Toast ---------- */
/* 舊版釘在畫面正中央底部，正好蓋住送出鈕與追問膠囊（評審量到「已刪除」的橫幅壓在停止鈕上）；
   而且 translateX(-50%) 對的是整個 .app，畫布展開時它會停在畫布底下，指著一個沒有關係的欄位。
   改成靠右、抬到座艙上方，右界跟著 --tripw 走，跟對話欄同一條右邊界。 */
.toast{position:absolute;left:auto;right:24px;bottom:calc(var(--dockh,0px) + 16px);transform:translateY(8px);z-index:60;display:flex;align-items:center;gap:12px;background:var(--ink);color:#fff;padding:10px 16px;border-radius:12px;font-size:13px;font-weight:600;box-shadow:var(--shadow);opacity:0;pointer-events:none;transition:.22s;max-width:calc(100% - 32px)}
.toast.on{opacity:1;transform:translateY(0)}
body[data-canvas="on"] .toast{right:calc(var(--tripw) + 24px)}
/* 帶動作的 toast（目前只有刪除對話的「復原」）：它必須真的按得到，所以這一顆要打開 pointer-events。 */
.toast.on .toast-act{pointer-events:auto}
.toast-act{flex:none;padding:3px 10px;border:1px solid rgba(255,255,255,.45);border-radius:8px;background:transparent;color:#fff;font-size:12px;font-weight:600;cursor:pointer}
.toast-act:hover{background:rgba(255,255,255,.16)}

/* ---------- 登入對話框（現行） ---------- */
dialog{width:min(420px,calc(100vw - 32px));padding:30px;border:0;border-radius:12px;box-shadow:var(--shadow-lg);text-align:center;font-family:inherit}
dialog::backdrop{background:rgba(28,25,23,.38);backdrop-filter:blur(4px)}
.dialog-close{position:absolute;right:14px;top:10px;border:0;background:transparent;font-size:24px;cursor:pointer;color:var(--ink2)}
.dialog-icon{display:block;width:48px;height:48px;margin:0 auto;border-radius:12px}
dialog h2{margin:12px 0 6px}dialog p{color:var(--muted)}dialog small{display:block;margin-top:16px;color:var(--muted)}dialog a{text-decoration:underline}
#googleButton{min-height:44px;display:flex;justify-content:center;margin-top:18px}
.warning{padding:9px;border-radius:8px;background:var(--amber-soft);color:var(--amber);font-size:12px}
noscript{display:block;padding:90px 20px;text-align:center}

/* ---------- 互動回饋（2026-08-25 Wave B 收斂） ---------- */
/* 丁14：全檔原本一條 :active 都沒有。滑鼠使用者還有 hover 可以看，觸控使用者從按下去到畫面真的有反應
   之間完全沒有回饋，在等後端的那一兩秒裡會以為自己沒按到而重複點。按住時縮到 96%、放開就彈回；
   刻意不掛過場，回饋才是即時的，不會讓人覺得按鈕比手指慢半拍。 */
.pill:active,.send:active,.examples button:active,.chip:active,.opt:active{transform:scale(.96)}
/* 丁15：hover 漏網的三處。日分頁與檢視切換的未選取項原本滑過去毫無變化，看起來像不能按；
   :not(.on) 讓已選取的那一顆維持自己的實心配色，不會被這條洗掉。 */
.day-tabs button:not(.on):hover,.seg button:not(.on):hover{color:var(--ink)}
/* 登入彈層右上角的關閉鈕原本只是一個裸的 × 字，補一塊底色讓它的可按範圍看得出來；圓角吃第 8px 那一階。 */
.dialog-close:hover{color:var(--ink);background:var(--soft);border-radius:8px}
/* 頂欄的點數鈕（#chip-pt）查過 JS 確認真的可以按——它開帳號浮層——所以它要跟其他按鈕一樣說得出
   「我可以被按」。點數不足時的紅框寫在 body[data-points="low"] .credits，特異性比這條高，警示狀態不會被洗掉。 */
.credits:hover{border-color:var(--muted);color:var(--ink)}
/* 丁17：有 hover 換色的按鈕殼補上同一條過渡。舊版顏色是瞬間跳的，而同一頁上有些元件有過場、有些沒有，
   看起來像兩套元件混在同一個介面裡。只過渡顏色不過渡位移，上面那條 :active 因此仍然是即時的。 */
.pill,.icon-button,.side-icon,.tb-menu,.opt,.chip,.dialog-close,.day-tabs button,.seg button,.examples button,.credits{transition:background-color .15s,border-color .15s,color .15s}

/* ---------- 手機（body[data-vp=mobile] 由 JS 依 900px 判定） ---------- */
/* 對話欄的下緣已經被 --dockh 抬到座艙上方，這顆浮鈕只要離對話欄底部一點距離就好。
   54px 是為了讓開「↓ 回到最新」：那一顆用負上緣把自己疊回訊息流底部，兩顆都置中，
   距離太近會直接疊在一起，變成兩顆互相看不清楚的藥丸。
   done 也要留著它：行程剛排好的那一刻正是最想過去看的時候，舊版偏偏在那一刻讓它消失。 */
.peek{display:none;position:absolute;left:50%;bottom:54px;transform:translateX(-50%);z-index:15;background:var(--ink);color:#fff;border:0;border-radius:8px;padding:8px 15px;font-size:12px;font-weight:600;box-shadow:var(--shadow);white-space:nowrap}
body[data-vp="mobile"][data-mtab="agent"][data-phase="running"] .peek,body[data-vp="mobile"][data-mtab="agent"][data-phase="clarify"] .peek,body[data-vp="mobile"][data-mtab="agent"][data-phase="done"] .peek{display:block}
body[data-vp="mobile"] .topbar{padding:env(safe-area-inset-top,0px) 12px 0;height:calc(56px + env(safe-area-inset-top,0px))}
/* 手機的頂欄高 4px，斷線條的落點跟著往下 */
body[data-vp="mobile"] .netbar{top:calc(56px + env(safe-area-inset-top,0px))}
body[data-vp="mobile"] .tb-title{display:none}
/* 「下載 App」在手機上不再消失，而是被搬進側欄底部（同一個節點，syncVp 依視窗寬度換家）。 */
.side-foot .tb-app{width:100%;margin-top:9px}
body[data-side="off"] .side-foot .tb-app{display:none}
/* 手機上左上角那顆 ☰ 是唯一的側欄入口，要放大到 44×44 才符合觸控目標尺寸。 */
body[data-vp="mobile"] .tb-menu{width:44px;height:44px}
body[data-vp="mobile"] .tb-menu .ic{width:20px;height:20px}
/* 對話欄裡再放一顆 ☰ 是同一個動作的第二個入口：桌機有常駐側欄、手機有左上角那顆，兩邊都不需要它。 */
#chatHistoryButton{display:none}
body[data-vp="mobile"] .pill{padding:7px 12px}
/* 39：手機上的觸控目標。評審量到分頁鈕 36px、送出鈕 36px、日分頁 27px，都低於 44px 的下限，
   而這幾顆正好是使用者最常按的。座艙長高由 ResizeObserver 寫回 --dockh 自動吸收，版面不必手改。 */
body[data-vp="mobile"] .mobile-tabs{height:56px}
body[data-vp="mobile"] .mobile-tabs button{min-height:44px}
body[data-vp="mobile"] .send,body[data-vp="mobile"] .compact .send{width:44px;height:44px}
body[data-vp="mobile"] .compact .send{font-size:22px}
body[data-vp="mobile"] .composer-foot .tool{width:44px;height:44px}
body[data-vp="mobile"] .day-tabs button,body[data-vp="mobile"] .dtabs button{min-height:40px}
body[data-vp="mobile"] .wb{display:block}
body[data-vp="mobile"] .pane{position:absolute;inset:0;border:none}
/* 手機一次只看得到一個分頁：畫布不滑動也不縮對話欄，三分頁行為與舊版逐條相同。 */
body[data-vp="mobile"] .pane.agent{right:0}
body[data-vp="mobile"] .pane.trip{width:auto;min-width:0;transform:none;transition:none}
body[data-vp="mobile"] .canvas-handle{display:none}
body[data-vp="mobile"] .pane.agent,body[data-vp="mobile"] .pane.trip{display:none}
body[data-vp="mobile"][data-mtab="agent"] .pane.agent,body[data-vp="mobile"][data-phase="first"] .pane.agent{display:flex}
body[data-vp="mobile"][data-mtab="trip"] .pane.trip,body[data-vp="mobile"][data-mtab="map"] .pane.trip{display:flex}
/* 三個分頁都停在座艙上方：輸入條與停止鈕住在座艙裡，所以不論看哪一頁都按得到。
   .pane 在手機是 inset:0，要在這裡把下緣重新抬起來。 */
body[data-vp="mobile"] .pane.agent,body[data-vp="mobile"] .pane.trip{bottom:var(--dockh,0px)}
body[data-vp="mobile"] .dock{right:0}
body[data-vp="mobile"] .trip-body{grid-template-columns:1fr}
body[data-vp="mobile"] .seg{display:none}
/* .seg 被藏起來之後 #saveButton 失去右錨，會漂到日分頁旁邊的正中央。 */
body[data-vp="mobile"] #saveButton{margin-left:auto}
body[data-vp="mobile"] .trip-head{min-height:48px;padding:6px 12px;gap:8px}
body[data-vp="mobile"] .trip-status{padding:6px 12px}
body[data-vp="mobile"] .trip-status #saveStatus{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
body[data-vp="mobile"] .hero{padding:20px 16px 24px}
body[data-vp="mobile"] h1{letter-spacing:-.6px;font-size:24px;line-height:1.3}
body[data-vp="mobile"] .quick{grid-template-columns:1fr}
body[data-vp="mobile"] .examples{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}
body[data-vp="mobile"] .examples button{padding:9px 10px;white-space:normal}
body[data-vp="mobile"] .hero-composer{padding:13px 13px 9px}
body[data-vp="mobile"] .composer textarea{font-size:16px}
body[data-vp="mobile"] .visual{padding:10px}
body[data-vp="mobile"] .vs{grid-template-columns:1fr}
body[data-vp="mobile"] .modal{padding:14px}
/* 手機：側欄退回滑入抽屜。它是 .app 的第一個 flex 子元素，所以要拉出流外絕對定位，
   再用 transform 滑進滑出；data-drawer 由 toggleDrawer 掛在 body 上，開闔時機與舊版一樣。 */
body[data-vp="mobile"] .side{position:absolute;top:0;left:0;bottom:0;width:min(320px,86vw);box-shadow:var(--shadow-lg);transform:translateX(-102%);transition:transform .25s cubic-bezier(.4,0,.2,1);padding-top:calc(12px + env(safe-area-inset-top,0px));padding-bottom:calc(10px + env(safe-area-inset-bottom,0px))}
body[data-vp="mobile"][data-side="off"] .side{width:min(320px,86vw)}
body[data-vp="mobile"][data-drawer] .side{transform:translateX(0)}
body[data-vp="mobile"][data-drawer] .side-scrim{opacity:1;pointer-events:auto}
body[data-vp="mobile"] .side-close{display:grid}
body[data-vp="mobile"] .pop{left:12px;right:12px;width:auto;bottom:76px}
/* 手機的行程是一個分頁而不是滑入的畫布，--tripw 在這裡沒有意義，右界改回貼著螢幕邊 */
body[data-vp="mobile"] .toast,body[data-vp="mobile"][data-canvas="on"] .toast{right:16px;left:16px;max-width:none}
body[data-vp="mobile"] .wl-top .n{display:none}
body[data-vp="mobile"] .growing{margin-left:80px}
/* 手機上的設定面板鋪滿整個螢幕：內容一次讀得完、不必在一個小框裡再捲一層。
   上緣讓開瀏海、下緣讓開系統手勢區，關閉鈕才不會被那條橫槓蓋住；
   面板裡每一顆按得到的東西都做到 44px，那是單手拇指點得準的下限。 */
body[data-vp="mobile"] .settings-modal{padding:0}
body[data-vp="mobile"] .settings-modal .mbox{max-width:none;height:100%;max-height:none;border-radius:0}
body[data-vp="mobile"] .settings-modal .mh{padding-top:calc(20px + env(safe-area-inset-top,0px))}
body[data-vp="mobile"] .settings-modal .mfoot{padding-bottom:calc(16px + env(safe-area-inset-bottom,0px))}
body[data-vp="mobile"] .settings-modal .pill,body[data-vp="mobile"] .settings-modal .slink{min-height:44px}
/* 行程頭那組檢視切換在手機上是被三個分頁取代的，所以上面有一條 body[data-vp="mobile"] .seg{display:none}。
   設定面板裡這一組是動畫效果的兩個選項，跟檢視無關，要把 display 補回來，否則它整組看不見。 */
body[data-vp="mobile"] .settings-modal .seg{display:flex;height:auto;padding:3px}
body[data-vp="mobile"] .settings-modal .seg button{min-height:44px}
/* 標籤與那組膠囊在 390 寬並排會把「跟隨系統設定」擠成兩行，改成上下兩層，膠囊各佔一半 */
body[data-vp="mobile"] .srow-set{flex-direction:column;align-items:stretch;gap:8px}
body[data-vp="mobile"] .sseg{width:100%}
body[data-vp="mobile"] .sseg button{flex:1}

/* 舊版是一份手寫的白名單，每加一個元件就要記得回來補一行——結果座艙、分隔軸、遮罩、Toast
   全部漏掉，評審量到減少動態開著時 #dock 與對話欄之間差了 613px 才追上。
   改成全域規則之後不必再維護名單：任何過場與動畫都收到 0.01ms，位置與可見性照舊，
   只有「會動」這件事被拿掉。0.01ms 而不是 none，是為了讓 transitionend／animationend 照樣會來，
   靠它們收尾的程式（例如 FLIP 收 inline style）不會卡在半路。
   2026-08-25（Wave D）：關掉動態的入口從一個變成兩個——系統的 prefers-reduced-motion，
   以及使用者在設定面板選的「動畫效果一律關閉」。CSS 沒有辦法讓一個媒體查詢與一個屬性選擇器共用
   同一組宣告，複製成兩份又遲早會各自漂移，所以把判斷收進 JS：syncMotion() 把「系統說要減少」
   或「使用者自己關掉」兩件事的結果一起寫進 body[data-motion]，宣告就只留這一份。
   JS 端的 reduceMotion()（FLIP 與淡入自己算幀的那幾段）讀的也是同一個屬性，兩邊不會各說各的。 */
body[data-motion="off"] *,body[data-motion="off"] *::before,body[data-motion="off"] *::after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}
/* 保底：上面那條靠 JS 寫 body[data-motion]，這一份直接認系統偏好，JS 沒跑起來時仍然成立。
   面板沒有「強制開啟動畫」這個選項，所以兩者並存不會互相打架。 */
@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}


/* ==============================================================================
   行程時間軸 v2：對標旅尋 App 的 ItinerarySheet / StopRow / LegRow
   1.骨架改成「左時間欄 52px ＋ 垂直軌道欄 44px ＋ 右卡片」三欄 grid，跟 App 的時間軸同一套讀法：
     先看幾點到，再看軌道上的節點，最後才看卡片內容。
   2.顏色一律用本檔第 1 行既有的 CSS 變數，不引入新色相。photoTone 由 JS 以 inline background
     寫在 .stop-tone 上，本檔只補 App Photo 元件那層斜紋與明暗覆蓋，不決定色票。
   3.圖示不引外部資源：直接內嵌 app-ui.jsx ICON_PATHS 的同一組 Lucide 線條成 SVG data URI 當遮罩，
     再用 background-color 上色，所以圖示顏色永遠跟著 --muted 走，不會多出第二個高飽和色。
   ============================================================================== */

/* 遮罩圖示來源：路徑逐字取自 app-ui.jsx 的 ICON_PATHS（car / walk / train / scooter / navigation / bed / cornerLeft），
   保持 viewBox 0 0 24 24、stroke-width 2、圓端圓角，跟 App 的 Icon 元件同形。transit 取 train（電車），
   它在 15px 尺寸下比 bus 好辨識，兩者都在 App 既有圖示集內，不算臨時手繪。 */
:root{--ic-drive:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 17h14 M3 17v-5l2.5-5h13L21 12v5 M7 17v2 M17 17v2 M6.5 12h11'/%3E%3C/svg%3E");--ic-walk:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13 4m-1.5 0a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0 M11 21l1.5-5 2 2v4 M9 11l3.5-2 2 3 2.5 1 M8 14l1.5-3'/%3E%3C/svg%3E");--ic-transit:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 4h14a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z M4 11h16 M8 16l-2 4 M16 16l2 4 M8.5 7.5h.01 M15.5 7.5h.01'/%3E%3C/svg%3E");--ic-moto:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 16m-2 0a2 2 0 1 0 4 0a2 2 0 1 0-4 0 M19 16m-2 0a2 2 0 1 0 4 0a2 2 0 1 0-4 0 M5 16h9l3-7h-3 M14 16l1.5-9H18 M7 9h5'/%3E%3C/svg%3E");--ic-move:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 11l19-9-9 19-2-8-8-2z'/%3E%3C/svg%3E");--ic-bed:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 4v16 M2 8h18a2 2 0 0 1 2 2v10 M2 17h20 M6 8v9'/%3E%3C/svg%3E");--ic-return:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 4v8a3 3 0 0 1-3 3H8 M11 12l-4 3 4 3'/%3E%3C/svg%3E");--ic-home:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 9.5l9-6.5 9 6.5V20a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z M9.5 22v-8h5v8'/%3E%3C/svg%3E")}

/* ── 覆蓋既有 .stop 系列的集中區塊 ──────────────────────────────────────────────
   舊規則一條都沒有刪，只用更特定的選擇器蓋掉，理由逐條列在下面：
   1.`.stop{margin-left:14px;padding-left:25px;border-left:2px solid}`：舊版把軌道畫在 .stop 自己的左邊界上。
     新結構的軌道要畫在中間那欄的 .stop-visual 裡，兩者並存會出現兩條平行線，而且左內距會把整張卡片再往右推 39px。
   2.`.stop:last-child{border-left-color:transparent}`：上一條的配套，border 歸零後它就沒有作用對象了，留著不影響。
   3.`.stop-title{display:flex;gap:8px}` 與 `.stop-title time`：舊版把時間塞在標題列裡。新契約時間移到獨立的
     .stop-time 欄，標題列只剩名稱與徽章，需要改成 baseline 對齊並允許換行，否則長店名會把徽章擠出卡片。
   4.`.stop-badges{margin-top:6px}`：徽章從卡片第二行搬進標題列後，那 6px 上緣間距會讓它跟名稱錯開一行高度。
   5.`.stop.changed .stop-card`（含 stop-flash 動畫）：卡片節點從 .stop-card 改名為 .stop-body，
     動畫本體沿用同一組 stop-flash keyframes，只是重新掛到新節點上，不新增動畫。
   6.`.day-heading{justify-content:space-between}`：子元素從兩個變三個，space-between 會把「出發」膠囊
     甩到正中央，改成讓 .day-count 用 margin-left:auto 靠右、膠囊緊貼標題。
   ────────────────────────────────────────────────────────────────────────────── */
.timeline .day .stop{position:relative;display:grid;grid-template-columns:52px 44px minmax(0,1fr);margin:0;padding:0;border-left:0}
.timeline .day .stop .stop-title{display:flex;align-items:baseline;flex-wrap:wrap;gap:5px 7px}
.timeline .day .stop .stop-title .stop-badges{margin-top:0}
.timeline .day .stop.changed .stop-body{animation:stop-flash 1.1s ease-out;border-color:var(--line2)}
.timeline .day-heading{justify-content:flex-start}

/* 乙3：日標題列改成貼在畫布頂端的 sticky 區塊標頭。使用者往下捲第七、第八站的時候，
   「現在看的是第幾天、幾點出發、幾個地點」不會被捲走，這一天才真的是一個看得出邊界的區塊。
   左右的負邊距是為了讓底色鋪滿整條畫布（時間軸自己有 16px 內距），
   否則捲上去的卡片會從標頭兩側的縫隙露出來。 */
.timeline .day-heading{position:sticky;top:0;z-index:3;align-items:center;flex-wrap:wrap;gap:8px;margin:0 -16px 14px;padding:10px 16px 9px;background:var(--card);border-bottom:1px solid var(--line)}
/* 標題在窄欄裡會被那幾顆 flex:none 的膠囊擠到剩一個字寬，然後逐字換行；固定住它，換行交給整列 wrap。 */
.timeline .day-heading h3{flex:none;margin:0;font-size:16px;font-weight:700;letter-spacing:-.2px;white-space:nowrap}
/* 出發時間原本是一顆藍底藍字的膠囊，那是一天裡最亮的一塊，可是它只是一個時間。
   改成中性底的小標，時間本身用等寬數字，跟時間欄的讀法一致。 */
.timeline .day-heading .day-depart{flex:none;padding:3px 9px;border-radius:8px;background:var(--soft);color:var(--ink2);font-size:11px;font-weight:600;letter-spacing:.02em;font-variant-numeric:tabular-nums;white-space:nowrap}
.timeline .day-heading .day-count{flex:none;margin-left:auto;color:var(--muted);font-size:12px;font-weight:600;white-space:nowrap}
.timeline .day-heading .day-depart:empty,.timeline .day-heading .day-count:empty{display:none}

/* 時間欄：抵達時間靠右貼著軌道，等寬數字讓一整排時間的冒號對齊；時段標（上午／午餐／傍晚）
   降一級放在時間下方。時間未知時（.unknown）只降成 hint 灰，不換成別的符號，保持欄寬穩定。 */
.timeline .day .stop-time{grid-column:1;align-self:start;padding:9px 9px 0 0;text-align:right}
.timeline .day .stop-time .arrive{display:block;color:var(--ink);font-size:14px;line-height:1.2;font-weight:700;letter-spacing:.2px;font-variant-numeric:tabular-nums}
.timeline .day .stop-time .arrive.unknown{color:var(--hint);font-weight:600}
.timeline .day .stop-time .slot{display:block;margin-top:3px;color:var(--muted);font-size:11px;line-height:1.3;font-weight:600}
.timeline .day .stop-time .slot:empty{display:none}

/* 垂直軌道與節點：軌道畫在 .stop-visual 的偽元素上，因為這一欄預設 stretch 會撐滿整列高度，
   線就能從卡片頂一路連到卡片底，再由下一個 .leg-row 接續，視覺上是一條不斷的軌道。
   節點是 40x40 圓角 10 的 photoTone 色塊（尺寸比照 App PeekStrip 的 Photo w=40 h=40 radius=10），
   外圈用卡片色的 3px 光暈把軌道切斷，讓色塊看起來是壓在線上而不是被線穿過。
   色塊自己的底色來自 JS 的 inline style，這裡只在上層疊 App Photo 元件那層 135 度斜紋與上下明暗，
   沒有 inline 色時退回 --line2，不會出現透明破洞。 */
.timeline .day .stop-visual{grid-column:2;position:relative;display:flex;justify-content:center}
.timeline .day .stop-visual::before{content:"";position:absolute;top:0;bottom:0;left:50%;width:2px;transform:translateX(-50%);background:var(--line)}
.timeline .day .stop:last-of-type .stop-visual::before{display:none}
.timeline .day .stop-tone{position:relative;z-index:1;align-self:flex-start;display:grid;place-items:center;width:40px;height:40px;overflow:hidden;border-radius:10px;background:var(--line2);box-shadow:0 0 0 3px var(--card)}
.timeline .day .stop-tone::before{content:"";position:absolute;inset:0;background:repeating-linear-gradient(135deg,rgba(0,0,0,0) 0 7px,rgba(0,0,0,.07) 7px 14px),linear-gradient(180deg,rgba(255,255,255,.10),rgba(0,0,0,.18))}
.timeline .day .stop-tone::after{content:attr(data-initial);position:relative;z-index:1;color:rgba(255,255,255,.92);font-size:16px;line-height:1;font-weight:700;text-shadow:0 1px 2px rgba(0,0,0,.35)}
/* 住宿與回程不是「去玩的地點」，節點換成語義圖示而不是站名首字：住宿用床、回程用返回箭頭，
   兩個都是 App 既有圖示（bed / cornerLeft）。沒有 photoTone 時退回 --ink2，白色圖示才有足夠對比。 */
.timeline .day .stop.is-lodging .stop-tone,.timeline .day .stop.is-return .stop-tone{background:var(--ink2)}
.timeline .day .stop.is-lodging .stop-tone::after,.timeline .day .stop.is-return .stop-tone::after{content:"";width:21px;height:21px;background-color:rgba(255,255,255,.94);text-shadow:none;filter:drop-shadow(0 1px 1px rgba(0,0,0,.28))}
.timeline .day .stop.is-lodging .stop-tone::after{-webkit-mask:var(--ic-bed) center/21px 21px no-repeat;mask:var(--ic-bed) center/21px 21px no-repeat}
/* 回程終點是「回到出發地」，用房子比用回頭箭頭直觀；--ic-home 與同組圖示一樣是內嵌遮罩，沒有外部資源。 */
.timeline .day .stop.is-return .stop-tone::after{-webkit-mask:var(--ic-home) center/21px 21px no-repeat;mask:var(--ic-home) center/21px 21px no-repeat}
/* 終點卡是一天的收尾，不是又一個要去的地點：用虛線描邊與淺底跟前面的站區隔，
   讓使用者一眼看出「行程到這裡結束」，而不是以為多排了一站。 */
.timeline .day .stop.is-return .stop-body{background:var(--soft);border-style:dashed}

/* 卡片：白底、1px 線框、圓角 12、內距 10/12，跟 App 的 StopRow 卡片同一個殼。
   下緣的 8px 用 margin 而不是 .stop 的 padding，因為 grid 項目的 margin 會撐高整列，
   軌道那一欄才會跟著長出來把這 8px 也蓋住，不然軌道會在每張卡片之間斷一節。 */
.timeline .day .stop-body{grid-column:3;min-width:0;margin-bottom:8px;padding:12px 14px;border:1px solid var(--line);border-radius:12px;background:var(--card);box-shadow:0 1px 3px rgba(28,25,23,.05)}
.timeline .day .stop-body .name{color:var(--ink);font-size:14px;line-height:1.4;font-weight:600;letter-spacing:-.2px;overflow-wrap:anywhere}
.timeline .day .stop-body .stop-meta{margin-top:4px;color:var(--muted);font-size:12px;line-height:1.5;overflow-wrap:anywhere}
.timeline .day .stop-body .stop-meta:empty{display:none}
/* 備註是智能體或使用者補的說明，不是地點事實，用 hairline 隔開並升一階字色，比照 App 卡片的頁腳分隔線 */
.timeline .day .stop-body .stop-note{margin-top:7px;padding-top:7px;border-top:1px solid var(--line);color:var(--ink2);font-size:12px;line-height:1.5;overflow-wrap:anywhere}
.timeline .day .stop-body .stop-note:empty{display:none}

/* 路段列：縮排 96px（52+44）對齊卡片欄，軌道段落改成 App LegRow 的虛線連接器，
   實線代表「停在這個地點」、虛線代表「在移動」，兩段接起來仍是一條連續的軌道。
   圖示用 data-mode 切換遮罩，沒有對應 mode 時退回 navigation 箭頭，不會變成空白。 */
.timeline .day .leg-row{position:relative;display:flex;align-items:center;gap:6px;min-height:28px;padding:4px 0 4px 96px}
.timeline .day .leg-row::before{content:"";position:absolute;top:0;bottom:0;left:74px;width:2px;transform:translateX(-50%);background:repeating-linear-gradient(var(--line2) 0 4px,transparent 4px 8px)}
.timeline .day .leg-row .leg-icon{flex:none;width:16px;height:16px;background-color:var(--muted);-webkit-mask:var(--ic-move) center/16px 16px no-repeat;mask:var(--ic-move) center/16px 16px no-repeat}
.timeline .day .leg-row .leg-icon[data-mode=drive]{-webkit-mask-image:var(--ic-drive);mask-image:var(--ic-drive)}
.timeline .day .leg-row .leg-icon[data-mode=walk]{-webkit-mask-image:var(--ic-walk);mask-image:var(--ic-walk)}
.timeline .day .leg-row .leg-icon[data-mode=transit]{-webkit-mask-image:var(--ic-transit);mask-image:var(--ic-transit)}
.timeline .day .leg-row .leg-icon[data-mode=moto],.timeline .day .leg-row .leg-icon[data-mode=scooter]{-webkit-mask-image:var(--ic-moto);mask-image:var(--ic-moto)}
.timeline .day .leg-row .leg-text{min-width:0;color:var(--muted);font-size:12px;line-height:1.4;font-weight:600;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
/* 交通時間還沒算出來時用虛線膠囊，跟已算好的實心文字明顯不同，使用者一眼知道這是缺口不是零分鐘。
   文字由 JS 給；萬一給了空節點，:empty 會補上預設字，不讓它變成看不見的空白膠囊。 */
.timeline .day .leg-row .leg-missing{display:inline-flex;align-items:center;padding:2px 9px;border:1px dashed var(--line2);border-radius:99px;color:var(--hint);font-size:12px;line-height:1.5;font-weight:600;white-space:nowrap}
.timeline .day .leg-row .leg-missing:empty::after{content:"交通時間待算"}
/* 契約裡 .leg-row 是 .stop 的兄弟節點，上面的縮排是照這個算的。萬一 JS 改成塞在 .stop 裡面，
   它會變成 grid 項目掉進第一欄（只有 52px）而爆版，這條讓它橫跨三欄，縮排與軌道位置就跟兄弟節點時一致。 */
.timeline .day .stop>.leg-row{grid-column:1/-1}
/* 一天的最後一個節點是站點不是路段；真的出現尾端多一條 leg 時，把那截沒有接續對象的虛線收掉 */
.timeline .day>.leg-row:last-child::before{display:none}

/* 過渡相容：JS 換 DOM 之前舊節點還在頁面上，上面的 grid 會讓它們自動落位到錯誤的欄。
   這三條只是把舊節點放回對的欄，讓新舊兩版 DOM 都能正常顯示，等舊節點真的消失後這一段自然失效。 */
.timeline .day .stop>.stop-number{position:static;grid-column:2;align-self:start;justify-self:center;margin-top:7px}
.timeline .day .stop>.stop-card{grid-column:3;margin-bottom:8px}
.timeline .day .stop>.route-note{grid-column:3}

/* 手機：欄寬縮成 44/36，節點跟著縮到 34px 仍留得下 3px 光暈；卡片內距縮一階。
   .leg-row 的縮排與軌道位置是絕對值，必須在這裡重算（44+36=80、44+36/2=62）。 */
@media(max-width:1100px){
.timeline .day .stop{grid-template-columns:44px 36px minmax(0,1fr)}
.timeline .day .stop-time{padding:8px 7px 0 0}
.timeline .day .stop-time .arrive{font-size:12px}
.timeline .day .stop-tone{width:34px;height:34px;border-radius:8px}
.timeline .day .stop-tone::after{font-size:13px}
.timeline .day .stop.is-lodging .stop-tone::after,.timeline .day .stop.is-return .stop-tone::after{width:18px;height:18px;-webkit-mask-size:18px 18px;mask-size:18px 18px}
.timeline .day .stop-body{padding:10px 12px}
.timeline .day .stop-body .name{font-size:14px}
.timeline .day .leg-row{padding-left:80px}
.timeline .day .leg-row::before{left:62px}
.timeline .day .stop>.stop-number{margin-top:5px}
}

/* 減少動態偏好：本段唯一的新動畫是掛到 .stop-body 的 stop-flash，比照本檔既有慣例關掉動畫、
   直接停在淡藍底表達「這一站剛被改過」，狀態訊息不會因為關動畫而消失。 */
/* 剛改過的站原本靠一段淡出的高亮標示自己。關掉動態時它需要一個靜態的替代，否則使用者只看得到
   一格閃一下就沒了。判斷同樣走 body[data-motion]，與上面那條全域規則同一個開關。 */
body[data-motion="off"] .timeline .day .stop.changed .stop-body{animation:none;background:var(--soft2)}
@media(prefers-reduced-motion:reduce){.timeline .day .stop.changed .stop-body{animation:none;background:var(--soft2)}}


/* ==============================================================================
   真照片上卡與地點詳情彈層（2026-08-24）
   1.照片走後端 GET /places/photo 的圖片位元組分支，前端只是一個普通的 <img>：
     沒有 fetch、沒有 blob、沒有 crossorigin，瀏覽器自己帶同站 cookie，也自己吃 HTTP 快取。
   2.色塊不是被照片取代，而是被照片蓋住：.stop-tone 的底色、斜紋與首字全部原地留著，
     只有 <img> 真的 load 成功才加上 .has-photo 把它們藏起來。載入失敗時 JS 直接把 <img> 移除，
     畫面就自動回到色塊＋首字那一版，永遠不會出現破圖框。
   3.照片是裝飾不是資訊（站名就在右邊卡片上），所以 alt 一律空字串，不讓讀屏軟體念兩次同一個名字。
   ============================================================================== */
.timeline .day .stop-tone .photo{position:absolute;inset:0;z-index:2;display:block;width:100%;height:100%;object-fit:cover}
/* 這兩條要贏過上面「住宿／回程換成床鋪與房子圖示」那組規則，所以刻意多帶一個 .stop 湊到同樣的
   特異性，再靠檔案順序後來居上；有真照片時就顯示真照片，不再蓋一個語義圖示上去。 */
.timeline .day .stop .stop-tone.has-photo::before,.timeline .day .stop .stop-tone.has-photo::after{display:none}

/* 地點詳情彈層：沿用衝突對話框那一套殼（絕對定位在 .app 內、遮罩加模糊、白底大圓角），
   所以視覺語言與現行卡片一致，沒有引進第二種浮層樣式。
   刻意用 role="dialog" 而不是 <dialog>：這一層只是把使用者點的那一站攤開來看，
   不需要焦點陷阱，也不該把鍵盤焦點從時間軸上搶走。 */
/* 收在旁邊而不是 display:none，淡入才有前一個狀態可以內插。visibility 刻意不做內插而是用延遲切換：
   開啟時 0s 立刻變成 visible（同一格就 focus 得到裡面的關閉鈕），關閉時等淡出跑完才收走，
   收走之後它自然退出鍵盤 Tab 序，不必再多掛一次 inert。 */
.sheet{position:absolute;inset:0;z-index:52;display:flex;align-items:center;justify-content:center;padding:22px;opacity:0;visibility:hidden;pointer-events:none;transition:opacity .18s cubic-bezier(.4,0,.2,1),visibility 0s linear .18s}
body[data-sheet] .sheet{opacity:1;visibility:visible;pointer-events:auto;transition:opacity .18s cubic-bezier(.4,0,.2,1),visibility 0s}
.sheet-box{position:relative;width:100%;max-width:400px;max-height:100%;overflow:auto;background:#fff;border-radius:12px;box-shadow:var(--shadow-lg)}
.sheet-close{position:absolute;right:12px;top:12px;z-index:4;display:grid;place-items:center;width:32px;height:32px;border:0;border-radius:50%;background:rgba(28,25,23,.55);color:#fff;font-size:20px;line-height:1;cursor:pointer}
.sheet-close:hover{background:rgba(28,25,23,.78)}
/* 大圖區的預設狀態就是縮圖那顆色塊的放大版（同一組斜紋與明暗、同一個首字），
   照片載進來才蓋上去。沒有 photoRef 的地點整塊仍然成立，不是一個空洞。 */
.sheet-photo{position:relative;display:grid;place-items:center;height:168px;overflow:hidden;border-radius:12px 12px 0 0;background:var(--line2)}
.sheet-photo::before{content:"";position:absolute;inset:0;background:repeating-linear-gradient(135deg,rgba(0,0,0,0) 0 12px,rgba(0,0,0,.07) 12px 24px),linear-gradient(180deg,rgba(255,255,255,.10),rgba(0,0,0,.18))}
.sheet-photo::after{content:attr(data-initial);position:relative;z-index:1;color:rgba(255,255,255,.92);font-size:44px;line-height:1;font-weight:700;text-shadow:0 2px 6px rgba(0,0,0,.35)}
.sheet-photo .photo{position:absolute;inset:0;z-index:2;display:block;width:100%;height:100%;object-fit:cover}
.sheet-photo.has-photo::before,.sheet-photo.has-photo::after{display:none}
.sheet-main{padding:16px 18px 18px}
.sheet-name{display:block;font-size:19px;font-weight:700;letter-spacing:-.3px;line-height:1.4;overflow-wrap:anywhere}
.sheet-sub{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;margin-top:6px;color:var(--muted);font-size:12px;font-weight:600}
/* 評分維持一顆星圖示，顏色回到中性：星星本身已經說明那是評分，不需要再靠金色說一次。 */
.sheet-sub .rate{display:inline-flex;align-items:center;gap:4px;color:var(--ink2)}
.sheet-sub .rate svg{width:12px;height:12px}
.sheet-rows{display:flex;flex-direction:column;margin-top:12px;border-top:1px solid var(--line)}
.sheet-row{display:flex;gap:10px;padding:10px 0;border-bottom:1px solid var(--line);font-size:13px;line-height:1.5;color:var(--ink2);align-items:flex-start;overflow-wrap:anywhere}
.sheet-row>svg{flex:none;margin-top:2px;color:var(--hint)}
.sheet-row .rv{min-width:0}
.sheet-row a{color:var(--blue);text-decoration:underline;text-underline-offset:3px}
/* 營業時間預設收成一行（2026-08-25）：七行週表把彈層撐掉半個畫面，而使用者要看的只有那一行——
   他去的那一天開不開。想看整週的人按「看整週」才展開，展開時那一天仍然加粗。 */
.sheet-hours{display:flex;flex-direction:column;gap:2px;font-variant-numeric:tabular-nums}
.sheet-hours .hours-head{display:flex;align-items:baseline;gap:8px}
.sheet-hours .hours-today{min-width:0;flex:1}
.sheet-hours .hours-more{flex:none;padding:0;border:0;background:none;color:var(--blue);font-size:12px;font-weight:600;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.sheet-hours .hours-all{display:flex;flex-direction:column;gap:2px;margin-top:6px;padding-top:6px;border-top:1px solid var(--line)}
.sheet-hours span.today{color:var(--ink);font-weight:700}
/* 彈層底部的四條捷徑：使用者點開一站十之八九是想改它，舊版只給名稱、營業時間與一顆外連，是條唯讀死路。 */
.sheet-acts{display:flex;flex-wrap:wrap;gap:7px;margin-top:14px}
.sheet-acts button{min-height:32px;padding:5px 12px;border:1px solid var(--line2);border-radius:8px;background:#fff;color:var(--ink2);font-size:12px;font-weight:600;cursor:pointer}
.sheet-acts button:hover{border-color:var(--muted);color:var(--ink)}
.sheet-acts button[data-act="drop"]{border-color:#fecaca;color:var(--red)}
.sheet-go{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;margin-top:14px;min-height:40px;padding:8px 16px;border:1px solid var(--line2);border-radius:8px;background:#fff;color:var(--ink);font-size:13px;font-weight:700;text-decoration:none}
.sheet-go:hover{border-color:var(--muted)}
body[data-vp="mobile"] .sheet{padding:14px}
body[data-vp="mobile"] .sheet-photo{height:150px}
