/* Hallmark · macrostructure: app-views (login/write/jar/history 共用系統) · theme: custom「暖黑房間×床頭燈」
 * genre: atmospheric · 移植自 design/mockup/ 三頁（設計真相源 docs/design/DESIGN.md）
 * SPA 差異：mockup 的 body 狀態 class 改掛在各 view section 上（#view-write.printing …），
 * 全域 overlay（peek sheet / 拆罐閱讀）維持 body class（一次只有一個 view 可見）。
 * #875（產品轉向：取消封存期）：拆罐儀式就地嵌進 #view-jar（不再是獨立 #view-ceremony），
 * 狀態 class（staged/holding/poured/scattered/settled/finished）沿用同一套機制，
 * 只是掛在 #view-jar 上；封存密語相關樣式（.cer-passphrase-box／#cer-passphrase／
 * .sealed／.finale .tally）整段退場，見 ADR-2026-08-30-875。 */

* { box-sizing: border-box; margin: 0; }
/* #918：html 也要上底色——iOS standalone 下 rubber-band 回彈／safe-area 邊緣露出的是
   html 的背景（不是 body 的），只設 body 那份在 notch/home-indicator 帶會看到系統預設色
   （偏黑但色不對，MM 回報「底部延展黑帶怪」的其中一個成因）。 */
html, body { height: 100%; overflow-x: clip; background: var(--room); }
body {
  color: var(--text);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
}
body::before { /* 燈只照中央：頁緣暗角 */
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
  background: radial-gradient(120% 90% at 50% 30%, transparent 55%, var(--room-deep) 100%);
}
[hidden] { display: none !important; }
a, button, input, textarea { font-family: inherit; }
:focus-visible { outline: 2px solid var(--lamp-dim); outline-offset: 2px; }

.view {
  position: relative; z-index: 1;
  max-width: 420px; margin: 0 auto;
  padding: var(--sp-6) var(--sp-4) 96px;
  /* #918：standalone PWA 沒有瀏覽器 UI，頁首直接貼著動態島/狀態列——
     原本只有固定 --sp-6（24px），完全沒吃 safe-area-inset-top，
     時鐘/電量列直接壓在 h1 上（MM 實機截圖）。inset=0 時 calc 結果等於原本的
     var(--sp-6)，一般瀏覽器零退化。 */
  padding-top: calc(var(--sp-6) + env(safe-area-inset-top, 0px));
}

/* 頁首靠左，破掉整頁單一置中軸（印表機/罐子仍是置中的 canvas） */
.page-head { text-align: left; margin-bottom: var(--sp-6); }
/* #887：三個分頁標題（罐子／寫一張／紀錄）跟副標同級沒有標題感——字級/字重都加重一階，
   副標（.sub）維持原樣不動，兩者的落差就是層級。 */
.page-head h1 { font-size: 26px; font-weight: 700; letter-spacing: 0.12em; }
.page-head .sub { margin-top: var(--sp-2); font-size: 14px; color: var(--text-dim); letter-spacing: 0.08em; }
.page-head .sub .m { color: var(--text); }

.history-page-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3);
}
.history-stats-link { padding-inline: var(--sp-3); font-size: 13px; }

/* ---------- #stats：罐子寫給兩人的月信 ---------- */
.stats-page-head { margin-bottom: var(--sp-4); }
.stats-back {
  display: inline-block; margin-bottom: var(--sp-4); color: var(--text-dim);
  font-size: 13px; letter-spacing: .1em; text-decoration: none;
}
.stats-back:hover { color: var(--text); }
.stats-month-nav {
  width: min(328px, 100%); margin: 0 auto var(--sp-4);
  display: grid; grid-template-columns: 44px 1fr 44px; align-items: center;
}
.stats-month-nav button {
  width: 40px; height: 40px; border: 1px solid var(--glass); border-radius: var(--radius-pill);
  background: transparent; color: var(--text-dim); cursor: pointer;
}
.stats-month-nav button:hover:not(:disabled) { color: var(--text); }
.stats-month-nav button:disabled { opacity: .25; cursor: default; }
.stats-month-nav button:focus-visible, .stats-back:focus-visible, .history-stats-link:focus-visible {
  outline-color: var(--glass);
}
#stats-month-label {
  color: var(--text); font-family: var(--font-label); text-align: center;
  font-size: 18px; letter-spacing: .12em;
}
.stats-letter {
  position: relative; width: min(328px, 100%); min-height: 120px; margin: 0 auto;
  padding: var(--sp-10) var(--sp-6); overflow: hidden;
  background: var(--paper); color: var(--ink); border-radius: var(--radius-paper);
  box-shadow: var(--shadow-paper); font-family: var(--font-receipt);
  transition: opacity 180ms var(--ease-fold), transform 280ms var(--ease-fold);
}
.stats-letter::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, transparent 48%, var(--crease-soft) 50%, transparent 52%);
}
.stats-letter.turning-left { opacity: 0; transform: rotateY(-5deg) translateX(-8px); }
.stats-letter.turning-right { opacity: 0; transform: rotateY(5deg) translateX(8px); }
.stats-passage {
  position: relative; padding: var(--sp-6) 0; font-size: var(--fs-receipt);
  line-height: var(--line-h); letter-spacing: var(--ls-receipt);
}
.stats-passage:first-child { padding-top: 0; }
.stats-passage:last-child { padding-bottom: 0; }
.stats-passage + .stats-passage { border-top: 1px solid var(--hairline); }
.stats-passage p { white-space: pre-line; }

/* #891：時段橫條圖——每位作者一條水平堆疊條，zero-dep（純 flex 比例寬度，
   不引入圖表庫）。掛在「兩人的時差」敘事句下方,同一個 .stats-passage 區塊裡,
   圖表是補充不是取代。 */
.stats-rhythm-bars { margin-top: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); }
.stats-rhythm-row { display: flex; align-items: center; gap: var(--sp-2); }
.stats-rhythm-emoji { flex: none; width: 1.4em; font-size: 15px; text-align: center; }
.stats-rhythm-track {
  flex: 1 1 auto; display: flex; height: 10px; overflow: hidden;
  border-radius: var(--radius-pill); background: var(--hairline);
}
.stats-rhythm-seg { display: block; height: 100%; }
.stats-rhythm-seg + .stats-rhythm-seg { border-left: 1px solid var(--paper); }
.stats-rhythm-seg[data-slot="dawn"]      { background: var(--rhythm-dawn); }
.stats-rhythm-seg[data-slot="day"]       { background: var(--rhythm-day); }
.stats-rhythm-seg[data-slot="noon"]      { background: var(--rhythm-noon); }
.stats-rhythm-seg[data-slot="afternoon"] { background: var(--rhythm-afternoon); }
.stats-rhythm-seg[data-slot="evening"]   { background: var(--rhythm-evening); }
.stats-rhythm-seg[data-slot="lateNight"] { background: var(--rhythm-latenight); }

.stats-rhythm-legend {
  list-style: none; display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3);
  margin-top: var(--sp-2); padding: 0;
}
.stats-rhythm-legend li { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink-faint); }
.stats-rhythm-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.stats-rhythm-swatch[data-slot="dawn"]      { background: var(--rhythm-dawn); }
.stats-rhythm-swatch[data-slot="day"]       { background: var(--rhythm-day); }
.stats-rhythm-swatch[data-slot="noon"]      { background: var(--rhythm-noon); }
.stats-rhythm-swatch[data-slot="afternoon"] { background: var(--rhythm-afternoon); }
.stats-rhythm-swatch[data-slot="evening"]   { background: var(--rhythm-evening); }
.stats-rhythm-swatch[data-slot="lateNight"] { background: var(--rhythm-latenight); }

.error { margin-top: var(--sp-3); font-size: 15px; color: var(--lamp); letter-spacing: 0.05em; }

/* ---------- 按鈕（儀式琥珀／ghost） ---------- */
.btn-ritual {
  display: inline-block;
  padding: var(--sp-3) var(--sp-10); border: 0; border-radius: var(--radius-pill);
  background: var(--lamp); color: var(--ink);
  font-size: 17px; font-weight: 600; letter-spacing: 0.2em; text-indent: 0.2em;
  white-space: nowrap; text-decoration: none; cursor: pointer;
}
.btn-ritual:hover:not([disabled]) { background: var(--lamp-bright); }
.btn-ritual:active { transform: scale(0.97); }
.btn-ritual[disabled] { opacity: .4; cursor: not-allowed; }
.btn-ghost {
  display: inline-block;
  padding: var(--sp-2) var(--sp-6); border: 1px solid var(--hairline-strong); border-radius: var(--radius-pill);
  background: transparent; color: var(--text-dim);
  font-size: 15px; letter-spacing: 0.15em; white-space: nowrap; cursor: pointer; text-decoration: none;
}
.btn-ghost:hover { color: var(--text); }

/* ---------- 登入 ---------- */
.login-box { margin-top: var(--sp-10); }
.field-label { font-size: 14px; color: var(--text-dim); letter-spacing: 0.12em; margin-bottom: var(--sp-2); }
/* #835：登入密語——type=text＋圓點顯示（password 型別擋 IME，中文密語打不進去） */
#passphrase {
  width: 100%; margin-bottom: var(--sp-6);
  background: var(--room-lift); color: var(--text);
  border: 1px solid var(--hairline); border-radius: var(--radius-card);
  padding: var(--sp-3) var(--sp-4);
  font-size: 18px; letter-spacing: 0.08em; /* ≥16px：iOS 聚焦不 zoom（#836） */
  -webkit-text-security: disc;
}
#passphrase::placeholder { color: var(--text-dim); }
#passphrase:focus {
  outline: 2px solid var(--lamp-dim); outline-offset: 0; border-color: transparent;
}
.member-buttons { display: flex; gap: var(--sp-3); }
.member-buttons button {
  flex: 1; padding: var(--sp-3) var(--sp-2);
  background: var(--room-lift); color: var(--text);
  border: 1px solid var(--hairline-strong); border-radius: var(--radius-card);
  font-size: 17px; letter-spacing: 0.1em; cursor: pointer;
}
.member-buttons button:hover { border-color: var(--lamp-dim); }
.member-buttons button:active { transform: scale(0.97); }
.member-buttons .m-emoji { display: block; font-size: 24px; margin-bottom: var(--sp-2); }

/* ---------- #872：語言切換（低調 footer，不搶暗房氛圍） ---------- */
.lang-switch {
  display: flex; justify-content: center; align-items: center; gap: var(--sp-1);
  margin-top: var(--sp-10); font-size: 12px; letter-spacing: 0.1em; color: var(--text-dim);
}
.lang-switch span { opacity: .4; }
.lang-switch button {
  background: none; border: 0; padding: var(--sp-1) var(--sp-2);
  color: var(--text-dim); font-size: 12px; letter-spacing: 0.1em; cursor: pointer;
}
.lang-switch button:hover { color: var(--text); }
.lang-switch button.on { color: var(--lamp); }

/* ---------- #write：印表機 ---------- */
.printer-scene { position: relative; width: 280px; margin: 0 auto; }
/* #858：這裡原本是固定 `min-height: 340px`——紙的容器（.paper-track 以下全是
   position:absolute，不佔文件流高度）沒有這個高度，短紙印完後面的「折起來」
   按鈕會離紙一大截空白；照 8 行上限的紙算勉強夠、但短紙就是純浪費空間。
   改成 printNote() 在算出紙高 H 的同時，用 inline style 把這裡設成剛好夠放
   那張紙的高度（見 app.js `sizePrinterScene`），紙多長容器就多高，
   resetWrite() 收工時清掉，回到 idle 沒有這個高度限制。 */
#svg-printer { display: block; width: 280px; height: 120px; }
#led { fill: var(--text-dim); transition: fill 150ms; }
#view-write.printing #led { fill: var(--lamp); }

.slot-light {
  position: absolute; top: 88px; left: 50%; transform: translateX(-50%);
  width: 224px; height: 3px; border-radius: 2px;
  background: var(--lamp); opacity: 0; transition: opacity 150ms;
  box-shadow: 0 0 12px var(--lamp), 0 0 3px var(--lamp);
  pointer-events: none;
}
.slot-light.on { opacity: 1; animation: hum 700ms linear infinite; }
@keyframes hum { 50% { opacity: .75; } }

.ka {
  position: absolute; top: 74px; right: -4px;
  font-size: 15px; color: var(--text-dim); letter-spacing: 0.1em;
  opacity: 0; pointer-events: none;
}
.ka.flash { animation: kaflash 300ms ease-out; }
@keyframes kaflash { 20% { opacity: 1; transform: translateY(-2px); } 100% { opacity: 0; } }

/* ---------- #write：紙 ---------- */
.paper-track {
  position: absolute; top: 93px; left: 50%; transform: translateX(-50%);
  width: 220px;
}
.paper-stage {
  perspective: 800px;
  transform-origin: top center;
  transition: transform var(--dur-fold2) var(--ease-fold), opacity 150ms linear;
}
.paper-stage.cut { animation: cut var(--dur-cut) ease-out; }
@keyframes cut { from { transform: translateY(4px) rotate(-0.6deg); } to { transform: none; } }
#view-write.fold2 .paper-stage { transform: scaleX(0.5); }
.paper-stage.gone { opacity: 0; }

/* 進紙＝固定視窗＋紙 translateY（只動 transform，不動 layout） */
.paper-window { width: 220px; height: 0; overflow: hidden; }
.paper-window.printed { overflow: visible; }
.paper { width: 220px; position: relative; will-change: transform; }
.paper-inner {
  background: var(--paper);
  /* 熱印的橫向 banding，極淡 */
  background-image: repeating-linear-gradient(
    to bottom, var(--band) 0 1px, transparent 1px 3px);
  border-radius: 0 0 var(--radius-paper) var(--radius-paper);
  padding: var(--sp-3) var(--sp-3) var(--sp-2);
  font-family: var(--font-receipt);
  font-size: var(--fs-receipt);
  letter-spacing: var(--ls-receipt);
  line-height: var(--line-h);
  color: var(--ink);
  box-shadow: var(--shadow-paper);
}
#view-write.folding .paper-inner { clip-path: inset(0 0 50% 0); box-shadow: none; }
.line { display: block; min-height: var(--line-h); clip-path: inset(0 0 100% 0); }
.line.meta { color: var(--ink-faint); font-size: 14px; text-align: right; }
#view-write.printing .line, #view-write.printed .line { animation: reveal var(--dur-reveal) linear forwards; }
@keyframes reveal { to { clip-path: inset(0 0 -2px 0); } }
#view-write.printing .paper-inner { animation: jitter 90ms steps(2) infinite; }
@keyframes jitter { 50% { transform: translateX(0.4px); } }

/* 折紙 flap（第一折：下半以中線為軸翻上來） */
.flap {
  position: absolute; left: 0; width: 100%; z-index: 2;
  transform-origin: top center; transform-style: preserve-3d;
  transition: transform var(--dur-fold) var(--ease-fold);
}
#view-write.fold1 .flap { transform: rotateX(-180deg); }
.flap-face {
  position: absolute; inset: 0; overflow: hidden;
  background: var(--paper); backface-visibility: hidden;
  border-radius: 0 0 var(--radius-paper) var(--radius-paper);
}
.flap-front::after { /* 折縫陰影 */
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to bottom, var(--crease), transparent 30%);
}
.flap-back { transform: rotateX(180deg); }
.flap-back::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, var(--crease-soft), transparent 40%); }

/* 折好的紙塊與拋物線（外層 x 線性、內層 y 重力加速） */
.chip-x { position: fixed; z-index: 30; transition: transform var(--dur-drop) linear; }
.chip-y { transition: transform var(--dur-drop) var(--ease-drop); }
.fly-chip {
  width: 110px; height: 52px; border-radius: var(--radius-paper);
  background: var(--paper);
  background-image:
    linear-gradient(to bottom, transparent 48%, var(--crease) 49% 51%, transparent 52%),
    linear-gradient(to right, transparent 48%, var(--crease-soft) 49% 51%, transparent 52%);
  box-shadow: var(--shadow-chip);
  transition: transform var(--dur-drop) linear;
}
.fly-chip.fly { transform: rotate(12deg) scale(0.5); }

/* ---------- #write：輸入 ---------- */
.compose { margin-top: var(--sp-6); transition: opacity 250ms; }
#view-write.printing .compose, #view-write.printed .compose { display: none; }
textarea {
  width: 100%; min-height: 96px; resize: none;
  background: var(--room-lift); color: var(--text);
  border: 1px solid var(--hairline); border-radius: var(--radius-card);
  padding: var(--sp-4);
  /* #836：輸入類一律 ≥16px——iOS Safari 對 <16px 的 input/textarea 聚焦自動 zoom
     且 blur 不縮回，整頁跑版（MM 實踩）。紙條字維持 --fs-receipt，只有輸入框放大。 */
  font-family: var(--font-receipt); font-size: 18px;
  letter-spacing: var(--ls-receipt); line-height: var(--line-h);
}
textarea::placeholder { color: var(--text-dim); }
textarea:focus { outline: 2px solid var(--lamp-dim); outline-offset: 0; border-color: transparent; }
.compose .btn-ritual { display: block; margin: var(--sp-4) auto 0; }

/* #830：時間可選（摺疊入口）。低調如 peek——不搶「寫」的主線 */
.backdate { margin-top: var(--sp-2); }
.backdate summary {
  display: inline-block; cursor: pointer; list-style: none;
  font-size: 14px; color: var(--text-dim); letter-spacing: 0.08em;
  padding: var(--sp-1) 0;
}
.backdate summary::-webkit-details-marker { display: none; }
/* 可發現性（MM 2026-08-29 反饋「不知道可以按」＋codex 二意見）：句子保留、
   只補一枚暖灰小 chevron 當「可展開」的形狀線索——不用琥珀不發光，
   不破壞 DESIGN.md 的暗房安靜感；[open] 時翻向上。 */
.backdate summary::after {
  content: ''; display: inline-block; margin-left: 8px;
  width: 6px; height: 6px; vertical-align: 2px;
  border-right: 1.5px solid var(--text-dim); border-bottom: 1.5px solid var(--text-dim);
  transform: rotate(45deg); transition: transform .2s;
}
.backdate[open] summary::after { transform: rotate(-135deg); vertical-align: -1px; }
.backdate summary:hover { color: var(--text); }
.backdate[open] summary { color: var(--text); }
/* #833：自製時間選擇器——MD3 的形（格線日曆、圓形選取、時鐘面），房間的色。
   觸控目標 ≥44px（日格、head 切換鍵）；時鐘拖曳由整個錶面接。 */
.picker {
  margin-top: var(--sp-2);
  background: var(--room-lift);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  padding: var(--sp-3);
  font-family: var(--font-ui);
}
.picker-head {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-1);
  margin-bottom: var(--sp-2);
}
.picker-part {
  background: none; border: 0; cursor: pointer;
  color: var(--text-dim); font-family: inherit; font-size: 21px;
  min-width: 44px; min-height: 44px;
  border-radius: var(--radius-card);
}
.picker-part.on { color: var(--lamp); background: var(--lamp-wash); }
.picker-dot, .picker-colon { color: var(--text-dim); font-size: 18px; }

.cal-title {
  text-align: center; font-size: 14px; color: var(--text-dim);
  letter-spacing: 0.08em; margin-bottom: var(--sp-2);
}
.cal-grid {
  display: grid; grid-template-columns: repeat(7, 1fr);
  justify-items: center; row-gap: 2px;
}
.cal-head { font-size: 13px; color: var(--text-dim); line-height: 24px; }
.cal-day {
  width: 44px; height: 44px; max-width: 100%;
  border: 0; border-radius: var(--radius-pill);
  background: none; color: var(--text); font-family: inherit; font-size: 16px;
  cursor: pointer;
}
.cal-day:disabled { color: var(--text-dim); opacity: .35; cursor: default; }
.cal-day.today { box-shadow: inset 0 0 0 1px var(--lamp-dim); } /* 今天：琥珀細圈 */
.cal-day.on { background: var(--lamp); color: var(--ink); }      /* 選中：MD 圓形選取 */
.cal-day:not(:disabled):not(.on):hover { background: var(--hairline); }

.clock { display: flex; justify-content: center; padding: var(--sp-2) 0; }
.clock-dial {
  position: relative; width: 256px; height: 256px; border-radius: var(--radius-pill);
  background: var(--room-deep);
  touch-action: none;   /* 拖曳選時間，不讓頁面跟著捲 */
  user-select: none; -webkit-user-select: none;
  cursor: pointer;
}
.clock-num {
  position: absolute; width: 40px; height: 40px; margin: -20px 0 0 -20px;
  display: grid; place-items: center; border-radius: var(--radius-pill);
  font-size: 16px; color: var(--text);
  pointer-events: none; /* 命中交給錶面角度換算，不逐顆接事件 */
}
.clock-num.inner { font-size: 14px; color: var(--text-dim); }
.clock-num.on { background: var(--lamp); color: var(--ink); }
.clock-pin {
  position: absolute; left: 50%; top: 50%; width: 8px; height: 8px;
  margin: -4px 0 0 -4px; border-radius: var(--radius-pill); background: var(--lamp);
}
.clock-hand {
  position: absolute; left: calc(50% - 1px); bottom: 50%;
  width: 2px; height: 40%;              /* 指到外圈數字（半徑 40%） */
  background: var(--lamp);
  transform-origin: 50% 100%;
  transition: transform 150ms var(--ease-ui);
}
.clock-hand.short { height: 26%; }      /* 內圈（00、13–23）縮到內圈半徑 */
.clock-knob { display: block; position: absolute; top: 0; left: 50%;
  width: 6px; height: 6px; margin-left: -3px;
  border-radius: var(--radius-pill); background: var(--lamp); }
@media (prefers-reduced-motion: reduce) {
  .clock-hand { transition: none; }     /* #833 驗收：reduced motion 不加動畫 */
}

.after { min-height: 56px; }
/* #863：.after 只會裝進一顆動態插入的 .btn-ritual（見 app.js printNote() 結尾
   appendChild 那顆「折起來」按鈕）——.btn-ghost／.rollback 從未出現在這個容器底下，
   兩個死選擇器（從未匹配過任何元素）已清掉。 */
.after .btn-ritual { display: block; margin: var(--sp-4) auto 0; animation: fadein 250ms ease-out; }
@keyframes fadein { from { opacity: 0; } }

/* ---------- #write：迷你罐（掉落目標） ---------- */
.mini-jar {
  position: fixed; right: 18px; z-index: 20;
  /* #918：原本 76px 靜態值＝56px tabbar 可視高＋20px 呼吸間距，沒算 tabbar
     為了 home indicator 多墊的 env(safe-area-inset-bottom)（見 .tabbar），
     結果迷你罐下緣被 nav bar 蓋住一截（MM 實機截圖）。把同一段 inset 加回來，
     inset=0 時等於原本 76px，零退化。 */
  bottom: calc(76px + env(safe-area-inset-bottom, 0px));
  width: 56px; text-align: center;
}
.mini-jar svg { display: block; width: 56px; height: 68px; }
.mini-jar .count {
  position: absolute; left: 0; right: 0; top: 32px;
  font-family: var(--font-receipt); font-size: 15px; color: var(--text-dim);
}
.mini-jar.pop { animation: pop 150ms ease-out; }
@keyframes pop { 40% { transform: scale(1.03, 0.97); } }

/* ---------- #jar：罐子場景 ---------- */
.jar-scene { position: relative; width: 280px; margin: 0 auto; }
.jar-scene > svg { display: block; width: 280px; height: 374px; }
.jar-overlay { position: absolute; inset: 0; pointer-events: none; }
.chips { position: absolute; inset: 0; }
.chips .chip {
  position: absolute; width: 56px; height: 26px;
  border: 0; padding: 0; cursor: pointer;
  border-radius: var(--radius-paper);
  background-color: var(--paper);
  background-image:
    linear-gradient(to bottom, transparent 46%, var(--crease) 48% 52%, transparent 54%),
    linear-gradient(to right, transparent 46%, var(--crease-soft) 48% 52%, transparent 54%);
  box-shadow: var(--shadow-chip);
}
.chips .chip.b { background-color: var(--paper-b); }
.jar-empty {
  position: absolute; left: 0; right: 0; top: 46%;
  text-align: center; font-size: 15px; color: var(--text-dim); letter-spacing: 0.1em;
}
/* #887：中央置中的窄版——縮字寬強制換行＋淡色底塊，三語長度不同都不准壓到罐身線條。
   只覆寫罐子頁這顆（#history-empty／#history-filtered-empty 沿用 .jar-empty 原樣，
   #886 教訓：這個 class 兩頁共用，改動範圍鎖在 ID 選擇器上，不動共用基底）。
   寬度收在玻璃高光兩條豎線（.jar-overlay 的 72px／230px）之間留出餘裕，
   --room-lift 是既有「略亮一層」卡片色票，不是新發明的顏色。 */
#jar-empty {
  top: 54%; left: 50%; right: auto; transform: translate(-50%, -50%);
  width: 132px; line-height: 1.7;
  background: var(--room-lift); border-radius: var(--radius-card);
  padding: var(--sp-3) var(--sp-2);
}

/* #901：.jar-empty 的絕對定位是為「高罐子插圖／canvas」量身訂做的——top:46% 靠插圖固定
   高度撐出置中效果（#jar-empty 疊在 374px 的 .jar-scene 上、#history-empty 疊的頁面裡
   history-sub 空狀態會被清空成空字串所以沒視覺衝突）。#stats-empty 沒有插圖可疊，副標
   （.stats-page-head .sub）又是寫死文字不會被清空；空狀態下 #stats-month-nav／
   #stats-letter 都 hidden（app.js enterStats），.view 塌到只剩 header 高度，
   top:46% 直接算進 header 範圍，副標跟空狀態訊息疊字。改回文件流本身，比照 .stats-letter
   的頂部留白（var(--sp-10)），不再靠容器高度換算位置。 */
#stats-empty {
  position: static;
  margin-top: var(--sp-10);
}

/* 罐口掛牌（月份標籤，楷體＝實體寫在標籤上的字） */
.tag {
  position: absolute; top: 52px; right: -6px;
  width: auto; min-width: 78px; padding: var(--sp-2); /* 張數位數多時掛牌加寬，不折行 */
  background: var(--paper);
  border-radius: 3px;
  transform: rotate(7deg);
  text-align: center;
  box-shadow: var(--shadow-tag);
}
.tag::before { /* 綁繩穿孔 */
  content: ""; position: absolute; top: 5px; left: 50%; margin-left: -3px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--room); opacity: .55;
}
.tag .m { display: block; margin-top: 6px; font-family: var(--font-label); font-size: 24px; color: var(--ink); }
.tag .c { display: block; margin-top: 2px; font-family: var(--font-receipt); font-size: 13px; color: var(--ink-faint); letter-spacing: 0.08em; white-space: nowrap; }

.early {
  display: block; text-align: center; margin: var(--sp-2) auto 0;
  background: none; border: 0; font-size: 14px; color: var(--text-dim);
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.early:hover { color: var(--text); }

/* ---------- #831：回應＋星標 ---------- */
.note-extras { margin-top: var(--sp-3); }
.reply { display: flex; flex-direction: column; padding: var(--sp-2) 0; border-top: 1px solid var(--hairline); }
/* #920：回應改多行——white-space:pre-wrap 保留使用者敲的換行，word-break 頂住
   單詞長到會撐爆容器的情況（跟 .receipt 的紙條本文同一套處理）。 */
.reply .r-body { font-size: 15px; color: var(--text); line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
.reply .r-meta { font-size: 13px; color: var(--text-dim); margin-top: 2px; }
/* #920：align-items 從 center 改 flex-end——textarea 長高時，送出/📌/⭐ 三顆
   按鈕貼著輸入框底部（單行時視覺跟 center 幾乎沒差，多行時才看得出差異，
   是最常見的聊天輸入列排法）。 */
.reply-row { display: flex; gap: var(--sp-2); align-items: flex-end; margin-top: var(--sp-2); }
.reply-row textarea {
  flex: 1; min-width: 0;
  background: var(--room-lift); color: var(--text);
  border: 1px solid var(--hairline);
  /* #920：原本 input 用 --radius-pill（999px）單行是好看的膠囊；長高到多行
     還維持全圓角兩端會變成很怪的橢圓，退到 --radius-card——單行/多行都自然。 */
  border-radius: var(--radius-card);
  /* 16px 非 13px：iOS 聚焦自動 zoom 的門檻（#836）；回應文字 .r-body 仍 13px 不動 */
  padding: var(--sp-2) var(--sp-3); font-family: var(--font-ui); font-size: 18px;
  /* #920：auto-grow textarea——resize:none 拿掉瀏覽器原生拖曳把手（跟自動長高
     衝突），line-height 給固定值讓 JS／CSS 對「幾行」算的是同一個數字，
     max-height 頂住 5 行高度、超過內部自己捲（overflow-y:auto），JS 只管長高
     （el.style.height = scrollHeight px），CSS 的 max-height 自然把它夾住。 */
  resize: none; overflow-y: auto; line-height: 1.4;
  max-height: calc(1.4em * 5 + var(--sp-2) * 2);
}
.reply-row textarea::placeholder { color: var(--text-dim); }
.reply-row textarea:focus { outline: 2px solid var(--lamp-dim); outline-offset: 0; border-color: transparent; }
.reply-send {
  background: none; border: 1px solid var(--hairline-strong); border-radius: var(--radius-pill);
  color: var(--text); font-family: var(--font-ui); font-size: 15px;
  padding: var(--sp-1) var(--sp-3); cursor: pointer;
}
.reply-send:hover { border-color: var(--lamp-dim); color: var(--lamp-bright); }
/* #920：防雙擊——送出中 disabled，disabled 的原生語意本身就擋掉第二次 click
   （不需要額外的 .pending class／JS 計數器）；:disabled 選擇器兼職當 pending
   態的視覺提示。 */
.reply-send:disabled { opacity: .5; cursor: default; pointer-events: none; }
.star-btn {
  background: none; border: none; cursor: pointer;
  font-size: 18px; line-height: 1; padding: var(--sp-1);
  filter: grayscale(1); opacity: .45; transition: filter 150ms, opacity 150ms, transform 150ms;
}
.star-btn:hover { opacity: .75; }
.star-btn.on { filter: none; opacity: 1; transform: scale(1.1); }
.star-btn:focus-visible { outline: 2px solid var(--lamp-dim); border-radius: var(--radius-card); }

/* 拆罐展開視圖裡的回應區：懸在遮罩上，跟著紙一起浮現 */
.overlay .note-extras { animation: fadein 250ms ease-out 1100ms backwards; }
.overlay .reply .r-body { color: var(--text); }

/* ---------- #885：紀錄工具列（排序＋篩選）----------
 * #900：原本單一橫向捲動列（overflow-x: auto＋scrollbar-width: none，不換行）
 * ——實測連 app 自己的版心（.view max-width 420px）都不夠塞下全部控制項，
 * 常態就是靜默溢出（無捲軸提示，排序鈕被裁在看不到的地方），MM 反映擠壓/看不到
 * 排序狀態就是這個。改 flex-wrap：塞得下維持單行，塞不下自然換行，不再裁切。
 * #900 reviewer 抓到第一版的坑：.ht-chips 若帶 flex: 0 0 auto，對外層 .ht-scroll
 * 回報的是「不換行」的 max-content 寬度、且禁止壓縮——外層永遠拿到同一個過寬數字，
 * 自己的 flex-wrap 沒機會生效（暱稱長/chip 多時整塊溢出、裁掉看不到）。
 * 改 flex: 1 1 auto; min-width: 0——允許在被單獨分到一行後縮回容器寬度，
 * 這樣它自己的 flex-wrap 才真的會把 chip 折成多行，不論暱稱多長、chip 多少顆。
 * 視覺貼齊既有 chip/按鈕語言：chip 借 .btn-ghost 的 pill／hairline 邏輯，
 * 星標 toggle 借 .star-btn 的 grayscale 開關手法（見上面「回應＋星標」區）。 */
.history-toolbar { margin: var(--sp-4) 0 var(--sp-6); }
/* #886：篩空訊息不能沿用罐子頁的絕對定位置中（會浮到工具列上），改回文流 */
#history-filtered-empty { position: static; margin: var(--sp-8) 0; }
.ht-scroll { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); }
.ht-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); flex: 1 1 auto; min-width: 0; }
.ht-chip {
  flex: 0 0 auto; white-space: nowrap; font-family: inherit;
  padding: var(--sp-1) var(--sp-3); border: 1px solid var(--hairline-strong); border-radius: var(--radius-pill);
  background: transparent; color: var(--text-dim); font-size: 14px; letter-spacing: 0.05em; cursor: pointer;
}
.ht-chip:hover { color: var(--text); }
.ht-chip.on { border-color: var(--lamp-dim); color: var(--lamp); background: var(--lamp-wash); }
/* #888：📌 Pin／⭐ Star 兩顆篩選 toggle 共用同一套視覺——原本單顆 .ht-star-toggle
 * 的 grayscale 開關手法，選擇器加上 .ht-pin-toggle 一起套，不重複寫規則。 */
.ht-star-toggle, .ht-pin-toggle {
  flex: 0 0 auto; background: none; border: 1px solid var(--hairline-strong); border-radius: var(--radius-pill);
  padding: var(--sp-1) var(--sp-3); font-size: 15px; line-height: 1; cursor: pointer;
  filter: grayscale(1); opacity: .55; transition: filter 150ms, opacity 150ms, border-color 150ms;
}
.ht-star-toggle:hover, .ht-pin-toggle:hover { opacity: .8; }
.ht-star-toggle.on, .ht-pin-toggle.on { filter: none; opacity: 1; border-color: var(--lamp-dim); }
.ht-sort-toggle {
  flex: 0 0 auto; white-space: nowrap; font-family: inherit;
  background: none; border: 1px solid var(--hairline-strong); border-radius: var(--radius-pill);
  padding: var(--sp-1) var(--sp-3); color: var(--text-dim); font-size: 13px; letter-spacing: 0.05em; cursor: pointer;
}
.ht-sort-toggle:hover { color: var(--text); }

/* ---------- #882：紀錄分兩塊（有新訊息／沒有新動靜）---------- */
.history-block + .history-block { margin-top: var(--sp-10); }
.history-block-heading {
  font-size: 14px; font-weight: 400; color: var(--text-dim); letter-spacing: 0.25em;
  margin-bottom: var(--sp-3); text-transform: uppercase;
}
.history-block .history-month:first-of-type { margin-top: 0; }

/* ---------- #875：紀錄（沉澱歷史）---------- */
.history-month + .history-month { margin-top: var(--sp-8); }
.history-month h2 {
  font-family: var(--font-label); font-size: 20px; font-weight: 400;
  color: var(--text); margin-bottom: var(--sp-2);
}
.history-row {
  display: flex; flex-direction: column; width: 100%; text-align: left; gap: 2px;
  background: none; border: none; border-top: 1px solid var(--hairline); cursor: pointer;
  padding: var(--sp-3) var(--sp-1); font-family: var(--font-ui);
}
.history-row .h-top {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2);
  font-size: 13px; color: var(--text-dim); font-family: var(--font-receipt); letter-spacing: 0.05em;
}
.history-row .h-snippet {
  color: var(--text); font-size: 16px; line-height: 1.5;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;
}
.history-row:hover .h-snippet { color: var(--lamp-bright); }
.history-row .h-meta { font-size: 13px; color: var(--text-dim); }
.history-row .h-meta .star { color: var(--lamp-dim); }

/* #921：任何全螢幕疊層開著（peek sheet／拆罐單張展開）就鎖背景捲動——
   疊層本身有自己的捲動容器（.sheet-scroll／未來若拆罐內文也長到需要捲）,
   背景（罐子場景／紀錄清單）不該再跟著手指一起動。純 CSS，兩個 class
   各自獨立掛拿掉都對，不用另外寫 JS 計數器。 */
body.peeking, body.reading { overflow: hidden; }

/* ---------- peek bottom sheet（低調：無琥珀） ---------- */
.backdrop {
  position: fixed; inset: 0; z-index: 50;
  background: var(--scrim);
  opacity: 0; pointer-events: none; transition: opacity var(--dur-sheet);
}
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 51;
  max-width: 420px; margin: 0 auto;
  /* #921：長回覆串會把 sheet 撐爆視窗——sheet 本身不再無限長高，
     超出 85vh 的部分交給 .sheet-scroll 自己捲（見下）。 */
  max-height: 85vh;
  display: flex; flex-direction: column;
  background: var(--room-lift);
  border-radius: 16px 16px 0 0;
  padding: var(--sp-4) var(--sp-4) calc(var(--sp-6) + env(safe-area-inset-bottom));
  transform: translateY(100%);
  transition: transform var(--dur-sheet) var(--ease-ui);
  visibility: hidden;
}
body.peeking .backdrop { opacity: 1; pointer-events: auto; }
body.peeking .sheet { transform: translateY(0); visibility: visible; }
.sheet .grip {
  flex: none; width: 36px; height: 4px; border-radius: 2px;
  background: var(--hairline-strong); margin: 0 auto var(--sp-4);
}
/* #921：內文＋回應串的獨立捲動容器——grip／close 留在外層固定不動。
   overscroll-behavior:contain 擋滾到底之後繼續往上滾穿透到背景清單（scroll chaining）；
   -webkit-overflow-scrolling 是舊 iOS Safari 慣性捲動的必要值，新版忽略無妨。 */
.sheet-scroll {
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  min-height: 0; /* flex 子項預設 min-height:auto 撐開父層，蓋掉 max-height，這裡要蓋掉那個預設 */
}
.receipt {
  width: var(--paper-w); margin: 0 auto;
  background: var(--paper);
  background-image: repeating-linear-gradient(to bottom, var(--band) 0 1px, transparent 1px 3px);
  border-radius: var(--radius-paper);
  padding: var(--sp-4) var(--sp-4) var(--sp-3);
  font-family: var(--font-receipt); font-size: var(--fs-receipt);
  letter-spacing: var(--ls-receipt); line-height: var(--line-h);
  color: var(--ink); white-space: pre-wrap; word-break: break-word;
  box-shadow: var(--shadow-sheet);
}
.receipt .meta { margin-top: var(--sp-2); color: var(--ink-faint); font-size: 14px; text-align: right; white-space: pre-line; /* 署名/時間分行（MM 2026-08-29） */ }
.sheet .close {
  flex: none; /* #921：留在 .sheet-scroll 外層，不隨內文捲走 */
  display: block; margin: var(--sp-4) auto 0;
  padding: var(--sp-2) var(--sp-6); border: 1px solid var(--hairline-strong); border-radius: var(--radius-pill);
  background: transparent; color: var(--text-dim);
  font-size: 15px; letter-spacing: 0.15em; white-space: nowrap; cursor: pointer;
}
.sheet .close:hover { color: var(--text); }

/* ---------- 拆罐儀式：第一關（兩個人都在了嗎）----------
 * #875：就地嵌在 #view-jar 裡（不再是獨立 #view-ceremony），狀態 class
 * 照舊掛在 #view-jar 上；#jar-normal（罐子場景／倒出來看／星標）在儀式
 * 開始時整塊隱藏（見 app.js startCeremony），不需要額外的顯隱 class。 */
.gate { text-align: center; padding-top: 96px; }
.gate p { font-size: 22px; letter-spacing: 0.1em; line-height: 1.9; }
.gate .why { margin-top: var(--sp-3); font-size: 15px; color: var(--text-dim); }
.gate .btn-ritual { margin-top: var(--sp-10); }

/* ---------- 拆罐儀式：按住罐子 ---------- */
.stage { display: none; }
#view-jar.staged .stage { display: block; }
#view-jar.staged .gate { display: none; }

.jar-hold {
  position: relative; width: 170px; margin: 0 auto;
  touch-action: none; user-select: none; -webkit-user-select: none;
  transition: transform 400ms var(--ease-ui), opacity 400ms;
  cursor: pointer;
}
.jar-hold svg.jar { display: block; width: 170px; height: 227px;
  transition: transform var(--dur-pour) var(--ease-pour);
  transform-origin: 50% 12%;      /* 以罐口為軸傾倒 */
}
#view-jar.holding .jar-hold { transform: scale(1.04); }
#view-jar.poured .jar-hold svg.jar { transform: rotate(120deg); }
#view-jar.settled .jar-hold { transform: translateY(-10px) scale(0.72); opacity: .45; }

/* 長按進度環（罐口） */
.ring { position: absolute; top: -22px; left: 50%; margin-left: -32px; width: 64px; height: 64px; }
.ring circle {
  fill: none; stroke: var(--lamp); stroke-width: 3; stroke-linecap: round;
  stroke-dasharray: 176; stroke-dashoffset: 176;
  transform: rotate(-90deg); transform-origin: center;
  opacity: 0;
}
#view-jar.holding .ring circle { opacity: 1; animation: ringfill var(--hold-open) linear forwards; }
@keyframes ringfill { to { stroke-dashoffset: 0; } }

.hold-hint { text-align: center; margin-top: var(--sp-4); font-size: 15px; color: var(--text-dim); letter-spacing: 0.1em; }

/* ---------- 拆罐儀式：地板與散落 ----------
 * 設計 reviewer 移交 (a)：散落 chip 不得遮進度字——
 * mockup 的 .floor 用 margin-top:-40px 疊上進度列；這裡取消負 margin，
 * 散落區完全落在進度字下方，另給 .progress 疊高保險。 */
.floor { position: relative; height: 380px; margin-top: var(--sp-2); z-index: 1; }
.fchip {
  position: absolute; width: 56px; height: 26px;
  border: 0; padding: 0; cursor: pointer;
  border-radius: var(--radius-paper);
  background-color: var(--paper);
  background-image:
    linear-gradient(to bottom, transparent 46%, var(--crease) 48% 52%, transparent 54%),
    linear-gradient(to right, transparent 46%, var(--crease-soft) 48% 52%, transparent 54%);
  box-shadow: var(--shadow-chip);
  opacity: 0; pointer-events: none;
}
.fchip.b { background-color: var(--paper-b); }
#view-jar.scattered .fchip {
  pointer-events: auto;
  animation: fall 700ms var(--ease-fall) forwards;
  animation-delay: var(--d);
}
/* 550ms 自由落體＋150ms 著地小彈跳（fall 78% 處落地） */
@keyframes fall {
  0%   { opacity: 0; transform: translate(var(--dx), var(--dy)) rotate(0deg); }
  6%   { opacity: 1; }
  78%  { transform: translate(0, 0) rotate(var(--r)); }
  89%  { transform: translate(0, -6px) rotate(var(--r)); }
  100% { opacity: 1; transform: translate(0, 0) rotate(var(--r)); }
}
.fchip.collected { transition: opacity 300ms ease-in; opacity: 0 !important; pointer-events: none !important; }

.progress {
  display: none; position: relative; z-index: 5;
  text-align: center; margin-top: var(--sp-2);
  font-family: var(--font-receipt); font-size: 15px; letter-spacing: 0.15em;
  color: var(--text-dim);
}
#view-jar.settled .progress { display: block; }

/* ---------- 拆罐儀式：單張展開 ---------- */
.overlay {
  position: fixed; inset: 0; z-index: 60;
  display: none; place-items: center;
  background: var(--scrim-read);
  padding: var(--sp-4);
}
body.reading .overlay { display: grid; }
.overlay .receipt {
  box-shadow: var(--shadow-read);
  animation: unfold 920ms var(--ease-fold);
  position: relative; overflow: hidden;
}
/* 展開：0.25 → 0.5（停 120ms）→ 1，摺痕陰影隨之淡出 */
@keyframes unfold {
  0%   { transform: scaleY(0.25); }
  43%  { transform: scaleY(0.5); }
  57%  { transform: scaleY(0.5); }
  100% { transform: scaleY(1); }
}
.overlay .receipt .creases {
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to bottom, transparent 46%, var(--crease) 49% 51%, transparent 54%),
    linear-gradient(to bottom, transparent 21%, var(--crease-soft) 24% 26%, transparent 29%),
    linear-gradient(to bottom, transparent 71%, var(--crease-soft) 74% 76%, transparent 79%);
  animation: creasefade 600ms ease-out 700ms forwards;
}
@keyframes creasefade { to { opacity: 0; } }
.overlay .receipt .body { animation: fadein 250ms ease-out 900ms backwards; }
.overlay .receipt .meta {
  margin-top: var(--sp-3); color: var(--ink-faint); font-size: 14px; text-align: right;
  animation: fadein 400ms ease-out 1200ms backwards;  /* 時刻是證據：最後浮現 */
}
.overlay .keep { margin-top: var(--sp-6); text-align: center; }
.overlay .keep .btn-ritual { animation: fadein 300ms ease-out 1400ms backwards; }

/* ---------- 拆罐儀式：全拆完 ----------
 * #875：沒有封存這回事——看完就看完了，沒有「封存這個月」按鈕、沒有密語關卡、
 * 沒有分作者計數的 tally（哪些是誰寫的沉澱後在紀錄裡看得到，這裡不用重複算）。
 * finale 只留一句話＋回罐子的連結。 */
.finale { display: none; text-align: center; padding-top: var(--sp-10); }
#view-jar.finished .finale { display: block; }
#view-jar.finished .floor, #view-jar.finished .jar-hold,
#view-jar.finished .progress, #view-jar.finished .hold-hint { display: none; }
.finale p.done { font-size: 23px; font-weight: 500; letter-spacing: 0.15em; margin-bottom: var(--sp-8); }

/* ---------- tab ---------- */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: flex; height: calc(56px + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--bar);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--hairline);
}
.tabbar a {
  flex: 1; display: grid; place-items: center;
  font-size: 15px; letter-spacing: 0.2em; text-indent: 0.2em;
  color: var(--text-dim); text-decoration: none;
}
.tabbar a.on, .tabbar a:hover { color: var(--text); }

/* #857/#875：未讀紅點（note＋reply 統一計）——掛在「罐子」分頁文字右上角，
   位置貼齊文字本身（inline-block wrapper）而非整個 flex 分頁格，
   不管文字寬度怎麼變都準。 */
.tab-label { position: relative; display: inline-block; }
.tab-badge {
  position: absolute; top: -3px; right: -9px;
  width: 7px; height: 7px; border-radius: var(--radius-pill);
  background: var(--notify);
}

/* ---------- reduced motion（DESIGN.md §4.7：停頓與長按是產品規則，JS 內保留） ---------- */
@media (prefers-reduced-motion: reduce) {
  .paper-inner, .line, .slot-light.on, .paper-stage.cut,
  .ka.flash, .mini-jar.pop, .after .btn-ritual { animation: none !important; }
  .line { clip-path: none; }
  .backdrop, .sheet { transition: none; }
  .jar-hold svg.jar, .jar-hold { transition: none; }
  #view-jar.scattered .fchip { animation: none; opacity: 1; transform: rotate(var(--r)); pointer-events: auto; }
  .overlay .receipt, .overlay .receipt .body, .overlay .receipt .meta, .overlay .keep .btn-ritual { animation: none; }
  .overlay .receipt .creases { display: none; }
  .stats-letter { transition: none; }
}
