/* =====================================================================
   防災アプリ2.0 — モバイル Web クライアント
   Design language: "Calm authority" — 公共の信頼 / 高コントラスト / 大きめタップ領域
   依存ゼロ・WebView / モバイルブラウザ両対応・safe-area 対応
   ===================================================================== */

/* ---------- Design tokens ---------- */
:root {
  /* brand — "fresh" 清新現代風 (#1584: --primary AA ink 4.95 on white; --primary-bright = surface/大要素) */
  --primary: #0a7e72;
  --primary-bright: #12b3a6;
  --primary2: #5fd6c6;
  --primary-soft: #dbf5ef;
  --ink: #143b3a;
  --ink-2: #4d706c;
  --ink-3: #527672;
  /* #2600: `#/home`'s `homeNormal()` (平時ホーム — every non-disaster citizen's landing
     screen) puts `var(--primary)`/`var(--ink-3)` text directly on the `.tint-primary`
     card's `var(--primary-soft)` background (the login-CTA card's title/body, and the
     "本日の情報" card's `.appbar__back` "›" chevron) — a combination neither token was
     ever verified against, since both are tuned for use as ink on the app's neutral
     `--card`/`--bg` surfaces, not on this specific tinted one. Measured 4.32:1 / 4.37:1,
     both just under AA's 4.5:1 for text. `--primary`/`--ink-3` themselves are used
     extremely widely with their own separate contrast contracts (segbar/tab/buttons/
     field borders for `--primary`; a dozen meta/label rows app-wide for `--ink-3` — see
     issue #2600's grep), so — same reasoning as #2599's `--danger-tabbar-active` — this
     adds two narrowly-scoped tokens instead of retuning the shared ones, applied via
     inline `style` only on `homeNormal()`'s own two elements (NOT via a `.tint-primary
     .card__title`-style selector, which would also silently repaint `homeEmergency()`'s
     byte-identical-looking `.tint-primary` card in `homeEmergency()` at app.js:1546 — that card had the
     identical defect, independently confirmed, and #2601 fixed it too by applying these
     SAME tokens directly via its own inline `style` (not by broadening this selector);
     `KNOWN_VIOLATIONS["#/home-off-emergency"]` is empty as of #2601 — see that key's own
     comment below). Dark mode already clears
     AA on this same pair (`--primary` dark 7.34:1, `--ink-3` dark 5.13:1 against dark
     `--primary-soft` #183436 — re-verified, WCAG relative-luminance formula) — see the
     `:root[data-theme="dark"]` overrides below, which reinstate the normal token instead
     of introducing a second dark hue. */
  --primary-on-tint: #097267; /* light-only fix: 5.07:1 on --primary-soft #dbf5ef (was var(--primary) #0a7e72, 4.32:1) */
  --ink3-on-tint: #4b6b68; /* light-only fix: 5.09:1 on --primary-soft #dbf5ef (was var(--ink-3) #527672, 4.37:1) */
  /* #2683: `#/evac/supplies` の困りごと例文（app.js、`--bg-deep` #e2f5ee の上）は
     `var(--ink-3)` #527672 を載せて light 4.42:1 と AA 未達。既存 `--ink3-on-tint` は
     コメントで `--primary-soft` 専用と明記されているため流用せず新設する。light は同値
     #4b6b68（5.14:1）、dark は下の :root[data-theme="dark"] で `var(--ink-3)` を再宣言
     （5.81:1、達成済みのため値は変えない）。 */
  --ink3-on-bg-deep: #4b6b68;

  /* semantic — 色相/ink 維持既存 AA 契約; -soft のみ fresh 系へ微調整(実算 ≥4.5 のもののみ) */
  --danger: #D32F2F;
  --danger-deep: #B71C1C;
  --danger-soft: #ffe1e6;
  /* #2599: 緊急モード時タブバー選択中ラベル専用トークン。--danger 自体は .tab__badge 等
     他所の意味論/対比契約を持つため変更しない（issue #2599 の PM 裁決）。light は現状の
     --danger のまま実測 4.98:1 で AA 達成済みのため据え置き、dark のみ下の
     :root[data-theme="dark"] ブロックで明るい赤に上書きする。`.tab.is-active::before`
     の頂部インジケータ（非文字要素・WCAG 1.4.11 の 3:1 対象、実測 3.15:1 で既に達成）は
     このトークンを使わず引き続き `var(--danger)` 直参照のまま。 */
  --danger-tabbar-active: var(--danger);
  --warn: #EF6C00;
  --warn-soft: #FFF3E0;
  /* #2673: `#/evac/map` の車中泊カード「残N台」(app.js:3615) は var(--warn) を素の .card
     背景に直書きしていた — #2600/#2601 と同じ「タグ付き -soft 背景専用に調整された既存
     トークンではなく、素の .card 背景に対して未検証だった」構図。light は 3.08:1 で AA
     未達、dark は --card が暗いため素の --warn のままで 5.08:1 と既に AA 達成 —
     #2600 の --primary-on-tint 等と同じ「light だけ専用トークン、dark は base を
     再宣言」パターン。
     #2805: 2つ目の呼び出し元として `#/me/safety` の「🤕 負傷あり」（app.js:2635、
     tint クラスの無い素の `--card` 背景）にも適用。値は変更しない（light 3.79→5.50:1 /
     dark 4.13→5.08:1）。 */
  --warn-on-card: #b24800; /* light: 5.50:1 on --card #FFFFFF (was var(--warn) #EF6C00, 3.08:1) */
  --safe: #2E7D32;
  --safe-soft: #dbf6ec;
  /* #2778: `#/info/epidemic` の `.tint-safe` 見出し 2 つ（app.js、「📊 …警戒レベル」「💉 予防接種・
     健康情報」）は `var(--safe)` #2E7D32 を `--safe-soft` 上に直載せしており light 4.49 / dark 2.45:1
     と AA 未達。`.b-safe` バッジと同じ「safe ink on --safe-soft」の墨色を流用する —— light は
     `.b-safe` の #1B5E20（6.9:1）、dark は下の :root[data-theme="dark"] で `.b-safe` と同じ
     #7cd99a（7.32:1）へ上書き。
     #2799: 3つ目の呼び出し元として `#/info/epidemic` の「Lv.N」の数字（app.js:1916、同じ
     `.tint-safe` = `--safe-soft` 背景）にも適用。値は変更しない（light 4.49→6.90:1 / dark
     2.45→7.32:1）。 */
  --safe-title-on-tint: #1B5E20;
  /* #2600: `homeNormal()`'s "本日の情報" summary line (app.js#todayStatus, the
     no-active-warning branch) renders `var(--safe)` directly on the plain `.card`
     background (`var(--card)`) — fine in light (white card, high margin) but only
     3.06:1 in dark (`--card` #14262a), under AA's 4.5:1. `todayStatus()` has exactly
     one call site (homeNormal's weather/status line), so this token's blast radius is
     that one element only — no selector-scoping trick needed the way the tint tokens
     above do. Light keeps `var(--safe)` (unchanged); dark overrides below. */
  --safe-on-card: var(--safe);
  /* #2601: `#/me` の「⚠ 居住自治体の変更」カード（`.tint-warn`, app.js の muniChange）は
     3 つの字面をインライン style で直書きしていた —— 題字 `#E65100`（hardcoded）・
     `var(--safe)`・`var(--danger)` を `--warn-soft` 上に載せる。light は題字 `#E65100` が
     4.5:1 未満（≈4.2:1）、dark は 3 つとも 3.65 / 2.69 / 2.77:1 と全滅。#2600 と同じ
     「共有トークンは再調整せず、この要素専用のスコープトークンを立てる」方針。
     #2673: 2つ目の呼び出し元として `#/evac/map` の協力店舗カード「⚠️ 利用ルール」
     ラベル（app.js:3629、同じ `--warn-soft` 背景）にも適用。値は変更しない（同色相・
     同意味論の再利用、light 2.81→5.01:1 / dark 4.48→7.98:1）。
     #2683: 3つ目の呼び出し元として `#/evac/supplies` の「不足の物資はありませんか？」
     見出し（app.js:3939、同じ `--warn-soft` 背景）にも適用。値は変更しない（同色相・
     同意味論の再利用、light 3.46→5.01:1 / dark 3.65→7.98:1）。
     #2805: 4〜7つ目の呼び出し元として `#/evac/checkout`「📋 罹災証明書のご案内」
     （app.js:3861）・`#/home` 平時「home.reg_t」（app.js:1453）・`#/info`
     「info.warn.title」（app.js:1703）・`#/me/checklist` 達成度%（app.js:2603、
     20px/900 の大きな文字）にも適用。B1（evac/checkout）はこのトークンの元々の
     設計対象そのもの（このコメント冒頭の #E65100 が同じ字面）。値は変更しない
     （light 3.46/4.21→5.01:1 / dark 2.99/3.65→7.98:1）。 */
  --warn-title-on-tint: #b24800; /* light: ≈5.05:1 on --warn-soft #fff3e0（was #E65100, ≈4.2:1） */
  --safe-on-warn-tint: var(--safe); /* light は据え置き（十分）; dark は下で明色へ */
  --danger-on-warn-tint: var(--danger); /* light は据え置き（十分）; dark は下で明色へ */
  --info: #0277BD;
  --info-soft: #E3F2FD;
  /* #2683: `#/evac/supplies` の「📍 本日の安否確認」見出し（app.js、`.tint-info` =
     `--info-soft` #E3F2FD の上）は `var(--info)` #0277BD を直載せしており light 4.20 /
     dark 3.08:1 と AA 未達。`--info` 自体は他所の意味論/対比契約を持つため変更せず、
     この要素専用のスコープトークンを立てる。light は同じ `--info-soft` 上で既に使われて
     いる `.b-info` の墨色 #01579B を流用（6.48:1）。dark は下の :root[data-theme="dark"]
     で明色 #4FC3F7（7.38:1）へ上書き。
     #2799: 2つ目の呼び出し元として `#/evac/supplies` 冒頭の帯 `supHead`（app.js:3937、
     同じ `--info-soft` 背景）にも適用。値は変更しない（light 11.60→6.48:1・dark
     1.12→7.38:1）。 */
  --info-title-on-tint: #01579B;
  --teal: #00897B;
  --teal-soft: #E0F2F1;
  --pet: #F57C00;
  --pet-soft: #FFF4E2;
  /* #2778: `#/evac/supplies` のペット物資の到着予定 eta（app.js、`etaTone:"danger"` の品目）は
     `var(--danger)` #D32F2F を `--pet-soft` 上に載せており dark 2.96:1 と AA 未達（light は
     4.57:1 で達成、据え置き）。`.b-danger` の dark ink と同じ明色 #ff8a80（6.46:1 on dark
     --pet-soft #33260F）を下の :root[data-theme="dark"] で上書きする。 */
  --danger-on-pet-tint: var(--danger);
  /* #2600: `homeNormal()`'s pet-evacuation card (`.tint-pet`, "🐾 ペット同行避難フロー")
     has two more never-verified pairs: its hardcoded `#C65000` title ink (the same
     shade `.b-pet`/`.b-warn` badges use elsewhere — a wider, out-of-scope finding
     reported separately, not fixed here) measured 4.24:1 light / 3.19:1 dark on
     `.tint-pet`'s `var(--pet-soft)` background — BOTH themes short of AA, unlike the
     primary/ink3 pair above; and its `var(--pet)` steps line measured 2.48:1 light
     (dark already clears AA at 5.45:1, untouched, see below — orange-on-dark-brown
     reads very differently from orange-on-pale-peach). `#C65000` isn't a css var at
     all here and `--pet` is used across most of the pet-flow screens (evac/checkin/
     pets — see issue #2600's grep), so both get scoped tokens instead of a global
     retune, applied via inline `style` only on `homeNormal()`'s own two lines.
     #2683: 2つ目の呼び出し元として `#/evac/supplies` のペット用物資カテゴリ見出し
     「🐾 ペット用物資」（app.js:3931、同じ `--pet-soft` 背景）にも適用。値は変更しない
     （light 3.48→5.05:1 / dark 3.89→5.02:1）。
     #2799: 3・4つ目の呼び出し元として `#/me/pets` の 0 件案内・一覧上の案内
     （app.js:3143・3172、同一文言・同一色で `.info-strip` の `--pet-soft` 背景）にも
     適用。値は変更しない（light 4.24→5.05:1 / dark 3.19→5.02:1）。
     #2805: 5〜11個目の呼び出し元として、`#/store/register`「🐾 ペットへの支援」
     （app.js:2682）・`#/me/pets`「📦 ペット用備蓄品チェック」（app.js:3206）・
     `#/home-evacuation/register`「🐾 同居ペット」（app.js:3289）・`#/evac/checkin`
     「🐾 ペット同行確認」（app.js:3795）・`#/home` 平時「home.pet_t」（app.js:1462）・
     `#/home` 発災「🐾 ペットの状況」（app.js:1561）・`#/me/checklist`「🐾 ペット用
     持ち出し品」（app.js:2599）にも適用。いずれも同じ `--pet-soft` 背景（一部は
     inline `background:var(--pet-soft)`、一部は `.tint-pet`）。値は変更しない
     （light 3.48/4.24→5.05:1 / dark 3.89/3.19→5.02:1）。 */
  --pet-title-on-tint: #b24800; /* light: 5.05:1 on --pet-soft #fff4e2 (was #C65000, 4.24:1) */
  --pet-steps-on-tint: #a35300; /* light-only fix: 5.08:1 on --pet-soft #fff4e2 (was var(--pet) #f57c00, 2.48:1) */
  /* #2836: `#/evac/status` の合計カード「同行ペット数」（app.js、28px/900 の large text、
     `.card` = `var(--card)` #FFFFFF 直上）は `var(--pet)` #F57C00 を直載せしており
     light 2.70:1（large text 閾値 3:1 未達、dark は 5.79:1 で既に AA）。dark は既存の
     --pet がそのまま通るため light-only の scoped token にする（--pet 自体は変更しない）。 */
  --pet-total-on-card: #E65100; /* light-only fix: 3.79:1 on --card #ffffff (was var(--pet) #f57c00, 2.70:1) */
  --purple: #7B1FA2;
  --purple-soft: #F5E9F8;
  /* #2799: `#/evac/register` 冒頭の帯（app.js:3539）は半透明の背景
     `rgba(92,107,192,0.08)` の上に `#3949AB` を直載せしており、実際の祖先に合成すると
     light `#e2f0f3` 上 6.65:1（既に AA 達成のため据え置き）・dark `#132029` 上 2.13:1 で
     AA 未達。PM 裁決（Q1=4-B）により background/border-color は変更せず、文字色だけを
     この要素専用のスコープトークンにする（呼び出し元は app.js 内でこの1箇所のみ）。
     dark は Material Indigo 200 相当 #9FA8DA（7.18:1）へ。 */
  --indigo-title-on-tint: #3949AB; /* light: 6.65:1 on 実効合成背景 #e2f0f3（据え置き、既に AA 達成） */

  /* surfaces */
  --bg: #eefcf7;
  --bg-deep: #e2f5ee;
  --card: #FFFFFF;
  --line: #dbeee9;
  --line-soft: #eaf6f1;

  /* type scale (mobile, elderly-friendly) — --fs-scale で文字サイズ設定を実効化 */
  --fs-scale: 1;
  --fs-display: calc(26px * var(--fs-scale));
  --fs-h1: calc(21px * var(--fs-scale));
  --fs-h2: calc(18px * var(--fs-scale));
  --fs-h3: calc(16px * var(--fs-scale));
  --fs-body: calc(15px * var(--fs-scale));
  --fs-sub: calc(13.5px * var(--fs-scale));
  --fs-meta: calc(12px * var(--fs-scale));
  --fs-micro: calc(11px * var(--fs-scale));

  /* spacing */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;

  /* radius — fresh: 結構卡20(--r-lg)/内嵌・入力14(--r-md)/pill999 不変; --r-sm は 14 に整列 */
  --r-sm: 14px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-pill: 999px;

  /* elevation — fresh: teal tinted shadow */
  --sh-1: 0 1px 2px rgba(20, 59, 58, 0.06), 0 1px 3px rgba(20, 59, 58, 0.05);
  --sh-2: 0 12px 30px rgba(18, 179, 166, 0.14);
  --sh-3: 0 20px 60px rgba(18, 120, 110, 0.16);
  --sh-appbar: 0 6px 18px rgba(20, 59, 58, 0.18);

  /* safe areas */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --tabbar-h: 62px;
}

* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
/* [hidden] must win over component display rules (.sheet-host/.netbar set display:flex);
   without this the empty sheet-host overlay (inset:0, z-index:150) eats every click. */
[hidden] { display: none !important; }

html, body {
  height: 100%;
  background: var(--bg-deep);
}

body {
  font-family: 'Segoe UI Rounded', 'Baloo 2', 'Noto Sans JP', -apple-system, BlinkMacSystemFont, 'Hiragino Kaku Gothic ProN', sans-serif;
  color: var(--ink);
  font-size: var(--fs-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overscroll-behavior-y: none;
}

/* #2255: UA default button color (ButtonText, effectively black) does not follow the
   normal CSS inheritance chain, so any button-descendant text/icon with no explicit
   color rule of its own renders black regardless of theme — invisible on dark
   surfaces (measured 1.08–1.38:1 across 5 icon sites; harmless-looking on light
   surfaces only because black-on-white already passes AA by accident). `color:
   inherit` restores the normal inheritance so buttons pick up the surrounding
   `--ink` like every non-button element already does. Class-level fix chosen over
   patching each icon class individually — see #2255 for the button-class audit
   (.btn/.btn-line/.card/.qa/.check/.opt-radio/.fchip/.segbar__item/.chattabs
   button/.chatbar button/.stepper button all already set their own explicit
   `color`, and every unstyled-color background involved is a theme `var(--*)`
   token, so this reset cannot fight an explicit color rule (lower specificity)
   and cannot land on a background that assumes UA-default black). Also corrects
   previously-unreported plain-text instances of the same defect (e.g. bare
   `.card__title` inside `<button class="card">`, such as the home screen's
   "本日の状況" card). */
button { font-family: inherit; cursor: pointer; color: inherit; }
a { color: inherit; text-decoration: none; }

/* ---------- App shell ---------- */
.app {
  position: relative;
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  overflow: hidden;
  box-shadow: 0 0 50px rgba(20, 59, 58, 0.12);
}

/* network strip */
.netbar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  background: #37474F;
  color: #fff;
  font-size: var(--fs-meta);
  font-weight: 700;
  padding: 6px 12px;
  padding-top: calc(6px + var(--safe-top));
  z-index: 60;
}
.netbar__dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #FFB300;
  box-shadow: 0 0 0 0 rgba(255, 179, 0, 0.6);
  animation: ping 1.6s infinite;
}
@keyframes ping { to { box-shadow: 0 0 0 8px rgba(255, 179, 0, 0); } }

/* global emergency status strip (§6.1 発災中に常時表示する赤帯) */
.emergency-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  background: linear-gradient(135deg, var(--danger-deep), var(--danger));
  color: #fff;
  font-size: var(--fs-meta);
  font-weight: 800;
  padding: 6px 12px;
  padding-top: calc(6px + var(--safe-top));
  z-index: 61;
  animation: bannerPulse 2.4s ease-in-out infinite;
}
.emergency-banner__ico { animation: shake 2.4s ease-in-out infinite; }

/* ---------- App bar ---------- */
.appbar {
  position: relative;
  flex-shrink: 0;
  color: #fff;
  padding: calc(var(--safe-top) + 14px) var(--sp-4) 16px;
  /* #1584 fresh: 白字載体 carrier gradient — 両 stop 白字 AA 実算(4.95:1 / 5.75:1); hardcoded so
     dark-mode --primary(#3ad6c6, tuned as ink not as a white-text surface) never leaks in here. */
  background: linear-gradient(135deg, #0a7e72, #1565c0);
  box-shadow: var(--sh-appbar);
  z-index: 40;
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}
/* when netbar/emergency-banner visible the safe-top is already consumed by them */
.app.is-offline .appbar, .app.is-emergency .appbar { padding-top: 14px; }

.appbar--danger { background: linear-gradient(135deg, var(--danger-deep), var(--danger)); }
.appbar--teal { background: linear-gradient(135deg, #00695C, var(--teal)); }
.appbar--ink { background: linear-gradient(135deg, #15233A, #243a5e); }
.appbar--purple { background: linear-gradient(135deg, #6A1B9A, var(--purple)); }
.appbar--warn { background: linear-gradient(135deg, #E65100, var(--warn)); }
.appbar--safe { background: linear-gradient(135deg, #1B5E20, var(--safe)); }

.appbar__top { display: flex; align-items: center; gap: var(--sp-2); }
.appbar__back {
  width: 44px; height: 44px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  margin-left: -11px;
  border: none; background: rgba(255, 255, 255, 0.16);
  color: #fff; border-radius: 50%; font-size: 22px; line-height: 1;
  transition: transform 0.12s, background 0.2s;
}
.appbar__back:active { transform: scale(0.9); background: rgba(255, 255, 255, 0.28); }
.appbar__titles { flex: 1; min-width: 0; }
.appbar__eyebrow { font-size: var(--fs-micro); font-weight: 700; opacity: 0.85; letter-spacing: 0.04em; }
.appbar__title {
  /* #2111 (div -> h1 for page-has-heading-one): defensive only. The global `* { margin: 0 }`
     reset at the top of this file ALREADY neutralises the <h1> UA default — an author rule
     beats the UA stylesheet regardless of specificity — so the swap was margin-identical
     before this line existed (independent CR measurement: identical rect/computed style for
     h1 vs div, both variants). Kept so the swap stays inert if that global reset is ever
     narrowed; do not read it as the thing that made the swap safe. */
  margin: 0;
  font-size: var(--fs-h1); font-weight: 900; letter-spacing: 0.01em;
  display: flex; align-items: center; gap: 8px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.appbar__title.is-small { font-size: var(--fs-h3); }
.appbar__sub { font-size: var(--fs-meta); opacity: 0.9; margin-top: 2px; }

.muni-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: rgba(255, 255, 255, 0.2);
  border-left: none; border-right: none; color: #fff;
  border-radius: var(--r-pill);
  padding: 4px 12px;
  /* #3414: 実寸 44px。上下の透明 border を box に含め、背景は padding-box だけに塗って見た目の丸薬は従来のまま。 */
  box-sizing: border-box; min-height: 44px;
  border-top: 9.5px solid transparent; border-bottom: 9.5px solid transparent;
  background-clip: padding-box;
  margin-top: -2.5px; margin-bottom: -9.5px;
  position: relative;
  font-size: var(--fs-meta); font-weight: 700;
  transition: background 0.2s;
}
.muni-chip:active { background-color: rgba(255, 255, 255, 0.34); }
@media (forced-colors: active) { .muni-chip { border-top-color: Canvas; border-bottom-color: Canvas; } }

.bell {
  position: relative; flex-shrink: 0;
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.16); border: none;
  border-radius: 50%; font-size: 19px;
  transition: transform 0.12s;
}
.bell:active { transform: scale(0.9); }
.bell__count {
  position: absolute; top: -2px; right: 0;
  min-width: 18px; height: 18px; padding: 0 4px;
  background: #FFC400; color: #1a1a1a;
  font-size: 10px; font-weight: 900; line-height: 18px; text-align: center;
  border-radius: var(--r-pill);
  border: 2px solid var(--primary);
}
.appbar--danger .bell__count { border-color: var(--danger); }

.appbar__actions { display: flex; align-items: center; gap: 6px; }
.appbar__icon-btn {
  width: 44px; height: 44px; border: none; border-radius: 50%;
  background: rgba(255, 255, 255, 0.16); color: #fff; font-size: 18px;
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.12s;
}
.appbar__icon-btn:active { transform: scale(0.9) rotate(40deg); }

/* sub-tabs inside an appbar context (segmented) */
.segbar {
  flex-shrink: 0;
  display: flex; background: var(--card);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 20;
}
.segbar__item {
  flex: 1; text-align: center; padding: 13px 6px;
  font-size: var(--fs-sub); font-weight: 700; color: var(--ink-3);
  background: none; border: none; border-bottom: 2.5px solid transparent;
  transition: color 0.2s, border-color 0.2s;
}
.segbar__item.is-active { color: var(--primary); border-bottom-color: var(--primary); }

/* filter chip rail */
.chiprail {
  flex-shrink: 0;
  display: flex; gap: var(--sp-2); overflow-x: auto;
  padding: 10px var(--sp-4); background: var(--card);
  border-bottom: 1px solid var(--line);
  scrollbar-width: none;
}
.chiprail::-webkit-scrollbar { display: none; }
.fchip {
  flex-shrink: 0;
  padding: 7px 14px; border-radius: var(--r-pill);
  background: var(--bg-deep); color: var(--ink-2);
  font-size: var(--fs-meta); font-weight: 700; border: none;
  min-height: 44px; /* #3129: タップ領域 44px */
  transition: background 0.18s, color 0.18s, transform 0.1s;
}
.fchip:active { transform: scale(0.95); }
.fchip.is-active { background: var(--primary); color: #fff; }

/* ---------- Screen body ---------- */
.screen {
  flex: 1; min-height: 0;
  overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;
  padding-bottom: calc(var(--tabbar-h) + var(--safe-bottom) + 14px);
}
.screen::-webkit-scrollbar { width: 0; }
.sec { padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); }
.sec--flush { padding-top: var(--sp-3); }

/* page-load stagger */
.stagger > * { opacity: 0; transform: translateY(10px); animation: rise 0.42s cubic-bezier(0.22, 1, 0.36, 1) forwards; }
.stagger > *:nth-child(1) { animation-delay: 0.02s; }
.stagger > *:nth-child(2) { animation-delay: 0.06s; }
.stagger > *:nth-child(3) { animation-delay: 0.10s; }
.stagger > *:nth-child(4) { animation-delay: 0.14s; }
.stagger > *:nth-child(5) { animation-delay: 0.18s; }
.stagger > *:nth-child(6) { animation-delay: 0.22s; }
.stagger > *:nth-child(7) { animation-delay: 0.26s; }
.stagger > *:nth-child(8) { animation-delay: 0.30s; }
.stagger > *:nth-child(n+9) { animation-delay: 0.34s; }
@keyframes rise { to { opacity: 1; transform: none; } }
/* #3129（未検証: 実クリックでの再現は Orchestrator）: 直下のボタンは transform を動かさず opacity だけで入場させる（入場中に当たり判定が 10px ずれない）。 */
.stagger > .btn, .stagger > .btn-line { transform: none; animation-name: riseFade; }
@keyframes riseFade { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .stagger > * { animation: none; opacity: 1; transform: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
/* #1851 item(1) / #2034: `.alert-banner`(:479) は自前の `animation: bannerPulse` を同一詳細度・
   後方で宣言するため `.stagger > *` の `animation: rise` を置換する。`bannerPulse` は box-shadow
   しか動かさず `.alert-banner` は `opacity` を再宣言しないので、`.stagger` 直下に置かれた瞬間
   **恒久 opacity:0** になっていた（`#/home`(発災) / `#/evac/alert` / `#/emergency` の 3 経路。
   `app.js:1042` `:2909`）。実地震データの緊急バナーが不可視になる不具合。
   両アニメを 1 本の shorthand に併記して復旧する。`opacity:1` を足すだけでは `.stagger > *` の
   `transform: translateY(10px)` が残り 10px 下にずれたままになるため不可。
   ・delay: shorthand は animation-delay を 0s に戻す＝`:285` の nth-child stagger delay を捨てる。
     捨てるのは意図的で、緊急バナーは両呼び出し元で常に第 1 子（本来 0.02s）であり、
     発災時の最重要要素を装飾的な順送りの後ろに置かない方が正しい。
   ・#2034: 当初この規則を `@media (prefers-reduced-motion: no-preference)` に包んでいたが、
     この media feature を実装しない UA では `no-preference` も `reduce`（:295）もどちらも
     match しない（未対応 media feature を使うクエリは非 match 扱い）。両方非 match だと
     包んだ本規則は丸ごと無効化され、`.alert-banner` は `.stagger > *` の `animation: rise` と
     後方 `.alert-banner{animation:bannerPulse}`（:479）の source-order 衝突に戻り、修正前と
     同じ恒久 opacity:0 が再発する（実測: 当該 media feature 非対応 UA を模すと、包装のままは
     opacity 0、無包装は opacity 1）。よって無包装（media query に依存しない形）にする。
     reduce-motion 環境でのモーション抑制は `:297-299` の
     `*,*::before,*::after { animation-duration:0.01ms !important; animation-iteration-count:1 !important }`
     （グローバル !important）が担っており、本規則の specificity（`.stagger > .alert-banner` は
     2 class で `:296` の reduce 側 `.stagger > *` より高い）で上書きしても、実際のモーションは
     同じ !important リセットで抑制される（実測: reduce エミュレーションでも computed opacity
     は 1、通常 UA でも opacity は 1）。 */
.stagger > .alert-banner {
  animation: rise 0.42s cubic-bezier(0.22, 1, 0.36, 1) forwards,
             bannerPulse 2.4s ease-in-out infinite;
}

/* screen transition */
.screen.is-entering { animation: screenIn 0.26s ease; }
@keyframes screenIn { from { opacity: 0; transform: translateX(8px); } to { opacity: 1; transform: none; } }

/* ---------- Cards ---------- */
.card {
  background: var(--card);
  border-radius: var(--r-md);
  padding: var(--sp-4);
  box-shadow: var(--sh-1);
  border: 1px solid var(--line);
}
.card--tap { transition: transform 0.15s, box-shadow 0.2s; }
.card--tap:active { transform: scale(0.985); box-shadow: var(--sh-2); }
@media (hover: hover) {
  .card--tap:hover { transform: translateY(-4px); box-shadow: var(--sh-2); }
}
.card--flat { box-shadow: none; }
/* #3311: #/info の出典カード（気象庁の出典・津波の注記）。旧実装は inline の #FAFBFD で dark でも白いまま、
   文字だけ --ink 系で明色になり対比が崩れていた。light は同値 #FAFBFD を維持し、dark は --card に追従。 */
.card--src { background: #FAFBFD; }
:root[data-theme="dark"] .card--src { background: var(--card); }
/* #3319: #/info/quake の行動指針カード（地震・津波）・#/info/epidemic のリスクカード・
   在宅避難ダッシュボードの dangerCard。旧実装は inline の淡色背景（#FFFDE7 / #FCE4EC / #FFEBEE）で
   dark でも明るいまま、文字だけ --ink 系で明色になり対比が崩れていた（--ink / #FFFDE7 = 1.09:1）。
   light の背景・枠は従来値を維持。dark は既存の tint token（--warn-soft / --danger-soft）に追従し、
   新しい色 token は作らない。light の題字のうち AA 未達だった 2 つ（#F57F17 2.58:1・--danger 4.36:1）は
   既存 token へ寄せる。感染症の題字 #AD1457 は AA 済みなので light は据え置き。 */
.card--guide { background: #FFFDE7; border: 1.5px solid #FBC02D; }
.card--guide .card__title { color: var(--warn-title-on-tint); }
.card--risk { background: #FCE4EC; border: 1.5px solid #C2185B; }
.card--risk .card__title { color: #AD1457; }
.card--danger-home { background: #FFEBEE; border: 1.5px solid var(--danger); }
.card--danger-home .card__title { color: var(--danger-deep); }
:root[data-theme="dark"] .card--guide { background: var(--warn-soft); border-color: rgba(239, 108, 0, 0.25); }
:root[data-theme="dark"] .card--risk,
:root[data-theme="dark"] .card--danger-home { background: var(--danger-soft); border-color: rgba(211, 47, 47, 0.25); }
:root[data-theme="dark"] .card--risk .card__title,
:root[data-theme="dark"] .card--danger-home .card__title { color: var(--danger-on-warn-tint); }
/* #3329: #/home-evacuation/dashboard の安否確認カード。旧実装は inline の #E8F5E9 / var(--safe) で dark でも淡緑のまま
   （題字 --safe #2E7D32 が dark で 2.45:1 未満）。light は同値 #E8F5E9 / --safe を維持し、dark は --safe-soft / --safe-title-on-tint に追従。 */
.card--safe-ok { background: #E8F5E9; }
.card--safe-ok .card__title { color: var(--safe); }
:root[data-theme="dark"] .card--safe-ok { background: var(--safe-soft); }
:root[data-theme="dark"] .card--safe-ok .card__title { color: var(--safe-title-on-tint); }
.card__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.card__title { font-size: var(--fs-h3); font-weight: 900; display: flex; align-items: center; gap: 7px; }
.card__more {
  font-size: var(--fs-meta); font-weight: 700; color: var(--primary); background: none; border: none;
  /* #3414: 実寸 44px。見出し行の高さは変えない（上下の負 margin で吸収） */
  display: inline-flex; align-items: center; justify-content: flex-end;
  min-width: 44px; min-height: 44px; margin: -14px -4px -14px 0; padding: 0 4px;
}

.accent-l { border-left: 4px solid var(--primary); }
.accent-l.danger { border-left-color: var(--danger); }
.accent-l.warn { border-left-color: var(--warn); }
.accent-l.safe { border-left-color: var(--safe); }
.accent-l.info { border-left-color: var(--info); }
.accent-l.purple { border-left-color: var(--purple); }
.accent-l.pet { border-left-color: var(--pet); }

/* tinted cards */
.tint { border: 1.5px solid transparent; }
.tint-danger { background: var(--danger-soft); border-color: rgba(211, 47, 47, 0.25); }
.tint-warn { background: var(--warn-soft); border-color: rgba(239, 108, 0, 0.25); }
.tint-safe { background: var(--safe-soft); border-color: rgba(46, 125, 50, 0.25); }
.tint-info { background: var(--info-soft); border-color: rgba(2, 119, 189, 0.22); }
.tint-pet { background: var(--pet-soft); border-color: rgba(245, 124, 0, 0.28); }
.tint-purple { background: var(--purple-soft); border-color: rgba(123, 31, 162, 0.22); }
.tint-primary { background: var(--primary-soft); border-color: rgba(10, 126, 114, 0.22); }

/* section label */
.sec-label {
  font-size: var(--fs-meta); font-weight: 800; color: var(--ink-3);
  letter-spacing: 0.04em; padding: 2px 2px 0; margin-top: 2px;
}

/* ---------- Typography helpers ---------- */
.t-meta { font-size: var(--fs-meta); color: var(--ink-3); }
.t-sub { font-size: var(--fs-sub); color: var(--ink-2); }
.t-strong { font-weight: 900; }
.muted { color: var(--ink-3); }
.lh { line-height: 1.75; }

/* ---------- Badges ---------- */
.badge {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 3px 9px; border-radius: var(--r-pill);
  font-size: var(--fs-micro); font-weight: 800; white-space: nowrap;
}
.b-safe { background: var(--safe-soft); color: #1B5E20; }
/* #2601: #C65000 は light の -soft 底で 4.24:1 と AA 未達（dark は下の .b-warn/.b-pet
   override で明色に差し替え済み）。--pet-title-on-tint と同じ #b24800 に寄せ 5.05:1 へ。 */
.b-warn { background: var(--warn-soft); color: #b24800; }
.b-danger { background: var(--danger-soft); color: #B3261E; }
.b-info { background: var(--info-soft); color: #01579B; }
.b-pet { background: var(--pet-soft); color: #b24800; }
.b-purple { background: var(--purple-soft); color: #6A1B9A; }
.b-gray { background: var(--bg-deep); color: var(--ink-2); }
.b-teal { background: var(--teal-soft); color: #00695C; }
.b-solid { background: var(--primary); color: #fff; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; padding: 14px 16px; border: none; border-radius: var(--r-pill);
  color: #fff; font-size: var(--fs-h3); font-weight: 800; line-height: 1.2;
  box-shadow: var(--sh-1); transition: transform 0.15s, box-shadow 0.2s, filter 0.2s;
}
.btn:active { transform: translateY(2px) scale(0.96); filter: brightness(0.96); }
.btn-p { background: linear-gradient(135deg, #0a7e72, #1565c0); }
.btn-d { background: linear-gradient(135deg, var(--danger-deep), var(--danger)); }
.btn-s { background: linear-gradient(135deg, #1B5E20, var(--safe)); }
.btn-o { background: linear-gradient(135deg, #E65100, var(--warn)); }
.btn-pet { background: linear-gradient(135deg, #E65100, var(--pet)); }
.btn-purple { background: linear-gradient(135deg, #6A1B9A, var(--purple)); }
.btn-teal { background: linear-gradient(135deg, #00695C, var(--teal)); }
.btn-sm { padding: 9px 14px; min-height: 44px; font-size: var(--fs-sub); border-radius: var(--r-pill); }

.btn-line {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; padding: 12px 16px; min-height: 44px; border-radius: var(--r-pill);
  background: var(--card); border: 1.5px solid var(--line);
  color: var(--ink); font-size: var(--fs-sub); font-weight: 800;
  transition: transform 0.15s, border-color 0.2s, background 0.2s;
}
.btn-line:active { transform: scale(0.99); background: var(--line-soft); }
.btn-line.is-primary { color: var(--primary); border-color: rgba(10, 126, 114, 0.4); }

/* ---------- Lists / rows ---------- */
.row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 12px 0; border-bottom: 1px solid var(--line-soft);
}
.row:last-child { border-bottom: none; }
.row__body { flex: 1; min-width: 0; }
.row__title { font-size: var(--fs-sub); font-weight: 700; }
.row__meta { font-size: var(--fs-meta); color: var(--ink-3); margin-top: 2px; }

/* icon chip */
.ichip {
  width: 42px; height: 42px; flex-shrink: 0; border-radius: 12px;
  display: flex; align-items: center; justify-content: center; font-size: 22px;
  background: var(--primary-soft);
}
.ichip--sm { width: 34px; height: 34px; font-size: 18px; border-radius: 10px; }
.ichip.t-danger { background: var(--danger-soft); }
.ichip.t-warn { background: var(--warn-soft); }
.ichip.t-safe { background: var(--safe-soft); }
.ichip.t-info { background: var(--info-soft); }
.ichip.t-pet { background: var(--pet-soft); }
.ichip.t-purple { background: var(--purple-soft); }
.ichip.t-teal { background: var(--teal-soft); }

/* key-value grid */
.kv { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 14px; }
.kv > div { font-size: var(--fs-sub); }
.kv b { font-weight: 800; }

/* ---------- Quick actions grid ---------- */
.qa-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); }
.qa {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 14px 6px 12px; text-align: center;
  box-shadow: var(--sh-1); transition: transform 0.12s, box-shadow 0.2s;
}
.qa:active { transform: scale(0.95); box-shadow: var(--sh-2); }
.qa__ico {
  width: 46px; height: 46px; margin: 0 auto 7px; border-radius: 14px;
  display: flex; align-items: center; justify-content: center; font-size: 24px;
  background: var(--primary-soft);
}
.qa__label { font-size: var(--fs-meta); font-weight: 700; color: var(--ink); }

/* ---------- Progress ---------- */
.progress { height: 8px; background: var(--bg-deep); border-radius: var(--r-pill); overflow: hidden; }
.progress__fill { height: 100%; border-radius: var(--r-pill); background: linear-gradient(90deg, var(--safe), #66BB6A); transition: width 0.6s ease; }
.progress__fill.warn { background: linear-gradient(90deg, var(--warn), #FFB74D); }

/* ---------- Banners ---------- */
.alert-banner {
  display: flex; align-items: center; gap: 10px;
  background: linear-gradient(135deg, var(--danger-deep), var(--danger));
  color: #fff; padding: 14px 16px; border-radius: var(--r-md);
  font-weight: 800; box-shadow: 0 8px 20px rgba(183, 28, 28, 0.3);
  animation: bannerPulse 2.4s ease-in-out infinite;
}
.alert-banner__ico { font-size: 22px; animation: shake 2.4s ease-in-out infinite; }
@keyframes bannerPulse { 0%, 100% { box-shadow: 0 8px 20px rgba(183, 28, 28, 0.3); } 50% { box-shadow: 0 8px 28px rgba(183, 28, 28, 0.5); } }
@keyframes shake { 0%, 92%, 100% { transform: rotate(0); } 94% { transform: rotate(-12deg); } 96% { transform: rotate(12deg); } 98% { transform: rotate(-8deg); } }

.info-strip {
  display: flex; gap: 8px; align-items: flex-start;
  background: var(--primary-soft); color: var(--ink);
  border: 1px solid rgba(10, 126, 114, 0.18);
  padding: 11px 13px; border-radius: var(--r-sm);
  font-size: var(--fs-meta); line-height: 1.65; font-weight: 500;
}
.info-strip.teal { background: var(--teal-soft); color: #00564B; border-color: rgba(0, 137, 123, 0.2); }
.info-strip.safe { background: var(--safe-soft); color: #1B5E20; border-color: rgba(46, 125, 50, 0.2); }
/* #2805: 14箇所（app.js、`git grep -c 'class="info-strip warn"'` で再確認済み）が
   共有するクラス定義。light の color を既存の --warn-title-on-tint（#2805 S3 §4）へ
   一本化する — 14箇所全ての背景が同一 --warn-soft であることを実測3件+コード確認11件
   で確定済み（S3 consult §1・§2）なので、一律の改善になる。background/border-color は
   変更しない。dark 側の専用上書き（app.css 内 `.info-strip.warn` dark ブロック）は
   既に同じ値を返しているため据え置く（PM 確認事項2、変更なし）。 */
.info-strip.warn { background: var(--warn-soft); color: var(--warn-title-on-tint); border-color: rgba(239, 108, 0, 0.22); }
.info-strip.purple { background: var(--purple-soft); color: #6A1B9A; border-color: rgba(123, 31, 162, 0.2); }
.info-strip .btn-line { width: auto; }

/* hero weather */
.weather {
  color: #fff; border: none;
  background: linear-gradient(135deg, #0a7e72, #1565c0);
  border-radius: var(--r-md); padding: var(--sp-4); box-shadow: var(--sh-2);
}
.weather__row { display: flex; justify-content: space-between; align-items: flex-start; }
.weather__big { font-size: 30px; font-weight: 900; line-height: 1.1; }
.weather__temp { font-size: 34px; font-weight: 900; }
.weather__forecast {
  display: flex; justify-content: space-around; margin-top: 12px;
  background: rgba(255, 255, 255, 0.16); border-radius: var(--r-sm); padding: 10px 4px;
}
.weather__day { text-align: center; font-size: 11px; line-height: 1.7; }
.weather__day .e { font-size: 19px; }

/* level meter (epidemic) */
/* #2683: 背景を `#fff` ハードコードから `var(--card)` へ（light は同値 #FFFFFF、dark は
   #14262a）。off セルの `--ink-3` は dark で白背景の上 2.59:1 と AA 未達だった — 背景を
   テーマ追従させて 6.06:1 に。on セルは `var(--safe)` 直載せだと dark の `--card` 上で
   3.06:1 に落ちるため、#2600 が作った `--safe-on-card`（light=var(--safe)、dark=#3da642
   5.02:1）へ切り替える。 */
.levelmeter { display: flex; gap: 4px; background: var(--card); border-radius: var(--r-sm); padding: 10px 8px; }
.levelmeter__cell { flex: 1; text-align: center; font-size: 10px; color: var(--ink-3); }
.levelmeter__cell .n { font-size: 15px; font-weight: 800; display: block; }
.levelmeter__cell.is-on { color: var(--safe-on-card); }
.levelmeter__cell.is-on .n { color: var(--safe-on-card); }

/* map placeholder (offline-safe schematic) */
.map {
  position: relative; height: 200px; border-radius: var(--r-md); overflow: hidden;
  background:
    radial-gradient(circle at 20% 30%, rgba(46, 125, 50, 0.12), transparent 40%),
    radial-gradient(circle at 80% 70%, rgba(21, 101, 192, 0.12), transparent 40%),
    linear-gradient(160deg, #DDEAD9, #CFE0EC);
  border: 1px solid var(--line);
}
.map::before {
  content: ""; position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.5) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.5) 1px, transparent 1px);
  background-size: 28px 28px;
}
.map__road {
  position: absolute; background: rgba(255, 255, 255, 0.85);
}
.map__road.r1 { top: 42%; left: -5%; width: 110%; height: 9px; transform: rotate(-7deg); border-radius: 6px; }
.map__road.r2 { top: 8%; left: 58%; width: 9px; height: 90%; transform: rotate(6deg); border-radius: 6px; }
.map__pin {
  position: absolute; transform: translate(-50%, -100%);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  font-size: 11px; font-weight: 800; color: var(--ink);
}
.map__pin .dot {
  width: 30px; height: 30px; border-radius: 50% 50% 50% 0;
  transform: rotate(45deg); display: flex; align-items: center; justify-content: center;
  background: var(--safe); color: #fff; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25);
  border: 2px solid #fff;
}
.map__pin .dot span { transform: rotate(-45deg); font-size: 15px; }
.map__pin.pet .dot { background: var(--pet); }
.map__pin.store .dot { background: var(--warn); }
.map__pin.me .dot { background: var(--primary); }
.map__badge {
  position: absolute; right: 10px; bottom: 10px;
  background: rgba(255, 255, 255, 0.92); color: var(--ink-2);
  font-size: 10px; font-weight: 700; padding: 4px 9px; border-radius: var(--r-pill);
  box-shadow: var(--sh-1);
}

/* 実地図（Leaflet）グリッドクラスタ バブル（#1539 scope-out item B） */
.map-cluster {
  display: flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--primary); color: #fff;
  font-size: 13px; font-weight: 800; font-family: inherit;
  border: 3px solid #fff;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.35);
}
.map-cluster--lg { width: 46px; height: 46px; font-size: 15px; }
:root[data-theme="dark"] .map-cluster {
  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.65), 0 0 0 1px var(--card);
}

/* #1794: 実地図ポップアップの自治体行＋緯度経度コピーボタン。Leaflet のポップアップ背景
   (.leaflet-popup-content-wrapper) は vendor CSS が `background: white` 固定でダークテーマでも
   白のため、テーマ変数ではなく白地前提の固定色を使う（--ink 系を当てると dark 時に
   白文字が白地へ乗って消える）。
   コントラスト: .popup-place #4d5f5d on #fff = 6.7:1 / .popup-copyll #0f5a52 on #e8f5f2 = 7.2:1
   （いずれも WCAG AA 本文 4.5:1 を満たす）。 */
.popup-place { display: inline-block; margin-top: 4px; font-size: 11px; color: #4d5f5d; }
.popup-copyll {
  margin-top: 6px; padding: 5px 10px;
  font-family: inherit; font-size: 11px; font-weight: 700;
  color: #0f5a52; background: #e8f5f2;
  border: 1px solid #b9dcd6; border-radius: var(--r-pill);
  cursor: pointer;
}

/* notice list */
.notice { padding: 11px 0; border-bottom: 1px solid var(--line-soft); }
.notice:last-child { border-bottom: none; }
.notice__t { font-size: var(--fs-sub); font-weight: 700; }
.notice__m { font-size: var(--fs-micro); color: var(--ink-3); margin-top: 3px; }

/* settings list */
.slist { background: var(--card); border-radius: var(--r-md); overflow: hidden; box-shadow: var(--sh-1); border: 1px solid var(--line); }
.slist__title { font-size: var(--fs-micro); font-weight: 800; color: var(--ink-3); padding: 13px 16px 6px; letter-spacing: 0.04em; }
.sitem { display: flex; align-items: center; gap: 12px; padding: 13px 16px; border-top: 1px solid var(--line-soft); background: none; border-left: none; border-right: none; width: 100%; text-align: left; }
.sitem:first-of-type { border-top: none; }
.sitem__ico { width: 26px; text-align: center; font-size: 18px; }
.sitem__label { flex: 1; font-size: var(--fs-sub); color: var(--ink); }
.sitem__value { font-size: var(--fs-meta); color: var(--ink-3); }
.sitem__chev { color: var(--ink-3); font-size: 19px; }
.on { color: var(--safe); font-weight: 800; }
.off { color: var(--ink-3); font-weight: 800; }

/* checklist row */
.check {
  display: flex; align-items: center; gap: 12px; padding: 11px 0;
  border-bottom: 1px solid var(--line-soft); background: none; border-left: none; border-right: none; border-top: none; width: 100%; text-align: left;
  font-size: var(--fs-sub); color: var(--ink);
}
.check:last-child { border-bottom: none; }
.check__box {
  width: 24px; height: 24px; flex-shrink: 0; border-radius: 7px;
  border: 2px solid var(--line); display: flex; align-items: center; justify-content: center;
  font-size: 13px; color: transparent; transition: background 0.18s, border-color 0.18s, color 0.18s;
}
.check.is-on .check__box { background: var(--safe); border-color: var(--safe); color: #fff; }
.check__label { flex: 1; }
.check.is-on .check__label { color: var(--ink-2); }
/* #3521: 「自分の項目」の 1 行 = チェック（.check をそのまま使う）＋ 削除ボタン。.check 自体は変えない */
.check-row { display: flex; align-items: center; gap: 4px; border-bottom: 1px solid var(--line-soft); }
.check-row .check { flex: 1; min-width: 0; border-bottom: none; }
.check-row .check__label { overflow-wrap: anywhere; }
.check-row__del { flex-shrink: 0; width: 44px; min-height: 44px; background: none; border: none; color: var(--ink-2); font-size: var(--fs-sub); }
.ck-err { color: var(--danger); }
/* dark の --card #14262a 上で --danger #D32F2F は 3.15:1（AA 未達）。#ff8a80 は 6.86:1 */
:root[data-theme="dark"] .ck-err { color: #ff8a80; }

/* pet card */
.petcard {
  display: flex; align-items: center; gap: 12px;
  background: linear-gradient(135deg, #FFF6E6, #FFE9CC);
  border: 1.5px solid rgba(245, 124, 0, 0.4);
  border-radius: var(--r-md); padding: 12px;
}
.petcard__av {
  width: 50px; height: 50px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; font-size: 26px;
  background: linear-gradient(135deg, #FFD166, #FF8F00);
}
/* #2810: .petcard の背景は固定の淡色グラデーション(#FFF6E6→#FFE9CC)でテーマに
   追従しない。文字色だけが --ink/--ink-2 経由でテーマに追従すると、dark では
   ほぼ白の文字がほぼ白い背景に乗ってしまう(#1794 の .popup-place と同型の欠陥)。
   そのため文字色もテーマに依らない固定値にする(#1794 と同じ作法)。
   コントラスト(両テーマとも同一、グラデーションの両 stop に対して):
     name 11.41:1 / 10.36:1、meta 5.09:1 / 4.62:1 (是正前の dark: name 1.04:1 / 1.06:1、
     meta 1.63:1 / 1.48:1)。--ink/--ink-2 の値自体は変えない。 */
.petcard__name { font-size: var(--fs-sub); font-weight: 800; color: #143b3a; }
.petcard__meta { font-size: var(--fs-meta); color: #4d706c; margin-top: 1px; }
/* #2822: `#/me/pets` の「編集」affordance（app.js、`.petcard` 内、旧
   `style="color:var(--pet);font-weight:700"`）も #2810 と同じ理由で固定リテラルが
   必要 — `.petcard` の背景は固定の淡色グラデーション(#FFF6E6→#FFE9CC)でテーマに
   追従しないが、`var(--pet)` #F57C00 は light/dark とも同じ値のため、両テーマで
   同一の低いコントラストのまま(2.52:1 / 2.29:1、15px bold は AA large text の閾値
   ≥18.66px bold に届かないため 4.5:1 判定)。#143b3a/#4d706c と同様、この背景専用の
   固定色にする(`--pet` 自体の値は変えない)。
   コントラスト(両テーマとも同一、グラデーションの両 stop に対して):
     7.12:1 / 6.47:1 (是正前: 2.52:1 / 2.29:1、両テーマとも AA 未達)。 */
.petcard__edit { color: #8a3d00; font-weight: 700; }

/* avatar */
.avatar {
  width: 42px; height: 42px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 800; color: #fff;
  background: linear-gradient(135deg, #0a7e72, #1565c0);
}

/* shelter list card */
.shelter { display: flex; flex-direction: column; gap: 8px; }
.shelter__top { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
.shelter__top > .badge { flex-shrink: 0; max-width: 50%; white-space: normal; text-align: center; border-radius: 12px; }
.shelter__name { font-size: var(--fs-h3); font-weight: 800; }
.shelter__meta { font-size: var(--fs-meta); color: var(--ink-3); margin-top: 2px; }
.shelter__tags { display: flex; flex-wrap: wrap; gap: 5px; }
.occ { display: flex; align-items: center; gap: 8px; }
.occ__bar { flex: 1; }

/* ---------- States: skeleton / empty / error ---------- */
.skeleton { padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); }
.sk {
  border-radius: var(--r-md);
  background: linear-gradient(100deg, #e3f0ea 30%, #f4faf7 50%, #e3f0ea 70%);
  background-size: 200% 100%; animation: shimmer 1.3s infinite linear;
}
.sk.card { height: 96px; box-shadow: none; border: none; padding: 0; }
.sk.line { height: 14px; }
.sk.line.w60 { width: 60%; } .sk.line.w40 { width: 40%; } .sk.line.w80 { width: 80%; }
.sk.tall { height: 150px; }
@keyframes shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .sk { animation: none; } }

.placeholder { text-align: center; padding: 48px 28px; color: var(--ink-3); }
.placeholder__ico {
  width: 78px; height: 78px; margin: 0 auto 16px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: 38px;
  background: var(--card); box-shadow: var(--sh-1);
}
.placeholder__title { font-size: var(--fs-h3); font-weight: 800; color: var(--ink-2); }
.placeholder__text { font-size: var(--fs-sub); margin-top: 6px; line-height: 1.7; }
.placeholder .btn-line { width: auto; margin: 18px auto 0; padding: 10px 22px; }

/* ---------- Bottom tab bar ---------- */
.tabbar {
  flex-shrink: 0; position: relative; z-index: 50;
  display: flex; background: rgba(255, 255, 255, 0.96);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-top: 1px solid var(--line);
  padding-bottom: var(--safe-bottom);
  box-shadow: 0 -4px 20px rgba(20, 59, 58, 0.06);
}
.tab {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  padding: 9px 0 7px; background: none; border: none;
  color: var(--ink-3); font-size: 10.5px; font-weight: 700;
  position: relative; transition: color 0.2s;
}
.tab__ico { font-size: 21px; line-height: 1; transition: transform 0.2s; }
.tab__badge {
  position: absolute; top: 5px; left: 56%;
  min-width: 16px; height: 16px; padding: 0 4px;
  background: var(--danger); color: #fff; font-size: 9px; font-weight: 900;
  line-height: 16px; text-align: center; border-radius: var(--r-pill); border: 1.5px solid #fff;
}
.tab.is-active { color: var(--primary); }
.tab.is-active .tab__ico { transform: translateY(-2px) scale(1.06); }
.tab.is-active::before {
  content: ""; position: absolute; top: 0; width: 28px; height: 3px;
  background: var(--primary); border-radius: 0 0 4px 4px;
}
.app.is-emergency .tab.is-active { color: var(--danger-tabbar-active); }
.app.is-emergency .tab.is-active::before { background: var(--danger); }

/* ---------- Toast ---------- */
.toast {
  position: fixed; left: 50%; bottom: calc(var(--tabbar-h) + var(--safe-bottom) + 18px);
  transform: translateX(-50%) translateY(12px);
  background: rgba(10, 30, 28, 0.94); color: #fff;
  padding: 12px 18px; border-radius: var(--r-pill);
  font-size: var(--fs-sub); font-weight: 700; max-width: 86%;
  box-shadow: var(--sh-3); z-index: 200; opacity: 0;
  transition: opacity 0.24s, transform 0.24s;
  pointer-events: none;
}
.toast.is-show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ---------- reCAPTCHA host (#1925 slice 2 / Security COND-29) ----------
   #screen の外に置く必要がある（authBusy() → render() が #screen の innerHTML を
   丸ごと差し替えるため、中に置くと requestOtp の直前にコンテナごと消える）。
   既定は hidden 属性で非表示。auth-flow.js が認証画面 mount 時だけ表示する。 */
.recaptcha-host {
  display: flex;
  justify-content: center;
  padding: 10px 14px;
  background: var(--bg);
}
.recaptcha-host[hidden] { display: none; }

/* ---------- Bottom sheet ---------- */
.sheet-host {
  position: fixed; inset: 0; z-index: 150;
  display: flex; align-items: flex-end; justify-content: center;
}
.sheet-host__bg { position: absolute; inset: 0; background: rgba(20, 59, 58, 0.5); animation: fade 0.2s; }
.sheet {
  position: relative; width: 100%; max-width: 480px;
  background: var(--card); border-radius: var(--r-lg) var(--r-lg) 0 0;
  padding: 8px var(--sp-4) calc(var(--sp-4) + var(--safe-bottom));
  max-height: 82vh; overflow-y: auto;
  animation: sheetUp 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes sheetUp { from { transform: translateY(100%); } to { transform: none; } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.sheet__handle { width: 42px; height: 4px; background: var(--line); border-radius: var(--r-pill); margin: 6px auto 14px; }
.sheet__title { display: flex; justify-content: space-between; align-items: center; font-size: var(--fs-h3); font-weight: 900; margin-bottom: 12px; }
.sheet__close { background: var(--bg-deep); border: none; width: 30px; height: 30px; border-radius: 50%; font-size: 16px; color: var(--ink-2); }
.sheet-item {
  display: flex; align-items: center; gap: 12px;
  background: var(--line-soft); border: 1.5px solid transparent;
  border-radius: var(--r-sm); padding: 12px; margin-bottom: 7px; width: 100%; text-align: left;
}
.sheet-item.is-active { background: var(--primary-soft); border-color: var(--primary); }
.sheet-item__radio { width: 20px; height: 20px; border-radius: 50%; border: 2px solid var(--line); flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.sheet-item.is-active .sheet-item__radio { border-color: var(--primary); }
.sheet-item.is-active .sheet-item__radio::after { content: ""; width: 10px; height: 10px; border-radius: 50%; background: var(--primary); }
.sheet-sec { font-size: var(--fs-micro); font-weight: 800; color: var(--ink-3); margin: 12px 2px 7px; }

/* segmented toggle (demo controls) */
.seg { display: flex; background: var(--bg-deep); border-radius: var(--r-pill); padding: 4px; gap: 4px; }
.seg__opt { flex: 1; padding: 9px 6px; border: none; background: none; border-radius: var(--r-pill); font-size: var(--fs-meta); font-weight: 800; color: var(--ink-2); transition: background 0.2s, color 0.2s, box-shadow 0.2s; }
.seg__opt.is-on { background: var(--card); color: var(--primary); box-shadow: var(--sh-1); }
.seg__opt.is-on.danger { color: var(--danger); }
.seg__opt.is-on.warn { color: var(--warn); }

/* dot list */
.dotlist { font-size: var(--fs-sub); line-height: 1.9; }
.dotlist .ok { color: var(--safe); font-weight: 800; }
.dotlist .ng { color: var(--danger); font-weight: 800; }

/* utility */
.gap-sm { display: flex; flex-direction: column; gap: 7px; }
.flex { display: flex; align-items: center; gap: 8px; }
.between { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.wrap { flex-wrap: wrap; }
.mt-2 { margin-top: 8px; } .mt-3 { margin-top: 12px; }
.center { text-align: center; }
.grow { flex: 1; min-width: 0; }

/* ---------- Form fields (interactive forms, e.g. evac pre-registration) ---------- */
.field-label { display: block; font-size: var(--fs-meta); font-weight: 700; color: var(--ink-3); margin: 10px 0 4px; }
.field-label:first-child { margin-top: 0; }
.field-input {
  display: block; width: 100%; padding: 10px 12px; border: 1.5px solid var(--line); border-radius: var(--r-sm);
  font-size: var(--fs-sub); font-family: inherit; color: var(--ink); background: var(--card);
}
.field-input:focus { outline: none; border-color: var(--primary); }
textarea.field-input { resize: none; }
.field-row { display: flex; gap: 8px; }
.field-row .field-col { flex: 1; min-width: 0; }
.field-col .field-label { font-size: var(--fs-micro); margin: 0 0 3px; }
.chk-row { display: flex; align-items: center; gap: 7px; padding: 5px 0; font-size: var(--fs-sub); color: var(--ink); }
.chk-row input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--safe); flex-shrink: 0; }

/* 選択式フォーム（チェックイン等・render 非依存でネイティブ input を使用） */
.opt-radio, .opt-check {
  display: flex; align-items: center; gap: 10px; padding: 11px 12px; margin-bottom: 6px;
  border: 1.5px solid var(--line); border-radius: var(--r-sm); cursor: pointer;
  font-size: var(--fs-sub); color: var(--ink); background: var(--card);
}
.opt-radio:has(input:checked) { border-color: var(--primary); background: var(--primary-soft); }
.opt-check:has(input:checked) { border-color: var(--safe); background: var(--safe-soft); }
.opt-radio input, .opt-check input { width: 18px; height: 18px; flex-shrink: 0; }
.opt-radio input { accent-color: var(--primary); }
.opt-check input { accent-color: var(--safe); }
.opt-radio .opt-desc { font-size: var(--fs-micro); color: var(--ink-3); margin-top: 2px; }
.stepper { display: flex; gap: 8px; align-items: center; }
.stepper button { width: 44px; height: 44px; border: 1.5px solid var(--line); border-radius: var(--r-sm); background: var(--card); font-size: 20px; font-weight: 700; color: var(--ink); flex-shrink: 0; }
.stepper input { flex: 1; text-align: center; font-weight: 800; min-height: 44px; }

/* 伝言板チャット（参照 p19） */
.chattabs { display: flex; background: var(--card); border-bottom: 1px solid var(--line); }
.chattabs button { flex: 1; padding: 10px 4px; text-align: center; font-size: var(--fs-meta); font-weight: 700; color: var(--ink-3); background: none; border: none; border-bottom: 2px solid transparent; }
.chattabs button.is-on { color: var(--teal, #00897B); border-bottom-color: var(--teal, #00897B); }
.chatarea { display: flex; flex-direction: column; gap: 10px; padding: 14px 12px; }
.chatdate { text-align: center; font-size: var(--fs-micro); color: var(--ink-3); margin: 4px 0; }
.msg { display: flex; gap: 8px; align-items: flex-end; max-width: 85%; }
.msg.mine { margin-left: auto; flex-direction: row-reverse; }
.msg .av { width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 13px; color: #fff; flex-shrink: 0; }
.bbl { background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 8px 12px; font-size: var(--fs-sub); color: var(--ink); line-height: 1.5; box-shadow: var(--sh-1); }
.msg.mine .bbl { background: var(--safe); color: #fff; border-color: transparent; }
.tm { font-size: var(--fs-micro); color: var(--ink-3); margin-top: 2px; }
.chatbar { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--line); background: var(--card); }
.chatbar input { flex: 1; border: 1.5px solid var(--line); border-radius: 20px; padding: 9px 14px; font-size: var(--fs-sub); font-family: inherit; }
.chatbar button { width: 40px; height: 40px; border-radius: 50%; background: var(--teal, #00897B); color: #fff; border: none; font-size: 18px; flex-shrink: 0; }

/* a11y */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.screen:focus { outline: none; }
:focus-visible { outline: 3px solid #FFC400; outline-offset: 2px; border-radius: 4px; }

/* ===== ダークモード（設定→data-theme="dark" を :root に付与。auto は JS で解決） ===== */
:root[data-theme="dark"] {
  --bg: #0d1a1c;
  --bg-deep: #122a2e;
  --card: #14262a;
  --ink: #e6f6f2;
  --ink-2: #aecac4;
  --ink-3: #84a8a4;
  --line: #20393d;
  --line-soft: #182e32;
  --primary: #3ad6c6;
  --primary-bright: #7ee6da;
  --primary-soft: #183436;
  --safe-soft: #123a30;
  --warn-soft: #3A2A12;
  --danger-soft: #3a1a20;
  --pet-soft: #33260F;
  --info-soft: #112A3C;
  /* #2683: dark では `--info-title-on-tint` を明色 #4FC3F7（7.38:1 on --info-soft #112A3C、
     was var(--info) #0277BD 3.08:1）へ上書きする。light の宣言は :root 側（#01579B）。 */
  --info-title-on-tint: #4FC3F7;
  --teal-soft: #0E2A28;
  --purple-soft: #241033;
  /* #2799: dark では light の #3949AB（2.13:1 on 実効合成背景 #132029）は AA 未達のため、
     Material Indigo 200 相当の明色へ上書きする。light の宣言は :root 側参照。 */
  --indigo-title-on-tint: #9FA8DA; /* 7.18:1 on 実効合成背景 #132029 (was #3949AB, 2.13:1) */
  /* #2600: dark already clears AA on these pairs with the theme's own base token (see
     the :root declarations above for the light-only fix + full rationale) — reinstate
     the normal token here rather than carrying the light-tuned override into dark. */
  --primary-on-tint: var(--primary); /* 7.34:1 on dark --primary-soft #183436 */
  --ink3-on-tint: var(--ink-3);      /* 5.13:1 on dark --primary-soft #183436 */
  --ink3-on-bg-deep: var(--ink-3);   /* #2683: 5.81:1 on dark --bg-deep #122a2e — already AA */
  --pet-steps-on-tint: var(--pet);   /* 5.45:1 on dark --pet-soft #33260F — already AA */
  /* #2836: dark already clears AA on --card with the base token — reinstate it rather
     than carry the light-tuned override into dark (see :root declaration above). */
  --pet-total-on-card: var(--pet);   /* 5.79:1 on dark --card #14262a — already AA */
  /* --safe-on-card / --pet-title-on-tint: unlike the three above, dark does NOT already
     pass on this pair (3.06:1 / 3.19:1) — these genuinely need a dark-only color, not a
     reinstated base token. See :root declarations above for full rationale. */
  --safe-on-card: #3da642;      /* 5.02:1 on --card #14262a (was var(--safe) #2E7D32, 3.06:1) */
  --pet-title-on-tint: #fe6700; /* 5.02:1 on dark --pet-soft #33260F (was #C65000, 3.19:1) */
  /* #2673: dark は --card (#14262a) 上で --warn がそのまま 5.08:1 を満たすため、
     #2600 の --primary-on-tint 等と同じく base token を再宣言するだけで新色は作らない。 */
  --warn-on-card: var(--warn); /* 5.08:1 on --card dark #14262a — already AA */
  /* #2601: `#/me` の居住自治体変更カード（`.tint-warn` = --warn-soft #3A2A12）専用。
     題字は badge と同じ明橙、safe/danger は badge の明色（.b-safe/.b-danger の dark ink）
     を再利用し、同じ色相・意味を保ったまま AA を満たす。 */
  --warn-title-on-tint: #ffb74d;    /* 7.98:1 on --warn-soft #3A2A12 (was #E65100, 3.65:1) */
  --safe-on-warn-tint: #7cd99a;     /* ≈6.8:1 on --warn-soft #3A2A12 (was var(--safe) #2E7D32, 2.69:1) */
  --danger-on-warn-tint: #ff8a80;   /* ≈5.9:1 on --warn-soft #3A2A12 (was var(--danger) #D32F2F, 2.77:1) */
  /* #2778: dark では `.b-safe` / `.b-danger` と同じ明色へ（:root 側宣言参照）。 */
  --safe-title-on-tint: #7cd99a;    /* 7.32:1 on dark --safe-soft #123a30 (was var(--safe) #2E7D32, 2.45:1) */
  --danger-on-pet-tint: #ff8a80;    /* 6.46:1 on dark --pet-soft #33260F (was var(--danger) #D32F2F, 2.96:1) */
  --sh-1: 0 1px 2px rgba(0, 0, 0, 0.24), 0 1px 3px rgba(0, 0, 0, 0.2);
  --sh-2: 0 12px 30px rgba(0, 0, 0, 0.34);
  --sh-3: 0 20px 60px rgba(0, 0, 0, 0.44);
  --sh-appbar: 0 6px 18px rgba(0, 0, 0, 0.4);
}
:root[data-theme="dark"] body { background: linear-gradient(135deg, #0d1c1e, #0e2230); color: var(--ink); }

/* #2262 fix: .tabbar's background is a literal `rgba(255, 255, 255, 0.96)` (not a
   var()), so unlike .tab's `color: var(--ink-3)` it never repainted for dark mode —
   themed (light) tab-label text landing on a bar that stayed white (measured
   2.59:1 unselected / 1.81:1 selected, both far under WCAG AA's 4.5:1 for text).
   Dark-only override here, not a new custom property: this rgba value is used
   nowhere else in app.css, and every other one-off component surface already
   re-themed for dark mode (.map-cluster earlier in this file, .b-*, .info-strip.*
   further down) follows the same "override in the dark block" pattern rather than
   getting its own token. Value is --card's dark rgb (#14262a → 20, 38, 42) — this app's
   existing dark "elevated surface" tone, reused instead of inventing a new color —
   at the SAME 0.96 alpha as the light rule, to preserve the bar's intended
   translucency/backdrop-blur look rather than going opaque. Verified (WCAG
   relative-luminance formula, same as dark-mode-icon-contrast-2255.spec.ts /
   dark-mode-contrast-audit-2258.spec.ts): --ink-3 dark (#84a8a4) → 6.06:1,
   --primary dark (#3ad6c6, active tab) → 8.66:1 against rgb(20, 38, 42), both
   clearing 4.5:1 with margin. Light mode is untouched (this file's base `.tabbar`
   rule is unchanged), so light-mode ratios (5.01:1 / 4.95:1) do not move. */
:root[data-theme="dark"] .tabbar { background: rgba(20, 38, 42, 0.96); }

/* #2673: .map__badge (`#/map` の shelter-map と `#/evac/map` の evac-map 双方で共有) の
   background は固定 rgba(255,255,255,.92) で dark 専用上書きが無く、一方 color:
   var(--ink-2) は dark で明色に repaint するため「暗い地の上向けの明るい ink」を
   「常に明るいままの地」に乗せる組み合わせになり 1.74:1 まで崩壊していた。#2262 の
   .tabbar 固定背景バグと同型 — ink 側 (--ink-2) は他の多数の contrast contract を
   持つため触らず、このコンポーネント自身の背景だけ dark 専用に上書きする。alpha は
   既存の 0.92 を維持、rgb は --card dark (#14262a) の値を流用（新規色を発明しない）。 */
:root[data-theme="dark"] .map__badge { background: rgba(20, 38, 42, 0.92); } /* --ink-2 dark #aecac4 → 8.99:1 (was 1.74:1 on rgba(255, 255, 255, .92)) */

/* #2599 fix: `.app.is-emergency .tab.is-active` (発災中の選択中タブラベル) had been
   `color: var(--danger)` (#D32F2F) unconditionally — fine against the light `.tabbar`
   (measured 4.98:1) but only 3.15:1 against this dark `.tabbar` background
   (rgb(20, 38, 42)), under WCAG AA's 4.5:1 for text. Every one of the 6 bottom tabs hits
   this same rule (the selector only checks `.is-active`, not which tab), so whichever
   tab is current becomes hardest to read at the exact moment (an active disaster) it most
   needs to be legible. Can't just brighten `--danger` itself — it's shared with
   `.tab__badge`, `.appbar--danger`, `.b-danger`, etc., each with its own contrast
   contract against a different surface. So this dark-only override targets the new
   `--danger-tabbar-active` token (declared at :root, default `var(--danger)`) instead of
   introducing a second dark-mode danger hue for those unrelated surfaces. Chose Material
   Red 300 (#E57373) over Red 400 (#EF5350, 4.49:1 — 0.01 short of AA) for margin: verified
   (same WCAG relative-luminance formula as the other dark-mode fixes in this file)
   #E57373 → 5.25:1 against rgb(20, 38, 42), clearing 4.5:1. The `.tab.is-active::before`
   top indicator bar is untouched (`background: var(--danger)`, still 3.15:1) — it's a
   non-text element so WCAG 1.4.11's 3:1 threshold applies, not 1.4.3's 4.5:1, and 3.15:1
   already clears that; the full-strength --danger there is what still carries the "this is
   an alert" visual weight. Light mode's `--danger-tabbar-active` stays `var(--danger)`
   (declared at :root, above), so the light-theme active-tab path is unchanged. */
:root[data-theme="dark"] { --danger-tabbar-active: #E57373; }

/* #1584 fix: .b-* badge ink は light 側の固定 hex を再利用しており、dark の -soft 底では
   軒並み sub-AA だった(実算: safe 1.59:1 / warn 2.99:1 / danger 2.38:1 / info 2.00:1 /
   pet 3.19:1 / purple 1.87:1 / teal 2.30:1 / solid(white on --primary) 1.81:1)。
   RN 側と同方針で dark 専用に「同色相・明色」ink へ差し替え(色相/意味は不変)。b-gray は
   --ink-2 由来で既に 8.63:1 のため対象外。 */
:root[data-theme="dark"] .b-safe { color: #7cd99a; }   /* 7.32:1 on --safe-soft #123a30 */
:root[data-theme="dark"] .b-warn { color: #ffb74d; }   /* 7.98:1 on --warn-soft #3A2A12 */
:root[data-theme="dark"] .b-danger { color: #ff8a80; } /* 6.82:1 on --danger-soft #3a1a20 */
:root[data-theme="dark"] .b-info { color: #64b5f6; }   /* 6.68:1 on --info-soft #112A3C */
:root[data-theme="dark"] .b-pet { color: #ffb37e; }    /* 8.42:1 on --pet-soft #33260F */
:root[data-theme="dark"] .b-purple { color: #ce93d8; } /* 7.34:1 on --purple-soft #241033 */
:root[data-theme="dark"] .b-teal { color: #4fd8c4; }   /* 8.66:1 on --teal-soft #0E2A28 */
:root[data-theme="dark"] .b-solid { color: #143b3a; }  /* 6.77:1 on --primary #3ad6c6 */

/* CR follow-up: .info-strip.safe/.warn/.purple/.teal share the exact same -soft bg tokens as
   .b-safe/.b-warn/.b-purple/.b-teal above, so the ratios carry over unchanged. */
:root[data-theme="dark"] .info-strip.teal { color: #4fd8c4; }   /* 8.66:1 on --teal-soft #0E2A28 */
:root[data-theme="dark"] .info-strip.safe { color: #7cd99a; }   /* 7.32:1 on --safe-soft #123a30 */
:root[data-theme="dark"] .info-strip.warn { color: #ffb74d; }   /* 7.98:1 on --warn-soft #3A2A12 */
:root[data-theme="dark"] .info-strip.purple { color: #ce93d8; } /* 7.34:1 on --purple-soft #241033 */

/* ===== シンプルモード（装飾控えめ・影と装飾を抑制） ===== */
:root[data-simple="on"] .card,
:root[data-simple="on"] .qa,
:root[data-simple="on"] .slist { box-shadow: none; }

/* ===== #3132 防災 ID の QR（#/me/id） =====
   QR の面は **テーマに依存せず白固定**（dark mode でも反転させない — 反転した QR は読み取れない）。
   quiet zone（4 module）は SVG の viewBox 側に含める。ここの padding は面の見た目だけ。
   user-select / touch-callout は見た目上の抑止であり、画面写真を防ぐ制御ではない。 */
/* 小さい端末（360px 級）でも QR を 3 px/module で置けるよう、card を .sec の余白へ 8px はみ出させ、padding を詰める。 */
.idq-card { text-align: center; padding: 12px 4px; margin: 0 -8px; }
.idq-panel {
  background: #fff; border-radius: 12px; padding: 4px;
  width: min(100%, 300px); max-width: 100%; margin: 0 auto 10px; box-sizing: border-box;
}
.idq-svg {
  display: block; width: 100%; height: auto; aspect-ratio: 1 / 1; background: #fff;
  shape-rendering: crispEdges; -webkit-touch-callout: none; user-select: none;
}
.idq-count { font-weight: 700; }
.idq-help { margin-top: 6px; }
.idq-msg { text-align: center; padding: 22px 16px; }
.idq-prep { text-align: center; padding: 28px 18px; }
.idq-prep__ico { font-size: 44px; line-height: 1; }
.idq-prep__t { font-size: 17px; margin-top: 10px; }
.idq-prep__x { margin: 8px 0 14px; }
.idq-prep__btn { opacity: .5; cursor: default; }
.idq-count, .idq-help { padding-left: 12px; padding-right: 12px; }
