/* 地球的樣式。⚠️ 每一條都限定在 #journey 底下——這份會跟網站的樣式放在同一頁，
   沒限定範圍的規則（例如 button、label）會改到導覽列。新增規則時照同樣寫法。
   宿主頁與地球之間的介面見 main.js 開頭。 */
  #journey {
    --ink:#12141a; --paper:#f4f2ec;
    /* 紙色光暈：深色字疊在紙感地圖上時靠它跟底分開。現在只剩回頭那一句（`#back`）在用。
       名牌與選單十三列在 2026-09-18 拿掉、行程層的三行讀數（`#meta`）在 2026-09-24 拿掉，
       兩次都是使用者看過之後判斷光暈讓字變糊。
       ⚠️ **不能有偏移。** 先前每一處都寫 `0 1px 2px`，那 1 px 的垂直偏移讓亮邊
          全部落在字的下緣，讀起來是疊影不是光暈。實測光暈重心比字身低 0.56 px，
          改成對稱之後是 −0.24 px。
       ⚠️ **也不能改用 `-webkit-text-stroke` 描邊。** 地圖自己的地名走的是硬邊光暈
          （`style-toner.json` 的 `text-halo-width: 3`、`blur: 0`），但那是 MapLibre
          在字形**外側**畫的；CSS 的描邊畫在字形的邊線上，中文字在 23 px 下筆畫比
          3 px 還細，外框會把字填實——實測字身最暗的像素從 27 變成 101，等於字沒了。
       同一個 2 px 疊兩次，是因為模糊會把 alpha 攤掉，靠近字的地方要夠不透明。
       外圈那一層各處不同（12／14 px），所以留在各自的規則裡。 */
    --halo-paper: 0 0 2px rgba(250,248,244,.92), 0 0 2px rgba(250,248,244,.92),
                  0 0 3px rgba(250,248,244,.92);
  }
  #journey * { box-sizing: border-box; }
  #journey { position:fixed; inset:0; margin:0; background:#000; overflow:hidden; }
  /* 會繼承的字排屬性一律在這裡定死，地球才不隨宿主變。
     ⚠️ **不定的話，同一份程式在兩個地方長得不一樣，而且兩邊都不報錯**：原型頁沒有
        全域樣式，這些屬性拿的是瀏覽器預設；網站頁的 Tailwind preflight 把它們設在
        `html`，於是繼承下來。2026-09-18 量過繼承起點，三條有差：字型（Times ↔ sans）、
        行高（normal ↔ 1.5）、顏色（純黑 ↔ 深灰）。看得到的症狀是行程層的
        `#mName`／`#mNum` 換了字、高度差 2 px——它們只設了 size 與 weight。
     ⚠️ **字型與行高跟網站的 `font-sans`／`1.5` 同一份**（macOS 上拉丁走 SF、中文落到
        蘋方）。網站換字型時這裡不會自動跟上，症狀是地球裡的字跟導覽列不同套而沒有提示。
     ⚠️ **顏色刻意不跟網站**：走地球自己的 `--ink`，因為看得見的文字都自己指定了顏色，
        這一條只兜底，跟著宿主反而多一條會漂的依賴。
     `-webkit-text-size-adjust` 是手機上的自動放大，不設的話兩邊在實機上會不一樣，
     而那件事在桌機上看不出來。 */
  #journey {
    font-family: ui-sans-serif, system-ui, sans-serif;
    line-height: 1.5;
    color: var(--ink);
    -webkit-text-size-adjust: 100%;
  }
  /* 太空層（星空 skybox + 大氣光暈，見 space.js）鋪在地圖 canvas 之後。
     光暈用 BackSide，從相機看它本來就在地球背面，只有超出輪廓那一圈會露出來——
     放在後面就是正確的層序，不需要 blend mode 硬湊。 */
  #journey #space { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; }
  #journey #map { position:absolute; inset:0; background:transparent; }


  /* 常駐的 zoom 讀數。⚠️ 放右下角而不是面板裡：面板是可以收合的，而這個數字
     在「看效果」的時候最需要，那正是面板被收起來的時候。 */
  #journey .zhud { position:fixed; right:14px; bottom:14px; z-index:9;
    background:rgba(21,23,27,.82); color:#f2efe8; padding:5px 9px; border-radius:6px;
    font:11px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace; letter-spacing:.02em;
    pointer-events:none; white-space:pre; }
  #journey .panel {
    position:absolute; z-index:5; top:14px; left:14px; width:270px;
    background:rgba(248,247,243,.94); color:#15171b; border:1px solid #c9c4b8;
    border-radius:10px; padding:12px 13px;
    font:13px/1.55 -apple-system,"Helvetica Neue",sans-serif;
    box-shadow:0 6px 22px rgba(0,0,0,.35);
  }
  #journey .panel h1 { font-size:13px; margin:0 0 8px; letter-spacing:.02em; }
  #journey .row { display:flex; gap:6px; flex-wrap:wrap; margin-bottom:8px; }
  #journey button {
    font:12px/1 inherit; padding:6px 9px; border-radius:6px; cursor:pointer;
    border:1px solid #b9b3a5; background:#fff; color:#15171b;
  }
  #journey button.on { background:#15171b; color:#f4f2ec; border-color:#15171b; }
  #journey label { display:flex; align-items:center; gap:6px; font-size:12px; margin:3px 0; }
  #journey .hint { font-size:11px; color:#6b6659; margin-top:8px; line-height:1.5; }
  #journey .maplibregl-popup-content { font:12px/1.5 -apple-system,sans-serif; }

  /* 轉場控制盤：滑桿在右，即時生效——數值由你推，不由我猜 */
  #journey .panel.right { left:auto; right:14px; width:300px; max-height:calc(100vh - 28px); overflow-y:auto; }
  #journey .panel.left { max-height:calc(100vh - 28px); overflow-y:auto; }

  /* 收合：控制盤是調參數用的，看效果的時候它只是佔畫面。
     收起來之後只留一顆小鈕，展開狀態記在 localStorage，重整不會又跳出來。 */
  #journey .panel.collapsed { max-height:none; overflow:visible; padding:0; border:none;
                     background:transparent; box-shadow:none; width:auto; }
  #journey .panel.collapsed > *:not(.paneltab) { display:none; }
  #journey .paneltab {
    display:block; margin:0 0 8px auto; font:12px/1 inherit; padding:6px 10px;
    border-radius:6px; cursor:pointer; border:1px solid #b9b3a5;
    background:rgba(248,247,243,.94); color:#15171b; box-shadow:0 2px 8px rgba(0,0,0,.25);
  }
  #journey .panel.left .paneltab { margin:0 auto 8px 0; }
  #journey .sld { display:grid; grid-template-columns:1fr auto; gap:2px 8px; align-items:center; margin:7px 0 0; }
  #journey .sld > label { grid-column:1/-1; font-size:11px; color:#4a463d; margin:0; display:block; }
  #journey .sld input[type=range] { width:100%; margin:0; }
  #journey .sld output { font:11px/1 ui-monospace,Menlo,monospace; color:#15171b; min-width:34px; text-align:right; }
  #journey .zbadge {
    position:absolute; z-index:5; left:14px; bottom:14px;
    background:rgba(248,247,243,.94); border:1px solid #c9c4b8; border-radius:8px;
    padding:6px 10px; font:12px/1.4 ui-monospace,Menlo,monospace; color:#15171b;
  }
  /* 地名牌：抵達一個地方的那一刻。置中偏上、不擋住地形主體、不吃滑鼠。
     大字用襯線體、字距拉開：那是地圖集與紀錄片的字，不是關卡名的字。
     副標帶真資訊（緯度、日期、停點數）——那是這趟才有的東西，也是它讀起來是遊記的原因。 */
  #journey #plate {
    position:absolute; z-index:7; left:50%; top:26%; transform:translate(-50%,0);
    text-align:center; pointer-events:none; opacity:0;
    text-shadow:0 2px 18px rgba(20,18,14,.45), 0 0 3px rgba(20,18,14,.3);
  }
  #journey #plate.on { animation:plate 3.2s ease forwards; }

  /* ── 名字會停站：同一個物件換停駐位置，不是三個各自出現的標籤 ──────────
     三站都在同一條動線上：降落（畫面上方）→ 選單落定（清單正上方）→ 進到行程層
     （左下角，取代原本那句「回到城市，換一段」）。

     ⚠️ **`.on` 那個 keyframe 收在 opacity 0**，所以會停站的名字不能用它——用了的話
        3.2 秒後它自己消失，而後面兩站移動的是一個看不見的東西，位置全對、畫面全空，
        不報錯。停站版走 `.parked` 這一組，入場用另一個收在 opacity 1 的 keyframe。
     ⚠️ **只有選單存在的地點才停站**（目前只有斯瓦爾巴）。其餘 54 個維持 `.on`
        的原行為，否則名字會停在站 1 不走，讀者看到一個賴在畫面上的標籤。 */
  /* ⚠️ **移動的秒數是變數不是常數**：站 1 → 站 2 要跟匯聚一樣長（同時出發、同時到齊），
     站 2 → 站 3 是一次乾脆的收合。寫死一個值的話，滑桿一推匯聚名字就跟光點脫鉤，
     而兩邊都還會動、都不報錯。顏色反轉不跟著拉長——它要在起步的頭半秒就換完，
     字才在整段旅程裡都讀得出來。 */
  /* ⚠️ **長的那一段要換一條曲線，不能只把秒數拉長。**`cubic-bezier(.22,1,.36,1)`
     是強收尾：0.9 秒時它是俐落，4.6 秒時它會在前三成就走完大半距離，然後慢慢爬。
     畫面上的結果是名字早早就到位、光點還在飛——秒數對了，讀起來仍然不是一起走。
     所以站 1 → 站 2 用對稱的 ease-in-out，把移動平均攤在整段匯聚上。 */
  #journey #plate.parked { --move:.9s; --ease:cubic-bezier(.22,1,.36,1);
    opacity:1; pointer-events:auto; cursor:pointer;
    transition:top var(--move) var(--ease), left var(--move) var(--ease),
               bottom var(--move) var(--ease), transform var(--move) var(--ease),
               text-shadow .6s ease; }
  /* ⚠️ **字級與字距也要跟著走，而它們不在 `#plate` 上**——大小寫在 `b`／`i` 身上，
     只讓容器移動的話，名字會在啟程的第一幀就瞬間縮小，然後用小字走完 4.6 秒。
     位置對、東西在、不報錯，但讀起來是「一個標籤消失、另一個標籤在移動」，
     而這一整段要的正好相反。`--move` 會繼承下來，所以兩邊一定同步。 */
  #journey #plate.parked b, #journey #plate.parked i, #journey #plate.parked span {
    transition:font-size var(--move) var(--ease), letter-spacing var(--move) var(--ease),
               text-indent var(--move) var(--ease), margin-top var(--move) var(--ease),
               color .6s ease, text-shadow .6s ease;
  }
  #journey #plate.parked.in { animation:plate-in 1.1s ease forwards; }
  @keyframes plate-in {
    0%   { opacity:0; transform:translate(-50%,10px); letter-spacing:.42em; }
    100% { opacity:1; transform:translate(-50%,0);    letter-spacing:.30em; }
  }

  /* 站 1：降落。白字配深陰影——這一刻的底是太空與地球。 */
  /* ⚠️ 站 1 的靜止值要寫在規則裡，不能靠入場動畫的 `forwards` 撐著。
     animation 的宣告贏過普通宣告，所以 `.in` 留在身上時它的 `translate(-50%)` 會
     壓過站 2、站 3 的 `transform:none`——名字往左飄出畫面半個自己的寬度，
     而它還在、還會動、也不報錯。`.in` 因此在 animationend 就拆掉。 */
  #journey #plate.parked.st-arrive { left:50%; top:26%; bottom:auto; transform:translate(-50%,0);
                            text-align:center; letter-spacing:.30em; }

  /* 站 2、3：底換成淺色的烘焙地圖，所以字要反轉成墨色、陰影換成紙色光暈。
     ⚠️ **顏色是這段轉場最容易漏的一半**：只搬位置的話白字會落在淺色地形上，
        而它不會消失也不報錯，只是讀不出來。 */
  #journey #plate.parked.st-menu, #journey #plate.parked.st-leg { text-align:left; text-shadow:none; }
  /* ⚠️ **沒有光暈是使用者用眼睛選的**（2026-09-18 並排比過四種：現況、拿掉外圈、
        一層 1.5px、完全沒有）。原本的光暈是兩層 2px + 3px + 12px 外圈，在亮底上讀起來
        是「字發光、有點糊」，而且把筆畫撐粗。
     ⚠️ 代價是**字壓在山地或密集街廓上時沒有東西擋**。比的那一塊底下剛好是海，
        所以這個選擇只在朗伊爾城驗過；換一個選單落在陸地上的地點時要再看一次。 */
  #journey #plate.parked.st-menu b, #journey #plate.parked.st-leg b,
  #journey #plate.parked.st-menu i, #journey #plate.parked.st-leg i {
    color:#1e1a15; text-shadow:none;
  }
  #journey #plate.parked.st-menu i, #journey #plate.parked.st-leg i { color:#6b6459; }
  /* 站 1 跨過兩種底：飛行中是衛星貼圖的深海（白字讀得到），紙感地圖接手之後換成
     跟站 2、3 一樣的墨色，深色陰影同時拿掉——白字加深色陰影落在亮底上就是那一團灰霧。
     `.paper` 由 main.js 的 applyTransition 掛上，它是唯一知道「現在是哪一種底」的地方。
     換色的 0.6 秒沿用 `#plate.parked` 那組 transition。 */
  #journey.paper #plate.parked.st-arrive { text-shadow:none; }
  #journey.paper #plate.parked.st-arrive b { color:#1e1a15; }
  #journey.paper #plate.parked.st-arrive i,
  #journey.paper #plate.parked.st-arrive span { color:#6b6459; }
  /* 副標活到站 2。**它報的是這一趟的規模（幾天、幾張），不是清單有幾列**——
     清單有幾列由清單自己回答，寫成數字就是同一件事講兩次而且兩份會漂。
     站 3 才收掉：那裡的 `#meta` 已經在報「這一段第幾 / 全趟第幾 / 134 張」。 */
  #journey #plate.parked.st-leg span { display:none; }
  #journey #plate.parked.st-menu span { margin-top:.5em; font-size:10.5px; letter-spacing:.1em;
                               text-indent:0; color:#6b6459; }

  /* 站 2：清單正上方。left 與 top 由 JS 從 `#menu` 的實際位置算出來，不用 vw 猜。
     ⚠️ **靠 `translate(0,-100%)` 貼齊，不靠一個固定的上移量**：`top` 指的是清單的
        上緣，名字用自己的高度把自己頂上去，所以副標多一行、字級在移動中還在變，
        下緣都貼在同一條線上。先前寫死 `-52px`，副標活到站 2 之後名牌變高，
        下緣就壓進清單第一列 8 px——量得出來，但畫面上只看得出「有點擠」。
     ⚠️ 三站的 transform 都寫成 `translate(x,y)` 的同一種形式。混用 `none` 與
        `translate()` 會讓瀏覽器改走矩陣內插，而百分比在矩陣裡是照當下的框換算的，
        名字的字級這段正在變——結果是它走一條會飄的路，而且不報錯。 */
  #journey #plate.parked.st-menu { transform:translate(0,-100%); }
  #journey #plate.parked.st-menu b { font-size:23px; letter-spacing:.06em; text-indent:0; }
  #journey #plate.parked.st-menu i { margin-top:.35em; font-size:10.5px; letter-spacing:.28em; text-indent:0; }

  /* 站 3：左下角，取代回頭那一句。 */
  /* 站 3 跟站 2 **停在同一個點**（位置由 main.js 的 plateStation 從選單的框算好寫進 inline），
     只是縮小、帶一個回頭的 chevron。2026-09-24 以前站 3 在左下角，使用者的判斷是
     「回上一層的東西有時在上面、有時在下面，不合理」——回去的入口要待在同一個地方，
     這也是 iOS 導覽列一律把返回放左上角的理由。 */
  #journey #plate.parked.st-leg { transform:translate(0,-100%); }
  #journey #plate.parked.st-leg b { font-size:15px; letter-spacing:.05em; text-indent:0; }
  #journey #plate.parked.st-leg i { margin-top:.3em; font-size:9.5px; letter-spacing:.24em; text-indent:0; }

  /* ── 箭頭在，代表這一格的標題就是回去的地方 ─────────────────────────────
     這是 Apple 的返回鍵規則：返回鍵寫的是**上一頁的標題**，不是這一頁的。
     站 3 回到的正是朗伊爾城，所以「← 朗伊爾城」成立，箭頭常駐。
     ⚠️ **站 2 回到的是「斯瓦爾巴」群島層，不是朗伊爾城**（`destOfPlace` 給了
        `svalbard-region`，所以 `back()` 走 goRegion 那一支）。那裡掛箭頭等於
        指著自己，讀成「回到我現在所在的地方」——所以站 2 常態不給箭頭，
        它就是標題；滑過去才換成目的地。
     ⚠️ 這是「滑過去是預覽，點下去是承諾」的第三個應用，觸控那一側的答案
        （按住 160 ms 且位移不超過 10 px）沿用同一條，還沒接上。 */
  /* 回頭的記號：向量 chevron，不用打字符號。
     ⚠️ **不能用 `←` 這種字元**：它的長相由字型決定，而三處用的是不同字型（系統字、襯線體），
        於是同一個記號在三個地方長得不一樣——襯線體的 ← 是一條細長線、系統字的是短箭頭。
        而且那個字元來自數學符號區，粗細跟旁邊的字對不起來。2026-09-18 使用者並排比過
        字元 ‹、向量 chevron、向量 arrow 之後選了 chevron（iOS 的做法：沒有桿，讀成「往上一層」）。
     走 mask 而不是 <svg>，顏色才吃得到 `background-color`，也才放得進 `::before`。
     尺寸用 em，所以 12px 與 15px 兩處自動等比。 */
  #journey { --chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 3 5 8l5 5'/%3E%3C/svg%3E"); }
  #journey #plate.parked.st-leg b::before,
  #journey #plate.parked.st-menu:hover u::before,
  #journey #back::before {
    content:''; display:inline-block; width:.78em; height:.78em; margin-right:.35em; vertical-align:-.04em;
    background-color:#8a8377;
    -webkit-mask:var(--chev) center/contain no-repeat; mask:var(--chev) center/contain no-repeat;
  }
  #journey #plate.parked.st-leg:hover b { color:#000; }
  /* 預覽的那一行：跟標題同一個左緣，所以換字不會讓版面跳——只有右邊變長。 */
  #journey #plate u { display:none; }
  /* ⚠️ **這三行用 `visibility` 藏，不能用 `display:none`。**
     名牌的高度就是滑鼠的命中範圍，而 `display:none` 會讓它從三行縮成一行——縮完之後
     游標落在框外，hover 立刻取消、名牌變回三行、游標又進來了。實測游標完全不動時，
     它每一幀都在切換：1.5 秒取樣 91 幀、換了 90 次，也就是每秒三十次。
     **畫面上看到的是兩個名字疊在一起**，而那正是「疊影」的真相——不是陰影、不是
     半個像素，是兩個狀態在互相打架。
     ⚠️ 這個形狀的通則是：**觸發區不能被它自己觸發的狀態改變大小。** 用 `visibility`
     藏，那三行仍然佔著位置，所以框在兩個狀態下一樣大。
     ⚠️ 滑到最下面那一行（「幾天幾張」）不會發作，因為下緣是兩種高度共有的——
     所以「有時候會有時候不會」不是隨機，是游標在不在共有的那一段裡。 */
  #journey #plate.parked.st-menu:hover b, #journey #plate.parked.st-menu:hover i,
  #journey #plate.parked.st-menu:hover span { visibility:hidden; }
  #journey #plate.parked.st-menu:hover u {
    /* 絕對定位貼齊下緣：三行的位置留著，而預覽那一行要落在原本最後一行的位置上，
       否則它會跑到三行的最上面去。 */
    /* ⚠️ 絕對定位之後它不再吃名牌的寬度，會照內容自己收縮——中文沒有空格，
       瀏覽器照樣會在字之間斷行，所以「斯瓦爾巴」會被折成兩行。 */
    display:block; position:absolute; left:0; bottom:0; white-space:nowrap;
    font:400 23px/1.06 "Iowan Old Style","Songti TC",Georgia,serif;
    text-decoration:none; letter-spacing:.06em; color:#1e1a15;
    text-shadow:none;   /* 跟站 2 的名字同一種處理，預覽換上來時不該突然多一圈光 */
  }
  @keyframes plate {
    0%   { opacity:0; transform:translate(-50%,10px); letter-spacing:.42em; }
    14%  { opacity:1; transform:translate(-50%,0);    letter-spacing:.30em; }
    76%  { opacity:1; transform:translate(-50%,0);    letter-spacing:.30em; }
    100% { opacity:0; transform:translate(-50%,-6px); letter-spacing:.26em; }
  }
  #journey #plate b {
    display:block; font:400 clamp(30px,5.2vw,64px)/1.06 "Iowan Old Style","Songti TC",Georgia,serif;
    color:#fdfaf3; letter-spacing:inherit; text-indent:.30em;   /* 字距會把整行推左，補回來才置中 */
  }
  #journey #plate i {
    display:block; margin-top:.5em; font:400 12px/1 -apple-system,sans-serif; font-style:normal;
    letter-spacing:.34em; text-indent:.34em; color:rgba(253,250,243,.78); text-transform:uppercase;
  }
  #journey #plate span {
    display:block; margin-top:.85em; font:400 12.5px/1.5 -apple-system,sans-serif;
    letter-spacing:.08em; text-indent:.08em; color:rgba(253,250,243,.9);
  }

  /* 停點卡：hover 一個停點時浮出那一句話。它是內容不是控制項，所以走中軸底部、不進左右面板 */
  #journey #stopcard {
    position:absolute; z-index:6; left:50%; bottom:16px; transform:translate(-50%,10px);
    display:flex; gap:11px; align-items:center; max-width:min(560px,72vw);
    background:rgba(248,247,243,.96); border:1px solid #c9c4b8; border-radius:12px;
    padding:9px 13px 9px 9px; box-shadow:0 8px 26px rgba(0,0,0,.32);
    font:13px/1.5 -apple-system,"Helvetica Neue",sans-serif; color:#15171b;
    opacity:0; pointer-events:none; transition:opacity .18s, transform .18s;
  }
  #journey #stopcard.on { opacity:1; transform:translate(-50%,0); }
  #journey #stopcard img { width:64px; height:64px; object-fit:cover; border-radius:9px; flex:none; }
  #journey #stopcard b { display:block; font-size:13px; }
  #journey #stopcard span { display:block; color:#4a463d; }
  #journey #stopcard em { display:block; margin-top:3px; font-style:normal; font-size:11px; color:#8a8474; }

  /* 停點展開層（2026-08-03）：**hover 是預覽，點是打開**。
   *
   * 卡片一直在寫「12 張照片」卻只給你看 1 張——介面自己在報告這個缺口。
   * v2.8 量過：456 張照片、134 張綁在停點上、畫面上只有 14 張封面，**內容用掉 3%**。
   * 這一層就是把剩下的放出來的地方，也是探索迴圈「得到回報」那一格。
   *
   * 走底部整條而不是跟著停點浮動：照片一散開就需要寬度，而被點的停點可能正貼在畫面邊緣。
   */
  #journey #stopsheet {
    position:absolute; z-index:8; left:0; right:0; bottom:0;
    /* 不透明，不是 97%——底下有地圖的版權字與停點卡，半透明會讓它們像髒污一樣滲上來 */
    background:#f8f7f3; border-top:1px solid #c9c4b8;
    box-shadow:0 -10px 30px rgba(0,0,0,.28); padding:12px 16px 14px;
    font:13px/1.55 -apple-system,"Helvetica Neue",sans-serif; color:#15171b;
    transform:translateY(102%); transition:transform .26s cubic-bezier(.22,.8,.3,1);
    pointer-events:none;
  }
  #journey #stopsheet.on { transform:translateY(0); pointer-events:auto; }
  #journey #stopsheet .hd { display:flex; align-items:baseline; gap:10px; margin-bottom:9px; }
  #journey #stopsheet .hd b { font-size:15px; flex:none; }
  #journey #stopsheet .hd span { color:#4a463d; flex:1; min-width:0; }
  #journey #stopsheet .hd em { font-style:normal; font-size:11px; color:#8a8474; white-space:nowrap; flex:none; }
  #journey #stopsheet .hd button {
    flex:none; border:1px solid #c9c4b8; background:#fff; border-radius:7px;
    padding:3px 9px; font-size:11px; color:#4a463d; cursor:pointer;
  }
  /* 主圖大、其餘小——**階層不是裝飾，是這一疊照片唯一現成的秩序**。
   *
   * 12 張等大排一排讀起來就是一堆圖，因為畫面沒有告訴你先看哪一張。而「先看哪一張」
   * 其實已經有答案了：`cover` 是人挑過的那一張，之前展開層把它跟其餘 11 張平均對待，
   * 等於把那個決定丟掉。⚠️ 照片本身沒有任何可以算出秩序的欄位（只有 src/t/lat/lng），
   * 所以階層只能來自這個既有的人工決定，不能來自規則。
   *
   * 其餘的走兩排橫捲而不是一排：一排要捲兩倍長，而兩排讓「還有多少」一眼看得出來。
   */
  #journey #stopsheet .body { display:flex; gap:10px; align-items:flex-start; }
  #journey #stopsheet .lead img { height:200px; border-radius:10px; display:block; object-fit:cover; background:#e8e5dd; }
  #journey #stopsheet .rest {
    display:grid; grid-auto-flow:column; grid-template-rows:repeat(2, 96px);
    gap:8px; overflow-x:auto; padding-bottom:4px; flex:1; min-width:0;
  }
  #journey #stopsheet .rest img { height:96px; border-radius:8px; display:block; object-fit:cover; background:#e8e5dd; }

  /* ── 時間軸 ──────────────────────────────────────────────────────────
     地圖是同時的，旅行是連續的。這條軸把一趟從「14 個同時存在的點」接回時間。

     ⚠️ 軸不等速：有軌跡的時間按實際時長攤開，空洞壓成固定寬度的休止符。
     量出來的理由是整趟 113.5 小時裡只有 45.6 小時有位置可講，等速的話六成的軸
     拖過去什麼都不會發生。代價寫在 .tl-rest 的斜線上——那個花紋是在說「這裡略過了」，
     不是在說「這裡斷掉了」。 */
  #journey #timeline {
    position:absolute; z-index:6; left:50%; bottom:14px; transform:translateX(-50%);
    /* 讓開左邊的控制盤（270 + 14 邊距）與右邊的縮放鈕，不要滑到它們底下 */
    width:min(1080px, calc(100vw - 640px)); padding:9px 13px 10px;
    background:rgba(248,247,243,.94); border:1px solid #c9c4b8; border-radius:12px;
    box-shadow:0 8px 26px rgba(0,0,0,.32); color:#15171b;
    font:12px/1.4 -apple-system,"Helvetica Neue",sans-serif;
    opacity:0; pointer-events:none; transition:opacity .22s, transform .22s;
  }
  #journey #timeline.on { opacity:1; pointer-events:auto; }
  #journey .tl-head { display:flex; align-items:baseline; gap:10px; margin-bottom:7px; }
  #journey .tl-clock { font:600 14px/1 ui-monospace,Menlo,monospace; letter-spacing:.02em; }
  #journey .tl-where { font-weight:600; }
  #journey .tl-meta { color:#6b6659; font-size:11px; margin-left:auto; text-align:right; }
  #journey .tl-btn {
    font:12px/1 inherit; padding:4px 9px; border-radius:6px; cursor:pointer;
    border:1px solid #b9b3a5; background:#fff; color:#15171b; flex:none;
  }
  #journey .tl-btn.on { background:#15171b; color:#f4f2ec; border-color:#15171b; }

  /* 軌道本體。三層疊在一起：休止符底、日界線、照片密度 */
  #journey .tl-track { position:relative; height:34px; cursor:pointer; touch-action:none; }
  #journey .tl-band { position:absolute; inset:0 0 14px; border-radius:4px; overflow:hidden;
             background:#e6e2d8; border:1px solid #d3cec1; }
  #journey .tl-run  { position:absolute; top:0; bottom:0; background:#cfc8b6; }
  /* 休止符：斜線花紋 + 比軌道窄，讀起來是「這裡被摺起來了」而不是「這裡沒有路」 */
  #journey .tl-rest { position:absolute; top:0; bottom:0;
             background:repeating-linear-gradient(-45deg, #ded9cc 0 3px, #e9e5db 3px 6px); }
  #journey .tl-day  { position:absolute; top:0; bottom:0; width:1px; background:rgba(20,22,28,.22); }
  #journey .tl-daylabel { position:absolute; bottom:0; font:10px/1 ui-monospace,Menlo,monospace;
                 color:#8a8474; transform:translateX(2px); white-space:nowrap; }
  /* 照片密度：哪裡有內容的訊號。一張一根，重疊本身就是密度 */
  #journey .tl-ph { position:absolute; top:3px; width:1px; height:7px; background:rgba(192,57,43,.5); }
  /* 停點：待著的是圓點，移動的是一段括號——形狀跟地圖上的分法同一套 */
  #journey .tl-stop { position:absolute; top:21px; height:7px; cursor:pointer; }
  #journey .tl-stop i { position:absolute; left:0; top:2px; width:100%; height:3px;
               background:#c0392b; border-radius:2px; opacity:.75; }
  #journey .tl-stop.dot i { left:50%; width:7px; height:7px; top:0; margin-left:-3.5px;
                   border-radius:50%; opacity:.85; }
  #journey .tl-stop.cur i { opacity:1; box-shadow:0 0 0 2px rgba(248,247,243,.9); }
  /* 游標：一條線加一顆頭，頭要夠大才抓得住（44 px 命中區靠 ::before 補，不靠加粗視覺） */
  #journey .tl-cursor { position:absolute; top:-2px; bottom:8px; width:2px; background:#15171b;
               margin-left:-1px; pointer-events:none; }
  #journey .tl-cursor::after { content:''; position:absolute; left:50%; top:-4px; width:11px; height:11px;
                      margin-left:-5.5px; border-radius:50%; background:#15171b;
                      border:2px solid #f6f4ee; box-sizing:border-box; }
  #journey .tl-ctl { display:flex; align-items:center; gap:8px; margin-top:8px; }
  #journey .tl-ctl .sld { margin:0; flex:1; }

  /* 照片標記：時間走到那一刻，照片在它被拍下的座標浮出。
     ⚠️ 位置把握度必須看得出來——187 張準的與 26 張等於猜的不能長一樣。
     猜的那些用虛線圈加低透明度，說的是「大概在這附近」。 */
  #journey .photo-pin { width:54px; height:54px; border-radius:50%; cursor:pointer;
               background-size:cover; background-position:center;
               box-shadow:0 3px 12px rgba(0,0,0,.35);
               opacity:0; transform:scale(.72); transition:opacity .28s, transform .28s;
               border:3px solid #f6f4ee; }
  #journey .photo-pin.in { opacity:1; transform:scale(1); }
  #journey .photo-pin.g-good  { border-color:#f2eee2; }
  #journey .photo-pin.g-rough { border-style:dashed; border-color:#e8e2d2; opacity:0; }
  #journey .photo-pin.g-rough.in { opacity:.85; }
  #journey .photo-pin.g-guess { border-style:dashed; border-color:#ddd6c4; width:42px; height:42px; }
  #journey .photo-pin.g-guess.in { opacity:.62; }
  /* 張數徽章：跟停點圓標同一個家族（紙白底、墨字），說的是「還有」不是「警告」 */
  #journey .photo-pin .pin-n {
    position:absolute; right:-3px; top:-3px; min-width:19px; height:19px; padding:0 4px;
    border-radius:10px; background:#f6f4ee; border:1px solid rgba(20,22,28,.3);
    font:600 11px/17px system-ui,sans-serif; color:#3a2f26; text-align:center;
    box-sizing:border-box;
  }
  #journey .photo-pin { position:relative; }

  /* 麵包屑：下鑽到哪一層是狀態機唯一的對外顯示，運鏡是它的結果不是它的來源 */
  #journey .crumb { display:flex; flex-wrap:wrap; align-items:center; gap:3px; margin:0 0 8px; }
  #journey .crumb button {
    padding:4px 7px; font-size:12px; border-color:#d3cec1; background:#fbfaf7;
  }
  #journey .crumb button.cur { background:#15171b; color:#f4f2ec; border-color:#15171b; }
  #journey .crumb .sep { color:#9a9384; font-size:11px; }
  #journey .drill-list { display:flex; flex-wrap:wrap; gap:4px; margin-bottom:8px; max-height:132px; overflow-y:auto; }
  #journey .drill-list button { padding:4px 7px; font-size:11px; }
  #journey .drill-list button.off { color:#a8a293; border-color:#ded9cc; cursor:default; }

  /* --- 地點選單：讀者的「還有哪些地方可以去」 --------------------------------
     桌機走右側欄、窄屏走底部抽屜。這是 Material 與 NN/g 對「地圖配清單」的共同形狀：
     寬螢幕橫向有餘裕所以放側邊，窄螢幕縱向有餘裕所以放底部。

     ⚠️ **靠右不靠左是版面逼出來的**：左邊已經是名牌加十三行行程選單，兩份清單並排在
        同一側會疊在一起，而畫面中間那一帶正是鎮上——真正有東西看的地方。
     ⚠️ **進城市層自動退場**（`.in-city`）：那時行程選單接手回答「可以去哪」，
        兩份清單同時在畫面上是同一個問題有兩個答案。這是已定案的「在挑的時候指出
        可以點什麼，挑完之後退場」在這一層的樣子。
     ⚠️ **收起用 translate 不用 display**：抽屜要看得出是滑出去的，
        而且 `display:none` 會讓清單的捲動位置歸零。 */
  /* ⚠️ **底走深色玻璃不走紙色**，沿用 `.zhud` 那一份（這個原型自己的前例）。
     理由是它要同時待在兩種底上：太空層是純黑、地圖層是亮紙。紙色的面板在太空上
     會亮成一塊招牌，而深色的在兩種底上都讀得出來。 */
  #journey #places {
    position:fixed; z-index:7; right:1.4rem; top:50%; transform:translateY(-50%);
    width:min(19rem, 26vw); max-height:min(60vh, 30rem); display:flex; flex-direction:column;
    padding:.8rem .85rem; border-radius:10px;
    background:rgba(21,23,27,.82); backdrop-filter:blur(8px);
    border:1px solid rgba(244,242,236,.14); box-shadow:0 2px 18px rgba(0,0,0,.28);
    transition:opacity .35s ease, transform .35s cubic-bezier(.22,1,.36,1);
  }
  /* 面板裡的按鈕跟著翻成深底淺字——外層換了底，內層不跟著換就會變成淺底疊在深底上。 */
  #journey #places button {
    background:rgba(244,242,236,.08); border-color:rgba(244,242,236,.22); color:#eceae4;
  }
  #journey #places button:hover:not(.off) { background:rgba(244,242,236,.18); }
  #journey #places .crumb button { background:rgba(244,242,236,.08); }
  #journey #places .crumb button.cur { background:#f4f2ec; color:#15171b; border-color:#f4f2ec; }
  #journey #places .crumb .sep { color:rgba(244,242,236,.45); }
  #journey #places .drill-list button.on { background:#f4f2ec; color:#15171b; border-color:#f4f2ec; }
  /* 收起的兩種來源：狀態機（進了城市層）與宿主（讀者按了收起介面）。
     ⚠️ 兩者要分開兩個 class——合成一個的話，從城市層退出來時會把讀者按過的收起一起還原。 */
  #journey.in-city #places,
  #journey.bare #places {
    opacity:0; pointer-events:none; transform:translate(calc(100% + 1.8rem), -50%);
  }
  #journey #places .crumb { margin:0 0 .55rem; }
  #journey #places .drill-list { max-height:none; margin:0; overflow-y:auto; }
  #journey #places #drill-search {
    width:100%; margin-bottom:.55rem; padding:.3rem .45rem;
    border:1px solid rgba(244,242,236,.22); border-radius:6px; font:12px/1.4 inherit;
    background:rgba(244,242,236,.08); color:#eceae4;
  }
  #journey #places #drill-search::placeholder { color:rgba(244,242,236,.42); }
  /* Safari 的搜尋框自帶一顆清除鈕，深底上它是深色的——看不見但按得到。 */
  #journey #places #drill-search::-webkit-search-cancel-button { filter:invert(1) opacity(.5); }
  /* 清單：一列一個地點，國家是小標題。先前是換行排的小膠囊（下鑽時每層只有幾個），
     平鋪之後有 55 列，膠囊會擠成一片分不出組，所以改成直排。 */
  #journey #places .drill-list {
    display:flex; flex-direction:column; flex-wrap:nowrap; gap:0; padding-right:.2rem;
    overscroll-behavior:contain;   /* 捲到底不要帶著地圖一起縮放 */
  }
  #journey #places .drill-list .grp {
    margin:.7rem 0 .2rem; padding:0 .45rem; font-size:10.5px; letter-spacing:.08em;
    color:rgba(244,242,236,.5);
  }
  #journey #places .drill-list .grp:first-child { margin-top:.1rem; }
  #journey #places .drill-list .grp.cur { color:#f4f2ec; }
  #journey #places .drill-list button.place {
    display:block; width:100%; text-align:left; padding:.28rem .45rem; font-size:13px;
    background:transparent; border:0; border-radius:5px; color:#eceae4;
  }
  #journey #places .drill-list button.place:hover:not(.off) { background:rgba(244,242,236,.12); }
  #journey #places .drill-list button.place.on { background:#f4f2ec; color:#15171b; }
  #journey #places .drill-list button.place .sub {
    margin-left:.5em; font-size:11px; color:rgba(244,242,236,.45);
  }
  #journey #places .drill-list button.place.on .sub { color:#6b6459; }
  /* 還沒有行程的地點：淡、點不下去、游標不變手指（理由見 main.js 的 renderCrumb）。
     ⚠️ `.off` 的淡度對齊舊的正式站清單（.46），那一版就是這樣讓讀者知道「去過、還沒寫」。 */
  #journey #places .drill-list button.place.off { opacity:.46; cursor:default; }

  /* --- 地點選單：只列讀得到的那幾趟，一趟一張照片卡片（見 main.js 的地點選單那一段）------
     卡片的底是那一趟的代表照，可以點的那張有一圈橘色在呼吸。桌機放在右側，窄屏收成底部一條小卡。 */
  /* ⚠️ 寬度只在桌機放：這條的權重比窄屏那段的 `#journey #places` 高，不包起來會把抽屜也縮成 30vw */
  @media (min-width: 761px) { #journey.menu-trips #places { width:min(22rem, 30vw); } }
  #journey.menu-trips #drill-search { display:none; }
  #journey #places .drill-list button.card {
    position:relative; flex:none; display:flex; flex-direction:column; justify-content:flex-end;
    width:100%; min-height:5.6rem; margin:0 0 .5rem; padding:.7rem .85rem; overflow:hidden;
    border:0; border-radius:10px; background:#1a1d22; color:#f3f8fc; text-align:left; cursor:pointer;
    transition:transform .25s ease, box-shadow .25s ease;
  }
  #journey #places .drill-list button.card:hover:not(.off) { transform:translateY(-2px); background:#1a1d22;
    box-shadow:inset 0 0 0 1.5px rgba(243,163,104,.7); }
  #journey #places .card .media { position:absolute; inset:0; z-index:0; }
  #journey #places .card .map, #journey #places .card .photo {
    position:absolute; inset:0; background-size:cover; background-position:center; }
  #journey #places .card .map { filter:blur(2px) brightness(.82) saturate(1.08); transform:scale(1.15); transition:opacity .5s ease; }
  #journey #places .card .photo { opacity:0; transform:scale(1.12); transition:opacity .5s ease, transform 8s ease-out; }
  #journey #places .card:hover .photo, #journey #places .card.big .photo { opacity:1; transform:scale(1.2); }
  #journey #places .card:hover:not(.off) .map { opacity:0; }
  #journey #places .card .media::after { content:''; position:absolute; inset:0;
    background:linear-gradient(180deg, rgba(6,10,18,.15) 0%, rgba(6,10,18,.4) 50%, rgba(6,10,18,.8) 100%); }
  #journey #places .card .num, #journey #places .card .txt, #journey #places .card em { position:relative; z-index:2; }
  #journey #places .card .num { font:600 10.5px/1 ui-monospace, monospace; opacity:.8; }
  #journey #places .card .txt { display:flex; flex-direction:column; gap:.2rem; margin-top:.3rem; }
  #journey #places .card .txt b { font-size:17px; font-weight:600; text-shadow:0 1px 8px rgba(0,0,0,.9); }
  #journey #places .card .txt i { font:normal 11px/1.2 ui-monospace, monospace; opacity:.9; text-shadow:0 1px 5px rgba(0,0,0,.9); }
  #journey #places .card em { position:absolute; right:.7rem; bottom:.75rem; font:600 9.5px/1 ui-monospace, monospace; font-style:normal;
    color:#ffd9b0; background:rgba(234,120,40,.32); padding:.22rem .45rem; border-radius:999px; letter-spacing:.04em; }
  #journey #places .drill-list button.card.off { opacity:.46; cursor:default; }
  /* 可以點的那張：一圈橘色慢慢呼吸，引導點擊；滑過去交給 hover 那一圈 */
  #journey #places .card:not(.off)::after { content:''; position:absolute; inset:0; z-index:1; border-radius:10px; pointer-events:none;
    animation:card-attn 3.6s ease-in-out infinite; }
  #journey #places .card:not(.off):hover::after { animation:none; }
  @keyframes card-attn { 0%,100% { box-shadow:inset 0 0 0 1px rgba(243,163,104,0); } 50% { box-shadow:inset 0 0 0 1px rgba(243,163,104,.45); } }
  #journey #places .drill-list button.card.big { min-height:15rem; padding:1rem; }
  #journey #places .card.big .map { display:none; }
  #journey #places .card.big .txt b { font-size:22px; }
  #journey #places .drill-list .note { margin:.3rem .2rem 0; font-size:11.5px; line-height:1.5; color:rgba(244,242,236,.5); }

  /* 窄屏：側欄換成底部抽屜。
     ⚠️ 高度用 `dvh` 不用 `vh`——手機的網址列收合會改變 `vh`，而抽屜是貼著底邊的，
        算錯的那一截剛好落在手指要碰的地方。
     ⚠️ 觸控至今沒有在真的手機上走過，所以這一段是照前人的形狀做的，還沒有人驗過。 */
  @media (max-width: 760px) {
    #journey #places {
      right:0; left:0; top:auto; bottom:0; width:auto; transform:none;
      max-height:42dvh; border-radius:12px 12px 0 0;
      padding:.7rem .9rem calc(.7rem + env(safe-area-inset-bottom));
    }
    #journey.in-city #places,
    #journey.bare #places { transform:translateY(calc(100% + 1rem)); }
  }
  /* 窄屏的 `trips`：抽屜收成一條浮起來的小卡（2026-09-25，見 Wayfinding 的 t-mobile-sheet）。
     左邊一張縮圖、右邊寫這一趟的地點與規模，點它就降落。地球由 main.js 的 `stripPad`
     往上讓出這一條的高度，整顆放得進沒被遮住的那一塊。
     前人是 Apple Maps／Google Maps 的底部抽屜只露一條；現在只有一趟，連拉都不用拉。
     故事多了之後，這一條改成左右滑的一排（Airbnb 地圖下方那種），不是往上長。
     網站原本在左下角有一顆收起導覽列的 ⤢，遊記改用葉子之後就沒有導覽列可以收了，那顆一起拿掉。 */
  @media (max-width: 760px) {
    #journey.menu-trips #places {
      left:12px; right:12px; bottom:calc(12px + env(safe-area-inset-bottom)); max-height:none;
      padding:6px; border-radius:14px;
    }
    #journey.menu-trips #places .crumb,
    #journey.menu-trips #places .drill-list .note { display:none; }
    #journey #places .drill-list button.card.big {
      flex-direction:row; align-items:center; justify-content:flex-start;
      min-height:0; height:68px; margin:0; padding:0 12px 0 82px; background:none;
    }
    #journey #places .card.big .media { inset:4px auto 4px 4px; width:68px; border-radius:9px; overflow:hidden; }
    #journey #places .card.big .media::after { display:none; }
    #journey #places .card.big .num { display:none; }
    #journey #places .card.big .txt { margin:0; }
    #journey #places .card.big .txt b { font-size:17px; text-shadow:none; }
    #journey #places .card.big .txt i { opacity:.7; text-shadow:none; }
    /* 右下角的縮放鈕與 ⓘ 貼著底邊，會被小卡蓋住：往上讓出小卡的高度（68 + 6×2 + 12 + 間距） */
    #journey.menu-trips:not(.in-city) .maplibregl-ctrl-bottom-right { bottom:calc(100px + env(safe-area-inset-bottom)); }
  }
  /* 滑過卡片時，地球上那一趟的點亮起來：卡片與地球說的是同一件事。
     點本來就在呼吸，這一圈只在滑過的時候加上去，所以沒滑的時候地球上不多任何東西。 */
  #journey .jglow { width:34px; height:34px; border-radius:50%; pointer-events:none;
    box-shadow:0 0 0 2px rgba(243,163,104,.95), 0 0 18px 4px rgba(243,163,104,.55);
    opacity:0; transform:scale(.6); transition:opacity .25s ease, transform .35s cubic-bezier(.22,1,.36,1); }
  #journey .jglow.on { opacity:1; transform:scale(1); }
  /* ==================================================================
     以下整段來自 prototype/chain：城市 → 行程那一段的樣式。
     ⚠️ 面板的 id 從 `panel` 改成 `chainPanel`——這一頁有兩組控制盤（宿主的下鑽
     與這一組動線），同名的話後綁的那一組會拿到前一組的節點，而兩組都長得出來。
     ================================================================== */
  /* ⚠️ chain 原本在這裡蓋掉 `body` 的底色與字體。**這一頁不能蓋**：宿主從太空開始，
     body 的墨色就是星空的底，換成峽灣的海色會讓地球外面整片變灰。
     峽灣那個底色改由城市層自己負責，見下面的 `#journey.in-city`。 */
  #journey.in-city { background: #a8b3b9; }

  /* ⚠️ 疊放順序就是這五層的先後，改動之前先讀這一段：
     地圖（會被糊）→ 紙紗 → 光軌 SVG → 光點 canvas → 環的 WebGL。
     光軌與光點畫在**地圖外面**，所以不吃地圖那道模糊——糊掉的是底，記號要清楚。 */
  /* ⚠️ `#map` 這一條刪掉了：宿主已經有它（absolute，背景透明好讓太空層透出來）。
     chain 原本寫 fixed 加不透明，蓋上去會把星空擋在地圖後面。 */
  #journey #veil  { position: fixed; inset: 0; pointer-events: none; background: #efeae1; opacity: 0; }
  #journey #trail { position: fixed; inset: 0; pointer-events: none; overflow: visible; }
  #journey #dots  { position: fixed; inset: 0; pointer-events: none; }
  #journey #pins  { position: fixed; inset: 0; pointer-events: none; }
  /* ⚠️ 指標一律歸這一層。地圖建成 interactive:false，命中判定與轉環都自己做——
     兩邊都收滾輪與拖曳的話，轉環會變成拖地圖，而且不會有任何錯誤訊息。 */
  /* ⚠️ **預設不收指標。** chain 那支整頁只有這一層，所以它一直吃著整個畫面；
     這一頁底下還有一顆要點的地球，照抄的話世界 → 洲 → 國那幾層全部點不動，
     而且不會有任何錯誤訊息——滑鼠有反應、地球沒反應。
     進到城市層（`#journey.in-city`）才把指標交給它。 */
  #journey #stage { position: fixed; inset: 0; touch-action: none; pointer-events: none; }

  /* ⚠️ **chain 那組畫面在進到城市層之前一律不出現。** 在 chain 那支它是整頁唯一的
     內容所以不必藏，這一頁在它之前還有太空與地球兩層——不藏的話載入讀數會從第一秒
     就掛在星空底下。 */
  #journey #loader, #journey #menu, #journey #meta, #journey #back, #journey #veil, #journey #trail, #journey #dots, #journey #pins, #journey #stage { visibility: hidden; }
  #journey.in-city #loader, #journey.in-city #menu, #journey.in-city #meta, #journey.in-city #back,
  #journey.in-city #veil, #journey.in-city #trail, #journey.in-city #dots, #journey.in-city #pins,
  #journey.in-city #stage { visibility: visible; }
  #journey.in-city #stage { pointer-events: auto; }

  #journey .pin {
    position: absolute; width: 10px; height: 10px; margin: -5px 0 0 -5px;
    border-radius: 50%; background: #b5544e; opacity: .5;
  }
  /* ⚠️ 當前那個不是「更亮」——暖灰紙的底上沒有發光的餘地，所以它靠**動作**：呼吸。 */
  #journey .pin.on { opacity: 1; animation: breathe 2.4s ease-in-out infinite; }
  @keyframes breathe {
    0%, 100% { transform: scale(1);   box-shadow: 0 0 0 0 rgba(181,84,78,.45); }
    50%      { transform: scale(1.5); box-shadow: 0 0 0 9px rgba(181,84,78,0); }
  }

  /* --- 選單：每一段由它自己的照片組成 -------------------------------------
     名字**不放到地圖上**（四條線在鎮上互相不到 7 px，標不下）。選單是 source，
     地圖上的光軌是 target，這是 brushing and linking。

     ⚠️ **每一列右邊那排光點就是那一段的照片，一顆一張。** 這是 Isotype 的作法：
        數量用重複相同的符號表示，不用放大符號——因為大小的變化沒辦法準確比較，
        而重複的符號必要時數得出來。所以這裡不寫「12」這個數字，也不畫長條。
     ⚠️ 光點畫在 canvas 上不在 DOM 裡（它們要從地圖飛過來），`.d` 這一格只負責
        佔位與被量位置。**每一列的 `.d` 一樣寬**，右緣才對得齊、長度才比得出來。 */
  #journey #menu {
    position: fixed; left: 5vw; top: 50%; transform: translateY(-50%);
    width: 430px; pointer-events: none;
  }
  #journey #menu.on { pointer-events: auto; }
  #journey .leg {
    display: flex; gap: 14px; align-items: center; cursor: pointer;
    padding: 5px 0; color: #1e1a15; opacity: 0;
    /* 無容器、也無光暈：字直接落在地圖上。光暈與 500 字重是 2026-09-18 拿掉的，
       理由與風險見站 2 名字那一段（`#plate.parked.st-menu b`）。 */
    text-shadow: none;
    transition: opacity .5s ease, transform .22s cubic-bezier(.22,1,.36,1);
  }
  #journey .leg.landed { opacity: 1; }
  #journey .leg .k { font: 400 11px/1.6 ui-monospace, monospace; color: #8a8377; min-width: 22px; }
  #journey .leg .t { font: 400 15px/1.45 "PingFang TC", system-ui, sans-serif; flex: 1; }
  #journey .leg .d { flex: none; height: 12px; }
  #journey #menu.dim .leg.landed { opacity: .34; }
  #journey #menu.dim .leg.hot.landed { opacity: 1; transform: translateX(4px); }
  #journey .leg.noline .t { border-bottom: 1px dashed rgba(138,131,119,.55); }
  /* 窄屏：清單寬度跟著畫面走（桌機固定 430px，手機會讓光點跑出畫面右緣）。
     縮排對齊標題（編號欄 22px + 間距 14px）。 */
  @media (max-width: 760px) {
    #journey #menu { left: 16px; width: calc(100vw - 32px); }
    #journey .leg { gap: 10px; }
  }

  /* --- 行程層的文字：左欄，寬度算得出來不靠 vw 猜 ---------------------- */
  #journey #meta {
    position: fixed; left: 6vw; top: 50%; transform: translateY(-50%);
    pointer-events: none; opacity: 0; transition: opacity .4s ease;
  }
  /* 三行都**不加光暈**（2026-09-24 使用者看過：白色光暈讓字讀起來是糊的）。
     行程層的底是模糊加紙色罩過的地圖，本身已經夠平，字不需要另一圈東西跟它分開。
     ⚠️ 光暈原本要解的是序號那一行：#7d7669 對上淺色地形幾乎同亮度，而它正是「走到第幾張」
        唯一的出口。所以拿掉光暈的同時把它壓深到 #5f584d，靠顏色而不是光暈讀得出來。 */
  #journey #meta > * { text-shadow: none; }
  #journey .num  { font-size: 13px; letter-spacing: .08em; color: #5f584d; font-variant-numeric: tabular-nums; }
  #journey .name { font-size: 28px; font-weight: 500; margin: 6px 0 14px; color: #111; }
  #journey .sig  { font-size: 14px; line-height: 1.75; color: #4a453d; }
  #journey #back {
    position: fixed; left: 6vw; bottom: 6vh; opacity: 0; pointer-events: none;
    font: 400 12px/1.6 system-ui, sans-serif; color: #6b6459; cursor: pointer;
    letter-spacing: .06em; transition: opacity .4s ease;
    text-shadow: var(--halo-paper);
  }
  #journey #back.on { opacity: 1; pointer-events: auto; }
  /* 站 3 的名字站的就是這個位置，所以那一句讓開。⚠️ 用 display 不用 opacity——
     留著透明的它會繼續吃掉那一塊的點擊，而名字就在同一個位置上。 */
  #journey #back.taken { display: none; }
  /* 直立的手機：這一段的文字住在最下面，滾筒住中間，葉子與城市名在上面（2026-09-25）。
     前例是 Apple Maps／Google Maps 的地點卡與限時動態的說明：媒體在上、字在下，各有一塊不重疊。
     底下墊一層由透明漸到紙色的底，字才不必跟模糊的地圖搶。
     ⚠️ 寬度由 JS 寫在 style 上（桌機要讓出正面那張卡片），這裡要用 !important 蓋掉。
     ⚠️ 切換點跟滾筒一樣是 640px（city-chain.js 的 TIGHT_AT），兩邊不一致的話會有一段寬度
        字在底下、環卻還是正圓。 */
  @media (max-width: 640px) {
    #journey #meta {
      left: 16px; right: 16px; top: auto; bottom: calc(18px + env(safe-area-inset-bottom));
      transform: none; max-width: none !important;
    }
    #journey #meta::before {
      content: ''; position: fixed; left: 0; right: 0; bottom: 0; height: 30vh; z-index: -1;
      background: linear-gradient(to top, rgb(240 236 228 / .94) 55%, rgb(240 236 228 / 0));
      pointer-events: none;
    }
    #journey .name { font-size: 22px; margin: 4px 0 8px; line-height: 1.3; }
    #journey .sig  { font-size: 14px; line-height: 1.65;
      display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
  }

  /* 載入計數器就是閘門：齊發在它讀到 100 的那一幀啟動，不是旁邊的讀數。 */
  #journey #loader {
    position: fixed; left: 50%; bottom: 3vh; transform: translateX(-50%);
    font-size: 12px; letter-spacing: .1em; color: #999; font-variant-numeric: tabular-nums;
  }

  #journey #chainPanel {
    position: fixed; top: 12px; right: 12px; width: 252px; z-index: 5;
    background: rgba(255,255,255,.93); border: 1px solid #ddd; border-radius: 8px;
    padding: 10px 12px; font-size: 12px; color: #333;
    max-height: calc(100vh - 24px); overflow-y: auto;
  }
  #journey #chainPanel h2 { font-size: 12px; margin: 0 0 8px; font-weight: 600; }
  #journey #chainPanel label { margin: 7px 0 2px; display: flex; justify-content: space-between; gap: 8px; }
  #journey #chainPanel input[type=range] { width: 100%; }
  #journey #chainPanel select, #journey #chainPanel button { width: 100%; font-size: 12px; }
  #journey #chainPanel button { margin-top: 6px; padding: 5px; cursor: pointer; }
  #journey #chainPanel .grp { margin-top: 10px; padding-top: 8px; border-top: 1px solid #eee; }
  #journey #chainPanel .grp > b { display: block; color: #888; font-size: 11px; font-weight: 500; margin-bottom: 2px; }
  #journey #chainPanel details { margin-top: 8px; border-top: 1px solid #eee; padding-top: 6px; }
  #journey #chainPanel summary { cursor: pointer; color: #666; font-size: 11px; list-style: revert; }
  #journey #chainPanel .hint { margin-top: 9px; color: #888; line-height: 1.6; font-size: 11px; }
  #journey #chainPanel .warn { color: #b25000; line-height: 1.55; font-size: 11px; margin-top: 8px; }
  #journey #state { font-family: ui-monospace, monospace; font-size: 10.5px; color: #6b6459;
           margin-top: 8px; line-height: 1.6; }

/* 除錯用的控制盤與讀數：網址帶 `?debug=1` 才出現（main.js 開頭掛上 .debug）。
   浮在畫面上的那幾塊用 visibility 藏，版面仍在，量尺寸的程式不會量到 0；
   時間軸裡的滑桿那一列是排在面板裡的，用 display 藏才不會留一塊空白。 */
#journey:not(.debug) :is(.panel, .zbadge, .zhud, #chainPanel) { visibility:hidden !important; pointer-events:none !important; }
#journey:not(.debug) .tl-ctl { display:none !important; }
  /* 放大檢視（見 city-chain.js 的「放大檢視」）：照片從環上被拿起來、轉正、長成滿版 */
  #pv { position:fixed; inset:0; z-index:90; display:none; touch-action:none; cursor:zoom-out; }
  #pv.on { display:block; }
  #pv .pv-bg { position:absolute; inset:0; background:rgba(12,13,15,.92); opacity:0; }
  #pv .pv-box { position:absolute; overflow:hidden; border-radius:6px; transform-origin:50% 50%;
    box-shadow:0 18px 60px rgba(0,0,0,.45); }
  #pv .pv-box img { display:block; width:100%; height:100%; object-fit:cover;
    pointer-events:none; user-select:none; -webkit-user-drag:none; }
  #pv .pv-cap { position:absolute; left:16px; right:16px; bottom:calc(22px + env(safe-area-inset-bottom)); margin:0;
    text-align:center; color:rgba(244,242,236,.85); font:400 13px/1.5 "PingFang TC", system-ui, sans-serif; opacity:0; }
