/* Design system ported from _artifacts/hmm-course-portal-ui.html (the
   verified, contrast-measured mockup). Tokens, type scale, and component
   classes below are a direct lift, not a reinterpretation -- see that file
   for the contrast measurements and reasoning behind each decision.
   Self-hosted fonts (both Perfectly Nineties and Rethink Sans) rather than
   the mockup's base64-embedded/Google-Fonts-linked versions -- those exist
   only so the mockup renders standalone; this is a live product. */

@font-face {
  font-family: "Perfectly Nineties";
  src: url("fonts/PerfectlyNineties-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Perfectly Nineties";
  src: url("fonts/PerfectlyNineties-Italic.ttf") format("truetype");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Rethink Sans";
  src: url("fonts/RethinkSans_400Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Rethink Sans";
  src: url("fonts/RethinkSans_500Medium.ttf") format("truetype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Rethink Sans";
  src: url("fonts/RethinkSans_600SemiBold.ttf") format("truetype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Rethink Sans";
  src: url("fonts/RethinkSans_700Bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* =========================================================================
   RESET
   ========================================================================= */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; background: none; border: none; padding: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
img, svg { display: block; max-width: 100%; }
input { font: inherit; color: inherit; }

/* =========================================================================
   TOKENS -- values copied verbatim from the mockup, which copied them
   verbatim from lib/theme.ts. Do not introduce new colors here.
   ========================================================================= */
:root {
  --dark-brown: #593904;
  --mid-brown: #af9983;
  --light-brown: #c8b19b;
  --beige: #efdece;
  --additional-brown: #eadfd4;
  --off-white: #f9f1e9;
  --site-white: #fffcf8;
  --green: #848241;
  --warn: #b85c00;
  --overlay: rgba(89, 57, 4, 0.55);

  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 16px;
  --space-lg: 24px;
  --space-xl: 32px;
  --space-xxl: 48px;

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 20px;
  --radius-xxl: 32px;
  --radius-xxxl: 40px;
  --radius-pill: 999px;

  --font-heading: 'Perfectly Nineties', Georgia, 'Times New Roman', serif;
  --font-body: 'Rethink Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

/* =========================================================================
   CONTRAST DECISIONS (measured against this palette, not eyeballed --
   see the mockup file for the full ratio table). The consequences that
   matter while editing this file:
   1. midBrown is NEVER a text color. Dividers, disabled fills, and resting
      placeholder text only (placeholders are contrast-exempt under WCAG).
   2. Input borders use darkBrown, not lightBrown/midBrown -- the lighter
      browns fail the 3:1 non-text minimum against both the page and the
      input's own near-white fill.
   3. Buttons keep the app's real green fill/text (matches Button.tsx).
   4. Italic emphasis renders in darkBrown, never green, so it stays
      legible at body-copy sizes.
   ========================================================================= */

body {
  background: var(--off-white);
  color: var(--dark-brown);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* =========================================================================
   TYPOGRAPHY
   ========================================================================= */
.pn-72, .pn-56, .pn-36, .pn-24, .pn-18 {
  font-family: var(--font-heading);
  font-weight: 400;
  font-style: normal;
  line-height: 1.1;
  color: var(--dark-brown);
  margin: 0;
}
.pn-72 { font-size: clamp(42px, 5vw + 24px, 72px); }
.pn-56 { font-size: clamp(34px, 4vw + 20px, 56px); }
.pn-36 { font-size: clamp(27px, 3vw + 16px, 36px); }
.pn-24 { font-size: clamp(21px, 1.5vw + 15px, 24px); }
.pn-18 { font-size: clamp(17px, 1vw + 12px, 18px); }

/* Emphasis: Perfectly Nineties italic, never bold, always darkBrown. */
.emph {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 400;
  color: var(--dark-brown);
}

.rs-24 { font-family: var(--font-body); font-size: 24px; font-weight: 400; }
.rs-20 { font-family: var(--font-body); font-size: 20px; font-weight: 400; }
.rs-18 { font-family: var(--font-body); font-size: 18px; font-weight: 400; }
.rs-16 { font-family: var(--font-body); font-size: 16px; font-weight: 400; }
.rs-14 { font-family: var(--font-body); font-size: 14px; font-weight: 400; }
.rs-semibold { font-weight: 600; }
.rs-bold { font-weight: 700; }

.lede { font-family: var(--font-body); font-size: 18px; line-height: 1.5; color: var(--dark-brown); max-width: 46em; margin: 0; }
.body-copy { font-family: var(--font-body); font-size: 16px; line-height: 1.5; color: var(--dark-brown); max-width: 46em; margin: 0; }

.field-label {
  display: block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--dark-brown);
  margin-bottom: var(--space-sm);
}

/* =========================================================================
   ICONS
   ========================================================================= */
.icon { width: 22px; height: 22px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
.icon-sm { width: 16px; height: 16px; }
.icon-fill { fill: currentColor; stroke: none; }

/* =========================================================================
   LAYOUT SHELL
   ========================================================================= */
.shell {
  max-width: 720px;
  margin-inline: auto;
  padding-inline: clamp(20px, 5vw, 40px);
}
.view { min-height: 100vh; }

/* =========================================================================
   SHARED PORTAL HEADER
   Sign-in intentionally does not use this header -- an unauthenticated
   visitor has nowhere it could take her yet.
   ========================================================================= */
.portal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-sm);
  padding: 18px clamp(20px, 5vw, 40px);
  background: var(--site-white);
  border-bottom: 1px solid var(--light-brown);
}
.wordmark {
  font-family: var(--font-heading);
  font-size: 20px;
  color: var(--dark-brown);
}
.header-links { display: flex; align-items: center; gap: var(--space-md); }
.signout-link, .help-link {
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  color: var(--dark-brown);
  padding: var(--space-sm);
  margin: calc(var(--space-sm) * -1);
  border-radius: var(--radius-sm);
}
.signout-link:hover, .help-link:hover { text-decoration: underline; }

/* =========================================================================
   BUTTONS -- mirrors components/ui/Button.tsx (padding, radius, fill,
   weight). min-height asserted explicitly for the 44-52px touch target.
   ========================================================================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  min-height: 52px;
  padding: 16px 32px;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 16px;
  width: 100%;
  text-align: center;
}
.btn-primary { background: var(--green); color: var(--site-white); }
.btn-secondary { background: var(--dark-brown); color: var(--site-white); }
.btn-outline { background: transparent; border: 1.5px solid var(--green); color: var(--green); }
/* Aug 2026, practitioner.js's delete-document confirmation -- the first
   genuinely destructive action in this app's UI, warrants its own real
   variant rather than an inline color override in a JS template string. */
.btn-danger { background: var(--warn); color: var(--site-white); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
.btn-inline { width: auto; padding: 12px 20px; min-height: 44px; font-size: 14px; }

a:focus-visible, button:focus-visible, input:focus-visible, [tabindex]:focus-visible {
  outline: 3px solid var(--dark-brown);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* =========================================================================
   FORM FIELDS
   ========================================================================= */
.field { margin-bottom: var(--space-lg); }
.text-input {
  width: 100%;
  min-height: 52px;
  padding: 0 var(--space-md);
  background: var(--site-white);
  border: 1.5px solid var(--dark-brown);
  border-radius: var(--radius-md);
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--dark-brown);
}
.text-input::placeholder { color: var(--mid-brown); }
.text-input:focus { outline: none; border-width: 2px; box-shadow: 0 0 0 3px rgba(89, 57, 4, 0.15); }

/* =========================================================================
   CARDS
   ========================================================================= */
.card {
  display: block;
  background: var(--beige);
  border-radius: var(--radius-lg);
  padding: 20px;
  box-shadow: 0 1px 3px rgba(89, 57, 4, 0.08);
}

/* =========================================================================
   COVER IMAGERY -- shared by the library card grid and the product hero
   (product.js). A real Kajabi cover photo/screenshot renders in .cover-img;
   .cover-fallback sits underneath it at all times, so a product with no
   mapped cover, or an <img> that fails to load, always resolves to a
   deliberate typographic panel -- never a broken image, never a grey box.
   ========================================================================= */
.cover-media {
  position: relative;
  overflow: hidden;
  background: var(--beige);
}
.cover-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.cover-fallback {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-xs);
  padding: var(--space-md);
  background: var(--dark-brown);
  overflow: hidden;
}
.cover-fallback-mark {
  position: absolute;
  top: -0.2em;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-heading);
  font-style: italic;
  font-size: 200px;
  line-height: 1;
  color: rgba(249, 241, 233, 0.08);
  pointer-events: none;
  user-select: none;
}
.cover-fallback-eyebrow {
  position: relative;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--light-brown);
}
.cover-fallback-title {
  position: relative;
  font-family: var(--font-heading);
  font-style: italic;
  font-size: clamp(19px, 2vw + 14px, 24px);
  line-height: 1.25;
  color: var(--site-white);
  max-width: 22ch;
}
.card-cover { aspect-ratio: 16 / 9; }
.hero-cover {
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg);
  margin-bottom: var(--space-lg);
}

/* Icon chips -- ported from the app's numbered lesson-row circle (ModuleCard/
   LessonRow in app/courses/). Video rows fill solid olive (the "real
   accent" this pass is meant to bring in); file/download rows stay on the
   neutral additionalBrown so the colour carries actual meaning (playable
   vs. not), not decoration for its own sake. */
.icon-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}
.icon-chip .icon { width: 18px; height: 18px; opacity: 1; }
.icon-chip--video { background: var(--green); }
.icon-chip--video .icon { color: var(--site-white); }
.icon-chip--file { background: var(--additional-brown); }
.icon-chip--file .icon { color: var(--dark-brown); }

/* =========================================================================
   REDUCED MOTION -- motion is opted IN only here, so a user who prefers
   reduced motion (or whose browser doesn't support the query) gets instant
   state changes by default.
   ========================================================================= */
@media (prefers-reduced-motion: no-preference) {
  .module-panel { transition: grid-template-rows 0.25s ease; }
  .icon-chevron { transition: transform 0.2s ease; }
  .auth-card, .library-state { transition: opacity 0.2s ease; }

  /* Timings mirror components/motion/FadeInOnScroll.tsx and
     useScrollReveal.ts (600ms, Easing.out(Easing.cubic)) -- there is no
     scroll-linked measurement on a static page like this one, so the reveal
     runs once on load rather than on viewport entry, but the feel matches. */
  .card-grid .product-card {
    animation: cover-reveal 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) both;
  }
  .card-grid .product-card:nth-child(2) { animation-delay: 0.06s; }
  .card-grid .product-card:nth-child(3) { animation-delay: 0.12s; }
  .card-grid .product-card:nth-child(4) { animation-delay: 0.18s; }
  .card-grid .product-card:nth-child(n+5) { animation-delay: 0.24s; }
  @keyframes cover-reveal {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: translateY(0); }
  }

  .product-card {
    transition: transform 0.25s cubic-bezier(0.215, 0.61, 0.355, 1), box-shadow 0.25s ease;
  }
  a.product-card:hover, a.product-card:focus-visible {
    transform: translateY(-3px);
    box-shadow: 0 10px 24px rgba(89, 57, 4, 0.16);
  }
}

/* =========================================================================
   BANNERS -- not in the mockup (it has no error states to design), kept
   from the working build. Styled with the ported tokens.
   ========================================================================= */
.banner {
  padding: var(--space-md);
  border-radius: var(--radius-md);
  margin: 0 0 var(--space-lg);
  font-family: var(--font-body);
  font-size: 15px;
  color: var(--dark-brown);
  background: var(--additional-brown);
  border: 1.5px solid var(--light-brown);
}
.banner.error { border-color: var(--warn); }

/* Loading skeletons, not in the mockup either -- neutral fill only. */
.skeleton { background: var(--beige); border-radius: var(--radius-lg); height: 88px; opacity: 0.6; }

/* =========================================================================
   SIGN IN
   ========================================================================= */
.auth-shell {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-xl) var(--space-md);
  background: var(--beige);
}
/* The single flex child of .auth-shell -- see the comment on this element
   in index.html for why it must stay the only one. Banner and both cards
   stack inside it in normal block flow. */
.auth-card-wrap { width: 100%; max-width: 420px; }
/* A real card surface (the mockup left this bare) -- floats the sign-in
   flow above the shell's beige ground instead of the two tones reading as
   one flat field. */
.auth-card {
  width: 100%;
  max-width: 420px;
  background: var(--site-white);
  border-radius: var(--radius-xl);
  padding: var(--space-xl) clamp(20px, 5vw, 32px);
  box-shadow: 0 4px 20px rgba(89, 57, 4, 0.1);
}
.auth-wordmark { font-family: var(--font-heading); font-size: 22px; text-align: center; margin-bottom: var(--space-xl); }
.auth-heading { margin-bottom: var(--space-sm); }
.auth-lede { margin-bottom: var(--space-xl); }

/* Real Turnstile widget mounts inside .turnstile-box (interaction-only
   appearance -- invisible unless Cloudflare's risk engine forces a
   challenge). The box's border/padding gives it a defined, findable home
   on the page even when the widget itself renders nothing. */
.turnstile-box {
  display: flex;
  align-items: center;
  min-height: 24px;
  margin-bottom: var(--space-lg);
}

.help-row { text-align: center; margin-top: var(--space-lg); font-size: 14px; }
.help-row a { text-decoration: underline; font-weight: 600; }

.sent-icon {
  width: 56px; height: 56px;
  border-radius: 50%;
  background: var(--green);
  color: var(--site-white);
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto var(--space-lg);
}
.resend-row { margin-top: var(--space-lg); }
.resend-note { text-align: center; font-size: 14px; margin-top: var(--space-sm); }

/* Cross-device sign-in (see index.html for the two screens this serves).
   No monospace webfont added for one small feature -- a system stack
   renders a UUID-shaped code perfectly well. */
.code-paste-row {
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--light-brown);
}
.code-display {
  background: var(--site-white);
  border: 1.5px solid var(--dark-brown);
  border-radius: var(--radius-md);
  padding: var(--space-md);
  text-align: center;
}
.code-display span {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 18px;
  letter-spacing: 0.5px;
  color: var(--dark-brown);
  word-break: break-all;
  user-select: all;
}

/* =========================================================================
   LIBRARY
   ========================================================================= */
.library-main { padding-top: var(--space-xl); padding-bottom: var(--space-xxl); }
.library-main h1 { margin-bottom: var(--space-sm); }
.library-main .lede { margin-bottom: var(--space-xl); }

.card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
}
@media (min-width: 640px) {
  .card-grid { grid-template-columns: repeat(2, 1fr); }
}
/* Single-item state: cap the card width instead of letting grid stretch
   one card across a whole desktop row. Not an edge case -- 598 of 1,193
   members own exactly one product. */
.card-grid.card-grid--single {
  grid-template-columns: minmax(0, 420px);
}

/* The card itself is now just the outer frame -- .cover-media bleeds to its
   edges (top corners follow from overflow:hidden on the card), .product-card-body
   holds the padding the flat version used to put directly on .card. */
.product-card {
  padding: 0;
  overflow: hidden;
  background: var(--site-white);
  box-shadow: 0 4px 14px rgba(89, 57, 4, 0.12);
}
.product-card-body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-sm);
  padding: 18px 20px 20px;
}
.tag {
  display: inline-flex;
  align-items: center;
  padding: 3px 12px;
  border-radius: var(--radius-pill);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}
/* Course/Workbook is real, derived data (productTag() in app.js), not a
   decorative label -- the fill says something true about the product, so it
   gets the app's real green rather than a hairline outline. */
.tag--course { background: var(--green); color: var(--site-white); }
.tag--workbook { background: var(--light-brown); color: var(--dark-brown); }
.product-card-body h2 { margin-top: var(--space-xs); }
.product-card-meta { font-size: 15px; color: var(--dark-brown); margin: 0; }
.card-cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--space-sm);
  font-size: 15px;
  font-weight: 700;
  color: var(--dark-brown);
}
.card-cta .icon { width: 16px; height: 16px; }

.empty-state {
  text-align: center;
  padding: var(--space-xxl) var(--space-md);
  max-width: 440px;
  margin: 0 auto;
}
.empty-state-icon-wrap {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: var(--beige);
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto var(--space-lg);
}
.empty-state h1 { margin-bottom: var(--space-sm); }
.empty-state .body-copy { margin: 0 auto var(--space-lg); }
.empty-state .help-text { font-size: 14px; }
.empty-state .help-text a { text-decoration: underline; font-weight: 600; }

/* Plain external links to publicly hosted PDFs -- no entitlement gate, no
   /api/document proxy. Shown identically below the product grid (or below
   the empty-state) to every signed-in member; see freeResourcesHtml() in
   index.js. Same .card base and .card-cta "Open" pattern as the product
   cards above it, laid out as a row instead of a stack since there's no
   cover image here. */
/* "Your protocol" card, above the course grid (index.js) -- same
   .resource-card shape the free-resources row already uses, just alone
   and first, since it's the most personal reason she opened the app
   today. Absent from the DOM entirely when she has no protocol row --
   see protocolCardHtml() in index.js. */
.your-protocol { margin-bottom: var(--space-xxl); }
.your-protocol h2 { margin-bottom: var(--space-md); }

.free-resources { margin-top: var(--space-xxl); }
.free-resources h2 { margin-bottom: var(--space-xs); }
.free-resources .lede { margin-bottom: var(--space-lg); }
.resource-card {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}
.resource-card-title { flex: 1; font-size: 17px; font-weight: 700; color: var(--dark-brown); }
.resource-card .card-cta { margin-top: 0; }
a.resource-card:hover, a.resource-card:focus-visible { box-shadow: 0 6px 18px rgba(89, 57, 4, 0.14); }

/* =========================================================================
   PRODUCT
   ========================================================================= */
.product-main { padding-top: var(--space-lg); padding-bottom: var(--space-xxl); }
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 15px;
  font-weight: 600;
  margin-bottom: var(--space-lg);
  padding: var(--space-xs) 0;
}
.back-link .icon { width: 18px; height: 18px; }
.product-main .tag { margin-bottom: var(--space-sm); }
.product-main h1 { margin-bottom: var(--space-sm); }
#course-meta { color: var(--dark-brown); font-size: 15px; margin-bottom: var(--space-md); }

.module {
  border-top: 1px solid var(--light-brown);
}
.module:last-child { border-bottom: 1px solid var(--light-brown); }
.module-header {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-md) 4px;
  min-height: 56px;
  text-align: left;
  border-radius: var(--radius-md);
}
.module-header-text { display: flex; flex-direction: column; gap: 2px; }
.module-title { font-family: var(--font-body); font-weight: 700; font-size: 17px; color: var(--dark-brown); }
.module-meta { font-size: 14px; color: var(--dark-brown); opacity: 0.75; }
.module-header[aria-expanded="true"] .icon-chevron { transform: rotate(180deg); }
/* An open module gets its own ground, the same tan the lesson-row hover
   uses -- one visual language for "this is where you are" across the page. */
.module-header[aria-expanded="true"] { background: var(--additional-brown); }

.module-panel {
  display: grid;
  grid-template-rows: 0fr;
}
.module-panel.is-open { grid-template-rows: 1fr; }
.module-panel-inner { overflow: hidden; min-height: 0; padding-bottom: var(--space-sm); }

/* Single-module products (all 3 flat products) skip the accordion header
   entirely and render lesson rows directly -- see product.js. */
.no-module-heading { padding-top: var(--space-sm); }

.lesson-row {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  min-height: 56px;
  padding: var(--space-sm) 4px;
  border-radius: var(--radius-md);
  color: var(--dark-brown);
}
a.lesson-row:hover, a.lesson-row:focus-visible { background: var(--additional-brown); }
.lesson-row-title { flex: 1; font-size: 16px; }
.lesson-row-files {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 13px;
  color: var(--dark-brown);
  opacity: 0.75;
  flex-shrink: 0;
}
.lesson-row-duration { font-size: 14px; color: var(--dark-brown); opacity: 0.75; flex-shrink: 0; }
.lesson-row--download { cursor: default; }
.lesson-row-dl {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--dark-brown);
  padding: 6px 12px;
  border: 1.5px solid var(--dark-brown);
  border-radius: var(--radius-pill);
  flex-shrink: 0;
}

/* =========================================================================
   LESSON
   ========================================================================= */
.lesson-main { padding-top: var(--space-lg); padding-bottom: var(--space-xxl); max-width: 760px; }
/* Matches the app's sectionLabel treatment (rs14Bold, textAccent, 1.5px
   tracking) instead of a dimmed neutral line -- olive as a real accent. */
.lesson-eyebrow { font-size: 13px; font-weight: 700; letter-spacing: 1.5px; text-transform: uppercase; color: var(--green); margin-bottom: var(--space-xs); }
.lesson-main h1 { margin-bottom: var(--space-lg); }

/* Real Cloudflare Stream iframe, not the mockup's decorative placeholder
   transport bar -- the iframe embed already provides its own native
   controls (play/pause, scrubber, captions, fullscreen), so there is
   nothing for a second, non-functional control bar to do. The frame
   itself keeps the mockup's exact container treatment. */
.video-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--dark-brown);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin-bottom: var(--space-xl);
}
.video-frame iframe { width: 100%; height: 100%; border: 0; }
.video-placeholder-text {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--site-white);
  font-size: 14px;
  text-align: center;
  padding: var(--space-md);
}

/* Sanitized lesson body text (see lesson.js -- DOMPurify strips everything
   but plain structural/inline tags before this ever reaches the DOM).
   Typography matches body-copy; headings inside the source content are
   downgraded so they read as in-body emphasis, not a second page title
   competing with the real <h1> above. */
.lesson-body {
  margin-bottom: var(--space-xl);
  padding: var(--space-lg);
  background: var(--site-white);
  border-radius: var(--radius-lg);
  box-shadow: 0 1px 3px rgba(89, 57, 4, 0.08);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  color: var(--dark-brown);
  max-width: 46em;
}
.lesson-body p { margin: 0 0 var(--space-md); }
.lesson-body p:last-child { margin-bottom: 0; }
.lesson-body ul, .lesson-body ol { margin: 0 0 var(--space-md); padding-left: 1.4em; list-style: disc; }
.lesson-body ol { list-style: decimal; }
.lesson-body li { margin-bottom: var(--space-xs); }
.lesson-body a { text-decoration: underline; font-weight: 600; }
.lesson-body blockquote {
  margin: 0 0 var(--space-md);
  padding-left: var(--space-md);
  border-left: 3px solid var(--light-brown);
  color: var(--dark-brown);
}
.lesson-body h1, .lesson-body h2, .lesson-body h3,
.lesson-body h4, .lesson-body h5, .lesson-body h6 {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 16px;
  color: var(--dark-brown);
  margin: 0 0 var(--space-sm);
}
.lesson-body hr { border: none; border-top: 1px solid var(--light-brown); margin: var(--space-lg) 0; }

/* A distinct, neutral surface from .lesson-body's white card -- files read
   as a separate block of the page, not a continuation of the body copy. */
.files-section {
  background: var(--additional-brown);
  border-radius: var(--radius-lg);
  padding: var(--space-lg);
}
.files-section h2 { margin-bottom: var(--space-md); }
.file-row {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  min-height: 56px;
  padding: var(--space-sm) 0;
  border-bottom: 1px solid var(--light-brown);
}
.file-row:last-child { border-bottom: none; }
.file-row-name { flex: 1; font-size: 16px; }
.file-row-dl {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--dark-brown);
  padding: 8px 14px;
  border: 1.5px solid var(--dark-brown);
  border-radius: var(--radius-pill);
  flex-shrink: 0;
}
.file-row-dl:hover, .file-row-dl:focus-visible { background: var(--site-white); }

/* =========================================================================
   PRACTITIONER -- roster list (practitioner.html, Phase One: read-only,
   no per-row action yet). Same row/divider shape as .file-row above, not a
   card grid -- a name+email pair has no cover image or "Open" affordance
   to justify one.
   ========================================================================= */
.roster-list { list-style: none; margin: 0; padding: 0; }
.roster-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-md);
  min-height: 56px;
  padding: var(--space-sm) 0;
  border-bottom: 1px solid var(--light-brown);
}
.roster-row:last-child { border-bottom: none; }
.roster-row-name { font-size: 16px; font-weight: 700; color: var(--dark-brown); }
.roster-row-email { font-size: 14px; color: var(--mid-brown); }
/* Same look as .roster-row-email -- a generic secondary metadata line
   (Aug 2026: reused for a document's "Published <date>" row, not just an
   email), named for what it means rather than the one context it started in. */
.roster-row-meta { font-size: 14px; color: var(--mid-brown); }

/* Roster rows are buttons in the publish flow (Phase Two) -- reset button
   chrome on top of the existing flex/spacing rules above rather than
   duplicating them. */
.roster-row--button {
  width: 100%;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  font: inherit;
}
.roster-row--button:hover .roster-row-name, .roster-row--button:focus-visible .roster-row-name { text-decoration: underline; }

/* Roster rows as real links (Aug 2026: client-facing document list,
   protocol.js) -- same flex/spacing rules, no button chrome to reset,
   just the underline-on-hover an <a> doesn't get by default here. */
.roster-row--link { display: flex; text-decoration: none; color: inherit; }
.roster-row--link:hover .roster-row-name, .roster-row--link:focus-visible .roster-row-name { text-decoration: underline; }

/* Practitioner-facing "what this client already has" list (Aug 2026,
   practitioner.js's publish panel) -- title+date stacked on the left,
   Delete pinned right. A new class rather than reusing .roster-row: that
   one puts name/email side by side with no justify-content, the wrong
   shape for a row that also needs a button pinned to the far right. */
.doc-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  min-height: 56px;
  padding: var(--space-sm) 0;
  border-bottom: 1px solid var(--light-brown);
}
.doc-row:last-child { border-bottom: none; }
.doc-row-title { display: block; font-size: 16px; font-weight: 700; color: var(--dark-brown); }
.doc-row-date { display: block; font-size: 14px; color: var(--mid-brown); }

/* Delete affordance on each row above. Small, quiet, red only on hover --
   not the primary action on this row; opening the document isn't offered
   here at all (there is nothing to preview after publish; she already
   saw it before confirming). */
.doc-row-delete {
  background: none;
  border: none;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--mid-brown);
  cursor: pointer;
  padding: 6px 10px;
  flex-shrink: 0;
}
.doc-row-delete:hover, .doc-row-delete:focus-visible { color: var(--warn); }

/* =========================================================================
   PRACTITIONER -- publish panel (practitioner.html, Phase Two)
   ========================================================================= */
.publish-section { max-width: 640px; }
.publish-section .field { margin-top: var(--space-lg); }
#publish-preview-wrap { margin-top: var(--space-lg); }
#publish-open-confirm { margin-top: var(--space-xl); }

.publish-confirm {
  margin-top: var(--space-xl);
  padding: var(--space-lg);
  background: var(--additional-brown);
  border-radius: var(--radius-lg);
}
.publish-confirm-name { font-size: 20px; font-weight: 700; color: var(--dark-brown); margin: var(--space-xs) 0 0; }
.publish-confirm-email { font-size: 15px; color: var(--mid-brown); margin: 2px 0 var(--space-lg); }

.banner.success { border-color: var(--green); }
