/* The components shared by more than one view.
 *
 * Frozen after Batch 0 (ARCHITECTURE §4.3): anything that belongs to a single
 * view goes in views/<name>.css instead, so two parallel tasks never edit the
 * same stylesheet. If a rule here is only used by one section, it is in the
 * wrong file.
 *
 * **Token 不在這裡了 — #259。** 顏色、陰影、圓角、字型堆疊搬進 web/themes.css,
 * 一個主題一塊,契約清單寫在那一支的檔頭。這裡剩下的是形狀:哪一個東西是圓角
 * 卡、哪一顆鈕是藥丸 —— 而「圓角多圓」由主題答。加一個主題不必碰這一支;改這一支
 * 的一條規則也不會動到任何一個主題。 */

* { box-sizing: border-box; }
/* 底色要畫在 html,不只 body — #352(D-F90)。安卓 15 起系統列透明、Chrome 135 起
   裝成 app 的網頁延伸到狀態列與導覽列底下,那兩塊露出來的是**畫布(html)**的底色:
   只設 body 的話,畫面是深色、上下兩條卻是白的(2026-09-05 使用者截圖)。 */
html { background: var(--bg); }
/* **底紋是 `background` 的第一層,不是一個 `::before`** — #392。負 z-index 的偽元
   素在繪製順序上排在**這一格自己的底色前面**(root 背景 → 負 z 子層 → 區塊層級後
   代的背景),所以 `body::before` 那一版會被 `background: var(--bg)` 整片蓋掉 ——
   實測看不到任何底紋。兩層寫在同一句話裡沒有這個問題:顏色一定是最後一層,而
   `--bg-deco` 在不畫底紋的主題上是 `none`(一個合法的 <image>)。 */
body {
  margin: 0; background: var(--bg-deco), var(--bg); color: var(--ink);
  /* 15px,而 root 由 web/prefs.css 釘在 16 — #360。速記法裡的字級與那 190 條
     `font-size` 是同一件事:少換這一個,整份文件的**基準**就不跟著字級偏好走,
     而它正是最多元素繼承到的那一個。 */
  font: .9375rem/1.5 var(--font-body);
  -webkit-font-smoothing: antialiased;
}
/* 底下留白 = 導覽列 + FAB 那一疊 — #201。原本是 96px(只讓過 nav);FAB 停在
   nav 上緣再高 56px,捲到底時最後一行字會落在它底下。 */
.wrap { max-width: 520px; margin: 0 auto; padding: 0 16px 152px; }
/* 標題列讓開瀏海 — #350(D-F88)。`apple-mobile-web-app-status-bar-style` 從這一
   票起是 `black-translucent`(index.html 那一段寫著為什麼),而那個值的代價就是
   **內容從 y = 0 開始畫** —— 少了這一道,裝成 app 的 iPhone 上左上角的頁名與右上
   角的鈴鐺會躺在時間與電量底下。

   加在 padding-top 上而不是 margin:`env()` 在讀不到的環境(桌面瀏覽器、Android、
   `viewport-fit=cover` 沒寫的頁面)是 0,所以 `calc(18px + 0px)` 逐像素等於原本
   那一行 —— 這一道對其他每一台裝置都不存在。**它與 nav 的
   `env(safe-area-inset-bottom)` 是同一件事的兩端**(那一行從 #201 起就在)。 */
header {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: calc(18px + env(safe-area-inset-top)) 0 14px;
}
.brand { font-family: var(--font-heading); font-weight: 650; letter-spacing: -.01em; }
/* 那一格裝的是一個控制,不是一句字 — D-F105(#393,nav.js 的 titleControl())。
   `.brand` 的字體與字級留著沒有意義也沒有害處(底下那組 seg 自己說了它要多大),
   這一條只負責讓那一格不再是一段文字流:少了它,`<span>` 裡的那個 `<div>` 靠行高
   撐高,而 seg 的 44 是它自己的 `min-height` 給的。 */
.brand.hd-ctl { display: flex; align-items: center; min-width: 0; }
.hd-left { display: flex; align-items: center; gap: 6px; min-width: 0; }
.hdr-back {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  cursor: pointer; padding: 0;
  color: var(--ink); background: none; border: 0;
  border-radius: var(--radius-pill);
}
.hd-icon {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  cursor: pointer; padding: 0;
  color: var(--ink); background: var(--chip);
  border: 1px solid var(--line); border-radius: var(--radius-pill);
}
/* 右上角那一組:換帳戶的下拉 + 通知鈴鐺 — #201。**它們得是同一個子節點**,
   否則 header 的 space-between 會把三個直接子節點拆成左中右,下拉飄到正中間。

   `flex: 1` + 靠右對齊,兩個都是量出來的(390 寬實測):少了靠右對齊,下拉的
   `max-width: 60%` 剩下的那 12.4px 會留在**右邊**,鈴鐺因此離螢幕邊 28.4px 而
   不是與內容切齊的 16px;少了 `flex: 1`,那個 60% 是「這一組」的 60%(93.6px)
   而不是 header 剩下那一段的(161px),長一點的帳戶名會提早被截掉。 */
.hd-right {
  flex: 1; display: flex; align-items: center; justify-content: flex-end;
  gap: 10px; min-width: 0;
}
/* 切換器那一格:一句固定的字 + 那顆鈕 — D-F94(#356)。使用者原話 2026-09-06:
   「快速切換按鈕左邊加『當前帳本:』字樣」,理由是那顆藥丸上只有一個帳本名,
   而一個名字說不出它是一顆做什麼的鈕。**那句字從 D-F105(#393)起是「帳本:」**
   ——記帳頁的頁首同時裝著返回鈕與模式 seg,320 寬那一列擠不下四個字(字面值與
   為什麼在 nav.js 的 `POOL_LAB`)。

   **兩樣東西住在同一個容器裡**,因為 paint() 是整格一起收的(`#poolPick` 的
   `.hide`):標籤留在外面的話,帳本管理頁與每一個子頁上會剩下一句沒有主詞的
   「帳本:」。字本身由 render() 畫進去(它同時是那顆鈕的 `aria-labelledby`
   ——讀屏唸的是「帳本: 微咪家用」,而不是把值蓋掉的一句「切換帳本」)。

   **用 class 不用 `#poolPick`**:`display` 寫在 id 選擇器上就再也收不起來了
   (`.hide` 是單一 class,而這個 repo 的特異度地雷踩過六次)。 */
.hd-pool { display: flex; align-items: center; gap: 6px; min-width: 0; }
.pick-lab { flex: none; font-size: 0.75rem; color: var(--dim); white-space: nowrap; }
/* 原生 `<select>` 的那條規則在 #233 拿掉了 —— #229 盤點表上剩下的兩顆(關帳分配
   政策 `#npClose`、更新餘額那張卡的 `#bkWho`)那一票一起換成了底下的 `.pick`,
   全站因此一顆 `<select>` 都不剩,規則沒有東西可以套。**留著才是危險的**:它的
   `max-width: 60%` 正是 390 上把「各自拿回入金,消耗按分配權重分攤」截成半句話
   的那一條,而一條沒有人套得到的規則會讓下一個人以為原生下拉還是這個 app 的
   選項之一。 */

/* ------------------------------------------- 自訂下拉選單 `.pick` — #229

   元件本身、它的三個呼叫端與那筆「放棄了什麼」的帳,寫在 web/picker.js 的檔頭。
   規則住在這裡而不是某一支 views/*.css,判準是這個檔案自己開頭那一句:只有一個
   section 用得到的規則放在這裡就是放錯地方 —— 而這一組有三個(右上角的切換器在
   header 上、建帳戶表單在 #v-me、月份在 #v-log)。

   **收合面的高度跟著呼叫端走**,不在這裡寫死:右上角那顆要和鈴鐺切齊(40px,
   style.css 底下 `.bell` 那一條當年量的),月份那顆站在一排 26px 的籤中間。

   ⚠️ **「真正要按的目標是紙上的選項,收合面不必 44」那句話在 D-F100(#373)被推
   翻了。** 收合面自己就是一顆要按的鈕 —— 不按它,紙根本不會出現。#370 在九種尺
   寸上量到它 37–42px 高(`#poolSwitch`),而使用者裁的是「全站觸控目標一律
   ≥44×44」,沒有「它只是入口」這個例外。padding 一格都沒動:44 由 `min-height`
   給,字仍然置中(`<button>` 自己會置中它的內容),所以短名字的那一顆看起來只是
   高了幾個像素,不是變成一顆大方塊。 */
.pick { min-width: 0; }
.pick-cur {
  display: inline-flex; align-items: center; justify-content: space-between;
  gap: 6px; max-width: 100%; min-height: 44px;
  font: inherit; color: var(--ink); background: var(--chip); cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius-pill); padding: 6px 12px;
}
/* 名字長就截斷,不換行也不把旁邊的東西擠出去 —— 收合面唯一要答的問題是「現在
   選的是哪一個」,而那句話的開頭比結尾重要。 */
.pick-now { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick-caret { flex: none; font-size: 0.625rem; font-style: normal; color: var(--dim); }
.pick[data-open] .pick-cur { color: var(--accent); border-color: var(--accent); }
/* 收合面自己的焦點框。瀏覽器本來就會畫一個(它是一顆真的 `<button>`),換成 accent
   只是為了讓它和紙上那一圈是同一種東西 —— 390 實測(sandbox,2026-08-23)選完之後
   焦點會回到這顆鈕上,而那一圈預設是藍的,在一張綠色的卡上讀起來像另一個系統的
   東西。 */
.pick-cur:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* **開合走 `data-open`,不走 `.hide`** —— `.hide` 是單一 class,而 view 的 css 後
   掛進 <head>,任何一條 `.pick-sheet { display: … }` 都會把它蓋掉(.bk-dot /
   .bal-sheet 踩過的坑)。這裡兩邊都是自己寫的:預設 `display: none`,`.pick[data-open]`
   那條 (0,2,0) 壓得過它。 */
.pick-scrim, .pick-sheet { display: none; }
.pick[data-open] .pick-scrim { display: block; }
/* 紙的版面抄 `.asheet`(#202)與 `.bal-sheet`(#216):離 nav 8px、左右各 8px、
   卡片底、圓角、往上 16px 的彈出。z-index 蓋過整個底部 chrome(nav 22、FAB 21),
   仍然在登入閘(auth.css 的 30)之下。

   **動畫掛在 `[data-open]` 上而不是靜態規則上**:紙不是每次開都重新造出來的節點
   (整段 HTML 由呼叫端一次畫好),`display: none → block` 那一刻動畫才會重跑 ——
   形狀同 home.css 的 `#flow .fl-why:not(.hide)`。.2s 落在 150–300ms 裡。 */
.pick[data-open] .pick-sheet {
  display: block; animation: pick-up .2s cubic-bezier(.2, .8, .3, 1);
}
.pick-scrim { position: fixed; inset: 0; z-index: 24; background: var(--scrim); }
.pick-sheet {
  position: fixed; left: 8px; right: 8px; z-index: 25;
  bottom: calc(var(--navh, 68px) + 8px);
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius-l); padding: 12px 16px 4px; box-shadow: var(--shadow);
}
@keyframes pick-up { from { opacity: 0; transform: translateY(16px); } }
@media (prefers-reduced-motion: reduce) { .pick[data-open] .pick-sheet { animation: none; } }
/* 紙彈在畫面底部,離被按的那顆鈕很遠 —— 它要自己說得出「這是哪一格」(同 .atitle
   與 .bal-sheet-t 的理由)。 */
.pick-head { padding-bottom: 10px; border-bottom: 1px solid var(--line); }
/* 長清單自己捲,紙不會長到蓋住整個畫面。52vh:390×844 上是 439px,剛好放得下
   八列 44px 的選項,而紙的頂端仍然離狀態列很遠。 */
.pick-list { max-height: 52vh; overflow-y: auto; }
.pick-grp + .pick-grp { border-top: 1px solid var(--line); }
.pick-ghd { padding: 12px 0 2px; font-size: 0.75rem; letter-spacing: .02em; color: var(--dim); }
/* 一列一個選項。44px 是點擊目標的下限,而說明那一行(建帳戶表單上每一種帳本的
   一句話)長在名字底下,不是取代它 —— 同 `.awhy` 的排法。 */
.pick-opt {
  display: flex; flex-direction: column; justify-content: center; gap: 2px;
  min-height: 44px; padding: 10px 0; cursor: pointer;
  border-bottom: 1px solid var(--line);
}
.pick-grp:last-child .pick-opt:last-child { border-bottom: 0; }
.pick-opt b { font-weight: 600; }
.pick-opt[aria-selected="true"] { color: var(--accent); }
/* 選中那一列右邊那顆勾 — #392。它以前是 `content: " ✓"`(一個 Dingbats 字元,
   字體說了算),而 `content` 畫不出 SVG:換成 icon 集之後那顆勾由 picker.js 一律
   印出來,**這裡決定哪一列看得到它** —— 一條規則,而不是兩種標記。 */
.pick-opt > .ic { margin-left: 6px; color: var(--accent); }
.pick-opt:not([aria-selected="true"]) > .ic { visibility: hidden; }
/* 鍵盤走到哪裡要看得見。**只在 :focus-visible 上畫**:用手指點開的人不需要一個
   跟著他的手指跑的方框,而他要的那一格已經有 ✓ 與 accent 色在說話。 */
.pick-opt:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; border-radius: var(--radius-s); }
.pick-note { font-size: 0.78125rem; color: var(--dim); line-height: 1.5; }

/* ---- 從按鈕往下長的那一種 `.pick[data-drop]` — D-F98(#356)-----------------

   使用者原話 2026-09-06:「快速切換選單從上往下長」。上面那張紙彈在畫面底部,
   而它是為了**拇指**(#229 的取捨:390 上浮在觸發鈕底下的清單有一半落在拇指伸
   不到的地方)。這一顆的答案反過來,理由也反過來:切換帳本要看的是「我現在在
   哪一本、旁邊還有哪幾本」,而那個問題的上下文就是那顆寫著現在這一本帳的鈕 ——
   一張從螢幕底部升起來的紙把答案搬到離問題最遠的地方。

   **只有這一顆換,另外兩顆(建帳本的型態、紀錄頁的月份)一個字都沒動**:它們是
   表單裡的欄位,站在畫面中段,底部彈出對它們仍然是對的。所以形狀是一個選項而
   不是一次改寫。

   四件事:
     position     基準是 `.pick` 自己(收合面就在它裡面),所以紙貼著鈕的下緣長。
     right: 0     靠鈕的**右緣**對齊 —— 那顆鈕站在標題列最右邊,靠左長會掉出螢幕。
     min-width    「寬度對齊按鈕」的下限是那顆鈕本身(`100%`),但一列要裝下型態、
                  帳本名與未讀圈,所以再給一個 15rem 的地板;上限收在 86vw,
                  390 寬的機器上兩邊仍然有邊。

                  ⚠️ **那個 86vw 要除以縮放倍率 — D-F99(#370)。** 字級偏好走的
                  是 `html { zoom }`(web/prefs.css),而**視口單位不跟著縮**:
                  `86vw` 算出來是 86% × 視口寬的 CSS px,再被 zoom 乘一次。實測
                  (Chrome 152、360×740、大字級、帳本名 22 個中文字):紙量到
                  356px 寬(= 98.9vw),而它靠右對齊在 341.6,**左緣落在
                  -14.4** —— 掉出螢幕外面。`var(--zoom, 1)` 由 prefs.css 那兩條
                  規則給,沒有人縮放時是 1,整條算式逐字退回原本的 86vw。

                  ⚠️ **而 86vw 在寬螢幕上是錯的尺 —— 這是 #370 收尾時量到的第二
                  個病。** 這張紙靠的是**那顆鈕的右緣**(`right: 0`),而 552 之
                  後 `.wrap` 就置中了:鈕的右緣停在內容欄的右邊,離視窗右邊還有一
                  段。用視窗寬當上限,紙就從內容欄的左邊長出去 —— 實測(帳本名
                  49 字元的中英混合名):768×1024 上紙寬 660、鈕右緣 628,**左緣
                  -32**;844×390 是 -8,大字級是 -23。
                  真正的上限是**內容欄的內寬**:`.wrap` 是 `max-width: 520px` 加
                  左右各 16px 的 border-box 內距,所以是 488。兩個上限取小的那一
                  個:窄螢幕上 86vw 贏(欄比視窗窄不了),寬螢幕上 488 贏,而紙的
                  左緣因此永遠不會跑到內容欄的左邊外面。
     box-shadow   浮起來的東西要有影子(同 `.card` 用的那一格 token)。 */
.pick[data-drop] { position: relative; }
.pick[data-drop] .pick-sheet {
  position: absolute; top: calc(100% + 6px); bottom: auto; left: auto; right: 0;
  min-width: max(100%, 15rem);
  max-width: min(calc(86vw / var(--zoom, 1)), 488px);
  padding: 4px 14px;
}
/* 往下長的那一張不必自己說「這是哪一格」— 它就貼在那顆鈕底下,而鈕的左邊已經
   寫著「帳本:」。上面那張紙需要標題是因為它離被按的地方很遠。 */
.pick[data-drop] .pick-head { display: none; }
/* 幕留著(點外面關掉、擋住底下那一列的誤觸都靠它),但**不要那層黑**:蓋住整個
   畫面的暗色是「一張紙升起來了」的語彙,而這一張只是從一顆鈕底下長出來的。 */
.pick[data-drop] .pick-scrim { background: transparent; }
.pick[data-drop] .pick-sheet { animation: pick-down .16s cubic-bezier(.2, .8, .3, 1); }
@keyframes pick-down { from { opacity: 0; transform: translateY(-8px); } }
@media (prefers-reduced-motion: reduce) { .pick[data-drop] .pick-sheet { animation: none; } }

/* 一列排成一橫排:**左邊帳本型態、右邊帳本名** — D-F98。有 `tag` 的那一列才切成
   橫的(`.pick-row`),沒有的照舊是上下兩行(名字 + 說明)。 */
.pick-opt.pick-row { flex-direction: row; align-items: center; gap: 10px; }
/* 型態是一個標籤不是一句話:固定的起點讓一整排帳本名對齊成一欄,掃起來比逐列
   找名字的開頭快。`--chip` 底 + `--dim` 字與 `.ghost` 同一種語言(次要資訊)。 */
.pick-tag {
  flex: none; min-width: 62px; text-align: center;
  font-size: 0.71875rem; line-height: 1.6; color: var(--dim);
  background: var(--chip); border-radius: var(--radius-s); padding: 2px 7px;
}
/* 帳本種類 = 一塊顏色,不是四個字 — D-F105(#393)。使用者原話 2026-09-08:
   「(多人分帳)這幾個字藏掉 微咪家用的底色改用多人分帳的顏色」。

   ⚠️ **色塊裡把型態那幾個字寫回去了 — D-F108 ②(#404)。** 使用者實機看完那一版:
   「快速切換選單展開後每列色塊裡要寫帳本名(只有頁首那顆藥丸不寫)」。D-F105 藏
   掉那四個字解的是**收合面**的寬度(320 的頁首同時裝著返回鈕、模式 seg 與這顆
   藥丸),而展開的清單有一整張紙 —— 一塊沒有字的顏色要人先學會四種顏色各代表
   什麼。所以現在**兩個版位是同一種樣子**:淡底 + `--ink` 的字 + 種類色。

   淡底那一半是**量出來的**:`--ink` 站在四個 `-soft` 上的對比在五個主題裡是
   10.9–16.3,而實色底沒有一顆字色站得上去 —— #392 的 token 契約裡沒有
   `--on-ledger-*`,而 `--on-accent`(多半是白)在深色主題的 `--ledger-split`
   (#60A5FA)上只有 2.2。兩組配對都進了 `test_web.EveryThemeMeetsContrast`,而
   這一格接上去的正是已經量過的那一組(不是第五種配對)。

   高度回到 `.pick-tag` 自己的行高(#393 那一行 `height: 18px` 是「裡面沒有東西」
   才需要的);寬度的地板**跟著最長的那個型態走**(「集資資金池」五個字 —— 6.5em
   在這一格的 0.71875rem 上是 74.75px,含左右各 7px 的內距),因為一整排帳本名要
   對齊成一欄,而那正是這一格存在的理由:62px 那個舊地板只裝得下四個字,五個字的
   那一列會自己長長,整欄名字跟著錯開。**用 em 不用 px**:字級偏好放大時這一格與
   它裡面的字要一起長(web/prefs.css 的 zoom 之外還有一條 `font-size` 的路)。
   **型態那幾個字不准換行**:320 寬那張紙只有 275px,折行的標籤會把那一列撐成兩倍
   高,而該讓的是名字那一欄 —— 它自己會截尾(下面 `.pick-opt.pick-row b`)。

   型態那幾個字現在**眼睛與耳朵各有一份**:色塊自己印出來,每一列的 `aria-label`
   照樣唸得出來 —— nav.js 的 poolRows() 那一格寫了為什麼後者不能省。 */
.pick-tag.lt-split, .pick-tag.lt-pool,
.pick-tag.lt-capital, .pick-tag.lt-personal {
  min-width: 6.5em; color: var(--ink); white-space: nowrap;
}
.pick-tag.lt-split { background: var(--ledger-split-soft); }
.pick-tag.lt-pool { background: var(--ledger-pool-soft); }
.pick-tag.lt-capital { background: var(--ledger-capital-soft); }
.pick-tag.lt-personal { background: var(--ledger-personal-soft); }
.pick-cur.lt-split { background: var(--ledger-split-soft); border-color: var(--ledger-split); }
.pick-cur.lt-pool { background: var(--ledger-pool-soft); border-color: var(--ledger-pool); }
.pick-cur.lt-capital { background: var(--ledger-capital-soft); border-color: var(--ledger-capital); }
.pick-cur.lt-personal { background: var(--ledger-personal-soft); border-color: var(--ledger-personal); }
/* 名字吃掉剩下的寬度,長就截斷 —— 同 `.pick-now` 的判準(那句話的開頭比結尾
   重要),而選中的那一列還有 accent 色在說話。 */
.pick-opt.pick-row b { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 每一列右上角那顆未讀圈 — D-F97。**貼上緣不置中**(`align-self`):它是掛在這一
   列上的標記,不是這一列的第三欄。顏色與 nav 上那一顆是同一格 token,兩處講的
   是同一個數字。 */
.pick-badge {
  flex: none; align-self: flex-start;
  min-width: 17px; padding: 0 5px; border-radius: var(--radius-pill);
  background: var(--warn); color: var(--on-warn);
  font-size: 0.65625rem; line-height: 1.0625rem; font-weight: 650; text-align: center;
  font-variant-numeric: tabular-nums;
}

.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius-l); padding: 18px; margin-bottom: 14px; box-shadow: var(--shadow);
}
.label { color: var(--dim); font-size: 0.78125rem; letter-spacing: .02em; }
.big { font-family: var(--font-heading); font-size: 2.375rem; font-weight: 640; letter-spacing: -.025em; margin: 4px 0 2px; }
.big small { font-size: 1rem; font-weight: 450; color: var(--dim); margin-right: 4px; }
.row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.muted { color: var(--dim); font-size: 0.8125rem; }
.num { font-variant-numeric: tabular-nums; }
.warn { color: var(--warn); }
.good { color: var(--accent); }
h3 { font-family: var(--font-heading); font-size: 0.875rem; margin: 0 0 4px; font-weight: 640; }

/* 一列一個人:首頁的狀態列與帳戶頁的成員列共用 */
.who { display: flex; align-items: center; gap: 12px; padding: 13px 0; border-bottom: 1px solid var(--line); }
.who:last-child { border-bottom: 0; }
.who .sw { width: 10px; height: 34px; border-radius: 4px; flex: none; }
.who .id { flex: 1; min-width: 0; }
.who .id b { font-weight: 600; }
.who .id span { display: block; font-size: 0.75rem; color: var(--dim); }
.who .val { text-align: right; white-space: nowrap; }

/* 列右邊那兩個記號 — D-H6(#367)。**同一段 path,轉幾度而已**:`.cv` 指右(「›」
   = 按下去跳到另一頁),`.cv-fold` 轉 90° 指下(「⌄」= 往下展開),而它所在的按鈕
   `aria-expanded="true"` 時再轉成指上(「⌃」)。畫它的那兩支在 `web/icons/chevron.js`。

   ⚠️ **轉向只寫在這裡。** `.fl-more` / `.fl-noteq` / `.ledger-fold` 三處在 #367 之
   前各自有一條「展開時 `.caret` 轉 90°」的規則,而那一層現在轉的是裡面這顆 svg ——
   兩層都轉的下場是 180°(實測:箭頭指回左邊)。那三條因此在同一票裡拿掉,不是留著
   沒人用。

   `width`/`height` 吃 `em`,所以每一個呼叫點仍然靠外面那顆 `.caret` 的 `font-size`
   決定它多大(`.mg-entry .caret` 是 13px、`.fl-noteq .caret` 是 11px…);換成 px 的
   話字級偏好(`data-fsize`)放大整個畫面時,只有這幾顆箭頭不會跟著長。

   `stroke` 走 `currentColor`:顏色仍然由外面那顆 `.caret` 說了算(`--dim`,或危險
   區那一列的 `--warn`),這裡不再有第二個作者。

   動畫 150ms —— 收合那一組的既有值(D-H6 允許省略,而轉向是它唯一動的東西)。 */
.caret .cv {
  display: block; width: 1em; height: 1em;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.caret .cv-fold { transform: rotate(90deg); transition: transform .15s; }
[aria-expanded="true"] .caret .cv-fold { transform: rotate(-90deg); }

label.f { display: block; margin: 14px 0 6px; font-size: 0.78125rem; color: var(--dim); }
/* ⚠️ **`min-height` 的選擇器把核取方塊與單選鈕排除掉了,而這不是潔癖是實測。**
   `min-height` 壓得過 `height`(兩個不同的屬性,不是同一條的兩個值),所以一條
   光禿禿的 `input { min-height: 44px }` 會把 add.css 的 `.share input[type=checkbox]`
   那顆 20px 的方塊拉成 20×44 的長條 —— 那不是「觸控目標變大」,那是畫壞了。

   那兩種自己的 44 不在這裡:它們是「一顆小方塊 + 旁邊一整列可按的字」,而那一整
   列(`.share` 的 label 那一格)本來就高過 44 —— 手指按的是那一列,不是方塊。 */
input {
  font: inherit; color: var(--ink); background: var(--bg); width: 100%;
  border: 1px solid var(--line); border-radius: var(--radius-s); padding: 10px 12px;
}
input:not([type=checkbox]):not([type=radio]) { min-height: 44px; }
.seg { display: flex; flex-wrap: wrap; gap: 8px; }
.seg button {
  font: inherit; color: var(--ink); background: var(--chip); cursor: pointer;
  border: 1px solid transparent; border-radius: var(--radius-pill); padding: 8px 14px;
  min-height: 44px; min-width: 44px;
}
.seg button[aria-pressed="true"] { background: var(--card); border-color: var(--accent); color: var(--accent); font-weight: 600; }
/* 標題列上那一組模式 seg — D-F105(#393)。使用者原話 2026-09-08:「A′-2:seg 直接
   當標題「← 記單筆|記多筆」,帳本切換留右側」。**規則排在 `.seg` 那一組後面而不是
   跟 header 住在一起**:它覆寫的正是上面那三行,而兩者的特異度一模一樣(class +
   屬性 + 型別),先後就是全部的勝負。

   `.seg` 那一組是**表單裡**的:8px 的縫、會換行、每格 14px 內距 —— 三樣在 320 寬
   的頁首上都會爆。量出來的預算(design-themes/FAB-UX.md §3 的像素表,內容區 288):
   返回 44 + 6 + seg(2×51 + 3 = 105)+ header gap 10 + 「帳本:」36 + 6 = 207,
   剩 81px 給藥丸(左右內距 24 + caret 22 + 名字 35,長名字截尾 —— D-F105 第 5 點)。

   **`flex: none` + `nowrap`**:這一列上唯一准縮的是藥丸(`.pick-now` 自己有省略
   號),seg 一縮就掉到 44 以下(D-F100)。 */
.hd-seg { flex: none; flex-wrap: nowrap; gap: 3px; }
.hd-seg button { min-width: 51px; padding: 0 6px; font-size: 0.8125rem; font-weight: 500; }
/* 選中格 = 現在站在哪一頁,而它**用帳本種類那一組色,不是 accent** — D-F105 第 1
   點。頂卡上那一排(支出/收入/退款/轉帳)的選中色是 accent 系,而兩排 seg 在記帳
   頁上下疊在同一個畫面裡;借 `--ledger-pool` 那一格是為了讓「這是模式,不是種類」
   一眼分得開 —— D-H17 第 2 點的「與相機鈕不同色」那句語意,從退役的 `.fab.swap`
   搬到這裡。對比由 `EveryThemeMeetsContrast` 的「共同帳戶籤」那一格守著。 */
.hd-seg button[aria-pressed="true"] {
  background: var(--ledger-pool-soft); border-color: var(--ledger-pool);
  color: var(--ledger-pool); font-weight: 600;
}

.primary {
  font: inherit; font-weight: 600; width: 100%; cursor: pointer; margin-top: 18px;
  background: linear-gradient(135deg, var(--accent-grad-a), var(--accent-grad-b));
  color: var(--on-accent); border: 0; border-radius: var(--radius-m); padding: 13px;
}
.primary:disabled { opacity: .4; cursor: not-allowed; }
/* ⚠️ **44 的下限從 add.css 搬上來了 — D-F100(#373)。** 那一條原本寫在
   `.capout / .caplib / .capback` 上,而它的檔頭當年寫著「44px 的下限寫在這裡而不
   是 `.ghost`:那一條全站共用」—— 意思是「不要為了三顆鈕動全站」。D-F100 把那句
   話的前提換掉了:全站就是要 44,所以下限的位置也跟著換成全站這一層。

   padding 沒動 —— 6px 的上下內距仍然決定這顆藥丸「看起來」多高;44 只在它撐不到
   的時候補進來(13px 的字撐出來大約 30px)。寬度同理:`#acCopyId` 的「複製」兩個
   字本來就 48 寬,`min-width` 對它一格都沒有影響,擋的是只有一個字的那一種。 */
.ghost {
  font: inherit; font-size: 0.8125rem; cursor: pointer; background: transparent; color: var(--dim);
  border: 1px solid var(--line); border-radius: var(--radius-pill); padding: 6px 12px;
  min-height: 44px; min-width: 44px;
}
.ghost.danger { color: var(--danger); }

/* 子畫面的返回鈕 — #136。它是 shell chrome(nav.js 畫的),不屬於任何一個
   view,所以住在這裡而不是某一支 views/*.css:紀錄頁的編輯與共同帳戶頁的
   建立新帳戶(#135)看到的是同一顆。 */

/* ⚠️ **`.bell` 那一組在 D-F97(#358)整段刪掉了。** 使用者原話 2026-09-06:
   「右上角鈴鐺拿掉;通知變成『我的帳號』裡的一個入口」。#201 把通知搬上頭是因為
   底部那一排只有五格而它「要一直看得見」;而「一直看得見」這件事現在由**徽章**
   自己做 —— 它長在「我的帳號」那顆分頁鈕上(底下 `.nbadge`),入口則收進那一頁的
   第一層。一顆按鈕的位子換掉一個紅點,右上角因此只剩「這一頁的操作」。

   徽章的樣式與定位基準跟著搬到這裡 —— **它從 views/notify.css 搬過來,理由與當年
   放在那裡的理由是同一條**:那時候徽章長在通知自己那一頁的入口上(#166 的「更多」
   那一列),拿掉那一頁它就該一起消失;現在它長在 shell 的導覽列上,和 `.fab` /
   `nav` 是同一族 —— 通知那一頁怎麼畫、要不要留,都不改變導覽列上有一顆徽章這件事。 */

/* 導覽列上那顆未讀徽章 — D-F97(#358)。「我的帳號」那一格的右上角,數字由
   nav.js 的 setUnread() 寫(0 就整顆 `hidden`)。

   **定位基準寫在 `nav button` 上,不是在徽章自己身上**:徽章是 absolute,少了
   基準它會跑到最近的一個定位祖先去 —— 那是整個 `nav`,五格的右上角。

   位置不是那顆鈕的角落,是 **icon 的角落**:`right: calc(50% - 22px)` 從那一格
   的中線往右量,而 icon(`nav em`,17px)也是置中的 —— 兩者因此對得上,不管
   那一格有多寬(五格平分,字級放大時一起變)。 */
nav button { position: relative; }
.nbadge {
  position: absolute; top: 3px; right: calc(50% - 22px);
  min-width: 17px; padding: 0 5px; border-radius: var(--radius-pill);
  background: var(--warn); color: var(--on-warn);
  font-size: 0.65625rem; line-height: 1.0625rem; font-weight: 650; text-align: center;
  font-variant-numeric: tabular-nums;
}

/* 記一筆的懸浮鈕 — #201(使用者原話:「右下角、控制 bar 之上的懸浮圓形 + 號」)。

   **位置建在量出來的 nav 高度上**,不是寫死的 px:`--navh` 由 nav.js 的 sizeNav()
   寫在 :root 上(nav 的高度是字級 + `env(safe-area-inset-bottom)` 算出來的),
   16px 那個縫是版面,留在這裡。退路值只在 sizeNav() 跑之前的那一瞬間用得到。

   **z-index 在 nav 之下**:兩者不重疊,而萬一重疊了該被蓋住的是浮的這顆 ——
   導覽列是骨架。它與 auth.css 的 #gate(30)、api.js 的 toast(40)在同一條線上。

   底色是 accent 實心配白字,和 `.primary` 同一種語言:它是這個 app 的主要動作。
   **這不會跟「現在在哪一頁」打架** —— 那個狀態在 nav 上是 accent 色的字,而這顆
   鈕不在 nav 上(站在記一筆那一頁時它拿到 `aria-current`,但沒有一條規則讀它:
   人已經站在那一頁上,浮著的入口不必再喊一次)。 */
.fab {
  position: fixed; right: 16px; bottom: calc(var(--navh, 68px) + 16px); z-index: 21;
  width: 56px; height: 56px; border-radius: var(--radius-pill); border: 0; cursor: pointer;
  font: inherit; font-size: 1.625rem; line-height: 1;
  background: linear-gradient(135deg, var(--accent-grad-a), var(--accent-grad-b));
  color: var(--on-accent);
  box-shadow: var(--shadow-fab);
  transition: transform .18s cubic-bezier(.2, .8, .3, 1), opacity .18s linear;
}
/* 寬螢幕上跟著內容欄收 — #289(QA F19)。`.wrap` 在 520 之後就置中不再變寬,而
   這顆鈕貼的是**視窗**右下角:768 寬實測 `.wrap` 收在 124–644,`#fab` 卻停在
   696–752,飄在內容欄右邊那片空白背景上,和它要作用的那張卡沒有任何視覺關係。

   算式就是版面自己那一條:視窗比內容欄寬多少,兩邊各分一半,再加回原本那 16px
   的縫 —— 所以 390 寬(欄比視窗窄不了)一個像素都不動,768 寬時它落在 628,與
   內容欄右緣的 16px 縫對齊。**門檻 552 = 520 + 兩邊各 16**(`.wrap` 是
   border-box,padding 算在那 520 裡),也就是內容欄開始置中的那一刻。

   **用 `50%` 不用 `50vw`**:`position: fixed` 的百分比算在初始包含區塊上,那是
   **不含捲軸**的視窗;`100vw` 含捲軸,桌機上會把這顆鈕往右推半條捲軸的寬度。

   左邊那一顆(`html[data-fab="left"]`)的同一條在 web/prefs.css —— 那條規則的
   特異度 (0,2,1) 壓得過這裡的 (0,1,0),得寫在它自己那一支旁邊才蓋得掉。 */
@media (min-width: 552px) { .fab { right: calc(50% - 244px); } }

/* 下滑收起來 — nav.js 的 onScroll()。**不是 `.hide`**:那是 `display: none`,
   而這裡要的是一段動畫;`pointer-events: none` 讓收起來的那顆按不到,不然使用者
   會點到一顆看不見的鈕。特異度 (0,2,0) 壓得過上面那條 (0,1,0)。

   `.kbd` 是**軟鍵盤彈出來的時候** — D-F99(#370),切它的是 nav.js 的
   fabKeyboard()(那一段寫著為什麼是「收起來」而不是「改跟著 visualViewport 的
   底」)。長相與 `.away` 逐字相同,而**是兩個 class 不是一個**:`.away` 是捲動方
   向的狀態,onScroll() 隨時會把它改掉 —— 共用一個的話,鍵盤還開著、手指往回滑一
   下,那顆鈕就自己冒到輸入法上面。 */
.fab.away, .fab.kbd {
  transform: translateY(96px) scale(.9); opacity: 0; pointer-events: none;
}
@media (prefers-reduced-motion: reduce) { .fab { transition: none; } }

/* z-index 是 #168 加的(那時排的是「更多」那張選單);#201 之後這一疊是
   FAB(21)→ nav(22)。兩個數字都在 auth.css 的 #gate(30)之下 —— 登入閘蓋著
   時整個 app 不該有東西冒出來,而 api.js 的 toast(40)在最上面。 */
nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 22; background: var(--nav);
  border-top: 1px solid var(--line); display: flex; padding-bottom: env(safe-area-inset-bottom);
}
nav button {
  flex: 1; font: inherit; font-size: 0.71875rem; cursor: pointer; padding: 10px 0 12px;
  background: none; border: 0; color: var(--dim);
}
/* 記一筆那顆底色的規則在 #201 退役了 —— 它整顆搬出 nav 變成 FAB(上面的
   `.fab`),而「不同顏色的底」在那裡是 accent 實心,比兌淡的那一版更像主要動作。
   #166 當時寫的取捨(底色不能逼白字上場,否則說不出「我在這一頁」)只在**那顆鈕
   站在 nav 上**時成立:nav 上「現在選著」是 accent 色的字,而 FAB 不在那一排裡。 */
nav button[aria-current="page"] { color: var(--accent); font-weight: 640; }
/* nav 那一格的 icon — #392 從五個幾何字元(▤▦⌂≡◈)換成 icon 集裡的五顆。
   `<em>` 那一層留著:它是「圖在上、字在下」那個版面,而 icon 換掉的是它裝的
   東西不是它自己。 */
nav em { display: block; font-style: normal; margin-bottom: 2px; line-height: 0; }
nav em .ic { vertical-align: 0; }

/* 「更多」那張向上彈的選單(`.scrim` / `.sheet` / `.mrow`,#168)在 #201 整組
   刪掉了 —— 它裝的三個入口各自回到導覽列與鈴鐺上,沒有東西再需要一張浮起來的
   紙。`--navh` 那個接縫留著,現在是 FAB 在用(見上面 `.fab`)。 */

.hide { display: none; }

/* --------------------------------------------------------------- icon — #392

   一套 stroke SVG(web/icons/set.js),而尺寸只有三格:24 / 20 / 16。**寫成 class
   而不是每一處各給一個 width**:同一顆 icon 在 nav 上與在籤裡是兩個大小,而
   `<use>` 引的是同一份 path —— 尺寸是使用的一部分,不是 icon 的一部分。

   `stroke: currentColor` 寫在 sprite 的 `<symbol>` 上,所以顏色由 icon 站的地方
   決定:nav 上是 `--dim`、選中那一格是 `--accent`、危險那一列是 `--danger`。
   **這正是 emoji 做不到、而 #221 / #225 兩次判決講的那件事。**

   `flex: none` 是量出來的:icon 多半站在 flex 容器裡(一列的右邊、chip 裡),而
   沒有它的話那個方框會被壓扁。 */
.ic { display: inline-block; flex: none; vertical-align: -.14em; }
.ic-lg { width: 24px; height: 24px; }
.ic-md { width: 20px; height: 20px; }
.ic-sm { width: 16px; height: 16px; }
/* sprite 本體。`display: none` 的 `<svg>` 仍然引得到(`<use>` 走的是文件裡的 id,
   不是畫面上的節點)—— 這是 sprite 這個做法的全部機制。 */
#icons { display: none; }

