/* ==========================================
   index.html 專屬樣式
   （home-01 header/公告列共用樣式已寫入 style.css，
   此檔留給後續 Hero / 課程 / 消息等區塊專屬調整）
   ========================================== */

/* ==========================================
   home-01：Hero 輪播
   ========================================== */
/* 🔴 hero 現在是**三段三值**，不是一個基準比例加例外。三段各有各的 PM 定案：

   | 寬度 | 比例 | 誰定的 | 理由 |
   |---|---|---|---|
   | `<640`（手機） | **`16 / 9`** | **W1（PM 2026-09-01）** | 要與「成為專屬夥伴」相簿輪播（`.gallery-item`，16/9）**同一個比例** |
   | `640–1023`（平板） | `2 / 1` | V5（PM 2026-08-31） | 13/5 在 768 只有 295px，照片太扁 |
   | `≥1024`（桌機） | `13 / 5` | U1（PM 2026-08-31） | 16/9 在 1920 是 1080px 高，正是客戶嫌太高的那個高度 |

   🔴 **不要為了「一致」把三段統一成同一個比例**——三次都是各自的 PM 定案，
      各有理由（U1 針對桌機太高、V5 針對平板太扁、W1 要手機與相簿輪播同比例）。
      這也符合本專案的規矩「每個區塊照它自己的內容決定斷點」（`CLAUDE.md` 六節）。
   ⚠️ 檔頭那條 `.hero` 的 `13 / 5` 現在的角色是「桌機值 ＋ 保底值」：
      它同時服務 ≥1024，並確保任何沒被兩段媒體查詢涵蓋的情況也有比例可用
      （沒有比例 hero 會塌成 0 高，子元素全是 `position: absolute`）。

   ⚠️ **W1 的「一樣尺寸」是一樣比例、不是一樣絕對高度**（PM 2026-09-01 已知並接受）：
      375 寬時 hero 是滿版 375px → 高 210.9px，而 `.gallery-item` 兩側各有
      `--page-gutter` 24px、只有 327px 寬 → 高 183.9px。**兩者差 27px 是預期的，不要再去調。**
   ⚠️ 639/640 之間高度仍會跳一階（211 → 320px），**那是刻意的**：
      平板是「一整塊照片」的閱讀距離，手機是「一條 banner」。

   ── 這推翻了 S3（PM 2026-08-26）的 `16 / 9` ──
   S3 把比例改成 16/9 的理由是「S2 把標語整組移走、客戶指定照片完整呈現」，
   但 16/9 在 **1920 寬時 hero 高 1080px**——**那正是客戶 8/25 嫌太高的那個高度**，
   S3 當下就預期會被退回（原本 `13 / 5` 的規則因此被註解保留在 ≥1024 那一段）。
   PM 2026-08-31 定案改回 13/5，那段註解已依約刪除。
   ⚠️ **被推翻的只有「比例」這一件。** S2 的其餘定案全部維持：
      hero 上**不放任何文字**、標語與 CTA 留在下方理念區、hero **刻意沒有 `data-aos`**。
   ⚠️ 也推翻了 R25／R26「13/5 只寫在 ≥1024、`<1024` 靠 `min-height: 520px` 保底」的做法
      ——本次 PM 明確要等比縮放，**保底條不要加回來**。
      （`min-height` 原本存在的理由是「撐住文字不被裁」，文字沒了就沒有對象要保護。）

   ⚠️ **各寬度的實際高度**（W1 之後）：
      `13/5` 段 → 1920→738／1440→554／1280→492／1024→394
      **`2/1` 段 → 1023→512／768→384／640→320**
      **`16/9` 段 → 430→241.9／375→210.9／320→180.0**
      ⚠️ V2 把 `<640` 的快速按鈕重疊拿掉了，W2 又補上 16px 間距，
         所以那 211px **是完整露出的**（之前有 28px 被卡片壓住）。

   ── 三條不可以「順手優化」掉的警語 ──
   🔴 **不要以「文字被裁了」為由把 ≥1024 改回 16:9**（R25／R26 立的，至今成立；
      何況 hero 上本來就已經沒有文字了）。W1 只把 **`<640`** 改成 16/9，桌機沒有動。
   🔴 **也不要改用 `contain` 或 `100% auto` 想「兩全其美」**：照片是 16:9、框比它寬，
      幾何上不可能同時滿足「壓低高度」與「照片完整」。要兩者兼得只能另備一組裁切版。
   ✅ **`<640` 的 16/9 是零裁切**：照片本身就是 16:9，框比 ＝ 圖比 → `cover` 不裁
      （2026-09-01 六張圖逐張實測）。下面那套「頭有沒有被切」的取捨只適用於 ≥640 的兩段。
   🔴 **13/5 的框比照片寬，`cover` 會上下各裁掉一截（1920 下各 15.8%）
      ——這是已知並接受的取捨（PM 2026-08-31），不是 bug。**

   ── 為什麼是 13/5 而不是更扁（R26，2026-08-25 六張圖實測）──
   以 `newhero-03`（八人合照，六張裡構圖最嚴格的一張）實測 1920 寬：

   | 比例 | 高 | 上下各裁 | 結果 |
   |---|---|---|---|
   | `32 / 9` | 536 | 25.0% | 🔴 **整排頭不見**，只剩肩膀以下 |
   | `3 / 1` | 635 | 20.4% | 🔴 髮際線被切，頭頂缺一塊 |
   | `2.8 / 1` | 680 | 18.3% | ⚠️ 最高的那位頭髮仍被切到 |
   | **`13 / 5`** | **733** | **15.8%** | ✅ **六張的頭全部完整，還留一點頭上空間** |
   | `21 / 9` | 816 | 11.9% | ✅ 更寬鬆，但已接近原本的高度 |

   🔴 **判準是「頭有沒有被切」，不是裁掉幾 %——而且六張都要看過。**
      `newhero-02` 在 `32 / 9` 下頭是完整的，**只看那一張會以為減半沒問題**。
      日後再調比例，一樣要把六張全部重看一次（用 `cover` 裁切後的實際結果，不是原圖）。
   ⚠️ `newhero-06` 的背板「領航金獎」與最下方白色橫幅看不到（那兩段就在最邊緣）。
      完整版由別處承擔：「成為專屬夥伴」輪播（16:9、零裁切）與燈箱（完整比例）。

   ⚠️ M2 的「斷點 × 字級」九宮格早在 Q1 就整組拆掉了（那是三組文案高度會跳動時的解），
      **不要再加回來**——現在 hero 裡連文字都沒有，高度只由寬度決定。 */
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  /* 🔴 這一行是**桌機（≥1024）的值，同時當所有寬度的保底**——不是「所有寬度都 13/5」。
     `<640` 由 W1 覆寫成 `16 / 9`、`640–1023` 由 V5 覆寫成 `2 / 1`，見檔頭那張表。
     ⚠️ 寫在這裡（不是只寫在 ≥1024）是刻意的：<1024 原本只有 `min-height` 保底，
        而保底已隨文字一起移除，不給比例的話 hero 會塌成 0 高
        （子元素全是 `position: absolute`，沒有任何東西能撐出高度）。
     ⚠️ ≥1024 那段原本另有一份被註解掉的 `aspect-ratio: 13 / 5`，
        U1 合併到這一行之後**已整段刪除**——同一個屬性留兩份宣告就是隱形分叉。 */
  aspect-ratio: 13 / 5;
  /* 🔴 **`width: 100%` 不可省，少了會橫向溢出 800px。**（2026-08-25 實測踩到）
     `aspect-ratio` 遇到「行內尺寸不是明確值」時，Chrome 會反過來**用高度去推寬度**
     （當時是 32/9 ＋ min-height 520：520 × 32/9 ＝ **1849px**，
     1024 視窗下 `.hero` 寬 1849、整頁橫向捲動 825px）。
     🔴 **1920 量不到那個 bug**（那裡推回去的寬度剛好也是 1920）——**只驗一種寬度會整個漏掉**。
     ⚠️ S3 拿掉 `min-height` 之後觸發條件消失，但這一行仍然留著：
        它成本為零，而下一個人若因為某個理由再加一次高度保底，這行就是唯一的防線。 */
  width: 100%;
  background-color: var(--purple-950);
}

/* 🔴 背景圖的**單一來源就在這裡**（HTML 只有幾個空的 div，`data-hero-slide` 是編號）。
   寫在 CSS 而不是 JS，是為了「JS 沒跑第一張仍然看得到」；
   寫在 CSS 而不是 HTML 的 inline style，是專案禁用 inline style（全域守則）。
   ⚠️ 換圖只改這幾行；檔名一律**小寫 .jpg**——
      macOS 檔名不分大小寫，`.JPG` 在本機怎麼測都正常，Linux 主機上線才破圖。
   🔴 **增減張數要同時改 `index.html` 的 `.hero-slide` div**，這裡是「編號 → 檔名」，
      張數由 HTML 決定（`script.js` 讀 `querySelectorAll('.hero-slide').length`，
      不必動 JS）。⚠️ 編號要從 1 連號，跳號的那一張會變成**沒有背景圖的黑格**。

   🔴 **`newhero-03` 已於 2026-08-25 移出 hero**（客戶：「這張移除，因為頭會被切掉」）。
      它是八人合照、頭距離上緣最近，hero 是寬幅裁切、最吃虧的就是這種構圖。
      ⚠️ **檔案不要刪**：它仍在「成為專屬夥伴」輪播（16:9、零裁切）
         與活動花絮兩本相簿的封面用著。 */
.hero-slide[data-hero-slide="1"] { background-image: url('../../images/hero/newhero-01.jpg'); }
.hero-slide[data-hero-slide="2"] { background-image: url('../../images/hero/newhero-02.jpg'); }
.hero-slide[data-hero-slide="3"] { background-image: url('../../images/hero/newhero-04.jpg'); }
.hero-slide[data-hero-slide="4"] { background-image: url('../../images/hero/newhero-05.jpg'); }
.hero-slide[data-hero-slide="5"] { background-image: url('../../images/hero/newhero-06.jpg'); }

/* 🔴 JS 沒跑時只留第一張：`.is-ready` 由 script.js 加上（見那一段的說明）。
   用 `display: none` 而不是 opacity，是因為 display:none 的元素**瀏覽器不會去下載背景圖**
   ——六張共約 1.6MB，首屏只該付第一張的流量。
   ⚠️ 特異性 (0,3,0) 高於 `.hero-slide` 的 (0,1,0)，不必 !important（專案禁用）。 */
.hero-slides:not(.is-ready) .hero-slide + .hero-slide {
  display: none;
}

.hero-slide {
  position: absolute;
  inset: 0;
  background-size: cover;
  /* 使用者 2026-09-14：寬幅裁切從上緣對齊，合照人物的頭才不會被切掉 */
  background-position: top center;
  opacity: 0;
  transition: opacity 1s ease;
}

.hero-slide.is-active {
  opacity: 1;
}

/* 首頁大圖（banner）進場（使用者 2026-09-19：要華麗、要有時間差）——時間軸：
     0s        整組淡入（1.2s）
     0s～8s    目前這張照片從 1.15 倍慢慢收回原尺寸（Ken Burns）；每換一張都會重播（輪播每 6 秒一張）
     0.5s      一道淡金色光帶從左掃到右（只跑一次）
     0.7s／0.85s 左、右箭頭各自從外側滑入
   🔴 用 CSS 關鍵影格、不用 data-aos：hero 是首屏最大的圖，data-aos 要等頁尾十支 CDN 腳本載完、
      AOS 初始化才解除隱藏，首屏會先空白一段；關鍵影格第一次繪製就開始跑、不依賴 JS。
   🔴 淡入掛在 .hero-slides、縮放掛在 .hero-slide.is-active，分開是刻意的：
      ・opacity 不能掛在 .hero-slide——動畫的最終值會蓋掉輪播用的 opacity 0／1，五張全部同時可見；
      ・transform 不能掛在 .hero-slides——它是 0 高的靜態容器，有 transform 就會變成
        absolute 投影片的包含區塊，動畫期間整張 hero 圖塌成 0 高。
   ⚠️ Ken Burns 的 8 秒比輪播間隔 6 秒長：換張時那張已經收回 99% 以上，拿掉動畫也看不出跳動。
   ⚠️ 箭頭滑入用獨立的 translate 屬性，不用 transform：箭頭自己用 transform 做垂直置中，兩者會疊加而不是互相覆蓋。
   ⚠️ 箭頭用 fill-mode backwards：跑完交還原本樣式，不會用最終值壓住 .carousel-arrow:disabled 這類狀態。 */
@keyframes hero-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes hero-kenburns {
  from { transform: scale(1.15); }
  to   { transform: none; }
}

@keyframes hero-sweep {
  from { transform: translateX(-150%) skewX(-20deg); opacity: 0; }
  20%  { opacity: 1; }
  to   { transform: translateX(350%) skewX(-20deg); opacity: 0; }
}

@keyframes hero-arrow-in-left {
  from { opacity: 0; translate: -48px 0; }
}

@keyframes hero-arrow-in-right {
  from { opacity: 0; translate: 48px 0; }
}

.hero-slides {
  animation: hero-fade-in 1.2s ease-out backwards;
}

.hero-slide.is-active {
  animation: hero-kenburns 8s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* 光帶：蓋在照片上、箭頭底下（箭頭 z-index 3），pointer-events: none 不擋點擊；.hero 有 overflow: hidden 會把它裁掉 */
.hero::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  width: 35%;
  background: linear-gradient(90deg, transparent, rgba(255, 226, 170, 0.35), transparent);
  pointer-events: none;
  animation: hero-sweep 1.6s ease-in-out 0.5s both;
}

.hero-arrow-prev {
  animation: hero-arrow-in-left 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.7s backwards;
}

.hero-arrow-next {
  animation: hero-arrow-in-right 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.85s backwards;
}

@media (prefers-reduced-motion: reduce) {
  .hero-slides,
  .hero-slide.is-active,
  .hero-arrow-prev,
  .hero-arrow-next {
    animation: none;
  }

  .hero::after {
    display: none;
  }
}

/* 首頁進場動畫：各區塊的 AOS 類型與時間差寫在 pages/home.php 與 site.js（課程卡、消息、連結卡），這裡只調位移大小。
   aos.css 預設的 100px／0.6 倍太猛，首頁用「看得出層次、但不晃」的量：左右 48px、放大從 0.88 倍、浮起 60px＋0.85 倍。
   權重 0,2,1 壓過 aos.css 的 0,1,0 與 style.css 全站的 0,1,1，但低於 .aos-animate 的 0,3,0（播完回到原位）。 */
.page-home main [data-aos="fade-left"] {
  transform: translate3d(48px, 0, 0);
}

.page-home main [data-aos="fade-right"] {
  transform: translate3d(-48px, 0, 0);
}

.page-home main [data-aos="zoom-in"] {
  transform: scale(0.88);
}

.page-home main [data-aos="zoom-in-up"] {
  transform: translate3d(0, 60px, 0) scale(0.85);
}

/* 從右側滑入（消息列表、區塊右側按鈕）在動畫開始前會往右凸出 48px，貼著視窗右緣的會撐出橫向捲軸、畫面左右晃一下。
   ⚠️ 用 clip 不用 hidden：hidden 會讓 main 變成捲動容器；clip 只裁 x 軸，快速連結往上疊到大圖的部分（y 軸）不受影響。 */
.page-home main {
  overflow-x: clip;
}

/* 🔴 S2（客戶 2026-08-26）：**hero 上不再有任何文字**——客戶不喜歡照片被擋住。
   標語與內文整組搬到下方的「公會理念」區（見本檔 `.creed`），
   所以下面這幾組規則**已全部刪除**，不是漏寫：

   | 已刪除 | 原本負責什麼 |
   |---|---|
   | `.hero-inner` | 文字容器：max-width 1440 ＋ 兩倍內距、上下 56/72、flex 置中 |
   | `.hero-content` | 文字區底色 `rgba(26,17,33,0.60)`（照片遮罩拿掉後讓白字可讀） |
   | `.hero-title` / `.hero-desc` | 標題 2.125→2.5→3rem、內文 1.25rem，皆白字 |
   | `--hero-arrow-lane`（0px；640 起 36px） | 文字要往內縮多少才不會被左右箭頭壓到 |
   | `<640` 的 `.hero-inner { padding-bottom: 168px }` | 箭頭移到下方時給文字讓位 |

   🔴 **它們全部只服務「hero 上的文字」，文字沒了就一個消費端都不剩**
      ——留著就是隱形分叉（下一個人會以為 hero 還有文字要排版）。
   ⚠️ 要復原（例如客戶看過實機後想把標語放回 hero）：`git show 13179fe:index.css`。
   ⚠️ **箭頭定位不受影響**：`.hero-arrow-prev/next` 用的是
      `max(4px, calc((100% - var(--container-max)) / 2 - 64px))`，與那條走道變數無關。
   ⚠️ `style.css` 檔頭有幾則註解拿 `.hero-inner` 當「max-width ＋ padding」的範例，
      規矩本身沒變（`.quicklinks`／`.register-inner` 仍是活的範例），
      但那幾句提到的元素已不存在——**已回報，不要各自去改 style.css**。
   ⚠️ `script.js` hero 輪播那段的註解還寫著「進場動畫交給 `.hero-content` 的 data-aos」
      ——那句在 Q1 就不成立了（hero 從那時起就沒有 data-aos），本輪之後連元素都沒了。
      **同樣已回報，本線不動 script.js。**

   ⚠️ Q1 的兩條舊決定仍然有效，不要「順手」加回來：
      ・蓋滿整張照片的 `.hero-overlay` 已整個移除（客戶不喜歡照片被壓暗）；
      ・`.hero-eyebrow`（「稅務智庫．專業領航」）已移除，不要自己編第三句。 */

/* 🔴 尺寸／形狀／圖示大小由 style.css 的 `.carousel-arrow` 提供（全站五處共用一份）。
   這裡只留**定位**與 hero 專屬的**配色**：它疊在活動照片上，
   深紫實心會過重、也可能與照片撞色，所以用半透明白＋白邊框＋輕微模糊。
   ⚠️ `.carousel-arrow` 設了 `border: none` 與 `box-shadow`，這裡各覆寫一次
      （同權重 (0,1,0)，靠 index.css 排在 style.css 之後勝出）。
   🔴 **不要在這裡重新宣告 width／height／border-radius**——那正是先前分叉的成因。 */
.hero-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  background-color: rgba(255, 255, 255, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.35);
  /* 照片上不需要投影，會糊成一團 */
  box-shadow: none;
  backdrop-filter: blur(2px);
}

.hero-arrow:hover,
.hero-arrow:focus-visible {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
}

.hero-arrow-prev {
  left: 4px;
}

.hero-arrow-next {
  right: 4px;
}

/* 🔴 手機（<640px）：兩顆箭頭移到 hero 正中間下方並排，不再貼左右兩側。
   客戶 2026-08-12 定案。理由是這個寬度不管文字怎麼往內縮都會撞到箭頭
   ——標題本來就要用滿整個寬度才排得下。

   ⚠️ **任何情況下都不可以直接把箭頭隱藏**：hero 沒有圓點指示器，
      這兩顆是唯一的手動控制，藏起來等於只剩自動輪播。

   斷點取 max-width: 639px 而不是別的值，是為了與下面 min-width: 640px 那一段
   嚴絲合縫（639/640 之間沒有空隙也沒有重疊）；640 也是本專案既有的斷點之一，
   不另開一個只有這裡用得到的新斷點。

   🔴 bottom **V2（2026-08-31）由 56px 改成 16px**——原本的算式是
     ・.quicklinks 用 margin-top: -40px 疊在 hero 底部，且 z-index 5 > 箭頭的 3，
       箭頭若放在 40px 以內會被那張卡片蓋住（而且不會報錯，只是按不到）
     ・56 - 40 = 16px 是箭頭與卡片上緣的實際間隙
   V2 拿掉了那 40px 的重疊，所以同樣的 16px 間隙 ＝ bottom: 16px。
   🔴 **若日後把重疊加回來，這個值要一起改回去**（兩者是綁在一起的，改一邊不會報錯）。
   置中算式：兩顆 40px ＋ 中間 8px ＝ 88px，所以各自距中線 44px 與 4px。 */
/* 🔴 V5（PM 2026-08-31）：平板 640–1023 的 hero 改用 `2 / 1`，不是檔頭的 13/5。
   理由見檔頭那段——768 在 13/5 下只有 295px，PM 看實機後要求加高。
   ⚠️ **上下界都要寫死**：少了 `max-width: 1023px`，桌機也會被蓋成 2/1
      （同特異性、排在後面就贏），1920 會變成 960px 高 ＝ 回到客戶嫌過的高度。
   ⚠️ 照片是 16:9（1.78），2/1 仍然比它寬 → `cover` 仍會上下各裁一截，
      但比 13/5 少（各約 11% vs 15.8%），六張圖的頭一樣都在。 */
@media (min-width: 640px) and (max-width: 1023px) {
  .hero {
    aspect-ratio: 2 / 1;
  }
}

@media (max-width: 639px) {

  /* 🔴 W1（PM 2026-09-01）：手機 hero 改用 `16 / 9`，與「成為專屬夥伴」相簿輪播
     （`.gallery-item`，同樣是 16/9）**同一個比例**。
     原本吃檔頭的 13/5，375 寬只有 144.2px，PM 看實機後要求加高到與輪播一致。
     ✅ 照片本身就是 16:9 → 框比 ＝ 圖比 → **`cover` 零裁切**（六張逐張實測）。
     ⚠️ 絕對高度仍與輪播差 27px（hero 滿版、輪播兩側各有 24px gutter），
        **那是預期的，不要為了「數字一樣」再去調**。 */
  .hero {
    aspect-ratio: 16 / 9;
  }

  .hero-arrow {
    top: auto;
    /* 🔴 V2 之後這個值要跟著重算：原本 56px ＝「40px 的卡片重疊 ＋ 16px 間隙」，
       而 V2 已經把重疊拿掉，卡片上緣就是 hero 下緣。
       留著 56px 會讓兩顆箭頭浮在只有 144px 高的照片正中央（實測會蓋住人臉那一帶）。
       改成 16px ＝ 維持原本那 16px 的間隙，意圖不變、只是基準點換了。 */
    bottom: 16px;
    transform: none;
  }

  .hero-arrow-prev {
    left: calc(50% - 44px);
    right: auto;
  }

  .hero-arrow-next {
    left: calc(50% + 4px);
    right: auto;
  }

  /* ⚠️ S2 之前這裡還有一條 `.hero-inner { padding-bottom: 168px }`
     （箭頭移到下方後要給文字讓位）。hero 上已經沒有文字，該讓的對象不存在，已刪除。
     🔴 **但上面那三條箭頭定位不可以跟著刪**：hero 沒有圓點指示器，
        這兩顆是唯一的手動控制。 */

  /* 🔴 M2 原本在這裡有 `html.fs-md .hero { height: 705px }`／`fs-lg 805px`。
     Q1 改用 min-height 之後**內容自己會把框撐高，不會裁字**，那兩條沒有作用了，
     已刪除。⚠️ 不要「補回來比較保險」——留著只會多兩個改文案時要一起維護的數字。
     （若日後真的改回固定 `height`，那條特異性陷阱會一起回來：
      `html.fs-lg .hero` 是 (0,2,1)、`.hero` 是 (0,1,0)，**特異性贏過來源順序**，
      所以那種覆寫一定要有 `max-width` 上界，否則會蓋到大螢幕去。） */
}

/* ⚠️ S2（2026-08-26）：原本這裡有一段 `@media (min-width: 640px)`，
   只放了 `--hero-arrow-lane: 36px`（文字避開箭頭的走道）與 `.hero-title` 的字級。
   hero 上已經沒有文字，兩者都沒有消費端，**整段已刪除**——不是漏寫。 */

@media (min-width: 1024px) {
  /* ⚠️ 原本這裡把 hero 箭頭放大成 44px。2026-08-19 統一之後尺寸由
     `.carousel-arrow` 的 `≥1024` 規則提供（48px），這裡不再宣告——
     hero 因此從 44 變成 48，**這是刻意的**。 */
  .hero-arrow-prev {
    left: max(4px, calc((100% - var(--container-max)) / 2 - 64px));
  }

  .hero-arrow-next {
    right: max(4px, calc((100% - var(--container-max)) / 2 - 64px));
  }
}

/* ==========================================
   home-01：快速連結卡片
   ========================================== */
/* 🔴 原本完全沒有左右內距，四格卡片整排貼齊視窗邊緣、圓角被切掉
   ——客戶 2026-08-12 截圖回報的第二處。max-width 一起加兩倍內距的理由同 .hero-inner。 */
.quicklinks {
  position: relative;
  z-index: 5;
  max-width: calc(var(--container-max) + var(--page-gutter) * 2);
  margin: -40px auto 0;
  padding-inline: var(--page-gutter);
}

/* 🔴 V2（PM 2026-08-31）：手機取消「快速按鈕疊在 hero 上」。
   PM 原話：「手機版 hero 區高度已經不高，因此快速按鈕就不要重疊到 hero 輪播區上方了，
   這樣照片可以比較完整出現。」——U1 把手機 hero 壓到 144px 之後，
   再被卡片壓掉 28px 就只剩 116px。
   ⚠️ **只做 <640**（PM 定案）；≥640 維持 -40／-56／-64px 的重疊設計。

   🔴 **這一段必須放在上面那條 `.quicklinks` 之後，不可以搬到檔案前面。**
      上面用的是 `margin` 簡寫（`-40px auto 0`），本條是同特異性 (0,1,0) 的
      `margin-top` ——**贏它只靠來源順序**。放到前面就完全不生效，
      而畫面只是「照片還是被蓋住」，不會報錯。
      （2026-08-31 施工時真的先寫錯位置，量到 `照片被蓋 28px` 才發現。）

   🔴 **W2（PM 2026-09-01）：由 `0` 改成 `16px`。**
      V2 拿掉重疊之後卡片上緣正好貼齊 hero 下緣、一點縫都沒有，PM 要求留間距。
      16px 取自 `.hero-arrow` 的 `bottom: 16px`，是同一個節奏、不是新數字。
      ⚠️ 這 16px **不會再遮住照片**（它是正值，卡片往下推、不是往上疊）。
      ⚠️ **只動 `<640`**：≥640 的 `-40／-56／-64px` 重疊設計是刻意的。

   🔴 **X5（PM 2026-09-02）：現行值是 `24px`**（W2 的 16px 實機看過後 PM 要再大一點點）。
      **24px ＝ `--page-gutter`**，與頁面左右間距同一個節奏，不是又一個新數字。
      ⚠️ **不要改成用 `.hero` 的 `margin-bottom`**：間距由**下方容器**提供是本專案的慣例
         （間距只有一個來源），兩邊各給一半會讓下次調整的人找不到是誰給的。
      ⚠️ 位置限制仍然有效（見上方那條紅字）：值變了也**不可以把這條搬走**。 */
@media (max-width: 639px) {
  .quicklinks {
    margin-top: 24px;
  }
}

/* 按鈕列下方一抹淺紫柔光，像映在白底上的反光 */
.quicklinks::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -70px;
  width: 60%;
  height: 140px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgba(163, 118, 199, 0.35), transparent 70%);
  filter: blur(32px);
  z-index: -1;
  pointer-events: none;
}

.quicklinks-inner {
  display: grid;
  grid-template-columns: 1fr;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
}

.quicklink-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 28px 20px;
  color: #FFFFFF;
  transition: filter 0.2s ease-out;
}

.quicklink-card:hover {
  filter: brightness(1.08);
}

/* 深／淺紫交替是**位置性的條紋**，所以用 nth-child 是對的（見 script.js 那段說明）。
   🔴 但要排除金色卡，否則會變成「兩條規則搶同一個 background-color」：
      `.quicklink-card:nth-child(even)` 的特異性是 (0,2,0)，和
      `.quicklink-card.quicklink-card--gold` 一樣——那時誰贏只看誰寫在後面，
      是最容易在日後搬動規則時安靜壞掉的一種寫法。用 :not() 把範圍講明，就沒有這個問題。 */
.quicklink-card:not(.quicklink-card--gold):nth-child(odd) {
  background-color: var(--color-primary);
}

/* 淺色卡：客戶指定色，見 style.css 的 --brand-purple-soft（R21 之後是 #704C8C，原本 #9B82BE）
   ⚠️ Q2（2026-08-24）之後第 2、4 張改成金色，**目前站上沒有淺紫卡了**。
      這條刻意留著：客戶日後加第 5 張（非金色）時它就會回來。 */
.quicklink-card:not(.quicklink-card--gold):nth-child(even) {
  background-color: var(--color-primary-soft);
}

/* 🔴 Q2（客戶 2026-08-24）：金色卡——**底色、文字、圖示圓底、圖示四樣要一起換**。
   只換底色的話會留下「白字白圓在金底上」，實測白字 on 金漸層暗端只有 1.80:1，形同看不見。

   實測（2026-08-24）：
     --color-on-gold #654729 文字 on 金漸層 → 暗端 4.70／亮端 5.86  ✓ 過 AA 4.5
     圖示圓底 --color-on-gold vs 金卡底      → 4.70                 ✓ 遠高於非文字 3:1
     白圖示 on --color-on-gold 圓底          → 8.45                 ✓
     （沿用白圓底的話：白圓 vs 金底只有 1.80，圓形整個看不出來）
   🔴 金底上的文字只能用 `--color-on-gold`，不要寫死色值也不要用白色（style.css :root 有完整說明）。
   ⚠️ 圖示配色刻意與紫卡**對稱**：紫卡是「白底＋主色圖示」，金卡是「深色底＋白圖示」。
   ⚠️ hover 沿用 `.quicklink-card:hover` 的 `filter: brightness(1.08)`，漸層也吃得到。 */
.quicklink-card.quicklink-card--gold {
  background-image: linear-gradient(135deg, var(--gold-from), var(--gold-to));
  color: var(--color-on-gold);
}

.quicklink-card.quicklink-card--gold .quicklink-desc {
  color: var(--color-on-gold);
}

.quicklink-card.quicklink-card--gold .quicklink-icon {
  background-color: var(--color-on-gold);
  color: #FFFFFF;
}

.quicklink-icon {
  flex-shrink: 0;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background-color: #FFFFFF;
  color: var(--color-primary);
  display: flex;
  align-items: center;
  justify-content: center;
}

.quicklink-icon svg {
  width: 28px;
  height: 28px;
}

.quicklink-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.quicklink-title {
  font-size: 1.125rem;
  font-weight: 500;
}

.quicklink-desc {
  font-size: 1rem;
  line-height: 1.5;
  color: #FFFFFF;
}

@media (min-width: 768px) {
  .quicklinks {
    margin-top: -56px;
  }

  .quicklinks-inner {
    grid-template-columns: repeat(2, 1fr);
  }

  .quicklink-card {
    padding: 32px 24px;
  }
}

@media (min-width: 1024px) {
  .quicklinks {
    margin-top: -64px;
  }

  .quicklinks-inner {
    grid-template-columns: repeat(4, 1fr);
  }

  .quicklink-card {
    padding: 36px 24px;
  }
}

/* ==========================================
   home-01b：公會理念（S2，客戶 2026-08-26）
   ========================================== */
/* hero 的標語與內文搬到這裡：**文字要大、金色、要顯眼、不放 CTA**（客戶原話）。

   🔴 **`.creed-title` 是首頁唯一的 `<h1>`**（hero 的 h1 隨標語一起移走了）。
      標記語意不可以退成 `<h2>`：一頁 0 個 h1 的失敗模式是安靜的
      ——SEO 與螢幕閱讀器都受影響，畫面上完全看不出來。

   🔴 **U2（PM 2026-08-31）：紫色底色已移除，金字直接坐在頁面白底上。**
      PM 原話：「按照我說的，移掉紫色背景，留下金色文字。」
      討論型已先回報過對比問題、PM 重申 → 照辦。

      🔴 **這是 PM 已知並接受的取捨，不要「修」回紫底、不要改深字，
         也不要加陰影／描邊去救對比**（那會變成第三種金色 ＝ 分叉）。
      實測對比（2026-08-31 於實機 `getComputedStyle` 取實際色值算 WCAG）：

      | 前景 | 底色 | 對比 |
      |---|---|---|
      | 標題：金色**漸層** `#E0BD70`→`#EED593`→`#E0BD70`（V1／V1-2） | **`#FFFFFF`（現況實際底色）** | **1.80 ↔ 1.44** 🔴 遠低於 AA 4.5 |
      | ~~內文 `--gold-from`~~ → **`--color-on-gold #654729`（V1）** | 同上 | **8.42:1** ✅ **過 AA** |
      | （對照）標題 | `--brand-purple-dark #471F70`（U2 之前） | 8.58:1 ✅ |
      | （對照）內文 | 同上 | 6.88:1 ✅ |

      🔴 **V1（PM 2026-08-31）改了兩件，這張表已依實測更新**：
         ① 標題由單色改成**金色漸層**——漸層兩端的對比是 1.80（暗端）到 1.44（亮端），
            **整條都讀不到，取捨性質與 U2 相同**。
         ② **內文改成 `--color-on-gold`，對比一舉回到 8.42 ✅**
            ——所以「這一區完全讀不到」已經不成立了，**只剩標題**。

      ⚠️ **本表的底色曾經寫錯，已於 U2 修正**：舊版寫著金字會壓在 `.courses-band`
         的淺底 `≈#F0EDE8`（記 1.2:1）。實測 `.creed` 與 `.creed-inner` 的
         `background-color` 都是透明，往上追到 `body` 是純白 `#FFFFFF`，
         所以數字是 **1.44／1.80**，不是 1.23。
         結論方向沒變（都讀不到），但拿錯的底色去算別的顏色會得到錯的答案。
      ⚠️ **一個誠實的補充（2026-08-31 實測）**：`.creed` 的祖父層 `.courses-band`
         確實**有一張 `background-image`**（`bg-01.jpg` ＋ 55% 白遮罩），
         所以嚴格說底色不是「純白」而是那張線條圖。但把該圖逐像素混完 55% 白之後
         **平均值是 `#FDFDFD`（等於白）**，所以上表的數字仍是可用的代表值；
         🔴 **只有金色線條剛好經過標題後面時會更低（實測掉到 1.14）**。
         判準：**要看「實際畫出來的底」就得追到有 `background-image` 的那一層，
         只看 `background-color` 會漏掉圖。**
      ⚠️ 與 LINE 綠底白字（2.26）、消息分類 `--logo-1` 白字（2.20）同一類，
         但要誠實記下差異：那兩處是**深底上的短標籤**，
         這一處是**白底上的首頁主標題**，1.44 比它們都低。
         ⚠️ V1 之後**只有標題如此**；它下方的說明文字已經過 AA（8.42）。
      🔴 **`.creed-title` 是首頁唯一的 `<h1>`——不可以因為「反正看不太清楚」
         就退成 `<h2>` 或改用圖片**；語意與 SEO 不受視覺取捨影響。
      🔴 換金色時要重量這張表，不要憑印象。

   🔴 **不放 CTA 按鈕是客戶指定的**，不要「順手」補一顆。

   ⚠️ 上內距 80px 不是隨手取的：`.quicklinks::after` 那抹柔光
      `bottom: -70px`、高 140px，而 `.quicklinks` 有 `z-index: 5`（建立堆疊脈絡）
      **會蓋在這一區上面**。留 80px 才不會有一片模糊的紫光壓在金字卡片的上緣。
   ⚠️ 下內距是 0：下方 `.courses` 自己有 `--spacing-section-sm` 的上內距，
      兩邊都給就會變成雙倍間距。 */
.creed {
  padding: 80px var(--page-gutter) 0;
}

/* 🔴 U2（PM 2026-08-31）：`background-color: var(--brand-purple-dark)` 已移除，
   `border-radius` 一併移除（沒有色塊就看不到圓角，留著是死碼）。
   🔴 **上內距保留、下內距歸零**：上內距是這一區與上方的呼吸空間，
      拿掉會讓金字直接貼上一區。

   🔴 **X1（PM 2026-09-02）：下內距由 `24px`／`40px` 那組的第三個值歸零。**
      根因是 U2 的遺留：這 `40px 24px`／`56px 40px` 原本是**深紫方框的內距**，
      U2 移除底色之後它就變成一段**看不見的空白**，與下方 `.courses` 的
      `--spacing-section` 96px 疊加 ——實測 1440 桌機「說明文字底部 → `.section-eyebrow` 頂部」
      是 **174.5px**，歸零後約 118px。
      ⚠️ 當時 U2 規格寫「`padding` 保留，那是呼吸空間」——**上下都保留才是問題**；
         `.creed` 自己的註解早就寫著「下內距是 0，因為下方 `.courses` 有上內距，
         兩邊都給會變雙倍」，同一條道理沒有套用到 `.creed-inner` 上。
      🔴 **不要改 `.courses` 的 `padding-top`**（`--spacing-section`，全站區塊共用，
         改它會動到每一頁），**也不要改 `.creed` 的 `padding: 80px … 0`**
         （那 80px 是為了避開 `.quicklinks::after` 的柔光，與本項無關）。 */
.creed-inner {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 40px 24px 0;
  text-align: center;
}

.creed-title {
  /* ⚠️ 一律用 rem：全站有小／中／大三段字級切換，寫死 px 那三段就不會跟著長，
     而這個站的使用者以長輩為主，字級切換正是為他們做的。 */
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.4;
  /* 標語是四個詞用「・」串起來的，加一點字距才不會擠成一團 */
  letter-spacing: 0.08em;
  /* 🔴 V1（PM 2026-08-31）：這是 `@supports` 不成立時的**保險色**，不是死碼。
     PM 要的是金色漸層（見下方 `@supports`），但漸層是靠 `background-clip: text`
     ＋ `color: transparent` 做的——**萬一瀏覽器不支援，transparent 會讓標題完全消失**，
     而那是首頁唯一的 `<h1>`。所以先給純金色，支援的瀏覽器才覆寫成漸層。
     ⚠️ 這與全域守則「任何靠 X 才看得見的寫法都要問『X 沒有會怎樣』」是同一條判準。 */
  color: var(--gold-to);
  margin-bottom: 16px;
  /* 🔴 V1-2（PM 2026-08-31 回報「這段文字沒有做金色漸層」）：**框要縮到貼合文字**。
     根因：`<h1>` 是區塊元素、框寬 = 容器寬（桌機實測 **1360px**），
     而文字置中、只佔中間約 588px ——**漸層鋪滿整個框，glyph 只取樣到中間那一小片**，
     於是看起來就是單色。這不是漸層沒生效（實測 `background-clip` 是 `text`、
     `color` 是 transparent，都正確），是**取樣範圍的問題**。
     🔴 改法是縮框不是加深顏色——加深就得引入第三種金色 ＝ 分叉（七之二節）。
     ⚠️ `-webkit-` 那行給舊版 Safari；兩行都不支援時 width 退回 auto，
        結果只是「又變回單色」，文字不會消失。
     ⚠️ 手機兩行時 `fit-content` 取較寬的那一行，兩行共用同一道漸層，看起來是連續的。 */
  width: -webkit-fit-content;
  width: fit-content;
  margin-inline: auto;
}

/* 🔴 V1（PM 2026-08-31）：標題文字用**金色漸層**，不是單一色
   （PM 原話：「文字要使用金色漸層，並非單純純色」）。
   🔴 漸層用全站唯一那組 `--gold-from`／`--gold-to` ＋ 135deg，**不要另寫一組金色**
      （七之二節：全站金色只有一組來源，另寫就是分叉）。
   ⚠️ 手機兩行時漸層仍然橫跨整個 `<h1>` 的框，所以第一行偏 from、第二行偏 to，
      看起來是連續的一道漸層——這是要的效果。
   ⚠️ `-webkit-` 前綴不可省：Safari 到現在仍只認前綴版的 `background-clip: text`。 */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  /* 🔴 選擇器是 `.creed .creed-title`（0,2,0）不是 `.creed-title`（0,1,0）：
     `style.css` 的進場動畫規則就是 `.creed .creed-title`，它的 `animation: creed-rise …`
     權重比較高，**會把這裡的 creed-shine 整條蓋掉**（2026-09-17 實測：桌機量到的
     animation-name 是 creed-rise，掃光從來沒有跑過，而且不會報錯）。
     所以這裡用同權重、靠載入順序（style.css 先、pages/home.css 後）勝出，
     並且**把進場與掃光寫成同一個 animation 的兩個值**，兩個都要在。 */
  .creed .creed-title {
    /* 🔴 三個停止點（暗→亮→暗）＝ 金屬反光的感覺，比兩點的單向漸層明顯得多，
       而且**只用既有的兩個金色 token**，沒有引入第三種金色。
       ⚠️ 角度用 100deg 不是全站按鈕那組的 135deg：按鈕是小方塊，
          這裡是一條又寬又扁的文字（588×69），太斜會讓變化被高度吃掉、又變回單色。 */
    /* 🔴 Z2（PM 2026-09-02，起點值待 PM 目視確認）：三停止點由平均分佈
       （0% / 50% / 100%）改成**集中式 42% / 50% / 58%** ——亮端只佔中間一小段，
       視覺上從「緩慢均勻的明暗起伏」變成「一道光掃過」。
       🔴 收窄的是**亮帶的幾何**，不是把亮端提亮：標題金字在白底的對比已經是 1.44
          （PM 已知並接受），再提亮會更難讀，而且會引入第三種金色 ＝ 分叉（七之二節）。
       ⚠️ 兩端仍必須是同一個色（Z2-2 之後是 `--color-on-gold`），接回起點才不會跳色。 */
    /* 🔴 Z2-2（PM 2026-09-03）：**深端由 `--gold-from #E0BD70` 換成既有的
       `--color-on-gold #654729`**（四個停止點：0% / 42% / 58% / 100%）。
       根因是 Z2 的調快與收窄亮帶都改善不了的一件事：**原本兩端彼此的對比只有 1.25**
       （1.0 ＝ 完全同色），所以亮帶掃過去時根本沒有深淺可看，動畫等於不存在。
       換成 `--color-on-gold` 之後兩端對比 **5.86（約 4.7 倍）**，才看得出「一道光掃過」。
       ⚠️ **沒有引入第四種金色**：`--color-on-gold` 是既有 token（定義在 `style.css`），
          V1 的理念區說明文字與全站金底按鈕的文字都在用它——仍然只有一組金色來源。
       🔴 **亮端 `--gold-to` 不要動，也不要再提亮**：亮帶只佔中間一小段，維持現值即可。
       🔴 **這讓上方那張對比表、以及 `CLAUDE.md` 七之二節「標題金字在白底只有 1.44／1.80，
          是 PM 已知並接受的取捨」那句，對「深端」而言已經過時**——
          深端白底對比現在是 **8.45（過 AA）**，只有亮端 `--gold-to` 仍是 1.44。
       🔴 **「動畫更明顯」與「文字更好讀」是同一個改動的兩個結果，不是取捨。**
          不要以為有人為了視覺效果偷偷放寬了對比標準：這裡沒有放寬任何標準，
          是把一個原本讀不到的深端換成本來就過 AA 的既有 token，兩件事一起變好。
       ⚠️ 備案（PM 若覺得深褐感太重）：**把亮帶放寬成 `38% / 50% / 62%`，不是改顏色。** */
    background-image: linear-gradient(100deg, var(--color-on-gold) 0%, var(--color-on-gold) 38%, var(--gold-to) 50%, var(--color-on-gold) 62%, var(--color-on-gold) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    /* 🔴 X4（PM 2026-09-02）：金光流動。把漸層框拉大才有位移空間，
       再讓 `background-position` 跑完整整一輪，接回起點不會跳。
       🔴 Z2（PM 2026-09-02，**起點值，待 PM 目視確認**）：`200%` → `300%`、`6s` → `3.5s`。
          餘裕變大等於亮帶相對更窄、掃得更乾脆；6s 是 X4 訂得太保守。
       🔴 **不要低於 3s**：那會變成「閃爍」，而這一區是首頁最重要的標語，
          閃爍會讓長輩看不進去文字（X4 訂 6s 的理由仍然成立，只是訂得太保守）。
       🔴 **改 `background-size` 一定要跟著改 keyframes 的終點值**，否則接點會跳色：
          終點 ＝ S ÷ (S − 1) × 100%（S ＝ background-size 的倍數）。
          200% → 200%；**300% → 150%**。算式來源：位移量 ＝ N% × (框寬 − 圖寬)，
          要正好等於一個漸層週期（＝圖寬）。 */
    background-size: 300% auto;
    /* 進場（一次，停在可見狀態）＋ 掃光（無限）：`animation` 是簡寫，
       只寫掃光就會把 style.css 的進場擦掉，所以兩個都列在這裡。
       進場的時間曲線與 `both` 必須跟 style.css 的 `.creed .creed-title` 一致。 */
    animation: creed-rise 0.7s cubic-bezier(0.22, 1, 0.36, 1) both, creed-shine 3.5s linear infinite;
  }
}

/* 🔴 X4 的三個條件，缺一不可——改動這裡之前逐條確認：

   ① **動畫必須寫在上面那個 `@supports` 裡**，跟著漸層一起。
      不支援 `background-clip: text` 的瀏覽器看到的是**純金色實心字**
      （`.creed-title` 的 `color: var(--gold-to)` 保險色），
      此時 `background-position` 動畫本來就沒有任何效果。
      🔴 **`color: transparent` 絕對不可以搬出 `@supports`。**
         那一行是漸層能透出來的前提，但它同時也是「字會不見」的開關：
         瀏覽器若不支援 `background-clip: text`，透明就沒有東西填回來，
         **首頁唯一的 `<h1>` 會整個消失**——而且不報錯、SEO 與螢幕閱讀器都受影響，
         畫面上只看得到一片空白。所以純金色寫在外面、透明＋漸層一起關在 `@supports` 裡。

   ② ~~必須尊重 `prefers-reduced-motion: reduce`~~ **（2026-09-17 由使用者指示解除，見下方）**：
      原本的理由是使用者以長輩為主、前庭敏感者看到持續移動的文字會不適；
      但實際上客戶自己的電腦開著減少動態，變成永遠看不到這道掃光。
      🔴 解除的只有這一行標題；其他位移型動畫仍然尊重系統設定。

   ③ **速度：`3.5s`、`linear`、`infinite`。**
      ⚠️ **原本是 6s**，Z2（PM 2026-09-02 回報「太慢、太不顯眼，長輩會看不出來有變化」）
         改成 3.5s；**這是起點值，待 PM 目視確認**，不是定案。
      🔴 **下限是 3 秒，不要再往下縮**——2–3 秒以下在長輩眼中是「畫面在閃」，
         而這一區是首頁最重要的標語，閃爍會讓人看不進去文字。
         （X4 當初訂 6s 的理由仍然成立，只是訂得太保守。）

   ⚠️ **只用既有的 token**（Z2-2 之後是 `--color-on-gold` 深端 ＋ `--gold-to` 亮端），
      不要為了「更閃」另外調一個金色或加白色高光——全站金色只有一組來源（CLAUDE.md 七之二節）。
   ⚠️ **手機兩行（`.creed-line` × 2）共用同一道背景**，動起來是連續的；
      不要改成各行獨立動畫，那看起來像兩段不同步的跑馬燈。 */
@keyframes creed-shine {
  /* 🔴 終點值跟著 `background-size` 走：S ÷ (S − 1) × 100%。
     `300%` ⇒ **150%**（舊值 200% 對應的是舊的 `background-size: 200%`）。
     寫錯的失敗模式是**每一輪接點跳一下色**，而且不會報錯。 */
  from { background-position: 0% center; }
  to   { background-position: 150% center; }
}

/* 🔴 使用者 2026-09-17：**這道掃光不跟著系統的「減少動態效果」關掉**。
   原本這裡（以及 style.css 的 `.creed .creed-title`）在 reduce 時是 `animation: none`，
   但使用者自己的電腦開著減少動態，等於永遠看不到首頁最重要的標語在動，
   多次回報「動畫沒做」——所以 reduce 時改成「只留掃光、取消進場位移」。
   ⚠️ 取消掉的是 `creed-rise`（位移＋淡入），保留的是原地換色的掃光：
      前庭敏感者的不適主要來自位移與縮放，這樣兩邊都顧到。
   ⚠️ 權重與順序：這條是 0,2,0 且在 style.css 之後載入，才蓋得掉 style.css 的
      `@media (prefers-reduced-motion: reduce) { .creed .creed-title { animation: none } }`。
   ⚠️ 其他區塊（AOS 進場、跑馬燈、理念說明文字的進場）的 reduce 處理全部保留。 */
@media (prefers-reduced-motion: reduce) {
  .creed .creed-title {
    animation: creed-shine 3.5s linear infinite;
  }
}

/* 讓斷行只能發生在「・」的位置，不會把某個詞從中間切開（見 index.html 的說明）。
   🔴 V4 之後這條也套用到新加的 `.creed-line`／`.creed-sep`（它們也是 `.creed-title span`）
      ——所以下面要覆寫成 `block` 的那條**必須用 `.creed-title .creed-line`**（特異性 0,2,0），
      寫成 `.creed-line`（0,1,0）會輸給這一條，**而且不會報錯，只是手機不換行**。 */
.creed-title span {
  display: inline-block;
}

/* 手機：四個詞一行放不下，**釘成「兩個詞一行」**，不要讓它自己決定。
   🔴 這裡用 `em` 而不是 px，所以三段字級（18／20／22px）算出來都一樣：
      每個詞 2 字 × 1.08（含字距）＝ 2.16em，分隔點約 1.08em ⇒
      兩個詞 ＝ 5.40em、三個詞 ＝ 8.64em。取中間的 **7em**，
      就保證「兩個放得下、三個放不下」。
   ⚠️ 不釘的話會隨寬度與字級變成 3+1 或 2+1+1（實測 375 預設是「和諧・團結・真誠／服務」、
      320 大字級是三行）——**那正是全域守則說的「靠字數解 RWD 只能解某一格」**，
      所以改成用容器寬度釘死，不是去調文案。
   ⚠️ ≥640 不套用：那邊四個詞排得下一行（4 詞 ＝ 11.88em，768 的可用寬約 17.8em）。 */
@media (max-width: 639px) {
  /* 🔴 V4（PM 2026-08-31）：手機改成**釘死兩行** ＋ 中間的「・」隱藏 ＋ 字級再放大一階。
     🔴 `max-width: 7em` 已移除：那是「逼它自己折成兩行」的舊做法，
        現在兩行是結構釘死的，留著只會多一個限制寬度的數字。
     🔴 特異性必須是 `.creed-title .creed-line`——見上方 `.creed-title span` 那條的說明。
     🔴 W4（PM 2026-09-01）：由 `2rem` 再放大一階到 **`2.25rem`**（PM：手機版理念區大標要更大）。
        🔴 **`≤359` 那段一定要跟著調**，只改這一條會讓 320 大字級退成四行。
        ⚠️ 那一段最後採用 **`1.8125rem`** 而不是規格建議的 `2rem`——實測逼出來的上限，
           理由與試過的值見那條規則上方的表。
        ⚠️ `.section-title`（最新課程那種）**不在本項範圍**，PM 明示不要一起動。 */
  .creed-title {
    font-size: 2.25rem;
  }

  .creed-title .creed-line {
    display: block;
  }

  .creed-title .creed-sep {
    display: none;
  }
}

/* 🔴 ≤359 才縮字級，**不要拉到 639**：375 是最常見的手機寬度，那裡放得下較大的字，
   為了 320 這一格把它一起縮掉是拿常見尺寸去換極端尺寸。
   它與上面那條 `<640` 的字級是**綁在一起的兩個數字**：上面放大，這裡就要跟著調，
   否則 320 那格會被上面那條蓋到而溢出。
   🔴 **W4（2026-09-01）把這個斷點由 `359` 往上移到 `374`**，理由見下方第二張表
      ——`2.25rem` 在 `fs-lg` 下要到 375 寬才真的排得開，360（很常見的 Android 寬度）會斷行。

   ── 🔴 W4（2026-09-01）：這個值是**實測逼出來的上限，不是估的** ──
   最危險的一格是 **320 × 大字級**（`fs-lg` ＝ 22px 基準）：
   `.creed-inner` 可用寬只有 **224px**（320 − `--page-gutter` 24 ×2 − `.creed-inner` 內距 24 ×2），
   而一行「和諧・團結」是 5 個字元 × (1 ＋ `letter-spacing` 0.08)em ＝ **5.4em**。

   | 試過的值 | 那一格算出來的行寬 | 結果 |
   |---|---|---|
   | `2.25rem`（＝上面 `<640` 的值） | 252px | 🔴 爆掉 28px |
   | `2rem`（W4 規格的建議值） | **224.0px** | 🔴 **餘裕 0 → 實測真的斷成 2+2 ＝ 四行** |
   | `1.9375rem` | 224.0px | 🔴 同樣斷行 |
   | `1.875rem` | 222.8px | ⚠️ 塞得下，但**只剩 1.2px**——等於隨時會翻 |
   | **`1.8125rem`（採用）** | **215.3px** | ✅ **餘裕 8.7px**，穩定兩行 |

   🔴 **規格檔建議的 `2rem` 是量錯的**（回報寫「兩行」，實際是每個 `.creed-line`
      各自折成兩行 ＝ 全部四行）。**判準：`.creed-line` 的寬度等於可用寬時就已經斷了**，
      不能只看「有沒有橫向溢出」——它折行之後當然不溢出，畫面卻是錯的。
   🔴 **所以這條不可以再往上加，也不要動 `.creed-inner` 的 24px 內距或
      `letter-spacing: 0.08em`**——任何一項變大，320 大字級就會退成四行。

   ── 🔴 斷點為什麼是 `374` 而不是本專案慣用的 `359` ──
   `2.25rem` 在 `fs-lg`（22px 基準）下一行要 **267.3px**，而可用寬 ＝ 視窗寬 − 96
   （`--page-gutter` 24 ×2 ＋ `.creed-inner` 內距 24 ×2），所以它需要 **≥363.3px** 的視窗：

   | 視窗寬 | 可用寬 | `2.25rem` 需要 | 餘裕 |
   |---|---|---|---|
   | 360（常見 Android） | 264 | 267.3 | 🔴 **−3.3 → 斷成四行**（實測） |
   | 364 | 268 | 267.3 | ⚠️ 0.7px，等於沒有 |
   | 375（最常見） | 279 | 267.3 | ✅ 11.7px |

   🔴 **所以界線畫在「比 375 窄的一律用小一階」＝ `max-width: 374px`。**
      ⚠️ 這是**本專案第一個用 374 的斷點**（其他地方是 359，例如課程卡改上下堆疊）
         ——不是打錯，是這一區的內容自己決定的（六節：每個區塊照它自己的內容決定斷點）。 */
@media (max-width: 374px) {
  .creed-title {
    font-size: 1.8125rem;
  }
}

.creed-desc {
  font-size: 1.125rem;
  line-height: 1.8;
  /* 🔴 V1（PM 2026-08-31）：由 `--gold-from`（白底 1.80，讀不到）改成 `--color-on-gold`
     #654729 ——**白底實測 8.42:1，遠高於 AA 4.5**。PM 指定。
     ⚠️ 這個 token 原本的用途是「金底上的文字」，這裡是白底上的深棕字；
        取的是同一組品牌色系裡的深色，不是另開一個新顏色。
     🔴 標題仍是金色（漸層），**只有這一行的說明文字改深色**——不要順手把標題也改掉。 */
  color: var(--color-on-gold);
  /* ⚠️ 長句在寬螢幕下不要拉成一整行，也不要在窄螢幕被 max-width 逼出孤字。
     用 em 而不是 px：字級放大時容納的字數才不變。 */
  max-width: 34em;
  margin-inline: auto;
}

@media (min-width: 768px) {
  /* 🔴 第三個值 `0` 是 X1（2026-09-02）加的，見上方 `.creed-inner` 的說明
     ——原本是 `56px 40px`（上下同值），下內距與 `.courses` 的 96px 疊加成 174.5px。 */
  .creed-inner {
    padding: 56px 40px 0;
  }

  .creed-title {
    font-size: 2.25rem;
  }

  .creed-desc {
    font-size: 1.25rem;
  }
}

@media (min-width: 1024px) {
  .creed-title {
    font-size: 2.75rem;
  }
}

/* ==========================================
   home-02：最新報名中課程
   ========================================== */
/* ══════════════════════════════════════════
   R7／R8／R9：首頁三區背景圖（客戶 2026-08-25）
   ------------------------------------------
   🔴 **三區都疊了一層半透明白，那不是保守，是實測出來的必要條件。**

   根因不是這三張圖特別暗，是**結構性的**：首頁這三區的內文用
   `--color-muted #636363`，那個色在**純白**上也只有 5.74——
   離 AA 門檻 4.5 只剩 1.24 的餘裕，**疊任何一層色調都會掉到門檻以下**。

   ⚠️ 而且這三區**沒有任何一個內容容器有自己的底色**（實測 `.course-card`、
      `.news-item`、`.news-list` 全是 `rgba(0,0,0,0)`）——所以整區的文字
      是**直接坐在背景圖上**的，不是只有標題那幾行。

   實測（1920 桌機，量的是「真實渲染後的截圖像素」不是原圖檔）：
   | 區塊 | 無遮罩 | 加了遮罩 |
   |---|---|---|
   | `.courses` bg-01 | 6.96% 未達 AA，最厚失敗帶 **50px** | α.55 → 0.41%、最厚 5px |
   | `.news` bg-02 | 4.97% 未達 AA，最厚失敗帶 **39px** | α.55 → 0.50%、最厚 2px |
   | `.join` bg-03 | 39.8% 未達 AA（下半是密集金點浪） | 漸層 → 見該區註解 |

   🔴 **「最厚失敗帶」才是判準，不是百分比**：50px 厚足以整行文字坐在上面；
      剩下的 2〜5px 是金線本身的線芯，比字的筆畫還細，遮不住任何一個字。
   ⚠️ **量原圖檔會低估**：`cover` 會裁切與放大，實際渲染出來的線比原圖粗、對比更差。
      一定要量截圖。

   ⚠️ **殘留的取捨要讓 PM 知道**：要 100% 過 AA 得把 α 拉到 0.75，
      那會把客戶要的金線幾乎洗掉。另一條路是這三區的內文改用
      `--color-text` 而不是 `--color-muted`（不必動背景，也不是新造顏色）
      ——**那是設計決定，已回報 PM，未定案前維持現在這樣。**
   🔴 調整時只改 `--section-bg-scrim` 這一個值，不要逐區去改 rgba。
   ══════════════════════════════════════════ */
.courses-band,
.news {
  --section-bg-scrim: rgba(255, 255, 255, 0.55);
}

/* 🔴 R7-2（客戶 2026-08-25）：「最新課程背景要從 hero 圖下方就顯示，中間不要有空白」。
   背景**掛在這個帶狀容器上**、不是掛在 `.courses` 上，因為 `.quicklinks` 疊在
   兩者之間而且是透明的——只給 `.courses` 上底圖的話，hero 結束到 `.courses` 開始
   之間會露出一條白帶（實測 98px，正是 `.quicklinks` 在 hero 下方的那一截）。

   🔴 **`display: flow-root` 不可省。** `.quicklinks` 有 `margin-top: -40px`，
      不建立 BFC 的話那個負 margin 會**穿透上來把整個容器一起往上拉**
      （margin collapsing），底圖就會爬到 hero 上面去——
      而那看起來只是「背景位置怪怪的」，不會有任何錯誤訊息。
   ⚠️ 這一層只負責背景：寬度、內距、置中仍由 `.quicklinks` 與 `.courses` 各自處理，
      不要把版面搬上來。 */
.courses-band {
  display: flow-root;
  position: relative;
  background-image:
    linear-gradient(var(--section-bg-scrim), var(--section-bg-scrim)),
    url('../../images/backgrounds/bg-01.jpg');
  /* 🔴 **底圖用 `100% auto`，不是 `cover`**（客戶 2026-08-25 反映「背景被放很大」）。
     這一帶很高（實測約 1935px），而 bg-01 是 1920×1004——`cover` 為了填滿高度
     會把圖放大到約 1.9 倍，線條變得又粗又糊。
     `<寬度> auto` ＝ **寬度依指定值、高度依原比例**，圖只鋪在上緣，
     **下方維持白底**（客戶指定）。
     ⚠️ 一定要配 `no-repeat`：`auto` 高度小於容器時，預設會**上下重複鋪滿**。
     ⚠️ 遮罩那一層維持整片（gradient 沒有原生尺寸，`auto` 就是滿版）——
        它疊在白底上仍然是白，看不出差別；疊在圖上才有作用。
     ✅ 附帶好處：圖以外的區域回到純白，那一段文字的對比反而更好。

     🔴 **「避開文字」要靠垂直位移，不要動寬度**（2026-08-25 兩次來回換到的結論）：

     ① 先試過縮成 `85%` ＋ `left top`——線條是離開文字了，但**圖的右緣露出一道
        看得見的接縫**（85% 只鋪到 x≈1620，右邊 285px 是白的，而右緣正好有三段
        金線橫切、在半空中被切斷）。客戶直接反映「右邊空一塊」。
     ② 也不可以「放大再往左推」：放大會讓線條變粗，客戶前幾天才因此抱怨過。
     🔴 **`100% auto` 時水平方向根本沒有位移餘裕**（圖寬 ＝ 容器寬，實測都是 1905px），
        `left`／`center`／`right` 算出來都是 0——改了會像「沒生效」。
        **所以水平方向只有「縮小」一條路，而縮小必然露出右緣。**
     ✅ **垂直位移沒有這個問題**：寬度維持 `100%`（右邊不會空），
        往上移只是把圖頂端那段裁掉——而那段幾乎是空白的。

     原圖 1920×1004，每 25px 一列統計「暗於 245」的比例：
     | 圖上的 y | 線條密度 |
     |---|---|
     | 0–175 | 0.8–3.8%（幾乎空白，**被裁掉的就是這一段**） |
     | **200–275** | **36–63%（最密的交叉帶）** |
     | 300–460 | 12–32%（次密） |
     | 475 以後 | 6% 以下 |

     文字區在 band 的 y **294–475**（eyebrow 頂到說明底）、x **233–1133**。

     🔴 **`-250px` 是量「文字框裡面」得到的，不是量整列**（客戶在 -170px 之後仍說
        「再往上移動一點」，原因就在這個差別）：

     | 往上移 | 文字框整段非白% | **標題那一段（左側 x233–400）** |
     |---|---|---|
     | -170px | 2.2% | **11.6%** ← 還有一條線壓在「最新課程」後面 |
     | -200px | 0.9% | 4.7% |
     | -220px | 0.3% | 1.5% |
     | **-250px** | **0.0%** | **0.1%**（乾淨） |

     🔴 **不要只看整段的百分比**：整段 2.2% 看起來已經很低，但那是被右側大片空白
        平均掉的——殘留的線集中在**左側**，而標題正好在左側。
        **要量的是「文字實際佔的那一小塊」，不是整條列。**
     ⚠️ 再往上移沒有意義（-250 之後那一帶本來就是空的），只會多裁掉圖頂。
     🔴 **改 hero 高度、改這一區的內距、或改文案行數都會讓文字的 y 位置變動**——
        那時要重跑上面那組量測，不要憑印象調數字。 */
  background-repeat: no-repeat, no-repeat;
  background-size: auto, 100% auto;
  background-position: top center, center -250px;
}

.courses {
  padding: var(--spacing-section-sm) var(--page-gutter);
}

.courses-inner {
  max-width: var(--container-max);
  margin: 0 auto;
}

@media (min-width: 1024px) {
  .courses {
    padding: var(--spacing-section) var(--page-gutter);
  }
}

/* ==========================================
   home-03：最新消息
   ========================================== */
/* R8（客戶 2026-08-25）：背景由 `section-pattern.png` **取代**為 `bg-02.jpg`（不是疊加）。
   ⚠️ `section-pattern.png` 留著不刪——已 grep 過本檔以外沒有其他消費端，
      但那是客戶素材，留著的成本是零，刪掉要不回來。

   🔴 **背景圖就是 `bg-02.jpg`，不要換成 `bg-01.jpg`**（客戶 2026-08-25 當場更正過一次）。
   當天曾短暫改成 `bg-01`（一度還說要換 `bg-04`），客戶看了畫面之後指明
   「本會會務的背景圖是 bg-02」——**這一區與上方最新課程本來就用不同張，不是漏改。**

   🔴 **`cover` 已換成 `100% auto`**（客戶 2026-08-25：「寬度和框架一樣寬」）：`cover` 為了填滿高度會把圖放大並裁切
      （客戶 2026-08-25 反映「背景被放很大」，最新課程那一區已因此改過一次）。
      `100% auto` ＝ **寬度與區塊同寬、高度依原比例**，圖只鋪在上緣、下方維持白底。
   ⚠️ **一定要配 `no-repeat`**：`auto` 高度小於區塊時，預設會**上下重複鋪滿**
      ——那會出現一條橫向的接圖線，而且不會報錯。
   🔴 **定位是 `center bottom`（貼齊下緣），不是 `top center`——這一項與最新課程相反，是刻意的。**
      2026-08-25 客戶問「本會會務的背景圖是不是有放大？」實測**沒有**：
      圖寬 1905 ＝ 區塊寬 1905、縮放 0.992（比原圖還小一點點），確實是框架同寬。
      真正的問題是**區塊比圖矮**：1920 下區塊只有 790px，而圖是 1088px，**下緣被切掉 298px**。
      🔴 而 `bg-02` 的線條**全部集中在下半部**——貼齊上緣時看到的 790px 大半是空白，
         那束金線正好卡在下邊界**被切成一半**，看起來就像「圖被放大了」。
      ✅ 改成貼齊下緣之後，被裁掉的換成圖的上方 298px——**而那一段本來就幾乎全白**，
         線條那一束因此完整呈現。**同樣是裁 298px，裁掉空白的那一半才對。**
      ⚠️ 最新課程那一區用 `top` 是因為它的區塊（1935px）比圖（996px）**高**，
         整張圖都放得下、下方留白是刻意的。**兩區規則不同，不要為了一致而統一。**
      ⚠️ 窄螢幕（區塊比圖高時）這個值不影響——那時整張圖都看得到。
   ⚠️ 遮罩那一層維持整片（gradient 沒有原生尺寸，`auto` 就是滿版）。
   ⚠️ 上面那張對比表的「`.news` bg-02」那一列量的是 `cover` 放大後的最壞情況，
      換成 `100% auto` 只會更好（圖不放大，線更細）。 */
.news {
  padding: var(--spacing-section) var(--page-gutter);
  background-image:
    linear-gradient(var(--section-bg-scrim), var(--section-bg-scrim)),
    url('../../images/backgrounds/bg-02.jpg');
  background-repeat: no-repeat, no-repeat;
  background-size: auto, 100% auto;
  background-position: top center, center bottom;
}

.news-inner {
  max-width: var(--container-max);
  margin: 0 auto;
}


/* .news-list / .news-item / .news-badge 等清單樣式已移至 style.css（本會會務列表頁共用） */

/* ==========================================
   home-04：加入會員 CTA + 活動相簿輪播
   ========================================== */
/* R9（客戶 2026-08-25）：背景由 `dot-corners.png` **取代**為 `bg-03.jpg`，並要視差效果。
   （`dot-corners.png` 同 R8 的理由留著不刪。）

   🔴 **`background-attachment: fixed` 在觸控裝置一定要關掉，這不是「加分優化」。**
   PM 已知「有些手機沒效果」，但**實情比「沒效果」嚴重**：
   - **iOS Safari 不支援，而且不是靜靜降級**——`fixed` ＋ `cover` 會以「視窗」為
     背景定位區域，圖被放大到整個視窗那麼大、區塊裡只露出一小塊，
     看起來像**放錯圖**，而且不會報錯。
   - Android Chrome 支援但會掉幀，捲動明顯不順。
   → `@media (hover: none)` 一起退回 `scroll`。用 `hover: none` 而不是寬度斷點：
     要區分的是「有沒有精確指標」＝觸控裝置，不是「螢幕大小」
     （小視窗的桌機瀏覽器仍該有視差；平板橫放很寬但仍是觸控）。

   ⚠️ 第三個已知問題**留在這裡當提醒**：`fixed` 的背景以**視窗**為基準，
      所以 `cover` 是「蓋滿視窗」不是「蓋滿區塊」——區塊比視窗矮時只看得到圖的一部分。
      這是視差本來的樣子，**要看實際構圖決定，不要只讀程式碼**。 */
/* 🔴 **淡化遮罩不是可選的**：bg-03 上半是米白、下半是密集的金色點浪，實測
   內文的 `--color-muted #636363` 疊在點浪上**對比只有 2.51〜2.92**（AA 門檻 4.5），
   而且 `fixed` 讓文字捲動時會**掃過整張圖**——所以「現在看起來還好」不代表沒問題。
   （逐列實測：圖的上 35% 完全不必處理，40% 起開始需要，70〜75% 需要 α≈0.67。）

   ⚠️ 用**漸層**而不是均勻白：均勻要壓到 0.65 才夠，那會把客戶要的金色浪整片洗掉。
      漸層只在圖變暗的地方加白，上半保持原樣。
   🔴 遮罩與圖**必須是同一個 background 的兩層、且 attachment 相同**，
      兩層才會對齊；拆成 `::before` 的話遮罩跟著區塊、圖跟著視窗，捲動時會錯開。
   ⚠️ 標題 `#33223E` 本來就過（最暗處 6.10），這層是為了內文與 eyebrow。 */
.join {
  position: relative;
  overflow: hidden;
  padding: var(--spacing-section) var(--page-gutter);
  background-image:
    linear-gradient(
      to bottom,
      rgba(255, 255, 255, 0.22) 0%,
      rgba(255, 255, 255, 0.22) 30%,
      rgba(255, 255, 255, 0.55) 52%,
      rgba(255, 255, 255, 0.78) 76%,
      rgba(255, 255, 255, 0.66) 100%
    ),
    url('../../images/backgrounds/bg-03.jpg');
  background-repeat: no-repeat, no-repeat;
  background-position: center, center;
  background-size: cover, cover;
  background-attachment: fixed, fixed;
  /* 原本這裡有一支 join-fade-in（整塊只淡入），已隨 style.css 的 main-fade-in 一起移除（2026-09-19）：
     區塊裡的標頭與相簿輪播都掛了 data-aos，整塊再淡入一次就是重複動畫。
     🔴 這個區塊本身仍然**不能**掛任何會動 transform 的動畫（含 data-aos）：
        transform 只要不是 none，上面那行 background-attachment: fixed 的視差就會失效，而且看不出原因。 */
}

@media (hover: none) {
  .join {
    /* 🔴 兩層都要改，不能只寫一個值——`background-attachment` 是逐層的，
       只給一個值時**所有層都吃那一個值**（這次剛好也對，但寫成兩個才看得出意圖）。 */
    background-attachment: scroll, scroll;
  }
}


.join-inner {
  position: relative;
  z-index: 1;
  max-width: var(--container-max);
  margin: 0 auto;
}

.join-gallery {
  position: relative;
  margin-top: 8px;
}

.join-gallery-inner {
  max-width: var(--container-max);
  margin: 0 auto;
}

.gallery-viewport {
  overflow: hidden;
}

.gallery-track {
  display: flex;
  gap: 16px;
  transition: transform 0.5s ease;
}

/* 🔴 M4（客戶 2026-08-17）：「成為專屬夥伴」的照片輪播改成
   **1024px 看 3 筆、768px 看 2 筆、手機看 1 筆**，照片才夠大。
   原本是 <640 看 2 筆／640–1023 看 3 筆／≥1024 看 4 筆。

   ⚠️ **每頁筆數是 CSS 決定的，不在 JS**：`script.js` 的 `VISIBLE_SLOTS = 4`
      只決定「在 DOM 裡渲染幾個格子」（要 ≥ 最多可見數 ＋ 2 個緩衝格），
      實際一次看到幾張取決於這裡的 `flex-basis`。**改筆數不要去動那個常數。**
   ⚠️ 圓點是「一張照片一顆」（滑動視窗的起點指示），不是「一頁一顆」，
      所以筆數改了圓點不必跟著改——這與相關連結那個 scroll-snap 輪播不同，
      那邊的圓點是按頁算的。
   ⚠️ 客戶指名的數字（1024→3）與相關連結那一區的規則並不完全相同
      （那邊 ≥1024 是 3 筆、≥1280 變 4 筆）。**以客戶指名的數字為準**，
      沒有跟著加 1280 那一級——照片變大是這一項的目的。
   ⚠️ 扣掉的 px 是 gap（16px）攤到每一張的份：
      2 欄扣 8、3 欄扣 11（16×2/3 ≈ 10.7 取 11）。 */
/* 🔴 **比例必須跟著 `galleryPhotos` 那六張走，不要回到 `4 / 3`**
   （客戶 2026-08-25：「比例依照 newhero-06 這張為主，客戶希望這張可以看到照片中完整文字」）。

   六張全部是 **16:9**（實測 `newhero-01` 1465×824、`02` 1052×592、`03`–`06` 2000×1125，
   比值 1.7770–1.7778）。原本框是 `4 / 3` ＝ 1.333，配 `object-fit: cover`
   → **左右被裁掉約 25%**，而 `newhero-06`（領航金獎頒獎典禮）的橫幅文字正好橫跨整張，
   一裁就少字（客戶看到的是「新北市」被切成「北市」）。
   🔴 框改成 16 / 9 之後與照片**完全相等**，`cover` 一個像素都不會裁。

   ⚠️ **這是「框去配圖」，所以換圖時要一起看**：日後若換上非 16:9 的照片，
      `cover` 又會開始裁切，而且**不會報錯、只是默默少一塊**。
      判準：換圖後量一次 `naturalWidth/naturalHeight`，不等於 1.778 就要回來改這個值
      （或把新圖裁成 16:9 —— 依 `CLAUDE.md`「構圖在上傳前裁好」的規矩，優先選這條）。
   ⚠️ 不要改成 `object-fit: contain` 來「保證不裁」：那會在照片兩側留出深紫底色，
      六張一起看就是六個深色缺口。比例對齊才是正解。 */
.gallery-item {
  flex: 0 0 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  overflow: hidden;
  background-color: var(--purple-950);
  cursor: pointer;
}

.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (min-width: 768px) {
  .gallery-item {
    flex-basis: calc(50% - 8px);
  }
}

@media (min-width: 1024px) {
  .gallery-item {
    flex-basis: calc(33.333% - 11px);
  }
}

/* 箭頭：定位在 1440 容器外側，不疊在圖片上。
   ⚠️ 外觀（尺寸／圓形／配色／陰影／hover）在 style.css 的 `.carousel-arrow`，全站五處共用。
   🔴 **不要在這裡加回尺寸**——2026-08-19 之前 `≥1024` 的放大規則就寫在本檔，
      而課程內頁不載入 index.css，導致 1280 下兩邊差 8px（客戶因此反映「其實有些不同」）。 */
.gallery-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
}

.gallery-arrow-prev {
  left: 4px;
}

.gallery-arrow-next {
  right: 4px;
}

/* ⚠️ `.gallery-dots` / `.gallery-dot` 已移到 style.css（P4，2026-08-18）：
   課程內頁的相關課程輪播也要用它，而那些頁面**不會載入 index.css**。
   🔴 留在這裡的話，相關課程的 dots 會變成沒有樣式的原生按鈕
      （實測是 16×6 的灰色方塊，客戶一眼就看得出不一樣）。 */

@media (min-width: 1024px) {
  /* ⚠️ 尺寸的放大已移到 style.css 的 `.carousel-arrow`（見上方說明），這裡只剩定位。 */
  .gallery-arrow-prev {
    left: max(4px, calc((100% - var(--container-max)) / 2 - 64px));
  }

  .gallery-arrow-next {
    right: max(4px, calc((100% - var(--container-max)) / 2 - 64px));
  }
}
/* ==========================================
   home-03：本會會務（左側直式分類切換 ＋ 右側文章列）
   ------------------------------------------
   ⚠️ 切換按鈕刻意做成「直式」：上一區的最新課程是橫式頁籤，
      兩區相鄰若都用橫式，視覺上會分不出是兩個不同的區塊。
   ========================================== */
.home-news-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 24px;
}

/* 捲動行為（含捲軸厚度與預留空間）全部來自共用元件 .scroll-tabs，
   HTML 上與 .home-news-tabs 一起掛。這裡只留這一列自己的事：
   手機是橫向、768px 以上改直式側欄。
   ⚠️ 不要在這裡重寫 overflow-x／scrollbar-width／padding-bottom——
      那正是「捲軸壓到按鈕」的來源：每處各留一個自己猜的值。 */
.home-news-tabs {
  /* 手機橫向：直式六個按鈕在手機上會佔掉整個畫面高度 */
  flex-direction: row;
}

.home-news-tab {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 16px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface);
  color: var(--color-text);
  font-size: 1rem;
  font-weight: 500;
  white-space: nowrap;
  transition: background-color 0.2s ease-out, color 0.2s ease-out, border-color 0.2s ease-out;
}

.home-news-tab svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  /* 手機橫排時箭頭沒有意義（它是指向右側內容的），只有直排才顯示 */
  display: none;
}

.home-news-tab:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.home-news-tab.is-active {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
  color: #FFFFFF;
}

.home-news-main {
  min-width: 0;
}

@media (min-width: 1024px) {
  .home-news-layout {
    grid-template-columns: 240px minmax(0, 1fr);
    gap: 40px;
  }

  /* 768px 起變直式側欄，不再需要捲動——把 .scroll-tabs 的捲動相關值關掉。
     ⚠️ padding-bottom 也要歸零，不然側欄底部會多出 12px 空白。 */
  .home-news-tabs {
    flex-direction: column;
    overflow-x: visible;
    padding-bottom: 0;
  }

  .home-news-tab {
    width: 100%;
  }

  .home-news-tab svg {
    display: block;
  }
}

/* ==========================================
   home-05：相關連結輪播
   ------------------------------------------
   🔴 用 CSS scroll-snap 而不是 JS 控制 transform。
      理由一：JS 沒跑時使用者仍然可以用觸控／觸控板／鍵盤左右滑動看完所有連結，
              箭頭與圓點只是加強（活動相簿那套 transform 輪播 JS 一沒跑就完全動不了）。
      理由二：不必複製活動相簿那套含緩衝格的無限輪播邏輯（約 80 行）。
   ⚠️ 兩者行為刻意不同：相簿是連續照片可無限循環，這裡是離散的卡片、到底就停住。
   ========================================== */
.home-links {
  /* 上方 padding 原本是 0，與「成為專屬夥伴」區的相簿輪播貼在一起。
     用 --spacing-section-sm 讓兩區有明確分界（客戶反映緊貼）。 */
  padding: var(--spacing-section-sm) var(--page-gutter) var(--spacing-section);
}

.home-links-inner {
  max-width: var(--container-max);
  margin: 0 auto;
}

.home-links-carousel {
  position: relative;
  margin-top: 8px;
}

.home-links-carousel-inner {
  max-width: var(--container-max);
  margin: 0 auto;
}

/* 🔴 M14（客戶 2026-08-17）：首頁最新課程在 1280 以下改成橫向輪播。
   手機把 6 筆課程直排會讓首頁變得非常長。

   ⚠️ `#courses-list` 同時掛著共用元件 `.courses-grid`：
      **1280 以上要用回它原本的格線**，所以這裡只覆寫 1280 以下，
      🔴 **不要去改 `style.css` 的 `.courses-grid` 本身**
         ——`courses.html` 的課程列表也用它，改了那一頁會變成一條橫向輪播。
   ⚠️ 這一組（viewport／track／卡片寬）與相關連結那一組刻意寫成同樣的結構，
      JS 也共用 `window.initScrollCarousel`。
   ⚠️ 每頁筆數與 M4 同一套規則：<768 一筆／768–1023 兩筆／≥1024 三筆。 */
.home-courses-carousel {
  position: relative;
}

@media (max-width: 1279px) {
  .home-courses-viewport {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;
    /* 卡片有陰影與 hover 位移，上下留一點空間免得被裁掉 */
    padding: 4px 0 12px;
  }

  .home-courses-viewport::-webkit-scrollbar {
    display: none;
  }

  /* 覆寫 .courses-grid 的 grid，改成橫向軌道 */
  .home-courses-viewport .courses-grid {
    display: flex;
    gap: 24px;
  }

  .home-courses-viewport .course-card {
    flex: 0 0 calc(100% - 8px);
    scroll-snap-align: start;
  }

  /* 空狀態在 flex 軌道裡要自己占滿一整頁，否則會縮成一小條文字。
     ⚠️ 它在格線模式下靠的是 `grid-column: 1 / -1`（style.css 的共用元件），
        那條在 flex 下不生效——這是同一個元件在兩種版面下各需要一行的情形。 */
  .home-courses-viewport .course-list-empty {
    flex: 0 0 100%;
  }
}

@media (min-width: 768px) and (max-width: 1023px) {
  .home-courses-viewport .course-card {
    flex-basis: calc(50% - 12px);
  }
}

@media (min-width: 1024px) and (max-width: 1279px) {
  .home-courses-viewport .course-card {
    flex-basis: calc(33.333% - 16px);
  }
}

/* 🔴 P4（客戶 2026-08-18 第 3 項）：**只有 <1024** 把箭頭從「浮在卡片上」改成
   與 dots 排成一列（左箭頭 ─ dots ─ 右箭頭）。
   客戶原話：「1024px 瀏覽時課程輪播的左右箭頭會遮擋到課程卡片……
   **其他我沒有提到的尺寸就不需要調整、不要更動到**。」
   ⚠️ 所以 1024–1279 維持原本「箭頭浮在兩側」的樣子，1280 以上照舊整組隱藏。
   ⚠️ 客戶說的是「1024px 瀏覽時」會遮到，而 1024 這個寬度屬於「桌機導覽已顯示」的範圍；
      **遮擋發生在比 1024 更窄的地方**（卡片寬度變大、箭頭壓在卡片上），
      所以斷點取 <1024。要改成含 1024 本身的話，那是客戶說的「不要更動」的尺寸，需先問過。 */
@media (max-width: 1023px) {
  .home-courses-carousel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    /* row-gap 40px 取代 dots 原本的 margin-top，column-gap 16px 是箭頭與 dots 的間距 */
    gap: 40px 16px;
  }

  .home-courses-viewport {
    order: 1;
    flex: 0 0 100%;
  }

  /* 從「浮在卡片上」改成「排在同一列」——position 與 transform 都要清掉，
     不然它仍然被拉離文件流、也仍然被 translateY(-50%) 往上推。 */
  .home-courses-carousel .gallery-arrow {
    position: static;
    transform: none;
  }

  .home-courses-carousel .gallery-arrow-prev {
    order: 2;
  }

  .home-courses-carousel #home-courses-dots {
    order: 3;
    margin-top: 0;
  }

  .home-courses-carousel .gallery-arrow-next {
    order: 4;
  }
}

/* 1280 以上不需要輪播的控制項。
   ⚠️ 箭頭其實也會被 JS 隱藏（canScroll() 為 false），
      但 JS 沒跑時就不會——所以 CSS 這一層也要擋，否則會看到兩顆按不動的箭頭。 */
@media (min-width: 1280px) {
  .home-courses-carousel .gallery-arrow,
  #home-courses-dots {
    display: none;
  }
}

.home-links-viewport {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  /* 卡片有陰影與 hover 位移，上下留一點空間免得被裁掉 */
  padding: 4px 0 12px;
}

.home-links-viewport::-webkit-scrollbar {
  display: none;
}

.home-links-track {
  display: flex;
  gap: 24px;
}

.home-links-track .link-card {
  flex: 0 0 calc(100% - 8px);
  scroll-snap-align: start;
}

/* 沒有連結時不要留一塊空白 */
.home-links-track:empty {
  display: none;
}

@media (min-width: 640px) {
  .home-links-track .link-card {
    flex-basis: calc(50% - 12px);
  }
}

@media (min-width: 1024px) {
  .home-links-track .link-card {
    flex-basis: calc(33.333% - 16px);
  }
}

@media (min-width: 1280px) {
  .home-links-track .link-card {
    flex-basis: calc(25% - 18px);
  }
}

/* ⚠️ 原本這裡有一條 `.gallery-arrow[hidden] { display: none }`，2026-08-13 刪除：
   已由 `style.css` Base Reset 的全站 `[hidden][hidden]` 涵蓋（見 CLAUDE.md 五節 2-2）。 */

@media (prefers-reduced-motion: reduce) {
  .home-links-viewport {
    scroll-behavior: auto;
  }
}

/* 第 3 項：首頁最新課程的分類切換靠左，不置中（客戶要求）。
   .pill-tabs 是共用元件、預設置中，這裡用修飾 class 覆寫，不改共用元件本身
   ——本會會務列表頁仍需要置中。 */
#home-course-tabs {
  justify-content: flex-start;
  margin-bottom: 32px;
  /* 🔴 S1（客戶 2026-08-26）：分類多時手機版要能左右滑，不要換行往下排
     ——換行會把課程卡片推到很下方才出現。

     🔴 **HTML 掛了 `.scroll-tabs` 還不夠，這一行不可省。**
        `.pill-tabs`（style.css:3615）自己宣告了 `flex-wrap: wrap`，
        而 `.scroll-tabs`（style.css:3476）**沒有宣告 flex-wrap**（靠預設的 nowrap）。
        兩者特異性同為 (0,1,0)，`.pill-tabs` 排在後面 → wrap 贏，
        **掛了 `.scroll-tabs` 也不會橫捲，只會多一個誤導的 class**。
        ⚠️ 這與 `news.css` 的 `#news-tabs`（M7）踩的是同一個坑，做法照抄。 */
  flex-wrap: nowrap;
}

/* ≥1280 還原成原本的樣子（分類排得下，不需要橫捲）。
   ⚠️ 要把 `.scroll-tabs` 帶進來的三件事一起還原，否則桌機會多出 12px 的捲軸留白：
      flex-wrap、overflow、padding-bottom。
   🔴 用 `overflow: visible`（**兩軸**）不是只寫 `overflow-x: visible`：
      `.scroll-tabs` 另外有 `overflow-y: hidden`，而依 CSS 規範
      **一軸 visible 搭另一軸非 visible 時，visible 會被算成 auto**
      ——只改 x 的話算出值仍是 `auto`，那條註解就變成一個錯的保證。 */
@media (min-width: 1280px) {
  #home-course-tabs {
    flex-wrap: wrap;
    overflow: visible;
    padding-bottom: 0;
  }
}
