/* ==========================================================================
   前台系統整合樣式
   --------------------------------------------------------------------------
   這個檔案存在的唯一理由：把設計師的靜態頁接上真實系統時，有幾個東西是
   靜態頁不需要、但接上後端與 Vue 之後一定會用到的。

   為什麼不直接寫進 main.css：
   main.css 是設計師的交付物，由 aicontest-ui 同步過來。專案規範是
   「前台畫面以設計師版本為準」，一旦把整合用的規則混進去，
   下次設計師出新版時就分不清哪幾行是設計、哪幾行是我們加的。

   規則：
   1. 只放「靜態頁不會有、系統才需要」的樣式（Vue 未掛載前的閃爍、
      驗證碼圖片的排版）。
   2. 一律使用 main.css 已定義的 CSS 變數，不引入新的色票或尺寸。
   3. 任何屬於「畫面長相」的調整都不該進來——那要回去請設計師改。
   ========================================================================== */

/* Vue 掛載前先藏起插值標記，否則使用者會看到一閃而過的 [[ message ]] */
[v-cloak] {
  display: none !important;
}

/* 驗證碼：設計稿沒有這個欄位（後端 /portal/api/* 必須帶 captcha 才會過），
   排版沿用 .field 的節奏，圖片高度對齊 .field__input 的 44px 最小高度。 */
.captcha-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.captcha-row .field__input {
  flex: 1 1 auto;
  inline-size: auto;
}

.captcha-row__image {
  block-size: 44px;
  border: 1px solid var(--color-line-on-dark);
  border-radius: var(--radius-control);
  cursor: pointer;
}

/* 淺色面板（.field--light 所在的區塊）上的驗證碼框線比照淺色欄位 */
.field--light .captcha-row__image {
  border-color: var(--color-line);
}

/* 登入／註冊的分頁按鈕：設計師用 <button>，我們用 <a>。

   設計稿把登入與註冊畫成同一頁的兩個面板，用 JS 切換 <button role="tab">。
   後端早就是 /portal/login 與 /portal/register 兩條路由（2026-08-10 決議
   「視覺照搬、路由照後端」），所以這裡必須是真的連結——用 button 加 JS 轉頁
   會讓右鍵開新分頁、複製網址、瀏覽器上一頁全部失效。

   .auth-seg__btn 的置中是靠瀏覽器對 <button> 的預設行為（button 的內容盒
   本來就是置中的），CSS 裡只有 flex: 1 與 min-block-size。換成 <a> 之後
   flex 子項被塊化，文字會靠左靠上，而且多一條底線——症狀就是「註冊頁跑版」。

   這裡補的是 <button> 本來就有、<a> 沒有的那幾項，不改任何設計。 */
.auth-seg__btn {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  text-decoration: none;
}

/* 後端回傳 field 時標出是哪一個欄位。設計稿只畫了區塊層級的
   .portal-alert，沒有欄位層級的錯誤樣式；報名表有二十幾個欄位，
   只說「某欄位有誤」而不指出是哪一個，使用者得自己一格一格找。
   用的是 main.css 既有的 --color-danger，沒有引入新色。 */
.field__input.is-invalid {
  border-color: var(--color-danger);
}

/* 活動花絮的 YouTube 嵌入播放（2026-08-12，static/js/site/news-gallery-inject.js）。

   設計稿的 .gallery-card__media 只設計給 <img> 用：main.css 的
   `.gallery-card__media > img` 用絕對定位把圖片撐滿卡片，但選擇器只認
   img，不認 iframe——嵌入播放器沒吃到這條規則，會用瀏覽器預設的
   300x150 顯示，卡片變形。

   `.gallery-card__media--video::after` 是設計稿原本疊在封面圖上的深色
   遮罩＋播放圖示，用來搭配「整塊可點、點了開新分頁」的舊互動；那個
   遮罩沒有 pointer-events: none，疊在真正的 <iframe> 播放器上會擋掉
   所有點擊，使用者點播放鍵沒有反應——症狀是「看得到影片縮圖，點不動」。
   嵌入播放時改用真正的播放器互動，不需要這層遮罩，因此排除。
   用 `.gallery-card__media--embed` 這個修飾字（注入腳本建立 iframe
   時才加上）明確標出「這張卡是嵌入播放」，不用 :has() 選擇器——
   後者在 2023 年底前的 Firefox 不支援，公開活動網站不該預設訪客
   都用最新瀏覽器。 */
.gallery-card__media > iframe {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  border: 0;
}

.gallery-card__media--embed::after {
  content: none;
}

/* 贊助廠商展示的分區排版（贊助與參展頁 #showcase，2026-08-13 修正）：
   設計稿 #showcase 的 lede 明寫「依戰略級、金級、銀級分區顯示」，但那個
   區塊在設計稿裡只有一個空狀態，沒有畫出分區的樣子。分區內容由
   static/js/site/vendor-showcase.js 注入，級別小標題用的是設計師既有的
   `.section-title.section-title--sub`（competition.html 切分同一個 section
   內的子區塊就是用這一組），這裡只補它在設計稿裡沒有的兩段間距。

   為什麼是 #showcase 底下的後代選擇器，而不是新增一個 class：
   前台規則是「只用設計師既有的 class」。#showcase 是設計稿自己的 id，
   `.section-title--sub` 也是設計稿的 class，兩者組合起來就足以只命中這個
   區塊，不必發明新名字。

   為什麼不是在 JS 裡寫 inline style：那會讓「這個標題為什麼有這段距離」的
   答案藏在一支注入腳本的中段，而不是在唯一一個放整合樣式的地方。
   兩個間距都取 main.css 既有的尺寸變數，沒有引入新的數值。 */
#showcase .section-title--sub {
  margin-block-end: var(--space-4);
}

/* 級別之間的距離：只加在「前面已經有一組卡片」的小標題上，第一個級別的
   標題因此緊貼 .section-header，不會多出一段空白。 */
#showcase .card-grid + .section-title--sub {
  margin-block-start: var(--space-12);
}

/* 廠商 Logo：設計師的 .card 沒有 Logo 版位，圖片不限制尺寸的話，一張
   2000px 寬的原圖會把整張卡撐爆。上限值沿用這個區塊原本寫在注入腳本裡的
   inline style（160×80），改放到這裡是為了讓「Logo 為什麼是這個大小」
   跟其他整合樣式在同一個地方；卡片內的垂直間距由 .card 既有的 gap 負責，
   不再另外補 margin。 */
#showcase .card img {
  max-inline-size: 160px;
  max-block-size: 80px;
  object-fit: contain;
}

/* 最新消息「最新公告」清單依競賽項目篩選（2026-08-14，
   static/js/site/news-showcase.js 動態插入）：設計稿只畫了公告清單本身，
   沒有畫篩選控制項或「這則公告屬於哪個競賽」的版位——已登記於
   docs/設計稿與系統落差清單.md。

   不能沿用 .field__input：那是設計給深色表單區塊用的（見 main.css），
   這裡是淺色的 .news-list 區塊（.section，白底），直接套用會變成白底上
   一塊深色選單，跟周圍風格不一致。這裡只用 main.css 既有的色票與尺寸
   變數，比照 .news-item__date 的次要文字調性另外寫一組淺色版本。 */
.news-filter {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-end: var(--space-4);
}

.news-filter__label {
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

.news-filter__select {
  font-family: inherit;
  font-size: 0.875rem;
  min-block-size: 36px;
  padding: var(--space-1) var(--space-3);
  color: inherit;
  background-color: var(--color-white);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-control);
}

/* 公告卡片上的競賽項目小字。刻意不用 .tag 系列 class：.tag 是固定三選一
   的狀態標籤（公告／截止提醒／審查結果，見 news-showcase.js 的
   BADGE_CLASS_BY_LABEL），競賽項目是開放式的名稱，混進同一套視覺語彙
   會讓使用者誤以為狀態標籤變成了不只三種。改用跟 .news-item__date
   一致的次要文字樣式。 */
.news-item__competition {
  font-size: 0.8125rem;
  color: var(--color-text-muted);
}

/* .portal-layout 右欄的內容包裝（2026-08-13；2026-08-17 從 main.css 移回這裡）。

   .portal-layout 是設計師既有的兩欄 grid（標題｜內容），main.css 定義了
   容器本身，但它只認得「前兩個直接子元素＝左欄、右欄」——用它的頁面
   （templates/portal/registration_form.html、submission.html、
   materials.html）常常要在右欄多插一個狀態
   提示，多出來的第三個直接子元素會被 grid 誤判成獨立的排版單位，擠壓
   版面。因此右欄一律包一層 .portal-layout__content，狀態提示放進這層
   包裝內部、跟著內容走，不再是 .portal-layout 自己的子元素。

   這條規則曾經被直接手改進 static/css/site/main.css（違反「main.css 由
   aicontest-ui 同步、不可手改」的規則），2026-08-17 重新從新版設計稿
   轉檔時被覆蓋消失，才發現這個違規。搬回這裡是正式歸位，不是新增功能：
   class 名稱、規則內容與原本完全相同，main.css 的 .portal-layout 容器
   本身才是設計師的東西，不受影響。 */
.portal-layout__content {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  min-inline-size: 0;
}

.hero__host-logo {
  height: auto;
}

/* 頁尾 CONTACT／SITEMAP 間距（2026-08-18 建立，2026-08-25 廢止）：
   原本 .footer-contact 是單一欄，CONTACT／SITEMAP 用 <ul> 緊接 <h2> 的
   方式在同一欄裡堆疊，這裡補的是那個組合特有的間距。2026-08-25 起
   CONTACT／SITEMAP 移到頁尾最下方、改橫式排列，且拆成兩個獨立的
   .footer-contact__group（不再是 ul 緊接 h2），這條選擇器已經命中不到。
   間距改由檔尾 .footer-contact--bar 那組規則負責，見該處。 */

/* Hero KV bar 背景改透明、拿掉負邊界（2026-08-18，使用者要求）：
   theme-2026.css 原本把首頁 KV 圖片下緣、放決賽日期與主辦單位的這條
   資訊列做成一張半透明卡片（漸層背景＋邊框＋陰影＋backdrop-filter 模糊），
   且用負的 margin-top（-1.6rem）疊在 KV 圖片下緣、margin-bottom 2rem
   （首頁另外再疊 .75rem）留白。這裡只清空視覺樣式與這兩個邊界，
   排版（寬度、grid、z-index）仍由 theme-2026.css 負責，不動版面結構。
   `.home-page .hero__kv-bar` 選擇器的特殊性（兩個 class）比這裡單一
   class 的寫法高，兩條都要覆寫，只寫 `.hero__kv-bar` 在首頁會不生效。 */
.hero__kv-bar,
.home-page .hero__kv-bar {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  margin: 0 auto;
}

/* 首頁「總獎金」四張卡片標題可點擊，連到 competition.html 對應分頁錨點
   （2026-08-18，使用者要求）：設計稿的 .card__title 只是純文字，main.css
   的全域 `a { color: var(--color-blue) }` 套用後標題會變色又加底線，
   跟其他 .card__title 的視覺不一致。這裡讓連結文字繼承標題原本的顏色與
   底線設定，只在 hover／focus 時加底線做可點擊提示，不新增色票或尺寸。 */
.prize-grid .card__title a {
  color: inherit;
  text-decoration: none;
}

.prize-grid .card__title a:hover,
.prize-grid .card__title a:focus-visible {
  text-decoration: underline;
}

/* 四個競賽類別分頁（神盾盃／AI 研討會／國防 AI 競賽及陳展／AI 飛行員擂台賽）
   標題下的說明文字收窄至 500px（2026-08-18，使用者要求）：.section-lede
   預設跟隨 .container 寬度，說明文字在寬螢幕下會拉成一整行、行長過長不易
   閱讀，四個分頁統一收窄維持排版一致。 */
#shield-cup .section-header .section-lede,
#ai-seminar .section-header .section-lede,
#defense-ai .section-header .section-lede,
#ai-pilot .section-header .section-lede {
  max-width: 480px;
}

/* AI 研討會分頁掛兩個識別（主題識別 seminar.png ＋協辦單位資策會橫式
   Logo iii.png，2026-08-18，使用者要求）：main.css 的 .track-logo 只設計
   給神盾盃／AI 飛行員的單一直式識別用（inline-size 決定寬、block-size
   auto 依比例算高）。iii.png 是很扁的橫式 Logo（471×80），沿用同一條
   inline-size 規則會被縮到只剩約 1rem 高、看不清字；因此另外用
   .track-logo--wide 改成用 block-size 控制高度，寬度依比例自動算，
   兩張圖統一包在 .track-logo-group 裡維持與其他分頁一致的 header 兩欄
   排版（文字欄｜Logo 欄）。 */
.track-logo-group {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.track-logo--wide {
  inline-size: auto;
  block-size: clamp(1.5rem, 2.5vw, 2.25rem);
}

/* AI 研討會「三大主題」卡片組（2026-08-18，使用者要求）：三張卡原本都套
   .card--accent-cyan，頂部色條同色、背景又跟下方六格資訊卡一樣是純白，
   三個主題彼此不好分辨，整組卡片在頁面上也不夠突出。改成比照首頁
   #about 三張特色卡的既有做法（index.html 已經在用 accent-cyan／
   accent-green／accent-warm 三色），三張卡各用一色，並各自加一層極淡
   同色背景（取 theme-2026.css 既有 accent 漸層的起始色轉半透明，不新增
   色票）。只鎖定 #ai-seminar 底下，不影響 index.html／register.html／
   sponsors.html／transport_contact.html 還在用同一組 class 只要頂部色條
   的地方。 */
#ai-seminar .card-grid--3 {
  margin-block-end: var(--space-12);
}

#ai-seminar .card-grid--3 .card--accent-cyan {
  background: rgba(8, 191, 233, 0.08);
}

#ai-seminar .card-grid--3 .card--accent-green {
  background: rgba(103, 88, 220, 0.08);
}

#ai-seminar .card-grid--3 .card--accent-warm {
  background: rgba(255, 173, 48, 0.08);
}

/* 贊助方案三個級別的金額顏色（sponsors.html #plans，2026-08-18，使用者
   要求）：.prize-card__value 原本固定用 var(--color-warm) 一種顏色，三個
   級別的金額看起來一樣重，不容易一眼分出戰略／金／銀的落差。改成跟著
   各卡片頂部色條同色（card--accent-warm／accent-blue／accent-cyan 既有
   的三色），數字與色條呼應，也讓「級別越高、色彩越暖」的視覺順序更清楚；
   沒有新增色票，且只鎖定 #plans，不影響 index.html 四張獎金卡（那邊的
   .card 沒有 accent 修飾字，選擇器命中不到）。 */
#plans .card--accent-warm .prize-card__value {
  color: var(--color-warm);
}

#plans .card--accent-blue .prize-card__value {
  color: var(--color-blue);
}

#plans .card--accent-cyan .prize-card__value {
  color: var(--color-cyan);
}

/* 首頁「決賽日期」卡片：決賽日期／主辦單位兩欄改上對齊、標籤放大 5px
   （2026-08-18，使用者要求）：theme-2026.css 的 .hero__dates 用
   align-items: center 把兩欄垂直置中，但「主辦單位」欄是 logo（較高）、
   「決賽日期」欄是文字（較矮），置中後兩個標籤（決賽日期／主辦單位）
   看起來高低不齊。這裡只改成 flex-start 讓兩欄從頂端對齊，
   grid-template-columns 等版面設定仍由 theme-2026.css 負責。
   .hero__date-label 原本繼承 main.css 的 0.75rem（12px），用 calc 加 5px
   放大，不寫死新的 rem 數值，維持「原字級 +5px」這個具體需求。 */
.hero__dates {
  align-items: flex-start;
}

.hero__date-label {
  font-size: calc(0.75rem + 5px);
}

/* 參賽者專區的文字對比（2026-08-19，使用者要求）

   兩個問題，根因不同：

   (1) 區塊標題在深色底上看不清楚
       theme-2026.css:102 的 `.section-title { color: #072a5b }` 是**無條件**
       規則，沒有 `.section--dark` 的變體。main.css 的
       `.section--dark { color: var(--color-text-on-dark) }` 只是繼承色，
       任何直接指定 color 的規則都會蓋過它。`.section-lede` 沒有這個問題
       ——main.css 有 `.section--dark .section-lede` 這條更高權重的規則，
       缺的正是同一家族的 `.section-title`，因此補在 class 層而不是逐頁修。

       ⚠️ **影響範圍不只參賽者專區**：`templates/register.html` 也有
       `.section--dark` 包 `.section-title` 的組合，同樣是深藍字壓在藍色
       漸層上。那一頁會一起被修好（原本就是同一個 bug），但它是
       import_ui_static.py 產生的設計稿頁面，值得知道有這個連動。

   (2) `.check-list` 是為深色面板設計的，被放到淺底容器上就看不見
       main.css:2091 起把 `.check-list li` 定成
       `--color-text-muted-on-dark`、項目符號 `--color-amber`、
       完成態 `--color-cyan`——全部假設深色底。專區把它用在兩個淺底容器
       （STEP 04 的面板、STEP 06 的 `.locked-panel`）。

       **用 modifier 而不是逐容器寫選擇器**：第二個容器出現時就證明了
       抽象缺一層；逐容器寫的話，下一個淺底容器仍然會安靜地變成看不見的字。

   一律只用 main.css/theme-2026.css 既有的 CSS 變數，不新增色票。

   > 2026-08-19 更正：上一版在這裡寫了一組 `#review .portal-panel--dark`
   > 覆寫，把面板改成白底深字，理由寫成「兩層藍分不開」。**那個診斷是錯的。**
   > `theme-2026.css:310` 把 `.portal-panel` 放進 glass 群組規則
   > （`background: var(--glass)`，同權重、後載入），所以
   > `.portal-panel--dark` 的底色與陰影**從來沒有生效過**，只有
   > `color: var(--color-text-on-dark)`（白字）活著——白字壓在近白色的
   > glass 面板上，那才是實際症狀。正解是樣板不要掛那個 modifier，
   > 已於同日改掉；當時「那個 class 其他頁面也在用」的說法也不成立，
   > 全專案只有兩處，其中一處還是已導轉的舊頁。 */

/* (1) 深色區塊裡的區塊標題 */
.section--dark .section-title {
  color: var(--color-text-on-dark);
}

/* (2) 淺底容器上的檢查清單 */
.check-list--on-light li {
  color: var(--color-text);
}

.check-list--on-light li::before {
  border-color: var(--color-blue);
  color: var(--color-blue);
}

.check-list--on-light li.is-complete {
  color: var(--color-ink-900);
}

/* 欄位下方的錯誤訊息（2026-08-19，使用者要求）

   接續 A-3：設計稿只有區塊層級的 `.portal-alert`，沒有欄位層級的錯誤版位，
   因此原本只能把 `is-invalid` 的紅框加在輸入框上，訊息本身還是印在頁首。
   報名表有二十幾個欄位，使用者按下「儲存草稿」後看到頁首一句
   「聯絡 Email 格式不正確」，仍然要自己往下找是哪一格。

   這一版把訊息移到該欄位底下（頁首同步讓位，見 index.html 的
   `!hasInlineFieldError`）。度量沿用設計稿既有的 `.field__hint`
   （0.8125rem、`--space-1` 上緣間距），顏色用 A-3 已經在用的
   `--color-danger`，**沒有引入新色票或新度量**。

   已登記在 docs/設計稿與系統落差清單.md A-3，待設計師補正式視覺。 */
.field__error {
  font-size: 0.8125rem;
  color: var(--color-danger);
  margin-block-start: var(--space-1);
}

/* 頁尾深色 Logo 的底板改為完全透明（2026-08-19，使用者要求）

   theme-2026.css:1157 的 `.footer-logo` 基底無條件鋪 `rgba(255,255,255,.92)`
   一塊近白色板，`.footer-logo--dark`（theme-2026.css:1170）只把它降到
   `rgba(255,255,255,.08)`——**不是 0**，所以 8% 白疊在深色頁尾上仍會顯示
   一塊淡灰圓角方塊，看起來像 PNG 沒去背。實際查過 iii.png 與 cycraft.png
   都是 colortype 6（RGBA）、背景像素 alpha=0，去背是好的，方塊來自 CSS。

   改在這裡而不是直接改 theme-2026.css：後者由 scripts/import_ui_static.py
   從 aicontest-ui 同步（該腳本 ASSETS 清單第 88 行），手改會被 --check 擋下
   或在下次同步時被覆蓋。見 .claude/CLAUDE.md 規則 1-1（2026-08-18 補充）。

   只動 background，padding／border-radius／尺寸仍由 theme-2026.css 負責。
   rollback：刪掉這一段即可回到 8% 白底。 */
.footer-logo--dark {
  background: transparent;
}

/* 方形識別標在頁尾 Logo 框內的尺寸（2026-08-19，使用者要求）

   theme-2026.css:1157 的 `.footer-logo` 是 8.4rem × 4.3rem、border-box，
   扣掉 `padding: .45rem .7rem` 後內容區 112 × 54.4px，長寬比 2.06——
   那是為橫式字標訂的扁框。`.footer-logo img` 的 `object-fit: contain`
   取寬高兩個限制中較嚴的一個，所以：

     長寬比 > 2.06 的橫式字標 → 卡寬度，高度只用掉 26%（iii）～90%（cycraft）
     長寬比 < 2.06 的方形識別標 → 卡高度，直接吃滿 100%、上下頂到 padding 內緣

   ncsist.png 長寬比 1.12，是整組唯一屬於後者的，因此看起來像撐爆框。
   這條把它的高度收到 2.8rem（44.8px），上下各留 0.3rem 呼吸空間，
   渲染成 50.1 × 44.8px。

   為什麼是新開 modifier 而不是改 theme-2026.css：後者由
   scripts/import_ui_static.py 從 aicontest-ui 同步（ASSETS 清單第 88 行），
   手改會被 --check 擋下或在下次同步時被覆蓋，見 .claude/CLAUDE.md 規則 1-1。
   設計稿原本的解法是 `.footer-logo--ncsist`（7rem × 5.3rem 另配一個框），
   但那排 modifier 已由使用者全數移除、框要維持一致，所以改成只縮圖不動框。

   命名用 --square 而非 --ncsist：限制條件是「這張圖接近正方形」，
   不是「這是中科院」，之後任何方形識別標掛上來都適用。

   要調大小只改下面這個 max-height。上限 3.4rem（＝100%，回到現況）。
   rollback：刪掉這一段，並移除 site_base.html 該 <a> 上的 footer-logo--square。 */
.footer-logo--square img {
  max-height: 2.8rem;
}

/* 首頁「重要日期與比賽時程」時間軸改成單欄直式版面（2026-08-25，使用者提供
   參考圖＋六筆日期後要求）

   原本 `.timeline--mega`（theme-2026.css:941 起）是左右交錯的雙欄版面，
   只有在 47.999rem 以下的手機斷點（theme-2026.css:1217-1228）才會收合成
   單欄。這裡把那份手機版的排法原封不動搬來當「所有寬度都適用」的預設，
   不新增版型，只是把既有的響應式樣式提早套用——沿用同一批 class
   （`.timeline__item` / `.timeline__dot` / `.timeline__date` /
   `.timeline__stage` / `.timeline__desc`），沒有新增或修改任何標籤結構。

   配色沿用系統既有的藍／青系（`--color-blue`／`--color-cyan`／
   `--glass-blue`，皆為 theme-2026.css :root 定義的既有色票，這裡不引入
   新色票），不採用使用者參考圖裡的綠松石漸層。

   為什麼寫在這裡而不是改 theme-2026.css：後者由
   scripts/import_ui_static.py 從 aicontest-ui 同步，手改會被 --check 擋下
   或在下次同步時被覆蓋，見 .claude/CLAUDE.md 規則 1-1（2026-08-18 補充）。
   templates/index.html 本身已於 2026-08-17 退出自動轉檔（見該檔檔頭），
   這裡的樣式調整不影響其他頁面，`.timeline--mega` 目前也只有這一頁在用。

   rollback：刪掉本區塊（含下面的 .next-deadline 徽章樣式）即可回到原本
   左右交錯的雙欄版面；`templates/index.html` 的時間軸文字改動不受影響，
   兩者互相獨立。 */
.key-timeline-section .timeline--mega {
  width: min(100%, 57rem);
}
.key-timeline-section .timeline--mega::before {
  left: 1.2rem;
  transform: none;
  width: 7px;
}
.key-timeline-section .timeline--mega::after {
  /* 參考圖的直式時間軸只有一條素線＋圓點，沒有底端箭頭裝飾，
     這裡直接關掉繼承自 .timeline::after 的三角形，不留一個沒對齊的箭頭。 */
  display: none;
}
.key-timeline-section .timeline--mega .timeline__item,
.key-timeline-section .timeline--mega .timeline__item:nth-child(even) {
  width: 100%;
  min-height: 0;
  margin-left: 0;
  padding: 0 0 2.5rem 4.5rem;
  text-align: left;
}
.key-timeline-section .timeline--mega .timeline__dot,
.key-timeline-section .timeline--mega .timeline__item:nth-child(even) .timeline__dot {
  left: .1rem;
  right: auto;
}
.key-timeline-section .timeline--mega .timeline__date {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
}
.key-timeline-section .timeline--mega .timeline__item--award {
  margin-top: 0;
  border-radius: 24px;
  padding-right: 1.5rem;
}

/* 徽章：時間軸上方「最近倒數」區塊。

   2026-08-25 原本做成「依伺服器當下日期自動判斷下一個未過期日期」
   （common/schedule_countdown.py + app.py 的 _schedule_next_milestone_data()），
   使用者確認後改為固定顯示第一筆（9/6 報名開始），不再跟日期判斷——
   那支模組與 context processor 已一併移除，這裡改成跟下面 <ol> 一樣
   直接寫死在 templates/index.html。日後這筆要換內容，直接改樣板文字即可，
   不必再回頭改 Python。 */
.next-deadline {
  width: min(100%, 40rem);
  margin: 0 auto 2.5rem;
  padding: 1.5rem 2rem;
  border-radius: var(--radius-card);
  background: var(--glass-blue);
  box-shadow: var(--shadow-md);
  color: var(--color-text-on-dark);
}
.next-deadline__eyebrow {
  margin: 0 0 .35rem;
  font-family: var(--font-display);
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--color-text-muted-on-dark);
}
.next-deadline__body {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .75rem 1.5rem;
}
.next-deadline__date {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 6vw, 3.2rem);
  font-weight: 900;
  letter-spacing: -.02em;
  line-height: 1;
}
.next-deadline__text {
  min-width: 12rem;
}
.next-deadline__stage {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 700;
}
.next-deadline__desc {
  margin: .25rem 0 0;
  font-size: .9rem;
  color: var(--color-text-muted-on-dark);
}


/* ── 頁尾「主辦／協辦單位」版型（2026-08-28 改版）────────────────────
   使用者提供的期望版型（圖 12）與改版前的差異有三點：

   1. 主辦單位的 Logo 從「只有院徽」（ncsist.png，380x340 的圓形徽章）
      換成「院徽＋國家中山科學研究院中英文全名」的橫式 Logo
      （ncsist-horizontal.png，475x100）。換圖在 site_base.html，
      這裡只負責它的尺寸。
   2. 版面從「主辦一欄、協辦一欄」的左右兩欄，改成「主辦一列、協辦一列」
      的上下兩列，且每一列的標籤（<h2>）與 Logo 同列、標籤在左。
   3. 各家 Logo 高度、間距、垂直對齊統一。

   因此下面這段整個取代了改版前的規則。被拿掉的東西與原因：
   - `grid-template-columns: 20% 1fr` + `align-items: stretch`：那是左右
     兩欄版型的骨架，兩列版型不需要，改由 `.footer-unit-group` 自己做
     「標籤欄｜Logo 欄」的二欄 grid。
   - `.footer-unit-group:first-child` 那組 `display:flex` + `flex:1`：
     那是為了讓主辦欄的 Logo 在「被協辦欄撐高的欄位」裡垂直置中。兩列
     版型下主辦列的高度只由自己的內容決定，沒有多餘高度要吃，規則失效
     且會干擾新的 grid，一併移除。
   - `.footer-logo--square`（主辦圓徽專用的 7rem 方框）：圓徽已不再使用，
     改用 `.footer-logo--host`。theme-2026.css 的 `.footer-logo--square`
     基底定義保留未動，只是頁尾不再套用它。

   rollback：把這一整段換回改版前的內容，並把 site_base.html 頁尾那個
   <div class="footer-units footer-units--panel"> 區塊一併還原。 */

.footer-units.footer-units--panel {
  display: grid;
  grid-template-columns: 1fr;   /* 主辦一列、協辦一列 */
  gap: 1.5rem;
  align-items: start;
}

/* 每一列＝標籤欄｜Logo 欄。標籤欄用 max-content 讓「主辦單位」「協辦單位」
   兩個標籤自己算寬度，不寫死 px／% ——標籤字數若日後調整（例如改成
   「指導單位」）不必回頭改 CSS。 */
.footer-units--panel .footer-unit-group {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: .5rem 1.25rem;
  align-items: center;
}

/* 兩列的標籤欄寬度對齊：兩個 .footer-unit-group 是各自獨立的 grid，
   預設不會互相對齊寬度。這裡讓外層宣告共用欄軌、子層用 subgrid 接上去，
   「主辦單位」與「協辦單位」的右邊界就會切齊，兩列 Logo 的起始位置也
   一致。subgrid 不支援時（Safari < 16）退回上面那條 max-content，標籤
   寬度各自計算——只是兩列 Logo 起點差幾 px，不破版。 */
@supports (grid-template-columns: subgrid) {
  .footer-units.footer-units--panel {
    grid-template-columns: max-content 1fr;
  }
  .footer-units--panel .footer-unit-group {
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
  }
}

.footer-units--panel h2 {
  margin: 0;
  padding: 0;            /* 改版前的 padding-bottom:10px 是標籤在 Logo
                            正上方時用來拉開距離的，同列之後由 gap 負責 */
  color: var(--color-blue);
  font-size: 1.3rem;
  line-height: 1.4;
  white-space: nowrap;   /* 「主辦單位」不可被折成兩行 */
}
.footer-units--panel h2::after {
  content: "：";         /* 圖 12 的標籤帶全形冒號。寫在 ::after 而不是
                            樣板文字裡，是為了讓 <h2> 的文字內容維持乾淨的
                            「主辦單位」，螢幕報讀與搜尋不會多一個標點 */
}

/* Logo 列：一律水平排列、垂直置中。gap 的直向值只在窄螢幕換行時才用到。 */
.footer-units--panel .footer-logo-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem 1.75rem;
}

/* 去掉 theme-2026.css `.footer-logo` 基底的白底卡片框（8.4rem x 4.3rem、
   圓角、近白色背景）。頁尾面板本身已是淡藍底，Logo 直接放上去即可，
   不需要每張再包一層白卡。 */
.footer-units--panel .footer-logo {
  display: flex !important;   /* 蓋掉基底的 `display: grid !important` */
  align-items: center;
  width: auto;
  height: auto;
  padding: 0;
  border-radius: 0;
  background: transparent;
}
.footer-units--panel .footer-logo--aoc {
  background: transparent;
}

/* ── Logo 等高：依「實測墨跡高度」換算的倍率 ─────────────
   這些 Logo 不能共用同一個 max-height。兩個原因，都是量出來的：

   (1) 長寬比差距大：iii 8.07、nics 5.01、ncsist-horizontal 4.75、
       ncku 3.35、cycraft 2.28、AOC 2.11。
   (2) 更關鍵的是【圖檔內的上下留白比例】不同。以 alpha 通道的
       bounding box 量出實際有墨跡的高度，佔圖檔總高的比例：

         iii      100.0%   純字標，完全沒留白
         nics     100.0%   純字標
         AOC       89.9%
         ncsist-horizontal  86.0%
         ncku      71.5%
         cycraft   58.5%   上下各 20.7% 是透明留白

   就算把【圖檔】調成一樣高，cycraft 只有 58.5% 是看得見的，iii 是
   100%，視覺上 cycraft 會小掉一大截。因此下面每一條倍率都是用
       倍率 = (目標墨跡高度 ÷ 墨跡佔比) ÷ 基準高度
   算出來的，目標是讓六張 Logo 【實際看得見的那一塊】等高約 1.55rem（主辦
   再乘 1.18 拉出層級差）。換圖時重量一次墨跡佔比、套同一條公式即可，
   不用再靠目測微調（改版前就是目測，所以得單獨為 iii 開一條特例）。 */
.footer-units--panel {
  --footer-logo-h: 2.6rem;   /* 基準高度。窄螢幕在下方 @media 改成 2rem，
                                所有倍率會自動跟著縮，不必逐條重寫 */
}
.footer-units--panel .footer-logo img {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: var(--footer-logo-h);
  object-fit: contain;
}

/* 主辦單位：墨跡佔比 86.0%，目標墨跡高度比協辦大 18%，讓單位層級
   一眼可辨（本次需求「不會誤認單位層級」的主要手段）。 */
.footer-units--panel .footer-logo--host img {
  max-height: calc(var(--footer-logo-h) * 1.6);
}

/* 純字標，墨跡佔比 100% */
.footer-units--panel .footer-logo--iii img{
  max-height: calc(var(--footer-logo-h) * 0.8);
}
/* 校徽＋字標，墨跡佔比 71.5% */
.footer-units--panel .footer-logo--ncku img {
  max-height: calc(var(--footer-logo-h) * 1.6);
}
/* 墨跡佔比 89.9% */
.footer-units--panel .footer-logo--aoc-mark img {
  max-height: calc(var(--footer-logo-h) * 1.2);
}
/* 墨跡佔比 58.5%（上下各 20.7% 透明留白），所以倍率最大 */
.footer-units--panel .footer-logo--cycraft img {
  max-height: calc(var(--footer-logo-h) * 1.8);
}

.footer-units--panel .footer-logo--nics img {
  max-height: calc(var(--footer-logo-h) * 1);
}

/* AOC 的基線修正：它是六張裡唯一【上下留白不對稱】的圖——上方 2.9%、
   下方 7.2%（其餘五張上下均等）。flex 的 align-items:center 對齊的是
   【外框】，外框置中時這張的【墨跡】就會偏上約 2% 圖高，視覺上比
   鄰居高一截。這裡把它往下推回來對齊。用 translateY 而不是 margin，
   是因為 transform 不影響排版盒子，不會反過來撠動同列其他 Logo 的位置。 */
.footer-units--panel .footer-logo--aoc-mark img {
  transform: translateY(calc(var(--footer-logo-h) * 0.02));
}

/* 窄螢幕：標籤退回 Logo 正上方（同列會把 Logo 擠成很窄的一欄），基準高度
   同步調小。改的是 --footer-logo-h 一個值，上面所有倍率自動跟著縮，
   不必逐條重寫。 */
@media (max-width: 47.999rem) {
  .footer-units.footer-units--panel {
    grid-template-columns: 1fr;
    gap: 1.25rem;
  }
  .footer-units--panel .footer-unit-group {
    grid-template-columns: 1fr;
    gap: .5rem;
  }
  .footer-units--panel .footer-logo-row {
    gap: .75rem 1.25rem;
  }
  .footer-units--panel {
    --footer-logo-h: 2rem;
  }
  .footer-units--panel .footer-logo {
    width: auto;
  }
}

/* 窄螢幕要把上面 @supports 裡的 subgrid 兩欄拆回單欄，否則標籤與 Logo
   仍會被 subgrid 綁在同一列。巢狀順序刻意是 @supports 包 @media，與上方
   那個 @supports 對稱，避免不支援 subgrid 的瀏覽器讀到多餘規則。 */
@supports (grid-template-columns: subgrid) {
  @media (max-width: 47.999rem) {
    .footer-units.footer-units--panel {
      grid-template-columns: 1fr;
    }
    .footer-units--panel .footer-unit-group {
      grid-column: auto;
      grid-template-columns: 1fr;
    }
  }
}
/* 淡藍底色改成滿版（2026-08-26，使用者要求「整個背景色填滿」）：
   `.site-footer__inner.footer-simple` 是 `.container` class（main.css:157
   `width: min(100% - 2rem, 1400px)`），底色如果直接寫在這個元素上，
   寬度就是被這個 1400px 卡住，兩側會露出 `.site-footer` 自己的深藍色，
   填不滿整個頁尾寬度。

   這裡不是把 `.container` 拿掉——內容（Logo 面板）仍然要維持置中、
   限制在可讀寬度，只有「底色」要滿版——因此用 CSS 常見的「滿版底色、
   內容維持容器寬」手法：用 `::before` 另外做一層背景，靠
   `left: 50%; margin-left: -50vw; width: 100vw` 這組寫法讓它不受父層
   `.container` 寬度限制、橫向撐滿整個視窗，`top/bottom: 0` 則讓它跟著
   `.site-footer__inner.footer-simple` 本身的高度走（多高就跟著多高，
   不必手動量測）。

   `.site-footer__inner.footer-simple` 本身需要 `position: relative`
   讓 `::before` 的 `position: absolute` 有正確的定位基準；`::before`
   給 `z-index: -1` 讓底色沉到 Logo 面板下面，不會蓋住內容。

   踩過的坑：只給 `position: relative` 不會建立新的堆疊環境（stacking
   context）——`z-index` 只有在「auto 以外的值」時才會建立堆疊環境，
   所以第一版只寫 `position: relative`（沒有搭配 z-index）的話，
   `::before` 的 `z-index: -1` 不是相對「這個容器」比大小，而是往上
   比到 `.site-footer` 那一層甚至更外層，結果整個淡藍底色被排到
   `.site-footer` 自己的深藍色背景後面、完全看不見（症狀：Logo 疊在
   深藍底上、看起來像整個底色設定沒生效）。這裡額外補上
   `z-index: 0`，讓這個容器自己先建立一個新的堆疊環境，`::before`
   的 -1 才會被鎖在「這個容器內部」墊底，而不是逃到外層。

   rollback：刪掉 `::before` 那組規則，並把 `position: relative` 與
   `z-index: 0` 拿掉，即可回到底色跟著 `.container` 寬度走的版本。 */
.site-footer__inner.footer-simple {
  grid-template-columns: 1fr;
  position: relative;
  z-index: 0;
}
.site-footer__inner.footer-simple::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 100vw;
  margin-left: -50vw;
  background: #dbe9fa;
  z-index: -1;
}

/* 2026-08-25 使用者追加意見：CONTACT／SITEMAP 各自「橫式一行」——原本
   兩段各自是「標籤在上、內容在下」直式堆疊兩行，這裡把每個
   .footer-contact__group 本身也改成一行內的 flex（標籤與內容同一行、
   baseline 對齊），.footer-contact--bar 則改成直向排列兩個 group，
   CONTACT 一行、SITEMAP 一行，而不是兩個 group 並排。

   同日再追加「靠左對齊」：把置中改成靠左，align-items／justify-content／
   text-align 三處置中都要改，缺一處仍會有元件維持置中（例如只改
   text-align，flex 的 justify-content 仍會把整行內容置中）。 */
.footer-contact--bar {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .85rem;
  padding-block: 1.75rem;
  border-block-start: 1px solid var(--color-line-on-dark);
  text-align: left;
}
.footer-contact--bar .footer-contact__group {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: flex-start;
  gap: .5rem 1rem;
}
.footer-contact--bar .footer-contact__group h2 {
  margin: 0;
}
.footer-contact--bar ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  list-style: none;
  padding: 0;
  margin: 0;
}
.footer-contact--bar li + li::before {
  content: "｜";
  margin-inline: .9rem;
  opacity: .45;
}

/* shieldCup 第一名獎金徽章拿掉黃底框改純粗體（2026-08-25，使用者要求）：
   .prize-inline（theme-2026.css:389）畫的是黃橙漸層圓角徽章，套用在所有
   data-config="prizes.items.*" 的獎金數字上。使用者只要 shieldCup 第一名
   這一個「20 萬元」改成粗體純文字，不要動到其他名次／其他競賽項目共用
   的黃色徽章樣式，因此另開一個 modifier class 疊在該 span 上，不改
   .prize-inline 本身。

   competition.html 2026-08-17 起已退出 import_ui_static.py 自動轉檔清單
   （見該腳本 PAGES 註解），可以直接手改樣板加這個 class，不受「七頁不能
   手改」的規則限制。

   顏色改 inherit：這個徽章疊在 .card__body 的段落文字裡，讀起來就是一句
   話中間的粗體數字，inherit 讓它跟著段落既有的文字色走，不必另外指定
   色票。font-weight 沿用 .prize-inline 既有的 800，即符合「粗體」需求。 */
.prize-inline--plain {
  display: inline;
  min-height: 0;
  padding: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: #072a5b;
}

/* portal/index.html 儲存草稿的成功提示改成浮動提示框（2026-08-26，使用者要求；
   同日改為底部置中，使用者要求）：
   `#portal-alert`（index.html）是這個單頁式參賽者專區唯一的中央訊息框，
   但「儲存草稿」等操作按鈕散落在頁面中段的 STEP 區塊。main.css 原本只把它
   當一般區塊排版（inline block、隨文件流），訊息永遠印在頁面最上方；使用者
   捲到表單處按下「儲存草稿」，畫面上完全看不到那句「草稿已儲存」，3 秒後
   還會自動消失，看起來就像沒有提示。

   改在這裡而不是直接改 main.css：main.css 由 scripts/import_ui_static.py
   從 aicontest-ui 同步，手改會被 --check 擋下或下次同步時被覆蓋，見
   .claude/CLAUDE.md 規則 1-1（2026-08-18 補充）——樣式調整一律走這支檔案。

   只用 id 選擇器疊加 fixed 定位，不動 `.portal-alert` 這個 class 本身，
   因此不影響同頁其他沿用 `.portal-alert` 的區塊錯誤訊息版位（如
   `periodError`／`status_reason`），也不影響 registration_form.html
   （該頁的訊息框本來就在表單正上方，同一視窗內看得到，不需要這個調整）。
   顏色、陰影、間距全部沿用 main.css 既有的 CSS 變數，沒有新色票。

   main.css 已有底部置中浮動提示的先例 `.demo-status`（main.css:2251），
   但它是深底純狀態列，沒有成功／錯誤兩種顏色版本，套用會跟
   `.portal-alert--success`／`--error` 的配色衝突，因此另外寫規則、
   不直接沿用該 class；z-index 沿用它的 60，兩者不會同時顯示，
   保持同一組浮動層級即可，不必另外發明新的層級。

   置中用「兩側 inset 一致＋max-inline-size＋margin-inline: auto」，不用
   `.demo-status` 那種 `inset-inline-start: 50%; transform: translateX(-50%)`
   ——後者會跟下面進場動畫的 `transform: translateY(...)` 互相覆蓋
   （同一個 property 只會留下最後套用的那個值，置中效果會在動畫播完後
   消失）。兩側 inset 統一用 --space-4：手機寬度時這就是實際邊界；
   桌機寬度會被 max-inline-size 提前卡住，實際留白遠大於 --space-4，
   因此不需要另外用 media query 切換成 --space-6，也不必為窄螢幕
   多寫一份覆寫規則。

   rollback：整段刪除即可回到原本的頁首靜態提示。 */
#portal-alert {
  position: fixed;
  inset-block-end: var(--space-6);
  inset-inline: var(--space-4);
  margin-inline: auto;
  z-index: 60;
  max-inline-size: 24rem;
  box-shadow: var(--shadow-md);
  animation: portal-alert-in var(--transition-enter);
}

@keyframes portal-alert-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* STEP 04「確認送出報名」按鈕：改用 class 模擬反灰，不用原生 disabled。

   原生 `disabled` 屬性會讓瀏覽器完全不派送 click 事件（不只擋動作，
   連事件本身都不會發生，外層元素也收不到冒泡），所以按鈕反灰時使用者
   點下去沒有任何回饋。改成掛這個 class，讓 Vue 的 click handler 仍然
   會執行，由 JS 判斷擋下並跳出提示訊息，不透過瀏覽器原生行為。

   main.css 沒有定義任何 `.btn:disabled` 樣式（未曾需要過)，這裡用
   opacity 模擬一般瀏覽器對停用控制項的視覺慣例，沒有引入新色票。
   `:hover`/`:focus-visible` 需要用「兩個 class 疊加」把選擇器優先度
   墊高過 `.btn--primary:hover`（main.css:559），否則滑鼠移上去背景
   還是會照原本的規則變色，看起來像「其實可以按」。 */
.btn--primary.btn--disabled,
.btn--primary.btn--disabled:hover,
.btn--primary.btn--disabled:focus-visible {
  opacity: 0.5;
  cursor: not-allowed;
  background: var(--color-warm);
}

/* --------------------------------------------------------------------------
   前台資料表格：手機版改為堆疊卡片（2026-08-28）
   --------------------------------------------------------------------------
   問題：theme-2026.css:761 在手機斷點裡把 `.data-table` 撐到 min-width: 46rem
   （736px），main.css:1194 另有 min-inline-size: 36rem。5 欄表格在 390px 的
   手機上只看得到前 2 欄，其餘要橫向捲動才看得到，第一欄標題還會被擠成兩行。

   作法：≤47.999rem 時把 table 的各層 display 改成 block，一列 = 一張卡片，
   每格變成「欄位名在上、內容在下」兩行——欄位名由 `td[data-label]` 的
   ::before 產生，thead 則用 clip 手法隱藏（保留給螢幕閱讀器，不用
   display:none，否則欄位語意會從無障礙樹消失）。

   為什麼放在 integration.css：本檔在 site_base.html 最後載入，同層級選擇器
   後載入者勝，才能覆寫 theme-2026.css 的 min-width，且不必去改動那兩份既有
   宣告——要回滾時整段刪除即可，原本行為完全不變。

   影響範圍僅前台 `.data-table`（達人論壇、競賽項目兩頁）。CMS 後台與評審端
   載入的是 css/cms/base.css，與本檔無關，不受影響。 */
@media (max-width: 47.999rem) {
  /* 解除橫捲：容器不再需要捲動，卡片直接依螢幕寬度排版 */
  .table-wrapper {
    overflow-x: visible;
    border: 0;
    border-radius: 0;
    background: transparent;
  }

  /* caption 也要一起改成 block：table 變成 block 之後，若 caption 仍是
     display:table-caption，它會依附在一個寬度為 0 的匿名 table box 上，
     整段標題被擠成一欄一字的直條。 */
  .data-table,
  .data-table caption,
  .data-table thead,
  .data-table tbody,
  .data-table tr,
  .data-table th,
  .data-table td {
    display: block;
  }

  .data-table {
    min-width: 0;
    min-inline-size: 0;
    width: 100%;
  }

  /* 表頭視覺上隱藏但保留在無障礙樹裡；欄位名改由 td::before 呈現 */
  .data-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  .data-table caption {
    width: 100%;
    padding: 0 0 0.75rem;
    border-block-end: 0;
    font-size: 0.95rem;
    line-height: 1.5;
    text-align: start;
  }

  /* 一列 = 一張卡片 */
  .data-table tbody tr {
    margin-bottom: 0.85rem;
    padding: 0.35rem 0.15rem;
    border: 1px solid rgba(108, 180, 226, 0.34);
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.72);
    box-shadow: 0 6px 18px rgba(7, 92, 207, 0.07);
  }

  /* 覆寫 theme-2026.css:501 的斑馬紋：卡片式版面每張卡片都該長得一樣，
     交錯底色在堆疊後會被誤讀成「這兩列是不同類型的資料」。 */
  .data-table tbody tr:nth-child(even) {
    background: rgba(255, 255, 255, 0.72);
  }

  .data-table tbody tr:last-child {
    margin-bottom: 0;
  }

  /* 每格＝「標籤在上、內容在下」的兩行式。
     為什麼不做成左右兩欄：格子內容常常是純文字，或「純文字＋<br>＋
     純文字」（例如「<strong>至 2026.09.05</strong><br>外部平台」）。
     CSS 選不到裸文字節點，因此 grid/flex 都無法穩定地把「整格內容」
     當成單一個右欄項目——grid 會把 <br> 後的文字丟到下一列、flex 會
     讓它變成另一個 item 而錯位。改成上下兩行後，不論格內是文字、
     inline 元素或含 <br> 的混排，都能正確靠左對齊且完整換行。 */
  .data-table tbody th,
  .data-table tbody td {
    display: block;
    padding: 0.55rem 0.9rem;
    border-block-end: 1px solid rgba(108, 180, 226, 0.2);
    text-align: start;
    overflow-wrap: anywhere;
  }

  /* 欄位名稱：內容取自 HTML 的 data-label，缺少時整格就是單純一段文字
     （優雅降級，不會留下空的標籤行）。 */
  .data-table tbody [data-label]::before {
    content: attr(data-label);
    display: block;
    margin-block-end: 0.15rem;
    color: var(--color-blue-deep, #0750ae);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.02em;
  }

  /* 每張卡片的標題列（competition.html 用 th[scope=row] 放競賽項目名稱） */
  .data-table tbody th[scope="row"] {
    display: block;
    padding-block: 0.7rem;
    font-size: 1.02rem;
    font-weight: 700;
  }

  /* 按鈕滿版比較好點，同時避免 theme-2026.css:869 的 min-width: 7rem
     在窄螢幕上把整格撐開 */
  .data-table tbody td .btn {
    display: block;
    min-width: 0;
    text-align: center;
  }
}


/* 首頁 KV 下方的英文全名橫幅（2026-09-02，使用者要求）：比照設計附圖，
   在主視覺圖片與決賽日期資訊列之間加一條深藍底、白字置中的橫幅。
   新增獨立 class，不動 .hero__kv-stage／.hero__kv-bar 既有規則；
   要移除時整段連同 index.html 的 .hero__kv-title-en-bar 一起刪即可。
   寬度沿用 theme-2026.css 的 .hero__kv-stage 設定（同一組 min() 值），
   讓橫幅左右緣對齊上方 KV 圖片。 */
.hero__kv-title-en-bar {
  width: min(calc(100% - 2.25rem), 1240px);
  margin-inline: auto;
  padding-inline: 0;
  margin-block-start: 1rem;
}

.hero__kv-title-en {
  margin: 0;
  padding: 0.85rem 1.5rem;
  border-radius: var(--radius-container);
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.9vw, 1.7rem);
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0.01em;
  text-align: center;
  text-wrap: balance;
  color: var(--color-text-on-dark);
  background: var(--color-ink-900);
  box-shadow: 0 12px 32px rgba(7, 92, 207, 0.18);
}

/* 平板：跟著 theme-2026.css:1225 的 .hero__kv-stage 一起收窄 */
@media (max-width: 63.9375rem) {
  .hero__kv-title-en-bar { width: min(calc(100% - 1.5rem), 52rem); }
}

/* 手機：對齊 theme-2026.css:1235 的 .hero__kv-stage 寬度，字級再縮一階 */
@media (max-width: 47.999rem) {
  .hero__kv-title-en-bar {
    width: calc(100% - 1rem);
    margin-block-start: 0.75rem;
  }
  .hero__kv-title-en {
    padding: 0.7rem 1rem;
    border-radius: 12px;
    font-size: clamp(0.85rem, 3.4vw, 1.05rem);
  }
}


/* 首頁「報名截止」倒數卡的兩行日期分色（2026-09-03，使用者要求）：
   .next-deadline__date 原本是一段用 <br> 斷行的文字，兩行同色（繼承
   .next-deadline 的 --color-text-on-dark），看不出「10/9」與「10/21」
   是兩個不同競賽的截止日。樣板改成兩個 <span class="next-deadline__date-line">
   （斷行改由 display:block 負責，不再依賴 <br>），第一行加
   --primary 修飾字轉黃、第二行維持白色。
   黃色沿用 theme-2026.css 既有 .card--accent-warm 色條的起始色 #ffad30，
   不新增色票。只鎖定 .next-deadline__date 底下，其他區塊不受影響。 */
.next-deadline__date-line {
  display: block;
}

/* 2026-09-03 追加：兩行日期原本沿用 .next-deadline__date 的
   clamp(2.2rem, 6vw, 3.2rem)，字級太大、兩行擠滿整張卡。縮成
   clamp(1.5rem, 3.6vw, 2rem)，仍明顯大於下方 .next-deadline__stage
   的 1.15rem，維持「日期為主、標籤為輔」的層級。行高從 1 放寬到 1.25，
   避免兩行貼在一起。 */
.next-deadline__date {
  font-size: clamp(1.5rem, 3.6vw, 2rem);
  line-height: 1.25;
}

/* 2026-09-03 追加：第一行原本用 #ffad30（accent-warm 漸層起始色），
   使用者回饋偏橘不夠黃，改用同一條漸層的結束色 #ffe36a——一樣是既有
   色票、不新增顏色，且在深色卡片背景上的對比度更高。 */
.next-deadline__date-line--primary {
  color: #ffe36a;
}

/* 首頁四張獎金卡的競賽名稱跟著自己頂部色條同色（2026-09-03，使用者要求）：
   .card__title 在 theme-2026.css 固定是 #0750ae，四張卡的標題一樣藍，
   但頂部色條已經靠 .card:nth-child(4n + n) 分成藍／青／紫／橘四色，
   標題與色條對不起來。這裡照 #plans .prize-card__value 的既有做法，
   用同一組 nth-child 順序與同一組 accent 起始色把標題（含裡面的 <a>）
   染成對應色，不新增色票、不動色條本身。
   選擇器鎖在 .prize-grid 底下，index.html 其他卡片組（八大主題、#about）
   與 competition.html／sponsors.html 都命中不到。 */
.prize-grid .card:nth-child(4n + 1) .card__title,
.prize-grid .card:nth-child(4n + 1) .card__title a {
  color: #0759d0;
}

.prize-grid .card:nth-child(4n + 2) .card__title,
.prize-grid .card:nth-child(4n + 2) .card__title a {
  color: #08bfe9;
}

.prize-grid .card:nth-child(4n + 3) .card__title,
.prize-grid .card:nth-child(4n + 3) .card__title a {
  color: #6758dc;
}

.prize-grid .card:nth-child(4n) .card__title,
.prize-grid .card:nth-child(4n) .card__title a {
  color: #ffad30;
}


/* 首頁時程表的階段標題改漸層填色（2026-09-03，使用者要求）：
   .timeline--mega .timeline__stage 原本是 theme-2026.css 的單色 #0750ae，
   跟上方 .next-deadline 卡片（背景用 --glass-blue）的漸層調性對不起來。
   這裡把同一個 --glass-blue 當成文字的背景、再用 background-clip: text
   把文字挖成遮罩，做出深藍→青的漸層字。用的是 theme-2026.css :root
   既有的色票，不新增顏色。

   為什麼要留 fallback color：background-clip: text 需要 -webkit- 前綴才
   吃得到較舊的 Safari／Chrome；若瀏覽器不支援，-webkit-text-fill-color
   也一併不支援，文字會退回這行 color 的 #0750ae，也就是改版前的樣子，
   不會變成看不見的透明字。

   不含頒獎典禮那張卡（.timeline__item--award）：它是金色底的強調卡，
   標題另外用 #8c5700 配色，套上藍青漸層會跟金色背景打架，因此排除。 */
.timeline--mega .timeline__item:not(.timeline__item--award) .timeline__stage {
  color: #0750ae;
  background: var(--glass-blue);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  /* 漸層以整行文字為範圍，兩行的標題才會延續同一段漸層而不是各自重來 */
  display: inline-block;
}


/* AI 飛行員擂台賽的單張影片卡（competition.html #ai-pilot，2026-09-03，
   使用者要求美化）：原本這張 .gallery-card 直接放在 .container 底下，
   沒有包 .gallery-grid，因此吃不到 gallery 區塊該有的排版脈絡——
   在寬螢幕會被拉成整個容器寬（1200px+），16:9 的 iframe 高度跟著暴增，
   跟下方 .track-summary-grid 的卡片節奏對不上；上下也沒有間距，
   緊貼 .section-header 看起來像誤植。

   改法是把它包進設計師既有的 .gallery-grid（news.html 的花絮牆用的就是
   這個），再加一個 --single 修飾字處理「只有一張卡」的情況：收窄至
   720px 並置中。不改 main.css 的 .gallery-grid／.gallery-card 通用樣式，
   news.html 那三張卡不受影響。間距沿用既有的 --space-* 尺寸變數，
   不引入新數值。

   2026-09-03 追加：720px 使用者回饋太小，依附圖放大到 900px（.container
   為 1240px，約佔七成寬，與下方 .track-summary-grid 的整組寬度相近，
   但仍留有左右留白不至於貼齊卡片邊緣）。

   2026-09-03 再修：影片沒有水平置中。原因不是 margin-inline: auto 沒生效
   （那條把 900px 的 grid 容器本身置中了，是對的），而是 main.css 的
   .gallery-grid 在 480px 以上變兩欄、1024px 以上變三欄（見 main.css 的
   兩個 @media）。裡面只有一張卡時，那張卡只佔第一欄，於是靠在容器左邊
   三分之一處，看起來就是「沒有置中」。這裡把 --single 明確宣告為單欄，
   卡片才會填滿 900px；grid-template-columns 寫在這裡而不是改 main.css，
   news.html 的多卡花絮牆維持原本的響應式欄數。 */
.gallery-grid--single {
  grid-template-columns: 1fr;
  inline-size: min(100%, 900px);
  margin-inline: auto;
  margin-block: var(--space-8);
}

/* 這張卡沒有 .gallery-card__body（依附圖只留影片本身），因此也不該有
   .gallery-card:hover 的位移與藍色框線——那組 hover 是設計給「整張卡可點、
   點了會開啟內容」的花絮卡用的，這裡卡片內就是可操作的播放器，滑鼠移過去
   整張卡浮起來反而讓人以為卡片本身可以點。只在這個 --single 的情境關閉，
   news.html 的花絮卡不受影響。 */
.gallery-grid--single .gallery-card:hover {
  border-color: var(--color-line);
  transform: none;
}

/* --------------------------------------------------------------------------
   交通與聯絡資訊：「場地與地圖」卡片的位置圖（transport_contact.html）

   為什麼不沿用既有的 .card__media：
   .card__media 是「八大主題」那種出血頭圖——main.css 給它固定高度
   8.5rem（theme-2026.css 再蓋成 10.5rem）、圖片 object-fit: cover，
   還用 ::after 疊一層深藍漸層。那組值對裝飾用的情境照是對的，但地圖
   是要讓人「看清楚」的資訊圖：固定高度會把 1672×941 的圖上下裁掉，
   漸層又會把地標文字染暗。所以另開 .card__map，只做這一件事——
   完整顯示、不裁切、不加遮罩。不動 .card__media，八大主題卡不受影響。 */
/* 地圖要「垂直靠上」＝緊貼上面的地址文字，不要被推到卡片底部。

   卡片是 flex column，而 .card__body 有 flex-grow: 1（main.css 用它把
   同列卡片撐到等高）。這張卡的內文只有兩行，於是 .card__body 自己長到
   184px，把地圖擠到最下面——光在 .card__map 寫 margin-block-end: auto
   沒有用，因為空間已經被會長大的兄弟吃掉了。

   所以改成「讓 .card__body 不要長大，改由地圖底下的 auto margin 吸收
   剩餘空間」。用 :has() 限定在「內含地圖的卡片」，八大主題卡那些沒有
   .card__map 的卡片完全不受影響，也不必動 main.css 的 .card__body。 */
.card:has(> .card__map) > .card__body {
  flex-grow: 0;
}

.card__map {
  display: block;
  /* figure 的瀏覽器預設 margin（上下 1em、左右 40px）要清掉，
     否則地圖會比卡片內文窄一大截。
     margin-block-end: auto 吸收剩餘空間，把地圖頂到文字下方。 */
  margin: var(--space-4) 0 auto;
  border-radius: var(--radius-control);
  overflow: hidden;
  border: 1px solid var(--color-line);
  transition: border-color var(--transition-enter);
}

.card__map img {
  display: block;
  inline-size: 100%;
  block-size: auto;   /* 依原圖比例完整顯示，不裁切 */
}

/* 只有 JS 成功掛上放大行為（is-zoomable）時才顯示可點擊的樣子——
   JS 沒載到時不該假裝可以點。 */
.card__map img.is-zoomable {
  cursor: zoom-in;
}

.card__map:has(img.is-zoomable:hover),
.card__map:has(img.is-zoomable:focus-visible) {
  border-color: var(--color-blue);
}

/* :has() 不支援時的退路：至少讓鍵盤焦點看得見。 */
.card__map img.is-zoomable:focus-visible {
  outline: 2px solid var(--color-blue);
  outline-offset: -2px;
}

/* 地址文字連結：沿用卡片內文顏色，只用底線表示可點，
   避免在綠色重點卡（.card--accent-green）裡出現搶眼的藍色連結。 */
.card__map-link {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.card__map-link:hover,
.card__map-link:focus-visible {
  color: var(--color-blue);
}

/* --------------------------------------------------------------------------
   交通與聯絡資訊：「大眾運輸」「自行開車」卡片的路線說明（transport_contact.html）

   原本這兩張卡是一行「待公告」的 .card__body，2026-09-04 補上實際路線後
   變成「交通方式 → 步驟」的兩層內容，單一段落塞不下也讀不動。這裡用
   dl/dt/dd 承載那個層次，dd 裡再放 ol 讓「先做什麼後做什麼」的順序
   對讀螢幕軟體也成立。

   為什麼另開 .card__routes 而不改 .card__body：
   .card__body 有 flex-grow: 1，是設計來把卡片撐到等高的那一塊，全站
   八大主題卡都在用；直接改它會動到所有卡片。這裡只在這兩張卡新增規則。 */
.card__routes {
  margin: 0;
  color: var(--color-text-muted);
  font-size: 0.9375rem;
  flex-grow: 1;   /* 取代 .card__body 的角色，讓同列卡片維持等高 */
}

.card__route-mode {
  font-weight: 700;
  color: var(--color-text);
}

/* 第二個以後的交通方式（搭乘高鐵／由南向北）與前一段拉開距離，
   第一個不加，避免和 .card__title 之間出現雙倍空白。 */
.card__route-mode + .card__route-steps + .card__route-mode {
  margin-block-start: var(--space-4);
}

.card__route-steps {
  margin: var(--space-2) 0 0;
}

.card__route-steps p {
  margin: 0;
}

/* 步驟編號用 ol 原生的序號，靠 padding 讓數字不會被卡片邊緣切掉。 */
.card__route-steps ol {
  margin: 0;
  padding-inline-start: 1.35em;
}

.card__route-steps li + li {
  margin-block-start: var(--space-1);
}

/* --------------------------------------------------------------------------
   場地地圖燈箱（js/site/venue-map-lightbox.js 建立的 DOM）

   版面與層級刻意比照 main.css 既有的 .external-modal：同樣的
   position: fixed + inset: 0 + z-index: 100 + 深藍半透明遮罩，
   讓站上兩種彈出層看起來是同一套東西。差別只在內容是一張要看清楚的圖，
   所以卡片換成「盡量放大但不超出視窗」的圖框。

   `[hidden]` 那條不能省：這裡設了 display: grid，會蓋掉瀏覽器對
   hidden 屬性的預設 display: none，不補就永遠關不掉。 */
.map-lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: var(--space-6);
  background: rgba(10, 43, 77, 0.72);
  backdrop-filter: blur(4px);
  cursor: zoom-out;   /* 點背景任一處即關閉 */
}

.map-lightbox[hidden] {
  display: none;
}

.map-lightbox__frame {
  position: relative;
  cursor: default;    /* 圖框內不繼承背景的 zoom-out */
  max-inline-size: 100%;
  max-block-size: 100%;
}

/* 讓圖片在「不超出視窗」的前提下盡量大。用 vh/vw 扣掉 padding 與
   關閉鈕的空間，直向手機與橫向桌機都不會被切到。 */
.map-lightbox__image {
  display: block;
  max-inline-size: min(96vw, 1672px);   /* 不超過原圖寬度，放大到糊掉沒有意義 */
  max-block-size: 88vh;
  inline-size: auto;
  block-size: auto;
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-md);
  background: var(--color-white);
}

.map-lightbox__close {
  position: absolute;
  inset-block-start: calc(-1 * var(--space-5));
  inset-inline-end: 0;
  inline-size: 2.25rem;
  block-size: 2.25rem;
  display: grid;
  place-items: center;
  padding: 0;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  color: var(--color-text-on-dark);
  background: transparent;
  border: 0;
  border-radius: var(--radius-pill);
}

.map-lightbox__close:hover,
.map-lightbox__close:focus-visible {
  background: rgba(255, 255, 255, 0.16);
}

/* 小螢幕上圖框已經貼近視窗頂端，關閉鈕移到圖內右上角才不會被切掉。 */
@media (max-width: 640px) {
  .map-lightbox__close {
    inset-block-start: var(--space-2);
    inset-inline-end: var(--space-2);
    background: rgba(10, 43, 77, 0.55);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .map-lightbox:not([hidden]) .map-lightbox__frame {
    animation: map-lightbox-pop 200ms ease-out;
  }
}

@keyframes map-lightbox-pop {
  from {
    opacity: 0;
    transform: scale(0.97);
  }
}


/* --------------------------------------------------------------------------
   達人論壇 — 講者卡片（.speaker-card）
   --------------------------------------------------------------------------
   結構由 static/js/site/forum-speaker-inject.js 動態產生，設計稿沒有這組
   樣式。這裡只加 .speaker-card 前綴的規則，不覆寫任何全域 .card /
   .card__title / .card__body，其他頁面的卡片不受影響。

   2026-09-04 使用者要求：照片從 96px 放大兩倍到 192px，並與姓名並列；
   職稱與簡介的間距縮小，把垂直空間讓給照片。
   2026-09-05 再調整：職稱從照片右側移到 header 下方，與簡介同層。版面
   由上而下是「照片＋姓名」／「現職｜單位」／「簡介」。
   -------------------------------------------------------------------------- */
.speaker-card {
  /* .card 本身是 gap: var(--space-6)。講者卡三段（頭部／職稱／簡介）沿用
     原本的間距會在職稱前後留下大片空白，照片就沒空間長大。收成
     --space-3；職稱與簡介之間再另外收更緊，見下方。 */
  gap: var(--space-3);
}

.speaker-card__header {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.speaker-card__photo {
  /* 96px 的兩倍。用 flex-shrink: 0 免得長姓名把照片壓扁。 */
  inline-size: 192px;
  block-size: 192px;
  flex-shrink: 0;
  object-fit: cover;
  border-radius: 50%;
}

.speaker-card__name {
  margin: 0;
  /* 姓名是 flex 橫排的子項，長名字要能自己換行而不是把照片擠掉。 */
  min-inline-size: 0;
}

.speaker-card__role {
  margin: 0;
  /* .card__body 有 flex-grow: 1（main.css，用來讓同列卡片等高）。職稱吃到
     那條會被拉長，把簡介推到卡片底部。等高一律交給 .speaker-card__bio。 */
  flex-grow: 0;
  /* 職稱與簡介是連續的兩段說明文字，貼緊一點讀起來才是同一個人的資訊。
     .speaker-card 的 gap 是 --space-3，這裡補負值收到約 --space-1。 */
  margin-block-end: calc(var(--space-1) - var(--space-3));
}

.speaker-card__bio {
  margin: 0;
}

/* 窄螢幕：192px 的照片加上文字排不進一行，改回直排並置中。 */
@media (max-width: 640px) {
  .speaker-card__header {
    flex-direction: column;
    align-items: center;
    text-align: center;
  }
}
