@import url("/shell/assets/ops-tokens.css");

/* ==================================================================
   ops-dashboard 共通スタイル (2026-09-13、全面刷新)
   ==================================================================
   ★手本は claude.ai の画面: 生成りの背景・濃い文字・強調は橙 1 色・囲みなし・
     広い余白・左に細い一覧。会社のパソコンで開いても普通の管理画面に見える。
   ★★**1 組だけ。** シェルと 4 モジュール (監視・取引・配信・記録) の iframe は
     このファイルを **URL で読む**。各リポジトリに CSS を複製しない・独自の CSS を
     書かない。色・余白・フォントは ops-tokens.css の変数 1 か所で決める
     (このファイルには生の色を書かない)。
   ★★**部品はここに置く** (今の一行 / 数字の行 / ボタン / 畳んだ区画 /
     お知らせの帯 / 浮き枠 / 表)。ページ側はデータを入れるだけ。
   ================================================================== */
* { box-sizing: border-box; margin: 0; padding: 0; }
/* ★hidden 属性は UA の [hidden]{display:none} に任せる。**global で !important の
   押さえは置かない** —— 置くと、モジュールが自前の [hidden] の押さえの有無を
   確かめる検査 (取引の verify_screen_render の負の対照) が空振りになる。
   display 規則を持つ要素 (.btn / .info / #offline など) を hidden で隠したいときは、
   そのページ側で `#id[hidden]{display:none}` のように**その要素だけ**を押さえるか、
   JS で style.display を切り替える。 */
body {
  background: var(--bg); color: var(--fg);
  font-family: var(--font); font-size: 15px; line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
::selection { background: color-mix(in srgb, var(--accent) 22%, transparent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
button, a, summary {
  transition: color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              background-color var(--t-fast) var(--ease);
}
h1, h2, h3 { font-family: var(--display); font-weight: 600; }
.mono, .num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.dim, .faint { color: var(--muted); }
.faint { font-size: 13px; }

.fade-in { animation: fade-in .3s ease-out both; }
@keyframes fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ==================================================================
   状態の目印 (色 + 形。色を区別できなくても形で読める。2026-09-09 の約束を継ぐ)
   ● 正常 ／ ▲ 注意 ／ ■ 異常 ／ ○ 停止中 (中空) ／ ◇ 不明
   ================================================================== */
.st-NORMAL  { --st: var(--ok); }
.st-WARNING { --st: var(--warn); }
.st-ERROR   { --st: var(--err); }
.st-STOPPED { --st: var(--stopped); }
.st-UNKNOWN { --st: var(--unknown); }

.badge {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 2px 10px; font-size: 12.5px; font-weight: 600;
  color: var(--st); background: transparent;
}
.badge::before {
  content: ""; width: 9px; height: 9px; flex: none;
  background: var(--st); border-radius: 50%;
}
.st-ERROR   .badge::before, .badge.st-ERROR::before   { border-radius: 1px; }         /* ■ */
.st-STOPPED .badge::before, .badge.st-STOPPED::before { background: transparent;
  border: 1.5px solid var(--st); }                                                     /* ○ */
.st-UNKNOWN .badge::before, .badge.st-UNKNOWN::before { transform: rotate(45deg);
  border-radius: 1px; }                                                                /* ◇ */
.st-WARNING .badge::before, .badge.st-WARNING::before {                                /* ▲ */
  width: 0; height: 0; background: transparent; border-radius: 0;
  border-left: 5px solid transparent; border-right: 5px solid transparent;
  border-bottom: 9px solid var(--st);
}
.badge.changed { animation: pulse .6s var(--ease-out) 1; }
@keyframes pulse { 0% { background: color-mix(in srgb, var(--st) 20%, transparent); } 100% { background: transparent; } }

/* ---- 状態の点 (lamp)。文字でなく色の点で出す (2026-09-18、人の指示 2・3) ----
   ★★**1 組だけ。** 使う所は 2 つ: (1) 左の一覧の各ページの点 (shell.js)、
     (2) AI自動売買の TOP と取引タブ (ops-core の watch が出す HTML): 先頭 (#now) に全体の重さの点 1 つ (名前「全体」)、
         本文の「四色」の節 (#colors) に feed・trade・watch・db の点 4 つ (2026-09-18、人の指示「点の規則」)。
     どちらもページ側は状態の class を付けるだけ。**色は --st だけから取る** (直書きしない)。
   ★形: 丸い点。**停止中 (st-STOPPED) は中空の輪** —— 左の一覧の点の従来の見え方と同じ。
   ★型: <span class="lamp-cell st-NORMAL"><i class="lamp"></i><span class="lamp-nm">feed</span></span>
     を .lamps で横に並べ、黄・赤・未判定があるときだけ、その右に 1 行 (.now-line) を置く。 */
.lamp {
  width: 8px; height: 8px; flex: none; border-radius: 50%;
  background: var(--st, var(--muted));
}
.st-STOPPED > .lamp { background: transparent; border: 1.5px solid var(--st, var(--muted)); }
/* 点を横に並べる入れ物。★点は縮めず (flex:none)、右の 1 行が残りの幅で折り返す
   (狭い幅でもページは横に溢れない。min-width:0 と overflow-wrap:anywhere が要る)。 */
.lamps { display: flex; align-items: center; gap: 16px; }
.lamps > .now-line { flex: 1 1 0; min-width: 0; overflow-wrap: anywhere; word-break: break-word; }
.lamp-cell { display: flex; flex-direction: column; align-items: center; gap: 5px; flex: none; }
.lamp-cell > .lamp { width: 14px; height: 14px; }
/* 点の下の小さな名前。1 行のまま (feed/trade/watch/db が縦に割れない) */
.lamp-nm { font-size: 12px; line-height: 1.2; color: var(--muted); white-space: nowrap; }
/* 点の下に置く 1 行 (取引タブの「段階: …」)。ページ側で余白を書かない */
.lamps + .now-line { margin-top: 10px; }

/* 2 段目の再起動の目印 (3 値) */
.second.mk-green  { color: var(--ok); }
.second.mk-yellow { color: var(--warn); }
.second.mk-red    { color: var(--err); }

/* ---- 更新ハイライト (値が変わった箇所を一瞬だけ) ---- */
.flash { animation: flash var(--t-slow) var(--ease) 1; }
@keyframes flash {
  0%   { background: color-mix(in srgb, var(--accent) 16%, transparent); }
  60%  { background: color-mix(in srgb, var(--accent) 10%, transparent); }
  100% { background: transparent; }
}
.flash-num { animation: flashnum var(--t-slow) var(--ease) 1; }
@keyframes flashnum { 0%,55% { color: var(--accent); } 100% { color: inherit; } }
.ops-changed { animation: ops-changed .3s ease-out 1; }
@keyframes ops-changed { from { opacity: .35; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .badge.changed, .flash, .flash-num, .fade-in, .ops-changed { animation: none; }
  * { transition: none !important; }
}

/* 更新リング */
.ring { width: 20px; height: 20px; flex: none; transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 2.5; }
.ring .bg { stroke: var(--line); }
.ring .fg { stroke: var(--accent); stroke-linecap: round; transition: stroke-dashoffset 1s linear; }

.ic { width: 18px; height: 18px; flex: none; }

/* ==================================================================
   ページの骨 (主画面は 今の一行 → 数字の行 → 操作 → 詳細)
   ================================================================== */
.page { max-width: var(--maxw); margin: 0 auto; padding: var(--pad-page) var(--pad-page) 64px; }
@media (max-width: 640px) { .page { padding: 20px 16px 56px; } }
/* ★区画の間隔は子孫で当てる (取引 v2 のように section を view の div で包んでも
   同じ間隔になるように。2026-09-13、本人指示: ページ側で間隔を変えない)。 */
.page section { padding: var(--pad-card); }
.page section + section { border-top: var(--hairline) solid var(--line); }
.sec-label { font-size: var(--label-size); color: var(--muted); margin-bottom: 12px; }
/* ★全ページ共通の見出し (大きさ・余白を 1 か所で決める。ページ側に書かない) */
.page > h1 { font-size: 20px; margin: 0 0 4px; font-weight: 600; }
/* 数字の行: API が alert=true を返した値を赤くする (ページ側の inline 色をやめる) */
.numrow .val.alert, .numrow .lbl .alert { color: var(--err); font-weight: 600; }
/* 縦に積む一般の間隔 (ページ側の inline margin をやめる) */
.stack > * + * { margin-top: 8px; }
.mt { margin-top: 16px; }
.mt-s { margin-top: 8px; }
/* 記録の回顧の 1 件 (v2)。薄い横線で区切る (ページ側に inline を書かない) */
.retro-item { padding: 8px 0; border-top: var(--hairline) solid var(--line-2); }

/* ---- 今の一行 ---- */
.now-line { font-size: 17px; line-height: 1.5; }
.now-line.act { color: var(--err); font-weight: 600; }   /* 人が今すぐ動くときだけ赤 */

/* ダッシュボードの一覧 (各ページの「今の一行」を並べる) */
.now-list { display: flex; flex-direction: column; }
.now-item {
  display: flex; align-items: baseline; gap: 14px;
  padding: 14px 4px; border: 0; background: none; width: 100%; text-align: left;
  color: var(--fg); font: inherit; cursor: pointer;
  border-bottom: var(--hairline) solid var(--line);
}
.now-item:hover { background: var(--hover); }
.now-item .nm { font-weight: 600; min-width: 8.5em; }
/* ★min-width:0 と overflow-wrap:anywhere: 長い切れない語 (webmin.satamasatada.com など) でも行の中で折り返し、狭い幅で横に溢れない。
   flex の子は min-width:auto で中身より縮まない (2026-09-15 の全体の TOP が 390 幅で scrollW 403、人の指示 11 通目) */
.now-item .msg { color: var(--muted); flex: 1; min-width: 0; overflow-wrap: anywhere; }
.now-item.act .msg { color: var(--err); font-weight: 600; }

/* ---- 数字の行 (左=名前+小さな補足 / 中央=細い横棒 1 色 / 右=数値+小さな単位) ---- */
.numrow {
  display: grid; grid-template-columns: minmax(9em, 15em) 1fr auto;
  align-items: center; gap: 16px; padding: 11px 0;
}
.numrow + .numrow { border-top: var(--hairline) solid var(--line-2); }
.numrow .lbl { display: flex; flex-direction: column; gap: 1px; }
.numrow .lbl .sub { font-size: 12px; color: var(--muted); }
.numrow .bar { height: 6px; border-radius: 999px; background: var(--track); overflow: hidden; }
.numrow .bar > i { display: block; height: 100%; border-radius: 999px; background: var(--accent); }
/* 上限を超えた使用の棒 (AI自動売買の取引の画面の予算、2026-09-17、人の指示「並べ替え」A の 1)。超えたのは異常なので状態色の赤 */
.numrow .bar > i.over { background: var(--err); }
.numrow .val { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 17px; white-space: nowrap; }
.numrow .val .unit { font-size: 12px; color: var(--muted); margin-left: 3px; }
/* 棒を出さない数字 (単なる件数など) は中央を空ける */
.numrow.nobar .bar { background: none; }
/* ★狭い幅では数字の行を折り返す (長い値=GPU 名や「… 使用(空き…)」で横に溢れないように)。
   名前と値を上段・細い横棒を下段に回し、値は列の中で折り返す。
   ★この規則は必ず base の .numrow .val (white-space:nowrap) より後に置く。
     前に置くと同じ詳細度で base が勝ち、値が折り返さず横に溢れた (2026-09-13、実測で直した)。 */
@media (max-width: 640px) {
  .numrow { grid-template-columns: minmax(0, 1fr) minmax(0, auto); align-items: baseline; }
  .numrow .val { white-space: normal; overflow-wrap: anywhere; word-break: break-word;
    max-width: 60vw; font-size: 15px; }
  .numrow .bar { grid-column: 1 / -1; order: 2; margin-top: 6px; }
}
/* ★入力欄やボタンを持つ数字の行 (AI自動売買 の予算の上限) は、どの幅でも値を折り返す (2026-09-21)。
   値は「使用 x / 上限 y / 残り z USD」+ 入力欄 + ボタンで、1 行に並べると約 520px。
   640px より広く 1000px より狭い幅では上の @media が効かず、頁が数 px 横に溢れていた (700px で 703>700 を実測)。
   中の語は それぞれの span が nowrap を持つので、語の中では割れない。 */
.numrow .val:has(input, button) { white-space: normal; }

/* ---- 操作 (ボタン 1 種類。同じ大きさ・同じ色。危険を色で区別しない) ---- */
.ops { display: flex; flex-wrap: wrap; gap: 10px; }
/* ★高さは入力欄と同じ 1 つの値 --ctl-h (2026-09-17、人の指示の追記 B-2・B-4)。縦の余白は使わず、文字は 1 行 */
.btn, button.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  box-sizing: border-box; height: var(--ctl-h); padding: 0 16px; line-height: 1.2; white-space: nowrap; min-width: 8em;
  background: var(--surface); color: var(--fg);
  border: var(--hairline) solid var(--line); border-radius: var(--radius);
  font: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
}
.btn:hover { border-color: var(--accent); color: var(--accent); background: var(--surface); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }
.btn.arm { color: var(--accent); border-color: var(--accent); }   /* 2 回押しの 1 回目の後 */
.btn.busy { color: var(--muted); cursor: progress; }
.btn .prog { font-family: var(--mono); font-size: 12px; color: var(--muted); font-weight: 400; }
/* ★危険な操作を色で区別しない。danger は色を足さない (名前は残す) */
.btn.danger { border-color: var(--line); color: var(--fg); }
.btn.danger:hover { border-color: var(--accent); color: var(--accent); }
/* 表のます等に置く小さめの同じボタン (色・形は共通。大きさだけ小さい) */
.btn.sm { min-width: 6em; padding: 0 12px; font-size: 13px; }   /* 高さは .btn と同じ --ctl-h (横の余白と文字だけ小さい) */

/* ---- 詳細 (畳んだ区画。開くまで見えない) ---- */
details.box { border-radius: var(--radius); background: transparent; }
details.box > summary {
  list-style: none; cursor: pointer; padding: 10px 0; color: var(--muted);
  display: flex; align-items: center; gap: 8px; font-size: 14px;
}
details.box > summary::-webkit-details-marker { display: none; }
details.box > summary::before { content: "▸"; color: var(--muted); font-size: 12px; }
details.box[open] > summary::before { content: "▾"; }
details.box > .body { padding: 6px 0 14px; }
/* 長い文を 2 行で畳む (押すと開く) */
.clamp { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; }
details.line > summary { list-style: none; cursor: pointer; }
details.line > summary::-webkit-details-marker { display: none; }
details.line[open] .clamp { -webkit-line-clamp: unset; }
/* ★長い文は列の中で折り返す (途中で切れて横スクロールを出さない。2026-09-13、item 4)。 */
.clamp { overflow-wrap: anywhere; word-break: break-word; }
/* 記録の表 (2026-09-13、人の指示で改め):
   ★折り返すのは理由・本文の列 (.wrap) だけ。短い列 (#・時刻・結果・種類 など) は
     1 行のまま折り返さない (数字や単語が縦に割れない)。列幅は中身に合わせる (auto)。
   ★2026-09-21 まで: 狭い幅では表を .scroll-x が横に送っていた。いまは下の @media が行を縦に積むので送らない。 */
.rec-tbl { width: 100%; }
.rec-tbl td, .rec-tbl th { white-space: nowrap; }
.rec-tbl td.wrap, .rec-tbl th.wrap {
  white-space: normal; overflow-wrap: anywhere; word-break: break-word; text-align: left; }
/* ★記録の表のますは本文と同じ書体・大きさ・濃さ (2026-09-20、人の指示 3
     「予算のモデル別の表・建玉・意図・有効な起床条件・影の結果の表は、等幅の小さい灰色の文字をやめ、
      他の画面の本文と同じ書体・大きさ・濃さにする。数字 (#・価格・時刻) だけ等幅のままでよい」)。
     共通の table は既定で全ますを var(--mono) 13.5px にするので、ここで本文に戻す (遮断の一覧 .ban-tbl と同じ形)。
     等幅で残すますは ops-core の watch/web.py の table(..., mono=(列の番号,)) が .mono を付ける。 */
.rec-tbl td { font-family: var(--font); font-size: 15px; }
.rec-tbl td.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* ★狭い幅では行を縦に積む (2026-09-21、人の指示「表を横に伸ばすのをやめ、画面の幅に収める。
     狭い画面では列を減らすのではなく行を縦に積む形にしてよい」)。
   横に送る (.scroll-x) と、表の右の列が画面の外に出て、指で横に動かさないと読めなかった。
   積んだときの見出しは ます の data-label (ops-core の watch/web.py の table が付ける)。列は 1 つも減らさない。
   ★区切りは表の入った箱の幅で決まる: モジュールは iframe の中の独立した文書なので、
     この @media は iframe の幅 (= 表の箱の幅) を見る (ブラウザの窓の幅ではない)。
   ★1000px: 積む前の幅で表が箱に収まる所まで上げた。記録の「道具」は折り返さない 3 列だけで約 590px 在り、
     長い文の 2 列の最小の幅 (10em = 120px ずつ) を足すと約 830px。箱 968px (窓 1000px) なら収まる。
     本物の殻では、モジュールは左の一覧 (232px) の右の iframe に入るので、窓 1280px → iframe 約 1048px → 列のまま。 */
@media (max-width: 1000px) {
  .rec-tbl, .rec-tbl tbody, .rec-tbl tr, .rec-tbl td { display: block; width: auto; }
  .rec-tbl thead { display: none; }
  .rec-tbl tr { padding: 10px 0; border-bottom: var(--hairline) solid var(--line-2); }
  .rec-tbl tr:last-child { border-bottom: 0; }
  .rec-tbl td, .rec-tbl td.wrap {
    border: 0; padding: 1px 0; text-align: left;
    white-space: normal; overflow-wrap: anywhere; word-break: break-word; }
  .rec-tbl td::before {
    content: attr(data-label); display: block;
    font-family: var(--font); font-size: 12px; color: var(--muted); }
  .rec-tbl td:empty { display: none; }
}

/* 遮断の一覧の表: 縞なし・薄い横線 1 本 (共通の表と同じ)。
   ★等幅は IP・時刻・残り時間の列 (.mono) だけ。他は本文のフォント
     (共通の table は既定で全ますを等幅にするので、ここで本文に戻す。2026-09-13)。 */
.ban-tbl td { font-family: var(--font); }
.ban-tbl td.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* ---- お知らせの帯 (薄い灰色の角丸 + 小さな i)。赤い帯は使わない ---- */
.info {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 14px; border-radius: var(--radius);
  background: var(--info-soft); color: var(--fg); font-size: 14px; max-width: 72ch;
}
.info::before {
  content: "i"; flex: none; width: 18px; height: 18px; border-radius: 50%;
  background: var(--muted); color: var(--surface); font-size: 12px; font-weight: 700;
  font-style: italic; display: flex; align-items: center; justify-content: center;
  line-height: 1;
}
.info b { font-weight: 600; }
.info code { font-family: var(--mono); font-size: 12.5px; }
/* 旧 .callout / .note / .stale-banner を .info の系統に寄せる (囲みや帯色を持たせない) */
.callout { padding: 12px 14px; border-radius: var(--radius); background: var(--info-soft);
  color: var(--fg); font-size: 14px; max-width: 72ch; margin-top: 12px; }
.callout b { font-weight: 600; } .callout code { font-family: var(--mono); font-size: 12.5px; }
.note { color: var(--muted); font-size: 13px; margin: 6px 0 0; }
.err { color: var(--err); font-size: 14px; }
.warn { color: var(--warn); }
.ok { color: var(--ok); }
.stale-banner { padding: 10px 14px; border-radius: var(--radius);
  background: var(--info-soft); color: var(--fg); font-size: 13px; }

/* ---- 浮き枠 (確認・メニュー): 角丸の白、行は図記号+文字、区切りは薄い線 1 本 ---- */
.popup {
  background: var(--surface); border-radius: var(--radius);
  border: var(--hairline) solid var(--line); padding: 6px; min-width: 220px;
}
.popup .row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 9px 10px; border: 0; background: none; color: var(--fg); font: inherit;
  cursor: pointer; border-radius: var(--radius-sm);
}
.popup .row:hover { background: var(--hover); }
.popup .row + .row { border-top: var(--hairline) solid var(--line); }
.popup .row .ic { color: var(--muted); }

/* ---- 表 (白地・薄い横線・数字は右寄せ)。囲みなし ----
   ★見出し行に灰色の下地を敷かない。白地に薄い横線 1 本だけ (2026-09-13、本人指示)。
     表の地は透明 (ページの白に乗る)。 */
.tbl, table { width: 100%; border-collapse: collapse; background: transparent; }
.tbl thead th, table thead th {
  font-size: 12px; font-weight: 600; color: var(--muted); background: transparent;
  padding: var(--pad-cell); text-align: right; white-space: nowrap;
  border-bottom: var(--hairline) solid var(--line);
}
.tbl thead th:first-child, table thead th:first-child,
.tbl tbody td:first-child, table tbody td:first-child { text-align: left; }
.tbl tbody td, table tbody td {
  padding: var(--pad-cell); border-bottom: var(--hairline) solid var(--line-2);
  text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 13.5px; vertical-align: top;
}
.tbl tbody tr:hover, table tbody tr:hover { background: var(--hover); }
.tbl tbody tr.on, table tbody tr.on { background: var(--hover); }
/* ★.scroll-x は「送る」ためではなく「はみ出しを測れるようにする」ために残す (2026-09-21)。
   記録の表は、広い幅では列が箱に収まり、狭い幅では上の @media が行を縦に積むので、送る先はもう無い。
   ここを overflow: clip にすると scrollWidth が clientWidth と同じになり、
   型の関門 (表の右端の切れ) と検査 (横スクロールが出ない) が、本当にはみ出していても緑になってしまう。 */
.scroll-x { overflow-x: auto; }
/* 列の寄せ (文字の列は左・数字と時刻の列は右)。共通の右寄せ既定より強く効かせる。 */
.tbl td.l, .tbl th.l, .ban-tbl td.l, .ban-tbl th.l,
table td.l, table th.l { text-align: left; }
.tbl td.r, .tbl th.r, .ban-tbl td.r, .ban-tbl th.r,
table td.r, table th.r { text-align: right; }

/* ---- タブ・チップ (記録ページの種類の切り替え) ---- */
.tabs { display: flex; flex-wrap: wrap; gap: 4px 18px; }
/* ★文字と下線だけ (青い丸いボタンはやめた。2026-09-13、人の指示)。
   選択中は文字色 (強調) と下線。背景・角丸・囲みは持たない。 */
.tab, .chip {
  background: none; border: 0; border-radius: 0; color: var(--muted);
  cursor: pointer; font: inherit; font-size: 14px; padding: 6px 2px;
  border-bottom: 2px solid transparent;
}
.tab:hover, .chip:hover { color: var(--fg); background: none; }
.tab.on, .chip.on, .tab.is-on, .chip.is-on, .tab[aria-selected="true"] {
  color: var(--accent); background: none; border-bottom-color: var(--accent);
}

/* ---- 入力欄 ---- */
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-size: 13px; color: var(--muted); }
.field input, .field select, .field textarea,
input[type="text"], input[type="number"], input[type="search"], input[type="password"],
select, textarea {
  background: var(--surface); border: var(--hairline) solid var(--line);
  border-radius: var(--radius); color: var(--fg); font: inherit; font-size: 15px;
  padding: var(--pad-field);
}
/* ★1 行の入力欄と選択はボタンと同じ高さ --ctl-h (2026-09-17、人の指示の追記 B-2・B-4)。textarea は複数行なので高さを決めない */
.field input, .field select,
input[type="text"], input[type="number"], input[type="search"], input[type="password"], select {
  box-sizing: border-box; height: var(--ctl-h); padding-top: 0; padding-bottom: 0; line-height: 1.2;
}

/* ---- 見出し・空・件数 ---- */
.mod-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 4px 0 16px; }
.mod-head h1 { font-size: 20px; margin: 0; font-weight: 600; }
.head-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.empty { text-align: center; padding: 40px 20px; color: var(--muted); }
.count { font-size: 12px; color: var(--muted); }

/* ---- 明滅する印 (動いていることを示すときだけ) ---- */
.pulse-dot { width: 8px; height: 8px; border-radius: 50%;
  background: var(--st, var(--accent)); position: relative; flex: none; }
.pulse-dot::after { content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: var(--st, var(--accent)); animation: pulse-ring 2.4s ease-out infinite; }
@keyframes pulse-ring { 0% { transform: scale(1); opacity: .5; } 100% { transform: scale(3.2); opacity: 0; } }
.pulse-dot.is-idle { background: var(--muted); }
.pulse-dot.is-idle::after { animation: none; opacity: 0; }
@media (prefers-reduced-motion: reduce) { .pulse-dot::after { animation: none; opacity: 0; } }

/* 旧レイアウト互換 (取引などが .card を箱として使う): 囲みを外し、余白と薄い線に) */
.card { background: transparent; border: 0; border-radius: 0; padding: var(--pad-card);
  overflow-x: auto; min-width: 0; }
.card + .card { border-top: var(--hairline) solid var(--line); }
.card h2 { font-size: 15px; font-weight: 600; color: var(--fg); margin-bottom: 12px; }
:root { --card-scroll-cap: min(52vh, 520px); --card-scroll-cap-short: min(30vh, 280px); }

/* ==================================================================
   シェルの骨 (左に細い一覧 + 主画面)。index.html だけが使う。
   モジュールの iframe には aside/main が無いので当たらない。
   ================================================================== */
body.shell { display: grid; grid-template-columns: 232px 1fr; min-height: 100vh; }
.shell aside { background: var(--bg); border-right: var(--hairline) solid var(--line);
  display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh; }
.shell .brand { padding: 20px 18px 10px; font-weight: 700; font-size: 15px; }
.shell .brand span { color: var(--accent); }
.shell nav { flex: 1; overflow-y: auto; padding: 6px 8px 20px; }
.shell .cat { font-size: 12px; color: var(--muted); padding: 16px 12px 4px; }
.shell .item { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 9px 12px; border: 0; background: transparent; color: var(--fg); font: inherit;
  font-size: 14.5px; cursor: pointer; border-radius: var(--radius-sm); }
.shell .item:hover { background: var(--hover); }
.shell .item[aria-current="page"] { background: var(--hover); color: var(--accent); font-weight: 600; }
.shell .item.stopped { color: var(--muted); }
/* ★点は共通部品 .lamp (2026-09-18、人の指示 3)。ここは置き場所だけを決める
   (大きさ・色・停止中の中空は上の .lamp / .st-STOPPED > .lamp の 1 組)。
   旧 .dot の規則は消した —— 一覧の外に .dot を使う所は無い (grep で確認)。 */
.shell .item .lamp { margin-left: auto; }
.shell .item .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shell .item .ic { color: var(--muted); }
.shell .item[aria-current="page"] .ic { color: var(--accent); }
.shell .side-foot { padding: 12px 12px 16px; border-top: var(--hairline) solid var(--line); }
.shell .side-foot form { margin: 0; }
.shell .side-foot button, .shell .side-foot a { display: flex; align-items: center; gap: 8px;
  width: 100%; padding: 8px 10px; border: 0; background: none; color: var(--muted);
  font: inherit; font-size: 13px; cursor: pointer; border-radius: var(--radius-sm); }
.shell .side-foot button:hover, .shell .side-foot a:hover { background: var(--hover);
  color: var(--fg); text-decoration: none; }
.shell .myip { padding: 8px 10px; display: flex; flex-direction: column; gap: 2px; }
.shell .myip[hidden] { display: none; }
/* 「一番上へ」(to-top.js と ops-core の watch、2026-09-24): .btn の display:inline-flex が UA の [hidden] に勝つので、この要素だけを押さえる */
#to-top[hidden] { display: none; }   /* 取得前は隠す (display:flex を上書き) */
.shell .myip-lbl { color: var(--muted); font-size: 12px; }
.shell #myip-val { color: var(--muted); font-size: 12px; word-break: break-all; font-family: var(--mono); }
.shell main { display: flex; flex-direction: column; min-width: 0; }
.shell header { display: flex; align-items: center; gap: 14px; padding: 14px 24px;
  border-bottom: var(--hairline) solid var(--line); }
.shell header h1 { font-size: 17px; margin: 0; font-weight: 600; }
.shell .spacer { flex: 1; }
.shell .stale { color: var(--warn); font-size: 12px; }
.shell .content { flex: 1; }
.shell iframe { flex: 1; width: 100%; border: 0; background: var(--bg); min-height: 0; }
.shell .burger, .shell .hdr-brand, .shell .scrim { display: none; }

@media (max-width: 768px) {
  body.shell { grid-template-columns: 1fr; }
  .shell aside { position: fixed; top: 0; left: 0; bottom: 0; z-index: 40;
    width: min(84vw, 300px); height: 100dvh; transform: translateX(-100%);
    transition: transform .18s ease; border-right: var(--hairline) solid var(--line); }
  body.shell.nav-open aside { transform: translateX(0); }
  body.shell.nav-open .scrim { display: block; position: fixed; inset: 0; z-index: 30;
    background: color-mix(in srgb, var(--fg) 30%, transparent); }
  .shell .burger { display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; flex: none; background: none; border: 0; color: var(--fg);
    padding: 0; cursor: pointer; }
  .shell .burger svg { width: 24px; height: 24px; }
  .shell .hdr-brand { display: inline; font-size: 14px; color: var(--muted); flex: none; }
  .shell .hdr-brand span { color: var(--accent); }
  .shell header { padding: 10px 12px; gap: 10px; }
  .shell header h1 { font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
  .shell #updated { font-size: 11px; flex: none; }
  .shell .side-foot { margin-top: auto; }
  .page { padding: 18px 14px 48px; }
}
@media (prefers-reduced-motion: reduce) { .shell aside { transition: none; } }

/* ==================================================================
   ページ/モジュール固有の小片を共通の 1 か所に集める (2026-09-13、人の指示)。
   ★各ページ・各モジュールは独自の CSS (<style> や mod.css の規則) を書かない。
     ここに置き、生の色は使わず変数だけを使う。
   ================================================================== */
/* サーバー: オフラインの覆い */
#offline { position: fixed; inset: 0; background: var(--bg); z-index: 9999;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; text-align: center; }
#offline[hidden] { display: none; }
.offline-title { font-size: 22px; font-weight: 600; }

/* ログイン */
body.login { display: grid; place-items: center; min-height: 100vh; padding: 20px; }
.login-wrap { width: min(360px, 92vw); display: flex; flex-direction: column; gap: 16px; }
.brand-lg { font-size: 22px; font-weight: 700; }
.brand-lg span { color: var(--accent); }
.btn.full { width: 100%; background: var(--accent); color: var(--bg); border-color: var(--accent); }
.btn.full:hover { color: var(--bg); background: var(--accent); border-color: var(--accent); filter: brightness(1.06); }
.recover { font-size: 14px; }
.recover form { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.recover .btn { width: 100%; }

/* パスキー */
.page.narrow { max-width: 560px; }
.msg { margin: 10px 0 0; font-size: 13px; color: var(--muted); }
.msg.err { color: var(--err); }
ol.codes { font-family: var(--mono); font-size: 16px; letter-spacing: .06em;
  columns: 2; padding-left: 1.6em; margin-top: 8px; }
.info[hidden] { display: none; }

/* 監視: 国旗・接続元IP の印 (状態の色 --warn/--err は使わない) */
.cc { display: inline-flex; align-items: center; gap: 6px; }
.flag { width: 18px; height: 13px; object-fit: cover; border-radius: 2px; flex: none; }
.tbl tbody tr.me td, table tbody tr.me td { color: var(--fg); }
.tbl tbody tr.me, table tbody tr.me { box-shadow: inset 2px 0 0 var(--accent); }
.viewer-note { color: var(--muted); border-left: 2px solid var(--line);
  padding-left: 10px; margin: 0 0 10px; font-size: 13px; }

/* 配信: いま流れている曲 */
tr.playing td { color: var(--accent); }

/* ★「AI の文」の頁の上の「⚠️ Claude に貼れません」の印 (.paste-mark) は 2026-09-29 に外した (本人の決定。画面の文の形を普通の文と「項目: 値」に揃えた) */
