/* 設計 token（唯一真相來源，見 docs/UI_REDESIGN_PLAN.md 第 3.1 節） */
:root {
  /* 色彩 token 比照 x:\Code\License 的 app.css（--bg/--card/--border/--text/
     --muted/--blue），讓兩個共用同一個登入入口（auth-portal）的服務視覺一致，
     使用者切換時不會有配色跳動的違和感。 */
  --bg: #0f172a;
  --surface: #1e293b;
  --surface-2: #0b1222;
  --border: #374151;

  --text: #e5e7eb;
  --text-muted: #9ca3af;

  --primary: #3b82f6;
  --primary-hover: #2563eb;
  --success: #22c55e;
  --danger: #f87171;
  --warning: #fbbf24;

  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;

  --fs-sm: 0.875rem;
  --fs-base: 1rem;
  --fs-lg: 1.25rem;
  --fs-xl: 1.5rem;
  --fs-word: 3rem;

  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 4px 24px rgba(0, 0, 0, .35);

  --transition: 150ms ease;
}

* { box-sizing: border-box; }

/* 全站固定在一個畫面高度內，不出現整頁捲軸；內容超過畫面高度時，只有
   .page-content 這個內容區自己捲動（見 base.html 的 <main class="page-content">）。 */
html, body { height: 100%; }
body {
  font-family: "Noto Sans TC", "Inter", -apple-system, "Segoe UI",
               "PingFang TC", "Microsoft JhengHei", sans-serif;
  background: var(--bg);
  color: var(--text);
  margin: 0;
  padding: 0;
  font-size: var(--fs-base);
  line-height: 1.5;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

a { color: var(--primary); text-decoration: none; }
a:hover { color: var(--primary-hover); text-decoration: underline; }

h1 { font-size: var(--fs-xl); margin: 0 0 var(--sp-4); }
h2 { font-size: var(--fs-lg); margin: 0 0 var(--sp-3); }

/* ---------- 版面容器 ---------- */
.page-content { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; }
.container--narrow { max-width: 680px; margin: 0 auto; padding: var(--sp-6) var(--sp-4); }
.container--wide { max-width: 1040px; margin: 0 auto; padding: var(--sp-6) var(--sp-4); }

/* ---------- 導覽列 ---------- */
.navbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: var(--sp-3) var(--sp-4);
  overflow-x: auto;
}
.navbar__brand { font-weight: 700; color: var(--text); white-space: nowrap; }
/* 導覽列登入者姓名＋管理者／一般徽章（見使用者要求），姓名文字跟徽章之間
   留一點間距，不要黏在一起。 */
.navbar__user { display: inline-flex; align-items: center; gap: var(--sp-2); color: var(--text); white-space: nowrap; }
.navbar__brand:hover { color: var(--text); text-decoration: none; }
.navbar__links { display: flex; gap: var(--sp-4); white-space: nowrap; }
.navbar__links a { color: var(--text-muted); padding: var(--sp-1) 0; border-bottom: 2px solid transparent; }
.navbar__links a:hover { color: var(--text); text-decoration: none; }
.navbar__links a.active { color: var(--text); border-bottom-color: var(--primary); }

/* ---------- 卡片 ---------- */
.card {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--sp-5);
  margin-top: var(--sp-4);
}
.card--enter { animation: card-fade-in 150ms ease; }
@keyframes card-fade-in {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ---------- 浮窗（modal）：只用在需要強制使用者先做決定的場合，例如登入後
   詢問要不要合併桌面版舊資料——一般提示用 .card 插在頁面裡就好，不用浮窗 */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
  z-index: 100;
  animation: modal-fade-in 150ms ease;
}
.modal {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--sp-5);
  max-width: 420px;
  width: 100%;
  animation: modal-pop-in 150ms ease;
}
.modal h2 { margin-top: 0; font-size: var(--fs-lg); }
.modal__actions { display: flex; gap: var(--sp-2); justify-content: flex-end; margin-top: var(--sp-5); }
@keyframes modal-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes modal-pop-in {
  from { opacity: 0; transform: scale(0.96); }
  to { opacity: 1; transform: scale(1); }
}

/* ---------- 按鈕 ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: var(--fs-base);
  padding: var(--sp-2) var(--sp-4);
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
}
.btn:hover { background: var(--border); text-decoration: none; }
.btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
.btn-danger { background: transparent; border-color: transparent; color: var(--danger); }
.btn-danger:hover { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-muted); padding: var(--sp-1) var(--sp-2); }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); }

/* ---------- 表單 ---------- */
.input {
  font-size: var(--fs-base);
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  width: 100%;
}
.input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, .25);
}
.field-row { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap; }
.field-row .input { width: auto; flex: 1 1 160px; }
label.inline { display: inline-flex; align-items: center; gap: var(--sp-1); color: var(--text-muted); }

/* 分段選擇器：真實 radio 視覺隱藏，label 做成分段按鈕（見計畫書 9.6） */
.segmented { display: inline-flex; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.segmented input { position: absolute; opacity: 0; pointer-events: none; }
.segmented label {
  padding: var(--sp-2) var(--sp-4);
  color: var(--text-muted);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.segmented input:checked + label { background: var(--primary); color: #fff; }
.segmented label:hover { background: var(--surface-2); }

/* ---------- 表格 ---------- */
.table-wrap { overflow-x: auto; overflow-y: visible; }
/* 操作欄：一行排開，不要換行撐開列高（見 lists.html/list_items.html） */
.table-actions { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: nowrap; white-space: nowrap; }
/* 行內編輯：<details> 展開時用絕對定位浮出來，不會把表格列往下撐開一整行
   （見 UI_REDESIGN_PLAN.md 9.6：行內編輯用 <details>，零 JS、免新路由） */
.inline-edit { position: relative; display: inline-block; }
.inline-edit > summary { list-style: none; }
.inline-edit > summary::-webkit-details-marker { display: none; }
/* 名稱旁的鉛筆圖示（取代常駐的「重新命名」按鈕），見 lists.html */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6em;
  height: 1.6em;
  border-radius: var(--radius-sm);
  cursor: pointer;
  opacity: .6;
  transition: opacity var(--transition), background var(--transition);
}
.icon-btn:hover, .icon-btn:focus-visible { opacity: 1; background: var(--surface-2); }
.inline-edit--icon { margin-left: var(--sp-2); vertical-align: middle; }
.inline-edit__form {
  position: absolute;
  top: calc(100% + var(--sp-1));
  left: 0;
  z-index: 10;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-2);
  box-shadow: var(--shadow);
  flex-wrap: nowrap;
}
.table { width: 100%; border-collapse: collapse; margin-top: var(--sp-3); }
.table th {
  text-align: left;
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--text-muted);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.table td { padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border); }
.table tbody tr:hover { background: var(--surface-2); }
.table form { margin: 0; display: inline-flex; gap: var(--sp-2); }

/* 測驗結案單字清單檢討的分頁籤（見 _answer_review.html）。 */
.answer-review__tabs { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.answer-review__tab.is-active { background: var(--surface-2); color: var(--text); font-weight: 600; }

/* ---------- 徽章 ---------- */
.badge {
  display: inline-block;
  font-size: var(--fs-sm);
  padding: 2px var(--sp-2);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-muted);
}
.badge--success { background: rgba(74, 222, 128, .15); color: var(--success); }
/* 導覽列登入者身分徽章（管理者／一般，見 _nav.html）——用主色跟一般灰色徽章
   區分，讓「管理者」一眼看得出來跟其他徽章不一樣。 */
.badge--primary { background: rgba(59, 130, 246, .18); color: var(--primary); }

/* ---------- 進度條 ---------- */
.progress {
  width: 100%;
  height: 8px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  overflow: hidden;
}
/* 進度 >0 但很小（如 0.2%）時，填色寬度會被四捨五入到 0px，看起來像壞掉的空
   進度條；min-width 保證只要真的有練習過就看得見一條小色塊，0% 則維持全空
   （模板端只在 pct > 0 時才加這個 inline style，見 index.html）。 */
.progress__bar--min-visible { min-width: 3px; }
.progress__bar { height: 100%; background: var(--primary); transition: width 100ms linear; }
.progress__bar--warning { background: var(--warning); animation: pulse 600ms ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }
/* 對戰模式雙色進度條：兩個 .progress__bar 並排（不是疊在一起），分別代表
   答對/答錯比例（見 battle.py render_room_state_html）。 */
.progress--battle { display: flex; }

/* 對戰開始前的倒數畫面（見使用者要求「所有玩家都要顯示五秒倒數」）。全螢幕
   半透明遮罩置中顯示數字，每次數字變化時 battle.js 會重新觸發
   battle-countdown-pop 這個 class（見該檔案說明）。

   [2026-07 使用者回報：畫面閃太快／動畫要流暢] 原本的動畫會在 1 秒內把數字
   「往上飄、放大再淡出」到完全透明——每個數字實際只顯示 1 秒左右，淡出動畫
   播完之後畫面會有一段空白（數字已經透明，但還沒換下一個），看起來像數字
   彈出來一下又整個消失，不夠流暢。改成「彈跳進場後停在完全不透明、不再往上
   飄走」——動畫本身縮短到 400ms（進場彈跳感），播完就是清楚穩定顯示的數字，
   一路維持到真的換下一個數字為止，不會有看不到數字的空窗期。（曾經額外多加
   1 秒開場緩衝讓「5」刻意多停留一下，但使用者實測後認為那樣反而像倒數重跑
   了一次「5」，不是要的效果，已經移除——見 battle.py BATTLE_COUNTDOWN_SECONDS
   的說明。） */
.battle-countdown-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  background: rgba(0, 0, 0, .55);
}
.battle-countdown-number {
  font-size: 6rem;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 2px 12px rgba(0, 0, 0, .5);
  line-height: 1;
}
.battle-countdown-number.battle-countdown-pop {
  animation: battle-countdown-pop-in 400ms cubic-bezier(.34, 1.56, .64, 1);
}
@keyframes battle-countdown-pop-in {
  0% { transform: scale(.4); opacity: 0; }
  60% { transform: scale(1.15); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
.battle-countdown-hint { color: #fff; opacity: .85; }
/* 綠燈／黃燈身分標記，兩處共用：大廳「等待中的房間」列表（你建立的／你已
   加入的，見 _battle_lobby_rooms.html）、房間內的玩家名單（房主／房客，見
   _battle_room_state.html）。重用既有的 pulse keyframe（跟測驗計時器的警示色
   同一個動畫），不另外定義一份。 */
.own-room-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--success);
  margin-right: 6px;
  animation: pulse 1s ease-in-out infinite;
}
/* 沒有燈的那幾列也要保留一樣寬的空位（visibility:hidden 不吃版面），不然代碼
   欄位起始位置會因為有沒有燈而不對齊（見使用者回報）。 */
.own-room-dot--hidden { visibility: hidden; animation: none; }
/* 「自己」是房客身分時的黃燈：大廳列表裡是「已加入但不是自己建立的房間」，
   房間內名單則是「自己是房客、不是房主」——跟綠燈（自己建立／自己是房主）
   區分開來。 */
.own-room-dot--joined { background: var(--warning); }

/* ---------- 測驗倒數計時器（比照桌面版 timer_label + timer_bar） ---------- */
.timer-row { display: flex; align-items: center; gap: var(--sp-3); }
.timer-seconds {
  font-size: var(--fs-lg); font-weight: 700; color: #FFD700;
  min-width: 3.2em; text-align: center; font-variant-numeric: tabular-nums;
}
.progress--timer { height: 12px; }

/* ---------- 統計卡 ---------- */
.stat-card { text-align: center; }
.stat-card__value { font-size: 2rem; font-weight: 700; }
.stat-card__value--success { color: var(--success); }
.stat-card__value--danger { color: var(--danger); }
.stat-card__label { color: var(--text-muted); font-size: var(--fs-sm); }
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--sp-4); }

/* ---------- 密集統計列（比照桌面版標頭那排 1/66 1.5% 的緊湊資訊列，
   取代大量留白的 stat-card 方塊，見 UI_REDESIGN_PLAN.md 討論） ---------- */
.stat-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-5);
  gap: var(--sp-5);
}
.stat-bar__item { display: flex; align-items: baseline; gap: var(--sp-2); }
.stat-bar__value { font-size: var(--fs-lg); font-weight: 700; }
.stat-bar__value--success { color: var(--success); }
.stat-bar__value--danger { color: var(--danger); }
.stat-bar__label { color: var(--text-muted); font-size: var(--fs-sm); }
.stat-bar__divider { width: 1px; height: 20px; background: var(--border); }

/* ---------- 密集清單列（取代巢狀 card-in-card 的單字庫選擇格，每個清單一行，
   進度條/數字/按鈕同一列，比照桌面版清單管理的密集排列） ---------- */
.list-rows { display: flex; flex-direction: column; }
.list-row {
  display: grid;
  grid-template-columns: 100px 1fr auto;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
}
.list-row:last-child { border-bottom: none; }
.list-row__name { font-weight: 600; }
.list-row__progress { display: flex; flex-direction: column; gap: var(--sp-1); }
@media (max-width: 560px) {
  .list-row { grid-template-columns: 1fr; }
}

/* 兩欄並排（如統計頁的雙圖表），窄螢幕自動疊成單欄 */
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); align-items: start; }
@media (max-width: 800px) {
  .two-col { grid-template-columns: 1fr; }
}

/* ---------- 空狀態 ---------- */
.empty-state { text-align: center; padding: var(--sp-6) var(--sp-4); color: var(--text-muted); }
.empty-state__icon { font-size: 2rem; margin-bottom: var(--sp-2); }

/* ---------- 提示文字 ---------- */
.hint { color: var(--text-muted); font-size: var(--fs-sm); }
.hint--success { color: var(--success); }
.hint--danger { color: var(--danger); }

/* ---------- 練習卡（作答頁專用） ---------- */
/* 卡片頂部狀態列：比照桌面版底部狀態列＋工具列設定的密集資訊排（進度/答對答錯/
   錯字庫/學習庫 靠左，語速/發音/隱藏音標設定靠右） */
.practice-status {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-3);
  font-size: var(--fs-sm);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--sp-3);
}
.practice-status__divider { width: 1px; height: 14px; background: var(--border); }
.practice-settings { margin-left: auto; display: inline-flex; gap: var(--sp-3); align-items: center; }
.input--compact { width: auto; padding: 2px var(--sp-2); font-size: var(--fs-sm); }
.practice-input-row { display: flex; gap: var(--sp-2); align-items: center; margin-top: var(--sp-4); }
.practice-input-row .input { flex: 1 1 auto; }

/* [2026-07 使用者回報：單字會換行，不要換行] flex-wrap 原本是 wrap——字夠長、
   單字的總寬度超過容器就會被擠到第二行。改成 nowrap，永遠保持單行；換行
   的空間讓給 .tile 的字級動態縮小（見下面 --letter-count 的說明），而不是
   讓瀏覽器自己把多出來的 tile 推到下一行。 */
.word-tiles { display: flex; justify-content: center; gap: var(--sp-1); flex-wrap: nowrap; margin: var(--sp-4) 0; }
.tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4em;
  height: 1.6em;
  /* --letter-count 由模板端算好塞進 inline style（見 _practice_card.html／
     _battle_question_card.html），伺服器已經知道這一題的字數，不用讓前端
     另外量測 DOM 寬度才知道該縮多小。算法：容器可用寬度（取「680px 版面上限
     扣掉左右留白」跟「視窗寬度扣掉留白」兩者較小的一個，因為窄螢幕手機版面
     沒有 680px 這麼寬）除以字數，就是每個 tile 大概該有的寬度；tile 寬度是
     字級的 1.4 倍（見上面 width: 1.4em），反推回字級。夾在 1rem～
     var(--fs-word) 之間：字少的短字維持原本的大字級（不會被公式反而放大），
     字多的長字才會縮小到剛好整個擠進同一行。 */
  font-size: clamp(1rem, calc(min(600px, 100vw - 4rem) / var(--letter-count, 6) / 1.4), var(--fs-word));
  font-variant-ligatures: none;
}
.tile--revealed { color: var(--primary); animation: tile-in 200ms ease; }
@keyframes tile-in { from { opacity: 0; transform: scale(.7); } to { opacity: 1; transform: scale(1); } }
/* 字首/字尾（詞綴）結構分析標示（見 app/spelling.py word_affixes）：結構分析
   式的拼寫記憶輔助（例如 unhappiness = un + happi + ness）。字首/字尾各自
   用底線區分（不用變色塊，跟 .tile--revealed 測驗模式提示揭曉動畫的顏色
   語意分開，避免使用者搞混「這是提示」還是「這是詞綴」）；字根（扣掉字首
   字尾剩下的部分）用粗體標出來，是使用者要記的核心部分。 */
.tile--prefix { border-bottom: 3px solid var(--primary); }
.tile--suffix { border-bottom: 3px solid var(--warning); }
.tile--root { font-weight: 700; }

.phonetic, .translation { text-align: center; color: var(--text-muted); margin-bottom: var(--sp-2); }
/* 重音節視覺強調（見 app/phonetics.py render_phonetic_stress）：主重音（ˈ 或
   資料裡常見的純引號 '）加粗、放大、變成主色；次重音（ˌ）淺一點的樣式，
   跟主重音區分開。 */
.phonetic-stress { font-weight: 700; font-size: 1.15em; color: var(--primary); }
.phonetic-stress--secondary { font-weight: 600; font-size: 1.05em; color: var(--text-muted); }

.correct { color: var(--success); }
.wrong { color: var(--danger); }

@keyframes card-correct-flash {
  0% { box-shadow: var(--shadow); }
  50% { box-shadow: 0 0 0 3px var(--success), var(--shadow); }
  100% { box-shadow: var(--shadow); }
}
.card--correct { animation: card-correct-flash 400ms ease; }

@keyframes card-shake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-8px); }
  40%, 60% { transform: translateX(8px); }
}
.card--wrong { animation: card-shake 400ms ease; }

@media (prefers-reduced-motion: reduce) {
  .card--enter, .card--correct, .card--wrong, .tile--revealed, .progress__bar--warning, .own-room-dot {
    animation: none !important;
  }
}

/* 鍵盤操作的可視 focus 樣式（滑鼠點擊不觸發，見 :focus-visible 規範） */
a:focus-visible,
.btn:focus-visible,
.input:focus-visible,
.segmented label:focus-within {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.segmented input:focus-visible + label {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

@media (max-width: 720px) {
  .navbar { gap: var(--sp-3); }
  .navbar__links { gap: var(--sp-3); }
  .container--narrow, .container--wide { padding: var(--sp-4) var(--sp-3); }
  /* 手機版最大字級降到 2rem（比桌面版的 var(--fs-word)＝3rem 小），但一樣要
     隨字數縮小才不會換行——不能維持固定 2rem，窄螢幕加長字一樣會被擠爆。 */
  .tile {
    font-size: clamp(1rem, calc(min(600px, 100vw - 3rem) / var(--letter-count, 6) / 1.4), 2rem);
    width: 1.2em;
    height: 1.4em;
  }
  .stat-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 480px) {
  .stat-grid { grid-template-columns: 1fr; }
  .field-row { flex-direction: column; align-items: stretch; }
  .field-row .input { width: 100%; }
}
