/* public/assets/css/style.css — DOPP shared styles (design handoff v1, 2026-09-03) */

:root {
  --bg: #F6F6F3;
  --card: #FFFFFF;
  --ink: #181817;
  --muted: #65645F;
  --line: #DEDED8;
  /* 第37便 (2026-09-15): 赤を1段濃くした (Home 改善の H13)。前は #D64524 で、白の上 4.43:1 / 背景の上 4.10:1 と
     本文サイズの AA (4.5:1) をわずかに下回っていた。赤は**文字としても** 14 種類 (This week / NOW PLAYING /
     本文中のリンク / @名前 / Editing / NEW …) に使っていて、白抜きの地 (Answer などのボタン・NEW のラベル) も同じ色だった。
     ⚠ --accent-dark は「押した瞬間の色」4 か所 (.btn-primary:active / .play:active / .link:active) と .msg-error の文字。
       --accent を濃くした分こちらも下げてある。**同じ値にすると押した時の反応が消える** */
  --accent: #B7371C;        /* 背景の上 5.42:1 / カードの上 5.87:1 / 白抜き 5.87:1 */
  --accent-dark: #9E2F17;   /* 背景の上 6.75:1 / カードの上 7.31:1 */
  --sans: 'Inter', 'Noto Sans JP', -apple-system, BlinkMacSystemFont, 'Hiragino Sans', sans-serif;
  --r-btn: 12px;
  --tap: 44px;

  /* 第54便 (2026-09-22): ここから下は「今の値に名前を付けただけ」の色。新しい色は 1 つも無い。
     基本の 7 色 (上) はそのまま。ダークモード (G の 2 段目) ではこの名前ごとに暗い値を入れる。
     ⚠ 名前を付けた時点で見た目は 1px も変わっていない (tests/fn_color_tokens.mjs が撮り比べで確かめている) */
  --on-fill: #fff;                      /* 塗りの上の白い文字・アイコン・つまみ (赤いボタン・黒い再生ボタン・吹き出し・黒いバー) */
  --press: rgba(24,24,23,0.06);         /* 丸いボタンを押した瞬間の薄い影 */
  --scrim: rgba(24,24,23,0.45);         /* シートの後ろの暗い幕 */
  --shadow: rgba(0,0,0,0.08);           /* 浮いた部品の影 (シート・メニュー・切替) */
  --shadow-knob: rgba(0,0,0,0.2);       /* スイッチのつまみの影 */
  --shadow-mini: rgba(0,0,0,0.25);      /* 棚のタイルの小さい再生ボタンの影 */
  --shadow-drag: rgba(0,0,0,0.28);      /* 棚で掴んだ盤の影 */
  --bg-clear: rgba(246,246,243,0);      /* --bg の透明版 (棚の右端のぼかし) */
  --on-dark-2: rgba(255,255,255,0.65);  /* 黒いバーの中の 2 行目の文字 */
  --on-dark-press: rgba(255,255,255,0.8); /* 黒いバーの再生ボタンを押した瞬間 */
  --on-dark-line: rgba(255,255,255,0.18); /* 吹き出しのボタンの区切り線 */
  --ok: #2E7D6B;                        /* Username が空いている時の緑の文字 */
  --ok-bg: #E9F0E8;                     /* うまくいった時のお知らせの地 */
  --ok-ink: #2E4A33;                    /* 同じく文字 */
  --err-bg: #FBE9E4;                    /* 失敗した時のお知らせの地 */
  --placeholder: #9A998F;               /* 入力欄の薄い案内文 */
  --ink-press: #333;                    /* Following (黒い丸ボタン) を押した瞬間 */
  --rec: #181817;                       /* レコード盤の黒 (⚠ --ink と同じ値だが意味が違う。暗くしても盤は黒のまま) */
  --rec-groove: #3A3A38;                /* レコード盤の溝 */
  /* ⚠⚠ 第37便より前の赤 (#D64524) の残骸。値は変えずに名前だけ付けた。今の赤に揃えるかは G の 2 段目で決める */
  --accent-a06: rgba(214,69,36,0.06);   /* 新着の行・棚に落とす時の薄い赤 */
  --accent-a07: rgba(214,69,36,0.07);   /* お知らせの帯の地 */
  --accent-a50: rgba(214,69,36,0.5);    /* Talk の新着の点が脈打つ影 (始まり) */
  --accent-a00: rgba(214,69,36,0);      /* 同じく (終わり) */
  --brand-dot: #D64524;                 /* 上の帯のロゴの中の赤い点 */
  /* 第55便 (ダークモード) で足した 4 つ。明るい画面では今までと同じ値。暗い画面の値は一番下 */
  --accent-text: #B7371C;               /* 赤い文字 (ボタンの地の赤とは別の名前。暗い画面で明るくする) */
  --accent-fixed: #B7371C;           /* 白い丸の上の赤 (第93便: Covers の ♥ を押した後)。白い丸は暗い画面でも白なので、この赤も暗い画面で変えない */
  --fill-ink: #181817;                  /* 黒く塗った部品の地 (Following・再生中のバー・吹き出し) */
  --on-ink: #fff;                       /* その上の文字 */
  --rec-rim: transparent;               /* レコード盤の外周の線 (明るい画面では見えない) */
  /* 第75便 (2026-09-26): 失敗のお知らせ (.msg-error) の文字。明るい画面は今までと同じ --accent-dark の値。
     暗い画面では --accent-dark (押した瞬間の色) のままだと地 --err-bg の上で 2.02:1 しかなかったので、別の名前にした */
  --err-text: #9E2F17;
  --sh-disc: #DEDED8;                   /* 第96便: Share のシートの行き先のマークの丸 (灰色) */
  --sh-mark: #181817;                   /* 同じくロゴの色 */
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}
a { color: var(--ink); text-decoration: none; }
/* 第32便: 画面には出ないが読み上げには届く文字 (Home の h1)。display:none だと読み上げにも届かないのでこの形 */
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
button { font-family: inherit; color: inherit; }
svg { display: block; }

/* Layout */
.app { max-width: 430px; margin: 0 auto; min-height: 100vh; display: flex; flex-direction: column; }
/* ⚠⚠ 第42便 (2026-09-16): iPhone で「中身の下まで余分にスクロールできる」のを止める。
   iOS の `100vh` は **ブラウザの上下のツールバーが引っ込んだ状態の高さ**を指すので、
   ツールバーが出ている間は `.app` が見えている画面より 94〜128px 高くなり、その分だけ下へ送れてしまう
   (一番下で跳ね返る間、固定しているナビが一瞬ずれて描かれるのもこれが原因)。
   `svh` は「ツールバーが出ている時の、いちばん小さい高さ」。これにすると余分なスクロールがゼロになる。
   ⚠ パソコンには引っ込むツールバーが無いので `svh = vh`。**パソコンの見え方は 1px も変わらない**。
   ⚠ 上の `100vh` は消さないこと(`svh` を知らない古いブラウザ向けの土台)。
   ⚠ `viewport-fit=cover` とは別の話。あちらはナビが約34px 高くなるので、今も宿題のまま */
@supports (min-height: 100svh) {
  .app { min-height: 100svh; }
}
.main { flex: 1; padding: 0 16px 104px 16px; }

/* Top bar */
.topbar { display: flex; align-items: center; justify-content: space-between; height: 56px; padding: 0 16px; }
.brand { display: flex; align-items: center; gap: 8px; color: var(--ink); }
.brand-mark { font-size: 16px; font-weight: 700; letter-spacing: 0.14em; }
.topbar-note { font-size: 13px; color: var(--muted); }
.topbar-right { display: flex; align-items: center; gap: 4px; margin-right: -10px; }
.bell { position: relative; }
.bell .dot { position: absolute; top: 9px; right: 9px; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); border: 2px solid var(--bg); }
.bell .dot:not(.hidden) { animation: dotpulse 1.6s ease-out 0.2s 2; }
.bell.ring svg { transform-origin: 50% 4px; animation: ring 1.2s ease-in-out 0.25s 1; }
.bell.inbox.ring svg { transform-origin: 50% 50%; animation: nudge 1s ease-in-out 0.25s 1; }
@keyframes ring { 0%, 100% { transform: rotate(0); } 15% { transform: rotate(14deg); } 30% { transform: rotate(-12deg); } 45% { transform: rotate(9deg); } 60% { transform: rotate(-6deg); } 75% { transform: rotate(3deg); } }
@keyframes nudge { 0%, 100% { transform: translateY(0); } 25% { transform: translateY(-3px); } 50% { transform: translateY(0); } 75% { transform: translateY(-2px); } }
@keyframes dotpulse { 0% { box-shadow: 0 0 0 0 var(--accent-a50); } 100% { box-shadow: 0 0 0 8px var(--accent-a00); } }
.act-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line); color: var(--ink); min-height: 64px; }
.act-row.new { background: linear-gradient(to right, var(--accent-a06), transparent 60%); margin: 0 -16px; padding-left: 16px; padding-right: 16px; }
.act-row .act-main { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; color: var(--ink); }
.act-row .act-follow { flex-shrink: 0; }        /* Follow back on "started following you" */
.act-row .act-follow .fbtn { height: 32px; padding: 0 10px 0 8px; font-size: 13px; }
/* 第75便 v2 (本人の決定 案A): 「フォローしました」の行だけ、フォローボタンを文の下の段に置く。
   1段目 = 顔・文・種類の絵・時刻 (第95便で「送る」を外した) / 2段目 = フォローボタン (文の頭にそろえる = 顔 32 + 隙間 12)。
   前は1段に全部並べていたので、320px では文の幅が 4〜15px しか残らず、日本語は1文字ずつ16行に割れていた */
.act-row.has-follow { flex-wrap: wrap; row-gap: 6px; }
.act-row.has-follow .act-follow { order: 1; flex-basis: 100%; padding-left: 44px; }
.act-row .kind { width: 22px; height: 22px; color: var(--muted); flex-shrink: 0; }
.act-row .kind svg { width: 22px; height: 22px; }
.act-row .txt { flex: 1; min-width: 0; font-size: 15px; line-height: 1.45; }
.act-row .txt b { font-weight: 600; }
.act-row .txt .t { color: var(--muted); }
.act-row .txt .q { display: block; font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.act-row .when { font-size: 13px; color: var(--muted); white-space: nowrap; }
.card.flash { animation: flash 1.2s ease-out; }
@keyframes flash { 0% { box-shadow: 0 0 0 3px var(--accent); } 100% { box-shadow: 0 0 0 0 transparent; } }

/* Headings */
.section-head { display: flex; align-items: center; gap: 10px; margin: 32px 0 16px 0; }
/* 第32便 (2026-09-15): 中身は h2 になった (読み上げで節を拾えるように)。margin: 0 は h2 の既定の余白を消すためで、見た目は span の時と 1px も変わらない */
.section-title { font-size: 18px; font-weight: 700; line-height: 1.4; flex: 1; margin: 0; }
/* Home: where the last visit ended. Above it = placed while you were away */
/* 第34便 (2026-09-15): 一覧の先頭に出す新着の件数 (「3 new songs」/「No new songs」) */
.new-line { font-size: 13px; font-weight: 600; color: var(--muted); margin: 0 0 12px 2px; }
.seen-mark { height: 0; margin: 0; }                              /* 新着の一番下の「下」の印。高さ 0・余白 0 なので場所を取らない (余白の相殺もそのまま通る) */
.since-line { display: flex; align-items: center; gap: 10px; margin: 4px 0 16px 0; color: var(--muted); font-size: 13px; }
.since-line::before, .since-line::after { content: ""; flex: 1; border-top: 1px solid var(--line); }
.section-sub { font-size: 13px; color: var(--muted); }
.page-title { font-size: 22px; font-weight: 700; line-height: 1.3; margin: 24px 0 8px 0; }
.eyebrow { font-size: 13px; color: var(--accent-text); font-weight: 600; letter-spacing: 0.02em; }
.h-serif { font-size: 22px; font-weight: 700; line-height: 1.3; margin: 8px 0; }
.lead { font-size: 15px; color: var(--muted); }
.note { font-size: 13px; color: var(--muted); line-height: 1.4; }

/* Icon button (44x44 tap area, 22px glyph) */
.ibtn { width: var(--tap); height: var(--tap); border-radius: 50%; border: 0; background: transparent; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; color: var(--ink); padding: 0; }
.ibtn:active { background: var(--press); }
.ibtn.ghost { border: 1px solid var(--line); background: var(--card); }
.ibtn svg { width: 22px; height: 22px; }

/* Avatar (static circle) */
.avatar { border-radius: 50%; overflow: hidden; flex-shrink: 0; display: flex; align-items: center; justify-content: center; color: var(--on-fill); font-weight: 700; background: var(--muted); }
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar.a32 { width: 32px; height: 32px; font-size: 14px; }
.avatar.a44 { width: 44px; height: 44px; font-size: 18px; }
.avatar.a80 { width: 80px; height: 80px; font-size: 32px; }

/* Profile photo picker */
.photo-pick { display: flex; flex-direction: column; align-items: center; gap: 8px; margin: 8px 0 24px 0; }
.photo-wrap { position: relative; width: 96px; height: 96px; }
.photo-wrap .avatar { width: 96px; height: 96px; font-size: 36px; }
.photo-wrap .cam { position: absolute; right: -4px; bottom: -4px; width: 40px; height: 40px; border-radius: 50%; background: var(--fill-ink); color: var(--on-ink); border: 2px solid var(--bg); display: flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; }
.photo-wrap .cam svg { width: 20px; height: 20px; }
.photo-wrap input[type=file] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }

/* Profile */
.profile-head { display: flex; flex-direction: column; align-items: center; gap: 12px; padding-top: 16px; text-align: center; }
.profile-name { display: flex; align-items: center; gap: 4px; }
.handle { font-size: 22px; font-weight: 700; line-height: 1.3; }
/* Person page / My Picks: avatar on the left, who they are on the right, so "person → Now → shelves" fits one screen (2026-09-08) */
.profile-head.side { align-items: stretch; text-align: left; gap: 0; padding-top: 12px; }
.profile-head.side .head-row { display: flex; gap: 14px; align-items: flex-start; }
.profile-head.side .head-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.profile-head.side .profile-name { gap: 0; margin-left: -2px; }
.profile-head.side .handle { font-size: 20px; line-height: 1.2; overflow-wrap: anywhere; }
.profile-head.side .chips { justify-content: flex-start; }
.profile-head.side .stats { gap: 12px; margin-top: 6px; flex-wrap: wrap; }      /* below the bio (their words come before the numbers, 2026-09-07) */
.profile-head.side .stats > span, .profile-head.side .stats .stat { min-height: 32px; padding: 0 2px; position: relative; }
.profile-head.side .stats .stat::after { content: ""; position: absolute; inset: -6px 0; }        /* keeps the 44px tap height */
.profile-head.side .bio { max-width: none; margin-top: 8px; }
.profile-head.side .head-actions { margin-top: 12px; }
/* 第84便 (2026-09-29): プロフィールの外部リンク。本人の一行の下に、鎖の絵 + 先頭の 1 本 (+「ほか2件」)。
   黒の太字 + 灰色の鎖 (本人の決定 9。暗い画面では --ink が白になる)。
   ⚠ 押せる高さは箱そのもので 44px (名前を「…」で切るため overflow: hidden を使う = ::after で外へ広げる手は使えない。第45便の罠)。
   ⚠ 下の数字 (Followers など) の当たり判定は上へ 6px はみ出しているので、この箱の下に負の margin を付けないこと (取られる) */
.plinks { display: flex; min-width: 0; }
.plink { display: inline-flex; align-items: center; gap: 6px; min-height: var(--tap); max-width: 100%; min-width: 0; padding: 0; margin: 0; background: none; border: 0;
  font: inherit; font-size: 15px; font-weight: 600; line-height: 1.4; color: var(--ink); text-decoration: none; text-align: left; cursor: pointer; }
.plink svg { width: 16px; height: 16px; flex-shrink: 0; color: var(--muted); }
.plink-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plink-more { flex-shrink: 0; white-space: nowrap; font-weight: 400; color: var(--muted); }
/* 一覧のシート (2 本以上)。1 行 56px (押せる高さ 44px 以上 + 区切り線)。8 本で 85 + 56×8 = 533px = iPhone SE でもスクロールしない */
.plink-item { display: flex; align-items: center; gap: 12px; height: 56px; border-bottom: 1px solid var(--line); color: var(--ink); font-size: 15px; font-weight: 600; text-decoration: none; }
.plink-item svg { width: 20px; height: 20px; flex-shrink: 0; color: var(--muted); }
.plink-item .plink-name { flex: 1; }
/* Edit profile の「リンク」の段。1 本 = 見出し行 (サービス名 + ▲ ▼ ×) + URL の欄 + 名前の欄 (SNS 8 つの時は無い) */
.plink-edit { display: flex; flex-direction: column; gap: 8px; padding: 0 12px 12px; margin-bottom: 8px; border: 1px solid var(--line); border-radius: 12px; background: var(--card); }
.plink-edit-head { display: flex; align-items: center; gap: 4px; min-height: var(--tap); margin-right: -8px; }
.plink-edit-svc { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; color: var(--muted); }
/* 第73便: 日本語は1文字ずつ折り返せるので、人のページの「フォロー」が横に縮んで縦に4行に割れた (320px)。
   日本語の端末だけ折り返さない (英語は単語の途中で割れないので元から同じ形。英語の画面は1pxも変わらない) */
:lang(ja) .head-actions .btn { white-space: nowrap; }
/* 第75便: Inbox の行のボタン。320px の日本語で「返信」が「返/信」と1文字ずつに割れた (隣の「Picks に追加済み」が長いため)。
   日本語の端末だけ、語の途中では折り返さない (空白の所では折り返す)。英語の画面は1pxも変わらない */
:lang(ja) .send-row .acts .act span { word-break: keep-all; }
/* 第75便 (2026-09-26。本人の決定): 320px の人のページで Follow・Send a song・⋯ が1行に入らず、⋯ が右に 28px (日本語 41px) はみ出していた。
   狭い画面 (360px 以下) だけ、人のページの2つのボタンの中の小さな絵を外して間を 12 → 8px に。言葉は残す (絵だけのボタンにはしない)。390px 以上は今のまま。My Picks の Add Pick は触らない */
@media (max-width: 360px) {
  .head-actions:has(#more-wrap) { gap: 8px; }
  .head-actions #follow svg, .head-actions #send svg { display: none; }
  .head-actions #follow { padding: 0 12px; }     /* 英語の「Following」だけ、これが無いと ⋯ が 1px 余白にかかる */
}
.avatar.a64 { width: 64px; height: 64px; font-size: 26px; }
.uname { font-size: 13px; color: var(--muted); line-height: 1.3; margin-top: -2px; }
.uname:empty { display: none; }
/* username field: fixed @ in front, hint under */
.uwrap { position: relative; }
.uwrap .uat { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: var(--muted); font-size: 15px; pointer-events: none; }
.uwrap .input { padding-left: 30px; }
.uhint { min-height: 18px; }
.uhint.ok { color: var(--ok); }
.uhint.bad { color: var(--accent-text); }
.attrs { font-size: 13px; color: var(--muted); }
.chips { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.bio { font-size: 15px; line-height: 1.5; color: var(--ink); max-width: 320px; overflow-wrap: anywhere; }
.stats { display: flex; gap: 16px; font-size: 13px; color: var(--muted); align-items: center; }
.stats > span { display: inline-flex; align-items: center; gap: 4px; min-height: var(--tap); padding: 0 4px; }
.stats b { color: var(--ink); font-weight: 600; }
.stats .stat { background: none; border: 0; padding: 0 4px; min-height: var(--tap); font: inherit; color: inherit; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; }
.stats .stat:active b { color: var(--accent-text); }
.sheet .person svg { width: 22px; height: 22px; color: var(--muted); }

/* Chips: tappable filter chips are 44px tall; display-only tags are 28px */
.chip { height: var(--tap); padding: 0 16px; border-radius: 22px; border: 1px solid var(--line); background: var(--card); color: var(--ink); font-size: 13px; font-weight: 500; cursor: pointer; display: inline-flex; align-items: center; white-space: nowrap; }
.chip.on { background: var(--fill-ink); color: var(--on-ink); border-color: var(--fill-ink); }
.chip.dashed { border-style: dashed; color: var(--muted); }
/* Add Pick sheet: the example collection names sit behind "Ideas ›" once you have a collection of your own */
.ideas { background: none; border: 0; padding: 0 4px; min-height: var(--tap); display: inline-flex; align-items: center; gap: 4px; color: var(--muted); font-size: 13px; font-weight: 500; cursor: pointer; }
.ideas::after { content: "\203A"; font-size: 15px; line-height: 1; transition: transform .2s; }
.ideas.open::after { transform: rotate(90deg); }
.tag { height: 28px; padding: 0 12px; border-radius: 14px; background: var(--card); border: 1px solid var(--line); color: var(--muted); font-size: 13px; font-weight: 500; display: inline-flex; align-items: center; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.card .tag { background: var(--bg); border-color: transparent; }
.tagline { display: flex; flex-wrap: wrap; gap: 8px; }
/* Collection name on a card → that person's shelf. Looks like the tag, reads as tappable (ink + ›), hit area padded to 44px */
.tag-link { position: relative; color: var(--ink); gap: 3px; cursor: pointer; overflow: visible; }
.tag-link > svg { width: 14px; height: 14px; flex-shrink: 0; color: var(--muted); }   /* 第35便: 棚の印。ジャンルのタグ (.tag だけ) には付かない */
.tag-link .tag-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.tag-link .chev { color: var(--muted); font-size: 14px; line-height: 1; }
.tag-link::after { content: ""; position: absolute; inset: -8px 0; }
.tag-link:active { background: var(--line); }
.tagpick { display: flex; flex-wrap: wrap; gap: 8px; }
.filter-row { display: flex; gap: 8px; overflow-x: auto; padding: 0 0 16px 0; -webkit-overflow-scrolling: touch; scrollbar-width: none; align-items: center; }
.filter-row::-webkit-scrollbar { display: none; }
.filter-row .chip { flex-shrink: 0; }
.filter-row .ibtn { flex-shrink: 0; margin-left: auto; }

/* Buttons */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; width: 100%; height: 48px; border: 0; border-radius: var(--r-btn); font-size: 15px; font-weight: 600; letter-spacing: 0.02em; cursor: pointer; padding: 0 16px; }
.btn svg { width: 22px; height: 22px; }
.btn-primary { background: var(--accent); color: var(--on-fill); }
.btn-primary:active { background: var(--accent-dark); }
.btn-primary:disabled { opacity: 0.5; cursor: default; }
.btn-ghost { background: var(--card); color: var(--ink); border: 1px solid var(--line); }
.btn-ghost:active { background: var(--bg); }
.btn-text { background: none; border: 0; color: var(--accent-text); font-weight: 600; font-size: 15px; cursor: pointer; padding: 12px 0; min-height: var(--tap); }
.btn-text.inline { padding: 0 4px; min-height: 0; font-size: 13px; }
/* under a translated note / comment: tap to see the original */
.tr-toggle { display: block; background: none; border: 0; padding: 6px 0; margin: 0; font: inherit; font-size: 13px; color: var(--muted); cursor: pointer; text-align: left; min-height: 28px; }
.btn-sm { height: var(--tap); font-size: 13px; padding: 0 14px; width: auto; }
.row { display: flex; gap: 12px; }
.row > * { flex: 1; }

/* Voice input */
.vbtn.listening { background: var(--accent); border-color: var(--accent); color: var(--on-fill); }
.vbtn.listening svg { animation: pulse 1s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.18); } }
.input.listening { outline: 2px solid var(--accent); outline-offset: -1px; }
/* mic inside any text field (2026-09-08). The field keeps its width; the button sits in the right edge, 44px */
.vwrap { position: relative; width: 100%; }
.vwrap > .input { padding-right: 46px; }
.vmic { position: absolute; right: 2px; top: 2px; width: 44px; height: 44px; border: 0; border-radius: 50%; background: none; color: var(--muted); display: flex; align-items: center; justify-content: center; padding: 0; cursor: pointer; }
.vmic svg { width: 22px; height: 22px; }
.vmic:active { background: var(--bg); }
.vmic.on { background: var(--accent); color: var(--on-fill); }
.vmic.on svg { animation: pulse 1s ease-in-out infinite; }
.tcomposer .vwrap > textarea.input { padding-right: 44px; }
.tcomposer .vmic { top: -2px; right: -4px; }
.voice-live { display: none; align-items: center; gap: 10px; min-height: 40px; padding: 6px 4px 0 4px; color: var(--accent-text); font-size: 15px; font-weight: 500; }
.voice-live.on { display: flex; }
.voice-live .lbl { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.voice-live .bars { display: inline-flex; align-items: flex-end; gap: 3px; height: 22px; flex-shrink: 0; }
.voice-live .bars i { display: block; width: 4px; height: 6px; border-radius: 2px; background: var(--accent); animation: eq .9s ease-in-out infinite; }
.voice-live .bars i:nth-child(2) { animation-delay: .15s; } .voice-live .bars i:nth-child(3) { animation-delay: .3s; }
.voice-live .bars i:nth-child(4) { animation-delay: .45s; } .voice-live .bars i:nth-child(5) { animation-delay: .6s; }
@keyframes eq { 0%, 100% { height: 6px; } 50% { height: 22px; } }

/* Tabs (picker sheet) */
.tabs { display: flex; gap: 0; border-bottom: 1px solid var(--line); margin-bottom: 16px; }
.tab-btn { flex: 1; height: var(--tap); background: none; border: 0; border-bottom: 2px solid transparent; font-size: 15px; font-weight: 500; color: var(--muted); cursor: pointer; }
.tab-btn.on { color: var(--ink); font-weight: 600; border-bottom-color: var(--accent); }

/* Songs | Albums switch inside the picker */
.seg { display: inline-flex; padding: 3px; border-radius: 999px; background: var(--line); margin-bottom: 12px; }
.seg-btn { height: 38px; min-width: 96px; padding: 0 18px; border: 0; border-radius: 999px; background: transparent; color: var(--muted); font-size: 14px; font-weight: 600; cursor: pointer; }
.seg-btn.on { background: var(--card); color: var(--ink); box-shadow: 0 1px 2px var(--shadow); }

/* Album results: covers in a 2-column grid, like flipping through a crate */
.album-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 12px; margin-top: 4px; }
.album-tile { display: flex; flex-direction: column; align-items: stretch; gap: 6px; padding: 0; border: 0; background: none; text-align: left; cursor: pointer; color: var(--ink); font-family: inherit; min-width: 0; }
.album-tile:active .album-art { transform: scale(0.97); }
.album-art { width: 100%; max-width: 100%; aspect-ratio: 1 / 1; border-radius: 10px; object-fit: cover; background: var(--card); border: 1px solid var(--line); display: block; transition: transform .12s ease; }
.album-art.ph { display: flex; align-items: center; justify-content: center; color: var(--muted); }
.album-art.ph svg { width: 32px; height: 32px; }
.album-art.sm { width: 96px; flex: 0 0 96px; }
.album-name { font-size: 15px; font-weight: 700; line-height: 1.3; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.album-sub { font-size: 13px; color: var(--muted); line-height: 1.4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.album-head { display: flex; align-items: center; gap: 10px; margin: 0 0 12px -8px; }
.album-head .card-body { gap: 3px; }

/* Card (one pick) */
.card { background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 16px; margin-bottom: 16px; }
.card.pick { display: flex; flex-direction: column; gap: 12px; }
.card.row-card { display: flex; align-items: center; gap: 12px; }
/* 第37便 (2026-09-15): 曲が届くまでのあいだ、カードの形だけを灰色で出す (Home 改善の H12)。
   Home は最初の曲が出るまでにサーバーと 4〜6 往復あり、その間ずっと画面が空だった。
   動きは付けない (チカチカしない・reduced-motion の配慮が要らない)。届いたら本物のカードに差し替わる。
   ⚠⚠ class 名は必ず `sk-` で始めること。`.row` は既にあり (`.row > * { flex: 1 }`)、ぶつかると描画が崩れる。
   ⚠ `.sk-disc` / `.sk-av` は `.sk-bar` と同じ強さなので、**必ず後ろに置く**(でないと丸くならない) */
.sk-card { background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 16px; margin-bottom: 16px; display: flex; flex-direction: column; gap: 12px; }
.sk-row { display: flex; align-items: center; gap: 12px; }
.sk-col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.sk-bar { display: block; background: var(--line); border-radius: 6px; opacity: 0.55; }
.sk-av { width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; }
.sk-disc { width: 88px; height: 88px; border-radius: 50%; flex-shrink: 0; }

/* 第36便 (2026-09-15): Home で同じ人が続けて置いた曲を 1 枚の白い塊にする (Home 改善の H06)。
   2曲目以降は選曲者の行そのものを出さない (index.html 側の showOwner: false)。曲と曲の境目は、
   下のカード自身の border-top がそのまま 1 本の線になる (上のカードの border-bottom を消してあるので二重にならない)。
   ⚠ 塊を切るのは index.html 側: 選曲者が変わった / 「Last visit」の線が入る / Talk / Now Playing / 運営が下げた曲 */
.card.pick.run-more { margin-bottom: 0; border-bottom: 0; border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.card.pick.run-cont { border-top-left-radius: 0; border-top-right-radius: 0; }
.owner-row { display: flex; align-items: center; gap: 10px; min-width: 0; }
.owner-row .who { min-width: 0; display: flex; flex-direction: column; }
.owner-row .who b { font-size: 15px; font-weight: 600; line-height: 1.4; }
.owner-row .who span { font-size: 13px; color: var(--muted); line-height: 1.45; }
.card-top { display: flex; align-items: center; gap: 12px; }
.card-body { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.track-title { font-size: 17px; font-weight: 700; line-height: 1.35; overflow-wrap: anywhere; }
.track-artist { font-size: 14px; font-weight: 500; color: var(--muted); line-height: 1.45; overflow-wrap: anywhere; }

/* 第53便 (2026-09-18): 大きな曲カードの曲名は 2 行、アーティスト名も 2 行で切る (本人の指示)。
   ⚠ なぜ 2 行 + 2 行か: 曲名 2 行 + アーティスト 2 行の文字の塊は **ちょうど 88px** で、
   左の盤 (88px) と同じ高さ。つまりカードの高さは盤が決めていて、アーティストを 1 行に詰めても
   カードは 1px も低くならない (実測済み)。短い曲名のカードも 1px も変わらない。
   ⚠ 効くのは 6 か所: Home / My Picks / 人のページ / Liked / 週の問い / 棚のタイルから開くカードのシート。
   同じ部品なので、画面によって形が変わらない。
   ⚠ 小さい曲カード (.card.mini = Talk の曲・コメントの曲・Inbox の曲) は別の部品で、ここでは切らない。
   (Home のチャートの行を第51便で別に切っていた #thisweek .ch-row は、第94便で Home に曲を並べなくなったので消した)
   ⚠ 切れた曲名は盤を押して開く「この曲」シートで全文が出る。
   足したら node tests/fn_home_top.mjs (【N】が実測する) */
.card.pick .track-title, .card.pick .track-artist {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.track-comment { font-size: 15px; line-height: 1.55; color: var(--ink); overflow-wrap: anywhere; }   /* the whole note (≤120 chars), no 2-line cut (2026-09-10) */

/* Weekly question */
.card-kicker { display: flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-text); margin: -4px 0 8px 0; }
.card-kicker svg { width: 14px; height: 14px; }
.q-line { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); min-height: 28px; }
.q-line svg { width: 16px; height: 16px; flex-shrink: 0; }
.q-line span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* "via aki": whose Pick this song was taken from. Tap → their page */
.avatar.a20 { width: 20px; height: 20px; font-size: 10px; }
.via-line { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); min-height: 28px; text-decoration: none; max-width: 100%; }
.via-line b { color: var(--ink); font-weight: 600; }
.via-line span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 0027: ♥ を押した人 (カードの操作の行の下に1行)。
   ♥ が0のときは中身が空文字なので、:empty で行ごと消して高さを持たせない */
/* 第39便 (2026-09-15。本人の指摘「♥ と Liked by の距離がありすぎてバランスが悪い」): 行ごと 14px 上に寄せた。
   余白が 4 つ重なっていた: ♥ のボタンの下 11px + カードの行間 12px + この 2px + 文字ボタンの上 6px = 31px。
   → 線から ♥ の上が 20px なので、♥ の下も **18px** にして上下を対称にした(前は 34px = 1.7 倍)。
   ⚠ **文字ボタン自身の余白(.likers の padding: 6px 0)は触っていない** — 押せる高さ 30px をそのまま保つため。
   ⚠ 「Liked by」の下からカードの底までは 17px のまま変わらない(下だけ詰まって見えない)。
   ⚠ ♥ が 0 のカードは下の :empty で行ごと消えるので、この余白は効かない */
.likers-row { margin-top: -14px; }
.likers-row:empty { display: none; }
.likers { display: block; max-width: 100%; background: none; border: 0; padding: 6px 0; margin: 0;
  font-size: 13px; color: var(--muted); text-align: left; cursor: pointer; line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.likers b { color: var(--ink); font-weight: 600; }
.q-box { background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 20px 16px 16px; margin-top: 8px; }
.q-when { font-size: 13px; color: var(--accent-text); font-weight: 600; letter-spacing: 0.02em; display: flex; align-items: center; gap: 6px; }
.q-when svg { width: 16px; height: 16px; }
.q-text { font-size: 22px; font-weight: 700; line-height: 1.3; margin: 6px 0 4px; overflow-wrap: anywhere; }
.q-sub { font-size: 13px; color: var(--muted); }
.q-box .btn { margin-top: 16px; }
.q-box.compact { padding: 16px; margin: 0 0 8px 0; }
.q-box.compact .q-text { font-size: 17px; margin: 4px 0; }
.q-box.compact .btn { margin-top: 12px; }
.q-mine .card { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.q-mine-label { display: flex; align-items: center; gap: 4px; font-size: 13px; color: var(--accent-text); font-weight: 600; margin: 16px 0 4px 0; }
.q-mine-label span { flex: 1; }
.past { display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 8px 0; border-bottom: 1px solid var(--line); color: var(--ink); }
.past .d { font-size: 13px; color: var(--muted); width: 104px; flex-shrink: 0; white-space: nowrap; }
.past .t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; font-size: 15px; }
.past .c { font-size: 13px; color: var(--muted); white-space: nowrap; }
.past svg { width: 22px; height: 22px; flex-shrink: 0; color: var(--muted); }
.switch-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: var(--tap); padding: 4px 0; }
.switch-row .lbl { font-size: 15px; font-weight: 600; }
.switch-row .hint { font-size: 13px; color: var(--muted); display: block; font-weight: 400; }
.switch { position: relative; width: 50px; height: 30px; border-radius: 15px; background: var(--line); border: 0; padding: 0; cursor: pointer; flex-shrink: 0; transition: background .18s ease; }
.switch::after { content: ''; position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: 50%; background: var(--on-fill); box-shadow: 0 1px 3px var(--shadow-knob); transition: transform .18s ease; }
.switch[aria-checked="true"] { background: var(--accent); }
.switch[aria-checked="true"]::after { transform: translateX(20px); }
.avatar.q-av { background: var(--accent); }
.avatar.q-av svg { width: 18px; height: 18px; color: var(--on-fill); }
.q-box.compact .q-when { color: var(--accent-text); }
.comment-editing { display: flex; align-items: center; justify-content: space-between; font-size: 13px; color: var(--accent-text); font-weight: 600; margin-bottom: 8px; }
.admin-row { display: flex; align-items: flex-start; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.admin-row .d { font-size: 13px; color: var(--muted); width: 84px; flex-shrink: 0; padding-top: 2px; }
.admin-row .t { flex: 1; min-width: 0; font-size: 15px; line-height: 1.45; overflow-wrap: anywhere; }
.admin-row .t .note { display: block; }
.card.mini { padding: 12px; margin: 8px 0; display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; border-radius: 12px; }
.card.mini .track-title { font-size: 15px; }
/* 2段目の ⊕ / ↗ (2026-09-12)。1段に5つ並べると 390px の画面で曲名に 70px しか残らず、
   1行3文字で縦に伸びていた。曲カード・Inbox と同じ「文字つきボタン」にそろえてある */
.card.mini .m-acts { flex: 1 0 100%; display: flex; align-items: center; gap: 4px; margin: 0 -6px; }
.card.mini .m-acts .act { height: 38px; min-width: 38px; }
.card.mini .m-acts .act svg { width: 20px; height: 20px; }

/* Record disc for a track (artwork clipped into the center label) */
.rec { position: relative; flex-shrink: 0; }
.rec svg { width: 100%; height: 100%; }
.rec.r88 { width: 88px; height: 88px; }
.rec.r56 { width: 56px; height: 56px; }
.rec.r44 { width: 44px; height: 44px; }
.rec .spinner { transform-origin: 50% 50%; }
.rec.spin .spinner { animation: spin 4.5s linear infinite; }
.rec.spin.paused .spinner { animation-play-state: paused; }
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* Play button with a 30-second progress ring */
.play { position: relative; width: 48px; height: 48px; border-radius: 50%; background: var(--fill-ink); border: 0; flex-shrink: 0; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--on-ink); padding: 0; }
.play:active { background: var(--accent-dark); }
.play .ico { width: 22px; height: 22px; }
.play .ico-pause { display: none; }
.play.playing .ico-play { display: none; }
.play.playing .ico-pause { display: block; }
.play .ring { position: absolute; inset: -3px; width: calc(100% + 6px); height: calc(100% + 6px); transform: rotate(-90deg); pointer-events: none; }
.play .ring circle { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-dasharray: 100 100; stroke-dashoffset: 100; opacity: 0; }
.play.playing .ring circle { opacity: 1; }

/* Collections: shelves of tiles */
.shelf { margin-bottom: 24px; }
.shelf-head { display: flex; align-items: center; gap: 8px; width: 100%; min-height: var(--tap); padding: 0; background: none; border: 0; cursor: pointer; text-align: left; margin-bottom: 4px; }
.shelf-name { font-size: 18px; font-weight: 700; line-height: 1.4; }
.shelf-count { font-size: 13px; color: var(--muted); flex: 1; }
.shelf-head svg { width: 22px; height: 22px; color: var(--muted); }
.shelf-head:not(button) { cursor: default; }   /* 第106便: 他の人から見た非公開の棚の題名 (押せない div) */
.shelf-top { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }   /* 第128便: 見出し + 「公開する」の横並び */
.shelf-top .shelf-head { flex: 1 1 0; min-width: 0; margin-bottom: 0; }
.shelf-top .shelf-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }   /* 長い名前は「…」(ボタンは縮めない) */
.shelf-top .shelf-head > svg { flex: none; }   /* 名前が長くても鍵と矢印の絵は縮めない */
/* 第129便A: あなたのためのプレイリスト (Beta)。Beta は .flabel、× は Home の人のカードの .fx を使い回す
   第129便B: 1 枚 = 白いカード (.card) にジャケット 4 枚を横 1 列 + 題名。2 枚以上 (.dr-many) は Step outside (#outside-list) と同じ横にめくる形 (次のカードの端が 62px のぞく)・1 枚は幅いっぱい */
.dr-row { display: flex; gap: 12px; overflow-x: auto; overflow-y: hidden; margin: 0 -16px 8px; padding: 0 16px; scroll-snap-type: x mandatory; scroll-padding-left: 16px; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.dr-row::-webkit-scrollbar { display: none; }
.dr-card { position: relative; flex: 0 0 100%; min-width: 0; margin: 0; padding: 12px; scroll-snap-align: start; }
.dr-many > .dr-card { flex-basis: calc(100% - 58px); }
.dr-open { display: block; width: 100%; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.dr-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; border-radius: 10px; overflow: hidden; }
.dr-strip img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; background: var(--line); }
.dr-title { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; margin-top: 8px; font-size: 14px; font-weight: 600; line-height: 1.4; }
.dr-card .fx { position: absolute; top: 6px; right: 6px; width: 28px; height: 28px; border: 0; border-radius: 50%; background: var(--card); color: var(--muted); display: flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; box-shadow: 0 1px 3px var(--shadow-mini); }
.dr-card .fx svg { width: 16px; height: 16px; }
.dr-card .fx::after { content: ""; position: absolute; inset: -8px; }   /* 見た目 28px・押せる範囲 44px */
/* 第131便B: 起点の 1 行 (題名の下。Home の段・曲の一覧のシート。1 行で「…」) */
.dr-from { display: block; margin-top: 2px; font-size: 13px; font-weight: 400; line-height: 1.4; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 第129便B: 下書きの曲の一覧のシートだけ、盤の代わりにジャケット (盤と同じ 44px・角丸 10px = 小さい札) */
.card.mini .mjk { display: block; width: 44px; height: 44px; border-radius: 10px; object-fit: cover; background: var(--line); }
/* 第132便B: 下書きのシートの曲の行の理由の 1 行 (つながり型・high だけ・英語) */
.card.mini .track-why { font-size: 13px; line-height: 18px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.shelf-wrap { position: relative; margin: 0 -16px; }
.shelf-wrap::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; width: 56px; background: linear-gradient(to right, var(--bg-clear), var(--bg) 85%); pointer-events: none; transition: opacity .2s; }
.shelf-wrap.at-end::after { opacity: 0; }
.shelf-scroller { display: flex; gap: 12px; overflow-x: auto; padding: 4px 16px 4px 16px; scroll-snap-type: x mandatory; scroll-padding-left: 16px; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.shelf-scroller::-webkit-scrollbar { display: none; }
/* 第107便: Home の公式のまとまり (.card.ofc-shelf) の中の棚だけ。カードの下に空きを残さない / 右端のぼかしをカードの色へ (暗い画面は --card が暗くなる) */
.ofc-shelf .shelf { margin-bottom: 0; }
.ofc-shelf .shelf-wrap::after { background: linear-gradient(to right, transparent, var(--card) 85%); }
.tile { flex: 0 0 92px; width: 92px; scroll-snap-align: start; display: flex; flex-direction: column; gap: 6px; }
.tile-art { position: relative; width: 88px; height: 88px; }
.tile-art .rec { width: 88px; height: 88px; }
.play.mini { position: absolute; right: -4px; bottom: -4px; width: 36px; height: 36px; box-shadow: 0 2px 8px var(--shadow-mini); }
.play.mini .ico { width: 18px; height: 18px; }
.play.mini .ring { inset: -3px; }
.play.mini.alt { background: var(--card); color: var(--ink); border: 1px solid var(--line); box-shadow: none; }
.play.mini.alt .ico { width: 18px; height: 18px; }
.tile-text { display: flex; flex-direction: column; gap: 1px; background: none; border: 0; padding: 0; text-align: left; cursor: pointer; min-height: 40px; }
.tile-title { font-size: 13px; font-weight: 600; line-height: 1.35; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.tile-artist { font-size: 13px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tile.tile-add { width: 88px; height: 88px; flex-basis: 88px; border: 1px dashed var(--line); border-radius: 50%; background: var(--card); display: flex; align-items: center; justify-content: center; color: var(--muted); cursor: pointer; }
.tile.tile-add svg { width: 26px; height: 26px; }
.tile.tile-empty { width: 88px; height: 88px; flex-basis: 88px; border: 1px dashed var(--line); border-radius: 50%; }
/* rearranging by hand: the lifted record follows the finger; the tile left behind is the slot */
.tile { -webkit-touch-callout: none; }
.tile.drag-src { opacity: .35; }
.drag-ghost { position: fixed; left: 0; top: 0; z-index: 70; pointer-events: none; transform-origin: 0 0; filter: drop-shadow(0 10px 18px var(--shadow-drag)); will-change: transform; }
.drag-ghost .rec { width: 100%; height: 100%; transform: scale(1.1); }
.shelf.drop-target .shelf-name { color: var(--accent-text); }
.shelf.drop-target .shelf-scroller { background: var(--accent-a06); border-radius: 12px; }
.shelf-scroller.dragging { scroll-snap-type: none; }
body.dragging-tile { user-select: none; -webkit-user-select: none; cursor: grabbing; }
body.dragging-tile .shelf-scroller { scroll-snap-type: none; }
.col-row .lock { width: var(--tap); height: var(--tap); display: inline-flex; align-items: center; justify-content: center; color: var(--muted); }
.col-row .lock svg { width: 22px; height: 22px; }
.all-row { display: flex; align-items: center; gap: 8px; width: 100%; height: 56px; padding: 0 16px; border: 1px solid var(--line); border-radius: 12px; background: var(--card); font-size: 15px; font-weight: 600; cursor: pointer; margin: 8px 0 24px 0; }
.all-row .shelf-count { flex: 1; }
.all-row > svg:first-child { color: var(--ink); }
.all-row + .all-row { margin-top: -16px; }
.sheet-sep { border-top: 1px solid var(--line); margin: 4px 0 16px 0; }
/* The record on a card is a button: tap it to read the sleeve */
.rec-btn { background: none; border: 0; padding: 0; margin: 0; cursor: pointer; flex-shrink: 0; border-radius: 50%; -webkit-tap-highlight-color: transparent; }
.rec-btn .rec { transition: transform .12s ease; }
.rec-btn:active .rec { transform: scale(0.94); }
.song-head { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 12px; padding: 8px 0 20px 0; }
.song-head .rec { width: 128px; height: 128px; }
.song-head .track-title { font-size: 20px; }
.song-head .track-artist { font-size: 15px; }
.song-meta { font-size: 13px; color: var(--muted); line-height: 1.5; margin-top: 4px; overflow-wrap: anywhere; }
.song-meta:empty { display: none; }
.all-row.in-sheet { margin: 0 0 16px 0; }
.all-row.in-sheet > svg:last-child { color: var(--muted); }
#inbox-row { margin: 0 0 16px 0; }
.send-row { padding: 12px 0; border-bottom: 1px solid var(--line); }
.send-row .head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.send-row .head b { font-size: 15px; font-weight: 600; }
.send-row .head .when { margin-left: auto; font-size: 13px; color: var(--muted); }
.send-row .note-txt { font-size: 15px; line-height: 1.5; margin: 4px 0 8px 0; }
.send-row .acts { display: flex; gap: 4px; align-items: center; }
.send-row.unread .head b::after { content: ''; display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); margin-left: 8px; vertical-align: middle; }
.all-row svg { width: 22px; height: 22px; color: var(--muted); }

/* Collection view header */
.subhead { display: flex; align-items: center; gap: 4px; margin: 8px 0 12px -8px; }
.subhead .title { font-size: 22px; font-weight: 700; line-height: 1.3; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.subhead .count { font-size: 13px; color: var(--muted); margin-right: 4px; }
.subhead .title { display: flex; align-items: center; gap: 6px; }
.col-owner { display: inline-flex; align-items: center; gap: 6px; font-size: 16px; font-weight: 600; color: var(--muted); text-decoration: none; flex-shrink: 0; min-height: 44px; }
.avatar.a24 { width: 24px; height: 24px; font-size: 11px; }
.col-sep { color: var(--muted); font-weight: 400; flex-shrink: 0; }
.col-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Reorder list */
.reorder-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.reorder-row .ibtn:disabled { opacity: 0.3; }

/* Manage collections sheet */
.col-row { display: flex; align-items: center; gap: 6px; padding: 6px 0; border-bottom: 1px solid var(--line); }
.col-row .name { flex: 1; min-width: 0; font-size: 15px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.col-row .name small { display: block; font-size: 13px; color: var(--muted); font-weight: 400; }
.col-row .input { height: var(--tap); }

/* 第80便 (2026-09-29): プレイリストの紹介文 (tags.note)。プレイリスト名のすぐ下 (My Picks・人のページ・/c/)
   改行はそのまま (pre-wrap)・3 行で切って「続き」(たたむボタンは無い)。URL はリンクにしない (JS が D.esc だけで入れる)
   ⚠ 「続き」は押せる高さ 44px を箱そのもので取る (下に翻訳ボタンが来るので、当たり判定を外へ広げると重なる)
   第81便: 「+ 紹介文」(.pl-add) は無くした。書くのは My Picks の鉛筆 (プレイリストを編集 = .pl-edit)
   ⚠ 色は :root の名前だけ。class は pl- / col-edit / col-note で始める */
#col-note { margin: -4px 0 12px; }
.pl-note-wrap { align-self: stretch; min-width: 0; }
.pl-note { font-size: 15px; line-height: 1.5; color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere; }
.pl-note.clamp { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; }
.pl-more { display: flex; align-items: center; min-height: 44px; padding: 0; margin: 0; background: none; border: 0; font: inherit; font-size: 13px; font-weight: 600; color: var(--accent-text); cursor: pointer; text-align: left; }
.pl-more:active { color: var(--ink); }
/* 第81便 (2026-09-29): プレイリストを編集 (My Picks の鉛筆)。名前 → 紹介文 → 曲順 (曲順の見出しも .pl-edit-label)。Done は題名の行の右 */
.pl-edit { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.pl-edit-label { font-size: 13px; color: var(--muted); }
.pl-edit textarea.input { height: auto; min-height: var(--tap); resize: none; line-height: 1.5; }
.subhead #col-reorder-done { flex: 0 0 auto; }
/* 第101便: 編集中の題名「プレイリストを編集」が 320px の日本語で「完了」にくっついていた (題名の箱が flex なので「…」が効かなかった)。
   題名は内側の .col-name に入れて「…」で切る + 360px 以下の幅だけ 20px (9 字 × 20 = 180px が収まる)。「完了」は縮まないので必ず全部見える */
@media (max-width: 360px) { .subhead.editing .title { font-size: 20px; } }
/* 第101便: プレイリストの Share の右の「⋯」(報告)。ピル 36px の行に 44px のボタンを置くので上下を -4px (行の高さは変えない) */
.c-more-wrap { margin: -4px 0; }
.c-more-wrap .c-more { color: var(--muted); }
.menu.start { right: auto; left: 0; }
/* 第101便: Edit profile で運営が外したリンクは書き換えられない (readonly)。文字を灰色に */
.plink-edit.held .input { color: var(--muted); }
.c-meta .c-actrow { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* 第99便 (2026-10-02): プレイリストの「いつ・どこで」(1 行) とリンク 1 本 (白いカード)。My Picks・人のページ・/c/ で同じ
   並び: プレイリスト名 → .pl-when → 紹介文 → .pl-link → Share
   ⚠ .pl-when は 2 行まで・3 行目からは「…」(本人の決定 3)。文字もピンも --muted。会場と街は書いた文字のまま (翻訳しない)
   ⚠ .pl-link は箱そのもので 56px (押せる高さ 44px 以上)。丸は黒く塗る部品なので --fill-ink + --on-ink (暗い画面では暗い灰色。第55便)
   ⚠ /c/ は PHP が同じ class の HTML を書く (public/c/index.php) */
#col-when { margin: -4px 0 10px; }
#col-link { margin: 0 0 12px; }
.c-meta .pl-when, .c-meta .pl-link { align-self: stretch; }
.pl-when { display: flex; align-items: flex-start; gap: 6px; min-width: 0; font-size: 14px; line-height: 1.5; color: var(--muted); }
.pl-when svg { width: 16px; height: 16px; flex-shrink: 0; margin-top: 2px; }
.pl-when-t { min-width: 0; overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
.pl-link { display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 0 16px 0 12px; background: var(--card); border: 1px solid var(--line); border-radius: 12px; color: var(--ink); font-size: 15px; font-weight: 600; text-decoration: none; min-width: 0; }
.pl-link:active { background: var(--bg); }
.pl-link-ic { flex: 0 0 auto; width: 32px; height: 32px; border-radius: 50%; background: var(--fill-ink); color: var(--on-ink); display: flex; align-items: center; justify-content: center; }
.pl-link-ic svg { width: 18px; height: 18px; }
.pl-link-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 編集画面: リンクの欄の下のサービス名 (よく知られたサービスの時だけ。名前の欄の代わり) */
.pl-edit-svc { font-size: 13px; font-weight: 600; color: var(--muted); }
/* 第100便 (2026-10-02): 編集画面の「イベント情報」。何も書いていなければ「＋ イベント情報を追加」と ？ の 1 行だけ (押すと開く)
   ⚠ 行の高さ 44px (＋の行も ？ も押せる高さ 44px)。開くと同じ行が見出し「イベント情報」(.pl-edit-label) に変わる
   ⚠ 日付は「日付を選ぶ」の箱 (.pl-date)。上に本物の <input type="date"> (.pl-date-in) を透明にして全面に重ねている =
     押すと端末のカレンダーが開く。端末の素の「年/月/日」は見えない。⚠ .pl-date-in の opacity: 0 を消さないこと */
.pl-ev { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; }
.pl-ev-head { display: flex; align-items: center; gap: 8px; min-height: var(--tap); }
.pl-ev-open { display: inline-flex; align-items: center; gap: 6px; padding: 0; text-align: left; }
.pl-ev-open svg { width: 18px; height: 18px; flex-shrink: 0; }
.pl-ev-title { flex: 1; min-width: 0; outline: none; }
.pl-ev-help { margin-left: auto; flex-shrink: 0; color: var(--muted); }
.pl-ev-help[aria-expanded="true"] { color: var(--ink); }
.pl-ev-help-t { margin: -4px 0 4px; font-size: 13px; line-height: 1.6; color: var(--muted); }
.pl-ev-body { display: flex; flex-direction: column; gap: 6px; }
.pl-edit-date { display: flex; align-items: center; gap: 4px; }
.pl-date { position: relative; flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; height: 48px; padding: 0 14px; border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--card); color: var(--ink); font-size: 16px; font-weight: 600; cursor: pointer; }
.pl-date.pl-date-none { color: var(--accent-text); }   /* ⚠ class 名を .empty にしないこと (空の状態の部品 .empty とぶつかって箱が崩れた) */
.pl-date svg { width: 20px; height: 20px; flex-shrink: 0; }
.pl-date-t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-date:focus-within { outline: 2px solid var(--accent); outline-offset: -1px; }
.pl-date:active { background: var(--bg); }
.pl-date-in { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; opacity: 0; cursor: pointer; font-size: 16px; -webkit-appearance: none; appearance: none; background: transparent; color: transparent; }
.pl-date-in::-webkit-calendar-picker-indicator { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; cursor: pointer; }

/* Actions row */
.actions { display: flex; align-items: center; gap: 4px; border-top: 1px solid var(--line); padding-top: 8px; margin-top: 4px; }
.act { position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 4px; min-width: var(--tap); height: var(--tap); padding: 0 6px; background: none; border: 0; border-radius: 22px; font-size: 13px; font-weight: 500; color: var(--ink); cursor: pointer; }
.act svg { width: 22px; height: 22px; }
.act .n { font-size: 13px; color: var(--muted); min-width: 0; }
.act.on { color: var(--accent-text); }
.act.on .n { color: var(--accent-text); }
.act.full { padding: 0 14px 0 10px; border: 1px solid var(--line); background: var(--card); font-weight: 600; }
.act.full:active { background: var(--bg); }
.act:disabled { opacity: 0.5; }
.act.like.pop svg { animation: pop .22s ease-out; }
@keyframes pop { 0% { transform: scale(1); } 45% { transform: scale(1.22); } 80% { transform: scale(0.95); } 100% { transform: scale(1); } }
.act.cmt:active svg { transform: translateY(-2px); transition: transform .16s; }
.act.full:active svg { transform: translate(2px, -2px); transition: transform .18s; }
.act.add.done svg { animation: morph .3s ease-out; color: var(--accent-text); }
.card.mini .cadd.on { color: var(--accent-text); }                     /* ⊕ on a Song Reply, once the song is in my Picks */
.card.mini .cadd.done svg { animation: morph .3s ease-out; }
@keyframes morph { 0% { transform: rotate(-90deg) scale(0.8); opacity: .4; } 100% { transform: none; opacity: 1; } }
/* 第31便 (2026-09-15): 再生数 (.plays) は操作行から外した (Full Track を 2 行に折っていた)。⋯ を右端に置くのは .menu-wrap の役目に */
.actions .menu-wrap { margin-left: auto; }

/* "…" menu */
.menu-wrap { position: relative; }
.menu { position: absolute; right: 0; bottom: calc(100% + 4px); background: var(--card); border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 8px 24px var(--shadow); min-width: 160px; z-index: 5; overflow: hidden; }
.menu.down { top: calc(100% + 4px); bottom: auto; }
.menu button { display: flex; align-items: center; gap: 10px; width: 100%; height: 48px; padding: 0 16px; background: none; border: 0; font-size: 15px; font-weight: 500; cursor: pointer; text-align: left; }
.menu button:active { background: var(--bg); }
.menu button svg { width: 22px; height: 22px; }

/* Forms */
.field { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.field label { font-size: 15px; font-weight: 600; }
.field .hint { font-size: 13px; color: var(--muted); }
/* Captcha の置き場所 (第43便)。⚠ min-height は **枠が出る前に高さを空けておく**ため。
   空けないと、Turnstile が描かれた瞬間に下のボタンが 65px 下へ飛び、押そうとした指が外れる。
   ⚠ 枠そのものの見た目は Cloudflare 側が描く (こちらからは幅と余白しか触れない) */
.captcha { margin: 0 0 16px 0; min-height: 65px; }
.input { width: 100%; height: 48px; padding: 0 14px; border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--card); font-size: 16px; line-height: 1.5; font-family: inherit; color: var(--ink); }
.input::placeholder { color: var(--placeholder); }
.input:focus { outline: 2px solid var(--ink); outline-offset: -1px; }
textarea.input { height: auto; padding: 12px 14px; }
select.input { -webkit-appearance: none; appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%), linear-gradient(135deg, var(--ink) 50%, transparent 50%); background-position: calc(100% - 20px) 21px, calc(100% - 15px) 21px; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }

/* Messages */
.msg { font-size: 15px; padding: 12px 16px; border-radius: 12px; margin: 12px 0; }
.msg-error { background: var(--err-bg); color: var(--err-text); }   /* 第75便: 暗い画面 5.05:1 (前は 2.02:1) */
.msg-ok { background: var(--ok-bg); color: var(--ok-ink); }

/* Invite codes */
.invite { display: flex; align-items: center; justify-content: space-between; gap: 12px; background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 8px 8px 8px 16px; margin-bottom: 8px; min-height: 60px; }
.invite code { font-size: 17px; font-weight: 700; letter-spacing: 0.12em; font-family: inherit; }
.invite.used { opacity: 0.5; }

/* People list */
/* One row = avatar · name · attributes (wrapping, never clipped) · up to two of their own Collection names.
   The Collection names are the tell: "how does this person sort music?" (2026-09-08; replaced the three small records) */
.person { display: flex; align-items: flex-start; gap: 12px; padding: 14px 0; border-bottom: 1px solid var(--line); color: var(--ink); }
.person .p-av { flex-shrink: 0; display: block; }
.person .p-body { flex: 1; min-width: 0; }
.person .p-follow { flex-shrink: 0; align-self: center; margin-left: 4px; }
.person .p-main { display: block; color: var(--ink); }
.person-name { font-size: 15px; font-weight: 600; line-height: 1.4; }
.person-attrs { font-size: 13px; color: var(--muted); line-height: 1.45; overflow-wrap: anywhere; }
.person-cols { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
.person-cols a { position: relative; display: inline-flex; align-items: center; gap: 3px; height: 28px; padding: 0 10px; border-radius: 14px; background: var(--card); border: 1px solid var(--line); color: var(--ink); font-size: 13px; font-weight: 500; max-width: 100%; }
.person-cols a span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.person-cols a .chev { color: var(--muted); font-size: 14px; line-height: 1; }
.person-cols a::after { content: ""; position: absolute; inset: -8px 0; }      /* 44px hit area on a 28px chip */
.person-cols a:active { background: var(--line); }
.flabel { display: inline-block; margin-left: 8px; font-size: 11px; font-weight: 600; color: var(--muted); border: 1px solid var(--line); border-radius: 9px; padding: 1px 7px; vertical-align: 2px; letter-spacing: 0.02em; }
.newdot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); margin-right: 7px; vertical-align: 2px; }

/* Talk (2026-09-08): words that point at a song / shelf / person / question */
.tpost { display: flex; flex-direction: column; gap: 10px; }
.thead { display: flex; align-items: center; gap: 8px; min-width: 0; }
.towner { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1; color: var(--ink); }
.towner .who { min-width: 0; display: flex; flex-direction: column; }
.towner .who b { font-size: 15px; font-weight: 600; line-height: 1.3; }
.towner .who span { font-size: 13px; color: var(--muted); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task { font-size: 11px; font-weight: 700; letter-spacing: 0.04em; color: var(--accent-text); border: 1px solid var(--accent); border-radius: 10px; padding: 1px 7px; line-height: 1.4; flex-shrink: 0; }
.twhen { font-size: 13px; color: var(--muted); white-space: nowrap; flex-shrink: 0; }
.thead .menu-wrap { margin: -10px -10px -10px 0; }
.thead .menu { bottom: auto; top: calc(100% + 4px); }
.tbody { font-size: 15px; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; }
.tchips { display: flex; flex-wrap: wrap; gap: 6px; }
.tchip { display: inline-flex; align-items: center; gap: 5px; height: 30px; padding: 0 10px 0 6px; border-radius: 15px; background: var(--bg); border: 1px solid var(--line); color: var(--ink); font-size: 13px; font-weight: 500; max-width: 100%; position: relative; }
.tchip svg { width: 16px; height: 16px; color: var(--muted); flex-shrink: 0; margin-left: 2px; }
.tchip .avatar { flex-shrink: 0; }
.tchip-owner { color: var(--muted); }
.tchip-sep { color: var(--muted); }
.tchip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tchip::after { content: ""; position: absolute; inset: -7px 0; }          /* 44px hit area */
.tchip:active { background: var(--line); }
.tchip.gone { color: var(--muted); border-style: dashed; }
.tchip.pend { background: var(--card); padding-right: 2px; }
.tchip.pend::after { content: none; }
.tchip-x { width: 28px; height: 28px; border: 0; background: none; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; color: var(--muted); padding: 0; cursor: pointer; }
.tchip-x svg { width: 14px; height: 14px; margin: 0; }
.card.mini.tref { margin: 0; }
.tfoot { display: flex; align-items: center; gap: 8px; border-top: 1px solid var(--line); padding-top: 4px; margin-top: 2px; }
.tbtn-like { display: inline-flex; align-items: center; gap: 5px; min-height: var(--tap); padding: 0 6px; margin-left: -6px; border: 0; background: none; color: var(--muted); font-size: 13px; font-weight: 600; cursor: pointer; }
.tbtn-like svg { width: 20px; height: 20px; }
.tbtn-like.on { color: var(--accent-text); }
.tbtn-like.pop svg { animation: pop .3s ease-out; }
/* 2026-09-13 (0028): ♥ は名前の行から本文の下の「操作の行」へ。投稿は ♥ だけ、返信は ♥ と Reply。
   この行は**曲カードより上**に置く(曲カードは中に [Add | Full Track] を持っているので、
   その真下に置くと操作の行が2段重なり、下の行も曲への操作に見える) */
.tacts { display: flex; align-items: center; gap: 4px; margin-inline: -6px; }
.tacts .tbtn-like { min-height: 38px; margin: 0; }
/* 第64便 (本人の決定): Reply と Share は**コレクションの Share (.c-share) と同じピル**。♥ は今のまま (枠なし) */
.tbtn-reply, .tbtn-share { display: inline-flex; align-items: center; gap: 6px; height: 36px; padding: 0 14px; border: 1px solid var(--line); border-radius: 18px; background: var(--card); color: var(--ink); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; }
.tbtn-reply svg, .tbtn-share svg { width: 18px; height: 18px; }
.tbtn-reply:active, .tbtn-share:active { background: var(--bg); }
.tacts .tbtn-reply, .tacts .tbtn-share { margin-left: 4px; }   /* ピル同士の間は 8px (tacts の gap 4 + 4) */
/* 返信先の1行。文字は毎回**親の行から読む**(コピーして持たない = 隠した/伏せた言葉が生き残らない) */
/* 2026-09-13 (第9便): 1行で打ち切るのをやめた。名前が1行目、親の言葉が2行目から(2行まで)。
   元は white-space: nowrap で、名前の右に残る幅しか使えず実質30字ほどで「…」になっていた。
   意味を取るには画面の上の親まで戻るしかない = この行が仕事をしていなかった。
   入力欄の上の .treply-ctx (「Replying to ◯◯」) は元から2行出していたので、**そちらに揃えた形**。
   本文の無い返信の引用は .tq-song (曲名 — アーティスト。1行で省略) */
.tquote { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; width: 100%; min-width: 0; padding: 0; border: 0; background: none; color: var(--muted); font: inherit; font-size: 13px; line-height: 1.5; text-align: left; cursor: pointer; }
.tquote svg { width: 14px; height: 14px; flex-shrink: 0; }
.tquote b { font-weight: 600; }
.tquote .tq-head { display: flex; align-items: center; gap: 5px; max-width: 100%; min-width: 0; min-height: 20px; }
.tquote .tq-head > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 19px = アイコン14 + gap5。親の言葉を名前の頭にそろえる */
.tquote .tq-body { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; width: 100%; padding-left: 19px; overflow-wrap: anywhere; }
.tquote .tq-song { display: flex; align-items: center; gap: 4px; width: 100%; min-width: 0; padding-left: 19px; }
.tquote .tq-song span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tquote.gone { cursor: default; }
.treply.flash { animation: flash 1.2s ease-out; }
/* 入力欄の上の「Replying to ◯◯」。× を押すと投稿への返信に戻る */
.treply-ctx { display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--bg); }
.treply-ctx > svg { width: 16px; height: 16px; color: var(--muted); flex-shrink: 0; margin-top: 3px; }
.treply-ctx .ctx { flex: 1; min-width: 0; font-size: 13px; color: var(--muted); line-height: 1.5; }
.treply-ctx .ctx b { color: var(--ink); font-weight: 600; }
.treply-ctx .ctx q { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; quotes: none; }
.treply-ctx .ctx-x { width: 28px; height: 28px; flex-shrink: 0; border: 0; background: none; border-radius: 50%; color: var(--muted); display: inline-flex; align-items: center; justify-content: center; padding: 0; margin: -2px -4px 0 0; cursor: pointer; }
.treply-ctx .ctx-x svg { width: 14px; height: 14px; }
.tfoot .tbtn-replies { margin-left: -6px; }
.tbtn-replies { display: inline-flex; align-items: center; gap: 6px; min-height: var(--tap); padding: 0 6px; margin-left: -6px; border: 0; background: none; color: var(--muted); font-size: 13px; font-weight: 600; cursor: pointer; }
.tbtn-replies svg { width: 20px; height: 20px; }
.tcomposer { background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 12px; margin-bottom: 16px; display: flex; flex-direction: column; gap: 8px; }
.tcomposer textarea.input { resize: none; border: 0; padding: 4px 2px; min-height: 52px; background: transparent; }
.tcomposer textarea.input:focus { outline: none; box-shadow: none; }
.tpending:empty { display: none; }
/* 第24便 (2026-09-15): 文字を書く欄の「n/上限」と、打った分だけ伸びる高さ (ui.js の D.charCount / D.autoGrow)。
   Talk では Song と Post の間 (.tattach の中)、他の欄では欄の右下に1行 (.fcount)。上限ぴったりで赤 */
.tcount { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.tcount.over { color: var(--accent-text); font-weight: 600; }
.tattach .tcount { margin-left: auto; padding-right: 2px; }
.tattach .tcount + .tsubmit { margin-left: 10px; }
.fcount { display: flex; justify-content: flex-end; margin-top: -2px; }
textarea.input[data-grow] { overflow: hidden; resize: none; }
.mention { color: var(--accent-text); font-weight: 600; }
/* 本文の中の URL (2026-09-15。第22便 → 第23便で色を変えた)。
   出るのは Talk の投稿・返信 / コメント / Pick の一言 /「Picked by」の一言 / Send a song の一言。

   第22便では「色は本文のまま、下線だけ」にしたが、**下線の色に --line(区切り線の薄いグレー)を
   使ったため、本文と見分けが付かなかった**(本人の指摘)。第23便で **accent + 同色の下線** に変更。
   ⚠ 色だけに頼らず**必ず下線も付ける**こと。accent は @メンション(赤・太字・下線なし)も使っていて、
     赤いだけでは「DOPP の中へ行くもの」と区別が付かない。下線が「外に出る」側の目印。
   ⚠ 第37便 (2026-09-15) で accent を #B7371C に濃くしたので、白の上 5.87:1 で AA(4.5:1) を満たす。
     ⚠ それでも下線は消さないこと。「文字のコントラスト」(1.4.3) と「色だけに頼らない」(1.4.1) は**別の条件**で、
       下線が満たしているのは後者。@メンションと見分けるためにも下線が要る。
   URL は短縮せず全文を出すので、はみ出さないよう折り返す(親の overflow-wrap: anywhere と揃える) */
.link { color: var(--accent-text); text-decoration: underline; text-underline-offset: 2px;
  text-decoration-thickness: 1px; text-decoration-color: currentColor; overflow-wrap: anywhere; }
.link:active { color: var(--accent-dark); }
.tsuggest { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 12px; background: var(--card); overflow: hidden; max-height: 220px; overflow-y: auto; }
.tsug { display: flex; align-items: center; gap: 10px; min-height: var(--tap); padding: 0 12px; border: 0; border-bottom: 1px solid var(--line); background: none; text-align: left; cursor: pointer; font: inherit; color: var(--ink); }
.tsug:last-child { border-bottom: 0; }
.tsug-u { font-weight: 600; font-size: 14px; }
.tsug-n { font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tattach { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.tab-chip { height: 36px; padding: 0 10px 0 8px; border-radius: 18px; border: 1px solid var(--line); background: var(--bg); color: var(--ink); font-size: 13px; font-weight: 500; display: inline-flex; align-items: center; gap: 5px; cursor: pointer; }
.tab-chip svg { width: 16px; height: 16px; color: var(--muted); }
.tab-chip:disabled { opacity: 0.4; cursor: default; }
.tab-chip.ask.on { background: var(--accent); color: var(--on-fill); border-color: var(--accent); }
.tab-chip.ask.on svg { color: var(--on-fill); }
.tsubmit { margin-left: auto; width: var(--tap); height: var(--tap); padding: 0; border-radius: 50%; flex: 0 0 auto; }
.treply { padding: 12px 0; border-bottom: 1px solid var(--line); display: flex; flex-direction: column; gap: 8px; }
.treply .thead .btn-text { margin-left: 0; }
.treply .towner .who b { font-size: 14px; }
/* the box for a new post looks different from the posts (dashed frame, "New Talk" on top, "Post" in words), so an answer is not typed here by mistake */
.tcomposer.new { border: 1.5px dashed var(--muted); background: var(--bg); margin-bottom: 24px; }
.tcomposer.new:focus-within { border-style: solid; border-color: var(--ink); background: var(--card); }
.tnew-head { display: flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.tnew-head svg { width: 14px; height: 14px; }
.tcomposer.new .tsubmit { width: auto; min-width: 72px; height: 40px; padding: 0 16px; border-radius: 20px; font-size: 14px; }
/* replies under the post: the latest few, a small "View all", and a "Reply…" line that turns into the composer */
.tinline { display: flex; flex-direction: column; gap: 0; border-left: 2px solid var(--line); padding-left: 12px; margin-top: -4px; }
/* 第12便: Home の Talk カードは返信を出さず、会話へ入る1行だけ。
   返信が無いので枝の縦線 (border-left) も余白も要らない */
.tinline.compact { border-left: 0; padding-left: 0; margin-top: 0; }
/* 第26便 (2026-09-15): 「View all N replies · N songs ›」は灰色の文字だけで本文の続きに見えた(本人の指摘)。
   New Talk の Song チップ・曲カードの Full Track と同じ**枠つきのピル**にした(押せる見た目を新しく作らず、既にある文法を借りる)。
   3案(ピル / 赤い文字 / 全幅の行)を Chromium で描いて比べ、本人がピルを選んだ。1話題 +8px。
   同じ CSS が Home の Talk カードの「View all … ›」「Reply ›」と、コメント欄の「N hidden comments ›」にも効く(揃う) */
.tbtn-more { display: inline-flex; align-items: center; gap: 4px; align-self: flex-start; height: 36px; margin: 2px 0; padding: 0 12px 0 14px; border: 1px solid var(--line); border-radius: 18px; background: var(--card); color: var(--ink); font-size: 13px; font-weight: 600; cursor: pointer; }
.tbtn-more:active { background: var(--bg); }
.tbtn-more svg { width: 16px; height: 16px; }
/* 2026-09-13 (第10便): 返信シートの先頭に置く元投稿。読むためだけ(♥ と ⋯ は無い)。
   前は .sheet-title の中に「名前 + 本文80字」の文字だけで、一覧で見えていた曲が開いた瞬間に消えていた */
.tpost-head { display: flex; flex-direction: column; gap: 10px; padding-bottom: 16px; margin-bottom: 4px; border-bottom: 1px solid var(--line); }
.tpost-head .thead { padding-right: 40px; }          /* 右上の × に重ならない */
.tpost-head .tbody { font-size: 15px; }
/* 2026-09-13 (第10便): 返信への返信は、親の直下に一段下げる。**2段まで**(孫は同じ枝に、下げずに並ぶ)。
   1段で 24px 使うので、390px の画面では3段目を組めない。左の細い線が枝の範囲を示す */
.treply.child { padding-left: 24px; position: relative; }
.treply.child::before { content: ''; position: absolute; left: 9px; top: 0; bottom: 0; width: 2px; background: var(--line); }
.treply.inline { padding: 8px 0; border-bottom: 0; gap: 6px; }
/* ⚠ .treply.inline と .treply.child は同じ強さなので、後に書いたこの1行が要る。
   これが無いと一覧の中で段が付かない(第11便) */
.treply.inline.child { padding-left: 20px; }
/* 第26便 (2026-09-15): Talk の押せるものを全部 44px 以上に(デザイン仕様v1「44px 以上のタップ範囲」。ChatGPT の評価報告の E)。
   議論は「決定_Talk改善_2026-09-15」。実測すると 44px 未満が 12 種類あった(♥ / Reply / Add / Full Track = 38、View all = 36、Reply… = 40 …)。
   案B = **見た目は 1px も変えず、当たり判定だけ疑似要素 (::after) で上下に広げる**(.tchip::after / .tag-link::after と同じ手)。
   行そのものを 44px に伸ばす案A は 1話題 +96px(第21便で削った分の4割)なので採らなかった。
   ⚠ 広げる量は**隣の当たり判定と重ならない範囲**で決めてある(Chromium で全組み合わせを測った。tests/fn_tap_44.mjs)。
     数字を大きくすると隣と重なり、「押したのに違うものが動く」になる。
   ⚠ .tquote(引用行)だけ**下にしか**広げない — 上には ⋯(44px)が名前の行から 10px はみ出していて、元から 4px 触れている。
   ⚠ 翻訳ボタン(.tr-toggle 28px)は全画面共通の部品なので**この便では触っていない**(次の便で全画面を測ってから) */
.tacts .tbtn-like, .tbtn-reply, .tbtn-more, .treply-open, .tab-chip, .tcomposer.new .tsubmit, .tquote, .towner, .tchip-x, .treply-ctx .ctx-x { position: relative; }
.tacts .tbtn-like::after, .tbtn-reply::after, .card.mini .m-acts .act::after { content: ""; position: absolute; inset: -3px 0; }   /* 38 → 44 (Add / Full Track はコメント欄の曲カードにも効く) */
.tacts .tbtn-like::after { left: -7px; }     /* 数字の無い ♥ は幅 37px。左(カードの余白側。隣は無い)にだけ 7px 広げて 44px に */
.tbtn-share { position: relative; }
.tbtn-reply::after, .tbtn-share::after { content: ""; position: absolute; inset: -5px 0; }   /* 第64便: ピル 36 + 枠 → 44 (.c-share と同じ) */
.tbtn-more::after, .tab-chip::after { content: ""; position: absolute; inset: -4px 0; }                                          /* 36 → 44 */
.treply-open::after, .tcomposer.new .tsubmit::after { content: ""; position: absolute; inset: -2px 0; }                          /* 40 → 44 */
.tquote::after { content: ""; position: absolute; inset: 0 0 -5px; }                                                              /* 39 → 44。下だけ */
.tchip-x::after, .treply-ctx .ctx-x::after { content: ""; position: absolute; inset: -8px; }                                     /* 28 → 44。左右も */
.tpost > .thead .towner::after, .tpost-head .thead .towner::after { content: ""; position: absolute; inset: -5px 0 -4px; }      /* 投稿の名前 35 → 44 */
/* 返信の名前の行は 24px しか無く、上の「View all」と下の引用行が近いので、当たり判定を広げるだけでは 30px までしか届かない。
   ⋯ が元から 44px で行からはみ出していたので、**行の方を 44px に揃えた**(案c。本人の選択。1話題 +40px。返信シートの中の返信も同じ)。
   名前のリンク (.towner) は行いっぱいに伸ばす (stretch) ので、行のどこを押しても人のページへ行ける */
.treply .thead { min-height: 44px; }
.treply .thead .towner { align-self: stretch; }
.treply.inline.child::before { left: 7px; }
.treply.inline .towner .who b { font-size: 13px; }
.treply.inline .tbody { font-size: 14px; }
.treply.inline .card.mini { margin: 0; }
.treply-open { display: block; width: 100%; height: 40px; margin-top: 4px; padding: 0 12px; border: 1px solid var(--line); border-radius: 20px; background: var(--card); color: var(--muted); font: inherit; font-size: 14px; text-align: left; cursor: text; }
/* 第85便 (0054): 中が見えない人に「曲で返すと、みんなの返信が見られます」。押せない説明の 1 行 (Reply… が入口) */
.tgate, .tlock { display: flex; align-items: flex-start; gap: 6px; margin: 8px 0 0; color: var(--muted); font-size: 13px; line-height: 1.5; }
.tgate svg, .tlock svg { width: 16px; height: 16px; flex: none; margin-top: 2px; }
#tr-gate { margin: 0 0 8px; }
.tinline.compact .tgate { margin: 0 0 6px; }
/* 第86便 (0055): 中が見えない投稿の曲・プレイリストの代わりの 1 行 (.tgate と同じ形・鍵の絵)。投稿のカードの中では行間 (gap) に任せる */
.card.tpost > .tlock { margin: 0; }
.tfoot .tbtn-replies > span { text-align: left; }
.treply-open:active { background: var(--bg); }
.tinline-form .tcomposer { margin: 4px 0 0 0; padding: 10px; border-radius: 14px; }
.shelf-row { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 52px; padding: 8px 4px; border: 0; border-bottom: 1px solid var(--line); background: none; color: var(--ink); font-size: 15px; font-weight: 500; text-align: left; cursor: pointer; }
.shelf-row svg { width: 20px; height: 20px; color: var(--muted); flex-shrink: 0; }
.shelf-row span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.person.prow { width: 100%; border: 0; border-bottom: 1px solid var(--line); background: none; cursor: pointer; align-items: center; font: inherit; }
.person.prow > svg { width: 20px; height: 20px; color: var(--muted); flex-shrink: 0; }
/* these sheets open on top of the replies sheet */
.sheet-bg[data-sheet="links"], .sheet-bg[data-sheet="tperson"], .sheet-bg[data-sheet="tshelf"], .sheet-bg[data-sheet="tquestion"] { z-index: 41; }

/* Meet: "Step outside" — a few people I do not follow, each with one song to try (2026-09-08) */
.card.outside { padding: 12px 14px; margin-bottom: 12px; }
.card.outside .person { padding: 0 0 10px 0; border-bottom: 0; }
.card.outside .card.mini.onow { margin: 0; background: var(--bg); border-color: transparent; }
.card.outside .onow .track-comment { display: block; font-size: 13px; color: var(--muted); margin-top: 2px; }
.card.outside .onow .rec-btn .rec { width: 44px; height: 44px; }
#outside .section-head { margin-top: 20px; }
/* 第89便 (2026-09-30): 1 人 3 曲。一言は出さず、曲名とアーティストは 1 行で「…」(本人の決定。曲の段は全員同じ高さ)。
   行の間は 4px、行の上下の余白は 8px (3 行分の高さを抑える)。カード (.card.outside) が「続けて聴く」の入れ物 */
.card.outside .o-songs { display: flex; flex-direction: column; gap: 4px; }
.card.outside .o-songs .card.mini.onow { padding: 8px 12px; flex-wrap: nowrap; }
.card.outside .o-songs .track-title, .card.outside .o-songs .track-artist { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; overflow-wrap: normal; }
/* 第91便 (2026-09-30): 人のカードを横 1 列に並べて、横にめくる (最大 10 人)。Home の .frow と同じ書き方。
   枠は画面の左右いっぱい (margin -16px)、1 枚目の左端は今まで通り 16px (padding)。めくるとカードの左端で止まる (scroll-snap)。
   カードの幅 = 枠の中の幅 − 58px (390px の画面で 300px。次のカードの左端がどの幅でも 46px 見える)。
   高さは横並びの既定 (stretch) で一番高いカードに揃う。3 曲の段はカードの下端に寄せる (めくっても曲の段の位置が同じ) */
#outside-list { display: flex; gap: 12px; margin: 0 -16px; padding: 0 16px; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; scroll-padding-left: 16px; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
#outside-list::-webkit-scrollbar { display: none; }
#outside-list > .card.outside { flex: 0 0 calc(100% - 58px); min-width: 0; margin: 0; display: flex; flex-direction: column; scroll-snap-align: start; }
#outside-list > .card.outside .o-songs { margin-top: auto; }
/* 第91便 v2: カードの名前は 1 行で「…」、属性は 2 行で「…」(本人の決定)。長い人 1 人に全員のカードの高さが引っ張られないように。
   全文はその人のページで読める。⚠ #outside-list の中だけ (Who's here の一覧・人のページの属性は切らない) */
#outside-list .person-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#outside-list .person-attrs { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
#here-head { margin-top: 28px; }
#shuffle { height: 36px; padding: 0 12px 0 10px; gap: 6px; }
#shuffle svg { width: 18px; height: 18px; }
#shuffle:disabled { opacity: 0.5; }

/* Now Playing (My Picks): the empty slot, and the glow while a record is carried over it (2026-09-09) */
.now-empty { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; height: 72px; border: 1.5px dashed var(--line); border-radius: 16px; background: var(--card); color: var(--muted); font-size: 15px; font-weight: 600; cursor: pointer; }
.now-empty svg { width: 22px; height: 22px; }
.now-empty:active { background: var(--bg); }
#now-block { border-radius: 18px; transition: box-shadow .15s ease, background .15s ease; }
#now-block.drop-zone-on { box-shadow: 0 0 0 3px var(--accent); background: var(--accent-a06); }
#now-block.drop-zone-on .now-empty { border-color: var(--accent); color: var(--accent-text); }

/* small Follow / Following (Meet rows, Home's follow cards) */
.fbtn { width: auto; height: 36px; padding: 0 12px 0 10px; font-size: 13px; border-radius: 18px; gap: 5px; flex: 0 0 auto; }
.fbtn svg { width: 16px; height: 16px; }
.fbtn.on { background: var(--fill-ink); color: var(--on-ink); border: 0; }
.fbtn.on:active { background: var(--ink-press); }

/* Home: Step outside — cards to slide through, one person + one song + Follow (2026-09-09) */
#outside .section-head, #cv-head { margin: 24px 0 12px 0; }   /* 第90便: Covers の見出しも同じ余白 */
#outside .section-head .btn-text { font-size: 13px; padding: 0 4px; min-height: 0; }
.frow { margin: 0 -16px 8px; padding: 0 16px 6px; display: flex; gap: 12px; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.frow::-webkit-scrollbar { display: none; }
.fcard { flex: 0 0 200px; scroll-snap-align: start; background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 14px 12px 12px; display: flex; flex-direction: column; align-items: center; text-align: center; position: relative; transition: opacity .4s ease, transform .4s ease; }
.fcard.done { opacity: 0; transform: scale(0.96); }
.fcard .fx { position: absolute; top: 4px; right: 4px; width: 36px; height: 36px; border: 0; background: none; color: var(--muted); display: flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; }
.fcard .fx svg { width: 16px; height: 16px; }
.fcard .flink { display: flex; flex-direction: column; align-items: center; color: var(--ink); max-width: 100%; }
.fcard .flink .avatar { width: 64px; height: 64px; font-size: 26px; margin-top: 4px; }
.fcard .fname { font-weight: 600; font-size: 15px; margin-top: 8px; line-height: 1.3; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fcard .fattrs { font-size: 13px; color: var(--muted); line-height: 1.4; min-height: 17px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fcard .fsong { display: flex; align-items: center; gap: 8px; margin: 12px 0; width: 100%; text-align: left; min-height: 44px; }
.fcard .fsong .rec { width: 40px; height: 40px; flex-shrink: 0; }
.fcard .fsong .ft { min-width: 0; flex: 1; }
.fcard .fsong .ft b { display: block; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fcard .fsong .ft span { display: block; font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fcard .fsong .play { width: 36px; height: 36px; }
.fcard .fsong .play .ico { width: 18px; height: 18px; }
.fcard .fsong.none { color: var(--muted); font-size: 13px; justify-content: center; }
.fcard .fslot { width: 100%; display: flex; }
.fcard .fslot .fbtn { width: 100%; height: 40px; font-size: 14px; border-radius: 20px; }

/* Picked by N people (from the song sheet): their note on this song under the name */
.pb-note { font-size: 13px; color: var(--ink); line-height: 1.45; margin-top: 4px; overflow-wrap: anywhere; }
#pickedby-sheet { z-index: 41; }
/* 第79便: 届いた先の一覧シート (曲シートの上から開くので同じ高さ) と、曲ごとの小見出し。曲シートの行は長い名前でも2行まで伸ばす */
#pickedup-sheet { z-index: 41; }
.pu-song { margin: 16px 0 0; font-size: 13px; font-weight: 600; color: var(--muted); overflow-wrap: anywhere; }
.all-row.pu-row { height: auto; min-height: 56px; padding-top: 8px; padding-bottom: 8px; }
.all-row.pu-row > span:first-of-type { min-width: 0; overflow-wrap: anywhere; line-height: 1.35; }

/* Bottom tabs */
/* Home の一番上: 招待した人からの一言(2026-09-10)。admin が書いた最新の1件だけ。× で閉じたことは端末が覚える */
.nbox { display: flex; align-items: flex-start; gap: 8px; background: var(--accent-a07); border-radius: 12px; padding: 10px 12px; margin: 0 0 8px 0; }
.nbox > svg { width: 18px; height: 18px; color: var(--accent-text); flex-shrink: 0; margin-top: 5px; }   /* centred on the 28px heading row (第27便) */
.nbox .n-col { flex: 1; min-width: 0; }
/* 第27便 (2026-09-15): 畳んで出す。見出し1行「A note from DOPP」+ (この端末でまだ開いていなければ) NEW + 矢印。
   .fold の間は本文・翻訳ボタン・What's new を隠す。見出しは 28px の行だが当たり判定は ::after で 44px (第26便と同じ手) */
.nbox .n-head { position: relative; display: flex; align-items: center; gap: 8px; width: 100%; min-height: 28px; padding: 0; border: 0; background: none; font: inherit; font-size: 14px; font-weight: 600; color: var(--ink); text-align: left; cursor: pointer; }
.nbox .n-head::after { content: ""; position: absolute; inset: -8px 0; }
.nbox .n-head > svg { width: 16px; height: 16px; margin-left: auto; color: var(--muted); flex-shrink: 0; transition: transform 0.15s; }
.nbox:not(.fold) .n-head > svg { transform: rotate(180deg); }
.nbox .n-new { font-size: 11px; font-weight: 700; letter-spacing: 0.06em; line-height: 1.2; color: var(--on-fill); background: var(--accent); border-radius: 999px; padding: 2px 7px; }
.nbox .n-fold { margin-top: 8px; }
.nbox.fold .n-fold { display: none; }
.nbox .n-body { font-size: 14px; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; }
/* the link sits OUTSIDE .n-body: translating replaces the whole text of that element, which would eat the link */
.nbox .n-more { position: relative; display: inline-flex; align-items: center; gap: 2px; margin-top: 6px; font-size: 13px; font-weight: 600; color: var(--accent-text); }
.nbox .n-more svg { width: 16px; height: 16px; color: var(--accent-text); }
.nbox .n-more::after { content: ""; position: absolute; inset: -6px -8px; }        /* a finger-sized tap area on a 13px line */
.nbox .n-x { width: 28px; height: 28px; flex-shrink: 0; margin: 0 -4px 0 0; padding: 0; border: 0; border-radius: 50%; background: none; color: var(--muted); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
.nbox .n-x svg { width: 14px; height: 14px; }
.nbox .tr-toggle { margin-top: 2px; }

/* What's new (/news.html) — 機能が増えた記録。静的に書く */
/* Report (2026-09-11). The reasons are the seven forbidden things from /about.html, one tap each */
.rep-reasons { display: flex; flex-direction: column; gap: 8px; }
.rep-reason { display: flex; align-items: center; min-height: var(--tap); padding: 0 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--card); color: var(--ink); font: inherit; font-size: 15px; font-weight: 500; text-align: left; cursor: pointer; }
.rep-reason:active { background: var(--line); }
.rep-reason.on { border-color: var(--ink); border-width: 1.5px; font-weight: 600; }

/* a reply the post's owner hid: still there, just stepped aside (0020) */
.treply.hidden-r { opacity: 0.55; }
.thidden { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); border: 1px solid var(--line); border-radius: 10px; padding: 1px 7px; flex-shrink: 0; }
.thidden svg { width: 12px; height: 12px; }
.tbtn-more.hid { color: var(--muted); gap: 5px; }
/* 第59便 (2026-09-22): 「⊕ Add all N songs ›」は View all の真上に並ぶピル。margin 2px どうしだと当たり判定 (::after) が
   重なって、上のピルの下側が下のピルに取られる。下だけ 6px にして当たり判定が重ならないようにする (elementFromPoint で実測済み。4px だと 1px 取られる) */
.tbtn-more.addall { margin-bottom: 6px; }
.tbtn-more.hid svg:first-child { width: 15px; height: 15px; }

/* Reports in /admin.html */
.admin-row.rep .t { display: flex; flex-direction: column; gap: 2px; }
.admin-row.rep.done { opacity: 0.5; }
.rep-quote { font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
.rep-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 4px; }
/* 第101便 (0061): /admin.html の項目ごとに外す / 戻す (報告の行と「会員を探す」)。1 項目 = 見出し + 中身 + ボタン */
.adm-parts { display: flex; flex-direction: column; gap: 2px; }
.adm-part { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; padding: 4px 0; border-top: 1px dashed var(--line); font-size: 14px; }
.adm-part-k { flex: 0 0 auto; font-size: 13px; color: var(--muted); min-width: 6em; }
.adm-part-v { flex: 1 1 12em; min-width: 0; overflow-wrap: anywhere; }
.adm-off { color: var(--muted); font-size: 13px; }
.adm-sub { display: block; margin-top: 8px; font-size: 13px; font-weight: 600; color: var(--muted); }

/* 運営が下げたもの。この行が見えるのは書いた本人と admin だけ (0021) */
.gone-line { display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; color: var(--muted); }
.gone-line svg { width: 15px; height: 15px; flex-shrink: 0; }
.card.pick.removed, .tpost.removed, .treply.removed, .comment.removed, .send-row.removed { opacity: 0.6; }
/* Pick の持ち主が畳んだコメント (0024)。Talk の返信と同じ見た目にする */
.comment.hidden-c { opacity: 0.55; }
#cm-showhidden { margin: 4px 0 8px 0; }
/* フィルターが自動で伏せたもの。まだ人が見ていない = 戻る見込みがあるので、消されたのとは色を変える (0022) */
.gone-line.wait { color: var(--accent-text); }
.send-row .gone-line { margin-bottom: 6px; }


/* 停止されている人に、どのページでも出る帯 (0021) */
.hold { display: flex; flex-direction: column; gap: 2px; border: 1px solid var(--accent); border-radius: 12px; padding: 12px 14px; margin: 8px 0 16px 0; font-size: 14px; line-height: 1.5; }
.hold b { font-size: 15px; }
.hold span { color: var(--muted); }
.hold a { color: var(--ink); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; margin-top: 4px; }

/* 運営からの警告 (0023)。停止の一歩手前。「I understand」を押すまで、どのページにも出る */
.warn { display: flex; flex-direction: column; gap: 6px; border: 1px solid var(--accent); border-radius: 12px; background: var(--card); padding: 14px; margin: 8px 0 16px 0; font-size: 14px; line-height: 1.6; }
.warn > b { display: flex; align-items: center; gap: 6px; font-size: 15px; }
.warn > b svg { width: 18px; height: 18px; color: var(--accent-text); flex-shrink: 0; }
.warn-body { white-space: pre-wrap; overflow-wrap: anywhere; color: var(--muted); }
.warn-acts { display: flex; align-items: center; gap: 16px; margin-top: 6px; }
.warn-acts .btn { width: auto; height: 40px; padding: 0 22px; flex: 0 0 auto; }
.warn-acts a { color: var(--muted); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }

/* About / Terms / Privacy (2026-09-11). The one page in DOPP with running text; Japanese first, English below */
.doc { font-size: 15px; line-height: 1.7; padding-bottom: 8px; }
.doc h2 { font-size: 19px; font-weight: 700; line-height: 1.4; margin: 34px 0 2px 0; scroll-margin-top: 12px; }
.doc h3 { font-size: 15px; font-weight: 700; line-height: 1.5; margin: 22px 0 2px 0; }
.doc p { margin: 8px 0; overflow-wrap: anywhere; }
.doc ul { margin: 8px 0; padding-left: 20px; }
.doc li { margin: 5px 0; overflow-wrap: anywhere; }
.doc a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
.doc .updated { font-size: 13px; color: var(--muted); margin: 0; }
.doc .lang { font-size: 13px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); margin: 0; }
.doc hr { border: 0; border-top: 1px solid var(--line); margin: 36px 0 28px 0; }
.doc .toc { display: flex; flex-wrap: wrap; gap: 8px; margin: 14px 0 4px 0; }
.doc .toc a { display: inline-flex; align-items: center; height: 32px; padding: 0 12px; border: 1px solid var(--line); border-radius: 16px; background: var(--card); font-size: 13px; font-weight: 500; text-decoration: none; }
.doc .toc a:active { background: var(--line); }

.news-item { padding: 18px 0; border-bottom: 1px solid var(--line); }
.news-item:last-child { border-bottom: 0; }
.news-when { font-size: 13px; font-weight: 600; letter-spacing: 0.02em; color: var(--muted); }
.news-title { font-size: 16px; font-weight: 700; line-height: 1.4; margin: 2px 0 6px 0; }
.news-body { font-size: 15px; line-height: 1.6; white-space: pre-line; overflow-wrap: anywhere; }

/* "Previews provided courtesy of iTunes" — one quiet line at the bottom of the content, and at the bottom of the song picker (2026-09-10) */
.credit { font-size: 13px; line-height: 1.5; color: var(--muted); text-align: center; margin: 24px 0 0; }
.sheet .credit { margin-top: 16px; }
/* when the line stands in a section heading's place (Home's stream, My Picks' Now Playing), it takes that heading's spacing */
/* 第56便 (2026-09-22): 32 → 26px。文字を 12 → 13px にした分、チャートの曲名が一番長い日に Home の最初の曲が下のタブに 2px 隠れたため。
   ⚠ 戻すなら node tests/fn_font_13.mjs と fn_home_top.mjs の【N】で下のタブまでの余裕を測ること */
.credit.slot { margin: 26px 0 16px; }

.tabbar { position: fixed; bottom: 0; left: 50%; transform: translateX(-50%); width: 100%; max-width: 430px; height: calc(72px + env(safe-area-inset-bottom)); display: flex; border-top: 1px solid var(--line); background: var(--card); padding-bottom: env(safe-area-inset-bottom); }
/* 第38便 (2026-09-15。本人の実機 = iPhone の Chrome での報告): スクロールしてブラウザの下のツールバーが引っ込むと、
   下部ナビが画面の底まで来ず、**ナビの下にカードが漏れて見える**(本人の画像で確認。ページ自体は動いていない)。
   → ナビと同じ白を 160px 下に伸ばして、ナビが画面の底まで続いているように見せる。
   ⚠ これは**漏れて見える中身を隠すだけ**で、ナビの位置そのものは直していない。位置の直しは viewport-fit=cover(未確認)。
   ⚠ 普通のブラウザでは `top: 100%` = 画面の底なので**完全に画面の外**。ページの高さも横幅も 1px も変わらない
      (Chromium で撮り比べて同一を確認。`node tests/fn_tabbar_skirt.mjs`)。
   ⚠ pointer-events は既定のまま(漏れている場所のタップを吸う。下のカードが誤って反応しないように) */
.tabbar::after { content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 160px; background: var(--card); }
/* 第28便 → 第29便 (2026-09-15): 曲が鳴っている間、下部ナビの真上に出る黒いバー (picks.js の nowbarOn / nowbarOff)。
   黒い面は再生ボタンにしか使っていない色なので「音が鳴っている」が一目で分かる。シートより下 (z 30 < 40)。
   .show でフェードして出る (0.22s、下から 8px 浮き上がる)。消える時は同じ道を戻る */
.nowbar { position: fixed; left: 50%; transform: translate(-50%, 8px); width: 100%; max-width: 430px; bottom: calc(72px + env(safe-area-inset-bottom)); height: 56px; display: flex; align-items: center; gap: 4px; padding: 0 12px 0 8px; background: var(--fill-ink); color: var(--on-ink); z-index: 30; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.22s ease, transform 0.22s ease, visibility 0s linear 0.22s; }
.nowbar.show { opacity: 1; visibility: visible; pointer-events: auto; transform: translate(-50%, 0); transition: opacity 0.22s ease, transform 0.22s ease, visibility 0s; }
.nowbar .nb-back { flex: 1; min-width: 0; height: 56px; display: flex; align-items: center; gap: 12px; padding: 0 8px; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.nowbar .rec { flex-shrink: 0; width: 40px; height: 40px; }
.nowbar .nb-text { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.nowbar .nb-title { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nowbar .nb-sub { font-size: 13px; color: var(--on-dark-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nowbar .nb-add { width: 44px; height: 44px; flex-shrink: 0; padding: 0; border: 0; background: none; color: var(--on-ink); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
.nowbar .nb-add[hidden] { display: none; }
.nowbar .nb-add svg { width: 24px; height: 24px; }
.nowbar .nb-add.on { color: var(--accent-text); }
.nowbar .play { width: 40px; height: 40px; margin-left: 4px; background: var(--on-ink); color: var(--fill-ink); }
.nowbar .play .ico { width: 18px; height: 18px; }
.nowbar .play::after { content: ""; position: absolute; inset: -8px -12px -8px -2px; }   /* 44px の当たり判定 (見た目は 40)。左は ⊕ と重ねない */
.nowbar .play:active { background: var(--on-dark-press); }
body.has-nowbar .main { padding-bottom: 160px; }                                            /* 最後のカードがバーに隠れない */
body.has-nowbar .toast:not(.anchored) { bottom: 156px; }                                     /* 第109便 3a: タブの上端 (下から 152px) と 4px 空ける */
/* 第109便 3a (2026-10-15): 右上のタブに Apple Music のバッジ (T2 = 肩付き)。バッジの絵 (compact.svg 78×16) は変えない。色はバーと同じ。
   押せる高さはタブの 24px のまま (上に広げない = タブの上の物が見えないまま押せなくなるのを避ける。本人の決定) */
.nowbar .am-tab { position: absolute; bottom: 100%; right: 20px; width: 98px; height: 24px; border-radius: 10px 10px 0 0; display: flex; align-items: center; justify-content: center; background: var(--fill-ink); line-height: 0; }
.nowbar .am-tab[hidden] { display: none; }
.nowbar .am-tab img { display: block; width: 78px; height: 16px; }
.nowbar .am-tab::before, .nowbar .am-tab::after { content: ""; position: absolute; bottom: 0; width: 8px; height: 8px; pointer-events: none; }
.nowbar .am-tab::before { left: -8px; background: radial-gradient(circle at 0 0, transparent 7.5px, var(--fill-ink) 8px); }
.nowbar .am-tab::after { right: -8px; background: radial-gradient(circle at 100% 0, transparent 7.5px, var(--fill-ink) 8px); }
/* シートの上 (body.sheet-up は ui.js の第33便の見張りが付ける): 下のタブは暗幕に隠れているので、バーは画面の一番下・シートより手前 (picker 50 < 55 < 吹き出し 60)。
   開いているシートの下に「バー 56 + タブ 24」の余白 = 一番下の保存・送る・書く欄はバーのすぐ上に並ぶ (スクロールで出せる) */
body.sheet-up .nowbar { bottom: env(safe-area-inset-bottom); z-index: 55; }
body.sheet-up.has-nowbar .sheet-bg.open .sheet { padding-bottom: calc(24px + 80px + env(safe-area-inset-bottom)); }
body.sheet-up.has-nowbar .toast:not(.anchored) { bottom: 84px; }
.tab { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; color: var(--muted); font-size: 13px; font-weight: 600; position: relative; }
.tab svg { width: 22px; height: 22px; transition: transform .18s; }
.tab.on { color: var(--ink); }
.tab.on svg { transform: translateY(-2px); }
.tab.on::after { content: ''; position: absolute; bottom: 8px; width: 4px; height: 4px; border-radius: 50%; background: var(--accent); }
.tab.bump svg { animation: bump .3s ease-out; }
.tab .tdot { position: absolute; top: 12px; left: calc(50% + 8px); width: 8px; height: 8px; border-radius: 50%; background: var(--accent); border: 2px solid var(--card); }
@keyframes bump { 0% { transform: translateY(0) scale(1); } 40% { transform: translateY(-4px) scale(1.12); } 100% { transform: translateY(0) scale(1); } }
/* 第44便 (2026-09-17): 下タブの中央の + = 曲を置く。会員のタブバーだけ 5 つになる (ui.js の D.mountAddTab が .five を付ける)。
   ⚠ .tab-add は <button> なので、ボタンの既定 (枠・背景・字) を落としてから .tab と同じ並びに戻している。
   ⚠ 44px の丸は当たり判定ではなく見た目。押せる範囲はタブ 1 つ分 (320px の画面でも 64×72px) */
.tabbar.five .tab-add { flex: 1; display: flex; align-items: center; justify-content: center; padding: 0; border: 0; background: none; font: inherit; color: inherit; cursor: pointer; }
.tabbar.five .add-disc { width: 44px; height: 44px; border-radius: 50%; background: var(--accent); color: var(--on-fill); display: inline-flex; align-items: center; justify-content: center; }
.tabbar.five .add-disc svg { width: 24px; height: 24px; }
.tabbar.five .tab-add:active .add-disc { background: var(--accent-dark); }

/* Toast */
.toast { position: fixed; left: 50%; bottom: 96px; transform: translateX(-50%); background: var(--fill-ink); color: var(--on-ink); font-size: 15px; padding: 12px 18px; border-radius: 12px; opacity: 0; transition: opacity .2s; pointer-events: none; z-index: 60; width: max-content; max-width: calc(100vw - 32px); text-align: center; }
.toast.show { opacity: 1; }
.toast.acts.show { pointer-events: auto; }        /* a faded toast must not keep catching taps */
.toast.acts { display: flex; align-items: center; gap: 4px; padding: 6px 6px 6px 16px; }
/* anchored to a button (the ⊕): absolute in the page, scrolls with it, caret points at the button */
.toast.anchored { position: absolute; bottom: auto; transform: none; transition: opacity .15s; }
.toast.anchored::after { content: ""; position: absolute; left: var(--caret-x, 50%); margin-left: -7px; border: 7px solid transparent; }
/* 第38便 (2026-09-15): 「Tap the record」だけの小さい吹き出し。盤にくっつけて三角で指す (Home 改善の H09)。
   ⚠ 他のトースト (「Added · Choose ›」など) は 15px のまま — 中のボタンが押しづらくなるため */
.toast.hint { font-size: 13px; padding: 8px 12px; border-radius: 10px; }
/* 第75便 → 第76便 (2026-09-26): .toast の left: 50% のせいで、幅が画面の半分で頭打ちになっていた (320px で 160px。日本語が 2〜5 行)。
   第75便で hint だけ直し、第76便で全部の吹き出しを「文字の長さの幅・画面の左右 16px まで」にした (上の .toast の width / max-width)。
   ⚠ 位置を決める JS (D.toastWith) は幅を測ってから left を決めるので、アンカー付きもそのまま正しく付く */
.toast.hint.anchored::after { border-width: 6px; margin-left: -6px; }
.toast.anchored.above::after { top: 100%; border-top-color: var(--fill-ink); }
.toast.anchored.below::after { bottom: 100%; border-bottom-color: var(--fill-ink); }
.toast .tbtn { height: 40px; padding: 0 12px; white-space: nowrap; border: 0; border-radius: 9px; background: transparent; color: var(--on-ink); font: inherit; font-weight: 600; font-size: 15px; }
.toast .tbtn + .tbtn { border-left: 1px solid var(--on-dark-line); border-radius: 0 9px 9px 0; }
/* 第118便: Picks に足した後の吹き出し = 黒い吹き出しの中を 2 段に (D.toastAdded)。上の段 = ✓ + 文 (押せない) / 下の段 = 横幅いっぱいの白い枠線のボタン。
   赤では塗らない (選ぶのは自由)。曲で返した時だけ上の段の右端に小さい「元に戻す」。出る場所・三角・5 秒・消え方は今の吹き出しのまま */
.toast.ta { display: block; width: min(358px, calc(100vw - 32px)); padding: 12px; text-align: left; }
.toast.ta .ta-info { display: flex; align-items: center; gap: 8px; min-height: 24px; }
.toast.ta .ta-ok { flex: none; width: 22px; height: 22px; border-radius: 50%; background: var(--on-ink); color: var(--fill-ink); display: grid; place-items: center; }
.toast.ta .ta-ok .ico { width: 14px; height: 14px; stroke-width: 2.6; }
.toast.ta .ta-msg { flex: 1; min-width: 0; font-weight: 600; }
.toast.ta .ta-undo { flex: none; height: 24px; padding: 0 2px; font-size: 13px; font-weight: 400; text-decoration: underline; text-underline-offset: 3px; }
.toast.ta .ta-choose { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; height: 44px; margin-top: 12px; border: 1px solid var(--on-ink); border-radius: 12px; }
.toast.ta .ta-choose .ico { width: 20px; height: 20px; }

/* Sheets */
.sheet-bg { position: fixed; inset: 0; background: var(--scrim); display: flex; align-items: flex-end; justify-content: center; z-index: 40; visibility: hidden; opacity: 0; transition: opacity .26s ease, visibility 0s linear .26s; }
.sheet-bg.open { visibility: visible; opacity: 1; transition: opacity .22s ease; }
.sheet { position: relative; width: 100%; max-width: 430px; background: var(--bg); border-radius: 20px 20px 0 0; padding: 20px 16px calc(24px + env(safe-area-inset-bottom)) 16px; max-height: 88vh; overflow: auto; -webkit-overflow-scrolling: touch; transform: translateY(100%); transition: transform .34s cubic-bezier(.2, .8, .2, 1); will-change: transform; box-shadow: 0 -8px 32px var(--shadow); }
.sheet-bg.open .sheet { transform: translateY(0); }
.sheet:focus { outline: none; }                                  /* 第33便: 開いた時に操作先をシート自身へ移す (tabindex=-1)。枠線は出さない */
.sheet-title { font-size: 18px; font-weight: 700; margin-bottom: 16px; padding-right: 48px; line-height: 1.4; }
.sheet-bg[data-sheet="card"] { z-index: 39; }                  /* comments / Full Track / ⊕ sheets open above it */
.card-sheet { padding-top: 52px; overflow: visible; }          /* room for × ; the "…" menu may hang below the card */
.card-sheet .card { margin: 0; }
.sheet-title .note { font-weight: 400; margin-top: 2px; }
.sheet-close { position: absolute; right: 8px; top: 8px; width: var(--tap); height: var(--tap); background: none; border: 0; font-size: 26px; line-height: 1; cursor: pointer; color: var(--muted); padding: 0; border-radius: 50%; }
/* 第25便 (2026-09-15): × をスクロールしても残す。.sheet 自身がスクロールするので sticky にする。
   開いた直後の位置は上の absolute と同じ 8px / 8px (margin -12 で padding 20 を相殺、margin-bottom -32 で次の要素を元の 20px に)。
   top: -12px は Chrome では「padding の内側から -12 = 見える上端から 8px」。⚠ Safari は未確認 (違えば 12px はみ出すだけ)。
   丸をシートと同じ色で塗るのは、下を通る文字が透けないようにするため (開いた直後は見えない) */
.sheet-close { position: sticky; top: -12px; right: auto; display: block; margin: -12px -8px -32px auto; z-index: 2; background: var(--bg); }
/* 曲カードのシート (.card-sheet) はスクロールしない (overflow: visible) ので sticky にする理由が無く、padding-top も 52px で違う。今まで通り absolute */
.card-sheet .sheet-close { position: absolute; top: 8px; right: 8px; margin: 0; }
#dopp-picker { z-index: 50; }

/* Comments */
.comment { padding: 12px 0; border-bottom: 1px solid var(--line); }
.comment-head { display: flex; align-items: center; gap: 8px; }
.comment-head b { font-size: 15px; font-weight: 600; }
.comment-head .note { font-size: 13px; }
.comment-head .btn-text { margin-left: auto; }
.comment-body { font-size: 15px; line-height: 1.55; margin-top: 4px; overflow-wrap: anywhere; }

/* Empty state */
.empty { height: 240px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px; color: var(--muted); text-align: center; }
.empty svg { width: 72px; height: 72px; }
.empty .label { font-size: 15px; font-weight: 600; color: var(--ink); }
.empty .btn { width: auto; min-width: 160px; margin-top: 8px; }

/* Brand disc */
.disc { width: 72px; height: 72px; }

/* Home hero */
.hero { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 12px; padding: 24px 0 8px 0; }
.hero .logo { width: 72px; height: 72px; }
.hero .wordmark { font-size: 28px; font-weight: 700; letter-spacing: 0.18em; margin-left: 0.18em; }
.hero .tagline { font-size: 17px; font-weight: 500; color: var(--muted); }

.center { text-align: center; }
.mt { margin-top: 16px; }
.mb { margin-bottom: 16px; }
.hidden { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  .rec.spin .spinner, .act.like.pop svg, .act.add.done svg, .card.mini .cadd.done svg, .tab.bump svg, .bell.ring svg, .bell .dot { animation: none; }
  .tab svg, .act svg, .sheet, .sheet-bg, .shelf-wrap::after, .nowbar { transition: none; }
  .vbtn.listening svg, .vmic.on svg, .voice-live .bars i { animation: none; }
  .voice-live .bars i { height: 14px; }
  .shelf-scroller { scroll-behavior: auto; }
}

/* ============================================================
   第45便 (2026-09-17): 44px 未満の押せるものを、見た目を変えずに 44px に
   ------------------------------------------------------------
   第26便 (2026-09-15) で「Talk の押せるものは 44px 以上・当たり判定は隣と重ねない」を恒久ルールにしたが、
   Talk の外では 44px 未満が **15 か所** 残っていた (提案_UI改善_2026-09-17 の D)。
   やり方は第26便と同じ「案B = 見た目は変えず、::after で当たり判定だけ広げる」。**見た目は 1px も変わらない。**

   ⚠⚠ 広げる量は「隣の押せるものと重ならない範囲」で 390px の実画面を測って決めてある。
       **数字を大きくして 44px に届かせるのは禁止**(押したのに違うものが動く)。
       足したら必ず `node tests/fn_tap_44_all.mjs`(44px・重なり 0・見た目据え置きを全部見る)。

   ⚠ 広げる向きが限られるもの (実測。下に空きが無い):
       ・お知らせの中の翻訳ボタン … 下に「What's new」が **0px** で接している → 上へ 14px
       ・棚のタイルの再生ボタン   … 下に曲名のボタンが **2px**              → 上と左右へ
       ・写真のカメラ             … 下に「Remove photo」が **4px**          → 上と左右へ
       ・Songs | Albums           … 左右は互いに **0px** で接している        → 上下だけ
       ・About の目次             … 左右が **8px** しかない                  → 上下だけ
   ============================================================ */

/* ① お知らせの帯の × (28 → 44) */
.nbox .n-x { position: relative; }
.nbox .n-x::after { content: ""; position: absolute; inset: -8px -12px -8px -4px; }
   /* ⚠ 左は 4px だけ。8px にすると見出し (.n-head::after が横幅いっぱい) と当たり判定がぴったり接する。
      足りない幅は右 (何も無い側) で稼ぐ */

/* ② 翻訳ボタン (30px) は **この便では触らない**。実測した結果、44px にすると必ず隣から取り上げてしまう:
      ・お知らせの中 … すぐ下の「What's new ›」と **0px** で接している
      ・コメントの中 … すぐ上の「⋯」(44px) が本文の側へ 7px はみ出していて、空きが無い
      ・自己紹介 / What's new … 下の押せるものと 0〜2px
      文字の行を太らせずに 44px にする空きがどこにも無いので、**見た目を変える判断が要る**(別の便)。
      第26便で「次の便で全画面を測ってから」と保留にしたものの、測った答えが「そのままでは入らない」だった。

/* ③ 「Liked by …」(30 → 44) + ♥ との 2px の重なりを解消
   ⚠⚠ 第39便 (`.likers-row { margin-top: -14px }`) の副作用で、**♥ / コメント / ⊕ / Full Track の
      当たり判定の底 2px が「Liked by」に食われていた**(実効 42px)。
   ⚠⚠ **ここだけ ::after が使えない。**`.likers` は文字が長い時に「…」で切るため `overflow: hidden` を
      持っていて、**はみ出した ::after はその場で切り落とされる**(広げたつもりが 1px も広がらない)。
      そこで **箱そのものを 44px にして、増えた分を負の margin で相殺する**:
        ・上: margin-top 2px + padding-top 4px  … 合計 6px で文字の位置は元と同じ。箱の上端だけ 2px 下がり、♥ と接する (重ならない)
        ・下: padding-bottom 22px + margin-bottom -14px … 箱は 44px、外から見た高さは元の 30px のまま
      **文字の位置もカードの高さも 1px も動かない**(fn_tap_44_all.mjs の【D】が撮り比べて見張る)
   ⚠ `.likers-row { margin-top: -14px }` は触っていない。消さないこと (第39便) */
.likers { position: relative; margin: 2px 0 -16px; padding: 4px 0 22px; }

/* ④ Keep in My Picks のトグル (30 → 44)
   ⚠⚠ `.switch::after` は**丸いつまみ**に使われている。ここだけ `::before` を使う */
.switch::before { content: ""; position: absolute; inset: -7px 0; }

/* ⑤ Follow (3 つの大きさがある。文脈ごとに量が違う) */
.fbtn { position: relative; }
.fbtn::after { content: ""; position: absolute; inset: -4px 0; }   /* Meet の行・人のページ 36 → 44 */
.act-row .act-follow .fbtn::after { inset: -6px 0; }               /* Activity の行 32 → 44 */
.fcard .fslot .fbtn::after { inset: -2px 0; }                      /* Step outside の人カード 40 → 44 */

/* ⑥ Step outside の Shuffle (36 → 44) */
#shuffle { position: relative; }
#shuffle::after { content: ""; position: absolute; inset: -5px 0; }
   /* ⚠ -4px ではなく -5px。`.btn-ghost` の **1px の枠線**のぶん、::after の基準 (padding box) が内側に寄る */

/* ⑦ 棚のタイルの再生ボタン (36 → 44)。下は曲名のボタンが 2px しか離れていないので上と左右へ */
.play.mini::after { content: ""; position: absolute; inset: -8px -4px 0; }
.play.mini.alt::after { inset: -9px -5px 0; }   /* ⚠ 試聴できない曲の ↗ 版は **1px の枠線**があるぶん 1px 多く */

/* ⑧ Step outside の人カードの × (36 → 44) */
.fcard .fx::after { content: ""; position: absolute; inset: -4px; }

/* ⑨ 曲を探す画面の Songs | Albums (38 → 44)。左右は互いに接しているので上下だけ */
.seg-btn { position: relative; }
.seg-btn::after { content: ""; position: absolute; inset: -3px 0; }

/* ⑩ プロフィール写真のカメラ (40 → 44)。下は「Remove photo」が 4px なので上と左右へ
   ⚠ -4px / -2px ではなく -6px / -4px。**2px の枠線**のぶん、::after の基準が内側に寄る */
.photo-wrap .cam::after { content: ""; position: absolute; inset: -6px -4px 0; }

/* ⑪ 吹き出しの中のボタン (40 → 44) */
.toast .tbtn { position: relative; }
.toast .tbtn::after { content: ""; position: absolute; inset: -2px 0; }
.toast.ta .ta-undo::after { inset: -10px -8px; }        /* 第118便: 小さい「元に戻す」(24px) も押せる高さ 44px */
.toast.ta .ta-choose::after { inset: 0; }

/* ⑫ 警告の「I understand」(40 → 44) */
.warn-acts .btn { position: relative; }
.warn-acts .btn::after { content: ""; position: absolute; inset: -2px 0; }

/* 第75便 (2026-09-26): 停止の帯・警告の帯の「Contact DOPP ›」(21 / 22 → 44)。見た目は変えず上下だけ広げる。
   警告の帯では左の「I understand」と 16px 空いているので、横には広げない */
.hold a, .warn-acts a { position: relative; }
.hold a::after, .warn-acts a::after { content: ""; position: absolute; inset: -12px 0; }

/* ⑬ /about.html の目次 (32 → 44)。左右が 8px しかないので上下だけ */
.doc .toc a { position: relative; }
.doc .toc a::after { content: ""; position: absolute; inset: -7px 0; }
   /* ⚠ -6px ではなく -7px。**1px の枠線**のぶん */

/* ===== Feedback (第61便、2026-09-23、0039)。/feedback.html だけ。class は全部 fb- で始める。
   ⚠ 置き場所はチャート (ch-) の節の**前**。tests/fn_chart_home.mjs の A1 が「チャートの節より後の class は全部 ch-」と見ているため (その便の番号をここに書かないこと。A1 は番号で節の頭を探す) =====
   色は :root の名前だけ (新しい色は無い)。角丸は表の値 (箱 12px / ピルは高さの半分)。
   届いた (received) と今はやらない (not_now) は灰色の枠、やる (planned) は黒い枠、できた (done) は黒く塗る (Following と同じ --fill-ink) */
.fb-form { margin-top: 8px; }
.fb-row { align-items: center; margin-top: 4px; }
.fb-row .fb-note { flex: 1; min-width: 0; }
.fb-row .btn { flex: 0 0 auto; width: auto; min-width: 96px; padding: 0 20px; }   /* .btn は width: 100% なので戻す。.row > * の flex: 1 も外す */
.fb-row-item { padding: 12px 0; border-bottom: 1px solid var(--line); }
.fb-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.fb-head .when { margin-left: auto; font-size: 13px; color: var(--muted); white-space: nowrap; }
.fb-status { height: 24px; padding: 0 10px; border-radius: 12px; border: 1px solid var(--line); background: var(--card); color: var(--muted); font-size: 13px; font-weight: 600; display: inline-flex; align-items: center; white-space: nowrap; }
.fb-status.planned { border-color: var(--ink); color: var(--ink); }
.fb-status.done { border-color: var(--fill-ink); background: var(--fill-ink); color: var(--on-ink); }
.fb-body { font-size: 15px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
.fb-reply { margin-top: 8px; padding: 10px 12px; border-radius: 12px; background: var(--card); font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
.fb-reply b { display: block; font-size: 13px; color: var(--muted); margin-bottom: 2px; }   /* 翻訳ボタン (.tr-toggle) が本文の後ろに入るので、横並びにしない */
.fb-reply span { white-space: pre-wrap; }

/* ============================================================
   第47便 (2026-09-17) — 世界チャート Daily World Chart
   ⚠ class は全部 `ch-` で始める(既存とぶつけない。第37便で `.row` を使って丸が楕円になった)
   ⚠ 高さは 412px。**第27便で作った 433px より短い**ので、会員の曲は1pxも下がらない
   ============================================================ */
.ch-box { background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 16px; margin: 0 0 8px 0; }
.ch-when { font-size: 13px; color: var(--accent-text); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; display: flex; align-items: center; gap: 6px; }
.ch-when svg { width: 15px; height: 15px; }
.ch-title { font-size: 17px; font-weight: 700; line-height: 1.3; margin: 4px 0 0; overflow-wrap: anywhere; }
   /* 国旗の絵文字。⚠ Windows には国旗が無いので「KR」の2文字になる(壊れない) */
.ch-flag { font-style: normal; margin-left: 6px; }
.ch-list { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.ch-row { display: flex; align-items: center; gap: 10px; }
   /* 番号は等幅の数字にして、2桁になっても曲名の左端が動かないようにする */
.ch-n { width: 16px; text-align: right; font-size: 14px; font-weight: 700; color: var(--muted); flex-shrink: 0; font-variant-numeric: tabular-nums; }
.ch-row .card.mini { flex: 1; margin: 0; min-width: 0; }
.ch-next { font-size: 13px; color: var(--muted); margin-top: 10px; text-align: center; }
   /* ⚠ 古いデータを使った日だけ出る。黙って前日の分を「今日の流行」として見せない */
.ch-stale { font-size: 13px; color: var(--muted); margin-top: 8px; text-align: center; }
/* 第68便 (2026-09-25): Daily World Chart の ♥ (/chart.html と Liked だけ。Home の3行には出ない)。
   形は .act のまま (Add・Full Track と同じ 38px + 当たり判定 44px)。押した色は .act.on の --accent-text。数が 0 の時は数の分のすき間も消す */
.ch-like .n:empty { display: none; }
/* Liked の中のチャートの曲: 上に「Daily World Chart · 🇰🇷 South Korea」(Now Playing の .card-kicker と同じ文字) */
.ch-liked { margin: 16px 0; }
.ch-liked .card.mini { margin: 0; }
.ch-kick { display: flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-text); margin: 0 0 8px 0; }
.ch-kick svg { width: 14px; height: 14px; flex-shrink: 0; }
.ch-kick .ch-flag { margin: 0 4px 0 0; }
/* ⭐ 第94便 (2026-10-01): Home の一番上は、押すと開くボタン 2 つ (Daily World Chart → /chart.html / Covers → /people.html#covers)。
   地・枠・角丸は .ch-box と同じ (大きい箱 = 16px)。上段 .ch-when と下段 .ch-title も /chart.html の見出しと同じものを使う。
   ボタン全体が 1 つのリンク。右端の › は --muted。2 つの間は 8px (すき間の表から)。
   (第51便の「Home の 3 行の曲名を 2 行で切る」2 行は、Home に曲を並べなくなったので消した)
   ⚠ 下段は 16px。17px (/chart.html の見出し) だと 320px の英語で「What's hot in South Korea」が折り返した (本物のフォントで実測)。/chart.html の見出しは 17px のまま
   足したら node tests/fn_chart_home.mjs */
.ch-go-list { display: flex; flex-direction: column; gap: 8px; margin: 0 0 8px 0; }
.ch-go { display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 14px 12px 14px 16px; background: var(--card); border: 1px solid var(--line); border-radius: 16px; color: var(--ink); }
.ch-go:active { background: var(--bg); }
.ch-go-text { flex: 1; min-width: 0; }
.ch-go .ch-title { font-size: 16px; margin-top: 3px; }
.ch-go .ch-stale { text-align: left; margin-top: 2px; }
.ch-go > svg { width: 20px; height: 20px; flex-shrink: 0; color: var(--muted); }
/* 第98便の Covers のボタンの「：」の行は第116便で外した (For You のボタンに置き換え) */
.ch-go .ch-cut { white-space: nowrap; }   /* 第116便: For You のボタンの下段は切れ目 (日「、」/ 英 文) の後でだけ折る (Covers のボタンの keep-all の行と入れ替え) */

/* ===== 第62便 (2026-09-23): コレクションを X などで共有する =====
   /c/<id> のページ (public/c/index.php) と、自分の棚・人の棚を開いた画面の Share。
   ⚠ class は全部 c- で始める (見本を描いた時に .row を使って、既存の .row > * { flex: 1 } で Share が横いっぱいに伸びた。第37便と同じ罠)
   ⚠ 色は :root の名前だけ (暗い画面でも効く)。角丸とすき間は CLAUDE.md の表から (格子 12px / ピル 18px = 高さ 36 の半分)
   ⚠ 格子の割り方は X のカードと同じ (本人の決定 11): 1曲 = 1枚 / 2曲 = 左右 / 3曲 = 左に1枚 + 右に2枚 / 4曲以上 = 2x2 */
.c-hero { display: flex; gap: 16px; align-items: flex-start; margin: 8px 0 20px; }
.c-grid { width: 148px; height: 148px; flex-shrink: 0; display: grid; border-radius: 12px; overflow: hidden; background: var(--line); }
.c-grid img { width: 100%; height: 100%; object-fit: cover; display: block; min-width: 0; min-height: 0; }
.c-grid.c-n1 { grid-template: 1fr / 1fr; }
.c-grid.c-n2 { grid-template: 1fr / 1fr 1fr; }
.c-grid.c-n3, .c-grid.c-n4 { grid-template: 1fr 1fr / 1fr 1fr; }
.c-grid.c-n3 img:first-child { grid-row: 1 / 3; }
.c-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.c-kicker { font-size: 13px; font-weight: 500; color: var(--muted); }
.c-title { margin: 0; font-size: 22px; font-weight: 700; line-height: 1.3; overflow-wrap: anywhere; }
.c-owner { position: relative; display: inline-flex; align-items: center; gap: 6px; min-height: 32px; font-size: 15px; font-weight: 600; color: var(--muted); }
.c-owner::after { content: ""; position: absolute; inset: -6px 0; }          /* 押せる高さ 32 → 44 (見た目は変えない) */
.c-count { font-size: 13px; font-weight: 600; color: var(--accent-text); }
.c-share { position: relative; display: inline-flex; align-items: center; gap: 6px; height: 36px; padding: 0 14px; border: 1px solid var(--line); border-radius: 18px; background: var(--card); color: var(--ink); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; }
.c-share svg { width: 18px; height: 18px; }
.c-share:active { background: var(--bg); }
.c-share::after { content: ""; position: absolute; inset: -5px 0; }         /* 押せる高さ 36 → 44。⚠ 枠線 1px の分だけ多い (第45便の罠。tests/fn_share.mjs が実測する) */
.c-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: -4px 0 16px; }
.c-opens { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }
.c-opens svg { width: 16px; height: 16px; flex-shrink: 0; }
.c-actions .switch-row { margin-left: auto; }   /* 第106便: My Picks のシェアの行の右に「非公開」のスイッチ (今の .switch-row のまま) */
/* 第79便 (2026-09-28): 届いた先。My Picks のプレイリストの上の1行 (押すと一覧)。本人にだけ出る。押せる高さ 44px */
#col-picked { margin: -8px 0 12px; }
.c-picked { display: flex; align-items: center; gap: 6px; width: 100%; min-height: 44px; padding: 0; margin: 0; background: none; border: 0; font: inherit; font-size: 13px; line-height: 1.4; color: var(--muted); text-align: left; cursor: pointer; }
.c-picked span { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.c-picked svg { width: 16px; height: 16px; flex-shrink: 0; }
.c-picked:active { color: var(--ink); }
.c-empty { text-align: center; padding: 24px 0; color: var(--muted); }
.c-empty p { margin: 0 0 12px; font-size: 15px; }
.c-empty .btn { width: auto; }
.c-gone { padding-top: 64px; }
.c-gone .c-title { margin-bottom: 20px; color: var(--ink); }
/* ログインしていない人の下の黒い帯 (本人の決定 9・14)。下のタブの真上。曲が鳴っている間は黒いバー (56px) の上へ逃げる */
.c-join { position: fixed; left: 50%; transform: translateX(-50%); width: 100%; max-width: 430px; bottom: calc(72px + env(safe-area-inset-bottom)); display: flex; align-items: center; gap: 12px; padding: 12px 16px; background: var(--fill-ink); color: var(--on-ink); z-index: 29; }
.c-join-t { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: 13px; line-height: 1.4; }
.c-join-t b { font-size: 15px; font-weight: 700; }
.c-join-t span { color: var(--on-dark-2); }
/* 第73便 v2: 日本語の端末だけ、言葉の途中で折り返さない。折り返すのは <wbr> を入れた所 (「DOPP の / プレイリスト」「こんなプレイリストを、/ あなたも。」) だけ。
   幅が足りれば1行のまま。英語の画面は変わらない (⚠ overflow-wrap: anywhere は入れない。「、」が行の頭に来た) */
:lang(ja) .c-kicker, :lang(ja) .c-join-t b, :lang(ja) .j-open { word-break: keep-all; }   /* 第76便 v2: 登録を送った後の「開いて、/ プロフィールの登録を…」(join.html) */
.c-join .btn { width: auto; height: 44px; flex-shrink: 0; }
body.c-joinbar .main { padding-bottom: 184px; }
body.c-joinbar.has-nowbar .c-join { bottom: calc(156px + env(safe-area-inset-bottom)); }   /* 第109便 3a: 128 → 156 (タブの上端 152 + 4px) */
body.c-joinbar.has-nowbar .main { padding-bottom: 268px; }
/* 第64便: Talk の共有ページ /t/<id> (黒い帯・消えた時の文は /c/ の部品をそのまま使う) */
.t-post { margin-top: 16px; }
/* 第65便: 退会 (/me/edit.html)。本人の決定 = 控えめな赤い文字。押せる高さは .btn-text の 44px のまま */
.da-open { font-size: 13px; font-weight: 500; padding: 12px; }
.da-lead { margin: 0 0 8px; font-size: 15px; }
.da-list { margin: 0 0 12px; padding-left: 20px; font-size: 14px; color: var(--muted); line-height: 1.6; }
.da-warn { margin: 0 0 16px; font-size: 15px; font-weight: 700; color: var(--accent-text); }
/* 第66便: Weekly email のスイッチ。メールの「止める」リンク (?email=1) から来た時に一瞬光る (カードの .flash と同じ動き) */
.switch-row.flash { animation: flash 1.2s ease-out; border-radius: 12px; }
/* 第96便 (2026-10-01): Share のシート。行き先のマークだけ (名前は出さない。本人の決定 2) = 丸い灰色の地にロゴ 1 色。暗い画面は反転 (明るい丸に暗いロゴ)
   プレイリスト = Instagram・Threads・X・その他 (4つ) / Talk = Threads・X・その他 (3つ)。丸 56px (押せる範囲もそのまま 56px)。
   ⚠ 320px の画面でも 4 つ並ぶ: 56 × 4 + 16 × 3 = 272px ≤ シートの中の幅 288px
   ⚠ ロゴは 28px = 丸の半分 (Instagram の「ロゴの半分の余白」、Threads の「幅の 1/4 の余白」を丸の中で守る) */
.c-sh-row { display: flex; flex-wrap: wrap; gap: 16px; padding: 4px 0 8px; }
.c-sh-btn { display: inline-flex; align-items: center; justify-content: center; width: 56px; height: 56px; padding: 0; margin: 0; border: 0; border-radius: 50%; background: var(--sh-disc); color: var(--sh-mark); cursor: pointer; flex-shrink: 0; }
.c-sh-btn:active { opacity: 0.7; }
.c-sh-btn[aria-busy="true"] { opacity: 0.4; cursor: progress; }   /* Instagram: ストーリーズ用の絵を読んでいる間 */
.c-sh-logo { width: 28px; height: 28px; display: block; }
.c-sh-btn .c-sh-ico { width: 26px; height: 26px; }

/* ===== 第88便 (2026-09-30): Meet の出会い方の切り替え (People / Covers) と Covers (ジャケ買い) =====
   切り替え = 文字 + 選んでいる方に下線 (黒・2px)。丸いチップ (.seg) にはしない (DOPP でチップは「押すと別の場所へ飛ぶもの」)。
     増えても 1 行のまま横にスクロール (スクロールバーは隠す)。赤い下線の .tab-btn とも別物
   Covers = 正方形のジャケットを 3 列・隙間 2px で左右いっぱい (.main の左右 16px を負の margin で打ち消す)。文字は出さない */
/* ⚠ 下の細い線は border ではなく内側の影で描く。.mv は横スクロールの箱なので、border にするとボタンの下線が線の上に重ならず 1px 切れる (押せる高さが 43px になった) */
.mv { display: flex; gap: 16px; margin: 0 -16px; padding: 0 16px; overflow-x: auto; overflow-y: hidden; box-shadow: inset 0 -1px 0 var(--line); scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.mv::-webkit-scrollbar { display: none; }
.mv-btn { flex: 0 0 auto; height: var(--tap); min-width: var(--tap); padding: 0 4px; background: none; border: 0; border-bottom: 2px solid transparent; color: var(--muted); font: inherit; font-size: 15px; font-weight: 600; white-space: nowrap; cursor: pointer; }
.mv-btn[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--ink); }
/* 第103便 (2026-10-05): Home の切り替えの「♥ to ♡」= 名前の中に絵 (D.icon の heartFill と heart)。
   DOPP の svg は display: block で大きさを持たないので、置き場所ごとに大きさを書く決まり。並べ方と大きさだけをここに書く。
   色・下線・高さ 44px・文字は上の .mv-btn のまま (絵は currentColor = 選んでいない時は灰色、選んだ時は黒。暗い画面も同じ名前で入れ替わる) */
.mv-btn.mv-ic { display: inline-flex; align-items: center; gap: 4px; }
.mv-btn .ico { width: 16px; height: 16px; flex-shrink: 0; }
/* 第103便の直し: ♥ to ♡ の説明 (見出しの下と、1 曲も無い時の中央ぞろえ) は、幅が足りない時だけ意味の切れ目で折る。
   index.html が切れ目の前後を <span> に分けて書くので、その中では折らない (折り目は span の間だけ)。文字・色・大きさ・余白は今の .note のまま */
#hv-h2h .note > span { white-space: nowrap; }
.cv-grid { position: relative; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px; margin: 2px -16px 0; }
.cv-tile { position: relative; min-width: 0; }
.cv-cover { position: relative; display: block; width: 100%; aspect-ratio: 1 / 1; padding: 0; border: 0; background: var(--line); cursor: pointer; overflow: hidden; transition: opacity .2s ease; }
.cv-cover img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* 第93便: 押した 1 枚がその場で 2 列 × 2 段に広がる (.cv-open)。置き場所は people.html が grid-row / grid-column で直接書く。
   他の 1 枚は並び順のまま空いたマスへ詰め直る (DOM の並びは変えない)。動きは people.html の FLIP (transform と opacity だけ)。
   大きさの変わる動きは左上を原点にする (transform-origin)。動いている途中の 1 枚は隣より上に描く (.cv-open / .cv-shrink の z-index) */
.cv-tile { transform-origin: 0 0; }
.cv-tile.cv-open, .cv-tile.cv-shrink { z-index: 1; }
/* ▶ は大きくした 1 枚の真ん中 (今の 48px の黒い丸と進行の輪)。押せるのは 1 枚そのもの (押すと閉じる) なので、丸は押せない飾り */
.cv-ring { position: absolute; left: 50%; top: 50%; margin: -24px 0 0 -24px; pointer-events: none; }
.cv-cover.playing .cv-ring .ico-play { display: none; }
.cv-cover.playing .cv-ring .ico-pause { display: block; }
.cv-cover.playing .cv-ring .ring circle { opacity: 1; }
/* ♥ ⊕ = 右下の内側 8px に白い丸 2 つ。白 (--on-fill) と黒い絵 (--rec) は暗い画面でも同じ = どんなジャケットの上でも同じ見え方。
   見た目 40px・押せる範囲は ::after で 44px (隣の丸と重ならない: 間 8px > 2 + 2) */
.cv-acts { position: absolute; right: 8px; bottom: 8px; display: flex; gap: 8px; }
.cv-act { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%; background: var(--on-fill); color: var(--rec); box-shadow: 0 2px 8px var(--shadow-mini); cursor: pointer; }
.cv-act::after { content: ""; position: absolute; inset: -2px; border-radius: 50%; }
.cv-act .ico { width: 22px; height: 22px; }
.cv-act.on { color: var(--accent-fixed); }   /* 白い丸の上の赤 (暗い画面でも同じ。白の上 5.87:1)。--accent-text は暗い画面で薄くなる */
@media (prefers-reduced-motion: reduce) { .cv-cover { transition: none; } }
.cv-empty { margin: 32px 0; text-align: center; color: var(--muted); font-size: 15px; }
/* 第90便: Covers の見出し (s551) は Step outside と同じ部品。余白は上の #outside .section-head の行に並べてある。
   第98便: 見出しの右の Shuffle は外した (一番下の #cv-shuffle だけ)。日本語「ジャケットデザインで選ぶ」は 320px でも 1 行なので、第93便の折り方 (keep-all) も外した */
.cv-more { display: flex; justify-content: center; margin: 16px 0 8px; }

/* 第110便B: Meet の For You (1 曲ずつ)。見本 (docs/見本_第110便/) の形。部品は fy- で始める
   ・ジャケットは正方形・角丸 16px。縦が足りない画面 (320×568) では高さに合わせて小さくなる (100svh − 360px)
   ・♥ ⊕ は Covers の白い丸 (.cv-acts / .cv-act) をそのまま右下に
   ・badge.svg は高さ 40px のまま (縮めない)。周りに 4px の空き (.fy-badge の padding) = 本人の確認 2
   ・.fy-stage (ジャケット・進み具合・曲名) の上でなぞると次 / 前 (touch-action: none = 画面は動かない・引っぱって再読み込みにならない) */
.fy { display: flex; flex-direction: column; padding-top: 16px; }
.fy[hidden] { display: none; }
.fy-stage { touch-action: none; }
.fy-art { position: relative; width: min(100%, calc(100svh - 360px)); aspect-ratio: 1; margin: 0 auto; border-radius: 16px; overflow: hidden; background: var(--line); }
.fy-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.fy-img:not([src]) { visibility: hidden; }
.fy-tap { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; padding: 0; border: 0; background: transparent; cursor: pointer; }
.fy-start { position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; background: var(--scrim); color: var(--on-fill); font-weight: 600; font-size: 15px; pointer-events: none; }
.fy-disc { width: 56px; height: 56px; border-radius: 50%; background: var(--rec); display: flex; align-items: center; justify-content: center; color: var(--on-fill); box-shadow: 0 2px 8px var(--shadow-mini); }
.fy-disc .ico { width: 26px; height: 26px; margin-left: 3px; }
.fy-art .cv-acts { z-index: 3; }
.fy-bar { height: 3px; border-radius: 2px; background: var(--line); margin: 10px auto 0; width: min(100%, calc(100svh - 360px)); overflow: hidden; }
.fy-bar i { display: block; height: 100%; width: 0; color: var(--ink); background: currentColor; }   /* 進み具合の線は文字と同じ色 (暗い画面では白)。文字の載る黒い塗りではないので --fill-ink は使わない */
.fy-bar.off { visibility: hidden; }
.fy-info { width: 100%; margin: 10px auto 0; min-width: 0; }
.fy-title { font-size: 20px; font-weight: 700; line-height: 1.3; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-height: 26px; }
.fy-artist { font-size: 15px; line-height: 1.4; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-height: 21px; }
.fy-row { width: 100%; margin: 8px auto 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 48px; }
.fy-badge { display: inline-flex; padding: 4px; margin-left: -4px; align-items: center; }
.fy-badge[hidden] { display: none; }
.fy-badge img { display: block; height: 40px; width: auto; }
.fy-next { flex-shrink: 0; white-space: nowrap; display: inline-flex; align-items: center; gap: 6px; margin-left: auto; }
.fy-next .ico { width: 18px; height: 18px; }
.fy .credit { margin: 10px 0 0; }
.fy-msg { text-align: center; margin: 16px 0 0; }
.fy.fy-wait .fy-stage, .fy.fy-wait .fy-row, .fy.fy-broken .fy-stage, .fy.fy-broken .fy-row { visibility: hidden; }
.fy.fy-broken .fy-stage, .fy.fy-broken .fy-row { display: none; }
.fy.fy-broken .fy-help { display: none; }
/* 第110便C: なぞる操作の案内・好みの 1 行 (ジャケットの上の端。枠・丸・影の札にしない = 押せそうに見せない。押せない)・曲が替わる時の滑り・右上の ? */
.fy { position: relative; }
.fy-hint { position: absolute; left: 0; right: 0; top: 0; z-index: 3; pointer-events: none; display: flex; align-items: center; justify-content: center; gap: 6px; padding: 14px 16px 36px; color: var(--on-fill); font-size: 13px; font-weight: 600; line-height: 1.4; text-align: center; background: linear-gradient(to bottom, var(--scrim), transparent); text-shadow: 0 1px 2px var(--shadow-mini); opacity: 0; visibility: hidden; transition: opacity .25s ease, visibility 0s linear .25s; }
.fy-hint.fy-on { opacity: 1; visibility: visible; transition: opacity .25s ease; }
.fy-hint .ico { width: 16px; height: 16px; flex-shrink: 0; }
.fy-old { position: absolute; inset: 0; }
.fy-peek { position: absolute; left: 0; top: 100%; width: 100%; height: 100%; object-fit: cover; }   /* 第125便: すき間 0 (前は 8px。iPhone で白い線に見えた) */
.fy-peek.fy-prev { top: auto; bottom: 100%; }   /* 第123便: 下へなぞる間に見える前の曲 (上側) */
.fy-pre { position: absolute; left: 0; top: 100%; width: 100%; height: 100%; object-fit: cover; visibility: hidden; pointer-events: none; }   /* 第127便: 先に作っておく次の曲ののぞく絵 (なぞり始めで .fy-peek に替える) */
.fy-pre.fy-prev { top: auto; bottom: 100%; }
.fy-help { position: absolute; top: -44px; right: -11px; color: var(--muted); }   /* 切り替えの行の右端 (For You を見ている間だけ) */
/* 第110便G: ? の吹き出し (1 行。? の真下・右端は .fy の右端にそろえる・上向きの三角が ? を指す。色は吹き出し .toast と同じ) */
.fy-tip { position: absolute; top: 6px; right: 0; z-index: 6; width: max-content; max-width: calc(100vw - 32px); padding: 8px 12px; border-radius: 10px; background: var(--fill-ink); color: var(--on-ink); font-size: 13px; font-weight: 600; line-height: 1.5; box-shadow: 0 6px 18px var(--shadow); }
.fy-tip::before { content: ''; position: absolute; top: -6px; right: 5px; border: 6px solid transparent; border-top: 0; border-bottom-color: var(--fill-ink); }
@media (prefers-reduced-motion: reduce) { .fy-hint, .fy-hint.fy-on { transition: none; } }
/* 第112便B3: 運営の端末だけ「なぜ」(? の左) と内訳の吹き出し (? の吹き出しと同じ色。横いっぱい・長ければ中でスクロール) */
.fy-why { position: absolute; top: -44px; right: 33px; color: var(--muted); font-size: 13px; font-weight: 700; }
.fy-why-t { width: calc(100vw - 32px); max-width: 398px; max-height: 60vh; overflow-y: auto; font-weight: 400; }
.fy-why-t::before { right: 49px; }
@media (max-width: 359px) { .fy-why { top: 0; right: -11px; z-index: 5; } .fy-why-t { top: 50px; } .fy-why-t::before { right: 5px; } }   /* 320px は切り替えのタブで ? の左が埋まる = ? の真下 (ジャケットの右上の角) に置く */
.fy-why-tb { width: 100%; margin-top: 6px; border-collapse: collapse; }
.fy-why-tb th, .fy-why-tb td { padding: 3px 4px; text-align: left; vertical-align: top; border-top: 1px solid var(--line); font-weight: 600; }
/* 第110便D: ジャケットは画面の幅いっぱい (左右の余白 0・角丸なし)。大きさ --fy-size と上の余白 --fy-pad は foryou.js の layout() が測って入れる
   (縦が足りない端末だけ縮める / 縦が余る端末はジャケット〜iTunes の 1 行を縦の真ん中に)。♥ ⊕ はバッジの右 (44px・間 8px)。「次へ」は .sr-only */
.fy { padding-top: 8px; }
.fy-stage { margin: var(--fy-pad, 0px) -16px 0; }
.fy-art, .fy-bar { width: var(--fy-size, 100%); border-radius: 0; }
.fy-bar { margin-top: 0; }
.fy-info { width: auto; margin-top: 8px; padding: 0 16px; }
.fy-title { font-size: 17px; line-height: 1.3; min-height: 22px; }
.fy-artist { font-size: 14px; line-height: 1.35; min-height: 19px; }
.fy-row { margin-top: 4px; gap: 8px; min-height: 44px; }
.fy-badge img { height: 32px; }
.fy-acts { display: flex; gap: 8px; margin-left: auto; flex-shrink: 0; position: relative; }   /* C (0100): 👎 の 2 択 (.menu) の基準 */
/* C (0100): 👎 の 2 択。白いカード (角丸 16px = 大きい箱) に、今ある .btn .btn-ghost を 2 つ縦に並べる (⚠ class は .menu にしない = picks.js の closeMenus が消すため) */
.fy-nmenu { position: absolute; right: 0; bottom: calc(100% + 4px); z-index: 5; display: flex; flex-direction: column; gap: 8px; padding: 8px; min-width: 200px; background: var(--card); border: 1px solid var(--line); border-radius: 16px; box-shadow: 0 8px 24px var(--shadow); }
.fy-nmenu > button { white-space: nowrap; }
.fy-acts .cv-acts { position: static; display: flex; gap: 8px; }
.fy-acts .cv-act { width: 44px; height: 44px; border: 1px solid var(--line); background: var(--card); color: var(--ink); box-shadow: none; }
.fy-acts .cv-act.on { color: var(--accent-text); }
.fy .credit { margin-top: 4px; }
/* 第110便E: 本当の画像が届くまで、Apple の 100px の画像をぼかして出す (foryou.js の showArt) */
.fy-img.fy-blur { filter: blur(12px); }
/* 第124便: 曲が替わる時、前の曲名・アーティストの写しを同じ場所に重ねて薄く消す (foryou.js の setText。位置は動かさない) */
.fy-info { position: relative; }
.fy-ghost { position: absolute; inset: 0; padding: inherit; pointer-events: none; }
/* 第110便F: 👎 の「元に戻す」(ジャケットの左下の内側 8px・3 秒だけ。押せる高さは ::after で 44px = 枠線 1px の分だけ -5) / 👎 の 1 行の折れ目 / 文の中の絵 (文字の大きさ) */
.fy-undo { position: absolute; left: 8px; bottom: 8px; z-index: 4; height: 36px; padding: 0 14px; border-radius: 18px; border: 1px solid var(--line); background: var(--card); color: var(--ink); font: inherit; font-size: 14px; font-weight: 600; }
.fy-undo::after { content: ''; position: absolute; inset: -5px 0; }
.fy-nw { white-space: nowrap; }
.ico.ico-t { display: inline-block; width: 1em; height: 1em; margin: 0; vertical-align: -0.14em; }
/* 第129便B: For You の下書きのカード。2×2 (/c/ の .c-grid) を枠いっぱいに・見出しは曲名の場所 (小さく灰色 + Beta)・題名はアーティストの場所 (高さは曲と同じ = 枠が跳ばない)・ボタンはバッジと 👎♥⊕ の場所 */
.fy-art .c-grid { width: 100%; height: 100%; border-radius: 0; }
.fy-cgrid { position: absolute; inset: 0; }
/* 第131便B: For You のカードの起点の 1 行 = 2×2 の下の端 (2×2 と一緒に動く・格子のマスは取らない)。字は白・下から薄い暗いぼかし (.fy-hint と同じ作り) */
.fy-cfrom { position: absolute; left: 0; right: 0; bottom: 0; margin: 0; padding: 28px 12px 10px; color: var(--on-fill); font-weight: 600; background: linear-gradient(to top, var(--scrim), transparent); text-shadow: 0 1px 2px var(--shadow-mini); pointer-events: none; }
.fy-title.fy-kick { font-size: 13px; font-weight: 600; color: var(--muted); }
.fy-artist.fy-ctitle { font-size: 16px; line-height: 19px; font-weight: 700; color: var(--ink); }
/* 第132便C: 理由の 1 行 (経路の曲・high だけ・英語)。会員だけ置き、行の高さは空でも取っておく (曲ごとにジャケットの大きさが変わらないように) */
.fy-reason { font-size: 13px; line-height: 18px; min-height: 18px; margin-top: 2px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 便2a (0111): 理由の 1 行の名前 (関係のある人の Picks)。押せる高さは見えない .fy-by-hit で 44px (上へ 22px・下へ 4px = 下のバッジと 👎♥⊕ の行に掛からない) */
.fy-by { color: var(--ink); font-weight: 600; text-decoration: none; }
.fy-by-hit { position: absolute; left: 16px; right: 16px; bottom: -4px; height: 44px; z-index: 1; }
.fy-seed { position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 3; white-space: nowrap; background: var(--card); color: var(--ink); border: 0; box-shadow: 0 2px 8px var(--shadow-mini); }
/* 便2 (0103): この曲の近くを掘る。横になぞる間の行き先の絵 (右 = 枠の右側 / .fy-xl = 左側) ・掘っている間の札 (ジャケットの左上) ・近い曲が尽きた印 (2 段の山形。押せない) */
.fy-xpeek { position: absolute; top: 0; left: 100%; width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
.fy-xpeek.fy-xl { left: auto; right: 100%; }
.fy-pill { position: absolute; left: 8px; top: 8px; z-index: 4; display: inline-flex; align-items: center; gap: 4px; max-width: calc(100% - 16px); height: 28px; padding: 0 12px 0 8px; border-radius: 14px; background: var(--fill-ink); color: var(--on-ink); font-size: 13px; font-weight: 600; box-shadow: 0 1px 3px var(--shadow-mini); pointer-events: none; }
.fy-pill > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fy-pill .ico { width: 16px; height: 16px; flex-shrink: 0; }
.fy-lend { position: absolute; left: 50%; bottom: 20px; z-index: 3; width: 56px; height: 56px; margin-left: -28px; color: var(--on-fill); opacity: .55; filter: drop-shadow(0 1px 2px var(--shadow-mini)); pointer-events: none; animation: fy-bob 1.6s ease-in-out infinite; }
.fy-lend svg { display: block; width: 56px; height: 56px; }
@keyframes fy-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(8px); } }
@media (prefers-reduced-motion: reduce) { .fy-lend { animation: none; } }
.fy-cbtns { display: flex; align-items: center; gap: 12px; min-width: 0; }
.fy.fy-oncard .fy-why, .fy.fy-oncard .fy-why-t { display: none; }

/* ===== ダークモード (2026-09-22、第55便。端末の設定に合わせるだけ。切り替えボタンは無い) =====
   明るい画面の値は上の :root のまま。ここは暗い画面の時だけ名前の中身を入れ替える
   - 赤は 2 色: ボタンの地 --accent は明るい画面と同じ (白い文字 5.87:1) / 赤い文字 --accent-text は #EC7458 (カードの上 5.86:1)
   - 黒く塗った部品 (Following・再生中のバー・吹き出し) は白く反転させず、暗い灰色 --fill-ink + 白い文字のまま
   - レコード盤は黒のまま。外周に 1px の灰色の線 --rec-rim (明るい画面では透明)
   - 古い赤の残骸 (--accent-a06 など) は、暗い画面では文字の赤から作った値にしてある
   足したら node tests/fn_dark_mode.mjs */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #121211; --card: #1C1C1A; --ink: #EDEDE8; --muted: #A3A29B; --line: #34342F;
    --accent: #B7371C; --accent-dark: #9E2F17; --accent-text: #EC7458;
    --accent-fixed: #B7371C;   /* 第93便: 白い丸 (--on-fill) の上の赤。明るい画面と同じ (白の上 5.87:1) */
    --fill-ink: #3A3A36; --on-ink: #fff; --ink-press: #4A4A45;
    --on-fill: #fff;
    --press: rgba(255,255,255,0.08); --scrim: rgba(0,0,0,0.6);
    --shadow: rgba(0,0,0,0.5); --shadow-knob: rgba(0,0,0,0.5); --shadow-mini: rgba(0,0,0,0.5); --shadow-drag: rgba(0,0,0,0.6);
    --bg-clear: rgba(18,18,17,0);
    --on-dark-2: rgba(255,255,255,0.65); --on-dark-press: rgba(255,255,255,0.8); --on-dark-line: rgba(255,255,255,0.18);
    --ok: #5FBF9F; --ok-bg: #1E2B25; --ok-ink: #CFE8DA; --err-bg: #3A221C; --err-text: #EC7458; --placeholder: #7C7B74;
    --rec: #181817; --rec-groove: #3A3A38; --rec-rim: #4A4A45;
    --accent-a06: rgba(236,116,88,0.10); --accent-a07: rgba(236,116,88,0.12);
    --accent-a50: rgba(236,116,88,0.5); --accent-a00: rgba(236,116,88,0);
    --brand-dot: #EC7458;
    --sh-disc: #EDEDE8; --sh-mark: #121211;   /* 第96便: 反転 (明るい丸に暗いロゴ) */
  }
}
