:root{--sun:#ee9d33;--paper:#f6f7fb;--ink:#111827;--muted:#64748b;--correct:#007d78;--correct-bg:#e0f2f1;--wrong:#c1447e;--wrong-bg:#fce8f1;--card:#fff;--line:#e6e9f0;--accent:#2957a4;--accent2:#5bb3e4;--track:#e6e9f0;--sel:#eaf1fb;
  --radius-xl:26px;--radius-lg:18px;--radius-md:14px;--radius-sm:10px;
  --shadow-sm:0 1px 2px rgba(17,24,39,.05),0 1px 1px rgba(17,24,39,.03);
  --shadow-md:0 10px 26px -14px rgba(17,24,39,.22);
  --shadow-lg:0 24px 48px -20px rgba(17,24,39,.28);
}
body.theme-green{--accent:#2f9e69;--accent2:#5ac48c;--track:#e0efe6;--sel:#e9f7ef;--paper:#f5faf7;--ink:#0f2b1f;--muted:#5d7a6c;--line:#dcebe2}
body.theme-purple{--accent:#7c5cbf;--accent2:#a78bda;--track:#ece5f7;--sel:#f1ecfa;--paper:#f8f7fb;--ink:#241c3d;--muted:#6f6489;--line:#e5ddf2}
body.theme-teal{--accent:#0e8074;--accent2:#4cc9be;--track:#dcf3ef;--sel:#e7f8f5;--paper:#f4faf9;--ink:#0b2b26;--muted:#4f7a73;--line:#d8ede9}
body.theme-amber{--accent:#b4560f;--accent2:#e8994a;--track:#f6e7d8;--sel:#fdf1e4;--paper:#fdf8f3;--ink:#3a1f0c;--muted:#87664c;--line:#f0e0cf}
/* ---------- Dark mode (site-wide toggle, theme.js) ----------
   One override layer stacked on top of whichever body.theme-X is active (or
   none, for the default blue): each theme's own accent/accent2/sun stays
   exactly as authored, only the neutral surfaces go dark. Same recipe
   story.css's night theme already uses for the fox/space-dogs story pages
   (which stay on their own fixed night theme regardless of this toggle -
   see theme.js), generalized here so every other page can opt in/out.

   Selector is `html[data-theme="dark"] body`, not `:root[data-theme="dark"]`:
   theme.js sets data-theme on <html>, but body.theme-green/purple/teal/amber
   above set --paper etc. directly ON <body> -- a custom property set on an
   element by a matching rule always wins there regardless of what the
   parent <html> has, so a plain :root rule never actually reached a themed
   page. Adding the "body" type selector gives this rule one more type-match
   than "body.theme-purple" (0,1,2) vs (0,1,1), which wins on specificity
   alone -- no dependence on which rule happens to come first in the file. */
html[data-theme="dark"] body{
  --paper:#0e1626;--card:#182338;--ink:#eaf0fb;--muted:#9db0d0;--line:#2b3a58;
  --sel:#1f2c47;--track:#22304c;
  --correct:#3fcfc0;--correct-bg:#0f322e;--wrong:#ff8ec0;--wrong-bg:#3a1730;
  color-scheme:dark;
}
*{box-sizing:border-box}
body{margin:0;background:var(--paper);color:var(--ink);font-family:'Be Vietnam Pro',system-ui,sans-serif;line-height:1.6;-webkit-font-smoothing:antialiased}
.wrap{max-width:820px;margin:0 auto;padding:24px 18px 60px}
a{color:var(--accent)}
header{background:linear-gradient(150deg,var(--accent2),var(--accent) 82%);color:#fff;border-radius:var(--radius-xl);padding:28px 28px 24px;position:relative;overflow:hidden;box-shadow:var(--shadow-lg)}
header .eyebrow{font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;opacity:.88;font-weight:800}
header h1{font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-weight:800;margin:.2em 0 .12em;font-size:1.9rem;line-height:1.15;letter-spacing:-.01em}
header p{margin:0;opacity:.92;font-size:.94rem}
.wave{position:absolute;left:0;right:0;bottom:-2px;height:22px;display:block;opacity:.7}
.namebar{display:flex;gap:10px;align-items:center;margin:18px 0 4px;flex-wrap:wrap}
.namebar label{font-weight:700;font-size:.94rem}
.namebar input{flex:1;min-width:200px;border:1.5px solid var(--line);border-radius:var(--radius-sm);padding:11px 13px;font-family:inherit;font-size:1rem;color:var(--ink)}
.namebar input:focus{outline:none;border-color:var(--accent2);box-shadow:0 0 0 3px color-mix(in srgb, var(--accent2) 25%, transparent)}
.namebar input[readonly]{background:var(--sel);cursor:default}
.acct-note{font-size:.85rem;color:var(--muted);white-space:nowrap}
.acct-note a{color:var(--accent);font-weight:700}
.toplink{font-size:.88rem;font-weight:700}
.progress-sticky{position:sticky;top:0;z-index:20;background:color-mix(in srgb, var(--paper) 92%, transparent);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);padding:10px 0 6px;margin:8px 0 0}
.bar-label{font-size:.84rem;color:var(--muted);font-weight:700;text-align:center;margin:0 0 6px}
.bar-track{height:10px;border-radius:999px;background:var(--track);overflow:hidden;border:1px solid var(--line)}
.bar-fill{height:100%;width:0;border-radius:999px;background:linear-gradient(90deg,var(--accent2),var(--accent));transition:width .5s cubic-bezier(.2,.8,.2,1)}
details.passage{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-lg);margin:20px 0;overflow:hidden;box-shadow:var(--shadow-sm)}
details.passage summary{cursor:pointer;padding:14px 18px;font-weight:700;color:var(--accent);list-style:none;display:flex;align-items:center;gap:8px;user-select:none}
details.passage summary::-webkit-details-marker{display:none}
/* No ::before icon here: 76 of the 85 passage titles already start with 📖 in
   the page itself, and the two together read "📖 📖 Đọc bài". The remaining
   nine were given the emoji instead, so every title carries its own. */
details.passage[open] summary{border-bottom:1px solid var(--line)}
.passage-body{padding:6px 20px 18px;font-size:.97rem}
.passage-body p{margin:.7em 0}
.passage-body strong{color:var(--accent)}

/* --- Reading section: passage beside its questions ------------------------
   A comprehension question is unanswerable without the passage, and the
   passage used to sit once at the top of the page -- so answering question 4
   meant scrolling back past questions 1-3 to re-read one sentence, then back
   down. Now the passage travels with the questions that need it.

   Wide screens get two columns and the passage sticks. The block is allowed to
   grow past .wrap's 820px, because splitting 820 in two leaves neither column
   readable; it is centred on the wrap so it stays aligned with the page.
   Narrow screens keep one column, and the passage becomes a sticky bar --
   collapsed it costs one line and follows you down; tap to read, tap to close.
   Both cap the passage's height and scroll inside it, so a long story can
   never push the questions off the screen. */
.split-passage details.passage{margin:0}
.split-questions>.q:first-child{margin-top:0}

@media (min-width:1180px){
  .section-split{
    display:grid;
    grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
    gap:20px;
    align-items:start;
    width:min(1120px,calc(100vw - 40px));
    margin-left:calc(50% - min(1120px,calc(100vw - 40px)) / 2);
  }
  .split-passage{position:sticky;top:calc(var(--sticky-top,56px) + 14px)}
  /* The height cap lives on .passage-body, not on the <details> itself.
     Chromium's native <details> does not let its content participate in
     flex-shrink -- max-height + display:flex on details.passage clips the
     box correctly, but a child that grows past it (like the "Xem bản dịch"
     translation nested inside) just gets cut off with no scrollbar, because
     .passage-body renders at its full content height instead of shrinking
     to the available space. Capping .passage-body's own height sidesteps
     that: a plain div's overflow:auto works exactly as expected. 54px is
     the summary row's rendered height (14px vertical padding + one line). */
  .split-passage details.passage{overflow:hidden;max-height:calc(100vh - var(--sticky-top,56px) - 34px)}
  .split-passage .passage-body{overflow:auto;overscroll-behavior:contain;max-height:calc(100vh - var(--sticky-top,56px) - 34px - 54px)}
}

@media (max-width:1179.98px){
  /* Closed, it is a thin bar that sticks under the progress bar and follows the
     questions down. Opened, it lifts out of the flow and floats over them --
     because a sticky box stops sticking once it reaches the bottom of its
     section, which on a phone left the story open with its own header (the
     thing you tap to close it) pushed off the top of the screen. Floating it
     keeps the header reachable wherever you opened it from. The bar's space is
     reserved by min-height so nothing jumps when it opens. */
  .split-passage{position:sticky;top:calc(var(--sticky-top,56px) + 4px);z-index:15;margin:14px 0;min-height:56px}
  .split-passage details.passage[open]{
    position:fixed;z-index:30;
    top:calc(var(--sticky-top,56px) + 8px);
    left:0;right:0;margin:0 auto;
    width:min(760px,calc(100vw - 20px));
    overflow:hidden;
    max-height:calc(100vh - var(--sticky-top,56px) - 20px);
    box-shadow:0 18px 44px rgba(15,23,42,.28)
  }
  .split-passage details.passage[open] > summary::after{content:"✕";margin-left:auto;color:var(--muted);font-size:1.05rem}
  /* Same reason as the desktop rule above: cap .passage-body itself rather
     than relying on <details> to flex-shrink it. */
  .split-passage details.passage[open] .passage-body{overflow:auto;overscroll-behavior:contain;max-height:calc(100vh - var(--sticky-top,56px) - 20px - 54px)}
}
.section-head{display:flex;align-items:baseline;gap:10px;margin:36px 0 10px}
.section-head .num{font-family:'Plus Jakarta Sans',system-ui,sans-serif;background:var(--sun);color:#5a3a00;width:32px;height:32px;border-radius:50%;display:grid;place-items:center;font-size:1rem;font-weight:800;flex:none}
.section-head h2{font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-weight:800;margin:0;font-size:1.25rem;letter-spacing:-.01em}
.section-head span.hint{color:var(--muted);font-size:.86rem;margin-left:auto}
.q{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-lg);padding:17px 19px;margin:12px 0;box-shadow:var(--shadow-sm)}
.q.flag{border-color:var(--wrong)}
.qtext{font-weight:700;margin-bottom:12px}
.qtext b{color:var(--accent)}
.emoji-q{display:inline-block;font-size:2.6rem;line-height:1;vertical-align:middle;margin-right:10px}
.q-note{font-weight:700;font-size:.82rem;color:var(--accent);background:var(--sel);border-radius:999px;padding:2px 9px;margin-left:6px;white-space:nowrap}
.spell-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.spell-pre{font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-weight:800;font-size:1.15rem;color:var(--accent);background:var(--sel);border-radius:var(--radius-sm);padding:9px 12px;letter-spacing:.04em}
.spell-input{flex:1;min-width:150px;max-width:280px;border:1.5px solid var(--line);border-radius:var(--radius-sm);padding:10px 13px;font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-size:1.1rem;font-weight:700;letter-spacing:.12em;color:var(--ink);background:var(--card)}
.spell-input:focus{outline:none;border-color:var(--accent2);box-shadow:0 0 0 3px color-mix(in srgb, var(--accent2) 25%, transparent)}
.spell-input.correct{border-color:var(--correct);background:var(--correct-bg);color:var(--correct)}
.spell-input.wrong{border-color:var(--wrong);background:var(--wrong-bg);color:var(--wrong)}
.spell-answer{font-weight:800;color:var(--correct);background:var(--correct-bg);border-radius:var(--radius-sm);padding:9px 12px;font-size:1.02rem}
.qnum{display:inline-block;min-width:1.7em;color:var(--sun);font-weight:800;font-family:'Plus Jakarta Sans',system-ui,sans-serif}
.speak{cursor:pointer;border:none;background:var(--sel);color:var(--accent);border-radius:8px;padding:2px 8px;font-size:.9rem;font-weight:800;margin-left:6px}
.opts{display:grid;gap:8px}
.opt{display:flex;align-items:center;gap:10px;padding:11px 14px;border:1.5px solid var(--line);border-radius:var(--radius-sm);cursor:pointer;transition:.15s;background:var(--card);font-size:.96rem}
.opt:hover{border-color:var(--accent2)}
.opt.selected{border-color:var(--accent);background:var(--sel)}
.opt .marker{width:24px;height:24px;border-radius:50%;border:1.5px solid var(--line);flex:none;display:grid;place-items:center;font-weight:800;color:var(--muted);font-size:.85rem;font-family:'Plus Jakarta Sans',system-ui,sans-serif}
.opt.selected .marker{border-color:var(--accent);background:var(--accent);color:#fff}
.opt.correct{border-color:var(--correct);background:var(--correct-bg)}
.opt.correct .marker{border-color:var(--correct);background:var(--correct);color:#fff}
.opt.wrong{border-color:var(--wrong);background:var(--wrong-bg)}
.opt.wrong .marker{border-color:var(--wrong);background:var(--wrong);color:#fff}
.opt.locked{cursor:default;pointer-events:none}
/* One-off PIN prompt (quiz.js askPin). Shown after submitting when the typed
   name matches a real student and this device hasn't proved it yet. */
.pin-ask{position:fixed;inset:0;z-index:99;background:rgba(17,24,39,.55);display:grid;place-items:center;padding:20px}
.pin-ask-box{background:var(--card);border-radius:var(--radius-lg);padding:22px 24px;max-width:380px;width:100%;box-shadow:0 24px 60px -20px rgba(17,24,39,.6)}
.pin-ask-box h3{font-family:'Plus Jakarta Sans',system-ui,sans-serif;margin:0 0 6px;font-size:1.1rem;color:var(--ink)}
.pin-ask-box h3 b{color:var(--accent)}
.pin-ask-box p{margin:0 0 12px;color:var(--muted);font-size:.92rem}
.pin-ask-input{width:100%;border:1.5px solid var(--line);border-radius:var(--radius-sm);padding:12px;font-family:inherit;font-size:1.3rem;letter-spacing:.4em;text-align:center;color:var(--ink)}
.pin-ask-input:focus{outline:none;border-color:var(--accent2);box-shadow:0 0 0 3px color-mix(in srgb, var(--accent2) 25%, transparent)}
.pin-ask-err{color:var(--wrong);font-weight:700;font-size:.88rem;margin:8px 0 0}
.pin-ask-btns{display:flex;gap:10px;margin-top:14px}
.pin-ask-btns button{flex:1;border-radius:var(--radius-sm);padding:11px;font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-weight:800;font-size:.95rem;cursor:pointer}
.pin-ask-skip{border:1.5px solid var(--line);background:var(--card);color:var(--muted)}
.pin-ask-ok{border:none;background:var(--accent);color:#fff}
.pin-ask-note{margin:12px 0 0!important;font-size:.84rem!important;line-height:1.45}
/* Right/wrong is carried by the ✓/✗ glyph, not by colour alone -- colour is
   unreliable for a red-green deficiency, in greyscale, or in bright sun.
   .why is the per-question explanation: it sits to the right of the answer on
   a wide screen and wraps onto its own line on a phone, which is why .opt
   wraps rather than needing a media query. */
.opt{flex-wrap:wrap}
.opt .opt-text{flex:0 1 auto}
.opt .glyph{flex:none;font-weight:800;font-size:1.05rem;line-height:1}
.opt.correct .glyph{color:var(--correct)}
.opt.wrong .glyph{color:var(--wrong)}
.opt .why{flex:1 1 250px;min-width:0;font-size:.85rem;font-weight:500;line-height:1.45;
  color:var(--ink);opacity:.9;border-left:2px solid var(--correct);padding-left:10px}
.why-block{margin-top:9px;font-size:.85rem;font-weight:500;line-height:1.45;
  color:var(--ink);opacity:.9;border-left:2px solid var(--correct);padding-left:10px}
.feedback{margin-top:10px;font-size:.9rem;font-weight:700;display:none}
.feedback.show{display:block}
.feedback.ok{color:var(--correct)}
.feedback.no{color:var(--wrong)}
textarea{width:100%;border:1.5px solid var(--line);border-radius:var(--radius-sm);padding:11px;font-family:inherit;font-size:.97rem;resize:vertical;min-height:70px;color:var(--ink)}
textarea:focus{outline:none;border-color:var(--accent2);box-shadow:0 0 0 3px color-mix(in srgb, var(--accent2) 25%, transparent)}
.model-answer{display:none;margin-top:10px;padding:11px 13px;border-radius:var(--radius-sm);background:var(--correct-bg);border:1px solid var(--correct);font-size:.92rem}
.model-answer.show{display:block}
.model-answer b{color:var(--correct)}
.actions{margin-top:28px;display:flex;gap:12px;flex-wrap:wrap;align-items:center}
.btn{border:none;border-radius:var(--radius-sm);padding:13px 22px;font-weight:700;cursor:pointer;font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-size:1rem;transition:filter .15s,transform .15s}
.btn-primary{background:linear-gradient(150deg,#ffb84d,var(--sun));color:#5a3a00;box-shadow:0 10px 22px -10px rgba(238,157,51,.65)}
.btn-primary:hover{filter:brightness(1.04);transform:translateY(-1px)}
.btn-ghost{background:var(--sel);color:var(--accent)}
.status{font-size:.9rem;color:var(--muted);font-weight:700}
.result{display:none;background:var(--card);border:1px solid var(--line);border-radius:var(--radius-xl);padding:26px;margin:26px 0;text-align:center;box-shadow:var(--shadow-lg)}
.result.show{display:block}
.ring{--p:0;width:128px;height:128px;border-radius:50%;margin:0 auto 14px;display:grid;place-items:center;background:conic-gradient(var(--accent) calc(var(--p)*1%), var(--track) 0)}
.ring .inner{width:102px;height:102px;border-radius:50%;background:var(--card);display:grid;place-items:center;font-family:'Plus Jakarta Sans',system-ui,sans-serif;box-shadow:inset 0 1px 3px rgba(17,24,39,.08)}
.ring .pct{font-size:1.85rem;font-weight:800;line-height:1;color:var(--accent)}
.ring .sub{font-size:.8rem;color:var(--muted);font-weight:700}
.result h3{font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-weight:800;margin:.2em 0;font-size:1.4rem}
.result .note{color:var(--muted)}
.result .saved{margin-top:10px;font-size:.9rem;font-weight:700}
.result .saved.ok{color:var(--correct)}
.result .saved.err{color:var(--wrong)}
.mistakes{text-align:left;margin-top:16px}
.mistakes h4{font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-weight:800;margin:0 0 8px;color:var(--wrong)}
.mistakes ul{margin:0;padding-left:0;list-style:none;display:grid;gap:8px}
.mistakes li{background:var(--wrong-bg);border:1px solid #f6c7d1;border-radius:var(--radius-sm);padding:10px 12px;font-size:.92rem}
.mistakes li .qn{font-weight:800;color:var(--wrong)}
.mistakes li .yours{color:var(--wrong)}
.mistakes li .right{color:var(--correct);font-weight:700}
.allgood{background:var(--correct-bg);border:1px solid var(--correct);border-radius:var(--radius-sm);padding:12px;font-weight:700;color:var(--correct);text-align:center;margin-top:14px}
@media (max-width:520px){header h1{font-size:1.55rem}}
.wordlist-part-head{display:flex;align-items:center;gap:10px;margin:28px 0 12px}
.wordlist-part-head:first-child{margin-top:6px}
.wordlist-part-head .badge{background:linear-gradient(150deg,var(--accent2),var(--accent));color:#fff;font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-weight:700;border-radius:999px;padding:7px 18px;font-size:.88rem;flex:none}
.wordlist-part-head .cnt{color:var(--muted);font-size:.85rem;font-weight:700}
.wordlist-list{display:flex;flex-direction:column;gap:10px}
.wordlist-item{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-md);padding:14px 18px;box-shadow:var(--shadow-sm)}
.wl-row1{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.wl-num{color:var(--muted);font-weight:700;font-size:.85rem;min-width:1.6em}
.wl-word{font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-size:1.1rem;color:var(--accent);font-weight:700}
.wl-pos{font-size:.72rem;color:var(--muted);text-transform:uppercase;border:1px solid var(--line);border-radius:6px;padding:2px 7px;font-weight:700}
.wl-row1 .spk{border:none;background:var(--sel);color:var(--accent);border-radius:8px;padding:4px 9px;font-size:.85rem;cursor:pointer;font-weight:800}
.wl-vi{font-weight:800;color:#fff;background:linear-gradient(150deg,var(--accent2),var(--accent));font-size:.95rem;padding:5px 13px;border-radius:9px;line-height:1.3}
.wl-emoji{font-size:1.35rem;line-height:1}
.wl-def{color:var(--muted);font-size:.87rem;margin-top:8px}
.wl-ex{font-style:italic;font-size:.92rem;margin-top:6px;color:var(--ink)}
.wl-exvi{color:var(--muted);font-size:.87rem;margin-top:2px}

/* Matching game */
.match-toolbar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;margin-top:18px}
.match-tabs{display:flex;gap:8px}
.match-tab{border:1.5px solid var(--line);background:var(--card);border-radius:var(--radius-sm);padding:8px 16px;font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-weight:700;font-size:.9rem;color:var(--muted);cursor:pointer}
.match-tab.active{background:linear-gradient(150deg,var(--accent2),var(--accent));color:#fff;border-color:var(--accent)}
.match-stats{font-weight:700;color:var(--muted);font-size:.92rem}
.match-instructions{color:var(--muted);font-size:.9rem;margin:10px 0}
.match-grid{display:flex;gap:16px;margin-top:8px}
.match-col{flex:1;display:flex;flex-direction:column;gap:9px;min-width:0}
.match-card{border:1.5px solid var(--line);background:var(--card);border-radius:var(--radius-sm);padding:13px 14px;font-family:inherit;font-size:.95rem;font-weight:700;color:var(--ink);cursor:pointer;text-align:left;transition:.12s;word-break:break-word;box-shadow:var(--shadow-sm)}
.match-card:hover:not(:disabled){border-color:var(--accent2)}
.match-card.selected{border-color:var(--accent);background:var(--sel)}
.match-card.matched{background:var(--correct-bg);border-color:var(--correct);color:var(--correct);opacity:.75;cursor:default}
.match-card.wrong{background:var(--wrong-bg);border-color:var(--wrong);color:var(--wrong)}
.match-card.match-vi{font-weight:600}
.match-card.match-icon{text-align:center;padding:10px 12px}
.match-emoji{font-size:2.1rem;line-height:1.25;display:inline-block}
.match-card.match-word{font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-weight:800;text-align:center}
.match-done{margin-top:16px}
.match-result{background:var(--correct-bg);border:1.5px solid var(--correct);border-radius:var(--radius-md);padding:16px;text-align:center;font-weight:700;color:var(--ink)}
.match-result .btn{margin-top:10px}
@media (max-width:520px){.match-grid{gap:10px}.match-card{padding:11px 10px;font-size:.87rem}}
