/* ==========================================================================
   learn.css — the classroom (learn.html)
   Page-scoped only. Every value resolves from css/tokens.css; no component
   declared in css/components.css or css/layout.css is restyled here.
   ========================================================================== */

.lx-page {
  /* Measured by js/pages/learn.js so the sticky rail always clears the bar.
     READ-ONLY to the bar itself: nothing inside .lx-bar may size from it, or
     the measurement feeds back into the thing being measured and the bar grows
     a little on every resize. See --lx-bar-min for the bar's own floor. */
  --lx-bar-h: 3.75rem;
  --lx-bar-min: calc(var(--control-h-lg) + var(--space-2));
  --lx-rail: 20rem;
  --lx-stage-ink: var(--slate-50);
  --lx-stage-ink-dim: var(--slate-400);
  padding-bottom: var(--section-y-tight);
}

/* ==========================================================================
   1 · COURSE BAR
   ========================================================================== */
.lx-bar {
  position: sticky;
  top: var(--header-h);
  z-index: var(--z-sticky);
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border-bottom: 1px solid var(--border);
}

/* Without the blur the 14% of transparency stops being frosting and starts
   being a hole: the lecture plate reads straight through the bar. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .lx-bar { background: var(--surface); }
}

.lx-bar-inner {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  min-height: var(--lx-bar-min);
  padding-block: var(--space-2);
}

.lx-back {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
  padding: var(--space-2) var(--space-3);
  margin-left: calc(var(--space-3) * -1);
  border-radius: var(--radius-md);
  color: var(--text-muted);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.lx-back:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.lx-back:active { background: var(--surface-3); }
.lx-back svg { width: 1.05rem; height: 1.05rem; flex: 0 0 auto; }

.lx-bar-course {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  color: var(--text);
  letter-spacing: var(--tracking-tight);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding-left: var(--space-4);
  border-left: 1px solid var(--border);
}

.lx-bar-progress {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 15rem;
}
.lx-bar-progress .progress { width: 8.5rem; }
.lx-bar-pct {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.lx-modules-toggle { display: none; flex: 0 0 auto; }

/* ==========================================================================
   2 · SHELL
   ========================================================================== */
.lx-shell {
  display: grid;
  grid-template-columns: var(--lx-rail) minmax(0, 1fr);
  align-items: start;
  gap: var(--space-8);
  padding-top: var(--space-6);
}

.lx-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* ==========================================================================
   3 · SYLLABUS SIDEBAR
   ========================================================================== */
.lx-sidebar {
  position: sticky;
  top: calc(var(--header-h) + var(--lx-bar-h) + var(--space-4));
  max-height: calc(100svh - var(--header-h) - var(--lx-bar-h) - var(--space-8));
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.lx-sidebar-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--card-pad-tight);
  border-bottom: 1px solid var(--border-subtle);
}

.lx-syl-top { display: flex; align-items: flex-start; gap: var(--space-3); }
.lx-syl-id { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: var(--space-1); }
.lx-syl-title {
  font-size: var(--fs-base);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--lh-snug);
}
.lx-sidebar-close { display: none; }

.lx-syl-progress { display: flex; align-items: center; gap: var(--space-4); }
.lx-syl-counts { min-width: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.lx-syl-count {
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.lx-syl-hint { font-size: var(--fs-xs); color: var(--text-muted); line-height: var(--lh-base); }

.lx-syl-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-3) var(--space-2) var(--space-4);
}

.lx-syl-empty { margin: var(--space-4) var(--space-2) 0; }

/* --- module disclosure -------------------------------------------------- */
.lx-modules { display: flex; flex-direction: column; gap: var(--space-1); }

.lx-mod { border-radius: var(--radius-md); }
.lx-mod.is-open { background: var(--surface-2); }

.lx-mod-trigger {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3);
  border-radius: var(--radius-md);
  text-align: left;
  background: none;
  color: var(--text);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-standard);
}
.lx-mod-trigger:hover { background: var(--surface-3); }
.lx-mod-trigger:active { background: var(--surface-3); }
.lx-mod-trigger:focus-visible { outline: 2px solid var(--focus-ring-color); outline-offset: -2px; }

.lx-mod-index {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1.625rem;
  height: 1.625rem;
  border-radius: var(--radius-sm);
  background: var(--primary-soft);
  color: var(--primary-soft-text);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}
.lx-mod.is-complete .lx-mod-index { background: var(--success-soft); color: var(--success-soft-text); }
.lx-mod.is-complete .lx-mod-index svg { width: 0.9rem; height: 0.9rem; }

.lx-mod-titles { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.lx-mod-title {
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--tracking-tight);
}
.lx-mod-meta {
  font-size: var(--fs-2xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.lx-mod-count { font-weight: var(--fw-bold); color: var(--text-muted); }
.lx-mod.is-complete .lx-mod-count { color: var(--success-soft-text); }

.lx-mod-chevron {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1rem;
  height: 1rem;
  color: var(--text-subtle);
  transition: transform var(--dur-base) var(--ease-out), color var(--dur-fast) var(--ease-standard);
}
.lx-mod-chevron svg { width: 1rem; height: 1rem; }
.lx-mod-trigger[aria-expanded="true"] .lx-mod-chevron { transform: rotate(180deg); color: var(--primary); }

.lx-mod-panel { padding: 0 var(--space-1) var(--space-2) var(--space-2); }
.lx-mod-panel[hidden] { display: none; }
.lx-mod-lectures { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.1rem; }

/* Extra element inside the shared .lecture-row — the kind glyph. */
.lx-kind {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1.125rem;
  height: 1.125rem;
  color: var(--text-muted);
}
.lx-kind svg { width: 1.125rem; height: 1.125rem; }
.lecture-row.is-current .lx-kind { color: currentColor; }

.lx-hit { color: var(--primary); font-weight: var(--fw-bold); }
.lecture-row.is-current .lx-hit { color: inherit; text-decoration: underline; }

/* ==========================================================================
   4 · LECTURE HEAD
   ========================================================================== */
.lx-lecture-head { display: flex; flex-direction: column; gap: var(--space-3); }

.lx-lecture-title {
  font-size: var(--fs-3xl);
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--tracking-tighter);
  line-height: var(--lh-tight);
  text-wrap: balance;
}

.lx-lecture-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  font-size: var(--fs-md);
  color: var(--text-muted);
}
.lx-lecture-meta .lx-meta-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-variant-numeric: tabular-nums;
}
.lx-lecture-meta .lx-meta-item svg { width: 1rem; height: 1rem; opacity: 0.8; }

/* ==========================================================================
   5 · THE STAGE
   ========================================================================== */
.lx-stage-wrap { display: flex; flex-direction: column; gap: var(--space-4); }

.lx-stage {
  position: relative;
  isolation: isolate;
  aspect-ratio: 16 / 9;
  /* 16:9 is very short on a phone; the floor keeps the furniture legible. */
  min-height: 15rem;
  width: 100%;
  border-radius: var(--radius-xl);
  overflow: hidden;
  border: 1px solid var(--slate-800);
  background:
    radial-gradient(120% 90% at 78% 8%, color-mix(in srgb, var(--a-500) 34%, transparent) 0%, transparent 58%),
    radial-gradient(90% 80% at 8% 96%, color-mix(in srgb, var(--amber-500) 20%, transparent) 0%, transparent 55%),
    linear-gradient(160deg, var(--slate-900) 0%, var(--slate-950) 52%, var(--slate-1000) 100%);
  box-shadow: var(--shadow-lg);
}

/* The plate is dark in BOTH themes, so it cannot borrow --focus-ring-color:
   in the light theme that resolves to --a-600, which all but disappears
   against the plate. Everything focusable on the plate rings in --a-300. */
.lx-stage :focus-visible {
  outline: 2px solid var(--a-300);
  outline-offset: 2px;
}

/* --- waveform motif ----------------------------------------------------- */
.lx-stage-art { position: absolute; inset: 0; z-index: 0; opacity: 0.9; }
.lx-wave { position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%); width: 100%; height: 62%; }
.lx-wave-stop-a { stop-color: var(--a-400); }
.lx-wave-stop-b { stop-color: var(--a-300); }
.lx-wave-stop-c { stop-color: var(--amber-400); }

.lx-wave-layer { animation: lx-wave-scroll 14s linear infinite; }
.lx-wave-1 { opacity: 0.55; }
.lx-wave-2 { opacity: 0.3; animation-duration: 22s; transform: translateY(16px) scaleY(0.72); }
.lx-wave-3 { opacity: 0.18; animation-duration: 31s; transform: translateY(-18px) scaleY(1.28); }

@keyframes lx-wave-scroll {
  from { translate: 0 0; }
  to   { translate: -1200px 0; }
}

.lx-stage.is-running .lx-wave-1 { opacity: 0.85; }
.lx-stage.is-running .lx-wave-2 { opacity: 0.5; }

/* --- stage furniture ---------------------------------------------------- */
.lx-stage-grid {
  position: relative;
  z-index: 1;
  height: 100%;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: var(--space-3);
  padding: clamp(var(--space-4), 2.4vw, var(--space-7));
}

.lx-stage-top { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }

.lx-stage-brand { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }
.lx-stage-brand svg { width: 1.5rem; height: 1.5rem; flex: 0 0 auto; }

/* The BI mark on the plate. Drawn from the live accent ramp so it stays legible
   on the dark plate at every accent, in both themes. */
.lx-mark-stop-a { stop-color: var(--a-300); }
.lx-mark-stop-b { stop-color: var(--a-500); }
.lx-mark-stop-c { stop-color: var(--amber-400); }

.lx-stage-brand-text {
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--lx-stage-ink-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lx-stage-pos {
  flex: 0 0 auto;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--lx-stage-ink-dim);
  border: 1px solid var(--slate-750);
  border-radius: var(--radius-full);
  padding: var(--space-1) var(--space-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.lx-stage-centre { display: grid; place-items: center; min-height: 0; overflow: hidden; }

.lx-stage-bottom { display: flex; flex-direction: column; gap: var(--space-1); }
.lx-stage-lecture {
  font-size: clamp(var(--fs-base), 1.6vw, var(--fs-xl));
  font-weight: var(--fw-bold);
  color: var(--lx-stage-ink);
  letter-spacing: var(--tracking-tight);
  line-height: var(--lh-snug);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.lx-stage-note { font-size: var(--fs-xs); color: var(--lx-stage-ink-dim); }

/* --- the action / countdown -------------------------------------------- */
.lx-stage-action { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); text-align: center; }
.lx-stage-action .lx-stage-caption { font-size: var(--fs-sm); color: var(--lx-stage-ink-dim); max-width: 34ch; }

.lx-count {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  text-align: center;
}

.lx-count-ring-wrap {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: clamp(6rem, 13vw, 8.5rem);
  height: clamp(6rem, 13vw, 8.5rem);
}
.lx-count-ring {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
  overflow: visible;
  --lx-c: 276.46;              /* 2πr for r = 44 in the 100×100 viewBox */
  --lx-pct: 0;
}
.lx-count-ring circle { fill: none; stroke-width: 6; }
.lx-count-track { stroke: var(--slate-800); }
.lx-count-fill {
  stroke: var(--a-300);
  stroke-linecap: round;
  stroke-dasharray: var(--lx-c);
  stroke-dashoffset: calc(var(--lx-c) - var(--lx-c) * var(--lx-pct) / 100);
}
.lx-count-num {
  grid-area: 1 / 1;
  font-size: clamp(var(--fs-2xl), 4vw, var(--fs-4xl));
  font-weight: var(--fw-extrabold);
  color: var(--lx-stage-ink);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--tracking-tighter);
}
.lx-count-status { font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--lx-stage-ink); }
.lx-count-hint { font-size: var(--fs-xs); color: var(--lx-stage-ink-dim); }

.lx-count-cancel {
  border: 1px solid var(--slate-750);
  border-radius: var(--radius-full);
  padding: var(--space-1) var(--space-4);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--lx-stage-ink-dim);
  background: none;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard);
}
.lx-count-cancel:hover { color: var(--lx-stage-ink); border-color: var(--slate-600); }
.lx-count-cancel:active { color: var(--lx-stage-ink); border-color: var(--slate-500); }

/* --- the viewed burst --------------------------------------------------- */
.lx-burst {
  position: relative;
  display: grid;
  place-items: center;
  width: clamp(4.5rem, 9vw, 6rem);
  height: clamp(4.5rem, 9vw, 6rem);
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--green-500) 22%, transparent);
  color: var(--green-300);
  animation: lx-burst-in var(--dur-slow) var(--ease-spring) both;
}
.lx-burst::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid var(--green-400);
  animation: lx-burst-ring calc(var(--dur-slower) * 1.6) var(--ease-out) 1 both;
}
.lx-burst svg { width: 55%; height: 55%; }

@keyframes lx-burst-in {
  from { transform: scale(0.6); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
@keyframes lx-burst-ring {
  from { transform: scale(1); opacity: 0.9; }
  to   { transform: scale(1.65); opacity: 0; }
}

.lx-viewed-label svg { width: 1.25rem; height: 1.25rem; flex: 0 0 auto; }
.lx-viewed-label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  line-height: var(--lh-snug);
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  color: var(--green-300);
  letter-spacing: var(--tracking-tight);
}

/* --- linear timer bar --------------------------------------------------- */
.lx-linear {
  position: relative;
  height: 0.25rem;
  width: 100%;
  border-radius: var(--radius-full);
  background: var(--surface-3);
  overflow: hidden;
}
.lx-linear-fill {
  display: block;
  height: 100%;
  width: 0%;
  border-radius: inherit;
  background: var(--grad-brand);
}
.lx-linear-fill.is-complete { background: linear-gradient(135deg, var(--green-400), var(--green-600)); }

/* ==========================================================================
   6 · CONTROL BAR
   ========================================================================== */
.lx-controls {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

.lx-controls-row { display: flex; align-items: center; gap: var(--space-3); }

.lx-ctl {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: var(--control-h-sm);
  height: var(--control-h-sm);
  min-height: var(--control-h-sm);
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.lx-ctl svg { width: 1.05rem; height: 1.05rem; }
.lx-ctl:hover:not(:disabled) { background: var(--surface-3); color: var(--text); }
.lx-ctl:active:not(:disabled) { background: var(--surface-3); color: var(--text); }
.lx-ctl:focus-visible { outline: 2px solid var(--focus-ring-color); outline-offset: 2px; }
/* Inactive, not invisible. Transparency stacked on --text-muted took these
   glyphs under 3:1 in both themes; --text-subtle is the dimmest tier that
   still draws, and it says "off" just as clearly. */
.lx-ctl:disabled { color: var(--text-subtle); cursor: not-allowed; }

.lx-ctl-main { background: var(--surface-3); color: var(--text-muted); }
.lx-ctl-main:disabled { background: var(--surface-3); }

.lx-ctl-text {
  width: auto;
  padding-inline: var(--space-3);
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  border-color: var(--border);
}
.lx-ctl-text[aria-expanded="true"] { background: var(--surface-3); color: var(--text); }

.lx-time {
  flex: 0 0 auto;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  font-family: var(--font-mono);
}

.lx-seek { position: relative; flex: 1 1 auto; min-width: 2rem; display: flex; align-items: center; height: var(--control-h-sm); }
.lx-seek-track { position: relative; display: block; width: 100%; height: 0.25rem; border-radius: var(--radius-full); background: var(--surface-3); overflow: hidden; }
.lx-seek-fill { display: block; height: 100%; width: 0%; background: var(--border-strong); }
.lx-seek-knob {
  position: absolute;
  left: 0;
  width: 0.625rem;
  height: 0.625rem;
  border-radius: var(--radius-full);
  background: var(--border-strong);
  box-shadow: 0 0 0 3px var(--surface-2);
}

.lx-controls-right { flex: 0 0 auto; display: flex; align-items: center; gap: var(--space-1); }

.lx-vol { display: block; width: 3.25rem; height: 0.25rem; border-radius: var(--radius-full); background: var(--surface-3); overflow: hidden; }
.lx-vol-fill { display: block; height: 100%; width: 72%; background: var(--border-strong); }

.lx-speed { position: relative; }

.lx-controls-note { font-size: var(--fs-xs); color: var(--text-muted); line-height: var(--lh-base); }

/* ==========================================================================
   7 · UP NEXT
   ========================================================================== */
.lx-upnext {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--primary-border);
  background: var(--primary-soft);
  border-radius: var(--radius-lg);
}
.lx-upnext[hidden] { display: none; }
.lx-upnext-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.lx-upnext-label {
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--primary-soft-text);
  font-variant-numeric: tabular-nums;
}
.lx-upnext-title {
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lx-upnext-track { margin-top: var(--space-1); }

/* ==========================================================================
   8 · COURSE COMPLETION
   ========================================================================== */
.lx-done { display: flex; align-items: center; gap: var(--space-6); }
.lx-done[hidden] { display: none; }

.lx-done-art {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: var(--radius-xl);
  background: var(--surface);
  border: 1px solid var(--primary-border);
  color: var(--accent);
}
.lx-done-art > svg { width: 2.25rem; height: 2.25rem; }

.lx-done-spark {
  position: absolute;
  width: 0.375rem;
  height: 0.375rem;
  border-radius: var(--radius-full);
  background: var(--accent);
  opacity: 0;
  animation: lx-spark 2.4s var(--ease-out) infinite;
}
.lx-done-spark-1 { top: -0.25rem; left: 18%; animation-delay: 0s; }
.lx-done-spark-2 { top: 30%; right: -0.35rem; animation-delay: 0.6s; background: var(--primary); }
.lx-done-spark-3 { bottom: -0.2rem; left: 62%; animation-delay: 1.2s; }

@keyframes lx-spark {
  0%   { opacity: 0; transform: translateY(4px) scale(0.5); }
  25%  { opacity: 1; transform: translateY(-2px) scale(1); }
  60%  { opacity: 0; transform: translateY(-9px) scale(0.6); }
  100% { opacity: 0; }
}

.lx-done-body { min-width: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.lx-done-title { font-size: var(--fs-2xl); font-weight: var(--fw-extrabold); letter-spacing: var(--tracking-tight); }
.lx-done-text { color: var(--text-muted); max-width: 56ch; line-height: var(--lh-base); }
.lx-done-serial { font-size: var(--fs-sm); color: var(--text-muted); }
.lx-done-serial:empty { display: none; }
.lx-done-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-1); }

/* ==========================================================================
   9 · PREV / NEXT
   ========================================================================== */
.lx-nav { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }

.lx-nav-btn {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: var(--control-h-lg);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard);
}
.lx-nav-btn:hover:not(:disabled) { border-color: var(--primary-border); background: var(--surface-2); }
.lx-nav-btn:active:not(:disabled) { transform: translateY(1px); }
.lx-nav-btn:focus-visible { outline: 2px solid var(--focus-ring-color); outline-offset: 2px; }
/* At the first and last lecture these buttons still carry the only wording
   that explains why they are dead ("You are at the first lecture"), so the
   disabled look is built from flatter surfaces rather than from opacity —
   half-opacity took the label to 2.2:1 in light and 2.9:1 in dark. */
.lx-nav-btn:disabled {
  cursor: not-allowed;
  background: var(--surface-2);
  border-color: var(--border-subtle);
  box-shadow: none;
}
.lx-nav-btn:disabled .lx-nav-title { color: var(--text-muted); font-weight: var(--fw-medium); }
.lx-nav-btn:disabled .lx-nav-icon { color: var(--text-subtle); }

.lx-nav-next { justify-content: flex-end; text-align: right; }
.lx-nav-next .lx-nav-copy { align-items: flex-end; }

.lx-nav-icon { flex: 0 0 auto; display: grid; place-items: center; width: 1.25rem; height: 1.25rem; color: var(--text-subtle); }
.lx-nav-icon svg { width: 1.25rem; height: 1.25rem; }
.lx-nav-btn:hover:not(:disabled) .lx-nav-icon { color: var(--primary); }

.lx-nav-copy { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 0.1rem; }
.lx-nav-label {
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-muted);
}
.lx-nav-title {
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

/* ==========================================================================
   10 · TAB PANELS
   ========================================================================== */
.lx-tabs-wrap {
  position: relative;
  padding: var(--card-pad);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
}

/* On a narrow card the five tabs are wider than the strip, and the shared
   .tabs scroller hides its scrollbar, so Transcript and Discussion sit
   off-screen with nothing to say so. js/pages/learn.js adds
   .has-tab-overflow whenever there is more to the right, and this fades the
   cut edge to show it. */
.lx-tabs-wrap::before {
  content: "";
  position: absolute;
  top: var(--card-pad);
  right: 1px;
  width: var(--space-8);
  height: calc(var(--control-h) + var(--space-1));
  border-top-right-radius: var(--radius-xl);
  background: linear-gradient(90deg, transparent, var(--surface) 78%);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-standard);
}
.lx-tabs-wrap.has-tab-overflow::before { opacity: 1; }

.lx-panel-title { font-size: var(--fs-lg); font-weight: var(--fw-bold); letter-spacing: var(--tracking-tight); }

.lx-panel-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}
.lx-panel-main { min-width: 0; display: flex; flex-direction: column; gap: var(--space-5); }
.lx-panel-side {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--card-pad-tight);
  background: var(--surface-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

/* --- notes -------------------------------------------------------------- */
.lx-notes { display: flex; flex-direction: column; gap: var(--space-4); }
.lx-notes-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }

.lx-save {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  min-height: 1.25rem;
}
.lx-save.is-saved { color: var(--success-soft-text); }
.lx-save.is-saving { color: var(--text-muted); }
.lx-save svg { width: 1rem; height: 1rem; flex: 0 0 auto; }

.lx-note-input { min-height: 13rem; resize: vertical; line-height: var(--lh-base); }
.lx-notes-foot { display: flex; flex-wrap: wrap; gap: var(--space-3); justify-content: space-between; }

/* --- resources ---------------------------------------------------------- */
/* These four rows are the page's honest statement about what does not exist
   yet, so they have to be readable. components.css dims .resource.is-locked
   to 0.6 opacity, which put "Not available yet" at 2.5:1 dark / 2.6:1 light
   and faded the card borders away with it. Same message, rebuilt from tokens:
   a recessed surface and a dashed edge instead of transparency. */
.lx-resources .resource.is-locked {
  opacity: 1;
  background: var(--surface-2);
  border-style: dashed;
  box-shadow: none;
}
.lx-resources .resource.is-locked .resource-name { color: var(--text-muted); }
.lx-resources .resource.is-locked .resource-meta { color: var(--text-muted); }

/* The file-type chips set a full-strength status colour on its own soft tint,
   which lands at 2.1–2.9:1 for an 11px uppercase label. The *-soft-text tokens
   are the ones tuned to sit on those tints, in both themes. */
.lx-resources .resource-icon.is-pdf   { color: var(--danger-soft-text); }
.lx-resources .resource-icon.is-code  { color: var(--info-soft-text); }
.lx-resources .resource-icon.is-sheet { color: var(--success-soft-text); }
.lx-resources .resource-icon.is-note  { color: var(--warn-soft-text); }

/* --- transcript --------------------------------------------------------- */
.lx-transcript-empty {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  padding: var(--card-pad);
  background: var(--surface-2);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
}
.lx-transcript-lines { flex: 0 0 auto; display: flex; flex-direction: column; gap: var(--space-2); width: 7rem; }
.lx-transcript-lines span { display: block; height: 0.4rem; border-radius: var(--radius-full); background: var(--border); }
.lx-transcript-lines span:nth-child(2) { width: 80%; }
.lx-transcript-lines span:nth-child(3) { width: 92%; }
.lx-transcript-lines span:nth-child(4) { width: 64%; }
.lx-transcript-lines span:nth-child(5) { width: 86%; }
.lx-transcript-lines span:nth-child(6) { width: 45%; }

/* --- discussion --------------------------------------------------------- */
.lx-disc-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); }

.lx-thread { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-4); }
.lx-post { display: flex; gap: var(--space-3); }
.lx-post-reply { padding-left: var(--space-8); }
.lx-post-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--card-pad-tight);
  background: var(--surface-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  color: var(--text-muted);
  line-height: var(--lh-base);
}
.lx-post-reply .lx-post-body { background: var(--primary-soft); border-color: var(--primary-border); }
.lx-post-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.lx-post-name { font-size: var(--fs-md); font-weight: var(--fw-bold); color: var(--text); }
.lx-post-time { font-size: var(--fs-xs); color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* ==========================================================================
   11 · SHORTCUTS OVERLAY BODY (rendered into layout.js modal())
   ========================================================================== */
.lx-keys { display: flex; flex-direction: column; gap: var(--space-3); margin: 0; }
.lx-keys > div { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); }
.lx-keys dt { font-size: var(--fs-md); color: var(--text); }
.lx-keys dd { margin: 0; display: inline-flex; gap: var(--space-1); }

/* ==========================================================================
   11b · FIRST PAINT — the shape of the classroom, before learn.js fills it

   Everything below is authored into learn.html and then replaced wholesale
   by js/pages/learn.js on its first render, so no region of the page is ever
   an empty box while the syllabus is being built.
   ========================================================================== */
.lx-skeleton-mods { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-2); }
.lx-skeleton-mod {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
}
.lx-skeleton-mod > .skeleton-chip { width: 1.625rem; height: 1.625rem; border-radius: var(--radius-sm); flex: 0 0 auto; }
.lx-skeleton-mod > .skeleton-line-group { flex: 1; min-width: 0; }

.lx-skeleton-meta { display: flex; flex-wrap: wrap; gap: var(--space-3); }

/* The plate is dark in both themes, so the shimmer tokens would flash a pale
   block onto it. The stage waits with type and a spinner instead. */
.lx-stage-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  color: var(--lx-stage-ink-dim);
  font-size: var(--fs-sm);
}

/* ==========================================================================
   12 · RESPONSIVE
   ========================================================================== */
@media (max-width: 1180px) {
  .lx-panel-grid { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
}

@media (max-width: 1023px) {
  .lx-shell { grid-template-columns: minmax(0, 1fr); }
  .lx-modules-toggle { display: inline-flex; }

  .lx-sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: var(--z-drawer);
    width: min(22rem, 88vw);
    max-height: none;
    border-radius: 0;
    border-left: 0;
    border-top: 0;
    border-bottom: 0;
    box-shadow: var(--shadow-xl);
    transform: translateX(-100%);
    transition: transform var(--dur-base) var(--ease-out);
  }
  .lx-sidebar.is-open { transform: none; }

  .lx-sidebar-close { display: inline-grid; }

  .lx-sidebar-scrim {
    position: fixed;
    inset: 0;
    z-index: calc(var(--z-drawer) - 1);
    background: var(--overlay-scrim);
    opacity: 0;
    transition: opacity var(--dur-base) var(--ease-standard);
  }
  .lx-sidebar-scrim[hidden] { display: none; }
  .lx-sidebar-scrim.is-open { opacity: 1; }
}

@media (max-width: 900px) {
  .lx-bar-progress { min-width: 0; }
  .lx-bar-progress .progress { width: 5rem; }
  .lx-bar-course { display: none; }
  .lx-done { flex-direction: column; align-items: flex-start; gap: var(--space-4); }
}

@media (max-width: 720px) {
  .lx-back-text { display: none; }
  .lx-bar-pct { font-size: var(--fs-xs); }
  .lx-nav { grid-template-columns: minmax(0, 1fr); }
  .lx-tabs-wrap { padding: var(--card-pad-tight); }
  .lx-tabs-wrap::before { top: var(--card-pad-tight); }
  .lx-seek { display: none; }
  .lx-vol { display: none; }
  .lx-transcript-empty { flex-direction: column; align-items: flex-start; gap: var(--space-4); }
  .lx-post-reply { padding-left: var(--space-4); }
}

@media (max-width: 640px) {
  /* The plate stays 16:9, so the furniture inside it has to give way. */
  .lx-stage { min-height: 17rem; }
  .lx-stage-pos { display: none; }
  .lx-stage-brand svg { width: 1.15rem; height: 1.15rem; }
  .lx-stage-grid { gap: var(--space-2); }
  .lx-stage-action { gap: var(--space-2); }
  .lx-stage-action .lx-stage-caption { display: none; }
  .lx-count { gap: var(--space-2); }
  .lx-count-ring-wrap { width: clamp(2.75rem, 16vw, 4.25rem); height: clamp(2.75rem, 16vw, 4.25rem); }
  .lx-count-num { font-size: var(--fs-xl); }
  .lx-count-status { font-size: var(--fs-sm); }
  .lx-burst { width: 3rem; height: 3rem; }
  .lx-viewed-label { font-size: var(--fs-base); }
}

@media (max-width: 480px) {
  .lx-bar-progress .progress { display: none; }
  .lx-time { display: none; }
  .lx-controls-row { flex-wrap: wrap; }
}

/* ==========================================================================
   13 · REDUCED MOTION — the timing holds, the flourishes go
   base.css already neutralises transitions; these rules drop the decorative
   loops entirely so nothing keeps moving behind the countdown.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .lx-wave-layer { animation: none; }
  .lx-done-spark { display: none; }
  .lx-burst { animation: none; }
  .lx-burst::after { display: none; }
}

/* The same three rules as the media query above, for the in-app setting.
   base.css already collapses every animation to 0.001ms under this attribute;
   these drop the decorative loops outright so nothing is left mid-frame. */
:root[data-motion="reduced"] .lx-wave-layer { animation: none; }
:root[data-motion="reduced"] .lx-done-spark { display: none; }
:root[data-motion="reduced"] .lx-burst { animation: none; }
:root[data-motion="reduced"] .lx-burst::after { display: none; }

/* Module heading wrapper — keeps the disclosure inside a real <h3>. */
.lx-mod-heading { margin: 0; font-size: inherit; font-weight: inherit; letter-spacing: normal; }

/* ==========================================================================
   CONTRAST BRIDGE — shared components that still carry --text-subtle

   --text-subtle resolves to #7c8598 in the light theme: 3.71:1 on --surface
   and 3.27:1 on --surface-2, both under the 4.5:1 AA bar for body text (it
   also lands at 4.43:1 on --surface-2 in dark). Every rule THIS file owns
   already uses --text-muted; what remains are shared components from
   css/components.css, which this page may not edit. These overrides are
   scoped to #main so they can never reach the site header or footer that
   css/layout.css owns. Delete this block once --text-subtle is retuned to
   clear AA in css/tokens.css — nothing here changes the design intent, only
   the tier of grey that carries it.
   ========================================================================== */
#main .field-hint,
#main .field-optional,
#main .checkbox-hint,
#main .radio-hint,
#main .switch-hint,
#main .stat-hint,
#main .accordion-meta,
#main .range-scale,
#main .range-scale > * {
  color: var(--text-muted);
}

/* The same grey, reached by a few other routes on this page:
   .breadcrumb sets --text-subtle on the whole trail, so the crumbs that are
   plain <span> rather than <a> inherit it (3.49:1 light); .ring-text small is
   the "%" beside the syllabus ring (3.71:1 light); the two menu classes carry
   the playback-speed menu's tail figures and its footnote. */
#main .breadcrumb,
#main .ring-text small,
#main .menu-note,
#main .menu-item-tail,
#main .resource-meta {
  color: var(--text-muted);
}

/* A placeholder still has to read as a prompt rather than a value: --text-muted
   sits well clear of --text, so the two never look alike. */
#main .input::placeholder,
#main .textarea::placeholder,
#main textarea::placeholder,
#main input::placeholder {
  color: var(--text-muted);
  opacity: 1;
}

#main .lecture-time,
#main .code-lang,
#main .code-caption {
  color: var(--text-muted);
}

/* The reference snippet is prose too: --tok-punct lands at 2.92:1 on --code-bg
   in light and --tok-comment at 4.38:1 in dark, both short of AA. --text-muted
   clears AA in both themes and still reads a full tier quieter than --code-fg,
   which is the whole job these two colours do. Delete this pair once the two
   tokens are retuned in css/tokens.css. */
#main .code .tok-punc,
#main .code .tok-com {
  color: var(--text-muted);
}
