/* Grammar AI Tutor — dark-glass redesign.
   Ported from claude.ai/design handoff. Geist + oklch + single accent + soft mesh glow.
*/

:root, html[data-theme="dark"] {
  --bg: oklch(15% 0.015 270);
  --bg-2: oklch(18% 0.018 275);
  --panel: oklch(20% 0.018 275 / 0.6);
  --panel-solid: oklch(22% 0.018 275);
  --hairline: oklch(100% 0 0 / 0.08);
  --hairline-strong: oklch(100% 0 0 / 0.14);
  --text: oklch(96% 0.005 270);
  --text-dim: oklch(72% 0.01 270);
  --text-muted: oklch(55% 0.01 270);
  --accent: oklch(72% 0.18 295);
  --accent-bright: oklch(78% 0.18 295);    /* gradient top stop */
  --accent-deep: oklch(56% 0.20 310);      /* darker shade for SVG / hover */
  --accent-soft: oklch(72% 0.18 295 / 0.16);
  --accent-glow: oklch(72% 0.18 295 / 0.35);
  --accent-on: oklch(15% 0.02 295);        /* text/icon on accent background */
  --ok: oklch(78% 0.16 155);
  --warn: oklch(80% 0.14 80);
  --err: oklch(72% 0.18 25);
  --tint-soft: oklch(100% 0 0 / 0.06);     /* generic hover wash on dark */
  --tint-strong: oklch(100% 0 0 / 0.22);
}

html[data-theme="light"] {
  --bg: oklch(98% 0.005 270);
  --bg-2: oklch(96% 0.008 275);
  --panel: oklch(100% 0 0 / 0.7);
  --panel-solid: oklch(100% 0 0);
  --hairline: oklch(0% 0 0 / 0.08);
  --hairline-strong: oklch(0% 0 0 / 0.14);
  --text: oklch(20% 0.01 270);
  --text-dim: oklch(40% 0.01 270);
  --text-muted: oklch(55% 0.01 270);
  --accent: oklch(58% 0.20 295);
  --accent-bright: oklch(64% 0.20 295);
  --accent-deep: oklch(45% 0.22 310);
  --accent-soft: oklch(58% 0.20 295 / 0.14);
  --accent-glow: oklch(58% 0.20 295 / 0.25);
  --accent-on: oklch(100% 0 0);
  --tint-soft: oklch(0% 0 0 / 0.04);
  --tint-strong: oklch(0% 0 0 / 0.18);
}

/* Theme-invariant tokens */
:root {
  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 20px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 0 oklch(100% 0 0 / 0.04) inset, 0 1px 2px oklch(0% 0 0 / 0.4);
  --shadow-md: 0 1px 0 oklch(100% 0 0 / 0.05) inset, 0 8px 32px oklch(0% 0 0 / 0.4);
  --shadow-glow: 0 0 0 1px var(--accent), 0 0 24px -2px var(--accent-glow);

  --header-h: 64px;
  --density: 1;

  --font-sans: 'Geist', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;
}

html[data-theme="light"] {
  --shadow-sm: 0 1px 0 oklch(100% 0 0 / 0.6) inset, 0 1px 2px oklch(0% 0 0 / 0.06);
  --shadow-md: 0 1px 0 oklch(100% 0 0 / 0.6) inset, 0 8px 32px oklch(0% 0 0 / 0.08);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html {
  font-family: var(--font-sans);
  font-size: 15px;
  color: var(--text);
  background: var(--bg);
  -webkit-text-size-adjust: 100%;
  font-feature-settings: 'ss01', 'cv11';
}
body {
  min-height: 100vh;
  min-height: 100dvh;
  line-height: 1.5;
  background:
    radial-gradient(900px 600px at 88% -10%, var(--accent-soft), transparent 60%),
    radial-gradient(700px 500px at -5% 110%, var(--accent-soft), transparent 55%),
    var(--bg);
  background-attachment: fixed;
  overflow-x: hidden; /* iOS Safari: composer focus can push layout 1-2px wider */
}

::selection { background: var(--accent-soft); color: var(--text); }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
code, .mono { font-family: var(--font-mono); font-feature-settings: 'ss01';
  background: oklch(100% 0 0 / 0.07); padding: 1px 6px; border-radius: 5px;
  font-size: 0.9em; color: var(--text); }
button { font: inherit; }

/* ---------- App shell ---------- */
.header {
  /* Fixed (not sticky) so iOS Safari can't scroll us out of view when the
     soft keyboard opens — the learner can always reach the user menu to
     log out or jump to Progress/Lessons. */
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  height: var(--header-h);
  display: flex; align-items: center;
  padding: 0 24px; gap: 20px;
  background: color-mix(in oklch, var(--bg) 70%, transparent);
  backdrop-filter: saturate(160%) blur(20px);
  -webkit-backdrop-filter: saturate(160%) blur(20px);
  border-bottom: 1px solid var(--hairline);
}
/* Reserve room for the fixed header on every authenticated page. Landing
   has no header so it stays at body top. */
body.with-header { padding-top: var(--header-h); }
.brand {
  display: inline-flex; align-items: center; gap: 10px;
  color: var(--text); text-decoration: none;
  font-weight: 600; letter-spacing: -0.01em;
}
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 32px; height: 32px;
  border-radius: 9px; display: block;
  filter: drop-shadow(0 0 14px var(--accent-glow));
}
.brand-mark .bg-fill { fill: var(--accent); }
.brand-mark .ink { fill: oklch(100% 0 0); }
.brand-mark .cursor { fill: oklch(100% 0 0); animation: cursorBlink 1.8s ease-in-out infinite; }
.brand-mark .hairline { stroke: oklch(100% 0 0 / 0.15); stroke-width: 1; fill: none; }
.brand-name { font-size: 0.95rem; }
.brand-name em { color: var(--text-muted); font-style: normal; font-weight: 400; }
@keyframes cursorBlink {
  0%, 45% { opacity: 1; }
  50%, 95% { opacity: 0.25; }
  100% { opacity: 1; }
}

.nav {
  display: flex; gap: 2px;
  flex: 1;
  padding: 3px;
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-pill);
  max-width: 360px;
}
.nav a {
  flex: 1; padding: 7px 14px;
  text-align: center;
  color: var(--text-dim);
  font-size: 0.85rem; font-weight: 500;
  border-radius: var(--radius-pill);
  text-decoration: none; transition: color 0.15s, background 0.15s;
}
.nav a:hover { color: var(--text); text-decoration: none; }
.nav a.active {
  color: var(--text);
  background: linear-gradient(180deg, oklch(100% 0 0 / 0.08), oklch(100% 0 0 / 0.03));
  box-shadow: 0 1px 0 oklch(100% 0 0 / 0.08) inset, 0 1px 2px oklch(0% 0 0 / 0.3);
}

/* margin-left:auto pushes the user menu all the way to the right edge of
   the sticky header even though .nav is capped at 360px. Without this the
   flex container piles everything on the left and leaves empty space after. */
.header-right { display: flex; align-items: center; gap: 12px;
  margin-left: auto; position: relative; }

/* User menu (details/summary) */
.user-menu { position: relative; }
.user-menu > summary {
  list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 3px 10px 3px 3px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline);
  background: var(--panel);
  color: var(--text);
  transition: background 0.15s, border-color 0.15s;
}
.user-menu > summary::-webkit-details-marker { display: none; }
.user-menu > summary::marker { display: none; }
.user-menu > summary:hover { background: oklch(100% 0 0 / 0.05); border-color: var(--hairline-strong); }
.user-menu .avatar {
  width: 26px; height: 26px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), var(--accent-deep));
  color: var(--accent-on);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.74rem; font-weight: 600; flex-shrink: 0;
}
.user-menu .name {
  font-size: 0.85rem; font-weight: 500; max-width: 110px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.user-menu .chev { color: var(--text-muted); transition: transform 0.2s; }
.user-menu[open] .chev { transform: rotate(180deg); }
.user-menu-pane {
  position: absolute; right: 0; top: calc(100% + 8px);
  min-width: 240px; padding: 6px;
  background: var(--panel-solid);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md), 0 0 0 1px oklch(0% 0 0 / 0.4);
  z-index: 60;
  animation: menuIn 0.15s ease-out;
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
}
@keyframes menuIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

.user-menu-id {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--hairline);
  margin-bottom: 4px;
}
.user-menu-id .av-lg {
  width: 36px; height: 36px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), var(--accent-deep));
  color: var(--accent-on);
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: 0.92rem; flex-shrink: 0;
}
.user-menu-id .who { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.user-menu-id .who strong {
  font-size: 0.88rem; font-weight: 600; letter-spacing: -0.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.user-menu-id .who small { font-size: 0.74rem; color: var(--text-muted); }
.user-menu-item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: 8px;
  font-size: 0.88rem; color: var(--text);
  text-decoration: none; cursor: pointer;
  border: none; background: transparent; width: 100%; text-align: left;
  font-family: inherit; transition: background 0.1s;
}
.user-menu-item:hover { background: oklch(100% 0 0 / 0.06); text-decoration: none; }
.user-menu-item.danger { color: var(--err); }
.user-menu-item.danger:hover { background: color-mix(in oklch, var(--err), transparent 88%); }
.user-menu-item svg { color: var(--text-muted); flex-shrink: 0; }
.user-menu-item.danger svg { color: var(--err); }
.user-menu-sep { height: 1px; background: var(--hairline); margin: 4px 6px; }

/* ---------- Generic ---------- */
.main {
  width: 100%; max-width: 1100px; margin: 0 auto;
  padding: calc(32px * var(--density)) 24px calc(80px * var(--density));
}
.eyebrow {
  text-transform: uppercase; letter-spacing: 0.12em;
  font-size: 0.72rem; color: var(--text-muted); font-weight: 500;
}
.h1 {
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  letter-spacing: -0.02em; font-weight: 600;
  margin: 6px 0 6px; line-height: 1.1;
}
.h1 .accented { color: var(--accent); }
.subtitle { color: var(--text-dim); margin: 0; max-width: 56ch; }
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 28px; }
.page-head .right { display: flex; gap: 10px; align-items: center; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 9px 16px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline-strong);
  background: var(--panel);
  color: var(--text);
  font-size: 0.88rem; font-weight: 500;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.05s, box-shadow 0.2s;
  text-decoration: none; white-space: nowrap;
  font-family: inherit;
  /* Suppress iOS Safari's gray tap-highlight overlay — it greyed the primary
     button down to black-on-dark for a moment after tap. We provide explicit
     :active/focus visuals instead. */
  -webkit-tap-highlight-color: transparent;
}
.btn:hover { background: oklch(100% 0 0 / 0.06); border-color: oklch(100% 0 0 / 0.22); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn:disabled, .btn[disabled] { opacity: 0.45; cursor: not-allowed; }
.btn-primary,
.btn-primary:hover,
.btn-primary:active,
.btn-primary:focus,
.btn-primary:focus-visible {
  background: linear-gradient(180deg, var(--accent-bright), var(--accent));
  border-color: var(--accent-bright);
  color: var(--accent-on);
  box-shadow: 0 1px 0 oklch(100% 0 0 / 0.25) inset, 0 8px 24px -4px var(--accent-glow);
  font-weight: 600;
}
.btn-primary:hover { filter: brightness(1.06); }
.btn-primary:focus-visible { outline: 2px solid var(--accent-bright); outline-offset: 2px; }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-dim); }
.btn-ghost:hover { background: oklch(100% 0 0 / 0.05); color: var(--text); }
.btn-danger { color: var(--err); border-color: color-mix(in oklch, var(--err), transparent 60%); }
.btn-danger:hover { background: color-mix(in oklch, var(--err), transparent 88%); border-color: var(--err); }

/* ---------- Chips ---------- */
.chips { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline);
  background: var(--panel);
  color: var(--text-dim);
  font-size: 0.78rem; font-weight: 500;
  cursor: pointer; transition: color 0.15s, border-color 0.15s, background 0.15s;
  text-decoration: none; font-family: inherit;
}
.chip:hover { color: var(--text); border-color: var(--hairline-strong); text-decoration: none; }
.chip.active {
  color: var(--text);
  background: var(--accent-soft);
  border-color: color-mix(in oklch, var(--accent), transparent 60%);
}
.chip .count { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.chip.active .count { color: var(--accent-bright); }

/* Search field (lesson picker header) */
.search-box {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px; min-width: 240px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline);
  background: var(--panel);
  color: var(--text-muted);
  transition: border-color 0.15s, box-shadow 0.2s;
}
.search-box:focus-within {
  border-color: color-mix(in oklch, var(--accent), transparent 50%);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent), transparent 85%);
  color: var(--text);
}
.search-box input {
  border: none; background: transparent; color: var(--text);
  font: inherit; font-size: 0.88rem; outline: none;
  flex: 1; min-width: 0; padding: 0;
}
.search-box input::placeholder { color: var(--text-muted); }

/* Section filter — combobox-style: shows current selection by default,
   expands to overlay with the full chip cloud on click. The overlay spans
   the full content width so the chip cloud is WIDE rather than a long list. */
.filter-row {
  display: flex; align-items: center; gap: 10px;
  margin: 16px 0 0;
  flex-wrap: wrap;
  /* Anchor for the absolute-positioned .filter-pane so it spans the full
     width of the picker (the surrounding card pane) instead of being clipped
     to the .filter-dd pill — Russian chip labels otherwise overflow into a
     1-line scroll-list. */
  position: relative;
}
.filter-row .filter-dd { margin: 0; }
/* Search box, when it lives in the filter row, fills the remaining width to
   the right of the filter + dice pills (down to a 240px floor). */
.filter-row .search-box {
  flex: 1 1 240px;
  min-width: 200px;
  padding: 7px 14px;
}

.dice-btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 16px 8px 12px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline);
  background: var(--panel);
  color: var(--text-dim);
  font: inherit;
  font-size: 0.82rem; font-weight: 500;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s, color 0.15s, transform 0.08s;
  user-select: none;
}
.dice-btn:hover {
  border-color: var(--hairline-strong);
  background: var(--tint-soft);
  color: var(--text);
}
.dice-btn:active { transform: scale(0.96); }
.dice-btn svg { color: var(--accent); flex-shrink: 0; }

/* Position handled by .filter-row above so the pane can span the full pane.
   Margin reset because .filter-row already provides spacing. */
.filter-dd { margin: 16px 0 0; display: block; }
.filter-row .filter-dd { margin: 0; }
.filter-dd > summary {
  list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px 8px 12px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline);
  background: var(--panel);
  color: var(--text-dim);
  font-size: 0.82rem; font-weight: 500;
  transition: border-color 0.15s, background 0.15s;
}
.filter-dd > summary::-webkit-details-marker,
.filter-dd > summary::marker { display: none; }
.filter-dd > summary:hover { border-color: var(--hairline-strong); background: var(--tint-soft); }
.filter-dd > summary .filter-label {
  text-transform: uppercase; letter-spacing: 0.08em;
  font-size: 0.66rem; color: var(--text-muted);
}
.filter-dd > summary .chip { pointer-events: none; padding: 3px 10px; }
.filter-dd > summary .chev { color: var(--text-muted); transition: transform 0.2s; }
.filter-dd[open] > summary .chev { transform: rotate(180deg); }

.filter-pane {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 30;
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 12px;
  background: var(--panel-solid);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md), 0 0 0 1px oklch(0% 0 0 / 0.4);
  animation: menuIn 0.15s ease-out;
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
}

/* ---------- Lesson sections (category blocks) ---------- */
.lesson-section { margin-top: 24px; }
.lesson-section:first-of-type { margin-top: 20px; }
.lesson-section .section-title {
  display: flex; align-items: baseline; gap: 10px;
  margin: 0 0 10px;
  padding-bottom: 6px;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--hairline);
}
.lesson-section .section-title .count {
  font-size: 0.7rem;
  color: var(--accent-bright);
  font-weight: 500;
}
.lesson-section .lesson-grid { margin-top: 0; }

/* ---------- Lesson cards ---------- */
.lesson-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 10px;
  margin-top: 16px;
}
.lesson-card {
  position: relative;
  padding: 12px 14px 10px;
  border-radius: var(--radius);
  background: var(--panel);
  border: 1px solid var(--hairline);
  cursor: pointer;
  transition: border-color 0.2s, transform 0.15s, box-shadow 0.2s;
  display: flex; flex-direction: column; gap: 8px;
  text-align: left; font: inherit; color: var(--text);
}
.lesson-card::before {
  content: ''; position: absolute; inset: -1px;
  border-radius: inherit; padding: 1px;
  background: linear-gradient(135deg, oklch(100% 0 0 / 0.06), transparent 40%);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  -webkit-mask-composite: xor;
  pointer-events: none;
}
.lesson-card:hover { border-color: var(--hairline-strong); transform: translateY(-1px); }
.lesson-card.selected {
  border-color: color-mix(in oklch, var(--accent), transparent 45%);
  box-shadow: var(--shadow-glow), var(--shadow-md);
  background: color-mix(in oklch, var(--accent), transparent 92%);
}
.lesson-card.disabled { opacity: 0.45; pointer-events: none; }
/* Lesson-id is now an inline prefix on the title line — no more top row. */
.lesson-id {
  display: inline;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--text-muted);
  font-weight: 500;
  letter-spacing: 0.02em;
  margin-right: 6px;
  background: none; padding: 0;
}
/* Checkmark floats in the top-right of the card so it doesn't consume a row. */
.lesson-check {
  position: absolute; top: 10px; right: 10px;
  width: 22px; height: 22px; border-radius: 7px;
  border: 1.5px solid var(--hairline-strong);
  display: flex; align-items: center; justify-content: center;
  transition: background 0.15s, border-color 0.15s;
  background: transparent;
  color: var(--accent-on);
}
.lesson-card.selected .lesson-check {
  background: var(--accent); border-color: var(--accent);
}
.lesson-check svg { opacity: 0; transition: opacity 0.15s; }
.lesson-card.selected .lesson-check svg { opacity: 1; }
/* "Урок" icon sits in the stats row alongside Attempts/Accuracy/Streak.
   It's a labeled affordance, not a tiny corner button, so the destination
   is unambiguous even at a glance. */
/* "Урок" is an action cell, not a stat. With the parent grid using
   ``auto`` widths, the cell hugs its content (icon + "Урок" label) — no
   centering tricks needed since there's no empty space inside the cell
   to center against. */
.lstat.lesson-open {
  text-decoration: none;
  color: var(--text-muted);
  transition: color 0.15s;
  cursor: pointer;
}
.lstat.lesson-open:hover { color: var(--accent); }
.lstat.lesson-open:focus-visible { outline: 2px solid var(--accent-bright); outline-offset: 2px; border-radius: 4px; }
/* Icon lives inside .v so it shares the same text-baseline + line-height as
   the numeric values on the other cells — that way "Урок" sits at the exact
   same y as "Попыток"/"Серия"/"Точность" regardless of icon dimensions. */
.lesson-open-icon {
  height: 0.88rem;       /* matches .v font-size */
  width: auto;
  display: inline-block;
  vertical-align: middle;
  filter: brightness(0.85) saturate(0.85);
  opacity: 0.85;
  transition: opacity 0.15s, filter 0.15s;
}
.lstat.lesson-open:hover .lesson-open-icon { opacity: 1; filter: brightness(1) saturate(1); }

/* Reserve right-side space so the absolute-positioned checkmark never overlaps
   long titles. */
.lesson-title {
  font-size: 0.94rem; font-weight: 600; letter-spacing: -0.01em; line-height: 1.3;
  /* Reserve space on the first line for the absolute-positioned checkmark
     plus the CEFR level pill that sits just to its left. */
  padding-right: 84px;
}

.lesson-stats {
  display: grid;
  /* Урок · Попыток · Серия each hug their content; Точность takes whatever
     space is left so the accuracy bar can stretch out. ``gap`` is what gives
     the eye the consistent horizontal rhythm between the labels — fixed-width
     columns would just leave dead space inside the cells. */
  grid-template-columns: auto auto auto 1fr;
  gap: 18px;
  margin-top: auto;
  padding-top: 8px;
  border-top: 1px solid var(--hairline);
  align-items: start;
}
.lstat { display: flex; flex-direction: column; gap: 1px; }
.lstat .v {
  font-size: 0.88rem; font-weight: 600;
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
  line-height: 1.1;
}
.lstat .l { font-size: 0.62rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.06em; }
.lstat.empty .v { color: var(--text-muted); font-weight: 400; }

.accuracy-bar {
  height: 4px; border-radius: 2px;
  background: oklch(100% 0 0 / 0.07);
  overflow: hidden; margin-top: 4px;
}
.accuracy-bar > i {
  display: block; height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-bright));
  border-radius: inherit;
}

/* Sticky action bar */
.action-bar {
  position: sticky; bottom: 24px;
  margin: 32px auto 0; max-width: 640px;
  padding: 12px 12px 12px 22px;
  border-radius: var(--radius-pill);
  background: color-mix(in oklch, var(--bg-2), transparent 12%);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid var(--hairline-strong);
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  box-shadow: var(--shadow-md); z-index: 20;
  transition: opacity 0.25s, transform 0.25s;
}
.action-bar.hidden { opacity: 0; transform: translateY(20px); pointer-events: none; }
.action-bar .count { display: flex; align-items: center; gap: 10px; font-size: 0.88rem; color: var(--text-dim); }
.action-bar .pips { display: inline-flex; gap: 4px; }
.action-bar .pips i { width: 7px; height: 7px; border-radius: 50%; background: oklch(100% 0 0 / 0.12); }
.action-bar .pips i.on { background: var(--accent); box-shadow: 0 0 8px var(--accent-glow); }

/* ---------- Trainer ---------- */
.trainer {
  display: grid;
  grid-template-rows: auto 1fr auto;
  /* Three viewport units, increasing specificity:
     - 100vh: classic fallback for old browsers.
     - 100dvh: dynamic viewport, excludes iOS Safari's URL bar.
     - --viewport-h: written by JS from visualViewport.height when present,
       so when the soft keyboard opens we shrink to exactly the visible area
       (dvh isn't enough on every iOS build). */
  height: calc(100vh - var(--header-h) - 24px);
  height: calc(100dvh - var(--header-h) - 24px);
  height: calc(var(--viewport-h, 100dvh) - var(--header-h) - 24px);
  max-width: 1040px; margin: 12px auto;
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  overflow: hidden;
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
}

.trainer-head {
  padding: 18px 22px;
  border-bottom: 1px solid var(--hairline);
  display: flex; justify-content: space-between; align-items: center; gap: 16px;
  background: linear-gradient(180deg, oklch(100% 0 0 / 0.025), transparent);
}
.trainer-head .lesson-name { font-size: 1rem; font-weight: 600; letter-spacing: -0.01em; }
.trainer-head .lesson-meta { font-size: 0.78rem; color: var(--text-muted); margin-top: 2px; }
.trainer-head .lesson-meta .lang-pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: var(--radius-pill);
  background: oklch(100% 0 0 / 0.05);
  border: 1px solid var(--hairline);
  font-family: var(--font-mono); font-size: 0.7rem;
  margin-right: 6px; color: var(--text-dim);
}
.trainer-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
/* On narrow phones the two voice toggles + Завершить consume too much of
   the row. Stack the toggles vertically (the column also right-aligns to
   keep the visual anchor near "Завершить"). */
@media (max-width: 520px) {
  .trainer-actions { flex-direction: column; align-items: stretch; gap: 6px; }
  .trainer-actions .voice-toggle { justify-content: flex-start; padding: 6px 10px 6px 8px; }
}

.voice-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 12px 7px 8px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline);
  background: var(--panel);
  color: var(--text-dim);
  font-size: 0.82rem; cursor: pointer;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
  font-family: inherit;
}
.voice-toggle:hover { color: var(--text); }
.voice-toggle.on {
  color: var(--text);
  background: var(--accent-soft);
  border-color: color-mix(in oklch, var(--accent), transparent 60%);
}
.voice-toggle .dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--text-muted);
  transition: background 0.2s, box-shadow 0.2s;
}
.voice-toggle.on .dot {
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent), transparent 80%), 0 0 10px var(--accent-glow);
}

/* The Авто toggle reuses .voice-toggle styling but pulses its dot when on,
   so the user has a clear cue the hands-free loop is armed. */
.auto-toggle.on .dot {
  animation: auto-pulse 1.4s ease-in-out infinite;
}
@keyframes auto-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.35); }
}

.chatlog {
  overflow-y: auto; overflow-anchor: none;
  padding: 22px 22px 12px;
  display: flex; flex-direction: column; gap: 14px;
  min-height: 0;
}
/* Telegram-style bottom-anchored layout. A pseudo-element with
   ``margin-top: auto`` eats all the free space above the first message,
   so a single-message chat sits at the bottom right above the composer.
   When the log overflows the auto-margin collapses and messages stack
   normally — overflowing content stays reachable by scrolling (unlike
   the naive ``justify-content: flex-end``, which clips the top in some
   browsers). */
.chatlog::before { content: ''; margin-top: auto; }
.chatlog::-webkit-scrollbar { width: 10px; }
.chatlog::-webkit-scrollbar-thumb { background: var(--hairline-strong); border-radius: 5px; }
.chatlog::-webkit-scrollbar-track { background: transparent; }

.msg {
  display: flex; gap: 10px;
  max-width: 78%;
  animation: msgIn 0.25s ease-out;
}
@keyframes msgIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.msg-assistant { align-self: flex-start; }
.msg-user { align-self: flex-end; flex-direction: row-reverse; }
.msg .av {
  width: 28px; height: 28px; border-radius: 50%;
  flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.7rem; font-weight: 600;
}
.msg-assistant .av {
  background: linear-gradient(135deg, var(--accent), var(--accent-deep));
  color: var(--accent-on);
  box-shadow: 0 0 16px -4px var(--accent-glow);
}
.msg-user .av {
  background: oklch(100% 0 0 / 0.06);
  border: 1px solid var(--hairline);
  color: var(--text);
}

.bubble {
  padding: 11px 14px; border-radius: 16px;
  font-size: 0.94rem; line-height: 1.5;
  border: 1px solid var(--hairline);
  background: oklch(100% 0 0 / 0.04);
  word-wrap: break-word; overflow-wrap: anywhere;
}
.msg-assistant .bubble { border-top-left-radius: 4px; }
.msg-user .bubble {
  background: linear-gradient(180deg, var(--accent), var(--accent-deep));
  color: var(--accent-on);
  border-color: var(--accent-bright);
  border-top-right-radius: 4px;
  font-weight: 500;
}
.bubble .src-line {
  display: flex; align-items: center; gap: 6px;
  color: var(--text-muted); font-size: 0.78rem; margin-bottom: 4px;
}
.bubble .src-line .lang { font-family: var(--font-mono); }
.bubble .src-sentence {
  font-size: 1.02rem; font-weight: 500; letter-spacing: -0.005em; color: var(--text);
}
.bubble .prompt { margin-top: 6px; color: var(--text-dim); font-size: 0.88rem; }

/* "Show hint" disclosure inside an assistant bubble — collapsed by default so
   the grammar tag doesn't give the answer away unless the learner asks. */
.prompt-hint { margin-top: 8px; }
.prompt-hint > summary {
  list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border-radius: var(--radius-pill);
  background: var(--tint-soft);
  border: 1px solid var(--hairline);
  color: var(--text-muted);
  font-size: 0.74rem; font-weight: 500;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.prompt-hint > summary::-webkit-details-marker,
.prompt-hint > summary::marker { display: none; }
.prompt-hint > summary::before { content: "💡"; font-size: 0.85em; }
.prompt-hint > summary:hover { color: var(--text); border-color: var(--hairline-strong); }
.prompt-hint[open] > summary { background: var(--accent-soft); color: var(--accent); border-color: color-mix(in oklch, var(--accent), transparent 60%); }
.prompt-hint .prompt {
  margin: 8px 0 0; padding: 8px 12px;
  background: var(--tint-soft);
  border-left: 2px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-style: italic;
}
/* Vocab hints (SCR-197) — above-level English words paired with their
   learner-language translations. Rendered inside the same .prompt-hint
   disclosure as target_grammar so the learner sees grammar + vocab in one
   tap. */
.prompt-hint .vocab-hints {
  margin: 8px 0 0; padding: 8px 12px;
  list-style: none;
  background: var(--tint-soft);
  border-left: 2px dashed var(--hairline-strong);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size: 0.95em;
}
.prompt-hint .vocab-hints li { margin: 2px 0; }
.prompt-hint .vocab-hints code {
  background: transparent; padding: 0 2px;
  font-weight: 600; color: var(--text);
}

.eval-row {
  display: flex; align-items: center; gap: 8px;
  font-size: 0.82rem; margin-bottom: 4px; font-weight: 600;
}
.eval-row.correct { color: var(--ok); }
.eval-row.partial { color: var(--warn); }
.eval-row.incorrect { color: var(--err); }
.eval-row .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
.bubble .alt { color: var(--text-muted); font-size: 0.85rem; margin-top: 4px; }
.bubble .alt code, .bubble .src-sentence code, .bubble code {
  font-family: var(--font-mono);
  background: oklch(100% 0 0 / 0.07);
  padding: 1px 6px; border-radius: 5px;
  font-size: 0.85em; color: var(--text);
}
/* Fill-blank pill: replaces the ``___`` marker in a sentence so the slot is
   visually obvious without leaking what the answer should look like. */
.fb-blank {
  display: inline-block;
  min-width: 3.5em;
  padding: 0 8px;
  margin: 0 2px;
  border-bottom: 2px solid var(--accent);
  background: var(--accent-soft, rgba(167, 139, 250, 0.12));
  border-radius: 4px 4px 0 0;
  color: transparent;
  font-family: var(--font-mono);
  letter-spacing: 0.05em;
  user-select: none;
}

/* Always-visible disambiguation instruction for fill-blank prompts
   ("сделай отрицание") — part of the task, NOT inside the hint toggle. */
.fb-task-note {
  margin-top: 6px;
  font-size: 0.85rem;
  color: var(--accent);
  font-weight: 500;
}
.fb-task-note::before {
  content: "→ ";
  opacity: 0.7;
}

/* CRD-2: trial-plan explainer on the lesson picker */
.trial-banner {
  margin: 0 0 18px;
  padding: 12px 16px;
  border: 1px solid var(--accent);
  border-radius: 10px;
  font-size: 0.9rem;
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.trial-banner strong { color: var(--accent); }

.typing { display: inline-flex; gap: 4px; padding: 12px 14px; }
.typing i {
  width: 6px; height: 6px; border-radius: 50%; background: var(--text-muted);
  animation: typingDot 1.1s infinite;
}
.typing i:nth-child(2) { animation-delay: 0.15s; }
.typing i:nth-child(3) { animation-delay: 0.3s; }
@keyframes typingDot {
  0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}
.typing-indicator { display: none; }
.typing-indicator.htmx-request { display: inline-flex; }
.typing-msg.htmx-request { display: flex !important; }
/* User-side "transcribing" bubble shown while the recorded audio is being
   uploaded + run through STT + cleanup. Same dot animation as the assistant
   typing indicator, plus a small label so the user knows what's happening. */
.stt-processing-msg .bubble.typing { align-items: center; }
.stt-processing-msg .stt-label {
  margin-left: 6px; font-size: 0.85rem; color: var(--text-muted);
}

.composer {
  border-top: 1px solid var(--hairline);
  padding: 14px 16px 16px;
  display: flex; gap: 10px; align-items: flex-end;
  background: linear-gradient(180deg, transparent, oklch(0% 0 0 / 0.05));
}
.composer-input {
  flex: 1; min-width: 0;   /* allow shrink inside flex composer */
  display: flex; align-items: flex-end;
  background: var(--panel-solid);
  border: 1px solid var(--hairline-strong);
  border-radius: 18px;
  padding: 4px 4px 4px 14px;
  transition: border-color 0.15s, box-shadow 0.2s;
}
.composer-input:focus-within {
  border-color: color-mix(in oklch, var(--accent), transparent 50%);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent), transparent 85%);
}
.composer-input textarea {
  flex: 1; border: none; background: transparent;
  color: var(--text); font: inherit; font-family: inherit;
  /* iOS Safari triggers a zoom-on-focus when the input's computed font-size
     is below 16px — which then "widens" the layout and clips the right edge.
     Pin at exactly 16px to keep the keyboard appearance compact without
     triggering zoom. */
  font-size: 16px;
  resize: none;
  padding: 10px 4px;
  max-height: 140px; min-height: 24px;
  outline: none; line-height: 1.5;
  overflow-y: auto;
  scrollbar-width: none; /* Firefox */
  width: 100%; min-width: 0; /* let flex shrink it below intrinsic */
}
.composer-input textarea::-webkit-scrollbar { display: none; width: 0; height: 0; }
.composer-input textarea::placeholder { color: var(--text-muted); }

.btn-mic, .btn-send {
  padding: 0; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  border: 1px solid var(--hairline);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer; font-family: inherit;
  transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.05s;
  /* Long-press on iOS otherwise highlights the SVG and shows the callout
     menu; suppress all selection feedback on the round buttons. */
  user-select: none; -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
/* Mic button is sized to match the single-line composer pill height exactly
   (textarea 44px line + 8px wrapper padding = 52px) so the mic's top and
   bottom edges both line up with the pill at default state. With multi-line
   the pill grows and `align-items: flex-end` on .composer keeps the mic
   anchored to the bottom of the pill. */
.btn-mic { width: 52px; height: 52px; }
/* Send button is a smaller circle inside the pill. The 4px margin-bottom
   compensates for the textarea's bottom padding (10px text-pad - 4px wrapper
   pad - 18px half-button = ...): nudges the button up so its centre matches
   the LAST LINE's centre rather than the pill's bottom-edge. */
.btn-send { width: 36px; height: 36px; margin-bottom: 4px; }
.btn-mic *, .btn-send * {
  pointer-events: none;   /* clicks always hit the button, never the SVG */
  user-select: none; -webkit-user-select: none;
}
.btn-mic:hover { background: oklch(100% 0 0 / 0.05); color: var(--text); }
.btn-mic.recording {
  background: color-mix(in oklch, var(--err), transparent 80%);
  border-color: var(--err);
  color: var(--err);
  animation: pulseMic 1.2s infinite;
}
@keyframes pulseMic {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklch, var(--err), transparent 65%); }
  50% { box-shadow: 0 0 0 10px color-mix(in oklch, var(--err), transparent 100%); }
}
.btn-send {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-on);
  box-shadow: 0 0 12px -2px var(--accent-glow);
}
.btn-send:disabled {
  background: oklch(100% 0 0 / 0.06);
  border-color: var(--hairline);
  color: var(--text-muted);
  box-shadow: none;
}
.btn-send:hover:not(:disabled) { filter: brightness(1.05); }

/* "Listening…" indicator that sits between the chatlog and the composer
   while the mic is hot. Pulsing accent dot reuses the recording animation
   pattern from .btn-mic.recording so the two visuals stay consistent. */
.mic-status {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 14px;
  margin: 0 16px;
  align-self: center;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  border: 1px solid color-mix(in oklch, var(--accent), transparent 60%);
  color: var(--accent);
  font-size: 0.82rem;
  font-weight: 500;
}
.mic-status[hidden] { display: none; }
.mic-status .mic-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 0 var(--accent-glow);
  animation: micPulse 1.1s ease-out infinite;
}
@keyframes micPulse {
  0% { box-shadow: 0 0 0 0 var(--accent-glow); }
  100% { box-shadow: 0 0 0 8px transparent; }
}
/* Visual centering: the paper-plane SVG path's visible mass leans right,
   so geometric centering looks off-axis. Nudge the icon ~1.5px left. */
.btn-send svg { transform: translateX(-1.5px); }

/* ---------- Progress ---------- */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px; margin-bottom: 28px;
}
.stat-card {
  position: relative;
  padding: 20px; border-radius: var(--radius);
  background: var(--panel);
  border: 1px solid var(--hairline);
  overflow: hidden;
}
.stat-card .label {
  text-transform: uppercase; letter-spacing: 0.08em;
  font-size: 0.7rem; color: var(--text-muted);
  margin-bottom: 8px; font-weight: 500;
}
.stat-card .value {
  font-size: 1.9rem; font-weight: 600;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
  display: flex; align-items: baseline; gap: 6px; line-height: 1;
}
.stat-card .value .unit { font-size: 0.85rem; color: var(--text-muted); font-weight: 400; }
.stat-card .delta { margin-top: 8px; font-size: 0.78rem; color: var(--text-dim); }
.stat-card.featured {
  background: linear-gradient(135deg, var(--accent-soft), transparent 70%), var(--panel);
  border-color: color-mix(in oklch, var(--accent), transparent 75%);
}
.stat-card.featured .value { color: var(--accent); }

.section-card {
  padding: 0; border-radius: var(--radius);
  background: var(--panel);
  border: 1px solid var(--hairline);
  overflow: hidden;
}
.section-card .sc-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 16px 20px; border-bottom: 1px solid var(--hairline);
}
.section-card .sc-head h3 {
  margin: 0; font-size: 0.95rem; font-weight: 600; letter-spacing: -0.01em;
}

.progress-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.progress-table th {
  text-align: left; padding: 12px 14px;
  font-weight: 500; font-size: 0.72rem;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--hairline);
  background: oklch(100% 0 0 / 0.02);
}
.progress-table th.num, .progress-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.progress-table td {
  padding: 14px; border-bottom: 1px solid var(--hairline);
  vertical-align: middle;
}
.progress-table tr:last-child td { border-bottom: none; }
.progress-table tr:hover td { background: oklch(100% 0 0 / 0.025); }
.progress-table .l-id { font-family: var(--font-mono); font-size: 0.78rem; color: var(--text-muted); background: none; padding: 0; }
.progress-table .acc-cell { display: flex; align-items: center; gap: 10px; justify-content: flex-end; }
.progress-table .acc-bar {
  width: 60px; height: 4px;
  background: oklch(100% 0 0 / 0.06);
  border-radius: 2px; overflow: hidden;
}
.progress-table .acc-bar i { display: block; height: 100%; background: var(--accent); border-radius: inherit; }

/* ---------- Skeleton placeholders (HTMX dynamic-load fallback) ----------
   Used by /app/progress's shell while the real data partial is fetching. */
.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  color: var(--text-muted);
}
.skeleton::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(
    90deg, transparent, oklch(100% 0 0 / 0.04) 50%, transparent
  );
  animation: skeletonPulse 1.4s ease-in-out infinite;
  pointer-events: none;
}
@keyframes skeletonPulse {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

/* ---------- Toast (transient on-screen banner) ---------- */
.toast {
  position: fixed;
  top: 76px;                /* clears the .header (~64px) */
  left: 50%;
  transform: translateX(-50%) translateY(-12px);
  z-index: 100;
  min-width: 280px; max-width: 420px;
  padding: 12px 16px;
  border-radius: 12px;
  background: var(--panel-solid);
  border: 1px solid var(--hairline-strong);
  color: var(--text);
  font-size: 0.85rem;
  box-shadow: var(--shadow-md), 0 0 0 1px oklch(0% 0 0 / 0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease-out, transform 0.2s ease-out;
}
.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.toast[hidden] { display: none; }
.toast .toast-head {
  font-weight: 500;
  margin-bottom: 6px;
  color: var(--text-dim);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.toast .toast-list {
  list-style: none;
  margin: 0; padding: 0;
  display: flex; flex-direction: column;
  gap: 4px;
}
.toast .toast-list li { line-height: 1.35; }
.toast .toast-id {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--accent);
  margin-right: 4px;
}
@media (max-width: 600px) {
  .toast { left: 12px; right: 12px; transform: translateY(-12px); min-width: 0; max-width: none; }
  .toast.show { transform: translateY(0); }
}

/* ---------- Session intro bubble (first assistant message) ---------- */
.intro-greet {
  font-weight: 500;
  margin-bottom: 8px;
}
.intro-list {
  list-style: none;
  margin: 0; padding: 0;
  display: flex; flex-direction: column;
  gap: 8px;
}
.intro-list > li {
  padding: 8px 10px;
  border-radius: 8px;
  background: oklch(100% 0 0 / 0.03);
  border: 1px solid var(--hairline);
}
.intro-list > li strong { color: var(--accent); }
.intro-brief {
  margin-top: 3px;
  font-size: 0.88rem;
  color: var(--text-dim);
  line-height: 1.4;
}

/* ---------- Practice-history bar chart ---------- */
/* Bars are server-rendered with inline `height: Npx` so we don't depend on
   percent-height cascading through flex (which collapses to 0 when a parent
   has auto cross-size). The chart container reserves enough space for the
   max bar height (CHART_PX server-side) plus the daily label. */
.history-chart {
  display: flex; align-items: flex-end; gap: 3px;
  padding: 14px 20px 12px;
}
.hist-col {
  flex: 1 1 0;
  display: flex; flex-direction: column; align-items: stretch;
  gap: 6px;
  min-width: 0;
  position: relative;
  cursor: default;
}
.hist-col:hover .hist-bar:not(.empty),
.hist-col:focus-visible .hist-bar:not(.empty) {
  filter: brightness(1.18);
}
.hist-tooltip {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%; transform: translateX(-50%);
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--hairline);
  padding: 6px 9px;
  border-radius: 6px;
  font-size: 0.72rem;
  line-height: 1.25;
  text-align: center;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s ease-out;
  z-index: 5;
  box-shadow: 0 4px 14px oklch(0% 0 0 / 0.25);
}
.hist-tooltip strong { color: var(--accent); font-weight: 600; }
.hist-col:hover .hist-tooltip,
.hist-col:focus-visible .hist-tooltip { opacity: 1; }
/* Avoid tooltip clipping at the left/right edges of the chart */
.history-chart > .hist-col:nth-child(-n+3) .hist-tooltip { left: 0; transform: none; }
.history-chart > .hist-col:nth-last-child(-n+3) .hist-tooltip { left: auto; right: 0; transform: none; }
.hist-bar {
  display: block; width: 100%;
  background: var(--accent);
  border-radius: 2px 2px 0 0;
  transition: height 0.18s ease-out;
}
.hist-bar.empty {
  background: oklch(100% 0 0 / 0.06);
  height: 2px;
}
.hist-lbl {
  text-align: center;
  font-size: 0.62rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 600px) {
  .history-chart { padding: 12px 12px 8px; gap: 2px; }
  .hist-lbl { font-size: 0.55rem; }
}

/* ---------- Forms ---------- */
.settings-form {
  display: grid; gap: 16px;
  max-width: 420px;
  padding: 20px;
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
}
.settings-form label { display: flex; flex-direction: column; gap: 6px; }
.settings-form label > span {
  font-size: 0.7rem; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600;
}
.settings-form select, .settings-form input,
.inline-form input, .inline-form select {
  padding: 9px 12px;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-sm);
  font: inherit; font-family: inherit; font-size: 0.92rem;
  background: var(--panel-solid);
  color: var(--text);
}
.settings-form select:focus, .settings-form input:focus,
.inline-form input:focus {
  outline: none;
  border-color: color-mix(in oklch, var(--accent), transparent 50%);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent), transparent 85%);
}
.mode-picker {
  border: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.mode-picker legend {
  font-size: 0.92rem;
  color: var(--text);
  font-weight: 500;
  margin-bottom: 6px;
  padding: 0;
}
.mode-option {
  display: flex !important; flex-direction: row !important;
  align-items: flex-start; gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.mode-option:hover { border-color: color-mix(in oklch, var(--accent), transparent 50%); }
.mode-option input[type="radio"] { margin-top: 3px; accent-color: var(--accent); }
.mode-option > span { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.mode-option strong { font-size: 0.92rem; color: var(--text); font-weight: 600; }
.mode-option em { font-style: normal; font-size: 0.82rem; color: var(--text-dim); }
.mode-option:has(input:checked) {
  border-color: var(--accent);
  background: color-mix(in oklch, var(--accent), transparent 92%);
}

.profile-summary { margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid var(--hairline); }
.profile-summary ul { list-style: none; padding: 0; line-height: 1.9; }
.profile-summary li { display: flex; gap: 1rem; }
.profile-summary li strong { color: var(--text-muted); min-width: 90px; font-weight: 500;
  font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; }

/* ---------- Admin ---------- */
.allow-list { list-style: none; padding: 0; margin: 0 0 .75rem; }
.allow-list li {
  display: flex; justify-content: space-between; align-items: center; gap: .5rem;
  padding: .65rem .85rem;
  background: var(--panel-solid);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  margin-bottom: .35rem;
  font-size: 0.88rem;
}
.inline-form { display: inline-flex; gap: .5rem; align-items: center; margin: 0; flex-wrap: wrap; }

/* ---------- Banners ---------- */
.banner {
  padding: 12px 16px; border-radius: var(--radius);
  margin-bottom: 16px; font-size: 0.9rem; line-height: 1.5;
  border: 1px solid; background: var(--panel);
}
.banner-ok { border-color: color-mix(in oklch, var(--ok), transparent 60%); color: var(--ok);
  background: color-mix(in oklch, var(--ok), transparent 92%); }
.banner-err { border-color: color-mix(in oklch, var(--err), transparent 60%); color: var(--err);
  background: color-mix(in oklch, var(--err), transparent 92%); }

/* Danger zone */
.danger-zone {
  padding: 18px 20px; border-radius: var(--radius);
  border: 1px solid color-mix(in oklch, var(--err), transparent 70%);
  background: color-mix(in oklch, var(--err), transparent 96%);
}
.danger-zone h3 { color: var(--err); margin-top: 0; }
.danger-zone p { color: var(--text-dim); font-size: .88rem; }
.tg-link-slot { margin-left: .5rem; display: inline-block; vertical-align: middle; }

/* ---------- Tables (generic) ---------- */
.table-wrap { overflow-x: auto; margin: 0 -4px; }
.lesson-table {
  width: 100%; border-collapse: collapse;
}
.lesson-table th, .lesson-table td {
  padding: 12px 14px; text-align: left; font-size: 0.88rem;
  border-bottom: 1px solid var(--hairline);
}
.lesson-table thead th {
  background: oklch(100% 0 0 / 0.02);
  font-weight: 500; font-size: 0.72rem;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--text-muted);
}
.lesson-table th.num, .lesson-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.lesson-table tbody tr:hover td { background: oklch(100% 0 0 / 0.025); }

/* ---------- Landing ---------- */
main.landing {
  max-width: 440px; margin: 12vh auto; padding: 2.5rem 1.75rem;
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  text-align: center;
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
}
main.landing .brand-mark { margin: 0 auto 1.25rem; width: 56px; height: 56px; }
main.landing h1 {
  margin: 0 0 .35rem; font-size: 1.8rem; letter-spacing: -0.02em; font-weight: 600;
}
main.landing .tagline { color: var(--text-dim); margin: 0 0 2rem; }
main.landing .login-buttons { display: flex; flex-direction: column; gap: .75rem; align-items: center; }
main.landing .silent-note { margin-top: 2rem; font-size: .85rem; color: var(--text-muted); }
.btn-google {
  width: 240px; padding: .75rem 1.4rem; justify-content: center;
  background: oklch(98% 0 0); color: #3c4043; border: 1px solid oklch(85% 0 0);
}
.btn-google:hover { filter: brightness(0.97); background: oklch(98% 0 0); border-color: oklch(80% 0 0); }
.g-icon {
  background: #4285f4; color: #fff;
  width: 22px; height: 22px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 0.8rem;
}
.tg-slot { min-height: 48px; display: flex; justify-content: center; align-items: center; }

/* ---------- Mobile ---------- */
@media (max-width: 720px) {
  .header { padding: 0 14px; gap: 8px; }
  .brand-name { display: none; }
  .nav { max-width: none; margin-left: 0; }
  .main { padding: 20px 14px 100px; }
  .lesson-grid { grid-template-columns: 1fr; gap: 10px; }
  .page-head { flex-direction: column; align-items: flex-start; gap: 14px; }
  .page-head .right { width: 100%; }
  .trainer { margin: 0; border-radius: 0;
             height: calc(100vh - var(--header-h));
             height: calc(100dvh - var(--header-h));
             border-left: none; border-right: none;
             border-top: none; border-bottom: none; }
  .msg { max-width: 92%; }
  .stats-grid { grid-template-columns: 1fr 1fr; }
  .user-menu .name { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition: none !important; }
}

/* ---------- learner-UX chips: header daily-streak + per-card next-review ---------- */

.streak-chip {
  display: inline-flex; align-items: center; gap: 4px;
  margin-left: 8px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 600;
  color: #ffa94d;
  background: rgba(255, 169, 77, 0.12);
  border: 1px solid rgba(255, 169, 77, 0.3);
  user-select: none;
}
.streak-chip svg { width: 13px; height: 13px; }

.next-review-chip {
  display: inline-block;
  margin-top: 4px;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--text-dim);
  background: var(--code-bg, rgba(255, 255, 255, 0.06));
  letter-spacing: 0.01em;
}
.next-review-chip.due {
  color: var(--accent);
  background: var(--accent-soft, rgba(167, 139, 250, 0.15));
  font-weight: 600;
}

/* CEFR level pill on the lesson card (A1 / A2 / A2-B1 etc.). Small muted
   chip absolutely positioned just left of the top-right checkmark so it
   shares that row without consuming vertical space. */
.lesson-level {
  position: absolute;
  top: 13px;
  right: 40px;
  padding: 0 6px;
  border-radius: 6px;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.55;
  color: var(--text-dim);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.08);
}

/* Larger badge on the lesson page header (next to the H1). */
.lesson-level-badge {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--text);
  background: var(--accent-soft, rgba(167, 139, 250, 0.15));
  vertical-align: middle;
}

/* ---------- /app/onboarding — first-visit mode picker ---------- */
.onboarding-page .page-head { margin-bottom: 32px; }
.onboarding-form { max-width: 1000px; margin: 0 auto; }
.mode-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
@media (max-width: 760px) {
  .mode-grid { grid-template-columns: 1fr; }
}
.mode-card {
  position: relative;
  display: block;
  padding: 20px 22px 16px;
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s, transform 0.15s;
}
.mode-card:hover { border-color: var(--hairline-strong); transform: translateY(-1px); }
.mode-card input[type="radio"] {
  position: absolute; top: 16px; right: 16px;
  margin: 0;
  accent-color: var(--accent);
}
.mode-card:has(input:checked) {
  border-color: var(--accent);
  background: color-mix(in oklch, var(--accent), transparent 92%);
}
.mode-card-head h3 {
  margin: 0 0 6px 0;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--text);
  padding-right: 28px; /* leave room for the radio */
}
.mode-card-head p {
  margin: 0 0 16px 0;
  color: var(--text-dim);
  font-size: 0.92rem;
  line-height: 1.5;
}
.mode-card-example {
  background: var(--panel-solid, rgba(0, 0, 0, 0.15));
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  padding: 14px;
  margin: 0 0 14px 0;
  pointer-events: none; /* preview only */
}
.mode-card-example .msg { margin-bottom: 10px; }
.mode-card-example .msg:last-child { margin-bottom: 0; }
.mode-card-example .bubble {
  font-size: 0.88rem;
  padding: 10px 12px;
}
.mode-card-foot {
  display: flex; gap: 8px; flex-wrap: wrap;
}
.mode-tag {
  padding: 2px 10px;
  font-size: 0.72rem;
  color: var(--text-muted);
  background: var(--code-bg, rgba(255, 255, 255, 0.06));
  border-radius: 999px;
}
.onboarding-cta {
  margin-top: 28px;
  display: flex; flex-direction: column; align-items: center;
}

/* ---------- /app/lesson/<id> — per-lesson study page ---------- */

.lesson-id-pill {
  display: inline-block;
  padding: 2px 10px;
  margin-right: 8px;
  border-radius: 999px;
  background: var(--accent-soft, rgba(167, 139, 250, 0.18));
  color: var(--accent);
  font-size: 0.6em;
  font-weight: 600;
  vertical-align: middle;
  letter-spacing: 0.02em;
}

.lesson-page {
  margin-top: 28px;
  background: var(--panel, rgba(255, 255, 255, 0.03));
  border: 1px solid var(--hairline);
  border-radius: 14px;
  padding: 28px 32px;
  line-height: 1.65;
  color: var(--text);
}
.lesson-page h1, .lesson-page h2, .lesson-page h3, .lesson-page h4 {
  color: var(--text);
  font-weight: 600;
  margin-top: 1.6em;
  margin-bottom: 0.6em;
}
.lesson-page h1 { font-size: 1.6rem; margin-top: 0; }
.lesson-page h2 { font-size: 1.25rem; border-bottom: 1px solid var(--hairline); padding-bottom: 0.3em; }
.lesson-page h3 { font-size: 1.08rem; color: var(--accent); }
.lesson-page p { margin: 0.7em 0; }
.lesson-page ul, .lesson-page ol { margin: 0.7em 0; padding-left: 1.6em; }
.lesson-page li { margin: 0.25em 0; }
.lesson-page strong { color: var(--text); font-weight: 600; }
.lesson-page em { color: var(--text-dim); font-style: italic; }
.lesson-page code {
  background: var(--code-bg, rgba(255, 255, 255, 0.06));
  border-radius: 4px;
  padding: 1px 6px;
  font-family: "Geist Mono", ui-monospace, monospace;
  font-size: 0.92em;
}
.lesson-page blockquote {
  margin: 1em 0;
  padding: 0.6em 1em;
  border-left: 3px solid var(--accent);
  background: var(--accent-soft, rgba(167, 139, 250, 0.08));
  color: var(--text);
  border-radius: 0 8px 8px 0;
}
.lesson-page blockquote p { margin: 0.3em 0; }
.lesson-page table {
  border-collapse: collapse;
  margin: 1em 0;
  width: 100%;
  font-size: 0.95em;
}
.lesson-page th, .lesson-page td {
  border: 1px solid var(--hairline);
  padding: 8px 12px;
  text-align: left;
}
.lesson-page th {
  background: var(--code-bg, rgba(255, 255, 255, 0.04));
  font-weight: 600;
}
.lesson-page img { max-width: 100%; height: auto; border-radius: 8px; margin: 1em 0; }
.lesson-page-cta {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--hairline);
  display: flex; justify-content: center;
}

/* ---------- 404 page ---------- */
.error-page {
  margin: 64px auto 0;
  max-width: 520px;
  text-align: center;
}
.error-code {
  font-family: "Geist Mono", ui-monospace, monospace;
  font-size: 5rem;
  font-weight: 700;
  line-height: 1;
  color: var(--accent);
  opacity: 0.9;
  letter-spacing: -0.04em;
}
.error-page .h1 { margin-top: 16px; }
.error-page .subtitle { margin: 12px auto 28px; }
.error-page code {
  background: var(--code-bg, rgba(255, 255, 255, 0.06));
  padding: 1px 6px;
  border-radius: 4px;
  font-family: "Geist Mono", ui-monospace, monospace;
  font-size: 0.95em;
}
.error-actions { display: flex; justify-content: center; gap: 12px; flex-wrap: wrap; }

.mistake-list { margin-top: 24px; padding: 20px 24px; }
.mistake-list h3 { margin: 0 0 12px 0; color: var(--accent); font-size: 1.05rem; }
.mistake-list ol { margin: 0; padding-left: 1.4em; }
.mistake-list li { margin: 0.8em 0; }
.mistake-prompt { color: var(--text-dim); font-size: 0.92em; margin-bottom: 2px; }
.mistake-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.mistake-bad {
  color: #f87171;
  background: rgba(248, 113, 113, 0.1);
  padding: 1px 8px;
  border-radius: 4px;
  font-family: "Geist Mono", ui-monospace, monospace;
  font-size: 0.92em;
}
.mistake-good {
  color: #4ade80;
  background: rgba(74, 222, 128, 0.1);
  padding: 1px 8px;
  border-radius: 4px;
  font-family: "Geist Mono", ui-monospace, monospace;
  font-size: 0.92em;
}
.mistake-arrow { color: var(--text-muted); }
.mistake-note { color: var(--text-dim); font-size: 0.9em; margin-top: 4px; }

@media (max-width: 720px) {
  .lesson-page { padding: 18px 16px; }
}
