/* ================================================================
   Board Sea Technology — 04-components.css
   S2–S6 與 footer 的共用元件（atom 層）。跨頁會重複用到的元件放這裡。

   ── 本檔是 styles.css（4,118 行）拆檔的第 4/5 段 ──
   拆檔只切不搬：五個檔案**依序串接回去逐位元組等於原檔**，層疊結果不變。
   由 includes/_head.php 依 01→05 的順序載入，**順序不可調換**。
   來源 banner 邊界見 git 歷史（2026-08-20 拆檔 commit）。
   ================================================================ */

/* ================================================================
   SHARED ATOM LAYER — Batch B1 (S2–S6 + Footer 模組化元件架構)
   單一真相源：/Users/dawa/博洋興業有限公司/site-b/DESIGN.md
   施工依據：/Users/dawa/博洋興業有限公司/site-b/docs/spec-s2-s6-components.md
   （uiux 2026-08-18 產出，§A 元件清冊／§A-2 逐元件詳規／§A-3 互動狀態矩陣）

   新增 14 個共用 atom（C1–C14）＋ 擴充既有 focus-visible 規則以涵蓋
   新元件。對應的新 token 已追加在檔案上方既有 :root 區塊尾端。

   本批範圍只到「共用 atom 層」，不含：
   - index.html（S2 的 DOM 組裝是下一批的事，本層純樣式定義）
   - 區塊層樣式：.split / .news / .news-row / .card-rail / .card /
     .stat-grid / .stat / .site-footer__* / .giant-wordmark
     （這 5 個是「區塊專屬」元件，各自組裝下面的 atom，屬 B2–B6 各批
     自己的命名空間，此處不越界；.card:hover .media__img 的 hover
     驅動同理留給 B4）
   - .nav-overlay__eyebrow 與 .eyebrow--label 的指紋合併（B6 的事）

   atom 層治理（DESIGN.md 交接契約 硬約束⑦）：C1–C14 只有本批（B1）
   可編輯；B2–B6 只能使用、不能改，發現缺口停下回報，不得自行分叉。

   前一個「Unit 1 of 2」／「Unit 2 of 2」標記（檔案上方）在本批之後
   已不是完整描述——本層是第三個邏輯區塊，但既有標記文字本身不動
   （非本批授權範圍），特此註記避免誤讀。
   ================================================================ */

/* ── 共用 focus-visible 擴充（新元件）——承 styles.css 上方 skip-link
   附近既有規則（.site-header/.nav-overlay 手列選擇器清單），該規則
   不會自動蓋到本批新增的 atom。這裡補一條共用規則涵蓋 C7/C8/C13 的
   可聚焦元素。深色區塊（.section--dark 黑 / .section--navy 深藍）內
   的 ring 色必須切到 --focus-ring-on-dark：on-light 的 accent.500
   對 navy 只有 1.7:1，等於沒有 ring（DESIGN.md 交接契約 硬約束③，
   驗收點 8）。.card / .news-row 的 :has(:focus-visible) 卡外緣 ring
   屬區塊層（B3/B4），不在本批範圍。 ── */
.btn:focus-visible,
.icon-btn:focus-visible,
.link-list a:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-on-light);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-alias-control);
}

.section--dark .btn:focus-visible,
.section--dark .icon-btn:focus-visible,
.section--dark .link-list a:focus-visible,
.section--navy .btn:focus-visible,
.section--navy .icon-btn:focus-visible,
.section--navy .link-list a:focus-visible,
/* .section--feature 也是深底（2026-08-24）。目前三個重音區塊裡沒有連結，
   但 accent_block 是資料層設定的、隨時可能指到有連結的區塊 ——
   焦點框在那一刻才發現看不見就太晚了。 */
.section--feature .btn:focus-visible,
.section--feature .icon-btn:focus-visible,
.section--feature .link-list a:focus-visible,
.section--feature a:focus-visible {
  outline-color: var(--focus-ring-on-dark);
}


/* ── C1 `.section` — 區帶外殼（規格 §A-2 C1）。padding-block 由
   --section-padding-block 承擔四斷點值，.section 本身不得寫 media
   query（硬約束⑥：同一元件四斷點須引用同一 token 名）。 ── */
.section {
  padding-block: var(--section-padding-block);
  border-radius: var(--radius-alias-flush);
}

/* ⚠️ 2026-08-25（daniel 裁示）：底色由 --surface-inverse-deep（純黑 #000）
   改為 --surface-inverse（深藍 #00173E）。**全站唯一消費端是首頁 S2**
   （data/intro.php 的 tone => 'dark'）。

   起因：daniel「header 下面的 section 看起來有點太黑了」。量出來的背景 ——
   原稿的 hero 是暗藍 plexus、S2 的配圖是暗機房（平均亮度 33），「hero 底緣
   →S2」在原設計裡是一整塊連續的深色；淺色改版把兩張照片都換成亮的
   （hero 196-202、S2 配圖 142）之後，純黑失去了深色鄰居變成一面牆，而且
   亮照片釘在純黑上會因**同時對比**讓黑讀起來更黑。改深藍之後 S2 與 S6
   同色，全站深色表面收斂成一種。

   ⚠️ class 名字**刻意不改**（不改叫 .section--navy）：tone => 'dark' 是
      data/intro.php 的欄位值＝第二期 CMS 的下拉選項，而 home.php 有四處
      `$b['tone'] === 'dark'` 在決定文字要不要走 on-inverse。改名要同時動
      資料值、view 四處三元式與本檔，收益只是名字好看，代價是漏改一處就
      靜默破版（同 .svc-axis 名不符實但不改名的先例）。
   ⚠️ 這是**刻意偏離已核定設計**：原稿取樣證實 S2 真的是純黑，不是抄錯。
      完整取樣結果與判準見 01-tokens.css 的 --surface-inverse-deep 註解。
   ⚠️ 要復原純黑就是把下面那一行改回 var(--surface-inverse-deep)，那顆 token
      保留著沒刪。**但復原前要先回頭看 hero 的 scrim** —— 底緣那隻 α=1 的黑腳
      已於同日收掉（01-tokens.css --hero-scrim-gradient），它存在的唯一理由
      就是要跟這裡的純黑對齊；只還原一邊會讓接縫回到一道可見階差。 */
.section--dark {
  background-color: var(--surface-inverse);
}

.section--subtle {
  background-color: var(--surface-subtle);
}

.section--page {
  background-color: var(--surface-page);
}

.section--navy {
  background-color: var(--surface-inverse);
}


/* ── 重音區塊：背景實景照 ＋ 深色遮罩 ＋ 反白文字（2026-08-24）─────────
   daniel：「有一些這種區域…應該還可以多一些層次…是不是可以在背景加張
   不要太複雜圖片套個模糊低明度遮罩」。**一頁最多一個**，而且
   **不放在已經有配圖的區塊**（daniel 指定）—— 哪一段是重音寫在
   data/service-details.php 的 accent_block。

   ⚠️ 底圖走 <img>（component('section-bg')）不是 background-image：
      CSP 沒有 unsafe-inline，inline style 會失效；寫死在 CSS 裡又等於把內容
      搬進樣式表。詳見該元件檔頭。
   ⚠️ 模糊烘在素材檔裡，不是 CSS filter —— 少一次執行期全寬模糊，
      而且模糊後的 JPEG 壓得極小（2000w 的 webp 只有 15–27KB）。 */
.section--feature {
  position: relative;
  /* isolation：把下面兩層負 z-index 關在這一段的堆疊脈絡裡，
     不加的話它們會鑽到頁面背景後面直接看不見。 */
  isolation: isolate;
  /* 圖是 lazy 的，載入前這顆底色就是畫面 —— 不給會先閃一下淺灰再變深。
     同時它也是遮罩的同色系，所以載入前後不會跳色。 */
  background-color: var(--surface-inverse);

  /* 反白：**就地重定義語意 token**，元件（.tbl／.prose／.eyebrow）本身
     不必知道自己被放在深底上 —— 這是本站處理 !important 與深色底的既定手法。
     四顆都是站上既有、註解裡帶著實測對比度的 on-inverse 版本，
     不自己調色（硬約束⑥：缺 token 要停下來回報，不可就地發明）。 */
  --text-primary: var(--text-on-inverse);
  --text-body: var(--text-secondary-on-inverse);
  --text-secondary: var(--text-secondary-on-inverse);
  --text-eyebrow: var(--text-eyebrow-on-inverse);
  --border-hairline: var(--border-hairline-on-inverse);
  --border-functional: var(--border-hairline-on-inverse);
  /* ⚠️ 2026-08-25：--border-interactive 也要換。它預設是 --color-accent-600
     （#0061C2，為**白底**選的，對白 6.02:1），放在遮罩後的深底上會變成一顆
     幾乎看不見的深藍點。/about/ 的區域清單用它畫「營運中」的狀態燈 ——
     那顆燈是 is_operating 唯一的視覺載體（data/regions.php 的檔頭寫明它存在的
     理由是對外禁灌水），看不見等於那條規矩沒有落地。
     換成 accent-200，與同一段裡的 --text-eyebrow 同值（對 navy 13.6:1）。 */
  --border-interactive: var(--color-accent-200);
  color: var(--text-body);
}

.section__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  display: block;
  overflow: hidden;
}

.section__bg img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* ⚠️ 遮罩的 z-index（-1）**必須大於** .section__bg 的 -2。
   兩者同值的話由 DOM 順序決定，而 ::before 排在 <picture> 前面 ——
   結果是圖蓋住遮罩，文字直接壓在照片上。 */
.section--feature::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: var(--section-feature-scrim);
}


/* ── C2 `.container`（規格 §A-2 C2，公式逐字轉錄）。這條公式讓「單一
   左緣」在五個區塊自動成立，驗收點 5（各區標題 left 相等，容差 0）
   靠它，不靠各區自己算 padding。 ── */
.container {
  width: min(100% - 2 * var(--inset-x), var(--container-max-width));
  margin-inline: auto;
}


/* ── C3 `.section-head`（規格 §A-2 C3）。結構：
   .section-head > .eyebrow + .section-title (+ .section-head__actions)。
   預設為 flex column，eyebrow/title 直接吃 --section-head-gap。
   --inline-actions（S5 專用）切成 row 佈局時，eyebrow+title 需要一個
   文字群組 wrapper（.section-head__text）才能在 row 佈局下繼續維持
   「兩者疊在一起」的視覺關係——DOM 巢狀深度屬「frontend 可自行決定」
   （交接契約 4「邊界」），下一批組裝 S5 DOM 時請照此 wrapper 結構。 ── */
.section-head {
  display: flex;
  flex-direction: column;
  gap: var(--section-head-gap);
  margin-block-end: var(--section-head-space-after);
}

.section-head__text {
  display: flex;
  flex-direction: column;
  gap: var(--section-head-gap);
}

.section-head__actions {
  display: flex;
  gap: var(--space-3);
  flex-shrink: 0;
}

.section-head--inline-actions {
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--space-4);
}

/* ≤1023：actions 移到 title 下方（長標題與控制項互擠時的既定行為，
   規格 §A-2 C3）。 */
@media (max-width: 1023px) {
  .section-head--inline-actions {
    flex-direction: column;
    align-items: flex-start;
  }
}


/* ── C4 `.eyebrow`（規格 §A-2 C4）。預設 transform:none 已由
   --type-role-eyebrow-transform 承擔，--label 變體覆寫為 uppercase +
   寬字距。--label 與既有 .nav-overlay__eyebrow 同指紋（見 D 段），
   合併是 B6 的事，本層不動 .nav-overlay__eyebrow。 ── */
/* ── eyebrow（2026-08-25 daniel 裁示改樣式，選的是「B：前導髮絲線」）──────
   **改的原因是量出來的，不是風格偏好**：

     --text-eyebrow  =  --color-accent-600  (#0061C2)
     --text-link     =  --color-accent-600  (#0061C2)   ← 同一個值

   （`--border-interactive` 的註解自己就寫著「與 --text-link 同值、不同語意」。）
   也就是說全站每一個 section 標籤都長得跟連結一模一樣 —— 粗體、藍色、
   可讀性又高 —— 但它們**一個都不能點**。

   處置：顏色轉中性、字重降回 regular，再給「一個區塊要開始了」的位置
   加一條前導髮絲線。

   ⚠️ **顏色改在這裡，不改 --text-eyebrow 那顆 token。** 那顆 token 有 7 個
      消費端，其中 `.scope-list__icon`／`.step-list__no`／`.tbl th`／
      `.figure__plate`／`.region-list__code` 都是**該留著的藍色重音**，
      不是「看起來像連結的標籤」。改 token 會把它們一起變灰，那超出這次的範圍。
      （token 本身保留原值不動，只是 `.eyebrow` 不再是它的消費端。）
   ⚠️ `.section--feature` 不必另外處理：它已經把 `--text-secondary` 換成
      on-inverse 版（本檔上方的 token 交換），所以這裡改吃 --text-secondary
      之後，重音區塊裡的 eyebrow 自動反白。
   ⚠️ **微互動不推廣到全站。** 服務卡那條 `.u-underline-wipe` 底線的語意是
      「這一格可以點」；其餘 eyebrow 是不可點的區塊標籤。給它們加 hover 效果
      既沒人會觸發，又會讓「有底線＝可點」這個訊號失效。 */
.eyebrow {
  display: block;
  font-family: var(--type-role-eyebrow-family);
  font-size: var(--type-role-eyebrow-size);
  line-height: var(--type-role-eyebrow-line-height);
  letter-spacing: var(--type-role-eyebrow-letter-spacing);
  font-weight: var(--font-weight-regular);
  text-transform: var(--type-role-eyebrow-transform);
  color: var(--text-secondary);
}

.eyebrow--on-inverse {
  color: var(--text-secondary-on-inverse);
}

/* ── 前導髮絲線 ──
   ⚠️ **正面列舉「一個區塊要開始了」的四個脈絡，不是掛在所有 .eyebrow 上。**
      全站 eyebrow 有 15 種父層脈絡（實測），其中這四個以外的都不該有線：
        .site-footer__column／.nav-overlay__services  頁尾與選單的欄標題
        .card／.svc-axis__body                        服務卡（有自己的底線微互動，
                                                      再加一條會變成兩條線打架）
        .panel／.page-hero__text／.section-note        卡片內與頁首的小標
      用排除法寫的話，日後新增一個脈絡會**預設長出線**；正面列舉則是預設不長，
      要就明寫。這一區的失敗模式偏向「多了不該有的線」，所以選預設不長。
   ⚠️ 線的顏色走 --border-functional（承載狀態的邊框階，對白 4.54:1、對灰 4.09:1，
      高於非文字門檻 3:1）。`.section--feature` 已把這顆換成 on-inverse 版，
      所以那裡自動變淡色，不必另寫。深底（--dark／--navy）走下面的 on-inverse 規則。
   ⚠️ flex ＋ gap 不是 `::before` 加 margin：eyebrow 可能折行，用 flex 的話
      線與文字第一行對齊；用 margin 會讓線黏在第一個字元前面而不是行首。 */
.section-head > .eyebrow,
.section-head__text > .eyebrow,
.split__content > .eyebrow,
.cta-band__in > .eyebrow,
.page-hero .eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.section-head > .eyebrow::before,
.section-head__text > .eyebrow::before,
.split__content > .eyebrow::before,
.cta-band__in > .eyebrow::before,
.page-hero .eyebrow::before {
  content: '';
  inline-size: var(--space-7);
  block-size: var(--border-width-hairline);
  /* ── 線的顏色（2026-08-25 三修，daniel：「把髮絲的顏色改成品牌的藍，
     文字不用動」）──────────────────────────────────────────────
     沿革，三個版本各自的失效點都記著，免得再繞一圈：
       初版  --border-functional ＋ 深底用 --border-hairline-on-inverse 覆寫
             → 後者是 rgba(255,255,255,0.10)，對 navy **1.32:1**，深底幾乎看不見
       二修  currentColor（線＝字色）
             → 解決了看不見，但線與字變成同一個灰，少了重音
       現行  --border-interactive（accent-600），**文字維持中性不動**

     ⚠️ **深底必須另給一顆，不能只寫一條。** accent-600 對 navy 只有
        **2.93:1**，低於非文字圖形的 3:1 門檻（WCAG 1.4.11）。深底改用
        accent-200（13.56:1），就是下面 --on-inverse 那條。
        （二修時把那條拿掉是因為 currentColor 自帶脈絡；改回固定色就必須加回來。）
     ⚠️ `.section--feature` **不必再列一次**：那一段已經把 --border-interactive
        換成 accent-200（2026-08-25 為 /about/ 的狀態燈加的），所以吃這顆
        token 就自動拿到深底版。
     ⚠️ 站上沒有 logo 那顆 #42baf9 的 token（實測 grep 全站 CSS 零命中）。
        這裡用的是本站實際在用的 accent 階 —— 硬約束⑥：缺 token 要回報，
        不可就地發明。真要用 logo 那顆藍，得先把它建成 token 並補對比實測。 */
  background-color: var(--border-interactive);
  flex-shrink: 0;
  /* 捲動進場的支點，見下方那組規則。放在基準規則裡是刻意的 ——
     transform-origin 不參與動畫，但寫在 is-armed 那條會讓「線從哪一端長出來」
     這個決定散在兩個地方。 */
  transform-origin: left center;
}

/* ── 前導線的捲動進場（2026-08-25，daniel：「讓標題上的 eyebrow 有捲動的
   進場 由左至右之類的」）────────────────────────────────────────
   **接在站上既有的 .reveal 機制上，不另外做一套**：沒有新的 IntersectionObserver、
   沒有新的 JS、沒有新的 state class，只多兩條 CSS。

   這樣寫直接繼承了 reveal 模組已經處理好的三件事（site.js 的 REVEAL IIFE）：
     1. 沒有 JS／瀏覽器不支援 IntersectionObserver → `is-armed` 不會加上去
        → 線停在基準態（可見）。**不會出現「線永遠不見了」這種靜默破圖。**
     2. `prefers-reduced-motion` → 該模組**直接早退**（連 is-armed 都不加）
        → 同樣停在可見態。這裡不必再寫一份 reduce 例外。
     3. `.page-hero` 沒有 data-reveal-group → 首屏的 eyebrow 不做進場。
        那是對的：對已經在視窗裡的東西播「捲動進場」本來就沒有意義。

   ⚠️ **只動線不動文字。** 文字本來就在 .reveal 裡（淡入 ＋ 上移），再給它
      一次進場會變成同一件事做兩次。
   ⚠️ **時長走 --motion-duration-draw（720ms），不是 --motion-duration-slide。**
      初版用了 slide(240ms)，理由是那顆 token 的註解寫著「底線劃出／方向性形變用」。
      手勢對，但**觸發方式不對**——daniel 2026-08-25 二修：「速度太快了，導致根本
      看不出來」。slide 的三個既有消費端全是 **hover 觸發**（nav 底線、.link-list
      的 wipe、服務卡的 wipe），使用者的眼睛已經盯著那一格，240ms 跟手才對；
      捲動進場是**被動發生**的，眼睛還在別處，太快就等於沒發生。
      實測：standard 曲線前段陡，240ms 在 **122ms 就畫到 78%**，40px 的線上
      看起來就是「本來就在那」。720ms 時同一個 78% 落在 367ms。
      ⚠️ **不可以改 --motion-duration-slide 那顆來解決**，會把上面三處 hover
         底線一起拖慢。新開一顆是刻意的，值＝3 × slide 維持在動效階梯上。
      現在是文字 400ms 淡入先落定、線 720ms 續劃 —— 順序與初版相反，這是對的：
      線是重音，讓它最後到位。
   ⚠️ **還有一個 delay，那才是真正讓它「看得到」的東西**（2026-08-25 三修，
      daniel：「好像還是太快，還是可以讓他在該區塊載入完後再載入？」）。
      二修只把 720ms 拉長，daniel 仍然覺得太快 —— 因為**那不是速度問題，
      是注意力被搶走的問題**：線與文字**同時起跑**，而文字是一整塊在淡入 ＋ 上移，
      眼睛一定看文字；等視線移到 eyebrow，40px 的線早就畫完了。
      調速度解決不了「同時發生」，**排序才可以**。
      delay 走 --motion-duration-enter（400ms）＝ **等文字自己那段淡入跑完**。
      這個 eyebrow 就是 .reveal 本身、而且是 .section-head 的第 1 個子元素
      （既有 stagger 從第 2 個才給延遲），所以它的文字正好在 400ms 落定；
      h2 是第 2 個、460ms 落定。線從 400ms 開始畫到 1120ms —— 後面那 660ms
      **畫面上只有它在動**，這才是讀得到的原因。
      ⚠️ 走 token 不寫 400ms：reduce 區塊已把 --motion-duration-enter 歸零，
         delay 會跟著塌縮（雖然 reduce 下 REVEAL 模組本來就早退、根本不會播）。
      ⚠️ 首頁 S2 是例外（圖在左、.split__content 排第 2），文字帶一個
         --motion-stagger(60ms)，所以線與文字尾端重疊 60ms。**刻意不為它複製
         一整組 nth-child 延遲規則** —— 60ms 在 720ms 的畫面上看不出來，而
         複製出來的第二份遲早會與 02-base.css 那份漂開（判準同二修那次）。
      ⚠️ 觀察器的 rootMargin 是 `0px 0px -20% 0px`（site.js），區塊頂端要越過
         視窗 80% 高度才觸發，所以 delay + duration 合計 1120ms 有足夠的捲動餘裕。
         **要再加長總時長的話得回頭看這件事。**
   ⚠️ **沒有另寫 stagger 延遲。** 實測全站 19 個有線的 eyebrow 裡，18 個所屬的
      `.reveal` 都是容器的第 1 個子元素（既有 stagger 規則從第 2 個才開始給延遲），
      所以線與文字本來就同時起跑；唯一的例外是首頁 S2（圖在左，.split__content
      排第 2），線比文字早 **60ms** —— 一個 --motion-stagger。為了那 60ms 去
      複製一整組 nth-child 延遲規則不划算，而且複製出來的第二份遲早會與
      02-base.css 那份漂開。 */
.reveal-group.is-armed .eyebrow::before {
  transform: scaleX(0);
}

.reveal-group.is-armed.is-revealed .eyebrow::before {
  transform: scaleX(1);
  transition: transform var(--motion-duration-draw) var(--motion-easing-standard);
  transition-delay: var(--motion-duration-enter);
}

.section-head > .eyebrow--on-inverse::before,
.section-head__text > .eyebrow--on-inverse::before,
.split__content > .eyebrow--on-inverse::before,
.cta-band__in > .eyebrow--on-inverse::before,
.page-hero .eyebrow--on-inverse::before {
  background-color: var(--text-eyebrow-on-inverse);
}

.eyebrow--label {
  text-transform: uppercase;
  letter-spacing: var(--letter-spacing-label-wide);
}


/* ── C5 `.section-title`（規格 §A-2 C5）。overflow-wrap:anywhere 是
   floor_guard 配套的第二層保險，.hero__title 已有此寫法，照抄。不得
   加 text-shadow——那是 hero 專屬（文字疊照片），S2–S6 標題不疊圖。 ── */
.section-title {
  font-family: var(--type-role-section-title-family);
  font-size: var(--type-role-section-title-size);
  line-height: var(--type-role-section-title-line-height);
  letter-spacing: var(--type-role-section-title-letter-spacing);
  font-weight: var(--type-role-section-title-weight);
  color: var(--text-primary);
  overflow-wrap: anywhere;
}

.section-title--on-inverse {
  color: var(--text-on-inverse);
}


/* ── C6 `.prose`（規格 §A-2 C6）。 ── */
.prose {
  font-family: var(--type-role-paragraph-family);
  font-size: var(--type-role-paragraph-size);
  line-height: var(--type-role-paragraph-line-height);
  letter-spacing: var(--type-role-paragraph-letter-spacing);
  font-weight: var(--type-role-paragraph-weight);
  max-width: var(--type-role-paragraph-max-width);
  color: var(--text-body);
}

/* 表面鎖定：--text-secondary-on-inverse 對白底僅 1.42:1，只准用在
   .section--dark / .section--navy 內；對 #00173E 實測 11.75:1、對
   #000000 實測 13.8:1（規格 §A-2 C6，驗收點 2）。 */
.prose--on-inverse {
  color: var(--text-secondary-on-inverse);
}


/* ── C7 `.btn` — 最重要的複用元件（規格 §A-2 C7／§A-3 狀態矩陣）。
   觸控地板逐斷點（caption 行高 + padding-block×2）：mobile 44 / tablet
   45 / base 46 / wide 48，四斷點全過 44；mobile 餘裕 0 →
   --btn-padding-block 是硬下限，不得再減。 ── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--btn-gap);
  padding: var(--btn-padding-block) var(--btn-padding-inline);
  border: none;
  border-radius: var(--btn-radius);
  font-family: var(--type-role-button-label-family);
  font-size: var(--type-role-button-label-size);
  line-height: var(--type-role-button-label-line-height);
  letter-spacing: var(--type-role-button-label-letter-spacing);
  font-weight: var(--type-role-button-label-weight);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--motion-duration-hover) var(--motion-easing-standard),
    transform var(--motion-duration-press) var(--motion-easing-standard);
}

/* 2026-08-18 全站微動態規格 P9：加 transform transition，供 S5
   .btn--with-icon:hover 消費（見 S5 區塊該處規則）。 */
.btn__icon {
  width: var(--btn-icon-size);
  height: var(--btn-icon-size);
  flex-shrink: 0;
  transition: transform var(--motion-duration-hover) var(--motion-easing-standard);
}

/* --primary：S3「See the delivery model」、S5 卡片×5「Explore …」 */
.btn--primary {
  background-color: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
}

@media (hover: hover) and (pointer: fine) {
  .btn--primary:hover {
    background-color: var(--btn-primary-bg-hover);
  }
}

/* 2026-08-18 全站微動態規格 P2：hardcode 1px 改 token，理由同
   .primary-nav__list a:active 註解。 */
.btn--primary:active {
  background-color: var(--btn-primary-bg-active);
  transform: translateY(var(--motion-press-offset));
}

.btn--primary:disabled,
.btn--primary[aria-disabled="true"] {
  background-color: var(--color-neutral-300);
  color: var(--color-neutral-600);
  cursor: not-allowed;
}

/* --on-inverse：S2「How we work」——深底上的白色實心膠囊＋深字，
   17.6:1。DESIGN.md 原本只有透明＋白框的 button_secondary.on_dark，
   本規格新增此變體（規格 §A-2 C7）。 */
.btn--on-inverse {
  background-color: var(--btn-on-inverse-bg);
  color: var(--btn-on-inverse-fg);
}

@media (hover: hover) and (pointer: fine) {
  .btn--on-inverse:hover {
    background-color: var(--btn-on-inverse-bg-hover);
  }
}

/* 2026-08-18 全站微動態規格 P2：hardcode 1px 改 token，理由同上。 */
.btn--on-inverse:active {
  background-color: var(--btn-on-inverse-bg-active);
  transform: translateY(var(--motion-press-offset));
}

.btn--on-inverse:disabled,
.btn--on-inverse[aria-disabled="true"] {
  opacity: 0.4;
}

/* --secondary：本輪 0 使用者，入庫備用（DESIGN.md button_secondary.on_light）。
   狀態矩陣未列 hover/active/disabled 明確值，本輪不發明，只建立
   default 外觀，需要態時回頭出規格。 */
.btn--secondary {
  background-color: transparent;
  color: var(--color-brand-900);
  border: var(--border-width-hairline) solid var(--color-brand-900);
}


/* ── C8 `.icon-btn`（規格 §A-2 C8／§A-3 狀態矩陣，S5 carousel 控制）。
   44×44 尺寸：A-5 未提供專屬 token，比照既有 .menu-toggle／
   .nav-overlay__close（同為方形控制按鈕 touch target，皆 raw literal
   px、非本批可編輯範圍）的既定寫法處理，非新發明數值，回報中已揭露。
   邊框用 --border-functional（4.54:1 ≥3:1），禁用 --decorative-only
   （2.49:1，僅裝飾用）。 ── */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: var(--border-width-hairline) solid var(--border-functional);
  border-radius: var(--radius-alias-control);
  background-color: transparent;
  cursor: pointer;
  /* 2026-08-18 全站微動態規格：矩陣對 [aria-disabled] 的 opacity 變化標記
     hover(160ms) 時長，原本未過渡（瞬時切換）。加入 opacity 使其平滑，
     opacity 為全站唯二允許的合成器屬性之一，非新違規。 */
  transition:
    background-color var(--motion-duration-hover) var(--motion-easing-standard),
    opacity var(--motion-duration-hover) var(--motion-easing-standard),
    transform var(--motion-duration-press) var(--motion-easing-standard);
}

.icon-btn__icon {
  width: var(--btn-icon-size);
  height: var(--btn-icon-size);
}

@media (hover: hover) and (pointer: fine) {
  .icon-btn:hover {
    background-color: var(--color-neutral-200);
  }
}

/* 2026-08-18 全站微動態規格 P2：原僅色變，補上全站一致的按下位移
   （矩陣「press 120」欄要求），token 化避免 reduce 漏洞。 */
.icon-btn:active {
  background-color: var(--color-neutral-300);
  transform: translateY(var(--motion-press-offset));
}

/* disabled＝捲到最左/最右時對應方向鍵不可用。用 aria-disabled 而非
   disabled 屬性，保留焦點可達性以利螢幕閱讀器理解邊界；
   pointer-events:none 只擋滑鼠 hover/click，不擋鍵盤 Tab/focus。 */
.icon-btn[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}


/* ── C9 `.media` — 11 張圖共用同一個元件（規格 §A-2 C9）。
   error state：.media 自身帶 --media-fallback-bg 灰底，圖載入失敗時
   3:2 版位不塌陷（<img> 帶 width/height 防 CLS 由下一批 HTML 負責）。
   --3x2 是預設外觀（比例/圓角已在 .media 本身），HTML 上仍可掛
   .media--3x2 class 以求顯式，不需要獨立、內容相同的空規則。
   hover 不在本元件定義——由 .card:hover .media__img 從外層驅動
   （.card 是 B4 的區塊層範圍，不在本批）。 ── */
.media {
  position: relative;
  aspect-ratio: var(--media-ratio);
  overflow: hidden;
  border-radius: var(--media-radius);
  background-color: var(--media-fallback-bg);
}

.media--thumb {
  border-radius: var(--media-radius-sm);
}

/* D37（docs/spec-s5-redesign.md §1②#1/#2 + §9）：S5 卡片圖改正方形。
   --media-ratio 全站僅 :root 定義一次、零覆寫的既有先例（見上方 C9
   註解）在此首次被打破——1:1 與 3:2 是內容不同的兩個比例值，不是
   .media--3x2 那種「顯式但零規則、三斷點皆同值」的情形。圓角比照
   .media--thumb 既有寫法沿用 --media-radius-sm（= small 階，四斷點
   12/10/12/14 由 --radius-small primitive 各自 media block 覆寫自動
   響應，此處零新增 media query）。 */
.media--1x1 {
  --media-ratio: var(--card-media-aspect);
  border-radius: var(--media-radius-sm);
}

/* D38（docs/spec-s5-redesign.md §3 逃生口，逐字）：素材右下 40%×30%
   若實測平均 sRGB 不達門檻（≤0.38），可對 .media 加掛本 class 提高
   描邊可讀性。預設不掛——開不開由 quality 對真實素材的 V7/V8 量測
   結果決定，不由手感決定。 */
.media--ordinal-scrim::before {
  content: '';
  position: absolute;
  inset-inline-end: 0;
  inset-block-end: 0;
  width: 40%;
  height: 30%;
  background: var(--card-ordinal-scrim-gradient);
  pointer-events: none;
}

/* ⚠️ <picture> 必須自己撐滿 .media，否則 .media__img 的 height:100% 會吃到
   picture 的內容高度而不是 .media 的高度 —— 結果是圖片只佔上半、下面留一片灰。
   （02-base.css 的 reset 給 img/picture 一組 height:auto，picture 因此縮成內容高。）

   2026-08-20 實測踩過：為了補 webp 而把 <img> 包進 <picture> 之後，
   1:1 的服務卡變成 380x380 的框裡塞 380x253 的圖。她自己的註解也記過同一件事
   —— 03-header-hero.css 提到「原本『單一 picture』年代用的 display:contents 手法
   （讓 picture 不佔盒模型、img 直接吃 .hero__media 的高度）」。
   這裡用明確的 block + 100% 而不是 display:contents，行為比較好預測。
   ⚠️ hero 的 .hero__slide-media 是**多個 picture 疊放**、走 position:absolute，
      不適用本規則，所以選擇器限定 .media 底下。 */
.media > picture {
  display: block;
  width: 100%;
  height: 100%;
}

.media__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}


/* ── C10 `.tag`（規格 §A-2 C10，S4×4）。非互動、無 5 態（DESIGN.md
   已裁決，交接契約 硬約束⑬）。不得做成 <a>。 ── */
.tag {
  display: inline-block;
  padding-block: var(--tag-padding-block);
  padding-inline: var(--tag-padding-inline);
  border-radius: var(--radius-alias-control);
  background-color: var(--tag-bg);
  color: var(--tag-fg);
  font-family: var(--type-role-tag-label-family);
  font-size: var(--type-role-tag-label-size);
  line-height: var(--type-role-tag-label-line-height);
  letter-spacing: var(--type-role-tag-label-letter-spacing);
  font-weight: var(--type-role-tag-label-weight);
  white-space: nowrap;
}


/* ── C11 `.badge`（規格 §A-2 C11，S6×4 `Fictional proposal`）。紅線
   #7 強制元件，必須可見（不得 opacity<1、不得只在 hover 顯示）。
   規格只定義了 --on-inverse 這一個變體（S6 navy 專用）；padding-block
   A-5 未給專屬 token，比照 C10 tag 的節奏直接複用既有 --space-1
   （非新發明值）。base .badge 本輪無淺底變體可用，不擅自發明。
   非互動、無 5 態。 ── */
.badge {
  display: inline-block;
  padding-block: var(--space-1);
  padding-inline: var(--badge-padding-inline);
  border-radius: var(--radius-alias-control);
  font-family: var(--type-role-button-label-family);
  font-size: var(--type-role-button-label-size);
  line-height: var(--type-role-button-label-line-height);
  letter-spacing: var(--type-role-button-label-letter-spacing);
  font-weight: var(--type-role-button-label-weight);
  white-space: nowrap;
}

/* ⚠️⚠️ **2026-08-26：由「白色實心藥丸」改成安靜的純文字標籤。**
   （daniel：「首頁 in numbers 這個區塊下面那個白色 tag 看起來很像按鈕」）

   他是對的，而且不是「有點像」—— 實測它與 hero 主 CTA（.btn--on-inverse）
   **11 項算出值有 8 項完全相同**：

     底色 rgb(255,255,255)｜文字 rgb(0,23,62)｜圓角 999px
     字級 13px｜字重 700｜字距 0.13px｜text-transform none｜字體 Albert Sans

   只有內距不同（4/12 vs 12/24）。成因在 base .badge 自己：它吃的是
   `--type-role-button-label-*`（**按鈕的**字級 role）與 `--radius-alias-control`
   （那顆 token 的註解逐字寫著「所有控件：按鈕/chevron/tag/carousel」）。
   **它本來就是照按鈕的規格做的。**

   ⚠️ 這與 2026-08-25 eyebrow 那次是**同一類問題**：一個不能點的東西長得
      跟可以點的東西一模一樣。那次的處置是「顏色轉中性、字重降回 regular」，
      這裡沿用同一個判斷。

   ⚠️ **不只是換樣式,順序也改了**（見 includes/signature/home.php）：原本是
      「大數字 → 說明 → 類別」，類別排在最後、而且是整段除了數字以外最亮的
      東西 —— 一個單字的分類壓過了真正的主張。現在是「類別 → 數字 → 說明」。

   ⚠️ **C11 的紅線 #7 仍然成立**：那條要求的是「強制元件、必須可見」
      （不得 opacity<1、不得只在 hover 顯示）。class 還在、文字照樣看得見，
      改的只是外觀與位置 —— 專案規則允許的正是「調整樣式和順序」。
      **不可以把它整個刪掉。**

   ⚠️ 顏色用 --text-eyebrow-on-inverse（accent-200，13.6:1 對 navy）而不是
      eyebrow 的中性色：這一格的數字本身就是 accent 系，標籤同色才會跟數字
      讀成一組；用中性灰的話它會跟下面的說明文字黏成一組，等於標錯對象。
      層級由**字級與字重**承擔（12px regular vs 數字的巨大字級），不靠顏色。

   ⚠️ base `.badge` 的藥丸樣式**刻意保留不刪**（比照 .ck-flow-* / .card-rail）：
      它是 Dawa 規格的 C11 元件，日後要在淺底上做一顆真的 badge 直接接得上。
      目前全站只有這一個消費端。 */
.badge--on-inverse {
  background-color: transparent;
  color: var(--text-eyebrow-on-inverse);
  padding: 0;
  border-radius: 0;
  font-family: var(--type-role-eyebrow-family);
  font-size: var(--type-role-eyebrow-size);
  line-height: var(--type-role-eyebrow-line-height);
  letter-spacing: var(--type-role-eyebrow-letter-spacing);
  /* ⚠️ 不吃 --type-role-eyebrow-weight（那顆是 bold）—— 2026-08-25 的
     eyebrow 裁決是「字重降回 regular」，而那個決定下在 .eyebrow 規則上
     不是 token 上（token 有 7 個消費端，改它會波及別處）。這裡同理。 */
  font-weight: var(--font-weight-regular);
}


/* ── C12 `.rule`（hairline 分隔，規格 §A-2 C12）。--on-inverse 不可
   直接沿用淺底 --border-hairline（#E8E8E8 對 #00173E 是 14.57:1，
   那是一條白線不是分隔線）；--border-hairline-on-inverse 對 navy
   1.32:1／對黑 1.21:1，與淺底 1.22:1 同一個感知重量。非互動、無 5 態。
   --v（垂直）欄間分隔屬 S6 .stat-grid 的區塊層用法（B5），本層只給
   基礎方向樣式。 ── */
.rule {
  border: none;
  background-color: var(--border-hairline);
}

.rule--h {
  width: 100%;
  height: var(--border-width-hairline);
}

.rule--v {
  width: var(--border-width-hairline);
  align-self: stretch;
}

.rule--on-inverse {
  background-color: var(--border-hairline-on-inverse);
}


/* ── C13 `.link-list`（footer 兩欄，規格 §A-2 C13）。垂直節奏：
   --footer-column-gap-block(16) + item 行高 22 = 38px（figma-exact）。
   觸控：22 行高 + padding-block:12px = 46px≥44；為維持 38px 視覺節奏
   不變，用 margin-block:-4px 抵銷 padding 撐出的額外高度。這是規格登錄過
   的 intentional deviation（理由：footer 同質連結清單，Figma 38px 節奏為
   figma-exact；擴大節奏會破壞兩欄底緣對齊 D11），frontend 不得自行改
   節奏。字重/字級用 --type-role-button-label-*（caption/700），非
   tag-label（caption/400）——link-list item 字重是 700，用 tag-label 會
   少了粗體。無 disabled。

   2026-08-18 QA 修正（qaB a11y FAIL，5 筆寬度不足 44px）：上一版註解曾寫
   「可點區因此相鄰重疊 8px」，QA 實測推翻——相鄰命中區其實是相隔 8px、
   不是重疊，規格登錄的例外只涵蓋垂直節奏（above），從未涵蓋寬度軸。真正
   的缺口在 `.link-list a` 舊為 `inline-block`（shrink-to-fit 自己的文字
   寬度），沒有吃滿父層 `<li>`（flex column 預設 stretch，已是滿欄寬）的
   寬度——欄寬本身由同欄最長字串撐開（如 explore 欄的「Contact Us」），
   但較短的字（Home/About/News）只佔自己文字的窄寬，未達 44px 地板。改為
   `block`＋`width:100%` 讓每個連結吃滿欄寬，只動水平軸，不改
   padding-block/margin-block/gap 任何一個垂直度量，38px 節奏不受影響。 ── */
.link-list {
  display: flex;
  flex-direction: column;
  gap: var(--footer-column-gap-block);
  list-style: none;
}

/* 2026-08-18 全站微動態規格 P3：HTML 端已把 `u-underline-wipe` class 直接
   掛在 `.link-list a` 本身（grep index.html 核實），grep 確認此元素全站
   零既有 ::before/::after 使用，安全套用。position:relative 為底線
   ::before 建立 positioning context——與 .primary-nav__list a（同樣
   padding-block:var(--space-3) 且 position:relative + bottom:0 底線）
   既有手法一致，非新發明的定位策略。文字色矩陣標「→ --text-primary」，
   但本規則現況預設色本已是 --text-primary（非其餘狀態），核對後判定
   矩陣此欄為既定目標的重申、非需要變更的 delta，未新增色彩規則。 */
.link-list a {
  position: relative;
  display: block;
  width: 100%;
  padding-block: var(--space-3);
  margin-block: -4px;
  color: var(--text-primary);
  font-family: var(--type-role-button-label-family);
  font-size: var(--type-role-button-label-size);
  line-height: var(--type-role-button-label-line-height);
  letter-spacing: var(--type-role-button-label-letter-spacing);
  font-weight: var(--type-role-button-label-weight);
  text-decoration: none;
}

.link-list a.u-underline-wipe::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background-color: var(--border-interactive);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--motion-duration-slide) var(--motion-easing-standard);
}

.link-list--explore a {
  text-transform: uppercase;
}

.link-list a.u-underline-wipe:focus-visible::before {
  transform: scaleX(1);
}

@media (hover: hover) and (pointer: fine) {
  .link-list a.u-underline-wipe:hover::before {
    transform: scaleX(1);
  }
}

/* 2026-08-18 全站微動態規格 P2：hardcode 1px 改 token，理由同
   .primary-nav__list a:active 註解。 */
.link-list a:active {
  transform: translateY(var(--motion-press-offset));
}


/* ── C14 `.empty-state`（規格 §A-2 C14）。三條硬約束（DESIGN.md D14）：
   不得是 <a>、不得有 href（含 #）、不得有 hover/pointer 樣式——本規則
   刻意不含任何互動選擇器或 cursor 宣告。純文字。 ── */
.empty-state {
  color: var(--text-secondary);
  font-family: var(--type-role-meta-family);
  font-size: var(--type-role-meta-size);
  line-height: var(--type-role-meta-line-height);
  letter-spacing: var(--type-role-meta-letter-spacing);
  font-weight: var(--type-role-meta-weight);
}


/* ══════════════════════════════════════════════════════════════
   S2 BLOCK LAYER — 區塊層（規格 §B「S2 — 深色圖文區」；.split 命名空間，
   Unit 2 派工單硬約束⑨：只寫 .split，不寫 .news/.card/.stat/.site-footer__*）
   ══════════════════════════════════════════════════════════════ */

/* .split — S2/S3 共用的圖文雙欄骨架，本批只建 S2 用得到的部分。
   base/wide：grid-template-columns 吃 --split-columns（583px 577px，
   token 已在既有 tablet/mobile media block 覆寫為 1fr）；.split 本身
   不寫 media query（硬約束⑥：同一元件四斷點須引用同一 token 名，響應
   由 token 層承擔）。
   .split--media-end（S3「文左圖右」鏡射）不在本批範圍，未建——DOM 順序
   或 order 屬性的取捨屬「frontend 可自行決定」（交接契約 4「邊界」），
   不替負責 S3 的下一批預先拍板。
   .split--media-start：預設 DOM 順序（media 在前）本身就是「圖左文
   右」，不需要額外規則——同 C9 `.media--3x2` 的既定先例（B1 報告：
   「無視覺差異的顯式變體 class 允許零規則」，HTML 上仍掛 class 以求
   顯式）。 */
.split {
  display: grid;
  grid-template-columns: var(--split-columns);
  align-items: center;
  gap: var(--space-7);
}

.split > * {
  min-width: 0; /* 防 grid item（圖片／長文字）撐爆軌道寬度，CSS grid 常見陷阱 */
}

/* 右側文字直欄：eyebrow → title → prose → btn 單一 gap 節奏（規格 §B
   S2「文字直欄內部 gap: var(--prose-stack-gap)（24）」，非 C3
   .section-head 的兩層節奏——A-1 總表列 C3 用於「S2 S3 S4 S5 S6」但
   §B 逐區組裝對 S2 的操作性描述是扁平單一 gap 直欄、未出現
   .section-head，兩處有落差，本批以更具體的 §B 為準（同 B1 報告處理
   prose/code-block 落差的方法論），回報中已標出。 */
.split__content {
  display: flex;
  flex-direction: column;
  align-items: flex-start; /* 修正：flex column 預設 stretch 會把 inline-flex 的
     .btn 撐成整欄滿寬（真機實測抓到，577px/327px 滿版 pill 按鈕，非按鈕內容應有
     尺寸）。flex-start 讓 .btn 恢復 shrink-to-fit；p/h2 本身是 block 元素、有無
     stretch 皆滿寬，.prose 有 max-width 封頂，三者視覺不受影響。 */
  gap: var(--prose-stack-gap);
}


/* ══════════════════════════════════════════════════════════════
   S3 BLOCK LAYER — 區塊層（規格 §B「S3 — 淺灰圖文區（S2 鏡射）」；
   .split 命名空間，B2 派工單硬約束⑨：只寫 .split，不寫其他區塊）

   .split--media-end（S3「文左圖右」鏡射，B1 註解標為未建、DOM 順序或
   order 屬性取捨屬「frontend 可自行決定」——交接契約 4「邊界」）。

   本批採 DOM 順序反轉（.split__content 在前、.media 在後），與 S2 的
   DOM 順序（.media 在前）刻意相反：desktop 2 欄 grid 依 DOM 順序自動
   排成文左圖右，不需要任何 order 規則介入，與 .split--media-start
   零規則的既定先例（「無視覺差異的顯式變體 class 允許零規則」）同一
   精神——這裡差別只在於「零規則」的那個斷點從 desktop 換成
   tablet/mobile。

   ≤1023 收成單欄（--split-columns 已在既有 media query 覆寫為 1fr）
   時，若不介入，DOM 順序會讓文字先出現、圖片在後——與規格「≤1023
   取消鏡射、一律圖先文後」相反（單欄堆疊時鏡射不可感，只會讓 S2 與
   S3 圖文順序不一致）。故只在該斷點用 order:-1 把 .media 拉到最前，
   讓視覺順序回到與 S2 一致的圖先文後；.split__content 不需要對應
   宣告（預設 order:0 已經在 .media 之後）。 ── */
/* ⚠️ 2026-08-24 補 .split__media：上面那段說明假設圖欄的 grid item 自己就是
   `.media`。但呼叫 component('figure') 的地方吐的是
   `<div class="…"><figure class="figure"><div class="media">…`，
   `.media` 是孫節點、不是 grid item，**order 對它完全無效** ——
   結果是 /services/cabling/ 在 ≤1023 變成「文先圖後」，與 S2／S3／about
   相反。那不是刻意的，是標記巢狀深度不同造成的意外。
   `.split__media` 掛在真正的 grid item 上，兩種寫法才會一致。
   ⚠️ 兩個選擇器要留在**同一條規則**裡：拆成兩條的話，日後有人改斷點
      只改到一條，就會回到「同一頁兩種順序」。 */
@media (max-width: 1023px) {
  .split--media-end .media,
  .split--media-end > .split__media {
    order: -1;
  }
}


/* ══════════════════════════════════════════════════════════════
   S4 BLOCK LAYER — 區塊層（規格 §B「S4 — News」；.news/.news-row 命名空間，
   B3 派工單硬約束⑩：只寫 .news/.news-row，不寫 .card/.stat/.site-footer__*）
   施工依據：docs/spec-s2-s6-components.md §B S4 段、§A-2 C9/C10/C12/C14、
   §A-3 互動狀態矩陣 .news-row 列、§A-4 內容韌性 .news-row 列

   互動實作說明：規格對 .news-row 的 focus-visible 態標「同上 :has()」
   （同 .card 手法），代表可聚焦元素是列內的一個後代連結、不是 .news-row
   本身。本批採 stretched-link 手法：.news-row__link 只包標題文字（可讀
   連結名稱＝完整標題，不需額外 aria-label），其 ::after 偽元素
   position:absolute + inset:0，相對 .news-row（position:relative）撐滿
   整列可點/可聚焦區——DOM 巢狀與連結範圍屬「frontend 可自行決定」（交接
   契約 4 邊界）。.news-row:has(.news-row__link:focus-visible) 在列外緣
   畫 ring；.news-row__link 本身的 outline:none 有明確替代（ring 轉移到
   父層），非違反硬約束③無替代裸關 outline。已知限制：:has() 不支援的
   瀏覽器會讓這個替代失效（規格本身在 .card 已預期用同一手法，非本批
   獨有風險，回報中已揭露）。 ══════════════════════════════════════════════════════════════ */

.news {
  display: grid;
  grid-template-columns: var(--news-columns);
  align-items: start;
  gap: var(--space-7);
}

.news > * {
  min-width: 0;
}

/* gap:0 是 figma-exact——列間分隔靠每列自己的 border-block-start，不靠
   flex gap（規格 §B S4：「列間 gap: 0 + 每列 border-block-start」）。 */
.news-list {
  display: flex;
  flex-direction: column;
}

.news-row {
  position: relative;
  display: grid;
  grid-template-columns: var(--news-thumb-width) 1fr auto;
  align-items: center;
  gap: var(--news-row-gap);
  min-height: var(--news-row-height); /* ≤768 已由既有 token 覆寫為 auto，本層不重寫 */
  padding-inline: var(--news-row-padding-inline); /* 2026-08-19 S4 news-row hover pass（R1）：
     plate 水平內距，≤768 由既有 token 覆寫為 space-4(16px)，見 media block */
  padding-block: var(--news-row-padding-block);
  border-block-start: var(--border-width-hairline) solid var(--border-hairline);
  /* 2026-08-18 全站微動態規格 P1：整列 bg 表面色變（矩陣「S4 .news-row
     hover」列，此前無此規則，全新新增）。
     2026-08-18 追加核對：寫成 base（非 :hover 覆寫）是否引入新的可見底色
     變化？已核對 index.html #s4 section class＝`section section--subtle`，
     `.section--subtle { background-color: var(--surface-subtle) }`——即 S4
     區塊本身底色就是 --surface-subtle（#F3F3F3），與這裡的 base 宣告同值，
     視覺上無變化，維持現況不撤銷。
     2026-08-19 更新（S4 hover pass R1）：下方「附帶觀察」段所述「hover 無
     第二色可切換」已被本次改動推翻——--news-row-bg-hover 引入 #FFFFFF 為
     真實第二色，段落保留僅供沿革查閱，現況請見 R3 hover 區塊。
     附帶觀察（非本項修正範圍，僅記錄）：因 base 與（不存在的）hover 態同色，
     矩陣要求的「hover 表面色變」目前沒有可見效果可言——base 已恆為
     --surface-subtle，沒有第二色可供 hover 再切換。是否需另訂 hover 專屬
     色階，屬新視覺決策，留待設計裁示，本批未動手。 */
  background-color: var(--news-row-bg);
  transition:
    transform var(--motion-duration-press) var(--motion-easing-standard),
    background-color var(--motion-duration-hover) var(--motion-easing-standard);
  /* 2026-08-19 用戶當面裁決極簡化 hover（派工單「NEWS hover 極簡化」）：background-color
     變色／box-shadow ring／border-radius／border-color 四項裝飾 hover 效果與其 transition
     已刪除，只留 transform（:active 按壓位移）。用戶原話「news 的 Hover 這樣太 奇怪 圖片
     放大 箭頭 微動就好」——整列可點（本規則 position:relative 是 stretched-link 的
     containing block）與 .news-row__title 已移除的 position:relative 不受影響、原樣
     保留，未被本次改動觸碰。 */
}

/* ── 整列 hover 底色（2026-08-26，daniel：「news 那邊 hover 的時候該 item
   會有背景變化」）────────────────────────────────────────────────
   ⚠️ **只加底色這一項。** 2026-08-19 的「NEWS hover 極簡化」拿掉的是背景變色／
      圓角／外框 ring／border-color **四項**，daniel 當時的原話是「news 的 Hover
      這樣太奇怪 圖片放大 箭頭微動就好」—— 他反對的是那一整組裝飾。
      **圓角與 ring 不要加回來。**
   ⚠️ 方向是**往深**不是往白，理由（兩頁的區塊底色相反）寫在 01-tokens.css 的
      --news-row-bg-hover。
   ⚠️ 只在精確指標上掛（同全站 hover 慣例），觸控裝置不會卡在 hover 態。 */
@media (hover: hover) and (pointer: fine) {
  .news-row:hover {
    background-color: var(--news-row-bg-hover);
  }
}

/* .reveal-group.is-armed.is-revealed .reveal（styles.css:1003-1009）用 transition
   簡寫把 transition-property 整個重設為 opacity,transform，特異度 (0,4,0) 蓋過
   .news-row 的 (0,1,0)，且 is-armed/is-revealed 由 site.js 加上後永不移除。本規則
   特異度 (0,5,0)，不依賴原始碼順序的 tie-break（沿用 .card .card__cta:active
   既有先例，styles.css:3334）。
   已知殘留：transform 仍綁在 --motion-duration-enter(400ms)，故 :active 的 1px
   按下位移實跑 400ms 而非宣告的 120ms —— 這是既有狀態、非本次回歸；根治須把
   REVEAL 由 transition 改為 @keyframes + animation（hero-load-in 已有先例，
   styles.css:2173-2181），屬另案。2026-08-19 hover 極簡化：background-color／
   box-shadow／border-color／border-radius 四項已隨 base 規則一併移除，此處同步簡化。 */
.reveal-group.is-armed.is-revealed .news-row.reveal {
  /* ⚠️ **background-color 必須列在這裡,否則 hover 變色不會有過場。**
     這條規則用 transition 簡寫把 transition-property **整個重設**，
     特異度 (0,5,0) 蓋過 .news-row 的 (0,1,0)，而 is-armed/is-revealed 由
     site.js 加上後**永不移除** —— 也就是說進場一播完，base 規則裡宣告的
     background-color 過場就被洗掉了，hover 會變成瞬間跳色。
     這個坑上面那段既有註解已經記過一次（當時是 hover 效果被整組洗掉），
     2026-08-19 極簡化時把它一起簡化掉，現在加回底色就必須同步加回來。 */
  transition:
    opacity          var(--motion-duration-enter) var(--motion-easing-standard),
    transform        var(--motion-duration-enter) var(--motion-easing-standard),
    background-color var(--motion-duration-hover) var(--motion-easing-standard);
}

.news-row > * {
  min-width: 0;
}

/* 2026-08-18 全站微動態規格 P2：hardcode 1px 改 token（本規則未列在矩陣
   8 處明細內，但與同批修正的其餘 :active 規則同一缺陷——字面 1px 繞過
   reduced-motion 安全網，一併修正，屬既有 pattern 的一致性維護）。 */
.news-row:active {
  transform: translateY(var(--motion-press-offset));
}

/* 2026-08-19 用戶當面裁決極簡化 hover：background-color／border-radius／box-shadow
   ring／相鄰列分隔線隱藏四項裝飾已移除，鍵盤 focus 指示改為只靠 outline（3px solid
   + 2px offset，全站標準值，單獨已是合規的清楚指示，不依賴額外背景/ring）。箭頭
   位移與圖片放大兩項與滑鼠 hover 保持同步（鍵盤與滑鼠拿到同一組視覺回饋，此原則
   延續自 R4 既有裁決，只是「同一組視覺」現已簡化）。 */
.news-row:has(.news-row__link:focus-visible) {
  outline: var(--focus-ring-width) solid var(--focus-ring-on-light);
  outline-offset: var(--focus-ring-offset);
}

.news-row:has(.news-row__link:focus-visible) .news-row__arrow svg {
  transform: translateX(var(--space-1));
}

.news-row:has(.news-row__link:focus-visible) .news-row__media .media__img {
  transform: scale(var(--media-scale-hover));
}

.news-row__meta {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.news-row__date {
  font-family: var(--type-role-meta-family);
  font-size: var(--type-role-meta-size);
  line-height: var(--type-role-meta-line-height);
  letter-spacing: var(--type-role-meta-letter-spacing);
  font-weight: var(--type-role-meta-weight);
  color: var(--text-secondary);
}

.news-row__content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-2);
}

/* h4 階：規格只寫「標題（h4，clamp 1 行）」，未給獨立 type-role token；
   --type-role-card-title-* 本身就是 h4 尺度（見既有定義），復用既有角色
   token，不新發明（交接契約 硬約束②）。 */
/* 2026-08-18 全站微動態規格 P3（.u-underline-wipe 定義見 SHARED ATOM LAYER
   區塊）：HTML 端已把 `u-underline-wipe` class 掛在子層 `.news-row__link`
   上（grep index.html 核實），但該元素的 `::after` 已被下方 stretched-link
   佔用（`position:absolute; inset:0`，相對 `.news-row` 撐滿整列可點區）——
   若在 `.news-row__link` 本身建立 `position:relative`，會讓它自己的
   `::after` 的 containing block 從 `.news-row`（整列）縮小成自己的文字寬，
   破壞整列可點擊/可鍵盤觸達區（且 ≤768 grid-template-areas 重排後無法用
   固定 inset 補償，見任務報告）。改在父層 `.news-row__title`（純文字
   wrapper `<h4>`，grep 確認全站零既有 ::before/::after/position 使用）
   建立 positioning context 與底線本體，視覺結果相同（文字緊貼），不觸碰
   `.news-row__link` 的既有規則一個字。 */
.news-row__title {
  font-family: var(--type-role-card-title-family);
  font-size: var(--type-role-card-title-size);
  line-height: var(--type-role-card-title-line-height);
  letter-spacing: var(--type-role-card-title-letter-spacing);
  font-weight: var(--type-role-card-title-weight);
  color: var(--text-primary);
  display: -webkit-box;
  /* ⚠️ 2026-08-26：1 → 2 行（daniel 選了「修首頁新聞列的截斷」）。
     量出來的：**四則標題全部需要 2 行**（1441／1440 實測 2/2/2/2），
     所以 1 行的 clamp 讓四則標題**今天全部被切掉** —— 而且在字級改動之前
     就已經如此，這不是字級造成的，是內容長度對上 1 行 clamp。
     ⚠️ 列高不受影響：`.news-row` 有 `min-height: 168px`，1440 下文字只用到
        約 60px，2 行仍在既有列高之內。
     ⚠️ 1024 與 375 的文字欄只有 290／251px（S4 的欄本身就窄），標題需要 3 行，
        2 行仍會切掉第三行 —— 但「切在第三行」比「只剩第一行」好得多。
     ⚠️ **最後定為 3 行不是 2 行。** 2 行在 1440 就夠（四則都只需要 2），
        但 1024／375 的欄寬只有 290／251px、標題需要 3 行，2 行仍切掉 3/4。
        clamp 放到 3 之後 1440 完全不受影響（沒有標題需要第三行），
        而 1024／375 也不再被切。 */
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.news-row__link {
  color: inherit;
  text-decoration: none;
}

/* stretched link：見本區塊頂部大註解 */
.news-row__link::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
}

.news-row__link:focus-visible {
  outline: none; /* 替代：ring 轉移到 .news-row:has() 規則，非無替代違約 */
}

.news-row__excerpt {
  font-family: var(--type-role-paragraph-family);
  font-size: var(--type-role-paragraph-size);
  line-height: var(--type-role-paragraph-line-height);
  letter-spacing: var(--type-role-paragraph-letter-spacing);
  font-weight: var(--type-role-paragraph-weight);
  color: var(--text-body);
  display: -webkit-box;
  /* ⚠️ 2026-08-26：1 → 2 行。data/news.php 檔頭記過「摘要長度受
     -webkit-line-clamp: 1 硬限制」並為此把四則摘要縮短過 —— 那個限制
     現在放寬了，但**摘要沒有改回長版**（縮短後的版本本身更好，見該檔註解）。
     實測 1440 下只有第 4 則需要 2 行，其餘 1 行；1024／375 需要 2–4 行，
     所以與標題一起放到 3 行。⚠️ 375 有一則需要 4 行，仍會切掉第四行 ——
     那一則的摘要偏長，屬於文案問題不是版面問題。 */
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-width: var(--type-role-paragraph-max-width);
}

.news-row__arrow {
  display: inline-flex;
  color: var(--text-link);
}

.news-row__arrow svg {
  width: var(--news-arrow-size);
  height: var(--news-arrow-size);
  display: block;
  transition: transform var(--motion-duration-hover) var(--motion-easing-standard);
}

.news-row__media .media__img {
  transition: transform var(--motion-duration-hover) var(--motion-easing-standard); /*
     2026-08-19 用戶當面裁決極簡化 hover：新增圖片放大效果，.media 父層已有
     overflow:hidden（styles.css:2660 一帶），縮放不會溢出卡片邊界。 */
}

/* iOS Safari pitfalls #8：hover 專屬樣式收在 hover-capable 裝置內
   （沿用本檔既有慣例，見 .primary-nav__list a:hover 等處）。 */
@media (hover: hover) and (pointer: fine) {
  /* 2026-08-19 用戶當面裁決極簡化 hover（派工單「NEWS hover 極簡化」）：background-color
     變色／border-radius／box-shadow ring／相鄰列分隔線隱藏四項裝飾已移除。用戶原話
     「news 的 Hover 這樣太 奇怪 圖片放大 箭頭 微動就好」——只留圖片放大與箭頭位移兩項。 */
  .news-row:hover .news-row__media .media__img {
    transform: scale(var(--media-scale-hover));
  }

  .news-row:hover .news-row__arrow svg {
    transform: translateX(var(--space-1));
  }
}

/* ≤768：圖上文下，箭頭移到摘要行尾附近（規格 §B S4）。grid-template-areas
   把三個既有 grid item 重新排位，不靠改 DOM 順序、不靠改 --news-row-gap
   以外任何 token 引用（硬約束⑥）。 */
@media (max-width: 768px) {
  .news-row {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "media    media"
      "content  arrow";
  }

  .news-row__media {
    grid-area: media;
  }

  .news-row__content {
    grid-area: content;
  }

  .news-row__arrow {
    grid-area: arrow;
    align-self: end;
  }
}


/* ══════════════════════════════════════════════════════════════════
   跨頁共用元件（2026-08-21 由 pages/inner.css 搬上來）

   .panel / .panel-grid / .anno / .partners 原本住在 pages/inner.css，
   因為當初只有內頁用。首頁新增「平台」與「服務保證」兩區之後它們變成
   **跨頁元件**，而首頁不載 pages/*.css（_head.php:81-86），
   搬到共用層才不會為了幾條規則讓首頁去載整支內頁樣式，也不會出現兩份定義。

   ⚠️ 搬動只改定義位置不改內容。共用層在 pages/*.css **之前**載入，內頁要覆寫仍然有效。
   ⚠️ `.panel` 原本與 `.phase` 是同一條群組選擇器（`.phase, .panel`）。
      第一次搬的時候只抓了 `.panel {` 那一行，留下懸空的 `.phase,` 併進下一條規則 ——
      /services/ 的 33 個元素因此靜默變樣（.phase 失去整個外框），
      是 .deploy/verify-css-refactor.py 抓出來的，肉眼在 diff 上看不出來。
      現在兩邊各自完整，但**外框規格必須一致，改一邊要改兩邊**。
   ══════════════════════════════════════════════════════════════════ */
/* ⚠️ 白底 ＋ 髮絲邊，不是灰底。
   灰底（--surface-subtle）放在 section--subtle 上會同色疊同色**整個看不見**——
   實測踩過。改成白底之後：放白底區靠邊線讀得出來、放淺灰區靠白底讀得出來，
   兩種底都成立，元件不必知道自己被放在哪一種區塊上。 */
.panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5);
  background-color: var(--surface-page);
  border: var(--border-width-hairline) solid var(--border-hairline);
  border-radius: var(--radius-alias-media);
}

/* ── 資訊面板格 ──────────────────────────────────────────────────
   .panel 的盒子樣式與 .phase 共用（見上方）。這裡只給排列容器。
   用於：contact 的辦公室、about 的合作夥伴等沒有圖片的資訊卡。 */
.panel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--card-row-scroll-width)), 1fr));
  gap: var(--space-5);
}

/* 固定四項的面板組。auto-fit 在寬容器下會排成 3 欄，第四張落單（3+1）——
   四項用 2×2 才平衡。項目數不固定的地方仍用 .panel-grid。 */
@media (min-width: 1024px) {
  .panel-grid--pair {
    grid-template-columns: repeat(2, 1fr);
  }
}

.panel__title {
  margin: 0;
  font-family: var(--type-role-card-title-family);
  font-size: var(--type-role-card-title-size);
  line-height: var(--type-role-card-title-line-height);
  letter-spacing: var(--type-role-card-title-letter-spacing);
  font-weight: var(--type-role-card-title-weight);
  font-synthesis: none;
  color: var(--text-primary);
}

.panel__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-family: var(--type-role-meta-family);
  font-size: var(--type-role-meta-size);
  line-height: var(--type-role-meta-line-height);
  color: var(--text-body);
}

.panel__list a {
  color: var(--text-link);
  /* ④ 電話與信箱是觸控目標 */
  display: inline-flex;
  align-items: center;
  min-block-size: var(--space-8);
}

.panel__list a:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-on-light);
  outline-offset: var(--focus-ring-offset);
}

/* 附註文字（狀態、計數之類的附屬資訊） */
.anno {
  font-family: var(--type-role-meta-family);
  font-size: var(--type-role-meta-size);
  line-height: var(--type-role-meta-line-height);
  letter-spacing: var(--type-role-meta-letter-spacing);
  color: var(--text-secondary);
}

/* 夥伴名單：一排 .tag，換行不撐出水平捲動 */
.partners {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-block-start: var(--space-6);
}

/* ⚠️⚠️ `.partners` 裡的 `.tag` 拿掉藥丸外觀 —— **第三次遇到同一個病**
   （2026-09-02，補做 /about/ 時量出來的）。

   量出來的比對（/about/ 的夥伴標籤 vs 同一頁真正的 `.btn--secondary`）：

     | | 夥伴標籤 | 次要按鈕 |
     |---|---|---|
     | 圓角 | 999px | **999px（相同）** |
     | 字級 | 13px  | **13px（相同）** |
     | 底色 ＋ 字色 | 淡藍底 ＋ **藍字** | 透明底 ＋ 深藍字 |
     | 可點 | ✗ | ✓ |

   也就是說**那六個不能點的廠牌名，比頁面上真正的按鈕還像按鈕**。
   根因與前兩次完全相同：`.tag` 吃的是 `--radius-alias-control`，
   而那顆 token 的註解逐字寫著「所有控件：按鈕/chevron/tag/carousel」。

   ⚠️ 這個站已經為同一個病裁決過兩次：
        2026-08-25 eyebrow（「每一個 section 標籤都長得跟連結一模一樣，
                            但它們一個都不能點」）→ 顏色轉中性、字重降回 regular
        2026-08-26 S6 badge（daniel：「那個白色 tag 看起來很像按鈕」）
                            → 拿掉填色與圓角、顏色轉安靜
      這一組**兩次都沒被涵蓋**。處置沿用同一個判準。

   ⚠️ **不改 `.tag` 本身。** 它是規格元件 C10（本檔上方註解：「非互動、無 5 態、
      不得做成 `<a>`」），而它的另一個消費端是 **news 的分類標籤** ——
      那是分類 chip、而且長在可點的卡片／列裡，藥丸外觀在那裡是對的。
      改 base 會把三個 news 版位一起改掉。

   ⚠️ 三個 `.partners` 消費端（/about/ 夥伴列、首頁 assurance 的夥伴列、
      /services/ 的 why 硬事實列，後兩者目前關閉）**都是同一種東西**：
      小標底下一排短字的列舉。所以統一處置，不另立修飾 class。 */
.partners .tag {
  padding-inline: 0;
  border-radius: 0;
  background-color: transparent;
  color: var(--text-secondary);
}

/* 拿掉底色之後相鄰兩個名字會黏在一起，補一個分隔點。
   ⚠️ 用 `·` 不用 `|` 或 `/` —— 與頁尾跑馬燈的分隔符同一顆
      （docs/footer-marquee-slogans.md：視覺重量最輕）。
   ⚠️ `::after` 而不是 `gap` 加大：分隔點要跟著換行走，
      最後一個不印（`:last-child`）。 */
.partners .tag + .tag::before {
  content: "·";
  margin-inline-end: var(--space-2);
  color: var(--border-functional);
}

/* 可點的資訊面板（相關服務卡）。
   ⚠️ hover 只加深邊線、不動底色 —— 淺底 hover 底色那顆 token 仍然不存在
      （見 chevron 那段的說明）。--border-hairline → --border-functional
      兩顆都是既有 token，且後者 4.54:1 足以承載狀態語意。 */
.panel--link {
  text-decoration: none;
  transition: border-color var(--motion-duration-hover) var(--motion-easing-standard);
}

.panel--link:active {
  transform: translateY(var(--motion-press-offset));
}

.panel--link:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-on-light);
  outline-offset: var(--focus-ring-offset);
}

@media (hover: hover) and (pointer: fine) {
  .panel--link:hover {
    border-color: var(--border-functional);
  }
}

/* .section-head 是 flex column，直接塞按鈕會被拉成滿寬。
   ⚠️ 05-blocks.css 的 .news__all 做的是同一件事（首頁 news 區先做的），
      這裡不動它，另立一個泛用名稱給其他區塊用。 */
.section-head__cta {
  align-self: start;
  margin-block-start: var(--space-5);
}

/* .container 沒有 gap —— 區塊內的兄弟元素要自己帶間距。
   （.section-head 有 margin-block-end，但它後面的東西彼此之間沒有。） */
.section-note {
  display: block;
  margin-block-start: var(--space-5);
}

/* ══════════════════════════════════════════════════════════════
   .u-hover-group ＋ .u-underline-wipe（文字版）—— 2026-08-24

   daniel：「不管首頁還是內頁的 service 卡片，滑鼠 hover 的行為要一致」，
   底線要「跟 nav 的類似，由左至右長出來」。

   兩個消費端（首頁 `.card`、/services/ `.svc-axis__stage`）**共用這一條規則**，
   而不是各寫一份 —— 「兩邊一致」如果靠兩份規則維持，遲早會漂。
   容器掛 `.u-hover-group`，要長底線的文字包一層 `.u-underline-wipe`。

   ⚠️ 底線掛在 **eyebrow（「01. Plan」）**，不是標題。daniel 2026-08-24 改判，
      初版做在標題上。eyebrow 是單行短字串，底線約 55px 寬，
      比橫跨兩行標題的底線收斂得多。

   ⚠️ **技法與 nav 的 `.u-underline-wipe::before` 不同，這是刻意的。**
      nav 那版是 `::before` 一條絕對定位的橫槓（`left:0;right:0`），畫出來的線
      **跨滿整個定位容器的寬度**。而 `.eyebrow` 是 block 元素、寬度等於整欄
      （桌機 242px），「01. Plan」本身只佔約 55px —— 用 `::before` 會拉出一條
      超出文字近 190px 的線。
      改用 background-image 漸層掛在 inline 的 `<span>` 上：它依行盒繪製，
      **貼齊文字實際寬度**。視覺語彙（由左至右長出、同一顆
      --border-interactive、同一個 --motion-duration-slide）與 nav 一致，
      只有實作不同。

   ⚠️ `box-decoration-break: clone` 留著。現在的消費端（eyebrow）是單行、
      用不到它，但這是一條**通用工具規則**：哪天掛到會折行的文字上，
      預設的 `slice` 會把折行前後當成同一個背景區域再切開，於是
      `background-size: 100%` 變成「兩行合起來的 100%」，動畫會橫跨兩行
      奇怪地推進。clone 讓每個行盒各自算 100%。
      （初版做在標題上時就是靠它 —— 242px 欄寬下有三支標題會折兩行。）

   ⚠️ 動畫時長走 `--motion-duration-slide`（與 nav 同一顆）。
      `prefers-reduced-motion` 由 02-base.css 的 token 歸零自動涵蓋，
      這裡不寫第二份例外。

   ⚠️ 粗細走 `--border-width-hairline`（1px），**刻意比 nav／footer 那版的
      2px 細**（daniel 2026-08-24：「太粗了，再細一點」）。
      理由站得住：nav 連結是 button-label 字級，eyebrow 是 caption 字級
      （`--type-role-eyebrow-size: var(--type-scale-caption-size)`），
      同樣 2px 的線壓在小一號的字下面就會顯得重。
      用既有 token 而不是字面 1px —— 順帶解掉「:root 以外禁非階梯 px」那條護欄。

   ⚠️ focus-visible 也要觸發：本站既定裁決是「鍵盤與滑鼠拿到同一組視覺回饋」
      （見 .card:has(.card__cta:focus-visible) 與 .news-row 的既有規則）。
      這裡用 `:has(a:focus-visible)` 而不是限定某個 class，因為兩個消費端的
      CTA class 名不同（.card__cta／.svc-axis__cta），而它們都只有一個 <a>。
   ══════════════════════════════════════════════════════════════ */
/* stretched link 覆蓋層的拖放抑制（2026-08-24）。

   ⚠️ 這是 draggable="false" 的第二道保險，針對**偽元素**：
      覆蓋層是 ::after，掛不上 HTML 屬性，只能靠 CSS。
   ⚠️ -webkit-user-drag 是非標準屬性，但這是 WebKit／Blink 上唯一能對
      偽元素關掉原生拖放的方法；Firefox 走 <a>／<img> 的 draggable 屬性。
      兩條合起來才涵蓋主流三引擎。
   ⚠️ 這**不是**「整卡點不進去」的根因（先前誤判）。根因在 05-blocks.css 的
      `.card .card__cta:active`，那裡有完整說明。本規則單純是擋原生拖放：
      按住後拖動會啟動 HTML5 拖放，在一張整格可點的卡上是干擾。
      site.js 的 D7 原本擋著它，rail 停用後不再掛上，這裡接手。 */
.card__cta::after,
.svc-axis__cta::after {
  -webkit-user-drag: none;
}


/* lucide() 行內圖示的基礎樣式（2026-08-24，Scope 是第一個消費端）。
   ⚠️ 只給尺寸與盒模型，**不給顏色** —— svg 是 stroke="currentColor"，
      顏色由消費端的文字色決定，這樣圖示永遠跟著它旁邊的字走。
   ⚠️ display:block 是必要的：inline 的 svg 會帶著行內盒的 baseline 間隙，
      在 flex/grid 項目裡會多出幾 px 的莫名下緣留白。 */
.licon {
  display: block;
  inline-size: var(--licon-size);
  block-size: var(--licon-size);
  flex-shrink: 0;
}


.u-hover-group .u-underline-wipe {
  /* ⚠️ 顏色沿革（2026-08-25 一天內來回兩次，兩次都記著）：
       原本  --border-interactive（accent-600）
       二修  currentColor —— daniel「底線顏色要跟字一樣」
       三修  改回 --border-interactive —— daniel「服務卡片微動態底線也改成品牌的藍」
     現行與 eyebrow 的前導線同一顆 token，兩處一起看才不會又漂開。
     ⚠️ 兩個消費端（首頁 .card／`/services/` 的 .svc-axis__stage）都在**淺底**上，
        accent-600 對白 6.02:1、對灰 5.42:1，遠高於非文字門檻 3:1。
        哪天有卡片落到深底上，要比照上面 eyebrow 的作法補一條 on-inverse。
     ⚠️ 這裡**不能用 background-color** —— 動畫是靠 background-size 從 0% 長到
        100%，需要一張「圖」可以被裁；純色背景沒有尺寸可言。所以是
        linear-gradient 出來的一張單色圖。 */
  background-image: linear-gradient(var(--border-interactive), var(--border-interactive));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 var(--border-width-hairline);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  transition: background-size var(--motion-duration-slide) var(--motion-easing-standard);
}

@media (hover: hover) and (pointer: fine) {
  .u-hover-group:hover .u-underline-wipe {
    background-size: 100% var(--border-width-hairline);
  }
}

.u-hover-group:has(a:focus-visible) .u-underline-wipe {
  background-size: 100% var(--border-width-hairline);
}


/* ⚠️ 只給間距、**不碰 display** 的版本。
   .section-note 帶著 display:block，套到 grid／flex 容器上會把版型整個打掉 ——
   實測把 About 的四張卡從三欄壓成單欄（display:grid 被蓋掉）。
   容器要間距時用這個。 */
.u-space-above {
  margin-block-start: var(--space-6);
}

.section-divider {
  margin-block: var(--space-8) var(--space-6);
}


/* ══════════════════════════════════════════════════════════════════
   .scope-peek / .why-list — 2026-09-02 由 pages/inner.css 搬上來

   ⚠️ **搬家的理由是多了一種頁型的消費端，不是整理癖。**
      CSP 改版在**首頁**新增了 Use Cases 區塊，版型直接沿用既有的 `.why-list`
      （左圖示 ＋ 右「硬事實／標題／描述」）。而 `pages/inner.css` 只有
      /about/、/services/、服務內頁、/news/、/contact/ 會載，**首頁不載** ——
      不搬的話首頁那一區會完全沒有樣式，而且不噴任何錯。

   ⚠️ **不選「首頁改成也載 inner.css」**：那支去掉註解仍有約 25KB 的規則，
      為了一個元件讓首頁多一支 render-blocking 樣式表，而合約驗收有
      Lighthouse ≥80。搬 ~100 行過來便宜得多。

   ⚠️ **規則內容一個字都沒改**，只是換檔案。連原本的註解一起搬 ——
      那些註解記的是量出來的判準（斷點為什麼是 1024、左欄為什麼放圖示而不是
      key、`.u-space-above` 那條層疊衝突），丟掉等於把教訓丟掉。

   ⚠️ **`.why-list.u-space-above` 那條補丁仍然必要，而且現在更穩。**
      它原本靠「inner.css 載入在後」才贏不過 —— 不對，是靠**兩個 class 的
      特異性 (0,2,0)** 贏過工具類的 (0,1,0)。搬到同一支檔案之後這一點不變，
      與載入順序無關。

   ⚠️ `.scope-peek` 一起搬是因為 `.why-list` 的 hover 預覽圖靠它。它同時仍是
      服務內頁 `.scope-list` 的預覽圖，載到全站不影響那邊（本檔每頁都載）。
      節點由 assets/js/inner.js 建立並掛在 <body> 上，**所以消費頁必須宣告
      `$page['js'] = ['inner']`** —— 忘了宣告是靜默失效（規則 8-3）。
   ══════════════════════════════════════════════════════════════════ */

/* ── 游標預覽圖（2026-08-24，daniel：「hover 的時候顯示該項的圖片然後跟著游標移動」）──

   ⚠️ **純裝飾**：aria-hidden ＋ alt=""。它只在精確指標 ＋ hover 時出現，
      讀屏使用者永遠看不到；意義完全由 label 承擔，所以不該進無障礙樹。
   ⚠️ position: fixed —— 跟的是**視窗座標**（pointer 的 clientX/Y）。
      用 absolute 的話得減去容器位移，捲動時還會漂。
   ⚠️ pointer-events: none 不能省：它跟著游標跑，會一路擋在指標下面，
      不關掉的話滑過清單時 hover 會在「項目」與「預覽圖」之間狂閃。
   ⚠️ 只在 (hover: hover) and (pointer: fine) 掛，且 reduced-motion 下完全不啟用
      —— 那是一個**跟著游標跑的東西**，不是可以只把時長歸零就安全的過場。
      JS 端也擋一次（見 assets/js/inner.js），CSS 這層是第二道。 */
.scope-peek {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: var(--z-hero-scrim);
  inline-size: var(--scope-peek-width);
  border-radius: var(--media-radius-sm);
  overflow: hidden;
  /* ⚠️ 這是 --elevation-level3 的**第二個**消費點（第一個是 .site-header__bar::before）。
     那顆 token 的註解禁止套用在「nav-overlay panel 或卡片」上 —— 這兩者都不是：
     它是一張真的浮在頁面之上、跟著游標跑的圖，不加陰影會讀成「貼在版面上的一塊」。
     全站也就只有這兩處需要真陰影，其餘一律走 hairline 語言。 */
  box-shadow: var(--elevation-level3);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--motion-duration-hover) var(--motion-easing-standard);
  will-change: transform;
}

.scope-peek.is-on {
  opacity: 1;
}

.scope-peek img {
  display: block;
  inline-size: 100%;
  block-size: auto;
}

/* ══════════════════════════════════════════════════════════════════
   .why-list — /about/ 的「Why Board Sea」四點（2026-08-26，daniel：
   「下面這些卡片目前太像 services 的 related services，看要不要改成
   services 的 scope 那種 layout」）

   他的觀察是**精確的**：改版前那四張是 `.panel`，而 related services 用的是
   `.panel--link` —— **同一個元件**，只差一段內文，所以看起來一樣是必然的。

   ⚠️ **這是「左欄清單」家族的第四個成員，不是新語彙：**
        .scope-list   圖示  ｜ 一行 label            服務內頁 Scope
        .step-list    編號  ｜ 標題 ＋ 描述           四處流程
        .region-list  國碼  ｜ 名稱／描述／狀態        /about/、/contact/
        .why-list     圖示  ｜ 硬事實 ＋ 標題 ＋ 描述   本區塊
      四者共用同一套：左窄欄 ＋ 右內容、髮絲線分隔、不用框。
      ⚠️ **家族已經四個了，第五個出現時就該把骨架抽共用**（規則 12）。
         現在沒抽，是因為抽要同時動三個既有消費端（跨 7 頁），
         而共用的部分只有約 10 行；風險大於收益。

   ⚠️ **左欄放圖示，不放 key。** 量過了：那四個 key 是 3–15 個字元
      （`RCS` vs `1hr / 4hr / NBD`），左欄要照最長的開，`RCS` 那一列就會浮在
      130px 的空白裡。`.region-list` 拿國碼當左欄行得通，是因為它們都是兩個字母。
      key 改當 eyebrow 留在右欄第一行，硬事實照樣站在最前面。

   ⚠️ **兩欄的斷點是 1024 不是 .scope-list 的 768。** scope 的右欄只有一行
      label，768 下切兩欄還讀得動；這裡右欄有標題 ＋ 內文，768 兩欄各只有
      330px，標題會折三行。1024 是站上既有的斷點值（同 .region-list、
      .step-block--with-media），**不另立新值** —— 四斷點掃描
      （1440/1024/768/375）才掃得到那一段。

   ⚠️ **單欄不是選項。** 內文受 .prose 的 540px 上限，而 1440 的容器是
      1305px —— 單欄只用得掉 41%，右邊空 765px。那正是 2026-08-25 daniel
      對 /about/ footprint 清單說的「右半邊空間太多」。
   ══════════════════════════════════════════════════════════════════ */
.why-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
}

/* ⚠️ **這一條不是重複宣告,是在修一個實測到的層疊衝突。**（2026-08-26，
   daniel：「圖片跟下面的欄位 border 黏在一起了」）
   `.u-space-above` 是 `04-components.css` 的工具類（`margin-block-start:
   var(--space-6)`），特異性與 `.why-list` **完全相同**（都是 0,1,0），
   而 `pages/inner.css` **載入在後** —— 所以上面那條 `margin: 0` 會贏，
   實測 `margin-block-start` 被壓成 **0px**，`.split` 的圖片底緣與清單
   第一列的髮絲線**直接貼在一起**（1440 量到距離 0）。

   ⚠️ 症狀只在**圖比文字高**的斷點出現：1440 圖底 942／文字底 856 → 0px；
      1024 圖底 915／文字底 941 → 26px；768 與 375 已堆疊 → 268／370px。
      所以只看窄斷點會以為沒問題。
   ⚠️ **不改 `.u-space-above` 本身**：它是全站共用的工具類，為了一個消費端
      去提高它的特異性（例如加 `!important`）會影響到別處。
   ⚠️ 值刻意**照抄工具類的 `--space-6`**，不自己另訂一個 —— 這裡要修的是
      「工具類沒生效」，不是「這裡需要不一樣的間距」。 */
.why-list.u-space-above {
  margin-block-start: var(--space-6);
}

@media (min-width: 1024px) {
  .why-list {
    grid-template-columns: repeat(2, 1fr);
    column-gap: var(--space-8);
  }
}

.why-list__item {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-4);
  align-items: start;
  padding-block: var(--space-6);
  border-block-start: var(--border-width-hairline) solid var(--border-hairline);
}

/* 圖示走 eyebrow 的藍，與 .scope-list__icon 同一個決定：
   顏色下在消費端，.licon 只給尺寸（svg 吃 currentColor）。 */
.why-list__icon {
  display: flex;
  color: var(--text-eyebrow);
}

/* 右欄三層：硬事實（eyebrow）→ 標題 → 內文。
   ⚠️ 這裡的 .eyebrow **不會長出前導髮絲線** —— 那條規則是正面列舉的
      （.section-head / .split__content / .cta-band__in / .page-hero），
      .why-list__body 不在名單上。這是對的：它是資料點，不是區塊起點。 */
.why-list__body {
  display: grid;
  gap: var(--space-3);
}

/* 字級沿用 .panel__title（card-title role）—— 換的是版型不是字級階梯。 */
.why-list__title {
  margin: 0;
  font-family: var(--type-role-card-title-family);
  font-size: var(--type-role-card-title-size);
  line-height: var(--type-role-card-title-line-height);
  letter-spacing: var(--type-role-card-title-letter-spacing);
  font-weight: var(--type-role-card-title-weight);
  font-synthesis: none;
  color: var(--text-primary);
}
