/* =========================================================
   Chao Visuals — 主樣式
   暗色沉浸攝影作品集主題
   ========================================================= */
:root{
  --bg:#0b0b0d;         /* 近黑主背景 */
  --bg-soft:#141418;    /* 卡片 / 區塊 */
  --ink:#f4f4f2;        /* 主要文字 */
  --muted:#8a8a92;      /* 次要文字 */
  /* ---- 1.67.0 內文灰 ----
     色票原本只命名了 --ink 與 --muted 兩級，但實際的內文（關於頁、服務頁、
     商店頁、跨頁式說明、規格表）用的既不是白也不是 --muted，而是散在檔案裡的
     五個沒有名字的值：#d8d8d5 / #d4d4d1 / #cfcfcc / #c7c7cd / #c3c3c0。
     它們最亮與最暗只差 2.6:1，肉眼幾乎分不出來——沒有人會刻意挑五個。
     更麻煩的是其中四個是暖中性、一個是冷調，而全站底色（#0b0b0d）、
     陰影（#06060a）與 --muted 都是冷調，暖灰壓在冷底上會微微發黃。

     收成兩級，都跟著色盤走冷： */
  --ink-2:#d6d6db;      /* 內文：在 --bg 上 13.6:1 */
  --ink-3:#c6c6cd;      /* 次級內文、圖說、方案條列：11.6:1 */
  --line:rgba(255,255,255,.08);
  /* 金色是全站唯一的強調色，而且只用在「可以互動或代表狀態」的地方：
     主要按鈕、目前所在頁面、價格、啟用中的篩選、連結 hover、
     skip-link 與 focus ring、載入進度條、logo。
     純裝飾性的小標、日期、分類字樣一律用 --muted / --ink，
     否則金色到處都是，真正該被看見的那一個就不再顯眼。 */
  --accent:#c9a35b;     /* 沉穩金點綴 */
  /* 金底上的字。全站有 25 個地方要在金色底上放字（主要按鈕、選取中的篩選、
     目前頁碼、skip-link⋯），原本每一處各自硬寫 #111。它其實是 --accent 的
     配對色：日後金色一動，這一個值就得跟著重算對比，所以它必須有名字。
     #111 在 #c9a35b 上是 7.98:1，過 AA 也過 AAA。 */
  --on-accent:#111;
  --ease:cubic-bezier(.22,.61,.36,1);

  /* ---- 1.67.0 z-index 階梯 ----
     這裡原本散著 40/60/90/95/97/99/100/101/110/200/1000/9999/99998/100000/100001，
     十五個數字沒有一個寫著它為什麼是那個數字。同一份檔案裡卻認真替圓角和
     斷點寫了階梯——z-index 是唯一漏掉的那一組。

     只收錄「position:fixed、跨越整頁」的那幾層。元件內部的 0~6
     （英雄區的四層濾鏡、作品頁的視差底圖）是各自的區域堆疊脈絡，
     跟這一組無關，維持原樣。

     最上面三個值刻意不是整數：WordPress 管理列固定在 99999，
     轉場效果要在它之下、自訂游標要在它之上，所以繞著 99999 排。
     這是有理由的魔術數字，把理由寫下來它就不再是魔術數字。 */
  --z-peek:40;          /* 跨頁式的翻頁提示 */
  --z-rail:60;          /* 側欄按鈕列、閱讀進度條、跨頁式頁碼 */
  --z-nav-backdrop:90;  /* 展開導覽的遮罩 */
  --z-panel:95;         /* 手機版浮動側欄 */
  --z-panel-btn:97;     /* 側欄開關：面板打開時仍要按得到 */
  --z-grain:99;         /* 全站顆粒：蓋住內容，但在頁首之下 */
  --z-header:100;       /* 固定頁首 */
  --z-sticky:101;       /* 吸頂的作品篩選列：捲動時取代頁首 */
  --z-nav-close:110;    /* 導覽的 X：要在自己的遮罩(90)之上 */
  --z-skip:200;         /* skip-link：鍵盤一 Tab 就必須看得到 */
  --z-lightbox:1000;    /* 燈箱 */
  --z-preload:1100;     /* 載入畫面 */
  --z-fx:99998;         /* 轉場效果：管理列(99999)之下 */
  --z-cursor:100000;    /* 自訂游標：管理列之上 */
  --z-fx-over:100001;   /* 燈箱開著時的轉場：游標之上 */
  --pad:5vw;

  /* ---- 1.23.0 字體與版面 token ----
     字體堆疊集中成兩個變數，日後換字只要改這裡。
     Jost 只自帶拉丁字母（每個 @font-face 都有 unicode-range），
     中文永遠會自動落到 PingFang TC / Noto Sans TC，所以把 Jost 放在
     顯示字體的第一順位不會影響任何一個中文字。
     自架的 Jost 只有 300/400/500 三個字重，因此全站不再要求 600
     ——瀏覽器合成的假粗體在細襯線的 Jost 上會糊掉。 */
  --font-display:"Jost","Helvetica Neue","PingFang TC","Noto Sans TC",system-ui,sans-serif;
  --font-body:"Helvetica Neue","PingFang TC","Noto Sans TC",system-ui,sans-serif;

  /* 內容最大寬度：超寬螢幕（21:9、雙 4K）上不讓格線一路拉到螢幕邊 */
  --maxw:1440px;

  /* 文章側欄欄寬。改這個值時，inc/sidebar.php 的 CHAOVISUAL_SIDE_W 要一起改。 */
  --side-w:260px;

  /* 陰影帶背景的冷調黑（#06060a），不用純黑；純黑陰影疊在 #0b0b0d 上會發灰 */
  --shadow-1:0 2px 10px rgba(6,6,10,.5);
  --shadow-2:0 18px 44px -18px rgba(6,6,10,.9),0 2px 8px rgba(6,6,10,.45);

  /* ---- 1.33.0 圓角 token ----
     原本站上散著 2/3/4/6/8px 五種圓角，而且同一張照片在燈箱裡是 3px、
     在跨頁式裡是 4px——讀者其實看得出來，只是說不上來哪裡不對。
     收斂成三個，各自對應一種東西：

       --r-img   照片。所有的照片都是這一個值，不管它在哪裡出現。
       --r-card  卡片、輸入框、方案盒——有邊框、裝內容的東西。
       --r-pill  膠囊：篩選鈕、標籤。

     圓形（頭像、圓點、關閉鈕）仍然直接寫 50%：那不是圓角，是形狀。
     新增樣式時請從這三個裡挑一個；真的都不合適時，先想想是不是
     那個元件本來就該長得像既有的某一類。 */
  --r-img:4px;
  --r-card:6px;
  --r-pill:100px;

  /* ---- 1.33.0 斷點 ----
     媒體查詢不能用 var()，所以這一組沒辦法變成真的變數，
     只能靠約定。這裡把它寫下來，新增媒體查詢時請從這六個裡挑：

       480   小手機：單行資訊開始換行堆疊
       640   手機／平板分界：兩欄一律變一欄
       760   導覽列變漢堡、文章側欄變浮動面板（結構性的分界）
       900   平板橫向：三欄變兩欄
       1024  跨頁式指示器收起（與 max-height:560px 合用）
       1200  桌機：文章側欄與內文並排

     原本有 420／560／600／720／820／1000 六個額外的值，
     而且同一種決策（多欄收單欄）就用掉了其中五個——
     在 580px 寬的螢幕上會同時看到三種節奏。1.33.0 全部併進上面這一組。 */
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font-family:var(--font-body);
  line-height:1.6;-webkit-font-smoothing:antialiased;overflow-x:hidden;
}
/* height:auto 不是可有可無的補充。WordPress 會把 width/height 屬性寫進 <img>，
   瀏覽器把它們當成 height 的樣式提示；只夾 max-width 而不放掉高度，
   圖在窄畫面就會被寬度夾住、高度卻停在原始像素——直式的空框、橫式的照片被拉長。
   桌機看不出來是因為寬度幾乎沒被夾到，這個錯只在手機上現形。 */
img{display:block;max-width:100%;height:auto}
/* 開了 Modern Image Formats 的 picture 元素之後，WordPress 會把 <img> 包進
   一層 <picture>。這一層預設是 inline 而且沒有尺寸，會踩到兩件事：
   一是 .hero-photo img、.tile img 這種 height:100% 的百分比要對照父層算，
   父層突然變成那個沒有高度的 picture；二是所有寫成直接子選擇器的規則會失聯。
   display:contents 讓 picture 從版面盒子樹裡消失，img 的父層維持原本那一個，
   於是站上每一條為裸 <img> 寫的規則都不必改。 */
picture{display:contents}
a{color:inherit;text-decoration:none}
/* 標題一律走顯示字體（Jost 拉丁 + PingFang TC 中文）。
   text-wrap:balance 讓多行標題自動平均分行，不會留下最後一行只有一個字的孤字；
   不支援的瀏覽器就照舊斷行，沒有副作用。 */
h1,h2,h3{font-family:var(--font-display);font-weight:300;letter-spacing:-.01em;margin:0;
  text-wrap:balance}
/* 內文段落用 pretty：只修掉孤字，不重排整段，長文比 balance 划算 */
p,li,figcaption{text-wrap:pretty}
b{font-weight:500}

/* ---------- 顆粒層（1.23.0） ----------
   純平面的暗色背景在大面積漸層（hero 暗角、卡片遮罩）上會出現色帶（banding），
   在便宜的螢幕上尤其明顯。疊一層極淡的雜訊可以把色階打散，順便讓整個站
   從「數位平面」變成接近底片的質地——這是攝影作品集該有的觸感。

   實作用內聯 SVG feTurbulence，不需要任何圖檔、零額外請求。
   z-index:99 剛好在頁首（100）之下：顆粒蓋住所有頁面內容，
   但導覽列、燈箱（1000）、開場遮罩（9999）、自訂游標（100000）保持乾淨。
   pointer-events:none 確保它完全不影響點擊。 */
body::before{content:"";position:fixed;inset:0;z-index:var(--z-grain);pointer-events:none;
  opacity:.04;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:160px 160px}
/* 印表與高對比模式下不需要顆粒 */
@media print{body::before{display:none}}

@media (hover:hover) and (pointer:fine){
  /* 前綴是 cv-cursor，不是 js（1.36.1）。這個差別是這一整段的重點。
     ─────────────────────────────────────────────────────────────
     把原生游標關掉的是這裡，把自訂游標畫出來的是 chaovisual.js。
     兩件事必須綁在一起，否則讀者會落入「原生游標被關掉、自訂游標又沒生出來」
     的狀態：整個網站沒有任何指標，等於完全不能操作。

     原本綁的是 html.js——那個 class 只代表「行內腳本跑了」，
     不代表自訂游標真的活著。中間還隔著「主腳本要載到」「不能中途出錯」
     「這台裝置要有滑鼠」三道，任何一道沒過，游標就會憑空消失一段時間，
     直到 2.6 秒的看門狗才補救。

     cv-cursor 由 chaovisual.js 在自訂游標**確實接好事件之後**才加上，
     所以它代表的是「替代品已經在畫面上了」。原生游標只在這個前提下才藏，
     那個空窗期就不存在了——不是縮短，是消失。 */
  html.cv-cursor body,html.cv-cursor a,html.cv-cursor button,
  html.cv-cursor .tile{cursor:none}

  /* 安全網：主腳本沒到位時，把原生游標還給讀者。
     :not(.cv-cursor) 是 1.36.1 補的，而且是這次「圓點不見了」的真正原因。
     ─────────────────────────────────────────────────────────────
     cv-bail 由 header.php 的看門狗加上，而它會被**頁面上任何一支腳本**的
     錯誤觸發——包含 WooCommerce、金流、統計碼這些跟本主題無關的腳本。
     原本的規則一看到 cv-bail 就把圓點 display:none 掉，於是：
     主題的游標好端端地在跑，某支第三方腳本丟了一個無害的例外，
     圓點就永久消失了。裝了商店之後頁面上的腳本變多，這件事就從
     「理論上會發生」變成「每天都在發生」。

     所以安全網只在**自訂游標真的沒起來**的時候才動手。
     游標活著就不關它的事——它要救的是「沒有游標」，不是「有游標但別處出錯」。 */
  html.cv-bail:not(.cv-cursor),
  html.cv-bail:not(.cv-cursor) *{cursor:auto!important}
  html.cv-bail:not(.cv-cursor) a,html.cv-bail:not(.cv-cursor) button,
  html.cv-bail:not(.cv-cursor) summary,html.cv-bail:not(.cv-cursor) [role="button"],
  html.cv-bail:not(.cv-cursor) .tile{cursor:pointer!important}
  html.cv-bail:not(.cv-cursor) .cursor-dot,
  html.cv-bail:not(.cv-cursor) .cursor-ring{display:none!important}

  /* 外掛（燈箱／曲面滾動／章節／篩選列）的元件自己帶了 cursor:pointer 或
     cursor:zoom-in，專一性比上面那一行的 body/button 高，會把原生箭頭叫回來，
     結果同一個畫面同時出現「原生箭頭 + 自訂游標」兩個游標。
     這裡把它們一併交還給自訂游標。前面刻意加 html，是為了讓專一性穩穩高過
     外掛端的單一類別選擇器，不必去賭兩支 CSS 檔案的載入順序。 */
  html.cv-cursor .cg-lightbox *,html.cv-cursor .cg-flow *,
  html.cv-cursor .cchap-lb *,html.cv-cursor .cg-f,html.cv-cursor .cg-nav button,
  html.cv-cursor .kg-f,html.cv-cursor .cchap-zoom{cursor:none}

  /* WooCommerce 的按鈕與連結同樣自己帶 cursor:pointer（1.36.1）。
     商品頁、購物車、結帳都會出現，不接回來的話商店那幾頁會變成
     「原生箭頭 + 圓點」兩個游標一起跑。 */
  html.cv-cursor .woocommerce a,html.cv-cursor .woocommerce button,
  html.cv-cursor .woocommerce .button,html.cv-cursor a.button,
  html.cv-cursor .wc-block-components-button{cursor:none}

  /* 照片牆的項目自己帶了 cursor:pointer（觸控裝置需要它來表示可點），
     而那條規則寫在檔案後面、專一性又跟 body 那行一樣，會贏過上面的 cursor:none，
     結果桌機上同時出現原生箭頭和自訂游標。加 html 前綴把專一性拉高一級收回來。 */
  html.cv-cursor .pw-item,html.cv-cursor .pw-item *{cursor:none}
}

/* ---------- 自訂游標 ----------
   z-index 必須高過站上所有的覆蓋層，否則會發生「燈箱裡完全沒有游標」：
   body 的 cursor:none 是繼承屬性，早就把原生游標關掉了，而自訂游標若被
   燈箱蓋住，使用者就什麼都看不到。目前最高的覆蓋層是外掛燈箱與曲面滾動
   （99999）、章節燈箱（99990），所以這裡取 100000。
   日後新增覆蓋層時，請保持在 100000 以下。 */
.cursor-dot,.cursor-ring{position:fixed;top:0;left:0;pointer-events:none;z-index:var(--z-cursor);
  border-radius:50%;transform:translate(-50%,-50%);mix-blend-mode:difference}
.cursor-dot{width:6px;height:6px;background:#fff}
.cursor-ring{width:38px;height:38px;border:1px solid rgba(255,255,255,.6);
  transition:width .3s var(--ease),height .3s var(--ease),background .3s var(--ease)}
.cursor-ring.hover{width:64px;height:64px;background:rgba(255,255,255,.12);border-color:transparent}
@media (hover:none){.cursor-dot,.cursor-ring{display:none}}

/* ---------- 燈箱開啟時的游標 ----------
   目標有兩個：游標要壓在照片最上面，而且在照片外圍那圈接近純黑的空白區
   要是白的（反白），黑色的在那裡等於沒有。

   為什麼不直接用 mix-blend-mode:difference 來「反白」：
   difference 是「跟背後的顏色相減」。背後是純黑時算出白色、純白時算出黑色，
   看起來很聰明——但照片裡大量出現的中灰（約 #808080）減白色之後還是中灰，
   結果就是游標在照片的中間調區域整個消失。這不是理論，是這類游標最常見的
   災情，而攝影作品集裡中灰佔的面積偏偏最大。

   所以改成「不靠背景計算、自己帶對比」：白色實心 + 一圈深色描邊。
   純黑底上看到的是白色（就是要的反白），亮部或中灰上白色本身夠亮，
   真的撞到很亮的天空時還有深色描邊撐著，任何底色都不會消失。
   顏色固定也少一次合成運算，不必再賭瀏覽器怎麼處理混色根。 */
/* cursor-media 由 chaovisual.js 在游標壓到任何照片表面時加上。
   燈箱之外的照片（照片牆、作品格線、系列卡片、單篇 hero）同樣會讓
   difference 混色失效，用的是同一帖藥，所以直接併進同一組選擇器。 */
html.overlay-open .cursor-dot,html.cchap-lb-open .cursor-dot,html.cursor-media .cursor-dot{
  mix-blend-mode:normal;background:#fff;width:8px;height:8px;
  box-shadow:0 0 0 1.5px rgba(0,0,0,.6),0 1px 6px rgba(0,0,0,.5)}
html.overlay-open .cursor-ring,html.cchap-lb-open .cursor-ring,html.cursor-media .cursor-ring{
  mix-blend-mode:normal;border-color:rgba(255,255,255,.92);
  box-shadow:0 0 0 1px rgba(0,0,0,.45),inset 0 0 0 1px rgba(0,0,0,.45)}
/* 停在照片或按鈕上時圈會放大。原本會把邊框設成透明、只留半透明填色，
   在亮部上就整個看不見了；這裡保留邊框，只把填色加上去。 */
html.overlay-open .cursor-ring.hover,html.cchap-lb-open .cursor-ring.hover,html.cursor-media .cursor-ring.hover{
  background:rgba(255,255,255,.18);border-color:rgba(255,255,255,.95)}

/* ---------- 導覽列 ---------- */
.site-header{position:fixed;top:0;left:0;right:0;z-index:var(--z-header);
  padding:22px var(--pad);display:flex;justify-content:space-between;align-items:center;
  transition:background .4s var(--ease),padding .4s var(--ease),backdrop-filter .4s}
/* 頂部漸層 scrim：讓導覽列文字在「淺色 hero 圖」上也永遠清楚可讀；捲動出現實心底時淡出 */
.site-header::before{content:"";position:absolute;left:0;right:0;top:0;height:130px;z-index:-1;
  pointer-events:none;background:linear-gradient(180deg,rgba(6,6,8,.62),rgba(6,6,8,0));
  opacity:1;transition:opacity .4s var(--ease)}
.site-header.scrolled::before{opacity:0}
.site-header.scrolled{background:rgba(11,11,13,.72);backdrop-filter:blur(14px);
  padding:14px var(--pad);border-bottom:1px solid var(--line)}
.logo{font-family:var(--font-display);font-weight:500;letter-spacing:.2em;font-size:15px;color:var(--ink);
  text-shadow:0 1px 14px rgba(0,0,0,.5)}
.logo span{color:var(--accent)}
.nav-list{display:flex;gap:34px;list-style:none;margin:0;padding:0;
  font-family:var(--font-display);font-weight:400;font-size:13px;letter-spacing:.14em}
.nav-list a{color:rgba(244,244,242,.86);position:relative;transition:color .3s;
  text-shadow:0 1px 12px rgba(0,0,0,.45)}
.nav-list a::after{content:"";position:absolute;left:0;bottom:-6px;width:0;height:1px;
  background:var(--accent);transition:width .35s var(--ease)}
.nav-list a:hover{color:var(--ink)}
.nav-list a:hover::after{width:100%}
/* 目前所在頁面的指示（1.23.0）
   使用者要看得出自己在哪一頁。WordPress 選單會自動加上 current-menu-item 等
   類別；header.php 的預設導覽（還沒建立選單時）則由 PHP 補上 aria-current。
   兩條路徑都收在同一組選擇器裡。 */
.nav-list .current-menu-item > a,
.nav-list .current_page_item > a,
.nav-list .current-menu-ancestor > a,
.nav-list .current-menu-parent > a,
.nav-list a[aria-current]{color:var(--ink)}
.nav-list .current-menu-item > a::after,
.nav-list .current_page_item > a::after,
.nav-list .current-menu-ancestor > a::after,
.nav-list .current-menu-parent > a::after,
.nav-list a[aria-current]::after{width:100%;background:var(--accent);opacity:.75}
/* 命中框至少 44×44（1.32.0）。原本是 padding:6px + 兩條 1.5px 的線 + 5px 間距
   ＝ 36×20，連 WCAG 2.2 最低的 24×24 都不到，而這是手機上最重要的一顆按鈕。
   同一份檔案裡 .footer-social a 是 44×44、.cv-fab-btn 是 46×46，
   所以 44 是本站既有的標準，不是新訂的數字。
   用 min-width/min-height + 置中撐開命中框，兩條線的外觀完全不變。 */
.nav-toggle{display:none;background:none;border:none;
  flex-direction:column;align-items:center;justify-content:center;gap:5px;
  min-width:44px;min-height:44px;padding:6px;margin-right:-6px;
  position:relative;z-index:var(--z-nav-close)}
.nav-toggle span{width:24px;height:1.5px;background:var(--ink);transition:.3s}

/* 選單展開時，頁首本身不可以有 backdrop-filter：
   任何非 none 的 filter／backdrop-filter／transform 都會讓子元素的 position:fixed
   改以「頁首」為定位基準，行動版全螢幕遮罩就會縮成頁首那一條、選項往下溢出。
   （這正是捲動後才出現、在頁面頂端時正常的原因——.scrolled 才加上模糊。） */
.site-header.nav-open,
.site-header.scrolled.nav-open{
  background:rgba(11,11,13,.96);
  backdrop-filter:none;-webkit-backdrop-filter:none;
  filter:none}
.site-header.nav-open::before{opacity:0}

/* 選單展開時鎖住背景捲動（由 chaovisual.js 加在 <html> 上） */
html.nav-lock,html.nav-lock body{overflow:hidden;overscroll-behavior:none}

@media(max-width:760px){
  .nav-toggle{display:flex}
  .primary-nav{position:fixed;top:0;left:0;right:0;bottom:0;width:100%;
    height:100vh;height:100dvh;              /* dvh：避開 IG／LINE 內建瀏覽器的浮動網址列 */
    background:rgba(11,11,13,.97);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
    display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;visibility:hidden;
    transition:opacity .4s var(--ease),visibility .4s;z-index:var(--z-nav-backdrop);
    overflow-y:auto;-webkit-overflow-scrolling:touch;padding:80px var(--pad)}
  .nav-open .primary-nav{opacity:1;pointer-events:auto;visibility:visible}
  .nav-list{flex-direction:column;gap:28px;text-align:center;font-size:20px;width:100%}
  .nav-list a{display:inline-block;padding:6px 10px}   /* 手機加大點擊範圍 */
  .nav-open .nav-toggle span:first-child{transform:translateY(3.25px) rotate(45deg)}
  .nav-open .nav-toggle span:last-child{transform:translateY(-3.25px) rotate(-45deg)}
}

/* ---------- Hero ----------
   圖層由下往上（z-index）：
     0  .hero-photo   背景照片（可選）
     1  .hero::before 光暈漸層
     2  .hero-grain   顆粒
     3  .hero-scrim   文字底襯
     4  .hero-bg      Canvas 動畫 ／ .hero-fx 游標軌跡
     5  .hero::after  暗角
     6  .hero-inner   文字 ／ .scroll-cue

   底襯刻意排在動畫「下面」：要壓暗的是背景，不是動畫。
   壓在上面的話，粒子與水波會跟著一起被洗掉，而那正是要給人看的東西。

   下面每一個 var() 都有 fallback。fallback 不是為了美觀，是為了讓
   這份 CSS 單獨存在時也能正確渲染——自訂器的值由 inc/hero.php 以
   inline style 補上，若那段因故沒輸出（外掛把 inline style 拆掉、
   快取拿到舊版），有 fallback 才不會整個封面變透明。 */
.hero{height:100vh;height:100svh;position:relative;
  overflow:hidden;text-align:center;background:var(--hero-bg,var(--bg))}

/* 背景照片。視差留在這一層（它是實拍，上下多出來的 8% 有東西可看），
   Canvas 那一層不再做視差——動畫的座標系必須跟視窗對齊，
   粒子從底部升起、水波從中段往下排，畫布一旦超出視窗，
   「底部」就跑到看不見的地方去了。 */
.hero-photo{position:absolute;inset:-8% 0;z-index:0;display:none;
  opacity:var(--hero-fade,1);will-change:transform}
.hero[data-hero-bg="photo"] .hero-photo,
.hero[data-hero-bg="both"] .hero-photo{display:block}
.hero-photo img{width:100%;height:100%;object-fit:cover;
  object-position:var(--hero-photo-pos,50% 50%);filter:blur(var(--hero-photo-blur,0px))}
.hero-photo::after{content:"";position:absolute;inset:0;background:#06060a;
  opacity:var(--hero-photo-dim,.42)}

/* 光暈：從底部升起的那道光。圓心刻意推到 100% 以外，
   看起來才像光源在畫面之外、只有邊緣透進來。 */
.hero::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  opacity:var(--hero-fade,1);
  background:radial-gradient(var(--hero-glow-w,120%) var(--hero-glow-h,82%) at 50% var(--hero-glow-y,112%),
    var(--hero-c-hi,#f2c88a) 0%,
    color-mix(in srgb, var(--hero-c-hi,#f2c88a) 55%, var(--hero-c-mid,#a9793a)) 14%,
    var(--hero-c-mid,#a9793a) 26%,
    color-mix(in srgb, var(--hero-c-mid,#a9793a) 50%, var(--hero-c-low,#191410)) 40%,
    var(--hero-c-low,#191410) 55%,
    color-mix(in srgb, var(--hero-c-low,#191410) 45%, var(--hero-bg,var(--bg))) 70%,
    var(--hero-bg,var(--bg)) 88%)}
.hero[data-hero-bg="photo"]::before{display:none}
.hero[data-hero-bg="both"]::before{mix-blend-mode:soft-light;opacity:calc(.92 * var(--hero-fade,1))}

/* 顆粒。尺寸固定 128px 不用百分比——用百分比的話每個視窗寬度都會把
   同一張雜訊拉伸成不同粗細，同一個站在筆電和手機上看起來會是兩種材質。
   它同時是防色帶的抖動層：大面積漸層在暗處會出現一圈一圈的色階，
   顆粒打散了那些邊界。 */
.hero-grain{position:absolute;inset:0;z-index:2;pointer-events:none;
  opacity:calc(var(--hero-grain,.16) * var(--hero-fade,1));
  mix-blend-mode:overlay;background-repeat:repeat;background-size:128px 128px;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='128' height='128'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='128' height='128' filter='url(%23n)' opacity='0.55'/></svg>")}

/* 文字底襯：橢圓，只壓標題後面那一塊。

   --hero-scrim-k 在背景是照片時加重。理由是可量的：同一個底襯設定下，
   純漸層背景的標題對比是 4.9:1（過 AA），換成苔蘚那張逆光照只剩 3.93:1，
   因為照片在文字那一帶有高光細節，漸層沒有。
   照片背景本來就需要更多的壓暗，這一條把它寫成規則，
   而不是要求使用者每次換圖都自己想起來去拉那根滑桿。 */
.hero-scrim{position:absolute;inset:0;z-index:3;pointer-events:none;
  opacity:var(--hero-fade,1);
  background:radial-gradient(118% 26% at 50% calc(var(--hero-text-y,64%) + 7%),
    rgba(6,6,10,calc(var(--hero-scrim,.42) * var(--hero-scrim-k,1))) 0%,
    rgba(6,6,10,calc(var(--hero-scrim,.42) * var(--hero-scrim-k,1) * .62)) 46%,
    rgba(6,6,10,0) 80%)}
.hero[data-hero-bg="photo"],
.hero[data-hero-bg="both"]{--hero-scrim-k:1.5}

.hero-bg{position:absolute;inset:0;z-index:4;opacity:var(--hero-fade,1)}
.hero-canvas{width:100%;height:100%;display:block}
/* 滑鼠拖行軌跡與點擊光暈的畫布。跟動畫同層，pointer-events:none 才不會擋住標題。 */
.hero-fx{position:absolute;inset:0;z-index:4;width:100%;height:100%;display:block;
  pointer-events:none;opacity:var(--hero-fade,1)}
.hero::after{content:"";position:absolute;inset:0;z-index:5;pointer-events:none;
  background:radial-gradient(125% 95% at 50% 42%,transparent 42%,
    rgba(6,6,10,var(--hero-vig,.55)) 100%)}

/* 標題落在動畫下方，位置由 --hero-text-y 控制（自訂器可調）。

   min() 是溢出保險。380px 這個數字是量出來的，不是估的：
   文字區塊（兩行大標＋中文一句＋按鈕）最高約 256px，
   底下的 SCROLL 提示連同它的下緣留白約佔 108px，再留 16px 不讓兩者貼著。
   矮視窗（橫放的手機、分割視窗、小筆電）把 64% 換算出來的位置
   會讓按鈕直接壓在 SCROLL 上面，這一段保證兩者永遠排得下。
   視窗夠高時 380px 完全不會生效，位置仍然是自訂器裡設的那個百分比。 */
.hero-inner{position:absolute;left:0;right:0;
  top:min(var(--hero-text-y,64%), calc(100% - 380px));
  z-index:6;padding:0 6vw;text-align:center;opacity:var(--hero-fade,1)}
@media(max-width:640px){
  .hero-inner{padding:0 8vw}
  .hero-inner .eyebrow{margin-bottom:10px;font-size:11px;letter-spacing:.32em}
  .hero-inner h1{line-height:1.08}
  .hero-inner p{font-size:14px;margin-top:10px;max-width:86vw}
  .scroll-cue::after{height:26px}
}
.eyebrow{font-family:var(--font-display);font-weight:400;
  font-size:12px;letter-spacing:.4em;color:var(--muted);text-transform:uppercase}
/* 頁首的眉標現在是中文（關於／服務／聯絡／作品／山岳）。
   .4em 是為拉丁字母調的——套在兩個中文字上會變成「關　於」，
   看起來像排版壞掉。中文本來就有字身框撐開間距，.18em 就夠了。 */
.page-hero .eyebrow{letter-spacing:.18em;font-size:13px}
.hero-inner .eyebrow{margin-bottom:26px;display:block;opacity:0;transform:translateY(20px)}
/* 封面大標是英文，維持 Jost 的 300 與寬字距——那是這個站的臉。 */
.hero-inner h1{font-family:var(--font-display);
  font-size:clamp(1.9rem,4.6vw,3.5rem);font-weight:300;letter-spacing:.05em;line-height:1.14;
  opacity:0;transform:translateY(28px)}
/* 強調字改成同一套字體的加粗，不用斜體（1.34.0）。
   主標從英文換成中文之後，italic 會變成瀏覽器合成的假斜體——
   中文字沒有真正的斜體字型，機器把每個字往右推一個角度，
   筆畫粗細會歪掉，在大字級上特別明顯。
   同字體加粗是中文排版裡正確的強調方式。 */
.hero-inner h1 b{font-style:normal;font-weight:500}
.hero-inner p{margin:24px auto 0;color:var(--muted);max-width:460px;font-size:15px;
  opacity:0;transform:translateY(20px)}
/* 中文輔句：跟在英文大標後面。字級小一階但不縮太小——
   它負責「他到底在做什麼」，讀者真正要讀懂的是這一行。
   字距用 .1em：中文不像拉丁字母靠字距撐氣質，放太寬只會變鬆散。 */
.hero-inner .hero-zh{margin-top:18px;color:var(--ink);
  font-size:clamp(15px,1.5vw,17px);letter-spacing:.1em;line-height:1.7;
  max-width:none;opacity:0;transform:translateY(20px)}
.hero-inner .hero-cta{margin-top:30px;opacity:0;transform:translateY(20px)}
/* 封面的兩顆按鈕（1.65.6）。
   .hero-cta 留在外層容器上，進場動畫與兩組安全網的選擇器都不必動。
   這裡只負責排成一列：hero-inner 本來就 text-align:center，
   但 flex 容器不吃 text-align，所以要自己寫 justify-content。
   換行交給 flex-wrap——兩顆中英並列的按鈕在 390px 的手機上
   本來就放不下，硬擠只會把字距壓掉。 */
.hero-ctas{display:flex;gap:12px;flex-wrap:wrap;justify-content:center}
/* 第二顆是實心的。這是全站唯一一顆「主要動作」按鈕，
   金色在這裡是狀態（可按、而且是最該按的那一顆），不是裝飾。
   文字用 var(--on-accent) 而不是 var(--bg)：對比 7.98:1，過 AA 也過 AAA。 */
.hero-ctas .hero-cta-go{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.hero-ctas .hero-cta-go:hover{background:#d8b673;border-color:#d8b673;color:var(--on-accent)}
/* 兩顆按鈕在窄螢幕會折成兩行，比原本高約 50px。
   上面的 top:min(…, calc(100% - 380px)) 是為一行按鈕算的，
   不放寬的話文字整組會被推到畫面外。
   用 :has() 只在「真的有兩顆」時才生效，不支援 :has() 的瀏覽器
   維持原本的 380px，也就是回到 1.65.5 的行為。 */
.hero-inner:has(.hero-ctas a + a){top:min(var(--hero-text-y,64%), calc(100% - 440px))}
.scroll-cue{position:absolute;bottom:34px;left:50%;transform:translateX(-50%);z-index:6;
  font-size:11px;letter-spacing:.3em;color:var(--muted);display:flex;flex-direction:column;
  align-items:center;gap:10px;opacity:var(--hero-fade,1)}
.scroll-cue::after{content:"";width:1px;height:46px;background:linear-gradient(rgba(255,255,255,.5),transparent);
  animation:cue 2s var(--ease) infinite}
@keyframes cue{0%{transform:scaleY(0);transform-origin:top}45%{transform:scaleY(1);transform-origin:top}
  55%{transform:scaleY(1);transform-origin:bottom}100%{transform:scaleY(0);transform-origin:bottom}}
.hero.in .eyebrow{opacity:1;transform:none;transition:.9s var(--ease) .1s}
.hero.in h1{opacity:1;transform:none;transition:1s var(--ease) .25s}
.hero.in p{opacity:1;transform:none;transition:.9s var(--ease) .5s}
.hero.in .hero-zh{opacity:1;transform:none;transition:.9s var(--ease) .42s}
.hero.in .hero-cta{opacity:1;transform:none;transition:.9s var(--ease) .7s}

/* ---------- 首頁 INTRO 與 PHILOSOPHY（1.34.0） ----------
   兩段都是純文字。刻意不放照片、不放卡片：
   讀者剛看完滿版的 hero，這裡需要的是一個安靜下來的地方。

   寬度比一般散文再窄一點（680px）。這兩段是「宣言」不是「說明」，
   一行不該讀太久；短行會讓人自動放慢速度。 */
.intro,.philos{padding:14vh var(--pad)}
.intro-inner,.philos-inner{max-width:680px;margin:0 auto}
/* 不指定 --font-display：Jost 沒有中文字符，這兩句本來就會落到 PingFang TC，
   寫上去只會讓人以為那是設計選擇。字重改 400——PingFang 的 300 在暗底上太細。 */
.intro-title,.philos-title{font-weight:400;
  font-size:clamp(1.5rem,3.2vw,2.2rem);letter-spacing:.02em;line-height:1.5;
  margin:0 0 18px;text-wrap:balance}
/* 同 hero：中文沒有真正的斜體，強調一律用同字體加粗。 */
.intro-title b,.philos-title b{font-style:normal;font-weight:500}
.intro-en,.philos-en{margin:0 0 30px;color:var(--muted);
  font-family:var(--font-display);font-size:13px;letter-spacing:.2em;line-height:2}
.intro-inner p,.philos-inner p{margin:0 0 16px;font-size:16px;line-height:1.9;color:var(--ink-2)}
.intro-inner p:last-of-type,.philos-inner p:last-of-type{margin-bottom:0}
.intro-inner .ghost-btn{margin-top:30px}
/* PHILOSOPHY 置中：它是整站唯一一段「不做事、只表態」的文字，
   置中把它跟前後那些要你去點的區塊分開。 */
.philos{text-align:center;background:var(--bg-soft);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
@media(max-width:640px){
  .intro,.philos{padding:10vh var(--pad)}
  .intro-en,.philos-en{letter-spacing:.14em;font-size:12px}
}

/* 首頁對照區塊（1.65.7）：同一個空間的上午與黃昏。
   ─────────────────────────────────────────────────────────
   兩半共用同一個 aspect-ratio。這一區要比的是光，
   兩張裁切比例不一樣的話，讀者第一眼比到的會是構圖。
   4/3 是刻意的：直式並排在桌機上會變成兩根柱子，
   而空間照片的訊息多半在水平方向。

   寬度用 min(1100px, 100%) 而不是 var(--maxw)：
   這一區只有兩張圖，撐到 1440 會讓它比上面的作品網格還大聲，
   但它不是作品，它是那句話的證據。 */
.philos-split{display:grid;grid-template-columns:1fr 1fr;gap:2px;
  width:min(1100px,100%);margin:44px auto 0}
.philos-split figure{position:relative;margin:0;overflow:hidden;border-radius:var(--r-img)}
.philos-split img{display:block;width:100%;height:100%;object-fit:cover;aspect-ratio:4/3}
/* 時間壓在圖上而不是放在圖下：兩個時間要能被一眼並排比較，
   中間隔著圖片邊界跟一行留白就不是比較，是兩張各自的說明。 */
.philos-split figcaption{position:absolute;left:0;right:0;bottom:0;
  padding:18px 20px;display:flex;flex-direction:column;gap:4px;text-align:left;
  background:linear-gradient(transparent,rgba(0,0,0,.62))}
.ps-time{font-family:var(--font-display);font-weight:400;
  font-size:clamp(20px,2.4vw,30px);letter-spacing:.08em;color:var(--ink);
  font-variant-numeric:tabular-nums}
.ps-note{font-size:12px;letter-spacing:.12em;color:var(--ink-2)}
.philos-link{margin-top:26px}
@media(max-width:760px){
  /* 窄螢幕改上下排。並排時每半只剩不到 190px，
     那個尺寸下兩張照片的差別會被縮圖本身吃掉。 */
  .philos-split{grid-template-columns:1fr;width:100%}
  .philos-split figcaption{padding:14px 16px}
}

/* 首頁的札記區塊沿用列表頁的卡片。
   1.34.2：原本 padding-top:0，緊貼在上一段（PHILOSOPHY）的分隔線下方，
   看起來像同一個區塊的延伸。補回上緣留白，讓它自己成為一段。 */
.home-journal{padding-top:12vh}
@media(max-width:640px){.home-journal{padding-top:9vh}}

/* ---------- 區塊通用 ---------- */
/* 上下留白刻意不對稱：視覺上「區塊結束」需要比開頭更多的呼吸空間，
   數學上等寬看起來反而會像下面被切掉一截。 */
section{padding:12vh var(--pad) 13.5vh}
/* 內容最大寬度（1.23.0）
   原本頂層區塊沒有任何寬度上限，在超寬螢幕上格線會一路拉到左右螢幕邊，
   照片被壓成一長條、標題與說明也離得太遠。這裡不動 HTML，直接約束
   區塊底下的內容容器，其餘頁面（作品頁、關於頁）本來就有自己的寬度。 */
section > .sec-head,
section > .series-grid,
section > .grid,
section > .filters,
section > .journal-list,
section > .journal-layout,
section > .pager,
section > .navigation,
section > .empty-hint{max-width:var(--maxw);margin-left:auto;margin-right:auto}
/* 註（1.34.2）：這一段以下的文字寬度一律用 px，不用 ch。
   ch 是「數字 0 的寬度」，約 0.5em；中文字是 1em，所以 52ch 只裝得下
   約 29 個中文字——看起來像被硬折成一條窄柱。中文排版只能用長度單位。

   區塊標題群（1.34.2 改成兩欄格線）。
   原本是 flex + space-between，三個子元素（標題、說明、按鈕）會被平均推開，
   說明剛好落在正中間——那個位置不屬於任何一邊，讀起來像漂在半空中。
   現在說明直接接在標題底下（同一欄、同一條左邊界），按鈕靠右下角。 */
.sec-head{display:grid;grid-template-columns:1fr auto;
  align-items:end;column-gap:44px;row-gap:14px;margin-bottom:48px}
/* 區塊大標：中文為主、英文為輔（1.34.1）。
   letter-spacing 改成 0：-.02em 是為拉丁字母收緊字間而設的，
   套在中文上會讓相鄰的字擠在一起，筆畫多的字尤其明顯。 */
.sec-head h2{grid-column:1;grid-row:1;margin:0;
  font-size:clamp(1.7rem,3.6vw,2.6rem);letter-spacing:0;line-height:1.35}
.sec-head h2 span{display:block;margin-top:10px;
  font-family:var(--font-display);font-weight:300;
  font-size:12px;letter-spacing:.28em;text-transform:uppercase;color:var(--muted)}
.sec-head p{grid-column:1;grid-row:2;margin:0;
  color:var(--muted);font-size:14px;line-height:1.9;max-width:620px}
/* 按鈕跨兩列、貼齊右下角：它對齊的是整個標題群，不是其中某一行。 */
.sec-head .ghost-btn{grid-column:2;grid-row:1 / span 2;align-self:end;justify-self:end}
@media(max-width:760px){
  /* 手機收成單欄：按鈕排到說明底下，靠左與標題同一條邊界。 */
  .sec-head{grid-template-columns:1fr;row-gap:16px}
  .sec-head .ghost-btn{grid-column:1;grid-row:auto;justify-self:start}
}
/* <a> 與 <button> 兩種都會用到這個 class，所以 inline-flex ＋ 明寫背景與游標，
   否則 <button> 會帶著瀏覽器預設的灰底與 text 游標。 */
.ghost-btn{display:inline-flex;align-items:center;justify-content:center;
  background:none;cursor:pointer;
  border:1px solid var(--line);padding:11px 24px;border-radius:var(--r-pill);
  font-family:var(--font-display);font-weight:400;
  font-size:13px;letter-spacing:.05em;color:var(--muted);
  transition:color .3s var(--ease),border-color .3s var(--ease),background .3s var(--ease),transform .12s var(--ease)}
.ghost-btn:hover{color:var(--ink);border-color:rgba(255,255,255,.35)}
/* 按下去要有回饋：沒有 :active 的按鈕摸起來像圖片，不像按鈕 */
.ghost-btn:active{transform:translateY(1px) scale(.985)}
.chaovisual-noimg{width:100%;padding-top:66%;background:
  linear-gradient(135deg,#17171c,#0e0e12)}
.empty-hint{color:var(--muted);font-size:14px;padding:40px 0}

/* ---------- 作品系列 ----------
   1.22.0 之後系列從三個（空間／人像／山岳）變成五個（＋人物／植物），
   原本寫死的 repeat(3,1fr) 會留下一排只有兩張的孤兒列。
   改成兩段式：
   1) 基礎用 auto-fill 自動填滿，不管幾個系列都不會破格；
   2) 剛好五個時，桌機切換成 2＋3 的非對稱編輯式版面
      （上排兩張寬的、下排三張），比五等分好看，也避開
      「三個等寬卡片」這種到處都看得到的通用排版。
   數量由 front-page.php 寫進 data-count，CSS 不必猜。 */
/* 系列入口：首頁精選作品底下的一行文字連結（1.56.0）。
   取代原本的整區系列卡片——兩個緊鄰的照片網格在做同一件事，
   而其中一個放的是分類卡，那是選單不是照片。詳見 front-page.php 的說明。
   `.series-grid` 以下那一整套仍然留著：系列封存頁還在用。 */
.series-links{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px 14px;
  margin-top:34px;padding-top:24px;border-top:1px solid var(--line)}
.series-links-lead{font-size:11px;letter-spacing:.2em;color:var(--muted);text-transform:uppercase}
.series-links a{font-size:14px;letter-spacing:.06em;color:var(--muted);transition:color .3s var(--ease)}
.series-links a:hover{color:var(--accent)}
.series-links i{font-style:normal;color:var(--line);margin:0 2px}
@media(max-width:640px){
  .series-links{gap:8px 10px}
  .series-links-lead{flex:1 0 100%}
}

.series-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:18px}
@media(min-width:1024px){
  .series-grid[data-count="5"]{grid-template-columns:repeat(6,1fr)}
  .series-grid[data-count="5"] > *{grid-column:span 2}
  .series-grid[data-count="5"] > :nth-child(-n+2){grid-column:span 3}
  /* 上排兩張變寬，3/4 直式會拉得過高，改成較平緩的比例 */
  .series-grid[data-count="5"] > :nth-child(-n+2) .series-img{aspect-ratio:4/3}
  .series-grid[data-count="4"]{grid-template-columns:repeat(4,1fr)}
  .series-grid[data-count="3"]{grid-template-columns:repeat(3,1fr)}
}
.series-card{position:relative;overflow:hidden;border-radius:var(--r-img);background:var(--bg-soft);
  opacity:0;transform:translateY(40px);transition:opacity .8s var(--ease),transform .8s var(--ease)}
.series-card.reveal{opacity:1;transform:none}
.series-img{aspect-ratio:3/4;overflow:hidden}
.series-img img{width:100%;height:100%;object-fit:cover;
  filter:grayscale(.2) brightness(.8);transition:transform .9s var(--ease),filter .6s}
.series-card:hover .series-img img{transform:scale(1.06);filter:grayscale(0) brightness(1)}
/* 遮罩比原本更早開始變暗：細線與文字都壓在照片上，
   遇到亮部（天空、白牆）時純靠底部漸層會讀不出來。 */
.series-cap{position:absolute;left:0;right:0;bottom:0;padding:52px 24px 24px;
  background:linear-gradient(transparent,rgba(0,0,0,.5) 42%,rgba(0,0,0,.88))}
/* 細線標籤列：英文系列名靠左、中文副標靠右，中間那條 1px 線就是分隔。
   原本兩行上下堆疊，讀起來像「標題＋說明」；改成同一條 baseline 的
   左右對位之後，卡片下緣有一條乾淨的水平線，五張卡並排時對得起來。 */
.series-label-row{display:flex;align-items:baseline;justify-content:space-between;gap:18px;
  padding-top:14px;border-top:1px solid rgba(255,255,255,.28)}
.series-name{font-family:var(--font-display);font-weight:400;font-size:20px;letter-spacing:.1em;
  line-height:1.1;white-space:nowrap}
.series-sub{color:rgba(255,255,255,.74);font-size:13px;letter-spacing:.04em;text-align:right}
/* 英文關鍵字行：告訴讀者這個系列實際包含什麼，也順便餵給搜尋引擎。
   壓在照片上，所以用 .74 而不是 --muted——--muted 是為 #0b0b0d 的底色調的，
   照片的亮部會把它吃掉。 */
.series-keys{display:block;margin-top:9px;color:rgba(255,255,255,.74);
  font-family:var(--font-display);font-size:11px;letter-spacing:.14em}
@media(max-width:480px){
  .series-label-row{flex-direction:column;align-items:flex-start;gap:4px}
  .series-sub{text-align:left}
  .series-keys{font-size:11px;letter-spacing:.1em}
}
@media(max-width:760px){.series-grid{grid-template-columns:1fr}}

/* 圖片骨架底色：照片還沒下載完（或訪客網路斷線、圖檔 404）時，
   用同色系的色塊把格子撐住，版面不會先塌一次再跳回來。
   對攝影網站特別有感——首屏往往是好幾 MB 的大圖。 */
.series-img img,.tile img,.jc-media,.jc-media img,
.sw-more-img img,.pw-item img,.lb-img-wrap img{background:var(--bg-soft)}

/* ---------- 作品網格（統一比例，整齊一致） ---------- */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:18px}
.tile{position:relative;display:block;overflow:hidden;aspect-ratio:1/1;   /* 統一正方形，改 4/5 或 3/2 可換比例 */
  border-radius:var(--r-img);background:var(--bg-soft);opacity:0;transform:translateY(40px);
  transition:opacity .8s var(--ease),transform .8s var(--ease)}
.tile.reveal{opacity:1;transform:none}
.tile.hide{display:none}
.journal-card.hide{display:none}
.tile img{width:100%;height:100%;object-fit:cover;transition:transform .9s var(--ease),filter .6s;
  filter:grayscale(.15) brightness(.92)}
.tile:hover img{transform:scale(1.06);filter:grayscale(0) brightness(1)}
.tile .meta{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:flex-end;
  padding:20px;background:linear-gradient(transparent 45%,rgba(0,0,0,.75));
  opacity:0;transition:opacity .5s var(--ease)}
.tile:hover .meta{opacity:1}
.tile .meta .cat{font-size:11px;letter-spacing:.18em;color:rgba(255,255,255,.8);text-transform:uppercase}
.tile .meta .ttl{font-size:18px;margin-top:4px}

/* ---------- 純文字替代（讀螢幕軟體專用） ----------
   全站原本沒有這條規則，而樣板裡已經有 .screen-reader-text 的用法——
   等於那些字會直接印在畫面上。用 clip-path 而不是 display:none：
   display:none 會讓內容從無障礙樹上消失，aria-live 也就永遠不會播報。 */
.screen-reader-text{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.screen-reader-text:focus{position:static!important;width:auto;height:auto;margin:0;
  clip:auto;clip-path:none;white-space:normal}

/* ---------- 篩選列 ---------- */
/* 選項可能是 <button>（就地篩選）或 <a>（真的會過去的系列頁），兩種一起選。 */
.filters{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:40px}
.filters button,.filters a{display:inline-flex;align-items:center;
  background:transparent;border:1px solid var(--line);color:var(--muted);
  padding:9px 20px;min-height:36px;border-radius:var(--r-pill);
  font-family:var(--font-display);font-weight:400;
  font-size:13px;letter-spacing:.05em;text-decoration:none;cursor:pointer;
  transition:color .3s var(--ease),border-color .3s var(--ease),background .3s var(--ease),transform .12s var(--ease)}
.filters button:hover,.filters a:hover{color:var(--ink);border-color:rgba(255,255,255,.3)}
.filters button:active,.filters a:active{transform:translateY(1px) scale(.985)}
.filters button.active,.filters a.active{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}

/* 系列的父子兩層（1.63.0；1.64.1 改成兩欄）。
   ─────────────────────────────────────────────────────────
   第一欄是「全部」與父層，第二欄是展開中那一支的子層。

   1.64.0 時兩層排在同一排，靠字級與亮度分層。實際看下來不夠：
   展開之後父層與子層混成一長條，那個字級差在手機上幾乎看不出來。
   分成兩欄之後，位置本身就說明了從屬關係，不必依賴樣式。

   .filters-tree 只掛在作品的兩排篩選列上——journal 的篩選列共用
   .filters 這個 class，但它沒有階層，不該被改成直式。 */
.filters-tree{flex-direction:column;align-items:flex-start;gap:12px}
.filters-row{display:flex;flex-wrap:wrap;gap:10px;align-items:center}
/* 第二欄往內縮一個字距，並用一條短分隔線起頭：
   它是「上面那一項的下一層」，不是另一組並列的選項。 */
.filters-sub{position:relative;padding-left:18px}
.filters-sub::before{content:"";position:absolute;left:0;top:50%;
  width:10px;height:1px;background:var(--line)}
.filters-sub[hidden]{display:none}

/* 父層：字距拉開、字級略小，但**有框線**（1.65.0）。
   1.64 版把未選取的父層做成無框線的純文字，結果它看起來像說明文字
   而不是可以點的東西。框線補回來，字級從 10.5px 提到 12px——
   和子層的 13px 還是有差，但已經不是「一個是標籤、一個是註解」的差距。 */
.filters a.is-parent{color:var(--muted);letter-spacing:.16em;font-size:12px}
.filters a.is-parent:hover{color:var(--ink);border-color:rgba(255,255,255,.3)}

/* 選取中的兩層用**不同顏色**（1.65.0）：
   父層是金色（--accent），子層是白底（--ink）。
   兩層都用金色時，畫面上會同時有兩顆金色膠囊，看起來像兩個並列的選取，
   而它們其實是「在哪一組」與「在哪一項」兩件事。

   選取中的父層要把字色搶回來：.filters a.active 的 color:var(--on-accent) 和
   .filters a.is-parent 權重相同（0,2,1），而 is-parent 寫在後面會贏——
   實測是 #8a8a92 壓在 #c9a35b 上，對比只有 1.45:1，遠低於 AA 的 4.5:1。 */
.filters a.is-parent.active{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.filters a.is-child.active{background:var(--ink);color:var(--bg);border-color:var(--ink)}
/* .filters a 是 inline-flex，權重比 [hidden]{display:none} 的 UA 樣式高，
   所以收起來的子層必須在這裡明講一次，否則 hidden 屬性形同無效。 */
.filters a[hidden]{display:none}

@media (max-width:640px){
  .filters-sub{padding-left:12px}
  .filters-sub::before{width:6px}
}

/* 篩選列頂替導覽列（1.65.0）。
   ─────────────────────────────────────────────────────────
   捲進作品區之後，導覽列讓位給篩選列：導覽列往上收，篩選列固定在
   同一個位置，一路跟到作品相關的區塊（格線＋照片牆）結束才放開。

   這是照片牆那排篩選列可以拿掉的前提——問題本來就是「上面那排會跟著
   區塊捲走」，把它留在畫面上就不需要第二排。

   高度佔位由 JS 產生的 .filters-spacer 負責，所以固定的那一刻不會跳版。
   沒有 JavaScript 時這整層不存在，篩選列就是頁面上的一排普通連結。 */
.filters-tree{transition:padding .3s var(--ease),background .3s var(--ease)}
/* 權重要壓過 .archive-work > .filters（同為 (0,2,0)，而它寫在後面），
   所以這裡把兩個選擇器都寫出來。 */
.filters-tree.is-stuck,
.archive-work > .filters.is-stuck{position:fixed;top:0;left:0;right:0;z-index:var(--z-sticky);
  margin:0;padding:12px var(--pad);
  background:rgba(11,11,13,.82);backdrop-filter:blur(14px);
  border-bottom:1px solid var(--line)}
/* 佔位元素永遠在版面流裡（高度 0），只有釘住時才撐出高度。
   一開始寫成 display:none，結果 getBoundingClientRect() 全部回 0，
   「捲過篩選列了沒」的判斷就永遠成立——一進頁面就把導覽列收起來。 */
.filters-spacer{display:block;height:0}

html.works-filter-stuck #site-header{
  opacity:0;transform:translateY(-102%);pointer-events:none}
/* 用鍵盤 Tab 進導覽列時要看得見自己在哪裡——這一條讓導覽列立刻回來。 */
html.works-filter-stuck #site-header:focus-within{
  opacity:1;transform:none;pointer-events:auto}

@media (prefers-reduced-motion: reduce){
  html.works-filter-stuck #site-header{transform:none}
  .filters-tree{transition:none}
}
.filters a:focus-visible,.filters button:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

/* /works/ 的篩選列置頂（1.32.0）。
   照片牆現在跟上面的格線共用同一排篩選，那排若停在頁面最上方，
   讀者捲到照片牆時就摸不到它了——「只有一排」的前提是那一排隨時在手邊。
   刻意不用 backdrop-filter：任何非 none 的 filter 都會讓子元素的 position:fixed
   改以這個容器為定位基準（頁首那段註解記過同一個坑），而且底色本來就夠不透明。 */
/* top 用實測的導覽列高度，不用寫死的數字（1.38.1 修正）。
   ─────────────────────────────────────────────────────────
   原本桌機寫 72px、手機寫 60px。但導覽列的高度是會變的：
   它在頁面頂端與捲動後有不同的 padding（會做 0.4 秒的過渡），
   而且手機比桌機高——因為 1.38.0 為了無障礙把漢堡鈕加大到 44×44。

   實測手機的導覽列是 88px（頁面頂端）與 78px（捲動後），
   而篩選列釘在 60px，所以有 18～28px 被蓋在導覽列底下。
   篩選列本身只有 62px 高，**等於少了將近一半**——
   讀者在手機上捲動時，看到的是被切掉上半截的按鈕。

   換一個更大的寫死數字只會拖到下一次改導覽列才再壞一次。
   所以改由 chaovisual.js 用 ResizeObserver 實測，寫進 --cv-header-h，
   這裡直接讀它。備援值取「較高的那一個」——多留一點空隙只是有點空，
   少留就會再次把按鈕切掉。 */
/* 1.65.0：這裡原本是 position:sticky，釘在導覽列**底下**
   （top 由 JS 量出來的 --cv-header-h 決定），而且只黏在 .archive-work
   裡面——區塊一結束就跟著捲走，照片牆因此需要自己的第二排篩選列。

   現在改成「捲到頂就頂替掉導覽列」：由 chaovisual.js 在捲過篩選列時
   加上 .is-stuck 改成 position:fixed、同時把導覽列收起來，一路跟到
   照片牆結束才放開。所以：
     ‧ 這裡不再需要 sticky，也不再需要讀 --cv-header-h。
     ‧ 照片牆那排（.filters-wall）整個拿掉了，選擇器一併刪掉。
   底色與框線也移到 .is-stuck 上——沒有釘住的時候它就是一排普通連結，
   不需要一條橫貫畫面的深色底。 */
.archive-work > .filters{margin-bottom:28px;padding:14px 0}
@media(max-width:760px){
  /* 手機：兩欄各自單行橫向捲動。換行會讓置頂列吃掉半個螢幕。 */
  .archive-work > .filters{padding:10px 0;gap:8px}
  .filters-tree .filters-row{flex-wrap:nowrap;overflow-x:auto;
    -webkit-overflow-scrolling:touch;scrollbar-width:none;gap:8px}
  .filters-tree .filters-row::-webkit-scrollbar{display:none}
  .filters-tree .filters-row a,.filters-tree .filters-row button{flex:none}
}
@media(prefers-reduced-motion:no-preference){
  .archive-work > .filters{transition:padding .3s var(--ease)}
}

/* 系列頁與作品頁的關鍵字行：小字、寬字距，是給讀者的分類線索。 */
.page-keys{margin-top:14px;color:var(--muted);
  font-family:var(--font-display);font-size:12px;letter-spacing:.18em}
























/* ---------- 燈箱 ---------- */
/* visibility:hidden 是必要的，不是保險。只用 opacity:0 + pointer-events:none
   的話，燈箱裡的關閉／上一張／下一張三顆按鈕仍然留在 Tab 順序裡——
   而燈箱是印在每一頁的，等於全站每頁開頭都有三個看不見、讀螢幕軟體也讀不到
   （aria-hidden="true"）的按鈕擋在前面。 */
/* 這裡刻意沒有 backdrop-filter：底色已經 96% 不透明，模糊幾乎看不出來，
   卻會強迫瀏覽器建立一個混色根與合成層——既拖慢開啟動畫，又讓上層
   自訂游標的 mix-blend-mode 行為變得不可預測。視覺上零損失，體感更順。 */
.lb{position:fixed;inset:0;z-index:var(--z-lightbox);background:rgba(6,6,8,.96);
  display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;
  visibility:hidden;
  transition:opacity .4s var(--ease),visibility 0s linear .4s}
.lb.open{opacity:1;pointer-events:auto;visibility:visible;
  transition:opacity .4s var(--ease),visibility 0s}
/* max-height 只寫在圖片上，不寫在外框上（1.36.0）。
   外框現在還裝著下面那一列說明與購買按鈕，若外框也限高，
   那一列就會被算進同一個 82vh 裡，圖片與文字互相擠壓。
   76vh 是留給下方那一列的空間：82 - 6（14px 間距 + 34px 按鈕）。 */
.lb-img-wrap{max-width:86vw;position:relative;margin:0}
.lb-img-wrap img{max-width:86vw;max-height:76vh;width:auto;height:auto;border-radius:var(--r-img)}
/* 開啟時的微幅放大改掛在舞台上，不掛在 <img> 上（1.47.0）。
   縮放功能是把 transform 寫成 <img> 的行內樣式，權重高於任何樣式表規則；
   進場動畫若還留在 <img> 身上，第一次 render() 就會被行內樣式蓋掉，
   動畫等於默默失效。掛在外面那一層，兩者各用各的 transform，互不干擾。 */
.lb-img-wrap > .lb-stage,
.lb-img-wrap > img{transform:scale(.96);transition:transform .5s var(--ease)}
.lb.open .lb-img-wrap > .lb-stage,
.lb.open .lb-img-wrap > img{transform:scale(1)}
/* 圖片下緣的那一列：左邊是說明，右邊是「購買這張」（1.36.0）。
   1.36.0 之前這兩個各自 position:absolute（一個 left:0、一個 right:0），
   看起來像分佔兩端，實際上是兩個獨立的框搶同一條空間——
   說明只要長一點（作品名稱＋系列＋「查看作品 →」）就會直接壓在按鈕上。
   包成一個 flex 列之後寬度由版面決定，重疊不可能發生。
   .lb-img-wrap 改成 flex column，這一列跟著圖片走，
   不必再靠負的 bottom 值去猜圖片下方還剩多少空間。 */
.lb-img-wrap{display:flex;flex-direction:column}
.lb-foot{display:flex;align-items:center;justify-content:space-between;
  gap:18px;margin-top:14px}
.lb-cap{font-size:13px;color:var(--muted);min-width:0}
/* 「購買這張」放在說明的另一側，不跟「查看作品」擠在同一行——
   那兩個是不同性質的動作：一個是繼續看，一個是要付錢。
   用金色框線：金色在這個站是狀態色，而「這張可以買」正是一種狀態。
   white-space:nowrap 是必要的：這顆按鈕不能折行，
   一折行整條說明列的高度就跳掉，而它就掛在圖片下緣。 */
.lb-buy{flex:none;display:inline-flex;align-items:center;white-space:nowrap;
  min-height:34px;padding:0 18px;border:1px solid var(--accent);border-radius:var(--r-pill);
  font-family:var(--font-display);font-size:13px;letter-spacing:.06em;
  color:var(--accent);background:transparent;
  transition:color .3s var(--ease),background .3s var(--ease)}
.lb-buy:hover,.lb-buy:focus-visible{background:var(--accent);color:var(--on-accent)}
.lb-buy:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.lb-buy[hidden]{display:none}
@media(max-width:760px){
  /* 手機一列放不下兩個東西：改成上下排，兩個都靠左與圖片左緣對齊。
     圖片高度同步收到 74vh，把下面那兩行需要的空間讓出來。 */
  .lb-foot{flex-direction:column;align-items:flex-start;gap:12px}
  .lb-img-wrap img{max-height:74vh}
}
.lb-cap b{color:var(--ink);font-weight:500}
/* 命中框 44×44：原本靠 30px 的字級撐開，實際只有約 19×30。 */
.lb-close{position:absolute;top:26px;right:34px;font-size:30px;color:var(--ink);
  background:none;border:none;line-height:1;opacity:.8;transition:.3s;
  min-width:44px;min-height:44px;display:flex;align-items:center;justify-content:center;padding:0}
.lb-close:hover{opacity:1;transform:rotate(90deg)}
.lb-nav{position:absolute;top:50%;transform:translateY(-50%);font-size:34px;color:var(--ink);
  background:none;border:none;padding:20px;opacity:.5;transition:.3s}
.lb-nav:hover{opacity:1}
.lb-prev{left:2vw}.lb-next{right:2vw}
.lb-count{position:absolute;top:30px;left:34px;font-family:var(--font-display);font-size:13px;
  letter-spacing:.2em;color:var(--muted);font-variant-numeric:tabular-nums}
/* 燈箱三顆按鈕的按壓回饋 */
.lb-close:active{transform:rotate(90deg) scale(.9)}
.lb-nav:active{transform:translateY(-50%) scale(.9)}

/* ---------- 單一作品 / 頁面 hero ---------- */
.sw-hero{height:70vh;position:relative;display:flex;align-items:flex-end;overflow:hidden}
.sw-hero-bg{position:absolute;inset:-10% 0;z-index:0;will-change:transform}
.sw-hero-bg img{width:100%;height:100%;object-fit:cover;filter:brightness(.55)}
.sw-hero::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(transparent 40%,var(--bg))}
.sw-hero-inner{position:relative;z-index:2;padding:0 var(--pad) 8vh}
.sw-hero-inner .eyebrow{display:block;margin-bottom:14px}
.sw-hero-inner h1{font-size:clamp(2rem,5vw,4rem)}
/* 一句話副標（1.35.0）：壓在照片上，所以用 .82 的白而不是 --muted——
   --muted 是為 #0b0b0d 的底色調的，遇到照片的亮部會被吃掉。
   寬度收在 640px：它是一句話，不是一段。 */
.sw-sub{margin:14px 0 0;max-width:640px;
  color:rgba(255,255,255,.82);font-size:clamp(15px,1.6vw,18px);
  letter-spacing:.04em;line-height:1.75;text-shadow:0 1px 12px rgba(0,0,0,.55)}
/* 行高必須自己寫，不能繼承 body 的 1.6（1.32.0）。
   同一份檔案裡其他散文全部更鬆：.about-bio p 是 2.0、.store-lead 1.95、
   .svc-intro 1.9、跨頁式內文 1.9——唯獨站上最長的兩塊主文漏了。
   繁體中文沒有西文的上下伸部撐開行距，16px/1.6 在暗底上讀久了特別容易跳行。 */
/* 1.66.0：長文的內文字級 16 → 17，並補上字距與段距。
   ─────────────────────────────────────────────────────────
   量過方格子（vocus）的長文版面：18px / 行高 1.9 / 字距 0.9px /
   段落間距 28px / 欄寬 740px。那是一個以長文為生的平台調出來的數字。

   這裡沒有直接照抄 18px：這個站是暗底，暗底上的淺色字視覺上會比亮底粗一點，
   17px 已經接近同樣的視覺重量，再大就會開始跟 h3 打架。

   段距是這一組裡最有感的一項。原本靠瀏覽器預設的 1em（16px），
   段落之間幾乎沒有呼吸；把它拉到 22px 之後，讀者才看得出來哪裡是一段的結束。
   寫 margin-top/bottom 而不是 margin 簡寫，是因為上面的
   .page-body > * 要靠 margin-left/right:auto 置中，簡寫會把它歸零。 */
.page-body{max-width:820px;margin:0 auto 12vh;padding:0 var(--pad);
  font-size:17px;line-height:1.9;letter-spacing:.02em;color:var(--ink-2)}
.page-body p{margin-top:0;margin-bottom:22px}
/* 作品介紹：容器加寬到 1100（依 Gleaning the Waves 內嵌圖庫調整）——
   純文字/專案資訊維持易讀寬度並置中，圖庫與照片才放大到滿寬 */
.sw-body{max-width:1100px;margin:0 auto 12vh;padding:0 var(--pad);
  font-size:16px;line-height:1.9;color:var(--ink-2)}
.sw-body > *{max-width:820px;margin-left:auto;margin-right:auto}
/* 內文標題（1.35.0）。作品頁與單篇文章的內文標題原本完全沒有樣式，
   靠瀏覽器預設值撐——那是 Times 的粗體，跟站上其他東西沒有任何關係。
   語言層級同全站：中文為主，英文用 <em> 包成一行小字。
   （用 <em> 是因為核心的標題區塊只認得少數幾個行內格式，
   <span> 會被驗證器判成非預期內容，編輯器就會跳出區塊修復提示。） */
/* 只寫上下邊界，左右留給 .sw-body > * 的 margin-left/right:auto。
   寫成 margin:2.4em 0 .9em 會把左右一起設成 0，標題就不再置中，
   結果是標題貼在 1100px 容器的左緣、段落卻在 820px 的欄裡——兩者對不齊。 */
.sw-body h2,.page-body h2,.entry-content h2{
  margin-top:2.4em;margin-bottom:.9em;
  font-size:clamp(1.15rem,2.2vw,1.45rem);font-weight:500;
  letter-spacing:.02em;line-height:1.5;color:var(--ink)}
.sw-body h3,.page-body h3,.entry-content h3{
  margin-top:2em;margin-bottom:.7em;
  font-size:clamp(1rem,1.8vw,1.15rem);font-weight:500;
  letter-spacing:.02em;line-height:1.6;color:var(--ink)}
.sw-body h2 em,.page-body h2 em,.entry-content h2 em,
.sw-body h3 em,.page-body h3 em,.entry-content h3 em{
  display:block;margin-top:8px;font-style:normal;
  font-family:var(--font-display);font-weight:300;font-size:12px;
  letter-spacing:.28em;text-transform:uppercase;color:var(--muted)}
/* 註：這裡曾經有一條 `> h2:first-child{margin-top:0}`。拿掉了——
   內文的第一個標題上面是麵包屑，margin-top:0 會讓兩者黏在一起。
   2.4em 的自然上緣留白正好是它需要的距離。 */
.sw-body > .cg,
.sw-body > .wp-block-gallery,
.sw-body > .wp-block-image,
.sw-body > figure{max-width:100%}
.page-body img{border-radius:var(--r-img);margin:24px 0}
.sw-body > figure img,.sw-body > p img,.sw-body > .wp-block-image img{border-radius:var(--r-img);margin:24px 0}
.sw-body .cg img{margin:0}   /* 圖庫圖片不套段落間距，避免破壞磚牆排版 */

/* ---------- 統一頁面標題（WORKS / SERVICES / ABOUT / CONTACT 一致） ----------
   單一英文大標（置中、全大寫）＋一行說明；各頁一致、不再有兩個標題 */
.page-hero{max-width:1100px;margin:0 auto;padding:24vh var(--pad) 7vh;text-align:center}
.page-hero .page-title{font-family:var(--font-display);font-size:clamp(2.4rem,6.5vw,4.6rem);font-weight:300;
  letter-spacing:.06em;text-transform:uppercase;line-height:1.05;margin:0}
.page-hero .page-desc{color:var(--muted);max-width:700px;margin:22px auto 0;font-size:15px}
/* 一般頁面內文欄寬一致、置中，避免各頁左右偏移不一 */
.page-body{text-align:left}
.page-body > *{margin-left:auto;margin-right:auto}
.page-head{padding-top:22vh}
/* ---------- 相鄰作品：大圖卡片式上一件／下一件 ---------- */
.sw-adjacent{display:grid;grid-template-columns:1fr 1fr;gap:2px;margin-top:8vh}
.sw-adj{position:relative;min-height:220px;display:flex;overflow:hidden;
  background:var(--bg-soft);text-decoration:none}
.sw-adj-bg{position:absolute;inset:0;background-size:cover;background-position:center;
  filter:brightness(.4) grayscale(.2);transform:scale(1.02);
  transition:transform .9s var(--ease),filter .6s}
.sw-adj:hover .sw-adj-bg{transform:scale(1.08);filter:brightness(.55) grayscale(0)}
.sw-adj::after{content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,rgba(0,0,0,.55),rgba(0,0,0,.2))}
.sw-adj-next::after{background:linear-gradient(270deg,rgba(0,0,0,.55),rgba(0,0,0,.2))}
.sw-adj-inner{position:relative;z-index:2;margin:auto var(--pad);width:100%;
  display:flex;flex-direction:column;gap:8px}
.sw-adj-next .sw-adj-inner{align-items:flex-end;text-align:right}
.sw-adj-dir{font-size:12px;letter-spacing:.15em;color:var(--muted);text-transform:uppercase}
.sw-adj-title{font-size:clamp(1.1rem,2.4vw,1.7rem);color:var(--ink);font-weight:300}
@media(max-width:760px){.sw-adjacent{grid-template-columns:1fr}
  .sw-adj-next .sw-adj-inner{align-items:flex-start;text-align:left}}

/* ---------- 更多作品縮圖網格 ---------- */
/* 作品頁最後一區（更多作品，或沒有更多作品時的上下篇）原本沒有下方留白，
   縮圖底邊會直接貼上頁尾 CONTACT 的分隔線，看起來像被切掉。
   在文章容器補下方留白，兩種收尾情況都有呼吸空間。 */
.single-work{padding-bottom:clamp(72px,12vh,150px)}
.sw-more{max-width:1200px;margin:12vh auto 0;padding:0 var(--pad)}
.sw-more-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:16px;margin-bottom:32px;border-bottom:1px solid var(--line);padding-bottom:18px}
.sw-more-head h2{font-size:clamp(1.4rem,3vw,2rem);font-weight:300;letter-spacing:.04em}
.sw-more-head h2 span{color:var(--muted);font-size:.6em;letter-spacing:.15em;
  text-transform:uppercase;margin-left:8px}
.sw-more-all{color:var(--muted);font-size:13px;letter-spacing:.05em;transition:color .3s;white-space:nowrap}
.sw-more-all:hover{color:var(--ink)}
.sw-more-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
.sw-more-item{position:relative;display:block;text-decoration:none;overflow:hidden;border-radius:var(--r-img)}
.sw-more-img{display:block;aspect-ratio:4/3;overflow:hidden;background:var(--bg-soft)}
.sw-more-img img{width:100%;height:100%;object-fit:cover;
  filter:grayscale(.15) brightness(.9);transition:transform .8s var(--ease),filter .5s}
.sw-more-item:hover .sw-more-img img{transform:scale(1.06);filter:none}
.sw-more-meta{position:absolute;inset:0;display:flex;flex-direction:column;
  justify-content:flex-end;padding:16px;
  background:linear-gradient(transparent 50%,rgba(0,0,0,.72));
  opacity:0;transition:opacity .5s var(--ease)}
.sw-more-item:hover .sw-more-meta{opacity:1}
.sw-more-cat{font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.8)}
.sw-more-title{font-size:16px;color:var(--ink);margin-top:4px}
@media(max-width:900px){.sw-more-grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:640px){.sw-more-grid{grid-template-columns:1fr}}

.sw-nav{display:flex;gap:24px;flex-wrap:wrap;justify-content:center;
  padding:8vh var(--pad);border-top:1px solid var(--line);font-size:14px}
.sw-nav a{color:var(--muted);transition:color .3s}
.sw-nav a:hover{color:var(--ink)}

/* ---------- 文章資訊欄（單篇 Journal） ---------- */
.journal-meta{max-width:820px;margin:0 auto;padding:26px var(--pad);
  display:flex;flex-wrap:wrap;gap:14px 44px;border-bottom:1px solid var(--line)}
.jm-item{display:flex;flex-direction:column;gap:5px}
.jm-label{font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
.jm-val{font-size:14px;color:var(--ink)}
.jm-val a{color:var(--ink);border-bottom:1px solid transparent;transition:border-color .3s}
.jm-val a:hover{border-color:var(--accent)}
.journal-tags{max-width:820px;margin:-4vh auto 0;padding:0 var(--pad);
  display:flex;flex-wrap:wrap;gap:12px}
.journal-tags a{font-size:12px;letter-spacing:.03em;color:var(--muted);
  border:1px solid var(--line);border-radius:var(--r-pill);padding:6px 15px;transition:.3s var(--ease)}
.journal-tags a:hover{color:var(--ink);border-color:var(--accent)}

/* 文末分享列（1.66.0）。
   沿用標籤那一套膠囊外框——它們在版面上是同一層級的東西：
   讀完之後才會用到的小工具，不該比內文本身還大聲。
   高度 40px，手機拉到 44px（觸控目標的下限）。 */
.cv-share{max-width:820px;margin:4vh auto 0;padding:0 var(--pad);
  display:flex;flex-wrap:wrap;align-items:center;gap:10px}
.cv-share-lead{font-size:11px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);margin-right:6px}
.cv-share a,.cv-share button{font-family:inherit;font-size:12px;letter-spacing:.03em;
  color:var(--muted);background:none;cursor:pointer;
  border:1px solid var(--line);border-radius:var(--r-pill);padding:11px 18px;
  display:inline-flex;align-items:center;transition:.3s var(--ease)}
.cv-share a:hover,.cv-share button:hover{color:var(--ink);border-color:var(--accent)}
.cv-share a:active,.cv-share button:active{transform:translateY(1px) scale(.985)}
/* 複製成功：外框轉金色。這是狀態，不是裝飾，符合 --accent 的用法。 */
.cv-share button.is-done{color:var(--accent);border-color:var(--accent)}
.cv-share-status{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}
@media(max-width:640px){
  .cv-share a,.cv-share button{padding:13px 18px}
  .cv-share-lead{width:100%;margin:0 0 2px}
}

/* 規格表與常見問題（1.66.1）。
   ─────────────────────────────────────────────────────────
   兩個都是為了「被引用」而做的。搜尋引擎與 AI 摘要在讀一頁的時候，
   條列句子要靠語意猜關係，<table> 的每一列則是明確的「欄位：值」；
   常見問題的 h3 問句 + 段落答案同理，是可以整段被抄走的形狀。

   人也受用：想知道 PHP 版本的人不必讀完三段散文。 */
.cv-spec{width:100%;border-collapse:collapse;margin:0 0 26px;font-size:15px}
.cv-spec th,.cv-spec td{text-align:left;vertical-align:top;padding:13px 0;
  border-bottom:1px solid var(--line)}
.cv-spec th{width:32%;padding-right:22px;color:var(--muted);font-weight:400;letter-spacing:.04em}
.cv-spec td{color:var(--ink-2)}
.cv-spec a{color:var(--accent)}
@media(max-width:640px){
  /* 窄螢幕改上下排。32% 的欄位名在手機上只剩一百出頭的寬度，
     「技術與授權聯絡」這種標籤會被折成四行。 */
  .cv-spec th,.cv-spec td{display:block;width:auto;padding:0;border:0}
  .cv-spec th{padding-top:14px}
  .cv-spec td{padding:2px 0 14px;border-bottom:1px solid var(--line)}
}
.cv-faq h3{margin-top:1.9em}
.cv-faq h3:first-child{margin-top:0}

/* ---------- Journal ---------- */
.journal-list{display:grid;gap:40px;max-width:900px}
.journal-card{display:grid;grid-template-columns:1fr 1.4fr;gap:28px;align-items:center;
  opacity:0;transform:translateY(40px);transition:.8s var(--ease)}
.journal-card.reveal{opacity:1;transform:none}
.jc-media{aspect-ratio:4/3;overflow:hidden;border-radius:var(--r-img)}
.jc-media img{width:100%;height:100%;object-fit:cover;transition:transform .8s var(--ease)}
.jc-media:hover img{transform:scale(1.05)}
.jc-date{font-size:12px;letter-spacing:.15em;color:var(--muted)}
.jc-body h3{font-size:22px;margin:8px 0 10px}
.jc-body p{color:var(--muted);font-size:14px}
@media(max-width:640px){.journal-card{grid-template-columns:1fr}}

/* 舊的 .pricing / .tier 報價卡整段已於 1.32.0 移除：
   服務頁早就改用 .svc-tier* 那一套，樣板裡沒有任何地方再輸出這兩個 class。
   （進場動畫那幾條規則裡的 .tier 一併清掉了。） */

/* ---------- 服務頁（重構版・中文為主） ---------- */
/* 開場那一句與「方案與費用」的區段標題都在 1.68.4 移除了，
   頁面標題底下直接就是第一個類別。原本那段留白是 .svc-intro 的
   margin-bottom 給的，它不在了，這裡要自己補回來，
   不然大標會和第一個類別的眉標黏在一起。 */
.services .page-hero{padding-bottom:13vh}
.svc-cat{max-width:1000px;margin:0 auto 9vh;padding:0 var(--pad)}
.svc-cat-head{text-align:center;margin-bottom:38px}
.svc-eyebrow{display:block;font-family:var(--font-display);font-weight:400;
  font-size:12px;letter-spacing:.4em;color:var(--muted);text-transform:uppercase}
.svc-cat-head h2{font-size:clamp(1.6rem,3.5vw,2.4rem);font-weight:400;margin:14px 0 10px}
.svc-audience{color:var(--ink-3);font-size:13px;letter-spacing:.03em}
/* 服務頁的 audience 副標（1.38.0）：原本 opacity:.65 把 --muted
   壓到 3.03:1，而且是 11px + 0.18em 字距 + 全大寫，三個條件一起削弱可讀性。
   層次改用主行提一階來達成，不由對比度付帳。 */
.svc-audience span{display:block;margin-top:4px;font-size:11px;letter-spacing:.18em;text-transform:uppercase;opacity:1;color:var(--muted)}
/* .svc-cat-lede（每個類別底下那一行說明）已於 1.68.4 移除：
   大標與客戶類型那兩行已經說完這一組在拍什麼，第三行是同一件事再講一次。 */


/* .svc-scope 整組已移除（1.39.2）：那六格與方案區是兩套分類在講同一件事。 */
.svc-tiers{display:grid;grid-template-columns:1fr 1fr;gap:18px}
.svc-tier{border:1px solid var(--line);border-radius:var(--r-card);padding:34px 30px;background:var(--bg-soft);
  box-shadow:var(--shadow-1)}
.svc-tier.featured{border-color:var(--accent);background:linear-gradient(180deg,rgba(201,163,91,.08),transparent);
  box-shadow:var(--shadow-2)}
/* 並排卡片的內部橫線要對齊：兩張卡的說明文字長度不同時，
   下面的條列會從不同高度開始，看起來像沒對好。subgrid 讓
   「標題列／說明／條列」三段共用同一組列高，基線自然對齊。
   不支援 subgrid 的瀏覽器就維持原本各自為政的排版，不會壞掉。 */
@supports (grid-template-rows:subgrid){
  .svc-tiers{grid-template-rows:auto auto auto}
  .svc-tier{display:grid;grid-row:span 3;grid-template-rows:subgrid;align-content:start}
}
.svc-tier-top{display:flex;justify-content:space-between;align-items:baseline;gap:12px;flex-wrap:wrap;
  padding-bottom:18px;margin-bottom:18px;border-bottom:1px solid var(--line)}
.svc-tier-name{font-size:19px;font-weight:500}
.svc-tier-name em{display:block;font-style:normal;font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);margin-top:3px}
.svc-price{font-family:var(--font-display);font-weight:400;font-size:20px;color:var(--accent);
  white-space:nowrap;font-variant-numeric:tabular-nums}
.svc-price small{font-size:12px;color:var(--muted);margin-left:4px}
.svc-tier-desc{margin:-4px 0 18px;color:var(--muted);font-size:14px;line-height:1.75}
.svc-tier ul{list-style:none;padding:0;margin:0}
.svc-tier li{position:relative;padding:9px 0 9px 20px;font-size:15px;color:var(--ink-2);
  border-bottom:1px solid rgba(255,255,255,.05)}
.svc-tier li:last-child{border-bottom:0}
/* 這裡原本用文字破折號當項目符號，字型不同時長度會跑掉、螢幕閱讀器也會念出來。
   改成和 .store-points 一致的細線 pseudo-element，全站項目符號語彙統一。 */
.svc-tier li::before{content:"";position:absolute;left:0;top:1.5em;width:7px;height:1px;background:var(--muted)}
.svc-addons{max-width:1000px;margin:22px auto 0;padding:14px var(--pad);
  font-size:13px;color:var(--muted);text-align:center;line-height:1.9}
/* 山岳沒有方案卡（它是專案報價），但仍然要有跟其他兩組一樣的外框（1.34.2）。
   原本是一段裸文字，夾在兩組有邊框的方案卡之間，看起來像漏掉了什麼。
   用單張滿寬的卡片：框線、底色、圓角、陰影都跟 .svc-tier 同一組值。 */
.svc-note{max-width:1000px;margin:0 auto;text-align:center;color:var(--ink-2);
  font-size:16px;line-height:1.9;
  border:1px solid var(--line);border-radius:var(--r-card);
  padding:34px 30px;background:var(--bg-soft);box-shadow:var(--shadow-1)}
.svc-note > p{max-width:700px;margin-left:auto;margin-right:auto}
.svc-price-line{margin-top:20px;color:var(--accent);font-size:18px;font-variant-numeric:tabular-nums}
.svc-price-line small{color:var(--muted);font-size:12px}
@media(max-width:640px){.svc-note{padding:28px 22px}}
@media(max-width:760px){.svc-tiers{grid-template-columns:1fr}}

.svc-block{max-width:860px;margin:0 auto 9vh;padding:0 var(--pad)}
.svc-section-title{text-align:center;font-size:clamp(1.5rem,3vw,2rem);font-weight:400;margin-bottom:44px}
.svc-section-title span{display:block;font-size:12px;letter-spacing:.28em;color:var(--muted);
  text-transform:uppercase;margin-top:8px}
.svc-steps{list-style:none;padding:0;margin:0;display:grid;gap:26px}
.svc-steps li{display:flex;gap:22px;align-items:flex-start;border-bottom:1px solid var(--line);padding-bottom:26px}
.svc-steps li:last-child{border-bottom:0}
.svc-no{font-size:28px;font-weight:300;color:var(--muted);min-width:46px;line-height:1}
.svc-steps strong{font-size:17px;font-weight:500}
.svc-steps strong em{font-style:normal;font-size:12px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);margin-left:10px}
.svc-steps p{margin:8px 0 0;color:var(--muted);font-size:15px;line-height:1.8}
.svc-faq{display:grid;gap:24px}
.svc-qa{border-left:2px solid rgba(201,163,91,.4);padding-left:20px}
.svc-qa h3{font-size:16px;font-weight:500;margin:0 0 8px}
.svc-qa p{margin:0;color:var(--muted);font-size:15px;line-height:1.8}
.svc-cta{text-align:center;padding:10vh var(--pad) 4vh}
.svc-cta h2{font-size:clamp(1.6rem,3.4vw,2.4rem);font-weight:400;line-height:1.4}
.svc-cta h2 span{display:block;margin-top:10px;
  font-family:var(--font-display);font-weight:300;font-size:12px;
  letter-spacing:.28em;text-transform:uppercase;color:var(--muted)}
.svc-cta p{color:var(--muted);margin:16px 0 30px}

/* ---------- 聯絡頁（含表單） ---------- */
.contact-wrap{max-width:640px;margin:0 auto;padding:0 var(--pad) 12vh}
.contact-intro{text-align:center;color:var(--ink-2);font-size:16px;line-height:1.9;margin:0 auto 44px;max-width:560px}
.contact-intro strong{color:var(--ink);font-weight:500}

/* ---------- 聯絡頁：可以委託什麼（1.34.0） ----------
   六個服務項目的縮寫版。放在表單之前，讓讀者先確認「我要問的東西你有在做」，
   再開始填。順序與服務頁一致（同一份來源）。 */
.contact-scope{margin:0 0 44px;padding-top:26px;border-top:1px solid var(--line)}
.contact-h2{font-size:16px;font-weight:500;letter-spacing:.06em;
  color:var(--ink);margin:0 0 20px;text-align:center;line-height:1.5}
.contact-h2 span{display:block;margin-top:7px;
  font-family:var(--font-display);font-weight:300;font-size:11px;
  letter-spacing:.28em;text-transform:uppercase;color:var(--muted)}
.contact-scope-list{list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:1fr 1fr;gap:12px 24px}
.contact-scope-list li{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  border-bottom:1px solid var(--line);padding-bottom:10px}
.contact-scope-zh{font-size:14px;letter-spacing:.03em;color:var(--ink)}
.contact-scope-en{font-family:var(--font-display);font-weight:300;font-size:11px;
  letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
@media(max-width:640px){.contact-scope-list{grid-template-columns:1fr}}

/* 表單下方的提示：告訴讀者多寫什麼可以換到更具體的回覆。 */
.cf-hint{margin:-6px 0 0;color:var(--muted);font-size:13px;line-height:1.8}
/* 收尾簽名句：整頁最後一行，不連結、不按鈕，只是把話講完。 */
.contact-sign{margin:44px 0 0;text-align:center;color:var(--ink);
  font-size:16px;letter-spacing:.04em;line-height:1.9}
.contact-sign span{display:block;margin-top:12px;
  font-family:var(--font-display);font-weight:300;font-size:12px;
  letter-spacing:.16em;color:var(--muted);line-height:1.8}
.contact-where{display:block;margin-top:10px;font-family:var(--font-display);
  font-size:12px;letter-spacing:.18em;color:var(--muted)}
.cf-note{text-align:center;padding:14px 18px;border-radius:var(--r-card);font-size:14px;margin-bottom:28px}
.cf-note.ok{background:rgba(201,163,91,.12);border:1px solid rgba(201,163,91,.4);color:#e6d3ab}
.cf-note.err{background:rgba(200,80,80,.1);border:1px solid rgba(200,80,80,.35);color:#e6b3b3}
.cf-note a{color:var(--accent)}
.contact-form{display:grid;gap:20px}
.contact-form label{display:block;font-size:13px;letter-spacing:.03em;color:var(--muted)}
.contact-form label span{color:var(--muted);text-transform:uppercase;letter-spacing:.15em;font-size:11px;margin-left:6px}
.contact-form input,.contact-form select,.contact-form textarea{
  width:100%;margin-top:8px;background:var(--bg-soft);border:1px solid var(--line);
  color:var(--ink);border-radius:var(--r-card);padding:13px 15px;font-size:15px;font-family:inherit;transition:border-color .3s}
.contact-form input:focus,.contact-form select:focus,.contact-form textarea:focus{outline:none;border-color:var(--accent)}
.contact-form textarea{resize:vertical}
.contact-form select{appearance:none;-webkit-appearance:none;cursor:pointer}
/* ---------- 表單的即時錯誤提示（1.23.0） ----------
   用 :user-invalid 而不是 :invalid：:invalid 一進頁面就會把所有必填空欄位標紅，
   等於還沒開始填就被罵；:user-invalid 只有在使用者真的動過那個欄位、
   或按過送出之後才成立，是正確的時機。
   不支援的舊瀏覽器只是看不到這層提示，原本的瀏覽器原生驗證仍然有效。 */
.field-err{display:none;margin-top:7px;font-size:13px;line-height:1.6;color:#e0a79b}
.contact-form input:user-invalid,
.contact-form textarea:user-invalid{border-color:#c8705b;background:rgba(200,112,91,.06)}
.contact-form input:user-invalid ~ .field-err,
.contact-form textarea:user-invalid ~ .field-err{display:block}
.cf-row{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.contact-form .ghost-btn{justify-self:start;margin-top:6px;cursor:pointer;background:none}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.contact-alt{text-align:center;color:var(--muted);font-size:14px;margin-top:34px}
.contact-alt a{color:var(--accent);border-bottom:1px solid rgba(201,163,91,.4);padding-bottom:2px}
@media(max-width:640px){.cf-row{grid-template-columns:1fr}}

/* ---------- 商店：從照片按「購買這張」過來（1.36.0） ----------
   放在產品線之前、標題之後：這位訪客是為了某一張照片來的，
   讓他先看到自己問的那張，再往下看其他東西。
   用邊框而不是底色，跟三條產品線區隔開——它是回應，不是第四項商品。 */
.store-photo{max-width:var(--maxw);margin:0 auto 9vh;padding:26px;
  display:grid;grid-template-columns:360px 1fr;gap:34px;align-items:start;
  border:1px solid var(--accent);border-radius:var(--r-card);
  background:linear-gradient(180deg,rgba(201,163,91,.06),transparent)}
.store-photo-img{margin:0;overflow:hidden;border-radius:var(--r-img);background:var(--bg-soft)}
.store-photo-img img{display:block;width:100%;height:auto}
.store-photo-body h2{margin:0 0 6px;font-size:clamp(1.1rem,2.2vw,1.4rem);font-weight:500;
  letter-spacing:.02em;line-height:1.5;color:var(--ink)}
.store-photo-body h2 span{display:block;margin-top:8px;
  font-family:var(--font-display);font-weight:300;font-size:12px;
  letter-spacing:.28em;text-transform:uppercase;color:var(--muted)}
.store-photo-from{margin:0 0 18px;color:var(--muted);font-size:14px}
.store-photo-from b{color:var(--ink);font-weight:500}
.store-photo-body p{margin:0 0 14px;color:var(--ink-3);font-size:15px;line-height:1.9}
.store-photo-body p b{color:var(--ink);font-weight:500}
.store-photo-price{color:var(--accent);font-size:18px;
  font-variant-numeric:tabular-nums}
.store-photo-body .ghost-btn{margin-top:6px}

/* 兩種買法並列（1.36.0）。用分隔線而不是卡片：
   它們是同一張照片的兩個選項，不是兩件商品。 */
.store-photo-buys{margin:0 0 18px;padding:0;list-style:none}
.store-photo-buys li{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px 14px;
  padding:14px 0;border-top:1px solid var(--line)}
.store-photo-buys li:last-child{border-bottom:1px solid var(--line)}
.store-photo-kind{color:var(--ink);font-size:15px;font-weight:500}
.store-photo-buys .ghost-btn{flex-basis:100%;margin-top:4px;align-self:flex-start}
.store-photo-more{font-size:14px!important;color:var(--muted)!important;line-height:1.9!important}
.store-photo-more a{color:var(--accent);text-decoration:none;
  border-bottom:1px solid transparent;transition:border-color .3s var(--ease)}
.store-photo-more a:hover,.store-photo-more a:focus-visible{border-bottom-color:var(--accent)}
/* 900 而不是 760：兩欄在 820px 的平板上雖然「排得下」，
   文字欄只剩約 290px，15px 的中文一行不到 20 個字，讀起來像在讀報紙的夾縫。
   排得下不等於讀得下。 */
@media(max-width:900px){
  .store-photo{grid-template-columns:1fr;gap:24px;padding:20px}
  .store-photo-img{max-width:320px}
}

/* ---------- 商店落地頁（page-shop.php） ---------- */
.store{max-width:1100px;margin:0 auto;padding:0 var(--pad) 12vh}
.store .page-hero{padding-bottom:5vh}
.store-intro{color:var(--ink-2);font-size:16px;line-height:1.9;max-width:680px;margin:0 auto 72px;text-align:center}

/* 產品線用左標題右內容的兩欄；標題欄 sticky，長列表捲動時仍知道自己在看哪一條產品線 */
.store-line{display:grid;grid-template-columns:minmax(220px,300px) 1fr;gap:44px;
  padding:52px 0;border-top:1px solid var(--line)}
.store-line-head{position:sticky;top:110px;align-self:start}
.store-eyebrow{display:block;font-size:11px;letter-spacing:.28em;color:var(--muted);margin-bottom:14px}
.store-line-head h2{font-size:clamp(1.5rem,2.6vw,2.1rem);line-height:1.35}
.store-en{color:var(--muted);font-size:13px;letter-spacing:.08em;margin:10px 0 0}
.store-lead{color:var(--ink-2);font-size:16px;line-height:1.9;margin:0 0 26px;max-width:640px}
.store-points{list-style:none;padding:0;margin:0 0 34px;display:grid;gap:11px;max-width:640px}
.store-points li{position:relative;padding-left:20px;color:var(--muted);font-size:15px;line-height:1.75}
.store-points li::before{content:"";position:absolute;left:0;top:.72em;width:7px;height:1px;background:var(--muted)}

/* 購買選項：未開賣與已開賣共用同一個框，只有裡面的字與按鈕不同，
   之後接上金流時版面不會位移。 */
.store-buy{display:flex;flex-wrap:wrap;gap:16px}
.store-option{flex:1 1 240px;background:var(--bg-soft);border:1px solid var(--line);
  border-radius:var(--r-card);padding:22px 22px 24px;transition:border-color .3s var(--ease)}
.store-option:hover{border-color:rgba(255,255,255,.2)}
.store-option.is-live{border-color:rgba(201,163,91,.32)}
.store-option-name{display:block;font-size:13px;letter-spacing:.06em;color:var(--ink)}
.store-price{display:block;margin-top:10px;font-size:20px;font-weight:300;color:var(--accent)}
.store-price.store-soon{font-size:13px;letter-spacing:.04em;color:var(--muted)}
/* 特價的原價（1.38.0）：原本用 opacity:.5 稀釋 --accent，
   在 --bg-soft 上只剩 2.84:1。價格是這個站真正要傳達的資訊，不是裝飾。
   改用明確的次要色，刪除線本身已經足以表達「這是舊價」。 */
.store-price del{opacity:1;color:var(--muted);font-size:15px;margin-right:8px}
.store-option-note{color:var(--muted);font-size:13px;line-height:1.7;margin:12px 0 18px}
.store-cta{display:inline-block;font-size:13px;letter-spacing:.05em}
.store-cta-buy{background:var(--accent);color:var(--on-accent);border:1px solid var(--accent);
  padding:11px 24px;border-radius:var(--r-pill);transition:.3s var(--ease)}
.store-cta-buy:hover{background:transparent;color:var(--accent)}

.store-note{border-top:1px solid var(--line);padding-top:44px;margin-top:8px;max-width:760px}
.store-note h3{font-size:1.1rem;margin-bottom:16px}
.store-note p{color:var(--muted);font-size:14px;line-height:1.9;margin:0 0 14px}
.store-note a{color:var(--accent);border-bottom:1px solid rgba(201,163,91,.4);padding-bottom:2px}

@media(max-width:900px){
  .store-line{grid-template-columns:1fr;gap:26px;padding:40px 0}
  /* 單欄時 sticky 會讓標題卡在畫面上擋住內容，關掉。 */
  .store-line-head{position:static}
}

/* ---------- 全站互動微效果 ---------- */
.svc-tier{transition:border-color .4s var(--ease),transform .4s var(--ease),background .4s}
.svc-tier:hover{transform:translateY(-4px);border-color:rgba(201,163,91,.5)}
.svc-qa{transition:border-left-color .3s,transform .3s var(--ease)}
.svc-qa:hover{transform:translateX(5px);border-left-color:var(--accent)}
.svc-cta .ghost-btn:hover,.contact-form .ghost-btn:hover{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.footer-social{display:flex;gap:20px;justify-content:center;margin-top:28px}
.footer-social a{color:var(--muted);line-height:0;transition:color .3s var(--ease),transform .3s var(--ease)}
.footer-social a:hover{color:var(--accent);transform:translateY(-3px)}
.jc-meta{display:flex;align-items:center;gap:14px;margin-bottom:8px;flex-wrap:wrap}
.jc-cat{font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);
  border:1px solid var(--line);border-radius:var(--r-pill);padding:3px 12px;transition:.3s var(--ease)}
.jc-cat:hover{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.jc-read{font-size:11px;letter-spacing:.1em;color:var(--muted)}
.jc-read::before{content:"·";margin-right:12px;color:var(--muted)}
/* .jc-eyebrow 已移除（1.38.0）：template-parts/journal-card.php 沒有這個元素。 */

/* 卡片上的標籤（1.59.0）。
   刻意比內頁的 .journal-tags 小一號、也不做圓框：卡片上已經有一顆
   分類膠囊，再放一排同樣形狀的框，眼睛會分不出哪一個是分類。
   這裡只用「#」和字級把它降到附註的層級。 */
.jc-tags{display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:12px}
.jc-tags a{font-size:12px;letter-spacing:.04em;color:var(--muted);
  border-bottom:1px solid transparent;transition:color .3s var(--ease),border-color .3s var(--ease)}
.jc-tags a:hover{color:var(--ink);border-bottom-color:var(--accent)}
.jc-tags-more{color:var(--muted);opacity:.75}

/* 行動裝置的命中框（1.60.0）。
   ─────────────────────────────────────────────────────────
   實測 386px 視寬：49 個可點元素有 29 個小於 44×44。最糟的是
   「+1」「+3」只有 16×19，連 WCAG 2.5.8 的 24×24 都不到；
   標籤 chip 與系列篩選只有 19-22px 高。

   視覺尺寸完全不動，只把命中框撐開。用 ::after 疊一層而不是加
   padding：加 padding 會撐開 flex 容器，把整排 chip 的間距弄亂。
   ::after 往上下溢出，畫面上看不出任何差別。 */
@media (max-width: 760px){
  .jc-tags a,.jc-cat,.series-links a,.filters a,.filters button{position:relative}
  .jc-tags a::after,.jc-cat::after,.series-links a::after,
  .filters a::after,.filters button::after{
    content:"";position:absolute;left:0;right:0;top:50%;
    transform:translateY(-50%);height:44px;min-width:44px}
  /* 「+N」本身只有 16px 寬，左右也要撐開才點得到 */
  .jc-tags-more::after{left:-14px;right:-14px}
}

/* ---------- 麵包屑（1.33.0） ----------
   外觀刻意沿用眉標那一套：小字、寬字距、--muted。它是定位資訊，不是主角。
   分隔符用 ::before 的 content 生成，不寫進 HTML——
   讀螢幕軟體逐項唸清單時不需要聽到十次「斜線」。
   目前這一頁不是連結（連到自己是死路），只給一點亮度差別。 */
.cv-crumbs{margin:0 0 14px;font-size:12px;letter-spacing:.24em;
  font-family:var(--font-display);line-height:1.6}
.cv-crumbs ol{list-style:none;display:flex;flex-wrap:wrap;align-items:center;
  gap:0 6px;margin:0;padding:0}
.cv-crumbs li{display:flex;align-items:center;gap:6px;color:var(--muted)}
.cv-crumbs li + li::before{content:"›";opacity:.5;font-size:13px;letter-spacing:0}
.cv-crumbs a{color:var(--muted);transition:color .3s var(--ease)}
.cv-crumbs a:hover,.cv-crumbs a:focus-visible{color:var(--accent)}
.cv-crumbs [aria-current="page"]{color:var(--ink-2)}
/* 單篇作品／文章：麵包屑落在 hero 之後、內文之前，要跟著內文的左右留白對齊 */
.single-work > .cv-crumbs,
.single-journal > .cv-crumbs{max-width:var(--maxw);margin:26px auto 0;padding:0 var(--pad)}
@media(max-width:640px){
  /* 手機收窄一點，長標題不要吃掉三行 */
  .cv-crumbs{font-size:11px;letter-spacing:.16em}
  .cv-crumbs li:last-child{min-width:0}
  .cv-crumbs [aria-current="page"]{display:inline-block;max-width:100%;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
}

/* ---------- 頁尾 ---------- */
/* 上內距從 14vh 降到 9vh（1.65.3）：那個數字本來是為了托住一個
   clamp(2rem,6vw,4rem) 的大標。標語拿掉之後實測是 177px 的留白壓在
   一行 20px 的信箱上面，上下內距變成 177 / 101——看起來像漏掉了東西，
   不像刻意的留白。降到 9vh 之後兩邊回到接近對稱。 */
.site-footer{padding:9vh var(--pad) 8vh;text-align:center;border-top:1px solid var(--line)}
.footer-eyebrow{color:var(--muted);letter-spacing:.4em;font-size:12px;margin-bottom:20px}
/* .footer-en 與 .site-footer h3 的樣式在 1.65.3 一併刪掉：
   頁尾的標語整組拿掉之後，這兩條沒有任何元素會用到。
   留著沒有壞處，但下一個讀這個檔的人會以為頁尾還有一個大標。 */
.footer-mail{display:inline-block;font-size:15px;letter-spacing:.05em;
  border-bottom:1px solid var(--accent);padding-bottom:4px}
.site-footer small{display:block;margin-top:60px;color:var(--muted);font-size:12px;letter-spacing:.08em}
.footer-nav ul{list-style:none;display:flex;gap:24px;justify-content:center;padding:0;margin:34px 0 0;
  font-size:13px;color:var(--muted);flex-wrap:wrap}
.footer-nav a{transition:color .3s var(--ease)}
.footer-nav a:hover{color:var(--ink)}
/* 法律連結刻意低調：它必須存在、但不該跟作品搶注意力 */
.footer-legal ul{gap:20px;font-size:12px;margin-top:26px}
/* 頁尾法律連結（1.38.0）：低調是對的，但原本用 .75 alpha 把 --muted
   壓到 3.66:1，而 12px 非大字要 4.5:1。隱私權政策與服務條款正是
   低視力使用者最需要找得到的東西。低調靠字級與位置達成就好。 */
.footer-legal a{color:var(--muted)}
.footer-social a:active{transform:translateY(-1px) scale(.92)}
.footer-mail{transition:opacity .3s var(--ease)}
.footer-mail:active{opacity:.7}

/* ---------- 分頁 ---------- */
.pager,.navigation{margin-top:60px;text-align:center}
.pager .page-numbers,.navigation .page-numbers{display:inline-block;padding:8px 14px;margin:0 3px;
  color:var(--muted);border:1px solid var(--line);border-radius:var(--r-pill);font-size:13px;
  font-variant-numeric:tabular-nums;transition:.3s}
.pager .page-numbers.current,.navigation .page-numbers.current{color:var(--on-accent);background:var(--accent);border-color:var(--accent)}

/* ---------- 捲動淡入通用 ---------- */
.reveal-up{opacity:0;transform:translateY(40px);transition:opacity .9s var(--ease),transform .9s var(--ease)}
.reveal-up.reveal{opacity:1;transform:none}

/* ---------- 尊重「減少動態」偏好 ---------- */
@media (prefers-reduced-motion:reduce){
  /* transition-delay 也要歸零（1.33.0）。
     原本只關掉 duration，但站上多處用 inline transition-delay 做交錯進場
     （網格最多 420ms、外掛畫廊最多 400ms）——動畫是不動了，
     東西卻仍然一個一個慢慢冒出來，對前庭不適的人來說差別不大。 */
  *{animation:none!important;transition-duration:.01ms!important;transition-delay:0s!important}
  .reveal-up,.tile,.series-card,.journal-card{opacity:1;transform:none}
}

/* ---------- 無障礙：跳過連結、焦點可見、觸控目標、減動捲動 ---------- */
.skip-link{position:fixed;top:-60px;left:12px;z-index:var(--z-skip);background:var(--accent);color:var(--on-accent);
  padding:10px 16px;border-radius:var(--r-card);font-size:13px;letter-spacing:.05em;transition:top .2s}
.skip-link:focus{top:12px;outline:2px solid #fff;outline-offset:2px}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.contact-form input:focus-visible,.contact-form textarea:focus-visible,.contact-form select:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px}
.footer-social a{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px}
@media (prefers-reduced-motion:reduce){ html{scroll-behavior:auto} }

/* -----------------------------------------------------------
 * 關於頁 ABOUT（page-about.php）
 * --------------------------------------------------------- */
.about-wrap{max-width:960px;margin:0 auto 14vh;padding:0 var(--pad)}
.about-intro{display:grid;grid-template-columns:minmax(260px,340px) 1fr;gap:clamp(30px,5vw,64px);
  align-items:start;padding-bottom:7vh;border-bottom:1px solid var(--line);margin-bottom:7vh}
.about-photo{margin:0;position:relative;overflow:hidden;border:1px solid var(--line);border-radius:var(--r-img)}
.about-photo img{display:block;width:100%;height:auto;aspect-ratio:3/4;object-fit:cover}
.about-photo::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,transparent 60%,rgba(11,11,13,.35))}
.about-intro-text{padding-top:2px}
.about-name{margin-bottom:26px}
.about-name-en{display:block;font-family:var(--font-display);
  font-weight:300;font-size:clamp(1.4rem,3vw,2rem);letter-spacing:.26em;color:var(--ink);line-height:1.2}
.about-name-zh{display:block;margin-top:12px;font-size:16px;letter-spacing:.32em;color:var(--ink)}
/* .about-role 與 .about-lead 已移除（1.38.0）：page-about.php 已改用 .about-name-* 與 .about-bio。 */
.about-bio p{color:var(--ink-3);font-size:16px;line-height:2;letter-spacing:.02em;margin:0 0 1.4em}
.about-bio p:last-child{margin-bottom:0}
.about-tl{margin-top:7vh;border-top:1px solid var(--line);padding-top:6vh}
.about-tl-row{display:grid;grid-template-columns:130px 1fr;gap:28px;padding:0 0 4vh}
.about-tl-row:last-child{padding-bottom:0}
.about-tl-year{font-size:13px;letter-spacing:.16em;color:var(--muted);padding-top:4px}
.about-tl-body strong{display:block;font-size:16px;font-weight:500;letter-spacing:.04em;color:var(--ink);margin-bottom:8px}
.about-tl-body strong em{font-style:normal;font-weight:300;color:var(--muted);font-size:13px;margin-left:10px;letter-spacing:.08em}
.about-tl-body p{margin:0;color:var(--muted);font-size:15px;line-height:1.9}
.about-cta{margin-top:8vh;padding-top:6vh;border-top:1px solid var(--line);text-align:center}
.about-cta p{color:var(--ink);font-size:15px;line-height:1.8;margin:0 0 26px}

/* ---------- 關於頁的新區塊（1.34.0） ----------
   MY APPROACH / FROM LANDSCAPE / WHAT I SEE 三段共用同一個節奏：
   一條上緣線、一個 h2、然後內容。線就是分段，不再額外加卡片或底色。 */
.about-approach,.about-shift,.about-see{margin-top:7vh;border-top:1px solid var(--line);padding-top:6vh}
/* 內文大綱：中文為主、英文為輔。英文另起一行、字級降到 12px，
   它是索引不是標題——讀者靠中文理解，靠英文對照。 */
.about-h2{font-weight:400;font-size:clamp(1.2rem,2.4vw,1.55rem);
  letter-spacing:.02em;line-height:1.45;margin:0 0 30px;color:var(--ink)}
.about-h2 span{display:block;margin-top:8px;
  font-family:var(--font-display);font-weight:300;font-size:12px;
  letter-spacing:.28em;text-transform:uppercase;color:var(--muted)}
/* 中文沒有真正的斜體，強調一律用同字體加粗（見 hero 的同一條註解）。 */
.about-bio b,.about-see b{font-style:normal;font-weight:500}

.about-steps{list-style:none;margin:0;padding:0;display:grid;gap:32px}
.about-steps li{display:grid;grid-template-columns:56px 1fr;gap:20px;align-items:start}
.about-step-no{font-family:var(--font-display);font-size:13px;letter-spacing:.16em;
  color:var(--muted);font-variant-numeric:tabular-nums;padding-top:3px}
.about-steps strong{display:block;font-size:16px;font-weight:500;
  letter-spacing:.06em;color:var(--ink);margin-bottom:8px}
.about-steps strong em{font-style:normal;font-weight:300;color:var(--muted);
  font-family:var(--font-display);font-size:12px;margin-left:12px;letter-spacing:.2em;text-transform:uppercase}
.about-steps p{margin:0;color:var(--ink-3);font-size:15px;line-height:1.9}

.about-shift p{color:var(--ink-3);font-size:16px;line-height:2;letter-spacing:.02em;margin:0 0 1.4em}
.about-shift p:last-child{margin-bottom:0}
/* 結語：不加引號、不置中，只用字體與留白把它抬起來。
   中文是主體，英文原句降成小字附在後面。 */
.about-quote{margin-top:34px!important;color:var(--ink)!important;
  font-size:clamp(1rem,2vw,1.2rem)!important;
  letter-spacing:.04em;line-height:1.9!important}
.about-quote span{display:block;margin-top:12px;
  font-family:var(--font-display);font-weight:300;font-size:12px;
  letter-spacing:.16em;color:var(--muted);line-height:1.8}

.about-see-list{list-style:none;margin:0 0 26px;padding:0;
  display:flex;flex-wrap:wrap;gap:10px 12px}
.about-see-list li{display:inline-flex;align-items:baseline;gap:8px;
  font-size:14px;letter-spacing:.04em;color:var(--ink-3);
  border:1px solid var(--line);border-radius:var(--r-pill);padding:7px 16px}
.about-see-list em{font-style:normal;font-family:var(--font-display);font-weight:300;
  font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.about-see > p{margin:0;color:var(--ink-3);font-size:16px;line-height:2}
@media(max-width:760px){
  .about-intro{grid-template-columns:1fr;gap:34px;text-align:center}
  .about-photo{max-width:300px;margin:0 auto}
  .about-bio{text-align:left}
}
@media(max-width:640px){
  .about-tl-row{grid-template-columns:1fr;gap:8px}
  .about-tl-year{padding-top:0}
  .about-bio p{font-size:15px;line-height:1.9}
  .about-steps li{grid-template-columns:1fr;gap:8px}
  .about-step-no{padding-top:0}
}

/* ---------- 404 ---------- */
.notfound .page-hero{padding-bottom:5vh}
.notfound-links{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;margin:34px 0 0}
.notfound-links a{background:transparent;border:1px solid var(--line);color:var(--muted);
  padding:9px 20px;border-radius:var(--r-pill);font-size:13px;letter-spacing:.05em;
  text-decoration:none;transition:.3s var(--ease)}
.notfound-links a:hover{color:var(--ink);border-color:rgba(255,255,255,.3)}
.notfound-links a:active{transform:translateY(1px) scale(.985)}
.notfound-links a.primary{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.notfound-links a.primary:hover{color:var(--on-accent);opacity:.88}
.notfound .grid{padding-top:0}

/* ================================================================
   1.18.0 進場動畫層
   規則：只動 transform / opacity / clip-path；
        「先隱藏再進場」的樣式全部掛在 html.js 底下（header.php 用內聯
        script 加上），關掉 JS 只是沒動畫，內容一定看得見。
   ================================================================ */

/* ---------- 開場遮罩 preloader（只在首頁、每個瀏覽階段一次） ---------- */
html.preloading,html.preloading body{overflow:hidden}
.preload{position:fixed;inset:0;z-index:var(--z-preload);background:var(--bg);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:20px;
  clip-path:inset(0 0 0 0);
  /* 保險絲：即使 chaovisual.js 載入失敗，6 秒後遮罩也會自己退場，不會蓋死整站 */
  animation:preload-bail .8s cubic-bezier(.76,0,.24,1) 6s forwards}
html:not(.preloading) .preload{display:none}
@keyframes preload-bail{to{clip-path:inset(0 0 100% 0);pointer-events:none}}
.preload.done{animation:none;clip-path:inset(0 0 100% 0);pointer-events:none;
  transition:clip-path 1s cubic-bezier(.76,0,.24,1)}
.preload-mark{font-family:var(--font-display);
  font-weight:300;font-size:13px;letter-spacing:.4em;color:var(--ink);opacity:.85}
.preload-mark span{color:var(--accent)}
.preload-num{font-family:var(--font-display);font-weight:300;
  font-size:clamp(2.4rem,8vw,4.4rem);line-height:1;color:var(--ink);
  font-variant-numeric:tabular-nums;letter-spacing:.02em}
.preload-bar{display:block;width:min(220px,44vw);height:1px;background:var(--line);overflow:hidden}
.preload-bar i{display:block;height:100%;width:0;background:var(--accent);transition:width .35s linear}
/* 跳過鈕。刻意低調——它是出口，不是主角——但命中框仍是 44 高，
   而且一鍵就能離開，不必等進度條跑完。 */
.preload-skip{margin-top:10px;background:none;border:0;padding:0 14px;
  min-height:44px;display:inline-flex;align-items:center;
  font-family:var(--font-display);font-size:12px;letter-spacing:.2em;
  color:var(--muted);cursor:pointer;transition:color .3s var(--ease)}
.preload-skip:hover{color:var(--ink)}
.preload-skip:focus-visible{outline:1px solid var(--accent);outline-offset:4px;color:var(--ink)}

/* ---------- 首頁大標：逐行進場 ---------- */
/* h1 本體立刻顯示，改由裡面的 .w（詞／字）分行帶入；.split 由 JS 加上，
   而且要等 document.fonts.ready，否則 Jost 換字時會重新斷行、文字跳動。 */
.js .hero-inner h1.split{opacity:1;transform:none;transition:none}
.js .hero-inner h1.split .w{display:inline-block;opacity:0;transform:translateY(.55em);
  transition:opacity .9s var(--ease),transform .9s var(--ease)}
.js .hero.in h1.split .w{opacity:1;transform:none}

/* ---------- 圖片揭開 mask reveal ---------- */
/* 外層用 clip-path 由下往上掃開，內層 img 反向從 1.12 縮回 1，
   看起來像一道邊緣掃過照片，而不是照片整塊彈出來。
   inset() 會把圓角切成直角，所以動畫期間帶 round 4px，
   結束後由 JS 在 transitionend 把 clipPath 清成 none。 */
.js .tile,.js .series-card{opacity:1;transform:none;
  clip-path:inset(0 0 100% 0 round 4px);
  transition:clip-path 1s cubic-bezier(.76,0,.24,1)}
.js .tile.reveal,.js .series-card.reveal{clip-path:inset(0 0 0 0 round 4px)}
.js .tile:not(.reveal) img,.js .series-card:not(.reveal) .series-img img{transform:scale(1.12)}
/* hover 放大要贏過揭開規則：.tile:hover img 是 (0,2,1)，
   這裡重述成 (0,4,1) 以免揭開後滑鼠移上去沒有反應。 */
.js .tile.reveal:hover img{transform:scale(1.06);filter:grayscale(0) brightness(1)}
.js .series-card.reveal:hover .series-img img{transform:scale(1.06);filter:grayscale(0) brightness(1)}

/* ---------- 頁面轉場（View Transitions，漸進增強，不支援就照舊） ----------
   @view-transition 這條 at-rule 不寫在這裡，改由 header.php 的行內腳本注入。
   原因：它是文件層級的規則，沒辦法用 class 選擇器關掉，而 App 內建瀏覽器
   （Instagram／Facebook／LINE）跑跨文件轉場容易卡在交接的那一瞬間——
   讀者看到的是一張不會動的舊畫面或一片空白，而且他沒有網址列可以重新整理。
   底下這條只是轉場的時間曲線，沒有啟用轉場，留在這裡是安全的。 */
::view-transition-old(root),::view-transition-new(root){animation-duration:.45s;
  animation-timing-function:cubic-bezier(.22,.61,.36,1)}

/* ---------- 降低動態偏好：全部關掉，內容直接就位 ---------- */
@media (prefers-reduced-motion:reduce){
  .preload{display:none!important}
  html.preloading,html.preloading body{overflow:auto}
  .js .tile,.js .series-card,.js .tile.reveal,.js .series-card.reveal{clip-path:none!important}
  .js .tile img,.js .series-card .series-img img{transform:none!important}
  .js .hero-inner h1.split .w{opacity:1!important;transform:none!important}
  ::view-transition-old(root),::view-transition-new(root){animation-duration:1ms}
}

/* ---------- 沒有 JS 的安全網：一切直接顯示 ---------- */
html:not(.js) .reveal-up,html:not(.js) .tile,html:not(.js) .series-card,
html:not(.js) .journal-card,html:not(.js) .pw-item,
html:not(.js) .hero-inner .eyebrow,html:not(.js) .hero-inner h1,
html:not(.js) .hero-inner p,html:not(.js) .hero-inner .hero-cta,
html:not(.js) .hero-inner .hero-zh{opacity:1!important;transform:none!important;clip-path:none!important}
html:not(.js) .preload{display:none!important}

/* ---------- 主腳本沒到位的安全網（1.29.1）----------
   上面那組只涵蓋「完全沒有 JavaScript」。真正會出事的是中間那個狀態：
   行內腳本跑了、html 已經是 .js（所有內容變成 opacity:0），
   然後主腳本沒載到或中途丟出例外——進場動畫永遠不會發生，整頁就是一片空白。
   Instagram、Facebook、LINE 這類 App 內建瀏覽器的網路與腳本環境比較不穩，
   最容易踩到這一段；而讀者在那裡連網址列都沒有，無法自己重新整理。

   header.php 的行內腳本在「任何腳本出錯」或「2.6 秒內主腳本沒回報就緒」時
   會補上 html.cv-bail，這一組就是它的樣式：一切直接就位。
   只做加法，正常的頁面完全不受影響。 */
html.cv-bail .reveal-up,html.cv-bail .tile,html.cv-bail .series-card,
html.cv-bail .journal-card,html.cv-bail .pw-item,
html.cv-bail .hero-inner .eyebrow,html.cv-bail .hero-inner h1,
html.cv-bail .hero-inner p,html.cv-bail .hero-inner .hero-cta,
html.cv-bail .hero-inner .hero-zh,html.cv-bail .hero-inner h1.split .w,
html.cv-bail .sw-page,html.cv-bail .kg-card{
  opacity:1!important;transform:none!important;clip-path:none!important;
  /* 連過場一起關掉。安全網啟動的意思是「已經出事了，內容現在就要出現」，
     再讓它慢慢淡進來 0.9 秒，讀者看到的仍然是接近空白的一頁。 */
  transition:none!important;animation:none!important}
html.cv-bail .tile img,html.cv-bail .series-card .series-img img{transform:none!important}
/* 開場遮罩要一起收掉，否則它會蓋著整頁直到 CSS 內建的 6 秒保險才退場 */
html.cv-bail .preload{display:none!important}
/* 解鎖捲動要用 visible，不能用 auto（1.54.0）。
   ─────────────────────────────────────────────────────────
   這一行的用意只是把 html.preloading 的 overflow:hidden 解開。
   但 auto 不只是「解開」——它會讓 html／body 變成捲動容器，
   而 position:sticky 是相對「最近的捲動祖先」定位的。於是整站所有
   sticky 元件（右側欄、工具列、商店的標題列）全部靜靜地失效：
   樣式還在、computed 仍然是 sticky，就是不黏。

   實測：安全網啟動時，側欄捲到哪就跟到哪（top 從 1002 一路變成 −2998，
   完全沒有在 104 停住）。改成 visible 之後 sticky 立刻恢復。

   visible 一樣解得開 hidden，而且不會建立捲動容器——這裡要的就是解鎖，
   不是「必要時可以捲」。 */
html.cv-bail,html.cv-bail body{overflow:visible!important}

/* ================================================================
   1.19.0 全景照（21:9 這類超寬幅）
   原則：網格縮圖維持正方形不動；只在「作品頁大圖」與「內文全景區塊」
        提供完整不裁切的呈現。
   ================================================================ */

/* ---------- 作品頁大圖 ---------- */
/* 桌機維持 70vh 沉浸式開場（21:9 在此只切掉約 18%）；
   但手機是直式螢幕，滿版裁切會切掉七成以上，
   因此窄螢幕改成照原比例完整顯示，標題移到圖片下方。 */
@media(max-width:760px){
  .sw-hero--pano{height:auto;min-height:0;display:block;overflow:visible}
  /* 原本用 inset:-10% 做視差，改成正常流；chaovisual.js 的視差會寫 inline transform，
     這裡必須 !important 蓋掉，否則圖片會被推離原位。 */
  .sw-hero--pano .sw-hero-bg{position:relative;inset:auto;
    aspect-ratio:var(--sw-ar,21/9);transform:none!important;will-change:auto}
  /* 標題不再壓在照片上，就不需要壓暗與漸層遮罩 */
  .sw-hero--pano .sw-hero-bg img{filter:none}
  .sw-hero--pano::after{display:none}
  .sw-hero--pano .sw-hero-inner{padding:26px var(--pad) 0}
}

/* ---------- 內文全景區塊（編輯器：圖片 → 樣式 → 全景（滿版）） ---------- */
/* 從置中容器「逃脫」到滿版：50% 是內容框的一半，
   calc(50% - 50vw) 剛好等於 -(內容左邊界)，所以圖片會貼齊螢幕左右緣。
   body 本來就有 overflow-x:hidden，不會產生橫向捲軸。 */
/* is-style-chao-pano 是改名前的舊類別。它已經被寫進既有文章裡，
   所以這裡一併保留，舊內容才不會突然失去滿版效果。 */
.sw-body > .chaovisual-pano,.sw-body > .is-style-chaovisual-pano,.sw-body > .is-style-chao-pano,
.page-body > .chaovisual-pano,.page-body > .is-style-chaovisual-pano,.page-body > .is-style-chao-pano{
  max-width:none;width:var(--vw,100vw);
  margin-left:calc(50% - var(--vw,100vw) / 2);margin-right:calc(50% - var(--vw,100vw) / 2);
  margin-top:7vh;margin-bottom:7vh}
.sw-body > .chaovisual-pano img,.sw-body > .is-style-chaovisual-pano img,.sw-body > .is-style-chao-pano img,
.page-body > .chaovisual-pano img,.page-body > .is-style-chaovisual-pano img,.page-body > .is-style-chao-pano img{
  display:block;width:100%;height:auto;border-radius:0;margin:0}
.sw-body > .chaovisual-pano figcaption,.sw-body > .is-style-chaovisual-pano figcaption,.sw-body > .is-style-chao-pano figcaption,
.page-body > .chaovisual-pano figcaption,.page-body > .is-style-chaovisual-pano figcaption,.page-body > .is-style-chao-pano figcaption{
  max-width:820px;margin:16px auto 0;padding:0 var(--pad);
  text-align:center;font-size:13px;color:var(--muted);letter-spacing:.02em}

/* ---------- 照片牆（瀑布流）/works/ 專案格線下方 ---------- */
/* 用 CSS 多欄（columns）做真正的瀑布流：圖片維持原始比例、高度不一，
   由瀏覽器自己排版，完全不需要 JS 量測，因此不會有版面跳動或 resize 卡頓。
   break-inside:avoid 確保一張圖不會被拆到兩欄。 */
.photowall{border-top:1px solid var(--line);padding-top:10vh}
.photowall .sec-head{margin-bottom:34px}
/* .pw-filters 已移除（1.38.0）：照片牆的第二排篩選列在 1.32.0 就拿掉了。 */

.photowall-grid{columns:4 260px;column-gap:14px}
@media (max-width:900px){.photowall-grid{columns:2 160px;column-gap:10px}}
/* 手機改成一列（1.29.2）。
   兩欄在 390px 的螢幕上每張照片只剩約 170px 寬——那個尺寸看不出構圖，
   對一個攝影作品集來說等於白放。一列之後每張是滿版，
   照片牆從「縮圖牆」變回「照片」。

   平板（640–900px）維持兩欄：那個寬度單欄反而會讓每張大到要一直捲。
   （1.33.0 把 600 併到全站的 640 斷點；那 40px 的差別看不出來，
   但少一個只有這裡在用的數字。）

   欄距在單欄時沒有意義（沒有相鄰的欄），但上下的間距要比兩欄時大一點，
   因為照片變大了，10px 會讓兩張黏在一起。 */
@media (max-width:640px){
  .photowall-grid{columns:1;column-gap:0}
  .photowall-grid .pw-item{margin-bottom:14px}
}

.pw-item{position:relative;display:block;margin:0 0 14px;padding:0;
  break-inside:avoid;-webkit-column-break-inside:avoid;
  overflow:hidden;border-radius:var(--r-img);background:var(--bg-soft);cursor:pointer;
  opacity:0;transform:translateY(24px);transition:opacity .7s var(--ease),transform .7s var(--ease)}
@media (max-width:900px){.pw-item{margin-bottom:10px}}

/* ---------- 照片牆的盡頭（1.33.0） ----------
   原本它就這樣停住。無盡的瀑布流有它的道理，但這裡不是社群動態——
   讀者是來看完一位攝影師的作品的，看完應該有個結束，還要有下一步。 */
.pw-end{max-width:var(--maxw);margin:56px auto 0;padding:36px var(--pad) 0;
  border-top:1px solid var(--line);text-align:center}
.pw-end-count{margin:0 0 22px;font-size:14px;color:var(--muted)}
.pw-end-count b{color:var(--ink);font-weight:500;font-variant-numeric:tabular-nums}
.pw-end-acts{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}
@media(max-width:640px){
  .pw-end-acts{flex-direction:column;align-items:stretch}
  .pw-end-acts > *{text-align:center;justify-content:center}
}
.pw-item.reveal{opacity:1;transform:none}
/* 完全停用 JavaScript 時 IntersectionObserver 不會跑，照片牆會整片留在 opacity:0。
   主要的安全網是上面 html:not(.js) 那條（header.php 在 wp_head 前同步加上 .js，
   所有瀏覽器都吃得到）；這條 scripting:none 只是多一層保險，
   新版瀏覽器才支援，因此不能單靠它。 */
@media (scripting:none){.pw-item{opacity:1;transform:none}}
.pw-item.hide{display:none}
.pw-item img{display:block;width:100%;height:auto;
  transition:transform .8s var(--ease),filter .6s var(--ease);
  filter:saturate(.86) contrast(1.02)}
.pw-item:hover img,.pw-item:focus-visible img{transform:scale(1.05);filter:saturate(1) contrast(1.04)}
.pw-item::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,transparent 55%,rgba(0,0,0,.55) 100%);
  opacity:0;transition:opacity .6s var(--ease)}
.pw-item:hover::after,.pw-item:focus-visible::after{opacity:1}
.pw-item:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* 燈箱說明列裡的「查看作品 →」 */
.lb-cap .lb-cap-link{display:inline-block;margin-left:12px;color:var(--accent);text-decoration:none;
  border-bottom:1px solid transparent}
.lb-cap .lb-cap-link:hover{border-bottom-color:var(--accent)}

@media (prefers-reduced-motion:reduce){
  .pw-item{opacity:1;transform:none;transition:none}
  .pw-item img{transition:none}
  .pw-item:hover img{transform:none}
}

/* =========================================================
   文章側欄（1.25.0）—— Journal 列表頁與單篇內文頁

   為什麼由佈景主題負責版面
     外掛的目錄欄是「浮動 + 負左邊界 + sticky」，靠內文欄左邊的留白過活。
     單邊留白 =（視窗寬 - 內文欄寬）/ 2，所以 1366px 的筆電只剩 231px、
     1280px 只剩 188px，欄位塞不下就被 body 的 overflow-x:hidden 直接切掉，
     看起來像「側欄消失」。這裡改成內文與側欄同屬一個 grid、兩欄一起置中，
     寬度變成算得出來的東西，門檻才降得下來。

   數字
     單篇：820 + 48 + 260 = 1128。1280px 螢幕扣掉左右 5vw 還有 1152，
     內文維持滿滿的 820px，一點都沒被吃掉；1200px 才會縮到約 772px。
     列表：900 + 48 + 260 = 1208，1200px 起同樣以縮內文欄為主。

   1200px 以下：grid 收回一般區塊流，側欄整塊落到內文下方。
   目錄模組在那裡沒有意義（讀者已經讀完了），所以只在窄螢幕隱藏目錄，
   窄螢幕要目錄請在內文插目錄區塊，那一份本來就會收成一行可展開的清單。
   ========================================================= */

/* ---------- 兩欄骨架 ---------- */
.article-layout,
.journal-layout{max-width:var(--maxw);margin-left:auto;margin-right:auto}

/* 側欄有可能整個是空的（全新網站只有一個分類、文章也沒有標題階層），
   樣板會補上 is-solo，這裡把版面完全還原成 1.24.0 的單欄狀態。
   權重 0,2,0，蓋得過下面 media query 裡的 .article-layout（0,1,0）。 */
.article-layout.is-solo,
.journal-layout.is-solo{display:block;max-width:none;padding:0}

/* 側欄落在內文下方時，寬度與位置對齊內文欄 */
.cv-side{max-width:820px;margin:0 auto;padding:6vh var(--pad) 0}
.cv-side-toc{display:none}   /* 內文下方的目錄幫不上忙 */

@media (min-width:1200px){

  /* 單篇不在 section 裡，左右留白要自己給；1200px 以下由 .page-body 等子元素
     各自帶 padding:0 var(--pad)，所以留白只寫在這裡，免得窄螢幕左右各縮兩次。 */
  .article-layout{display:grid;grid-template-columns:minmax(0,820px) var(--side-w);
    gap:48px;justify-content:center;padding:0 var(--pad)}
  .journal-layout{display:grid;grid-template-columns:minmax(0,900px) var(--side-w);
    gap:48px;justify-content:center}

  /* 內文欄的寬度與左右留白已經由 grid 決定，子元素不能再各自置中，
     否則 820px 的欄位裡又出現一次 820px 的置中容器，右邊會空一塊。
     權重寫成 0,2,0 才蓋得過 .page-body / .journal-meta / .journal-tags（0,1,0）。 */
  .article-layout:not(.is-solo) .article-main > *,
  .journal-layout:not(.is-solo) .journal-main > *{max-width:none;
    margin-left:0;margin-right:0;padding-left:0;padding-right:0}
  .article-layout:not(.is-solo) .article-main > .page-body{margin-bottom:8vh}
  .article-layout:not(.is-solo) .article-main > .journal-tags{margin-top:0}

  /* 側欄本體：grid 項目預設 stretch，撐滿整列高度，裡層才黏得住。
     這裡刻意不寫 align-items:start —— 寫了項目高度就等於內容高度，
     sticky 立刻失效，是這個版型最容易踩的一個坑。 */
  .cv-side{max-width:none;margin:0;padding:0}
  .cv-side-inner{position:sticky;top:104px;
    max-height:calc(100dvh - 168px);overflow-y:auto;overscroll-behavior:contain;
    scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.18) transparent}
  .cv-side-inner::-webkit-scrollbar{width:3px}
  .cv-side-inner::-webkit-scrollbar-thumb{background:rgba(255,255,255,.18)}

  .article-layout .cv-side-toc{display:block}

  /* 這一篇自己插了目錄區塊時：左邊留白已經讓給 grid 了，
     外掛的浮動欄會浮到看不見的地方，這裡把它壓回文章流裡。
     權重 0,3,0 > 外掛的 .cv-toc.is-rail（0,2,0）。 */
  .article-layout:not(.is-solo) .cv-toc.is-rail{float:none;position:static;
    width:auto;margin:0 0 clamp(28px,4vw,44px);max-height:none;overflow:visible}
}

/* ---------- 側欄模組共用 ----------
   模組是語意上的 <section>（每一塊都有自己的標題），會被上面
   section{padding:12vh var(--pad) 13.5vh} 打到，變成每塊之間空了一整個螢幕高。
   這裡把版面留白收回來，改由 .cv-side-mod + .cv-side-mod 控制間距。 */
.cv-side-mod{padding:0;margin:0}
.cv-side-mod + .cv-side-mod{margin-top:38px}
.cv-side-title{font-family:var(--font-display);font-size:11px;font-weight:500;
  letter-spacing:.2em;text-transform:uppercase;color:var(--muted);
  margin:0 0 14px;padding-bottom:10px;border-bottom:1px solid var(--line)}

/* 側欄裡的目錄：外掛樣式已經處理清單，這裡只收掉區塊級的外距 */
.cv-side-toc .cv-toc{margin:0}
.cv-side-toc .cv-toc-list{padding:0}
.cv-side-toc .cv-toc-a{font-size:13px}

/* 文章清單（相關文章 / 最新文章） */
.cv-side-posts{list-style:none;margin:0;padding:0}
.cv-side-post{display:block;padding:9px 0;text-decoration:none}
.cv-side-post-t{display:block;font-size:14px;line-height:1.55;color:var(--muted);
  transition:color .3s var(--ease)}
.cv-side-post:hover .cv-side-post-t,
.cv-side-post:focus-visible .cv-side-post-t{color:var(--ink)}
.cv-side-post-d{display:block;margin-top:4px;font-size:11px;letter-spacing:.08em;
  color:var(--muted);font-variant-numeric:tabular-nums}

/* 搜尋：一條線就好，不畫輸入框 */
.cv-side-search{display:flex;align-items:center;gap:8px;
  border-bottom:1px solid var(--line);transition:border-color .3s var(--ease)}
.cv-side-search:focus-within{border-bottom-color:var(--accent)}
.cv-side-search input{flex:1;min-width:0;background:transparent;border:0;
  color:var(--ink);font-family:var(--font-body);font-size:14px;padding:9px 0}
.cv-side-search input::placeholder{color:var(--muted)}
.cv-side-search input:focus{outline:none}
/* 命中框補到 32×32（側欄是密集清單，44 會撐開整條線；32 已高於 WCAG 2.2 的 24）。 */
.cv-side-search button{background:transparent;border:0;cursor:pointer;padding:0;
  min-width:32px;min-height:32px;display:flex;align-items:center;justify-content:center;
  color:var(--muted);font-size:15px;line-height:1;transition:color .3s var(--ease)}
.cv-side-search button:hover{color:var(--accent)}
.cv-side-search button:focus-visible{outline:1px solid var(--accent);outline-offset:2px}

/* ---------- 可收合模組（1.26.0：分類） ----------
   側欄的分類會愈長愈多，攤開來就把下面的東西推出視線外。
   收合用原生 <details>，所以沒有 JavaScript 也能開，
   鍵盤與螢幕閱讀器不必額外處理，Ctrl+F 也會自動展開命中的項目。 */
.cv-side-mod--fold{padding:0;margin:0}
.cv-side-fold{display:flex;align-items:center;justify-content:space-between;gap:10px;
  cursor:pointer;list-style:none;user-select:none;
  transition:color .3s var(--ease),border-color .3s var(--ease)}
.cv-side-fold::-webkit-details-marker{display:none}
.cv-side-fold:hover{color:var(--ink)}
/* 鍵盤焦點要看得見，這一行是可以按的 */
.cv-side-fold:focus-visible{outline:1px solid var(--accent);outline-offset:3px}
.cv-side-fold-t{display:inline-flex;align-items:center;gap:7px}
.cv-side-fold-t::after{content:"";width:5px;height:5px;display:inline-block;
  border-right:1px solid currentColor;border-bottom:1px solid currentColor;
  transform:translateY(-1px) rotate(45deg);transition:transform .3s var(--ease)}
.cv-side-mod--fold[open] .cv-side-fold-t::after{transform:translateY(1px) rotate(-135deg)}
/* 收合時仍看得出「我人在哪個分類」；沒有的話就只顯示分類數量。
   展開之後這行資訊由清單本身取代，留著只是重複。 */
.cv-side-fold-v{font-size:11px;letter-spacing:.08em;text-transform:none;
  color:var(--muted);font-variant-numeric:tabular-nums}
.cv-side-mod--fold[open] .cv-side-fold-v{opacity:0}
/* 標題本身有 margin-bottom，收合時那段留白會變成無主的空隙 */
.cv-side-mod--fold:not([open]) .cv-side-fold{margin-bottom:0}

/* 分類清單：名稱在左、篇數在右 */
.cv-side-list{list-style:none;margin:0;padding:0}
.cv-side-list a{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  padding:9px 0;font-size:14px;color:var(--muted);text-decoration:none;
  border-bottom:1px solid var(--line);transition:color .3s var(--ease)}
.cv-side-list li:last-child a{border-bottom:0}
.cv-side-list a:hover,
.cv-side-list a:focus-visible{color:var(--ink)}
.cv-side-n{flex:none;font-size:11px;color:var(--muted);
  font-variant-numeric:tabular-nums}
.cv-side-list li.is-current > a{color:var(--ink)}
.cv-side-list li.is-current .cv-side-n{color:var(--accent)}

/* ---------- 上下層分類（1.27.0） ----------
   有子分類的那一列，名稱本身是收合開關而不是連結——
   一個既能點開又能跳走的東西，讀者永遠猜不到按下去會發生什麼。
   父分類自己有文章時，展開後的第一列才是通往它彙整頁的連結。 */
.cv-side-item.has-sub > .cv-side-branch{display:block}
.cv-side-branch-sum{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  padding:9px 0;font-size:14px;color:var(--muted);cursor:pointer;
  list-style:none;user-select:none;border-bottom:1px solid var(--line);
  transition:color .3s var(--ease)}
.cv-side-branch-sum::-webkit-details-marker{display:none}
.cv-side-branch-sum:hover{color:var(--ink)}
.cv-side-branch-sum:focus-visible{outline:1px solid var(--accent);outline-offset:2px}
.cv-side-branch[open] > .cv-side-branch-sum{color:var(--ink)}
.cv-side-item.is-current > .cv-side-branch > .cv-side-branch-sum{color:var(--ink)}
.cv-side-branch-t{display:inline-flex;align-items:center;gap:7px;min-width:0}
.cv-side-branch-t::after{content:"";width:5px;height:5px;flex:none;display:inline-block;
  border-right:1px solid currentColor;border-bottom:1px solid currentColor;
  transform:translateY(-1px) rotate(45deg);transition:transform .3s var(--ease)}
.cv-side-branch[open] > .cv-side-branch-sum .cv-side-branch-t::after{
  transform:translateY(1px) rotate(-135deg)}
/* 子層縮排靠一條細線，不靠留白：側欄只有 260px，
   每多一層就吃掉一次留白的話，第三層的分類名會被擠到換行。 */
.cv-side-list--sub{margin:0 0 2px;padding-left:12px;border-left:1px solid var(--line)}
.cv-side-list--sub a{font-size:13px;padding:8px 0}
.cv-side-list--sub li:last-child > a{border-bottom:0}
.cv-side-item--self a{color:var(--muted)}
.cv-side-item--self a:hover,
.cv-side-item--self a:focus-visible{color:var(--ink)}
@media(prefers-reduced-motion:reduce){
  .cv-side-branch-sum,.cv-side-branch-t::after{transition:none}
}

/* 標籤：沿用文章底部標籤的膠囊語彙，圓角一致 */
.cv-side-tags{display:flex;flex-wrap:wrap;gap:8px}
.cv-side-tags a{font-size:12px;letter-spacing:.03em;color:var(--muted);
  border:1px solid var(--line);border-radius:var(--r-pill);padding:5px 13px;
  text-decoration:none;transition:.3s var(--ease)}
.cv-side-tags a:hover,
.cv-side-tags a:focus-visible,
.cv-side-tags a.is-current{color:var(--ink);border-color:var(--accent)}

/* ---------- 側欄廣告位（1.26.0） ----------
   沒有貼廣告碼時，chaovisual_side_mod_ad() 根本不輸出這一塊，
   所以這裡不必寫「空的時候要隱藏」——空的時候它不存在。

   min-height 是給 AdSense 用的：廣告是非同步載入的，
   先把高度佔好，載進來時版面才不會往下跳（CLS）。
   用 min-height 而不是固定 height，是為了讓回應式廣告能自己長高。 */
.cv-side-ad{border-top:1px solid var(--line);padding-top:16px}
.cv-side-ad-label{display:block;font-size:10px;letter-spacing:.24em;
  text-transform:uppercase;color:var(--muted);margin-bottom:10px}
.cv-side-ad-slot{min-height:250px;display:flex;align-items:flex-start;justify-content:center;
  overflow:hidden}
/* 廣告服務常常給死寬度的 iframe，側欄只有 260px，不夾一下會撐破版面 */
.cv-side-ad-slot :is(iframe,img,ins,div){max-width:100%}

@media (prefers-reduced-motion:reduce){
  .cv-side-post-t,.cv-side-list a,.cv-side-tags a,
  .cv-side-search,.cv-side-search button,
  .cv-side-fold,.cv-side-fold-t::after{transition:none}
}

/* =========================================================
   作品頁跨頁式（1.28.0）

   一頁一屏，捲動時吸附到下一頁的起點，讀起來像翻一本電子攝影集。
   開關在「外觀 → 自訂 → 作品頁版面」；關掉之後這一整段完全不生效，
   版面原封不動退回連續捲動，不必回頭改任何一篇作品。

   吸附用 proximity 不用 mandatory：mandatory 會強迫捲動一定停在頁面起點，
   一旦某一頁的文字比視窗還高，讀者就被鎖在那一頁裡；頁尾的「更多作品」
   也可能幾乎按不到。proximity 一樣有滑一下就翻過去的手感，
   但內容比視窗高的時候會自動讓開。這是這個版面唯一真正的取捨。
   ========================================================= */
/* scroll-snap-type 一定要下在真正的捲動容器（<html>）上。
   規範明確規定它「不會」像 overflow 那樣從 body 傳播到視窗，
   寫在 body 上是完全沒有作用的——這一點很容易踩。
   兩個選擇器擇一命中即可：:has() 是純 CSS 的路（無 JavaScript 也有吸附），
   .has-spread 由前台腳本補上，給不支援 :has() 的舊瀏覽器。 */
html:has(.single-work.is-spread),
html.has-spread{scroll-snap-type:y proximity}

/* 跨頁模式的 hero 也是一頁：70vh 會讓第一頁看起來像沒對齊。
   用 dvh 而不是 vh，手機瀏覽器的浮動網址列收合時版面才不會跳。 */
.single-work.is-spread .sw-hero{height:100vh;height:100dvh;scroll-snap-align:start}

.sw-spread{margin:0}
/* 上下留白刻意不用 --pad（5vw）。5vw 是「左右」的節奏單位，套到上下之後
   1440 的螢幕會一口氣吃掉 208px，照片只剩七成屏高，跨頁式就變成
   「一張中等大小的照片配一大片黑」——那正是這個版面最不該有的樣子。
   改用一個跟視窗高度掛勾、上下有界的值，照片才吃得到八成以上的屏高。 */
.sw-page{--sw-gap:clamp(22px,3.4vh,48px);
  min-height:100vh;min-height:100dvh;scroll-snap-align:start;
  display:flex;align-items:center;justify-content:center;
  padding:calc(var(--sw-gap) + 64px) var(--pad) var(--sw-gap);
  position:relative}
/* 頁與頁之間一條極淡的線。沒有它，兩張深色照片相接時會看不出換頁了。 */
.sw-page + .sw-page::before{content:"";position:absolute;top:0;left:var(--pad);right:var(--pad);
  height:1px;background:var(--line)}
/* 照片可以比內文欄寬——這裡是攝影集不是文章。文字另外收在 720px。 */
.sw-page-in{width:100%;max-width:1400px;margin:0 auto;
  font-size:16px;color:var(--ink-2);text-align:center}
.sw-page-in > *{margin-left:auto;margin-right:auto}
.sw-page-in > :first-child{margin-top:0}
.sw-page-in > :last-child{margin-bottom:0}
/* 純文字的頁靠左讀比較舒服，一整段靠中間對齊的中文很難讀。 */
.sw-page-in > p,
.sw-page-in > ul,
.sw-page-in > ol,
.sw-page-in > blockquote{max-width:720px;text-align:left;line-height:1.9}
/* 但同一頁有照片時，那段文字實際上是這張照片的說明，置中才跟圖是一組的。
   不支援 :has() 的瀏覽器退回靠左，只是少了一點對齊感，不會壞。 */
.sw-page-in:has(figure) > p,
.sw-page-in:has(.wp-block-image) > p{max-width:640px;text-align:center}

/* 照片一律完整顯示，不裁切。
   跨頁式的重點是「這一屏就是這張照片」，為了填滿畫面把構圖切掉，
   等於把這個版面存在的理由拿掉——寧可上下留黑邊。
   高度扣掉頁首與上下留白，圖再高也不會把下面的圖說擠出畫面。 */
.sw-page-in :is(figure,.wp-block-image){margin:0 auto;width:fit-content;max-width:100%}
/* 高度上限要扣掉：上下留白（--sw-gap 隨視窗高變，所以寫進 calc 而不是猜一個常數）、
   頁首讓出的 64px，再加上同一頁其他東西佔掉的空間——
   圖說實測 31px，留 46px；再加一段文字實測 46px（兩行 76px），合計留 122px。
   用同一個數字套全部的話，不是文字被擠出畫面，就是每張照片都白白矮一截。 */
/* 排除 .cvf（作品影像）：那個區塊自己算高度預算，而且是這裡把
   --cvf-room 交給它的（見下面「作品影像區塊在跨頁式裡的高度預算」）。
   這條規則若也套進去，等於把交出去的決定權又收回來——實測後果是
   1400px 寬的欄位裡照片被畫成 547px 並且**靠左**（margin:0 蓋掉了置中），
   跟章節對開那個出血的問題是同一種：兩邊都想決定同一件事。 */
.sw-page-in :is(figure,.wp-block-image):not(.cvf) img{width:auto;max-width:100%;height:auto;
  max-height:calc(100dvh - (var(--sw-gap) * 2) - 110px);
  object-fit:contain;border-radius:var(--r-img);margin:0}
.sw-page.has-text .sw-page-in :is(figure,.wp-block-image):not(.cvf) img{
  max-height:calc(100dvh - (var(--sw-gap) * 2) - 186px)}
/* width:0 + min-width:100% 是為了不讓圖說去撐寬 <figure>。
   外框是 width:fit-content（貼著照片本身），而 fit-content 會取子元素裡最寬的那個——
   一句長圖說就會把外框撐得比照片還寬，看起來像圖說「凸出去」了。
   width:0 讓它對外框的寬度計算不作數，min-width:100% 再把它拉回外框寬度並自然折行。 */
.sw-page-in figcaption{margin-top:14px;font-size:13px;letter-spacing:.04em;line-height:1.6;
  color:var(--muted);text-align:center;width:0;min-width:100%}
/* 作品影像的圖說例外（1.53.0）。
   上面那組 width:0 + min-width:100% 是為了「不讓圖說撐寬 width:fit-content 的外框」，
   前提是外框已經貼著照片。但 .cvf 的外框是 width:100%（給 iframe/百分比寬度用的），
   貼著照片的是它裡面的 .cvf-stage——min-width:100% 於是把圖說拉成整個欄位那麼寬，
   1400px 的圖說掛在 547px 的照片下面，看起來不像那張照片的說明。
   放開之後由區塊自己的 max-width 收，並靠 .cvf 的 align-items:center 置中。 */
.sw-page-in .cvf figcaption{width:auto;min-width:0}
/* 圖庫、章節對開、地點導覽這類自帶版面的區塊不要被上面的規則夾住 */
.sw-page-in :is(.cg,.wp-block-gallery,.cchap,.kg){width:100%;max-width:100%;text-align:left}
.sw-page-in :is(.cg,.wp-block-gallery) img{max-height:none;width:100%}

/* 滿版出血的區塊要放開 width，不只是 max-width（1.52.0）。
   ─────────────────────────────────────────────────────────
   章節對開有一個 is-bleed 模式，做法是經典的
   `margin-inline: calc(50% - 50vw)`：靠負的左右外距把框推出內文欄。
   那個技巧成立的前提是 **width:auto** —— 寬度要能被負外距撐開。

   但上面那條 `.sw-page-in :is(…,.cchap,…){width:100%}` 把寬度釘死了。
   釘死之後負外距不再撐開盒子，只是把整個盒子往左「平移」半個出血距離。
   實測 2519px 的視窗、1400px 的內文欄：margin-inline 是 −559.5px，
   結果 .cchap 仍然是 1400px 寬、但 x 從 552 變成 −7，整塊往左偏 567px，
   右邊空出一大片——這就是「跨頁式開啟後圖片都靠左」。

   放開 width（順帶放開 max-width）之後，同一個視窗量到 x=−7、w=2519，
   九頁的中心偏移全部一致。 */
.sw-page-in :is(.cchap,.cg,.kg,.wp-block-gallery).is-bleed{width:auto;max-width:none}

/* 影片與作品影像也一樣（1.51.0）——這兩個漏掉的後果比其他幾個嚴重得多。
   ─────────────────────────────────────────────────────────
   它們的最外層都是 <figure>，所以會被上面那條
   `.sw-page-in :is(figure,.wp-block-image){width:fit-content}` 收成貼齊內容。
   一般的 <img> 有固有尺寸，fit-content 收出來還是原本的大小，看不出差別；
   **但 <iframe> 的固有尺寸是 300×150**，而播放器是 width:100% ——
   百分比寬度碰到 fit-content 的父層等於沒有依據，於是整個播放器塌成
   300×150 的一小塊。畫面上看到的就是「影片點開後視窗很小一個」。

   作品影像（.cvf）雖然目前還沒人回報，但它的外層同樣是 <figure>、
   內部也是 flex + 百分比寬度，是同一個坑，一起補起來。 */
.sw-page-in :is(.cv-video,.cvf){width:100%;max-width:100%}

/* ---- 頁碼指示器 ----
   伺服器端就輸出成一排錨點連結：沒有 JavaScript 時仍然點得到、Tab 得到，
   腳本只負責「目前在第幾頁」的高亮。 */
.sw-dots{position:fixed;right:calc(var(--pad) / 2);top:50%;transform:translateY(-50%);
  z-index:var(--z-rail);display:flex;flex-direction:column;gap:0;padding:8px 4px}
/* 點本身維持 6px 的視覺，但可點區域補到 24×24（WCAG 2.2 最低）。
   原本是 12×12，手指按不太到。改用 flex 置中撐開命中框，
   外觀不變：原本 12px 方塊 + 11px 間距 = 23px 節奏，現在 24px 方塊 + 0 間距 = 24px。 */
.sw-dot{display:flex;align-items:center;justify-content:center;
  min-width:24px;min-height:24px;padding:0;line-height:0}
/* 未選中的頁碼點提到與 --muted 同級（1.38.0）。
   原本 rgba(255,255,255,.42) 在 #0b0b0d 上只有 4.04:1——它是傳達
   「你在第幾頁」的狀態指示器，不是裝飾，1.4.11 要求 3:1，
   但真正的問題是低視力讀者根本看不出總共有幾頁。 */
.sw-dot i{display:block;width:6px;height:6px;border-radius:50%;
  background:var(--muted);transition:.3s var(--ease)}
.sw-dot:hover i{background:rgba(255,255,255,.7)}
.sw-dot.is-current i{background:var(--accent);transform:scale(1.5)}
.sw-dot:focus-visible{outline:1px solid var(--accent);outline-offset:1px;border-radius:50%}
/* 螢幕不夠高或視窗太窄時，指示器會壓在內容上，直接收起來。
   翻頁本來就靠捲動，指示器只是輔助的定位資訊。 */
@media(max-width:1024px),(max-height:560px){
  .sw-dots{display:none}
}

/* 讀者要求減少動態時不做平滑捲動；吸附本身保留，那是版面不是動畫。 */
@media(prefers-reduced-motion:reduce){
  .sw-dot i{transition:none}
}

/* =========================================================
   全站點擊光暈與 CTA 互動（1.29.0）
   ========================================================= */

/* ---------- 點擊光暈 ----------
   首頁 hero 的版本畫在 canvas 上，那張 canvas 只存在於 hero 裡；
   這一份是 DOM 版本，任何頁面按下去都有，數字與 hero 完全一致
   （0.76 秒、18px 起、擴散到約 168px、白色核心→金色→透明）。

   光暈用 transform:scale（交給合成器，不觸發版面計算）；
   外環改用 width/height，因為 1px 的框被 scale 放大九倍會變成一條粗白線。
   單一元素、0.76 秒後自己移除，代價很小。 */
.cv-fx{position:fixed;inset:0;pointer-events:none;z-index:var(--z-fx);overflow:hidden}
.cv-ripple{position:absolute;left:0;top:0;width:0;height:0}
.cv-ripple i{position:absolute;left:0;top:0;display:block;border-radius:50%;
  transform:translate(-50%,-50%)}
.cv-ripple-glow{width:168px;height:168px;
  background:radial-gradient(circle closest-side,
    rgba(255,255,255,.20) 0%,
    rgba(201,163,91,.10) 55%,
    rgba(201,163,91,0) 100%);
  animation:cv-ripple-glow .76s var(--ease) forwards}
.cv-ripple-ring{width:36px;height:36px;border:1px solid rgba(255,255,255,.30);
  animation:cv-ripple-ring .76s var(--ease) forwards}
@keyframes cv-ripple-glow{
  from{transform:translate(-50%,-50%) scale(.12);opacity:1}
  to{transform:translate(-50%,-50%) scale(1);opacity:0}
}
@keyframes cv-ripple-ring{
  from{width:36px;height:36px;opacity:.9}
  to{width:336px;height:336px;opacity:0}
}
/* 燈箱之類的覆蓋層開著時，光暈要浮在它上面才看得到 */
html.overlay-open .cv-fx{z-index:var(--z-fx-over)}

/* ---------- CTA 互動 ----------
   金色是狀態色，只在互動時出現——所以 CTA 的 hover 不是「換個顏色」，
   而是「金色從左邊掃進來」，掃完就是按下去會發生什麼的預告。

   為什麼用 scaleX 的偽元素而不是 background-position 或漸層動畫：
   transform 走合成器，掃過去的過程不會每一格都重算版面；
   而且 scaleX(0) 在起始狀態完全不佔位，不必擔心圓角被切到。

   isolation:isolate 是必要的：偽元素用 z-index:-1 躲到文字後面，
   沒有這一行它會躲到整個按鈕（甚至父層背景）後面，變成看不見。 */
.ghost-btn,
.store-cta-buy,
[data-cta]{position:relative;overflow:hidden;isolation:isolate}
.ghost-btn::before,
.store-cta-buy::before,
[data-cta]::before{content:"";position:absolute;inset:0;z-index:-1;
  background:var(--accent);transform:scaleX(0);transform-origin:left center;
  transition:transform .45s var(--ease)}
.ghost-btn:hover::before,
.ghost-btn:focus-visible::before,
.store-cta-buy:hover::before,
.store-cta-buy:focus-visible::before,
[data-cta]:hover::before,
[data-cta]:focus-visible::before{transform:scaleX(1)}
/* 掃過來之後文字要換成深色，否則金底配灰字讀不到（對比不足） */
.ghost-btn:hover,
.ghost-btn:focus-visible,
[data-cta]:hover,
[data-cta]:focus-visible{color:var(--on-accent);border-color:var(--accent)}
/* 離開時讓金色往右退回去，而不是原路縮回左邊——來回的方向一致，
   看起來才像「掃進來、掃出去」而不是「伸出來又縮回去」。 */
.ghost-btn::before,
.store-cta-buy::before,
[data-cta]::before{transform-origin:right center}
.ghost-btn:hover::before,
.ghost-btn:focus-visible::before,
.store-cta-buy:hover::before,
.store-cta-buy:focus-visible::before,
[data-cta]:hover::before,
[data-cta]:focus-visible::before{transform-origin:left center}

/* 已經是金底的購買鈕：掃進來的是反相的深色，維持「hover 一定有變化」 */
.store-cta-buy::before{background:var(--bg)}
.store-cta-buy:hover,
.store-cta-buy:focus-visible{color:var(--accent);border-color:var(--accent)}

/* 服務頁與聯絡頁原本寫了「hover 直接換成金底」，那會讓掃入完全看不到。
   權重要壓過 .svc-cta .ghost-btn:hover（0,2,1），所以這裡寫 0,3,0。 */
.svc-cta .ghost-btn:hover,
.svc-cta .ghost-btn:focus-visible,
.contact-form .ghost-btn:hover,
.contact-form .ghost-btn:focus-visible{background:transparent}

/* 文字型 CTA：底線由右往左收、由左往右展，跟按鈕的方向語言一致 */
.sw-more-all,
.about-cta a,
[data-cta-text]{position:relative}
.sw-more-all::after,
.about-cta a::after,
[data-cta-text]::after{content:"";position:absolute;left:0;right:0;bottom:-5px;
  height:1px;background:var(--accent);transform:scaleX(0);transform-origin:right center;
  transition:transform .4s var(--ease)}
.sw-more-all:hover::after,
.sw-more-all:focus-visible::after,
.about-cta a:hover::after,
.about-cta a:focus-visible::after,
[data-cta-text]:hover::after,
[data-cta-text]:focus-visible::after{transform:scaleX(1);transform-origin:left center}

/* 按下去要有回饋：沒有 :active 的按鈕摸起來像圖片，不像按鈕。
   幅度刻意很小——這是觸感，不是動畫表演。 */
.ghost-btn:active,
.store-cta-buy:active,
[data-cta]:active{transform:translateY(1px) scale(.985)}

/* 鍵盤焦點一定要看得見。掃入效果本身就是很明顯的狀態變化，
   但只有滑鼠使用者看得到 hover，鍵盤使用者需要一個外框。 */
.ghost-btn:focus-visible,
.store-cta-buy:focus-visible,
.sw-more-all:focus-visible,
[data-cta]:focus-visible,
[data-cta-text]:focus-visible{outline:1px solid var(--accent);outline-offset:3px}

@media(prefers-reduced-motion:reduce){
  .cv-fx{display:none}
  .ghost-btn::before,.store-cta-buy::before,[data-cta]::before,
  .sw-more-all::after,.about-cta a::after,[data-cta-text]::after{transition:none}
  .ghost-btn:active,.store-cta-buy:active,[data-cta]:active{transform:none}
}

/* =========================================================
   手機版側欄面板（1.30.0）

   桌機側欄就在內文右邊、捲動時黏在畫面上（position:sticky，1.25.0 起就是如此）。
   手機沒有那個空間，所以整個側欄變成從頁首左邊那顆按鈕打開的全螢幕面板。

   為什麼是左邊：左邊＝「這一頁裡面有什麼」（目錄、相關文章、分類），
   右邊＝「這個網站有什麼」（作品、服務、關於）。兩種不同層級的導覽
   分居兩側，讀者一眼就分得出來；擠在同一顆漢堡裡只會讓兩邊都變難找。

   面板化只在 html.js 底下生效。沒有 JavaScript（或安全網啟動）時，
   側欄退回原本「落在內文下方」的排法——內容一定看得到，只是少了面板。
   ========================================================= */

/* ---------- 浮動按鈕（1.31.0）----------
   右下角是手機上拇指本來就在的位置。頁首左上角要換一隻手才按得到，
   而讀者一路往下捲的時候，手指離頁首愈來愈遠。

   兩顆由下往上堆：本頁導覽在下（常用，優先給最好按的位置），
   回到最上面在它上面。DOM 順序是 [回到最上面, 本頁導覽]，配 flex-direction:column
   剛好是這個視覺順序——先前寫成 column-reverse 就反了，兩顆位置對調。
   沒有側欄的頁面只有回到最上面那一顆，容器貼著底部，它自己就落到最下面，
   畫面上不會留一個空位。 */
.cv-fab{position:fixed;right:max(16px,calc(var(--pad) / 2));
  bottom:calc(18px + env(safe-area-inset-bottom));
  z-index:var(--z-panel-btn);
  display:flex;flex-direction:column;gap:10px;
  pointer-events:none}              /* 容器不吃事件，只有按鈕吃 */
.cv-fab-btn{pointer-events:auto;position:relative;
  width:46px;height:46px;flex:none;border-radius:50%;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  color:var(--ink);border:1px solid var(--line);
  background:rgba(20,20,24,.82);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  transition:transform .35s var(--ease),opacity .35s var(--ease),
    border-color .3s var(--ease),color .3s var(--ease),background-color .3s var(--ease)}
.cv-fab-btn:hover,.cv-fab-btn:focus-visible{color:var(--on-accent);background:var(--accent);border-color:var(--accent)}
.cv-fab-btn:focus-visible{outline:1px solid var(--accent);outline-offset:3px}
/* 按下去的觸感。幅度刻意很小——這是回饋，不是動畫表演。 */
.cv-fab-btn:active{transform:scale(.92)}
.cv-fab-ico{display:flex;align-items:center;justify-content:center;position:relative}
.cv-fab-ico svg{display:block}

/* 進場／退場：往下移一點再淡出，方向和「它要離開視線」一致 */
.cv-fab-top{opacity:0;transform:translateY(14px) scale(.9)}
.cv-fab-top.is-in{opacity:1;transform:none}
/* [hidden] 會被上面的 display:flex 蓋掉，必須自己補回來 */
.cv-fab-btn[hidden]{display:none}

/* 本頁導覽：打開時圖示換成 X，並轉一下 */
.cv-fab-side .cv-fab-x{position:absolute;inset:0;margin:auto;
  opacity:0;transform:rotate(-90deg);transition:opacity .3s var(--ease),transform .3s var(--ease)}
.cv-fab-side .cv-fab-ico > svg:first-child{transition:opacity .3s var(--ease),transform .3s var(--ease)}
html.side-open .cv-fab-side .cv-fab-ico > svg:first-child{opacity:0;transform:rotate(90deg)}
html.side-open .cv-fab-side .cv-fab-x{opacity:1;transform:none}
html.side-open .cv-fab-side{color:var(--on-accent);background:var(--accent);border-color:var(--accent)}
/* 兩個條件都要成立才顯示這一顆：
   (a) 前台腳本確認面板可用（side-ready）、(b) 視窗窄到側欄真的變成面板。
   桌機的側欄本來就在畫面上，那裡出現一顆「打開側欄」只會是個按了沒反應的按鈕——
   面板的樣式整組寫在 760px 的媒體查詢裡，所以顯示條件也必須含同一個斷點。 */
.cv-fab-side{display:none}
@media(max-width:760px){
  html.side-ready .cv-fab-side{display:flex}
}

/* 長按（或滑鼠停留）跑出說明。
   圖示按鈕的老問題是「看得懂圖但不確定會發生什麼」；
   長按提示讓讀者可以先確認再放手，手指滑開就取消。 */
.cv-fab-hint{position:absolute;right:calc(100% + 10px);top:50%;
  transform:translateY(-50%) translateX(6px);white-space:nowrap;
  font-family:var(--font-display);font-size:12px;letter-spacing:.12em;
  color:var(--ink);background:rgba(20,20,24,.94);
  border:1px solid var(--line);border-radius:var(--r-pill);padding:7px 13px;
  opacity:0;pointer-events:none;
  transition:opacity .25s var(--ease),transform .25s var(--ease)}
.cv-fab-btn.is-hold .cv-fab-hint{opacity:1;transform:translateY(-50%)}
@media(hover:hover){
  .cv-fab-btn:hover .cv-fab-hint{opacity:1;transform:translateY(-50%)}
}

@media(prefers-reduced-motion:reduce){
  .cv-fab-btn,.cv-fab-hint,.cv-fab-side .cv-fab-x,
  .cv-fab-side .cv-fab-ico > svg:first-child{transition:none}
  .cv-fab-top{transform:none}
  .cv-fab-btn:active{transform:none}
}

/* 面板的標題列：桌機不需要（側欄本來就在畫面上），只在手機出現 */
.cv-side-bar{display:none}

@media(max-width:760px){

  /* 面板本體。用 fixed 全螢幕，與網站選單同一套互動語言。
     ⚠ 頁首在 .scrolled 時有 backdrop-filter，那會讓子元素的 fixed 改以頁首
     為定位基準——所以面板一定要放在頁首**外面**（它在 .article-layout 裡，沒問題）。 */
  html.side-ready .cv-side{position:fixed;top:0;left:0;right:0;bottom:0;width:100%;
    height:100vh;height:100dvh;max-width:none;margin:0;padding:0;z-index:var(--z-panel);
    background:rgba(11,11,13,.97);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
    opacity:0;visibility:hidden;pointer-events:none;
    transition:opacity .35s var(--ease),visibility .35s;
    display:flex;flex-direction:column}
  html.side-ready.side-open .cv-side{opacity:1;visibility:visible;pointer-events:auto}
  html.side-ready.side-open,html.side-ready.side-open body{overflow:hidden;overscroll-behavior:none}

  /* 面板在頁首底下（z-index 95 < 100），所以最上面要讓出頁首的高度，
     標題列才不會被頁首壓住。頁首捲動後會縮成 14px 內距，這裡取展開時的高度。
     底部也要讓出浮動按鈕的空間，否則最後一列會被按鈕壓住。 */
  html.side-ready .cv-side-bar{display:flex;align-items:center;flex:none;
    padding:calc(22px + 46px) var(--pad) 16px;border-bottom:1px solid var(--line)}
  .cv-side-bar-t{font-family:var(--font-display);font-size:11px;letter-spacing:.24em;
    text-transform:uppercase;color:var(--accent)}

  /* 面板開著的時候，右上角的網站選單先收起來：
     兩個全螢幕覆蓋層不該同時打得開。關閉的動作由右下角那顆按鈕負責
     （它在面板之上，而且就在拇指的位置）。 */
  html.side-ready.side-open .nav-toggle{opacity:0;pointer-events:none}

  /* 面板內容自己捲；桌機的 sticky 與高度上限在這裡都要收掉，
     否則面板裡會出現「內層又黏又限高」的怪捲動。 */
  html.side-ready .cv-side-inner{position:static;max-height:none;flex:1 1 auto;
    overflow-y:auto;-webkit-overflow-scrolling:touch;
    padding:28px var(--pad) calc(96px + env(safe-area-inset-bottom))}
  /* 手機的點擊範圍要夠大 */
  html.side-ready .cv-side .cv-side-list a,
  html.side-ready .cv-side .cv-side-branch-sum{padding-top:12px;padding-bottom:12px}
  html.side-ready .cv-side .cv-side-post{padding:12px 0}

  /* 安全網（cv-bail）刻意**不再**插手面板。
     面板能不能用只由 side-ready 決定，而 side-ready 是由「真的掛好事件的那段程式」
     加上的——兩個開關各自判斷，就會出現「一個說可以、一個說不行」的錯位，
     那正是「按鈕變成 X 了，畫面卻什麼都沒發生」的成因。
     主腳本沒到位時 side-ready 根本不存在，按鈕不會出現，側欄留在內文下方，
     不需要另外一條規則去救。 */
}

/* 頁尾之前的廣告落點。空的時候完全不佔位——
   側欄的廣告是由前台腳本在窄螢幕時搬進來的，寬螢幕這裡本來就是空的。 */
.cv-ad-bottom:empty{display:none}
.cv-ad-bottom{max-width:820px;margin:0 auto;padding:0 var(--pad) 8vh}
.cv-ad-bottom .cv-side-ad{margin:0}

/* =========================================================
   PhotoFlow 產品頁（page-photoflow.php）

   原始銷售頁是一份淺色的獨立 HTML：紙白底、橘色強調色、2px 直角、
   自帶一套按鈕與字級。整份搬進來會變成站上唯一一頁長得不一樣的頁面，
   而讀者對「這頁是不是還在同一個網站」是很敏感的。

   所以這裡不是把淺色轉成暗色而已，是換成本站既有的那一套：
     ‧ 顏色     一律 var(--bg/--bg-soft/--ink/--muted/--line/--accent)
     ‧ 強調色   橘色（低角度日光）換成全站唯一的金色，用法照舊：
                只給可互動或代表狀態的東西。
     ‧ 圓角     2px 換成 --r-img / --r-card / --r-pill 三選一
     ‧ 字重     原稿用 600，但自架的 Jost 只有 300/400/500，
                要 600 會拿到瀏覽器合成的假粗體，糊掉。全部降成 500。
     ‧ 按鈕     不另做一套，直接用 .store-cta-buy 與 .ghost-btn
     ‧ 進場     .rise + 自帶的 IntersectionObserver 換成全站的 .reveal-up
     ‧ 寬度     原稿用 ch / em 限寬，那是拉丁字母的量法
                （1ch 是「0」的寬度），中文排下來會忽寬忽窄。改成 px。
   ========================================================= */
.pf{
  --pf-ink-2:var(--ink-3);        /* 攝影流程頁沿用全站內文灰，不再自成一格 */
  /* 受光種類色階：同一個色相由亮到暗，剛好對應「光的強度」由強到無。
     最強的那一段用全站的金色，因為那正是這個功能要你去卡的時段。 */
  --pf-side:var(--accent);
  --pf-front:#9a7c46;
  --pf-graze:#6b5936;
  --pf-back:#3c3c44;
  --pf-none:#22222a;
  max-width:var(--maxw);margin:0 auto;
}
.pf .pf-sec{padding:clamp(64px,10vw,132px) var(--pad)}
.pf .pf-sec-tight{padding-top:0}
.pf .pf-sec-head{margin-bottom:clamp(30px,4vw,52px)}
.pf .pf-h2{font-family:var(--font-display);font-weight:400;letter-spacing:-.01em;
  font-size:clamp(26px,4vw,44px);line-height:1.26;margin:0 0 18px;max-width:720px}
.pf .pf-h3{font-family:var(--font-display);font-weight:500;font-size:18px;line-height:1.4;margin:0 0 12px}
.pf .pf-lead{color:var(--pf-ink-2);font-size:clamp(15px,1.4vw,17px);line-height:1.9;
  margin:0 0 16px;max-width:620px}
.pf .pf-small{color:var(--muted);font-size:13px;line-height:1.8;margin:0}
.pf h3{font-family:var(--font-display);font-weight:500}
.pf ul{list-style:none;margin:0;padding:0}
.pf .pf-i{flex:none}

/* ---- 首屏 ---- */
.pf-hero{display:grid;grid-template-columns:1fr;gap:clamp(28px,4vw,56px);align-items:center;
  padding:clamp(24px,4vw,52px) var(--pad) clamp(40px,6vw,72px)}
.pf-hero h1{font-family:var(--font-display);font-weight:300;letter-spacing:-.02em;
  font-size:clamp(30px,5vw,54px);line-height:1.2;margin:0 0 20px}
.pf-hero h1 em{font-style:normal;color:var(--accent)}
.pf-hero-media img{width:100%;height:clamp(240px,40vh,400px);object-fit:cover;
  border-radius:var(--r-img);box-shadow:var(--shadow-2)}
.pf-hero-media{margin:0}
.pf-cta{display:flex;flex-wrap:wrap;gap:12px;margin-top:26px}
@media(min-width:900px){
  .pf-hero{grid-template-columns:1.1fr .9fr}
  .pf-hero-media img{height:min(62vh,540px)}
}

/* ---- 規格帶 ---- */
.pf-specs{border-block:1px solid var(--line);padding:20px var(--pad);margin:0}
.pf-specs ul{display:flex;flex-wrap:wrap;gap:10px 38px;font-size:13px;color:var(--muted)}
.pf-specs li{display:flex;align-items:center;gap:9px}
.pf-specs .pf-i{width:17px;height:17px;color:var(--accent)}

/* ---- 章節捷徑 ---- */
.pf-rail{display:flex;flex-wrap:wrap;gap:10px 26px;padding:20px var(--pad) 0;
  font-size:13px;color:var(--muted);letter-spacing:.04em}
.pf-rail a{border-bottom:1px solid transparent;padding-bottom:2px;transition:color .3s var(--ease),border-color .3s var(--ease)}
.pf-rail a:hover{color:var(--accent);border-color:var(--accent)}

/* ---- 受光色帶 ---- */
.pf-band-card{border:1px solid var(--line);border-radius:var(--r-card);
  padding:clamp(20px,3vw,36px);background:var(--bg-soft)}
.pf-band-head{display:flex;flex-wrap:wrap;justify-content:space-between;gap:10px;
  align-items:baseline;margin-bottom:20px}
.pf-band-head h3{font-size:15px;margin:0}
.pf-band-head .pf-small{font-size:12px}
.pf-band{display:flex;height:36px;border-radius:var(--r-img);overflow:hidden}
.pf-band div{height:100%}
.pf-ticks{display:flex;justify-content:space-between;margin-top:8px;font-size:11px;
  color:var(--muted);letter-spacing:.06em}
.pf-legend{display:flex;flex-wrap:wrap;gap:8px 22px;margin-top:24px;font-size:13px;color:var(--pf-ink-2)}
.pf-legend span{display:inline-flex;align-items:center;gap:8px}
.pf-legend i{width:13px;height:13px;border-radius:1px;display:block}
.pf-windows{margin-top:28px;border-top:1px solid var(--line)}
.pf-windows li{display:grid;grid-template-columns:104px 1fr auto;gap:16px;align-items:baseline;
  padding:13px 0;border-bottom:1px solid var(--line);font-size:15px}
.pf-windows li.is-best{color:var(--accent)}
.pf-windows time{font-variant-numeric:tabular-nums}
.pf-windows .pf-why{color:var(--muted);font-size:13px}
@media(max-width:640px){
  .pf-windows li{grid-template-columns:100px 1fr}
  .pf-windows .pf-why{grid-column:1/-1;margin-top:-4px}
}

/* ---- 左右分割 ---- */
.pf-split{display:grid;grid-template-columns:1fr;gap:clamp(28px,4vw,64px);align-items:center}
.pf-split-media{margin:0}
.pf-split-media img{width:100%;aspect-ratio:5/4;object-fit:cover;
  border-radius:var(--r-img);box-shadow:var(--shadow-2)}
@media(min-width:900px){ .pf-split{grid-template-columns:1fr 1fr} }
.pf-facts{border-top:1px solid var(--line);margin-top:26px}
.pf-facts li{padding:15px 0;border-bottom:1px solid var(--line);
  display:grid;grid-template-columns:auto 1fr;gap:14px;align-items:start}
.pf-facts .pf-i{width:19px;height:19px;color:var(--accent);margin-top:3px}
.pf-facts b{display:block;font-weight:500;font-size:15px;margin-bottom:3px}
.pf-facts p{margin:0;font-size:14px;color:var(--muted);line-height:1.75}

/* ---- 條件網格 ---- */
.pf-cond,.pf-money{display:grid;gap:14px;grid-template-columns:1fr}
.pf-cell{border:1px solid var(--line);border-radius:var(--r-card);
  padding:clamp(20px,2.6vw,30px);background:var(--bg-soft)}
.pf-cell h3{font-size:16px;margin:0 0 10px}
.pf-cell p{margin:0;font-size:14px;color:var(--muted);line-height:1.8}
.pf-cell.is-wash{background:rgba(201,163,91,.07);border-color:rgba(201,163,91,.22)}
.pf-cell.is-photo{padding:0;overflow:hidden;min-height:200px;margin:0}
.pf-cell.is-photo img{width:100%;height:100%;min-height:200px;object-fit:cover}
.pf-metrics{display:flex;flex-wrap:wrap;gap:12px 32px;margin-top:16px}
.pf-metrics b{display:block;font-family:var(--font-display);font-weight:400;
  font-size:clamp(22px,3vw,32px);line-height:1.1;color:var(--accent)}
.pf-metrics span{font-size:13px;color:var(--muted)}
@media(min-width:760px){
  .pf-cond{grid-template-columns:repeat(6,1fr)}
  .pf-cond>*:nth-child(1){grid-column:span 6}
  .pf-cond>*:nth-child(2),.pf-cond>*:nth-child(3){grid-column:span 3}
  .pf-cond>*:nth-child(4){grid-column:span 2}
  .pf-cond>*:nth-child(5){grid-column:span 4}
  /* 沒有照片時只剩四格：最後一格改成整列，才不會留一個 2 欄寬的缺口。 */
  .pf-cond.no-photo>*:nth-child(4){grid-column:span 6}
}

/* ---- 錢與法律 ---- */
/* 原稿讓第一格跨兩列（1.4fr + 兩個 1fr 疊起來）。字數對不上的時候，
   第一格會被拉成右邊兩格的總高，用途標籤與底下那行摘要之間就空出
   一大片沒有東西的區域。改成同一列並排，高度由 grid 自己對齊。 */
.pf-money .pf-cell{display:flex;flex-direction:column;gap:20px}
.pf-money .pf-summary{margin-top:auto}
@media(min-width:900px){
  .pf-money{grid-template-columns:1fr 1fr}
  .pf-money>*:nth-child(3){grid-column:span 2}
}
@media(min-width:1200px){
  .pf-money{grid-template-columns:repeat(3,1fr)}
  .pf-money>*:nth-child(3){grid-column:auto}
}
.pf-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px}
.pf-chips span{font-size:13px;padding:6px 13px;border:1px solid var(--line);
  border-radius:var(--r-pill);color:var(--muted)}
.pf-chips .is-on{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.pf-summary{margin:20px 0 0;padding-top:16px;border-top:1px solid var(--line);
  font-size:14px;color:var(--pf-ink-2);line-height:1.8}
.pf-warn{display:flex;gap:12px;align-items:flex-start;margin-top:18px;
  padding:15px 17px;border-radius:var(--r-card);background:rgba(201,163,91,.08);
  font-size:14px;line-height:1.7;color:var(--pf-ink-2)}
.pf-warn .pf-i{width:19px;height:19px;color:var(--accent);margin-top:2px}

/* ---- 四步驟 ---- */
.pf-flow{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);
  border-radius:var(--r-card);overflow:hidden;grid-template-columns:1fr}
.pf-flow article{background:var(--bg-soft);padding:clamp(22px,2.8vw,32px);
  display:flex;flex-direction:column;gap:10px}
.pf-flow .pf-i{width:22px;height:22px;color:var(--accent)}
.pf-flow h3{font-size:16px;margin:0}
.pf-flow p{margin:0;font-size:14px;color:var(--muted);line-height:1.75}
@media(min-width:640px){ .pf-flow{grid-template-columns:repeat(2,1fr)} }
@media(min-width:1024px){ .pf-flow{grid-template-columns:repeat(4,1fr)} }

/* ---- 截圖 ---- */
.pf-shot{margin:0 auto;max-width:960px}
.pf-shot img{width:100%;border:1px solid var(--line);border-radius:var(--r-card)}
/* 這一格改放影片時，影片區塊自帶邊距，這裡收掉避免上下各留一次。 */
.pf-shot .cv-video{margin:0}
.pf-shot .cv-video img{border:0}

/* ---- 取捨與誠實 ---- */
.pf-manifesto{background:var(--bg-soft);border-block:1px solid var(--line)}
.pf-manifesto blockquote{margin:0;max-width:520px;font-family:var(--font-display);
  font-weight:300;font-size:clamp(22px,3.4vw,38px);line-height:1.32;letter-spacing:-.01em}
.pf-cols{display:grid;gap:clamp(24px,3.4vw,56px);grid-template-columns:1fr;margin-top:38px}
.pf-cols h3{font-size:15px;margin:0 0 8px}
.pf-cols p{margin:0;font-size:14px;color:var(--muted);line-height:1.8}
@media(min-width:900px){ .pf-cols{grid-template-columns:repeat(3,1fr)} }
.pf-honest{display:grid;gap:clamp(26px,4vw,60px);grid-template-columns:1fr}
@media(min-width:1024px){ .pf-honest{grid-template-columns:.9fr 1.1fr} }
.pf-limits{display:grid;gap:18px}
.pf-limits article{padding-left:17px;border-left:2px solid var(--accent)}
.pf-limits h3{font-size:15px;margin:0 0 4px}
.pf-limits p{margin:0;font-size:14px;color:var(--muted);line-height:1.8}

/* ---- 方案 ---- */
.pf-plans{display:grid;gap:14px;grid-template-columns:1fr;align-items:start}
@media(min-width:900px){ .pf-plans{grid-template-columns:.9fr 1.1fr} }
.pf-plan{border:1px solid var(--line);border-radius:var(--r-card);
  padding:clamp(24px,3vw,38px);background:var(--bg-soft)}
.pf-plan.is-pro{border-color:rgba(201,163,91,.4)}
.pf-plan h3{font-size:17px;margin:0 0 6px}
.pf-price{display:flex;align-items:baseline;gap:10px;margin:16px 0 20px}
.pf-price b{font-family:var(--font-display);font-weight:400;letter-spacing:-.02em;
  font-size:clamp(26px,3.4vw,38px);line-height:1;color:var(--accent)}
.pf-price b.pf-soon{color:var(--muted);font-size:clamp(18px,2.2vw,24px)}
.pf-price del,.pf-price s{color:var(--muted);font-size:15px}
.pf-price ins{text-decoration:none}
.pf-plan>.store-cta-buy{display:inline-flex;justify-content:center;width:100%}
.pf-dl{display:grid;gap:10px}
.pf-dl .ghost-btn{width:100%;gap:10px}
.pf-dl .ghost-btn small{color:var(--muted);font-size:12px}
.pf-dl-note{margin:12px 0 0;font-size:13px;color:var(--muted);line-height:1.8}
.pf-dl-note a{color:var(--accent)}
.pf-plan ul{margin-top:24px;padding-top:20px;border-top:1px solid var(--line);display:grid;gap:11px}
.pf-plan li{font-size:15px;display:grid;grid-template-columns:auto 1fr;gap:11px;
  align-items:start;color:var(--pf-ink-2);line-height:1.6}
.pf-plan li .pf-i{width:16px;height:16px;color:var(--accent);margin-top:3px}
.pf-plan li.is-off{color:var(--muted)}
.pf-plan li.is-off .pf-i{color:#4a4a52}

/* ---- 常見問題 ---- */
.pf-faq{border-top:1px solid var(--line);max-width:820px}
.pf-faq details{border-bottom:1px solid var(--line)}
.pf-faq summary{cursor:pointer;list-style:none;padding:20px 44px 20px 0;position:relative;
  font-size:16px;line-height:1.6}
.pf-faq summary::-webkit-details-marker{display:none}
.pf-faq summary::after{content:"";position:absolute;right:8px;top:30px;width:10px;height:10px;
  border-right:1.5px solid var(--muted);border-bottom:1.5px solid var(--muted);
  transform:rotate(45deg);transition:transform .22s var(--ease)}
.pf-faq details[open] summary::after{transform:rotate(-135deg);top:32px}
.pf-faq p{margin:0;padding:0 0 22px;font-size:15px;color:var(--pf-ink-2);
  max-width:640px;line-height:1.9}

/* ---- 結尾 ---- */
.pf-end{border-top:1px solid var(--line)}
.pf-fine{margin:28px 0 0;font-size:13px;color:var(--muted);line-height:1.9}
.pf-fine a{color:var(--accent)}

/* 自訂游標：這一頁多出來的可點元素也要吃到 cursor:none，
   否則會同時出現系統游標與圓點。 */
html.cv-cursor .pf a,html.cv-cursor .pf summary{cursor:none}

/* 商店頁：指向產品頁的那一條連結。金色底線，跟站上其他「這裡可以點」
   的訊號一致；不做成按鈕，因為它不是購買行為。 */
.store-more{margin:14px 0 0;font-size:14px}
.store-more a{color:var(--accent);border-bottom:1px solid rgba(201,163,91,.4);padding-bottom:2px;
  transition:border-color .3s var(--ease)}
.store-more a:hover{border-color:var(--accent)}

/* 頁首的購物車入口。只在車裡有東西時輸出（見 header.php），
   所以這裡不需要處理「數字是 0」的狀態。 */
.site-cart{display:inline-flex;align-items:center;gap:7px;
  min-height:44px;min-width:44px;justify-content:center;
  padding:0 12px;border:1px solid var(--line);border-radius:var(--r-pill);
  font-size:13px;color:var(--ink);letter-spacing:.04em;
  transition:color .3s var(--ease),border-color .3s var(--ease)}
.site-cart:hover,.site-cart:focus-visible{color:var(--accent);border-color:var(--accent)}
.site-cart svg{flex:none}
@media(max-width:760px){ .site-cart{margin-left:auto;margin-right:8px} }

/* 商店頁底部的條款連結。刻意小、刻意灰：它們要找得到，但不該跟購買按鈕搶。 */
.store-legal{margin:16px 0 0;font-size:13px;color:var(--muted)}
.store-legal a{color:var(--muted);border-bottom:1px solid transparent;padding-bottom:1px;
  transition:color .3s var(--ease),border-color .3s var(--ease)}
.store-legal a:hover{color:var(--accent);border-color:var(--accent)}

/* ---------- 沉浸閱讀（作品跨頁式，1.46.0） ----------

   跨頁式已經把一件作品切成一頁一屏，但畫面上仍然有一整條頁首、
   一排導覽連結、一個頁尾。看一件作品的時候，那些東西沒有一個是你要的。

   這一層做的事只有一件：讓介面在你開始看的時候退場，在你需要的時候回來。
   規則刻意寫得很保守——會自己消失的介面若猜錯時機，比不會消失更煩人：
     ‧ 只在真正進到內文（離開 hero）之後才隱藏，第一屏永遠看得到導覽。
     ‧ 往上捲、把游標移到畫面頂端、按 Tab、或在觸控上點一下，介面立刻回來。
     ‧ prefers-reduced-motion 時不做位移，只做透明度。
     ‧ 沒有 JavaScript 時整層不存在，頁面完全照舊。 */

#site-header{transition:opacity .4s var(--ease), transform .4s var(--ease)}
html.sw-immersive #site-header{opacity:0;transform:translateY(-102%);pointer-events:none}
html.sw-immersive .site-footer,
html.sw-immersive .sw-more,
html.sw-immersive .sw-adjacent{opacity:.28;transition:opacity .5s var(--ease)}

/* 進度條：讀到哪裡。做成 2px 的一條線而不是百分比數字——
   這是餘光要能接收的資訊，不是要人去讀的。 */
.sw-progress{position:fixed;top:0;left:0;right:0;height:2px;z-index:var(--z-rail);
  background:var(--accent);transform:scaleX(var(--sw-p,0));transform-origin:0 50%;
  opacity:.75;pointer-events:none;transition:transform .1s linear}

/* 頁碼：跟指示點是兩件事。點是「可以按的導覽」，頁碼是「我在哪」，
   在手機上點被隱藏，頁碼仍然留著。 */
.sw-count{position:fixed;left:var(--pad);bottom:calc(20px + env(safe-area-inset-bottom));
  z-index:var(--z-rail);font-family:var(--font-display);font-size:12px;letter-spacing:.18em;
  color:var(--muted);pointer-events:none;font-variant-numeric:tabular-nums;
  opacity:0;transition:opacity .4s var(--ease)}
html.sw-immersive .sw-count{opacity:1}
.sw-count b{color:var(--ink);font-weight:400}

/* 文字比影像晚一步進場。
   一頁裡真正的主角是照片；文字同時出現會搶第一眼。
   延遲不是為了裝飾，是為了決定看的順序。

   整組規則都掛在 html.has-spread 底下，而那個 class 是前台腳本加的。
   沒有 JavaScript 時這一段完全不生效——否則 .is-read 永遠不會被加上，
   所有說明文字會是隱形的。會動的效果一定要用「有沒有能力執行」當開關，
   不能預設它一定跑得起來。 */
html.has-spread .sw-page .sw-page-in > :is(p,ul,ol,blockquote,h2,h3,figcaption){
  opacity:0;transform:translateY(10px);
  transition:opacity .7s var(--ease) .25s, transform .7s var(--ease) .25s}
html.has-spread .sw-page.is-read .sw-page-in > :is(p,ul,ol,blockquote,h2,h3,figcaption){
  opacity:1;transform:none}

@media (prefers-reduced-motion:reduce){
  html.sw-immersive #site-header{transform:none}
  .sw-progress{transition:none}
  html.has-spread .sw-page .sw-page-in > :is(p,ul,ol,blockquote,h2,h3,figcaption){
    opacity:1;transform:none;transition:none}
}

/* ---------- 燈箱：縮放與平移（1.47.0） ----------

   .lb-stage 是腳本在開啟燈箱時包上去的裁切框。
   為什麼不直接在 .lb-img-wrap 上 overflow:hidden：那一層是直向 flex，
   裡面除了圖還有說明與購買鈕，放大的圖會蓋掉下面那些東西。
   transform 不影響版面，所以舞台的尺寸仍然等於原本那張圖的顯示尺寸，
   放大只發生在裁切框裡面。 */
.lb-stage{overflow:hidden;line-height:0;border-radius:var(--r-img);
  touch-action:none;                 /* 雙指要留給縮放，不要讓瀏覽器先拿去捲頁 */
  cursor:zoom-in}
.lb-stage.is-zoomed{cursor:grab}
.lb-stage.is-zoomed:active{cursor:grabbing}
.lb-stage img{transform-origin:0 0;will-change:transform;
  -webkit-user-select:none;user-select:none;-webkit-user-drag:none}

/* 放大狀態下，左右翻頁鈕會擋在照片上而且此時方向鍵已改成平移，
   留著只會讓人以為壞了。關閉鈕與說明維持原樣，那是逃生門。 */
.lb.is-zoomed .lb-nav{opacity:0;pointer-events:none}

@media (prefers-reduced-motion:reduce){
  .lb-stage img{will-change:auto}
}

/* ---------- 游標樣式（1.48.0） ----------

   四種樣式共用同一組 DOM（.cursor-dot 與 .cursor-ring），
   靠 <html data-cursor="..."> 切換外觀。不另外生元素的理由是
   四種都只是「一個點加一個圈」的變化，多做三份 DOM 只會多三份要維護的狀態。

   一般（system）那一項不只是把兩個元素藏起來——JS 也不會加 cv-cursor，
   所以原生游標會保留。只藏元素的話，畫面上會變成完全沒有游標。 */
:root{--cv-cursor-k:1}
.cursor-dot{width:calc(6px * var(--cv-cursor-k,1));height:calc(6px * var(--cv-cursor-k,1))}
.cursor-ring{width:calc(38px * var(--cv-cursor-k,1));height:calc(38px * var(--cv-cursor-k,1))}
.cursor-ring.hover{width:calc(64px * var(--cv-cursor-k,1));height:calc(64px * var(--cv-cursor-k,1))}

/* 只有圓環：把中心那一點收掉，讓圈自己說話。 */
html[data-cursor="ring"] .cursor-dot{opacity:0}

/* 對焦準星：中心是一個十字，外圈是一個細環。
   這是四種裡唯一有「攝影」語意的一種——它跟封面那支鏡頭動畫是同一個字彙。 */
html[data-cursor="reticle"] .cursor-dot{
  width:calc(14px * var(--cv-cursor-k,1));height:calc(14px * var(--cv-cursor-k,1));
  background:none;border-radius:0;
  background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);
  background-size:100% 1px,1px 100%;
  background-position:center center,center center;
  background-repeat:no-repeat}
html[data-cursor="reticle"] .cursor-ring{
  width:calc(30px * var(--cv-cursor-k,1));height:calc(30px * var(--cv-cursor-k,1));
  border-width:1px}
html[data-cursor="reticle"] .cursor-ring.hover{
  width:calc(52px * var(--cv-cursor-k,1));height:calc(52px * var(--cv-cursor-k,1))}

/* 系統游標：兩個元素完全不出現（JS 也不會接管，原生游標留著）。 */
html[data-cursor="system"] .cursor-dot,
html[data-cursor="system"] .cursor-ring{display:none}

/* ---------- 作品影像的襯底（1.48.0） ----------

   網站底色是 #0b0b0d，一般的黑色陰影打在上面等於看不見。
   所以預設是「光暈」：一圈很淡的暖白，像光從照片邊緣滲出來。
   用 drop-shadow 而不是 box-shadow，因為它跟著影像的實際形狀走
   （之後若有去背 PNG 或非矩形的圖也不會出錯）。

   兩層疊起來：一層小而緊貼邊緣負責「浮起來」，
   一層大而淡負責讓它跟背景之間有空氣。單層做不出這個層次，
   只會像貼了一圈白框。 */
:root{--cv-imgfx:.55}

html[data-imgfx="glow"] .sw-page-in :is(figure,.wp-block-image) img,
html[data-imgfx="glow"] .lb-stage img{
  filter:drop-shadow(0 0 1px rgba(255,250,240,calc(.22 * var(--cv-imgfx,.55))))
         drop-shadow(0 0 42px rgba(255,246,232,calc(.30 * var(--cv-imgfx,.55))))}

/* 陰影：深黑加上大範圍擴散，並且往下偏移。
   在偏亮的照片下才看得出來，暗照片上幾乎沒有作用——這是物理上的必然，
   不是設定壞掉，所以說明文字有寫清楚。 */
html[data-imgfx="shadow"] .sw-page-in :is(figure,.wp-block-image) img,
html[data-imgfx="shadow"] .lb-stage img{
  filter:drop-shadow(0 10px 26px rgba(0,0,0,calc(.55 * var(--cv-imgfx,.55))))
         drop-shadow(0 30px 60px rgba(0,0,0,calc(.40 * var(--cv-imgfx,.55))))}

/* 放大中的燈箱不套襯底：drop-shadow 會跟著 transform 一起被放大，
   6× 時那一圈光會變成一片糊，而且每一格都要重算濾鏡，很貴。 */
.lb.is-zoomed .lb-stage img{filter:none}

/* ---------- 跨頁式的吸附強度（1.48.0） ---------- */
html.has-spread[data-snap="off"]{scroll-snap-type:none}
html.has-spread[data-snap="soft"]{scroll-snap-type:y proximity}
html.has-spread[data-snap="strong"]{scroll-snap-type:y mandatory}
/* 比視窗還高的頁面一律退出吸附。
   這是「強」這個選項能存在的前提：mandatory 碰到高於視窗的區塊時，
   捲動會被強制拉回該區塊的起點，讀者永遠看不到它的下半。
   高度由前台腳本量，量到超過就加上這個 class。 */
.sw-page.is-tall{scroll-snap-align:none}
@media (prefers-reduced-motion:reduce){
  html.has-spread[data-snap="strong"]{scroll-snap-type:y proximity}
}

/* ---------- 跨頁式：收尾頁與外掛區塊的收斂（1.49.0） ----------

   收尾頁（作品介紹被移到最後那一頁）。它不是照片頁，所以不套照片頁那一套
   高度限制；改成寬鬆的排版，讓「看完了」這件事有一個停下來的地方。 */
.sw-page.is-end{align-items:center}
.sw-page.is-end .sw-page-in{max-width:1000px;text-align:left}
.sw-page.is-end .cw-info{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);
  gap:clamp(28px,5vw,72px);align-items:start}
.sw-page.is-end .cw-title{font-family:var(--font-display);font-weight:300;
  font-size:clamp(24px,3.4vw,40px);letter-spacing:.04em;margin:0 0 22px}
.sw-page.is-end .cw-meta{margin:0}
.sw-page.is-end .cw-row{padding:11px 0;border-bottom:1px solid var(--line)}
.sw-page.is-end .cw-desc{color:var(--ink-2);line-height:1.9;max-width:560px}
@media(max-width:760px){
  .sw-page.is-end .cw-info{grid-template-columns:1fr;gap:26px}
}

/* 章節對開在跨頁式下最多兩欄（1.49.0）。
   這個區塊自己支援三張並排，在一般的連續版面上沒問題——讀者會往下捲，
   一排三張只是節奏快一點。但在跨頁式下，那三張要一起塞進一個螢幕，
   每一張都變成原本的三分之一，跟「一屏就是這張照片」正好相反。

   收斂成兩欄，第三張換行到下一列。刻意**不**把它藏起來：
   少給讀者一張照片，比讓那一頁高過視窗更糟。
   而那一頁真的變高的時候，.is-tall 的保險會讓它退出吸附，
   讀者照樣捲得到——兩個機制在這裡剛好接得上。

   只在 .sw-page 裡面收斂，區塊本身的能力不動：同一個區塊放在
   Journal 或一般頁面上，三欄仍然是三欄。 */
.sw-page .cchap-pair[data-count="3"]{grid-template-columns:repeat(2,minmax(0,1fr))}
@media(max-width:760px){
  .sw-page .cchap-pair[data-count="2"],
  .sw-page .cchap-pair[data-count="3"]{grid-template-columns:minmax(0,1fr)}
}

/* 作品影像區塊在跨頁式裡的高度預算（1.49.0）。

   .cvf 自己用 --cvf-room 算「除了照片以外的東西佔掉多少高度」，
   但只有 .sw-page 知道這一頁到底有沒有文字——那個判斷在伺服器端
   就做好了（has-text）。這裡把答案交給區塊。

   數字要跟上面那條給一般圖片的 max-height 對得起來（1.52.0 修正）。
   原本寫 60px／130px，比實際少算了約 49px：漏掉的是頁首讓出的 64px
   有一部分沒被算進去、以及區塊自己的說明與它上面那道 gap。
   後果不是「照片矮一點」而是**整頁高過視窗**——高過視窗的頁面會被
   .is-tall 踢出吸附，於是每一張照片頁都沒有磁吸感。實測 900px 的視窗
   量到 952px，四頁裡有三頁被踢掉。

   拆開來看：頁首 64px ＋ 上下留白（--sw-gap × 2）
            ＋ 圖說 46px（實測 31px，留 46px）
            ＋ 另有一段文字時再 76px（實測 46px，兩行 76px）
   說明壓在角落或不顯示時它不佔高度，那 46px 要還給照片——
   一張照片頁的高度預算差 46px 是看得出來的。 */
.sw-page .cvf{--cvf-room:calc(110px + var(--sw-gap, 32px) * 2)}
.sw-page.has-text .cvf{--cvf-room:calc(186px + var(--sw-gap, 32px) * 2)}
.sw-page .cvf:is(.cvf-cap-none,.cvf-cap-bl,.cvf-cap-br){
  --cvf-room:calc(64px + var(--sw-gap, 32px) * 2)}
.sw-page.has-text .cvf:is(.cvf-cap-none,.cvf-cap-bl,.cvf-cap-br){
  --cvf-room:calc(140px + var(--sw-gap, 32px) * 2)}
/* 滿版出血要真的滿版：連頁面本身的左右留白也要吃掉。

   ---- 1.67.1：跟著外掛一起只在視窗全展開時成立 ----
   外掛（chaovisual-gallery 1.18.1）把「滿版出血」整組規則包進 min-width:1200px，
   1200px 以下照片自動變回完整顯示。這三條是**主題這一側**的配套：
   它們負責把頁面本身的左右留白吃掉。少了同一個門檻，窄視窗會出現
   「照片已經縮回置中留白、頁面卻還是零留白滿版」的錯位——
   照片浮在一片沒有邊界的黑裡，看起來像版面壞了。

   兩邊的門檻必須一致。改這裡就要改 assets/chaovisual-frame.css 那三處。 */
@media (min-width:1200px){
  .sw-page .cvf-fit-cover{width:100vw;margin-inline:calc(50% - 50vw)}
  .sw-page:has(.cvf-fit-cover) .sw-page-in{padding:0;max-width:none}
}
/* 上下的留白也要吃掉（1.53.1）。
   ─────────────────────────────────────────────────────────
   上面那條只清了 .sw-page-in 的 padding，但留白其實是掛在 .sw-page 上的
   （calc(--sw-gap + 64px) 上、--sw-gap 下）。滿版的照片本身就是 100svh，
   再加上那 150px，整頁就比視窗高 150px——**每一張滿版開場都因此退出吸附**，
   而且是最顯眼的那一張。實測 1263px 的視窗量到 1413px，剛好差一個 padding。

   滿版模式下沒有東西需要那圈留白：照片自己就是整個畫面。 */
@media (min-width:1200px){
  .sw-page:has(.cvf-fit-cover){padding:0}
}

/* ---------- 跨頁式：一頁兩張（1.50.0） ----------

   兩張並排。高度預算跟單張那一頁一樣（都是一整個螢幕），
   但每一張只分到一半的寬度，所以直式照片剛好把螢幕填滿——
   這正是「自動」模式只配對直式的原因。 */
/* 用 flex 不用 grid。
   兩欄等寬的 grid 會讓每張圖在自己那一欄裡置中，而圖的實際寬度是由
   高度上限反推出來的（直式圖被壓到滿高之後就比欄位窄）。結果是兩張圖
   中間多出一段跟設定無關的空隙，看起來不像一對，像兩張剛好放在一起的圖。
   flex 讓欄寬跟著圖走，間距就真的是 gap 那個數字。 */
.sw-page.is-duo .sw-duo{
  display:flex;justify-content:center;align-items:center;
  gap:clamp(10px,1.6vw,26px);width:100%}
.sw-page.is-duo .sw-duo > *{margin:0;min-width:0;flex:0 1 auto;
  max-width:calc(50% - clamp(10px,1.6vw,26px) / 2)}
/* 刻意不寫 img{width:100%}。
   跨頁式的圖片規則是 width:auto + max-height，靠高度上限反推寬度，
   比例才保得住。強制 width:100% 之後，寬度由欄位決定、高度由 max-height
   夾住，兩個都被外力指定，圖就被壓扁了（實測 1200×1600 的直式圖
   會被畫成 636×729，那不是 3:4）。這裡只限制外框的最大寬度，
   實際尺寸仍然由那條規則決定。 */
.sw-page.is-duo .sw-duo :is(figure,.wp-block-image){max-width:100%}

@media(max-width:760px){
  /* 手機改成上下排，而且**不**把高度砍半。
     兩張直式各分半個螢幕高，在手機上會小到看不出是什麼——
     這一頁因此高過視窗，1.48.0 的 .is-tall 保險會讓它退出吸附，
     讀者就一路捲過兩張。少給讀者一張照片比讓那一頁變高更糟，
     這跟章節對開收斂成兩欄時的取捨是同一個。

     （作品影像區塊的兩張模式相反，它在手機上會砍半高度：
     那個模式的用途是「對照」，看不到兩張就失去意義。
     兩種行為對應兩種意圖，不是不一致。） */
  .sw-page.is-duo .sw-duo{flex-direction:column;gap:18px}
  .sw-page.is-duo .sw-duo > *{max-width:100%}
}

/* ---------- 導覽列：滑過去換中文（1.51.0） ----------

   中文絕對定位疊在英文上，不參與版面寬度。
   「SERVICES」和「服務」的寬度差很多，若讓中文佔位，
   滑過去整排導覽會左右跳動——那比看不懂英文更煩人。 */
.nav-list a{display:inline-block}
.nav-list .nav-en{display:inline-block;
  transition:opacity .26s var(--ease),transform .26s var(--ease)}
.nav-list .nav-zh{position:absolute;left:50%;top:0;white-space:nowrap;pointer-events:none;
  transform:translateX(-50%) translateY(7px);opacity:0;color:var(--ink);
  letter-spacing:.16em;   /* 中文不靠字距撐氣質，比英文的 .14em 稍寬就夠 */
  transition:opacity .26s var(--ease),transform .26s var(--ease)}
.nav-list a:hover .nav-en,
.nav-list a:focus-visible .nav-en{opacity:0;transform:translateY(-7px)}
.nav-list a:hover .nav-zh,
.nav-list a:focus-visible .nav-zh{opacity:1;transform:translateX(-50%) translateY(0)}

/* 觸控裝置沒有 hover，中文永遠不會出現——那等於這個功能對手機不存在。
   改成兩個並排一起顯示：手機的導覽是展開的覆蓋層，本來就有橫向空間。 */
@media (hover:none){
  .nav-list .nav-zh{position:static;transform:none;opacity:.62;
    margin-left:10px;font-size:12px}
  .nav-list a:hover .nav-en{opacity:1;transform:none}
}
@media (prefers-reduced-motion:reduce){
  .nav-list .nav-en,.nav-list .nav-zh{transition:opacity .01s}
  .nav-list .nav-zh{transform:translateX(-50%)}
  .nav-list a:hover .nav-en{transform:none}
  .nav-list a:hover .nav-zh{transform:translateX(-50%)}
}

/* ---------- 標誌：讓人知道可以點（1.51.0） ----------

   頁首上每一個可點的東西都有 data-hover（自訂游標的圓環會放大），
   只有標誌漏了——那是「看起來不能點」最直接的原因，已在 header.php 補上。

   視覺上用跟導覽同一套語言：由左往右掃出來的一條金線。
   中間那個點跟著放大並發光——它本來就是標誌裡唯一的重音，
   把它當成一個會呼吸的光圈，比替整組字加效果安靜得多。
   點用 inline-block + transform，所以放大不會把後面的字推開。 */
.logo{position:relative;display:inline-block;transition:color .3s var(--ease)}
.logo::after{content:"";position:absolute;left:0;bottom:-7px;height:1px;width:0;
  background:var(--accent);transition:width .45s var(--ease)}
.logo:hover::after,
.logo:focus-visible::after{width:100%}
.logo span{display:inline-block;
  transition:transform .5s var(--ease),text-shadow .5s var(--ease)}
.logo:hover span,
.logo:focus-visible span{transform:scale(1.85);text-shadow:0 0 14px var(--accent)}
/* 焦點仍然給實際的外框。金線與放大的點是「可以點」的暗示，
   不是鍵盤焦點的指示——後者要在任何背景上都一眼看得到，
   而且要跟站上其他可聚焦元素長得一樣（同 .lb-buy、.cv-fab-btn）。 */
.logo:focus-visible{outline:2px solid var(--accent);outline-offset:4px;border-radius:2px}
@media (prefers-reduced-motion:reduce){
  .logo::after{transition:none}
  .logo span{transition:none}
  .logo:hover span{transform:none;text-shadow:0 0 14px var(--accent)}
}

/* ---------- 跨頁式：讓吸附「感覺得到」（1.52.0） ----------

   scroll-snap 本身沒有可以調的動畫。瀏覽器怎麼把畫面拉到吸附點是它自己
   決定的，CSS 沒有介面可以介入，所以「吸附動畫不明顯」不能從吸附下手。
   兩個能真正改變感受的地方：

   一、scroll-snap-stop:always —— 一次滑動只能走一頁。
   沒有它，用力一甩會連翻三四頁，中間那些頁面只是一閃而過，
   讀者感受到的是「滑得很順」，不是「一頁一頁停下來」。
   有了它，每一次動作都有一個明確的終點，那才是磁吸感的來源。
   只在「強」時開：這是接管使用者捲動幅度的行為，不該是預設。 */
html.has-spread[data-snap="strong"] .sw-page{scroll-snap-stop:always}
html.has-spread[data-snap="strong"] .sw-hero{scroll-snap-stop:always}

/* 二、落定動畫 —— 停下來的那一刻給一個收束的回饋。
   放大 1.8% 收回原尺寸、透明度補滿，480ms。幅度刻意小：
   這是「我到站了」的訊號，不是轉場特效；做大了每翻一頁都在跳。
   只在有吸附時播放，自由捲動時翻頁本來就沒有「一頁」的概念。 */
@keyframes sw-land{
  from{transform:scale(1.018);opacity:.82}
  to{transform:none;opacity:1}
}
html.has-spread[data-snap="soft"] .sw-page.is-land .sw-page-in,
html.has-spread[data-snap="strong"] .sw-page.is-land .sw-page-in{
  animation:sw-land .48s cubic-bezier(.22,.61,.36,1) both}

@media (prefers-reduced-motion:reduce){
  html.has-spread .sw-page.is-land .sw-page-in{animation:none}
}

/* ---------- 跨頁式：捲動視差（1.55.0） ----------

   影像隨捲動緩緩位移，翻頁時多一層深度。

   **為什麼整段是 CSS 而不是 JS。** 這種效果最常見的寫法是監聽 scroll，
   算出進度再寫 transform。那在跨頁式上特別糟：這個版型本來就是一路捲到底，
   等於整趟瀏覽都在主執行緒上跑計算，而且捲動事件和實際上畫不同步，
   位移會慢半拍。scroll-driven animation 由合成器直接驅動，
   不佔主執行緒，也不會有落後一格的問題。

   **位移量是算出來的，不是喬出來的。** 照片放大 s 倍之後，上下各多出
   (s−1)/2 的餘裕；位移 p 實際移動的距離是 p×s（translate 在 scale 之後，
   吃的是放大後的座標）。要不露出邊，必須 (s−1)/2 ≥ p×s。
   s=1.06 時 p 最多 2.83%，所以「輕」取 2.5%，留一點餘裕給次像素。

   **兩種照片，兩種做法。** 這個站的照片分成兩類，不能一視同仁：

   ‧ 滿版出血（.cvf-fit-cover）與作品頁首：本來就是 object-fit:cover，
     照片已經被裁了，再位移不會失去任何原本看得到的東西。這兩種做真的視差。

   ‧ 其餘的頁面：object-fit:contain，「完整不裁切」正是跨頁式存在的理由，
     --cvf-room 那一整套高度預算就是為了這件事算的。這些頁面只做縮放收束
     ——永遠不放大超過 1，所以不可能裁到任何一邊。

   **停下來的時候一定是原位。** 兩組動畫都跑在 `entry exit`（等於整個
   cover 範圍）。頁高等於視窗高時，照片剛好填滿視窗的那一刻就是進度 50%，
   也就是位移 0、縮放 1。吸附停住的畫面永遠是照片的正位，
   動的只有「正在翻」的那段過程。 */
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {

	html[data-parallax="soft"]   { --sw-pz: 1.06; --sw-pt: 2.5%; --sw-psettle: .965; --sw-pdim: .88 }
	html[data-parallax="strong"] { --sw-pz: 1.12; --sw-pt: 5%;   --sw-psettle: .94;  --sw-pdim: .8 }

	@keyframes sw-parallax{
		from{transform:scale(var(--sw-pz)) translateY(calc(var(--sw-pt) * -1))}
		to{transform:scale(var(--sw-pz)) translateY(var(--sw-pt))}
	}

	/* 收束：中點（＝吸附停住的那一刻）是原尺寸、不透明；
	   進出畫面時略縮、略淡。縮放永遠 < 1，不會裁到照片。 */
	@keyframes sw-settle{
		from{transform:scale(var(--sw-psettle));opacity:var(--sw-pdim)}
		50%{transform:none;opacity:1}
		to{transform:scale(var(--sw-psettle));opacity:var(--sw-pdim)}
	}

	/* 一、會被裁的照片：真的位移。
	   overflow:clip 只切內容，不會建立捲動容器，
	   所以不會像 overflow:auto 那樣把 position:sticky 弄死。 */
	html[data-parallax="soft"] .cvf-fit-cover .cvf-cell,
	html[data-parallax="strong"] .cvf-fit-cover .cvf-cell{overflow:clip}

	html[data-parallax="soft"] .cvf-fit-cover .cvf-img,
	html[data-parallax="strong"] .cvf-fit-cover .cvf-img,
	html[data-parallax="soft"] .sw-hero-bg,
	html[data-parallax="strong"] .sw-hero-bg{
		animation:sw-parallax linear both;
		animation-timeline:view();
		animation-range:entry exit;
		will-change:transform}

	/* 二、完整顯示的照片：只收束，不位移。
	   :not(:has(.cvf-fit-cover)) 把滿版那幾頁排除掉，
	   它們已經在上面那條裡了，兩組動畫疊在同一個元素上會互相蓋掉。 */
	html[data-parallax="soft"] .sw-page:not(:has(.cvf-fit-cover)) :is(.cvf-img,.sw-page-in figure img,.sw-page-in .wp-block-image img),
	html[data-parallax="strong"] .sw-page:not(:has(.cvf-fit-cover)) :is(.cvf-img,.sw-page-in figure img,.sw-page-in .wp-block-image img){
		animation:sw-settle linear both;
		animation-timeline:view();
		animation-range:entry exit}

	/* 圖庫、章節對開、地點導覽這些整組的排版不參加：
	   它們一頁裡有很多張圖，每一張各自縮放會變成一片在呼吸的網格。 */
	html[data-parallax] .sw-page :is(.cg,.wp-block-gallery,.cchap,.kg) img{animation:none}
}
}

/* ---------- 指示點的縮圖預覽（1.52.0） ----------
   位置由腳本寫 top（跟著滑到的那顆點），右側距離交給 CSS，
   這樣改版面時不必回頭改 JavaScript。 */
.sw-peek{position:fixed;right:calc(var(--pad) / 2 + 26px);z-index:var(--z-peek);
  transform:translateY(-50%) translateX(8px);
  width:112px;pointer-events:none;opacity:0;
  transition:opacity .22s var(--ease),transform .22s var(--ease)}
.sw-peek.is-on.is-ready{opacity:1;transform:translateY(-50%) translateX(0)}
.sw-peek img{display:block;width:100%;height:auto;max-height:150px;object-fit:cover;
  border-radius:var(--r-img);border:1px solid rgba(255,255,255,.14);
  box-shadow:0 10px 30px rgba(0,0,0,.55)}
@media(max-width:760px){
  /* 指示點本身在 760px 以下就隱藏了（見 .sw-dots），預覽跟著沒有意義 */
  .sw-peek{display:none}
}
@media (prefers-reduced-motion:reduce){
  .sw-peek{transition:opacity .01s}
  .sw-peek.is-on.is-ready{transform:translateY(-50%)}
}

/* =========================================================
   導覽列：第二層（1.68.0）

   為什麼收成四項：原本七個項目並列，讀者要自己在腦子裡分組，
   而其中五個其實只講兩件事——「買東西的地方」與「這個人和他的工作」。
   收成 WORKS／STORE／JOURNAL／STUDIO 之後，第二層才有地方放。

   刻意不寫 JavaScript：桌機用 :hover 與 :focus-within（鍵盤 Tab 進去
   子選單就會展開，不需要另外攔 keydown），手機直接把子項目攤開成縮排清單。
   導覽是全站最不應該依賴腳本的東西——腳本沒載到，其他區塊壞掉只是可惜，
   導覽壞掉整個站就進不去了。
   ========================================================= */

.nav-list{align-items:center}
.nav-list li{position:relative}
.nav-list .sub-menu{list-style:none;margin:0;padding:0}

@media(min-width:761px){
  /* 有子選單的項目要看得出來有子選單。用一個小箭頭，不是圖示字型。 */
  .nav-list > li.menu-item-has-children > a{padding-right:15px}
  .nav-list > li.menu-item-has-children > a::before{
    content:"";position:absolute;right:1px;top:50%;width:4px;height:4px;
    border-right:1px solid currentColor;border-bottom:1px solid currentColor;
    transform:translateY(-75%) rotate(45deg);opacity:.5;
    transition:opacity .3s var(--ease),transform .3s var(--ease)}
  .nav-list > li.menu-item-has-children:hover > a::before,
  .nav-list > li.menu-item-has-children:focus-within > a::before{opacity:1}
  /* 底線是 ::after，展開時不要跟著跑滿——那會讓人以為自己已經在那一頁 */
  .nav-list > li.menu-item-has-children > a::after{right:15px}

  .nav-list > li > .sub-menu{
    position:absolute;top:100%;left:50%;
    transform:translate(-50%,6px);margin-top:16px;min-width:186px;
    background:rgba(11,11,13,.97);
    backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
    border:1px solid var(--line);border-radius:var(--r-card);
    padding:9px 0;text-align:left;
    box-shadow:0 18px 44px rgba(0,0,0,.45);
    opacity:0;visibility:hidden;pointer-events:none;
    transition:opacity .26s var(--ease),transform .26s var(--ease),visibility .26s;
    z-index:var(--z-nav-close)}

  /* 滑鼠從父項移到子選單，中間會經過 16px 的空白。沒有這條隱形的橋，
     選單會在半路關掉——那是下拉式選單最常見、也最惱人的壞法。 */
  .nav-list > li > .sub-menu::before{
    content:"";position:absolute;left:0;right:0;top:-17px;height:17px}

  .nav-list > li:hover > .sub-menu,
  .nav-list > li:focus-within > .sub-menu{
    opacity:1;visibility:visible;pointer-events:auto;transform:translate(-50%,0)}

  .nav-list .sub-menu a{display:block;padding:9px 20px;white-space:nowrap;
    font-size:12px;letter-spacing:.1em;color:rgba(244,244,242,.7);
    transition:color .25s var(--ease),background-color .25s var(--ease)}
  .nav-list .sub-menu a::after{display:none}   /* 底線是給第一層的 */
  .nav-list .sub-menu a:hover,
  .nav-list .sub-menu a:focus-visible{color:var(--ink);background:rgba(255,255,255,.055)}
  .nav-list .sub-menu .current-menu-item > a,
  .nav-list .sub-menu a[aria-current]{color:var(--accent)}
}

@media(max-width:760px){
  /* 手機沒有 hover，摺疊起來就需要一顆展開鈕、一段腳本、一組 aria 狀態。
     這個站的第二層只有九個項目，全部攤開反而更快也更不會壞。 */
  .nav-list{gap:22px}
  .nav-list .sub-menu{display:flex;flex-direction:column;gap:13px;margin-top:14px}
  .nav-list .sub-menu a{font-size:14px;letter-spacing:.12em;
    color:rgba(244,244,242,.62);padding:4px 10px}
  .nav-list .sub-menu a::after{display:none}
  .nav-list .sub-menu .current-menu-item > a,
  .nav-list .sub-menu a[aria-current]{color:var(--accent)}
  /* 第二層的中文對照沒有意義（子項目本來就是中文），把它關掉 */
  .nav-list .sub-menu .nav-zh{display:none}
}

/* ---------- 商店頁：照片輸出的入口（1.68.0） ----------
   放在三條產品線之前，因為它是這個站唯一的實體商品，
   也是最多人是為了它才點進商店的東西。 */
.store-prints{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:38px;
  align-items:center;margin:56px 0 0;padding:32px;
  background:var(--bg-soft);border:1px solid var(--line);border-radius:var(--r-card)}
.store-prints h2{margin:10px 0 0;font-family:var(--font-display);font-size:clamp(20px,2.4vw,26px);
  letter-spacing:.04em;line-height:1.5;color:var(--ink)}
.store-prints-lead{margin:14px 0 0;font-size:15px;line-height:2.05;color:var(--ink-3)}
.store-prints-act{display:flex;flex-wrap:wrap;align-items:center;gap:18px;margin:22px 0 0}
.store-prints-alt{font-size:13px;letter-spacing:.06em;color:var(--ink-3)}
.store-prints-alt:hover{color:var(--accent)}
.store-prints-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
.store-prints-grid a{display:block;overflow:hidden;border-radius:var(--r-img);background:#141416}
.store-prints-grid img{display:block;width:100%;height:auto;aspect-ratio:1/1;object-fit:cover;
  opacity:.86;transition:transform .6s var(--ease),opacity .35s var(--ease)}
.store-prints-grid a:hover img{transform:scale(1.04);opacity:1}

@media(max-width:820px){
  .store-prints{grid-template-columns:1fr;gap:26px;padding:24px}
  .store-prints-grid{grid-template-columns:repeat(4,1fr)}
}
@media(max-width:480px){
  .store-prints-grid{grid-template-columns:repeat(2,1fr)}
}

/* ---------- 手機版第二層：收合（1.68.1） ----------

   1.68.0 在手機上把子項目全部攤開，是拿 390 × 844 的模擬視窗量出來的：
   13 個項目佔 699px、容器 840px，剛好塞得下就當成過關。
   實機在 Instagram 內建瀏覽器裡上下各被 App 工具列吃掉一截，於是撐破，
   最上面和最下面的項目都被切掉。

   手機的可用高度不等於裝置高度。用剛好塞得下的版面去賭，一定會輸。

   按鈕由 chaovisual.js 注入，所以整段用 html.js 當閘門：
   沒有 JavaScript 時按鈕不存在，子選單維持全部展開，
   而不是留一顆按不動的箭頭。 */
.nav-sub-toggle{display:none}

@media(max-width:760px){
  /* 父項變成一行：標題 ＋ 箭頭；子選單靠 flex-basis 另起一列 */
  html.js .nav-list > li.menu-item-has-children{
    display:flex;flex-wrap:wrap;align-items:center;justify-content:center}
  html.js .nav-list > li.menu-item-has-children > .sub-menu{flex:0 0 100%}

  /* 命中框 44×44，與 .nav-toggle、.footer-social a 同一個標準 */
  html.js .nav-sub-toggle{
    display:inline-flex;align-items:center;justify-content:center;
    min-width:44px;min-height:44px;padding:0;margin-left:2px;
    background:none;border:none;cursor:pointer;
    color:rgba(244,244,242,.62);
    -webkit-tap-highlight-color:transparent}
  html.js .nav-sub-toggle:focus-visible{
    outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--r-card)}
  .nav-sub-chev{display:block;width:7px;height:7px;
    border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
    transform:translateY(-2px) rotate(45deg);
    transition:transform .3s var(--ease)}
  html.js .nav-list > li.is-open > .nav-sub-toggle{color:var(--accent)}
  html.js .nav-list > li.is-open > .nav-sub-toggle .nav-sub-chev{
    transform:translateY(2px) rotate(-135deg)}

  html.js .nav-list > li.menu-item-has-children > .sub-menu{
    max-height:0;margin-top:0;opacity:0;overflow:hidden;
    transition:max-height .38s var(--ease),opacity .26s var(--ease),margin-top .38s var(--ease)}
  html.js .nav-list > li.is-open > .sub-menu{max-height:320px;margin-top:14px;opacity:1}

  /* 內容比容器高的時候，align-items:center 會把上緣切掉，而且捲不回去。
     safe center 在放不下時自動退回貼齊起點；不認得它的瀏覽器會忽略整條，
     維持上面那條 center。收合之後幾乎不會再撐破，這條是保險。 */
  .primary-nav{align-items:safe center}
}

@media (prefers-reduced-motion:reduce){
  .nav-sub-chev,
  html.js .nav-list > li.menu-item-has-children > .sub-menu{transition-duration:.01s}
}

/* ===== 首頁 HERO 背景輪替（1.71.0） ===== */
.hero-rot{position:absolute;inset:0;z-index:0}
.hero-photo .hero-rot-img{position:absolute;inset:0;opacity:0;transition:opacity var(--hero-rot-fade,180ms) linear}
.hero-photo .hero-rot-img.is-on{opacity:1}
/* 原本那張 LCP 照片先撐場面，輪替備妥後再交棒 */
.hero-photo>picture img{transition:opacity 240ms linear}
.hero-photo.has-rot>picture img{opacity:0}
@media (prefers-reduced-motion:reduce){
  .hero-photo .hero-rot-img{transition:none}
  .hero-photo>picture img{transition:none}
}
