/* Self-hosted Noto Sans Devanagari (SIL OFL) — the guaranteed-available fallback for all
   Hindi passage text and keyboard labels, on every device and every selected typing layout.
   'Mangal' is listed first so devices that already have it installed (most Windows PCs) show
   the real Mangal font by default; everywhere else (Mac/Linux/mobile, or Windows without it)
   silently falls back to this self-hosted font instead of breaking — we don't bundle Mangal
   itself since it's a proprietary Microsoft font we can't legally redistribute. */
@font-face {
  font-family: 'Noto Sans Devanagari';
  src: url('../vendor/fonts/noto-sans-devanagari/NotoSansDevanagari-Variable.ttf') format('truetype-variations');
  font-weight: 100 900;
  font-display: swap;
}
.font-devanagari { font-family: 'Mangal', 'Noto Sans Devanagari', 'Nirmala UI', sans-serif; }
.typing-passage.font-devanagari,
.typing-input.font-devanagari { font-family: 'Mangal', 'Noto Sans Devanagari', 'Nirmala UI', sans-serif; }
/* Explicit font-size here so the Hindi passage keeps its pre-existing size — the base
   .typing-passage rule below was changed to a fixed 14px reading size for English only. */
.typing-passage.font-devanagari { font-size: calc(1.25rem * var(--typing-font-scale, 1)); line-height: calc(1.65rem * var(--typing-font-scale, 1) * var(--typing-line-height-scale, 1)); font-weight: 400; }
.vk-key.font-devanagari { font-size: 1rem; }

/* ==== Gov exam long-form SEO article (below practice sets) ==== */
.exam-article-content { font-size: 1.02rem; line-height: 1.8; color: var(--text-primary); }
.exam-article-content h2 { font-weight: 700; margin-top: 1.75rem; margin-bottom: 1rem; font-size: 1.3rem; }
.exam-article-content h2:first-child { margin-top: 0; }
.exam-article-content h3 { font-weight: 700; margin-top: 1.4rem; margin-bottom: .6rem; font-size: 1.08rem; }
.exam-article-content p { margin-bottom: 1.1rem; }
.exam-article-content ul, .exam-article-content ol { margin-bottom: 1.1rem; padding-left: 1.5rem; }
.exam-article-content li { margin-bottom: .4rem; }

/* ==== Gov exam page header banner ==== */
.exam-header-banner {
  display: flex; align-items: flex-start; gap: 1.25rem; flex-wrap: wrap;
  background: linear-gradient(135deg, rgba(var(--accent-rgb), .08), var(--bg-surface) 60%);
  border: 1px solid rgba(var(--accent-rgb), .2); border-radius: 20px; padding: 1.75rem;
}
.exam-header-icon {
  width: 56px; height: 56px; border-radius: 16px; flex-shrink: 0;
  background: rgba(var(--accent-rgb), .15); display: flex; align-items: center; justify-content: center; font-size: 1.7rem;
}
.exam-header-content { flex: 1; min-width: 220px; }
.exam-header-title { font-size: 1.5rem; font-weight: 800; margin-bottom: .4rem; }
.exam-header-desc { color: var(--text-muted); margin-bottom: .9rem; }
.exam-header-stats { display: flex; flex-wrap: wrap; gap: .6rem; }
.exam-header-stat {
  display: inline-flex; align-items: center; gap: .35rem; font-size: .82rem; font-weight: 600;
  background: var(--bg-surface); border: 1px solid var(--border-color); padding: .4rem .85rem; border-radius: 999px;
}

/* ==== Numbered "mistakes/tips" list (typing, hindi, mock-test SEO content) ==== */
.mistake-list { display: flex; flex-direction: column; gap: 1.1rem; }
.mistake-item {
  display: flex; align-items: flex-start; gap: 1rem;
  background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: 14px; padding: 1.1rem 1.25rem;
}
.mistake-num {
  flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%;
  background: rgba(var(--accent-rgb), .12); color: var(--accent); font-weight: 800; font-size: .95rem;
  display: flex; align-items: center; justify-content: center;
}

/* ==== Gov exam search box + card grid (exams home) ==== */
.exam-search-wrap { position: relative; }
.exam-search-icon {
  position: absolute; left: .9rem; top: 50%; transform: translateY(-50%);
  color: var(--text-muted); pointer-events: none; transition: color .15s ease;
}
.exam-search-wrap:focus-within .exam-search-icon { color: var(--accent); }
.exam-search-input {
  border-radius: 999px; padding: .45rem 2.2rem; font-size: 1rem; border: 1.5px solid #0d9488;
  background: var(--bg-surface); color: var(--text-primary); box-shadow: var(--shadow-sm);
  transition: border-color .15s ease, box-shadow .15s ease;
  width: 100%;
}
.exam-search-input::-webkit-search-cancel-button { display: none; }
.exam-search-input:focus {
  border-color: #0d9488; box-shadow: 0 0 0 .2rem rgba(13, 148, 136, .18); outline: none;
}
.exam-search-clear {
  position: absolute; right: .7rem; top: 50%; transform: translateY(-50%);
  width: 20px; height: 20px; border-radius: 50%; border: none; padding: 0;
  background: var(--bg-surface-alt); color: var(--text-muted); font-size: 1rem; line-height: 1;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.exam-search-clear:hover { background: var(--border-color); color: var(--text-primary); }
.exam-card-category {
  display: block; font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--accent); margin-top: .3rem;
}
.exam-card:hover .icon-wrap { background: rgba(var(--accent-rgb), .2); }
/* The icon sits in a row next to the "N Sets" badge here (not alone above the title like a
   plain .module-card), so .module-card's own 1rem icon-wrap bottom margin is redundant blank
   space on top of this card's own mb-2 row spacing — kill it. */
/* border-top intentionally excluded here — .feature-card + .feature-accent-N (app.css) own
   the top edge color/width, loaded after this file, so a full 4-side border here would
   silently win the cascade and mask the accent color. */
.exam-card { padding: 1.25rem; border-left: 1.5px solid #0d9488; border-right: 1.5px solid #0d9488; border-bottom: 1.5px solid #0d9488; }
.exam-card .icon-wrap { margin-bottom: 0; }
.exam-card-icon-img { padding: 0; overflow: hidden; background: var(--bg-surface-alt); }
.exam-card-icon-img img { width: 100%; height: 100%; object-fit: cover; }

.typing-settings-menu { min-width: 220px; }

/* ==== Donate card (exams-home.php) ==== */
.donate-card { padding: .5rem .9rem; display: inline-flex; align-items: center; gap: .75rem; }
.donate-card-qr { width: 62px; height: 62px; border-radius: 6px; border: 1px solid var(--border-color); flex-shrink: 0; }
.donate-card-name { font-size: .92rem; font-weight: 700; color: var(--text-primary); line-height: 1.25; }
.donate-card-badge { font-size: .76rem; color: var(--text-muted); line-height: 1.25; }

/* ==== Gov exam difficulty tabs ==== */
.exam-phase-tabs { border-bottom: none; gap: .6rem; flex-wrap: wrap; }
.exam-phase-tab {
  border: 1px solid var(--border-color); border-radius: 999px; padding: .55rem 1.15rem;
  background: var(--bg-surface); color: var(--text-primary); font-weight: 600; font-size: .9rem;
  display: inline-flex; align-items: center; gap: .5rem;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.exam-phase-tab:hover { border-color: var(--accent); color: var(--text-primary); }
.exam-phase-tab-count {
  font-size: .72rem; font-weight: 700; background: var(--bg-surface-alt); color: var(--text-muted);
  padding: .15rem .55rem; border-radius: 999px;
}
.exam-phase-tab.active { color: #fff; border-color: transparent; }
.exam-phase-tab.active:hover { color: #fff; }
.exam-phase-tab.active .exam-phase-tab-count { background: rgba(255, 255, 255, .25); color: #fff; }
.exam-phase-tab-easy.active { background: #16a34a; }
.exam-phase-tab-medium.active { background: #d97706; }
.exam-phase-tab-hard.active { background: #dc2626; }
.exam-phase-tab-advanced.active { background: #7c3aed; }
.exam-phase-tab-expert.active { background: #7f1d1d; }

/* ==== Gov exam grouped set boxes (10 sets per collapsible, box-level unlock) ==== */
.exam-box-list { display: flex; flex-direction: column; gap: .85rem; }

.exam-box {
  --diff: var(--accent); --diff-soft: rgba(var(--accent-rgb), .12); --diff-15: rgba(var(--accent-rgb), .16);
  border: 1px solid var(--border-color); border-radius: 16px;
  background: var(--bg-surface); overflow: hidden; box-shadow: var(--shadow-sm);
  transition: border-color .18s ease, box-shadow .18s ease;
}
.exam-box-easy     { --diff: #16a34a; --diff-soft: rgba(22, 163, 74, .12);  --diff-15: rgba(22, 163, 74, .16); }
.exam-box-medium   { --diff: #d97706; --diff-soft: rgba(217, 119, 6, .12);  --diff-15: rgba(217, 119, 6, .16); }
.exam-box-hard     { --diff: #dc2626; --diff-soft: rgba(220, 38, 38, .12);  --diff-15: rgba(220, 38, 38, .16); }
.exam-box-advanced { --diff: #7c3aed; --diff-soft: rgba(124, 58, 237, .12); --diff-15: rgba(124, 58, 237, .16); }
.exam-box-expert   { --diff: #7f1d1d; --diff-soft: rgba(127, 29, 29, .12);  --diff-15: rgba(127, 29, 29, .16); }
.exam-box[open], .exam-box:hover { border-color: var(--diff); }
.exam-box[open] { box-shadow: 0 10px 26px -16px var(--diff); }

.exam-box-head {
  display: flex; align-items: center; gap: .8rem; padding: .95rem 1.15rem;
  cursor: pointer; list-style: none; user-select: none; position: relative;
}
.exam-box-head::-webkit-details-marker { display: none; }
.exam-box-head::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 4px; height: 58%; border-radius: 0 4px 4px 0; background: var(--diff);
}
.exam-box-chevron { color: var(--diff); font-weight: 800; font-size: 1.15rem; line-height: 1; transition: transform .2s ease; flex-shrink: 0; }
.exam-box[open] > .exam-box-head .exam-box-chevron { transform: rotate(90deg); }
.exam-box-title { font-weight: 700; font-size: .98rem; color: var(--text-primary); flex-shrink: 0; }
.exam-box-count {
  font-size: .72rem; font-weight: 700; color: var(--diff); background: var(--diff-soft);
  padding: .2rem .6rem; border-radius: 999px; flex-shrink: 0;
}
.exam-box-progress { flex: 1; height: 6px; min-width: 40px; border-radius: 999px; background: var(--bg-surface-alt); overflow: hidden; }
.exam-box-progress > span { display: block; height: 100%; border-radius: 999px; background: var(--diff); transition: width .3s ease; }
.exam-box-done { font-size: .74rem; font-weight: 700; color: #16a34a; flex-shrink: 0; }
.exam-box.is-complete .exam-box-title { color: var(--text-muted); }

.exam-box-body { padding: .3rem .6rem .65rem; }
/* Outer row container: holds the title-link, the preview/steno icons, and the
   status-link as independent flex siblings (see exam-show.php's comment on why
   the icons must never be descendants of either link). */
.exam-set-row-outer {
  display: flex; align-items: center; gap: .85rem; padding: .68rem .75rem;
  border-radius: 11px; transition: background .14s ease, transform .14s ease;
}
.exam-set-row-outer:has(.exam-set-row:hover) { background: var(--bg-surface-alt); transform: translateX(2px); }
.exam-set-row {
  display: flex; align-items: center; gap: .85rem; flex: 1; min-width: 0;
  text-decoration: none; color: var(--text-primary);
}
.exam-set-num {
  width: 30px; height: 30px; border-radius: 9px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: .82rem;
  background: var(--bg-surface-alt); color: var(--text-muted);
}
.exam-set-row-outer.is-active .exam-set-num { background: var(--diff-15); color: var(--diff); }
.exam-set-row-outer.is-complete .exam-set-num { background: rgba(22, 163, 74, .14); color: #16a34a; }
.exam-set-title { flex: 1; font-weight: 600; font-size: .92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.exam-set-row-outer.is-locked { opacity: .55; }
.exam-set-row-outer.is-locked .exam-set-title { font-weight: 500; }
.exam-set-status {
  font-size: .76rem; font-weight: 700; flex-shrink: 0; white-space: nowrap; text-decoration: none;
  padding: .4rem .9rem; border-radius: 999px; transition: transform .14s ease, box-shadow .14s ease, background .14s ease;
}
.status-start { color: #fff; background: var(--diff); box-shadow: 0 3px 10px -3px var(--diff); }
.status-start:hover, .status-start:focus-visible { transform: translateY(-1px); box-shadow: 0 5px 14px -3px var(--diff); outline: none; }
.status-done { color: #16a34a; background: rgba(22, 163, 74, .12); }
.status-locked { color: var(--text-muted); font-weight: 500; background: none; padding: 0; }

.exam-set-preview-btn {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%; display: flex;
  align-items: center; justify-content: center; font-size: .85rem; color: var(--text-muted);
  background: var(--bg-surface-alt); border: 1px solid var(--border-color); cursor: pointer;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.exam-set-preview-btn:hover, .exam-set-preview-btn:focus-visible {
  background: rgba(var(--accent-rgb), .15); color: var(--accent); outline: none;
}
.passage-preview-text {
  max-height: 45vh; overflow-y: auto; line-height: 1.9; font-size: 1rem;
  padding: 1rem; border: 1px solid var(--border-color); border-radius: 12px;
  background: var(--bg-surface-alt); white-space: pre-wrap;
}

.exam-box-locked { background: var(--bg-surface-alt); box-shadow: none; }
.exam-box-locked .exam-box-head { cursor: default; }
.exam-box-locked .exam-box-head::before { background: var(--border-color); }
.exam-box-lock { color: var(--text-muted); font-size: .95rem; flex-shrink: 0; }
.exam-box-locked .exam-box-title { color: var(--text-muted); }
.exam-box-hint { margin-left: auto; font-size: .78rem; color: var(--text-muted); font-weight: 500; flex-shrink: 0; }

@media (max-width: 480px) {
  .exam-box-hint { font-size: .72rem; }
  .exam-set-status.status-start,
  .exam-set-status.status-locked { display: none; }
}

/* ==== Practice page shell ==== */
.typing-breadcrumb { font-size: .78rem; }
.typing-breadcrumb a { font-weight: 600; text-decoration: none; }
.typing-breadcrumb a:hover { color: var(--accent); }
.typing-page-header { margin-bottom: .75rem; }
.typing-page-header h1 { font-size: 1.15rem; font-weight: 700; letter-spacing: -.01em; }
.custom-setup-subtitle { color: var(--text-muted); font-size: .88rem; max-width: 520px; }

/* ==== Custom practice setup panel (numbered steps + OR divider) ==== */
/* Timer preset pills (custom.php/hindi-custom.php) — were plain Bootstrap outline-secondary,
   so the selected one turned Bootstrap's default grey/black instead of the site's accent
   color when active. */
.timer-preset { border-color: var(--accent); color: var(--accent); }
.timer-preset:hover, .timer-preset:focus { background: rgba(var(--accent-rgb), .1); border-color: var(--accent); color: var(--accent); }
.timer-preset.active { background: var(--accent); border-color: var(--accent); color: #fff; }
/* The custom-minutes input was a fixed 150px regardless of content — with a short "Custom"
   placeholder left-aligned inside it, that left a large empty gap before the "min" suffix.
   Narrower + centered text matches the compact look of the preset pills beside it. */
.custom-timer-input-group { width: 132px; }

.custom-step { display: flex; gap: 1rem; align-items: flex-start; }
.custom-step-badge {
  flex: none; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center;
  justify-content: center; font-weight: 800; font-size: .95rem; color: #fff;
  background: radial-gradient(circle at 32% 26%, rgba(var(--accent-rgb), .85), rgba(var(--accent-rgb), 1) 70%);
}
.custom-step-body { flex: 1; min-width: 0; }
.custom-step-title { display: block; font-weight: 700; margin-bottom: .5rem; }
.custom-or-divider {
  display: flex; align-items: center; gap: .75rem; margin: 1.25rem 0; color: var(--text-muted);
  font-size: .78rem; text-transform: uppercase; letter-spacing: .04em;
}
.custom-or-divider::before, .custom-or-divider::after {
  content: ''; flex: 1; height: 1px; background: var(--border-color);
}
/* Exam mode: a true 3-column layout (grid, not flex) so the title stays visually centered
   regardless of how wide the left toolbar or right timer badge are. */
.exam-mode .typing-page-header {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: .75rem;
}
.exam-mode .typing-page-header h1 { justify-self: center; text-align: center; }
.exam-mode .typing-header-controls { justify-self: start; }
.exam-mode .typing-mode-badge-timer { justify-self: end; }
/* Applies to the header toolbar (Fullscreen/Font/Settings) in BOTH exam and practice mode,
   since practice mode now uses the same compact toolbar in its header row too. */
.typing-header-controls .btn-xs { padding: .3rem .65rem; font-size: .78rem; }
.typing-header-controls #layoutSelect {
  font-size: .78rem; padding: .3rem 1.6rem .3rem .65rem; height: auto;
  border: 1px solid var(--accent); color: var(--accent); border-radius: .375rem; background-color: transparent;
}
.exam-mode .typing-mode-badge-timer { font-size: .85rem; padding: .38rem .8rem; }
/* Tighten the gap between the header row and the passage box — applies identically in
   both windowed and fullscreen exam mode since it's the same markup either way. */
.exam-mode .typing-page-header { margin-bottom: .4rem; }
.exam-mode .typing-progress-wrap { margin-bottom: .5rem; }
/* A little side breathing room beyond Bootstrap's default .container gutter — kept small
   on purpose, tapering down further on narrow screens. Also fluid (no max-width) instead
   of Bootstrap's default .container breakpoint caps, so it genuinely fills the viewport
   on wide screens rather than leaving unused space outside a capped-width box. */
.exam-mode { padding-left: 10px; padding-right: 10px; max-width: none; }
.exam-mode .typing-passage { font-size: calc(19px * var(--typing-font-scale, 1)); line-height: calc(1.3rem * var(--typing-font-scale, 1) * var(--typing-line-height-scale, 1)); }
/* Exam mode: the answer box reads at the same size/line-height as the passage above it
   (English and Hindi both use this same .exam-mode markup) — still driven by its own
   --typing-input-font-scale, not --typing-font-scale, so the independent Input Font Size
   control in Settings keeps working; at the default scale (1) it now matches exactly. */
.exam-mode .typing-input { font-size: max(19px, calc(19px * var(--typing-input-font-scale, 1))); line-height: calc(1.3rem * var(--typing-input-font-scale, 1) * var(--typing-line-height-scale, 1)); }
.typing-mode-badge {
  display: inline-block; font-size: .75rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  background: linear-gradient(120deg, rgba(var(--accent-rgb), .18), rgba(var(--accent-rgb), .08));
  color: var(--accent); padding: .3rem .8rem; border-radius: 999px;
  border: 1px solid rgba(var(--accent-rgb), .3); box-shadow: 0 2px 8px rgba(var(--accent-rgb), .12);
}

/* Groups Fullscreen / A-A+ / Settings into one visual toolbar instead of three separate
   floating buttons — a shared rounded surface behind them, same idea as other module
   toolbars on this site. */
.typing-header-controls {
  background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: 10px;
  padding: .3rem; gap: .3rem !important;
}
.typing-header-controls .typing-font-controls { margin: 0; }

/* ==== Stats bar ==== */
.typing-stats-bar {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: .6rem; margin-bottom: .85rem;
}
.typing-stat {
  background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: 12px;
  padding: .4rem .75rem; text-align: center;
  display: flex; flex-direction: row; align-items: center; justify-content: center; gap: .45rem;
}
.typing-stat .val { font-size: 1.15rem; font-weight: 800; color: var(--accent); }
.typing-stat .lbl { font-size: .72rem; text-transform: uppercase; letter-spacing: .03em; color: var(--text-muted); }
.typing-stat-icon {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 26px; height: 26px; border-radius: 50%; font-size: .85rem;
  background: rgba(var(--accent-rgb), .12);
}

/* Exam mode: shorter stat tiles so more of the passage/keyboard is visible without scrolling. */
.exam-mode .typing-stats-bar { margin-bottom: .9rem; }
.exam-mode .typing-stat { padding: .4rem .75rem; }
.exam-mode .typing-stat .val { font-size: 1.1rem; }

/* Themed (accent-colored) border for the header's Fullscreen/font-size buttons, instead of the default grey outline. */
.typing-header-controls .btn.btn-outline-secondary {
  border-color: var(--accent);
  color: var(--accent);
}
.typing-header-controls .btn.btn-outline-secondary:hover,
.typing-header-controls .btn.btn-outline-secondary:focus,
.typing-header-controls .btn.btn-outline-secondary:active,
.typing-header-controls .btn.btn-outline-secondary.active,
.typing-header-controls .show > .btn.btn-outline-secondary.dropdown-toggle {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.typing-progress-wrap { height: 8px; background: var(--bg-surface-alt); border-radius: 999px; overflow: hidden; margin-bottom: .75rem; }
.typing-progress-bar { height: 100%; background: var(--accent); width: 0; transition: width .2s ease; }

/* ==== Typing text display ==== */
.typing-passage {
  position: relative; /* so child .tc spans' offsetTop resolves relative to THIS scroll
    container in the auto-scroll JS, not to some unrelated positioned ancestor up the page */
  /* --typing-bg-color (Settings ▸ Background Color) overrides the reading background for
     both the passage and the input box below; falls back to the theme surface color, which
     is white in light mode — so "default" really does stay white until changed. */
  background: var(--typing-bg-color, var(--bg-surface)); border: 1px solid var(--accent); border-radius: 0;
  /* Default font is Times New Roman (Settings ▸ Font Style defaults to it on first visit —
     overridable per student, which sets --typing-font-family on #practiceWrap; this
     fallback only matters if JS hasn't run yet). English default reading size is a fixed
     18px at the default A-/A+ scale (same value used everywhere below — mobile breakpoint,
     input box, custom mode — so English typing has one consistent size). */
  padding: .35rem .35rem .9rem .35rem; font-family: var(--typing-font-family, 'Times New Roman', Times, serif); font-size: calc(18px * var(--typing-font-scale, 1));
  /* Unitless 1.6 (not a fixed rem amount) so it already tracks the font-scale above on its
     own — multiplying by --typing-font-scale again here would double-apply that scale.
     --typing-line-height-scale is still an independent extra multiplier (Settings ▸ Line
     Height +/-) so a student can spread the lines out further without changing text size.
     Same unitless 1.6 base as .typing-input below, so passage and input read with visually
     identical line spacing, not just proportionally similar. */
  line-height: calc(1.6 * var(--typing-line-height-scale, 1)); letter-spacing: normal; user-select: none; margin-bottom: .7rem; font-weight: 400;
  text-align: justify;
  /* Fixed box height (min === max) so it doesn't jump around between a one-line Sentence-mode
     passage and a full Paragraph-mode one — same idea as exam mode below, just a smaller
     fixed size for practice. Anything taller than this simply scrolls inside the box
     (overflow-y: auto above already handles that) instead of growing it. */
  max-height: 12rem; min-height: 12rem; overflow-y: auto; overflow-x: hidden; scroll-behavior: smooth;
  width: 100%; box-sizing: border-box; overflow-wrap: break-word; word-break: break-word;
}
.exam-mode .typing-passage { min-height: 22.8rem; max-height: 22.8rem; }
/* Fullscreen has real extra vertical room to spend — let the passage box grow to use it
   instead of staying pinned to the same fixed height as the normal windowed view. Practice
   pages keep this modest (32vh) so the on-screen keyboard below still fits in the viewport
   without scrolling; exam mode restores the original larger 46vh since it doesn't show that
   keyboard the same way. */
#practiceWrap:fullscreen .typing-passage, #practiceWrap.fs-fallback .typing-passage {
  max-height: 32vh; min-height: 32vh;
}
#practiceWrap.exam-mode:fullscreen .typing-passage, #practiceWrap.exam-mode.fs-fallback .typing-passage {
  max-height: 46vh; min-height: 46vh;
}
/* Custom Typing keeps the same 18px English size as everywhere else, just a tighter
   line-height. */
.typing-mode-custom .typing-passage {
  line-height: calc(1.3rem * var(--typing-font-scale, 1) * var(--typing-line-height-scale, 1));
}
/* Random Word practice isn't real prose — lines often end with just a couple of short,
   unrelated words, so justify (the .typing-passage default, fine for real sentences) stretches
   the sparse word-gaps on those lines to reach the right edge, reading as oddly wide gaps.
   Left-align keeps natural single-space gaps regardless of how a line happens to break. */
.typing-mode-random .typing-passage {
  text-align: left;
}
.typing-passage.blind-active { filter: blur(0.02px); } /* placeholder hook, coloring itself is suppressed in JS */
/* --typing-text-color (Settings ▸ Text Color) overrides the default reading color for
   untyped and correctly-typed text; .tc-incorrect keeps its own fixed red/white error
   colors regardless — that's a state indicator, not a reading-color preference. */
.tc { color: var(--typing-text-color, var(--text-primary)); position: relative; white-space: pre-wrap; }
.tc-current { background: rgba(var(--accent-rgb), .18); border-radius: 3px; }
.tc-correct { color: var(--typing-text-color, var(--text-primary)); }
.tc-incorrect { color: #fff; background: #dc2626; border-radius: 3px; }

.typing-input {
  /* Independent --typing-input-font-scale (not --typing-font-scale) so the "Lock Input
     Font Size" setting can hold this steady while the passage font above still grows. */
  /* No max(16px, ...) floor here (deliberately removed) — that guarded against iOS Safari
     auto-zooming on focus for any input under 16px; the default size is now 18px anyway so
     it's moot, but keeping this plain avoids the same floor silently breaking the "exact
     same size as .typing-passage" guarantee again if the default is ever lowered below 16px.
     Same font/size as .typing-passage above so the passage and the box you're typing into
     read truly identically — same --typing-font-family variable, so the Font Style dropdown
     changes both together. */
  width: 100%; font-family: var(--typing-font-family, 'Times New Roman', Times, serif); font-size: calc(18px * var(--typing-input-font-scale, 1));
  /* Unitless 1.6, same reasoning as .typing-passage above — already tracks
     --typing-input-font-scale on its own via font-size, so it's not multiplied in again
     here (that would double-scale it). --typing-line-height-scale is still applied, so
     Settings ▸ Line Height grows both boxes together by the same amount. */
  line-height: calc(1.6 * var(--typing-line-height-scale, 1));
  border: 1px solid var(--accent); border-radius: 0; padding: .55rem .7rem 1rem .7rem;
  background: var(--typing-bg-color, var(--bg-surface)); color: var(--typing-text-color, var(--text-primary)); resize: none; margin-bottom: .8rem;
  box-sizing: border-box; overflow-wrap: break-word; word-break: break-word;
  /* rows="3" browser default ~5.7rem baseline, now +30% twice (~9.6rem). */
  min-height: 9.6rem;
}
#practiceWrap:fullscreen .typing-input, #practiceWrap.fs-fallback .typing-input {
  min-height: 12rem;
}
.typing-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 .2rem rgba(var(--accent-rgb), .18); }
.typing-input:disabled { opacity: .6; }

/* ==== Controls ==== */
.typing-controls {
  display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.5rem; align-items: center;
  position: sticky; top: var(--typing-controls-top, 0px); z-index: 1010;
  background: var(--bg-body); padding: .6rem 0;
}
.typing-controls .form-range { width: 110px; }
.typing-font-controls .btn { min-width: 2.4rem; }

/* Submit/Cancel are the primary exam actions, sized 20% above the normal btn-sm scale. */
.exam-mode .typing-controls #btnCancelExam,
.exam-mode .typing-controls #btnSubmitExam {
  --bs-btn-padding-y: .36rem; --bs-btn-padding-x: .84rem; --bs-btn-font-size: .96rem;
}

/* Fixed orange (not accent-following) so Cancel always reads as a distinct, cautionary
   action regardless of the student's chosen accent color. */
.btn-exam-cancel {
  background-color: #f97316; border-color: #f97316; color: #fff;
}
.btn-exam-cancel:hover, .btn-exam-cancel:focus {
  background-color: #ea6a0c; border-color: #ea6a0c; color: #fff;
}

.btn-xs { padding: .38rem .85rem; font-size: .85rem; line-height: 1.4; }
.typing-header-controls .typing-font-controls .btn { min-width: 2.2rem; }

/* ==== Exam header: settings dropdown + live timer badge ==== */
.typing-settings-menu {
  /* Explicit theme-aware background/text — Bootstrap's own .dropdown-menu background
     (--bs-dropdown-bg) is hardcoded white regardless of our data-theme-resolved dark mode
     (this site never sets Bootstrap's own data-bs-theme attribute), so without this the
     panel stayed a stark white card floating over a dark page. A faint accent tint (not
     flat --bg-surface) instead of plain white/dark ties the panel visually to the
     solid-accent "Settings" trigger button above it, instead of looking like an unrelated
     plain box snapped underneath a colored button. */
  /* Plain solid color first as a guaranteed-opaque fallback, then the nicer accent-tinted
     version — if color-mix() ever fails to apply (unsupported browser, bad var), the panel
     still has a solid background instead of silently painting transparent over whatever is
     behind it (the stat cards row this panel overlaps when open). */
  background-color: var(--bg-surface);
  background: color-mix(in srgb, var(--accent) 4%, var(--bg-surface)); color: var(--text-primary);
  min-width: 240px; border-radius: 14px; border: 1px solid var(--border-color);
  box-shadow: var(--shadow-lg); padding: 1rem !important; z-index: 1030;
}
/* Settings panel had grown into one long single-column list as controls were added — laid
   out as two columns instead so the dropdown grows sideways, not endlessly downward. The
   heading/hr stay full-width (grid-column: 1 / -1); everything else auto-flows into
   whichever column has room next, top-to-bottom then left-to-right. */
.typing-settings-menu { min-width: 420px; }
.typing-settings-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: .25rem 1.5rem; align-items: start;
}
.typing-settings-grid > * { grid-column: span 1; }
.typing-settings-grid > .typing-settings-full,
.typing-settings-grid > hr { grid-column: 1 / -1; }
.typing-settings-grid hr { margin: .25rem 0; }
.typing-settings-menu .form-check { padding-top: .3rem; padding-bottom: .3rem; border-radius: 8px; transition: background .12s ease; }
.typing-settings-menu .form-check:hover { background: var(--bg-surface-alt); }
.typing-settings-menu .form-check-label { cursor: pointer; }
/* Font Style picker: a bit more compact than the default form-select-sm (20 options in a
   small settings panel), with each <option> rendered in its own font as a live preview. */
.typing-font-style-select { font-size: .8rem; padding: .3rem 1.75rem .3rem .55rem; min-height: auto; }
.typing-font-style-select option { padding: .3rem; }
/* Text Color swatches — same visual language as the header's accent-color picker
   (.color-swatch in themes.css), just smaller to fit the compact Settings panel. */
.typing-color-swatch {
  width: 20px; height: 20px; border-radius: 50%; border: 2px solid var(--border-color);
  cursor: pointer; padding: 0; display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; line-height: 1; color: var(--text-muted); background-clip: padding-box;
}
.typing-color-swatch.active { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(var(--accent-rgb), .25); }
.typing-color-swatch-custom { background: var(--bg-surface-alt); position: relative; overflow: hidden; }
.typing-color-swatch-custom input[type="color"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.typing-mode-badge-timer {
  font-size: 1rem; font-weight: 700; padding: .5rem 1rem; letter-spacing: .01em;
  text-transform: none; background: rgba(var(--accent-rgb), .14);
}

/* ==== Focus mode ==== */
.focus-mode .typing-stats-bar .typing-stat:not(.stat-wpm):not(.stat-timer) { opacity: .25; }
.focus-mode .virtual-keyboard { opacity: .35; }
/* Every direct child of the header EXCEPT .typing-header-controls (Fullscreen, A-/A+,
   Settings) — covers the title, the exam mode badge, and Custom Typing's title+subtitle
   wrapper div in one selector, on every page that uses this header, without needing a
   per-page list. Dimming the WHOLE .typing-page-header used to fade the Settings button's own
   open dropdown panel along with it too (opacity on a parent applies to its entire rendered
   subtree, so a child can't opt back in to full opacity), making Settings unreadable the
   moment you opened it in Focus Mode. */
.focus-mode .typing-page-header > *:not(.typing-header-controls),
.focus-mode .typing-breadcrumb { opacity: .25; }

/* ==== Virtual keyboard ====
   Finger colors live in --vk-finger-color (set per f-* class below) so each skin can decide
   how to USE that color — as a solid fill (Classic), an accent border (Dark), a flat fill
   (Minimal), or a glow (Neon) — without repeating the color list per skin. */
.virtual-keyboard { display: flex; flex-direction: column; gap: 8px; margin: 1.5rem .5rem; user-select: none; position: relative; }
.vk-row { display: flex; gap: 7px; }

.f-l-pinky, .f-r-pinky { --vk-finger-color: #ef4444; }
.f-l-ring, .f-r-ring { --vk-finger-color: #f59e0b; }
.f-l-middle, .f-r-middle { --vk-finger-color: #10b981; }
.f-l-index, .f-r-index { --vk-finger-color: #3b82f6; }
.f-thumb, .f-thumb-left, .f-thumb-right { --vk-finger-color: #6b7280; }

/* ==== Finger-guide hand overlay ====
   Built from the site's real hand photo (assets/img/ty.png) sliced into a palm/wrist piece and
   five finger pieces per hand (see HAND_SPRITE in virtual-keyboard.js) — each piece is a
   fixed-size crop (never stretched, so the photo never distorts) positioned via left/top. The
   ACTIVE finger physically travels from its home-row resting spot to whichever key is next,
   then travels back, instead of a static hand that just changes color; the palm stays anchored
   to the home row throughout, reaching down to the wrist. A small zone-colored dot near each
   fingertip (::after) carries the finger-color coding a flat SVG fill used to convey. Sits
   above the key caps (translucent) so it reads as a hand resting over the keyboard; the
   currently-required key (.vk-next) pops back above it so it's never obscured, and the
   connector line — drawn from the lit finger to that key — sits topmost. */
.vk-hands-layer { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 2; }
.vk-palm-photo, .vk-finger-photo {
  position: absolute; overflow: hidden; background-repeat: no-repeat;
  background-image: url('../img/ty.png');
  transition: left .16s ease, top .16s ease;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .18));
}
/* Hard clamps as a safety net so a sizing bug can never again balloon these into covering the
   whole page — sized separately since the palm reaches from the home row down past the bottom
   row toward the wrist, legitimately much taller than a single finger crop. */
.vk-finger-photo { max-width: 130px; max-height: 220px; opacity: .55; z-index: 2; }
.vk-palm-photo { max-width: 460px; max-height: 320px; opacity: .5; z-index: 1; }
.vk-finger-photo::after {
  content: ''; position: absolute; top: 4%; left: 50%; transform: translateX(-50%);
  width: 40%; height: 12%; max-width: 16px; max-height: 16px; border-radius: 50%;
  background: var(--vk-finger-color); opacity: .5; pointer-events: none;
  transition: opacity .15s ease, box-shadow .15s ease;
}
.vk-finger-photo.active::after { opacity: .95; box-shadow: 0 0 8px var(--vk-finger-color); }
.vk-finger-photo.active { filter: drop-shadow(0 0 7px var(--vk-finger-color)) drop-shadow(0 2px 3px rgba(0, 0, 0, .25)); }
/* Was z-index: 3 — LOWER than .vk-key.vk-next's z-index: 5, so the active finger reaching for
   its key rendered entirely BEHIND that (raised, popped-forward) key and was invisible. The
   finger needs to sit above the key it's reaching for to actually read as "this finger is
   about to press this key" instead of silently doing nothing. */
.vk-finger-photo.active { z-index: 6; }
.vk-connector-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; z-index: 6; pointer-events: none; }
/* Fixed vivid pink/magenta (not the site's own --accent, which is teal/green here and reads
   too close to the finger-zone key colors to stand out) — a dedicated color makes the
   finger's path to the next key unmistakable at a glance, on any keyboard skin. */
.vk-connector-path {
  fill: none; stroke: #ec4899; stroke-width: 4; stroke-linecap: round; opacity: 0;
  transition: opacity .15s ease; filter: drop-shadow(0 0 5px rgba(236, 72, 153, .8));
}
.vk-connector-arrowhead { fill: #ec4899; }

/* Classic 3D (default skin, no .vk-skin-* class needed) — a raised keycap look: a solid
   colored fill, a soft highlight near the top to fake light catching the cap, and a bottom
   "lip" shadow for depth. Pressing a key flattens it toward the lip shadow to look pushed in. */
.vk-key {
  flex: 1 1 0; min-width: 0; height: 46px; border-radius: 7px; display: flex; align-items: center; justify-content: center;
  font-size: .8rem; font-weight: 600; color: #fff; position: relative; flex-direction: column; line-height: 1;
  background: linear-gradient(180deg, color-mix(in srgb, var(--vk-finger-color) 85%, white 15%), var(--vk-finger-color) 55%);
  box-shadow: 0 3px 0 color-mix(in srgb, var(--vk-finger-color) 55%, black 45%), 0 5px 7px rgba(0, 0, 0, .22);
  border-bottom: 2px solid color-mix(in srgb, var(--vk-finger-color) 45%, black 55%);
  transition: transform .08s ease, box-shadow .08s ease;
  z-index: 1;
}
.vk-key.vk-nonchar { font-size: .65rem; opacity: .9; }
.vk-shift-char { font-size: .6rem; opacity: .85; }
.vk-base-char { font-size: .85rem; text-transform: uppercase; }

/* --vk-highlight-color is set inline by the "Highlight Color" swatch picker (practice.php);
   falls back to the site accent when the student hasn't customized it. */
.vk-key.vk-next { outline: 3px solid var(--vk-highlight-color, var(--accent)); transform: translateY(-2px); z-index: 5; }
.vk-key.vk-pressed-correct, .vk-key.vk-pressed-wrong {
  transform: translateY(3px);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--vk-finger-color) 55%, black 45%), 0 2px 3px rgba(0, 0, 0, .18);
}
.vk-key.vk-pressed-correct { outline: 2px solid #16a34a; }
.vk-key.vk-pressed-wrong { outline: 2px solid #dc2626; }

/* ---- Dark skin: near-black caps, finger color moves to the bottom accent + label text ---- */
.virtual-keyboard.vk-skin-dark .vk-key {
  background: linear-gradient(180deg, #2a3040, #1c212e 55%); color: var(--vk-finger-color);
  box-shadow: 0 3px 0 #0d0f15, 0 5px 7px rgba(0, 0, 0, .35);
  border-bottom: 3px solid var(--vk-finger-color);
}
.virtual-keyboard.vk-skin-dark .vk-key.vk-pressed-correct,
.virtual-keyboard.vk-skin-dark .vk-key.vk-pressed-wrong { box-shadow: 0 1px 0 #0d0f15, 0 2px 3px rgba(0, 0, 0, .3); }

/* ---- Minimal flat: no depth at all, closest to the old flat-block look ---- */
.virtual-keyboard.vk-skin-minimal .vk-key {
  background: var(--vk-finger-color); box-shadow: none; border-bottom: none; border-radius: 8px;
}
.virtual-keyboard.vk-skin-minimal .vk-key.vk-next { transform: scale(1.05); }
.virtual-keyboard.vk-skin-minimal .vk-key.vk-pressed-correct,
.virtual-keyboard.vk-skin-minimal .vk-key.vk-pressed-wrong { transform: none; box-shadow: 0 0 0 3px rgba(255, 255, 255, .5) inset; }

/* ---- Neon: dark cap, glowing color outline instead of a fill ---- */
.virtual-keyboard.vk-skin-neon .vk-key {
  background: #14161f; color: var(--vk-finger-color);
  box-shadow: inset 0 0 0 2px var(--vk-finger-color), 0 0 10px color-mix(in srgb, var(--vk-finger-color) 55%, transparent);
  border-bottom: none;
}
.virtual-keyboard.vk-skin-neon .vk-key.vk-next {
  transform: none;
  box-shadow: inset 0 0 0 2px var(--vk-highlight-color, var(--vk-finger-color)),
    0 0 18px var(--vk-highlight-color, var(--vk-finger-color)), 0 0 6px var(--vk-highlight-color, var(--vk-finger-color));
}
.virtual-keyboard.vk-skin-neon .vk-key.vk-pressed-correct,
.virtual-keyboard.vk-skin-neon .vk-key.vk-pressed-wrong {
  transform: none; box-shadow: inset 0 0 0 3px var(--vk-finger-color), 0 0 14px var(--vk-finger-color);
}

/* Keyboard Color / Hand Color quick swatches, matching a reference design's flat single-color
   keyboard: every key becomes the one chosen color (not per-finger anymore) by forcing
   --vk-finger-color to that color on every key, overriding the finger-class rules above
   (.f-l-pinky etc.) since those are !important-free and set directly per element. Whichever
   skin (Classic 3D/Dark/Minimal/Neon) is active still applies — its own gradient/shadow
   formulas are already built from var(--vk-finger-color), so they render flat/uniform too
   once every key resolves to the same color value. The hand overlay is a single real photo
   (no separate photo per skin tone exists), so its swatches are a filter-based tone shift of
   that same photo instead of a true color swap. */
.virtual-keyboard.vk-kbcolor-black .vk-key { --vk-finger-color: #1a1a1a !important; }
.virtual-keyboard.vk-kbcolor-white .vk-key { --vk-finger-color: #f5f5f5 !important; }
.virtual-keyboard.vk-kbcolor-red .vk-key { --vk-finger-color: #b91c1c !important; }
.virtual-keyboard.vk-kbcolor-orange .vk-key { --vk-finger-color: #c2410c !important; }
.virtual-keyboard.vk-kbcolor-green .vk-key { --vk-finger-color: #166534 !important; }
.virtual-keyboard.vk-kbcolor-teal .vk-key { --vk-finger-color: #0f766e !important; }
.virtual-keyboard.vk-kbcolor-blue .vk-key { --vk-finger-color: #1e3a8a !important; }
.virtual-keyboard.vk-kbcolor-purple .vk-key { --vk-finger-color: #6d28d9 !important; }
.virtual-keyboard.vk-kbcolor-pink .vk-key { --vk-finger-color: #be185d !important; }
.virtual-keyboard.vk-kbcolor-gray .vk-key { --vk-finger-color: #4b5563 !important; }

.vk-handcolor-fair .vk-palm-photo, .vk-handcolor-fair .vk-finger-photo { filter: saturate(.85) brightness(1.12) hue-rotate(-3deg); }
.vk-handcolor-orange .vk-palm-photo, .vk-handcolor-orange .vk-finger-photo { filter: saturate(1.3) sepia(.25) hue-rotate(-8deg) brightness(1.05); }
.vk-handcolor-tan .vk-palm-photo, .vk-handcolor-tan .vk-finger-photo { filter: sepia(.4) saturate(1.3) brightness(.88) hue-rotate(-6deg); }
.vk-handcolor-brown .vk-palm-photo, .vk-handcolor-brown .vk-finger-photo { filter: sepia(.55) saturate(1.4) brightness(.75) hue-rotate(-6deg); }
.vk-handcolor-pink .vk-palm-photo, .vk-handcolor-pink .vk-finger-photo { filter: saturate(1.5) hue-rotate(-18deg) brightness(1.08) contrast(1.05); }
.vk-handcolor-dark .vk-palm-photo, .vk-handcolor-dark .vk-finger-photo { filter: sepia(.6) saturate(1.6) brightness(.45) hue-rotate(-5deg); }
.vk-handcolor-deep .vk-palm-photo, .vk-handcolor-deep .vk-finger-photo { filter: sepia(.7) saturate(1.75) brightness(.3) hue-rotate(-4deg); }

/* Keyboard & Hand Colors panel — bigger swatches in labeled, cushioned groups (instead of a
   plain flat row) with a checkmark on the active swatch, matching the visual weight of a
   proper settings panel rather than a cramped quick-menu. */
.keyboard-skin-quick-menu { min-width: 280px; }
.kb-hand-group + .kb-hand-group { margin-top: .9rem; }
.kb-hand-group-label {
  display: block; font-size: .68rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--text-muted); margin-bottom: .55rem;
}
.kb-hand-swatch-row {
  display: flex; flex-wrap: wrap; gap: .55rem; justify-content: center;
  background: var(--bg-surface-alt); border-radius: 12px; padding: .65rem;
}
.kb-hand-swatch {
  width: 30px; height: 30px; border-width: 2px;
  transition: transform .12s ease, box-shadow .12s ease;
}
.kb-hand-swatch:hover { transform: scale(1.14); }
.kb-hand-swatch.active { transform: scale(1.05); }
.kb-hand-swatch.active::after {
  content: '✓'; font-size: 14px; font-weight: 700; color: #fff;
  text-shadow: 0 0 3px rgba(0, 0, 0, .65);
}
.kb-hand-swatch[data-light="true"].active::after { color: #1a1a1a; text-shadow: 0 0 3px rgba(255, 255, 255, .85); }

/* ==== Quick "Keyboard & Hand Colors" access button (below #keyboardContainer) — same 4
   skins as Settings ▸ Keyboard Style, just one tap away instead of buried in the dropdown. */
/* display:flex used to sit directly on .keyboard-skin-quick-menu at the same specificity as
   Bootstrap's own ".dropdown-menu { display: none }" — whichever stylesheet loaded later won
   the tie, which happened to be this one, so the panel stayed visibly open on every page load
   regardless of Bootstrap's .show toggle. Scoping flex to .show (matching how Bootstrap itself
   only flips to display:block on .show) fixes that without touching the toggle logic at all. */
.keyboard-skin-quick-menu { gap: .4rem; flex-wrap: wrap; min-width: 220px; justify-content: center; }
.keyboard-skin-quick-menu.show { display: flex; }
.keyboard-skin-swatch {
  border: 1px solid var(--border-color); background: var(--bg-surface-alt); color: var(--text-primary);
  border-radius: 999px; font-size: .78rem; padding: .3rem .7rem;
}
.keyboard-skin-swatch.active { border-color: var(--accent); background: rgba(var(--accent-rgb), .12); color: var(--accent); font-weight: 600; }

/* ==== Results panel ==== */
.typing-results-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,.55); display: flex; align-items: center; justify-content: center;
  z-index: 1080; padding: 1rem;
}
.typing-results-card {
  position: relative; background: var(--bg-surface); border-radius: 20px; max-width: 640px; width: 100%; padding: 2rem;
  box-shadow: var(--shadow-lg); max-height: 90vh; overflow-y: auto;
}
.typing-results-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: .75rem; margin: 1.25rem 0; }
.typing-results-grid .typing-stat .val { font-size: 1.6rem; }
.typing-results-card-wide { max-width: 1100px; }
.typing-result-icon {
  width: 64px; height: 64px; margin: 0 auto .6rem; border-radius: 50%;
  background: rgba(var(--accent-rgb), .12); color: var(--accent);
  display: flex; align-items: center; justify-content: center; font-size: 1.9rem;
  animation: typingResultPop .4s cubic-bezier(.34,1.56,.64,1);
}
@keyframes typingResultPop { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* ==== Detailed exam report (post-submit overlay + dashboard Reports modal) ==== */
.exam-report-info-card { background: var(--bg-surface-alt); border-radius: 14px; padding: 1.25rem 1.5rem; margin: 1.25rem 0; }
.exam-report-info-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem 1.5rem; }
.exam-report-info-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); margin-bottom: .15rem; }
.exam-report-info-val { font-weight: 700; }

/* Hero row: the headline numbers (Result / Gross / Net / Marks) get their own larger,
   more prominent row above the secondary stats grid — Net Speed is the qualifying figure
   so it gets the accent treatment, Result gets a pass/fail tint. */
.exam-report-hero { display: grid; grid-template-columns: repeat(4, 1fr); gap: .9rem; margin-bottom: 1.5rem; }
.exam-report-hero-tile {
  background: var(--bg-surface-alt); border: 1px solid var(--border-color); border-radius: 14px;
  padding: 1.1rem 1rem; text-align: center;
}
.exam-report-hero-label { font-size: .74rem; text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); margin-bottom: .35rem; }
.exam-report-hero-val { font-size: 1.9rem; font-weight: 800; line-height: 1.1; }
.exam-report-hero-unit { font-size: .85rem; font-weight: 600; color: var(--text-muted); margin-left: .3rem; }
.exam-report-hero-icon { font-size: 1.4rem; font-weight: 800; margin-bottom: .1rem; }
.exam-report-hero-primary { background: color-mix(in srgb, var(--accent) 12%, var(--bg-surface-alt)); border-color: var(--accent); }
.exam-report-hero-primary .exam-report-hero-val { color: var(--accent); }
.exam-report-hero-pass { background: rgba(22, 163, 74, .12); border-color: #16a34a; }
.exam-report-hero-pass .exam-report-hero-val, .exam-report-hero-pass .exam-report-hero-icon { color: #16a34a; }
.exam-report-hero-fail { background: rgba(220, 38, 38, .12); border-color: #dc2626; }
.exam-report-hero-fail .exam-report-hero-val, .exam-report-hero-fail .exam-report-hero-icon { color: #dc2626; }

.exam-report-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: .75rem; margin-bottom: 1.5rem; }
.exam-report-tile { background: var(--bg-surface-alt); border-radius: 12px; padding: .9rem 1rem; }
.exam-report-tile-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); margin-bottom: .25rem; }
.exam-report-tile-val { font-size: 1.4rem; font-weight: 700; }
.exam-report-tile-danger .exam-report-tile-val { color: #dc2626; }
.exam-report-tile-warning .exam-report-tile-val { color: #d97706; }
.exam-report-tile-info .exam-report-tile-val { color: #7c3aed; }
.exam-report-tile-success .exam-report-tile-val { color: #16a34a; }
.exam-report-comparison-title { font-size: 1rem; font-weight: 700; text-align: center; margin-bottom: 1rem; }
.exam-report-comparison-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.exam-report-comparison-col { min-width: 0; }
.exam-report-comparison-head { font-weight: 700; text-align: center; margin-bottom: .5rem; }
.exam-report-comparison-box {
  background: var(--bg-surface-alt); border-radius: 12px; padding: 1rem; max-height: 300px; overflow-y: auto; overflow-x: hidden;
  line-height: 2.1; font-family: Georgia, 'Times New Roman', serif;
  overflow-wrap: anywhere; word-break: break-word;
}
.exam-report-word-full { background: rgba(220, 38, 38, .18); color: #dc2626; border-radius: 3px; padding: 0 2px; overflow-wrap: anywhere; }
.exam-report-word-half { background: rgba(217, 119, 6, .18); color: #d97706; border-radius: 3px; padding: 0 2px; overflow-wrap: anywhere; }

/* ==== Overlay close button + fullscreen (shared look with games.css) ==== */
.overlay-close-btn {
  position: absolute; top: .9rem; right: .9rem; width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--border-color); background: var(--bg-surface-alt); color: var(--text-primary);
  display: flex; align-items: center; justify-content: center; font-size: 1.1rem; line-height: 1; cursor: pointer;
}
.overlay-close-btn:hover { background: var(--border-color); }
#practiceWrap:fullscreen, #gamePlayWrap:fullscreen,
#practiceWrap.fs-fallback, #gamePlayWrap.fs-fallback {
  background: var(--bg-body); padding: 2rem; overflow-y: auto;
}
#practiceWrap.fs-fallback, #gamePlayWrap.fs-fallback { position: fixed; inset: 0; z-index: 1090; }

@media (max-width: 767.98px) {
  .typing-stats-bar { grid-template-columns: repeat(2, 1fr); }
  .typing-results-grid { grid-template-columns: repeat(2, 1fr); }
  .exam-report-info-grid { grid-template-columns: repeat(2, 1fr); }
  .exam-report-hero { grid-template-columns: repeat(2, 1fr); }
  .exam-report-tiles { grid-template-columns: repeat(2, 1fr); }
  .exam-report-comparison-grid { grid-template-columns: 1fr; }
  .typing-passage { font-size: calc(18px * var(--typing-font-scale, 1)); line-height: calc(1.6 * var(--typing-line-height-scale, 1)); padding: .75rem; max-height: 9rem; min-height: 9rem; }
  .exam-mode .typing-passage { min-height: 15.8rem; max-height: 15.8rem; }
  .typing-passage.font-devanagari { font-size: calc(1.15rem * var(--typing-font-scale, 1)); }
  .typing-input { font-size: calc(18px * var(--typing-input-font-scale, 1)); line-height: calc(1.6 * var(--typing-line-height-scale, 1)); padding: .65rem .8rem 1.1rem .8rem; min-height: 8.5rem; }
  .exam-mode .typing-controls #btnCancelExam,
  .exam-mode .typing-controls #btnSubmitExam { padding: .65rem 1.5rem; font-size: 1rem; }
  .vk-key { height: 36px; font-size: .68rem; }
  .virtual-keyboard { display: none; } /* keyboard guidance is a desktop touch-typing aid; hidden on small screens */

  /* Exam header controls (Fullscreen / A-/A+ / Settings) shrink back down on mobile —
     the larger desktop .btn-xs sizing otherwise crowds this row on narrow screens. */
  .typing-header-controls .btn-xs { padding: .3rem .65rem; font-size: .78rem; }
  .typing-header-controls .typing-font-controls .btn { min-width: 1.9rem; }
  .typing-mode-badge-timer { font-size: .88rem; padding: .4rem .8rem; }
  /* The 3-column grid (controls / title / badge) squeezes the controls into a narrow left
     column on phones, forcing every button onto its own line and the badge into a tall
     oval. Stack instead: title on top, then controls and badge each as their own centered,
     wrapping row with the full width to spread across. */
  .exam-mode .typing-page-header {
    display: flex; flex-direction: column; gap: .5rem;
  }
  .exam-mode .typing-page-header h1 { order: -1; font-size: 1rem; }
  .exam-mode .typing-header-controls { justify-content: center; }
  .exam-mode .typing-mode-badge-timer { align-self: center; }
  /* Lesson/practice mode's header (a plain flex row, not the 3-column grid .exam-mode uses
     above) had no mobile stacking of its own: title, toolbar, and the mode badge would all
     fight for space on one wrapped row. Stack it the same way exam mode already does — this
     general rule also reaches exam-mode's header, but its own more specific rule above
     already sets the identical flex-direction:column, so there's no conflict either way. */
  .typing-page-header { flex-direction: column; align-items: stretch !important; }
  .typing-page-header h1 { text-align: center; font-size: 1rem; }
  .typing-page-header .typing-header-controls { justify-content: center; }
  .typing-page-header .typing-mode-badge { align-self: center; }
  .typing-settings-menu { max-width: calc(100vw - 2rem); min-width: 0; }
  /* 5 stat tiles in a 2-column grid leave the last one (Timer) orphaned alone on its own
     row — give it the full width instead of looking like a stray half-empty row. */
  .typing-stats-bar .typing-stat:last-child { grid-column: 1 / -1; }
  .typing-settings-grid { grid-template-columns: 1fr; }
}
