/* ==========================================================================
   SPOUT DESIGN — 官網視覺系統
   ========================================================================== */

@font-face {
  font-family: 'DFLiSong';
  src: url('../fonts/DFLiSongStd-W3.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'DFLiSong';
  src: url('../fonts/DFLiSongStd-W5.woff2') format('woff2');
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: 'DFLiSong';
  src: url('../fonts/DFLiSongStd-W7.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
}

/* Bodoni Moda（英文字體）——2026-09-28 起改為主題內自架，不再走 Google Fonts CDN。
   來源與授權見 fonts/bodoni-moda/README.txt、OFL.txt。可變字體：wght 400–900、含 opsz 光學尺寸軸；
   unicode-range 沿用 Google Fonts 原本的 latin／latin-ext 分割，瀏覽器只下載用得到的子集。 */
@font-face {
  font-family: 'Bodoni Moda';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('../fonts/bodoni-moda/bodoni-moda-latin-ext-opsz-normal.woff2') format('woff2');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: 'Bodoni Moda';
  font-style: italic;
  font-weight: 400 900;
  font-display: swap;
  src: url('../fonts/bodoni-moda/bodoni-moda-latin-ext-opsz-italic.woff2') format('woff2');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: 'Bodoni Moda';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('../fonts/bodoni-moda/bodoni-moda-latin-opsz-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: 'Bodoni Moda';
  font-style: italic;
  font-weight: 400 900;
  font-display: swap;
  src: url('../fonts/bodoni-moda/bodoni-moda-latin-opsz-italic.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

:root {
  /* 全站區塊左右內距的單一來源。原本只定義在 .section 這個 class
     上，2026-09-26 發現這個做法有一個隱藏限制：CSS 自訂屬性只會
     繼承給「該規則所在元素的子孫」，任何不在 .section 底下的元素
     完全讀不到值（例如 .site-header／.nav-trigger／.fan-menu--social
     這些獨立掛在 <body> 底下、不屬於任何 .section 的元素），套用
     var(--section-side-padding) 會直接失效、悄悄退回瀏覽器預設值，
     不會報錯也看不出來，這輪修 Header／漢堡選單對齊時才踩到。
     改成定義在 :root，全站任何元素都能穩定繼承到同一個值，各斷點
     只需要覆蓋這裡一處，.section 的 padding 跟其他所有用到這個
     變數的地方會自動同步 */
  --section-side-padding: var(--space-12);
}
:root {
  /* ---- 色彩系統 ----
     2026-08-28 重新定義：業主指出 --ink 從 #000000 改成 #505050
     後，中間 8 階灰階仍是照著舊端點（white→#000000）內插算出來的
     舊值，導致 --grey-900(#505050) 反而比 --grey-800(#333333) 亮，
     出現「數字越大顏色越淺」的矛盾，不符合灰階遞增/遞減的基本邏輯。
     重新內插原則：
     1. 頭尾端點改成 white(#ffffff) → ink(#505050)，取代舊的
        white → #000000 端點，讓整條刻度跟目前的 --ink 定義一致。
     2. --grey-300（品牌灰 Brand Grey #c9caca）業主明確要求維持
        原值不動，這是設計稿定案的品牌色，不隨這次內插改變。
     3. 因為 --grey-300 要固定住、不能被公式蓋掉，改採兩段內插：
        white → grey-300 分 4 階（50/100/200/300），
        grey-300 → ink 分 7 階（300/400/500/600/700/800/900/ink，
        counting 300 為共用起點），確保 --grey-300 精準等於
        #c9caca，同時前後兩段各自都是均勻等距漸層，不會在中間
        出現轉折感。
     這組新數值業主已用色票對照圖確認過，全站遞減嚴格單調，
     不再有 900 比 800 亮的矛盾。 */
  --grey-50:  #f2f2f2;
  --grey-100: #e4e4e4;
  --grey-200: #d6d7d7;
  --grey-300: #c9caca;  /* 品牌灰 Brand Grey，業主要求維持原值不隨內插改變 */
  --grey-400: #b8b9b9;
  --grey-500: #a6a7a7;
  --grey-600: #959696;
  --grey-700: #848484;
  --grey-800: #737373;
  --grey-900: #616161;
  --ink:   #505050;     /* 業主 2026-08-24 要求：原純黑 #000000 全站改成 #505050，其餘色票不變。這也是新灰階刻度的終點 */
  --white: #ffffff;     /* 純白，新灰階刻度的起點 */
  --placeholder: var(--grey-300);    /* Logo / 徽章 / icon 替代色塊 */

  /* ---- 字級系統（10 階，16px 為內文基準） ---- */
  --text-14: 14px;
  --text-16: 16px;  /* base */
  --text-18: 18px;
  --text-20: 20px;
  --text-22: 22px;
  --text-24: 24px;
  --text-26: 26px;
  --text-28: 28px;
  --text-30: 30px;
  --text-32: 32px;

  /* ---- 字距（先歸零，日後需要再套用 utility class） ---- */
  /* ---- 字距系統 ----
     CSS letter-spacing 只能吃 em/px 等單位，沒有「Illustrator
     tracking 值」這種格式可以直接輸入，但兩者是固定的線性換算
     關係：CSS em 值 × 1000 = Illustrator 字元面板的 Tracking 值
     （Illustrator 的 Tracking 本來就是以 1/1000 em 為單位）。
     業主是平面設計背景、習慣用 Illustrator 字元面板的 Tracking
     數值溝通字距，這裡直接把對應的 Illustrator 數值標在註解裡，
     方便業主跟工程端對話時直接對照，不需要每次都心算換算。 */
  --tracking-0: 0em;        /* Illustrator Tracking: 0 */
  --tracking-xs: 0.1em;     /* Illustrator Tracking: 100 */
  --tracking-tight: 0.2em;  /* Illustrator Tracking: 200 */
  /* 2026-08-24：--tracking-wide (0.4em / Illustrator 400) 全站
     沒有任何元素實際使用，業主要求先移除，之後有需要再重新建立 */

  /* ---- 行高（4 階，1–2 倍區間） ---- */
  --leading-1: 1.2;   /* 標題／緊 */
  --leading-2: 1.5;   /* 內文預設 */
  --leading-3: 1.75;  /* 舒展內文 */
  --leading-4: 2;     /* 長文/寬鬆段落 */

  /* ---- 間距系統（10 階，4px 基準） ---- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --space-16: 64px;
  --space-24: 96px;
  --space-32: 128px;

  /* ---- 水波紋線條系統：隨螢幕寬度連續縮放 ----
     Hero 水波紋（canvas，main.js initRippleCanvas 讀取本變數的計算值）
     與硬幣觸水波紋（.splash-ripple，SVG）兩處共用同一個線寬 token --stroke-water，
     統一在這裡調整，不用兩處分別改。
     （2026-09-20：原本還有第三處「回彈水柱 .splash-column」與它專用的
     --stroke-water-thin，水柱改成填色的半調圓點水花後不再有描邊，
     該變數已刪除，業主同意。）
     原本三處都是寫死的固定 px（5 / 5 / 4），搭配
     vector-effect: non-scaling-stroke（讓線條粗細不受 SVG
     縮放影響），這在桌機沒問題，但小螢幕上 viewBox 整體視覺
     縮小、線條粗細沒有跟著等比例縮小，導致小裝置上線條「相對
     畫面比例」顯得過粗。
     改用 clamp(最小值, 隨螢幕寬度浮動的中間值, 最大值)，讓線寬
     隨螢幕寬度連續、流暢地縮放，不會有斷點切換造成的視覺跳動
     （水波紋是很細膩的線條動畫，斷點式的粗細突變會很明顯、
     顯得廉價，連續縮放才符合這個動畫本身的質感）。
     中間值用 vw（視窗寬度百分比）而非 vh，因為線條粗細應該
     跟隨版面的「水平方向」尺寸感縮放，這跟大部分 RWD 排版的
     直覺一致。--stroke-water 是主要水波紋／觸水波紋用的寬度 */
  /* 2026-09-07：業主指定線條粗細改為絕對值 2px。--stroke-water
     是背景水波紋跟硬幣觸水水花共用的 token，業主確認兩者要連動，
     不要分開設定 */
  --stroke-water: clamp(1.6px, 0.4vw, 2px);

  /* ---- 圓角系統（4 階） ---- */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 16px;
  --radius-full: 999px;

  /* ---- 版面容器 ---- */
  --container-max: 1240px;

  /* ---- 圖示系統（3 階） ---- */
  --icon-sm: 16px;   /* 行內小圖示、表單符號 */
  --icon-md: 24px;   /* 導覽/按鈕圖示（例：水滴選單圖示） */
  --icon-lg: 34px;   /* 強調用圖示（例：footer 社群圖示） */

  /* ---- 元件狀態 ---- */
  --state-hover-opacity: 0.75;
  --state-disabled-opacity: 0.4;
  --focus-ring: 2px solid var(--ink);
  --focus-ring-offset: 3px;

  /* ---- 字體 ---- */
  --font-cn: 'DFLiSong', 'Noto Serif TC', serif;
  --font-en: 'Bodoni Moda', 'DFLiSong', serif;

  /* ---- 節奏 ---- */
  --ease-water: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* ---- 導覽色系（依 JS 偵測目前疊在哪個區塊上，動態切換） ----
     hover：互動時的強調色（滿色黑／白）
     muted：扇形選單文字預設色（未 hover 前的淡化狀態）
     預設值＝淺色背景版本。
     ⚠️ 2026-09-08 死碼清理記錄：這裡原本還提到「JS 會在偵測到
     深色背景區塊時，於 <html data-nav-bg="dark"> 切換成對應深色
     背景版本」，並且下方也有對應的 html[data-nav-bg="dark"] { ... }
     選擇器區塊。但這個機制早在 2026-08-22 就被業主關閉，JS 永遠
     不會寫入這個屬性，該選擇器規則從未生效過，已確認是死碼並
     整段刪除。全站真正生效的深色背景智慧變色機制是
     .nav-trigger.is-over-dark（水滴/文字疊在 Footer 深色底上時
     由 JS 局部加上這個 class），不要再照抄 data-nav-bg 這個寫法
     去做新的深色背景適配。

     2026-09-28：--nav-fg-idle（水滴本身未互動時的顏色）已刪除——水滴改成圖檔後沒有任何元素讀取它。
     它的顏色沿革（grey-500→600→700）與刪除前原文逐字保存在《已移除程式碼備查_2026-09-28.md》E10；
     本檔其他註解中提到 --nav-fg-idle 的地方是歷史說明，不是現行變數 ---- */
  --nav-fg-hover: var(--ink);
  /* 2026-09-08：新增獨立變數，只給扇形選單連結（.fan-menu a）跟
     水滴提示文字（.droplet-hint）的 hover/highlight 狀態用，
     不再共用 --nav-fg-hover。原因：--nav-fg-hover 同時控制水滴
     本身的亮燈顏色跟 Logo 顏色，業主要求「Footer 上選單連結
     hover 要變深色，但水滴本身亮燈仍要維持白色」，這兩個需求
     互相衝突，沒辦法共用同一個變數同時滿足，才拆成獨立變數。
     淺色背景版本沿用 --ink（深色），跟原本 --nav-fg-hover 在
     淺色背景下的值一致，不影響淺色背景的既有視覺 */
  --nav-fg-link-hover: var(--ink);
  /* 2026-09-08：新增獨立變數，只給水滴下方常駐提示文字
     （.droplet-hint，「選單」二字）用，跟水滴本身（--nav-fg-idle）
     綁定同一個顏色來源，不再跟 --nav-fg-muted（扇形選單連結的
     預設色）共用。業主要求「選單」二字要跟水滴顏色一致，但扇形
     選單連結的預設顏色要維持獨立（Footer 上是白色），這兩者
     用同一個變數會互相衝突，所以拆開。淺色背景版本直接沿用
     --nav-fg-idle 的值，等於淺色背景下維持原本的行為不變 */
  /* 「社群」二字（.droplet-hint）default 色——智慧變色：
     淺色背景：--ink（#505050，宗霖 2026-09-24 晚指定；先前一版用 --grey-500 跟水滴平均色一致，
     但在灰底上太淡、看不清楚）；
     深色背景（Footer，.nav-trigger.is-over-dark）：--white（2026-09-24 晚宗霖改為白色；先前是 --grey-500），
     見下方 .nav-trigger.is-over-dark 的覆蓋。
     不綁 --nav-fg-idle（已不再有元素使用，水滴本體改為圖檔） */
  --nav-fg-hint: var(--ink);
  /* 水滴 hover／展開時的濾鏡：新水滴是固定灰階圖檔，無法像舊版遮罩水滴那樣改 background-color，
     改用 filter 調整明暗。淺色背景變深（更有份量），深色背景（Footer）變亮（維持可視度） */
  --droplet-hover-filter: brightness(0.62) contrast(1.15);
  /* 2026-09-08：新增獨立變數，只給水滴展開後的社群圖示
     （.fan-menu--social a，FB/IG/LINE/Threads）用，不再跟
     --nav-fg-muted 共用。業主要求這組圖示的 default 顏色要能
     獨立指定成 grey-700（比原本共用的 --nav-fg-muted 深一階），
     不要因為 --nav-fg-muted 之後被其他地方調整而被連動改變 */
  --nav-fg-social-icon: var(--grey-600);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* 2026-09-24：全站禁止左右滑動（宗霖要求）。
     根因：body 原本就有 overflow-x:hidden，理論上瀏覽器會把 body 的
     overflow 值「傳遞」給 <html>（視窗實際捲動的對象是 html，不是 body），
     但實測（Chromium）不管用——html 仍可被拖到 scrollLeft:135px，
     跟手機版已知的橫向溢出量（135px，見 index.html 硬幣水波紋、
     contact.html 側欄裝飾等未收邊元素）完全吻合，代表這個「傳遞」
     沒有實際生效，html 本身才是真正需要設定的層級，body 那條單獨
     設定並不夠。這裡直接在 html 上也明確加 overflow-x（見下方
     2026-09-26 追記，這裡當時用的是 hidden，已改成 clip）。

     ⚠️⚠️⚠️ 2026-09-26 重大追記（宗霖回報：首頁硬幣落水動畫捲到一半
     莫名蓋上一大塊灰色空白，硬幣還沒入水就被吃掉）——上面這個
     2026-09-24 的「防呆」本身就是根因，不是防呆完全無害：
     CSS 規範規定，只要 overflow-x 被設成 visible 以外的值
     （這裡是 hidden），瀏覽器就【必須】把同一個元素原本沒特別設定、
     維持預設 visible 的 overflow-y 自動升級成 auto（兩軸不能一個
     visible 一個不是 visible，只要有一軸不是 visible，另一軸就會
     被強制變成可捲動的 auto）。這裡 html 跟 body 兩層都被設了
     overflow-x:hidden，兩層的 overflow-y 因此雙雙被瀏覽器自動偷改成
     auto——實測 getComputedStyle 證實：html/body 的 overflow-y
     從沒設定過的 visible 變成 auto。
     「html 跟 body 同時變成各自獨立的可捲動容器」正是這次事故的
     根因：全站所有 position:sticky 元素（.hero-pin、獎項清單的
     .awards-scroll-sticky 等）都是靠「相對於最近的可捲動祖先」
     來卡住畫面，最近可捲動祖先原本該是瀏覽器視窗本身；現在 html／
     body 意外插進來變成兩層額外的可捲動容器，sticky 的定位基準被
     打亂，在某些瀏覽器/環境下整個失效——實測 .hero-pin 的
     getBoundingClientRect().top 直接等於 -scrollY，等於完全沒有
     卡住，硬幣所在的整塊內容跟著頁面正常捲走，捲完那一小段（僅
     一個視窗高）後，「硬幣掉落／觸水」這一大段本來要在畫面中央
     慢慢播放的動畫，因為畫面本身已經捲走消失，變成後面一大段
     （將近一個螢幕高）空空如也的軌道空間，才會看起來像「莫名跑出
     一塊灰色空白」，硬幣也才會在還沒真正入水的分鏡就被「吃掉」
     （不是被誰蓋住，是硬幣所在的整個畫面本身已經被捲出視窗外）。
     這個 bug 在無頭測試環境剛好沒有實際重現（推測是無頭瀏覽器對
     這個特定 CSS 規格邊界案例的實作跟真實瀏覽器有落差），導致
     一開始排查花了很多輪都對不上，改用真正的瀏覽器手動逐步捲動
     測量 .hero-pin 的 rect.top 才抓到。

     修法：改用 overflow-x: clip 取代 overflow-x: hidden。clip 是
     CSS 較新的關鍵字，效果一樣是「裁掉超出範圍的內容、不給捲動」，
     但明確不受這條「另一軸強制變 auto」的規範限制（clip 從設計上
     就是為了不產生可捲動容器），實測 overflow-y 恢復成 visible，
     sticky 完全恢復正常，橫向捲動依然完全鎖死（scrollWidth／
     強制 scrollTo 都驗證過）。瀏覽器支援：Chrome/Edge 90+、
     Safari 16+、Firefox 102+，2026 年的正式站台無相容性疑慮 */
  overflow-x: clip;
}

body {
  font-family: var(--font-cn);
  font-size: var(--text-16);
  line-height: var(--leading-2);
  color: var(--ink);
  background: var(--grey-100);
  overflow-x: clip; /* 2026-09-26：同上，從 hidden 改成 clip，避免強制 overflow-y:auto 打斷全站 position:sticky */
  letter-spacing: var(--tracking-0);
}
/* loading 期間鎖定捲動：#loading-screen 雖然用 position:fixed
   蓋滿全螢幕，但底下的頁面內容原本還是能被滑鼠滾輪/觸控捲動
   （只是被蓋住看不到），業主要求 loading 期間完全不能捲動。
   由 main.js 在 loading 開始時加上這個 class、loading 畫面真正
   隱藏的同一刻移除，兩者動作同步 */
body.is-loading {
  overflow: hidden;
  height: 100vh;
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; border: none; background: none; cursor: pointer; }

/* ---- 無障礙：鍵盤 focus 可視樣式（全站統一） ---- */
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-sm);
}

/* ---- 元件狀態：disabled 統一樣式 ---- */
button:disabled,
input:disabled,
[aria-disabled="true"] {
  opacity: var(--state-disabled-opacity);
  cursor: not-allowed;
  pointer-events: none;
}

/* ---- 滾動淡入：data-reveal 元素進場動畫（整塊淡入 + 輕微上移）----
   涵蓋所有標題與內文區塊，統一用同一種手法，不再區分逐行遮罩滑入 */
[data-reveal] {
  opacity: 0;
  transform: translateY(48px);
  z-index: 1;
  transition: opacity 1s var(--ease-water),
              transform 1s var(--ease-spring);
}
[data-reveal].is-visible {
  opacity: 1;
  transform: none;
}
/* 2026-09-12：宗霖要求全站中英標 appear animation 統一，以首頁
   showcase 分類卡片（室內設計/品牌設計/整合型設計）為模範——那組
   英標中標是同一個 data-reveal 容器一起觸發，動畫參數完全相同。
   拿掉這裡原本讓中標（.about-tagline）位移 80px、比英標
   （.about-label 沿用全域 48px）更大的特例，兩者現在統一用全域
   預設的 48px，視覺上才會是「同一個動作」，不是中標動得比英標
   明顯的兩個各自獨立的動作 */

/* 內文區塊延遲稍晚一點再淡入，製造漸進層次感（泉力以赴、設計實力
   兩塊都用同一個延遲時間，讓標題→內文的節奏感一致） */
.about-desc-group[data-reveal],
.stat-block-body[data-reveal] { transition-delay: 0.25s; }
/* 2026-09-12：about.html 的「設計實力推動產業與城市發展」區塊
   （about-recognition-*，從首頁 #recognition 簡化複製而來，見
   about.html 對應區塊上方註解）補齊 appear animation，宗霖指出
   標題/內文/照片完全沒有進場動畫。套用跟首頁 .stat-block-body
   完全一致的節奏：標題與照片正常淡入，內文延遲 0.25s 晚一點，
   不發明新的時間值 */
.about-recognition-body[data-reveal] { transition-delay: 0.25s; }

/* 2026-09-11 第一次調整：全站英標補上 data-reveal 後，曾經統一
   跟對應的中標之間錯開 0.15s（英標先、中標後），營造由上到下的
   閱讀順序。
   2026-09-11 第二次調整（撤回上面的做法）：宗霖盤點後發現這造成
   全站中英標動畫時序不一致——首頁三組（About/FAQ/Contact）用了
   0.15s 錯開、變成「中標明顯慢一拍」，但 Showcase 三個分類卡片
   的英標中標是同一個 data-reveal 容器（topRow）觸發、完全同步，
   兩種模式並存在同一個頁面上很突兀。宗霖明確要求統一成「差不多
   時間出現」（即 Showcase 那種同步模式），所以撤回這裡原本的
   transition-delay:0.15s 宣告，讓英標中標都用基礎值 0s、完全
   同步淡入 */
/* 2026-09-21 移除：#faq .page-header-cta[data-reveal]、.page-label[data-reveal]／.contact-label[data-reveal]（含 .is-visible 變體）、
   html[data-page="home"] .page-label[data-reveal]（含 .is-visible 變體）、.contact-title[data-reveal] 這幾組規則。
   原因：這些元素「自己」已不帶 data-reveal（2026-09-12 全站中英標統一重構後，淡入改掛在外層 .page-header／.contact-aside 容器），
   選擇器在 17 頁 × 5 種寬度的實測與靜態掃描中一次都沒有比對到元素，是永遠不會生效的死碼。
   ⚠️ 若日後又讓 .page-label／.contact-label／.contact-title／.page-header-cta 自己帶 data-reveal，會與 main.js 直接寫入的
   transform／transition 互搶同一個屬性、造成位置錯亂（FAQ 的 CTA 曾因此偏移 116px）。屆時要恢復「transform:none ＋ 只保留
   opacity transition」的排除規則；原規則與完整除錯記錄逐字保存在《已移除程式碼備查_2026-09-21.md》。 */
.showcase-row--bottom[data-reveal] { transition-delay: 0.15s; }

/* 2026-09-10：作品內頁的標題區塊+資訊總覽，套用同一套「主要內容
   先出現、補充資訊延遲淡入」慣例——業主反饋原本只有資訊總覽有
   appear animation、標題區塊完全沒有動畫，兩者現在合併成同一塊
   白底、物理距離很近，若整塊只用單一 data-reveal 一起觸發，容易
   在使用者捲動到一半時「上半部已完全進入視窗、下半部還沒觸發
   20% threshold」，動畫效果不夠俐落；也不想讓每個小欄位各自跳動
   顯得太花。折衷做法：標題區塊（.work-detail-title-section）正常
   淡入，資訊總覽延遲 0.25s（沿用上面 .stat-block-body 同一個
   數值，不發明新的節奏）晚一點淡入，兩塊有先後層次但克制、統一 */
.work-detail-info-summary[data-reveal] { transition-delay: 0.25s; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   共用元件：膠囊標籤（Tag Pill）
   ========================================================================== */
/* 全站所有「圓角膠囊、點擊後反黑」的標籤共用同一份樣式定義，
   目前套用在：聯絡我們表單的服務項目（.pill）、作品案例頁的
   分類篩選標籤（.project-filter-item）。
   之前這兩處各自獨立寫了一份幾乎相同的 CSS，只要改其中一邊
   （內距/顏色/字重）忘記同步另一邊，兩處視覺就會不一致——這正是
   先前反覆回報「不一樣」的根本原因。統一成單一元件類別後，
   往後任何頁面需要同款標籤，直接加上 .tag-pill 即可，只有一份
   真相來源，不會再有兩邊各自維護、彼此漂移的問題。 */
.tag-pill {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--grey-600);
  border-radius: var(--radius-full);
  padding: var(--space-1) var(--space-3);
  font-family: var(--font-cn);
  font-weight: 500;
  font-size: var(--text-14);
  /* 明確鎖定 line-height，不放任它被繼承來源不同而跑掉。
     根因：這個元件套用在不同 HTML 標籤上時（<button> vs <span>），
     瀏覽器 user-agent 樣式表對 line-height 的預設值不一致
     ——<button> 預設會重置成 normal，<span> 沒有這個重置、
     會一路往上繼承 body 的 1.5 倍行高，導致即使 padding 完全
     相同，兩者的實際渲染高度還是會差了將近 7px。統一寫死
     line-height:1 後，不管套用在什麼標籤上，視覺高度只由
     padding + font-size 決定，不再受繼承鏈影響 */
  line-height: 1;
  color: var(--ink);
  background: transparent;
  transition: background-color 0.3s var(--ease-water),
              color 0.3s var(--ease-water),
              border-color 0.3s var(--ease-water);
}
.tag-pill:hover,
.tag-pill.is-selected,
.tag-pill.is-active {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--white);
}

/* ---- 服務項目標籤 hover 提示（tooltip）----
   業主要求：聯絡我們區塊的服務項目三顆標籤（室內設計/品牌設計/
   整合型設計），桌機版滑鼠 hover 時要在標籤上方顯示說明文字。
   ⚠️ 第一版用 ::before + content:attr(data-tooltip) 實作，業主
   反映提示框右側留白明顯比左側大很多。根因：attr() 產生的是一整串
   連續中文字，中間沒有西方文字那種空白字元可以參考斷行，
   width:max-content 搭配 max-width 換行時，瀏覽器是用「整串文字
   完全不換行時的總寬度」去跟 max-width 比較，這個總寬度遠超過
   max-width，所以三個框最終都直接鎖死在 max-width 這個上限，而不是
   「換行後最長那一行的實際寬度」——文字換行後每一行實際佔用的寬度
   都比框窄，才會造成文字整體偏左、右側大片留白。嘗試過 CSS 的
   fit-content() 函式想讓框寬貼合換行結果，但這個函式用在
   content:attr() 產生的偽元素上，瀏覽器換行前的 intrinsic sizing
   計算支援度不穩定，不是能放心依賴的做法。
   改用真正的 HTML 子元素（<span class="tag-pill-tip">，文字直接
   寫在 HTML 裡，不再透過 attr() 產生），寬度計算完全交給瀏覽器
   處理一般文字排版最基本、最穩定的原生行為（跟平常任何一段會
   自動換行的文字容器完全一樣），不依賴任何進階 CSS 函式，從根本
   避開 attr() 字串沒有斷行參考點導致的寬度計算問題。
   只加在額外的 .tag-pill--tooltip 這個 class 上，不動 .tag-pill
   本體——因為 .tag-pill 是全站共用元件（works.html 篩選標籤也在
   用），如果直接改 .tag-pill 本身，會讓所有用到這個共用元件的
   地方都跟著長出 tooltip，波及範圍過大且不是這次需求的一部分。
   桌機限定：用 hover 觸發，觸控裝置沒有滑鼠停留這個互動概念，
   點擊時瀏覽器通常會把 :hover 跟 :active 混在一起觸發，容易讓
   提示框在手機上误闪一下又消失，體驗不佳，這裡不特別做觸控版本，
   維持「桌機專屬」的簡單提示，跟業主原始需求（桌機版 hover）一致 */
.tag-pill--tooltip {
  position: relative;
}
.tag-pill-tip {
  position: absolute;
  bottom: calc(100% + var(--space-2));
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  /* ⚠️ 業主反映提示框變成「兩個字就換行」，根因：display:inline-block
     沒有明確指定 width，只給了 max-width 當上限，inline-block 元素
     沒有 width 時預設行為是 shrink-to-fit（盡量收縮到內容需要的
     最小寬度），瀏覽器因此傾向把字排得很窄，而不是撐到 max-width
     那麼寬——這跟「文字會自然撐滿到上限」的直覺剛好相反。
     改成明確指定 width（固定寬度）解決了換行過窄的問題。業主
     接著發現「最後一行字數不滿一整行時，右側會比左側多出留白」
     ——這是文字排版的必然結果（左右 padding 數值本身完全一致，
     不是 CSS 內距設錯）。原本嘗試用調整寬度（230px，每行約15字）
     讓最後一行盡量貼近满行來緩解，業主後來決定改用更直接的做法：
     text-align:justify（齊頭齊尾），讓每一行（除了最後一行）都
     強制左右對齊到滿版寬度，字元間距自動微調撐開——業主明確接受
     這會讓中文字距看起來不完全均勻（justify 對中日文這類無空白
     字元的語言，是靠字元本身間距被拉伸來對齊，不像英文有天然的
     單字空白可以彈性伸縮），優先滿足「每行都要左右對齊、不要
     視覺上一邊多一邊少」的需求。寬度改回 260px（業主指定數值） */
  width: 260px;
  padding: var(--space-2) var(--space-3);
  background: var(--ink);
  color: var(--white);
  font-family: var(--font-cn);
  font-size: var(--text-14);
  font-weight: 400;
  line-height: var(--leading-2);
  letter-spacing: var(--tracking-xs);
  text-align: justify;
  text-align-last: left;
  border-radius: var(--radius-md);
  white-space: normal;
  opacity: 0;
  pointer-events: none;
  z-index: 20;
  transition: opacity 0.25s var(--ease-water), transform 0.25s var(--ease-water);
}
/* 小三角形，指向標籤本身，強化「這段文字是在說明這顆標籤」的
   視覺關聯，跟提示框主體用同一個顏色（--ink），無縫銜接 */
.tag-pill-tip::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: var(--ink);
  border-bottom-width: 0;
}
@media (hover: hover) {
  .tag-pill--tooltip:hover .tag-pill-tip {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}
/* ---- Tooltip 靠近螢幕邊界時的碰撞修正（2026-09-11 新增）----
   根因：.tag-pill-tip 預設用 left:50%+translateX(-50%) 相對「自己
   這顆標籤/徽章的中心」水平置中，這個定位邏輯不知道自己在畫面
   哪個位置，也不知道旁邊剩多少空間。純 CSS 無法感知 viewport
   邊界（沒有原生的碰撞偵測機制），所以離螢幕邊界太近的標籤
   （例如置右對齊的獲獎徽章區塊，最右邊那顆徽章）置中展開的
   tooltip 必然會溢出畫面外。
   解法：JS 在 hover 當下用 getBoundingClientRect() 即時量測，
   偵測到溢出就動態加上這兩個 class 之一，把水平定位基準從
   「自身中心」切換成「自身左邊界」或「自身右邊界」，讓文字
   往畫面內側展開，同時把小三角形一起移動、繼續指向原本的
   標籤/徽章位置（不是整個 tooltip 死板地貼齊邊界） */
.tag-pill-tip.tip-align-right {
  left: auto;
  right: 0;
  transform: translateX(0) translateY(4px);
}
@media (hover: hover) {
  .tag-pill--tooltip:hover .tag-pill-tip.tip-align-right {
    transform: translateX(0) translateY(0);
  }
}
.tag-pill-tip.tip-align-right::after {
  left: auto;
  /* 距離由 JS 依標籤中心跟 tooltip 右邊界的實際差距即時計算並寫入
     --tip-arrow-offset，這裡只負責套用，不猜測固定數值 */
  right: var(--tip-arrow-offset, 16px);
  transform: none;
}
.tag-pill-tip.tip-align-left {
  left: 0;
  transform: translateX(0) translateY(4px);
}
@media (hover: hover) {
  .tag-pill--tooltip:hover .tag-pill-tip.tip-align-left {
    transform: translateX(0) translateY(0);
  }
}
.tag-pill-tip.tip-align-left::after {
  left: var(--tip-arrow-offset, 16px);
  transform: none;
}

/* ---- work-detail.html 獲獎徽章區塊（2026-09-11 新增）----
   跟標題同一橫列、置右，數量不固定（WP/ACF Repeater 欄位），
   單排橫向排列，數量多時自動換行——不使用 nowrap，因為徽章
   數量沒有上限，業主之後可能一次掛很多個獎項，換行比橫向溢出
   或擠壓變形更安全 */
.work-detail-award-badges {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-3);
  /* 徽章尺寸由 JS 依實際圖片比例/固定高度決定（見 main.js），
     這裡先給一個保底最大寬度，避免圖片還沒載入完成時版面跳動 */
  max-width: 320px;
}
.work-detail-award-badge {
  display: block;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  background: var(--placeholder); /* 佔位灰色方塊，實際圖片載入後會蓋掉 */
  flex-shrink: 0;
  position: relative; /* .tag-pill--tooltip 需要的定位基準 */
}
/* 2026-09-30：有真實徽章圖片時，容器底色要透明。
   根因：.work-detail-award-badge 的灰底（var(--placeholder)）是「沒有圖片」時的佔位視覺，但它掛在容器本身，徽章圖以
   object-fit: contain 放進 40×40 方框，只要圖片不是正方形，上下（或左右）就會露出灰色底，把徽章「框」在灰色方塊裡。
   用 :has(> img) 只在容器內真的有圖片時才清掉底色；沒圖片時（.is-placeholder）仍是灰色方塊佔位，不影響。 */
.work-detail-award-badge:has(> img) {
  background: transparent;
}

/* 之後串接真實徽章圖片時，改成 <img class="work-detail-award-badge">
   或在這個容器內放 <img>，.is-placeholder 只是開發階段的灰色
   佔位視覺，正式圖片就緒後移除這個 class 即可，不影響版面結構 */
.work-detail-award-badge.is-placeholder {
  cursor: default;
}

/* ---- 獎項名稱 tooltip：寬度自適應（跟服務項目說明文字的固定
   260px 版本不同）----
   根因：現有 .tag-pill-tip 是為「室內設計」這類完整敘述句設計的
   （例如「住宅、商業空間與老屋翻新，從設計到施工，陪您完成理想
   空間。」），固定 260px + text-align:justify 是為了讓多行文字
   左右對齊好看。但獎項名稱是短字串（實測全站現有 5 個獎項名稱
   長度落在 10～23 字，例如「金點設計空間設計住宅」「美國TITAN
   PROPERTY AWARDS」），單行就能顯示完，如果套用同一個 260px
   寬度，會變成一行字被硬撐在 260px 的框裡，兩側留下大片不必要
   的空白，跟旁邊小巧的徽章圖片比例明顯失衡。
   改用 width:max-content（寬度貼合文字內容本身），搭配一個
   max-width 上限防止萬一業主之後填入異常長的獎項名稱時無限撐寬；
   不覆寫 text-align，單行文字不需要 justify 對齊效果 */
.work-detail-award-tip {
  width: max-content;
  max-width: 240px;
  text-align: left;
}

/* ==========================================================================
   Loading Screen
   ========================================================================== */
#loading-screen {
  position: fixed;
  inset: 0;
  background: var(--grey-200);
  z-index: 9999;
  overflow: hidden;
  transition: opacity 0.8s var(--ease-water), visibility 0.8s;
}
#loading-screen.hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
/* ---- 第一層失效保險（純 CSS，完全不依賴 JS）2026-09-19 ----
   根因：整站唯一能讓 #loading-screen 消失的，只有 main.js 成功執行後加上
   .hidden。<noscript> 只在「JS 被關閉」時生效，但實務上更常見的是「JS 開著、
   main.js 卻沒有跑完」——例如直接雙擊 html 用 file:// 開啟（瀏覽器會擋掉
   type=module 的外部腳本）、模組載入失敗、被擴充功能封鎖、執行到一半當掉。
   這些情況 <noscript> 完全不會觸發，loading 畫面就永遠蓋住整個網站。
   做法：用 CSS 動畫在 10 秒後強制淡出並放開點擊，同時解除 body 的捲動鎖。
   正常情況下 main.js 最晚約 3.0 秒內就會隱藏 loading，這條動畫抵達時
   畫面早已是相同的最終狀態，視覺上完全無感；只有真的卡住時才會生效。
   forwards 讓動畫結束後維持最終狀態。10 秒是刻意抓的上限：夠慢網路正常
   跑完，又不會讓真正壞掉的頁面卡太久。 */
#loading-screen {
  animation: loading-failsafe 0.8s var(--ease-water) 10s forwards;
}
@keyframes loading-failsafe {
  to { opacity: 0; visibility: hidden; pointer-events: none; }
}
body.is-loading {
  animation: scroll-lock-failsafe 0.01s linear 10s forwards;
}
@keyframes scroll-lock-failsafe {
  to { overflow: visible; height: auto; }
}
.loader-gif {
  /* 業主提供的 loading GIF。
     2026-08-21：首次置換，取代原本的 SVG 漏斗+落球動畫
     （尺寸 1440x850，100 幀）。
     2026-09-11：第二次置換，改成點陣風格的漏斗+水滴動畫
     （尺寸 1920x1080，121 幀，約 4 秒循環）。
     GIF 本身尺寸是滿版寬螢幕比例，設計上就是整個 loading 畫面
     本身，不是一個小圖示，所以用 object-fit:cover 撐滿容器——
     這也是為什麼兩次置換尺寸/比例不同（1440x850 vs 1920x1080）
     完全不需要額外處理，cover 會自動等比裁切填滿，不會變形，
     未來如果業主再換一版新 GIF，只要 assets/images/loading.gif
     檔案本身放上去即可，不需要動這裡的 CSS */
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ==========================================================================
   Header / Nav
   ========================================================================== */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 500;
  isolation: isolate;
  /* 2026-09-08：業主要求把 Footer 那 6 個站內連結搬到 Header，
     變成一條橫向 navbar，並且要有品牌灰 --grey-300 背景色（跟
     About/Recognition 等首頁其他區塊用的同一個品牌灰，一開始
     誤用了 grey-400，業主確認要改回 grey-300）。原本 Header
     是透明背景疊在 Hero 上，現在整個 Header（含 Logo/連結/LINE
     按鈕）都要有底色，直接在 .site-header 本身加背景色，讓
     padding 範圍內也一併吃到底色，不是只有 .site-header-inner
     內部有背景（那樣兩側 padding 的位置會露出沒有底色的縫隙） */
  background: var(--grey-300);
  /* 2026-09-20：原本這裡有一句 transition: background-color 0.5s，但下方
     transform 的 transition 是另一個獨立宣告，CSS 規則是「後者整個取代前者」，
     所以背景色的 0.5s 淡出從來沒有生效（水滴選單展開時 header 灰底是瞬間變
     透明）。已把兩者合併成下方單一宣告（見 transform 那一行）。 */
  /* 2026-09-08：上下內距從 --space-6(24px) 縮小為 --space-4(16px)，
     左右維持 --space-12 不變 */
  padding: var(--space-4) var(--space-12);
  /* 業主要求：往下捲動時 header（公司 logo）收到畫面外，往上捲動時
     歸位。用 transform 而非 top/margin，避免觸發 layout 重排，只
     影響合成層（compositing），效能較好。JS 控制 .is-hidden 這個
     class 的加減（見 js/main.js 的 headerScrollHide 相關邏輯），
     這裡只負責過渡動畫本身，沿用全站慣用的 --ease-water 緩動曲線
     維持一致的質感 */
  transform: translateY(0);
  /* 兩個過渡合併成同一個 transition 宣告（逗號分隔）：
     ① background-color 0.5s：水滴選單展開時 header 灰底淡出成透明，露出底下的
        模糊遮罩（.nav-overlay 的 opacity／backdrop-filter 過渡同為 0.5s，
        兩者同步淡入淡出）；收合時反向淡回灰底。
     ② transform 0.4s：往下捲收起、往上捲歸位。 */
  transition: background-color 0.5s var(--ease-water),
              transform 0.4s var(--ease-water);
}
.site-header.is-hidden {
  transform: translateY(-100%);
}
.site-header-inner {
  /* 2026-09-08：業主要求這條 navbar「不要那麼侷限在最大寬度，
     會隨著裝置變大而一直往兩側延伸」——拿掉原本的
     max-width: var(--container-max) + margin: 0 auto 置中公式，
     改成滿版延展，寬度完全交給 .site-header 的左右 padding
     （--space-12）決定內距，不再跟其他區塊的 1240px 置中內容
     對齊。這是業主明確確認過的取捨：Logo/連結/LINE按鈕從此不再
     跟 about/recognition/partners 等區塊的左邊界對齊，換取
     navbar 本身能隨裝置寬度持續延伸的效果 */
  width: 100%;
  display: flex;
  /* 2026-09-07 新增 LINE 預約按鈕後，header 內有兩個子元素
     （logo + 按鈕），加上 space-between 讓 logo 靠左、按鈕靠右，
     兩者維持在 .site-header-inner 這同一組置中容器邊界內，
     不需要另外用 margin-left:auto 之類的方式手動推開。
     2026-09-08：新增中間的導覽連結（.header-nav-links）後，
     space-between 依然適用——三個子元素（logo/導覽連結/LINE按鈕）
     會自動被平均推開到最左、中間、最右 */
  justify-content: space-between;
  align-items: center;
}
/* ---- Header 導覽連結（2026-09-08 新增）----
   從 Footer 的 .footer-links 搬一份到 Header，內容/連結網址/
   順序完全一致（關於我們／服務項目／獲獎紀錄／作品案例／常見
   問題／聯絡我們），只是視覺樣式獨立設計，不共用 Footer 那份的
   class，避免兩處樣式（例如 Footer 是深色背景白字、這裡是
   grey-400 背景深字）耦合在一起、改一邊會意外連動到另一邊。
   業主要求排列順序是「Logo 最左、LINE按鈕最右、6個連結夾在
   兩者之間、稍微靠右一點」，用 margin-left:auto 讓連結群組
   自動貼齊 LINE 按鈕那一側，而不是均勻置中 */
.header-nav-links {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  margin-left: auto;
  margin-right: var(--space-8);
}
.header-nav-links a {
  font-family: var(--font-cn);
  font-size: var(--text-14);
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  transition: opacity 0.3s var(--ease-water);
}
.header-nav-links a:hover {
  opacity: var(--state-hover-opacity);
}
/* ---- 「作品案例」hover 下拉子選單（2026-09-10 新增）----
   業主需求：hover 到「作品案例」時，跑出室內設計/品牌設計/整合型
   設計三個子項目，點擊直接連到對應的主分類頁（works-interior/
   branding/integrated.html）。
   刻意用純 CSS :hover 觸發（不寫 JS），原因跟 .header-nav-links
   本身「不依賴 JS 也要能運作」的既有原則一致——無 JS 環境下，
   雖然 hover 互動本身仍然需要滑鼠事件（觸控裝置沒有 hover，但
   這排連結本來就只在桌面寬度顯示，見上方 max-width:1024px 隱藏
   規則），但下拉選單的顯示/隱藏機制完全不靠 JavaScript 執行，
   停用 JS 也不會讓「作品案例」這個入口本身失效（它自己還是一個
   正常的 <a href="works.html">，可以直接點擊進入作品總覽頁，
   下拉選單只是額外的捷徑，不是必要路徑）。
   .has-dropdown 包一層 position:relative 定位容器，下拉選單
   （.nav-dropdown）用 position:absolute 疊在下方，預設
   opacity:0 + visibility:hidden + 輕微 translateY 位移（懸浮感），
   hover 到父層 .has-dropdown 時才淡入displacement 歸零。
   z-index 設定高於 .site-header 的 500，確保不會被 header 背景
   或其他同層元素蓋住 */
.header-nav-links .has-dropdown {
  position: relative;
  /* 2026-09-15 修正：業主反饋「作品案例」在導覽列裡的垂直位置比
     其他連結低。根因：其他連結是 .header-nav-links 底下直接的
     <a> 標籤，「作品案例」則是包在這個 <div class="has-dropdown">
     裡面才有 <a>，這個 div 預設沒有明確的排版方式，在外層 flex
     容器（.header-nav-links，align-items:center）裡對齊時，
     依賴的是內部 inline 內容自然撐出的高度基準，這個基準點在
     不同瀏覽器/字體渲染環境下，容易跟其他純 <a> 元素出現細微
     的垂直落差。修法：直接讓 .has-dropdown 本身也是
     display:flex + align-items:center，內部的 <a> 有明確、
     跟其他連結一致的置中對齊基準，不再依賴容易出現落差的預設
     inline 排版方式 */
  display: flex;
  align-items: center;
}
.nav-dropdown {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  margin-top: var(--space-3);
  min-width: 140px;
  background: var(--white);
  border-radius: var(--radius-sm);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
  padding: var(--space-2) 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s var(--ease-water), transform 0.25s var(--ease-water), visibility 0.25s;
  z-index: 501;
}
.header-nav-links .has-dropdown:hover .nav-dropdown,
.header-nav-links .has-dropdown:focus-within .nav-dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}
.nav-dropdown a {
  display: block;
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-14);
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  text-align: center;
}
.nav-dropdown a:hover {
  background: var(--grey-100);
  opacity: 1;
}
/* 2026-09-27 根因修正（宗霖回報：nav bar「作品案例」點擊時會先
   瞬間跑出子選單、緊接著才被導到子頁面，要求單純直接導頁不要
   秀出子選單，選項 B：不隱藏桌機版導覽列，只關閉 hover 觸發）：
   實測宗霖裝置是 iPad Pro 13（CSS 寬度 1032px，屬於觸控裝置）。
   .header-nav-links 用 max-width:1024px 隱藏，1032px 卡在斷點
   外側仍顯示桌機版導覽列，而「作品案例」用 :hover 觸發子選單
   （見上面 .has-dropdown:hover .nav-dropdown）。觸控裝置沒有真正
   的 hover 狀態，點擊時瀏覽器會先觸發一次 :hover（子選單瞬間
   顯示），緊接著才觸發 click 導頁，這正是宗霖說的「瞬間跑出子
   選單又被導頁」的成因。
   原本考慮把這段寬度隱藏、改用水滴選單導覽（選項 A），但水滴
   選單目前已改版成只剩社群連結、不含頁面導覽，選項 A 會讓這段
   寬度失去導覽功能，經宗霖確認改採選項 B：不隱藏導覽列，只用
   (hover: none) 精準鎖定「沒有真正 hover 能力」的觸控裝置，關掉
   這一項的子選單 hover 觸發，讓它在觸控裝置上單純變成一個連結，
   點擊直接導頁到 project.html，不會有子選單瞬間跳出的現象；
   :focus-within 是鍵盤 Tab 聚焦觸發，跟滑鼠 hover 是獨立的無障礙
   路徑，不受觸控裝置影響，予以保留。
   用 (hover:none) 而非寬度斷點，是因為問題本質是「觸控輸入沒有
   hover 概念」，不是某個特定寬度區間——這樣寫可以同時涵蓋所有
   觸控裝置（含桌機版寬度但用觸控螢幕的情況），比寬度斷點更精準
   對應問題成因，也完全不影響滑鼠使用者原有的 hover 展開體驗 */
@media (hover: none) {
  .header-nav-links .has-dropdown:hover .nav-dropdown {
    opacity: 0;
    visibility: hidden;
    transform: translateX(-50%) translateY(4px);
  }
}

@media (max-width: 1024px) {
  /* 平板：橫向空間變窄，6 個連結 + Logo + LINE 按鈕容易擠爆一行，
     先隱藏這排連結，導覽功能交給水滴扇形選單（本來就存在、
     支援手機/平板尺寸），避免 Header 在中等寬度螢幕上跑版 */
  .header-nav-links {
    display: none;
  }
}
/* ---- LINE 預約諮詢 CTA 按鈕（2026-09-07 新增，全站共用）----
   參考業主提供的嘉韻診所截圖：header 右上角的實心填色按鈕樣式。
   跟站內既有的 .cta-arrow（文字+外框箭頭圓圈的連結樣式）不同，
   這裡刻意做成「填色按鈕」的視覺型態，比較貼近截圖裡的意圖——
   一個清楚、獨立、行動呼籲感強烈的按鈕，不是融入內文的連結。
   顏色/圓角沿用既有 token（--ink 品牌黑、--radius-full 膠囊圓角），
   不是憑空生造新樣式，維持跟全站設計系統一致 */
.line-cta-button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-6);
  background-color: var(--ink);
  color: var(--white);
  border-radius: var(--radius-full);
  font-family: var(--font-cn);
  /* 2026-09-08：業主再次確認，改成 14px（先前 2026-09-07 曾定案
     16px、跟「送出」按鈕 .form-submit 統一，這次業主推翻那個決定，
     .form-submit 維持 16px 不變，只有這顆 LINE 按鈕改小） */
  font-size: var(--text-14);
  font-weight: 500;
  letter-spacing: var(--tracking-xs);
  white-space: nowrap;
  /* 2026-09-07：業主反饋原本降低透明度的 hover 效果讓實心按鈕看起來
     變半透明、不夠紮實，改成切換背景色深淺（--ink → --grey-800），
     維持全程不透明的實心質感，只是有清楚可辨識的深淺變化當作
     互動回饋。這裡不沿用 .cta-arrow 的「反轉配色」hover 邏輯，
     因為那是給「透明底+外框」的按鈕設計的，這顆按鈕本身已經是
     實心黑底，沒有更深的顏色可以反轉，換一種對應的做法 */
  transition: background-color 0.3s var(--ease-water);
}
.line-cta-button:hover {
  background-color: var(--grey-800);
}
@media (max-width: 767px) {
  /* 手機版：文字保留但稍微縮小 padding，避免跟水滴選單（right: 28px
     起算）視覺上太擠。目前手機斷點水滴選單本身也還沒有跟這顆按鈕
     一起測試過共存間距，如果之後畫面看起來太擠，可以考慮手機版
     只顯示圖示不顯示文字，先維持完整文字版本觀察實際效果再說 */
  .line-cta-button {
    padding: var(--space-2) var(--space-4);
    font-size: 13px;
  }
}
.logo-wordmark {
  position: relative;
  display: block;
  /* 尺寸：高度跟原本文字版一致（--text-20 = 20px），
     寬度依 Logo 原始檔案比例（283.46 : 26.82）等比換算 */
  height: var(--text-20);
  width: calc(var(--text-20) * 283.46 / 26.82);
  transition: opacity 0.3s var(--ease-water);
  /* 定位點：由 .site-header 的 padding + .site-header-inner 的置中
     公式共同決定，不再是單一固定 padding 數值。要改動 logo 位置，
     調整 .site-header 的 padding 即可（跟其他區塊的側邊 padding
     保持一致，否則又會跟內容左邊界對不齊） */
}
/* 保險做法：疊一層完全透明、覆蓋整個長方形範圍的偽元素在最上層，
   強制讓「感應熱區」永遠是完整方框，不受底下 mask 圖層的可見
   形狀影響（部分瀏覽器對 mask 元素的 pointer-events 處理不夠
   徹底，單靠 pointer-events:none 不保證每個瀏覽器都吃得到） */
.logo-wordmark::after {
  content: '';
  position: absolute;
  inset: 0;
}
.logo-mark-svg {
  display: block;
  width: 100%;
  height: 100%;
  /* 2026-09-08：Header 改成固定 grey-400 實心背景後，Logo 不再
     需要跟著 --nav-fg-hover 智慧變色（那是設計給「透明 Header
     疊在不同深淺背景上」用的機制，現在背景固定了，不會再穿透
     看到底下區塊的深淺變化）。改用固定深色 --ink，在中等灰階的
     grey-400 背景上有足夠對比度、清楚可見 */
  pointer-events: none;
  background-color: var(--ink);
  -webkit-mask: url('../assets/icons/logo.svg') left center / contain no-repeat;
  mask: url('../assets/icons/logo.svg') left center / contain no-repeat;
  transition: background-color 0.4s var(--ease-water);
}
.logo-wordmark:hover {
  opacity: 0.32;
}


/* ==========================================================================
   側邊點選清單（扇形展開）
   ========================================================================== */
/* 水滴選單展開時的模糊遮罩：讓底下頁面內容模糊、視覺焦點集中在
   右側展開的社群圖示選單上，跟選單共用開合狀態
   （.is-active 由 JS 跟 .nav-trigger 的 .is-open 同步控制）。
   2026-09-08 曾一度拿掉這個效果，業主確認後要求補回來，
   維持原本 rgba + backdrop-filter 的做法，不要再拿掉 */
.nav-overlay {
  position: fixed;
  inset: 0;
  z-index: 399; /* 剛好在 nav-trigger（400）之下 */
  opacity: 0;
  pointer-events: none;
  background: rgba(245, 245, 244, 0.45);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: opacity 0.5s var(--ease-water), backdrop-filter 0.5s var(--ease-water);
}
.nav-overlay.is-active {
  opacity: 1;
  pointer-events: auto; /* 點遮罩處也能收合選單 */
}
/* 2026-09-08：業主要求水滴選單展開時，Header 的實色底也要消失，
   一律讓底下的半透明模糊遮罩（.nav-overlay）當作視覺底色。
   .nav-overlay 的 z-index(399) 比 .site-header(500) 低，原本
   Header 的不透明實色背景會完全蓋住遮罩效果、擋住底下的模糊；
   這裡讓 Header 背景在展開時變透明，模糊遮罩才能透過 Header
   所在的區域被看見，兩者疊加起來才是業主要的「全螢幕統一由
   模糊遮罩當底色」效果。用 body:has() 偵測 .nav-trigger.is-open
   狀態，全站已有 .marquee:has(.marquee-logo:hover) 的先例，
   瀏覽器相容性沒有疑慮 */
body:has(.nav-trigger.is-open) .site-header {
  background: transparent;
}

.nav-trigger {
  position: fixed;
  top: 50%;
  right: 46px;
  transform: translateY(-50%);
  z-index: 400;
  width: 16px;
}
/* 水滴選單疊在 Footer（深色背景）上時，局部覆蓋這幾個顏色變數。
   ⚠️ 2026-09-08 除錯記錄（第三輪）：業主要求「扇形選單連結預設
   維持白色、hover 時變深色」，同時「水滴本身亮燈仍要維持白色」
   ——這兩者如果共用 --nav-fg-hover 會互相衝突（改深色會讓水滴
   跟 Footer 純黑底融合看不見，改白色則選單連結 hover 沒有變化）。
   拆成兩個獨立變數解決：--nav-fg-hover 繼續只給水滴本身跟 Logo
   用（維持白色，可視度優先），--nav-fg-link-hover 只給扇形選單
   連結的 hover/is-current 狀態用（改成深色 --ink，Footer 底色
   也是 --ink，這裡刻意選擇讓 hover 後的文字融入背景、變得不明顯，
   這是業主要的「default 白色顯眼、hover 後低調」效果，跟水滴
   「必須隨時可視」的需求本質不同，不會互相矛盾）。
   --nav-fg-muted（扇形選單連結的 default 顏色）業主這次也要求
   改成白色，不再是淺灰 grey-300。
   --nav-fg-hint（「選單」提示文字）業主要求要跟水滴本身
   （--nav-fg-idle）同色，不要跟著 --nav-fg-muted 變白，這裡
   直接沿用 --nav-fg-idle 的值，兩者綁在一起。
   （2026-09-28：--nav-fg-idle 已刪除，見 :root 處說明；這段是歷史記錄） */
.nav-trigger.is-over-dark {
  --nav-fg-hover: var(--white);
  --nav-fg-link-hover: var(--ink);
  --nav-fg-hint: var(--white); /* 2026-09-24 宗霖：Footer 深色底「社群」變白色（先前一版是 grey-500） */
  --droplet-hover-filter: brightness(1.3) contrast(1.05); /* 深色背景改為變亮 */
  /* 2026-09-08：社群圖示（.fan-menu--social a）的智慧變色已經
     改成逐一判斷機制（見 .fan-menu--social a.is-over-dark-icon，
     跟 main.js 的 checkEachIconOverFooter），不再透過這裡的
     --nav-fg-social-icon 整組切換，這裡不需要再覆蓋這個變數 */
}
.droplet-icon {
  /* 2026-09-24：換成新水滴圖檔（viewBox 630.23×1000，寬高比 0.630）。高度維持 34px
     （JS 捲動定位、「社群」字距、社群圖示垂直位移都以此高度計算，不能動），
     寬度隨圖檔比例變成 21.43px（舊遮罩水滴較瘦，16px）。.nav-trigger 寬度仍是 16px，
     所以左右各用 -2.715px 負 margin 把圖示撐出去，保持水平中心不變（仍在 8px 處，
     與下方社群圖示同一條垂直線） */
  width: 21.43px;
  height: 34px;
  margin: 0 -2.715px;
  cursor: pointer;
  transition: transform 0.4s var(--ease-spring);
  position: relative;
  z-index: 2;
  /* idle 呼吸動畫：套用在 .droplet-icon 本身（不是 .nav-trigger），
     因為 .nav-trigger 的 top 由 JS 每一幀直接用 style.top 覆蓋
     （見 js/main.js updateDropletScrollPosition），若在 .nav-trigger
     上疊加 CSS transform 動畫，會跟 JS 的定位邏輯互相打架，
     .droplet-icon 沒有被 JS 動態控制位置，套用在這裡才安全 */
  animation: droplet-idle-float 2.4s ease-in-out infinite;
}
/* Hover / 展開時：停止呼吸位移，改用既有的 scale 強調效果，
   兩者共用同一個 transition，避免動畫瞬間切換造成跳動 */
.nav-trigger:hover .droplet-icon,
.nav-trigger.is-open .droplet-icon {
  animation-play-state: paused;
  transform: scale(1.12) translateY(0);
}
@keyframes droplet-idle-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(18px); }
}
.droplet-icon .droplet-shape {
  position: absolute;
  inset: 0;
  /* 2026-09-24：改用業主提供的 3D 質感灰階水滴（assets/icons/droplet-nav.svg）。
     根因：舊版是「遮罩＋background-color」單色水滴，顏色靠 --nav-fg-idle／--nav-fg-hover
     切換；新水滴是帶光影的固定灰階圖檔（內含點陣紋理，遮罩只會取得輪廓、丟掉光影），
     所以改成一般背景圖，hover／展開的變化改用 filter 明暗（見下方 --droplet-hover-filter）。
     圖檔已從原稿 390KB 降採樣到約 7.5KB（幾何與 clipPath 不變，肉眼無差異）。
     ⚠️ 表單預算滑桿的水滴把手（.range-slider-handle）仍用單色 droplet-black.svg，
     不受這次替換影響 */
  background: url('../assets/icons/droplet-nav.svg') center / contain no-repeat;
  transition: filter 0.3s var(--ease-water);
}
/* Hover / 點選：依當下主題調整明暗（淺色背景變深、Footer 深色背景變亮） */
.nav-trigger:hover .droplet-icon .droplet-shape,
.nav-trigger.is-open .droplet-icon .droplet-shape {
  filter: var(--droplet-hover-filter);
}

/* ---- 水滴文字提示：常駐可見，位於水滴下方 ----
   （2026-08-30 SEO 顧問建議常駐顯示；2026-08-31 業主要求改到水滴
   下方、且 hover 到文字本身也要觸發變色）
   原本只在 hover 時才顯示 opacity:0 → 1，桌面滑鼠使用者才看得到，
   觸控裝置、第一次進站的使用者完全沒有機會看到這個提示——已改成
   常駐顯示，預設用較淡的顏色（--nav-fg-muted，跟扇形選單項目預設色
   一致）維持低調感，hover 時才轉成強調色。
   位置從水滴左側改到下方：用 top:100% 定位在 .droplet-icon 正下方，
   不放進 flex 排列流程，是因為 .droplet-icon 本身有呼吸浮動動畫
   （droplet-idle-float，見上方），如果文字跟著同一個 flex 容器走，
   會被拖著一起上下跳動；用 absolute 定位固定在水滴容器（.nav-trigger）
   的座標系底下，只跟著 .nav-trigger 整體（由 JS 控制的捲動位移）
   移動，不會被水滴自己的呼吸動畫影響，視覺上維持穩定不跳動。
   hover 判定範圍：拿掉原本的 pointer-events:none，讓文字本身也能
   接收滑鼠事件——因為文字用 absolute 定位，視覺上仍在 .nav-trigger
   容器範圍內，滑鼠移到文字上會被瀏覽器判定為「還在 .nav-trigger
   裡」，進而觸發 .nav-trigger:hover，水滴跟文字因此共用同一組
   hover 變色邏輯，不需要另外寫一份規則。
   文字內容直接寫在 HTML 裡，是原始碼裡的真實文字，不是圖片 */
.droplet-hint {
  position: absolute;
  left: 50%;
  top: 100%;
  transform: translateX(-50%);
  /* 2026-09-08：業主要求回朔到最初的間距，水滴底部到「社群」
     文字維持 --space-2(8px)。中間曾經誤改成 --space-5(20px)，
     這是誤解需求後的錯誤調整，已經改回來，不要再調整這個值 */
  margin-top: var(--space-2);
  white-space: nowrap;
  font-family: var(--font-cn);
  font-size: 13px;
  font-weight: 500;
  /* 明確設定 line-height:1，消除繼承 body 預設 1.5 倍行高造成的
     文字容器高度不確定性（中文字體 line-height 1.5 時，文字上下
     會有額外留白，實際視覺文字比容器矮），這樣「文字→FB」的間距
     計算才能精準對應到文字實際可見的下緣，不是文字容器的下緣 */
  line-height: 1;
  /* 2026-09-08：改用獨立變數 --nav-fg-hint，跟水滴本身
     （--nav-fg-idle）綁定同一個顏色來源，不再跟 --nav-fg-muted
     共用——業主要求「選單」二字要跟水滴顏色一致，但 --nav-fg-muted
     同時也控制扇形選單連結的預設色（Footer 上要維持白色），兩者
     用同一個變數會互相衝突 */
  color: var(--nav-fg-hint);
  opacity: 1;
  cursor: pointer;
  transition: color 0.35s var(--ease-water);
}
/* ⚠️ 2026-09-08 除錯記錄：業主反饋「社群」文字顏色有時候會跟
   水滴本身的顏色不一致。根因：水滴本身變色觸發條件是
   .nav-trigger:hover 或 .nav-trigger.is-open 兩者其一（見上方
   .droplet-icon .droplet-shape 的規則），但這裡原本只綁定了
   :hover，沒有 .is-open。選單展開後滑鼠移開水滴本體時，水滴
   因為 .is-open 條件繼續維持高亮色，但文字因為沒有對應規則就
   退回預設色，兩者就對不上了。修法：讓文字的變色條件比照水滴，
   同時綁定 :hover 跟 .is-open，之後任何跟水滴顏色綁定的元素
   都要記得檢查是否同時涵蓋這兩個觸發條件，不要只寫 :hover */
.nav-trigger:hover .droplet-hint,
.nav-trigger.is-open .droplet-hint {
  color: var(--nav-fg-hover);
}
/* 2026-09-08：業主要求「社群」二字不論收合／展開都固定顯示在
   水滴下方同一位置，拿掉原本「展開後淡出」的規則（原邏輯是怕跟
   扇形選單展開項目視覺互相干擾，業主確認不需要這層考量，希望
   提示文字位置全程一致，不要有出現/消失的過場）。
   .droplet-hint 因此不再需要響應 .nav-trigger.is-open，
   opacity:1、pointer-events 維持預設可點擊即可 */

/* ---- 扇形選單：以水滴為軸心，每個項目間隔固定 30 度展開 ---- */
.fan-menu {
  position: absolute;
  right: 8px;
  top: 17px;
  width: 0;
  height: 0;
}
/* 2026-09-08：以下原本是舊版扇形選單連結（.fan-menu a/button）的
   樣式規則已刪除——水滴選單早已從「6個站內連結扇形展開」全面換成
   「4個社群圖示垂直展開」（.fan-menu--social）。
   ⚠️ 2026-09-26 更正：上面這句話原本接著寫「全站已無任何 .fan-menu
   （不含 --social）的 HTML 元素，這組規則是死碼」，這是錯的、已刪除——
   實際上 index.html 的水滴選單元素 class 是 `fan-menu fan-menu--social`
   兩個 class 都掛著，這條 .fan-menu 規則本身（尤其是 width:0/height:0）
   仍然生效，之後任何人想在別處（例如手機版）重新設計這個元素的尺寸，
   記得這條規則也要一併覆蓋，不能只覆蓋 .fan-menu--social 那條，
   否則會像 2026-09-26 那次手機選單面板被壓成 0 大小的事故一樣重踩
   上面的 .fan-menu 基礎容器規則（position/width/height）仍然
   保留，因為 .fan-menu--social 元素同時帶有 .fan-menu 這個
   class，只覆蓋 top/left/transform，position:absolute 等其餘
   屬性仍然由這裡提供，不能一併刪除。 */

/* ---- 社群圖示垂直選單（2026-09-08 新增，取代原本站內導覽的
   扇形展開）----
   跟 .fan-menu 共用展開/收合的顯示邏輯（opacity + pointer-events
   由 .nav-trigger.is-open 觸發），但排列方式從「角度旋轉」改成
   「垂直往下堆疊」，不使用 --angle/--dist 這兩個 CSS 變數（那是
   給角度展開用的，這裡完全不需要）。每個連結固定往下位移
   固定的距離，用 nth-child 個別指定，不是用角度公式算出來的 */
/* ⚠️ 2026-09-08 除錯記錄：業主反饋 4 個社群圖示沒有以水滴為基準
   置中對齊。根因：原本用 right:0（圖示容器）疊加 right:8px
   （.fan-menu--social），這種「以右邊界為錨點」的定位方式，跟
   水滴本身（.nav-trigger 寬度只有 16px，水平中心在 .nav-trigger
   正中央）的水平中心對不上——圖示是 34px 寬，右邊界對齊到某個
   位置時，圖示的視覺中心點會落在比水滴中心更偏左的地方，兩者
   看起來就不是同一條垂直線。
   修法：捨棄 right 定位，改用標準的水平置中寫法
   （left:50% + transform:translateX(-50%)），直接讓每個圖示的
   幾何中心對齊到 .nav-trigger 容器的水平中心，這樣不管容器/圖示
   寬度將來怎麼調整，都能保證跟水滴在同一條垂直線上，不需要
   再手動核算 right 偏移量 */
.fan-menu--social {
  /* 2026-09-08 第七次修正：業主要求「文字→Facebook」間距再縮小到
     24px（先前是 32px）。公式方向已在上一輪驗證過正確，這次只需
     調整目標值：備援 top 值從 45px 同步減少 8px（間距少 8px）
     變成 37px */
  top: 37px;
  left: 50%;
  transform: translateX(-50%);
}
.fan-menu--social a {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%) translateY(0);
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 2026-09-08：改用獨立變數 --nav-fg-social-icon，不再共用
     --nav-fg-muted，讓這組社群圖示的顏色能獨立指定（業主要求
     default 顏色改成 grey-700）。
     ⚠️ 2026-09-08 除錯記錄：原本想比照 .nav-trigger.is-over-dark
     的做法，用「整組共用一個開關」控制全部圖示變色，但業主反饋
     捲到接近頁面底部展開水滴時，只有部分圖示（展開後距離水滴
     較遠的 LINE/Threads）疊在 Footer 深色底上，另一部分圖示
     還在淺色背景，用同一個開關沒辦法同時滿足「部分變色、部分
     不變色」的實際畫面狀況。改成逐一判斷（見 main.js 的
     checkEachIconOverFooter），每個 <a> 各自獨立加上
     .is-over-dark-icon，不透過這裡的 --nav-fg-social-icon
     變數統一切換 */
  color: var(--nav-fg-social-icon);
  transform-origin: center;
  opacity: 0;
  pointer-events: none;
  /* 垂直往下展開：初始位移量是 0（跟水滴重疊），展開後移到各自
     固定的垂直位置，用 nth-child 逐一指定固定的位移量，不使用
     角度公式。
     ⚠️ 這裡務必只保留一個 transform 宣告，且水平置中的
     translateX(-50%) 要跟垂直位移疊加寫在同一個屬性值裡
     （見上方第 30 行已經寫好的 translateX(-50%) translateY(0)）。
     2026-09-08 曾經在這裡多寫一次 `transform: translateY(0)`，
     CSS 同屬性後寫的會直接覆蓋前面整個值，導致收合狀態圖示的
     translateX(-50%) 消失、只剩 left:50% 定位（等於用左邊界對齊
     而非幾何中心對齊），跟水滴中心線對不上，一展開才因為
     nth-child 規則補回 translateX(-50%)，視覺上就變成「先往左跳
     一下才往下展開」。已刪除這行重複宣告，不要再加回來。 */
  transition: opacity 0.45s var(--ease-water),
              transform 0.55s var(--ease-spring),
              color 0.3s;
}
/* 2026-09-08：逐一判斷機制的個別覆蓋規則——只有真正疊在 Footer
   深色背景上的那個圖示才會套用這個淺色，其他還在淺色背景上的
   圖示維持原本的 --nav-fg-social-icon 深色，不會整組一起變色 */
.fan-menu--social a.is-over-dark-icon {
  color: var(--white);
}
.fan-menu--social a.is-over-dark-icon:hover {
  /* 業主要求 hover 顏色跟「水滴亮燈時」用同一個深色，直接引用
     --nav-fg-link-hover——這個變數在 .nav-trigger.is-over-dark
     情境下就是 var(--ink)，跟水滴本身 hover/亮燈時的深色語意
     一致，不寫死色號，未來若這組深色定義調整，這裡會自動跟著變 */
  color: var(--nav-fg-link-hover);
}
.fan-menu--social a svg {
  width: 22px;
  height: 22px;
}
.nav-trigger.is-open .fan-menu--social a {
  opacity: 1;
  pointer-events: auto;
}
.nav-trigger.is-open .fan-menu--social a:nth-child(1) { transform: translateX(-50%) translateY(48px); }
.nav-trigger.is-open .fan-menu--social a:nth-child(2) { transform: translateX(-50%) translateY(96px); }
.nav-trigger.is-open .fan-menu--social a:nth-child(3) { transform: translateX(-50%) translateY(144px); }
.nav-trigger.is-open .fan-menu--social a:nth-child(4) { transform: translateX(-50%) translateY(192px); }
.fan-menu--social a:hover {
  color: var(--nav-fg-link-hover);
  font-weight: 400; /* 圖示沒有文字粗細概念，這裡明確歸零，避免繼承到 .fan-menu a:hover 的 font-weight:700（雖然選擇器不同不會真的套用，這裡是防禦性寫法） */
}

/* ---- 語言切換（中／EN）----
   2026-09-08：雙語功能尚未上線，這組樣式先規劃好位置、供未來
   啟用時直接使用（見 index.html 對應的 HTML 註解）。獨立於
   .fan-menu--social（社群圖示）之外，不依附在已刪除的舊版扇形
   選單機制上（原本 .lang-item 樣式依附在 .fan-menu button.lang-item
   底下，隨舊機制一起被清理掉了，這裡重新獨立定義）。
   位置：社群圖示展開範圍最遠到 translateY(192px) + 圖示自身高度
   34px ≈ 226px，這裡再往下留一段間距，避免視覺上跟社群圖示黏在
   一起 */
.lang-toggle-standalone {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.45s var(--ease-water), transform 0.55s var(--ease-spring);
}
.nav-trigger.is-open .lang-toggle-standalone {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(-50%) translateY(250px);
}
.lang-item {
  font-family: var(--font-en);
  font-size: 13px;
  letter-spacing: var(--tracking-0);
  color: var(--nav-fg-social-icon);
  white-space: nowrap;
  transition: color 0.3s var(--ease-water);
}
.lang-item:hover {
  color: var(--nav-fg-link-hover);
}
.lang-item .current { color: var(--ink); }
.lang-item .divider { margin: 0 var(--space-1); opacity: 0.5; }

/* ==========================================================================
   Hero — 硬幣落水 / Logo 生成
   ========================================================================== */
/* .hero-scroll-track：實際佔用文件高度的捲動軌道（200vh，由 JS 的
   COIN_SCROLL_VH 常數控制，之後要調整動畫捲動距離長短，改那個常數
   即可，不用改這裡的寫死數字——這裡的 200vh 只是 CSS 尚未執行 JS
   前的備援初始值，避免 JS 還沒跑完前 layout 高度是 0）
   .hero-pin：用原生 CSS sticky 卡住畫面，捲動軌道期間全程停在
   視窗內，內部疊放水波紋 + 硬幣序列幀 canvas + SCROLL DOWN 提示。
   採用原生 sticky（不像 #recognition 用 JS 手動 fixed），是因為
   這裡只有單一個 pin 元素、沒有「兩個 sticky 要同步」的問題，
   不需要那麼複雜的手動控制。 */
.hero-scroll-track {
  position: relative;
  height: 200vh; /* 備援值，JS 會用 COIN_SCROLL_VH 覆蓋 */
}
.hero-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  min-height: 640px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: linear-gradient(to bottom, var(--grey-300) 0%, var(--grey-200) 75%, var(--grey-100) 90%, var(--white) 100%);
  overflow: hidden;
}

/* 硬幣 3D 即時渲染容器（Three.js renderer 掛載點）：
   取代前一版純 CSS rotateY 雙面翻轉的做法。這裡本身不做任何
   3D 變形，單純是一個佔滿版面的容器，Three.js 會在裡面塞入
   一個 <canvas>（尺寸由 JS 動態控制，跟隨這個容器的寬高）。
   位置先置中偏上（模擬硬幣從畫面內上方墜入），業主之後會再
   細調實際位置/尺寸。 */
.coin-3d-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
}
.coin-3d-container canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.ripple-rings {
  position: absolute;
  bottom: -64px;
  left: 50%;
  transform: translateX(-50%);
  width: 140vw;
  height: 560px;
  pointer-events: none;
  overflow: visible;
  /* 2026-09-07：中央水波紋改用 canvas 繪製後，這裡不再需要
     will-change: opacity（那是給 SVG 版本用的合成層提示，canvas
     每幀都是直接畫點陣圖，本身就是獨立的合成層，不需要額外提示）。
     canvas 版本效能瓶頸不在合成層策略，而在於避免用 SVG 對 r
     屬性做動畫這個做法本身，詳見下方 JS 繪製邏輯的說明 */
  display: block;
}
/* 2026-09-07：中央背景水波紋（.ripple-rings）已從 SVG + CSS 動畫改成 canvas + JS 繪製（見 main.js 的 initRippleCanvas）。
   2026-09-21：舊 SVG 版本專用的規則（.ripple-plane、.ripple-rings .ring 與 6 條 nth-of-type 延遲、@keyframes ripple-grow）
   已移除（沒有任何元素使用；原 <svg> 早已註解掉並一併移除），連同「為何改用 canvas」的完整根因說明逐字保存在
   《已移除程式碼備查_2026-09-21.md》E1。
   水波紋的視覺參數（scaleY(0.26) 橢圓壓扁、線寬、緩動、生長時長、圈間延遲）都寫在 main.js 的 initRippleCanvas 裡，
   要調整請改那邊。硬幣觸水水花（.splash-ripple／.splash-ripple-plane）是獨立的另一組規則，不受影響。 */

/* ---- 硬幣觸水水花（版本 A / B 比較用）：定位跟畫面中心的水波紋
   圓心共用同一個座標系（viewBox 800x800，跟 .ripple-rings 相同），
   由 JS 直接控制 stroke-dashoffset / opacity / transform，不用
   CSS @keyframes（時間軸要精準對齊硬幣墜落的 COIN_TIMELINE，
   見 main.js） ---- */
.coin-splash {
  position: absolute;
  bottom: -64px; /* 跟 .ripple-rings 用同一個定位基準，保證兩者
                    的橢圓水波紋圓心永遠對齊，不會出現「水花在這裡、
                    背景水波紋在那裡」的視覺不一致 */
  left: 50%;
  transform: translateX(-50%);
  width: 140vw;
  height: 560px;
  pointer-events: none;
  overflow: visible;
  z-index: 2; /* 疊在硬幣（z-index:1）之上 */
}
/* 橢圓化：跟 .ripple-plane 用同一個 scaleY(0.26) 壓扁手法，
   保證新水花的橢圓弧度跟背景既有水波紋完全一致，不是自己算
   一套不同的橢圓比例 */
.splash-ripple-plane {
  transform: scaleY(0.26);
  transform-box: view-box;
  transform-origin: 400px 400px;
}
.splash-ripple {
  fill: none;
  stroke: var(--white);
  stroke-width: var(--stroke-water);
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  opacity: 0; /* 初始隱藏，由 JS 依硬幣墜落進度控制 r / opacity */
}

/* 回彈水柱（僅版本 B）：尖底、圓潤頂端的水滴形路徑，只有外框
   線條（跟全站線描風格一致，不做實色填滿），JS 控制 scaleY
   模擬水柱從水面「拉起→回落」的動作，不重畫多個關鍵幀路徑 */
/* 入水水花（2026-09-20 換版）：兩片半調圓點水花，取代原本線描的尖底圓頂輪廓
   (.splash-column，像燭火)。路徑內嵌在 index.html #coin-splash 內，純填色白色。
   動畫由 main.js 的 splashSprays 驅動：硬幣觸水後「依時間播放」約 1.8 秒
   （長出→維持→淡出，見 main.js 的 SPRAY_DURATION_MS），不隨捲動速度縮短；
   opacity 與 scale 由 JS 逐格設定，從各片的「尖端」
   （靠近水面那一端）往外長，所以 transform-origin 是 viewBox 座標系裡的絕對位置
   （transform-box: view-box，與 .splash-ripple-plane 同一套技巧）。
   ⭐ 要微調位置／大小，改 index.html 內各片 <g transform="translate(x y) scale(0.05)">；
   尖端座標若跟著移動，這裡的 transform-origin 要一起改：
     左片尖端 = translate(330.81, 331.14) + 尖端SVG座標(499, 673) × 0.0625 = (362.0, 373.2)
     右片尖端 = translate(428.11, 338.36) + 尖端SVG座標(51, 999) × 0.0625 = (431.3, 400.8)
     （2026-09-20 放大 1.25 倍：scale 0.05→0.0625，translate 以尖端為錨點反推，
     所以尖端位置與下面的 transform-origin 都不用動） */
/* 波紋圈獨立圖層（2026-09-20）：業主要求「硬幣要在水波紋之上」。.coin-splash 的
   z-index:2 高於硬幣容器 .coin-3d-container 的 z-index:1，所以原本同一層的波紋線
   會蓋在硬幣上；波紋圈改放這一層（z-index:0，硬幣之下），水花仍在 .coin-splash
   （硬幣之上）。兩層共用同一組定位與 viewBox，圓心一致。 */
.coin-splash--under { z-index: 0; }
.splash-spray {
  opacity: 0;
  transform-box: view-box;
}
.splash-spray--left { transform-origin: 362px 373.2px; }
.splash-spray--right { transform-origin: 431.3px 400.8px; }
.splash-spray path { fill: var(--white); }

/* ---- Hero 開場祝福語：loading 結束後、硬幣掉落前的固定開場句 ----
   2026-09-23 根因修正（宗霖回報「沒有左右置中」＋「字級太大」）：
   ① 原本 left:62% 不是螢幕置中，是舊版依截圖比例「抓大概」留下的
      偏移錨點——實測 1920px 寬時區塊中心落在 x=1190px，螢幕中心是
      960px，差了 230px，並非置中。改成 left:50%，搭配既有的
      translate(-50%, 0)，區塊中心才會精準等於螢幕水平中心。
   ② 字級 clamp(24px,3vw,40px) 在 ≥1333px 寬（幾乎所有桌面）就會
      頂到 40px 的上限，等同固定 40px、且完全不隨螢幕縮放——跟
      about-tagline（「小城市，大創新」，--text-28=28px）這類同性質
      的中文短句相比明顯偏大。改用 --text-28 當新的視覺上限，
      比例同步縮小 vw 係數與下限，落款同步等比縮小。
   內距／落款字重（500 vs 主文 700）跟宗霖提供的參考截圖比對後
   視覺上一致，這次沒有改動。 */
.hero-intro-blessing {
  position: absolute;
  top: 32%;
  left: 50%;
  transform: translate(-50%, 0);
  width: max-content;
  max-width: 55vw;
  text-align: left;
  font-family: var(--font-cn);
  font-weight: 500;
  color: var(--white);
  text-shadow: 0 0 24px rgba(255, 255, 255, 0.35), 0 2px 12px rgba(0, 0, 0, 0.15);
  z-index: 5;
  opacity: 1;
  transition: opacity 1s var(--ease-water);
}
.hero-intro-blessing p {
  font-size: clamp(18px, 2.1vw, var(--text-28));
  line-height: 1.5;
  letter-spacing: var(--tracking-xs);
}
.hero-intro-blessing-attr {
  margin-top: var(--space-4);
  font-size: clamp(13px, 1.35vw, var(--text-18)) !important;
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.35em;
}
/* 落款前的破折號改用 CSS 畫一條線，不用兩個 EM DASH 文字字元——
   實測發現這個字型的 EM DASH（—）glyph 本身在字框內有留白，
   兩個字元排在一起會出現約 4px 的斷點縫隙（1920px 寬、18px 字級下
   量測到），是字型設計的先天限制，不是程式碼寫錯。字型原始檔裡
   雖然還有 HORIZONTAL BAR（U+2015）這個字符、兩個相鄰時剛好無縫
   接合，但目前子集化字型還沒收錄它，且 rebuild_font_subset.py
   目前只掃描中文表意文字（U+4E00–9FFF 等），不會自動掃到標點符號，
   採用它需要額外修改子集化腳本、多一層日後容易忘記的維護成本。
   改用純 CSS 畫線可以完全繞開字型相依性，長度用 1.8em 對齊原本
   兩個 EM DASH 加起來的實際墨色寬度（實測 35.5px／18px 字級，
   換算約 1.97em），粗細 1px 對齊原本單一 EM DASH 筆畫的實測粗細。 */
.hero-intro-blessing-attr::before {
  content: '';
  display: block;
  width: 1.8em;
  height: 1px;
  background: currentColor;
}
.hero-intro-blessing.is-gone {
  opacity: 0;
  pointer-events: none;
}
@media (max-width: 767px) {
  .hero-intro-blessing {
    max-width: 86vw;
    text-align: center;
    top: 26%;
  }
  .hero-intro-blessing-attr { justify-content: center; }
}

/* ---- Hero 湧泉文案：硬幣觸水後從水中浮上來的祝福短句 ----
   位置對齊水波紋中心正上方，業主提供的參考截圖裡文案落在畫面
   垂直中線偏上一點的位置，這裡用 top 百分比定位（不是跟隨水波紋
   容器動態量測，這段文字本身不需要跟水波紋圓心像素級精準對齊，
   只要視覺上「從水面附近浮起」的觀感正確即可）。
   初始狀態完全透明 + 往下偏移一點，加上 .is-visible 時觸發淡入
   + 上浮到最終定位的動畫，這個 class 由 main.js 在硬幣真正觸水
   的瞬間加上去（詳見 initCoin3D 內的 hasTouchedWater 判定）。
   2026-09-22 五次修正，宗霖最終定案：就是橫式的
   "上句，下句" 直接轉成直排——右欄（逗號前，含右引號）與左欄
   （逗號後，含左引號）都是純文字流，不用絕對定位、不用
   transform、不用額外分層，見 main.js pickHeroBlessing。容器本身
   是橫向 flex（排列兩個直排欄位的順序，中文直排由右至左閱讀，
   右欄在前／左欄在後，用 row-reverse 讓 HTML 順序對應到正確的
   視覺順序），每個 .hero-blessing-col 自己是獨立的 vertical-rl
   直排欄，text-orientation: upright 讓引號／逗號／句號這類非表意
   符號正立顯示（不設定的話會被自動旋轉縮小成小圓點）。 */
.hero-blessing {
  position: absolute;
  top: 14%;
  left: 50%;
  transform: translate(-50%, 24px);
  display: flex;
  flex-direction: row-reverse;
  /* 2026-09-23 從 center 改回 flex-start：引號已經脫離文字流、改用
     JS 絕對定位（見 js/main.js positionHeroBlessingQuotes），兩欄
     不再各自被引號佔位擠歪，flex-start 才能讓「兩欄的第一個字」
     精準對齊在同一個高度，這是宗霖這輪明確要的效果。 */
  align-items: flex-start;
  gap: var(--space-2);
  width: max-content;
  max-height: 60vh;
  max-width: 90vw;
  font-family: var(--font-cn);
  font-weight: 500;
  /* 2026-09-23 從斷點式（手機 26px／桌機固定 32px，中間不隨寬度變化）
     改成流體 clamp，用線性內插公式精算：767px（手機斷點）＝26px、
     1333px（跟 .hero-intro-blessing 用同一組轉折寬度，維持全站一致）
     ＝32px，中間平滑過渡，不是憑感覺湊的係數。 */
  font-size: clamp(26px, 17.87px + 1.06vw, var(--text-32));
  letter-spacing: var(--tracking-tight);
  color: var(--white);
  text-shadow: 0 0 24px rgba(255, 255, 255, 0.5), 0 2px 12px rgba(0, 0, 0, 0.15);
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.4s var(--ease-water), transform 1.4s var(--ease-water);
  z-index: 5; /* 疊在水波紋 canvas 之上、硬幣 3D 容器之下，跟業主截圖的視覺層次一致 */
}
.hero-blessing-col {
  writing-mode: vertical-rl;
  text-orientation: upright;
  text-align: center;
}
/* 2026-09-23 第六輪修正：引號放棄文字流，改成 position:absolute
   （.hero-blessing 本身已經是 position:absolute，可以直接當定位
   環境，不用再多包一層容器）。left/top 由 js/main.js
   positionHeroBlessingQuotes() 在每次抽句子、視窗尺寸改變、字體
   載入完成後即時量測「右欄第一字」「左欄句尾字」的實際邊界計算，
   這裡不寫死數值。字重維持 medium(500) 跟主文字一致。
   字級：宗霖先選定 0.6em，看實際渲染後回報還是太小，再從三版
   放大比例（0.7／0.8／0.9em）比對選定 0.9em（現版）。 */
.hero-blessing-quote {
  position: absolute;
  writing-mode: horizontal-tb;
  font-size: 0.9em;
  font-weight: 500;
  pointer-events: none;
}
.hero-blessing.is-visible {
  opacity: 1;
  transform: translate(-50%, 12px);
}
/* 2026-09-23 宗霖要求筆電寬度下再往下 8px，之後又再追加一次 8px
   ——用常見筆電寬度區間 1025–1440px 疊加位移，最終跟基礎的 12px
   相加＝28px，不影響手機版（≤767px 走另一條 media query）跟大於
   1440px 的螢幕 */
@media (min-width: 1025px) and (max-width: 1440px) {
  .hero-blessing.is-visible {
    transform: translate(-50%, 28px);
  }
}
/* 2026-09-23 宗霖確認大螢幕（>1440px）要往下移到「置中」——跟
   v91 的差別是：v91 是「不分螢幕大小全部改成置中」，這次限定只在
   大螢幕才生效，筆電（1025–1440px）跟手機維持原本各自的數值不受
   影響。top 改 50%、is-visible 的 transform 垂直分量改 -50%，
   兩者搭配才是整個文字區塊置中（不是只有頂端對齊在畫面中線）。
   base rule（淡入動畫起始點）維持「比最終位置再往下一點」的寫法，
   用 calc(-50% + 12px) 保留原本「淡入時上升 12px 就定位」的動畫
   幅度，只是起點跟終點都往下平移到置中的位置。 */
@media (min-width: 1441px) {
  .hero-blessing {
    top: 50%;
    transform: translate(-50%, calc(-50% + 12px));
  }
  .hero-blessing.is-visible {
    transform: translate(-50%, -50%);
  }
}
@media (max-width: 767px) {
  .hero-blessing {
    top: 12%;
    max-height: 66vh;
  }
}

.scroll-cue {
  position: absolute;
  bottom: var(--space-4);
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-en);
  font-size: var(--text-18);
  letter-spacing: var(--tracking-0);
  color: var(--grey-700);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

/* ==========================================================================
   Section 通用
   ========================================================================== */
.section {
  position: relative;
  padding: var(--space-32) var(--section-side-padding);
}
/* 跟「小城市，大創新」區塊底部（漸層終點是 grey-300）用同一個灰階，
   純色、不做漸層，讓兩區塊交界處沒有明顯色差 */
.section--grey { background: var(--grey-300); }
.section--white {
  background: var(--white);
  /* 此區塊轉場大圓角屬於「版面簽名」造型，非一般 UI 圓角，
     刻意獨立於 4/8/16/999 的元件圓角系統之外，數值可與你討論後調整 */
  border-radius: 60px 60px 0 0;
  margin-top: -60px;
}
/* 「代表案例」單獨覆蓋成跟 Hero 反向銜接的漸層（其餘沿用
   .section--white 共用的大圓角轉場樣式，例如合作夥伴區塊仍維持
   白底，不受這條規則影響）。
   2026-09-07：業主要求把「代表案例」搬到 Hero 跟「關於我們」之間，
   原本這段「跟 Hero 反向銜接的漸層」規則是寫在 #about 上（那時候
   About 緊接在 Hero 後面），現在 Hero 後面變成 Showcase，改由
   Showcase 接手這段漸層邏輯，讓視覺上自然銜接 Hero 的收尾。
   #about 則改成純灰底（見下方 #about 規則），接手原本 Showcase
   的角色 */
#showcase {
  /* 跟 Hero 用同一組漸層參數與色階，方向上下翻轉：
     Hero 是「上灰(grey-300) → 下白」，這裡改成「上白 → 下灰(grey-300)」 */
  background: linear-gradient(to top, var(--grey-300) 0%, var(--grey-200) 75%, var(--grey-100) 90%, var(--white) 100%);
  /* 不要圓角轉場，維持方正 */
  border-radius: 0;
  /* 取消共用的 -60px 上疊效果：Hero 底部有 SCROLL DOWN 文字，
     疊上去會被蓋住，所以緊接在 Hero 下方的區塊要改成不上疊 */
  margin-top: 0;
}
/* #about 現在接手原本 Showcase 的純灰底角色，跟後面的
   #recognition 用同一階純灰無縫銜接，不要漸層、不要圓角轉場 */
#about {
  background: var(--grey-300);
  border-radius: 0;
  margin-top: 0;
}
.section-inner {
  max-width: var(--container-max);
  margin: 0 auto;
}

/* ==========================================================================
   About 區塊
   ========================================================================== */
.about {
  position: relative;
  min-height: 90vh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
/* 上排：( ABOUT US ) 標籤 + 「小城市，大創新」標語，左右對齊 */
/* 2026-09-11 修正：業主指出這裡的中英標排列方式錯了，應該跟
   子頁面（.page-header/.page-label/.page-title）用同一套規範
   ——英標在左上角、中標緊接在下方，不是左右並排（原本
   justify-content:space-between 是「小城市，大創新」這種短句
   橫向對齊時的舊排法，現在中標內容已經改成「關於我們」這種
   區塊標籤名稱，要統一成全站慣例）。
   容器改成 position:relative，讓內部的英標／中標可以用固定座標
   定位，不再依賴 flex 的左右對齊 */
.about-top-row {
  position: relative;
  min-height: 100px;
}
.about-label {
  writing-mode: vertical-rl;
  font-family: var(--font-en);
  font-size: var(--text-16);
  letter-spacing: var(--tracking-0);
  color: var(--grey-700);
  /* 業主明確要求「英標視覺位置不要變」——原本用 flex item 自然
     排列在容器左側、跟中標同一水平線，這裡改成絕對定位疊在
     左上角，數值上量測過跟原本 flex 排列的視覺位置完全相同
     （left:0 對齊容器左邊界，top:0 對齊容器頂部），只是定位
     方式從「flex 排列」換成「絕對定位」，才能讓下方中標脫離
     跟它左右並排的關係，改成緊接在下方。
     ⚠️ 這裡不需要任何 JS 對齊邏輯：2026-09-08 已確認 Header
     navbar 改成滿版延伸、不受 1240px 容器限制後，繼續用 JS
     對齊 Logo 水平位置反而會把這個標籤拖出 1240px 最大寬度
     範圍，當時的 alignAboutLabelToLogo 函式已經整個移除，
     .about-label 本身已經在 .section-inner（1240px 容器）內，
     維持 CSS 原生排版位置即可 */
  position: absolute;
  top: 0;
  left: 0;
}
.about-tagline {
  font-family: var(--font-cn);
  /* 2026-09-12 宗霖回報「關於我們」中標字級目測比其他區塊小，
     要求統一。這裡原本是固定 36px（曾是宗霖明確指定的值，見
     舊註解），比全站其他中標（.page-title／.contact-title 用的
     clamp(26px,3vw,38px)，在桌面寬度下等於 38px）小了 2px，
     且是固定值、不是響應式 clamp，行為機制也跟其他標題不一致。
     改用同一套 clamp(26px,3vw,38px)，跟全站字級統一 */
  font-size: clamp(26px, 3vw, 38px);
  font-weight: 700;
  /* 跟子頁面 .page-title 同一套邏輯：英標改絕對定位後不再佔用
     文件流高度，中標改用固定的 padding-top 直接往下推，緊接在
     英標下方，不是左右並排。
     2026-09-11 修正根因：原本這裡是 128px，理由寫著「沿用
     .page-label 實測高度 100px 多留一點餘裕」，但這個「多留
     餘裕」的估算從未真正用 Playwright 驗證過跟子頁面的視覺
     間距是否一致，導致宗霖實際比對時發現這裡明顯比其他頁面
     寬（截圖確認肉眼可見的明顯留白差距）。
     用 Playwright 實測（先歸零 padding-top 量出基準間距，
     再反推精準值）發現，子頁面 .page-label→.page-title 的
     文字視覺間距統一都是 22px（.page-title 用 JS 動態校正
     margin-top 達成），首頁這裡用寫死的固定值也應該對齊到
     同一個 22px 基準，而不是自己另外估一個「安全值」。
     算出的精準值是 87px，不是 128px，取代原本沒有實測依據
     的保守估算 */
  /* 2026-09-24：87px 留白改由外層 .about-title-row 承擔（中標右側加了 CTA，需要中標＋CTA 同一列 flex），
     數值與實測依據不變，這裡歸零 */
  padding-top: 0;
  display: block;
}
/* 2026-09-24 新增：首頁「關於我們」中標＋右側「了解更多」CTA 同一列。
   比照 .services-title-row：flex、align-items:center 讓 CTA 與中標垂直置中，
   justify-content:space-between 讓 CTA 靠右對齊 .section-inner（max-width 1240px）容器右緣。
   padding-top:87px 是原本中標自帶、英標到中標視覺間距 22px 的實測值（見上方 .about-tagline 說明），
   搬到這一層後整列高度與位置不變（實測 h2 列高度、下方照片位置與修改前相同） */
.about-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-top: 87px;
}
/* CTA 精準靠右／不撐高版面：
   ① padding-right 歸零，文字右緣才會剛好貼齊容器右緣（.cta-arrow 本體預設左右各 8px）；
      padding-left 也歸零（與 footer／service 頁 CTA 同一個坑，見 v110）
   ② 上下 16px 內距改用等量負 margin 抵銷：保留原本的點擊熱區，但不參與 flex 高度計算，
      整列高度仍由中標決定，下方照片位置不會被 CTA 撐開 */
/* ⚠️ 選擇器多帶 .about-title-row：本規則位置在 .cta-arrow（後面才定義）之前，同為單一 class 的話
   會被後面的 .cta-arrow { padding:16px 8px } 蓋掉（實測 padding 沒生效），多一層 class 提高優先權 */
.about-title-row .about-more-cta {
  padding: var(--space-4) 0;
  margin-block: calc(-1 * var(--space-4));
  flex-shrink: 0;
}
/* 底圖區塊：業主要求水平置中，寬度為內容容器（.section-inner，
   最大 1240px）的 80%，比之前的 58% 明顯放大許多，上下文案的
   間距會因此被自然撐開，這是預期中的效果，不用額外處理 */
.about-showcase {
  display: block;
  width: 80%;
  margin: var(--space-16) auto;
}
/* 2026-09-11：業主要求首頁「關於我們」中標到照片的間距，仿照
   子頁面 about.html 的視覺間距（140px）。子頁面之所以是 140px，
   是因為 .page-header 容器本身有 128px 的 padding-top（用來統一
   全站標題垂直位置），跟首頁 .about-top-row 用絕對定位、不佔用
   直向空間的結構完全不同，沒辦法只靠共用的 .about-showcase
   margin 數值自動對齊。這裡用 #about 精準只覆蓋首頁這個區塊的
   margin-top，不動 .about-showcase 本身的共用規則（避免連動影響
   about.html 也在用同一個 class 的地方） */
#about .about-showcase {
  margin-top: 140px;
  margin-bottom: 140px;
}
/* 2026-09-26 根因修正（宗霖回報：手機版「關於我們」照片跟上方中標／
   下方 slogan 的間距太開）：手機版 767px 斷點原本就寫了
   `.about-showcase { margin: var(--space-8) auto; }`（32px）想縮小
   這個間距，但實測 computed margin 仍是 140px，覆蓋完全沒生效。
   根因是選擇器優先權：上面這條 `#about .about-showcase` 帶了 ID，
   優先權（1,1,0）永遠贏過手機版那條純 class 選擇器 `.about-showcase`
   （0,1,0），不管後者寫在哪個 media query 裡、寫在檔案多後面都一樣
   會輸——這是全站另外幾處已經踩過的同一類坑（見 README 教訓第 8
   點）。在這個斷點用同樣帶 #about 的選擇器覆蓋，才能真正贏過上面
   這條規則 */
@media (max-width: 767px) {
  #about .about-showcase {
    margin-top: var(--space-8);
    margin-bottom: var(--space-8);
  }
}
/* 子頁面 about.html 用同樣的邏輯，數值先測試後校準（因為子頁面
   .page-header 結構跟首頁 .about-top-row 不同，collapse 情境
   也不同，不能直接套用跟首頁一樣的數字） */
html[data-page="about"] .about-showcase {
  margin-bottom: 140px;
}
/* 2026-09-26 根因修正（宗霖要求：手機版關於我們子頁面照片跟上下
   內容的間距，套用跟首頁同一天修正的間距）：跟首頁 #about
   .about-showcase 那次踩到的是同一種選擇器優先權問題——
   `html[data-page="about"] .about-showcase`（屬性選擇器＋class，
   優先權跟 2 層 class 相當）比手機版基礎規則的純 class 選擇器
   優先權更高，導致手機版原本想縮小成 32px 的 margin-bottom 覆蓋
   完全沒生效，一直吃到桌機版的 140px。修法跟首頁那次一致：在
   手機斷點內用同樣帶 `html[data-page="about"]` 的選擇器覆蓋，
   才能真正贏過上面這條規則 */
@media (max-width: 767px) {
  html[data-page="about"] .about-showcase {
    margin-bottom: var(--space-8);
  }
  /* 2026-09-26 第二輪根因修正（宗霖回報：修完 margin-bottom 後，
     照片跟上方「關於我們」中標的間距還是太大，要求對齊首頁同一
     區塊的視覺間距）：上一輪只修了 margin-bottom，沒注意到頂部
     間距的根因完全不同、需要另外處理。
     根因：子頁面「中標到照片」這段路徑，實際經過 .page-header
     （margin-bottom:64px，全站子頁面共用元件）→ .about-showcase
     （margin-top:32px）兩層 margin。首頁的對應路徑（.about-tagline
     → .about-showcase）沒有經過任何帶 margin-bottom 的獨立容器，
     只有 .about-showcase 自己的 margin-top:32px 在起作用（另外
     還有 .about-title-row 內部高度差異造成的約 33px，這部分是
     排版結構本身的自然高度，不是刻意設計的間距，不去動它）。
     子頁面的 .page-header 跟 .about-showcase 是 .section-inner
     這個 flex 容器（display:flex; flex-direction:column，見 .about
     這個 class 的定義）的直接子元素——flex 容器的直接子元素之間，
     CSS 規範明確規定 margin 不會 collapse（合併取大值），只會
     維持各自獨立、疊加相加，所以子頁面的間距是 64+32=96px 相加，
     而不是像一般文件流那樣取兩者較大值，這也是子頁面間距明顯
     比首頁大出一截的根因。
     用 Playwright 實測反推校正值：首頁手機版「中標到照片」總
     視覺間距是 65px，這裡讓 .page-header 的 margin-bottom 跟
     .about-showcase 的 margin-top(32px) 相加後正好貼齊 65px，
     反覆測試後 21px 是精準對齊的數值（不是設計 token，是專門
     為了「對齊另一個區塊的既有間距」反推出來的校正值，量測基準
     若未來變動需要重新反推，不是單純套用 --space 系列可以直接
     算出來的）。
     scope 限定只在 about.html（html[data-page="about"]），
     .page-header 是全站子頁面共用元件（contact.html／faq.html／
     work-detail.html 等都在用），不能直接改基礎規則影響到其他頁 */
  html[data-page="about"] .page-header {
    margin-bottom: 21px;
  }
}
.about-showcase img {
  width: 100%;
  height: auto;
  display: block;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
/* 下排：標題 + 內文，靠左對齊，跟上排之間留大片空白 */
.about-bottom-block {
  /* 業主要求跟獎項小卡（.award-detail-list 兩欄 grid）同一個
     最大寬度公式：(容器寬度 - gap) / 2，gap 對應
     .award-detail-list 的 gap:var(--space-8)，取代原本寫死的
     640px，兩者之後如果要調整都能連動 */
  max-width: calc((100% - var(--space-8)) / 2);
}
.about-headline {
  font-family: var(--font-cn);
  font-weight: 700;
  /* 業主指定固定 32px（原本是響應式 clamp，改成固定值） */
  font-size: 32px;
  line-height: 1.35;
  letter-spacing: var(--tracking-xs);
  margin-bottom: var(--space-5);
  white-space: nowrap;
}
.about-headline em {
  font-style: normal;
  /* 拿掉原本的灰色強調，全部統一黑字 */
  color: inherit;
}
.about-desc {
  font-size: var(--text-16);
  line-height: var(--leading-3);
  color: var(--ink);
  letter-spacing: var(--tracking-xs);
}
/* 兩段之間的間距用 margin-top 精準控制，不再依賴疊兩個 <br>
   （那種做法間距會直接綁定行高，沒辦法獨立微調，跳動感也偏大） */
.about-desc--second {
  margin-top: var(--space-6);
}

/* ==========================================================================
   品牌里程碑時間軸（首頁 #about 與 about.html，2026-09-20 新增；2026-09-21 關於我們頁也放一份）
   顧問建議（E-E-A-T「Experience 經驗度」）：把品牌的年份事件整理成時間軸。
   結構：<ol.timeline> 每個 <li.timeline-item> ＝ 一個年份（<time>）＋ 該年事件清單。
   版面：桌機／平板＝橫向多欄（每個年份一欄，CSS grid auto-fit，新增一年會自動
   多一欄或換行）；手機（≤767px）＝直向，線在左側。
   線與節點畫在 .timeline-events 的 ::before／::after（不寫死像素位置，事件多寡
   都對得準）。全部沿用既有 token：--font-en（年份，Bodoni Moda）、--font-cn、
   --ink、--grey-700、--space-*、--text-*。
   動態：沿用全站 data-reveal（進場淡入）；沒有 JS 時由各頁 <noscript> 規則
   強制顯示，不需要額外處理。
   ========================================================================== */
.about-timeline {
  margin-top: var(--space-32);
}
.about-timeline-header {
  margin-bottom: var(--space-16);
}
.timeline {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(224px, 1fr));
  /* 欄距用每個項目的 padding-right 做，而不是 grid 的 column-gap：這樣橫線可以
     直接畫滿整個項目寬度（＝自然接到下一欄），且每一列最後一欄的線剛好停在容器
     右緣，換行時不會多伸出去造成橫向溢出。 */
  column-gap: 0;
  row-gap: var(--space-16);
}
.timeline-item {
  position: relative;
  padding-right: var(--space-8);
}
.timeline-year {
  display: block;
  font-family: var(--font-en);
  font-weight: 500;
  font-size: var(--text-20); /* 2026-09-20 業主要求：--text-24 → --text-22 → 再改 --text-20（＝「合作夥伴」中文標題同級 20px） */
  line-height: 1;
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
  margin-bottom: var(--space-4);
}
.timeline-events {
  list-style: none;
  position: relative;
  padding-top: var(--space-6);
}
/* 橫線：畫滿整個項目寬度（項目的 padding-right 就是欄距），相鄰欄的線自然連成
   一條；每一列最後一欄停在容器右緣。.timeline-events 本身要延伸到 padding 之外，
   所以用負的 right 抵銷項目的 padding-right。 */
.timeline-events::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: calc(var(--space-8) * -1);
  height: 1px;
  background: var(--ink);
}
/* 節點：壓在橫線左端 */
.timeline-events::after {
  content: '';
  position: absolute;
  top: -4px;
  left: 0;
  width: 9px;
  height: 9px;
  border-radius: var(--radius-full);
  background: var(--ink);
}
.timeline-event + .timeline-event {
  margin-top: var(--space-6);
}
.timeline-event-type {
  display: block;
  font-size: var(--text-14);
  line-height: var(--leading-2);
  letter-spacing: var(--tracking-xs);
  /* 2026-09-20 業主反映「品牌成立／年度肯定／獲獎」太淺：實測原本的 --grey-800 在網站
     色票下渲染為 rgb(115,115,115)，而案名與獎項說明是 --ink＝rgb(80,80,80)；
     改用 --ink，與同一區塊其他文字一樣深（筆畫核心亮度 120 → 88）。 */
  color: var(--ink);
}
.timeline-event-title {
  display: block;
  font-weight: 700;
  font-size: var(--text-16);
  line-height: var(--leading-2);
  color: var(--ink);
  margin-top: var(--space-1);
}
.timeline-event-desc {
  display: block;
  font-size: var(--text-14);
  line-height: var(--leading-3);
  color: var(--ink);
}
/* 平板：固定兩欄（4 個年份排成 2＋2，避免 auto-fit 排成 3＋1 讓最後一個孤伶伶） */
@media (max-width: 1024px) {
  .timeline { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 767px) {
  .about-timeline { margin-top: var(--space-24); }
  .about-timeline-header { margin-bottom: var(--space-12); }
  /* 手機：直向時間軸，線在左側，每個年份一個節點 */
  .timeline {
    grid-template-columns: 1fr;
    row-gap: var(--space-12);
    border-left: 1px solid var(--ink);
    padding-left: var(--space-6);
  }
  .timeline-year { position: relative; margin-bottom: var(--space-3); }
  .timeline-year::before {
    content: '';
    position: absolute;
    top: 50%;
    left: calc((var(--space-6) + 1px) * -1 - 4px);
    width: 9px;
    height: 9px;
    border-radius: var(--radius-full);
    background: var(--ink);
    transform: translateY(-50%);
  }
  .timeline-item { padding-right: 0; }
  .timeline-events { padding-top: 0; }
  .timeline-events::before,
  .timeline-events::after { display: none; }
}

/* ==========================================================================
   設計實力區塊 + 獲獎清單
   ========================================================================== */
/* 2026-09-01 業主要求：上下內距統一128px，移除原本 96px 的特例
   （原本沒有留下說明理由的註解，判斷是遺留的不一致，非刻意設計），
   現在跟其他五個內容區塊（關於我們／代表案例／合作夥伴／常見問題／
   聯絡我們）一致，全部沿用 .section 的基礎 padding: var(--space-32)
   var(--space-12)，不再另外覆蓋。 */
/* 標題 CTA 區塊在跟公司 Logo 頂部平行時卡住（top 對齊 header 的
   padding-top，也就是 var(--space-6) = 24px），生效範圍是父層
   .recognition-sticky-zone 的整個高度（含底下的獲獎清單捲動軌道），
   所以會一路卡住到獲獎卡片完全展開、捲動軌道結束才解除 */
.recognition-sticky-zone {
  position: relative;
}
/* .stat-block-sticky 內部用 flex 左圖右文並排，圖片跟文案同屬一個
   被 JS 動態 position:fixed 控制的容器，會一起卡住、一起解除，
   不需要另外寫同步邏輯。
   容器本身撐滿寬度（跟 .stat-block-spacer 同寬 = 內容區全寬），
   justify-content:space-between 讓圖片貼齊容器左邊界（＝ Logo
   左邊界，兩者共用同一個 .section-inner 置中公式）、文案維持貼齊
   容器右邊界（呼應原本 .stat-block 的靠右對齊視覺） */
.stat-block-inner {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-8);
  width: 100%;
}
.recognition-showcase {
  /* 根因：flex-shrink:0 讓這個元素永遠不縮小，寬度固定
     min(38%, 480px)。當容器（螢幕）縮小到不足以同時容納「固定
     寬度圖片 + 固定 gap + 右側文字」時，右側文字沒有退讓空間，
     內容溢出容器邊界，業主稱為「貼邊」的視覺瑕疵。業主明確要求
     圖片也要能跟著螢幕縮小，拿掉 flex-shrink:0，改成
     flex-shrink:1（預設值，可以縮小），寬度上限維持不變。
     高度原本寫死 300px（JS 尚未執行前的備援值，有 JS 時會被
     main.js measurePanelHeight 動態覆蓋成對齊右側文案的精準
     高度）。業主要求「螢幕夠大時固定高度、螢幕變小時等比例
     縮小」——改用 aspect-ratio 取代寫死的 height，讓寬度縮小時
     高度能跟著等比例縮放，不會維持 300px 不變導致比例失調
     （圖片又窄又高）。aspect-ratio 8/5 是取目前呈現尺寸
     480:300 化簡後的比例，跟原本視覺設計最接近。
     ⚠️ 這個 aspect-ratio 只在無 JS，或有 JS 但
     measurePanelHeight 尚未執行完成的極短暫過渡時間生效——
     有 JS 執行完成後，JS 動態設定的 inline style height 優先權
     比這裡的 CSS class 高，會直接覆蓋，維持原本「精準對齊右側
     文案高度」的效果，不受這次改動影響 */
  flex-shrink: 1;
  min-width: 0;
  width: min(38%, 480px);
  aspect-ratio: 8 / 5;
  overflow: hidden;
}
.recognition-showcase img {
  /* 改成撐滿容器高度（由 JS 控制），不再用 aspect-ratio 自動撐開，
     因為現在高度是外部指定的目標值，圖片本身要完全填滿、多餘的
     部分用 object-fit:cover 從中央裁切，避免變形 */
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  /* 2026-09-09 業主確認：裁切基準改為正中央（object-position 的
     預設值即為 center，等同 50% 50%）。先前這裡寫的是 top left
     （左上角基準），跟上方註解「從中央裁切」的描述互相矛盾，是
     先前某次改動只更新了這裡、沒同步修正上方舊描述遺留的文件
     不同步問題，業主確認後改回中央裁切，兩段註解現在一致 */
  object-position: center;
}
/* 手機版（767px 以下，見文末 RWD 區塊）改為上圖下文堆疊排版並
   顯示；768px～1024px 這段中間寬度目前沿用桌機版的左圖右文
   並排，暫不特別處理（可能會偏擠，之後有需要再細調） */
.stat-block-sticky {
  /* 改用 JS 全程手動控制（見 js/main.js），不再用 CSS 原生 sticky。
     原因：原生 sticky 的「何時卡住」「何時放開」是同一組數學算出來的，
     沒辦法同時滿足「卡住時機要準」又「保證比獎項舞台早放開」這兩個
     各自獨立的要求。改成 JS 每一幀直接算：
       - 還沒捲到 Logo 高度：跟著自然位置走（不卡）
       - 捲到 Logo 高度、但獎項動畫還沒播完：卡在 24px
       - 獎項動畫播完（一定比獎項舞台自己放開的時間點早，因為
         軌道高度公式刻意多留了緩衝）：立刻放開，之後用捲動位置
         直接算出對應的絕對座標，跟著頁面 1:1 平滑移動，不會有跳動。
     搭配 .stat-block-spacer 固定佔位，全程用 position:fixed，
     不再中途切換定位方式，排版永遠不會位移，也就不會有彈射炮感 */
  position: fixed;
  top: var(--space-6);
  z-index: 10;
  /* ⚠️ 根因記錄：這個元素在 JS 完成第一次定位計算前，會用這裡
     寫死的初始 top 值（24px）顯示，固定卡在螢幕頂部。如果使用者
     是從頁面深處（例如捲到後面的 showcase 區塊附近）重新整理，
     瀏覽器通常會保留原本的捲動位置，但 JS 要等 DOMContentLoaded
     才開始執行——這段「瀏覽器已還原深捲動位置、JS 尚未接手計算
     正確 top 值」的空窗期，會讓這個 fixed 元素顯示在錯誤（頂部）
     位置，疊在畫面當下捲動到的區塊上面，直到 JS 算完才「跳」到
     正確位置。修法：預設先隱藏，JS 算出正確 top 值後才用
     .is-ready 顯示出來，不改動任何 sticky 核心計算邏輯 */
  visibility: hidden;
}
.stat-block-sticky.is-ready {
  visibility: visible;
}
.stat-block-spacer {
  /* 高度由 JS 設定，永遠跟 .stat-block-sticky 的實際高度一致 */
  visibility: hidden;
  /* 這裡才是 CTA 跟 ( AWARDS RECOGNITION ) 之間真正的視覺間距
     （原本誤加在 #recognition 的 padding-bottom，那個位置其實是
     整個區塊「最尾端」，跟畫面上這兩者中間的空隙完全無關，
     難怪調了視覺上沒感覺——已修正到正確的位置）
     2026-09-01 業主希望「(AWARDS RECOGNITION) 不漂移」且「精準
     跟 CTA 圓圈垂直置中對齊」同時達成。這兩個目標原本互相牽制：
     獎項舞台的 sticky top 取它自然抵達位置（見 js/main.js
     measurePanelHeight 的 naturalTopAtStatStuck 計算）來消除漂移，
     但這個自然位置由這段間距的大小決定，間距越大、自然位置越低，
     跟 CTA 的對齊落差就越大。
     從 128px(--space-32) 一路縮小到 48px(--space-12) 再到現在的
     6px，讓自然位置精準對齊 CTA 圓圈的垂直中心（377px），兩個目標
     同時達成，不用再犧牲其中一個。代價：CTA 跟 (AWARDS RECOGNITION)
     之間原本設計的視覺呼吸空間幾乎完全消失，兩者現在非常貼近
     （業主已確認要以此為優先）。 */
  margin-bottom: 4px;
}
.stat-block {
  text-align: right;
  /* 業主要求跟獎項小卡（.award-detail-list 兩欄 grid）同一個
     最大寬度公式：(容器寬度 - gap) / 2，取代原本寫死的 760px，
     跟「關於我們」（.about-bottom-block）採用同一套公式，兩處
     視覺寬度統一 */
  max-width: calc((100% - var(--space-8)) / 2);
  /* 根因：flex item 預設的最小寬度是「內容不換行時的自然寬度」，
     不是 0。這段文字內容不短，這個隱性下限可能比可用空間還大，
     導致螢幕縮小時內容溢出容器邊界（貼邊）。明確設為 0，讓它
     能安全隨可用空間縮小，改用容器寬度決定文字換行時機，不受
     內容本身自然寬度限制 */
  min-width: 0;
}
.stat-block h2 {
  font-family: var(--font-cn);
  font-weight: 700;
  /* 業主指定固定 32px（原本是響應式 clamp，改成固定值） */
  font-size: 32px;
  line-height: 1.35;
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
  margin-bottom: var(--space-5);
  white-space: nowrap;
}
/* 根因：white-space:nowrap 讓這行標題永遠不換行，寬螢幕下沒問題
   （標題本身就設計成一行），但螢幕縮小到不足以容納整行文字時，
   nowrap 會強制撐開容器寬度，導致內容溢出邊界（業主稱為「邋邊」
   的視覺瑕疵）。業主確認窄螢幕時可以允許標題自動換行成兩行，
   跟圖片 flex-shrink / stat-block min-width 的修正一起解決同一
   個貼邊問題的三個成因。寬螢幕（1025px 以上）維持原本單行設計
   不受影響 */
@media (max-width: 1024px) {
  .stat-block h2 {
    white-space: normal;
  }
}
.stat-block-lines {
  font-size: var(--text-16);
  color: var(--ink);
  line-height: var(--leading-3);
  /* 2026-09-13 改版：業主要求兩段文案改回獨立 <p>（不用 <br> 分行），
     採用區域文字自然換行。原本單一段落的 margin-bottom:40px（跟下方
     CTA 的視覺 gap）改移到第二段（.stat-block-lines--second）上，
     避免中間出現多餘間距 */
  white-space: normal;
  letter-spacing: var(--tracking-xs);
  /* 2026-09-15 修正：業主要求內文改成置左對齊，標題（.stat-block h2）
     跟 CTA 按鈕維持原樣（置右）不動。.stat-block 本體是
     text-align:right，h2／CTA 都沒有各自覆蓋、直接繼承這個右對齊，
     只有這兩段內文（.stat-block-lines）需要單獨覆蓋成置左 */
  text-align: left;
}
.stat-block-lines--second {
  /* 跟 .about-desc--second 用同一套「用 margin-top 精準控制段落間距」
     手法，取代原本的 <br> 分行 */
  margin-top: var(--space-6);
  margin-bottom: 40px;
}
.cta-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-en);
  font-size: var(--text-20);
  font-weight: 500;
  letter-spacing: var(--tracking-0);
  /* 2026-09-26 根因修正（宗霖回報：首頁很多圓圈圈按鈕都偏右一點）：
     這裡原本左右都是 --space-2(8px)。圓圈圈永遠是這個元件的第一個
     子元素（HTML 固定寫法：<span class="arrow-circle">➜</span> 在前，
     文字在後），只要這顆按鈕所在的容器是「靠左對齊、左緣要對齊某段
     文字或版面基準」的排版（例如首頁代表案例三個分類的「更多作品」、
     award.html 每張獎項卡片右側的官方認證連結在手機版收合成一欄時），
     這 8px 左內距就會把圓圈圈整個往右推 8px，跟上面/左邊的文字對不齊。
     這個坑過去已經在 3 個地方各自加 padding-left:0 修過（.footer-cta-link
     2026-09-14、.service-process-cta-link 2026-09-24、.about-more-cta
     2026-09-24），這次宗霖再次抓到「還有很多沒修到」（.showcase-cta 三個
     ＋award.html 六個 .cta-arrow--xs），代表每次遇到就補一個特例、
     永遠補不完，這裡直接把左內距歸零成為全站預設值。
     這樣改對「靠右對齊」的按鈕（.stat-block .cta-arrow--sm／
     .page-header-cta／.about-more-cta 這類容器右緣固定、文字是最後一個
     子元素的排版）不會有任何視覺影響：這類按鈕的容器右緣位置不變，
     整個按鈕的寬度縮小 8px 全部從左側「隱形內距」扣掉，圓圈圈的螢幕
     實際位置分毫不動，只有滑鼠熱區左側少了 8px（可忽略，熱區主體
     仍完整涵蓋圓圈圈與文字）。右側 8px 內距維持不變（各處 hover 熱區
     與呼吸感不變）。
     上面提到的 3 個舊特例規則變成多餘但無害（重複設定同一個值），
     為了不做超出這次需求的整理，先保留不動 */
  padding: var(--space-4) var(--space-2) var(--space-4) 0;
}
.cta-arrow .arrow-circle {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1px solid currentColor;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  background-color: transparent;
  transition: background-color 0.35s var(--ease-water), color 0.35s var(--ease-water);
}
.cta-arrow:hover .arrow-circle {
  background-color: var(--ink);
  border-color: var(--ink);
  color: var(--white);
}
/* 圓圈圈縮小一階修飾 class：28px → 24px（沿用設計系統既有的
   --icon-md 圖示階）。給「作品案例」（#recognition CTA）跟
   「更多案例」（showcase 動態 CTA）共用，這兩處業主指定要縮小，
   不動 .cta-arrow 本體，避免影響其他沿用預設尺寸的 CTA */
.cta-arrow--sm .arrow-circle {
  width: var(--icon-md);
  height: var(--icon-md);
}
/* 再縮小一階修飾 class：字級跟圓圈都比 --sm 更小一號
   （--icon-md 24px → --icon-sm 16px；字級 20px → 16px），
   獨立於 --sm 之外新增，不動既有的 --sm（首頁「作品案例」／
   「更多FAQ」CTA 仍維持原尺寸），專供獎項卡片「連結至作品頁」
   使用，因為卡片內部空間較侷促，業主要求比標準 --sm 再小一階 */
.cta-arrow--xs {
  font-size: var(--text-18);
  gap: var(--space-2);
}
.cta-arrow--xs .arrow-circle {
  width: var(--icon-md);
  height: var(--icon-md);
  font-size: var(--text-14);
}

/* 根因修正：.cta-arrow 本體自帶 padding:16px 0（上下），這個
   padding 算在按鈕本身範圍內，會跟 .stat-block-lines 的
   margin-bottom 疊加，導致「內文跟按鈕」的實際視覺間距
   （32+16=48px）遠大於「標題跟內文」的間距（20px），業主要求
   兩者視覺上要一致。這裡歸零 padding-top，改成完全由
   .stat-block-lines 的 margin-bottom 統一控制間距（已改成
   20px），才是精準對齊的最終視覺間距。只作用在「作品案例」
   這顆 CTA（唯一套用 .cta-arrow--sm 且直接跟在內文段落後面的
   情境），不影響其他沿用 .cta-arrow 預設 padding 的按鈕（例如
   作品案例列表頁等其他情境的 CTA） */
.stat-block .cta-arrow--sm {
  padding-top: 0;
}

/* ---- about.html 專屬：「設計實力推動產業與城市發展」靜態版 ----
   2026-09-11 新增：從首頁 #recognition 區塊複製過來的簡化靜態
   版本，不含 sticky 卡住/捲動 scrubbing 動畫、不含獲獎清單捲動
   小卡。樣式數值完全沿用首頁 .stat-block 系列的既有規範，但改用
   獨立的 about-recognition- 前綴，不共用 selector——這是刻意的，
   避免 main.js 裡 document.querySelector('.stat-block-sticky')
   這類選擇器意外抓到這裡的元素並嘗試套用 JS 邏輯（子頁面沒有
   對應的排版基準，直接沿用同名 class 有風險讓 JS 誤操作 DOM）。
   左圖右文排版邏輯對應首頁 .stat-block-inner + .recognition-showcase */
.about-recognition-inner {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-8);
  width: 100%;
}
.about-recognition-showcase {
  /* 對應首頁 .recognition-showcase：這裡沒有 JS 動態量測高度的
     機制（那是首頁 sticky 版面專屬的 measurePanelHeight），直接
     採用「無 JS/JS 尚未執行前」的備援樣式 aspect-ratio，本身就是
     完整可用的獨立排版方案，不需要額外處理 */
  flex-shrink: 1;
  min-width: 0;
  width: min(38%, 480px);
  aspect-ratio: 8 / 5;
  overflow: hidden;
}
.about-recognition-showcase img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center;
}
.about-recognition-block {
  text-align: right;
  /* 比照首頁 .stat-block／.about-bottom-block，統一改用跟獎項小卡
     同一個最大寬度公式，取代原本寫死的 760px */
  max-width: calc((100% - var(--space-8)) / 2);
  min-width: 0;
}
.about-recognition-block h2 {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: 32px;
  line-height: 1.35;
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
  margin-bottom: var(--space-5);
  white-space: nowrap;
}
@media (max-width: 1024px) {
  .about-recognition-block h2 {
    white-space: normal;
  }
}
.about-recognition-lines {
  font-size: var(--text-16);
  color: var(--ink);
  line-height: var(--leading-3);
  white-space: normal;
  letter-spacing: var(--tracking-xs);
  /* 2026-09-24：比照首頁 .stat-block-lines 的做法——區塊（.about-recognition-block）
     與標題 h2 維持靠右，只有兩段內文單獨覆蓋成置左對齊。
     根因：.about-recognition-block 是 text-align:right，內文沒有各自覆蓋、直接繼承右對齊 */
  text-align: left;
}
.about-recognition-lines--second {
  /* 跟 .about-desc--second／.stat-block-lines--second 同一套手法：
     用 margin-top 精準控制段落間距，取代原本的 span 分行機制 */
  margin-top: var(--space-6);
  margin-bottom: 40px;
}
@media (max-width: 767px) {
  .about-recognition-inner {
    flex-direction: column;
  }
  .about-recognition-showcase {
    width: 100%;
  }
  .about-recognition-block {
    text-align: left;
    max-width: 100%;
  }
}

/* ==========================================================================
   Q&A（單一手風琴 accordion）
   ========================================================================== */
.faq-list {
  display: flex;
  flex-direction: column;
}
.faq-category-toggle {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 56px 0 var(--space-6);
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: var(--text-20);
  color: var(--ink);
  cursor: pointer;
  position: relative;
}
.faq-toggle-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--icon-md);
  height: var(--icon-md);
  color: var(--ink);
  font-family: var(--font-cn);
  font-weight: 500;
  font-size: var(--text-18);
  line-height: 1;
  transition: transform 0.4s var(--ease-spring);
}
.faq-category-toggle[aria-expanded="true"] .faq-toggle-icon {
  transform: rotate(180deg);
}

/* ---- Hover 提示：告訴使用者箭頭可以點擊展開/收合 ----
   跟全站黑底白字的 tooltip 視覺語言一致（見 .tag-pill-tip，聯絡我們
   服務項目標籤使用的同一套元件），這裡直接沿用相同結構：用真正的
   HTML 子元素 <span class="faq-toggle-tip">（不是 ::before/::after
   偽元素），三角形用該元素自己的 ::after 定位在其底部，兩者天生
   緊密相連、不會像獨立偽元素各自定位那樣中間留出空隙。
   ⚠️ 重要：.faq-toggle-tip 必須是 .faq-toggle-icon 的兄弟元素、
   而不是子元素——.faq-toggle-icon 展開時會被 rotate(180deg)（見
   上方 [aria-expanded="true"] 規則），如果提示框是它的子元素，
   180度旋轉會連文字內容一起整個顛倒過來，這正是先前「收合」兩個字
   上下顛倒的根因。改成兄弟元素後，提示框完全不受箭頭旋轉影響。
   桌機限定（跟 .tag-pill-tip 同樣考量）：觸控裝置沒有 hover 概念，
   點擊時 :hover 容易跟 :active 混在一起觸發，提示框會误闪一下。 */
.faq-toggle-tip {
  position: absolute;
  /* ⚠️ 根因記錄：不能用 bottom:100%（相對於整個 button 的頂端），
     .faq-category-toggle 有 padding:56px 0 24px，bottom:100% 會把
     提示框定位到 button 最頂端（56px padding 之上的地方），而不是
     貼著箭頭圖示上方，導致提示框跑到上一個分類區塊裡被完全遮住、
     視覺上「消失」。改用 bottom，扣掉 button 底部 padding（24px）
     跟箭頭圖示自身高度（--icon-md, 24px），精準對齊箭頭正上方，
     不受頂部 padding-top(56px) 影響。 */
  bottom: calc(var(--space-6) + var(--icon-md) + var(--space-2));
  /* 水平置中對齊箭頭圖示（非對齊整個 button 右邊界）：right 先定位
     到箭頭圖示的水平中心點（箭頭寬度 --icon-md 的一半），再用
     translateX(50%) 讓提示框以這個中心點為軸左右置中 */
  right: calc(var(--icon-md) / 2);
  transform: translateX(50%) translateY(4px);
  padding: var(--space-1) var(--space-3);
  background: var(--ink);
  color: var(--white);
  font-family: var(--font-cn);
  font-size: var(--text-14);
  font-weight: 400;
  white-space: nowrap;
  border-radius: var(--radius-md);
  opacity: 0;
  pointer-events: none;
  z-index: 20;
  transition: opacity 0.25s var(--ease-water), transform 0.25s var(--ease-water);
}
.faq-toggle-tip::after {
  content: '';
  position: absolute;
  top: 100%;
  right: 50%;
  transform: translateX(50%);
  border: 5px solid transparent;
  border-top-color: var(--ink);
  border-bottom-width: 0;
}
.faq-toggle-tip-collapse { display: none; }
.faq-category-toggle[aria-expanded="true"] .faq-toggle-tip-expand { display: none; }
.faq-category-toggle[aria-expanded="true"] .faq-toggle-tip-collapse { display: inline; }
@media (hover: hover) {
  .faq-category-toggle:hover .faq-toggle-tip {
    opacity: 1;
    transform: translateX(50%) translateY(0);
  }
}

/* 分類展開的收合動畫：用 grid-template-rows 0fr→1fr 做高度過渡，
   不用 height:auto（無法做 transition）也不用 JS 量測固定高度
   （分類數量、Q&A 筆數會持續增加，寫死高度之後每次加內容都要
   回來重改，改用 grid 這個純 CSS 技巧可以讓內容自然撐開，
   不用維護任何高度數字） */
.faq-category-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.5s var(--ease-water);
}
.faq-category-toggle[aria-expanded="true"] + .faq-category-panel {
  grid-template-rows: 1fr;
}
.faq-category-panel-inner {
  overflow: hidden;
}
.faq-item {
  padding-bottom: var(--space-12);
}
.faq-item:first-child {
  padding-top: var(--space-2);
}
.faq-q {
  font-size: var(--text-16);
  font-weight: 500;
  line-height: var(--leading-2);
  color: var(--ink);
  margin-bottom: var(--space-2);
  letter-spacing: var(--tracking-xs);
}
.faq-a {
  font-size: var(--text-16);
  font-weight: 400;
  line-height: var(--leading-1);
  color: var(--ink);
  white-space: pre-line;
  letter-spacing: var(--tracking-xs);
}
.faq-a strong {
  font-weight: 500;
}
/* 每個分類上方的分隔線，用 div+clip-path（跟聯絡我們表單欄位
   底線 .input-line-wrap::after 逐字對齊的寫法）。曾經試過改用
   inline SVG、mask-image 兩種替代技術，但 mask 只能做到兩端
   透明度漸淡，無法像 clip-path 這樣做出真正中間垂直隆起、兩端
   收窄的形狀，業主明確要求造型不能妥協，所以維持 clip-path。
   目前已知：業主反映中間那條分隔線視覺上仍偏粗，但程式碼層面
   （HTML結構、CSS數值、DevTools computed樣式）反覆驗證確認
   三條線完全一致，判斷是瀏覽器次像素渲染層面的現象 */
.faq-category-divider {
  height: 1px;
  background: var(--ink);
  clip-path: polygon(
    0% 50%,
    3% 20%,
    50% 0%,
    97% 20%,
    100% 50%,
    97% 80%,
    50% 100%,
    3% 80%
  );
}

/* ---- 獲獎清單：捲動連續驅動（scroll-scrubbed）展開效果 ----
   .awards-scroll-track 是一個很長的捲動軌道（高度給足夠空間），
   裡面的 .awards-scroll-sticky 用 position:sticky 黏在畫面上，
   使用者捲動這段長軌道時，JS 會即時計算捲動進度（0~1），
   直接控制黑線寬度跟卡片顯現程度——不是進入畫面就觸發一次的動畫，
   而是跟捲動位置即時綁定，來回捲動就會看到黑線跟卡片跟著收合展開。
   對應到原始 PDF 規格：「(AWARDS RECOGNITION)」→中間長出黑線→
   黑線變長→線下方長出獲獎卡片。 */
.awards-scroll-track {
  position: relative;
  /* 軌道總長度＝動畫需要的捲動距離＋一小段緩衝，卡片展開完後
     不會再有大段「卡住但畫面沒變化」的空檔，多捲一點點就解除卡住 */
  height: 220vh;
  background: var(--grey-300);
}
.awards-scroll-sticky {
  position: sticky;
  top: 340px; /* JS 會依 CTA 按鈕實際垂直中心動態覆蓋，這裡只是備援初始值 */
  /* 拿掉固定高度限制跟 overflow:hidden——原本這兩個設定會把
     超出範圍的卡片內容直接裁掉，導致卡片還沒展開完就被切斷。
     現在讓內容依實際高度自然撐開 */
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: flex-start;
  /* ⚠️ 根因修正（2026-09-02）：業主截圖重現「獎項卡片被壓在照片
     後面」——根因跟捲動時序無關，是純粹的 CSS 堆疊順序問題：
     .stat-block-sticky（含左側照片）有明確 z-index:10，這裡
     （獎項卡片的 sticky 容器）原本完全沒有設定 z-index（預設
     auto），在標準堆疊規則下，有明確 z-index 的定位元素通常會
     蓋過沒設定的，不管 DOM 順序誰先誰後、也不管兩者何時進入
     sticky 狀態。只要兩者在視覺上重疊到，這個問題就必然發生，
     不是時序競爭。這裡明確給一個比 10 更高的值，確保獎項卡片
     一定顯示在照片之上 */
  z-index: 11;
  /* ⚠️ 根因修正（2026-09-15）：業主反饋卡住展開期間，左側
     「更多獲獎紀錄」CTA 按鈕（在 .stat-block-sticky，z-index:10）
     完全無法點擊。根因：這個容器是 display:flex 但沒有限制寬度，
     實際佔用範圍是整個區塊全寬（不是視覺上黑線/卡片看起來偏右
     的那一小塊），上面 z-index:11 讓這片看不見的滿版區域整個蓋在
     z-index:10 的 CTA 按鈕之上，攔截掉所有滑鼠事件——即使肉眼
     完全看不到任何東西擋在那裡。修法：這個容器本身設
     pointer-events:none（不再攔截事件），實際內容
     （.awards-scroll-inner，見下方）設回 pointer-events:auto，
     確保卡片內部真正需要可點擊的獎項連結（.award-row）維持正常
     互動，不影響任何視覺呈現，純粹解決事件攔截問題 */
  pointer-events: none;
}
.awards-scroll-inner {
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--space-12) 0 0;
  /* 這一層本身也是 width:100%（撐滿跟父層一樣的全寬），設回 auto
     沒有意義——真正需要保持可互動的是下面 .awards-toggle／
     .awards-panel 這兩個實際只佔內容自身寬度的元素，見那兩則
     2026-09-15 根因修正的說明 */
}
.awards-toggle {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-en);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: var(--tracking-0);
  color: var(--ink);
  /* 父層 .awards-scroll-sticky 設了 pointer-events:none（見該處
     2026-09-15 根因修正），這裡設回 auto——這個元素是 inline-flex，
     實際寬度只等於內容本身（文字＋黑線），不會撐滿全寬，設回 auto
     不會重蹈上一層的攔截問題 */
  pointer-events: auto;
}
.awards-toggle-line {
  width: 0px; /* 由 JS 依捲動進度即時設定，不用 CSS transition */
  height: 1px;
  background: var(--ink);
  margin: 0 var(--space-2);
  /* 2026-09-07：業主指定線條粗細為視覺上的 0.75px。用
     transform: scaleY(0.75) 而不是直接寫 height: 0.75px——後者是
     次像素數值，在一般解析度螢幕上瀏覽器只能整數捨入，不同瀏覽器
     行為可能不一致，業主已經在 0.5px 那次調整時確認過這個風險、
     選擇改用 scaleY 這條路線，之後再調整粗細請比照辦理，不要
     改回直接寫小數點 px 數值 */
  transform: scaleY(0.75);
  transform-origin: center;
}
.awards-panel {
  width: 380px; /* 由 JS 依黑線寬度即時覆蓋，這裡只是備援初始值 */
  height: 0; /* 由 JS 依捲動進度即時設定 */
  opacity: 0; /* 由 JS 依捲動進度即時設定 */
  overflow: hidden;
  margin-top: 0; /* 緊接在黑線底下，不留間距 */
  background: var(--white);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.12);
  /* 父層 .awards-scroll-sticky 設了 pointer-events:none（見該處
     2026-09-15 根因修正），這裡設回 auto——這個元素明確有固定
     width（JS 動態設定成內容實際需要的寬度），不會撐滿全寬，設回
     auto 不會重蹈上一層的攔截問題，且卡片內的 .award-row 獎項
     連結需要維持可點擊 */
  pointer-events: auto;
}
/* ---- prefers-reduced-motion：強制展開成最終狀態 ----
   （2026-08-31 動畫效能優化，見 js/main.js 對應說明）
   .is-motion-reduced 由 JS 在偵測到使用者開啟「減少動態」時加在
   .awards-scroll-track 上，這裡用 !important 覆蓋掉 JS 原本逐格
   插值設定的 inline height/opacity/width，讓內容直接以完整展開
   的樣子呈現，不會因為停用 scroll-scrubbing 運算就永遠停在摺疊、
   看不見的初始狀態——獎項清單是內容，不是特效，內容不能因為動畫
   被關掉就跟著消失 */
.is-motion-reduced .awards-panel {
  height: auto !important;
  opacity: 1 !important;
}
.is-motion-reduced .awards-toggle-line {
  width: 60px !important;
}
.awards-panel-inner {
  /* 2026-09-15 修正：業主要求左右 padding 統一改成跟上下一致（都用
     --space-4＝16px），原本左右是 --space-6＝24px，跟上下不對稱。
     這樣改也是後續「卡片寬度由內容決定」需求的前提之一——padding
     縮小後，卡片自然需要的寬度會跟著變窄 */
  padding: var(--space-4);
  /* 2026-09-01 業主希望縮短「獎項卡片完全展開」到「畫面真正接上
     showcase 區塊」之間的過渡距離。這段過渡是 CSS 原生
     position:sticky 的物理特性：sticky 元素放開所需的捲動距離
     下限，等於它自己的完整高度，不是可以直接調的參數，只能透過
     縮小舞台本身的展開高度來間接縮短。這裡先從最保守的地方下手：
     只縮小卡片內距（上下從24px各縮到16px），不動列表項目本身的
     間距/字級，盡量不影響內容呈現，只壓縮純留白空間。 */
  /* 改用單純的 flex 兩欄，取代原本的 Grid（Grid 那個做法試了三次
     都會有非預期的排版問題——徽章消失、線長度算不準等，可能是
     徽章被自動排到隱性新增的第二排造成的連鎖問題。flex 兩欄結構
     簡單很多：「年份」跟「清單+徽章包成一個容器」單純並排，
     沒有多排的歧義，JS 量高度、對齊也更直接可靠） */
  display: flex;
  gap: var(--space-6);
}
.awards-content {
  flex: 1;
  min-width: 0;
}
.awards-year {
  /* 改成直式排列：文字在上、線在下方（不是文字旁邊）。
     高度由 JS 直接量測 .awards-content 的實際高度後指定，
     兩者是單純的 flex 兩欄並排，量測跟對齊都直接可靠 */
  width: 24px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.awards-year-text {
  writing-mode: vertical-rl;
  /* v48：標籤從「2025」改成中文「重點獲獎」。
     原本的 rotate(180deg) 是為「數字」設計的（數字在 vertical-rl 下
     會橫躺、方向相反，需翻正）；中文在 vertical-rl 本來就是正立、
     由上往下閱讀，若沿用翻轉會整個倒過來（實測渲染確認）。
     現在這個元素只放中文，所以取消翻轉。日後若改回放年份數字，
     要把 rotate(180deg) 加回來 */
  font-family: var(--font-en);
  font-size: var(--text-14);
  /* 2026-09-21：字重增加一級（宗霖指示）。中文字體只有 W3／W5／W7 三級（400／500／700），
     原本沒指定＝繼承 400（W3），升一級＝500（W5），與旁邊獎項名稱 .award-name 同一級 */
  font-weight: 500;
  letter-spacing: var(--tracking-xs);
  color: var(--ink); /* 修正顏色：原本是灰色，改成品牌黑 */
}
.awards-year::after {
  content: '';
  width: 1px;
  flex: 1;
  min-height: var(--space-8);
  margin-top: var(--space-2);
  background: var(--ink); /* 修正顏色：原本是灰色，改成品牌黑 */
}
.awards-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
  .award-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: var(--space-1) var(--space-2) var(--space-2) var(--space-2);
    margin: 0 calc(-1 * var(--space-2));
    line-height: 1;
  }
.award-name {
  font-size: var(--text-14);
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  /* 2026-09-19 業主要求：獎項名稱不截斷，每一行的字都要完整顯示，
     卡片基本寬度＝最長那一行的完整寬度（由 JS 量測後設定，見
     js/main.js measurePanelHeight）。
     原本這裡設 overflow:hidden＋text-overflow:ellipsis＋min-width:0
     讓名稱在空間不足時被截成刪節號；現在改成 flex-shrink:0——名稱
     在結構上永遠不會被壓縮，寬度不夠時應該是「卡片變寬」，而不是
     「文字被吃掉」。
     hover 底線維持用 border-bottom（不改回 text-decoration），
     固定的透明邊框預留位置，hover 時不會因邊框出現造成行高跳動 */
  flex-shrink: 0;
  border-bottom: 1px solid transparent;
  padding-bottom: 3px;
}
.award-tag {
  font-family: var(--font-en);
  font-size: var(--text-14);
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  margin-left: var(--space-4);
  /* 跟 .award-name 統一使用 border-bottom 畫底線（不用
     text-decoration:underline），確保兩者 hover 時的線條粗細、
     垂直位置完全一致，不會因為兩種不同技巧畫出的底線觀感不同 */
  border-bottom: 1px solid transparent;
  padding-bottom: 3px;
}
.awards-badges {
  /* Grid 排成兩排、每排三個（3欄 x 2列）。這次改成 1fr 1fr 1fr：
     三欄平分容器可用寬度，讓整排徽章左右撐滿到跟獎項清單同寬，
     不再是 max-content 各自取寬（那樣每排總寬度會不一致，
     圖片小的欄位比較窄，看起來兩排寬度沒對齊）。gap 用同一個
     column-gap 在三欄之間平均分配空間 */
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  column-gap: var(--space-4);
  row-gap: var(--space-4);
  /* 2026-09-11 第三次修正：宗霖指定「清單→徽章」間距固定為
     16px（--space-4），不再跟隨清單列間距（12px）。這是獨立的
     設計決定，不是換算或對齊出來的數字 */
  margin-top: var(--space-4);
}
.award-badge-logo {
  display: block;
  /* 統一高度為基準，寬度依各自比例自然決定（hug content），
     避免直式圖（如 MUSE 標章）被撐成跟橫式圖同寬造成高度暴增 */
  height: 40px;
  width: auto;
  object-fit: contain;
  /* 圖片在自己的格子（欄寬已改為 1fr 平分）裡水平置中，不再貼左，
     這樣不管圖片實際寬度多窄，都會置中顯示在配置到的欄位範圍內 */
  justify-self: center;
  align-self: center;
}

/* ---- 無 JS 降級：獲獎清單 ----
   實際生效規則寫在 index.html <head> 的 <noscript><style> 區塊
   （CSS 選擇器沒有「父層是 noscript」這種語法，只能透過
   <noscript><style> 整段插入才會生效，故不在這裡放規則，
   這裡僅保留註解說明脈絡，實際規則見 index.html） */

/* ==========================================================================
   代表案例（室內設計／品牌設計／整合型設計 三分類切換展示）
   ========================================================================== */
/* 2026-09-07：原本這裡（.showcase-section）有純灰底 + 無圓角轉場的
   規則，那時候 Showcase 緊接在 #recognition 跟 partners 之間，
   三個區塊共用同一階純灰無縫銜接。業主要求把 Showcase 搬到 Hero
   跟 About 之間後，背景規則改寫在上方的 #showcase（id 選擇器）
   身上，變成「跟 Hero 反向銜接的漸層」，不再是純灰。
   這裡不寫 .showcase-section 的背景規則，避免跟 #showcase 的規則
   同時存在造成閱讀上的混淆（id 選擇器優先權必定比 class 高，
   就算兩者都寫也不會有視覺錯誤，但容易誤導之後維護的人以為
   還在用這條规則）。.showcase-section 這個 class 目前純粹作為
   JS/HTML 裡辨識用的鉤子，不承載任何背景樣式 */

/* ---- 無 JS 降級：代表案例（見 index.html 內對應 <noscript> 說明） ----
   三個分類直接攤開列出，不重現拖曳跑馬燈／切換按鈕的互動效果，
   只保留標題、文案、CTA 連結這些核心內容，樣式跟全站字體/間距
   token 一致，但排版刻意簡化成單欄清單。
   圖片與文字段落的 max-width 套用跟 awards.html 獎項卡片
   （.award-page-intro）同一個公式：(100% - gap) / 2，也就是
   「兩欄 grid 反推出來的單欄寬度」，不是之前隨手訂的固定 px 值
   （480px／640px）。這裡的父容器同樣是 .section-inner（全站
   標準 1240px 容器），跟 awards.html 的 .award-detail-list
   外層容器基準一致，公式可以直接套用，不會算錯比例 */
.noscript-showcase-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
}
.noscript-showcase-item img {
  display: block;
  width: 100%;
  max-width: calc((100% - var(--space-8)) / 2);
  height: auto;
  border-radius: var(--radius-md);
  margin-bottom: var(--space-4);
}
.noscript-showcase-item h3 {
  /* 2026-09-11 修正：字級/字距原本各自獨立訂了一套數值
     （固定 24px、無字距），沒有跟有 JS 版本的
     .showcase-category-name-zh 對齊，宗霖回報兩者不一致。
     改成套用完全相同的 token：clamp(26px,3vw,38px) 響應式字級
     （clamp 是純 CSS 功能，無 JS 環境一樣正常運作，不需要
     替代方案）+ letter-spacing:var(--tracking-xs)，確保視覺上
     不管有沒有 JS 都是同一套排版數值 */
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: clamp(26px, 3vw, 38px);
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
  margin-bottom: var(--space-3);
}
/* .noscript-showcase-heading / .noscript-showcase-name-en
   （2026-09-11 新增）：無 JS 版本原本只有純中文 <h3>，完全沒有
   對應有 JS 版本（.showcase-category-name-en，見該處定義）的
   「( INTERIOR )」這類直式英標。宗霖要求無 JS 環境也要一併補上，
   且指定直式排列、模仿有 JS 版本視覺——用同一套 writing-mode:
   vertical-rl + 絕對定位疊在左上角的做法。
   ⚠️ 三個分類各自的 padding-top 無法共用同一個數字：直式文字
   （writing-mode:vertical-rl）的視覺高度取決於文字長度，
   INTERIOR(8字元)／BRAND(5字元)／INTEGRATED(10字元) 三個長度
   都不同，視覺高度也不同。有 JS 版本靠 alignShowcaseLabelToTitle
   即時量測校正，無 JS 時沒有這個能力，改成幫每個分類項目各自
   用 inline style 設定精準的 padding-top（Playwright 實測反推：
   量出英標實際渲染高度 + 16px 目標間距），這裡的 32px 只是
   HTML 沒有內聯覆蓋時的備援初始值，正常情況下三個項目都會被
   各自的 inline style 覆蓋 */
.noscript-showcase-heading {
  position: relative;
  padding-top: 32px;
  margin-bottom: var(--space-3);
}
.noscript-showcase-name-en {
  position: absolute;
  top: 0;
  left: 0;
  /* 根因：position:absolute 元素若不設 height，且父層
     (.noscript-showcase-heading) 也沒有固定高度，某些瀏覽器對
     writing-mode:vertical-rl 直式文字的 auto 高度計算會退化成
     撐滿 containing block 的完整高度，而不是文字內容本身需要
     的高度——這會造成「padding-top 影響容器高度 → 容器高度
     影響這裡的高度 → 這裡的高度又用來反推 padding-top」的循環
     依賴，導致每次量測結果都跟著容器高度飄動、對不準。加上
     height:max-content 明確鎖定「高度只取決於文字內容本身」，
     切斷這個循環，才能讓 Playwright 反推的 padding-top 數值
     穩定、可重現 */
  height: max-content;
  writing-mode: vertical-rl;
  font-family: var(--font-en);
  font-size: var(--text-16);
  letter-spacing: var(--tracking-0);
  color: var(--grey-700);
}
.noscript-showcase-heading h3 {
  margin-bottom: 0;
}
.noscript-showcase-item p {
  font-size: var(--text-16);
  line-height: var(--leading-3);
  /* 2026-09-11 補上：有 JS 版本 (.showcase-category-desc) 有
     letter-spacing:var(--tracking-xs)，這裡原本完全沒有設定
     （瀏覽器預設值 normal=0），造成字距觀感比有 JS 版本緊密，
     補上同一個 token 讓兩者字距一致 */
  letter-spacing: var(--tracking-xs);
  margin-bottom: var(--space-3);
  max-width: calc((100% - var(--space-8)) / 2);
}

/* ---- 單一分類完整內容：四角配置 ----
   一次只呈現「目前選中的那一個分類」，不是三分類同時擠在畫面上。
   結構由上到下：
     上排（左右對齊）：左上分類標題（中英文分兩行）／右上 CTA
     中間：跑馬燈帶狀展示該分類代表作品照片
     下排（左右對齊）：左下內文文案／右下左右切換分類按鈕
   要切到別的分類，只透過右下角的左右箭頭。 */
.showcase-stage {
  position: relative;
  width: 100%;
  /* ⚠️ 根因記錄：原本這裡有 overflow:hidden，本意是配合切換
     分類時的輕微橫移過場動畫，但這個裁切範圍意外連帶把「往上
     絕對定位突出」的英文小標也切掉了看不見。跑馬燈照片本身的
     左右溢出已經由 .showcase-marquee-band／.showcase-stage-marquee
     這兩層各自的 overflow:hidden 負責裁切，不需要在這裡外層
     再裁一次，拿掉後英文小標才能完整顯示 */
}
.showcase-stage-inner {
  display: flex;
  flex-direction: column;
  /* 2026-09-08：業主要求改成一頁式，三個分類同時展開顯示，
     不再是切換式的單一分類。原本這裡的 transition 是給切換分類
     時的橫移淡出/淡入過場用，一頁式模式下不再有切換動作，但
     transition 保留也無害（不會被觸發），故不特別移除，避免
     動到跟其他邏輯的耦合 */
  transition: transform 0.5s var(--ease-water), opacity 0.5s var(--ease-water);
}
.showcase-stage-inner + .showcase-stage-inner {
  /* 一頁式三組分類之間的垂直間距 */
  margin-top: var(--space-32);
}
/* 2026-09-25 宗霖回報：手機/平板版捲出 Hero 後，看到「室內設計」分類，
   接著會撞上一大塊莫名的灰色空白，導致硬幣入水後的節奏感覺很怪。
   根因：這個 128px（--space-32）的分類間距全站只有這一個寫死值，沒有
   隨斷點縮小。桌機版分類內容本身較高（約 650~700px）、視窗也更高，
   128px 只占版面一小部分，是正常的呼吸空間；手機版分類內容矮了快一半
   （約 530~590px），128px 卻沒有跟著縮小，比例上變成快 1/4 個分類的高度，
   在「灰底＋沒有任何內容」的狀態下，視覺上就是一塊突兀的純灰空白，
   緊接在硬幣落水的高潮後面，把節奏感打斷。
   修法：改成跟緊接在後面、緊鄰的 .section 上下內距同一套數值，維持全站
   既有的間距節奏（≤1024 用 --space-24＝96px，≤767 用 --space-16＝64px），
   桌機版（≥1025px）完全不動，仍是 128px */
@media (max-width: 1024px) {
  .showcase-stage-inner + .showcase-stage-inner { margin-top: var(--space-24); }
}
@media (max-width: 767px) {
  .showcase-stage-inner + .showcase-stage-inner { margin-top: var(--space-16); }
}

/* 上排／下排共用的左右對齊列，四角的「角」都是靠這個 flex
   space-between 撐出來的 */
.showcase-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-6);
}
.showcase-row--top {
  margin-bottom: var(--space-8);
  /* CTA 的垂直位置改由 JS 用 transform 精準對齊中文標題中心
     （見 alignShowcaseLabelToTitle），這裡的 align-items 只是
     排版初始基準，用 flex-start 讓 name 容器（含往上絕對定位的
     英文小標）跟 CTA 都從各自的自然頂部開始，避免跟 JS 算出的
     位移量互相干擾 */
  align-items: flex-start;
}
.showcase-row--bottom {
  margin-top: var(--space-8);
  /* 2026-09-12：CTA（更多作品）從 topRow 移過來這裡跟文案並排，
     宗霖要求兩者「頂端切齊」，覆蓋掉 .showcase-row 基礎樣式的
     align-items:flex-end（那是給舊版「文案 vs 左右切換按鈕」配置
     用的，兩者底部切齊才好看；現在是「文案 vs CTA 按鈕」，改成
     頂端切齊才符合新需求） */
  align-items: flex-start;
}

/* 左上：分類標題，中英文分兩行 */
/* 左上：分類標題，仿照全站子分頁（.page-label + .page-title）
   的排法：中文標題固定在同一個位置，英文小標用絕對定位疊在
   上方、往上延展，不會因為英文字數長短把中文標題往下推。
   兩者間距由 JS 動態校正成精準 16px（見 alignShowcaseLabelToTitle） */
.showcase-category-name {
  /* 比照子分頁 .page-label + .page-title 的機制：英文小標用
     絕對定位疊在左上角、中文標題固定在下方位置，不佔用文件流
     高度、不會被英文字數長短推開。中英文間距由 JS 動態校正成
     精準值（見 alignShowcaseLabelToTitle）。
     padding-top 這裡的固定值只是 JS 執行前／JS 關閉時的降級
     初始值，實際數值由 JS 動態量測英文小標的真實高度後精準
     覆蓋，不會像原本固定寫死時那樣，遇到較長的英文名稱（例如
     "( INTEGRATED DESIGN )"）就不夠用、往上頂到上一個區塊 */
  position: relative;
  padding-top: var(--space-32);
}
.showcase-category-name-en {
  position: absolute;
  top: 0;
  left: 0;
  writing-mode: vertical-rl;
  font-family: var(--font-en);
  font-size: var(--text-16);
  letter-spacing: var(--tracking-0);
  color: var(--grey-700);
}
.showcase-category-name-zh {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: clamp(26px, 3vw, 38px);
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
}

/* 更多作品 CTA：2026-09-12 起改到 bottomRow 跟簡介文案並排、
   頂端切齊（見 .showcase-row--bottom 的 align-items:flex-start）。
   這裡原本殘留 align-self:center，是舊版「按鈕跟中標同高、垂直
   置中對齊」時代的樣式——align-self 會覆蓋父層 .showcase-row--bottom
   的 align-items:flex-start，導致按鈕看起來像整體置中對齊文案，
   這正是宗霖回報「置中對齊，我不要」的根因。拿掉這條規則，讓它
   自然繼承父層的頂端對齊 */
.showcase-cta {
  display: inline-flex;
  flex-shrink: 0;
}

/* 左下：內文文案 */
.showcase-category-desc {
  font-size: var(--text-16);
  /* 這裡的兩行文字是同一個 <p> 內部用 <br> 手動換行（不是像
     .about-desc 那樣拆成兩個獨立段落用 margin-top 拉開間距），
     所以不能沿用 .about-desc 的 line-height:1——那是配合「每個
     段落本身只有單行」的前提下才成立，同一段落內的多行文字用
     line-height:1 會顯得行距過緊、太貼近。改用全站「舒展內文」
     的 --leading-3（1.75），比照普通多行內文的閱讀舒適度 */
  line-height: var(--leading-3);
  color: var(--ink);
  /* 比照全站內文段落統一套用的 0.1em 字距（Illustrator Tracking
     100），跟 .about-desc／.faq-a 等內文段落使用同一個 token，
     不要另外發明一組數值 */
  letter-spacing: var(--tracking-xs);
  max-width: 480px;
}
@media (max-width: 1024px) {
  /* 2026-09-25：見 js/main.js 對應說明——平板／手機取消手動斷行，
     交給 CSS 自動換行決定斷點 */
  .showcase-desc-break { display: none; }
}

/* 下方：跑馬燈帶狀展示，改成較矮的橫帶（不是滿版大圖），
   讓上下文字內容有足夠呼吸空間 */
.showcase-marquee-band {
  position: relative;
  /* Full-bleed 滿版突破技巧：這個容器原本在 .section-inner 裡，
     會被 --container-max（1240px）鎖住寬度，導致就算照片本身
     用 vw 為單位算出更寬的尺寸，也會因為容器裝不下而被迫擠壓、
     露出的張數比預期少（實測 2383px 寬螢幕下容器仍被鎖在
     1240px，3 張 35vw 寬的照片完全放不進去，只能看到 1.4 張）。
     用 width:100vw + margin-left 負值，讓這個容器脫離
     .section-inner 的寬度限制，真正撐滿到視窗邊緣，這樣照片的
     vw 尺寸才有一致的參考基準可以正確運作。這一層本身不做任何
     裁切，純粹只是提供「視窗寬度」這個計算基準，真正的可視裁切
     邊界（業主要的左右安全邊距／白邊）由內層 .showcase-marquee-window
     負責 */
  width: 100vw;
  margin-left: calc(50% - 50vw);
  /* 高度跟著 .showcase-photo 的寬度反推 4:3 比例的高度，
     兩者用同一套計算基準，確保帶狀容器高度永遠剛好等於照片
     高度，不會裁切或留白 */
  height: calc(35vw * 0.75);
}
.showcase-marquee-window {
  /* ⚠️ 根因記錄：業主回報「跑馬燈貼齊螢幕邊緣、白邊不見了」。
     原本只在 .showcase-stage-marquee 這單一層同時做「padding
     內縮出安全邊界」+「overflow:hidden 裁切」，但 CSS 的
     overflow:hidden 裁的是元素自己完整的 border box（含 padding
     在內），並不會因為加了 padding 就把可視範圍限縮到 padding
     內側——這代表照片實際上還是能顯示到 padding 區域，真正的
     裁切線落在最外層 100vw 的邊界，不是文字對齊的安全邊距邊界。
     修法：拆成獨立一層，這裡先用 padding 把寬度「實際」內縮到
     安全邊界（不是用 overflow 假裝裁切），內部的 .showcase-stage-marquee
     才需要 overflow:hidden，這時候裁的就是已經內縮過的正確寬度。
     .section-inner 的實際左邊界公式是
       max(--section-side-padding, (100vw - --container-max) / 2)
     跟文字對齊用的是同一條公式，確保任何螢幕寬度下都精準疊合 */
  position: absolute;
  inset: 0;
  padding: 0 max(var(--section-side-padding), calc((100vw - var(--container-max)) / 2));
  box-sizing: border-box;
}
.showcase-stage-marquee {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  /* 業主指定：不用 hover 暫停，改用拖曳手勢控制，
     游標提示這裡可以左右拖曳 */
  cursor: grab;
}
.showcase-stage-marquee.is-dragging {
  cursor: grabbing;
}
.showcase-stage-marquee-track {
  display: flex;
  align-items: center;
  height: 100%;
  width: max-content;
  gap: var(--space-4);
  animation: showcase-marquee-scroll 32s linear infinite;
  will-change: transform;
}
/* 照片統一 4:3 比例，寬度固定、高度用 aspect-ratio 自動算出，
   不再用「撐滿容器高度」的方式決定尺寸——避免容器高度跟照片
   比例沒有對齊關係時，被拉伸變形成細長條。
   桌機版寬度抓「視窗寬度三等分」，讓畫面一次只完整看到 3 張
   （業主明確要求，不是 4 張），第 4 張後面的內容自然被裁切在
   可視範圍外，不需要额外處理——這正是業主要的效果。
   用 100vw 而非 --container-max 三等分，因為 .showcase-marquee-band
   本身是滿版寬度、沒有被 .section-inner 的 max-width 限制住，
   照片尺寸要跟著「實際可視窗寬度」等比縮放，才能在各種螢幕寬度
   下都準確維持「剛好看到 3 張」的視覺效果，不是固定在某個
   容器寬度算出的常數值 */
.showcase-photo {
  /* 業主放寬需求：只要中間主視覺那張完整可見即可，左右兩側的
     照片被舞台邊界裁切掉一部分完全沒關係。改用更穩健的做法：
     單張寬度直接抓「視窗寬度的 35%」，這樣三張排列時中間那張
     一定完整落在可視範圍內，左右兩側自然會被 .showcase-marquee-band
     的 overflow:hidden 切掉一截——不再需要精算 gap 才能維持
     「剛好 3 張」，那套公式只要 gap 或 padding 有一點誤差就會
     跑出第 4 張的一角，改成這個寬鬆但穩定的比例後不會再有這個問題 */
  width: 35vw;
  aspect-ratio: 4 / 3;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  /* 業主提供真實作品照片後，這裡從灰色佔位 <div> 改成 <img>，
     object-fit:cover 確保不同長寬比的原始照片都能裁切填滿
     4:3 框架、不變形；background 灰階保留當作圖片載入前/失敗
     時的過渡底色，不會出現空白閃爍。
     object-position 指定 bottom：預設值是 50% 50%（正中央），
     直式照片裁進橫式 4:3 框架時會上下各切一截，畫面主體如果
     偏下（例如空間案例的地板、家具下半部）容易被切掉。改成
     bottom 讓裁切基準對齊底部，需要犧牲的部分優先從上方裁掉，
     底部內容永遠完整露出、對齊方塊底緣 */
  object-fit: cover;
  object-position: center bottom;
  background: var(--grey-400);
  /* 照片內容用 draggable，避免瀏覽器原生「拖曳圖片另存」行為
     跟這裡的自訂拖曳手勢互相搶奪同一個拖曳手勢 */
  -webkit-user-drag: none;
  user-select: none;
}
@keyframes showcase-marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* 2026-09-08：以下原本是「底部左右切換按鈕」的樣式規則
   （.showcase-controls/.showcase-nav 及其響應式覆蓋規則）已刪除
   ——首頁「代表案例」從切換式改成一頁式（三個分類同時展開）後，
   main.js 已不再生成這些切換按鈕的 HTML 元素，這組規則是死碼 */

@media (max-width: 1024px) {
  /* 平板窄一點，比例拉高到 50vw 讓單張照片仍有足夠存在感 */
  .showcase-photo { width: 50vw; }
  .showcase-marquee-band { height: calc(50vw * 0.75); }
}

@media (max-width: 767px) {
  /* 手機螢幕太窄，四角配置（左右對齊）容易擠壓變形，
     改成上下堆疊：標題 → CTA → 跑馬燈 → 文案 */
  .showcase-row {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
  }
  .showcase-row--top { margin-bottom: var(--space-6); }
  .showcase-row--bottom { margin-top: var(--space-6); }
  /* 手機螢幕更窄，比例再拉高到 70vw，避免照片顯得過小 */
  .showcase-photo { width: 70vw; }
  .showcase-marquee-band { height: calc(70vw * 0.75); }
}

/* ==========================================================================
   合作夥伴（雙排跑馬燈，方向相反）
   ========================================================================== */
.partners {
  padding: var(--space-24) var(--space-12);
  /* 2026-09-01 業主要求：取消 .partners 從 .section--white 繼承來的
     圓角浮貼轉場效果（border-radius:60px 60px 0 0 + margin-top:-60px）。
     這個效果原本是「灰轉白」區塊的統一視覺簽名（跟 #about 用同一套
     手法），讓白色區塊看起來浮貼在上一個灰色區塊之上，但代價是造成
     60px 的視覺重疊——業主希望「代表案例(showcase)」下側文案跟
     「合作夥伴」標題之間的視覺間距精準等於 256px（跟其他相鄰區塊
     128+128 的標準間距慣例一致），不要因為這個轉場效果被扣掉60px
     變成196px。
     不直接修改 .section--white 共用規則本身（會連帶影響 #about，
     業主沒有要求改那裡），改用範圍限定，只在 .partners 這裡覆蓋掉
     圓角跟負 margin，恢復成方正邊界、正常間距。 */
  border-radius: 0;
  margin-top: 0;
}
.partners-header {
  max-width: var(--container-max);
  margin: 0 auto var(--space-24);
  /* padding-left 改由 JS 精準量測 Logo 實際視覺位置後動態設定，
     不再用猜測的固定數值（見 js/main.js 的 alignPartnersHeaderToLogo） */
}
.partners-title {
  font-family: var(--font-cn);
  font-weight: 500;
  font-size: var(--text-20);
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
}
.partners-subtitle {
  font-family: var(--font-en);
  font-size: var(--text-14);
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
  margin-top: var(--space-1);
}
.marquee-row {
  overflow: hidden;
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
}
.marquee-row + .marquee-row {
  margin-top: var(--space-24);
}
.marquee {
  display: flex;
  width: max-content;
  gap: var(--space-8);
  animation: marquee-scroll 55s linear infinite;
}
.marquee--reverse {
  animation-direction: reverse;
}
.marquee-logo {
  width: 140px;
  height: 90px;
  border-radius: var(--radius-md);
  /* 業主提供正式 logo 圖片後，這裡改成白底容器（原本 --placeholder
     灰色只是佔位期的視覺提示，現在裝了真實 logo，改用白底讓
     各家色彩、造型不一的 logo 都能在乾淨背景上正常顯示） */
  background: var(--white);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2);
  /* 目前仍沒有 href（沒有實際連結行為，等業主提供合作夥伴連結
     網址後再補上），維持 default 游標，不誤導使用者以為可點擊 */
  cursor: default;
  transition: box-shadow 0.3s var(--ease-water);
}
.marquee-logo img {
  /* 等比例縮放置中，避免長寬比例不同的 logo 被拉伸變形；
     max-width/max-height 確保不會超出容器，同時保留 logo
     原始比例 */
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}
/* [.marquee-logo:hover 目前沒有獨立樣式（2026-09-20 移除空規則外殼）]
   業主要求拿掉陰影，hover 目前不做任何視覺變化（純展示佔位，無 href，
   不需要額外提示）。跑馬燈「游標移到某個 logo 時該排暫停」由下方
   .marquee:has(.marquee-logo:hover) 負責，另有 js/main.js 的
   mouseenter／mouseleave 雙重保險。實測（含 JS）：移除這條空規則前後，
   游標移到 logo 時只有該排暫停、移開即恢復，行為一致。
   （未驗證：完全沒有 JS 時，僅靠 CSS 的 :has() 是否單獨運作。） */
.marquee:has(.marquee-logo:hover) {
  animation-play-state: paused; /* 游標移到該排任一方塊上時，整排跑馬燈暫停 */
}
@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* ==========================================================================
   聯絡我們
   ========================================================================== */
.contact-section {
  /* 業主要求：所有子頁面（含聯絡我們）的中文標題要固定在同一個
     水平高度。原本這裡是 min-height:100vh + flex置中，讓整個
     區塊內容垂直置中在畫面正中央，這跟其他子頁面（about/works/
     faq）「內容從頂部固定距離開始」的版面邏輯完全不同，導致
     不管標題間距怎麼調，中文標題的實際高度都對不齊。
     改成跟 .section 完全一致的 padding-top 起始邏輯，不再垂直
     置中，讓內容統一從頂部固定距離開始。
     ⚠️ 2026-09-09 除錯記錄：左右 padding 原本是 0，這是先前
     改動只顧著統一 padding-top 起始邏輯時的副作用，不是刻意
     設計——全站標準 .section 都有左右 var(--space-12)（48px）
     的側邊安全邊界，這裡漏掉了。導致視窗寬度接近或略大於全站
     容器上限 1240px 時，其他頁面有 48px 緩衝不會貼邊，但這裡
     完全沒有，.contact-inner（左欄固定420px+右欄）內容會直接
     貼齊視窗邊緣，業主稱為「邋邊」的視覺瑕疵。補回跟全站一致
     的側邊 padding */
  position: relative;
  padding: var(--space-32) var(--space-12);
  background: var(--grey-300);
}
.contact-section .section-inner {
  /* flex item 的寬度預設縮到內容大小，不會自動撐滿 max-width，
     這裡明確加 width:100% 強制撐滿，.section-inner 原有的
     max-width + margin:auto 才能正確生效、對齊到跟其他區塊
     （Logo／AWARDS RECOGNITION）同一條容器邊界線。
     額外加上 position:relative，讓水滴裝飾（.contact-corner-decor）
     的絕對定位基準明確鎖定在這個容器本身，不受外層 .contact-section
     的 flex 排版影響定位計算 */
  width: 100%;
  position: relative;
}
.contact-inner {
  position: relative;
  display: grid;
  /* 改用全站 12 欄 grid 邏輯：左欄（聯絡資訊）固定佔比，
     右欄（表單）縮減寬度、貼右對齊，不再無限吃滿剩餘空間——
     原本 1fr 會把表單拉到跟左欄同等比例寬，內容顯得鬆散冗長 */
  grid-template-columns: 420px 1fr;
  /* 根因：gap 原本是固定值 var(--space-24)（96px），左欄也是
     固定 420px，兩者都不會隨螢幕寬度縮小而縮小。當可用空間變窄
     時，瀏覽器沒有辦法透過縮小這兩個固定值來讓內容更貼合，只能
     犧牲外側留白、讓整個容器貼齊視窗邊緣，這不是業主要的效果
     （業主要求優先縮小兩欄之間的間距，而不是先讓外側貼齊）。
     改用 clamp() 讓 gap 隨可用寬度縮放：下限 32px（--space-8，
     避免縮到太窄時兩欄視覺上擠在一起分不清楚）、理想值用 vw
     隨螢幕寬度線性縮放、上限維持原本的 96px（--space-24，寬螢幕
     時不變）。這樣在切換成單欄的斷點（1024px）之前，會先經歷
     間距逐漸縮小的平滑過渡，而不是維持固定值直到觸發斷點 */
  gap: clamp(var(--space-8), 8vw, var(--space-24));
}
.contact-form {
  max-width: 640px;
  margin-left: auto;
}

/* ---- 左欄：標題 + 聯絡資訊 + Logo + 社群 ---- */
.contact-aside {
  /* 業主要求：所有子頁面（含這裡）的中文標題要固定在同一個
     水平高度，不受各頁英文小標文字長短影響。加上 position:relative
     容器，讓 .contact-label 用絕對定位疊在左上角（不再佔用
     文件流高度、不會把下方的 .contact-title 往下推）。

     ⚠️ 架構修正（2026-08-22 第三次，業主提供螢幕錄影回報「捲動
     還是會突然跳一下」，並指示直接比照 contact.html 子頁面的
     做法）：原本首頁這個區塊會整體用 JS 往上位移去追右側表單
     欄位（用 top 屬性直接控制），但表單帶 data-reveal 動畫、
     位置持續變化，等於追一個會動的目標，衍生一連串補丁式修正
     都無法根治問題。現在改成完全比照子頁面：.contact-aside／
     .contact-label 全程維持原本的靜態文件流位置，不再被 JS
     移動；改成移動 .contact-form（見 main.js 的
     alignContactFormToLabelHome），用 margin-top 讓表單去對齊
     這裡的 .contact-label，跟子頁面 alignContactFormToHeading()
     是同一套邏輯。目標永遠靜止不動，就不會再有追蹤時序的問題，
     也不需要任何 transition 補丁去掩蓋跳動——已用 playwright
     實測比對子頁面全程 0 跳動，這裡採用同一套架構後應有相同的
     穩定性 */
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}
/* 2026-09-12 全站中英標統一重構：data-reveal 整組掛在
   .contact-aside 本身（含英標/中標/聯絡方式，比照首頁 showcase
   分類卡片模範組的做法）。main.js 的 alignContactAsideToNameField
   會用 margin-top 移動這個容器去對齊右側表單，同時容器本身仍
   維持全域 [data-reveal] 的 transform:translateY(48px)→none 動畫
   （沒有另外排除），因為那次量測時序問題已經改用「量測前暫時
   清空 transition、強制設回終點值」的手法解決（見該函式定義），
   不需要再犧牲位移動畫效果，這樣才能跟 .page-header／
   .about-top-row 等其他區塊呈現一致的絲滑進場動態感 */
.contact-label {
  /* 跟子頁面 .page-label／首頁 .about-label 視覺完全一致：
     直式排版、左側對齊公司 Logo。水平位移量由 JS 動態量測
     Logo 實際渲染位置後設定（見 js/main.js 的
     alignContactLabelToLogo），不用猜測的固定 px 值。

     改用絕對定位疊在容器左上角，不再佔用文件流高度、不會推開
     下方的 .contact-title——跟 .page-label 用同一套手法統一
     全站子頁面的中文標題水平高度 */
  position: absolute;
  top: var(--space-32);
  left: 0;
  writing-mode: vertical-rl;
  font-family: var(--font-en);
  font-size: var(--text-16);
  letter-spacing: var(--tracking-0);
  color: var(--grey-700);
}
.contact-title {
  /* 樣式參照「關於我們」的 .about-headline 手法：同一套字級/字重/行高 */
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: clamp(26px, 3vw, 38px);
  line-height: 1.35;
  letter-spacing: var(--tracking-xs);
  /* 固定的 margin-top，取代原本「被 .contact-label 自然文件流
     高度推開」的效果，讓中文標題落在跟其他子頁面統一的水平高度。
     用 calc() 疊加兩個 --space-32：其他子頁面（about/works/faq）
     的中文標題位置，是 .section 跟 .page-header 兩層 padding-top
     各 128px 疊加而成，但 .contact-section 只有單層 128px
     padding-top，所以這裡要在 margin-top 補回缺少的那一層，
     兩個 token 加總才會等於其他頁面的疊加總量 */
  margin-top: calc(var(--space-32) + var(--space-32));
  margin-bottom: var(--space-2);
  /* 覆蓋全域 [data-reveal] 的 transform 動畫，改用純 opacity 淡入。
     根因：transform（即使數值是 translateY(0)）會讓元素建立獨立的
     CSS 堆疊上下文（stacking context），一旦建立，z-index 的比較
     基準就不再是單純數字大小，而是牽涉到父層 DOM 順序——這個標題
     的父層鏈（.contact-section 等）都排在 .site-header 之後，
     曾經導致捲動經過時蓋過本該在最上層、固定定位的 Logo。
     這裡直接拿掉 transform，只保留 opacity 動畫，從根本上避免
     這個元素再建立任何堆疊上下文，就不會有 z-index 比較的問題 */
  transform: none !important;
}
/* 2026-09-27 根因修正（宗霖回報：手機版聯絡我們子頁面中標位置比
   其他子頁面低，要求比照全站慣例——中標對齊統一高度，英標
   （position:absolute，不佔文件流）隨之相對往上，下方內容因為
   在正常文件流中會自動跟著中標一起往上移動）：
   根因：.page-title（about/faq/work-detail 等頁面共用）在手機版
   透過 .page-header { padding-top: var(--space-24) } 把桌機版
   128px 的 padding-top 縮小到 96px，中標位置跟著同比例上移；但
   .contact-title 手機版從未有對應覆蓋，margin-top 仍是桌機版寫死
   的 calc(--space-32 + --space-32)=256px 沒有縮小，兩邊的「中標
   統一高度」機制從此不同步。實測 about.html／faq.html 手機版中標
   的 top 都是 224px，contact.html 卻是 256px，正好差 32px。
   修法：手機版 .contact-title 的 margin-top 直接縮小 32px
   （256-32=224px），讓中標 top 精準對齊其他頁面的 224px，不需要
   額外處理英標或下方內容——英標本來就是絕對定位不受 margin-top
   影響，下方 .contact-meta 在正常文件流中會自動跟著往上位移 */
@media (max-width: 767px) {
  .contact-title { margin-top: 224px; }
}
.contact-meta {
  /* 樣式參照「關於我們」的 .about-desc 手法 */
  font-size: var(--text-16);
  line-height: 1.8;
  color: var(--ink);
  /* 補上全站內文段落統一套用的 0.1em 字距，原本漏掉、跟宣稱
     的「參照 .about-desc」不一致 */
  letter-spacing: var(--tracking-xs);
}
/* 2026-09-12：跟上面 .contact-title 拿掉 transform 同一個理由——這裡
   還多一個更直接的原因：.contact-meta 是 alignContactAsideToNameField
   量測 .contact-aside 整組高度時的其中一份文件流內容，若讓它參與
   transform 位移動畫，量測時機點落在動畫播放中途會抓到錯誤的
   暫態高度，連帶讓整組容器的位移計算跟著出錯。改成純 opacity
   淡入，位置全程穩定 */
.contact-meta[data-reveal] {
  transform: none !important;
  transition: opacity 1s var(--ease-water);
}

/* 換上新版漏斗 SVG（含黑色 SPOUT DESIGN 文字），viewBox
   687.46:1000，比例約 0.687:1。要求「以左下角為縮放定位點放大」，
   在原本 flex-direction:column 的文件流裡直接放大 height 只會讓
   元素往下延伸、把後面的營業時間文字往下推，達不到「左下角固定、
   向上變大」的效果。改用絕對定位，讓 .contact-aside-hours 保留
   一個固定高度的佔位空間（維持營業時間文字位置不跳動），漏斗本身
   絕對定位錨定在這個佔位空間的左下角，往上放大到估算高度 320px
   （大致抓「頂部切齊預算 bar 那一行」的區域，不做動態像素級量測，
   避免上次跨欄位動態計算在此環境無法驗證、導致排版嚴重跑掉的
   問題再度發生） */
/* 左側漏斗裝飾：定位基準是 .contact-inner（左右兩欄共同容器，
   見上方 position:relative 設定）。bottom:0 讓漏斗下緣對齊到
   .contact-inner 的實際底部——由於右欄表單內容通常比左欄多，
   容器高度會被右欄撐出，這個底部大致對應「得知管道」checkbox
   到送出按鈕一帶的高度，不做像素級動態量測。
   left:0 對齊左欄起始點，高度 320px（估算值，可再依實際偏差調整） */
/* 左側漏斗裝飾：定位基準是 .contact-inner（左右兩欄共同容器）。
   要對齊「得知管道」checkbox 那一行的下緣，但 .contact-inner 的
   底部實際上是送出按鈕的下緣（checkbox 不是表單最後一個元素，
   後面還有送出按鈕），兩者之間差了「送出按鈕高度 + 表單欄位
   間距」。這裡用估算值：--space-8(32px) 欄位間距 + 送出按鈕本身
   高度約 34px ≈ 66px，把 bottom 往上偏移這個距離，讓漏斗下緣
   更貼近 checkbox 那一行，而非整個表單含送出鈕的底部 */
.contact-aside-decor {
  /* 統一管理漏斗、社群、營業時間三者定位的容器：寬度固定 420px
     （跟左欄同寬），絕對定位貼在 .contact-inner 左下角，高度等於
     .contact-inner 實際高度（用 100% 撐滿父層）。容器內三個子
     元素都用相對於這個容器的 left/right/bottom 定位，確保
     right:0 是對齊到「左欄範圍內」的右邊界，而不是 .contact-inner
     （整個 1240px 容器）的最右邊 */
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 420px;
  /* 根因修正（2026-09-13 三次）：z-index 負責「視覺疊放順序」，
     pointer-events 負責「滑鼠事件是否穿透」，兩者是獨立的機制，
     缺一不可——先前只調 z-index 導致本容器蓋住同層的
     .contact-meta；只拿掉 z-index 又會變成 .contact-aside
     （繼承全域 [data-reveal] 的 z-index:1）蓋過本容器，導致
     社群連結點不到。正確做法：z-index 維持較高（確保本容器
     漏斗/社群視覺上蓋在 .contact-aside 之上，不被業主要求的
     data-reveal 進場動畫效果蓋住），但容器本身設 pointer-
     events:none 讓滑鼠事件完全穿透到下層，只有真正需要點擊的
     子元素（.contact-aside-decor a，即社群連結）另外設回
     pointer-events:auto 接收點擊。這樣兩個容器不管視覺上誰蓋著
     誰，滑鼠點擊都只會命中真正的可點擊元素，不會誤觸容器本身 */
  z-index: 2;
  pointer-events: none;
}
.contact-aside-decor a {
  pointer-events: auto;
}
/* 漏斗：下緣對齊「得知管道」checkbox 那一行，用估算值往上偏移
   66px（扣掉送出按鈕高度＋欄位間距，跟送出按鈕不同層次，
   所以獨立設定，不跟社群/營業時間共用同一條 bottom 基準線） */
/* 漏斗下緣偏移量統一用變數管理：漏斗跟社群三連結都要對齊到
   同一條線（得知管道 checkbox 那一行），用同一個變數確保兩者
   永遠一致，不會再各自估算出現落差 */
:root {
  /* 聯絡側欄「白色 Logo 組合（漏斗＋SPOUT DESIGN＋白水設計）置頂、
     社群三兄弟置左」的內部相對距離。
     2026-09-22：移除「白水設計 Monday–Friday · 09:30–18:30」文字後，
     這些數值不再是「相對於營業時間那一行」，改為直接相對
     .contact-aside-decor 容器（bottom:0＝.contact-inner 底部）。
     整組（漏斗＋社群）最終顯示位置由 JS 動態對齊送出按鈕下緣
     （main.js，兩頁皆有），這裡的數值只決定 JS 尚未執行前的初始
     落點，以及社群相對漏斗的內部排版間距（沿用移除文字前的
     視覺間距，未重新設計）。
       --contact-lockup-w      Logo 組合寬度（高度由 SVG 比例自動算）
       --contact-lockup-left   Logo 組合左緣 ← 距容器左緣
       --contact-lockup-bottom Logo 組合下緣 ← 距容器底（JS 對齊前的初始值）
       --contact-social-left   社群三兄弟左緣 ← 距容器左緣（與 Logo 組合左緣對齊）
       --contact-social-bottom 社群圖示底 ← 距容器底（JS 對齊前的初始值）
     要微調位置只改這四個變數。 */
  --contact-lockup-w: 243.7px;
  --contact-lockup-left: 1.8px;
  --contact-lockup-bottom: 106.2px;
  --contact-social-left: 2.1px;
  --contact-social-bottom: 46.2px;
}
/* Logo 組合（漏斗＋SPOUT DESIGN＋白水設計，白色 SVG）：定位數值見上方 :root 變數。
   2026-09-22：拿掉「白水設計 Monday–Friday · 09:30–18:30」文字後，
   本容器（.contact-aside-decor）底部不再有文字撐出的參照點，
   bottom 改為直接相對容器（.contact-aside-decor，高度＝
   .contact-inner 高度）計算，整組視覺位置由 JS 動態對齊送出按鈕
   下緣（見 main.js alignContactFormToHeading／首頁對應邏輯），
   這裡的變數值只決定「無 JS 時的初始落點」與「JS 對齊時的相對
   內部排版」，不再是最終顯示位置 */
.contact-decor {
  position: absolute;
  left: var(--contact-lockup-left);
  bottom: var(--contact-lockup-bottom);
  width: var(--contact-lockup-w);
  height: auto;
  aspect-ratio: 1000 / 528.94;
  display: block;
}
/* 社群三連結：業主明確要求跟「SPOUT DESIGN」的 DESIGN 那一行
   同高、左緣切齊 Logo 組合左緣。
   2026-09-22：原本巢狀在「營業時間」文字容器內、靠文字右緣或
   左緣定位——該文字拿掉後，改為直接巢狀在 .contact-aside-decor
   下，用專屬變數 --contact-social-left / --contact-social-bottom
   定位（沿用移除前的視覺間距數值，只是定位基準換成容器本身，
   不再依賴文字容器的隱性寬度） */
.contact-aside-social {
  position: absolute;
  left: var(--contact-social-left);
  bottom: var(--contact-social-bottom);
  display: flex;
  gap: 16px;
  /* 巢狀容器本身不接收滑鼠事件，只有三個 <a> 連結本身可點
     （見 .contact-aside-decor a 統一設 pointer-events:auto） */
  pointer-events: none;
}
.contact-aside-social a {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 2026-09-08 根本性修法：先前用 <img src="...svg"> + mask-image
     的做法，數學驗證過顏色數值完全正確（#505050），但業主持續
     反饋視覺上偏黑，反覆確認多次都沒有進展。這次直接排除
     mask 這條路徑本身的不確定性——改用內嵌 <svg> + fill:currentColor
     （複製自水滴選單裡已經驗證穩定可靠、從未被反饋顏色跑掉的
     寫法），完全跳過 mask 渲染，讓顏色單純透過 CSS color 屬性
     繼承，這是最直接、最少中間環節的做法 */
  color: var(--ink);
  transition: color 0.3s var(--ease-water),
              transform 0.3s var(--ease-water);
}
.contact-aside-social a:hover {
  color: var(--grey-900);
  transform: scale(1.1);
}
.contact-aside-social a svg {
  width: 24px;
  height: 24px;
}



/* ---- 右欄：表單 ----
   關鍵修正：截圖是完全裸露、無容器的極簡表單，不是白色卡片包住的
   一般表單樣式。表單背景直接透明疊在灰底 .contact-section 上，
   輸入框只用一條細底線，不用任何 box/border 包框，整體字級偏小、
   排列疏朗，這是這次重寫的核心方向 */
.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  padding-top: var(--space-2);
}
.form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
/* 純文字輸入框（稱呼／公司／電話／Email）比照截圖改成標籤在左、
   底線輸入框在右的水平並排結構，標籤欄位固定寬度，確保四行的
   底線起始位置對齊在同一條垂直線上，不受標籤文字長短影響 */
.form-field--inline {
  flex-direction: row;
  align-items: stretch;
  gap: var(--space-6);
}
/* 需求描述用的是多行 textarea，不適合 baseline 對齊（會讓標籤
   卡在奇怪的高度），改成頂部對齊，且標籤要跟頂部第一行文字切齊 */
.form-field--textarea {
  align-items: flex-start;
}
.form-field--textarea textarea {
  flex: 1;
}
.form-field--inline label {
  flex-shrink: 0;
  white-space: nowrap;
  width: 180px;
  display: flex;
  align-items: center;
}
.form-field--inline input {
  flex: 1;
}
/* 2026-09-27 根因修正（宗霖回報：全站「需求描述」四個字明顯
   低於右側輸入框的上緣）：外層 .form-field--textarea 已經用
   align-items:flex-start 讓 label／textarea 兩個子項目的容器
   頂部對齊（實測兩者 getBoundingClientRect().top 完全相同，
   這一層沒有問題）。真正落差在 label 內部：.form-field--inline
   label 的基礎規則是 display:flex; align-items:center（給一般
   單行 input 用，讓文字垂直置中對齊 input 高度），原本
   .form-field--textarea label 想覆蓋成 flex-start，但選擇器
   優先權（都是 2 層 class）完全相同時，CSS 採用「書寫順序在後者
   勝出」，這條規則當時寫在 .form-field--inline label 前面，
   等於直接被後面那條蓋掉、從未生效過——這是純粹的規則排列順序
   問題，不是選擇器語法錯誤，實測時完全看不出來（computed style
   顯示的還是被蓋掉後的 center）。
   第一輪只把規則搬到 .form-field--inline label 之後、改成
   align-items:flex-start，實測「容器」邊界確實對齊了，但宗霖
   截圖比對後指出文字視覺上仍然偏低——用 Range API 精確量測文字
   glyph 本身的渲染矩形（不是 label 容器的 DOM box）才抓到第二層
   根因：label 原本留著 padding-top:8px（是為了在舊的
   align-items:center 模式下把文字往下推的微調值），改成
   flex-start 之後，這個 padding 從「抵銷置中效果」變成「純粹疊加
   的多餘位移」，加上 line-height(24px) 比 font-size(16px) 本身
   在 line-box 內置中造成的 4px 偏移，兩者相加＝12px，這才是文字
   glyph 明顯比 textarea 視覺邊框低的真正原因。
   修法：padding-top 改成 0，只留下 line-height 置中造成、幾乎
   無法避免也難以肉眼察覺的 4px 落差（改用 line-height:1 可以
   完全消除，但會讓多行文字或不同字體渲染的行高變得不一致，這裡
   不做這個取捨） */
.form-field--textarea label {
  padding-top: 0;
  align-items: flex-start;
}
.form-field label {
  font-family: var(--font-cn);
  font-weight: 500;
  font-size: var(--text-16);
  color: var(--ink);
}
.required-mark {
  /* 純視覺隱藏，保留 HTML 結構跟語意（span 本身、required 屬性
     都不受影響），screen reader 仍會讀到但畫面上不顯示星號 */
  display: none;
}
.form-field--inline .input-line-wrap {
  /* 根因：底線沒有延伸到頁面右側，不是因為 .contact-form 容器
     寬度不夠——.contact-form 用 max-width:640px + margin-left:auto
     靠右對齊，右邊界本來就已經等於 .contact-inner（全站 1240px
     容器）的右邊界。真正的限制在這裡：max-width:360px 讓底線在
     父層內部就先被攔住，撐不滿 .form-field--inline 扣掉 label
     寬度後的剩餘空間。業主要求這四個純文字欄位（稱呼/公司/電話/
     Email）的底線要延伸到頁面最大寬度右側，拿掉這個限制即可，
     不需要動 .contact-form 本身（那會影響其他欄位寬度） */
  position: relative;
  width: 100%;
}
.form-field--inline .input-line-wrap::after {
  /* 改用 clip-path 直接畫紡錘形（中間粗、兩端細），取代原本用
     background-image 縮放 input-underline-v2.svg 的做法。
     根因：那份 SVG viewBox 是 1000:1（長寬比達1000倍），垂直方向
     的粗細變化只佔 0~0.5 個單位，縮放進一個高度僅個位數px的容器
     時，這個變化幅度會被壓縮到遠低於螢幕可辨識的精細度，肉眼
     完全看不出粗細對比。clip-path 直接控制形狀比例，不受這個
     縮放精度限制，可以做出跟預算拉bar同等明顯的中間粗兩端細效果 */
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--ink);
  clip-path: polygon(
    0% 50%,
    3% 20%,
    50% 0%,
    97% 20%,
    100% 50%,
    97% 80%,
    50% 100%,
    3% 80%
  );
  pointer-events: none;
}
.form-field input[type="text"]:not(.date-input-single),
.form-field input[type="tel"],
.form-field input[type="email"] {
  width: 100%;
  border: none;
  padding: var(--space-1) 0 var(--space-2);
  font-size: var(--text-14);
  font-family: var(--font-cn);
  color: var(--ink);
  background: transparent;
  position: relative;
  z-index: 1;
}
.form-field input[type="text"]:not(.date-input-single):focus,
.form-field input[type="tel"]:focus,
.form-field input[type="email"]:focus {
  outline: none;
}
/* 覆蓋瀏覽器（Chrome/Edge/Safari）內建的 autofill 淺藍色背景。
   直接設定 background-color 對 autofill 無效，瀏覽器會強制蓋過，
   業界標準做法是用超長的 transition-delay 讓瀏覽器誤以為還在
   套用自己的顏色過渡動畫，藉此讓它永遠不會真正顯示出來，
   同時用 -webkit-text-fill-color 確保文字顏色不受影響 */
.form-field input[type="text"]:not(.date-input-single):-webkit-autofill,
.form-field input[type="tel"]:-webkit-autofill,
.form-field input[type="email"]:-webkit-autofill,
.form-field input[type="text"]:not(.date-input-single):-webkit-autofill:hover,
.form-field input[type="tel"]:-webkit-autofill:hover,
.form-field input[type="email"]:-webkit-autofill:hover,
.form-field input[type="text"]:not(.date-input-single):-webkit-autofill:focus,
.form-field input[type="tel"]:-webkit-autofill:focus,
.form-field input[type="email"]:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--ink);
  -webkit-box-shadow: 0 0 0 1000px transparent inset;
  box-shadow: 0 0 0 1000px transparent inset;
  transition: background-color 9999s ease-in-out 0s;
}
/* textarea 背景改用 CSS 線性漸層，精準對應 Illustrator 的漸層設定：
   位置0（上）不透明度0、位置100（下）不透明度100，兩端都是白色，
   角度 90°（垂直方向，上方透明到下方白色不透明）。用原生 CSS
   漸層語法直接重現，比依賴 SVG 圖片更精確、也更輕量 */
.form-field textarea {
  border: none;
  border-radius: var(--radius-lg);
  /* 上下左右內距各降一階：上下 --space-5(20px)→--space-4(16px)，
     左右 --space-6(24px)→--space-5(20px)（2026-08-24 修正：
     先前誤把左右多降了一階到16px，24px降一階應為20px才對） */
  padding: var(--space-4) var(--space-5);
  font-size: var(--text-14);
  font-family: var(--font-cn);
  color: var(--ink);
  background-color: var(--grey-200);
  background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
  resize: vertical;
  /* 內文行距加大，讓填寫的文字視覺上更舒服，不會太擁擠
     （2026-08-24：從 --leading-4(2) 降一階到 --leading-3(1.75)，
     業主覺得原本行距偏鬆） */
  line-height: var(--leading-3);
  /* 邊框改用 box-shadow 多層內陰影疊加，模擬反光/高光的立體質感，
     取代原本單色淡灰邊框（border-image 雖然能做漸層邊框，但會讓
     大圓角失效變直角，這裡改用 box-shadow 完全不受此限制）。
     由上而下疊加：頂部一條較亮的白色高光線（模擬光源由上照射），
     底部一條較暗的陰影線（製造深度/凹陷感），中間用細緻的灰階
     內陰影補足整體邊框輪廓，讓視覺上有金屬/玻璃邊緣的反光效果 */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    inset 0 -1px 0 rgba(0, 0, 0, 0.12),
    inset 1px 0 0 rgba(255, 255, 255, 0.4),
    inset -1px 0 0 rgba(0, 0, 0, 0.08),
    0 0 0 1px rgba(0, 0, 0, 0.06);
}
.form-field textarea:focus {
  outline: none;
}

/* 服務項目：細邊框圓角矩形選項按鈕（不是全圓角藥丸） */
.pill-group {
  display: flex;
  justify-content: space-between;
  /* 寬度由 JS 動態量測 .budget-field（預算 bar）實際寬度後同步設定，
     確保兩者精準對齊，不用猜測的 grid 比例（見 main.js 的
     alignPillGroupToBudgetField） */
}
/* 服務項目／得知管道的必選錯誤提示：預設隱藏，JS 在驗證失敗時
   加上 .is-visible 顯示。用紅色文字明確標示錯誤，跟其他中性色
   文字區隔開 */
.field-error-message {
  display: none;
  margin-top: var(--space-2);
  font-size: var(--text-14);
  color: #c0392b;
}
.field-error-message.is-visible {
  display: block;
}
/* 原生必填欄位（姓名/公司/Email/需求描述）驗證失敗時的樣式，
   跟服務項目/得知管道共用同一套紅色錯誤語彙，避免只靠瀏覽器
   原生提示氣泡（各瀏覽器長相不一，也常常不夠顯眼）。
   注意：.form-field--inline 底下的底線是 .input-line-wrap::after
   這個偽元素畫出來的紡錘形，不是 input 自己的 border，所以錯誤色
   要套在偽元素的 background 上才會生效；textarea 沒有這層 wrap，
   直接用 border 即可 */
.contact-form .input-line-wrap.is-invalid::after {
  background: #c0392b;
}
.contact-form textarea.is-invalid {
  border-color: #c0392b;
}
.contact-form .field-error-message--inline {
  margin-top: var(--space-1);
}
/* .pill 的視覺樣式已併入共用元件 .tag-pill（見上方「共用元件：
   膠囊標籤」區塊），這裡只保留 class 名稱給 HTML/JS 用於語意
   跟互動邏輯辨識（js/main.js 的服務項目單選邏輯抓的是 .pill），
   不再重複宣告樣式 */

/* 預算範圍 + 完工日期並排 */
.form-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-16);
  align-items: start;
}
/* completion-field 所在的 .form-row 第二欄是 grid-template-columns
   的 auto，寬度會依內容自然撐開，沒有明確寬度基準。這導致內部
   .date-input-single 的 flex:1 沒有可撐開的空間、退化成貼合
   placeholder 文字本身的寬度，造成底線只出現在文字下方一小段、
   沒有貫穿整個視覺上的輸入框範圍。這裡明確給 completion-field
   最小寬度，讓 flex:1 有效撐開 */
.completion-field {
  min-width: 260px;
}
.budget-note {
  font-size: var(--text-14);
  font-weight: 500;
  color: var(--grey-800);
}

/* 雙滑桿：極簡水滴造型把手，細線軌道 */
.range-slider {
  position: relative;
  height: 20px;
  margin: var(--space-6) var(--space-2) 0;
}
/* 改用 clip-path 直接畫「兩端粗、中間細」的形狀，取代原本用
   SVG（預算拉Bar.svg）左右拼接的做法。根因：使用者這次提供的
   底線_2.svg viewBox 是 1000:1，跟先前四個文字欄位底線踩過的坑
   完全一樣——這種極扁比例的圖案縮放進只有個位數px高的容器時，
   粗細變化幅度會被壓縮到遠低於螢幕可辨識精細度，肉眼看不出來。
   clip-path 直接控制形狀比例，不受縮放精度限制，形狀為兩端在
   0%/100% 位置達到最寬（比中間更粗），中間 50% 位置收窄，
   線條主體厚度先抓 0.75px */
.range-slider-track {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 4px;
  background: var(--ink);
  opacity: 0.35;
  transform: translateY(-50%);
  clip-path: polygon(
    0% 15%,
    3% 35%,
    50% 47%,
    97% 35%,
    100% 15%,
    100% 85%,
    97% 65%,
    50% 53%,
    3% 65%,
    0% 85%
  );
}
.range-slider-fill {
  position: absolute;
  top: 50%;
  height: 4px;
  background: var(--ink);
  transform: translateY(-50%);
  clip-path: polygon(
    0% 15%,
    3% 35%,
    50% 47%,
    97% 35%,
    100% 15%,
    100% 85%,
    97% 65%,
    50% 53%,
    3% 65%,
    0% 85%
  );
  /* left/right 由 JS 依拖曳位置即時設定 */
}
.range-slider-handle {
  position: absolute;
  top: 50%;
  width: 12px;
  height: 25px;
  /* 改用正式的水滴 SVG（跟 nav 選單水滴同一份素材），取代手刻的
     clip-path 形狀——手刻的水滴造型跟品牌識別的水滴不一致，
     這裡改用 mask 疊色，跟全站水滴視覺語言統一 */
  background-color: var(--ink);
  -webkit-mask: url('../assets/icons/droplet-black.svg') center / contain no-repeat;
  mask: url('../assets/icons/droplet-black.svg') center / contain no-repeat;
  transform: translate(-50%, -50%);
  cursor: grab;
  transition: transform 0.15s var(--ease-water);
  /* left 由 JS 依拖曳位置即時設定 */
}
.range-slider-handle:active {
  cursor: grabbing;
  transform: translate(-50%, -50%) scale(1.15);
}
.range-slider-labels {
  display: flex;
  justify-content: space-between;
  margin-top: var(--space-2);
  font-family: var(--font-en);
  font-size: 13px;
  color: var(--ink);
}
.budget-noscript-select {
  /* 根因：原本嘗試用 appearance:none 拿掉原生外觀、改用自訂
     SVG 箭頭，目的是解決原生外觀跟自訂 padding 疊加造成的文字
     重疊問題。但業主兩輪實測都回報選項內容完全消失（不只是
     文字重疊，是整個選單都看不見），先後嘗試補 line-height／
     min-height／改用完全標準編碼的 SVG data URI 都沒有解決。
     這個開發環境沒有瀏覽器可以實際渲染驗證，與其繼續在
     appearance:none 這條路線上疊加沒有把握的猜測性修正，改為
     放棄自訂外觀、恢復瀏覽器原生 <select> 樣式——原生外觀是
     瀏覽器保證一定會顯示的基本行為，不會因為 CSS 疊加而完全
     消失，優先確保「看得到、能用」，犧牲一點跟其他輸入框的
     視覺一致性（原生下拉箭頭樣式）換取確定性 */
  width: 100%;
  border: none;
  border-bottom: 1px solid var(--ink);
  padding: var(--space-2) 0;
  margin-top: var(--space-4);
  font-size: var(--text-14);
  font-family: var(--font-cn);
  color: var(--ink);
  background-color: transparent;
  cursor: pointer;
}

/* 完工日期：年/月/日三個輸入框，僅底線 */
.date-inputs {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-2);
}
.date-input-single {
  flex: 1;
  min-width: 160px;
  /* 明確關閉瀏覽器原生輸入框外觀（appearance），避免部分瀏覽器
     在 focus 狀態時殘留原生邊框裝飾效果，跟自訂的 border-bottom
     疊加造成兩端翹起的弧線，確保只有純粹的一條直線 */
  appearance: none;
  -webkit-appearance: none;
  border: none;
  border-bottom: 1px solid var(--grey-500);
  border-radius: 0;
  padding: var(--space-1) 0 var(--space-2);
  font-size: var(--text-14);
  font-family: var(--font-cn);
  color: var(--ink);
  background: transparent;
  text-align: left;
}
.date-input-single:focus {
  outline: none;
  border-radius: 0;
  border-bottom-color: var(--ink);
}
.date-input-single:focus-visible {
  /* 覆蓋全站 input:focus-visible 的 outline + border-radius 規則
     （見 style.css 開頭的無障礙 focus 樣式）。那組規則是為了鍵盤
     操作可視性設計的圓角外框，但套在這種細長的底線輸入框上，
     outline 的圓角在兩端視覺上會像「線條往上翹」，這裡明確關閉，
     只保留單純的底線顏色變化作為 focus 提示 */
  outline: none;
  border-radius: 0;
}
.date-input-single:-webkit-autofill,
.date-input-single:-webkit-autofill:hover,
.date-input-single:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--ink);
  -webkit-box-shadow: 0 0 0 1000px transparent inset;
  box-shadow: 0 0 0 1000px transparent inset;
  transition: background-color 9999s ease-in-out 0s;
}

/* 日曆選擇器：可見的小按鈕（圖示）+ 隱藏的原生 date input。
   點擊按鈕觸發原生 input[type=date] 的 showPicker()，使用者用
   瀏覽器內建日曆點選完成後，JS 把值填回上面單一的文字輸入框，
   兩種輸入方式（手動打字／日曆點選）並存 */
.date-picker-trigger {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--grey-700);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color 0.3s var(--ease-water);
}
.date-picker-trigger:hover {
  color: var(--ink);
}
.date-picker-trigger svg {
  width: 100%;
  height: 100%;
}
.date-picker-native {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* 得知管道：方形小勾選框 */
.checkbox-group {
  display: flex;
  flex-wrap: wrap;
  /* 2026-09-26 根因修正（宗霖回報：得知管道兩排 checkbox 之間的
     行距太寬）：原本單一 gap:var(--space-6)（24px）會同時套用在
     水平（同一排項目間）跟垂直（換行後排與排之間）兩個方向——
     flexbox 的 gap 屬性本來就是控制「行與列的間距」統一值，兩者
     天生綁在一起，這裡的視覺問題其實是「兩個方向需要不同數值」，
     不是單一數值調整就能兩全。拆成 row-gap／column-gap 分開設定：
     水平（column-gap）維持原本 24px 不變，垂直（row-gap）縮小到
     var(--space-3)(12px)，只改行距，同排項目間的間距不受影響 */
  column-gap: var(--space-6);
  row-gap: var(--space-3);
}
.checkbox-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-cn);
  font-size: var(--text-14);
  color: var(--ink);
  cursor: pointer;
}
.checkbox-item input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  border: 1px solid var(--ink);
  border-radius: 2px;
  cursor: pointer;
  position: relative;
}
.checkbox-item input[type="checkbox"]:checked {
  background: var(--ink);
}
.checkbox-item input[type="checkbox"]:checked::after {
  content: '';
  position: absolute;
  left: 4px;
  top: 1px;
  width: 3px;
  height: 7px;
  border: solid var(--white);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}

.form-submit {
  align-self: flex-end;
  border: 1px solid var(--ink);
  border-radius: var(--radius-full);
  padding: var(--space-2) var(--space-8);
  font-family: var(--font-en);
  font-weight: 500;
  font-size: var(--text-16);
  color: var(--ink);
  background: transparent;
  transition: background-color 0.3s var(--ease-water),
              color 0.3s var(--ease-water);
}
.form-submit:hover {
  background: var(--ink);
  color: var(--white);
}

/* 缺 SVG 素材佔位：右下角水滴裝飾 */
.contact-corner-decor-placeholder {
  position: absolute;
  right: var(--space-12);
  bottom: var(--space-12);
  width: 32px;
  height: 48px;
  background: var(--placeholder);
  border-radius: var(--radius-sm);
}

/* 2026-09-27 根因修正（宗霖回報：全站「聯絡我們」區塊 —— 三個服務
   項目 pill 跟預算範圍拉bar太擠，要求各自獨立一橫欄）：
   實測宗霖截圖來源是 Chrome DevTools 模擬 iPad Pro 13（CSS 寬度
   1032px）。全站的手機/平板單欄化斷點是 max-width:1024px，1032px
   剛好卡在這條線的「桌機版」那一側，套用桌機版的
   .contact-inner{grid-template-columns:420px 1fr} 雙欄佈局——
   扣掉左欄 420px 跟 gap 後，右欄表單可用寬度被壓縮到約 500px 出頭，
   裡面的 .form-row 再切成「預算範圍／完工日期」兩欄並排
   （grid-template-columns:1fr auto），兩層並排疊加，才會讓三個
   服務項目 pill 被壓到文字直式換行、預算 bar 兩端幾乎貼在一起。
   宗霖指定的修法：只在 .contact-inner／.form-row 這兩個聯絡表單
   容器另外新增這段 min-width:1025px 到 max-width:1099px 的局部
   規則，讓 1025~1099px 這段目前吃不到全站 1024px 斷點的寬度也切
   成單欄；不去更動全站共用的 1024px 斷點分界本身（避免間接影響
   其他所有跟這條斷點掛鉤的規則與已定案的桌機/平板版面）。
   上限抓 1099px（略高於複現用的 1032px，留一點餘裕涵蓋其他機型的
   類似寬度），下限 1025px 確保跟既有 1024px 規則的生效範圍完全不
   重疊、不會有 CSS 書寫順序陷阱（見 handoff README 第 1 節第 3 點）。
   .contact-form 額外覆蓋 width/max-width/margin-left 的原因跟
   下面 1024px 區塊記載的原因相同：桌機版 .contact-form 有
   max-width:640px + margin-left:auto（讓表單在兩欄並排時偏窄、
   靠右對齊），單欄化後如果不歸零，表單不會撐滿這段寬度，仍會維持
   偏窄靠右的桌機視覺、無法真正利用單欄化後多出來的寬度。 */
@media (min-width: 1025px) and (max-width: 1099px) {
  .contact-inner { grid-template-columns: 1fr; }
  .contact-aside { min-height: auto; margin-bottom: var(--space-16); }
  .form-row { grid-template-columns: 1fr; }
  .contact-form { min-width: 0; width: 100%; max-width: 100%; margin-left: 0; }
  /* .contact-aside-decor（漏斗裝飾／SPOUT DESIGN Logo／社群三連結）
     是桌機版兩欄並排專用的 position:absolute 定位，寬度固定對齊
     420px 左欄、高度撐滿 .contact-inner。上面把 .contact-inner 改成
     單欄後，這個容器的高度計算基準跟著跑掉（變成兩個子元素堆疊後
     的總高度，不是桌機版單一左欄的高度），實測會飄到頁面中段、
     疊在「得知管道」checkbox 那一段，文字互相重疊——這正是下面
     1024px 區塊已經記載過、同一套結構性成因在這段寬度重新出現。
     修法比照 1024px 區塊：直接隱藏（品牌 Logo／社群連結內容跟
     Footer 重複，不需要在這個寬度另外設計適應版面的定位邏輯） */
  .contact-aside-decor { display: none; }
}

@media (max-width: 1024px) {
  .contact-inner { grid-template-columns: 1fr; }
  .contact-aside { min-height: auto; margin-bottom: var(--space-16); }
  .form-row { grid-template-columns: 1fr; }
  /* 2026-09-25 根因修正（宗霖回報：手機版全站「聯絡我們」區塊大跑版）：
     .contact-inner 切成單欄（grid-template-columns:1fr）之後，右欄
     （放 .contact-form 的那個 grid item）預設 min-width:auto——這是
     CSS Grid／Flex 的預設值，意思是「這個 track 不會縮到比裡面內容
     的 min-content 還窄」。.contact-form 裡面的 .form-field--inline
     是「180px 固定寬 label ＋ 底線輸入框」並排的橫向排版，label 設了
     flex-shrink:0（不能縮），這個組合的 min-content 寬度遠大於手機
     可用寬度，於是整個右欄／.contact-form 被撐開到超過 .contact-inner
     （也就是超過螢幕邊界），底線、預算滑桿、需求描述框、得知管道
     checkbox 列、送出按鈕全部一起被撐出去，才會看起來「大跑版」。
     這正是這份文件早先 RWD 掃描報告過的已知結構性 bug（.contact-inner
     手機版單欄撐開），這次宗霖要求處理。
     修法：把這個 grid item 的 min-width 明確歸零，讓瀏覽器改成用
     「可用空間」而不是「內容最小需求寬度」來決定這個 track 該多寬，
     裡面的 flex 子元素（label 固定、輸入框 flex:1）才能真正照可用
     空間縮小，不會撐破容器。只在這個斷點覆蓋，不影響桌機版兩欄並排
     時 .contact-form 本來就有 max-width:640px 的固定寬度需求 */
  /* 2026-09-25 根因修正第二輪（宗霖回報：手機版全站「聯絡我們」區塊
     大跑版）：上面 .contact-form 的 min-width:0 沒有解決問題——實測
     .contact-form 的 computed width 仍是 419px。真正原因不是
     min-width:auto 撐開 grid track，而是 .contact-form 桌機版寫的
     `max-width:640px; margin-left:auto;`（讓表單在兩欄並排時偏窄、
     靠右對齊）：grid item 只要設了 auto margin，就會讓瀏覽器改成
     「用內容自然寬度＋auto margin 推到一側」，不會再拉伸填滿整個
     track 寬度——這在桌機兩欄並排、track 本身夠寬時沒問題，但單欄
     版面下，.contact-form 的「內容自然寬度」是由裡面 .form-field--inline
     （180px 固定 label＋輸入框）撐出來的最小需求寬度（419px），
     而不是可用的螢幕寬度（342px），表單整個超出容器，內部的底線、
     預算滑桿、需求描述框、checkbox 列、送出按鈕全部一起被撐出螢幕
     外，這才是「大跑版」的真正原因。上面的 min-width:0 對這個情境
     沒有作用（保留著也無害），真正需要覆蓋的是 width／max-width／
     margin-left 這三個造成「不撐滿、用內容自訂寬度」效果的屬性 */
  .contact-form { min-width: 0; width: 100%; max-width: 100%; margin-left: 0; }
  /* 2026-09-28：原本這裡有一條 .contact-aside-decor { display: none; }（≤1024px 單欄化時
     避免漏斗／Logo 疊到表單），2026-09-25 改成「拿回來、放在表單下面」之後，被下方同選擇器的
     display:block 整條蓋掉、從未生效，已刪除；原文與根因說明逐字保存在
     《已移除程式碼備查_2026-09-28.md》E1 */
  /* 2026-09-25 宗霖回報：手機版「送出」按鈕有點被遮到——根因是這個
     右下角水滴裝飾佔位方塊（.contact-corner-decor-placeholder，目前
     還沒有正式 SVG 素材，先用灰色方塊佔位）。它用 position:absolute;
     right/bottom 固定貼齊 .contact-section 的右下角，桌機版表單是
     兩欄並排、送出按鈕不會靠近這個角落，所以不會撞在一起；單欄化後
     送出按鈕變成整個區塊裡最靠右下角的元素，剛好跟這個佔位方塊的
     位置重疊，蓋住按鈕的一小塊區域。這個方塊本來就只是未來要換成
     正式素材的佔位符、不是必要內容，直接在單欄斷點隱藏即可，等
     業主提供正式水滴裝飾素材、且設計出手機版適用的位置後再顯示 */
  /* 2026-09-25 宗霖要求：漏斗＋SPOUT DESIGN Logo＋社群三連結這組裝飾
     內容（上一輪先隱藏避免疊到表單），在手機/平板版重新拿回來，
     改成正常區塊、放在表單下面、footer 前面（不是原本桌機版那套
     絕對定位＋JS 動態貼齊送出按鈕的做法，那套是為兩欄並排設計的）。
     .contact-inner 在這個斷點是 grid 單欄，三個直接子元素
     （.contact-aside／.contact-aside-decor／.contact-form）依 DOM
     順序原本是「側欄資訊→裝飾→表單」，用 order 只調視覺順序、
     不用搬動 DOM（跟 JS 搬 DOM 節點比起來風險更低、也更直觀），
     排列成「側欄資訊→表單→裝飾」 */
  .contact-aside { order: 1; }
  .contact-form { order: 2; }
  .contact-aside-decor {
    order: 3;
    display: block;
    /* 拿掉桌機版「貼在左欄下方、絕對定位」那套機制：position:static
       讓它回到正常文件流，寬度撐滿容器，跟表單同寬對齊；pointer-events
       跟著拿掉 none（桌機版是為了不擋住旁邊 .contact-aside 的文字
       跟社群連結而設，正常流排版不會有這個疊放問題，社群連結需要
       維持可點擊） */
    position: static;
    width: 100%;
    height: auto;
    pointer-events: auto;
    z-index: auto;
    margin-top: var(--space-16);
  }
  .contact-decor {
    /* 桌機版用 left/bottom 絕對定位＋固定 243.7px 寬度（CSS 變數
       --contact-lockup-w），這裡改回正常 block 內容自然置左，寬度
       縮小一階（180px）給手機版畫面比例，比例仍用同一個 aspect-ratio
       維持圖檔不變形 */
    position: static;
    width: 180px;
  }
  .contact-aside-social {
    /* 同樣拿掉絕對定位，改成 Logo 下方的正常區塊，維持原本的橫向
       排列（gap:16px）跟社群圖示樣式，只是定位基準換成一般文件流 */
    position: static;
    margin-top: var(--space-4);
    pointer-events: auto;
  }
  .contact-corner-decor-placeholder { display: none; }
}

/* ==========================================================================
   Footer
   ========================================================================== */
/* ==========================================================================
   Footer（2026-09-07 全新四欄橫向排版，深色背景）
   ========================================================================== */
.site-footer {
  /* 2026-09-21：下內距由 --space-12（48px）改為 42px，上內距與左右維持 48px。
     根因：原本上下都是 48px（盒子相等），但最上緣是標誌／分隔線（無行距留白），最底下是 12–14px 的文字
     （行高 18–22px，上下有行距留白），肉眼看到的下內距比上內距大（桌機 51 vs 48px、手機 54 vs 48px）。
     過程：先試降一級 32px（視覺下比上小 13／10px）→ 宗霖指定 36px → 40px → 42px（現值）。
     ⚠️ 42px 不在間距 token（…32／48…）裡，也不是 4 的倍數（間距系統以 4px 為基準），是宗霖指定的刻意例外，
     所以直接寫 42px（沒有任何 token 組合能湊出 42）。改回去：把第三個值改回 var(--space-12)（手機那條同）。 */
  padding: var(--space-12) var(--space-12) 42px;
  /* 業主提供設計稿：深色背景＋白字，這是全站第一個深色區塊。
     用 --ink（純黑）而不是 --grey-900 之類的深灰，比照設計稿的
     視覺深度，且 --ink 本來就是全站既有 token，不是新造顏色 */
  background: var(--ink);
  color: var(--white);
  text-align: left;
}
.footer-inner {
  max-width: var(--container-max);
  margin: 0 auto;
  display: flex;
  /* 2026-09-08 第三次修正（回歸最單純可靠的方案）：先前在
     align-items:stretch 跟 flex-start 之間來回切換，又試過 JS
     動態量測 + min-height，但 JS 方案有時序風險（reset 跟量測
     之間可能讀到中間狀態，多次執行容易累積誤差，導致分隔線
     時而超出、時而不足，反覆修正都沒有真正穩定）。
     根本問題釐清：業主要的是「分隔線精準切齊品牌欄
     （.footer-links 所在欄位）的下緣」，而品牌欄本身是四欄中
     內容最多的一欄（Logo+公司名+6個站內連結，比 Follow/Contact/
     CTA 三欄內容都多）。只要品牌欄維持是最高的一欄，
     align-items:stretch 讓其他三欄「物理拉伸」到跟品牌欄一樣高，
     分隔線（border-left，長度=元素高度）就會精準等於品牌欄高度，
     不需要任何 JS 計算。.footer-col 本身不是 flex 容器，拉伸
     高度只會在其他三欄底部產生留白，不會把裡面的文字內容位置
     往下推，文字仍貼齊各自欄位頂端 */
  align-items: stretch;
  gap: var(--space-12);
}
.footer-col {
  padding-left: var(--space-12);
  border-left: 1px solid var(--grey-700);
}
.footer-col:first-child {
  padding-left: 0;
  border-left: none;
}
.footer-col--brand {
  flex: 1.4;
  min-width: 0;
}
.footer-col--follow {
  flex: 0.8;
}
.footer-col--contact {
  flex: 1.1;
}
.footer-col--cta {
  flex: 1;
}
.footer-wordmark {
  /* 原本是純文字，改用 Logo SVG mask 呈現。尺寸沿用 header logo
     同一套邏輯：高度＝20px，寬度依 SVG 原始檔案比例
     （283.46 : 26.82）等比換算，維持視覺上該有的長寬比。
     深色背景下改成白色（--white），原本淺色背景版本用 --ink */
  height: 20px;
  width: calc(20px * 283.46 / 26.82);
  margin-bottom: var(--space-4);
  background-color: var(--white);
  -webkit-mask: url('../assets/icons/logo.svg') left center / contain no-repeat;
  mask: url('../assets/icons/logo.svg') left center / contain no-repeat;
}
.footer-brand-name {
  font-size: var(--text-14);
  line-height: var(--leading-2);
  letter-spacing: var(--tracking-xs);
  color: var(--grey-300);
  margin-bottom: var(--space-6);
}
/* 常駐可見的頁尾導覽連結。
   ⚠️ 2026-09-07 除錯記錄：業主反饋這裡 hover 沒有變白色。根因：
   原本這裡沿用 --nav-fg-muted / --nav-fg-hover 這兩個跟水滴選單
   共用的變數，設計初衷是「html[data-nav-bg="dark"] 底下會自動
   切換成深色背景對應版本」——但這個屬性只有在「全站智慧變色
   機制」有在運作時才會被寫入，而那套機制 2026-08-22 已經被業主
   整套關閉（判定時機跟畫面不符，見 js/main.js 對應段落的完整
   說明），html[data-nav-bg="dark"] 永遠不會被設定，這兩個變數
   因此一直讀的是 :root 的預設值（深色文字），不是深色背景對應
   版本，才會看起來「沒有變白」。
   之前處理水滴/扇形選單疊在 Footer 上的類似問題時，是用
   .nav-trigger.is-over-dark 這個 JS 判斷式的局部覆蓋解決的，但
   .footer-links 是 Footer 內部固定的常駐元素（不像水滴會移動
   到 Footer 上方才需要判斷），它本來就永遠身處深色 Footer 裡，
   不需要動態判斷，直接寫死適合深色背景的顏色即可，不透過那組
   共用變數 */
.footer-links {
  /* 2026-09-08：業主要求從「一行一個、直向堆疊六行」改成
     「一行三個、共兩行」的排列方式。原本用 flex-direction:column
     只能做到單欄直向排列，改用 CSS Grid 搭配
     grid-template-columns: repeat(3, ...) 才能讓 6 個連結自動
     排成 3 欄 × 2 列——HTML 裡連結的書寫順序決定了排列順序
     （由左到右、由上到下依序填入）。
     2026-09-10：新增第三列，放室內設計/品牌設計/整合型設計三個
     作品分類連結，業主要求這三個連結要接在「作品案例」正下方。
     因為「作品案例」目前排在第一欄第二列，若照 grid 預設的自動
     流動順序（由左到右、由上到下依序填入）直接把三個新連結插入
     在 HTML 裡「作品案例」後面，會把後面的「常見問題、聯絡我們」
     擠到第三欄，打亂原本 6 個連結的相對位置。
     改用明確的 grid-column 指定：三個新連結固定卡在第一欄
     （grid-column:1），不管它們在 HTML 原始碼裡實際寫在哪個
     位置，都會精準疊在「作品案例」正下方，不影響其餘 6 個連結
     的既有排列（見 .footer-subcategory-links 規則） */
  display: grid;
  grid-template-columns: repeat(3, auto);
  column-gap: var(--space-6);
  /* 2026-09-08：業主要求跟 .footer-social-links 的行距一致，
     兩者都用 var(--space-2)（8px），是同一個變數來源，
     不是各自寫死巧合相同 */
  row-gap: var(--space-2);
  margin-bottom: var(--space-6);
}
/* 2026-09-10 新增：三個作品分類子連結，明確卡在 .footer-links
   grid 的第一欄（跟「作品案例」同一欄），从第三列開始往下排。
   用 grid-column 顯式定位，不依賴 HTML 書寫順序的自動流動，
   避免影響 .footer-links 裡其餘 6 個連結原本的排列位置。
   （2026-09-24：字級／顏色已與其他連結統一，見下方說明；本規則現在只負責排列位置） */
.footer-subcategory-links {
  /* 2026-09-10 三次修正：品牌設計/整合型設計沒有對齊到上方
     「服務項目/常見問題」「獲獎紀錄/聯絡我們」的欄位起始點。
     根因：.footer-links 上方 6 個連結是 CSS Grid（
     grid-template-columns: repeat(3, auto)），每一欄的寬度由
     grid 自動計算、3 欄各自獨立取固定寬度；但這個容器用的是
     display:flex + column-gap，每個連結的寬度是「文字本身的
     寬度」（室內設計/品牌設計都是56px，整合型設計因為多兩個字
     變成70px），用固定間距累加出來的位置自然對不上 grid 的欄位
     邊界——文字越長，越往右偏移越多，這就是「整合型設計」偏移
     量最大的原因。
     修正：改用 display:contents，讓這個容器本身在版面計算上
     「隱形」（不佔用任何 grid cell、不建立自己的排版脈絡），
     內部三個 <a> 直接變成 .footer-links 這個 grid 的真正子項目，
     天然沿用同一組 grid-template-columns 欄寬定義，精準對齊
     上方兩排的欄位起始點，不需要额外計算 gap 或寬度 */
  display: contents;
}
/* 2026-09-20：子連結群組（作品案例的三個分類）永遠從新的一列、第 1 欄開始。
   原本靠「一級連結剛好 6 個＝兩整列」才會自然排到第 3 列第 1 欄；一旦一級連結變成 7 個
   （例如啟用「團隊介紹」，見 toggle_team_nav.py），第 3 列只剩「聯絡我們」一個，子連結會
   接在它後面擠進同一列、最後一個還掉到下一列，分組就亂了。強制第一個子連結從第 1 欄換行，
   目前 6 個一級連結時的排版完全不變（已逐頁比對頁尾連結位置）。 */
.footer-subcategory-links a:first-child { grid-column-start: 1; }
.footer-links a {
  /* 2026-09-26 宗霖要求：連結的可點擊範圍要「hug content」（貼合文字
     大小），不要「fill container」（撐滿整個欄位寬度）。
     根因：父層 `.footer-links` 是 CSS Grid（grid-template-columns:
     repeat(3, auto)），Grid 子項目預設會 stretch（撐滿）自己所在的
     格子寬度，`display:inline-block` 只決定這個連結內部的排版方式，
     並不會阻止它身為 grid 子項目時被撐滿——同一欄裡最長的那個連結
     決定欄寬，其餘較短的連結雖然文字看起來比較窄，實際可點擊／
     觸控的範圍卻跟著撐到跟最長那個一樣寬，滑鼠移到文字右側的空白
     處也會觸發 hover，這就是「fill container」。
     加上 justify-self:start，讓每個連結在自己的格子裡只占文字本身
     需要的寬度、靠左對齊，其餘空間不算在可點擊範圍內 */
  justify-self: start;
  /* 2026-09-08 沿革記錄：
     ① 最早要求跟 Contact 欄完全一致，字級統一成 --text-16
     ② 接著要求站內連結改成跟 Header navbar 一致的 14px，
        當時只改這裡，Follow/Contact 欄維持 16px
     ③ 最終業主要求 Footer 所有連結統一回 14px，Follow 欄
        （.footer-social-links）跟 Contact 欄（.footer-contact-line）
        也一併改成 14px 了，見下方兩處。目前三組字級一致，都是 14px */
  display: inline-block;
  font-size: var(--text-14);
  color: var(--white);
  line-height: var(--leading-2);
  transition: color 0.3s var(--ease-water);
}
.footer-links a:hover {
  color: var(--grey-400);
}
/* 2026-09-24：三個作品分類子連結（室內設計／品牌設計／整合型設計）不再單獨上色。
   宗霖要求：跟上面其他 footer 連結一樣是白色、hover 也一樣，不要特地用顏色把這三頁區分出來。
   做法：刪除原本的 .footer-subcategory-links a（default grey-400）與 :hover（白）兩條覆蓋規則，
   讓這三個 <a> 直接沿用上方 .footer-links a（白字、14px、hover 變 grey-400）與
   .footer-links a:hover，之後這組連結的顏色／字級／hover 都跟其他連結自動一致，不會再分歧。
   原本為了讓覆蓋生效而寫在 .footer-links a 之後的順序限制也一併消失。
   排列相關規則（display:contents、first-child 換行）與此無關，維持不變 */
/* 2026-09-08：版權列從品牌欄內部搬出來，變成獨立於四欄 flex
   佈局之外的橫條，貫穿整個 Footer 寬度。原本 flex-direction:column
   是設計給「品牌欄內部堆疊多行」用的，現在只剩一行文字、且是
   獨立區塊，改成置中對齊，並用 margin-top 跟上方四欄拉開間距
   （業主確認不需要分隔線，只要留白間距即可） */
.footer-legal {
  max-width: var(--container-max);
  /* 2026-09-08：業主反饋原本 --space-12(48px) 太大，縮小兩級到
     --space-6(24px)（階梯：--space-12 → --space-8 → --space-6） */
  margin: var(--space-6) auto 0;
  /* 2026-09-08：業主要求隱私權政策從站內連結清單搬到這一行，
     跟版權文字並排、置右對齊，改成 flex 兩端對齊（版權文字置左、
     隱私權政策置右）。同一輪之後又新增「回到頂部」按鈕，改成
     跟隱私權政策並排在 .footer-legal-right 容器內，這裡的
     space-between 邏輯不用改，右側現在是一個容器而不是單一
     元素，兩端對齊的效果不受影響 */
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
/* 隱私權政策 + 回到頂部並排容器 */
.footer-legal-right {
  display: flex;
  align-items: baseline;
  gap: var(--space-6);
}
/* 回到頂部：<button> 需要重置瀏覽器預設樣式（border/background/
   font 等），視覺上完全比照 .footer-legal-privacy（隱私權政策），
   讓兩者看起來像同一組並排的文字連結，不會有「一個是連結、
   一個是按鈕」的視覺落差 */
.footer-back-to-top {
  border: none;
  background: none;
  padding: 0;
  font-family: inherit;
  cursor: pointer;
}
.footer-copyright {
  font-family: var(--font-en);
  font-size: 12px;
  color: var(--grey-500);
  letter-spacing: var(--tracking-0);
}
/* 隱私權政策：業主要求字級跟版權文字（.footer-copyright）一樣大，
   不是站內連結清單原本的字級，顏色/hover 效果沿用同一套邏輯
   （預設淺灰、hover 變白），這裡只覆蓋字級跟字體家族 */
.footer-legal-privacy {
  font-family: var(--font-en);
  font-size: 14px;
  color: var(--grey-500);
  letter-spacing: var(--tracking-0);
  transition: color 0.3s var(--ease-water);
}
.footer-legal-privacy:hover {
  color: var(--white);
}
.footer-col-label {
  font-family: var(--font-en);
  font-size: var(--text-14);
  font-weight: 500;
  letter-spacing: var(--tracking-xs);
  color: var(--grey-400);
  margin-bottom: var(--space-4);
}
.footer-social-links {
  display: flex;
  flex-direction: column;
  /* 同 .footer-links 的根因修正：align-items:flex-start 才是真正
     讓子項目依內容寬度顯示、不被拉伸撐滿整行的關鍵設定 */
  align-items: flex-start;
  gap: var(--space-2);
}
.footer-social-links a {
  /* 2026-09-08：業主確認社群連結的 hover 熱區也要改成 hug content，
     跟 .footer-links a 用同樣的修法，原因相同：.footer-social-links
     也是 flex column 容器，需要在父容器設定 align-items:flex-start
     才能真正生效（見上方 .footer-social-links 容器規則） */
  display: inline-block;
  /* 2026-09-24：四個社群名稱（Facebook／Instagram／Threads／Youtube）改用指定英文字體。
     根因：此規則原本沒指定 font-family，繼承 body 的 --font-cn（DFLiSong），
     英文字母是由中文字體的內建拉丁字形畫出來，不是 Bodoni Moda */
  font-family: var(--font-en);
  /* 2026-09-08 稍晚：業主要求 Footer 所有連結統一改成 14px
     （跟 .footer-links / .header-nav-links 一致），這裡從
     --text-16 改成 --text-14，不再比照 Contact 欄的 16px */
  font-size: var(--text-14);
  color: var(--white);
  line-height: var(--leading-2);
  transition: color 0.3s var(--ease-water);
}
.footer-social-links a:hover {
  color: var(--grey-400);
}
/* 2026-09-07：業主先要求移除 Contact 欄跟 START THE FLOW 欄，
   後來反悔要求恢復成四欄完整版本，這裡把樣式規則加回來 */
.footer-contact-info {
  display: flex;
  flex-direction: column;
  /* 2026-09-08：業主要求全站 Footer 各欄內部連結的間距統一抓 8px，
     從 --space-3(12px) 改成 --space-2(8px)，跟 .footer-links 的
     row-gap、.footer-social-links 的 gap 一致 */
  gap: var(--space-2);
}
.footer-contact-line {
  display: block;
  /* 2026-09-08：業主要求 Footer 所有連結統一改成 14px，
     從 --text-16 改成 --text-14 */
  font-size: var(--text-14);
  color: var(--white);
  line-height: var(--leading-2);
  transition: color 0.3s var(--ease-water);
}
a.footer-contact-line:hover {
  color: var(--grey-400);
}
.footer-contact-hours {
  /* 2026-09-08：業主確認全站營業時間文字要用 Bodoni Moda
     （--font-en），並加上 0.1em 字距（--tracking-xs）。之前這裡
     一度誤改成 --font-cn，這次直接修正回英文字體 */
  font-family: var(--font-en);
  font-size: var(--text-14);
  letter-spacing: var(--tracking-xs);
  color: var(--grey-400);
  line-height: var(--leading-2);
}
.footer-cta-heading {
  display: block;
  font-family: var(--font-en);
  font-weight: 700;
  font-size: clamp(24px, 2.6vw, 28px);
  line-height: 1.1;
  color: var(--white);
  letter-spacing: var(--tracking-0);
  margin-bottom: var(--space-4);
}
.footer-cta-text {
  font-size: var(--text-14);
  color: var(--grey-300);
  line-height: var(--leading-2);
}
/* footer 聯絡我們按鈕（2026-09-13 新增）：footer 本身是黑底白字，
   .cta-arrow 預設 hover 效果是圓圈變黑底白字——在已經是黑底的
   footer 上，hover 時圓圈會直接「隱形」在背景裡。這裡反轉配色，
   hover 時改用白底黑字，在深色背景上才看得出互動回饋 */
.footer-cta-link {
  margin-top: var(--space-4);
  padding-top: 0;
  /* 2026-09-14 修正：.cta-arrow 本體自帶左右 padding（--space-2＝
     8px），這裡跟上面同樣道理歸零上下 padding，卻漏了左側——
     導致按鈕（含圓圈圈）的視覺左邊界比 .footer-cta-heading／
     .footer-cta-text（都沒有左側 padding）多縮進 8px，造成圓圈圈
     跟文字看起來偏右、沒有對齊標題與內文的左側。右側 padding
     維持不動，保留原本的呼吸感跟 hover 熱區大小 */
  padding-left: 0;
  color: var(--white);
  font-size: var(--text-18);
}
.footer-cta-link .arrow-circle {
  width: var(--icon-md);
  height: var(--icon-md);
}
.footer-cta-link:hover .arrow-circle {
  background-color: var(--white);
  border-color: var(--white);
  color: var(--ink);
}

@media (max-width: 1024px) {
  /* 平板：四欄橫向空間不夠寬時，改成兩欄兩排，維持分隔線邏輯
     （第一欄不用左邊界跟分隔線，其餘欄位保留） */
  .footer-inner {
    flex-wrap: wrap;
  }
  .footer-col--brand {
    flex: 0 0 100%;
    border-left: none;
    padding-left: 0;
    margin-bottom: var(--space-8);
  }
  .footer-col--follow,
  .footer-col--contact,
  .footer-col--cta {
    flex: 1 1 30%;
  }
}
@media (max-width: 767px) {
  /* 手機：完全改回直向堆疊，分隔線改成上邊界（水平線）取代左邊界
     （垂直線），閱讀順序維持品牌→Follow→Contact→CTA */
  .site-footer { padding: var(--space-12) var(--space-6) 42px; } /* 下內距同桌機：42px（2026-09-21，見上方 .site-footer 註解） */
  .footer-inner {
    flex-direction: column;
    gap: var(--space-8);
  }
  .footer-col {
    flex: 1 1 auto;
    width: 100%;
    padding-left: 0;
    border-left: none;
  }
  /* 2026-09-26 根因修正（宗霖回報：室內設計/品牌設計/整合型設計最後
     一排連結到下面分隔線的間距，比分隔線到「Follow」的間距明顯大很多，
     希望兩邊一致）：
     手機版連結列表到分隔線之間，實際疊了三層間距：
       .footer-links 自己的 margin-bottom（24px，桌機版用來跟品牌欄
       其他內容留白，手機版沒有意義卻沒歸零）
       + .footer-col--brand 的 margin-bottom（32px，這條其實是給上面
       ≤1024px 「兩欄兩排」平板版排版用的，≤767 手機版沒有另外覆蓋，
       但兩個 @media 在 390px 寬度會同時生效，這條平板專用的間距就
       這樣漏進了手機版）
       + .footer-inner 的 gap（32px，這才是手機版真正想要的、跟其他
       欄位之間統一的間距）
     三層相加＝88px，比分隔線到 Follow 只有單一來源的 32px（.footer-col
     的 padding-top）大了 56px，這就是「間距明顯不一致」的根因。
     修法：手機版把前兩層多餘的間距歸零，只留 .footer-inner 的 gap，
     跟其他欄位間距（包含分隔線到 Follow）統一使用同一個 32px 來源 */
  .footer-col--brand { margin-bottom: 0; }
  .footer-links { margin-bottom: 0; }
  .footer-col:not(:first-child) {
    padding-top: var(--space-8);
    border-top: 1px solid var(--grey-700);
  }
  /* 2026-09-25 宗霖要求：版權列／隱私權政策／回到頂部 3 項擠在同一橫排太擠，分兩橫列。
     .footer-legal-right（隱私權政策＋回到頂部）本來就是同一個群組，維持在一起當第二行，
     版權文字單獨一行，不需要拆散重新分組 */
  .footer-legal {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
  }
  /* 2026-09-25 宗霖要求：Follow 的 4 個社群連結改成兩欄兩排（原本是單欄直向堆疊 4 列）。
     grid-template-columns 用 auto 而不是 1fr，讓每欄寬度貼合各自內容（Instagram 比 FB 寬），
     不會被拉伸撐滿；四個名稱長度落差不大，兩欄自然對齊也不會歪斜 */
  .footer-social-links {
    display: grid;
    grid-template-columns: repeat(2, auto);
    column-gap: var(--space-8);
    row-gap: var(--space-2);
  }
}

/* ==========================================================================
   子頁面共用骨架樣式（關於我們/作品案例/Q&A/聯絡我們）
   ========================================================================== */
.page-header {
  /* 業主要求：所有子頁面的中文標題要固定在同一個水平高度，不受
     各頁英文小標文字長短影響（原本 .page-label 是直式文字、用
     自然文件流「推開」下方的 .page-title，字數越多的英文標題
     — 例如 "( ABOUT US )" 比 "( FAQ )" 長 — 就會把中文標題推得
     越下面，導致每頁進站時看到的內容位置都不一樣）。
     改成 position:relative 容器，.page-label 用絕對定位疊在左上角
     （不再佔用文件流高度），.page-title 改用固定的 padding-top
     直接往下推到統一高度，不受英文小標長度影響。這個固定高度
     以 works.html（業主指定的基準頁）為準：128px（原 padding-top）
     + 英文小標的最大可能高度 + 間距，實測抓一個安全值 */
  position: relative;
  padding-top: var(--space-32);
  margin-bottom: var(--space-16);
}
.page-label {
  writing-mode: vertical-rl;
  font-family: var(--font-en);
  font-size: var(--text-16);
  letter-spacing: var(--tracking-0);
  color: var(--grey-700);
  /* 改用絕對定位疊在容器左上角，不再佔用文件流高度、不會推開
     下方的 .page-title。水平位移量由 JS 動態量測 Logo 實際渲染
     位置後設定（見 js/main.js 的 alignPageLabelToLogo），不用
     猜測的固定 px 值 */
  position: absolute;
  top: var(--space-32);
  left: 0;
}
.page-title {
  font-family: var(--font-cn);
  font-weight: 700;
  /* 統一跟全站其他區塊標題（.contact-title「聯絡我們」、
     .about-headline、.stat-block h2）同一套字級，原本
     clamp(32px,4vw,48px) 明顯比其他區塊標題大一截，不一致 */
  font-size: clamp(26px, 3vw, 38px);
  line-height: 1.35;
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
  /* 固定的 margin-top，取代原本「被 .page-label 自然文件流高度
     推開」的效果——.page-label 現在是絕對定位，不再佔用空間，
     這裡改用寫死的間距讓中文標題落在統一水平線。數值取
     --space-32(128px)：比全站最長的英文小標「( ABOUT US )」
     實測高度(100px)多留一點餘裕，確保任何頁面的英文小標都不會
     跟中文標題重疊 */
  margin-top: var(--space-32);
  margin-bottom: var(--space-3);
}
/* ---- FAQ 區塊「更多問答」CTA（2026-09-08 新增）----
   只在首頁 FAQ 區塊使用，比照首頁「代表案例」的 .showcase-cta
   視覺與定位邏輯：右側、垂直置中對齊中文標題。.page-header 是
   全站共用元件（about/works/faq 子頁面都用同一顆 class），
   不能直接改動它本身的排版方式去容納這顆 CTA（會影響其他沒有
   這個需求的頁面），改成獨立的絕對定位元素疊加在容器右側，
   不影響 .page-header 既有的定位邏輯。垂直位置的初始值只是
   JS 執行前的備援，實際精準值由 main.js 的
   alignFaqCtaToPageTitle 動態計算對齊 .page-title 垂直中心 */
.page-header-cta {
  position: absolute;
  top: var(--space-32);
  right: 0;
  /* 位置由 main.js 的 alignFaqCtaToPageTitle() 動態計算並寫入
     style.transform（垂直置中對齊 .page-title）。顯示時機交給
     [data-reveal] 的 opacity 淡入（跟中英標同一顆 is-visible、
     同時觸發），不再需要 visibility 開關去延遲顯示——完整除錯
     記錄見《已移除程式碼備查_2026-09-21.md》A1 */
}

/* ---- 隱私權政策頁（privacy-policy.html）內容排版 ----
   2026-09-12 更新：內容已從「準備中」骨架換成正式九章條文，
   這裡的 .privacy-policy-content 是正式內容的外層容器 */
.privacy-policy-content {
  /* 業主指定跟 awards.html 的 .award-page-intro 套用同一個公式，
     不是同一個固定數字。當時是為了讓內文精準對齊兩欄卡片其中一欄
     寬度；這裡雖然沒有卡片可對齊，但業主要求視覺寬度比照辦理，
     所以直接沿用同一個公式，維持兩處未來一起等比例縮放。
     ⚠️ 2026-09-26：這個公式在手機版窄容器上會算出過窄的寬度（實測
     155px，沒幾個字就換行），跟 .award-page-intro 是同一個根因，
     手機版覆蓋見下方 @media (max-width:767px) */
  max-width: calc((100% - var(--space-8)) / 2);
}
@media (max-width: 767px) {
  .privacy-policy-content { max-width: 100%; }
}
.privacy-policy-updated {
  font-size: var(--text-16);
  /* 業主指定色 #505050（非 10 階灰階 token 內的數值，
     比照 service.html 分類英標的做法，直接寫死該色碼） */
  color: #505050;
  margin-bottom: var(--space-8);
}
.privacy-policy-intro {
  font-size: var(--text-16);
  line-height: var(--leading-3);
  color: var(--ink);
  letter-spacing: var(--tracking-xs);
  margin-bottom: var(--space-12);
}
.privacy-policy-heading {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: var(--text-20);
  color: var(--ink);
  letter-spacing: var(--tracking-xs);
  margin-top: var(--space-12);
  margin-bottom: var(--space-4);
}
.privacy-policy-p {
  font-size: var(--text-16);
  line-height: var(--leading-3);
  color: var(--ink);
  letter-spacing: var(--tracking-xs);
  margin-bottom: var(--space-4);
}
.privacy-policy-p a {
  /* 2026-09-19：全站 a 預設 text-decoration:none，內文中的外部連結
     （Google 隱私權政策網址）需要底線才看得出可點擊 */
  text-decoration: underline;
  text-underline-offset: 3px;
  overflow-wrap: anywhere; /* 長網址在窄螢幕不撐破版面 */
}
.privacy-policy-list--contact li {
  color: var(--ink);
}
.privacy-policy-list {
  padding-left: var(--space-6);
  color: var(--ink);
  font-size: var(--text-16);
  line-height: var(--leading-3);
  /* 補上全站內文段落統一套用的 0.1em 字距 */
  letter-spacing: var(--tracking-xs);
  margin-bottom: var(--space-4);
}
.privacy-policy-list li {
  margin-bottom: var(--space-3);
}

/* ---- 作品案例頁：左側分類側欄 + 右側作品 grid ----
   左側 .project-sidebar 固定寬度不隨內容伸縮；右側 .project-grid
   是可以獨立捲動的區域（業主截圖標註「左方標籤選單是固定住的，
   右邊下滑會出現新的內容」），用 sticky 讓側欄跟著頁面捲動但
   不超出 section 範圍，不用 JS 額外控制定位。 */
.project-layout {
  display: flex;
  align-items: flex-start;
  gap: var(--space-16);
}
.project-sidebar {
  flex: 0 0 260px;
  position: sticky;
  top: var(--space-24);
}
.project-filter-group + .project-filter-group {
  margin-top: var(--space-8);
}
/* 2026-09-09：從 <div> 改成 <a>，連結到對應的主分類 demo 頁
   （works-interior/branding/integrated.html）。回應 SEO 顧問建議
   ——三大服務分類應有獨立入口頁，這裡讓 works.html 現有的分類
   標題本身就是通往該分類頁的連結，同時也建立起「作品總覽頁 →
   主分類頁」的內部連結，有利於分類頁被搜尋引擎正確索引。
   視覺上沿用原本 <div> 的樣式（字重/顏色不變），只加 hover 底線
   提示這是可點擊連結；標籤本身在側欄的篩選功能（點擊子標籤篩選
   右側作品）完全不受影響，因為篩選邏輯抓的是 .project-filter-item
   不是 .project-filter-category */
/* 2026-09-10：display 從 block 改成 inline-block——block 會讓這個
   <a> 撐滿父容器 .project-sidebar 的整個寬度，可點擊熱區跟著側欄
   一樣寬（fill container），業主反饋不要這樣，要熱區貼合文字本身
   寬度即可（hug content）。inline-block 才能讓寬度由內容決定，
   同時保留 margin-bottom 等區塊排版屬性正常生效 */
.project-filter-category {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: var(--text-16);
  color: var(--ink);
  margin-bottom: var(--space-3);
  display: inline-block;
}
.project-filter-category:hover {
  text-decoration: underline;
}
.project-filter-tags {
  display: flex;
  flex-wrap: wrap;
  /* 上下(換行)、左右分開設定，不再共用單一 gap：
     上下(row-gap) 比左右(column-gap) 大一階（8px -> 12px），
     左右維持原本的 8px 不變 */
  row-gap: var(--space-3);
  column-gap: var(--space-2);
}
/* .project-filter-item 的視覺樣式已併入共用元件 .tag-pill（見全站
   共用元件區塊），這裡只保留 class 名稱給 HTML/JS 用於篩選邏輯
   辨識（js/main.js 的作品分類篩選邏輯抓的是 .project-filter-item），
   不再重複宣告樣式 */

.project-grid {
  flex: 1;
  min-width: 0;
  min-height: 240px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-16) var(--space-8);
  align-content: start;
}
.work-card {
  display: block;
  /* 業主要求：hover/可點擊的游標樣式只在照片跟標題範圍生效，
     標籤區域不算。原本整個 .work-card 給 cursor:pointer 會讓
     滑鼠移到標籤上也顯示手指游標，容易讓人誤以為標籤本身可點擊
     （事實上 .work-tag 是純展示用、不可點擊篩選）。拿掉這裡的
     全域 cursor:pointer，改成只在 .work-thumb / .work-name
     各自套用（見下方），搭配 js/main.js 用 mouseenter/mouseleave
     控制的 .is-hover-active class 觸發縮圖變色效果。
     2026-08-24：光是不寫 cursor:pointer 還不夠——<a> 標籤本身
     瀏覽器預設就會顯示手指游標，不需要額外 CSS 就會這樣，所以
     明確寫 cursor:default 覆蓋掉這個預設行為，確保 .work-card
     底下除了 .work-thumb / .work-name 以外的所有區域（包含
     .work-meta 的空白間隙、.work-tags），滑鼠移過去都維持一般
     箭頭游標，不會有任何「這裡可以點擊」的視覺暗示 */
  cursor: default;
}
.work-thumb,
.work-name {
  cursor: pointer;
}
/* 進場動畫：套用全站共用的 [data-reveal] 淡入機制（見全站共用
   樣式區塊），捲動進入視窗時整張卡片從下方淡入。額外用
   :nth-of-type 給每張卡片依序遞增的 transition-delay，讓多張
   卡片依序浮現、有層次感，而不是所有卡片同時彈出。只做到第 6 張
   （超過 6 張的延遲封頂在同一個值，避免捲動很久才進場的卡片還要
   多等好幾秒才浮現，等待感過重） */
.work-card:nth-of-type(1) { transition-delay: 0s; }
.work-card:nth-of-type(2) { transition-delay: 0.08s; }
.work-card:nth-of-type(3) { transition-delay: 0.16s; }
.work-card:nth-of-type(4) { transition-delay: 0.24s; }
.work-card:nth-of-type(5) { transition-delay: 0.32s; }
.work-card:nth-of-type(n+6) { transition-delay: 0.4s; }
/* 作品縮圖（WordPress 版：業主在後台上傳列表縮圖時 .work-thumb 內會有一張 <img>；靜態原型沒有 <img>，這條規則不會生效）。
   固定裁成 4:3、填滿容器，圓角沿用 .work-thumb 的 --radius-md。 */
.work-thumb > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}
.work-thumb {
  width: 100%;
  aspect-ratio: 4 / 3;
  /* 沒用共用的 --placeholder（= --grey-300），因為這個頁面
     section 背景本身就是 --grey-300，兩者同色會讓灰色方塊
     完全融進背景、看不出色塊邊界在哪。這裡改用更深一階的
     --grey-400，確保跟背景有可視對比，hover 再加深到 --grey-500 */
  background: var(--grey-400);
  border-radius: var(--radius-md);
  transition: background-color 0.3s var(--ease-water);
}
/* 業主要求：hover 觸發範圍限縮在照片＋標題，不含標籤區域。
   改用 JS（js/main.js，監聽 .work-thumb / .work-name 各自的
   mouseenter/mouseleave）控制的 .is-hover-active class，取代
   原本 .work-card:hover 的原生偽類寫法——原生 :hover 是整個
   .work-card（含標籤）一起判定，沒辦法排除子區域 */
.work-card.is-hover-active .work-thumb {
  background: var(--grey-500);
}
/* 2026-08-22 改版：業主提供實際截圖參考後，確認需求根本不是「標題
   跟標籤擠同一行、換行後靠右」，而是單純的左右兩欄版面——
   左欄：標題（固定靠左、垂直置中）
   右欄：標籤群組（固定靠右，標籤自己內部 wrap + 靠右對齊）
   兩欄互不干擾，不需要 row-reverse / wrap-reverse 這類容易反向的
   技巧，直接用 flex 兩欄 + 右欄自己是一個獨立的 flex-wrap 容器即可，
   這也是先前 #recognition 徽章區塊已經驗證過可靠的兩欄模式。 */
.work-meta {
  display: flex;
  /* 業主指出：標籤變兩行時，原本的 align-items:center 會讓標題
     對齊「整個容器高度」的中心，導致標題被往下拉、跟第一行標籤
     不對齊（單行標籤時視覺正常是巧合，剛好只有一行）。
     改成 flex-start：兩欄都從頂部切齊，讓標題永遠對齊「第一行
     標籤」，不受標籤是否換行影響。垂直置中的微調交給 .work-name
     自己的 margin-top（見下方），因為標題文字行高(27px)比
     .tag-pill 實際高度(24px)高一點點，兩者頂部對齊還不算真正
     視覺置中，需要再往下微調一點點 */
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  /* 照片跟下方標題+標籤組的間距：業主反饋目前間距偏窄，往上
     升一階，從 --space-3(12px) 改成 --space-4(16px) */
  margin-top: var(--space-4);
}
.work-name {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: var(--text-18);
  color: var(--ink);
  /* 業主要求：標題永遠一行顯示，不換行。中文字體是等寬字，
     用 white-space:nowrap 鎖定單行；flex-shrink:0 確保右欄
     的標籤區塊寬度收縮時，標題不會被跟著擠壓換行 */
  white-space: nowrap;
  flex: 0 0 auto;
  /* 讓標題垂直中心對齊「第一行標籤」的垂直中心，不是對齊整個
     .work-tags 容器（容器換兩行後會變高，中心點會跟著往下移，
     這正是業主截圖指出的問題）。實測標題文字行高 27px、
     .tag-pill 實際高度 24px，兩者頂部對齊(flex-start)後，標題
     視覺中心會比 pill 視覺中心高 1.5px，用 margin-top 補回這個
     差距，讓兩者中心精準切齊，且這個值只跟字級/pill尺寸相關，
     不受標籤是否換行影響，永遠準確 */
  margin-top: -1.5px;
}
.work-tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
  /* 跟左側 .project-filter-tags 統一：左右 8px 間距（column-gap 不動）；
     業主 2026-08-22 先要求改成 --space-2(8px)，隨後反悔調回原本的
     --space-3(12px)，維持這個值即可，不用再猜測方向 */
  row-gap: var(--space-3);
  column-gap: var(--space-2);
  flex: 0 1 auto;
  min-width: 0;
  /* 業主要求：一行最多容納「兩個六字標籤」的寬度，超過就換行。
     實測 .tag-pill 在 --text-14 + 左右 padding 12px 的組合下，
     六字標籤實際渲染寬度是 110px（中文字實際字寬略大於 font-size
     本身，用 font-size 直接換算會低估，已用 playwright 量測校正），
     兩個六字標籤 + 中間 column-gap(8px) = 110px×2 + 8px = 228px。
     用這個實測值當 max-width，兩個六字標籤剛好能同一行，第三個
     標籤（或任何會讓寬度超過 228px 的組合）才換行 */
  max-width: 228px;
}

/* .work-tag 的視覺樣式改套用共用元件 .tag-pill（外框、內距、
   字級字重、顏色，跟聯絡我們服務項目、作品分類篩選標籤統一），
   但這裡是純展示用標籤（不可點擊篩選），所以明確關閉 .tag-pill
   內建的 hover 反黑效果，滑鼠移過去維持原樣不變色。
   2026-08-24 補充：點擊標籤也不會觸發卡片跳轉（.work-card 是
   整個 <a> 包住，標籤區域點擊事件在 js/main.js 用
   e.stopPropagation() 攔截，避免冒泡到外層 <a>），完整維持
   「標籤純展示、無任何互動效果」的定位。
   2026-08-24 再補充：游標樣式也要明確覆蓋成 cursor:default。
   根因——.work-tag 雖然自己沒有寫 cursor:pointer，但因為整張
   卡片外層是 <a> 標籤，瀏覽器對「連結內的任何子元素」預設就會
   套用手指游標樣式（這是 <a> 的 user-agent 預設行為，不需要
   額外 CSS 就會這樣），滑鼠移到標籤上一樣會顯示手指游標，讓人
   誤以為標籤可點擊。這裡明確蓋掉這個繼承，才能真正做到「移到
   標籤上完全沒有任何可點擊的視覺暗示」 */
.work-tag.tag-pill {
  cursor: default;
}
.work-tag.tag-pill:hover {
  background: transparent;
  border-color: var(--grey-600);
  color: var(--ink);
}
/* 篩選未命中的作品卡片：隱藏但不影響 grid 排版重新流動 */
.work-card.is-hidden {
  display: none;
}
/* 篩選後沒有任何作品符合時的空狀態提示：預設隱藏（JS 依篩選結果
   切換 .is-visible），顯示時橫跨兩欄置中，跟作品卡片區分開來 */
.project-empty-state {
  display: none;
  grid-column: 1 / -1;
  padding: var(--space-16) 0;
  text-align: center;
  font-size: var(--text-16);
  font-weight: 500;
  color: var(--ink);
  letter-spacing: var(--tracking-xs);
}
.project-empty-state.is-visible {
  display: block;
}

/* ==========================================================================
   作品案例詳細頁（work-detail.html）— 依業主提供的正式排版稿
   （2026-08-22，先依稿子排出大概架構，字級/間距先抓最接近的既有
   token，細節數值待業主看過大概排版後再精修）
   ========================================================================== */

.work-detail-page {
  /* 2026-08-24：整頁最外層底色，從原本沒有設定、繼承 body 的
     --grey-100（太淺），改成跟 about/works/faq 子頁面主要內容區
     一致的 --grey-300。這一層蓋住從 Header 底下開始、到「三組
     左圖右文 sticky」（該區塊有自己的漸層背景會覆蓋這裡）之前的
     全部內容，包含滿版大圖、標題、Type/Client 資訊列等區塊 */
  background: var(--grey-300);
}

/* 1. 滿版大圖/影片區：只有 .work-detail-hero-media 這個滿版容器
   本身，不再疊加標題/資訊列文字（2026-09-10 已移到下方獨立白底
   區塊，見 .work-detail-title-section）也不再有黑色遮罩（業主
   反饋容易被 YouTube 播放器介面干擾，已完全移除，HTML/CSS/JS
   三處都清除乾淨）。標題樣式定義見 .work-detail-title 規則 */
.work-detail-hero-spacer {
  /* 2026-09-10 業主反悔原本的留白需求：影片上方不要再留呼吸
     空間，要直接緊接在 Header 下方。但 .site-header 是
     position:fixed 疊加在內容最上層、且現在是不透明的 --grey-300
     背景（不是透明疊在 Hero 上），如果單純把這個 spacer 的高度
     設成 0，影片最上緣會被固定在畫面最上層的 Header 直接蓋住
     一部分，不是「緊接在下方」而是「被蓋住」。
     Header 實際高度＝padding(--space-4 上下) + 內容行高，這個
     組合值會隨字體實際渲染結果有微幅浮動，寫死一個固定 px 容易
     跟實際情況有 1-2px 落差，改用 JS 動態量測 Header 當下的真實
     高度後設定給這個 spacer（見 js/main.js 的
     syncHeroSpacerToHeaderHeight），精準等於 Header 高度、
     一px 不多留，同時也不會被 Header 蓋住。初始值先給 0，
     避免 JS 尚未執行前這裡完全沒有高度導致畫面閃一下 */
  height: 0;
}
.work-detail-hero-wrap {
  position: relative;
}
.work-detail-hero-media {
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: 640px;
  background: var(--grey-400);
  display: flex;
  align-items: center;
  justify-content: center;
  /* overflow:hidden + position:relative：容器本身維持固定的
     16:9 外框，內部的 <iframe> 用 absolute 撐滿，這樣不管業主
     哪天想改容器比例，iframe 都會自動跟著滿版鋪好，不用個別
     調整 iframe 的 width/height 屬性 */
  position: relative;
  overflow: hidden;
}
/* 2026-09-24：主視覺區塊除了 YouTube/Vimeo 影片（iframe），也要能放圖片。
   根因：原本只有 iframe 有 absolute 滿版規則（.work-detail-hero-video），
   HTML 註解雖寫「圖片一樣沿用 .work-detail-hero-media 直接放 <img>」，但 <img>
   並沒有對應規則——放進 flex 容器會以圖片原始尺寸置中，不會撐滿 16:9 外框，
   尺寸不對就會留灰底或被裁切。現在 iframe／img 共用同一組滿版鋪法，
   img 另加 object-fit:cover，比照下方成果照 .work-detail-photo-gallery-item */
.work-detail-hero-media iframe,
.work-detail-hero-media img,
.work-detail-hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.work-detail-hero-media img {
  display: block;
  object-fit: cover;
  object-position: center;
}


/* 佔位文字：所有灰色佔位區塊共用同一顆說明文字元件，字色刻意用
   跟品牌識別色接近的藍灰色（跟業主原始設計稿裡的藍色標註文字
   呼應），跟其餘正式內文用的黑色 --ink 明確區分，一眼就能看出
   這是「尚待置換的佔位說明」而不是正式顯示文案。這裡的佔位文字
   疊在遮罩「下面」（媒體區塊自己的內容），不受遮罩影響變色，
   遮罩只影響疊在最上層的標題/資訊列文字 */
.work-detail-placeholder-text {
  position: relative;
  font-family: var(--font-en);
  font-size: var(--text-16);
  font-weight: 500;
  color: var(--grey-700);
  text-align: center;
  padding: 0 var(--space-8);
}

/* 標題+資訊列容器：白底，緊接在影片下方、資訊總覽上方。原本是
   position:absolute疊在深色遮罩影片上，現在改成一般文件流排版 */
/* 標題區塊 + 資訊總覽合併容器：統一負責整塊的白底背景，讓兩個
   子區塊視覺上是連續的同一塊白色，不會因為各自獨立的 padding
   間隙而顯得像分離的兩塊背景色 */
.work-detail-info-block {
  background: var(--white);
}
/* 兩個子區塊之間的分隔線：業主指定用細線區隔取代背景色差異，
   粗細先抓 0.75px（比一般瀏覽器最小可渲染的 1px 更細緻，符合
   業主想要的「輕量分隔感」，不是明顯的粗黑線）。用 max-width
   容器置中對齊全站內容寬度，不是貼齊整個螢幕邊緣的通版線，跟
   .work-detail-info-summary 的 .section-inner 是同一個對齊基準 */
.work-detail-info-divider {
  max-width: var(--container-max);
  margin: 0 auto;
  height: 0.75px;
  background: var(--grey-200);
}
.work-detail-title-section {
  padding: var(--space-16) 0 var(--space-8);
}
.work-detail-hero-title-row {
  padding: 0 var(--space-12);
  margin-bottom: var(--space-8);
}
/* 2026-09-11 新增獲獎徽章區塊：置中容器（max-width+margin:auto）
   跟 flex 雙欄排版（標題左、徽章右）現在是同一層。
   ⚠️ 踩坑記錄：原本嘗試把 display:flex 直接加在 .work-detail-hero-title-row
   本身、讓 .work-detail-hero-title-inner 維持它原本的 max-width+
   margin:0 auto，結果標題整個跑到畫面中間而不是貼齊容器左邊界。
   根因：.work-detail-hero-title-inner 一旦變成 flex 的子項目，
   margin:0 auto 的行為從「把整個容器置中在可用寬度裡、內容再貼齊
   容器邊界」變成「這個子項目在 flex 容器分配到的剩餘空間中，
   把自己（縮到內容大小）置中」——同一段 CSS 在父層結構改變後
   語意完全不同（跟 calc() 的 % 是相對父容器同一類陷阱）。
   修正：把置中容器的職責（max-width+margin:auto）留在
   .work-detail-hero-title-inner 上不動，改成用一個新的外層
   .work-detail-hero-title-row-inner 做 flex 雙欄，這個新外層
   本身就在置中容器「裡面」，不會再受置中邏輯干擾 */
.work-detail-hero-title-row-inner {
  max-width: var(--container-max);
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  /* 業主明確要求標題變兩行時，徽章要貼齊標題「第一行」的高度，
     不是跟整列的垂直中點對齊，所以用 flex-start 不能用 center */
  align-items: flex-start;
  gap: var(--space-8);
}
/* [.work-detail-hero-title-inner 目前沒有獨立樣式，2026-09-20 移除空規則外殼，僅保留以下說明] 現在只單純包住標題文字本身，置中容器的職責已移到外層 .work-detail-hero-title-row-inner */
@media (max-width: 767px) {
  /* work-detail.html 獲獎徽章區塊（2026-09-11）：桌機版是「標題左、
     徽章右」同一橫列，手機寬度下改成縱向排列——標題在上一行，
     徽章換到下一行並靠左（不再跟桌機版一樣靠右）。根因：桌機版
     用 justify-content:space-between 把徽章推到最右側，但手機
     版寬度有限，標題文字（尤其中文標題）一旦要跟徽章擠在同一橫列，
     很容易把標題本身也擠到換行、觀感差（例如「專案標題」四個字
     被迫拆成兩行）。改成 flex-direction:column 讓兩者分成上下兩列，
     徽章列改用 justify-content:flex-start 貼齊左邊界，跟標題文字
     的左邊界對齊，維持視覺上的一致起始點 */
  .work-detail-hero-title-row-inner {
    flex-direction: column;
    gap: var(--space-4);
  }
  /* 2026-09-28：原本這裡有 .work-detail-hero-title-row { padding: 0 var(--space-6); }，被更後面的
     1024px 區塊蓋掉、從未生效（真正生效的是本檔更下方 767px 區塊重新宣告的那一條）；已刪除，
     原文與說明逐字保存在《已移除程式碼備查_2026-09-28.md》E2 */
  .work-detail-award-badges {
    justify-content: flex-start;
    max-width: 100%;
  }
}
.work-detail-title {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: 32px;
  color: var(--ink);
}

/* 資訊列：左欄 Type/Client（固定寬度），右欄一整段連續文案
   （彈性寬度，2026-09-11 從三行分段文字改為單一段落），業主稿子
   用細分隔線區隔左右欄。
   2026-09-10：從疊加在深色遮罩上的白字，改成一般文件流排版、
   深色文字（--ink 系列），對齊 Logo 的計算鏈跟原本完全相同——
   外層只負責水平 padding（比照 .site-header 的 48px），內層
   .work-detail-meta-row-inner 才是 max-width+margin:auto 的
   置中容器，這樣左邊界依然精準對齊 Logo，右邊界對齊容器右側 */
.work-detail-meta-row {
  padding: 0 var(--space-12);
}
.work-detail-meta-row-inner {
  max-width: var(--container-max);
  margin: 0 auto;
  display: flex;
  gap: var(--space-16);
}
.work-detail-meta-left {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  /* 2026-08-23：業主要求 Type 區塊跟 Client 區塊之間的間距再上升
     一階，從 --space-3(12px) 改成 --space-4(16px) */
  gap: var(--space-4);
  padding-right: var(--space-16);
  /* 拿掉 Type/Client 跟右側內文之間的垂直分隔線，改用純間距
     （padding-right + 右欄的 gap）區隔兩欄，不用視覺線條 */
}
.work-detail-meta-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
/* 2026-09-10：「類別」這一項（label + tag-pill 的組合）跟其他
   項目（例如「客戶」，label + 純文字 value）的間距分開處理——
   業主反饋「類別」標籤跟底下的圓角標籤感覺貼太近，要單獨調大
   一階，其餘項目維持原本 --space-1(4px) 不變。用 :has() 精準
   鎖定「內部包含 tag-pill」的 meta-item，不會影響到「客戶」那項 */
.work-detail-meta-item:has(.tag-pill) {
  gap: var(--space-2);
}
/* 2026-09-27 根因修正（宗霖回報：手機版「類別」標籤 pill 被撐得
   太開，要 hug content 只包住文字）：.tag-pill 本身雖然是
   display:inline-flex（理論上會 hug content），但這個 pill 是
   .work-detail-meta-item（display:flex; flex-direction:column，
   沒有明確設定 align-items）的子元素——flex 容器沒有指定
   align-items 時預設值是 stretch，會讓交叉軸（這裡是水平方向，
   因為主軸是垂直的 column）的子元素被拉伸撐滿容器寬度，這才是
   pill 被撐開的真正原因，跟 .tag-pill 自己的 display 屬性無關。
   修法：只在這個特定的 pill（.work-detail-type-tag）加上
   align-self:flex-start，讓它跳脫父容器的 stretch 規則，恢復
   依文字內容自身寬度呈現，不影響 .work-detail-meta-item 底下
   其他子元素（label／客戶純文字）原本的 stretch 行為 */
.work-detail-type-tag {
  align-self: flex-start;
}

/* 2026-09-30：類別標籤「一橫列放兩個再換行」（宗霖要求，桌機／平板／手機三種版本一致，所以不寫斷點）。
   根因：標籤原本是 .work-detail-meta-item（直向 flex 欄）的直接子元素，每個標籤各占一列。
   做法：WP 樣板（single-work.php）把標籤包進 .work-detail-type-tags，用兩欄 grid：
   ・欄寬用 minmax(0, max-content)：正好兩個一列，每欄寬度由該欄最長的標籤決定；空間不夠時允許縮小，不橫向溢出。
   ・justify-items: start：沿用 2026-09-27 的決定——標籤只包住文字（hug content），不被欄寬拉伸。
   ・列距與原本直排時相同（--space-2）。單一標籤時只占第一欄，看起來與原本一樣。 */
.work-detail-type-tags {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, max-content));
  justify-items: start;
  gap: var(--space-2);
  align-self: flex-start;
}
/* Type 標籤：這裡只是純展示用途（顯示這個作品的服務類型），不是
   像 works.html／contact.html 那樣可點擊篩選/切換的互動元件，
   套用全站共用的 .tag-pill:hover 變色效果反而會誤導使用者以為
   這是可以點擊的按鈕。用專屬 class 精準覆蓋掉 hover，不動
   .tag-pill:hover 本身（那是全站篩選用標籤共用的互動樣式，不能
   直接拿掉） */
.work-detail-type-tag:hover {
  background: transparent;
  border-color: var(--grey-600);
  color: var(--ink);
}
.work-detail-meta-label {
  font-family: var(--font-cn);
  font-size: var(--text-14);
  color: var(--grey-600);
}
.work-detail-meta-value {
  font-family: var(--font-cn);
  font-size: var(--text-16);
  font-weight: 500;
  color: var(--ink);
}
.work-detail-meta-right {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
}
.work-detail-meta-text {
  font-family: var(--font-cn);
  font-size: var(--text-16);
  color: var(--ink);
  text-align: left;
  letter-spacing: var(--tracking-xs);
  line-height: var(--leading-3);
  /* 2026-09-11：業主要求文案改成一整段連續區塊文字（不再是三句
     各自獨立換行），文字改置左對齊，內容文字框大小限制在跟
     awards.html 卡片同一個公式：calc((100% - var(--space-8)) / 2)
     （見 .award-page-intro 的完整說明，這是全站已經在用的「兩欄
     grid 卡片單欄寬度」反推公式，不是隨意挑的數字）。
     ⚠️ 二次修正：原本直接寫 100% 當基準，但這裡的 100% 指的是
     .work-detail-meta-right 這個 flex 子項目的寬度，而它因為要
     跟左邊 .work-detail-meta-left（Type/Client 欄）平分空間，
     實際寬度只有 974px，不是完整的 1240px 容器寬度——導致同樣的
     公式在這裡跟 awards.html（父容器就是完整 1240px）算出不同的
     絕對寬度（471px vs 604px），業主反饋「同公式應該同寬度」是
     對的，問題出在兩處公式的「100%」基準不一致。改成直接用
     var(--container-max) 當基準，這樣不管當前所在的 flex 佈局
     父容器實際寬度是多少，算出來的絕對寬度永遠跟 awards.html 的
     單欄卡片寬度一致 */
  max-width: calc((var(--container-max) - var(--space-8)) / 2);
  margin-left: auto;
}

/* 3.5. 資訊總覽區塊（2026-09-10 新增，回應 SEO 顧問建議）------
   白底、緊接在 Hero 深色圖片之後，用淺色背景跟上方深色 Hero
   形成清楚的區塊區隔。5 個欄位橫向排列，用 auto-fit + minmax
   讓欄位數量隨容器寬度自動增減，不用手動為不同斷點各寫一次
   grid-template-columns。label/value 的字級/顏色沿用
   .work-detail-meta-item 同一套視覺語言（英文小寫字 label +
   中文正常字 value），只是這裡是淺色背景，顏色改用 --ink 系列
   （原本 Hero 上是白字疊深色遮罩，這裡是黑字疊白底） */
.work-detail-info-summary {
  padding: var(--space-8) var(--space-12);
}
.work-detail-info-grid {
  display: grid;
  grid-template-columns: repeat(5, auto);
  column-gap: var(--space-8);
  row-gap: var(--space-4);
}
.work-detail-info-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.work-detail-info-label {
  font-family: var(--font-cn);
  font-size: var(--text-14);
  letter-spacing: var(--tracking-xs);
  color: var(--grey-600);
}
.work-detail-info-value {
  font-family: var(--font-cn);
  font-size: var(--text-16);
  font-weight: 500;
  color: var(--ink);
  line-height: var(--leading-2);
}
@media (max-width: 767px) {
  .work-detail-info-summary {
    padding: var(--space-6);
  }
  .work-detail-info-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
  }
}

/* 4. 設計主體展示區：業主標註置換單一主視覺物件（png/gif），
   不是滿版照片，容器比照 hero-media 但留更多周邊留白，突顯
   主體本身 */
.work-detail-showcase-block {
  /* 2026-08-24：包住「設計主體照片」+「置中說明文字」的滿版
     背景容器，統一用跟 about/works/faq 子頁面一致的 --grey-300，
     不是 Footer 用的 --grey-200，讓兩個區塊視覺上連成同一片
     灰色，不會有色差斷層 */
  background: var(--grey-300);
}
.work-detail-showcase {
  padding: var(--space-24) var(--space-12);
}
.work-detail-showcase-media {
  width: 100%;
  aspect-ratio: 4 / 3;
  max-width: 800px;
  margin: 0 auto;
  background: var(--grey-400);
  display: flex;
  align-items: center;
  justify-content: center;
}
.work-detail-showcase-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* 5. 置中說明文字：跟資訊列右欄同一組 14pt 內文字級，置中對齊、
   限制最大寬度避免長行閱讀吃力 */
.work-detail-caption {
  max-width: 640px;
  margin: 0 auto;
  padding: 0 var(--space-12) var(--space-24);
  /* 2026-09-27 宗霖要求：三個 RWD 斷點的這段內文都改成置左對齊
     （原本 text-align:center，見上方註解「業主稿子這段文字置中
     對齊」，這次是要推翻那個決策，全斷點一併修改，不分桌機/
     平板/手機）。只改文字對齊方式，不動 max-width/margin:0 auto
     ——這兩個屬性控制的是容器本身在頁面上收窄、置中的版面位置，
     跟文字自己往哪個方向對齊是兩回事，繼續保留可以維持「內文
     閱讀寬度適中、置中呈現在頁面正中央」的版面效果 */
  text-align: left;
}.work-detail-caption p {
  font-family: var(--font-cn);
  font-size: var(--text-16);
  line-height: var(--leading-3);
  color: var(--ink);
  margin-bottom: var(--space-4);
  /* 補上全站內文段落統一套用的 0.1em 字距 */
  letter-spacing: var(--tracking-xs);
}
.work-detail-caption p:last-child {
  margin-bottom: 0;
}

/* 6. 雙欄區塊（左圖右文）× 3 組，sticky scrubbing 效果
   （2026-08-23 改版，取代原本靜態單組版面）。做法完全比照全站
   唯一的 sticky scrubbing 前例——首頁 #recognition 獎項清單動畫
   （見 js/main.js 的 awardsTrack 那組邏輯）：
   - .work-detail-split-track：拉長的軌道，高度 = 3 倍視窗高度
     （一組佔 1 份），提供足夠的捲動距離讓三組內容依序切換
   - .work-detail-split-sticky：原生 position:sticky，捲動時黏在
     螢幕頂部，直到軌道捲完才隨頁面正常捲走
   - .work-detail-split-image-wrap / -content-wrap：兩欄各自的
     「三組疊放」容器，position:relative，讓內部三組
     image/content 可以用 position:absolute 疊在同一個位置
   - .work-detail-split-image / -content：預設 opacity:0 且
     pointer-events:none（不可見、不可互動），加上
     .is-split-active 時 opacity:1（可見），JS 依捲動進度切換
     哪一組帶這個 class，達到「位置不變、只切換內容」的效果 */
.work-detail-split-track {
  position: relative;
  /* 高度由 JS 動態設定（見 main.js updateSplitTrackHeight），
     這裡的 300vh 只是備援值，一組佔 100vh 的邏輯 */
  height: 300vh;
}
.work-detail-split-sticky {
  position: sticky;
  top: 0;
  /* 業主明確要求「先 sticky 在網頁最頂部」，不是像 #recognition
     那樣卡在 Logo 高度下方，這裡直接貼齊 top:0，佔滿一個視窗
     高度，畫面上看起來就是整個左圖右文區塊固定佔滿螢幕 */
  height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
  /* 2026-08-24：底色從純灰改成跟首頁 hero 完全一致的漸層數值
     （方向維持 to bottom，跟 hero 同步，之後如需微調再個別覆蓋） */
  background: linear-gradient(to bottom, var(--grey-300) 0%, var(--grey-200) 75%, var(--grey-100) 90%, var(--white) 100%);
}
.work-detail-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  width: 100%;
  height: 100%;
}
.work-detail-split-image-wrap,
.work-detail-split-content-wrap {
  position: relative;
  height: 100%;
}
.work-detail-split-image {
  position: absolute;
  inset: 0;
  background: var(--grey-400);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s var(--ease-water);
}
.work-detail-split-image.is-split-active {
.work-detail-split-image[src] {
  object-fit: cover;
}
  opacity: 1;
  pointer-events: auto;
}
.work-detail-split-content {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-4);
  padding: var(--space-16) var(--space-16) var(--space-16) var(--space-12);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s var(--ease-water);
}
.work-detail-split-content.is-split-active {
  opacity: 1;
  pointer-events: auto;
}
/* 2026-09-27：.work-detail-split-image／.work-detail-split-content
   這次補上 [data-reveal] 屬性是為了手機/平板版「圖1文1圖2文2圖3
   文3」依序捲動進場時，每一組都能各自觸發淡入動畫（見下方
   @media max-width:1024px 的說明）。但桌機版這兩個元素依賴
   .is-split-active 控制 opacity 切換顯示哪一組（用同一個 sticky
   舞台疊放三組、opacity 切換模擬「換頁」效果），如果讓
   [data-reveal] 全域預設的 opacity:0／transform:translateY(48px)
   也套用在桌機版，會跟 .is-split-active 的顯示邏輯打架——已實測
   確認：套用 .is-split-active 的那組因為選擇器優先權較高不受
   影響，但沒有 .is-split-active 的另外兩組，一旦被 JS 切換成
   .is-split-active 時，若 revealObserver 還沒觸發過 is-visible
   （例如使用者還沒捲動到能觸發淡入的位置），會帶著多餘的
   translateY(48px) 位移一起淡入，讓切換到第 2、3 組時的位置跳掉。
   這裡明確在桌機版覆蓋掉 [data-reveal] 的效果，讓這兩個元素桌機版
   完全維持原本只由 .is-split-active 控制的行為，不受這次新增的
   data-reveal 屬性影響。
   ⚠️ 2026-09-27 追加修正：這條隔離規則一開始沒有限定斷點，結果
   `.is-split-active[data-reveal] { opacity:1 }` 這條規則在手機版
   也生效，選擇器優先權（3層：class+is-split-active+屬性）比手機版
   想要的 [data-reveal].is-visible（2層）更高，導致預設帶
   is-split-active 的第一組（圖1文1）在手機版一開始就是 opacity:1，
   使用者根本還沒捲到那裡就已經完全不透明，完全沒有播放淡入動畫，
   等於图1文1两组的動畫「消失」了——這正是宗霖說「有些不明顯」的
   真正根因之一，比動畫時長不一致更根本。加上 min-width:1025px
   限定，只在桌機/平板以外（也就是真正還在用 is-split-active
   切換機制的桌機寬度）生效，手機版完全交給下面 max-width:1024px
   的覆蓋規則處理 */
@media (min-width: 1025px) {
  .work-detail-split-image[data-reveal],
  .work-detail-split-content[data-reveal] {
    opacity: 0;
    transform: none;
    transition: opacity 0.6s var(--ease-water);
  }
  .work-detail-split-image.is-split-active[data-reveal],
  .work-detail-split-content.is-split-active[data-reveal] {
    opacity: 1;
  }
}
.work-detail-split-title {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: clamp(26px, 3vw, 38px);
  color: var(--ink);
  margin-bottom: var(--space-4);
  /* 2026-08-23：業主要求字距上升一級。全站字距系統目前是
     --tracking-0(0) → --tracking-xs(0.1em) → --tracking-tight(0.2em)，
     這裡原本沒設定 letter-spacing，等同 --tracking-0，往上一級
     即為 --tracking-xs（--tracking-wide 0.4em 已於 2026-08-24
     移除，全站未使用） */
  letter-spacing: var(--tracking-xs);
}
.work-detail-split-content p {
  font-family: var(--font-cn);
  font-size: var(--text-16);
  line-height: var(--leading-3);
  color: var(--ink);
  letter-spacing: var(--tracking-xs);
}

/* 7. 成果照片組（2026-08-22 改版）：業主明確要求規劃成「WP 後台
   可自由新增數量」的獨立媒體單位，不是單張寫死的滿版圖片。目前
   先放 1 張佔位，但用「清單」結構（.work-detail-photo-gallery 包
   多個 .work-detail-photo-gallery-item）取代原本單一 div 的寫法，
   即使現在只有 1 張，樣板結構上就已經是「可重複項目」，日後
   ACF Repeater/Gallery 動態輸出時，直接照這個結構重複印出多個
   .work-detail-photo-gallery-item 即可自動排列，不需要更動 CSS。
   每張照片各自滿版、上下不留間距（業主稿子裡這類成果照通常希望
   一張接一張連續呈現，不是網格式排列），比例先抓 3:4（人像/直式
   案場照片常見比例），實際會依業主上傳的照片自然比例調整，這裡
   只是佔位階段的預設值。
   2026-09-27 根因修正（宗霖回報：成果照片要維持在 4:3 或 3:4，
   依直式橫式而定）：原本用 max-height:900px 限制高度上限，理由
   是避免超寬螢幕（例如 1440px 甚至更寬）下，寬度撐滿容器、依
   3:4 比例算出的高度會誇張到超過 1900px，視覺上太突兀。但這個
   限制的代價是犧牲了比例本身——寬度持續變寬時，高度被鎖死在
   900px 不再跟著等比放大，aspect-ratio 因此完全失真：實測平板
   900px 寬時比例變成 1:1（正方形），桌機 1440px 寬時變成 1.6:1
   （橫向長方形），兩者都不是 3:4 也不是 4:3，這正是宗霖說「沒有
   維持比例」的根因。
   修法：拿掉 max-height，改用 max-width 限制寬度上限（避免超寬
   螢幕下圖片本身過度放大、失去該有的視覺尺度感），這樣不管容器
   多寬，aspect-ratio 都能在寬度不超過上限的前提下正確維持
   3:4 這個比例 */
/* 2026-09-28 根因修正（宗霖回報：所有 RWD 版本的成果照片要撐滿
   網頁容器的最大寬度，不是撐滿整個瀏覽器）：
   原本 max-width:675px 是刻意設計的縮小效果（跟頁面另外兩處類似
   設計——.work-detail-showcase-media 的 800px、.work-detail-caption
   的 640px 是同一種風格），經宗霖確認這次只改成果照片這一處，
   其他兩處維持不動。
   把 max-width 從 675px 放寬成全站容器最大寬度 var(--container-max)
   (1240px)，這樣照片會盡量撐到跟其他用 .section-inner 的區塊同一個
   容器邊界，而不是自己另外設一個更小的上限。同時外層
   .work-detail-photo-gallery 補上左右 padding（見下方新增規則），
   確保真正撐到 1240px 上限時，容器本身不會貼齊瀏覽器邊緣——這條
   padding 只在容器寬度超過「1240px + 兩倍 padding」時才會讓照片
   兩側露出間距，容器變窄時（平板/手機寬度）padding 會讓照片跟其他
   內容區塊的左右邊界對齊一致 */
/* 2026-09-28 根因修正（宗霖回報：所有RWD版本成果照片還是要有
   下距，不要直接接著更多作品區塊）：原本完全沒有上下padding，
   只有左右，.work-detail-photo-gallery-item 因此直接貼齊容器
   底部、緊接著 .more-work-section，中間沒有任何間距——這是全
   斷點共通的問題（含桌機版），補在基礎規則讓所有寬度都繼承到，
   不需要在每個斷點各自補一次 */
.work-detail-photo-gallery {
  /* 2026-09-28 宗霖要求：所有RWD版成果照片補上上內距，數值跟下內距
     相同。原本只有 padding-bottom，這裡改成「上下相同、左右另計」
     的單一簡寫，之後各斷點只要同步改這一行，不會再出現上下不對稱 */
  padding: var(--space-24) var(--space-12);
}
.work-detail-photo-gallery-item {
  width: 100%;
  aspect-ratio: 3 / 4;
  max-width: var(--container-max);
  margin: 0 auto;
  background: var(--grey-400);
  display: flex;
  align-items: center;
  justify-content: center;
  /* 跟 .work-detail-hero-media 同一套「容器固定比例外框、內部
     媒體用 absolute 滿版鋪好」的做法，這樣不管這個項目放的是
     <img> 還是 <iframe>（YouTube/Vimeo embed），都能直接套用
     同一顆 class 撐滿容器，不需要為圖片/影片兩種情境分別寫版面
     邏輯 */
  position: relative;
  overflow: hidden;
}
/* 2026-09-27 宗霖要求：成果照片依照片本身方向維持 4:3（橫式）或
   3:4（直式），不是固定同一個比例。預設（不加 class）維持 3:4
   直式；WP 後台該筆照片若是橫式，額外加上 is-landscape 這個
   class，切換成 4:3。max-width 維持跟直式版一樣的上限（容器寬度
   本身的限制邏輯不變，只有比例翻轉），橫式照片因此會比直式版矮，
   視覺上符合橫式照片天生比較扁的直覺。
   2026-09-28 澄清（宗霖回報「所有 RWD 版本成果照片都要改成橫式
   4:3，現在直式是錯的」）：確認後這不是要拆掉這套依方向切換的
   機制——宗霖要的正是這套機制本身（業主上傳直式或橫式照片時，
   都能依那張實際照片切換），不是要全站寫死同一個比例。問題只在
   於 work-detail.html 裡唯一那張示範照片剛好沒加 is-landscape，
   套用了預設的 3:4 直式，這才是宗霖看到「直式」的原因。已在
   work-detail.html 幫這張示範照片加上 is-landscape，機制本身
   （這條規則、下面的 .is-landscape 規則）維持不動，未來 WP 後台
   新增照片時，依那張照片實際方向決定要不要加這個 class 即可 */
.work-detail-photo-gallery-item.is-landscape {
  aspect-ratio: 4 / 3;
}
.work-detail-photo-gallery-item img,
.work-detail-photo-gallery-item iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  object-fit: cover;
}
.work-detail-photo-gallery-item + .work-detail-photo-gallery-item {
  margin-top: var(--space-1);
}

/* ---- 作品內頁：WordPress 版才有的圖片（業主在後台上傳；靜態原型只有灰色佔位方塊，這些規則不會生效）----
   設計主體照片＝單一 png／gif 主視覺，用 contain 完整顯示（透明背景的 png 不被裁切）；
   左圖右文的圖片跟成果照片一樣用 cover 填滿容器（容器比例由上方 .is-landscape／直式規則決定）。
   獎項徽章圖片放在徽章容器內，撐滿 40×40 並保留圓角。 */
.work-detail-showcase-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.work-detail-split-image img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.work-detail-award-badge img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: inherit;
}

/* ---- 更多作品推薦（MORE WORK）----
   放在單一作品案例頁面最下方，業主提供設計稿參考：頂部一條細
   分隔線、斜體英文大標題、三張橫向並排的作品卡片（圖片＋雙語
   標題，不含標籤）。沿用 .work-thumb 的既有灰階佔位邏輯（見
   works.html 對應樣式），確保跟作品列表頁的視覺語言一致 */
.more-work-section {
  /* 2026-09-10：改成白底，跟上一個區塊（深灰的左圖右文 split
     區塊）拉開對比，避免原本沿用 body 的淺灰底（--grey-100）
     跟前面深灰、跟作品縮圖佔位框的灰色都疊在一起、層次感偏弱。
     白底也呼應全站其他子頁面常用的「灰轉白」轉場語言，並讓
     Footer 深色收尾的對比更清楚 */
  background: var(--white);
  /* 2026-09-08 根因修正：先前把 max-width 跟左右 padding 疊加在
     同一個元素上，這跟全站標準模式（.section 有 padding、內部的
     .section-inner 只有 max-width+margin:auto，兩者分開兩層）
     相反，導致視覺寬度計算跟其他頁面對不齊。改成拆成兩層：這裡
     只負責外層 padding（安全間距）跟分隔線，真正的 1240px 內容
     寬度限制交給下面新增的 .more-work-inner */
  padding: var(--space-16) var(--space-12) var(--space-32);
  border-top: 1px solid var(--grey-500);
}
.more-work-inner {
  max-width: var(--container-max);
  margin: 0 auto;
}
.more-work-heading {
  /* 2026-09-08：業主要求標題改成中文「更多作品」，原本套用在英文
     斜體上的樣式（font-style:italic + --font-en）不適合中文字體，
     改用全站標題慣用的中文襯線字體。顏色也改成深灰 --ink，比照
     業主提供的作品列表頁截圖配色 */
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: clamp(24px, 2.6vw, 32px);
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
  margin-bottom: var(--space-12);
}
/* 2026-09-08：卡片改成直接沿用 works.html 的 .work-card（見該
   元件既有樣式規則，包含標題+標籤兩欄佈局、hover 效果），這裡
   只需要提供獨立的三欄容器 .more-work-grid，不重寫卡片本身樣式。
   跟 .project-grid（作品列表頁用的兩欄）是不同的容器，欄數不同 */
.more-work-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-16) var(--space-8);
}

@media (max-width: 767px) {
  /* 手機：三欄橫向排不下，改成單欄直向堆疊 */
  .more-work-grid {
    grid-template-columns: 1fr;
    gap: var(--space-6);
  }
}

/* 2026-09-27 根因修正（宗霖回報四項問題，全部同一根因）：
   ①「平配圖/概念介紹圖」要恢復原本高度，圖1配文1、圖2配文2依序
      往下排列，不要用桌機版 sticky 切換方式；
   ②最後一段文字（文3）底色要跟文1文2一致，不要漸層；
   ③每張圖文都要有 appear animation，translateY/秒數統一比照
      「更多作品」區塊；
   （以上都明說「照手機版邏輯執行即可」）
   實測宗霖裝置是 iPad Pro 13（CSS 寬度 1032px）。下方
   @media (max-width: 1024px) 區塊已經把這整組「單欄依序排列＋
   統一底色＋逐項 appear animation」的手機版邏輯做好了，但 1032px
   卡在這條斷點外側，吃到的是桌機版的 position:sticky＋雙欄切換
   邏輯，這正是宗霖看到「桌機版 sticky 效果」而非「手機版順順
   scroll」的根因——跟前面表單／匯流線／nav 導覽列那幾次同一類
   「斷點邊界卡在 1024px 外側」的問題。
   修法比照前面幾次：新增一段獨立的 min-width:1025px 到
   max-width:1099px 局部規則，把下方 1024px 區塊裡跟
   .work-detail-split-* 相關的完整規則原樣複製過來（padding 調整
   等跟這次需求無關的規則不重複搬移），不去更動全站共用的 1024px
   斷點分界本身。規則內容逐字複製自下方 1024px 區塊，理由與根因
   說明見該處對應規則的註解 */
@media (min-width: 1025px) and (max-width: 1099px) {
  /* 2026-09-28 根因修正（宗霖回報：搭配文左側沒有切齊「類別/客戶
     資訊列」的左邊界）：排查後發現這批 work-detail-* 容器的
     padding，先前只同步了 .work-detail-split-track／
     .work-detail-photo-gallery 兩個（見下方），其餘容器
     （.work-detail-meta-row／.work-detail-showcase／
     .work-detail-hero-title-row／.more-work-section／
     .work-detail-caption）都還停留在桌機版的 --space-12(48px)，
     沒有同步縮小到跟 1024px 主區塊一致的 --space-8(32px)，導致
     1032px 這個寬度下，.work-detail-meta-row 是 48px、
     .work-detail-split-track 是 32px，兩者左邊界對不齊。這裡
     一次性把全部同批容器補齊，規則內容逐字複製自下方 1024px
     區塊對應規則 */
  .work-detail-meta-row { padding: 0 var(--space-8); }
  .work-detail-showcase { padding: var(--space-16) var(--space-8); }
  .work-detail-hero-title-row { padding: 0 var(--space-8); }
  .more-work-section { padding-left: var(--space-8); padding-right: var(--space-8); }
  .work-detail-caption { padding: 0 var(--space-8) var(--space-16); }
  /* 2026-09-28 根因修正（宗霖回報：搭配文最大寬度要比照
     award.html 的 .award-page-intro 公式）：那個公式是
     calc((100% - gap) / 2)，但那裡的 100% 是相對於 .section-inner
     （已經被 1240px 上限收窄過的容器），這裡的
     .work-detail-split-content 沒有被 .section-inner 包裹，父層
     是滿版的 .work-detail-split-track，如果直接抄同一個公式，
     100% 會抓到整個視窗寬度而不是 1240px 容器寬度，算出來的值會
     偏大、失去公式原本「跟容器寬度掛鉤」的意義。
     改用 min(var(--container-max), 100%) 明確重建「容器寬度」這個
     基準（限制在 1240px 上限內，或視窗更窄時取視窗寬度本身），
     再套用跟 award-page-intro 完全一致的減半公式：
     (容器寬度 - gap) / 2，gap 用同一個 --space-8 token */
  .work-detail-split-content {
    /* 2026-09-28 根因修正（宗霖回報：平板版搭配文最大寬度要跟獲獎小卡
       一樣，現在明顯比小卡少）：max-width 公式算出來的容器寬度本來就
       等於獲獎小卡寬度（例如 1032px 都是 468px），但這裡多留了
       padding-right:32px，border-box 下把文字實際寬度吃掉 32px
       （436px vs 468px）。平板版右側 padding 歸零，文字寬度就會跟
       小卡完全相同；左側本來就是 0（對齊容器左邊界），上下維持 32px。
       手機版由 767px 區塊自己的 padding 覆蓋，不受這裡影響 */
    padding: var(--space-8) 0;
    max-width: calc((min(var(--container-max), 100%) - var(--space-8)) / 2);
  }
  /* 2026-09-28 根因修正（宗霖回報：所有RWD版本成果照片要撐滿容器
     最大寬度）：.work-detail-photo-gallery 桌機版是48px，1024px
     以下已縮小到32px（見下方1024px區塊），這裡補齊同一階，避免
     1024px(32px)→1032px(桌機48px)→1100px(桌機48px)這種先縮小又
     放大的不連續斷點 */
  .work-detail-photo-gallery {
    /* 上下內距相同（宗霖要求上內距跟下內距一致），左右 32px */
    padding: var(--space-16) var(--space-8);
  }
  .work-detail-split-sticky {
    position: static;
    height: auto;
    overflow: visible;
    background: var(--grey-300);
  }
  /* 2026-09-28 根因修正（宗霖回報：平板版平配圖/概念介紹圖跟文
     沒有遵從網頁容器最大寬度，直接撐滿沒有 padding）：
     .work-detail-split-track 桌機版是刻意滿版設計（sticky 舞台的
     漸層背景要鋪滿整個螢幕營造沉浸感，不能動），但手機/平板版已
     經改成單欄依序排列的一般內容區塊，不再需要滿版沉浸效果，理應
     跟頁面其他內容區塊（.work-detail-meta-row／.work-detail-showcase
     等）一樣有左右安全邊界。實測發現這裡完全沒有幫 track 本身補上
     padding——.work-detail-split-content 雖然自己有 padding，但
     .work-detail-split-image（圖片容器）完全沒有任何限制，直接
     撐滿 track 的滿版寬度，貼齊瀏覽器左右邊緣。
     修法：track 本身補上跟其他區塊同一階（--space-8）的左右
     padding，圖片容器跟著收進這個邊界內，不用再對圖片單獨處理 */
  .work-detail-split-track {
    height: auto;
    padding: 0 var(--space-8);
  }
  .work-detail-split {
    grid-template-columns: 1fr;
  }
  .work-detail-split-image-wrap,
  .work-detail-split-content-wrap {
    display: contents;
  }
  .work-detail-split-image,
  .work-detail-split-content {
    position: static;
    opacity: 1;
    pointer-events: auto;
    height: auto;
  }
  .work-detail-split-image[data-reveal],
  .work-detail-split-content[data-reveal] {
    opacity: 0;
    transform: translateY(48px);
    transition: opacity 1s var(--ease-water),
                transform 1s var(--ease-spring);
  }
  .work-detail-split-image[data-reveal].is-visible,
  .work-detail-split-content[data-reveal].is-visible {
    opacity: 1;
    transform: none;
  }
  /* 2026-09-28 根因修正（宗霖回報：平配圖/概念介紹圖的比例跑掉了，
     要維持4:3或3:4）：原本用固定 min-height:320px 撐開高度，寬度
     隨容器變寬時（例如平板 1032px 時寬度撐到 968px）高度沒有跟著
     等比放大，比例因此完全失真（實測 1032px 時算出來是 968:320
     ≈ 3.025，不是 4:3 也不是 3:4）。
     修法比照成果照片（.work-detail-photo-gallery-item）同一套
     機制：改用 aspect-ratio 讓寬高比在容器變寬時自動維持一致，
     預設 3:4（直式），額外加上 is-landscape 這個 class 切換成
     4:3（橫式）——業主上傳直式或橫式照片時，都能依那張實際照片
     切換，不寫死同一個比例。示範資料已在 work-detail.html 幫三張
     平配圖依內容性質補上 is-landscape，機制本身跟成果照片完全
     一致，方便日後對照維護 */
  .work-detail-split-image {
    aspect-ratio: 3 / 4;
  }
  .work-detail-split-image.is-landscape {
    aspect-ratio: 4 / 3;
  }
  .work-detail-split-image[data-split-index="0"] { order: 0; }
  .work-detail-split-content[data-split-index="0"] { order: 1; }
  .work-detail-split-image[data-split-index="1"] { order: 2; }
  .work-detail-split-content[data-split-index="1"] { order: 3; }
  .work-detail-split-image[data-split-index="2"] { order: 4; }
  .work-detail-split-content[data-split-index="2"] { order: 5; }
}

@media (max-width: 1024px) {
  /* 2026-09-27 根因修正（宗霖回報：個別作品介紹子頁面很多地方的
     內容區塊沒有撐滿螢幕容器）：跟下方 767px 斷點同一個根因（見
     767px 區塊內的完整說明），平板寬度先縮小到 --space-8(32px)，
     跟全站 --section-side-padding 在這個斷點的標準一致，手機版
     再進一步縮到 24px，兩層漸進，不要從桌機的 48px 直接跳到
     手機的 24px */
  .work-detail-meta-row { padding: 0 var(--space-8); }
  .work-detail-showcase { padding: var(--space-16) var(--space-8); }
  /* 2026-09-28 根因修正（宗霖回報：所有RWD版本成果照片要撐滿容器
     最大寬度，且平板版平配圖/文要遵從容器最大寬度）：
     .work-detail-photo-gallery 桌機版是 padding:0 var(--space-12)
     (48px)，這裡跟其他區塊（.work-detail-meta-row／
     .work-detail-showcase）一致，漸進縮小到 --space-8(32px)，
     767px 手機版再進一步縮到 --space-6(24px)，避免從桌機的 48px
     直接跳到手機的 24px */
  .work-detail-photo-gallery {
    /* 上下內距相同（宗霖要求上內距跟下內距一致），左右 32px */
    padding: var(--space-16) var(--space-8);
  }
  /* 2026-09-27 追加：.work-detail-hero-title-row（專案標題／獲獎
     徽章的外層容器）同一個斷點也還沒縮小過，跟這裡其他區塊補齊
     成同一個 --space-8，避免手機版縮到 24px 但平板寬度停在桌機的
     48px、中間空了一個斷點沒縮小 */
  .work-detail-hero-title-row { padding: 0 var(--space-8); }
  /* 2026-09-27 追加：「更多作品」區塊（.more-work-section）跟前面
     幾處是同一個根因——左右內距固定用 --space-12(48px)，從未有
     平板/手機斷點覆蓋，這裡補齊成同一個 --space-8 */
  .more-work-section { padding-left: var(--space-8); padding-right: var(--space-8); }
  /* 2026-09-27 根因修正（宗霖回報：個別作品介紹子頁面很多地方
     內容區塊沒有撐滿容器）：.work-detail-caption 左右內距固定用
     --space-12(48px)，從未有平板/手機斷點覆蓋——但同一頁其他
     內容區塊（.work-detail-meta-row、.work-detail-showcase）在
     這個斷點已經縮小成 --space-8(32px)，只有這裡沒跟著縮，加上
     稍早已經把文字改成置左對齊（原本置中時，過大的 padding 不會
     太明顯，改成置左後，文字左邊界比其他區塊多縮進 16px 的落差
     就非常清楚可見）。這裡跟其他區塊一致，漸進縮到 --space-8 */
  .work-detail-caption { padding: 0 var(--space-8) var(--space-16); }
  /* .work-detail-split-content 桌機版 padding 是給「圖左文右」
     並排版面設計的呼吸間距（左 48px、其餘 64px），手機/平板版
     已經改成上下堆疊排列（見下方 max-width:1024px 區塊），沿用
     桌機版寬鬆的 padding 會讓文字內容比其他區塊明顯內縮一大截，
     這裡先在平板斷點縮小一階，手機斷點（767px）再縮一階。
     2026-09-28 根因修正（宗霖回報：搭配文左側沒有切齊網頁容器
     左側）：桌機版這裡是四邊都有 padding 的卡片式元件設計（背景
     色需要四邊留白），但手機/平板單欄模式下背景已經是透明、直接
     融入頁面（不是卡片），此時如果還留著 padding-left，文字左側
     會比 .work-detail-split-track 本身的 padding 邊界又多縮進
     一層，導致跟 .work-detail-meta-row-inner 等其他容器的左邊界
     對不齊。改成只保留上/右/下三邊 padding，左側歸零，讓文字左
     邊界直接對齊 track 的 padding 邊界（跟其他容器一致），右側
     維持舒適的換行留白 */
  .work-detail-split-content {
    /* 2026-09-28 根因修正（宗霖回報：平板版搭配文最大寬度要跟獲獎小卡
       一樣，現在明顯比小卡少）：max-width 公式算出來的容器寬度本來就
       等於獲獎小卡寬度（例如 1032px 都是 468px），但這裡多留了
       padding-right:32px，border-box 下把文字實際寬度吃掉 32px
       （436px vs 468px）。平板版右側 padding 歸零，文字寬度就會跟
       小卡完全相同；左側本來就是 0（對齊容器左邊界），上下維持 32px。
       手機版由 767px 區塊自己的 padding 覆蓋，不受這裡影響 */
    padding: var(--space-8) 0;
    max-width: calc((min(var(--container-max), 100%) - var(--space-8)) / 2);
  }
  /* 2026-09-27 根因修正（宗霖回報兩項問題：①手機版平配圖1-3被
     壓扁，要恢復原本高度；②圖1只配文1、圖2/圖3跟文2/文3整個消失，
     要改成圖1接文1、圖2接文2、圖3接文3依序往下排列，不要用桌機版
     的 sticky 切換方式）：
     這裡原本的手機/平板降級方案本身就有兩個問題疊在一起：
     ① .work-detail-split-image 改回 position:static 後，原本
        「position:absolute; inset:0 撐滿父層高度」的機制不再
        生效，圖片容器（裡面目前是文字佔位，之後會換成 <img>）
        完全沒有其他屬性能撐開高度，只依內容文字的自然行高塌陷成
        24px，這才是「被壓扁」的根因——min-height:320px 當時只
        寫在 .work-detail-split-image-wrap（外層容器）身上，不是
        寫在真正需要撐高度的 .work-detail-split-image（裡面 3 個
        疊放 item）身上，等於撐錯了層級。
     ② 用 `.work-detail-split-image + .work-detail-split-image
        { display:none }` 這種相鄰兄弟選擇器，把「第一個以外的
        圖片／文字」全部隱藏，只留第一組——這是配合桌機版「同一
        時間只顯示一組、用 opacity 切換」的邏輯設計的降級方案，
        但宗霖這次明確要手機版三組都要能看到、依序往下捲動閱讀，
        不是只留第一組。
     解法：拿掉 display:none 那條規則，讓 3 張圖／3 段文字都顯示；
     每個 .work-detail-split-image 各自給 min-height:320px（撐開
     高度，不再依賴父層或 inset:0）；用 CSS Grid 的 order 屬性
     搭配 HTML 既有的 data-split-index 屬性（0/1/2），把視覺順序
     從「圖1圖2圖3｜文1文2文3」（原本 wrap 分組的 DOM 順序）重新
     排列成「圖1、文1、圖2、文2、圖3、文3」交錯順序，不需要更動
     HTML 結構本身——.work-detail-split-image-wrap／
     .work-detail-split-content-wrap 這兩層 wrap 改成
     display:contents（讓 wrap 自己在排版上「消失」，裡面的 6 個
     item 直接變成 .work-detail-split 這個 grid 容器的直接子元素，
     才能用 order 互相穿插排序，否則 order 只能在同一層兄弟之間
     生效，跨越 wrap 邊界排不動）。
     sticky pin 住的效果依然在窄螢幕上退化成一般捲動（不 pin），
     這個既有取捨維持不變 */
  .work-detail-split-sticky {
    position: static;
    height: auto;
    overflow: visible;
    /* 2026-09-27 根因修正（宗霖回報：平配圖最後一段文字（文3）
       底色明顯偏白，跟文1、文2的底色不一致，要求全部統一，不要
       漸層）：.work-detail-split-sticky 桌機版背景是
       linear-gradient(灰→白)，設計初衷是給「固定 100vh 高度的
       sticky 舞台」用的漸層氛圍效果。手機版拿掉 sticky 機制、
       改成 height:auto 正常文件流後，這個漸層背景依然套用在整個
       .work-detail-split-sticky 容器上，只是現在的容器高度變成
       全部 6 組內容疊加後的實際高度（2221px），漸層會沿著這整段
       高度延展——文字區塊本身背景透明，會透出後面 sticky 容器對應
       位置的漸層顏色，文1文2剛好落在漸層前段（接近純灰），文3
       落在漸層後段（接近白色），才會看起來「文3特別淡」，其實
       整條漸層本身沒有跳動或錯誤，只是手機版的用法已經脫離了
       這個漸層原本設計的情境。
       修法：手機版改用純色 var(--grey-300)（漸層的起始色，也是
       品牌灰，文1文2目前視覺上最接近的顏色），不再用漸層，全部
       6 組內容底色統一 */
    background: var(--grey-300);
  }
  /* 2026-09-28 根因修正（宗霖回報：平板版平配圖/概念介紹圖跟文
     沒有遵從網頁容器最大寬度，直接撐滿沒有padding；經確認手機版
     跟原本768~1024px平板同樣有這個問題，一併統一修正）：
     track 補上跟 .work-detail-meta-row 同一階（--space-8=32px）
     的左右 padding，圖片容器（.work-detail-split-image）跟著收進
     這個邊界內，不再直接撐滿貼齊瀏覽器邊緣 */
  .work-detail-split-track {
    height: auto;
    padding: 0 var(--space-8);
  }
  .work-detail-split {
    grid-template-columns: 1fr;
  }
  .work-detail-split-image-wrap,
  .work-detail-split-content-wrap {
    display: contents;
  }
  .work-detail-split-image,
  .work-detail-split-content {
    position: static;
    opacity: 1;
    pointer-events: auto;
    height: auto;
  }
  /* 2026-09-27 根因修正（宗霖回報：平配圖 appear animation 不是
     每個都有做到）：手機/平板版這 6 個項目（3圖+3文）已經改成
     依序正常排列展示（不再是桌機版疊放切換），但先前只有最外層
     .work-detail-split 掛了一個 [data-reveal]，桌機版設計時這樣
     沒問題（整個 sticky 舞台第一次進入畫面時淡入一次即可），改成
     手機版正常 scroll 之後，捲動到下面才看得到的圖2文2圖3文3
     因為跟外層容器共用同一個一次性動畫（進入畫面後
     revealObserver.unobserve，不會重複觸發），從來沒有機會播放
     自己的淡入效果，才會是宗霖說的「不是每個都有做到」。
     這裡在每個 .work-detail-split-image／.work-detail-split-content
     身上都補了 [data-reveal]（HTML 端已加上屬性），手機/平板這裡
     的通用規則把它們強制設成 opacity:1（因為要六組同時可見，不是
     切換式），會蓋掉 [data-reveal] 想要的初始 opacity:0——這裡
     額外用屬性選擇器精準覆蓋回 data-reveal 該有的淡入效果，讓每
     一組捲動進入視窗時各自觸發一次 */
  /* 2026-09-27 根因修正第二輪（宗霖回報：跟「更多作品」.work-card
     比對後，這頁動畫還是沒有統一）：上一輪只加了
     transition-duration:1s，以為這樣就跟全站一致，但用
     getComputedStyle 完整比對 transition-property 這個維度後才
     發現真正的問題——.work-detail-split-image／
     .work-detail-split-content 的基礎規則寫的是
     `transition: opacity 0.6s ...`，只針對 opacity 這一個屬性
     設定 transition，transform 完全沒有被納入，所以 transform 的
     變化是瞬間跳變、沒有動畫過渡的；.work-card（跟全域 [data-reveal]
     的預設寫法）則是 `transition: opacity 1s ease-water,
     transform 1s ease-spring`，opacity 跟 transform 各自有自己
     的 transition、各自用不同的緩動函數（opacity 用平順的
     ease-water，transform 用有彈性回彈感的 ease-spring）。上一輪
     只加 transition-duration:1s，只會延長「已經存在的 opacity
     transition」的時間，不會讓 transform 憑空多出一個 transition
     ——這才是宗霖說「還是沒有統一」的真正原因，比對 duration 數字
     一致是不夠的，property 跟 timing-function 也要完全一致。
     修法：直接用完整的 transition 簡寫，逐字比照 .work-card／
     全域 [data-reveal] 的寫法，不再依賴繼承基礎規則再疊加覆蓋 */
  .work-detail-split-image[data-reveal],
  .work-detail-split-content[data-reveal] {
    opacity: 0;
    transform: translateY(48px);
    transition: opacity 1s var(--ease-water),
                transform 1s var(--ease-spring);
  }
  .work-detail-split-image[data-reveal].is-visible,
  .work-detail-split-content[data-reveal].is-visible {
    opacity: 1;
    transform: none;
  }
  /* 2026-09-28 根因修正：跟上面1024px區塊同一根因，手機版一併
     採用同一套aspect-ratio+is-landscape機制，避免手機版比例
     也跟著跑掉 */
  .work-detail-split-image {
    aspect-ratio: 3 / 4;
  }
  .work-detail-split-image.is-landscape {
    aspect-ratio: 4 / 3;
  }
  .work-detail-split-image[data-split-index="0"] { order: 0; }
  .work-detail-split-content[data-split-index="0"] { order: 1; }
  .work-detail-split-image[data-split-index="1"] { order: 2; }
  .work-detail-split-content[data-split-index="1"] { order: 3; }
  .work-detail-split-image[data-split-index="2"] { order: 4; }
  .work-detail-split-content[data-split-index="2"] { order: 5; }
}

@media (max-width: 767px) {
  /* 2026-09-27 根因修正（宗霖回報：個別作品介紹子頁面很多地方的
     內容區塊沒有撐滿螢幕容器）：盤點全頁區塊後找到兩處是「內層
     容器被外層固定 48px（--space-12）padding 擠壓」造成的偏窄，
     不是本身寬度算錯：
     ① .work-detail-meta-row（Type/客戶/內文那個資訊列的外層
        padding 容器）與 ② .work-detail-showcase（設計主體照片
        區塊的外層 padding 容器）——這兩個都是「桌機版夠寬，48px
        留白比例上合理」的固定值，從未有手機版縮小覆蓋，跟全站
        其他區塊（例如 .work-detail-title-section 系列、
        .work-detail-info-summary）手機版早已縮小到 24px
        （--space-6）的標準不同步，才會讓這兩處看起來比其他區塊
        窄一截。統一縮小成跟全站一致的 --space-6，兩層容器內部的
        內容（.work-detail-meta-row-inner／.work-detail-showcase-media）
        會自動撐滿到新的可用寬度，不需要額外調整內層 */
  .work-detail-meta-row { padding: 0 var(--space-6); }
  /* 2026-09-28 根因修正：跟上面1024px區塊同一根因，手機版再縮小
     到全站標準的 --space-6(24px) */
  .work-detail-photo-gallery {
    /* 上下內距相同（宗霖要求上內距跟下內距一致），左右 24px */
    padding: var(--space-12) var(--space-6);
  }
  .work-detail-split-track { padding: 0 var(--space-6); }
  /* 2026-09-27 根因修正（宗霖回報：設計主體照片上下間距明顯比
     左右大，要求以左右為基準統一）：原本 padding 是
     var(--space-16) var(--space-6)（上下 64px、左右 24px），
     這個「上下比左右寬」的比例是從桌機版基礎規則就有的既有設計
     （桌機版是 96px/48px），手機版縮小內距時只等比例縮小了左右，
     上下沒有跟著調整成同一個數值，才會是宗霖看到的「上下比左右
     大很多」。宗霖明確要求以左右（--space-6=24px）為準，所以
     這裡改成上下左右統一都是 --space-6，不再區分方向 */
  .work-detail-showcase { padding: var(--space-6); }
  /* 2026-09-27 根因修正（宗霖回報：個別作品介紹子頁面很多地方
     內容區塊沒有撐滿容器，截圖裡的「專案標題」跟「設計主體照片」
     只是舉例，逐一盤點後這兩處也是同一類問題）：跟上面
     .work-detail-meta-row／.work-detail-showcase 是同一種模式
     ——.work-detail-caption 跟 .work-detail-split-content 的左右
     內距同樣從未縮小到跟全站一致的 --space-6，這裡補齊 */
  .work-detail-caption { padding: 0 var(--space-6) var(--space-12); }
  /* 2026-09-28 根因修正（宗霖回報：手機版搭配文最大寬度要調整成
     跟網頁容器一樣，且左側要切齊容器左側不是切齊瀏覽器）：
     跟上面 1024px／1025~1099px 平板斷點同一根因——桌機版四邊
     padding 沿用到手機版，左側 padding 讓文字比 track 本身的
     padding 邊界又多縮一層，跟其他容器對不齊。手機版是單欄、沒有
     跟其他欄位並排，不需要像平板版套用減半公式，max-width:100%
     明確表示「文字寬度就是容器寬度本身」（不額外收窄），左側
     padding 歸零讓文字左邊界對齊 track 的 padding 邊界 */
  .work-detail-split-content {
    padding: var(--space-6) var(--space-6) var(--space-6) 0;
    max-width: 100%;
  }
  /* 2026-09-27 根因修正（宗霖回報：專案標題跟徽章沒有切齊容器
     左側，目測還是偏右）：實測發現 .work-detail-hero-title-row
     在手機版（390px）算出來的 padding 是 32px，不是預期的 24px
     ——根因不是數值寫錯，是 CSS 書寫順序問題：這條規則原本只
     寫在 .work-detail-title-section 專屬的 767px 區塊裡（見上方
     更早的位置），但同一個屬性在 1024px 區塊（寫在檔案更後面，
     見上方 .work-detail-meta-row 那組 1024px 統一補丁）也設定了
     --space-8(32px)。因為 390px 螢幕同時符合「max-width:1024px」
     跟「max-width:767px」兩個條件，選擇器優先權相同時，CSS 採用
     「書寫順序在後者勝出」，1024px 的規則寫在檔案更後面，直接把
     767px 想要的 24px 蓋掉。
     修法：不去搬動或刪除原本 767px 專屬區塊裡的規則（避免牽動
     旁邊 .work-detail-award-badges 那段），而是在這個本來就排在
     1024px 統一補丁「之後」的 767px 區塊裡，重新宣告一次同樣的
     24px，靠 CSSOM 順序（這裡確實排在最後）確保它才是真正生效
     的最終值。
     （2026-09-28：那條較早、被蓋掉的 767px 規則已證實從未生效而刪除，原文見
     《已移除程式碼備查_2026-09-28.md》E2；這一條是唯一生效的宣告） */
  .work-detail-hero-title-row { padding: 0 var(--space-6); }
  /* 2026-09-27 追加：「更多作品」區塊同一個根因，一併補齊 */
  .more-work-section { padding-left: var(--space-6); padding-right: var(--space-6); }
  /* 2026-09-11 根因修正：flex-direction:column 原本加在
     .work-detail-meta-row 身上，但這個元素本身只是外層 padding
     容器，不是 flex 容器——真正需要改變排列方向的是內層的
     .work-detail-meta-row-inner（見上方該規則的 display:flex 
     定義）。這是既有的既存 bug（原本可能因為視覺上剛好還過得去
     沒被發現），這次在修正 .work-detail-meta-text 的 max-width
     公式時才真正暴露出來：.work-detail-meta-right 因為沒有正確
     被推到下一行、還維持在桌機版的並排配置下，寬度被 flex 母版
     擠壓到只剩 77px，文字幾乎不可讀。改成加在正確的
     .work-detail-meta-row-inner 上，Type/Client 跟文案才會真正
     上下堆疊，.work-detail-meta-right 才能撐滿手機版的可用寬度 */
  .work-detail-meta-row-inner { flex-direction: column; gap: var(--space-6); }
  .work-detail-meta-left {
    padding-right: 0;
    padding-bottom: var(--space-4);
  }
  .work-detail-meta-right { text-align: left; }
  .work-detail-meta-text {
    /* 桌機版的 max-width:calc((100%-32px)/2) 是配合左右兩欄並排
       （Type/Client 在左、文案在右）反推出的「半欄寬度」，手機版
       改成上下堆疊後 .work-detail-meta-right 撐滿整個容器寬度，
       如果沿用桌機版的「半欄」公式，會把文字不合理地限縮成只剩
       容器一半寬。手機版重置成撐滿可用寬度，不受桌機版兩欄配置
       的公式限制 */
    max-width: 100%;
    margin-left: 0;
  }
}

@media (max-width: 767px) {
  .page-header { padding-top: var(--space-24); }
  .project-filter-tags { gap: var(--space-1); }
  .project-grid { grid-template-columns: 1fr; }
  /* 2026-09-26 根因修正（宗霖回報：作品案例／室內設計／品牌設計／
     整合型設計四個頁面，手機版明顯沒做 RWD）：.project-layout 本身
     從頭到尾只有 display:flex（橫向排列），.project-sidebar 是寫死
     的 flex:0 0 260px，兩者都沒有任何斷點覆蓋——上面這行
     .project-grid 單欄化雖然有做，但外層排版容器沒有跟著從「左右並排」
     改成「上下堆疊」，260px 寬的側欄依然佔走版面，右側留給作品網格的
     可用寬度在 390px 螢幕上被壓縮到只剩不到 100px，作品卡片、標籤
     因此被擠到看不見、部分內容直接超出螢幕右側。
     修法：手機版把 .project-layout 改成上下堆疊（側欄在上、作品網格
     在下），.project-sidebar 拿掉桌機版的固定寬度與 sticky 卡住效果
     （手機螢幕本來就矮，側欄卡住捲動反而佔用寶貴垂直空間），改成
     依內容自然佔滿寬度 */
  .project-layout { flex-direction: column; align-items: stretch; gap: var(--space-8); }
  /* 2026-09-26 根因修正（宗霖回報：作品小卡寬度沒有撐滿容器，
     小小一個）：`.project-layout` 桌機版基礎規則是
     `align-items: flex-start`（左右並排時，側欄跟網格各自依內容
     高度對齊頂端用的），改成手機版上下堆疊（column）後，這個屬性
     的意義從「垂直對齊方式」變成「水平撐滿方式」——flex-start 讓
     每個子項目依自己內容需要的寬度「hug content」，不再預設撐滿
     整個容器寬度。`.project-sidebar` 剛好有自己明確寫 width:100%
     才沒受影響，但 `.project-grid` 沒有設寬度，所以跟著縮成內容
     本身需要的寬度（約 228px），底下的 `.work-card` 也跟著窄。
     手機版把 align-items 改成 stretch，讓網格（跟未來任何新加的
     子項目）預設撐滿容器寬度，不用每個都個別補 width:100% */
  .project-sidebar { flex: 1 1 auto; width: 100%; position: static; top: auto; }
  /* 手機版寬度較窄，標題+標籤兩欄硬擠容易太擠，改成上下堆疊：
     標題一行，標籤群組另起一行、靠左對齊（跟左側篩選欄一致的
     閱讀方向，避免窄螢幕上标签靠右显得突兀） */
  .work-meta { flex-direction: column; }
  .work-tags { justify-content: flex-start; width: 100%; max-width: none; }
  /* 2026-09-26 根因修正（宗霖回報：作品小卡標籤沒有撐滿整行才換行，
     現在到第三個標籤就強制換行）：上面 width:100% 沒有蓋到基礎規則
     的 max-width:228px——那個 228px 是特地為桌機版兩欄卡片窄版面
     算出來的「剛好兩個六字標籤」上限，手機版卡片已經改成撐滿容器寬度
     （見同一天的作品小卡撐滿修正），但這個 228px 上限沒有跟著鬆綁，
     標籤還是被鎖死在跟桌機版一樣窄的寬度內換行，等於「卡片變寬了，
     標籤還是照舊擠成一小條」。這裡明確蓋掉成 max-width:none，讓標籤
     真正利用卡片的完整寬度，撐滿一整行才換行 */
  /* 2026-09-26 根因修正（宗霖要求：作品小卡標籤的間距縮到跟室內設計
     子頁面的分類標籤（.project-filter-tags，住宅空間/辦公空間/商業
     空間/公共空間）一樣，讓四個標籤能擠在同一行，現在三個就換行）：
     .work-tags 沿用的是桌機版基礎值 row-gap:12px／column-gap:8px，
     從未有手機版覆蓋；.project-filter-tags 在這個斷點已經縮成
     gap:4px（見上面 5536 行），兩者間距天生不一致，才會出現同樣是
     四個字左右的中文標籤，篩選標籤能一行擠下四個、作品小卡標籤卻
     三個就換行。這裡比照套用同樣的 gap:var(--space-1)(4px) */
  .work-tags { gap: var(--space-1); }
}


/* ==========================================================================
   Cookie / 隱私權同意橫幅（2026-08-24 新增）
   ------------------------------------------------------------------------
   根因：privacy-policy.html 文字已經承諾「會使用 Cookie 與網站分析
   工具（GA4、Meta Pixel 等）」，但全站目前完全沒有實際的同意橫幅，
   文字承諾了但功能沒兌現。純前端可以先做出橫幅本身跟「記住使用者
   選擇」的邏輯（用 localStorage，不需要後端/伺服器）；「使用者選了
   拒絕後，真的擋掉 GA4/Meta Pixel 載入」這件事，要等業主提供正式的
   追蹤碼 ID、GTM 實際安裝後才能真正生效——目前這些追蹤碼本體都還
   沒安裝，所以現階段這個橫幅先做「UI + 記住選擇」，等追蹤碼安裝時
   要記得讓安裝邏輯讀取這裡存的同意狀態，才決定要不要真的載入。

   使用 localStorage（不是 sessionStorage）：Cookie 同意是「長期
   決定」，使用者關閉分頁/重開瀏覽器不應該又跳出來問一次，這跟
   .project-filter 用 sessionStorage 記錄篩選狀態的情境不同（那個是
   短暫的瀏覽行為，理當每次重新進站就重置）。
   ========================================================================== */
.cookie-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 600; /* 高於 nav-trigger(400)/nav-overlay(399)，確保橫幅
                   在選單之上，避免使用者被選單擋住看不到橫幅 */
  background: var(--grey-900);
  color: var(--white);
  padding: var(--space-6) var(--space-12);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);
  flex-wrap: wrap;
  box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.15);
  transform: translateY(100%);
  transition: transform 0.5s var(--ease-water);
}
.cookie-banner.is-visible {
  transform: translateY(0);
}
.cookie-banner-text {
  font-size: var(--text-14);
  line-height: var(--leading-2);
  max-width: 640px;
}
.cookie-banner-text a {
  text-decoration: underline;
  text-underline-offset: 2px;
}
.cookie-banner-actions {
  display: flex;
  gap: var(--space-3);
  flex-shrink: 0;
}
.cookie-banner-btn {
  font-family: var(--font-cn);
  font-size: var(--text-14);
  font-weight: 500;
  padding: var(--space-3) var(--space-6);
  border-radius: var(--radius-full);
  white-space: nowrap;
  transition: opacity 0.3s var(--ease-water);
}
.cookie-banner-btn:hover {
  opacity: var(--state-hover-opacity);
}
.cookie-banner-btn--accept {
  background: var(--white);
  color: var(--ink);
}
.cookie-banner-btn--decline {
  background: transparent;
  color: var(--white);
  border: 1px solid var(--grey-500);
}

@media (max-width: 767px) {
  .cookie-banner {
    flex-direction: column;
    align-items: stretch;
    text-align: center;
    padding: var(--space-6) var(--space-6);
  }
  .cookie-banner-actions {
    justify-content: center;
  }
}


/* 2026-09-28 根因修正（宗霖回報：平板版 nav bar 的公司 Logo／LINE
   預約諮詢按鈕感覺沒有貼齊網頁容器左右側）：
   實測宗霖提到的寬度範圍落在 iPad Pro 13（CSS 寬度 1032px）附近。
   --section-side-padding 這個全站共用變數（控制 .site-header、
   .nav-trigger 水滴選單位置、以及全站所有 .section 區塊的左右
   安全邊界）只在 max-width:1024px 才會從桌機版的 48px（--space-12）
   覆蓋成平板版的 32px（--space-8），1032px 剛好卡在這條斷點外側，
   整個變數退回桌機版的 48px——這正是這批問題反覆出現的同一種
   「斷點邊界卡在 1024px 外側」模式，只是這次影響的是全站共用的
   核心變數，而不是單一容器。
   實測驗證：Logo／LINE按鈕本身跟 .section-inner 的左右邊界其實
   一直都精準對齊（同一個變數驅動，機制沒有壞），只是這個平板
   寬度整體套用的 padding 數值本身不是平板該有的標準（48px 而不是
   32px），感覺上因此偏窄、不像其他平板寬度那樣舒展。
   修法：新增這段 min-width:1025px 到 max-width:1099px 局部規則，
   把 --section-side-padding 這個變數本身覆蓋回 32px，--container-max
   相關的響應式邏輯全部透過這個變數連動修正，不需要再對
   .site-header／.nav-trigger／各個 .section 個別補規則——這是
   比逐一修正個別容器更根本的修法，經宗霖確認採用 */
@media (min-width: 1025px) and (max-width: 1099px) {
  :root { --section-side-padding: var(--space-8); }
  .section { padding: var(--space-24) var(--section-side-padding); }
  .site-header { padding-left: var(--section-side-padding); padding-right: var(--section-side-padding); }
  .nav-trigger { right: var(--section-side-padding); }
}

@media (max-width: 1024px) {
  :root { --section-side-padding: var(--space-8); }
  .section { padding: var(--space-24) var(--section-side-padding); }
  /* 2026-09-11：.about-top-row 已經從 display:flex 改成
     position:relative（配合中英標排列邏輯修正，見該規則的完整
     說明），這裡的 flex-direction:column 已經沒有作用對象、
     變成死碼，一併移除。.about-label 改成跟子頁面 .page-label
     完全一致的窄螢幕橫式排列邏輯（見下一行），不需要額外調整
     容器排版方式。
     2026-09-25 宗霖要求：英標在平板/手機也要維持直排，跟桌機一致。
     根因：這裡原本主動把 .about-label／.page-label／.contact-label
     覆蓋成橫排（writing-mode: horizontal-tb），跟桌機版的直排（vertical-rl，
     見各自的基礎規則）不一致。三個都是純文字標籤（"( ABOUT )" 這類），
     直排本身不會造成版面溢出或內容被裁切的問題，拿掉這 3 行覆蓋，
     讓它們直接繼承桌機版的直排基礎規則即可，不需要另外寫排版邏輯 */
  .about-showcase { width: min(75%, 480px); margin: var(--space-8) auto; }
  .about-bottom-block { max-width: 100%; }
  /* 2026-09-26 宗霖回報 Logo／漢堡沒有切齊容器：根因是 .site-header
     左右內距一直沿用桌機版 --space-12(48px)，但 .section 在這個斷點
     已經改成 --space-8(32px)（見上方），兩者不同步，導致 Logo／漢堡
     跟其他區塊內容（.section-inner）的左右邊界對不齊。改成同步套用
     --section-side-padding（跟 .section 用同一個變數），任何斷點
     只要 .section 的側邊留白改變，Header 會自動跟著同步，不用兩處
     各自維護一份數字 */
  .site-header { padding-left: var(--section-side-padding); padding-right: var(--section-side-padding); }
  .nav-trigger { right: var(--section-side-padding); }
}

@media (max-width: 767px) {
  :root { --section-side-padding: var(--space-6); }
  .section { padding: var(--space-16) var(--section-side-padding); }
  .section--white { border-radius: 32px 32px 0 0; margin-top: -32px; }
  /* 同上一個斷點的根因：Header 左右內距同步改用 --section-side-padding，
     這個斷點的值已在 .section 那行改成 --space-6(24px)，這裡不用
     再重複寫一次數字，直接沿用變數即可自動同步 */
  .site-header { padding-left: var(--section-side-padding); padding-right: var(--section-side-padding); }
  /* margin 改由上面 #about .about-showcase 的手機版覆蓋負責（見該處
     根因說明），這裡只留 width，避免兩處各自宣告 margin、其中一份
     其實從未生效、卻誤導未來維護者以為這裡在管控間距 */
  .about-showcase { width: 100%; }
  /* 2026-09-25 宗霖回報：「「美」件事都能「泉」力以赴」在手機版被裁切在螢幕外。
     根因：.about-headline 基礎規則有 white-space:nowrap（桌機版單行夠寬，
     沒有問題），但在 390px 寬度下，就算縮到 26px，整句文字的 scrollWidth
     實測仍有 372px，超過容器可用寬度 342px；因為全站已經改成 overflow-x:hidden
     防呆（見另一輪修改），這段溢出的文字不會出現橫向捲軸，而是直接被裁切、
     完全看不到——比原本「可以捲動看到」更嚴重。
     實測只有 ≤767 這個斷點會溢出（768px／1024px 皆不會），所以只在這裡修正，
     不動桌機／平板版的 nowrap 設定。宗霖表示可以接受標題換行，改成 normal
     讓它自動換行，不需要手動斷句（比照下面內文段落的處理方式，不用猜斷點） */
  /* 2026-09-27 根因修正（宗霖回報：「美」件事都能「泉」力以赴
     要縮小到能一行顯示，現在是兩行；且要跟「設計實力推動產業與
     城市發展」同步字級）：
     用 Playwright 逐步測試不同字級下的實際渲染行數，26px／24px
     都還是兩行，22px 是第一個能維持一行的字級，且 scrollWidth
     剛好等於 clientWidth（貼合可用寬度、沒有溢出風險）。
     .stat-block h2（設計實力推動產業與城市發展）手機版原本完全
     沒有字級覆蓋，一直沿用桌機版固定的 32px，跟這裡的 26px 本來
     就不一致——這次一併改成同樣的 22px，兩者統一 */
  .about-headline { font-size: 22px; white-space: normal; }
  .stat-block h2 { font-size: 22px; }
  /* 2026-09-27 根因修正（宗霖回報：關於我們子頁面的「設計實力
     推動產業與城市發展」字級沒改到）：上一輪只改了首頁用的
     .stat-block h2，沒注意到 about.html 這段標題其實是「不共用
     class」的獨立複製版（見 about.html 的原始註解），用的是
     .about-recognition-block h2，跟首頁的 .stat-block h2 是完全
     不同的選擇器，各自維護一份桌機版 32px，手機版都沒有縮小過。
     這裡補上跟首頁同樣的 22px，兩個子頁面/首頁的這段標題字級才
     會真正統一 */
  .about-recognition-block h2 { font-size: 22px; }
  .fan-menu a { font-size: 12px; }
  .stat-block-inner { flex-direction: column; align-items: stretch; }
  .recognition-showcase { width: 100%; height: 240px !important; margin-bottom: var(--space-6); }
  .stat-block { text-align: left; margin-left: 0; max-width: 100%; }
  .stat-block-sticky { position: static; top: auto; width: 100% !important; } /* 手機版關閉，避免小螢幕上互相遮擋；width強制100%蓋掉JS設定的固定px，避免爆版 */
  .stat-block-spacer { display: none; }
  /* 2026-09-25：手機版取消 (AWARDS RECOGNITION) 捲動慢慢展開。
     JS 端會在 ≤767 一律加上 .is-motion-reduced（見 main.js 對應說明），
     讓卡片跟黑線強制用最終展開樣式呈現；這裡另外把「長捲動軌道＋sticky
     卡住」也一併取消，兩者合起來才是完整的「不用捲」體感——只讓內容變成
     展開樣子、但軌道還是很長且還會卡住的話，使用者還是得多捲一段空白
     距離才會放開，跟目標不符。
     .awards-scroll-track 的 height 原本是 JS 逐格量測後用行內樣式設定
     （見 updateTrackHeight()，動辄數千 px），這裡用 !important 蓋掉，
     沿用同一份檔案裡 .is-motion-reduced 已經用過的相同手法（見上方
     「用 !important 覆蓋掉 JS 原本逐格插值設定的 inline 值」說明） */
  .awards-scroll-track { height: auto !important; }
  .awards-scroll-sticky { position: static; top: auto; height: auto; padding-top: var(--space-8); }
  /* 2026-09-25 宗霖要求：手機版直接不要「( AWARD RECOGNITION )」這行字，
     卡片內容已經是完全展開的樣子（見上面 .is-motion-reduced），拿掉這行
     提示文字跟黑線之後，整個區塊看起來就是一張普通卡片，不需要額外的
     切換提示。JS 端量測 .awards-toggle／.awards-line 算 .awards-panel
     的 marginTop 那段（見 measurePanelHeight()）在元素 display:none 時
     getBoundingClientRect() 全部歸零，算出來的 marginTop 會是 0，不會
     產生非預期的留白，不需要額外處理 JS */
  .awards-toggle { display: none; }
  /* 2026-09-26 根因修正（宗霖要求：獎項小卡左右置中於螢幕，目前卻貼齊
     左側）：`.awards-scroll-inner` 的 `padding: 0 var(--space-12) 0 0`
     是桌機版專用的不對稱內距（只有右側 48px，左側 0），從來沒有手機版
     覆蓋。這個內距吃掉的是卡片可以用來置中的可用寬度——手機版容器本身
     只有 342px 寬，扣掉這 48px 右內距只剩 294px 可用空間，卡片
     （307px）比這個可用空間還寬，margin:auto 沒有多餘空間可以分配，
     直接失效變成貼齊左側（甚至右側還會被推出 13px 去疊到內距裡）。
     手機版拿掉這個內距（歸零），讓卡片可以用完整的 342px 寬度置中 */
  .awards-scroll-inner { padding: 0; }
  .awards-panel-inner { flex-direction: column; padding: var(--space-6); }
  .awards-year { flex-direction: row; width: 100%; }
  .awards-year-text { writing-mode: horizontal-tb; transform: none; }
  /* 2026-09-26 根因修正（宗霖回報：獎項小卡「美國 TITAN PROPERTY
     AWARDS」這類較長的英文獎項名稱，在手機版卡片超出螢幕、右側標籤
     文字被裁掉）：卡片寬度是 JS 依「最長那一行的獎項名稱＋間距＋
     標籤，同一行不換行」的自然寬度反推出來的（業主要求獎項名稱完整
     顯示、不截斷、不換行——見 .award-name 2026-09-19 的說明，這點
     沒有改）。這個邏輯在桌機版沒問題，但手機版視窗本身就窄，塞不下
     「名稱＋標籤同一行」需要的寬度，卡片只好被撐超過螢幕寬度。
     修法：手機版把每一行改成「名稱在上、標籤在下」兩行堆疊，不再
     同一行左右並排，這樣單行只需要容納名稱或標籤其中較寬的一個，
     不用兩者相加，卡片寬度就能收進手機螢幕內。JS 那邊算卡片寬度用的
     naturalContentWidth（measurePanelHeight() 裡），手機版同步改成
     取「名稱、標籤兩者中較寬的一個」，不再相加，兩邊要對應著看 */
  .award-row { flex-direction: column; align-items: flex-start; row-gap: var(--space-1); }
  .award-tag { margin-left: 0; }
  /* 2026-09-27 根因修正（宗霖回報：首頁獲獎小卡的內文字級，要調
     成跟上方「設計實力推動產業與城市發展」內文（.stat-block-lines，
     16px）相同）：.award-name／.award-tag 全站固定 14px，從未有
     手機版覆蓋，這裡統一改成 16px。卡片本身寬度在手機版是直接讀
     容器寬度（不會因為字級變大而跟著放大，見 js/main.js 的
     isMobileCardWidth 分支），字級調整後需要重新確認長內容（例如
     「金點設計空間設計商業空間類」這類較長的獎項名稱）會不會超出
     卡片寬度，已用 Playwright 實測確認正常換行、沒有溢出裁切 */
  .award-name, .award-tag { font-size: var(--text-16); }
  /* 2026-09-25 修正：這裡原本沒有覆蓋掉基礎規則的 min-height:var(--space-8)
     （32px，桌機版直式排列時用來確保線條至少有 32px 長）。.awards-year
     在手機版改成橫式排列（flex-direction:row）後，min-height 會變成
     這個橫向排列裡的「最小高度」限制，跟這裡設定的 height:1px 互相衝突
     ——min-height 優先生效，實際渲染出一個 24px（寬，flex:0 0 24px）
     ×32px（高，被 min-height 撐開）的實心色塊，而不是一條細線。
     這裡明確歸零 min-height，讓 height:1px 才是真正生效的高度 */
  /* 2026-09-26 宗霖要求：「重點獲獎」後面的橫線撐滿整張卡片寬度。
     根因：這裡原本是 flex:0 0 24px（固定 24px 短橫線），.awards-year
     本身也只有 width:auto（跟文字一樣寬，不是滿版）。改成 .awards-year
     width:100%（見上面同一天的修正）讓這一整列撐滿卡片內容寬度，
     這裡的橫線改成 flex:1 1 auto，在文字後面把剩餘空間全部撐滿 */
  .awards-year::after { width: auto; height: 1px; min-height: 0; flex: 1 1 auto; margin: 0 0 0 var(--space-2); }
  .marquee-logo { width: 100px; height: 64px; }

  /* ---- 手機版：LINE 預約諮詢＋社群水滴，收進右上角一顆漢堡選單 ----
     2026-09-25 宗霖要求。DOM 搬動邏輯見 js/main.js（把 .line-cta-button
     搬進 .fan-menu--social 當第一項）；這裡負責視覺：把水滴本身重新
     定位到 Header 右上角、外觀從「水滴＋社群文字」換成標準三線漢堡圖示，
     展開時維持原有的 .fan-menu--social 垂直清單機制（開合/模糊遮罩/
     逐一判斷是否疊在 Footer 深色底，全部沿用既有邏輯，不重寫）。
     只在這裡（≤767）覆蓋，不影響桌機／平板版原本「水滴常駐畫面右側
     垂直置中」的樣子——那是既有、業主已經確認過的獨立功能，維持不變 */
  .nav-trigger {
    /* 對齊 Header 自己的內距：上下 --space-4(16px)、左右跟 Logo 用
       同一個 --section-side-padding（2026-09-26 修正，原本這裡寫死
       --space-12，跟同一輪稍早改成 --section-side-padding 的
       .site-header／右側那條 .nav-trigger 規則衝突，因為這條規則
       在檔案更下面、疊加順序會蓋掉前面設定的值，等於白改。統一
       用同一個變數，才能真正保證 Logo／漢堡／其他區塊內容三者的
       左右邊界同步） */
    top: var(--space-4);
    right: var(--section-side-padding);
    transform: none;
    /* ⚠️ 根因修正：搬到 Header 的視覺範圍內之後，實測點擊完全點不到漢堡圖示——
       .nav-trigger 原本 z-index:400，.site-header 是 500，桌機／平板版兩者
       從不重疊（水滴在螢幕垂直置中，離 Header 很遠）所以疊放順序沒差；
       這裡把水滴搬進 Header 同一塊區域後，z-index 較低的 .nav-trigger
       整個被 z-index 較高的 .site-header 蓋住、攔截掉點擊事件。
       這裡明確給比 500 更高的值，確保漢堡在 Header 之上可以正常點擊 */
    z-index: 501;
    /* 2026-09-26 宗霖回報：手機版往下捲動時 Header（Logo）會收起來，
       但漢堡選單按鈕沒有跟著收合。根因：.nav-trigger 是獨立的
       position:fixed 元素，完全在 .site-header 的 DOM／定位範圍
       之外（桌機版刻意如此設計，讓水滴選單常駐畫面右側、不受
       Header 顯隱影響），JS 的捲動顯隱邏輯（updateHeaderVisibility）
       只切換 .site-header 自己的 class，從未涉及 .nav-trigger，
       這在桌機版是預期行為，但手機版已經把漢堡「視覺上」搬進
       Header 同一列，使用者會預期兩者是同一個整體、要一起收合。
       修法：讓 .nav-trigger 也能響應同一個 .is-hidden 狀態，
       套用跟 Header 一致的 transform／transition（見下方
       .site-header.is-hidden ~ .nav-trigger 規則），JS 端不需要
       新增任何邏輯，兩者共用同一個 class 切換時機 */
    transition: transform 0.4s var(--ease-water);
  }
  /* 手機版選單「打開中」的狀態不受此規則影響：is-open 時使用者
     正在操作選單，不應該因為捲動被連帶收起，下面用 :not 排除 */
  .site-header.is-hidden ~ .nav-trigger:not(.is-open) {
    transform: translateY(-72px);
  }
  .droplet-icon {
    /* 三線漢堡的整體尺寸，寬高比不用跟原本水滴圖檔一致，改成常見的
       24×16 線寬排列。原本靠負 margin 讓 21.43px 寬的圖檔在 16px 容器
       內置中的算法，換成三線漢堡後不再適用，改成單純 margin:0（容器
       寬度不影響漢堡本身置中，因為漢堡是絕對定位在自己 24px 寬的框內） */
    width: 24px;
    height: 16px;
    margin: 0;
    /* 選單圖示不需要呼吸浮動感，取消原本套用給水滴的 idle 動畫 */
    animation: none;
  }
  .droplet-icon .droplet-shape {
    /* 原本是背景圖水滴，這裡改成純色的「中線」：拿掉背景圖，
       改成 2px 高的實色橫線，垂直置中在 16px 高的容器內
       （(16-2)/2=7px），左右撐滿容器寬度 */
    background: var(--ink);
    inset: auto;
    top: 7px;
    left: 0;
    width: 100%;
    height: 2px;
    transition: opacity 0.3s var(--ease-water), background-color 0.3s var(--ease-water);
  }
  .droplet-icon::before,
  .droplet-icon::after {
    /* 上線／下線，用偽元素補上，跟中線（.droplet-shape）湊成三線 */
    content: '';
    position: absolute;
    left: 0;
    width: 100%;
    height: 2px;
    background: var(--ink);
    transition: transform 0.3s var(--ease-water), background-color 0.3s var(--ease-water);
  }
  .droplet-icon::before { top: 0; }
  .droplet-icon::after { top: 14px; } /* 容器高 16px - 線高 2px = 14px */
  /* 疊在 Footer 深色底上時，沿用既有的 .is-over-dark 機制切換成白色
     （原本是給水滴 filter 用，這裡三線漢堡直接換 background-color 更直接） */
  .nav-trigger.is-over-dark .droplet-icon .droplet-shape,
  .nav-trigger.is-over-dark .droplet-icon::before,
  .nav-trigger.is-over-dark .droplet-icon::after {
    background: var(--white);
  }
  /* hover／點選時，桌機版原本的 scale+filter 效果是設計給水滴圖檔用的，
     三線漢堡不需要這些，明確歸零避免殘留（filter 對純色線條而言只是
     徒增一層不必要的運算，且視覺上不需要） */
  .nav-trigger:hover .droplet-icon,
  .nav-trigger.is-open .droplet-icon {
    transform: none;
  }
  .nav-trigger:hover .droplet-icon .droplet-shape,
  .nav-trigger.is-open .droplet-icon .droplet-shape {
    filter: none;
  }
  /* 展開狀態：三線收成 X，是漢堡選單常見的開合回饋，讓使用者清楚
     知道現在是「可以再點一次關閉」的展開狀態 */
  .nav-trigger.is-open .droplet-icon .droplet-shape { opacity: 0; }
  .nav-trigger.is-open .droplet-icon::before { transform: translateY(7px) rotate(45deg); }
  .nav-trigger.is-open .droplet-icon::after { transform: translateY(-7px) rotate(-45deg); }
  /* 「社群」文字提示改用 visibility:hidden 而不是 display:none：
     漢堡圖示不需要顯示這段文字，但 js/main.js 的
     alignSocialIconsToHintGap() 需要用它的 getBoundingClientRect()
     算出社群清單第一項該落在哪個位置，display:none 會讓量到的座標
     全部歸零、算式跟著跑掉；visibility:hidden 保留版面佔位與座標，
     只是視覺上不畫出來，兩全其美 */
  .droplet-hint { visibility: hidden; }

  /* 2026-09-26 宗霖要求：手機版選單背景改成素色，不要模糊遮罩
     （比較不干擾）。桌機版水滴選單的模糊遮罩效果不變，只在手機
     斷點覆蓋成不透明的純色底、拿掉 backdrop-filter */
  .nav-overlay {
    background: var(--grey-200);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  /* ---- 手機選單面板改版（2026-09-25 第二輪）----
     宗霖回報：漢堡選單裡子頁面連結不見了，另外 LINE 按鈕跟社群連結
     排版很怪。根因是上一輪只把 4 個小圖示塞進面板，用的是桌機版
     水滴原本那套「絕對定位＋nth-child 固定位移」機制，設計上只夠
     放 4～5 個等高的小圖示；這次面板改放站內導覽連結（含「作品案例」
     3 個子分類）＋LINE 按鈕＋4 個社群圖示，內容量遠超過這套機制能
     負荷，直接整個換掉：面板本身變成一張有背景色、隨內容自然撐高的
     卡片，內部項目一律用正常文件流（flex column）排列，不再用
     nth-child 固定位移／絕對定位堆疊，開合動畫改成「整個面板」一起
     淡入淡出＋位移，不是逐項展開 */
  .fan-menu--social {
    /* 2026-09-26 宗霖要求：不要用白色卡片包住選單，改成直接疊在
       水滴選單本來就有的全螢幕模糊遮罩（.nav-overlay，z-index:399）
       上面，連結／按鈕直接放在模糊背景上，不要额外的卡片容器感。
       做法：拿掉背景色、圓角、陰影；因為沒有卡片邊界可以「框住」
       視覺寬度，改用跟 Header 兩側一致的留白（--space-12，跟
       .site-header 的左右 padding 同一個數值），寬度不再用
       max-width 侷限成一張小卡片，改成 left/right 對稱留白、自然
       撐滿螢幕寬度 */
    position: fixed;
    top: 64px;
    /* 2026-09-26：改用 --section-side-padding，跟 Header／其他區塊
       內容邊界同步（見 .site-header 同一輪修正的說明），不再各自
       硬寫 --space-12 */
    right: var(--section-side-padding);
    left: var(--section-side-padding);
    bottom: auto;
    width: auto;
    height: auto;
    max-height: calc(100vh - 96px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: var(--space-6) 0 var(--space-4);
    /* 用 grid 而不是 flex column：站內導覽連結／LINE 按鈕各自撐滿整排
       （grid-column:1/-1），最後 4 個社群圖示不特別指定 column-span，
       會自動接續排進剩餘欄位，四個剛好排成一整排並排——不需要額外的
       DOM 包裝容器就能達成「上面清單直排、圖示橫向並排」的版面 */
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    row-gap: var(--space-2);
    column-gap: var(--space-4);
    /* 開合動畫：整個面板一起變化，取代原本逐項 nth-child 展開 */
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition: opacity 0.3s var(--ease-water), transform 0.3s var(--ease-water), visibility 0.3s;
    pointer-events: none;
    /* 2026-09-26 根因修正（宗霖回報：點擊「室內設計／品牌設計／
       整合型設計」時位置會突然往左跳）：逐格拆解宗霖提供的螢幕
       錄影後發現，「跳動」其實是文字被瀏覽器原生的拖曳選字
       （drag-to-select）選取——選取範圍（藍底反白）從點擊處開始
       隨滑鼠微小位移不斷向右擴大、吃掉後面幾行的文字，視覺上才
       誤以為是「位置跳掉」，實際上位置從頭到尾沒有變動過一毫米。
       這也解釋了先前三種模擬方式（滑鼠按住不放、攔截 click 事件、
       模擬觸控 tap）都重現不了的原因：問題根本不是 click／tap 這類
       離散事件，而是「mousedown 後有位移」這個連續拖曳動作觸發的
       瀏覽器原生行為，純點擊模擬完全不會觸發它。
       修法：整個選單面板加上 user-select:none，跟全站選單／按鈕
       這類「操作用」而非「內容用」文字的慣例一致（不需要逐一排除
       文字連結，直接在面板層級統一設定，子元素會自動繼承） */
    user-select: none;
    -webkit-user-select: none;
  }
  .nav-trigger.is-open .fan-menu--social {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
  }
  /* 面板內所有連結／按鈕統一先歸零基礎規則給「小圖示」設計的
     絕對定位／固定尺寸／opacity，改回正常文件流；下面再依三種
     內容類型（站內導覽連結／LINE按鈕／社群圖示列）分別覆蓋外觀 */
  .fan-menu--social a,
  .fan-menu--social button {
    position: static;
    width: auto;
    height: auto;
    opacity: 1;
    pointer-events: auto;
    /* 2026-09-26 根因修正（宗霖回報：漢堡選單打開後，子頁面連結／LINE
       按鈕／社群圖示全部不見了，這是三個疊加問題裡的第三個，另外兩個
       分別是行內樣式 top 誤寫、.fan-menu 基礎規則 height:0，都已在
       上面／js/main.js 修正）：
       這裡原本就有 transform:none，但完全沒生效——根因是選擇器優先權
       不夠。桌機版原本專門給「4 個社群圖示垂直展開」寫的固定位移規則
       `.nav-trigger.is-open .fan-menu--social a:nth-child(1~4)`，
       選擇器疊了 3 個 class＋1 個 :nth-child（優先權相當於 4 個
       class），比這裡的 1 個 class 高出很多，永遠會贏。
       這組 nth-child 規則的本意是「面板裡第 1～4 個 <a>」，但 CSS 的
       :nth-child 是「在自己親生父層裡排第幾個」，不是「在整個面板裡
       排第幾個」——現在面板裡塞進了 .header-nav-links（6 個站內連結
       ＋作品案例下拉 3 項）、LINE 按鈕，這些巢狀在別的容器裡的 <a>，
       只要剛好也是「自己親生父層的第 1～4 個小孩」，一樣會被這組規則
       選中、套上原本只該給社群圖示用的位移，導致大部分連結被推到面板
       左側 -130px 外看不到、只剩少數項目位置剛好沒被影響。
       這裡用 !important 明確蓋掉，是刻意、範圍侷限的例外（只在
       ≤767 這個手機選單重新設計的情境下使用，針對性地反制上面那組
       選擇器優先權過高的舊規則，不是隨手擴大范圍的用法） */
    transform: none !important;
  }
  /* 站內導覽連結（.header-nav-links，桌機版是橫排＋hover 下拉，
     這裡改直排清單，字級跟間距比照選單一般連結該有的觸控舒適度），
     跟 LINE 按鈕一樣獨占一整排（grid-column:1/-1） */
  .fan-menu--social .header-nav-links {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    /* 2026-09-26 宗霖要求：每個連結的點擊範圍改成 hug content（貼合
       文字），不要 fill container（撐滿整排寬度）。align-items 原本是
       stretch（預設值），在 flex-direction:column 底下會讓每個子項目
       （連結）的寬度撐滿整個橫向可用空間；改成 flex-start，子項目改回
       依自己文字內容決定寬度、靠左對齊，其餘空間不算在可點擊範圍內 */
    align-items: flex-start;
    gap: 0;
    margin: 0 0 var(--space-3);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--grey-200);
  }
  .fan-menu--social .header-nav-links a {
    display: block;
    padding: var(--space-2) 0;
    font-size: var(--text-16);
    color: var(--ink);
    white-space: normal;
  }
  /* 「作品案例」＋其下拉 3 個子分類：桌機版靠 :hover 觸發顯示，
     觸控裝置沒有 hover，這裡改成永遠展開、直接當一般清單項目縮排
     呈現，不依賴任何互動狀態 */
  .fan-menu--social .header-nav-links .has-dropdown {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }
  .fan-menu--social .nav-dropdown,
  /* 2026-09-26 根因修正（宗霖回報：手機版點擊「室內設計／品牌設計／
     整合型設計」時，畫面看起來像整排文字突然往左跳掉）。
     這不是視覺錯覺，也不是文字被選取造成的（DOM textContent 全程
     沒變，用 getComputedStyle 逐一排查才抓到）：真正根因是選擇器
     優先權。桌機版「作品案例」hover 下拉選單的顯示規則
     `.header-nav-links .has-dropdown:hover .nav-dropdown` 疊了
     3 層 class（.header-nav-links + .has-dropdown + .nav-dropdown），
     沒有任何斷點限制、全站都生效；手機版這裡原本想覆蓋成
     `transform:none` 的規則只疊了 2 層 class
     （.fan-menu--social + .nav-dropdown），優先權比前者低。
     手機版使用者的手指觸碰／滑鼠移動到「室內設計」這類連結上時，
     瀏覽器一樣會判定為進入 :hover（或 :focus-within）狀態，這時
     優先權較高的桌機版規則會贏，把手機版清空的 transform 重新蓋回
     `translateX(-50%) translateY(0)`——這個位移量是「往左移動自己
     寬度的一半」，寫死給桌機版「以自身寬度置中對齊在父層正下方」
     用的，手機版的 .nav-dropdown 寬度、定位方式（position:static，
     不是 absolute）完全不同，套用這個位移就是把整排文字一次推出
     螢幕左側，露出來的部分才會讓人以為是「文字不見了、位置跳動」。
     這也解釋了先前為什麼點擊、觸控 tap 模擬都無法重現——問題在
     :hover／:focus-within 這兩個偽類本身被觸發的當下，不是任何
     click／tap 這類離散事件。
     修法：這裡把選擇器補上 .header-nav-links，讓層數（3層）跟
     桌機版那條規則打平，同分時比較書寫順序——這條規則在檔案更
     後面，會贏過前面的桌機版規則，不需要 !important */
  .fan-menu--social .header-nav-links .has-dropdown:hover .nav-dropdown,
  .fan-menu--social .header-nav-links .has-dropdown:focus-within .nav-dropdown {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    box-shadow: none;
    background: none;
    padding: 0 0 0 var(--space-4);
    margin-top: 0;
    min-width: 0;
  }
  .fan-menu--social .nav-dropdown a {
    padding: var(--space-2) 0;
    font-size: var(--text-14);
    color: var(--grey-700);
    text-align: left;
  }
  .fan-menu--social .nav-dropdown a:hover {
    background: none;
  }
  /* LINE 預約諮詢按鈕：維持自己原本的黑底膠囊樣式，獨占一整排
     （grid-column:1/-1），跟下面的社群圖示列之間留一點間距 */
  .fan-menu--social a.line-cta-button {
    grid-column: 1 / -1;
    display: flex;
    justify-content: center;
    padding: var(--space-3) var(--space-6);
    margin-bottom: var(--space-4);
    white-space: nowrap;
    /* 2026-09-26 根因修正（宗霖回報：LINE 按鈕預設文字應該是白色，
       目前卻是灰色）：`.fan-menu--social a { color: var(--nav-fg-
       social-icon) }` 這條規則是給桌機版「4 個社群小圖示」設計的
       文字色（本來就該是灰色，圖示本身沒有文字內容看不出差異），
       但選擇器同時也會選到這顆 LINE 按鈕（同樣是 `.fan-menu--social`
       底下的 `<a>`），優先權跟 `.line-cta-button` 自己的
       `color:var(--white)`打平、寫在後面的贏，蓋掉了白字。
       這裡明確重新指定白色，跟按鈕本身桌機版／其他頁面的樣式一致 */
    /* 2026-09-27 根因修正（宗霖回報：漢堡選單裡「LINE 預約諮詢」
       字級太小，要加大）：這顆按鈕在這個斷點沒有自己的字級設定，
       繼承了 .line-cta-button 手機版基礎規則的 13px（原本是給
       Header 上固定顯示的那顆同名按鈕縮小用的），比同一個選單裡
       其他站內導覽連結（.header-nav-links a，16px）明顯小了一截，
       在整個選單裡顯得不協調、不容易注意到。這裡明確指定跟其他
       選單連結一致的 16px */
    font-size: var(--text-16);
    color: var(--white);
  }
  /* 4 個社群圖示：不特別指定 grid-column，跟著自動排版接續排進上面
     兩排（各自 grid-column:1/-1）用完後剩下的欄位，四個剛好接成一
     整排並排 */
  /* 4 個社群圖示：不特別指定 grid-column，跟著自動排版接續排進上面
     兩排（各自 grid-column:1/-1）用完後剩下的欄位，四個剛好接成一
     整排並排、置中對齊 */
  .fan-menu--social > a:not(.line-cta-button) {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    justify-self: center;
  }

  /* ---- 手機版：Logo 觸控熱區擴大到 44px 高 ----
     2026-09-25 宗霖要求。Logo 視覺高度是 --text-20=20px，遠低於
     一般建議的 44px 觸控標準。不能直接放大 Logo 本身的視覺尺寸
     （桌機版已定案、這裡只調手機版，而且 Logo 視覺大小不分斷點都
     應該一致），改成放大既有的「感應熱區」保險用偽元素
     （.logo-wordmark::after，本來就是為了讓熱區不受底下 mask 圖層
     可見形狀影響而做的完整方框，這裡直接沿用、只在手機版擴大它的
     範圍），Logo 看起來完全不變，但點擊/觸控範圍變大。
     Header 總高度實測 52px（16px 上下 padding + 20px Logo），
     Logo 目前佔滿 16~36px 這段；上下各擴 12px 變成 4~48px，總高
     44px，仍完整落在 Header 的 0~52px 範圍內，不會外溢到 Header
     以外蓋住下面內容的點擊事件 */
  .logo-wordmark::after {
    top: -12px;
    bottom: -12px;
    left: 0;
    right: 0;
  }
}
/* ==========================================================================
   首頁專屬覆蓋：#faq／.contact-section 區塊的英文標籤視覺距頂固定 128px
   ========================================================================== */
/* 2026-09-01 業主明確要求：只調整首頁這兩個區塊，子頁面
   （about.html/works.html/faq.html/contact.html 等共用
   .page-header/.page-label/.contact-label 基礎規則的頁面）完全
   不能受影響，「子頁面很完美，不要動」。

   根因：
   1. #faq（首頁常見問題）：.page-header 的 padding-top:128px
      （子頁面用來統一容納任意長度英文標籤、讓中文標題跨頁對齊的
      核心機制，不能動）疊加了 .page-label 自己的 top:128px 絕對
      定位，變成256px；另外 .page-title 的動態 margin-top 因為
      .page-header 是 display:block（沒有 BFC）而 margin collapse
      穿透到外層，又疊加了額外間距，實測首頁 #faq 視覺距頂變成
      316px。
   2. .contact-section（首頁聯絡我們）：.contact-label 的
      top:128px 疊加在 section 本身的 128px padding 之上，變成
      248px。

   解法：完全不碰 .page-header/.page-label/.page-title/
   .contact-label 這些共用基礎規則本身，只用範圍限定選擇器：
   - html[data-page="home"] #faq .xxx：⚠️ 2026-09-01 修正過一次
     嚴重誤傷——原本只用 #faq 當選擇器，以為這個 id 只存在於
     index.html，但實際上 faq.html（子頁面）內部的 section 也用
     了同樣的 id="faq"（兩個獨立 HTML 檔案各自使用相同 id 在
     技術上不算違規，但選擇器沒考慮到這點）。結果 #faq .page-header
     這條規則同時命中了首頁跟子頁面 faq.html，把子頁面的中文標題
     從跨頁對齊的 384px 拉低到 256px，破壞了業主要求保留的「子頁面
     所有中文標題同一高度」效果。改用 html[data-page="home"] #faq
     雙重限定，只有 <html data-page="home">（也就是 index.html）
     底下的 #faq 才會被選中，faq.html 的 <html data-page="faq">
     不會被誤傷。
   - html[data-page="home"] .contact-label：.contact-section／
     .contact-label 這兩個 class 同時被首頁 index.html 跟子頁面
     contact.html 共用，不能只用 class 選擇器，必須額外用只存在
     首頁 <html> 標籤上的 data-page="home" 屬性做外層範圍限定，
     確保 contact.html 完全不受影響。

   驗證：已用 Playwright 逐一測試 about.html/works.html/faq.html/
   contact.html 四個子頁面的標籤位置、標籤-標題間距、以及四個
   子頁面彼此的中文標題是否維持在同一個絕對高度（跨頁對齊），
   確認完全沒有被首頁的改動影響。 */
html[data-page="home"] #faq .page-header {
  padding-top: 0;
  display: flow-root;
}
html[data-page="home"] #faq .page-label {
  top: 0;
}
html[data-page="home"] .contact-label {
  top: 0;
}

/* ==========================================================================
   子頁面專屬覆蓋：about/works/faq/contact 四個頁面整體內容上移 64px
   ========================================================================== */
/* 2026-09-01 業主要求：把這四個子頁面的中文標題從 384px 調整為
   320px，但不是只調標題本身——業主明確要求「所有內容都往上64px」，
   也就是整個頁面主要內容區塊（含標題以下的所有東西：FAQ手風琴
   列表、作品案例格線、聯絡表單等）整體上移，不是單獨改標題的
   margin-top（那樣只會讓標題跟底下內容的間距跑掉，不是真正的
   「整頁上移」）。

   首頁完全不受影響（業主明確要求「首頁現在很棒不要動到」）：這裡
   用 html[data-page="xxx"] 精準鎖定各自子頁面，不會誤傷首頁
   index.html（它的 data-page="home"，且首頁的六個區塊各自獨立，
   不會被這裡的選擇器命中）。

   做法：每個子頁面都只有一個主要內容 <section class="section">
   容器（header/nav 是 position:fixed，不受文件流位移影響；footer
   在 section 之後，section 往上移動後 footer 會自然跟著往上補位，
   讓整頁高度減少64px，這正是「往上移動」該有的效果，不需要額外
   處理 footer）。用 margin-top:-64px 讓這個 section 整體上移。 */
html[data-page="about"] > body > section.section,
html[data-page="project"] > body > section.section,
html[data-page="faq"] > body > section.section,
html[data-page="contact"] > body > section.section,
html[data-page="award"] > body > section.section,
html[data-page="service"] > body > section.section,
html[data-page="privacy-policy"] > body > section.section {
  margin-top: -64px;
}

/* ==========================================================================
   獲獎紀錄頁（awards.html）— 2026-09-01 新增
   ========================================================================== */
/* .page-header/.page-label/.page-title 沿用全站子頁面共用骨架，不重寫。
   本頁其餘內容是全新獨立元件，全部用 .award-detail-* 命名前綴，跟
   首頁 #recognition 專用的 .award-row/.award-name/.award-tag 完全
   區隔，避免共用 class 互相影響（見 handoff.md「改共用 class 前先
   盤點」教訓）。 */

.award-page-intro {
  /* 業主要求跟下方獎項卡片同寬。卡片寬度是 .award-detail-list
     兩欄 grid 動態分配出來的（沒有寫死 px，會隨容器寬度縮放），
     不是固定數字，所以這裡用跟 grid 兩欄一致的公式反推單欄寬度：
     (容器寬度 - gap) / 2，gap 跟 .award-detail-list 的
     gap:var(--space-8) 保持一致，兩者連動、不會各自調整後跑掉。
     手機版兩欄 grid 會改回單欄（見 767px 斷點），這裡的 max-width
     只在桌機版有意義，手機版當它是「足夠寬、實際不會被觸發限制」
     即可，不影響手機版版面 */
  max-width: calc((100% - var(--space-8)) / 2);
  font-size: var(--text-16);
  line-height: var(--leading-3);
  color: var(--ink);
  /* 正文段落統一套用 0.1em 字距，跟全站 .about-desc/.faq-a 等
     內文段落一致的 token（業主只要求正文段落，年份/標籤等小字
     不動，不套用在 .award-detail-year/.award-detail-org 等） */
  letter-spacing: var(--tracking-xs);
  margin-bottom: var(--space-16);
}

.award-detail-list {
  /* 一橫排兩張卡片，寬度固定分兩欄。
     2026-09-13 更新：舊決策是「同排卡片強制等高」（align-items
     預設值 stretch），但改成可折疊卡片後這條規則造成矛盾——
     業主要求每張卡片的展開/收合完全獨立，不能因為左邊展開了、
     右邊收合的卡片外框高度也被拉長跟著留白。改成 align-items:
     start，讓每張卡片依自己實際內容高度呈現，不受同排其他卡片
     影響，兩者現在同時滿足：卡片各自獨立摺疊 + 版面不會出現
     詭異的大片空白 */
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-items: start;
  gap: var(--space-8);
}

.award-detail-card {
  background: var(--white);
  border-radius: var(--radius-md);
  /* 折疊按鈕跟展開內容各自控制自己的 padding，容器本身不留
     padding，避免收合狀態下按鈕四周留白不對稱 */
  padding: 0;
  overflow: hidden;
  /* 首頁獎項清單連結用 #award-xxx 錨點跳轉過來時，避免卡片標題
     被 fixed 定位的 .site-header 遮住 */
  scroll-margin-top: var(--space-24);
}

/* ---- 折疊頭部（2026-09-13 改版）----
   標題＋對應作品/年份常駐可見，這裡改成純展示用的 div（不可
   點擊），展開/收合改由卡片底部的文字按鈕觸發，取代原本「整列
   可點擊但只有一個箭頭圖示」的設計——業主反饋只有箭頭圖示不容易
   讓人理解可以點擊展開，且觸發區跟顯示內容混在一起，右下角
   會出現一大塊空白 */
.award-detail-head {
  /* 2026-09-26 根因修正（宗霖回報：各張獎項小卡的上下內距明顯比
     左右大，要求統一成跟左右一樣）：卡片本身 padding:0（見上面
     .award-detail-card 的說明，折疊按鈕跟展開內容各自控制自己的
     padding），實際內距分別來自這裡（頂部到標題）跟下方
     .award-detail-toggle（收合狀態下按鈕到卡片底部）兩處。原本
     頂部是 --space-8(32px)，左右是 --space-6(24px)，上比左右
     明顯寬；改成頂部也用 --space-6，四個方向的視覺留白統一 */
  padding: var(--space-6) var(--space-6) 0;
}

/* 展開/收合動畫：跟 FAQ 手風琴同一套純 CSS 技巧
   （grid-template-rows 0fr→1fr），不用 JS 量測高度，內容增減
   時自動適應，不需要額外維護 */
.award-detail-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.5s var(--ease-water);
}
.award-detail-card.is-expanded .award-detail-panel {
  grid-template-rows: 1fr;
}
.award-detail-panel-inner {
  overflow: hidden;
  padding: 0 var(--space-6);
}
/* 展開內容跟頭部（對應作品/年份）之間的間距：不能用
   .award-detail-panel-inner 的 padding-top——那個 padding 是容器
   box model 的一部分，即使 grid-template-rows:0fr 把內容區域摺到
   視覺高度 0，padding 依然會撐開容器，導致收合狀態下還是能看到
   一小截空隙外露（跟先前 padding-bottom 洩漏第一行文字是同一種
   坑）。改成套用在 panel 內第一個子元素身上，才會隨內容一起被
   摺疊 */
.award-detail-panel-inner > *:first-child {
  margin-top: var(--space-6);
}
/* 展開時卡片底部留白：不能用 .award-detail-panel-inner 本身的
   padding-bottom——那個 padding 是容器 box model 的一部分，即使
   grid-template-rows:0fr 把內容區域摺到視覺高度 0，padding 依然
   會撐開容器，導致收合狀態下還是能看到一小截內容外露（實測值等於
   padding-bottom 的 32px，正是這次「簡介第一行跑出來」的根因）。
   改成套用在 panel 內最後一個子元素身上，才會隨內容一起被摺疊 */
.award-detail-panel-inner > *:last-child {
  margin-bottom: var(--space-6);
}

/* ---- 展開內容底部照片佔位（2026-09-13 新增）----
   業主要求每張卡片展開後最下方放一張照片，目前用灰框佔位，
   等業主提供實際照片後直接把這個 div 換成 <img> 即可。
   4:3 比例、寬度撐滿卡片內容區（不受 max-width 限制，區別於
   .award-detail-desc/.award-detail-quote 那種文字段落刻意收窄
   閱讀寬度的做法——這裡是視覺圖片，撐滿更有份量） */
.award-detail-photo {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--placeholder);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-4);
  /* 2026-09-13 更新：業主提供實際照片後，改用 <img> 取代原本的
     灰框 <div> 佔位。照片原始比例不是 4:3（實測從 1.25 到 1.78
     都有），用 object-fit:cover 讓照片依框架比例裁切、填滿整個
     4:3 區域，框架尺寸本身完全不受照片原始尺寸影響，不會被
     撐大或變形 */
  object-fit: cover;
}

/* ---- 底部文字展開/收合按鈕（2026-09-13 新增）----
   取代原本卡片右上角「只有一個箭頭圖示」的觸發方式——業主反饋
   單獨一個箭頭不容易讓人理解可以點擊展開，改成明確的文字敘述
   （收合時顯示「點擊展開查看詳情」，展開時顯示「收合詳情內容」），
   放在卡片最底部，跟上方常駐可見的標題/對應作品/年份區隔開，
   收合狀態下也不會在卡片右下角留下一大塊空白 */
.award-detail-toggle {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  /* 2026-09-26 同上（.award-detail-head 根因說明）：這裡原本上下
     是 --space-4(16px)，比左右 --space-6(24px) 小，是「上下比左右
     小」這個不一致的另一半來源（收合狀態下卡片底部到按鈕文字的
     距離）。統一成 --space-6，四個方向的內距現在一致 */
  padding: var(--space-6);
  font-family: var(--font-cn);
  font-weight: 500;
  font-size: var(--text-14);
  color: #505050;
  cursor: pointer;
  transition: background-color 0.3s var(--ease-water);
}
/* 2026-09-26 根因修正（宗霖回報：點擊展開/收合詳情時，會有一條
   灰色色塊跑出來、揮之不去，希望維持一開始的 default 樣子，灰色
   只留給「按壓下去的那一瞬間」）：
   根因是觸控裝置的已知行為——手機/平板沒有真正的滑鼠游標，但
   瀏覽器仍然會在使用者「點擊」一個元素後，把 :hover 這個本來
   設計給滑鼠指標「懸停」用的偽類狀態套用上去，而且通常會一直
   卡住，直到使用者點擊畫面上其他地方才會解除。這裡原本用 :hover
   顯示灰色背景，在觸控裝置上就變成「點完之後灰色一直留著」，
   跟宗霖想要的「只在按壓當下短暫出現」完全是兩回事。
   修法：改用 :active（手指/滑鼠真正按壓中的那一刻才成立，放開
   的瞬間就解除，觸控裝置上不會有殘留），拿掉 :hover 版本 */
.award-detail-toggle:active {
  background-color: var(--grey-100);
}
.award-detail-toggle-text-collapse { display: none; }
.award-detail-toggle[aria-expanded="true"] .award-detail-toggle-text-expand { display: none; }
.award-detail-toggle[aria-expanded="true"] .award-detail-toggle-text-collapse { display: inline; }
.award-detail-toggle-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-cn);
  font-weight: 500;
  font-size: var(--text-14);
  line-height: 1;
  transition: transform 0.4s var(--ease-spring);
}
.award-detail-toggle[aria-expanded="true"] .award-detail-toggle-icon {
  transform: rotate(180deg);
}


.award-detail-name {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: var(--text-24);
  line-height: var(--leading-2);
  color: #505050;
  /* 業主要求字距大一級：原本繼承 body 預設 0em，改成 0.1em */
  letter-spacing: var(--tracking-xs);
  margin-bottom: var(--space-3);
}

/* ---- ② 頒發單位｜年份（2026-09-13 改版）----
   從原本單行 .award-detail-org 改成雙欄並排，比照示意圖「頒發
   單位｜Red Dot Design Award（德國） 獲獎年份｜2025」的呈現方式。
   欄位標籤（頒發單位／獲獎年份／對應作品）統一用 .award-detail-
   meta-label 灰階弱化，不搶內文本身的視覺份量 */
.award-detail-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* 業主要求右側常駐一顆官方認證按鈕，作品名稱靠左，兩者分居
     容器兩端 */
  justify-content: space-between;
  gap: var(--space-1) var(--space-6);
  font-size: var(--text-16);
  color: #505050;
  /* 2026-09-13 修正：同 .award-detail-project，margin-bottom +
     padding-bottom 疊加造成間距比其他區塊大一倍，拿掉多餘的
     margin-bottom，只保留 padding-bottom 維持文字跟底線間距 */
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--grey-300);
}
.award-detail-project-link {
  /* 對應作品名稱連結（2026-09-13 新增）：業主要求把原本展開內容裡
     獨立的「連結至作品頁」按鈕拿掉，改成直接把連結掛在收合區常駐
     顯示的作品名稱本身，用底線暗示可點擊，hover 時降低透明度呼應
     全站連結的互動回饋語言 */
  font-size: var(--text-20);
  font-weight: 500;
  color: inherit;
  text-decoration: none;
  transition: opacity 0.3s var(--ease-water);
}
.award-detail-project-link:hover {
  opacity: var(--state-hover-opacity);
}

.award-detail-desc {
  font-size: var(--text-16);
  line-height: var(--leading-3);
  color: #505050;
  /* 業主要求參考首頁「關於我們」內文段落（.about-desc）的寬度，
     改成同樣的 620px（原本是 680px），寫死 px 而非用 grid 欄位
     系統，做法跟 .about-desc 一致 */
  max-width: 620px;
  /* 正文段落統一套用 0.1em 字距 */
  letter-spacing: var(--tracking-xs);
  margin-bottom: var(--space-4);
}

/* ---- ⑤ 獲獎心得總結（2026-09-13 改版）----
   沿用原本的引言樣式（.award-detail-quote），額外加上小標題
   （.award-detail-summary-title）呼應示意圖「獲獎心得總結」字樣 */
.award-detail-summary-title {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: var(--text-16);
  color: #505050;
  margin-bottom: var(--space-2);
}
.award-detail-quote {
  /* 業主要求拿掉斜體 */
  font-style: normal;
  font-size: var(--text-16);
  /* 2026-09-13 四次修正：業主要求行距要跟簡介（.award-detail-desc）
     一樣寬，改回 leading-3（1.75倍），取代先前為了對齊「對應
     作品」字級所改的 leading-2（1.5倍）——現在對應作品欄位已經
     改版拿掉，不需要再遷就那個對齊需求 */
  line-height: var(--leading-3);
  color: #505050;
  /* 跟 .award-detail-desc 一起改成 620px，維持兩段文字寬度一致
     （原本是 680px，業主要求對齊「關於我們」內文段落寬度） */
  max-width: 620px;
  /* 正文段落統一套用 0.1em 字距 */
  letter-spacing: var(--tracking-xs);
  padding-left: var(--space-4);
  border-left: 2px solid var(--grey-400);
  margin-bottom: var(--space-4);
}


/* ---- ⑥ 連結至官方認證來源（2026-09-13 新增，依業主提供示意圖）----
   膠囊外框按鈕樣式，比照示意圖圓角外框、置中對齊。業主確認先用
   各獎項官網首頁佔位連結，之後直接替換 href 即可，樣式不用動 */



/* ---- 年份手風琴（2026-09-13 改版，比照 faq.html 的
   .faq-category-toggle 完整機制）----
   業主要求年份分隔線改成手風琴見風樣：預設完全收合只顯示年份
   列，點擊展開才顯示該年度全部獎項卡片。年份文字獨立包在
   .award-year-label（單一、明確的文字節點），未來 WP+ACF 後台
   要讓業主編輯年度時可直接對應這個文字節點，不用改動外層按鈕
   結構或展開動畫邏輯 */
/* [.award-year-category 目前沒有獨立樣式，2026-09-20 移除空規則外殼，僅保留以下說明] ⚠️ 2026-09-14 修正：原本這裡的 margin-bottom:24px，跟 .award-year-toggle 自己的 padding-bottom:24px 疊加，導致 「年份文字→分隔線」的視覺間距變成 48px，比 FAQ 對應的 「室內設計→分隔線」間距（.faq-category 完全沒有這個 margin，純粹靠 .faq-category-toggle 的 padding-bottom:24px） 多了整整 24px。拿掉這個 margin-bottom，改成跟 FAQ 一致， 間距完全交給 toggle 的 padding-bottom 控制 */
.award-year-toggle {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: 0 0 var(--space-6);
  cursor: pointer;
  position: relative;
}
/* 手繪風格分隔線（2026-09-13 改版）：比照 faq-category-divider
   同一套 clip-path 技巧（中間垂直隆起、兩端收窄的手繪造型），
   取代原本普通的 border-bottom 直線，跟全站手風琴視覺語言一致 */

/* 年份分類之間的分隔線（2026-09-13 新增，比照 faq-category-
   divider 同一套手繪 clip-path 技巧）：獨立、固定顯示在兩個
   年份分類之間，不管前一個年份展開或收合都在同樣位置，作為
   年度跟年度之間的視覺區隔
   ⚠️ 2026-09-14 修正：原本這裡多帶了 margin:32px 0，導致「年份
   文字→分隔線」的視覺間距變成 24px(toggle padding-bottom) +
   32px(這裡的 margin-top) = 56px，比 FAQ 對應的「室內設計→
   分隔線」間距（純粹 24px，因為 .faq-category-divider 完全沒有
   margin）明顯大出一截。拿掉 margin，比照 .faq-category-divider
   做法，讓上方間距完全交給 .award-year-toggle 的 padding-bottom
   （24px）控制，兩處視覺間距就一致了。下方（分隔線到下一個年份）
   的間距改用 margin-bottom 補回，維持原本 32px 的視覺呼吸感
   不變（避免拿掉全部 margin 後下面完全貼齊） */
.award-year-category-divider {
  height: 1px;
  background: var(--ink);
  clip-path: polygon(
    0% 50%,
    3% 20%,
    50% 0%,
    97% 20%,
    100% 50%,
    97% 80%,
    50% 100%,
    3% 80%
  );
  margin: 0 0 var(--space-8);
}
.award-year-label {
  font-family: var(--font-en);
  font-weight: 700;
  font-size: var(--text-20);
  color: var(--ink);
}
.award-year-toggle-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--icon-md);
  height: var(--icon-md);
  color: var(--ink);
  font-family: var(--font-cn);
  font-weight: 500;
  font-size: var(--text-18);
  line-height: 1;
  transition: transform 0.4s var(--ease-spring);
}
.award-year-toggle[aria-expanded="true"] .award-year-toggle-icon {
  transform: rotate(180deg);
}

/* Hover 提示：跟 .faq-toggle-tip 完全同一套結構跟定位邏輯——
   真正的 HTML 子元素（不是偽元素），跟箭頭圖示是兄弟關係，
   不受箭頭 180 度旋轉影響；桌機限定（觸控裝置沒有 hover 概念） */
.award-year-toggle-tip {
  position: absolute;
  bottom: calc(var(--space-6) + var(--icon-md) + var(--space-2));
  right: calc(var(--icon-md) / 2);
  transform: translateX(50%) translateY(4px);
  padding: var(--space-1) var(--space-3);
  background: var(--ink);
  color: var(--white);
  font-family: var(--font-cn);
  font-size: var(--text-14);
  font-weight: 400;
  white-space: nowrap;
  border-radius: var(--radius-md);
  opacity: 0;
  pointer-events: none;
  z-index: 20;
  transition: opacity 0.25s var(--ease-water), transform 0.25s var(--ease-water);
}
.award-year-toggle-tip::after {
  content: '';
  position: absolute;
  top: 100%;
  right: 50%;
  transform: translateX(50%);
  border: 5px solid transparent;
  border-top-color: var(--ink);
  border-bottom-width: 0;
}
.award-year-toggle-tip-collapse { display: none; }
.award-year-toggle[aria-expanded="true"] .award-year-toggle-tip-expand { display: none; }
.award-year-toggle[aria-expanded="true"] .award-year-toggle-tip-collapse { display: inline; }
@media (hover: hover) {
  .award-year-toggle:hover .award-year-toggle-tip {
    opacity: 1;
    transform: translateX(50%) translateY(0);
  }
}

/* 展開動畫：跟 FAQ 手風琴同一套純 CSS 技巧
   （grid-template-rows 0fr→1fr），不用 JS 量測高度 */
.award-year-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.5s var(--ease-water);
}
.award-year-toggle[aria-expanded="true"] ~ .award-year-panel {
  grid-template-rows: 1fr;
}
.award-year-panel-inner {
  overflow: hidden;
}
.award-year-panel-inner .award-detail-list {
  padding-top: var(--space-6);
  /* ⚠️ 2026-09-14 補充修正：拿掉 .award-year-category 的
     margin-bottom:24px 後（見上方說明），才發現這裡原本完全沒有
     padding-bottom——先前「展開卡片清單底部→分隔線」看起來有
     間距，其實是那個 margin-bottom 意外幫忙撐開的，不是這裡
     本來就有正確設計。現在補上 padding-bottom:32px（跟
     .award-year-category-divider 的 margin-bottom 一致，維持
     視覺上下對稱），讓展開狀態下最後一張卡片跟分隔線之間恢復
     應有的留白，不會贴在一起 */
  padding-bottom: var(--space-8);
}

.award-page-badges {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* 2026-09-13 修正：原本用 grid repeat(6,1fr) 等寬欄位切割，
     但六個 logo 實際寬度差異很大（28px～176px），置中在等寬
     欄格裡會讓 logo 之間的視覺間距忽大忽小、很不均勻。改用
     flex + space-between：最左右兩個 logo 天生貼齊容器邊緣，
     中間的依實際寬度在剩餘空間裡視覺均分間距，不受個別 logo
     寬度影響 */
  /* 2026-09-14 進行中：宗霖要求 logo 列上下視覺間距一致（下方
     「logo→footer」固定 128px，來自全站 .section 標準
     padding-bottom，不需調整）。上方「分隔線→logo」原本只有
     32px 明顯偏小，來回調整多輪：96(太小)→144(太大)→120(太大)→
     104(微大)→98(微大)→92(微大)→84→68→36(最新，效果未確認)。
     ⚠️ 這是純粹依宗霖肉眼回饋來回試出來的數字，沒有可靠的算式
     依據——.award-page-badges 是 align-items:center 的 flex
     容器，加上分隔線本身的視覺留白，兩者疊加後的實際視覺間距
     跟 padding-top 的數字不是線性對應關係（曾經 padding-top 從
     48 加到 176 完全沒反映在視覺上，後來才發現是量測基準搞錯，
     見本次 git 歷史 / handoff v22 完整說明）。之後如果還要再調，
     務必先用瀏覽器開發者工具或 Playwright 精確量測「分隔線底部
     → logo <img> 頂部」的絕對頁面座標差，不要單看這個 CSS 數字
     去推算，也不要只憑肉眼在不同截圖間比較（不同截圖的視窗尺寸
     可能不同，會造成誤判） */
  margin-top: 0;
  padding-top: 36px;
}
.award-page-badges .award-badge-logo {
  height: 56px;
  width: auto;
  object-fit: contain;
}

@media (max-width: 767px) {
  /* 2026-09-26 死碼清理：這裡原本有一條 .award-detail-card
     { padding: var(--space-4); } 想統一上下左右內距，但完全沒有
     生效過——.award-detail-card 本身的基礎規則是 padding:0（見該
     處說明：折疊按鈕跟展開內容各自控制自己的 padding，容器本身
     不留 padding），改這個元素的 padding 從一開始就打錯目標，
     真正決定內距的是 .award-detail-head（頂部到標題）、
     .award-detail-toggle（收合狀態下按鈕到卡片底部）、
     .award-detail-panel-inner（左右內距）這幾個子元素，這條規則
     形同虛設。這次改成直接在基礎規則（不分斷點）把 .award-detail-head
     跟 .award-detail-toggle 的內距統一成 --space-6，全斷點一致
     生效，不需要手機版再額外覆蓋，故移除這條死碼 */
  /* 桌機版改成兩欄固定寬度後，手機螢幕太窄放不下兩欄，改回單欄
     堆疊，避免卡片被擠壓變形 */
  .award-detail-list { grid-template-columns: 1fr; }
  /* 2026-09-26 根因修正（宗霖回報：獲獎紀錄子頁面內文手機版沒幾個字
     就換行）：.award-page-intro 的 max-width 是跟下面兩欄卡片 grid
     同一個公式（(容器寬度-gap)/2，算出「單欄卡片的寬度」），這裡的
     舊註解寫「手機版兩欄 grid 會改回單欄，這裡的 max-width 只在桌機版
     有意義，手機版當它是足夠寬、實際不會被觸發限制即可」——這個假設
     是錯的，沒有實際驗證過：手機版容器本身就窄，同一個「除以 2」的
     公式套用在窄容器上算出來還是窄（實測只有 155px），完全會被觸發，
     不是「不會被觸發限制」。手機版跟下面的卡片 grid 一樣改回單欄
     （100% 寬度），不要再對半分 */
  .award-page-intro { max-width: 100%; }
  .award-detail-meta { flex-direction: column; align-items: flex-start; gap: var(--space-1); }
  /* 2026-09-26 根因修正（宗霖回報：logo 牆一行塞太多，大概 3-4 個
     就好）：桌機版用 justify-content:space-between 讓每一行的 logo
     自動撐開、均分整行寬度——這在桌機版寬容器、logo 數量剛好排滿
     一行時是合理的效果，但手機版加上 flex-wrap:wrap 換行後，
     space-between 會讓「每一行」各自盡量撐滿容器寬度、塞進去
     越多 logo 越好，這正是宗霖看到「一行塞了 5 個」的根因——
     這個排列邏輯的目標本來就是「填滿」，不是「維持固定間距」。
     改成 justify-content:flex-start（logo 依序排列，不強制撐滿）
     ＋ 固定 column-gap（--space-6=24px），實際塞得下幾個依各
     logo 實際寬度自然決定（logo 寬度差異很大，20px～125px 都有，
     沒辦法鎖死精確數字），但不會再被強迫撐滿整行 */
  .award-page-badges {
    flex-wrap: wrap;
    justify-content: flex-start;
    column-gap: var(--space-6);
    row-gap: var(--space-6);
  }
  .award-page-badges .award-badge-logo { height: 40px; }
}

/* ==========================================================================
   無 JS 環境備援內容（<noscript>）
   ========================================================================== */
.awards-noscript-fallback {
  padding: var(--space-8) 0;
  color: var(--ink);
}
/* .awards-noscript-fallback .awards-badges 根因（第三次診斷，
   2026-09-11）：前兩次修正只調了 max-width，卻沒發現
   .awards-badges 跟 <ul> 兩者的「起點 x 座標」根本不一樣——
   <ul> 有 padding-left:var(--space-6)（24px），文字實際從
   x:124 開始畫；.awards-badges 沒有這個 padding，直接從
   .section-inner 的邊界 x:100 起算。兩個容器起點不同，就算
   max-width 設成同一個數字，右邊界也不可能對齊（實測會固定
   差 24px，正好等於這個 padding 差異，不是巧合）。
   加上這個 padding-left 就能同時解決三個問題：其一是右邊界對齊
   的起點問題；其二是連帶讓最右側徽章有機會透過 justify-self:end
   真正頂到跟清單文字相同的右邊界（見下方 :last-child 規則）；
   ⚠️ max-width 數字第一次寫成 281px 時算錯了——這個專案全站
   套用 * { box-sizing: border-box }（見 style.css 開頭），代表
   padding 是包含在 width/max-width「裡面」，不是額外加總上去的。
   容器起點 x:100，要讓右邊界落在跟清單文字相同的 429px，需要的
   「總寬度」= 429 − 100 = 329px，這個 329px 本身就已經內含
   24px 的 padding-left，不需要再扣一次（扣掉 padding 才會content
   -box 寬度 329-24=305px，剛好等於前面量到的最長文字寬度 305px，
   兩者吻合，證明這次算式方向才是對的） */
.awards-noscript-fallback .awards-badges {
  padding-left: var(--space-6);
  max-width: 329px;
}
/* 每一排（grid row）最右邊那一欄的圖片，貼齊格子右邊界而非
   置中——.award-badge-logo 全站預設用 justify-self:center
   讓寬窄不一的圖片在自己格子裡置中顯示，但宗霖明確要求「上下
   兩排徽章最右側的兩個要切齊清單列的最右側」。3欄 grid 裡，
   nth-child(3n) 精準對應到「每排的第3欄」（不論總共有幾排），
   比寫死 nth-child(3), nth-child(6) 更能因應未來徽章數量增減
   （例如業主透過 WP/ACF 新增到 9 個徽章時，第9個一樣會自動
   套用，不用回來加規則） */
.awards-noscript-fallback .award-badge-logo:nth-child(3n) {
  justify-self: end;
}
/* 2026-09-11 第四次修正：宗霖指定「清單→徽章」間距在無 JS 環境
   下要改成 20px，跟有 JS 版本（16px，見上方 .awards-badges 的
   margin-top:var(--space-4) 基礎規則）從此分開、各自獨立控制。
   .awards-badges 這個 class 是有 JS／無 JS 兩邊共用的，不能直接
   改基礎規則（那樣兩邊會一起變動），改成在這裡疊加一條 scoped
   覆寫規則，只在 .awards-noscript-fallback 底下生效，優先權
   靠選擇器更具體（多一層父層）自然蓋過基礎規則，不用 !important */
.awards-noscript-fallback .awards-badges {
  margin-top: 20px;
}
.awards-noscript-fallback h3 {
  font-family: var(--font-en);
  font-size: var(--text-20);
  margin-bottom: var(--space-4);
}
.awards-noscript-fallback ul {
  margin-bottom: var(--space-4);
  padding-left: var(--space-6);
}
/* .awards-noscript-fallback ul 根因：上面這條 margin-bottom:
   var(--space-4)（16px）原本是給「清單後面沒有其他內容」的情況
   設計的收尾間距。2026-09-11 加入徽章後，清單下面接著
   .awards-badges（它自己有 margin-top:var(--space-3) 12px，
   跟有 JS 版本的 .awards-list 到 .awards-badges 間距用同一個
   token，兩邊才會一致），兩個 margin 疊加會變成 16+12=28px，
   比業主要求的「跟清單列間距一樣是 12px」多了一倍以上。
   這裡把 ul 的 margin-bottom 歸零，讓「清單→徽章」的間距完全
   交給 .awards-badges 的 margin-top 一個規則負責，不重複疊加 */
.awards-noscript-fallback ul:has(+ .awards-badges) {
  margin-bottom: 0;
}
/* 根因：<ul><li> 預設完全沒有設定行距，瀏覽器預設值很擠。
   有 JS 版本的獎項清單（.awards-list）用 gap:var(--space-3)
   （12px）分隔每一列，這裡直接套用同一個間距數值，讓無 JS 版本
   跟有 JS 版本的視覺間距一致，不是憑感覺調整的數字 */
.awards-noscript-fallback li {
  margin-bottom: var(--space-3);
}
.awards-noscript-fallback li:last-child {
  margin-bottom: 0;
}

/* ==========================================================================
   服務項目子頁面（service.html）
   ========================================================================== */

/* ---- Hero 匯流動畫區 ---- */
.service-intro {
  position: relative;
  /* 2026-09-12 拿掉白底圓角容器（宗霖要求「當此容器完全不存在」）：
     原本用 .section--white 讓這個區塊變成白底、上緣大圓角轉場，
     現在改成不掛這個 class，直接補上跟前一個區塊（page-header 所在
     的 .section--grey）一致的背景色，讓兩個區塊自然融合成一整塊
     連續的灰色背景，不再有任何轉場造型的存在感 */
  background: var(--grey-300);
  /* 2026-09-12 第五層修正：拿掉 overflow:hidden——這是導致
     position:sticky 完全失效的根因（sticky 元素的任何祖先若設定
     overflow:hidden/auto/scroll，會讓 sticky 定位機制失效，這是
     CSS 的已知限制，不是瀏覽器 bug）。原本加這個 overflow:hidden
     是為了保險裁掉可能超出的視覺內容，但拿掉 sticky 就完全動不了，
     兩者不能並存。改成不裁切，讓弧線視覺內容完整顯示（半徑雖然
     放大到 620px，但起點精準落在容器左右兩端，不會超出容器寬度） */
}
/* 2026-09-12 第四層修正：改成跟「服務旅程」同一套 track+sticky
   家族手法（見 HTML 的完整根因記錄）。外層 track 拉長提供捲動
   緩衝距離，內層 sticky 舞台卡住不動，讓弧線動畫有充分的捲動
   距離可以慢慢展開，不會像原本區塊自然捲動那樣幾乎瞬間播完 */
.service-intro-track {
  position: relative;
  /* 高度由 JS 動態設定（3 倍視窗高，跟服務旅程一致），這裡只是
     JS 尚未執行前的備援初始值 */
  height: 300vh;
  /* 2026-09-12：宗霖要求維持「服務項目中標→讓想法匯流成形中標」
     原本的 192px 間距。改成頂端對齊後，這個間距因為兩個因素
     變大：(1) sticky 內容跟前一區塊之間本來就有 256px 的自然
     間距，(2) sticky 內部又補了 padding-top:96px 避免內容被固定
     header 遮住。實測驗證兩者是線性疊加關係（256+margin-top+96=
     實際間距），反推需要 margin-top:-160px 才能精準達成 192px
     目標，不是單純用 192-256=-64 這種忽略 padding-top 的算法 */
  margin-top: -160px;
}
.service-intro-sticky {
  /* 2026-09-14 四次改版：原生 position:sticky 的「何時放開」是瀏覽器
     自己算的，跟弧線動畫進度（JS 算的另一套數字）是兩條沒有真正
     綁定的獨立邏輯，只靠 track 高度公式的緩衝值讓兩者「大致對齊」，
     沒有實質保證——這正是 #recognition 那節「關鍵技術決策」明確
     踩過、也明確禁止重踩的坑。改成跟 #recognition 標題區塊同一套
     做法：JS 手動控制 position:fixed，用同一個 progress 數值
     同時驅動「弧線畫多少」跟「這裡卡不卡住」，兩者保證同步。
     搭配 .service-intro-spacer 隱形佔位，維持版面高度不跳動。 */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* 2026-09-13 修正：原本強制 height:100vh，但內容本身（標題+
     副標+內文）通常比一個視窗矮，justify-content:flex-start 讓
     內容貼齊頂部，下方因此留下大片空白——這正是業主反饋「讓想法，
     匯流成形」跟下方「室內設計」區塊間距過大的真正原因（不是
     track 高度或 margin/padding 的問題）。改成 height:auto，
     sticky 舞台只會跟內容一樣高，不再有多餘空白 */
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  /* 2026-09-13 修正：業主要求匯流線起點對齊前一個 section 的
     「服務項目」中標，SVG 容器因此需要往上位移超出這個 sticky
     舞台本身的邊界。原本的 overflow:hidden 會把這段超出邊界的
     SVG 內容整個裁掉，導致線條完全不可見。拿掉這個屬性，讓 SVG
     可以視覺上延伸到 sticky 範圍之外，不會被裁切 */
  padding-top: var(--space-24);
}
.service-intro-spacer {
  /* 高度由 JS 設定，永遠跟 .service-intro-sticky 的實際高度一致，
     避免 sticky 切換成 fixed 定位時，後面的內容瞬間往上補位跳動 */
  visibility: hidden;
}
.service-intro-inner {
  position: relative;
  text-align: center;
  width: 100%;
}
.service-flow-lines {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: var(--container-max);
  height: 700px;
  pointer-events: none;
  overflow: visible;
}
.service-flow-line {
  stroke: var(--white);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
  /* 初始狀態：完全隱藏（透過 stroke-dasharray = 路徑總長、
     stroke-dashoffset = 同樣長度，讓整條線「畫出來的部分」是 0）。
     JS 用 getTotalLength() 量出精準路徑長度後設定這兩個屬性，
     捲動時再讓 dashoffset 往 0 移動，做出「線隨捲動被畫出來」的
     scroll-scrubbing 效果，寫法跟 Hero 水波紋動畫用的 stroke-
     dashoffset 技巧相同概念，只是這裡改用捲動進度直接驅動，不是
     CSS keyframes 自動播放 */
  opacity: 0.8;
}

.service-intro-content {
  position: relative;
  z-index: 1;
  max-width: 760px;
  margin: 0 auto;
}
.service-intro-title {
  font-family: var(--font-cn);
  font-weight: 700;
  /* 2026-09-12：套用首頁 #recognition「設計實力推動產業與城市
     發展」（.stat-block h2）同一套規格。業主指定固定 32px，
     不是響應式 clamp——直接複製過去，不自行調整數值 */
  font-size: 32px;
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
  margin-bottom: var(--space-2);
}
.service-intro-subtitle {
  font-family: var(--font-en);
  font-size: var(--text-18);
  letter-spacing: var(--tracking-0);
  color: #505050;
  margin-bottom: var(--space-8);
}
.service-intro-desc {
  /* 2026-09-12：套用首頁 #recognition「設計實力推動產業與城市
     發展」內文（.stat-block-lines）同一套規格：字級/行高本來就
     一致，這次補上 color（原本是較淺的 --grey-700，改成一致的
     --ink）跟 letter-spacing（原本沒有設定） */
  font-size: var(--text-16);
  color: var(--ink);
  letter-spacing: var(--tracking-xs);
}
/* 2026-09-12 二次修正：宗霖追問「行距真的跟首頁一樣嗎」，實測
   發現不一樣——原本用 <br> 手動換行＋單一 line-height 均分三行，
   跟首頁 .stat-block-line 的「每句話獨立 span，line-height 之外
   再疊加 margin-bottom:2px」不是同一套機制，實測視覺行距差了
   2px，且原本的寫法在較長那行觸發瀏覽器軟換行時，會被同一個
   line-height 硬壓在一起、跟其他手動換行行擠壓不一致（這正是
   首頁當初改成這個結構要修正的同一個坑，見 .stat-block-lines
   的 CSS 註解）。改成跟首頁完全一致的兩層結構，不再各自維護
   一套相近但不同的行距邏輯 */
.service-intro-line {
  display: block;
  line-height: var(--leading-3);
  margin-bottom: 2px;
}
.service-intro-line:last-child {
  margin-bottom: 0;
}

/* ---- 三大服務分類：左文右圖交錯排列 ---- */
.service-categories {
  padding-top: var(--space-16);
  /* 2026-09-12 拿掉白底圓角容器（宗霖要求整頁改成連續灰底，
     不要圓角白底分隔區塊）：跟前後 .service-intro / .service-process
     用同一階灰色，避免拿掉 section--white 後透出 body 的
     --grey-100 造成交界處色差 */
  background: var(--grey-300);
}
.service-category {
  display: grid;
  /* 2026-09-12 業主指定改成左右兩欄都固定寬度，不再用 5:7 比例：
     文字欄（原本 5fr）天生比公式算出的寬度窄，5:7 比例下公式
     max-width 永遠不會真正生效（父層本身就比公式值窄，max-width
     只能限制上限、不能撐大超過父容器）。改成兩欄都直接用公式
     算出的絕對寬度 calc((var(--container-max) - var(--space-8)) / 2)
     （跟 .service-category-text / .service-category-photo 上的
     max-width 完全同一個公式，三處保證同寬），中間留白靠 gap 撐開。
     gap 從 --space-16 改成 --space-8：兩欄各 604px + gap 32px
     剛好等於容器完整寬度 1240px，不會溢出（若維持 64px gap，
     總寬會變成 1272px，超出容器） */
  /* 2026-09-28 根因修正（宗霖要求修掉：桌機寬度 1100～1336px 服務項目
     兩欄溢出，例如 iPad 橫放）：
     上面寫死的兩欄絕對寬度（604px ×2 ＋ gap ＝ 1240px 整個容器）只有
     容器剛好等於 1240px（視窗 ≥1336px）時才放得下；視窗 1100～1335px
     容器比 1240px 窄，兩欄合計 1240px 就一定溢出——1100px 時容器只有
     1004px，兩欄合計固定 1240px 必然溢出（修正後 1099～1920px 實測溢出皆為 0）。
     修法：每欄改成 minmax(0, 604px)——上限維持原本的 604px（跟
     award.html 獎項卡片同公式，容器夠寬時完全不變），下限 0 讓兩欄
     在容器變窄時等比縮小、永遠塞得進容器。視窗 ≥1336px 每欄仍精準
     604px，行為跟修正前一模一樣；平板／手機的單欄規則在下方斷點內
     覆蓋成 1fr，不受影響 */
  grid-template-columns: repeat(2, minmax(0, calc((var(--container-max) - var(--space-8)) / 2)));
  justify-content: space-between;
  gap: var(--space-8);
  /* 2026-09-12 第二輪：從 center 改成 stretch，讓文字欄撐滿跟照片
     一樣的高度，搭配 .service-category-text 的 flex space-between，
     做出「編號＋中英標＋標籤」貼齊照片上緣、「引言＋內文」貼齊
     照片下緣的效果（宗霖指定，室內設計/品牌設計/整合型設計三組
     全部同步套用同一套排版邏輯） */
  align-items: stretch;
  position: relative;
}
.service-category + .service-category {
  margin-top: var(--space-32);
}
.service-category-text {
  /* 業主指定套用跟 award.html 獎項卡片同一個寬度公式：
     calc((容器完整寬度 - gap) / 2)。⚠️ 基準務必用
     var(--container-max)（1240px 完整容器寬度），不能用 100%——
     這裡的 100% 指的是 .service-category 這個 grid 的 5fr 子欄位
     寬度，已經被 5:7 比例切分過，不是完整容器寬度，用它當基準會
     算出跟 award.html 不同的絕對寬度，重踩 work-detail.html
     那次「同公式應該同寬度」的教訓（見該處 CSS 註解） */
  max-width: calc((var(--container-max) - var(--space-8)) / 2);
  /* 2026-09-12 第二輪：改成 flex column + space-between。
     .service-category-text 底下剛好是三個直接子元素
     （.service-category-heading／.service-category-tags／
     .service-category-desc），space-between 會把最大的空隙自動
     留在 tags 跟 desc 之間，讓「編號＋中英標＋標籤」這組貼齊
     容器頂部（＝照片上緣，因為父層 .service-category 已改成
     align-items:stretch 讓文字欄跟照片同高），「引言＋內文」
     這組貼齊容器底部（＝照片下緣）。不需要額外包 wrapper */
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
/* 2026-09-12 第三輪根因修正：.service-category-top 純粹是個包裹層，
   把 heading（編號+中英標）跟 tags（標籤列）合併成 flex column
   底下的單一子項目。根因是 space-between 會平均分配「所有」相鄰
   兄弟元素之間的空隙——heading/tags/desc 原本是三個平行的 flex
   items 時，heading↔tags 跟 tags↔desc 這兩段間隙都會被撐開，
   導致「英標到標籤列」出現非預期的大片空白（實測 111px，遠超過
   heading 自己的 margin-bottom:24px）。包成一組後，flex column
   底下只剩「top 群組」跟「desc」兩個項目，space-between 才會
   精準只把空隙留在這兩者之間，top 群組內部的 heading→tags 間距
   完全交由 .service-category-heading 的 margin-bottom 控制 */
.service-category-top {
  display: flex;
  flex-direction: column;
}
.service-category-heading {
  /* 2026-09-12 第四輪：拿掉 flex 並排編號跟中英標的排版。
     業主要求「中英標＋標籤＋內文」整組貼齊容器（網頁最大寬度）
     左緣，編號則移到容器外側（類似 absolute 定位法）。
     改成 relative 作為編號絕對定位的錨點，中英標 wrapper
     （.service-category-titles）不再跟編號並排佔用左側起始空間，
     直接從 heading 容器的左邊界（＝容器左緣）開始 */
  position: relative;
  margin-bottom: var(--space-6);
}
.service-category-number {
  font-family: var(--font-en);
  font-size: var(--text-16);
  font-weight: 500;
  color: var(--grey-500);
  /* 2026-09-12 第四輪：移到容器（.service-category-heading）外側，
     用 position:absolute + right:100% 讓編號完全落在左邊界之外，
     不佔用容器內的排版空間。margin-right 決定編號跟容器左緣之間
     的視覺間距，跟原本編號與中英標之間的 gap 數值一致（--space-4），
     維持觀感上的連續性。
     2026-09-12 第五輪：top 改成 0（原本是 50%+translateY(-50%)
     置中對齊整個 heading 容器），讓編號上緣對齊中標（.service-
     category-title）上緣。
     2026-09-12 第六輪：宗霖反映「編號明顯高於中標」，先前用
     Range.getBoundingClientRect() 量測，結果顯示視覺頂端完全一致
     （diff=0），但宗霖截圖仍清楚看到編號偏高，代表 Range API
     這個方法沒有正確反映跨字體（--font-en 數字 vs --font-cn
     中文）的真實墨色視覺差異，量測方法本身失準，不能只信任
     單一種量測工具。
     2026-09-12 第七輪：改用像素分析法（截圖後用 PIL 逐行掃描找出
  /* 2026-09-12：前幾輪用不同量測方法（Range API、像素分析）反覆
     算出不一致的補正值，宗霖確認實際效果仍未對齊，改為直接指定
     再往下移動 4px（從先前的 3px 累加），不再依賴自動化量測 */
  position: absolute;
  right: 100%;
  margin-right: var(--space-4);
  top: 6px;
  white-space: nowrap;
}
@media (max-width: 767px) {
  /* 2026-09-26 根因修正（宗霖回報：service.html 手機版有明顯沒做
     RWD 的地方——服務分類編號「01」被裁到看不見）：
     桌機版編號用 position:absolute + right:100% 的技巧，讓編號完全
     浮在 .service-category-heading 容器外側的左邊，不佔用容器內部
     排版空間，靠桌機版容器本身左側有足夠的頁面留白來容納這個「浮出
     去」的編號。但手機版 .section 左側留白（--space-6＝24px）比編號
     本身寬度加上右邊距（約 36px）還窄，編號因此有一部分被推到頁面
     容器外、超出視窗左緣，被全站的 overflow-x:clip 直接裁掉，只剩
     一小段看得到。
     修法：手機版放棄「浮到容器外」的技巧，編號改回正常文件流、
     顯示在標題正上方（不是側邊），不再需要往容器外側佔用額外空間 */
  .service-category-number {
    position: static;
    display: block;
    right: auto;
    top: auto;
    margin-right: 0;
    margin-bottom: var(--space-2);
  }
}
.service-category-title {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: var(--text-30);
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
}
.service-category-title-en {
  font-family: var(--font-en);
  font-size: var(--text-14);
  letter-spacing: var(--tracking-0);
  color: var(--grey-600);
  margin-top: var(--space-1);
}
.service-category-tags {
  list-style: none;
  margin-bottom: var(--space-12);
}
.service-category-tags li {
  font-size: var(--text-16);
  font-weight: 500;
  color: var(--ink);
  line-height: var(--leading-2);
}
.service-category-desc {
  max-width: 480px;
}
.service-category-desc-lead {
  font-size: var(--text-20);
  font-weight: 700;
  color: var(--ink);
  margin-bottom: var(--space-2);
}
.service-category-desc p:not(.service-category-desc-lead) {
  font-size: var(--text-16);
  /* 2026-09-12：宗霖要求跟首頁 #recognition 內文（.stat-block-line）
     行距一致。但這裡是自動軟換行的單一 <p>（換行位置隨容器寬度
     變動），無法比照首頁「每行拆成固定 span + margin-bottom:2px」
     的機制。改用等效 line-height 數值：首頁實際行距 = 28px
     行高 + 2px margin = 30px，這裡换算成比例 30/16 = 1.875，
     不是同一套機制、但視覺行距會很接近（經宗霖確認接受此作法，
     若之後真的需要逐字精準對齊，只能改回手動 <br> 固定換行
     位置後才能套用完全相同的 span+margin 結構） */
  line-height: 1.875;
  color: var(--grey-600);
}
.service-category-media {
  position: relative;
}
.service-category-carousel {
  position: relative;
  width: 100%;
  /* 業主指定套用跟 award.html 獎項卡片同一個寬度公式（見
     .service-category-text 的完整說明），4:3 比例不變，只是
     額外加上寬度上限，避免在寬螢幕上被 7fr 欄位撐得過大。
     欄位實際可用寬度（7fr）通常比這個上限更寬，所以要置中對齊，
     不然照片會貼齊欄位左緣、右側留白不對稱 */
  max-width: calc((var(--container-max) - var(--space-8)) / 2);
  margin: 0 auto;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-md);
  overflow: hidden;
}
/* 2026-09-13 新增：每個分類的照片改成 5 張輪播，比照首頁各項
   設計現成的素材（interior/brand/integrated 各 5 張），每隔數秒
   自動淡入淡出切換（見 main.js 的 initServiceCategoryCarousels）。
   5 張圖片全部絕對定位疊在同一個位置，同一時間只有 .is-active
   那張 opacity:1，其餘 opacity:0，靠 transition 做交叉淡化 */
.service-category-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* 2026-09-12：原本只有 <div> 佔位灰框，不需要這個屬性。現在
     換成正式的 <img>，圖片實際比例不會剛好跟 4:3 容器一致，加上
     object-fit:cover 讓圖片依比例裁切填滿容器，不會被拉伸變形；
     display:block 避免 inline 元素預設的底部留白縫隙。
     object-position 從預設的 center center 改成 center bottom：
     宗霖要求裁切基準點是「照片底部」，不要用置中方式定位——
     容器寬高比（4:3）通常比原始照片更「方」，裁切時瀏覽器預設
     會平均裁掉上下兩側，改成貼齊底部後，裁切只發生在照片頂部，
     底部（通常是地板、家具、店面招牌等主體內容）完整保留 */
  object-fit: cover;
  object-position: center bottom;
  display: block;
  opacity: 0;
  transition: opacity 1.2s var(--ease-water);
}
.service-category-photo.is-active {
  opacity: 1;
}

/* ---- 服務旅程：三步驟依序出現 ---- */
.service-process {
  /* 2026-09-12：宗霖要求「整合型設計」到「服務旅程」中標的真實
     視覺間距縮小到 64px。注意：這個 padding-top 的 CSS 數值
     跟實際量測到的視覺間距不是 1:1 對應——用絕對頁面座標實測，
     CSS 寫 96px 時，真實視覺間距是 112px（多了 16px 不明落差，
     可能來自瀏覽器對相鄰區塊邊界的渲染細節），所以這裡改成
     48px 是「反推」出來的值：96(原CSS) - 48(要削減的量) = 48，
     不是單純的 64+/-算式，之後如果要再調整這個間距，務必用
     Playwright 實測「整合型設計底部」到「service-process-track
     頂部」的絕對頁面座標差，不能只看這個 padding-top 的 CSS 值 */
  padding-top: var(--space-12);
  padding-bottom: 0;
}
/* 2026-09-12：拿掉原本用來跟旁邊 hint 文字並排的 flex 排列
   （hint 已依宗霖要求刪除），改成單純的 block 讓中英標自然垂直
   堆疊，結構比照首頁 .partners-header（本身無 flex 設定，
   靠子元素預設的 block 排列自然垂直堆疊） */
.service-process-header {
  margin-bottom: var(--space-24);
  /* 2026-09-15 修正：中英標已經移出 sticky 舞台，改放進
     .section-inner 一般文件流（見 service.html 該處說明），不再
     跟 .service-process-viewport 共用同一個父層，原本用來抵銷
     viewport padding 的負 margin-left/right 已經不需要——
     .section-inner 本身就是全站標準的置中容器，中英標維持預設的
     0 margin 就會自然對齊左緣，不用再手動抵銷任何 padding。
     ⚠️ 中英標原本在 sticky 舞台內部時，頂部會被
     .service-process-sticky 的 padding-top:96px（--space-24）
     往下推，這是 2026-09-12 記載「整合型設計→服務旅程」64px
     目標視覺間距的其中一部分。移出到一般文件流後不會再被那段
     padding 影響，這裡補回同樣的 96px，盡量維持原本疊加出來的
     視覺間距不變。這個數字沒有用 Playwright 重新實測驗證過，
     如果實際視覺間距跟移動前有落差，這是第一個該檢查的地方 */
  padding-top: var(--space-24);
}
/* 2026-09-12：中英標樣式完全比照首頁「合作夥伴」（.partners-title／
   .partners-subtitle），宗霖要求兩者「一模一樣，只有文字的差別」。
   直接複製字級/字重/字距/顏色/間距，不自行調整任何數值 */
.service-process-title {
  font-family: var(--font-cn);
  font-weight: 500;
  font-size: var(--text-20);
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
}
.service-process-title-en {
  font-family: var(--font-en);
  font-size: var(--text-14);
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
  margin-top: var(--space-1);
}

/* ==========================================================================
   服務旅程：捲動水平滑動（六步驟）
   跟首頁 #recognition 的 awards-scroll-track / awards-scroll-sticky
   同一套家族手法：外層 track 是一段刻意拉長的捲動軌道（提供緩衝
   距離），內層用原生 position:sticky 把「舞台」黏在畫面上，JS 讀取
   目前捲過軌道多少距離、換算成 0~1 進度，直接控制卡片群組的
   translateX，做出「垂直捲動→水平滑動」的效果。
   ========================================================================== */
.service-process-track {
  position: relative;
  /* ⚠️ 2026-09-14：高度改由 JS 用固定的筆電基準高度（830px）計算，
     不再是「視窗高度 × 3」（那樣會讓大螢幕出現超大空白，且讓
     START THE FLOW 的視覺位置隨螢幕高度變化，詳見 main.js
     對應區塊 LAPTOP_BASELINE_HEIGHT 的完整說明）。這裡的 300vh
     只是 JS 尚未執行前的備援初始值 */
  height: 300vh;
}
.service-process-sticky {
  position: sticky;
  top: 0; /* 桌機由 js/main.js 依視窗高度覆寫（視窗高於舞台時＝視窗高−舞台高，底緣貼齊視窗底部）；這裡是備援值 */
  /* 2026-09-19：原本 height:100vh。舞台內現在包含六大步驟＋START THE FLOW，
     改成「內容高度」(auto)：100vh 會在內容下方留下大片空白，那正是
     六大步驟與 START THE FLOW 之間約 430px 間距的真正來源。
     ⚠️ 連動：js/main.js 的軌道高度與進度分母原本用 window.innerHeight
     代表舞台高度，已同步改為實際量測舞台高度（stageHeight），兩處必須
     一致，否則捲動進度與放開時機會錯位。 */
  height: auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  overflow: hidden;
  /* 拿掉垂直置中改成頂部對齊後，補一段安全間距，避免 sticky 卡住
     時標題被固定的 .site-header（實測高度約69px）蓋住，同時仍比
     原本置中造成的 221px 明顯往上移動 */
  padding-top: var(--space-24);
}
.service-process-viewport {
  /* 可視窗口：卡片群組在這個寬度範圍內橫向捲動，超出範圍的部分
     用 overflow:hidden 裁掉，不會提前露出下一張卡片 */
  max-width: var(--container-max);
  width: 100%;
  margin: 0 auto;
  padding: 0 var(--space-12);
  overflow: hidden;
  position: relative;
}
.service-process-steps {
  display: flex;
  gap: var(--space-4);
  position: relative; /* 讓橫線的絕對定位以卡片群組為基準 */
  /* width 由 JS 動態設定，避免依賴猜測的固定卡片寬度 */
  will-change: transform;
}
.service-process-step {
  flex: 0 0 auto;
  /* 卡片寬度：桌面版一次看到約 3 張多一點，暗示「還可以繼續滑」，
     實際寬度由 JS 依可視窗口寬度計算後指定 */
  text-align: center;
  position: relative; /* 圓圈定位基準 */
}
/* ---- 圓圈之間的串連橫線 ----
   每一段橫線代表「這一張卡的圓心」到「下一張卡的圓心」，用 JS
   依圓圈實際渲染位置動態產生（見 main.js layoutConnectorLines），
   不用猜測的固定寬度／間距，確保卡片寬度隨螢幕寬度變動時橫線
   永遠精準對齊圓心，不會跟圓圈脫節或穿過圓圈內部 */
.service-process-connector {
  position: absolute;
  height: 1px;
  background: var(--white);
  z-index: 0;
  /* top / left / width 由 JS 動態設定 */
}
.service-process-icon {
  width: 200px;
  height: 200px;
  border-radius: var(--radius-full);
  margin: 0 auto var(--space-6);
  position: relative;
  z-index: 1; /* 蓋在橫線之上，橫線視覺上「穿過」圓圈後方 */
  /* 2026-09-12：六個步驟正式圖示（宗霖提供的 SVG，含漸層圓形背景
     ＋白色線條圖案）已經置換上去，拿掉先前灰框佔位的
     background/border（原本是因為背景色跟 --placeholder 變數
     顏色重疊才需要的權宜樣式，正式圖檔本身已經有完整視覺，
     不需要額外襯底）。object-fit:contain 確保 SVG 等比縮放、
     不因為容器是正圓形而被拉伸變形；display:block 避免 img
     預設的 inline 元素底部留白縫隙 */
  object-fit: contain;
  display: block;
}
.service-process-step-title {
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: var(--text-22);
  color: var(--ink);
  letter-spacing: var(--tracking-0);
  margin-bottom: var(--space-2);
}
.service-process-step-desc {
  font-size: var(--text-16);
  line-height: var(--leading-2);
  color: var(--grey-600);
}

/* ---- 服務旅程下方 CTA 文案（比照 Footer 的 START THE FLOW） ---- */
.service-process-cta {
  /* 2026-09-19 改版：從獨立 <section> 變成 sticky 舞台內的區塊（見
     service.html 註解）。歷程（舊做法）：section 的 padding-top 64→128
     →32→0，全部無效，因為真正的間距來自舞台 100vh 的空白。
     ⭐ 要調「六大步驟文字下緣 → START THE FLOW 上緣」的視覺間距，
     只改下面這個 margin-top（業主 2026-09-19 指定約 96px）。
     ⭐ padding-bottom 是「START THE FLOW → Footer」的間距，沿用原
     section 的 --space-32(128px)。 */
  margin-top: var(--space-24);
  padding-bottom: var(--space-32);
  /* 舞台是 flex column：.section-inner 的 margin:0 auto 會讓它縮成
     內容寬度，這裡明確給 100% 寬，左緣才會跟原本一致 */
  width: 100%;
}
.service-process-cta-heading {
  display: block;
  font-family: var(--font-en);
  font-weight: 700;
  font-size: 48px;
  line-height: 1.1;
  color: #505050;
  letter-spacing: var(--tracking-0);
  margin-bottom: var(--space-4);
}
.service-process-cta-text {
  font-size: var(--text-16);
  /* 字重降一級：500(W5) → 400(W3) */
  font-weight: 400;
  color: #505050;
  line-height: var(--leading-2);
}
/* 「聯絡我們」按鈕：跟文案的視覺 gap 要對齊上方「START THE FLOW」
   跟文案之間的 gap（.service-process-cta-heading 的
   margin-bottom: var(--space-4) = 16px）。直接複製 footer-cta-link
   同一套「margin-top:16px + padding-top歸零」手法——.cta-arrow
   本體自帶 padding:16px 8px，會讓按鈕文字視覺位置比外框往下推，
   只設 margin-top 數字，視覺 gap 會變成 margin-top + padding-top，
   跟上面 16px 對不齊，必須把 padding-top 歸零才能讓兩處 gap
   視覺一致（同一個坑，見 footer-cta-link 的說明） */
.service-process-cta-link {
  margin-top: var(--space-4);
  padding-top: 0;
  /* 2026-09-24：補上 padding-left 歸零。根因：上面複製 footer-cta-link 的手法時
     漏掉了它 2026-09-14 已修過的同一個坑——.cta-arrow 本體自帶左右 padding
     （--space-2＝8px），沒歸零左側，圓圈圈就比 START THE FLOW／內文
     （都沒有左側 padding）多縮進 8px、看起來偏右。右側 padding 不動（hover 熱區） */
  padding-left: 0;
  color: #505050;
  /* 字級/字重比照首頁「更多作品」按鈕（.cta-arrow--sm，文字部分
     沿用 .cta-arrow 本體：20px / 500），圓圈圈維持這裡原本的
     var(--icon-md) 尺寸不變 */
  font-size: var(--text-20);
  font-weight: 500;
}
.service-process-cta-link .arrow-circle {
  width: var(--icon-md);
  height: var(--icon-md);
}

/* ---- RWD：平板／手機 ---- */
/* 2026-09-28 根因修正（宗霖回報：平板版服務項目子頁面的三種服務項目
   跑版）：
   實測宗霖裝置是 iPad Pro 13（CSS 寬度 1032px）。.service-category
   桌機版兩欄寫死成絕對寬度 calc((var(--container-max) - gap) / 2)
   ＝604px（見上方基礎規則註解，是刻意用 1240px 換算的固定值，不隨
   容器縮放），兩欄＋gap 合計剛好 1240px。容器只要窄於 1240px，兩欄
   就一定溢出——1032px 時容器只有 968px，右側照片整塊被擠出螢幕外
   （實測欄寬 604px 604px，合計 1208px > 968px）。單欄化的斷點只寫
   max-width:1024px，1032px 剛好卡在這條線外側，這跟前面表單／導覽列／
   平配圖那幾次是同一類「斷點邊界卡在 1024px 外側」的問題。
   修法比照前面幾次：只新增這段 min-width:1025px 到 max-width:1099px
   的局部規則，把下方 1024px 區塊的兩條規則（單欄＋圖片排最上）原樣
   對應過來，讓這段寬度的版型跟 768~1024px 平板版一致；不去動全站
   共用的 1024px 分界，也不動 1100px 以上的桌機版 */
@media (min-width: 1025px) and (max-width: 1099px) {
  .service-category {
    grid-template-columns: 1fr;
    gap: var(--space-6);
  }
  .service-category-media { order: -1; }
}

/* 2026-09-28 根因修正（宗霖回報：平板版三種服務項目跑版，其中一項）：
   服務分類編號「01／02／03」桌機版用 position:absolute + right:100%
   浮到 .service-category-heading 容器外側的左邊，靠桌機版容器左側
   有足夠頁面留白來容納。平板（768~1099px）.section 左側留白只有
   --space-8(32px)，比編號寬度加右邊距（約 34px）還窄，實測編號
   left=-1，被推到視窗左緣外、被全站 overflow-x:clip 裁掉一點——
   跟手機版（見下方 767px 區塊 2026-09-26 那段說明）是同一個根因，
   當時只處理了 767px 以下，平板這段沒有同步。
   修法比照手機版：只在平板寬度（768~1099px）放棄「浮到容器外」的
   技巧，編號改回正常文件流、顯示在標題正上方；手機（≤767px）由
   下方既有規則負責，桌機（≥1100px）維持原本浮在左側的設計不動 */
@media (min-width: 768px) and (max-width: 1099px) {
  .service-category-number {
    position: static;
    display: block;
    right: auto;
    top: auto;
    margin-right: 0;
    margin-bottom: var(--space-2);
  }
  /* 2026-09-28 宗霖要求（平板版）：三種服務項目的照片要撐滿網頁容器
     最大寬度，並維持 4:3。
     根因：.service-category-carousel 基礎規則的 max-width 是
     calc((var(--container-max) - var(--space-8)) / 2)＝604px，那是桌機版
     「左文右圖兩欄」每欄的固定寬度；平板改單欄後這個上限還在，照片被
     限制在 604px 並置中（margin:0 auto），容器有 968px 寬卻只用了 604px，
     左右各留一大塊空白。
     修法：平板寬度把上限拿掉（none），照片寬度＝單欄容器寬度（跟文字、
     其他區塊同一條左右邊界）；aspect-ratio:4/3 是基礎規則本來就有的，
     寬度變了高度自動跟著等比放大，比例不會跑掉。手機（≤767px）與桌機
     （≥1100px）的規則不動 */
  .service-category-carousel {
    max-width: none;
  }
}

/* 2026-09-28 宗霖決定（平板版服務流程）：不釘住，改成 3×2 格狀排列，
   正常往下捲。
   歷程與根因：平板視窗高（1024～1376px）遠高於舞台內容高度（約 939px），
   舞台釘住時填不滿畫面——貼底釘住，上方露出上一區塊被捲走；貼頂釘住，
   下方空出、頁尾從那裡升上來；把舞台撐高到填滿視窗，差額就變成段落之間
   的大空白。三種都是同一個幾何限制：內容比畫面矮，多出來的高度一定要放
   在某處。桌機／手機沒有這個問題，只是因為筆電視窗高（約 830px）跟手機
   視窗高（約 844px）剛好跟舞台高度（788～865px）差不多，差額趨近 0。
   宗霖要求「不要有空白」，選定的解法：平板寬度整段不釘住（沒有舞台、
   沒有捲動驅動的橫移），六個步驟改成 3 欄 × 2 列的格狀，跟頁面其他內容
   一樣正常往下捲——所有元素在同一個文件流裡一起移動，任何間距都不可能
   因為捲動而改變，也沒有需要填補的空白。代價（宗霖已同意）：平板沒有
   左右橫移效果。桌機（≥1100px）與手機（≤767px）維持原本的釘住＋橫移。
   js/main.js 在平板寬度會清掉 JS 寫入的 inline 樣式（軌道高度、舞台 top、
   步驟寬度、位移），版面完全交給下面這段 CSS；同時只在同一列相鄰的圓圈
   之間畫串連橫線（第 3、4 個圓圈跨列，不畫線）。
   間距（全部用實測校正到跟桌機同一套數值）：
   ・上一區塊 → 中英標：中英標自己 padding-top:96px（同桌機基礎規則）
   ・中英標 → 第一列圓圈：96px（margin-bottom）＝說明文字 → START THE FLOW
   ・第一列說明 → 第二列圓圈：row-gap 96px
   ・START THE FLOW → 頁尾：128px（CTA 的 padding-bottom，不變）
   選擇器加 html[data-page="service"] 提高優先權：上方 max-width:1024px
   區塊有一條 .service-process-header{margin-bottom:0}（給手機用），
   書寫順序在這段之後，同優先權會被它蓋掉 */
@media (min-width: 768px) and (max-width: 1099px) {
  .service-process-track {
    height: auto;
  }
  .service-process-sticky {
    position: static;
    overflow: visible;
    padding-top: 0;
  }
  html[data-page="service"] .service-process-header {
    margin-bottom: var(--space-24);
  }
  .service-process-viewport {
    padding: 0;
    overflow: visible;
  }
  .service-process-steps {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: 0;
    row-gap: var(--space-24);
    will-change: auto;
  }
}

@media (max-width: 1024px) {
  .service-category {
    grid-template-columns: 1fr;
    gap: var(--space-6);
  }
  .service-category-media { order: -1; }

  /* 2026-09-27 根因修正（宗霖回報：「服務旅程」英標跟六大步驟圓圈
     的間距明顯比「步驟說明文字→START THE FLOW」的間距大，要求
     兩者統一）：
     ⚠️ 這條規則第一輪被誤寫進 max-width:767px 區塊（見該處歷史
     註解），導致 768~1024px 這段平板寬度完全沒套用到、仍吃桌機版
     的 margin-bottom:96px（--space-24），這正是宗霖回報「上一輪
     改動不明顯」的根因之一——767px 以下的手機寬度確實有改到，但
     平板寬度沒有，且手機寬度當時的目標數值本身也算錯了（見下）。
     現在移到這裡（max-width:1024px），讓手機／平板都套用同一套
     修正，並改用重新驗證過的正確數值。

     第二個根因（數值本身算錯）：桌機版 margin-bottom:96px 是配合
     .service-process-sticky 的 padding-top:96px 疊加設計的視覺
     間距。上一輪只把 margin-bottom 降到 48px，並記載「Playwright
     實測 gap 精準等於 96px」——重新用 spout_testkit 的 settle()
     確實捲動到 sticky 真正卡住定位的狀態後再量測（不是讀取 sticky
     生效前、icon 還在自然文件流位置時的初始值），實測結果是
     144px，不是 96px：144 = 48(margin-bottom) + 96(sticky 的
     padding-top)，兩段間距是疊加關係，不是互相抵銷，上一輪的
     「96px」結論來自量測時機錯誤。
     要把總間距降到跟基準值一致的 96px，margin-bottom 必須整個
     歸零，讓間距完全由 .service-process-sticky 的 padding-top:96px
     單獨負責（那段 padding 是功能性間距，用來避免 sticky 卡住時
     標題被固定 Header 遮住，不能動，見該處註解）。
     用 settle() 重新驗證：margin-bottom:0 時，390px／768px／1024px
     三個寬度英標→圓圈實測 gap 皆精準等於 96px，與基準值一致；
     1440px 桌機版仍維持原本的 192px（margin-bottom:96px + sticky
     padding-top:96px 疊加），未受影響。 */
  .service-process-header {
    margin-bottom: 0;
  }
}

@media (max-width: 767px) {
  .service-intro-track {
    height: auto;
  }
  /* 2026-09-27 根因修正（宗霖要求：「讓想法，匯流成形」中標跟上方
     「服務項目」中標的間距要調成 65px，原本明顯偏小）：
     「服務項目」中標（.page-title）到「讓想法，匯流成形」
     （.service-intro-title）之間的視覺間距，主要由這裡的
     .service-intro-sticky padding-top 決定——這個容器手機版拿掉
     了桌機版的 position:fixed（改回 position:static，交給一般
     文件流排版，理由見上方 JS 註解：手機版拿掉 sticky 長軌道
     機制），padding-top 直接把裡面的 SVG 弧線跟標題往下推，是
     唯一實際影響這段間距的屬性。
     原本 padding-top 是 var(--space-16)(64px)，實測間距只有 32px；
     用 Playwright 實測反推，把 padding-top 加大到 97px，精準對齊
     65px 的目標間距（不是設計 token，是專門為了達成這個目標間距
     反推出來的校正值，兩者不是 1:1 對應關係，因為中間還經過
     .service-intro-content 內部 .service-intro-title 的
     margin-bottom 等其他既有間距疊加，未來如果要再調整，需要
     重新用實測反推，不能只看這個數字的差值去線性外推） */
  .service-intro-sticky {
    position: static;
    height: auto;
    overflow: visible;
    padding-top: 97px;
  }
  .service-intro-spacer { display: none; }
  .service-flow-lines { height: 260px; }
  /* 2026-09-27 根因修正（宗霖回報：匯流線頂部要切齊 (SERVICE) 英標
     的頭，尾部維持不動，整條線等於拉長，只是起點不同；線的粗細
     也要調細一級）：
     這條 SVG path（.service-flow-line）跟座標本身（viewBox="0 0
     1240 700"，四分之一圓弧 d="M 0,3.4 A 620,620 ...）是全站
     共用的同一份 HTML，桌機版也在用，不能直接改 path 的座標數值
     —— 那樣會連動影響已定案的桌機版視覺。改用 CSS transform 在
     只有手機版生效的地方達成「頂部延伸、底部不動」的效果。
     ⚠️ 第一次嘗試踩坑：transform-origin 設成 `center bottom`
     這個關鍵字，本以為會用「線的視覺終點」當錨點，但實測發現
     `bottom` 指的是 svg 元素自己的 border-box 底部（螢幕座標
     584px），跟 path 實際繪製的終點（螢幕座標 556px）中間有將近
     28px 的落差（因為 viewBox 高度 700 比 path 實際到達的 623.4
     更高，留了一段空白），縮放結果因此連底部端點都跟著位移了
     26px 左右，完全不符合「尾部不動」的要求。
     修法：直接用精確的 px 值指定 transform-origin，把錨點設在
     path 實際終點所在的位置（相對 svg 容器頂部 231.5px），而不是
     用 `bottom` 這種依賴元素框線、不是依賴實際內容位置的關鍵字。
     用這個精確錨點反推 scaleY，讓頂部端點精準對齊 (SERVICE)
     英標頂部，同時底部端點完全不受影響 */
  .service-flow-lines {
    /* 2026-09-27 根因修正（宗霖回報：匯流線沒有左右置中）：
       基礎規則（未覆寫時）用 transform: translateX(-50%) 搭配
       left:50% 做水平置中，但這裡手機版新增 scaleY(1.896) 時，
       直接整個覆蓋了 transform 屬性，等於把 translateX(-50%) 一起
       蓋掉，容器左邊界因此卡在 left:50% 沒有再往左移回去，導致
       整條線大幅偏右。兩個 transform 效果要疊加，必須寫在同一個
       transform 宣告裡，不能分開覆蓋。 */
    transform-origin: center 231.5px;
    transform: translateX(-50%) scaleY(1.896);
  }
  /* vector-effect:non-scaling-stroke（基礎規則已設定）讓 stroke-width
     不受外層 transform:scaleY 縮放影響，維持螢幕上恆定的視覺粗細
     ——這裡不需要反推縮放前的補償值，直接設定最終想要呈現的粗細
     即可。原本 1.5px，細一級改成 1px */
  .service-flow-line {
    stroke-width: 1;
  }
  /* 2026-09-26 宗霖要求：手機版「讓想法，匯流成形」整段文字取消
     置中、改成置左對齊，並取消軟換行（讓文字依容器寬度自然換行，
     不再照桌機版手動排版的斷點換行）。
     根因：.service-intro-inner 桌機版是 text-align:center（配合
     兩側對稱的 SVG 流線動畫設計），.service-intro-line 則是把每句
     內文用獨立 <span> 包成 display:block，模擬「手動安排在哪裡
     斷行」的效果——這兩個桌機版的排版決策，在手機版窄螢幕下並不
     適用：置中對齊在窄欄位下閱讀動線較差，手動斷行的每一句在窄
     螢幕可能還是超出容器寬度、又被迫二次自動換行，兩種换行機制
     疊在一起，行距/斷點都不好看。
     修法：.service-intro-inner 手機版改回預設 text-align:left；
     .service-intro-line 拿掉 display:block，改回 inline（文字
     自然接續、由瀏覽器依容器寬度決定斷行位置，不再是各自獨立的
     一行） */
  .service-intro-inner { text-align: left; }
  .service-intro-line {
    display: inline;
    margin-bottom: 0;
  }
  /* 2026-09-26 第二輪修正（宗霖回報：上一輪把整段文字都改成置左，
     但「讓想法，匯流成形」這句中標跟下面的英標 "Where Ideas Flow
     into Form." 應該要置中對齊螢幕容器，置左是錯的；下方三行敘述
     維持置左不動）：
     根因：.service-intro-title／.service-intro-subtitle 跟三行
     內文（.service-intro-desc）共用同一個父容器
     .service-intro-content，text-align 是會繼承的 CSS 屬性，上一輪
     把父層 .service-intro-inner 改成 text-align:left 後，底下所有
     子元素（含標題、英標、內文）全部一起被帶成置左，沒有意識到
     宗霖只是想取消內文的軟換行跟置中，並不是要標題／英標也跟著
     變置左。
     修法：標題跟英標各自覆蓋回 text-align:center，內文
     （.service-intro-desc，連帶底下的 .service-intro-line）不動、
     繼續繼承父層的 text-align:left，兩者各自獨立不衝突 */
  .service-intro-title,
  .service-intro-subtitle {
    text-align: center;
  }
  /* 2026-09-26 宗霖要求：「讓想法，匯流成形」中標字級縮小。
     根因：.service-intro-title 是業主先前指定的固定 32px（不是
     響應式 clamp），套用首頁 #recognition 中標同一套規格，手機版
     從未有斷點覆蓋，390px 窄螢幕下 32px 中文字顯得偏大。這裡比照
     全站其他中標在手機版慣用的縮小幅度，改成 26px */
  .service-intro-title { font-size: 26px; }
  .service-process-header {
    flex-direction: column;
    align-items: flex-start;
  }
  /* 2026-09-26 宗霖要求：拿掉手機版原生橫向滑動降級，恢復跟桌機版
     一致的「捲動驅動水平位移」效果（.service-process-track／
     .service-process-sticky／.service-process-viewport／
     .service-process-steps／.service-process-step 全部改回繼承
     桌機版基礎規則，不再有手機版專屬覆蓋）。
     根因：原本這裡刻意讓手機版跳過 sticky+JS 位移，改用
     overflow-x:auto 原生橫向滑動，理由是避免跟垂直捲動手勢衝突。
     但宗霖實際體驗後發現，原生滑動缺乏「還有更多步驟」的視覺
     引導，往下滑過這個區塊時很容易誤以為六步驟只有第一步、後面
     直接接 CTA，等於後面五步實質上被忽略——這正是原本想避免的
     「使用者看不到其餘步驟」問題又以另一種方式發生。宗霖確認要
     恢復桌機版的捲動驅動效果，JS 端 shouldEnableDesktopScrub()
     已同步改成全斷點恆為 true（見 js/main.js 同一天的修正），
     這裡拿掉對應的 CSS 降級覆蓋，讓手機版真正套用同一套機制 */
}

/* ==========================================================================
   服務項目子頁面（service.html）— 文字顏色統一覆蓋（2026-09-12）
   ========================================================================== */
/* 業主指定：service.html 全頁文字（除了 footer／navbar／水滴選單／
   英標之外）統一改成 #505050。用 html[data-page="service"] 限定
   scope，只影響這一頁，不直接修改共用規則本身——.page-title 是
   全站子頁面共用的標題元件（about.html／contact.html 等都在用），
   直接改 .page-title 的 color 會連帶波及其他子頁面，違反
   handoff.md 記錄過的「改共用 class 前先盤點」教訓。
   排除範圍（維持原色不動）：
   - .page-label（頁首英標 "( SERVICE )"）
   - .service-intro-subtitle（Hero 匯流動畫英標）
   - .service-category-title-en（服務分類英標，如 "BRAND DESIGN"）
   - .service-process-title-en（服務旅程英標 "SERVICE PROCESS"）
   - footer／navbar／水滴選單：本來就不在 service.html 這幾個
     區塊的選擇器範圍內，不需要額外排除 */
html[data-page="service"] .page-title,
html[data-page="service"] .service-intro-title,
html[data-page="service"] .service-intro-desc,
html[data-page="service"] .service-category-number,
html[data-page="service"] .service-category-title,
html[data-page="service"] .service-category-title-en,
html[data-page="service"] .service-category-tags li,
html[data-page="service"] .service-category-desc-lead,
html[data-page="service"] .service-category-desc p:not(.service-category-desc-lead),
html[data-page="service"] .service-process-title,
html[data-page="service"] .service-process-step-title,
html[data-page="service"] .service-process-step-desc {
  color: #505050;
}

/* ==========================================================================
   團隊介紹（列表頁 team.html／個人專屬頁樣板 team-member.html）— 預留架構（2026-09-20）
   顧問（E-E-A-T「Expertise 專業度」）建議新增。目前只有版面骨架與佔位，成員內容尚未提供。
   ⭐ 全部使用專屬前綴（.breadcrumb／.team-*），不會影響其他頁面；顏色、字級、間距、圓角全部沿用既有 token。
   視覺語言對齊作品卡片：.team-card-photo ＝ .work-thumb（灰底圓角），只是比例改成人像的 4:5。
   顏色注意：這站的 --ink 是 #505050、--grey-800 實際約 #737373（見 handoff v42），文字一律用 --ink，
   不用灰階 token 做小字，避免疊在 --grey-300 底上太淡。
   ========================================================================== */
/* ---- 麵包屑（目前只有團隊頁使用；全站還沒有麵包屑，若日後全站導入可沿用這組 class）---- */
.breadcrumb { margin-top: var(--space-4); }
.breadcrumb ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  font-size: var(--text-14);
  line-height: var(--leading-2);
  color: var(--ink);
}
.breadcrumb li + li::before { content: '\203A'; margin-right: var(--space-2); }
.breadcrumb a { text-decoration: underline; text-underline-offset: 3px; }
.breadcrumb a:hover { opacity: var(--state-hover-opacity); }
.breadcrumb [aria-current="page"] { font-weight: 700; }

/* ---- 預留期間的可見提示（啟用時由 toggle_team_nav.py 加上 hidden 隱藏）---- */
.team-reserved-note,
.press-reserved-note,
.credentials-reserved-note,
.testimonials-reserved-note {
  margin-bottom: var(--space-8);
  padding: var(--space-4) var(--space-6);
  border: 1px dashed var(--ink);
  border-radius: var(--radius-md);
  font-size: var(--text-14);
  line-height: var(--leading-3);
  color: var(--ink);
}
.team-reserved-note[hidden],
.press-reserved-note[hidden],
.credentials-reserved-note[hidden],
.testimonials-reserved-note[hidden] { display: none; }
.team-reserved-note code,
.press-reserved-note code,
.credentials-reserved-note code,
.testimonials-reserved-note code { font-family: monospace; }

/* ---- 列表頁 ---- */
.team-intro {
  max-width: 640px;
  margin-bottom: var(--space-16);
  font-size: var(--text-16);
  line-height: var(--leading-3);
  color: var(--ink);
}
.team-grid {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-16) var(--space-8);
}
.team-card-link { display: block; transition: opacity 0.3s var(--ease-water); }
.team-card-link:hover { opacity: var(--state-hover-opacity); }
.team-card-photo {
  width: 100%;
  aspect-ratio: 4 / 5;
  background: var(--grey-400);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.team-card-photo img { width: 100%; height: 100%; object-fit: cover; }
.team-card-meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-top: var(--space-4);
}
.team-card-name { font-weight: 700; font-size: var(--text-18); line-height: var(--leading-2); color: var(--ink); }
.team-card-name-en { font-family: var(--font-en); font-weight: 400; font-size: var(--text-14); letter-spacing: var(--tracking-xs); }
.team-card-title { font-size: var(--text-14); line-height: var(--leading-2); color: var(--ink); }
.team-card-tagline { font-size: var(--text-14); line-height: var(--leading-3); color: var(--ink); }

/* ---- 個人專屬頁 ---- */
.team-member-name-en { font-family: var(--font-en); font-weight: 400; font-size: var(--text-20); letter-spacing: var(--tracking-xs); }
.team-member-role { font-size: var(--text-16); line-height: var(--leading-2); color: var(--ink); }
.team-member-layout {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--space-16);
  align-items: start;
}
.team-member-photo-ph {
  width: 100%;
  aspect-ratio: 4 / 5;
  background: var(--grey-400);
  border-radius: var(--radius-md);
}
.team-member-photo img { width: 100%; border-radius: var(--radius-md); }
.team-member-tagline {
  margin-bottom: var(--space-12);
  font-weight: 700;
  font-size: var(--text-20);
  line-height: var(--leading-2);
  color: var(--ink);
}
.team-member-block + .team-member-block { margin-top: var(--space-12); }
.team-member-block h2 {
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--ink);
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: var(--text-18);
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
}
.team-member-text { font-size: var(--text-16); line-height: var(--leading-3); color: var(--ink); }
.team-credentials { list-style: none; display: grid; gap: var(--space-4); }
.team-credential { display: grid; gap: var(--space-1); font-size: var(--text-14); line-height: var(--leading-3); color: var(--ink); }
.team-credential-name { font-weight: 700; font-size: var(--text-16); }
.team-facts { display: grid; gap: var(--space-3); }
.team-facts > div { display: grid; grid-template-columns: 8em 1fr; gap: var(--space-4); font-size: var(--text-16); line-height: var(--leading-3); color: var(--ink); }
.team-facts dt { font-weight: 700; }
.team-list { list-style: disc; padding-left: 1.2em; display: grid; gap: var(--space-2); font-size: var(--text-16); line-height: var(--leading-3); color: var(--ink); }
.team-list a { text-decoration: underline; text-underline-offset: 3px; }
.team-list a:hover { opacity: var(--state-hover-opacity); }
.team-social { list-style: none; display: flex; flex-wrap: wrap; gap: var(--space-4); margin-top: var(--space-12); font-size: var(--text-14); }
.team-social a { text-decoration: underline; text-underline-offset: 3px; color: var(--ink); }

@media (max-width: 1024px) {
  .team-member-layout { gap: var(--space-8); }
}
@media (max-width: 767px) {
  .team-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-8) var(--space-4); }
  .team-member-layout { grid-template-columns: 1fr; }
  .team-member-photo-ph { max-width: 320px; }
  .team-facts > div { grid-template-columns: 1fr; gap: var(--space-1); }
}

/* ==========================================================================
   媒體報導／專業認證／客戶見證（press.html、credentials.html、testimonials.html）
   ＋作品頁對應區塊（work-detail.html）— 預留架構（2026-09-20）
   顧問 E-E-A-T「Authoritativeness 權威度」「Trustworthiness 可信度」建議新增。目前只有版面骨架與佔位。
   ⭐ 全部使用專屬前綴（.press-*／.credentials-*／.testimonials-*／.testimonial-*／.work-eeat-*），
     不會影響其他頁面；顏色、字級、間距、圓角全部沿用既有 token。
   ⭐ .breadcrumb、預留提示（.press-／.credentials-／.testimonials-reserved-note）沿用上方團隊介紹那一組規則。
   顏色注意：這站的 --ink 是 #505050（見 handoff v42），文字一律用 --ink，不用灰階 token 做小字。
   ========================================================================== */
/* ---- 三個預留頁共用的導言 ---- */
.press-intro,
.credentials-intro,
.testimonials-intro {
  max-width: 640px;
  margin-bottom: var(--space-16);
  font-size: var(--text-16);
  line-height: var(--leading-3);
  color: var(--ink);
}

/* ---- 媒體報導列表頁 ---- */
.press-list { list-style: none; display: grid; gap: var(--space-12); }
.press-item {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: var(--space-8);
  padding-bottom: var(--space-12);
  border-bottom: 1px solid var(--ink);
}
.press-item--text-only { grid-template-columns: minmax(0, 1fr); }
.press-item-media {
  width: 100%;
  aspect-ratio: 3 / 4;
  background: var(--grey-400);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.press-item-media img { width: 100%; height: 100%; object-fit: cover; }
.press-item-body { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.press-item-source { font-weight: 700; font-size: var(--text-14); line-height: var(--leading-2); letter-spacing: var(--tracking-xs); color: var(--ink); }
.press-item-title { font-weight: 700; font-size: var(--text-22); line-height: var(--leading-2); color: var(--ink); }
.press-item-date { font-family: var(--font-en); font-size: var(--text-14); line-height: var(--leading-2); letter-spacing: var(--tracking-xs); color: var(--ink); }
.press-item-summary { max-width: 640px; font-size: var(--text-16); line-height: var(--leading-3); color: var(--ink); }
.press-item-links { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-6); margin-top: var(--space-3); font-size: var(--text-14); line-height: var(--leading-2); }
.press-item-links a,
.testimonial-foot a,
.work-eeat-link { text-decoration: underline; text-underline-offset: 3px; color: var(--ink); }
.press-item-links a:hover,
.testimonial-foot a:hover,
.work-eeat-link:hover { opacity: var(--state-hover-opacity); }

/* ---- 客戶見證列表頁 ---- */
.testimonials-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4) var(--space-8);
  margin-bottom: var(--space-12);
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--ink);
}
.testimonials-rating { font-size: var(--text-16); line-height: var(--leading-2); color: var(--ink); }
.testimonials-rating-score { font-family: var(--font-en); font-size: var(--text-32); letter-spacing: var(--tracking-xs); }
.testimonials-grid {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--space-8);
}
.testimonial-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-6);
  background: var(--white);
  border-radius: var(--radius-lg);
}
.testimonial-card-head { display: flex; align-items: center; gap: var(--space-3); }
.testimonial-avatar { flex: 0 0 var(--space-12); width: var(--space-12); height: var(--space-12); border-radius: var(--radius-full); background: var(--grey-400); }
.testimonial-card-who { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1); min-width: 0; }
.testimonial-name { font-weight: 700; font-size: var(--text-16); line-height: var(--leading-2); color: var(--ink); }
.testimonial-tag { padding: var(--space-1) var(--space-3); border: 1px solid var(--ink); border-radius: var(--radius-full); font-size: var(--text-14); line-height: var(--leading-2); color: var(--ink); }
.testimonial-quote { font-size: var(--text-16); line-height: var(--leading-3); color: var(--ink); }
.testimonial-foot { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-2) var(--space-4); margin-top: auto; font-size: var(--text-14); line-height: var(--leading-2); color: var(--ink); }

/* ---- 作品案例詳細頁：本案例的客戶見證／曾獲媒體報導（work-detail.html，預設隱藏）----
   ⚠️ 靜態原型所有作品共用同一個樣板，做不出「這個案例專屬」的內容，所以兩個區塊永遠帶 hidden；
   WP 化後依該作品的關聯欄位有值才輸出（沒有值整段不輸出，不留空標題）。 */
.work-eeat-section {
  background: var(--white);
  padding: var(--space-16) var(--space-12);
  border-top: 1px solid var(--grey-500);
}
.work-eeat-section[hidden] { display: none; }
.work-eeat-inner { max-width: var(--container-max); margin: 0 auto; }
.work-eeat-heading {
  margin-bottom: var(--space-8);
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: clamp(24px, 2.6vw, 32px);
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
}
.work-eeat-quote { max-width: 720px; }
.work-eeat-quote blockquote p { font-size: var(--text-20); line-height: var(--leading-3); color: var(--ink); }
.work-eeat-quote figcaption { margin-top: var(--space-4); font-size: var(--text-14); line-height: var(--leading-3); color: var(--ink); }
.work-eeat-tag { display: inline-block; margin-right: var(--space-2); padding: var(--space-1) var(--space-3); border: 1px solid var(--ink); border-radius: var(--radius-full); }
.work-eeat-press-list { list-style: none; display: grid; gap: var(--space-8); max-width: 720px; }
.work-eeat-press-item { display: flex; flex-direction: column; gap: var(--space-2); }
.work-eeat-press-source { font-weight: 700; font-size: var(--text-14); line-height: var(--leading-2); letter-spacing: var(--tracking-xs); color: var(--ink); }
.work-eeat-press-title { font-weight: 700; font-size: var(--text-18); line-height: var(--leading-2); color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.work-eeat-press-title:hover { opacity: var(--state-hover-opacity); }
.work-eeat-press-date { font-family: var(--font-en); font-size: var(--text-14); letter-spacing: var(--tracking-xs); color: var(--ink); }
.work-eeat-press-summary { font-size: var(--text-16); line-height: var(--leading-3); color: var(--ink); }
.work-eeat-more { margin-top: var(--space-8); font-size: var(--text-14); line-height: var(--leading-2); }

/* ---- 專業認證頁（credentials.html）---- */
.credentials-list { list-style: none; display: grid; max-width: 880px; }
.credentials-item {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.4fr) minmax(0, 1fr);
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--ink);
  font-size: var(--text-16);
  line-height: var(--leading-2);
  color: var(--ink);
}
.credentials-item:first-child { border-top: 1px solid var(--ink); }
.credentials-item-name { font-weight: 700; }
.credentials-item-issuer { font-size: var(--text-14); }

@media (max-width: 1024px) {
  .work-eeat-section { padding: var(--space-12) var(--space-8); }
}
@media (max-width: 767px) {
  .press-item { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); padding-bottom: var(--space-8); }
  .press-item-media { max-width: 160px; }
  .testimonials-grid { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
  .work-eeat-section { padding: var(--space-12) var(--space-6); }
  .credentials-item { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); }
}

/* ==========================================================================
   聯絡表單：上傳附件（首頁與 contact.html 共用同一份表單，2026-09-21 新增）
   ⭐ 使用專屬前綴 .attachment-*，顏色／字級／間距／圓角全部沿用既有 token。
   ⭐ 漸進增強：沒有 JS 時顯示原生 <input type="file">；JS 加上 .is-enhanced 後，
     原生 input 只做視覺隱藏（仍留在表單裡、仍可被鍵盤與輔助科技取用），改顯示自訂按鈕、清單與拖曳框。
   ========================================================================== */
.attachment-field { align-items: flex-start; }
/* 2026-09-27 根因修正（宗霖回報：全站「上傳附件」四個字要切齊
   旁邊上傳框的上緣，目前明顯偏低，桌機/平板/手機三個斷點都要改）：
   跟先前「需求描述」四個字偏低是同一套根因（見 .form-field--textarea
   label 上方那段記錄）——.attachment-field > label 繼承
   .form-field--inline label 的 display:flex; align-items:center，
   讓文字在 label 自身 24px 高的 line-box 內垂直置中，這是設計給
   單行 input 並排用的置中效果，不是「切齊上緣」；疊加原本的
   padding-top（16px，見下面 .is-enhanced 那條，目的是對齊框內
   「選擇檔案」按鈕的垂直中心，本來就不是為了切齊上緣設計的），
   兩者相加，用 Range.getClientRects() 精確量測 glyph 頂部，實測
   1032px／1440px 都是 20px 落差。
   修法比照需求描述：align-items 改成 flex-start、padding-top 歸零，
   只留下 line-height(24px) 比 font-size(16px) 在 line-box 內置中
   造成、無法避免也難以肉眼察覺的 4px 微幅殘留（改用 line-height:1
   可完全消除，但會讓多行內容或不同字體渲染的行高不一致，這裡
   維持原本的取捨，不做這個更動）。
   下面 .is-enhanced 那條「配合框 16px 內距對齊按鈕垂直中心」的
   padding-top:16px 規則，因為目標對齊方式已經改變（切齊上緣，
   不再是對齊按鈕垂直中心），一併歸零，見該處說明 */
.attachment-field > label {
  align-items: flex-start;
  padding-top: 0;
}
/* 目標對齊方式已改成「切齊上緣」，不再需要配合框的內距把標籤往下
   推、對齊按鈕垂直中心，原本的 padding-top:16px 拿掉 */
.attachment-field.is-enhanced > label { padding-top: 0; }
.attachment-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}
.attachment-trigger { display: none; gap: var(--space-2); cursor: pointer; }
/* 「＋」用 CSS 畫，不用文字符號：字形（尤其和中文混排時）的視覺中心會比文字低約 1.25–1.5px（實測），
   而且無法用 line-height 精準修正；畫出來的圖示由 flex（.tag-pill 已是 align-items:center）置中，位置固定、不受字型影響。 */
.attachment-trigger-icon { position: relative; flex: 0 0 auto; width: 8px; height: 8px; }
.attachment-trigger-icon::before,
.attachment-trigger-icon::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  background: currentColor;
}
.attachment-trigger-icon::before { width: 100%; height: 1.5px; transform: translate(-50%, -50%); }
.attachment-trigger-icon::after { width: 1.5px; height: 100%; transform: translate(-50%, -50%); }
.attachment-trigger:hover { background: var(--ink); border-color: var(--ink); color: var(--white); }
.attachment-field.is-enhanced .attachment-trigger { display: inline-flex; }
.attachment-field.is-enhanced .attachment-input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
.attachment-field.is-enhanced .attachment-body {
  position: relative;
  width: 100%;
  padding: var(--space-4);
  border: 1px dashed var(--grey-600);
  border-radius: var(--radius-lg);
  transition: border-color 0.3s var(--ease-water), background-color 0.3s var(--ease-water);
}
.attachment-field.is-enhanced .attachment-body.is-dragover {
  border-style: solid;
  border-color: var(--ink);
  background: rgba(255, 255, 255, 0.4);
}
.attachment-hint { font-size: var(--text-14); line-height: var(--leading-2); color: var(--ink); }
.attachment-list { list-style: none; width: 100%; min-width: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.attachment-list:empty { display: none; }
.attachment-item {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--white);
  border-radius: var(--radius-md);
  font-size: var(--text-14);
  line-height: var(--leading-2);
  color: var(--ink);
}
/* ⚠️ 超長檔名不能撐寬表單：overflow:hidden＋min-width:0 只讓「這個元素自己」可以縮小，
   它的文字寬度仍會被外層 grid／flex 當成「最小內容寬度」往上傳，整張表單（與頁面）就被撐出橫向捲軸
   （實測 1100px 多 96px、手機多 139px）。width:0 讓它的固有寬度歸零，再由 flex:1 撐滿剩餘空間。 */
.attachment-name { flex: 1 1 0; width: 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attachment-size { flex-shrink: 0; font-family: var(--font-en); letter-spacing: var(--tracking-xs); }
.attachment-remove {
  position: relative;
  flex-shrink: 0;
  width: var(--space-6);
  height: var(--space-6);
  border-radius: var(--radius-full);
  cursor: pointer;
  transition: background-color 0.3s var(--ease-water);
}
.attachment-remove:hover { background: var(--grey-200); }
.attachment-remove::before,
.attachment-remove::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--space-3);
  height: 1px;
  background: var(--ink);
}
.attachment-remove::before { transform: translate(-50%, -50%) rotate(45deg); }
.attachment-remove::after { transform: translate(-50%, -50%) rotate(-45deg); }
.attachment-error { margin-top: 0; white-space: pre-line; }
.attachment-status {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
@media (max-width: 767px) {
  /* 手機：其他「標籤在左」的欄位維持並排，但附件框需要整行寬度放檔名，改成標籤在上、框在下 */
  .attachment-field { flex-direction: column; gap: var(--space-2); }
  .attachment-field > label,
  .attachment-field.is-enhanced > label { padding-top: 0; }
  .attachment-body { width: 100%; }
}

/* ==========================================================================
   首頁：服務項目（簡易版）三張卡片（2026-09-21 新增）
   ⭐ 專屬前綴 .services-*／.service-card*，顏色／字級／間距／圓角全部沿用既有 token。
   ⭐ 純 CSS：hover／focus-visible 展開介紹；沒有 hover 的裝置（@media (hover: none)）一律顯示介紹。
   ⭐ 2026-09-21：卡片右上角的圓圈箭頭已拿掉（宗霖指示）；整張卡片本身仍是連結。
   ⭐ 照片上的白字需要深色遮罩才有足夠對比：遮罩用 rgba(28,28,28,…)（＝ --grey-900 #1c1c1c 加透明度，token 無法帶透明度）。
   ========================================================================== */
/* 中英標「一橫一直」：直排英標（比照 .about-label／.page-label）＋橫排中標（比照 .about-tagline／.page-title 的字級）。
   ≤1024px 英標改橫排，與全站其他英標的窄螢幕行為一致（見 @media (max-width: 1024px) 內的 .about-label 等）。
   CTA 用 flex 與「中標」垂直置中（align-items:center）、靠右（justify-content:space-between）。 */
.services-header { margin-bottom: var(--space-16); }
.services-label {
  /* 2026-09-25 補漏（宗霖回報服務項目英標在平板/手機沒有變直的）：
     這是跟 .about-label／.page-label／.contact-label 同一種問題，
     但 .services-label 是首頁「服務項目」區塊專用的獨立 class，
     上一輪只改了前三個、漏掉這個——原本這裡在 ≤1024 被覆蓋成
     writing-mode:horizontal-tb，跟其他英標一樣拿掉即可，不需要
     額外的排版邏輯 */
  writing-mode: vertical-rl;
  font-family: var(--font-en);
  font-size: var(--text-16);
  letter-spacing: var(--tracking-0);
  color: var(--grey-700);
}
.services-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  /* 英標底→中標頂的視覺間距對齊首頁 FAQ 標頭（實測 25px）。11px 是實測值，不在間距 token 內
     （同 .about-tagline 的 87px 是實測校正值的既有作法）；改字級或英標時要重新量測，不要憑感覺調 */
  margin-top: 10px;
}
.services-title {
  /* 中文字形的視覺中心比行盒中心高約 0.75px，flex 置中後 CTA 圓圈會比中標墨跡低 0.75px（實測；FAQ 標頭靠 JS
     動態校正才是 0）。整數像素下移 1px（不用小數，避免圓圈邊線在 1x 螢幕模糊），偏差降到 −0.25px；
     margin-top 因此少 1px（11→10）保持與 FAQ 相同的英標／中標間距 */
  position: relative;
  top: 1px;
  font-family: var(--font-cn);
  font-weight: 700;
  font-size: clamp(26px, 3vw, 38px);
  line-height: 1.35;
  letter-spacing: var(--tracking-xs);
  color: var(--ink);
}
.service-cards {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6);
}
.service-card {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  isolation: isolate;
  border-radius: var(--radius-lg);
  background: var(--grey-400);
  color: var(--white);
}
.service-card-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.8s var(--ease-water);
}
/* 底部漸層：任何狀態下標題都清楚；hover 時再整張加深（::after） */
.service-card::before,
.service-card::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.service-card::before { background: linear-gradient(to top, rgba(28, 28, 28, 0.72) 0%, rgba(28, 28, 28, 0.25) 45%, rgba(28, 28, 28, 0) 70%); }
.service-card::after { background: rgba(28, 28, 28, 0.58); opacity: 0; transition: opacity 0.5s var(--ease-water); }
.service-card-body {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  padding: var(--space-6);
}
.service-card-number { font-family: var(--font-en); font-size: var(--text-16); line-height: var(--leading-2); letter-spacing: var(--tracking-xs); }
.service-card-title { font-family: var(--font-cn); font-weight: 700; font-size: var(--text-24); line-height: var(--leading-2); letter-spacing: var(--tracking-xs); }
.service-card-title-en { font-family: var(--font-en); font-size: var(--text-14); line-height: var(--leading-2); letter-spacing: var(--tracking-xs); }
/* 介紹文字：grid 0fr → 1fr 是「高度從 0 展開到內容高度」最穩的純 CSS 做法（不必猜高度數字） */
.service-card-desc-wrap { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.5s var(--ease-water); }
.service-card-desc {
  display: block;
  min-height: 0;
  overflow: hidden;
  padding-top: 0;
  font-size: var(--text-16);
  line-height: var(--leading-3);
  opacity: 0;
  transition: opacity 0.4s var(--ease-water), padding-top 0.5s var(--ease-water);
}
.service-card:hover .service-card-img,
.service-card:focus-visible .service-card-img { transform: scale(1.05); }
.service-card:hover::after,
.service-card:focus-visible::after { opacity: 1; }
.service-card:hover .service-card-desc-wrap,
.service-card:focus-visible .service-card-desc-wrap { grid-template-rows: 1fr; }
.service-card:hover .service-card-desc,
.service-card:focus-visible .service-card-desc { padding-top: var(--space-4); opacity: 1; }
/* 介紹文字會壓在照片上、且可能是「一律顯示」的情境（觸控裝置；以及 ≤767px 卡片改成橫式裁切、文字容易剛好壓在照片最亮處）：
   底部遮罩必須更重。⚠️ 白字對比度是實測調出來的（量文字後方背景的亮度，目標 WCAG AA ≥ 4.5:1），
   改遮罩的數字前後要重新量測，不要憑肉眼調。 */
@media (hover: none), (max-width: 767px) {
  .service-card::before { background: linear-gradient(to top, rgba(28, 28, 28, 0.92) 0%, rgba(28, 28, 28, 0.84) 45%, rgba(28, 28, 28, 0.55) 75%, rgba(28, 28, 28, 0.2) 100%); }
}
/* 沒有 hover 的裝置（觸控）：永遠顯示介紹，否則使用者看不到內容 */
@media (hover: none) {
  .service-card::after { opacity: 0.3; }
  .service-card-desc-wrap { grid-template-rows: 1fr; }
  .service-card-desc { padding-top: var(--space-4); opacity: 1; }
}
/* 從服務項目頁的錨點進來時，避免分類標題貼齊視窗頂端 */
.service-category { scroll-margin-top: var(--space-24); }
@media (max-width: 1023px) {
  /* 三欄並排時每張卡片只有約 220px 寬，3:4 會太矮、照片被文字吃掉，改高一點（≤767px 另外改成橫式 4:3，見下） */
  .service-card { aspect-ratio: 2 / 3; }
  .service-card-body { padding: var(--space-4); }
  .service-card-title { font-size: var(--text-22); }
  .service-card-desc { font-size: var(--text-14); }
}
@media (max-width: 767px) {
  .services-header { margin-bottom: var(--space-12); }
  .service-cards { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
  .service-card { aspect-ratio: 4 / 3; }
  .service-card-body { padding: var(--space-6); }
  .service-card-title { font-size: var(--text-24); }
  .service-card-desc { font-size: var(--text-16); }
}

/* ==========================================================================
   聯絡表單（首頁與 contact.html 共用 .form-field--inline，兩處同步生效）
   ========================================================================== */
@media (max-width: 1024px) {
  /* 2026-09-26 宗霖回報：手機版表單「稱呼／公司／電話／Email」四個
     純文字欄位的輸入框太短，要求把起點（頭）往左延伸，底線右邊界
     （尾）維持不動。
     根因：.form-field--inline label 全站固定 180px（見基礎規則的
     設計說明：這個固定寬度是刻意的，目的是讓四行底線起點對齊在
     同一條垂直線上，不受各欄位標籤文字長短影響），但最長的標籤
     文字「電子郵件（E-mail）」實測只需要約 161px，180px 比實際
     需要的寬度多留了將近 20px 的空白，輸入框因此比視覺上「應該」
     能延伸到的起點更靠右，看起來偏短。
     2026-09-26 第二輪：宗霖確認第一次改到 165px 還不夠長，要求
     「輸入框或底線都還可以再更長」。因為 .input-line-wrap／input
     是撐滿 label 縮小後剩下的可用空間（見下方 .input-line-wrap
     的設計說明），縮小 label 寬度本身就會同時讓輸入框跟底線一起
     變長，是同一個修正、不需要分開處理兩個地方。
     這次直接貼近最長標籤「電子郵件（E-mail）」的自然寬度 161px，
     只留 1px 緩衝（已用 Playwright 逐一測試 163px／162px／161px／
     160px 四組數值，確認 161px 時六個標籤都還沒有換行，160px 才
     開始逼近極限）——161px 是目前技術上能做到的最短寬度，再更小
     連最長的「電子郵件（E-mail）」都會被迫換行成兩行，反而讓
     這一欄的標籤／輸入框垂直對齊被破壞。
     桌機版（>1024px）維持原本的 180px，這輪只鎖定手機/平板斷點，
     不動桌機版已定案的排版 */
  .form-field--inline label { width: 162px; }
}

/* ==========================================================================
   2026-09-28 宗霖回報（平板版）：常見問題子頁面多出一條灰帶。
   第一輪：灰帶在 footer 下方；第二輪我把 footer 推到視窗底部，灰帶只是跑到
   footer 上方，宗霖回報「還是沒修好」。
   根因（兩輪是同一件事）：頁面內容（含 footer）只有約 1209px 高，但平板視窗高
   （iPad Pro 13 直向 1376px）比它高，多出來的 167px 一定要在某處——這是物理
   上不可能消掉的（faq 頁視窗高 ≥ 1250px 就會出現，≤ 1200px 才消失）。真正
   難看的不是「有多出高度」，而是那段高度露出了 body 的淺灰底色（--grey-100），
   跟內容區的品牌灰（--grey-300）不同色，看起來像多了一條別的區塊。
   修法：讓多出來的高度由「footer 正上方那個內容區塊」自己吸收（flex-grow:1）。
   該區塊背景本來就是不透明的品牌灰或白（實測 17 頁 footer 正上方的元素背景全部
   不透明），多長出來的高度就是它自己的底色，跟上方內容連成同一片，沒有任何
   異色灰帶；footer 貼齊視窗底部。視覺上等於該區塊底部留白多一點。
   內容本來就比視窗高的頁面：沒有多出來的高度可以分配，flex-grow 不起作用，
   排版完全不變。
   ⚠️ body > * { flex-shrink:0 }：body.is-loading 期間會被設成固定 height:100vh，
   若子元素可以收縮，帶 overflow:hidden 的區塊會被壓扁、main.js 在 loading 期間
   量到錯誤高度。固定定位的元素（header／nav／遮罩／cookie 橫幅）不參與 flex
   排版，不受影響。
   只套用平板（768～1099px）：桌機（≥1100px）與手機（≤767px）依宗霖指示
   未經同意不動——同樣的灰帶在桌機高視窗（例如 1440×1400，faq 頁 181px）也存在，
   之後若要一併處理，把這段的 media query 範圍放寬即可 */
@media (min-width: 768px) and (max-width: 1099px) {
  body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
  }
  body > * {
    flex-shrink: 0;
  }
  body > :has(+ .site-footer) {
    flex-grow: 1;
  }
}

/* 2026-09-30：聯絡表單「沒有表單時的替代文字」（沒填 Forminator 編號、或 Forminator 未啟用）。
   聯絡頁桌機版的左欄裝飾（Logo＋社群，約 400px 高）是對齊到「表單下緣」（main.js 的 alignContactFormToHeading），
   版面假設表單很高；替代文字只有約 270px，裝飾會被往上推、蓋到「聯絡我們」標題。
   桌機版（左右雙欄，1100px 以上）給替代區塊足夠的高度，單欄時（≤1099px）不需要。只作用在聯絡頁。 */
@media (min-width: 1100px) {
  [data-page="contact"] .contact-form-fallback-box {
    min-height: 720px;
  }
}

