/* 国道マップ。標識の青を基調にした操作パネル。
   地図に主役を譲るため彩度は抑える。 */
:root {
  /* 明るいときと暗いときの色を light-dark() で一つの宣言に書く。どちらを
     使うかは color-scheme が決める。既定の `light dark` は端末の設定に従い、
     app.js が data-theme を置けばそちらが勝つ。配色ごとにブロックを分けると
     同じ色が二箇所に並ぶ。重用の色の写しを持っていたころ、暗い側だけが N_COLORS
     と食い違っていた。

     color-scheme はブラウザが自前で描く部品(スクロールバー、チェックボックス、
     検索欄の消去ボタン)にも配色を伝える。無いと暗い配色でもスクロールバーだけが
     白いままになる。 */
  color-scheme: light dark;

  --sign-blue: light-dark(#00449E, #79AEF7);

  /* 重用の深さの色はここに無い。地図の線も凡例の見本も web/mapspec.mjs の
     N_COLORS から取るので、CSS に写しを置くと二箇所になる。 */

  /* 明るい側の地は真っ白ではなく地図の白(#FDFDFE)にする。操作パネルは地図の上に
     浮いており、純白だと画面で一番明るい面になって地図より前へ出る。#FDFDFE
     はごく薄く青が入っているので、一段沈めた --panel-2 も同じ側へ寄せる。

     --panel-2 は body の地でもある。地図の raster はその上へ 0.82 で乗るので、
     ここを動かすと地図の色も動く。差は RGB で 2 に満たず、GSI_SHADE_PAINT が
     守る「見え方を変えない」の内側である。 */
  --panel: light-dark(#FDFDFE, #131C29);
  --panel-2: light-dark(#F3F4F7, #0E161F);
  --line: light-dark(#D7DFEA, #27364A);
  --line-2: light-dark(#E7ECF3, #1D2938);
  --ink: light-dark(#121A24, #E6EDF6);
  --ink-2: light-dark(#46566A, #B2C1D3);
  --ink-3: light-dark(#6C7E93, #8799AE);
  --focus: light-dark(#1E6FD9, #79AEF7);

  /* スクロールバー。地図と操作パネルのあいだで一番目に入る必要のないもの
     なので、溝は透かし、つまみだけを枠線の色より一段濃くする。 */
  --scroll-thumb: light-dark(#C2CDDC, #33445C);
  --scroll-thumb-hover: light-dark(#9FB0C5, #48607E);

  /* コピー成功のチェックマークだけが使う。他の状態を持たないので上の配色群
     には混ぜない。 */
  --success: light-dark(#1E8E3E, #4ADE80);

  /* 「道路を選択」の系統ボタンで、都道府県道の側が出ている間のチェックの箱の
     地。明るい側は地図の主要地方道のラベルと同じ濃い緑(mapspec.mjs の
     PREF_MAJOR_INK)で、箱の色が地図と同じ意味を持つ。線の緑(PREF_MAJOR)では
     ない。あちらは縁取りが輪郭を持つ前提の明るい緑で、白いチェックを載せると
     比が 2.5:1 しか出ず、図形に要る 3:1 にも届かない。暗い側は --sign-blue と
     同じ扱いで、地と印を入れ替えられる明るさへ寄せる。test/panel.test.mjs が
     明るい側の値を PREF_MAJOR_INK と突き合わせる。 */
  --pref-green: light-dark(#1B7A3E, #7ED2A0);

  /* 凡例の都道府県道の見本だけが使う縁取り。地図の縁取りと同じ色(mapspec.mjs の
     PREF_CASING)である。一般都道府県道の黄は白い地に対して 1.24:1 しかなく、
     見本だけ縁を外すと凡例の中でその行が消える。test/panel.test.mjs が値を
     突き合わせる。写真の下地図では地図側の主要地方道が濃い灰になるが、凡例は
     操作パネルの地に載っているので追わない。 */
  --pref-casing: #85909F;

  /* 道路を一時的に隠すボタンが、隠している間だけ使う。白い字を載せる地なので、
     配色が明るくても暗くてもこの赤のままでよい。 */
  --danger: #B3261E;
  --danger-hover: #8C1F19;

  /* 操作パネルの書体。先頭の 1 書体だけが自前で、残りは端末の書体である。
     届くのは画面に出ている字を含む片だけだが数百 kB は待つ。font-display が
     swap なのでその間は次の候補で出て、届いた時点で入れ替わる。標識の番号
     (.shield text)もこの並びを Roboto の後ろに繋いで使う。並びを二箇所に
     書くと片方が暗黙のうちに古くなる。 */
  --ui-font: "LINE Seed JP", "Hiragino Kaku Gothic ProN", "Hiragino Sans",
             "Yu Gothic UI", "Yu Gothic", "Noto Sans JP", "Segoe UI",
             system-ui, sans-serif;

  /* 国道番号標識の配色。地の青、白の縁、白抜きの番号である。
     標識は明るい配色でも暗い配色でも同じ色なので、切り替えない。 */
  --shield-face: #00449E;
  --shield-edge: #FFFFFF;
  --shield-ink: #FFFFFF;
  /* 白い縁は明るい配色の面では地に溶け、標識が面に貼り付いて見える。実物は
     面から浮いているので、縁の外側を薄い影で締める。暗い面では縁自身が
     境目になるので影は見えないだけで、邪魔にはならない。 */
  --shield-shadow: drop-shadow(0 1px 1.5px rgba(0, 0, 0, .34));
}
/* 配色を人が選んだとき。app.js が置き、上の light-dark はこれに従う。
   端末に合わせているあいだも app.js は解いた側を置くので、色ではない
   切り替え(ボタンの絵の反転)もここ一つを見れば済む。 */
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

/* 標識の番号だけに使う。実物の書体はヒゲ(セリフ)が無く字面が立っており、
   等幅の代替書体は "1" などに細いヒゲが残って実物と字形が違って見える。
   scripts/vendor_web.mjs が node_modules から複製する。 */
@font-face {
  font-family: Roboto;
  src: url('vendor/roboto-latin-700-normal.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* Wikipedia の W だけに使う(.detail-wiki text)。あちらのロゴは写せないので、V
   を二つ重ねた W(オールドスタイルのセリフの字形)で代える。端末の書体には
   頼れない。Garamond も Bodoni MT も Goudy Old Style も Office や Adobe の
   付属品で、持たない端末では総称の serif へ落ち、V の重なりの保証が無い。標識の
   番号に Roboto を配るのと同じ理由で自前で配る。EB Garamond は OFL-1.1 の
   Garamond 復刻である。

   weight は 500 だけ複製する。400 では 15px のとき斜めの細い線が 1 画素を割り、
   上の飾り罫と一続きの滲みになる。index.html は preload しない。この 24 kB が
   必要なのは詳細パネルを開いた人だけである。 */
@font-face {
  font-family: 'EB Garamond';
  src: url('vendor/eb-garamond-latin-500-normal.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

* { box-sizing: border-box; }

/* スクロールバー ----------------------------------------------------------
   同じ見た目を二通りで書く。標準の 2 行が Firefox と新しい Chrome に効き、
   ::-webkit- の側が Safari と古い Chrome に効く。両方を解する Chrome は
   標準の側を採用する。 */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--scroll-thumb) transparent;
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track,
::-webkit-scrollbar-corner { background: transparent; }
::-webkit-scrollbar-thumb {
  /* 透かした枠を内側の余白として使い、つまみを溝より細く見せる。 */
  background: var(--scroll-thumb); background-clip: content-box;
  border: 2px solid transparent; border-radius: 6px;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--scroll-thumb-hover); background-clip: content-box;
}
html, body { height: 100%; margin: 0; }
body {
  font-family: var(--ui-font);
  color: var(--ink);
  background: var(--panel-2);
  font-size: 14px;
  line-height: 1.6;
}

#app { position: relative; height: 100%; }

/* 地図の左上の列 ----------------------------------------------------------
   見出しのバーが一枚と、ポップオーバーを開くグループが三つ。かつては 340px の
   サイドパネルがあり、畳むと選択解除や都道府県道を戻す操作ごと消えて、閉じた
   人が地図に効いている絞り込みを戻せなくなっていた。

   グループは MapLibre 自身のボタンと同じクラス(maplibregl-ctrl-group)で書く。
   地の色・角丸・影は vendor/maplibre-gl.css とこのファイルの
   `.maplibregl-ctrl-group` が持ち、ここが足すのは並べ方だけである。右上の拡大・
   表示・地図の種類と寸法まで揃う。

   列そのものは地図を掴む操作を通す。バーとグループだけが受け取る。 */
#map-ui {
  position: absolute; left: 12px; top: 12px; z-index: 4;
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  pointer-events: none;
}
#map-ui > * { pointer-events: auto; }

/* ------------------------------------------------------------ 地図の見出し --- */
/* グループと同じ地・角丸・影で書く。名前とボタンが一枚に載っているだけで、
   浮き方は他のボタンと変わらない。 */
#brand {
  position: relative;
  display: flex; align-items: center; gap: 7px; height: 32px;
  padding: 0 7px 0 10px;
  background: var(--panel); color: var(--ink);
  border-radius: 4px; box-shadow: 0 0 0 2px rgba(0,0,0,.1);
}
.brand-icon { width: 16px; height: auto; flex: 0 0 auto; }
#brand h1 {
  margin: 0; font-size: .95rem; font-weight: 800; letter-spacing: -.01em;
  white-space: nowrap;
}
/* 名前と、押せる二つを分ける線。 */
.brand-sep { width: 1px; height: 17px; background: var(--line); flex: 0 0 auto; }
/* バーの中のボタンは枠を持たない。バーそのものが枠だからである。 */
.brand-btn {
  width: 24px; height: 24px; flex: 0 0 auto; padding: 0;
  display: grid; place-items: center; cursor: pointer;
  background: none; border: 0; border-radius: 3px; color: var(--ink-2);
}
.brand-btn:hover { color: var(--sign-blue); background: var(--panel-2); }
.brand-btn svg { width: 14px; height: 14px; }

/* ポップオーバーを開くグループ --------------------------------------------
   maplibregl-ctrl-group が地・角丸・影を持つので、ここは並べ方と、
   ポップオーバーを右へ出すための位置の基準(relative)だけを書く。 */
.ui-ctrl { position: relative; display: flex; }
/* ボタンの規則はどれも `.ui-ctrl` から書き起こす。maplibre-gl.css の
   `.maplibregl-ctrl-group button` は要素まで数えるぶん詳細度が一段高く、
   クラス一つで書くと寸法も display も向こうが勝つ。 */
.ui-ctrl .ui-btn {
  width: 29px; height: 29px; padding: 0; flex: 0 0 auto;
  display: grid; place-items: center; cursor: pointer;
  background: none; border: 0; color: var(--ink-2);
}
/* display: grid は hidden の既定(display: none)より強い。取り消す物が無いあいだ
   ✕ は出さないので、ここで明示的に伏せる。 */
.ui-ctrl .ui-btn[hidden] { display: none; }
/* 数のバッジを抱えるぶんだけ横に伸びる。バッジが無いときは他と同じ 29px 角。 */
.ui-ctrl .ui-btn-wide {
  width: auto; min-width: 29px; padding: 0 6px;
  grid-auto-flow: column; gap: 5px;
}
.ui-btn svg { width: 17px; height: 17px; display: block; }
/* 一つの台に二つ載る「道路を選択」だけが横に並ぶ。MapLibre の区切り線は縦積み
   を前提に border-top を引くので、こちらは向きを 90 度倒す。 */
.ui-ctrl-row .ui-btn + .ui-btn { border-top: 0; border-left: 1px solid var(--line); }
/* ポップオーバーが開いているあいだ、ボタンは押されたままである。地と字を
   入れ替えて示す。ホバーの地は `.maplibregl-ctrl button:not(:disabled):hover`
   が既に持つので書かないが、押されているあいだは上書きが必要である。あちらは
   クラス 3 つと要素 1 つで、クラス 3 つのこちらでは足りず、青が薄い灰色に
   置き換わって白い絵が白い地に消えていた。`.ui-ctrl` を頭に足して勝つ。 */
.ui-btn.active { background: var(--sign-blue); color: var(--panel); }
.ui-ctrl .ui-btn.active:hover {
  background-color: var(--sign-blue); filter: brightness(1.12);
}
/* グループの角はグループが丸めるが、押されたボタンの地は四角いまま外へはみ
   出す。グループに overflow: hidden を置くとポップオーバーまで刈られるので、
   外側の角はボタン自身が丸める。 */
.ui-ctrl > .ui-btn:only-of-type { border-radius: 4px; }
.ui-ctrl-row > .ui-btn:first-of-type { border-radius: 4px 0 0 4px; }
.ui-ctrl-row > .ui-btn:last-of-type { border-radius: 0 4px 4px 0; }
/* ✕ が無いあいだ、残った一つはグループの四隅を丸める。:only-of-type は伏せた
   ボタンも数えるので、当てにできない。 */
.ui-ctrl-row:has(> .ui-btn[hidden]) > .ui-btn:not([hidden]) {
  border-radius: 4px;
}
/* maplibre-gl.css は焦点の当たったボタンの角を縦積み前提で丸め直す
   (button:focus:first-child は上の二隅)。横並びのグループでは直角の下辺になる
   ので、id で押し戻す。#display-btn の :focus と同じ手当てである。 */
#ranking-btn:focus, #shared-btn:focus { border-radius: 4px; }
#select-btn:focus { border-radius: 4px 0 0 4px; }
#sel-none:focus { border-radius: 0 4px 4px 0; }
.ui-ctrl-row:has(> .ui-btn[hidden]) > #select-btn:focus { border-radius: 4px; }
/* 選択解除は取り消す操作なので、ホバーで危険色の地に染める。道路を一時的に隠す
   ボタンの `.active` と同じ組み合わせである。id を持つ選択子なので
   `.maplibregl-ctrl button:not(:disabled):hover` に詳細度で勝つ。 */
#sel-none:hover { background: var(--danger); color: #fff; }
/* 選んでいる本数。国道と都道府県道の合計で、系統は分けない。「道路を選択」が
   両方を引き受けるためである。 */
.sel-count {
  font-size: .62rem; font-weight: 700; line-height: 1.6;
  padding: 0 5px; border-radius: 999px;
  background: var(--sign-blue); color: var(--panel);
  font-variant-numeric: tabular-nums;
}
.sel-count[hidden] { display: none; }
.ui-btn.active .sel-count { background: var(--panel); color: var(--sign-blue); }
/* アイコン一つだけのボタン。詳細パネルの中で使う。GitHub リンクのように
   <a> で使う箇所もあるので、要素は問わない。 */
.icon-btn {
  display: grid; place-items: center; padding: 0; width: 28px; height: 28px;
  background: var(--panel-2); color: var(--ink-2); cursor: pointer;
  border: 1px solid var(--line); border-radius: 4px;
}
.icon-btn:hover:not(:disabled) { color: var(--sign-blue); border-color: var(--sign-blue); }
/* 押しても何も起きないボタンは、押せないと見えていなければならない。 */
.icon-btn:disabled { color: var(--ink-3); opacity: .45; cursor: default; }
.icon-btn svg { width: 15px; height: 15px; }
/* 目には出さず、読み上げにだけ残す文字。display: none と違って描画はされる
   ので、aria-labelledby の指し先になれるし、Chromium の innerText にも出る
   (pipeline/render_check.mjs がパネルの名前をそこから読む)。 */
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* 区画の見出しは、小さく・太く・字を離した帯である。等幅にしない。等幅を頼むと
   日本語の字だけが端末の代替書体へ落ち、同じ 1 行の中で書体が二つになる。帯の
   見た目は字の大きさ・太さ・letter-spacing が作る。

   id を含む選択子で書かない。詳細度が上がると .fold > summary:hover h2 の hover
   色(クラスのみ)に勝ち、折りたたみの見出しだけホバーで色が変わらなくなる。 */
.pane-hd h2, .map-popover h2 {
  margin: 0; font-size: .7rem; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-3);
}
/* ポップオーバーの頭。見出しと件数が一行に並ぶ。 */
.pane-hd {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px;
}
.pane-hd .count {
  font-size: .68rem; flex: 0 0 auto;
  color: var(--ink-3); font-variant-numeric: tabular-nums;
}
/* 絞り込み欄。虫眼鏡は欄の中に置き、ラベルを書き足さずにこの欄が探す所である
   ことを示す。押せる物ではないので、クリックは通す。 */
.filter-row { position: relative; display: flex; align-items: center; margin-bottom: 10px; }
.filter-icon {
  position: absolute; left: 9px; width: 13px; height: 13px;
  color: var(--ink-3); pointer-events: none;
}
.filter-row input[type="search"] {
  flex: 1; min-width: 0; margin-bottom: 0; padding-left: 28px;
}

/* 畳んだ区画 --------------------------------------------------------------
   「国道マップについて」の但し書きが使う。開く前から場所を取る理由が無く、
   畳んだままでも見出しが中身の見当を示す。 */
.fold > summary {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  list-style: none; min-height: 24px;
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::after {
  content: ""; margin-left: auto; align-self: center;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid var(--ink-3);
}
.fold[open] > summary::after { transform: rotate(180deg); }
.fold[open] > summary { margin-bottom: 10px; }
.fold > summary:hover h2 { color: var(--sign-blue); }

/* ボタンの骨格。about ダイアログのリンク(a.mini)もこれを借りる。`button.mini`
   と書いていたころは a に当たらず、既定の青と訪問後の紫になっていた。ここで色を
   決めるので :visited でも変わらない。 */
.mini {
  font: inherit; font-size: .72rem; padding: 2px 8px; cursor: pointer;
  background: var(--panel-2); color: var(--ink-2);
  border: 1px solid var(--line); border-radius: 3px;
}
.mini:hover:not(:disabled) {
  border-color: var(--sign-blue); color: var(--sign-blue);
}
.mini:disabled { color: var(--ink-3); opacity: .55; cursor: default; }

input[type="search"] {
  font: inherit; width: 100%; padding: 6px 9px; margin-bottom: 10px;
  background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: 3px;
}
input[type="search"]::placeholder { font-size: .82em; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

/* 一覧に出す系統 ----------------------------------------------------------
   状態は三つだけで、どちらも外れることはない。二枚が一枚に見えるので、二つで
   一組であることを形が示す。地図の絞り込みではなく、この一覧の
   絞り込みである。

   出ているかどうかはチェックの箱が言い、系統の色はその箱が持つ。面の色に
   持たせていたころは、色が「その系統である」と「選ばれている」を兼ねており、
   既定(どちらも押されている)では色の面が二枚並んで、押して外せる物に
   見えなかった。 */
.sys-seg { display: flex; border: 1px solid var(--line); border-radius: 3px; overflow: hidden; }
.sys-seg .sys {
  flex: 1; font: inherit; font-size: .72rem; line-height: 1; padding: 6px 0;
  /* 高さは自分で決める。グループの 29px に揃えるためで、以前は maplibre-gl.css
     の `.maplibregl-ctrl-group button` から漏れて届いていた。 */
  min-height: 29px;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  cursor: pointer; border: 0; background: var(--panel-2); color: var(--ink-2);
}
.sys-seg .sys + .sys { border-left: 1px solid var(--line); }
/* 系統の色は、出ているかどうかに関わらずその側のものである。国道は標識の青、
   都道府県道は地図の主要地方道の緑である。 */
.sys-seg #sys-national { --sys-on: var(--sign-blue); }
.sys-seg #sys-pref { --sys-on: var(--pref-green); }
/* 出ている側は面と同じ地まで起き上がり、字が濃くなる。沈んだままの側との差は
   地・字の濃さ・太さ・箱の四つが同時に述べる。 */
.sys-seg .sys[aria-pressed="true"] {
  background-color: var(--panel); color: var(--ink); font-weight: 700;
}
/* チェックの箱。すぐ下の路線一覧もチェックボックスなので、面の中で語彙が一つ
   で済む。系統の色は字の地ではなくこの箱が持つ——字に要る 4.5:1 ではなく図形の
   3:1 でよくなり、青(8.9:1)と緑(5.4:1)で字の読みやすさが揃う。 */
.sys-seg .sys-box {
  flex: 0 0 auto; display: grid; place-items: center;
  width: 14px; height: 14px; box-sizing: border-box;
  border: 1.5px solid var(--ink-3); border-radius: 3px; color: var(--panel);
}
.sys-seg .sys[aria-pressed="true"] .sys-box {
  background: var(--sys-on); border-color: var(--sys-on);
}
.sys-seg .sys-box svg { display: none; width: 12px; height: 12px; }
.sys-seg .sys[aria-pressed="true"] .sys-check { display: block; }
/* 最後の一枚は押しても外れない。チェックを錠に替えて、押す前にそう言う。
   読み上げには wiring.mjs が置く aria-disabled が同じことを言う。 */
.sys-seg .sys[aria-disabled="true"] { cursor: default; }
.sys-seg .sys[aria-disabled="true"] .sys-check { display: none; }
.sys-seg .sys[aria-disabled="true"] .sys-lock { display: block; width: 10px; height: 10px; }
/* ホバーの地は選択子を四つ数えさせる。maplibre-gl.css の
   `.maplibregl-ctrl button:not(:disabled):hover` はクラス 3 つと要素 1 つで、
   このポップオーバーがグループの中にあるぶんここにも当たる。負けると地だけ
   薄い灰色になり、出ている側と沈んでいる側の差が消える。 */
.sys-seg .sys[aria-pressed="true"]:hover { background-color: var(--panel); }
/* 沈んでいる側は、押せば何が起きるかをホバーが先に見せる——字が濃くなり、空の
   箱の縁がその系統の色になる。 */
.sys-seg .sys[aria-pressed="false"]:hover {
  background-color: var(--line-2); color: var(--ink);
}
.sys-seg .sys[aria-pressed="false"]:hover .sys-box { border-color: var(--sys-on); }

/* 路線のチェックボックスの並び --------------------------------------------
   一覧は「道路を選択」のポップオーバー(#select-popover)の中にあり、開け閉ては
   app.js の registerPane が持つ。中は系統ごとの群に分かれる。国道は 459 行が
   最初からあり当たらない行を伏せ、都道府県道は当たった行だけをその場で組む
   (wiring.mjs の applyRouteFilter)。 */
.route-list {
  display: flex; flex-direction: column; gap: 8px;
  /* 高さは固定する。459 路線は常にこれより多く、`max-height` だと読み込み前の
     空の状態だけ小さく潰れ、データが届いた瞬間に膨らんで見えた。 */
  height: 260px; overflow-y: auto;
  border: 1px solid var(--line-2); border-radius: 3px; padding: 5px;
  background: var(--panel-2);
}
.rl-group { display: flex; flex-direction: column; gap: 4px; }
.rl-group[hidden] { display: none; }
/* 群の名前。区画の見出し(.pane-hd h2)より一段小さく、同じ帯の言葉で書く。 */
.rl-head {
  font-size: .6rem; font-weight: 700; letter-spacing: .1em; color: var(--ink-3);
  padding-left: 2px;
}
.rl-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
  gap: 3px; position: relative; min-height: 26px;
}
.rl-rows { display: flex; flex-direction: column; gap: 2px; }
/* 一覧の中で状態を示す一行。空・待ち・次の一手を同じ形にする。 */
.rl-note { margin: 0; padding: 4px 3px; font-size: .7rem; color: var(--ink-3); }
.rl-note[hidden] { display: none; }
/* 都道府県道の行。番号は県の中でしか一意でないので、ヘキサの隣に県名を置く。 */
.pref-row {
  display: flex; align-items: center; gap: 6px; cursor: pointer;
  -webkit-user-select: none; user-select: none;
  padding: 1px 3px; border-radius: 2px; color: var(--ink-2); font-size: .74rem;
}
.pref-row:hover { background: var(--panel); color: var(--ink); }
.pref-row.on { color: var(--sign-blue); font-weight: 700; }
.pref-row input { margin: 0; accent-color: var(--sign-blue); flex: 0 0 auto; }
.pref-row .shield { height: 18px; }
.pref-row .nm { white-space: nowrap; }
/* データが届く前にこの場所に何も無いと「壊れている」と読める。buildUI() が
   innerHTML を差し替えると一緒に消えるので、消す側のコードは不要である。 */
.route-list-spinner {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 26px; height: 26px; border-radius: 50%;
  border: 3px solid var(--line); border-top-color: var(--sign-blue);
  animation: route-list-spin .8s linear infinite;
}
@keyframes route-list-spin { to { transform: translate(-50%, -50%) rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .route-list-spinner { animation-duration: 2.4s; }
}
/* 国道の行。選択子を .rl-grid から書き起こす。.route-list から書くと
   都道府県道の行(.pref-row)にも当たり、要素まで数えるぶん詳細度で
   勝ってしまう。 */
.rl-grid label {
  display: flex; align-items: center; gap: 4px; cursor: pointer;
  /* 数字を選ばせない。459 個の的が 3 px 間隔で並んでいるので、少しでも
     手が動くとチェックではなく文字の範囲選択になってしまう。 */
  -webkit-user-select: none; user-select: none;
  font-size: .78rem;
  padding: 2px 3px; border-radius: 2px; color: var(--ink-2);
  /* 1 桁から 3 桁までが縦に並ぶ。桁を揃えるのは等幅ではなくこれの仕事で、
     操作パネルの書体はもともと数字が等幅である。 */
  font-variant-numeric: tabular-nums;
}
.rl-grid label:hover { background: var(--panel); color: var(--ink); }
.rl-grid label.on { color: var(--sign-blue); font-weight: 700; }
.rl-grid label.hidden { display: none; }
.rl-grid input { margin: 0; accent-color: var(--sign-blue); }
.rl-grid .mn { font-size: .62rem; color: var(--ink-3); font-weight: 400; }

.radios, .checks { display: flex; flex-flow: row wrap; gap: 6px 16px; }
.radios label, .checks label {
  display: flex; align-items: center; gap: 7px; cursor: pointer;
  color: var(--ink-2); font-size: .82rem;
}
.radios input, .checks input { accent-color: var(--sign-blue); margin: 0; }

/* 凡例 --------------------------------------------------------------------
   地図の右下に浮かせる。下端の 28px は出典の帯のぶんである。1 km の
   縮尺はここにあったが、この地図で読むもの(どの番号がどこを通るか)には
   効かないので落とした。

   地は明暗どちらの配色でも白いままにする。凡例は地図の部品で、隣の拡大ボタンも
   MapLibre が白い地に濃い灰色で描く。そこだけ地の色が変わると、同じ列に別の物が
   混ざる。 */
#legend-bar {
  position: absolute; left: 12px; right: 12px; bottom: 28px; z-index: 3;
  display: flex; justify-content: flex-end;
  /* 帯そのものは地図を掴む操作を通す。パネルだけが受け取る。 */
  pointer-events: none;
}
.legend-box {
  pointer-events: auto; max-width: 100%;
  display: flex; align-items: flex-start; gap: 2px;
  /* 右は畳む × のぶんだけ薄くする。ボタン自身が余白を持っている。 */
  padding: 7px 6px 7px 11px;
  background: var(--panel); color: var(--ink);
  border-radius: 6px; box-shadow: 0 0 0 2px rgba(0,0,0,.1);
}
.legend-rows { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.legend {
  display: flex; flex-wrap: wrap; gap: 2px 12px; justify-content: flex-end;
}
/* display:flex は hidden の既定(display:none)より強い。出ていない系統の行を
   app.js の syncLegend が hidden で隠すので、ここで明示する。 */
.legend[hidden], #legend-bar[hidden] { display: none; }
/* 行は字面の高さまで詰める。本文の 1.6 は読み下す文章のためのもので、
   一行ずつ拾い読みする見本の一覧には広すぎる。 */
.legend .item {
  display: flex; align-items: center; gap: 6px;
  font-size: .72rem; line-height: 1.35; color: var(--ink-2);
}
.legend .swatch {
  width: 20px; height: 0; flex: none;
  border-top-width: 3px; border-top-style: solid;
}
/* 都道府県道の見本にだけ縁取りを足す。地図では縁取りが線の輪郭を引き受けており
   (mapspec.mjs の pref-casing)、塗りだけの見本では一般都道府県道の黄が白い地の
   上でほとんど消える。破線の見本(.duo)にも足す。10px の刻みが
   二つ並ぶだけなので、黄の側が沈むと緑の破線 1 本に見える。国道の見本には
   足さない。縁取りは白のままで、白い操作パネルの上では引いても引かなくても
   同じである。 */
#legend-pref .swatch { box-shadow: 0 0 0 1px var(--pref-casing); }
/* 都道府県道の破線の見本だけが二色を半分ずつ並べる。地図では走れない区分も格の
   色のまま描かれるので、どちらの格でも破線になることを示す(panel.mjs の
   duoRule)。刻みは border ではなく背景で描く。1 本が 10px しかなく、
   border-top-style: dashed では刻みが 1 本に丸まって実線に見える。3px / 2px は
   隣に並ぶ 20px の dashed の見本が実際に描かれる刻みに合わせてある。 */
.legend .swatch.duo { display: flex; height: 3px; border-top: 0; }
.legend .swatch.duo > span {
  width: 10px; height: 3px;
  background-image: repeating-linear-gradient(
    to right, currentcolor 0 3px, transparent 3px 5px
  );
}
/* 行の頭の語。行ごとに色の意味が違う(国道は重用の深さ、都道府県道は格)ので、
   どちらの話かを示す。見本の名前より一段淡くする。 */
.legend .lead {
  font-size: .68rem; line-height: 1.35; color: var(--ink-3);
  margin-right: 2px; white-space: nowrap;
}
/* title 属性を持つ項目だけ、補足があることをカーソルで示す。 */
.legend .item[title] { cursor: help; }

/* 凡例を畳むボタンと、開き直すボタン。畳んでいるかどうかは <html> の
   data-legend が持つ。index.html の <head> が前回の選択を最初の描画の前に
   置くので、畳んでいる人の画面に凡例が一度出てから消えることがない。書くのは
   app.js である。× は共有ダイアログの .dialog-close と同じ書き方だが、寸法は
   一回り小さい。凡例は 3 行しかなく、32px 角ではその高さの半分を占める。 */
#legend-close {
  flex: none; border: 0; background: none; cursor: pointer; padding: 0;
  display: grid; place-items: center; width: 26px; height: 26px;
  border-radius: 4px; color: var(--ink-3);
}
#legend-close:hover { color: var(--ink); background: var(--panel-2); }
#legend-close svg { width: 13px; height: 13px; }
/* 開き直すボタンは地図の上の部品なので、地図の上のボタンと同じクラスで書く。
   maplibregl-ctrl-group を自分で持ち、地・角丸・影をそちらから借りる。字は
   持たない。他のボタンも絵だけなので、ここだけ字を添えると書き方が二つになる。
   名前は title と aria-label にある。 */
#legend-open {
  pointer-events: auto; display: none; place-items: center;
  width: 29px; height: 29px; padding: 0; border: 0; cursor: pointer;
  color: var(--ink-2);
}
#legend-open:hover { color: var(--sign-blue); }
#legend-open svg { width: 17px; height: 17px; display: block; }
:root[data-legend="off"] #legend-box { display: none; }
:root[data-legend="off"] #legend-open { display: grid; }

/* 重用ランキング -------------------------------------------------------- */
.ranking { display: flex; flex-direction: column; gap: 2px; margin-top: 8px; }
/* ポップオーバーの高さを止め、あふれたぶんはこの一覧がスクロールする。25 行・
   20 行は窓の高さをほとんど使い切る。 */
#ranking-popover .ranking, #shared-popover .ranking {
  max-height: 46vh; overflow-y: auto; padding-right: 2px;
}
.ranking .row {
  /* 縦に積む flex の中にあるので、縮まないと明示する。既定の flex-shrink: 1 が
     行を content より低く潰し、標識が折り返した行の中身が次の行の上へはみ出して
     いた。 */
  flex: 0 0 auto;
  display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: center;
  padding: 6px 8px; border: 1px solid var(--line-2); border-radius: 3px;
  background: var(--panel-2); cursor: pointer; text-align: left;
  font: inherit; color: var(--ink-2); width: 100%;
}
.ranking .row:hover { border-color: var(--sign-blue); }
/* 直前に飛んだ行。一覧は動かないので、どれを見ているのかは印でしか
   分からない。 */
.ranking .row.on {
  border-color: var(--sign-blue); background: var(--panel);
  box-shadow: inset 3px 0 0 var(--sign-blue);
}
.ranking .row .shields { display: flex; gap: 3px; flex-wrap: wrap; }
.ranking .row .km {
  font-size: .72rem;
  color: var(--ink-3); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.ranking .row .nm {
  grid-column: 1 / -1; font-size: .7rem; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ranking .empty { font-size: .75rem; color: var(--ink-3); }

/* おにぎり(国道番号標識)-------------------------------------------------
   実物と同じ配色である。白い縁は明るい配色の面では見えないが、暗い面では標識と
   地の境目になる。幅は決め打ちにしない。SHIELD_VIEWBOX の縦横比が変わっても、
   height だけ決めて width を auto にすれば追随する。 */
.shield { height: 30px; flex: 0 0 auto; display: block; }
/* 影は縁の外側に落ちるので svg の枠より外へ出る。番号だけに落ちないよう、path
   ではなく svg にかける。 */
.shield svg {
  display: block; height: 100%; width: auto; filter: var(--shield-shadow);
}
.shield path { fill: var(--shield-face); stroke: var(--shield-edge); }
.shield text {
  /* x/y/textLength は shield.mjs とここで合わせて目で調整してある。viewBox を
     変えるときは三つとも一緒に見直す。Roboto の後ろに並ぶのは、
     届くまでのあいだに出る書体である。等幅を並べていたころは、
     待っているあいだだけ "1" にヒゲの付いた字が出ていた。 */
  fill: var(--shield-ink); font-family: Roboto, var(--ui-font);
  font-size: 212.5px; font-weight: 700;
}
/* ヘキサだけ番号を大きくする。ヘキサは胴が広く、「県道」も県名も載せない
   (shield.mjs の hexShield)ので、空いたぶんを番号に回すと 22px の行でも 3 桁が
   読める。変えるのは大きさだけである。 */
.shield.hex text { font-size: 240px; }
.shield.sm { height: 22px; }

/* ポップアップの標識は押せる。標識そのものが路線の名前なので、脇に別の
   ボタンを足すより標識自体を的にするほうが短い。 */
.shield-btn {
  padding: 0; border: 0; background: none; cursor: pointer;
  border-radius: 4px; line-height: 0;
}
.shield-btn:hover { background: var(--line-2); }

/* データの出どころ。いつ時点の OSM か。出す場所は「国道マップについて」の
   ダイアログである。 */
.stats, .freshness {
  display: grid; grid-template-columns: max-content 1fr;
  gap: 1px 10px; font-size: .68rem; line-height: 1.55;
}
/* 国道・都道府県道、二つの .stats を分ける小見出し。数を合算せず系統ごとに
   出す(issue #171)ので、どちらの数かを示す必要がある。h3(区画の見出し)より
   一段小さく、凡例の .lead と同じ重さにしてある。 */
.stats-label {
  margin: 10px 0 2px; font-size: .68rem; line-height: 1.35; color: var(--ink-3);
}
.stats-label:first-of-type { margin-top: 0; }
/* 更新日時以下との区切りとわかる程度の余白。 */
.freshness { margin: 8px 0 0; }
.stats dt, .freshness dt { color: var(--ink-3); }
.stats dd, .freshness dd { margin: 0; color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------ 地図 --- */
/* 地図の上の部品 -----------------------------------------------------------
   拡大のボタンも縮尺も出典も凡例も、この地図が描く面である。下の地理院タイルは
   写真と同じ「中身」であって面ではない。明暗の切り替えはこの地図が
   描くものすべてに効き、地図そのものには効かない。薄い地図の上では
   暗い面のほうが白い面より境目がはっきりする。

   MapLibre のボタンのアイコンは #333 の塗りを data URI に焼き込んであり、色を
   差し替える口が無い。暗い配色では反転させる。hue-rotate を添えるのは、
   現在位置の青や方位の赤まで反対の色にしないためである。 */
.maplibregl-ctrl-group { background: var(--panel); }
.maplibregl-ctrl-group button + button { border-top-color: var(--line); }
/* グループは角を丸めるが、中のボタンは既定では四角い。ふだんは地を持たないので
   グループの丸みが見えており、ホバーや押された状態で地を持った瞬間だけ
   四隅がはみ出して矩形に見えていた。グループに overflow: hidden を置くと
   ポップオーバー(.map-popover)まで刈られるので、外側の角はボタン自身が継ぐ。

   数えるのは button だけ(:first-child ではなく :first-of-type)。グループには
   状態のラベル(.state-tip)やポップオーバーが同居しており、:last-child
   はそちらに当たる。 */
.maplibregl-ctrl-group > button:first-of-type { border-radius: 4px 4px 0 0; }
.maplibregl-ctrl-group > button:last-of-type { border-radius: 0 0 4px 4px; }
.maplibregl-ctrl-group > button:only-of-type { border-radius: 4px; }
/* maplibre-gl.css 側と同じ形の選択子で書き、記述順ではなく形で並ばせる。 */
.maplibregl-ctrl button:not(:disabled):hover { background-color: var(--panel-2); }
:root[data-theme="dark"] .maplibregl-ctrl-icon {
  filter: invert(1) hue-rotate(180deg);
}
/* 出典の地は二つのクラスで指定されている
   (.maplibregl-ctrl.maplibregl-ctrl-attrib)。片方だけで書くと詳細度で負け、
   字だけが変わって地が白いまま残る。地は透かす。出典は常に出ているもので、
   白い帯を敷くとその幅ぶんの地図が隠れる。読めるかどうかは字の周りの淡い縁が
   引き受ける。 */
.maplibregl-ctrl.maplibregl-ctrl-attrib { background-color: transparent; }
.maplibregl-ctrl-attrib {
  color: var(--ink-2);
  /* 同じ影を重ねて縁にする。1 枚では下地図の細い線が字に食い込む。地理院
     タイルは配色を切り替えても明るいままなので、暗い側では明るい海の上に明るい
     字が乗る。 */
  text-shadow:
    0 0 2px var(--panel), 0 0 2px var(--panel), 0 0 2px var(--panel),
    0 0 4px var(--panel), 0 0 4px var(--panel), 0 0 6px var(--panel);
}
.maplibregl-ctrl-attrib a { color: var(--sign-blue); }

/* 地図は窓いっぱいである。操作パネルも詳細も、その上に浮いている。 */
#map-wrap { position: absolute; inset: 0; }
#map { position: absolute; inset: 0; }

#loading {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: var(--panel-2); color: var(--ink-3);
  font-size: .85rem; z-index: 5;
}
#loading.done { display: none; }

/* 視点の傾きボタン ---------------------------------------------------------
   道路を隠すボタンと同じグループに載せる。 */
.pitch-ctrl button {
  display: grid; place-items: center; color: var(--ink-2);
}
.pitch-ctrl button svg { width: 17px; height: 17px; display: block; }

/* 道路を隠すボタン -------------------------------------------------------
   MapLibre のズームボタンと同じグループの体裁に載せる。地が常に白いので、
   アイコンの色は MapLibre のズームアイコンに合わせた固定の濃い灰色にする。 */
.hide-routes-ctrl button {
  display: grid; place-items: center; color: var(--ink-2);
}
.hide-routes-ctrl button svg { width: 17px; height: 17px; display: block; }
.hide-routes-ctrl button.active { background: var(--danger); color: #fff; }
/* MapLibre の `.maplibregl-ctrl button:not(:disabled):hover` も三つのクラスに
   当たり、勝っているのはこのファイルが後に読まれるからでしかない。順序が
   崩れると 5% の黒が赤を置き換え、白に近いボタンに白いアイコンが載る。選択子の
   形を揃えて読み込み順に頼らない。 */
.hide-routes-ctrl button.active:hover { background: var(--danger-hover); }

/* 地図の種類・濃さボタン ---------------------------------------------------
   二つで一つのグループである。どちらも下地図の見え方を決めるので、離さない。 */
.basemap-ctrl button {
  display: grid; place-items: center; color: var(--ink-2);
}
.basemap-ctrl button svg { width: 17px; height: 17px; display: block; }

/* 表示のボタンと、そこから出るポップオーバー ------------------------------
   ボタンは他と同じグループに載る。 */
.display-ctrl button {
  display: grid; place-items: center; color: var(--ink-2);
}
.display-ctrl button svg { width: 17px; height: 17px; display: block; }
/* ポップオーバーが開いているあいだ、ボタンは押されたままである。地の青と字の
   色を入れ替えて示す。 */
.display-ctrl button.active { background: var(--sign-blue); color: var(--panel); }
/* maplibre-gl.css 側の hover 規則と同じ形で書いて、記述順に頼らず勝つ
   (.hide-routes-ctrl button.active:hover と同じ理由)。 */
.display-ctrl button.active:hover {
  background-color: var(--sign-blue); filter: brightness(1.12);
}

/* ポップオーバー。グループの中にあるので位置はグループを基準に決まり、寸法を
   測って合わせる計算は無い。左へ出すのは、右に窓の端しか無いためである。 */
.map-popover {
  /* 上端はボタンに合わせ、窓の下からはみ出すときだけ app.js が引き上げる。
     それでも入り切らない高さの窓では、中がスクロールする。 */
  position: absolute; top: -1px; right: calc(100% + 8px);
  width: max-content; max-width: min(280px, calc(100vw - 64px));
  max-height: calc(100vh - 24px); overflow-y: auto; overscroll-behavior: contain;
  padding: 12px 14px; text-align: left;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px;
  box-shadow: 0 6px 26px rgba(0,0,0,.26);
  display: grid; grid-template-columns: 1fr; gap: 15px 20px;
}
.map-popover[hidden] { display: none; }
/* ポップオーバーの中のボタンはグループのボタンではない。maplibre-gl.css の
   `.maplibregl-ctrl-group button` は 29px 角を前提に寸法を決めており、それが
   中身にまで及んで一覧の行が 29px に固定され、折り返した標識が次の行にはみ
   出していた。グループのクラスを頭に足して形で勝たせる。手放すのは
   寸法だけにする。display まで書くと要素をひとつ数えるぶん強く、一覧の行が
   自分で持つ `display: grid` にまで勝つ。 */
.maplibregl-ctrl-group .map-popover button { width: auto; height: auto; }

/* 左上のグループから出るポップオーバーは右へ向く。左には窓の端しか無い。幅は
   決め打ちにする。中身(459 個のチェックボックス、標識の行)は auto-fill の
   格子で、max-content は auto-fill を 1 列と数えるので、幅が定まらないと 1 列に
   潰れる。 */
.map-popover.to-right {
  right: auto; left: calc(100% + 8px);
  width: 300px; max-width: calc(100vw - 64px);
}
/* 区画の中は見出しと中身が一組。区画どうしの間はポップオーバーの gap が
   空ける。 */
.map-popover > section { display: flex; flex-direction: column; gap: 9px; }
/* 幅に余裕がある窓では上段に短い三区画、下段に「表示」だけを置く。「表示」は
   項目が 6 つあり頭一つ抜けて長い。560px は中が崩れない実測の下限。

   ここは「表示」だけの話である。.map-popover 全体に書いていたころ、左上の
   三つまで 3 列の格子にされ、区画を一つしか持たないそれらが
   grid-template-areas
   の外へ落ちて崩れていた。 */
@media (min-width: 560px) {
  #display-popover {
    grid-template-columns: repeat(3, 1fr);
    grid-template-areas: "national conc color" "kind kind kind";
    max-width: min(560px, calc(100vw - 64px));
  }
  #display-popover > section:nth-child(1) { grid-area: national; }
  #display-popover > section:nth-child(2) { grid-area: conc; }
  #display-popover > section:nth-child(3) { grid-area: kind; }
  #display-popover > section:nth-child(4) { grid-area: color; }
  /* 「表示」は段の幅いっぱいを使えるので、縦一列のままだと幅を余す。
     二列に折り返して段の高さを詰める。 */
  #display-popover > section:nth-child(3) .checks {
    flex-flow: row wrap; column-gap: 20px;
  }
}
/* ポップオーバーの中では縦に積む。横に折り返すと、どれが何行目かを目で
   追うことになる。 */
.map-popover .radios,
.map-popover .checks { flex-direction: column; gap: 8px; }

/* 「外部サイトで開く」。文字リンク 2 本だけなので、他のポップオーバーの
   300px は要らない。中身を測って崩れない幅にする。 */
#ext-popover { padding: 6px; width: max-content; }
.ext-links { display: flex; flex-direction: column; gap: 2px; }
.ext-link {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: 4px;
  color: var(--ink); text-decoration: none;
  font-size: .82rem; font-weight: 600; white-space: nowrap;
}
.ext-link:hover { background: var(--panel-2); color: var(--sign-blue); }
.ext-link svg { width: 14px; height: 14px; flex: 0 0 auto; color: var(--ink-3); }
.ext-link:hover svg { color: var(--sign-blue); }

/* ボタンの状態を示す一瞬のラベル -----------------------------------------
   タップには hover の title が出せないので、一瞬だけ状態を返す。ボタンと
   同じグループの中に置き、左へ出す。ラベルが同居するとボタンは :only-child
   でなくなり、maplibre-gl.css のフォーカス時の角丸が外れて上下どちらかの角が
   直角になる。ここで丸みをグループの値へ戻す。 */
.pitch-ctrl, .hide-routes-ctrl, .basemap-ctrl, .display-ctrl { position: relative; }
/* 左上のグループも同じ理由で手前にある。グループどうしは DOM の順で重なるので、
   開いているポップオーバーを持つグループを前に出す。 */
.ui-ctrl:has(> .map-popover:not([hidden])) { z-index: 1; }
/* #brand は先頭にあるので、素の DOM 順では後続のグループに隠れる側になる。
   スマートフォン幅で #ext-popover が下へ落ちると、すぐ下のグループと
   重なる高さに来るので、開いているあいだは #brand を前に出す。 */
#brand:has(> .map-popover:not([hidden])) { z-index: 1; }
/* 表示のポップオーバー(#display-popover)を持つこのグループは他より先に
   足してあるので、後のグループの state-tip がポップオーバーの上に出ていた。
   ポップオーバーのほうが手前だと決めておけば、足す順に左右されない。 */
.display-ctrl { z-index: 1; }
#pitch-btn:focus,
#hide-routes-btn:focus,
#gsi-shade-btn:focus,
#basemap-btn:focus,
#display-btn:focus {
  border-radius: inherit;
}
.state-tip {
  /* 上端は app.js が押されたボタンに合わせる。グループにボタンが二つ載ることが
     あり、真ん中に出すとどちらの返事か分からない。 */
  position: absolute; top: 0; right: calc(100% + 8px);
  transform: translate(4px, 0);
  display: flex; align-items: center;
  height: 29px; /* maplibre-gl.css の .maplibregl-ctrl-group button の高さに合わせる */
  padding: 0 8px; box-sizing: border-box;
  background: var(--panel); color: var(--ink); box-shadow: 0 0 0 2px rgba(0,0,0,.1);
  font-size: .72rem; border-radius: 4px;
  white-space: nowrap; opacity: 0; pointer-events: none;
  transition: opacity .15s ease, transform .15s ease;
}
.state-tip.show { opacity: 1; transform: translate(0, 0); pointer-events: auto; cursor: pointer; }

/* ポップアップ ---------------------------------------------------------- */
.maplibregl-popup-content {
  font-family: inherit; font-size: .8rem; padding: 12px 14px;
  border-radius: 4px; background: var(--panel); color: var(--ink);
  box-shadow: 0 4px 20px rgba(0,0,0,.22);
}
/* 吹き出しの角。MapLibre は三角形を border で描くので、色を差し替える辺は
   尖る向きで変わる。下向きなら border-top、左向きなら border-right である。
   残る二辺は透明のままでなければ四角に見える。以前は辺を選ばず上下の色だけを
   差し替えていたので、左右へ出たときに塗られた二辺が加わって四角になり、
   尖る辺は既定の白のままだった。MapLibre 側と同じ形の選択子なので詳細度は並び、
   後に読まれることで勝つ。 */
.maplibregl-popup-anchor-top .maplibregl-popup-tip,
.maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.maplibregl-popup-anchor-top-right .maplibregl-popup-tip {
  border-bottom-color: var(--panel);
}
.maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip {
  border-top-color: var(--panel);
}
.maplibregl-popup-anchor-left .maplibregl-popup-tip { border-right-color: var(--panel); }
.maplibregl-popup-anchor-right .maplibregl-popup-tip { border-left-color: var(--panel); }
/* 閉じるボタン。MapLibre の既定は寸法を持たず、× の字面ぶんしか当たり判定が
   無い。共有ダイアログの ×(.dialog-close)と同じ 32px 角に揃える。 */
.maplibregl-popup-close-button {
  top: 2px; right: 2px; width: 32px; height: 32px; border-radius: 4px;
  display: grid; place-items: center;
  font-size: 1.6rem; line-height: 1; color: var(--ink-3);
}
.maplibregl-popup-close-button:hover {
  color: var(--ink); background: var(--panel-2);
}
.pop-hd {
  display: flex; gap: 4px; flex-wrap: wrap; align-items: center;
  /* 右は閉じるボタンのぶんだけ空ける。標識がその下に潜り込まないように。 */
  margin-bottom: 8px; padding-bottom: 8px; padding-right: 26px;
  border-bottom: 1px solid var(--line-2);
}
.pop-n {
  font-size: .7rem;
  color: var(--ink-3); margin-left: 4px;
}
.pop-row { display: flex; justify-content: space-between; gap: 14px; color: var(--ink-2); }
.pop-row dt { color: var(--ink-3); font-size: .72rem; }
/* 行ごとに km と本数が右端で揃う。桁は tabular-nums が揃える。 */
.pop-row dd {
  margin: 0; font-size: .72rem; font-variant-numeric: tabular-nums;
}
/* ポップアップの中の anchor は OSM の way へのリンクだけである。ブラウザの
   既定の青は暗い操作パネルで消えるので、配色に追随する標識の青にする。 */
.maplibregl-popup-content a { color: var(--sign-blue); }

/* 詳細パネル --------------------------------------------------------------
   一つの国道について述べるパネル。地図の上に浮かせ、地図は padding でそのぶん
   空ける(app.js の applyMapPadding)。#map を細くすると canvas の寸法が変わり、
   開くたびに全部描き直しになる。

   幅は固定し、高さは中身に合わせる。高さまで固定すると短い路線ではパネルの下が
   空く。広い画面では mapPadding() が box.right だけを見るので、高さを中身に
   合わせても地図はずれない。入り切らないぶんは .detail-scroll が
   スクロールする。860px 以下では mapPadding() が box.top を見るので、路線を
   切り替えるたびに地図がわずかに動くことがあるが、パネルの下に空きが
   残るよりましと判断した。 */
#detail {
  /* 地図の左下に浮く。上を占めているのは見出しとグループの列なので、そこへ
     届かないところで高さを止める。184px はその列(12 + 32 + 8 + 29 + 8 + 29 + 8
     + 29)と間の余白ぶんである。 */
  position: absolute; left: 12px; bottom: 12px; z-index: 4;
  width: 340px; max-height: calc(100% - 184px);
  display: flex; flex-direction: column;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px;
  box-shadow: 0 6px 26px rgba(0,0,0,.26);
}
/* display:flex は hidden の既定 (display:none) より強い。閉じているパネルが
   出たままにならないよう、ここで明示的に伏せる。 */
#detail[hidden] { display: none; }
/* × は共有ダイアログと同じ見た目でよい。.icon-btn と同じで、載る要素は
   問わない。 */
#detail-close { position: absolute; top: 4px; right: 4px; z-index: 1; }
#detail-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.detail-hd {
  display: flex; align-items: center; gap: 10px;
  /* 右は閉じるボタンのぶんだけ空ける。 */
  padding: 12px 44px 12px 14px;
  border-bottom: 1px solid var(--line-2);
}
/* ポップアップの標識(30px)より大きい。これがパネルのタイトルである。標識が
   路線の名前そのものなので「国道N号」と書き添えない。 */
.detail-hd .shield { height: 44px; }
/* 標識の空けた場所には、その路線について次にできることを置く。 */
.detail-acts { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.detail-scroll {
  flex: 1; min-height: 0; overflow-y: auto;
  /* パネルの中を読み切ってもページごと動かさない。 */
  overscroll-behavior: contain;
  padding: 12px 14px 14px;
  display: flex; flex-direction: column; gap: 12px;
}
/* Wikipedia の W。字体は自前で配る EB Garamond が持ち、後ろの三つは届くまでの
   繋ぎである。寸法は svg 側の viewBox・textLength と目で合わせてある(detail.mjs
   の WIKIPEDIA_ICON)。印だけ 17px にしてある。他の印は線で引いた図で 15px でも
   形が残るが、これは字なので同じ 15px では小さく見え、隣の絞り込みアイコンと
   釣り合わない。 */
/* 「この路線だけ表示」が押されている状態。操作パネルに都道府県道の区画が
   無いので(#109)、絞っていることを示す場所がこのボタンのほかに無い。 */
.detail-only.active {
  background: var(--sign-blue); color: var(--panel); border-color: var(--sign-blue);
}
.detail-only.active:hover { color: var(--panel); }
.detail-wiki { text-decoration: none; }
.detail-wiki svg { width: 17px; height: 17px; }
.detail-wiki text {
  fill: currentcolor; font-size: 22px; font-weight: 500;
  font-family: 'EB Garamond', Garamond, 'Bodoni MT', 'Goudy Old Style', serif;
}

/* 起点・終点 --------------------------------------------------------------
   行そのものを路線に見立てる。左端が起点、右端が終点で、あいだを矢印が結ぶ。
   ラベルは地名の上に載せる。 */
.detail-termini {
  display: flex; align-items: center; gap: 6px;
  /* 押せる範囲は字面より広く取る。その食み出したぶんを外へ逃がして、
     左右の端をこのパネルの他の欄と揃える。 */
  margin: 0 -6px;
}
/* 両端は地名ぶんだけ取る。余りは矢印が飲むので、字数が少ない路線ほど矢印が
   長くなる。入り切らないときはここが縮み、地名は … で切れる。 */
.detail-termini .end {
  flex: 0 1 auto; min-width: 0;
  display: flex; flex-direction: column; gap: 2px;
  font: inherit; text-align: left; padding: 4px 6px;
  border: 0; border-radius: 3px; background: none; color: var(--ink-2);
}
/* 終点は右端に立つ。片方しか無い路線では唯一の flex item になり、寄せ先を
   自分で持たないと左端に残る。矢印が余りを飲みきる普段は、auto が取る余白が
   残らないので何も起きない。 */
.detail-termini .to {
  margin-left: auto; align-items: flex-end; text-align: right;
}
/* 座標が当たらなかった起終点は地名だけの <div> で出る。押せないものに
   ホバーの反応を付けない。 */
.detail-termini button.end { cursor: pointer; }
.detail-termini button.end:hover {
  background: var(--panel-2); color: var(--sign-blue);
}
.detail-termini .lbl {
  font-size: .68rem; color: var(--ink-3);
  letter-spacing: .06em;
}
.detail-termini .nm {
  max-width: 100%; font-size: .78rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 矢印は線と鏃を CSS で引く。span 一つで済む。幅は持たず、両端が取った残りを
   すべて飲む。地名が長い路線では 16px まで詰めて、そこで止める。 */
.detail-termini .arrow {
  flex: 1 1 auto; min-width: 16px; height: 1px;
  background: var(--ink-3); position: relative;
}
.detail-termini .arrow::after {
  content: ''; position: absolute; right: 0; top: 50%;
  width: 5px; height: 5px;
  border-top: 1px solid var(--ink-3); border-right: 1px solid var(--ink-3);
  transform: translateY(-50%) rotate(45deg);
}

.detail-stats {
  display: grid; grid-template-columns: max-content 1fr; gap: 2px 12px;
  margin: 0; font-size: .72rem; line-height: 1.6;
}
.detail-stats dt { color: var(--ink-3); }
/* 数の列は右で揃える。左揃えだと桁の違う km が単位ごとばらける。ポップアップの
   .pop-row が dt と dd を両端に振り分けているのと同じ理由である。 */
.detail-stats dd {
  margin: 0; color: var(--ink-2); font-variant-numeric: tabular-nums;
  text-align: right;
}
.detail-kinds { display: flex; flex-direction: column; gap: 5px; }
.detail-sub {
  font-size: .68rem; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-3);
}

/* 関わりのある国道 --------------------------------------------------------
   .detail-kinds と同じ組み方をする。見出し(.detail-sub)の下に中身を置く欄が
   パネルの中で三つ続くので、欄どうしの間隔は .detail-scroll の gap が持つ。 */
.detail-rel { display: flex; flex-direction: column; gap: 5px; }
/* 標識は折り返す。交差する路線は 31 まであり、一列には収まらない。行間は
   標識の影(--shield-shadow)が下へ落ちるぶんだけ列の隙間より広く取る。 */
.rel-shields { display: flex; flex-wrap: wrap; gap: 5px 3px; }

/* 都道府県道のパネル --------------------------------------------------------
   路線の名前を見出しに出す。国道のパネルは出さない。おにぎりの番号がそのまま
   路線の名前だからである。ヘキサは県を持たないので、番号だけでは 47 本のどれか
   決まらない。標識と同じ行に、標識より小さく置く。 */
.detail-name {
  margin: 0; font-size: .95rem; font-weight: 600; letter-spacing: .01em;
  /* 三つのボタンの列 (.detail-acts) を右端へ押し出すのは、こちらではなく
     あちらの margin-left: auto である。名前が長くても列は動かない。 */
  min-width: 0; overflow-wrap: anywhere;
}

/* 数が届くまでのあいだ、と読めなかったとき。 */
.detail-wait { margin: 0; font-size: .78rem; color: var(--ink-3); }

/* 複数の都道府県にわたる路線の区画 --------------------------------------------
   パネルの中でこの区画だけが地の色を持つ。県境の向こうまで同じ道であることは、
   重用や交差より強い関わりで、それが読まなくても分かる。ほかの区画
   (.detail-kinds と .detail-rel)は見出しと中身を並べるだけで、器を持たない。 */
.detail-cont {
  display: flex; flex-direction: column; gap: 7px;
  padding: 10px 11px 11px;
  background: var(--panel-2);
  border: 1px solid var(--line-2); border-radius: 4px;
}
/* まとめて表示しているあいだ。絞り込みアイコンは 15px しかなく、地図の上で
   パネルは 0.62 倍に見えるのでそこでは 9px になる。効いていることを述べるのは
   面のほうである。 */
.detail-cont.on { border-color: var(--sign-blue); }
/* 見出しと合算延長を両端に振り分ける。合算延長は区画が述べている 2〜4 本ぶんの
   数で、路線 1 本の数を並べる .detail-stats とは別の量である。だから統計の
   <dl> には足さず、この区画の右上に置く。書体・色・右揃え・等幅数字は
   .detail-stats の dd と揃える。 */
.cont-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.cont-head .detail-sub { flex: 1 1 auto; }
.cont-km {
  font-size: .68rem; color: var(--ink-3);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* 路線名。取れない群では行ごと出ない(detail.mjs の continuationHTML)。 */
.cont-name {
  font-size: .82rem; font-weight: 600; color: var(--ink); line-height: 1.4;
}
/* チップの行。右端に絞り込みアイコンが付く。何を絞るのかは、隣に並んだ
   チップが述べる。 */
.cont-row { display: flex; align-items: flex-start; gap: 8px; }
.cont-chips {
  display: flex; flex-wrap: wrap; gap: 5px;
  flex: 1 1 auto; min-width: 0; padding-top: 1px;
}
/* 区画の絞り込みアイコン。チップが増えても縮まない。地はチップと同じ
   --panel にして、区画の地(--panel-2)から立たせる。
   押していないときだけ塗るのは、押した状態の色を .detail-only.active 一箇所に
   残すためである。詳細度が同じで後ろに在るぶん、ここで無条件に塗ると青地を
   打ち消し、白地に白い絞り込みアイコンが乗って印が消える。 */
.cont-row .icon-btn { flex: 0 0 auto; }
.cont-row .icon-btn:not(.active) { background: var(--panel); }
/* 相手のチップ。.shield-btn の骨格を借りるので、line-height: 0 と
   display: block を打ち消してから中身を並べる。地は区画の地(--panel-2)より
   明るくして、押せる物として立たせる。 */
.cont-chip {
  display: inline-flex; align-items: center; gap: 5px; line-height: 1.6;
  padding: 2px 8px 2px 4px; background: var(--panel);
  border: 1px solid var(--line); border-radius: 4px;
}
.cont-chip:hover { background: var(--line-2); }
.cont-chip .shield { height: 20px; }
.cont-chip .pref {
  font-size: .7rem; color: var(--ink-2); white-space: nowrap;
}

/* ダイアログ --------------------------------------------------------------
   ネイティブの <dialog> を使う。showModal() が Esc とフォーカスの往復を
   面倒みるので、独自のフォーカストラップは書かない。共有と「この地図について」
   は同じ体裁で、器の見た目は .sheet が一度だけ決め、中身の違いだけをそれぞれが
   足す。 */
.sheet {
  border: 1px solid var(--line); border-radius: 6px; padding: 0;
  background: var(--panel); color: var(--ink);
  width: min(420px, 92vw);
  box-shadow: 0 8px 32px rgba(0,0,0,.28);
}
/* backdrop。ダイアログとその後ろの隔たりが読める濃さにする。押せば閉じる
   (app.js)。 */
.sheet::backdrop { background: rgba(8, 12, 18, .66); }
.sheet form {
  padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 14px;
}
.sheet form > header {
  display: flex; align-items: center; justify-content: space-between;
}
.sheet h2 { margin: 0; font-size: 1rem; font-weight: 800; }
/* 区画の見出し。操作パネルの h2 と同じ小さな大文字の帯で、同じものだと
   分かる。 */
.sheet h3 {
  margin: 0 0 8px; font-size: .7rem; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-3);
}
.sheet section { margin: 0; }

/* 「国道マップについて」 --------------------------------------------------
   出典はここに無い。地図の上の表示が一度だけ示している。 */
#about-dialog { width: min(480px, 92vw); }
.about-lead { margin: 0; font-size: .82rem; color: var(--ink-2); }
/* 考え方の但し書き。三つとも .fold で畳み、見出しだけを常に見せる。更新日時
   (.freshness)と同じ字の大きさにしてある。 */
.notes { display: flex; flex-direction: column; gap: 8px; }
.notes .fold > summary { min-height: 0; font-size: .78rem; font-weight: 600; color: var(--ink); }
.notes .fold[open] > summary { margin-bottom: 4px; }
.notes .fold span { display: block; font-size: .78rem; color: var(--ink-2); }

/* .mini の骨格を借りる。リンクなので、下線ではなくボタンの形で立たせる。 */
.about-links { display: flex; flex-wrap: wrap; gap: 8px; }
.mini.about-link {
  text-decoration: none;
  display: flex; align-items: center; gap: 7px;
  font-size: .78rem; padding: 7px 10px;
}
.mini.about-link:hover { border-color: var(--sign-blue); color: var(--sign-blue); }
.about-link svg { width: 14px; height: 14px; display: block; flex: 0 0 auto; }
.dialog-close {
  border: 0; background: none; cursor: pointer; line-height: 1;
  color: var(--ink-3); border-radius: 4px;
  display: grid; place-items: center; width: 32px; height: 32px;
  font-size: 1.7rem;
}
.dialog-close:hover { color: var(--ink); background: var(--panel-2); }

.share-url-row { display: flex; gap: 6px; }
/* ここだけは等幅のままにする。欄に入っているのは URL で、渡す前に 1 字ずつ
   確かめる物だからである。プロポーショナルでは l と 1 と I、0 と O が見分け
   にくい。桁を揃えるための等幅ではないので、tabular-nums では代われない。 */
.share-url-row input {
  flex: 1; min-width: 0; font: inherit; font-family: ui-monospace, Consolas, monospace;
  font-size: .76rem; padding: 6px 8px; background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: 3px;
}
/* コピー成功時は文言をチェックの印に差し替える。幅を固定しておかないと、
   文字列よりアイコンのほうが短いぶんボタンが縮んで隣の欄がずれる。 */
#share-copy {
  min-width: 58px; display: inline-flex; align-items: center; justify-content: center;
}
#share-copy svg, .share-text-btn svg { width: 14px; height: 14px; display: block; }
#share-copy.copied, .share-text-btn.copied { color: var(--success); border-color: var(--success); }

/* URL だけのコピーとは別に、SNS などへそのまま渡せる「タイトル + URL」の文章を
   渡す。対応環境では Web Share API の共有シートを開き、無ければ #share-copy と
   同じ「コピーしました」で伝える。.mini にクラスを重ねて詳細度を
   上げているので、記述順に頼らない。 */
.mini.share-text-btn {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  font-size: .78rem; padding: 7px 10px;
}

.share-summary { display: flex; flex-direction: column; gap: 9px; font-size: .8rem; }
.share-row { display: flex; gap: 10px; align-items: baseline; }
.share-row .lbl {
  flex: 0 0 72px; color: var(--ink-3); font-size: .68rem; font-weight: 700;
  letter-spacing: .06em;
}
.share-row .shields { display: flex; flex-wrap: wrap; gap: 3px; }
.share-row .all { color: var(--ink-2); }
.share-toggles {
  list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column;
  gap: 3px; color: var(--ink-2);
}
.share-toggles li::before { content: "✓ "; color: var(--sign-blue); }
.share-toggles li.off { color: var(--ink-3); }
.share-toggles li.off::before { content: "– "; color: var(--ink-3); }

@media (max-width: 860px) {
  #map-ui { left: 8px; top: 8px; }
  /* この幅では #brand の右に 300px を割く余地が無い。バーの下へ落とし、
     バーの右端(ボタン自身がある側)に揃える。 */
  #ext-popover { top: calc(100% + 8px); left: auto; right: 0; }
  /* 横に 340px を割く幅が無いので、詳細は幅いっぱいの帯にして下端へ置く。高さは
     中身に合わせ、上限は画面の高さの 42% か 240px の小さいほうにする。 */
  #detail {
    left: 8px; right: 8px; bottom: 8px; width: auto;
    max-height: min(42vh, 240px);
  }
  #legend-bar { left: 8px; right: 8px; }
  /* 詳細パネルはこの幅では下端に出て凡例と場所を取り合うので、
     開いているあいだは凡例を隠す。 */
  #app.detail-open #legend-bar { display: none; }
}

/* 更新履歴のページ --------------------------------------------------------
   web/changelog.html だけが使う。地図とは別の 1 枚だが、色も書体も余白も上と
   同じ物を借りる。ここに要るのは読み物としての骨格だけである。

   html, body の height: 100% は地図が画面いっぱいを占めるための指定で、縦に
   伸びるこのページには合わない。ここだけ解く。 */
body.changelog { height: auto; }
.log { max-width: 720px; margin: 0 auto; padding: 26px 20px 64px; }
.log-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
/* ダイアログの見出し(.sheet h2)と同じ大きさにする。地図から来た人に、同じ
   ものの続きだと分かる。 */
.log-head h1 { margin: 0; font-size: 1rem; font-weight: 800; }
.mini.log-back {
  text-decoration: none; font-size: .78rem; padding: 5px 10px; flex: 0 0 auto;
}
.mini.log-back:hover { border-color: var(--sign-blue); color: var(--sign-blue); }

/* 1 日ぶんが 1 区画。狭い画面では日付を見出しにして、その下へ変更をぶら下げる。
   広い画面では日付を左の欄へ出し、日付が縦一列に並ぶ形にする(下の @media)。
   境目の 640px は、日付の欄 8rem を引いても本文が窮屈にならない幅である。 */
.log-day { padding: 16px 0; border-top: 1px solid var(--line-2); }
.log-day:first-of-type { border-top: 0; }
.log-date {
  margin: 0 0 8px; font-size: .78rem; font-weight: 400;
  color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.log-items {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.log-items > li { color: var(--ink-2); }
.log-items b { color: var(--ink); font-weight: 700; }
/* 本文の中のリンク。いまは書体の名前(LINE Seed JP)だけが使う。下の
   .log-commit と違い、地の文に混ざるので下線で示す。 */
.log-link { color: var(--sign-blue); text-decoration-thickness: 1px; }
.log-link:visited { color: var(--sign-blue); }
.log-link:hover { color: var(--ink); }

/* コミットの短い名前。共有ダイアログの URL 欄と同じ等幅にする。1 字ずつ突き
   合わせる字だからである。 */
.log-commit {
  font-family: ui-monospace, Consolas, monospace;
  font-size: .72em; color: var(--sign-blue); text-decoration: none;
  border-bottom: 1px solid currentcolor; margin-left: .4em;
  white-space: nowrap;
}
.log-commit:visited { color: var(--sign-blue); }
.log-commit:hover { color: var(--ink); }

@media (min-width: 640px) {
  .log-day {
    display: grid; grid-template-columns: 8rem 1fr; gap: 0 20px;
    align-items: start;
  }
  /* 左の欄に移るので、下の余白は要らない。 */
  .log-date { margin: 0; padding-top: .1em; }
}
