/* ============================================================
   Lectern — design system mirrored from wireframe
   tokens: paper / ink / ink-soft / ink-faint / rule / red / hl
   ============================================================ */

* { box-sizing: border-box; }
[hidden] { display: none !important; }

:root {
  --mono: "JetBrains Mono", "SF Mono", Menlo, monospace;
  --sans: "Inter", -apple-system, system-ui, sans-serif;
  --serif: "Newsreader", Georgia, "Times New Roman", serif;
}

/* Self-hosted webfonts — see static/fonts/ */
@font-face {
  font-family: "Inter";
  src: url("/static/fonts/Inter-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  src: url("/static/fonts/Newsreader-Variable.woff2") format("woff2");
  font-weight: 200 800;
  font-display: swap;
}
/* Fast-Font (Born2Root, MIT) — bionic-reading variants. Layered on top
   of the user's font choice when the 'bionic' toggle is on. */
@font-face {
  font-family: "Fast Sans";
  src: url("/static/fonts/Fast_Sans.ttf") format("truetype");
  font-display: swap;
}
@font-face {
  font-family: "Fast Serif";
  src: url("/static/fonts/Fast_Serif.ttf") format("truetype");
  font-display: swap;
}
@font-face {
  font-family: "Fast Mono";
  src: url("/static/fonts/Fast_Mono.ttf") format("truetype");
  font-display: swap;
}

/* ===== Themes =====
   All chrome colors live in body.theme-*. Switch via the Aa popover.
   Each theme defines: paper, paper-warm, ink, ink-soft, ink-faint, rule,
   rule-soft, hl, hl-soft, red, green, accent-link, shadow-hard.            */

body.theme-cream {
  --paper:       #fbfaf6;
  --paper-warm:  #f5f2eb;
  --ink:         #1a1a1a;
  --ink-soft:    #4a4a4a;
  --ink-faint:   #8a8a86;
  --rule:        #d9d4c7;
  --rule-soft:   #e7e2d4;
  --hl:          #ffe680;
  --hl-soft:     #fff4c2;
  --red:         #d24d3a;
  --green:       #2f8a4a;
  --accent-link: #2c5282;
  --shadow-hard: 4px 4px 0 #d9d4c7;
}

body.theme-gray {
  /* Cool, low-contrast: light gray paper + dark gray text */
  --paper:       #e9ebee;
  --paper-warm:  #dde0e4;
  --ink:         #2c2f33;
  --ink-soft:    #54585d;
  --ink-faint:   #8a8e94;
  --rule:        #c4c8cd;
  --rule-soft:   #d4d8dd;
  --hl:          rgba(255, 215, 0, 0.50);
  --hl-soft:     rgba(255, 215, 0, 0.18);
  --red:         #c8503a;
  --green:       #3a8a52;
  --accent-link: #2c5282;
  --shadow-hard: 4px 4px 0 #c4c8cd;
}

body.theme-white {
  /* Crisp, cool, max-contrast: pure white + pure black, faint cool hover */
  --paper:       #ffffff;
  --paper-warm:  #eef1f4;
  --ink:         #000000;
  --ink-soft:    #1a1a1a;
  --ink-faint:   #5a5e63;
  --rule:        #a8acb0;
  --rule-soft:   #d8dcdf;
  --hl:          rgba(255, 215, 0, 0.55);
  --hl-soft:     rgba(255, 215, 0, 0.20);
  --red:         #d01515;
  --green:       #1e7a3e;
  --accent-link: #0040a0;
  --shadow-hard: 4px 4px 0 #000000;
}

body.theme-rose {
  /* Dusty light pink paper, deep plum ink, purple cursor */
  --paper:       #f9e6e6;
  --paper-warm:  #f2d8d8;
  --ink:         #2a1820;
  --ink-soft:    #4a2f3a;
  --ink-faint:   #8a7078;
  --rule:        #d8b8b8;
  --rule-soft:   #e8cccc;
  --hl:          rgba(140, 77, 200, 0.40);
  --hl-soft:     rgba(140, 77, 200, 0.15);
  --red:         #a8262a;
  --green:       #2f7a48;
  --accent-link: #6a3aa0;
  --shadow-hard: 4px 4px 0 #2a1820;
}

body.theme-slate {
  /* Deeper cold gray: blue-leaning paper + cool dark text */
  --paper:       #d6dade;
  --paper-warm:  #c6cbd1;
  --ink:         #1b1f25;
  --ink-soft:    #3c424c;
  --ink-faint:   #6b7280;
  --rule:        #a8aeb5;
  --rule-soft:   #bcc1c7;
  --hl:          rgba(255, 215, 0, 0.55);
  --hl-soft:     rgba(255, 215, 0, 0.20);
  --red:         #b03830;
  --green:       #2f7a48;
  --accent-link: #1f3d80;
  --shadow-hard: 4px 4px 0 #a8aeb5;
}

body.theme-dark {
  --paper:       #1f1d1a;
  --paper-warm:  #2a2826;
  --ink:         #f6f1e4;
  --ink-soft:    #c8c4ba;
  --ink-faint:   #888880;
  --rule:        #3a3834;
  --rule-soft:   #2a2826;
  /* Warm amber on dark — coherent with cream-on-warm palette.
     Force dark text on the highlighted word so it stays readable. */
  --hl:          #d99d44;
  --hl-soft:     rgba(217, 157, 68, 0.20);
  --hl-ink:      #1a1a1a;
  --red:         #ff7a5f;
  --green:       #6dc97f;
  --accent-link: #6ea8e0;
  --shadow-hard: 4px 4px 0 #0a0907;
}

body.theme-oled {
  --paper:       #000000;
  --paper-warm:  #0a0a0a;
  --ink:         #e8e8e8;
  --ink-soft:    #b0b0b0;
  --ink-faint:   #707070;
  --rule:        #2a2a2a;
  --rule-soft:   #1a1a1a;
  --hl:          #d99d44;
  --hl-soft:     rgba(217, 157, 68, 0.22);
  --hl-ink:      #000000;
  --red:         #ff7a5f;
  --green:       #6dc97f;
  --accent-link: #6ea8e0;
  --shadow-hard: 4px 4px 0 #1a1a1a;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
}

/* ============================================================
   GENERIC WIREFRAME PRIMITIVES — copied from the design spec
   ============================================================ */
.pill, .btn, .chip {
  border: 1.25px solid var(--ink);
  background: var(--paper);
  font: 500 11.5px/1 var(--mono);
  color: var(--ink);
  display: inline-flex; align-items: center; gap: 6px;
  white-space: nowrap;
}
.pill { border-radius: 999px; padding: 7px 12px; cursor: pointer; }
.btn  { border-radius: 4px;   padding: 8px 12px;  cursor: pointer; }
.chip { border-radius: 3px;   padding: 4px 7px; font-size: 11px; }
.btn-primary  { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.btn-primary:hover { background: var(--ink-soft); border-color: var(--ink-soft); }
.pill:hover { background: var(--paper-warm); }
.pill:active, .btn:active { transform: translateY(1px); }

/* Filled-black inversion for chips (used for "selected" Aa chips) */
.chip.filled { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* Mode badge moved to the statusline. See `#statusline .sl-mode[data-mode=…]`
   at the bottom of this file. */

.lbl {
  font: 600 10px/1 var(--mono);
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-faint);
  user-select: none;
}
.mono { font-family: var(--mono); font-size: 11.5px; color: var(--ink); }
.faint { color: var(--ink-faint); }
.dim   { color: var(--ink-faint); }

.row       { display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.row-tight { gap: 6px; }

/* Circle (used for play, avatar, "?" button) */
.circle {
  width: 22px; height: 22px; border-radius: 50%; border: 1.25px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  font-family: var(--mono);
}
.circle-lg { width: 30px; height: 30px; }
.circle-xl { width: 44px; height: 44px; }
.circle.filled { background: var(--ink); color: var(--paper); }

/* Scrub bar (used for volume + stepped speed/gap sliders). */
.scrub {
  position: relative; height: 6px; background: var(--rule-soft);
  border-radius: 3px; border: 1px solid var(--ink);
  cursor: pointer;
  overflow: hidden;  /* clip the fill to the rounded shape */
}
.scrub > .fill {
  position: absolute; left: 0; top: -1px; bottom: -1px;
  background: var(--ink); border-radius: 3px 0 0 3px;
}
/* Stepped slider variant (SPD, GAP) — slightly wider track. */
.scrub.stepper { width: 70px; }

/* SVG chevron — drawn as a CSS mask so its color follows currentColor
   (= --ink), making it themeable. Stroked SVG in the mask paints alpha. */
.chev {
  width: 9px; height: 6px; flex-shrink: 0;
  display: inline-block;
  margin-left: 2px;
  background-color: currentColor;
  -webkit-mask: center / 9px 6px no-repeat
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 6' fill='none'><path d='M1 1l3.5 4L8 1' stroke='black' stroke-width='1.25' stroke-linecap='round'/></svg>");
          mask: center / 9px 6px no-repeat
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 6' fill='none'><path d='M1 1l3.5 4L8 1' stroke='black' stroke-width='1.25' stroke-linecap='round'/></svg>");
}

/* ============================================================
   HEADER (3-row sticky strip)
   ============================================================ */
#topbar {
  position: sticky; top: 0;
  background: var(--paper);
  border-bottom: 1.25px solid var(--ink);
  font-family: var(--mono);
  z-index: 100;
  padding: 14px 20px 12px;
  display: flex; flex-direction: column;
  gap: 0;
}

.hdr-row {
  display: flex; align-items: center;
  gap: 10px;
}
#hdr-row1 { justify-content: space-between; margin-bottom: 22px; flex-wrap: nowrap; }
#hdr-row2 { margin-bottom: 4px; }
#hdr-row3 { margin-top: 12px; justify-content: space-between; padding-top: 12px; border-top: 1px solid var(--rule); }

.hdr-left  { display: flex; align-items: center; gap: 10px; min-width: 0; flex-wrap: nowrap; overflow: hidden; }
.hdr-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; flex-wrap: nowrap; }

/* View-mode toggle: hide review-only chrome when on library */
body.view-library [data-only="review"] { display: none !important; }
body.view-library #hdr-row1 { margin-bottom: 0; }

/* Brand — `:lectern` wordmark. Colon is brand orange (#c45a2a), the
   brand's only color and the same hue across every app theme. Word is
   ink so it inherits theme contrast on dark themes. JetBrains Mono 600,
   tracking -0.01em per the brand spec. */
#home-link {
  text-decoration: none; color: var(--ink);
  display: inline-flex; align-items: baseline; gap: 6px;
  flex-shrink: 0;
  padding: 3px 4px;
  border-radius: 3px;
  margin-left: -4px;
  transition: background-color 0.1s;
}
#home-link:hover { background: var(--paper-warm); }
body.view-library #home-link:hover { background: transparent; cursor: default; }
.brand-mark {
  font: 600 12px/1 var(--mono);
  letter-spacing: -0.01em;
  color: var(--ink);
}
.brand-colon { color: #c45a2a; }

.hdr-sep {
  color: var(--ink-faint);
  font-family: var(--mono); font-size: 11.5px;
  opacity: 0.55; user-select: none;
}

#lecture-title {
  font-family: var(--mono); font-size: 11.5px;
  color: var(--ink-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-width: 0;
}

#status { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); }

/* (Save state moved to the statusline's sl-dirty segment; .save-state styles
   removed.) */

/* Viewing-other-user pill */
#viewing {
  font-family: var(--mono); font-size: 10.5px;
  padding: 3px 7px;
  border-radius: 3px;
  /* Theme-derived (was hardcoded blue → wrong on dark/oled — L10). */
  background: color-mix(in srgb, var(--accent-link) 15%, transparent);
  color: var(--accent-link);
  border: 1px solid color-mix(in srgb, var(--accent-link) 35%, transparent);
}
#viewing:empty { display: none; }

/* Make chips use the spec class */
#chip-cursor { cursor: pointer; }
#chip-cursor:hover { background: var(--paper-warm); }

/* ============================================================
   TRANSPORT (Row 2) — waveform centerpiece
   ============================================================ */
.waveform-host {
  flex: 1; min-width: 0;
  position: relative;
  height: 48px;
  display: flex; align-items: center;
}
#waveform {
  flex: 1; min-width: 0;
  width: 100%; height: 100%;
  cursor: pointer;
  display: block;
}
.waveform-host[data-mode="native"]   #waveform { display: none; }
.waveform-host[data-mode="native"]   #audio    { display: block; }
.waveform-host[data-mode="waveform"] #audio    { display: none; }
.waveform-host[data-mode="loading"]  #audio    { display: none; }
.waveform-host[data-mode="loading"]  #waveform::before {
  content: "loading…"; color: var(--ink-faint); font: 500 10px/48px var(--mono);
  padding: 0 12px;
}
.waveform-host[data-mode="decoding"] #waveform::before {
  content: "decoding (first time only)…"; color: var(--ink-faint); font: 500 10px/48px var(--mono);
  padding: 0 12px;
}
/* During loading/decoding, hide wavesurfer's inner canvas + cursor and my time pill */
.waveform-host[data-mode="loading"]  #waveform > *,
.waveform-host[data-mode="decoding"] #waveform > *,
.waveform-host[data-mode="loading"]  .wave-time-pill,
.waveform-host[data-mode="decoding"] .wave-time-pill {
  display: none !important;
}
#audio { flex: 1; min-width: 0; height: 36px; }

/* Floating red time text over playhead — plain text, no background */
.wave-time-pill {
  position: absolute;
  top: -16px;
  font: 600 10.5px/1 var(--mono);
  color: var(--red);
  transform: translateX(-50%);
  white-space: nowrap;
  pointer-events: none;
  z-index: 2;
  font-variant-numeric: tabular-nums;
}

#chip-audio-dur { color: var(--ink-faint); font-family: var(--mono); font-size: 11px; }
.transport-dur { font-size: 11px; flex-shrink: 0; }

/* Play button — circle XL with triangle (the triangle is a CSS-drawn glyph) */
#btn-play.circle-xl {
  cursor: pointer;
  transition: transform 0.05s, opacity 0.15s;
  font-family: inherit;
}
#btn-play.circle-xl:hover { background: var(--paper-warm); }
#btn-play.circle-xl:active { transform: translateY(1px); }
/* Disabled while waveform is still decoding — prevents the wrong-lecture-
   plays race during the seconds-long first-load decode window. */
#btn-play.circle-xl:disabled,
#btn-play.circle-xl.is-loading {
  opacity: 0.35;
  cursor: progress;
}
#btn-play.circle-xl:disabled:hover,
#btn-play.circle-xl.is-loading:hover { background: transparent; }
#btn-play.circle-xl:disabled:active,
#btn-play.circle-xl.is-loading:active { transform: none; }

/* ============================================================
   VOLUME (row 3) — custom .scrub, not native range
   ============================================================ */
.vol-icon {
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; user-select: none;
}
#volume-scrub {
  width: 60px;
}
#volume-scrub > .fill { width: 100%; }

/* Row 3 controls: every direct flex child gets the same box height so their
   internal text/icons center on the same visual baseline. Without this, a
   short item (just an icon) centers its label higher than a tall item (a
   button with vertical padding), even with align-items: center on the row. */
#hdr-row3 .ctl-group > * { min-height: 28px; display: inline-flex; align-items: center; }

/* Hide the native range — kept in DOM for compatibility but invisible */
#volume[type="range"] { display: none; }

/* ============================================================
   SAVE BUTTON variant
   ============================================================ */
#btn-save-disk {
  font: 600 11px/1 var(--mono);
  padding: 5px 11px;
  letter-spacing: 0.04em;
}

/* DONE chip — reviewed/not-reviewed toggle. Outline by default;
   filled (warm green tint via theme accent) when state.done is true. */
#btn-done {
  font: 600 11px/1 var(--mono);
  padding: 5px 9px 5px 8px;
  letter-spacing: 0.04em;
  background: var(--paper);
  color: var(--ink-faint);
  border: 1.25px solid var(--rule);
  border-radius: 3px;
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 5px;
}
#btn-done .done-mark { opacity: 0.35; }
#btn-done:hover { color: var(--ink); border-color: var(--ink); }
#btn-done[aria-pressed="true"] {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
#btn-done[aria-pressed="true"] .done-mark { opacity: 1; }
#btn-save-disk.dirty {
  animation: pulse-dirty 1.6s ease-in-out infinite;
}
@keyframes pulse-dirty {
  0%,100% { box-shadow: 0 0 0 0 rgba(210,77,58,0); }
  50%     { box-shadow: 0 0 0 4px rgba(210,77,58,0.22); }
}

/* ============================================================
   AVATAR (Row 1 right) — circle 30px white + ink border
   ============================================================ */
.hdr-avatar {
  position: relative;
  display: inline-flex; align-items: center;
  margin-left: 4px; padding-left: 8px;
  border-left: 1px solid var(--rule);
}
.avatar-circle {
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 1.25px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  font: 600 12px/1 var(--mono);
  text-transform: uppercase;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  transition: transform 0.1s;
}
.avatar-circle:hover { background: var(--paper-warm); }

/* Avatar dropdown menu (right-aligned) */
.user-menu {
  position: absolute;
  top: calc(100% + 6px); right: 0; left: auto;
  background: var(--paper);
  border: 1.25px solid var(--ink);
  border-radius: 4px;
  box-shadow: var(--shadow-hard);
  min-width: 10em;
  padding: 4px 0;
  z-index: 150;
  font-family: var(--mono);
}
.user-name {
  padding: 7px 12px 5px;
  font-size: 10px;
  color: var(--ink-faint);
  border-bottom: 1px solid var(--rule);
  margin-bottom: 4px;
  white-space: nowrap;
}
.user-menu-section {
  padding: 6px 12px 8px;
  border-bottom: 1px solid var(--rule);
}
.user-menu-label {
  font: 600 9px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 6px;
}
.theme-swatches { display: flex; gap: 5px; }
.theme-swatch {
  width: 18px; height: 18px;
  border: 1.25px solid var(--ink);
  border-radius: 3px;
  cursor: pointer;
  padding: 0;
  background: var(--paper);
  position: relative;
  flex-shrink: 0;
  transition: transform 0.08s;
}
.theme-swatch:hover { transform: scale(1.12); }
.theme-swatch.selected {
  outline: 1.25px solid var(--ink);
  outline-offset: 2px;
}
/* Fixed swatch colors regardless of current theme */
.theme-swatch[data-theme="cream"] { background: #fbfaf6; }
.theme-swatch[data-theme="gray"]  { background: #e9ebee; }
.theme-swatch[data-theme="slate"] { background: #d6dade; }
.theme-swatch[data-theme="white"] { background: #ffffff; }
.theme-swatch[data-theme="rose"]  { background: #f9e6e6; }
.theme-swatch[data-theme="dark"]  { background: #1f1d1a; }
.theme-swatch[data-theme="oled"]  { background: #000000; }

.user-logout {
  display: block;
  padding: 7px 12px;
  font-size: 11px;
  color: var(--ink);
  text-decoration: none;
}
.user-logout:hover { background: var(--paper-warm); }

/* ============================================================
   ROW 3 — inline label + value + chevron (no borders)
   ============================================================ */
.ctl-inline {
  display: inline-flex; align-items: center; gap: 6px;
  cursor: pointer;
  padding: 4px 0;
  position: relative;
  background: transparent;
  border: none;
  font: inherit;
  color: inherit;
}
.ctl-inline:hover .ctl-val,
.ctl-inline:hover .chev { opacity: 1; }
.ctl-val { font: 500 11.5px/1 var(--mono); color: var(--ink); transition: opacity 0.1s; }

.ctl-group { display: inline-flex; align-items: center; gap: 14px; }

/* "out TXT · DOCX" — clickable mono spans, no borders */
.ctl-clickmono {
  font: 500 11.5px/1 var(--mono);
  color: var(--ink);
  cursor: pointer;
  background: none; border: none; padding: 2px 0;
}
.ctl-clickmono:hover { text-decoration: underline; text-underline-offset: 3px; }

/* Aa trigger: borderless to match SPD/GAP/VOL on the left side. When the
   popover is open, the Aa label inverts (filled ink) as a "this is active"
   cue — same convention chips use elsewhere. */
#btn-aa {
  font: 600 13px/1 -apple-system, system-ui, "Inter", sans-serif;
}
#btn-aa[aria-expanded="true"] .ctl-val {
  background: var(--ink); color: var(--paper);
  padding: 2px 6px; border-radius: 3px;
}
/* .chev follows currentColor, so opening Aa (which flips color to --paper)
   already inverts the chevron. No filter needed. */

/* Help button now uses the .ctl-inline label+value rhythm — no extra
   styling needed beyond a clickable inline-flex of label + value. */

/* ============================================================
   Aa POPOVER (anchored under #btn-aa, brutalist drop shadow)
   ============================================================ */
.popover {
  position: fixed;
  width: 244px;
  background: var(--paper);
  border: 1.5px solid var(--ink);
  border-radius: 6px;
  box-shadow: var(--shadow-hard);
  padding: 10px 12px;
  z-index: 150;
  font-family: var(--mono);
}
.popover-notch {
  position: absolute; top: -7px;
  width: 12px; height: 12px;
  background: var(--paper);
  border-top: 1.5px solid var(--ink);
  border-left: 1.5px solid var(--ink);
  transform: rotate(45deg);
}
.popover-header {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 8px;
}
.popover-header .lbl { color: var(--ink-faint); }
.popover-header .faint { font: 500 9.5px/1 var(--mono); color: var(--ink-faint); }

.popover-row {
  display: flex; justify-content: space-between; align-items: center;
  gap: 8px;
  padding: 3px 0;
}
.popover-label {
  font: 500 10.5px/1 var(--mono);
  color: var(--ink-faint);
  flex-shrink: 0;
}

/* Segmented control = row of .chip (each chip is a button) */
.seg { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; justify-content: flex-end; }
.seg button.chip {
  border: 1.25px solid var(--ink);
  background: var(--paper);
  font: 500 10.5px/1 var(--mono);
  color: var(--ink);
  cursor: pointer;
  padding: 3px 6px; border-radius: 3px;
}
.seg button.chip:hover { background: var(--paper-warm); }
.seg button.chip.selected,
.popover-row > button.chip[aria-pressed="true"] {
  background: var(--ink); color: var(--paper); border-color: var(--ink);
}
/* Chip disabled state — used by the bold-cursor gate (lines or mono only). */
.chip[aria-disabled="true"] {
  opacity: 0.35;
  cursor: not-allowed;
}
.chip[aria-disabled="true"]:hover { background: var(--paper); }
/* Standalone .chip in a popover-row (e.g. the bionic toggle) needs the
   same metrics as the in-.seg chips so it sits at the same baseline. */
.popover-row > button.chip {
  cursor: pointer;
  font: 500 10.5px/1 var(--mono);
  padding: 3px 6px;
  border-radius: 3px;
}
.popover-row > button.chip:hover { background: var(--paper-warm); }
/* When pressed, hover should DARKEN, not lighten — otherwise the
   light :hover bg lands behind the pressed state's light text color
   (=paper) and the label disappears into the background. */
.popover-row > button.chip[aria-pressed="true"]:hover { background: var(--ink-soft); }

/* Reflow row in popover — inline-num input */
.popover-row input.num {
  font: 500 10.5px/1 var(--mono);
  width: 3em;
  text-align: center;
  border: 1.25px solid var(--ink);
  border-radius: 3px;
  padding: 4px 4px;
  background: var(--paper);
}

/* ============================================================
   DROPDOWN MENU (speed selector)
   ============================================================ */
.dropdown { position: relative; display: inline-block; }
.dropdown-menu {
  position: absolute;
  top: calc(100% + 6px); left: 0;
  background: var(--paper);
  border: 1.25px solid var(--ink);
  border-radius: 4px;
  box-shadow: var(--shadow-hard);
  z-index: 150;
  min-width: 5em;
  padding: 4px 0;
  font-family: var(--mono);
}
/* Speech-cloud notch above the menu, matching the Aa popover. */
.dropdown-menu::before {
  content: "";
  position: absolute; top: -7px; left: 14px;
  width: 12px; height: 12px;
  background: var(--paper);
  border-top: 1.25px solid var(--ink);
  border-left: 1.25px solid var(--ink);
  transform: rotate(45deg);
}
.dropdown-menu button {
  display: block; width: 100%;
  padding: 6px 14px;
  background: var(--paper);
  border: none;
  font: 500 11px/1 var(--mono);
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}
.dropdown-menu button:hover { background: var(--paper-warm); }
.dropdown-menu button.selected { background: var(--ink); color: var(--paper); }
/* Caption row at the top of a dropdown menu — used to explain what the
   selectable values do (e.g. the gap menu). Wraps so the menu can stay narrow. */
.dropdown-menu .menu-caption {
  padding: 6px 14px 8px;
  font: 400 10px/1.35 var(--mono);
  color: var(--ink-faint);
  border-bottom: 1px solid var(--rule-soft);
  margin-bottom: 4px;
  max-width: 22ch;
  white-space: normal;
}

/* ============================================================
   HELP MODAL (centered, dim backdrop, brutalist black shadow)
   ============================================================ */
#help-overlay {
  position: fixed; inset: 0;
  background: rgba(26,26,26,0.30);
  display: flex; align-items: center; justify-content: center;
  z-index: 200;
}

/* Generic in-app modal (new-project, future dialogs) — replaces native
   prompt/alert with theme-styled chrome matching the help overlay. */
.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(26,26,26,0.30);
  display: flex; align-items: center; justify-content: center;
  z-index: 210;
}
.modal-card {
  background: var(--paper);
  width: 92%; max-width: 380px;
  padding: 18px 20px 16px;
  border: 1.5px solid var(--ink);
  border-radius: 6px;
  box-shadow: 6px 6px 0 var(--ink);
  font-family: var(--mono);
}
.modal-title { font: 700 14px/1 var(--mono); color: var(--ink); margin-bottom: 14px; }
.modal-label {
  display: block; font: 600 9.5px/1 var(--mono);
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-faint); margin: 12px 0 5px;
}
.modal-input {
  width: 100%; font: 500 13px/1 var(--mono);
  padding: 9px 11px; background: var(--paper);
  border: 1.25px solid var(--ink); border-radius: 4px; color: var(--ink);
}
.modal-input:focus { outline: 2px solid var(--accent-link); outline-offset: 1px; }
.modal-seg { display: inline-flex; gap: 6px; }
.modal-seg .chip { cursor: pointer; }
.modal-seg .chip.selected { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.modal-err {
  font: 500 11px/1.3 var(--mono); color: var(--red);
  margin-top: 10px;
}
.modal-actions {
  display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px;
}
#help-box {
  background: var(--paper);
  max-width: 780px;
  width: 92%;
  max-height: 85vh;
  overflow-y: auto;
  padding: 0;
  border: 1.5px solid var(--ink);
  border-radius: 6px;
  box-shadow: 6px 6px 0 var(--ink);
  font-family: var(--mono);
}
.help-titlebar {
  display: flex; justify-content: space-between; align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--rule);
}
.help-title    { font: 700 12px/1 var(--mono); color: var(--ink); }
.help-titlebar .dim { font: 500 10.5px/1 var(--mono); color: var(--ink-faint); }

/* Vim / basic cheatsheet toggle. Segmented pill — selected button fills
   with ink. Behavior-only: persists in localStorage, doesn't change
   keymap (both fire at all times). */
.help-variant-toggle {
  display: inline-flex;
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
}
.help-variant-btn {
  font: 600 10.5px/1 var(--mono);
  letter-spacing: 0.06em;
  padding: 4px 10px;
  background: var(--paper);
  color: var(--ink-faint);
  border: 0;
  cursor: pointer;
}
.help-variant-btn + .help-variant-btn { border-left: 1px solid var(--rule); }
.help-variant-btn:hover { color: var(--ink); }
.help-variant-btn[aria-selected="true"] {
  background: var(--ink);
  color: var(--paper);
}

.help-body { padding: 12px 14px; }
.help-intro {
  background: var(--paper-warm);
  padding: 10px 14px;
  border-radius: 4px;
  margin-bottom: 12px;
  font-family: var(--mono);
}
/* Definition-list rhythm: term on the left, explanation on the right.
   Mono throughout to match the grid below; reads as a structured key/value
   block instead of the previous wall of paragraphs. */
.help-concept {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 6px 14px;
  margin: 0;
  font-size: 11px;
  line-height: 1.5;
}
.help-concept dt {
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
}
.help-concept dd { margin: 0; color: var(--ink); }
.help-concept .hl-demo {
  background: var(--hl);
  color: var(--hl-ink, var(--ink));
  padding: 0 0.4em;
  border-radius: 3px;
  font-weight: 600;
}
.help-concept .hl-mode {
  background: var(--paper);
  border: 1.25px solid var(--ink);
  padding: 0 5px;
  border-radius: 3px;
  font-weight: 600;
  letter-spacing: 0.05em;
}

.help-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 14px 20px;
}
.help-col { display: flex; flex-direction: column; gap: 14px; }
.help-group { display: flex; flex-direction: column; gap: 2px; }
.help-group-title {
  font: 600 9.5px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 4px;
}
.help-cmd {
  display: flex; justify-content: space-between; align-items: center;
  gap: 10px;
  padding: 3px 0;
}
.help-desc { font: 500 11px/1 var(--mono); color: var(--ink); flex: 1; min-width: 0; }
.help-key {
  border: 1.25px solid var(--ink);
  background: var(--paper);
  border-radius: 3px;
  padding: 2px 7px;
  min-width: 30px;
  font: 600 10.5px/1 var(--mono);
  color: var(--ink);
  white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
kbd {
  font: 600 10.5px/1 var(--mono);
  background: var(--paper);
  border: 1.25px solid var(--ink);
  border-radius: 3px;
  padding: 2px 6px;
  color: var(--ink);
  box-shadow: none;
}
.help-footer {
  padding: 8px 14px 12px;
  font: 500 10.5px/1.4 var(--mono);
  color: var(--ink-faint);
}

/* ============================================================
   MAIN VIEWS
   ============================================================ */
main { padding: 1em 2em; max-width: 84em; margin: 0 auto; }
.hidden { display: none !important; }

/* Library header ("Lectures" + search) */
.lib-header {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; margin: 0 0 14px;
}
#library h2, #vocab h2, #project-detail h2 {
  font: 700 18px/1 var(--mono);
  letter-spacing: 0.01em;
  margin: 0;
  color: var(--ink);
}

/* vocab link in the library header + the vocab view itself */
#lib-vocab-link {
  font: 600 11px/1 var(--mono);
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  text-decoration: none;
  padding: 4px 8px;
  border: 1px solid var(--rule);
  border-radius: 3px;
  margin-right: auto;   /* hug the h2, push search to the right */
}
#lib-vocab-link:hover { color: var(--ink); border-color: var(--ink); }
#vocab-export {
  font: 600 10.5px/1 var(--mono);
  letter-spacing: 0.06em;
  padding: 5px 10px;
  background: var(--paper);
  color: var(--ink);
  border: 1.25px solid var(--ink);
  border-radius: 3px;
  cursor: pointer;
}
#vocab-export:hover { background: var(--ink); color: var(--paper); }
.vocab-lecture {
  font: 600 12px/1 var(--mono);
  color: var(--ink-faint);
  margin: 1.6em 0 0.5em;
}
.vocab-row {
  display: flex; align-items: baseline; gap: 10px;
  padding: 7px 8px;
  border-radius: 4px;
}
.vocab-row:hover { background: var(--paper-warm); }
.vocab-ctx { flex: 1; cursor: pointer; line-height: 1.5; }
.vocab-word {
  text-decoration: underline dotted var(--green);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
.vocab-meta { font: 500 10.5px/1 var(--mono); color: var(--ink-faint); white-space: nowrap; }
.vocab-rm {
  font: 600 13px/1 var(--mono);
  background: none; border: 0; cursor: pointer;
  color: var(--ink-faint); padding: 2px 6px;
}
.vocab-rm:hover { color: var(--red); }
/* armed (two-click confirm) state for member removal */
.vocab-rm.armed {
  font: 600 9.5px/1 var(--mono); color: var(--paper); background: var(--red);
  border-radius: 3px; padding: 2px 5px;
}
.lib-search {
  position: relative;
  flex: 0 0 320px;
  max-width: 320px;
}
#lib-search-input {
  width: 100%;
  font: 500 12px/1 var(--mono);
  padding: 7px 28px 7px 10px;
  background: var(--paper);
  border: 1.25px solid var(--rule);
  border-radius: 4px;
  color: var(--ink);
  outline: none;
}
#lib-search-input:focus { border-color: var(--ink); }
#lib-search-input::placeholder { color: var(--ink-faint); }
#lib-search-clear {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 18px; height: 18px;
  background: transparent; border: 0; cursor: pointer;
  color: var(--ink-faint);
  font: 600 14px/1 var(--mono);
  display: flex; align-items: center; justify-content: center;
}
#lib-search-clear:hover { color: var(--ink); }

/* Search results panel — replaces the table when query is active */
#lib-search-results { font-family: var(--mono); }
#lib-search-results .sr-status {
  font: 500 11px/1.4 var(--mono);
  color: var(--ink-faint);
  padding: 4px 0 12px;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 8px;
}
#lib-search-results .sr-hit {
  padding: 14px 4px;
  border-bottom: 1px solid var(--rule);
}
#lib-search-results .sr-headline {
  display: flex; align-items: baseline; gap: 12px;
}
#lib-search-results .sr-title {
  font: 600 14px/1.3 var(--sans);
  color: var(--ink);
  text-decoration: none;
  flex: 1; min-width: 0;
}
#lib-search-results .sr-title:hover { text-decoration: underline; text-underline-offset: 3px; }
#lib-search-results .sr-count {
  font: 600 10px/1 var(--mono);
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--ink-faint);
  flex-shrink: 0;
}
#lib-search-results .sr-meta {
  font: 500 10px/1 var(--mono);
  color: var(--ink-faint);
  letter-spacing: 0.06em; text-transform: uppercase;
  margin-top: 4px;
}
#lib-search-results .sr-snippet {
  display: block;
  font: 400 13px/1.55 var(--serif);
  color: var(--ink-soft);
  margin-top: 6px;
  padding: 6px 8px;
  border-left: 2px solid var(--rule);
  cursor: pointer;
  text-decoration: none;
  border-radius: 0 3px 3px 0;
}
#lib-search-results .sr-snippet:hover {
  background: var(--paper-warm);
  border-left-color: var(--ink);
}
/* Snippet HTML wraps matches in <b>; style them with the cursor highlight. */
#lib-search-results .sr-snippet b {
  background: var(--hl);
  color: var(--hl-ink, inherit);
  padding: 0 0.15em;
  font-weight: inherit;
  border-radius: 2px;
}
/* Per-lecture "N more snippets" collapsed under top 3 */
#lib-search-results .sr-more {
  margin-top: 2px;
}
#lib-search-results .sr-more > summary {
  font: 600 10px/1 var(--mono);
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--ink-faint);
  padding: 8px 4px 6px;
  cursor: pointer;
  list-style: none;
}
#lib-search-results .sr-more > summary::-webkit-details-marker { display: none; }
#lib-search-results .sr-more > summary::before {
  content: "▸ ";
  display: inline-block;
  transition: transform 0.1s;
}
#lib-search-results .sr-more[open] > summary::before {
  transform: rotate(90deg);
}
#lib-search-results .sr-more > summary:hover { color: var(--ink); }

#lib-search-results .sr-empty {
  font: 500 12px/1.4 var(--mono);
  color: var(--ink-faint);
  padding: 24px 4px;
}

/* When search is showing results, hide the table */
#library.searching .lec-table { display: none; }

table.lec-table {
  width: 100%; border-collapse: collapse;
  font-family: var(--mono);
}
.lec-table th, .lec-table td {
  padding: 8px 10px;
  text-align: left;
  border-bottom: 1px solid var(--rule);
  vertical-align: baseline;
  font-size: 11.5px;
}
.lec-table thead th {
  font: 600 9.5px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  background: transparent;
  border-bottom: 1.25px solid var(--ink);
  padding-bottom: 8px;
}

/* Series divider row */
.lec-table tr.series-row th {
  background: transparent;
  font: 600 9.5px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  padding: 18px 10px 6px;
  border-bottom: 1px dashed var(--rule);
  text-align: left;
}

.lec-table tbody tr:not(.series-row):hover td { background: var(--paper-warm); }

.lec-table td.lec-title {
  font-family: var(--sans);
  font-size: 13px;
}
.lec-table td.lec-title a { color: var(--ink); text-decoration: none; }
.lec-table td.lec-title a:hover { text-decoration: underline; text-underline-offset: 3px; }
.lec-table .lec-ep {
  display: inline-block;
  font: 600 10px/1 var(--mono);
  color: var(--ink-faint);
  width: 1.8em;
  text-align: right;
  margin-right: 8px;
  letter-spacing: 0.05em;
}
.lec-table .lec-done {
  display: inline-block;
  font: 600 12px/1 var(--mono);
  color: var(--red);
  margin-right: 6px;
}

.lec-table td.num {
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  text-align: right;
  white-space: nowrap;
  width: 1%;     /* shrink-to-fit numeric columns */
}

.lec-table td.revs { font-size: 11px; }
.lec-table .rev {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 3px;
  background: var(--paper-warm);
  color: var(--ink-soft);
  margin-right: 4px;
}
.lec-table .rev.rev-me {
  background: var(--ink);
  color: var(--paper);
}
.lec-table .rev .rev-n {
  font-weight: 600;
  margin-left: 3px;
  opacity: 0.7;
}
.lec-table .rev.rev-me .rev-n { opacity: 0.85; }
.lec-table .dim { color: var(--ink-faint); }

/* ============================================================
   TRANSCRIPT BODY
   ============================================================ */
#words-container {
  /* Single source of truth for column geometry. --text-width is driven by
     applyTextWidth() and always means the prose column width. Structured
     layouts place their line-number gutter outside that column. */
  --gutter-track: 6em;
  --gutter-gap: 0.9em;
  --text-width: 100ch;
  margin: 1em auto 0;
  font-size: 1.05em;
  font-family: var(--serif);
  font-weight: 400;
  outline: none;
  max-width: var(--text-width);
  /* So absolutely-positioned probes in computeLineBreakChars() are sized
     against this container rather than the viewport. */
  position: relative;
}
#words-container.font-serif { font-family: var(--serif); }
#words-container.font-sans  { font-family: var(--sans); }
#words-container.font-mono  { font-family: var(--mono); }

/* User-controlled line spacing — drives line-height on the reading column
   only, so global UI line-heights stay untouched. */
body.leading-tight  #words-container { line-height: 1.4; }
body.leading-normal #words-container { line-height: 1.75; }
body.leading-airy   #words-container { line-height: 2.1; }

/* Bionic Reading: layered on top of the font choice. Swaps to the
   matching Fast-Font variant (Born2Root, MIT) which bakes the
   first-half-bolded look into the glyphs. */
#words-container.bionic.font-serif { font-family: "Fast Serif", var(--serif); }
#words-container.bionic.font-sans  { font-family: "Fast Sans",  var(--sans); }
#words-container.bionic.font-mono  { font-family: "Fast Mono",  var(--mono); }

.word {
  display: inline-block;
  padding: 0 0.15em;
  margin: 0 0.05em;
  border-radius: 3px;
  cursor: pointer;
  border: 1px solid transparent;
}
.word:hover    { background: var(--hl-soft); }
/* Cursor IS the playhead — one yellow box, not two indicators.
   --hl-ink lets dark themes force readable text on the bright highlight.
   No font-weight bump and no shadow: proportional fonts (serif/sans)
   would reflow each line on every step, and synthesized weight via
   text-shadow looks muddy. Pad + bg + radius alone carry the cursor. */
.word.cursor {
  background: var(--hl);
  color: var(--hl-ink, inherit);
  padding: 0.05em 0.3em;
  margin: 0 -0.1em;            /* counter the extra padding so layout doesn't reflow */
  border-radius: 4px;
}
/* Bold cursor — only applied when the body class is set. evalCursorBoldGate()
   in app.js only sets the class when reflow=lines OR font=mono, both of
   which are layout-stable for bolding. */
body.cursor-bold .word.cursor { font-weight: 700; }
.word.edited   { background: var(--hl-soft); border-color: var(--rule); }
.word.deleted  { text-decoration: line-through; opacity: 0.4; }
/* Solid red underline. Wavy fragmented around letter ink on cyrillic
   serifs (text-decoration-skip-ink kicks in per-glyph). Solid is more
   legible and renders consistently across all fonts. */
.word.uncertain {
  text-decoration: underline var(--red);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  text-decoration-skip-ink: none;
}
/* Vocab mark (learning mode) — dotted green, distinct from uncertain's
   solid red. Collected at /vocab; toggled with `v` in NORMAL. */
.word.vocab {
  text-decoration: underline dotted var(--green);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  text-decoration-skip-ink: none;
}
.word.editing  {
  background: var(--paper);
  color: var(--ink);   /* override .word.cursor's --hl-ink (dark) when editing on paper bg */
  border: 1px solid var(--ink-faint);
  outline: 2px solid var(--red);
}

/* Paragraph break markers — word-processor formatting-marks style.
   The blank gap line itself is the click target (remove break). ¶ sits
   in the left margin: faint for auto-gap breaks, red-tinted for manual
   marks. Spacing identical to the old marker-less gap (glyph is
   absolutely positioned, zero layout shift). */
.para-break { display: block; height: 0.5em; position: relative; cursor: pointer; }
.para-break .pilcrow {
  position: absolute; left: -1.25em; top: 50%; transform: translateY(-50%);
  font: 500 11px/1 var(--mono);
  /* Use --ink-soft at full opacity (was --ink-faint × 0.45 ≈ 2:1 contrast,
     below the WCAG 3:1 floor for UI affordances — M4). */
  color: var(--ink-soft);
  user-select: none;
}
.para-break.manual .pilcrow { color: var(--red); }
.para-break:hover { background: var(--hl-soft); }
.para-break:hover .pilcrow { color: var(--ink); }

/* ↵ sentence-break marker (sents mode) — end of each sentence line.
   Click merges the line with the next (sets a "join" override). */
.sent-break {
  font: 500 10px/1 var(--mono);
  color: var(--ink-soft);   /* was --ink-faint × 0.35 — failed contrast (M4) */
  margin-left: 7px;
  cursor: pointer;
  user-select: none;
}
.sent-break:hover { color: var(--red); }

/* Read mode — clean copyable prose. Inherits font family/size/weight
   from the same controls as the other modes (set on #words-container). */
#words-container.read .read-para {
  margin: 0 0 0.85em;
}
#words-container.read .read-heading {
  font-weight: 700;
  font-size: 1.05em;
  margin: 1.3em 0 0.55em;
}
#words-container.read .read-vocab {
  text-decoration: underline dotted var(--green);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  text-decoration-skip-ink: none;
}

/* Section heading — block-level break with a title. Renders before its
   section's first word in any mode. Mono caps-ish (no transform; we
   store as-typed), thin underline, § prefix glyph. Click to edit. */
.section-head {
  display: block;
  margin: 1.8em 0 0.6em;
  padding: 0 0 0.3em;
  font: 600 0.88em/1.25 var(--mono);
  letter-spacing: 0.03em;
  color: var(--ink);
  border-bottom: 1px solid var(--rule);
  cursor: pointer;
}
.section-head::before {
  content: "§  ";
  color: var(--ink-faint);
  font-weight: 500;
}
.section-head:hover { color: var(--ink-soft); }
.section-head input {
  width: 100%;
  font: inherit;
  color: inherit;
  background: transparent;
  border: 0;
  outline: 1.5px solid var(--ink);
  outline-offset: 1px;
  padding: 2px 4px;
  border-radius: 2px;
}
.section-head input::placeholder { color: var(--ink-faint); }

/* Reflow mode */
#words-container.reflow .line {
  display: flex; align-items: baseline; gap: var(--gutter-gap);
}
#words-container.reflow .line-no {
  font: 500 0.7em/1 var(--mono);
  color: var(--ink-faint);
  flex: 0 0 var(--gutter-track);
  width: var(--gutter-track);
  margin-left: calc(0px - var(--gutter-track) - var(--gutter-gap));
  text-align: right;
  user-select: none; opacity: 0.55; padding-top: 0.15em;
  font-variant-numeric: tabular-nums;
}
/* "off" hides the digits while the gutter remains outside the prose column. */
body.gutter-off   #words-container.reflow .line-no { visibility: hidden; }
#words-container.reflow .line-content { flex: 1 1 auto; min-width: 0; word-wrap: normal; overflow-wrap: normal; }
#words-container.reflow .line.para-break { height: 0.7em; }
/* Structured modes: park the ¶ in the line-number gutter instead of the
   prose column. */
#words-container.reflow .line.para-break .pilcrow {
  left: calc(4px - var(--gutter-track) - var(--gutter-gap));
}

/* Highlight the line that contains the cursor word (structured modes
   only — in flow there is no .line wrapper to paint). Faint paper-warm
   wash so it sits behind the cursor's brighter --hl without competing. */
#words-container.reflow .line.current {
  background: var(--paper-warm);
  border-radius: 4px;
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 1100px) {
  #hdr-row3 { flex-wrap: wrap; }
}
@media (max-width: 760px) {
  #topbar { padding: 10px 14px; }
  .hdr-avatar { margin-left: 0; padding-left: 4px; }
}

/* Phone (≤ 640px): read-only listening mode. JS gates editing; CSS
   tightens chrome, simplifies the library table, and lets row 2/3
   wrap aggressively. The cursor-tap-to-seek + follow-along audio
   experience stays — the goal is "still useful as a transcript player
   even when you can't edit." */
@media (max-width: 640px) {
  #topbar { padding: 8px 10px; }

  /* Header rows tighten + wrap */
  #hdr-row1 { flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
  #hdr-row2 { flex-wrap: wrap; gap: 6px; }
  #hdr-row3 { gap: 8px; padding-top: 8px; margin-top: 8px; }
  .ctl-group { gap: 8px; }
  .hdr-left  { gap: 6px; overflow: hidden; min-width: 0; }
  .hdr-right { gap: 6px; flex-wrap: wrap; }

  /* Waveform: smaller height to free vertical space */
  .waveform-host { height: 36px; }
  #btn-play.circle-xl { width: 36px; height: 36px; }

  /* Avatar slim */
  .avatar-circle { width: 26px; height: 26px; }
  .hdr-avatar { border-left: 0; padding-left: 0; }

  /* Keep the structured-mode gutter visible without letting it change the
     prose width relative to flow/read modes. */
  #words-container {
    --gutter-track: 3.25em;
    --gutter-gap: 0.55em;
    max-width: calc(100% - var(--gutter-track) - var(--gutter-gap));
    margin-left: calc(var(--gutter-track) + var(--gutter-gap));
    margin-right: 0;
    font-size: 1em;
    line-height: 1.7;
  }

  /* Hide editing-only chrome — save button + OUT exports cluster.
     Tap-to-seek still works; follow-along still works. */
  body.phone #btn-save-disk,
  body.phone #btn-done,
  body.phone .ctl-inline[style*="cursor:default"] {
    display: none;
  }

  /* Library table: keep title + duration, hide derived numeric columns. */
  .lec-table thead th:nth-child(2),
  .lec-table thead th:nth-child(3),
  .lec-table thead th:nth-child(4),
  .lec-table tbody td:nth-child(2),
  .lec-table tbody td:nth-child(3),
  .lec-table tbody td:nth-child(4) {
    display: none;
  }
  .lec-table td.lec-title { font-size: 14px; }
  .lec-table td, .lec-table th { padding: 10px 6px; }

  /* Login fits naturally; just make the card breathe at small widths */
  .login-card { width: auto; max-width: 320px; margin: 0 12px; }
}

/* ============================================================
   STATUSLINE — vim-style strip at the bottom of the viewport.
   Renders mode (left), cursor pos + audio time (right), and a
   dirty indicator (far right). See statusline.js + the
   2026-05-25 spec for behavior.
   ============================================================ */
#statusline {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 26px;
  padding: 0 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--ink);
  color: var(--paper);
  font: 600 11px/1 var(--mono);
  letter-spacing: 0.05em;
  z-index: 100;
  user-select: none;
}
.sl-spacer { flex: 1; }
.sl-mode {
  padding: 4px 10px;
  border-radius: 2px;
  letter-spacing: 0.1em;
  cursor: pointer;
}
.sl-mode[data-mode="normal"] {
  background: transparent;
  color: var(--paper);
  opacity: 0.85;
}
.sl-mode[data-mode="normal"]:hover { opacity: 1; }
.sl-mode[data-mode="insert"] {
  background: var(--hl);
  color: var(--hl-ink, var(--ink));
}
.sl-mode[data-mode="editing"] {
  background: var(--red);
  color: var(--paper);
  cursor: default;
}
.sl-segment {
  color: var(--paper);
  opacity: 0.85;
  cursor: pointer;
}
.sl-segment:hover { opacity: 1; }
.sl-sep {
  color: var(--paper);
  opacity: 0.45;
  cursor: default;
}
.sl-dirty {
  font-size: 14px;
  line-height: 1;
  min-width: 16px;
  text-align: center;
}
.sl-dirty.is-dirty { color: var(--hl); opacity: 1; }

/* Reserve space at the bottom of the page so the last lines of the
   transcript aren't covered by the fixed statusline. */
body:has(#statusline:not([hidden])) { padding-bottom: 32px; }

/* Phones: statusline is hidden (read-only listening mode doesn't need it). */
@media (max-width: 640px) {
  #statusline { display: none; }
  body:has(#statusline) { padding-bottom: 0; }
}

/* Splash overlay — first paint covers the page so the user sees the
   wordmark, not the half-bootstrapped chrome. Hidden by app.js after
   bootstrapMe() resolves (single /api/me roundtrip). */
#splash {
  position: fixed; inset: 0;
  background: var(--paper);
  display: flex; align-items: center; justify-content: center;
  z-index: 9999;
  transition: opacity 0.18s ease-out;
}
#splash.hidden { opacity: 0; pointer-events: none; }
.splash-mark {
  font: 600 64px/1 var(--mono);
  letter-spacing: -0.01em;
  color: var(--ink);
}
.splash-colon { color: #c45a2a; }
@media (max-width: 640px) { .splash-mark { font-size: 44px; } }

/* ============================================================
   Projects list (home view at /)
   ============================================================ */
#projects-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; }
.proj-card {
  display: flex; flex-direction: column; gap: 6px;
  padding: 14px; border: 1.25px solid var(--rule); border-radius: 6px;
  background: var(--paper); color: var(--ink); text-decoration: none;
  transition: border-color .1s, background .1s;
}
.proj-card:hover { border-color: var(--ink); background: var(--paper-warm); }
.proj-name { font: 600 14px/1.2 var(--mono); }
.proj-meta { font: 500 11px/1 var(--mono); color: var(--ink-faint); }
.proj-type { align-self: flex-start; font: 600 9.5px/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; padding: 3px 7px; border-radius: 3px; background: var(--paper-warm); color: var(--ink-soft); }
.proj-type-learn { background: color-mix(in srgb, var(--green) 18%, transparent); color: var(--green); }
.proj-type-podcast { background: color-mix(in srgb, var(--accent-link) 18%, transparent); color: var(--accent-link); }

/* Project-detail manage panel (owner/admin) — themed card with styled
   type select + member controls. */
#pd-manage-panel { margin: 4px 0 16px; }
.pd-manage {
  background: var(--paper-warm);
  border: 1.25px solid var(--rule);
  border-radius: 6px;
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 12px;
  max-width: 520px;
}
.pd-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pd-label {
  font: 600 9.5px/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-faint); width: 64px; flex-shrink: 0;
}
.pd-select {
  font: 500 12px/1 var(--mono);
  padding: 6px 9px; background: var(--paper);
  border: 1.25px solid var(--ink); border-radius: 4px; color: var(--ink);
  cursor: pointer;
}
.pd-select:focus { outline: 2px solid var(--accent-link); outline-offset: 1px; }
.pd-member-list { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.pd-member-input { width: auto; max-width: 150px; padding: 6px 9px; font-size: 12px; }
#pd-add-member-btn { font: 600 11px/1 var(--mono); padding: 6px 11px; }
.pd-hint { font-size: 11px; margin: 2px 0 0; }
body.podcast-readonly #btn-save-disk,
body.podcast-readonly #btn-done,
body.podcast-readonly #hdr-row3 .ctl-group:last-child { display: none; }

/* Auto cleanup baseline shows as a distinct chip, never a human reviewer. */
.lec-table .rev.rev-cleanup { color: #7a5cc0; border-color: #7a5cc0; }
.ctl-inline.armed .ctl-val { color: var(--warn); }

/* ===== review mode (diff another user's edits) ===== */
#review-banner { display: flex; gap: 12px; align-items: center; padding: 4px 8px;
  background: var(--hl-soft); border: 1px solid var(--rule); border-radius: 6px; font: 12px var(--mono); }
#review-banner[hidden] { display: none; }
.word[data-diff] { cursor: default; }
.diff-old { text-decoration: line-through; opacity: 0.55; }
.diff-arrow { opacity: 0.5; margin: 0 2px; }
.diff-new { color: var(--green); }
.word.diff-del { text-decoration: line-through; color: var(--red); opacity: 0.7; }
.word.diff-reverted { outline: 1px dotted var(--rule); outline-offset: 1px; }
.diff-toggle { border: none; background: none; cursor: pointer; font-size: 0.8em;
  opacity: 0; margin-left: 2px; padding: 0 2px; color: var(--warn); vertical-align: super; }
.word[data-diff]:hover .diff-toggle, .word.diff-reverted:hover .diff-toggle { opacity: 0.85; }
