/* 愛發筆公開網站 —— 共用樣式
   ⚠️ 主色原本是橙色，刻意沿用鼠鬚管配色（squirrel.custom.yaml 的高亮色），讓網站跟
   實際打字畫面看起來是同一套東西。2026-08-21 依 Wilson 決定改成深青 #0e7c73（理由見
   --accent 旁邊的註解），**這條對應關係就斷了** —— 網站是青的、輸入法候選窗還是橙的。
   Wilson 決定就這樣：網站和輸入法不必同色 —— 鼠鬚管只是承載愛發筆的一個介面，
   不是這個專案的一部分。**所以這不是待辦事項，不用回報給 Side B、也不要「修好」它。**
   所有路徑都用相對路徑：GitHub Pages 是專案站，網址在 /AiPhaBi/ 底下，絕對路徑會全部失效。 */

:root {
  /* 中性色（底色、線、文字灰、程式碼底色）全部帶一點主色的色相（青 175°）。
     原本帶的是暖米色，配的是舊的橙主色；主色換成深青之後那層米色就變成「泛黃」
     （Wilson 指出底色和導覽 hover 都偏黃）。作法是保留每個值原本的明度和飽和度，
     只把色相換成 175° —— 深淺關係完全不變，只是冷暖翻面。
     ⚠️ 這一組跟 --accent 綁在一起：換主色時要一起換，不然又會一冷一暖。 */
  --bg:      #fcfefe;   /* 只留一絲青，再多就整頁泛綠（Wilson）*/
  --surface: #ffffff;
  --line:    #d8e6e5;
  --ink:     #1c2322;
  --ink-dim: #5b6b6a;
  --ink-faint: #839493;   /* 比 --ink-dim 再淡一階，給附註類的文字 */
  /* 主色：深青 #0e7c73（色相 175°）。原本是那個橙（色相 27°）——它離分組色的
     橘黃 #ffb732（39°）只有 11°，而主色不只是品牌色：〈字根表〉highlight 的字根
     筆畫就是用它填色，跟六個分組色出現在同一頁，撞在一起會讓人以為是同一件事。
     六色（355/39/88/205/271/332）只留下綠→藍那一段是空的，深青正好落在裡面，
     離最近的藍 30°。白底對比也從 3.77:1 升到 5.06:1。
     ⚠️ 之後要換主色，先確認新色相跟那六個都隔得開，不然會重蹈這次的覆轍。 */
  --accent:  #0e7c73;
  /* 同一個字根在一個字裡出現第二、第三次時用的色階。用明確色值而不是 color-mix：
     color-mix 用在 fill 上不是每個瀏覽器都吃，而 @supports 測的是 color 不是 fill，
     測得過卻畫不出來，結果整個宣告被丟掉、退回原本的橙色 —— 看起來就像沒分色。 */
  --accent-2: #094d47;
  --accent-3: #06322e;
  --accent-soft: #eef6f5;
  --code-bg: #ecf4f3;
  /* 字例圖示專用的一組：高亮的筆畫、和沒高亮的底色筆畫。
     跟 --accent 分開，因為兩者的需求相反 —— --accent 要當標題和連結的文字色，
     必須夠深才讀得清楚；這裡是又細又小的筆畫，要的是「一眼看出哪幾筆是字根」，
     靠的是跟灰筆畫的差距。

     ⚠️ 調這一組的時候，兩個值要一起看：把綠調亮會**縮小**它跟灰的明度差。
     實測 #14b8aa 配原本的灰只剩 1.04:1，等於兩者亮度一樣、只剩色相差得出來，
     比沒調還糟。現在這組是綠往亮＋飽和推一階、灰同時往淺推並且改成中性灰：
       舊  #0e7c73 ／ ink@.42（#a0a3a2，帶青）   兩者 1.99:1
       新  #0d9488 ／ #c4c4c4（中性灰）          兩者 2.13:1
     綠更亮更飽和、灰更灰更淡，而且分得更開（Wilson 要的兩件事其實可以同時成立，
     但只調其中一個就會反效果）。 */
  --zg-on:   #0d9488;
  --zg-on-2: #09625a;
  --zg-on-3: #06413c;
  --zg-off:  #c4c4c4;
  --radius: 10px;
  /* 正文行寬上限。原本 34rem 在桌機上只佔中間一條，像手機版。
     現在設成跟版面內容寬一樣（.wrap 58rem 減去左右各 1.6rem），
     等於不再另外限制，正文與標題、分隔線同寬。 */
  --measure: 54.8rem;

  /* 全站字級倍率（頁面上的 小／標準／大，每一頁的頁首都有）。html 的 font-size
     乘上它，rem 全部跟著縮放，三段只要改這一個值。 */
  --zg-scale: 1;
  /* 小字：出處、授權、圖說、頁尾版權共用一個字級（Wilson 2026-08-28）。
     原本 .zg-credit .78 / footer .82 / figcaption .85 三個尺寸做同一件事。 */
  --credit-size: .78rem;

  /* 「正確拆法 vs 錯誤拆法」小圖對照專用（見字母欄底下的 .zg-altmini）。跟上面的
     --accent-* 刻意不同一套：那組色階表示「同一個字根」，這裡要表示「筆畫分成幾組」，
     混在一起讀者會誤會兩件事是同一個系統。
     配色調整過三輪（Wilson）：原本刻意跳過橙色，因為紅／橙／黃色相太近，小圖示的
     尺寸下橙會同時貼著紅和黃。後來黃調亮成檸檬黃（#d8c600）解決了「看起來像土黃」
     的問題，但太淺、讀起來吃力。現在改成橘黃 #ffb732、紅 #ed2939（兩個都是
     Wilson 指定的值）：色相差 44°（355° vs 39°），比當初擔心的距離開一些，明度也
     差很開（白底對比 4.2:1 vs 1.7:1），一個深一個亮，不會認錯。
     也就是說：**這兩個顏色是靠明度分開的，不是靠色相**——之後要動其中一個，
     得把另一個一起看，不然又會撞在一起。

     藍原本是 #1f66c2（色相 214°），綠→藍之間空了 126°、藍→紫卻只有 57°，看起來
     藍離綠太遠、又貼著紫（Wilson）。把藍拉到偏青的 205°，兩段變成 117° 和 66°。
     粉紅原本是 #c23b7a（332°），跟紅只隔 23°，是全圈最擠的一段；換成 309° 之後
     那段變成 46°，紫→粉則從 61° 收成 38°（紫很深、粉很亮，靠明度分得開）。
     六色相鄰間距現在是 44° / 49° / 117° / 66° / 38° / 46°。 */
  --rb-0: #ed2939;   /* 紅（Wilson 指定的值）*/
  --rb-1: #ffb732;   /* 黃（橘黃，Wilson 指定的值）*/
  --rb-2: #8bc34a;   /* 綠（Wilson 指定的值）*/
  --rb-3: #0096ff;   /* 藍（Wilson 指定的值；偏青，補綠→藍那段太空的色相）*/
  --rb-4: #7a3fb0;   /* 紫 */
  --rb-5: #f26fde;   /* 粉紅（Wilson 指定的值）——超過五組筆畫的字（藍 HCKAMI 六組）
                         才用得到，不然照 RAINBOW.length 循環到第六組會撞回紅色 */

  /* 打錯／警告的紅。要比第一組的筆畫紅（--rb-0）更深，兩種紅才分得開（Wilson）——
     試打頁同一畫面上就會同時出現：第一條字根的筆畫是 rb-0，打歪的那幾碼是這個。
     淺色底下對比 7.66:1，rb-0 是 4.17，亮度差 11.3，不會看成同一個紅。 */
  --warn: #a4161a;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:      #141717;
    --surface: #1b2020;
    --line:    #2d3534;
    --ink:     #e1eceb;
    --ink-dim: #8ea2a0;
    --ink-faint: #708381;   /* 深色主題往背景靠，一樣是「更不搶眼」 */
    --accent:  #3fc0b0;
    /* 深色主題往亮的方向拉開，往暗拉會跟背景糊在一起 */
    --accent-2: #319689;
    --accent-3: #26736a;
    --accent-soft: #1d2f2b;
    --code-bg: #1f2625;
    --zg-on:   #2fd6c4;
    --zg-on-2: #22aa9b;
    --zg-on-3: #197e74;
    --zg-off:  #6f6f6f;

    /* 深色主題往亮、往飽和拉開，跟 --accent-* 那組同理；黃在暗背景上不用壓暗。 */
    --rb-0: #ff5563;   /* 深色底上把 #ed2939 提亮，色相不動 */
    --rb-1: #ffb732;
    --rb-2: #8bc34a;   /* 深淺主題共用，這個綠在兩種背景上都夠亮 */
    --rb-3: #0096ff;   /* 本來就夠亮，深淺主題共用 */
    --rb-4: #c084fc;
    --rb-5: #f26fde;   /* 本來就夠亮，深淺主題共用 */
    /* 深色底下「更深」會直接吃掉對比，所以取「還過得了 AA 的最深」：4.84:1
       （rb-0 是 5.78），亮度差 5.5，看得出是另一個紅。再深一階 #e6404d
       只剩 4.47，低於 4.5 就不收。 */
    --warn: #ee4653;
  }
}

:root[data-zg-size="small"] { --zg-scale: .86; }
:root[data-zg-size="large"] { --zg-scale: 1.2; }

* { box-sizing: border-box; }

/* [hidden] 原本靠瀏覽器內建樣式生效，但只要哪個元素自己另外設了 display
   （這裡幾乎每個區塊都有），author stylesheet 的 display 會蓋掉 UA stylesheet
   的 [hidden]{display:none}——兩邊 specificity 打平，author 後到者贏。試打頁
   切換「自由試打」時 practice-head 等區塊設回 hidden 卻沒消失，就是這個原因
   （見 try.js setMode）。這條規則保證 hidden 永遠贏。 */
[hidden] { display: none !important; }

/* 只給螢幕閱讀器看的標籤 */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* rem 全部相對 html 的字級，所以字級（小／標準／大）在這裡一次縮放整頁，
   不必再到每條規則各自乘一次 --zg-scale。 */
html {
  -webkit-text-size-adjust: 100%;
  font-size: calc(100% * var(--zg-scale));
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  /* body 自己吃固定 px，不是 rem，所以子層直接繼承 body 字級的段落文字
     （沒另外寫 font-size 的 <p> 等）也要在這裡乘一次，字級才管得到它們。 */
  font: calc(15px * var(--zg-scale))/1.8 "Noto Sans TC", "PingFang TC", "Hiragino Sans CNS",
        "Microsoft JhengHei", system-ui, -apple-system, sans-serif;
  text-rendering: optimizeLegibility;
}

/* 中文正文不需要斜體，瀏覽器合成的假斜體很醜 */
em, i { font-style: normal; font-weight: 600; color: var(--accent); }

a { color: var(--accent); text-underline-offset: .2em; }
a:hover { text-decoration-thickness: 2px; }

code, kbd, .code {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: .9em;
  letter-spacing: .06em;
}

code {
  background: var(--code-bg);
  padding: .12em .4em;
  border-radius: 4px;
}

kbd {
  background: var(--surface);
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 5px;
  padding: .1em .45em;
  font-size: .85em;
}

/* ---------- 版面 ---------- */

.wrap {
  max-width: 58rem;
  margin: 0 auto;
  padding: 0 1.6rem;
}

/* ---------- 頁首 ---------- */

/* ---------- 側邊導覽（寬螢幕）／頂部導覽（窄螢幕） ----------
 * 導覽固定在左側，內容往右讓開。窄螢幕會在檔案後面的 media query 改回頂部橫列，
 * 因為手機上左側欄會吃掉一半的可用寬度。 */
:root { --nav-w: 12.5rem; }

.topbar {
  position: fixed;
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--nav-w);
  border-inline-end: 1px solid var(--line);
  background: var(--surface);
  z-index: 10;
  overflow-y: auto;
  /* ⚠️ 一定要留著捲軸的位置。收合章節清單會讓側邊欄的內容變短、捲軸消失，
     內容區當場寬 15px，整排連結（連同那顆收合箭頭）就往右跳一下 —— 看起來
     像按鈕自己變寬了，其實是側邊欄變寬（實測 145.63 → 160.63px，按鈕本身
     一直是 25.59px）。 */
  scrollbar-gutter: stable;
}

.topbar .wrap {
  max-width: none;
  margin: 0;
  padding: 1.6rem 1.2rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.6rem;
}

/* 繁簡切換／字級切換：擺在品牌名下面、導覽連結上面，兩組左右並排 */
.topbar-controls {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
}

.topbar-controls .zg-size { flex-direction: row; align-items: center; gap: .35rem; }

/* 「字級」文字標籤只留給 role="group" aria-label 用，並排在繁簡切換旁邊時不重複顯示 */
.topbar-controls .zg-size > span { display: none; }

/* 用 body 的 padding 讓開側邊欄，而不是給 main 加 margin-inline-start ——
   後者會破壞 .wrap 的 margin: 0 auto，內容會貼著側邊欄、右邊空一大片。
   讓開之後 main 仍然是在「剩下的空間」裡置中。 */
body { padding-inline-start: var(--nav-w); }

.brand {
  /* 圖示在左、字在右（Wilson）。圖示本身已經帶圓角與透明背景，不用再加
     border-radius —— 見 assets/img/logo-512.png 的做法。 */
  display: flex;
  align-items: center;
  gap: .55rem;
  font-weight: 700;
  font-size: 1rem;
  line-height: 1.4;
  color: var(--ink);
  text-decoration: none;
  letter-spacing: .04em;
  white-space: nowrap;
}

.brand-logo {
  flex: none;
  width: 2.1rem;
  height: 2.1rem;
}

.brand .en {
  display: block;
  color: var(--ink-dim);
  font-weight: 500;
  font-size: .78em;
  margin-inline-start: 0;
  letter-spacing: .08em;
}

nav.site {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  width: 100%;
}

nav.site a {
  color: var(--ink-dim);
  text-decoration: none;
  padding: .35rem .6rem;
  border-radius: 6px;
  border-inline-start: 2px solid transparent;
  white-space: nowrap;
}

nav.site a:hover { color: var(--ink); background: var(--code-bg); }

nav.site a[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
  border-inline-start-color: var(--accent);
  background: var(--accent-soft);
}

/* 側邊欄分組：九頁平鋪看不出關係，用一條**不能點**的小標＋上下留白把它們分成
   「基礎學習」（字根表／取碼原則／約定字表／簡碼）與「流暢模式」（詞組連打／
   自動上屏）兩區，簡介、線上試打、後記維持頂層。⚠️ 小標刻意不是 <a> —— 這兩組
   沒有自己的頁面，做成連結就是騙點擊（Wilson 明講不要為它們開頁）。
   「流暢模式」這個詞不是新造的：試打頁那組單選鈕本來就叫這個名字，涵蓋的也正是
   這兩頁，兩邊用同一個詞，改名要一起改。 */
.nav-sec {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  margin-block: .5rem;      /* 分組之間的留白，比 nav.site 的 gap（.1rem）大得多 */
}

.nav-sec-t {
  padding: .1rem .6rem .15rem;
  font-size: .72rem;
  font-weight: 700;
  color: var(--ink-dim);
  letter-spacing: .1em;
}

/* 組員縮排一階。縮排加在 padding 而不是整個 .nav-sec 上：目前頁面那條橙色左框
   要跟簡介／線上試打／後記對齊成同一條直線，整組推進去的話框線會參差不齊。

   ⚠️ 第二條選擇器不能省：site.js 給有章節清單的那一頁加收合箭頭時，會把連結
   包進 .pr-navhead 裡（見「側邊欄章節清單：可以收起來」），那個連結就不再是
   .nav-sec 的**直接子元素**，`> a` 選不到它，縮排整個掉光 —— 畫面上就是「有
   箭頭的那一條標題比別條往左凸出來一截」（Wilson 2026-08-31 看出來的）。 */
nav.site .nav-sec > a,
nav.site .nav-sec > .pr-navhead > a { padding-inline-start: 1.35rem; }

/* 章節錨點本來就縮一階（.pr-sidenav 的 1.1rem），在組裡要再讓開組員那一階 */
nav.site .nav-sec .pr-sidenav { padding-inline-start: 1.85rem; }

/* .pr-sidenav 的錨點連結（#pr-1 之類）跟「取碼原則」共用同一個網址路徑，
   site.js 判斷目前頁面只看路徑、不看 hash，所以九條連結全部會被標成
   aria-current="page"——這裡取消粗體／橙色框線／橙色底色，這組樣式是給
   四個主連結分辨「在哪一頁」用的，不是給這幾條錨點連結用的。 */
nav.site .pr-sidenav a[aria-current="page"] {
  font-weight: 400;
  border-inline-start-color: transparent;
  background: none;
}

/* 繁簡切換 */
.langtoggle {
  display: flex;
  border: 1px solid var(--line);
  border-radius: 999px;
  overflow: hidden;
  font-size: .66rem;
}

.langtoggle button {
  border: 0;
  background: transparent;
  color: var(--ink-dim);
  padding: .12rem .45rem;
  cursor: pointer;
  font: inherit;
}

.langtoggle button[aria-pressed="true"] {
  background: var(--accent);
  color: #fff;
}

/* ---------- 主體 ---------- */

/* 上方留白要撐開頁首與內容 —— 3rem 時眉標幾乎貼著導覽列的底線。
   下方主要交給 footer 的 margin/padding，見檔案下方 footer。 */
/* ⚠️ 一定要寫成 main.wrap：<main> 同時掛著 class="wrap"，而 .wrap 有
   padding: 0 1.4rem。類別選擇器的權重高過元素選擇器，所以單寫 main { padding }
   會被 .wrap 的 0 蓋掉，怎麼調都沒反應 —— 這個坑踩過一次。 */
main.wrap { padding-block: 3rem 1.25rem; }

/* 標題上方的小字（愛發筆輸入法）—— 頁面標題是「簡介」，品牌名放在它上面當眉標 */
.eyebrow {
  font-size: .88rem;
  color: var(--ink-dim);
  letter-spacing: .08em;
  margin: 0 0 .45rem;
}

h1 {
  font-size: clamp(1.6rem, 4vw, 2.1rem);
  line-height: 1.35;
  margin: 0 0 .8rem;
  letter-spacing: .01em;
}

h2 {
  font-size: 1.15rem;
  /* 上緣間距由這裡決定 —— 與前一段的 margin-bottom 會合併取大者，加不起來 */
  margin: 2rem 0 .8rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
  letter-spacing: .02em;
}

h3 {
  font-size: 1rem;
  margin: 1.8rem 0 .5rem;
}

p { margin: 0 0 1.1rem; max-width: var(--measure); }

/* 〈簡介〉導語底下那一行——由 site.js 從 dict.json 填字，見那邊「進度數字」
   那段的註解，數字不手寫死。HTML 裡的內容是離線後備值。 */
.jieshao-stat {
  font-size: .88rem;
  color: var(--ink-dim);
  margin: -.4rem 0 1.6rem;
}

/* 導語（每頁標題底下那一段）—— ⚠️ 大小以〈字根表〉那一段為準（Wilson 2026-08-28）：
   全站只有這一個尺寸，.zg-intro 與 .lede 是同一種東西的兩個名字，別再讓它們分家。
   .doc-prose 底下的正文也是同一個 .92rem，導語不可以比正文大。 */
.lede,


/* 說明頁的正文：段落、清單、定義列表全部跟導語同一個字級。掛在 main 上，而且只認
   **直接子代** —— 卡片、圖例、註腳那些元件自己有字級，套進去會亂。 */
/* ⚠️ :where() 是刻意的 —— 它讓這條規則的權重停在「一個 class」，跟 .cz-legend、
   .zg-credit 那些自己訂了字級的元件同級，於是後面出現的元件規則照樣蓋得過來。
   寫成 .doc-prose > p 權重會高一級，把每一個註腳、圖例都拉成正文大小。
   .eyebrow 排在這條之前，蓋不過來，只能明寫排除。 */
.doc-prose > :where(p:not(.eyebrow), ul, ol, dl) {
  font-size: .92rem;
  line-height: 1.6;
}

ul, ol { max-width: var(--measure); padding-inline-start: 1.3rem; }
li { margin-bottom: .5rem; }

/* ---------- 元件 ---------- */

/* 拆碼示範 —— ⚠️ 目前沒有頁面用到（首頁那塊 2026-08-19 依 Wilson 指示移除）。
   留著是因為做〈學習取碼〉那類頁面時很可能再用到。 */
.demo-eq {
  display: flex;
  align-items: center;
  gap: .7rem;
  flex-wrap: wrap;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem 1.3rem;
  margin: 0 0 1.4rem;
}

.demo-eq .glyph {
  font-size: 2.4rem;
  line-height: 1;
  font-family: "Noto Serif TC", "Songti TC", serif;
}

.demo-eq .op { color: var(--ink-dim); font-size: 1.1rem; }

.demo-eq .key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2rem;
  height: 2rem;
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent);
  font-family: ui-monospace, Menlo, monospace;
  font-weight: 700;
}

.demo-eq .why {
  color: var(--ink-dim);
  font-size: .88rem;
  flex-basis: 100%;
  margin: 0;
}

/* 重點卡片 —— ⚠️ 目前沒有頁面用到（首頁九大特點改用 .points，設計原理頁已移除）。
   留著是因為之後很可能再用到；要清理的話這一段和 .card 一起拿掉。 */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
  margin: 1.6rem 0 0;
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.2rem 1.3rem;
}

.card h3 { margin: 0 0 .4rem; font-size: 1rem; }
.card p  { margin: 0; font-size: .93rem; color: var(--ink-dim); max-width: none; }

/* 九大特點：Wilson 文案的原文，逐條照抄。每條是一整段散文而不是一句短標語，
 * 所以用單欄編號清單而不是 .cards 的網格 —— 長短不一的段落擠成兩欄很難讀。 */
.points {
  list-style: none;
  padding-inline-start: 0;
  max-width: var(--measure);
  margin: 1.6rem 0 0;
  counter-reset: point;
}

.points > li {
  counter-increment: point;
  position: relative;
  padding-inline-start: 2.6rem;
  margin-bottom: 1.8rem;
}

/* 編號用 ::before 而不是 <ol> 內建標記，才能跟標題對齊並上色 */
.points > li::before {
  content: counter(point);
  position: absolute;
  inset-inline-start: 0;
  top: .1rem;
  width: 1.8rem;
  height: 1.8rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent);
  font-family: ui-monospace, Menlo, monospace;
  font-size: .85rem;
  font-weight: 700;
}

.points > li > h3 { margin: 0 0 .45rem; font-size: 1rem; }
.points > li > p  { margin: 0; max-width: none; }

/* 數字列 —— ⚠️ 目前沒有頁面用到（首頁〈目前進度〉移除、設計原理頁移除）。
   **不要刪**：網站上線時要講「教育部甲表全部收錄」，那個數字就會用回這一組。 */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  margin: 1.6rem 0;
}

.stat { background: var(--surface); padding: 1rem 1.1rem; }

.stat b {
  display: block;
  font-size: 1.6rem;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
  letter-spacing: .01em;
}

.stat span { font-size: .82rem; color: var(--ink-dim); }

/* 引言 —— ⚠️ 目前沒有頁面用到。留著給之後的內容頁。 */
blockquote {
  margin: 1.6rem 0;
  padding: .2rem 0 .2rem 1.2rem;
  border-inline-start: 3px solid var(--accent);
  color: var(--ink-dim);
  max-width: var(--measure);
}

blockquote p:last-child { margin-bottom: 0; }

/* 表格 */
.tablewrap { overflow-x: auto; margin: 1.4rem 0; }
.zg-table .tablewrap { margin: .3rem 0 0; }

/* ⚠️ overflow-x: auto 會讓這一層變成捲動容器，裡面的 position: sticky 就會黏在
   「這個容器」而不是視窗上，表頭因此會飄到內容中間、蓋住字母欄。
   欄寬是固定的（3.2+13+8.5rem ＋ 字例），寬螢幕本來就放得下，所以不需要橫向捲；
   只有窄螢幕才開，那時表頭改成不黏（sticky 在捲動容器裡沒有意義）。 */
.zg-table .tablewrap { overflow-x: visible; }

@media (max-width: 40rem) {
  .zg-table .tablewrap { overflow-x: auto; }
  .zg-tbl thead th { position: static; }
}

table {
  border-collapse: collapse;
  width: 100%;
  font-size: .92rem;
}

th, td {
  text-align: start;
  padding: .55rem .8rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

th { font-weight: 600; white-space: nowrap; }
tbody tr:last-child td { border-bottom: 0; }

/* ---------- 字根表（zigen.html） ---------- *
 * 版面參考《倉頡輸入法／輔助字形》：一字母一節，節裡是「取形意圖｜字根｜字例」的表格。
 * 這一頁的內容比 --measure 寬，所以整頁不套那個上限，交給表格自己捲。 */

/* 字根表的說明段：比正文小一級。這一頁的主體是表格，說明只是進場前的一句話，
   用正文大小會跟表格搶注意力。 */
.zg-intro {
  font-size: .92rem;
  color: var(--ink-dim);
  max-width: var(--measure);
  margin-bottom: 1rem;
  line-height: 1.6;
}

.zg-tools {
  margin: 1.6rem 0 .6rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.zg-find { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; }
.zg-find > span { font-size: .9rem; color: var(--ink-dim); }

.zg-find input {
  font: inherit;
  font-size: 1.1rem;
  width: 7rem;
  padding: .35rem .6rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
}
.zg-find input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

/* 字級切換：在側邊欄裡直排，比繁簡切換再小一點 —— 每一頁的頁首都有，不是字根表專屬 */
.zg-size {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .3rem;
  font-size: .66rem;
  color: var(--ink-dim);
}

.zg-size > span { white-space: nowrap; letter-spacing: .06em; }

.zg-size-btns {
  display: flex;
  border: 1px solid var(--line);
  border-radius: 999px;
  overflow: hidden;
}

.zg-size button {
  border: 0;
  border-inline-start: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-dim);
  padding: .12rem .4rem;
  cursor: pointer;
  font: inherit;
  line-height: 1.5;
}

.zg-size button:first-child { border-inline-start: 0; }

.zg-size button:hover { color: var(--ink); }

.zg-size button[aria-pressed="true"] {
  background: var(--accent);
  color: #fff;
}

.zg-find { flex: 0 1 auto; }

.zg-status { font-size: .88rem; color: var(--accent); margin: .5rem 0 0; min-height: 1.2em; }

/* A–Z 跳轉列：黏在頂端，但要讓開 .topbar */
/* A–Z 一整列不換行：26 個字母分兩行會讓「跳到某個字母」這件事變得要先找。
   欄寬不夠時讓它自己橫向捲，而不是折行。 */
/* 三層黏頂，由上往下：頁首(3.4rem, z10) → A–Z 列 → 表頭。
   top 要各自讓開上面那層的高度，不然會互相疊在一起；z-index 也要照這個順序，
   不然下面的會蓋到上面的。 */
.zg-jump {
  position: sticky;
  top: 0;                             /* 導覽在左側，上方沒有東西要讓開 */
  z-index: 5;
  display: flex;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  gap: .12rem;
  padding: .45rem 0;
  margin-bottom: .5rem;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}
.zg-jump::-webkit-scrollbar { display: none; }

.zg-jl {
  font-family: ui-monospace, Menlo, monospace;
  font-weight: 700;
  font-size: .85rem;
  min-width: 1.3rem;
  flex: 0 0 auto;
  text-align: center;
  padding: .15rem .05rem;
  border-radius: 4px;
  text-decoration: none;
  color: var(--accent);
  background: var(--accent-soft);
}
.zg-jl.is-off { color: var(--ink-dim); background: transparent; opacity: .45; }

/* .zg-h / .zg-letter 已不再使用：字母改成表格最左邊的欄，不再每個字母一條標題。
   保留 .zg-key 的樣式，字母欄和辨析表都還在用。 */
.zg-tbl tbody tr { scroll-margin-top: 5rem; }   /* 讓開 A–Z 列 ＋ 表頭 */

/* 側邊欄的〈相近字形辨析〉跳過來時，標題要讓開黏在頂端的 A–Z 列（實測不讓開的話
   h2 落在 top=0，而 A–Z 列的下緣在 45px，標題整條被蓋住）。這裡不必像表格列那樣
   多讓一個表頭的高度，所以值比 .zg-tbl tbody tr 小一點。 */
#zg-similar { scroll-margin-top: 4rem; }

.zg-h {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .95rem;
  margin: .9rem 0 .2rem;
  padding-top: .5rem;
  border-top: 1px solid var(--line);
}

/* 字母本身就是字根的形狀，所以給它鍵帽的樣子 —— 跟首頁的 .key 一致 */
.zg-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.8rem;
  height: 1.8rem;
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent);
  font-family: ui-monospace, Menlo, monospace;
  font-weight: 700;
  font-size: 1.15rem;
}

.zg-n { font-size: .88rem; color: var(--ink-dim); font-weight: 400; }

/* 相近字形辨析：說明文字裡點名「不取哪個碼」時，淡化＋刪除線放在正確碼旁邊對照
   （失 該取 JIY 不取 YK 那一類）—— 錯的碼不搶眼，但一眼就對得出差在哪。
   直排兩行：碼在上，正確/錯誤拆法的小圖對照（若有）在下——同一欄，不另外開欄。
   靠上對齊，跟字根表的 .zg-letterkey 同理：說明欄一長，鍵帽垂直置中就會浮在
   一大塊空白正中間，格線離鍵帽老遠，像多了一條沒作用的線、一格空的。
   vertical-align 只對「還是表格儲存格」的盒子有效，所以下在 <td> 本身（.zg-codecell），
   flex 排版另外包一層 <div>（.zg-codepair）——兩件事各自的盒子分開，才不會互相打架。 */
/* !important 是必要的：.zg-simtbl th, .zg-simtbl td 那條泛用規則的權重（一個類＋一個
   元素）比只有一個類的 .zg-codecell 高，光靠選擇器順序贏不了它——跟字根表的
   .zg-desc/.zg-letterkey 用 !important 是同一個原因，不是隨手加的。 */
.zg-codecell { vertical-align: top !important; }
.zg-codepair { display: flex; flex-direction: column; gap: .35rem; }
.zg-codepair-row { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; }

.zg-key-wrong {
  color: var(--ink-faint);
  font-family: ui-monospace, Menlo, monospace;
  font-size: .8rem;
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--ink-faint);
}

/* 密度參考倉頡的〈輔助字形列表〉：完整格線、字級小、列高緊。
 * 原本一列佔兩三行、要捲很久才看得完一個字母，資訊密度太低。 */
/* 三欄寬度釘死，26 個字母的表才會對齊（不然各表依自己的內容決定欄寬，
   A 的「取形意圖」欄跟 B 的不一樣寬，整頁參差不齊）。 */
.zg-tbl { font-size: .95rem; table-layout: fixed; width: 100%; }

/* 欄寬直接下在表頭儲存格上，不靠 <col>。table-layout: fixed 是看第一列決定欄寬的，
   下在 th 上最直接；<col class> 那條路在某些瀏覽器上不吃，結果 26 張表又各自為政。 */
/* 版面加寬到 58rem 之後重新分配：取形意圖那一欄本來就常常折成三四行，
   多出來的寬度給它最有用；字例只有四個字，不需要更多空間。 */
.zg-tbl thead th:nth-child(1) { width: 3.2rem; }   /* 字母 */
.zg-tbl thead th:nth-child(2) { width: 20rem; }   /* 取形意圖 */
/* 9.5rem 對「來源字＋第 X 筆」大多夠用，但來源字筆序多的時候（東 用到「來」
   第 1、6、7、8 筆）會斷成兩行，字例欄（auto）那邊明明還有得是餘裕，加寬這欄。 */
.zg-tbl thead th:nth-child(3) { width: 11.5rem; } /* 字根 */
.zg-tbl thead th:nth-child(4) { width: auto; }                            /* 字例 */

@media (max-width: 40rem) {
  .zg-tbl thead th:nth-child(1) { width: 2.6rem; }
  .zg-tbl thead th:nth-child(2) { width: 8rem; }
  .zg-tbl thead th:nth-child(3) { width: 7.6rem; }
}

/* 字母與字母之間留一道分隔：整張表連在一起雖然省空間，但 A 的最後一列和 B 的
   第一列黏在一起會看不出換字母了。用加粗的上框線＋一點額外留白，比整條標題省得多。
   （第一列不用，表頭底下不需要再來一道。） */
.zg-tbl tbody tr.is-letter-start > td {
  border-top: 2px solid var(--ink-dim);
  padding-top: .45rem;
}

.zg-tbl tbody tr:first-child > td { border-top-width: 1px; padding-top: .15rem; }

/* 最左邊的字母欄：跨滿該字母的所有列，字母放大當作分段的視覺錨點 */
.zg-letterkey {
  vertical-align: top !important;
  text-align: center;
  padding-top: .5rem !important;
  background: var(--code-bg);
  border-inline-end: 1px solid var(--line) !important;
}

.zg-letterkey .zg-key {
  min-width: 2rem;
  height: 2rem;
  font-size: 1.15rem;
}

.zg-letterkey .zg-n {
  display: block;
  margin-top: .25rem;
  font-size: .7rem;
}

.zg-tbl thead th {
  position: sticky;
  top: 2.5rem;                        /* 只需讓開上面那條 A–Z 列 */
  z-index: 3;                         /* 低於 A–Z 列（5），高於內容 */
  background: var(--code-bg);         /* 不透明，否則捲動時會透出下面的列 */
}

.zg-tbl th {
  color: var(--ink-dim);
  font-size: .84rem;
  padding: .2rem .45rem;
  background: var(--code-bg);
  border: 1px solid var(--line);
}

.zg-tbl td {
  vertical-align: middle;
  padding: .15rem .45rem;             /* 列高的主因之一，壓到最低 */
  border: 1px solid var(--line);      /* 完整格線，不是只有底線 */
}

.zg-desc {
  color: var(--ink);
  overflow-wrap: break-word;
  vertical-align: top !important;
  padding-top: .35rem !important;
  font-size: .9rem;
  line-height: 1.5;
}

.zg-todo { color: var(--ink-dim); font-style: italic; }

/* 取形意圖底下的額外說明：為什麼這一類形狀算是像這個字母。
   只有少數意圖有，所以要看得出是附註而不是意圖本身。 */
.zg-note {
  display: block;
  margin-top: .45rem;
  padding-top: .4rem;
  border-top: 1px dotted var(--line);
  color: var(--ink-faint);
  font-size: .72rem;
  line-height: 1.55;
}

/* 等級標籤（次等／三等）自成一行、排在取形意圖上面 —— 它是整組的分類，
   不是意圖的一部分。接在意圖後面會被讀成句子的尾巴。 */
.zg-tier {
  display: block;
  width: fit-content;
  margin: 0 0 .35rem;
  font-size: .68rem;
  color: var(--ink-faint);
  background: var(--code-bg);
  border-radius: 4px;
  padding: .05rem .4rem;
}

/* 非連續筆序的標籤很長（東 第 1、6、7、8 筆 有 11 個字），nowrap 會直接溢出到
   字例欄上面。改成允許換行，圖示與文字上下排 —— 欄寬是固定的，硬撐只會壓到隔壁。 */
.zg-shapecell { overflow: hidden; }

/* 圖示固定不縮，文字自己換行 */
.zg-shape { display: flex; align-items: center; gap: .3rem; flex-wrap: wrap; }
/* 圖示欄固定寬度，字根才會垂直對齊成一直排，而不是隨形狀寬窄左右跳 */
.zg-shape > .zg-icon { flex: 0 0 1.55rem; }

/* 取自哪個字。刻意不放大到像「這就是字根」—— 字根只是它的其中幾筆 */
.zg-src {
  font-family: "Noto Serif TC", "Songti TC", serif;
  font-size: 1.15rem;
  line-height: 1.2;
}

/* 「石字 1、2 筆」這種描述式的形，字太多，放大會撐爆欄寬 */
.zg-src.is-desc { font-size: .84rem; font-family: inherit; color: var(--ink); }

/* 畫出來的字根本身。有圖之後，來源字退成小字註記——圖才是主角 */
.zg-icon { display: inline-flex; align-items: center; justify-content: center; }

/* 跟字例欄的字**同尺寸**：兩邊都是 1024 的字身框畫在同樣大小的方框裡，
 * 所以同一個形狀在兩欄看起來一樣大。字根欄只是把該字根置中而已。 */
.zg-svg {
  display: block;
  width: 1.55rem;
  height: 1.55rem;
}

.zg-svg path {
  fill: var(--ink);
  stroke: none;
}

.zg-src.is-ref {
  font-size: .84rem;
  color: var(--ink-dim);
  font-family: inherit;
}

/* 字形資料的出處與授權。Arphic PL 要求隨附授權全文，這一行是給人看的入口。 */
.zg-credit {
  font-size: var(--credit-size);
  color: var(--ink-dim);
  border-top: 1px solid var(--line);
  padding-top: .8rem;
  margin-top: 1.6rem;
  max-width: none;
}

.zg-span { font-size: .78rem; color: var(--ink-dim); }

.zg-ex { line-height: 1.15; }

.zg-ch {
  font-family: "Noto Serif TC", "Songti TC", serif;
  font-size: 1.05rem;
  margin-inline-end: .08rem;
}

.zg-ch.is-hit {
  color: var(--accent);
  font-weight: 700;
  background: var(--accent-soft);
  border-radius: 3px;
  padding: 0 .12rem;
}

.zg-more { font-size: .72rem; color: var(--ink-dim); margin-inline-start: .2rem; }

.zg-loading { color: var(--ink-dim); font-size: .92rem; }

@media (max-width: 34rem) {
  .zg-desc { font-size: .84rem; }
  .zg-ch { font-size: .98rem; }
  .zg-tbl { font-size: .8rem; }
}

/* 相近字形辨析（內容來自 site/content/similar.md） */
.zg-sim {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.2rem .4rem;
  margin: 0 0 1.1rem;
}

.zg-sim h3 { margin: 0 0 .3rem; font-size: 1rem; }
.zg-sim .tablewrap { margin: .6rem 0 .2rem; }
.zg-simtbl { font-size: .9rem; }
.zg-simtbl th { color: var(--ink-dim); font-size: .8rem; }
.zg-simtbl td { vertical-align: middle; }
.zg-simshape { width: 3rem; }
.zg-trait { color: var(--ink-dim); font-size: .86rem; }

.zg-key-sm {
  min-width: 1.7rem;
  height: 1.7rem;
  font-size: .9rem;
}

/* 取碼不只一個字母時（目 的「DI（D）」）就不要用鍵帽了 —— 鍵帽是「按這一鍵」的
   意思，而那是一串碼加註解，硬塞進圓角膠囊只會擠成破掉的樣子。改成單純的等寬字。 */
.zg-key-sm.is-wide {
  min-width: 0;
  height: auto;
  padding: .1rem .3rem;
  border: 0;
  border-radius: 4px;
  background: var(--code-bg);
  color: var(--accent);
  font-size: .82rem;
  white-space: nowrap;
}

/* 每一組辨析是各自的一張表，欄寬若各自算就會隨內容左右跳 —— 捲動時很明顯。
   跟字根表一樣用 table-layout: fixed ＋ 表頭寫死欄寬，所有組對齊。 */
.zg-simtbl { table-layout: fixed; width: 100%; }
.zg-simtbl thead th:nth-child(1) { width: 4.5rem; }    /* 形 */
.zg-simtbl thead th:nth-child(2) { width: 6.2rem; }    /* 字母（正確/錯誤拆法小圖也放這欄） */
.zg-simtbl thead th:nth-child(3) { width: auto; }      /* 特徵，吃掉剩下的 */
.zg-simtbl thead th:nth-child(4) { width: 9rem; }      /* 例字 */

.zg-simtbl th, .zg-simtbl td {
  padding: .35rem .55rem;
  border: 1px solid var(--line);
  vertical-align: middle;
}
.zg-simtbl th { background: var(--code-bg); }
.zg-simshape { white-space: nowrap; text-align: center; }
/* 說明欄常常是全列最長的內容，垂直置中會讓短短一個字母鍵帽浮在很大一塊空白正中間，
   底下那條格線因此離鍵帽很遠、像是斷開的一條線——跟字根表的 .zg-desc 同一個修法：
   長文字那一欄靠上對齊，讓整列的視覺起點對齊在頂端。 */
.zg-simtbl .zg-trait { overflow-wrap: break-word; vertical-align: top; }
.zg-simtbl .zg-ex { line-height: 1.3; }

/* 說明文字裡就地畫出來的字根（{目#1,2,3,4}）—— 跟文字對齊、大小相稱 */
.zg-inline {
  display: inline-block;
  vertical-align: -.28em;
  margin: 0 .1em;
}
.zg-inline .zg-svg {
  width: 1.35em;
  height: 1.35em;
}
.zg-inline svg path { fill: var(--ink); }

@media (max-width: 40rem) {
  .zg-simtbl thead th:nth-child(1) { width: 3.4rem; }
  .zg-simtbl thead th:nth-child(2) { width: 5rem; }
  .zg-simtbl thead th:nth-child(4) { width: 6rem; }
}

/* 字形欄連到它在字根表裡的那一列 */
.zg-simlink {
  text-decoration: none;
  border-bottom: 1px dashed var(--accent);
  color: inherit;
}
.zg-simlink:hover { background: var(--accent-soft); }

/* 只有從〈相近字形辨析〉點過來的才標記（那些列的 id 是 Z 開頭）——
   在幾百列裡找一列確實需要標一下。A–Z 跳轉列跳到的是字母開頭那一列（id 是 L 開頭），
   那本來就有粗分隔線和字母欄可以認，再加底色反而像選了什麼東西。 */
.zg-tbl tbody tr[id^="Z"]:target > td {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.zg-tbl tbody tr { scroll-margin-top: 4.5rem; }

.zg-simnote {
  font-size: .88rem;
  color: var(--ink-dim);
  border-top: 1px solid var(--line);
  padding-top: .6rem;
  margin: .4rem 0 .8rem;
  max-width: none;
}

/* 未完成的段落，Side C 接手時把它拿掉 */
.todo {
  background: var(--accent-soft);
  border: 1px dashed var(--accent);
  border-radius: var(--radius);
  padding: 1rem 1.2rem;
  font-size: .9rem;
  color: var(--ink-dim);
  margin: 1.4rem 0;
  max-width: var(--measure);
}

.todo b { color: var(--accent); }

/* ---------- 頁尾 ---------- */

/* 頁尾只剩一行版權，但仍然要留白 —— 內容緊貼視窗底端會像是被裁掉的。
   上面的分隔線改成淡一點，一行字不需要被框起來。 */
/* 頁尾只有一行字，所以留白要自己撐起來，不然整頁會像被裁掉。
   分隔線上方 4rem（＋ main 自己的 4rem）＝ 內容與線之間 8rem；
   線到文字 2.5rem；文字之下 7rem，捲到底時字不會黏在視窗邊緣。 */
/* 同上：footer 也掛著 wrap，所以要寫 footer.wrap 才蓋得過 .wrap 的 padding: 0 */
footer.wrap {
  border-top: 1px solid var(--line);
  margin-top: 1.75rem;
  padding-block: 1.8rem 3.5rem;
  color: var(--ink-dim);
  font-size: var(--credit-size);
}

footer p { max-width: none; margin: 0 0 .4rem; }

/* 英文那半句排在中文後面、再淡一級 —— 同一件事講兩次，第二次不該搶注意力 */
.en-note {
  margin-inline-start: .5rem;
  opacity: .7;
  letter-spacing: .02em;
}

/* ---------- 線上試打 ---------- */

/* 試打框現在住在試打區的左欄裡，所以自己不再是一個獨立的面板 */
.typebox { margin-top: .9rem; }

.typebox textarea {
  width: 100%;
  /* 比參考文章框高一點就好 —— 打出來的字要看得清楚，但也不用佔掉半個畫面 */
  min-height: 7.5rem;
  resize: vertical;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  color: var(--ink);
  padding: .9rem;
  /* ⚠️ 不要寫成 `font: 1.9rem/1.6 inherit` —— inherit 是 CSS 全域關鍵字，
     不能當簡寫的其中一段，整條宣告會被瀏覽器直接丟掉。這個框從一開始就是這樣
     寫的，所以字級一直是瀏覽器預設的 13.3px monospace，改幾次都沒有反應
     （Wilson 連講三次「還是太小」才查出來）。要分開寫。
     打出來的字要大 —— 這一格是「你打了什麼」，練習的時候眼睛一直在這裡；
     參考文章反而可以小（.88rem），它是照著抄的來源，不是成果。 */
  font-family: inherit;
  font-size: 1.2rem;
  line-height: 1.7;
}

.typebox textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* resize:vertical 的 textarea 在 Chromium 下一個兄弟元素前面會多出約 8px
   說不出從哪來的間距——量過 CSS 盒模型（margin／padding／border）都對不上，
   換一個完全沒有 class 的空 div 放在後面照樣多 8px，是瀏覽器對「可調整大小
   的 textarea」內建的行為，不是這裡哪個屬性算錯。跟 .rail 之間留的 .7rem
   margin-top 因此變成視覺上比其他地方的 .7rem 多一截，這裡扣掉那 8px，
   跟下面拼音那排（rail→.pyq-row）的間距才看起來一樣（Wilson）。 */
.typebox textarea + .rail { margin-top: .2rem; }

.rail {
  display: flex;
  align-items: center;
  gap: .6rem;
  /* 固定高度，不是 min-height：候選字太多時橫向捲軸會冒出來，如果只設
     min-height，捲軸會把這個框撐高一截，讓底下的東西跟著跳一下
     （Wilson 抓到：候選字有幾個跟沒有候選字，這個框高度不一樣）。
     固定高度讓捲軸自己內縮，框本身永遠一樣高。 */
  height: 2.9rem;
  margin-top: .7rem;
  padding: .35rem .6rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  overflow-x: auto;
}

.rail .buf {
  font-family: ui-monospace, Menlo, monospace;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
}

.rail .cands { display: flex; gap: .1rem; }

.rail .cand {
  display: flex;
  align-items: baseline;
  gap: .22em;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 1.15rem;
  padding: .2rem .5rem;
  border-radius: 5px;
  cursor: pointer;
  white-space: nowrap;
}

.rail .cand:hover { background: var(--accent-soft); }
/* 序號與碼行的字級、位移都跟標註站那頁對齊（type.html 的 .cand i／.cand em）——
 * 那邊的註解寫得很清楚：兩者的底部原本差快 3px，序號往下 2px、碼行往上 1px，
 * 底部才會切齊。這裡用 px 不用 rem 也是為了跟那邊一模一樣。 */
.rail .cand .n {
  font: 600 11px ui-monospace, Menlo, monospace;
  color: var(--ink-dim);
  position: relative;
  top: 2px;
}

/* 打中的字（你打的這幾碼就是它的碼）用主色標出來 —— 一眼看出哪個是真打中的，
 * 哪些只是「開頭一樣、還要再補幾碼」。跟標註站那個試打頁同一條規則。 */
.rail .cand.is-exact .g { color: var(--accent); }

/* 碼欄：標籤（簡碼）在上、碼在下，疊成一欄。align-self:flex-end 是必要的 ——
 * 讓這一欄自己底部對齊，不要參與那一排的 baseline 計算，否則基準線會算到
 * 「簡碼」那一行，把候選字整個往上頂，跟旁邊沒有標籤的候選字對不齊。 */
.rail .cand .c {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  align-self: flex-end;
  line-height: 1.4;
  font: 600 10px ui-monospace, Menlo, monospace;
  color: var(--ink-faint);
  position: relative;
  /* 量出來的：碼行的底原本比序號的底低 4.1px（橘色那頁的基準字級跟這裡不一樣，
     所以它的 -1px 搬過來剛好差這麼多）。往上挪到兩邊切齊為止。 */
  top: -5px;
}

.rail .cand .c .tag { color: var(--accent); font-size: 9px; }

.rail .hint {
  margin-inline-start: auto;
  font-size: .8rem;
  color: var(--accent);
  background: var(--accent-soft);
  border-radius: 999px;
  padding: .15rem .7rem;
  white-space: nowrap;
}

/* 候選列沒東西時那句說明：比候選字小一階，它是說明不是內容 */
.rail .empty { color: var(--ink-dim); font-size: .78rem; }

/* 例字：整個字畫出來，屬於該字根的筆畫塗深、其餘塗淺。
 * 這就是「元件分開、上色」的效果 —— 讀者一眼看到字根在字裡的哪個位置。 */
.zg-exg { display: inline-block; vertical-align: middle; margin-inline-end: .08rem; }

.zg-exsvg { width: 1.55rem; height: 1.55rem; display: block; }
/* 同一個字根在一個字裡出現兩次時分色（朋＝月月、夠＝夕夕）：第二次用深一點的橙。
   同色會讀成「這個字根就是整個朋」，分色才看得出是同一個字根出現兩次。 */
.zg-exsvg path.on    { fill: var(--zg-on); }
.zg-exsvg path.on-2  { fill: var(--zg-on-2); }
.zg-exsvg path.on-3  { fill: var(--zg-on-3); }
/* 未高亮的筆畫：要看得出整個字長什麼樣，才知道字根長在字的哪個位置。
   太淡的話字形認不出來，等於只看到一團橙色。 */
.zg-exsvg path.off   { fill: var(--zg-off); }


.zg-exg.is-hit {
  background: var(--accent-soft);
  border-radius: 4px;
  box-shadow: 0 0 0 1px var(--accent);
}

@media (max-width: 34rem) {
  .zg-exsvg { width: 1.8rem; height: 1.8rem; }
}

/* 「正確拆法 vs 錯誤拆法」小圖對照，見 zigen.js 的 altMiniCard／
 * build_site_data.py 的 WRONG_BREAKDOWN。彩虹色跟表格其餘地方「同一個字根」
 * 用的橙色系不是同一套語言 —— 這裡要凸顯的是「筆畫怎麼分組」，不是「這是哪個字根」。
 * 放在「字母」欄、碼底下那一行（見 .zg-codepair-row），不另外開一欄。
 * 打勾／打叉是圖示旁邊的字，不疊在圖示上面 —— 疊上去會蓋住角落的筆畫（Wilson）。 */
/* 兩組（正確／錯誤）不能各自換行 —— 字母欄本來就窄，換行會比並排更難比較 */
.zg-codepair-row:has(.zg-altpair) { flex-wrap: nowrap; gap: .35rem; }

.zg-altpair { display: inline-flex; align-items: center; gap: .12rem; flex: none; }

.zg-altmini {
  display: inline-block;
  width: 1.6rem;
  height: 1.6rem;
  vertical-align: middle;
  flex: none;
}

.zg-altmini .zg-altsvg { width: 100%; height: 100%; display: block; }

/* 描邊：同色系的紅／橙／黃在小尺寸下光靠色相不夠分，每一筆畫加一圈背景色窄邊，
   筆畫之間才有實際的分隔線，不是只能靠顏色本身分。 */
.zg-altsvg path { stroke: var(--surface); stroke-width: 26; paint-order: stroke; }

.zg-altsvg path.rb-0 { fill: var(--rb-0); }
.zg-altsvg path.rb-1 { fill: var(--rb-1); }
.zg-altsvg path.rb-2 { fill: var(--rb-2); }
.zg-altsvg path.rb-3 { fill: var(--rb-3); }
.zg-altsvg path.rb-4 { fill: var(--rb-4); }
.zg-altsvg path.rb-5 { fill: var(--rb-5); }
.zg-altsvg path.off  { fill: var(--zg-off); }

.zg-altminimark {
  font-size: .8rem;
  line-height: 1;
  font-weight: 700;
  flex: none;
}
/* 打勾用主色（深青），不另外挑一個綠——網站已經有一個主色，再多一個綠只是多一種
   顏色要記（Wilson）。打叉維持自己的紅：它跟主色是相反的意思，不該同色系。 */
.zg-altpair.is-ok .zg-altminimark  { color: var(--accent); }
.zg-altpair.is-bad .zg-altminimark { color: #d1382c; }

@media (max-width: 40rem) {
  .zg-altmini { width: 1.4rem; height: 1.4rem; }
}

/* ---------- 〈取碼原則〉頁 ---------- */

/* 九條原則的錨點連結，掛在側邊導覽「取碼原則」那個連結底下、縮排一階——
   跟 shurufa.app 那類文件站的側邊欄同一個做法（章節底下掛小節），
   不是另外開一條跳轉列。只有 principles.html 自己的 nav.site 裡有這段 <ul>，
   其他三頁的側邊欄不需要看到這九條連結。 */
.pr-sidenav {
  list-style: none;
  margin: 0 0 .15rem;
  padding-inline-start: 1.1rem;
  display: flex;
  flex-direction: column;
  gap: .05rem;
}
/* 選擇器要比 nav.site a 更明確才贏得過它的 padding／font-size
  （nav.site a 是「一個類＋一個元素」，.pr-sidenav a 只有「兩個類」還不夠，
  這裡直接把 nav.site 也寫進來）。 */
nav.site .pr-sidenav a {
  display: block;
  padding: .15rem .6rem;
  font-size: .68rem;
  color: var(--ink-dim);
}
nav.site .pr-sidenav a:hover { color: var(--ink); background: var(--code-bg); }
/* 小節（h3）在側欄再縮一層，讓「唯一上屏／頂功上屏 屬於 自動上屏」一眼看得出來。
   縮排加在 a 上而不是 li，不然 hover 的底色會缺一角。 */
nav.site .pr-sidenav .is-sub a { padding-inline-start: 1.4rem; }

/* 顏色圖例：紅／黃／綠／藍／紫依序對應拆碼順序第一到第五組，跟例字圖示同一套色階
   （見 .zg-altsvg 的 rb-* class），放在頁面最上面，讀圖之前先講清楚顏色的意思。 */
.pr-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .25rem .9rem;
  font-size: .82rem;
  color: var(--ink-dim);
  margin: 0 0 1rem;
}
.pr-legend-item { display: inline-flex; align-items: center; gap: .35rem; }
.pr-legend-dot { width: .65rem; height: .65rem; border-radius: 50%; display: inline-block; }
.pr-legend-dot.rb-0 { background: var(--rb-0); }
.pr-legend-dot.rb-1 { background: var(--rb-1); }
.pr-legend-dot.rb-2 { background: var(--rb-2); }
.pr-legend-dot.rb-3 { background: var(--rb-3); }
.pr-legend-dot.rb-4 { background: var(--rb-4); }
.pr-legend-dot.rb-5 { background: var(--rb-5); }
.pr-legend-dot.off  { background: var(--zg-off); }

/* 例字拆法對照，同一套 .zg-altsvg／rb-* 色階，只是放大成正文裡的插圖尺寸，
   不是表格小圖示。見 assets/principles.js。
   密度參考 shurufa.app 那類文件站：字級、留白、圖示都比照小圖示表格再縮一點，
   一屏能看到更多內容，不用一直捲。 */
/* 掛式縮排：text-indent 把整行拉回去，讓「1.」永遠貼齊 padding 讓出來的最左邊，
   標題本身的字接在數字後面往右排，跟下面 .pr-body 的內容切齊。改用 text-indent
   而不是 position: absolute——後者要另外處理直排位置，前者是本來就給這種
   「掛式縮排」用的標準寫法，數字寬度不一致時也不會跳來跳去。 */
.pr-page h2 {
  /* 原則名稱一律用 accent 橘（Wilson）——〈原則套用順序〉那七條改成橘色之後，
     上面八條標題也要一起，同一批東西不該兩種顏色。編號 .pr-num 維持淡灰，
     它是序號不是名字。 */
  color: var(--accent);
  /* ⚠️ 不要在這裡改 font-size：節標題的字級全站統一由上面的 h2 決定（Wilson
     2026-08-28：各分頁的標題、副標題字級必須一致）。這裡只調顏色和掛式縮排。 */
  margin: 1.3rem 0 .5rem;
  padding-top: .7rem;
  padding-inline-start: 1.1rem;
  text-indent: -1.1rem;
}
.pr-num { color: var(--ink-dim); }
/* body 的 line-height 是 1.8，正文用還好，但這一頁短句子多、例字方塊本身
   又有留白，1.8 疊起來行距、段落間距都顯得鬆散——這裡另外收緊。 */
.pr-page :where(p:not(.eyebrow), ul, ol) { font-size: .92rem; line-height: 1.5; }
.pr-page p { margin: 0 0 .45rem; }
.pr-page li { margin-bottom: .2rem; }

/* 條文本身（原則說明、例字方塊）縮排一階，跟標題分出主從——原則的名字是標題，
   說明和例字是它底下的內容，不該跟標題齊頭。 */
.pr-body { padding-inline-start: 1.1rem; }

.pr-example {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .8rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .55rem .8rem;
  /* margin-top 跟 h2 的 margin-bottom 一樣（.5rem）——上面段落文字到例字方塊的
     距離，要跟標題到段落文字的距離一樣，兩邊的留白節奏才一致（Wilson）。 */
  margin: .5rem 0 .7rem;
}

.pr-cards { display: flex; gap: .8rem; flex: none; }

.pr-card { display: flex; flex-direction: column; align-items: center; gap: .25rem; }

.pr-icon { position: relative; width: 3.1rem; height: 3.1rem; }
.pr-icon .zg-altsvg { width: 100%; height: 100%; display: block; }

/* 描邊在字根表的小圖示（1.6rem）上是細細一圈分隔線，但這裡的圖示放大到
   3rem 多，同一個 stroke-width（SVG 座標，viewBox 1024）換算成螢幕像素就跟著
   變粗，一堆筆畫疊在一起反而變成惹眼的黑框（Wilson）。改用細很多的描邊，
   放大之後看起來還是一條分隔線，不是一圈黑邊。 */
.pr-icon .zg-altsvg path { stroke-width: 8; }

/* 碼和打勾／打叉放同一行，勾叉在碼右邊——不疊在圖示上，疊上去會蓋住
   角落的筆畫（Wilson，跟辨析表 .zg-altpair 同一個修法）。 */
.pr-coderow { display: flex; align-items: center; gap: .3rem; }

.pr-mark {
  width: 1.05rem;
  height: 1.05rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .62rem;
  font-weight: 700;
  color: #fff;
  flex: none;
}
.pr-card.is-ok .pr-mark  { background: var(--accent); }
.pr-card.is-bad .pr-mark { background: #d1382c; }
/* 還沒判定：留一個虛線空圈佔位。不留的話，勾叉出現的那一刻整張卡片會橫向跳一下 */
.pr-card.is-pending .pr-mark { background: none; border: 1px dashed var(--line); }

.pr-code {
  font-family: ui-monospace, Menlo, monospace;
  font-weight: 700;
  font-size: .82rem;
  letter-spacing: .03em;
  color: var(--ink-dim);
}
.pr-card.is-bad .pr-code { text-decoration: line-through; }

/* 拆法的碼逐字上色，跟圖示的分組顏色對應（見 principles.js 的 card()）——
   rb-N 原本只定義給 SVG fill／圖例圓點用，這裡另外接上文字顏色。錯誤拆法的字母
   調暗（opacity，不是換成灰色），刪除線＋調暗兩個線索一起說「這是不取的示範」，
   但字母顏色仍看得出跟圖示哪一組對應。 */
.pr-code .rb-0 { color: var(--rb-0); }
.pr-code .rb-1 { color: var(--rb-1); }
.pr-code .rb-2 { color: var(--rb-2); }
.pr-code .rb-3 { color: var(--rb-3); }
.pr-code .rb-4 { color: var(--rb-4); }
.pr-code .rb-5 { color: var(--rb-5); }
.pr-code .off  { color: var(--ink-faint); }
.pr-card.is-bad .pr-code span { opacity: .55; }

.pr-text { flex: 1 1 16rem; min-width: 0; margin: 0 !important; color: var(--ink); }
.pr-text code {
  font-family: ui-monospace, Menlo, monospace;
  background: var(--code-bg);
  border-radius: 4px;
  padding: .05rem .3rem;
}

@media (max-width: 34rem) {
  .pr-icon { width: 2.6rem; height: 2.6rem; }
}

/* ---------- 簡碼頁（jianma.html） ---------- */

.jm-conditions {
  font-size: .92rem;
  color: var(--ink-dim);
  line-height: 1.6;
  max-width: var(--measure);
  margin: 0 0 1.4rem;
}

.jm-tbl { font-size: .92rem; }
.jm-tbl th { color: var(--ink-dim); font-size: .82rem; }
.jm-tbl td, .jm-tbl th { white-space: nowrap; }

.jm-char { font-size: 1.2em; font-weight: 600; }
.jm-same { color: var(--ink-faint); cursor: help; }

.jm-groupcount {
  font-size: .68em;
  font-weight: 400;
  color: var(--ink-dim);
  margin-inline-start: .4em;
}

.jm-sortbar {
  display: flex;
  align-items: center;
  gap: .6rem;
  font-size: .82rem;
  color: var(--ink-dim);
  margin: .8rem 0 0;
}

.jm-sortbar-btns {
  display: flex;
  border: 1px solid var(--line);
  border-radius: 999px;
  overflow: hidden;
}

.jm-sortbar-btns button {
  border: 0;
  border-inline-start: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-dim);
  padding: .2rem .7rem;
  cursor: pointer;
  font: inherit;
}

.jm-sortbar-btns button:first-child { border-inline-start: 0; }
.jm-sortbar-btns button:hover { color: var(--ink); }

.jm-sortbar-btns button[aria-pressed="true"] {
  background: var(--accent);
  color: #fff;
}

/* 約定簡碼：六十幾個字擠在一欄要捲很久，橫向空間卻用不完——拆三欄並排（Wilson），
   行距同時收緊，每欄各自完整連續（不是逐行交錯），比較好找字。 */
.jm-cols {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* start，不是預設的 stretch：字數很少整除，最後一欄一定短一兩行，不要為了湊齊
     高度把矮的那欄的列高拉伸——寧可矮一行，也不要各欄的行距對不上（Wilson）。 */
  align-items: start;
  column-gap: 1.4rem;
  margin: 1.4rem 0;
  overflow-x: auto;
}
/* 三欄之後每欄變窄，左右內距跟著收，不然表頭會折行 */
.jm-compact th, .jm-compact td { padding: .28rem 1rem; }

/* ⚠️〈約定字表〉裡整條寬度的組（土／甲字類）自己拆欄時借用 .jm-cols，但那條規則是
   〈簡碼〉頁的**三欄**（約定簡碼表用的）。三欄裡只放兩張表，第二張就落在整條寬度的
   三分之一處，而並排的兩組（大｜目）是各佔一半、第二組落在二分之一處 —— 兩種機制
   的右半邊對不齊，整頁看起來歪歪的（Wilson 2026-08-31 一眼看出來）。
   這一頁改回兩欄，欄距也跟 .cv-grouppair 取同一個值，兩種情況的右半邊才落在同一條
   垂直線上。用 ID 選擇器，權重比 .jm-cols 高，不管檔案裡誰先誰後都贏。 */
#cv-groups .jm-cols {
  grid-template-columns: 1fr 1fr;
  column-gap: 2.5rem;
}

/* 大／目、馬／己兩對字數少的組並排放，省掉上下堆疊的空間（見 conventional.js 的
   SIDE_BY_SIDE_PAIRS）。align-items: start 理由跟 .jm-cols 一樣：兩組字數不同，
   高度本來就不會一樣，不要為了湊高度拉伸列高。 */
.cv-grouppair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: start;
  column-gap: 2.5rem;
}

/* 約定字表的表格（.cv-tbl，見 conventional.js 的 table()）寬度交給內容自己撐開，
   不要撐滿容器：table { width: 100% } 是全站預設，這裡蓋掉。用 max-content 而不是
   auto——.jm-cols／.cv-grouppair 底下表格是 grid 子項（或子項裡的內容），grid 預設
   的 stretch 對齊會把 auto 寬度撐滿整條軌道，max-content 是明確指定的寬度，
   不會被 stretch 蓋過去。（試過 table-layout: fixed 配猜的固定欄寬，兩種版面撐開
   的方式不一樣，一邊還是撐太寬、一邊又擠到表頭要折兩行，改回讓瀏覽器照實際內容
   自己算才穩。） */
.cv-tbl { width: max-content; max-width: 100%; }
.cv-tbl th:nth-child(4), .cv-tbl td:nth-child(4) { padding-inline-start: 0; }

/* 中等寬度先退兩欄，再到窄螢幕才變一欄——三欄硬撐會把表頭擠到折行 */
@media (max-width: 62rem) {
  .jm-cols { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 40rem) {
  .jm-cols { grid-template-columns: 1fr; row-gap: 0; }
  .cv-grouppair { grid-template-columns: 1fr; row-gap: 1.4rem; }
}

/* 左簡碼表的欄位比較擠：偏旁／字母碼／簡碼窄，例字欄放寬並允許換行 */
.jm-leftshort td:nth-child(4),
.jm-leftshort td:nth-child(5) { white-space: normal; }

.jm-leftshort summary {
  cursor: pointer;
  color: var(--accent);
  white-space: nowrap;
}

.jm-members {
  margin-top: .4rem;
  max-width: 28rem;
  font-size: .88rem;
  line-height: 1.7;
  color: var(--ink-dim);
}

/* ---------- 約定字表頁（conventional.html） ---------- *
 * 字形圖示欄跟「單獨成字」碼的逐字上色是同一個開關：#cv-groups 有沒有 .cv-color
 * 這個 class，由 conventional.js 的顏色開關按鈕控制（見該檔開頭註解）。 */

.cv-icon-col { display: none; }
.cv-color .cv-icon-col { display: table-cell; }

.cv-icon {
  display: inline-block;
  width: 1.6rem;
  height: 1.6rem;
  vertical-align: middle;
}
.cv-icon .zg-altsvg { width: 100%; height: 100%; display: block; }

.cv-color .jm-tbl code .rb-0 { color: var(--rb-0); }
.cv-color .jm-tbl code .rb-1 { color: var(--rb-1); }
.cv-color .jm-tbl code .rb-2 { color: var(--rb-2); }
.cv-color .jm-tbl code .rb-3 { color: var(--rb-3); }
.cv-color .jm-tbl code .rb-4 { color: var(--rb-4); }
.cv-color .jm-tbl code .rb-5 { color: var(--rb-5); }
.cv-color .jm-tbl code .off  { color: var(--ink-faint); }


/* 章節清單的收合箭頭。整排（連結＋箭頭）是一個 flex 列，連結照樣佔滿剩下的
   寬度，所以目前頁面那塊底色與左邊的橙色框線看起來跟改之前一樣。
   箭頭本身是 CSS 畫的三角形（border 那一招），收起來時轉 -90°。 */
.pr-navhead { display: flex; align-items: stretch; }
.pr-navhead > a { flex: 1; min-width: 0; }

.pr-toggle {
  flex: none;
  width: 1.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--ink-faint);
  cursor: pointer;
}
.pr-toggle:hover { color: var(--ink); background: var(--code-bg); }
.pr-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.pr-toggle::before {
  content: "";
  width: 0; height: 0;
  border-inline: .3rem solid transparent;
  border-top: .34rem solid currentColor;
  transition: transform .15s ease;
}
.pr-toggle[aria-expanded="false"]::before { transform: rotate(-90deg); }

@media (prefers-reduced-motion: reduce) {
  .pr-toggle::before { transition: none; }
}

/* ---------- 拆碼查詢 ---------- */

/* 兩個查法擺在同一塊面板裡，跟〈線上試打〉那個面板同一個長相（surface 底、
   一條細框、同一個圓角）—— 這一頁跟試打頁是同一組「動手玩玩看」的工具，
   看起來就該是一家人（Wilson）。 */
.cm-panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem 1.2rem;
  margin: 0 0 1.5rem;
  max-width: var(--measure);
}

/* 拼音短、貼字長，所以貼字那個吃掉剩下的寬度。窄螢幕自己換行（flex-wrap），
   不必另寫斷點。 */
.cm-inputs { display: flex; flex-wrap: wrap; gap: 1rem; }
.cm-field { display: flex; flex-direction: column; gap: .4rem; flex: 1 1 12rem; }
.cm-field-wide { flex: 2.4 1 22rem; }

.cm-field label {
  font-size: .8rem;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: .04em;
}

/* 框要大、要好按 —— 這一頁除了打字就沒別的事做（Wilson：要更 inviting）。
   ⚠️ 字級分開寫，不要用 `font:` 簡寫配 inherit，那整條會被丟掉（試打頁那個
   textarea 就是這樣被吃掉三次才查出來，見 .typebox textarea 的註）。 */
.cm-in {
  width: 100%;
  box-sizing: border-box;
  padding: .75rem .85rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  color: var(--ink);
  font-family: inherit;
  font-size: 1.05rem;
  line-height: 1.7;
  transition: border-color .15s ease, box-shadow .15s ease;
}
input.cm-in { height: 3.1rem; }
textarea.cm-in { min-height: 5.4rem; resize: vertical; }

.cm-in:hover { border-color: var(--accent); }
.cm-in:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.cm-in::placeholder { color: var(--ink-faint); opacity: 1; font-size: .88rem; }

@media (prefers-reduced-motion: reduce) {
  .cm-in { transition: none; }
}

/* 顯示選項那一排，沿用試打頁的 .short-toggle／.chk-toggle，不另開一套長相 */
.cm-opts {
  display: flex;
  flex-wrap: wrap;
  /* 組與組之間拉開到 2.6rem：三組各有自己的小標（大小／套用簡碼／顯示），
     組內的間距是 1.1rem（.short-toggle 的 gap），組間要明顯大過它，才看得出
     哪個勾選格歸哪個小標管（Wilson）。 */
  gap: .5rem 2.6rem;
  align-items: center;
  margin-top: 1rem;
  padding-top: .9rem;
  border-top: 1px solid var(--line);
}

/* ⚠️ 兩組開關要對齊在同一條線上。.short-toggle 那一套是給試打頁**上下堆疊**用
   的，帶了 margin-bottom: .8rem，第二排還多一條 `.short-toggle + .short-toggle
   { margin-top: -.35rem }`（讓第二排貼著第一排走）。在這裡是橫排，那個負的上外
   距把第二組整個往上提，兩組中線差 2.8px（實測 g0 top=369.1、g1 top=366.3，
   g1 的 computed margin-top 是 -5.6px）。
   ⚠️ 第二條選擇器不能只寫 `.cm-opts > .short-toggle` —— 那跟 `.short-toggle +
   .short-toggle` 同樣是兩個 class 的權重，而後者排在這個檔案後面，後來者贏，
   歸零完全沒有作用。要把相鄰選擇器整條寫出來才蓋得過去。 */
.cm-opts > .short-toggle,
.cm-opts > .short-toggle + .short-toggle { margin: 0; }

/* 拆碼圖關掉時，「字根顏色」跟著失效 —— 淡掉並換成不可點的游標，讓「現在
   按不動」看得出來，而不是按了沒反應。 */
.cm-opts .chk-toggle.is-off { opacity: .45; cursor: not-allowed; }
.cm-opts .chk-toggle.is-off input { cursor: not-allowed; }

/* 勾選格／圓鈕本身也要跟旁邊的字對齊：瀏覽器給 input 的預設外距是上下不對稱的
   （上 3px、下 0），在 align-items: center 底下會把控制項壓低約 1.5px。
   只在這一頁歸零，不動試打頁既有的長相。 */
.cm-opts .chk-toggle input { margin: 0; }

/* 卡牆：一個字一張。auto-fill 讓一行塞得下幾張就幾張，窄螢幕自己掉成幾張、
   一張，不必為它另寫斷點。欄寬與碼格大小綁在一起（見下面三個尺寸），因為
   「五個字母的碼不准換行」這條要求是靠兩者的比例撐住的。 */
.cm-wall {
  display: grid;
  gap: .9rem .6rem;
  align-items: start;
  max-width: var(--measure);
  margin: 0 0 .8rem;
}

.cm-card { position: relative; display: flex; flex-direction: column; align-items: center; gap: .35rem; }

/* 右上角的簡碼角標。約定簡碼用主色、三簡碼用比較安靜的灰 —— 約定簡碼是人挑
   出來的少數常用字，值得比自動規則搶眼一點。
   底色用 --surface 而不是透明：角標會壓在田字格的筆畫上，透明會糊成一團。 */
.cm-tag {
  position: absolute;
  top: -.2rem;
  inset-inline-end: -.2rem;
  z-index: 1;
  /* 圓的（Wilson）：寬高相等＋50% 圓角。字擺正靠 flex 置中，不要靠 line-height
     去湊 —— 中文字的字面在行高裡本來就不置中，湊出來的圓永遠偏一點。 */
  width: 1.05rem;
  height: 1.05rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: .56rem;
  line-height: 1;
  color: var(--surface);
  background: var(--ink-faint);
}
/* 約定簡碼用主色，三簡碼用安靜的灰 —— 約定簡碼是人挑出來的少數常用字，
   值得比自動規則搶眼一點。 */
.cm-tag.is-conv { background: var(--accent); }

/* 約定字角標：這個字不是照筆畫拆的，是取碼原則第 8 條「約定俗成」整字
   認的（見〈約定字表〉，跟上面 is-conv／約定簡碼是兩件事——一個是「這個字
   本身怎麼取碼」，一個是「這個字有沒有更短的簡碼」，字面都帶「約定」但
   講的不是同一條規則，不要混用同一個角標）。
   跟簡碼角標同一側（右上），預設就佔右上角那個位置——一張卡通常只有
   一顆角標，沒有簡碼角標時約定角標不必讓位。只有兩顆都要出現時
   （.is-bumped，chaima.js 判斷這個字同時有簡碼又是約定字才加這個 class）
   才把約定角標往下推，接在簡碼角標下面，兩顆才不會疊在一起
   （Wilson：預設要在右上角，兩顆都有才往下擠）。放左上角會讓人以為是
   **左邊那張卡**的角標，卡牆是一排一排排的，左上角天生容易被讀成
   「上一張卡的註記溢出來」，所以跟簡碼角標同一側。 */
.cm-tag.is-except {
  top: -.2rem;                  /* 預設＝簡碼角標原本的位置（那顆角標不在時） */
  /* ⚠️ 試過 writing-mode:vertical-rl 直接讓文字直書，但那個屬性配上
     position:absolute 在多數瀏覽器上有已知的高度計算問題（量過：108px，
     兩個字不可能那麼高，換掉 display 也一樣）。改用最土的辦法：兩個字
     中間塞一個 <br>，兩行字疊起來，效果一樣是窄窄一條，但不會踩到那個
     邊角案例。 */
  display: block;
  /* 寬度跟圓形的簡碼角標一樣（1.05rem），兩顆角標才會正中對齊——
     兩個都是 inset-inline-end:-.2rem（右邊對齊），寬度不一樣的話中心點
     會左右錯開（Wilson：兩顆角標沒有對齊）。 */
  width: 1.05rem;
  height: auto;
  padding: .12rem 0;
  line-height: 1.15;
  text-align: center;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--accent);
  color: var(--accent);
}
.cm-tag.is-except.is-bumped { top: 1rem; }   /* 簡碼角標佔 -.2rem 到 .85rem，這裡接著排 */
.cm-wall.is-lg .cm-tag { width: 1.3rem; height: 1.3rem; font-size: .7rem; }
.cm-wall.is-lg .cm-tag.is-except { width: 1.3rem; height: auto; padding: .18rem 0; }
.cm-wall.is-lg .cm-tag.is-except.is-bumped { top: 1.25rem; }
.cm-wall.is-sm .cm-tag.is-except { width: .92rem; height: auto; padding: .08rem 0; }
.cm-wall.is-sm .cm-tag.is-except.is-bumped { top: .85rem; }
.cm-wall.is-sm .cm-tag { width: .92rem; height: .92rem; font-size: .5rem; }
.cm-foot { display: flex; justify-content: center; }

/* ⚠️ 碼一律排成一行，不准折行（Wilson）。主碼最長就是五個字母（實測 dict.json：
   1–5 碼，五碼的有 3097 個字），所以每個尺寸的欄寬都是照「五格排得下」倒推的。

   ⚠️ 縮小的時候縮的是**格子的寬度與內距，不是字級**（Wilson：小尺寸也要看得清
   楚碼）。.tz-chip 預設 min-width 是 1.5rem，對單一個大寫字母來說很寬鬆，先砍
   這裡就能在字級幾乎不動的情況下把整排收窄。三個尺寸的字級是 .85 / .72 / .66rem
   ——最小的那一級也還在看得清楚的範圍，之前照比例縮成 .46rem 是不能讀的。 */
.cm-wall .tz-hintcodes { flex-wrap: nowrap; gap: var(--cm-chip-gap); }
.cm-wall .tz-chip {
  font-size: var(--cm-chip-fs);
  min-width: var(--cm-chip-w);
  padding: var(--cm-chip-pad);
  border-radius: 3px;
}

/* 大：一行六個上下（正文寬 54.8rem） */
.cm-wall.is-lg {
  grid-template-columns: repeat(auto-fill, minmax(8.4rem, 1fr));
  --cm-chip-fs: .85rem; --cm-chip-w: 1.2rem; --cm-chip-pad: .06rem .16rem; --cm-chip-gap: .16rem;
}
.cm-wall.is-lg .tianzi { max-width: 8.4rem; }
.cm-wall.is-lg .tianzi .tz-fallback { font-size: 4.4rem; }

/* 中：一行九個上下 */
.cm-wall.is-md {
  grid-template-columns: repeat(auto-fill, minmax(5.8rem, 1fr));
  --cm-chip-fs: .78rem; --cm-chip-w: .8rem; --cm-chip-pad: .03rem .1rem; --cm-chip-gap: .08rem;
}
.cm-wall.is-md .tianzi { max-width: 5.8rem; }
.cm-wall.is-md .tianzi .tz-fallback { font-size: 3rem; }

/* 小：一行十一個上下。字級只比大號小 .11rem —— 縮的是田字格，不是碼（Wilson
   兩次要求把小尺寸的碼再放大）。碼那一排因此會比田字格略寬一點點（4.6 對
   4.4rem），往兩側各溢出約 .1rem，欄距有 .6rem，不會撞到隔壁。 */
.cm-wall.is-sm {
  grid-template-columns: repeat(auto-fill, minmax(4.4rem, 1fr));
  --cm-chip-fs: .74rem; --cm-chip-w: .72rem; --cm-chip-pad: .02rem .08rem; --cm-chip-gap: .05rem;
}
.cm-wall.is-sm .tianzi { max-width: 4.4rem; }
.cm-wall.is-sm .tianzi .tz-fallback { font-size: 2.2rem; }

/* 沒有拆碼圖的字：同一種碼格，但配不出顏色，所以整排中性深灰（Wilson）。
   --ink-dim 在深淺主題各有值，配 .tz-chip 的 --surface 字色，兩邊對比都在
   5.5:1 以上，不必為深色主題另寫一條。 */
.tz-chip.is-plain { background: var(--ink-dim); }

/* 關掉字根顏色：筆畫與碼一律用正文的墨色。
   ⚠️ 碼不是換個底色，是**整個色塊拿掉**（Wilson）—— 反白的字母格本身就是在
   說「這一格屬於某一條字根」，沒有顏色資訊的時候還留著格子，等於留下一個沒有
   意義的裝飾。拿掉之後就是一串深色字母，該說的都說了。
   ⚠️ 用 --ink（#1c2322，很深的灰）而不是純黑（Wilson）—— 全站的正文都是這個
   色，這裡寫死 #000 會比周圍的字還重。 */
.cm-wall.is-mono .tianzi .tz-z0,
.cm-wall.is-mono .tianzi .tz-z1,
.cm-wall.is-mono .tianzi .tz-z2,
.cm-wall.is-mono .tianzi .tz-z3,
.cm-wall.is-mono .tianzi .tz-z4,
.cm-wall.is-mono .tianzi .tz-z5 { fill: var(--ink); }
.cm-wall.is-mono .tz-chip {
  background: none;
  color: var(--ink);
  padding-inline: 0;
  min-width: 0;
}
/* 沒有色塊就不需要色塊的縫（Wilson）。彩色模式的 gap 是為了讓相鄰兩塊顏色
   分得開；拿掉色塊之後，那個縫變成字母之間的空白 —— 實測每格字母只有 7.5px，
   縫卻有 3.2px，等於字寬的四成，整串碼散成一個一個字母。
   改成 gap 歸零、改用 letter-spacing 撐開一點點：它跟著字級走，三個尺寸都不
   用各調一次。 */
.cm-wall.is-mono .tz-hintcodes { gap: 0; }
.cm-wall.is-mono .tz-chip { letter-spacing: .1em; padding-inline: .04em; }

/* 沒有被任何字根取到的筆畫（主要是「頭四尾一」略過的那幾段）本來畫成正文墨色，
   在這一頁改成跟「簡碼略過」同一個淺灰（Wilson）—— 兩者是同一件事的兩種說法：
   「這幾筆你不用打」。用兩種顏色講同一句話，只會讓人以為它們不一樣。
   ⚠️ 選擇器要三個 class 才蓋得過 `.tianzi .tz-ink`（兩個 class，而且排在這條
   後面）—— 這個檔案裡已經為了同樣的理由踩過兩次。 */
.cm-wall .tianzi .tz-ink { fill: var(--zg-off); }

/* 「顯示簡碼」淡掉的碼格：簡碼沒用到的那幾條字根。整條碼照樣看得見，只是
   退到背景去 —— 拿走的話就看不出簡碼是從哪裡簡出來的（Wilson）。
   用 opacity 而不是換顏色：六種字根色各有各的深淺，統一調透明度才會一致淡。 */
.cm-wall .tz-chip.is-dim { opacity: .28; }
.cm-wall.is-mono .tz-chip.is-dim { opacity: .34; }

/* 純文字的字：有拆碼圖的時候不需要它（格子裡就是那個字），關掉才出場。
   關掉之後卡片只剩「字＋碼」，欄寬跟著縮一半，一行塞得下更多。 */
.cm-ch { display: none; font-size: 1.5rem; line-height: 1.2; color: var(--ink); }
.cm-wall.is-nogrid .tianzi { display: none; }
.cm-wall.is-nogrid .cm-ch { display: block; }

/* 沒有田字格的時候，字與它的碼要**貼緊**，行與行之間反而要拉開（Wilson）：
   格子不在了，字跟碼之間就沒有東西界定「這兩個是一組」，靠的全是遠近 ——
   碼離自己的字太遠、離下一行的字太近，讀起來會黏到下一行去。 */
.cm-wall.is-nogrid { row-gap: 1.6rem; }
.cm-wall.is-nogrid .cm-card { gap: .1rem; }
.cm-wall.is-nogrid { grid-template-columns: repeat(auto-fill, minmax(3.2rem, 1fr)); }
.cm-wall.is-nogrid.is-lg { grid-template-columns: repeat(auto-fill, minmax(5rem, 1fr)); }
.cm-wall.is-nogrid.is-lg .cm-ch { font-size: 2.1rem; }
.cm-wall.is-nogrid.is-sm { grid-template-columns: repeat(auto-fill, minmax(2.6rem, 1fr)); }
.cm-wall.is-nogrid.is-sm .cm-ch { font-size: 1.15rem; }

.cm-none { font-size: .62rem; color: var(--ink-faint); }
.cm-card.is-none .tianzi { opacity: .55; }

.cm-none { font-size: .72rem; color: var(--ink-faint); }
.cm-card.is-none .tianzi { opacity: .55; }

.cm-note { font-size: .82rem; color: var(--ink-dim); max-width: var(--measure); }

/* ---------- 窄螢幕：導覽改回頂部橫列 ----------
   側邊欄在手機上會吃掉一半可用寬度，所以在這個斷點還原成原本的橫列。
   字根表那幾層黏頂的 top 也要跟著改回讓開頁首的值。 */
@media (max-width: 52rem) {
  .topbar {
    position: sticky;
    inset: 0 auto auto 0;
    width: auto;
    border-inline-end: 0;
    border-bottom: 1px solid var(--line);
    overflow: visible;
  }

  .topbar .wrap {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 1.1rem;
    padding: .5rem 1.4rem;
    min-height: 3.4rem;
    flex-wrap: wrap;
  }

  /* 窄螢幕：品牌 → 導覽連結 → 繁簡／字級，橫排。桌面版的 DOM 順序是品牌／控制項／
     導覽（控制項擺在「AiPhaBi」下面），這裡用 order 把控制項挪到橫列最右側，
     不用改 HTML 順序。 */
  nav.site { flex-direction: row; width: auto; gap: 1rem; margin-inline-end: auto; order: 1; }
  nav.site a { padding: .2rem 0; border-radius: 0; border-inline-start: 0;
               border-bottom: 2px solid transparent; }
  nav.site a[aria-current="page"] { background: none; border-bottom-color: var(--accent); }
  /* 橫列裡沒有「上下分組」這回事：display:contents 讓 .nav-sec 自己從版面消失，
     組員直接變成橫列的項目，排出來跟沒分組時一模一樣。 */
  .nav-sec { display: contents; }
  .nav-sec-t { display: none; }
  nav.site .nav-sec > a,
  nav.site .nav-sec > .pr-navhead > a { padding-inline-start: 0; }
  .brand .en { display: inline; margin-inline-start: .45em; }
  /* 橫列的頁首只有一行高，圖示跟著收小一點，不然它比整行字還高 */
  .brand-logo { width: 1.6rem; height: 1.6rem; }

  .topbar-controls { order: 2; flex-direction: row; align-items: center; gap: .7rem; }
  .zg-size, .topbar-controls .zg-size { flex-direction: row; align-items: center; gap: .35rem; }

  body { padding-inline-start: 0; }

  .zg-jump { top: 3.4rem; }
  .zg-tbl thead th { top: 5.9rem; }
  .zg-tbl tbody tr { scroll-margin-top: 8.5rem; }
  #zg-similar { scroll-margin-top: 6.5rem; }

}


/* 〈取碼原則〉：拆法標籤（川 的 A／B／C），讓正文指名討論時對得上。
   排在字的**上方**、不疊在圖示上 —— 絕對定位會蓋住角落的筆畫，
   跟打勾／打叉當初移到碼旁邊是同一個理由。 */
.pr-label {
  display: block;
  text-align: center;
  margin-bottom: .25rem;
  font: 700 .74rem ui-monospace, Menlo, monospace;
  color: var(--ink-faint);
  letter-spacing: .04em;
}


/* 〈取碼原則〉的完整示範：逐條原則的檢驗過程 */
.pr-walk { margin: 1.4rem 0; }
.pr-walk dt {
  font-weight: 600;
  margin-top: 1rem;
  color: var(--accent);
  font-size: .95rem;
}
.pr-walk dd { margin: .3rem 0 0; padding-inline-start: 0; }

/* 編號改用 counter ＋ 絕對定位，不用瀏覽器的 list marker。
   原因：這個 li 的第一個子元素是 block（橘色的原則名稱），而「marker 遇到 block
   子元素要怎麼擺」各家瀏覽器不一樣 —— Chrome 量到名稱和說明都切齊 li 的內容左緣，
   Wilson 那邊看到的卻是名稱被 marker 往右推、說明留在左緣，兩行對不齊。
   自己畫編號就沒有這個問題：名稱和說明都是正常的區塊，左緣一定一致。 */
.pr-order {
  list-style: none;
  counter-reset: pr-order;
  padding-inline-start: 2rem;
}
.pr-order > li {
  counter-increment: pr-order;
  position: relative;
  margin-bottom: .6rem;
}
.pr-order > li::before {
  content: counter(pr-order) ".";
  position: absolute;
  inset-inline-start: -2rem;
  width: 1.6rem;
  text-align: end;
  color: var(--ink-dim);
}

/* 補充討論：比正文淡一階，是「有人可能會問」那種旁註 */
.pr-aside {
  margin-top: 1.6rem;
  padding: .9rem 1.1rem;
  background: var(--code-bg);
  border-inline-start: 3px solid var(--line);
  border-radius: 0 var(--radius) var(--radius) 0;
  color: var(--ink-dim);
  font-size: .92rem;
}


/* ---------- 〈取碼原則〉的逐步示範（川） ----------
   三張拆法卡片一開始不掛勾叉，走到淘汰它的那一條原則時才打叉（Wilson：先掛好
   等於先把答案講了）。卡片黏在頂端，因為讀到第 5 條原則時卡片早就捲出畫面，
   而每一步要看的正是卡片上的變化。 */
.pr-walkbox { margin: .5rem 0 1.6rem; }

/* 黏頂的是外層而不是 .pr-example 本身：外層鋪一層底色，把捲到底下的內文遮住，
   不然文字會從卡片邊框和圓角的縫隙裡透出來（跟 .zg-jump 同一個做法）。 */
.pr-sticky {
  position: sticky;
  top: 0;
  z-index: 4;
  background: var(--bg);
  padding-block: .5rem;
}
.pr-sticky .pr-example { margin: 0; }

.pr-steps {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin-top: .45rem;
  font-size: .85rem;
}
.pr-stepbtn {
  font: inherit;
  color: var(--accent);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .2rem .6rem;
  cursor: pointer;
}
.pr-stepbtn:hover:not(:disabled) { border-color: var(--accent); }
.pr-stepbtn:disabled { color: var(--ink-faint); cursor: default; opacity: .6; }
.pr-stepnow { color: var(--ink-faint); font-variant-numeric: tabular-nums; }

/* 目前這一步：左邊一條 accent 直線。還沒走到的步驟調淡——調淡而不是收起來，
   想整頁讀完或列印的人還是看得到全文。 */
.pr-walk[data-stepper] dt { cursor: pointer; }
.pr-walk dt.is-now {
  border-inline-start: 3px solid var(--accent);
  padding-inline-start: .55rem;
  margin-inline-start: -.58rem;
}
.pr-walk .is-later { opacity: .45; }
.pr-walk dt, .pr-walk dd { transition: opacity .18s ease; }

@media (max-width: 52rem) {
  .pr-sticky { top: 3.4rem; }     /* 窄螢幕的導覽改回黏在頂端，要讓開它 */
}

@media (prefers-reduced-motion: reduce) {
  .pr-walk dt, .pr-walk dd { transition: none; }
}

/* 還沒「登場」的拆法：三種拆法是〈筆順原則〉那一步才推出來的，在那之前整個方塊
   都不出現（Wilson）。用 display:none 而不是 visibility——留著空位等於還是先告訴
   讀者「等一下會有三個東西」。 */
.pr-card.is-unborn, .pr-example.is-unborn { display: none; }

/* 判定為錯的拆法：**筆畫也一起淡掉**，不是只有底下的碼淡掉（Wilson）。
   用的就是碼那邊本來已經在用的手法（.pr-code span 的 opacity: .55），同一個值，
   兩邊看起來才是同一件事。顏色留著不動 —— 分組是靠顏色看的，而「哪幾筆併成
   一組」正是這張卡片要講的事（拆法 B 被否掉就是因為它把第 1、2 筆併成一組）。 */
.pr-card.is-bad .pr-icon { opacity: .55; }

/* 逐步示範第 1、2 步的原字：沒上色、沒有碼，就是這個字本身。
   高度比後面三張卡片矮（少了標籤和碼那兩行），補上等高的留白，換到第 3 步時
   方塊不會忽然抽高一截 —— 它是黏在頂端的，抽高會把整段內文往下推。 */
.zg-altsvg path.ink { fill: var(--ink); }
.pr-card.is-plain { padding-block: .9rem; }

/* 〈原則套用順序〉：原則名稱自成一行、說明另起一行（Wilson）。
   名稱後面的「：」跟著拿掉 —— 冒號掛在行尾沒有東西接，看起來像斷句斷掉了。
   顏色比照〈完整示範〉那邊逐條原則的 dt，兩處講的是同一批原則。 */
.pr-order > li > .pr-rule {
  display: block;
  color: var(--accent);
  font-weight: 600;
  margin-bottom: .1rem;
}

/* ── 試打頁的「跟著打」：參考文章 + 田字格 ─────────────────────────
 * 左邊是文章、右邊是田字格，格子裡是**下一個要打的字**。
 * 窄螢幕時田字格移到文章上面 —— 它是主角，不該被擠到捲軸底下。 */
.tryarea {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 13rem;
  gap: 1.4rem;
  /* 兩欄一起拉到同高：右欄（田字格＋提示）因此拿得到整個左欄的高度，
     提示要多長都放得下，也不會反過來把面板撐高。 */
  align-items: stretch;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* 上緣收窄（Wilson）：標題到面板、面板到「試打文本」都少一點空白。
     上外距歸零，標題與面板之間就只剩 .h1-tight 的下外距（.5rem）—— 兩個外距
     會合併，留著較大的那個，所以只改一邊沒有用。 */
  padding: .85rem 1.2rem 1.2rem;
  margin: 0 0 1.4rem;
}

/* practice.json 沒產出來時 JS 會加這個 —— 收成單欄，只剩試打框
   （見 try.js setupPractice；載入之後兩個模式都是兩欄，不會再收回單欄）。 */
.tryarea.is-plain { grid-template-columns: minmax(0, 1fr); }

/* 模式切換那排橫跨兩欄、自己佔一整列（見 try.html 裡它是 .tryarea 的第一個
   子元素，不在 .tryarea-main 裡）——這樣試打文本／自由試打切換時，左欄的
   試打框跟右欄的內容（田字格或拼音查字）永遠從同一條線開始，不會因為模式
   不同而跳來跳去（Wilson：拼音查字框的上緣要跟試打框切齊）。 */
.try-mode { grid-column: 1 / -1; margin: 0 0 .8rem; }

/* 簡碼／三簡碼開關：兩組各一顆的獨立開關（不是一組互斥的兩顆），跟模式
   切換一樣橫跨兩欄、貼在它下面。 */
.short-toggle {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  /* 三組開關（簡碼／詞組／自動上屏）擠不下時整組換行，不要讓標籤自己斷成兩行
     ——「套用簡／碼」那樣斷開之後，看不出哪個標籤管哪幾個勾選格。 */
  flex-wrap: wrap;
  gap: .55rem 1.1rem;
  font-size: .82rem;
  color: var(--ink-dim);
  margin: 0 0 .8rem;
}
.short-toggle > span,
.short-toggle .chk-toggle,
.short-toggle-link { white-space: nowrap; }

.chk-toggle {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  cursor: pointer;
}

.chk-toggle input[type="radio"],
.chk-toggle input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--accent);
  cursor: pointer;
}

/* 〈跟著打〉的一格是一個詞時，詞裡打到哪個字由〈下一個〉那行的 .tz-unit 顯示
   （打完的淡、正在打的用主色）。文章框裡本來也在那個字底下畫一條底線
   （.pc.is-here），Wilson 說文本不要有底線，已拿掉 —— 同一件事講一次就夠。
   （提示區上面本來還有一條攤開整串的 .tz-word，一樣是多餘，也拿掉了。） */

.tz-unit { display: inline-flex; gap: .05em; }
.tz-unit .is-done { color: var(--ink-faint); }
.tz-unit .is-now  { color: var(--accent); }

.word-badge {
  font-size: .68rem;
  color: var(--ink-dim);
  background: var(--code-bg);
  border-radius: 999px;
  padding: .05rem .4rem;
}

/* 設定分兩排（簡碼／流暢模式）之後，同一排裡不再需要分隔線 —— 換行本身就是
   分隔。第二排貼著第一排走，中間不要留一整個段落的空白。 */
.short-toggle + .short-toggle { margin-top: -.35rem; }

/* 詞組詞庫的狀態（載入中／失敗／收了幾個詞）。這是這一排唯一會等待的開關，
   沒有這句話，打開之後還沒有詞候選會看起來像壞掉。 */
.short-toggle-note {
  font-size: .78rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.short-toggle-note.is-bad { color: var(--warn); }

/* 自動上屏那組旁邊的說明連結。這一排本來全是開關，唯獨這個功能光看名字看不出
   在做什麼（「即時頂」不是常用詞），所以直接把說明頁擺在手邊。 */
.short-toggle-link {
  font-size: .78rem;
  color: var(--accent);
  /* 貼著前面那個選項走 —— 整排的 gap 是 1.1rem，照那個距離看起來像獨立的一項，
     而它其實是「單字上屏」的附註（Wilson）。 */
  margin-inline-start: -.75rem;
}

/* 這一頁的大標題貼著底下的試打區 —— 中間那塊空白沒有作用，擠掉可以讓按鍵指南
   在同一畫面上多露一列（Wilson）。 */
.h1-tight { margin-bottom: .5rem; }

/* 左欄是直排：參考文章 → 進度列 → 試打框 → 候選列 */
.tryarea-main { display: flex; flex-direction: column; min-height: 0; }

.practice-head { display: flex; align-items: baseline; gap: .8rem; flex-wrap: wrap; flex: none; }
.practice-head h2 { margin: 0; color: var(--accent); }
.practice-src { margin: 0; font-size: .8rem; color: var(--ink-faint); }

.practice-text {
  margin-top: .8rem;
  /* 固定高度（Wilson）：試打框現在就在同一欄的下面，文章框不再吃掉剩餘空間，
     不然試打框會被擠到看不見。要多讀幾行就捲這一格。
     6.5rem 剛好三行（行高 27.5px × 3 ＋ 上下 padding .6rem ＋ 框線）—— 從五行收成
     三行是為了讓底下的按鍵指南在同一畫面上多露一點。 */
  /* 5.7rem 是量出來的：剛好三行，第四行整個看不到。
     ⚠️ 不要照「3 × 行高 ＋ padding」算 —— CJK 行框有 half-leading，字面比行框矮，
     照算出來的 6.5rem 會讓第四行的字頭露出來（Wilson 說「3.5 行很難看」）。
     改了字級或行高就重新量一次，別重算。 */
  height: 5.7rem;
  overflow-y: auto;
  line-height: 1.95;
  font-size: .88rem;
  padding: .6rem .7rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  flex: none;
}

/* 一個字一格，格子要比字大一點 —— 不然底色貼著筆畫，看起來像壓在字上而不是
   框住字（Wilson）。作法是文章整體加字距，再把那道字距分一半到字的左邊：
   letter-spacing 加出來的空白算在**前一個字的 span 裡**（跟在字後面），所以
   只加字距的話底色會右邊寬、左邊貼死。padding-left 補左邊、負 margin 把它拉
   回原位，字就回到格子正中間，相鄰兩格照樣接得起來（差的那一點是重疊，不是縫）。 */
.practice-text { letter-spacing: .16em; }
.practice-text .pc {
  padding: .12em 0 .12em .16em;
  margin-inline-start: -.16em;
  border-radius: 3px;
  cursor: pointer;
}
.practice-text .pc:hover { background: var(--accent-soft); }
.practice-text .pc.is-done { color: var(--ink-faint); }
/* 目前這一格：底色而不是外框 —— 外框會讓那一個字比左右鄰居寬，整行跳一下 */
/* 圓角歸零是為了下面那兩條：一格是一個詞（詞組開著）的時候，那幾個字要連成
   一塊底色，不是一字一塊 —— 每個字各自收圓角會在字與字之間切出缺口。圓角只
   收在整塊的兩端，.is-wl／.is-wr 由 renderPractice 標。 */
.practice-text .pc.is-now {
  background: var(--accent); color: var(--surface); border-radius: 0;
}
.practice-text .pc.is-now.is-wl { border-top-left-radius: 3px; border-bottom-left-radius: 3px; }
.practice-text .pc.is-now.is-wr { border-top-right-radius: 3px; border-bottom-right-radius: 3px; }

.practice-bar {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-top: .7rem;
  flex: none;
}
.practice-prog {
  font-family: ui-monospace, Menlo, monospace;
  font-size: .8rem; color: var(--ink-dim); margin-inline-end: auto;
}
.practice-tip { font-size: .75rem; color: var(--ink-faint); }

/* 進度長條：跟旁邊的「X / Y　Z%」文字講同一件事，用寬度再視覺化一次——
   數字要心算，長條一眼看出走了多遠（Wilson：想在百分比底下加一條）。
   寬度用 inline style 直接設，transition 讓它跟著打字平滑地長，不是跳一下。 */
.practice-progbar {
  width: 100%;
  height: .35rem;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
  margin-top: .5rem;
}
.practice-progbar-fill {
  height: 100%;
  width: 0%;
  background: var(--accent);
  border-radius: inherit;
  transition: width .25s ease-out;
}

/* 篇目選單：一篇一顆，現在這篇用主色實心標出來 */
.practice-pick { display: inline-flex; gap: .3rem; margin-inline-start: auto; }
.practice-pickbtn {
  font: inherit; font-size: .78rem;
  padding: .18rem .7rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg);
  color: var(--ink-dim);
  cursor: pointer;
}
.practice-pickbtn:hover { border-color: var(--accent); color: var(--accent); }
.practice-pickbtn[aria-pressed="true"] {
  background: var(--accent); border-color: var(--accent); color: var(--surface);
}
.practice-btn {
  font: inherit; font-size: .82rem;
  padding: .25rem .8rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg);
  color: var(--ink-dim);
  cursor: pointer;
}
.practice-btn:hover { border-color: var(--accent); color: var(--accent); }

.practice-cell { text-align: center; }

/* 田字格：外框＋十字虛線，跟標註頁那個一樣。筆畫一律 --ink，不上色 ——
 * 這裡講的是「這個字長這樣」，不是在講字根，上色會讓人以為顏色有意思。 */
.tianzi { position: relative; width: 100%; max-width: 13rem; margin-inline: auto; }
.tianzi svg { display: block; width: 100%; height: auto; }
.tianzi .tz-grid {
  stroke: var(--line); stroke-dasharray: 14 14; stroke-width: 2; fill: none;
}
.tianzi .tz-ink { fill: var(--ink); }
/* 標點跟沒有字形資料的字：退回系統字型，疊在格子中央 */
.tianzi .tz-fallback {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 5.5rem; color: var(--ink); line-height: 1;
}

/* 四碼快打：一格是三字以上的詞時，那一個田字格換成四個四分之一大的小格
 * （見 try.js drawQuad）。一小格一碼，四個字母連起來就是要打的四碼。
 * 小格照樣沿用 .tianzi 底下那幾條（格線、tz-ink、tz-z*、tz-fallback），
 * 這裡只管排版 —— 顏色改一次全站一起改，不要在這裡另開一組。 */
/* 已經揭了碼的小格裡，沒被取到的筆畫：跟〈字根表〉〈詞組〉頁的「不是這一條」
   同一個灰。深淺主題各有值，所以這裡不要寫死顏色。 */
.tianzi .tz-off { fill: var(--zg-off); }
.tz-quad { display: grid; grid-template-columns: 1fr 1fr; gap: .3rem .4rem; }
.tz-q { position: relative; }
/* 三字詞只有三格（第四碼是第三個字的末碼，畫在它自己那一格裡）。
   最後一格橫跨底下兩欄再置中，格子大小不變 —— 2×2 缺一角比置中難看。 */
.tz-quad.is-three .tz-q:last-child {
  grid-column: 1 / -1;
  width: calc(50% - .2rem);
  margin-inline: auto;
}
/* 小格裡沒有字形資料時的退路字要跟著縮，不然 5.5rem 會撐破四分之一的格子 */
.tz-q .tz-fallback { font-size: 2.6rem; }
/* 一格底下的碼：一碼一個反白小方塊，跟單字提示那排是同一種（.tz-chip）。 */
.tz-qcode {
  display: flex; justify-content: center; align-items: baseline;
  gap: .2rem; margin-top: .2rem;
}
/* 三字詞的第三格有兩個字母：那個字同時被取首碼和末碼（首首首末）。兩個字母
   分不出誰是誰，所以末碼那個加一個小字；首碼一律不標，都標等於什麼都沒說。 */
/* 還沒按 = 揭曉的那幾碼：虛線的 ？ 方塊。用中性灰而不是那一位的顏色 ——
   .tz-chip.is-blank 本來會留著字根色（單字提示那邊筆畫已經標出來了，留色才
   對得上），但四小格是「什麼都還沒說」的狀態，先給顏色等於先講一半答案。 */
.tz-qcode .tz-chip.is-blank { color: var(--ink-faint); }
.tz-qtag {
  font-family: inherit; font-style: normal; font-size: .6rem; font-weight: 400;
  color: var(--ink-faint); margin-inline-start: .2em; vertical-align: .15em;
}

/* 兩字詞：主格子上面多一排小格（見 try.js drawPair）。右上角是等一下要打的
 * 那個字，一直是黑的；打完前一個字，它放大成主格子，剛打完的那個縮到左上角、
 * 顏色留著。小格照樣沿用 .tianzi 底下那幾條（格線、tz-ink、tz-z*），這裡只管排版。
 *
 * 兩邊的小格**一直**佔著位子（空的那邊只是 visibility:hidden）—— 用 display:none
 * 會讓整塊在換字的那一瞬間左右跳一下，而它底下就是提示區，一起跟著跳。 */
.tz-prow {
  display: flex; justify-content: space-between; align-items: flex-start;
  margin-bottom: .45rem;
}
.tz-mini { position: relative; width: 27%; }
.tz-mini.is-blank { visibility: hidden; }
/* 小格裡沒有字形資料時的退路字要跟著縮，不然 5.5rem 會撐破格子（同 .tz-q） */
.tz-mini .tz-fallback { font-size: 1.5rem; }
.tz-pmain { position: relative; }

/* 慶祝畫面：整篇打完了，田字格裡放幾個 emoji 小小彈一下，取代原本要畫的字
 * （見 try.js celebrateCell）。跟 .tz-fallback 一樣疊在格子中央，動畫很短，
 * 每片彈跳的時間錯開一點點（inline style 的 animation-delay），看起來比較
 * 活潑，不是全部同時跳一下（Wilson：完成時想要一點慶祝感）。 */
.tz-confetti {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center; gap: .3rem;
  pointer-events: none;
}
.tz-confetti-piece {
  font-size: 2.2rem;
  animation: tz-confetti-pop .6s cubic-bezier(.34, 1.56, .64, 1) both;
}
@keyframes tz-confetti-pop {
  0%   { transform: scale(0) translateY(8px) rotate(-10deg); opacity: 0; }
  100% { transform: scale(1) translateY(0) rotate(0deg); opacity: 1; }
}

/* 約定字標籤：這個字不是照筆畫拆的，是整字背下來的（rules.json 的
 * convention 規則，見〈約定字表〉）——標出來，免得學的人以為自己看不出
 * 字根，其實這個字本來就不歸那套推理管（Wilson）。跟〈約定字表〉、
 * 〈取碼原則〉頁裡標籤類的用色一致（accent 底色、accent 字）。 */
.conv-badge {
  font-size: .68rem;
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-soft);
  border-radius: 999px;
  padding: .05rem .55rem;
  white-space: nowrap;
}

/* 有簡碼的字：跟〈約定字〉同一個藥丸形，但灰的不是 accent 的 —— 約定字講的是
 * 「這個字不歸拆碼那套推理管」（例外，該搶眼），有簡碼講的是「有捷徑，按 = 會教
 * 你」（好消息，不該搶戲）。灰底 5.0:1／深色 5.7:1，小字也讀得動。 */
.short-badge {
  font-size: .68rem;
  font-weight: 600;
  color: var(--ink-dim);
  background: var(--code-bg);
  border-radius: 999px;
  padding: .05rem .55rem;
  white-space: nowrap;
}

.practice-next {
  margin: .6rem 0 0;
  font-size: .85rem; color: var(--ink-dim);
  display: flex; align-items: baseline; justify-content: center; gap: .4rem; flex-wrap: wrap;
}
.practice-next b { font-size: 1.15rem; color: var(--ink); }
.practice-next .warn { color: var(--rb-0); }
.practice-next .ok { color: var(--accent); }

@media (max-width: 46rem) {
  .tryarea { grid-template-columns: minmax(0, 1fr); }
  .practice-cell { order: -1; }
  .tianzi { max-width: 10rem; }
}


/* 田字格的提示：被提示到的筆畫用取碼原則頁那一套彩虹分組色 —— 同一條字根
 * 同一個顏色。沒按 / 之前整個字是黑的（.tz-ink）。 */
.tianzi .tz-z0 { fill: var(--rb-0); }
.tianzi .tz-z1 { fill: var(--rb-1); }
.tianzi .tz-z2 { fill: var(--rb-2); }
.tianzi .tz-z3 { fill: var(--rb-3); }
.tianzi .tz-z4 { fill: var(--rb-4); }
.tianzi .tz-z5 { fill: var(--rb-5); }

/* 提示貼著田字格底下 —— 講的是格子裡那個字的哪幾筆，就該貼著那個字。
 * 直排置中，跟上面的格子對齊。 */
.tz-hint {
  margin-top: .55rem;
  display: flex; flex-direction: column; align-items: center; gap: .35rem;
  /* 高度先留著，空的時候也佔位 —— 提示一出現就把底下的試打框往下推，
     打到一半整個版面跳一下（Wilson）。留的是最壞情況：一排字母＋最長的那條
     取形意圖（全篇最長 39 字＝A 的「半包框中夾一點…」，在這個欄寬排到三行）
     ＋底下那一行字。⚠️ 這個值要拿**真的排到三行**的字去量（付、封、將、待、
     得、持），拿短的意圖量會少留十幾 px，長的一出現還是會跳。
     所以這裡不能用 hidden／display:none，內容清掉、框留著。 */
  min-height: 7.5rem;
}
.tz-hintcodes { display: flex; gap: .25rem; flex-wrap: wrap; justify-content: center; }
.tz-chip {
  font-family: ui-monospace, Menlo, monospace;
  font-weight: 700; font-size: .82rem;
  min-width: 1.5rem; text-align: center;
  padding: .1rem .35rem;
  border-radius: 4px;
  color: var(--surface);
}
.tz-chip.z0 { background: var(--rb-0); }
.tz-chip.z1 { background: var(--rb-1); }
.tz-chip.z2 { background: var(--rb-2); }
.tz-chip.z3 { background: var(--rb-3); }
.tz-chip.z4 { background: var(--rb-4); }
.tz-chip.z5 { background: var(--rb-5); }
/* 還沒揭曉字母的那一格：留著它那一條字根的顏色（對得上格子裡剛標出來的那幾筆），
 * 但字母還是問號 —— 灰掉的話就看不出這一格講的是哪幾筆了。 */
.tz-chip.is-blank { background: none; border: 1px dashed currentColor; }
.tz-chip.z0.is-blank { color: var(--rb-0); }
.tz-chip.z1.is-blank { color: var(--rb-1); }
.tz-chip.z2.is-blank { color: var(--rb-2); }
.tz-chip.z3.is-blank { color: var(--rb-3); }
.tz-chip.z4.is-blank { color: var(--rb-4); }
.tz-chip.z5.is-blank { color: var(--rb-5); }

.tz-intent { font-size: .8rem; line-height: 1.5; color: var(--ink); text-align: center; }
/* 簡碼提示的第一句（「這個字有簡碼，只要打這兩條字根」）。比取形意圖淡一階：
 * 它是框住整件事的一句話，不是這一步要讀的內容。 */
.tz-short { font-size: .78rem; line-height: 1.5; color: var(--ink-dim); text-align: center; }
/* 打歪的時候：候選列裡那幾碼標紅，田字格底下說「應該是哪一條字根」。
 * 已經打對的字根照樣留著顏色 —— 整個字變回黑的等於把進度也收掉了（Wilson）。 */
.rail .buf .is-bad { color: var(--warn); }
.tz-wrong { font-size: .8rem; font-weight: 600; color: var(--warn); }
.tz-more { font-size: .72rem; color: var(--ink-faint); }

/* 自由試打的拼音查字，分兩塊：
 * 1. 輸入框＋候選（.pyq-row）住在左欄，貼在試打框自己的候選列（#rail）
 *    下面、同一列。左右是**兩個獨立的框**，不是一個框套一個框（Wilson 指出
 *    輸入框自己的邊框跟外層候選列的邊框疊在一起，看起來像框中框）——輸入框
 *    窄、候選框借 .rail 的樣式貼著它右邊，中間只留一點點縫，看起來像同一條
 *    （Wilson：候選框要緊接在輸入框右邊）。
 * 2. 拆碼圖（.pyq，右欄）固定在側欄，跟左欄完全分開——這樣候選字換了
 *    拼音、行數變多變少，也不會牽動拆碼圖的位置（Wilson）。 */
/* 上邊距跟 .rail 自己的 margin-top 一樣（.7rem）——textarea→#rail 跟
   #rail→這一排要同一個間距，兩條「候選列」上下疊起來間距才均勻
   （Wilson：兩條候選列中間的間距不一致）。 */
.pyq-row { display: flex; align-items: stretch; gap: .35rem; margin-top: .7rem; }

/* 拼音／注音分頁鈕：跟 .pyq-input 同排、同高，.jm-sortbar-btns 本來的
   邊框／底色已經夠，只需要蓋掉它原本給列表用的字級（拼音查字這排字級
   比較大）跟拿掉多餘的外距。 */
/* 字級比 .jm-sortbar-btns 原本的 .82rem 略大一點，跟旁邊 .95rem 的輸入框
   同一列比較搭，但不必真的頂到 .95rem 那麼大（Wilson：字級太大了）。 */
.pyq-mode-btns { flex: none; font-size: .85rem; }
.pyq-mode-btns button { padding: 0 .6rem; }
/* 〈線上試打〉：跟同一列的輸入框、候選框一樣高（.pyq-row 本身
   align-items:stretch，這裡跟著撐滿）。 */
.pyq-row .pyq-mode-btns { align-self: stretch; }
/* 〈拆碼查詢〉：.cm-field 是直排 flex，容器預設 align-items:stretch 會把
   這顆藥丸鈕拉滿整欄寬度，兩個字旁邊留一大截空白（Wilson 指出）。這裡只要
   跟內容一樣寬，用 flex-start 取消橫向撐滿。 */
.cm-field .pyq-mode-btns { align-self: flex-start; }

.pyq-input {
  flex: none;
  width: 12.5rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  color: var(--ink);
  padding: 0 .6rem;
  font: inherit;
  font-size: .95rem;
}
.pyq-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
/* 輸入框的提示字跟候選框「查無此字」那句提示，字色／字級要一致——兩個框
   現在緊挨著，一句話沒打完接另一句，深淺、大小不一樣會很明顯（Wilson）。
   跟 .rail .empty 用同一組值。 */
.pyq-input::placeholder { color: var(--ink-dim); opacity: 1; font-size: .78rem; }

/* 候選框借 .rail 的樣式（邊框／底色／固定高度），但這裡是橫排裡的一個
   item，.rail 自己的 margin-top 是給「接在上一個區塊下面」用的，這裡
   用 .pyq-row 的 gap 取代，要歸零，不然會被拉出兩層間距。 */
.pyq-cands-box { flex: 1; min-width: 0; margin-top: 0; }

/* 注音鍵盤：只在注音模式展開（見 try.js setPyqMode），四排照實體鍵盤的
   注音鍵位排（Q 那排、A 那排、Z 那排、數字那排），每排整齊對齊——
   不是為了像鍵盤，是讓「同一排的鍵長得一樣寬」，找起來比較快。 */
.pyq-bpmf { margin-top: .6rem; display: flex; flex-direction: column; gap: .3rem; }
.pyq-bpmf-row { display: flex; gap: .3rem; }
/* 固定高度，不是靠 padding／line-height 撐出來的：調號鍵（.is-tone）字級
   比字母鍵大，如果高度是算出來的，那幾顆鍵會比同一排其他鍵高，而
   .pyq-bpmf-row 預設 align-items:stretch，一整排會被那幾顆撐高
   （Wilson 發現：查字頁的第一排比其他排高）。改用固定高度＋flex 置中，
   字級再怎麼調，鍵的外框都一樣高。 */
.pyq-bpmf-key {
  flex: 1;
  min-width: 0;
  height: 2.1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 600 1.6rem/1 inherit;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  color: var(--ink);
  cursor: pointer;
  text-align: center;
}
.pyq-bpmf-key:hover { border-color: var(--accent); color: var(--accent); }
/* 清除鍵比字母鍵寬一點、字級小一點——它是文字不是符號，跟旁邊的注音符號
   混在一起大小一樣會很擠。 */
.pyq-bpmf-key.is-wide { flex: 1.6; font-size: 1rem; }
/* 調號鍵（ˊˇˋ˙）：符號本身很小，字級比字母鍵拉大一點才看得清楚；顏色
   淡一階（ink-dim）暗示「這個可打可不打」——查詢不分聲調（見 try.js
   onPyqInput），不是真的操作要求。 */
.pyq-bpmf-key.is-tone { font-size: 1.7rem; color: var(--ink-dim); }

/* 拆碼圖那一塊：跟 .typebox 的上外距（.9rem）一樣，讓這個面板的上緣跟
   左邊試打框的 textarea 上緣切齊（Wilson）。田字格跟色塊碼都給固定高度
   （不是 min-height）：選字之前／之後、有沒有取形意圖，高度都一樣，
   不會讓側欄一下高一下矮，把下面按鍵指南的位置跟著跳一下
   （Wilson：選字前後右欄框在跳）。 */
.pyq { margin-top: .9rem; }
.pyq .tianzi { margin-top: 0; height: 13rem; }
/* 基礎的 .tz-hint 有 min-height:7.5rem（給練習模式的多行取形意圖用），這裡
   只放一行色塊碼，不用蓋那麼大——沒蓋掉 min-height 的話，實際高度會被那個
   7.5rem 頂住，拆碼圖右欄比左邊的輸入框／候選框那排高一大截，兩欄拉齊之後
   輸入框那排下面就會空出一大塊白（Wilson 抓到）。 */
/* 高度留夠兩行（色塊碼一行＋約定字標籤一行），不管標籤有沒有出現都一樣高——
   跟固定高度那套邏輯一致（見上面拆碼圖／田字格的說明），選到約定字跟選到
   一般字，側欄高度不該不一樣。 */
.pyq .tz-hint { margin-top: .6rem; height: 3.3rem; min-height: 0; }

/* 姓名常用字：故意擺在 #tryarea 這個 grid 外面，不跟著拆碼圖那欄的固定
   高度被拖出一段空白——詳見 try.html 裡這一塊的說明。上外距換成跟
   .tryarea 自己的下外距一樣（1.4rem）：這一塊現在是接在卡片後面的新
   段落，不是卡片裡的最後一列，用卡片本來的外距當作跟卡片的距離，
   比另外量一個數字更不容易兜不起來。 */
.namechars { margin: 1.4rem 0; padding-top: .5rem; border-top: 1px dashed var(--line); }
.namechars-tag { margin: 0 0 .7rem; font-size: .82rem; color: var(--accent); }

/* 姓氏／男女名左右並排兩欄，各欄自己是「標籤在左、內容在右」——見
   try.html 裡的說明：並排之後兩邊各自維持自己原本的捲動方向（姓氏橫向、
   男女名直向），只是排成兩個平行的小面板。 */
/* 40 / 60 分——男女名的字卡牆字比姓氏多（45 對 40，但姓氏字卡本身也窄），
   實際佔用的欄寬用視覺抓：字卡牆要有比姓氏更寬的欄位才不會被擠成一直捲
   （Wilson）。 */
.namechars-cols {
  display: grid;
  grid-template-columns: 2fr 3fr;
  /* 兩欄各自算自己的高度，不要互相拉齊——兩欄字卡牆的行數不一定剛好
   * 一樣多（40 字跟 45 字分到不同欄寬，折成的行數不會剛好對齊），拉齊
   * 只會逼比較矮的那欄多出一截沒東西的空白。 */
  align-items: start;
  gap: .6rem 1.6rem;
}
/* 窄螢幕：兩欄並排收成上下疊，各自維持自己原本「標籤在左、內容在右」的
   排法——欄寬只剩一欄寬時，並排會把兩邊都擠成窄直條，兩個都比原本難用。
   ⚠️ 這條**必須**接在上面 .namechars-cols 的基礎規則後面，不能擺在檔案
   前段的其他窄螢幕 media query 堆裡——CSS 层叠是照檔案順序，擺前面的話
   即使 media query 條件成立，還是會被後面那條沒有 media query、選擇器
   優先度一樣高的基礎規則蓋掉，媒體查詢形同虛設（親眼在 400px 寬量到還是
   2fr 3fr，才發現是這個順序問題）。 */
@media (max-width: 34rem) {
  .namechars-cols { grid-template-columns: 1fr; gap: 1rem; }
}
/* min-width: 0 不能省——grid 欄位預設 min-width: auto，會拿裡面那條可以
   橫向捲的姓氏列的「完整展開寬度」（40 個字卡連成一排）當作這一欄的最小
   寬度，把 2fr／3fr 的比例整個沖垮，變成姓氏那欄自己撐到 1700+px、
   男女名那欄被擠到剩不到 8rem（親眼在 devtools 量到的）。 */
/* 標籤／切換鈕在上，字卡牆在下——不是標籤在左內容在右（Wilson）。 */
.namechars-col { display: flex; flex-direction: column; gap: .5rem; min-width: 0; }
.namechars-label {
  font-size: .82rem;
  color: var(--ink-dim);
}

/* 男/女名切換鈕：橫的並排（Wilson），跟左邊「常用姓氏」純文字標籤一樣
   貼在自己那欄字卡牆的上面——兩欄現在都是「標籤／切換鈕在上，字卡牆
   在下」同一種結構。長相沿用 .jm-sortbar-btns 那套「按下去變實心」的
   橫排藥丸鈕，跟拼音／注音那顆切換鈕是同一個系統，不用另外自創一套。 */
.namechars-gender { align-self: flex-start; font-size: .82rem; }
.namechars-gender button { padding: .3rem .9rem; }

/* 姓氏／男名／女名共用同一顆字卡牆：固定三行高、超出的部分往下捲，不是
   不斷換行撐高整個面板——字全部攤開會把面板拉得很長，固定高度讓兩欄
   「看得出還有更多」，捲軸本身就是提示（Wilson：姓氏也要跟男/女名一樣
   上下捲，不要一個橫向捲一個縱向捲）。
   align-content: flex-start 不能省：flex-wrap 容器给了固定高度之後，
   預設的 align-content: normal 會把行距拉開去撐滿整個高度，字卡會變成
   一行一行分散開，不是「捲軸以外看不到」該有的樣子。 */
.namechars-wrap {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: .35rem;
  max-height: 6.6rem;
  overflow-y: auto;
  padding-right: .3rem;   /* 捲軸旁留一點空隙，不要貼死最後一欄字卡 */
  min-width: 0;
  /* 瀏覽器原生捲軸太粗，會搶走字卡的注意力，但完全藏起來（scrollbar-width:
     none）又會讓人看不出能捲，細一點、顏色淡一點剛好在「看得到」跟
     「不礙眼」中間。Firefox／新版 Safari 走 scrollbar-width／
     scrollbar-color；Chrome／舊版 Safari 走 ::-webkit-scrollbar，
     兩套都要寫。 */
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
.namechars-wrap::-webkit-scrollbar { width: 7px; }
.namechars-wrap::-webkit-scrollbar-track { background: transparent; }
.namechars-wrap::-webkit-scrollbar-thumb { background: var(--line); border-radius: 999px; }

/* 字卡本身沿用 .practice-pickbtn 的藥丸鈕長相（邊框／底色／hover 變主色），
   但字級拉大——這裡放的是單一個漢字，要一眼認出來，不是一句話。 */
.namechars-chip {
  font: inherit;
  font-size: 1.1rem;
  line-height: 1;
  padding: .35rem .55rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  color: var(--ink);
  cursor: pointer;
  flex: none;
}
.namechars-chip:hover { border-color: var(--accent); color: var(--accent); }
/* 剛點過的那個字：跟拆碼圖右欄現在顯示的是同一個字，加個底色呼應一下，
   不然點了字、答案跑到右邊側欄去，看不出兩邊是同一件事。 */
.namechars-chip.is-sel { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }

/* 窄螢幕：.tryarea 收成單欄時姓名常用字自然也是滿版，不用另外處理；
   姓氏列維持橫向捲（不然 40 個字疊成一直排會把整頁拉得很長）。 */

/* 按鍵指南：兩欄並排。用 grid 而不是表格 —— 表格要橫向捲才塞得下兩組，
 * grid 在窄螢幕自己收成一欄。每一格是「鍵｜說明」，鍵那一欄寬度看內容，
 * 但不換行（Backspace 斷成兩行很難看）。 */
.keyguide {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .5rem 2rem;
  margin: 1.2rem 0;
}

.keyguide > div {
  display: grid;
  grid-template-columns: minmax(6.5rem, auto) minmax(0, 1fr);
  gap: .9rem;
  align-items: baseline;
  padding: .35rem 0;
  border-bottom: 1px solid var(--line);
}

.keyguide dt { white-space: nowrap; }
.keyguide dd { margin: 0; color: var(--ink-dim); font-size: .9rem; line-height: 1.6; }

@media (max-width: 46rem) {
  .keyguide { grid-template-columns: minmax(0, 1fr); gap: 0; }
}

/* 節標題用主色，跟〈取碼原則〉那頁一致（Wilson）—— 兩頁都是「一節講一條規則」，
   同一種東西不該兩種顏色。只借顏色，不借 .pr-page h2 的字級與掛式縮排：那是為
   編號標題（「1. 筆順原則」）做的，這一頁的標題沒有編號。 */
.cz-page h2 { color: var(--accent); }
/* 節末的補充小字（例如「四碼快打沒有自己的開關」）。
   ⚠️ 不要叫 .cz-note —— 那個 class 是 cizu.js 給詞卡用的，撞名會互相蓋。 */
.cz-aside { font-size: .86rem; color: var(--ink-dim); margin-top: -.5rem; }

/* ---------------------------------------------------------------------------
   〈詞組〉頁（cizu.html）—— 詞組連打與四碼快打
   核心是「一個字的碼在分解式和總碼裡是同一個顏色」，串接這件事才一眼看得懂，
   所以顏色用的是全站分組色 --rb-0…--rb-5（跟約定字表的拆碼分析同一組），
   索引在 cizu.js 裡按「第幾個字」給，不是按筆畫段。
   --------------------------------------------------------------------------- */
.cz-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.2rem .9rem;
  margin: 0 0 1.1rem;
}

.cz-wordhead {
  display: flex;
  align-items: baseline;
  gap: .7rem;
  flex-wrap: wrap;
  margin: 0 0 .7rem;
  max-width: none;
}

.cz-ch {
  font-family: "Noto Serif TC", "Songti TC", serif;
  font-size: 1.35rem;
  line-height: 1.2;
}

.cz-wordhead .cz-ch { font-size: 1.6rem; font-weight: 600; }

.cz-note { font-size: .86rem; color: var(--ink-dim); }

/* 一行分解式：字＋碼＋種類，用 ＋ 串起來，最後 ＝ 總碼。窄螢幕會自己折行，
   所以 ＋ ＝ 是行內元素而不是 grid 欄 —— 折了還是讀得通。 */
.cz-eq {
  display: flex;
  align-items: flex-end;
  gap: .45rem;
  flex-wrap: wrap;
  padding: .35rem 0;
}

.cz-op { color: var(--ink-faint); font-size: .9rem; padding-bottom: .15rem; }

.cz-part, .cz-slot {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: .1rem;
  line-height: 1.25;
}

.cz-part code, .cz-slot code {
  background: none;
  padding: 0;
  font-weight: 700;
  letter-spacing: .04em;
}

.cz-kind {
  font-style: normal;
  font-size: .7rem;
  color: var(--ink-faint);
  white-space: nowrap;
}

.cz-total {
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: .05em;
  padding: .15rem .5rem;
}

.cz-eq .rb-0 { color: var(--rb-0); }
.cz-eq .rb-1 { color: var(--rb-1); }
.cz-eq .rb-2 { color: var(--rb-2); }
.cz-eq .rb-3 { color: var(--rb-3); }
.cz-eq .rb-4 { color: var(--rb-4); }
.cz-eq .rb-5 { color: var(--rb-5); }
.cz-eq .off  { color: var(--ink-faint); }

/* 四碼快打每一格的字形：取到的那一條字根亮著（顏色跟它下面那個字母同色），
   其餘筆畫壓成淡灰。「取首碼」講的是「取第一條字根的字母」—— 這件事看圖比看字快。
   2.6rem：小於這個，一兩筆的字根（德 的 J 只有一筆）在螢幕上看不出顏色。 */
.cz-glyph {
  display: block;
  width: 2.6rem;
  height: 2.6rem;
}

.cz-glyph svg { width: 100%; height: 100%; display: block; }
.cz-glyph .cz-off { fill: var(--zg-off); }
.cz-glyph .cz-lit-0 { fill: var(--rb-0); }
.cz-glyph .cz-lit-1 { fill: var(--rb-1); }
.cz-glyph .cz-lit-2 { fill: var(--rb-2); }
.cz-glyph .cz-lit-3 { fill: var(--rb-3); }
.cz-glyph .cz-lit-4 { fill: var(--rb-4); }
.cz-glyph .cz-lit-5 { fill: var(--rb-5); }

.cz-count {
  margin: .5rem 0 0;
  font-size: .84rem;
  color: var(--ink-dim);
  max-width: none;
}

/* 三字以上的四式：每一式前面掛一個標籤，說明另起一行、對齊標籤右邊 */
.cz-mode { padding: .3rem 0; border-top: 1px solid var(--line); }
.cz-mode:first-of-type { border-top: 0; }

.cz-modetag {
  display: inline-flex;
  align-items: center;
  min-width: 4.6rem;
  height: 1.5rem;
  padding: 0 .5rem;
  border-radius: 999px;
  background: var(--code-bg);
  color: var(--ink-dim);
  font-size: .76rem;
  white-space: nowrap;
}

.cz-modetag.is-dup { opacity: .55; }

.cz-why {
  margin: 0 0 .2rem;
  padding-inline-start: 5.05rem;   /* 4.6rem 標籤 ＋ .45rem gap，對齊分解式 */
  font-size: .8rem;
  color: var(--ink-faint);
  max-width: none;
}

.cz-si4row .cz-modetag { align-self: center; }

/* 現算的碼跟出貨碼表對不上時的標記。不是錯誤 —— 取碼剛改過、碼表還沒重建就會這樣，
   是暫時狀態（見 CLAUDE.md 硬規則二）。標出來比悄悄顯示一個對不上的碼好。 */
.cz-stale {
  font-size: .72rem;
  color: var(--warn);
  border: 1px solid currentColor;
  border-radius: 999px;
  padding: .05rem .45rem;
  cursor: help;
}

.cz-tag {
  font-family: ui-monospace, Menlo, monospace;
  font-size: .88em;
  background: var(--code-bg);
  border-radius: 5px;
  padding: .05rem .35rem;
}

/* 詞庫收錄了什麼：一組一張卡，例詞橫排、自己折行 */
.cz-cat { padding: .8rem 1.1rem .9rem; }

.cz-cathead {
  display: flex;
  align-items: baseline;
  gap: .7rem;
  flex-wrap: wrap;
  margin: 0 0 .5rem;
  max-width: none;
}

.cz-cathead b { font-size: 1rem; }

.cz-words { display: flex; flex-wrap: wrap; gap: .35rem .9rem; }

.cz-w {
  display: inline-flex;
  align-items: baseline;
  gap: .25em;
}

.cz-w .cz-ch { font-size: 1.05rem; }

.cz-w code {
  background: none;
  padding: 0;
  font-size: .68rem;
  color: var(--ink-faint);
  letter-spacing: .03em;
}

/* 四碼那一條用主色**並加粗**：這一排的碼是 .68rem 的細字，光靠色相分不出來
   （Wilson：thin 的時候綠跟灰看起來差不多）。粗細是第二個訊號，色盲也讀得到。 */
.cz-w code.is-si4 { color: var(--accent); font-weight: 700; }

/* 上面那條顏色說明。裡面的 <code> 借同一組顏色當樣本，說明本身就是圖例，
   不必另外畫色塊。 */
.cz-legend { font-size: .86rem; color: var(--ink-dim); margin: 0 0 1.1rem; }
.cz-legend code { background: none; padding: 0; color: var(--ink-faint); font-weight: 400; }
.cz-legend code.is-si4 { color: var(--accent); font-weight: 700; }

.cz-stats { margin: 1.6rem 0 2rem; }

.cz-loading { color: var(--ink-dim); }

@media (max-width: 40rem) {
  .cz-why { padding-inline-start: 0; }
}

/* ── 〈自動上屏〉頁 ─────────────────────────────────────────────────────
 * 唯一上屏／即時頂的說明頁（dingping.html）。內容全部由 dingping.js 從碼表現算，
 * 這裡只管排版。顏色一律走既有的 token，不另立一組。 */

/* 三種上屏方式、什麼時候不該開：兩處都是「名詞＋一段解釋」，用 dl 而不是清單，
   名詞才站得住（清單會讓三個名詞讀起來一樣重）。 */
/* 唯一上屏／頂功上屏這兩個小節標題用主色（Wilson）—— 它們本來是 .ac-kinds 的 dt，
   升成 h3 之後不該把綠色丟掉，那是「這是一個名詞」的記號。字級照全站的 h3。 */
.ac-page h3 { color: var(--accent); }

.ac-kinds { margin: 1.1rem 0 1.6rem; }
.ac-kinds dt {
  font-weight: 600;
  color: var(--accent);
  margin-top: .9rem;
}
.ac-kinds dd { margin: .25rem 0 0; }

.ac-demo {
  margin: 1.2rem 0 1.6rem;
  padding: .9rem 1rem 1rem;
  background: var(--surface);
  border-radius: 6px;
}
.ac-demo-cap { margin: 0 0 .7rem; font-size: .88rem; color: var(--ink-dim); }

/* 按鍵流程表：一列一鍵（按鍵／碼欄／結果）。用 grid 而不是 table —— 窄螢幕時
   第三欄的說明字很長，table 會把整張表撐到要橫向捲。 */
.ac-row {
  display: grid;
  grid-template-columns: 2.4rem 6.5rem 1fr;
  gap: .5rem;
  align-items: baseline;
  padding: .3rem 0;
  border-top: 1px solid var(--line);
}
.ac-row.is-head {
  border-top: none;
  font-size: .76rem;
  color: var(--ink-faint);
  padding-top: 0;
}
/* 有上屏發生的那一列標出來 —— 整張表大部分的列都是「等下一鍵」，不標的話
   真正發生事情的那兩列會被淹掉。 */
.ac-row.is-fire { background: var(--bg); }

.ac-key {
  font-family: inherit;
  font-weight: 600;
  text-align: center;
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: .05rem 0;
  background: var(--bg);
}
.ac-buf { color: var(--ink-dim); letter-spacing: .04em; }
.ac-act { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem; }
.ac-act b { font-size: 1.15rem; }
.ac-tag {
  font-style: normal;
  font-size: .72rem;
  padding: .1rem .35rem;
  border-radius: 3px;
  color: var(--surface);
}
.ac-tag.is-sole { background: var(--accent); }
/* 即時頂用另一個顏色：兩種上屏在同一張表裡並排，同色就分不出誰是誰。
   走〈取碼原則〉那組彩虹色的紫，跟四碼快打那邊「最後一碼」同一個色位。 */
.ac-tag.is-push { background: var(--rb-4); }
.ac-why { font-size: .8rem; color: var(--ink-faint); }

/* 「碼打完了卻不算唯一」：打中的那個 vs 還在排隊的那個，並排比較 */
.ac-pair { display: flex; flex-wrap: wrap; gap: .8rem; }
.ac-card {
  flex: 1 1 9rem;
  padding: .7rem .8rem;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--bg);
}
.ac-card.is-hit { border-color: var(--accent); }
.ac-card-ch { display: block; font-size: 2rem; line-height: 1.2; }
.ac-card-code { display: block; color: var(--ink-dim); letter-spacing: .04em; }
.ac-card-tag { display: block; margin-top: .25rem; font-size: .78rem; color: var(--ink-faint); }
.ac-card.is-hit .ac-card-tag { color: var(--accent); }

.ac-caveat { font-size: .92rem; color: var(--ink-dim); }

@media (max-width: 40rem) {
  .ac-row { grid-template-columns: 2.2rem 5rem 1fr; }
}

/* 〈自動上屏〉頁開頭那句對照：試打頁把這個功能叫「流暢模式 · 單字上屏」，
   兩個名字要在同一畫面上綁起來，不然讀者會以為是兩個不同的東西。 */

/* 單字上屏底下、田字格下面那一行：碼打完之後接下來會發生什麼（見 try.js 的
   flowState）。多數時候是空的 —— 只有「這個碼不只一個字，得自己按空白」那一種
   才要說話，會自己上屏的那一種不必說，隔一拍它就上屏了，說了反而是噪音。 */
.practice-flow {
  margin: .4rem 0 0;
  min-height: 1.2em;               /* 佔著位子：出現／消失時底下那行不要跳 */
  font-size: .8rem;
  color: var(--ink-faint);
  text-align: center;
}
.practice-flow.is-space { color: var(--accent); }

/* ---------------------------------------------------------------------------
   首頁 landing（index.html）—— 2026-08-30 改版：首頁不再是〈簡介〉那篇文件的
   開頭，是獨立的入口頁。原本的九點清單搬去 jieshao.html，首頁只留品牌名、
   幾個關鍵詞、一段拆件動畫、跟一顆按鈕（連去 jieshao.html）。側邊欄本來就
   列了全站每一頁，首頁不用再擺一份導覽卡片（Wilson：新訪客什麼都不懂，應該
   先讓他們看到「打字會變成中文字」這件事本身，不是一堆連結）。
   --------------------------------------------------------------------------- */
:root {
  /* hero 背景那三團色暈的顏色——刻意沿用 --accent／--rb-1，不另開一組色相
     （道理跟下面 .qn 拿掉之後留的說明一樣：這個網站的色彩一直很克制）。
     寫成獨立變數而不是背景裡直接 color-mix()：site.css 別處註解過 color-mix
     用在漸層上不是每個瀏覽器都吃得動，深淺主題分開寫死比較保險。 */
  --hero-glow-1: rgba(14, 124, 115, .30);
  --hero-glow-2: rgba(255, 183, 50, .16);
  --hero-glow-3: rgba(9, 77, 71, .26);
}
@media (prefers-color-scheme: dark) {
  :root {
    --hero-glow-1: rgba(63, 192, 176, .32);
    --hero-glow-2: rgba(255, 183, 50, .14);
    --hero-glow-3: rgba(49, 150, 137, .28);
  }
}

.hero--landing {
  position: relative;
  overflow: hidden;
  text-align: center;
  padding-block: 3.4rem 2.6rem;
  margin-bottom: 2.4rem;
}

/* 會動的漸層色暈——三團模糊的色塊慢慢漂移，唯一的「動畫」，但很克制：
   減少動態偏好的使用者直接關掉（下面 prefers-reduced-motion）。 */
.hero-bg {
  position: absolute;
  inset: -25% -15%;
  z-index: -1;
  background:
    radial-gradient(38% 45% at 22% 28%, var(--hero-glow-1), transparent 70%),
    radial-gradient(30% 38% at 80% 18%, var(--hero-glow-2), transparent 70%),
    radial-gradient(46% 50% at 50% 92%, var(--hero-glow-3), transparent 70%);
  filter: blur(48px);
  animation: hero-drift 20s ease-in-out infinite alternate;
}
/* ---------- 首頁：漸層鋪滿整個視窗 ----------
   原本 .hero-bg 是 absolute，關在 .hero--landing 裡面，而那一節又被 main.wrap
   的 max-width（58rem）與 padding-block（3rem）框住，所以漸層四周一圈白邊
   （Wilson：要全頁都是漸層，不要白框）。

   做法是把它改成 fixed 鋪滿視窗、擺在所有東西後面（z-index: -1）。這樣不必去
   跟 .wrap 的寬度、body 的 padding-inline-start 算負外距，版面一個 px 都不用動，
   漸層自然連側邊欄底下、頁尾底下都鋪到 —— 側邊欄本身是不透明的 --surface，
   會蓋在漸層上面，所以「白色側邊欄」照舊（Wilson 說白側邊欄是好的）。
   ⚠️ fixed 元素的 filter: blur 由它自己帶著（見上面 .hero-bg），不要往祖先加
   transform／filter，那會讓 fixed 改以祖先為包含塊，整片漂掉。 */
.lg-body .hero-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
}

/* 頁尾要透光，不然漸層在底部被一條白色橫帶切掉 */
.lg-body footer.wrap { background: none; }

/* 側邊欄在首頁**先躲在左邊**，等拆件動畫播完一輪才滑出來（Wilson）。第一眼
   只有漸層與動畫，不被導覽分心；動畫收尾接上猜猜看的那一刻，導覽才登場。

   ⚠️ 躲起來的 class 是 landing.js 加上去的，不是寫死在 HTML 裡 —— 沒有 JS 的
   時候 class 永遠不會出現，側邊欄就一直是看得見的。反過來寫（HTML 先藏、JS 負責
   顯示）的話，JS 一壞整個導覽就永遠消失。
   ⚠️ body 的 padding-inline-start 不跟著變：側邊欄只是移出畫面，版面不重排，
   所以滑進來的時候正文不會跳。那條空出來的直帶由滿版漸層補上。 */
.topbar { transition: transform .55s cubic-bezier(.22, .61, .36, 1); }
.lg-body.lg-navhide .topbar { transform: translateX(-100%); }

/* 導覽還沒進場時，正文要**置中在整個視窗**，不要先把側邊欄那條寬度空在那裡
   —— 空著會讓整頁看起來偏右（Wilson）。body 的 padding-inline-start 平常是
   var(--nav-w)（讓開側邊欄），躲起來的時候歸零，導覽滑進來時再變回去。
   兩者用同一條時間曲線與時長，看起來就是「導覽把正文推到右邊」這一個動作，
   而不是兩件各自發生的事。 */
.lg-body { transition: padding-inline-start .55s cubic-bezier(.22, .61, .36, 1); }
.lg-body.lg-navhide { padding-inline-start: 0; }

@media (prefers-reduced-motion: reduce) {
  .topbar, .lg-body { transition: none; }
}

@keyframes hero-drift {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(-2.5%, 2%, 0) scale(1.08); }
  100% { transform: translate3d(2.5%, -2%, 0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-bg { animation: none; }
}

.hero-kicker {
  font-size: .88rem;
  color: var(--ink-dim);
  letter-spacing: .1em;
  margin: 0 0 .6rem;
}

.hero-title {
  font-size: clamp(2.3rem, 6vw, 3.4rem);
  line-height: 1.2;
  /* 下外距收窄，讓標語貼著品牌名（Wilson）—— 兩行是一組，離太遠會各自為政。
     標語自己的下外距（1.1rem）維持不變，跟底下的動畫仍然分得開。 */
  margin: 0 0 .2rem;
  letter-spacing: .01em;
}
/* 品牌名整串都用正文墨色，AiPhaBi 不另外上主色（Wilson 2026-08-31）——
   主色讓給底下那句標語，一個畫面裡只留一個綠色的重點。 */
.hero-title .en { color: inherit; }

/* 標語（Wilson 寫的）。排在品牌名底下、關鍵詞那一列上面 —— 跟宇浩、虎碼、搜狗
   那幾個站同一個結構：先一句有溫度的話，再一列講清楚是什麼的關鍵詞。
   字級介於品牌名與關鍵詞之間，顏色用正文墨色（不是 --ink-dim）：它是一句話，
   不是註記，淡掉會變成關鍵詞的附屬品。 */
.hero-tagline {
  font-size: clamp(1.25rem, 3.2vw, 1.75rem);
  font-weight: 600;
  color: var(--accent);
  letter-spacing: .06em;
  margin: 0 0 1.1rem;
}

/* 拆件動畫——首頁最主要的視覺，見 assets/landing.js 跟 assets/landing-glyphs.json。
   幾個手選的字（哈／竹／晶／石）輪流播：每個字要用到的字母先在左邊排隊登場，
   一個一個飛到自己真正該在的位置，落定後字母揉散、筆畫在同一個點長出來，疊成
   完整的字——飛回去的終點就是這個字真正的筆畫座標，不是另外做一份假動畫去湊
   「看起來像」。字根表那頁講「B 像日、D 像月」，這裡直接讓看得到的字母形狀
   飛進去拼成字，是同一件事的動態版本。

   顏色統一用網站自己的主色（見下面 .lg-piece, .lg-letter 那條）——這是展示動畫，
   不是〈拆碼查詢〉那種要教「筆畫分成幾組」的頁面。減少動態偏好的訪客看到的是
   每個字直接組好、淡入淡出換下一個，不會有東西飛。 */
/* .lg-box 包住拆件動畫（.lg-stage／.lg-code）跟猜猜看（.guess）——兩個階段
   共用同一個位置，動畫播完就把動畫那組隱藏、猜猜看那組打開，不是切去另一個
   區塊（見 assets/landing.js）。.lg-restart 用這一層當定位基準，兩個階段
   都看得到、都能按。 */
.lg-box { position: relative; }
/* A 字母飛的時候留殘影那個 bug（Wilson 截圖回報過），試過 will-change／
   translateZ(0)／isolation:isolate 都沒有徹底解決，而且 isolation 那個做法
   會把排隊站在可視範圍外的字母切掉（overflow:visible 在被提升成獨立合成層
   的框裡不管用）。後來換一個方向：不要讓排隊的字母真的站在 viewBox 外面
   （0–1024）靠 overflow:visible 硬擠出來，而是把 viewBox 本身往左加寬到
   -650，字母排隊的座標（最左到 -590，見 landing.js 的 queueNearX／spacing）
   整組都在 viewBox 宣告的範圍內，不用再依賴 overflow 這條路徑，殘影的成因
   （overflow 內容的重繪範圍算錯）直接不成立。.lg-stage 的寬高比例跟著新
   viewBox 換成 aspect-ratio，字的大小／位置跟改之前一樣（高度不變，寬度照
   新的比例撐開），只是框變寬了、字往右邊靠。 */
.lg-stage {
  position: relative;
  height: 13.5rem;
  aspect-ratio: 1674 / 1024;
  margin: 0 auto 1.2rem;
}
.lg-svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}
/* 字母跟筆畫統一都用網站自己的主色，不按字根分組上色——這是首頁的展示動畫，
   不是〈拆碼查詢〉那種要教「筆畫分成幾組」的頁面，彩虹色在這裡沒有意思，
   只會讓人以為顏色代表什麼。 */
.lg-piece, .lg-letter { fill: var(--accent); }
/* 字母排隊飛去定點那段在部分瀏覽器會留殘影（Wilson 2026-08-30 回報：A 飛的
   時候會拖幾個綠點）——這個 svg 用了 overflow:visible，飛出視窗範圍的內容
   重繪範圍算得不夠準，舊的畫面沒清乾淨。三層（位置、彈跳、筆畫）都逼著獨立
   成合成層；⚠️ 不能在這裡寫 transform: translateZ(0) 硬升級——這三層的
   transform 都是 landing.js 直接用行內 style 設的，行內樣式一定蓋過這裡，
   寫了也沒用。真正逼合成層的 translateZ(0) 疊在 landing.js 每一次設
   transform 的字串尾巴（跟著 translate／scale／skew 一起寫），這裡只負責
   will-change 那部分。 */
.lg-letter-pos, .lg-letter, .lg-piece {
  will-change: transform, opacity, filter;
  backface-visibility: hidden;
}
/* 正常情況下筆畫怎麼「長出來」（clip-path／filter／transform 那組）都是
   assets/landing.js 的 materializePiece() 直接用行內 style 設定跟做動畫的，
   這裡不用重複寫一次 transition。減少動態偏好的訪客會走 JS 裡的另一條路
   （見 REDUCED 那個分支）：直接把 opacity 設回 1，不套 clip-path／filter，
   這裡的 transition 只負責讓那一下 opacity 變化不要太生硬。 */
@media (prefers-reduced-motion: reduce) {
  .lg-piece { transition: opacity .55s ease; }
}
.lg-code {
  font-size: .92rem;
  color: var(--ink-dim);
  letter-spacing: .04em;
  margin: 0 0 1.3rem;
}
.lg-code b { color: var(--ink); font-weight: 600; }

/* 重播／跳過圖示——都不寫字（Wilson），疊在一起、垂直置中對齊範例字的高度，
   靠右站到接近漸層背景的邊緣（Wilson：「farther right, near the edge of
   the gradient background」）。.lg-box 沒設寬度，會撐滿 .hero--landing 的
   內容寬度，所以貼著 .lg-box 的 right:0 就等於貼著漸層背景的邊緣，不用算
   .lg-stage 多寬——這樣猜猜看階段（.lg-stage 被藏起來）按鈕還是站在同一個
   地方，不會跳位置。跳過在上、重播在下，跟 .lg-restart 同一顆按鈕的樣式，
   只有垂直位置不同。 */
/* ⚠️ .lg-skip 原本用 calc(50% - 2.1rem - .5rem) 算 top，沒算到 .lg-restart
   自己還套了 translateY(-50%)（讓它的「中心」對齊 50%，不是「頂邊」對齊
   50%）——兩顆按鈕的基準點不一樣，calc 出來的間距是錯的，實際疊在一起
   （Wilson 回報「overlapped」）。改成兩顆都用同一個 translateY(-50%) 當
   基準（中心先對齊 50%），.lg-skip 再從那個基準往上多推「一顆按鈕高度＋
   間距」，這樣間距的算法跟兩顆按鈕實際的定位方式一致，不會算錯。 */
.lg-skip, .lg-restart {
  position: absolute;
  top: 50%;
  right: .5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  color: var(--ink-dim);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
}
.lg-skip { transform: translate(0, calc(-50% - 2.1rem - .5rem)); }
.lg-restart { transform: translateY(-50%); }
.lg-skip:hover, .lg-restart:hover { color: var(--accent); border-color: var(--accent); }
.lg-skip svg, .lg-restart svg { width: 1.15rem; height: 1.15rem; fill: currentColor; }
/* 滑鼠停留才顯示的文字提示——原本用 title 屬性，但瀏覽器原生 title 的
   停留時間是瀏覽器自己控制的，網頁沒辦法調（Wilson：「hover threshold is
   too long」）。改成自己畫的小氣泡，用 transition-delay 控制停留多久才顯示
   （.6s），滑開的時候不等，立刻淡出。往左彈出，不往上或往右——按鈕貼著
   .lg-box 右邊緣，.hero--landing 又是 overflow:hidden，往右會被切掉；往上
   彈在 .lg-skip 那顆（本來就已經站得比較高）risk 頂到 hero 區塊上緣。往左
   是唯一保證有空間的方向。 */
.lg-tip {
  position: absolute;
  right: 100%;
  top: 50%;
  transform: translateY(-50%);
  margin-right: .55rem;
  white-space: nowrap;
  font-size: .74rem;
  line-height: 1.4;
  padding: .3rem .6rem;
  border-radius: 6px;
  background: var(--ink);
  color: var(--bg);
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s ease;
}
.lg-skip:hover .lg-tip, .lg-restart:hover .lg-tip { opacity: 1; transition-delay: .6s; }

/* 關鍵詞——不是完整的句子，就是幾個詞用點隔開，跟下面的長文分開語氣 */
.hero-keywords {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0;
  font-size: 1.02rem;
  color: var(--ink-dim);
  margin: 0 0 1.8rem;
}
/* 用 --line（邊框那組很淡的灰）當分隔點的顏色，在淺色主題底下（#d8e6e5
   對 #fcfefe 的背景）幾乎看不見（Wilson：「otherwise cant see」）。換成
   --accent——這個 token 本來就是主色綠，淺色／深色主題各自有對比夠的版本，
   不用另外寫 media query 分兩套。 */
.hero-keywords .dot { margin: 0 .6em; color: var(--accent); }

.hero-cta { display: flex; flex-wrap: wrap; justify-content: center; gap: .7rem; }

.btn {
  display: inline-flex;
  align-items: center;
  padding: .6rem 1.3rem;
  border-radius: var(--radius);
  font-size: .92rem;
  text-decoration: none;
  border: 1px solid transparent;
  /* .btn 大多掛在 <a> 上，<a> 本來就繼承頁面字體，這行對它是沒差的無操作；
     但〈猜猜看〉的「看答案」是唯一一個掛在 <button> 上的 .btn —— 表單控制項
     不像 <a> 會自動繼承頁面字體，瀏覽器預設給它套系統原生控制項字型（Mac 是
     San Francisco），不是 body 的 Noto Sans TC。旁邊「換一個字」(.guess-next)
     有寫 font: inherit 所以吃得到 Noto Sans TC；兩顆按鈕字型不同，即使都寫
     line-height: normal，各自字型量出來的「normal」還是不一樣高，兩顆按鈕
     還是對不齊（Wilson 回報過兩次，上一次只修了 line-height 那一半）。 */
  font-family: inherit;
}
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--surface); }
.btn-primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
.btn-ghost { background: var(--surface); border-color: var(--line); color: var(--ink); }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); }

/* 猜猜看——動畫播完一輪，接手 .lg-box 同一個位置（見 assets/landing.js 的
   showGuess()），不是另一個獨立區塊，所以不需要自己的上邊界／大段留白，
   排版承接 .lg-stage 原本的位置感覺。答案（碼）不是寫在這裡，是
   assets/landing.js 開頁就去查 dict.json 真正的碼表算出來的，見那邊的
   GUESS_CHARS；字形是 #guess-tianzi 接 ZG.paintGlyph 畫的真正筆畫，
   不是系統字型，跟上面拆件動畫同一種。 */
.guess {
  max-width: 30rem;
  margin: 0 auto 1.2rem;
  text-align: center;
}
/* 提示字（「猜猜看，這個字怎麼打？」）比其他文字更小、更淡——是引導語不是
   內容，不用搶眼（Wilson）。 */
.guess-label {
  font-size: .8rem;
  color: var(--ink-faint);
  margin: 0 0 1rem;
}
#guess-tianzi { margin-bottom: 1.3rem; }
/* 輸入框自己一排、置中；「看答案」跟「換一個字」並排在輸入框下面，兩顆
   看起來是同一組動作（Wilson）——.guess-next 比照 .btn 的尺寸／間距，
   跟旁邊的 .btn.btn-ghost 站在一起才不會一顆明顯比較小。 */
/* 字級縮小過（原本 1.15rem）——提示字換成整句「在這裡輸入英文字母」之後，
   原本給兩三個大寫字母用的尺寸太大，一整句擠在框裡不好看（Wilson）。
   letter-spacing 也跟著收窄，原本的寬度是為大寫字母的猜測（OO、WJO 那種）
   調的，中文提示字不需要拉那麼開。 */
.guess-input {
  display: block;
  width: 13rem;
  margin: 0 auto 1rem;
  font: inherit;
  font-size: .84rem;
  letter-spacing: .1em;
  text-align: center;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--code-bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: .6rem .3rem;
}
.guess-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.guess-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .7rem;
}
.guess-answer {
  font-size: .9rem;
  color: var(--ink-dim);
  min-height: 1.4em;
  margin: 1rem 0 0;
}
.guess-answer.is-right { color: var(--accent); }
.guess-answer.is-wrong { color: var(--warn); }
/* ⚠️ font: inherit 會把 line-height 也一起繼承成 body 那組（1.6 上下），
   跟旁邊 .btn.btn-ghost 用的 <button> 預設 line-height（normal，約
   1.15）對不上，兩顆按鈕明明 padding／font-size 一樣，高度卻差了近 6px
   （Wilson 回報「should be same height」，量出來 42px vs 48px）。
   明寫 line-height: normal 蓋掉那個繼承值，兩顆就對齊了。 */
.guess-next {
  display: inline-flex;
  align-items: center;
  font: inherit;
  font-size: .92rem;
  line-height: normal;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .6rem 1.3rem;
  cursor: pointer;
}
.guess-next:hover { border-color: var(--accent); color: var(--accent); }


/* ---------------------------------------------------------------------------
   〈後記〉（houji.html）—— 全站唯一一頁長文，Wilson 的自述。
   其餘各頁是查閱用的（表格、原則、碼），這一頁是從頭讀到尾的散文，所以字級比
   .doc-prose 大一級、行距放寬、行寬收窄到 34em（中文一行約三十幾字最好讀）。
   這是「後記」這個標籤本來就在做的事：換一種語域，就換一種排版。要收回統一
   字級的話，把 font-size 那一行刪掉即可，其餘不受影響。
   --------------------------------------------------------------------------- */
/* 行寬只定義這一次，段落、落款、手稿圖都引用它 —— 分開寫遲早會走鐘（圖片本來就
   比段落寬了一截）。用 rem 不用 em：.hj-fig 沒有自己的 font-size，em 會依它繼承到
   的 body 字級去算，跟段落的 34em 對不上。 */
.hj-page { --hj-measure: 34rem; }

.hj-page p {
  font-size: 1rem;
  line-height: 2;
  max-width: var(--hj-measure);
  margin: 0 0 1.45rem;
}
.hj-page p.eyebrow { font-size: .88rem; line-height: 1.8; margin: 0 0 .45rem; }
/* 行內的碼（JBA／BFY）在散文裡不要太搶眼，跟著正文走 */
.hj-page code { font-size: .95em; }

/* 結語與落款：跟正文拉開距離，落款淡一階、靠右，像信末署名 */
.hj-close { margin-top: 2.2rem; }

/* 署名。中文書信的收尾是「署名在上、日期在下」，兩行都靠右，所以跟 .hj-date
   共用同一條右邊界（--hj-measure）。署名與日期**同一個顏色**（--ink-dim，比正文淡
   一階）—— Wilson：落款那兩行是一塊，不要一深一淺。跟日期之間留一點點就好。 */
/* ⚠️ 選擇器要寫成 .hj-page .hj-sign（兩個 class）：`.hj-page p`（一個 class ＋
   一個元素）的權重比單一 class 高，只寫 .hj-sign 的話 font-size 根本不作數。
   同一個檔案裡 .hj-date 就是這樣 —— 它寫著 .92rem，實際量出來是 16px，那條
   字級從來沒生效過。這裡先把自己寫對，.hj-date 要不要跟著修是另一件事。 */
.hj-page .hj-sign {
  font-size: 1rem;
  color: var(--ink-dim);
  margin-top: 2.4rem;
  margin-bottom: 0;
  max-width: var(--hj-measure);
  text-align: end;
}
.hj-sign + .hj-date { margin-top: .35rem; }

/* 只留真的會生效的兩條。原本還寫著 font-size: .92rem 與 margin-top: 2.4rem，
   但這一頁的 `.hj-page p`（一個 class ＋ 一個元素）權重比單一 class 的 .hj-date
   高，那兩條從來沒作數過（實測字級一直是 16px、上外距 5.6px，不是 14.7 與 38.4）。
   留著只會讓後人改了沒反應、跑去別的地方找原因，所以刪掉。
   真要改字級或上下間距，選擇器得寫成 `.hj-page .hj-date` 才蓋得過去。 */
.hj-date {
  color: var(--ink-dim);
  max-width: var(--hj-measure);
  text-align: end;
}

/* 手稿圖：跟正文同寬（Wilson）。縮到這個寬度鉛筆字會看不清楚，所以點圖開原圖，
   1600px 那一張才讀得出來。 */
.hj-fig { margin: 2rem 0 2.4rem; max-width: var(--hj-measure); }
/* 只有包住圖片的那個連結是 block（圖下面才不會多出一條基線空隙）——
   用 > a 限定直接子代，不然圖說裡的出處連結也會各自佔一行。 */
.hj-fig > a { display: block; }
.hj-fig img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: 6px;
}
.hj-fig figcaption {
  margin-top: .65rem;
  font-size: var(--credit-size);
  color: var(--ink-faint);
  line-height: 1.7;
}
