/*
 * ds.css — IELTS Speaking Coach shared design system
 * All classes are prefixed .ds- to avoid conflicts with existing page styles.
 * Safe to link from any page; no globals are overridden except :root vars.
 */

/* ── Design tokens ─────────────────────────────────────────────────────────── */
:root {
  --ds-navy:      #0C2340;
  --ds-teal:      #0F766E;
  --ds-teal-lt:   #14b8a6;
  --ds-bg:        #0a1628;
  --ds-surface:   rgba(255,255,255,0.04);
  --ds-border:    rgba(255,255,255,0.08);
  --ds-text:      rgba(255,255,255,0.85);
  --ds-muted:     rgba(255,255,255,0.4);
  --ds-faint:     rgba(255,255,255,0.15);

  /* Criterion colours */
  --ds-fc:  #38bdf8;   /* sky-400 */
  --ds-lr:  #a78bfa;   /* violet-400 */
  --ds-gra: #fb923c;   /* orange-400 */
  --ds-p:   #f472b6;   /* pink-400 */

  /* ── Sprint 6.2 skill-direction tokens ───────────────────────────────────
   * Migrated from home.css + vocabulary.css unprefixed namespace
   * (Sprint 5.1 / 6.0). These coexist with the legacy --ds-bg / --ds-surface
   * / --ds-muted tokens above so 18 pre-Sprint-6.2 pages keep their existing
   * appearance while skill-aligned pages (home, vocabulary, Tier 1) opt into
   * the more refined opacity scale via these names.
   */
  --ds-bg-elevated:        rgba(255,255,255,0.035);
  --ds-bg-elevated-hover:  rgba(20,184,166,0.06);
  --ds-border-hover:       rgba(20,184,166,0.4);
  --ds-border-strong:      rgba(255,255,255,0.16);
  --ds-text-muted:         rgba(241,245,249,0.55);  /* readable secondary */
  --ds-text-faint:         rgba(241,245,249,0.32);  /* tertiary / hints */
  --ds-accent-warm:        #f59e0b;                  /* amber heat */
  --ds-shadow-card:        0 12px 40px rgba(7, 12, 24, 0.4);
  --ds-shadow-lift:        0 20px 60px rgba(15, 118, 110, 0.18);

  /* ── Sprint 14.7 warning banner tokens ───────────────────────────────────
   * Dark-theme defaults. Light theme overrides below. WCAG AA contrast
   * verified manually: dark theme uses --ds-warning-text = #fbbf24
   * (amber-400) on rgba(251,191,36,0.10) which composites against the
   * #0a1628 ds-bg to ~5.7:1 contrast for normal text. Light theme uses
   * #92400e (amber-800) on #fef3c7 (amber-100) → 8.4:1 contrast.
   * Sprint 14.1 noted #fbbf24 → 1.7:1 on light bg — avoided by
   * darkening the text token under [data-theme="light"] below.
   */
  --ds-warning-bg:     rgba(251,191,36,0.10);
  --ds-warning-border: rgba(251,191,36,0.45);
  --ds-warning-text:   #fbbf24;

  /* Sprint 16.3.1 danger tokens (content-purge warning chip) — dark defaults. */
  --ds-danger-bg:      rgba(248,113,113,0.12);
  --ds-danger-border:  rgba(248,113,113,0.45);
  --ds-danger-text:    #f87171;   /* red-400 — readable on dark */

  /* ── Sprint 14.8 grammar-check tokens ─────────────────────────────────────
   * Wavy underline colour for transcript highlights + the tooltip
   * surface. Red is the conventional "spell-check" signal in browsers,
   * which keeps the affordance learnable. Light theme darkens both
   * the underline (red-700 #b91c1c, 7.0:1 on white) and the tooltip
   * surface to clear WCAG AA — Sprint 14.1 amber lesson re-applied
   * to red.
   */
  --ds-grammar-underline: #ef4444;            /* red-500 */
  --ds-grammar-tooltip-bg:   rgba(15,23,42,0.96);
  --ds-grammar-tooltip-text: rgba(255,255,255,0.95);
  --ds-grammar-flash-bg:     rgba(251,191,36,0.30);
}

/* ── Sprint 14.1 — light-theme override for the legacy --ds-* tokens ────────
 *
 * The :root block above ships dark-theme-only values:
 *   --ds-text     = rgba(255,255,255,0.85)   (invisible on light)
 *   --ds-surface  = rgba(255,255,255,0.04)   (invisible on light)
 *   --ds-border   = rgba(255,255,255,0.08)   (invisible on light)
 *
 * aver-design tokens.css (frontend/css/aver-design/tokens.css) already
 * defines the correct light + dark palettes via [data-theme] on <html>,
 * so the cheapest fix is to alias --ds-* to the matching --av-* tokens
 * under [data-theme="light"]. Dark theme keeps the legacy literals
 * verbatim — zero regression.
 *
 * Andy 2026-05-22: speaking results page light-theme contrast bug. Sprint
 * 14.0 Discovery confirmed result.css is already on --av-* tokens; the
 * remaining offender is ds.css' :root block + a dozen hardcoded
 * rgba(255,255,255,X) literals in result-page rules (.ds-question-card,
 * .ds-crit, .ds-band-pill, .ds-strength-item, .ds-improve-item,
 * .ds-empty-title, .ds-progress-track). Those literals are migrated to
 * var(--ds-surface) / var(--ds-text) below so they inherit the flip too.
 */
:root[data-theme="light"] {
  --ds-bg:                var(--av-surface-page);
  --ds-surface:           var(--av-surface-sunken);
  --ds-border:            var(--av-border-default);
  --ds-text:              var(--av-text-primary);
  --ds-muted:             var(--av-text-muted);
  --ds-faint:             var(--av-text-faint);
  --ds-bg-elevated:       var(--av-surface-card);
  --ds-bg-elevated-hover: var(--av-surface-sunken);
  --ds-border-hover:      var(--av-border-strong);
  --ds-border-strong:     var(--av-border-strong);
  --ds-text-muted:        var(--av-text-muted);
  --ds-text-faint:        var(--av-text-faint);

  /* Sprint 14.7 light-theme warning palette. amber-100 / amber-800 +
   * amber-400 border combo for 8.4:1 normal-text contrast (WCAG AA
   * required ≥4.5:1). The dark-theme #fbbf24 text on light bg would
   * be 1.7:1 — explicitly avoided per Sprint 14.1 lesson. */
  --ds-warning-bg:     #fef3c7;
  --ds-warning-border: #d97706;
  --ds-warning-text:   #92400e;

  /* Sprint 16.3.1 light-theme danger palette — red-100 / red-600 / red-800
   * (text #991b1b on #fee2e2 ≈ 7:1, clears WCAG AA; dark #f87171 would fail). */
  --ds-danger-bg:      #fee2e2;
  --ds-danger-border:  #dc2626;
  --ds-danger-text:    #991b1b;

  /* Sprint 14.8 light-theme grammar tokens — darken red underline
   * to red-700 for 7.0:1 contrast on white; darken tooltip surface
   * to gray-800 with a white text for 12.6:1. */
  --ds-grammar-underline:    #b91c1c;
  --ds-grammar-tooltip-bg:   rgba(31,41,55,0.96);
  --ds-grammar-tooltip-text: rgba(255,255,255,0.96);
  --ds-grammar-flash-bg:     rgba(217,119,6,0.20);
}

/* ── Skill-direction page canvas (.ds-canvas) ────────────────────────────────
 * Opt-in body class that supplies the canonical Sprint 5.1 navy ground +
 * atmosphere overlay (faint film grain + corner radial gradient mesh).
 * Lifted from home.css so any Tier 1/Tier 0 page can reuse the look with
 * one class instead of duplicating ~30 lines of pseudo-element CSS per
 * page. Atmosphere is fixed-positioned + pointer-events: none, so it never
 * intercepts clicks or scrolls with content.
 *
 * Legacy pages that don't link this class keep their existing solid /
 * gradient backgrounds — opt-in keeps the migration risk surface contained
 * to whoever's actively touching their page.
 */
body.ds-canvas {
  background: var(--ds-bg);
  color: var(--ds-text);
  position: relative;
  min-height: 100vh;
  /* Sprint 6.2.1 — explicit font stack so pages get Manrope without
     depending on Tailwind CDN's runtime compile of `font-sans`. The
     CDN compile is timing-sensitive (it runs after first paint on slow
     networks) and several Tier 1 pages were rendering Inter as the
     browser fallback before this declaration landed. The Google Fonts
     <link> already loads Manrope; this just wires it into the cascade
     deterministically. */
  font-family: 'Manrope', ui-sans-serif, system-ui, sans-serif;
  font-feature-settings: 'ss01', 'cv11';
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
body.ds-canvas::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0.025;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220' viewBox='0 0 220 220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}
body.ds-canvas::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(900px 600px at 12% -10%, rgba(20, 184, 166, 0.12), transparent 60%),
    radial-gradient(700px 500px at 88% 105%, rgba(15, 118, 110, 0.10), transparent 60%);
}

/* ── Display utility (Fraunces variable serif) ──────────────────────────────
 * Hand-applied to hero headings + page titles only — NOT a blanket replace
 * for every h1/h2. Functional headings (form labels, modal titles) stay in
 * the body sans (Manrope) so the contrast stays meaningful.
 */
.ds-display,
.display {
  font-family: 'Fraunces', ui-serif, Georgia, serif;
  font-optical-sizing: auto;
  font-variation-settings: "opsz" 144;
  letter-spacing: -0.02em;
  font-weight: 400;
}

/* ── Fade-in animation ─────────────────────────────────────────────────────── */
@keyframes ds-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.ds-fadein { animation: ds-in 0.25s ease both; }

/* ── Question card — highlighted left-border accent ───────────────────────── */
.ds-question-card {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-left: 4px solid var(--ds-teal-lt);
  border-radius: 16px;
  padding: 20px 24px;
}
.ds-question-card .ds-q-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ds-teal-lt);
  margin-bottom: 10px;
}
.ds-question-card .ds-q-text {
  font-size: 1.1rem;
  font-weight: 600;
  line-height: 1.6;
  color: var(--ds-text);
}

/* ── Cue card ──────────────────────────────────────────────────────────────── */
.ds-cue-card {
  background: rgba(15,118,110,0.08);
  border: 1px solid rgba(20,184,166,0.25);
  border-radius: 14px;
  padding: 18px 20px;
}
.ds-cue-bullet {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 0.875rem;
  color: var(--ds-text);
  padding: 4px 0;
}
.ds-cue-bullet::before {
  content: '→';
  color: var(--ds-teal-lt);
  flex-shrink: 0;
  font-weight: 700;
  margin-top: 1px;
}

/* ── Band hero (large overall band display) ────────────────────────────────── */
.ds-band-hero {
  background: linear-gradient(135deg, rgba(15,118,110,0.2) 0%, rgba(20,184,166,0.08) 100%);
  border: 1px solid rgba(20,184,166,0.3);
  border-radius: 20px;
  padding: 28px 24px;
  text-align: center;
}
.ds-band-hero .ds-band-value {
  font-size: 5rem;
  font-weight: 800;
  line-height: 1;
  color: var(--ds-teal-lt);
  letter-spacing: -0.03em;
}
.ds-band-hero .ds-band-value.band-high { color: #14b8a6; }
.ds-band-hero .ds-band-value.band-mid  { color: #fbbf24; }
.ds-band-hero .ds-band-value.band-low  { color: #f97316; }
.ds-band-hero .ds-band-value.band-none { color: #6b7280; }
.ds-band-hero .ds-band-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--ds-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: 6px;
}

/* ── Criterion cards ───────────────────────────────────────────────────────── */
.ds-crit {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: 12px;
  padding: 16px;
  text-align: center;
  transition: border-color 0.2s, background 0.2s;
}
.ds-crit:hover { background: var(--ds-bg-elevated-hover); }

.ds-crit-fc  { border-top: 3px solid var(--ds-fc);  }
.ds-crit-lr  { border-top: 3px solid var(--ds-lr);  }
.ds-crit-gra { border-top: 3px solid var(--ds-gra); }
.ds-crit-p   { border-top: 3px solid var(--ds-p);   }

.ds-crit .ds-crit-score {
  font-size: 2rem;
  font-weight: 800;
  line-height: 1;
  margin-bottom: 4px;
}
/* Default colours per criterion — JS band-* classes (higher specificity) will override */
.ds-crit-fc  > .ds-crit-score.band-none  { color: var(--ds-fc);  }
.ds-crit-lr  > .ds-crit-score.band-none  { color: var(--ds-lr);  }
.ds-crit-gra > .ds-crit-score.band-none  { color: var(--ds-gra); }
.ds-crit-p   > .ds-crit-score.band-none  { color: var(--ds-p);   }
/* Once JS sets a real band class, use semantic colour */
.ds-crit-score.band-high { color: #14b8a6; }
.ds-crit-score.band-mid  { color: #fbbf24; }
.ds-crit-score.band-low  { color: #f97316; }

.ds-crit .ds-crit-label {
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ds-muted);
}

/* ── Recording state ring ──────────────────────────────────────────────────── */
.ds-rec-ring {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: rgba(239,68,68,0.08);
  border: 2px solid rgba(239,68,68,0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  animation: ds-rec-pulse 2s ease-in-out infinite;
  margin: 0 auto;
}
@keyframes ds-rec-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0.25); }
  50%       { box-shadow: 0 0 0 16px rgba(239,68,68,0); }
}

/* ── Empty state ───────────────────────────────────────────────────────────── */
.ds-empty {
  text-align: center;
  padding: 48px 24px;
}
.ds-empty-icon {
  font-size: 3rem;
  line-height: 1;
  margin-bottom: 12px;
}
.ds-empty-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--ds-text);
  margin-bottom: 6px;
}
.ds-empty-sub {
  font-size: 0.8125rem;
  color: var(--ds-muted);
  margin-bottom: 20px;
}

/* ── Strength / improvement list items ────────────────────────────────────── */
.ds-strength-item {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 0.875rem;
  color: var(--ds-text);
  padding: 4px 0;
}
.ds-strength-item::before {
  content: '✓';
  color: var(--ds-teal-lt);
  font-weight: 700;
  flex-shrink: 0;
  margin-top: 1px;
}
.ds-improve-item {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 0.875rem;
  color: var(--ds-text);
  padding: 4px 0;
}
.ds-improve-item::before {
  content: '↑';
  color: #fbbf24;
  font-weight: 700;
  flex-shrink: 0;
  margin-top: 1px;
}

/* ── Progress bar ──────────────────────────────────────────────────────────── */
.ds-progress-track {
  height: 4px;
  border-radius: 9999px;
  background: var(--ds-border);
  overflow: hidden;
}
.ds-progress-fill {
  height: 100%;
  border-radius: 9999px;
  background: linear-gradient(90deg, var(--ds-teal), var(--ds-teal-lt));
  transition: width 0.4s ease;
}

/* ── Section heading divider ───────────────────────────────────────────────── */
.ds-section-head {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ds-muted);
  margin-bottom: 12px;
}

/* ── Inline band pill ──────────────────────────────────────────────────────── */
.ds-band-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.6875rem;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 9999px;
  background: var(--ds-surface);
}
.ds-band-pill-fc  { color: var(--ds-fc);  border: 1px solid rgba(56,189,248,0.25); }
.ds-band-pill-lr  { color: var(--ds-lr);  border: 1px solid rgba(167,139,250,0.25); }
.ds-band-pill-gra { color: var(--ds-gra); border: 1px solid rgba(251,146,60,0.25); }
.ds-band-pill-p   { color: var(--ds-p);   border: 1px solid rgba(244,114,182,0.25); }

/* ── Toast notification ────────────────────────────────────────────────────── */
.ds-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%) translateY(8px);
  background: rgba(15,118,110,0.95);
  color: #fff;
  font-size: 0.875rem;
  font-weight: 600;
  padding: 10px 20px;
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.4);
  opacity: 0;
  transition: opacity 0.2s, transform 0.2s;
  pointer-events: none;
  z-index: 9999;
  white-space: nowrap;
}
.ds-toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.ds-toast-error { background: rgba(185,28,28,0.95); }

/* ── Focus ring (accessibility) ────────────────────────────────────────────── */
button:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 2px solid var(--ds-teal-lt);
  outline-offset: 2px;
}

/* ── Scrollbar ──────────────────────────────────────────────────────────────── */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.12); border-radius: 9999px; }
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.22); }

/* ── Canonical buttons ──────────────────────────────────────────────────────── */
.btn-primary {
  background: var(--ds-teal);
  color: #fff;
  padding: 10px 20px;
  border-radius: 10px;
  font-weight: 700;
  font-size: 0.875rem;
  cursor: pointer;
  border: none;
  transition: background 0.15s, transform 0.1s;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.btn-primary:hover { background: #0d5f58; transform: translateY(-1px); }
.btn-primary:active { transform: translateY(0); }
.btn-primary:disabled { opacity: 0.55; cursor: not-allowed; transform: none; }

.btn-secondary {
  background: var(--ds-surface);
  color: var(--ds-text);
  padding: 10px 20px;
  border-radius: 10px;
  font-weight: 600;
  font-size: 0.875rem;
  cursor: pointer;
  border: 1px solid var(--ds-border);
  transition: background 0.15s, border-color 0.15s;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.btn-secondary:hover { background: var(--ds-bg-elevated-hover); border-color: var(--ds-border-strong); }
.btn-secondary:disabled { opacity: 0.55; cursor: not-allowed; }

/* ── Form inputs ────────────────────────────────────────────────────────────── */
.ds-form-input {
  background: rgba(255,255,255,0.07);
  border: 1.5px solid rgba(255,255,255,0.14);
  border-radius: 10px;
  color: #fff;
  padding: 11px 14px;
  font-size: 0.9rem;
  width: 100%;
  transition: border-color 0.18s, background 0.18s;
  -webkit-appearance: none;
}
.ds-form-input:focus {
  outline: none;
  border-color: var(--ds-teal);
  background: rgba(15,118,110,0.1);
}

/* ── Modal backdrop ─────────────────────────────────────────────────────────── */
.ds-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.65);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ── Sprint 15.1 — pronunciation phoneme drill-down modal ─────────────────────
 * Pattern #26: colour reaches via --ds-*/--av-* tokens only (the JS renderer
 * bakes NO inline styles; no hex/rgb literals here) so the light/dark flip
 * holds. Score tiers reuse the aver-design semantic tokens. Sentinel:
 * pronunciation-drilldown.test.mjs (Pattern #25/#26 extension). */
/* Sprint 15.3 — phoneme drill-down ACCORDION (replaces the 15.1.2 modal). Native
   <details>/<summary> (free toggle + keyboard + ARIA), rendered inline in the
   pronunciation section so surrounding context stays visible. Token-driven
   (Pattern #25/#26) — no hex/rgb literals; flips with the theme. */
.ds-accordion { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--ds-border); }
.ds-accordion__hint { font-size: 11px; color: var(--ds-muted); margin: 0 0 8px; }
.ds-accordion__item {
  border: 1px solid var(--ds-border);
  border-radius: 10px;
  background: var(--ds-bg-elevated);
  margin-bottom: 8px;
}
.ds-accordion__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 14px;
  cursor: pointer;
  list-style: none;
  font-size: 13px;
  color: var(--ds-text);
}
.ds-accordion__head::-webkit-details-marker { display: none; }
.ds-accordion__head::after { content: '⌄'; color: var(--ds-muted); transition: transform 0.15s ease; }
.ds-accordion__item[open] .ds-accordion__head::after { transform: rotate(180deg); }
.ds-accordion__word { font-weight: 700; }
.ds-accordion__count { font-size: 11px; color: var(--ds-muted); }
.ds-accordion__body { padding: 0 14px 12px; }
.ds-accordion__item--highlight { outline: 2px solid var(--ds-border-hover); outline-offset: 1px; }

.ds-phoneme { border-top: 1px solid var(--ds-border); padding: 12px 0; }
.ds-phoneme:first-of-type { border-top: none; padding-top: 0; }
.ds-phoneme__row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.ds-phoneme__sym { font-size: 1.25rem; font-weight: 800; color: var(--ds-text); }
.ds-phoneme__ipa { font-size: 0.8rem; color: var(--ds-muted); margin-left: 6px; }
.ds-phoneme__score { font-size: 0.8rem; font-weight: 700; }
.ds-phoneme__bar { height: 6px; border-radius: 999px; background: var(--ds-border); margin: 6px 0 8px; overflow: hidden; }
.ds-phoneme__bar-fill { height: 100%; border-radius: 999px; }
.ds-phoneme__bar-fill--low  { background: var(--av-error); }
.ds-phoneme__bar-fill--mid  { background: var(--av-warning); }
.ds-phoneme__bar-fill--high { background: var(--av-success); }
.ds-phoneme__score--low  { color: var(--av-error); }
.ds-phoneme__score--mid  { color: var(--av-warning); }
.ds-phoneme__score--high { color: var(--av-success); }
.ds-phoneme__examples { font-size: 0.8rem; color: var(--ds-muted); margin: 2px 0; }
.ds-phoneme__examples b { color: var(--ds-text); font-weight: 600; }
.ds-phoneme__tip { font-size: 0.8rem; color: var(--av-text-secondary); line-height: 1.5; margin: 4px 0 0; }

.ds-pron-weak-word { cursor: pointer; }
.ds-pron-weak-word:focus-visible { outline: 2px solid var(--ds-border-hover); outline-offset: 2px; }

/* ── Badge / chip ───────────────────────────────────────────────────────────── */
.ds-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.6875rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 9999px;
  background: rgba(255,255,255,0.06);
  color: var(--ds-muted);
  border: 1px solid var(--ds-border);
}
.ds-badge-teal  { background: rgba(15,118,110,0.18); color: var(--ds-teal-lt); border-color: rgba(20,184,166,0.25); }
.ds-badge-sky   { background: rgba(56,189,248,0.1);  color: var(--ds-fc);      border-color: rgba(56,189,248,0.2); }
.ds-badge-amber { background: rgba(251,191,36,0.1);  color: #fbbf24;           border-color: rgba(251,191,36,0.2); }
.ds-badge-red   { background: rgba(239,68,68,0.1);   color: #f87171;           border-color: rgba(239,68,68,0.2); }

/* ── Callout block ──────────────────────────────────────────────────────────── */
.ds-callout {
  background: rgba(15,118,110,0.08);
  border: 1px solid rgba(20,184,166,0.2);
  border-left: 3px solid var(--ds-teal-lt);
  border-radius: 10px;
  padding: 14px 16px;
  font-size: 0.875rem;
  color: rgba(255,255,255,0.8);
  line-height: 1.6;
}

/* ── Sprint 14.7 warning banner ──────────────────────────────────────────────
 * Yellow/amber warning for off-topic + short-length signals (L5/L9).
 * Stacks above per-criterion feedback. Uses --ds-warning-* tokens
 * which flip per theme; banner copy stays readable on both light and
 * dark (WCAG AA verified — see token comments above).
 *
 * Pattern #26 (Sprint 14.6.1): banner copy is rendered via CSS classes
 * only — JS helpers MUST NOT bake inline color/background styles or
 * the light-theme flip breaks. Sentinel `warning-banner-tokens.test.mjs`
 * pins this contract.
 */
.ds-result-warnings {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;
}

.ds-warning-banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: var(--ds-warning-bg);
  border: 1px solid var(--ds-warning-border);
  border-left: 4px solid var(--ds-warning-border);
  border-radius: 10px;
  padding: 12px 14px;
}
.ds-warning-banner .ds-warning-icon {
  flex-shrink: 0;
  font-size: 1.1rem;
  line-height: 1.4;
}
.ds-warning-banner .ds-warning-message {
  flex: 1;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--ds-warning-text);
  margin: 0;
}

/* ── Sprint 16.3 retention soft-hide warning chip (speaking.html history) ────
 * Compact per-row pill flagging a session approaching the 7-day soft-hide.
 * Reuses the --ds-warning-* tokens so both themes pass WCAG AA (the light
 * override is pinned by warning-banner-tokens.test.mjs). No inline literals
 * (Pattern #26). */
.ds-retention-chip {
  display: inline-block;
  margin-top: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  white-space: nowrap;
  background: var(--ds-warning-bg);
  border: 1px solid var(--ds-warning-border);
  color: var(--ds-warning-text);
}
/* Sprint 16.3.1 v2 variants (base chip carries the amber --ds-warning-* tokens). */
.ds-retention-chip--audio-soon { /* amber — inherits the base --ds-warning-* tokens */ }
.ds-retention-chip--content-soon {   /* red — report deletion imminent */
  background: var(--ds-danger-bg);
  border-color: var(--ds-danger-border);
  color: var(--ds-danger-text);
}
/* Sprint 16.4.1: the gray audio-gone variant was removed (Andy D2 — clutter). */

/* ── Sprint 14.6.4 cue-card textarea length warning ─────────────────────────
 * Part-2-only soft warning that surfaces under the cue-card textarea
 * when the user pastes content longer than the AI-gen trigger needs.
 * Driven by `data-state` (`hidden` | `visible`) so the JS helper
 * never injects inline colour / background literals — Pattern #26
 * source-scan sentinel stays clean.
 *
 * Reuses the Sprint 14.7 amber palette tokens (--ds-warning-*) so the
 * banner flips per theme without redefining colours here.
 */
.ds-cuecard-length-warning {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  background: var(--ds-warning-bg);
  border: 1px solid var(--ds-warning-border);
  border-left: 3px solid var(--ds-warning-border);
  border-radius: 8px;
  padding: 8px 12px;
  margin-top: 6px;
}
.ds-cuecard-length-warning[data-state="hidden"] {
  display: none;
}
.ds-cuecard-length-warning-icon {
  flex-shrink: 0;
  font-size: 0.95rem;
  line-height: 1.45;
}
.ds-cuecard-length-warning-message {
  flex: 1;
  margin: 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--ds-warning-text);
}

/* ── Sprint 14.8 grammar-check UI ────────────────────────────────────────────
 * Two surfaces share the data:
 *   1. .ds-grammar-highlight — wavy underline on the transcript that
 *      maps each character span to the offending error. Clickable +
 *      keyboard-focusable so screen readers + keyboard users can
 *      jump to the inline list entry.
 *   2. .ds-grammar-section / .ds-grammar-category / .ds-grammar-error-*
 *      — grouped list under the per-criterion feedback that explains
 *      each error in Vietnamese with the suggested correction.
 *
 * Pattern #26 (Sprint 14.6.1 lesson): the JS helpers do NOT bake
 * inline color/background literals; every visual property below comes
 * from the --ds-grammar-* tokens above. The tokens flip per theme.
 */

.ds-grammar-highlight {
  background: transparent;
  text-decoration: underline wavy var(--ds-grammar-underline);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  cursor: pointer;
  color: inherit;        /* transcript stays in its container's colour */
  position: relative;
  padding: 0;
}
.ds-grammar-highlight:hover,
.ds-grammar-highlight:focus-visible {
  background: var(--ds-grammar-flash-bg);
  outline: 2px solid var(--ds-grammar-underline);
  outline-offset: 1px;
}
.ds-grammar-highlight:hover::after,
.ds-grammar-highlight:focus-visible::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: var(--ds-grammar-tooltip-bg);
  color: var(--ds-grammar-tooltip-text);
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 0.75rem;
  line-height: 1.4;
  max-width: 280px;
  white-space: normal;
  z-index: 100;
  pointer-events: none;
}

.ds-grammar-section {
  margin-bottom: 16px;
}
.ds-grammar-section-head {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ds-text);
  margin: 0 0 8px;
}
.ds-grammar-category {
  margin-bottom: 10px;
}
.ds-grammar-category-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--ds-muted);
  margin: 0 0 4px;
}
.ds-grammar-error-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.ds-grammar-error-item {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: 8px;
  padding: 8px 10px;
  margin-bottom: 6px;
  font-size: 12.5px;
  color: var(--ds-text);
  transition: background 0.4s ease;
}
.ds-grammar-error-item.is-flash {
  background: var(--ds-grammar-flash-bg);
}
.ds-grammar-error-pair {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
}
.ds-grammar-error-original {
  color: var(--ds-grammar-underline);
  text-decoration: underline wavy var(--ds-grammar-underline);
  text-decoration-thickness: 1.5px;
}
.ds-grammar-error-arrow {
  color: var(--ds-muted);
}
.ds-grammar-error-suggestion {
  font-weight: 600;
  color: var(--ds-text);
}
.ds-grammar-error-explanation {
  margin: 4px 0 0;
  font-size: 11.5px;
  color: var(--ds-muted);
  line-height: 1.4;
}
.ds-grammar-more-info {
  margin: 4px 0 0;
  font-size: 11.5px;
  color: var(--ds-muted);
  font-style: italic;
}
