:root{
  --bg:#141b2b; --surface:#1e2739; --surface-2:#29344a; --line:#38445d;
  --text:#e9e5da; --muted:#97a1b5; --gold:#d4a537; --gold-dim:#8a6d24;
  --green:#58a88c; --rust:#cd6152; --blue:#6f8fd0;
  --gk:"Noto Serif","GFS Didot","Palatino Linotype",Palatino,Georgia,"Times New Roman",serif;
  --ui:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",sans-serif;
  --nav-h:60px;
  /* "Greek text size" used to reach exactly two places. Everything Greek is
     sized through this, so the setting means what it says. */
  --gk-scale:1;
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html{height:100%}
html,body{margin:0;padding:0}
body{min-height:100%}
body{
  background:var(--bg); color:var(--text); font-family:var(--ui);
  /* rem, not px: every caption around it is already relative, so a fixed
     body pinned the lesson prose while the captions grew. */
  font-size:1rem; line-height:1.55; overscroll-behavior-y:contain;
  padding-bottom:calc(var(--nav-h) + env(safe-area-inset-bottom) + 20px);
}
button{font-family:inherit;font-size:inherit;color:inherit;background:none;border:none;cursor:pointer}
:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.gk{font-family:var(--gk)}

/* ---------- layout ---------- */
#app{max-width:640px;margin:0 auto;padding:0 18px}
.screen{display:none;padding-top:calc(14px + env(safe-area-inset-top))}
.screen.on{display:block;animation:in .18s ease-out}
@keyframes in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
/* The pseudo-elements have to be named. `*` matches elements only, so the
   tick that scales in on a correct answer would have kept animating for
   someone who had asked the whole app to stop moving. */
@media (prefers-reduced-motion:reduce){*,*::before,*::after{
  animation:none!important;transition:none!important}}

h1{font-size:1.45rem;font-weight:600;margin:0 0 2px;letter-spacing:-.01em}
h2{font-size:1.1rem;font-weight:600;margin:26px 0 10px}
h3{font-size:.95rem;font-weight:600;margin:18px 0 6px;color:var(--gold)}
p{margin:0 0 12px}
.sub{color:var(--muted);font-size:.87rem;margin:0 0 20px}
.muted{color:var(--muted)}
small{font-size:.8rem}

.card{background:var(--surface);border:1px solid var(--line);border-radius:14px;padding:16px;margin-bottom:12px}
.row{display:flex;align-items:center;gap:12px}
.between{display:flex;align-items:center;justify-content:space-between;gap:12px}

/* ---------- buttons ---------- */
.btn{
  display:block;width:100%;padding:14px 18px;border-radius:12px;
  background:var(--gold);color:#1a1408;font-weight:650;text-align:center;
  border:none;transition:transform .08s;
}
.btn:active{transform:scale(.985)}
.btn.ghost{background:transparent;border:1px solid var(--line);color:var(--text);font-weight:500}
.btn.small{width:auto;padding:9px 16px;font-size:.87rem;border-radius:10px}
.btn[disabled]{opacity:.4}

/* ---------- bottom nav ---------- */
nav{
  position:fixed;left:0;right:0;bottom:0;z-index:40;
  height:calc(var(--nav-h) + env(safe-area-inset-bottom));
  padding-bottom:env(safe-area-inset-bottom);
  background:rgba(20,27,43,.94);backdrop-filter:blur(12px);
  border-top:1px solid var(--line);display:flex;
}
nav button{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;color:var(--muted);font-size:.66rem;letter-spacing:.02em}
nav button .ic{font-family:var(--gk);font-size:1.15rem;line-height:1}
nav button.on{color:var(--gold)}

/* ---------- today ---------- */
.hero{text-align:center;padding:22px 0 6px}
.ring{width:150px;height:150px;margin:0 auto 14px;position:relative}
.ring svg{transform:rotate(-90deg)}
.ring .mid{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}
.ring .big{font-size:2rem;font-weight:600;line-height:1}
.streak{display:inline-flex;align-items:center;gap:6px;background:var(--surface-2);border-radius:999px;padding:5px 13px;font-size:.83rem}
.streak i{font-style:normal;color:var(--muted);font-size:.76rem}
.streak i:empty{display:none}
/* ---------- today's plan ----------
   Built on .lesson-item's shape so the two lists read as one app. The tick
   is a circle that fills when the row is done, which is the whole point of
   the screen: you can see what today asks before you start it. */
.plan-row{display:flex;align-items:center;gap:13px;width:100%;text-align:left;
  padding:13px 15px;margin-bottom:9px;background:var(--surface);
  border:1px solid var(--line);border-radius:12px;transition:opacity .2s}
.plan-row .tick{flex:0 0 22px;width:22px;height:22px;border-radius:50%;
  border:1.5px solid var(--line);display:flex;align-items:center;
  justify-content:center;font-size:.76rem;font-weight:700;color:#12191a}
.plan-row .t{flex:1;min-width:0;display:flex;flex-direction:column}
.plan-row .t b{font-weight:600;font-size:.95rem}
.plan-row .t span{font-size:.76rem;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.plan-row .chev{color:var(--muted)}
.plan-row.done{opacity:.55}
.plan-row.done .tick{background:var(--green);border-color:var(--green)}
.plan-row.done .t b{text-decoration:line-through;text-decoration-color:var(--muted)}

/* the passage you are working. Gold-edged like the pinned row, because it is
   the same kind of thing: something you chose, that the day now bends around. */
.card.focus{border-color:var(--gold-dim);margin-top:14px}
.card.focus h3{margin:0 0 2px;color:var(--text);font-size:.98rem}
.card.focus .prog-bar{margin-bottom:6px}

.stat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin:14px 0}
.stat{background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:12px 8px;text-align:center}
.stat b{display:block;font-size:1.3rem;font-weight:600}
.stat span{font-size:.72rem;color:var(--muted)}

/* ---------- flashcard ---------- */
.fc{
  background:var(--surface);border:1px solid var(--line);border-radius:18px;
  min-height:290px;display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;padding:26px 20px;margin-bottom:14px;
}
/* The cap and the wrap are both safety nets for the longest words at Extra
   large on a narrow phone; below that nothing here changes the rendering. */
.fc .word{font-family:var(--gk);font-size:min(calc(2.9rem * var(--gk-scale)),18vw);line-height:1.25;font-weight:400;overflow-wrap:anywhere}
.fc .rule{width:54px;height:2px;background:var(--gold);margin:16px 0;opacity:.75}
.fc .ans{font-size:1.12rem}
.fc .meta{color:var(--muted);font-size:.79rem;margin-top:12px}
.grades{display:grid;grid-template-columns:repeat(4,1fr);gap:7px}
.grades button{padding:12px 4px;border-radius:11px;border:1px solid var(--line);font-size:.78rem;font-weight:600;background:var(--surface)}
.grades button i{display:block;font-style:normal;font-size:.64rem;font-weight:400;color:var(--muted);margin-top:2px}
.g1{color:var(--rust)}.g2{color:#d6a05e}.g3{color:var(--green)}.g4{color:var(--blue)}
.prog-bar{height:4px;background:var(--surface-2);border-radius:99px;overflow:hidden;margin-bottom:14px}
.prog-bar i{display:block;height:100%;background:var(--gold);transition:width .25s}

/* ---------- quiz ---------- */
.opt{
  display:block;width:100%;text-align:left;padding:14px 16px;margin-bottom:9px;
  background:var(--surface);border:1px solid var(--line);border-radius:12px;transition:border-color .15s;
}
.opt.pick{border-color:var(--gold)}
.opt.right{border-color:var(--green);background:rgba(88,168,140,.13)}
.opt.wrong{border-color:var(--rust);background:rgba(205,97,82,.13)}

/* ---------- how an answer feels ----------
   A tinted border was the whole of it, which is what "lifeless" meant. The
   reduced-motion rule near the top of this file switches every animation
   here off in one line, and the marks and colours stay. */
.opt{position:relative}
.opt.right,.opt.wrong{padding-right:44px}
.opt.right::after,.opt.wrong::after{
  position:absolute;right:15px;top:50%;margin-top:-11px;
  width:22px;height:22px;line-height:22px;text-align:center;border-radius:50%;
  font-size:.8rem;font-weight:700;color:#12191a}
.opt.right::after{content:"✓";background:var(--green);animation:mark .26s cubic-bezier(.2,1.5,.4,1) both}
.opt.wrong::after{content:"✕";background:var(--rust);color:#1c0f0d}
.opt.right{animation:pop .2s ease-out}
.opt.wrong{animation:nudge .22s ease-in-out}
@keyframes pop{0%{transform:scale(1)}45%{transform:scale(1.035)}100%{transform:scale(1)}}
@keyframes mark{from{transform:scale(0) rotate(-25deg);opacity:0}to{transform:scale(1) rotate(0);opacity:1}}
@keyframes nudge{0%,100%{transform:translateX(0)}25%{transform:translateX(-5px)}75%{transform:translateX(5px)}}

/* the XP lifting off the button it was earned on */
.xpfly{position:absolute;right:14px;top:6px;font-size:.76rem;font-weight:700;
  color:var(--gold);pointer-events:none;animation:fly .9s ease-out forwards}
@keyframes fly{0%{opacity:0;transform:translateY(4px)}
  22%{opacity:1;transform:translateY(-4px)}100%{opacity:0;transform:translateY(-26px)}}

/* the run, beside the card count. The header is justify-content:space-between,
   so this needs no margin of its own — and :empty removes it from the row
   entirely rather than leaving a gap the other three spread around. */
.combo{font-size:.76rem;font-weight:650;
  color:var(--muted);white-space:nowrap;transition:color .2s}
.combo:empty{display:none}
.combo.hot{color:var(--gold)}
.combo.blaze{color:var(--gold);text-shadow:0 0 10px rgba(212,165,55,.5)}

/* the progress bar acknowledging a correct answer */
.prog-bar i.hit{animation:barhit .45s ease-out}
@keyframes barhit{0%{box-shadow:0 0 0 0 rgba(212,165,55,.6);filter:brightness(1)}
  35%{box-shadow:0 0 9px 2px rgba(212,165,55,.55);filter:brightness(1.35)}
  100%{box-shadow:0 0 0 0 rgba(212,165,55,0);filter:brightness(1)}}
/* one section of a chapter, inside a session. The prose keeps the page's own
   type; only the first heading loses its top margin so it sits on the card. */
.card.read>:first-child{margin-top:0}
.card.read>:last-child{margin-bottom:0}
.card.read h3:first-child{margin-top:0}
.feedback{border-left:3px solid var(--gold);padding:2px 0 2px 13px;margin:14px 0;font-size:.9rem;color:var(--muted)}
.feedback b{color:var(--text);display:block;margin-bottom:3px}

/* ---------- lessons ---------- */
.lesson-item{display:flex;align-items:center;gap:13px;padding:13px 15px;background:var(--surface);border:1px solid var(--line);border-radius:12px;margin-bottom:9px;width:100%;text-align:left}
.lesson-item .n{width:30px;height:30px;flex:0 0 30px;border-radius:50%;border:1px solid var(--line);display:flex;align-items:center;justify-content:center;font-size:.8rem;color:var(--muted)}
.lesson-item.done .n{background:var(--green);border-color:var(--green);color:#0e1a16;font-weight:700}
.lesson-item .t{flex:1;min-width:0}
.lesson-item .t b{display:block;font-weight:600;font-size:.94rem}
.lesson-item .t span{font-size:.76rem;color:var(--muted)}

table{width:100%;border-collapse:collapse;margin:10px 0 16px;font-size:.86rem}
th,td{padding:7px 6px;text-align:left;border-bottom:1px solid var(--line)}
th{color:var(--muted);font-weight:500;font-size:.74rem}
td.g{font-family:var(--gk)}
caption{caption-side:top;text-align:left;color:var(--gold);font-size:.82rem;padding-bottom:5px}

.vid{display:flex;align-items:center;gap:11px;padding:12px 14px;background:var(--surface-2);border-radius:11px;margin-bottom:9px;text-decoration:none;color:var(--text)}
.vid .p{width:26px;height:26px;flex:0 0 26px;border-radius:50%;background:var(--rust);display:flex;align-items:center;justify-content:center;font-size:.6rem;color:#fff}
.vid b{display:block;font-size:.88rem;font-weight:600}
.vid span{font-size:.74rem;color:var(--muted)}
/* a song that plays here rather than throwing you out to a browser. It is a
   <button> so it matches the <a> rows around it exactly. */
button.vid{width:100%;text-align:left;font:inherit}
.vidbox{position:relative;width:100%;aspect-ratio:16/9;margin-bottom:9px;
  border-radius:11px;overflow:hidden;background:#000}
.vidbox iframe{position:absolute;inset:0;width:100%;height:100%;border:0}

/* ---------- alphabet ---------- */
.alpha-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.alpha{background:var(--surface);border:1px solid var(--line);border-radius:11px;padding:11px 4px;text-align:center}
.alpha .l{font-family:var(--gk);line-height:1.15}
.alpha .nm{font-size:.66rem;color:var(--muted);margin-top:2px}

/* ---------- reading ---------- */
.passage{font-family:var(--gk);font-size:calc(1.35rem * var(--gk-scale));line-height:2.05;margin-bottom:16px}
/* 13px tall inside a 39px line box meant a tap in the leading hit the
   container and was silently dropped. Vertical padding on an inline element
   does not change the line layout, and the negative margin keeps the
   horizontal spacing exactly as it was. */
.passage w{cursor:pointer;border-bottom:1px dotted transparent;padding:5px 2px;margin:0 -1px}
.passage w.tapped{background:rgba(212,165,55,.2);border-radius:3px}

/* How well you know the word, in four steps. Opacity only — colour here
   would fight .tapped, which is the one thing on the page that has to be
   unmistakable. Settled words are full strength and the rest recede, so a
   chapter fills in as the deck grows instead of staying uniformly grey.
   Never below .42: this is a reading surface, and a word you cannot read is
   worse than a word you do not know. */
.passage w.k3{opacity:1}
.passage w.k2{opacity:.82}
.passage w.k1{opacity:.6}
.passage w.k0{opacity:.44}
/* .tapped outranks all four: looking a word up is how you stop it being k0 */
.passage w.tapped{opacity:1}
/* the verses a focus is aimed at */
.passage w.inf{background:rgba(212,165,55,.07)}
.passage w.inf.tapped{background:rgba(212,165,55,.2)}
/* the dagger on a gloss that came from a shipped lexicon rather than from
   the course's own 509. Quiet, but there — a terser, older wording is worth
   having and worth knowing about. */
.gloss .src{color:var(--gold);opacity:.75;margin-left:5px;font-size:.8em;cursor:help}

.gloss{position:sticky;bottom:calc(var(--nav-h) + env(safe-area-inset-bottom) + 12px);background:var(--surface-2);border:1px solid var(--gold-dim);border-radius:12px;padding:13px 15px;min-height:74px}
.gloss .w{font-family:var(--gk)}
.gloss .d{font-size:.86rem;color:var(--muted);margin-top:3px}

/* ---------- badges ---------- */
.badges{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.badge{background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:14px 7px;text-align:center;opacity:.32}
.badge.got{opacity:1;border-color:var(--gold-dim)}
.badge .e{font-size:1.5rem;line-height:1}
.badge b{display:block;font-size:.72rem;font-weight:600;margin-top:5px}
.badge span{font-size:.63rem;color:var(--muted)}

/* Clear of the reading gloss, which is a near-identical panel at an
   overlapping offset — the toast used to sit entirely inside it. Its own
   surface colour too, so the two read as different things. */
.toast{position:fixed;left:50%;bottom:calc(var(--nav-h) + env(safe-area-inset-bottom) + 22px);transform:translateX(-50%);max-width:min(88vw,420px);text-align:center;background:var(--surface);border:1px solid var(--line);border-radius:11px;padding:11px 18px;font-size:.87rem;z-index:60;opacity:0;pointer-events:none;transition:opacity .25s}
.toast.on{opacity:1}
.empty{text-align:center;padding:44px 20px;color:var(--muted)}
.empty .gk{font-size:2.4rem;display:block;margin-bottom:12px;color:var(--gold);opacity:.5}

/* ---------- pwa ---------- */
.install{display:none;align-items:center;gap:12px;background:var(--surface-2);border:1px solid var(--gold-dim);border-radius:12px;padding:12px 14px;margin-bottom:16px}
.install.on{display:flex}
.install .t{flex:1;min-width:0}
.install .t b{display:block;font-size:.88rem;font-weight:600}
.install .t span{font-size:.74rem;color:var(--muted);line-height:1.35}

.netpill{position:fixed;left:50%;transform:translateX(-50%);top:calc(9px + env(safe-area-inset-top));z-index:70;background:var(--rust);color:#fff;font-size:.72rem;font-weight:650;letter-spacing:.02em;padding:4px 13px;border-radius:999px;opacity:0;pointer-events:none;transition:opacity .25s}
.netpill.on{opacity:1}

.update{position:fixed;left:50%;bottom:calc(var(--nav-h) + env(safe-area-inset-bottom) + 22px);transform:translateX(-50%);display:none;align-items:center;gap:14px;white-space:nowrap;background:var(--surface-2);border:1px solid var(--gold-dim);border-radius:11px;padding:10px 16px;font-size:.87rem;z-index:61}
.update.on{display:flex}
.update button{color:var(--gold);font-weight:650}

/* Pronunciation links go off-device, so they are the one thing that cannot
   work offline. Say so and make the tap genuinely inert — but dim only the
   title and the bullet: fading the whole element composited the warning
   twice and left it at 1.7:1, effectively unreadable. .local marks the
   things in this list that are precached, such as the alphabet chart. */
.vid .net{display:none;font-size:.72rem;color:#e8907f;margin-top:1px}
body.off .vid:not(.local){pointer-events:none}
body.off .vid:not(.local) .p{opacity:.4}
body.off .vid:not(.local) b{color:var(--muted)}
body.off .vid:not(.local) .net{display:block}

/* ---------- tables tab ---------- */
#tablesSearch{width:100%;padding:11px 14px;border-radius:11px;border:1px solid var(--line);
  background:var(--surface);color:var(--text);font-size:.95rem;margin-bottom:14px}
#tablesSearch::placeholder{color:var(--muted)}
.ptable{margin-bottom:6px}
.ptable>button{width:100%;text-align:left;padding:13px 15px;background:var(--surface);
  border:1px solid var(--line);border-radius:12px;font-weight:600;font-size:.94rem;
  display:flex;justify-content:space-between;align-items:center;gap:12px}
.ptable>button::after{content:"›";color:var(--muted);transform:rotate(90deg);flex:0 0 auto}
.ptable.open>button::after{transform:rotate(-90deg)}
.ptable .pt-body{display:none;padding:2px 4px 10px}
.ptable.open .pt-body{display:block}

/* ---------- parsing builder chips ---------- */
.chips{display:flex;flex-wrap:wrap;gap:7px;margin:7px 0 13px}
.chips button{padding:8px 13px;border-radius:999px;border:1px solid var(--line);
  background:var(--surface);font-size:.85rem;color:var(--muted)}
.chips button.sel{background:var(--gold);border-color:var(--gold);color:#1a1408;font-weight:650}
.chip-lbl{font-size:.72rem;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-top:10px}

/* ---------- settings ---------- */
.setrow{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 0;border-bottom:1px solid var(--line)}
/* Report a problem. The textarea inherits the app's own type rather than
   the browser's monospace default, so what the tester writes looks like
   the rest of the app; the diagnostic block deliberately does not, so it
   reads as machine output and columns line up. */
.rep-what{width:100%;box-sizing:border-box;font:inherit;line-height:1.45;color:var(--text);
  background:var(--surface-2);border:1px solid var(--line);border-radius:10px;padding:10px 12px;resize:vertical}
.rep-what:focus{outline:2px solid var(--gold);outline-offset:1px;border-color:transparent}
.rep-diag{white-space:pre-wrap;word-break:break-word;font-size:.72rem;line-height:1.5;
  color:var(--muted);background:var(--surface-2);border:1px solid var(--line);border-radius:10px;
  padding:10px 12px;margin:8px 0 0;max-height:15em;overflow:auto}
#repShotPrev{display:block;max-width:100%;max-height:16em;margin:10px 0 0;
  border:1px solid var(--line);border-radius:10px}
.setrow:last-child{border-bottom:none}
.setrow select{background:var(--surface-2);color:var(--text);border:1px solid var(--line);border-radius:9px;padding:7px 10px;font-size:.9rem}

/* Greek text size preference */
body[data-gk="lg"]{--gk-scale:1.18}
body[data-gk="xl"]{--gk-scale:1.35}

/* Quiz and drill prompts. These were seven inline font-sizes, so the setting
   could not touch them and the principal-parts drill showed its Greek at
   body size whatever you picked. */
.q-gk{font-family:var(--gk);font-size:calc(1.5rem * var(--gk-scale));line-height:1.35}
.q-gk.sm{font-size:calc(1.2rem * var(--gk-scale))}
.q-gk.lg{font-size:calc(2rem * var(--gk-scale))}
.opt .gk{font-size:calc(1.05rem * var(--gk-scale))}
.gloss .w{font-size:calc(1.4rem * var(--gk-scale))}
td.g{font-size:calc(1.02rem * var(--gk-scale))}
.lk .w b{font-size:calc(1.12rem * var(--gk-scale))}
.alpha .l{font-size:calc(1.5rem * var(--gk-scale))}
.fc .meta .gk{font-size:calc(.95rem * var(--gk-scale))}

/* ---------- pronunciation tiles ---------- */
.alpha.snd{position:relative;cursor:pointer;width:100%;text-align:center;
  transition:background .15s,border-color .15s,transform .08s}
.alpha.snd:active{transform:scale(.96)}
.alpha.snd .sd{font-size:.62rem;color:var(--gold);opacity:.85;margin-top:2px}
.alpha.snd::after{content:"\1F50A";position:absolute;top:5px;right:6px;font-size:.6rem;opacity:.3}
.alpha.snd.playing{background:var(--surface-2);border-color:var(--gold)}
.alpha.snd.playing::after{opacity:1}
.alpha.snd.playing .l{color:var(--gold)}

/* ---------- word lookup ---------- */
#lookupSearch{width:100%;padding:11px 14px;border-radius:11px;border:1px solid var(--line);
  background:var(--surface);color:var(--text);font-size:.95rem;margin-bottom:14px}
#lookupSearch::placeholder{color:var(--muted)}
/* Top-aligned: with an example verse a row is several lines tall, and a
   vertically centred speaker and frequency float away from the headword
   they belong to. */
.lk{display:flex;align-items:flex-start;gap:11px;padding:11px 13px;background:var(--surface);
  border:1px solid var(--line);border-radius:11px;margin-bottom:8px;width:100%;text-align:left}
.lk .w{flex:1;min-width:0}
.lk .w b{display:block;font-family:var(--gk);font-weight:500}
.lk .w span{font-size:.8rem;color:var(--muted)}
.lk .fq{font-size:.68rem;color:var(--muted);white-space:nowrap;margin-top:5px}
.lk .pl{width:32px;height:32px;flex:0 0 32px;border-radius:50%;border:1px solid var(--line);
  display:flex;align-items:center;justify-content:center;font-size:.8rem;margin-top:1px}
.lk .pl.on{background:var(--gold);border-color:var(--gold);color:#1a1408}

/* leech flag */
.leech{display:inline-block;font-size:.62rem;font-weight:700;letter-spacing:.04em;
  background:var(--rust);color:#fff;border-radius:999px;padding:2px 8px;margin-left:8px;vertical-align:middle}

/* ---------- Greek New Testament reader ---------- */
.ch-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:7px}
.ch{background:var(--surface);border:1px solid var(--line);border-radius:10px;
  padding:12px 0;font-size:.9rem;color:var(--text)}
.ch:active{background:var(--surface-2)}
.passage.gnt{font-size:calc(1.25rem * var(--gk-scale));line-height:1.95}
.passage .vn{font-family:var(--ui);font-size:.62rem;color:var(--gold);
  vertical-align:super;margin-right:3px;opacity:.75}

/* dismiss control on the install banner and the update bar */
.install .x, .update .x{flex:0 0 auto;width:28px;height:28px;border-radius:50%;color:var(--muted);
  font-size:1.15rem;line-height:1;display:flex;align-items:center;justify-content:center}
.install .x:active, .update .x:active{background:var(--surface)}

/* handwriting pad — touch-action:none so a stroke does not scroll the page */
.pad{background:var(--surface);border:1px solid var(--line);border-radius:14px;overflow:hidden}
.pad canvas{display:block;width:100%;height:250px;touch-action:none;cursor:crosshair}
@media (min-height:760px){ .pad canvas{height:300px} }

/* example verse and principal parts on the card back */
.ex{margin-top:12px;padding-top:10px;border-top:1px solid var(--line);text-align:center}
.ex .gk{display:block;font-size:calc(1rem * var(--gk-scale));line-height:1.5;color:var(--text)}
.ex .gk b{color:var(--gold);font-weight:500}
.ex .ref{display:block;font-size:.72rem;color:var(--muted);margin-top:4px}
/* what the highlighted form actually is — the .gk inside has to go back to
   inline, or it inherits the display:block above and breaks the line */
.ex .form{display:block;font-size:.75rem;color:var(--muted);margin-top:6px}
.ex .form .gk{display:inline;font-size:calc(.84rem * var(--gk-scale));color:var(--gold)}
.parts{margin-top:10px;font-size:.8rem;color:var(--muted)}
.parts .gk{font-size:calc(.95rem * var(--gk-scale));color:var(--muted)}
/* in a lookup row it sits under the gloss, tighter and unbordered */
.lk .ex{margin-top:5px;padding-top:0;border-top:none;text-align:left}
.lk .ex .gk{font-size:calc(.92rem * var(--gk-scale));line-height:1.4;color:var(--muted)}
.lk .ex .ref{display:inline;margin-left:6px;font-size:.68rem}
/* not in the lookup list: forty results each gaining a second line turns a
   scannable list into a scroll. The card is where the parse is wanted. */
.lk .ex .form{display:none}

/* play the whole lexical entry */
.mini{font-size:.72rem;padding:2px 7px;border:1px solid var(--line);border-radius:999px;
  color:var(--muted);vertical-align:middle;line-height:1.6}
.mini:active{background:var(--surface-2)}

/* ---------- fill the grid ----------
   The same table markup the Tables tab renders, so a paradigm looks the same
   whether you are reading it or filling it in. Only the empty cells and the
   tray of forms below are new. */
.pgcard{padding:12px 10px}
/* A wide paradigm scrolls inside its own card rather than pushing the page
   sideways — the third declension is five nouns across. */
.pgwrap{overflow-x:auto;-webkit-overflow-scrolling:touch;display:flex;justify-content:center}
/* auto, not the global 100%: a two-column round stretched into two wide bars
   with nothing in them. Sized to its cells, centred, and scrolled inside the
   card when it is wider than the phone. */
.pg{margin:4px 0 2px;width:auto}
.pg th:first-child{white-space:nowrap;padding-right:12px}
.pg td{text-align:center;font-family:var(--gk);font-size:calc(1rem * var(--gk-scale))}
.pgs{min-width:74px;height:38px;border-radius:8px;
  background:var(--surface-2);border:1px dashed var(--line);
  border-bottom:1px dashed var(--line);cursor:pointer;transition:border-color .15s,background .15s}
.pgs.live{border-style:solid;border-color:var(--gold);background:rgba(212,165,55,.10)}
.pgs.on{border-style:solid;border-color:var(--green);background:rgba(88,168,140,.10);cursor:default;
  animation:pgin .22s cubic-bezier(.2,1.4,.4,1) both}
@keyframes pgin{from{transform:scale(.86);opacity:.4}to{transform:none;opacity:1}}

/* which cell is armed, said in words — the grid is small on a phone and a
   gold border alone is not enough to read a slot from */
.pgnow{text-align:center;font-size:.84rem;color:var(--muted);margin:2px 0 10px;min-height:1.2em}
.pgnow b{color:var(--text);font-weight:600}

.tray{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin-bottom:12px}
.tray button{padding:9px 13px;border-radius:11px;border:1px solid var(--line);
  background:var(--surface);font-size:calc(.96rem * var(--gk-scale));line-height:1.2}
.tray button.gone{opacity:0;pointer-events:none;transition:opacity .18s}
.tray button.no{border-color:var(--rust);background:rgba(205,97,82,.13);
  animation:pgno .3s both}
@keyframes pgno{25%{transform:translateX(-5px)}50%{transform:translateX(5px)}
  75%{transform:translateX(-3px)}100%{transform:none}}

/* ---------- read a sentence ----------
   A verse you tap a word in, rather than a verse you tap every word in.
   Smaller than the Read passage because it sits inside a card and has to
   fit on one screen with the question and the answer under it. */
.clause{font-family:var(--gk);font-size:calc(1.1rem * var(--gk-scale));
  line-height:1.95;text-align:center}
.clause .lit{background:rgba(212,165,55,.16);border-radius:4px;padding:2px 4px;font-weight:600}
.passage.clause{margin:0}
.passage.clause w{border-radius:5px;transition:background .15s}
.passage.clause w.right{background:rgba(88,168,140,.22);font-weight:600}
.passage.clause w.wrong{background:rgba(205,97,82,.2)}

/* a card's example reference, which opens Read at that verse */
/* margin:auto rather than text-align: a button is a replaced-ish box and
   does not centre from the parent's text-align the way the span it replaced
   did. */
.ex .ref.link{background:none;border:none;padding:0;color:var(--gold);
  font-size:.72rem;display:block;margin:3px auto 0}
.ex .ref.link:active{opacity:.6}
/* and the verse it lands on, said briefly */
.vn.hit{background:rgba(212,165,55,.28);border-radius:3px;padding:0 3px}

/* ---------- a verse quoted in a lesson ----------
   Marked up as <p class="v" data-ref="Mark 2:12">, and every one is held to
   that verse by tools/check_lessons.py. Set apart from the prose because it
   is the text rather than a claim about the text. */
.read .v, .card.read .v{font-family:var(--gk);
  font-size:calc(1.06rem * var(--gk-scale));line-height:1.75;
  margin:14px 0;padding:10px 0 10px 14px;border-left:2px solid var(--gold-dim);
  color:var(--text)}
.read .v::after{content:attr(data-ref);display:block;font-family:inherit;
  font-size:.72rem;color:var(--muted);margin-top:6px;letter-spacing:.02em}

/* ---------- the Greek keyboard ----------
   Eight columns because the alphabet divides into three rows of eight, so
   the grid is the alphabet rather than a layout that happens to fit. Keys
   are sized off the row rather than fixed, so the whole thing scales to the
   phone instead of overflowing on a small one. */
.gkb{margin-top:12px}
.gkb-out{
  min-height:52px;padding:11px 14px;border-radius:12px;
  background:var(--surface);border:1px solid var(--line);
  font-family:var(--gk);font-size:calc(1.5rem * var(--gk-scale));
  line-height:1.3;word-break:break-word;
}
.gkb-out.empty::after{content:"…";color:var(--muted)}
.gkb-keys{margin-top:10px;display:flex;flex-direction:column;gap:6px}
.gkb-row{display:grid;grid-template-columns:repeat(8,1fr);gap:6px}
.gkb-k{
  padding:11px 0;border-radius:10px;border:1px solid var(--line);
  background:var(--surface-2);color:var(--text);
  font-family:var(--gk);font-size:1.15rem;line-height:1.1;
  transition:transform .06s,background .12s;
}
.gkb-k:active{transform:scale(.94);background:var(--line)}

/* The marks sit above the letters and are always there. Dimmed, not hidden:
   a circumflex greyed out over ε is the keyboard teaching that ε is short,
   which a missing key could not say. */
.gkb-marks .gkb-k{font-size:1.3rem;color:var(--gold);background:var(--surface)}
.gkb-marks .gkb-k.on{background:var(--gold);color:#1a1408}
.gkb-marks .gkb-k.off{opacity:.28;color:var(--muted)}
.gkb-last{grid-template-columns:repeat(4,1fr)}
.gkb-wide{grid-column:span 1}
.gkb-go{background:var(--gold);color:#1a1408;font-weight:650}
.gkb-go:active{background:var(--gold-dim)}
@media (max-width:340px){ .gkb-k{padding:9px 0;font-size:1.05rem} }

/* ---------- drill icons ----------
   The kind of task, drawn, so the screen can be scanned instead of read. The
   tone is the group's, set on the card and inherited by the icon through
   currentColor, which is why one icon set serves six groups and both themes. */
:root{ --violet:#9c86d6; }
.dgroup{margin:22px 0 10px;display:flex;align-items:center;gap:9px}
.dgroup::before{content:"";width:16px;height:2px;border-radius:2px;background:var(--tone)}
.dgroup[data-tone="gold"],.drill-item[data-tone="gold"]{--tone:var(--gold)}
.dgroup[data-tone="blue"],.drill-item[data-tone="blue"]{--tone:var(--blue)}
.dgroup[data-tone="rust"],.drill-item[data-tone="rust"]{--tone:var(--rust)}
.dgroup[data-tone="green"],.drill-item[data-tone="green"]{--tone:var(--green)}
.dgroup[data-tone="violet"],.drill-item[data-tone="violet"]{--tone:var(--violet)}
.dgroup[data-tone="muted"],.drill-item[data-tone="muted"]{--tone:var(--muted)}

.dwell{
  width:38px;height:38px;flex:0 0 38px;border-radius:11px;
  display:flex;align-items:center;justify-content:center;
  color:var(--tone);
  /* the tone at low alpha, so the well tints without a second colour token */
  background:color-mix(in srgb, var(--tone) 14%, transparent);
  border:1px solid color-mix(in srgb, var(--tone) 26%, transparent);
  transition:transform .16s ease, background .16s ease;
}
/* color-mix is recent; a browser without it still gets a legible well */
@supports not (background: color-mix(in srgb, red 10%, transparent)){
  .dwell{background:var(--surface-2);border-color:var(--line)}
}
.dicon{width:21px;height:21px;display:block}
.drill-item{transition:border-color .16s ease, transform .08s ease}
.drill-item:active{transform:scale(.99)}
.drill-item:hover{border-color:color-mix(in srgb, var(--tone) 45%, var(--line))}
.drill-item:hover .dwell{transform:scale(1.06)}
@media (prefers-reduced-motion:reduce){
  .dwell,.drill-item{transition:none}
  .drill-item:hover .dwell{transform:none}
}

/* ---------- a badge landing ----------
   Keyframes only. The ring opens, the emblem comes up to meet it, eight
   sparks go out, and the whole thing leaves on its own. */
.fanfare{
  position:fixed;inset:0;z-index:80;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:16px;
  background:rgba(20,27,43,.72);backdrop-filter:blur(2px);
  animation:fan-in .22s ease both;
}
.fanfare.out{animation:fan-out .3s ease both}
@keyframes fan-in{from{opacity:0}to{opacity:1}}
@keyframes fan-out{to{opacity:0}}

.fan-card{position:relative;width:132px;height:132px;display:grid;place-items:center}
.fan-emblem{
  font-size:3.3rem;line-height:1;
  animation:fan-emblem .62s cubic-bezier(.2,1.5,.4,1) both .06s;
}
@keyframes fan-emblem{
  from{transform:scale(.2) translateY(14px);opacity:0}
  to{transform:none;opacity:1}
}
.fan-ring{
  position:absolute;inset:0;border-radius:50%;
  border:2px solid var(--gold);
  animation:fan-ring .85s cubic-bezier(.2,.7,.3,1) both;
}
@keyframes fan-ring{
  from{transform:scale(.35);opacity:0}
  55%{opacity:.9}
  to{transform:scale(1.28);opacity:0}
}
.fan-spark{
  position:absolute;width:6px;height:6px;border-radius:50%;
  background:var(--gold);
  transform:rotate(var(--a)) translateY(0) scale(0);
  animation:fan-spark .8s cubic-bezier(.25,.8,.3,1) both .1s;
}
@keyframes fan-spark{
  30%{transform:rotate(var(--a)) translateY(-46px) scale(1)}
  to{transform:rotate(var(--a)) translateY(-74px) scale(0);opacity:0}
}
.fan-say{text-align:center;max-width:260px;animation:fan-say .5s ease both .3s}
.fan-say b{display:block;font-size:1.12rem}
.fan-say span{font-size:.85rem;color:var(--muted)}
@keyframes fan-say{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* Nothing travels for anyone who has asked for that. */
@media (prefers-reduced-motion:reduce){
  .fan-emblem,.fan-ring,.fan-spark,.fan-say{animation:fan-in .2s ease both}
  .fan-spark{display:none}
}

/* ---------- rings that fill ----------
   The arc is mounted empty and the real value is set a frame later, so every
   ring sweeps up to its number instead of appearing at it. */
#ringArc,.ring-arc{
  transition:stroke-dashoffset .9s cubic-bezier(.3,.85,.3,1), stroke .4s ease;
}
/* The plan finishing — the one ring event worth marking. Green, once. */
.ring.just-done #ringArc,.ring.just-done .ring-arc{stroke:var(--green)}
.ring.just-done{animation:ring-pop .7s cubic-bezier(.25,1.4,.4,1)}
@keyframes ring-pop{0%{transform:scale(1)}38%{transform:scale(1.055)}100%{transform:scale(1)}}

/* The session summary's ring is the same thing, smaller. */
.summary{display:flex;flex-direction:column;align-items:center}
.ring.sring{width:118px;height:118px;margin:2px auto 10px}
.ring.sring svg{width:118px;height:118px}
.ring.sring .big{font-size:1.42rem}
.ring.sring .mid small{font-size:.7rem}
.ring.sring.clean{--ring-tone:var(--green)}
.summary .gk{font-size:1.5rem;color:var(--gold);display:block;margin-bottom:2px}

@media (prefers-reduced-motion:reduce){
  #ringArc,.ring-arc{transition:none}
  .ring.just-done{animation:none}
}

/* ---------- what a drill is worth today ----------
   The badge carries a number the app already knew and never showed. Dimming
   rather than hiding, because a drill that runs on its cold-start pool is
   still worth having — it just should not look like the one with twelve
   cards due. */
.dbadge{
  /* block, or it flows into the middle of the wrapped description and the
     pill radius turns it into a blob sitting on the text. width:fit-content
     keeps it as wide as its words rather than the whole card. */
  display:block;width:fit-content;max-width:100%;
  /* nowrap, or fit-content inside a min-width:0 flex item collapses to
     min-content and the pill wraps into a two-line blob */
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  margin-top:6px;padding:2px 8px;border-radius:999px;
  font-size:.7rem;line-height:1.5;color:var(--tone);
  background:color-mix(in srgb, var(--tone) 13%, transparent);
  border:1px solid color-mix(in srgb, var(--tone) 30%, transparent);
}
/* Two rules already in this file reach into the badge and had to be beaten,
   which is why these selectors are longer than they look as though they need
   to be. `.lesson-item .t b{display:block}` put the number on a line of its
   own and turned every pill into a two-line blob. `.lesson-item .t span` is
   more specific than `.dbadge`, so it repainted the text muted and the tone
   never showed. */
.lesson-item .t .dbadge{color:var(--tone);font-size:.7rem}
.lesson-item .t .dbadge.cold{color:var(--muted)}
.lesson-item .t .dbadge b{display:inline;font-weight:700;font-size:inherit}
.dbadge.cold{color:var(--muted);background:transparent;border-color:var(--line)}
@supports not (background: color-mix(in srgb, red 10%, transparent)){
  .dbadge{background:var(--surface-2);border-color:var(--line)}
}
.drill-item.not-ready{opacity:.62}
.drill-item.not-ready .dwell{filter:grayscale(.55)}
.dgroup small{
  margin-left:auto;font-size:.72rem;font-weight:500;color:var(--muted);
  border:1px solid var(--line);border-radius:999px;padding:1px 8px;
}

/* ---------- the lessons list ----------
   A chapter stopped halfway used to look exactly like one never opened. */
.lcount{margin:-4px 0 14px;font-size:.8rem;color:var(--muted)}
.lesson-item.resume{--tone:var(--gold);border-color:color-mix(in srgb,var(--gold) 38%,var(--line));
  background:color-mix(in srgb,var(--gold) 7%, var(--surface))}
@supports not (background: color-mix(in srgb, red 10%, transparent)){
  .lesson-item.resume{background:var(--surface-2);border-color:var(--gold-dim)}
}
.lesson-item.resume .t b{color:var(--gold)}
/* how far into the chapter you are, on the card that offers to carry on */
.lbar{display:block;height:4px;margin-top:7px;border-radius:3px;background:var(--line);overflow:hidden}
.lbar i{display:block;height:100%;background:var(--gold);border-radius:3px;
  transition:width .5s cubic-bezier(.3,.85,.3,1)}
/* the size of a chapter, or where you stopped in it */
.lesson-item .t .lmeta{display:block;margin-top:4px;font-size:.7rem;color:var(--muted)}
.lesson-item.here{border-color:color-mix(in srgb,var(--gold) 34%,var(--line))}
.lesson-item.here .t .lmeta{color:var(--gold)}
.lesson-item.done .t .lmeta{color:var(--green)}

/* ---------- the fortnight ahead ----------
   Fourteen bars, scaled to the tallest, so the shape of the coming load is
   readable at a glance. Today is picked out because it is the one you can
   do something about. */
.fcast{display:flex;align-items:flex-end;gap:3px;height:46px;margin:10px 0 7px}
.fcast i{flex:1;background:var(--surface-2);border:1px solid var(--line);
  border-radius:3px 3px 0 0;min-height:3px;transition:height .5s cubic-bezier(.3,.85,.3,1)}
.fcast i.now{background:var(--gold);border-color:var(--gold)}
@media (prefers-reduced-motion:reduce){ .fcast i{transition:none} }
