/* MiM GP Part 2 — module styles
   Shared component layer is in mim-gp-shared.css (imported second).
   Only Part 2-specific styles live here.
   ─────────────────────────────────────────────────────────────────── */
@import url('./mim-design-system.css');
@import url('../../../../_components/mim-gp-shared.css');


/* ══ LEGACY TOKEN ALIASES ════════════════════════════════════════════════
   Part 2 was authored with --s* spacing and --purple-* colour names.
   These map them to the shared design-system tokens so no HTML needs
   changing when the design system is updated.
   ──────────────────────────────────────────────────────────────────────── */
:root {
  --s2:  var(--sp-2);   /* 8px  */
  --s3:  var(--sp-3);   /* 12px */
  --s4:  var(--sp-4);   /* 16px */
  --s5:  var(--sp-5);   /* 24px */
  --s6:  var(--sp-6);   /* 32px */
  --s8:  var(--sp-8);   /* 64px */
  --s10: var(--sp-10);  /* 128px */
  --s12: 96px;          /* bottom breathing room on content screens */

  --purple-light: rgba(183, 163, 252, 0.10);
  --purple-mid:   rgba(183, 163, 252, 0.30);
  --purple-dark:  var(--mim-purple-aa-dark);   /* #5D3CC9 — AA-accessible on white */
  --text-muted:   var(--fg-muted);             /* #4A4A4A */
  --text-faint:   var(--fg-subtle);            /* #7A7A7A */
  --border-mid:   rgba(0, 0, 0, 0.25);
  --black:        var(--mim-black);
}


/* ══ CONTENT LAYOUT ═══════════════════════════════════════════════════ */

.content-wrap { flex: 1; max-width: 720px; width: 100%; margin: 0 auto; padding: var(--s10) var(--s6) var(--s12); }
.content-wrap--wide { max-width: 900px; }


/* ══ FULL-BLEED CINEMATIC HERO (screen 1) ════════════════════════════ */

.screen--hero {
  position: relative;
  height: calc(100vh - var(--header-h) - var(--footer-h));
  overflow: hidden; background: var(--mim-black); color: var(--mim-white);
}
.screen--hero.active { display: block; animation: none; }
.hero__media { position: absolute; inset: 0; }
.hero__media img { width: 100%; height: 100%; object-fit: cover; object-position: center 30%; filter: saturate(0.9) contrast(1.02) brightness(0.88); }
.hero__scrim { position: absolute; inset: 0; background: linear-gradient(0deg, rgba(0,0,0,0.92) 0%, rgba(0,0,0,0.72) 30%, rgba(0,0,0,0.30) 62%, rgba(0,0,0,0.12) 100%); }
.hero__tex { position: absolute; inset: 0; background: var(--tex-photocopy-black) center/cover; opacity: 0.45; mix-blend-mode: multiply; }
/* 2. Hero clipping on short viewports. The copy was bottom-anchored with
   `align-items: flex-end`; when it is taller than the hero box the overflow goes off
   the TOP, under the header, and flexbox start-edge overflow is NOT scrollable (so
   the `overflow:auto` below could never reach it). An auto top margin gives the same
   bottom-anchored look when there is room, but collapses to 0 on overflow so the
   content starts at the top and can be scrolled. */
.hero__inner { position: absolute; inset: 0; z-index: 2; display: flex; align-items: flex-start; overflow: auto; }
.hero__inner-wrap { width: 100%; max-width: 1240px; margin: auto auto 0; padding: 56px 56px 52px; }
.hero__copy { display: flex; flex-direction: column; align-items: flex-start; gap: 20px; max-width: 760px; }
.hx-kicker { font-family: var(--font-primary); font-weight: var(--weight-semibold); font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--mim-purple); display: inline-block; }
.hx-title { font-family: var(--font-feature); font-weight: var(--weight-regular); font-size: clamp(44px, 5.6vw, 84px); line-height: 1.0; letter-spacing: -0.028em; color: #fff; margin: 0; text-wrap: balance; }
.hx-sub { font-family: var(--font-primary); font-weight: var(--weight-light); font-size: clamp(18px, 1.9vw, 23px); line-height: 1.32; color: rgba(255,255,255,0.86); letter-spacing: -0.01em; margin: 0; max-width: 44ch; }
.hx-bodies { display: flex; flex-direction: column; gap: 11px; }
.hx-body { font-family: var(--font-primary); font-weight: var(--weight-light); font-size: 15px; line-height: 1.6; color: rgba(255,255,255,0.62); margin: 0; max-width: 52ch; }
@media (prefers-reduced-motion: no-preference) {
  .screen--hero [data-rise] { opacity: 0; transform: translateY(16px); animation: hxRise 0.66s var(--ease-out) forwards; animation-delay: var(--d, 0ms); }
  .screen--hero .hero__media img { animation: hxImg 1.2s var(--ease-out) both; }
}
@keyframes hxRise { to { opacity: 1; transform: none; } }
@keyframes hxImg { from { transform: scale(1.06); opacity: 0.4; } to { transform: scale(1); opacity: 1; } }
@media (max-width: 600px) { .hero__inner-wrap { padding: 60px 22px 36px; } .hx-title { font-size: clamp(36px, 12vw, 54px); } }


/* ══ BANNER SCREEN (full-bleed image) ════════════════════════════════ */

.banner-screen { flex: 1; min-height: 0; width: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; background: var(--mim-black); }
.banner-screen__img { width: 100%; height: 100%; object-fit: contain; object-position: center; display: block; max-height: calc(100vh - var(--header-h) - var(--footer-h)); }


/* ══ BASE ELEMENT TYPOGRAPHY (Part 2 uses raw elements, not .body/.title classes) ══ */

h2 { font-family: var(--font-feature); font-size: clamp(22px,3vw,36px); font-weight: var(--weight-regular); color: var(--mim-black); line-height: var(--lh-snug); letter-spacing: var(--tr-display); margin-bottom: var(--s6); }
h3 { font-family: var(--font-primary); font-size: var(--fs-h4); font-weight: var(--weight-semibold); color: var(--mim-black); margin-bottom: var(--s4); letter-spacing: 0; line-height: var(--lh-snug); }
p { font-family: var(--font-primary); font-weight: var(--weight-light); font-size: var(--fs-body); line-height: var(--lh-relaxed); color: var(--fg); }
p + p { margin-top: var(--s4); }
.eyebrow { font-family: var(--font-primary); font-size: var(--fs-eyebrow); font-weight: var(--weight-semibold); letter-spacing: var(--tr-eyebrow); text-transform: uppercase; color: var(--mim-purple-aa-dark, #5D3CC9); margin-bottom: var(--s3); }
.divider { border: none; border-top: 1px solid var(--border); margin: var(--s6) 0; }
.pull-quote { font-family: var(--font-feature); font-style: italic; font-size: clamp(17px,2.2vw,22px); color: var(--mim-black); line-height: var(--lh-normal); border-left: 2px solid var(--mim-purple); padding: var(--s5) var(--s6); margin: var(--s8) 0; background: var(--purple-light); border-radius: 0 var(--radius-md) var(--radius-md) 0; }
.pull-quote cite { display: block; font-size: var(--fs-small); font-style: normal; color: var(--fg-muted); margin-top: var(--s3); }

a { color: var(--purple-dark); text-decoration: underline; text-underline-offset: 3px; }
a:hover { color: var(--mim-purple); }


/* ══ CARD ════════════════════════════════════════════════════════════ */

.card { background: var(--mim-white); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--s5) var(--s6); transition: transform var(--dur-base) var(--ease-standard), box-shadow var(--dur-base) var(--ease-standard); }
.card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.card + .card { margin-top: var(--s4); }
.card--purple { background: var(--purple-light); border-color: var(--purple-mid); }
.completion-note { display: flex; align-items: flex-start; gap: 14px; margin: var(--s8) auto 0; max-width: var(--measure); background: #B7A3FC; border: 1px solid #B7A3FC; border-radius: var(--radius-md); padding: 20px 22px; text-align: left; }
.completion-note__check { flex-shrink: 0; width: 28px; height: 28px; border-radius: 50%; background: #1A1A1A; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; }
.completion-note__text { font-family: var(--font-primary); font-weight: 600; font-size: 16px; line-height: 1.5; color: #1A1A1A; margin: 0; }
body.night-mode .completion-note { background: #B7A3FC; }
body.night-mode .completion-note__text { color: #1A1A1A; }


/* ══ INFOGRAPHIC ════════════════════════════════════════════════════ */

.infographic-wrap { margin: var(--s8) 0; text-align: center; }
.infographic-wrap img { max-width: 100%; height: auto; border-radius: var(--radius-md); cursor: zoom-in; transition: opacity var(--dur-fast) var(--ease-standard); }
.infographic-wrap img:hover { opacity: 0.88; }
.infographic-wrap::after { content: 'Click to zoom'; display: block; font-size: 12px; color: var(--fg-subtle); text-align: center; margin-top: 6px; }


/* ══ FIND OUT MORE (expandable boxes) ════════════════════════════════ */

.find-out-more { border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; margin: var(--s5) 0; }
.find-out-more__trigger { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: var(--s3); padding: var(--s4) var(--s5); background: var(--bg-muted); border: none; cursor: pointer; font-family: var(--font-primary); font-size: var(--fs-small); font-weight: var(--weight-semibold); color: var(--fg-muted); text-align: left; transition: background var(--dur-base) var(--ease-standard); }
.find-out-more__trigger:hover { background: var(--purple-light); color: var(--purple-dark); }
.find-out-more__trigger .fom-icon { flex-shrink: 0; width: 18px; height: 18px; color: var(--mim-purple); transition: transform var(--dur-base) var(--ease-standard); }
.find-out-more.open .find-out-more__trigger .fom-icon { transform: rotate(180deg); }
.find-out-more__panel { max-height: 0; overflow: hidden; transition: max-height 450ms var(--ease-standard); }
.find-out-more.open .find-out-more__panel { max-height: 1200px; }
.find-out-more__inner { padding: var(--s5); border-top: 1px solid var(--border); font-size: var(--fs-small); font-weight: var(--weight-light); color: var(--fg-muted); line-height: var(--lh-relaxed); }
.find-out-more__inner p { font-size: var(--fs-small); }
.find-out-more__inner p + p { margin-top: var(--s3); }


/* ══ REFLECTION BOX (Part 2 dark-bg variant — different from shared .reflect) ══ */

.reflection-box { margin: var(--s8) 0; background: var(--mim-black) var(--tex-photocopy-black) center / cover; border-radius: var(--radius-lg); padding: var(--s5) var(--s6); color: rgba(255,255,255,0.9); }
.reflection-toggle { display: inline-flex; align-items: center; gap: var(--s2); background: var(--mim-white); border: none; border-radius: var(--radius-pill); padding: 10px 20px; font-family: var(--font-primary); font-size: 12px; font-weight: var(--weight-semibold); letter-spacing: 0.1em; text-transform: uppercase; color: var(--mim-black); cursor: pointer; transition: opacity var(--dur-base) var(--ease-standard); }
.reflection-toggle:hover { opacity: 0.88; }
.reflection-panel { display: none; margin-top: var(--s4); padding-top: var(--s4); border-top: 1px solid rgba(255,255,255,0.12); }
.reflection-panel.open { display: block; }
.reflection-panel textarea { width: 100%; min-height: 100px; border: 1px solid rgba(255,255,255,0.2); border-radius: var(--radius-md); padding: var(--s3) var(--s4); font-family: var(--font-primary); font-weight: var(--weight-light); font-size: var(--fs-small); color: var(--fg); background: var(--mim-white); resize: vertical; transition: border-color var(--dur-base) var(--ease-standard); line-height: var(--lh-relaxed); }
.reflection-panel textarea:focus { outline: 2px solid var(--mim-purple); outline-offset: 2px; border-color: transparent; }
.reflection-panel__actions { display: flex; align-items: center; justify-content: space-between; margin-top: var(--s3); gap: var(--s3); }
.reflection-panel__save { display: inline-flex; align-items: center; gap: var(--s2); background: var(--mim-purple); border: none; border-radius: var(--radius-pill); padding: 8px 18px; font-family: var(--font-primary); font-size: 12px; font-weight: var(--weight-semibold); letter-spacing: 0.1em; text-transform: uppercase; color: var(--mim-black); cursor: pointer; transition: filter var(--dur-base) var(--ease-standard); }
.reflection-panel__save:hover { filter: brightness(0.92); }
.reflection-panel__saved { font-size: 12px; color: var(--mim-purple); display: none; }
.reflection-panel__saved.visible { display: inline; }


/* ══ REFLECTIONS VIEWER MODAL (Part 2 variant) ═══════════════════════ */

.reflections-viewer { position: fixed; inset: 0; z-index: 300; background: rgba(0,0,0,0.5); display: none; align-items: flex-end; justify-content: center; }
.reflections-viewer.open { display: flex; }
.reflections-viewer__panel { background: var(--mim-white); border-radius: var(--radius-lg) var(--radius-lg) 0 0; width: 100%; max-width: 720px; max-height: 70vh; overflow-y: auto; padding: var(--s6); }
.reflections-viewer__title { font-size: var(--fs-body-lg); font-weight: var(--weight-semibold); color: var(--mim-black); margin-bottom: var(--s5); display: flex; align-items: center; justify-content: space-between; }
.reflections-viewer__close { background: none; border: none; cursor: pointer; color: var(--fg-subtle); font-size: 22px; line-height: 1; }
.reflection-entry { border-left: 2px solid var(--purple-mid); padding: var(--s4) var(--s5); margin-bottom: var(--s5); background: var(--bg-muted); border-radius: 0 var(--radius-md) var(--radius-md) 0; }
.reflection-entry__q { font-size: 13px; font-style: italic; color: var(--fg-muted); margin-bottom: var(--s2); }
.reflection-entry__a { font-size: var(--fs-small); color: var(--fg); line-height: var(--lh-normal); }
.reflection-entry__delete { background: none; border: none; font-size: 11px; color: #cc4444; cursor: pointer; margin-top: var(--s2); padding: 0; text-decoration: underline; }


/* ══ REVEAL LIST ═════════════════════════════════════════════════════ */

.reveal-list { list-style: none; display: flex; flex-direction: column; gap: var(--s3); margin: var(--s6) 0; }
.reveal-item { display: flex; align-items: flex-start; gap: var(--s4); padding: var(--s4) var(--s5); background: var(--bg-muted); border: 1px solid var(--border); border-radius: var(--radius-md); opacity: 0; transform: translateX(-12px); transition: opacity 350ms var(--ease-standard), transform 350ms var(--ease-standard); pointer-events: none; }
.reveal-item.visible { opacity: 1; transform: translateX(0); pointer-events: auto; }
.reveal-item__text { font-size: var(--fs-body); font-weight: var(--weight-light); color: var(--fg); line-height: var(--lh-relaxed); }
.reveal-item__text strong { font-weight: var(--weight-semibold); color: var(--mim-black); }

/* Click-to-reveal CARDS: the box is present from the start (black photocopy
   texture, white text); a "Click to reveal" hint sits on top until the user
   clicks, then the text shows in place — no appearing over empty whitespace. */
.reveal-list--clickeach .reveal-item {
  opacity: 1; transform: none; pointer-events: auto; cursor: pointer;
  position: relative; min-height: 60px;
  background: #000 url('./assets/mim/texture-photocopy-black.png') center / cover no-repeat;
  border-color: #000; color: #fff;
  transition: box-shadow 180ms var(--ease-standard);
}
.reveal-list--clickeach .reveal-item:hover,
.reveal-list--clickeach .reveal-item:focus-visible { box-shadow: inset 0 0 0 2px var(--mim-purple); outline: none; }
.reveal-list--clickeach .reveal-item__text { color: #fff; visibility: hidden; }
.reveal-list--clickeach .reveal-item__text em,
.reveal-list--clickeach .reveal-item__text strong { color: #fff; }
.reveal-list--clickeach .reveal-item.revealed .reveal-item__text { visibility: visible; }
.reveal-list--clickeach .reveal-item__hint {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: var(--font-primary); font-size: 11px; font-weight: var(--weight-semibold);
  letter-spacing: 0.12em; text-transform: uppercase; color: rgba(255,255,255,0.55);
  pointer-events: none;
}
.reveal-list--clickeach .reveal-item.revealed .reveal-item__hint { display: none; }

/* Slide 6 — purple eyebrow/text reads poorly on white; force black. */
#screen-5 .eyebrow { color: var(--mim-black); }

/* Textured flipcards (slides 9 & 19): black photocopy texture on the front,
   purple photocopy texture on the reverse with all reverse text in black. */
.flipcard-grid--male .flipcard__front,
.flipcard-grid--textured .flipcard__front {
  background: #000 url('./assets/mim/texture-photocopy-black.png') center / cover no-repeat;
  border-color: #000;
}
.flipcard-grid--male .flipcard__back,
.flipcard-grid--textured .flipcard__back {
  background: var(--mim-purple) url('./assets/mim/MIM_Photocopy-Texture-Purple.jpg') center / cover no-repeat;
  border-color: var(--mim-purple);
  color: #000;
}
.flipcard-grid--male .flipcard__back .part-label,
.flipcard-grid--male .flipcard__back p,
.flipcard-grid--textured .flipcard__back p,
.flipcard-grid--textured .flipcard__back em { color: #000; }
/* Slide 9 fronts carry numbers/hints (not the white MALE letters) — force white
   so they read against the dark texture. */
.flipcard-grid--textured .flipcard__front span { color: #fff !important; }

/* Bricks (slide 14): taller cards so the longer two-sided text fits without clipping;
   centre the lone 5th card instead of leaving it left-aligned. */
.flipcard-grid--bricks .flipcard { min-height: 340px; }
.flipcard-grid--bricks .flipcard__back { padding: var(--s4); }
.flipcard-grid--bricks .flipcard__back p { font-size: 14px; line-height: 1.45; }
.flipcard-grid--bricks .flipcard--center { grid-column: 1 / -1; justify-self: center; width: 100%; max-width: calc((100% - var(--sp-4)) / 2); }
@media (max-width: 600px) { .flipcard-grid--bricks .flipcard--center { max-width: 100%; } }

/* Purple quotation mark in the top-right of every lived-experience quote screen. */
.image-quote::before {
  content: ""; position: absolute; z-index: 3; pointer-events: none;
  top: clamp(18px, 3vw, 32px); right: clamp(20px, 3.5vw, 38px);
  width: clamp(56px, 8vw, 104px); aspect-ratio: 272 / 150;
  background: url('./assets/images/MIM_Quotation-Marks.png') center / contain no-repeat;
}

/* ══ COMBINED QUOTE CARD — portrait + quote composed as one graphic ══ */
.quote-card { display: flex; align-items: stretch; margin: var(--s8) 0; background: #000 url('./assets/mim/texture-photocopy-black.png') center / cover no-repeat; border-radius: var(--radius-lg); overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,0.18); }
.quote-card__photo { width: 38%; max-width: 300px; min-height: 260px; object-fit: cover; object-position: center top; flex-shrink: 0; display: block; }
.quote-card__body { position: relative; flex: 1; padding: clamp(28px, 4vw, 52px); display: flex; flex-direction: column; justify-content: center; }
.quote-card__text { font-family: var(--font-feature); font-style: italic; font-size: calc(clamp(18px, 2.2vw, 26px) * var(--fs-scale)); line-height: 1.32; color: #fff; margin: 0; }
.quote-card__cite { display: block; font-family: var(--font-primary); font-style: normal; font-weight: var(--weight-semibold); font-size: var(--fs-small); letter-spacing: 0.04em; color: var(--mim-purple); margin-top: var(--s4); }
@media (max-width: 640px) {
  .quote-card { flex-direction: column; }
  .quote-card__photo { width: 100%; max-width: none; height: 240px; min-height: 0; }
}

@keyframes pulse-btn {
  0%, 100% { box-shadow: 0 0 0 0 rgba(183,163,252,0.7); }
  50%       { box-shadow: 0 0 0 10px rgba(183,163,252,0); }
}


/* ══ VIDEO SCREEN (Part 2 layout) ════════════════════════════════════ */

.video-screen { flex: 1; display: flex; flex-direction: column; background: var(--bg); }
.video-screen__intro { padding: var(--s8) var(--s6) var(--s5); max-width: 720px; margin: 0 auto; width: 100%; }
.video-player-wrap { position: relative; aspect-ratio: 16/9; background: var(--mim-black); border-radius: var(--radius-lg); overflow: hidden; }
.video-player-wrap iframe, .video-player-wrap video { position: absolute; inset: 0; width: 100%; height: 100%; border: none; }
.video-gate { position: absolute; inset: 0; z-index: 5; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s4); background: rgba(0,0,0,0.8); opacity: 0; pointer-events: none; transition: opacity 500ms var(--ease-standard); }
.video-gate.open { opacity: 1; pointer-events: auto; }
.video-gate__label { font-family: var(--font-feature); font-size: 20px; font-weight: var(--weight-regular); color: var(--mim-white); text-align: center; max-width: 400px; line-height: var(--lh-snug); }


/* ══ TOOLKIT HEADER ═════════════════════════════════════════════════ */

.toolkit-header { background: var(--mim-black) var(--tex-photocopy-black) center / cover; padding: var(--s10) var(--s6); display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; min-height: 220px; }
.toolkit-header__title { font-family: var(--font-feature); font-size: clamp(44px,7vw,72px); font-weight: var(--weight-regular); color: var(--mim-white); line-height: var(--lh-tight); letter-spacing: var(--tr-display); }


/* ══ QUIZ ════════════════════════════════════════════════════════════ */

.quiz-question { font-family: var(--font-feature); font-size: calc(clamp(17px,2.2vw,22px) * var(--fs-scale)); font-weight: var(--weight-regular); color: var(--mim-black); line-height: var(--lh-normal); margin-bottom: var(--s6); }
.quiz-options { display: flex; flex-direction: column; gap: var(--s3); margin-bottom: var(--s5); }
.quiz-option { display: flex; align-items: flex-start; gap: var(--s3); padding: var(--s4) var(--s5); background: var(--bg-muted); border: 2px solid var(--border); border-radius: var(--radius-md); cursor: pointer; font-family: var(--font-primary); font-weight: var(--weight-light); font-size: var(--fs-body); color: var(--fg); text-align: left; line-height: var(--lh-normal); transition: border-color var(--dur-base) var(--ease-standard), background var(--dur-base) var(--ease-standard); -webkit-tap-highlight-color: transparent; }
.quiz-option:hover:not(:disabled) { border-color: var(--mim-purple); background: var(--purple-light); }
.quiz-option:disabled { cursor: default; }
/* Quiz answer states — purple + tick, matching Part 1's .kc-option and Part 3.
   Was green/red here, which made "correct" mean two different colours inside
   the same course. Unified 2026-07-17. */
.quiz-option.correct   { border: 2.5px solid var(--mim-purple-aa); background: rgba(183,163,252,0.10); }
.quiz-option.correct::after  { content: ''; margin-left: auto; flex-shrink: 0; width: 22px; height: 22px; background: url('./assets/mim/mark-tick.png') center / contain no-repeat; }
.quiz-option.incorrect { border: 2.5px solid var(--fg); background: rgba(0,0,0,0.05); color: var(--fg-muted); text-decoration: line-through; }
.quiz-option.incorrect::after { content: '\00D7'; margin-left: auto; padding-left: var(--s3); font-size: 24px; line-height: 1; font-weight: 400; color: var(--fg); text-decoration: none; flex-shrink: 0; }
/* The right answer, revealed after a wrong choice. Thinner stroke than
   .correct, so "this was the answer" reads differently from "you got it
   right" — the same distinction Part 1 draws between chosen- and
   revealed-correct. */
.quiz-option.revealed-correct { border: 1.5px solid var(--mim-purple-aa); background: rgba(183,163,252,0.10); }
.quiz-option.revealed-correct::after { content: ''; margin-left: auto; flex-shrink: 0; width: 22px; height: 22px; background: url('./assets/mim/mark-tick.png') center / contain no-repeat; }
.quiz-feedback { padding: var(--s5); border-radius: var(--radius-md); font-size: var(--fs-small); font-weight: var(--weight-light); line-height: var(--lh-relaxed); margin-top: var(--s4); border-left: 2px solid transparent; }
.quiz-feedback--correct   { background: #f0faf5; border-left-color: #22a05a; color: #1a5232; }
.quiz-feedback--incorrect { background: #fdf2f2; border-left-color: #cc4444; color: #7a2a2a; }


/* ══ SUMMARY SCREEN ═════════════════════════════════════════════════ */

.summary-screen__logo { height: 56px; width: auto; margin-bottom: var(--s6); }
.summary-screen__title { font-family: var(--font-feature); font-size: clamp(26px,3vw,32px); font-weight: var(--weight-regular); color: var(--mim-black); margin-bottom: var(--s4); letter-spacing: var(--tr-display); }
.summary-tick { flex-shrink: 0; width: 40px; height: 40px; object-fit: contain; margin-top: 2px; }
.summary-items { list-style: none; display: flex; flex-direction: column; gap: var(--s3); margin-top: var(--s4); }
.summary-card { display: flex; align-items: flex-start; gap: var(--s4); }


/* ══ VIEW REFLECTIONS BUTTON ════════════════════════════════════════ */

.view-reflections-btn { display: inline-flex; align-items: center; gap: var(--s2); background: none; border: 1px solid rgba(0,0,0,0.2); border-radius: var(--radius-pill); padding: 8px 16px; font-family: var(--font-primary); font-size: 12px; font-weight: var(--weight-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--fg-muted); cursor: pointer; margin-top: var(--s4); transition: border-color var(--dur-base) var(--ease-standard), color var(--dur-base) var(--ease-standard); }
body.night-mode .view-reflections-btn { border-color: rgba(255,255,255,0.2); color: rgba(255,255,255,0.6); }
.view-reflections-btn:hover { border-color: var(--mim-purple); color: var(--mim-purple); }


/* ══ MISC SCREEN RULES ══════════════════════════════════════════════ */

.screen[data-type="quote"] .banner-screen { background: var(--mim-black) var(--tex-photocopy-black) center / cover; }
.content-wrap img:not([data-nozoom]) { cursor: zoom-in; }


/* ══ TUTORIAL (nav tutorial screen) ════════════════════════════════ */

.nav-tutorial { flex: 1; max-width: 720px; width: 100%; margin: 0 auto; padding: var(--s10) var(--s6) var(--s12); }
.tutorial-step { display: flex; align-items: flex-start; gap: var(--s5); padding: var(--s5) var(--s6); background: var(--bg-muted); border: 2px solid var(--border); border-radius: var(--radius-lg); margin-bottom: var(--s4); cursor: pointer; transition: border-color var(--dur-base) var(--ease-standard), background var(--dur-base) var(--ease-standard); user-select: none; width: 100%; text-align: left; }
.tutorial-step:hover { border-color: var(--purple-mid); background: var(--purple-light); }
.tutorial-step__icon { flex-shrink: 0; width: 48px; height: 48px; border-radius: var(--radius-md); background: var(--purple-light); border: 1px solid var(--purple-mid); display: flex; align-items: center; justify-content: center; }
.tutorial-step__icon svg { width: 22px; height: 22px; color: var(--purple-dark); }
.tutorial-step__body { flex: 1; }
.tutorial-step__body h3 { font-size: var(--fs-body); margin-bottom: var(--s2); }
.tutorial-step__body p  { font-size: var(--fs-small); font-weight: var(--weight-light); color: var(--fg-muted); }


/* ══ FAQ ════════════════════════════════════════════════════════════ */

.faq-screen { flex: 1; max-width: 720px; width: 100%; margin: 0 auto; padding: var(--s10) var(--s6) var(--s12); }
.faq-list { list-style: none; display: flex; flex-direction: column; gap: var(--s3); margin-top: var(--s6); }
.faq-item { border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; }
.faq-trigger { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: var(--s3); padding: var(--s4) var(--s5); background: var(--bg-muted); border: none; cursor: pointer; font-family: var(--font-primary); font-size: var(--fs-small); font-weight: var(--weight-semibold); color: var(--fg); text-align: left; transition: background var(--dur-base) var(--ease-standard), color var(--dur-base) var(--ease-standard); }
.faq-trigger:hover { background: var(--purple-light); color: var(--purple-dark); }
.faq-icon { flex-shrink: 0; width: 18px; height: 18px; color: var(--mim-purple); transition: transform var(--dur-base) var(--ease-standard); }
.faq-item.open .faq-icon { transform: rotate(180deg); }
.faq-body { max-height: 0; overflow: hidden; transition: max-height 400ms var(--ease-standard); }
.faq-item.open .faq-body { max-height: 800px; }
.faq-body__inner { padding: var(--s4) var(--s5); border-top: 1px solid var(--border); font-size: var(--fs-small); font-weight: var(--weight-light); color: var(--fg-muted); line-height: var(--lh-relaxed); }
.faq-body__inner p + p { margin-top: var(--s3); }
.faq-title-wrap { position: relative; display: flex; align-items: flex-start; gap: var(--s4); }
.faq-title-wrap h2 { flex: 1; }

/* Accordion (FAQ) — aligned to GP Module 1 */
.accordion { border-top: 1px solid var(--border-strong); border-bottom: 1px solid var(--border-strong); max-width: var(--measure); }
.accordion__item { border-bottom: 1px solid var(--border); }
.accordion__item:last-child { border-bottom: none; }
.accordion__summary { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 22px 4px; width: 100%; background: none; border: none; cursor: pointer; text-align: left; }
.accordion__title { font-family: var(--font-primary); font-weight: var(--weight-semibold); font-size: calc((17px) * var(--fs-scale)); line-height: 1.3; color: var(--fg); }
.accordion__toggle { font-family: var(--font-primary); font-size: 22px; color: var(--fg-muted); line-height: 1; transition: transform 220ms var(--ease-standard); flex-shrink: 0; }
.accordion__item.open .accordion__toggle { transform: rotate(45deg); }
.accordion__body { display: none; padding: 0 4px 24px; }
.accordion__item.open .accordion__body { display: block; }
.accordion__body .body { font-family: var(--font-primary); font-weight: var(--weight-light); font-size: calc((16px) * var(--fs-scale)); line-height: 1.6; max-width: 62ch; }
body.night-mode .accordion { border-color: rgba(255,255,255,0.2); }
body.night-mode .accordion__item { border-color: rgba(255,255,255,0.12); }
body.night-mode .accordion__title { color: rgba(255,255,255,0.92); }
body.night-mode .accordion__toggle { color: rgba(255,255,255,0.7); }
.questionmark-accent { flex-shrink: 0; width: 70px; height: auto; opacity: 0.45; margin-top: 4px; pointer-events: none; }


/* ══ TRANSCRIPT ═════════════════════════════════════════════════════ */

.transcript-toggle { background: none; border: 1px solid var(--border-mid); border-radius: var(--radius-pill); padding: 7px 16px; font-family: var(--font-primary); font-size: 12px; font-weight: var(--weight-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--fg-muted); cursor: pointer; margin-top: var(--s3); transition: border-color var(--dur-base) var(--ease-standard), color var(--dur-base) var(--ease-standard); }
.transcript-toggle:hover { border-color: var(--mim-purple); color: var(--purple-dark); }
.transcript-panel { display: none; padding: 0 0 var(--s6); }
.transcript-panel.open { display: block; }
.transcript-panel__inner { background: var(--bg-muted); border-radius: var(--radius-md); padding: var(--s5) var(--s6); font-size: var(--fs-small); font-weight: var(--weight-light); color: var(--fg-muted); line-height: var(--lh-relaxed); }
.transcript-panel__inner p + p { margin-top: var(--s4); }


/* ══ REFLECTION QUESTION (standalone italic prompt) ═════════════════ */

.reflection-question { font-family: var(--font-feature); font-size: var(--fs-body-lg); font-weight: var(--weight-regular); font-style: italic; color: rgba(255,255,255,0.92); line-height: var(--lh-normal); margin-bottom: var(--s4); }


/* ══ STATEMENT BOX ══════════════════════════════════════════════════ */

.statement-box { background: var(--purple-light); border-left: 3px solid var(--mim-purple); border-radius: 0 var(--radius-md) var(--radius-md) 0; padding: var(--s5) var(--s6); font-family: var(--font-feature); font-size: var(--fs-body-lg); font-weight: var(--weight-regular); color: var(--mim-black); line-height: var(--lh-normal); margin-top: var(--s8); }


/* ══ EMAIL RESOURCES + RESOURCES LIST ══════════════════════════════ */

.email-resources-btn { display: inline-flex; align-items: center; gap: var(--s2); margin-top: var(--s5); background: var(--mim-black); border: none; border-radius: var(--radius-pill); padding: 12px 22px; font-family: var(--font-primary); font-size: 12px; font-weight: var(--weight-semibold); letter-spacing: 0.1em; text-transform: uppercase; color: var(--mim-white); cursor: pointer; transition: opacity var(--dur-base) var(--ease-standard); text-decoration: none; }
.email-resources-btn:hover { opacity: 0.88; color: var(--mim-white); }
.email-resources-btn svg { width: 16px; height: 16px; flex-shrink: 0; }
.resources-list { list-style: none; display: flex; flex-direction: column; gap: var(--s3); margin-top: var(--s4); }
.resources-list li { font-size: var(--fs-small); font-weight: var(--weight-light); color: var(--fg-muted); line-height: var(--lh-normal); padding-left: var(--s4); position: relative; }
.resources-list li::before { content: ''; position: absolute; left: 0; top: 8px; width: 5px; height: 5px; border-radius: 50%; background: var(--mim-purple); }


/* ══ PHOTO ALONGSIDE LAYOUT ═════════════════════════════════════════ */

.photo-alongside-layout { display: flex; gap: var(--s6); align-items: flex-start; margin-top: var(--s4); }
.photo-alongside-layout__text { flex: 1; min-width: 0; }
.brad-photo { flex-shrink: 0; width: 190px; position: relative; border-radius: var(--radius-md); overflow: hidden; }
.brad-photo img { width: 100%; height: auto; display: block; border-radius: var(--radius-md); }
.brad-photo--large { width: 240px; }
.brad-photo--xl { width: 380px; }

/* ══ HEAR IT FROM HIM — full-bleed cover with overlaid text ═════════ */
.hifh-cover { position: relative; width: 100%; max-width: 1100px; margin: 0 auto; aspect-ratio: 3 / 2; border-radius: var(--radius-lg); overflow: hidden; }
.hifh-cover img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.hifh-cover::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0,0,0,0.20) 0%, transparent 32%, rgba(0,0,0,0.78) 100%); }
.hifh-cover__inner { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; padding: clamp(28px, 5vw, 56px); max-width: 780px; }
.hifh-cover__eyebrow { font-family: var(--font-primary); font-size: var(--fs-eyebrow); font-weight: var(--weight-semibold); letter-spacing: var(--tr-eyebrow); text-transform: uppercase; color: var(--mim-purple); margin: 0 0 var(--s3); }
.hifh-cover__title { font-family: var(--font-feature); font-weight: 700; font-size: clamp(46px, 7.5vw, 88px); line-height: 0.96; letter-spacing: -0.02em; color: var(--mim-white); margin: 0 0 var(--s4); text-shadow: 0 2px 28px rgba(0,0,0,0.55); }
.hifh-cover__lead { font-family: var(--font-feature); font-style: italic; font-size: calc(clamp(18px, 2.2vw, 25px) * var(--fs-scale)); line-height: 1.3; color: rgba(255,255,255,0.96); margin: 0 0 var(--s4); text-shadow: 0 1px 18px rgba(0,0,0,0.5); }
.hifh-cover__note { font-family: var(--font-primary); font-size: calc(15px * var(--fs-scale)); line-height: var(--lh-relaxed); color: rgba(255,255,255,0.88); margin: 0; }
.hifh-cover__note strong { font-weight: var(--weight-semibold); color: #fff; }
@media (max-width: 720px) { .hifh-cover { aspect-ratio: 3 / 4; } }


/* ══ HIGHLIGHT LINE ═════════════════════════════════════════════════ */

.highlight-line-wrap { position: relative; display: inline-block; }
.highlight-line-wrap strong { position: relative; z-index: 1; font-size: 17px; }
.highlight-line-img { position: absolute; bottom: -16px; left: -12px; width: calc(100% + 24px); height: 22px; object-fit: fill; pointer-events: none; z-index: 0; }


/* ══ TIPS & EXAMPLES BLOCKS ═════════════════════════════════════════ */

.tips-heading { font-size: var(--fs-small); font-weight: var(--weight-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--mim-black); margin: var(--s6) 0 var(--s3); }
.tips-list { list-style: none; display: flex; flex-direction: column; gap: var(--s3); margin-bottom: var(--s5); }
.tips-list li { font-size: var(--fs-body); font-weight: var(--weight-light); color: var(--fg); line-height: var(--lh-relaxed); padding-left: var(--s5); position: relative; }
.tips-list li::before { content: ''; position: absolute; left: 0; top: 0.25em; width: 14px; height: 10px; border-radius: 0; background: url('./assets/images/MIM_Arrow1.png') center/contain no-repeat; }
.examples-block { background: var(--purple-light); border-left: 2px solid var(--mim-purple); border-radius: 0 var(--radius-md) var(--radius-md) 0; padding: var(--s5) var(--s6); margin: var(--s4) 0; }
.examples-block ul { list-style: none; display: flex; flex-direction: column; gap: var(--s3); }
.examples-block li { font-size: var(--fs-body); font-style: italic; color: var(--fg); line-height: var(--lh-relaxed); padding-left: var(--s4); position: relative; }
.examples-block li::before { content: '"'; position: absolute; left: 0; top: 0; color: var(--mim-purple); font-weight: var(--weight-semibold); }


/* ══ MALE ACRONYM CARDS ═════════════════════════════════════════════ */

.male-cards { display: grid; grid-template-columns: repeat(2,1fr); gap: var(--s4); margin: var(--s6) 0; }
.male-card { background: var(--bg-muted); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--s5); display: flex; align-items: flex-start; gap: var(--s4); }
.male-card__letter { font-family: var(--font-feature); font-size: 42px; font-weight: var(--weight-regular); color: var(--mim-purple); line-height: 1; flex-shrink: 0; }
.male-card__body h4 { font-size: var(--fs-body); font-weight: var(--weight-semibold); color: var(--mim-black); margin-bottom: var(--s2); }
.male-card__body p  { font-size: var(--fs-small); color: var(--fg-muted); }


/* Screen 5 — background video */
#screen-4 { overflow: hidden; }
.screen-bg-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; z-index: 0; pointer-events: none;
}
/* Scrim between the video and its text (design feedback 14 Jul 2026): dimming
   the video itself washed out its colour without reliably protecting text
   contrast against bright frames. A black scrim above the video, below the
   text, does both — full video vibrancy, consistent white-text contrast. */
.screen--dark:has(> .screen-bg-video) { position: relative; }
.screen--dark:has(> .screen-bg-video)::before {
  content: ''; position: absolute; inset: 0;
  background: rgba(0,0,0,0.45); z-index: 1; pointer-events: none;
}
.screen--dark:has(> .screen-bg-video) > .screen-inner { position: relative; z-index: 2; }
#screen-4 .screen-inner { position: relative; z-index: 1; }

/* Remove texture on slides 30 and 36 */
#screen-28 { background-image: none; }
/* S32 — white background only (design feedback 17 Jul 2026). */
#screen-31 { background-image: none; }
#screen-36 { background-image: none; }

/* ── Animated quote cards (IGQ) — screens 22 (David) and 30 (Malcher) ── */
@keyframes igqFadeRise { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
@keyframes igqMark { from { opacity: 0; transform: translateY(10px) scale(.86); } to { opacity: 1; transform: none; } }
@keyframes igqSplash { from { background-size: 0% 100%; } to { background-size: 104% 100%; } }
@keyframes igqUnderline { from { background-size: 0% 78%; } to { background-size: 100% 78%; } }
.igq-card [data-anim="fade"],
.igq-card [data-anim="mark"] { opacity: 0; }
.igq-card[data-play="true"] [data-anim="fade"] { animation: igqFadeRise .72s cubic-bezier(0.16,1,0.3,1) forwards; }
.igq-card[data-play="true"] [data-anim="mark"] { animation: igqMark .6s cubic-bezier(0.16,1,0.3,1) forwards; }
.igq-card[data-play="true"] [data-anim="splash"] { animation: igqSplash 1.05s .95s cubic-bezier(0.2,0.7,0.2,1) both; }
.igq-card[data-play="true"] [data-anim="underline"] { animation: igqUnderline .9s .7s cubic-bezier(0.2,0.7,0.2,1) both; }
.igq-photo--david { background-image: url('./assets/images/portrait-david.jpg'); background-position: center 18%; background-size: cover; }
.igq-splash { background-image: url('./assets/images/mark-highlighter-blocks.png'); background-repeat: no-repeat; background-position: left center; background-size: 0% 100%; padding: .04em .18em .12em; -webkit-box-decoration-break: clone; box-decoration-break: clone; }
.igq-underline { background-image: url('./assets/images/mark-highlighter-line-v2.png'); background-repeat: no-repeat; background-position: left 92%; background-size: 0% 78%; padding: 0 .1em .04em; }
@media (prefers-reduced-motion: reduce) {
  .igq-card [data-anim="fade"],
  .igq-card [data-anim="mark"] { opacity: 1 !important; animation: none !important; }
  .igq-splash { background-size: 104% 100% !important; }
  .igq-underline { background-size: 100% 78% !important; }
}

/* Toggle twin of the @media block above — same state, driven by the
   in-course setting. A body class cannot un-match a media query, so the
   two entry points have to be authored in parallel. Keep them in step. */
body.reduced-motion .igq-card [data-anim="fade"], body.reduced-motion .igq-card [data-anim="mark"] { opacity: 1 !important; animation: none !important; }
body.reduced-motion .igq-splash { background-size: 104% 100% !important; }
body.reduced-motion .igq-underline { background-size: 100% 78% !important; }

@media (max-width: 720px) {
  .igq-grid { grid-template-columns: 1fr !important; }
  .igq-photo { min-height: 280px !important; max-height: 340px; order: -1; }
}

/* White photocopy texture on all non-dark editorial screens */
.screen:not(.screen--dark):not(.screen--multimedia):not(.screen--closing) {
  background-image: url('./assets/images/MIM_Photocopy-Texture-White.jpg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
body.night-mode .screen:not(.screen--dark):not(.screen--multimedia):not(.screen--closing) { background-image: none; }


/* ══ RESOURCE TAG BUTTON ════════════════════════════════════════════ */

.fom-tag-btn { display: flex; align-items: center; gap: 6px; width: fit-content; margin-top: 16px; background: none; border: 1.5px solid rgba(183,163,252,0.5); border-radius: var(--radius-pill); padding: 6px 14px; font-family: var(--font-primary); font-weight: var(--weight-semibold); font-size: 12px; letter-spacing: 0.04em; color: var(--purple-dark); cursor: pointer; transition: background var(--dur-base) var(--ease-standard), border-color var(--dur-base) var(--ease-standard), color var(--dur-base) var(--ease-standard); }
.fom-tag-btn:hover { background: rgba(183,163,252,0.14); border-color: var(--mim-purple); }
.fom-tag-btn.is-tagged { background: var(--mim-purple); border-color: var(--mim-purple); color: var(--mim-black); }
.fom-tag-btn.is-tagged svg { fill: var(--mim-black); }


/* ══ RESOURCE LIST ITEMS ════════════════════════════════════════════ */

.resources-list { list-style: none; margin: 0; padding: 0; }
.summary-resource-item { border-bottom: 1px solid var(--border); transition: background var(--dur-base) var(--ease-standard); }
.summary-resource-item:first-child { border-top: 1px solid var(--border); }
.resource-item__label { display: flex; align-items: flex-start; gap: 14px; padding: 12px 8px; cursor: pointer; margin: 0; }
.resource-item__label:hover { background: var(--mim-grey-light); }
.resource-checkbox { flex-shrink: 0; width: 18px; height: 18px; margin-top: 2px; accent-color: var(--mim-purple); cursor: pointer; }
.resource-item__text { font-family: var(--font-primary); font-weight: var(--weight-light); font-size: calc(14px * var(--fs-scale)); line-height: 1.55; color: var(--fg-muted); }
.summary-resource-item.tagged .resource-item__text { font-weight: var(--weight-semibold); color: var(--fg); }
.resources-email-section { margin-top: var(--sp-5); }
.resources-email-btns { display: flex; flex-wrap: wrap; gap: 12px; }
.resources-email-hint { font-size: 12px; font-style: italic; color: var(--fg-subtle); margin-top: 14px; }
.resources-email-hint.hidden { display: none; }
.resources-select-all { font-size: 12px !important; padding: 8px 16px !important; }


/* ══ REVEAL LIST BUTTON ═════════════════════════════════════════════ */

.reveal-list-btn { display: inline-flex; align-items: center; gap: var(--s2); background: none; border: 1.5px solid var(--border); border-radius: var(--radius-pill); padding: 9px 18px; font-family: var(--font-primary); font-size: 12px; font-weight: var(--weight-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--fg-muted); cursor: pointer; transition: border-color var(--dur-base) var(--ease-standard), color var(--dur-base) var(--ease-standard), background var(--dur-base) var(--ease-standard); margin-bottom: var(--s4); }
.reveal-list-btn:hover:not(:disabled) { border-color: var(--mim-purple); color: var(--purple-dark); background: var(--purple-light); }
.reveal-list-btn:disabled { opacity: 0.38; cursor: default; }


/* ══ NIGHT MODE — Part 2-specific component overrides ════════════════
   (Shared component night-mode rules are in mim-gp-shared.css)
   ══════════════════════════════════════════════════════════════════ */

body.night-mode h2, body.night-mode h3 { color: rgba(255,255,255,0.95); }
body.night-mode p { color: rgba(255,255,255,0.82); }
body.night-mode .divider { border-top-color: rgba(255,255,255,0.1); }
body.night-mode a { color: #c0a8ff; }
body.night-mode .card { background: #17171b; border-color: rgba(255,255,255,0.1); }
body.night-mode .card--purple { background: rgba(183,163,252,0.1); border-color: rgba(183,163,252,0.2); }
body.night-mode .pull-quote { background: rgba(183,163,252,0.08); color: rgba(255,255,255,0.9); }
body.night-mode .pull-quote cite { color: rgba(255,255,255,0.5); }
body.night-mode .find-out-more { border-color: rgba(255,255,255,0.1); }
body.night-mode .find-out-more__trigger { background: #17171b; color: rgba(255,255,255,0.6); }
body.night-mode .find-out-more__trigger:hover { background: rgba(183,163,252,0.1); color: rgba(255,255,255,0.85); }
body.night-mode .find-out-more__inner { background: #111115; border-top-color: rgba(255,255,255,0.08); color: rgba(255,255,255,0.65); }
body.night-mode .find-out-more__inner p { color: rgba(255,255,255,0.65); }
body.night-mode .quiz-option { background: #17171b; border-color: rgba(255,255,255,0.15); color: rgba(255,255,255,0.85); }
body.night-mode .quiz-option:hover:not(:disabled) { background: rgba(183,163,252,0.1); border-color: var(--mim-purple); }
/* .incorrect now uses var(--fg), which night mode does not redefine — without
   these it would render black-on-dark. Mirrors Part 1's .kc-option rules. */
body.night-mode .quiz-option.incorrect { color: rgba(255,255,255,0.6); border-color: rgba(255,255,255,0.5); background: rgba(255,255,255,0.06); }
body.night-mode .quiz-option.incorrect::after { color: rgba(255,255,255,0.9); }
body.night-mode .quiz-option.correct, body.night-mode .quiz-option.revealed-correct { background: rgba(183,163,252,0.14); }
body.night-mode .quiz-question { color: rgba(255,255,255,0.9); }
/* Quiz feedback panels were only styled for light mode (bright green/red on dark
   looked jarring). Darken the fill + lighten the text, keep the semantic border. */
body.night-mode .quiz-feedback--correct   { background: rgba(34,160,90,0.14); color: rgba(255,255,255,0.9); }
body.night-mode .quiz-feedback--incorrect { background: rgba(204,68,68,0.14); color: rgba(255,255,255,0.9); }
/* "Tips" heading was hard-set to black — invisible on the dark night-mode bg. */
body.night-mode .tips-heading { color: rgba(255,255,255,0.92); }
body.night-mode .faq-item { border-color: rgba(255,255,255,0.1); }
body.night-mode .faq-trigger { background: #17171b; color: rgba(255,255,255,0.8); }
body.night-mode .faq-trigger:hover { background: rgba(183,163,252,0.1); color: rgba(255,255,255,0.95); }
body.night-mode .faq-body__inner { border-top-color: rgba(255,255,255,0.08); color: rgba(255,255,255,0.65); }
body.night-mode .faq-body__inner p { color: rgba(255,255,255,0.65); }
body.night-mode .transcript-panel__inner { background: #17171b; color: rgba(255,255,255,0.65); }
body.night-mode .reveal-item { background: #17171b; border-color: rgba(255,255,255,0.1); }
body.night-mode .reveal-item__text { color: rgba(255,255,255,0.82); }
body.night-mode .reflection-entry { background: rgba(255,255,255,0.04); }
body.night-mode .reflection-entry__q { color: rgba(255,255,255,0.5); }
body.night-mode .reflection-entry__a { color: rgba(255,255,255,0.8); }
body.night-mode .reflections-viewer__panel { background: #17171b; }
body.night-mode .reflections-viewer__title { color: rgba(255,255,255,0.9); }
body.night-mode .tutorial-step { background: #17171b; border-color: rgba(255,255,255,0.1); }
body.night-mode .tutorial-step:hover { background: rgba(183,163,252,0.08); border-color: rgba(183,163,252,0.25); }
body.night-mode .tutorial-step__body p { color: rgba(255,255,255,0.55); }
body.night-mode .tips-list li { color: rgba(255,255,255,0.82); }
body.night-mode .resources-list li { color: rgba(255,255,255,0.6); }
body.night-mode .summary-screen__title { color: rgba(255,255,255,0.95); }
body.night-mode .fom-tag-btn { color: #cdbcff; }
body.night-mode .fom-tag-btn.is-tagged { color: var(--mim-black); }
body.night-mode .reveal-list-btn { border-color: rgba(255,255,255,0.15); color: rgba(255,255,255,0.5); }
body.night-mode .reveal-list-btn:hover:not(:disabled) { border-color: var(--mim-purple); color: var(--mim-purple); background: rgba(183,163,252,0.1); }


/* ══ RESPONSIVE — Part 2-specific overrides ══════════════════════════
   (Shared component responsive rules are in mim-gp-shared.css)
   ══════════════════════════════════════════════════════════════════ */

@media (max-width: 600px) {
  .male-cards { grid-template-columns: 1fr; }
  .photo-alongside-layout { flex-direction: column-reverse; }
  .brad-photo { width: 100%; max-width: 260px; margin: 0 auto; }
  .content-wrap { padding: var(--s6) var(--s4) var(--s10); }
  .quiz-option { padding: var(--s4); font-size: var(--fs-small); }
  .tutorial-step { flex-direction: column; gap: var(--s3); }
  .tutorial-step__icon { width: 40px; height: 40px; }
}


/* ── S13: 2 flip cards top row, 3 bottom row (design feedback 15 Jul 2026) ── */
#screen-11 .flipcard-grid { grid-template-columns: repeat(6, 1fr); }
#screen-11 .flipcard-grid > .flipcard:nth-child(1) { grid-column: 2 / span 2; }
#screen-11 .flipcard-grid > .flipcard:nth-child(2) { grid-column: 4 / span 2; }
#screen-11 .flipcard-grid > .flipcard:nth-child(3),
#screen-11 .flipcard-grid > .flipcard:nth-child(4),
#screen-11 .flipcard-grid > .flipcard:nth-child(5) { grid-column: span 2; }
@media (max-width: 600px) {
  #screen-11 .flipcard-grid { grid-template-columns: 1fr; }
  #screen-11 .flipcard-grid > .flipcard { grid-column: auto; }
}

/* ═══ A11y: Text-size (--fs-scale) coverage for the hero copy ═══
   .hx-sub / .hx-body hard-coded font-size without * var(--fs-scale); re-declared
   here (values unchanged) so the Text-size control affects them.
   ⚠ Verify at Text-size 5 (2.1×) that the hero doesn't overflow/clip. */
.hx-sub  { font-size: calc(clamp(18px,1.9vw,23px) * var(--fs-scale)); }
.hx-body { font-size: calc(15px * var(--fs-scale)); }

/* ── S32 moustache: GIF vs still ───────────────────────────────────────────
   An animated GIF ignores prefers-reduced-motion entirely — there's no CSS or
   JS hook to pause one. So the still is a real element, swapped in by the same
   two entry points as every other motion rule here. */
.summary-screen__logo.mo-still { display: none; }
@media (prefers-reduced-motion: reduce) {
  .summary-screen__logo.mo-anim  { display: none; }
  .summary-screen__logo.mo-still { display: block; }
}
body.reduced-motion .summary-screen__logo.mo-anim  { display: none; }
body.reduced-motion .summary-screen__logo.mo-still { display: block; }

/* The sentence lifted above the video on S32 (it used to sit below the divider). */
.summary-screen__lead {
  max-width: var(--measure); margin: var(--s4) auto 0;
  font-size: calc(16px * var(--fs-scale)); line-height: var(--lh-relaxed);
  color: var(--fg); font-weight: var(--weight-light);
}

/* ══ DOWNLOAD CALLOUT ════════════════════════════════════════════════
   Ported from Part 3 (slides 23/41) so the handout callout is identical
   across the course. Only the live-download rules are carried over —
   Part 3's "--pending / coming soon" state has no use here. Spacing uses
   this module's --s6 alias (Part 3 authors the same value as --sp-6). */
.download { max-width: var(--measure); margin-top: var(--s6); display: flex; align-items: center; gap: 20px; flex-wrap: wrap; padding: 20px 22px; background: rgba(183,163,252,0.08); border: 1px solid var(--mim-purple-aa); border-radius: var(--radius-md); }
.download__body { flex: 1 1 260px; }
.download__body .body { margin: 0; }
.download__btn { flex: 0 0 auto; text-decoration: none; }

/* ══ Layout fixes inherited from the ACRRM build (20 Jul 2026) — promote to the shared
   engine once the other courses are done, then delete this block. Kept verbatim so this
   edition stays diffable against ACRRM; geometry only, nothing accreditation-related.
   ══════════════════════════════════════════════════════════════════════════════════ */


/* ═══════════════════════════════════════════════════════════════════════════════
   AUDIENCE DISCLAIMER + CRISIS SUPPORT — Health and Community Professionals edition only
   Added 12 Aug 2026. Not present in the GP / ACRRM / Pharmacy / Nurses courses,
   so a diff against ACRRM will show this block as an intended delta.

   Two components:
     .hero-note      short notice on the hero (screen 1)
     .audience-note  the full disclaimer on the onboarding screen
   Conventions these deliberately follow (each one is a documented past defect):
     · Opaque backgrounds, never translucent. Over the hero photograph a
       translucent panel is both genuinely hard to read and unmeasurable —
       qa-contrast composites to the painted backdrop and cannot see the image,
       so it reports a confident false result in either direction.
     · font-size carries * var(--fs-scale) so the A/A+/A++ control actually
       resizes this copy. qa-text-size only samples a fixed list of blocks, so a
       new component that omits the scale sails through the gate (Ph2/Ph3 hero
       copy did exactly that).
     · Explicit body.night-mode overrides. Inheriting --fg in night mode is the
       documented route to ~2.6:1 body copy.
     · NO [data-rise]. The hero rise animation is correctly wrapped in
       @media (prefers-reduced-motion: no-preference), but a disclaimer must not
       depend on an animation having run under any circumstances.
   ═══════════════════════════════════════════════════════════════════════════════ */

.hero-note {
  /* Deliberately loud (Tom, 13 Aug). This is the only thing telling a learner the
     course was not written for their role, so it is sized to be read, not skimmed
     past: body-copy size rather than caption size, a full border plus a heavy left
     rule, and a shadow to lift it off the photograph. Still OPAQUE — a translucent
     panel over the hero image is both hard to read and unmeasurable (qa-contrast
     composites to the painted backdrop and cannot see a photograph). */
  max-width: 62ch;
  background: #141318;
  border: 1px solid rgba(183, 163, 252, 0.42);
  border-left: 6px solid var(--mim-purple);
  border-radius: var(--radius-md);
  padding: 20px 24px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.5);
}
.hero-note__label {
  display: block;
  font-family: var(--font-primary); font-weight: var(--weight-bold);
  font-size: calc(13px * var(--fs-scale));
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--mim-purple);
  margin-bottom: 9px;
}
.hero-note__text {
  font-family: var(--font-primary); font-weight: var(--weight-regular);
  font-size: calc(17px * var(--fs-scale)); line-height: 1.5;
  color: #fff;                              /* 19:1 on #141318 */
  margin: 0;
}

.audience-note {
  max-width: var(--measure);
  margin-top: var(--sp-6);
  background: #F4F1FF;                      /* light purple tint, opaque */
  border-left: 3px solid var(--mim-purple);
  border-radius: var(--radius-md);
  padding: 22px 24px;
}
.audience-note__label {
  display: block;
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(11px * var(--fs-scale));
  letter-spacing: 0.16em; text-transform: uppercase;
  color: #4B3A9E;                           /* 7.4:1 on #F4F1FF — --mim-purple is too light here */
  margin-bottom: 10px;
}
.audience-note__text {
  font-family: var(--font-primary); font-weight: var(--weight-regular);
  font-size: calc(15px * var(--fs-scale)); line-height: 1.6;
  color: #1A1A1A; margin: 0;
}
.audience-note__text + .audience-note__text { margin-top: 0.9em; }

body.night-mode .audience-note      { background: #17171b; }
body.night-mode .audience-note__label { color: #cdbcff; }   /* 8.1:1 on #17171b */
body.night-mode .audience-note__text  { color: rgba(255,255,255,0.90); }

/* Short viewports. 1366x768 is the most common laptop resolution and the hero copy
   stack there (kicker + up-to-84px title + sub + note + body paragraphs) overran the
   usable height by ~8px, putting the audience disclaimer behind the Back/Continue
   footer. Measured, not guessed: see tools/qa-hcp-disclaimer.js, which asserts the
   note's real rect against innerHeight minus the footer at every breakpoint.
   Tighten the stack rather than let a disclaimer depend on the learner scrolling. */
@media (max-height: 850px) {
  /* The disclaimer is now bigger, so the space has to come from somewhere. It comes
     from the DISPLAY TITLE, not from the disclaimer: capping the title reclaims ~60px
     across its three lines, which is more than the larger note costs. Verified with a
     real measurement at 1366x768 (the most common laptop size, and the one that
     overran by 8px before), 1440x900, 1280x720 and 1920x1080 — see
     tools/qa-hcp-disclaimer.js, which asserts the note's rect against innerHeight
     minus the footer. Never shrink the note to make it fit. */
  .screen--hero .hx-title         { font-size: clamp(34px, 4.1vw, 54px); }
  .screen--hero .hero__copy      { gap: 12px; }
  .screen--hero .hero__inner-wrap { padding-bottom: 26px; }
  .hero-note                      { padding: 16px 20px; }
  .hero-note__label               { margin-bottom: 7px; }
}

/* .evidence__link is display:block / 11px / uppercase by design. Restore body size for
   the disclaimer's contact link, following the .find-out-more__link precedent in
   mim-gp-shared.css. Explicit calc(), not var(--fs-body): the token form silently
   ignores the text-size control. */
/* Inline, body-size contact link inside the disclaimer copy. Deliberately NOT
   .evidence__link (display:block / 11px / uppercase -- a standalone CTA). Explicit
   calc() rather than var(--fs-body): the token form ignores the text-size control. */
.audience-note__inline-link {
  font-size: calc(15px * var(--fs-scale));
  color: #4B3A9E;                 /* 7.4:1 on #F4F1FF */
  text-decoration: underline;
}
body.night-mode .audience-note__inline-link { color: #cdbcff; }   /* 8.1:1 on #17171b */

/* ═══════════════════════════════════════════════════════════════════
   PROMOTED FROM THE v2 PREVIEW LAYER, 2026-09-21
   This was tools/v2-preview.css, loaded AFTER the module's own rules.
   ⚠ IT MUST STAY BELOW THEM. Much of the v2 release is additive rules that
   win on source order — the quote screens, the button unification, the
   video measure. Moving this block above the module's own CSS undoes them
   silently.
   ═══════════════════════════════════════════════════════════════════ */
.evidence,
.flipcard__front,
.flipcard__back,
.transcript-toggle,
.reflect__toggle,
.kc-option,
.quiz-option {
  box-shadow: var(--depth-1);
  transition: box-shadow 240ms var(--ease-standard), transform 240ms var(--ease-standard),
              border-color var(--dur-base) var(--ease-standard), background var(--dur-base) var(--ease-standard);
}

.evidence:hover,
.transcript-toggle:hover,
.reflect__toggle:hover,
.kc-option:hover:not(:disabled),
.quiz-option:hover:not(:disabled) {
  box-shadow: var(--depth-2);
  transform: translateY(-2px);
}

/* The lift belongs to the CARD, the shadow to its faces: .flipcard is a 3D
   perspective container and a shadow on it is flattened by the rotation. The
   engine gives .flipcard its lift; these are the faces. */
.flipcard:hover .flipcard__front,
.flipcard:hover .flipcard__back { box-shadow: var(--depth-2); }

/* An answered option is no longer a button, so it stops behaving like one. */
.kc-option:disabled, .quiz-option:disabled { box-shadow: 0 2px 6px rgba(0,0,0,0.08); }

/* Night mode puts a dark ground under all of these, so the lift comes from
   light instead of shade — the same inversion the engine applies to its own. */
body.night-mode .evidence,
body.night-mode .flipcard__front,
body.night-mode .flipcard__back,
body.night-mode .transcript-toggle,
body.night-mode .reflect__toggle,
body.night-mode .kc-option,
body.night-mode .quiz-option { box-shadow: var(--depth-1-lt); }
body.night-mode .evidence:hover,
body.night-mode .transcript-toggle:hover,
body.night-mode .reflect__toggle:hover,
body.night-mode .kc-option:hover:not(:disabled),
body.night-mode .quiz-option:hover:not(:disabled) { box-shadow: var(--depth-2-lt); }

/* The engine's global reduced-motion blocks already compress every duration to
   0.01ms. What they cannot do is remove a TRANSFORM, so the hover lift is
   cancelled here rather than merely made instant. */
@media (prefers-reduced-motion: reduce) {
  .evidence:hover, .transcript-toggle:hover, .reflect__toggle:hover,
  .kc-option:hover, .quiz-option:hover { transform: none; }
}
body.reduced-motion .evidence:hover,
body.reduced-motion .transcript-toggle:hover,
body.reduced-motion .reflect__toggle:hover,
body.reduced-motion .kc-option:hover,
body.reduced-motion .quiz-option:hover { transform: none; }


/* -- THE FAQ, BROUGHT BACK TO THE RTL STANDARD ---------------------------
   Tom, 2026-09-14, of the v2 previews: "updating it has made them look bad.
   Bring them in line with the look of the FAQ for the MIM MH."

   He is right, and it is not a taste call: it is five measured regressions.
   The ENGINE carries the FAQ standard Tom approved on MIM MH module 1 and
   promoted on 31 Aug 2026, but MIM Pro's own module.css still carries the
   FLAT accordion it had before that, and a module stylesheet loads after the
   engine. So each of the first four is the old rule winning on source order,
   measured against MIM MH module 1 with getComputedStyle:

     .accordion           1px black-60% rule above AND below the stack.
                          The promoted look is a column of cards with no
                          rules around it at all. MH measures 0px.
     .accordion__summary  padding 22px 4px, so the question sits 18px
                          further left than the card holding it.
     .accordion__body     the same 4px, so the answer does not line up with
                          its own question.
     :last-child          border-bottom: none, which was right for a list
                          drawn with dividers and leaves the bottom CARD
                          with no bottom edge.

   The fifth is the engine arguing with itself, and it is the one that does
   the visible damage. ".screen button" (0,1,1) gives every pressable thing
   --depth-1, and it OUTRANKS the ".accordion__summary { box-shadow: none }"
   in the engine's own promoted FAQ block (0,1,0). The summary is a button
   inside a card with overflow: hidden, so its shadow is clipped into a hard
   grey band across the card under the question. That band is most of what
   "looks bad" means here, and it is present in MIM Pro v1 as well.

   Fixed by SPECIFICITY rather than !important: ".screen .accordion__summary"
   is 0,2,0 and its hover variant 0,3,0, so each beats exactly the engine
   rule it has to beat and disturbs nothing else. MIM MH reaches the same end
   state with "box-shadow: none !important", which is this fix with a bigger
   hammer.

   None of the values are invented. They are MIM MH module 1's own, read off
   the RENDERED page rather than reassembled from the cascade, and
   tools/qa-faq-parity.js asserts the two still agree. */
.accordion { border-top: 0; border-bottom: 0; }
.accordion__item:last-child { border-bottom: 1px solid var(--border); }
.accordion__body { padding-left: 22px; padding-right: 22px; }
.screen .accordion__summary { padding-left: 22px; padding-right: 22px; box-shadow: none; }
.screen .accordion__summary:hover { box-shadow: none; }

/* Night mode: the promoted card takes "background: var(--bg)", which stays
   white, so without this the FAQ is a column of white cards on a black
   screen carrying white question text - invisible. The value is MIM MH's
   own. This is the standing trap that night mode is an OVERRIDE LIST and not
   a token flip: anything new to a screen renders wrong until someone writes
   its night rule. */
body.night-mode .accordion__item { background: #17171b; }

/* And the band comes back in night mode unless it is cancelled there too:
   the engine ships a night variant of the button-depth rule,
   "body.night-mode .screen button" at 0,2,1, which outranks the 0,2,0 fix
   above. Measured: every one of the five streams still carried a white
   --depth-1-lt shadow on the summary while the light mode read clean. Both
   halves of an override list, every time. */
body.night-mode .screen .accordion__summary,
body.night-mode .screen .accordion__summary:hover { box-shadow: none; }


/* ═══════════════════════════════════════════════════════════════════════
   v2.7 — THE SAME BAND, ON THE COMPONENTS THE FAQ FIX DID NOT REACH.

   Tom, 19 September 2026: "the accordions in the V2 still have the shading
   issue - when you expand them, the shadow from the button displays into the
   revealed text and looks odd."

   He is right, and the accordion is no longer where it comes from. Measured
   on the rendered page rather than read off the cascade: an open
   .accordion__item is clean white all the way down, because the block above
   fixed it. What still bands is every OTHER expandable built the same way. A
   whole-suite audit for the actual defect condition - an element whose outer
   box-shadow is painted inside an ancestor that clips - found two that reveal
   text when opened:

     104  .evidence__row       inside .evidence           all 15 modules
      12  .mim-stages__toggle  inside .mim-stages__card    4 modules

   The MO' RESEARCH panel is the one learners meet constantly, and to a
   learner it IS an accordion: a header you press, a body that appears.
   Measured on GP Part 3 screen 7, panel background rgb(241,242,242): the
   first pixels of the revealed body read (200,201,201) and fade back to
   (234,235,235) over about 25px. That is a drop shadow cropped by the panel,
   lying across the answer. The stages card is the same, (198,198,196)
   against (242,242,240).

   🔑 THE RULE IS MIM MH'S OWN, and it is worth stating AS a rule rather than
   patching a third selector later. MIM MH module 1 puts it exactly: "the card
   is the button now, so the card lifts and the summary inside it does not -
   two shadows nested in one another is what looked wrong in the first place."
   So: A LIFTED, CLIPPING PANEL CARRIES THE ONLY SHADOW; any control nested
   inside it is flat. The engine breaks that rule three ways, because
   .screen button, .screen [role=button] and its own
   ".evidence__row { box-shadow: var(--depth-1) }" each hand a shadow to the
   header, while .evidence and .mim-stages__card both set overflow: hidden.

   ⚠ MIM MH HAS THE EVIDENCE BAND TOO, pixel for pixel identical: it fixed its
   accordion and never its research panel. So this is not "catching up with
   MIM MH" on that component, it is finishing the job. MIM MH is a separate
   course outside this release, so it is flagged rather than changed here.

   Specificity, not !important, for the same reason as the FAQ block: each
   selector beats exactly the engine rule it has to beat.
     .screen .evidence__row                  0,2,0  beats  .screen button
                                                            0,1,1
     body.night-mode .screen .evidence__row  0,3,0  beats  body.night-mode
                                                            .screen button
                                                            0,2,1
   Both halves, every time, because night mode is an override list and the
   engine ships a night variant of each of these. */
.screen .evidence__row,
.screen .evidence__row:hover,
.screen .mim-stages__toggle,
.screen .mim-stages__toggle:hover { box-shadow: none; }

body.night-mode .screen .evidence__row,
body.night-mode .screen .evidence__row:hover,
body.night-mode .screen .mim-stages__toggle,
body.night-mode .screen .mim-stages__toggle:hover { box-shadow: none; }


/* ═══════════════════════════════════════════════════════════════════════
   v2.4 — Tom's round of 15 September 2026.

   Everything below is suite-wide and CSS-only unless a step in
   tools/build-mim-pro-v2.js is named beside it. Nothing here touches a live
   entry file: this stylesheet is loaded by v2.html alone.
   ═══════════════════════════════════════════════════════════════════════ */


/* ── 1. THE NAVIGATION SCREEN: the icons become the actual buttons ────────
   "Update the navigation screens to look the same as the nav screen from the
   MIM MH course (the buttons match the actual buttons)."

   MIM Pro drew seven identical purple chips. MIM MH draws a REPLICA of the
   control each row describes, so the learner is looking at the thing they will
   be looking for. These are MIM MH module 1's own resolved values, read off
   the live controls rather than guessed:

     Continue  #btnNext   black pill, white 13px/600, radius 999px, 12px 26px
     Back      #btnPrev   #F1F2F2 on #4A4A4A, 1px rgba(0,0,0,.12), same pill
     the four  .btn-icon  40px, radius 8px, white-on-near-black

   The header buttons are transparent on a near-black bar, so a faithful copy
   on this white screen has to BRING ITS GROUND WITH IT - otherwise it is a
   white glyph on white. Each is drawn on the header's own dark plate.

   The two pills also need the word rather than a chevron, which is markup:
   step 8 of the generator swaps it. This half is only the paint.

   WARNING Part 1 ONLY, because the navigation screen was removed from Parts 2
   and 3 earlier in this same release. These rules match nothing there, which
   is correct rather than an oversight. */
.tutorial-step__icon--pill {
  width: auto;
  min-width: 0;
  padding: 12px 26px;
  border-radius: 999px;
  font-family: var(--font-primary);
  font-size: calc(13px * var(--fs-scale));
  font-weight: var(--weight-semibold);
  line-height: 1;
  white-space: nowrap;
  box-shadow: var(--depth-1);
}
.tutorial-step[data-target="next"] .tutorial-step__icon--pill {
  background: var(--mim-black);
  color: var(--mim-white);
  border: none;
}
.tutorial-step[data-target="prev"] .tutorial-step__icon--pill {
  background: #F1F2F2;
  color: #4A4A4A;
  border: 1px solid rgba(0,0,0,0.12);
}
.tutorial-step[data-target="menu"] .tutorial-step__icon,
.tutorial-step[data-target="support"] .tutorial-step__icon,
.tutorial-step[data-target="bug"] .tutorial-step__icon,
.tutorial-step[data-target="settings"] .tutorial-step__icon {
  width: 40px;
  height: 40px;
  flex: 0 0 40px;
  border-radius: 8px;
  background: rgba(10,10,12,0.92);
  border: 1px solid rgba(255,255,255,0.2);
  color: rgba(255,255,255,0.65);
  box-shadow: var(--depth-1);
}
.tutorial-step[data-target="menu"] .tutorial-step__icon svg,
.tutorial-step[data-target="support"] .tutorial-step__icon svg,
.tutorial-step[data-target="bug"] .tutorial-step__icon svg,
.tutorial-step[data-target="settings"] .tutorial-step__icon svg { width: 18px; height: 18px; }
.tutorial-step[data-target="support"] .tutorial-step__icon--text {
  font-size: calc(17px * var(--fs-scale));
  font-weight: var(--weight-semibold);
  color: rgba(255,255,255,0.85);
}
/* The seventh step, "Keyboard and swipe shortcuts", points at a GESTURE. There
   is no button on screen to replicate, so it keeps the purple chip - which is
   now the thing that says so - and takes the same depth so it does not read as
   the one row nobody styled. */
.tutorial-step[data-target="none"] .tutorial-step__icon { box-shadow: var(--depth-1); }
.tutorial-step:hover .tutorial-step__icon { box-shadow: var(--depth-2); }


/* ── 2. PHOTOGRAPHS ON A DARK SCREEN GET AN EDGE ──────────────────────────
   "Update the dark photograph screens to give the images the same white
   glowing border as the transcript buttons."

   That button's edge on a dark ground is TWO things, and it needs both or it
   is not the same edge: a 1px rgba(255,255,255,0.4) border from the module's
   own stylesheet, and --depth-1-lt from the engine, which is the white-light
   inversion of the ordinary shadow. A photograph with neither floats with no
   boundary at all on a near-black screen. */
.screen--dark .image-quote,
.screen--multimedia .image-quote {
  border: 1px solid rgba(255,255,255,0.4);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--depth-1-lt);
  transition: box-shadow var(--dur-base) var(--ease-standard);
}


/* ── 3. AND SO DOES THE VIDEO BOX ─────────────────────────────────────────
   "for these dark screens with a black video box, place a white glowing border
   around the video box the same as the read video transcript button."

   The same pair, on .video-frame. It sits directly above the transcript button
   it is being matched to, which is why a near miss here would read as a
   mistake rather than as a variation. */
.screen--dark .video-frame,
.screen--multimedia .video-frame {
  border: 1px solid rgba(255,255,255,0.4);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--depth-1-lt);
}


/* ── 4. THE LIFE-STAGE CARDS LOOK PRESSABLE ───────────────────────────────
   "give the three masculinities boxes the depth and shadow to show that they
   are clickable boxes."

   They are .reveal-item, and the engine's rule that gives every pressable
   thing depth is scoped to `.screen button` - the button here is the HEAD
   inside the card, and a shadow on that is clipped by the card's own
   overflow: hidden. So the depth goes on the CARD and the head is flattened,
   exactly as the FAQ accordion is handled earlier in this file. */
.reveal-item {
  box-shadow: var(--depth-1);
  transition: box-shadow 240ms var(--ease-standard), transform 240ms var(--ease-standard);
}
.reveal-item:hover { box-shadow: var(--depth-2); transform: translateY(-2px); }
.screen .reveal-item__head,
.screen .reveal-item__head:hover { box-shadow: none; }
body.night-mode .reveal-item { box-shadow: var(--depth-1-lt); }
body.night-mode .reveal-item:hover { box-shadow: var(--depth-2-lt); }
@media (prefers-reduced-motion: reduce) { .reveal-item:hover { transform: none; } }
body.reduced-motion .reveal-item:hover { transform: none; }


/* ── 5. AN ATTRIBUTED QUOTE IS THE MIM MH "MO QUOTE" ──────────────────────
   Tom, 15 Sep 2026: "the new attributed quote boxes don't match the style I
   had in mind. Have a look at Slide 8 of the Men in Mind Mental Health course,
   Module 1 for what I meant."

   That slide is `.moq`: a purple block, the quote in black, a hairline rule
   inset to the text, the attribution beneath it, and a hand-drawn moustache
   overhanging the top-left corner which DRAWS ITSELF on arrival and then
   wiggles. v2.4 gave these a white card instead, which was not it.

   These are MIM MH module 1's own values. The markup is built by
   tools/v2-round4.js, which reads the stroked path from
   _components/assets/mo-quote/mo-mark.svg so the two courses cannot end up
   with slightly different moustaches.

   SCOPED TO THE ONES THAT HAVE A SOURCE. 35 purple-line keypoints exist across
   the suite and only three carry an attribution. Tom: "absolutely do not invent
   attributions if one isn't there." The other 32 keep the purple left rule they
   were authored with, because they are emphasis statements and not quotations.
   ───────────────────────────────────────────────────────────────────────── */
.moq {
  /* Tom, 20 Sep: "the accredited quote box is smaller than the practical tool
     box below and looks odd." Measured on GP2 S18 this renders 560px against
     the annotated portrait's 656, and on GP1 S30 560 against 700.

     560px was a number, not a decision. --measure (700px) is the course's
     content measure and is already what every panel that DOES line up uses
     (.ap, .evidence, .download). It is context-correct without a second rule:
     inside .content-wrap the parent clamps it to 656 and inside .screen-inner
     it reaches 700 - which is what its neighbours do in each of those places. */
  max-width: var(--measure);
  margin: var(--sp-6) 0;
}

/* The moustache overhangs the purple block by 22px and sits above it. */
.moq__mo {
  width: 240px; height: auto; display: block;
  margin: 0 0 -22px 4px;
  position: relative; z-index: 2;
  overflow: visible;
  transform-origin: 50% 70%;
  animation: moq-wiggle 3200ms ease-in-out 2000ms infinite;
}
.moq__path {
  fill: var(--mim-black); fill-opacity: 0;
  stroke: var(--mim-black); stroke-width: 3;
  stroke-linejoin: round; stroke-linecap: round;
  stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: moq-draw 1400ms var(--ease-standard) 200ms forwards,
             moq-fill 500ms var(--ease-standard) 1500ms forwards;
}

.moq__body {
  background: var(--mim-purple);
  margin: 0;
  padding: 44px 40px 32px;
}
.moq__quote {
  font-family: var(--font-primary); font-weight: 400;
  font-size: calc(23px * var(--fs-scale));
  line-height: 1.45; letter-spacing: -0.01em;
  color: var(--mim-black); margin: 0;
  opacity: 0; animation: moq-rise 520ms var(--ease-standard) 900ms forwards;
}
/* The rule above the attribution is inset to the text, not bled to the edge of
   the purple, because the padding lives on the parent here. */
.moq__attr {
  position: relative;
  margin-top: 26px; padding-top: 16px;
  color: var(--mim-black);
  opacity: 0; animation: moq-fade 520ms var(--ease-standard) 1300ms forwards;
}
.moq__attr::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0;
  border-top: 1px solid rgba(0,0,0,0.35);
}

@keyframes moq-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes moq-fill { from { fill-opacity: 0; } to { fill-opacity: 1; } }
@keyframes moq-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes moq-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes moq-wiggle {
  0%   { transform: rotate(-5deg) translateY(0) scaleY(1); }
  20%  { transform: rotate(2deg) translateY(-5px) scaleY(1.06); }
  40%  { transform: rotate(5.5deg) translateY(0) scaleY(0.96); }
  60%  { transform: rotate(1deg) translateY(-6px) scaleY(1.05); }
  80%  { transform: rotate(-3.5deg) translateY(-2px) scaleY(0.97); }
  100% { transform: rotate(-5deg) translateY(0) scaleY(1); }
}

@media (max-width: 600px) {
  .moq__mo { width: 168px; margin-bottom: -15px; }
  .moq__body { padding: 30px 24px 24px; }
  .moq__quote { font-size: calc(19px * var(--fs-scale)); }
  .moq__attr { margin-top: 20px; padding-top: 13px; }
}

/* An entrance that never runs must not leave the quote invisible: these sit at
   opacity 0 until their animation fires, so reduced motion has to hand them the
   FINAL state rather than simply cancelling the animation. */
@media (prefers-reduced-motion: reduce) {
  .moq__mo { animation: none !important; transform: none !important; }
  .moq__path { animation: none !important; stroke-dashoffset: 0 !important; fill-opacity: 1 !important; }
  .moq__quote, .moq__attr { animation: none !important; opacity: 1 !important; transform: none !important; }
}
body.reduced-motion .moq__mo { animation: none !important; transform: none !important; }
body.reduced-motion .moq__path { animation: none !important; stroke-dashoffset: 0 !important; fill-opacity: 1 !important; }
body.reduced-motion .moq__quote,
body.reduced-motion .moq__attr { animation: none !important; opacity: 1 !important; transform: none !important; }


/* ── 6. THE FIGURATIVE ILLUSTRATIONS BREATHE ──────────────────────────────
   "animate the purple illustration to gently bounce up and down with a slight
   tilt left to right. Check to see if this screen appears in the other courses
   and if it does, apply the same animation."

   Selected by the ARTWORK rather than by screen number, which is what makes
   the second sentence answer itself: every module that carries one of these
   three files gets it, now and whenever a new part is built. Tom named screens
   7 and 33 of RACGP Module 1; those are mark-person-1 and
   MIM_Man-with-Speech-Bubble1, and the same two files plus Fetal-Position
   appear 13 times across the suite.

   The marks in step 7 are deliberately NOT in this list. A highlighter stroke
   is a drawn gesture, not a character, and bobbing it reads as a glitch.

   translate, not transform: an animation REPLACES the property it animates, so
   an illustration that was centred or offset by a transform would be yanked to
   the middle the moment this started. */
/* ⚠ NO CLASS IN THE SELECTOR, and that is the second fix this rule needed.
   It listed .anote-figure and .accent-row__art, which is what an inventory of
   Part 1 turns up - and the Part 3s carry the same artwork on a THIRD class,
   .float-art, so the fetal-position figure sat still in five modules. The
   artwork is the thing being animated, so the artwork is what to select on;
   a wrapper class invented next month is then covered too. */
img[src$="mark-person-1.png"],
img[src$="MIM_Fetal-Position1.png"],
img[src$="MIM_Man-with-Speech-Bubble1.png"] {
  animation: mimFigureFloat 5200ms ease-in-out infinite;
  transform-origin: 50% 85%;
  will-change: translate, rotate;
}
/* ⚠ .anote-figure ALREADY HAS AN ANIMATION, and an animation shorthand
   replaces the whole property. The module runs anoteFade on it at
   `.screen--note.anote-play .anote-figure` (0,3,0), which outranks the
   selector above, so the float simply never started - measured as
   animation-name "anoteFade" on the very screen Tom named. Both are declared
   together here, at a specificity that wins, so the figure still fades in as
   authored and then breathes. They compose cleanly because anoteFade animates
   opacity and transform while the float uses translate and rotate, which are
   separate properties. */
.screen--note.anote-play .anote-figure[src$="mark-person-1.png"],
.screen--note.anote-play .anote-figure[src$="MIM_Fetal-Position1.png"],
.screen--note.anote-play .anote-figure[src$="MIM_Man-with-Speech-Bubble1.png"] {
  animation: anoteFade 0.8s cubic-bezier(0.16,1,0.3,1) 0.38s both,
             mimFigureFloat 5200ms ease-in-out 1200ms infinite;
}


@keyframes mimFigureFloat {
  0%   { translate: 0 0;     rotate: -1.6deg; }
  25%  { translate: 0 -7px;  rotate: 0.8deg; }
  50%  { translate: 0 0;     rotate: 1.8deg; }
  75%  { translate: 0 -5px;  rotate: 0.2deg; }
  100% { translate: 0 0;     rotate: -1.6deg; }
}
@media (prefers-reduced-motion: reduce) {
  img.anote-figure, img.accent-row__art { animation: none !important; translate: none !important; rotate: none !important; }
}
body.reduced-motion img.anote-figure,
body.reduced-motion img.accent-row__art { animation: none !important; translate: none !important; rotate: none !important; }


/* ── 7. THE HIGHLIGHTER MARKS ARRIVE RATHER THAN BEING THERE ──────────────
   "S11 animate in the purple swoosh" and "S20 animate in the purple splash and
   have it fill more of the space."

   Again keyed to the artwork, so every course with the same mark gets the same
   entrance. Both are drawn gestures, so both arrive the way a stroke is made:
   the swoosh wipes left to right, the splash blooms from its own centre.

   They play on screen ARRIVAL, not on load, which is what .screen.active
   buys - otherwise the entrance happens while the learner is twenty screens
   away and they never see it. */
.screen.active img[src$="MIM_Highlighter-Line3_V1_HR.png"] {
  animation: mimSwooshIn 760ms var(--ease-standard) 160ms both;
}
@keyframes mimSwooshIn {
  from { opacity: 0; clip-path: inset(0 100% 0 0); translate: -12px 0; }
  to   { opacity: 1; clip-path: inset(0 0 0 0);    translate: 0 0; }
}

/* The splash also grows. Tom: "have it fill more of the space." The authored
   width is clamp(140px, 25.7vw, 340px) as an inline style on the img, so this
   has to out-specify an inline declaration - hence !important, which is the
   one place in this file it is the right tool rather than the lazy one. */
/* Tom: "have it fill more of the space." The image is an item in the note
   screen's two-column grid, and that column is clamp(160px, 19.1vw, 280px) -
   measured at 1280px it is 244px, which is exactly what the image rendered at.
   Widening the image alone did nothing, because the COLUMN was the constraint.
   data-splash is put on the section by tools/v2-round4.js so this widens the
   one screen that has a splash and leaves every other note screen alone.

   The inline style on the img caps it at 340px, so that has to be lifted too -
   the one place in this file where !important is the right tool rather than the
   lazy one, because an inline declaration is what it is beating. */
.screen[data-splash] .screen-inner { grid-template-columns: 1fr clamp(240px, 32vw, 460px); }
.screen[data-splash] img.anote-figure[src$="MIM_Highlighter-Circle-1-LRG.png"] {
  width: clamp(240px, 32vw, 460px) !important;
  height: auto !important;
}
.screen.active img[src$="MIM_Highlighter-Circle-1-LRG.png"] {
  animation: mimSplashIn 820ms var(--ease-standard) 140ms both;
}
@keyframes mimSplashIn {
  from { opacity: 0; scale: 0.72; rotate: -8deg; }
  60%  { opacity: 1; scale: 1.04; rotate: 2deg; }
  to   { opacity: 1; scale: 1;    rotate: 0deg; }
}
@media (prefers-reduced-motion: reduce) {
  .screen.active img[src$="MIM_Highlighter-Line3_V1_HR.png"],
  .screen.active img[src$="MIM_Highlighter-Circle-1-LRG.png"] {
    animation: none !important; opacity: 1 !important; clip-path: none !important;
    scale: none !important; rotate: none !important; translate: none !important;
  }
}
body.reduced-motion .screen.active img[src$="MIM_Highlighter-Line3_V1_HR.png"],
body.reduced-motion .screen.active img[src$="MIM_Highlighter-Circle-1-LRG.png"] {
  animation: none !important; opacity: 1 !important; clip-path: none !important;
  scale: none !important; rotate: none !important; translate: none !important;
}


/* ── 8. THE MIM STARBURST ─────────────────────────────────────────────────
   "apply the slowly spinning MIM_Rays_V2 in the top right hand corner under
   the text. Going forward we will call this the MIM Starburst."

   Named, so it has a class of its own rather than a screen number: .mim-
   starburst, added by step 9 of the generator. This is the same treatment MIM
   MH module 1's Course Overview carries (.co-rays) - 46s linear infinite, top
   right, behind the copy, spin on the img and fade on the wrapper - so the two
   courses stay one course.

   It uses the module's OWN assets/mim/mark-rays.png, which is the same mark as
   the supplied MIM_Rays_V2.png and is already in every module's asset tree.
   Shipping the supplied file would have added 820 KB to fifteen modules to
   draw a picture they already have.

   The siblings are lifted to z-index 1 rather than the starburst being pushed
   below 0, because a negative z-index on a positioned child can slide behind
   the screen's own painted background and vanish entirely. */
/* The column has to become a positioning context, and only on the screens that
   actually carry a starburst - .screen-inner is static everywhere by design and
   making all of them relative would change stacking on 545 screens in order to
   decorate five. data-starburst is put on the section by tools/v2-round4.js.

   The siblings are lifted to z-index 1 rather than the starburst being pushed
   to -1: a negative z-index on a positioned child can slide behind the screen's
   own painted background and disappear completely. */
.screen[data-starburst] .screen-inner { position: relative; }
.screen[data-starburst] .screen-inner > *:not(.mim-starburst) { position: relative; z-index: 1; }

.mim-starburst {
  position: absolute;
  top: -60px;
  right: -80px;
  width: clamp(200px, 30vw, 420px);
  aspect-ratio: 1;
  opacity: 0;
  pointer-events: none;
  animation: mimStarburstIn 900ms var(--ease-standard) 240ms forwards;
}
.mim-starburst img { width: 100%; height: 100%; display: block; animation: mimStarburstSpin 46s linear infinite; }
@keyframes mimStarburstIn { to { opacity: 0.30; } }
@keyframes mimStarburstSpin { from { rotate: 0deg; } to { rotate: 360deg; } }
body.night-mode .mim-starburst { animation: mimStarburstInNight 900ms var(--ease-standard) 240ms forwards; }
@keyframes mimStarburstInNight { to { opacity: 0.22; } }
@media (max-width: 700px) { .mim-starburst { top: -70px; right: -90px; } }
@media (prefers-reduced-motion: reduce) {
  .mim-starburst { opacity: 0.26; animation: none !important; }
  .mim-starburst img { animation: none !important; }
  body.night-mode .mim-starburst { opacity: 0.22; animation: none !important; }
}
body.reduced-motion .mim-starburst { opacity: 0.26; animation: none !important; }
body.reduced-motion .mim-starburst img { animation: none !important; }


/* ── 9. THE ARROW ARCH ────────────────────────────────────────────────────
   "animate in MIM_Arrow-Arch_V1 under 'These are different problems that
   require different responses.'"

   Added by step 10 of the generator, immediately after that sentence, from the
   module's own assets/mim/mark-arrow-arch.png. It draws itself in the way an
   arch is drawn - left to right, rising - and it is decorative, so it is
   aria-hidden and adds nothing for a screen reader to read out. */
.mim-archin {
  display: block;
  width: clamp(160px, 26vw, 300px);
  height: auto;
  margin: var(--sp-5) 0 var(--sp-4);
}
.screen.active .mim-archin {
  animation: mimArchIn 880ms var(--ease-standard) 220ms both;
}
@keyframes mimArchIn {
  from { opacity: 0; clip-path: inset(0 100% 0 0); translate: 0 8px; }
  to   { opacity: 1; clip-path: inset(0 0 0 0);    translate: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .screen.active .mim-archin { animation: none !important; opacity: 1 !important; clip-path: none !important; translate: none !important; }
}
body.reduced-motion .screen.active .mim-archin {
  animation: none !important; opacity: 1 !important; clip-path: none !important; translate: none !important;
}


/* ── 10. A PURPLE MOUSTACHE ON EVERY ACCORDION ────────────────────────────
   Tom, 15 Sep 2026: "for the accordion buttons throughout the entire suite of
   modules - i'd like to implement a purple moustache on the left hand side the
   same as how a black one appears in the Moustaches Love Research boxes."

   That black one is `.evidence__mo`: 44x28, the --img-mo-mark token drawn as a
   background image. An SVG loaded as a background CANNOT be recoloured, so this
   uses the same token as a MASK and paints purple through it. Same artwork,
   same token, one colour different - rather than a second purple moustache file
   that would have to be kept in step with the first.

   ⚠ THE SPACER IT REPLACES WAS LOAD-BEARING. The engine's promoted FAQ block
   puts `content: ""; flex: 0 0 22px` here purely to mirror the 22px toggle on
   the right, so the centred question centres on the CARD rather than on
   whatever the toggle left over. Widening the left to 44px without widening the
   right would shift every question 11px off centre. So the toggle matches. */
.accordion__summary::before {
  content: "";
  flex: 0 0 44px;
  height: 28px;
  background-color: var(--mim-purple);
  -webkit-mask: var(--img-mo-mark) left center / contain no-repeat;
  mask: var(--img-mo-mark) left center / contain no-repeat;
}
.accordion__toggle { flex: 0 0 44px; }

/* Night mode: the purple has to lift off a near-black card, and the engine's
   own night rules never touch a mask. */
body.night-mode .accordion__summary::before { background-color: #cdbcff; }

/* A feedback accordion is a different component that happens to share the
   class - it is a single tinted panel with its own left rule, not a question in
   a card - so it keeps its spacer and takes no moustache. MIM Pro has none of
   these today; the rule is here so that promoting one later does not quietly
   grow a moustache. */
.accordion--feedback .accordion__summary::before {
  background: none;
  -webkit-mask: none;
  mask: none;
  flex-basis: 0;
}

@media (max-width: 600px) {
  .accordion__summary::before { flex-basis: 32px; height: 20px; }
  .accordion__toggle { flex: 0 0 32px; }
}


/* ── 11. THE STARBURST ON A SCREEN WITH NO INNER COLUMN ───────────────────
   Six of the 68 multiple-choice screens - all in Part 2s - have no
   .screen-inner at all; their children hang directly off the screen. Those are
   marked data-starburst-bare by tools/v2-round4.js and the screen itself
   becomes the positioning context.

   ⚠ Scoped to those six and no further. `.screen` is position: static
   everywhere by design, and a child with `inset: 0` resolves against the
   VIEWPORT because of it - which is a real layout that exists in this course.
   Making every screen relative would silently move any such child. These six
   were checked for absolutely-positioned children first; none has one. */
.screen[data-starburst-bare] { position: relative; }
.screen[data-starburst-bare] > *:not(.mim-starburst) { position: relative; z-index: 1; }


/* ── 12. A VIDEO SCREEN WITH BODY COPY WAS PINNED TO THE LEFT EDGE ────────
   Tom, 19 Sep 2026, on Part 2 screen 12: "has a broken look. All the content
   is now left aligned. This has happened before."

   Measured across all fifteen previews at 1440px: three screens sit with a
   72px left gutter against a 668px right one, while every other video screen
   in the same modules measures L360 R360. The three are Part 2 screen 12 in
   GPs, GPs (ACRRM) and HCP - the same content in the three streams that carry
   it.

   THE CAUSE IS ONE TOKEN MEANING TWO DIFFERENT THINGS.

     .screen-inner:has(.body),
     .content-wrap:has(.body),
     .video-screen:has(.body) { --video-w: var(--measure); --video-ml: 0; }

   For the first two that rule is exactly right: those wrappers are themselves
   CENTRED columns, so `margin-left: 0` lines the video up with the paragraph
   beside it, which is the 2026-07-03 rule it exists to serve.

   `.video-screen` is a different box. It is deliberately FULL-BLEED -
   `max-width: none` a few lines further down - because on a dedicated video
   screen the STACK owns the measure and every child lines up on --video-w. So
   on that selector `margin-left: 0` does not mean "align with the text", it
   means "the left edge of the viewport", and the whole column slams left with
   700px of dead space beside it.

   The fix keeps the part that was intended and drops the part that was not:
   the column still narrows to the text measure, so the video never out-sizes
   the copy it sits with, but it stays CENTRED like every other video screen.
   Only --video-ml is overridden; --video-w is left alone.

   ⚠ IT IS NOT ONLY `.video-screen`. Fixing that selector alone moved the video
   and left the words behind, which is worse than the bug. The intro block is
   `div.video-screen__intro.content-wrap`, so it matches
   `.content-wrap:has(.body)` from the SAME rule and takes --video-ml: 0 of its
   own, and its children inherit it. Inside a video screen that wrapper is ALSO
   full-bleed, because `.screen[data-type="video"] .content-wrap` sets
   max-width: none a few lines below. So every wrapper this applies to inside a
   video screen has the same problem, and the fix has to name all of them.

   The real condition is "the wrapper has been made full-bleed", which CSS
   cannot ask. Inside a video screen it is always true, so that is what is
   selected on.

   ⚠ THIS IS NOT A v2 REGRESSION. The live entry files measure identically -
   index.html screen-14 is the same content and the same L72/R668 - so it is in
   the shipped course today and has been since the rule was written. It is
   fixed here rather than in the engine because that is where this release
   keeps its changes; promoting v2 carries the fix to the live files with
   everything else. */
/* ── SUPERSEDED 21 Sep 2026 ────────────────────────────────────
   Tom: "Some of the videos and the text boxes are misaligned. A good example is
   Pharmacy M1S19." Measured across the suite: 52 of 70 video screens had the
   video off the copy's left edge - 700 or 720 wide and CENTRED inside a 772
   content column, so a 26 or 36px step.

   Centring was this rule's own doing, and it was the right answer to the
   question it was asked in v2.8: `--video-ml: 0` pinned the video to the left
   edge of a FULL-BLEED wrapper rather than to the text, so the words and the
   video drifted apart on the MALE framework screen.

   ⚠ THE REAL FAULT WAS THE WIDTH, NOT THE MARGIN. The engine's own rule says a
   video sharing a slide with copy should "match the TEXT measure", and sets
   --video-w to var(--measure), 700px. But the body copy is NOT capped at the
   measure - it runs the full 772 of the content column - so the video was being
   matched to a width the text does not use, and then had to be centred or
   pinned, neither of which lines up.

   Filling the container settles both at once: the video takes exactly the box
   its copy takes, so it shares the left edge AND the right edge, and centred
   versus left-aligned stops meaning anything. Part 2's narrower .content-wrap
   is served by the same rule, because 100% is of whatever holds it.

   The transcript, the controls and the toggle all read --video-w from the same
   place, so they follow and stay matched to the video (qa-video-widths). */
.video-screen:has(.body),
.video-screen .content-wrap:has(.body),
.video-screen .screen-inner:has(.body),
.screen[data-type="video"] .content-wrap:has(.body),
.screen[data-type="video"] .screen-inner:has(.body),
.screen-inner:has(.body),
.content-wrap:has(.body),
/* and the screens whose copy is a HEADING rather than a paragraph - the
   "hear it from him" tiles and the part dividers. Measured: they were the whole
   of the remaining 35, all 720 wide and centred against 772 of copy. */
.screen-inner:has(.title, .heading, .section-lead, .eyebrow),
.content-wrap:has(.title, .heading, .section-lead, .eyebrow) { --video-w: 100%; --video-ml: 0; }


/* ═══════════════════════════════════════════════════════════════════════
   v2.10 — RACGP Module 2, Tom's round of 20 September 2026.

   The markup half is tools/v2-round5.js. Everything here is paint, and every
   rule is scoped to a marker that round 5 put on the section, so nothing
   leaks onto a screen Tom was not describing.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── S7 · "Azhaan" animates in, in purple ─────────────────────────────── */
.name-in {
  color: var(--mim-purple);
  display: inline-block;
  opacity: 0;
  animation: nameIn 620ms var(--ease-standard) 420ms both;
}
@keyframes nameIn {
  from { opacity: 0; transform: translateY(0.18em); }
  to   { opacity: 1; transform: translateY(0); }
}
/* Never leave a name invisible for someone who has asked for less motion. */
@media (prefers-reduced-motion: reduce) { .name-in { opacity: 1; animation: none; } }
body.reduced-motion .name-in { opacity: 1; animation: none; }

/* ── S7 / S25 · a photograph behind the video poster ──────────────────────
   The poster is the panel that covers the player until you press play.

   ⚠ THE PLAY CONTROL IS CENTRED AND ENGINE-WIDE, so "make sure the play
   button doesn't cover his face" is solved by moving the PICTURE, not the
   control: object-position pulls the frame so the subject sits off-centre and
   the control lands on background rather than on him. Moving the control
   instead would have changed every video screen in every course. */
/* ⚠ THE POSTER IS CONTENT-SIZED, and the photograph is absolutely positioned,
   so it contributes no height. On S7, where Tom asked for the copy to come
   off, hiding the copy collapsed the poster from 278px to 72px and the picture
   with it. The frame behind it is 720x405, so the poster is given that ratio
   outright: it now fills the box it is covering, with or without copy. */
[data-poster-photo] {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
/* ⚠ THIS USED TO BLOW THE PICTURE UP TO 150% AND SHOVE IT LEFT. Tom, 21 Sep:
   "The Tom and David video portrait is too compressed, cutting off quite a bit
   of their faces." Measured across the suite: every one of the 34 tiles carrying
   a chosen photograph rendered it 1080px wide inside a 720px tile and threw away
   33% of its height - 44% for the two that were still 3:2.

   The 150% and the translate were written for ONE tile: S7, where the picture
   was 3:2 in a 16:9 frame and the centred play control landed on Azhaan's face.
   Widening bought horizontal room and the shift carried him clear. Both reasons
   are now gone: every one of these stills is cut to 16:9 on disk, so there is
   nothing to make up, and the play control is moved off centre below instead.

   So the picture simply fills its tile: same ratio, same box, nothing discarded. */
.poster-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* the engine's img { max-width: 100% } would otherwise clamp this */
  max-width: none;
  object-fit: cover;
  object-position: 50% 50%;
  z-index: 0;
}

/* The play control on a tile that has NO caption strip - the screens about one
   man, where the copy is deliberately hidden. It is centred by the engine, which
   puts it squarely on the subject's face now that the picture is no longer
   shifted sideways. It goes to the bottom left, clear of a centred head, and
   takes the same purple disc as the one in the strip so the two read as one
   control in two places. */
[data-poster-photo]:not([data-poster-photo="keep"]) .video-poster__play {
  position: absolute;
  left: clamp(16px, 3%, 28px);
  bottom: clamp(16px, 3%, 28px);
  z-index: 3;
  width: 72px; height: 72px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 2px solid var(--mim-purple);
  background: var(--mim-purple);
  transition: transform 220ms var(--ease-standard),
              background-color 220ms var(--ease-standard),
              border-color 220ms var(--ease-standard);
}
[data-poster-photo]:not([data-poster-photo="keep"]) .video-poster__play::after {
  content: ""; position: absolute; inset: -2px;
  border-radius: 50%; border: 2px solid var(--mim-purple);
  animation: vpPlayPulse 2600ms ease-out infinite;
  pointer-events: none;
}
[data-poster-photo]:not([data-poster-photo="keep"]) .video-poster__play svg {
  width: 30px; height: 30px; fill: #000; margin-left: 4px;
}
[data-poster-photo]:not([data-poster-photo="keep"]):hover .video-poster__play {
  transform: scale(1.06); background: #fff; border-color: #fff;
}
@media (prefers-reduced-motion: reduce) {
  [data-poster-photo]:not([data-poster-photo="keep"]) .video-poster__play::after { animation: none; opacity: 0; }
}
body.reduced-motion [data-poster-photo]:not([data-poster-photo="keep"]) .video-poster__play::after { animation: none; opacity: 0; }

/* A scrim, so white copy and the play control stay legible on a photograph
   whose brightness we do not control. */
[data-poster-photo]::before {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0.45) 0%, rgba(0,0,0,0.30) 45%, rgba(0,0,0,0.55) 100%);
  pointer-events: none;
}
[data-poster-photo] > *:not(.poster-photo) { position: relative; z-index: 1; }

/* S7: the copy comes off the poster entirely. It is hidden rather than deleted
   in round 5 because it is the module's own authored text and the live entry
   file still carries it - this is a preview-layer change, and a deletion in
   the generator would be a change to what the course says. */
[data-poster-photo]:not([data-poster-photo="keep"]) .video-poster__instruct,
[data-poster-photo]:not([data-poster-photo="keep"]) .video-poster__cue { display: none; }

/* ── S15 · the headline word inks in, white to black ──────────────────────
   Tom: "instead of animating in the purple splash, animate the text itself
   converting from white to black."

   The highlighter stroke stays put - it is what makes black text legible on
   that panel - and stops being the thing that moves. .ap-hl::before is the
   stroke; only the word's colour is animated now. */
[data-ink-in] .ap-hl {
  color: var(--mim-white);
  animation: inkIn 900ms var(--ease-standard) 600ms both;
}
[data-ink-in] .ap-hl::before { animation: none; opacity: 1; }
/* ⚠ IT ENDS ON PURPLE, NOT BLACK. Tom, 20 Sep, asked for "the text itself
   converting from white to black" in place of a purple splash; on 21 Sep, of
   the same effect: "the practical tools animates the word anxiety as black, but
   it's on a dark screen. Change it to purple."

   Both are right, and the second supersedes the first, because EVERY .ap-hl in
   the suite sits inside an .ap-frame - checked, all 32 of them - which is a
   photograph under a scrim. Black on that is very nearly invisible; the word
   was there and unreadable. Purple carries the same "inks in" idea and is the
   accent the rest of the screen already uses. */
@keyframes inkIn {
  from { color: var(--mim-white); }
  to   { color: var(--mim-purple); }
}
/* ⚠ Reduced motion lands on the END state, not the start. Stopping at white
   would leave the word unreadable against its own highlighter, which is worse
   than the animation it is replacing. */
@media (prefers-reduced-motion: reduce) {
  [data-ink-in] .ap-hl { animation: none; color: var(--mim-purple); }
}
body.reduced-motion [data-ink-in] .ap-hl { animation: none; color: var(--mim-purple); }

/* ── S27 · bigger copy, and the MIM Zig Zag ───────────────────────────────
   A NAMED EFFECT, per Tom: "We'll make this a new effect called MIM Zig Zag."
   Marked on the section so it can be reused by name rather than copied. */
/* S27 has no .body class - its copy is plain <p> inside .content-wrap, with
   the kicker carrying .eyebrow. Targeting .body changed nothing and read, in
   the diff, exactly like it had worked. */
[data-zigzag] .content-wrap > p:not(.eyebrow) { font-size: calc(var(--fs-body) * 1.18); line-height: 1.5; }

.mim-zigzag {
  max-width: var(--measure);
  margin: var(--sp-3) 0 var(--sp-5);
  overflow: hidden;
}
.mim-zigzag img {
  display: block;
  width: min(360px, 62%);
  height: auto;
  /* Drawn on, left to right, by revealing the artwork rather than by moving
     it: a transform here would be replaced wholesale by the animation and is
     the trap that cost the figure float a whole round. */
  clip-path: inset(0 100% 0 0);
  animation: zigZagDraw 900ms var(--ease-standard) 350ms both;
}
@keyframes zigZagDraw {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}
@media (prefers-reduced-motion: reduce) {
  .mim-zigzag img { animation: none; clip-path: inset(0 0 0 0); }
}
body.reduced-motion .mim-zigzag img { animation: none; clip-path: inset(0 0 0 0); }

/* ── S28 · the reflections review opens in the top right ──────────────────
   Tom: "the review exporting reflections should pop up in the top right hand
   corner."

   It was a full-viewport modal: a fixed 50%-black scrim with the panel laid
   out in the middle of it, measured at 720x139 sitting low on the screen. As a
   corner popup it stops being a modal, so the scrim goes transparent rather
   than being removed - the element is what closes the panel when you click
   away, and deleting it would take the dismissal with it.

   Pinned below the module header rather than to the very top, so it does not
   sit under the chrome, and capped in height so a long set of reflections
   scrolls inside the popup instead of running off the screen. */
.reflections-viewer { background: transparent; }
.reflections-viewer__panel {
  position: fixed;
  top: 88px;
  right: 24px;
  left: auto;
  margin: 0;
  width: min(460px, calc(100vw - 48px));
  max-height: calc(100vh - 140px);
  overflow-y: auto;
  box-shadow: var(--depth-2);
}
@media (max-width: 640px) {
  /* No corner worth speaking of on a phone: full width under the header. */
  .reflections-viewer__panel { right: 12px; left: 12px; width: auto; top: 76px; }
}


/* ═══════════════════════════════════════════════════════════════════════
   v2.11 — the rotating portraits, 20 September 2026.

   Two places, one mechanic. The markup half is in tools/v2-round5.js.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── The lived-experience video tile, from Tom's "LE Tiles" artboard ────
   Tom, 21 Sep 2026: "I've improved upon it in claude design... apply the new
   design, but maintain the changing pictures. That said, let's leave
   happy10.jpg out of the potential options as he doesn't look particularly
   happy."

   Read off export-1c/Video Screen.dc.html. Four things change from the 20 Sep
   version, and the first is the point of the whole round:

     1. THE CAPTION COMES OFF THE PICTURE. It was a bar laid over the bottom of
        the photograph; it is now a solid strip UNDERNEATH it. Nothing is over
        the photograph at all any more.
     2. A purple rule is drawn round the tile once, and a short white dash then
        traces round it continuously.
     3. The play control is a filled purple disc with a black glyph and a ring
        that pulses out of it, rather than a white-on-shadow button.
     4. The picture is graded and sits under a 24% scrim.

   NINE photographs, not ten. */

/* ⚠ THE FRAME IS A HARD 16:9 WITH overflow:hidden, so a strip under the
   picture is simply clipped away - which is why the caption was overlaid in the
   first place. The generator marks the frame and it grows to its content here.

   The ::before is a 16:9 FLOOR, not decoration. The engine hides the poster on
   play (poster.style.display = 'none') and the iframe it swaps in is
   position:absolute, so it contributes no height: without a floor the frame
   would collapse to nothing the moment anyone pressed play. A zero-width float
   inside the frame's existing block formatting context sets that floor and
   holds no space of its own. */
.video-frame[data-happy-frame],
.video-player-wrap[data-happy-frame] {
  aspect-ratio: auto;
  border-radius: 0;            /* the artboard's tile is square, and the rule drawn round it is too */
  background: #0b1519;
}
.video-frame[data-happy-frame]::before,
.video-player-wrap[data-happy-frame]::before {
  content: ""; float: left; width: 0; padding-top: 56.25%;
}
.video-frame[data-happy-frame] > .video-poster,
.video-player-wrap[data-happy-frame] > .video-poster {
  position: relative; inset: auto;
  display: block; height: auto;
  background: #0b1519;
  /* the engine's .video-poster--styled adds `padding: 0 clamp(24px, 6vw, 80px)`
     to centre big serif copy over a dark plate. Measured: 76.8px a side at
     1280, which held the picture to 564 of the frame's 718 and inset the strip
     with it. The artboard's tile is edge to edge. */
  padding: 0;
  /* ⚠ AND THE POSTER'S OWN 16:9 HAS TO GO, for the three tiles that carry a
     chosen photograph: round 5's `[data-poster-photo]` rule puts aspect-ratio
     16/9 and overflow:hidden on the POSTER, so the strip was laid out below a
     locked 405px box and clipped straight off. Those three measured 405 tall
     against the 517 they needed while every reel tile was correct. */
  aspect-ratio: auto;
  overflow: visible;
}

/* The picture. A 16:9 window, exactly the ratio the wide crops were cut to.
   (The artboard sets object-position: 52% 34% for its own poster.jpg; with the
   crop and the window at the same ratio there is no overflow to position, so it
   would do nothing here. Omitted rather than copied as a no-op.) */
.vp-stage { position: relative; aspect-ratio: 16 / 9; overflow: hidden; }
.vp-stage::after {
  content: ""; position: absolute; inset: 0;
  background: rgba(0,0,0,0.24); pointer-events: none;
}
.happy-reel { position: absolute; inset: 0; }
.happy-reel img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  /* the engine's img { max-width: 100% } clamps this otherwise - the same rule
     that caught the S7 poster and, before that, the survey portrait */
  max-width: none;
  object-fit: cover;
  filter: saturate(0.82) contrast(1.06);
  opacity: 0;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-delay: calc(var(--i) * 3s);
}

/* ⚠ THE CROSS-FADE PERCENTAGES ARE COMPUTED FROM THE NUMBER OF PICTURES, so a
   set of a different size needs its own pair. Three seconds a picture in every
   case; one turn is 3s/total and the cross-fade is 0.45s of that. Get this
   wrong and the reel shows a black gap once a lap, which is what nine pictures
   on the ten-picture keyframes did.

   The sets: nine lived-experience portraits, three pharmacy experts, two GP or
   nursing experts, and Dr Zac on his own - Tom: "just use this static image". */
.happy-reel[data-n="9"] img { animation-name: reel9; animation-duration: 27s; }
.happy-reel[data-n="3"] img { animation-name: reel3; animation-duration: 9s; }
.happy-reel[data-n="2"] img { animation-name: reel2; animation-duration: 6s; }
.happy-reel[data-n="1"] img { animation: none; opacity: 1; }

@keyframes reel9 {   /* 3/27 = 11.111%, fade 1.667% */
  0%      { opacity: 0; }
  1.667%  { opacity: 1; }
  11.111% { opacity: 1; }
  12.778% { opacity: 0; }
  100%    { opacity: 0; }
}
@keyframes reel3 {   /* 3/9 = 33.333%, fade 5% */
  0%      { opacity: 0; }
  5%      { opacity: 1; }
  33.333% { opacity: 1; }
  38.333% { opacity: 0; }
  100%    { opacity: 0; }
}
@keyframes reel2 {   /* 3/6 = 50%, fade 7.5% */
  0%    { opacity: 0; }
  7.5%  { opacity: 1; }
  50%   { opacity: 1; }
  57.5% { opacity: 0; }
  100%  { opacity: 0; }
}


/* The purple rule round the tile, and the white light that travels it.

   ⚠ THE ARTBOARD DRAWS THIS AS AN SVG RECT WITH A STROKE DASH AND IT CANNOT BE
   COPIED. Its dash numbers (2648) are the perimeter of its own 820x508 box, so
   they under- or over-draw at any other size, and stretching the viewBox to fit
   the tile distorts where along the path the dashes land. Measured: three stray
   flecks on the edges instead of a rule. pathLength and vector-effect fix the
   total and the stroke width, not the distribution.

   So the rule is a real border wiped in with clip-path, and the light is four
   edge elements each running a moving gradient in turn. Both are exact at every
   tile size, and neither depends on masks or :has(). */
/* ⚠ .video-poster .vp-rule, not a bare .vp-rule. On the three tiles that carry
   a chosen photograph, round 5's
   `[data-poster-photo] > *:not(.poster-photo) { position: relative }` (0,2,0)
   out-ranks a single class and pulled the rule INTO THE FLOW - an empty div
   with a 2px border, so those three grew a 4px stripe above the picture and had
   no rule round them at all. Equal specificity, later in the file, wins it back. */
.video-poster .vp-rule {
  position: absolute; inset: 0; z-index: 2;
  pointer-events: none;
  border: 2px solid rgba(183, 163, 252, 0.45);   /* --mim-purple at the artboard's 0.45 */
  animation: vpRuleDraw 1600ms cubic-bezier(0.2, 0.7, 0.2, 1) 600ms both;
}
@keyframes vpRuleDraw {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

/* One light, handed from edge to edge. Each edge holds it for a quarter of the
   5200ms lap and is invisible for the other three quarters. */
.vp-rule span {
  position: absolute; opacity: 0;
  background-repeat: no-repeat;
  animation-duration: 5200ms;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.vp-rule__t, .vp-rule__b {
  left: 0; right: 0; height: 2px;
  background-image: linear-gradient(90deg, transparent, #fff, transparent);
  background-size: 18% 100%;
}
.vp-rule__r, .vp-rule__l {
  top: 0; bottom: 0; width: 2px;
  background-image: linear-gradient(180deg, transparent, #fff, transparent);
  background-size: 100% 18%;
}
.vp-rule__t { top: -2px;    animation-name: vpTraceR; animation-delay: 2200ms; }
.vp-rule__r { right: -2px;  animation-name: vpTraceD; animation-delay: 3500ms; }
.vp-rule__b { bottom: -2px; animation-name: vpTraceL; animation-delay: 4800ms; }
.vp-rule__l { left: -2px;   animation-name: vpTraceU; animation-delay: 6100ms; }

@keyframes vpTraceR {          /* left to right along a horizontal edge */
  0%      { opacity: 1; background-position: -20% 0; }
  25%     { opacity: 1; background-position: 120% 0; }
  25.01%, 100% { opacity: 0; background-position: 120% 0; }
}
@keyframes vpTraceD {          /* top to bottom down a vertical edge */
  0%      { opacity: 1; background-position: 0 -20%; }
  25%     { opacity: 1; background-position: 0 120%; }
  25.01%, 100% { opacity: 0; background-position: 0 120%; }
}
@keyframes vpTraceL {          /* right to left */
  0%      { opacity: 1; background-position: 120% 0; }
  25%     { opacity: 1; background-position: -20% 0; }
  25.01%, 100% { opacity: 0; background-position: -20% 0; }
}
@keyframes vpTraceU {          /* bottom to top */
  0%      { opacity: 1; background-position: 0 120%; }
  25%     { opacity: 1; background-position: 0 -20%; }
  25.01%, 100% { opacity: 0; background-position: 0 -20%; }
}

/* The caption strip. Solid, under the picture, never over it. */
.video-poster .vp-box {
  position: relative;
  z-index: 1;
  display: flex; flex-direction: row; align-items: center;
  justify-content: space-between; gap: 28px;
  width: auto; margin: 0;
  padding: 20px 26px;
  background: #0D0D0D;
  border-radius: 0;
  text-align: left;
}
.video-poster .vp-box .video-poster__instruct {
  margin: 0;
  flex: 1 1 auto;
  max-width: 62ch;
  color: #E8E8E8;
  font-family: var(--font-primary);
  font-weight: 300;
  /* the artboard hard-codes 16px; every size in this estate is scaled, or the
     text-size control silently stops working on this one component */
  font-size: calc(16px * var(--fs-scale));
  line-height: 1.45;
  /* the engine's .video-poster--styled .video-poster__instruct sets
     text-align: center ON THE ELEMENT, so inheriting left from .vp-box
     never reached it and the caption rendered centred. */
  text-align: left;
}

/* The play control: a filled purple disc with a black glyph, and a ring that
   pulses out of it. */
.video-poster .vp-box .video-poster__play {
  position: relative;
  flex: 0 0 auto;
  width: 72px; height: 72px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 2px solid var(--mim-purple);
  background: var(--mim-purple);
  box-shadow: none;
  transition: transform 220ms var(--ease-standard),
              background-color 220ms var(--ease-standard),
              border-color 220ms var(--ease-standard);
}
.video-poster .vp-box .video-poster__play::after {
  content: ""; position: absolute; inset: -2px;
  border-radius: 50%; border: 2px solid var(--mim-purple);
  animation: vpPlayPulse 2600ms ease-out infinite;
  pointer-events: none;
}
.video-poster .vp-box .video-poster__play svg { width: 30px; height: 30px; fill: #000; margin-left: 4px; }
.video-poster:hover .vp-box .video-poster__play {
  transform: scale(1.06);
  background: #fff; border-color: #fff;
}
@keyframes vpPlayPulse {
  0%, 100% { transform: scale(1);    opacity: 0.5; }
  50%      { transform: scale(1.22); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .happy-reel img { animation: none; }
  .happy-reel img:first-child { opacity: 1; }
  .vp-rule { animation: none; clip-path: none; }
  .vp-rule span { animation: none; opacity: 0; }
  .video-poster .vp-box .video-poster__play::after { animation: none; opacity: 0; }
  .video-poster:hover .vp-box .video-poster__play { transform: none; }
}
body.reduced-motion .happy-reel img { animation: none; }
body.reduced-motion .happy-reel img:first-child { opacity: 1; }
body.reduced-motion .vp-rule { animation: none; clip-path: none; }
body.reduced-motion .vp-rule span { animation: none; opacity: 0; }
body.reduced-motion .video-poster .vp-box .video-poster__play::after { animation: none; opacity: 0; }

/* ── The learning-outcomes screen, from the Claude Design artboard ────────
   Tom: "Replace the design of the learning outcomes with the one I created in
   claude design... The copy MUST stay the same as it currently is in the
   module."

   So no copy is touched anywhere below. The 01-05 numbering is a CSS counter
   rather than typed text, which is what makes that possible: the module's <ul>
   keeps its five <li> exactly as authored and the numbers are drawn.

   ⚠ THE FACES ARE PRE-CROPPED, NOT object-position'd. Head height across the
   ten source frames runs from 0.14 to 0.55 of the frame - a near-4x spread -
   and no single CSS crop can normalise that. They are cut to a common head
   size on disk; see the header of scratchpad normalise_faces.py for why it is
   ten measured numbers rather than a face model. */
/* ⚠ THE PANEL SHAPE IS WHY THE FACES WERE CUT. Tom: "the photos of the gents
   on the learning outcomes slides are far too zoomed in on some of them -
   cutting off part of their faces." Measured: the band is 210px tall, so each
   of the five panels is 278x210, a 1.33 LANDSCAPE box - and the crops are 0.75
   PORTRAIT. object-fit: cover then scales to the width and throws away 44% of
   the height, straight through foreheads and chins.

   The artboard's strip is clamp(240px, 40vh, 420px), which at a normal viewport
   makes each panel about 278x400, a 0.70 ratio against the crops' 0.75. Taking
   the artboard's height is both the faithful port and the fix: almost nothing
   is cropped. */
.lo-band[data-happy] {
  display: flex;
  gap: 2px;
  overflow: hidden;
  height: clamp(240px, 40vh, 420px);
}
.lo-band[data-happy] .lo-portrait {
  position: relative;
  flex: 1 1 0;
  height: 100%;
  overflow: hidden;
  background: #0b1519;
}
.lo-band[data-happy] .lo-portrait img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  max-width: none;
  object-fit: cover;
  filter: contrast(1.04) saturate(0.9);
  opacity: 0;
  /* Staggered by panel so the strip is never all changing at once, which is
     what makes it read as alive rather than as a slideshow. */
  /* ⚠ NEGATIVE delays, so every panel is already mid-cycle at load. A positive
     stagger left panels 3, 4 and 5 blank for their first few seconds, and the
     first render of the strip showed two photographs and three dark boxes. */
  /* Tom, 21 Sep: every panel now cycles all NINE of his re-framed portraits,
     eight seconds each, so a panel still changes at the pace it did when it
     held two and traded every eight.

     THE PANEL STAGGER IS WHAT KEEPS A FACE OFF THE STRIP TWICE AT ONCE. Panel i
     reaches picture j at t = 8j + 1.6i, so two panels can only coincide if i is
     the same, and no two are. Five panels of two was ten slots against nine
     pictures, so one had to repeat - and the repeat was visible: panels 1 and 5
     would have shown the same man together for six seconds of every sixteen. */
  animation: loSwap 72s linear infinite;
  animation-delay: calc(var(--j) * -8s - var(--i) * 1.6s);
}
/* Nine pictures over 72s: one turn is 8/72 = 11.111%, and the 0.8s cross-fade
   is 1.111%. Both are computed from the count - LO_N in tools/v2-round5.js. */
@keyframes loSwap {
  0%      { opacity: 0; }
  1.111%  { opacity: 1; }
  11.111% { opacity: 1; }
  12.222% { opacity: 0; }
  100%    { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .lo-band[data-happy] .lo-portrait img { animation: none; opacity: 0; }
  .lo-band[data-happy] .lo-portrait img:first-child { opacity: 1; }
}
body.reduced-motion .lo-band[data-happy] .lo-portrait img { animation: none; opacity: 0; }
body.reduced-motion .lo-band[data-happy] .lo-portrait img:first-child { opacity: 1; }

/* A 2px purple rule under the strip, drawn on from the left - the artboard's. */
.lo-band[data-happy]::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--mim-purple);
  transform-origin: left center;
  animation: mimRule 900ms cubic-bezier(0.2,0.7,0.2,1) 700ms both;
}
.lo-band[data-happy] { position: relative; }
@keyframes mimRule { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* The outcomes list: the artboard's numbered three-column grid. */
/* ⚠ THE SCREEN HAS TWO <ul class="lo-list">, NOT ONE. Putting the grid and the
   counter on the list gave two independent grids and restarted the numbering at
   01 on the second - the render showed 01 02 03 then 01 02. The wrap owns both,
   so it owns the grid and the counter, and the lists step out of the way with
   display: contents so all five <li> land in one grid. */
.screen--lo .lo-list-wrap {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: 28px 56px;
  counter-reset: lo;
}
.screen--lo .lo-list {
  display: contents;
  list-style: none;
  margin: 0; padding: 0;
}
.screen--lo .lo-list li {
  counter-increment: lo;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 18px;
  align-items: start;
  border-top: 1px solid rgba(255,255,255,0.16);
  padding: 16px 0 0;
  margin: 0;
  max-width: none;
}
/* ⚠ position: static IS THE LOAD-BEARING LINE. The module's own rule draws the
   purple chevron with `position: absolute; left: 0`, and this ::before INHERITS
   that declaration - only `content` is being replaced. Left absolute, every
   number sat on top of the first word of its own outcome. */
.screen--lo .lo-list li::before {
  content: counter(lo, decimal-leading-zero);
  position: static;
  width: auto; height: auto;
  background: none;
  font-family: var(--font-feature, 'Lora', Georgia, serif);
  font-size: 22px; line-height: 1.3;
  color: var(--mim-purple);
}
body.night-mode .screen--lo .lo-list li::before {
  position: static; width: auto; height: auto;
  background: none; background-color: transparent;
  color: var(--mim-purple);
}
/* The authored chevron marker is replaced by the number, not stacked with it. */
.screen--lo .lo-list li::marker { content: none; }
.screen--lo .lo-leadin {
  display: flex; align-items: center; gap: 14px;
  font-size: 12px; font-weight: 600; letter-spacing: 0.16em;
  text-transform: uppercase; color: #fff;
}
.screen--lo .lo-leadin::after {
  content: ""; flex: 1; height: 1px; background: rgba(255,255,255,0.18);
}

/* MIM Sunlight now lives in the engine as a named effect - see
   mim-gp-shared.css. Only its USE is here, on the marked artwork. */

/* ── S17 · copy and artwork side by side ──────────────────────────────────
   Tom: "place MIM_Fetal-Position1 in a box next to this copy. Make sure the two
   side by side boxes does not overshoot the Pause for a Mo box below."

   Capped at var(--measure), which is what the reflect block below it uses, so
   the two line up by construction instead of by a number that would drift. The
   artwork is portrait and the copy is not, so the columns are weighted rather
   than even, and the pair stacks under 620px where two columns would squeeze
   the sentence into a ribbon. */
.split-art {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: clamp(18px, 3vw, 34px);
  align-items: stretch;
  max-width: var(--measure);
  margin: var(--sp-5) 0;
}
/* Tom, 21 Sep: "yes I meant a visible panel for S17". Both halves are real
   boxes now, on the card treatment the rest of the suite uses, rather than copy
   and artwork merely sitting beside each other. */
.split-art__copy,
.split-art__fig {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg, 16px);
  padding: clamp(18px, 2.4vw, 26px);
}
.split-art__copy { display: flex; align-items: center; }
.split-art__copy > .body:last-child { margin-bottom: 0; }
.split-art__fig { margin: 0; display: flex; justify-content: center; align-items: center; }
.split-art__fig img {
  width: 100%; max-width: 220px; height: auto; display: block;
}
@media (max-width: 620px) {
  .split-art { grid-template-columns: 1fr; }
  .split-art__fig img { max-width: 180px; }
}

/* ── S33 · the backpack fills with bricks ───────────────────────────
   Ported from MIM MH module 1, where Tom asked for "a constant stream of bricks
   that fall from the top of the screen and vanish into the backpack... Bricks
   should never appear over the red line."

   Everything here is a percentage of the stage, which is why it can be dropped
   into a 190px slot without re-tuning: the sky, the fall and the brick are all
   relative, and translateY on a span whose height IS the stage resolves against
   the stage, so the distance stays right at any size.

   ⚠ THE LIP IS THE PACK AGAIN, CLIPPED AND STACKED ON TOP. That is how a brick
   is guaranteed never to cross the front of the pack: not by timing the fall,
   but by painting the lip over it. The polygon is Tom's own from the Backpackv2
   handover, so this and MIM MH agree on where the mouth is. */
.bpkfall { position: relative; display: block; }
.bpkfall::before { content: ''; display: block; padding-top: 62%; }   /* the sky */
.bpkfall__pack { display: block; width: 100%; height: auto; position: relative; z-index: 0; }
.bpkfall__lip {
  position: absolute; left: 0; bottom: 0; width: 100%; height: auto;
  z-index: 2; pointer-events: none;
  clip-path: polygon(0% 44%, 8% 41%, 18% 48%, 28% 54%, 40% 58%, 52% 56%, 62% 49%, 70% 42%, 78% 37%, 100% 37%, 100% 100%, 0% 100%);
}
.bpkfall__brick {
  position: absolute; top: 0; left: var(--x, 20%);
  width: 21%; height: 100%;
  z-index: 1; pointer-events: none;
  animation: bpkFall var(--dur, 3.8s) linear var(--d, 0s) infinite;
}
.bpkfall__brick i {
  display: block; width: 100%; aspect-ratio: 815 / 730;
  background: url('../../../../_components/assets/v2-round5/backpack/brick-isometric.svg') center / contain no-repeat;
  transform: rotate(var(--r, 0deg));
  filter: drop-shadow(0 6px 10px rgba(0,0,0,0.16));
}
@keyframes bpkFall {
  0%   { transform: translateY(-16%); opacity: 0; }
  9%   { opacity: 1; }
  100% { transform: translateY(72%); opacity: 1; }
}
/* "this version will need to be smaller to fit the gap" - it takes the slot the
   still occupied, and the engine's img { max-width: 100% } does not reach a div,
   so the width is stated here. */
.accent-row .bpkfall { width: clamp(110px, 16vw, 190px); flex: 0 0 auto; }

/* Motion is the whole point of this graphic, so under reduced motion it stops
   rather than flickers: the bricks rest above the pack and it reads as a still
   of the same idea. */
@media (prefers-reduced-motion: reduce) {
  .bpkfall__brick { animation: none; transform: translateY(6%); }
  .bpkfall__brick:nth-of-type(even) { transform: translateY(22%); }
}
body.reduced-motion .bpkfall__brick { animation: none; transform: translateY(6%); }
body.reduced-motion .bpkfall__brick:nth-of-type(even) { transform: translateY(22%); }

/* ── S20 · the tick ────────────────────────────────────────────────────────
   Tom, 21 Sep: "replace the animated circle with MIM_Tick1 and have it animate
   in."

   ⚠ THIS HAS TO OUT-RANK THE FIGURE'S EXISTING ANIMATION. module.css already
   runs `.screen--note.anote-play .anote-figure { animation: anoteFade ... }`
   (0,3,0), and an animation shorthand REPLACES the property, so adding one here
   at lower specificity would simply lose. The extra attribute takes it to
   (0,4,0).

   It is drawn on rather than faded: the mark scales up from the left with a
   slight over-rotation that settles, which reads as a tick being made.

   ⚠ THE SUPPLIED FILE IS 320x270, against the 2560x2410 circle it replaces and
   a slot that ran to 340px. It is displayed at no more than 240px so it stays
   crisp; a larger export would let it fill the original slot. */
.screen--note.anote-play .anote-figure[data-tick] {
  animation: mimTickIn 760ms cubic-bezier(0.16, 1, 0.3, 1) 0.38s both;
  transform-origin: 18% 78%;
}
.anote-figure[data-tick] { width: clamp(110px, 18vw, 240px) !important; }
@keyframes mimTickIn {
  0%   { opacity: 0; transform: scale(0.42) rotate(-16deg); }
  60%  { opacity: 1; transform: scale(1.06) rotate(4deg); }
  100% { opacity: 1; transform: scale(1) rotate(0deg); }
}
@media (prefers-reduced-motion: reduce) {
  .screen--note.anote-play .anote-figure[data-tick] { animation: none; opacity: 1; transform: none; }
}
body.reduced-motion .screen--note.anote-play .anote-figure[data-tick] { animation: none; opacity: 1; transform: none; }

/* ── THE SAME BUTTON EVERYWHERE ─────────────────────────────────
   Tom, 21 Sep: "Make sure the buttons are the same across all the modules."

   Measured across all fifteen: .nav-btn itself is engine-owned and no module
   touches it, but every Part 2 authors its OWN .email-resources-btn on top of
   it (module.css:375) and its own !important .resources-select-all
   (module.css:523). The result on a Part 2 resources screen:

     .nav-btn--ghost   rendered BLACK like a primary, because the Part 2 block
                       sets its own background and colour - two buttons side by
                       side that are meant to read as primary and secondary
                       looked like two primaries
     font-size         12px against 13px everywhere else
     padding           12px 22px, and 8px 16px on select-all, against 12px 26px
     text-transform    uppercase, with 0.1em tracking, against sentence case

   These reset the properties Part 2 re-declares back to the engine's own
   values, using the engine's own tokens rather than copies of them, so
   .nav-btn / --primary / --ghost govern the look in every module. The Part 2
   rule is left in place rather than deleted: it is the live module's file, and
   this release changes the preview layer.

   ⚠ !important is needed on the select-all half ONLY because the Part 2 rule
   carries it; same specificity, later file, so this wins. */
.email-resources-btn.nav-btn {
  background: none;
  border-radius: var(--radius-pill);
  padding: 12px 26px;
  font-family: var(--font-primary);
  font-weight: var(--weight-semibold);
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: none;
}
.email-resources-btn.nav-btn--primary { background: var(--mim-black); color: var(--mim-white); border: none; }
.email-resources-btn.nav-btn--ghost {
  background: var(--mim-grey-light); color: var(--fg-muted); border: 1px solid var(--border);
}
.email-resources-btn.nav-btn--ghost:hover {
  background: var(--mim-purple); color: var(--mim-black); border-color: var(--mim-purple);
}
.nav-btn.resources-select-all { font-size: 13px !important; padding: 12px 26px !important; }

/* ── ONE QUIZ OPTION ───────────────────────────────────────
   Part 2 and Part 3 authored the multiple-choice option separately and it shows:
   Part 2 is a grey plate with a 2px hairline, Part 3 a white card with a 1px
   rule and room on the right for the tick. 52 instances against 212.

   Part 3's is the one taken forward, because it is the majority, it is the one
   with space reserved for the correct/incorrect mark, and a tick drawn into
   24px of padding is what crowded the Part 2 version. */
.quiz-option {
  background: var(--mim-white);
  border: 1px solid var(--fg);
  padding: 16px 48px 16px 20px;
}
