/* ==========================================================================
   Divide and Conquer Math — Phase 1 design system
   --------------------------------------------------------------------------
   Brand: bright cyan accent on near-black ground (dark default), with a
   light theme that flips background and text color but keeps the same cyan
   accent. Theme is controlled via a `data-theme` attribute on <html>.
   --------------------------------------------------------------------------
   File map:
     styles.css   ← this file (shared design system)
     index.html   ← homepage (class picker)
     class.html   ← class landing (chapter grid)
     section.html ← section page (chapter rail + video list)
     app.js       ← theme toggle, chapter rail expand/collapse, batch mode
   ========================================================================== */

/* ------------------------------------------------------------------ tokens */

:root,
[data-theme="dark"] {
  --bg:               #000000;
  --bg-surface:       #131313;  /* cards, video rows */
  --bg-elevated:      #0C0C0C;  /* chapter rail panel */
  --border:           #1F1F1F;
  --border-strong:    #2A2A2A;
  --text-primary:     #FFFFFF;
  --text-secondary:   #BBBBBB;
  --text-muted:       #888888;
  --text-faint:       #7A7A7A;  /* a11y: was #555 (2.8:1 on black) */
  --accent:           #2BB5E8;  /* brand cyan */
  --accent-text:      #2BB5E8;  /* same on dark; differs on light */
  --accent-on-bg:     #000000;  /* text color when sitting on accent fill */
  --accent-tint:      rgba(43, 181, 232, 0.14);
  --accent-tint-soft: rgba(43, 181, 232, 0.06);
}

[data-theme="light"] {
  --bg:               #FAFAF6;
  --bg-surface:       #FFFFFF;
  --bg-elevated:      #FFFFFF;
  --border:           #E2E0D8;
  --border-strong:    #C9C7BE;
  --text-primary:     #1A1A1A;
  --text-secondary:   #555555;
  --text-muted:       #6E6E6E;  /* a11y: was #888 (3.4:1 on light bg) */
  --text-faint:       #707070;  /* a11y: was #AAA (2.2:1) */
  --accent:           #2BB5E8;  /* same vibrant cyan for buttons/borders */
  --accent-text:      #185FA5;  /* darker for body-text contrast on white */
  --accent-on-bg:     #08222E;  /* a11y: was #FFF — white on cyan was 2.4:1;
                                   this dark ink hits 6.9:1 on the accent */
  --accent-tint:      rgba(43, 181, 232, 0.14);
  --accent-tint-soft: rgba(43, 181, 232, 0.06);
}

/* ------------------------------------------------------------------ reset */

*,
*::before,
*::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text-primary);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; }

img, svg { display: block; max-width: 100%; }

/* ------------------------------------------------------------------ chrome */

.brand-row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 18px 24px 8px;
}

.brand {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 24px;
  font-weight: 700;
  letter-spacing: 0.005em;
  color: var(--text-primary);
  flex: 1;
}

/* Larger displays: let the wordmark carry more presence than the compact
   mobile bar (.mobile-bar .brand pins its own size below, unaffected). */
@media (min-width: 900px) {
  .brand-row .brand {
    font-size: 34px;
  }
}

.brand a:hover { color: var(--accent-text); }

.nav-row {
  padding: 8px 24px 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 14px 22px;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 13px;
  border-bottom: 0.5px solid var(--border);
}

.nav-row a {
  white-space: nowrap;
  color: var(--text-primary);
}
.nav-row a:hover { color: var(--accent-text); }

/* ---------------------------------------------------------------------------
   Hover dropdowns on class nav items
   Each class link is wrapped in a .nav-item. Hovering the wrapper reveals a
   .nav-dropdown listing the chapters for that class. Click a chapter to land
   on its first section page.
   --------------------------------------------------------------------------- */
.nav-item {
  position: relative;
}
.nav-item > a::after {
  content: '';
  display: inline-block;
  margin-left: 4px;
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
  border-top: 4px solid currentColor;
  opacity: 0.6;
  vertical-align: middle;
  transform: translateY(-1px);
}
.nav-dropdown {
  position: absolute;
  top: 100%;
  left: -6px;
  margin-top: 4px;
  display: none;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: 6px;
  min-width: 260px;
  max-width: 360px;
  padding: 6px 0;
  z-index: 100;
  box-shadow: 0 8px 24px rgba(0,0,0,0.45);
  font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Source Sans Pro', 'Segoe UI', sans-serif;
  font-size: 13px;
}
.nav-item:hover .nav-dropdown,
.nav-item:focus-within .nav-dropdown {
  display: block;
}
.nav-dropdown a {
  display: block;
  padding: 7px 14px;
  color: var(--text-primary);
  text-decoration: none;
  white-space: normal;        /* allow long chapter names to wrap inside the dropdown */
  line-height: 1.35;
}
.nav-dropdown a:hover {
  background: var(--bg-card);
  color: var(--accent-text);
}
.nav-dropdown .dd-eyebrow {
  display: block;
  padding: 8px 14px 4px;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-family: Georgia, "Times New Roman", serif;
}
.nav-dropdown .dd-divider {
  height: 1px;
  margin: 4px 0;
  background: var(--border);
}
.nav-dropdown .dd-open-all {
  display: block;
  padding: 7px 14px;
  font-size: 12px;
  color: var(--accent-text);
}

.crumb {
  padding: 18px 24px 0;
  font-size: 12px;
  color: var(--text-muted);
}
.crumb a { color: var(--accent-text); }
.crumb a:hover { text-decoration: underline; }

/* ----------------- mobile chrome ------------------ */

.mobile-bar { display: none; }

.burger {
  width: 24px;
  height: 24px;
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  background: transparent;
  border: 0;
  padding: 0;
}
.burger span {
  display: block;
  height: 2px;
  background: var(--text-primary);
  border-radius: 1px;
}

/* ------------------------------------------------------------------ hero */

.hero {
  padding: 36px 24px 40px;
  display: flex;
  align-items: center;
  gap: 28px;
}

.hero-photo {
  flex: 1;
  background: var(--bg-surface);
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 320px;
  padding: 24px;
}

.hero-photo-cap {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 10px;
  letter-spacing: 0.04em;
}

.hero-text { flex: 1; }

.eyebrow {
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-weight: 500;
  margin-bottom: 14px;
}

.hero-title {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 46px;
  line-height: 1.05;
  color: var(--text-primary);
  letter-spacing: -0.005em;
  margin: 0;
}

.hero-sub {
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-secondary);
  margin: 16px 0 0;
  max-width: 340px;
}

/* ------------------------------------------------------------------ class hero (class.html) */

.class-hero {
  padding: 22px 24px 30px;
  text-align: center;
  border-bottom: 0.5px solid var(--border);
}

.class-eyebrow {
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-weight: 500;
  margin-bottom: 8px;
}

.class-title {
  font-family: Georgia, serif;
  font-size: 38px;
  line-height: 1.1;
  color: var(--text-primary);
  letter-spacing: -0.005em;
  margin: 0;
}

.class-desc {
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-secondary);
  margin: 14px auto 18px;
  max-width: 460px;
}

.class-stats {
  display: inline-flex;
  align-items: center;
  gap: 18px;
  padding: 8px 18px;
  border: 0.5px solid var(--accent);
  border-radius: 30px;
  font-size: 12px;
  color: var(--accent-text);
}
.class-stats .dot {
  width: 3px;
  height: 3px;
  background: var(--accent);
  border-radius: 50%;
}

/* ------------------------------------------------------------------ section heads */

.section-head { padding: 32px 24px 14px; }
.section-eyebrow {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-weight: 500;
  margin-bottom: 6px;
}
.section-title {
  font-family: Georgia, serif;
  font-size: 22px;
  color: var(--text-primary);
  line-height: 1.2;
  margin: 0;
}

/* ------------------------------------------------------------------ wavy underline */

.wavy {
  display: block;
  margin-top: 8px;
}

/* ------------------------------------------------------------------ class / chapter cards */

.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  padding: 8px 24px 32px;
}

.card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  color: var(--text-primary);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.card:hover { border-color: var(--accent); background: var(--accent-tint-soft); }

.card-text { flex: 1; min-width: 0; }
.card-title {
  font-family: Georgia, serif;
  font-size: 16px;
  line-height: 1.2;
  margin-bottom: 4px;
}
.card-sub {
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.35;
}
.card-arrow svg { width: 14px; height: 14px; color: var(--accent-text); }

/* ----------- chapter card variant (class.html) ---------- */

.ch-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px 16px 16px;
  align-items: stretch;
}
.ch-eyebrow {
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.ch-pill {
  background: var(--accent-tint);
  color: var(--accent-text);
  padding: 3px 8px;
  border-radius: 4px;
  font-size: 9.5px;
  letter-spacing: 0.08em;
}
.ch-title {
  font-family: Georgia, serif;
  font-size: 17px;
  line-height: 1.25;
  color: var(--text-primary);
  margin: 0;
}
.ch-desc {
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.5;
  flex: 1;
}
.ch-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 10px;
  border-top: 0.5px solid var(--border);
  font-size: 11.5px;
  color: var(--text-muted);
}
.ch-card.is-resume {
  background: var(--accent-tint-soft);
  border-color: var(--accent);
}

/* ------------------------------------------------------------------ buttons */

.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 14px;
  border-radius: 6px;
  background: var(--accent);
  color: var(--accent-on-bg);
  font-size: 13px;
  font-weight: 500;
  border: 0;
  cursor: pointer;
}
.btn-primary svg { width: 14px; height: 14px; }
.btn-primary:hover { filter: brightness(1.1); }

.btn-secondary {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  border-radius: 6px;
  background: transparent;
  color: var(--accent-text);
  border: 1px solid var(--accent);
  font-size: 13px;
  cursor: pointer;
}

.btn-ghost {
  display: inline-flex;
  align-items: center;
  padding: 8px 12px;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  border: 0;
  font-size: 12.5px;
  cursor: pointer;
}
.btn-ghost:hover { color: var(--text-primary); }

/* ------------------------------------------------------------------ section page layout */

.layout {
  display: flex;
  padding: 18px 24px;
  gap: 18px;
}

.rail {
  width: 240px;
  flex-shrink: 0;
  background: var(--bg-elevated);
  border-radius: 8px;
  padding: 12px 0 8px;
}

.rail-title {
  font-family: Georgia, serif;
  font-size: 15px;
  padding: 0 14px 8px;
  font-weight: 500;
  color: var(--text-primary);
}

.rail-chapter {
  display: flex;
  align-items: center;
  padding: 8px 14px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-muted);
  cursor: pointer;
  background: transparent;
  border: 0;
  width: 100%;
  text-align: left;
}
.rail-chapter:hover { color: var(--text-primary); }
.rail-chapter .chev {
  margin-left: auto;
  opacity: 0.5;
  flex-shrink: 0;
  display: flex;
  align-items: center;
}
.rail-chapter .chev svg { width: 10px; height: 10px; }

.rail-chapter.is-active {
  color: var(--text-primary);
  background: var(--accent-tint);
  border-left: 3px solid var(--accent);
  padding-left: 11px;
  font-weight: 500;
}
.rail-chapter.is-active .chev { opacity: 1; }

.rail-section {
  display: block;
  padding: 6px 14px 6px 28px;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-secondary);
  background: var(--accent-tint-soft);
}
.rail-section:hover { color: var(--text-primary); }
.rail-section.is-active {
  color: var(--text-primary);
  background: var(--accent-tint);
  font-weight: 500;
}
.rail-section.is-study { font-style: italic; }

.rail-sections { display: none; }
.rail-chapter.is-active + .rail-sections { display: block; }

.content { flex: 1; min-width: 0; padding: 0; }

/* ----------- section content header ---------- */

.s-eyebrow {
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-weight: 500;
}
.s-title {
  font-family: Georgia, serif;
  font-size: 22px;
  line-height: 1.2;
  margin: 6px 0 4px;
  color: var(--text-primary);
}
.s-sub {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0 0 14px;
}

/* ----------- batch bar (select-mode) ---------- */

.batch-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  padding: 10px 14px;
  border-radius: 8px;
  flex-wrap: wrap;
  font-size: 12.5px;
  background: var(--accent-tint-soft);
  border: 1px solid var(--accent);
  color: var(--text-primary);
}
.batch-bar.is-hidden { display: none; }
.batch-count { color: var(--accent-text); font-weight: 500; }
.batch-bar .spacer { flex: 1; }
.batch-bar .btn-primary { padding: 6px 12px; font-size: 12.5px; }

.select-all {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: 0;
  color: var(--text-primary);
  cursor: pointer;
}
.select-all .checkbox {
  display: inline-flex;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  border: 1px solid var(--text-muted);
  align-items: center;
  justify-content: center;
}
.select-all.is-checked .checkbox {
  background: var(--text-primary);
  border-color: var(--text-primary);
}
.select-all.is-checked .checkbox svg {
  width: 10px;
  height: 10px;
  stroke: var(--bg);
}

/* ----------- video rows ---------- */

.vrow {
  display: flex;
  gap: 14px;
  padding: 12px;
  border-radius: 8px;
  margin-bottom: 8px;
  align-items: flex-start;
  background: var(--bg-surface);
  cursor: pointer;
  border: 1px solid transparent;
}
.vrow:hover { border-color: var(--accent); }

.vrow-cb {
  width: 16px;
  height: 16px;
  border-radius: 3px;
  flex-shrink: 0;
  margin-top: 24px;
  display: none;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--text-muted);
}
.vrow-cb svg { width: 11px; height: 11px; display: none; }

.is-batch-mode .vrow-cb { display: flex; }
.is-batch-mode .vrow-cb.is-checked {
  background: var(--accent);
  border-color: var(--accent);
}
.is-batch-mode .vrow-cb.is-checked svg {
  display: block;
  stroke: var(--accent-on-bg);
}

.thumb {
  width: 124px;
  height: 70px;
  border-radius: 4px;
  flex-shrink: 0;
  background: var(--border-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.thumb img { width: 100%; height: 100%; object-fit: cover; border-radius: 4px; }
.play {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
}
.play svg { width: 12px; height: 12px; margin-left: 2px; fill: var(--bg); }

.vinfo { flex: 1; min-width: 0; padding-top: 2px; }
.vtype {
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--accent-text);
  margin-bottom: 4px;
}
.vh {
  font-size: 14px;
  line-height: 1.35;
  font-weight: 500;
  margin-bottom: 8px;
  color: var(--text-primary);
}
.vnotes {
  font-size: 12.5px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--text-primary);
}
.vnotes:hover { color: var(--accent-text); }
.vnotes svg { width: 11px; height: 13px; }

/* ------------------------------------------------------------------ footer */

.footer {
  padding: 18px 24px 22px;
  border-top: 0.5px solid var(--border);
  margin-top: 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: Georgia, serif;
  font-size: 13px;
  color: var(--text-muted);
}

.theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 12px;
  border: 0.5px solid var(--accent);
  border-radius: 20px;
  background: transparent;
  color: var(--accent-text);
  font-family: -apple-system, system-ui, sans-serif;
  font-size: 11.5px;
}
.theme-toggle svg { width: 13px; height: 13px; }
.theme-toggle:hover { background: var(--accent-tint-soft); }

/* ----------------- mobile section selector (replaces rail) ------------------ */

.mobile-section-selector { display: none; }

/* ============================================================================
   Mobile (≤ 720px)
   ============================================================================ */

@media (max-width: 720px) {

  /* hide desktop chrome */
  .nav-row { display: none; }
  .brand-row { display: none; }

  /* show mobile chrome */
  .mobile-bar {
    display: flex;
    align-items: center;
    padding: 14px 16px;
    border-bottom: 0.5px solid var(--border);
  }
  .mobile-bar .brand { font-size: 16px; flex: 1; margin: 0; }

  .crumb { padding: 10px 16px 0; font-size: 11px; }

  /* hero: stack */
  .hero {
    padding: 18px 16px 10px;
    flex-direction: column;
    gap: 18px;
    text-align: center;
  }
  .hero-photo { min-height: 200px; padding: 18px; }
  .hero-text { text-align: center; }
  .hero-title { font-size: 30px; }
  .hero-sub { max-width: none; margin-left: auto; margin-right: auto; }

  /* class hero */
  .class-hero { padding: 18px 16px 22px; }
  .class-title { font-size: 28px; }
  .class-stats { gap: 12px; padding: 6px 14px; flex-wrap: wrap; }

  /* card grid → single column */
  .card-grid { grid-template-columns: 1fr; padding: 8px 16px 18px; gap: 8px; }

  /* section page: hide rail, show selector */
  .layout { flex-direction: column; padding: 0; gap: 0; }

  .rail { display: none; }

  .mobile-section-selector {
    display: flex;
    align-items: center;
    margin: 12px 16px;
    padding: 12px 14px;
    background: var(--bg-elevated);
    border: 0.5px solid var(--border);
    border-radius: 8px;
    width: calc(100% - 32px);
    text-align: left;
    color: var(--text-primary);
  }
  .mobile-section-selector .text { flex: 1; }
  .mobile-section-selector .ms-class {
    font-size: 10px;
    letter-spacing: 0.1em;
    color: var(--accent-text);
    text-transform: uppercase;
    font-weight: 500;
  }
  .mobile-section-selector .ms-section {
    font-family: Georgia, serif;
    font-size: 15px;
    margin-top: 2px;
  }
  .mobile-section-selector .chev svg { width: 14px; height: 14px; color: var(--accent-text); }

  .content { padding: 6px 16px 18px; }

  /* batch button: full width */
  .content > .btn-primary {
    width: 100%;
    justify-content: center;
  }

  /* video rows: smaller thumbnail */
  .thumb { width: 88px; height: 50px; }
  .play { width: 24px; height: 24px; }
  .vh { font-size: 12.5px; }

  /* footer: keep it simple */
  .footer { padding: 14px 16px 16px; font-size: 11px; }
}

/* ==========================================================================
   ADDITIONS 2026-05-19 — section-level resources, inline video player,
   vrow restructure, mobile drawers, external-link tags
   ========================================================================== */

/* Section-level resources panel (1635 stats — Guided Notes + Excel labs on tbl_sections) */
.section-resources {
  margin: 12px 0 14px;
  padding: 12px 14px;
  background: var(--accent-tint-soft);
  border: 0.5px solid var(--border);
  border-left: 2px solid var(--accent);
  border-radius: 8px;
}
.sr-eyebrow {
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--accent-text);
  text-transform: uppercase;
  font-weight: 600;
  margin-bottom: 8px;
}
.sr-buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.sr-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 11px;
  font-size: 12.5px;
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
  transition: border-color 0.12s ease, color 0.12s ease;
}
.sr-button:hover { border-color: var(--accent); color: var(--accent-text); }
.sr-button svg { width: 12px; height: 14px; flex-shrink: 0; }
.sr-ext-tag,
.ext-tag {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 5px;
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  background: transparent;
  border: 0.5px solid var(--border-strong);
  border-radius: 3px;
  vertical-align: middle;
}

/* Section description (optional, between title and "N lessons. Pick what you need.") */
.s-desc {
  font-size: 13px;
  color: var(--text-secondary);
  margin: 4px 0 10px;
  max-width: 760px;
}

/* Video row restructure — vrow-main wraps the original row content;
   vrow-player is the inline-player slot that lives below it when expanded. */
.vrow {
  display: block;
}
.vrow-main {
  display: grid;
  grid-template-columns: 0 124px 1fr;
  align-items: center;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 0.5px solid var(--border);
  transition: grid-template-columns 0.16s ease;
}
.is-batch-mode .vrow-main {
  grid-template-columns: 24px 124px 1fr;
  cursor: pointer;
}
.vrow-main .vrow-cb {
  width: 0;
  height: 18px;
  border: 1.5px solid var(--border-strong);
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: transparent;
  background: transparent;
  overflow: hidden;
  transition: width 0.16s ease, color 0.12s ease, background 0.12s ease, border-color 0.12s ease;
}
.is-batch-mode .vrow-main .vrow-cb {
  width: 18px;
}
.vrow-main .vrow-cb svg { width: 12px; height: 12px; }
.vrow-main .vrow-cb.is-checked {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-on-bg);
}

.thumb {
  width: 124px;
  height: 70px;
  background: linear-gradient(135deg, var(--bg-elevated), var(--bg-surface));
  border: 0.5px solid var(--border-strong);
  border-radius: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent-text);
  padding: 0;
  cursor: pointer;
  transition: border-color 0.12s ease, transform 0.12s ease;
}
.thumb:hover { border-color: var(--accent); transform: translateY(-1px); }
.thumb .play {
  width: 30px;
  height: 30px;
  background: var(--accent);
  color: var(--accent-on-bg);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.thumb .play svg { width: 12px; height: 12px; }

.vlinks { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 4px; }
.vnotes-extra { opacity: 0.86; }
.vnotes-extra:hover { opacity: 1; }

/* Inline video player */
.vrow-player {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.22s ease;
  margin: 0;
}
.vrow.is-playing .vrow-player {
  max-height: 600px;
  margin: 8px 0 14px;
  border-bottom: 0.5px solid var(--border);
  padding-bottom: 14px;
}
.player-aspect {
  position: relative;
  width: 100%;
  max-width: 780px;
  margin: 0 auto;
  /* aspect-ratio (not %-padding): percentage padding resolves against the
     PARENT width, which made the player taller than 16:9 on wide screens
     and YouTube cropped the video to fill it. */
  aspect-ratio: 16 / 9;
  background: #000;
  border-radius: 8px;
  overflow: hidden;
  border: 0.5px solid var(--border-strong);
}
.player-aspect iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.player-empty {
  padding: 14px 16px;
  text-align: center;
  color: var(--text-secondary);
  background: var(--bg-elevated);
  border: 0.5px dashed var(--border-strong);
  border-radius: 8px;
  font-size: 12.5px;
}

.vrow.is-playing .thumb {
  border-color: var(--accent);
}
.vrow.is-playing .thumb .play {
  background: var(--text-muted);
}

/* ------------------------------------------------------- mobile hamburger drawer */
.nav-drawer {
  position: fixed;
  inset: 0;
  z-index: 1000;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}
.nav-drawer.is-open {
  visibility: visible;
  opacity: 1;
  transition: opacity 0.18s ease, visibility 0s linear 0s;
}
.nav-drawer-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
}
.nav-drawer-panel {
  position: absolute;
  inset: 0 0 0 auto;
  width: min(86vw, 360px);
  background: var(--bg-elevated);
  border-left: 0.5px solid var(--border-strong);
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 0.22s ease;
  box-shadow: -10px 0 30px rgba(0, 0, 0, 0.35);
}
.nav-drawer.is-open .nav-drawer-panel { transform: translateX(0); }
.nav-drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 18px;
  border-bottom: 0.5px solid var(--border);
}
.nav-drawer-brand {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 14px;
  color: var(--accent-text);
}
.nav-drawer-close {
  width: 32px;
  height: 32px;
  background: transparent;
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
}
.nav-drawer-close svg { width: 14px; height: 14px; }
.nav-drawer-body {
  flex: 1;
  overflow-y: auto;
  padding: 8px 0;
}
.nav-drawer-item {
  display: block;
  padding: 12px 18px;
  font-size: 14px;
  color: var(--text-primary);
  border-bottom: 0.5px solid var(--border);
}
.nav-drawer-item:hover { background: var(--accent-tint-soft); color: var(--accent-text); }
.nav-drawer-sub { font-size: 12.5px; color: var(--text-secondary); }
body.drawer-open { overflow: hidden; }

/* ------------------------------------------------------- mobile section-selector drawer */
.mss-drawer {
  position: fixed;
  inset: 0;
  z-index: 1000;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}
.mss-drawer.is-open {
  visibility: visible;
  opacity: 1;
  transition: opacity 0.18s ease, visibility 0s linear 0s;
}
.mss-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.55); }
.mss-sheet {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  max-height: 78vh;
  background: var(--bg-elevated);
  border-top: 0.5px solid var(--border-strong);
  border-top-left-radius: 14px;
  border-top-right-radius: 14px;
  display: flex;
  flex-direction: column;
  transform: translateY(100%);
  transition: transform 0.22s ease;
  box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.4);
}
.mss-drawer.is-open .mss-sheet { transform: translateY(0); }
.mss-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 0.5px solid var(--border);
}
.mss-title {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 14px;
  color: var(--accent-text);
}
.mss-close {
  width: 30px;
  height: 30px;
  background: transparent;
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
}
.mss-close svg { width: 13px; height: 13px; }
.mss-body { flex: 1; overflow-y: auto; padding: 6px 0 12px; }
.mss-chapter { border-bottom: 0.5px solid var(--border); }
.mss-chapter-head {
  padding: 11px 18px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary);
  cursor: pointer;
}
.mss-chapter:hover .mss-chapter-head { background: var(--accent-tint-soft); }
.mss-sections {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.18s ease;
}
.mss-chapter.is-open .mss-sections {
  max-height: 800px;
  padding-bottom: 6px;
}
.mss-section {
  display: block;
  padding: 9px 28px;
  font-size: 12.5px;
  color: var(--text-secondary);
}
.mss-section:hover { color: var(--accent-text); background: var(--accent-tint-soft); }
.mss-section.is-active {
  color: var(--accent-text);
  border-left: 2px solid var(--accent);
  padding-left: 26px;
  font-weight: 500;
}

/* Hide drawer triggers above mobile breakpoint */
@media (min-width: 721px) {
  .nav-drawer, .mss-drawer { display: none !important; }
}

/* When in a small viewport, video row gets a slightly tighter thumb to leave
   room for the inline player below it. */
@media (max-width: 720px) {
  .vrow-main { grid-template-columns: 0 88px 1fr; gap: 10px; }
  .is-batch-mode .vrow-main { grid-template-columns: 22px 88px 1fr; }
  .thumb { width: 88px; height: 50px; }
  .thumb .play { width: 24px; height: 24px; }
  .vlinks { gap: 8px; }
}


/* ==========================================================================
   ADDITIONS 2026-05-19 — section-level resources, inline video player,
   vrow restructure, mobile drawers, external-link tags
   ========================================================================== */

.section-resources {
  margin: 12px 0 14px;
  padding: 12px 14px;
  background: var(--accent-tint-soft);
  border: 0.5px solid var(--border);
  border-left: 2px solid var(--accent);
  border-radius: 8px;
}
.sr-eyebrow {
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--accent-text);
  text-transform: uppercase;
  font-weight: 600;
  margin-bottom: 8px;
}
.sr-buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.sr-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 11px;
  font-size: 12.5px;
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
  transition: border-color 0.12s ease, color 0.12s ease;
}
.sr-button:hover { border-color: var(--accent); color: var(--accent-text); }
.sr-button svg { width: 12px; height: 14px; flex-shrink: 0; }
.sr-ext-tag, .ext-tag {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 5px;
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  background: transparent;
  border: 0.5px solid var(--border-strong);
  border-radius: 3px;
  vertical-align: middle;
}

.s-desc {
  font-size: 13px;
  color: var(--text-secondary);
  margin: 4px 0 10px;
  max-width: 760px;
}

.vrow { display: block; }
.vrow-main {
  display: grid;
  grid-template-columns: 0 124px 1fr;
  align-items: center;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 0.5px solid var(--border);
  transition: grid-template-columns 0.16s ease;
}
.is-batch-mode .vrow-main {
  grid-template-columns: 24px 124px 1fr;
  cursor: pointer;
}
.vrow-main .vrow-cb {
  width: 0;
  height: 18px;
  border: 1.5px solid var(--border-strong);
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: transparent;
  background: transparent;
  overflow: hidden;
  transition: width 0.16s ease, color 0.12s ease, background 0.12s ease, border-color 0.12s ease;
}
.is-batch-mode .vrow-main .vrow-cb { width: 18px; }
.vrow-main .vrow-cb svg { width: 12px; height: 12px; }
.vrow-main .vrow-cb.is-checked {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-on-bg);
}

.thumb {
  width: 124px;
  height: 70px;
  background: linear-gradient(135deg, var(--bg-elevated), var(--bg-surface));
  border: 0.5px solid var(--border-strong);
  border-radius: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent-text);
  padding: 0;
  cursor: pointer;
  transition: border-color 0.12s ease, transform 0.12s ease;
}
.thumb:hover { border-color: var(--accent); transform: translateY(-1px); }
.thumb .play {
  width: 30px;
  height: 30px;
  background: var(--accent);
  color: var(--accent-on-bg);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.thumb .play svg { width: 12px; height: 12px; }

.vlinks { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 4px; }
.vnotes-extra { opacity: 0.86; }
.vnotes-extra:hover { opacity: 1; }

.vrow-player {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.22s ease;
  margin: 0;
}
.vrow.is-playing .vrow-player {
  max-height: 600px;
  margin: 8px 0 14px;
  border-bottom: 0.5px solid var(--border);
  padding-bottom: 14px;
}
.player-aspect {
  position: relative;
  width: 100%;
  max-width: 780px;
  margin: 0 auto;
  /* aspect-ratio (not %-padding): percentage padding resolves against the
     PARENT width, which made the player taller than 16:9 on wide screens
     and YouTube cropped the video to fill it. */
  aspect-ratio: 16 / 9;
  background: #000;
  border-radius: 8px;
  overflow: hidden;
  border: 0.5px solid var(--border-strong);
}
.player-aspect iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.player-empty {
  padding: 14px 16px;
  text-align: center;
  color: var(--text-secondary);
  background: var(--bg-elevated);
  border: 0.5px dashed var(--border-strong);
  border-radius: 8px;
  font-size: 12.5px;
}
.vrow.is-playing .thumb { border-color: var(--accent); }
.vrow.is-playing .thumb .play { background: var(--text-muted); }

.nav-drawer {
  position: fixed;
  inset: 0;
  z-index: 1000;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}
.nav-drawer.is-open {
  visibility: visible;
  opacity: 1;
  transition: opacity 0.18s ease, visibility 0s linear 0s;
}
.nav-drawer-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.55); }
.nav-drawer-panel {
  position: absolute;
  inset: 0 0 0 auto;
  width: min(86vw, 360px);
  background: var(--bg-elevated);
  border-left: 0.5px solid var(--border-strong);
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 0.22s ease;
  box-shadow: -10px 0 30px rgba(0, 0, 0, 0.35);
}
.nav-drawer.is-open .nav-drawer-panel { transform: translateX(0); }
.nav-drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 18px;
  border-bottom: 0.5px solid var(--border);
}
.nav-drawer-brand {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 14px;
  color: var(--accent-text);
}
.nav-drawer-close {
  width: 32px;
  height: 32px;
  background: transparent;
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
}
.nav-drawer-close svg { width: 14px; height: 14px; }
.nav-drawer-body { flex: 1; overflow-y: auto; padding: 8px 0; }
.nav-drawer-item {
  display: block;
  padding: 12px 18px;
  font-size: 14px;
  color: var(--text-primary);
  border-bottom: 0.5px solid var(--border);
}
.nav-drawer-item:hover { background: var(--accent-tint-soft); color: var(--accent-text); }
.nav-drawer-sub { font-size: 12.5px; color: var(--text-secondary); }
body.drawer-open { overflow: hidden; }

.mss-drawer {
  position: fixed;
  inset: 0;
  z-index: 1000;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}
.mss-drawer.is-open {
  visibility: visible;
  opacity: 1;
  transition: opacity 0.18s ease, visibility 0s linear 0s;
}
.mss-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.55); }
.mss-sheet {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  max-height: 78vh;
  background: var(--bg-elevated);
  border-top: 0.5px solid var(--border-strong);
  border-top-left-radius: 14px;
  border-top-right-radius: 14px;
  display: flex;
  flex-direction: column;
  transform: translateY(100%);
  transition: transform 0.22s ease;
  box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.4);
}
.mss-drawer.is-open .mss-sheet { transform: translateY(0); }
.mss-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 0.5px solid var(--border);
}
.mss-title {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 14px;
  color: var(--accent-text);
}
.mss-close {
  width: 30px;
  height: 30px;
  background: transparent;
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
}
.mss-close svg { width: 13px; height: 13px; }
.mss-body { flex: 1; overflow-y: auto; padding: 6px 0 12px; }
.mss-chapter { border-bottom: 0.5px solid var(--border); }
.mss-chapter-head {
  padding: 11px 18px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary);
  cursor: pointer;
}
.mss-chapter:hover .mss-chapter-head { background: var(--accent-tint-soft); }
.mss-sections { max-height: 0; overflow: hidden; transition: max-height 0.18s ease; }
.mss-chapter.is-open .mss-sections { max-height: 800px; padding-bottom: 6px; }
.mss-section {
  display: block;
  padding: 9px 28px;
  font-size: 12.5px;
  color: var(--text-secondary);
}
.mss-section:hover { color: var(--accent-text); background: var(--accent-tint-soft); }
.mss-section.is-active {
  color: var(--accent-text);
  border-left: 2px solid var(--accent);
  padding-left: 26px;
  font-weight: 500;
}

@media (min-width: 721px) {
  .nav-drawer, .mss-drawer { display: none !important; }
}

@media (max-width: 720px) {
  .vrow-main { grid-template-columns: 0 88px 1fr; gap: 10px; }
  .is-batch-mode .vrow-main { grid-template-columns: 22px 88px 1fr; }
  .thumb { width: 88px; height: 50px; }
  .thumb .play { width: 24px; height: 24px; }
  .vlinks { gap: 8px; }
}


/* ==========================================================================
   ADDITIONS 2026-07-08 — thumbnail-first video rows + play-mode toggle
   --------------------------------------------------------------------------
   Every video row now shows its real YouTube thumbnail (img.youtube.com)
   instead of a bare play button. Clicking still expands the inline player
   below the row (the thumbnail hides while playing), unless the user flips
   the per-page "Play videos" toggle to open videos in a new tab instead.
   Overrides the 124x70 .thumb sizing from the earlier sections.
   ========================================================================== */

.vrow-main {
  grid-template-columns: 0 232px 1fr;
}
.is-batch-mode .vrow-main {
  grid-template-columns: 24px 232px 1fr;
}

.thumb {
  position: relative;
  width: 232px;
  height: auto;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 8px;
}
.thumb .yt-thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* hqdefault.jpg is 4:3 with letterbox bars — cover on a 16:9 box crops
     the bars away. */
  object-fit: cover;
  display: block;
}
.thumb .play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 42px;
  height: 42px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
  opacity: 0.92;
  transition: opacity 0.12s ease, transform 0.12s ease;
}
.thumb:hover .play {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1.08);
}
/* Rows with no YouTube id keep the old gradient tile + centered button. */
.thumb.no-thumb .play { position: static; transform: none; box-shadow: none; }
.thumb.no-thumb { display: flex; align-items: center; justify-content: center; }

/* While the inline player is open the big thumbnail is redundant — collapse
   its grid column so the row tightens up. visibility (not display:none)
   keeps the thumb occupying its grid slot; removing it would shift the text
   into the zero-width column and scrunch it. */
.vrow.is-playing .vrow-main { grid-template-columns: 0 0 1fr; gap: 0; }
.vrow.is-playing .thumb {
  visibility: hidden;
  width: 0;
  min-width: 0;
  border: 0;
}

/* ------------------------------------------------ play-mode toggle pill */
.play-mode {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 2px 0 12px;
  font-size: 12px;
  color: var(--text-secondary);
}
.pm-opt {
  padding: 5px 12px;
  font-size: 12px;
  color: var(--text-secondary);
  background: var(--bg-surface);
  border: 0.5px solid var(--border-strong);
  border-radius: 999px;
  cursor: pointer;
  transition: border-color 0.12s ease, color 0.12s ease, background 0.12s ease;
}
.pm-opt:hover { border-color: var(--accent); color: var(--accent-text); }
.pm-opt.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-on-bg);
  font-weight: 600;
}

@media (max-width: 720px) {
  .vrow-main { grid-template-columns: 0 128px 1fr; }
  .is-batch-mode .vrow-main { grid-template-columns: 22px 128px 1fr; }
  .thumb { width: 128px; height: auto; }
  .thumb .play { width: 30px; height: 30px; }
  .vrow.is-playing .vrow-main { grid-template-columns: 0 0 1fr; gap: 0; }
}


/* ==========================================================================
   ADDITIONS 2026-07-08b — class-stats breathing room + static pages
   (About / Stickers / Contact) + contact form
   ========================================================================== */

/* More air between the items in the class hero stats pill. */
.class-stats { gap: 26px; padding: 9px 24px; }

/* Two-column static content page: text left, media right; stacks on mobile. */
.static-page {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: 56px;
  align-items: start;
  max-width: 1160px;
  margin: 34px auto 40px;
  padding: 0 22px;
}
.static-title {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 40px;
  font-weight: 700;
  margin: 0 0 18px;
  color: var(--text-primary);
}
.static-text p {
  font-size: 15px;
  line-height: 1.85;
  color: var(--text-secondary);
  margin: 0 0 16px;
}
.static-media { text-align: center; }
.static-media img {
  max-width: 100%;
  height: auto;
  border-radius: 10px;
}
.sticker-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 34px;
  align-items: center;
  justify-content: center;
  padding-top: 20px;
}
.sticker-strip img {
  width: min(300px, 42%);
  height: auto;
  border-radius: 0;
}
.sticker-strip img:first-child { transform: rotate(-5deg); }
.sticker-strip img:last-child  { transform: rotate(4deg); }

/* ---------------------------------------------------------- contact form */
.contact-form { display: grid; gap: 16px; }
.cf-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.cf-field { display: grid; gap: 6px; }
.cf-field label {
  font-size: 12.5px;
  color: var(--text-secondary);
}
.cf-field label .req { color: var(--text-muted); font-size: 11px; }
.cf-field input,
.cf-field textarea {
  width: 100%;
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
}
.cf-field input:focus,
.cf-field textarea:focus {
  outline: none;
  border-color: var(--accent);
}
.cf-field textarea { min-height: 130px; resize: vertical; }
.cf-honeypot { position: absolute; left: -9999px; opacity: 0; }
.cf-status {
  padding: 12px 14px;
  border-radius: 8px;
  font-size: 13.5px;
  border: 0.5px solid var(--border-strong);
}
.cf-status.ok { border-left: 3px solid var(--accent); color: var(--text-primary); }
.cf-status.err { border-left: 3px solid #c0564f; color: var(--text-primary); }

@media (max-width: 800px) {
  .static-page { grid-template-columns: 1fr; gap: 28px; }
  .cf-row { grid-template-columns: 1fr; }
  .static-title { font-size: 32px; }
}


/* ==========================================================================
   ADDITIONS 2026-07-08c — bigger play-mode toggle, batch-button spacing,
   whole-class batch panel, data-driven chapter labels
   ========================================================================== */

/* "Play videos:" toggle — larger and more obvious. */
.play-mode {
  font-size: 15px;
  gap: 10px;
  margin: 8px 0 18px;
  color: var(--text-primary);
}
.play-mode .pm-label { font-weight: 600; }
.pm-opt { font-size: 14px; padding: 8px 16px; }

/* Air between the batch-entry button and the first video row. */
#batch-enter { margin-bottom: 22px; }

/* Whole-class print/download panel on the class page. */
.class-batch {
  max-width: 860px;
  margin: 26px auto 4px;
  padding: 14px 18px 8px;
  background: var(--accent-tint-soft);
  border: 0.5px solid var(--border);
  border-left: 2px solid var(--accent);
  border-radius: 8px;
}
.class-batch .cb-eyebrow {
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-weight: 600;
  margin-bottom: 6px;
}
.cb-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 8px 0;
  border-top: 0.5px solid var(--border);
}
.cb-row:first-of-type { border-top: 0; }
.cb-label {
  flex: 1;
  min-width: 200px;
  font-size: 13.5px;
  color: var(--text-primary);
}
.cb-label .cb-count {
  margin-left: 8px;
  font-size: 11.5px;
  color: var(--text-muted);
}
.cb-actions { display: flex; gap: 8px; }
.cb-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 13px;
  font-size: 12.5px;
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
  transition: border-color 0.12s ease, color 0.12s ease;
}
.cb-btn:hover { border-color: var(--accent); color: var(--accent-text); }

/* Chapter-card eyebrow may be empty now (unnumbered entries like exam
   reviews) — keep its height so the RESUME pill still has a home. */
.ch-eyebrow { min-height: 15px; }


/* ==========================================================================
   ADDITIONS 2026-07-08d — global type-size bump (~15%) for readability.
   Jen: base sizes were hard to read. Raises body text roughly +1.5-2px and
   small labels +1-1.5px across every component; big serif headings were
   already large and stay put. The @media block at the bottom re-tempers a
   few sizes on phones.
   ========================================================================== */

html, body { font-size: 15.5px; }

/* chrome */
.nav-row { font-size: 15px; }
.nav-dropdown { font-size: 14.5px; }
.nav-dropdown .dd-eyebrow { font-size: 12px; }
.nav-dropdown .dd-open-all { font-size: 13px; }
.crumb { font-size: 13.5px; }
.footer { font-size: 14px; }

/* homepage */
.eyebrow { font-size: 12px; }
.hero-sub { font-size: 16px; max-width: 400px; }
.card-title { font-size: 18px; }
.card-sub { font-size: 13.5px; }
.section-eyebrow { font-size: 12.5px; }
.section-title { font-size: 24px; }

/* class page */
.class-eyebrow { font-size: 12.5px; }
.class-desc { font-size: 16px; }
.class-stats { font-size: 14px; }
.ch-eyebrow { font-size: 12px; min-height: 17px; }
.ch-title { font-size: 19px; }
.ch-desc { font-size: 14px; }
.ch-meta { font-size: 13px; }
.ch-pill { font-size: 10.5px; }
.class-batch .cb-eyebrow { font-size: 11px; }
.cb-label { font-size: 15px; }
.cb-label .cb-count { font-size: 12.5px; }
.cb-btn { font-size: 14px; }

/* section page */
.rail-title { font-size: 16.5px; }
.rail-chapter { font-size: 14px; }
.rail-section { font-size: 13.5px; }
.s-eyebrow { font-size: 12px; }
.s-title { font-size: 26px; }
.s-desc { font-size: 15px; }
.s-sub { font-size: 14px; }
.sr-eyebrow { font-size: 11px; }
.sr-button { font-size: 14px; }
.play-mode { font-size: 16px; }
.pm-opt { font-size: 15px; }
.btn-primary { font-size: 14.5px; }
.btn-ghost { font-size: 14px; }
.batch-bar { font-size: 14px; }
.batch-bar .btn-primary { font-size: 13.5px; }
.vtype { font-size: 12px; }
.vh { font-size: 16.5px; }
.vnotes { font-size: 14px; }
.player-empty { font-size: 14px; }
.sr-ext-tag, .ext-tag { font-size: 10px; }

/* drawers */
.nav-drawer-brand { font-size: 15px; }
.nav-drawer-item { font-size: 15.5px; }
.nav-drawer-sub { font-size: 14px; }
.mss-title { font-size: 15px; }
.mss-chapter-head { font-size: 14.5px; }
.mss-section { font-size: 14px; }

/* static pages + contact form */
.static-text p { font-size: 16.5px; }
.cf-field label { font-size: 14px; }
.cf-field input, .cf-field textarea { font-size: 15.5px; }
.cf-status { font-size: 15px; }

/* phones: temper the biggest jumps so lines still fit */
@media (max-width: 720px) {
  .nav-row { font-size: 14px; }
  .vh { font-size: 14.5px; }
  .s-title { font-size: 22px; }
  .card-title { font-size: 16.5px; }
  .ch-title { font-size: 17px; }
}


/* ==========================================================================
   ADDITIONS 2026-07-08e — stats pill clearance + bigger grey card text
   ========================================================================== */

/* The rounded stats pill was crowding the class title / wavy underline —
   give it real clearance. */
.class-stats { margin-top: 20px; }

/* Grey chapter-card copy up a notch. */
.ch-desc { font-size: 15.5px; }
.ch-meta { font-size: 14px; }


/* ==========================================================================
   ADDITIONS 2026-07-08f — collapsible whole-class batch panel
   ========================================================================== */

.class-batch-cta { text-align: center; margin: 26px auto 4px; }
.class-batch.is-collapsed { display: none; }
.cb-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}
.cb-close {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  color: var(--text-secondary);
  background: transparent;
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
  transition: border-color 0.12s ease, color 0.12s ease;
}
.cb-close:hover { border-color: var(--accent); color: var(--accent-text); }
.cb-close svg { width: 11px; height: 11px; }


/* ==========================================================================
   ADDITIONS 2026-07-08g — feedback form select field
   ========================================================================== */

.cf-field select {
  width: 100%;
  padding: 10px 12px;
  font: inherit;
  font-size: 15.5px;
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
}
.cf-field select:focus { outline: none; border-color: var(--accent); }

/* ============================================================
   ADDITIONS 2026-07-08g — Phase 2 prototype: textbook picker
   (books.php) — search box + subject group headings
   ============================================================ */
.book-search-wrap {
  max-width: 620px;
  margin: 26px auto 8px;
  padding: 0 20px;
}
.book-search {
  width: 100%;
  padding: 13px 18px;
  font-size: 16px;
  font-family: inherit;
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  outline: none;
}
.book-search:focus {
  border-color: var(--accent);
}
.book-search-none {
  margin-top: 14px;
  text-align: center;
  color: var(--text-muted);
  font-size: 15px;
}
.book-search-none a { color: var(--accent-text); }
.book-group-head {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 14px;
  margin-top: 34px;
}
.book-group-count {
  color: var(--text-muted);
  font-size: 14px;
  white-space: nowrap;
}

/* ============================================================
   ADDITIONS 2026-07-08h — Phase 2 prototype: accounts
   (utility bar, account.php screens)
   ============================================================ */
.utility-bar {
  display: flex;
  justify-content: flex-end;
  padding: 8px 28px 0;
  font-size: 13.5px;
}
.utility-bar a {
  color: var(--text-muted);
  text-decoration: none;
}
.utility-bar a:hover { color: var(--accent-text); }
@media (max-width: 720px) {
  .utility-bar { display: none; } /* the drawer carries the sign-in link */
}

.account-shell {
  max-width: 640px;
  margin: 34px auto;
  padding: 0 20px;
}
.acct-eyebrow {
  color: var(--accent-text);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.acct-h1 {
  font-size: 30px;
  margin: 8px 0 10px;
}
.acct-accent { color: var(--accent-text); }
.acct-sub {
  color: var(--text-secondary);
  font-size: 15.5px;
  line-height: 1.55;
  margin: 0 0 14px;
}
.acct-sub a { color: var(--accent-text); }
.acct-hint {
  color: var(--text-muted);
  font-size: 13px;
  margin-top: 6px;
}
.acct-form { margin-top: 18px; }
.acct-alt {
  margin-top: 18px;
  color: var(--text-secondary);
  font-size: 14.5px;
}
.acct-alt a { color: var(--accent-text); }
.acct-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--text-faint);
  font-size: 12.5px;
  margin: 24px 0;
}
.acct-divider::before,
.acct-divider::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--border);
}
.acct-pass-details summary {
  cursor: pointer;
  color: var(--text-secondary);
  font-size: 14.5px;
}
.acct-pass-details[open] summary { color: var(--text-primary); }
.acct-devlink {
  margin-top: 20px;
  padding: 14px 16px;
  border: 1.5px dashed var(--accent);
  border-radius: 10px;
  font-size: 13.5px;
  line-height: 1.6;
  word-break: break-all;
  background: var(--accent-tint-soft);
}
.acct-devlink a { color: var(--accent-text); }
.acct-welcome { margin-bottom: 0; }
.acct-section {
  margin-top: 28px;
  padding: 18px 20px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.acct-section h3 { margin: 0 0 4px; font-size: 17px; }
.acct-section-sub {
  color: var(--text-muted);
  font-size: 13.5px;
  margin-bottom: 10px;
}
.acct-row {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 9px 0;
  border-top: 1px solid var(--border);
  font-size: 14.5px;
}
.acct-row:first-of-type { border-top: none; }
.acct-label {
  flex: 0 0 200px;
  color: var(--text-muted);
}
.acct-value {
  flex: 1;
  color: var(--text-primary);
}
.acct-edit {
  color: var(--accent-text);
  text-decoration: none;
  white-space: nowrap;
}
.acct-danger {
  display: flex;
  gap: 14px;
  align-items: center;
  justify-content: space-between;
}

/* Signed-out page: sign UP (left) / sign IN (right) as two cards. */
.acct-shell-wide { max-width: 900px; }
.acct-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: stretch;   /* both cards the same height */
  margin-top: 20px;
}
.acct-split-card { margin-top: 0; }
@media (max-width: 720px) {
  .acct-split { grid-template-columns: 1fr; }
}
.acct-inline-form { margin: 0; }
.acct-inline-form select {
  font-family: inherit;
  font-size: 12.5px;
  padding: 3px 6px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg-card);
  color: var(--text-primary);
  max-width: 150px;
}
.acct-star-class {
  font-weight: 700;
  font-size: 13.5px;
  color: var(--text-primary);
  margin-top: 14px;
}
.acct-coll { margin-bottom: 8px; }
.acct-coll-item { padding-left: 22px; }
.acct-join-form { margin-top: 14px; }
.acct-purpose-form { display: grid; gap: 8px; }
.acct-purpose-opt {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 14px;
  cursor: pointer;
}
.acct-purpose-opt input { accent-color: var(--accent); }
.acct-delete {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 13.5px;
  cursor: pointer;
  text-decoration: underline;
  font-family: inherit;
}
.acct-delete:hover { color: #d96c6c; }

/* Settings page: fixed three-across layout (Dan 2026-07-19). Boxes in a
   row stretch to equal height (align-items:stretch) so their bottoms line
   up — tidier than the ragged masonry it replaced.
     row 1  Profile | What brings you here | My classes
     row 2  Saved for review (spans 2)     | Your collections
     row 3  Teaching (full width)
   Danger row (sign out / delete) sits full-width below the grid. */
.acct-settings { max-width: 1060px; }
.acct-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin-top: 20px;
  align-items: stretch;
}
.acct-grid .acct-section { margin-top: 0; }
#saved { grid-column: span 2; }
@media (max-width: 900px) {
  .acct-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #saved { grid-column: 1 / -1; }
}
@media (max-width: 620px) {
  .acct-grid { grid-template-columns: 1fr; }
  #saved { grid-column: auto; }
}

/* Top row above the main grid. Students: one full-width box (Recently
   watched). Teachers: two side-by-side (Teaching | Recently watched),
   equal height. */
.acct-toprow {
  display: grid;
  gap: 16px;
  margin-top: 20px;
  align-items: stretch;
}
.acct-toprow-solo  { grid-template-columns: 1fr; }
.acct-toprow-split { grid-template-columns: 1fr 1fr; }
.acct-toprow .acct-section { margin-top: 0; }
@media (max-width: 620px) {
  .acct-toprow-split { grid-template-columns: 1fr; }
}

/* Recently-watched cards: 3 across when the box is full-width (student
   solo view); stacked when it's the narrow right half (teacher split). */
.acct-recent-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.acct-toprow-split .acct-recent-grid { grid-template-columns: 1fr; }
.acct-recent-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-card);
  text-decoration: none;
  color: inherit;
}
.acct-recent-card:hover { border-color: var(--accent); }
.acct-recent-play {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent-tint-soft);
  color: var(--accent-text);
  font-size: 12px;
}
.acct-recent-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.acct-recent-meta b { font-size: 14px; line-height: 1.25; }
.acct-recent-meta small { color: var(--text-muted); font-size: 12px; }
.acct-recent-cta { flex: 0 0 auto; color: var(--accent-text); font-size: 13px; white-space: nowrap; }
@media (max-width: 700px) {
  .acct-recent-grid { grid-template-columns: 1fr; }
}

/* Rows inside the narrower columns: the 200px fixed label won't fit
   beside its value + actions in a ~290px column, so stack the label on
   its own line and let the value/actions wrap instead of overflowing. */
.acct-grid .acct-row { flex-wrap: wrap; row-gap: 4px; }
.acct-grid .acct-label { flex: 1 1 100%; }
.acct-grid .acct-value { flex: 1 1 auto; min-width: 0; }


@media (max-width: 720px) {
  .acct-label { flex-basis: 120px; }
  .acct-danger { flex-direction: column; align-items: flex-start; }
}

/* ============================================================
   ADDITIONS 2026-07-08i — Phase 2 prototype: general homepage
   (carousel, resume hero, 3-card fork, featured strip)
   ============================================================ */
.home-hero {
  padding: 28px 24px 8px;
  max-width: 980px;
  margin: 0 auto;
}
.is-hidden { display: none !important; }

/* ---- carousel ---- */
.carousel { position: relative; }
.car-slide {
  display: none;
  align-items: center;
  gap: 34px;
  min-height: 280px;
  padding: 10px 6px;
}
.car-slide.is-active { display: flex; }
.car-text { flex: 1.2; }
.car-title {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 40px;
  line-height: 1.08;
  margin: 10px 0 0;
}
.car-sub {
  color: var(--text-secondary);
  font-size: 15.5px;
  line-height: 1.55;
  margin: 14px 0 0;
  max-width: 430px;
}
.car-cta {
  display: inline-block;
  margin-top: 16px;
  color: var(--accent-text);
  font-weight: 600;
  font-size: 15px;
}
.cred-chip {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 18px;
  padding: 8px 14px 8px 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg-surface);
  font-size: 13.5px;
  color: var(--text-secondary);
}
.cred-chip b { color: var(--text-primary); }
.cred-avatar {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--accent-tint);
  color: var(--accent-text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
}
.car-visual {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: var(--bg-surface);
  border-radius: 10px;
  min-height: 250px;
  padding: 20px;
}
.car-visual-pair { flex-direction: row; gap: 16px; }
.car-frame {
  flex: 1;
  height: 150px;
  border: 1.5px solid var(--border-strong);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--text-muted);
}
.car-frame span { font-size: 30px; color: var(--accent-text); }
.car-frame small { font-size: 11.5px; letter-spacing: 0.06em; text-transform: uppercase; }
.car-visual-book { flex-direction: row; gap: 20px; }
.car-book {
  width: 96px; height: 128px;
  border: 1.5px solid var(--accent);
  border-radius: 4px 10px 10px 4px;
  background: var(--accent-tint-soft);
  display: flex; align-items: center; justify-content: center;
  text-align: center;
  color: var(--accent-text);
  font-size: 11px; letter-spacing: 0.08em; line-height: 1.5;
}
.car-arrow-glyph { font-size: 26px; color: var(--text-muted); }
.car-toc { display: flex; flex-direction: column; gap: 10px; width: 130px; }
.car-toc i {
  display: block; height: 12px; border-radius: 6px;
  background: var(--border-strong);
}
.car-toc i:nth-child(1) { width: 100%; background: var(--accent); opacity: 0.75; }
.car-toc i:nth-child(2) { width: 78%; }
.car-toc i:nth-child(3) { width: 90%; }
.car-toc i:nth-child(4) { width: 64%; }
.car-visual-devices { flex-direction: row; gap: 22px; align-items: flex-end; }
.car-laptop {
  width: 190px; height: 118px;
  border: 1.5px solid var(--border-strong);
  border-bottom-width: 8px;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
}
.car-phone {
  width: 64px; height: 118px;
  border: 1.5px solid var(--border-strong);
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
}
.car-phone .ch-pill { transform: scale(0.8); }
.car-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 10px 0 4px;
}
.car-nav {
  background: none;
  border: 1px solid var(--border);
  border-radius: 50%;
  width: 30px; height: 30px;
  color: var(--text-secondary);
  font-size: 16px;
  line-height: 1;
}
.car-nav:hover { border-color: var(--accent); color: var(--accent-text); }
.car-dots { display: flex; gap: 8px; }
.car-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  border: none;
  padding: 0;
  background: var(--border-strong);
}
.car-dot.is-active { background: var(--accent); }

/* ---- resume hero ---- */
.resume-hero { padding: 10px 6px 16px; }
.resume-card {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-top: 18px;
  padding: 18px 20px;
  border: 1.5px solid var(--accent);
  border-radius: 12px;
  background: var(--accent-tint-soft);
}
.resume-card:hover { background: var(--accent-tint); }
.resume-play {
  width: 46px; height: 46px;
  flex: 0 0 46px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-on-bg);
  display: flex; align-items: center; justify-content: center;
  font-size: 17px;
}
.resume-meta { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.resume-meta b { font-size: 16.5px; }
.resume-meta span { color: var(--text-secondary); font-size: 14.5px; }
.resume-meta small { color: var(--text-muted); font-size: 12.5px; }
.resume-cta {
  color: var(--accent-text);
  font-weight: 700;
  white-space: nowrap;
}
.resume-others {
  display: flex;
  gap: 12px;
  margin-top: 14px;
  flex-wrap: wrap;
}
.resume-other {
  flex: 1 1 180px;
  max-width: 260px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-surface);
  display: flex; flex-direction: column; gap: 2px;
  font-size: 13px;
}
.resume-other:hover { border-color: var(--accent); }
.resume-other b { font-size: 13.5px; }
.resume-other span { color: var(--text-muted); }
.resume-identity {
  margin-top: 16px;
  font-size: 13px;
  color: var(--text-muted);
  display: flex; gap: 8px; align-items: center;
}
.resume-identity a { color: var(--accent-text); }
.resume-clear {
  background: none; border: none; padding: 0;
  color: var(--text-muted);
  font-size: 13px;
  text-decoration: underline;
  font-family: inherit;
}
.resume-clear:hover { color: var(--text-primary); }

/* ---- fork ---- */
.fork-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  max-width: 980px;
  margin: 18px auto 8px;
  padding: 0 24px;
}
.fork-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 20px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg-surface);
}
.fork-card:hover { border-color: var(--accent); }
.fork-eyebrow {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-weight: 600;
}
.fork-title {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 19px;
}
.fork-sub {
  color: var(--text-secondary);
  font-size: 13.5px;
  line-height: 1.5;
  flex: 1;
}
.fork-go { color: var(--accent-text); font-weight: 600; font-size: 14px; }

/* Homepage fork with the two review tracks broken out: 4 across. */
.fork-grid-4 { grid-template-columns: repeat(4, 1fr); max-width: 1180px; }
@media (max-width: 980px) {
  .fork-grid-4 { grid-template-columns: repeat(2, 1fr); }
}

/* setup.php chooser: six equal cards, 3×2; the situation line ("I have
   a textbook") is the thing you notice first, so it gets the size. */
.setup-grid { grid-template-columns: repeat(3, 1fr); max-width: 1060px; }
.setup-grid .fork-card { padding: 22px; gap: 10px; }
.setup-grid .fork-title { font-size: 20px; }
.setup-grid .fork-sub { font-size: 13.5px; }
@media (max-width: 900px) {
  .setup-grid { grid-template-columns: repeat(2, 1fr); }
}
.fork-code-form { display: flex; gap: 8px; align-items: stretch; }
.fork-code-input {
  flex: 1;
  min-width: 0;
  font-family: inherit;
  font-size: 15px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-card);
  color: var(--text-primary);
}
.fork-code-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.fork-code-form .btn-primary { padding: 9px 18px; font-size: 14px; white-space: nowrap; }
.fork-code-error {
  color: #d96c6c;
  font-size: 13px;
  line-height: 1.4;
}
/* Soft account nudge below the adventure cards: visible (bordered card,
   readable size, one button) but not a takeover — the free/no-signup
   promise stays the headline of the sentence. */
.setup-note-card {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  flex-wrap: wrap;
  max-width: 720px;
  margin: 26px auto 44px;
  padding: 16px 22px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg-surface);
}
.setup-note-card p {
  margin: 0;
  flex: 1 1 340px;
  color: var(--text-secondary);
  font-size: 14.5px;
  line-height: 1.55;
}
.setup-note-card .btn-primary { white-space: nowrap; }

/* ---- search.php ---- */
.search-bar {
  display: flex;
  gap: 10px;
  max-width: 620px;
  margin: 18px auto 8px;
  padding: 0 24px;
}
.search-input {
  flex: 1;
  min-width: 0;
  font-family: inherit;
  font-size: 16px;
  padding: 11px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-surface);
  color: var(--text-primary);
}
.search-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.search-status {
  text-align: center;
  color: var(--text-secondary);
  font-size: 14.5px;
  max-width: 560px;
  margin: 18px auto;
  padding: 0 24px;
}
.search-status a { color: var(--accent-text); }
.search-results {
  max-width: 760px;
  margin: 22px auto 8px;
  padding: 0 24px;
}
.search-group-head { font-size: 16px; margin: 0 0 6px; }
.search-hit {
  padding: 10px 0;
  border-top: 1px solid var(--border);
}
.search-hit:last-child { border-bottom: 1px solid var(--border); margin-bottom: 24px; }
.search-hit-name { font-weight: 600; font-size: 14.5px; margin-bottom: 3px; }
.search-hit-links { display: flex; flex-direction: column; gap: 3px; }
.search-hit-link {
  color: var(--accent-text);
  text-decoration: none;
  font-size: 13.5px;
}
.search-hit-link:hover { text-decoration: underline; }

/* ---- featured strip ---- */
.featured-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 12px;
  max-width: 980px;
  margin: 14px auto 40px;
  padding: 0 24px;
}
.featured-card {
  padding: 14px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-surface);
  text-align: center;
}
.featured-card:hover { border-color: var(--accent); }
.featured-title { font-size: 14px; font-weight: 600; }
.featured-meta { color: var(--text-muted); font-size: 12px; margin-top: 3px; }

.hero-switch { color: var(--accent-text); font-weight: 600; }

@media (max-width: 860px) {
  .car-slide { flex-direction: column; gap: 18px; min-height: 0; }
  .car-visual { width: 100%; min-height: 180px; }
  .fork-grid { grid-template-columns: 1fr; }
  .featured-grid { grid-template-columns: repeat(2, 1fr); }
  .car-title { font-size: 30px; }
}

/* ============================================================
   ADDITIONS 2026-07-08j — center homepage/picker section heads
   (scoped: cod.php and class pages keep the Phase 1 left align)
   ============================================================ */
.section-head-center {
  text-align: center;
  max-width: 980px;
  margin: 0 auto;
}


/* ==========================================================================
   ADDITIONS 2026-07-08h — real Jen-with-tablet photo in the splash carousel
   ========================================================================== */

/* The photo has its own black studio background, so the slot drops its
   surface color/padding and lets the image be the visual. */
.car-visual-photo {
  background: #000;
  padding: 0;
  overflow: hidden;
}
.car-photo {
  width: 100%;
  height: 100%;
  max-height: 340px;
  object-fit: contain;
  display: block;
}

/* ============================================================
   ADDITIONS 2026-07-09a — textbook barcode scan (books.php)
   ============================================================ */
.book-scan-row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 12px;
}
.book-scan-btn {
  display: inline-block;
  padding: 9px 16px;
  border: 1.5px solid var(--accent);
  border-radius: 999px;
  color: var(--accent-text);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  background: var(--accent-tint-soft);
}
.book-scan-btn:hover { background: var(--accent-tint); }
.book-scan-hint { color: var(--text-muted); font-size: 12.5px; }
.book-scan-status {
  margin-top: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-surface);
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-secondary);
}
.book-scan-status a { color: var(--accent-text); }
.book-scan-status b { color: var(--text-primary); }
.book-scan-result {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-top: 12px;
  padding: 14px 18px;
  border: 1.5px solid var(--accent);
  border-radius: 12px;
  background: var(--accent-tint-soft);
}
.book-scan-result:hover { background: var(--accent-tint); }
.book-scan-result-eyebrow {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-weight: 600;
}
.book-scan-result b { font-size: 16px; }
.book-scan-result > span:not(.book-scan-result-eyebrow):not(.fork-go) {
  color: var(--text-secondary);
  font-size: 13.5px;
}
.book-scan-result .fork-go { margin-top: 4px; }

/* ============================================================
   ADDITIONS 2026-07-09b — section-materials batch buttons +
   welcome-back resume prompt (COD hub homepages)
   ============================================================ */
.sr-batch {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 12px;
}
.sr-batch .btn-primary svg { width: 12px; height: 12px; }

.resume-prompt {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 300;
  display: none;
  align-items: center;
  gap: 14px;
  max-width: 440px;
  padding: 14px 16px;
  border: 1.5px solid var(--accent);
  border-radius: 14px;
  background: var(--bg-elevated);
  box-shadow: 0 12px 34px rgba(0, 0, 0, 0.5);
}
.resume-prompt.is-open { display: flex; }
.rp-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 13.5px;
  color: var(--text-secondary);
  min-width: 0;
}
.rp-text > b { color: var(--text-primary); font-size: 14px; }
.rp-text [data-rp-class] { color: var(--text-primary); }
.resume-prompt .btn-primary { white-space: nowrap; }
.rp-dismiss {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 14px;
  padding: 2px 4px;
  align-self: flex-start;
}
.rp-dismiss:hover { color: var(--text-primary); }
@media (max-width: 720px) {
  .resume-prompt { left: 14px; right: 14px; bottom: 14px; max-width: none; }
}

/* ============================================================
   ADDITIONS 2026-07-09c — teacher classes (dashboard, curate,
   student-view banner)
   ============================================================ */
.utility-bar { gap: 18px; }

.tclass-banner {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 18px;
  flex-wrap: wrap;
  margin: 14px 24px 0;
  padding: 10px 18px;
  border: 1.5px solid var(--accent);
  border-radius: 10px;
  background: var(--accent-tint-soft);
  font-size: 14px;
  color: var(--text-secondary);
}
.tclass-banner b { color: var(--text-primary); }
.tclass-banner-code { color: var(--text-muted); font-size: 13px; white-space: nowrap; }
.tclass-banner-join { margin: 0; }
.tclass-banner-join .btn-primary { padding: 6px 14px; font-size: 13px; }
.tclass-banner-joined { color: var(--accent-text); font-size: 13.5px; white-space: nowrap; }
.tclass-banner-joined a { color: inherit; }
.tclass-banner-signin { font-size: 13.5px; color: var(--accent-text); }
.tclass-row-members { color: var(--text-muted); font-size: 12.5px; display: block; }
.tclass-row-members small { font-size: 11.5px; }

.tclass-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 0;
  border-top: 1px solid var(--border);
}
.tclass-row:first-of-type { border-top: none; }
.tclass-row-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  font-size: 14.5px;
}

/* ==========================================================================
   ADDITIONS 2026-07-09d — "Save for exam review" pins
   Pin button on video rows; pinned list panel on the class page; highlight
   flash when a pinned link jumps to its row.
   ========================================================================== */

.vpin {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  font-size: 14px;
  color: var(--text-muted);
  background: transparent;
  border: 0;
  transition: color 0.12s ease;
}
.vpin:hover { color: var(--accent-text); }
.vpin svg { width: 14px; height: 14px; flex-shrink: 0; }
.vpin.is-pinned { color: var(--accent-text); }
.vpin.is-pinned .vpin-star { fill: var(--accent); stroke: var(--accent); }

/* class-page pinned list */
.pinned-panel {
  max-width: 860px;
  margin: 24px auto 0;
  padding: 14px 18px;
  background: var(--accent-tint-soft);
  border: 0.5px solid var(--border);
  border-left: 2px solid var(--accent);
  border-radius: 8px;
}
.pinned-panel.is-hidden { display: none; }
.pp-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-bottom: 6px;
}
.pp-eyebrow {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-weight: 600;
}
.pp-hint { font-size: 12.5px; color: var(--text-muted); }
.pp-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 0;
  border-top: 0.5px solid var(--border);
}
.pp-item:first-child { border-top: 0; }
.pp-link {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  font-size: 14.5px;
}
.tclass-row-base { color: var(--text-secondary); font-size: 13.5px; }
.tclass-row-code { color: var(--text-muted); font-size: 12.5px; word-break: break-all; }
.tclass-row-code a { color: var(--accent-text); }
.tclass-row-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.tclass-row-actions .btn-primary { padding: 7px 14px; font-size: 13px; }

.curate-shell { max-width: 760px; }
.curate-savebar {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 18px 0;
}
.curate-count { color: var(--text-muted); font-size: 13.5px; }
.curate-chapter {
  border: 1px solid var(--border);
  border-radius: 12px;
  margin: 14px 0;
  padding: 10px 16px 14px;
  background: var(--bg-surface);
}
.curate-chapter legend { padding: 0 8px; }
.curate-toggle {
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  gap: 8px;
  align-items: baseline;
}
.curate-section { margin: 10px 0 4px 6px; }
.curate-sec-toggle { font-size: 13.5px; color: var(--text-secondary); }
.curate-video {
  display: flex;
  gap: 10px;
  align-items: baseline;
  padding: 4px 0 4px 26px;
  font-size: 13.5px;
  cursor: pointer;
  color: var(--text-secondary);
}
.curate-video:hover { color: var(--text-primary); }
.curate-type {
  flex: 0 0 auto;
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-text);
  min-width: 72px;
}
@media (max-width: 720px) {
  .tclass-row { flex-direction: column; align-items: flex-start; }
}
.pp-link b { font-size: 15px; font-weight: 600; color: var(--text-primary); }
.pp-link:hover b { color: var(--accent-text); }
.pp-link small { font-size: 12.5px; color: var(--text-muted); }
.pp-remove {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  padding: 0;
  color: var(--text-muted);
  background: transparent;
  border: 0.5px solid var(--border-strong);
  border-radius: 6px;
  font-size: 12px;
  line-height: 1;
}
.pp-remove:hover { border-color: var(--accent); color: var(--accent-text); }

/* jump-target flash when arriving from the pinned list (?v=...) */
.vrow.is-review-target {
  animation: dcm-review-flash 2.4s ease 0.3s;
  border-radius: 8px;
}
@keyframes dcm-review-flash {
  0%   { box-shadow: 0 0 0 2px var(--accent); background: var(--accent-tint); }
  70%  { box-shadow: 0 0 0 2px var(--accent); background: var(--accent-tint-soft); }
  100% { box-shadow: none; background: transparent; }
}

/* ==========================================================================
   PORTED FROM PHASE 1 (P1 2026-07-09a) — mobile pass (Jen's phone review)
   1) hero wavy underline centered; 2) class stats pill stacks cleanly;
   3) video rows go thumbnail-on-top with real breathing room;
   4) play-mode toggle wraps gracefully.
   ========================================================================== */

@media (max-width: 720px) {

  /* 1 — the wavy underline is a block element, so text-align:center never
     moved it; center it explicitly under the centered title. */
  .hero-text .wavy,
  .class-hero .wavy,
  .content > .wavy { margin-left: auto !important; margin-right: auto !important; }

  /* 2 — the stats pill was wrap-jumbling at 375px (orphaned dot separators,
     uneven lines). Stack it as a tidy centered list and drop the dots. */
  .class-stats {
    flex-direction: column;
    gap: 6px;
    padding: 12px 26px;
  }
  .class-stats .dot { display: none; }

  /* 4 — section page: video rows become thumbnail-on-top cards.
     Explicit grid placement (not column-collapsing) so hiding the thumb
     while playing can't shift the text into a zero-width track. */
  .vrow-main {
    grid-template-columns: 0 1fr;
    gap: 10px 10px;
    padding: 16px 0 18px;
  }
  .is-batch-mode .vrow-main { grid-template-columns: 26px 1fr; }
  .vrow-main .thumb {
    grid-column: 1 / -1;
    grid-row: 1;
    width: 100%;
    max-width: 420px;
    height: auto;
  }
  .is-batch-mode .vrow-main .thumb { grid-column: 2; }
  .vrow-main .vrow-cb {
    grid-column: 1;
    grid-row: 2;
    align-self: start;
    margin-top: 3px;
  }
  .vrow-main .vinfo { grid-column: 2; grid-row: 2; }
  .vrow.is-playing .vrow-main { grid-template-columns: 0 1fr; gap: 0 10px; }
  .vrow.is-playing .thumb { display: none; }

  /* text spacing inside the row */
  .vtype { margin-bottom: 5px; }
  .vh { font-size: 15.5px; line-height: 1.4; margin: 0 0 9px; }
  .vlinks { gap: 10px 14px; }

  /* section header + page padding get more air */
  .content { padding: 12px 18px 26px; }
  .s-title { margin: 8px 0 6px; }
  .s-desc { margin: 8px 0 12px; }
  .s-sub { margin: 0 0 16px; }
  .section-resources { margin: 14px 0 18px; }

  /* 3/4 — the play-mode toggle was wrap-jamming; let it wrap with row gap */
  .play-mode { flex-wrap: wrap; row-gap: 8px; margin: 8px 0 20px; }
}

/* Play-mode second option: phones open youtube.com links in the YouTube
   app, so label it that way there; desktop keeps "in a new tab". */
.pm-lbl-mobile { display: none; }
@media (max-width: 720px) {
  .pm-lbl-desktop { display: none; }
  .pm-lbl-mobile { display: inline; }
}

/* ==========================================================================
   PORTED FROM PHASE 1 (P1 2026-07-09b) — center section header on mobile
   ========================================================================== */

@media (max-width: 720px) {
  .s-eyebrow, .s-title, .s-desc, .s-sub { text-align: center; }
  .s-desc { margin-left: auto; margin-right: auto; }
}

/* ==========================================================================
   PORTED FROM PHASE 1 (P1 2026-07-10a) — mobile section navigator
   Chips for every section in the current chapter + an explicit "Switch
   chapter" button (replaces the easy-to-miss selector pill). Mobile only;
   desktop keeps the chapter rail.
   ========================================================================== */

.msec-nav { display: none; }

@media (max-width: 720px) {
  .msec-nav {
    display: block;
    margin: 12px 16px 2px;
  }
  .msec-chapter {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
  }
  .msec-ch-label {
    min-width: 0;
    font-size: 13.5px;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .msec-switch {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--accent-text);
    background: var(--bg-surface);
    border: 1px solid var(--accent);
    border-radius: 999px;
  }
  .msec-switch svg { width: 12px; height: 12px; }

  .msec-chips {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    padding: 2px 2px 8px;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .msec-chips::-webkit-scrollbar { display: none; }
  .msec-chip {
    flex: 0 0 auto;
    padding: 8px 15px;
    font-size: 14px;
    color: var(--text-primary);
    background: var(--bg-surface);
    border: 0.5px solid var(--border-strong);
    border-radius: 999px;
    white-space: nowrap;
  }
  .msec-chip.is-active {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-on-bg);
    font-weight: 600;
  }
}

/* ==========================================================================
   PORTED FROM PHASE 1 (P1 2026-07-10b) — "Navigate the Course" panel chrome
   ========================================================================== */

@media (max-width: 720px) {
  .msec-nav {
    margin: 2px 0 18px;
    padding: 12px 14px;
    background: var(--accent-tint-soft);
    border: 1px solid var(--accent);
    border-radius: 10px;
  }
  .msec-eyebrow {
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--accent-text);
    font-weight: 600;
    margin-bottom: 9px;
  }
  .msec-chips { padding-bottom: 2px; }
}

/* ==========================================================================
   PORTED FROM PHASE 1 (P1 2026-07-10c) — mobile: play-mode toggle as a
   centered blue box; both panels center-capped.
   ========================================================================== */

@media (max-width: 720px) {
  .play-mode {
    flex-direction: column;
    align-items: center;
    gap: 10px;
    max-width: 480px;
    margin: 2px auto 14px;
    padding: 14px 16px;
    background: var(--accent-tint-soft);
    border: 1px solid var(--accent);
    border-radius: 10px;
  }
  .play-mode .pm-label { text-align: center; }
  .pm-opt {
    width: min(280px, 100%);
    text-align: center;
  }

  /* keep the two blue boxes visually aligned */
  .msec-nav {
    max-width: 480px;
    margin-left: auto;
    margin-right: auto;
  }
}

/* ==========================================================================
   PORTED FROM PHASE 1 (P1 2026-07-10d) — matched panel titles + centered
   boxes at every phone width.
   ========================================================================== */

@media (max-width: 720px) {
  .msec-eyebrow {
    font-size: 16px;
    font-weight: 600;
    letter-spacing: normal;
    text-transform: none;
    color: var(--text-primary);
    text-align: center;
    margin-bottom: 11px;
  }
  .play-mode,
  .msec-nav {
    max-width: 420px;
    margin-left: auto;
    margin-right: auto;
  }
}

/* ==========================================================================
   PORTED FROM PHASE 1 (P1 2026-07-10e) — Navigate panel: chapter label and
   switch button stack on their own centered lines.
   ========================================================================== */

@media (max-width: 720px) {
  .msec-chapter {
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
  }
  .msec-ch-label {
    max-width: 100%;
    text-align: center;
  }
}

/* ==========================================================================
   PORTED FROM PHASE 1 (P1 2026-07-10f) — welcome-back banner sits IN the
   page, above the hero (was a fixed floating card in the corner).
   ========================================================================== */

.resume-prompt {
  position: static;
  right: auto;
  bottom: auto;
  z-index: auto;
  max-width: 900px;
  margin: 18px 24px 0;
  box-shadow: none;
  justify-content: center;
}
@media (min-width: 949px) {
  .resume-prompt { margin-left: auto; margin-right: auto; }
}
@media (max-width: 720px) {
  .resume-prompt { left: auto; right: auto; bottom: auto; margin: 14px 16px 0; }
}

/* ==========================================================================
   PORTED FROM PHASE 1 — .hero-photo-real (real tablet photo in the hero;
   missed in the 2026-07-17 parity port, which is why the photo rendered
   full-size). The photo brings its own black studio background — drop the
   slot's surface color/padding and cap the height.
   ========================================================================== */
.hero-photo-real {
  background: #000;
  padding: 0;
  overflow: hidden;
  min-height: 0;
}
.hero-photo-real img {
  width: 100%;
  max-height: 380px;
  object-fit: contain;
  display: block;
  border-radius: 6px;
}

/* ============================================================
   ADDITIONS 2026-07-18 — "Tell us which book you use" reads as
   a link (was inheriting body text color, looked like plain text)
   ============================================================ */
.book-request-link {
  color: var(--accent-text);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  white-space: nowrap;
}
.book-request-link:hover {
  color: var(--accent);
  text-decoration-thickness: 2px;
}

/* ==========================================================================
   PORTED FROM PHASE 1 (2026-07-18) — play-mode panel collapses behind a
   button "Change How the Video Opens". Defaults closed; ✕ re-collapses.
   ========================================================================== */

.play-mode.is-collapsed { display: none; }

.pm-open {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 15px;
  margin: 6px 0 16px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--accent-text);
  background: var(--bg-surface);
  border: 1px solid var(--accent);
  border-radius: 999px;
}
.pm-open svg { width: 13px; height: 13px; flex-shrink: 0; }
.pm-open:hover { background: var(--accent-tint-soft); }

.play-mode { position: relative; }
.pm-close {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  color: var(--text-muted);
  background: transparent;
  border: 0;
}
.pm-close svg { width: 11px; height: 11px; }
.pm-close:hover { color: var(--text-primary); }

@media (min-width: 721px) {
  .play-mode {
    padding: 10px 36px 10px 14px;
    border: 1px solid var(--accent);
    border-radius: 10px;
    background: var(--accent-tint-soft);
    display: inline-flex;
    margin: 2px 0 16px;
  }
}
@media (max-width: 720px) {
  .pm-open {
    display: flex;
    width: fit-content;
    margin: 4px auto 16px;
  }
}

/* ==========================================================================
   ADDITIONS 2026-07-24a — editable display name in account settings (Dan).
   The Profile card now holds a small form above the read-only email row.
   ========================================================================== */

.acct-name-form { margin: 0 0 14px; }
.acct-name-form .cf-field { margin-bottom: 10px; }
.acct-name-form input[type="text"] { max-width: 320px; }

/* ==========================================================================
   ADDITIONS 2026-07-24b — the resume hero's identity line ("Not you? …")
   moved from the foot of the hero to directly under the welcome-back
   greeting (Dan), so the escape hatch sits beside the name it disputes.
   Old rule's margin-top:16px was spacing for the bottom position.
   ========================================================================== */

.resume-hero .resume-identity { margin: 2px 0 14px; }

/* ==========================================================================
   ADDITIONS 2026-07-24c — "Sign out" in the utility bar (Dan). It has to
   be a POST (CSRF), so it's a form + button dressed to match the bar's
   links; .utility-bar's flex gap handles the spacing.
   ========================================================================== */

.util-signout { margin: 0; }
.util-signout button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--text-muted);
  cursor: pointer;
}
.util-signout button:hover { color: var(--accent-text); }

/* ==========================================================================
   ADDITIONS 2026-07-24d — "Recently watched" now lives in the homepage
   resume hero (moved from account settings, Dan). It REUSES the
   .acct-recent-* card styles above so the two surfaces can't drift —
   those rules are now shared, not account-only. Only the wrapper and
   heading are new. No `display` here on purpose: the [hidden] attribute
   must still be able to hide the block when there's nothing to list.
   ========================================================================== */

.resume-recent { margin-top: 22px; }
.resume-recent-title {
  font-size: 15px;
  margin: 0 0 10px;
  color: var(--text-secondary, var(--text-muted));
}

/* ==========================================================================
   ADDITIONS 2026-07-24e — account-area tabs (Dan). "Account Settings" /
   "For Teachers" sit under the blue "Your account" eyebrow on both
   account.php and teachers.php. Signed-in only; the utility bar's "For
   teachers" link is hidden for those users, since this replaces it.
   ========================================================================== */

.acct-tabs {
  display: flex;
  gap: 22px;
  margin: 6px 0 14px;
  border-bottom: 1px solid var(--border);
}
.acct-tab {
  padding: 6px 0 9px;
  margin-bottom: -1px;              /* sit on the container's border */
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  text-decoration: none;
  font-size: 14.5px;
}
.acct-tab:hover { color: var(--accent-text); }
.acct-tab.is-active {
  color: var(--accent-text);
  border-bottom-color: var(--accent);
  font-weight: 600;
}

/* ==========================================================================
   ADDITIONS 2026-07-24f — "Your account" is the account area's page
   heading now (Dan): large, bold, white, and no longer a small blue
   eyebrow. Applied as a MODIFIER so every other .acct-eyebrow on the site
   ("Save your spot", "Your free account", "For teachers" for guests)
   keeps its original treatment. Colour is --text-primary rather than a
   literal white so the light theme stays readable.
   ========================================================================== */

.acct-page-title {
  font-size: 30px;
  font-weight: 800;
  color: var(--text-primary);
  letter-spacing: 0;
  text-transform: none;
  line-height: 1.15;
  margin-bottom: 4px;
}
@media (max-width: 620px) {
  .acct-page-title { font-size: 25px; }
}

/* ==========================================================================
   ADDITIONS 2026-07-24g — "Your class, your way" is a subheading when the
   For Teachers tab is inside the account area (Dan), so it sits under the
   30px "Your account" title rather than matching it. Guests still get
   .acct-h1 there, where it IS the page's heading.
   ========================================================================== */

.acct-subhead {
  font-size: 20px;
  font-weight: 700;
  margin: 10px 0 8px;
  line-height: 1.2;
}

/* ==========================================================================
   ADDITIONS 2026-07-24h — [data-copy] buttons (Dan). First use: the
   teacher share links in "Your classes". Small and quiet next to the
   link; turns accent while it confirms the copy.
   ========================================================================== */

.copy-btn {
  margin-left: 8px;
  padding: 2px 9px;
  border: 1px solid var(--border-strong, var(--border));
  border-radius: 999px;
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-size: 12px;
  line-height: 1.6;
  cursor: pointer;
  white-space: nowrap;
}
.copy-btn:hover { color: var(--accent-text); border-color: var(--accent); }
.copy-btn.is-copied {
  color: var(--accent-text);
  border-color: var(--accent);
  cursor: default;
}

/* ==========================================================================
   ADDITIONS 2026-07-24i — curate page (Dan): the video count moved out of
   the save bar to its own line directly above the lesson list, so it
   reads as a heading for what follows. Pulled up slightly since the bar
   above already carries an 18px bottom margin.
   ========================================================================== */

.curate-count { display: block; margin: -8px 0 0; }
/* .acct-alt carries an 18px top margin for standalone use; inside the
   centred save bar that pushes the link below the button's baseline.
   (Applies to the bottom bar too, which had the same wobble.) */
.curate-savebar .acct-alt { margin-top: 0; }

/* ==========================================================================
   ADDITIONS 2026-07-24j — teachers.php intro (Dan): three numbered steps
   and two "how students get in" cards, so a teacher who has never seen
   the site can take it in at a glance.
   ========================================================================== */

.tch-steps {
  margin: 8px 0 20px;
  padding-left: 22px;
  color: var(--text-secondary);
  font-size: 15px;
  line-height: 1.7;
}
.tch-steps li { margin: 1px 0; padding-left: 2px; }
.tch-steps li::marker { color: var(--accent-text); font-weight: 700; }

.tch-ways-lead { margin-bottom: 6px; }
.tch-ways {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: grid;
  gap: 8px;
}
.tch-ways li {
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 0 10px 10px 0;
  background: var(--bg-card);
  color: var(--text-secondary);
  font-size: 14px;
  line-height: 1.6;
}
.tch-ways li b { color: var(--text-primary); }

/* ==========================================================================
   ADDITIONS 2026-07-24k — the "Teaching" tile now lives on the homepage
   (Dan). .account-shell is 640px, too narrow beside the homepage's wider
   sections, so it gets a wrapper matching .fork-grid's metrics instead.
   The tile itself reuses .acct-section, unchanged.
   ========================================================================== */

.home-teaching {
  max-width: 980px;
  margin: 18px auto 0;
  padding: 0 24px;
}
.home-teaching .acct-section { margin-top: 0; }

/* ==========================================================================
   ADDITIONS 2026-07-24l — curate.php header: class code and class link on
   their own lines with a copy button (Dan), matching teachers.php. Tight
   spacing so the two read as a pair rather than loose paragraphs.
   ========================================================================== */

.curate-share { margin: 2px 0; word-break: break-all; }
.curate-share + .curate-share { margin-bottom: 10px; }

/* ==========================================================================
   ADDITIONS 2026-07-24m — index.php top-of-page cleanup (Dan). The top now
   uses the same rhythm as the bottom: a centred title over a grid of equal
   cards. Both new grids reuse .featured-card, so they can't drift from
   "Popular subjects". Nothing in the fork or featured sections changed.
   ========================================================================== */

.home-greeting { max-width: 980px; margin: 22px auto 0; padding: 0 24px; }
.home-greeting .eyebrow { margin-bottom: 0; }

.section-sub {
  font-size: 13.5px;
  color: var(--text-muted);
  margin: 6px 0 0;
}

/* Teaching + resume grids: same metrics as .featured-grid */
.teach-grid,
.resume-grid {
  display: grid;
  gap: 12px;
  max-width: 980px;
  margin: 14px auto 8px;
  padding: 0 24px;
}
.teach-grid  { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.resume-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.teach-card,
.resume-tile {
  display: block;
  color: inherit;
  text-decoration: none;
}
.teach-name  { font-size: 14px; font-weight: 600; line-height: 1.3; }
.teach-meta  { color: var(--text-muted); font-size: 12px; margin-top: 4px; }
.teach-go    { color: var(--accent-text); font-size: 12.5px; margin-top: 7px; }
.teach-card-manage { border-style: dashed; }
.teach-card-manage .teach-name { color: var(--accent-text); }

.resume-tile.is-current { border-color: var(--accent); }
.resume-flag {
  display: block;
  color: var(--accent-text);
  font-size: 11px;
  margin-bottom: 4px;
}
.resume-sec  { display: block; font-size: 13.5px; font-weight: 600; line-height: 1.3; }
.resume-cls  { display: block; color: var(--text-muted); font-size: 12px; margin-top: 3px; }
.resume-when { display: block; color: var(--text-faint); font-size: 11.5px; margin-top: 3px; }

.resume-hero .resume-identity { justify-content: center; margin: 0 0 4px; }

@media (max-width: 760px) {
  .teach-grid  { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .resume-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ==========================================================================
   ADDITIONS 2026-08-03a — account page: benefits column beside the sign-in
   form (Jen). The signed-out page asked students to sign up without ever
   listing what an account gets them. Two columns on desktop (benefits left,
   form right), one column on phones with the benefits first.
   The wider shell is scoped to .account-shell-signedout so the signed-in
   account area keeps its 640px reading measure.
   ========================================================================== */

.account-shell.account-shell-signedout { max-width: 940px; }

.acct-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 26px;
  align-items: start;
  margin-top: 22px;
}
.acct-split .acct-section { margin-top: 0; }

.acct-benefits {
  padding: 18px 20px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.acct-benefits-head {
  margin: 0 0 12px;
  font-size: 17px;
}
.acct-benefit-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.acct-benefit-list li {
  position: relative;
  padding: 0 0 0 24px;
  margin-bottom: 13px;
  color: var(--text-secondary);
  font-size: 14.5px;
  line-height: 1.5;
}
.acct-benefit-list li:last-child { margin-bottom: 0; }
.acct-benefit-list li b {
  color: var(--text-primary);
  font-weight: 600;
}
.acct-benefit-list li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 7px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}
.acct-benefits-note {
  margin: 15px 0 0;
  padding-top: 13px;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 13.5px;
  line-height: 1.5;
}

@media (max-width: 720px) {
  .acct-split { grid-template-columns: minmax(0, 1fr); gap: 18px; }
}

/* ==========================================================================
   ADDITIONS 2026-08-03b — account page: the benefits card and the sign-in
   card are the same height (Jen). The grid was align-items:start, so the
   shorter benefits box stopped early and left a ragged edge next to the
   form. Stretching both to the row height squares the pair off.
   ========================================================================== */

.account-shell .acct-split { align-items: stretch; }
.account-shell .acct-split > .acct-benefits,
.account-shell .acct-split > .acct-section {
  display: flex;
  flex-direction: column;
}
/* The early-member note sits on the bottom edge of whichever card is
   shorter, so the two cards end level instead of the text floating. */
.account-shell .acct-split > .acct-benefits .acct-benefits-note { margin-top: auto; }

/* ==========================================================================
   ADDITIONS 2026-08-03c — "Popular subjects" strip centers itself (Jen).
   The grid was a hardcoded repeat(6, 1fr) from when the strip had six COD
   cards; with the five topic classes the sixth column stayed empty and the
   row sat 86px left of the page centre. Flex instead, so the strip fills
   and balances at ANY card count and the last wrapped row centres on
   phones. The old grid-template-columns rules are inert under flex and are
   left in place per the append-only rule.
   ========================================================================== */

.featured-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.featured-grid > .featured-card {
  flex: 1 1 140px;
  min-width: 0;
}

/* ==========================================================================
   ADDITIONS 2026-08-03d — general.php: topic classes in titled subject
   sections (Jen). Eleven cards in one flat grid read as a wall of text.
   Section headings reuse .book-group-head; the cards inside centre
   themselves so a section with one or two classes doesn't sit stranded in
   the left third of a fixed 3-column grid. Scoped to .gen-group so the
   shared .card-grid (chapter grids, the book picker) is untouched.
   ========================================================================== */

.gen-group .card-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.gen-group .card-grid > .card {
  /* 260 not 300: a four-class subject has to fit on ONE row at desktop
     width, otherwise the fourth card sits alone underneath the other
     three. They grow from there to fill the row evenly. */
  flex: 1 1 260px;
  max-width: 420px;
  min-width: 0;
}

/* ==========================================================================
   ADDITIONS 2026-08-03e — books.php: one collapsed bucket per subject
   (Jen). 97 book cards on screen at once was a wall, and Algebra alone is
   47. Each subject is now a <details> the student opens. The heading row
   keeps its centred .book-group-head look and becomes the click target;
   the chevron rotates when open. Buckets themselves stay data-driven
   (fld_class_group), so a new group appears here with no code change.
   ========================================================================== */

.book-group-toggle {
  cursor: pointer;
  list-style: none;
  padding: 10px 24px;
  border-radius: 10px;
}
.book-group-toggle::-webkit-details-marker { display: none; }
.book-group-toggle:hover .section-title { color: var(--accent-text); }
.book-group-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.book-group-chev {
  display: inline-flex;
  width: 16px;
  height: 16px;
  color: var(--text-muted);
  transition: transform 0.15s ease;
}
details[open] > .book-group-toggle .book-group-chev { transform: rotate(180deg); }

/* ==========================================================================
   ADDITIONS 2026-08-03f — "Pick up where you left off" and "Teaching: your
   classes" centre themselves (Jen). Both were fixed-column grids — resume
   4 across, teaching 3 — so a student with ONE saved spot got a single card
   clamped to the far left of an otherwise empty row. Flex instead: the
   cards fill the row when there are enough, and centre when there aren't.
   flex-basis 150px keeps the counts identical to the old grid (4 across on
   desktop, 2 on phones); max-width stops a lone card stretching the full
   980px. The old grid-template-columns rules are inert under flex and are
   left in place per the append-only rule.
   ========================================================================== */

.teach-grid,
.resume-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.teach-grid > *,
.resume-grid > * {
  flex: 1 1 150px;
  max-width: 320px;
  min-width: 0;
}

/* ==========================================================================
   ADDITIONS 2026-08-03g — carousel visuals: real graphics replace the
   CSS-only placeholders (Jen). Assets and markup approved 2026-08-03; see
   D:\DCMDatabase\Website Graphics\carousel\IMPLEMENTATION.md for the source
   spec. Slide 0 (Jen + tablet photo) is unchanged.
   The old .car-frame / .car-book / .car-toc / .car-arrow-glyph / .car-laptop
   / .car-phone rules are dead now that index.php no longer emits those
   classes; left in place per the append-only / never-delete rule rather
   than removed as the spec suggested.
   ========================================================================== */

/* ---- shared ---- */
.car-visual-cascade,
.car-visual-book,
.car-visual-devices { position: relative; }

/* ---- "The format": one lesson cascading over its notes page ---- */
.car-cas { position: relative; width: 100%; padding-bottom: 60.255%; }

.car-cas-card {
  position: absolute;
  border: 1.5px solid var(--border-strong);
  border-radius: 7px;
  overflow: hidden;
  background: #000;
  box-shadow: 0 8px 26px rgba(0, 0, 0, .6);
}
.car-cas-card img { width: 100%; display: block; }

.car-cas-vid { width: 54%; }

/* the notes page: right edge lands on the centre of the back video card,
   bottom edge midway between the 2nd and 3rd cards' bottoms. Both are
   load-bearing -- changing width or the image's aspect breaks the alignment. */
.car-cas-paper {
  background: #fff;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .55);
}

.car-cas-1 { left: 2.5%;  top: 0;      width: 46%; }
.car-cas-2 { left: 21.5%; top: 20.25%; }
.car-cas-3 { left: 32.5%; top: 34.92%; }
.car-cas-4 { left: 43.5%; top: 49.59%; }

/* depth: the further back, the darker */
.car-cas-dim1::after,
.car-cas-dim2::after { content: ""; position: absolute; inset: 0; pointer-events: none; }
.car-cas-dim1::after { background: rgba(0, 0, 0, .40); }
.car-cas-dim2::after { background: rgba(0, 0, 0, .22); }

.car-cas-stamp {
  position: absolute; left: 7px; top: 6px; z-index: 2;
  background: rgba(0, 0, 0, .72); color: #fff;
  font-size: 8.5px; border-radius: 3px; padding: 1px 5px;
}
.car-cas-tag {
  position: absolute; right: 7px; top: 6px; z-index: 2;
  background: var(--accent); color: #08222E;
  font-size: 7.5px; font-weight: 700; letter-spacing: .06em;
  border-radius: 3px; padding: 1.5px 6px;
}

/* caption sits BELOW the panel so it can't push the artwork off centre
   or collide with the front card */
.car-cas-note {
  position: absolute; left: 0; right: 0; top: 100%; margin-top: 11px;
  text-align: center; color: var(--text-faint); font-size: 11.5px;
}

/* ---- "Your book, your order" ---- */
.car-bk {
  display: flex; align-items: center; justify-content: center;
  gap: 14px; width: 100%;
}
.car-bk-cover { width: 104px; height: 144px; }
.car-bk-arrow { color: var(--text-muted); font-size: 20px; }
.car-bk-toc {
  width: 150px; border: 1.5px solid var(--border-strong); border-radius: 7px;
  overflow: hidden; background: var(--bg); position: relative;
}
.car-bk-toc img { width: 100%; display: block; }
.car-bk-toc::after {                     /* fade the cut-off bottom row */
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 44px;
  background: linear-gradient(to bottom, transparent, var(--bg-surface));
}
.car-bk-cap {
  font-size: 10px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--text-muted); text-align: center; margin-top: 8px;
}

/* ---- "Pick up anywhere" ---- */
/* proportional stage, so the arc's endpoint stays glued to the phone
   at every width */
.car-dev {
  position: relative; width: 100%; max-width: 340px;
  aspect-ratio: 340 / 230; margin: 0 auto;
}
.car-dev-lap { position: absolute; left: 5.9%; bottom: 0; width: 73.5%; }
.car-dev-screen {
  border: 1.5px solid var(--border-strong); border-radius: 8px;
  overflow: hidden; background: var(--bg);
}
.car-dev-screen img { width: 100%; display: block; }
.car-dev-base {
  height: 8px; border-radius: 0 0 5px 5px; background: var(--border-strong);
  width: 112%; margin: 3px 0 0 -6%;
}
.car-dev-phone {
  position: absolute; left: 71.2%; top: 6.1%; width: 22.9%; z-index: 3;
  border: 1.5px solid var(--border-strong); border-radius: 11px;
  background: var(--bg); padding: 5px 4px 6px;
  box-shadow: -10px 8px 24px rgba(0, 0, 0, .6);
}
.car-dev-notch {
  width: 60%; height: 3px; border-radius: 2px;
  background: var(--border-strong); margin: 1px auto 4px;
}
.car-dev-phone img { width: 100%; display: block; border-radius: 4px; }
.car-dev-arc {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 4; pointer-events: none;
}

/* ==========================================================================
   ADDITIONS 2026-08-03h — carousel: all four visuals render at the same
   size (Jen). .car-slide uses align-items:center, not stretch, so each
   .car-visual's height came from its own content -- the untouched photo
   slide (a portrait image, capped at max-height:340) sat at 340px while
   the three new graphic slides settled around 270-276px, so the panel
   visibly grew and shrank as the carousel cycled. Explicit height on
   .car-visual makes it a fixed box regardless of what's inside; the photo
   slide's existing object-fit:contain then letterboxes the portrait photo
   inside it instead of stretching the box to match the photo.
   ========================================================================== */

.carousel .car-visual { height: 280px; }

@media (max-width: 860px) {
  .carousel .car-visual { height: 220px; }
}

/* ==========================================================================
   ADDITIONS 2026-08-03i — homepage fork grid: 5th card ("I'm a teacher"),
   in the row, not stranded on one of its own (Jen). .fork-grid-4 was a
   fixed repeat(4, 1fr)/repeat(2, 1fr) grid sized for exactly 4 cards; a 5th
   would sit alone underneath. Unlike the featured strip / resume / teach
   grids fixed earlier today, this card count is fixed content (hardcoded
   in index.php), not data-driven, so it doesn't need to handle an
   arbitrary count -- it needs to fit exactly 5 across at desktop widths.
   flex-basis 190px is sized so 5 cards' hypothetical widths (what the wrap
   decision uses, before flex-grow/shrink) fit within the grid's own
   980-1180px width; below that they wrap in twos, still centred.
   ========================================================================== */

.fork-grid-4 {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.fork-grid-4 > .fork-card {
  flex: 1 1 190px;
  max-width: 260px;
  min-width: 0;
}

/* Mid widths: let it break 3+2 rather than 4+1, and pin the wrapped cards
   to the same width as the full row (flex-grow was stretching the lone
   trailing card to its 260px max while its row-mates sat at 197). */
@media (max-width: 1080px) {
  .fork-grid-4 > .fork-card {
    flex: 0 1 calc((100% - 32px) / 3);
    max-width: none;
  }
}
@media (max-width: 700px) {
  .fork-grid-4 > .fork-card { flex: 0 1 calc((100% - 16px) / 2); }
}
@media (max-width: 460px) {
  .fork-grid-4 > .fork-card { flex: 0 1 100%; }
}

/* ==========================================================================
   ADDITIONS 2026-08-03j — homepage fork cards as squares, one row (Jen).
   The 5 cards were 214x286 because .fork-grid-4 caps at 1180px; a square
   needs the card as tall as it is wide, so the grid widens to 1560 and the
   cards take a fixed fifth of it (~290px) with aspect-ratio 1/1.
   align-items:flex-start is required — the default stretch would force
   every card to the row's height and aspect-ratio would never apply.
   Gated to wide viewports: below 1360px the card would be narrower than
   its own text needs to be tall, so it keeps the auto-height behaviour
   from block (i) and wraps 3+2 as before.
   ========================================================================== */

@media (min-width: 1360px) {
  .fork-grid-4 {
    max-width: 1560px;
    align-items: flex-start;
  }
  .fork-grid-4 > .fork-card {
    flex: 0 0 calc((100% - 64px) / 5);
    max-width: none;
    aspect-ratio: 1 / 1;
  }
  /* pin the call-to-action to the bottom edge so the squares share a
     baseline no matter how long each card's copy runs */
  .fork-grid-4 > .fork-card .fork-go { margin-top: auto; }
}

/* ==========================================================================
   ADDITIONS 2026-08-03k — carousel a little bigger (Jen). Block (h) sized
   the visual panel at 280px to make all four slides match; this lifts that
   to 340 (260 on phones) and gives the slide a matching min-height so the
   hero reads as the page's main event rather than a strip above the fork
   cards. Everything inside is proportional, so the artwork just scales.
   ========================================================================== */

.carousel .car-visual { height: 340px; }
.carousel .car-slide  { min-height: 340px; }

@media (max-width: 860px) {
  .carousel .car-visual { height: 260px; }
  .carousel .car-slide  { min-height: 0; }
}

/* ==========================================================================
   ADDITIONS 2026-08-03l — setup.php chooser centres its cards (Jen). The
   statistics card makes seven, and .setup-grid is repeat(3, 1fr), so the
   seventh sat alone at the left of an empty row — the same fixed-column
   bug fixed today on the featured strip, the resume/teach grids and the
   homepage fork. Flex + wrap + centre; equal widths on every row so a
   short last row doesn't stretch its cards wider than the rest.
   ========================================================================== */

.setup-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.setup-grid > .fork-card {
  flex: 0 1 calc((100% - 32px) / 3);
  min-width: 0;
}
@media (max-width: 860px) {
  .setup-grid > .fork-card { flex: 0 1 calc((100% - 16px) / 2); }
}
@media (max-width: 560px) {
  .setup-grid > .fork-card { flex: 0 1 100%; }
}

/* ==========================================================================
   ADDITIONS 2026-08-04a — teacher-defined groups inside a class
   --------------------------------------------------------------------------
   "Exam 1", "Week 1", "Unit 3 review": named buckets a teacher fills with
   videos they already picked (Jen 2026-08-04). Two surfaces:

     curate.php        the group manager (.curate-groups) plus ASSIGN mode
                       (.curate-assignbar + .curate-assign-row), which reuses
                       the existing .curate-* tree styling and only adds a
                       name column and membership chips.
     class.php         the student side: .tgroup-grid of cards above the
                       chapter grid, and .tgroup-open when one is opened.

   Everything here is additive. A class with no groups matches no selector
   in this block, which is what keeps existing classes byte-identical.
   ========================================================================== */

/* ---------------------------------------------------- curate: the manager */

.curate-groups {
  border: 1px solid var(--border-strong);
  background: var(--bg-surface);
  border-radius: 10px;
  padding: 16px 18px;
  margin: 22px 0;
}
.curate-groups h3 {
  margin: 0 0 2px;
  font-size: 16px;
}
.cgroup-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 14px 0 0;
}
.cgroup-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  border: 1px solid var(--border);
  background: var(--bg-elevated);
  border-radius: 8px;
  padding: 9px 12px;
}
.cgroup-name {
  font-weight: 600;
  color: var(--text-primary);
}
.cgroup-count {
  font-size: 12px;
  color: var(--text-muted);
}
.cgroup-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-left: auto;
}
.cgroup-actions .btn-primary {
  padding: 5px 12px;
  font-size: 12.5px;
}
.cgroup-rename input[type="text"] {
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  color: var(--text-primary);
  border-radius: 7px;
  padding: 5px 9px;
  font-size: 12.5px;
  max-width: 170px;
}
.cgroup-actions button[disabled] {
  opacity: 0.35;
  cursor: default;
}
.cgroup-new {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
  margin-top: 14px;
}
.cgroup-new-label {
  font-size: 12px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 700;
}
.cgroup-new input[type="text"] {
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  color: var(--text-primary);
  border-radius: 7px;
  padding: 8px 11px;
  font-size: 13px;
  min-width: 220px;
}

/* ------------------------------------------------------ curate: assign mode */

.curate-assignbar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  background: var(--accent-tint);
  border: 1px solid var(--accent);
  border-radius: 9px;
  padding: 10px 14px;
  margin: 18px 0 10px;
}
.curate-assignbar .ca-lbl {
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  font-weight: 700;
}
.curate-assignbar .ca-name {
  font-weight: 700;
  font-size: 15px;
  color: var(--text-primary);
}
.curate-assignbar .ca-count {
  margin-left: auto;
  font-size: 12.5px;
  color: var(--text-secondary);
}

/* The assign row carries a name column and membership chips; the include
   tree's own rows are untouched by these selectors. */
.curate-video.curate-assign-row {
  gap: 10px;
}
.curate-video.curate-assign-row .curate-vname {
  flex: 1 1 auto;
  min-width: 0;
}
.curate-chips {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
  flex: 0 1 auto;
  justify-content: flex-end;
}
.curate-chip {
  display: inline-block;
  font-size: 10.5px;
  line-height: 1.7;
  padding: 0 7px;
  border-radius: 999px;
  border: 1px solid var(--accent);
  background: var(--accent-tint);
  color: var(--accent-text);
  font-weight: 600;
  white-space: nowrap;
}

/* ------------------------------------------------------- student: the cards */

.tgroup-grid {
  margin-bottom: 6px;
}
.card.tgroup-card {
  border-color: var(--border-strong);
  background: linear-gradient(180deg, var(--accent-tint-soft), transparent);
}
.card.tgroup-card:hover {
  border-color: var(--accent);
}
.tgroup-note {
  text-align: center;
  color: var(--text-muted);
  font-size: 12.5px;
  margin: 8px 0 0;
}

/* --------------------------------------------------- student: opened group */

.tgroup-open {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.tgroup-video {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid var(--border);
  background: var(--bg-surface);
  border-radius: 9px;
  padding: 10px 14px;
}
.tgroup-video:hover {
  border-color: var(--accent);
}
.tgroup-video .tgv-type {
  flex: 0 0 74px;
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.tgroup-video .tgv-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13.5px;
  color: var(--text-primary);
}
.tgroup-video .tgv-go {
  flex: 0 0 auto;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--accent-text);
  white-space: nowrap;
}
.tgroup-back {
  margin: 16px 0 0;
  font-size: 13px;
}
.tgroup-back a {
  color: var(--accent-text);
  font-weight: 600;
}

@media (max-width: 620px) {
  .cgroup-actions {
    margin-left: 0;
    width: 100%;
  }
  .cgroup-rename input[type="text"] { max-width: 120px; }
  .curate-chips { justify-content: flex-start; }
  .tgroup-video {
    flex-wrap: wrap;
    gap: 4px 12px;
  }
  .tgroup-video .tgv-type { flex: 0 0 100%; }
  .tgroup-video .tgv-name { flex: 1 1 100%; }
}

/* ==========================================================================
   ADDITIONS 2026-08-04a — book buckets centre their cards (Jen). The picker
   used the shared .card-grid, a fixed repeat(3, 1fr), so a bucket holding
   one or two books left the empty columns on the right and the row sat off
   to the left — Statistics, the first bucket with fewer than three books,
   measured 264px off centre. Same fixed-column bug fixed on the featured
   strip, the resume/teach grids, the homepage fork and general.php.
   flex-basis 300px keeps three across at full width, exactly as before.
   Scoped to .book-group so the shared .card-grid is untouched elsewhere.
   ========================================================================== */

.book-group .card-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
/* A fixed third of the row, NOT flex-basis with grow. Grow would let a
   remainder row stretch its cards to double width (13 books came out 5+5+3
   with the last three twice the size of the rest), and a plain basis would
   change the density the grid had. This keeps exactly three across and
   simply centres whatever the last row holds. Gap is 12px, so two gaps. */
.book-group .card-grid > .book-card {
  flex: 0 1 calc((100% - 24px) / 3);
  min-width: 0;
}
@media (max-width: 860px) {
  .book-group .card-grid > .book-card { flex: 0 1 calc((100% - 12px) / 2); }
}
@media (max-width: 560px) {
  .book-group .card-grid > .book-card { flex: 0 1 100%; }
}

/* ==========================================================================
   ADDITIONS 2026-08-04b — "Add Groups" reframed as an optional add-on (Jen)
   --------------------------------------------------------------------------
   Same feature as block (a); this is the wrapper it now lives in. The panel
   is a plain <details> so it works with no JS: the pitch sits INSIDE the
   <summary> (the only part that shows while closed) and these rules hide the
   pitch again once it's open, leaving just the title row above the manager.
   PHP adds `open` when the class already has groups.

   Overrides here are all more-specific selectors layered on block (a)'s
   .curate-groups; nothing above is edited.
   ========================================================================== */

details.addon-groups > summary.addon-summary {
  cursor: pointer;
  list-style: none;
  display: block;
}
details.addon-groups > summary.addon-summary::-webkit-details-marker { display: none; }

/* Closed: an invitation, not a section of the form. */
details.addon-groups:not([open]) {
  border-style: dashed;
  background: var(--accent-tint-soft);
}

.addon-groups .addon-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.addon-groups .addon-head::after {
  content: "▸";
  margin-left: auto;
  color: var(--text-faint);
  font-size: 12px;
}
.addon-groups[open] .addon-head::after { content: "▾"; }

.addon-groups .addon-title {
  margin: 0;
  font-size: 16px;
}
.addon-badge {
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--accent);
  background: var(--accent-tint);
  color: var(--accent-text);
}

.addon-groups .addon-pitch,
.addon-groups .addon-eg,
.addon-groups .addon-skip,
.addon-groups .addon-cta {
  display: block;
  margin-top: 9px;
}
.addon-groups .addon-pitch {
  color: var(--text-secondary);
  max-width: 64ch;
}
.addon-groups .addon-pitch b { color: var(--text-primary); }
.addon-groups .addon-eg {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.addon-chip {
  font-size: 11px;
  line-height: 1.8;
  padding: 0 9px;
  border-radius: 999px;
  border: 1px dashed var(--border-strong);
  color: var(--text-muted);
  white-space: nowrap;
}
.addon-groups .addon-skip {
  font-size: 12.5px;
  color: var(--text-muted);
}
.addon-groups .addon-cta {
  display: flex;
  align-items: center;
  gap: 11px;
  flex-wrap: wrap;
  margin-top: 13px;
}
/* Looks like the button it stands in for; the <summary> is the real control,
   so this must NOT be a nested <button>. */
.addon-fauxbtn {
  background: var(--accent);
  color: var(--accent-on-bg);
  border-radius: 7px;
  padding: 8px 15px;
  font-weight: 600;
  font-size: 13px;
}
.addon-hint {
  font-size: 12px;
  color: var(--text-muted);
}

/* Open: the pitch has done its job. */
.addon-groups[open] .addon-pitch,
.addon-groups[open] .addon-eg,
.addon-groups[open] .addon-skip,
.addon-groups[open] .addon-cta { display: none; }

.addon-inner {
  margin-top: 15px;
  border-top: 1px solid var(--border);
  padding-top: 14px;
}
.addon-inner .addon-reassure {
  font-size: 12.5px;
  color: var(--text-muted);
}
.addon-none {
  color: var(--text-muted);
}

/* ==========================================================================
   ADDITIONS 2026-08-04c — teacher groups centre their cards (Jen)
   --------------------------------------------------------------------------
   Exactly the bug the book buckets had earlier today: the group cards use
   the shared .card-grid, a fixed repeat(3, 1fr), so a class with one or two
   groups filled the left columns and left the empty ones on the right. The
   heading above and the "everything else" note below are both centred, so a
   lone "Week 1" card sat visibly off to the side.

   Same fix, same reasoning as the .book-group block above: flex + wrap +
   centre, with a FIXED third of the row rather than a growing basis. Grow
   would let a remainder row stretch its cards to double width; a plain
   basis would change the density. Three across at full width is unchanged,
   and any short row simply centres. Gap is 12px, hence two gaps.

   Scoped to .tgroup-grid, which sits ON the .card-grid element itself
   (class="card-grid tgroup-grid"), so the chapter grid below is untouched.
   ========================================================================== */

.card-grid.tgroup-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.card-grid.tgroup-grid > .tgroup-card {
  flex: 0 1 calc((100% - 24px) / 3);
  min-width: 0;
}
@media (max-width: 860px) {
  .card-grid.tgroup-grid > .tgroup-card { flex: 0 1 calc((100% - 12px) / 2); }
}
@media (max-width: 560px) {
  .card-grid.tgroup-grid > .tgroup-card { flex: 0 1 100%; }
}

/* ==========================================================================
   ADDITIONS 2026-08-04d — "Show only my groups" (Jen)
   --------------------------------------------------------------------------
   The teacher can hide the book's chapter navigation entirely so their own
   groups are the only way through the class. One checkbox inside the Add
   Groups panel, plus the warning that counts the videos no group holds —
   with the setting on, those become unreachable, so the number is stated
   rather than left to be discovered.

   The student side needed no new rules: the group rail, mobile chips and
   drawer reuse .rail-chapter / .rail-section / .msec-chip / .mss-section
   exactly as the chapter versions did.
   ========================================================================== */

.cgroup-view {
  margin-top: 14px;
  padding-top: 13px;
  border-top: 1px solid var(--border);
}
.cgroup-view-opt {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  color: var(--text-secondary);
  max-width: 64ch;
  cursor: pointer;
}
.cgroup-view-opt input[type="checkbox"] {
  margin-top: 3px;
  flex: 0 0 auto;
  accent-color: var(--accent);
}
.cgroup-view-opt b { color: var(--text-primary); }
.cgroup-view-warn {
  margin: 9px 0 0 26px;
  padding: 8px 12px;
  border-left: 3px solid var(--accent);
  background: var(--accent-tint-soft);
  border-radius: 0 6px 6px 0;
  font-size: 12.5px;
  color: var(--text-secondary);
  max-width: 60ch;
}
.cgroup-view-warn b { color: var(--text-primary); }
.cgroup-view > button {
  margin-top: 11px;
}

/* ==========================================================================
   ADDITIONS 2026-08-04e — teacher-guide.php, "Four ways to run your class"
   --------------------------------------------------------------------------
   A help page (Jen 2026-08-04): teachers kept having to be told that
   trimming is optional, that groups are optional, and that groups can
   either sit above the book or replace it. Four cards, each a numbered
   shape with the same three labelled rows, so the options can be compared
   down a column rather than read as prose.

   Everything lives inside .account-shell and borrows its tokens; the rows
   are a <dl> because that is what they are.
   ========================================================================== */

.tguide-lead {
  max-width: 68ch;
}
.tguide-ways {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin: 22px 0 8px;
}
.tguide-way {
  border: 1px solid var(--border-strong);
  background: var(--bg-surface);
  border-radius: 10px;
  padding: 16px 18px 14px;
}
.tguide-head {
  display: flex;
  align-items: center;
  gap: 11px;
}
.tguide-num {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-on-bg);
  font-weight: 700;
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.tguide-head h3 {
  margin: 0;
  font-size: 17px;
}
.tguide-fit {
  margin: 9px 0 0 37px;
  color: var(--accent-text);
  font-size: 13px;
  font-weight: 600;
  max-width: 62ch;
}
.tguide-rows {
  margin: 12px 0 0 37px;
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 7px 16px;
}
.tguide-rows dt {
  font-size: 11.5px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 700;
  padding-top: 2px;
}
.tguide-rows dd {
  margin: 0;
  color: var(--text-secondary);
  max-width: 66ch;
}
.tguide-rows dd b { color: var(--text-primary); }

.tguide-facts {
  margin: 10px 0 0;
  padding-left: 20px;
  color: var(--text-secondary);
}
.tguide-facts li {
  margin-bottom: 7px;
  max-width: 70ch;
}
.tguide-facts b { color: var(--text-primary); }

.tguide-cta {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 24px 0 8px;
}
.tguide-cta-note {
  font-size: 12.5px;
  color: var(--text-muted);
}

@media (max-width: 620px) {
  .tguide-fit,
  .tguide-rows { margin-left: 0; }
  .tguide-rows {
    grid-template-columns: 1fr;
    gap: 2px;
  }
  .tguide-rows dd { margin-bottom: 8px; }
}

/* ==========================================================================
   ADDITIONS 2026-08-04f — teacher-guide.php becomes a 2x2 with visuals (Jen)
   --------------------------------------------------------------------------
   Four stacked cards made the reader hold three options in their head to
   compare the fourth. Two by two puts all four in one glance, and each
   tile carries a picture of what the STUDENT ends up with, because the
   difference between these options is structural and a sentence describing
   a layout is slower than seeing it.

   The visuals are WIREFRAMES, not screenshots: at tile size a real
   screenshot of a class page is unreadable grey mush, and it would go
   stale on the next CSS change. They are drawn by tg_wire() from two
   numbers, so they cannot drift out of sync with the description. A real
   screenshot dropped at img/guide-way<N>.png replaces one automatically.

   Overrides block (e)'s single-column .tguide-ways with a more specific
   selector; nothing above is edited.
   ========================================================================== */

.account-shell .tguide-ways {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  align-items: start;
}

/* The tile visual */
.tguide-shot {
  margin: 13px 0 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-elevated);
  overflow: hidden;
}
.tguide-shot .tg-wire,
.tguide-shot .tg-shot {
  display: block;
  width: 100%;
  height: auto;
}
.tguide-shot figcaption {
  padding: 7px 10px;
  border-top: 1px solid var(--border);
  font-size: 11.5px;
  color: var(--text-muted);
  text-align: center;
}

/* Wireframe parts. Accent = "this came from the teacher"; grey = the book. */
.tg-wire { padding: 8px 0; }
.tgw-band  { fill: var(--accent-tint); }
.tgw-title { fill: var(--text-faint); }
.tgw-label { fill: var(--text-faint); }
.tgw-label-on { fill: var(--accent); }
.tgw-card {
  fill: var(--bg-surface);
  stroke: var(--border-strong);
  stroke-width: 1;
}
.tgw-group {
  fill: var(--accent-tint);
  stroke: var(--accent);
  stroke-width: 1;
}
.tgw-ghost {
  fill: none;
  stroke: var(--border);
  stroke-width: 1;
  stroke-dasharray: 3 3;
}

/* Inside a tile the rows stack: 140px of label plus a column half as wide
   as before left the text in a gutter. */
.account-shell .tguide-ways .tguide-fit,
.account-shell .tguide-ways .tguide-rows {
  margin-left: 0;
}
.account-shell .tguide-ways .tguide-rows {
  grid-template-columns: 1fr;
  gap: 1px;
}
.account-shell .tguide-ways .tguide-rows dt { padding-top: 7px; }
.account-shell .tguide-ways .tguide-rows dd { max-width: none; }

@media (max-width: 760px) {
  .account-shell .tguide-ways { grid-template-columns: 1fr; }
}

/* ==========================================================================
   ADDITIONS 2026-08-04g — teacher guide: wider, level boxes, facts on top (Jen)
   --------------------------------------------------------------------------
   Three things, all from looking at the built page:

   1. The shared .account-shell is 640px, written for a single column of
      settings rows. A 2x2 inside it gave each tile ~300px and the copy
      wrapped every four or five words. Widened for THIS page only, the
      same way the signed-out account page already does it
      (.account-shell-signedout), so no other page moves.
   2. Block (f) set align-items: start, which let each tile stop at its own
      content and left one box in a row visibly shorter than its neighbour.
      Stretch makes both boxes in a row end level; the wireframe stays put
      at the top and the extra height falls below the text.
   3. With more width the label/value rows fit side by side again, which is
      what they were designed for in block (e).

   Same specificity as (f) and later in the file, so these win. Nothing
   above is edited.
   ========================================================================== */

.account-shell.tguide-shell {
  max-width: 1040px;
}

.account-shell .tguide-ways {
  align-items: stretch;
  gap: 18px;
}

/* Grid items stretch by default; the tile just has to be a column so the
   rows can sit at the top and the growth happen underneath them. */
.account-shell .tguide-ways > .tguide-way {
  display: flex;
  flex-direction: column;
  height: 100%;
}

@media (min-width: 900px) {
  .account-shell .tguide-ways .tguide-rows {
    grid-template-columns: 132px minmax(0, 1fr);
    gap: 7px 16px;
  }
  .account-shell .tguide-ways .tguide-rows dt { padding-top: 2px; }
}

/* ==========================================================================
   ADDITIONS 2026-08-04h — teacher guide: centred header, visuals removed (Jen)
   --------------------------------------------------------------------------
   Widening the shell to 1040px in block (g) left the title and the opening
   paragraph hugging the left edge with a third of the row empty beside
   them, which read as a broken column rather than a wide page. Centred,
   with the lead's own max-width doing the measure so the line length stays
   readable instead of running the full 1040px.

   The bulleted facts list and the option cards stay left aligned: centring
   a list of bullets or a label/value table hurts scanning.

   The .tguide-shot / .tg-wire / .tgw-* rules in blocks (e) and (f) are now
   DEAD — Jen dropped the wireframe diagrams from this page. Left in place
   rather than deleted, per the append-only rule; nothing renders them.
   ========================================================================== */

.account-shell.tguide-shell .acct-eyebrow,
.account-shell.tguide-shell .acct-h1,
.account-shell.tguide-shell .acct-subhead,
.account-shell.tguide-shell .tguide-lead {
  text-align: center;
}
.account-shell.tguide-shell .tguide-lead {
  margin-left: auto;
  margin-right: auto;
}
.account-shell.tguide-shell .tguide-cta {
  justify-content: center;
}

/* ==========================================================================
   ADDITIONS 2026-08-04i — teacher guide: facts bullets fill their box (Jen)
   --------------------------------------------------------------------------
   Block (e) capped .tguide-facts li at 70ch, which was right when the shell
   was 640px and wrong once block (g) widened it to 1040px: the bullets
   stopped two thirds of the way across and the box looked half empty. The
   card's own padding is the measure now.
   ========================================================================== */

.account-shell.tguide-shell .tguide-facts li {
  max-width: none;
}

/* ==========================================================================
   ADDITIONS 2026-08-05a — stick figures + mock carousel placeholder (Jen)
   --------------------------------------------------------------------------
   Jen's Stick Figure Project (89 drawings, D:\DCMDatabase\Stick Figure
   Project) starts appearing around the site. Two placements in this pass:

     .stick-signoff  bottom of a class/section page, above the footer.
                     PHP decides whether it renders at all — see
                     dcm_stick_rates() in includes/dcm_data.php.
     .stick-fork     over the homepage fork heading, returning users only.

   Sizing is capped on BOTH axes because the drawings' aspect ratios are all
   over the place: the cheering figures are wide (364x208) and the graph
   gags are portrait (1266x1640). Capping width alone would let y=x tower
   over the page. No raw hex anywhere, so both themes come free.

   .mock-carousel is a PLACEHOLDER and is meant to look like one — dashed
   border, muted label, no imagery. It is scaffolding for the personalized
   returning-user slides parked in OneDrive "Website stuff\memoryofusers\",
   and should be deleted wholesale when the real slides land.
   ========================================================================== */

.stick-signoff {
  display: flex;
  justify-content: center;
  margin: 46px auto 6px;
  padding: 0 20px;
}

.stick-signoff img {
  max-width: 280px;
  max-height: 200px;
  width: auto;
  height: auto;
  opacity: 0.92;
}

.stick-fork {
  display: flex;
  justify-content: center;
  margin: 0 0 10px;
}

.stick-fork img {
  max-width: 230px;
  max-height: 155px;
  width: auto;
  height: auto;
  opacity: 0.92;
}

/* ---- mock carousel (placeholder, delete with the real slides) ---- */

.mock-carousel {
  /* Sits at the TOP of the returning-user hero (Jen 2026-08-05), so the
     breathing room goes underneath it, before "Pick up where you left off". */
  margin: 0 auto 34px;
  max-width: 1040px;
  padding: 0 20px;
}

.mock-carousel-label {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  text-align: center;
  margin-bottom: 10px;
}

.mock-carousel-track {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}

.mock-slide {
  border: 1px dashed var(--border-strong);
  border-radius: 10px;
  background: var(--bg-surface);
  color: var(--text-muted);
  text-align: center;
  padding: 30px 16px;
  font-size: 15px;
}

@media (max-width: 700px) {
  .mock-carousel-track { grid-template-columns: 1fr; }
  .stick-signoff img   { max-width: 210px; max-height: 160px; }
  .stick-fork img      { max-width: 180px; max-height: 125px; }
}

/* ==========================================================================
   ADDITIONS 2026-08-05b — the homepage stick figure gets bigger (Jen)
   --------------------------------------------------------------------------
   "The stick figure on the hero page should be bigger."

   Raising block (a)'s max-width/max-height alone does NOT do it. The 51
   drawings have wildly different intrinsic sizes — 250x198 up to 492x449,
   aspect ratios 0.77 to 2.06 — and max-* only ever shrinks. A short figure
   sits well inside any cap and renders at its own small natural size, so
   raising the cap makes the big drawings bigger and leaves the small ones
   exactly as they were. That is what "12_y-equals-abs-x renders 250x227
   under a 380x250 cap" was telling us.

   So set the HEIGHT and let width follow. Every figure now occupies the
   same vertical band whatever its proportions, which is both bigger and
   more consistent than the caps were.

   No distortion risk: width:auto keeps the ratio, and max-width is only a
   safety net — the widest drawing (ratio 2.06) is 536px at this height,
   well inside the content column, so it never actually binds.

   The page-bottom .stick-signoff figure is deliberately NOT touched — Jen
   asked about the hero one. It has the same natural-size spread, so its
   rendered height still varies; worth a look if it reads unevenly.
   ========================================================================== */

.stick-fork img {
  height: 340px;
  width: auto;
  max-width: 100%;
  max-height: none;
}

@media (max-width: 700px) {
  .stick-fork img { height: 200px; max-width: 100%; }
}

/* ---- the page-bottom figure lines up with the left edge of the content ----
   Jen: "it should be aligned all the way to the left under that right-side
   grey box". Centred, it floated in the middle of a wide content column with
   nothing to relate to; flush left it hangs off the same edge as the video
   rows / chapter cards above it. Padding drops to 0 so the drawing's own box
   starts exactly where those grey boxes start. */

.stick-signoff {
  justify-content: flex-start;
  padding: 0;
}

/* ---- mock carousel: one slide at a time, rotating, in brand colours ----
   Replaces the three dashed grey boxes. Same shape as the real first-visit
   carousel (stacked slides, dots, prev/next) so the placeholder can be
   judged in motion. app.js initMockCarousel() drives it.

   ⚠ .mock-carousel-label and .mock-carousel-track in block (a) are now DEAD
   — no markup carries those classes any more. Left in place per the
   append-only rule, same as the .tguide-shot / .tg-wire remains from
   2026-08-04e. Nothing renders them. */

.mock-carousel-viewport {
  position: relative;
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  background: var(--accent-tint-soft);
  min-height: 132px;
}

.mock-carousel-viewport .mock-slide {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 26px 20px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s ease;
  /* reset the flat placeholder look from block (a) */
  border: 0;
  background: none;
}

.mock-carousel-viewport .mock-slide.is-active {
  opacity: 1;
  visibility: visible;
}

.mock-slide-eyebrow {
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent-text);
}

.mock-slide-title {
  font-size: 24px;
  font-weight: 600;
  color: var(--text-primary);
}

.mock-carousel-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 12px;
}

.mock-nav {
  background: none;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  color: var(--text-secondary);
  width: 28px;
  height: 28px;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}

.mock-nav:hover {
  border-color: var(--accent);
  color: var(--accent-text);
}

.mock-dots {
  display: flex;
  gap: 7px;
}

.mock-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--border-strong);
  cursor: pointer;
}

.mock-dot.is-active { background: var(--accent); }

@media (max-width: 700px) {
  .mock-slide-title { font-size: 19px; }
  .mock-carousel-viewport { min-height: 118px; }
}

/* ==========================================================================
   ADDITIONS 2026-08-05c - the placeholder reuses the real carousel (Jen)
   --------------------------------------------------------------------------
   "Let's reuse the carousel on the original page in terms of sizing but then
   just have it say placeholder for each." So #mock-carousel now carries the
   REAL carousel's classes - .carousel, .car-slide, .car-controls, .car-nav,
   .car-dots, .car-dot - and inherits its sizing for free: min-height 280px
   per slide, 340px on wide screens, same dots and same arrows. app.js scopes
   its queries to the mock root, so the two carousels never see each other's
   slides.

   Only two rules are needed on top: centre the word in a slide that is
   otherwise a two-column text/visual layout, and size the word itself.

   DEAD as of this block, left per the append-only rule: .mock-carousel-label
   and .mock-carousel-track from (a), and .mock-carousel-viewport,
   .mock-slide, .mock-slide-eyebrow, .mock-slide-title,
   .mock-carousel-controls, .mock-nav, .mock-dots, .mock-dot from (b).
   No markup carries any of those classes now. Worth one tidy-up pass with
   Jen's blessing rather than nine more overrides.
   ========================================================================== */

.mock-carousel .car-slide {
  justify-content: center;
}

/* A bordered box rather than a bare word, so the slide reads as the picture
   it is standing in for (Jen: "put a blue border around the placeholder so
   we get the effect of the image"). align-self:stretch beats .car-slide's
   align-items:center, so the box fills the slide's full 280/340px height and
   occupies the room a real slide would. --accent is the brand cyan and holds
   the same value in both themes, so the border works on light too. */
.mock-placeholder {
  flex: 1;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--accent);
  border-radius: 12px;
  background: var(--accent-tint-soft);
  font-family: Georgia, "Times New Roman", serif;
  font-size: 40px;
  color: var(--text-muted);
}

@media (max-width: 700px) {
  .mock-placeholder { font-size: 28px; }
}

/* ==========================================================================
   ADDITIONS 2026-08-05d - breathing room under the resume cards (Jen)
   --------------------------------------------------------------------------
   The hero figure moved from ABOVE the "Pick up where you left off" heading
   to BELOW the card grid, so block (a)'s "margin: 0 0 10px" now has the gap
   on the wrong side - the drawing sat right on top of the cards. Give it
   real space above, and keep some below so it does not crowd the fork
   heading underneath either.
   ========================================================================== */

.stick-fork {
  margin-top: 56px;
  margin-bottom: 34px;
}

@media (max-width: 700px) {
  .stick-fork { margin-top: 36px; margin-bottom: 22px; }
}

/* ---- and less space between the carousel and the heading under it ----
   Jen: "a little less space here". The gap measured 72px, from three
   places at once: 4px of .car-controls padding, 34px of block (a)'s
   .mock-carousel margin, and 32px of .section-head's own padding-top.
   Only the middle one is ours to change, so drop it and leave the shared
   .section-head rhythm alone. Lands at about 38px. */

.mock-carousel {
  margin-bottom: 2px;
}

/* ==========================================================================
   ADDITIONS 2026-08-05e - the account top row retiles itself (Jen)
   --------------------------------------------------------------------------
   "After 'what brings you here' is answered and goes away, this should
   automatically retile so the 2 top boxes are equal width and match the
   total width of the boxes below."

   The old grid was 3 fixed columns, so losing a top box left a dead third
   and pushed the layout out of alignment with the wider row underneath.
   The band above can now hold 2, 3 or 4 boxes:

     2  Profile | My classes                        (purpose answered, locked)
     3  + Stick figures  OR  + What brings you here
     4  both

   None of 2/3/4 divides 3 columns, but all of them divide TWELVE, so the
   grid goes to 12 and PHP writes the count into data-top. Each .acct-topbox
   takes an equal share, so the row is always full and always flush with
   "Saved for review" + "Your collections" below it (8 + 4 = 12).

   Overrides rather than edits, per the append-only rule: same specificity
   as the originals at line ~2185, later in the file, so these win.
   ========================================================================== */

.acct-grid {
  grid-template-columns: repeat(12, minmax(0, 1fr));
}

.acct-grid[data-top="2"] > .acct-topbox { grid-column: span 6; }
.acct-grid[data-top="3"] > .acct-topbox { grid-column: span 4; }
.acct-grid[data-top="4"] > .acct-topbox { grid-column: span 3; }

/* The wide row keeps its 2:1 feel: 8 + 4 of 12. */
#saved       { grid-column: span 8; }
#collections { grid-column: span 4; }

/* Two-up, then one-up. Mirrors what the 3-column version did at these
   widths - four boxes would be unreadably narrow on a tablet. */
@media (max-width: 900px) {
  .acct-grid[data-top="2"] > .acct-topbox,
  .acct-grid[data-top="3"] > .acct-topbox,
  .acct-grid[data-top="4"] > .acct-topbox { grid-column: span 6; }
  #saved       { grid-column: span 12; }
  #collections { grid-column: span 6; }
}

@media (max-width: 620px) {
  .acct-grid[data-top="2"] > .acct-topbox,
  .acct-grid[data-top="3"] > .acct-topbox,
  .acct-grid[data-top="4"] > .acct-topbox { grid-column: span 12; }
  #saved       { grid-column: span 12; }
  #collections { grid-column: span 12; }
}

/* ==========================================================================
   ADDITIONS 2026-08-05f - room around the suggest-a-figure toggle (Jen)
   --------------------------------------------------------------------------
   "More space between these." The <details> summary sat directly under the
   Save button with nothing between them, so the two read as one control
   group. Give the toggle its own air, and a rule above it so it reads as a
   separate thing you can open rather than part of the form.
   ========================================================================== */

.acct-stick-suggest {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}

.acct-stick-suggest > summary {
  cursor: pointer;
  color: var(--accent-text);
}

.acct-stick-suggest[open] > summary { margin-bottom: 12px; }

/* ==========================================================================
   ADDITIONS 2026-08-05g - widen the signed-out sign-up page (Jen)
   --------------------------------------------------------------------------
   "This is starting to look a little awkward, let's widen a bit."

   The 940px shell was set when the benefits list had FOUR short items. It
   is seven now, several of them two or three lines, so the left card grew
   very tall while the form stayed short - and because the pair is
   align-items:stretch (block 2026-08-03b), the right card inherited that
   height as dead space under the button. Widening shortens the list, which
   fixes both halves at once.

   The columns also stop being equal. The form has a fixed amount in it and
   was never the reason for the height; giving the prose the larger share is
   what actually shortens the page. At 1140px that is about 600px of text
   measure, which is wide but still inside a comfortable line length for a
   bulleted list.

   Overrides, not edits: same specificity as the originals at ~3658/3660,
   later in the file. The 720px single-column breakpoint is untouched and
   still wins, since it comes later in the cascade only for narrow screens.
   ========================================================================== */

.account-shell.account-shell-signedout { max-width: 1140px; }

.acct-split {
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: 30px;
}

@media (max-width: 900px) {
  .acct-split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; }
}

@media (max-width: 720px) {
  .acct-split { grid-template-columns: minmax(0, 1fr); gap: 18px; }
}

/* ==========================================================================
   ADDITIONS 2026-08-05h - centre the sign-up page header (Jen)
   --------------------------------------------------------------------------
   "Centre the top words now." At 940px the eyebrow, headline and sub sat
   close enough to the two cards below to read as one left-aligned column;
   at 1140px they hang off the left edge of a much wider page and the
   header stops feeling attached to anything.

   Scoped to .account-shell-signedout ONLY. The signed-in account page
   shares .acct-eyebrow / .acct-h1 / .acct-sub and is a 640px reading
   measure, where centring would be wrong.

   The sub also gets a measure of its own so it breaks somewhere sensible
   on a wide screen instead of running the full 1140px.
   ========================================================================== */

.account-shell.account-shell-signedout .acct-eyebrow,
.account-shell.account-shell-signedout .acct-h1,
.account-shell.account-shell-signedout .acct-sub {
  text-align: center;
}

.account-shell.account-shell-signedout .acct-sub {
  max-width: 68ch;
  margin-left: auto;
  margin-right: auto;
}

/* ==========================================================================
   ADDITIONS 2026-08-05i - close the gap under the mock carousel (Jen)
   --------------------------------------------------------------------------
   "Less space here." The gap from the carousel dots to the "Pick up where
   you left off" text measured 87px, and it was FOUR things stacked, not one:

       15px  the dots sit mid-row in .car-controls, whose 30px nav buttons
             set the row height
        2px  .mock-carousel margin-bottom
       28px  .home-hero padding-top
       10px  .resume-hero padding-top
       32px  .section-head padding-top

   Three of those are safe to trim because they only ever apply to the
   returning-student view. .home-hero's 28px is NOT touched: it also spaces
   the first-visit carousel, which no one has complained about, and taking
   it out here would move a screen Jen has already signed off.

   Lands at about 47px.
   ========================================================================== */

.mock-carousel { margin-bottom: 0; }

.mock-carousel .car-controls { padding-bottom: 0; }

.resume-hero { padding-top: 0; }

#resume-hero > .section-head { padding-top: 8px; }

/* ==========================================================================
   ADDITIONS 2026-08-05j - mobile nav drawer matches the desktop nav flow
   --------------------------------------------------------------------------
   The hamburger drawer (partials/page_bottom.php) rendered ONE fixed link
   set on every page — the COD class list plus Start here/Search/Sign in —
   no matter which of the desktop nav-row's three variants (cod/general/
   track) the page was actually on. It also always said "Sign in" even for
   a signed-in student, since the utility bar that normally carries the
   account link is hidden on mobile (rule at ~2010). page_bottom.php now
   switches on the same $nav_context/$nav_track the top nav uses and adds
   a signed-in Account/Sign out pair. The sign-out control is a form (state
   change, same as the desktop utility bar's), so it needs a button styled
   to sit flush in the item list instead of looking like a form control.
   ========================================================================== */

.nav-drawer-signout { margin: 0; }
.nav-drawer-signout .nav-drawer-item {
  width: 100%;
  text-align: left;
  background: transparent;
  border-radius: 0;
  font: inherit;
  cursor: pointer;
}

/* ==========================================================================
   ADDITIONS 2026-08-05k - COD classes disclose their chapters in the drawer
   --------------------------------------------------------------------------
   Mobile parity, final gap (Jen 2026-08-05: "mobile needs the same flow as
   the desktop"). The desktop COD nav has ten hover .nav-dropdown menus
   holding ninety chapter links; the drawer had none of them. It now renders
   each multi-chapter class as a <details>, so the chapters are one tap away
   instead of unreachable.

   The summary carries .nav-drawer-item so it inherits the row's padding,
   size, divider and hover. Only three things have to be added on top: kill
   the default disclosure triangle (which sits outside the padding and looks
   broken against a full-bleed row), lay the row out as flex so a caret can
   sit on the right where a phone user expects it, and rotate that caret when
   open.
   ========================================================================== */

.nav-drawer-class > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  cursor: pointer;
  list-style: none;
}

/* Safari/Chrome put the marker in a pseudo-element of its own. */
.nav-drawer-class > summary::-webkit-details-marker { display: none; }

.nav-drawer-class > summary::after {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.15s ease;
}

.nav-drawer-class[open] > summary::after {
  transform: rotate(-135deg) translate(-2px, -2px);
}

/* The chapter list is a nested block, so indent it a touch to read as a
   level down rather than as more top-level rows. */
.nav-drawer-class > .nav-drawer-sub { padding-left: 30px; }

.nav-drawer-open-all { color: var(--accent-text); }

/* ==========================================================================
   ADDITIONS 2026-08-05l - links inside static page copy
   --------------------------------------------------------------------------
   The reset sets `a { color: inherit; text-decoration: none }`, which is
   right for nav and cards but makes a link inside a paragraph invisible.
   The About page now points at the two contact forms from its last line, so
   prose links need to look like links. stickers.php solved the same problem
   with an inline style; this replaces the need for that.
   ========================================================================== */

.static-text a {
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.static-text a:hover { text-decoration-thickness: 2px; }

/* ==========================================================================
   ADDITIONS 2026-08-05m - wider About page + the full-width ride photo
   --------------------------------------------------------------------------
   "Expand the width." The static page was 1160px with a 5fr/6fr split, so
   the bio ran at roughly 430px - a very narrow measure for eight paragraphs,
   and the reason the text column looked like a column of confetti next to a
   tall photo. Wider shell, and the text takes the larger share now: prose is
   what needs the room, the portrait photo was never the constraint.

   .static-wide is the landscape ride photo. It sits under BOTH columns
   because it is 3:2 and would be shrunk to a stamp inside the right-hand
   column beside the portrait shot. Capped below the shell width so it reads
   as a photograph rather than a banner.
   ========================================================================== */

.static-page {
  max-width: 1320px;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 48px;
}

/* Same box as .static-page - identical max-width and padding - so the photo
   lines up with the copy above it instead of floating in its own measure
   (Jen: "both pictures should align with the words"). */
.static-wide {
  max-width: 1320px;
  margin: 8px auto 52px;
  padding: 0 22px;
}

/* And the portrait shot fills its grid column, so its edges meet the column
   the same way. 995px wide natively, so at a ~512px column it is still
   scaling DOWN - no upscaling blur. */
.static-media img { width: 100%; }

.static-wide img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12px;
}

.static-wide figcaption,
.static-media figcaption {
  margin-top: 10px;
  text-align: center;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--text-muted);
}

/* <figure> carries a UA margin; the grid already spaces this column. */
.static-media { margin: 0; }

@media (max-width: 900px) {
  .static-page { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   ADDITIONS 2026-08-05n - both About photos stack in one column (Jen)
   --------------------------------------------------------------------------
   "I want the two photos together in the same column." The ride shot moves
   out of its full-width slot below the copy and into .static-media, under
   the CB175. Both are figures now, so both carry a caption, and both fill
   the column so their edges still line up with each other and with the text.

   The landscape one lands around 500x334 in this column instead of 1276px
   wide. That is the trade Jen asked for: the pair reads as a set, at the
   cost of the big photo no longer being big.

   DEAD as of this block, left per the append-only rule: .static-wide and
   .static-wide img / figcaption from block (m). No markup carries that
   class any more.
   ========================================================================== */

.static-media {
  display: grid;
  gap: 26px;
  align-content: start;
}

.static-photo { margin: 0; }

.static-photo img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 10px;
}

.static-photo figcaption {
  margin-top: 10px;
  text-align: center;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--text-muted);
}

/* ==========================================================================
   ADDITIONS 2026-08-05o - give the sidecar photo more room (Jen)
   --------------------------------------------------------------------------
   "Make the sidecar photo a bit bigger." Stacking both shots in the media
   column left the landscape one at about 512x342 - it lost a lot when it
   came out of the full-width slot, and it is the photo with the most going
   on in it.

   Rather than widen the column (which would squeeze the prose back down,
   the thing the 08-05m widening was for), the ride photo breaks out of the
   column to the RIGHT by 130px. It is the last thing in the column and the
   page has margin to spare on that side at this width, so nothing collides.
   Clamped so the breakout shrinks to nothing before it can cause sideways
   scroll on a narrow screen, and dropped entirely once the layout stacks.
   ========================================================================== */

/* The breakout budget is the page's own outer margin, so the reference is
   the SHELL width (1320px), not an arbitrary number - getting that wrong
   pushed the photo 130px past a 1425px viewport and gave the page a
   sideways scrollbar. The extra 32px backs off far enough that a scrollbar
   counted into 100vw cannot tip it over either. */
.static-photo-wide {
  margin-right: calc(-1 * clamp(0px, (100vw - 1352px) / 2, 120px));
}

@media (max-width: 900px) {
  .static-photo-wide { margin-right: 0; }
}

/* ==========================================================================
   ADDITIONS 2026-08-05p - the karate figures get room to be readable (Jen)
   --------------------------------------------------------------------------
   "Make the karate chop one bigger." They were not styled small on purpose;
   they were being crushed. .stick-signoff caps every figure at 280px WIDE,
   which is fine from 0.77:1 up to 2.48:1 - the whole rest of the set - but
   the karate drawings run 2.52:1 to 3.78:1, so the cap bit on width and
   left them 280x74. A double integral in a 74px strip.

   PHP tags anything past dcm_stick_wide_ratio() (2.5, chosen because
   exactly the 19 karate figures clear it and nothing else does) with
   .stick-signoff-wide. Those get sized by HEIGHT instead, so the drawing
   grows sideways to whatever its own proportions want rather than being
   squeezed to a fixed width. max-width keeps it inside the content column
   on a narrow screen.

   Roughly 280x74 becomes 700x185 on a wide screen: the same figure, at a
   size where the maths can actually be read.
   ========================================================================== */

.stick-signoff-wide img {
  max-width: 100%;
  max-height: none;
  width: auto;
  height: 185px;
}

@media (max-width: 900px) {
  .stick-signoff-wide img { height: auto; width: 100%; }
}

/* ============================================================
   ADDITIONS 2026-08-08a — teacher mode (Jen)

   A slide toggle on the account page that says "lead with the teacher
   side". It is a VIEW PREFERENCE, never a permission — every teacher tool
   stays open to every account whichever way it sits — so nothing here may
   ever grow a disabled/locked look. Tokens only, both themes free.
   ============================================================ */

.acct-tmode-form { margin-top: 14px; padding-top: 14px;
                   border-top: 1px solid var(--border); }
.acct-tmode-row  { display: flex; align-items: center; gap: 14px;
                   justify-content: space-between; }
.acct-tmode-text { display: block; min-width: 0; }
.acct-tmode-text .acct-hint { margin-top: 2px; }

/* The switch is a submit button: one gesture, no separate Save. */
.acct-tmode-switch {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 9px;
  padding: 5px 12px 5px 6px; border: 1px solid var(--border-strong);
  border-radius: 999px; background: var(--bg-elevated);
  color: var(--text-secondary); font: inherit; font-size: 14px;
  cursor: pointer; transition: background .15s ease, border-color .15s ease,
                               color .15s ease;
}
.acct-tmode-switch:hover { border-color: var(--accent); color: var(--text-primary); }
.acct-tmode-switch:focus-visible { outline: 2px solid var(--accent);
                                   outline-offset: 2px; }

/* The track + knob. The knob slides on .is-on; the written On/Off beside it
   means the state is never carried by position or colour alone (WCAG:
   colour is never the only signal). */
.acct-tmode-knob {
  position: relative; display: inline-block; width: 34px; height: 20px;
  border-radius: 999px; background: var(--border-strong); flex: 0 0 auto;
  transition: background .15s ease;
}
.acct-tmode-knob::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--bg-surface); transition: transform .15s ease;
}
.acct-tmode-switch.is-on { border-color: var(--accent);
                           color: var(--text-primary); }
.acct-tmode-switch.is-on .acct-tmode-knob { background: var(--accent); }
.acct-tmode-switch.is-on .acct-tmode-knob::after { transform: translateX(14px); }
.acct-tmode-state { font-weight: 600; letter-spacing: .01em; }

.acct-tmode-note { margin-top: 10px; }

@media (prefers-reduced-motion: reduce) {
  .acct-tmode-switch, .acct-tmode-knob, .acct-tmode-knob::after {
    transition: none;
  }
}

/* The post-create offer on curate.php. Reuses .cf-status ok for the frame,
   so it reads as part of the same "class created" moment rather than as a
   second, competing banner. */
.curate-tmode-offer {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-top: 10px;
}
.curate-tmode-offer span { flex: 1 1 260px; }
.curate-tmode-offer button { flex: 0 0 auto; }

@media (max-width: 700px) {
  .acct-tmode-row { align-items: flex-start; gap: 10px; }
  .curate-tmode-offer button { width: 100%; }
}

/* ============================================================
   ADDITIONS 2026-08-08b — teacher mode moves out of the Profile card (Jen)

   "The toggle switch is not obvious." In a third-width grid box the label
   wrapped to six short lines and the switch read as a settings detail.
   It now sits FULL WIDTH directly under the "Teachers: use the For
   Teachers tab..." line — the sentence it belongs to — as a bordered band
   that the eye catches on its way down the page.

   Overrides the 08-08a rules with a more specific selector per the
   append-only rule; 08-08a still styles the switch itself.
   ============================================================ */

.acct-settings .acct-tmode-form {
  margin: 4px 0 22px; padding: 16px 18px; border-top: 0;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg-surface);
}
.acct-settings .acct-tmode-row {
  display: flex; align-items: center; gap: 20px;
  justify-content: space-between;
}
.acct-settings .acct-tmode-text { flex: 1 1 auto; }

/* Its own label class now — .acct-label is a grid-row label elsewhere and
   was making this read like a table cell. */
.acct-tmode-label {
  display: block; font-size: 17px; font-weight: 600;
  color: var(--text-primary); line-height: 1.3;
}
.acct-tmode-label + .acct-hint { margin-top: 3px; max-width: 62ch; }

/* Bigger target than the in-card version: this is a decision, not a
   preference buried in settings. */
.acct-settings .acct-tmode-switch { padding: 7px 16px 7px 8px; font-size: 15px; }
.acct-settings .acct-tmode-knob   { width: 42px; height: 24px; }
.acct-settings .acct-tmode-knob::after { width: 20px; height: 20px; }
.acct-settings .acct-tmode-switch.is-on .acct-tmode-knob::after {
  transform: translateX(18px);
}
.acct-settings .acct-tmode-note { margin-top: 12px; max-width: 78ch; }

@media (max-width: 700px) {
  .acct-settings .acct-tmode-row { flex-direction: column; align-items: stretch; gap: 12px; }
  .acct-settings .acct-tmode-switch { align-self: flex-start; }
}

/* ============================================================
   ADDITIONS 2026-08-08c — the teacher-mode toggle on teachers.php (Jen)

   Same switch, two placements, chosen by its own state: OFF leads the page
   as an offer, ON sits under the student-routes boxes as a way back out.
   The 08-08b band rules are scoped to .acct-settings (account.php only),
   so the band is restated here for the two teachers.php positions.
   ============================================================ */

.acct-tmode-form.tmode-lead,
.acct-tmode-form.tmode-tail {
  padding: 16px 18px; border-top: 0;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg-surface);
}
.acct-tmode-form.tmode-lead .acct-tmode-row,
.acct-tmode-form.tmode-tail .acct-tmode-row {
  display: flex; align-items: center; gap: 20px;
  justify-content: space-between;
}
.acct-tmode-form.tmode-lead .acct-tmode-text,
.acct-tmode-form.tmode-tail .acct-tmode-text { flex: 1 1 auto; }
.acct-tmode-form.tmode-lead .acct-tmode-switch,
.acct-tmode-form.tmode-tail .acct-tmode-switch { padding: 7px 16px 7px 8px; font-size: 15px; }
.acct-tmode-form.tmode-lead .acct-tmode-knob,
.acct-tmode-form.tmode-tail .acct-tmode-knob { width: 42px; height: 24px; }
.acct-tmode-form.tmode-lead .acct-tmode-knob::after,
.acct-tmode-form.tmode-tail .acct-tmode-knob::after { width: 20px; height: 20px; }
.acct-tmode-form.tmode-lead .acct-tmode-switch.is-on .acct-tmode-knob::after,
.acct-tmode-form.tmode-tail .acct-tmode-switch.is-on .acct-tmode-knob::after {
  transform: translateX(18px);
}
.acct-tmode-form.tmode-lead .acct-tmode-note,
.acct-tmode-form.tmode-tail .acct-tmode-note { margin-top: 12px; max-width: 78ch; }

/* Leading the page: an offer, so it carries a tint and the accent edge that
   the site already uses for "this one is for you". */
.acct-tmode-form.tmode-lead {
  margin: 18px 0 26px; background: var(--accent-tint-soft);
  border-color: var(--accent);
}

/* Under the boxes: settled, so it recedes. */
.acct-tmode-form.tmode-tail { margin: 26px 0 6px; }

@media (max-width: 700px) {
  .acct-tmode-form.tmode-lead .acct-tmode-row,
  .acct-tmode-form.tmode-tail .acct-tmode-row {
    flex-direction: column; align-items: stretch; gap: 12px;
  }
  .acct-tmode-form.tmode-lead .acct-tmode-switch,
  .acct-tmode-form.tmode-tail .acct-tmode-switch { align-self: flex-start; }
}

/* ============================================================
   ADDITIONS 2026-08-08d — dropdown whiteout + the toggle's note (Jen)

   BUG (Jen 2026-08-08, "Add to collection" on account.php): the popup list
   rendered white-on-white and one row read as a blank white bar.

   Cause: `.acct-inline-form select` sets `background: var(--bg-card)` and
   --bg-card IS NEVER DEFINED anywhere in this file. An unresolvable var()
   makes the whole declaration invalid, so the select had no background at
   all — fine while closed (the dark card shows through) but the popup is
   painted by the browser, which defaults to white, under text still set to
   var(--text-primary) = white.

   ⚠ --bg-card is used in FOUR other places (nav-dropdown hover, and three
   card-ish rows). They are all silently transparent for the same reason.
   NOT touched here: they have shipped looking the way they look, and
   defining the token would restyle four things nobody asked about. Flagged
   to Jen instead.

   Two fixes, belt and braces:
     1. color-scheme tells the browser which way to paint native widgets,
        which fixes popup lists, scrollbars and focus rings in one line.
     2. explicit option colours, because color-scheme alone is not honoured
        for <option> backgrounds everywhere.
   ============================================================ */

[data-theme="dark"]  { color-scheme: dark; }
[data-theme="light"] { color-scheme: light; }

select option,
select optgroup {
  background-color: var(--bg-elevated);
  color: var(--text-primary);
}
/* The one the bug was reported on: give the control itself a real surface
   so the closed state and the popup agree. */
.acct-inline-form select { background: var(--bg-elevated); }

/* The teacher-mode note's trailing clause is swapped by CSS, not PHP, so
   app.js can flip the switch in place without re-rendering the page. */
.acct-tmode-note-on  { display: none; }
.acct-tmode-form.is-on .acct-tmode-note-on  { display: inline; }
.acct-tmode-form.is-on .acct-tmode-note-off { display: none; }

/* ============================================================
   ADDITIONS 2026-08-08e — the toggle keeps each page's rhythm (Jen)

   "The spacing between the boxes is not the same — make it uniform."
   The margins in 08-08b/c were tuned for the toggle's ORIGINAL positions
   (under the "Teachers:" line, and under the intro boxes). Now that it sits
   among the real cards on both pages it has to match their gaps, and the
   two pages do not use the same one:

     account.php   .acct-grid gap        = 16px
     teachers.php  .acct-section to next = 28px

   So the target is per page, not one number. Measured, not guessed.
   ============================================================ */

/* account.php: 16px above and below, so the band reads as one more card in
   the stack. Sign out / Delete keeps its own 28px elsewhere, but directly
   under the toggle it comes down to 16 for the same reason. */
.acct-settings .acct-tmode-form { margin: 16px 0 0; }
.acct-settings .acct-tmode-form + .acct-section.acct-danger { margin-top: 16px; }

/* teachers.php: the section boxes above it are 28px apart. Nothing follows
   it, so no bottom margin — the shell's own padding closes the page. */
.acct-tmode-form.tmode-tail { margin: 28px 0 0; }

/* ============================================================
   ADDITIONS 2026-08-08f — the real returning-visitor slides (Jen)

   Replaces the 2026-08-05 mock placeholder. The mock inherited the
   first-visit carousel's full 280/340px hero height because it was standing
   in for a picture; these slides are short text and a link, so they read as
   a STRIP — which is what Jen leaned toward in the first place ("big
   two-column hero, or a slimmer strip? Leaning strip").

   DEAD as of this block, left per the append-only rule: .mock-carousel and
   .mock-placeholder from 08-05a/c, plus everything 08-05c already listed as
   dead. No markup carries any of them now.
   ============================================================ */

.home-slides {
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--bg-surface);
  padding: 4px 22px 10px;
  margin: 0 0 26px;
}

/* Override the hero height: a nudge is not a hero. */
.home-slides .car-slide {
  min-height: 0;
  align-items: flex-start;
  padding: 18px 0 6px;
}
.home-slides .hs-text { flex: 1 1 auto; }

.hs-title {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 26px;
  line-height: 1.22;
  color: var(--text-primary);
  margin: 6px 0 0;
}
.hs-body {
  margin: 8px 0 0;
  max-width: 68ch;
  color: var(--text-secondary);
  line-height: 1.55;
}
.home-slides .hs-cta { display: inline-block; margin-top: 14px; }

/* One slide left after the guest filter: a card, not a carousel. app.js
   adds .is-single and skips the dots, the arrows and the rotation. */
.home-slides.is-single .car-controls { display: none; }
.home-slides.is-single .car-slide { padding-bottom: 16px; }

@media (max-width: 700px) {
  .home-slides { padding: 2px 16px 8px; margin-bottom: 20px; }
  .hs-title { font-size: 22px; }
  .hs-body { font-size: 15px; }
}

/* ============================================================
   ADDITIONS 2026-08-08g — the slide strip joins the page column (Jen)

   "The carousel is broken and too big."

   BROKEN = full bleed. The first-visit carousel is constrained because it
   lives INSIDE .home-hero, which carries `max-width: 980px; margin: 0 auto`.
   This strip is a direct child of <body> — it has to be, so it can clear
   the Teaching section — so it inherited nothing and ran the whole window
   width while every other block sat at 980. The mock had the same bug and
   hid it: its big blue box filled the space, so it read as deliberate.

   Now matched to .home-greeting / .home-hero / .teach-grid exactly: 980
   wide, centred.

   TOO BIG = it was still carrying hero-sized padding and a 26px title for
   three lines of text. Tightened throughout.
   ============================================================ */

.home-slides {
  max-width: 980px;
  margin: 0 auto 22px;
  padding: 2px 20px 6px;
}

.home-slides .car-slide { padding: 14px 0 4px; }
.home-slides .hs-title  { font-size: 22px; margin-top: 4px; }
.home-slides .hs-body   { margin-top: 6px; max-width: 66ch; }
.home-slides .hs-cta    { margin-top: 10px; }

/* The dots sat in their own band under the slide. Pull them up. */
.home-slides .car-controls { margin-top: 2px; }

@media (max-width: 1040px) {
  .home-slides { margin-left: 24px; margin-right: 24px; }
}
@media (max-width: 700px) {
  .home-slides { margin-left: 16px; margin-right: 16px; padding: 2px 14px 6px; }
  .home-slides .hs-title { font-size: 20px; }
}

/* --- 08-08g continued: the last of the height is chrome, not copy ---
   Of the 219px, the slide's own text was ~145 and the rest was spacing:
   the shared .eyebrow carries a 14px bottom margin sized for hero slides,
   and .car-controls is a 44px band built for a full-width carousel. Both
   come down here rather than shortening Jen's copy. */

.home-slides .eyebrow      { margin-bottom: 4px; }
.home-slides .car-controls { padding: 2px 0 0; }
.home-slides .car-slide    { padding: 12px 0 2px; }

/* ============================================================
   ADDITIONS 2026-08-08h — visuals in the slide strip (Jen)

   "I think it needs some sort of visual to go with it, so even if a user
   does not click on the carousel they have an impression of what the
   feature is and to try it."

   So the picture carries the slide for anyone who does not read it. These
   are COMPACT renderings of the approved 2026-08-03 carousel art — the
   first-visit carousel builds 280px+ hero compositions from the same files,
   which would undo the height work in 08-08g. Same assets, smaller frame,
   capped so a slide can never outgrow the strip.

   Five slides have no art yet (shot list in includes/dcm_slides.php) and
   render text-only; .hs-text stretching to full width is what makes that
   read as intentional rather than broken.
   ============================================================ */

.home-slides .car-slide { gap: 26px; }
.hs-visual {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  align-self: center;
  max-height: 132px;
}

/* A single screenshot: the book chapter list, a page of notes. */
.hs-shot {
  max-height: 132px; width: auto;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: var(--bg-elevated);
}
/* The notes page is portrait and mostly white — a touch smaller so it does
   not shout louder than the copy. */
.hs-shot-paper { max-height: 120px; }

/* Laptop + phone, the phone overlapping like the hero version. */
.hs-dev { position: relative; padding-right: 26px; }
.hs-dev-laptop { display: block; height: 116px; width: auto; border-radius: 6px; }
.hs-dev-phone {
  position: absolute; right: 0; bottom: -8px;
  height: 84px; width: auto; border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .45);
}

/* One of Jen's own drawings. Taller than the screenshots: it is line art on
   transparent, so it reads small. */
.hs-stick { height: 138px; width: auto; }

@media (max-width: 860px) {
  /* Stack rather than squeeze: a 100px-wide screenshot shows nothing. */
  .home-slides .car-slide { flex-direction: column; align-items: flex-start; gap: 14px; }
  .hs-visual { justify-content: flex-start; align-self: flex-start; max-height: 108px; }
  .hs-shot { max-height: 104px; }
  .hs-shot-paper { max-height: 96px; }
  .hs-dev-laptop { height: 92px; }
  .hs-dev-phone { height: 66px; }
  .hs-stick { height: 104px; }
}

/* --- 08-08h continued: the drawing was outgrowing the strip ---
   .hs-stick at 138px made the slide taller than its own text and pushed the
   strip to 308. The figures are line art on transparent, so they read fine
   smaller; 112 puts the visual just under the text block's height. */
.home-slides .hs-stick { height: 112px; }

/* --- 08-08h continued: undo the hero visual panel ---
   .car-visual is built for the first-visit carousel: min-height 250px, 20px
   padding and its own --bg-surface panel. In this strip that forced every
   slide to 308px tall around a 120px image (min-height beats max-height,
   so the 08-08h cap could not win), and painted a surface panel inside a
   surface panel. Strip out the panel; keep only the sizing this needs. */
.home-slides .hs-visual {
  min-height: 0;
  padding: 0;
  background: none;
  border-radius: 0;
  gap: 0;
}

/* ============================================================
   ADDITIONS 2026-08-08i — control mockups in the slide strip (Jen)

   Jen picked five crops by screenshotting the controls she wants students
   to recognise. These rebuild each control from the site's own tokens
   instead of pasting a raster: sharp at any size, correct in BOTH themes,
   and no 300KB of PNG. A 'shot:' slide can replace any of them later — the
   .hs-shot rules already handle that.

   Everything is .hs-ui-* and used nowhere else, so nothing here can leak
   into the real components it imitates.
   ============================================================ */

.hs-ui {
  display: flex; flex-direction: column; gap: 5px;
  width: 300px; padding: 12px 14px;
  border: 1px solid var(--border-strong); border-radius: 10px;
  background: var(--bg-elevated);
  font-size: 11.5px; line-height: 1.35; color: var(--text-secondary);
  /* Slightly back from the copy: it is an illustration, not a control. */
  transform: scale(.98);
}
.hs-ui-h {
  font-size: 13px; font-weight: 600; color: var(--text-primary);
  line-height: 1.3;
}
.hs-ui-eyebrow, .hs-ui-kicker {
  font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--accent-text); font-weight: 700;
}
.hs-ui-meta, .hs-ui-label { font-size: 10.5px; color: var(--text-muted); }
.hs-ui-line {
  font-size: 11px; color: var(--text-secondary);
  padding-top: 5px; border-top: 1px solid var(--border);
}

/* The bit the slide is actually pointing at. */
.hs-ui-hi { color: var(--accent-text); font-weight: 700; }

.hs-ui-btns { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.hs-ui-btn {
  display: inline-block; padding: 5px 9px; border-radius: 999px;
  border: 1px solid var(--border-strong); font-size: 10.5px;
  color: var(--text-secondary); white-space: nowrap;
}
.hs-ui-btn.is-primary {
  background: var(--accent); color: var(--accent-on-bg);
  border-color: var(--accent); font-weight: 600;
}

/* The starred video row. */
.hs-ui-star { flex-direction: row; align-items: center; gap: 10px; }
.hs-ui-thumb {
  flex: 0 0 auto; width: 64px; height: 40px; border-radius: 5px;
  background: var(--accent-tint-soft); border: 1px solid var(--accent);
}
.hs-ui-rowtext { display: flex; flex-direction: column; gap: 3px; min-width: 0; }

/* Form-ish rows for the create-a-class card. */
.hs-ui-input {
  padding: 5px 8px; border: 1px solid var(--border-strong);
  border-radius: 5px; background: var(--bg-surface);
  color: var(--text-muted); font-size: 10.5px;
}
.hs-ui-input.is-select::after { content: " \25BE"; }
.hs-ui-card .hs-ui-btn { align-self: flex-start; margin-top: 3px; }

/* The rate radios. */
.hs-ui-radio { display: flex; align-items: center; gap: 7px; font-size: 11px; }
.hs-ui-radio i {
  width: 11px; height: 11px; border-radius: 50%;
  border: 1.5px solid var(--border-strong); flex: 0 0 auto;
}
.hs-ui-radio.is-on i { border-color: var(--accent); background: var(--accent); }
.hs-ui-radio.is-on { color: var(--text-primary); }

@media (max-width: 860px) {
  .hs-ui { width: 260px; transform: none; }
}

/* ============================================================
   ADDITIONS 2026-08-08j — Jen's pass over the slide visuals

   Four notes, all from looking at admin/slides-preview.php:
     - the devices pair needed the OG sync arc back
     - "put a box or some other way to make this clear what we are looking
       at" → a focus ring on the one control each slide is about
     - the curate slide needed visibly UNCHECKED rows
     - the textbook slide needed the PICKER, not a chapter list
   ============================================================ */

/* ---- the laptop tied to the phone ---- */
.hs-dev { position: relative; padding: 22px 26px 0 0; }
.hs-dev-arc {
  position: absolute; top: 0; left: 0; width: 100%; height: 46px;
  overflow: visible; pointer-events: none;
}

/* ---- "this is the bit" ---- */
.hs-ui-focus {
  position: relative;
  outline: 1.5px solid var(--accent);
  outline-offset: 3px;
  border-radius: 5px;
}
/* On a filled button the outline needs air, not a second border. */
.hs-ui-btn.hs-ui-focus { outline-offset: 2px; }

/* ---- the curate tree: unchecked rows are the message ---- */
.hs-ui-check, .hs-ui-book {
  display: flex; align-items: flex-start; gap: 7px;
  font-size: 11px; color: var(--text-muted); line-height: 1.3;
}
.hs-ui-check i, .hs-ui-book i {
  flex: 0 0 auto; width: 11px; height: 11px; margin-top: 1px;
  border: 1.5px solid var(--border-strong); border-radius: 3px;
}
.hs-ui-check.is-on, .hs-ui-book.is-on { color: var(--text-primary); }
.hs-ui-check.is-on i, .hs-ui-book.is-on i {
  background: var(--accent); border-color: var(--accent);
}
/* The tick. Drawn, not a glyph, so it stays crisp at 11px. */
.hs-ui-check.is-on i::after, .hs-ui-book.is-on i::after {
  content: ""; display: block; width: 3px; height: 6px;
  margin: 0 auto; border: solid var(--accent-on-bg);
  border-width: 0 1.5px 1.5px 0; transform: rotate(45deg) translate(-1px, -1px);
}
.hs-ui-book i { border-radius: 50%; }
.hs-ui-books .hs-ui-book { padding: 2px 0; }

/* ---- the feedback form ---- */
.hs-ui-area {
  height: 30px; border: 1px solid var(--border-strong);
  border-radius: 5px; background: var(--bg-surface);
}

@media (max-width: 860px) {
  .hs-dev { padding-top: 18px; }
}

/* ============================================================
   ADDITIONS 2026-08-08k — the device graphic is the OG one, and two
   mockups say what they mean (Jen)

   Jen: "this doesn't look like the same graphic from the OG hero." It
   wasn't — the compact version used the bare PNGs and lost the laptop
   chassis, the base, the phone bezel and the notch, which are the parts
   that make them read as devices. The partial now carries the hero's own
   .car-dev markup, so ALL it needs here is a width: .car-dev is
   percentage-based over aspect-ratio 340/230 and scales itself.
   ============================================================ */

.hs-visual .car-dev { width: 196px; max-width: 196px; margin: 0; }

/* ---- "You create your own lists" ---- */
.hs-ui-listrow {
  display: flex; flex-direction: column; gap: 1px;
  padding: 5px 0; border-top: 1px solid var(--border);
}
.hs-ui-listrow b { font-size: 11.5px; color: var(--text-primary); font-weight: 600; }
.hs-ui-listrow em { font-style: normal; font-size: 10px; color: var(--text-muted); }
.hs-ui-card .hs-ui-btn { white-space: nowrap; }

/* ---- teacher groups above the chapters ---- */
.hs-ui-chips { display: flex; gap: 5px; flex-wrap: wrap; margin: 2px 0 4px; }
.hs-ui-chip {
  font-style: normal; font-size: 10px; padding: 3px 8px;
  border-radius: 999px; border: 1px solid var(--accent);
  background: var(--accent-tint-soft); color: var(--accent-text);
  white-space: nowrap;
}

/* ---- the no-book option in the picker ---- */
.hs-ui-book-none { margin-top: 3px; padding-top: 6px;
                   border-top: 1px solid var(--border); }
.hs-ui-book-none em { font-style: normal; color: var(--text-muted); }

@media (max-width: 860px) {
  .hs-visual .car-dev { width: 168px; }
}

/* ============================================================
   ADDITIONS 2026-08-08l — the slide strip is hero-sized (Jen)

   "The carousel should be as big as the OG first visitor carousel."

   Blocks 08-08f/g/h shrank it to a ~193px strip, which was the right call
   while the slides were three lines of text and no picture. Now that every
   slide carries a visual, it is the same kind of thing as the first-visit
   carousel and should read at the same weight.

   So this restores the hero geometry that .carousel already defines and
   those blocks were overriding: 340px panel and slide (08-03k), 40px serif
   title, 15.5px body capped at 430px. The strip keeps its own bordered
   surround and its 980px column — only the INSIDE grows.

   ⚠ Dead as of this block: the sizing halves of 08-08f/g/h. Left in place
   per the append-only rule, and they still carry the reasoning for why the
   strip exists at all.
   ============================================================ */

.home-slides { padding: 6px 24px 10px; margin: 0 auto 26px; }

.home-slides .car-slide {
  min-height: 340px; padding: 10px 6px;
  align-items: center; gap: 34px;
}
.home-slides .hs-text { flex: 1.2; }
.home-slides .eyebrow { margin-bottom: 0; }
.home-slides .hs-title {
  font-size: 40px; line-height: 1.08; margin: 10px 0 0;
}
.home-slides .hs-body {
  font-size: 15.5px; line-height: 1.55; margin: 14px 0 0; max-width: 430px;
}
.home-slides .hs-cta { margin-top: 16px; font-size: 15px; }
.home-slides .car-controls { margin-top: 0; padding: 10px 0 4px; }

/* The visual panel goes back to being a panel — .car-visual's own surface,
   padding and 340px height, which 08-08h had stripped out. */
.home-slides .hs-visual {
  flex: 1; height: 340px; min-height: 0; max-height: none;
  flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 20px;
  background: var(--bg-surface); border-radius: 10px;
}

.home-slides .hs-shot,
.home-slides .hs-shot-paper { max-height: 280px; }
.home-slides .hs-stick { height: 250px; }
.home-slides .hs-visual .car-dev { width: 100%; max-width: 320px; }

/* The control mockups scale as a unit rather than re-specifying a dozen
   font sizes: they are pure CSS, so a transform keeps every border, dot
   and tick crisp and in proportion. */
.home-slides .hs-ui { transform: scale(1.16); transform-origin: center; }

@media (max-width: 860px) {
  /* Match the OG's phone behaviour: shorter panel, slide free to shrink. */
  .home-slides .car-slide { min-height: 0; flex-direction: column;
                            align-items: flex-start; gap: 16px; }
  .home-slides .hs-visual { height: 220px; width: 100%; }
  .home-slides .hs-title { font-size: 26px; }
  .home-slides .hs-stick { height: 170px; }
  .home-slides .hs-shot, .home-slides .hs-shot-paper { max-height: 170px; }
  .home-slides .hs-ui { transform: none; }
}

/* 08-08l continued: 1.16 left the mockups looking small inside a 424x340
   panel. 1.24 puts them at 372 wide against 384 of usable room and 225 tall
   against 300 — filling the panel without touching its padding. Measured,
   not guessed; the tallest mockup is the feedback form. */
.home-slides .hs-ui { transform: scale(1.24); }

/* ============================================================
   ADDITIONS 2026-08-08m — the batch checkboxes are findable (Jen)

   "Make the checkboxes to the left of the videos more visible. Maybe blue
   outline instead of light gray?"

   They were `1.5px solid var(--border-strong)` — which is #2A2A2A on the
   dark theme, i.e. a near-black box on a near-black row. You had to know it
   was there. An empty checkbox is the whole affordance in batch mode, so it
   has to read at a glance.

   Accent outline plus a faint accent wash, so it looks like a target rather
   than an outline someone forgot to fill. The CHECKED state is unchanged:
   solid accent with the tick, which already worked.

   Select-all comes along for the ride — it is the same control family two
   inches away, and leaving it grey while the rows go blue looks like a bug.
   ============================================================ */

.vrow-main .vrow-cb {
  border-color: var(--accent);
  background: var(--accent-tint-soft);
}
/* Hovering the row is a strong hint you can click the box. */
.is-batch-mode .vrow:hover .vrow-cb { background: var(--accent-tint); }

.is-batch-mode .vrow-main .vrow-cb.is-checked {
  background: var(--accent);          /* keep the filled state as it was */
}

.batch-bar .select-all .checkbox {
  border-color: var(--accent);
  background: var(--accent-tint-soft);
}
.batch-bar .select-all.is-checked .checkbox {
  background: var(--accent);
  border-color: var(--accent);
}
.batch-bar .select-all.is-checked .checkbox svg { stroke: var(--accent-on-bg); }

/* ============================================================
   ADDITIONS 2026-08-08n — Select all stops pretending, and the batch
   buttons wait their turn (Jen)

   1. "The Select all checkbox appears to be checked by default."

   It never was — no code checks it, aria-pressed is false and the count
   reads 0. The tick was simply always PAINTED: .vrow-cb got a
   `svg { display: none }` rule so its tick only shows when checked, and
   .select-all never got the equivalent. Its tick inherits currentColor,
   which on that control is --text-primary, so an unchecked box has been
   drawing a white checkmark since the batch bar shipped. Block 08-08m's
   accent outline just made the box prominent enough to notice.

   2. "Disable/gray out the print, download, download ms word buttons until
   the user selects at least one file."

   batchAction() already returned early on an empty selection, so those
   buttons did nothing — they just didn't look like it, which reads as a
   broken site rather than as "pick something first". app.js now toggles
   the disabled attribute; this is what it looks like.
   ============================================================ */

/* The tick belongs to the checked state, same as the row checkboxes. */
.select-all .checkbox svg { display: none; }
.select-all.is-checked .checkbox svg { display: block; }

.batch-bar .btn-primary[disabled] {
  background: var(--bg-elevated);
  color: var(--text-muted);
  border: 1px solid var(--border-strong);
  cursor: not-allowed;
}
/* :hover brightness on a grey button reads as "it did something". */
.batch-bar .btn-primary[disabled]:hover { filter: none; }

/* ============================================================
   ADDITIONS 2026-08-08o — changing your email address (Jen)

   ⚠ This is the credential. No passwords exist here, so the address on
   file is the only way back into an account — which is why the control
   sits behind a <details> instead of being a field a student can edit by
   accident, and why the pending state is loud rather than subtle.
   ============================================================ */

.acct-emailchange { margin-top: 14px; padding-top: 12px;
                    border-top: 1px solid var(--border); }
.acct-emailchange > summary {
  cursor: pointer; font-size: 13px; color: var(--accent-text);
  list-style: none;
}
.acct-emailchange > summary::-webkit-details-marker { display: none; }
.acct-emailchange > summary::before { content: "\25B8 "; }
.acct-emailchange[open] > summary::before { content: "\25BE "; }
.acct-emailchange > summary:hover { text-decoration: underline; }
.acct-emailchange .acct-form { margin-top: 10px; }

/* Pending: deliberately the loudest thing in the card. Someone who did not
   ask for this needs to see it the moment they open the page. */
.acct-emailpending {
  margin-top: 14px; padding: 12px 14px;
  border: 1px solid var(--accent); border-radius: 8px;
  background: var(--accent-tint-soft);
  display: flex; flex-direction: column; gap: 6px;
  font-size: 13px; line-height: 1.45;
}
.acct-emailpending b { color: var(--text-primary); }
.acct-emailpending span { color: var(--text-secondary); }
.acct-emailpending .acct-inline-form { margin-top: 2px; }

/* ============================================================
   ADDITIONS 2026-08-08p — take the air out of the slide strip (Jen)

   "Make this a little less tall."

   08-08l matched the first-visit carousel's 340px, which is right for a
   hero carrying a photo but leaves ~58px of dead space around three lines
   of text and a small mockup. Measured across all eleven slides: the
   tallest content is 282px (t-nogroups, whose title wraps to three lines)
   and the tallest artwork is the stick figure at 250.

   296 clears the tallest by 14px. Not smaller, because the height is FIXED
   rather than fitted on purpose — 08-03h had to add exactly this to the
   original carousel after the panel visibly grew and shrank as the slides
   cycled. A slide with unusually tall text still grows past it (min-height,
   not height, on the slide); the panel stays put and centres.

   The stick figure comes down 250 -> 228 so the art is never the thing
   pressing on the ceiling — the text should be.
   ============================================================ */

.home-slides .car-slide  { min-height: 296px; }
.home-slides .hs-visual  { height: 296px; }
.home-slides .hs-stick   { height: 228px; }
.home-slides .hs-shot,
.home-slides .hs-shot-paper { max-height: 244px; }

@media (max-width: 860px) {
  /* The phone layout already stacks and sets its own heights; nothing to
     trim there, but keep the slide free to shrink. */
  .home-slides .car-slide { min-height: 0; }
}

/* 08-08p continued: the last of it is chrome again.
   Strip 378 = slide 296 + slide padding 20 + dots band 44 + strip padding
   16. The 296 is a real floor — the tallest slide's title wraps to three
   40px lines — so the only fat left is the band and the padding. */
.home-slides { padding: 2px 24px 4px; }
.home-slides .car-slide { padding: 6px 6px 2px; }
.home-slides .car-controls { padding: 2px 0 0; }

/* ============================================================
   ADDITIONS 2026-08-08q — "Go to the old website" (Jen)

   A quiet line at the foot of the homepage for longtime students who know
   the Squarespace site and cannot find something here yet. Deliberately
   understated: it is an escape hatch, not a destination, and it should not
   compete with the fork cards above it.
   ============================================================ */

.home-oldsite {
  max-width: 980px;
  margin: 34px auto 8px;
  padding: 0 24px;
  text-align: center;
  font-size: 13.5px;
  color: var(--text-muted);
}
.home-oldsite a { color: var(--accent-text); font-weight: 600; }
.home-oldsite a:hover { text-decoration: underline; }

@media (max-width: 700px) {
  .home-oldsite { margin-top: 26px; padding: 0 16px; font-size: 13px; }
}

/* ============================================================
   ADDITIONS 2026-08-08r — define --bg-card, which never existed (Jen)

   The token is used five times and was declared nowhere, so every one of
   those `background` declarations was invalid and silently dropped. Four
   were harmlessly transparent; the fifth painted the "Add to collection"
   dropdown white-on-white and hid a real collection (08-08d fixed that one
   by hand). Defining it makes the other four do what they were written to
   do: the nav-dropdown hover, the starred-video row, a chip, and the
   teacher-guide "two ways in" boxes.

   Given a value rather than aliased, because neither existing surface token
   works: --bg-surface and --bg-elevated are BOTH #FFFFFF on the light
   theme, so a hover using either would be invisible there. This is a
   deliberate half-step above the surface in each theme.
   ============================================================ */

[data-theme="dark"]  { --bg-card: #1A1A1A; }
[data-theme="light"] { --bg-card: #F1EFE8; }

/* ============================================================
   ADDITIONS 2026-08-08s — the drawer's sign-in link goes last, and bold

   Jen: "move the save your spot/sign in option in the hamburger menu all
   the way to the bottom and bold it." It had been sitting above About /
   Stickers / Say Hi / Feedback, which buried the only item on that menu
   that is a call to action rather than a destination.

   Bold and full-strength text, against .nav-drawer-sub's 12.5px secondary
   grey. Only the SIGNED-OUT link gets this — "Hi, <name> · Account" is a
   destination, and bolding it would make every signed-in student's own
   name the loudest thing in the menu.
   ============================================================ */

.nav-drawer-cta {
  font-weight: 700;
  color: var(--text-primary);
  margin-top: 4px;
}

/* ============================================================
   ADDITIONS 2026-08-08t — the one-time nickname ask (Jen)

   The "what should we call you?" field came off the sign-in form; the
   question now appears once, on the welcome screen, right after a new
   account's first sign-in. Skippable — making it required would just move
   the mandatory field one screen later, which is the opposite of the
   2026-07-18 decision that a signup is an email and nothing else.
   ============================================================ */

.acct-nameask {
  margin: 18px 0 4px;
  padding: 16px 18px;
  border: 1px solid var(--accent);
  border-radius: 12px;
  background: var(--accent-tint-soft);
  max-width: 520px;
}
.acct-nameask .acct-form { margin: 0; }
.acct-nameask-actions {
  display: flex; align-items: center; gap: 16px; margin-top: 12px;
}
/* "Skip for now" reads as a way out, not a second button — a student who
   does not want to give a name should not have to weigh two CTAs. */
.acct-nameask-actions .acct-alt {
  color: var(--text-muted); font-size: 13px;
}
.acct-nameask-actions .acct-alt:hover { color: var(--text-secondary); }

@media (max-width: 560px) {
  .acct-nameask { padding: 14px; }
  .acct-nameask-actions { flex-direction: column; align-items: stretch; gap: 10px; }
  .acct-nameask-actions .acct-alt { text-align: center; }
}

/* ============================================================
   ADDITIONS 2026-08-08u — the numbered membership badge

   Jen 2026-08-08, from the mockups: members are numbered in signup
   order and the badge is coloured by bracket. Gold 1-50, brand cyan
   51-100, plain after that. The bounds are in dcm_config.php; the
   colours are here, and the two must be changed together.

   Two shapes, one colour scheme:
     .mem-badge  the ring + two lines, on the account profile card
                 and the welcome screen (partials/member_badge.php)
     .mem-pill   the short chip beside "Welcome back, <name>" on the
                 homepage (built inline in index.php)

   ⚠ WHY THERE ARE NEW COLOUR TOKENS HERE. Gold is not in the palette
   — the site had one accent and it is cyan. #E8B22B is the warm
   counterpart of #2BB5E8 (same saturation and lightness, hue turned
   round) so the two brackets read as one family rather than two
   unrelated colours. It is declared as a token, not sprayed as hex,
   so the light theme can override it in one place.

   ⚠ THE THIRD TIER IS NOT WHITE ON THE LIGHT THEME. Jen asked for
   white for 101+, and white on #FAFAF6 is invisible. Her call on the
   mockup was "flip to ink": white on the dark theme, near-black on
   the light one. So --mem-plain is a TOKEN, not the literal #FFF.
   Anyone hardcoding white here breaks the light theme silently, and
   only for the third bracket, which is the one nobody tests.
   ============================================================ */
:root,
[data-theme="dark"] {
  --mem-gold:       #E8B22B;
  --mem-gold-tint:  rgba(232, 178, 43, 0.14);
  --mem-gold-line:  rgba(232, 178, 43, 0.40);
  --mem-cyan:       var(--accent);
  --mem-cyan-tint:  var(--accent-tint);
  --mem-cyan-line:  rgba(43, 181, 232, 0.40);
  --mem-plain:      #FFFFFF;
  --mem-plain-tint: rgba(255, 255, 255, 0.10);
  --mem-plain-line: rgba(255, 255, 255, 0.35);
}
[data-theme="light"] {
  /* a11y: #E8B22B is 2.0:1 on the light page and fails as text. This
     darker gold hits 5.7:1 while staying recognisably the same colour.
     The ring keeps more of the original so the badge still reads gold. */
  --mem-gold:       #7A5A00;
  --mem-gold-tint:  rgba(232, 178, 43, 0.20);
  --mem-gold-line:  #B8860B;
  --mem-cyan:       var(--accent-text);
  --mem-cyan-tint:  rgba(43, 181, 232, 0.16);
  --mem-cyan-line:  var(--accent);
  --mem-plain:      var(--text-primary);
  --mem-plain-tint: rgba(0, 0, 0, 0.05);
  --mem-plain-line: var(--text-primary);
}

.mem-badge {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 13px;
  margin: 0 0 18px;
  border: 1px solid var(--mem-line);
  border-radius: 12px;
}
.mem-badge-no {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1.5px solid var(--mem-ink);
  background: var(--mem-tint);
  color: var(--mem-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  /* Long numbers must shrink rather than burst the circle. Four digits
     would mean 10,000 members, which is a good problem, but the badge
     should not break on the way there. */
  letter-spacing: -0.01em;
}
.mem-badge-title { font-size: 14.5px; color: var(--text-primary); }
.mem-badge-sub   { font-size: 12.5px; color: var(--text-secondary); margin-top: 2px; }

.mem-pill {
  display: inline-block;
  margin-left: 9px;
  padding: 3px 10px;
  border: 0.5px solid var(--mem-line);
  border-radius: 999px;
  background: var(--mem-tint);
  color: var(--mem-ink);
  font-size: 11.5px;
  /* The greeting is an .eyebrow, which is uppercased and letter-spaced.
     The pill opts out of both: "LEGACY MEMBER 7" shouts, and the tracking
     makes it wider than the name it sits next to. */
  text-transform: none;
  letter-spacing: 0;
  vertical-align: middle;
  white-space: nowrap;
}

.mem-badge--gold,  .mem-pill--gold  { --mem-ink: var(--mem-gold);  --mem-tint: var(--mem-gold-tint);  --mem-line: var(--mem-gold-line); }
.mem-badge--cyan,  .mem-pill--cyan  { --mem-ink: var(--mem-cyan);  --mem-tint: var(--mem-cyan-tint);  --mem-line: var(--mem-cyan-line); }
.mem-badge--plain, .mem-pill--plain { --mem-ink: var(--mem-plain); --mem-tint: var(--mem-plain-tint); --mem-line: var(--mem-plain-line); }

@media (max-width: 560px) {
  /* The pill drops under the name rather than squeezing it. */
  .mem-pill { margin-left: 0; margin-top: 6px; display: block; width: fit-content; }
  .mem-badge { gap: 11px; padding: 11px; }
  .mem-badge-no { width: 40px; height: 40px; font-size: 13px; }
}

/* ============================================================
   ADDITIONS 2026-08-08v — the two-inbox email-change screens

   An email change now needs BOTH the old and the new address to
   confirm (Jen 2026-08-08). Two new pieces:

   .acct-emailbig   the full-page takeover. Jen asked for "large text
                    that explicitly states the user MUST confirm the
                    change on their old and new emails", so .acct-lede
                    is a deliberately oversized paragraph — bigger than
                    .acct-sub, which is what a normal page uses.
   .ecs-*           the two-line checklist (old address / new address,
                    confirmed or waiting) shared by the takeover and the
                    account page's Email section.

   ⚠ The tick and the circle are TEXT (&#10003; / &#9711;), not colour
   alone, and each row also spells out "Confirmed" or "Waiting". Whether
   a student has to go and open another email must not depend on being
   able to tell cyan from grey.
   ============================================================ */
.acct-emailbig { max-width: 640px; }
.acct-emailbig .acct-lede {
  font-size: 1.15rem;
  line-height: 1.6;
  color: var(--text-primary);
  margin: 14px 0 0;
}

.ecs-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 20px 0 0;
}
.ecs-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 14px;
  border: 0.5px solid var(--border);
  border-radius: 12px;
}
.ecs-row--done { border-color: var(--accent); }
.ecs-mark {
  flex: none;
  width: 22px;
  text-align: center;
  font-size: 1rem;
  color: var(--text-muted);
}
.ecs-row--done .ecs-mark { color: var(--accent-text); }
.ecs-text { display: flex; flex-direction: column; min-width: 0; }
.ecs-label {
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.ecs-email {
  font-size: 0.95rem;
  color: var(--text-primary);
  /* Long addresses wrap instead of pushing the state chip off the row. */
  overflow-wrap: anywhere;
}
.ecs-state {
  margin-left: auto;
  flex: none;
  padding-left: 10px;
  font-size: 0.8rem;
  color: var(--text-muted);
}
.ecs-row--done .ecs-state { color: var(--accent-text); }
.ecs-clock {
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--text-secondary);
  margin: 14px 0 0;
}

/* Inside the account page's pending box the checklist is a detail, not the
   headline, so it gives back the takeover's breathing room. */
.acct-emailpending .ecs-list { margin-top: 12px; }
.acct-emailpending .ecs-clock { margin-top: 10px; }

@media (max-width: 560px) {
  .acct-emailbig .acct-lede { font-size: 1.05rem; }
  /* The state chip drops under the address rather than crushing it. */
  .ecs-row { flex-wrap: wrap; }
  .ecs-state { margin-left: 34px; padding-left: 0; }
}

/* ============================================================
   ADDITIONS 2026-08-08w — the privacy page

   privacy.php reuses .static-page / .static-text from about.php and
   stickers.php; these are the few extras it needs. .privacy-text
   restyles the shared h2 for a page that is a list of short sections
   rather than one long bio.
   ============================================================ */
.privacy-text h2 {
  font-size: 1.05rem;
  margin: 30px 0 8px;
  color: var(--text-primary);
}
.privacy-text h2:first-of-type { margin-top: 26px; }
.privacy-lede {
  font-size: 1.15rem;
  line-height: 1.6;
  color: var(--text-primary);
}
.privacy-text ul {
  margin: 10px 0 0;
  padding-left: 20px;
  line-height: 1.7;
  color: var(--text-secondary);
}
.privacy-text li { margin-bottom: 7px; }
.privacy-text li b { color: var(--text-primary); font-weight: 600; }
.privacy-updated {
  margin-top: 34px;
  padding-top: 14px;
  border-top: 0.5px solid var(--border);
  font-size: 0.85rem;
  color: var(--text-muted);
}

/* The pointer sitting under "Delete my account". Muted: it is a
   reassurance, not a call to action competing with the button. */
.acct-privacy-note {
  flex-basis: 100%;
  margin: 12px 0 0;
  font-size: 0.85rem;
  line-height: 1.6;
  color: var(--text-muted);
}

/* ============================================================
   ADDITIONS 2026-08-08x — the footer's Privacy link

   Inherits the footer's Georgia and muted grey so it reads as part of
   the same line, and only picks up the accent on hover. It is a
   reference, not a destination anyone should be steered toward.
   ============================================================ */
.footer-link {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--border-strong);
}
.footer-link:hover,
.footer-link:focus-visible {
  color: var(--accent-text);
  text-decoration-color: currentColor;
}

/* ============================================================
   ADDITIONS 2026-08-08y — fixing the account page's bottom tile

   Jen 2026-08-08: "make the sign out button have one line of text."

   white-space: nowrap is what actually delivers that, unconditionally
   and at any width, zoom or font size.

   ⚠ Note for whoever comes next: the wrap on a two-word label could
   NOT be reproduced here. Measured at eight container widths from
   1000px down to 240px, before and against this block, "Sign out"
   stayed on one line every time. An earlier reading of "three lines
   in a 57px button" turned out to be the Browser pane reporting a
   ZERO-WIDTH viewport, not a real layout — so if you are chasing a
   layout bug through devtools, check innerWidth is non-zero first.
   Whatever Jen saw is real to her; this rule makes the requirement
   hold regardless of what caused it.

   .acct-danger (line ~2117) is a nowrap flex row of two small forms,
   and .acct-privacy-note joined it with flex-basis:100%. Letting the
   row wrap is what gives the note its own line rather than a squeezed
   column beside the buttons.

   Appended rather than edited, because styles.css is APPEND-ONLY and
   these override the originals by source order.
   ============================================================ */
.acct-danger { flex-wrap: wrap; }
.acct-danger .acct-inline-form { flex: 0 0 auto; }
.acct-danger .btn-primary,
.acct-danger .acct-delete { white-space: nowrap; }

/* The privacy link in that note: same treatment as the footer's, on
   Jen's instruction — underlined in the surrounding grey, accent on
   hover and on keyboard focus. Declared separately because .footer-link
   is scoped to the footer and this file cannot be edited in place. */
.acct-privacy-note a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--border-strong);
}
.acct-privacy-note a:hover,
.acct-privacy-note a:focus-visible {
  color: var(--accent-text);
  text-decoration-color: currentColor;
}

/* ============================================================
   ADDITIONS 2026-08-08z — the account tile stacks down the left

   Jen 2026-08-08: "make the delete my account link on the left side,
   under the sign out button." So Sign out, then Delete, then the
   privacy note, all flush left, at EVERY width. Above 720px it used to
   be a space-between row with Delete pushed to the far right.

   The 720px media query at line ~2269 already did exactly this on
   phones; this simply stops it being a phone-only layout.

   ⚠ flex-basis on .acct-privacy-note has to be undone here. In a row it
   meant "take the full width", which is what put the note on its own
   line. Flex-basis follows the MAIN AXIS, so the moment the container
   became a column that same 100% started meaning "be as tall as the
   whole tile". Column layout, so it goes back to auto.
   ============================================================ */
.acct-danger {
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
}
.acct-danger .acct-privacy-note {
  flex-basis: auto;
  /* The 14px flex gap already separates it from the buttons; this is
     the little extra that keeps prose from crowding a control. */
  margin-top: 4px;
}

/* ============================================================
   ADDITIONS 2026-08-08aa — the delete warning sits beside the control

   Jen 2026-08-08: "move the deleting is permanent... text right after
   the link." It was already the next thing DOWN the column; she wants
   it on the same line, immediately after "Delete my account".

   .acct-danger is a column (2026-08-08z), so the two need a row of
   their own to sit side by side. baseline alignment, not centre, so
   the sentence sits on the same text baseline as the link rather than
   floating against the middle of it.

   Wraps under the link on a narrow screen instead of squeezing the
   sentence into a two-word-wide column.
   ============================================================ */
.acct-danger-delete {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
}
.acct-danger-delete .acct-inline-form { flex: 0 0 auto; }
.acct-danger-delete .acct-privacy-note {
  /* Overrides the stacked spacing from block z: nothing to clear when
     it is sitting on the same line. */
  margin-top: 0;
  flex: 1 1 260px;
  min-width: 0;
}

/* ============================================================
   ADDITIONS 2026-08-08ab — belt and braces on the honeypot

   The stick-figure suggestion form hid its spam trap with
   class="hp-field", which was defined in NO stylesheet, so the trap
   rendered as a visible empty text box above the real field. Anything
   typed into it was treated as a bot: suggestion binned, and the
   student bounced to the "check your email" sign-in page.

   The markup now uses the .cf-honeypot wrapper like every other form.
   This rule is insurance only, so that the same slip cannot fail
   SILENTLY a second time. .cf-honeypot (line ~1714) remains the
   canonical pattern — write that, not this.
   ============================================================ */
.hp-field { position: absolute; left: -9999px; opacity: 0; }

/* ============================================================
   ADDITIONS 2026-08-08ac — the About DCM feature guide

   about-dcm.php reuses .static-page / .static-text like about.php and
   privacy.php. These are the extras for a page that is a stack of
   short how-tos rather than prose.

   .guide-part  the two big dividers, "For students" / "For teachers"
   .guide-how   the "how to get there" line under each feature. Muted
                and slightly smaller, so a reader scanning for the
                click-path can find it without reading the paragraph.
   ============================================================ */
.guide-lede {
  font-size: 1.15rem;
  line-height: 1.6;
  color: var(--text-primary);
}
.guide-part {
  margin: 40px 0 4px;
  padding-bottom: 8px;
  border-bottom: 0.5px solid var(--border);
  font-size: 1.3rem;
  color: var(--text-primary);
}
.guide-text h3 {
  font-size: 1.05rem;
  margin: 26px 0 6px;
  color: var(--text-primary);
}
.guide-text p { line-height: 1.7; }
.guide-how {
  font-size: 0.9rem;
  line-height: 1.65;
  color: var(--text-muted);
  /* A left rule rather than a box: it is an aside to the paragraph above,
     not a separate card. No radius, since it is a single-sided border. */
  border-left: 2px solid var(--border-strong);
  border-radius: 0;
  padding-left: 12px;
  margin-top: 10px;
}
.guide-how b { color: var(--text-secondary); }

/* ============================================================
   ADDITIONS 2026-08-08ad — more air before "For teachers"

   Jen 2026-08-08 wanted the two halves of about-dcm.php further
   apart. The divider's top margin goes 40px → 64px, so the jump from
   the student half to the teacher half reads as a new part of the
   page rather than as the next heading in a list.

   ⚠ The FIRST divider is pulled back to where it was. It follows the
   lede rather than a whole section, so giving it the same 64px opens
   a hole under the opening line and makes the page look like it
   starts twice.
   ============================================================ */
.guide-part { margin-top: 64px; }
.guide-text .guide-part:first-of-type { margin-top: 34px; }

/* ============================================================
   ADDITIONS 2026-08-08ae — the three parts of About DCM as tiles

   Jen 2026-08-08: "put each of the 3 sections in gray tiles, similar
   to the account page layout." The markup reuses .acct-section
   itself, so the surface, border and radius are literally the account
   page's and cannot drift from it. These rules only fix up the
   spacing, which was built for headings floating on the page.

   ⚠ The old gaps have to be UNDONE, not merely reduced. The dividers
   carried margin-top: 64px (and 34px on the first) to separate
   sections that had nothing else separating them. Inside a tile the
   tile IS the separation, so that margin becomes dead space at the
   top of every box.

   ⚠ Specificity, deliberately three classes: the rule it overrides is
   .guide-text .guide-part:first-of-type, which is also 0,3,0. Two
   classes would lose. Worse, :first-of-type now matches the heading
   in EVERY tile, because each is the first h2 among its own siblings
   — so without this all three boxes would open with 34px of nothing.
   ============================================================ */
.guide-text .guide-tile .guide-part {
  margin-top: 0;
  font-size: 1.2rem;
}
/* The tile's own top padding sits above the heading, so the rule under
   it needs a little less room than it did floating on the page. */
.guide-text .guide-tile .guide-part { padding-bottom: 10px; }

/* Space BETWEEN tiles. .acct-section brings 28px; a touch more here
   because these boxes are long reads rather than short account rows. */
.guide-tile { margin-top: 34px; }
.guide-text .guide-tile:first-of-type { margin-top: 26px; }

/* First heading inside a tile shouldn't be shoved away from the divider
   it belongs to. */
.guide-tile .guide-part + h3 { margin-top: 18px; }

/* ============================================================
   ADDITIONS 2026-08-08af — static pages that have no second column

   Jen 2026-08-08 asked for the About DCM tiles to be wider. The cause
   was not the tiles: .static-page (line ~1644) is a TWO-COLUMN grid
   built for about.php, text at 5fr and the photo at 6fr. about-dcm.php
   and privacy.php have no photo, so they were rendering into the text
   column and leaving 559px of the page empty on the right at 1280px.

   This modifier collapses the grid to one column and narrows the
   container, so the content is both wider and centred instead of
   hugging the left with a hole beside it.

   ⚠ NOT the full 1160px. That would give roughly 140 characters a
   line, which is unreadable for prose. 900px lands near 100, which is
   long but fine for a page of short sections. If a third solo page
   ever wants long-form prose, narrow it rather than widening this.
   ============================================================ */
.static-page--solo {
  grid-template-columns: minmax(0, 1fr);
  max-width: 900px;
}

/* ============================================================
   ADDITIONS 2026-08-08ag — solo static pages get the account width

   Jen 2026-08-08, asking for the About DCM tiles wider a second time.
   900px → 1060px, which is not a number picked by eye: it is
   .acct-settings (line ~2184), the container these tiles were asked to
   resemble in the first place. Tiles go 856px → 1016px.

   ⚠ Overrides the 900px in block af rather than editing it, because
   styles.css is APPEND-ONLY. Block af's comment argues for 900 on
   line-length grounds; that reasoning is still sound and still worth
   reading, it was simply overruled. Around 120 characters a line now,
   which is long for prose and fine for this page's short sections.
   ============================================================ */
.static-page--solo { max-width: 1060px; }

/* ============================================================
   ADDITIONS 2026-08-08ah — the whole video tile plays

   Jen 2026-08-08. .vrow has carried cursor:pointer and an accent
   border on hover since it was written, so the tile always LOOKED
   clickable; only the thumbnail actually was. app.js now plays from
   anywhere on .vrow-main, which makes that affordance honest.

   ⚠ Once a row is playing, tile clicks are ignored on purpose (a stray
   click must not kill a video someone is watching), so the pointer and
   the hover border have to stop advertising otherwise. A cursor that
   promises something the click does not do is worse than no cursor.
   ============================================================ */
.vrow.is-playing { cursor: default; }
.vrow.is-playing:hover { border-color: transparent; }

/* The player is content, not a control. */
.vrow-player { cursor: default; }

/* The tile lifts a little on hover, matching what the thumbnail already
   does, so the target reads as the whole row rather than the picture. */
.vrow:hover:not(.is-playing) { background: var(--bg-elevated); }
.vrow.is-playing { background: var(--bg-surface); }

/* ============================================================
   ADDITIONS 2026-08-08ai — expanded tile: text clears the blue bar

   Jen 2026-08-08: with the player open, the video name and the links
   sit on top of the little blue bar at the left edge.

   The bar is .vrow-cb, the batch-mode checkbox: outside batch mode its
   grid column is 0 wide, but the element still paints its 1px accent
   border, which is the 2px sliver everyone reads as a design detail.
   While a row is playing the thumbnail leaves the grid, so the text
   column starts at the same x as that sliver and lands on top of it.

   Measured before this rule: bar at 31–33, text at 31.
   ============================================================ */
.vrow.is-playing .vinfo { padding-left: 14px; }

/* ============================================================
   ADDITIONS 2026-08-08aj — the COD page's mobile class list

   Jen 2026-08-08. On a phone the COD page offered no way into any
   class: they all lived in the hamburger. This is the list, above the
   "Not a COD student?" link.

   ⚠ HIDDEN BY DEFAULT, shown only at ≤720px. That is not a rounded
   guess, it is the exact width where .nav-row disappears (line ~769)
   and the hamburger takes over. The desktop page stays hero-only,
   which is what Jen asked for when she called a class grid too busy —
   the dropdowns already do this job up there.
   ============================================================ */
.cod-mobile-classes { display: none; }
.cod-menu-hint { display: inline; }

@media (max-width: 720px) {
  .cod-menu-hint { display: none; }

  .cod-mobile-classes {
    display: flex;
    flex-direction: column;
    gap: 7px;
    margin: 16px 0 18px;
  }
  .cmc-label {
    font-size: 12px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 2px;
  }
  .cmc-row {
    display: flex;
    align-items: center;
    gap: 10px;
    /* 11px vertical on a 14px line clears 44px, the smallest target a
       thumb should ever be asked to hit. */
    padding: 11px 13px;
    background: var(--bg-surface);
    border: 0.5px solid var(--border);
    border-radius: 10px;
    text-decoration: none;
  }
  .cmc-row:active { border-color: var(--accent); }
  .cmc-code {
    flex: none;
    min-width: 52px;
    font-size: 13.5px;
    color: var(--accent-text);
  }
  .cmc-name {
    flex: 1;
    min-width: 0;
    font-size: 13.5px;
    color: var(--text-primary);
    /* Long titles wrap rather than push the chevron off the row. */
    overflow-wrap: anywhere;
  }
  .cmc-chev { flex: none; width: 7px; height: 11px; color: var(--accent); }
}

/* ============================================================
   ADDITIONS 2026-08-08ak — links inside a tile's sub-text are blue

   Jen 2026-08-08: "make the link blue to make it obvious that it's
   clickable." The teacher-guide link in the Create a class tile was
   rendering #888 — the exact same grey as the sentence around it, with
   no underline — because the site's base rule is `a { color: inherit }`
   and .acct-section-sub had no link colour of its own.

   Mirrors .acct-sub a (line ~2037), which already does this for the
   other flavour of sub-text. Written as a general rule rather than for
   this one link: it is the only such link on the site today, so nothing
   else changes, and the next one cannot land invisible.
   ============================================================ */
.acct-section-sub a { color: var(--accent-text); }
.acct-section-sub a:hover,
.acct-section-sub a:focus-visible { text-decoration: underline; }

/* ============================================================
   ADDITIONS 2026-08-08al — curate chapter tiles contain their checkbox

   Jen 2026-08-08: "the first checkbox in each tile is partially
   outside of the tile."

   Exactly right, and it is not a sizing problem. .curate-chapter is a
   <fieldset> and its chapter checkbox lives in the <legend>. A legend
   STRADDLES the top border by design: the browser paints the border
   across the legend's midline. Measured before this fix — border at
   y=1150, checkbox spanning 1143 to 1156, so the line ran through the
   box 7px down a 13px control.

   Floating the legend takes it out of that special placement and makes
   it ordinary content inside the box, so the border draws straight
   across the top above it. width:100% keeps the rows below from
   riding up beside it, and the clearfix keeps the float inside the
   tile's height.

   ⚠ Do NOT "simplify" this by dropping the float and adding padding to
   the fieldset. Padding does not move a legend; the browser positions
   it against the border regardless, and the checkbox goes back on the
   line.
   ============================================================ */
.curate-chapter > legend {
  float: left;
  width: 100%;
  /* was 0 8px, which existed only to space the old border notch */
  padding: 0;
  margin-bottom: 2px;
}
.curate-chapter::after { content: ''; display: block; clear: both; }

/* The row after the legend must CLEAR it. A float is contained by the
   ::after above, but following block siblings still start alongside it:
   their line boxes get pushed down while their boxes do not, which
   measured as a 13px overlap between the legend and the first section.
   Invisible today only because .curate-section has no background of its
   own, and it would appear the moment one is added. */
.curate-chapter > legend + * { clear: both; }

/* ============================================================
   ADDITIONS 2026-08-09a — renaming a class from the curate page

   Dan 2026-08-08. The class name is now editable where a teacher is
   already working on the class.

   A <details> so the page still OPENS as a heading, not as a form:
   renaming happens once a term, curating is why anyone is here. The
   summary is the h1 itself with a quiet "Rename" beside it.

   ⚠ The h1 has to be display:inline inside the summary, or it takes a
   line of its own and the affordance ends up orphaned underneath the
   title it belongs to.
   ============================================================ */
.curate-rename > summary {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  cursor: pointer;
  /* The default triangle would sit oddly against a page title; the
     "Rename" text is the affordance instead. */
  list-style: none;
}
.curate-rename > summary::-webkit-details-marker { display: none; }
.curate-rename > summary .acct-h1 { display: inline; margin: 0; }
.curate-rename-hint {
  font-size: 0.85rem;
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--border-strong);
}
.curate-rename > summary:hover .curate-rename-hint,
.curate-rename > summary:focus-visible .curate-rename-hint {
  text-decoration-color: currentColor;
}
/* Open: the title is now the field, so the prompt has done its job. */
.curate-rename[open] > summary .curate-rename-hint { display: none; }

.curate-rename-form {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 10px 0 0;
}
.curate-rename-form input[type="text"] {
  flex: 1 1 260px;
  min-width: 0;
  font-size: 1.05rem;
}

/* ⚠ CORRECTION to the block above, same day. Setting display:flex on
   .curate-rename-form made it visible even with the <details> CLOSED:
   an author `display` on a child of a closed details beats the UA rule
   that hides it, so the form rendered under the title and spilled out
   of the 45px details box. Any display value on a details child has to
   be scoped to [open]. */
.curate-rename-form { display: none; }
.curate-rename[open] .curate-rename-form { display: flex; }

/* ==========================================================================
   ADDITIONS 2026-08-09 — curate.php "Select class contents" tile (Dan)
   --------------------------------------------------------------------------
   The two lines of instruction above the checkbox tree were loose page copy
   with nothing marking where the curation step began. They now sit in a tile
   (option A of the mockup): .acct-section supplies the surface, border and
   12px radius, which are already identical to .curate-chapter, so the tile
   reads as the head of the checkbox list rather than as a new component.

   Only the spacing is set here. The gap BELOW is deliberately generous —
   Jen asked for room before "Save picks" so the button is not crowded by
   the paragraph. Note it does not add to the save bar's own 18px: the div's
   margin-bottom collapses through the (border-less, padding-less) form with
   .curate-savebar's margin-top, so 34px is the whole gap, not 34 + 18.
   ========================================================================== */

.curate-intro {
  margin-top: 26px;
  margin-bottom: 34px;
}
/* No trailing margin inside the tile — the padding is the breathing room. */
.curate-intro > :last-child { margin-bottom: 0; }

/* ==========================================================================
   ADDITIONS 2026-08-09b — Add Groups tile drops its tint (Dan)
   --------------------------------------------------------------------------
   Overrides the "Closed: an invitation, not a section of the form" rule in
   the 2026-08-04 block above, which filled the closed <details> with
   --accent-tint-soft. With the new "Select class contents" tile directly
   under it, the page showed two panels of the same size in two different
   colours, and the tinted one read as a notice rather than as the optional
   step it is. Both now sit on --bg-surface.

   The DASHED border stays, and is deliberately the whole of what marks the
   panel as an invitation now — do not also solidify it without asking, or
   the closed state becomes indistinguishable from the tile below it.
   ========================================================================== */

details.addon-groups:not([open]) { background: var(--bg-surface); }

/* ==========================================================================
   ADDITIONS 2026-08-09c — Easy Share (class-email.php), Dan
   --------------------------------------------------------------------------
   The page holds ONE editable block containing the whole message. Every
   rule here styles the PREVIEW only: what the teacher copies is the block's
   own markup, which lands in a mail client with none of this attached, so
   nothing below may be load-bearing. The label column is the example —
   .ce-k gives it a tidy column here and degrades to a plain space in the
   email, which is why the labels are followed by a real space in the HTML
   rather than being spaced by CSS alone.

   Non-link text is deliberately ONE colour (Jen: "keep the non link colors
   consistent, some of the text is showing up in white"). <b> inside the
   message carries WEIGHT ONLY — it must not also brighten to
   --text-primary, or the bold class code reads as a different kind of
   thing from the words around it.
   ========================================================================== */

.ce-shell { max-width: 760px; }

.ce-email {
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: var(--bg-elevated);
  padding: 14px 16px;
  margin-top: 4px;
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--text-secondary);
}
.ce-email:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.ce-email p { margin: 0 0 12px; }
.ce-email p:last-child { margin-bottom: 0; }
/* Weight, not colour — see the note above. */
.ce-email b { color: inherit; font-weight: 600; }
.ce-email a { color: var(--accent-text); text-decoration: underline; }

.ce-facts { margin: 0 0 12px; }
.ce-facts > div { display: flex; gap: 8px; flex-wrap: wrap; }
.ce-facts .ce-k { min-width: 88px; }

.ce-actions { margin-top: 14px; }
.ce-note { margin: 10px 0 0; }

/* The share line on teachers.php sits under the action buttons, so it needs
   the top gap those buttons do not give it. On curate.php the line is a
   plain .acct-sub in a stack of them and needs nothing. */
.tclass-row-share { display: block; margin-top: 2px; }
.tclass-row-share a { color: var(--accent-text); }
.tclass-row-share a:hover,
.tclass-row-share a:focus-visible { text-decoration: underline; }

/* ⚠ CORRECTION to the block above, same day. .ce-facts > div was display:flex
   to align the label column, and flex CHILDREN each start a new line in
   innerText — so the plain-text flavour of the clipboard came out as

       Our class:
       Dr. Hill's Spring 2026 Calculus Class

   one label per line, in the exact place the email is supposed to read
   cleanly. Nothing was visibly wrong on the page, which is why this needed
   reading innerText rather than looking at it. An inline-block label keeps
   the same column in the preview, stays on one line in innerText, and still
   degrades to a plain space with no CSS at all. */
.ce-facts > div { display: block; }
.ce-facts .ce-k { display: inline-block; min-width: 88px; }

/* ⚠ SPACING CORRECTION, same day: Easy Share moved from BELOW the Curate
   button to above it (Jen), so the 2px top margin that separated it from
   the buttons is now on the wrong side and left the line 2px off a row of
   buttons. It needs room underneath instead — the class code and link
   above it are text, but what follows is a control. */
.tclass-row-share { margin-top: 4px; margin-bottom: 10px; }

/* ⚠ SPACING CORRECTION 2026-08-09d — the three share lines must be evenly
   spaced (Dan: the gap under "Class link" did not match the gap above it).
   Two different causes, one per page.

   curate.php: `.curate-share + .curate-share { margin-bottom: 10px }` was
   written when there were only TWO of these lines, so "the second one" and
   "the last one" were the same line. Easy Share made a third, and the rule
   fired on the middle line as well — code→link 2px, link→share 10px. The
   trailing space it was providing is not needed: what follows is the Add
   Groups panel, whose own 22px margin does that job.

   teachers.php: the code and link are two lines inside ONE span split by a
   <br>, so they sit on nothing but line rhythm, while Easy Share is a
   separate block that was adding 4px on top of that. Zero it and the three
   lines share the same rhythm; the space before the Curate button stays,
   because a control below still needs room a line of text does not. */
.curate-share + .curate-share { margin-bottom: 2px; }
.tclass-row-share { margin-top: 0; }

/* ==========================================================================
   ADDITIONS 2026-08-09e — the For Teachers intro becomes a tile (Dan)
   --------------------------------------------------------------------------
   The three steps and the two ways in now sit in .acct-section, matching My
   classes and Create a class below them. Only spacing is set here; the tile
   itself is the shared component, unchanged.

   Both lists carried a 20px bottom margin from when they were loose page
   copy that needed separating from what followed. Inside a tile that margin
   is doubling the padding, so the last child gives it up — the padding is
   the breathing room now. The steps keep theirs, because it is what
   separates them from the "Two ways" line below.
   ========================================================================== */

.tch-intro .tch-steps { margin-top: 6px; }
.tch-intro > :last-child { margin-bottom: 0; }

/* ==========================================================================
   ADDITIONS 2026-08-09f — the drawer's Sign out stops looking like a button
   --------------------------------------------------------------------------
   Jen, on a phone while signed in: "a gray border on the top and left side
   of it. it looks weird." It is the browser's own button chrome. The
   2026-08-05 block above styles this control to sit flush in the item list
   and sets background, radius and font, but never touches `border` — and
   `.nav-drawer-item` only ever declares border-BOTTOM, so the UA's default
   `2px outset` survived on the other three sides. Outset renders light on
   two edges and shaded on the other two, which is exactly the top-and-left
   gray she saw.

   Measured against its neighbour before the fix: Feedback had
   `0px none` on three sides, Sign out `2px outset white`.

   The type was off as well, which is the same rule's doing: `font: inherit`
   beats `.nav-drawer-sub`, so the button took the body's 15.5px while every
   item around it sat at 14px. ⚠ The 14px below is that value copied — if
   `.nav-drawer-sub` ever moves, this moves with it.
   ========================================================================== */

.nav-drawer-signout .nav-drawer-item {
  border: 0;
  border-bottom: 0.5px solid var(--border);
  font-size: 14px;
}

/* The top copy button (2026-08-09): same row, mirrored spacing — the
   bottom one pushes away from the message above it, this one from the
   heading below it. */
.ce-actions--top { margin: 0 0 14px; }

/* The two routes are an <ol> now (Dan 2026-08-09, hand-edited then tidied).
   Preview-only spacing, matching the paragraphs around it; the copy that
   lands in a mail client uses that client's own list defaults, which is
   exactly what an email should look like. */
.ce-email ol { margin: 0 0 12px; padding-left: 24px; }
.ce-email li { margin: 2px 0; }

/* ==========================================================================
   ADDITIONS 2026-08-09g — the delete-account privacy link goes blue (Dan)
   --------------------------------------------------------------------------
   ⚠ THIS REVERSES AN EARLIER INSTRUCTION OF HERS, deliberately. The
   2026-08-08 block above gave this link the footer's treatment — grey with
   a faint underline, accent only on hover — on her say-so. Seeing it on a
   phone she said it "doesn't look like a link", which it does not: on a
   touch screen there is no hover to reveal the colour, so the whole hint
   reads as one grey sentence.

   It now matches every other in-copy link on the site (.acct-sub a,
   .acct-section-sub a): accent at rest, underline on hover and keyboard
   focus. The hover rule below still applies and needs nothing.

   The FOOTER keeps the grey treatment — it was not what she was looking at,
   and the same argument would apply there if she ever raises it.
   ========================================================================== */

.acct-privacy-note a {
  color: var(--accent-text);
  text-decoration: none;
}
.acct-privacy-note a:hover,
.acct-privacy-note a:focus-visible { text-decoration: underline; }

/* The same fix one line up the page (Dan 2026-08-09): the privacy link in
   the create-account form's hint. .acct-hint styled no links at all, so
   this one rendered at exactly the hint's own grey with no underline and
   no hover — invisible as a link on any device, not just a phone.

   Scoped to .acct-hint rather than that one sentence: only one of the six
   hints on the site contains a link today, and any that gains one should
   look like this too. */
.acct-hint a { color: var(--accent-text); text-decoration: none; }
.acct-hint a:hover,
.acct-hint a:focus-visible { text-decoration: underline; }

/* NOTE 2026-08-09: about-dcm.php was renamed explore-dcm.php (Dan), to match
   the "Explore" wording its heading, tab and footer link all use now. Three
   comment blocks above still name the old file — they are dated narrative
   about when those rules were written, so they are left as they stand; this
   line is here so a grep for the new name finds its stylesheet. No selector
   changed: the page reuses .static-page / .static-text / .guide-* and never
   had a rule keyed to its filename. */

/* ==========================================================================
   ADDITIONS 2026-08-09h — explore-dcm.php rebuilt as two collapsible halves
   with a visual per entry (Jen: "all text and a long scroll to the bottom")
   --------------------------------------------------------------------------
   Layout B and graphic style 2 of the mockups: <details> per audience, a
   card grid inside, and each card carrying a small rendering of the control
   it describes.

   ⚠ THE VISUALS ARE MARKUP, NOT IMAGES, and this block is the whole reason
   that works. Ten screenshots would be ten files to re-shoot whenever a
   button moves — on the one page whose header already warns it goes stale —
   and would need a light and a dark version each. Everything below is drawn
   from the same tokens as the real controls, so it restyles itself with the
   site and is right in both themes for free. Nothing here is load-bearing:
   every .guide-shot is aria-hidden and the words beside it say the same
   thing, so a reader who gets none of it loses nothing.

   The .gs-* names are deliberately NOT the real component classes. Reusing
   .vrow or .batch-bar would drag their layout, their hover states and their
   JS hooks onto a static page, and would break this page the next time one
   of them is refactored. These borrow the tokens, not the components.
   ========================================================================== */

/* ---------------------------------------------------------- the two halves */
.guide-sec { margin-top: 18px; padding: 15px 17px; }
.guide-sec > summary { cursor: pointer; list-style: none; display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.guide-sec > summary::-webkit-details-marker { display: none; }
.guide-sec-title { font-size: 18px; font-weight: 600; color: var(--text-primary); }
.guide-sec-count { font-size: 12px; color: var(--text-muted); }
.guide-sec-head::after { content: "▸"; margin-left: auto; color: var(--text-faint); font-size: 12px; }
.guide-sec[open] .guide-sec-head::after { content: "▾"; }
/* The teaser is the closed state's whole job: it is the sentence that used to
   open the section as body copy, where a shut box would have hidden it. */
.guide-sec-teaser { flex-basis: 100%; font-size: 13px; color: var(--text-secondary); margin-top: 5px; }
.guide-sec[open] .guide-sec-teaser { display: none; }

/* ------------------------------------------------------------- the cards */
.guide-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 12px;
  margin-top: 15px;
}
.guide-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 13px;
}
/* Entry headings stay h3 — the document outline is h1 page, h2-in-summary,
   h3 entry — and are only sized down to card scale here. */
.guide-card h3 { margin: 10px 0 4px; font-size: 14.5px; }
.guide-card p { margin: 0 0 7px; font-size: 13px; line-height: 1.55; color: var(--text-secondary); }
.guide-card p:last-child { margin-bottom: 0; }
.guide-card .guide-how { font-size: 12px; color: var(--text-muted); }
.guide-card .guide-how a { color: var(--accent-text); }

/* ------------------------------------------------- the control renderings */
.guide-shot {
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: 7px;
  padding: 8px;
  min-height: 76px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  overflow: hidden;
}
.gs-lab  { font-size: 10px; color: var(--text-muted); }
.gs-row  { display: flex; gap: 5px; flex-wrap: wrap; }
.gs-mid  { align-items: center; }
.gs-grow { flex: 1; min-width: 0; }
.gs-bar  { height: 6px; border-radius: 2px; background: var(--border-strong); }
.gs-w45  { width: 45%; } .gs-w70 { width: 70%; } .gs-w90 { width: 90%; }
.gs-thumb { width: 38px; height: 23px; border-radius: 3px; background: var(--border-strong); flex: 0 0 auto; }
.gs-type { font-size: 8px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent-text); }
.gs-name { font-size: 10.5px; color: var(--text-secondary); line-height: 1.35; }
.gs-btn  { background: var(--accent); color: var(--accent-on-bg); border-radius: 6px; padding: 5px 10px; font-size: 10.5px; font-weight: 600; white-space: nowrap; }
.gs-btn2 { border: 1px solid var(--border-strong); color: var(--text-secondary); border-radius: 6px; padding: 5px 10px; font-size: 10.5px; white-space: nowrap; }
.gs-inp  { border: 1px solid var(--border-strong); border-radius: 5px; background: var(--bg-surface); padding: 5px 7px; font-size: 10.5px; color: var(--text-muted); }
.gs-mini { border: 1px solid var(--border-strong); border-radius: 5px; background: var(--bg-surface); padding: 5px 6px; font-size: 9.5px; color: var(--text-secondary); flex: 1; text-align: center; line-height: 1.3; }
.gs-mini.gs-wide { flex-basis: 100%; text-align: left; }
.gs-mini.is-on { border-color: var(--accent); background: var(--accent-tint-soft); color: var(--accent-text); }
.gs-star { margin-left: auto; font-size: 10px; color: var(--accent-text); border: 1px solid var(--accent); border-radius: 5px; padding: 2px 6px; background: var(--accent-tint); white-space: nowrap; }
.gs-pill { font-size: 9.5px; background: var(--accent-tint); color: var(--accent-text); border-radius: 999px; padding: 2px 8px; white-space: nowrap; }
.gs-chip { font-size: 9.5px; border: 1px dashed var(--border-strong); color: var(--text-muted); border-radius: 999px; padding: 1px 8px; }
/* The teacher-mode switch, drawn on: a pill with the knob to the right. */
.gs-switch { width: 30px; height: 17px; border-radius: 999px; background: var(--accent); position: relative; flex: 0 0 auto; }
.gs-switch::after { content: ""; position: absolute; top: 2px; right: 2px; width: 13px; height: 13px; border-radius: 999px; background: var(--accent-on-bg); }

/* --------------------------------------------------------------- Stuck? */
.guide-stuck {
  background: var(--accent-tint-soft);
  border: 1px dashed var(--border-strong);
  border-radius: 10px;
  padding: 12px 14px;
  margin-top: 13px;
}
.guide-stuck b { font-size: 14px; color: var(--text-primary); }
.guide-stuck p { margin: 3px 0 0; font-size: 13px; color: var(--text-secondary); }
.guide-stuck a { color: var(--accent-text); }

/* The section title is an <h2> (document outline), so it needs its heading
   margins removed to sit on the summary line. No display change: the summary
   is a flex container and blockifies its children whatever they were. */
.guide-sec-title { margin: 0; }

/* THREE across on a desktop (Dan 2026-08-09, after seeing two), two on a
   tablet, one on a phone. Explicit counts rather than auto-fit: how many
   cards sit in a row is a design decision, not something to leave to
   whatever minimum width happens to divide into the container.

   The widths, because they are not obvious. ⚠ .static-page--solo is declared
   TWICE in this file — 900px at ~7046 and 1060px at ~7065 — and the later
   one wins, so the container is 1060px. Minus .static-page's 22px padding
   each side that leaves ~1016px, and three columns with two 12px gaps come
   out ~330px each. The third column starts at a 960px VIEWPORT rather than
   900px because at 900 the same maths gives ~277px, which is narrower than
   the 250px the shots were drawn against once padding is taken off. The
   shots are flex rows that wrap, so a tight card reflows rather than clips.
   721px is the site's phone cutover, used everywhere else. */
.guide-cards { grid-template-columns: 1fr; }
@media (min-width: 721px) {
  .guide-cards { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 960px) {
  .guide-cards { grid-template-columns: 1fr 1fr 1fr; }
}

/* More air between the cards (Dan 2026-08-09). 12px was set when they sat
   two across and read as a pair; at three across the grid looked like one
   block of text cut into strips. 18px on both axes — the gap is a grid gap,
   so the same number separates the rows.

   ⚠ The gap is part of the column arithmetic in the block above: three
   ~345px cards assumed two 12px gaps. At 18px they land at ~341px, which
   changes nothing that matters, but adjust both together if the column
   count moves again. */
.guide-cards { gap: 18px; }

/* ==========================================================================
   ADDITIONS 2026-08-09i — the Explore tour slide's visual
   --------------------------------------------------------------------------
   'ui:explore' on the carousel slide that closes every run. It borrows
   .hs-ui-card and .hs-ui-listrow from the mockups above; all it adds is the
   band of card shapes that stands for the open half's grid. Like every
   other mockup in that file it is a likeness, not a screenshot, so it
   follows the theme for free — see the note at the top of dcm_slides.php.
   ========================================================================== */

.hs-ui-explore .hs-ui-listrow em { color: var(--text-muted); }
.hs-ui-tiles {
  display: flex;
  gap: 5px;
  margin: 2px 0 4px 10px;
}
.hs-ui-tiles i {
  flex: 1;
  height: 26px;
  border-radius: 4px;
  border: 1px solid var(--border);
  background: var(--bg-surface);
}

/* ==========================================================================
   ADDITIONS 2026-08-09j — the Explore slide inside the FIRST-VISIT carousel
   --------------------------------------------------------------------------
   The same slide now renders in two carousels (Jen: "always include it for
   all users", and the personalised strip only reaches returning visitors).
   One definition, two contexts — so the shared partial needs its type
   matched to whichever carousel it lands in.

   In the strip, .hs-title is 26px because a slide there sits under a
   returning visitor's resume grid. In the hero it stands beside four slides
   whose headings are .car-title at 40px, and at 26px it read as a different
   kind of thing. The body follows .car-sub's measure for the same reason.
   ========================================================================== */

.hs-in-hero .hs-title { font-size: 40px; line-height: 1.08; }
.hs-in-hero .hs-body  { font-size: 15.5px; max-width: 430px; }
@media (max-width: 720px) {
  .hs-in-hero .hs-title { font-size: 30px; }
}

/* ==========================================================================
   ADDITIONS 2026-08-09k — the Explore slide's fanned cards (Dan, option 3)
   --------------------------------------------------------------------------
   Replaces the small flat card from 08-09i, which read as a diagram next to
   the carousel's photograph and its rendered devices. Three feature cards
   overlapping, echoing the notes-cascade slide two slides along.

   Sized to the box it must live in: .hs-visual caps at 132px tall in the
   hero carousel, so the fan is 300x130 and every card is positioned inside
   that. Under 860px .hs-visual drops to 108px, so the whole thing scales to
   .8 AND its box shrinks to match — a transform alone would leave a 130px
   hole and overflow the cap.

   The front card is simply LAST in the source, so no z-index is needed.
   ========================================================================== */

.hs-fan { position: relative; width: 300px; height: 130px; flex: 0 0 auto; }
.hs-fan-c {
  position: absolute;
  width: 170px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 8px 9px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: var(--bg-elevated);
}
.hs-fan-1 { left: 0;    top: 18px; transform: rotate(-6deg); opacity: .62; }
.hs-fan-2 { left: 44px; top: 4px;  transform: rotate(-1deg); opacity: .82; }
.hs-fan-3 { left: 96px; top: 24px; transform: rotate(5deg); border-color: var(--accent); }
.hs-fan-k { font-style: normal; font-size: 8.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent-text); }
.hs-fan-t { font-style: normal; font-size: 10.5px; line-height: 1.25; color: var(--text-primary); }
.hs-fan-b {
  font-style: normal;
  margin-top: 3px;
  height: 16px;
  border-radius: 4px;
  border: 1px solid var(--accent);
  background: var(--accent-tint);
  color: var(--accent-text);
  font-size: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* The strip's visual panel is 340px tall, so the fan has room to sit larger
   there than the hero's 132px cap allows. */
.home-slides .hs-fan { transform: scale(1.18); }

@media (max-width: 860px) {
  .hs-fan { width: 240px; height: 104px; transform: scale(.8); transform-origin: left center; }
  .home-slides .hs-fan { transform: scale(1); transform-origin: left center; }
}

/* The 08-09i block above (.hs-ui-explore / .hs-ui-tiles) is now DEAD: the
   Explore slide's visual was replaced by the fan the same day and no markup
   references those classes any more. Left in place rather than deleted
   because this file is append-only and the block records what was tried and
   why it was dropped; a grep for either name will land here. */

/* The tour link under the teachers page heading (Dan 2026-08-09). Pulled
   up tight to the heading it belongs to, and set at hint size so it reads
   as an aside rather than competing with the page's own lead copy. */
.tch-explore { margin-top: -2px; font-size: 14px; color: var(--text-muted); }
.tch-explore a { color: var(--accent-text); }
.tch-explore a:hover,
.tch-explore a:focus-visible { text-decoration: underline; }

/* ==========================================================================
   ADDITIONS 2026-08-09l — sign-in first on a phone (Dan)
   --------------------------------------------------------------------------
   The signed-out account page is .acct-split: "What you get" on the left,
   the sign-in box on the right. Source order puts the benefits first, which
   is right on a desktop where the two sit side by side and the eye starts
   left — but at 720px the grid becomes one column and the pitch buried the
   thing someone came to do. Someone who arrived to sign in should not have
   to scroll past nine selling points to find the box.

   `order` on the grid child, not a change to the markup, so the DESKTOP
   arrangement is untouched. Safe for tab order too: .acct-benefits is a
   static list with nothing focusable in it, so nobody keyboarding through
   meets the two in a different order than they see them.

   ⚠ .acct-split is declared four times in this file; the one that governs
   phones is the @media (max-width: 720px) at ~5295, the LAST of them. Check
   there before assuming what the mobile layout is.
   ========================================================================== */

@media (max-width: 720px) {
  .account-shell .acct-split > .acct-section  { order: -1; }
  .account-shell .acct-split > .acct-benefits { order: 0; }
}

/* A wider measure for the sign-in intro (Dan 2026-08-09: it should not roll
   to a third line unless it must). The signed-out shell gives .acct-sub a
   68ch measure so it breaks sensibly on a 1140px page; at 68ch this
   particular sentence took three lines.

   84ch, not the 76ch where it first fits on two: 76 is the exact threshold,
   so any word added later tips it straight back to three. 84 leaves room to
   edit the sentence without re-tuning this number, and is still a shorter
   line than the 100 characters Jen has objected to elsewhere.

   Measured at 1280px with the real sentence: 68ch = 3 lines, 76ch = 2,
   84ch = 2. Below 720px the container is narrower than any of this and the
   cap stops mattering. */
.account-shell.account-shell-signedout .acct-sub-wide { max-width: 84ch; }

/* The collections card grew a two-step list (Dan 2026-08-09). The cards had
   never held one, so it needs the same measure as their paragraphs rather
   than the browser's 40px default indent. */
.guide-card ol { margin: 0 0 7px; padding-left: 20px; font-size: 13px;
                 line-height: 1.55; color: var(--text-secondary); }
.guide-card ol li { margin: 3px 0; }

/* ==========================================================================
   ADDITIONS 2026-08-09m — Explore: one card per row, visual beside the text
   --------------------------------------------------------------------------
   Option B of the mockups. Three across could not cope with cards of very
   different lengths: the collections entry grew a two-step list and every
   short card in its row was padded out to match.

   ⚠ ONE CARD PER ROW ALONE WAS THE WRONG FIX — it was option A, and it puts
   the text across the full 1060px, which is past 140 characters a line.
   Jen has objected to 100 elsewhere. So the extra width goes to the PICTURE
   instead: a 270px column for the control mockup, the words in what is left,
   and lines land near 90 characters.

   No markup changed. The shot is placed in column 1 spanning every row and
   everything else is sent to column 2, so the ten cards did not need a
   wrapper div each. The span is a large number rather than `1 / -1`, which
   only spans the EXPLICIT grid and would collapse to one row here.

   Below 721px it all goes back to stacking, which is what a phone had
   anyway. These rules come after the earlier 2-column and 3-column ones and
   have the same specificity, so they win at every width.
   ========================================================================== */

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

@media (min-width: 721px) {
  .guide-card {
    display: grid;
    /* 300px, not the mockup's 270: at 270 the text column reached ~101
       characters a line on a 1440 screen, and 100 is the number Jen has
       pushed back on before. The extra 30px goes to the picture, which
       is the point of this layout, and brings the line to ~96. */
    grid-template-columns: 300px minmax(0, 1fr);
    column-gap: 18px;
    align-items: start;
    padding: 14px 16px;
  }
  .guide-card > .guide-shot { grid-column: 1; grid-row: 1 / span 30; min-height: 112px; }
  .guide-card > *:not(.guide-shot) { grid-column: 2; }
  /* The heading is the first thing in its column, so it loses the top
     margin that was spacing it off the shot when they were stacked. */
  .guide-card > h3 { margin-top: 0; }
}

/* The Add button in Saved for review (Dan 2026-08-09): the fill and colour
   of "Create it", trimmed to fit a starred row. btn-primary is a page-level
   control at 9px/14.5px — full size it makes every starred row noticeably
   taller, and there is one on each. Same background, same radius, smaller
   box. */
.acct-add { padding: 4px 12px; font-size: 12.5px; }

/* ==========================================================================
   ADDITIONS 2026-08-09n — the starred rows line up (Dan)
   --------------------------------------------------------------------------
   Watch → and Add sat at a different x on any row whose video title was
   long: .acct-row is a flex line and .acct-value is flex:1 with a basis of
   0, but flex-basis does not beat a word that will not fit, so one long
   title pushed everything after it to the right. Four rows agreed at 368px
   and the fifth sat at 405.

   A grid fixes the columns instead of negotiating them. minmax(0, 1fr) on
   the title is the part that matters: without the 0 minimum a grid track
   also refuses to go below min-content and the same push comes back.

   ⚠ Scoped to #saved. .acct-row is used all over this page — profile,
   classes, collections — and those rows hold different things.
   ========================================================================== */

#saved .acct-row {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr) auto auto auto;
  align-items: center;
  column-gap: 14px;
}
#saved .acct-row > .acct-value { min-width: 0; }

/* Saved for review takes the full row, collections moves under it (Dan
   2026-08-09, "make the tile a little wider if needed" — it was needed).

   Fixing the column alignment above traded a push for a wrap: the video
   title can no longer shove Watch → sideways, so instead it wrapped to
   three and four lines inside a 333px track and rows grew from 72px to
   106px. Five columns do not fit in 675px.

   ⚠ This breaks the deliberate 8 + 4 pairing a few blocks up ("the wide row
   keeps its 2:1 feel"). It is the only place the width could come from —
   the neighbour WAS the other four twelfths — so the pair becomes two
   full-width tiles stacked. Put the 8/4 back and the wrapping returns. */
#saved       { grid-column: span 12; }
#collections { grid-column: span 12; }

/* ==========================================================================
   ADDITIONS 2026-08-09o — starred and collection rows: text left, actions
   right (Dan 2026-08-09, option C of the mockups)
   --------------------------------------------------------------------------
   Replaces the five-column grid from 08-09n, which aligned the controls but
   made the title wrap to four lines to do it. Now the section and the title
   STACK in one flexible column and every control sits in a track of its own
   at the right, so nothing the text does can move them.

   Two columns, not five: the controls are one flex row, which is why a row
   with no collections (no dropdown, no Add) still lines its Watch up with
   the rows that have them.
   ========================================================================== */

#saved .acct-row,
#collections .acct-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 16px;
  row-gap: 8px;
  align-items: center;
}
.acct-rowtext  { min-width: 0; }
.acct-rowsect  { font-size: 12.5px; color: var(--text-muted); line-height: 1.35; }
.acct-rowtitle { font-size: 14.5px; color: var(--text-primary); line-height: 1.35; }
.acct-rowctl {
  display: flex;
  align-items: center;
  gap: 12px;
  justify-content: flex-end;
  white-space: nowrap;
}

/* The remove cross. A bordered target rather than bare text: at 14px a naked
   ✕ is a small thing to hit on a phone and reads as decoration. */
.acct-x {
  width: 26px; height: 26px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  background: none;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  color: var(--text-muted);
  font-size: 14px; line-height: 1;
  cursor: pointer;
}
.acct-x:hover { color: #d96c6c; border-color: #8c2f2f; }
/* ⚠ The destructive one. Deleting a collection and removing one video from
   it are the same mark an indent apart; this is what tells them apart at a
   glance. The confirm() on the form is the other half. */
.acct-x-hot { color: #E24B4A; border-color: #8c2f2f; }
.acct-x-hot:hover { color: #fff; background: #8c2f2f; }

/* On a phone there is no room for both columns, so the controls drop under
   the text and left-align — which is what the old flex row did anyway. */
@media (max-width: 620px) {
  #saved .acct-row,
  #collections .acct-row { grid-template-columns: minmax(0, 1fr); }
  .acct-rowctl { justify-content: flex-start; }
}

/* ==========================================================================
   ADDITIONS 2026-08-09p — the top band is two per row (Dan 2026-08-09)
   --------------------------------------------------------------------------
   Profile and My classes always pair on the first row. Then Stick figures
   and What brings you here pair on the second — or, when Stick figures has
   not been earned, What brings you here takes the whole width like Saved
   for review does.

   Why the tiles wanted this: at a quarter of the page the two option lists
   had to be written short ("Reviewing for a placement exam"); at half they
   fit as the site actually words them ("I'm reviewing for a placement exam
   (like ALEKS)"), and the email address stops needing an ellipsis.

   ⚠ data-top is only ever 3 or 4 — see account.php, $acct_top_n = 3 +
   sticks. Profile, My classes and What-brings-you-here always render, so
   "3" means precisely "no stick figures" and these two rules are total.

   ⚠ The 620px rule has to be repeated. These declarations come later in the
   file than the original @media block, and later wins at equal specificity
   whatever the media query, so without it a phone would keep two columns.
   ========================================================================== */

.acct-grid[data-top="3"] > .acct-topbox,
.acct-grid[data-top="4"] > .acct-topbox { grid-column: span 6; }

/* Alone on its row, so it spans it. The id beats the rule above. */
.acct-grid[data-top="3"] > #purpose { grid-column: span 12; }

@media (max-width: 620px) {
  .acct-grid[data-top="3"] > .acct-topbox,
  .acct-grid[data-top="4"] > .acct-topbox,
  .acct-grid[data-top="3"] > #purpose { grid-column: span 12; }
}

/* ==========================================================================
   PASSWORDS, BACK AGAIN (Dan 2026-08-09)
   --------------------------------------------------------------------------
   Two ways to sign in, and Jen's constraint was that the second one must not
   cost the first one anything: "make the login with password option
   non-intrusive to keep the sign in or log in tile clean." So the password
   field is not in the tile until somebody asks for it.

   ⚠ THE REVEAL IS THIS RULE AND NOTHING ELSE — no script is involved:
       #acct-usepw:checked ~ .acct-pwbox { display: grid }
   which means the checkbox and the box MUST STAY SIBLINGS. `~` does not
   climb out of a wrapper. If someone tidies the checkbox into its own row
   div, the selector stops matching, `display:none` never lifts, and the
   password field becomes unreachable with no error anywhere. There is a
   matching ⚠ in account.php.

   ⚠ display:GRID, not block. .cf-field is a grid (label / input / hint with
   a 6px gap); revealing it as a block collapses that spacing and the hint
   ends up flush against the input.

   ⚠ This stylesheet is APPEND-ONLY and this block is at the end, so these
   rules beat anything above them for the same selector. Nothing here is
   meant to override an earlier rule — the class names are all new.

   Nothing in this block reaches admin/admin.php. Its sign-in is a different
   mechanism on a different page and Jen asked for it to be left alone.
   ========================================================================== */

/* The wrapper exists to put a checkbox and its label on ONE line inside
   .contact-form, which is a grid and would otherwise stack them. The
   revealed field then spans both columns. */
.acct-pwwrap {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 8px;
}
.acct-pwwrap > input[type="checkbox"] { margin: 0; width: 15px; height: 15px; }
.acct-pwlabel {
  font-size: 13px;
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
}
.acct-pwlabel:hover { color: var(--accent-text); }

/* Hidden until asked for. Full width of the wrapper when it appears. */
.acct-pwbox { display: none; grid-column: 1 / -1; }
#acct-usepw:checked ~ .acct-pwbox { display: grid; }

/* "Show password" inside a password field — same one-line treatment, but it
   sits within a .cf-field's 6px grid rather than the wrapper above. */
.acct-pwtoggle {
  display: flex;
  align-items: center;
  gap: 7px;
}
.acct-pwtoggle > input[type="checkbox"] { margin: 0; width: 14px; height: 14px; }
.acct-pwtoggle > label {
  font-size: 12.5px;
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
}
.acct-pwtoggle > label:hover { color: var(--accent-text); }
.acct-pwshow { margin-top: 2px; }

/* The two full-page "pick a password" screens. They borrow .account-shell's
   width; all this does is stop the form running the full measure on a wide
   monitor, where a single short field looks lost. */
.acct-setpass .acct-section { max-width: 460px; }
.acct-setpass .acct-sub { max-width: 620px; }

/* The password disclosure in the Profile card sits directly under the email
   one and shares its styling; without this the two rules stack their
   borders and read as one thick divider. */
.acct-pwchange { margin-top: 10px; }

/* ==========================================================================
   ADDITIONS 2026-08-09p — the Explore slide's fan gets bigger (Dan)
   --------------------------------------------------------------------------
   "keep the image but make it bigger." It was 354x153 inside a 424x296 panel
   while the art on neighbouring slides runs 228-244px tall, so it read as the
   small one in the set. Now 414x179 on a normal desktop.

   ⚠ WIDTH IS THE LIMIT, NOT HEIGHT — which is the opposite of what the
   08-09k block above had to worry about. There are still ~57px of unused
   height at the biggest size here; the fan stops growing because 300px x
   scale runs out of PANEL WIDTH first. Do not "use the spare height".

   ⚠ AND THE PANEL WIDTH IS FLUID between 861px and ~1050px of viewport
   (measured: 349px at 870 -> 424px at 1100, then fixed). A single scale
   therefore cannot be right everywhere: 1.38 fits at 1100+ and overflows the
   panel by 11px at 980. Hence the bands. Each one is set from the panel
   width at the NARROW end of its own range, with ~6px to spare.

   ⚠ EVERY RULE IS INSIDE A min-width QUERY, on purpose. An unconditional
   `.home-slides .hs-fan { transform: ... }` here would sit LATER in this
   append-only file than the `max-width: 860px` rule in 08-09k and silently
   beat it, undoing the mobile fan. Scoping by min-width leaves that rule the
   only one that matches on a phone.

   The 861-939 band comes out at 1.12, SMALLER than the 1.18 it replaces:
   that was already overflowing its panel by ~2px a side at 870px. Fixing it
   was not the ask, but the band had to be given a value either way.

   Phones are untouched: at 375px the fan has 9px of slack and 20px of
   height, so there is nothing to give. (It does overflow at 320px — that
   predates this block and is still there.)
   ========================================================================== */

@media (min-width: 861px) and (max-width: 939px) {
  .home-slides .hs-fan { transform: scale(1.12); }
}
@media (min-width: 940px) and (max-width: 999px) {
  .home-slides .hs-fan { transform: scale(1.22); }
}
@media (min-width: 1000px) and (max-width: 1099px) {
  .home-slides .hs-fan { transform: scale(1.30); }
}
@media (min-width: 1100px) {
  .home-slides .hs-fan { transform: scale(1.38); }
}

/* ==========================================================================
   ADDITIONS 2026-08-09q — "Save your spot" art fills its panel (Dan)
   --------------------------------------------------------------------------
   The laptop-and-phone render was pinned at max-width 320px inside a 424px
   panel, so it sat at 73% of the panel height while the stick-figure slide
   beside it reaches 77% and most .hs-ui mockups are wider still. 320 was
   inherited from the 08-08i block, where the panel was a different size.

   372px is not arbitrary: it is the width .hs-ui uses on every other slide
   in this carousel, so the art in the strip now lines up on one edge instead
   of this one slide being inset. Its aspect is ~0.675, so 372 wide lands at
   ~251 tall against 256px of inner height (296px panel less its 20px
   padding) — the height is the real ceiling, and this sits just under it.
   ⚠ Do not push the width past ~376 without re-checking that: the art is
   width-driven and would start clipping vertically rather than horizontally.

   min-width scoped, like 08-09p, so the phone rules earlier in this
   append-only file keep winning on a phone.
   ========================================================================== */

@media (min-width: 861px) {
  .home-slides .hs-visual .car-dev { max-width: 372px; }
}

/* ==========================================================================
   ADDITIONS 2026-08-09r — the Explore fan is RE-PROPORTIONED, not just scaled
   --------------------------------------------------------------------------
   Dan, twice: "still looks smaller than it can be." He was right, and 08-09p
   could not have fixed it. That block scaled the fan until it ran out of
   PANEL WIDTH — 414px of 424 — and stopped at 61% of the panel height. The
   limit was never the scale factor, it was the SHAPE: three cards spread
   almost horizontally is a 2.3:1 composition sitting in a 1.4:1 panel, so
   width runs out with ~80px of height still unused. Scaling a wide, flat
   thing inside a nearly-square hole can only ever fill one axis.

   So the fan is now a STAIRCASE rather than a row: same three cards, same
   text, same overlap idea, but each card is bigger and each sits lower than
   the last instead of beside it. Intrinsic box 290x190 (was 300x130).

   ⚠ TARGET WIDTH IS 372-380, NOT 424. The old 414 was overflowing into the
   panel's own 20px padding, which is why this slide's art started further
   left than every other slide's. .hs-ui is 372 wide on eight of the twelve
   slides and the device render is now 372 too — matching that is what makes
   the strip line up on one edge, so do not "reclaim" the last 45px.

   ⚠ Height is now the binding constraint, the reverse of 08-09p: inner box
   is 256px (296 panel less 20px padding a side) and the fan lands at ~250.
   There is nothing left in either axis; a bigger card size from here starts
   clipping.
   ========================================================================== */

.hs-fan { width: 290px; height: 190px; }

.hs-fan-c {
  width: 200px;
  gap: 5px;
  padding: 11px 12px;
  border-radius: 10px;
}

/* A staircase: each card down AND across from the one before, so the group
   grows into the panel's height. Rotations are gentler than 08-09k's — at
   this size the old -6deg read as tilted rather than fanned. */
.hs-fan-1 { left: 0;   top: 0;   transform: rotate(-4deg); opacity: .62; }
.hs-fan-2 { left: 45px; top: 47px; transform: rotate(-1deg); opacity: .82; }
.hs-fan-3 { left: 90px; top: 94px; transform: rotate(3deg); border-color: var(--accent); }

.hs-fan-k { font-size: 10px; }
.hs-fan-t { font-size: 12.5px; line-height: 1.3; }
.hs-fan-b { height: 20px; font-size: 9.5px; margin-top: 4px; border-radius: 5px; }

/* Re-derived for the new 290px intrinsic width, same method as 08-09p: the
   panel width at the NARROW end of each band, less ~6px, over 290 — then
   held to the 372-380 ink target rather than filling the panel edge to
   edge. min-width scoped so the phone rule in 08-09k still wins. */
@media (min-width: 861px) and (max-width: 939px) {
  .home-slides .hs-fan { transform: scale(1.05); }
}
@media (min-width: 940px) and (max-width: 999px) {
  .home-slides .hs-fan { transform: scale(1.14); }
}
@media (min-width: 1000px) and (max-width: 1099px) {
  .home-slides .hs-fan { transform: scale(1.22); }
}
@media (min-width: 1100px) {
  .home-slides .hs-fan { transform: scale(1.30); }
}

/* --- 08-09r corrections, measured -----------------------------------------
   1. Card 3 sat 2px past the fan's right edge. The box is content-sized by
      hand (the cards are absolutely positioned, so nothing sizes it for us),
      and 90px of offset plus a 204px rotated bounding box needs 294, not
      290. A 2px bleed hurt nothing visually, but the fan's LAYOUT box is
      what keeps it off the text column, so it has to be honest.

   2. ⚠ THE MOBILE FAN. `.hs-fan { width/height }` above is unconditional and
      therefore beat 08-09k's `max-width: 860px` rule in this append-only
      file — the exact failure that block's own comment warns about, walked
      into while writing it. On a 375px screen the fan went to 290px wide in
      a 258px panel and escaped the slide. The phone needs the NEW geometry
      (the cards are bigger now, so 08-09k's 240x104 no longer describes
      them) scaled down to fit, so it is restated here rather than reverted.
   -------------------------------------------------------------------------- */

.hs-fan { width: 294px; }

@media (max-width: 860px) {
  .home-slides .hs-fan,
  .hs-fan {
    width: 294px; height: 190px;
    transform: scale(.8); transform-origin: left center;
  }
}

/* --- 08-09r, mobile: real geometry, not a scaled copy ----------------------
   The scale(.8) above got the INK down to 235px but left the LAYOUT box at
   294 — transform does not affect layout — so on a 375px screen the fan's
   box still overhung its 258px panel by 36px and pushed the slide out.
   ⚠ That is the second time in this block that "just scale it" was the wrong
   tool: a transform is invisible to everything that does layout, so it can
   only ever be a finishing touch, never a fit.

   So the phone gets the staircase at its own SIZE: smaller cards, tighter
   steps, no transform at all, box sized to what it actually draws (218x150
   inside a 258px panel). Same shape as the desktop version, which is the
   point — 08-09k's flat row is gone from both.
   -------------------------------------------------------------------------- */

@media (max-width: 860px) {
  .home-slides .hs-fan,
  .hs-fan { width: 218px; height: 150px; transform: none; }

  .hs-fan-c { width: 150px; gap: 3px; padding: 8px 9px; border-radius: 8px; }
  .hs-fan-1 { left: 0;    top: 0; }
  .hs-fan-2 { left: 33px; top: 37px; }
  .hs-fan-3 { left: 66px; top: 74px; }

  .hs-fan-k { font-size: 8.5px; }
  .hs-fan-t { font-size: 10.5px; line-height: 1.25; }
  .hs-fan-b { height: 16px; font-size: 8px; margin-top: 3px; border-radius: 4px; }
}
