/* bernard courses - deliberately plain; the site’s own styles lead. */
/* Base-font floor: without it, sites whose sampled theme derives no body font
   fall to the browser default serif. Same selector shape as the theme’s
   site-match rule and loaded BEFORE it, so a sampled site font still wins. */
body[data-bernard-courses] { font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; line-height: 1.6; }
.course-header, .course-footer { display: flex; justify-content: space-between; align-items: center; padding: 1rem 1.5rem; }
.course-header a, .course-footer a { color: inherit; text-decoration: none; font-weight: 600; }
.course-header nav a { margin-left: 1rem; font-weight: 400; }
.course-main { max-width: 46rem; margin: 0 auto; padding: 1rem 1.5rem 4rem; }
.course-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: 1.5rem; }
.course-card { display: block; color: inherit; text-decoration: none; }
.course-card img, .course-card-blank { width: 100%; aspect-ratio: 16/9; object-fit: cover; background: #f2f2ef; border-radius: 4px; }
.course-card h3 { margin: 0.6rem 0 0.15rem; font-size: 1rem; }
.course-card-summary { margin: 0.15rem 0; font-size: 0.9rem; opacity: 0.75; }
.course-card-meta { margin: 0.15rem 0; font-size: 0.85rem; opacity: 0.6; }
.course-cover { width: 100%; border-radius: 4px; margin-bottom: 1rem; }
.course-table-wrap { overflow-x: auto; margin: 1.4em 0; }
.course-table-wrap table { border-collapse: collapse; width: 100%; font-size: 0.95em; }
.course-table-wrap th, .course-table-wrap td { border: 1px solid #ddd; padding: 0.5rem 0.75rem; text-align: left; vertical-align: top; }
.course-table-wrap th { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 7%, transparent); font-weight: 600; }
.course-price { font-size: 1.15rem; margin: 0.5rem 0 0.15rem; }
/* Reassurance, not content: one rung below body copy, and it sits above the
   door (see courseHero). */
.course-access { margin: 0.15rem 0 1.1rem; opacity: 0.7; font-size: 0.9rem; }
/* inline-flex + min-height so the button matches the email field’s height in
   the free-enrol row; they used to differ by 7px. */
.course-enrol { display: inline-flex; align-items: center; justify-content: center; min-height: 3rem; padding: 0.75rem 2rem; font-size: 0.95rem; font-weight: 600; line-height: 1.2; cursor: pointer; border-radius: 6px; border: 1px solid transparent; background: var(--bernard-accent, #1c5e53); color: var(--bernard-accent-ink, #fff); }
.course-enrol:hover { filter: brightness(1.08); }
.course-enrol:focus-visible, .course-free-enrol input:focus-visible, .course-recover input:focus-visible, .course-recover button:focus-visible { outline: 2px solid var(--bernard-accent, #1c5e53); outline-offset: 2px; }
.course-enrol[disabled] { opacity: 0.5; cursor: default; }
.course-soon { opacity: 0.7; }
/* The free door: one clear row - label+input beside the button on wide
   screens, stacked on phones. The email input matches the enquiry form’s
   fields; states read as states, not stray paragraphs. */
.course-free-enrol { margin: 0.75rem 0 0.5rem; }
/* The field label is furniture, not a heading: a rung below body copy so the
   button is the loudest thing in the row. It used to match the button exactly
   (17px/600 against 17px/600), which left the block with no hierarchy at all. */
.course-free-enrol > label:first-child { display: block; font-size: 0.85rem; font-weight: 600; margin-bottom: 0.35rem; }
/* box-sizing is the whole ball game here (found live on lewisnoble,
   2026-08-20). A migrated site’s own reset does NOT necessarily cover our
   inputs, so width:100% + padding + border made the field 27px WIDER than
   the slot it was given: on desktop its right edge ran under the button, and
   on a 390px phone it hung 2px off the right of the page and was the only
   thing making the document scroll sideways. Never size one of our fields
   without pinning box-sizing first.
   font-weight is reset because "font: inherit" picks up the label’s 600 and
   would render the visitor’s typed email in bold. */
.course-free-enrol > label:first-child input { box-sizing: border-box; display: block; width: 100%; max-width: 22rem; min-height: 3rem; margin-top: 0.35rem; padding: 0.65rem 0.75rem; font: inherit; font-size: max(16px, 1rem); font-weight: 400; border: 1px solid color-mix(in srgb, currentColor 40%, transparent); border-radius: 6px; background: transparent; color: inherit; }
.course-free-enrol-marketing { display: flex; align-items: center; gap: 0.5rem; margin: 0.6rem 0 0.9rem; font-size: 0.9rem; opacity: 0.85; font-weight: 400; }
.course-free-enrol-marketing input { width: 1rem; height: 1rem; accent-color: var(--bernard-accent, #1c5e53); }
@media (min-width: 560px) {
  /* max-content, NOT auto, for the button track. An "auto" track absorbs all
     the leftover width of the column, so in a 1088px course column the
     "Enrol free" button rendered 701px wide - nobody chose that, and its left
     edge then sat on top of the email field (found live on lewisnoble,
     2026-08-20). A CTA should be sized by its label. */
  .course-free-enrol { display: grid; grid-template-columns: minmax(0, 22rem) max-content; gap: 0.5rem 0.75rem; align-items: end; }
  .course-free-enrol > label:first-child { margin-bottom: 0; }
  .course-free-enrol .course-enrol { grid-column: 2; grid-row: 1; }
  .course-free-enrol-marketing, .course-free-enrol-done, .course-free-enrol-error { grid-column: 1 / -1; }
}
.course-free-enrol-done { font-weight: 600; margin: 0.25rem 0 0; }
.course-free-enrol-error { font-weight: 600; margin: 0.25rem 0 0; }
.course-enrolled-note p { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 9%, transparent); border-radius: 4px; padding: 0.6rem 1rem; }
/* The escape hatch: quietest thing in the block, and UNDERLINED. Without the
   underline it read as a plain sentence, so the one route back in for an
   existing learner did not look clickable at all. */
.course-recover { margin: 0.9rem 0 1.5rem; font-size: 0.85rem; }
.course-recover summary { cursor: pointer; opacity: 0.7; text-decoration: underline; text-underline-offset: 3px; }
.course-recover label { display: block; margin: 0.6rem 0 0.4rem; }
/* 16px is a floor, not a preference: iOS Safari ZOOMS the whole page when a
   focused field is smaller, so tapping this box shoved the layout sideways on
   a phone. The box sets 0.85rem, which lands at about 13.6px - and the people
   most likely to need this form are the least likely to enjoy the page
   jumping at them. */
.course-recover input { box-sizing: border-box; display: block; margin-top: 0.25rem; padding: 0.55rem 0.7rem; min-width: 16rem; max-width: 100%; font: inherit; font-size: max(16px, 1rem); border: 1px solid color-mix(in srgb, currentColor 40%, transparent); border-radius: 6px; background: transparent; color: inherit; }
.course-recover button { padding: 0.45rem 1rem; cursor: pointer; }
.course-recover button[disabled] { opacity: 0.55; cursor: default; }
.course-recover-wait { margin: 0.5rem 0 0; opacity: 0.85; }
.course-recover-hint { margin: 0.15rem 0 0.6rem; opacity: 0.7; }
/* Built by courses.js (bndEmailGate), so it lands in the OWNER’S cascade with
   no theme rule of its own. Structure is pinned inline by the runtime; this is
   only the quiet register - and the two answer buttons must not look like the
   primary action, because "No, mine’s right" is a perfectly good answer. */
.bnd-email-check { font-size: 0.95em; }
.bnd-email-check button { font: inherit; padding: 0.3rem 0.7rem; cursor: pointer; }
/* The shop window’s invitation (PRD 145 #4a) - where a checkout would be. */
.course-enquiry { margin: 1.5rem 0 2rem; }
.course-enquiry h2 { margin: 0 0 0.75rem; font-size: 1.15rem; }
.course-enquiry-form label { display: block; margin-bottom: 0.75rem; }
.course-enquiry-form input, .course-enquiry-form textarea { box-sizing: border-box; display: block; margin-top: 0.25rem; width: 100%; max-width: 26rem; padding: 0.5rem; font: inherit; border: 1px solid currentColor; border-radius: 4px; background: transparent; color: inherit; }
.course-enquiry-form textarea { resize: vertical; }
[data-bernard-form-feedback] { margin: 0.5rem 0; opacity: 0.8; }
[data-bernard-form-status="error"] { opacity: 1; }
.course-description { margin: 1.5rem 0; }
/* Imported descriptions/notes carry real markdown images (often the old
   site’s full-size uploads) - bound them to the column, never the viewport. */
.course-description img, .course-notes img { max-width: 100%; height: auto; border-radius: 4px; }
.course-description h1, .course-description h2 { font-size: 1.35rem; margin: 1.5rem 0 0.5rem; }
.course-description h3, .course-description h4, .course-description h5, .course-description h6,
.course-notes h1, .course-notes h2, .course-notes h3, .course-notes h4, .course-notes h5, .course-notes h6 { font-size: 1.1rem; margin: 1.25rem 0 0.5rem; }
.course-section-title { margin: 1.5rem 0 0.5rem; font-size: 1.05rem; }
/* PRD 96 #484 - a collapsible module on the CONTENTS page. Its own family, on
   purpose: "course-accordion" belongs to the lesson-notes marker pair and the
   two must never share a rule. Same plain register as that one - the native
   marker off, a "+" that becomes a minus when open, a 48px summary so a thumb
   can hit it, and a visible focus ring for keyboard use. */
.course-contents-section { border-bottom: 1px solid rgba(0,0,0,0.08); }
.course-contents-section > summary { box-sizing: border-box; list-style: none; cursor: pointer; display: flex; align-items: center; gap: 0.6rem; min-height: 48px; font-weight: 600; font-size: 1.05rem; }
.course-contents-section > summary::-webkit-details-marker { display: none; }
.course-contents-section > summary::before { content: "+"; width: 20px; flex: none; font-weight: 400; opacity: 0.55; }
.course-contents-section[open] > summary::before { content: "\2212"; }
.course-contents-section > summary:focus-visible { outline: 2px solid var(--bernard-accent, #1c5e53); outline-offset: 2px; }
/* The module title stays an <h2> so the modules keep their place in the
   page outline - it is what a search engine and an answer engine read the
   shape of a course from. <summary> permits heading content; the heading
   just has to stop behaving like a block in the flex row, so the standalone
   rule’s top margin and its own font sizing are reset here. */
.course-contents-section > summary > .course-section-title { flex: 1 1 auto; min-width: 0; margin: 0; font-size: inherit; font-weight: inherit; line-height: inherit; }
.course-contents-section-meta { flex: none; font-weight: 400; font-size: 0.85rem; opacity: 0.7; }
.course-contents-section > .course-syllabus { margin-top: 0; }
.course-syllabus { list-style: none; margin: 0.5rem 0; padding: 0; }
.course-syllabus-item { padding: 0.6rem 0; border-bottom: 1px solid rgba(0,0,0,0.08); }
.course-syllabus-item a { color: inherit; text-decoration: none; font-weight: 600; }
.course-syllabus-item.is-sub-lesson { padding-left: 1.6rem; }
.course-syllabus-item.is-sub-lesson a { font-weight: 400; }
.course-lesson-n { display: inline-block; min-width: 1.5rem; opacity: 0.5; }
.course-tag { font-size: 0.75rem; margin-left: 0.5rem; padding: 0.1rem 0.5rem; border-radius: 99px; background: #f2f2ef; }
.course-tag-free, .course-tag-unlocked { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 14%, transparent); }
.course-lesson-meta { margin-left: 0.5rem; font-size: 0.8rem; opacity: 0.55; }
.course-lesson-summary { margin: 0.25rem 0 0 2rem; font-size: 0.9rem; opacity: 0.75; }
.course-crumb { font-size: 0.85rem; opacity: 0.65; }
.course-crumb a { color: inherit; }
.course-crumb-sep { margin: 0 0.4rem; opacity: 0.5; }
/* PRD 152 - the quiz page. Every colour is derived from the site’s own accent
   (--bernard-accent, set by the sampled courses-theme.css) or from
   currentColor, so the page adopts the site’s look rather than carrying a
   palette of its own. The pass/fail greens and reds are the only fixed hues,
   because "correct" and "wrong" must not depend on a brand colour that might
   itself be red. */
.course-quiz-kicker { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--bernard-accent, #1c5e53); margin: 0 0 0.4rem; }
.course-quiz-head h1 { margin: 0 0 0.5rem; }
.course-quiz-meta { display: flex; gap: 1.1rem; flex-wrap: wrap; font-size: 0.85rem; opacity: 0.7; margin-bottom: 1.4rem; }
.course-quiz-meta b { font-weight: 600; opacity: 1; }
.course-tag-quiz { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 10%, transparent); }
.course-quiz-q { border: 1px solid rgba(0,0,0,0.1); border-radius: 14px; padding: 1.2rem 1.4rem; margin: 0 0 1rem; background: rgba(255,255,255,0.65); }
.course-quiz-n { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.55; margin: 0 0 0.5rem; }
.course-quiz-prompt { font-weight: 500; margin: 0 0 0.9rem; }
.course-quiz-prompt p { margin: 0 0 0.4rem; }
.course-quiz-opts { display: flex; flex-direction: column; gap: 0.55rem; }
.course-quiz-opt { display: flex; gap: 0.7rem; align-items: flex-start; border: 1px solid rgba(0,0,0,0.12); border-radius: 10px; padding: 0.7rem 0.85rem; }
.course-quiz-opt:hover { border-color: var(--bernard-accent, #1c5e53); }
.course-quiz-opt input { margin-top: 0.28rem; accent-color: var(--bernard-accent, #1c5e53); }
.course-quiz-opt label { flex: 1; cursor: pointer; }
.course-quiz-q.is-marked .course-quiz-opt { pointer-events: none; }
.course-quiz-q.is-marked .course-quiz-opt.is-chosen.is-right { background: #eef6f0; border-color: #2e7d4f; }
.course-quiz-q.is-marked .course-quiz-opt.is-chosen.is-wrong { background: #fbf0ef; border-color: #a8352f; }
.course-quiz-q.is-marked .course-quiz-opt.is-answer { border-color: #2e7d4f; border-style: dashed; }
.course-quiz-verdict { margin-top: 0.8rem; font-size: 0.9rem; border-radius: 10px; padding: 0.6rem 0.8rem; }
.course-quiz-verdict.is-right { background: #eef6f0; color: #2e7d4f; font-weight: 500; }
.course-quiz-verdict.is-wrong { background: #fbf0ef; }
.course-quiz-verdict.is-wrong b { color: #a8352f; }
.course-quiz-verdict p { margin: 0.35rem 0 0; }
.course-quiz-result { display: flex; gap: 1.1rem; align-items: center; border: 1px solid rgba(0,0,0,0.1); border-radius: 14px; padding: 1.1rem 1.2rem; margin: 0 0 1.3rem; }
.course-quiz-result.is-pass { background: #eef6f0; border-color: #cfe4d6; }
.course-quiz-result.is-fail { background: #fbf0ef; border-color: #eeddda; }
.course-quiz-score { font-size: 2.4rem; font-weight: 600; line-height: 1; min-width: 4.8rem; text-align: center; }
.course-quiz-result.is-pass .course-quiz-score { color: #2e7d4f; }
.course-quiz-result.is-fail .course-quiz-score { color: #a8352f; }
.course-quiz-result h2 { margin: 0 0 0.2rem; font-size: 1.15rem; }
.course-quiz-result p { margin: 0; font-size: 0.9rem; opacity: 0.8; }
.course-quiz-result .course-quiz-cert { margin-top: 0.35rem; opacity: 1; }
.course-quiz-bar { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; margin-top: 1.4rem; }
.course-quiz-submit { padding: 0.75rem 1.6rem; font-size: 0.95rem; font-weight: 600; cursor: pointer; border-radius: 4px; border: 1px solid transparent; background: var(--bernard-accent, #1c5e53); color: var(--bernard-accent-ink, #fff); }
.course-quiz-submit[disabled] { opacity: 0.45; cursor: not-allowed; }
.course-quiz-retry { padding: 0.75rem 1.6rem; font-size: 0.95rem; cursor: pointer; border-radius: 4px; border: 1px solid rgba(0,0,0,0.2); background: transparent; color: inherit; }
.course-quiz-hint { font-size: 0.85rem; opacity: 0.65; }
.course-quiz-error { font-size: 0.9rem; color: #a8352f; }
.course-quiz :focus-visible { outline: 2px solid var(--bernard-accent, #1c5e53); outline-offset: 2px; }
/* Narrow phones. Deliberately NOT a second max-width:480px block: the
   player’s own 480px block is located by string index in
   tests/course-player-emitted.test.ts, and a second one earlier in the sheet
   would take that anchor out from under it. 30rem is the same width. */
@media (max-width: 30rem) {
  .course-quiz-q { padding: 1rem 0.9rem; }
  .course-quiz-score { font-size: 2rem; min-width: 3.6rem; }
}
.course-video { position: relative; aspect-ratio: 16/9; margin: 1rem 0; background: #10201c; border-radius: 4px; overflow: hidden; }
.course-video iframe, .course-video video { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.course-video video { object-fit: contain; }
/* A YouTube Short embedded via <iframe> (videoEmbedHtml) reuses the SAME
   portrait treatment as the hosted player’s .bnd-player-root.is-portrait
   rule below (max-height, centered) instead of a second mechanism - just
   targeted at .course-video since the static embed has no .bnd-player-root
   wrapper. 9/16 overrides the 16/9 default above so the iframe box itself
   is portrait-shaped, not just height-capped. */
.course-video.is-portrait { aspect-ratio: 9/16; max-height: min(80vh, 42rem); width: auto; margin-inline: auto; }
/* PRD 160 audio lesson: the SAME 16/9 stage, with the course artwork painted
   behind a video element that has no picture of its own to draw. The element
   stays in the layout (it is the player - controls, captions, chapters and
   resume all hang off it); it just contributes nothing visually, so the
   artwork behind it shows through - which is why the video element must stay
   transparent rather than inheriting a paint of its own. The artwork itself is
   set inline by the runtime, since it is per-course. The static pre-hydration
   slot uses .course-audio for the same dark ground. */
.bnd-player-audio, .course-video.course-audio { background-color: #10201c; }
.bnd-player-audio video { background: transparent; }
.bnd-player:fullscreen { aspect-ratio: auto; }
.bnd-player:-webkit-full-screen { aspect-ratio: auto; }
.course-loading { position: absolute; inset: 0; display: grid; place-items: center; color: #fff; opacity: 0.7; }
/* WP3 - the enrolled lesson’s holding shape, painted by courses.js the moment
   it decides to ask /access, so the content area is never blank. Reserves the
   video stage and three lines of notes, so nothing jumps when the real content
   lands. The shimmer respects prefers-reduced-motion. */
.course-skeleton { margin: 1.25rem 0; }
.course-skeleton-stage { aspect-ratio: 16 / 9; border-radius: 6px; margin-bottom: 1rem; }
.course-skeleton-line { height: 1rem; border-radius: 4px; margin: 0.6rem 0; }
.course-skeleton-line:last-child { width: 62%; }
.course-skeleton-stage, .course-skeleton-line { background: linear-gradient(90deg, rgba(0,0,0,0.06) 25%, rgba(0,0,0,0.11) 37%, rgba(0,0,0,0.06) 63%); background-size: 400% 100%; animation: bnd-skeleton 1.4s ease infinite; }
@keyframes bnd-skeleton { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) { .course-skeleton-stage, .course-skeleton-line { animation: none; } }
.course-skeleton-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.bnd-player { outline: none; }
.bnd-player-bar { position: absolute; left: 0; right: 0; bottom: 0; display: flex; align-items: center; gap: 0.35rem; padding: 0.5rem 0.6rem; background: linear-gradient(to top, rgba(0,0,0,0.75), transparent); transition: opacity 0.2s ease; opacity: 1; pointer-events: auto; flex-wrap: wrap; }
.bnd-player.bnd-player-idle .bnd-player-bar { opacity: 0; }
.bnd-player-btn { min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; background: transparent; border: 0; color: #fff; cursor: pointer; border-radius: 4px; font-size: 0.85rem; padding: 0 0.4rem; margin: 0; line-height: 1; appearance: none; -webkit-appearance: none; box-shadow: none; font-family: inherit; }
.bnd-player-btn:hover, .bnd-player-btn:focus-visible { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 45%, transparent); }
/* The chrome lives inside an arbitrary customer site whose stylesheet also
   targets bare button/:focus-visible (witnessed: howto’s 3px ochre outline,
   offset 3px, swallowing the play button at small sizes). !important because
   a site is free to use id-scoped selectors we cannot outrank politely; the
   keyboard focus ring stays visible via our own :focus-visible treatment. */
.bnd-player-btn:focus { outline: none !important; }
.bnd-player-btn:focus-visible { outline: 2px solid rgba(255,255,255,0.9) !important; outline-offset: -2px !important; }
.bnd-player-time { color: #fff; font-size: 0.8rem; min-width: 5.5rem; text-align: center; }
.bnd-player-scrub { position: relative; flex: 1 1 8rem; min-width: 6rem; height: 44px; display: flex; align-items: center; }
.bnd-player-buffered { position: absolute; left: 0; top: 50%; height: 4px; transform: translateY(-50%); background: rgba(255,255,255,0.35); border-radius: 2px; width: 0%; pointer-events: none; }
.bnd-player-scrub input[type="range"] { box-sizing: border-box; position: relative; width: 100%; accent-color: var(--bernard-accent, #1c5e53); height: 44px; cursor: pointer; }
.bnd-player-captions-on, .bnd-player-playing { color: var(--bernard-accent, #1c5e53); }
/* PRD 172: the subtitle language menu. A real <select> rather than a custom
   popover - it has to work over a fullscreen video, where an absolutely
   positioned menu of our own would be painted behind the video on iOS. */
.bnd-player-caption-lang { width: auto; min-width: 0; padding: 0 0.4rem; max-width: 8rem; font: inherit; font-size: 0.8rem; color: #fff; background: rgba(0,0,0,0.35); border: 1px solid rgba(255,255,255,0.35); border-radius: 3px; cursor: pointer; }
.bnd-player-caption-lang option { color: #10201c; background: #fff; }
.bnd-player-caption-lang[hidden] { display: none; }
.bnd-player-note { position: absolute; top: 0.6rem; left: 50%; transform: translateX(-50%); max-width: calc(100% - 1.6rem); box-sizing: border-box; background: rgba(0,0,0,0.75); color: #fff; font-size: 0.85rem; padding: 0.35rem 0.9rem; border-radius: 999px; z-index: 2; pointer-events: none; text-align: center; }
.bnd-player-note[hidden] { display: none; }
.bnd-preview-thumb { position: absolute; left: 0; bottom: 3.2rem; max-width: calc(100% - 8px); max-height: 160px; background-color: #10201c; background-repeat: no-repeat; border: 2px solid rgba(255,255,255,0.85); border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.35); pointer-events: none; display: none; align-items: flex-end; justify-content: center; z-index: 2; box-sizing: border-box; }
.bnd-preview-thumb:not([hidden]) { display: flex; }
.bnd-preview-thumb-time { margin: 0.2rem; padding: 0.05rem 0.4rem; max-width: calc(100% - 0.4rem); background: rgba(0,0,0,0.75); color: #fff; font-size: 0.7rem; border-radius: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; box-sizing: border-box; }
.bnd-chapter-tick { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 3px; height: 12px; background: rgba(255,255,255,0.85); border-radius: 1px; pointer-events: none; z-index: 1; }
.bnd-player-root { display: block; }
.bnd-upnext { position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.75rem; padding: 1.5rem; text-align: center; background: rgba(16,32,28,0.92); color: #fff; }
.bnd-upnext-label { margin: 0; font-size: 1rem; opacity: 0.85; }
.bnd-upnext-next { display: inline-block; padding: 0.6rem 1.5rem; border-radius: 4px; background: var(--bernard-accent, #1c5e53); color: var(--bernard-accent-ink, #fff); text-decoration: none; font-weight: 600; min-height: 44px; line-height: 1.9; }
.bnd-upnext-again { min-height: 44px; padding: 0.5rem 1.25rem; border-radius: 4px; border: 1px solid rgba(255,255,255,0.4); background: transparent; color: #fff; cursor: pointer; font: inherit; }
.course-tick { display: none; margin-left: 0.5rem; opacity: 0.6; }
.course-syllabus-item-done .course-tick { display: inline; }
.bnd-chapter-list { list-style: none; margin: 0.75rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.25rem; }
.bnd-chapter-item { display: flex; align-items: center; gap: 0.6rem; width: 100%; min-height: 44px; text-align: left; padding: 0.5rem 0.75rem; background: transparent; border: 0; border-radius: 4px; cursor: pointer; font: inherit; color: inherit; }
.bnd-chapter-item:hover, .bnd-chapter-item:focus-visible { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 12%, transparent); }
.bnd-chapter-thumb { width: 4rem; aspect-ratio: 16/9; object-fit: cover; border-radius: 3px; flex: none; background: #10201c; }
.bnd-chapter-item-title { flex: 1 1 auto; }
.course-notes { margin: 1.25rem 0; }
.course-locked { border: 1px solid rgba(0,0,0,0.12); border-left: 3px solid var(--bernard-accent, #1c5e53); border-radius: 6px; padding: 1.4rem 1.6rem; margin: 1.25rem 0; }
.course-locked > p:first-child { font-weight: 600; margin-top: 0; }
.course-attachments-title { font-size: 1rem; margin: 1.5rem 0 0.4rem; }
.course-attachments { margin: 0; padding-left: 1.2rem; }
.course-lesson-nav { display: flex; justify-content: space-between; gap: 1rem; margin-top: 2.5rem; font-size: 0.9rem; }
.course-lesson-nav a { color: inherit; }
.course-empty { opacity: 0.7; }
.bnd-transcript { margin-top: 1rem; border: 1px solid rgba(0,0,0,0.1); border-radius: 6px; overflow: hidden; min-width: 0; max-width: 100%; }
.bnd-transcript-toggle { display: block; width: 100%; min-height: 44px; box-sizing: border-box; text-align: left; padding: 0.6rem 1rem; background: rgba(0,0,0,0.03); border: 0; cursor: pointer; font: inherit; font-weight: 600; color: inherit; }
.bnd-transcript-body { padding: 0.75rem 1rem 1rem; }
.bnd-transcript-collapsed .bnd-transcript-body { display: none; }
.bnd-transcript-filter { display: block; width: 100%; max-width: 100%; box-sizing: border-box; padding: 0.5rem 0.75rem; margin-bottom: 0.5rem; border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; font: inherit; }
.bnd-transcript-list { list-style: none; margin: 0; padding: 0; max-height: 22rem; overflow-y: auto; }
.bnd-transcript-row { display: flex; gap: 0.6rem; padding: 0.45rem 0.3rem; border-radius: 4px; cursor: pointer; min-height: 44px; align-items: flex-start; }
.bnd-transcript-row[hidden] { display: none; }
.bnd-transcript-row:hover, .bnd-transcript-row:focus-visible { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 8%, transparent); }
.bnd-transcript-row-active { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 14%, transparent); }
.bnd-transcript-stamp { flex: 0 0 auto; font-size: 0.8rem; opacity: 0.55; font-variant-numeric: tabular-nums; }
.bnd-transcript-text { flex: 1 1 auto; min-width: 0; }
.bnd-transcript-word-active { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 35%, transparent); border-radius: 2px; }
.bnd-transcript-empty { opacity: 0.7; margin: 0.5rem 0; }
.bnd-player-root.is-portrait .bnd-player { max-height: min(80vh, 42rem); width: auto; margin-inline: auto; }
/* Compact chrome, keyed to the PLAYER’s own width, not the viewport - a
   small player in a big window (side panel, scaled preview, half-screen
   film) otherwise wears full-size chrome that swallows the picture
   (Spencer’s report, 2026-08-14). container-type: inline-size makes the
   wrap a query container; browsers without container queries simply keep
   the full-size chrome, which is the safe direction. The 480px viewport
   media query below stays untouched - it handles row ORDER on narrow
   phones; these tiers handle SCALE. NOTE: placed AFTER every base
   .bnd-preview-thumb/.bnd-player rule - two emitted-CSS tests locate those
   base rules by FIRST string index, so a compact override of the same
   selector earlier in the sheet would steal their anchor. */
.bnd-player { container-type: inline-size; }
@container (max-width: 560px) {
  .bnd-player-btn { min-width: 34px; min-height: 34px; padding: 0 0.2rem; }
  .bnd-player-btn svg { width: 16px; height: 16px; }
  .bnd-player-bar { gap: 0.15rem; padding: 0.3rem 0.45rem; }
  .bnd-player-time { font-size: 0.7rem; min-width: 4.6rem; }
  .bnd-player-speed { font-size: 0.7rem; }
  .bnd-player-scrub { min-width: 4rem; height: 34px; }
  .bnd-player-scrub input[type="range"] { height: 34px; }
  .bnd-player-note { font-size: 0.72rem; padding: 0.25rem 0.7rem; }
  .bnd-preview-thumb { bottom: 2.6rem; }
}
/* Tighter still: keep what watching needs (play, scrub, captions,
   fullscreen); skip-10s, speed and picture-in-picture are luxuries a
   postage-stamp player cannot afford. */
@container (max-width: 400px) {
  .bnd-player-back, .bnd-player-fwd, .bnd-player-pip, .bnd-player-speed { display: none; }
}
@container (max-width: 270px) {
  .bnd-player-time, .bnd-player-captions, .bnd-player-caption-lang { display: none; }
}
@media (min-width: 960px) {
  .bnd-player-root:has(.bnd-transcript) { display: grid; grid-template-columns: minmax(0, 1fr) 22rem; gap: 1rem; align-items: start; }
  /* A portrait video WITHOUT a transcript (every Reel - audio, and so
     captions/the transcript, is stripped) must NOT reserve this two-column
     grid: with nothing to put in column 2 it left a permanent empty 22rem
     gutter and centered the video only within column 1. Scoping .is-portrait
     to :has(.bnd-transcript) means the two cases can’t both apply - a
     portrait video WITH a transcript still gets the side-by-side grid,
     unchanged; a portrait video alone falls through to the .bnd-player-root
     default of display:block (line above the media query), where the
     max-height + margin-inline:auto rule centers it as a single narrower
     column. If a browser doesn’t support :has() at all, this whole rule is
     simply dropped (same fallback behavior the pre-existing
     :has(.bnd-transcript) rule above already relies on) - the safe
     direction, since the unconditional max-height bound isn’t gated by
     :has() and still caps the video’s height regardless. */
  .bnd-player-root.is-portrait:has(.bnd-transcript) { display: grid; grid-template-columns: minmax(0, 1fr) 22rem; gap: 1rem; align-items: start; }
  .bnd-player-root .bnd-transcript { grid-column: 2; grid-row: 1 / span 2; margin-top: 0; }
}
@media (max-width: 959px) {
  .bnd-player-root { display: block; }
}
@media (max-width: 480px) {
  /* 390px control-bar reflow: play/scrub/time/fullscreen must stay on row
     1 - the essentials for watching and going fullscreen - while back/fwd/
     speed/captions/PiP may wrap to row 2. The invisible .bnd-player-linebreak
     item (flex-basis:100%) forces the row break deterministically instead of
     relying on organic wrap math at this exact width. */
  .bnd-player-play, .bnd-player-scrub, .bnd-player-time, .bnd-player-full { order: 1; }
  .bnd-player-linebreak { order: 2; flex-basis: 100%; width: 0; height: 0; margin: 0; padding: 0; }
  .bnd-player-back, .bnd-player-fwd, .bnd-player-speed, .bnd-player-captions, .bnd-player-caption-lang, .bnd-player-pip { order: 3; }
  /* Item 2 (player followups batch): the site-wide "made with bernard"
     badge (src/lib/sites/branding.ts) is position:fixed 14px from the true
     viewport bottom-right, independent of scroll/page content. A portrait
     player fills up to 80vh (.is-portrait above), so on a narrow phone
     viewport its own bottom control-bar row (row 2, wrapped just above)
     can land in that same 14px corner, covering speed/PiP/chapters. Prefer
     moving the BADGE up over shrinking/removing player chrome: the badge is
     injected as an inline style, so an id-selector override needs
     !important to win the cascade; scoping it inside courses.css (loaded
     only on course pages) keeps every other page’s badge position
     untouched. */
  #bernard-badge { bottom: 4.5rem !important; }
}

/* PRD 121 §4a - discussion under a lesson (shares the room’s post classes). */
.course-discussion { margin-top: 2.5rem; border-top: 1px solid #e5e5e5; padding-top: 1.5rem; }
.course-discussion h2 { font-size: 1.1rem; }
.course-discussion textarea { width: 100%; box-sizing: border-box; font: inherit; padding: 10px; border: 1px solid #ccc; border-radius: 8px; }
.course-discussion button { font: inherit; margin-top: 8px; padding: 8px 18px; border-radius: 8px; border: none; background: #1c5e53; color: #fff; cursor: pointer; }
.bnd-post { border-top: 1px solid #e5e5e5; padding: 12px 0; }
.bnd-post-owner strong { color: #1c5e53; }
.bnd-post-when { margin-left: 8px; font-size: .8rem; opacity: .6; }
[data-discussion-error] { color: #b3261e; font-size: .9rem; }

/* PRD 158 - course page hero, derived module headings, transcript search and
   the look-inside strip. Tenant-neutral: everything derives from the site’s
   own --bernard-accent / currentColor, same as the rest of this sheet. */
.course-hero { margin: 0 0 1.5rem; }
.course-hero-media .course-video { margin: 0 0 1rem; }
.course-hero-media .course-cover { margin: 0 0 1rem; }
.course-hero-action h1 { margin-top: 0; }
.course-strapline { font-size: 1.05rem; opacity: 0.85; margin: 0.35rem 0 0.75rem; }
@media (min-width: 920px) {
  /* Room for two columns - only when the page actually has the hero, so
     lesson pages keep their reading-width column. No :has() support simply
     keeps the narrow single column, which still renders correctly. */
  .course-main:has(.course-hero) { max-width: 64rem; }
  .course-hero { display: grid; grid-template-columns: minmax(0, 3fr) minmax(16rem, 2fr); gap: 2rem; align-items: start; }
  .course-hero-no-media { display: block; }
  .course-hero-media .course-video, .course-hero-media .course-cover { margin: 0; }
}
.course-description { max-width: 70ch; }
/* Modules overview grid - one numbered card per owner section, between the
   hero and the description. The big ordinal sits in the accent at low
   opacity: present, not wallpaper. */
.course-modules { margin: 2rem 0; }
.course-modules h2 { margin: 0 0 0.75rem; }
.course-modules-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 660px) {
  .course-modules-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1000px) {
  .course-modules-grid { grid-template-columns: repeat(3, 1fr); }
}
.course-module-card { border: 1px solid rgba(0,0,0,0.08); border-radius: 6px; padding: 1rem 1.1rem; }
.course-module-n { display: block; font-size: 1.9rem; font-weight: 700; line-height: 1; margin-bottom: 0.4rem; font-variant-numeric: tabular-nums; color: color-mix(in srgb, var(--bernard-accent, #1c5e53) 40%, transparent); }
.course-module-title { margin: 0 0 0.25rem; font-size: 1rem; }
.course-module-meta { margin: 0; font-size: 0.85rem; opacity: 0.65; }
/* Collapsible sections in lesson notes, built by the renderer from the
   [[accordion: Title]] marker pair (PRD 96 #346). Deliberately plain: the
   site’s own type and colour lead, this only supplies the clickable row and
   the indent. Native "details", so it collapses even before a site picks up
   this sheet. */
.course-accordion { margin: 1.5rem 0; border-top: 1px solid rgba(0,0,0,0.12); border-bottom: 1px solid rgba(0,0,0,0.12); }
.course-accordion + .course-accordion { margin-top: -1.5rem; border-top: none; }
.course-accordion > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 0.6rem; min-height: 48px; font-weight: 600; }
.course-accordion > summary::-webkit-details-marker { display: none; }
.course-accordion > summary::before { content: "+"; width: 20px; font-weight: 400; opacity: 0.55; }
.course-accordion[open] > summary::before { content: "\2212"; }
.course-accordion > summary:focus-visible { outline: 2px solid var(--bernard-accent, #1c5e53); outline-offset: 2px; }
.course-accordion-body { padding: 0.25rem 0 1.25rem; }
.course-accordion-body > :first-child { margin-top: 0; }
.course-accordion-body > :last-child { margin-bottom: 0; }
/* Transcript search - the howto site’s "Read the transcript" drawer shape
   (disclosure + find-a-line input + timestamped rows), in this site’s own
   fonts and accent. */
.course-search { margin: 2.5rem 0; border-top: 1px solid rgba(0,0,0,0.12); border-bottom: 1px solid rgba(0,0,0,0.12); }
.course-search > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 0.6rem; min-height: 56px; font-weight: 600; color: var(--bernard-accent, #1c5e53); }
.course-search > summary::-webkit-details-marker { display: none; }
.course-search > summary::before { content: "+"; width: 20px; font-weight: 400; opacity: 0.55; }
.course-search[open] > summary::before { content: "\2212"; }
.course-search > summary:focus-visible { outline: 2px solid var(--bernard-accent, #1c5e53); outline-offset: 2px; }
.course-search-body { padding: 0.25rem 0 1.5rem; }
.course-search-input { display: block; width: 100%; max-width: 28rem; box-sizing: border-box; min-height: 48px; padding: 0.6rem 0.9rem; font: inherit; border: 1px solid rgba(0,0,0,0.2); border-radius: 6px; background: transparent; color: inherit; }
.course-search-input:focus-visible { outline: 2px solid var(--bernard-accent, #1c5e53); outline-offset: 2px; }
.course-search-results { list-style: none; margin: 0.75rem 0 0; padding: 0; max-height: 27rem; overflow-y: auto; }
.course-search-hit a { display: flex; gap: 0.9rem; align-items: flex-start; padding: 0.5rem 0.6rem; border-radius: 6px; color: inherit; text-decoration: none; min-height: 44px; }
.course-search-hit a:hover, .course-search-hit a:focus-visible { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 8%, transparent); }
.course-search-hit a:focus-visible { outline: 2px solid var(--bernard-accent, #1c5e53); outline-offset: 2px; }
.course-search-stamp { flex: none; font-size: 0.8rem; font-variant-numeric: tabular-nums; color: var(--bernard-accent, #1c5e53); padding-top: 0.2rem; }
.course-search-hit-title { display: block; font-weight: 600; margin-bottom: 0.15rem; }
.course-search-hit-snippet { display: block; font-size: 0.9rem; opacity: 0.8; }
.course-search-hit-snippet mark { background: color-mix(in srgb, var(--bernard-accent, #1c5e53) 25%, transparent); color: inherit; border-radius: 2px; padding: 0 0.1em; }
.course-search-empty { opacity: 0.7; margin: 0.5rem 0; padding: 0.5rem 0.6rem; }
.course-search-note { font-size: 0.85rem; opacity: 0.6; margin: 0.5rem 0 0; }
[data-course-strip][hidden] { display: none; }
.course-strip { margin: 2.5rem 0; }
.course-strip h2 { margin: 0 0 0.75rem; }
.course-strip-track { display: flex; gap: 0.75rem; overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 0.5rem; -webkit-overflow-scrolling: touch; }
.course-strip-item { flex: 0 0 auto; width: 11rem; scroll-snap-align: start; color: inherit; text-decoration: none; }
.course-strip-item img { width: 100%; aspect-ratio: 16/9; object-fit: cover; border-radius: 6px; background: #10201c; display: block; }
.course-strip-caption { display: block; margin-top: 0.35rem; font-size: 0.8rem; opacity: 0.75; }
.course-strip-item:focus-visible { outline: 2px solid var(--bernard-accent, #1c5e53); outline-offset: 2px; }
@media (prefers-reduced-motion: no-preference) {
  .course-strip-track { scroll-behavior: smooth; }
}

/* C-21 structural guard (PRD 151). Everything above is deliberately plain and
   loses politely to the site’s own styles - that is the house rule and it
   stays. This block is the exception, and it is narrow on purpose.

   The problem it solves: our furniture is injected into the OWNER’S cascade,
   and their stylesheet is full of perfectly ordinary rules with more
   specificity than our single classes. On babyem-courses (owner crop,
   2026-08-15/16) ".course-lesson .course-content img { width: 100% }" plus a
   scoped "{ width: auto }" was enough to letterbox the player small in the
   top-left, blow a 4rem chapter thumbnail to roughly five times its size, and
   wrap chapter titles over four lines straight through the transcript rows
   beside them. Nothing was wrong with her CSS; the furniture simply had no
   floor under it.

   Why not @layer: unlayered author CSS beats EVERY layer, and a customer
   stylesheet is unlayered - putting ours in a layer would make us lose by
   construction, which is the opposite of the fix. Why not Shadow DOM: the
   runtime builds and mutates this DOM in place (and half of it is
   server-rendered markup the runtime only hydrates), so a shadow root is a
   rewrite of the runtime AND the projected HTML - and it would cut off
   the per-site courses-theme.css, which is a supported per-site feature we are not
   willing to break.

   So: STRUCTURE ONLY. Every declaration below is width/height/aspect/
   position/overflow/flex/box-sizing - the properties that decide whether the
   page can be read at all. Colour, type, radius, spacing, background and
   motion are NOT here, so courses-theme.css keeps theming the surface exactly
   as before. The runtime sets the same structural values inline as it builds
   (lockStructure in courses-runtime.ts), which beats any non-!important site
   rule; this block is what covers the static, server-rendered markup and the
   case where a site forces something with !important of its own. An owner who
   really means it can still win here with their own !important in
   courses-theme.css, which loads after this sheet. */
.bnd-player-root > * { min-width: 0 !important; max-width: 100% !important; }
.course-video { position: relative !important; overflow: hidden !important; box-sizing: border-box !important; }
.course-video > video, .course-video > iframe { position: absolute !important; top: 0 !important; right: 0 !important; bottom: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; min-width: 0 !important; min-height: 0 !important; max-width: none !important; max-height: none !important; margin: 0 !important; border: 0 !important; box-sizing: border-box !important; }
.course-video > video { object-fit: contain !important; }
/* Fullscreen has to be able to drop the stage’s aspect box - and the runtime
   now sets that box inline, so the release needs !important to reach it. Two
   rules, never one selector list: an unknown pseudo invalidates the whole
   list, and each browser knows only one of these spellings. */
.bnd-player:fullscreen { aspect-ratio: auto !important; width: 100% !important; height: 100% !important; max-height: none !important; }
.bnd-player:-webkit-full-screen { aspect-ratio: auto !important; width: 100% !important; height: 100% !important; max-height: none !important; }
.bnd-player > .bnd-player-bar { position: absolute !important; left: 0 !important; right: 0 !important; bottom: 0 !important; display: flex !important; flex-wrap: wrap !important; align-items: center !important; box-sizing: border-box !important; max-width: 100% !important; }
/* display is left alone on the buttons: the container-query tiers hide
   back/fwd/PiP/speed on a small player and an !important display here would
   nail them back on. */
.bnd-player > .bnd-player-bar > .bnd-player-btn { width: auto !important; flex: 0 0 auto !important; box-sizing: border-box !important; }
.bnd-player > .bnd-player-bar > .bnd-player-scrub { position: relative !important; display: flex !important; align-items: center !important; flex: 1 1 8rem !important; box-sizing: border-box !important; }
.bnd-player .bnd-player-note { position: absolute !important; max-width: calc(100% - 1.6rem) !important; box-sizing: border-box !important; }
.bnd-player .bnd-preview-thumb { position: absolute !important; max-width: calc(100% - 8px) !important; max-height: 160px !important; box-sizing: border-box !important; }
.bnd-player .bnd-chapter-tick { position: absolute !important; }
.bnd-player .bnd-upnext { position: absolute !important; top: 0 !important; right: 0 !important; bottom: 0 !important; left: 0 !important; box-sizing: border-box !important; }
.bnd-player-root .bnd-chapter-list { display: flex !important; flex-direction: column !important; list-style: none !important; padding-left: 0 !important; box-sizing: border-box !important; }
.bnd-player-root .bnd-chapter-list > li { list-style: none !important; margin-left: 0 !important; max-width: 100% !important; min-width: 0 !important; }
.bnd-player-root .bnd-chapter-item { display: flex !important; align-items: center !important; width: 100% !important; max-width: 100% !important; min-width: 0 !important; overflow: hidden !important; box-sizing: border-box !important; }
/* The thumbnail that went to 5x. Any img inside a chapter row, not just the
   one wearing our class, because the site’s rule matched on the img element
   itself. */
.bnd-player-root .bnd-chapter-item img { width: 4rem !important; max-width: 4rem !important; min-width: 0 !important; height: auto !important; aspect-ratio: 16 / 9 !important; object-fit: cover !important; flex: none !important; }
.bnd-player-root .bnd-chapter-item-title { flex: 1 1 auto !important; min-width: 0 !important; }
.bnd-player-root .bnd-transcript { min-width: 0 !important; max-width: 100% !important; overflow: hidden !important; box-sizing: border-box !important; }
.bnd-transcript .bnd-transcript-body { max-width: 100% !important; box-sizing: border-box !important; }
/* display on the body and on a row is toggled (collapse, filter), so it is
   forced here and immediately released for the toggled state - never left to
   a plain rule the site can outrank in either direction. */
.bnd-transcript.bnd-transcript-collapsed .bnd-transcript-body { display: none !important; }
.bnd-transcript .bnd-transcript-list { list-style: none !important; padding-left: 0 !important; max-width: 100% !important; max-height: 22rem !important; overflow-y: auto !important; box-sizing: border-box !important; }
.bnd-transcript .bnd-transcript-row { display: flex !important; align-items: flex-start !important; max-width: 100% !important; min-width: 0 !important; box-sizing: border-box !important; list-style: none !important; }
.bnd-transcript .bnd-transcript-row[hidden] { display: none !important; }
.bnd-transcript .bnd-transcript-stamp { flex: 0 0 auto !important; }
.bnd-transcript .bnd-transcript-text { flex: 1 1 auto !important; min-width: 0 !important; }
.bnd-transcript .bnd-transcript-filter { width: 100% !important; max-width: 100% !important; box-sizing: border-box !important; }
/* The look-inside strip is the same class of furniture on the course page. */
.course-strip-track > .course-strip-item { flex: 0 0 auto !important; width: 11rem !important; max-width: 11rem !important; box-sizing: border-box !important; }
.course-strip-item > img { width: 100% !important; max-width: 100% !important; height: auto !important; aspect-ratio: 16 / 9 !important; object-fit: cover !important; }
