/* ============================================================
   Meridian 炁 · Design System
   依 docs/reference/meridian_conclusion.html §2 定調
   ============================================================ */
:root{
  /* 主色票 */
  --paper:#f6f1e7; --paper2:#efe8d8; --cream:#fffdf8;
  --ink:#2b2b28; --ink2:#57534a; --dim:#8a8478;
  --line:#e0d8c6; --vermil:#9c3b32; --vermil2:#b8564a;
  --sage:#7f8f7a; --gold:#b8862b;
  /* 七脈輪能量色 */
  --c1:#c0574e; --c2:#cf8a4a; --c3:#c9a83a; --c4:#7f9f6f;
  --c5:#5f93a8; --c6:#6a6ab0; --c7:#9a6bb0;
  /* 字體 */
  --serif:"Noto Serif TC","Songti TC",serif;
  --sans:"Noto Sans TC","PingFang TC","Microsoft JhengHei",system-ui,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{background:#1a1814;font-family:var(--sans);color:var(--ink);line-height:1.6;
  -webkit-font-smoothing:antialiased}
.serif{font-family:var(--serif)}

/* app frame:行動優先,桌機置中 */
/* Fixed viewport height so .screen is the ONLY scroller — with min-height alone,
   long content grew #app and made the BODY scroll, so absolute overlays (quiz,
   sheets) opened off-viewport on iPhone (ES feedback, F-059). */
#app{position:relative;max-width:430px;height:100vh;height:100dvh;margin:0 auto;background:var(--paper);
  box-shadow:0 0 60px #0008;display:flex;flex-direction:column;overflow:hidden}
.screen{flex:1;overflow-y:auto;padding:22px 18px calc(86px + env(safe-area-inset-bottom));
  scrollbar-width:none}
.screen::-webkit-scrollbar{width:0}

/* top header */
.top{margin-bottom:14px}
.top .date{font-size:10.5px;letter-spacing:2px;color:var(--gold);text-transform:uppercase}
.top h2{font-size:22px;font-weight:800;margin-top:2px;font-family:var(--serif)}
.top .en{font-size:11px;color:var(--dim);font-style:italic}

/* cards & bands */
.c{background:var(--cream);border:1px solid var(--line);border-radius:15px;padding:14px 15px;margin-bottom:11px}
.c h4{font-size:15px;display:flex;justify-content:space-between;align-items:center;gap:8px}
.c p{font-size:14px;color:var(--ink2);margin-top:4px;line-height:1.65}
.band{background:var(--cream);border:1px solid var(--line);border-radius:15px;padding:13px 15px;margin-bottom:11px}
.band .el{display:inline-block;font-size:11px;color:#fff;background:var(--sage);border-radius:20px;padding:3px 11px;font-weight:700}
.band h3{font-size:17px;margin:6px 0 3px;font-family:var(--serif)}
.band p{font-size:14px;color:var(--ink2);line-height:1.65}
.hint{font-size:11px;color:var(--ink2);margin:2px 2px 6px;letter-spacing:1px;font-weight:600}

/* tags — 實色底,拉高對比(F-024:年輕受眾要的是有力設計,不是淡雅低對比) */
.tag{font-size:11px;padding:3px 10px;border-radius:20px;font-weight:800;white-space:nowrap}
.tag.free{background:var(--sage);color:#fff}
.tag.pro{background:var(--gold);color:#2b2b28}
.tag.ai{background:var(--vermil);color:#fff}

/* buttons */
.btn{display:block;width:100%;text-align:center;padding:13px;border-radius:13px;border:none;cursor:pointer;
  font-weight:700;font-size:14.5px;background:var(--vermil);color:#fff;margin-top:8px;font-family:inherit;transition:.15s}
.btn:active{transform:scale(.97)}
.btn.ghost{background:transparent;border:1px solid var(--vermil);color:var(--vermil)}
.btn.ink{background:var(--ink)}
.btn.gold{background:var(--gold);color:#2b2b28}
.btn:disabled{opacity:.45;cursor:default}

/* nav */
.navbar{position:absolute;bottom:0;left:0;right:0;height:calc(66px + env(safe-area-inset-bottom));
  padding-bottom:env(safe-area-inset-bottom);background:#fffdf8f2;border-top:1px solid var(--line);
  display:flex;justify-content:space-around;align-items:center;z-index:40;backdrop-filter:blur(6px)}
.nb{flex:1;text-align:center;font-size:9.5px;color:var(--dim);cursor:pointer;padding:6px 0;
  background:none;border:none;font-family:inherit}
.nb .ic{font-size:18px;display:block;line-height:1.15;margin-bottom:2px}
.nb.on{color:var(--vermil);font-weight:700}

/* daily loop */
.loop{display:flex;justify-content:space-between;background:var(--paper2);border-radius:14px;padding:10px 6px;margin-bottom:12px}
.lo{flex:1;text-align:center;font-size:9.5px;color:var(--dim);cursor:pointer;background:none;border:none;font-family:inherit}
.lo .d{width:27px;height:27px;border-radius:50%;margin:0 auto 3px;border:1.5px solid var(--line);
  display:flex;align-items:center;justify-content:center;font-size:12px;background:var(--cream);transition:.25s}
.lo.done .d{background:var(--vermil);border-color:var(--vermil);color:#fff}
.lo.now .d{border-color:var(--vermil);color:var(--vermil);box-shadow:0 0 0 3px #9c3b3222}
.lo.done{color:var(--ink)}

/* chakra bars */
.cbar{display:flex;align-items:center;gap:9px;margin-bottom:8px}
.cbar .nm{width:74px;font-size:11.5px;line-height:1.25}
.cbar .nm span{color:var(--dim);font-size:9.5px}
.cbar .track{flex:1;height:8px;border-radius:6px;background:#0000000d;overflow:hidden}
.cbar .track i{display:block;height:100%;border-radius:6px;transition:width 1s}
.cbar .pct{width:26px;text-align:right;font-size:10.5px;color:var(--ink2)}

/* streak */
.streak{display:flex;gap:4px;margin-top:8px}
.streak i{flex:1;aspect-ratio:1;border-radius:7px;background:var(--paper2);display:flex;align-items:center;
  justify-content:center;font-size:10px;color:var(--dim);font-style:normal;transition:.3s}
.streak i.on{background:var(--vermil);color:#fff}
.streak i.pop{animation:pop .4s}
@keyframes pop{0%{transform:scale(.6)}60%{transform:scale(1.25)}100%{transform:scale(1)}}
.flame{font-size:24px;text-align:center;margin:4px 0}
.journal{width:100%;background:var(--paper2);border:1px dashed var(--line);border-radius:12px;padding:11px;
  font-size:13px;color:var(--ink);min-height:58px;font-family:inherit;resize:none}
.journal::placeholder{color:var(--dim)}
.journal:focus{outline:1.5px solid var(--sage)}

/* ensō — F-029:放大圓相與炁字,配 Noto Serif TC 網頁字型 */
.enso{width:170px;height:170px;margin:2px auto 8px;position:relative}
/* T11.3 breathing sync, Attune step only: 12s cycle = 4s in / 2s hold / 6s out */
.enso.breathing svg{animation:breathe 12s ease-in-out infinite;transform-origin:center}
/* F-089: amplitude bumped (was 1→1.14, too subtle to notice on a phone) so the
   grow/shrink actually reads as breathing; opacity swing widened to match. */
@keyframes breathe{
  0%{transform:scale(.9);opacity:.72}
  33.3%{transform:scale(1.24);opacity:1}   /* inhale 4s */
  50%{transform:scale(1.24);opacity:1}     /* hold 2s */
  100%{transform:scale(.9);opacity:.72}    /* exhale 6s */
}

/* energy card */
.ecard{border-radius:20px;padding:22px 20px;color:#fff;position:relative;overflow:hidden;
  box-shadow:0 14px 34px #0004,inset 0 -96px 76px -46px #00000066;min-height:348px}
.ecard .brand{font-size:11px;letter-spacing:3px;opacity:.8}
.ecard .big{font-family:var(--serif);font-size:30px;margin:14px 0 3px;font-weight:800}
.ecard .sub{font-size:13px;letter-spacing:.3px;opacity:.9}
.ecard .glyph{position:absolute;right:-14px;top:58px;font-size:150px;opacity:.13;font-family:var(--serif)}
.ecard .quote{font-size:15px;line-height:1.6;margin-top:20px;font-family:var(--serif);white-space:pre-line}
.ecard .foot{position:absolute;bottom:16px;left:18px;right:18px;display:flex;justify-content:space-between;font-size:10.5px;opacity:.8}
/* F-043 rarity visuals — presentation only */
.ecard.goldframe{border:3px solid transparent;
  background-clip:padding-box;box-shadow:0 14px 34px #0004,inset 0 -96px 76px -46px #00000066,0 0 0 3px var(--gold),0 0 18px #b8862b66}
.ecard.shine::after{content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(115deg,transparent 30%,#ffffff2e 45%,#ffffff55 50%,#ffffff2e 55%,transparent 70%);
  background-size:250% 100%;animation:sheen 3.2s ease-in-out infinite}
@keyframes sheen{0%{background-position:120% 0}55%{background-position:-60% 0}100%{background-position:-60% 0}}
/* 顯念卡 cycle collection (F-046/F-050) */
.cyclegrid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:10px}
.cyclecard{border-radius:12px;aspect-ratio:3/4;color:#fff;position:relative;padding:8px;overflow:hidden;
  box-shadow:0 6px 16px #0003}
.cyclecard svg.face{position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none}

/* Daily-card first-reveal ritual (ES feedback, F-061/F-065) — escalates by rarity:
   t1 normal: entrance + one light sweep
   t2 shine:  entrance + double sweep
   t3 gold:   3D flip-in + gold glow pulse + sweep
   t4 gold+shine: flip + glow + double sweep + sparkles */
.ecard.reveal{animation:cardin .9s cubic-bezier(.2,.85,.3,1) both}
@keyframes cardin{from{transform:scale(.9) translateY(14px);opacity:0;filter:brightness(1.6)}
  60%{filter:brightness(1.15)}to{transform:none;opacity:1;filter:none}}
.ecard.reveal-t3,.ecard.reveal-t4{animation:cardflip 1.15s cubic-bezier(.25,.9,.3,1) both,
  goldglow 2.4s ease-out .3s}
@keyframes cardflip{from{transform:perspective(900px) rotateY(100deg) scale(.9);opacity:0;filter:brightness(1.9)}
  55%{filter:brightness(1.25)}to{transform:none;opacity:1;filter:none}}
@keyframes goldglow{0%{box-shadow:0 0 0 #d9b36a00}35%{box-shadow:0 0 42px #d9b36aa8}100%{box-shadow:0 0 0 #d9b36a00}}
.revealflash{position:absolute;inset:0;border-radius:inherit;pointer-events:none;overflow:hidden;
  background:linear-gradient(115deg,transparent 30%,#ffffff59 48%,#f7e7b866 52%,transparent 70%);
  background-size:260% 100%;background-position:130% 0;
  animation:cardsweep 1.4s ease-out .45s forwards}
.ecard.reveal-t2 .revealflash,.ecard.reveal-t4 .revealflash,
.ecard.reveal-t5 .revealflash{animation:cardsweep 1.1s ease-out .45s 2 forwards}

/* t5 · 極光日 — the rarest daily state (~1 in 128 days, see screens/card.js).
   Deliberately NOT foil and NOT diamond: those two materials belong to the
   earned milestone ladder, and lending them to a lucky day would cheapen the
   100/180/365 cards. Aurora gets its own language — a slow bloom in the day's
   own chakra colour, which also makes it look different every time it lands. */
.ecard.aurora::before{content:'';position:absolute;inset:-32%;pointer-events:none;
  border-radius:50%;background:radial-gradient(circle,var(--aura) 0%,transparent 62%);
  mix-blend-mode:screen;opacity:.42;animation:auraDrift 7s ease-in-out infinite}
@keyframes auraDrift{0%,100%{transform:translate(-11%,-7%) scale(1);opacity:.38}
  50%{transform:translate(11%,7%) scale(1.22);opacity:.6}}
.ecard.reveal-t5{animation:cardflip 1.15s cubic-bezier(.25,.9,.3,1) both,
  auraGlow 3.2s ease-out .3s}
@keyframes auraGlow{0%{box-shadow:0 0 0 0 #0000}
  32%{box-shadow:0 0 64px 8px var(--aura)}100%{box-shadow:0 0 0 0 #0000}}
@media (prefers-reduced-motion:reduce){
  .ecard.aurora::before{animation:none;opacity:.46}
}
@keyframes cardsweep{from{background-position:130% 0}to{background-position:-130% 0}}
.sparkles{position:absolute;inset:6px;pointer-events:none} /* .ecard clips overflow */
.sparkles i{position:absolute;font-style:normal;color:#f2dc9e;font-size:13px;opacity:0;
  animation:spark 1.5s ease-out both}
@keyframes spark{0%{opacity:0;transform:translateY(8px) scale(.4) rotate(0)}
  35%{opacity:1}100%{opacity:0;transform:translateY(-26px) scale(1.15) rotate(50deg)}}
.sparkles i:nth-child(1){left:8%;top:16%;animation-delay:.55s}
.sparkles i:nth-child(2){left:88%;top:10%;animation-delay:.75s;font-size:16px}
.sparkles i:nth-child(3){left:16%;top:74%;animation-delay:.95s;font-size:11px}
.sparkles i:nth-child(4){left:80%;top:64%;animation-delay:1.1s}
.sparkles i:nth-child(5){left:48%;top:4%;animation-delay:1.3s;font-size:15px}
.sparkles i:nth-child(6){left:60%;top:88%;animation-delay:1.45s;font-size:11px}
.sparkles i:nth-child(7){left:2%;top:44%;animation-delay:1.6s}
.sparkles i:nth-child(8){left:94%;top:40%;animation-delay:1.75s;font-size:12px}
/* 9–10 exist only for the 365-day 周天卡, the single richest burst in the app
   (F-095 ladder). Without these two the extra glyphs would pile up unpositioned
   at the container origin instead of joining the burst. */
.sparkles i:nth-child(9){left:34%;top:30%;animation-delay:1.9s;font-size:14px}
.sparkles i:nth-child(10){left:70%;top:78%;animation-delay:2.05s;font-size:11px}

/* Collection-card reveal tiers (F-065/F-067): distinct from the daily-card
   .reveal-t1..t4 family above — these apply to .cyclecard (顯念卡/special cards).
   t3 = 49-day cycle card: flip + glow, no sparkles (frequent-ish, moderate rarity).
   t5 = 100/180/365 special card: slower flip, wider halo pulse, tinted per
   milestone via --revealtint, plus sparkles — the most ornate tier in the app,
   reserved for the rarest unlocks. */
.cyclecard.reveal.reveal-t3{animation:cflip .95s cubic-bezier(.25,.9,.3,1) both,cglow 2s ease-out .25s}
.cyclecard.reveal.reveal-t5{--revealtint:#d9b458;animation:cflipslow 1.5s cubic-bezier(.22,.9,.3,1) both,chalo 2.8s ease-out .3s}
@keyframes cflip{from{transform:perspective(800px) rotateY(90deg) scale(.88);opacity:0}to{transform:none;opacity:1}}
@keyframes cflipslow{from{transform:perspective(900px) rotateY(110deg) scale(.82);opacity:0;filter:brightness(1.8)}
  50%{filter:brightness(1.3)}to{transform:none;opacity:1;filter:none}}
@keyframes cglow{0%{box-shadow:0 0 0 #d9b36a00}35%{box-shadow:0 0 30px #d9b36a90}100%{box-shadow:0 0 0 #d9b36a00}}
@keyframes chalo{0%{box-shadow:0 0 0 transparent}30%{box-shadow:0 0 50px 6px color-mix(in srgb,var(--revealtint,#d9b458) 70%,transparent)}100%{box-shadow:0 0 0 transparent}}
/* F-073 VFX prototypes (Blair review, dev-preview only — not wired into the
   production unlock flow pending sign-off): alternates to the t5 slow-flip
   tier. t6 = fast 2D spin into freeze; t7 = "revolving door" style — two full
   Y-axis passes, fast, landing flat. */
.cyclecard.reveal.reveal-t6{--revealtint:#d9b458;animation:cspin2d .85s cubic-bezier(.3,.9,.25,1) both,chalo 2.4s ease-out .2s}
@keyframes cspin2d{from{transform:rotate(360deg) scale(.7);opacity:0;filter:brightness(1.8)}
  60%{filter:brightness(1.3)}to{transform:rotate(0) scale(1);opacity:1;filter:none}}
.cyclecard.reveal.reveal-t7{--revealtint:#d9b458;animation:crevolve .9s cubic-bezier(.35,.9,.2,1) both,chalo 2.6s ease-out .25s}
@keyframes crevolve{from{transform:perspective(700px) rotateY(720deg) scale(.85);opacity:0;filter:brightness(1.9)}
  70%{filter:brightness(1.3)}to{transform:perspective(700px) rotateY(0) scale(1);opacity:1;filter:none}}
/* F-093 VFX prototypes round 2 (dev-preview only, Tiger's request — 5 new
   tiers on top of t5/t6/t7, none wired into the production unlock flow):
   t8  A1 · 原型A(2D spin)轉 3 圈
   t9  B1 · 原型B(旋轉門 3D)轉 5 圈
   t10 A2 · 原型A 轉 5 圈,同時由 10% 放大到 100%
   t11 B2 · 原型B 從右上角、10%→100% 沿弧線飛入定位,到 100% 再轉 5 圈,最後減緩
   t12 V1 · 現行慢速翻牌+光暈,但卡片由 10% 放大到 100% */
.cyclecard.reveal.reveal-t8{--revealtint:#d9b458;animation:cspin2d3 1.05s cubic-bezier(.3,.9,.25,1) both,chalo 2.4s ease-out .2s}
@keyframes cspin2d3{from{transform:rotate(1080deg) scale(.7);opacity:0;filter:brightness(1.8)}
  60%{filter:brightness(1.3)}to{transform:rotate(0) scale(1);opacity:1;filter:none}}
.cyclecard.reveal.reveal-t9{--revealtint:#d9b458;animation:crevolve5 1.2s cubic-bezier(.35,.9,.2,1) both,chalo 2.6s ease-out .25s}
@keyframes crevolve5{from{transform:perspective(700px) rotateY(1800deg) scale(.85);opacity:0;filter:brightness(1.9)}
  70%{filter:brightness(1.3)}to{transform:perspective(700px) rotateY(0) scale(1);opacity:1;filter:none}}
.cyclecard.reveal.reveal-t10{--revealtint:#d9b458;animation:cspin2d5grow 1.15s cubic-bezier(.3,.9,.25,1) both,chalo 2.5s ease-out .2s}
@keyframes cspin2d5grow{from{transform:rotate(1800deg) scale(.1);opacity:0;filter:brightness(1.8)}
  55%{opacity:1}60%{filter:brightness(1.3)}to{transform:rotate(0) scale(1);opacity:1;filter:none}}
.cyclecard.reveal.reveal-t11{--revealtint:#d9b458;animation:cflyspin 1.8s cubic-bezier(.3,.85,.25,1) both,chalo 2.8s ease-out 1s}
/* B14.1: start 10%, arc in to 100%, then 5 turns whose last 1/3-turn is spread
   over the final 14% of the timeline so the spin visibly decelerates (最後減緩). */
@keyframes cflyspin{0%{transform:perspective(800px) translate(140%,-140%) scale(.1) rotateY(0);opacity:0}
  18%{opacity:1}
  35%{transform:perspective(800px) translate(48%,-14%) scale(.5) rotateY(0)}
  52%{transform:perspective(800px) translate(0,0) scale(1) rotateY(0)}
  86%{transform:perspective(800px) translate(0,0) scale(1) rotateY(1680deg)}
  100%{transform:perspective(800px) translate(0,0) scale(1) rotateY(1800deg)}}
.cyclecard.reveal.reveal-t12{--revealtint:#d9b458;animation:cflipslowgrow 1.5s cubic-bezier(.22,.9,.3,1) both,chalo 2.8s ease-out .3s}
@keyframes cflipslowgrow{from{transform:perspective(900px) rotateY(110deg) scale(.1);opacity:0;filter:brightness(1.8)}
  50%{filter:brightness(1.3)}to{transform:none;opacity:1;filter:none}}

/* F-074: metallic/foil/diamond particle progression on top of the t3/t5 flip
   tiers above (ES bug — special cards had zero particle markup). Escalates:
   49-day 顯念卡 = one silver/metallic local highlight patch, tinted to sit on
   its OWN gradient (no fixed color) via a white radial + overlay blend, so it
   reads as "polish" rather than importing a foreign hue; 100/180-day = a
   brighter multi-band foil sweep (wider than the daily .shine sheen) + a
   small 4-particle sparkle; 365-day = a rotating prismatic conic sweep +
   the full 8-particle glitter burst (cool-toned, distinct from the daily
   card's warm gold sparkles so the diamond tier reads as its own material). */
.cyclecard .metalspot{position:absolute;top:8%;right:7%;width:34%;height:34%;border-radius:50%;pointer-events:none;
  background:radial-gradient(circle,#ffffffb0 0%,#ffffff30 42%,transparent 74%);
  mix-blend-mode:overlay;opacity:0;animation:metalspot 2.2s ease-out .5s both}
@keyframes metalspot{0%{opacity:0;transform:scale(.4)}40%{opacity:.95}100%{opacity:.55;transform:scale(1)}}
.cyclecard.foil::after{content:'';position:absolute;inset:0;pointer-events:none;border-radius:inherit;
  background:linear-gradient(100deg,transparent 18%,#fff3cf59 32%,#ffffffc0 45%,#f7e7b873 53%,transparent 66%,#fff3cf45 80%,transparent 96%);
  background-size:260% 100%;background-position:150% 0;
  animation:foilsweep 1.8s ease-out .35s 2 forwards}
@keyframes foilsweep{from{background-position:150% 0}to{background-position:-150% 0}}
.cyclecard.diamond::after{content:'';position:absolute;inset:0;pointer-events:none;border-radius:inherit;
  background:conic-gradient(from 0deg,#ffb3d9,#b3e0ff,#fff6b3,#c8ffcf,#e0b3ff,#ffb3d9);
  opacity:0;mix-blend-mode:overlay;animation:diamondspin 2.6s ease-out .3s both}
@keyframes diamondspin{0%{opacity:0;transform:rotate(0)}30%{opacity:.7}100%{opacity:.32;transform:rotate(140deg)}}
.sparkles.gem i:nth-child(odd){color:#eaf6ff}
.sparkles.gem i:nth-child(even){color:#ffe6f5}

.cyclecard .n{position:relative;font-size:10px;letter-spacing:2px;opacity:.85}
.cyclecard .glyph{position:absolute;right:2px;bottom:14px;font-size:52px;opacity:.16;font-family:var(--serif)}
.cyclecard .no{position:absolute;left:8px;bottom:7px;font-size:9.5px;opacity:.9}
.cyclecard.big{width:150px;aspect-ratio:3/4}
.cyclecard.big .glyph{font-size:72px}

/* ---- English card typography (F-095, Blair · "Caption") ----------------
   The base scale above is tuned for Chinese: 2px tracking on a 3-glyph
   title (顯念卡) reads as elegance. The same rule on 14-25 English
   characters injects ~20% of the em per character — that, not font-size,
   is why English card faces read oversized and wrapped 3 deep into the
   face artwork. English gets its own scale, gated on `lang`, which
   main.js sets on <html> at boot — so this costs no JS and cannot leak
   into the Chinese pack.

   Direction: text recedes, the face art leads. Uppercase micro-label,
   tracking cut 2px→.5px, clamped to 2 lines. Reads app-native, which is
   the right register for the US 18-34 audience (F-028); the literary
   register lives in 命之書, one layer up.

   NOTE: the shared PNG is drawn on <canvas> (card.js buildCanvas) and
   does NOT read this CSS — the same treatment is applied there by hand.
   Change one, change the other, or the screen and the shared image drift. */
html[lang="en"] .cyclecard .n{
  font-size:8.5px;letter-spacing:.5px;text-transform:uppercase;font-weight:600;
  opacity:.72;line-height:1.3;padding-right:3px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
html[lang="en"] .cyclecard.big .n{font-size:9.5px}
html[lang="en"] .cyclecard .no{font-size:8.5px;letter-spacing:.2px;opacity:.85}
html[lang="en"] .ecard .sub{
  font-size:11.5px;letter-spacing:1.4px;text-transform:uppercase;opacity:.8}

/* sheet / modal */
.sheet{position:absolute;inset:0;background:#1a1814cc;z-index:70;display:flex;align-items:flex-end}
.sheetbox{background:var(--cream);width:100%;border-radius:22px 22px 0 0;padding:16px 16px calc(22px + env(safe-area-inset-bottom));animation:up .3s}
@keyframes up{from{transform:translateY(100%)}to{transform:none}}
.sheetbox h4{font-size:14.5px;text-align:center;margin-bottom:12px}

/* toast */
.toast{position:absolute;bottom:calc(80px + env(safe-area-inset-bottom));left:50%;
  transform:translateX(-50%) translateY(20px);background:var(--ink);color:#fff;
  padding:9px 16px;border-radius:24px;font-size:12.5px;opacity:0;transition:.3s;z-index:80;
  white-space:nowrap;pointer-events:none;max-width:92%;overflow:hidden;text-overflow:ellipsis}
.toast.on{opacity:1;transform:translateX(-50%) translateY(0)}

/* onboarding */
.ob{position:absolute;inset:0;background:var(--paper);z-index:60;overflow-y:auto;
  padding:38px 22px 30px;display:flex;flex-direction:column}
.ob .k{font-size:11px;letter-spacing:5px;color:var(--gold);text-align:center}
.ob h1{font-family:var(--serif);font-size:26px;text-align:center;margin:8px 0 2px}
.ob .sub{font-size:12.5px;color:var(--dim);text-align:center;margin-bottom:18px}
/* F-103 · 輕身份層:真八字日主 + 五行強弱 */
.identity{text-align:center;margin:2px auto 14px;padding:14px 16px;max-width:300px;
  border:1px solid var(--line);border-radius:14px;background:var(--cream)}
.identity .k{margin-bottom:6px}
.identity .dm-badge{font-family:var(--serif);font-size:30px;color:var(--gold);letter-spacing:2px;line-height:1.15}
.identity .dm-en{font-size:11px;letter-spacing:3px;color:var(--dim);text-transform:uppercase;margin-top:2px}
.identity .dm-line{font-size:13px;color:var(--ink2);line-height:1.6;margin-top:9px}
.identity .dm-sw{font-size:12px;color:var(--dim);margin-top:6px;letter-spacing:.3px}
.identity .dm-bridge{font-size:12.5px;color:var(--gold);margin-top:8px;line-height:1.55;font-style:italic}
.ob label{font-size:12px;color:var(--ink2);display:block;margin:12px 0 5px;letter-spacing:1px}
.ob input,.ob select{width:100%;padding:12px;border:1px solid var(--line);border-radius:12px;
  background:var(--cream);font-size:14px;font-family:inherit;color:var(--ink)}
.ob input:focus,.ob select:focus{outline:1.5px solid var(--sage)}
.qopt{display:block;width:100%;text-align:left;padding:12px 14px;margin-bottom:8px;border:1px solid var(--line);
  border-radius:12px;background:var(--cream);font-size:14px;font-family:inherit;cursor:pointer;color:var(--ink);transition:.15s}
.qopt:active{transform:scale(.98)}
.qopt.sel{border-color:var(--vermil);box-shadow:0 0 0 2px #9c3b3222}
/* privacy badge — F-025:提高視覺權重,不再是淺灰小字免責聲明 */
.privacy{display:flex;align-items:center;gap:8px;background:var(--paper2);border:1px solid var(--sage);
  border-radius:12px;padding:10px 12px;margin-top:16px;font-size:12.5px;color:var(--ink);line-height:1.55;text-align:left}
.privacy .ic{flex:none;color:var(--sage)}

/* book */
.book{position:relative;height:310px;border-radius:14px;overflow:hidden;border:1px solid var(--line);background:var(--cream)}
.page{position:absolute;inset:0;padding:18px;display:none;flex-direction:column}
.page.on{display:flex}
.page .pk{font-size:10px;letter-spacing:2px;color:var(--gold)}
.page h3{font-family:var(--serif);font-size:17px;margin:4px 0 8px}
/* Unlocked chapters scroll so long content (e.g. myth chapter) is fully readable (F-057) */
.page .txt{font-size:12.5px;color:var(--ink2);line-height:1.75;overflow-y:auto;flex:1;min-height:0;
  padding-right:4px;-webkit-overflow-scrolling:touch;scrollbar-width:thin}
.page.lock .txt{filter:blur(6px);user-select:none;overflow:hidden}
.page .more{font-size:10px;color:var(--dim);text-align:center;padding-top:4px;flex:none}
.locko{position:absolute;inset:0;background:linear-gradient(180deg,#fffdf800,#fffdf8f2 70%);display:flex;
  flex-direction:column;align-items:center;justify-content:flex-end;padding-bottom:20px;text-align:center}
.locko .lk{font-size:24px}
.locko p{font-size:12px;color:var(--ink2);margin-top:4px}
.toc{font-size:12.5px;color:var(--ink2)}
.toc div{display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px dotted var(--line)}
/* F-092: the 完整目錄 page sits in the fixed-height, overflow-hidden .book box.
   Content pages use .txt (which scrolls); the TOC uses .toc, which had no
   scroll/flex, so a full 8-chapter list (esp. with unlocked long titles or
   Chinese wrapping) was clipped at the bottom with no way to reach it. Scope
   the scroll to the TOC-inside-a-book-page only — .toc is reused in sheets /
   settings / annual where it must stay auto-height. */
.page .toc{overflow-y:auto;flex:1;min-height:0;-webkit-overflow-scrolling:touch;scrollbar-width:thin}
.pager{display:flex;justify-content:space-between;align-items:center;margin-top:8px}
.pager button{background:var(--paper2);border:1px solid var(--line);border-radius:9px;padding:6px 12px;
  font-size:12px;cursor:pointer;font-family:inherit;color:var(--ink)}
.dots{display:flex;gap:5px}
.dots i{width:6px;height:6px;border-radius:50%;background:var(--line)}
.dots i.on{background:var(--vermil)}
.pricebox{background:var(--ink);color:var(--cream);border-radius:16px;padding:15px;margin-top:10px}
.pricebox .p{font-size:20px;font-weight:800}
.pricebox .p s{font-size:11px;color:#b8b0a0;font-weight:400}

/* full-document print view (F-057): print the whole generated profile, never the screen */
#printdoc{display:none}
@media print{
  body{background:#fff}
  #app{display:none!important}
  #printdoc{display:block;color:#1c1a17;font-family:var(--sans);line-height:1.8;padding:0 6mm}
  #printdoc .pd-cover{text-align:center;padding:90px 0 30px;page-break-after:always}
  #printdoc .pd-cover h1{font-family:var(--serif);font-size:32px;letter-spacing:3px;margin-bottom:6px}
  #printdoc .pd-cover .sub{color:#57534a;margin-top:6px;font-size:13px}
  #printdoc .pd-cover .viz{width:230px;height:230px;margin:26px auto 6px}
  #printdoc .pd-ch{page-break-inside:avoid;margin:0 0 26px;padding-bottom:16px;border-bottom:1px solid #d9d2c4}
  #printdoc .pd-k{font-size:10px;letter-spacing:2.5px;color:#b8862b;text-transform:uppercase}
  #printdoc .pd-ch h2{font-family:var(--serif);font-size:20px;margin:4px 0 8px}
  #printdoc .pd-ch p{font-size:13px;white-space:pre-line;margin:0}
  #printdoc .pd-foot{font-size:10px;color:#8a8478;text-align:center;margin-top:26px}
}

/* misc */
.center{text-align:center}
.spacer{height:10px}
.small{font-size:10.5px;color:var(--dim)}
.link{background:none;border:none;color:var(--sage);font-size:11px;cursor:pointer;font-family:inherit;text-decoration:underline}
/* F-084 info layer: the 「圈中間問號」 affordance. Sits inline next to whatever
   it explains; 30px box keeps the tap target usable without visual weight. */
.helpbtn{background:none;border:0;padding:0;margin:0 0 0 5px;width:30px;height:30px;line-height:0;
  color:var(--dim);cursor:pointer;flex:none;vertical-align:middle}
.helpbtn:active{color:var(--vermil)}

/* 開場歡迎頁 (內測用, welcome.js) — static build-identity card, not a splash
   animation: the three motion concepts were rejected 2026-08-01. Sits above
   every sheet so the version is readable even if onboarding opens underneath. */
.welcome{position:fixed;inset:0;z-index:200;background:#141210;color:#f6f1e7;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  transition:opacity .32s ease;cursor:pointer;
  padding-bottom:env(safe-area-inset-bottom)}
.welcome.out{opacity:0;pointer-events:none}
.welcome .wbrand{font-size:12px;letter-spacing:.42em;text-indent:.42em;opacity:.7}
.welcome .wglyph{font-family:var(--serif);font-size:76px;line-height:1.2;margin:4px 0 16px}
.welcome .wver{font-size:15.5px;font-weight:700;letter-spacing:.03em;
  font-variant-numeric:tabular-nums}
.welcome .wdep{font-size:12px;opacity:.6;margin-top:3px;font-variant-numeric:tabular-nums}
.welcome .wtag{margin-top:18px;font-size:10.5px;letter-spacing:.2em;text-indent:.2em;
  border:1px solid #f6f1e740;border-radius:999px;padding:4px 13px;opacity:.75}
@media (prefers-reduced-motion:reduce){.welcome{transition:none}}

/* 護盾補上的日子 (manifest.js) — the streak survived, but the user did not
   practise that day, so this must read as clearly different from a real
   check-in rather than as a slightly-off version of one. Outline, not fill. */
.streak i.shielded{background:transparent;color:var(--vermil);
  box-shadow:inset 0 0 0 1.5px var(--vermil);opacity:.8}

/* F-095 · 打卡即時回饋 — reuses the existing .pop keyframes (was .streak i
   only) on the flame number and the rare-day note so check-in has a visible
   beat beyond the toast. justCheckedIn in manifest.js gates this to fire
   once, on the render that immediately follows the click. */
.flame span.pop{animation:pop .4s}
.rarenote{color:var(--gold);font-weight:700}
.rarenote.pop{animation:pop .4s .1s both}
