/*
  ╔══════════════════════════════════════════════════════════════╗
  ║  首頁樣式                                                     ║
  ║  assets/css/index.css                                        ║
  ╚══════════════════════════════════════════════════════════════╝

  來源：index.html 原內嵌 <style> 區塊（653 行），逐行原樣移出，
        分節順序與註解未更動。

  ⚠ 本檔不得與 assets/css/event.css 或 assets/style.css 合併（CLAUDE.md 決定 7）。
    首頁與事件頁是兩套設計系統，下列 6 個同名 CSS 變數數值不同：

      變數          index.css   style.css
      --ash         #b0a89e     #2B2B2B     ← 差距最大（淺灰 vs 近黑）
      --border      #ddd6cc     #E0D9CF
      --ember       #e05a20     #F4A324
      --mid         #7a7068     #888888
      --paper       #f5f0ea     #F5F0E8
      --smoke       #3a3530     #4A4A4A

    index.html 只載入本檔，不載入 style.css／event.css。

  ⚠ 修飾詞命名查 assets/css/event.css 開頭的「修飾詞命名詞彙表」（決定 16）。
    本檔不另立詞彙表 —— 兩套設計系統是「詞彙共用、數值不共用」：
    詞彙（--spaced-above／--tight-below 等）一律沿用該表，
    數值（色碼、間距值）各自獨立，不得因為詞彙相同就互相對齊（決定 7）。
    資料值對照類修飾詞（.typhoon-legend-item--<id>、.map-popup-tag--<類型> 等）
    不受該表管轄，以資料既有的 slug 命名。

  引用方式（index.html <head>）：
    <link rel="stylesheet" href="assets/css/index.css">
*/

/* ══════════════════════════════
   本機化字型（子集）

   改造前由 fonts.googleapis.com 載入，資安需求第九節要求
   style-src 'self' 與 font-src 'self'，故本機化。

   宣告結構照抄 Google Fonts CSS2 API 的輸出（每個家族每字重一條，
   同家族各字重指向同一個可變字型檔），只把 URL 換成本機路徑，
   以確保渲染結果與改造前一致。
   font-display: swap 對應原本 link 上的 &display=swap。

   Google 原輸出另有 unicode-range（每條 5,374 字元），此處省略：
   自架單檔時該宣告只影響「字元不在子集內時是否下載字型」，
   對本頁的渲染結果沒有差別，列入只會讓本檔多出約 43KB 難讀的內容。

   ⚠ 字型是依當初的 788 個字元子集化的。修改首頁文字或
     events.csv／events.json 後必須重跑 tools/font-coverage-check.ps1，
     重建步驟見 assets/vendor/fonts/README.md。
══════════════════════════════ */
@font-face {
  font-family: 'Bebas Neue';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../vendor/fonts/bebas-neue-subset.woff2') format('woff2');
}
@font-face {
  font-family: 'Noto Sans TC';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../vendor/fonts/noto-sans-tc-subset.woff2') format('woff2');
}
@font-face {
  font-family: 'Noto Sans TC';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../vendor/fonts/noto-sans-tc-subset.woff2') format('woff2');
}
@font-face {
  font-family: 'Noto Sans TC';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../vendor/fonts/noto-sans-tc-subset.woff2') format('woff2');
}
@font-face {
  font-family: 'Noto Sans TC';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../vendor/fonts/noto-sans-tc-subset.woff2') format('woff2');
}
@font-face {
  font-family: 'Noto Serif TC';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../vendor/fonts/noto-serif-tc-subset.woff2') format('woff2');
}
@font-face {
  font-family: 'Noto Serif TC';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../vendor/fonts/noto-serif-tc-subset.woff2') format('woff2');
}
@font-face {
  font-family: 'Noto Serif TC';
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url('../vendor/fonts/noto-serif-tc-subset.woff2') format('woff2');
}

/* ══════════════════════════════
   TOKENS
══════════════════════════════ */
:root {
  --navy:    #1c2b44;
  --rose:    #9b4050;
  --accent:  #c8341a;
  --ember:   #e05a20;
  --paper:   #f5f0ea;
  --white:   #ffffff;
  --charcoal:#1a1a1a;
  --smoke:   #3a3530;
  --mid:     #7a7068;
  --border:  #ddd6cc;
  --ash:     #b0a89e;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  font-family: 'Noto Sans TC', sans-serif;
  background: var(--paper);
  color: var(--charcoal);
  line-height: 1.6;
}

/* ── Container ── */
.container { max-width: 1200px; margin: 0 auto; padding: 0 48px; }
@media (max-width: 768px) { .container { padding: 0 20px; } }
@media (max-width: 480px) { .container { padding: 0 16px; } }

/* ══════════════════════════════
   NAV
══════════════════════════════ */
.site-nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 1000;
  background: var(--paper);
  border-bottom: 3px solid #9b3a2a;
  height: 56px;
  display: flex; align-items: center;
  padding: 0;
}
.nav-inner {
  max-width: 1200px; margin: 0 auto; padding: 0 48px;
  width: 100%;
  display: flex; align-items: center;
}
.nav-logo {
  display: flex; align-items: center; gap: 12px;
  text-decoration: none; color: inherit;
}
.nav-logo img { height: 28px; }
.nav-logo-text {
  font-size: 16px; font-weight: 700; color: var(--smoke);
  letter-spacing: 0.08em;
}
@media (max-width: 480px) {
  .nav-inner { padding: 0 16px; }
  .nav-logo-text { display: none; }
}

/* ══════════════════════════════
   HERO
══════════════════════════════ */
.home-hero {
  margin-top: 56px;
  width: 100%;
  height: auto;
  overflow: hidden;
  line-height: 0;
}
.hero-img {
  width: 100%;
  height: auto;
  display: block;
}

/* ══════════════════════════════
   KPI STRIP
══════════════════════════════ */
.kpi-strip {
  background: #2d3561;
  border-bottom: 3px solid #9b3a2a;
}
.kpi-inner {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 48px;
}
.kpi-item {
  padding: 18px 32px;
  border-right: 1px solid rgba(255,255,255,0.08);
}
.kpi-item:last-child { border-right: none; }
.kpi-num {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 44px; line-height: 1;
  color: #fff;
  letter-spacing: 0.02em;
}
.kpi-num span { font-size: 20px; color: rgba(255,255,255,0.55); margin-left: 2px; }
.kpi-label {
  font-size: 11px; font-weight: 500;
  letter-spacing: 0.12em;
  color: rgba(255,255,255,0.5);
  margin-top: 5px;
}
.kpi-type {
  display: inline-block;
  font-size: 10px; font-weight: 700; letter-spacing: 0.1em;
  padding: 2px 8px;
  margin-bottom: 8px;
  background: var(--accent);
  color: #fff;
}
@media (max-width: 768px) {
  .kpi-inner { grid-template-columns: repeat(2, 1fr); padding: 0 20px; }
  .kpi-item { padding: 14px 20px; }
  .kpi-num { font-size: 36px; }
}
@media (max-width: 480px) {
  .kpi-inner { grid-template-columns: repeat(2, 1fr); padding: 0 16px; }
  .kpi-item { padding: 12px 16px; }
  .kpi-num { font-size: 30px; }
  .kpi-num span { font-size: 16px; }
  .kpi-type { font-size: 9px; padding: 2px 6px; margin-bottom: 5px; }
  .kpi-label { font-size: 10px; margin-top: 3px; }
}

/* ══════════════════════════════
   TAB BAR
══════════════════════════════ */
.tab-bar {
  display: flex;
  justify-content: center;
  background: #3d3d6b;
  border-bottom: none;
}
.tab-bar-inner {
  display: flex;
  width: 100%;
  max-width: 1200px;
  padding: 0 48px;
}
.tab-btn {
  font-family: 'Noto Serif TC', serif;
  font-size: 18px; font-weight: 900;
  letter-spacing: 0.15em;
  color: rgba(255,255,255,0.45);
  background: transparent;
  border: none;
  border-bottom: 3px solid transparent;
  padding: 20px 40px 17px;
  cursor: pointer;
  flex: 1;
  text-align: center;
  transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.tab-btn:hover { color: rgba(255,255,255,0.75); }
.tab-btn.active-world {
  color: #fff;
  border-bottom-color: #c8a96e;
  background: rgba(255,255,255,0.07);
}
.tab-btn.active-taiwan {
  color: #fff;
  border-bottom-color: #e07050;
  background: rgba(224,112,80,0.12);
}
@media (max-width: 768px) {
  .tab-bar-inner { padding: 0 20px; }
}
@media (max-width: 480px) {
  .tab-btn { font-size: 14px; padding: 16px 20px 13px; letter-spacing: 0.08em; }
  .tab-bar-inner { padding: 0 16px; }
}

/* ══════════════════════════════
   TAB PANELS
══════════════════════════════ */
.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* ══════════════════════════════
   SECTION HEADER
══════════════════════════════ */
.sec {
  padding: 64px 0 0;
}
.sec-head {
  display: flex; align-items: flex-start; gap: 20px;
  margin-bottom: 8px;
}
.sec-num {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 80px; line-height: 0.85;
  color: rgba(200,52,26,0.12);
  letter-spacing: -0.02em;
  user-select: none;
  flex-shrink: 0;
}
.sec-meta {}
.sec-label {
  font-size: 10px; font-weight: 700;
  letter-spacing: 0.35em;
  color: var(--accent);
  text-transform: uppercase;
  margin-bottom: 4px;
}
.sec-title {
  font-family: 'Noto Serif TC', serif;
  font-size: 24px; font-weight: 900;
  color: var(--charcoal);
  letter-spacing: 0.04em;
}
.rule {
  height: 1px;
  background: linear-gradient(to right, var(--accent) 60px, var(--border) 60px);
  margin: 12px 0 40px;
}

/* ══════════════════════════════
   MAP
══════════════════════════════ */
#world-map {
  width: 100%; height: 480px;
  background: #e8f0f7;
  margin-bottom: 64px;
  border: 1px solid var(--border);
}
@media (max-width: 768px) { #world-map { height: 300px; } }
@media (max-width: 480px) { #world-map { height: 240px; } }

/* Leaflet popup */
.leaflet-popup-content-wrapper {
  border-radius: 0 !important;
  border-top: 3px solid var(--accent) !important;
  box-shadow: 0 8px 32px rgba(0,0,0,0.18) !important;
  font-family: 'Noto Sans TC', sans-serif !important;
}
.map-popup { padding: 16px 18px 14px; min-width: 200px; }
.map-popup-tag {
  font-size: 10px; font-weight: 700; letter-spacing: 0.12em;
  padding: 2px 8px; background: var(--accent); color: #fff;
  display: inline-block; margin-bottom: 8px;
}
.map-popup-title {
  font-family: 'Noto Serif TC', serif;
  font-size: 14px; font-weight: 900; color: #1a1a1a;
  line-height: 1.4; margin-bottom: 6px;
}
.map-popup-desc { font-size: 12px; color: #4a4a4a; line-height: 1.7; margin-bottom: 10px; }
.map-popup-link {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
  color: var(--accent); text-decoration: none;
  border-top: 1px solid #e0d9cf; padding-top: 10px; display: block;
}

/* popup 內的地點列。原為 style="color:#888;font-size:11px;"。
   直接命中該 <span>，勝過從 .map-popup-desc（父層 0,1,0）與
   .leaflet-popup-content（祖先 0,1,0）繼承來的 color／font-size ——
   繼承值只在沒有任何規則直接命中時才生效，故無競爭。 */
.map-popup-loc { color: #888; font-size: 11px; }

/* ── 地圖 popup 標籤：資料值 → CSS class 對照 ────────────────
   八種災害類型的代表色。原本以 style="background:${c}" 由 JS 寫在
   <span class="map-popup-tag"> 上，色碼取自 assets/js/index-map.js
   的 TYPE_COLOR。

   ⚠ class 為手寫的靜態對照（index-map.js 的 TYPE_TAG_CLASS），
     不得由 JS 以 'map-popup-tag--' + ev.type 串接產生
     （CLAUDE.md 的 Leaflet 圖例規則）。查不到時回退 --unknown。

   ⚠ 這八個色碼與 index-map.js 的 TYPE_COLOR 是同一組資料的兩種呈現。
     TYPE_COLOR 現在只剩後備大頭針 SVG 的 fill 在用（SVG 呈現屬性，
     不受 style-src 管轄），但兩邊必須同步，以免同一類型在圖釘與
     標籤上出現兩種顏色。

   ⚠ 「洪水」在此為 #4B7BB9，各洲甜甜圈圖的「洪水」為 #1D9E75，
     兩處刻意不同，不得統一 —— 見 KNOWN-ISSUES.md 第 12 項。

   權重推算：基準 .map-popup-tag（本檔上方）已設 background: var(--accent)，
   權重同為 (0,1,0)，平手時由順序決勝，故本區塊必須排在基準規則之後。
   其餘可能參與競爭者：leaflet.css 只有 .leaflet-popup-content-wrapper
   與 .leaflet-popup-content 兩條命中祖先元素，不直接命中本元素；
   index.html 不載入 style.css（決定 7）。無 !important 競爭。 */
.map-popup-tag--wildfire     { background: #C8341A; }  /* 野火 */
.map-popup-tag--flood        { background: #4B7BB9; }  /* 洪水 */
.map-popup-tag--earthquake   { background: #BA7517; }  /* 地震 */
.map-popup-tag--storm        { background: #378ADD; }  /* 風暴 */
.map-popup-tag--landslide    { background: #888780; }  /* 崩塌 */
.map-popup-tag--drought      { background: #D85A30; }  /* 乾旱 */
.map-popup-tag--volcano      { background: #7F77DD; }  /* 火山活動 */
.map-popup-tag--extreme-temp { background: #D4537E; }  /* 極端溫度 */
/* 對照表查無此類型時的後備色，對應改寫前的 '#888' */
.map-popup-tag--unknown      { background: #888; }

/* ══════════════════════════════
   DONUT CHARTS
══════════════════════════════ */
.donut-legend {
  display: flex; flex-wrap: wrap; gap: 8px 18px;
  margin-bottom: 24px;
}
.donut-legend-item {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--smoke);
}
.donut-legend-dot {
  width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0;
}

/* ── 各洲甜甜圈圖例：資料值 → CSS class 對照 ──────────────────
   八種災害類型的代表色。原本由 JS 寫成
   <span class="donut-legend-dot" style="background:${i.color}">。

   ⚠ class 為手寫的靜態對照（index-donuts.js 的 LEGEND_DOT_CLASS），
     不得由 JS 以 'donut-legend-dot--' + i.name 串接產生
     （CLAUDE.md 的 Leaflet 圖例規則）。查不到時回退 --unknown。
     slug 沿用 5c 為地圖 popup 標籤建立的那一組（.map-popup-tag--<類型>）。

   ⚠⚠ 「洪水」在此為 #1D9E75（綠），地圖 popup 標籤的「洪水」為
      #4B7BB9（藍），**兩處刻意不同，不得統一** ——
      詳見 KNOWN-ISSUES.md 第 12 項。其餘七種兩處相同。
      統一顏色是內容決策，不屬於 CSP 改造範圍。

   ⚠ 這八個色碼與 index-donuts.js 的 CONTINENTS[].items[].color 是同一組
     資料的兩種呈現：扇形由 Chart.js 畫在 <canvas> 上（不產生 DOM 樣式，
     色碼留在 JS 是正確的），圖例點則是 DOM 元素、走 CSS。
     兩邊必須同步，否則同一類型在圖例與扇形上會出現兩種顏色。
     色碼重複分佈的全貌見 KNOWN-ISSUES.md 第 17 項。

   權重推算：基準 .donut-legend-dot（本規則上方）未設 background，
   (0,1,0) 無競爭；本區塊仍排在其後以維持慣例。
   leaflet.css 無任何 .donut 規則；index.html 不載入 style.css（決定 7）。
   index.css 的 14 個 @media 區塊無一含 .donut 家族選擇器。 */
.donut-legend-dot--wildfire     { background: #C8341A; }  /* 野火 */
.donut-legend-dot--flood        { background: #1D9E75; }  /* 洪水 ← 與地圖不同 */
.donut-legend-dot--earthquake   { background: #BA7517; }  /* 地震 */
.donut-legend-dot--storm        { background: #378ADD; }  /* 風暴 */
.donut-legend-dot--landslide    { background: #888780; }  /* 崩塌 */
.donut-legend-dot--drought      { background: #D85A30; }  /* 乾旱 */
.donut-legend-dot--volcano      { background: #7F77DD; }  /* 火山活動 */
.donut-legend-dot--extreme-temp { background: #D4537E; }  /* 極端溫度 */
/* 對照表查無此類型時的回退，比照 .map-popup-tag--unknown 的既有慣例 */
.donut-legend-dot--unknown      { background: #888;    }
.donut-grid-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.donut-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
  min-width: 600px;
  margin-bottom: 8px;
}
.donut-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-top: 3px solid var(--accent);
  padding: 20px 14px 18px;
  display: flex; flex-direction: column; align-items: center;
}
.donut-card-name {
  font-family: 'Noto Serif TC', serif;
  font-size: 16px; font-weight: 900; color: var(--charcoal);
  margin-bottom: 12px;
}
.donut-wrap {
  position: relative; width: 120px; height: 120px;
}
.donut-center {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  pointer-events: none;
}
.donut-center-num {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 30px; color: var(--charcoal); line-height: 1;
}
.donut-center-unit { font-size: 11px; color: var(--mid); font-weight: 700; letter-spacing: 0.1em; }
.data-source {
  font-size: 11px; color: var(--mid); margin-top: 4px; margin-bottom: 64px;
}

/* ══════════════════════════════
   OVERVIEW ACCORDION
══════════════════════════════ */
.overview-intro {
  font-size: 16px; line-height: 1.9; color: var(--smoke);
  font-weight: 300;
  margin-bottom: 36px;
}
.overview-intro strong { font-weight: 700; color: var(--charcoal); }

.accordion { margin-bottom: 64px; }
.acc-item {
  border: 1px solid var(--border);
  border-top: 3px solid var(--accent);
  margin-bottom: 12px;
  background: var(--white);
}
.acc-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 20px 24px;
  gap: 16px;
}
.acc-header-left { display: flex; align-items: center; gap: 16px; }
.acc-tag {
  font-size: 10px; font-weight: 700; letter-spacing: 0.12em;
  padding: 3px 10px; background: var(--navy); color: #fff;
  white-space: nowrap;
}
.acc-h { font-family: 'Noto Serif TC', serif; font-size: 17px; font-weight: 900; color: var(--charcoal); }
.acc-sub { font-size: 12px; color: var(--mid); margin-top: 2px; }
.acc-arrow {
  font-size: 18px; color: var(--accent);
  transition: transform 0.3s;
  flex-shrink: 0;
}
.acc-item.open .acc-arrow { transform: rotate(180deg); }
.acc-body {
  display: none;
  padding: 0 24px 28px;
  border-top: 1px solid var(--border);
}
.acc-item.open .acc-body { display: block; }
.acc-body p {
  font-size: 15px; line-height: 1.9; color: var(--smoke);
  font-weight: 300; margin-top: 20px;
}
.acc-body p + p { margin-top: 12px; }
.acc-figures {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 20px; margin-top: 24px;
}
.acc-figure img {
  width: 100%; border: 1px solid var(--border); display: block;
}
.acc-caption {
  font-size: 11px; color: var(--mid); line-height: 1.6; margin-top: 6px;
}
.acc-notes {
  background: var(--paper); border: 1px solid var(--border);
  padding: 14px 18px; margin-top: 20px;
}
.acc-notes p {
  font-size: 12px; color: var(--mid); line-height: 1.8; margin-top: 0;
}
.acc-notes p + p { margin-top: 4px; }
@media (max-width: 768px) {
  .acc-figures { grid-template-columns: 1fr; }
}

/* ══════════════════════════════
   TOP-10 TABS
══════════════════════════════ */
.top10-section { margin-bottom: 64px; }
.top10-tabs {
  display: flex; border-bottom: 2px solid var(--border); margin-bottom: 0;
}
.top10-tab-btn {
  font-family: 'Noto Serif TC', serif;
  font-size: 14px; font-weight: 700; letter-spacing: 0.05em;
  color: var(--mid);
  background: none; border: none;
  padding: 12px 24px 10px;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  transition: color 0.2s, border-color 0.2s;
}
.top10-tab-btn.active {
  color: var(--accent); border-bottom-color: var(--accent);
}
.top10-tab-btn:hover:not(.active) { color: var(--smoke); }
.top10-panel { display: none; }
.top10-panel.active { display: block; }
/* 三個排行攤開時的小標與間距 */
.top10-rank-title {
  font-family: 'Noto Serif TC', serif;
  font-size: 18px; font-weight: 900; color: var(--accent);
  letter-spacing: 0.05em;
  padding-bottom: 8px;
  border-bottom: 2px solid var(--accent);
  margin-bottom: 0;
}
.top10-panel + .top10-panel { margin-top: 48px; }

/* intro text above table */
.top10-intro {
  font-size: 14px; line-height: 1.85; color: var(--smoke);
  font-weight: 300; padding: 20px 0 16px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0;
}

.table-wrap { overflow-x: auto; }
.data-table {
  width: 100%; border-collapse: collapse;
  font-size: 14px; min-width: 480px;
}
.data-table thead tr { background: var(--charcoal); color: #fff; }
.data-table thead th {
  padding: 10px 14px; text-align: left;
  font-weight: 500; letter-spacing: 0.04em; white-space: nowrap;
}
.data-table tbody tr:nth-child(odd) { background: #f7f3ee; }
.data-table tbody tr:nth-child(even) { background: #fff; }
.data-table tbody tr.hl { background: #fdeee9; }
.data-table tbody td {
  padding: 10px 14px; border-bottom: 1px solid var(--border); color: var(--smoke);
}
.data-table tbody td:first-child {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 18px; color: var(--accent); width: 40px;
}
.data-source-sm { font-size: 11px; color: var(--mid); margin-top: 8px; }

/* ══════════════════════════════
   EVENTS GRID
══════════════════════════════ */
.events-sec { padding-bottom: 72px; }
.events-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px; margin-top: 8px;
}
.event-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-top: 4px solid var(--accent);
  text-decoration: none; color: inherit;
  display: flex; flex-direction: column;
  transition: box-shadow 0.2s, transform 0.2s;
}
.event-card:hover {
  box-shadow: 0 8px 32px rgba(0,0,0,0.10);
  transform: translateY(-3px);
}
.event-card-img {
  width: 100%; height: 170px; object-fit: cover; display: block;
}
.event-card-img.ph {
  background: linear-gradient(135deg, #2b2b2b 0%, #444 100%);
  display: flex; align-items: center; justify-content: center;
  color: rgba(255,255,255,0.18);
  font-family: 'Bebas Neue', sans-serif;
  font-size: 13px; letter-spacing: 0.2em;
}
.event-body { padding: 20px; flex: 1; display: flex; flex-direction: column; }
.event-meta { display: flex; gap: 10px; align-items: center; margin-bottom: 8px; }
.event-tag {
  font-size: 10px; font-weight: 700; letter-spacing: 0.12em;
  padding: 2px 9px; background: var(--accent); color: #fff;
}
.event-date { font-size: 11px; color: var(--mid); letter-spacing: 0.08em; }
.event-title {
  font-family: 'Noto Serif TC', serif;
  font-size: 16px; font-weight: 900; color: var(--charcoal);
  line-height: 1.4; margin-bottom: 8px;
}
.event-desc { font-size: 13px; color: var(--smoke); line-height: 1.7; font-weight: 300; flex: 1; }
.event-footer {
  margin-top: 16px; padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: 11px; color: var(--accent); font-weight: 700;
  letter-spacing: 0.08em;
  display: flex; justify-content: space-between; align-items: center;
}
.event-loc { color: var(--mid); font-weight: 400; }
@media (max-width: 1024px) { .events-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .events-grid { grid-template-columns: 1fr; } }

/* ══════════════════════════════
   TAIWAN PANEL — 颱風互動地圖
══════════════════════════════ */
.typhoon-legend-bar {
  display: flex; flex-wrap: wrap; gap: 10px 12px;
  margin-bottom: 20px;
}
.typhoon-legend-item {
  display: inline-flex; align-items: center;
  font-family: 'Noto Serif TC', serif;
  font-size: 15px; font-weight: 900;
  color: #fff;
  cursor: pointer;
  padding: 7px 18px;
  border-radius: 999px;
  letter-spacing: 0.04em;
  box-shadow: 0 2px 6px rgba(0,0,0,0.15);
  transition: transform 0.15s, box-shadow 0.15s, filter 0.15s;
}
.typhoon-legend-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0,0,0,0.22);
  filter: brightness(1.08);
}
.typhoon-map-wrap {
  position: relative; display: block;
  width: 1104px;       /* container max-width(1200) - padding(48*2) */
  min-width: 1104px;
  overflow: hidden;
}
.typhoon-map-wrap img { width: 100%; height: auto; display: block; }
.typhoon-overlay {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 100%; pointer-events: none;
}
.hl-path {
  fill: none; stroke-width: 20; stroke-linecap: round;
  stroke-dasharray: 36 20; opacity: 0;
  transition: opacity 0.3s ease;
  filter: drop-shadow(0 0 12px currentColor);
}
.hl-path.flowing {
  animation: typhoonFlow 0.8s linear infinite;
}
/* 路徑高亮。原為 JS 的 el.style.opacity = '1' / '0'。
   基準的 opacity: 0（本規則上方）不動 —— 它就是隱藏狀態。
   權重：基準 (0,1,0)、本規則 (0,2,0)，勝出不依賴順序。
   ⚠ stroke 來自 HTML 的 stroke="#xxxxxx" presentation attribute，不在 CSS 裡，
     本批未動。filter 的 currentColor 亦沿用基準，未改。 */
.hl-path.is-active { opacity: 1; }
@keyframes typhoonFlow {
  from { stroke-dashoffset: 0; }
  to   { stroke-dashoffset: -56; }
}
/* 固定摘要框 */
.event-summary {
  /* position 與 width 原本由 JS 的 el.style.cssText 供給，階段五 5d 第 2 批
     移進本檔。⚠ position 不可拿掉：下方的 z-index: 9999 在 static 下完全
     不參與堆疊，摘要卡會被路徑與點位蓋住。
     width 原本寫 280px，但 inline 的 30% 一直蓋著它，280px 從未生效過；
     改為 30% 以維持既有外觀（1104px 容器實測 331.198px）。 */
  position: absolute;
  width: 30%;
  background: #f5f0e8;
  border: 2.5px solid currentColor; /* 顏色由 .event-summary--<id> 的 color 供給 */
  border-radius: 4px;
  padding: 16px 18px;
  font-family: 'Noto Sans TC', sans-serif;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.3s ease;
  z-index: 9999;
  box-shadow: 0 4px 20px rgba(0,0,0,0.15);
}
.event-summary.visible { opacity: 1; }
.event-summary.visible a { pointer-events: auto; cursor: pointer; }
/* 標題列：事件名稱與日期區間並排。原為無 class 的 <div> 帶 inline style。 */
.event-summary-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 6px;
}
/* 日期區間（events.csv 的 period 欄）。原為無 class 的 <div> 帶 inline style。
   ⚠ 明寫 color: #777，不繼承卡片的事件色。
   ⚠ 命名注意：本卡另有一個 .event-summary-period，它渲染的其實是
     events.csv 的 subtitle 欄，與名稱對不上（KNOWN-ISSUES 第 15 項）。
     那一項修好之後，本 class 可以改回 .event-summary-period。 */
.event-summary-daterange {
  font-size: 11.5px; color: #777; letter-spacing: 0.03em;
  white-space: nowrap; margin-left: 8px;
}
.event-summary-name {
  font-family: 'Noto Serif TC', serif;
  font-size: 18.0px; font-weight: 900;
  margin-bottom: 6px; letter-spacing: 0.05em;
}
.event-summary-period {
  font-size: 14.5px; color: #777;
  margin-bottom: 10px; letter-spacing: 0.03em;
}
.event-summary-body {
  font-size: 15.0px; color: #333;
  line-height: 1.75;
}
.event-summary-stat {
  display: flex; justify-content: space-between;
  margin-top: 12px; gap: 6px;
}
.event-summary-stat-item {
  flex: 1; text-align: center;
  background: rgba(0,0,0,0.05);
  border-radius: 3px; padding: 6px 4px;
}
.event-summary-stat-num {
  font-size: 18.0px; font-weight: 700; line-height: 1.2;
  /* 原為 color: #222，但 inline 的事件色一直蓋著它，#222 從未生效過。
     改為 inherit，從卡片根的 .event-summary--<id> 取事件色。 */
  color: inherit;
}
.event-summary-stat-label {
  font-size: 13.0px; color: #777;
  margin-top: 3px;
}
/* 卡片頁尾：連結靠右，上方一條淡分隔線。原為無 class 的 <div> 帶 inline style。
   border-top 必須寫完整 —— 基準沒有任何 border-top，寬度是 0。 */
.event-summary-footer {
  margin-top: 12px; padding-top: 10px;
  border-top: 1px solid rgba(0,0,0,0.1);
  text-align: right;
}
/* 卡片連結。原為無 class 的 <a> 帶 inline style。
   ⚠ color 與 text-decoration 必須明寫：這個 <a> 沒有任何其他 author 規則，
     少寫就會浮出瀏覽器 UA 預設（實測 rgb(0,0,238) 藍色 + underline）。
   color: inherit 取卡片根的事件色。 */
.event-summary-link {
  font-size: 12px; font-weight: 700; letter-spacing: 0.05em;
  color: inherit; text-decoration: none;
}

/* ── 颱風摘要卡：資料值 → CSS class 對照 ──────────────────────
   八個事件的代表色與擺放位置。原本由 JS 寫成一整條 cssText：
     el.style.cssText = 'position:absolute; left:' + x + '; top:' + y +
                        '; width:30%; border:2.5px solid ' + ev.color + ';'

   ⚠ class 為手寫的靜態對照（index-typhoon.js 的 SUMMARY_CLASS），
     不得由 JS 以 'event-summary--' + ev.id 串接產生
     （CLAUDE.md 的 Leaflet 圖例規則）。查不到時回退 --unknown。

   ⚠ 只設 color，不另設 border-color。基準 .event-summary 是
     border: 2.5px solid currentColor，邊框與卡內三處文字
     （名稱、三個 stat 數字、連結）全部靠這一個 color 供給。

   ⚠ 位置值刻意重複寫滿，不抽共用修飾詞 —— 六個事件同為
     left: 68%; top: 45%。本站資料已凍結，重複的維護成本不會發生，
     換得零新命名慣例、與 .typhoon-legend-item--<id> 對稱。

   ⚠ 自階段五 5d 第 2 批起，assets/events.csv 的 pos_x / pos_y 兩欄
     **不再被程式讀取**，位置一律以本表為準。
     改 CSV 的那兩欄不會有任何效果，也不會有任何錯誤訊息。

   ⚠ 這八個色碼與 .typhoon-legend-item--<id>（本檔下方）是同一組資料，
     修改時必須同步。

   權重推算：基準 .event-summary 設的是 position／width／border／z-index 等，
   與本區塊設的 color／left／top **完全不重疊**，理論上不依賴順序；
   仍排在基準之後，以免日後有人在基準補 color 就翻盤。
   其餘可能命中同一元素者：leaflet.css 沒有任何 .event-summary 規則，
   index.html 不載入 style.css（決定 7）。無 !important 競爭。 */
.event-summary--mataian   { color: #bf9000; left: 68%; top: 45%; }  /* 馬太鞍堰塞湖 */
.event-summary--caoling   { color: #548235; left: 68%; top: 45%; }  /* 草嶺潭堰塞湖 */
.event-summary--yanzikou  { color: #c55a11; left: 68%; top: 45%; }  /* 燕子口堰塞湖 */
.event-summary--chiayi    { color: #333f50; left: 68%; top: 45%; }  /* 嘉義大埔地震 */
.event-summary--rain0728  { color: #7030a0; left: 68%; top: 45%; }  /* 0728 豪雨 */
.event-summary--hagupit   { color: #ea6695; left: 35%; top: 55%; }  /* 樺加沙颱風 */
.event-summary--danas     { color: #85b928; left: 68%; top: 45%; }  /* 丹娜絲颱風 */
.event-summary--fenghuang { color: #f7b500; left: 30%; top: 15%; }  /* 鳳凰颱風 */
/* 對照表查無此 id 時的回退。位置沿用改寫前 JS 的預設值
   （ev.pos_x || '72%' / ev.pos_y || '5%'），顏色比照 .map-popup-tag--unknown。 */
.event-summary--unknown   { color: #888;    left: 72%; top:  5%; }
.typhoon-hit {
  pointer-events: all; cursor: pointer;
  fill: transparent; stroke: transparent;
  /* ⚠ 24 是 hit 判定範圍（讓細路徑也好點），不是視覺描邊。
     高亮時的描邊寬度由下方 .is-active 明寫，不靠清空 inline 回退到這個值。 */
  stroke-width: 24; stroke-linecap: round;
}

/* ── 點位／範圍高亮 ────────────────────────────────────────────
   原為 JS 在 showEvent() 寫 6 個 element.style、hideEvent() 再逐一清空。

   顏色全部走 currentColor，由 .typhoon-hit--<id> 的一個 color 供給
   （fill、stroke、drop-shadow 三處共用）。

   權重：基準 .typhoon-hit 為 (0,1,0)，本區塊的 .is-active 為 (0,2,0)、
   帶元素型別的為 (0,2,1)，兩者都勝出且不依賴順序。
   index.css 的 @media 區塊無一含 .typhoon-hit / .hl-path 家族選擇器。 */
.typhoon-hit.is-active {
  fill: currentColor;
  fill-opacity: 0.35;
  stroke: currentColor;
  stroke-opacity: 0.9;
  filter: drop-shadow(0 0 8px currentColor);
}
/* ⚠ 依裁示 3 明寫，不得省略。circle 與 polygon 的值本來就不同。
   只有 circle 與 polygon 會拿到 .is-active —— rect 是互動熱區、
   從不高亮（與改寫前 showEvent() 的 tag 判斷一致），故不會受影響。 */
circle.typhoon-hit.is-active  { stroke-width: 4; }
polygon.typhoon-hit.is-active { stroke-width: 3; }

/* 事件代表色。class 由 index-typhoon.js 的 HIT_CLASS 手寫對照表在
   bindHitZones() 時依 data-id 掛上，不由字串串接產生。
   ⚠ 這八個色碼與 .event-summary--<id>、.typhoon-tooltip--<id>、
     .typhoon-legend-item--<id> 是同一組資料，修改時四處都要同步。 */
.typhoon-hit--mataian   { color: #bf9000; }  /* 馬太鞍堰塞湖 */
.typhoon-hit--caoling   { color: #548235; }  /* 草嶺潭堰塞湖 */
.typhoon-hit--yanzikou  { color: #c55a11; }  /* 燕子口堰塞湖 */
.typhoon-hit--chiayi    { color: #333f50; }  /* 嘉義大埔地震 */
.typhoon-hit--rain0728  { color: #7030a0; }  /* 0728 豪雨 */
.typhoon-hit--hagupit   { color: #ea6695; }  /* 樺加沙颱風 */
.typhoon-hit--danas     { color: #85b928; }  /* 丹娜絲颱風 */
.typhoon-hit--fenghuang { color: #f7b500; }  /* 鳳凰颱風 */
/* 對照表查無此 id 時的回退 */
.typhoon-hit--unknown   { color: #888;    }

/* ── 點位 icon（buildDotIcons 產生的 <g>）──────────────────────
   原為 makeIconG() 寫 g.style.opacity = '0' 與 g.style.transition，
   再由 showEvent()／hideEvent() 改寫 opacity。
   ⚠ transition 的 ease 是預設值，computed 會顯示成 "opacity 0.3s"，
     與改寫前逐字相同。 */
.dot-icon { opacity: 0; transition: opacity 0.3s ease; }
.dot-icon.is-active { opacity: 1; }

/* ── 沿路徑移動的颱風圖示（arrow-layer 內的 <g>）────────────────
   原為 g.style.display = 'none' ↔ ''，其中 '' 是「移除 inline、
   退回 UA 預設」。
   ⚠ SVG <g> 的 UA 預設值為 display: inline —— 已實測確認：
     新建一個未設任何樣式的 <g> 量到 inline，且把原本的 inline
     清成 '' 之後量到的也是 inline。此處照實測值寫，不憑記憶。 */
.typhoon-moving-icon { display: none; }
.typhoon-moving-icon.is-active { display: inline; }
.typhoon-tooltip {
  position: absolute;
  background: rgba(245, 240, 232, 0.92);
  /* 顏色由 .typhoon-tooltip--<id> 的 color 供給。原本寫死 #c8341a，
     但 JS 的 tooltip.style.borderLeftColor 一直蓋著它，那個值從未生效。
     用 currentColor 而不是 transparent：漏掉修飾詞時會退回繼承的文字色
     （看得見的異常），而不是整條色帶消失、版面卻不變（無聲失敗）。 */
  border-left: 3px solid currentColor;
  padding: 12px 18px;
  font-family: 'Noto Sans TC', sans-serif;
  font-size: 13px; line-height: 1.65;
  pointer-events: none; opacity: 0;
  transition: opacity 0.2s;
  z-index: 10;
  box-shadow: 0 8px 32px rgba(0,0,0,0.15);
  max-width: 260px; white-space: normal;
}
.typhoon-tooltip.visible { opacity: 1; }
.typhoon-tooltip-name {
  font-family: 'Noto Serif TC', serif;
  /* 原為 color: #1a1a1a，被 inline 的事件色壓著、從未生效。
     改 inherit，從 .typhoon-tooltip--<id> 取事件色。 */
  font-size: 18px; font-weight: 900; margin-bottom: 4px; color: inherit;
}
.typhoon-tooltip-desc {
  font-size: 12px; color: #666; margin-bottom: 10px;
}
.typhoon-tooltip-link {
  display: block; font-size: 11px; font-weight: 700; letter-spacing: 0.05em;
  /* 原為 color: #c8341a，被 inline 的事件色壓著、從未生效。改 inherit。 */
  color: inherit; text-decoration: none;
  /* border-top-color 由下方 8 條 .typhoon-tooltip--<id> .typhoon-tooltip-link
     覆寫為事件色的 25% 透明版；這裡的 rgba(0,0,0,0.1) 是查表失敗時的後備。 */
  border-top: 1px solid rgba(0,0,0,0.1); padding-top: 8px;
}
/* ⚠ 這條在目前的版面下永遠不會命中：.typhoon-tooltip 是 pointer-events: none，
   連結的 computed 值也是 none，滑鼠事件到不了它。改寫前後皆然，原樣保留。 */
.typhoon-tooltip-link:hover { color: #f5a080; }

/* ── 颱風 tooltip：資料值 → CSS class 對照 ──────────────────────
   八個事件的代表色。原本由 JS 寫成三處 inline：
     tooltip.style.borderLeftColor = t.color;
     <div class="typhoon-tooltip-name" style="color:…">
     <a class="typhoon-tooltip-link" style="color:…; border-color:…40;">

   ⚠ class 為手寫的靜態對照（index-typhoon.js 的 TOOLTIP_CLASS），
     不得由 JS 以 'typhoon-tooltip--' + id 串接產生
     （CLAUDE.md 的 Leaflet 圖例規則）。查不到時回退 --unknown。

   ⚠ 只設 color，邊框與兩處文字全靠 currentColor / inherit 供給。

   ⚠ border-top-color 另寫 8 條後代選擇器（0,2,0），不用自訂屬性 ——
     自訂屬性的名稱會編碼「用途」而非「內容」，且 var() 的 fallback
     是隱性的，漏掉修飾詞時會無聲退回原值。
     這個色是事件色的 25% 透明版（8 位元 hex 的 40 尾綴）。

   ⚠ 這八個色碼與 .event-summary--<id>、.typhoon-legend-item--<id>
     是同一組資料，修改時三處都要同步。

   權重推算：基準 .typhoon-tooltip 未設 color，(0,1,0) 無競爭；
   border-left-color 由基準的 currentColor 解析。
   後代規則 .typhoon-tooltip--<id> .typhoon-tooltip-link 為 (0,2,0)，
   勝過基準 .typhoon-tooltip-link 的 (0,1,0)，不依賴順序。
   leaflet.css 無任何 .typhoon-tooltip 規則；index.html 不載入 style.css。
   index.css 的 14 個 @media 區塊無一含 .typhoon-tooltip 家族選擇器。 */
.typhoon-tooltip--mataian   { color: #bf9000; }  /* 馬太鞍堰塞湖 */
.typhoon-tooltip--caoling   { color: #548235; }  /* 草嶺潭堰塞湖 */
.typhoon-tooltip--yanzikou  { color: #c55a11; }  /* 燕子口堰塞湖 */
.typhoon-tooltip--chiayi    { color: #333f50; }  /* 嘉義大埔地震 */
.typhoon-tooltip--rain0728  { color: #7030a0; }  /* 0728 豪雨 */
.typhoon-tooltip--hagupit   { color: #ea6695; }  /* 樺加沙颱風 */
.typhoon-tooltip--danas     { color: #85b928; }  /* 丹娜絲颱風 */
.typhoon-tooltip--fenghuang { color: #f7b500; }  /* 鳳凰颱風 */
/* 對照表查無此 id 時的回退，比照 .map-popup-tag--unknown 與
   .event-summary--unknown 的既有慣例。 */
.typhoon-tooltip--unknown   { color: #888;    }

/* 連結上方的分隔線：事件色的 25% 透明版（原為 inline 的 t.color + '40'）。 */
.typhoon-tooltip--mataian   .typhoon-tooltip-link { border-top-color: #bf900040; }
.typhoon-tooltip--caoling   .typhoon-tooltip-link { border-top-color: #54823540; }
.typhoon-tooltip--yanzikou  .typhoon-tooltip-link { border-top-color: #c55a1140; }
.typhoon-tooltip--chiayi    .typhoon-tooltip-link { border-top-color: #333f5040; }
.typhoon-tooltip--rain0728  .typhoon-tooltip-link { border-top-color: #7030a040; }
.typhoon-tooltip--hagupit   .typhoon-tooltip-link { border-top-color: #ea669540; }
.typhoon-tooltip--danas     .typhoon-tooltip-link { border-top-color: #85b92840; }
.typhoon-tooltip--fenghuang .typhoon-tooltip-link { border-top-color: #f7b50040; }
.typhoon-tooltip--unknown   .typhoon-tooltip-link { border-top-color: #88888840; }
@media (max-width: 768px) {
  .typhoon-legend-bar { gap: 8px 10px; }
  .typhoon-legend-item { font-size: 13px; padding: 6px 14px; }
}

/* ══════════════════════════════
   FOOTER
══════════════════════════════ */
.site-footer {
  background: #2d3561;
  border-top: 3px solid #9b3a2a;
  padding: 28px 48px;
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 12px;
}
.site-footer .left { font-size: 13px; color: rgba(255,255,255,0.6); font-weight: 500; }
.site-footer .left strong { color: #fff; }
.site-footer .right { font-size: 11px; color: rgba(255,255,255,0.38); line-height: 1.8; text-align: right; }
@media (max-width: 768px) {
  .site-footer { padding: 24px 20px; flex-direction: column; text-align: center; }
  .site-footer .right { text-align: center; }
}

/* ══════════════════════════════
   階段五 5a：原內嵌 style 屬性改寫而來的 class

   每一條都附競爭規則與勝出依據。index.html 只載入本檔，
   不載入 style.css／event.css，故競爭規則全部來自本檔。
══════════════════════════════ */

/* 兩個分頁面板的橫向捲動（世界、臺灣各一）。
   基準 .tab-panel（本檔上方）只設 display，未觸及 min-width／overflow-x，
   亦無 @media 規則觸及，(0,1,0) 無競爭。

   ── overflow-x: auto 保留，不要拿掉 ────────────────────────────
   臺灣面板內有 .typhoon-map-wrap（width/min-width 皆 1104px 的災點圖）。
   沒有這個捲動容器，那 1104px 會一路撐破 body，整頁產生橫向捲軸。
   本規則的職責就是「把過寬的內容關在面板裡捲」，這一半是對的。

   ── min-width: 900px 已刪除 ───────────────────────────────────
   刪除理由：它掛在**捲動容器自己**身上，於是溢位的是容器而不是內容 ——
   面板被撐成 900px，連帶把 .site-nav／.tab-bar／.container／KPI 全部
   撐到 900px，整份文件的版面寬度變成 900。手機上看到的「桌機版等比例
   縮小」就是這樣來的，不是缺 viewport meta，也不是缺 media query
   （viewport meta 正常，max-480 的 media query 也確實有命中）。

   同檔案裡有兩組**正確模式**可對照，兩者都是「容器不設寬，寬的是內容」：
     .donut-grid-wrap { overflow-x: auto }  ←→  .donut-grid { min-width: 600px }
     .table-wrap      { overflow-x: auto }  ←→  .data-table { min-width: 480px }
   本規則原本等於把這兩層合寫在同一個元素上，捲動容器與被捲內容變成
   同一個，overflow-x 就失去作用對象。

   實測證據（headless Chrome 裝置模擬，六個寬度 × 有/無此規則）：
     ≥1024px  該規則完全惰性 —— 面板寬度本來就 ≥900，刪不刪一樣
     900px    桌機捲軸吃掉 15px，可用寬只剩 885，
              此規則反而製造出 15px 的橫向捲軸（它自己就是問題來源）
     <900px   強制 900，這是唯一「有作用」的區間，也正是壞掉的區間

   ⚠ 連動：assets/js/index-map.js:169
     刪掉本行後 window.innerWidth 會從 900 變成實際裝置寬（390／414），
     於是 index-map.js 的 isMobile = window.innerWidth <= 480 將**首次
     生效** —— 手機上會執行 map.dragging.disable() 與 map.touchZoom.disable()，
     世界地圖變成不能拖曳、不能雙指縮放。
     該行為是否要保留尚未決定，本批次不動 index-map.js。 */
.tab-panel--wide-scroll {
  overflow-x: auto;
}

/* 導言段落與下一區塊的間距收緊（基準 .overview-intro 為 36px）。
   同權重 (0,1,0)，本規則位置在基準之後，靠順序勝出。 */
.overview-intro--tight-below { margin-bottom: 28px; }

/* 資料來源列在颱風互動地圖下方時的間距。
   基準 .data-source 為 margin-top:4px / margin-bottom:64px，
   此處上緣加大、下緣收緊，故拆成兩個方向明確的修飾詞。 */
.data-source--spaced-above { margin-top: 12px; }
.data-source--tight-below  { margin-bottom: 48px; }

/* 臺灣災點分布圖（figure + img + figcaption）。
   原本 <figure>／<img>／<figcaption> 三個元素各帶一個 style 屬性。 */
.figure-disaster-spot { margin: 0 0 16px; }
.figure-disaster-spot img {
  width: 100%;
  display: block;
}
/* 圖說。與 .figure-disaster-spot 分開命名：它是可重複使用的圖說樣式，
   不專屬於災點圖。 */
.figure-caption {
  font-size: 12px;
  color: var(--mid);
  margin-top: 8px;
  letter-spacing: 0.05em;
}

/* ── 颱風圖例：資料值 → CSS class 對照 ──────────────────────
   八個事件的代表色。原本以 style="background:#xxxxxx" 寫在各 div 上。

   ⚠ class 為手寫的靜態對照，不得由 JS 以 'typhoon-legend-item--' + id
     串接產生（CLAUDE.md 的 Leaflet 圖例規則）。

   ⚠ 這八個色碼與 assets/events.csv 的 color 欄相同，但兩者來源本來就分開：
     圖例的顏色原本寫死在 HTML 的 style 屬性裡，不是從 CSV 讀的。
     本檔取代的是那些 style 屬性。
     CSV 的 color 欄目前仍由內嵌 script 的 buildSummary() 用於摘要卡，
     要到階段五 5d 才一併改為 class；屆時 CSV 的 color 欄將僅供參考，
     實際顏色以本檔為準。改顏色時兩邊都要動，以免說法不一。

   基準 .typhoon-legend-item（本檔上方）未設 background，(0,1,0) 無競爭。 */
.typhoon-legend-item--mataian   { background: #bf9000; }  /* 馬太鞍堰塞湖 */
.typhoon-legend-item--caoling   { background: #548235; }  /* 草嶺潭堰塞湖 */
.typhoon-legend-item--yanzikou  { background: #c55a11; }  /* 燕子口堰塞湖 */
.typhoon-legend-item--chiayi    { background: #333f50; }  /* 嘉義大埔地震 */
.typhoon-legend-item--rain0728  { background: #7030a0; }  /* 0728 豪雨 */
.typhoon-legend-item--hagupit   { background: #ea6695; }  /* 樺加沙颱風 */
.typhoon-legend-item--danas     { background: #85b928; }  /* 丹娜絲颱風 */
.typhoon-legend-item--fenghuang { background: #f7b500; }  /* 鳳凰颱風 */

/* ══════════════════════════════
   LIGHTBOX（圖片點擊放大）
   ══════════════════════════════
   來源：assets/css/event.css 第 853–897 行與 924–925 行，逐字抄一份。
   class 名稱與數值全部照抄，未新建 class、未改為 var()
   —— 這些規則本來就不依賴任何 CSS 變數，全是寫死色值。

   ⚠ 為什麼是抄一份，不是共用
     index.html 只載入 assets/css/index.css（與 leaflet.css），
     不載入 event.css 也不載入 style.css。這是既有架構
     （CLAUDE.md 決定 7：首頁與事件頁是兩套設計系統，
     同名 CSS 變數數值不同，不得合併為單一 base.css）。
     要共用就得讓首頁載入 event.css，那會把 20 頁事件頁的
     整套規則帶進首頁，代價遠大於重複這 40 行。
     ⚠ 兩邊是各自獨立的複本，改動時要自行同步。

   ⚠ body.lb-open { overflow: hidden } 在首頁**會生效**
     首頁的 html 沒有任何 overflow 宣告（index.css 只有
     html { scroll-behavior: smooth }），是初始值 visible。
     依 CSS 規範，viewport 的 overflow 取自 html；
     **只有當 html 是 visible 時，才改從 body 取** —— 首頁正是這個情況，
     所以鎖定會傳播到 viewport，背景真的鎖得住。

     這與事件頁不同：事件頁載入 event.css:81 的
     html, body { overflow-x: clip; }，html 非 visible，傳播被擋，
     body 上的 overflow: hidden 鎖不住背景 —— 那就是
     KNOWN-ISSUES 第 3 項。
     **該項的成因在首頁不成立**，首頁不需要 html.lb-open 那種修法。
     （event.css:81 之所以存在，是為了修正 style.css 的
     overflow-x: hidden 破壞 position: sticky；首頁兩者都沒載入。）

   對應的 JS 在 assets/js/index-lightbox.js。 */
.lb-zoomable { cursor: zoom-in; }
.lb-overlay {
  position: fixed; inset: 0; z-index: 9999;
  display: none;
  align-items: center; justify-content: center;
  flex-direction: column;
  background: rgba(10, 12, 16, 0.92);
  padding: 32px;
  cursor: zoom-out;
  opacity: 0;
  transition: opacity 0.25s ease;
}
.lb-overlay.open { display: flex; opacity: 1; }
.lb-overlay img {
  max-width: 100%;
  max-height: calc(100vh - 120px); /* 留空間給圖說與邊距 */
  width: auto; height: auto;
  object-fit: contain;
  border: 1px solid rgba(255,255,255,0.15);
  box-shadow: 0 8px 40px rgba(0,0,0,0.5);
  cursor: default;
}
.lb-caption {
  color: rgba(255,255,255,0.88);
  font-size: 13px; line-height: 1.6;
  letter-spacing: 0.04em;
  text-align: center;
  max-width: 900px;
  margin-top: 16px;
}
.lb-close {
  position: fixed; top: 20px; right: 28px;
  width: 40px; height: 40px;
  border: none; background: rgba(255,255,255,0.12);
  color: #fff; font-size: 22px; line-height: 1;
  border-radius: 50%; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background 0.2s;
}
.lb-close:hover { background: rgba(255,255,255,0.25); }
@media (max-width: 600px) {
  .lb-overlay { padding: 16px; }
  .lb-overlay img { max-height: calc(100vh - 100px); }
  .lb-close { top: 12px; right: 14px; }
}
.lb-caption.is-hidden { display: none; }
body.lb-open { overflow: hidden; }
