/*
 * Course rich-text content stylesheet — the SINGLE SOURCE OF TRUTH for how
 * authored section content renders on courses/take, skills/take AND in the
 * Nova admin preview (backend-school proxies this file live from
 * /css/rich-text.css). Edit this file only; do not copy it elsewhere.
 *
 * Served verbatim from /public (no PostCSS/Tailwind pass), so keep it plain
 * CSS: no CSS-Module syntax (:global/:local/composes) and no Tailwind @apply.
 */

/* Rich Text Content Styling - Display rendered Quill content */

/* Preserve empty line spacing from Enter key presses */
.richTextContent p:empty,
.richTextContent p:has(> br:only-child) {
  min-height: 1.5em !important;
  display: block !important;
}

.richTextContent h1 + p:empty,
.richTextContent h1 + p:has(> br:only-child),
.richTextContent h2 + p:empty,
.richTextContent h2 + p:has(> br:only-child),
.richTextContent h3 + p:empty,
.richTextContent h3 + p:has(> br:only-child) {
  min-height: 1em !important;
  display: block !important;
}

@font-face {
  font-family: 'SuisseIntl-Medium';
  src: url('/fonts/SuisseIntl-Medium.otf') format('opentype');
  font-weight: 500;
  font-style: normal;
}

/* 1. Text Color Override - All text should be #475467 */
.richTextContent {
  color: #475467 !important;
  font-family: 'SuisseIntl-Medium', sans-serif !important;
  font-size: 1.3rem !important;
  max-width: 100% !important;
  overflow-wrap: break-word !important;
  word-break: normal !important;
}

.richTextContent p,
.richTextContent span:not(.katex, .katex *),
.richTextContent div:not(.katex, .katex *),
.richTextContent h1,
.richTextContent h2,
.richTextContent h3 {
  font-family: 'SuisseIntl-Medium', sans-serif !important;
}

.richTextContent p {
  color: #475467 !important;
  font-size: 1.3rem !important;
  overflow-wrap: break-word !important;
  word-break: normal !important;
}

.richTextContent li {
  overflow-wrap: break-word !important;
  word-break: normal !important;
}

.richTextContent h1,
.richTextContent h2,
.richTextContent h3 {
  color: #3b2f86 !important;
}

.richTextContent h4,
.richTextContent h5,
.richTextContent h6 {
  color: #475467 !important;
}

/* h2/h3 step up like .ql-size-large (the purple "large text" look):
   bigger and bolder than the 1.3rem body text */
.richTextContent h2 {
  font-size: 2rem !important;
  font-weight: 800 !important;
}

.richTextContent h3 {
  font-size: 1.7rem !important;
  font-weight: 800 !important;
  text-decoration: underline !important;
}

/* Large and Huge Text Size - Purple Color */
.richTextContent .ql-size-large,
.richTextContent .ql-size-huge {
  color: #3b2f86 !important;
}

.richTextContent .ql-size-large *,
.richTextContent .ql-size-huge * {
  color: #3b2f86 !important;
}

.richTextContent .ql-size-large,
.richTextContent .ql-size-huge {
  color: #3b2f86 !important;
}

.richTextContent .ql-size-large *,
.richTextContent .ql-size-huge * {
  color: #3b2f86 !important;
}

.richTextContent strong,
.richTextContent b {
  color: #475467 !important;
}

.richTextContent em,
.richTextContent i {
  color: #475467 !important;
}

.richTextContent a {
  color: #475467 !important;
}

.richTextContent blockquote {
  color: #475467 !important;
  border-left: 4px solid #3b2f86 !important;
  padding-left: 16px !important;
  margin: 12px 0 !important;
  font-style: italic !important;
  background-color: #f8f7ff !important;
  padding: 12px 16px !important;
  border-radius: 0 8px 8px 0 !important;
}

.richTextContent * {
  color: #475467 !important;
}

/* 2. Embedded Video Styling - responsive 16:9, capped by WIDTH not height.
 *
 * The previous rule capped `max-height` at 350px while `width` stayed a definite
 * 100%. `aspect-ratio` can only derive the AUTO axis from the definite one, so
 * the height clamp could not pull the width back: the box rendered at roughly
 * 3:1 and the YouTube player letterboxed a 16:9 picture inside it — measured at
 * 622px of actual video inside a 1098px column, with 238px of black each side.
 *
 * Capping the WIDTH instead keeps the ratio intact at every size: the player
 * fills the column up to --rt-media-max and the height always follows from 16:9.
 * Below that cap nothing changes (a 380px column rendered 380x214 before and
 * after), so this only affects columns wider than ~622px.
 */
.richTextContent {
  --rt-media-max: 860px;
}

.richTextContent iframe {
  width: 100% !important;
  max-width: var(--rt-media-max) !important;
  height: auto !important;
  aspect-ratio: 16 / 9 !important;
  display: block;
  margin: 24px auto 0 !important;
  border: 0;
  border-radius: 12px 12px 0 0;
  background-color: #000;
}

.richTextContent video {
  width: 100% !important;
  max-width: var(--rt-media-max) !important;
  height: auto !important;
  aspect-ratio: 16 / 9 !important;
  display: block;
  margin: 24px auto 0 !important;
  border-radius: 12px 12px 0 0;
  background-color: #000;
}

/* 2b. The video's caption line, attached to the player as one unit.
 *
 * The generator emits `<iframe …></iframe><p><em>Video: title (channel, m:ss)</em></p>`
 * (prompts/generate-course-v6.md -> MEDIA ENRICHMENT; media-fulfil.mjs videoEmbed),
 * so the caption is always the iframe's immediate next sibling. Rendered with the
 * default paragraph style it was body-sized italic floating under a black band.
 * `:has(> em:first-child)` keeps this scoped to that generated shape — an ordinary
 * paragraph that merely happens to follow a video is left alone.
 *
 * The label stays BELOW the player: moving it above needs new markup and is
 * deliberately out of scope here.
 */
.richTextContent iframe + p:has(> em:first-child),
.richTextContent video + p:has(> em:first-child) {
  box-sizing: border-box;
  max-width: var(--rt-media-max);
  margin: 0 auto 24px !important;
  padding: 12px 18px !important;
  background-color: #f8fafc;
  border: 1px solid #e6edf6;
  border-top: 0;
  border-radius: 0 0 12px 12px;
  font-size: 1.05rem !important;
  font-weight: 600 !important;
  font-style: normal !important;
  line-height: 1.45 !important;
}

/* The caption text ships wrapped in <em>; the bar supplies the emphasis now. */
.richTextContent iframe + p:has(> em:first-child) em,
.richTextContent video + p:has(> em:first-child) em {
  font-style: normal !important;
}

/* 3. Unordered List Styling - Custom bullet icon */
/* Items carry no margin: the line pitch (section 6) already holds the space
   between them, so the next item starts exactly one line further down, as the
   next line of a paragraph does. The card's inset is 23px top and bottom so
   that a list of one-line items stays exactly as tall as it is with a 16px
   inset and a 14px margin on every item. */
.richTextContent ul {
  background-color: #e3f2fd !important;
  padding: 23px 16px 23px 40px !important;
  border-radius: 12px !important;
  margin: 36px 0 !important;
  padding-left: 24px !important;
}

.richTextContent ul > li {
  color: #475467 !important;
  margin: 0 !important;
  list-style: none !important;
  position: relative !important;
  padding-left: 28px !important;
  font-size: 1.3rem !important;
}

/* The marker sits on the item's FIRST line (half a line box down), not at the
   middle of the item: with no extra space between items it is the marker that
   shows where a wrapped item starts. On a one-line item the two are the same.
   `--rt-body-line-height` is a number, hence the multiplication by an em. */
.richTextContent ul > li::before {
  content: '' !important;
  position: absolute !important;
  left: 0 !important;
  top: calc(var(--rt-body-line-height) * 0.5em) !important;
  transform: translateY(-50%) !important;
  width: 24px !important;
  height: 24px !important;
  background-image: url('/images/list-bullet-icon.png') !important;
  background-size: contain !important;
  background-repeat: no-repeat !important;
  background-position: center !important;
}

/* Hide Quill's default .ql-ui bullet element */
.richTextContent li[data-list='bullet'] > .ql-ui {
  display: none !important;
}

/* 3b. Ordered List Styling - Use same image bullet */
.richTextContent ol {
  background-color: #e3f2fd !important;
  padding: 23px 16px 23px 40px !important;
  border-radius: 12px !important;
  margin: 36px 0 !important;
  padding-left: 24px !important;
}

/* globals.css pads every `ol > li` by 0.25rem above and below. Left in place it
   would set the items of an <ol> 8px further apart than those of a <ul>. */
.richTextContent ol > li {
  color: #475467 !important;
  margin: 0 !important;
  list-style: none !important;
  position: relative !important;
  padding: 0 0 0 28px !important;
  font-size: 1.3rem !important;
}

.richTextContent ol > li::before {
  content: '' !important;
  position: absolute !important;
  left: 0 !important;
  top: calc(var(--rt-body-line-height) * 0.5em) !important;
  transform: translateY(-50%) !important;
  width: 24px !important;
  height: 24px !important;
  background-image: url('/images/list-bullet-icon.png') !important;
  background-size: contain !important;
  background-repeat: no-repeat !important;
  background-position: center !important;
}

/* Hide Quill's default .ql-ui ordered list element */
.richTextContent li[data-list='ordered'] > .ql-ui {
  display: none !important;
}

/* 4. Label line before any list (ul or ol) - joins the light blue card, bold
   only, slightly larger than body text. Applies to a plain sentence (p) AND to
   headings (h2/h3) sitting right above a list — as a label they trade the
   heading card/red bar/underline for the light-blue bar. RichText.tsx removes
   the single blank line authors often leave between the label and the list
   (CSS can't bridge it: :has() can't nest), so direct adjacency is all this
   rule needs. A blank paragraph itself (p:is(:empty, :has(> br:only-child)))
   is never a label, and neither is a paragraph that IS a title — a Quill
   "huge"/"large" span (section titles such as "Key Terms and Chapter Wrap-Up")
   keeps its heading card and the list below keeps its own card. Top corners
   match the card radius; the list below drops its own top corners so
   label + list read as one card. */
.richTextContent :is(p, h2, h3):not(:empty, :has(> br:only-child), :has(> .ql-size-huge), :has(> .ql-size-large)):has(+ :is(ul, ol)) {
  background-color: #e3f2fd !important;
  color: #475467 !important;
  font-weight: bold !important;
  font-size: 1.4rem !important;
  text-decoration: none !important;
  border: none !important;
  box-shadow: none !important;
  padding: 12px 16px !important;
  border-radius: 12px 12px 0 0 !important;
  margin-bottom: 0 !important;
  margin-top: 12px !important;
}

/* A heading acting as a list label drops the heading card's red left bar */
.richTextContent :is(h2, h3):has(+ :is(ul, ol))::before {
  content: none !important;
}

/* Override any inline styles */
.richTextContent [style*='color'] {
  color: #475467 !important;
}

/* Make sure videos and iframes respond properly */
.richTextContent div[data-type='video'],
.richTextContent .ql-video-container {
  width: 100% !important;
  height: auto !important;
}

/* Ensure text in blockquotes also follows the color scheme */
.richTextContent blockquote * {
  color: #475467 !important;
}

/* 5. Table Embed Container */
.richTextContent .ql-table-embed {
  display: block !important;
  margin: 24px 0 !important;
}

/* 5b. Table Styling - Professional Design */
.richTextContent table,
.richTextContent .ql-table-embed table {
  width: 100% !important;
  border-collapse: collapse !important;
  margin: 24px 0 !important;
  border: none !important;
  background-color: #ffffff !important;
  border-radius: 8px !important;
  overflow: hidden !important;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08) !important;
}

.richTextContent table thead {
  background-color: #e3f2fd !important;
}

.richTextContent table thead tr {
  background-color: #e3f2fd !important;
}

.richTextContent table th {
  background-color: #e3f2fd !important;
  color: #475467 !important;
  font-weight: 700 !important;
  padding: 18px 20px !important;
  text-align: left !important;
  border: none !important;
  border-bottom: 1px solid #e8e8e8 !important;
  font-size: 1.3rem !important;
  border-radius: 6px !important;
}

.richTextContent table td {
  color: #475467 !important;
  padding: 18px 20px !important;
  text-align: left !important;
  border: none !important;
  border-bottom: 1px solid #f0f0f0 !important;
  font-size: 1.3rem !important;
}

/* Style first tbody row as header when no thead exists */
.richTextContent table:not(:has(thead)) tbody tr:first-child {
  background-color: #e3f2fd !important;
}

.richTextContent table:not(:has(thead)) tbody tr:first-child td {
  background-color: #e3f2fd !important;
  color: #475467 !important;
  font-weight: 700 !important;
  border-bottom: 1px solid #e8e8e8 !important;
}

.richTextContent table tbody tr {
  background-color: #ffffff !important;
}

.richTextContent table tbody tr:hover {
  background-color: #fafafa !important;
}

.richTextContent table tbody tr:last-child td {
  border-bottom: none !important;
}

.richTextContent table tr:first-child th {
  border-top: none !important;
}

/* ==== FINAL OVERRIDE: Ensure image bullets are used ==== */
/* This must come last to ensure it overrides all Quill's default bullets */

/* Ensure Quill's .ql-ui elements are completely hidden */
.richTextContent li[data-list='bullet'] > .ql-ui,
.richTextContent li[data-list='ordered'] > .ql-ui {
  display: none !important;
}

/* Ensure image bullets are applied with proper sizing at all levels */
.richTextContent li[data-list='bullet'],
.richTextContent li[data-list='ordered'] {
  list-style: none !important;
  position: relative !important;
  padding-left: 28px !important;
  font-size: 1.3rem !important;
}

.richTextContent li[data-list='bullet']::before,
.richTextContent li[data-list='ordered']::before {
  content: '' !important;
  position: absolute !important;
  left: 0 !important;
  top: calc(var(--rt-body-line-height) * 0.5em) !important;
  transform: translateY(-50%) !important;
  width: 24px !important;
  height: 24px !important;
  background-image: url('/images/list-bullet-icon.png') !important;
  background-size: contain !important;
  background-repeat: no-repeat !important;
  background-position: center !important;
}

/* ==== NORMAL SIZE CLASS: font-size 1.3rem for ul, li, table, tr, td ==== */
.richTextContent.normal ul,
.richTextContent.normal ol,
.richTextContent.normal ul > li,
.richTextContent.normal ol > li,
.richTextContent.normal table,
.richTextContent.normal table tr,
.richTextContent.normal table td,
.richTextContent.normal table th,
.richTextContent.normal li[data-list='bullet'],
.richTextContent.normal li[data-list='ordered'] {
  font-size: 1.3rem !important;
}

/* ==== 6. VERTICAL RHYTHM: one line pitch for body text, margins around headings ==== */
/* Quill emits margin-less <p>/<h1-h6>. Headings get their breathing room from
   the margins below; body text gets its rhythm from line-height alone. Must
   stay in sync with the identical section in RichEditor/QuillEditor.module.css
   (WYSIWYG parity). See docs/course-skill-section-content-css.md */

/* Body text keeps ONE distance from each line to the next: inside a paragraph,
   from one paragraph to the next, inside a list item and from one item to the
   next. The line-height IS that distance, so paragraphs and list items carry
   no margin of their own (section 3). `li` needs the value spelled out: with
   none it takes whatever leaks in from outside this file, 2 inside a <ul> (the
   MUI wrapper in RichText.tsx) but 1.3 inside an <ol> (the global `ol` rule in
   globals.css).
   2.6735 is 55.6px for 1.3rem text: the step from one one-line "Learning
   Objectives" bullet to the next, which is what prose is measured against. It
   is a plain number on purpose: smaller or larger text inside a paragraph then
   scales its own line box and does not push its line away from the others. */
.richTextContent {
  --rt-body-line-height: 2.6735;
}

.richTextContent p {
  margin: 0 !important;
  line-height: var(--rt-body-line-height) !important;
}

.richTextContent li {
  line-height: var(--rt-body-line-height) !important;
}

/* A label line (rule 4, same selector) is a title bar, not prose: it keeps a
   compact line. */
.richTextContent p:not(:empty, :has(> br:only-child), :has(> .ql-size-huge), :has(> .ql-size-large)):has(+ :is(ul, ol)) {
  line-height: 1.7 !important;
}

.richTextContent h1 {
  margin: 32px 0 16px 0 !important;
  line-height: 1.3 !important;
}

.richTextContent h2 {
  margin: 28px 0 14px 0 !important;
  line-height: 1.3 !important;
}

.richTextContent h3 {
  margin: 24px 0 12px 0 !important;
  line-height: 1.4 !important;
}

.richTextContent h4,
.richTextContent h5,
.richTextContent h6 {
  margin: 20px 0 10px 0 !important;
  line-height: 1.4 !important;
}

/* No stray gap at the very top/bottom of a section */
.richTextContent > :first-child {
  margin-top: 0 !important;
}

.richTextContent > :last-child {
  margin-bottom: 0 !important;
}

/* Re-assert AFTER the generic p/heading margins: the bold label line stays
   attached to the list card below it (rule 4 above) */
.richTextContent :is(p, h2, h3):not(:empty, :has(> br:only-child), :has(> .ql-size-huge), :has(> .ql-size-large)):has(+ :is(ul, ol)) {
  margin-bottom: 0 !important;
  margin-top: 12px !important;
}

/* A list that directly follows its label line hugs it (no 36px gap, square
   top corners) */
.richTextContent
  :is(p, h2, h3):not(:empty, :has(> br:only-child), :has(> .ql-size-huge), :has(> .ql-size-large)):has(+ :is(ul, ol))
  + :is(ul, ol) {
  margin-top: 0 !important;
  border-top-left-radius: 0 !important;
  border-top-right-radius: 0 !important;
}

/* ==== 7. FIGURES ==== */
/* Every course figure ships as a pre-composited "figure card" PNG: a white card
 * on a light ground with a navy header band carrying the figure's TITLE
 * (course-generator src/lib/figure-card.mjs). The title therefore already lives
 * inside the image and must NOT be repeated in markup — no caption line is
 * emitted for these and none is added here.
 *
 * What was missing was a boundary. The card's own ground (#eef2f7) sits inside
 * the white lesson panel with no edge of its own, so the figure bled into the
 * page and read as loose artwork rather than as one titled object. A radius,
 * a hairline border and rhythm that clearly exceeds the 16px paragraph gap fix
 * that without touching the asset.
 *
 * Scoped to `p > img:only-child` — the generator wraps every figure in its own
 * paragraph (quill-whitespace.mjs wrapBareImages), so an image sitting inline
 * inside a sentence is never matched. */
.richTextContent p > img:only-child,
.richTextContent > img {
  box-sizing: border-box;
  display: block;
  margin: 36px auto !important;
  border: 1px solid #e3e8f0;
  border-radius: 14px;
  box-shadow: 0 1px 3px rgba(16, 24, 40, 0.06);
}

/* ==== 8. PRACTICE ACTIVITY ("Try it yourself" + "Show answer") ==== */
/* The generator emits the pair as
 *     <p><strong>Try it yourself.</strong> …</p>
 *     <details><summary>Show answer</summary><p><strong>Answer.</strong> …</p></details>
 * (prompts/generate-course-v6.md -> "The practice block"). Neither element had a
 * single rule in this stylesheet, so an interactive activity rendered as ordinary
 * prose with a bare native disclosure triangle jammed against the next paragraph.
 *
 * The two elements are joined into ONE card: the prompt is its head, the
 * disclosure its body. No pseudo-element label is added — the bold
 * "Try it yourself." lead-in already names the block, and inventing a second
 * label would duplicate it.
 *
 * Teal is deliberate: it is the one accent not already in use here — lists are
 * #e3f2fd blue, heading cards carry the coral bar from globals.css, blockquotes
 * are #f8f7ff purple. `.richTextContent * { color: … !important }` (rule 1)
 * overrides any text colour set here, so the hierarchy is built from background
 * and border only.
 *
 * `<details>` needs no scripting: the native open/close behaviour is untouched. */
.richTextContent p:not(:empty, :has(> br:only-child)):has(+ details) {
  background-color: #eafaf6;
  border: 1px solid #bfe8de;
  border-left: 5px solid #0e9384;
  border-bottom: 0;
  border-radius: 12px 12px 0 0;
  padding: 18px 20px 14px !important;
  margin: 32px 0 0 !important;
}

.richTextContent details {
  background-color: #eafaf6;
  border: 1px solid #bfe8de;
  border-left: 5px solid #0e9384;
  border-radius: 12px;
  padding: 4px 20px 16px;
  margin: 32px 0;
}

/* A disclosure that follows its prompt squares the join so the pair reads as
   one card; a stray <details> with no prompt keeps its own full rounding. */
.richTextContent p:not(:empty, :has(> br:only-child)):has(+ details) + details {
  border-top: 0;
  border-radius: 0 0 12px 12px;
  margin-top: 0;
}

.richTextContent summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 0;
  font-weight: 700 !important;
  font-size: 1.15rem !important;
  cursor: pointer;
  list-style: none;
  user-select: none;
}

/* Replace the native marker with one that reads at this type size. Both the
   standards selector and the WebKit pseudo-element are needed for full
   browser coverage. */
.richTextContent summary::-webkit-details-marker {
  display: none;
}

.richTextContent summary::marker {
  content: '';
}

.richTextContent summary::before {
  content: '▸';
  display: inline-block;
  font-size: 0.95em;
  line-height: 1;
  transition: transform 0.15s ease;
}

.richTextContent details[open] summary::before {
  transform: rotate(90deg);
}

/* The revealed answer sits clear of the summary and leaves no trailing gap
   inside the card. */
.richTextContent details > *:not(summary) {
  margin-left: 0;
}

.richTextContent details > *:last-child {
  margin-bottom: 0 !important;
}

/* Structured math owns its fonts, spacing and bidirectional layout. The prose
   font rule above must never override KaTeX's individual symbol fonts. */
.richTextContent [data-math-status='rendered'] {
  direction: ltr;
  unicode-bidi: isolate;
  white-space: normal;
  overflow-wrap: normal;
  word-break: normal;
  text-indent: 0;
}

.richTextContent [data-math='display'][data-math-status='rendered'] {
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  padding: 0.25em 0;
  margin: 1em 0;
}

.richTextContent [data-math='display'] .katex-display {
  margin: 0;
  width: max-content;
  min-width: 100%;
}

.richTextContent [data-math='display']:focus-visible {
  outline: 2px solid #3b2f86;
  outline-offset: 2px;
}

.richTextContent [data-math-status='error'] {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  border-bottom: 1px dotted currentColor;
}

/* ==== 8. HEADING CARDS (moved here from globals.css) ==== */
/* h2/h3 and the Quill "large"/"huge" spans render as a soft card with a coral
   bar on the left. This used to live in globals.css under `.rich-text-content`,
   which only the dashboard loads; it belongs in this file so every surface that
   renders course content (dashboard, Nova preview) gets the same headings. The
   `.ql-editor` copies stay in globals.css for the editor. */
.richTextContent h2,
.richTextContent h3,
.richTextContent :is(span, strong, em, u).ql-size-huge,
.richTextContent :is(span, strong, em, u).ql-size-large {
  display: block;
  position: relative;
  padding: 1rem 1.5rem 1rem 1.5rem;
  margin-top: 1.5rem;
  margin-bottom: 1rem;
  font-weight: 500;
  background-color: #f8fafc;
  color: #2d3a6e;
  border-radius: 0.95rem;
  line-height: 1.4;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
  border: 1px solid #f1f5f9;
  border-left: none;
  overflow: hidden;
}

.richTextContent h2::before,
.richTextContent h3::before,
.richTextContent :is(span, strong, em, u).ql-size-huge::before,
.richTextContent :is(span, strong, em, u).ql-size-large::before {
  font-family: 'SuisseIntl-Medium' !important;
  content: '';
  position: absolute;
  left: 0;
  color: #3b2f86 !important;
  top: 0;
  bottom: 0;
  width: 5px;
  background: linear-gradient(to bottom, #ee5b5b 0%, #ee5b5b 50%, #ee5b5b 50%, #ee5b5b 100%);
  border-radius: 0.95rem 0 0 0.95rem;
}

/* ==== 9. AUTHORED SECTION PANELS ==== */
/* Generated courses wrap "Learning Objectives" / "End-of-chapter recap" in an
   inline-styled panel (coral left border, light background, its own padding)
   that carries its own <h2> and list:
     <div class="learning-objectives" style="border-left:6px solid …; background:…">
       <h2 style="margin:0; color:…">Learning Objectives</h2>
       <p><br></p>
       <h3>By the end of this chapter …</h3>
       <ul>…</ul>
     </div>
   The heading card (rule 8) and the list card (rule 3) already draw a bar and a
   background each, so the panel doubled both and its inline colour turned the
   heading grey. A panel that STARTS with a heading is therefore rendered as a
   transparent grouping: its children get exactly the top-level treatment.
   Panels without a leading heading (figure headers, image panels) are untouched. */
.richTextContent div[style*='border-left']:has(> :is(h1, h2, h3):first-child),
.richTextContent div.learning-objectives,
.richTextContent div.end-of-chapter-recap {
  background: transparent !important;
  border: 0 !important;
  border-radius: 0 !important;
  padding: 0 !important;
  margin: 0 !important;
  box-shadow: none !important;
}

/* Reading surfaces drop blank spacer paragraphs at the top level (RichText's
   `compact`); inside these panels they would keep a 35px hole between the
   heading card and the list, so they are hidden here too. */
.richTextContent div[style*='border-left']:has(> :is(h1, h2, h3):first-child) > p:is(:empty, :has(> br:only-child)),
.richTextContent div.learning-objectives > p:is(:empty, :has(> br:only-child)),
.richTextContent div.end-of-chapter-recap > p:is(:empty, :has(> br:only-child)) {
  display: none !important;
}

/* The leading heading keeps the heading colour even though the author gave it
   an inline colour (rule 1's `[style*='color']` normalisation would grey it). */
.richTextContent div[style*='border-left']:has(> :is(h1, h2, h3):first-child) > :is(h1, h2, h3):first-child[style],
.richTextContent div.learning-objectives > :is(h1, h2, h3):first-child[style],
.richTextContent div.end-of-chapter-recap > :is(h1, h2, h3):first-child[style] {
  color: #3b2f86 !important;
}
