/* 色は2色（深緑・琥珀）＋無彩色まで。赤緑に意味を持たせない（色覚多様性）。
   「もうすぐ請求」は色ではなく残り日数の数字で伝える。数字は tabular-nums で桁を揃える。

   🔴 深緑（--brand）は「押せるもの」専用。数字・見出し・情報の地色には使わない。
      1つの色が「主数値・主ボタン・選択中・フォーカスリング」を兼任すると、緑が出ていても
      それが操作なのか結果なのか読めなくなる（2026-08-19 UI採点）。数字は --ink。
      ロゴも同じ理由で --ink にした（押せないのに緑だと、緑＝押せるの規則が最初の1行から破れる）。
   琥珀（--amber）は「期限が近い注意」だけ＝書き出しの催促バナーの地色と、今日/明日の請求。
   赤（--danger）は「消える操作とエラー」だけ。 */
:root {
  color-scheme: light dark;
  --ink: #191d1b;
  --muted: #5f6b66;
  --paper: #f7f5f0;
  --card: #ffffff;
  --line: #e2ded4;
  --brand: #1f4d43;
  --brand-soft: #dfeae5;
  --amber: #8a5a12;
  --amber-soft: #f6ecd8;
  --danger: #a02b1f;
  --bar: #6d7a75;        /* カテゴリ別の横棒。緑にすると「押せる」と混ざる */
  --placeholder: #8a938f; /* 入力例。本文(--ink)・説明(--muted)より薄い＝「まだ何も入っていない」段 */
  --row-hover: #fbfaf7;  /* 一覧の行のホバー。紙と白カードの中間。ミントにすると「選択中」と混ざる */
  --shadow: 0 2px 10px rgba(20, 35, 30, .05);
  --shadow-pop: 0 8px 24px rgba(20, 35, 30, .14);

  /* 余白は4pxグリッド。ここ以外の数値を新しく持ち込まない */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px;
  /* 文字は6段。行内の強弱はこの中だけで付ける */
  --fs-xs: 12px; --fs-s: 13px; --fs-m: 14px; --fs-l: 16px; --fs-xl: 18px; --fs-2xl: 21px;
  --r-s: 10px; --r-m: 12px; --r-l: 16px; --r-xl: 20px; --r-pill: 100px;

  font-family: system-ui, -apple-system, BlinkMacSystemFont, "Hiragino Sans", "Segoe UI", sans-serif;
  font-variant-numeric: tabular-nums;
  accent-color: var(--brand);
}

@media (prefers-color-scheme: dark) {
  :root {
    --ink: #eef1ef; --muted: #a2aeaa; --paper: #14181a; --card: #1e2426;
    --line: #313a3c; --brand: #8fd4c2; --brand-soft: #253531; --amber: #e6c07a; --amber-soft: #33291a;
    --danger: #f0998c; --bar: #8b9995; --row-hover: #262d2f; --placeholder: #8a938f;
    --shadow: 0 2px 10px rgba(0, 0, 0, .3);
    --shadow-pop: 0 8px 24px rgba(0, 0, 0, .5);
  }
}

* { box-sizing: border-box; }
html { background: var(--paper); }
body { margin: 0; color: var(--ink); background: var(--paper); overflow-x: hidden; }
button, input, select, textarea { font: inherit; color: inherit; }
/* 🔴 既定のプレースホルダ（rgb(117,117,117)・地色との比4.61）は入力済みの値と見分けが付かず、
      採点者が「埋まっているのに保存でエラーになる」と誤認した（2026-08-19 UI採点）。
      文言は index.html で「例）Netflix」にし、色は入力値（比17.03）・説明文（--muted 5.10）より
      薄い専用色にする。実測 light 3.16 / dark 4.98 ＝ 本文の基準を意図的に下回らせる段。 */
::placeholder { color: var(--placeholder); opacity: 1; }
button { -webkit-tap-highlight-color: transparent; }
:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }
[hidden] { display: none !important; }
h1, h2, h3, p, dl, dd, figure, ul, ol { margin: 0; }
/* 日本語を語中で改行させない。auto-phrase 未対応ブラウザでは無視されるので、
   日付・金額など絶対に割りたくない断片は .nowrap で個別に守る。 */
.summary-range, .notice, .empty-state, .preview, .footnote, .help, .toast,
.preset-empty p, .form-error, .field-label, .field-hint, .settings-card h3 { word-break: auto-phrase; }
.nowrap { white-space: nowrap; }

/* ============================================================
   押せるものは3系統だけ（2026-08-19 UI採点で「6系統ある」と指摘された点の作り直し）
     ①塗り   .button.primary … 主行動。サブスクを追加／保存する／JSONを書き出す
     ②枠線   .button.outline / .chip … それ以外の実行と開閉。書き出す・解約した・読み込む・
              カレンダー・記録ごと削除（文字だけ赤）・⚙・×・カテゴリ別を見る・自分で入力する
     ③選択   .segmented > .seg … 排他の2択。表示（利用中/解約済み）と並び替え
   ②と③を同じ白ピルで兼ねると、390pxの同じ行に「解約済み（未選択トグル）」と
   「＋追加（実行）」が同じ見た目で並ぶ。選択は必ず受け皿の中、実行は受け皿の外。
   ============================================================ */
.button {
  display: inline-flex; gap: var(--s2); align-items: center; justify-content: center;
  min-height: 48px; padding: var(--s3) var(--s4);
  border: 0; border-radius: var(--r-m); font-size: var(--fs-l); font-weight: 750; cursor: pointer;
}
.button.primary { background: var(--brand); color: var(--paper); }
/* ミント(--brand-soft)は「選択中」だけに使う。中立の操作は枠線ボタンにする */
.button.outline { border: 1px solid var(--line); background: var(--card); color: var(--ink); }
.button.outline:hover { border-color: var(--brand); }
/* 赤は色だけで示す。様式（枠線）は他の中立操作と同じにして、系統を増やさない */
.button.outline.danger { color: var(--danger); }
.button:disabled { opacity: .55; cursor: not-allowed; }
.button-compact { min-height: 44px; padding: var(--s2) var(--s3); font-size: var(--fs-m); }
.add-glyph { font-size: var(--fs-l); font-weight: 400; }

/* 枠線系の小型版。高さと文字が違うだけで、地色・線・角丸は .button.outline と同じ */
.chip {
  display: inline-flex; gap: var(--s1); align-items: center; justify-content: center;
  min-height: 44px; padding: var(--s2) var(--s3);
  border: 1px solid var(--line); border-radius: var(--r-m);
  background: var(--card); color: var(--ink); font-size: var(--fs-m); font-weight: 750; cursor: pointer;
}
.chip:hover { border-color: var(--brand); }
.chip-icon { width: 44px; padding: 0; color: var(--muted); font-size: 20px; }
.chip-caret { color: var(--muted); font-size: var(--fs-xs); }

/* 排他の2択。受け皿（トラック）に入っていること自体が「これは選択である」という印 */
.segmented { display: inline-flex; gap: 2px; padding: 2px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--card); }
.seg { min-height: 44px; padding: var(--s2) var(--s3); border: 0; border-radius: var(--r-pill); background: transparent; color: var(--muted); font-size: var(--fs-m); font-weight: 700; white-space: nowrap; cursor: pointer; }
.seg.is-selected { color: var(--brand); background: var(--brand-soft); }
.seg-count { opacity: .75; font-size: var(--fs-xs); }

.app-shell { max-width: 720px; min-height: 100dvh; margin: 0 auto; padding: 0 20px calc(40px + env(safe-area-inset-bottom)); }
.topbar { display: flex; gap: var(--s2); align-items: center; justify-content: space-between; padding: max(10px, env(safe-area-inset-top)) 0 6px; }
.topbar-actions { display: flex; gap: var(--s2); align-items: center; }
.brand { color: var(--ink); font-size: 20px; font-weight: 800; letter-spacing: -.03em; }

/* 3つの数字。いちばん大きいのは1つだけ＝今後30日に出ていく額。文字色は --ink（緑は操作専用） */
.summary { padding: 14px 0 4px; }
.summary-label { color: var(--muted); font-size: var(--fs-m); font-weight: 700; }
.summary-main { color: var(--ink); font-size: clamp(44px, 13vw, 68px); font-weight: 800; line-height: 1.05; letter-spacing: -.045em; }
.summary-range { margin-top: var(--s1); color: var(--muted); font-size: var(--fs-s); }
.summary-sub { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2); margin-top: var(--s3); }
.summary-sub > div { min-width: 0; padding: var(--s2) var(--s3); border: 1px solid var(--line); border-radius: 14px; background: var(--card); }
.summary-sub dt { color: var(--muted); font-size: var(--fs-xs); font-weight: 700; }
.summary-sub dd { margin: 2px 0 0; font-size: clamp(17px, 4.4vw, 21px); font-weight: 700; letter-spacing: -.02em; }

/* 琥珀は地色だけ。中の文字は --ink、ボタンは他と同じ枠線チップ（琥珀枠の第4の様式を作らない） */
.notice { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3); align-items: center; margin-top: var(--s2); padding: var(--s2) var(--s3); border-radius: var(--r-m); color: var(--ink); background: var(--amber-soft); font-size: var(--fs-s); }

/* カテゴリ別の内訳。1080px未満では畳んだ状態が既定（開くまで一覧の密度を1行も削らない）、
   1080px以上では左カラムに開いたまま置く。 */
.breakdown { margin-top: var(--s1); }
.breakdown-label { color: var(--muted); font-size: var(--fs-xs); font-weight: 700; }
.breakdown > .breakdown-label { display: none; }
.breakdown-list { display: grid; gap: var(--s2); margin-top: var(--s3); padding: 0; list-style: none; }
.breakdown-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px var(--s2); font-size: var(--fs-xs); }
.breakdown-name { min-width: 0; overflow: hidden; color: var(--ink); font-weight: 700; text-overflow: ellipsis; white-space: nowrap; }
.breakdown-amount { color: var(--muted); white-space: nowrap; }
.breakdown-bar { grid-column: 1 / -1; height: 6px; border-radius: var(--r-pill); background: var(--line); }
.breakdown-bar > span { display: block; height: 100%; border-radius: var(--r-pill); background: var(--bar); }

/* 「何を切るか」への答え。1080px以上の左カラムでだけ出す */
.toplist { display: none; margin-top: var(--s5); }
.toplist-list { display: grid; gap: var(--s2); margin-top: var(--s3); padding: 0; list-style: none; counter-reset: rank; }
.toplist-row { display: grid; grid-template-columns: 16px minmax(0, 1fr) auto; gap: var(--s2); align-items: baseline; font-size: var(--fs-s); }
.toplist-rank { color: var(--muted); font-size: var(--fs-xs); font-weight: 700; }
.toplist-name { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; min-width: 0; overflow: hidden; color: var(--ink); font-weight: 700; line-height: 1.35; }
.toplist-amount { color: var(--ink); font-weight: 700; white-space: nowrap; }
.toplist-note { margin-top: var(--s3); color: var(--muted); font-size: var(--fs-xs); line-height: 1.6; }

/* 操作行。左＝どれを見るか、右＝どう並べるか。どちらも同じセグメントで書く。
   600px以上では1行に収まり、390pxでだけ2行に折り返す（行数は以前と同じ）。 */
.list-controls { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4); align-items: center; margin: var(--s3) 0 var(--s2); }
.sort-line { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; }
.sort-legend { color: var(--muted); font-size: var(--fs-xs); font-weight: 700; }

/* 🔴 通知を通常フローに置くと、出るたびに一覧が1行ぶん（47px）押し下がり、ブラウザが通知の位置まで
      スクロールを戻す＝いま保存した行が画面外へ消える（390pxで scrollY 1623→491。2026-08-19 UI採点）。
      画面下端に固定し、スクロールは一切動かさない（→ app.js の toast()）。
      固定要素は中間スクロールでは行に重なるので、覆う面積を最小にする作りにする:
        ・幅は文字ぶん（fit-content）で、広い画面でも最大340px＝行の一部だけ
        ・余白は s2/s3 まで詰める（1行なら 110×39px＝行の11〜19%）
        ・3秒で消える（解約の説明だけ4秒）
        ・pointer-events: none ＝下の行はトーストが出ている間もそのまま押せる */
.toast {
  position: fixed; z-index: 5;
  right: 0; bottom: calc(var(--s4) + env(safe-area-inset-bottom)); left: 0;
  width: fit-content; max-width: min(340px, calc(100% - 40px)); margin: 0 auto;
  padding: var(--s2) var(--s3); border: 1px solid var(--line); border-radius: var(--r-m);
  background: var(--card); color: var(--ink); font-size: var(--fs-m); font-weight: 700; text-align: center;
  box-shadow: var(--shadow-pop); pointer-events: none;
}

.col-side, .col-main { display: contents; }
/* 単位（/月・/2ヶ月）を数字と同じ塊で右寄せすると、単位が長い行だけ数字が左にずれる。
   単位に固定幅の列を与え、数字の右端をそろえる。列幅は表示中の最長単位に合わせてJSが更新する。 */
.sub-list { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; container: list / inline-size;
  /* 数字の列幅はJSが実測して上書きする（下は測る前の保険） */
  --unit-col: 1.6em; --amount-col: 104px; --secondary-col: 84px; --due-col: 84px; }
.sub-row { border-radius: var(--r-l); background: var(--card); box-shadow: var(--shadow); }
/* 解約済み: 破線枠と「◯月◯日に解約」の文字（色に依存しない表現）は維持したうえで、
   減光・取り消し線・ピルを足す。小さい文字は減光後もAAを保つよう濃色に寄せる。 */
.sub-row.is-cancelled { background: transparent; border: 1px dashed var(--line); box-shadow: none; opacity: .72; }
.sub-row.is-cancelled .sub-amount { text-decoration: line-through; }
.sub-row.is-cancelled .sub-meta, .sub-row.is-cancelled .sub-due { color: var(--ink); }

/* 行は2段組み。1段目＝名前と主数値、2段目＝説明と従数値。
   名前と数字を同じ行に押し込むと390pxで名前が必ず省略される（Adobe Creative … になる）。 */
.sub-button {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr) auto;
  grid-template-rows: auto auto;
  column-gap: 10px; row-gap: 2px;
  align-items: center;
  position: relative;
  width: 100%; padding: var(--s3); border: 0; border-radius: var(--r-l);
  /* 右だけ広く空ける。編集の目印をこの余白に絶対配置する（グリッドの列は増やさない＝右端そろえを崩さない） */
  padding-right: 26px;
  background: none; text-align: left; cursor: pointer;
}
/* 静止画でも「押せる」と分かる目印。ホバーでは色が濃くなる（行の地色と影も上がる）。 */
.sub-caret { position: absolute; top: 50%; right: 8px; transform: translateY(-50%);
  color: var(--muted); font-size: var(--fs-l); font-weight: 700; line-height: 1; pointer-events: none; }

/* 🔴 行は編集・解約・削除への唯一の入口なのに、ホバーで地色も影も動かず、cursor:pointer しか
      変わらなかった＝静的なカードに見える（2026-08-19 UI採点）。地色と影を上げる。
      hover:hover の環境だけに出す（タップ端末で押した行のホバーが残らないように）。
      .sub-row と .sub-button の両方に書くのは、どちらを測っても変化が見えるようにするため。 */
@media (hover: hover) {
  .sub-row:hover, .sub-button:hover { background: var(--row-hover); box-shadow: 0 4px 14px rgba(20, 35, 30, .09); }
  /* 破線の解約済みカードに影を足すと浮いて見えるので、線の色で応える（チップのホバーと同じ作法） */
  .sub-row.is-cancelled:hover { border-color: var(--brand); }
  .sub-row.is-cancelled:hover, .sub-row.is-cancelled .sub-button:hover { box-shadow: none; }
  .sub-button:hover .sub-caret { color: var(--ink); }
}
.sub-emoji { grid-area: 1 / 1 / 3 / 2; font-size: 22px; line-height: 1; text-align: center; }
.sub-title { grid-area: 1 / 2 / 2 / 3; display: flex; gap: 6px; align-items: center; min-width: 0; }
/* 390pxは横に伸ばす先が無いので、切るのではなく3行まで折り返す（4行目からは…）。
   2行までにすると、右端に編集の目印を置いたぶん（14px）名前の列が158pxになり、
   「Adobe Creative Cloud コンプリート…」で切れる。名前を切るより1行ぶん（21px）伸ばすほうを取る。 */
/* 🔴 長い英単語（Supercalifragilistic…）は既定では折返し位置が無く、横に243pxはみ出したまま
      text-overflow:clip で切れていた＝切れた事実が画面から読めない（2026-08-19 UI採点）。
      overflow-wrap:anywhere で「他に手が無ければ字の途中で折る」を許し、はみ出しを0にする。
   🔴 反対に日本語は既定でどこでも折れるので「コンプリートプラ / ン」と1文字だけ次行に落ちていた。
      word-break:keep-all でカタカナ語の中割れを止める（英字の空白での折返しはそのまま効く）。
      2つで役割が違う: keep-all が中割れを禁じ、それでも1語が行に収まらないときだけ anywhere が折る。 */
.sub-title strong { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; min-width: 0; overflow: hidden; font-size: 15px; line-height: 1.4; overflow-wrap: anywhere; word-break: keep-all; text-overflow: ellipsis; }
.pill { flex: 0 0 auto; padding: 2px var(--s2); border: 1px solid var(--line); border-radius: var(--r-pill); color: var(--muted); font-size: var(--fs-xs); font-weight: 700; white-space: nowrap; }
.sub-meta { grid-area: 2 / 2 / 3 / 3; min-width: 0; overflow: hidden; color: var(--muted); font-size: var(--fs-xs); line-height: 1.4; text-overflow: ellipsis; white-space: nowrap; }
.sub-rel { color: var(--ink); font-weight: 700; }
/* 今日・明日の請求だけは埋没させない。赤は「消える操作」で使い切っているので琥珀の点を打つ */
.sub-rel.is-soon { color: var(--amber); }
.sub-rel.is-soon::before { content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 5px; border-radius: 50%; background: currentColor; vertical-align: middle; }
/* 数字は右列にまとめて縦積み。並び替えキーがいちばん上・いちばん大きい */
.sub-figures { grid-area: 1 / 3 / 3 / 4; display: flex; flex-direction: column; align-items: flex-end; justify-content: center; line-height: 1.35; }
.sub-fig { display: inline-grid; grid-template-columns: auto var(--unit-col); align-items: baseline; white-space: nowrap; }
.fig-unit { text-align: left; }
.sub-amount { color: var(--ink); font-size: var(--fs-m); font-weight: 700; }
.sub-secondary { color: var(--muted); font-size: var(--fs-s); }
.sub-due { color: var(--muted); font-size: var(--fs-xs); }
/* 🔴 並び替えキーが、その行でいちばん大きい数字になる。
   請求日順なら日付、年額順なら年額。逆転すると「何で並んでいるか」が字面から読めない。 */
.sort-due .sub-due { order: -1; color: var(--ink); font-size: var(--fs-l); font-weight: 700; }
.sort-due .sub-amount { font-size: var(--fs-m); font-weight: 400; }
.sort-yearly .sub-amount { font-size: var(--fs-l); font-weight: 800; }
.sort-yearly .sub-secondary { color: var(--ink); font-size: var(--fs-s); font-weight: 700; }

.empty-state { padding: 34px 20px; border: 1px dashed var(--line); border-radius: var(--r-l); color: var(--muted); text-align: center; }
.empty-state strong { display: block; margin-bottom: 6px; color: var(--ink); font-size: var(--fs-l); }

/* 一覧の末尾に通常フローで置く。sticky にすると、どのスクロール位置でも後ろの行を1〜2行ぶん隠す。
   「常に見えるが必ず何かを覆うCTA」より「覆わないCTA2本（ページ先頭と一覧末尾）」を選ぶ。 */
.add-button { width: 100%; min-height: 56px; margin-top: var(--s4); }
.footnote { margin-top: 26px; color: var(--muted); font-size: var(--fs-xs); line-height: 1.7; }

/* 中身が1×1pxのinputなので、包んでいるラベル側でリングを描く（Tabで到達しても何も見えない状態を潰す） */
.file-button { display: inline-flex; align-items: center; justify-content: center; width: 100%; }
.file-button:focus-within { outline: 3px solid var(--brand); outline-offset: 2px; }

.sheet { width: min(560px, 100%); max-height: 88dvh; padding: 0; border: 0; border-radius: var(--r-xl) var(--r-xl) 0 0; background: var(--paper); color: var(--ink); }
/* [open] を必ず付ける。付けないと dialog:not([open]){display:none} を上書きして閉じたシートが出っぱなしになる */
.sheet[open] { display: flex; flex-direction: column; }
.sheet::backdrop { background: rgba(10, 18, 16, .45); }
.sheet-head { display: flex; align-items: center; justify-content: space-between; position: sticky; top: 0; z-index: 1; padding: var(--s4) var(--s4) var(--s3); border-bottom: 1px solid var(--line); background: var(--paper); }
/* 本文がヘッダの下に潜っていることを影で示す（境界線だけだと、上に続きがあるのか読めない） */
.sheet.is-scrolled .sheet-head { box-shadow: var(--shadow-pop); }
.sheet-head h2 { font-size: var(--fs-xl); }
.sheet-head-actions { display: flex; gap: var(--s2); align-items: center; }
/* scroll-padding-bottom はブラウザが勝手に行うスクロール（フォーカス移動）用の下駄。
   これが無いと、下の sticky フッターの裏でちょうど「見えない位置」に止まる。 */
.sheet-body { flex: 1 1 auto; min-height: 0; padding: var(--s4) var(--s4) calc(var(--s5) + env(safe-area-inset-bottom)); overflow-y: auto; scroll-padding-bottom: 96px; }
/* フッターがあるシートは下の余白をフッター自身が持つ。body側に残すと、その隙間から中身が覗く */
.sheet-body:has(.sheet-foot) { padding-bottom: 0; }
/* スクロール領域の中の sticky フッター。sheet-head(top:0) と上下で対になる。
   これが無いと390pxで「保存する」が y=847（ビューポート844）に落ちて画面外に出る。 */
.sheet-foot { position: sticky; z-index: 2; bottom: 0; display: grid; gap: var(--s2); margin: 14px calc(var(--s4) * -1) 0; padding: var(--s3) var(--s4) calc(14px + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); background: var(--paper); }
/* フッターの上端でハードに切ると、ちょうど境目にあるカード（「記録ごと削除」）が15pxの丸い
   切れ端になり、描画不良に見える（2026-08-19 UI採点）。潜っていくことを20pxのフェードで示す。 */
.sheet-foot::before { content: ""; position: absolute; right: 0; bottom: 100%; left: 0; height: 20px;
  background: linear-gradient(to top, var(--paper), transparent); pointer-events: none; }
/* 末尾まで送ったら消す。残したままだと最後のカードが常に半分かすんで見える */
.sheet.is-bottom .sheet-foot::before { opacity: 0; }

.field { display: block; margin-bottom: var(--s3); }
.field-label { display: block; margin-bottom: 5px; color: var(--muted); font-size: var(--fs-xs); font-weight: 700; }
.field-label em { padding: 1px 6px; border-radius: var(--r-pill); background: var(--line); color: var(--ink); font-size: var(--fs-xs); font-style: normal; }
.field input, .field select { width: 100%; min-height: 48px; padding: var(--s2) var(--s3); border: 1px solid var(--line); border-radius: var(--r-m); background: var(--card); }
/* 足りない欄そのものを示す。赤い文言だけだと、どの欄の話か目で追う手間が残る。
   線幅を変えず inset の影で太らせる（枠が太ると1pxぶん中身がずれる） */
.field input.is-invalid { border-color: var(--danger); box-shadow: inset 0 0 0 1px var(--danger); }
.field-hint { display: block; margin-top: var(--s1); color: var(--muted); font-size: var(--fs-xs); }
/* 入力ではなく結果。枠を持たせず、値だけ本文色で置く */
.field-derived { margin-bottom: var(--s3); }
.field-derived span:last-child { color: var(--ink); font-size: var(--fs-m); font-weight: 700; }
.field-row { display: flex; gap: var(--s2); }
.field-row > .field { flex: 1; min-width: 0; }
/* .field-row > .field { flex: 1 } の方が詳細度が高く、`.field-emoji` 単体では負けて
   絵文字欄がサービス名と同じ156pxになっていた（2026-08-19 UI採点）。同じ詳細度で後から上書きする。 */
.field-row > .field-emoji { flex: 0 0 80px; }
.cycle-field { margin: 0 0 var(--s3); padding: 0; border: 0; }
.cycle-inputs { display: flex; gap: var(--s2); }
.cycle-inputs input { flex: 0 0 84px; }
.cycle-inputs select { flex: 1; }

.preset-area { margin-bottom: var(--s2); }
/* 🔴 窓が260pxしかなく、3,091pxの中身の8.4%だけが見えて、次のカードを20pxで硬く切っていた
      ＝レンダリング不良に見える（2026-08-19 UI採点）。窓を7枚ぶん（56px×7−すき間＝388px）に広げ、
      続きがあることは下端のフェードで示す。
      ここは「JSが実測して切りそろえる前の保険」（→ syncPresetWindow）。カードの高さは名前が
      1行か2行かで変わるので、CSSの倍数計算だけでは最後のカードが途中で切れる。
      --preset-row … カード48px＋すき間8px。+4px は自分の上下padding（フォーカスリング用）。 */
.preset-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: var(--s2);
  --preset-row: 56px;
  max-height: min(56vh, calc(var(--preset-row) * 7 - var(--s2) + 4px));
  overflow-y: auto; padding: 2px; }
/* 下端のフェードは「まだ続きがある」ときだけ（末尾まで送ったら消す）。JS がクラスを付け外しする */
.preset-grid.has-more { mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent); }
.preset-chip { display: flex; gap: var(--s2); align-items: center; min-height: 48px; padding: var(--s2) var(--s2); border: 1px solid var(--line); border-radius: var(--r-m); background: var(--card); text-align: left; cursor: pointer; }
.preset-chip:hover { border-color: var(--brand); }
/* 同梱の名前（Amazon プライム・YouTube Premium）が「…」で切れると、どれか判別できない。
   2行まで折り返す＋390pxでは1列にして、省略が起きない幅を必ず与える。 */
.preset-chip b { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; font-size: var(--fs-s); font-weight: 700; line-height: 1.3; }
.preset-chip span { color: var(--muted); font-size: var(--fs-xs); }
.preset-chip .preset-emoji { font-size: 20px; }
.preset-chip div { min-width: 0; }
.preset-empty { padding: var(--s4) var(--s1); }
.preset-empty p { margin-bottom: var(--s2); color: var(--muted); font-size: var(--fs-m); }
@media (max-width: 440px) {
  .preset-grid { grid-template-columns: 1fr; }
}

.manual { margin-top: var(--s3); border-top: 1px solid var(--line); padding-top: var(--s3); }
.manual.is-editing { margin-top: 0; border-top: 0; padding-top: 0; }
.manual.is-editing > summary { display: none; }
/* 開閉も「枠線」系統で書く。緑の下線テキストだと第4の様式になる */
.manual summary { display: inline-block; list-style: none; cursor: pointer; }
.manual summary::-webkit-details-marker { display: none; }
.manual[open] summary { margin-bottom: var(--s2); }
/* 結果の表示であって選択中ではないので、ミントの地色は使わない（緑＝押せるものだけ） */
.preview { margin: var(--s1) 0 var(--s3); padding: var(--s2) var(--s3); border: 1px solid var(--line); border-radius: var(--r-s); background: var(--card); color: var(--ink); font-size: var(--fs-s); line-height: 1.6; }
.form-error { margin-bottom: var(--s2); color: var(--danger); font-size: var(--fs-s); font-weight: 700; }
.sheet-foot .form-error { margin: 0; }
.sheet-actions { display: grid; gap: var(--s2); }

.settings-card { margin-bottom: 14px; padding: var(--s4); border: 1px solid var(--line); border-radius: var(--r-l); background: var(--card); }
.settings-card h3 { margin-bottom: var(--s2); font-size: var(--fs-l); }
.settings-card .button { width: 100%; }
.help { margin-bottom: var(--s2); color: var(--muted); font-size: var(--fs-s); line-height: 1.7; }
.import-mode { margin: 0 0 var(--s2); padding: 0; border: 0; }
.import-mode label { display: flex; gap: var(--s3); align-items: center; min-height: 44px; margin: 0 calc(var(--s2) * -1); padding: var(--s1) var(--s2); border-radius: var(--r-s); font-size: var(--fs-m); cursor: pointer; }
.import-mode label:hover { background: var(--brand-soft); }
.import-mode input[type="radio"] { display: grid; flex: 0 0 22px; place-items: center; width: 22px; height: 22px; margin: 0; padding: 0; border: 2px solid var(--muted); border-radius: 50%; background: var(--card); appearance: none; -webkit-appearance: none; cursor: pointer; }
.import-mode input[type="radio"]::after { content: ""; width: 12px; height: 12px; border-radius: 50%; background: transparent; }
.import-mode input[type="radio"]:checked { border-color: var(--brand); }
.import-mode input[type="radio"]:checked::after { background: var(--brand); }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

@media (min-width: 600px) {
  .sheet { border-radius: var(--r-xl); }
  .sheet-foot { border-radius: 0 0 var(--r-xl) var(--r-xl); }
}

/* 行のレイアウトは「ビューポート幅」ではなく「一覧そのものの幅」で切り替える。
   ビューポート1080pxは2カラムに割れるので一覧は644pxしかなく、単一カラムの1024px（860px）より狭い。
   メディアクエリで組むと、この逆転のせいでどちらかの帯が必ず崩れる。 */
@media (min-width: 600px) {
  /* 🔴 720px固定だと960〜1279pxで左右に120pxずつ死んだ余白ができ、その内側で名前が折り返していた
     （2026-08-19 UI採点）。一覧は860pxまで伸ばす（それ以上は行の中央が空くだけ）。 */
  .app-shell { max-width: 900px; }
  .footnote { max-width: 720px; }
}

/* 一覧が480px以上あれば行を横に寝かせる。縦積みのまま幅だけ広げると行の中央が500px以上空く
   （iPad縦 768/810/834 が該当していた）。数字は種類ごとの固定幅の列に入れ、行をまたいで右端をそろえる。
   金額と「その月あたり」は同じ量の言い換えなので1つの列に縦に積む＝並び替えで列数が変わらない。
   大小（＝並び替えキー）は列の位置ではなく文字サイズで示す。 */
@container list (min-width: 480px) {
  .sub-button {
    grid-template-columns: 26px minmax(0, 1fr) var(--amount-col) var(--due-col);
    grid-template-rows: auto auto;
    column-gap: var(--s3);
    min-height: 56px; padding: var(--s2) var(--s4); padding-right: 32px;
  }
  .sub-emoji { grid-area: 1 / 1 / 3 / 2; font-size: 20px; }
  .sub-title { grid-area: 1 / 2 / 2 / 3; }
  /* 文字だけ大きくする。折り返しの許可は狭い画面と同じまま＝名前はどの幅でも省略しない。
     1行に収まらない名前がある行だけ高くなるが、切って読めなくするよりはいい
     （600〜1024pxで「Adobe Creative Cloud コンプリートプ…」になっていた） */
  .sub-title strong { font-size: var(--fs-l); line-height: 1.35; }
  .sub-meta { grid-area: 2 / 2 / 3 / 3; line-height: 1.3; }
  .sub-figures { display: contents; }
  .sub-amount { grid-area: 1 / 3 / 2 / 4; align-self: center; justify-self: end; }
  .sub-secondary { grid-area: 2 / 3 / 3 / 4; justify-self: end; }
  /* 従数値が無い請求日順では、金額が2段ぶんの高さの中央に来る */
  .sort-due .sub-amount { grid-area: 1 / 3 / 3 / 4; }
  /* 日付は専用の列に入る。金額と桁をそろえるための空の単位セルはここでは畳む */
  .sub-due { grid-area: 1 / 4 / 3 / 5; align-self: center; justify-self: end; grid-template-columns: auto 0; }
}

/* 一覧が640px以上（請求日順）／720px以上（年額順・数字が1つ多いぶん遅らせる）:
   説明を名前の下から独立した列へ出し、行を1段（56px→48px）に畳む。広げたぶんが行数になる。
   🔴 説明の列は max-content（その行の説明ぶんだけ）にして、余りは全部名前に渡す。
      固定180pxにすると、右に300px空いているのに名前だけ「Adobe Creative Cloud コンプリートプ…」
      と切れた（2026-08-19 UI採点）。名前は折り返せるので、幅が足りなければ2行になるだけで切れない。
      ⚠️ 右寄せ（justify-self:end）の要素は幅が content になる＝列より広いと左へはみ出し、
         省略記号ではなく隣の名前に重なる（768pxで実測 -4px）。max-width:100% で列に閉じ込める。
      並びの整列: 可変なのは名前と説明の境目だけ。説明より右は固定幅なので右端は行をまたいでそろう。
      日付の列は解約済みの「◯月◯日に解約」だけ長いので、そのときだけ広がる（利用中は常に80px）。 */
@container list (min-width: 640px) {
  .sort-due .sub-button {
    /* 名前セルの最小幅は180pxのまま。カタカナの中割れ（コンプリートプラ / ン）は word-break: keep-all
       だけで直る（180pxでも「コンプリートプラン」＝16px×9字＝144pxは1行に収まる）。
       ⚠️ 220pxに広げると、その40pxは説明の列（minmax(0, max-content)）から取られ、
          680px請求日順・768px年額順で「あと2日 · クリエイ…」と説明が省略された
          （scratch/edge-check.mjs の省略検査＝維持項目に引っかかる。24件中3件で実測）。 */
    grid-template-columns: 26px minmax(180px, 1fr) minmax(0, max-content) var(--amount-col) var(--due-col);
    grid-template-rows: auto; min-height: 48px; column-gap: 10px;
  }
  .sort-due .sub-emoji { grid-area: 1 / 1 / 2 / 2; }
  .sort-due .sub-title { grid-area: 1 / 2 / 2 / 3; }
  .sort-due .sub-meta { grid-area: 1 / 3 / 2 / 4; justify-self: end; max-width: 100%; text-align: right; }
  .sort-due .sub-amount { grid-area: 1 / 4 / 2 / 5; }
  .sort-due .sub-due { grid-area: 1 / 5 / 2 / 6; }
}

@container list (min-width: 720px) {
  .sort-yearly .sub-button {
    grid-template-columns: 26px minmax(180px, 1fr) minmax(0, max-content) var(--amount-col) var(--secondary-col) var(--due-col);
    grid-template-rows: auto; min-height: 48px; column-gap: 10px;
  }
  .sort-yearly .sub-emoji { grid-area: 1 / 1 / 2 / 2; }
  .sort-yearly .sub-title { grid-area: 1 / 2 / 2 / 3; }
  .sort-yearly .sub-meta { grid-area: 1 / 3 / 2 / 4; justify-self: end; max-width: 100%; text-align: right; }
  .sort-yearly .sub-amount { grid-area: 1 / 4 / 2 / 5; }
  .sort-yearly .sub-secondary { grid-area: 1 / 5 / 2 / 6; }
  .sort-yearly .sub-due { grid-area: 1 / 6 / 2 / 7; }
}

/* 1080px以上: 左に「3つの数字＋内訳＋高い順の上位5件」を貼り付け、右を一覧にする。
   中央寄せしただけだと左右が死に、24件でページが2,952px（初期表示4.5行）になる。
   🔴 切替点は「切り替えた瞬間に一覧が640pxを割らない」幅にする。1000pxで割ると、単一カラムで
      1段だった行が2カラムに変わった途端2段へ戻る（1080 - 64の余白 - 320 - 52 = 644px）。
   🔴 ガターは28→52px、外側は170→72pxにする。以前は中身が接着してページ端だけ空いていた
      うえ、300pxの箱に7桁のhero（341px）が収まらず一覧カードが上に描かれていた（2026-08-19 UI採点）。 */
@media (min-width: 1080px) {
  .app-shell { max-width: 1360px; padding-right: 32px; padding-left: 32px; }
  main { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: 52px; align-items: start; }
  /* min-width:0 と overflow で、溢れた数字が隣の列へ出ていくのを封じる（切れて見える原因）。
     縦は auto。700px高のウィンドウでも左カラムの下端（上位5件の注記）まで届く。 */
  .col-side { display: block; position: sticky; top: var(--s4); min-width: 0;
    max-height: calc(100dvh - var(--s6)); overflow: hidden auto; container-type: inline-size; }
  .col-main { display: block; min-width: 0; }
  /* 器ではなく「左カラムの幅」で縮める。vw基準だと1440pxでも68pxのままで箱から出る。
     16cqi＝320pxのとき51px。¥99,999,999（12字＝約5.7em）でも箱に収まる。 */
  .summary-main { font-size: clamp(28px, 16cqi, 60px); }
  .summary { padding-top: var(--s3); }
  .breakdown { margin-top: var(--s5); }
  .breakdown > .breakdown-label { display: block; }
  .breakdown-toggle { display: none; }
  .toplist { display: block; }
  .list-controls { margin-top: 6px; }
  .add-button { min-height: 52px; }
}


/* 1360px以上: 器はもう広げず、空いた幅は左カラムに渡す。一覧をこれ以上広げても、短い名前の行は
   中央が500px近く空くだけ（名前の列が1frなので余りは全部そこに行く）。左カラムなら数字が大きくなり、
   内訳の棒も上位5件の名前も伸びる＝同じ幅が中身になる。 */
@media (min-width: 1360px) {
  main { grid-template-columns: 400px minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* 共有は一覧の後ろで余白を取り、操作中の行を覆わない。 */
.foot { margin-top: var(--s6); }
/* 既存の入力様式を使い、カード内の操作を縦に揃える。 */
#reminder-card .field input, #reminder-card .field select { min-height: 44px; }
#reminder-card .help { overflow-wrap: anywhere; }
#reminder-registered .button + .button { margin-top: var(--s2); }
#reminder-help:not(:empty) { margin-top: var(--s3); }
/* 失敗だけ赤（赤は「消える操作とエラー」専用）。成功・進行中は通常の help のまま */
#reminder-help.is-error { color: var(--danger); font-weight: 700; }
/* 共有欄はこのアプリの寸法に寄せる（share.css は hundred-days の複製なので触らず、ここで上書き）。
   幅は一覧と同じ上限、角丸は他のボタンと同じ12px、コピー結果の予約行は詰めて説明を近づける */
.share { max-width: 720px; }
.share__button { border-radius: var(--r-m); }
.share__said { min-height: 1.2em; margin-top: 4px; }
.share__note { margin-top: 0; }
/* 状態名は本文より先に目に入る1行。色は --ink（緑は操作専用） */
.reminder-state { display: block; margin-bottom: 4px; color: var(--ink); font-size: var(--fs-m); font-weight: 700; }
