/* app.css — v2.1-green → v2.2-peach (5/30 brand migration, Vivi sign-off)
   Source of truth: docs/v5-spec/engineering/09-green-ui-spec.md
   §1 colours, §2 fonts, §3 響應式 (mobile-first centred 440-480 col),
   §4 components (DayTile / 連線 / Treasure / buttons), §5 page layouts.

   5/30 Patrick — 整套色票從「綠色療癒系」遷移到「粉色 / 赤陶 (terracotta)
   積極型教練系」(對齊 Landing v1.7 + PRODUCT-TRUTH v2.6). 從 A003 sandbox
   Vivi 進 App 看到綠色跟 Landing 撞色開始. 修法:
     · 新 canonical token 完全照 Landing v1.7 的 :root (下方第一段).
     · 舊 token 名 (--brand-green / --green-walked / --bg-mint / --gold-accent
       等) 全部 alias 到新 token、保留向後相容、HTML / JS / 既有元件 0 改動.
       現有 var(--brand-green) 自動繼承新赤陶色, 不用 grep-replace 全 repo.
     · Body background 從 solid mint → linear-gradient (peach cream → peach).
   鐵則沒破: 紙感 (.paper-card 仍 solid cream 不動)、無計分 UI 自動繼承新色票、
   諮商保密 + API 不動. 之後若要清理 deprecated 別名、另開 cleanup commit. */

@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+TC:wght@300;400&family=Noto+Sans+TC:wght@300;400&display=swap');

/* ════════════════════════════════════════════════════════════════
   §1 colour tokens — 5/30 Vivi 拍板的新粉色 / 赤陶 brand 系統
   (1:1 對齊 Landing v1.7 的 :root, 用戶從 Landing 點進 App 不撞色)
   ════════════════════════════════════════════════════════════════ */
:root {
  /* ── New canonical tokens (Landing v1.7 spec, source of truth) ── */
  --bg-top:     #f7ebe5;            /* peach cream — body gradient 起點 */
  --bg-bot:     #ead4ca;            /* peach — body gradient 終點 */

  --ink:        #2d2422;            /* warm dark brown — 主文字 */
  --ink-soft:   #6b5c57;            /* warm gray — 次文字 */
  --ink-dim:    #9c8c87;            /* lighter warm gray — 淡文字 */

  --gold:       #c66b4f;            /* terracotta — primary accent (按鈕 / 強調) */
  --gold-soft:  #a8553c;            /* deeper terracotta — hover / deep title */

  --coral:      #d6826a;            /* coral — secondary accent (focus / walked tile) */
  --coral-soft: #b96544;            /* deeper coral */

  --card:       rgba(255,255,255,.55);    /* glassy white card (Landing style) */
  --card-line:  rgba(198,107,79,.20);     /* terracotta hairline */

  /* ── Back-compat aliases (舊 token 名指向新值, HTML / JS 0 改動) ── */
  /* 主按鈕色 — 綠 → 赤陶 */
  --brand-green:    var(--gold);
  /* 走過格子 + focus border — 綠 → 珊瑚 (warm 強調) */
  --green-walked:   var(--coral);
  /* 深色標題強調 — 森林綠 → 深赤陶 */
  --green-forest:   var(--gold-soft);
  /* 主背景 — solid mint → solid peach cream (gradient 在 body, 此 token 用 fallback) */
  --bg-mint:        var(--bg-top);
  /* 今天格子 — 暖桃 → 直接用赤陶 (在 peach bg 上要 pop) */
  --peach-today:    var(--gold);
  /* ✦ / ✓ 金光 marker — 真金 → 赤陶 (對齊 Landing 的 .glow / 不留兩種 accent) */
  --gold-accent:    var(--gold);
  /* 未到的格子 — 淺薄荷 → 淡奶油 */
  --tile-future:    #f4e8e0;
  /* 腳印 / locked / 中性 icon — 本來就是暖棕、保留 */
  --neutral-step:   #B9A88C;
  /* 卡片 (筆記 / 報告) — 保持 solid 米白 (紙感鐵則, 不換成 glass) */
  --paper-card:     #FBF6EC;
  /* 用戶泡泡 — 淺薄荷 → 淺珊瑚 */
  --bubble-user:    #f2ddd2;
  /* 微分隔線 — 綠 hairline → 赤陶 hairline */
  --border-line:    var(--card-line);
  /* 文字三階 — 全換暖色文字 */
  --text-primary:   var(--ink);
  --text-secondary: var(--ink-soft);
  --text-faint:     var(--ink-dim);

  /* ── Typography (不動) ── */
  --font-serif: 'Noto Serif TC', 'Songti SC', 'Songti TC', serif;
  --font-sans:  'Noto Sans TC', 'PingFang TC', sans-serif;
}

/* ════════════════════════════════════════════════════════════════
   reset + base
   ════════════════════════════════════════════════════════════════ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
  /* 5/30 Patrick — peach gradient (Landing v1.7 同款). 之前 solid mint. */
  background: linear-gradient(180deg, var(--bg-top), var(--bg-bot) 55%);
  background-attachment: fixed;                /* 避免長頁滾動時 gradient 跟著 scroll、保持紙感 */
  color: var(--text-primary);
  font-family: var(--font-serif);
  font-size: 17px;
  line-height: 1.8;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
button { background: none; border: none; font-family: inherit; color: inherit; cursor: pointer; }
input, textarea { font-family: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }

/* §2 — never bold (CJK weight bumps break the paper feel; rely on size/lts contrast) */
b, strong, h1, h2, h3, h4, h5, h6 { font-weight: 400; }

/* ════════════════════════════════════════════════════════════════
   §3 響應式 — 學員 app 桌面置中 440-480 px col
   ════════════════════════════════════════════════════════════════ */
.view { display: none; min-height: 100vh; max-width: 480px; margin: 0 auto; }
.view.active { display: flex; flex-direction: column; }
.view.fade-out { opacity: 0; transform: translateY(-12px); transition: opacity 400ms ease-in, transform 400ms ease-in; }
.view.fade-in  { opacity: 0; transform: translateY(8px); }
.view.fade-in.shown { opacity: 1; transform: none; transition: opacity 500ms ease-out, transform 500ms ease-out; }

/* ════════════════════════════════════════════════════════════════
   §4.4 buttons — 3 primitives per spec.
   Legacy class names (.entry-btn / .paper-btn / .conv-send-btn) share the
   primitive selectors so existing HTML keeps working before P1/P3 cleanup.
   ════════════════════════════════════════════════════════════════ */
.btn-green,
.entry-btn,
.conv-send-btn {
  background: var(--brand-green);
  color: #FFFFFF;
  font-family: var(--font-serif);
  font-size: 15px;
  letter-spacing: 4px;
  padding: 14px 36px;
  border-radius: 10px;
  transition: background-color 200ms ease-out, opacity 200ms ease-out;
}
.btn-green:hover,
.entry-btn:hover,
.conv-send-btn:hover { background: var(--gold-soft); }   /* 6/02 — shade darker
   (was #348651 darker forest green, 46a4681 brand transition 漏這個).
   --gold-soft = #a8553c deeper terracotta, 跟 --gold (--brand-green alias) 同
   warm 系一階深. */
.btn-green:disabled,
.entry-btn:disabled,
.conv-send-btn:disabled { opacity: 0.45; cursor: default; background: var(--brand-green); }

.btn-gold {
  background: var(--gold-accent);
  color: #2d1f1a;    /* 5/30 — text on terracotta button (was #3A2E10 on real gold) */
  font-family: var(--font-serif);
  font-size: 15px;
  letter-spacing: 4px;
  padding: 14px 36px;
  border-radius: 10px;
}

.btn-paper,
.paper-btn {
  background: var(--paper-card);
  color: var(--text-primary);
  border: 0.5px solid var(--green-walked);
  font-family: var(--font-serif);
  font-size: 14px;
  letter-spacing: 2px;
  padding: 12px 28px;
  border-radius: 10px;
  transition: background-color 200ms ease-out, border-color 200ms ease-out;
}
.btn-paper:hover,
.paper-btn:hover { background: #f4e0d3; }    /* 5/30 — warm peach hover (was light cream #F4ECDA) */
/* Vivi 5/24: coach day-note picker active-day visual mark. Tiny ring so the
   coach knows which day is currently shown + clicking the same day again
   toggles the note collapsed. */
.paper-btn--active {
  background: var(--bg-mint);
  border-color: var(--green-walked);
  color: var(--green-forest);
}

/* Override layout of legacy .conv-send-btn so it stays inline with the textarea */
.conv-send-btn { padding: 12px 22px; letter-spacing: 2px; font-size: 14px;
  border-radius: 14px; white-space: nowrap; min-height: 48px; align-self: flex-end; }

/* ════════════════════════════════════════════════════════════════
   §4.5 input + paper-card + pace-radio (component primitives)
   ════════════════════════════════════════════════════════════════ */
.entry-input,
.conv-input {
  width: 100%;
  padding: 11px 16px;
  background: var(--paper-card);
  border: 0.5px solid var(--border-line);
  border-radius: 10px;
  font-family: var(--font-sans);
  font-size: 15px;
  color: var(--text-primary);
  transition: border-color 200ms ease-out;
}
/* The conv-input textarea keeps the roomier padding — only the entry inputs got tight. */
.conv-input { padding: 14px 18px; }
.entry-input::placeholder,
.conv-input::placeholder {
  color: var(--text-faint);
  font-family: var(--font-serif);
  font-style: italic;
}
.entry-input:focus,
.conv-input:focus {
  outline: none;
  border-color: var(--green-walked);
}
.entry-input.invalid { border-color: var(--green-walked); }   /* validation: §5.1 — no red, brand-green border */
.conv-input { resize: none; min-height: 48px; max-height: 200px; overflow-y: auto; border-radius: 14px; }

/* Paper card — used by 教練筆記 / 週報 / 結業 / Phase Report */
.paper-card {
  background: var(--paper-card);
  border: 0.5px solid var(--border-line);
  border-radius: 10px;
  /* no shadow, no gradient — spec §4.5 */
}

/* Pace radio (entry §5.1) — paper底 + 選中 green-walked 邊 + 深綠圓點 */
.entry-pace { border: none; padding: 0; margin: 16px 0 0; }
.entry-pace .entry-field-label { margin-bottom: 6px; padding: 0; }
.entry-pace-option {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 10px 14px; margin-top: 8px;
  background: var(--paper-card);
  border: 0.5px solid var(--border-line);
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 200ms ease-out, background-color 200ms ease-out;
}
.entry-pace-option:has(input:checked) {
  border-color: var(--green-walked);
  background: var(--paper-card);
}
.entry-pace-option input[type="radio"] {
  margin-top: 6px; flex: 0 0 auto;
  accent-color: var(--brand-green);     /* §4.5: 深綠圓點 */
}
.entry-pace-option__body { display: flex; flex-direction: column; gap: 4px; }
.entry-pace-option__title { font-family: var(--font-serif); font-size: 15px; letter-spacing: 1px; color: var(--text-primary); }
.entry-pace-option__sub { font-family: var(--font-serif); font-style: italic; font-size: 12px; line-height: 1.6; color: var(--text-secondary); }

/* ════════════════════════════════════════════════════════════════
   §5.1 entry — token sweep only at P0; logo hero + new wording lands at P1
   PR-4c-green Vivi A001 mobile fix: tightened vertical rhythm so the whole
   entry page fits within a 390×844 viewport without scrolling. Don't bump
   these back up — they're calibrated against the real device.
   ════════════════════════════════════════════════════════════════ */
#view-entry { justify-content: flex-start; align-items: center; padding-top: 24px; padding-bottom: 24px; }
.entry-container { width: 100%; max-width: 420px; padding: 0 28px; text-align: center; }
/* P1 (PR-4c-green) — logo hero (Vivi 已提供、green 望遠鏡 + ✦) */
.entry-logo { display: block; width: 100%; max-width: 180px; height: auto; margin: 0 auto 14px; user-select: none; }
.entry-title { font-family: var(--font-serif); font-size: 28px; letter-spacing: 6px; line-height: 1.2; color: var(--green-forest); }
.entry-sub { margin-top: 10px; font-family: var(--font-serif); font-style: italic; font-size: 12px; letter-spacing: 2.5px; color: var(--text-secondary); }
.entry-form { margin-top: 24px; text-align: left; }
.entry-field-label { display: block; font-family: var(--font-serif); font-size: 12px; letter-spacing: 1.5px; color: var(--text-secondary); margin-bottom: 6px; }
.entry-field-label--gap { margin-top: 16px; }
.entry-btn { display: block; margin: 20px auto 0; }   /* spacing only; visual via .btn-green grouping above */
.entry-foot { margin-top: 24px; font-family: var(--font-serif); font-style: italic; font-size: 12px; color: var(--text-faint); text-align: center; }
.entry-error { margin-top: 12px; font-family: var(--font-serif); font-style: italic; font-size: 13px; color: var(--green-walked); text-align: center; }

/* ════════════════════════════════════════════════════════════════
   header (used by journey / conversation / note / week / graduation)
   ════════════════════════════════════════════════════════════════ */
.app-header { padding: 16px 28px; border-bottom: 0.5px solid var(--border-line); text-align: center; }
.app-header .label { font-family: var(--font-serif); font-size: 11px; letter-spacing: 3px; color: var(--text-secondary); }

/* ════════════════════════════════════════════════════════════════
   §5.2 journey — P0 ONLY token sweep. P2 rewrites the grid entirely
   (3-col snake DayTile + plant illustrations + path + treasure shelf).
   ════════════════════════════════════════════════════════════════ */
#view-journey { background: var(--bg-mint); }
.journey-title-wrap { text-align: center; padding-top: 28px; padding-bottom: 4px; }
.journey-title { font-family: var(--font-serif); font-size: 19px; letter-spacing: 2px; color: var(--green-forest); }
.journey-sub { margin-top: 8px; font-family: var(--font-serif); font-style: italic; font-size: 12px; letter-spacing: 1px; color: var(--text-secondary); }

/* P2 (PR-4c-green) §5.2 — 3-col snake grid + plant tiles + path + treasure shelf */
.journey-grid-wrap { padding: 28px 24px 0; display: flex; justify-content: center; }
.journey-stage {
  position: relative;
  width: 100%;
  max-width: 360px;          /* 3 cols + gaps, comfortable on phone + the 480 col */
}
.journey-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
}

/* SVG snake-path overlays the stage behind tiles (z-index 0 vs tile 1). Lives
   in HTML outside #journey-grid so renderJourney's innerHTML clear leaves it intact. */
.journey-path {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
  overflow: visible;
}

/* ─── §4.1 DayTile — 角色旅程 puzzle reveal (PR-4c-green Patrick 5/24) ───
   ⚠️ Supersedes the old「植物 Option A」: scenes are full-bleed (not去背), the
   whole journey reads as a darkened picture that lights up格一格. States below. */
.day-tile {
  position: relative;
  z-index: 1;
  aspect-ratio: 1 / 1;
  border-radius: 14px;
  border: 0.5px solid var(--border-line);
  background: var(--tile-future);
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  cursor: default;
  overflow: hidden;   /* clip the WebP scene to the tile's rounded corners */
  transition: filter 350ms ease-out, border-color 250ms ease-out;
}
.day-tile:focus-visible { outline: 2px solid var(--gold-accent); outline-offset: 3px; }

/* Scene WebP — fills the tile via object-fit: cover. Common to all states.
   State-specific filters are applied to the IMG (not the tile) so the day
   number + check + footprint overlays stay full-colour. */
.day-tile__scene {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;   /* match parent .day-tile border-radius */
  pointer-events: none;
  user-select: none;
  transition: filter 350ms ease-out, opacity 350ms ease-out;
  z-index: 1;
}

/* future = LOCKED puzzle piece: warm sepia「未翻開的書頁」(Vivi preview-feedback,
   PR-4c-green Patrick 5/24 — 從深綠黑死黑改成 tan-sepia、放亮、讓「今天」那格 pop).
   Tint is brand-neutral tan (#B9A88C = --neutral-step), NOT green — green is
   reserved for the「走過的路」signal on completed tiles. */
.day-tile--future        { background: var(--tile-future); cursor: default; }
.day-tile--future .day-tile__scene {
  /* 6/2 Vivi sandbox 觀察 — 粉版圖加 sepia 變黃褐, 整體太暗看不清插畫.
     拿掉 sepia (圖本身已 warm), 亮度 0.78→0.92, 飽和 0.5→0.65, 對比 0.95→0.97.
     仍能看出「沒到」 但插畫不再悶死. */
  /* 6/4 Vivi — 0.65/0.92 跟 completed 全彩太接近、做過沒做過分不出來.
     退到淺米白:「未來=還沒翻開的紙頁、走過的=上了色」. */
  filter: saturate(0.2) brightness(1.1) contrast(0.92);
}
.day-tile--future::after {
  content: '';
  position: absolute;
  inset: 0;
  /* 6/2 Vivi — tan 28% → white 12%. 粉本身已 warm, 再加 tan 染色會混濁;
     白霧只負責「未翻開」 薄薄一層, 不染色. */
  /* 6/4 Vivi — 12% 白霧太薄. 改米白霧(紙感 cream、非純白)、蓋出「未翻開」. */
  background: rgba(247, 240, 232, 0.5);
  border-radius: inherit;
  pointer-events: none;
  z-index: 2;
}

/* today (active) = LIVE: full colour + brand-green frame + halo via keyframes below */
.day-tile--active-empty,
.day-tile--active-filled {
  border-color: var(--green-walked);
  cursor: pointer;
}

/* completed = REVEALED: full colour scene + gold ✓ (no green wash now — the
   scene itself carries the "warm" full-colour signal of "walked + has memory") */
.day-tile--completed {
  border: 1px solid var(--green-walked);
  cursor: pointer;
}

/* Footprint (future only — sits over the tan overlay as a quiet「鎖」 hint).
   PR-4c-green Patrick 5/24: 淺背景 (--bg-mint, 5/30 後 aliased to --bg-top peach
   cream) over warm tan = quiet retreat, lets「今天」 那格 pop. 不用品牌色
   (--brand-green, 5/30 後 aliased to terracotta) — 那是 CTA / 走過的路才該亮。
   5/30: 顏色名稱保留歷史名 (-mint / -green-walked 等)、值已遷移到粉色/赤陶系. */
.day-tile__footprint {
  width: 28px;
  height: 28px;
  /* 6/4 — 卡片變米白後淺色腳印會隱形, 換暖棕 (--neutral-step). */
  color: var(--neutral-step);
  opacity: 0.55;
  position: relative;
  z-index: 3;
}

/* Day number — top-left, sans, white with shadow over every state since scenes
   are full-bleed across the board now. (Old per-state colour variants retired
   along with the植物 wash background.) */
.day-tile__day {
  position: absolute;
  top: 6px;
  left: 8px;
  font-family: var(--font-sans);
  font-size: 11px;
  z-index: 3;
  color: #FFFFFF;
  pointer-events: none;
  text-shadow: 0 0 4px rgba(0, 0, 0, 0.45);
}
/* 6/4 — future 卡米白化後白字+黑影變髒, 改暖灰、拿掉影. */
.day-tile--future .day-tile__day { color: var(--text-secondary); text-shadow: none; }

/* Completed ✓ — gold disc top-right with white check */
.day-tile__check {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--gold-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 3;
  pointer-events: none;
}
.day-tile__check svg { width: 9px; height: 9px; color: #FFFFFF; }

/* Active 「開始」 pill — only active-empty (today, still going) */
.day-tile__start-pill {
  position: absolute;
  bottom: 8px;
  left: 50%;
  transform: translateX(-50%);
  padding: 4px 14px;
  background: var(--brand-green);
  color: #FFFFFF;
  font-family: var(--font-serif);
  font-size: 11px;
  letter-spacing: 2px;
  border-radius: 999px;
  white-space: nowrap;
  z-index: 3;
  pointer-events: none;
  box-shadow: 0 1px 4px rgba(46, 82, 56, 0.18);  /* faint lift, NOT a SaaS shadow */
}

/* Active gold halo (§4.1 「2.5× 半徑」)— box-shadow keyframe animates intensity */
.day-tile--active-empty,
.day-tile--active-filled {
  animation: day-tile-halo 3s ease-in-out infinite;
}
@keyframes day-tile-halo {
  0%, 100% { box-shadow: 0 0 30px 8px rgba(227, 179, 64, 0.32); }
  50%      { box-shadow: 0 0 40px 12px rgba(227, 179, 64, 0.58); }
}

/* ─── §4.3 TreasureBox — 5 phase boxes ABOVE the 21-day grid (Vivi 5/24).
   Was: margin 40px auto 12px (treasures sat below grid, needed top breathing).
   Now: margin 18px auto 10px (treasures sit just under journey-title-wrap,
   tighter so the 5 寶藏 reads as part of the「your journey」 header zone
   rather than an island floating above the grid). */
.treasure-title {
  margin: 18px auto 10px;
  text-align: center;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 11px;
  letter-spacing: 3px;
  color: var(--text-secondary);
}
.treasure-shelf {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
  max-width: 360px;
  margin: 0 auto;
  padding: 0 24px;
}
.treasure-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 8px 2px;
  background: transparent;
  color: var(--neutral-step);
  border: none;
  cursor: default;
}
.treasure-box--unlocked {
  color: var(--gold-accent);
  cursor: pointer;
}
.treasure-box__icon {
  width: 32px;
  height: 32px;
}
.treasure-box__roman {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 11px;
  letter-spacing: 1px;
  color: var(--text-faint);
}
.treasure-box--unlocked .treasure-box__roman { color: var(--text-secondary); }
.treasure-box--unlocked .treasure-box__icon { filter: drop-shadow(0 0 6px rgba(227, 179, 64, 0.45)); }

.journey-prompt {
  margin: 28px auto 40px;
  text-align: center;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 12px;
  letter-spacing: 1.5px;
  color: var(--text-secondary);
}

/* ════════════════════════════════════════════════════════════════
   §5.3 conversation — green sweep; structural copy lands in P3
   ════════════════════════════════════════════════════════════════ */
#view-conversation { background: var(--bg-mint); position: relative; }
.conv-scroll { flex: 1; max-width: 540px; width: 100%; margin: 0 auto; padding: 88px 28px 24px; overflow-y: auto; }

/* PR-4c-green Patrick 5/24 — day hero scene shown at the top of #conv-scroll
   (scrolls away with content so the input bar stays docked) AND above the
   paper-card on the note view. 1:1 square asset; max-width caps the visual so
   it doesn't swallow a mobile screen. Subtle paper aesthetic, no shadow. */
.day-hero {
  margin: 0 auto 24px;
  max-width: 360px;       /* ~92vw on a 390px viewport — roomy not overwhelming */
  width: 100%;
  border-radius: 14px;
  overflow: hidden;
  border: 0.5px solid var(--border-line);
  background: var(--paper-card);
}
.day-hero__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  user-select: none;
}
/* On the note (paper-page) view the hero sits above the paper-card with a bit
   more breathing room and centered within the page's narrower column. */
.day-hero--note { margin: 0 auto 18px; }
@media (max-width: 480px) {
  /* Tighter on phones so the input bar / note buttons stay in view. */
  .day-hero       { max-width: 280px; margin-bottom: 18px; }
  .day-hero--note { max-width: 280px; }
}
/* Conversation messages — Vivi 5/24 polish:「字間距太大、要收緊一點」
   5/25 follow-up: AI 側仍然太鬆、再收一階 (1.55 → 1.4, margin 16 → 10).
   user 側已合適、不動. Font size + family unchanged. */
/* 6/4 Vivi — 教練字太大行距太大: 17px→15.5px, 1.4→1.35. 段落空隙是 AI 文字
   的空行 (pre-wrap 原樣呈現)、跟著字級縮. serif 仍略大於 user 15px sans. */
.msg-ai { font-family: var(--font-serif); font-size: 15.5px; line-height: 1.35; color: var(--text-primary); margin-bottom: 10px; white-space: pre-wrap; }
.msg-user-wrap { display: flex; justify-content: flex-end; margin-bottom: 12px; }
.msg-user { background: var(--bubble-user); padding: 10px 14px; border-radius: 16px 16px 4px 16px; max-width: 80%;
  font-family: var(--font-sans); font-size: 15px; line-height: 1.5; color: var(--text-primary); white-space: pre-wrap; }
.callback { background: var(--paper-card); border-left: 2px solid var(--green-walked); border-radius: 0 8px 8px 0;
  padding: 14px 18px; margin-bottom: 22px; }
.callback__label { font-family: var(--font-sans); font-size: 11px; letter-spacing: 1px; color: var(--text-secondary); margin-bottom: 8px; }
.callback__quote { font-family: var(--font-serif); font-style: italic; font-size: 15.5px; line-height: 1.75; color: var(--text-primary); }
.hint-italic { font-family: var(--font-serif); font-style: italic; font-size: 13px; color: var(--text-faint); }

.conv-input-bar { border-top: 0.5px solid var(--border-line); padding: 16px 28px 18px; background: var(--bg-mint); }
.conv-input-wrap { max-width: 540px; margin: 0 auto; }
.conv-input-row { display: flex; align-items: flex-end; gap: 10px; }
.conv-send-btn:disabled { opacity: 0.4; cursor: default; }
.conv-hint { margin-top: 10px; font-family: var(--font-sans); font-size: 11px; letter-spacing: 0.5px; color: var(--text-faint); }

/* §5.3 收尾 — token sweep; ✦ now gold per §1 */
/* 收尾 loading — Vivi 5/24:「太淡」 (paper aesthetic, no SaaS spinner).
   5/25 Vivi: 改米白底黑字 (was 薄荷底綠字 — 像 SaaS 通知、不像在等).
   ✦ star 維持金色當唯一點綴、breathe 動畫保留. 文字 JS 來回逐字打
   (student.js startClosureTypewriter) — 「教練在寫今天的字」打進→停→刪→再打 loop. */
.conv-closure { border-top: 0.5px solid var(--border-line); padding: 28px 28px 36px; text-align: center;
  background: var(--paper-card); opacity: 0; transition: opacity 400ms ease-out; }
.conv-closure.shown { opacity: 1; }
.conv-closure .star { color: var(--gold-accent); margin-right: 10px; font-family: var(--font-sans); font-size: 12px; display: inline-block; }
.conv-closure.shown .star { animation: paper-breathe 2.4s ease-in-out infinite; }
.conv-closure .text { font-family: var(--font-serif); font-style: italic; font-size: 16px; letter-spacing: 1.5px; color: var(--text-primary); }

/* 5/29 Patrick (PRODUCT-TRUTH v2.3 §2.5 折衷 a) — 採集深度 5 圓點.
   紙感: 褪色 (.55 容器 opacity)、安靜 (無動畫、慢 transition)、無顏色喧嘩.
   點亮 = 「✦ 走到了這層」、不是「還差幾層」. 5 顆固定、學員不看也能對話. */
.conv-depth { display: flex; gap: 8px; justify-content: center;
  padding: 8px 0; margin-bottom: 4px; opacity: 0.55; }
.conv-depth__dot { width: 6px; height: 6px; border-radius: 50%;
  background: var(--text-secondary); opacity: 0.25;
  transition: opacity 0.8s ease; }
.conv-depth__dot.lit { opacity: 0.85; }

.conv-input-bar.exiting { opacity: 0; transform: translateY(8px); transition: opacity 250ms ease-out, transform 250ms ease-out; }

.conv-waiting { display: flex; justify-content: center; align-items: center; margin: 40px 0 24px;
  opacity: 0; animation: conv-waiting-fade 400ms ease-out 100ms forwards; }
.conv-waiting .star { color: var(--gold-accent); margin-right: 8px; font-family: var(--font-sans); font-size: 9px; display: inline-block;
  animation: paper-breathe 2.4s ease-in-out infinite; }
.conv-waiting .text { font-family: var(--font-serif); font-style: italic; font-size: 13px; letter-spacing: 1px; color: var(--text-secondary); }
@keyframes conv-waiting-fade { to { opacity: 1; } }

/* Mid-conversation typing indicator — Vivi 5/24:「沒回饋會被當壞掉」.
   Left-aligned like AI message side. Tighter margins than .conv-waiting
   (which is a page-level kickoff/closure indicator); this sits snug under
   the user's just-sent bubble. ✦ paper-breathe carries the「I'm composing」
   signal — no SaaS spinner. */
.conv-typing { display: flex; align-items: center; margin: 4px 0 16px;
  opacity: 0; animation: conv-waiting-fade 300ms ease-out forwards; }
.conv-typing .star { color: var(--gold-accent); margin-right: 8px;
  font-family: var(--font-sans); font-size: 10px; display: inline-block;
  animation: paper-breathe 1.6s ease-in-out infinite; }
.conv-typing .text { font-family: var(--font-serif); font-style: italic;
  font-size: 14px; letter-spacing: 0.5px; color: var(--text-secondary); }

@keyframes paper-breathe {
  0%, 100% { opacity: 0.5; }
  50%      { opacity: 1; }
}

.conv-hint--chain {
  margin-top: 6px;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 11px;
  letter-spacing: 0.5px;
  color: var(--text-secondary);
  line-height: 1.55;
}

/* 6/3 Patrick (Vivi burst protection) — Anthropic 429 overload friendly hint
   with 30s-countdown retry button. Paper aesthetic — not a red error banner. */
.conv-hint--overload {
  display: flex; flex-direction: column; gap: 10px; align-items: flex-start;
  margin: 14px 0 22px; padding: 14px 16px;
  background: var(--paper-card, #f7ebe5);
  border: 0.5px solid var(--border-line);
  border-radius: 6px;
  font-family: var(--font-serif); font-style: italic;
  font-size: 13px; color: var(--text-secondary);
}
.conv-hint--overload__msg { display: flex; align-items: center; }
.conv-hint--overload .star {
  color: var(--gold-accent); font-style: normal; margin-right: 8px;
  font-family: var(--font-sans); font-size: 9px;
}
.conv-hint--overload .text { line-height: 1.5; }
.conv-hint__retry {
  padding: 6px 14px; font-size: 12px; letter-spacing: 1px;
  font-style: normal;
}
.conv-hint__retry:disabled { opacity: 0.5; cursor: not-allowed; }

/* ════════════════════════════════════════════════════════════════
   §5.4 教練卡 / §5.5 Phase Report / §5.6 結業 — shared .paper-card
   ════════════════════════════════════════════════════════════════ */
.paper-page { background: var(--bg-mint); align-items: center; padding: 52px 24px 48px; }
.paper-card { max-width: 440px; width: 100%; padding: 38px 36px 30px; }
.paper-card--wide       { max-width: 480px; padding: 42px 42px 32px; }
.paper-card--graduation { max-width: 540px; padding: 48px 44px 36px; }
.paper-card__header { text-align: center; margin-bottom: 28px; }
.paper-card__eyebrow { font-family: var(--font-serif); font-size: 11px; letter-spacing: 4px; color: var(--green-walked); }
.paper-card__title { margin-top: 4px; font-family: var(--font-serif); font-size: 17px; letter-spacing: 1.5px; color: var(--green-forest); }
.paper-card__subtitle { margin-top: 10px; font-family: var(--font-serif); font-style: italic; font-size: 11px; letter-spacing: 3px; color: var(--text-secondary); }
.paper-card__divider { width: 24px; height: 0.5px; background: var(--gold-accent); margin: 14px auto 0; }
.paper-card__body { font-family: var(--font-serif); font-size: 14.5px; line-height: 2; color: var(--text-primary); white-space: pre-wrap; }
.paper-card__body p { margin-bottom: 18px; }
.paper-card__body p:last-child { margin-bottom: 0; }
.paper-card__sig { margin-top: 32px; text-align: right; font-family: var(--font-serif); font-style: italic; font-size: 14px; letter-spacing: 0.5px; color: var(--text-secondary); }

.status-row { margin-top: 32px; text-align: center; font-family: var(--font-serif); font-style: italic; font-size: 12px; letter-spacing: 1px; color: var(--text-secondary); }
.status-row .star { color: var(--gold-accent); margin-right: 6px; font-family: var(--font-sans); font-size: 9px; }

.btn-row { margin-top: 26px; display: flex; justify-content: center; gap: 12px; }

/* §5.5 Phase Report — 你的寶藏 (P4 green).
   Longer than a daily note (里程碑份量); PHASE N eyebrow in sans + gold;
   ✦ separator between teaching (上半 fixed §8) and breakthrough (下半 generated). */
.paper-card--phase { max-width: 480px; padding: 42px 36px 32px; }
.paper-card__eyebrow--phase {
  font-family: var(--font-sans);     /* §5.5: "PHASE N" sans 10 lts4 --gold-accent */
  font-size: 10px;
  letter-spacing: 4px;
  color: var(--gold-accent);
}
.phase-section-sep {
  margin: 28px auto;
  text-align: center;
  color: var(--gold-accent);
  font-family: var(--font-sans);
  font-size: 16px;
  letter-spacing: 8px;
  opacity: 0.85;
}

/* §5.6 graduation specifics */
.poem-block { margin: 40px auto 36px; text-align: center; }
.poem-line { font-family: var(--font-serif); font-size: 13px; line-height: 2.4; letter-spacing: 0.5px; color: var(--text-secondary); margin-bottom: 6px; }
.declaration-leadin { text-align: center; font-family: var(--font-serif); font-style: italic; font-size: 12px; letter-spacing: 2px; color: var(--green-walked); margin-bottom: 18px; }
.declaration { text-align: center; font-family: var(--font-serif); font-size: 19px; line-height: 2.1; letter-spacing: 1.5px; color: var(--green-forest); margin-bottom: 36px; }
.export-notice { margin-top: 18px; text-align: center; font-family: var(--font-serif); font-style: italic; font-size: 12px; color: var(--text-secondary); }

/* ════════════════════════════════════════════════════════════════
   /coach — separate aesthetic (admin), green sweep only at P0;
   full restyle for /coach lands in P5.
   ════════════════════════════════════════════════════════════════ */
.coach-shell { padding: 32px 28px; max-width: 960px; margin: 0 auto; background: var(--bg-mint); min-height: 100vh; }
.coach-header { padding-bottom: 16px; border-bottom: 0.5px solid var(--border-line); margin-bottom: 24px;
  display: flex; align-items: baseline; justify-content: space-between; }
.coach-title { font-family: var(--font-serif); font-size: 20px; letter-spacing: 2px; color: var(--green-forest); }
.coach-nav { font-family: var(--font-sans); font-size: 13px; color: var(--text-secondary); }
.coach-nav a { margin-left: 14px; }
.coach-list { display: grid; grid-template-columns: 1fr; gap: 8px; }
/* 6/3 Patrick — list row grid: sid (110) / email (1fr) / tags (auto, min 110) /
   day (90) / open (88). Tags column 顯 is_beta + is_blocked pills (空格也 reserve). */
.coach-list__row { display: grid; grid-template-columns: 110px 1fr minmax(100px,auto) 90px 88px; gap: 12px;
  background: var(--paper-card); border: 0.5px solid var(--border-line); border-radius: 6px;
  padding: 12px 16px; align-items: center; font-family: var(--font-sans); font-size: 13px; color: var(--text-primary); cursor: pointer; }
.coach-list__sid { font-family: var(--font-sans); font-size: 13px; letter-spacing: 0.5px; }
.coach-list__email { color: var(--text-secondary); }
.coach-list__tags { display: flex; gap: 6px; flex-wrap: wrap; }
.coach-list__day { font-family: var(--font-serif); font-size: 13px; }
.coach-list__open { font-family: var(--font-serif); font-size: 13px; color: var(--text-secondary); text-align: right; }
/* 6/3 Patrick — is_beta / is_blocked pill 樣式 (brand peach / 灰). */
.coach-pill { display: inline-block; padding: 2px 9px; border-radius: 12px;
  font-family: var(--font-sans); font-size: 11px; letter-spacing: 1px;
  line-height: 1.5; white-space: nowrap; }
.coach-pill--beta { background: rgba(214,130,106,.16); color: var(--coral-soft, #b96544); }
.coach-pill--blocked { background: rgba(156,140,135,.18); color: var(--ink-dim, #9c8c87); }
/* v5.2 6/5 Vivi — active_context label (主場景) pill: muted blue-ink tone. */
.coach-pill--context { background: rgba(99,124,140,.14); color: var(--ink-deep, #4a5d68); }
.coach-section { margin-top: 32px; }
.coach-h2 { font-family: var(--font-serif); font-size: 14px; letter-spacing: 2px; color: var(--text-secondary); margin-bottom: 10px; }
/* P5 (PR-4c-green): 3×7 daily only — 週報 I/II/III column retired (spec 09 §10).
   Phase Reports render in a separate stacked section below the grid. */
.coach-mini-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; max-width: 480px;
  margin-bottom: 16px; }
.coach-mini-cell { height: 38px; border-radius: 4px; display: flex; align-items: center; justify-content: center;
  font-family: var(--font-serif); font-size: 11px; color: var(--text-primary); padding: 0 4px;
  border: 0.5px solid var(--border-line); box-sizing: border-box;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis; min-width: 0; }
.coach-mini-cell--active   { background: var(--peach-today);  border-color: var(--green-walked); }
.coach-mini-cell--revealed { background: var(--green-walked); border-color: var(--green-walked); color: #FFFFFF; }
.coach-mini-cell--graduation { grid-column: 1 / -1; font-size: 12px; letter-spacing: 2px; height: 32px; }
.coach-pre { background: var(--paper-card); border: 0.5px solid var(--border-line); border-radius: 6px;
  padding: 16px 18px; font-family: var(--font-serif); font-size: 14px; line-height: 1.85; color: var(--text-primary); white-space: pre-wrap;
  overflow-wrap: anywhere; word-break: break-word;
  box-sizing: border-box; max-width: 100%; }

/* 5/26 Patrick — transcript 容器 (paper card) 視覺照 .coach-pre、但 white-space: normal.
   .coach-pre 是 pre-wrap、會把 renderTranscript 模板字串的縮排/換行當可見空白
   渲染出來 → 角色標籤跟 body 之間爆出大段空白. 訊息內文自己的換行由
   .coach-transcript-msg__body { white-space: pre-wrap } 保留. */
.coach-transcript-box { background: var(--paper-card); border: 0.5px solid var(--border-line);
  border-radius: 6px; padding: 16px 18px; font-family: var(--font-serif); font-size: 14px;
  line-height: 1.6; color: var(--text-primary); white-space: normal;
  overflow-wrap: anywhere; word-break: break-word; box-sizing: border-box; max-width: 100%; }

/* 5/26 Vivi cleanup — dd43a8d 的「兩塊」 顯示已拆成獨立 section
   #coach-card-* (b1d2... 之後), 不再需要 .coach-note-box / .coach-note-block*.
   #coach-day-note 回到 .coach-pre 緊湊單塊樣式;
   #coach-card-body 沿用 .coach-pre 即可. */

/* PR-4c-green Patrick 5/24 — coach-only transcript message rows (audience=coach
   逐字 review). Subtle role label + paper card, no SaaS chat bubbles. */
.coach-transcript-msg { margin-bottom: 9px; padding-bottom: 7px;
  border-bottom: 0.5px dashed var(--border-line); }
.coach-transcript-msg:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
.coach-transcript-msg__role { font-family: var(--font-sans); font-size: 10px;
  letter-spacing: 2px; color: var(--text-secondary); margin-bottom: 4px;
  text-transform: uppercase; }
.coach-transcript-msg--user .coach-transcript-msg__role { color: var(--green-walked); }
.coach-transcript-msg__time { font-family: var(--font-sans); font-size: 10px;
  color: var(--text-faint); margin-left: 8px; letter-spacing: 0; text-transform: none; }
.coach-transcript-msg__body { font-family: var(--font-serif); font-size: 14px;
  line-height: 1.55; color: var(--text-primary); white-space: pre-wrap;
  overflow-wrap: anywhere; word-break: break-word; }
.coach-transcript-empty { font-family: var(--font-serif); font-style: italic;
  font-size: 13px; color: var(--text-faint); text-align: center; }

/* ════════════════════════════════════════════════════════════════
   shared utilities
   ════════════════════════════════════════════════════════════════ */
.muted   { color: var(--text-faint); }
.hidden  { display: none !important; }
