/* Study Hub - one stylesheet. Light by default; dark = <html data-theme="dark"> (set in index.html from
   the saved choice: system | light | dark). */
:root {
  --bg: #f5f3ee;
  --surface: #ffffff;
  --surface-2: #faf9f6;
  --surface-3: #f0ede6;
  --border: #e6e2d9;
  --border-strong: #d4cec2;
  --text: #1e2227;
  --text-2: #4a515b;
  --muted: #7a818c;
  --primary: #1e2227;
  --primary-hover: #353b43;
  --primary-text: #ffffff;
  --accent: #3b5bdb;
  --focus: rgba(59, 91, 219, 0.35);

  --reading: #2f6fde;   --reading-bg: #eaf1fd;
  --listening: #7c4ddb; --listening-bg: #f1ebfc;
  --writing: #c66a05;   --writing-bg: #fdf1e1;
  --speaking: #0c8f61;  --speaking-bg: #e3f5ed;

  --ok: #1d8f4e;   --ok-bg: #e6f5eb;
  --bad: #cc3d3d;  --bad-bg: #fcebeb;
  --warn: #a86a0c; --warn-bg: #fdf3df;
  --claude: #b85a36; --claude-bg: #fbefe9;
  --mark: #fff0a6; --mark-strong: #ffe066;

  --radius: 14px;
  --radius-sm: 9px;
  --shadow: 0 1px 2px rgba(30, 34, 39, 0.04), 0 6px 20px rgba(30, 34, 39, 0.05);
  --shadow-lg: 0 10px 40px rgba(30, 34, 39, 0.18);
  --font: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-display: "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
  --font-serif: Georgia, Cambria, "Times New Roman", serif;
  --mono: "Cascadia Mono", Consolas, "Courier New", monospace;
  --lv1: #e8743b; --lv2: #d9a21b; --lv3: #9bab2a; --lv4: #2f9e62; --lv5: #1f8fa8;

  /* To mau cu phap Java (khoi code trong de quiz) */
  --syn-kw: #a626a4; --syn-type: #0184bc; --syn-str: #1d7d4e; --syn-num: #b26100;
  --syn-lit: #a626a4; --syn-cmt: #8a919b; --syn-fn: #4055c8; --syn-ann: #986801;

  /* Khoá Excel: lưới ô giống Excel (views/excel/sheet.js) */
  --xl: #217346; --xl-bg: #e3f1e8; --xl-grid: #d9dcd6; --xl-head: #f2f3f0; --xl-mark: #fff1bf;
  color-scheme: light;
}

:root[data-theme="dark"] {
  --bg: #141619;
  --surface: #1c1f23;
  --surface-2: #212428;
  --surface-3: #272b30;
  --border: #2e3339;
  --border-strong: #3b4148;
  --text: #e9ebee;
  --text-2: #b9bfc7;
  --muted: #8a919b;
  --primary: #e9ebee;
  --primary-hover: #ffffff;
  --primary-text: #141619;
  --accent: #8ea6ff;
  --focus: rgba(142, 166, 255, 0.4);
  --reading: #74a4ff;   --reading-bg: rgba(116, 164, 255, 0.13);
  --listening: #b294ff; --listening-bg: rgba(178, 148, 255, 0.13);
  --writing: #f0a54a;   --writing-bg: rgba(240, 165, 74, 0.13);
  --speaking: #3fcf98;  --speaking-bg: rgba(63, 207, 152, 0.12);
  --ok: #4fd08a;   --ok-bg: rgba(79, 208, 138, 0.13);
  --bad: #ff7b7b;  --bad-bg: rgba(255, 123, 123, 0.13);
  --warn: #f2c14e; --warn-bg: rgba(242, 193, 78, 0.13);
  --claude: #eb8f69; --claude-bg: rgba(235, 143, 105, 0.13);
  --mark: rgba(255, 214, 10, 0.28); --mark-strong: rgba(255, 214, 10, 0.5);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 6px 20px rgba(0, 0, 0, 0.25);
  --shadow-lg: 0 10px 40px rgba(0, 0, 0, 0.5);
  --lv1: #ff9b6b; --lv2: #f2c14e; --lv3: #c8d86a; --lv4: #7fd6a0; --lv5: #4fc3d9;

  /* To mau cu phap Java - ban nen toi */
  --syn-kw: #d98ce8; --syn-type: #6cc6f0; --syn-str: #8fd694; --syn-num: #f0b36b;
  --syn-lit: #d98ce8; --syn-cmt: #7b828c; --syn-fn: #9db4ff; --syn-ann: #e8c07d;

  --xl: #52c68a; --xl-bg: rgba(82, 198, 138, 0.14); --xl-grid: #353a40; --xl-head: #24282d;
  --xl-mark: rgba(255, 214, 10, 0.17);
  color-scheme: dark;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--bg);
  color: var(--text);
  font: 15px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 { font-family: var(--font-display); margin: 0; line-height: 1.25; letter-spacing: -0.01em; }
h1 { font-size: 28px; font-weight: 650; }
h2 { font-size: 19px; font-weight: 650; }
h3 { font-size: 16px; font-weight: 650; }
p { margin: 0; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
button, input, select, textarea { font: inherit; color: inherit; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 6px; }
svg.icon { width: 18px; height: 18px; flex: none; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
svg.icon.fill { fill: currentColor; }
::selection { background: var(--mark-strong); }

/* ------------------------------------------------------------ shell */
.shell { display: grid; grid-template-columns: 236px 1fr; height: 100vh; }
.shell.focus { grid-template-columns: 1fr; }
.shell.focus .sidebar { display: none; }
.sidebar {
  display: flex; flex-direction: column; gap: 18px;
  padding: 20px 14px; border-right: 1px solid var(--border);
  background: var(--surface-2); overflow-y: auto;
}
.brand { display: flex; align-items: center; gap: 11px; padding: 4px 8px; color: var(--text); }
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center;
  background: linear-gradient(135deg, #2f6fde, #7c4ddb 55%, #c15f3c); color: #fff;
  font: 700 20px/1 var(--font-display);
}
.brand-text { display: flex; flex-direction: column; line-height: 1.2; }
.brand-text strong { font-size: 16px; }
.brand-text small { color: var(--muted); font-size: 12px; }
.nav { display: flex; flex-direction: column; gap: 2px; }
.nav a {
  display: flex; align-items: center; gap: 11px; padding: 9px 12px; border-radius: 10px;
  color: var(--text-2); font-weight: 500;
}
.nav a:hover { background: var(--surface-3); text-decoration: none; color: var(--text); }
.nav a.active { background: var(--surface); color: var(--text); box-shadow: var(--shadow); }
.nav .badge {
  margin-left: auto; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px;
  background: var(--claude); color: #fff; font-size: 12px; font-weight: 600; display: grid; place-items: center;
}
.sidebar-foot { margin-top: auto; padding: 12px; border-radius: 12px; background: var(--surface); border: 1px solid var(--border); font-size: 13px; color: var(--text-2); }
.sidebar-foot .big { font: 650 22px/1.1 var(--font-display); color: var(--text); }

.main { overflow-y: auto; padding: 34px 44px 60px; }
.shell.focus .main { padding: 0; overflow: hidden; }
.page { max-width: 1140px; margin: 0 auto; }
.page-head { display: flex; align-items: flex-end; gap: 20px; margin-bottom: 26px; flex-wrap: wrap; }
.page-head .sub { color: var(--text-2); margin-top: 6px; }
.page-head .actions { margin-left: auto; display: flex; gap: 8px; }

/* ------------------------------------------------------------ utilities */
.row { display: flex; align-items: center; gap: 10px; }
.row.wrap { flex-wrap: wrap; }
.row.top { align-items: flex-start; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.stack.lg { gap: 20px; }
.stack.sm { gap: 6px; }
.spacer { flex: 1; }
.muted { color: var(--muted); }
.soft { color: var(--text-2); }
.small { font-size: 13px; }
.tiny { font-size: 12px; }
.mono { font-family: var(--mono); }
.nowrap { white-space: nowrap; }
.hidden { display: none !important; }
.center { text-align: center; }
.pre { white-space: pre-wrap; }
.divider { height: 1px; background: var(--border); margin: 6px 0; }
.grid-main { display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: 24px; align-items: start; }
.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
@media (max-width: 1180px) {
  .grid-main { grid-template-columns: 1fr; }
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ------------------------------------------------------------ cards */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }
.card-pad { padding: 20px 22px; }
.card-head { display: flex; align-items: center; gap: 10px; padding: 16px 20px; border-bottom: 1px solid var(--border); }
.card-head h2, .card-head h3 { font-size: 16px; }
.card-body { padding: 16px 20px; }
/* display:flex + gap để icon() đặt trước chữ không bị dính sát (khoá Java dùng kiểu này).
   VSTEP chỉ truyền chữ, và một text node trong flex container thành anonymous flex item
   nên bố cục cũ không đổi. */
.section-title { display: flex; align-items: center; gap: 8px; font: 650 13px/1 var(--font); text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin: 26px 0 12px; }
.section-title:first-child { margin-top: 0; }

.stat { padding: 16px 18px; }
.stat .label { color: var(--muted); font-size: 13px; display: flex; align-items: center; gap: 6px; }
.stat .value { font: 650 28px/1.15 var(--font-display); margin-top: 6px; }
.stat .value small { font-size: 15px; color: var(--muted); font-weight: 500; }
.stat .sub { color: var(--text-2); font-size: 13px; margin-top: 3px; }
/* Ô số của Tiến độ Java (.stat > .big) và tổng kết Kết quả quiz Java (.score-tiles): .big trước đây không có
   kiểu nào ở hai trang này nên số chính hiện bằng chữ thường 15px (06/10/2026). */
.stat .big { font: 650 24px/1.2 var(--font-display); margin-top: 4px; }
.score-tiles { display: flex; gap: 28px; flex-wrap: wrap; align-items: flex-start; }
.score-tiles .big { font: 650 24px/1.2 var(--font-display); margin: 2px 0 4px; }
.score-tiles .tile-label { display: flex; align-items: center; gap: 6px; }
.topics-more { margin-top: 8px; }

.empty { padding: 34px 20px; text-align: center; color: var(--text-2); }
.empty .icon { width: 34px; height: 34px; color: var(--muted); margin-bottom: 8px; }

/* ------------------------------------------------------------ buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 38px; padding: 0 16px; border-radius: 10px; border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--text); font-weight: 550; cursor: pointer; white-space: nowrap;
  transition: background 0.12s, border-color 0.12s, transform 0.05s;
}
.btn:hover { background: var(--surface-3); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }
.btn-primary { background: var(--primary); border-color: var(--primary); color: var(--primary-text); }
.btn-primary:hover { background: var(--primary-hover); }
/* Nút chính bị khoá: nền nhạt + chữ mờ. Trước đây chỉ opacity 0.45 nên thành một khối xám chữ đen, trông như
   hỏng chứ không phải "chưa bấm được" (nút Nộp bài của Speaking, 06/10/2026). */
.btn-primary:disabled { opacity: 1; background: var(--surface-3); border-color: var(--border); color: var(--muted); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-2); }
.btn-ghost:hover { background: var(--surface-3); color: var(--text); }
.btn-danger { background: var(--bad); border-color: var(--bad); color: #fff; }
.btn-danger:hover { filter: brightness(1.05); background: var(--bad); }
.btn-rec { background: #d93a3a; border-color: #d93a3a; color: #fff; }
.btn-rec:hover { background: #c22f2f; }
.btn-sm { height: 32px; padding: 0 12px; font-size: 13px; border-radius: 8px; }
.btn-lg { height: 46px; padding: 0 22px; font-size: 16px; border-radius: 12px; }
.btn-icon { width: 38px; padding: 0; }
.btn-sm.btn-icon { width: 32px; }
.btn .icon { width: 17px; height: 17px; }

/* ------------------------------------------------------------ chips & badges */
.chip {
  display: inline-flex; align-items: center; gap: 5px; height: 24px; padding: 0 9px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600; background: var(--surface-3); color: var(--text-2); white-space: nowrap;
}
.chip .icon { width: 14px; height: 14px; }
.chip-ok { background: var(--ok-bg); color: var(--ok); }
.chip-bad { background: var(--bad-bg); color: var(--bad); }
.chip-warn { background: var(--warn-bg); color: var(--warn); }
.chip-claude { background: var(--claude-bg); color: var(--claude); }
.chip-info { background: var(--reading-bg); color: var(--reading); }
.level { display: inline-grid; place-items: center; height: 22px; padding: 0 7px; border-radius: 6px; font: 700 11.5px/1 var(--font); border: 1px solid var(--border-strong); color: var(--text-2); }

.skill-icon { width: 40px; height: 40px; border-radius: 11px; display: grid; place-items: center; flex: none; }
.skill-icon .icon { width: 20px; height: 20px; }
.skill-reading { color: var(--reading); background: var(--reading-bg); }
.skill-listening { color: var(--listening); background: var(--listening-bg); }
.skill-writing { color: var(--writing); background: var(--writing-bg); }
.skill-speaking { color: var(--speaking); background: var(--speaking-bg); }
.skill-tag { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; font-weight: 650; }
.skill-tag.reading { color: var(--reading); }
.skill-tag.listening { color: var(--listening); }
.skill-tag.writing { color: var(--writing); }
.skill-tag.speaking { color: var(--speaking); }

/* ------------------------------------------------------------ task rows (Java lộ trình, Excel bài học) */
.task-list { display: flex; flex-direction: column; gap: 10px; }
.task {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 16px; align-items: center;
  padding: 16px 18px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); transition: border-color 0.12s;
}
.task:hover { border-color: var(--border-strong); }
.task-kicker { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--muted); flex-wrap: wrap; }
.task-title { font-weight: 650; font-size: 16px; margin: 2px 0 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Khoá Java đặt icon() ngay trong tiêu đề; .task-title không phải flex nên icon dính sát
   chữ (thấy ngày 24/09/2026). Biến thể này giữ nguyên kiểu cũ của VSTEP, chỉ thêm khoảng
   cách — và để phần chữ tự cắt bằng ellipsis thay vì cắt cả icon. */
.task-title.has-icon { display: flex; align-items: center; gap: 9px; white-space: normal; }
.task-title.has-icon > .icon { flex: 0 0 auto; color: var(--muted); }
.task-title.has-icon > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.task-actions { display: flex; align-items: center; gap: 6px; }
.menu {
  position: absolute; right: 0; top: calc(100% + 4px); min-width: 200px; z-index: 20; padding: 6px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow-lg);
}
.menu button { display: flex; width: 100%; align-items: center; gap: 9px; padding: 8px 10px; border: 0; border-radius: 8px; background: none; cursor: pointer; text-align: left; }
.menu button:hover { background: var(--surface-3); }

.banner {
  display: flex; align-items: center; gap: 14px; padding: 14px 18px; border-radius: var(--radius);
  background: var(--claude-bg); color: var(--text); border: 1px solid transparent; margin-bottom: 10px;
}
.banner .icon { color: var(--claude); width: 22px; height: 22px; }
.banner.warn { background: var(--warn-bg); }
.banner.warn .icon { color: var(--warn); }
.banner.info { background: var(--reading-bg); }
.banner.info .icon { color: var(--reading); }
.banner.ok { background: var(--ok-bg); }
.banner.ok .icon { color: var(--ok); }
.banner .grow { flex: 1; min-width: 0; }

.meter { height: 8px; border-radius: 99px; background: var(--surface-3); overflow: hidden; }
.meter > span { display: block; height: 100%; border-radius: 99px; background: var(--text); transition: width 0.3s; }
.meter.reading > span { background: var(--reading); }
.meter.listening > span { background: var(--listening); }
.meter.writing > span { background: var(--writing); }
.meter.speaking > span { background: var(--speaking); }
.meter.ok > span { background: var(--ok); }
.meter.warn > span { background: var(--warn); }

/* ------------------------------------------------------------ library & history */
.tabs { display: inline-flex; gap: 4px; padding: 4px; background: var(--surface-3); border-radius: 12px; }
.tabs button { border: 0; background: none; padding: 7px 14px; border-radius: 9px; cursor: pointer; font-weight: 550; color: var(--text-2); }
.tabs button.active { background: var(--surface); color: var(--text); box-shadow: var(--shadow); }
.ex-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
.ex-card { display: flex; flex-direction: column; gap: 10px; padding: 16px; cursor: pointer; transition: transform 0.12s, border-color 0.12s; }
.ex-card:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.ex-card .title { font-weight: 650; line-height: 1.35; }
.ex-card .foot { display: flex; align-items: center; gap: 8px; margin-top: auto; flex-wrap: wrap; }

table.table { width: 100%; border-collapse: collapse; }
.table th { text-align: left; font-size: 12.5px; font-weight: 650; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; padding: 10px 14px; border-bottom: 1px solid var(--border); }
.table td { padding: 12px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.table tr:last-child td { border-bottom: 0; }
.table tr.link { cursor: pointer; }
.table tr.link:hover td { background: var(--surface-2); }
.score-pill { display: inline-grid; place-items: center; min-width: 42px; height: 28px; padding: 0 8px; border-radius: 8px; font-weight: 700; font-variant-numeric: tabular-nums; }
.score-hi { background: var(--ok-bg); color: var(--ok); }
.score-mid { background: var(--warn-bg); color: var(--warn); }
.score-lo { background: var(--bad-bg); color: var(--bad); }

/* ------------------------------------------------------------ player */
.player { display: grid; grid-template-rows: auto minmax(0, 1fr); grid-template-columns: minmax(0, 1fr); height: 100vh; height: 100dvh; }
/* Cột minmax(0,1fr): cột "auto" mặc định nở theo nội dung rộng nhất (sơ đồ ý của Speaking ở 390px) và kéo cả
   thanh trên rộng hơn màn hình, nút Nộp bài bị cắt (06/10/2026) — cùng bẫy với .quiz-shell. */
.topbar {
  display: flex; align-items: center; gap: 14px; padding: 10px 20px; border-bottom: 1px solid var(--border);
  background: var(--surface); min-height: 62px;
}
.topbar .title { min-width: 0; }
.topbar .title strong { display: block; font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar .title span { font-size: 12.5px; color: var(--muted); }
.timer {
  display: inline-flex; align-items: center; gap: 8px; font: 600 18px/1 var(--mono); padding: 8px 12px;
  border-radius: 10px; background: var(--surface-3); font-variant-numeric: tabular-nums;
}
.timer .icon { width: 17px; height: 17px; }
.timer.warn { background: var(--warn-bg); color: var(--warn); }
.timer.over { background: var(--bad-bg); color: var(--bad); }
.player-body { overflow-y: auto; }
.split { display: grid; grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr); height: 100%; }
.split > .pane { overflow-y: auto; padding: 28px 32px 80px; }
.split > .pane + .pane { border-left: 1px solid var(--border); background: var(--surface-2); }
.narrow { max-width: 860px; margin: 0 auto; padding: 28px 28px 90px; }

.passage-wrap { padding-left: 30px; }   /* chỗ cho số đoạn (.pnum) bên trái; điện thoại: số nằm trong dòng */
.passage { font: 17.5px/1.75 var(--font-serif); max-width: 720px; }
.passage h2 { font: 650 24px/1.3 var(--font-display); margin-bottom: 18px; }
.passage p { margin: 0 0 16px; position: relative; }
.passage .pnum { position: absolute; left: -30px; top: 5px; font: 650 11.5px/1 var(--font); color: var(--muted); width: 22px; height: 22px; border-radius: 50%; border: 1px solid var(--border-strong); display: grid; place-items: center; }
.passage .ref { font-weight: 700; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
mark { background: var(--mark); color: inherit; border-radius: 3px; padding: 0 1px; }
mark.flash { background: var(--mark-strong); box-shadow: 0 0 0 3px var(--mark-strong); transition: box-shadow 0.6s; }

.qnav { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 18px; position: sticky; top: -28px; padding: 10px 0; background: var(--surface-2); z-index: 5; }
.qnav button { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--border-strong); background: var(--surface); cursor: pointer; font-weight: 650; font-size: 13px; }
.qnav button.answered { background: var(--text); border-color: var(--text); color: var(--primary-text); }
.qnav button.correct { background: var(--ok); border-color: var(--ok); color: #fff; }
.qnav button.wrong { background: var(--bad); border-color: var(--bad); color: #fff; }

/* Thẻ câu hỏi: MỘT component cho mọi khoá — questionCard() trong app/web/js/quiz/card.js (02/10/2026).
   Trước đó 5 màn tự dựng thẻ, có màn thêm .card-pad có màn không, chip mỗi nơi đặt một kiểu. */
.q-card { padding: 18px 20px; margin-bottom: 14px; scroll-margin-top: 70px; }
/* Tách danh sách đáp án khỏi đề bài / khối code bằng một khoảng rộng + đường kẻ mảnh, để
   mắt thấy ngay đâu là phần phải chọn. .page-stack đã lo khoảng cách giữa các câu. */
.q-card .options { margin-top: 20px; padding-top: 16px; border-top: 1px dashed var(--border); gap: 9px; }
.q-card .code-block + .options { margin-top: 18px; }
/* Đề lấy từ sách: phần sau dòng câu hỏi (đoạn văn, khối code) và lời giải của sách ở màn kết quả. */
.q-stem { margin: 2px 0 0 40px; }
.q-stem > p:first-child { margin-top: 0; }
.q-explain { margin-top: 14px; }
.q-explain .rail-label { margin-bottom: 6px; }
/* Lời giải trong khung .explain: nhỏ hơn trang Sách một chút, giữ khoảng cách đoạn của .md-doc. */
.q-explain .md-doc { font-size: 14.5px; line-height: 1.65; }
.q-explain .md-doc p { margin: 8px 0; }
.q-explain .md-doc > :last-child { margin-bottom: 0; }
.option .opt-text .code-block { margin: 4px 0; }
.q-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 12px; }
.q-num { flex: none; width: 28px; height: 28px; border-radius: 8px; background: var(--surface-3); display: grid; place-items: center; font-weight: 700; font-size: 13.5px; }
.q-text { flex: 1; min-width: 0; font-weight: 560; padding-top: 3px; }
/* Chip gợi ý ("Chọn 2 đáp án"), tiến độ, nút "?" đoán, đúng/sai: cuối dòng đề, không bao giờ ép chữ đề. */
.q-chips { flex: none; display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 6px; max-width: 45%; }
/* Ô trả lời không phải trắc nghiệm (loại "input"…): cùng đường kẻ ngăn với .options. */
.q-answer { margin-top: 18px; padding-top: 16px; border-top: 1px dashed var(--border); }
.q-input { width: min(420px, 100%); height: 44px; font: 16px/1 var(--mono); }
.q-input::placeholder { font-family: var(--font); }
/* Chữa bài loại không có ô đáp án để tô (câu gõ, lượt làm cũ không còn đề): "Bạn trả lời … · Đáp án …". */
.q-typed { display: flex; gap: 22px; flex-wrap: wrap; margin-top: 14px; }
.ok-text { color: var(--ok); }
.bad-text { color: var(--bad); }
.q-note { margin: 12px 0 0; padding: 10px 14px; font-size: 14px; }
.q-review-head { align-items: center; flex-wrap: wrap; gap: 12px; }
.q-review-head .section-title { margin: 0; }
.q-wrong-only { cursor: pointer; margin-left: auto; }
.quiz-foot .ok-text .icon, .quiz-foot .muted .icon { width: 16px; height: 16px; vertical-align: -3px; margin-right: 6px; }
.options { display: flex; flex-direction: column; gap: 7px; }
.option {
  display: grid; grid-template-columns: 28px 1fr auto; gap: 10px; align-items: center; text-align: left; width: 100%;
  padding: 9px 12px; border-radius: 10px; border: 1px solid var(--border); background: var(--surface); cursor: pointer;
  transition: border-color 0.1s, background 0.1s;
}
button.option:hover:not(:disabled) { border-color: var(--border-strong); background: var(--surface-2); }
div.option { cursor: default; }
/* Ô đáp án do choiceList() trong ui.js dựng, luôn đúng 3 con khớp 3 cột: .letter · .opt-text · .mark.
   Ô dấu có bề rộng cố định để chữ không xê dịch khi ✓ hiện ra. Câu chọn nhiều: chữ cái vuông như checkbox. */
.option .letter { width: 26px; height: 26px; border-radius: 50%; border: 1.5px solid var(--border-strong); display: grid; place-items: center; font-weight: 700; font-size: 12.5px; }
.options.multi .option .letter { border-radius: 7px; }
.option .mark { width: 18px; display: grid; place-items: center; }
.option .mark .icon { width: 17px; height: 17px; stroke-width: 2.6; }
.option.selected .mark { color: var(--accent); }
.option.correct .mark { color: var(--ok); }
.option.wrong .mark { color: var(--bad); }
/* Đáp án đang chọn: viền + nền theo màu nhấn, cộng một vòng trong cho dày viền. Trước đây
   chỉ đổi sang var(--text) + var(--surface-3), ở nền tối thành một viền trắng mảnh gần như
   không thấy (24/09/2026). Dùng --accent nên không lẫn với xanh "đúng" và đỏ "sai". */
.option.selected { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 13%, var(--surface));
                   box-shadow: inset 0 0 0 1px var(--accent); }
.option.selected .letter { background: var(--accent); border-color: var(--accent); color: #fff; }
.option.selected .opt-text { color: var(--text); font-weight: 600; }
.option.correct { border-color: var(--ok); background: var(--ok-bg); }
.option.correct .letter { background: var(--ok); border-color: var(--ok); color: #fff; }
.option.wrong { border-color: var(--bad); background: var(--bad-bg); }
.option.wrong .letter { background: var(--bad); border-color: var(--bad); color: #fff; }
/* Đáp án đúng mà người học KHÔNG chọn: viền nét đứt + chữ cái rỗng. Nét liền/chữ cái đặc = đã chọn. */
.option.missed { border-style: dashed; background: color-mix(in srgb, var(--ok-bg) 45%, var(--surface)); }
.option.missed .letter { background: transparent; color: var(--ok); }
.option:disabled { cursor: default; }
.explain { margin-top: 12px; padding: 12px 14px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--border); font-size: 14px; }
.explain .ev { margin-top: 8px; display: flex; align-items: baseline; gap: 8px; }
.explain .ev > .en { font-family: var(--font-serif); font-style: italic; color: var(--text-2); }
.q-card.review-wrong { border-left: 4px solid var(--bad); }
.q-card.review-right { border-left: 4px solid var(--ok); }

/* listening */
.item-card { padding: 20px 22px; margin-bottom: 18px; }
.item-card .ctx { font-weight: 560; margin-bottom: 12px; }
.audio {
  display: flex; align-items: center; gap: 12px; padding: 10px 14px; border-radius: 12px;
  background: var(--listening-bg); margin-bottom: 16px;
}
.audio .play { width: 42px; height: 42px; border-radius: 50%; border: 0; background: var(--listening); color: #fff; display: grid; place-items: center; cursor: pointer; flex: none; }
.audio .play:disabled { opacity: 0.4; cursor: not-allowed; }
.audio .play .icon { width: 18px; height: 18px; }
.audio .track { flex: 1; height: 6px; border-radius: 99px; background: color-mix(in srgb, var(--listening) 22%, transparent); position: relative; cursor: pointer; }
.audio .track.locked { cursor: default; }
.audio .track > span { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 99px; background: var(--listening); }
.audio .time { font: 600 13px/1 var(--mono); color: var(--text-2); min-width: 92px; text-align: right; }
.audio select { border: 1px solid var(--border-strong); border-radius: 8px; background: var(--surface); padding: 3px 6px; font-size: 13px; }
.script { margin-top: 14px; padding: 14px 16px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); }
.script .line { margin: 0 0 8px; }
.script .who { font-weight: 700; margin-right: 6px; }

/* writing */
.prompt-box { display: flex; flex-direction: column; gap: 14px; }
.stimulus { padding: 16px 18px; border-left: 4px solid var(--writing); background: var(--surface); border-radius: 0 12px 12px 0; white-space: pre-wrap; font: 16px/1.65 var(--font-serif); box-shadow: var(--shadow); }
.editor-wrap { display: flex; flex-direction: column; height: 100%; }
.editor {
  flex: 1; width: 100%; min-height: 360px; resize: none; border: 1px solid var(--border); border-radius: 14px;
  padding: 20px 22px; background: var(--surface); font: 16.5px/1.75 var(--font); outline: none; box-shadow: var(--shadow);
}
.editor:focus { border-color: var(--border-strong); }
.wordbar { display: flex; align-items: center; gap: 14px; margin-top: 12px; font-size: 14px; color: var(--text-2); }
.wordbar .meter { flex: 1; max-width: 240px; }
.tips { padding: 14px 16px; border-radius: 12px; background: var(--warn-bg); font-size: 14px; }
.tips ul { margin: 8px 0 0; padding-left: 18px; }
.tips li + li { margin-top: 4px; }
details.reveal > summary { cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 7px; color: var(--text-2); font-weight: 600; font-size: 14px; }
details.reveal > summary::-webkit-details-marker { display: none; }
details.reveal[open] > summary { margin-bottom: 10px; }

/* speaking */
.sp-layout { display: grid; grid-template-columns: 250px minmax(0, 1fr); height: 100%; }
.sp-steps { border-right: 1px solid var(--border); background: var(--surface-2); padding: 20px 14px; overflow-y: auto; }
.sp-step { display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 10px; border-radius: 10px; border: 0; background: none; text-align: left; cursor: pointer; color: var(--text-2); }
.sp-step:hover { background: var(--surface-3); }
.sp-step.current { background: var(--surface); color: var(--text); box-shadow: var(--shadow); }
.sp-step .n { width: 24px; height: 24px; border-radius: 50%; border: 1.5px solid var(--border-strong); display: grid; place-items: center; font-size: 12px; font-weight: 700; flex: none; }
.sp-step.done .n { background: var(--speaking); border-color: var(--speaking); color: #fff; }
.sp-step .lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; }
.sp-main { overflow-y: auto; }
.sp-prompt { padding: 22px 24px; }
.sp-prompt .heading { font-size: 13px; font-weight: 650; color: var(--speaking); text-transform: uppercase; letter-spacing: 0.05em; }
.sp-prompt .question { font: 600 22px/1.4 var(--font-display); margin-top: 8px; }
.sp-options { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 16px; }
.sp-options div { padding: 14px; border-radius: 12px; background: var(--speaking-bg); font-weight: 600; text-align: center; }
.mindmap { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: auto auto auto; gap: 12px; margin-top: 18px; align-items: center; }
.mindmap .node { padding: 12px 14px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); text-align: center; font-weight: 560; }
.mindmap .center { grid-column: 2; grid-row: 2; background: var(--speaking); color: #fff; border: 0; font-weight: 650; }
.mindmap .n1 { grid-column: 1; grid-row: 1; }
.mindmap .n2 { grid-column: 3; grid-row: 1; }
.mindmap .n3 { grid-column: 1; grid-row: 3; }
.mindmap .n4 { grid-column: 3; grid-row: 3; border-style: dashed; color: var(--muted); }
.rec-panel { padding: 26px 24px; display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
.big-timer { font: 650 54px/1 var(--mono); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.phase-label { font-weight: 650; text-transform: uppercase; letter-spacing: 0.06em; font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 8px; }
.phase-label.rec { color: #d93a3a; }
.rec-dot { width: 11px; height: 11px; border-radius: 50%; background: #d93a3a; animation: pulse 1.1s infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.35; transform: scale(0.8); } }
.levels { display: flex; align-items: flex-end; gap: 3px; height: 34px; }
.levels i { width: 6px; border-radius: 3px; background: var(--speaking); opacity: 0.25; height: 20%; transition: height 0.08s, opacity 0.08s; }
.levels i.on { opacity: 1; }
.progress-line { width: 100%; max-width: 480px; height: 6px; border-radius: 99px; background: var(--surface-3); overflow: hidden; position: relative; }
.progress-line > span { position: absolute; inset: 0 auto 0 0; background: #d93a3a; border-radius: 99px; }
.progress-line.prep > span { background: var(--speaking); }
.progress-line .minmark { position: absolute; top: -2px; bottom: -2px; width: 2px; background: var(--text); opacity: 0.5; }
.notes { width: 100%; max-width: 560px; min-height: 90px; border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; background: var(--surface-2); resize: vertical; }
audio { width: 100%; max-width: 480px; height: 40px; }

/* ------------------------------------------------------------ attempt / feedback */
.score-hero { display: flex; align-items: center; gap: 22px; padding: 22px 24px; }
.score-ring { --p: 0; width: 98px; height: 98px; border-radius: 50%; flex: none; display: grid; place-items: center;
  background: conic-gradient(var(--ring, var(--ok)) calc(var(--p) * 1%), var(--surface-3) 0); }
.score-ring > div { width: 78px; height: 78px; border-radius: 50%; background: var(--surface); display: grid; place-items: center; font: 700 26px/1 var(--font-display); }
.score-hero .meta { display: flex; flex-direction: column; gap: 6px; }
.criteria { display: flex; flex-direction: column; gap: 16px; }
.criterion .top { display: flex; align-items: baseline; gap: 10px; margin-bottom: 6px; }
.criterion .name { font-weight: 650; }
.criterion .sc { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.criterion .comment { font-size: 14px; color: var(--text-2); margin-top: 7px; }
.bullets { margin: 0; padding-left: 20px; }
.bullets li + li { margin-top: 5px; }
.good li::marker { color: var(--ok); }
.improve li::marker { color: var(--warn); }
.corr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 4px 16px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.corr:last-child { border-bottom: 0; }
.corr .orig { color: var(--bad); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--bad) 60%, transparent); }
.corr .fix { color: var(--ok); font-weight: 600; }
.corr .why { grid-column: 1 / -1; font-size: 13.5px; color: var(--text-2); }
/* Khoảng cách dọc cho các trang của khoá Java.
   .page không tự tạo khoảng cách giữa các con: VSTEP dựa vào margin riêng của từng khối
   (.section-title, .task-list…), còn các màn Java xếp thẳng nhiều .card vào .page nên chúng
   dính sát nhau — thấy rõ ở màn Sổ lỗi và màn làm quiz ngày 24/09/2026. Dùng flex + gap để
   mọi khối đều cách nhau đều, không phải nhớ đặt margin ở từng chỗ. */
.page-stack { display: flex; flex-direction: column; gap: 18px; }
.page-stack > .section-title { margin: 8px 0 0; }
.page-stack > .page-head { margin-bottom: 0; }

/* ---------------------------------------------------------------- màn đọc Sách
   Nội dung bên trái + cột mục lục CỐ ĐỊNH bên phải. Không dùng header dính ngang trên đầu:
   nó chỉ phủ đúng bề rộng .page nên chữ vẫn lòi ra hai bên khi cuộn, và một thanh trôi giữa
   trang trông rất rối (24/09/2026). */
.reader { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: 28px; align-items: start; }
.reader-main { min-width: 0; }
/* Giới hạn bề rộng dòng chữ cho dễ đọc; bảng và khối code vẫn dùng hết bề ngang. */
.reader-doc .md-doc { font-size: 16px; line-height: 1.75; }
.reader-doc .md-doc > p,
.reader-doc .md-doc > ul,
.reader-doc .md-doc > ol { max-width: 76ch; }
.reader-doc .md-doc h2 { padding-bottom: 8px; border-bottom: 1px solid var(--border); }

.chapter-head { margin-bottom: 26px; padding-bottom: 20px; border-bottom: 1px solid var(--border); }
.chapter-head h1 { font-size: 27px; margin: 4px 0 0; }
.chapter-goals { margin-top: 16px; padding: 14px 16px; border-radius: 12px;
                 background: var(--surface-2); border: 1px solid var(--border); max-width: 76ch; }
.chapter-goals .bullets { margin-top: 8px; font-size: 14px; color: var(--text-2); }

.reader-rail { position: sticky; top: 0; align-self: start; max-height: calc(100vh - 70px);
               display: flex; flex-direction: column; gap: 12px; }
.rail-block { display: flex; flex-direction: column; gap: 8px; min-height: 0; }
.rail-grow { flex: 1; min-height: 0; }
.rail-label { font: 650 11px/1 var(--font); text-transform: uppercase; letter-spacing: 0.07em;
              color: var(--muted); }
.rail-wide { justify-content: flex-start; }
/* Sách gốc · Đáp án · Bản soạn: ba cột đều nhau cho vừa cột 280px. */
.rail-seg { display: grid; grid-template-columns: repeat(3, 1fr); }
.rail-seg button { justify-content: center; padding: 0 6px; font-size: 12.5px; }
.segmented button:disabled { opacity: 0.45; cursor: not-allowed; }
.outline { overflow-y: auto; display: flex; flex-direction: column; gap: 1px;
           border-left: 2px solid var(--border); }
.outline a { padding: 5px 10px; border-radius: 0 8px 8px 0; color: var(--text-2);
             font-size: 13px; line-height: 1.35; border-left: 2px solid transparent;
             margin-left: -2px; }
.outline a.sub { padding-left: 22px; font-size: 12.5px; color: var(--muted); }
.outline a:hover { background: var(--surface-2); text-decoration: none; color: var(--text); }
.outline a.on { color: var(--accent); border-left-color: var(--accent); font-weight: 600;
                background: var(--surface-2); }
@media (max-width: 1100px) {
  .reader { grid-template-columns: 1fr; }
  .reader-rail { position: static; max-height: none; order: -1; }
  .outline { max-height: 190px; }
}

/* ------------------------------------------- các ô buổi của lộ trình Java (màn Lộ trình, Tiến độ)
   KHÔNG đặt tên .steps: .steps là danh sách bước DỌC của VSTEP (flex-direction: column),
   dùng lại tên đó thì 33 ô xếp mỗi ô một dòng, trang nhìn như trống trơn (24/09/2026). */
.timeline { display: flex; flex-wrap: wrap; gap: 6px; }
.tl-cell { width: 34px; height: 34px; display: grid; place-items: center; border-radius: 9px;
           font: 700 11.5px/1 var(--font); cursor: default;
           border: 1px solid var(--border); background: var(--surface-2); color: var(--muted); }
.tl-cell.done { border-color: var(--ok); background: var(--ok-bg); color: var(--ok); }
a.tl-cell { text-decoration: none; cursor: pointer; }

a.tl-cell:hover { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Đầu thẻ buổi học Java (trang Lộ trình): tiêu đề trái · chuyển buổi phải. Nút "Lịch" ở cột thứ ba
   đã bỏ cùng lịch chọn buổi ngày 02/10/2026 (lộ trình không còn ngày). */
.card-head.sess-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px; }
.sess-title { min-width: 0; }
.sess-title-row { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; }
.sess-nav { display: inline-flex; align-items: center; gap: 2px; padding: 2px;
            border: 1px solid var(--border); border-radius: 10px; }
.sess-nav .btn { min-width: 0; }
.sess-nav-sep { width: 1px; height: 18px; background: var(--border); }
/* Thẻ hẹp (cửa sổ nhỏ, hoặc khung Chạy thử đang đẩy nội dung) thì tiêu đề chiếm hàng trên, cụm
   chuyển buổi xuống hàng dưới, sát phải. Đo theo bề rộng THẺ, không theo cửa sổ. */
.sess-card { container-type: inline-size; }
@container (max-width: 560px) {
  .sess-title { grid-column: 1 / -1; }
  .sess-nav { grid-column: 1 / -1; justify-self: end; }
}
/* Ô buổi trong trang Lộ trình là <button> (chọn buổi tại chỗ), ở trang Tiến độ là <a>. */
button.tl-cell { cursor: pointer; padding: 0; }
button.tl-cell:hover { outline: 2px solid var(--accent); outline-offset: 1px; }
.tl-cell.current { border-color: var(--accent); color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.tl-cell.sel { background: var(--accent); border-color: var(--accent); color: #fff; }
.tl-legend { display: flex; gap: 16px; margin-top: 14px; font-size: 12px; color: var(--muted); }
.tl-legend span { display: flex; align-items: center; gap: 6px; }
.tl-key { width: 12px; height: 12px; border-radius: 4px; border: 1px solid var(--border);
          background: var(--surface-2); }
.tl-key.done { border-color: var(--ok); background: var(--ok-bg); }
.tl-key.current { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }

/* ------------------------------------------------------------- màn làm quiz (Java)
   Cùng khuôn với .player của VSTEP: height 100vh + grid 3 hàng (header / thân cuộn / footer).
   Phải dùng 100vh chứ KHÔNG dùng height:100%: main.js gắn view vào một <div> trung gian có
   chiều cao tự động, nên height:100% không có gì để bám và khung cuộn không hình thành —
   nội dung bị .shell.focus .main (overflow:hidden) cắt cụt, không cuộn được. Gặp 24/09/2026. */
.quiz-shell { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; grid-template-columns: minmax(0, 1fr); height: 100vh; height: 100dvh; }
/* Cột phải là minmax(0, 1fr): cột lưới mặc định rộng bằng nội dung rộng nhất, nên một khối code hay bảng tính
   dài kéo cả màn quiz rộng hơn điện thoại — thanh trên, đề và nút Nộp bị cắt mép phải (có từ bản web đầu
   tiên, thấy ở ảnh 390px ngày 02/10/2026). Khối code / bảng tự cuộn ngang trong khung của nó. */
.quiz-head { display: flex; align-items: center; gap: 18px; padding: 12px 28px;
             border-bottom: 1px solid var(--border); background: var(--surface-2); }
/* Nút thoát ở cạnh trái (cạnh dẫn) theo quy ước điều hướng; trạng thái và hành động ở cạnh
   phải. Trước đây "Thoát" nằm lẫn giữa tiêu đề và đồng hồ nên không thuộc về bên nào. */
.quiz-head .quiz-title { min-width: 0; }
.quiz-head .quiz-title h1 { font-size: 20px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.quiz-head .quiz-status { margin-left: auto; display: flex; align-items: center; gap: 14px; }
.quiz-body { overflow-y: auto; overscroll-behavior: contain; padding: 24px 28px 28px; }
.quiz-foot { display: flex; align-items: center; justify-content: space-between; gap: 18px;
             padding: 12px 28px; border-top: 1px solid var(--border); background: var(--surface-2); }
.quiz-head .quiz-status { flex: none; white-space: nowrap; }
@media (max-width: 900px) {
  .quiz-head, .quiz-foot { padding: 10px 16px; }
  .quiz-head { gap: 10px; }
  .quiz-body { padding: 16px; }
  .quiz-count-label { display: none; }
}

/* Khối code của câu hỏi: khu riêng biệt, số dòng ở gutter, CUỘN NGANG chứ không xuống
   dòng — code Java xuống dòng giữa chừng thì đọc sai ngay. */
.code-block { margin: 14px 0 4px; border: 1px solid var(--border); border-radius: 12px;
              overflow: hidden; background: var(--surface-2); }
.code-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px;
            padding: 7px 12px; border-bottom: 1px solid var(--border);
            background: color-mix(in srgb, var(--surface-2) 60%, var(--surface));
            font-size: 12px; color: var(--muted); }
.code-wrap { display: flex; align-items: stretch; max-height: 460px; overflow: auto; }
.code-bar-right { display: inline-flex; align-items: center; gap: 10px; }
.code-run { display: inline-flex; align-items: center; gap: 5px; height: 24px; padding: 0 9px; border-radius: 7px;
            border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
            font: 600 12px/1 var(--font); cursor: pointer; }
.code-run:hover { border-color: var(--accent); color: var(--accent); }
.code-run-ic { font-size: 9px; }
a.run-file { font-weight: 600; }

/* ---- Khung "Chạy thử" (views/java/runner.js). Màn rộng: đẩy nội dung sang trái để vừa đọc vừa
   sửa code; màn hẹp: đè lên (người học chọn 24/09/2026). Nằm dưới hộp thoại (100) và popup (150). */
:root { --runner-w: clamp(420px, 36vw, 680px); }
.runner { position: fixed; top: 0; right: 0; bottom: 0; width: min(var(--runner-w), 100vw); z-index: 60;
          display: flex; flex-direction: column; background: var(--surface); border-left: 1px solid var(--border);
          box-shadow: -10px 0 30px rgba(0, 0, 0, 0.18); transform: translateX(105%); visibility: hidden;
          transition: transform 0.18s ease, visibility 0s linear 0.18s; }
.runner.open { transform: none; visibility: visible; transition: transform 0.18s ease; }
@media (min-width: 1500px) {
  .shell.runner-open .main { margin-right: var(--runner-w); }
  /* Màn Sách có thêm cột mục lục 280px: khi bị đẩy, cột chữ chỉ còn ~250px ở màn 1400px (tiêu đề
     vỡ thành 5 dòng, 24/09/2026). Đang chạy thử thì mục lục nhường chỗ; đóng drawer là hiện lại. */
  .shell.runner-open .reader { grid-template-columns: minmax(0, 1fr); }
  .shell.runner-open .reader-rail { display: none; }
}
.runner-head { display: flex; align-items: center; justify-content: space-between; gap: 10px;
               padding: 12px 14px; border-bottom: 1px solid var(--border); }
.runner-title { display: flex; flex-direction: column; min-width: 0; }
.runner-label { font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.runner-actions { display: flex; align-items: center; gap: 6px; flex: none; }
.runner-note { padding: 7px 14px; font-size: 12.5px; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.runner-editor { flex: 1 1 60%; min-height: 160px; display: flex; }
.runner-out { flex: 0 0 38%; min-height: 120px; display: flex; flex-direction: column; border-top: 1px solid var(--border); }
.runner-out-head { display: flex; align-items: center; gap: 10px; padding: 8px 14px; font-size: 12.5px; }
.runner-out-head .rail-label { margin: 0; }
.runner-out-body { flex: 1; overflow: auto; padding: 0 14px 12px; }
.runner-stdout, .runner-stderr { margin: 0 0 8px; padding: 10px 12px; border-radius: 8px; white-space: pre-wrap;
                                 word-break: break-word; font: 12.5px/1.55 var(--mono); background: var(--surface-2); }
.runner-stderr { color: var(--bad); background: var(--bad-bg); }
.runner-errors { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.runner-err { display: grid; grid-template-columns: auto 1fr; gap: 10px; text-align: left; padding: 7px 10px;
              border-radius: 8px; border: 1px solid color-mix(in srgb, var(--bad) 45%, var(--border));
              background: var(--bad-bg); color: var(--text); font-size: 12.5px; cursor: pointer; }
.runner-err .mono { color: var(--bad); font-weight: 700; }
.runner-err:hover { border-color: var(--bad); }

/* Trình soạn thảo (views/java/editor.js): textarea trong suốt đè lên <pre> đã tô màu. Hai lớp phải
   cùng font, cỡ, line-height, padding và tab-size, nếu không con trỏ lệch khỏi chữ. */
.ed { flex: 1; display: grid; grid-template-columns: auto minmax(0, 1fr); min-height: 0; background: var(--surface-2); }
.ed-gutter { overflow: hidden; border-right: 1px solid var(--border); }
.ed-ln { display: flex; flex-direction: column; padding: 12px 10px 12px 14px; text-align: right;
         font: 13px/1.6 var(--mono); color: var(--muted); user-select: none; }
.ed-area { position: relative; overflow: hidden; min-height: 0; }
.ed-hl, .ed-ta { margin: 0; padding: 12px 16px; border: 0; font: 13px/1.6 var(--mono); tab-size: 4;
                 white-space: pre; letter-spacing: normal; }
.ed-hl { position: absolute; top: 0; left: 0; min-width: 100%; pointer-events: none; color: var(--text); }
.ed-ta { position: absolute; inset: 0; width: 100%; height: 100%; resize: none; outline: none; overflow: auto;
         background: transparent; color: transparent; caret-color: var(--text); }
.ed-ta::selection { background: color-mix(in srgb, var(--accent) 35%, transparent); color: transparent; }
.code-ln { flex: 0 0 auto; position: sticky; left: 0; z-index: 1; display: flex;
           flex-direction: column; padding: 12px 10px 12px 14px; text-align: right;
           border-right: 1px solid var(--border); background: var(--surface-2);
           font: 13px/1.6 var(--mono);
           color: var(--muted); user-select: none; }
.code-body { margin: 0; padding: 12px 16px; white-space: pre; tab-size: 4;
             font: 13px/1.6 var(--mono); }
.code-body .cl { display: block; min-height: 1.6em; }   /* một dòng code (dòng trống vẫn giữ chiều cao) */
.code-wrap-btn { display: inline-flex; align-items: center; height: 24px; padding: 0 9px; border-radius: 7px;
                 border: 1px solid var(--border-strong); background: var(--surface); color: var(--text-2);
                 font: 600 12px/1 var(--font); cursor: pointer; }
.code-wrap-btn[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }

/* Tô màu cú pháp. Giữ số lượng màu ít và tương phản đủ ở cả nền sáng lẫn nền tối — đọc đề
   thi cần thấy ngay từ khoá và chuỗi, không cần bảng màu 10 sắc. */
.tk-kw   { color: var(--syn-kw); font-weight: 600; }
.tk-type { color: var(--syn-type); }
.tk-str  { color: var(--syn-str); }
.tk-num  { color: var(--syn-num); }
.tk-lit  { color: var(--syn-lit); font-weight: 600; }
.tk-cmt  { color: var(--syn-cmt); font-style: italic; }
.tk-fn   { color: var(--syn-fn); }
.tk-ann  { color: var(--syn-ann); }

/* --------------------------------------------------- markdown khoá Java (.md-doc)
   KHÔNG dùng .essay cho nội dung này. .essay lấy var(--font-serif) = Georgia, mà Georgia
   không có sẵn chữ tiếng Việt như "ắ" nên trình duyệt phải ghép ă + dấu, hiện ra "nhă´c"
   thay vì "nhắc". .essay còn có white-space: pre-wrap, thừa với markdown đã render thành
   thẻ khối. (Cả hai lỗi gặp ngày 24/09/2026.) */
.md-doc { font: 15.5px/1.7 var(--font); }
.md-doc > :first-child { margin-top: 0; }
.md-doc h2 { font-size: 20px; margin: 26px 0 10px; }
.md-doc h3 { font-size: 17px; margin: 22px 0 8px; }
.md-doc h4, .md-doc h5, .md-doc h6 { font-size: 15px; margin: 18px 0 6px; color: var(--text-2); }
.md-doc p { margin: 10px 0; }
.md-doc hr { border: 0; border-top: 1px solid var(--border); margin: 22px 0; }
.md-doc ul, .md-doc ol { margin: 10px 0; }
.md-doc li + li { margin-top: 8px; }
/* Phần khối con của một mục list (code fence, đoạn văn tiếp theo). */
.md-doc .li-body { margin: 8px 0 4px; }
.md-doc .li-body > :first-child { margin-top: 0; }
.md-doc .li-body > :last-child { margin-bottom: 0; }
.md-doc .li-body .code-block { margin: 8px 0; }
.md-doc .table { margin: 12px 0; }
.md-doc .table th, .md-doc .table td { vertical-align: top; }
/* tiêu đề cột của bảng markdown là nội dung (có thể là tên Java): không viết hoa, `g(5)` không được thành G(5) */
.md-doc .table th, .table th code { text-transform: none; letter-spacing: 0; }
.md-doc .pre { margin: 12px 0; padding: 12px 14px; border-radius: 10px; font-size: 13.5px;
               line-height: 1.55; background: var(--surface-2); border: 1px solid var(--border);
               overflow-x: auto; }
.md-doc .explain { font-size: 14px; }
.md-doc code.mono { font-size: 0.92em; padding: 1px 5px; border-radius: 5px;
                    background: var(--surface-2); border: 1px solid var(--border); }
.md-doc .pre code.mono { padding: 0; background: none; border: 0; }

.essay { white-space: pre-wrap; font: 16px/1.8 var(--font-serif); }
.essay mark.err { background: var(--bad-bg); border-bottom: 2px solid var(--bad); cursor: help; border-radius: 2px; }
.improved { white-space: pre-wrap; font: 16px/1.8 var(--font-serif); padding: 18px 20px; border-radius: 12px; background: var(--ok-bg); }
.expr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px 16px; }
.expr .en { font-weight: 600; }
.metrics { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.transcript { font: 15.5px/1.7 var(--font-serif); padding: 12px 14px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--border); }
.transcript .lowc { border-bottom: 2px dotted var(--warn); }
.copybox { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 10px; background: var(--surface); border: 1px dashed var(--border-strong); font-family: var(--mono); font-size: 14px; }
.steps { counter-reset: s; list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; }
.steps li { counter-increment: s; display: grid; grid-template-columns: 30px 1fr; gap: 10px; align-items: start; }
.steps li::before { content: counter(s); width: 26px; height: 26px; border-radius: 50%; background: var(--text); color: var(--primary-text); display: grid; place-items: center; font-weight: 700; font-size: 13px; }

/* ------------------------------------------------------------ progress */
.chart { width: 100%; height: auto; display: block; }
.chart .grid line { stroke: var(--border); }
.chart .axis text { fill: var(--muted); font-size: 11px; }
.chart .target { stroke: var(--text); stroke-dasharray: 4 4; opacity: 0.45; }
.chart .line { fill: none; stroke-width: 2.5; }
.chart .pt { stroke: var(--surface); stroke-width: 2; }
.hbar { display: grid; grid-template-columns: 170px 1fr 70px; gap: 12px; align-items: center; font-size: 14px; margin-bottom: 9px; }
.hbar .val { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-2); }

/* ------------------------------------------------------------ settings */
.form-row { display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 20px; padding: 16px 0; border-bottom: 1px solid var(--border); align-items: center; }
.form-row:last-child { border-bottom: 0; }
.form-row .lab { font-weight: 600; }
.form-row .hint { font-size: 13px; color: var(--muted); font-weight: 400; margin-top: 3px; }
.input, select.input { height: 38px; padding: 0 12px; border-radius: 10px; border: 1px solid var(--border-strong); background: var(--surface); min-width: 180px; }
.switch { position: relative; display: inline-block; vertical-align: middle; width: 44px; height: 26px; flex: none; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch span { position: absolute; inset: 0; border-radius: 99px; background: color-mix(in srgb, var(--muted) 55%, var(--surface)); transition: 0.15s; cursor: pointer; }
.switch span::after { content: ""; position: absolute; width: 20px; height: 20px; left: 3px; top: 3px; border-radius: 50%; background: #fff; transition: 0.15s; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); }
.switch input:checked + span { background: var(--ok); }
.switch input:checked + span::after { transform: translateX(18px); }

/* ------------------------------------------------------------ tap-to-translate */
.w { cursor: pointer; border-radius: 3px; transition: background 0.1s; }
.w:hover { background: color-mix(in srgb, var(--accent) 14%, transparent); }
.w.key { text-decoration: underline dotted; text-decoration-color: color-mix(in srgb, var(--accent) 70%, transparent); text-decoration-thickness: 2px; text-underline-offset: 4px; }
.w.looked { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.w.active { background: color-mix(in srgb, var(--accent) 24%, transparent); }
button.option .w { cursor: context-menu; }
.lk-pop {
  position: fixed; z-index: 150; width: min(380px, calc(100vw - 16px)); max-height: min(420px, calc(100vh - 16px)); overflow-y: auto;
  background: var(--surface); color: var(--text); border: 1px solid var(--border-strong); border-radius: 14px;
  box-shadow: var(--shadow-lg); font: 14px/1.5 var(--font); animation: lk-in 0.12s ease-out;
}
@keyframes lk-in { from { transform: translateY(4px); } to { transform: none; } }
.lk-loading { display: flex; align-items: center; gap: 8px; padding: 14px 16px; color: var(--muted); }
.lk-head { display: flex; align-items: center; gap: 8px; padding: 10px 10px 8px 16px; border-bottom: 1px solid var(--border); position: sticky; top: 0; background: var(--surface); }
.lk-word { font-size: 17px; }
.lk-ipa { color: var(--muted); font-family: var(--mono); font-size: 13px; }
.lk-sec { padding: 10px 16px; border-bottom: 1px solid var(--border); }
.lk-sec:last-child { border-bottom: 0; }
.lk-ctx { background: color-mix(in srgb, var(--accent) 7%, var(--surface)); }
.lk-label { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); margin-bottom: 3px; }
.lk-main { font-size: 15.5px; font-weight: 600; }
.lk-phrase { font-style: italic; }
.lk-pos { display: inline-block; font-size: 11.5px; font-weight: 600; color: var(--accent); margin: 0 6px; }
.lk-grp .lk-pos { margin: 0 6px 0 0; }
.lk-grp + .lk-grp { margin-top: 4px; }
.lk-hw { font-weight: 700; margin: 6px 0 2px; }
.lk-hw:first-child { margin-top: 0; }
.lk-ex { font-size: 13px; color: var(--text-2); margin: 2px 0 4px 12px; }
.lk-more { margin-top: 6px; border: 0; background: none; padding: 0; color: var(--accent); cursor: pointer; font-size: 13px; }
.lk-foot { display: flex; align-items: center; gap: 6px; padding: 7px 16px; font-size: 12px; color: var(--muted); }
.lk-foot .icon { width: 14px; height: 14px; color: var(--ok); }
.lookup-hint { font-size: 12.5px; color: var(--muted); display: flex; align-items: center; gap: 6px; }

/* ------------------------------------------------------------ vocabulary review */
.nav .badge.badge-vocab { background: var(--accent); }
.rv-wrap { max-width: 680px; margin: 0 auto; padding: 36px 24px 80px; }
.rv-progress { display: flex; align-items: center; gap: 10px; min-width: 220px; }
.rv-progress .meter { flex: 1; }
.rv-progress .meter > span { background: var(--accent); }
.rv-count { font: 600 14px/1 var(--mono); color: var(--text-2); }
.rv-card { padding: 22px 26px 24px; }
.rv-head { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.rv-type { font-size: 12.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.rv-dots { display: inline-flex; gap: 3px; vertical-align: middle; }
.rv-dots i { width: 9px; height: 9px; border-radius: 50%; background: var(--surface-3); border: 1px solid var(--border-strong); }
.rv-dots i.on { background: var(--accent); border-color: var(--accent); }
.rv-prompt { text-align: center; padding: 10px 0 22px; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.rv-word { font: 700 38px/1.15 var(--font-display); letter-spacing: -0.01em; }
.rv-meaning { font: 650 26px/1.3 var(--font-display); max-width: 560px; }
.rv-sentence { font: 20px/1.7 var(--font-serif); max-width: 600px; }
.rv-blank { display: inline-block; min-width: 120px; margin: 0 4px; padding: 0 8px; border-bottom: 2px solid var(--accent); color: var(--accent); font: 600 16px/1.6 var(--mono); letter-spacing: 0.08em; }
.rv-listen { width: 88px; height: 88px; border-radius: 50%; border: 0; background: var(--listening); color: #fff; display: grid; place-items: center; cursor: pointer; box-shadow: var(--shadow); }
.rv-listen .icon { width: 36px; height: 36px; }
.rv-listen:hover { filter: brightness(1.08); }
.rv-options { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
@media (max-width: 700px) { .rv-options { grid-template-columns: 1fr; } }
.rv-options .option { min-height: 58px; }
.rv-typebox { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.rv-input { width: 280px; height: 46px; font-size: 18px; text-align: center; }
.rv-input.ok { border-color: var(--ok); background: var(--ok-bg); }
.rv-input.bad { border-color: var(--bad); background: var(--bad-bg); }
.rv-feedback { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 12px; }
.rv-verdict { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 16px; }
.rv-verdict.ok { color: var(--ok); }
.rv-verdict.bad { color: var(--bad); }
.rv-answer { padding: 12px 14px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); display: flex; flex-direction: column; gap: 4px; }
.rv-aw { font-size: 18px; }
.rv-example { font: italic 15px/1.6 var(--font-serif); color: var(--text-2); }
.rv-keys { text-align: center; margin-top: 12px; }
.rv-empty, .rv-done { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.rv-empty > .icon { width: 36px; height: 36px; color: var(--accent); }
.rv-done .table { text-align: left; margin-top: 8px; }
.rv-bigscore { font: 700 44px/1 var(--font-display); }
.rv-bigscore small { font-size: 16px; font-weight: 500; color: var(--muted); }
.rv-summary { display: grid; grid-template-columns: minmax(250px, 0.9fr) minmax(0, 1.7fr); gap: 24px; padding: 22px 24px; }
.rv-hero { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; padding-right: 24px; border-right: 1px solid var(--border); }
.rv-hero-label { display: flex; align-items: center; gap: 8px; color: var(--text-2); font-weight: 650; font-size: 14px; }
.rv-hero-label .icon { color: var(--accent); }
.rv-hero-num { font: 700 64px/1 var(--font-display); letter-spacing: -0.03em; color: var(--accent); margin-top: 4px; }
.rv-hero-num small { font: 600 17px var(--font); color: var(--text-2); margin-left: 8px; letter-spacing: 0; }
.rv-hero-num.zero { color: var(--text); }
.rv-hero-sub { font-size: 13.5px; color: var(--text-2); }
.rv-hero-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: auto; padding-top: 8px; }
.rv-side { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.rv-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
.rv-tile { position: relative; padding: 14px 14px 12px 16px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); display: flex; flex-direction: column; gap: 1px; overflow: hidden; }
.rv-tile::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--c); }
.rv-tile-num { font: 700 32px/1.1 var(--font-display); color: var(--c); letter-spacing: -0.02em; }
.rv-tile-num small { font-size: 18px; font-weight: 650; margin-left: 1px; }
.rv-tile-label { font-weight: 650; font-size: 14px; margin-top: 2px; }
.rv-tile-sub { font-size: 12px; color: var(--muted); line-height: 1.35; }
.rv-bar { height: 6px; border-radius: 99px; background: var(--surface-3); overflow: hidden; margin-top: 8px; }
.rv-bar i { display: block; height: 100%; background: var(--c); border-radius: inherit; }
.rv-levels-wrap { padding: 12px 14px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); }
.rv-levels-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; flex-wrap: wrap; font-size: 13.5px; margin-bottom: 8px; }
.rv-levels { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 10px; align-items: end; }
.rv-level { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.rv-level-n { font: 700 14px/1 var(--font-display); min-height: 14px; }
.rv-level-bar { width: 100%; max-width: 54px; height: 54px; border-radius: 7px; background: var(--surface-3); display: flex; align-items: flex-end; overflow: hidden; }
.rv-level-bar i { display: block; width: 100%; background: var(--c); border-radius: 7px 7px 0 0; }
.rv-level-l { font-size: 11.5px; color: var(--muted); font-weight: 600; }
.rv-steps { grid-column: 1 / -1; display: flex; gap: 10px 22px; flex-wrap: wrap; padding-top: 14px; border-top: 1px solid var(--border); }
.rv-step { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--text-2); flex: 1 1 220px; }
.rv-step b { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; flex: none; background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); font-size: 12px; }
.rv-step strong { color: var(--text); }
@media (max-width: 1180px) {
  .rv-summary { grid-template-columns: 1fr; }
  .rv-hero { border-right: 0; padding-right: 0; border-bottom: 1px solid var(--border); padding-bottom: 18px; }
  .rv-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ------------------------------------------------------------ menus & custom select (ui.js popMenu/selectBox) */
select option { background: var(--surface); color: var(--text); }
.select-btn {
  display: inline-flex; align-items: center; gap: 10px; height: 38px; padding: 0 10px 0 12px; min-width: 180px; max-width: 100%;
  border-radius: 10px; border: 1px solid var(--border-strong); background: var(--surface); cursor: pointer; text-align: left;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.select-btn:hover { border-color: var(--muted); }
.select-btn[aria-expanded="true"] { border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus); }
.select-label { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.select-label .icon { width: 16px; height: 16px; color: var(--muted); }
.select-chev { width: 16px; height: 16px; color: var(--muted); transition: transform 0.15s; }
.select-btn[aria-expanded="true"] .select-chev { transform: rotate(180deg); }
.pop-menu { position: fixed; right: auto; top: 0; left: 0; z-index: 150; max-height: min(400px, 72vh); overflow-y: auto; animation: menu-in 0.12s ease-out; }
@keyframes menu-in { from { transform: translateY(-4px); } }
.menu button { color: var(--text); font-size: 14px; }
.menu button:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.menu button.on { background: color-mix(in srgb, var(--accent) 13%, transparent); }
.menu button:disabled { opacity: 0.5; cursor: default; }
.menu-text { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.3; }
.menu-label { font-weight: 550; }
.menu-text small { color: var(--muted); font-size: 12px; }
.menu-check { color: var(--accent); }
.menu-right { color: var(--muted); font-size: 12px; margin-left: 14px; white-space: nowrap; }
.menu-head { padding: 7px 10px 5px; font-size: 11.5px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); }
.menu-sep { height: 1px; background: var(--border); margin: 6px 4px; }
.menu-ic { width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center; flex: none; }
.menu-ic .icon { width: 16px; height: 16px; }

/* ------------------------------------------------------------ settings extras */
.segmented { display: inline-flex; padding: 3px; gap: 3px; border-radius: 11px; background: var(--surface-3); border: 1px solid var(--border); flex-wrap: wrap; }
.segmented button { display: inline-flex; align-items: center; gap: 7px; height: 32px; padding: 0 14px; border: 0; border-radius: 8px; background: none; cursor: pointer; color: var(--text-2); font-weight: 600; }
.segmented button .icon { width: 16px; height: 16px; }
.segmented button:hover { color: var(--text); }
.segmented button.on { background: var(--surface); color: var(--text); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18); }
.sidebar-tools { margin-top: -8px; }
.theme-btn { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 12px; border: 0; border-radius: 10px; background: none; color: var(--text-2); cursor: pointer; font-size: 13.5px; }
.theme-btn:hover { background: var(--surface-3); color: var(--text); }

/* ------------------------------------------------------------ modal & toast */
.modal-backdrop { position: fixed; inset: 0; background: rgba(15, 17, 20, 0.45); display: grid; place-items: center; z-index: 100; animation: fade 0.12s; }
.modal { width: min(480px, calc(100vw - 40px)); padding: 24px; border-radius: 18px; background: var(--surface); box-shadow: var(--shadow-lg); }
.modal h3 { font-size: 18px; margin-bottom: 8px; }
.modal .body { color: var(--text-2); }
.modal .actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 22px; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.toasts { position: fixed; right: 22px; bottom: 22px; display: flex; flex-direction: column; gap: 10px; z-index: 200; }
.toast { display: flex; align-items: center; gap: 10px; min-width: 260px; max-width: 420px; padding: 12px 16px; border-radius: 12px; background: var(--primary); color: var(--primary-text); box-shadow: var(--shadow-lg); animation: rise 0.18s; font-weight: 500; }
.toast.error { background: var(--bad); color: #fff; }
.toast.claude { background: var(--claude); color: #fff; }
.toast .icon { width: 18px; height: 18px; }
@keyframes rise { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } }
.spin { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.loading { display: grid; place-items: center; min-height: 50vh; color: var(--muted); }
.load-more { display: flex; justify-content: center; padding: 18px 0 8px; color: var(--muted); grid-column: 1 / -1; }

/* ---------------------------------------------------------------- khoá Excel
   Lưới ô giống Excel (khối ```sheet), thanh công thức (```formula), các bước của một bài.
   Class riêng tiền tố sheet-/xl- — không dùng lại class của VSTEP hay Java cho bố cục khác
   (bẫy .steps ngày 24/09/2026). */
.sheet { margin: 16px 0; max-width: 100%; }
.sheet-fx, .fx-row { display: flex; align-items: stretch; background: var(--surface);
                     border: 1px solid var(--xl-grid); font-size: 13.5px; max-width: 100%; }
.sheet-fx { border-bottom: 0; border-radius: 9px 9px 0 0; }
.sheet-name { flex: none; min-width: 62px; padding: 6px 10px; border-right: 1px solid var(--xl-grid);
              font: 600 13px/1.4 var(--mono); color: var(--text); }
.sheet-fx-ic { flex: none; padding: 6px 10px; border-right: 1px solid var(--xl-grid); color: var(--muted);
               font: italic 14px/1.35 var(--font-serif); }
.sheet-fx-text, .fx-text { padding: 6px 12px; font: 13.5px/1.4 var(--mono); white-space: pre; overflow-x: auto; min-width: 0; }
.sheet-scroll { overflow-x: auto; border: 1px solid var(--xl-grid); border-radius: 9px; background: var(--surface); }
.sheet.has-fx .sheet-scroll { border-top-left-radius: 0; border-top-right-radius: 0; }
.sheet-grid { border-collapse: collapse; font-size: 14px; }
.sheet-grid th, .sheet-grid td { border: 1px solid var(--xl-grid); padding: 5px 12px; height: 30px; white-space: nowrap; }
.sheet-grid tr > :first-child { border-left: 0; }
.sheet-grid tr:last-child > * { border-bottom: 0; }
.sheet-grid thead th { border-top: 0; min-width: 96px; background: var(--xl-head); color: var(--muted);
                       font: 600 12px/1 var(--font); text-align: center; }
.sheet-grid thead th.sheet-corner { min-width: 0; width: 42px; }
.sheet-grid tbody th { width: 42px; padding: 5px 8px; background: var(--xl-head); color: var(--muted);
                       font: 600 12px/1 var(--font); text-align: center; }
.sheet-grid th.hot { background: var(--xl-bg); color: var(--xl); }
.sheet-grid td.head { font-weight: 650; }
.sheet-grid td.num { text-align: right; font-variant-numeric: tabular-nums; }
.sheet-grid td.fx { font: 13px/1.4 var(--mono); color: var(--xl); }
.sheet-grid td.err { color: var(--bad); font-weight: 650; }
.sheet-grid td.mark { background: var(--xl-mark); }
.sheet-grid td.active { outline: 2px solid var(--xl); outline-offset: -2px; }
/* Thẻ trang tính ở đáy lưới, như Excel: nền trắng, gạch chân xanh. */
.sheet-tabs { display: flex; padding-left: 42px; }
.sheet-tab { padding: 4px 16px 5px; font-size: 12.5px; font-weight: 650; color: var(--xl); background: var(--surface);
             border: 1px solid var(--xl-grid); border-top: 0; border-bottom: 2px solid var(--xl); border-radius: 0 0 6px 6px; }
.fx-block { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; margin: 14px 0; }
.fx-row { border-radius: 9px; overflow: hidden; }
.fx-result { padding: 6px 12px; border-left: 1px solid var(--xl-grid); background: var(--surface-2); color: var(--text-2); white-space: nowrap; }
.q-card .sheet { margin: 4px 0 0; }

.xl-big { font: 650 24px/1.2 var(--font-display); margin-top: 4px; }
.xl-next { border-top: 4px solid var(--xl); }
.xl-next-title { font-size: 24px; margin: 4px 0 2px; }
.xl-steps { display: flex; gap: 8px; flex-wrap: wrap; }
.xl-howto { margin: 8px 0 0; padding-left: 22px; display: flex; flex-direction: column; gap: 8px; color: var(--text-2); }
.xl-num { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 9px; background: var(--xl-bg);
          color: var(--xl); font: 700 13.5px/1 var(--font); font-variant-numeric: tabular-nums; }
.task.xl-soon { background: var(--surface-2); box-shadow: none; }
.task.xl-soon .task-title { color: var(--muted); }
.task.xl-soon .xl-num { background: var(--surface-3); color: var(--muted); }

/* Ba bước của một bài: to ở cuối bài, gọn ở cột bên phải. */
.xl-finish { margin-top: 34px; display: flex; flex-direction: column; gap: 14px; }
.xl-finish .banner { margin-bottom: 0; }
.xl-steps-card { display: flex; flex-direction: column; gap: 18px; }
.xl-step { display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: 14px; align-items: start; }
.xl-step-n { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; background: var(--surface-3);
             color: var(--text-2); font-weight: 700; font-size: 13.5px; }
.xl-step-n.done { background: var(--ok-bg); color: var(--ok); }
.xl-step-n .icon { width: 16px; height: 16px; }
.xl-step-title { font-weight: 650; margin-top: 4px; }
.xl-step-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 8px; }
.xl-step.compact { grid-template-columns: 26px minmax(0, 1fr); gap: 10px; }
.xl-step.compact .xl-step-n { width: 24px; height: 24px; font-size: 12px; }
.xl-step.compact .xl-step-title { margin-top: 2px; font-size: 14px; }
.xl-step.compact .xl-step-actions { margin-top: 6px; gap: 6px; }

/* ------------------------------------------------ bài riêng (views/java/quizzes.js, 14/10/2026) */
.custom-form { border-top: 1px solid var(--border); }
.custom-form .form-row.top { align-items: start; }
.custom-text { width: 100%; min-height: 84px; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--border-strong);
               background: var(--surface); resize: vertical; line-height: 1.45; }
.custom-ideas { gap: 6px; }
.custom-ideas .chip { cursor: pointer; border: 0; }
.custom-ideas .chip:hover { color: var(--text); background: var(--border); }
.custom-send { padding-top: 14px; }
.custom-jobs { display: flex; flex-direction: column; gap: 10px; }
.custom-jobs:empty { display: none; }
/* .task trên máy tính là lưới 3 cột (icon | nội dung | nút): một việc soạn cần xếp dọc, không thì câu yêu cầu bị ép
   thành cột hẹp mỗi chữ một dòng (ảnh chụp 14/10/2026). Hai class để thắng cả luật .task của màn hẹp. */
.task.custom-job { display: flex; flex-direction: column; align-items: stretch; gap: 6px; }
.task.custom-job > .task-actions { align-self: flex-start; }
.custom-job .banner { margin: 0; padding: 10px 14px; }
.custom-ask { color: var(--text-2); font-style: italic; overflow-wrap: anywhere; margin-top: 2px; }
.custom-seg button { white-space: nowrap; }
@media (max-width: 860px) {   /* ba nhãn dài: mỗi nhãn một hàng, thay vì gãy thành ba dòng chữ trong nút hẹp */
  /* hai class: thắng luật `.segmented { display: grid; 3 cột }` của khối "bản web" nằm phía sau file */
  .segmented.custom-seg { display: flex; flex-direction: column; align-items: stretch; }
  .segmented.custom-seg button { justify-content: flex-start; padding: 0 14px; }
}


/* ============================================================ bản web (01/10/2026)
   Đăng nhập, nút chấm bài, và bố cục cho màn hình hẹp (điện thoại ~390px). Bản desktop chỉ chạy
   trong cửa sổ ≥ 1000px nên chưa từng có bố cục này. */
.shell { height: 100vh; height: 100dvh; }
.mobile-bar { display: none; }
.scrim[hidden] { display: none; }

/* đăng nhập */
.shell.login .main { overflow-y: auto; }
.login-page { min-height: 100vh; min-height: 100dvh; display: grid; place-items: center; padding: 24px 16px; }
.login-card { width: min(380px, 100%); padding: 28px 26px; display: flex; flex-direction: column; gap: 14px; }
.login-brand { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; }
.login-brand > div { display: flex; flex-direction: column; line-height: 1.25; }
.login-brand strong { font: 650 20px/1.2 var(--font-display); }
.login-field { display: flex; flex-direction: column; gap: 6px; font-weight: 600; font-size: 14px; }
.login-field .input { width: 100%; min-width: 0; }
.login-error { color: var(--bad); font-size: 14px; min-height: 1.2em; }
.login-card .btn-lg { width: 100%; }
.login-card .tiny { display: flex; align-items: flex-start; gap: 6px; }
.login-card .tiny .icon { width: 14px; height: 14px; margin-top: 1px; }

/* tài khoản ở chân thanh bên */
.user-btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* trang kết quả: chữa bài Reading */
.review-split { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 22px; margin-top: 20px; align-items: start; }
.review-passage { position: sticky; top: 0; max-height: calc(100vh - 90px); overflow-y: auto; padding: 26px 28px 26px 58px; }
.grade-box { display: flex; flex-direction: column; gap: 10px; }

/* ------------------------------------------------ lớp bố cục thay cho style viết thẳng trong JS (06/10/2026)
   Bố cục viết bằng style:{...} thì media query không đè được (bẫy trong sua-app). Mỗi lớp dưới đây giữ đúng
   giá trị cũ trên máy tính; khối điện thoại ở cuối file đổi chúng. */
/* .only-sm: chỉ hiện trên điện thoại; .hide-sm (trong khối điện thoại): chỉ hiện trên máy tính. */
@media (min-width: 861px) { .only-sm { display: none !important; } }
.pane-switch { display: none; }                /* chuyển Bài đọc / Câu hỏi: chỉ điện thoại */
.rail-fab, .rail-scrim { display: none; }      /* nút "Mục lục" + nền mờ của bảng trượt: chỉ điện thoại */
@media (hover: none) and (pointer: coarse) { .rv-keys { display: none; } }   /* phím tắt vô nghĩa trên màn cảm ứng */

.lib-filter { margin-bottom: 18px; }
.lib-only-new { cursor: pointer; }
.lib-extra { margin-top: 26px; }
.ex-warn { color: var(--warn); }
.hist-tabs { margin-bottom: 16px; }
.hist-table .c-icon { width: 48px; }
.hist-table .c-score, .hist-table th.c-score { text-align: right; }
.hist-title { font-weight: 600; }
.hist-new { margin-left: 8px; }
.hist-correct { margin-right: 8px; }
.vocab-filter { margin: 18px 0 16px; }
.vocab-search { min-width: 220px; }
.vocab-table .c-word { width: 20%; }
.vocab-word { gap: 6px; }
.vocab-ex { font-family: var(--font-serif); font-style: italic; margin-top: 3px; }
.vocab-due { color: var(--accent); font-weight: 600; }
.vocab-src { margin-top: 3px; }
.vocab-table .c-act { text-align: right; }
.attempt-head h1 { font-size: 25px; }
.attempt-title { gap: 14px; }
.attempt-meta { margin-top: 6px; }
.attempt-meta .sep { margin-right: -6px; }   /* "· làm trong …" sát dấu chấm như trước */
.review-q-head { margin-bottom: 12px; }
.review-gloss { margin-top: 22px; }
.lr-item { margin-top: 18px; }
.lr-item .lr-ctx { margin: 0; }
.lr-audio { margin-top: 12px; }
.lr-qs { margin-top: 14px; }
.prog-title { margin-top: 28px; }
.page-narrow { max-width: 980px; }
.submit-end { margin-top: 20px; }
.listen-intro { margin-bottom: 18px; }
.prompt-intro { font-weight: 600; }
.warn-text { color: var(--warn); }
.sess-back { gap: 8px; }
.sess-actions { gap: 10px; }
.sess-note { margin-top: 0; }
.rail-nav { gap: 6px; flex-wrap: wrap; }
.center-row { justify-content: center; }

/* Speaking: khung nội dung bên phải (thay style viết thẳng trong players/speaking.js; số đo giữ như cũ). */
.sp-body { max-width: 900px; margin: 0 auto; padding: 8px 28px 60px; }
.sp-body > * { margin-top: 16px; }
.sp-body > .sp-intro, .sp-body > .sp-mic { margin-top: 24px; }
.sp-steps-head { padding: 0 10px 10px; font-weight: 650; }
.sp-listen { margin-top: 12px; }
.sp-situation { margin-top: 8px; font-size: 17px; }
.sp-prompt .question.sp-q-small { font-size: 18px; }
.sp-topic-note { margin-top: 14px; }
.banner.sp-silent { text-align: left; width: 100%; max-width: 620px; }

/* ============================================================ điện thoại (≤ 860px)
   01/10/2026: bố cục đầu tiên cho màn hẹp. 06/10/2026: làm lại cả khối sau khi người học (dùng web chủ yếu trên
   điện thoại) báo "trông rất khó nhìn": cả trang cuộn thay vì #main cuộn bên trong, thanh trên có tên trang +
   nút đổi khoá, dải tab một hàng tự cuộn ngang, thẻ/dòng gọn hơn, nút ≥ 40px, thanh trên màn làm bài một hàng,
   chuyển Bài đọc / Câu hỏi, mục lục thành bảng trượt từ dưới lên. Bản máy tính (> 860px) không đổi.
   30/10/2026: bỏ nút đổi khoá ở góc phải thanh trên — trùng với tên khoá đầu ngăn kéo ☰ (người học báo thừa). */
@media (max-width: 860px) {
  :root {
    --gutter: 14px;                 /* lề hai bên trang */
    --pad: 14px;                    /* lề trong thẻ */
    --gap: 12px;                    /* khoảng giữa các khối */
    --bar-h: calc(52px + env(safe-area-inset-top, 0px));   /* thanh trên cùng (dính) */
    --tap: 40px;                    /* vùng bấm tối thiểu */
  }
  /* Chữ mờ đậm hơn (3,5:1 → khoảng 4,9:1) — chữ nhỏ trên điện thoại ngoài trời khó đọc. Chưa đổi cho máy tính. */
  :root:not([data-theme="dark"]) { --muted: #636a74; }

  /* ---------------------------------------------------------------- khung: cả trang cuộn
     Trước đây #main là một vùng cuộn riêng trong khung cao 100dvh: thanh địa chỉ không tự thu lại, chạm thanh
     trạng thái iPhone không về đầu trang, ảnh --full chỉ chụp được một màn. Màn làm bài/quiz/ôn từ (.focus)
     vẫn giữ khung cố định với vùng cuộn bên trong. */
  .shell { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
  .shell.focus { grid-template-rows: minmax(0, 1fr); }
  .shell:not(.focus) { display: block; height: auto; min-height: 100vh; min-height: 100dvh; }
  .shell:not(.focus) .mobile-bar { position: sticky; top: 0; }
  .shell:not(.focus) .main { overflow: visible; overflow-x: clip; }
  .shell.focus .mobile-bar, .shell.login .mobile-bar { display: none; }
  html { scroll-padding-top: calc(var(--bar-h) + 8px); }   /* scrollIntoView không trốn dưới thanh trên */
  html:has(.shell.nav-open) { overflow: hidden; }         /* ngăn kéo đang mở: trang phía sau không cuộn */

  .mobile-bar {
    display: flex; align-items: center; gap: 6px; min-height: var(--bar-h);
    padding: env(safe-area-inset-top, 0px) calc(8px + env(safe-area-inset-right, 0px)) 0 calc(6px + env(safe-area-inset-left, 0px));
    border-bottom: 1px solid var(--border); background: var(--surface-2); z-index: 20;
  }
  .mobile-menu { position: relative; display: grid; place-items: center; width: 44px; height: 44px; border: 0; border-radius: 10px;
                 background: none; color: var(--text); cursor: pointer; flex: none; }
  .mobile-menu:hover { background: var(--surface-3); }
  .mobile-menu .icon { width: 22px; height: 22px; }
  /* Chấm nhỏ trên ☰ khi trong menu có số (bài mới chấm, từ đến hạn ôn). */
  .mobile-menu.has-badge::after { content: ""; position: absolute; top: 9px; right: 8px; width: 9px; height: 9px; border-radius: 50%;
                                  background: var(--accent); box-shadow: 0 0 0 2px var(--surface-2); }
  .mobile-title { flex: 1; min-width: 0; font: 650 17px/1.2 var(--font-display); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* thanh bên thành ngăn kéo trượt từ trái */
  .sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 80; width: min(300px, 86vw); overscroll-behavior: contain;
    padding-top: calc(20px + env(safe-area-inset-top, 0px)); padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-105%); visibility: hidden;
    transition: transform 0.2s ease, visibility 0s linear 0.2s;
  }
  .shell.nav-open .sidebar { transform: none; visibility: visible; box-shadow: var(--shadow-lg); transition: transform 0.2s ease; }
  .scrim { position: fixed; inset: 0; z-index: 70; background: rgba(15, 17, 20, 0.45); }
  .nav a, .theme-btn { min-height: 44px; }
  .menu button { min-height: 44px; }

  /* ---------------------------------------------------------------- trang, khoảng cách */
  .main { padding: 12px calc(var(--gutter) + env(safe-area-inset-right, 0px)) calc(40px + env(safe-area-inset-bottom, 0px))
                   calc(var(--gutter) + env(safe-area-inset-left, 0px)); }
  .page-head { margin-bottom: 14px; gap: 10px; }
  .page-head h1 { font-size: 21px; }
  .page-head .actions { margin-left: 0; flex-wrap: wrap; }
  /* Trang trong menu: tên trang đã ở thanh trên, không lặp lại tiêu đề lớn; dòng mô tả tối đa 2 dòng. */
  .shell.nav-page .page-head h1 { display: none; }
  .page-head .sub, .page-head h1 + div.muted { font-size: 13.5px; line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 2;
                                                -webkit-box-orient: vertical; overflow: hidden; }
  .shell.nav-page .page-head .sub { margin-top: 0; }
  .page-stack { gap: var(--gap); }
  .grid-2, .grid-3, .grid-main { grid-template-columns: minmax(0, 1fr); gap: var(--gap); }
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .card-pad { padding: var(--pad); }
  .card-head { padding: 12px var(--pad); }
  .card-body { padding: 12px var(--pad); }
  .section-title { margin: 18px 0 8px; text-transform: none; letter-spacing: 0; font-size: 13.5px; line-height: 1.35; color: var(--text-2); }
  .page-stack > .section-title { margin: 4px 0 0; }
  .banner { flex-wrap: wrap; padding: 12px 14px; gap: 8px 12px; }
  /* chữ chiếm phần còn lại của dòng đầu (cạnh icon), nút xuống dòng dưới, thẳng hàng với chữ */
  .banner > div, .banner > .grow { flex: 1 1 calc(100% - 34px); min-width: 0; }
  .banner > .btn { margin-left: 34px; }
  .stat { padding: 12px 14px; }
  .stat .value { font-size: 24px; }
  .empty { padding: 26px 16px; }

  /* ---------------------------------------------------------------- nút, ô nhập, chữ */
  .btn { height: 40px; }
  .btn-icon { width: 40px; }
  .btn-sm { height: 36px; position: relative; }
  .btn-sm::after { content: ""; position: absolute; inset: -4px 0; }   /* vùng bấm 44px, không làm nút to ra */
  .btn-sm.btn-icon { width: 36px; }
  .select-btn { height: 40px; }
  .input, select.input { min-width: 0; max-width: 100%; height: 40px; }
  .input, textarea, select { font-size: 16px; }   /* iPhone tự phóng to trang khi gõ vào ô chữ nhỏ hơn 16px */
  .hide-sm { display: none !important; }
  .form-row { grid-template-columns: minmax(0, 1fr); gap: 10px; padding: 14px 0; }
  .segmented { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); width: 100%; }
  .segmented button { justify-content: center; min-height: 40px; padding: 0 6px; }
  .logout-btn { background: var(--surface); border-color: var(--border-strong); color: var(--text); }
  .corr { grid-template-columns: minmax(0, 1fr); }

  /* ---------------------------------------------------------------- dải tab: một hàng, tự cuộn ngang
     Trước đây "Tất cả" vỡ 2 dòng và "Speaking" bị cắt mép (06/10). Mép mờ (.more-left/.more-right, do
     scrollStrip() trong ui.js bật/tắt) cho biết còn tab bị khuất. */
  .tabs { display: flex; width: 100%; max-width: 100%; overflow-x: auto; scrollbar-width: none;
          scroll-snap-type: x proximity; overscroll-behavior-x: contain; }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs button { flex: none; white-space: nowrap; min-height: var(--tap); padding: 0 12px; scroll-snap-align: start; }
  .tabs.more-right { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
                     mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); }
  .tabs.more-left.more-right { -webkit-mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent);
                               mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent); }
  .tabs.more-left:not(.more-right) { -webkit-mask-image: linear-gradient(to right, transparent, #000 28px);
                                     mask-image: linear-gradient(to right, transparent, #000 28px); }

  /* ---------------------------------------------------------------- Kho bài */
  .lib-filter { margin-bottom: 12px; row-gap: 4px; }
  .lib-filter .spacer { display: none; }
  .lib-only-new { min-height: 40px; }
  .lib-only-new input { width: 20px; height: 20px; accent-color: var(--accent); }
  .lib-extra { margin-top: 18px; }
  .ex-grid { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  /* Thẻ bài thành một dòng gọn: icon | tên + cấp độ | mã · chủ đề | (đã làm: trạng thái + điểm). */
  .ex-card { display: grid; grid-template-columns: 32px minmax(0, 1fr) auto; grid-template-areas: "icon title level" "icon meta meta" "icon foot foot";
             gap: 2px 12px; padding: 12px 14px; align-items: start; }
  .ex-card:hover { transform: none; }
  .ex-top { display: contents; }
  .ex-top .skill-icon { grid-area: icon; width: 32px; height: 32px; border-radius: 9px; }
  .ex-top .spacer, .ex-kicker, .ex-new, .ex-best-label { display: none; }
  .ex-top .level { grid-area: level; }
  .ex-card .title { grid-area: title; font-size: 15px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .ex-meta { grid-area: meta; font-size: 12.5px; }
  .ex-card .foot { grid-area: foot; margin-top: 6px; }
  .ex-card.is-new .foot { display: none; }
  .ex-warn { grid-column: 2 / -1; }

  /* ---------------------------------------------------------------- bảng */
  table.table { display: block; overflow-x: auto; }
  .md-doc table.table th, .md-doc table.table td { min-width: 7.5em; padding: 8px 10px; font-size: 14px; }
  /* .table-stack: mỗi dòng thành một khối; ô có data-label thành chip "nhãn: giá trị". */
  .table-stack { overflow: visible; }
  .table-stack thead { display: none; }
  .table-stack tbody { display: block; }
  .table-stack tr { display: block; padding: 12px var(--pad); border-bottom: 1px solid var(--border); }
  .table-stack tr:last-child { border-bottom: 0; }
  .table-stack td { display: block; padding: 0; border: 0; }
  .table-stack td + td { margin-top: 4px; }
  .table-stack td:first-child { font-weight: 600; }
  .table-stack td[data-label] { display: inline-flex; align-items: center; gap: 4px; margin: 6px 10px 0 0; }
  .table-stack td[data-label]::before { content: attr(data-label) ":"; color: var(--muted); font-size: 12.5px; font-weight: 500; }
  .table-stack td.is-empty { display: none; }
  .table-stack tr.link:hover td { background: none; }
  .table-stack tr.link:active { background: var(--surface-2); }

  /* Lịch sử: icon | tên bài · điểm / ngày · thời gian · trạng thái */
  .hist-table { overflow: visible; }
  .hist-table thead { display: none; }
  .hist-table tbody { display: block; }
  .hist-table tr { display: grid; grid-template-columns: 36px minmax(0, 1fr) auto; grid-template-areas: "icon main score" "icon date status";
                   gap: 4px 12px; padding: 12px var(--pad); border-bottom: 1px solid var(--border); align-items: center; }
  .hist-table tr:last-child { border-bottom: 0; }
  .hist-table td { padding: 0; border: 0; }
  .hist-table tr.link:hover td { background: none; }
  .hist-table tr.link:active { background: var(--surface-2); }
  .hist-table .c-icon { grid-area: icon; width: auto; align-self: start; }
  .hist-table .c-icon .skill-icon { width: 36px; height: 36px; }
  .hist-table .c-main { grid-area: main; }
  .hist-table .c-date { grid-area: date; min-width: 0; white-space: normal; }   /* không chạy xuống dưới chip trạng thái */
  .hist-table .c-status { grid-area: status; justify-self: end; }
  .hist-table .c-score { grid-area: score; justify-self: end; }
  .hist-table .c-main .small { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .hist-title { font-size: 15px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .hist-new { margin-left: 6px; }
  .hist-correct { display: none; }

  /* Sổ từ: từ · mức nhớ / nghĩa + câu gốc / nút */
  .vocab-filter { margin: 14px 0 12px; row-gap: 8px; }
  .vocab-filter .spacer { display: none; }
  .vocab-search { min-width: 0; width: 100%; }
  .vocab-table { overflow: visible; }
  .vocab-table thead { display: none; }
  .vocab-table tbody { display: block; }
  .vocab-table tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "word level" "mean mean" "act act";
                    gap: 4px 10px; padding: 12px var(--pad); border-bottom: 1px solid var(--border); }
  .vocab-table tr:last-child { border-bottom: 0; }
  .vocab-table td { padding: 0; border: 0; }
  .vocab-table .c-word { grid-area: word; width: auto; }
  .vocab-table .c-word .tiny { display: inline; margin-left: 2px; }
  .vocab-word { display: inline-flex; }
  .vocab-table .c-mean { grid-area: mean; font-size: 15px; }
  .vocab-table .c-level { grid-area: level; justify-self: end; text-align: right; white-space: normal; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
  .vocab-lookups { display: none; }
  .vocab-table .c-act { grid-area: act; display: flex; justify-content: space-between; align-items: center; text-align: left; margin-top: 4px; }
  .vocab-table .c-act .btn:not(.btn-icon) { height: 40px; }
  .vocab-ex { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; cursor: pointer; }
  .vocab-ex.open { display: block; }
  .rv-summary { padding: 14px; gap: 12px; }
  .rv-hero { padding-bottom: 12px; }
  .rv-hero-num { font-size: 44px; }
  .rv-tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
  .rv-tile { padding: 8px 6px 8px 10px; }
  .rv-tile-num { font-size: 22px; }
  .rv-tile-num small { font-size: 14px; }
  .rv-tile-sub, .rv-bar { display: none; }
  .rv-tile-label { font-size: 12px; line-height: 1.25; }
  .rv-tile::before { width: 3px; }
  .rv-levels-wrap, .rv-steps { display: none; }

  /* ---------------------------------------------------------------- thanh trên màn làm bài: một hàng ~52px
     [← ] [tên bài / dòng phụ, cắt bằng …] [đồng hồ] [Nộp bài] */
  .topbar { flex-wrap: nowrap; gap: 8px; padding: calc(6px + env(safe-area-inset-top, 0px)) 10px 6px; min-height: calc(52px + env(safe-area-inset-top, 0px)); }
  .topbar .skill-icon, .topbar > .spacer { display: none; }
  .topbar .title { flex: 1 1 0; min-width: 0; }
  .topbar .title strong { font-size: 14.5px; }
  .topbar .title span { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 12px; }
  .topbar .timer, .quiz-head .timer { font-size: 15px; padding: 6px 8px; }
  .topbar .timer .icon { display: none; }
  .topbar > .btn:not(.btn-back) { height: 36px; padding: 0 12px; flex: none; }
  .btn-back .btn-label { display: none; }
  .topbar .btn.btn-back, .quiz-head .btn.btn-back { width: 40px; height: 40px; padding: 0; flex: none; }
  .rv-progress { min-width: 0; flex: 1 1 0; }

  /* ---------------------------------------------------------------- màn làm bài VSTEP */
  .split { grid-template-columns: minmax(0, 1fr); height: auto; }
  .split > .pane { overflow: visible; padding: 12px var(--gutter) calc(40px + env(safe-area-inset-bottom, 0px)); }
  .split > .pane + .pane { border-left: 0; border-top: 0; background: none; }   /* một khung một lúc: cùng nền */
  .narrow { padding: 12px var(--gutter) calc(40px + env(safe-area-inset-bottom, 0px)); }
  /* paneSwitch() (players/common.js): hai nút Bài đọc | Câu hỏi, dính ở đầu vùng cuộn. Ở màn rộng không có. */
  .pane-switch { display: block; position: sticky; top: 0; z-index: 6; padding: 8px 0; background: var(--bg); }
  .player-body > .pane-switch { padding: 8px var(--gutter); }
  .page > .pane-switch { top: var(--bar-h); margin: 0 calc(-1 * var(--gutter)); padding: 8px var(--gutter); }
  .pane-seg { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px; padding: 4px; border-radius: 12px; background: var(--surface-3); }
  .pane-seg button { min-height: 36px; padding: 0 8px; border: 0; border-radius: 9px; background: none; color: var(--text-2); font-weight: 600;
                     cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .pane-seg button.on { background: var(--surface); color: var(--text); box-shadow: var(--shadow); }
  /* nền tối: --surface tối hơn --surface-3, ô đang chọn trông như lõm xuống — đảo lại cho nổi lên */
  :root[data-theme="dark"] .pane-seg { background: var(--surface); box-shadow: inset 0 0 0 1px var(--border); }
  :root[data-theme="dark"] .pane-seg button.on { background: var(--border-strong); }
  .pane-off { display: none !important; }
  .split > .pane:has(> .qnav) { padding-top: 0; }
  .passage { font-size: 16.5px; line-height: 1.7; max-width: none; }
  .passage-wrap { padding-left: 0; }
  .passage .pnum { position: static; display: inline-grid; width: 20px; height: 20px; margin-right: 6px; vertical-align: 2px; font-size: 10.5px; }
  .player .passage h2, .review-passage .passage h2 { display: none; }
  /* số câu: một hàng 10 ô, dính ngay dưới nút chuyển (8 + 44 + 8 = 60px) */
  .qnav { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(28px, 1fr); overflow-x: auto; gap: 4px; top: 60px;
          padding: 8px 0; margin-bottom: 10px; scrollbar-width: none; background: var(--bg); }
  .qnav::-webkit-scrollbar { display: none; }
  .qnav button { width: auto; height: 40px; }
  .split .q-card { scroll-margin-top: 124px; }
  .submit-end { margin-top: 16px; }
  .listen-intro { margin-bottom: 12px; }
  .item-card { padding: 14px 12px; margin-bottom: 12px; }
  /* Thẻ câu nằm trong thẻ đoạn nghe: bỏ khung thứ hai, chỉ còn đường kẻ; đúng/sai chuyển sang ô số câu. */
  .item-card .q-card { border: 0; box-shadow: none; border-radius: 0; margin: 0; padding: 14px 0 4px; border-top: 1px solid var(--border); }
  .item-card .q-card.review-wrong, .item-card .q-card.review-right { border-left: 0; }
  .item-card .q-card.review-wrong .q-num { background: var(--bad-bg); color: var(--bad); }
  .item-card .q-card.review-right .q-num { background: var(--ok-bg); color: var(--ok); }
  .item-card .audio { position: sticky; top: 0; z-index: 4; }
  .page .item-card .audio { top: var(--bar-h); }
  .lr-item { margin-top: 12px; }
  .audio { display: grid; grid-template-columns: 42px minmax(0, 1fr) auto; column-gap: 12px; row-gap: 0; padding: 8px 12px; align-items: center; }
  .audio .play { grid-column: 1; grid-row: 1 / span 2; }
  .audio .track { grid-column: 2; grid-row: 1; height: 24px; padding: 9px 0; background-clip: content-box; align-self: end; }
  .audio .track > span { top: 9px; bottom: 9px; }
  .audio .time { grid-column: 2; grid-row: 2; min-width: 0; text-align: left; font-size: 12px; align-self: start; }
  .audio select, .audio > .small { grid-column: 3; grid-row: 1 / span 2; }
  .editor { min-height: 55vh; min-height: 55dvh; padding: 14px; font-size: 16.5px; }
  .editor-wrap { height: auto; }
  .wordbar { position: sticky; bottom: 0; z-index: 3; margin-top: 0; padding: 8px 0 calc(8px + env(safe-area-inset-bottom, 0px)); background: var(--bg); }
  .stimulus { padding: 12px 14px; }

  /* Speaking: dải phần ghi âm thành các ô số 40px một hàng */
  .sp-layout { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); }
  .sp-steps { display: flex; gap: 6px; overflow-x: auto; padding: 6px var(--gutter); border-right: 0; border-bottom: 1px solid var(--border); scrollbar-width: none; }
  .sp-steps::-webkit-scrollbar { display: none; }
  .sp-steps > .sp-steps-head { display: none; }
  .sp-step { width: 40px; height: 40px; padding: 0; justify-content: center; flex: none; }
  .sp-step .lbl { display: none; }
  /* phần đang làm: tô ngay vòng số (không còn ô nền + bóng quanh vòng tròn) */
  .sp-step.current { background: none; box-shadow: none; }
  .sp-step.current .n { border: 2px solid var(--speaking); color: var(--speaking); }
  .sp-step.current.done .n { color: #fff; box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--speaking); }
  .sp-steps.single { display: none; }    /* bài chỉ có một phần: dải số vô ích */
  .sp-layout:has(> .sp-steps.single) { grid-template-rows: minmax(0, 1fr); }
  .sp-body { padding: 12px var(--gutter) calc(40px + env(safe-area-inset-bottom, 0px)); }
  .sp-body > * { margin-top: 12px; }
  .sp-body > :first-child { margin-top: 0; }
  .sp-intro .row > .icon { display: none; }
  .sp-prompt { padding: 16px; }
  .sp-prompt .question { font-size: 19px; }
  .sp-prompt .topic-q { display: none; }   /* sơ đồ ý ngay dưới đã có chủ đề ở giữa */
  .sp-listen .btn { height: 40px; }
  .rec-panel { padding: 18px 14px; }
  .sp-options { grid-template-columns: minmax(0, 1fr); }
  .mindmap { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; }
  .mindmap .node { padding: 10px; overflow-wrap: anywhere; }
  .mindmap .node { grid-column: auto; grid-row: auto; }
  .mindmap .center { grid-column: 1 / -1; grid-row: 1; }
  .big-timer { font-size: 42px; }

  /* ---------------------------------------------------------------- thẻ câu hỏi (mọi khoá) */
  .q-card { padding: 14px 12px; margin-bottom: 10px; scroll-margin-top: 12px; }
  .q-card .options { margin-top: 12px; padding-top: 12px; gap: 6px; }
  .option { gap: 8px; padding: 8px 10px; min-height: 44px; grid-template-columns: 26px minmax(0, 1fr) 14px; }
  .option .letter { width: 24px; height: 24px; }
  .option .mark { width: 14px; }
  .explain { padding: 10px 12px; }
  .explain .ev { flex-direction: column; align-items: flex-start; gap: 6px; }
  .q-head { gap: 10px; }
  /* có chip: chip cạnh ô số câu, đề chiếm cả bề ngang ở dòng dưới */
  .q-head.has-chips { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px 10px; align-items: center; }
  .q-head.has-chips .q-num { grid-row: 1; grid-column: 1; }
  .q-head.has-chips .q-chips { grid-row: 1; grid-column: 2; max-width: none; justify-content: flex-start; }
  .q-head.has-chips .q-text { grid-row: 2; grid-column: 1 / -1; padding-top: 0; }
  .q-stem { margin-left: 0; }
  .q-chips .btn-ghost { border-color: var(--border-strong); }
  .q-chips .q-flag { height: 40px; min-width: 40px; padding: 0 12px; }   /* "? Đoán": vùng bấm đủ 40px */
  .code-ln { padding: 10px 6px 10px 8px; font-size: 12.5px; }   /* cùng cỡ với .code-body: lệch cỡ là lệch dòng */
  .code-body { padding: 10px; font-size: 12.5px; }
  .code-bar { padding: 5px 10px; }
  .code-run, .code-wrap-btn { height: 30px; }
  /* "Xuống dòng" bật: dòng dài vỡ xuống, số dòng in ngay đầu mỗi dòng (CSS counter) để vẫn khớp khi vỡ dòng;
     phần vỡ thụt vào thêm 2 ký tự. */
  .code-block.wrapped .code-ln { display: none; }
  .code-block.wrapped .code-body { flex: 1 1 auto; min-width: 0; white-space: pre-wrap; overflow-wrap: anywhere; counter-reset: ln; }
  .code-block.wrapped .cl { padding-left: 2ch; text-indent: -2ch; }
  .code-block.wrapped.numbered .cl { padding-left: 6ch; text-indent: -6ch; }
  .code-block.wrapped.numbered .cl::before { counter-increment: ln; content: counter(ln); display: inline-block; width: 3ch; margin-right: 1ch;
                                             text-indent: 0; text-align: right; color: var(--muted); user-select: none; }
  /* lời giải dưới câu (Java): bỏ khung thứ hai, tràn ra mép thẻ như khối code; bảng giữ chữ code liền một mạch
     và cuộn ngang thay vì bóp mỗi cột còn ~100px */
  .q-card .q-explain { margin-inline: -12px; padding: 12px; border-radius: 0; border-inline: 0; }
  .q-explain .md-doc table.table th, .q-explain .md-doc table.table td { min-width: 9em; }
  .q-explain .md-doc table.table th:first-child, .q-explain .md-doc table.table td:first-child { min-width: 0; }
  .q-explain .md-doc table.table code { white-space: nowrap; }
  .q-card .code-block { margin-inline: -12px; border-radius: 0; border-inline: 0; }
  .item-card .q-card .code-block { margin-inline: 0; }

  /* màn làm quiz Java/Excel */
  .quiz-head { padding: calc(6px + env(safe-area-inset-top, 0px)) 10px 6px; gap: 8px; min-height: calc(52px + env(safe-area-inset-top, 0px)); }
  .quiz-head .task-kicker { display: none; }
  .quiz-head .quiz-title { flex: 1 1 0; }
  .quiz-head .quiz-title h1 { font-size: 16px; }
  .quiz-head .quiz-status { gap: 8px; }
  .quiz-body { padding: 12px var(--gutter) 24px; }
  .quiz-body .page-stack { gap: 12px; }
  .quiz-foot { padding: 8px 12px calc(8px + env(safe-area-inset-bottom, 0px)); gap: 10px; }
  .quiz-foot .btn-lg { height: 44px; padding: 0 18px; }
  .quiz-jump { padding: 0 10px; }

  /* ---------------------------------------------------------------- trang kết quả */
  .attempt-title .skill-icon { width: 32px; height: 32px; border-radius: 9px; }
  .attempt-title .skill-icon .icon { width: 17px; height: 17px; }
  .attempt-title { gap: 10px; }
  .attempt-head h1 { font-size: 20px; }
  .attempt-meta { gap: 4px 12px; }
  .attempt-meta .sep { display: none; }
  .attempt-head .actions { width: 100%; flex-wrap: nowrap; }
  .attempt-head .actions > .btn:not(.btn-back) { flex: 1; }
  .page-head .btn-back { width: 40px; padding: 0; }
  /* trang kết quả VSTEP: "← Quay lại" có chữ, đứng đầu hàng; "Làm lại bài này" chiếm phần còn lại */
  .attempt-head .actions .btn-back { order: -1; width: auto; padding: 0 12px; flex: none; }
  .attempt-head .btn-back .btn-label { display: inline; }
  .review-q-head { margin-bottom: 8px; }
  .review-q-head h2 { display: none; }        /* nút chuyển "Chữa bài · x/y" ngay trên đã nói */
  .q-wrong-only { min-height: 40px; }
  .q-wrong-only input { width: 20px; height: 20px; accent-color: var(--accent); }
  /* "Về câu N" sau khi bấm "Xem trong bài" ở trang kết quả Listening (attempt.js) */
  .back-fab { position: fixed; z-index: 30; display: inline-flex; align-items: center; gap: 6px; height: 44px; padding: 0 16px;
              right: calc(16px + env(safe-area-inset-right, 0px)); bottom: calc(16px + env(safe-area-inset-bottom, 0px));
              border: 0; border-radius: 999px; background: var(--primary); color: var(--primary-text); font-weight: 600;
              box-shadow: var(--shadow-lg); cursor: pointer; }
  .back-fab .icon { width: 18px; height: 18px; transform: rotate(90deg); }
  .page-head > .actions:has(> .btn-back:only-child) { margin-left: auto; align-self: flex-start; }
  .review-split { grid-template-columns: minmax(0, 1fr); margin-top: 0; gap: 0; }
  .review-passage { position: static; max-height: none; padding: 16px 14px; }
  .score-hero { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: 8px 14px; padding: 14px; align-items: center; }
  .score-hero .meta { display: contents; }
  .score-ring { width: 64px; height: 64px; grid-row: span 2; }
  .score-ring > div { width: 50px; height: 50px; font-size: 18px; }
  .score-hero .meta > :nth-child(n+3) { grid-column: 1 / -1; }
  .score-hero h2 { font-size: 17px; }
  .score-hero .meta > .tiny.muted { display: none; }   /* lời nhắc "bấm Xem trong bài…" — nút đã tự nói */
  .chart .axis text { font-size: 17px; }
  .empty-inline { padding: 10px 0; text-align: left; }
  .card-head:has(+ .card-body.hide-sm:last-child) { border-bottom: 0; }   /* thẻ chỉ còn dòng tiêu đề (Tiến độ, chưa có bài) */
  .hbar { grid-template-columns: minmax(0, 1fr) auto; gap: 4px 10px; margin-bottom: 12px; }
  .hbar .meter { grid-column: 1 / -1; grid-row: 2; }

  /* ---------------------------------------------------------------- dòng bài Java / Excel
     flex thay cho lưới: lưới cũ "auto minmax(0,1fr)" ngầm cần một ô đầu (chỉ dòng Excel có số bài), nên ở
     dòng Java tên bài rơi vào cột "auto" và chip bị cắt mép (06/10). */
  .task { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 12px 14px; }
  .task > .task-title { flex: 1 1 100%; min-width: 0; margin: 0; white-space: normal; }
  .task-title.has-icon > span { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  .task > .task-meta { flex: 1 1 160px; min-width: 0; }   /* nút ở cùng hàng nếu còn ≥ 160px cho dòng phụ */
  .task > .task-actions { flex: 0 0 auto; margin-left: auto; flex-wrap: wrap; justify-content: flex-end; }
  /* Bước của Lộ trình Java (30/10/2026, người học: tag nên nằm ngang tên bài): tên + tag chung hàng đầu, nút xuống
     hàng riêng căn phải. Ba class để thắng .task > .task-title ở trên; chỉ áp cho .step-row, thẻ trang khác giữ nguyên. */
  .task.step-row > .task-title { flex: 0 1 auto; }
  .task.step-row > .task-meta { flex: 1 1 auto; }
  .task.step-row > .task-actions { flex: 1 1 100%; }
  .task > .xl-num { flex: none; }
  .task > .task-main { flex: 1 1 0; min-width: 0; }
  .task-main .task-title { white-space: normal; margin: 0 0 4px; }
  /* dòng nằm trong thẻ: bỏ khung thứ hai, chỉ còn đường kẻ ngăn */
  .card-body > .task-list { gap: 0; }
  .card-body > .task-list > .task { border: 0; border-radius: 0; box-shadow: none; background: none; padding: 12px 0; border-bottom: 1px solid var(--border); }
  .card-body > .task-list > .task:first-child { padding-top: 4px; }
  .card-body > .task-list > .task:last-child { border-bottom: 0; padding-bottom: 4px; }
  .card-body > .task-list > .task.xl-soon { padding-block: 8px; }
  .task.xl-soon .task-meta { display: none; }
  .task.xl-soon .task-title { margin: 0; }
  .xl-next-title { font-size: 20px; }
  .xl-next .btn-lg { width: 100%; }
  .xl-next > .card-body > :first-child { order: -2; }   /* tên bài, rồi ngay dưới là nút "Học tiếp", rồi mục tiêu + bước */
  .xl-next-cta { order: -1; }
  .task-actions .step-check { width: 40px; height: 40px; padding: 0; }
  .rv-done .table-stack tr { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 2px 10px; align-items: start; }
  .rv-done .table-stack td + td { margin: 0; }
  .rv-done .table-stack td:nth-child(3) { grid-column: 2; color: var(--muted); }
  .card-head.sess-head .sess-title, .card-head.sess-head .sess-nav { grid-column: auto; justify-self: auto; }
  .card-head.sess-head { gap: 10px; align-items: start; }
  .sess-nav .btn { padding: 0 8px; height: 40px; }
  .sess-actions .btn { width: 100%; }
  .tl-cell { width: auto; height: 38px; }
  .timeline { display: grid; grid-template-columns: repeat(auto-fill, minmax(38px, 1fr)); }   /* ô giãn đều, không hụt mép phải */
  .score-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
  .score-tiles .big { font-size: 22px; }
  .stat-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
  .stat-tiles .stat { padding: 10px; }
  .stat-tiles .stat .row .icon { display: none; }
  .stat-tiles .stat .big { font-size: 20px; }
  .stat-tiles .stat .tiny { font-size: 11.5px; }
  .jp-chapters td:nth-child(1), .jp-chapters td:nth-child(2) { display: inline; }
  .jp-chapters td:nth-child(1)::after { content: " · "; }
  .jp-chapters td + td:nth-child(2) { margin: 0; }
  .jp-sessions tr { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
  .jp-sessions td, .jp-sessions td + td, .jp-sessions td[data-label] { margin: 0; }
  .jp-sessions td:nth-child(1) { flex: 0 0 40px; }
  .jp-sessions td:nth-child(3) { order: 1; flex: 1 1 calc(100% - 50px); min-width: 0; font-weight: 400; }
  .jp-sessions td:nth-child(2), .jp-sessions td:nth-child(4), .jp-sessions td:nth-child(5) { order: 2; font-size: 13px; color: var(--muted); }
  /* .row-table (cùng .table-stack): dòng = [tên · điểm] / [ngày · phụ]; cả dòng bấm được nên ẩn nút "Xem". */
  .row-table tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 12px; align-items: center; }
  .row-table td + td { margin: 0; }
  .row-table td.c-go { display: none; }
  .row-table td.c-main { grid-column: 1; grid-row: 1; font-weight: 600; }
  .row-table td.c-score { grid-column: 2; grid-row: 1; justify-self: end; }
  .row-table td.c-sub { grid-column: 1; grid-row: 2; font-weight: 400; font-size: 13px; color: var(--muted); }
  .row-table td.c-sub2 { grid-column: 2; grid-row: 2; justify-self: end; font-weight: 400; font-size: 13px; color: var(--muted); }

  /* ---------------------------------------------------------------- Sách Java, bài Excel: mục lục trượt từ dưới lên */
  .reader { grid-template-columns: minmax(0, 1fr); gap: 0; padding-bottom: 56px; }
  .reader-rail { position: fixed; left: 0; right: 0; bottom: 0; top: auto; z-index: 75; max-height: 78vh; max-height: 78dvh; overflow-y: auto;
                 overscroll-behavior: contain; border-radius: 16px 16px 0 0; padding: 22px 16px calc(16px + env(safe-area-inset-bottom, 0px));
                 background: var(--surface); box-shadow: var(--shadow-lg); transform: translateY(105%); visibility: hidden;
                 transition: transform 0.2s ease, visibility 0s linear 0.2s; }
  .reader.rail-open .reader-rail { transform: none; visibility: visible; transition: transform 0.2s ease; }
  .reader-rail::before { content: ""; position: absolute; top: 8px; left: 50%; width: 40px; height: 4px; margin-left: -20px; border-radius: 2px; background: var(--border-strong); }
  .rail-scrim { position: fixed; inset: 0; z-index: 74; background: rgba(15, 17, 20, 0.45); }
  .reader.rail-open .rail-scrim { display: block; }
  .rail-fab { display: inline-flex; align-items: center; gap: 8px; position: fixed; z-index: 30; height: 44px; padding: 0 16px;
              right: calc(16px + env(safe-area-inset-right, 0px)); bottom: calc(16px + env(safe-area-inset-bottom, 0px));
              border: 0; border-radius: 999px; background: var(--primary); color: var(--primary-text); font-weight: 600;
              box-shadow: var(--shadow-lg); cursor: pointer; }
  .shell.runner-open .rail-fab { display: none; }
  .rail-fab { transition: transform 0.2s ease; }
  .rail-fab.fab-away { transform: translateY(calc(100% + 24px + env(safe-area-inset-bottom, 0px))); }
  .xl-finish-nav { margin-top: 14px; justify-content: center; }
  .reader-rail .outline { max-height: none; overflow: visible; }
  .reader-rail .outline a { padding-block: 9px; }
  .reader-rail .rail-steps { display: none; }
  .reader-doc .md-doc { font-size: 16px; line-height: 1.7; }
  .chapter-head { margin-bottom: 18px; padding-bottom: 14px; }
  .chapter-head h1 { font-size: 22px; }
  .xl-finish { margin-top: 24px; }

  /* khung "Chạy thử" */
  .runner { height: 100vh; height: 100dvh; padding-bottom: env(safe-area-inset-bottom, 0px); }
  .runner-head .btn-sm { height: 40px; min-width: 40px; }
  .ed-hl, .ed-ta, .ed-ln { font-size: 16px; }   /* cả ba lớp cùng cỡ, nếu không con trỏ lệch khỏi chữ */

  /* ôn từ vựng */
  .rv-wrap { padding: 16px 12px calc(24px + env(safe-area-inset-bottom, 0px)); }
  .rv-card { padding: 16px; }
  .rv-word { font-size: 32px; }
  .rv-meaning { font-size: 22px; }
  .rv-sentence { font-size: 18px; }
  .rv-type { font-size: 11.5px; }
  .rv-input { width: 100%; }
  .rv-typebox .row { flex-wrap: wrap; justify-content: center; }

  .modal { padding: 20px; }
  /* thẻ gập (Hướng dẫn: "Các lệnh với Claude"; Java Tiến độ: danh sách buổi) */
  details.guide-fold > summary { list-style: none; cursor: pointer; }
  details.guide-fold > summary::-webkit-details-marker { display: none; }
  details.guide-fold:not([open]) > summary { border-bottom: 0; }
  details.guide-fold .fold-chev { width: 18px; height: 18px; color: var(--muted); transition: transform 0.15s; }
  details.guide-fold[open] .fold-chev { transform: rotate(180deg); }

  /* ---------------------------------------------------------------- máy hẹp (≤ 400px, ví dụ 360px) */
  @media (max-width: 400px) {
    .rv-tile { padding: 8px 4px 8px 8px; }
    .rv-tile-label { font-size: 11.5px; }
  }
  .toasts { left: 12px; right: 12px; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
  .toast { min-width: 0; max-width: none; }
}
