/* 📉価格ウォッチ（js/price-watch.js） */

/* ============================================================
   在庫の価格推移（📦 在庫管理 › 📉 価格推移）
   ============================================================ */
/* 棚卸が「月に1度の断面」なのに対して、ここは毎日の線。**主役は12枚の小さなカード**
   ＝12商品の線を1枚に重ねても金額の桁がばらばら（789円〜13,000円）で読めない。
   1商品1枚にして「いまいくらで、安いのか高いのか」だけを出し、詳しくは押して見る。 */
/* 見出しは**役割の違う2段**＝上は取り込みの話（文と、その操作）、下は一覧を触る道具。
   以前は1行に3種類の道具を詰めていて、左の文が1行増えただけで道具が折れ、高さの合わない
   余白ができた。段ごとに「左に文/見せ方・右に操作/追加」で両端に揃える */
.ipx-head {
  position: relative;   /* トーストと浮かぶ一覧の基準（出入りで並びを動かさない） */
  display: flex; align-items: center; justify-content: space-between; gap: 10px 16px; flex-wrap: wrap;
  margin-bottom: 14px; padding-bottom: 14px;
  border-bottom: 1px solid var(--color-border);   /* 商品ページでも一覧でも、見出しの区切りはこの1本 */
}
.ipx-head-txt { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ipx-head-fetch, .ipx-head-add { display: flex; align-items: center; gap: 10px; }
.ipx-head-fetch { margin-left: auto; }
/* 道具の段は線を引かない＝見出しの線と2本続かない（下のグループの箱が区切りになる）。
   直後の箱が借り物の上余白（.mst-group--section の 24px）を持つと、道具の上下で間隔が
   揃わない＝ここでは消して、道具の段の下の 14px だけにする */
.ipx-toolbar + * { margin-top: 0; }
.ipx-toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  margin-bottom: 14px;
}
.ipx-head-add { margin-left: auto; }

/* ── 取り込みの知らせ（見出しの下）────────────────────────────
   重さの違う2つを見た目で分ける。**色を持つのは回そのものの失敗だけ**（普段は出ない＝
   出た日は見落とさせない）。商品ごとの「取れていない」は状態であって警告ではないので、
   札と同じ灰色の世界に置き、既定は畳んだピル1つ。 */
.ipx-notes { display: flex; flex-direction: column; gap: 10px; margin: 0 0 14px; }

.ipx-alert {
  --ipx-amber: var(--color-warning);
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 16px;
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--ipx-amber) 9%, var(--color-surface));
  border: 1px solid color-mix(in srgb, var(--ipx-amber) 38%, transparent);
  /* 左の1本で「これは知らせ」と言う＝箱全体を塗らずに重さを出す */
  box-shadow: inset 3px 0 0 var(--ipx-amber);
}
.ipx-alert-ico {
  flex: none; display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: var(--radius-circle);
  color: var(--color-warning-text);
  background: color-mix(in srgb, var(--ipx-amber) 18%, transparent);
}
.ipx-alert-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding-top: 4px; }
.ipx-alert-ttl { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--color-text); }
.ipx-alert-txt { font-size: var(--text-xs); color: var(--color-text-muted); line-height: 1.6; }

/* ── 取れていない商品：見出しの2行目の引き金＋真下に浮かぶ一覧 ──────────
   **前回の取り込みの結果**なので「最終取得」の隣に置く（見出しの下に独立した段を作らない）。
   状態であって警告ではない＝既定は灰色。**琥珀は「手を入れないと戻らない」札（リンク切れ・
   読めない）がある時だけ**＝色の意味を「あなたの操作が要る」1つに絞る（毎日出る在庫切れで
   色を使うと目が慣れ、本当に要る日に効かない）。 */
.ipx-head-sub { display: flex; align-items: center; gap: 4px 10px; flex-wrap: wrap; }
.ipx-fails-trig {
  --ipx-amber: var(--color-warning);
  display: inline-flex; align-items: center; gap: 7px;
  padding: 2px 9px 2px 8px; margin: -2px 0;
  border: 1px solid var(--color-border); border-radius: var(--radius-pill);
  background: var(--color-surface); cursor: pointer;
  font: inherit; font-size: var(--text-2xs); color: var(--color-text-muted);
  white-space: nowrap;   /* 中で折り返すと「ん」「れ」だけが次の行へ落ちる */
  transition: border-color .15s, box-shadow .15s;
}
.ipx-fails-trig:hover { border-color: color-mix(in srgb, var(--color-text) 25%, var(--color-border)); }
.ipx-fails-trig:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.ipx-fails-trig[aria-expanded="true"] {
  border-color: color-mix(in srgb, var(--color-text) 30%, var(--color-border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-text) 6%, transparent);
}
.ipx-fails-dot {
  width: 7px; height: 7px; border-radius: var(--radius-circle);
  background: var(--color-text-subtle);
}
.ipx-fails-trig.is-act .ipx-fails-dot {
  background: var(--ipx-amber);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ipx-amber) 22%, transparent);
}
.ipx-fails-lead { color: var(--color-text); font-weight: var(--fw-semibold); }
.ipx-fails-chip {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 0 7px; border-radius: var(--radius-pill);
  background: var(--color-bg);
}
.ipx-fails-chip b { font-weight: var(--fw-semibold); color: var(--color-text); font-variant-numeric: tabular-nums; }
.ipx-fails-chip.is-act {
  color: var(--color-warning-text);
  background: color-mix(in srgb, var(--color-warning) 14%, transparent);
}
.ipx-fails-chip.is-act b { color: var(--color-warning-text); }
.ipx-fails-chev {
  width: 6px; height: 6px; margin-left: 1px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg); transition: transform .18s;
}
.ipx-fails-trig[aria-expanded="true"] .ipx-fails-chev { transform: translateY(1px) rotate(-135deg); }

/* 浮かぶ一覧。**開いても画面が動かない**＝見出し（position:relative）を基準に絶対配置 */
.ipx-fails-pop {
  position: absolute; z-index: 30;
  width: min(680px, calc(100vw - 32px));
  padding: 6px;
  background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  box-shadow: 0 12px 32px -12px rgba(15, 23, 42, .28), 0 2px 6px rgba(15, 23, 42, .06);
  transform-origin: top left;
  animation: ipx-pop-in .14s ease-out;
}
@keyframes ipx-pop-in { from { opacity: 0; transform: translateY(-4px) scale(.98); } }
.ipx-fails-pop-hd {
  padding: 6px 10px 8px; font-size: var(--text-2xs); color: var(--color-text-muted);
}
.ipx-fails-row {
  display: flex; flex-direction: column; align-items: stretch;
  border-radius: var(--radius-md);
}
.ipx-fails-row + .ipx-fails-row { box-shadow: 0 -1px 0 var(--color-border); }
.ipx-fails-row:hover { background: var(--color-bg); box-shadow: none; }
.ipx-fails-row:hover + .ipx-fails-row { box-shadow: none; }
.ipx-fails-main {
  flex: 1; min-width: 0;
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto 10px; align-items: center; gap: 12px;
  padding: 9px 10px; border: 0; border-radius: var(--radius-md);
  background: none; text-align: left; cursor: pointer; font: inherit; color: inherit;
}
.ipx-fails-main:focus-visible, .ipx-fails-act:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }
/* 札の幅を揃える＝「リンク切れ」と「在庫切れ」で名前の頭がずれない（px＝次の一手の字下げと同じ物差し） */
.ipx-fails-main .ipx-state { margin-left: 0; min-width: 72px; box-sizing: border-box; text-align: center; }
.ipx-fails-row.is-act .ipx-state {
  color: var(--color-warning-text);
  background: color-mix(in srgb, var(--color-warning) 12%, transparent);
  border-color: color-mix(in srgb, var(--color-warning) 35%, transparent);
}
.ipx-fails-name {
  font-size: var(--text-sm); color: var(--color-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ipx-fails-when { font-size: var(--text-2xs); color: var(--color-text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ipx-fails-ago { margin-left: 6px; color: var(--color-warning-text); }
.ipx-fails-go { color: var(--color-text-subtle); font-size: var(--text-sm); }
/* 次の一手は**名前の下の2行目**（名前の頭に字下げを揃える＝10px＋札72px＋間12px）。
   行の右に置くと、無い行に空きの列ができる */
.ipx-fails-acts {
  display: flex; align-items: center; gap: 16px;
  margin: -6px 0 8px 94px;
}
.ipx-fails-act {
  padding: 2px 0;
  border: 0; background: none; cursor: pointer;
  font: inherit; font-size: var(--text-xs); font-weight: var(--fw-semibold); color: var(--color-primary);
}
.ipx-fails-act:hover { text-decoration: underline; text-underline-offset: 3px; }
/* 止めるのは2番手＝灰色（置き換えが普通の道） */
.ipx-fails-act--quiet { font-weight: var(--fw-normal); color: var(--color-text-muted); }
@media (max-width: 600px) {
  .ipx-fails-pop { left: 0 !important; width: 100%; }
  /* 内訳は開いた一覧の札が言うので、引き金は件数だけにして1行に収める */
  .ipx-fails-trig .ipx-fails-chip { display: none; }
  .ipx-fails-main { grid-template-columns: auto minmax(0, 1fr) 10px; row-gap: 2px; }
  .ipx-fails-when { grid-column: 2; grid-row: 2; }
  .ipx-fails-go { grid-row: 1 / span 2; grid-column: 3; }
  .ipx-fails-acts { margin-top: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ipx-fails-trig, .ipx-fails-chev { transition: none; }
  .ipx-fails-pop { animation: none; }
}

.ipx-head-ttl { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--color-text); }
.ipx-head-sub { font-size: var(--text-xs); color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
.ipx-warn { color: var(--color-danger-text); }
.ipx-toggle { display: flex; align-items: center; gap: 8px; }
.ipx-toggle-lbl { font-size: var(--text-xs); color: var(--color-text-muted); }

.ipx-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(min(210px, 100%), 1fr));
}
.ipx-card {
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); padding: 12px 14px; cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
}
.ipx-card:hover { border-color: var(--color-primary-border); box-shadow: var(--shadow-xs); }
/* 最安値の札だけ色を持つ＝12枚のうち「いま買える1枚」が目に飛び込む。
   他は静かなまま（資産系タブの「濃紺1枚が主役、周りは静か」と同じ考え）。 */
/* 最安のカードは**左の帯**で示す。面を塗ると図の色と competing になり、14枚並んだ時に
   「どこが違うのか」が散る。帯なら列を目で流すだけで拾える。 */
.ipx-card--low { border-left: 3px solid var(--color-success-text); padding-left: 12px; }
.ipx-card-name {
  font-size: var(--text-xs); color: var(--color-text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 4px;
}
.ipx-card-row { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.ipx-card-price {
  font-size: var(--text-lg); font-weight: var(--fw-bold);
  color: var(--color-text); font-variant-numeric: tabular-nums;
}
.ipx-card-diff { font-size: var(--text-3xs); font-variant-numeric: tabular-nums; }
/* 「値段が動いた日」の表。**3列だと横が余る**ので、余った幅は帯に持たせる
   （数字を離して置くだけだと、離れた2つを目で結ぶ手間が増えるだけ）。 */
.ipx-moves th:last-child, .ipx-moves td:last-child { width: 34%; }
.ipx-mv-unit {
  font-size: var(--text-3xs); color: var(--color-text-muted);
  font-variant-numeric: tabular-nums; margin-top: 2px;
}
/* 期間の後ろ半分（「〜 09-17（7日）」）。**薄く小さく**＝行を縦に読むとき目で追うのは
   始まりの日付で、終わりと長さはその行の中でだけ効く（同じ濃さだと日付が2つ並んで見える）。 */
.ipx-thru {
  font-size: var(--text-2xs); color: var(--color-text-muted);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.ipx-mv-cur .ipx-thru { color: var(--color-primary); }
/* いまも続いている値段の行。**左端の線で印す**＝行の中に札を置くと数字が動く */
.ipx-mv-cur td:first-child { box-shadow: inset 3px 0 0 var(--color-primary); }
/* この期間で最初に記録した行＝「動いた」のではない（`—` だと「動いていない」に見える） */
.ipx-mv-first { font-size: var(--text-3xs); color: var(--color-text-subtle); }
/* 取れなかった日の行。**地を沈めて、値段の行の流れから外す**＝ここには比べる値が無い
   （軸の点も差も持たない）。行を出すこと自体が目的で、目立たせるのが目的ではない。 */
.ipx-mv-gap td {
  background: var(--color-bg); color: var(--color-text-subtle);
  font-size: var(--text-2xs);
}

/* 位置は**量ではない**＝塗った帯は「長いほど多い＝良い」と読まれるが、ここは長いほど
   高い＝損なので、軸の上に点を置く。左端＝選んでいる期間の最安、右端＝最高、縦の点線＝
   平均。見出し（.ipx-lvl-legend）が同じ軸に両端の金額と「平均」を出すので、列の意味は
   注記を読まなくても決まる。 */
.ipx-lvl { display: flex; align-items: center; gap: 10px; }
/* **溝に玉が乗っている**形にする＝1pxの線と小さな点だけだと、23行並べたときに軸が
   痩せて読み取りにくい。地の色は**両端だけをごく薄く染める**（左＝安い側に緑、右＝高い
   側に赤、いずれも 14% 前後）。在庫の価格帯バーのような濃いグラデーションにはしない＝
   あちらは行ごとに商品も金額の軸も違うので色が共通の物差しになるが、この表は全行が
   同じ商品・同じ軸なので、位置だけで比べられる。しかも幅が12円しかない商品（¥500〜
   ¥512）で赤く塗ると「高い」に見えてしまう（実際の差は右の「+¥N」が言う）。 */
.ipx-lvl-track {
  position: relative; flex: 1; min-width: 88px; height: 10px;
  border-radius: var(--radius-pill);
  background: linear-gradient(to right,
    rgba(22, 163, 74, 0.15), rgba(22, 163, 74, 0) 42%,
    rgba(239, 68, 68, 0) 58%, rgba(239, 68, 68, 0.13));
  box-shadow: inset 0 1px 2px rgba(15, 23, 42, 0.09),
              inset 0 0 0 1px var(--color-border);
}
/* 玉の半径ぶん内側を「軸の 0〜100%」にする＝両端でも玉が切れない（カードの図と同じ理屈） */
.ipx-lvl-rail { position: absolute; left: 6px; right: 6px; top: 0; bottom: 0; }
/* 軸の両端に目盛り＝「ここが最安／最高」と、溝の端が同じ場所だと分かる */
.ipx-lvl-rail::before, .ipx-lvl-rail::after {
  content: ""; position: absolute; top: 2px; bottom: 2px; width: 1px;
  background: var(--color-border-strong, var(--color-border)); opacity: .55;
}
.ipx-lvl-rail::before { left: 0; }
.ipx-lvl-rail::after { right: 0; }
.ipx-lvl-dot {
  position: absolute; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px;
  border-radius: 50%; background: var(--color-primary);
  border: 2px solid var(--color-surface);
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.30);
}
.ipx-lvl-dot.is-low {
  background: var(--color-success-text);
  box-shadow: 0 1px 4px rgba(22, 163, 74, 0.45);
}
.ipx-lvl-avg {
  position: absolute; top: -3px; bottom: -3px; width: 0;
  border-left: 1px dashed var(--color-text-subtle); opacity: .5;
}
.ipx-lvl-val {
  min-width: 56px; text-align: right; white-space: nowrap;
  font-size: var(--text-3xs); color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}
.ipx-lvl-low { color: var(--color-success-text); font-weight: var(--fw-semibold); }
/* 見出し＝軸の凡例。行の軸とピクセルで揃える（両端の金額・平均の位置が行の点と同じ物差し） */
.ipx-lvl-th { text-align: left; font-weight: var(--fw-semibold); }
.ipx-lvl-legend {
  display: flex; align-items: center; gap: 10px;
  font-size: var(--text-3xs); font-variant-numeric: tabular-nums;
  color: var(--color-text-muted); text-transform: none; letter-spacing: 0;
}
.ipx-lvl-end { white-space: nowrap; font-weight: var(--fw-semibold); }
.ipx-lvl-rail-wrap { position: relative; flex: 1; min-width: 88px; height: 14px; }
.ipx-lvl-legend-rail { position: absolute; left: 6px; right: 6px; top: 0; bottom: 0; }
/* 「平均」の下に短い破線を垂らす＝下の行に並ぶ点線と同じ位置だと目で繋がる */
.ipx-lvl-avg-lbl {
  position: absolute; top: 0; transform: translateX(-50%);
  white-space: nowrap; color: var(--color-text-subtle);
}
.ipx-lvl-avg-lbl::after {
  content: ""; position: absolute; left: 50%; top: 100%; height: 4px;
  border-left: 1px dashed var(--color-text-subtle); opacity: .5;
}
/* 見出しの右端は「+¥N」の列ぶん空ける（行の値と縦に揃える） */
.ipx-lvl-legend::after { content: ""; min-width: 56px; }
.ipx-moves-note { font-size: var(--text-3xs); color: var(--color-text-subtle); margin: 6px 2px 0; line-height: 1.6; }
/* 狭い画面では**余った幅に足したものを畳む**＝もともとの3列（日時・価格・前回との差）に
   戻る。横スクロールの先に置いても読まれないし、置いた幅ぶん本体が狭くなる。 */
@media (max-width: 640px) {
  /* 畳むのは軸の列だけ（4列→3列）。期間・価格・前回との差は狭い画面でも要る。 */
  .ipx-moves th:last-child, .ipx-moves td:last-child { display: none; }
  .ipx-moves-note { display: none; }
  /* 期間の後ろ半分は下へ回す＝いちばん広い列から幅を出す */
  .ipx-moves .ipx-thru { display: block; }
}
.ipx-up { color: var(--color-danger-text); }
.ipx-dn { color: var(--color-success-text); }
.ipx-low-badge {
  margin-left: auto; padding: 1px 8px; border-radius: var(--radius-pill);
  background: rgba(22, 163, 74, 0.16); color: var(--color-success-text);
  font-size: var(--text-3xs); font-weight: var(--fw-semibold);
}
.ipx-card-meta {
  font-size: var(--text-3xs); color: var(--color-text-muted); font-variant-numeric: tabular-nums;
}
.ipx-card-meta .fxc-dot { color: var(--color-border); margin: 0 5px; }
/* グラフの見出し＝名前（左）と期間の切替（右）を1行に。**切り替える対象の隣に置く** */
.ipx-chart-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: var(--sp-3);
}
.ipx-chart-head h2 { margin-bottom: 0; }
/* 線が途切れている理由。**図に敷かずに下へ1行**＝線そのものより目立ってはいけない */
.ipx-gaps {
  margin: 8px 2px 0; font-size: var(--text-3xs); color: var(--color-text-subtle);
  font-variant-numeric: tabular-nums;
}



/* 取り込み中の進捗。**3秒で消えるトーストでは足りない**＝1商品ずつ間を空けるので
   全部で1分以上かかり、押した直後しか何も出ないと「動いていない」ように見える
   （実際そう報告された）。終わるまで消えない行にして、何件目か・経過時間を出す。 */
.ipx-prog {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: -6px 0 14px; padding: 8px 12px;
  background: var(--color-primary-light); border: 1px solid var(--color-primary-border);
  border-radius: var(--radius-md); font-size: var(--text-xs); color: var(--color-text);
}
.ipx-prog-spin {
  width: 13px; height: 13px; flex-shrink: 0; border-radius: 50%;
  border: 2px solid var(--color-primary-border); border-top-color: var(--color-primary);
  animation: ipx-spin 0.8s linear infinite;
}
@keyframes ipx-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ipx-prog-spin { animation-duration: 3s; } }
.ipx-prog-txt { flex: 1; min-width: 180px; }
.ipx-prog-bar {
  flex: 0 0 140px; height: 5px; border-radius: var(--radius-pill);
  background: var(--color-surface); overflow: hidden;
}
.ipx-prog-bar > span {
  display: block; height: 100%; background: var(--color-primary);
  border-radius: var(--radius-pill); transition: width .3s;
}
.ipx-prog-time { font-variant-numeric: tabular-nums; color: var(--color-text-muted); }
.ipx-prog-err { color: var(--color-warning-text); line-height: 1.7; }

/* 価格ウォッチ：一覧⇄個別の行き来と、カードからの設定 */
.ipx-back { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
/* **帰り道はパンくず**＝以前は青いピルで、その行で唯一色が付いているせいで商品名より
   先に目が行っていた（青く塗るのは「保存」「+ 商品を追加」＝しに来た操作）。親をタブの
   名前で呼ぶので「どこへ帰るのか」も言えている。色は落とし、下線はホバーの時だけ。 */
.ipx-crumb { display: inline-flex; align-items: center; gap: 6px; }
.ipx-crumb-up {
  border: none; background: none; padding: 0; cursor: pointer;
  color: var(--color-text-muted); font-size: var(--text-xs); font-weight: var(--fw-semibold);
  white-space: nowrap;
}
.ipx-crumb-up:hover { color: var(--color-primary); text-decoration: underline; }
.ipx-crumb-sep { color: var(--color-border); font-size: var(--text-xs); }
/* **高さだけは揃える**＝同じ行に button と a が混ざると行の高さが1px ずれる
   （幅は中身のままでよい）。 */
.ipx-back .mst-chip {
  height: 32px; display: inline-flex; align-items: center;
  padding-top: 0; padding-bottom: 0; text-decoration: none;
}
/* 名前は伸ばして右側のチップを端へ寄せる。商品ページの長いタイトルがそのまま入る
   ことがあるので、はみ出しは畳む（全文は title= で読める）。 */
.ipx-back-name {
  flex: 1; min-width: 120px; margin-right: auto;
  font-size: var(--text-md); font-weight: var(--fw-semibold);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* ASIN は名前ではなく符丁＝等幅で字送りを開ける（読み比べるのは10文字の並び） */
.ipx-asin-chip { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.02em; }
/* カードの頭。**名前とボタンを別の枠にする**＝グループが「何の商品か」を担うように
   なった結果、カード名は商品ページの長いタイトルになりやすく（同じ商品の別ページを
   見分ける手掛かりが容量やセット数としてタイトルの奥にある）、1つの行に混ぜると
   名前がボタンを押し出してしまう。 */
.ipx-card-head { display: flex; align-items: flex-start; gap: 6px; margin-bottom: 4px; }
.ipx-card-title {
  flex: 1; min-width: 0;
  font-size: var(--text-xs); color: var(--color-text-muted); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ipx-card-elide { color: var(--color-text-subtle); }   /* 比べるグループで畳んだ頭の印 */
/* **常に見えている**＝ホバーでしか出ないボタンは触る端末で永久に押せない。
   薄く置いておき、当たり判定は 24px 確保する（小さすぎて押しにくいと言われた）。 */
.ipx-card-acts { flex-shrink: 0; display: flex; align-items: center; gap: 1px; }
.ipx-card-acts > * {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border: none; background: none; cursor: pointer;
  padding: 0; border-radius: var(--radius-sm); text-decoration: none;
  color: var(--color-text-muted); font-size: var(--text-xs);
  opacity: .5; transition: opacity .15s, background .15s;
}
.ipx-card:hover .ipx-card-acts > * { opacity: 1; }
.ipx-card-acts > *:hover { background: var(--color-bg); color: var(--color-primary); }
.ipx-card-acts .ipx-card-mute { cursor: default; opacity: .9; }
.ipx-card--empty { border-style: dashed; }

/* ── 価格ウォッチの商品モーダル ─────────────────────────────────
   **主役は1つの欄だけ**。貼り付ける → 商品名と今の値段が出る → 保存、で終わる。
   以前は名前・URL・目標額・メモを同じ重さで並べ、ラベルに付けた長い説明が折り返して
   詰まっていた（説明は欄の下へ、任意の欄は弱く）。 */
.pw-modal-inner { max-width: 520px; }
.pw-body { display: flex; flex-direction: column; gap: 18px; }
.pw-hero {
  background: var(--color-bg); border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); padding: 14px;
}
.pw-hero-label {
  display: block; font-size: var(--text-xs); font-weight: var(--fw-semibold);
  color: var(--color-text); margin-bottom: 8px;
}
/* 入力＋ボタンの行。**ボタンは縮ませない**＝隣の input が `width:100%` を持っていると
   ボタンが潰れ、「補完」の2文字が縦に積まれる（実際そうなった）。input 側も
   フレックスの取り分で伸ばす（width ではなく flex で決める）。 */
.pw-hero-row { display: flex; gap: 8px; align-items: center; }
.pw-hero-row > input { flex: 1; min-width: 0; width: auto; }
.pw-hero-row > .btn { flex-shrink: 0; white-space: nowrap; }
.pw-hero-input {
  flex: 1; min-width: 0; padding: 9px 11px;
  border: 1px solid var(--color-border-strong); border-radius: var(--radius-md);
  font-size: var(--text-sm); font-family: var(--font-mono, ui-monospace, monospace);
  background: var(--color-surface); color: var(--color-text);
}
.pw-hero-input:focus { outline: none; border-color: var(--color-primary); }
.pw-hero-hint, .pw-field-hint {
  font-size: var(--text-3xs); color: var(--color-text-muted); margin: 6px 0 0; line-height: 1.6;
}
.pw-field-hint { display: block; margin-top: 3px; }

/* 貼り付けたものが正しい商品かは10文字を見ても分からない＝名前と値段を出して確かめる */
.pw-preview {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px;
  border: 1px solid var(--color-primary-border); background: var(--color-primary-light);
  border-radius: var(--radius-lg);
}
.pw-preview--warn { border-color: rgba(245, 158, 11, .45); background: rgba(245, 158, 11, .10); }
.pw-preview-main { flex: 1; min-width: 0; }
.pw-preview-name {
  font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--color-text);
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.pw-preview-meta {
  font-size: var(--text-3xs); color: var(--color-text-muted); margin-top: 3px;
  font-variant-numeric: tabular-nums;
}
.pw-preview-price {
  font-size: var(--text-lg); font-weight: var(--fw-bold); color: var(--color-text);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.pw-field label {
  display: block; font-size: var(--text-xs); font-weight: var(--fw-semibold);
  color: var(--color-text); margin-bottom: 6px;
}
.pw-field input {
  width: 100%; box-sizing: border-box; padding: 9px 11px;
  border: 1px solid var(--color-border-strong); border-radius: var(--radius-md);
  font-size: var(--text-sm); background: var(--color-surface); color: var(--color-text);
}
.pw-field input:focus { outline: none; border-color: var(--color-primary); }
.pw-opt {
  margin-left: 6px; font-size: var(--text-3xs); font-weight: var(--fw-medium);
  color: var(--color-text-muted);
}
.pw-stop {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 14px; border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  font-size: var(--text-xs); cursor: pointer;
}
.pw-msg { font-size: var(--text-sm); color: var(--color-danger-text); }
/* 通知を切っている商品の札（監視を切ったものは畳んだ見出しの中なので、札は要らない） */
.ipx-card-mute { font-size: var(--text-3xs); opacity: .75; }
/* 🎯 しきい値の札（「いくらを下回ったら知らせるか」）。**緑とは別の色**にする＝緑は
   「全期間の最安＝いま買える1枚」で、こちらは人が決めた別の物差し。普段は静かな灰色で、
   **いま下回っている時だけ琥珀**に灯る（＝鳴る条件が満たされている状態が一覧で分かる）。 */
.ipx-goal {
  display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: var(--radius-pill);
  background: var(--color-bg); color: var(--color-text-subtle);
  font-size: var(--text-3xs); font-weight: var(--fw-semibold); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.ipx-card-meta .ipx-goal { margin-left: 0; }
.ipx-goal--under { background: rgba(245, 158, 11, 0.16); color: var(--color-warning-text); }
/* 単価で書いてあるのに容量が無い＝効いていない。**消さずに言う**（黙って無効にすると
   「設定したのに鳴らない」になる） */
.ipx-goal--broken {
  background: rgba(239, 68, 68, 0.12); color: var(--color-danger-text);
  text-decoration: line-through;
}

/* しきい値の入力：種別（金額/単価）と数値欄を1行に置く＝物差しと数字は一続きの1つの設定 */
.pw-limit-row { display: flex; gap: 8px; align-items: center; }
.pw-limit-row .fxc-biz { width: auto; flex: 0 0 168px; }
.pw-limit-row input { flex: 1 1 auto; min-width: 0; }
.pw-limit-row .btn { flex: 0 0 auto; }
/* まだ取れていないカードは ASIN を出す＝名前だけでは「何を登録したか」が確かめられない */
.ipx-card-asin {
  font-size: var(--text-3xs); color: var(--color-text-muted);
  font-family: ui-monospace, monospace; margin: 6px 0 2px;
}

/* ── 価格ウォッチのグループ ─────────────────────────────────────
   **同じ商品なのに ASIN が複数ある**状態を束ねる見出し。商品ページが変わっても古いほうを
   消さない（復活しうる）運用の帰結で、平らに並べると「どれが同じ商品か」が読めない。 */
/* グループの見出しは**マスタ管理の「まとまり」と同じ**（.mst-group--section を借りる）＝
   アプリの中で「束ねたもの」の表し方を1つにする。畳めるのもそのまま活きる。 */
.ipx-grp { margin-bottom: 14px; }
.ipx-grp > .mst-group-head { gap: 8px; }
.ipx-grp .ipx-grid, .ipx-grp .table-wrapper { margin-top: 10px; }
.ipx-grp-head[draggable="true"] { cursor: grab; }
.ipx-grp-head[draggable="true"] .ipx-grp-name { cursor: text; }
.ipx-grp-count {
  padding: 0 7px; border-radius: var(--radius-pill); background: var(--color-bg);
  font-size: var(--text-3xs); color: var(--color-text-muted); font-variant-numeric: tabular-nums;
}
/* 見出しが持つのは**この中でいま一番安いのはどれか**＝束ねている意味がここに出る */
.ipx-grp-best {
  margin-left: auto; font-size: var(--text-xs); color: var(--color-success-text);
  font-variant-numeric: tabular-nums;
}
.ipx-grp-del {
  border: none; background: none; cursor: pointer; padding: 0 4px;
  color: var(--color-text-muted); font-size: var(--text-xs); opacity: .5; transition: opacity .15s;
  min-height: 24px;
}
/* **常時薄く表示し、見出しに乗せたら濃く**（カードのボタンと同じ約束）。以前は 0 から
   `.ipx-grp-head:hover` で出していたが、見出しの実体は `.mst-group-head`（マスタ管理の
   見出しを借りている）で当たらず、⚖ と ✕ が常に透明だった＝触る端末では永久に見えない */
.ipx-grp > .mst-group-head:hover .ipx-grp-del,
.ipx-grp > .mst-group-head:focus-within .ipx-grp-del { opacity: 1; }
.ipx-grp-del:hover { color: var(--color-danger-text); }
/* 空のグループにも受け皿を出す＝先に箱を作ってから放り込む、が成り立つ */
.ipx-grp-empty {
  grid-column: 1 / -1; padding: 18px; text-align: center;
  border: 1px dashed var(--color-border-strong); border-radius: var(--radius-lg);
  font-size: var(--text-xs); color: var(--color-text-muted);
}
.ipx-card[draggable="true"] { cursor: grab; }
.ipx-card--dragging { opacity: .4; }
/* 落とし先を1段階だけ強調する（枠線と面で、動かしている最中だけ） */
.ipx-dragging .ipx-grid { min-height: 60px; border-radius: var(--radius-lg); }
.ipx-card.ipx-over { border-color: var(--color-primary); box-shadow: -3px 0 0 var(--color-primary); }
.ipx-grid.ipx-over { background: var(--color-primary-light); }
.ipx-grp-head.ipx-over { border-bottom-color: var(--color-primary); }

/* グループ名をその場で書く欄（prompt は使わない＝この repo のどこにも無く操作が浮く）。
   **見出しの字のまま編集できる**ように、枠も背景も持たせない＝入力欄に化けると
   「その場で書き換えている」感じが消え、枠のぶん文字の位置もズレる。触れることは
   focus 時の下線で示す。 */
.ipx-grp-input {
  /* **打つ時に狭い意味がない**＝グループ名は商品名ほどではないが長くなりうる */
  flex: 1; min-width: 220px; max-width: 520px; padding: 0; margin: 0;
  border: none; border-bottom: 1px solid transparent; border-radius: 0;
  background: none; color: var(--color-text);
  font: inherit; font-size: var(--text-sm); font-weight: var(--fw-semibold);
  line-height: inherit;
}
.ipx-grp-input::placeholder { font-weight: var(--fw-normal); color: var(--color-text-muted); }
.ipx-grp-input:focus { outline: none; border-bottom-color: var(--color-primary); }

/* 監視オフの置き場は**マスタ管理の「休止中」と同じ見た目**（畳んだ見出し＋行）。
   空のときはドラッグ中だけ現れる＝落とし先が無いと止められないが、普段から空の見出しを
   置いておく意味もない。 */
.ipx-off[data-empty] { display: none; }
.ipx-dragging .ipx-off[data-empty] { display: block; }
.ipx-dragging .ipx-off .mst-rows { min-height: 54px; }
.ipx-off .mst-row[draggable="true"] { cursor: grab; }
.ipx-off .mst-rows.ipx-over { background: var(--color-primary-light); border-radius: var(--radius-md); }
.ipx-grp-note { font-size: var(--text-3xs); color: var(--color-text-muted); margin-left: auto; }
/* 一覧から直接 商品ページへ（詳細まで潜らずに「買うか」を決められる） */
/* 「値段を比べる」の札。**同じ商品を別ページで見張っている時だけ**押す（既定はオフ）。 */
.ipx-grp-cmp {
  border: 1px solid var(--color-border); background: none; cursor: pointer;
  border-radius: var(--radius-pill); padding: 1px 9px;
  font-size: var(--text-3xs); color: var(--color-text-muted);
  opacity: .5; transition: opacity .15s;
  min-height: 24px;
}
.ipx-grp > .mst-group-head:hover .ipx-grp-cmp,
.ipx-grp > .mst-group-head:focus-within .ipx-grp-cmp, .ipx-grp-cmp.active { opacity: 1; }
.ipx-grp-cmp.active {
  border-color: rgba(22, 163, 74, .45); background: rgba(22, 163, 74, .10);
  color: var(--color-success-text); font-weight: var(--fw-semibold);
}
/* ドラッグ中は「監視オフ」を下に貼り付ける＝一番下まで運ばずに落とせる
   （14枚あると落とし先が画面の外にいて、掴んだままスクロールする羽目になる） */
.ipx-dragging .ipx-off {
  position: sticky; bottom: 8px; z-index: 5;
  background: var(--color-surface); border-radius: var(--radius-lg);
  box-shadow: 0 -6px 16px rgba(20, 30, 60, .10);
}

/* 取り込みや設定のメッセージ。**流れから外して浮かせる**＝出入りのたびにボタンが
   横へずれる（レイアウトが動くのは、押した場所が動くということ）。 */
/* **id で指定する**＝`formToast()` は className を丸ごと上書きするので、クラスに
   書くと表示された瞬間に剥がれる（実際そうなって、出るたびにボタンがずれていた）。 */
/* **画面下中央に浮かべる**（取り消しトースト .row-toast と同じ見た目）＝見出しの直下に
   置いていた頃は、見出しを2段にした途端に下の段（道具）と重なった。画面の段組みに依存させない */
#ipx-msg {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%); z-index: 400;
  max-width: min(640px, calc(100vw - 32px));
  padding: 11px 16px; border-radius: var(--radius-lg);
  background: #1f2937; color: var(--color-text-on-accent);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-sm); font-weight: var(--fw-normal);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  animation: ipx-toast-in .18s ease-out;
}
#ipx-msg.form-toast-ng { background: var(--color-danger-text); }
@keyframes ipx-toast-in { from { opacity: 0; transform: translateX(-50%) translateY(12px); } }
@media (max-width: 900px) { #ipx-msg { bottom: calc(82px + env(safe-area-inset-bottom)); } }
@media (prefers-reduced-motion: reduce) { #ipx-msg { animation: none; } }


/* 最後に見たときの状態（在庫切れ／ページが無い…）。**行動が変わる情報**なので札で出す */
.ipx-state {
  margin-left: auto; padding: 1px 8px; border-radius: var(--radius-pill);
  font-size: var(--text-3xs); font-weight: var(--fw-semibold); white-space: nowrap;
}
/* **色は「いま最安」の緑にだけ持たせる**＝この画面で人が動くのはそこだけ。取れなかった
   理由（在庫切れ・ページが無い・値段が読めない）は、**古い値が出ている理由の説明**で
   あって警告ではない（在庫切れも廃番も復活しうるので、この機能は見張り続ける）。赤や橙で
   塗ると、並べたカードの中で主役より強くなる。階層は
   「最安（緑・太字）＞ M/D から取れていません（その上の数字が古いという注意）＞ 理由の札」。 */
.ipx-state--warn, .ipx-state--bad {
  background: var(--color-bg); color: var(--color-text-muted);
  border: 1px solid var(--color-border);
}
/* 人が手を入れないと直らないもの（ページが無い・読めない）だけ、文字を一段だけ濃く */
.ipx-state--bad { color: var(--color-text); }

/* カードの図。線・床・最新の点を1枚に畳んである（上下の数字は図の目盛り＝位置が意味を持つ）。
   `preserveAspectRatio` を外してあるので点は丸いまま。 */
/* 目盛りの居場所を上下に確保する＝**現在値が天井や床と重なる商品がある**（最高値の日が
   今日なら線は上辺まで届く）ので、図の中にラベルを浮かせると数字が線に乗る。 */
.ipx-plot { position: relative; margin: 6px 0 4px; padding: 13px 0; }
.ipx-plot-svg { display: block; width: 100%; height: auto; }
.ipx-plot--empty { height: 52px; }
.ipx-plot-hi, .ipx-plot-lo {
  position: absolute; font-size: var(--text-3xs); color: var(--color-text-muted);
  font-variant-numeric: tabular-nums; line-height: 1; pointer-events: none;
}
.ipx-plot-hi { top: 0; right: 0; }
.ipx-plot-lo { bottom: 0; left: 0; }
.ipx-plot-lo.is-low { color: var(--color-success-text); font-weight: var(--fw-semibold); }

/* 一覧。カードと同じ事実を数字で並べる形（件数が増えたとき「どれが安いか」を比べやすい） */
.ipx-modes { display: flex; gap: 6px; }
.ipx-table td, .ipx-table th { white-space: nowrap; }
/* **名前の列に上限**＝取り込んだ商品名はそのままだと1行が長く（「LUX ルミニーク シャンプー
   ダメージリペア ノンシリコン ビューティーセラム配合 ローズ&ピーチの香り」）、右の
   「最高」「最後に見たとき」を画面の外へ押し出していた（名前の短いグループだけ8列とも
   見えている、という状態になる）。畳んで全文は title で読む＝カードのタイトルと同じ扱い。 */
.ipx-table td:first-child a {
  display: inline-block; max-width: 300px; vertical-align: middle;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ipx-table .ipx-card-mute { margin-left: 4px; }   /* 🔕 が名前に張り付く */
.ipx-table .ipx-state { margin-left: 6px; }       /* 札も同じ（.ipx-state の auto は効かない） */
/* 今日ぶんが無い商品の「最後に見たとき」（表の右端・カードの足元で共通）。
   **日付の字は他と同じ大きさのまま**色だけ変える＝同じ列で字の大きさが混ざると、日付が
   縦に揃って見えない。添える「N日前」だけ小さく（文ではなく量で「どれだけ古いか」を言う）。
   古い値が「いまの価格」に見えないようにするのが目的。 */
.ipx-late { color: var(--color-warning-text); }
.ipx-ago { margin-left: 6px; font-size: var(--text-3xs); }
/* 記録が無い行は**行ごと薄く**＝金額が1つも無い行なので、価格を見比べる目には邪魔になる
   （カードは破線の枠＋薄い題で既にそうなっていて、表だけが黒いままだった）。
   **値が古いだけの行は薄くしない**＝その金額は本物で、いちばん安いかもしれない。 */
.ipx-row--nodata td, .ipx-row--nodata td a { color: var(--color-text-muted); }
.ipx-table td a { color: var(--color-text); text-decoration: none; }
.ipx-table td a:hover { color: var(--color-primary); text-decoration: underline; }
.ipx-row--low td { background: rgba(22, 163, 74, 0.05); }
.ipx-at-low { color: var(--color-success-text); font-weight: var(--fw-semibold); }
