/* ── AulaAI Design System ─────────────────────────────── */
/* Student Portal */
.classroom-grid {
    display: grid;
    /* auto-fit (not auto-fill) so one class stretches to fill the row rather
       than sitting in a 300px box beside an empty track. */
    grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
    gap: var(--space-6);
}

.classroom-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    cursor: pointer;
    transition: var(--transition);
    display: flex;
    flex-direction: column;
    position: relative;
    text-align: left;
}

.classroom-card:hover {
    transform: translateY(-3px);
    border-color: var(--accent);
    box-shadow: var(--shadow-lg);
}

.classroom-card-header {
    padding: 24px;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
}

.classroom-icon {
    font-size: 28px;
    background: var(--bg-secondary);
    width: 56px;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius);
    border: 1px solid var(--border);
}

.classroom-status {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.8px;
    padding: 4px 10px;
    border-radius: 12px;
}

.classroom-status.approved {
    background: var(--success-bg);
    color: var(--success);
    border: 1px solid rgba(16, 185, 129, 0.15);
}

.classroom-status.pending {
    background: var(--warning-bg);
    color: var(--warning);
    border: 1px solid rgba(245, 158, 11, 0.15);
}

.classroom-card-body {
    padding: 0 24px 20px;
    flex: 1;
}

.classroom-name {
    font-size: 18px;
    font-weight: 700;
    color: var(--text-primary);
    margin-bottom: 6px;
    letter-spacing: -0.02em;
}

.classroom-meta {
    font-size: 13px;
    color: var(--text-muted);
    font-weight: 500;
}

.classroom-card-footer {
    padding: 14px 24px;
    background: rgba(255,255,255,0.01);
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-top: 1px solid var(--border);
}

[data-theme="light"] .classroom-card-footer {
    background: rgba(0,0,0,0.01);
}

.classroom-code {
    /* Was a hardcoded `'JetBrains Mono', monospace`, which fell past the
       unloaded family to the generic monospace — Courier on iOS — while the
       rest of the app's codes fell to ui-monospace. One token, one face. */
    font-family: var(--font-mono);
    font-weight: 700;
    color: var(--accent-light);
    font-size: 13px;
}

.classroom-arrow {
    font-size: 16px;
    color: var(--text-muted);
    transition: var(--transition);
}

.classroom-card:hover .classroom-arrow {
    transform: translateX(3px);
    color: var(--accent);
}

@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
    .classroom-grid {
        grid-template-columns: 1fr;
    }
}

/* Palette.
   The identity — deep academic navy, classic gold — is unchanged. What is new
   is that the legacy background and border aliases now resolve to the surface
   ladder in foundation.css, so there is one definition of "card background"
   in the product instead of four that drifted apart.
   Scales (radius, shadow, spacing, type, transition) live in foundation.css
   and are deliberately NOT redeclared here. */
:root {
  --bg-primary: var(--surface-0);
  --bg-secondary: var(--surface-2);
  --bg-card: var(--surface-1);
  --bg-card-hover: var(--surface-hover);
  --bg-input: var(--surface-3);
  --border: var(--line);
  --border-light: var(--line-subtle);
  --text-primary: #ffffff;
  --text-secondary: rgba(255, 255, 255, 0.72);
  --text-muted: rgba(255, 255, 255, 0.48);
  --accent: #c5a059;          /* Classic gold */
  --accent-light: #d6b87d;
  --accent-glow: rgba(197, 160, 89, 0.10);
  --accent-contrast: #0a1626; /* Text that sits on a gold fill */
  --success: #34d399;
  --success-bg: rgba(52, 211, 153, 0.10);
  --warning: #fbbf24;
  --warning-bg: rgba(251, 191, 36, 0.10);
  --danger: #f87171;
  --danger-bg: rgba(248, 113, 113, 0.10);
  --info: #60a5fa;
  --info-bg: rgba(96, 165, 250, 0.10);
  --gradient-1: linear-gradient(135deg, #0b2f61, #132b4d);
  --gradient-2: linear-gradient(135deg, #c5a059, #b89047);
  --gradient-3: linear-gradient(135deg, #c5a059, #8c6b2d);
  --bg-main: var(--surface-0);
  --text-main: #ffffff;
}

[data-theme="light"] {
  --text-primary: #0b2f61;    /* Deep navy for a strong academic feel */
  --text-secondary: #41526b;
  /* #5b6b85 clears 4.5:1 against every light surface it is used on — white
     cards (5.40), the recessed #f7f9fc well (5.12) and the #e9ecf1 chip fill
     (4.56). The previous value passed on white by eye but measured 4.23, and
     failed outright on the tinted surfaces. */
  --text-muted: #5b6b85;
  --accent: #0b2f61;          /* Deep navy accent */
  --accent-light: #16468a;
  --accent-glow: rgba(11, 47, 97, 0.06);
  --accent-contrast: #ffffff;
  --success: #15803d;
  --success-bg: rgba(21, 128, 61, 0.08);
  --warning: #b45309;
  --warning-bg: rgba(180, 83, 9, 0.08);
  --danger: #b91c1c;
  --danger-bg: rgba(185, 28, 28, 0.07);
  --info: #1d4ed8;
  --info-bg: rgba(29, 78, 216, 0.07);
  --bg-main: var(--surface-0);
  --text-main: #0b2f61;
  --gradient-1: linear-gradient(135deg, #0b2f61, #16468a);
  --gradient-2: linear-gradient(135deg, #0b2f61, #3a78b4);
  --gradient-3: linear-gradient(135deg, #16468a, #0b2f61);
}

*, *::before, *::after { 
  box-sizing: border-box; 
  margin: 0; 
  padding: 0; 
  scrollbar-width: thin;
  scrollbar-color: var(--border-light) transparent;
}

/* Custom Scrollbar Integration */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-light); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  -webkit-text-size-adjust: 100%;
  background: var(--bg-primary);
}
/* `overflow-x: hidden` and `position: relative` used to sit on BOTH html and
   body. On the root element that turns the document itself into a scroll
   container, and iOS then stops painting the page background into the strips
   its toolbars vacate as they collapse and expand — which is the black bands
   at the top and bottom, and the jitter while they animate. Horizontal
   clipping belongs on the body, where it does the same job without owning
   the document's scrolling. */
body {
  overflow-x: hidden;
  position: relative;
}
/* Turns off pull-to-refresh. `contain` and not `none`: contain stops the
   gesture chaining out to the browser, which is the refresh; `none` would
   additionally kill the rubber-band bounce, and an earlier attempt at that
   is what made the page feel glitchy. It has to sit on `html` — unlike
   `overflow`, overscroll-behavior set on `body` does not propagate to the
   viewport, so on the body it would do nothing here. */
html {
  overscroll-behavior-y: contain;
}

body {
  font-family: var(--font-ui);
  line-height: 1.6;
  color: var(--text-primary);
  /* On iOS `100vh` is the LARGE viewport — the height the page WOULD have if
     Safari's toolbars were collapsed. While they are showing, a body pinned to
     100vh is ~90-140px taller than the visual viewport, so every screen is
     scrollable by exactly that much even when its content fits, and the strip
     the content does not cover publishes page background. That is the band
     along the bottom, and (once scrolled) the navy hero filling the top.
     `100dvh` is the viewport as it actually is right now; the `100vh` line
     above it stays as the fallback for browsers without dvh. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6, .classroom-name, .logo-mark, .card-header h3, .modal-content h2, .modal-content h3 {
  font-family: var(--font-ui);
  font-weight: 700;
  letter-spacing: -0.025em;
}

.nav-title, .hero-subtitle, .btn, .stat-value, .nav-badge, .nav-tab, .tab-label, .form-input, .text-input, .text-muted, .subtitle {
  font-family: var(--font-ui);
  letter-spacing: normal;
}

/* ── Screens ─────────────────────────────────────────── */
/* No viewport floor. A screen is as tall as what it holds, so a short page
   ends just after its content instead of padding out to a full screen and
   leaving a gap beneath it. The body keeps min-height:100dvh, so the page
   background still covers the screen — it is the empty box that is gone, not
   the backdrop. */
.screen { display: none; }
/* A page with less on it than fits sits in the middle of the screen rather than
   at the top with the remainder below it. The auto margins go on the ends of
   the body's flex column — the top of the screen and the bottom of the notice —
   so the two centre together as one block and stay adjacent; putting one on the
   screen alone would have centred the page and thrown the notice to the floor.
   Free space only: when the content is taller than the viewport both resolve to
   zero and nothing moves. */
@media (max-width: 1024px) {
  /* Normal app screens stay in document flow. Never globally centre them. */
  .screen.active { margin-top: 0; }
  .site-footer { margin-bottom: 0; }
  body:has(> .screen.active:not(#login-screen)) { padding-top: 0; padding-bottom: 0; }
}
.screen.active { display: block; animation: fadeIn 0.4s ease; }
/* Login must appear in its final position immediately. On iOS, even a tiny
   translate animation reads as the whole sign-in screen settling after paint. */
#login-screen.screen.active { animation: none; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* ── Spinners ── */
.spinner {
  width: 32px;
  height: 32px;
  border: 3px solid var(--border);
  border-top: 3px solid var(--accent);
  border-radius: 50%;
  animation: spin 0.8s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
  box-shadow: 0 0 12px var(--accent-glow);
}

.spinner-small {
  width: 20px;
  height: 20px;
  border: 2.5px solid var(--border);
  border-top: 2.5px solid var(--accent);
  border-radius: 50%;
  animation: spin 0.8s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
  box-shadow: 0 0 8px var(--accent-glow);
  flex-shrink: 0;
}

/* ── Progress Bars ── */
.progress-bar-container {
  width: 100%;
  height: 8px;
  background: var(--bg-input);
  border-radius: 10px;
  overflow: hidden;
  margin: 12px 0;
  border: 1px solid var(--border);
}

.progress-bar-fill {
  height: 100%;
  background: var(--gradient-1);
  width: 0%;
  transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
}

.progress-bar-fill::after {
  content: '';
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
  animation: shine 2s infinite;
}

@keyframes shine {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
.no-scroll { overflow: hidden !important; }

/* ── Login ───────────────────────────────────────────── */
.login-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 100vh;
  min-height: 100dvh;
}
.login-hero {
  background: #09162a; /* Solid academic navy */
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
  border-right: 1px solid var(--border);
}
[data-theme="light"] .login-hero {
  background: #f1f3f7; /* Solid warm academic cream-gray */
  border-right: 1px solid var(--border);
}
/* Hero Branding Header */
.hero-branding {
  position: absolute;
  top: 32px;
  left: 32px;
  display: flex;
  align-items: center;
  gap: 12px;
  z-index: 10;
}
.hero-logo-img {
  height: 40px;
  width: auto;
}
.hero-branding-text {
  display: flex;
  flex-direction: column;
}
.hero-branding-title {
  font-family: var(--font-ui);
  font-size: 18px;
  font-weight: 800;
  color: #fff;
  line-height: 1.1;
  letter-spacing: -0.02em;
}
[data-theme="light"] .hero-branding-title {
  color: var(--text-primary);
}
.hero-branding-sub {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.4);
  font-weight: 500;
}
[data-theme="light"] .hero-branding-sub {
  color: var(--text-secondary);
}

/* ── Academic & Institutional Showcase ───────────────── */
.hero-minimal-showcase {
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 36px;
  animation: fadeIn 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.hero-value-statement {
  text-align: left;
  border-left: 3px solid var(--accent); /* Gold accent line */
  padding-left: 20px;
}

[data-theme="light"] .hero-value-statement {
  border-left-color: var(--accent); /* Navy accent line */
}

.hero-value-title {
  font-family: var(--font-ui);
  font-size: 26px;
  font-weight: 700;
  line-height: 1.3;
  color: #ffffff;
  margin-bottom: 12px;
  letter-spacing: -0.02em;
}

[data-theme="light"] .hero-value-title {
  color: var(--accent);
}

.hero-value-subtitle {
  font-size: 14px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.7);
  font-weight: 400;
}

[data-theme="light"] .hero-value-subtitle {
  color: #3b4b61;
}

/* Academic Sheet Container */
.academic-sheet {
  background: #0f2440;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 4px; /* Classic sharp academic look */
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
  overflow: hidden;
  transition: border-color var(--transition);
}

[data-theme="light"] .academic-sheet {
  background: #ffffff;
  border: 1px solid #dcdfe6;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}

.academic-sheet:hover {
  border-color: color-mix(in srgb, var(--accent) 50%, transparent); /* Gold hover accent */
}

[data-theme="light"] .academic-sheet:hover {
  border-color: #a5b6cf;
}

/* Sheet Header */
.sheet-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-7);
  border-bottom: 1px solid var(--line-subtle);
  background: var(--surface-3);
}
.sheet-header > .sheet-title { min-width: 0; }

[data-theme="light"] .sheet-header {
  border-bottom: 1px solid #dcdfe6;
  background: #f7f9fc;
}

.sheet-title {
  font-family: var(--font-ui);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--accent); /* Gold title */
}

[data-theme="light"] .sheet-title {
  color: var(--accent);
}

/* Sheet Level Link Toggles */
.sheet-toggles {
  display: flex;
  align-items: center;
  /* Each toggle keeps its label on one line, so the row has to be allowed to
     wrap — otherwise three language names overflow a 320px card. */
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
  font-family: var(--font-ui);
  font-size: var(--fs-xs);
  min-width: 0;
}

.sheet-toggle-btn {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  /* Was 22px tall on a touch screen. The visible type stays small; the target
     does not. */
  min-height: max(var(--control-sm), var(--tap-min));
  background: none;
  border: none;
  font-family: inherit;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  cursor: pointer;
  padding: 0 var(--space-4);
  border-radius: var(--radius-sm);
  transition: color var(--transition-fast);
}

[data-theme="light"] .sheet-toggle-btn {
  color: var(--text-muted);
}

.sheet-toggle-btn:hover {
  color: #ffffff;
}

[data-theme="light"] .sheet-toggle-btn:hover {
  color: var(--accent);
}

.sheet-toggle-btn.active {
  color: var(--accent) !important;
  font-weight: 700;
}

[data-theme="light"] .sheet-toggle-btn.active {
  color: var(--accent) !important;
}

.toggle-separator {
  color: rgba(255, 255, 255, 0.15);
  pointer-events: none;
}

[data-theme="light"] .toggle-separator {
  color: #dcdfe6;
}

/* Sheet Body */
.sheet-body {
  padding: 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.sheet-sentence-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.sheet-sentence {
  font-family: var(--font-ui);
  font-size: 16px;
  font-weight: 500;
  line-height: 1.55;
  color: #ffffff;
  margin: 0;
}

[data-theme="light"] .sheet-sentence {
  color: var(--accent);
}

/* Explanation text is read-only — no pointer cursor anywhere inside */
.ai-explanation,
.ai-explanation * {
  cursor: default !important;
}

/* Words in the target language. They used to open a dictionary on a tap,
   and looked like links for it (pointer, underline, a colour on hover).
   That feature is gone, so they are plain text again. */
.foreign-word {
  position: relative;
  display: inline-block;
}

/* Academic Audio Link Button */
.tts-link-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px;
  color: rgba(255, 255, 255, 0.4);
  transition: color 0.2s ease, transform 0.1s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 2px;
}

[data-theme="light"] .tts-link-btn {
  color: var(--text-muted);
}

.tts-link-btn:hover {
  color: var(--accent);
}

[data-theme="light"] .tts-link-btn:hover {
  color: var(--accent);
}

.tts-link-btn:active {
  transform: scale(0.95);
}

.tts-link-btn.playing {
  color: var(--accent) !important;
}

[data-theme="light"] .tts-link-btn.playing {
  color: var(--accent) !important;
}

/* Formal Sheet Translation Block */
.sheet-translation {
  font-family: var(--font-ui);
  font-size: 13.5px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.65);
  padding: 10px 14px;
  background: rgba(0, 0, 0, 0.1);
  border-left: 2px solid var(--accent);
}

[data-theme="light"] .sheet-translation {
  color: #404f66;
  background: #f7f9fc;
  border-left: 2px solid var(--accent);
}

.sheet-translation-label {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--accent);
}

[data-theme="light"] .sheet-translation-label {
  color: var(--accent);
}

/* Sheet Footer */
.sheet-footer {
  padding: 10px 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(0, 0, 0, 0.1);
  text-align: center;
}

[data-theme="light"] .sheet-footer {
  border-top: 1px solid #dcdfe6;
  background: #f7f9fc;
}

.sheet-tip {
  font-family: var(--font-ui);
  font-size: 10px;
  color: rgba(255, 255, 255, 0.4);
  font-weight: 500;
}

[data-theme="light"] .sheet-tip {
  color: var(--text-muted);
}


/* Hero Footer Sub */
.hero-footer-sub {
  position: absolute;
  bottom: 32px;
  left: 32px;
  font-family: var(--font-ui);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--text-muted);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
}
.login-form-section {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 48px 80px;
  background: var(--bg-secondary);
}
/* The desktop hero carries the branding beside the form, so the phone-only
   brand mark stays out of the way here. */
.login-form-brand { display: none; }
.login-form-section h2 {
  font-family: var(--font-ui);
  font-size: 24px;
  font-weight: 700;
  margin-bottom: 6px;
  letter-spacing: -0.02em;
  color: var(--text-primary);
}
.login-hint {
  color: var(--text-secondary);
  margin-bottom: 28px;
  font-size: 14px;
}
.login-legal { margin: 0; }
.login-footer {
  margin-top: 24px;
  font-size: 12px;
  color: var(--text-secondary);
  text-align: center;
  line-height: 1.5;
}
/* Kept deliberately small and quiet, because it is paying for itself in
   vertical space: the phone login form already stands ~16px taller than a
   700px viewport before this line exists. 11px type and a plain margin — no
   rule, no padding block — hold the cost to ~25px rather than ~40px, and the
   muted colour keeps it reading as a footer mark rather than a third
   sentence after the privacy line. */
/* Ordinary text at the end of the page. It is the last child of <body>, which
   is a column flex container, so it follows whichever screen is active and
   scrolls with the content — off the bottom of a short page until you scroll
   for it, and gone again when you scroll back. No border, no bar, no reserved
   band: it behaves like every other line of text on the site. */
.site-footer {
  flex-shrink: 0;
  /* Ordinary spacing, top and bottom — the page ends just after this line
     instead of trailing a screen of nothing. The reserve that used to sit here
     existed only to keep the text out from under the floating theme/language
     pill; aligning to the leading edge does that for free, because the pill is
     in the opposite corner. */
  padding: var(--space-5) var(--gutter-safe) calc(var(--space-5) + env(safe-area-inset-bottom, 0px));
  text-align: start;
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-muted);
  letter-spacing: 0.01em;
}
/* On the login screen the notice is simply the next line after the privacy
   sentence, inside the form, laid out by the same rules. No page-level footer
   there at all, so nothing sits below a fold and nothing can reveal it by
   scrolling — there is nothing to scroll. */
.login-copyright {
  margin-top: 10px;
  font-size: 11px;
  color: var(--text-muted);
  letter-spacing: 0.01em;
}
body:has(#login-screen.active) .site-footer { display: none; }
.login-footer-link {
  color: var(--accent-light);
  text-decoration: none;
  font-weight: 600;
  transition: all 0.2s ease;
}
[data-theme="light"] .login-footer-link {
  color: var(--accent);
}
.login-footer-link:hover {
  color: var(--accent);
  text-decoration: underline;
}
[data-theme="light"] .login-footer-link:hover {
  color: var(--accent-light);
}

.modal-scroll-area::-webkit-scrollbar {
  width: 6px;
}
.modal-scroll-area::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.02);
  border-radius: 3px;
}
[data-theme="light"] .modal-scroll-area::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.02);
}
.modal-scroll-area::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 3px;
}
[data-theme="light"] .modal-scroll-area::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.1);
}
.modal-scroll-area h4 {
  color: #fff;
}
[data-theme="light"] .modal-scroll-area h4 {
  color: var(--text-primary);
}

/* Segmented Tabs Switcher */
.login-tabs-wrapper {
  display: flex;
  background: rgba(0, 0, 0, 0.2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 3px;
  margin-bottom: 28px;
  position: relative;
}
[data-theme="light"] .login-tabs-wrapper {
  background: rgba(0, 0, 0, 0.04);
}
.login-tab-btn {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 9px 12px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 7px;
  color: var(--text-secondary);
  font-family: var(--font-ui);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.login-tab-btn:hover {
  color: var(--text-primary);
}
.login-tab-btn.active {
  background: var(--bg-card);
  color: var(--text-primary);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  border-color: var(--border-light);
}
[data-theme="light"] .login-tab-btn.active {
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  border-color: rgba(0, 0, 0, 0.06);
}

/* Theme / language switcher */
.lang-switcher {
  background: var(--surface-nav);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: var(--space-2);
  box-shadow: var(--shadow-lg);
  transition: border-color var(--transition-fast);
}
.lang-switcher:hover { border-color: var(--line-strong); }

/* The floating pill is the only way to reach theme and language on the signed
   out and classroom-picker screens, so it lives there. Inside a dashboard the
   nav bar and the drawer already carry both controls, and a fixed pill in the
   bottom-right corner sat on top of page content on every phone screen —
   including, on the overview tab, directly over the reset-classroom button.
   So it stands down wherever a dashboard is the active screen. */
.floating-actions {
  position: fixed;
  bottom: max(var(--space-8), env(safe-area-inset-bottom, 0px));
  right: var(--space-8);
  z-index: var(--z-sticky);
}

body:has(#lecturer-dashboard.active) .floating-actions,
body:has(#student-dashboard.active) .floating-actions {
  display: none;
}
/* Where the pill does float, the screen under it reserves room so it never
   sits on top of the last line of content.

   The login screen is excluded: it is sized to exactly one viewport, so adding
   the reserve OUTSIDE that height made the page taller than the screen and
   published a strip of page background below it. It reserves the same room
   inside its own hero instead, where it costs no document height. */
/* No pill reserve on the screen itself any more. The footer follows every
   screen and stands 41px tall plus the safe-area inset, and the content
   container keeps its own 24px, so the last card already ends ~99px above the
   bottom of the page — well clear of the 70px the pill occupies. Reserving
   another 40px here only pushed the notice away from the content it belongs
   under. */
.action-pill-container {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3) !important;
}
/* Compact by design. This control floats over page content, so it shows the
   theme icon and a two-letter language code rather than "Theme: Dark | TR" —
   a 160px label bar parked over a data table is obstruction, not affordance.
   The full labels stay available to assistive tech and as tooltips. */
.floating-actions #global-theme-toggle-text {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
.floating-actions .btn-lang { padding-inline: var(--space-5); gap: var(--space-3); }
.floating-actions .lang-icon { display: none; }
.action-separator {
  color: var(--border);
  font-size: 14px;
  opacity: 0.4;
  pointer-events: none;
  user-select: none;
}
/* Study Vocab Card Styling */
.study-vocab-card {
  background: var(--bg-input);
  padding: 16px 20px;
  border-radius: 12px;
  border: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
  cursor: default;
  width: 100%;
  box-sizing: border-box;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.study-vocab-card:hover {
  border-color: var(--accent-line);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
}

.vocab-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  width: 100%;
}
.vocab-term-wrapper {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
}

.vocab-term-text {
  flex: 1;
  padding: 0 4px;
}

.vocab-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.vocab-meaning-pill {
  font-weight: 700;
  font-size: 14.5px;
  line-height: 1.3;
  color: var(--text-primary);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  padding: 4px 12px;
  border-radius: 20px;
  letter-spacing: 0.2px;
  white-space: nowrap;
}

[data-theme="light"] .vocab-meaning-pill {
  background: var(--accent-glow);
  border-color: var(--accent-line);
  color: var(--accent);
}

.vocab-pos-badge {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent-line);
}

.vocab-pedagogy-section {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text-secondary);
  background: rgba(255, 255, 255, 0.025);
  border-left: 3px solid var(--accent);
  padding: 8px 12px;
  border-radius: 0 8px 8px 0;
  text-align: left;
}

[data-theme="light"] .vocab-pedagogy-section {
  background: rgba(0, 0, 0, 0.02);
}

.vocab-pedagogy-section svg {
  flex-shrink: 0;
  margin-top: 3px;
  color: var(--accent);
  opacity: 0.9;
}

.vocab-example-card {
  background: rgba(0, 0, 0, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 8px;
  padding: 10px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-align: left;
}

[data-theme="light"] .vocab-example-card {
  background: rgba(0, 0, 0, 0.03);
  border-color: rgba(0, 0, 0, 0.06);
}

.vocab-example-target-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.vocab-example-target {
  font-size: 14px;
  font-weight: 600;
  font-style: italic;
  color: var(--text-primary);
  line-height: 1.45;
}

.vocab-example-trans {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.4;
}

.study-vocab-card .english-translation {
  color: var(--text-secondary);
  font-weight: 500;
  font-size: 14px;
  text-align: left;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
}

.study-vocab-card .vocab-meaning-title {
  font-weight: 700;
  color: var(--text-primary);
  font-size: 14.5px;
  line-height: 1.3;
}

.study-vocab-card .vocab-brief-explanation {
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--text-secondary);
  font-weight: 400;
  opacity: 0.9;
  text-align: left;
}
.alphabet-pronunciation-block {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
}
.phonetic-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--accent-light);
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.3px;
}
[data-theme="light"] .phonetic-badge {
  background: rgba(79, 70, 229, 0.1);
  color: #4338ca;
}
.vocab-example-block {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed rgba(255, 255, 255, 0.08);
  width: 100%;
}
[data-theme="light"] .vocab-example-block {
  border-top-color: rgba(0, 0, 0, 0.08);
}
.vocab-example-target {
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--text-primary);
  font-style: italic;
}
.vocab-example-trans {
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-secondary);
  margin-top: 2px;
}

.btn-lang {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  min-height: max(var(--control-md), var(--tap-min));
  min-width: max(var(--control-md), var(--tap-min));
  padding: 0 var(--space-6);
  background: transparent;
  border: none;
  border-radius: var(--radius-pill);
  color: var(--text-secondary);
  font-family: var(--font-ui);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}
.btn-lang:hover { color: var(--text-primary); }
.btn-lang:hover {
  color: var(--text-primary);
}
.lang-icon {
  width: 15px;
  height: 15px;
  color: var(--accent-light);
}

/* Method Cards Redesign */
.method-card {
  background: var(--bg-input);
  border: 1px solid var(--border);
  padding: 28px 24px;
  border-radius: 16px;
  cursor: pointer;
  transition: var(--transition);
  text-align: left;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.method-card:hover {
  transform: translateY(-2px);
  border-color: var(--accent);
  box-shadow: var(--shadow-lg);
}
.method-card.active-method {
  border-color: var(--accent);
}
.method-icon-wrapper {
  margin-bottom: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 12px;
  transition: var(--transition);
}
.method-icon-wrapper svg {
  width: 24px;
  height: 24px;
}
.method-icon-wrapper.pdf, .method-icon-wrapper.ai {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  color: var(--accent);
}
.method-card:hover .method-icon-wrapper.pdf, .method-card:hover .method-icon-wrapper.ai {
  background: var(--accent);
  color: var(--bg-primary);
}

/* ── Forms ───────────────────────────────────────────────
   Labels are sentence case, not uppercase micro-type: a form is read, not
   scanned, and uppercase 13px with letter-spacing is the single biggest
   reason the create flows read as a template rather than a product. */
.form-group { margin-bottom: var(--space-7); }
.form-group label {
  display: block;
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text-secondary);
  margin-bottom: var(--space-3);
  text-transform: none;
  letter-spacing: var(--ls-normal);
}
.form-group input, .form-group select, .form-group textarea,
.text-input, .select-input {
  width: 100%;
  min-height: max(var(--control-lg), var(--tap-min));
  padding: var(--space-4) var(--space-5);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-primary);
  font-size: var(--fs-md);
  font-family: inherit;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.form-group textarea { min-height: 96px; line-height: var(--lh-normal); resize: vertical; }
.form-group input:hover, .text-input:hover, .select-input:hover { border-color: var(--line-strong); }
.form-group input:focus, .form-group select:focus, .form-group textarea:focus,
.text-input:focus, .select-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}
.form-group input:disabled, .text-input:disabled, .select-input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
/* 16px is the threshold below which iOS zooms the viewport on focus. */
@media (pointer: coarse) {
  .form-group input, .form-group select, .form-group textarea,
  .text-input, .select-input { font-size: 16px; }
}

/* ── Buttons ─────────────────────────────────────────────
   Four weights and one size ladder. Primary is gold and is meant to appear
   once per view; secondary is a bordered navy; ghost carries no chrome until
   you touch it; danger is reserved for destruction. Sizes come from
   --control-*, so nothing sets its own height any more. */
.btn {
  --btn-h: var(--control-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  min-height: max(var(--btn-h), var(--tap-min));
  padding: 0 var(--space-6);
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-family: inherit;
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-snug);
  line-height: 1.25;
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
  -webkit-tap-highlight-color: transparent;
}

/* Primary: the one gold action. Gold on navy needs dark text to stay legible. */
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-contrast);
}
.btn-primary:hover { background: var(--accent-light); border-color: var(--accent-light); }
.btn-primary:active { background: var(--accent); }

/* Secondary: structure without shouting. */
.btn-outline,
.btn-secondary {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-primary);
}
.btn-outline:hover, .btn-secondary:hover {
  border-color: var(--line-strong);
  background: var(--surface-hover);
}
[data-theme="light"] .btn-outline:hover, [data-theme="light"] .btn-secondary:hover {
  background: var(--surface-3);
}

/* Ghost: for tertiary and in-toolbar actions. */
.btn-ghost { background: transparent; color: var(--text-secondary); }
.btn-ghost:hover { color: var(--text-primary); background: var(--surface-hover); }
[data-theme="light"] .btn-ghost:hover { background: var(--surface-3); }

.btn-success { background: var(--success); border-color: var(--success); color: var(--accent-contrast); }
.btn-danger  { background: var(--danger);  border-color: var(--danger);  color: #fff; }
/* Destructive actions that are not the main event: readable, clearly hazardous,
   but not competing with the primary button for attention. */
.btn-danger-quiet {
  background: var(--danger-bg);
  border-color: var(--tone-line, rgba(248, 113, 113, 0.32));
  color: var(--danger);
}
.btn-danger-quiet:hover { background: var(--danger); border-color: var(--danger); color: #fff; }

.btn-full { width: 100%; }
.btn-xs { --btn-h: var(--control-xs); padding: 0 var(--space-4); font-size: var(--fs-xs); gap: var(--space-3); }
.btn-sm { --btn-h: var(--control-sm); padding: 0 var(--space-5); font-size: var(--fs-sm); }
.btn-lg { --btn-h: var(--control-lg); padding: 0 var(--space-8); font-size: var(--fs-md); }

.btn:disabled, .btn[disabled] { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
.btn > svg { width: var(--icon); height: var(--icon); flex-shrink: 0; }

.error-msg { color: var(--danger); font-size: 14px; margin-top: 12px; text-align: center; }
.hidden { display: none !important; }
/* Controls only an administrator sees (the body gets .is-admin at sign-in). */
.admin-only { display: none !important; }
body.is-admin .admin-only { display: inline-flex !important; }
/* Only in a local copy, where an administrator may import a class. */
.import-only { display: none !important; }
body.can-import-class .import-only { display: inline-flex !important; }

.demo-accounts { margin-top: 32px; border-top: 1px solid var(--border); padding-top: 24px; }
.demo-title { font-size: 12px; text-transform: uppercase; letter-spacing: 1px; color: var(--text-muted); margin-bottom: 12px; }
.demo-btn {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 16px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 14px;
  cursor: pointer;
  transition: var(--transition);
  margin-bottom: 8px;
}

/* ── Navigation ──────────────────────────────────────── */
.topnav {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding-inline: var(--gutter-safe);
  height: var(--topnav-h);
  /* Was a hardcoded rgba(14,18,29,.75) that matched nothing in the palette,
     which is why the bar read as a different, greyer navy than the page. */
  background: var(--surface-nav);
  border-bottom: 1px solid var(--border);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-topnav);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}
[data-theme="light"] .topnav { background: var(--surface-nav); }
.nav-brand {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-right: var(--space-2);
  flex-shrink: 0;
  min-width: 0;
}
.nav-logo { font-size: 20px; }
.nav-logo-img { height: 28px; width: auto; object-fit: contain; }
.nav-title { font-size: 16px; font-weight: 700; color: var(--text-primary); }
.nav-badge {
  padding: 2px 8px;
  background: var(--gradient-1);
  border-radius: 20px;
  font-size: 10px;
  font-weight: 700;
  white-space: nowrap;
  color: #fff;
  text-transform: uppercase;
  letter-spacing: 0.8px;
}
.student-badge { background: linear-gradient(135deg, #10b981, #059669); }
/* The tab row is the nav's flexible zone. min-width:0 lets it yield to the
   fixed zones, and overflow-x means that if it ever does run out of room the
   tabs scroll instead of being silently clipped at the right edge — which is
   what was happening at 1280-1440px, where "Messages" disappeared under the
   account controls. */
.nav-tabs {
  display: flex;
  gap: var(--space-1);
  flex: 1 1 auto;
  min-width: 0;
  justify-content: center;
  overflow-x: auto;
  scrollbar-width: none;
}
.nav-tabs::-webkit-scrollbar { display: none; }
.nav-tab {
  height: var(--control-sm);
  padding: 0 var(--space-4);
  flex: 0 0 auto;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius);
  color: var(--text-secondary);
  font-family: var(--font-ui);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.nav-tab:hover {
  color: var(--text-primary);
  background: var(--fill-hover);
}
.nav-tab.active {
  color: var(--text-primary);
  background: var(--accent-glow);
  border-color: var(--accent-glow);
}
[data-theme="light"] .nav-tab.active {
  background: var(--accent-glow);
  border-color: var(--border);
  color: var(--accent);
}
.nav-user { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-secondary); margin-left: 12px; flex-shrink: 0; }
.topnav .btn { padding: 6px 12px; font-size: 12px; height: 32px; }

.tab-icon, .sidebar-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tab-icon svg, .sidebar-icon svg {
  width: 15px;
  height: 15px;
  stroke: currentColor;
  stroke-width: 2px;
  display: block;
  transition: var(--transition);
}
.nav-tab .tab-icon svg {
  color: var(--text-secondary);
}
.nav-tab:hover .tab-icon svg {
  color: var(--text-primary);
}
.nav-tab.active .tab-icon svg {
  color: var(--text-primary);
}
[data-theme="light"] .nav-tab.active .tab-icon svg {
  color: var(--accent);
}

/* ── Dashboard Content ───────────────────────────────── */
.dashboard-content { max-width: 1280px; margin: 0 auto; padding: 84px 24px 32px; }
/* The study surfaces are wider than the rest of the product, but they keep the
   same side gutter — a 20px inset here against a 16px page gutter elsewhere is
   exactly the kind of 4px drift that makes tabs feel like separate apps. */
.dashboard-content:has(#tab-study-materials.active),
.dashboard-content:has(#tab-s-study-tab.active) {
  max-width: var(--container-wide);
}

@keyframes tabFadeSlide {
  0% {
    opacity: 0;
    transform: translateY(8px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.tab-panel { 
  display: none; 
}

.tab-panel.active { 
  display: block; 
  animation: tabFadeSlide 0.22s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@media (prefers-reduced-motion: reduce) {
  .tab-panel.active {
    animation: none;
  }
}

/* ── Page header ─────────────────────────────────────────
   Title and its supporting line form one block on the left; page actions sit
   on the right and drop below the title when there is no room for both. The
   old rule let a 28px h1 and the action share one line at any width, which is
   why the mobile dashboard title collided with the greeting beside it. */
.page-header {
  margin-bottom: var(--space-9);
  /* A two-column grid with explicit placement, because the markup uses two
     shapes: sometimes <h1> and <p class="subtitle"> are direct siblings,
     sometimes they are wrapped in a div next to an action. With flex and
     space-between, the first shape threw the subtitle to the far right of the
     screen, a thousand pixels from the title it belongs to. */
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  column-gap: var(--space-8);
  row-gap: var(--space-4);
}
.page-header > h1            { grid-area: 1 / 1 / 2 / 2; min-width: 0; }
.page-header > .subtitle     { grid-area: 2 / 1 / 3 / 2; min-width: 0; }
.page-header > div:first-child { grid-area: 1 / 1 / 3 / 2; min-width: 0; }
.page-header > .page-actions,
.page-header > .btn,
.page-header > button {
  grid-area: 1 / 2 / 3 / 3;
  justify-self: end;
  align-self: end;
}
.page-header h1 {
  font-size: var(--fs-4xl);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-tight);
}
.page-header .subtitle { margin-top: var(--space-3); }
/* Action cluster on the right of a page header. */
.page-header .page-actions {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex: 0 0 auto;
  flex-wrap: wrap;
}
.subtitle { color: var(--text-secondary); font-size: var(--fs-md); line-height: var(--lh-snug); }

/* ── Stats ───────────────────────────────────────────────
   A metric row is a scoreboard, not a colour chart. Values are plain text in
   the primary colour and only take a status colour when the status is the
   point. The old .accent painted the number with the navy page gradient and
   clipped it to the glyphs, which made it almost invisible on a navy card. */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
  gap: var(--space-5);
  margin-bottom: var(--space-9);
}
.stat-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-7);
  transition: border-color var(--transition-fast);
}
.stat-card:hover { border-color: var(--line-strong); }
.stat-label {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--text-muted);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
}
.stat-value {
  font-size: var(--fs-5xl);
  font-weight: var(--fw-bold);
  color: var(--text-primary);
  margin-top: var(--space-4);
  letter-spacing: var(--ls-tight);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.stat-sub {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  margin-top: var(--space-3);
  line-height: var(--lh-snug);
}
/* Status variants stay available for the metrics where the colour carries
   meaning (at-risk counts, failing averages) rather than decorating. */
.stat-value.accent  { color: var(--text-primary); }
.stat-value.success { color: var(--success); }
.stat-value.warning { color: var(--warning); }
.stat-value.danger  { color: var(--danger); }

/* ── Cards ───────────────────────────────────────────────
   A card is a grouping device. Header and body share one horizontal rhythm so
   a title always sits on the same optical line as the content beneath it, and
   the card carries no shadow of its own — the border does the separating, and
   elevation is reserved for things that genuinely float. */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin-bottom: var(--space-6);
  transition: border-color var(--transition-fast);
}
.card-header {
  padding: var(--space-6) var(--space-8);
  border-bottom: 1px solid var(--line-subtle);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  flex-wrap: wrap;
}
.card-header h3 {
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  letter-spacing: var(--ls-snug);
  min-width: 0;
}
.card-body { padding: var(--space-8); }
/* A card whose body is nothing but a state should not also draw a header rule
   above an empty box. */
.card-body > .empty-state:only-child { padding-block: var(--space-9); }

/* Two-column layouts collapse at the tablet breakpoint (see the responsive
   section); min-width:0 keeps a wide child from pushing the grid open. */
.grid-2col { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6); }

/* ── Curriculum Tree ─────────────────────────────────── */
.chapter-block {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 16px;
  overflow: hidden;
  transition: var(--transition);
}
.chapter-header {
  padding: 16px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  transition: var(--transition);
}
.chapter-header:hover { background: var(--bg-card-hover); }
.chapter-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: var(--gradient-1);
  border-radius: 10px;
  font-size: 14px;
  font-weight: 700;
  color: #fff;
  margin-right: 16px;
  flex-shrink: 0;
}
.chapter-title { font-size: 16px; font-weight: 600; flex: 1; }
.chapter-toggle { color: var(--text-muted); font-size: 20px; transition: var(--transition); }
.chapter-topics { padding: 0 24px 16px; display: none; }
.chapter-topics.open { display: block; animation: fadeIn 0.2s ease; }

.topic-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-radius: var(--radius-sm);
  margin-bottom: 4px;
  transition: var(--transition);
}
.topic-item:hover { background: var(--fill-hover); }
.topic-info { display: flex; align-items: center; gap: 12px; }
.topic-type-badge {
  padding: 3px 10px;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.topic-type-badge.vocabulary { background: rgba(59,130,246,0.15); color: #60a5fa; }
.topic-type-badge.grammar { background: rgba(168,85,247,0.15); color: #c084fc; }
.topic-type-badge.reading { background: rgba(34,197,94,0.15); color: #4ade80; }
.topic-type-badge.communication { background: rgba(249,115,22,0.15); color: #fb923c; }
.topic-type-badge.phonetics { background: rgba(6,182,212,0.15); color: #22d3ee; }
.topic-type-badge.functional, .topic-type-badge.functional_language { background: rgba(236,72,153,0.15); color: #f472b6; }
.topic-type-badge.mixed { background: rgba(107,114,128,0.15); color: #9ca3af; }
.topic-name { font-size: 14px; font-weight: 500; }
.topic-meta { font-size: 12px; color: var(--text-muted); display: flex; gap: 12px; }

/* ── Activity Preview ────────────────────────────────── */
.activity-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px;
  margin-bottom: 12px;
  transition: var(--transition);
}
.activity-card.correct { border-color: var(--success); background: var(--success-bg); }
.activity-card.incorrect { border-color: var(--danger); background: var(--danger-bg); }
.activity-type-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--accent-light);
  font-weight: 600;
  margin-bottom: 8px;
}
.activity-prompt { font-size: 18px; font-weight: 600; margin-bottom: 16px; line-height: 1.5; }

.options-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.option-btn {
  padding: 14px 20px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: var(--transition);
  text-align: left;
  box-shadow: var(--shadow);
}
.option-btn:hover {
  border-color: var(--accent);
  background: var(--accent-glow);
}
[data-theme="light"] .option-btn:hover {
  background: var(--accent-glow);
}
.option-btn.selected {
  border-color: var(--accent);
  background: var(--accent-glow);
  box-shadow: 0 0 0 2px var(--accent-glow);
}
.option-btn.correct-answer {
  border-color: var(--success) !important;
  background: var(--success-bg) !important;
  color: var(--success) !important;
  font-weight: 600;
}
.option-btn.wrong-answer {
  border-color: var(--danger) !important;
  background: var(--danger-bg) !important;
  color: var(--danger) !important;
  font-weight: 600;
}

.fill-blank-input {
  padding: 12px 16px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 15px;
  width: 240px;
  transition: var(--transition);
}
.fill-blank-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-glow);
}

.feedback-msg {
  display: none !important;
  margin-top: 12px;
  padding: 10px 16px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 500;
}
.feedback-msg.correct { background: var(--success-bg); color: var(--success); }
.feedback-msg.incorrect { background: var(--danger-bg); color: var(--danger); }
.feedback-msg.clickable-feedback { cursor: pointer; transition: all 0.2s ease; border: 1px solid transparent; }
.feedback-msg.clickable-feedback:hover { filter: brightness(1.1); border-color: rgba(255, 255, 255, 0.2); transform: translateY(-1px); }

/* ── Roster ──────────────────────────────────────────────
   The roster renders through the shared .listrows / .listrow primitive in
   foundation.css. What used to live here — .student-card and its avatar block,
   bordered metrics box and three full-width action buttons — is gone with it:
   a roster is one list, not one card per person. Only the two pieces the row
   still uses are kept.

   A number is identity, so it stays monospaced and set apart from prose. */
.student-school-num {
  font-family: var(--font-mono);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
}
/* The mastery dot that precedes the percentage in a row's metadata. */
.metric-indicator {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}

/* ── Progress Bars ───────────────────────────────────── */
.progress-item { margin-bottom: 16px; }
.progress-label { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 14px; }
.progress-label span:first-child { font-weight: 500; }
.progress-label span:last-child { color: var(--text-secondary); }
.progress-bar { height: 8px; background: var(--bg-input); border-radius: 4px; overflow: hidden; }
.progress-fill { height: 100%; border-radius: 4px; transition: width 0.8s cubic-bezier(0.4,0,0.2,1); }

/* ── Report ──────────────────────────────────────────── */
.report-section { margin-bottom: 28px; }
.report-section h3 { font-size: 18px; font-weight: 600; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }

.risk-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-bottom: 8px;
}
.risk-name { font-weight: 600; }
.risk-badges { display: flex; gap: 6px; }
.risk-badge {
  padding: 3px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
}
.risk-badge.critical { background: var(--danger-bg); color: var(--danger); }
.risk-badge.warning { background: var(--warning-bg); color: var(--warning); }
.risk-badge.low { background: rgba(59,130,246,0.12); color: var(--info); }

/* The practice list renders through the shared .listrows / .listrow primitive.
   .topic-grid and .topic-practice-card went with it: a curriculum is a list of
   topics, and as a card grid thirty topics cost over 3,000px on a phone. */

/* ── Modal ────────────────────────────────────────────── */
/* ── Overlays ────────────────────────────────────────────
   Centred dialog on desktop, bottom sheet on phones and tablets. The scroll
   lives on the content, so the close button stays reachable and nothing runs
   off the bottom of a phone with no way to get back to it. */
.modal {
  position: fixed;
  inset: 0;
  background: var(--scrim);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
  z-index: var(--z-modal);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.modal-content {
  display: flex;
  flex-direction: column;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-overlay);
  /* One token owns the panel's inset. The sticky close and the sticky action
     bar cancel it with negative offsets, so when a breakpoint changed the
     padding alone they drifted out of alignment with the panel edge. */
  --modal-pad: var(--space-8);
  padding: var(--modal-pad);
  max-width: 640px;
  width: 100%;
  max-height: min(86vh, 900px);
  /* A dialog scrolls in one direction only. `overflow-y: auto` on its own is
     not that: the other axis computes to `auto` as well, which on iOS gives
     the panel an elastic sideways drag with nothing to reach — the AI
     Architect's language list slid left and right under the thumb. Clipping
     the axis costs nothing, because no dialog overflows it: measured at 320,
     393 and 430px, all ten have scrollWidth exactly equal to clientWidth.
     Nested scrollers inside keep working; they scroll themselves. */
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  position: relative;
}
/* The close control is a real 44px target that stays pinned while the body
   scrolls under it, rather than a 24px glyph that scrolls away. */
.modal-close {
  /* .modal-content is a column flex container, so a float here would be
     ignored; align-self is what actually parks it on the trailing edge. */
  position: sticky;
  top: calc(var(--modal-pad) * -1);
  align-self: flex-end;
  order: -1;
  margin: calc(var(--space-5) * -1) calc(var(--space-5) * -1) calc(var(--space-2) * -1) 0;
  width: max(var(--control-md), var(--tap-min));
  min-height: max(var(--control-md), var(--tap-min));
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius);
  color: var(--text-muted);
  font-size: var(--fs-3xl);
  line-height: 1;
  cursor: pointer;
  z-index: var(--z-sticky);
  transition: color var(--transition-fast), background var(--transition-fast);
}
.modal-close:hover { color: var(--text-primary); background: var(--surface-hover); }
[data-theme="light"] .modal-close:hover { background: var(--surface-3); }

/* A sticky action bar so the primary action of a long wizard is always in
   reach instead of sitting below an invisible fold. */
.modal-actions {
  position: sticky;
  bottom: calc(var(--modal-pad) * -1);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-5);
  margin: var(--space-8) calc(var(--modal-pad) * -1) calc(var(--modal-pad) * -1);
  padding: var(--space-6) var(--modal-pad);
  border-top: 1px solid var(--line-subtle);
  background: var(--surface-2);
}

/* ── Quiz Taking ─────────────────────────────────────── */
.quiz-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
  padding: 16px 24px;
  background: var(--bg-card);
  border-radius: var(--radius);
  border: 1px solid var(--border);
}
.quiz-progress-text { font-size: 14px; color: var(--text-secondary); }
.quiz-timer { font-size: 20px; font-weight: 700; color: var(--accent-light); font-variant-numeric: tabular-nums; }

.quiz-result-card {
  text-align: center;
  padding: 48px;
  background: var(--bg-card);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
}
.quiz-score-big { font-size: 72px; font-weight: 800; margin: 16px 0; }
.quiz-score-label { font-size: 18px; color: var(--text-secondary); }

.form-row { display: flex; gap: 16px; margin-bottom: 16px; }
.form-row .form-group { flex: 1; }
.card-list .card { cursor: pointer; }
.card-list .card:hover { border-color: var(--accent); }

/* ── Responsive ──────────────────────────────────────── */

/* Tablet */
/* Between roughly 1240px and 1500px the bar cannot show everything at full
   size. Rather than clip the last tabs, it sheds chrome in order of
   importance: first the "view classrooms" label, then the role badge, then
   the tab labels. */
@media (max-width: 1500px) {
  .nav-back-btn .nav-back-label { display: none; }
  .nav-back-btn { padding-inline: var(--space-4); }
}
@media (max-width: 1340px) {
  .nav-badge { display: none; }
  #nav-course-code { display: none; }
}
@media (max-width: 1240px) {
  .nav-title { display: none; }
  .tab-label { display: none; }
  .nav-tab { padding: 0 var(--space-4); }
}
@media (max-width: 1024px) {
  .grid-2col { grid-template-columns: minmax(0, 1fr); }

  /* The compact bar carries the menu, the mark, and the account actions.
     Anything that cannot be read at this width is in the drawer instead —
     the class name and code are shown in full in the drawer header. */
  .nav-brand {
    margin-right: 0;
    gap: var(--space-3);
    /* Only as wide as the mark: the stretch after it is the study buddy's
       (buddy.js), and a tap there must not count as a tap on the logo. The
       account actions keep to the right edge on their own (margin-left). */
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
  }
  .nav-title { display: none; }
  .nav-logo-img { height: 22px; }
  .nav-badge { font-size: var(--fs-2xs); padding: var(--space-1) var(--space-4); flex-shrink: 0; }

  #nav-course-name, #student-nav-course-name { display: none !important; }
  .nav-separator { display: none; }

  .nav-user { display: flex; gap: var(--space-3); align-items: center; margin-left: auto; }
}

/* Below 480px the role badge is the first thing to go: on a 320px screen it
   was being clipped mid-word by the bar it sits in. The role is stated in
   full at the top of the drawer. */
@media (max-width: 480px) {
  .nav-badge { display: none; }
  .nav-logo-img { height: 20px; }
}
/* ^ The tablet block ends HERE. It used to run on for another 330 lines,
   swallowing the messaging styles below and the whole mobile layout section,
   so chat bubbles were unstyled on desktop and the "mobile" rules were really
   "tablet and below". Closing it is the fix; the rules that follow are global
   again, and the genuinely responsive ones live in their own blocks. */

/* ── Classroom picker ────────────────────────────────────
   A tighter grid minimum than the default so a single class fills its row
   rather than floating in a half-empty two-column layout. */
/* One container width for the whole screen so the header, the class grid and
   the roster table share a left edge. The grid minimum does the work of
   keeping class cards from stretching absurdly wide. */
.picker { --grid-min: 340px; }
.picker__header { border-bottom: 1px solid var(--line-subtle); padding-bottom: var(--space-7); }
.picker__admin { margin-top: var(--space-11); }

/* The class card's footer action fills the card and is the card's affordance,
   so it reads as "enter" rather than as a second competing button. */
.classroom-card > .btn:last-child {
  border-radius: 0;
  border-inline: none;
  border-bottom: none;
  border-top: 1px solid var(--line-subtle);
  min-height: var(--control-xl);
}

/* ── Wizard steps ────────────────────────────────────────
   The create flows are the product's most important screens. Steps are
   numbered with a real marker rather than "1." typed into a label, and each
   step is a block with its own rhythm so a three-step form reads as three
   decisions instead of one long column of controls. */
.wizard-intro {
  color: var(--text-muted);
  font-size: var(--fs-base);
  line-height: var(--lh-snug);
  margin-bottom: var(--space-9);
  max-width: 52ch;
}
.wizard-step { margin-bottom: var(--space-9); }
.wizard-step:last-of-type { margin-bottom: 0; }
.wizard-step__head {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin-bottom: var(--space-5);
}
.wizard-step__num {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--accent-line);
  background: var(--accent-glow);
  color: var(--accent-light);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}
[data-theme="light"] .wizard-step__num { color: var(--accent); }
.wizard-step__label {
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  letter-spacing: var(--ls-snug);
}

/* ── Choice tiles ────────────────────────────────────────
   Selectable options — target languages, CEFR levels. Compact single-line
   rows so fifteen of them fit on a phone screen without a thousand pixels of
   scrolling, with one selected treatment shared by every choice group. */
.choice-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr));
  gap: var(--space-4);
}
.choice-grid--level { grid-template-columns: repeat(auto-fit, minmax(72px, 1fr)); }

.choice-tile {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  min-height: max(var(--control-lg), var(--tap-min));
  padding: var(--space-4) var(--space-5);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-secondary);
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  cursor: pointer;
  text-align: center;
  transition: border-color var(--transition-fast), background var(--transition-fast), color var(--transition-fast);
}
.choice-tile:hover { border-color: var(--line-strong); color: var(--text-primary); }
.choice-tile.is-selected {
  background: var(--accent-glow);
  border-color: var(--accent);
  color: var(--text-primary);
  font-weight: var(--fw-semibold);
}
[data-theme="light"] .choice-tile.is-selected { color: var(--accent); }

/* The ISO code reads as quiet leading metadata, not a coloured badge. */
.choice-tile__code {
  flex-shrink: 0;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-wide);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.choice-tile.is-selected .choice-tile__code { color: var(--accent-light); }
[data-theme="light"] .choice-tile.is-selected .choice-tile__code { color: var(--accent); }
.choice-tile__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A table's card body carries no padding of its own: the table's own cell
   padding provides the inset, so rows can run edge to edge on desktop and the
   stacked records get their own spacing on phones. */
.table-wrap { padding: 0; }
.table-wrap > .data-table { margin: 0; }

/* Between the stacked-record breakpoint and the width where six columns
   genuinely fit, the table scrolls on purpose rather than being clipped by its
   card — at tablet width the action buttons were being cut off 166px past the
   card's edge with no way to reach them. */
@media (min-width: 601px) {
  .table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .table-wrap > .data-table { min-width: 44rem; }
}
@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  .table-wrap { padding: var(--space-5); }
}

/* ── Danger zone ─────────────────────────────────────────
   Destructive settings get their own block at the end of a page, visually
   separated and honestly labelled, rather than a near-invisible ghost link in
   a grey strip. */
.danger-zone {
  margin-top: var(--space-11);
  padding: var(--space-6) var(--space-7);
  border: 1px solid var(--tone-line, rgba(248, 113, 113, 0.22));
  border-radius: var(--radius-lg);
  background: var(--danger-bg);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  flex-wrap: wrap;
}
.danger-zone__text { flex: 1 1 24rem; min-width: 0; }
.danger-zone__title {
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  letter-spacing: var(--ls-snug);
}
.danger-zone__body {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  margin-top: var(--space-2);
  line-height: var(--lh-snug);
  max-width: 62ch;
}
@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  .danger-zone { flex-direction: column; align-items: stretch; }
  /* flex-basis follows the main axis, so the 24rem basis that gives the text
     a sensible minimum WIDTH in a row became a 384px minimum HEIGHT once the
     container turned into a column — 384px of blank space under every
     lecturer overview. */
  .danger-zone__text { flex: 0 0 auto; }
  .danger-zone .btn { width: 100%; }
}

/* ── Mobile navigation drawer ────────────────────────────
   The drawer is the primary navigation below 1024px, so it is built as a real
   surface rather than a narrow strip of inline styles. It takes most of the
   screen, groups the class tabs separately from the "leave this class" and
   account actions, and its close control is a normal 44px target inside the
   header instead of a 28px circle straddling the panel edge. */
.drawer {
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer);
  pointer-events: none;
}
.drawer__scrim {
  position: absolute;
  inset: 0;
  background: var(--scrim);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
}
.drawer__panel {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  /* Wide enough for full menu labels in Turkish and German, capped so the
     page behind stays visible as context. */
  width: min(320px, 86vw);
  display: flex;
  flex-direction: column;
  background: var(--surface-2);
  border-inline-end: 1px solid var(--border);
  transform: translateX(-102%);
  /* The panel keeps its box-shadow only while open: parked off-screen its
     60px blur still painted across the left edge of every page, which is what
     that faint vertical band down the side of the dashboard was. visibility
     also keeps the closed drawer out of the tab order. */
  visibility: hidden;
  transition: transform 0.28s cubic-bezier(0.32, 0.72, 0, 1), visibility 0s linear 0.28s;
  pointer-events: auto;
  overscroll-behavior: contain;
}
.drawer.is-open .drawer__panel {
  visibility: visible;
  box-shadow: var(--shadow-overlay);
  transition: transform 0.28s cubic-bezier(0.32, 0.72, 0, 1), visibility 0s;
}
.drawer.is-open { pointer-events: auto; }
.drawer.is-open .drawer__scrim { opacity: 1; pointer-events: auto; }
.drawer.is-open .drawer__panel { transform: translateX(0); }
/* iOS home-screen apps can end the web view's layout area above the
   screen's bottom edge (at the top of a page, or when it cannot scroll);
   fixed layers stop there and the band below shows the page background.
   While the drawer is open that background continues the panel on the
   left, so the band reads as part of the drawer. The right side stays the
   page colour, which is what the scrim sits on. */
html:has(#mobile-sidebar.is-open),
html:has(#mobile-sidebar.is-open) body {
  background: linear-gradient(90deg, var(--surface-2) 0 calc(min(320px, 86vw) + env(safe-area-inset-left, 0px)), var(--surface-0) 0);
}

.drawer__header {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-4);
  padding: calc(var(--space-7) + env(safe-area-inset-top, 0px)) var(--space-6) var(--space-6);
  border-bottom: 1px solid var(--line-subtle);
}
.drawer__identity { min-width: 0; }
.drawer__name {
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  letter-spacing: var(--ls-snug);
  overflow-wrap: anywhere;
}
.drawer__role {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  margin-top: var(--space-1);
}
.drawer__close { align-self: start; color: var(--text-muted); }
.drawer__close svg { width: var(--icon-lg); height: var(--icon-lg); }

/* Course name and code are separate lines: they used to butt together as
   "Demo Classroom#11111" with nothing between them. */
.drawer__course {
  grid-column: 1 / -1;
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line-subtle);
  min-width: 0;
}
.drawer__course-name {
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.drawer__course-code {
  font-size: var(--fs-xs);
  font-family: var(--font-mono);
  color: var(--accent-light);
  margin-top: var(--space-2);
  letter-spacing: var(--ls-wide);
}

.drawer__nav {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5) var(--space-5);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.drawer__group { display: flex; flex-direction: column; gap: var(--space-1); }
/* Separates the tabs of the current class from the actions that leave it. */
.drawer__divider {
  height: 1px;
  border: none;
  background: var(--line-subtle);
  margin: var(--space-5) var(--space-5);
}
.sidebar-item--leave { color: var(--accent-light); }

.drawer__section {
  margin-top: auto;
  padding-top: var(--space-7);
}
.drawer__section-label { margin-bottom: var(--space-4); padding-inline-start: var(--space-4); }
.drawer__lang { justify-content: flex-start; gap: var(--space-5); }

.drawer__footer {
  flex: 0 0 auto;
  padding: var(--space-5);
  padding-bottom: calc(var(--space-5) + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line-subtle);
}
/* Reload the current view. It lives beside sign-out because both are utility
   actions on the way out of the menu rather than places to go, and it takes the
   same row shape so it adds a line, not a new kind of thing. Muted, not
   accented: it is a convenience, and nothing on this screen should compete with
   sign-out for attention. */
.drawer__profile,
.drawer__settings,
.drawer__appearance,
.drawer__refresh {
  justify-content: flex-start;
  gap: var(--space-5);
  color: var(--text-secondary);
}
.drawer__profile:hover,
.drawer__settings:hover,
.drawer__appearance:hover,
.drawer__refresh:hover { background: var(--fill-hover); color: var(--text-primary); }
.drawer__signout {
  justify-content: flex-start;
  gap: var(--space-5);
  color: var(--danger);
}
.drawer__signout:hover { background: var(--danger-bg); color: var(--danger); }

/* Drawer nav items. One row height, one active treatment — a gold rail on the
   leading edge — used for both roles. */
.sidebar-item {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-5);
  width: 100%;
  min-height: max(var(--control-lg), var(--tap-min));
  padding: var(--space-4) var(--space-5);
  border: none;
  border-inline-start: 2px solid transparent;
  border-radius: var(--radius);
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  color: var(--text-secondary);
  background: transparent;
  text-align: start;
  transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}
.sidebar-item:hover { color: var(--text-primary); background: var(--surface-hover); }
[data-theme="light"] .sidebar-item:hover { background: var(--surface-3); }
.sidebar-item.active {
  color: var(--text-primary);
  background: var(--accent-glow);
  border-inline-start-color: var(--accent);
  border-start-start-radius: 0;
  border-end-start-radius: 0;
}
[data-theme="light"] .sidebar-item.active { color: var(--accent); }
.sidebar-item > span:not(.sidebar-icon) { min-width: 0; }

.sidebar-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--icon-lg);
  flex-shrink: 0;
}
.sidebar-icon svg { width: var(--icon-lg); height: var(--icon-lg); }

/* ── Messaging ───────────────────────────────────────── */
.chat-container {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 10px;
}

.chat-bubble {
    max-width: 85%;
    padding: 12px 16px;
    border-radius: 18px;
    font-size: 14px;
    line-height: 1.5;
    position: relative;
    word-wrap: break-word;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.chat-bubble.sent {
    align-self: flex-end;
    background: var(--gradient-1) !important;
    color: white !important;
    border-bottom-right-radius: 4px;
    border: none !important;
}

.chat-bubble.received {
    align-self: flex-start;
    background: var(--bg-input) !important;
    color: var(--text-primary) !important;
    border: 1px solid var(--border) !important;
    border-bottom-left-radius: 4px;
}

.chat-time {
    font-size: 10px;
    opacity: 0.7;
    margin-top: 4px;
    display: block;
    text-align: right;
}

.chat-bubble.received .chat-time {
    text-align: left;
}

.chat-sender {
    font-size: 11px;
    font-weight: 700;
    margin-bottom: 4px;
    color: var(--accent-light);
}

/* Mobile Messaging Optimizations */
@media (max-width: 768px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
    .tab-panel#tab-inbox, .tab-panel#tab-s-messages {
        padding: 0 !important;
    }
    
    .tab-panel#tab-inbox .page-header, .tab-panel#tab-s-messages .page-header {
        padding: 16px 20px;
        margin-bottom: 0;
        background: var(--bg-card);
        border-bottom: 1px solid var(--border);
    }
    
    .chat-wrapper.is-active {
        display: flex !important;
        flex-direction: column !important;
        /* Enough for a short conversation without opening a void under an
           empty one. */
        min-height: 260px;
        height: auto !important;
        background: var(--bg-card);
        border-radius: 12px;
        overflow: visible !important;
    }

    .chat-wrapper:not(.is-active) {
        display: flex !important;
        flex: 1;
    }

    .chat-header {
        display: none;
        padding: 12px 16px;
        background: var(--bg-card);
        border-bottom: 1px solid var(--border);
        align-items: center;
        gap: 12px;
        position: sticky;
        top: 0;
        z-index: 10;
    }

    .chat-input-area {
        background: var(--bg-card) !important;
        border-top: 1px solid var(--border);
        display: flex !important;
        gap: 8px;
        padding: 10px 12px env(safe-area-inset-bottom, 12px) !important;
        width: 100%;
        box-sizing: border-box;
        position: sticky;
        bottom: 0;
        z-index: 5;
    }

    .chat-wrapper.is-active .chat-header {
        display: flex;
    }
    
    html.chat-open, body.chat-open {
        overflow: hidden !important;
        height: 100% !important;
        position: fixed !important;
        width: 100% !important;
    }

    /* Kill stacking context hacks - no longer needed */
    html.chat-open main, 
    html.chat-open section,
    html.chat-open .container,
    html.chat-open .lecturer-dashboard,
    html.chat-open .student-dashboard {
        z-index: auto !important;
    }
    
    .chat-wrapper.is-active #inbox-messages,
    .chat-wrapper.is-active #student-chat-history {
        flex: 1 !important;
        overflow-y: auto !important;
        padding: 16px !important;
        -webkit-overflow-scrolling: touch;
    }
    
    
    .chat-bubble {
        max-width: 90%;
    }
}

/* ── Tablet and below: layout pattern changes ────────────
   Below 1024px the top tab bar is replaced by the drawer, so the nav becomes
   a compact bar and the content gets phone-appropriate gutters. These rules
   used to be inside the same runaway block as the chat styles above. */
/* ════════════════════════════════════════════════════════════════════════
   RESPONSIVE LAYOUT
   Two breakpoints carry the layout changes, and only two:

     ≤ 1024px  the top tab bar gives way to the drawer, so the nav becomes a
               compact bar and the page switches to phone gutters;
     ≤ 600px   multi-column layouts become single column and side-by-side
               controls stack.

   Everything that used to be scattered through five overlapping blocks of
   per-page overrides lives here, expressed once against the shared
   primitives. Sizing comes from the tokens, so these rules change *layout*,
   not magic numbers.
   ═══════════════════════════════════════════════════════════════════════ */

@media (max-width: 1024px) {
  .topnav {
    position: fixed;
    inset-inline: 0;
    top: 0;
    flex-wrap: nowrap;
    justify-content: flex-start;
    /* Padding to the raw inset puts the logo flush against the notch/Dynamic
       Island edge — fine in a browser tab, where Safari's own chrome already
       adds clearance, but tight enough as a home-screen app (full-bleed,
       black-translucent status bar) to read as "behind" it. A small buffer
       on top of the inset gives it room to breathe in both. */
    padding: calc(env(safe-area-inset-top, 0px) + var(--space-3)) var(--space-5) 0;
    height: calc(var(--topnav-h) + env(safe-area-inset-top, 0px) + var(--space-3));
    gap: var(--space-4);
    z-index: var(--z-topnav);
  }

  /* The tab row moves wholesale into the drawer rather than being squeezed
     into a horizontally scrolling strip of 9px labels. */
  .nav-tabs { display: none !important; }

  /* Content clears the fixed bar and ends at the safe area. It used to
     reserve 90px at the bottom for a mobile tab bar that does not exist,
     which is where a chunk of the dead space at the foot of every phone
     screen came from. */
  .dashboard-content {
    padding-top: calc(var(--topnav-h) + env(safe-area-inset-top, 0px) + var(--space-8));
    padding-inline: var(--gutter-safe);
    /* No safe-area inset here: the site footer sits below this and reserves
       it once, at the actual bottom of the page. Reserving it in both places
       pushed the notice a whole inset away from the content. */
    padding-bottom: var(--space-9);
  }

  /* Side insets belong to the scroll container, not to <body>: on body they
     shift the fixed top bar out of alignment with the page under it. */
  body { padding: 0; }

  .page-header { margin-bottom: var(--space-8); }
  .page-header h1 { font-size: var(--fs-3xl); }
  .subtitle { font-size: var(--fs-base); }

  .stats-grid { grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); gap: var(--space-5); margin-bottom: var(--space-8); }
  .stat-card { padding: var(--space-6); }
  .stat-value { font-size: var(--fs-4xl); }

  .card { margin-bottom: var(--space-5); }
  .card-header { padding: var(--space-5) var(--space-6); }
  .card-body { padding: var(--space-6); }

  .grid-2col { grid-template-columns: minmax(0, 1fr); }

  /* Dialogs stay centred on a phone, as a panel rather than a full-bleed
     bottom sheet. The panel keeps its column layout so the sticky close and
     the sticky action bar still work — turning it into a plain scrolling box
     is how the AI Architect once ended up running off the bottom of the screen
     with its primary button unreachable.

     The inset is applied to the backdrop rather than the panel, so the panel
     is centred in the space that is actually free: clear of a device cutout on
     the sides, and of the status bar and home indicator top and bottom. */
  .modal {
    align-items: center;
    padding: calc(var(--space-6) + env(safe-area-inset-top, 0px))
             var(--gutter-safe)
             calc(var(--space-6) + env(safe-area-inset-bottom, 0px));
  }
  .modal-content {
    --modal-pad: var(--space-7);
    /* Whatever is left after the backdrop's inset — the panel scrolls
       internally rather than growing past the screen. */
    max-height: 100%;
  }
  /* An action bar owns the panel's bottom edge and sits flush with it; the
     panel's own overflow clipping keeps the rounded corners. */
  .modal-content:has(.modal-actions) { padding-bottom: 0; }
  .modal-actions { margin-bottom: 0; bottom: 0; padding-block: var(--space-5); }

  .pdf-container {
    height: calc(100svh - 120px);
    border-radius: 0;
    border-inline: none;
  }
}

@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  /* The metric row keeps the auto-fit track from the tablet rule rather than
     being forced to one column: at 360-414px two 150px cards still fit and
     read fine, and four full-width cards is 370px of scrolling for four
     numbers. Below ~340px the track stops fitting and it collapses on its own.
     Everything else that was two-up does become one-up. */
  .options-grid { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }

  /* Page actions go full width and stack, instead of wrapping a label across
     three lines inside a shrunken button. */
  .page-header { grid-template-columns: minmax(0, 1fr); }
  .page-header > h1            { grid-area: auto; }
  .page-header > .subtitle     { grid-area: auto; }
  .page-header > div:first-child { grid-area: auto; }
  .page-header > .page-actions,
  .page-header > .btn,
  .page-header > button {
    grid-area: auto;
    justify-self: stretch;
    width: 100%;
  }
  .page-header .page-actions { display: flex; }
  .page-header .page-actions > .btn { flex: 1 1 auto; }

  .card-header { flex-wrap: wrap; }
  .card-header > .btn { width: 100%; }

  .form-row { flex-direction: column; gap: var(--space-5); }
  /* A form's submit in a single-column layout spans the column: a 180px
     button floating at the left of a full-width field stack reads as unrelated
     to it. */
  .card-body > .btn-primary,
  .card-body > form > .btn-primary,
  .form-actions > .btn { width: 100%; }

  .chapter-header { padding: var(--space-5) var(--space-6); }
  .activity-card { padding: var(--space-6); }
  .activity-prompt { font-size: var(--fs-lg); line-height: var(--lh-snug); }
  .fill-blank-input { width: 100%; margin-bottom: var(--space-6); }

  /* A sheet's actions stack, primary first (it is last in the DOM, so the
     visual order is reversed rather than the markup). */
  .modal-actions { flex-direction: column-reverse; align-items: stretch; }
  .modal-actions > .btn { width: 100%; }
}

/* Small phones (iPhone SE, etc) */
/* Small phones. The previous rules here forced the metric row back to two
   columns and shrank the type to 22px/8px to make it fit — the narrowest
   screen was getting the densest layout. It now keeps the single column the
   600px breakpoint establishes.
   The gutter is deliberately NOT tightened here any more: a 12px inset was
   the narrowest screen getting the least breathing room, which is where the
   glued-to-the-edge feel was worst. 16px on both sides costs 8px of a 320px
   screen and buys a page that reads as a page. */
@media (max-width: 375px) {
  .stat-card { padding: var(--space-5); }
  .page-header h1 { font-size: var(--fs-2xl); }
}

/* Mobile Login Optimization */
@media (max-width: 768px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  /* The phone login is ONE panel, exactly one viewport tall, and it does not
     scroll. That is the whole fix, and the dvh work above it was only half.

     The hero used to sit below the form, ordered second. It is ~400px of
     marketing copy underneath a form that already fills the screen, so the
     page was always taller than the viewport and always scrollable — and a
     scrollable page is what lets iOS Safari collapse its toolbars, open its
     overscroll gutter and put its pull-to-refresh strip above the document.
     That strip is painted in `theme-color`, not in the page background, which
     is why the band at the top stayed black through every change made to the
     page's own colours and heights. Nothing below the fold was being read
     anyway: by the time you scroll past a sign-in form you have already
     decided to sign in.

     With the hero gone the form is ~650px in a ~700px viewport, so it fits,
     nothing scrolls, and the toolbars stay put. */
  /* Keep the login layout on a stable phone viewport. 100dvh follows the
     iOS keyboard animation frame-by-frame; because the form is centred, that
     makes the whole screen visibly drift while the keyboard opens/closes.
     100svh stays fixed, so only the browser keyboard changes — the login
     layout itself does not chase it. */
  #login-screen {
    height: 100svh;
    min-height: 100svh;
  }
  .login-container {
    display: flex;
    flex-direction: column;
    height: 100svh;
    min-height: 100svh;
  }
  .login-hero { display: none; }
  .login-form-section {
    /* The only panel now, so it owns the whole viewport and the form centres
       inside it — no second background to meet, and no seam to mismatch. */
    flex: 1 0 auto;
    min-height: auto;
    justify-content: center;
    /* Matching the page background rather than the raised surface: with one
       panel there is no two-column split left to distinguish, and a single
       colour from the status bar to the home indicator is the thing that
       cannot band. */
    background: var(--bg-primary);
    /* Symmetric, plus room at the bottom for the floating theme/language
       pill so it never lands on the privacy link. */
    padding: 26px 20px calc(28px + var(--control-lg));
  }
  .login-form-brand {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-bottom: 18px;
  }
  .login-form-brand__logo { height: 34px; width: auto; }
  .login-form-brand__name {
    font-size: 17px;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--text-primary);
  }
  /* Every rule that laid out the hero and its children on a phone lived
     here. The hero is display:none above, so all of it was dead weight; the
     desktop rules for the same elements are untouched, and switchDemoLang /
     handleDemoTTS still have their .academic-sheet to work on there. */
  .login-form-section h2 { font-size: 22px; }
  .login-hint { font-size: 14px; margin-bottom: 22px; }
  .login-tabs-wrapper { margin-bottom: 24px; }
  .form-group input { padding: 12px 14px; font-size: 16px; } /* 16px prevents iOS zoom */
  .btn-full { padding: 13px; font-size: 16px; }
  .demo-btn { padding: 14px 16px; }
  .nav-logo-img { height: 28px; width: auto; }
  .floating-actions {
    bottom: max(16px, env(safe-area-inset-bottom, 0px));
    right: 16px;
  }
  .floating-actions .btn-lang { min-height: 40px; min-width: 40px; padding-inline: var(--space-4); }
  .btn-lang {
    padding: 8px 12px;
    font-size: 12px;
  }
}

/* Landscape phone */
@media (max-height: 500px) and (orientation: landscape) {
  .login-form-section {
    padding: 16px 32px;
    min-height: 100vh;
    min-height: 100dvh;
    overflow-y: auto;
  }
  .login-form-section h2 { font-size: 20px; margin-bottom: 2px; }
  .login-hint { margin-bottom: 12px; }
  .form-group { margin-bottom: 10px; }
  .form-group input { padding: 10px 14px; }
  .btn-full { padding: 12px; }
  .demo-accounts { margin-top: 16px; padding-top: 12px; }
  .dashboard-content { padding-bottom: 70px; } /* footer reserves the safe area */
}

/* ── Utility ─────────────────────────────────────────── */
.text-center { text-align: center; }
.mt-16 { margin-top: 16px; }
.mt-24 { margin-top: 24px; }
.mb-16 { margin-bottom: 16px; }
.gap-8 { gap: 8px; }
.flex { display: flex; }
.flex-between { display: flex; justify-content: space-between; align-items: center; }

/* ── PDF Viewer ───────────────────────────────────────── */
.pdf-container {
    background: var(--bg-card);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    overflow: hidden;
    box-shadow: var(--shadow-lg);
    width: 100%;
    height: 90vh; /* Maximize height for reading */
    margin: 0 auto;
    display: flex;
}
.pdf-viewer {
    width: 100%;
    height: 100%;
    border: none;
}

/* ==========================================================================
   Independent Scroll & Locked Frame Layout for Study Material Container
   ========================================================================== */
.study-container {
  display: flex !important;
  background: var(--bg-card);
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  height: clamp(620px, calc(100vh - 170px), 900px);
  min-height: 580px;
  position: relative;
  box-sizing: border-box;
}

/* Left Sidebar: Fixed Width, 100% Height, Independent Scroll */
.study-sidebar {
  width: 250px;
  min-width: 230px;
  max-width: 260px;
  height: 100%;
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.08);
  overflow: hidden;
  flex-shrink: 0;
  box-sizing: border-box;
}

[data-theme="light"] .study-sidebar {
  background: rgba(0, 0, 0, 0.02);
}

.study-sidebar-header {
  padding: 20px 20px 16px 20px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.study-sidebar-header h3 {
  margin: 0;
  font-size: 13px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 1.2px;
  color: var(--text-muted);
}

.study-sidebar-toc {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 16px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.study-sidebar-toc::-webkit-scrollbar {
  width: 6px;
}
.study-sidebar-toc::-webkit-scrollbar-track {
  background: transparent;
}
.study-sidebar-toc::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 4px;
}
.study-sidebar-toc::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted);
}

/* Desktop only: widen the sidebar and let long unit/topic names wrap
   instead of being clipped. Tablet/mobile (<=1024px) styles are untouched. */
@media (min-width: 1025px) {
  .study-sidebar {
    width: 330px;
    min-width: 300px;
    max-width: 360px;
  }

  .study-sidebar-toc .study-topic-btn {
    width: 100%;
    max-width: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
    height: auto;
  }
}

/* Right Content Panel: Fixed 100% Height, Flex Column */
.study-content-panel {
  flex: 1;
  min-width: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 24px 28px;
  background: var(--bg-primary);
  position: relative;
  box-sizing: border-box;
}

.study-content-area {
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
  min-height: 0;
  box-sizing: border-box;
}

/* Inside Topic Page: Locked Frame Layout */
.study-topic-wrapper {
  max-width: 1100px;
  width: 100%;
  margin: 0 auto;
  height: 100%;
  display: flex;
  flex-direction: column;
  min-height: 0;
  box-sizing: border-box;
  animation: fadeIn 0.3s ease-out;
}

.study-topic-header {
  flex-shrink: 0;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 16px;
}

/* Study Breadcrumb & Title */
.study-breadcrumb-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--accent-glow);
  border: 1px solid color-mix(in srgb, var(--accent) 20%, transparent);
  padding: 4px 10px;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--accent-light);
  margin-bottom: 8px;
}

[data-theme="light"] .study-breadcrumb-pill {
  background: rgba(11, 47, 97, 0.06);
  border-color: rgba(11, 47, 97, 0.15);
  color: var(--accent);
}

.study-badge-tag {
  font-weight: 700;
}

.study-badge-divider {
  opacity: 0.5;
}

.study-badge-page {
  font-weight: 600;
  opacity: 0.9;
}

.study-page-heading {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
  line-height: 1.25;
  color: var(--text-primary);
}

/* Study Card: Locked Frame Height with Independent Scroll */
.study-card {
  flex: 1;
  min-height: 0;
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 12px !important;
  padding: 26px 30px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08) !important;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
  box-sizing: border-box;
  font-size: 15px;
  line-height: 1.65;
  animation: fadeIn 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}

#activity-preview {
  animation: fadeIn 0.25s ease-out;
}

[data-theme="light"] .study-card {
  background: #ffffff;
  border-color: #e2e8f0 !important;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.03) !important;
}

.study-card::-webkit-scrollbar {
  width: 6px;
}
.study-card::-webkit-scrollbar-track {
  background: transparent;
}
.study-card::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 4px;
}
.study-card::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted);
}

/* Modern Pedagogical Rules Block */
.pedagogy-guide-block {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 20px 22px;
  margin-bottom: 22px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
}

[data-theme="light"] .pedagogy-guide-block {
  background: #f8fafc;
  border-color: #e2e8f0;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
}

.pedagogy-guide-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--accent);
  background: var(--accent-glow);
  padding: 4px 10px;
  border-radius: 6px;
  margin-bottom: 14px;
  border: 1px solid color-mix(in srgb, var(--accent) 20%, transparent);
}

[data-theme="light"] .pedagogy-guide-badge {
  background: rgba(11, 47, 97, 0.06);
  border-color: rgba(11, 47, 97, 0.15);
  color: var(--accent);
}

.pedagogy-rules-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.pedagogy-rule-item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 11px 14px;
  background: rgba(255, 255, 255, 0.02);
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.05);
  transition: all 0.2s ease;
}

[data-theme="light"] .pedagogy-rule-item {
  background: #ffffff;
  border-color: #eef2f6;
}

.pedagogy-rule-item:hover {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--border);
  transform: translateX(2px);
}

[data-theme="light"] .pedagogy-rule-item:hover {
  background: #ffffff;
  border-color: #cbd5e1;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.03);
}

.pedagogy-rule-bullet {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  margin-top: 8px;
  flex-shrink: 0;
  box-shadow: 0 0 6px var(--accent-glow);
}

.pedagogy-rule-content {
  font-size: 15px;
  line-height: 1.65;
  color: var(--text-primary);
  font-weight: 400;
  flex: 1;
}

[data-theme="light"] .pedagogy-rule-content {
  color: #1e293b;
}

.pedagogy-single-note {
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-primary);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  padding: 16px 20px;
  border-radius: 8px;
  margin-bottom: 22px;
}

[data-theme="light"] .pedagogy-single-note {
  background: #f8fafc;
  color: #1e293b;
  border-color: #e2e8f0;
  border-left-color: var(--accent);
}

/* CEFR Pedagogical Level Components */
.cefr-level-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  transition: all 0.2s ease;
}

.cefr-level-subtitle {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  margin-top: 5px;
  letter-spacing: 0.2px;
  line-height: 1.4;
}

.pedagogy-rules-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-bottom: 22px;
}

.pedagogy-rule-card {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: 10px;
  padding: 18px 20px;
  transition: all 0.2s ease;
}

[data-theme="light"] .pedagogy-rule-card {
  background: #ffffff;
  border-color: #e2e8f0;
  border-left-color: var(--accent);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02);
}

.pedagogy-rule-card:hover {
  border-color: var(--border-hover);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
}

.pedagogy-rule-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.pedagogy-rule-explanation {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--text-secondary);
  margin-bottom: 12px;
}

.pedagogy-rule-example-box {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 8px;
  padding: 12px 16px;
  margin-top: 8px;
}

[data-theme="light"] .pedagogy-rule-example-box {
  background: #f8fafc;
  border-color: #e2e8f0;
}

.pedagogy-rule-example-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}

.pedagogy-rule-example-label {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--accent);
}

.pedagogy-contrast-section {
  margin-bottom: 22px;
}

.pedagogy-contrast-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px;
  margin-top: 10px;
}

.pedagogy-contrast-card {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

[data-theme="light"] .pedagogy-contrast-card {
  background: #ffffff;
  border-color: #e2e8f0;
}

.pedagogy-contrast-tag {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--accent-light);
}

.pedagogy-contrast-target {
  font-style: italic;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
}

.pedagogy-contrast-trans {
  font-size: 13px;
  color: var(--text-secondary);
}

.pedagogy-contrast-note {
  font-size: 12px;
  color: var(--text-muted);
  border-top: 1px dashed var(--border);
  padding-top: 6px;
  margin-top: 2px;
}

.pedagogy-pitfall-card {
  background: rgba(245, 158, 11, 0.08);
  border: 1px solid rgba(245, 158, 11, 0.3);
  border-left: 4px solid #f59e0b;
  border-radius: 10px;
  padding: 16px 20px;
  margin-bottom: 20px;
}

[data-theme="light"] .pedagogy-pitfall-card {
  background: rgba(217, 119, 6, 0.06);
  border-color: rgba(217, 119, 6, 0.25);
  border-left-color: #d97706;
}

.pedagogy-pitfall-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: #f59e0b;
  margin-bottom: 6px;
}

[data-theme="light"] .pedagogy-pitfall-header {
  color: #b45309;
}

.pedagogy-pitfall-body {
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-primary);
}

.pedagogy-scene-banner {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
  padding: 12px 18px;
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* Micro-Tokens & Chips */
.study-term-chip {
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 600;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent-light);
  padding: 1px 6px;
  border-radius: 5px;
  border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
  display: inline-block;
  vertical-align: baseline;
  letter-spacing: 0.2px;
}

[data-theme="light"] .study-term-chip {
  background: rgba(11, 47, 97, 0.08);
  color: var(--accent);
  border-color: rgba(11, 47, 97, 0.2);
}

.study-term-highlight {
  font-style: italic;
  font-weight: 600;
  color: var(--accent-light);
}

[data-theme="light"] .study-term-highlight {
  color: var(--accent);
}

.study-term-paren {
  color: var(--text-secondary);
}

/* Bottom Pagination Pills */
.study-pills-footer {
  flex-shrink: 0;
  margin-top: 16px;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
}

.study-pill-btn {
  background: none;
  border: none;
  padding: 6px 3px;
  cursor: pointer;
  display: flex;
  align-items: center;
  outline: none;
}

.study-pill {
  display: block;
  width: 16px;
  height: 4px;
  border-radius: 4px;
  background: var(--border);
  transition: all 0.25s ease;
}

.study-pill.active {
  width: 32px;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
}

.mobile-only { display: none !important; }
.pc-only { display: flex; }

/* Nav utility controls: theme and language sit together at the end of the bar
   with one treatment. The theme toggle used to be .mobile-only (the floating
   pill covered its job on desktop) and the language button was a bordered box
   next to a borderless icon — two controls doing the same class of work,
   styled as if unrelated. */
#theme-toggle-btn, #student-theme-toggle-btn {
  color: var(--text-secondary);
}
#theme-toggle-btn .theme-svg-icon,
#student-theme-toggle-btn .theme-svg-icon { width: var(--icon-lg); height: var(--icon-lg); }
.nav-lang-btn {
  min-width: max(var(--control-sm), var(--tap-min));
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--ls-wide);
  color: var(--text-secondary);
}
#theme-toggle-btn:hover, #student-theme-toggle-btn:hover, .nav-lang-btn:hover { color: var(--text-primary); }

.ai-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.5px;
  background: var(--accent);
  color: #ffffff;
  padding: 2px 6px;
  border-radius: 4px;
  text-transform: uppercase;
  line-height: 1.2;
}

.rank-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 800;
  padding: 2px 7px;
  border-radius: 6px;
  margin-right: 6px;
}
.rank-badge.rank-1 { background: rgba(255, 215, 0, 0.15); color: #ffd700; border: 1px solid rgba(255, 215, 0, 0.4); }
.rank-badge.rank-2 { background: rgba(192, 192, 192, 0.15); color: #c0c0c0; border: 1px solid rgba(192, 192, 192, 0.4); }
.rank-badge.rank-3 { background: rgba(205, 127, 50, 0.15); color: #cd7f32; border: 1px solid rgba(205, 127, 50, 0.4); }

@media (max-width: 1024px) {
    /* Completely remove Read Textbook from Mobile/Tablets */
    [data-tab="book"], [data-tab="s-book"], 
    #l-sidebar-book-tab, #s-sidebar-book-tab,
    #lecturer-book-tab, .pdf-container, .mobile-preview {
        display: none !important;
    }

    .study-container {
        flex-direction: column !important;
        height: auto !important;
        /* Same iOS trap as the body rule: `100vh` is the LARGE viewport, so
           while Safari's toolbars are showing this floor is ~90-140px taller
           than the screen and the study page scrolls past its own content into
           a strip of page background. `!important` has to be repeated on the
           fallback pair, or the dvh line loses to the vh one above it. */
        min-height: 100vh !important;
        min-height: 100dvh !important;
    }
    
    /* Study Units Sidebar (now top) */
    .study-sidebar,
    .study-container > div:first-child {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
        border-right: none !important;
        border-bottom: 1px solid var(--border) !important;
        max-height: 250px !important;
        height: auto !important;
        background: var(--bg-secondary) !important;
        padding: 0 !important;
    }
    
    .study-sidebar-header {
        padding: 12px 16px !important;
    }
    
    .study-sidebar-toc {
        max-height: 200px !important;
        padding: 10px 16px !important;
    }

    /* Study Content Area */
    .study-content-panel,
    .study-container > div:last-child {
        width: 100% !important;
        height: auto !important;
        padding: 20px 14px !important;
        background: var(--bg-primary) !important;
        overflow: visible !important;
    }

    .study-content-area,
    .study-topic-wrapper {
        height: auto !important;
    }

    .study-card {
        height: auto !important;
        max-height: none !important;
        padding: 20px 16px !important;
        overflow: visible !important;
    }

    #s-ai-book-content-area, #ai-book-content-area {
        font-size: 17px !important;
        line-height: 1.6 !important;
    }
    
    .mobile-only { display: inline-flex !important; }
    .pc-only { display: none !important; }
}

.new-chat-item {
    transition: all 0.2s ease;
}
.new-chat-item:hover {
    border-color: var(--accent) !important;
    transform: translateY(-2px);
    background: var(--accent-glow) !important;
}
.new-chat-item:active {
    transform: scale(0.98);
}

.method-card:hover {
    transform: none !important;
    border-color: var(--accent) !important;
    box-shadow: none !important;
    background: var(--bg-card-hover) !important;
}

.method-card h3 {
    transition: var(--transition);
}

.method-card:hover h3 {
    color: var(--accent-light);
}

.level-btn.active {
    background: var(--accent) !important;
    color: white !important;
    border-color: var(--accent) !important;
    box-shadow: none !important;
}

.lang-btn.active {
    border-color: var(--accent) !important;
    background: var(--accent-glow) !important;
    box-shadow: none !important;
}

/* The sharp, unshadowed academic treatment these three blanket !important
   rules used to enforce is now a property of the components themselves: every
   surface, control and indicator takes its corner from the radius scale and
   none of them carry decorative elevation. Keeping the sledgehammer as well
   only meant it also flattened the two places where elevation is meaningful —
   the overlay and the drawer — and overrode the sheet's own corner radius,
   which is what left the AI Architect's action bar floating 40px above the
   bottom of the sheet on a phone. */
.card,
.classroom-card,
.method-card,
.stat-card,
.chapter-block,
.activity-card,
.chat-wrapper,
.syllabus-chapter,
.report-card,
.study-card {
  box-shadow: none;
}

.classroom-status,
.nav-badge,
.progress-bar-container,
.progress-bar,
.listrow__bar,
.listrow__bar > i,
.progress-fill,
.progress-bar-fill,
.tag-badge {
  border-radius: var(--radius-sm);
  box-shadow: none;
}

/* Chat bubble styling: clean sheets rather than round SaaS bubbles */
.chat-bubble {
  border-radius: var(--radius) !important;
  box-shadow: none !important;
}
.chat-bubble.sent {
  border-bottom-right-radius: 0 !important;
  background: var(--gradient-1) !important;
}
.chat-bubble.received {
  border-bottom-left-radius: 0 !important;
  background: var(--bg-input) !important;
  border: 1px solid var(--border) !important;
}

/* Custom Checkbox */
.checkbox-container {
  display: inline-flex !important;
  align-items: center !important;
  min-height: max(var(--control-md), var(--tap-min));
  gap: var(--space-5) !important;
  cursor: pointer !important;
  user-select: none !important;
  font-size: 13px !important;
  color: var(--text-secondary) !important;
  font-family: var(--font-ui)!important;
  text-transform: none !important;
  margin-bottom: 0 !important;
  transition: color 0.2s;
}

.checkbox-container:hover {
  color: var(--text-primary) !important;
}

.checkbox-container input {
  position: absolute !important;
  opacity: 0 !important;
  cursor: pointer !important;
  height: 0 !important;
  width: 0 !important;
  margin: 0 !important;
}

.checkbox-custom {
  display: inline-block !important;
  flex-shrink: 0 !important;
  width: 18px !important;
  height: 18px !important;
  background: rgba(255, 255, 255, 0.02) !important;
  border: 1px solid var(--border) !important;
  border-radius: var(--radius-sm) !important;
  position: relative !important;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
  box-sizing: border-box !important;
}

[data-theme="light"] .checkbox-custom {
  background: rgba(0, 0, 0, 0.02) !important;
}

.checkbox-container:hover input ~ .checkbox-custom {
  border-color: var(--accent-light) !important;
}

.checkbox-container input:checked ~ .checkbox-custom {
  background: var(--accent-glow) !important;
  border-color: var(--accent) !important;
}

.checkbox-custom::after {
  content: "" !important;
  position: absolute !important;
  display: none !important;
  left: 5px !important;
  top: 1px !important;
  width: 5px !important;
  height: 9px !important;
  border: solid var(--accent) !important;
  border-width: 0 2px 2px 0 !important;
  transform: rotate(45deg) !important;
  box-sizing: border-box !important;
}

.checkbox-container input:checked ~ .checkbox-custom::after {
  display: block !important;
}

/* Responsive overrides for vocab cards and confirm modal */
@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  .study-vocab-card {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 12px 16px;
  }
  .study-vocab-card .english-translation {
    text-align: left !important;
    min-width: 0 !important;
    width: 100%;
    max-width: 100%;
    align-items: flex-start;
    margin-top: 4px;
    border-top: 1px solid rgba(255,255,255,0.05);
    padding-top: 8px;
    padding-left: 32px; /* Align translation with the foreign word text (offsetting button width) */
  }
  [data-theme="light"] .study-vocab-card .english-translation {
    border-top-color: rgba(0,0,0,0.05);
  }
}

/* The #confirm-modal centring override that used to live here is gone: every
   dialog is centred on mobile now, so it had nothing left to correct. */

/* ── Modern Classroom Build Banner ── */
.build-banner-card {
  position: relative;
  background: var(--bg-card);
  border: 1px solid var(--accent);
  border-radius: var(--radius-lg, 14px);
  padding: 18px 22px;
  margin-bottom: 24px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow: hidden;
  transition: all 0.3s ease;
}
.build-banner-card.build-failed {
  border-color: var(--danger, #ef4444) !important;
}
.build-banner-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}
.build-banner-left {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: 1;
  min-width: 240px;
}
.build-banner-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  gap: 8px;
}
.build-stage-badge {
  font-size: 10px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.build-banner-right {
  display: flex;
  align-items: center;
  gap: 12px;
}
.build-pct-pill {
  font-size: 16px;
  font-weight: 800;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  background: var(--accent-glow);
  padding: 4px 10px;
  border-radius: 8px;
  border: 1px solid var(--accent-line);
}
.build-banner-detail {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.4;
  margin-top: 2px;
}
.build-steps-track {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}
@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  .build-steps-track {
    grid-template-columns: repeat(2, 1fr);
  }
}
.build-step-node {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--text-muted);
  font-weight: 500;
  padding: 6px 10px;
  border-radius: 6px;
  background: var(--bg-primary, rgba(0,0,0,0.05));
  transition: all 0.3s ease;
}
.build-step-node.active {
  color: var(--accent);
  background: var(--accent-soft);
  font-weight: 700;
  box-shadow: inset 0 0 0 1px var(--accent-line);
}
.build-step-node.done {
  color: var(--success, #10b981);
  background: rgba(16, 185, 129, 0.1);
  font-weight: 600;
}
.build-step-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.build-banner-bar {
  height: 8px;
  background: var(--bg-input);
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--border);
  position: relative;
}
.build-banner-fill {
  height: 100%;
  background: var(--gradient-2);
  width: 0%;
  border-radius: 10px;
  transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
}
.build-banner-fill::after {
  content: '';
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
  animation: shine 1.8s infinite;
}
/* ==========================================================================
   CONVERSATIONAL DIALOGUE OVERLAY / CHAT THREAD REDESIGN
   ========================================================================== */
.dialogue-thread-container {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-top: 12px;
  margin-bottom: 12px;
  position: relative;
}

.study-dialogue-card {
  position: relative;
  background: var(--bg-card, var(--bg-input));
  padding: 16px 20px;
  border-radius: 14px;
  border: 1px solid var(--border);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
  margin-bottom: 8px;
  width: 100%;
  box-sizing: border-box;
}

.study-dialogue-card:hover {
  border-color: var(--accent-line);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.14);
}

.study-dialogue-card.speaker-a {
  border-left: 4px solid var(--accent);
  border-radius: 16px 16px 16px 6px;
  background: linear-gradient(180deg, var(--accent-glow) 0%, rgba(0, 0, 0, 0) 100%), var(--bg-input);
}

.study-dialogue-card.speaker-b {
  border-left: 4px solid #10b981;
  border-radius: 16px 16px 6px 16px;
  background: linear-gradient(180deg, rgba(16, 185, 129, 0.05) 0%, rgba(0, 0, 0, 0) 100%), var(--bg-input);
}

.dialogue-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
  gap: 8px;
}

.dialogue-speaker-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.dialogue-speaker-avatar {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  flex-shrink: 0;
}

.speaker-a .dialogue-speaker-avatar {
  background: var(--accent-soft);
  color: var(--accent);
  border: 1.5px solid var(--accent-line);
}

.speaker-b .dialogue-speaker-avatar {
  background: rgba(16, 185, 129, 0.18);
  color: #10b981;
  border: 1.5px solid rgba(16, 185, 129, 0.45);
}

.dialogue-speaker-name {
  font-weight: 700;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.7px;
}

.speaker-a .dialogue-speaker-name {
  color: var(--accent);
}

.speaker-b .dialogue-speaker-name {
  color: #10b981;
}

.dialogue-card-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.dialogue-phrase {
  font-style: italic;
  font-size: 16.5px;
  font-weight: 600;
  line-height: 1.55;
  color: var(--text-primary);
  display: block;
}

.dialogue-translation-box {
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 8px 12px;
  font-size: 13.5px;
  color: var(--text-secondary);
  line-height: 1.45;
  margin-top: 8px;
  transition: opacity 0.15s ease-in-out;
}

.dialogue-translation-box.hidden-trans {
  display: none !important;
}

[data-theme="light"] .dialogue-translation-box {
  background: rgba(0, 0, 0, 0.04);
  border-color: rgba(0, 0, 0, 0.08);
}

.dialogue-trans-toggle-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-secondary);
  font-size: 11px;
  font-weight: 600;
  border-radius: 6px;
  padding: 3px 8px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  transition: all 0.15s ease;
}

.dialogue-trans-toggle-btn:hover {
  background: var(--fill-hover);
  color: var(--text-primary);
  border-color: var(--accent);
}

.dialogue-trans-toggle-btn.active {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: var(--accent-line);
}


/* ── Touch target floor ──────────────────────────────────
   Icon-only controls carry no label to give them width, so they were ending
   up 24px and 36px wide. These are the real interactive elements of the
   product — a delete on a class card, the pronunciation button beside a
   sentence — and they get a proper square target. */
.btn-ghost:not(.btn-full):empty,
.btn-ghost > svg:only-child { pointer-events: none; }

.btn.btn-ghost.btn-sm,
.btn.btn-ghost.btn-xs {
  min-width: max(var(--control-sm), var(--tap-min));
}
.tts-btn,
.tts-link-btn,
.mobile-menu-btn,
button.mobile-only {
  min-width: max(var(--control-md), var(--tap-min));
  min-height: max(var(--control-md), var(--tap-min));
}

/* The brand block doubles as a control, so it gets a row height rather than
   hugging a 20px logo. */
.nav-brand { min-height: max(var(--control-md), var(--tap-min)); }

/* ── Top bar chrome ──────────────────────────────────────
   The class name and code used to carry their layout in inline style
   attributes, so the breakpoint ladder could not reach them and the bar had
   no way to shed weight as it narrowed. */
.nav-course-name {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  border-inline-start: 1px solid var(--border);
  padding-inline-start: var(--space-4);
  margin-inline-start: var(--space-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 14ch;
}
.nav-course-code {
  font-size: var(--fs-xs);
  font-family: var(--font-mono);
  font-weight: var(--fw-bold);
  color: var(--accent);
  background: var(--accent-glow);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  border: 1px solid var(--accent-line);
  margin-inline-start: var(--space-3);
  white-space: nowrap;
}
.nav-back-btn {
  flex-shrink: 0;
  color: var(--text-muted);
  margin-inline-end: var(--space-2);
}
.nav-back-btn:hover { color: var(--text-primary); }

/* ── Selects ─────────────────────────────────────────────
   Native select chrome is a different shape, colour and height on every
   platform, so next to a styled text input it reads as a foreign control.
   These draw their own chevron and match the input ladder exactly. */
.select-input,
select.text-input,
.form-group select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-inline-end: var(--space-10);
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    right var(--space-6) center,
    right calc(var(--space-6) - 5px) center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  cursor: pointer;
}
.select-input:disabled,
select.text-input:disabled { cursor: not-allowed; }
/* The dropdown list itself is drawn by the OS; give it readable colours. */
.select-input option,
select.text-input option,
.form-group select option {
  background: var(--surface-2);
  color: var(--text-primary);
}

/* A caveat about what a form will produce, placed above the action it
   qualifies rather than orphaned below it. */
.form-note {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  line-height: var(--lh-snug);
  max-width: 72ch;
  margin-bottom: var(--space-6);
}

/* ── Form measure ────────────────────────────────────────
   A single field stretched across a 1200px card is hard to scan and makes a
   short form look unfinished. Fields in a full-width card get a comfortable
   measure; fields inside a .form-row keep sharing the row equally. */
.card-body > .form-group > input,
.card-body > .form-group > select,
.card-body > .form-group > textarea,
.card-body > form > .form-group > input,
.card-body > form > .form-group > select,
.card-body > form > .form-group > textarea {
  max-width: 44rem;
}
.form-row .form-group > input,
.form-row .form-group > select,
.form-row .form-group > textarea { max-width: none; }

/* ════════════════════════════════════════════════════════════════════════════
   MATERIAL READER — mobile density and navigation
   ----------------------------------------------------------------------------
   Measured on real generated lessons at 320-414px, the reader spent roughly
   440px — over half a phone viewport — on chrome before the first line of the
   lesson: a page title, a stale subtitle, an export button, an inline unit
   navigator, a breadcrumb, a page heading and a CEFR blurb, repeated on every
   page. The only "next page" control rendered 81-147px off the right edge, and
   the only other page control was a row of dots at the bottom of a 2,500px
   scroll. This section replaces that with one sticky bar and a set of compact,
   script-safe content blocks.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Material toolbar ─────────────────────────────────────
   One sticky row, ~46px, carrying position + outline + PDF + step controls.
   It is the only persistent chrome the reader adds, and it stands in for a
   page title, a stale subtitle, an export button, an inline unit list, a
   breadcrumb and a CEFR blurb that were repeated on every lesson page. */
.mtoolbar {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 46px;
  padding: var(--space-1) 0;
  margin-bottom: var(--space-5);
  background: var(--surface-nav);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--line);
}
.mtoolbar__where {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: max(var(--control-md), var(--tap-min));
  padding: 0 var(--space-4);
  border: none;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-primary);
  font: inherit;
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-snug);
  cursor: pointer;
  text-align: start;
}
.mtoolbar__where:hover { background: var(--fill-hover); }
.mtoolbar__title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mtoolbar__pos {
  flex-shrink: 0;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  margin-inline-start: auto;
}
.mtoolbar__caret { width: 13px; height: 13px; flex-shrink: 0; color: var(--text-muted); }

.mtoolbar__pdf { flex-shrink: 0; color: var(--accent-light); }
[data-theme="light"] .mtoolbar__pdf { color: var(--accent); }
.mtoolbar__pdf svg { width: var(--icon); height: var(--icon); }

.mtoolbar__step {
  flex-shrink: 0;
  font-size: var(--fs-2xl);
  line-height: 1;
  color: var(--text-secondary);
  padding-bottom: 3px;
}
.mtoolbar__step:disabled { opacity: 0.22; }

.mtoolbar__progress {
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--line-subtle);
}
.mtoolbar__progress > span { display: block; height: 100%; background: var(--accent); transition: width var(--transition); }

/* ── Course outline sheet ─────────────────────────────────
   Units, their topics, and the pages of the topic being read — the whole
   course reachable in one gesture, so switching unit and jumping to a section
   are the same cheap action. */
.outline-sheet__panel { max-width: 560px; }
.outline__unit + .outline__unit { margin-top: var(--space-7); }
.outline__unit-title {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--text-muted);
  margin-bottom: var(--space-4);
}
.outline__unit-no {
  flex-shrink: 0;
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  background: var(--fill-subtle);
  color: var(--text-secondary);
  font-size: var(--fs-2xs);
  font-variant-numeric: tabular-nums;
}
.outline__topic {
  display: block;
  width: 100%;
  min-height: max(var(--control-lg), var(--tap-min));
  padding: var(--space-3) var(--space-5);
  border: none;
  border-inline-start: 2px solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--fs-md);
  text-align: start;
  cursor: pointer;
}
.outline__topic:hover { background: var(--fill-hover); color: var(--text-primary); }
.outline__topic.is-current {
  color: var(--text-primary);
  font-weight: var(--fw-semibold);
  border-inline-start-color: var(--accent);
  background: var(--accent-glow);
  border-start-start-radius: 0;
  border-end-start-radius: 0;
}
[data-theme="light"] .outline__topic.is-current { color: var(--accent); }

.outline__pages {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: var(--space-2) 0 var(--space-3) var(--space-6);
  padding-inline-start: var(--space-5);
  border-inline-start: 1px solid var(--line-subtle);
}
.outline__page {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
  min-height: max(var(--control-md), var(--tap-min));
  padding: var(--space-2) var(--space-4);
  border: none;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-muted);
  font-size: var(--fs-base);
  text-align: start;
  cursor: pointer;
}
.outline__page:hover { background: var(--fill-hover); color: var(--text-primary); }
.outline__page.is-current { color: var(--text-primary); font-weight: var(--fw-medium); }
.outline__num {
  flex-shrink: 0;
  width: 18px;
  font-size: var(--fs-2xs);
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.outline__page.is-current .outline__num { color: var(--accent); }
.outline__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.outline-sheet__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: var(--space-7);
  padding-top: var(--space-6);
  border-top: 1px solid var(--line-subtle);
}
.outline-sheet__actions .btn { justify-content: flex-start; gap: var(--space-5); }

/* ── Lesson page furniture ────────────────────────────── */
.study-meta { margin-bottom: var(--space-3); }
.study-page-heading { margin-bottom: var(--space-6); }

/* Footer nav mirrors the bar so a reader who has scrolled to the end does not
   have to scroll back up. */
.study-footer-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  margin-top: var(--gap-section);
  padding-top: var(--space-6);
  border-top: 1px solid var(--line-subtle);
}

/* ── Vocabulary rows ──────────────────────────────────── */
.vocab-row {
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-5) var(--pad-row);
}
.vocab-row + .vocab-row { margin-top: var(--gap-tight); }

.vocab-row__main { display: flex; align-items: flex-start; gap: var(--space-4); min-width: 0; }
.vocab-row__audio { flex-shrink: 0; margin-top: 1px; }
.vocab-row__text { flex: 1 1 auto; min-width: 0; }

/* The term takes whatever width it needs. A German compound, an Arabic string
   with harakat and a four-character CJK run all wrap rather than clip. */
.vocab-row__term {
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  line-height: var(--lh-snug);
  display: block;
  overflow-wrap: break-word;
}

/* Transcription and meaning share one wrapping line beneath the term. */
.vocab-row__gloss {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-2);
  min-width: 0;
}
.vocab-row__ipa {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--accent-light);
  white-space: nowrap;
  unicode-bidi: isolate;
}
[data-theme="light"] .vocab-row__ipa { color: var(--accent); }
.vocab-row__meaning {
  font-size: var(--fs-md);
  color: var(--text-secondary);
  line-height: var(--lh-snug);
  min-width: 0;
}
.vocab-row__detail { margin-top: var(--space-4); }
.vocab-row__note {
  font-size: var(--fs-base);
  color: var(--text-secondary);
  line-height: var(--lh-normal);
  margin-bottom: var(--space-4);
}

/* ── Example block ────────────────────────────────────────
   One recessed well, not a bordered card inside a bordered card. The target
   sentence and its translation are distinguished by weight, colour and a
   leading accent rule rather than by another box. */
.example-block {
  background: var(--surface-3);
  border-inline-start: 2px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: var(--space-4) var(--space-5);
}
.example-block__row { display: flex; align-items: flex-start; gap: var(--space-4); }
.example-block__target {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  color: var(--text-primary);
  line-height: var(--lh-snug);
  overflow-wrap: break-word;
}
.example-block__trans {
  font-size: var(--fs-base);
  color: var(--text-muted);
  line-height: var(--lh-snug);
  margin-top: var(--space-3);
}

/* Phonetic badges everywhere in the reader share the notation treatment. */
.phonetic-badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--accent-light);
  background: var(--accent-glow);
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-sm);
  padding: 1px var(--space-4);
  letter-spacing: var(--ls-normal);
  white-space: nowrap;
  unicode-bidi: isolate;
}
[data-theme="light"] .phonetic-badge { color: var(--accent); }

/* ── Reader chrome on phones ──────────────────────────────
   Below the tablet breakpoint the lesson bar carries navigation, so the layers
   that merely repeated it stand down. Nothing educational is hidden: what goes
   is the tab title already shown in the nav, a subtitle that still said
   "choose a topic" after a topic was chosen, the inline unit list now reachable
   from the bar, and a generic CEFR blurb repeated on every page of every
   lesson. Together they were ~300px of the ~440px of pre-content chrome. */
@media (max-width: 1024px) {
  /* The unit navigator becomes a sheet, opened from the lesson bar. */
  #s-ai-book-container .study-sidebar,
  #ai-book-container .study-sidebar { display: none; }

  /* Page title + stale subtitle + export button above the reader. Export
     stays available from the units sheet and on desktop. */
  #tab-s-study-tab > .page-header,
  #tab-study-materials > .page-header { display: none; }

  /* Boilerplate repeated on every lesson page. */
  .cefr-level-subtitle { display: none; }

  .study-content-panel,
  .study-container > div:last-child { padding: 0 !important; }

  /* The card stops being a card — it is the page itself — but it keeps a
     reading inset. With the padding zeroed outright, every block inside the
     lesson (rule cards, callouts, vocabulary rows, bulleted lines) sat flush
     against the border of the frame around it, which is what made the text
     read as glued to the edge of the screen. Inline only: vertical density
     is untouched. */
  .study-card {
    padding-block: 0 !important;
    padding-inline: var(--pad-read) !important;
    background: transparent !important;
    border: none !important;
    overflow: visible !important;
  }

  /* Siblings of the card inside the same column get the same inset, so the
     lesson reads as one text column rather than three differently-indented
     ones. The toolbar is deliberately excluded: it is a bar and spans the
     full width of the frame. */
  .study-footer-nav,
  .study-meta { padding-inline: var(--pad-read); }

  .study-topic-wrapper { padding: 0; }

  /* The reader's own bar is the page chrome, so it sits directly beneath the
     nav rather than below a band of page padding. */
  .dashboard-content:has(#tab-s-study-tab.active),
  .dashboard-content:has(#tab-study-materials.active) {
    padding-top: calc(var(--topnav-h) + env(safe-area-inset-top, 0px));
  }

  /* The page name is in the sticky bar at all times; repeating it as a heading
     that scrolls away is duplication. The <h1> stays in the document so the
     heading outline and screen readers are unaffected — only its pixels go. */
  .study-page-heading {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* The dot row at the foot of the page is redundant once the bar and the
     footer buttons exist, and it was the only page control for readers who
     scrolled to the end. */
  .study-pills-footer { display: none; }

  /* Rule and contrast blocks: one surface each, not a card inside a card. */
  .pedagogy-rule-card { padding: var(--space-6); }
  .pedagogy-rule-example-box {
    background: var(--surface-3);
    border: none;
    border-inline-start: 2px solid var(--accent);
    border-radius: 0 var(--radius) var(--radius) 0;
    padding: var(--space-4) var(--space-5);
  }
  .pedagogy-guide-block { padding: var(--space-5) var(--space-6); }
  .pedagogy-rule-item { padding: var(--space-4) 0; background: transparent; }
  .pedagogy-contrast-card { padding: var(--space-5) var(--space-6); }
  .pedagogy-pitfall-card { padding: var(--space-5) var(--space-6); }
  .pedagogy-scene-banner { padding: var(--space-5) var(--space-6); }
}

/* On a phone the reader is the whole screen: the page itself scrolls, so every
   ancestor between the lesson bar and the root must be non-scrolling. The
   desktop layout nests the reader inside its own scroll panes, which made the
   bar stick to an inner scrollport and sit 56px below where it belonged,
   overlapping the lesson heading underneath it. Plain block flow here also
   avoids the flex sizing that the desktop two-pane layout needs and the phone
   does not. */
@media (max-width: 1024px) {
  .study-container,
  .study-content-panel,
  .study-content-area,
  .study-topic-wrapper,
  #s-ai-book-content-area,
  #ai-book-content-area {
    display: block !important;
    height: auto !important;
    max-height: none !important;
    overflow: visible !important;
  }
  .mtoolbar { top: calc(var(--topnav-h) + env(safe-area-inset-top, 0px)); }
}

/* Assessment options are the most-tapped controls in the product. */
.study-card .options-grid { display: grid; gap: var(--space-4); }
.study-card .options-grid .btn {
  min-height: max(var(--control-xl), var(--tap-min));
  justify-content: flex-start;
  text-align: start;
  font-size: var(--fs-md);
  line-height: var(--lh-snug);
  padding: var(--space-5) var(--space-6);
  white-space: normal;
  height: auto;
}

/* ════════════════════════════════════════════════════════════════════════════
   DASHBOARD DENSITY ON PHONES
   ----------------------------------------------------------------------------
   Measured at 390px, the lecturer overview was 1,551px — 1.8 screens — to show
   four numbers and two "nothing here yet" states. The height was not going to
   content: a 129px card per number, a 171px empty state per card, and a page
   header repeating what the screen already said. None of this is fixed by
   smaller type; it is fixed by tighter containers and less repetition.
   ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 1024px) {
  /* Page header: one line of title, one of context, and the actions beside
     them rather than below. */
  .page-header { margin-bottom: var(--space-6); row-gap: var(--space-2); }
  .page-header h1 { font-size: var(--fs-2xl); line-height: var(--lh-tight); }
  .page-header .subtitle { font-size: var(--fs-sm); margin-top: 0; }

  .stat-card { padding: var(--space-5) var(--space-6); }
  .stat-label { font-size: var(--fs-2xs); }
  .stat-value { font-size: var(--fs-3xl); margin-top: var(--space-2); }
  .stats-grid { gap: var(--space-4); margin-bottom: var(--space-7); }

  /* An empty state inside a card should fill the card, not set its height. */
  .card-body > .empty-state-sm:only-child { padding: var(--space-7) var(--space-5); }
  .empty-state-sm .empty-state__mark { width: 28px; height: 28px; }

  .grid-2col { gap: var(--space-5); }
  .danger-zone { margin-top: var(--gap-section); }
}

/* At phone widths the metric row goes three-up: a label and a number need far
   less width than a sentence, and three short columns beat two tall rows. */
@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  /* Two columns, not three: with four metrics both give two rows, but the
     wider column stops labels like "Eksiğim Olan Konular" breaking across
     three lines, so the row is shorter as well as more legible. */
  .stats-grid { grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr)); }
  .stat-card { padding: var(--space-5); }
  .stat-value { font-size: var(--fs-2xl); }

  /* A metric is a label and a number. The sentence underneath explains the
     metric, which is worth its height on a tablet and is the first thing to go
     when four of them share a phone screen — the label already names the
     metric, and the sentence stays in the DOM for screen readers. */
  .stat-sub {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* ── Classroom card ───────────────────────────────────────
   Was 269px on a phone: a language label row, a name, a semester line, a
   dashed full-width box holding one five-digit code, and a footer button,
   each separated by its own margin. The code is metadata, so it joins the
   semester on one chip line and the card loses about a third of its height
   without losing a single fact. */
.classroom-card { position: relative; overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; }
.classroom-card.is-pending { opacity: 0.65; }
.classroom-card__building {
  position: absolute; inset-inline: 0; top: 0; height: 2px;
  background: var(--gradient-2);
  animation: slide 2s linear infinite;
}
.classroom-card__top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-4);
  margin-bottom: var(--space-3);
}
.classroom-card__lang {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  min-width: 0;
}
.classroom-card__delete { color: var(--danger); flex-shrink: 0; }
.classroom-card__tools { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }
.classroom-card__rename { color: var(--text-muted); opacity: .7; }
.classroom-card:hover .classroom-card__rename { opacity: 1; }
.classroom-card__rename:hover { color: var(--accent); }
.classroom-card__name {
  font-size: var(--fs-xl);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  margin-bottom: var(--space-3);
}
.classroom-card__meta { margin-bottom: var(--space-5); }
.classroom-card__code {
  font-family: var(--font-mono);
  font-weight: var(--fw-bold);
  color: var(--accent);
  letter-spacing: var(--ls-wide);
}

@media (max-width: 1024px) {
  .classroom-card .card-body { padding: var(--space-6); }
  .classroom-card__name { font-size: var(--fs-lg); }
}

/* ── Picker header ────────────────────────────────────────
   Title, supporting line and two actions in as few rows as the width allows. */
@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  .picker__header { padding-bottom: var(--space-5); }
  .picker__admin { margin-top: var(--gap-section); }
}

/* ── Minimum legible size ────────────────────────────────
   Density must not come out of type size. A handful of labels had drifted to
   10 and 10.5px — below anything readable on a phone, and below the 11px floor
   the rest of the scale already respects. These are raised to the bottom of
   the scale rather than being allowed to keep their own ad-hoc values. */
.pedagogy-rule-example-label,
.pedagogy-rule-card strong,
.pedagogy-guide-badge,
.pedagogy-formula-badge,
.pedagogy-contrast-tag,
.vocab-pos-badge,
.study-badge-page,
.chat-time,
.classroom-status {
  font-size: var(--fs-2xs);
}

/* Lesson prose keeps a comfortable reading size and leading on phones: the
   density in this pass comes from structure, never from shrinking the text a
   student actually has to read. */
@media (max-width: 1024px) {
  .pedagogy-rule-explanation,
  .pedagogy-rule-content,
  .pedagogy-single-note,
  .pedagogy-pitfall-body,
  .pedagogy-contrast-note,
  .vocab-row__note,
  .vocab-pedagogy-text {
    font-size: var(--fs-md);
    line-height: var(--lh-normal);
  }
  .pedagogy-rule-title { font-size: var(--fs-lg); line-height: var(--lh-snug); }
}

.pedagogy-scene-label {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--accent);
}
.pedagogy-analysis {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  line-height: var(--lh-snug);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px dashed var(--line);
}
.pedagogy-analysis__label {
  text-transform: uppercase;
  font-size: var(--fs-2xs);
  letter-spacing: var(--ls-caps);
  color: var(--accent-light);
}
[data-theme="light"] .pedagogy-analysis__label { color: var(--accent); }

/* Standalone tappable terms are controls, not prose, so they get a real target.
   Target-language words INSIDE a sentence stay inline — WCAG 2.5.8 exempts
   inline targets, and giving each word a 44px box would destroy the line. */
.vocab-row__term,
.dialogue-trans-toggle-btn {
  min-height: max(var(--control-md), var(--tap-min));
  display: flex;
  align-items: center;
}
.dialogue-trans-toggle-btn { display: inline-flex; }

/* ════════════════════════════════════════════════════════════════════════════
   MOBILE COMPACTION
   ----------------------------------------------------------------------------
   Density here comes from removing repetition and tightening containers, never
   from shrinking type or targets. Body text stays at its reading size and every
   control keeps its 44px floor; what goes is chrome that says the same thing
   twice and padding that carries no information.
   ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 1024px) {
  /* Nav chrome. 52px instead of 56 buys a row back on every screen without
     touching the targets inside it, which keep their own minimum. */
  :root { --topnav-h: 52px; }
  .topnav { gap: var(--space-3); }

  /* Page frame */
  .dashboard-content {
    /* One gap under the top bar for ordinary dashboard tabs. The study
       surfaces are deliberately excluded: their optical heights are set on
       .study-container above and are not this rule's to move. */
    padding-top: calc(var(--topnav-h) + env(safe-area-inset-top, 0px) + var(--space-8));
    /* Same: the safe area is the footer's to reserve, not this container's. */
    padding-bottom: var(--space-8);
  }
  .page-header { margin-bottom: var(--space-5); }
  .page-header h1 { font-size: var(--fs-xl); }

  /* Cards become rows: a bordered box per item, with its own 24px of padding
     on four sides, is desktop furniture. */
  .card { margin-bottom: var(--space-5); border-radius: var(--radius); }
  .card-header { padding: var(--space-4) var(--space-6); }
  .card-body { padding: var(--space-6); }
  .card-header h3 { font-size: var(--fs-base); }

  /* One action group, not a column of full-width buttons. */
  .page-header .page-actions { gap: var(--space-3); }
  .card-header > .btn { width: auto; }

  /* Sections */
  .report-section { margin-bottom: var(--space-7); }
  .form-group { margin-bottom: var(--space-6); }
  .chapter-block { margin-bottom: var(--space-4); }
  .activity-card, .quiz-header { padding: var(--space-6); }
  .quiz-result-card { padding: var(--space-9) var(--space-6); }
  .quiz-score-big { font-size: 56px; margin: var(--space-5) 0; }

  /* Overlays: a sheet's header should not cost a third of its height. */
  .modal-content { --modal-pad: var(--space-6); }
  .modal-content h2 { font-size: var(--fs-xl); }

  /* Curriculum */
  .chapter-header { padding: var(--space-4) var(--space-6); }
  .topic-item { padding: var(--space-4) var(--space-6); }
}

@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  .card-body { padding: var(--space-5); }
  .card-header { padding: var(--space-4) var(--space-5); }
  .modal-content { --modal-pad: var(--space-5); }
  .page-header h1 { font-size: var(--fs-lg); }

  /* Page actions sit beside the title when they fit rather than each claiming
     a full-width row of their own. */
  .page-header .page-actions { flex-wrap: nowrap; }
  .page-header .page-actions > .btn {
    flex: 1 1 auto;
    min-width: 0;
    padding-inline: var(--space-4);
  }
  .page-header .page-actions > .btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ── Reader on phones ─────────────────────────────────────
   The toolbar is the reader's chrome, so the page frame gives it the top of
   the screen and nothing else competes for it. */
@media (max-width: 1024px) {
  .dashboard-content:has(#tab-s-study-tab.active),
  .dashboard-content:has(#tab-study-materials.active) {
    padding-top: calc(var(--topnav-h) + env(safe-area-inset-top, 0px));
    padding-inline: var(--gutter-safe);
  }
  .study-meta { margin-bottom: var(--space-4); }
  .study-footer-nav { margin-top: var(--space-8); padding-top: var(--space-5); }
  .vocab-row { padding: var(--space-4) var(--space-5); }
  .vocab-row__detail { margin-top: var(--space-3); }
  .pedagogy-rule-card { padding: var(--space-5); margin-bottom: var(--space-4); }
  .pedagogy-contrast-card, .pedagogy-pitfall-card, .pedagogy-guide-block { padding: var(--space-5); }
  .pedagogy-rules-container { gap: var(--space-4); }
  .study-dialogue-card { padding: var(--space-5); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PHONE DENSITY
   ---------------------------------------------------------------------------
   Outside the material reader, vertical scrolling is the expensive resource.
   Everything below trades repeated chrome — padding, boxes inside boxes, one
   fact per line, a full-width button under every record — for information the
   person came to read. Nothing here shrinks body text or a touch target: the
   floors set in foundation.css (--fs-base for prose, --tap-min for controls)
   still hold, and density comes from structure instead.

   These rules live together rather than beside each component so the phone
   layout can be read, and changed, as one decision.
   ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {

  /* ── Metric row ──
     Four metrics used to be four stacked cards, each with a 34px display
     number and a caption, costing roughly 400px before the dashboard said
     anything. As a two-column strip the same four numbers cost about 130px and
     can be compared against each other, which is what a metric row is for.
     The label leads, the number sits opposite it on the same optical line, and
     the caption runs underneath on one line. */
  .stats-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--gap-section);
  }
  .stat-card {
    padding: var(--space-5);
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: baseline;
    column-gap: var(--space-4);
  }
  .stat-label { grid-column: 1; grid-row: 1; }
  .stat-value {
    grid-column: 2;
    grid-row: 1;
    margin-top: 0;
    font-size: var(--fs-2xl);
  }
  .stat-sub {
    grid-column: 1 / -1;
    grid-row: 2;
    margin-top: var(--space-2);
    font-size: var(--fs-2xs);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* ── Class picker ──
     The card's action moves beside its content instead of under it, so a class
     costs one row rather than a title block plus a 52px footer button. */
  .classroom-card {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
  }
  .classroom-card .card-body { padding: var(--space-5) var(--pad-row); }
  .classroom-card__top { margin-bottom: var(--space-2); }
  .classroom-card__name {
    font-size: var(--fs-md);
    margin-bottom: var(--space-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .classroom-card__meta { margin-bottom: 0; }
  .classroom-card > .btn:last-child {
    width: auto;
    border: none;
    border-inline-start: 1px solid var(--line-subtle);
    border-radius: 0;
    align-self: stretch;
    padding-inline: var(--space-6);
    min-height: 0;
  }
  /* A class that is still building keeps its progress on its own line: it is
     live state, not metadata, and it is the reason the person is looking. */
  .classroom-card:has(.classroom-card__building) { grid-template-columns: minmax(0, 1fr); }
  .classroom-card:has(.classroom-card__building) > .btn:last-child {
    width: 100%;
    border-inline-start: none;
    border-top: 1px solid var(--line-subtle);
    min-height: var(--control-lg);
  }

  /* ── At-risk list ──
     Name and badges on one row, wrapping only when the badges genuinely do not
     fit, instead of a bordered card per student. */
  .risk-item {
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    padding: var(--space-4) var(--pad-row);
    margin-bottom: var(--space-3);
  }
  .risk-badges { flex-wrap: wrap; }

  /* ── Progress readouts ──
     A progress row is a label and a number over a bar. 16px between rows was
     built for a desktop report card. */
  .progress-item { margin-bottom: var(--space-5); }
  .progress-label { font-size: var(--fs-sm); }

  /* ── Section rhythm ──
     Report sections were separated by 28px of nothing. */
  .report-section { margin-bottom: var(--gap-section); }
  .report-section h3 { font-size: var(--fs-lg); margin-bottom: var(--space-5); }
}

/* On the narrowest phones the metric strip keeps two columns — the labels are
   short enough — but the caption is allowed to go, because a caption that
   ellipses to three words is noise where the number is the point. */
@media (max-width: 340px) {
  .stat-sub { display: none; }
}

/* ── Toasts ──────────────────────────────────────────────
   A passive notice: it reports what already happened and dismisses itself, so
   it never blocks the screen. Centred at the top, clear of the notch and of
   the top nav, where it does not cover the content the person is reading and
   does not collide with the bottom-sheet dialogs. */
#toast-stack {
  position: fixed;
  top: calc(var(--topnav-h) + env(safe-area-inset-top, 0px) + var(--space-5));
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  width: max-content;
  max-width: min(420px, calc(100vw - (var(--gutter-safe) * 2)));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  cursor: pointer;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: var(--space-5) var(--space-6);
  font-size: var(--fs-base);
  line-height: var(--lh-snug);
  color: var(--text-primary);
  text-align: start;
  animation: toast-in 0.18s ease;
}
.toast--success { border-inline-start-color: var(--success); }
.toast--error   { border-inline-start-color: var(--danger); }
.toast--info    { border-inline-start-color: var(--accent); }
.toast.is-leaving { opacity: 0; transition: opacity 0.2s ease; }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; }
  .toast.is-leaving { transition: none; }
}


/* Mobile study pages sit at the intended optical height instead of being
   either hard-centred or pinned directly under the nav. This moves the reader
   as one block, so assessment and in-class activity pages share the same top. */
@media (max-width: 1024px) {
  .dashboard-content:has(#tab-study-materials.active) .study-container,
  .dashboard-content:has(#tab-s-study-tab.active) .study-container {
    /* The same 24px the ordinary tabs get from .dashboard-content's top
       padding. The reader's own :has() rules give it no padding at all, so the
       gap has to come from here instead — the total is identical either way.
       7vh was ~49px on a 700px screen, which is what left the reader sitting
       lower than every other surface. */
    margin-top: var(--space-8);
  }

  /* The in-class activity position was already approved; preserve it while
     assessment/lesson pages move slightly upward. */
  .study-container:has(#activity-preview:not(:empty)) {
    margin-top: 15vh;
  }

  /* The classroom picker has no top nav, so using the generic dashboard
     top-nav allowance pushes its first decision block too low on iPhone. */
  #classroom-selection-screen .dashboard-content.picker,
  #student-portal-screen .dashboard-content.picker {
    padding-top: calc(env(safe-area-inset-top, 0px) + 36px);
  }

  /* Do not animate the material shell/content into place on iOS. The content
     is already painted before reveal; these transforms only make that paint
     look like the old first-frame glitch. */
  .study-topic-wrapper, .study-card, #activity-preview {
    animation: none !important;
    transform: none !important;
  }

  html, body, body * { touch-action: manipulation; }
}

/* ── Profile pictures & account menu ────────────────────────────────────
   "Sign Out" used to be a text button at the end of every top bar. It is now
   a 32px avatar that opens a small account menu (My Profile, Sign Out), which
   frees ~60px for the tab row on desktop instead of adding a new control. */
.avatar {
  --avatar-size: 32px;
  width: var(--avatar-size);
  height: var(--avatar-size);
  flex: 0 0 var(--avatar-size);
  display: inline-grid;
  place-items: center;
  border-radius: 50%;
  overflow: hidden;
  background: var(--marker-bg);
  color: var(--marker-fg);
  box-shadow: inset 0 0 0 1px var(--line);
  font-family: var(--font-ui);
  font-size: calc(var(--avatar-size) * 0.38);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.02em;
  line-height: 1;
  user-select: none;
}
.avatar--sm { --avatar-size: 32px; }
.avatar--md { --avatar-size: 44px; }
.avatar--xl { --avatar-size: 96px; }
.avatar__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar__initials { display: block; }

.account-btn {
  display: inline-grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  margin-left: var(--space-1);
  border: 0;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  flex-shrink: 0;
}
.account-btn .avatar { transition: box-shadow var(--transition-fast); }
.account-btn:hover .avatar,
.account-btn[aria-expanded="true"] .avatar { box-shadow: inset 0 0 0 1px var(--line), 0 0 0 2px var(--accent-glow); }
.account-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.account-menu {
  position: fixed;
  z-index: var(--z-overlay);
  font-family: var(--font-ui);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  width: 248px;
  padding: var(--space-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-overlay);
}
.account-menu.hidden { display: none; }
.account-menu__head {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-4) var(--space-5);
  margin-bottom: var(--space-2);
  border-bottom: 1px solid var(--line-subtle);
}
.account-menu__who { min-width: 0; }
.account-menu__name {
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.account-menu__sub {
  margin-top: 2px;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.account-menu__item {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
  min-height: 40px;
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-ui);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  text-align: left;
  cursor: pointer;
}
.account-menu__item svg { width: 16px; height: 16px; flex-shrink: 0; }
.account-menu__item:hover,
.account-menu__item:focus-visible { background: var(--fill-hover); color: var(--text-primary); outline: none; }
.account-menu__item--danger:hover,
.account-menu__item--danger:focus-visible { color: var(--danger); }

/* Drawer header: avatar | name + role | close */
.drawer__header { grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; }
.drawer__avatar {
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: 50%;
  cursor: pointer;
}
.drawer__avatar:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* My Profile dialog */
.profile-card { max-width: 440px; width: 100%; font-family: var(--font-ui); font-size: var(--fs-base); line-height: var(--lh-normal); }
.profile-card h2 { margin-bottom: var(--space-7); }
.profile-card__photo {
  display: flex;
  align-items: center;
  gap: var(--space-7);
  padding-bottom: var(--space-7);
  border-bottom: 1px solid var(--line-subtle);
}
.profile-card__photo-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}
.profile-card__hint {
  flex-basis: 100%;
  margin: var(--space-2) 0 0;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.profile-card__fields { margin: var(--space-6) 0 0; display: grid; gap: var(--space-5); }
.profile-card__fields > div { display: grid; grid-template-columns: 140px minmax(0, 1fr); gap: var(--space-4); align-items: baseline; }
/* Same treatment as .field-label so the dialog reads like the rest of the forms. */
.profile-card__fields dt { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--text-secondary); }
.profile-card__fields dd { margin: 0; font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--text-primary); overflow-wrap: anywhere; }

@media (max-width: 480px) {
  .profile-card__photo { flex-direction: column; text-align: center; }
  .profile-card__photo-actions { justify-content: center; }
  .profile-card__fields > div { grid-template-columns: 1fr; gap: var(--space-1); }
}
.listrow__marker--photo { padding: 0; overflow: hidden; border-radius: 50%; }
.listrow__marker--photo .avatar__img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Photo cropper (inside My Profile) */
.profile-card.is-cropping .profile-card__photo,
.profile-card.is-cropping .profile-card__fields,
.profile-card.is-cropping .profile-card__password { display: none; }
.profile-card__password { margin-top: var(--space-6); padding-top: var(--space-5); border-top: 1px solid var(--line); }
.profile-card__password.is-open #pw-toggle { display: none; }
.pw-form { display: grid; gap: var(--space-4); }
.pw-form.hidden { display: none; }
.pw-form .form-group { margin: 0; }
.pw-form__hint { margin: 0; font-size: var(--fs-xs); color: var(--text-muted); }
.pw-form__error { margin: 0; font-size: var(--fs-sm); color: var(--danger, #f87171); }
.pw-form__error.hidden { display: none; }
.pw-form__actions { display: flex; justify-content: flex-end; gap: var(--space-3); flex-wrap: wrap; }
.cropper { display: flex; flex-direction: column; align-items: center; gap: var(--space-5); }
.cropper.hidden { display: none; }
.cropper__hint { margin: 0; font-size: var(--fs-sm); color: var(--text-secondary); text-align: center; }
.cropper__stage {
  position: relative;
  width: min(300px, 100%);
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--surface-3);
  cursor: grab;
  touch-action: none;
  user-select: none;
}
.cropper__stage.is-dragging { cursor: grabbing; }
.cropper__stage:focus-visible { box-shadow: var(--focus-ring); }
.cropper__stage img {
  position: absolute;
  left: 50%;
  top: 50%;
  max-width: none;
  transform-origin: center center;
  pointer-events: none;
  will-change: transform;
}
/* Darken everything outside the circle that will become the avatar. */
.cropper__mask {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 999px rgba(4, 12, 24, 0.62);
  outline: 2px solid rgba(255, 255, 255, 0.85);
  outline-offset: -2px;
  pointer-events: none;
}
.cropper__zoom {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  width: min(300px, 100%);
  color: var(--text-muted);
}
.cropper__zoom svg { width: 18px; height: 18px; flex-shrink: 0; }
.cropper__zoom input[type="range"] { flex: 1; accent-color: var(--accent); }
.cropper__actions { display: flex; justify-content: flex-end; gap: var(--space-3); width: 100%; padding-top: var(--space-5); border-top: 1px solid var(--line-subtle); }

/* Student detail (lecturer → student) */
.modal-content.sdetail-modal { max-width: 640px; width: 100%; font-family: var(--font-ui); }
.sdetail__loading { display: grid; place-items: center; min-height: 240px; }
.sdetail__head { display: flex; align-items: center; gap: var(--space-5); padding-right: var(--space-8); }
.avatar--lg { --avatar-size: 56px; }
.sdetail__who { min-width: 0; }
.sdetail__name { margin: 0; font-size: var(--fs-2xl); font-weight: var(--fw-semibold); overflow-wrap: anywhere; }
.sdetail__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); margin-top: var(--space-2); font-size: var(--fs-sm); color: var(--text-muted); }
.sdetail__num { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-secondary); }
.sdetail__presence { display: inline-flex; align-items: center; gap: var(--space-2); }
.sdetail__presence.is-online { color: var(--success); }
.sdetail__presence.is-online::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--success); }
.sdetail__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: var(--space-6) 0; }
.sdetail__actions .btn svg { width: 14px; height: 14px; }
.sdetail__stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4); }
.sdetail__stat { padding: var(--space-5); background: var(--surface-1); border: 1px solid var(--line); border-radius: var(--radius-lg); min-width: 0; }
.sdetail__stat-label { font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--text-muted); }
.sdetail__stat-value { margin-top: var(--space-2); font-size: var(--fs-3xl); font-weight: var(--fw-semibold); color: var(--text-primary); font-variant-numeric: tabular-nums; line-height: var(--lh-tight); }
.sdetail__stat-sub { margin-top: var(--space-1); font-size: var(--fs-xs); color: var(--text-muted); }
.sdetail__section { margin-top: var(--space-8); }
.sdetail__h { margin: 0 0 var(--space-4); font-size: var(--fs-md); font-weight: var(--fw-semibold); }
.sdetail__empty { margin: 0; padding: var(--space-6); text-align: center; font-size: var(--fs-sm); color: var(--text-muted); background: var(--surface-1); border: 1px dashed var(--line); border-radius: var(--radius-lg); }
.sdetail__unit + .sdetail__unit { margin-top: var(--space-5); }
.sdetail__unit-title { margin-bottom: var(--space-2); font-size: var(--fs-2xs); font-weight: var(--fw-semibold); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-muted); }
.sdetail__topic { display: grid; grid-template-columns: minmax(0, 1fr) minmax(80px, 34%) 40px; align-items: center; gap: var(--space-4); padding: var(--space-3) 0; border-bottom: 1px solid var(--line-subtle); font-size: var(--fs-sm); }
.sdetail__topic-name { color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sdetail__bar { height: 4px; border-radius: 2px; background: var(--line); overflow: hidden; }
.sdetail__bar i { display: block; height: 100%; border-radius: 2px; }
.sdetail__pct { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-secondary); font-weight: var(--fw-medium); }
.sdetail__answers { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; background: var(--surface-1); }
.sdetail__answer { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-4) var(--space-5); }
.sdetail__answer + .sdetail__answer { border-top: 1px solid var(--line-subtle); }
.sdetail__mark { flex: 0 0 24px; width: 24px; height: 24px; display: grid; place-items: center; border-radius: 50%; }
.sdetail__mark svg { width: 13px; height: 13px; }
.sdetail__mark.is-ok { color: var(--success); background: color-mix(in srgb, var(--success) 14%, transparent); }
.sdetail__mark.is-wrong { color: var(--danger); background: color-mix(in srgb, var(--danger) 14%, transparent); }
.sdetail__mark.is-partial { color: var(--warning); background: color-mix(in srgb, var(--warning) 14%, transparent); }
.sdetail__answer-main { flex: 1; min-width: 0; }
.sdetail__answer-prompt { font-size: var(--fs-sm); color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sdetail__answer-meta { margin-top: 2px; font-size: var(--fs-xs); color: var(--text-muted); }
.sdetail__answer-score { font-size: var(--fs-sm); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.sdetail__answer-score.is-ok { color: var(--success); }
.sdetail__answer-score.is-wrong { color: var(--danger); }
.sdetail__answer-score.is-partial { color: var(--warning); }
@media (max-width: 520px) {
  .sdetail__stats { gap: var(--space-3); }
  .sdetail__stat { padding: var(--space-4); }
  .sdetail__stat-value { font-size: var(--fs-2xl); }
  .sdetail__topic { grid-template-columns: minmax(0, 1fr) 64px 36px; }
}

/* ── Messaging ──────────────────────────────────────────────────────────
   One conversation component. Desktop: thread list | conversation. Phones:
   the list, and an opened conversation takes the screen under the top bar. */
.msgr {
  display: grid;
  grid-template-columns: minmax(260px, 320px) minmax(0, 1fr);
  height: clamp(440px, calc(100dvh - 230px), 780px);
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  overflow: hidden;
  font-family: var(--font-ui);
}
.msgr--single { grid-template-columns: minmax(0, 1fr); }
.msgr__threads { border-right: 1px solid var(--line); overflow-y: auto; background: var(--surface-1); }
.msgr__thread-list { display: flex; flex-direction: column; padding: var(--space-2); gap: 2px; }
.msgr__thread {
  display: flex; align-items: center; gap: var(--space-4);
  width: 100%; padding: var(--space-4); border-radius: var(--radius-lg);
  text-align: left; cursor: pointer; color: var(--text-secondary);
  transition: background var(--transition-fast);
}
.msgr__thread:hover { background: var(--fill-hover); }
.msgr__thread.is-active { background: var(--accent-glow); }
.msgr__thread-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.msgr__thread-top, .msgr__thread-bottom { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.msgr__thread-name { flex: 1; min-width: 0; font-size: var(--fs-base); font-weight: var(--fw-semibold); color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msgr__thread-time { flex-shrink: 0; font-size: var(--fs-xs); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.msgr__thread-preview { flex: 1; min-width: 0; font-size: var(--fs-sm); color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msgr__thread.is-unread .msgr__thread-preview { color: var(--text-primary); font-weight: var(--fw-medium); }
.msgr__thread.is-unread .msgr__thread-time { color: var(--accent); }
.msgr__unread {
  flex-shrink: 0; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px;
  display: inline-grid; place-items: center; background: var(--accent); color: var(--accent-contrast);
  font-size: var(--fs-2xs); font-weight: var(--fw-bold); font-variant-numeric: tabular-nums;
}
.msgr__conv { position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--surface-0); }
.msgr__placeholder { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-4); padding: var(--space-8); color: var(--text-muted); text-align: center; font-size: var(--fs-sm); }
.msgr__placeholder svg { width: 40px; height: 40px; opacity: 0.6; }
.msgr__placeholder p { margin: 0; max-width: 260px; }
.msgr__head {
  display: flex; align-items: center; gap: var(--space-4);
  min-height: 60px; padding: var(--space-3) var(--space-6);
  background: var(--surface-1); border-bottom: 1px solid var(--line);
}
.msgr__back { display: none; width: 36px; height: 36px; margin-left: calc(-1 * var(--space-3)); border-radius: 50%; color: var(--text-secondary); place-items: center; cursor: pointer; }
.msgr__back:hover { background: var(--fill-hover); color: var(--text-primary); }
.msgr__back svg { width: 22px; height: 22px; }
.msgr__who { min-width: 0; }
.msgr__name { font-size: var(--fs-base); font-weight: var(--fw-semibold); color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msgr__status { font-size: var(--fs-xs); color: var(--text-muted); }
.msgr__log {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-direction: column;
  padding: var(--space-6) var(--space-6) var(--space-6);
}
.msgr__log > :first-child { margin-top: auto; }
.msgr__empty { margin: auto; padding: var(--space-8); text-align: center; font-size: var(--fs-sm); color: var(--text-muted); }
.msgr__day { display: flex; justify-content: center; margin: var(--space-6) 0 var(--space-3); }
.msgr__day span { padding: 2px var(--space-4); border-radius: 999px; background: var(--surface-1); border: 1px solid var(--line-subtle); font-size: var(--fs-2xs); font-weight: var(--fw-medium); color: var(--text-muted); }

.msg { display: flex; flex-direction: column; margin-top: var(--space-4); animation: msg-in 0.18s ease-out; }
.msg.is-cont { margin-top: 3px; }
.msg.is-mine { align-items: flex-end; }
.msg.is-theirs { align-items: flex-start; }
@keyframes msg-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .msg { animation: none; } }
.msg__bubble {
  max-width: min(72%, 560px);
  padding: 8px 12px 6px;
  border-radius: 16px;
  font-size: var(--fs-base);
  line-height: var(--lh-snug);
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}
.msg.is-mine .msg__bubble { background: var(--accent); color: var(--accent-contrast); border-bottom-right-radius: 6px; }
.msg.is-theirs .msg__bubble { background: var(--surface-2); color: var(--text-primary); border: 1px solid var(--line-subtle); border-bottom-left-radius: 6px; }
.msg.is-mine.is-cont .msg__bubble { border-top-right-radius: 6px; }
.msg.is-theirs.is-cont .msg__bubble { border-top-left-radius: 6px; }
.msg__meta { float: right; display: inline-flex; align-items: center; gap: 4px; margin: 6px 0 -2px 10px; font-size: 10.5px; line-height: 1; opacity: 0.7; white-space: nowrap; font-variant-numeric: tabular-nums; }
.msg.is-pending .msg__bubble { opacity: 0.65; }
.msg.is-pending .msg__state::before { content: ""; display: inline-block; width: 8px; height: 8px; border: 1.5px solid currentColor; border-top-color: transparent; border-radius: 50%; animation: spin 0.8s linear infinite; }
.msg.is-failed .msg__bubble { background: var(--danger-bg); color: var(--danger); border: 1px solid var(--danger); }
.msg__retry { margin-top: 4px; padding: 0; font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--danger); cursor: pointer; }
.msg__retry:hover { text-decoration: underline; }

/* Delivery state on my messages: ✓ sent, ✓✓ seen. */
.msg.is-mine:not(.is-pending):not(.is-failed) .msg__state::before {
  content: ""; display: inline-block; width: 12px; height: 9px; background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 9'%3E%3Cpath d='M1 4.6l2.8 2.8L10.8 1' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 9'%3E%3Cpath d='M1 4.6l2.8 2.8L10.8 1' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
.msg.is-mine.is-read:not(.is-pending):not(.is-failed) .msg__state::before {
  width: 16px; color: #0b4fa8;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 9'%3E%3Cpath d='M1 4.6l2.8 2.8L10.8 1M7.2 7.4L14.2 1' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 9'%3E%3Cpath d='M1 4.6l2.8 2.8L10.8 1M7.2 7.4L14.2 1' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
[data-theme="light"] .msg.is-mine.is-read:not(.is-pending):not(.is-failed) .msg__state::before { color: #0b3f86; }
.msg.is-mine.is-read .msg__meta { opacity: 0.9; }
.msg__seen { align-self: flex-end; margin: 4px 2px 0; font-size: var(--fs-2xs); color: var(--text-muted); animation: msg-in 0.18s ease-out; }
/* "Typing…": three dots in a bubble on their side, at the foot of the log. */
.msg-typing {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 4px;
  margin-top: var(--space-4); padding: 11px 14px; border-radius: 16px; border-bottom-left-radius: 6px;
  background: var(--surface-2); border: 1px solid var(--line-subtle);
  animation: msg-in 0.18s ease-out;
}
.msg-typing span { width: 6px; height: 6px; border-radius: 50%; background: var(--text-muted); animation: msg-typing 1.2s ease-in-out infinite; }
.msg-typing span:nth-child(2) { animation-delay: 0.15s; }
.msg-typing span:nth-child(3) { animation-delay: 0.3s; }
@keyframes msg-typing { 0%, 60%, 100% { transform: none; opacity: 0.45; } 30% { transform: translateY(-3px); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .msg-typing span { animation: none; opacity: 0.7; } }
.msgr__status.is-typing.is-online { color: var(--accent); font-style: italic; }

/* Online dot on an avatar. */
.presence { position: relative; display: inline-flex; flex-shrink: 0; }
.presence.is-online::after {
  content: ""; position: absolute; right: 0; bottom: 0;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--success, #22c55e); box-shadow: 0 0 0 2px var(--surface-1);
}
.msgr__status.is-online { color: var(--success, #22c55e); }

/* Inbox rows: swipe to reveal actions (touch), "…" menu (mouse). */
.thread-swipe { position: relative; border-radius: var(--radius-lg); overflow: hidden; }
.thread-swipe .msgr__thread {
  position: relative; z-index: 1;
  background: var(--surface-1);
  touch-action: pan-y;
  will-change: transform;
}
.thread-swipe .msgr__thread:hover { background: linear-gradient(var(--fill-hover), var(--fill-hover)), var(--surface-1); }
.thread-swipe .msgr__thread.is-active { background: linear-gradient(var(--accent-glow), var(--accent-glow)), var(--surface-1); }
.thread-swipe__actions { position: absolute; top: 0; bottom: 0; display: flex; visibility: hidden; }
.thread-swipe.is-open .thread-swipe__actions { visibility: visible; }
.thread-swipe__actions--start { left: 0; }
.thread-swipe__actions--end { right: 0; }
.thread-act {
  width: 84px; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  font-size: var(--fs-2xs); font-weight: var(--fw-semibold); color: #fff; cursor: pointer;
}
.thread-act svg { width: 20px; height: 20px; }
.thread-act--pin { background: var(--accent); color: var(--accent-contrast); }
.thread-act--read { background: #3b82f6; }
.thread-act--delete { background: var(--danger); }
.msgr__thread-pin { flex-shrink: 0; display: inline-flex; color: var(--text-muted); }
.msgr__thread-pin svg { width: 13px; height: 13px; }
.msgr__unread--dot { min-width: 10px; width: 10px; height: 10px; padding: 0; }
.thread-more {
  position: absolute; z-index: 2; right: var(--space-3); top: 50%; transform: translateY(-50%);
  width: 30px; height: 30px; border-radius: 50%;
  display: none; place-items: center;
  background: var(--surface-2); color: var(--text-secondary); box-shadow: inset 0 0 0 1px var(--line);
  cursor: pointer;
}
.thread-more svg { width: 16px; height: 16px; }
.thread-more:hover { color: var(--text-primary); }
@media (hover: hover) and (pointer: fine) {
  .thread-swipe:hover .thread-more, .thread-more:focus-visible { display: inline-grid; }
  .thread-swipe:hover .msgr__thread-time { visibility: hidden; }
}
.thread-menu {
  position: fixed; z-index: var(--z-toast);
  min-width: 210px; padding: var(--space-2);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-overlay, 0 12px 32px rgba(0, 0, 0, 0.35));
  font-family: var(--font-ui);
  animation: msg-in 0.14s ease-out;
}
.thread-menu__item {
  width: 100%; display: flex; align-items: center; gap: var(--space-3);
  padding: 9px var(--space-4); border-radius: var(--radius-sm);
  font-size: var(--fs-sm); color: var(--text-primary); text-align: left; cursor: pointer;
}
.thread-menu__item svg { width: 17px; height: 17px; color: var(--text-secondary); }
.thread-menu__item:hover, .thread-menu__item:focus-visible { background: var(--fill-hover); outline: none; }
.thread-menu__item.is-danger, .thread-menu__item.is-danger svg { color: var(--danger); }

.msgr__jump {
  position: absolute; left: 50%; bottom: 78px; transform: translateX(-50%);
  padding: 6px 14px; border-radius: 999px; background: var(--accent); color: var(--accent-contrast);
  font-size: var(--fs-xs); font-weight: var(--fw-semibold); box-shadow: var(--shadow-lg); cursor: pointer; z-index: 2;
}
.msgr__jump.hidden, .msgr .hidden { display: none !important; }

.msgr__composer {
  display: flex; align-items: flex-end; gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  background: var(--surface-1); border-top: 1px solid var(--line);
}
.msgr__composer textarea {
  flex: 1; min-width: 0; resize: none; max-height: 132px;
  padding: 10px 14px; border-radius: 20px;
  background: var(--surface-3); border: 1px solid var(--line); color: var(--text-primary);
  font-family: var(--font-ui); font-size: var(--fs-base); line-height: 1.4;
}
.msgr__composer textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
.msgr__send {
  flex-shrink: 0; width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center; background: var(--accent); color: var(--accent-contrast); cursor: pointer;
  transition: background var(--transition-fast), transform var(--transition-fast);
}
.msgr__send:hover { background: var(--accent-light); }
.msgr__send:active { transform: scale(0.94); }
.msgr__send svg { width: 18px; height: 18px; margin-left: -2px; }

/* New chat picker */
.new-chat-card { max-width: 440px; font-family: var(--font-ui); }
.new-chat-card h2 { margin-bottom: var(--space-5); }
.pick-list { max-height: 360px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; margin-top: var(--space-4); }
.pick-list__loading { display: grid; place-items: center; padding: var(--space-8); }
.pick-list__error { text-align: center; color: var(--danger); font-size: var(--fs-sm); }
.pick-row { display: flex; align-items: center; gap: var(--space-4); width: 100%; padding: var(--space-3) var(--space-4); border-radius: var(--radius-lg); text-align: left; cursor: pointer; }
.pick-row:hover { background: var(--fill-hover); }
.pick-row__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.pick-row__name { font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick-row__sub { font-size: var(--fs-xs); color: var(--text-muted); font-family: var(--font-mono); }
.pick-row__action { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--accent); opacity: 0; transition: opacity var(--transition-fast); }
.pick-row:hover .pick-row__action, .pick-row:focus-visible .pick-row__action { opacity: 1; }

@media (max-width: 768px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  .msgr { grid-template-columns: minmax(0, 1fr); height: auto; border-radius: var(--radius-lg); }
  .msgr__threads { border-right: 0; }
  .msgr[data-view="list"] .msgr__conv { display: none; }
  .msgr[data-view="chat"]:not(.msgr--single) .msgr__threads { display: none; }
  /* The conversation lives in #chat-sheet while open; the in-page shell of
     the student's single conversation is then empty and collapses. */
  .msgr[data-view="chat"]:not(.msgr--single) .msgr__threads { display: block; }
  .msgr.is-portaled.msgr--single { display: none; }
  .msgr__log { padding: var(--space-5) var(--space-4) 14px; }
  .msg__bubble { max-width: 84%; }
  /* 16px stops iOS Safari from zooming the page when the field is focused. */
  .msgr__composer textarea { font-size: 16px; }
  /* No overflow:hidden or fixed body here: a document with nothing to
     scroll makes the iOS home-screen web view shrink by the status-bar
     height (see _lockPage). */
  html.msgr-open { overscroll-behavior: none; }
  /* Whatever the web view does not cover is painted with the page and
     theme colour; while a chat is open that is the composer's colour, so the
     band under a short home-screen web view (see _updateAppHeight) reads as
     part of the composer. */
  html.msgr-open, html.msgr-open body { background: var(--surface-1); }
}

/* Phone chat sheet — pinned to the visual viewport by _syncChatSheet(). */
.chat-sheet {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: calc(var(--z-drawer) - 100);
  will-change: transform;
  display: flex;
  flex-direction: column;
  background: var(--surface-0);
  overscroll-behavior: none;
  touch-action: pan-y;
  /* Mounted under <html>, not <body>, so it inherits nothing from body. */
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  line-height: var(--lh-normal);
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}
.chat-sheet[hidden] { display: none; }
/* Colour-matched extensions above the header and below the composer: if the
   keyboard pans the viewport a frame before the sheet follows, what shows is
   more header / composer, never the page behind. */
.chat-sheet::before,
.chat-sheet::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 100vh;
  background: var(--surface-1);
  pointer-events: none;
}
.chat-sheet::before { bottom: 100%; }
.chat-sheet::after { top: 100%; }
.chat-sheet > .msgr__conv {
  flex: 1;
  min-height: 0;
  opacity: 0;
  transform: translateX(18px);
  transition: opacity 0.2s ease-out, transform 0.24s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.chat-sheet.is-open > .msgr__conv { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .chat-sheet > .msgr__conv { transition: none; transform: none; } }
.chat-sheet .msgr__head {
  position: relative;
  z-index: 3;
  padding-top: calc(var(--space-3) + env(safe-area-inset-top, 0px));
  min-height: calc(60px + env(safe-area-inset-top, 0px));
  flex-shrink: 0;
  will-change: transform;
}
/* Header colour extends upward so a lagging frame never shows a seam. */
.chat-sheet .msgr__head::before { content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 100vh; background: inherit; }
.chat-sheet .msgr__back { display: inline-grid; }
.chat-sheet .msgr__log { flex: 1; min-height: 0; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.chat-sheet .msgr__composer { flex-shrink: 0; padding-top: var(--space-3); padding-bottom: max(var(--space-3), env(safe-area-inset-bottom, 0px)); }
.chat-sheet.kb-open .msgr__composer { padding-bottom: var(--space-3); }
/* In the iOS home-screen app the web view can end above the screen's bottom
   edge by the status-bar height (100dvh < 100lvh); the home indicator then
   sits in the band below, so only the part of the inset still inside the
   sheet is kept. Recomputed by the browser whenever that height changes. */
.chat-sheet:not(.kb-open) .msgr__composer {
  padding-bottom: max(var(--space-3), calc(env(safe-area-inset-bottom, 0px) - (100lvh - 100dvh)));
}
.chat-sheet .msgr__jump { bottom: 84px; }

/* Invisible field at the top of the chat sheet that receives focus first on
   iOS so the keyboard opens without panning the page (see _finishKbHandoff). */
.kb-proxy {
  position: absolute;
  top: calc(env(safe-area-inset-top, 0px) + 8px);
  left: 0;
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  opacity: 0;
  font-size: 16px;
  pointer-events: none;
  caret-color: transparent;
}

/* ── Phone held sideways ─────────────────────────────────
   A short touch screen in landscape gets the phone layout (the phone media
   queries include it; see _PHONE_QUERY in app.js). What is left here is what
   only the sideways phone needs: room to scroll where a portrait screen fits
   everything, a readable measure on a wide-but-short screen, and clearance
   for the camera cutout, which is now at a side edge. */
@media (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  /* Sign-in: one centred column that scrolls; the portrait layout is sized
     to exactly one screen, which a 390px-tall screen cannot hold. */
  #login-screen, .login-container { height: auto; min-height: 100dvh; }
  .login-form-section {
    justify-content: flex-start;
    overflow: visible;
    padding: calc(var(--space-6) + env(safe-area-inset-top, 0px)) var(--gutter-safe) calc(var(--space-8) + env(safe-area-inset-bottom, 0px));
  }
  .login-form-section > * { width: 100%; max-width: 440px; margin-inline: auto; }
  .login-form-brand { margin-bottom: var(--space-4); }
  .login-tabs-wrapper { margin-bottom: var(--space-5); }

  /* Drawer: on a 390px-tall screen the header and footer took nearly all the
     height and squeezed the tab list into a one-row scroller. The whole panel
     scrolls instead, every part at its natural height, and the tabs sit in
     two columns so most of them are visible at once. */
  .drawer .drawer__panel { overflow-y: auto; width: calc(min(560px, 70vw) + env(safe-area-inset-left, 0px)); }
  html:has(#mobile-sidebar.is-open),
  html:has(#mobile-sidebar.is-open) body {
    background: linear-gradient(90deg, var(--surface-2) 0 calc(min(560px, 70vw) + env(safe-area-inset-left, 0px)), var(--surface-0) 0);
  }
  .drawer__header { padding: calc(var(--space-4) + env(safe-area-inset-top, 0px)) var(--space-6) var(--space-4); }
  .drawer__course { margin-top: var(--space-3); padding-top: var(--space-3); }
  .drawer__nav { flex: 0 0 auto; overflow: visible; padding: var(--space-3) var(--space-5); }
  /* !important: the role groups are shown with an inline display by app.js. */
  .drawer__nav .drawer__group:not([style*="none"]) { display: grid !important; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-1) var(--space-3); }
  .drawer__group > .drawer__divider { grid-column: 1 / -1; margin: var(--space-2) var(--space-5); }
  .drawer__group > .sidebar-item--leave { grid-column: 1 / -1; }
  .drawer__section { margin-top: 0; padding-top: var(--space-3); }
  .drawer__footer { padding-block: var(--space-3) calc(var(--space-3) + env(safe-area-inset-bottom, 0px)); }

  /* Chat with the keyboard up: a sideways keyboard leaves ~140px, which the
     header and composer used to fill on their own. The header steps aside
     while typing (it is back as soon as the keyboard closes). */
  .chat-sheet.kb-compact .msgr__head { display: none; }
  .chat-sheet.kb-compact .msgr__composer { padding-top: var(--space-2); padding-bottom: var(--space-2); }
  .chat-sheet.kb-compact .msgr__composer textarea { max-height: 72px; }

  /* Theme / language pill: clear of the cutout and the home indicator. */
  .floating-actions {
    right: max(16px, calc(env(safe-area-inset-right, 0px) + 8px));
    bottom: max(12px, env(safe-area-inset-bottom, 0px));
  }
}

/* The drawer on any screen: the tab list used to be its own scroller squeezed
   between the header and the pinned footer, so on a short screen (a tablet
   turned sideways) the last options sat below its fold and looked missing.
   Now the list takes its natural height and fills any spare room, which keeps
   the footer at the bottom when everything fits; when it does not, the whole
   panel scrolls as one.
   Portrait screens are tall enough for the pinned footer and keep it. */
@media (max-width: 1024px) and (orientation: landscape) {
  .drawer .drawer__panel { overflow-y: auto; -webkit-overflow-scrolling: touch; }
  .drawer .drawer__nav { flex: 1 0 auto; min-height: auto; overflow: visible; }
  /* A sideways tablet gets the sideways phone's arrangement: a wider panel
     with the tabs in two columns, so the whole menu fits its short height. */
  .drawer .drawer__panel { width: calc(min(560px, 70vw) + env(safe-area-inset-left, 0px)); }
  /* !important: the role groups are shown with an inline display by app.js. */
  .drawer__nav .drawer__group:not([style*="none"]) { display: grid !important; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-1) var(--space-3); }
  .drawer__group > .drawer__divider { grid-column: 1 / -1; margin: var(--space-2) var(--space-5); }
  .drawer__group > .sidebar-item--leave { grid-column: 1 / -1; }
  .drawer__section { padding-top: var(--space-3); }
}

/* Side cutouts (landscape phones). env() is 0 everywhere else, so these only
   ever add room where a notch or camera island actually is. */
.drawer__panel {
  padding-left: env(safe-area-inset-left, 0px);
  width: calc(min(320px, 86vw) + env(safe-area-inset-left, 0px));
}
.chat-sheet .msgr__head {
  padding-left: max(var(--space-6), calc(env(safe-area-inset-left, 0px) + var(--space-3)));
  padding-right: max(var(--space-6), calc(env(safe-area-inset-right, 0px) + var(--space-3)));
}
.chat-sheet .msgr__log {
  padding-left: max(var(--space-4), calc(env(safe-area-inset-left, 0px) + var(--space-3)));
  padding-right: max(var(--space-4), calc(env(safe-area-inset-right, 0px) + var(--space-3)));
}
.chat-sheet .msgr__composer {
  padding-left: max(var(--space-5), calc(env(safe-area-inset-left, 0px) + var(--space-3)));
  padding-right: max(var(--space-5), calc(env(safe-area-inset-right, 0px) + var(--space-3)));
}

/* ══ Visual polish (2026-09) ═════════════════════════════════════════════
   Presentation only: no layout, behaviour or element changes. What made the
   interface read as a template is toned down here, in one place:
   - the brand mark is shown cropped and in a light variant on dark themes,
     so it is legible at nav size instead of a 13px smudge;
   - small labels are set in sentence case at normal tracking instead of
     spaced capitals everywhere;
   - decorative colour (rainbow topic pills, a filled role badge, a boxed
     class code, traffic-light numbers) gives way to the navy/gold palette,
     with colour kept where it means something (at risk, errors). */

/* Brand mark: one image per theme. */
.logo-for-light { display: none !important; }
[data-theme="light"] .logo-for-light { display: inline-block !important; }
[data-theme="light"] .logo-for-dark { display: none !important; }
.nav-logo-img { height: 30px; width: auto; }
.login-form-brand__logo { height: 44px; width: auto; }
.hero-logo-img { height: 40px; width: auto; }
.loading-logo { height: 72px; width: auto; }
@media (max-width: 768px), (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  .nav-logo-img { height: 26px; }
  .login-form-brand { margin-bottom: var(--space-6); }
}

/* Top bar: role and class code as quiet text, not stickers. */
.nav-badge {
  background: none;
  border: 1px solid var(--line);
  color: var(--text-secondary);
  text-transform: none;
  letter-spacing: 0;
  font-weight: var(--fw-medium);
  font-size: 12px;
  padding: 1px 8px;
}
.nav-course-code {
  background: none;
  border: none;
  padding: 0;
  color: var(--text-muted);
  font-weight: var(--fw-medium);
}

/* Sentence case for labels. Some strings arrive in capitals ("ÖĞRENCİLER",
   "DİLBİLGİSİ"), so these are lower-cased and the first letter restored;
   the page language is set, so Turkish İ/ı come out right. */
.stat-label,
.topic-type-badge {
  text-transform: lowercase;
  letter-spacing: 0;
}
.stat-label::first-letter,
.topic-type-badge::first-letter { text-transform: uppercase; }
.stat-label { font-size: 13px; font-weight: var(--fw-medium); color: var(--text-secondary); }

.badge,
.risk-badge,
.classroom-status,
.classroom-card__lang,
.cefr-level-badge,
.pedagogy-guide-badge,
.pedagogy-scene-label,
.sheet-title,
.sheet-translation-label,
.hero-footer-sub,
.study-sidebar-header h3 {
  text-transform: none;
  letter-spacing: 0;
}
.badge { font-weight: var(--fw-medium); font-size: 12px; }
.classroom-card__lang { font-size: 13px; font-weight: var(--fw-medium); color: var(--text-secondary); }
.study-sidebar-header h3 { font-size: 13px; font-weight: var(--fw-semibold); color: var(--text-secondary); }
.cefr-level-badge { font-weight: var(--fw-semibold); }
.sheet-title { font-size: 12px; font-weight: var(--fw-semibold); }

/* Topic type: one neutral chip for every type instead of six hues. */
.topic-type-badge,
.topic-type-badge.vocabulary,
.topic-type-badge.grammar,
.topic-type-badge.reading,
.topic-type-badge.communication,
.topic-type-badge.phonetics,
.topic-type-badge.functional,
.topic-type-badge.functional_language,
.topic-type-badge.mixed {
  background: var(--fill-subtle);
  color: var(--text-secondary);
  border: 1px solid var(--line);
  font-weight: var(--fw-medium);
  font-size: 12px;
}

/* Numbers: one colour; red stays for what needs attention. */
.stat-value.success,
.stat-value.warning,
.stat-value.accent { color: var(--text-primary); }

/* Headings: a little less weight and shout. */
.page-header h1,
.page-header h2 { letter-spacing: -0.015em; }

/* A chip with nothing in it (a topic without a difficulty) left a stray
   separator dot after "Unit 1". */
.meta-chip:empty { display: none; }

/* Copyright line: at the foot of the page, centred. <body> is a column at
   least one screen tall, so on a short page this sits at the bottom of the
   screen instead of floating under the last card; on a long page it simply
   follows the content. Centred, it is also clear of the corner theme pill. */
.site-footer {
  margin-top: auto;
  text-align: center;
}

/* Curriculum review of a single-track class: only that language's column. */
#ai-curriculum-list.tracks-tr .topic-title-en,
#ai-curriculum-list.tracks-tr div:has(> .syllabus-title-en),
#ai-curriculum-list.tracks-en .topic-title-tr,
#ai-curriculum-list.tracks-en div:has(> .syllabus-title-tr) { display: none; }
#ai-curriculum-list.tracks-tr [style*="grid-template-columns:1fr 1fr"],
#ai-curriculum-list.tracks-en [style*="grid-template-columns:1fr 1fr"] { grid-template-columns: 1fr !important; }

/* Browsers with a forced "dark mode for web pages" (Samsung Internet among
   them) leave a page alone when it answers prefers-color-scheme itself. The
   site picks its theme from its own setting, so this only declares that it
   handles dark: the scheme it already paints is kept as it is. */
html { color-scheme: dark; }
html[data-theme="light"] { color-scheme: light; }
@media (prefers-color-scheme: dark) {
  html { color-scheme: dark; }
  html[data-theme="light"] { color-scheme: light; }
}

/* A custom theme (appearance.js) paints the lesson's boxes in its own
   surfaces. The light-theme rules above fix them to the default theme's
   white and grey, which showed as off-colour boxes on a tinted theme. */
html[data-appearance][data-theme="light"] :is(.study-card, .pedagogy-rule-item, .pedagogy-rule-item:hover, .pedagogy-rule-card, .pedagogy-contrast-card) {
  background: var(--surface-1);
  border-color: var(--line) !important;
}
html[data-appearance][data-theme="light"] :is(.pedagogy-guide-block, .pedagogy-single-note, .pedagogy-rule-example-box) {
  background: var(--surface-2);
  border-color: var(--line);
}
html[data-appearance][data-theme="light"] .pedagogy-single-note { border-left-color: var(--accent); }
html[data-appearance][data-theme="light"] :is(.pedagogy-rule-content, .pedagogy-single-note) { color: var(--text-primary); }

@media (max-width:768px){
 .screen.active{animation:none!important;transform:none!important;opacity:1!important}
 /* Login uses document scrolling like the other screens. A nested viewport-height
    scroller can leave iOS fixed overlays clipped at the web-view boundary. */
 .study-container{min-height:0!important;height:auto!important}
 .study-container,.study-content-panel,.study-content-area,.study-topic-wrapper,.study-card{min-width:0!important;box-sizing:border-box!important}
 .study-container,.study-content-panel{overflow-x:clip!important}
 .study-content-area,.study-topic-wrapper,.study-card{max-width:100%!important}
 .study-card img,.study-card video,.study-card iframe,.study-card table,.study-card pre{max-width:100%!important}
 .study-meta,.study-meta *,.cefr-level-subtitle,.cefr-level-subtitle *,#s-ai-book-content-area>.study-meta,#ai-book-content-area>.study-meta{min-width:0!important;max-width:100%!important;box-sizing:border-box!important;white-space:normal!important;overflow-wrap:anywhere!important;word-break:break-word!important}
 #s-ai-book-content-area .study-card *,#ai-book-content-area .study-card *{min-width:0!important;max-width:100%!important;box-sizing:border-box!important}
 #s-ai-book-content-area .study-card p,#s-ai-book-content-area .study-card li,#s-ai-book-content-area .study-card span,#s-ai-book-content-area .study-card div,#s-ai-book-content-area .study-card code,#s-ai-book-content-area .study-card pre,#ai-book-content-area .study-card p,#ai-book-content-area .study-card li,#ai-book-content-area .study-card span,#ai-book-content-area .study-card div,#ai-book-content-area .study-card code,#ai-book-content-area .study-card pre,.vocab-row__ipa,.phonetic-badge{overflow-wrap:anywhere!important;word-break:break-word!important}
 .vocab-row__ipa,.phonetic-badge{white-space:normal!important}
 .outline-sheet__panel{width:calc(100vw - 24px)!important;max-width:calc(100vw - 24px)!important;min-width:0!important;overflow-x:hidden!important;overscroll-behavior:contain!important;box-sizing:border-box!important}
 .outline-sheet__panel *,.outline__unit,.outline__unit-title,.outline__topic{min-width:0!important;max-width:100%!important;box-sizing:border-box!important}
 .outline__unit-title,.outline__topic{white-space:normal!important;overflow-wrap:anywhere!important;word-break:break-word!important}
 .outline__topic{font-size:var(--fs-2xs)!important;font-weight:var(--fw-medium)!important;text-transform:none!important;letter-spacing:var(--ls-normal)!important;line-height:1.4!important;color:var(--text-secondary);padding:var(--space-3) var(--space-5)!important}
 .outline__topic.is-current{color:var(--text-primary);font-weight:var(--fw-semibold)!important}
 .outline__unit-title[data-aula-unit-toggle="1"]{width:100%;min-height:44px;padding:8px 10px;margin-bottom:4px;border-radius:var(--radius);cursor:pointer;user-select:none;-webkit-user-select:none}
 .outline__unit-title[data-aula-unit-toggle="1"]::after{content:'›';margin-inline-start:auto;font-size:20px;line-height:1;transform:rotate(90deg);transition:transform .15s ease}
 .outline__unit[data-aula-expanded="1"]>.outline__unit-title::after{transform:rotate(-90deg)}
 .outline__unit:not([data-aula-expanded="1"])>:not(.outline__unit-title){display:none!important}
}
