/* 版位。顏色一律 var(--px-*)，來源 tokens.generated.css（契約 L1）。
   這一版只有導覽列與 hero（契約 L3 的第 1、2 段），其餘版位之後再補。 */

/* ── 導覽列（契約 L3-1，sticky） ───────────────────────────────── */

.nav {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 12px 24px;
  background: var(--px-surface-panel);
  border-bottom: 3px solid var(--px-ink);
}

.nav__brand {
  font-family: 'Cubic11';
  font-size: 22px;
  margin-right: auto;
}

.nav__link {
  font-family: 'Cubic11';
  font-size: 22px;
  color: var(--px-ink);
  text-decoration: none;
}

/* hover 用 --px-wood-dark (#734C44) 不是 --px-wood (#B55945)：
   對導覽列底色 --px-surface-panel (#FEE1B8)，--px-wood 只有 3.72:1，不過 AA；
   --px-wood-dark 是 5.86:1。平時的 --px-ink 對 paper 是 14.92:1，不用動。
   （三個數字都是 WCAG 2.x 相對亮度公式現算的。） */
.nav__link:hover {
  color: var(--px-wood-dark);
}

/* ── Hero（契約 L3-2 / L4） ───────────────────────────────────── */

.hero {
  padding: 72px 0 0;
  text-align: center;
}

.hero__sub {
  max-width: 34em;
  margin: 24px auto 32px;
}

/*
 * 佔位背景。之後補插畫**只動這一個 class**（契約 L20）。
 * 現在：草地 tile 橫向鋪滿一條地平線帶，上緣那條 3px ink 就是地平線本身。
 * 不做景深、雲、水面反光——那些是之後那張插畫的事。
 *
 * 兩件跟計畫不一樣、但非改不可的事：
 *
 * 1. background-size 是 112px，不是計畫寫的 64px。
 *    assets/sprites/grass_tile.png 實際是 112×112（sips 量過）。64/112 = 0.57×，
 *    是縮小且非整數倍，會把點陣重新取樣糊掉——違反「像素圖放大只能整數倍」（契約 L5）。
 *    要放大只能是 224 / 336 這種 112 的整數倍。
 *
 * 2. 不鋪柵欄。assets/sprites/fence_run.png（128×128）橫向連鋪，每 128px 有一道
 *    明顯斷縫、橫桿接不起來，鋪成地平線會看起來像壞掉。契約 L4 的「柵欄／草地」
 *    是「或」不是「且」，所以只鋪草地仍在契約內。
 *
 * height 用 112px（= 1 塊 tile 的高）而不是計畫的 220px：tile 是 repeat-x 貼在底部，
 * 220px 會讓上半 108px 露出沒有紋理的純色，看起來像圖沒載完。
 *
 * image-rendering 這裡要自己寫一次：base.css 的 `.pixelated` 那條要掛 class 才生效，
 * 而這是 CSS background 不是 <img>（瀏覽器縮放／非整數 devicePixelRatio 時會用得上）。
 * 2026-09-02 補記：base.css 原本那條是 `img, .pixelated {...}`，已經收窄成只剩 .pixelated
 * （理由見 base.css 該處註解），所以這一行更不能刪。
 */
.hero__scene {
  height: 112px;
  margin-top: 56px;
  background-color: var(--px-grass);
  background-image: url('./tiles/grass_tile.png');
  background-repeat: repeat-x;
  background-size: 112px 112px;
  background-position: bottom left;
  border-top: 3px solid var(--px-ink);
  image-rendering: pixelated;
}

/* ── 三格賣點（契約 L3-3 / L5） ───────────────────────────────── */

/*
 * padding 的左右是 24px 不是計畫寫的 0：這個 section 同時掛著 .wrap，
 * 而 .wrap 的 `padding: 0 24px` 會被這一條整個覆蓋掉（簡寫的四個邊都會寫入）。
 * 寫 `72px 0` 的話，窄螢幕上文字會直接貼到視窗邊緣。
 */
.pillars {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
  padding: 72px 24px;
}

.pillar { text-align: center; }

/*
 * icon 是 16×16 的原生點陣（web/icons/*.png，由 npm run landing:icons 從
 * assets/kits/ui/PNG/Icons.png 切出來）。96 / 16 = 6，整數倍，符合契約 L5。
 *
 * 契約 L5 寫的是「32 → 64 → 96」，因為它假設來源是 32×32。實際來源是 16×16
 * （理由見 scripts/build-landing-icons.ts 的檔頭），所以合法的級距是 16 的整數倍。
 * 96 同時落在兩套級距上，換來源這件事沒有動到畫面尺寸。
 *
 * image-rendering 這裡要自己寫一次，不靠 base.css 那條全域的
 * `img, .pixelated { image-rendering: pixelated; }`：
 * 那條選得到頁面上每一張 <img>，包含契約 L6／L7 要放的截圖。截圖不是點陣圖，
 * 用 pixelated 縮放會有嚴重鋸齒——那條遲早要收窄。
 * 2026-09-02：收窄的那一天到了，base.css 已經只剩 `.pixelated`（量測見該處註解）。
 * 這一行就是當初預留的那一份，別把它當成重複宣告刪掉——
 * src/__tests__/landingWindow.test.ts 有一條測試盯著它。
 */
.pillar__icon {
  --icon-size: 96px;
  display: block;
  width: var(--icon-size);
  height: var(--icon-size);
  margin: 0 auto;
  image-rendering: pixelated;
}

.pillar__title { margin: 16px 0 8px; }

/* ── 敘事段（契約 L3-4 / L6） ─────────────────────────────────── */

/*
 * 一句大標 + 一段內文 + 一張包在 pixel 視窗裡的截圖。左右交錯：1、3 段圖在右，
 * 第 2 段圖在左（契約 L6）。
 *
 * 320px 這個數字是承重的：win.css 的 .shot 是 `width: 100%` + `aspect-ratio: 491/1000`，
 * 所以視窗寬度由這一欄決定，截圖的顯示高度跟著算出來（320 × 1000/491 ≈ 652px）。
 * web/shots/ 的 webp 是 640 寬——正好是 320 的 2 倍，2× 螢幕上一個像素都不用內插。
 * （重產指令與理由見 web/shots/README.md。）
 *
 * padding 的左右是 24px 不是 0：這個 section 同時掛著 .wrap，簡寫的四個邊會把
 * .wrap 的 `padding: 0 24px` 整個覆蓋掉。跟上面 .pillars 同一個坑，理由見那裡。
 */
.story {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 56px;
  align-items: center;
  padding: 72px 24px;
}

/*
 * 交錯的那一段。**欄寬也要跟著換邊，不能只換 order。**
 *
 * 計畫原本只寫 `.story--flip .story__text { order: 2 }`。那樣做的話文字被排到第 2 欄，
 * 而第 2 欄是 320px——文字變成 320px 窄條、視窗吃掉 1fr 被撐成 700 多寬，
 * 截圖會放大到原生尺寸以上而糊掉。所以欄寬在這裡反過來寫成 `320px 1fr`：
 * 視窗（order 預設 0，排第 1 欄）拿 320px，文字（order 2，排第 2 欄）拿 1fr。
 */
.story--flip {
  grid-template-columns: 320px 1fr;
}

.story--flip .story__text {
  order: 2;
}

/*
 * 進場動畫（契約 L13）。**整頁只有這一種動畫**，沒有視差、沒有跟隨捲動的東西。
 * 起始態與終態都寫在 CSS，web/reveal.js 只負責在捲進畫面時加上 .is-in。
 */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 400ms ease, transform 400ms ease;
}

.reveal.is-in {
  opacity: 1;
  transform: none;
}

/*
 * 契約 L13：reduce 時**直接顯示終態**，不是「動畫變快」。
 *
 * 所以這裡三行缺一不可，而且 opacity／transform 那兩行才是重點：
 * 只寫 `transition: none` 的話，.reveal 會停在 `opacity: 0`——IntersectionObserver
 * 沒掛上（JS 掛了、被擋掉、或使用者根本沒捲到）的時候，這三段就是永久看不見。
 * src/__tests__/landingMotion.test.ts 用「只寫 transition: none」當反證盯著這一條。
 *
 * 這是**媒體查詢不是斷點**——契約 L14 的兩個斷點（768 / 480）是另一回事。
 */
@media (prefers-reduced-motion: reduce) {
  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ── Waitlist（契約 L3-5 / L9 / L12） ─────────────────────────── */

/*
 * padding 的左右是 24px 不是計畫寫的 0：這個 section 同時掛著 .wrap，
 * 簡寫的四個邊會把 .wrap 的 `padding: 0 24px` 整個覆蓋掉。
 * 跟上面 .pillars／.story 同一個坑，理由見那裡。
 */
.waitlist {
  padding: 72px 24px;
  text-align: center;
}

/*
 * flex-wrap 不是斷點，是「不要在窄螢幕上把整頁撐出橫向捲軸」。
 * 欄位 280px + 間距 12px + 按鈕約 130px ≈ 440px，比 375px 的視窗寬。
 * 窄螢幕的正式排版留給契約 L14 的斷點（Task 9），這裡只保證它不會溢出。
 */
.waitlist__form {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: center;
  margin: 24px 0 8px;
}

/*
 * 計畫沒給 input 任何樣式，那會在這一頁上留一個原生方框。
 *
 * 字型是**系統字**不是 Cubic11：使用者打進去的是內文不是標籤（契約 L2）。
 * placeholder 用 --px-stone-dark (#636663) 對 --px-surface-panel (#FEE1B8) 是 4.62:1，
 * 過 WCAG AA。**注意它對頁面底色 --px-surface-screen (#D4C692) 只有 3.40:1**，
 * 所以這個顏色只能用在 paper 底上，別搬到頁面背景上。
 * （對比數字都是 WCAG 2.x 相對亮度公式現算的。）
 */
.waitlist__input {
  flex: 0 1 280px;
  min-width: 0;
  padding: 12px 16px;
  font-family: var(--prose-stack);
  font-size: 17px;
  background: var(--px-surface-panel);
  color: var(--px-ink);
  border: 3px solid var(--px-ink);
  border-radius: 4px;
}

.waitlist__input::placeholder {
  color: var(--px-stone-dark);
}

/* 鍵盤使用者要看得到自己在哪一格。這條刪掉就等於把 focus 藏起來。 */
.waitlist__input:focus-visible {
  outline: 3px solid var(--px-accent-deep);
  outline-offset: 2px;
}

/*
 * 錯誤訊息（契約 L9 的三句話裡的兩句）。
 *
 * 這是**無障礙不是品味**：計畫原本寫 `color: var(--px-wood)`，而 --px-wood (#B55945)
 * 對頁面底色 --px-surface-screen (#D4C692) 只有 2.74:1，差得很遠；
 * 退一步的 --px-wood-dark (#734C44) 對同一個底也只有 4.32:1，還是不到 4.5:1。
 * 所以把它放進一塊 paper 底的小牌子：--px-wood-dark 對 --px-surface-panel (#FEE1B8)
 * 是 5.86:1，過 AA，而且仍然是「紅字」。牌子這個形狀也正好是這一頁的視覺語言。
 * （四個數字都是 WCAG 2.x 相對亮度公式現算的；review 量到的是 2.77／4.36，
 *  差在小數第二位，結論一樣。）
 *
 * 字級用 .px-label（22px）不是 .px-micro（11px）：錯誤訊息是使用者**現在必須讀懂**
 * 的東西，11px 的繁中點陣字太小。
 */
#waitlist-error {
  display: inline-block;
  margin: 8px 0 0;
  padding: 8px 16px;
  background: var(--px-surface-panel);
  border: 3px solid var(--px-wood-dark);
  border-radius: 4px;
  color: var(--px-wood-dark);
}

/*
 * 上面那條用 id 選擇器（特異性 1-0-0）寫了 display，會蓋掉瀏覽器預設樣式表裡
 * `[hidden] { display: none }`（0-1-0）。少了這一條，`error.hidden = true` 之後
 * 畫面上會留一塊空的紅牌子——**而且沒有任何測試會紅，只會在螢幕上很怪**。
 * src/__tests__/landingWaitlist.test.ts 有一條護欄盯著這件事。
 */
#waitlist-error[hidden] {
  display: none;
}

/*
 * 隱私那一行（契約 L12：11px **系統字**，不是點陣字）。
 *
 * 顏色刻意不寫：.prose 已經是 --px-ink-soft (#3D3333)，對頁面底色
 * --px-surface-screen (#D4C692) 是 7.15:1。計畫原本要換成 --px-stone-dark
 * 的 3.40:1 是不及格的——而這一行正是契約 L12 的隱私承諾，它必須讀得到。
 */
.waitlist__note {
  font-size: 11px;
  margin: 16px 0 0;
}

/*
 * 成功視窗（契約 L9）。固定在畫面底部，z-index 高於 sticky 導覽列的 10。
 */
.waitlist__modal {
  position: fixed;
  inset: auto 0 24px;
  max-width: 420px;
  margin: 0 auto;
  z-index: 20;
}

.waitlist__modal-body {
  padding: 16px;
  text-align: center;
}

#waitlist-modal-title {
  margin: 0 0 8px;
}

/*
 * pre-line 是承重的：COPY.success 是 `開發時間預計 ${eta} 天，\n完成後會通知您下載。`，
 * 而 waitlist.js 用 textContent 寫入。HTML 預設的 white-space: normal 會把那個 \n
 * 摺成一個空格——契約 L9 明寫的兩行就變成一行，而且不會有任何測試紅。
 */
#waitlist-modal-body {
  margin: 0;
  white-space: pre-line;
}

/*
 * 這一顆 × **是**真的可點——視窗是使用者的動作叫出來的，沒有出口就是陷阱（契約 L9）。
 * 跟 win.css 那顆 .win__deco 裝飾按鈕不同，那一顆有 pointer-events: none，這一顆不准有。
 * --px-highlight (#CCE2E1) 對標題列的 --px-accent-deep (#222A5C) 是 10.0:1（見 win.css）。
 */
.win__close {
  padding: 0 4px;
  background: none;
  border: none;
  color: var(--px-highlight);
  cursor: pointer;
}

.win__close:focus-visible {
  outline: 3px solid var(--px-highlight);
  outline-offset: 2px;
}

/* ── Footer 授權標示（契約 L3-6 / L16） ───────────────────────── */

/*
 * padding 用**長寫的上下兩條**，不是 `padding: 48px 0` 那種簡寫。
 *
 * 這個 <footer> 同時掛著 .wrap（`padding: 0 24px`），簡寫的四個邊會把左右那 24px
 * 一起覆蓋掉，窄螢幕上文字會直接貼到視窗邊緣——.pillars／.story／.waitlist 三個
 * section 就是踩了這個坑，才各自要重寫一次 24px，然後 480 的斷點又要再重寫一次 16px。
 * 只寫上下的話，左右完全交給 .wrap，480 斷點縮 padding 這件事自動跟著生效，
 * 不用在斷點裡再多列一個選擇器。
 */
.footer {
  padding-top: 48px;
  padding-bottom: 48px;
  border-top: 3px solid var(--px-ink);
}

/*
 * 授權那三行用 .prose（系統字）11px，不是 .px-micro（11px 點陣字）。
 * 契約 L2：內文一律系統字。這三行是句子，而且混著 "SIL Open Font License 1.1"、
 * "craftpix.net" 這種拉丁小字——跟 .waitlist__note（契約 L12 的隱私那一行）同一種東西，
 * 那裡也是這樣寫的。
 */
.footer__line {
  font-size: 11px;
  margin: 0 0 8px;
}

/*
 * 連結顏色明寫 --px-ink：對頁面底色 --px-surface-screen (#D4C692) 是 11.1:1。
 * 不寫的話會吃到瀏覽器預設的藍色連結，那個顏色沒人量過對比。
 * **不可以換成** --px-wood (2.74)、--px-stone-dark (3.40)、--px-wood-dark (4.32)，
 * 三組都不過 WCAG AA 的 4.5:1。底線留著——11px 的連結只靠顏色分辨太吃力。
 * （數字是 WCAG 2.x 相對亮度公式算的。）
 */
.footer__link {
  color: var(--px-ink);
}

.footer__link:focus-visible {
  outline: 3px solid var(--px-accent-deep);
  outline-offset: 2px;
}

/* ── RWD（契約 L14） ──────────────────────────────────────────────
 *
 * 只有兩個斷點：768（平板／窄桌機）與 480（手機）。契約 L14 明寫就這兩個，
 * 而且 `<360px` 不做特別處理。
 *
 * Task 4 曾經另外加過一個 720px 的媒體查詢（三格賣點改單欄）。
 * 那一塊已經併進 768——三個斷點會在 720–768 之間多出一個沒人設計過、也沒人看過的
 * 中間狀態（賣點還是三欄、敘事段卻已經單欄）。併進來的同時把 gap／padding 一起帶過來，
 * 所以單欄時的間距沒有變。src/__tests__/landingMeta.test.ts 釘死媒體查詢的**總數**是 3
 * （768、480、prefers-reduced-motion），防的就是這種漂移再長回來。
 * （這一段註解刻意不寫出那個 at-rule 的字面字串：手動 `grep -c` 這個檔會把註解裡的
 *   示範字串一起數進去，數字對不上會讓人以為斷點又多了一個。測試本身是先剝註解再數的。）
 *
 * 這兩塊放在檔案最後面：它們要覆寫的規則（.pillars／.story／.story--flip／.wrap 那幾條）
 * 特異性一模一樣，靠後來居上贏。往上搬就會靜悄悄地失效。
 */

@media (max-width: 768px) {
  /* 三欄各 1/3 寬時，96px 的 icon 與 17px 內文會擠成細長條。 */
  .pillars {
    grid-template-columns: 1fr;
    gap: 48px;
    padding: 48px 24px;
  }

  /* 敘事段全部單欄，圖在文字下方（契約 L14）。 */
  .story {
    grid-template-columns: 1fr;
    gap: 32px;
    padding: 48px 24px;
  }

  /*
   * 交錯的那一段要**兩件事一起還原**，不是只還原 order。
   * 桌機版的 .story--flip 是 `grid-template-columns: 320px 1fr` +
   * `.story__text { order: 2 }` 一起做的（理由見上面 .story--flip 的註解）。
   * - 只還原 order：欄寬還是 `320px 1fr`，單欄時第一欄被釘在 320px，文字擠成窄條。
   * - 只還原欄寬：order 還是 2，第 2 段的圖會跑到文字上面，跟其他兩段不一致。
   */
  .story--flip {
    grid-template-columns: 1fr;
  }

  .story--flip .story__text {
    order: 0;
  }

  /*
   * 視窗（截圖外框）在單欄時會被撐到整個欄寬。web/shots/ 的 webp 是 640 寬，
   * 撐超過 320px 就開始放大內插；而且一張 491:1000 的直立截圖佔滿整個畫面寬
   * 會高到一個畫面放不下。釘回 320px 並置中，跟桌機版的顯示尺寸一致。
   */
  .win {
    max-width: 320px;
    margin: 0 auto;
  }

  /*
   * 導覽列只留站名與 CTA。三個 22px 的點陣連結 + 站名 + 按鈕在 768 以下會換行，
   * 把 sticky 導覽列撐成兩層。連結指向的三個 section 就在同一頁上，捲一下就到，
   * 藏起來不會讓任何內容變成到不了。
   */
  .nav__link {
    display: none;
  }
}

@media (max-width: 480px) {
  /* 主標降一級：44 → 33，仍是 11 的整數倍（契約 L2／L14）。 */
  .px-title {
    font-size: 33px;
  }

  /*
   * padding 縮小（契約 L14）。
   *
   * **只改 .wrap 是沒有用的**：.pillars／.story／.waitlist 三個 section 同時掛著 .wrap，
   * 而它們各自寫了 `padding: … 24px` 的簡寫，簡寫的四個邊會把 .wrap 那條整個覆蓋掉
   * （理由見上面那三處的註解）。所以四條都要縮，少一條就有一個 section 不動。
   */
  .wrap {
    padding: 0 16px;
  }

  .pillars {
    padding: 48px 16px;
  }

  .story {
    padding: 48px 16px;
  }

  .waitlist {
    padding: 48px 16px;
  }

  /*
   * 表單直排。桌機是 flex-wrap 讓它自己換行（見上面 .waitlist__form 的註解），
   * 但換行之後按鈕會被 justify-content: center 排成置中的一小顆，
   * 在 375px 上看起來像沒對齊的孤兒。直排 + stretch 讓欄位與按鈕同寬、上下疊。
   */
  .waitlist__form {
    flex-direction: column;
    align-items: stretch;
  }

  /*
   * flex-basis 一定要跟著改回 auto。**這不是清理，是修一個會炸掉版面的東西。**
   *
   * .waitlist__input 桌機版是 `flex: 0 1 280px`，那個 280px 是 flex-basis；
   * flex-basis 量的是**主軸**，而主軸剛剛被上面那條 flex-direction: column 轉成了縱向。
   * 於是 280px 從「欄位寬 280」變成「欄位**高** 280」——375px 上量到的是
   * 一個 328×280 的巨大空框（Chrome getBoundingClientRect，2026-09-02）。
   * 改成 auto 之後高度回到內容高（17px 內文 + 上下 12px padding + 3px 外框）。
   *
   * 寬度不用寫：align-items: stretch 已經讓它跟按鈕一樣滿欄寬。
   */
  .waitlist__input {
    flex: 0 0 auto;
  }

  /*
   * 導覽列的左右 padding 與 gap 也要縮，否則 CTA 會被擠到換行。
   *
   * 375px 實測（Chrome getBoundingClientRect，2026-09-02；扣掉 15px 捲軸剩 360 可用）：
   * 站名 154 + gap 24 + padding 48 = 226，留給按鈕只剩 134，
   * 而「加入名單」這顆按鈕自然寬是 149.3。差 15px，它就斷成「加入名／單」兩行，
   * 把 sticky 導覽列從 82px 撐成 107px（量到的 .nav 高度）。
   * 縮成 padding 16、gap 16 之後：360 − 32 − 154 − 16 = 158 ≥ 149.3，還剩 8.7px。
   * 這 8.7px 是真的很緊——導覽列之後要再加東西，先回來量一次。
   */
  .nav {
    padding: 12px 16px;
    gap: 16px;
  }
}
