
/* Blue-black ground. Hue only: each value is the exact luminance of the warm
   near-black it replaces, so every contrast ratio and the weight of everything
   on top of it are unchanged. */
:root{
  --ground:#10131B; --raise:#171C28; --raise-2:#1D2332; --line:#252C3E;
  --paper:#F3F0EA; --dim:#8E8679; --dim-2:#847D6E; --dim-hi:#A39B8D;
  --seal:#D9503C; --seal-bg:#C4432F; --jade:#4FB783; --miss:#E2604C;
  --t1:#E0A93B; --t2:#5CC08D; --t3:#B98BDB; --t4:#5FA3E8; --t0:#A39B8D;
  --disp:"Manrope","Helvetica Neue",Arial,sans-serif;
  --ui:"Inter","Helvetica Neue",Arial,sans-serif;
  --han:"Noto Sans SC","PingFang SC","Hiragino Sans GB",sans-serif;
  --snap:cubic-bezier(.2,.85,.3,1);
}
*{box-sizing:border-box}
html,body{margin:0;padding:0;height:100%}
body{background:var(--ground);color:var(--paper);font-family:var(--ui);font-size:1rem;
  -webkit-font-smoothing:antialiased;-webkit-tap-highlight-color:transparent;overflow:hidden}
button{font:inherit;color:inherit;border:none;background:none;cursor:pointer}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition-duration:.01ms!important}}

.app{height:100%;height:100dvh;display:flex;flex-direction:column;max-width:520px;margin:0 auto;
  padding:0 16px}

/* ---------- top: progress + streak ---------- */
.top{flex:none;padding:18px 2px 8px;display:flex;align-items:center;gap:14px}
.segs{flex:1 1 auto;display:flex;gap:2px}
.segs.many{gap:0;border-radius:2px;overflow:hidden} .segs.many .seg{border-radius:0}   /* a long queue reads as one bar */
.seg{flex:1 1 0;height:4px;border-radius:2px;background:var(--paper);transition:background .34s var(--snap)}
.seg.hit{background:var(--jade)} .seg.miss{background:var(--miss)}
.streak{flex:none;display:flex;align-items:center;gap:6px;font-family:var(--disp);font-weight:800;
  font-size:0.9375rem;color:var(--dim);transition:color .2s}
.streak.live{color:var(--seal)}
.streak i{font-style:normal;font-size:0.8125rem}
.streak-l{font-size:0.6562rem;letter-spacing:.14em;font-weight:700;text-transform:uppercase;color:var(--dim-2);margin-left:2px}

/* ---------- middle: the character ---------- */
.stage{flex:1 1 auto;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:16px;min-height:0;text-align:center;padding:8px 0}
.hanzi{font-family:var(--han);font-weight:500;font-size:clamp(3.625rem,17vw,5.75rem);line-height:1.06;
  letter-spacing:.04em;color:var(--paper)}
.hanzi.in{animation:cardin .26s var(--snap)}
@keyframes cardin{from{opacity:0;transform:translateY(10px) scale(.97)}to{opacity:1;transform:none}}
.reveal{min-height:74px;display:flex;flex-direction:column;gap:7px;align-items:center;justify-content:center}
.py{font-size:1.4375rem;letter-spacing:.01em;opacity:0;transform:translateY(5px);
  transition:opacity .24s var(--snap),transform .24s var(--snap)}
.py.on{opacity:1;transform:none}
.note{font-size:0.875rem;color:var(--dim);opacity:0;transition:opacity .24s .06s}
.note.on{opacity:1}
.note b{color:var(--jade);font-weight:600}
.note.bad b{color:var(--miss)}
.lvl{font-family:var(--disp);font-size:0.6562rem;letter-spacing:.16em;color:var(--dim-2);font-weight:700}

/* ---------- bottom: the answers ---------- */
.opts{flex:none;display:flex;flex-direction:column;gap:8px;
  padding-bottom:calc(16px + env(safe-area-inset-bottom))}
.opt{width:100%;min-height:56px;padding:15px 18px;border-radius:12px;background:var(--raise);
  border:1px solid var(--line);text-align:left;font-size:1.0312rem;font-weight:500;color:var(--paper);
  display:flex;align-items:center;gap:12px;
  transition:background .18s var(--snap),border-color .18s var(--snap),transform .12s var(--snap)}
.opt:active{transform:scale(.985)}
@media (hover:hover){ .opt:not(.done):hover{background:var(--raise-2);border-color:#39435C} }
.opt .k{flex:none;width:22px;font-family:var(--disp);font-size:0.75rem;font-weight:800;color:var(--dim)}
.opt.right{background:rgba(79,183,131,.16);border-color:var(--jade);color:#B6E8CD}
.opt.right .k{color:var(--jade)}
.opt.wrong{background:rgba(226,96,76,.14);border-color:var(--miss);color:#F2BDB3}
.opt.wrong .k{color:var(--miss)}
.opt.fade{opacity:.5}
.opt.pulse{animation:pulse .3s var(--snap)}
@keyframes pulse{0%{transform:scale(1)}40%{transform:scale(1.025)}100%{transform:scale(1)}}
.opt.shake{animation:shake .32s}
@keyframes shake{0%,100%{transform:translateX(0)}20%{transform:translateX(-6px)}
  40%{transform:translateX(5px)}60%{transform:translateX(-3px)}80%{transform:translateX(2px)}}

.next{width:100%;min-height:56px;border-radius:12px;background:var(--seal-bg);color:#fff;
  font-family:var(--disp);font-weight:800;font-size:1rem;display:flex;align-items:center;
  justify-content:center;animation:cardin .2s var(--snap)}
.next:active{transform:scale(.99)}

/* ---------- the end ---------- */
.done-wrap{flex:1 1 auto;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:4px;text-align:center;animation:cardin .3s var(--snap)}
.done-n{font-family:var(--disp);font-size:4.625rem;font-weight:800;letter-spacing:-.045em;line-height:1;
  color:var(--jade);font-variant-numeric:tabular-nums}
.done-of{font-size:0.9375rem;color:var(--dim)}
.done-l{font-family:var(--disp);font-size:0.6875rem;letter-spacing:.16em;color:var(--dim-2);font-weight:700;
  margin-bottom:18px}
.bars{width:100%;margin-top:26px;display:flex;flex-direction:column;gap:9px}
.bar{display:flex;align-items:center;gap:11px;font-size:0.8438rem;color:var(--dim)}
.bar-t{flex:none;width:74px;text-align:right;font-family:var(--disp);font-weight:700;font-size:0.75rem;
  letter-spacing:.06em;color:var(--dim-2)}
.bar-track{flex:1 1 auto;height:8px;border-radius:4px;background:#303A52;overflow:hidden}
.bar-fill{display:block;height:100%;border-radius:4px;width:0;transition:width .7s var(--snap)}
.bar-n{flex:none;width:26px;font-family:var(--disp);font-weight:800;font-size:0.875rem;color:var(--paper);
  font-variant-numeric:tabular-nums}
.longest{margin-top:26px;font-size:0.875rem;color:var(--dim)}
.longest b{color:var(--seal);font-family:var(--disp);font-weight:800;font-size:1.0625rem}
.again{margin-top:auto;margin-bottom:calc(16px + env(safe-area-inset-bottom))}
.hint{flex:none;text-align:center;font-size:0.7188rem;color:var(--dim-2);padding-bottom:8px;
  font-family:var(--disp);letter-spacing:.05em}
@media (max-width:380px){ .hint{display:none} }
@media (hover:none) and (pointer:coarse){ .hint{display:none} }   /* keyboard advice means nothing to a finger */

/* ---------- laptop: the keyboard is the input, and the space carries the trail ---------- */
.trail{display:none}
.main{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;overflow-y:auto;overflow-x:hidden;
  scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.main>*{flex-shrink:0}
.main>.stage{min-height:auto}          /* never shrinks under its content; the column scrolls instead */
@media (min-width:760px){
  .app{max-width:1120px;display:grid;grid-template-columns:270px 1fr;gap:36px;padding:0 26px}
  .segs{display:none}                      /* the trail says this better */
  .trail{display:flex;flex-direction:column;min-height:0;padding:24px 0 20px}
  .trail-h{font-family:var(--disp);font-size:0.6562rem;letter-spacing:.16em;color:var(--dim-2);
    font-weight:700;margin-bottom:13px;display:flex;justify-content:space-between}
  .trail-h span{color:var(--dim)}
  .trail-list{flex:1 1 auto;overflow-y:auto;display:flex;flex-direction:column;gap:3px;
    padding-right:8px;scrollbar-width:thin;scrollbar-color:var(--line) transparent}
  .ti{display:flex;align-items:baseline;gap:10px;padding:7px 11px;border-radius:7px;
    border-left:3px solid transparent;background:var(--raise);min-height:34px;
    animation:tin .22s var(--snap)}
  @keyframes tin{from{opacity:0;transform:translateX(-6px)}to{opacity:1;transform:none}}
  .ti-h{font-family:var(--han);font-size:1rem;flex:none;color:var(--paper)}
  .ti-e{font-size:0.75rem;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .ti.hit{border-left-color:var(--jade)}
  .ti.miss{border-left-color:var(--miss)}
  .ti.miss .ti-h{color:#F2BDB3}
  .ti.now{border-left-color:var(--seal);background:var(--raise-2)}
  .ti.wait{background:transparent;border-left:3px solid var(--line);min-height:11px;padding:0;
    animation:none;border-radius:0 3px 3px 0}
  .top{padding-top:24px;justify-content:flex-end}
  /* one decision: from here up, the way out is the top-right corner on every
     screen, and what the screen is stays at the left edge of its column */
  .top .quit{order:9}
  .app.solo .top{justify-content:space-between;gap:18px}
  .g-title,.rd-pos{flex:0 0 auto;text-align:left}
  .rd-pos{margin-right:auto}
  /* auto margins above and below centre the character + answers as one block,
     so the pair sits at eye level instead of bunching under the top bar */
  .stage{flex:0 0 auto;gap:14px;padding-top:0;margin-top:auto;justify-content:flex-start}
  .hint{margin-bottom:auto}
  .hanzi{font-size:clamp(4.625rem,7.2vw,6.75rem)}
  .reveal{min-height:82px}
  /* four answers in one glance, and the eye never travels to the bottom of the screen */
  .opts{display:grid;grid-template-columns:1fr 1fr;gap:11px;width:100%;max-width:660px;
    margin:30px auto 0;padding-bottom:20px}
  .opt{min-height:64px}
  .next{grid-column:1 / -1}
  .hint{padding-bottom:22px}
  .done-wrap{justify-content:center}
  .again{max-width:340px;margin-left:auto;margin-right:auto}
}


/* ---------- the day ---------- */
.day{max-width:520px;margin:0 auto;width:100%;padding:26px 4px}
.date{font-family:var(--mono,var(--disp));font-size:0.7188rem;letter-spacing:.14em;color:var(--dim-2);
  text-transform:uppercase;margin-bottom:30px}
.owed{display:flex;align-items:baseline;gap:12px}
.owed-n{font-family:var(--disp);font-size:4.625rem;font-weight:800;letter-spacing:-.045em;line-height:.82;
  color:var(--paper);font-variant-numeric:tabular-nums}
.owed-n.none{color:var(--dim-2)}
.owed-l{font-family:var(--disp);font-size:1rem;font-weight:700;color:var(--dim)}
.owed-sub{font-size:0.8438rem;color:var(--dim-2);margin-top:8px}
.block{margin-top:34px}
.block-h{font-family:var(--disp);font-size:0.6562rem;letter-spacing:.16em;color:var(--dim-2);font-weight:700;
  display:flex;justify-content:space-between;margin-bottom:11px}
.marks{display:flex;gap:2px}
.mk{flex:1 1 0;min-width:0;height:22px;border-radius:2px;background:var(--raise)}
.mk.on{background:var(--seal-bg)} .mk.light{background:#B3523F}
.mk.today{box-shadow:0 4px 0 0 var(--paper)}
.lvrow{display:flex;gap:8px;flex-wrap:wrap}
.lv{min-height:46px;min-width:66px;padding:11px 15px;border:1px solid var(--line);border-radius:10px;
  background:var(--raise);font-family:var(--disp);font-size:0.875rem;font-weight:700;color:var(--dim);cursor:pointer}
.lv[aria-pressed="true"]{background:var(--paper);border-color:var(--paper);color:var(--ground)}
.lv:focus-visible{outline:2px solid var(--t4);outline-offset:2px}

/* ---------- the teach card ---------- */
.play{min-height:44px;padding:8px 18px;border-radius:9px;background:var(--raise);border:1px solid var(--line);
  font-family:var(--disp);font-size:0.8125rem;font-weight:700;color:var(--dim)}
.play[data-state="none"]{color:var(--dim-hi)}
.teach{display:flex;flex-direction:column;align-items:center;gap:12px;text-align:center}
.teach .reveal{min-height:30px}
.teach .en{font-size:1.3125rem;color:var(--paper);font-weight:500;max-width:26ch}
.new-tag{font-family:var(--disp);font-size:0.625rem;letter-spacing:.18em;font-weight:800;color:var(--ground);
  background:var(--t1);border-radius:999px;padding:4px 11px}

/* ---------- the alarm ---------- */
.alarm{background:rgba(226,96,76,.13);border:1px solid var(--miss);border-left:5px solid var(--miss);
  border-radius:9px;padding:13px 15px;margin-bottom:18px;color:#F5C9C1;font-size:0.875rem;line-height:1.5}
.alarm b{display:block;font-family:var(--disp);font-weight:800;margin-bottom:3px;color:var(--miss)}

/* the produce card asks for the character, so options carry hanzi + pinyin */
.opt .oz{font-family:var(--han);font-size:1.3125rem;margin-right:2px}
.opt .op{font-size:0.875rem;opacity:.85}
.opt .ostack{display:flex;flex-direction:column;gap:2px;min-width:0}

/* the produce card has no pinyin line, so it reserves only the note */
.stage.produce .reveal{min-height:38px}

/* leaving a session — quiet, but always there */
.quit{flex:none;min-height:44px;padding:8px 14px;border-radius:9px;background:transparent;
  border:1px solid transparent;font-family:var(--disp);font-size:0.8125rem;font-weight:700;
  color:var(--dim-2);cursor:pointer;transition:color .15s,background .15s}
.quit:hover{color:var(--paper);background:var(--raise)}
.quit:focus-visible{outline:2px solid var(--t4);outline-offset:2px}

/* ================================================================ v2.1 */
/* headings carry no browser margin or weight of their own */
h1{margin:0;font:inherit}
[data-focus]:focus{outline:none}
/* visually hidden, read aloud */
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.opt.right .k,.opt.wrong .k{font-size:1rem}
.prompt{font-size:1.875rem;color:var(--paper);font-weight:600;line-height:1.25;max-width:22ch}

/* screens without a trail: one centred column, on every width */
.app.solo{display:flex;flex-direction:column;max-width:520px;grid-template-columns:none;gap:0}
.app.solo.wide{max-width:720px}
.solo-opts{margin-top:30px}
.next.ghost{background:var(--raise);color:var(--paper);border:1px solid var(--line)}

/* the three doors on the day screen */
.modes{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.mode{flex:1 1 8rem;min-height:56px;padding:10px 12px;border-radius:12px;background:var(--raise);
  border:1px solid var(--line);display:flex;flex-direction:column;align-items:flex-start;gap:3px;
  transition:background .18s var(--snap),border-color .18s var(--snap)}
.mode:disabled{cursor:default;border-style:dashed}
.mode:disabled .mode-l{color:var(--dim)}
.mode:disabled .mode-u{color:var(--paper);font-size:0.875rem;font-weight:700;text-align:left;white-space:nowrap}
@media (hover:hover){ .mode:not(:disabled):hover{background:var(--raise-2);border-color:#39435C} }
.mode-l{font-family:var(--disp);font-size:0.75rem;letter-spacing:.06em;font-weight:700;color:var(--dim)}
.mode-n{font-family:var(--disp);font-size:1.25rem;font-weight:800;color:var(--paper);font-variant-numeric:tabular-nums;
  display:flex;align-items:baseline;gap:5px}
.mode-u{font-size:0.75rem;font-weight:600;color:var(--dim);letter-spacing:.02em}

/* sentence line: words as stacked pinyin + character */
.sline{display:flex;flex-wrap:wrap;justify-content:center;align-items:flex-end;gap:2px 6px;max-width:100%}
.sp{display:inline-flex;flex-direction:column;align-items:center;gap:1px;padding:4px 3px;border-radius:8px;
  font-family:var(--han);color:var(--paper)}
.sp.punct{align-self:flex-end;padding:4px 0;color:var(--dim)}
.spy{font-family:var(--ui);font-size:0.75rem;line-height:1.2;opacity:.9;min-height:14px}
.sz{font-size:1.875rem;line-height:1.2;font-weight:500}
.sline.big .sz{font-size:clamp(1.875rem,6.5vw,2.75rem)}
.sline.big .spy{font-size:0.8438rem;visibility:hidden;min-height:16px}
.sline.big .spy.on{visibility:visible;opacity:.9}
.sp.gap .sz{color:var(--seal);letter-spacing:.05em;border-bottom:2px solid var(--seal);line-height:1.05;padding-bottom:2px}
.sp.gap.filled .sz{letter-spacing:0}
.sp.gap.filled.good .sz{color:#B6E8CD;border-bottom-color:var(--jade)}
.sp.gap.filled.bad .sz{color:#F2BDB3;border-bottom-color:var(--miss)}
.stage.sent{gap:16px}
.stage.sent .sline.big .spy{visibility:visible;opacity:.9}
.sent-en{font-size:1.1875rem;font-weight:500;color:var(--dim-hi);max-width:34ch}
.stage.sent .reveal{min-height:38px}
@media (max-width:360px){
  .sline{gap:1px 3px} .sp{padding:3px 2px}
  .sline.big .sz{font-size:1.625rem} .sline.big .spy{font-size:0.75rem;min-height:14px}
  .stage.sent{gap:10px} .sent-en{font-size:1.0625rem}
}
.t1{color:var(--t1)} .t2{color:var(--t2)} .t3{color:var(--t3)} .t4{color:var(--t4)} .t0{color:var(--t0)}

/* read */
.stage.read{gap:22px}
.sp.word{cursor:pointer;min-width:44px;border:1px solid transparent;transition:background .15s,border-color .15s}
.sp.word.unmet .sz{color:var(--t1);text-decoration:underline dotted;text-decoration-thickness:1.5px;text-underline-offset:6px}
.sp.word.picked{background:var(--raise-2);border-color:var(--line)}
@media (hover:hover){ .sp.word:hover{background:var(--raise)} }
.sp.word:focus-visible,.opt:focus-visible,.next:focus-visible,.tog:focus-visible,.mode:focus-visible,.play:focus-visible,
.chip:focus-visible,.g-head:focus-visible,.g-q:focus-visible{outline:2px solid var(--t4);outline-offset:2px}
.g-head:focus-visible{outline-offset:-3px}
.rd-note{min-height:26px;font-size:1rem;color:var(--dim);display:flex;gap:10px;align-items:baseline;justify-content:center;flex-wrap:wrap}
.rn-z{font-family:var(--han);font-size:1.1875rem;color:var(--paper)}
.rn-e{color:var(--paper)}
.rd-en{font-size:1.0625rem;color:var(--dim);opacity:0;transition:opacity .2s;max-width:36ch;text-align:center;line-height:1.4}
.rd-en.on{opacity:1}
.rd-pos{font-family:var(--disp);font-size:0.75rem;letter-spacing:.08em;color:var(--dim);font-variant-numeric:tabular-nums;flex:1 1 auto;text-align:center}
.tog{min-height:44px;padding:8px 14px;border-radius:9px;background:var(--raise);border:1px solid var(--line);
  font-family:var(--disp);font-size:0.8125rem;font-weight:700;color:var(--dim)}
.tog[aria-pressed="true"]{background:var(--paper);border-color:var(--paper);color:var(--ground)}
.rd-row{flex-direction:row;flex-wrap:wrap;gap:8px}
.opt.small{min-height:52px;padding:10px 12px;justify-content:center;font-family:var(--disp);font-weight:700;font-size:0.875rem;flex:1 1 120px}
.opt.small[aria-pressed="true"]{background:var(--raise-2);border-color:var(--paper)}
.opt.small:disabled{opacity:.35;cursor:default}
@media (min-width:760px){
  .app.solo .opts{display:flex;flex-direction:column;margin:0;max-width:none}
  .app.solo .rd-row{flex-direction:row}
  .app.solo .again{margin-top:auto;max-width:340px;margin-left:auto;margin-right:auto}
  .app.solo .solo-opts{margin-top:30px}
  .app.solo .top{justify-content:space-between}
  .app.solo .stage{margin-top:auto}
  .app.solo .rd-row{margin-bottom:auto}
}

/* words */
.gloss{overflow:hidden}
.gloss>*{flex-shrink:0}
.g-title{font-family:var(--disp);font-size:0.6562rem;letter-spacing:.16em;color:var(--dim-2);font-weight:700;flex:1 1 auto;text-align:center}
.g-levels{margin:6px 0 14px}
.g-levels .lv{flex:1 1 0;display:flex;flex-direction:column;align-items:flex-start;gap:2px;min-width:0;padding:9px 12px}
.lv-n{font-size:0.6875rem;font-weight:600;letter-spacing:.02em;opacity:.75;min-height:13px;line-height:1.2}
.g-bar{display:flex;flex:none;height:8px;border-radius:4px;overflow:hidden;background:var(--raise);gap:2px}
.g-seg{display:block;height:100%}
.g-seg.known{background:var(--jade)} .g-seg.learning{background:var(--t1)} .g-seg.new{background:var(--line)}
.g-key{display:flex;flex-wrap:wrap;gap:6px 16px;margin:10px 0 14px;font-size:0.7812rem;color:var(--dim);font-family:var(--disp);font-weight:600}
.g-key span{display:inline-flex;align-items:center;gap:6px}
.g-key .g-seg{width:10px;height:10px;border-radius:3px;border:1px solid var(--line)}
.g-tools{display:flex;flex-direction:column;gap:10px;margin-bottom:10px}
.chips{display:flex;gap:6px;flex-wrap:wrap}
.chip{min-height:44px;min-width:44px;padding:6px 14px;border-radius:999px;background:var(--raise);border:1px solid var(--line);
  font-family:var(--disp);font-size:0.7812rem;font-weight:700;color:var(--dim)}
@media (max-width:430px){ .chip{flex:1 1 30%;padding:6px 8px;text-align:center} }   /* two rows of three, none cut */
.chip[aria-pressed="true"]{background:var(--paper);border-color:var(--paper);color:var(--ground)}
.g-q{width:100%;min-height:44px;padding:10px 14px;border-radius:10px;background:var(--raise);border:1px solid var(--line);
  color:var(--paper);font:inherit;font-size:1rem}
.g-q::placeholder{color:var(--dim)}
.g-list{flex:1 1 auto!important;overflow-y:auto;min-height:120px;display:flex;flex-direction:column;gap:4px;padding:0 0 12px;
  scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.g-row{flex:none;border-radius:9px;background:var(--raise);border:1px solid transparent;border-left:3px solid var(--line)}
.g-head{display:grid;width:100%;grid-template-columns:auto 1fr auto auto;grid-template-areas:"z p flag st" "z e flag st";
  column-gap:12px;row-gap:2px;align-items:center;padding:9px 12px;border-radius:9px;cursor:pointer;text-align:left;min-height:44px}
.g-row.known{border-left-color:var(--jade)} .g-row.learning{border-left-color:var(--t1)} .g-row.isdue{border-left-color:var(--seal)}
.g-row.open{background:var(--raise-2);border-top-color:var(--line);border-right-color:var(--line);border-bottom-color:var(--line)}
.g-row.open .g-e{white-space:normal}
@media (hover:hover){ .g-row:hover{background:var(--raise-2)} .g-row:hover .g-e{color:var(--dim-hi)} }
.g-z{grid-area:z;font-family:var(--han);font-size:1.375rem;color:var(--paper);min-width:2.2em}
.g-p{grid-area:p;font-size:0.8438rem}
.g-e{grid-area:e;font-size:0.8438rem;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.g-flag{grid-area:flag;font-family:var(--disp);font-weight:800;color:var(--miss);font-size:0.9375rem}
.g-st{grid-area:st;font-family:var(--disp);font-size:0.7188rem;font-weight:700;letter-spacing:.04em;color:var(--dim);white-space:nowrap;text-align:right}
.g-st.due{color:#EE6E58} .g-st.new{color:var(--dim)}
.g-detail{display:flex;flex-wrap:wrap;gap:6px 16px;align-items:center;margin:0 12px 10px;padding-top:8px;
  border-top:1px solid var(--line);font-size:0.8125rem;color:var(--dim-hi)}
.g-row.open .g-e{color:var(--dim-hi)}
.g-detail b{color:var(--paper);font-weight:600}
.g-play{min-height:44px;margin-left:auto}
.g-empty{padding:30px 0;text-align:center;color:var(--dim-2);font-family:var(--disp);font-weight:700;font-size:0.8125rem;letter-spacing:.08em}
.g-foot{flex:none;padding:8px 0 calc(10px + env(safe-area-inset-bottom));font-size:0.6875rem;color:var(--dim-2);text-align:center;
  font-family:var(--disp);letter-spacing:.04em}

/* forced colours: every state must survive without its hue */
@media (forced-colors:active){
  .opt,.next,.mode,.tog,.chip,.lv,.g-row,.g-head,.sp.word,.play{border:1px solid ButtonText}
  .opt.right{border:3px double ButtonText} .opt.wrong{border:3px dashed ButtonText}
  .opt.fade{opacity:1;border-style:dotted}
  .lv[aria-pressed="true"],.tog[aria-pressed="true"],.chip[aria-pressed="true"],.opt.small[aria-pressed="true"],.sp.word.picked{
    forced-color-adjust:none;background:Highlight;color:HighlightText}
  .lv[aria-pressed="true"] *,.tog[aria-pressed="true"] *,.chip[aria-pressed="true"] *,.opt.small[aria-pressed="true"] *,
  .sp.word.picked *{color:HighlightText}
  .seg,.mk,.g-seg,.bar-fill,.bar-track{border:1px solid ButtonText}
  .seg.hit,.mk.on,.g-seg.known,.bar-fill{forced-color-adjust:none;background:Highlight}
  .seg.miss,.mk.light,.g-seg.learning{forced-color-adjust:none;background:repeating-linear-gradient(45deg,CanvasText 0 2px,Canvas 2px 5px)}
  .sp.word.unmet .sz{text-decoration:underline dotted}
  .sp.gap .sz{border-bottom:2px solid CanvasText}
}

/* short viewports: the card and its answers must fit without scrolling */
@media (max-height:620px){
  .stage{gap:8px;padding:4px 0}
  .hanzi{font-size:2.75rem}
  .prompt{font-size:1.25rem}
  .sline .sz{font-size:1.5rem} .sline.big .sz{font-size:1.75rem}
  .spy{font-size:0.6875rem;min-height:12px}
  .reveal{min-height:40px} .stage.produce .reveal,.stage.sent .reveal{min-height:26px}
  .opt{min-height:46px;padding:9px 14px} .next{min-height:48px} .opts{gap:6px}
  .top{padding-top:8px}
  .hint{display:none}
  .teach{gap:8px} .teach .en{font-size:1.0625rem}
}

/* ---------- write ---------- */
.stage.writeS{gap:10px}
.w-word{font-family:var(--han);font-size:1.75rem;color:var(--paper);letter-spacing:.06em}
.w-word .w-gap{color:var(--seal);font-weight:500}
.w-py{font-size:1.25rem}
.w-en{font-size:1rem;color:var(--dim-hi);max-width:30ch}
.w-box{width:min(320px,80vw,46vh);aspect-ratio:1;margin:6px auto 0;border-radius:14px;background:var(--raise);
  border:1px solid var(--line);position:relative;overflow:hidden}
#hw{width:100%;height:100%;touch-action:none;user-select:none;-webkit-user-select:none}
#hw svg{display:block;width:100%;height:100%}
.w-box::before,.w-box::after{content:"";position:absolute;background:var(--line);opacity:.7;pointer-events:none}
.w-box::before{left:50%;top:0;bottom:0;width:1px}
.w-box::after{top:50%;left:0;right:0;height:1px}
.w-fail{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:20px;text-align:center;
  font-size:0.875rem;color:var(--dim-hi)}
.w-rail{flex-direction:row;flex-wrap:wrap;gap:8px}
.w-rail .next{flex:1 1 100%}
.stage.writeS .reveal{min-height:30px}
@media (min-width:760px){
  .app .w-rail{display:flex;flex-direction:row;flex-wrap:nowrap;max-width:660px;margin:18px auto 0}
  .app .w-rail .next{flex:2 1 auto}       /* one row: Trace · Play · Skip */
  .w-box{width:min(400px,50vh)}          /* a mouse or trackpad wants room */
}
/* short viewports: the box is the point of the screen, so it keeps its size and the words around it shrink */
@media (max-height:620px){
  .stage.writeS{gap:6px}
  .w-box{width:min(80vw,52vh);margin-top:2px}
  .w-word{font-size:1.25rem} .w-py{font-size:1rem} .w-en{font-size:0.875rem}
  .stage.writeS .reveal{min-height:22px}
}
/* wide and very short (a landscape phone, a laptop at 200% zoom): the words sit beside the box */
@media (min-width:600px) and (max-height:460px){
  .stage.writeS{display:grid;grid-template-columns:minmax(150px,1fr) auto;grid-auto-rows:auto;column-gap:22px;row-gap:6px;
    align-items:center;justify-items:center;justify-content:center;padding:4px 0}
  .stage.writeS>*{grid-column:1}
  .stage.writeS .w-box{grid-column:2;grid-row:1 / span 6;width:min(68vh,320px);margin:0}
  .stage.writeS .reveal{min-height:0}
  .app .w-rail{margin-top:4px}
}

/* ---------- the day screen on a laptop ----------
   The phone keeps its single column. From 1000px the day opens to the whole
   screen: the counts and the last 35 days along the top, the four doors down
   the left where the hand is, the day's note filling the right, Begin under
   all of it. The note is desktop only — the phone screen is settled. */
.panel{display:none}
@media (min-width:1000px){
  .app.dayview{max-width:1560px;padding:0 44px}
  .app.dayview .main{overflow:hidden}
  .day{max-width:none;padding:28px 0 0;flex:1 1 auto;min-height:0;
    display:grid;column-gap:34px;
    grid-template-columns:minmax(250px,340px) minmax(0,1fr) auto;
    grid-template-rows:auto auto auto auto auto auto;
    grid-template-areas:
      "alarm alarm alarm"
      "date  strip levels"
      "owed  panel panel"
      "sub   panel panel"
      "doors panel panel"
      "begin begin begin";
    align-content:start;row-gap:0}
  /* on a tall screen the whole day sits as one block, centred, rather than
     hanging from the top with a hole under it */
  @media (min-height:840px){ .day{align-content:center;padding-bottom:28px} }
  .day .alarm{grid-area:alarm}
  .day .date{grid-area:date;align-self:end;padding-bottom:6px}
  .day .owed{grid-area:owed;flex-direction:column;align-items:flex-start;gap:0;margin-top:10px}
  .day .owed-n{line-height:.88}
  .day .owed-sub{grid-area:sub;margin:6px 0 0}
  .day .block.days{grid-area:strip;margin:0;align-self:end}
  .day .block.levels{grid-area:levels;margin:0;align-self:end}
  .day .block.levels .lvrow{flex-wrap:nowrap}
  .day .modes{grid-area:doors;margin-top:24px;flex-direction:column;align-self:start}
  .day .mode{flex:none;width:100%;min-height:68px}
  .app.dayview .day .solo-opts{grid-area:begin;margin:24px auto 22px;width:100%;max-width:520px}
  .day .marks{gap:3px} .day .mk{height:34px}

  .panel{grid-area:panel;display:flex;flex-direction:column;margin:16px 0 0;
    border:1px solid var(--line);border-radius:18px;background:var(--raise);padding:20px 28px 24px}
  .panel .block-h{margin-bottom:0}
  .panel-body{flex:1 1 auto;display:flex;align-items:center;justify-content:center;gap:36px;padding:10px 4px}
  .panel-z{font-family:var(--han);font-size:clamp(4.5rem,11vh,9rem);line-height:1;color:var(--paper);
    flex:none;letter-spacing:.04em}
  .panel-t{margin:0;font-size:1.1875rem;line-height:1.6;color:var(--dim-hi);max-width:42ch}
  .panel-body:only-child .panel-t,.panel-t:only-child{font-size:1.25rem;max-width:38ch;text-align:center}
}
@media (min-width:1000px) and (max-height:780px){
  .day{padding-top:16px} .day .mk{height:26px}
  .day .mode{min-height:58px} .day .modes{margin-top:16px}
  .app.dayview .day .solo-opts{margin:16px auto 14px}
  .panel{margin-top:12px;padding:16px 24px 18px}
}

/* ---------- the sitting on a laptop ----------
   Same decision as the day screen: from 1000px the screen is used. The queue
   runs down the left as slots you can count, the character takes the room it
   deserves, and the four answers sit under it in one glance. */
@media (min-width:1000px){
  .app:not(.solo){max-width:1560px;grid-template-columns:minmax(260px,340px) minmax(0,1fr);
    gap:44px;padding:0 44px}
  .trail{padding:30px 0 22px}
  .trail-h{font-size:0.6875rem;margin-bottom:15px}
  .trail-list{gap:5px}
  .ti{min-height:44px;padding:9px 14px;border-radius:9px;gap:12px}
  .ti-h{font-size:1.1875rem}
  .ti-e{font-size:0.8125rem}
  .ti.wait{min-height:26px;padding:0;background:#141926;border-left:3px solid var(--line);
    border-radius:0 6px 6px 0}
  .hanzi{font-size:clamp(6rem,16vh,11.5rem)}
  .prompt{font-size:clamp(1.875rem,3.4vh,2.5rem);max-width:26ch}
  .py{font-size:clamp(1.5rem,3vh,2rem)}
  .stage{gap:clamp(10px,2vh,22px)}
  .reveal{min-height:clamp(60px,9vh,96px)}
  .opts{max-width:940px;gap:14px;margin-top:clamp(18px,3.5vh,40px)}
  .opt{min-height:clamp(64px,9vh,86px);font-size:1.125rem;padding:16px 22px}
  .opt .k{width:26px;font-size:0.8125rem}
  .new-tag{font-size:0.75rem}
  .sline .sz{font-size:clamp(2rem,4.6vh,3rem)} .sline.big .sz{font-size:clamp(2.5rem,7vh,4.5rem)}
  .sline.big .spy{font-size:clamp(0.9375rem,2vh,1.1875rem);min-height:22px}
  .sent-en{font-size:clamp(1.1875rem,2.6vh,1.5rem);max-width:38ch}
  .w-box{width:min(46vh,440px)}
}

/* ---------- the rest of the screens on a laptop ----------
   Read, Words and the end summary get the same frame as the day and the
   sitting, and the way out sits in the same corner on every screen: top right.
   The phone keeps the layout it was given. */
@media (min-width:1000px){
  .app.solo,.app.solo.wide{max-width:1560px;padding:0 44px}
  /* one column of content, centred in the frame, header included so the way
     out lines up with the edge of what it leaves */
  .app.solo:not(.dayview) .main{max-width:1120px;margin-left:auto;margin-right:auto;width:100%}

  /* Read: one wide line to read, the controls under it */
  .rd-note{font-size:1.125rem;min-height:32px}
  .rn-z{font-size:1.4375rem}
  .rd-en{font-size:1.25rem;max-width:44ch}
  .rd-pos{font-size:0.8125rem}
  .app.solo .rd-row{max-width:820px;margin-left:auto;margin-right:auto;gap:12px}
  .app.solo .rd-row .tog,.app.solo .rd-row .next{min-height:60px;font-size:1.0625rem}

  /* Words: a wider list with room for the meaning */
  .g-levels .lv{max-width:240px}
  .g-title{font-size:0.75rem}
  .g-head{padding:13px 16px;gap:4px 16px}
  .g-z{font-size:1.75rem;min-width:2.4em}
  .g-p{font-size:0.9375rem} .g-e{font-size:0.9375rem}
  .g-st{font-size:0.8125rem}
  .g-key{font-size:0.8438rem;margin:12px 0 16px}
  .g-bar{height:10px}
  .g-tools{flex-direction:row;align-items:center;gap:16px}
  .g-tools .chips{flex:1 1 auto}
  .g-q{max-width:380px}
  .g-list{gap:6px}
  .g-detail{font-size:0.9375rem;margin:0 16px 12px}

  /* the end: the number carries the screen */
  .app.solo .done-wrap{max-width:720px;margin:0 auto;width:100%}
  .done-n{font-size:6.5rem} .done-of{font-size:1.0625rem} .done-l{font-size:0.8125rem}
  .bar{font-size:0.9375rem} .bar-t{width:88px;font-size:0.8125rem} .bar-n{font-size:1rem}
  .longest{font-size:1rem} .longest b{font-size:1.25rem}
  .app.solo .again{max-width:520px;margin-left:auto;margin-right:auto}
}
