/* ═══════════════════════════════════════════════════════════════════════════
   SHAReT Module 1 — module CSS

   Men in Mind brand layer + the RTL engine, then only what this module adds.
   Branding is recorded as TBD; if it changes, rebind the tokens in the block
   below rather than touching any of the 65 screens.
   ═══════════════════════════════════════════════════════════════════════════ */
@import url('./mim-design-system.css');
@import url('mim-gp-shared.css');

/* The engine declares its own :root AFTER the design system, so the two AA
   purples must be re-stated here or the engine's win. They are the accessible
   pair: --mim-purple itself fails AA as text on white and is decorative only. */
:root {
  --mim-purple-aa:      #8463F8;   /* AA large: 24px+, or 18.66px bold */
  --mim-purple-aa-dark: #5D3CC9;   /* AA normal: small text and links */

  /* The activity library (_components/rtl-activities.css) is brand-agnostic:
     every colour is var(--accent, #5B4FD0) and friends, so WITHOUT these it
     renders in its own fallback purple - close enough to look like a mistake
     rather than a choice, and a different purple from everything around it.

     --mim-purple-aa-dark, not --mim-purple-aa: the library's buttons are
     white text on the accent at 15px, and the AA-large purple is only good
     from 24px up. Same rule that caught the tile labels at 4.1:1.
     The dark-mode pair is the engine's own night purple. */
  --accent:             var(--mim-purple-aa-dark);
  --on-accent:          #FFFFFF;
  --accent-on-dark:     #CDBCFF;
  --on-accent-dark:     #1A1A1A;
}

/* ── ONE TYPE SCALE ────────────────────────────────────────
   Anu, 30 September, twice: "many different font types and sizes ... I am
   still not happy with the typography."

   Measured, the worst screen carried EIGHT sizes - 12, 13, 15, 16, 17, 20,
   23, 28.8 - because every component that arrived brought its own: the arrow
   list at 16, the reveal face at 17, the toolkit at 15, a heading at 28.8, a
   caption at 13. None of them was wrong on its own; together they read as
   noise, and each new component made it worse.

   So there are now FIVE steps and nothing is allowed its own. Each one has a
   job, and a component picks the step that matches its job rather than a
   number that happened to look right in isolation.

     --t-micro  12px   eyebrows, captions, attributions, counts
     --t-body   16px   body copy, list items, everything read at length
     --t-lead   23px   the lead-in, quotes, reveal faces - one voice up
     --t-sub    29px   section headings inside a screen
     --t-title  44px   the screen title (dividers have their own, larger)

   Faces stay at two: Lora carries the title and anything that is a person
   speaking; Overpass carries everything else. */
:root {
  --t-micro: calc(12px * var(--fs-scale));
  --t-body:  calc(16px * var(--fs-scale));
  --t-lead:  var(--fs-subhead);
  --t-sub:   calc(29px * var(--fs-scale));
  --t-title: var(--fs-h1);
}

/* micro */
.eyebrow, .mo-quote figcaption, .refs li, .rtl-toolkit__count,
.rtl-act__hint, .evidence__label, .image-quote__attr,
.mo-diagram figcaption { font-size: var(--t-micro); }

/* body */
.body, .list li, .mo-arrows li, .keypoint-list li, .mo-reasons li,
.evidence__paper, .rtl-toolkit__text, .rtl-recall__got,
.mo-reveal__body .body { font-size: var(--t-body); }

/* lead: one voice up - the lead-in, a person speaking, a reveal's face */
.section-lead, .mo-quote blockquote, .image-quote__text,
.reflect__prompt, .mo-reveal__face, .keypoint,
.rtl-act__prompt, .rtl-act__stem, .mo-beat { font-size: var(--t-lead); }

/* sub: a heading inside a screen */
.heading, .mo-reasons li > strong:first-child,
.mo-arrows--airy li > strong:first-child { font-size: var(--t-sub); }

/* title */
.title { font-size: var(--t-title); }

/* Anu, 30 September: on screen 22 "can we distribute the words in the title
   better? Most of it can be in the first row." Something upstream sets
   text-wrap: balance on every title, which EVENS the lines - measured, 395px
   and 407px inside a 700px column, so both stopped 300px short. Balance is
   right for a centred divider and wrong for a left-aligned sentence, which
   should fill its first line and carry the remainder. `pretty` fills but
   still avoids leaving one word stranded on the last line. */
.screen-inner > .title { text-wrap: pretty; }

/* The divider keeps its own, set on .screen--part .title further down: a
   lesson opening is meant to outrank everything a content screen can do. */

/* ── the reading column ────────────────────────────────────
   Anu, 30 September: "the text alignment looks very left aligned. I want it
   distributed more evenly."

   Measured, it was: the engine's .screen-inner is 820px, but every text block
   inside it is capped at --measure (700px) and aligned left. So a title ran
   the full 772px while the paragraph under it stopped 244px short, and the
   whole screen read as a column pushed against its own left edge.

   Fixed by making the two agree rather than by centring the paragraphs, which
   would have indented them away from the title they belong to. The column
   comes in to the measure, so every block starts AND ends on the same two
   edges and the page's own margins carry the rest. Line length is unchanged,
   which is the part that matters for reading.

   Screens that are a picture rather than a page opt out below. */
.screen-inner { max-width: calc(var(--measure) + 2 * var(--sp-5)); }

/* Full-bleed by design: the hero screens, the image-quote, the outcomes band
   and the covers screen all size themselves and would be squeezed by the
   reading column. */
.screen--hero > .screen-inner,
.screen--multimedia > .screen-inner,
.screen--covers .screen-inner,
.screen--lo .screen-inner,
.screen--objectives .screen-inner { max-width: 1100px; }

/* NOT the nav screen. It is a column of text cards, so it belongs in the
   reading column like any other page of reading - widened to 1100px its
   720px tutorial sat hard left with 526px of empty screen beside it. */
.nav-tutorial { margin-inline: auto; }

/* Screen 7's title is centred over full-width tiles, so its one paragraph -
   capped at the measure inside a 1100px column - was hanging 200px left of
   everything else. Centred as a block; the text itself stays left. */
.screen--covers .body, .screen--covers .section-lead { margin-inline: auto; }

/* The kit caps .section-lead at 38ch, which at the subhead size is 552px
   against the column's 700px. So the right edge stepped 700 / 552 / 700 down
   a screen - title full width, the lead stopping well short, body full width
   again - and that ragged edge is most of what reads as "left aligned".
   The lead now shares the column. ~48ch at that size is still a short measure
   for a lead-in, so nothing is lost in readability. */
.section-lead { max-width: var(--measure); }

/* ── the image-quote screen ──────────────────────────────────
   Plain black, no texture. Anu, 30 September 2026. The kit's .screen--multimedia
   lays the photocopy grain over black for every expressive screen; behind a
   single large photograph it just competes with it, and the grain reads as
   noise around the frame rather than as a surface. */
.screen--multimedia[data-type="image-quote"] {
  background-color: #000;
  background-image: none;
}

/* Anu, 30 September: the accordion text "is too small". The kit sets
   .evidence__paper at 15px against a 16px body, which reads as a footnote on
   a screen whose whole content is inside the accordion. Matched to body size;
   the link keeps its own small uppercase treatment. */
.evidence__paper { font-size: calc(16px * var(--fs-scale)); line-height: 1.6; }

/* ── fewer voices on a screen ──────────────────────────────────
   Anu, 30 September: screen 22 "has many different font types and sizes which
   makes it look odd." Measured, it carried SIX sizes - 12 / 13 / 16 / 19 /
   23 / 44 - and the 19px quote sat between the 16px body and the 23px lead,
   three steps inside a few centimetres.

   The quote now takes the lead's own size, so Lora says two things on a
   screen (the title, and a person speaking) and Overpass says the rest. Five
   sizes, and each one means something. */

/* ⚠ <strong> WAS NOT BOLD. Body copy is weight 300, and the browser's
   default for strong is 700 of a face that only ships 300/400/600 - it
   resolved to 400. One step off the surrounding text is not emphasis, so
   every bolded phrase the deck wrote has been arriving flat: "if it is
   mentioned at all", "The point:", "ask". Semibold is the kit's own emphasis
   weight, and .list strong already used it - this extends it to the places
   the engine missed. */
.body strong, .section-lead strong, .keypoint strong,
.mo-beat strong, .reflect__prompt strong, .mo-reasons li strong,
.evidence__paper strong { font-weight: var(--weight-semibold); }

/* ── click to reveal ────────────────────────────────────────
   Screen 26's three assumptions. Anu, 30 September: "the boxes look odd."
   Three bordered cards stacked on a white screen read as a form to fill in.
   No box now - a rule under each line and a purple marker that turns, which
   is how the rest of the module sets a list, and it stops competing with the
   accordion rows two screens later. Built on the engine's .reveal-item so
   Space/Enter sequencing and audit.js both see it. */
.mo-reveals { display: grid; margin: var(--sp-5) 0; max-width: var(--measure); }
.mo-reveal { border-bottom: 1px solid var(--border, #D8D6E0); }
.mo-reveal:first-child { border-top: 1px solid var(--border, #D8D6E0); }
.reveal-btn--wide {
  display: flex; align-items: baseline; gap: 14px;
  width: 100%; text-align: left; background: none; border: none; cursor: pointer;
  padding: 18px 4px;
}
.mo-reveal__mark {
  flex: none; width: 13px; height: 13px; position: relative; top: -1px;
  background: var(--mim-purple-aa);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
  transition: transform var(--dur-base, .22s) var(--ease-standard, ease);
}
.mo-reveal.open .mo-reveal__mark { transform: rotate(90deg); }
.mo-reveal__face {
  font-family: var(--font-feature); font-weight: var(--weight-regular);
  font-size: var(--t-lead); line-height: 1.3; color: var(--fg);
}
.mo-reveal__body { padding: 0 0 20px 27px; }
.mo-reveal__body .body { margin-top: 0; }
.reveal-btn--wide:hover .mo-reveal__face { color: var(--mim-purple-aa-dark); }
body.night-mode .mo-reveal,
body.night-mode .mo-reveal:first-child { border-color: rgba(255,255,255,0.22); }
body.night-mode .mo-reveal__face { color: rgba(255,255,255,0.92); }
body.night-mode .mo-reveal__mark { background: #cdbcff; }

/* ── nothing gives the answer away ─────────────────────────────
   Content after an activity, held until the learner has answered. The hook is
   the library's own: markEngaged() sets data-rtl-engaged="1" on the activity
   root, and every activity calls it, so this one rule covers the estimate,
   the recall and anything added later. A sibling selector, so the held block
   simply follows the activity in the markup - no JS of ours involved. */
.mo-after { display: none; }
.rtl-act[data-rtl-engaged="1"] ~ .mo-after { display: block; }

/* ── the statement screen, in two rows ───────────────────────────
   Measured at four lines in a 700px column. It is the module's one dramatic
   beat, so it gets the divider's width and a size tuned to break twice on its
   68 characters. Anu, 30 September: "can we make the text appear in two
   rows?" */
.screen--statement .screen-inner { max-width: min(1040px, 92vw); }
.screen--statement .title {
  font-size: calc(clamp(30px, 4vw, 56px) * var(--fs-scale));
  line-height: 1.1;
  text-wrap: balance;
}

/* ── the divider's own body copy ───────────────────────────────
   The title centres and the sub-line centres, but lesson 1.2's closing
   paragraph is capped at --measure inside a 1040px divider, so it sat left
   with 316px of empty screen beside it - which is what reads as "not aligned
   to the centre". Centred as a block; the text inside stays centred with the
   rest of the divider. */
.screen--part .screen-inner > .body { margin-inline: auto; }

/* ── room to breathe ────────────────────────────────────────
   Anu, 30 September, on both reflections: "space it out as it appears too
   crowded." The kit pads .reflect at 32/36 and sets its prompts 14px apart,
   which is fine for one short question and cramped for five numbered ones. */
.reflect { padding: clamp(28px, 3.6vw, 44px) clamp(24px, 3.4vw, 46px); }
.reflect__label { margin-bottom: 22px; }
.reflect__prompt + .reflect__prompt { margin-top: 20px; }
.reflect ol { margin-top: 20px; }
.reflect ol li + li { margin-top: 16px; }
.reflect__respond { margin-top: 26px; }
.reflect__actions { margin-top: 16px; gap: 14px; }

/* ── the lesson's references, centred ────────────────────────── */
.evidence--refs { margin-inline: auto; }

/* ── the reveal actually reveals ────────────────────────────────
   ⚠ NOTHING IN THE SUITE HIDES .reveal-item__body. toggleReveal() adds and
   removes `.open` on .reveal-item, and mim-gp-shared.css styles only
   `.try-saying .reveal-item`, which is Pharmacy Part 3's own variant. So the
   rehearsal's phrasings were on screen from the start and the button toggled
   a class no rule listened to - Anu, 30 September: "the phrasings is visible
   already and the button isn't working."

   Written against .reveal-item rather than .rehearsal-panel so any reveal
   this module adds later works the same way. Raised for Tom: the generic
   pair belongs in the engine. */
.reveal-item > .reveal-item__body { display: none; }
.reveal-item.open > .reveal-item__body { display: block; }

/* ── emphasis that reads as emphasis ─────────────────────────────
   Anu, 30 September: on screen 31 "the bold needs to be bolder." The earlier
   pass caught .body and .section-lead but not list items, and screen 31's
   whole structure is three bolded leads inside an arrow list. Bold is also
   what carries the three-way distinction the deck calls the module's most
   transferable idea, so it has to land. */
.mo-arrows li strong, .keypoint-list li strong,
.list li strong, .rtl-act strong { font-weight: var(--weight-semibold); }

/* ── the divider's sub-line ──────────────────────────────────
   Sits directly under the title it qualifies, centred with it, no rule. */
.part-sub {
  font-family: var(--font-primary); font-weight: var(--weight-regular);
  font-size: calc(15px * var(--fs-scale)); line-height: 1.45;
  letter-spacing: 0.02em;
  color: rgba(255,255,255,0.82);
  margin-top: var(--sp-3);
  max-width: none;
}

/* ── the starburst ──────────────────────────────────────────
   MIM Pro's mark, GP Part 1 screen 16: `.mim-starburst` holding an <img> of
   mark-rays.png, sitting behind the content rather than in it. Their CSS is
   in their own module, not the engine, so this is the mechanism rebuilt from
   the markup - same class and same shape, so a later port replaces it
   cleanly.

   Decorative, so aria-hidden in the markup, and the turn stops outright under
   reduced motion. Low opacity because it is a ground: the questions sit on
   it, and anything stronger competes with the type it is behind. */
.mo-rays-wrap { position: relative; }
.mo-rays-wrap > .mo-questions { position: relative; z-index: 1; }
/* Anu, 30 September: "can we move the graphic to top right hand corner of the
   page?" Centred behind the questions it sat under the type; in the corner it
   is a mark on the page, which is how MIM Pro uses it too. It overhangs the
   column deliberately - the screen has room either side and the crop is part
   of the effect. */
.screen[data-starburst] .screen-inner { position: relative; }
.mim-starburst {
  position: absolute; top: -8px; right: -78px; z-index: 0;
  pointer-events: none;
}
.mim-starburst img {
  width: clamp(130px, 17vw, 210px); height: auto;
  opacity: .2;
  animation: starburstTurn 72s linear infinite;
}
@keyframes starburstTurn { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .mim-starburst img { animation: none; } }
body.reduced-motion .mim-starburst img { animation: none; }
body.night-mode .mim-starburst img { opacity: .26; }

/* ── air under a title, above its picture ─────────────────────────
   Anu, 30 September: "more space needed between title and placeholder image.
   Apply this for all screens that contain images." The engine's stacking
   rhythm gives every block the same gap, which is right for two paragraphs
   and too tight when a 700px picture lands straight under a 44px title. */
.title + .mo-figure,
.title + .mo-diagram,
.heading + .mo-figure { margin-top: var(--sp-6); }

/* ── two things, side by side ─────────────────────────────────
   Screen 42's linear and circular models. The copy already sets them against
   each other - one asks what has stopped working, the other what could work -
   so they face each other instead of running down the page. A purple keyline
   on each, no box: cards stay screen 7's. */
.mo-pair {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: clamp(28px, 4vw, 56px); row-gap: 28px;
  margin: var(--sp-6) 0; max-width: var(--measure);
}
.mo-pair__side { padding-top: 14px; border-top: 2px solid var(--mim-purple-aa); }
.mo-pair__side > .heading { margin-top: 0; font-size: var(--t-lead); }
.mo-pair__side > .body:first-of-type { margin-top: 10px; }
body.night-mode .mo-pair__side { border-top-color: #cdbcff; }
@media (max-width: 720px) { .mo-pair { grid-template-columns: minmax(0, 1fr); } }

/* ── sequencing ──────────────────────────────────────────
   The library ships its own styling; this only pulls the numbers onto the
   module's purple so the activity does not arrive in the fallback colour. */
.rtl-sequence__num { background: var(--mim-purple-aa); color: #fff; }
body.night-mode .rtl-sequence__num { background: #cdbcff; color: #1A1A1A; }

/* ── right and wrong look different ─────────────────────────────
   MIM Pro's own modifiers, 14 uses across its three GP parts. The engine
   styles .quiz-feedback; the modifier is what tells a learner at a glance
   which of the two panels they are reading. Green and red are the kit's
   semantic pair, not new colour. */
.quiz-feedback--correct { border-left: 3px solid var(--mim-green, #1F7A52); padding-left: 16px; }
.quiz-feedback--incorrect { border-left: 3px solid var(--mim-purple-aa); padding-left: 16px; }
body.night-mode .quiz-feedback--correct { border-left-color: #5EC98F; }
body.night-mode .quiz-feedback--incorrect { border-left-color: #cdbcff; }


/* ── purple bullets ─────────────────────────────────────────
   Anu: "for all the treatment screens, make the bullet points purple", and
   on the last one "make the bullet points like small purple boxes". Squares
   throughout rather than one screen in squares and the rest in dots - a
   marker that changes shape between screens reads as a mistake. */
ul.list li::before {
  background: var(--mim-purple-aa);
  border-radius: 2px;
  width: 8px; height: 8px;
  top: 0.55em;
}
ol.list li::before { color: var(--mim-purple-aa-dark); }
body.night-mode ul.list li::before { background: #cdbcff; }
body.night-mode ol.list li::before { color: #cdbcff; }

/* ── purple lettering ────────────────────────────────────
   A second way to put purple on a screen, for the ones where a smear would be
   the fourth mark in a row. --mim-purple-aa-dark because this is running text
   at reading size, not a 24px display line. */
.mo-accent { color: var(--mim-purple-aa-dark); font-weight: var(--weight-semibold); }
body.night-mode .mo-accent { color: #cdbcff; }

/* ── the treatment tiles ───────────────────────────────────
   Not clickable, and deliberately so - they are a contents list for the four
   screens that follow, not navigation. A purple top edge each, which is the
   device screen 7's tiles already use. */
.mo-treats {
  list-style: none; margin: var(--sp-6) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px; max-width: var(--measure);
}
.mo-treat {
  padding: 16px 18px;
  border-top: 3px solid var(--mim-purple-aa);
  background: var(--mim-grey-light);
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: var(--t-body); line-height: 1.35; color: var(--fg);
}
body.night-mode .mo-treat { background: #17171b; color: rgba(255,255,255,0.92); }
body.night-mode .mo-treat { border-top-color: #cdbcff; }

/* Anu, 12 October: "increase the height of the four grey tiles so the white
   space is reduced a bit at the bottom." The tiles sat in a band taller than
   they were and floated at the top of it. */
.mo-treat { padding: 28px 18px 30px; min-height: 148px; }

/* ── screen 46, the five effects as flip cards ─────────────────────────────
   Anu, 12 October: "Remove the grey background on the cards. Can we have the
   cards placed evenly. Reduce the size if needed. Ideally one row."

   ONE ROW OF FIVE INSIDE A 748px READING COLUMN IS TIGHT, and the sizes below
   are what that costs. `.screen-inner` is capped at the measure plus its
   padding, and breaking a grid out of the reading column would fight the
   decision recorded at the top of this file, so the cards get narrower rather
   than the column getting wider: (700 - 4 gaps) / 5 is about 132px each.

   Everything else follows from that width - a 10px gap instead of 16, 12px of
   card padding instead of 24, and a smaller icon and type - because the
   longest back runs to 222 characters and has to stay readable in roughly a
   108px column. */
/* Anu, 12 October: "3 boxes in the first row and 2 in the second but spaced
   out evenly (centre-aligned)." Six columns, two per card: three to a row, and
   the last two placed by hand so the short row centres. auto-fit cannot centre
   a short final row - it would push both cards hard left. */
.effect-cards { grid-template-columns: repeat(6, 1fr); gap: 16px; }
.effect-cards .flipcard { grid-column: span 2; }
.effect-cards .flipcard:nth-child(4) { grid-column: 2 / span 2; }
.effect-cards .flipcard:nth-child(5) { grid-column: 4 / span 2; }
@media (max-width: 600px) {
  .effect-cards { grid-template-columns: minmax(0, 1fr); }
  .effect-cards .flipcard,
  .effect-cards .flipcard:nth-child(4),
  .effect-cards .flipcard:nth-child(5) { grid-column: auto; }
}
.effect-cards .flipcard { min-height: 272px; }
.effect-cards .flipcard__front,
.effect-cards .flipcard__back { padding: 18px 14px; }

/* ⚠ THE FRONT IS OVERRIDDEN TWICE OVER. mim-gp-shared.css:1893 deliberately
   makes `.flipcard__front` BLACK with white text - "a card should read as a
   card on the page" - which hid these dark line icons entirely. It was then
   set to the pale panel here, and Anu asked for that grey to go too. White
   with the engine's own border is what is left, and the border is doing the
   work the fill used to. */
.effect-cards .flipcard__front {
  background: var(--mim-white);
  border-color: var(--border);
  color: var(--fg);
}
.effect-cards .flipcard__front .flip-hint { margin-top: 8px; }
.effect-cards__lead { margin-bottom: 14px; }
.effect-cards .flipcard__front img {
  width: 76px; height: 76px; object-fit: contain; margin-bottom: var(--sp-4);
}
.effect-cards .flipcard__front .effect-cards__name {
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(17px * var(--fs-scale)); color: var(--fg); text-align: center;
}
.effect-cards .flipcard__back p {
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(14px * var(--fs-scale)); line-height: 1.5; margin: 0;
  color: var(--fg);
}

@media (max-width: 720px) { .mo-treats { grid-template-columns: minmax(0, 1fr); } }

/* ── the film that is not wired yet ─────────────────────────────
   The pause-and-choose tile carries the deck's real Vimeo id but no play
   action, because embedding is not confirmed on the course domain. It reads
   as a placeholder rather than a dead button: no pointer, no hover, and the
   play mark at rest. */
.video-frame--placeholder .video-poster { cursor: default; }
.video-frame--placeholder .video-poster__play { opacity: .55; }

/* The way back to the film, after the choice has been made. */
.mo-back { margin-top: var(--sp-4); }

/* ── the three practice points, as cards ──────────────────────────
   Anu, 30 September: screen 60 "looks too similar to screen 59". It was the
   same reveal component twice in a row - same markup, same "Select each one
   to see how it plays out" instruction - so three cards across read as a
   different interaction. The copy already said "three things".

   The grid drops to one column under 720px: three cards side by side at phone
   width would each be too narrow to read.

   No `all: unset` on the button. The engine gives every `.screen button` a
   box-shadow and a border through its own rules, so those are named and
   cleared explicitly - the same reason .evidence__row needs neutralising
   further down this file. */
.mo-cards {
  list-style: none; margin: var(--sp-5) 0 0; padding: 0;
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (max-width: 720px) { .mo-cards { grid-template-columns: 1fr; } }
.mo-card {
  background: var(--mim-grey-light); border-radius: var(--radius-lg);
  border: 1px solid transparent; display: flex; flex-direction: column;
  overflow: hidden;
}
.mo-card.is-open { border-color: var(--mim-purple-aa); }
.screen .mo-card__btn,
.screen .mo-card__btn:hover {
  background: none; border: 0; box-shadow: none; margin: 0;
  box-sizing: border-box; cursor: pointer; display: block; width: 100%;
  text-align: left; padding: clamp(18px, 2vw, 24px);
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(17px * var(--fs-scale)); line-height: 1.3; color: var(--fg);
}
.mo-card__btn:focus-visible {
  outline: 3px solid var(--mim-purple-aa); outline-offset: 2px;
}
/* NOT --mim-purple-aa. Measured on the tile background it is 3.66:1 in day
   and 4.37:1 at night, both under AA, and audit.js fails on it. #5D3CC9 is
   6.34:1 in day and #B7A3FC is 8.23:1 at night - both already in this
   module's palette (they are two of the confetti colours). */
.mo-card__num {
  display: block; font-family: var(--font-primary);
  font-size: calc(13px * var(--fs-scale)); letter-spacing: .14em;
  color: #5D3CC9; margin-bottom: 10px;
}
.mo-card__cue {
  float: right; color: #5D3CC9;
  font-weight: var(--weight-regular); line-height: 1;
}
body.night-mode .mo-card__num,
body.night-mode .mo-card__cue { color: #B7A3FC; }
.mo-card.is-open .mo-card__cue { display: inline-block; transform: rotate(45deg); }
.mo-card__body { padding: 0 clamp(18px, 2vw, 24px) clamp(18px, 2vw, 24px); }
.mo-card__body .body { margin: 0; }
/* var(--fg) does not flip to a light colour inside these components at
   night - it resolved to black on #171719, which audit.js caught at 1.18:1 -
   so the text colour is named for night explicitly. */
body.night-mode .mo-card { background: rgba(255, 255, 255, .05); }
body.night-mode .screen .mo-card__btn,
body.night-mode .mo-card__face { color: rgba(255, 255, 255, .92); }

/* ── "What the research says" as a tile, not a screen ─────────────
   Anu, 30 September: "can we make this similar to Pause for a Mo tile - and
   where possible fold it into the previous screen. The heading is too big
   right now and I still think it doesn't need a screen of its own."

   So the evidence rows sit in a labelled tile the same shape as the reflect
   tile, instead of under a 96px h1 on a screen of their own.

   ⚠ IT IS ITS OWN CLASS, NOT A REUSE OF .reflect. The engine's .reflect
   starts at opacity 0 and waits for a class the engine only ever adds to
   .reflect[data-reflect] (mim-gp-shared.css:520, mim-gp-shared.js:2013), so
   borrowing the class for a tile with no data-reflect would have shipped an
   invisible block - and audit.js counts invisible text, so it would have
   failed the gate rather than reaching a learner. */
.evidence-tile {
  background: var(--mim-grey-light); border-radius: var(--radius-lg);
  padding: clamp(28px, 3.6vw, 44px) clamp(24px, 3.4vw, 46px);
  max-width: var(--measure); margin-top: var(--sp-6);
}
.evidence-tile__label {
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(13px * var(--fs-scale)); letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--fg);
  margin-bottom: 10px; display: block;
}
.evidence-tile .mo-instruction { margin-bottom: 18px; }
.evidence-tile .evidence:first-of-type { margin-top: 0; }
body.night-mode .evidence-tile { background: rgba(255, 255, 255, .05); }
body.night-mode .evidence-tile__label { color: rgba(255, 255, 255, .92); }

/* ── the tick and the cross ───────────────────────────────────
   Anu, 30 September: "when a learner chooses one option, that option needs to
   have either a cross or a tick." On the option itself, so it is clear WHICH
   one was chosen - the engine only colours the border, which says something
   happened but not what. Shape as well as colour: a tick and a cross read
   without relying on green and red being distinguishable.

   THE GLYPHS ARE LITERAL CHARACTERS (U+2713 tick, U+2715 cross) AND MUST
   STAY THAT WAY. They reached 2026-09-30 as "¹3" and "¹5", so every chosen
   option showed a stray number instead of a mark. The cause is a Python
   octal escape, not a file encoding: in a non-raw Python string, "\2713"
   is \271 (octal 271 = 185 = ¹) followed by "3". Any script that writes
   this rule must use a raw string, chr(0x2713), or the character itself.
   The symbol faces lead the font stack because Overpass may not carry these
   code points. */
.quiz-option[data-fb] { position: relative; padding-right: 46px; }
.quiz-option[data-fb].correct::after,
.quiz-option[data-fb].incorrect::after {
  position: absolute; right: 16px; top: 50%; transform: translateY(-50%);
  width: 22px; height: 22px; border-radius: 999px;
  display: grid; place-items: center;
  font-family: 'Segoe UI Symbol', 'Apple Symbols', 'Noto Sans Symbols 2',
               var(--font-primary); font-weight: var(--weight-semibold);
  font-size: 14px; line-height: 1; color: #fff;
}
.quiz-option[data-fb].correct::after   { content: "✓"; background: var(--mim-green, #1F7A52); }
.quiz-option[data-fb].incorrect::after { content: "✕"; background: #B3261E; }
/* The right answer, once the tries are used up. */
.quiz-option[data-fb].revealed-correct {
  border-color: var(--mim-green, #1F7A52);
}
.quiz-option[data-fb].revealed-correct::after {
  content: "✓"; position: absolute; right: 16px; top: 50%;
  transform: translateY(-50%); width: 22px; height: 22px; border-radius: 999px;
  display: grid; place-items: center; font-size: 14px; color: #fff;
  background: var(--mim-green, #1F7A52); opacity: .55;
}

/* The chosen option's own feedback. */
.mcq-fb {
  margin-top: var(--sp-5); padding-left: 16px;
  border-left: 3px solid var(--mim-purple-aa);
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: var(--t-body); line-height: 1.55; color: var(--fg);
  max-width: var(--measure);
}
body.night-mode .mcq-fb { color: rgba(255,255,255,0.9); border-left-color: #cdbcff; }
.mcq-after { margin-top: var(--sp-4); }

/* The other options' explanations, under the chosen one. Anu, 30 September:
   "display the remaining feedback after this." Set back from the chosen
   feedback rather than beside it - the one they picked stays the answer to
   their question, and these are the ones they did not ask about. */
.mcq-rest {
  margin-top: var(--sp-4); padding-left: 16px;
  border-left: 3px solid rgba(0,0,0,0.12);
  max-width: var(--measure);
}
.mcq-rest .body { font-size: var(--t-body); line-height: 1.55; margin: 0 0 10px; }
.mcq-rest .body:last-child { margin-bottom: 0; }
.mcq-rest strong { color: var(--mim-purple-aa-dark); }
body.night-mode .mcq-rest { border-left-color: rgba(255,255,255,0.22); }
body.night-mode .mcq-rest strong { color: #cdbcff; }

/* ── click them in the order you would ask them ────────────────
   The third mechanic this screen has worn. Ranking and select-then-place both
   made the learner work out the CONTROL before they could answer the
   QUESTION; this one is a list of buttons, and the only thing to know is that
   the order you press them in is your answer. The number appears in the
   circle as you go, so the answer is visible while it is being made.

   The circle is the screen's purple element - registered in check-purple.py
   as mo-order__num. */
.mo-order { max-width: var(--measure); }
.mo-order__list { list-style: none; margin: 0; padding: 0; counter-reset: none; }
.mo-order__row + .mo-order__row { margin-top: 10px; }

.mo-order__item {
  display: flex; align-items: flex-start; gap: 14px; width: 100%;
  text-align: left; cursor: pointer;
  padding: 14px 16px; border-radius: 10px;
  background: rgba(0,0,0,0.02);
  border: 1px solid rgba(0,0,0,0.14);
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: var(--t-body); line-height: 1.5; color: var(--fg);
  transition: background .15s ease, border-color .15s ease;
}
.mo-order__item:hover:not(:disabled) {
  background: rgba(132,99,248,0.07); border-color: var(--mim-purple-aa);
}
.mo-order__item:focus-visible {
  outline: 3px solid var(--mim-purple-aa); outline-offset: 2px;
}
.mo-order__item:disabled { cursor: default; }

/* Empty until it is chosen: an outline where the number will go, so the list
   reads as six slots rather than six paragraphs. */
.mo-order__num {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 999px;
  display: grid; place-items: center;
  font-weight: var(--weight-semibold); font-size: 15px;
  border: 2px solid rgba(0,0,0,0.18); color: transparent;
}
.mo-order__item.is-picked { background: rgba(132,99,248,0.09); border-color: var(--mim-purple-aa); }
.mo-order__item.is-picked .mo-order__num {
  background: var(--mim-purple-aa-dark); border-color: var(--mim-purple-aa-dark);
  color: #fff;
}
.mo-order__text { flex: 1 1 auto; padding-top: 3px; }

/* After the sixth. Colour is not the only signal: the wanted position is
   spelled out in words beside the ones that moved. */
.mo-order__item.is-right .mo-order__num {
  background: var(--mim-green, #1F7A52); border-color: var(--mim-green, #1F7A52);
}
.mo-order__item.is-wrong .mo-order__num {
  background: none; color: var(--fg); border-color: rgba(0,0,0,0.3);
}
.mo-order__want {
  flex: 0 0 auto; align-self: center;
  font-size: var(--t-micro); font-weight: var(--weight-semibold);
  letter-spacing: .06em; text-transform: uppercase;
  color: rgba(0,0,0,0.55); white-space: nowrap;
}
.mo-order__reset { margin-top: var(--sp-4); }
.mo-order__fb { margin-top: var(--sp-4); max-width: var(--measure); }
.mo-order__fb[hidden] { display: none; }

body.night-mode .mo-order__item {
  background: rgba(255,255,255,0.04); border-color: rgba(255,255,255,0.22);
  color: rgba(255,255,255,0.92);
}
body.night-mode .mo-order__item:hover:not(:disabled) { border-color: #cdbcff; }
body.night-mode .mo-order__num { border-color: rgba(255,255,255,0.3); }
body.night-mode .mo-order__item.is-picked .mo-order__num { background: #5D3CC9; border-color: #cdbcff; }
body.night-mode .mo-order__item.is-wrong .mo-order__num { color: rgba(255,255,255,0.92); }
body.night-mode .mo-order__want { color: rgba(255,255,255,0.6); }

/* ── the confetti at the end of the module ─────────────────────
   Anu, 30 September: "something celebratory, like confetti falling on the
   screen for completing module 1. After completing every module."

   Purely decorative: it never takes a click, it is aria-hidden, and the
   script removes the canvas when it stops. Below the modals (300+) so a
   lightbox or the mail dialog still sits on top of it. The script does not
   run at all under reduced motion, so there is no animation here to damp. */
/* ── the module contents menu ────────────────────────────────
   Anu, 30 September: "in the menu bar, lesson 1.3 is slightly indented. Fix
   this to make it consistent with other lesson titles."

   Measured rather than guessed: every group header is 36px tall except 1.3's,
   which is 48px. Its label - "1.3 How sex works, and how cancer changes it" -
   is the only one long enough to wrap in the 356px panel, and the header
   inherits text-align: center, so BOTH its lines centre. The first line
   therefore starts further right than the five single-line labels beside it,
   and the orphaned "it" sits in the middle of the second line. Nothing is
   indenting it; it is being centred.

   Left-aligning the label fixes it for any label that wraps, which is the
   real condition - a longer lesson title in a later module would have done
   the same thing. Module-local: .nav-group__label belongs to the engine, and
   the engine is shared by twelve modules. */
#chapterList .nav-group__label { text-align: left; }

.mo-confetti {
  position: fixed; inset: 0; z-index: 250;
  width: 100%; height: 100%;
  pointer-events: none;
}

/* ── the resources checklist ──────────────────────────────────
   The engine styles .resource-item__label and little else, because the whole
   component is left to the module. Rows rather than bullets: these are things
   to tick, not things to read past. */
.resources-list { list-style: none; margin: var(--sp-5) 0 0; padding: 0; max-width: var(--measure); }
.summary-resource-item { border-bottom: 1px solid var(--border, #D8D6E0); }
.summary-resource-item:first-child { border-top: 1px solid var(--border, #D8D6E0); }
.resource-item__label {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 14px 4px; cursor: pointer;
}
.resource-checkbox { margin-top: 3px; width: 18px; height: 18px; accent-color: var(--mim-purple-aa-dark); flex: none; }
.resource-item__text {
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: var(--t-body); line-height: 1.5; color: var(--fg);
}
.summary-resource-item.tagged .resource-item__text { color: var(--fg); font-weight: var(--weight-regular); }
body.night-mode .summary-resource-item,
body.night-mode .summary-resource-item:first-child { border-color: rgba(255,255,255,0.22); }
body.night-mode .resource-item__text { color: rgba(255,255,255,0.9); }

/* The link on a resource that ships inside the package.
   Anu, 12 October: "let's link it". Only the conversation guide has one - the
   rest of the list is things the learner goes and finds, where the citation is
   the point because the screen emails it to them.

   Indented to the width of the checkbox and its gap (18 + 14) so it lines up
   under the citation rather than under the tick, and OUTSIDE the <label>,
   because a link nested in a label toggles the checkbox it sits in. */
.resource-item__link {
  display: inline-block; margin: 0 0 14px 32px;
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(11px * var(--fs-scale)); letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--mim-purple-aa-dark);
  text-decoration: none;
}
.resource-item__link:hover { text-decoration: underline; }
body.night-mode .resource-item__link { color: #cdbcff; }

.resources-select-all { margin-top: var(--sp-4); }
/* The deck's own group headings, inside the checklist. */
.resources-group { border: none; padding: var(--sp-5) 0 6px; }
.resources-group:first-child { padding-top: 0; }
.resources-group .heading { margin: 0; font-size: var(--t-lead); }
.rtl-act__btn--ghost {
  background: none; color: var(--mim-purple-aa-dark);
  border-color: var(--mim-purple-aa);
}
body.night-mode .rtl-act__btn--ghost { color: #cdbcff; border-color: #cdbcff; }
.resources-email-section { margin-top: var(--sp-6); display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.email-resources-btn:disabled { opacity: .45; cursor: not-allowed; }

/* ── save for later ────────────────────────────────────────
   On the evidence blocks, so "anything you saved as you went along is already
   ticked for you" is true rather than aspirational. */
.res-save {
  display: inline-block; margin-top: 12px;
  background: none; border: 1.5px solid var(--mim-purple-aa); border-radius: var(--radius-pill, 999px);
  padding: 6px 14px; cursor: pointer;
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(12px * var(--fs-scale)); letter-spacing: .02em;
  color: var(--mim-purple-aa-dark);
}
.res-save:hover { background: rgba(132,99,248,.10); }
.res-save.is-saved { background: var(--mim-purple-aa); color: #fff; border-color: var(--mim-purple-aa); }
body.night-mode .res-save { color: #cdbcff; border-color: #cdbcff; }
body.night-mode .res-save.is-saved { background: #cdbcff; color: #1A1A1A; }

/* ── tell the learner what to do ──────────────────────────────
   Anu's standing rule of 30 September: every interaction carries an
   instruction. It reads as an instruction rather than as body copy - the
   kit's own .instructional weight and colour - without shouting. */
/* Anu, 12 October: "Make this in a different font so that it appears
   different from the eyebrow." It was Overpass semibold uppercase and so is
   .eyebrow, four lines above it. Lora italic, sentence case: a different
   family, case and posture, so it reads as direction rather than as a second
   label. */
.mo-instruction {
  font-family: var(--font-feature); font-style: italic;
  font-weight: var(--weight-regular);
  font-size: calc(16px * var(--fs-scale));
  letter-spacing: 0; text-transform: none; line-height: 1.5;
  color: var(--fg-subtle);
  margin-bottom: var(--sp-4);
}
body.night-mode .mo-instruction { color: rgba(255,255,255,0.72); }

/* ── the recall list, once it arrives ──────────────────────────
   Plain lines now, not tick buttons - nothing is scored, so a tick was a
   control that did nothing but invite a click. */
.rtl-recall__line {
  position: relative; padding-left: 20px;
  font-size: var(--t-body); line-height: 1.55; color: var(--fg);
}
.rtl-recall__line + .rtl-recall__line { margin-top: 8px; }
.rtl-recall__line::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 7px; height: 7px; border-radius: 999px; background: var(--mim-purple-aa);
}
body.night-mode .rtl-recall__line { color: rgba(255,255,255,0.9); }
body.night-mode .rtl-recall__line::before { background: #cdbcff; }

/* ── air after a numbered prompt ──────────────────────────────
   Anu, twice: "more space between the last question and the paragraph." Both
   reflections end a numbered list and then carry a closing line, and the
   engine's list spacing runs the two together. */
.reflect ol + .reflect__prompt,
.reflect ol + .body,
.reflect ul + .reflect__prompt,
.reflect ul + .body { margin-top: 26px; }

/* ── hidden means hidden ────────────────────────────────────
   ⚠ AN ENGINE BUG, NOT A MODULE ONE. rtl-activities.css sets
   `.rtl-recall__list { display: flex }` with no [hidden] guard, and a display
   rule beats the hidden attribute's UA `display: none` every time. So the
   free-recall answers were on screen from the start - the learner could read
   the list they were being asked to recall, which is the whole activity gone.
   Measured: hidden=true, display=flex, visible=true.

   The same shape would hit any [hidden] element the library gives a display
   to, so the guard is written broadly rather than for the one class. Raised
   for Tom; this override can come out once rtl-activities.css carries it. */
.rtl-act [hidden], .rtl-act[hidden] { display: none !important; }

/* ── type scale ───────────────────────────────────────────
   Anu, 29 September 2026: "the titles are very big". The kit's --fs-h1 tops
   out at 64px, which is a poster size - it was drawn for a hero line of three
   or four words, and this module's titles are sentences ("The moment that
   mattered had already passed"). At 64px that wraps to three lines and pushes
   everything under it off the first screenful.

   Retuned, not removed: still the largest thing on the screen, still fluid,
   and still scaled by --fs-scale so the accessibility text-size control keeps
   working. The DIVIDER keeps the poster size - see .screen--part below - so
   the contrast between a lesson opening and a content screen gets stronger,
   not weaker.

   Overridden here rather than in mim-design-system.css, which is synced from
   the kit master and checked against it by design-system-check.js. */
:root {
  --fs-h1: calc(clamp(30px, 3.1vw, 44px) * var(--fs-scale));
  --fs-h2: calc(clamp(22px, 2.0vw, 30px) * var(--fs-scale));
}

/* ── the lesson divider ─────────────────────────────────────
   Anu, 30 September 2026: the black textured ground, no photograph, and the
   kit's purple smear behind the title.

   The photograph left plain black bands above and below it, because .mo-hero
   sizes to its image and the screen is taller than a 16:9 crop. Without the
   image there is no band - .screen--dark paints the whole screen, texture and
   all, and the title is the only thing on it.

   Size and centring are still the engine's, off `.part-divider` on the inner
   div; only the smear and the type colour are local. */
.screen--part .screen-inner {
  max-width: min(1040px, 92vw);
  margin-inline: auto;
}
.screen--part .title {
  position: relative;
  display: inline-block;
  padding: clamp(10px, 1.8vh, 22px) clamp(16px, 1.8vw, 30px);
  /* ⚠ THE MARK TAPERS AT BOTH ENDS, so stretching it to exactly 100% puts
     the fade on the first and last letters - measured, mean alpha across the
     height is 240 in the middle but 9 near the right edge, and the right
     taper alone is 5.7% of the artwork's width. Overscanned so both tapers
     fall outside the text, which is also how a real highlighter overshoots. */
  background: url('./assets/mim/mark-highlighter-line-v2.png') center / 118% 104% no-repeat;
  font-size: calc(clamp(26px, 3.2vw, 44px) * var(--fs-scale));
  line-height: 1.08;
  text-wrap: balance;
  /* ⚠ BLACK, NOT THE WHITE .screen--dark GIVES IT. White on the brand
     lavender is about 1.9:1 and fails AA outright; black on it is about 11:1.
     Screen 13 carries the same note for the same mark. */
  color: var(--mim-black);
  text-shadow: none;
}
/* The eyebrow stays on the dark ground, so it keeps the kit's white. Its own
   width cap boxes it well short of the column, so `text-align: center` was
   centring it inside that box rather than on the screen - the label sat left
   of the title it introduces. The box gets centred too. */
.screen--part .eyebrow {
  color: rgba(255,255,255,0.78);
  max-width: none;
  margin-inline: auto;
}

/* ── drawn diagrams ────────────────────────────────────────
   Inline SVG, so they follow the theme instead of being a light rectangle on
   a dark screen. Every colour resolves from the module's own tokens, and the
   night block restates the ones that lean on --fg, which night mode does not
   redefine. Each <svg> is aria-hidden: every word in them is in the copy
   beside them, so a screen reader would otherwise read the screen twice.

   ⚠ WITHOUT THESE RULES THE DIAGRAMS DO NOT DEGRADE GRACEFULLY - they break.
   An unresolved `fill` falls back to SVG's default, which is solid BLACK, and
   unset `text-anchor` puts every label at `start`, so the right-hand ones run
   off the edge. That is exactly what shipped for one build when this block was
   deleted by accident, and it is why the rules live next to the markup that
   needs them rather than anywhere more logical. */
.mo-diagram { max-width: 640px; margin-inline: auto; }
.mo-diagram svg { width: 100%; height: auto; display: block; overflow: visible; }
/* The diagram on screen 20 is the only `.mo-diagram` holding an <img> rather
   than an <svg>, so this reaches it and nothing else.

   It is capped well under the 640px the figure allows. The drawing it replaced
   was 640x370 - wide and short. The ring is SQUARE, so at the full measure it
   would be 640px tall, and on a 900px viewport that pushes every word of the
   screen's copy below the fold. */
.mo-diagram img {
  display: block; width: 100%; max-width: 430px; height: auto;
  margin-inline: auto;
}

.mo-diagram figcaption {
  margin-top: 12px;
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(11.5px * var(--fs-scale)); line-height: 1.45;
  color: var(--fg-muted); text-align: center;
}
body.night-mode .mo-diagram figcaption { color: rgba(255,255,255,0.6); }

.dia-line { stroke: var(--mim-purple-aa); stroke-width: 1.6; opacity: .55; }
.dia-line--rule { stroke-width: 2.5; opacity: .4; }
.dia-hub { fill: var(--mim-purple-aa); }
.dia-hub-t {
  fill: #fff; font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: 14px; text-anchor: middle;
}
.dia-node rect { fill: none; stroke: var(--mim-purple-aa); stroke-width: 1.6; opacity: .75; }
.dia-dot { fill: var(--mim-purple-aa); }
.dia-dot--end { fill: var(--mim-purple-aa-dark); }
.dia-year {
  fill: var(--mim-purple-aa-dark); font-family: var(--font-primary);
  font-weight: var(--weight-semibold); font-size: 17px; text-anchor: middle;
}
/* Sized up from 14/16: these are labels on a 640-unit canvas scaled down to
   fit a 700px column, so the on-screen size is smaller than the number looks.
   Anu, 30 September: "can't see the wording clearly." */
.dia-t {
  fill: var(--fg); font-family: var(--font-primary); font-weight: var(--weight-regular);
  font-size: 17px; text-anchor: middle;
}
.dia-t--lg { font-size: 19px; font-weight: var(--weight-semibold); }
.dia-t--start { text-anchor: start; }
.dia-t--end { text-anchor: end; }
.dia-field circle { fill: var(--mim-purple); opacity: .38; }



body.night-mode .dia-line { stroke: #cdbcff; opacity: .6; }
body.night-mode .dia-hub { fill: #cdbcff; }
body.night-mode .dia-hub-t { fill: #1A1A1A; }
body.night-mode .dia-node rect { stroke: #cdbcff; }
body.night-mode .dia-dot, body.night-mode .dia-dot--end { fill: #cdbcff; }
body.night-mode .dia-year { fill: #cdbcff; }

/* ── diagram nodes as tiles ─────────────────────────────────────────────────
   Anu, 12 October: "Make the word boxes like tiles in different colours
   within the MiM palette." They were `fill: none` outlines.

   ⚠ DECLARED AFTER the night-mode block above on purpose. That block sets
   `.dia-node rect { stroke: #cdbcff }`, and these need to win on order
   rather than by being more specific than they have to be.

   The text is pinned to a fixed dark rather than `var(--fg)`, because every
   fill here is light in BOTH themes and `--fg` goes white at night. */
.dia-node--teal   rect { fill: var(--mim-teal);   stroke: none; opacity: 1; }
.dia-node--green  rect { fill: var(--mim-green);  stroke: none; opacity: 1; }
.dia-node--purple rect { fill: var(--mim-purple); stroke: none; opacity: 1; }
.dia-node--grey   rect { fill: var(--mim-grey);   stroke: none; opacity: 1; }
/* Screen 17's nodes are icon cards, not coloured boxes. Anu, 12 October, with
   a reference: "It looks nicer than just plain boxes."

   All four cards are the same off-white on purpose. The shade ramp this
   replaced was four steps of one purple, which was carrying a distinction the
   colour could not actually make; the icons carry it now, and the only colour
   left is the accent inside them. */
.dia-node--card rect { fill: var(--mim-grey-light); stroke: none; }
.dia-t--card { font-weight: var(--weight-semibold); font-size: 18px; }
.dia-node--card .dia-t,
body.night-mode .dia-node--card .dia-t { fill: #1A1A1A; }
body.night-mode .dia-node--card rect { fill: var(--mim-grey-light); stroke: none; }
.dia-node[class*="dia-node--"] .dia-t,
body.night-mode .dia-node[class*="dia-node--"] .dia-t { fill: #1A1A1A; }
body.night-mode .dia-node[class*="dia-node--"] rect { stroke: none; }


/* ── diagram nodes as tiles ─────────────────────────────────────────────────
   Anu, 12 October: "Make the word boxes like tiles in different colours
   within the MiM palette." They were `fill: none` outlines.

   ⚠ DECLARED AFTER the night-mode block above on purpose. That block sets
   `.dia-node rect { stroke: #cdbcff }`, and these need to win on order
   rather than by being more specific than they have to be.

   The text is pinned to a fixed dark rather than `var(--fg)`, because every
   fill here is light in BOTH themes and `--fg` goes white at night. */
.dia-node[class*="dia-node--"] .dia-t,
body.night-mode .dia-node[class*="dia-node--"] .dia-t { fill: #1A1A1A; }
body.night-mode .dia-node[class*="dia-node--"] rect { stroke: none; }

body.night-mode .dia-t { fill: rgba(255,255,255,0.92); }
body.night-mode .dia-field circle { fill: #b7a3fc; opacity: .34; }

/* ── the lesson's references ─────────────────────────────────
   The engine's evidence accordion carrying the whole lesson's references. The
   list inside it loses the rule and the top margin it needed when it sat
   loose at the foot of a screen. */
.evidence--refs { margin-top: var(--sp-6); }
.evidence--refs .refs { margin-top: 0; padding-top: 0; border-top: none; }

/* ── references ────────────────────────────────────────────
   Anu's rule of 18 September 2026, carried from Module 3: superscript markers,
   no in-text citation. The marker is purple because it is the only thing on a
   reference-carrying screen that could be, and --mim-purple-aa-dark because it
   is small text. The list sits quiet at the foot - it is provenance, not
   reading matter, so it takes the muted colour and a rule to separate it. */
.ref {
  font-size: 0.62em;
  font-weight: var(--weight-semibold);
  color: var(--mim-purple-aa-dark);
  vertical-align: super;
  line-height: 0;
  margin-left: 1px;
}
body.night-mode .ref { color: #cdbcff; }

.refs {
  margin-top: var(--sp-6);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border, #D8D6E0);
  list-style: decimal;
  padding-left: 1.4em;
  max-width: var(--measure);
}
.refs li {
  font-family: var(--font-primary);
  font-weight: var(--weight-light);
  font-size: calc(12.5px * var(--fs-scale));
  line-height: 1.5;
  color: var(--fg-muted);
}
.refs li + li { margin-top: 6px; }
/* ── phrasings, read rather than collected ─────────────────────────────────
   Anu, 12 October: the checkboxes and the "Nothing saved yet" count go. The
   checkbox is `.rtl-toolkit__item::before` in _components/rtl-activities.css,
   which is the shared engine and off-limits, so screen 30's markup drops the
   engine's classes and these take over.

   Same border, radius, padding and size as the engine's card. What is gone:
   the 2.5rem left inset, which existed only to make room for the checkbox,
   and the pointer cursor, because clicking does nothing now. */
.phrasing-set__items {
  display: flex; flex-direction: column; gap: .5rem;
  margin: 0; padding: 0; list-style: none;
}
.phrasing-set__item {
  font-size: calc(15px * var(--fs-scale, 1));
  padding: .65rem .9rem;
  border: 2px solid var(--border, rgba(0,0,0,0.12));
  border-radius: var(--radius-sm, 8px);
  background: var(--bg, #fff);
  color: var(--fg);
}


/* References are a PLAIN VISIBLE LIST, not an accordion - lifted from Module
   2, which had it right. Module 1 used `evidence--refs`, the same Mo-icon
   accordion as the research boxes, so two different things wore identical
   chrome and a learner could not tell which was which. The heading is what
   separates the references from the screen above, so the rule sits on the
   wrapper rather than on the list. */
.lesson-refs {
  margin-top: var(--sp-6); padding-top: var(--sp-4);
  border-top: 1px solid var(--border, #D8D6E0); max-width: var(--measure);
}
body.night-mode .lesson-refs { border-top-color: rgba(255,255,255,0.22); }

/* A cited reference that resolves. Anu, 12 October: "We will also need to link
   the research cited eventually as well."

   The WHOLE citation is the link, not a trailing "read it": a reference list
   is scanned rather than read, and a column of identical "read the paper"
   links at the end of every line is harder to use than the titles themselves.

   Underlined only on hover and focus. Fifteen underlined citations stacked on
   one another turn the block into a wall of rules, and the list already reads
   as references from its position and its heading. Colour alone is not the
   only signal - these sit inside an <ol> that announces what they are - and
   the underline is there the moment a pointer or the keyboard reaches one. */
.lesson-refs__link {
  color: var(--mim-purple-aa-dark); text-decoration: none;
}
.lesson-refs__link:hover,
.lesson-refs__link:focus-visible { text-decoration: underline; }
body.night-mode .lesson-refs__link { color: #cdbcff; }

.lesson-refs__title {
  margin: 0 0 var(--sp-3);
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(11px * var(--fs-scale)); letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--mim-purple-aa-dark);
}
body.night-mode .lesson-refs__title { color: #cdbcff; }
.lesson-refs .refs { margin-top: 0; padding-top: 0; border-top: none; }

/* A reference may now carry what the study found and a link to it, moved out
   of the inline evidence boxes on 12 October. The note is set a shade larger
   than the citation above it: the citation is the address, the note is the
   part anyone actually reads. */
.refs__note { margin: 5px 0 0; font-size: calc(13.5px * var(--fs-scale)); line-height: 1.55; }
.refs li .evidence__link { display: block; margin-top: 4px; }

body.night-mode .refs li { color: rgba(255,255,255,0.7); }
body.night-mode .refs { border-top-color: rgba(255,255,255,0.22); }

/* ── the estimate's verdict ─────────────────────────────────
   The payoff line of the whole activity, and the library sets it at body size
   where it read as a footnote to the thing the learner had just done. The
   engine writes the sentence as one text node, so the answer cannot be styled
   apart from the guess without an engine change - raised for Tom. Until then
   the whole verdict carries the weight. */
/* Anu, 30 September: "more space between the you guessed and 56% were offered
   no support at all. It's a bit crowded." The verdict and the sentence it
   explains are two separate statements arriving at the same moment, and the
   library stacks them at its own tight gap. */
/* Anu, 30 September, twice on this screen: more air between the slider and
   the answer. Measured, the verdict landed 26px under the result track and
   the whole reveal sat 38px off the button - close enough that the answer
   read as part of the control rather than as the payoff for using it. The
   reveal is a separate beat, so it gets a section's worth of space. */
.rtl-estimate__track { margin-top: 30px; }
.rtl-estimate__reveal { margin-top: var(--sp-7); }
.rtl-estimate__verdict + .body { margin-top: 22px; }
.rtl-estimate__verdict {
  font-family: var(--font-feature);
  font-size: calc(21px * var(--fs-scale));
  line-height: 1.3;
  color: var(--fg);
  border-left: 3px solid var(--mim-purple-aa);
  padding-left: 14px;
  margin-bottom: 18px;
}
body.night-mode .rtl-estimate__verdict { color: rgba(255,255,255,0.92); }

/* ── photocopy texture paths ───────────────────────────────────────────────
   THE KIT MASTER'S PATHS ARE WRONG. design-systems/men-in-mind/
   mim-design-system.css declares all three as
   url('assets/mim/mim/texture-photocopy-*.png') - a doubled "mim/" - and the
   files are at assets/mim/. Confirmed on the review server: the doubled path
   404s, the single one is 200.

   So every module carrying that kit has been rendering with NO photocopy
   texture at all, this one included, wherever --tex-photocopy-* is consumed:
   the engine's light video screens, .surface-white, and this module's
   .screen--lo and .screen--cinematic.

   Overridden here rather than in mim-design-system.css, because that file is a
   copy of the master and design-system-check.js compares the two - a fix there
   would read as drift and be overwritten by --fix. Raised for Tom; it belongs
   in the kit. */
:root {
  --tex-photocopy-black:  url('./assets/mim/texture-photocopy-black.png');
  --tex-photocopy-white:  url('./assets/mim/texture-photocopy-white.png');
  --tex-photocopy-purple: url('./assets/mim/texture-photocopy-purple.png');
  /* The kit ships the quotation mark but declares no token for it. */
  --img-mo-quote:         url('./assets/mim/mark-quotation.png');
}

/* ── lived-experience quotes ────────────────────────────── */
/* A quote and its attribution as one figure, not a blockquote followed by a
   loose paragraph - which is what these were, so nothing tied the voice to the
   words and the attribution rendered as ordinary body copy.

   The kit's own quotation mark opens each one. Two side by side on a wide
   screen, because they are a pair of voices saying the same thing from two
   sides, and stacking them buries the second. */

/* ONE PER ROW, not two abreast. Side by side each quote had half a measure to
   sit in - three or four words a line - and the pair read as a comparison
   table rather than as two men saying the same thing from two sides. */
.mo-quotes {
  display: flex; flex-direction: column;
  gap: clamp(26px, 3.2vh, 40px);
  margin: var(--sp-6) 0 var(--sp-5);
}

/* The mark hangs in the left margin rather than sitting above the words,
   which is what the full measure makes possible. It is absolute, so the
   blockquote and its figcaption stay the flex children and the caption
   still tucks under the quote it belongs to. */
.mo-quote {
  position: relative; margin: 0;
  padding-left: clamp(46px, 4.4vw, 66px);
  display: flex; flex-direction: column; gap: 10px;
}

.mo-quote::before {
  content: ""; position: absolute; left: 0; top: 0.3em;
  width: clamp(34px, 3vw, 46px); height: clamp(19px, 1.7vw, 25px);
  background: var(--img-mo-quote) left top / contain no-repeat;
}

.mo-quote blockquote {
  margin: 0;
  font-family: var(--font-feature); font-weight: var(--weight-regular);
  /* The lead's size, not a third step between it and the body. Screen 22 had
     six text sizes; the 19px quote sat between 16px body and 23px lead. Lora
     now says two things on a screen - the title, and a person speaking. */
  font-size: var(--fs-subhead); line-height: 1.32;
  letter-spacing: -0.01em; color: var(--fg);
}
body.night-mode .mo-quote blockquote { color: rgba(255,255,255,0.92); }

.mo-quote figcaption {
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(13px * var(--fs-scale)); line-height: 1.4;
  letter-spacing: 0.04em; color: var(--fg-muted);
}
body.night-mode .mo-quote figcaption { color: rgba(255,255,255,0.7); }

/* ── figures ───────────────────────────────────────────────────────────── */
.mo-figure { margin: 0 0 var(--sp-6); max-width: var(--measure); }
.mo-figure img { width: 100%; height: auto; display: block; border-radius: var(--radius-md); }

/* Diagrams and clean line illustrations read as reference material, not
   documentary photography - boxed and centred rather than run full-measure. */
.mo-figure--diagram {
  /* ⚠ SET HERE, not overridden earlier in the file. The first attempt at
     this added `.mo-figure--diagram { max-width: var(--measure) }` near the
     top, which this rule then beat - so screen 48's picture stayed small.
     Anu, 30 September, twice. */
  max-width: var(--measure); margin-left: auto; margin-right: auto;
  padding: var(--sp-5); background: var(--mim-grey-light); border-radius: var(--radius-md);
}
.mo-figure--diagram img { border-radius: var(--radius-sm); }
body.night-mode .mo-figure--diagram { background: #17171b; }

/* A portrait band (several faces) runs the full measure at a wide, short
   crop so it reads as one panorama rather than a single photograph. */
.mo-figure--band img { aspect-ratio: 21 / 6; object-fit: cover; }

/* A banner that runs the full width of the screen. The 820px measure and the
   side padding both live on .screen-inner, and .screen itself has neither, so
   this works by sitting OUTSIDE .screen-inner in the markup rather than by
   clawing its way back out with negative margins or 100vw - which would add a
   horizontal scrollbar as wide as the vertical one.

   Height is capped so the banner does not eat the screen on a wide monitor;
   object-fit crops rather than letterboxing. Square corners, because a rounded
   one against the viewport edge reads as a mistake. */
.mo-figure--bleed { max-width: none; margin: 0; }
.mo-figure--bleed img {
  border-radius: 0;
  aspect-ratio: 21 / 6;
  max-height: 340px;
  object-fit: cover;
}
@media (max-width: 680px) {
  .mo-figure--bleed img { aspect-ratio: 16 / 9; max-height: 220px; }
}

/* ── the statement screen's mark ─────────────────────────── */
/* The mark is the kit's own PNG, with its alpha intact, painted behind the
   line as the storyboard briefs it.

   ⚠ DO NOT PUT THIS BACK IN AN <img>. It was a flattened JPEG in a figure
   above the title, which is what the missing alpha forced: JPEG has no alpha
   channel, so the transparency became a black plate and mix-blend-mode:
   screen had to drop the black back out. That is also why it could not sit
   under the type - a blended plate greys whatever is over it.

   Decorative, so it is a background and carries no alt: the sentence is the
   content and a screen reader gaining "highlighter mark" here learns
   nothing. */
.screen--statement .title {
  position: relative;
  padding: clamp(10px, 1.6vh, 20px) clamp(14px, 1.6vw, 26px);
  /* ⚠ THE MARK TAPERS AT BOTH ENDS, so stretching it to exactly 100% puts
     the fade on the first and last letters - measured, mean alpha across the
     height is 240 in the middle but 9 near the right edge, and the right
     taper alone is 5.7% of the artwork's width. Overscanned so both tapers
     fall outside the text, which is also how a real highlighter overshoots. */
  background: url('./assets/mim/mark-highlighter-line-v2.png') center / 118% 104% no-repeat;
  /* ⚠ BLACK TYPE, NOT WHITE. The engine's .screen--dark .title is white, which
     is right on the dark ground and wrong on the mark: white on the brand
     lavender is about 1.9:1 and fails AA outright. Black on it is about 11:1.
     This is also the module's own convention - .mo-hl sets no colour because
     every other screen using the mark already has dark type on a light
     surface. */
  color: var(--mim-black);
}

/* A single portrait keeps an upright crop instead of being stretched to the
   shared measure width like a landscape photograph. */
.mo-figure--portrait { max-width: 320px; }
.mo-figure--portrait img { aspect-ratio: 3 / 4; object-fit: cover; }

/* ── pull quotes ───────────────────────────────────────────────────────────
   *italic* blocks that are ENTIRELY italic (rehearsal example phrasings, a
   divider's own aside) read as a beat apart from body copy, not just an
   emphasised sentence. Night mode does not redefine --fg, so this needs its
   own dark counterpart like every other class that leans on it. */
.pull-quote {
  margin: var(--sp-5) 0; padding-left: var(--sp-5); max-width: var(--measure);
  border-left: 3px solid var(--mim-purple-aa); color: var(--fg);
}
body.night-mode .pull-quote { color: rgba(255,255,255,.92); border-left-color: var(--mim-purple); }

/* ── hero ──────────────────────────────────────────────────────────────── */
.screen--hero.active { display: flex; padding: 0; max-width: none; overflow: hidden; }
.screen--hero { background: var(--mim-black); }
.mo-hero { position: relative; flex: 1; display: flex; align-items: flex-end; background: var(--mim-black); }
.mo-hero__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 58%; }
.mo-hero::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,.25) 0%, rgba(0,0,0,.15) 40%, rgba(0,0,0,.88) 100%); }
.mo-hero__inner { position: relative; z-index: 2; padding: clamp(28px,5vw,64px); max-width: 900px; }
.mo-hero__inner .title, .mo-hero__inner .heading, .mo-hero__inner .section-lead { color: #fff; }
.mo-hero__inner li { color: rgba(255,255,255,.94); }
/* The module line on a part divider, in MiM purple. It sits on the dark hero,
   where the kit's own --mim-purple has the contrast for it; the AA-dark
   recolour used on light surfaces would disappear here. */
.mo-hero__inner .body { color: var(--mim-purple); }

/* The hero backdrop is a permanent black scrim regardless of theme, so its
   part-label/pull-quote need the same fixed light-on-dark treatment as the
   title/heading/body above rather than the site-theme-driven variants. */
.mo-hero__inner .part-label { color: var(--mim-purple); }
.mo-hero__inner .pull-quote { color: rgba(255,255,255,.94); border-left-color: var(--mim-purple); }

/* ── cinematic landing (screen 1 only) ─────────────────────── */
/* Screen 1 opens the way MIM Pro for GPs Part 1 does: full-bleed image, scrim,
   photocopy texture, copy stacked bottom-left. Scoped to .screen--cinematic
   rather than .screen--hero, because the part-divider screens share
   .screen--hero and .mo-hero above and must keep that treatment.

   The [data-rise] entrance sits inside prefers-reduced-motion: no-preference,
   so a learner with reduced motion gets the copy already visible instead of
   stranded at opacity 0. The in-app reduced-motion setting is handled at the
   foot of this file, which compresses durations rather than killing the
   animation. */

.screen--cinematic {
  position: relative;
  height: calc(100vh - var(--header-h) - var(--footer-h));
  overflow: hidden;
  background: var(--mim-black);
  color: var(--mim-white);
}
.screen--cinematic.active { display: block; padding: 0; max-width: none; animation: none; }

.screen--cinematic .hero__media { position: absolute; inset: 0; }
.screen--cinematic .hero__media img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: 42% 42%;
  filter: saturate(0.96) contrast(1.03) brightness(0.94);
}

.screen--cinematic .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%);
}

.screen--cinematic .hero__tex {
  position: absolute; inset: 0;
  background: var(--tex-photocopy-black) center/cover;
  opacity: 0.45; mix-blend-mode: multiply;
}

.screen--cinematic .hero__inner {
  position: absolute; inset: 0; z-index: 2;
  display: flex; align-items: flex-start;
  overflow: auto;
}
/* margin-top:auto bottom-aligns the copy the way MIM Pro's does, but collapses
   to 0 once the stack is taller than the screen. align-items:flex-end would
   instead push the overflow off the top edge, out of reach of the scroll -
   which clipped the course title, because this landing carries the four
   objectives and MIM Pro's does not. */
.screen--cinematic .hero__inner-wrap {
  width: 100%; max-width: 1240px;
  margin: auto auto 0;
  padding: 56px 56px 52px;
}
.screen--cinematic .hero__copy {
  display: flex; flex-direction: column;
  align-items: flex-start; gap: 20px;
  max-width: 760px;
}

.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;
}
/* The same purple rule screen 7 puts under its title, aligned left here
   because this copy is stacked bottom-left rather than centred. The brand
   lavender, not the AA-dark recolour: this sits on the scrim, where the dark
   variant reads as near-black. */
.hx-title::after {
  content: "";
  display: block;
  width: clamp(48px, 5vw, 72px); height: 3px;
  margin: clamp(16px, 1.8vh, 24px) 0 0;
  border-radius: 2px;
  background: var(--mim-purple);
}

.hx-sub {
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(clamp(18px, 1.9vw, 23px) * var(--fs-scale)); 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: calc(15px * var(--fs-scale)); line-height: 1.6;
  color: rgba(255,255,255,0.72);
  margin: 0; max-width: 52ch;
}

/* This landing carries the four course objectives, which MIM Pro's does not.
   Same type as .hx-body so the list reads as part of that stack, with the MiM
   purple marker used elsewhere in the module. */
.hx-body--lead-in { color: rgba(255,255,255,0.86); }
.hx-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 9px;
  max-width: 62ch;
}
.hx-list li {
  position: relative; padding-left: 18px;
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(15px * var(--fs-scale)); line-height: 1.6;
  color: rgba(255,255,255,0.72);
}
.hx-list li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--mim-purple);
}

@keyframes hxRise { to { opacity: 1; transform: none; } }
@keyframes hxImg  { from { transform: scale(1.06); opacity: 0.4; } to { transform: scale(1); opacity: 1; } }

@media (prefers-reduced-motion: no-preference) {
  .screen--cinematic [data-rise] {
    opacity: 0; transform: translateY(16px);
    animation: hxRise 0.66s var(--ease-out) forwards;
    animation-delay: var(--d, 0ms);
  }
  .screen--cinematic .hero__media img { animation: hxImg 1.2s var(--ease-out) both; }
}

@media (max-width: 600px) {
  .screen--cinematic .hero__inner-wrap { padding: 60px 22px 36px; }
  .hx-title { font-size: clamp(36px, 12vw, 54px); }
}

/* ── module tiles (what this course covers) ─────────────────── */
/* The four modules as rectangular tiles rather than a run of headings and
   paragraphs. Two up on desktop, one up below 680px. Tiles size to their own
   content and the row stretches them to match, so the four read as a set. */

.mo-tiles {
  list-style: none; margin: 28px 0 32px; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
}
@media (max-width: 680px) {
  .mo-tiles { grid-template-columns: minmax(0, 1fr); gap: 14px; }
}

.mo-tile {
  display: flex; flex-direction: column; gap: 8px;
  padding: 22px 24px 24px;
  background: #fff;
  border: 1px solid var(--border);
  border-top: 3px solid var(--mim-purple-aa);
  border-radius: var(--radius-md);
}
body.night-mode .mo-tile {
  background: rgba(255,255,255,0.04);
  border-color: rgba(255,255,255,0.16);
  border-top-color: var(--mim-purple);
}

.mo-tile__num {
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(12px * var(--fs-scale));
  letter-spacing: 0.13em; text-transform: uppercase;
  /* --mim-purple-aa is AA for 24px+ only; this label is 12px, so it takes the
     dark variant. audit.js caught it at 4.1:1 against the tile's white. */
  color: var(--mim-purple-aa-dark); margin: 0;
}
body.night-mode .mo-tile__num { color: var(--mim-purple); }

.mo-tile__title {
  font-family: var(--font-feature); font-weight: var(--weight-regular);
  font-size: calc(23px * var(--fs-scale));
  line-height: 1.15; letter-spacing: -0.015em;
  margin: 0; color: var(--fg); text-wrap: balance;
}
body.night-mode .mo-tile__title { color: rgba(255,255,255,0.94); }

.mo-tile__body {
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(15px * var(--fs-scale)); line-height: 1.55;
  margin: 0; color: var(--fg-muted);
}
body.night-mode .mo-tile__body { color: rgba(255,255,255,0.78); }

/* ── the eyebrow, in purple ─────────────────────── */
/* Four screens carry an eyebrow and none of them had any other purple in the
   type. This is one rule instead of a mark per screen.

   The kit's `.screen--dark .eyebrow` is two classes deep and still wins, so
   eyebrows on dark surfaces stay white - which is right, purple on the
   cinematic scrim would disappear. AA-dark, not the brand lavender: an
   eyebrow is 12px and the lavender is an AA-large token. */
.eyebrow { color: var(--mim-purple-aa-dark); }
body.night-mode .eyebrow { color: var(--mim-purple); }

/* ── editorial beat ──────────────────────────────────────── */
/* A line where the course steps out and speaks to the learner about why a
   screen matters. Display face, a size up from body, air either side - and
   NO left rule, deliberately. .mo-stat and .keypoint-wrap both carry a purple
   rule, and a third on the same screen stops any of them meaning anything.

   Smaller than .keypoint (22px) so the screen's conclusion still outranks it. */
.mo-beat {
  font-family: var(--font-feature); font-weight: var(--weight-regular);
  font-size: calc(20px * var(--fs-scale));
  line-height: 1.35; letter-spacing: -0.01em;
  color: var(--fg);
  max-width: var(--measure);
  /* Anu, 30 September: the space around "Some days he doesn't feel like much
     of a man" on screen 12 "is too much white space." --sp-6 top and bottom
     is the gap between SECTIONS; the beat is a line inside one, and it was
     reading as though the screen had ended. */
  margin: var(--sp-5) 0 var(--sp-4);
}
body.night-mode .mo-beat { color: rgba(255,255,255,0.92); }

/* --pull is the beat given its full weight, for a screen that has no other
   purple rule competing with it. Screen 12's pivot line is the emotional turn
   of the whole scenario and it was reading at a size and colour that let the
   eye pass straight over it.

   The type stays --fg and the purple is the rule, not the words: a full
   sentence set in purple at this size reads as a system message rather than
   as Anthony. The brand lavender is too light for a 3px rule on white, so
   this is the AA-dark recolour, and night mode swaps back. */
.mo-beat--pull {
  font-size: calc(26px * var(--fs-scale));
  line-height: 1.3;
  padding-left: clamp(20px, 2.2vw, 30px);
  border-left: 3px solid var(--mim-purple-aa-dark);
  /* ⚠ SET HERE, not on `.mo-beat`. Anu asked for less space around
     screen 12's line on 30 September; that fix went on the base rule,
     which this modifier is declared after and overrode with 48px top
     and bottom - so the screen never changed. Anu, again, 12 October. */
  margin: var(--sp-5) 0 var(--sp-4);
}
body.night-mode .mo-beat--pull { border-left-color: var(--mim-purple); }

/* ── pulled-out statistic ──────────────────────────────── */
/* A figure set large beside the sentence it comes from.

   THE BIG NUMBER IS aria-hidden AND THE SENTENCE IS VERBATIM. The figure
   restates what the sentence already says, so it is decoration for the eye and
   a screen reader hears the claim once. Pulling the number out and shortening
   the sentence around it would read better and would be a rewrite of
   signed-off copy, so it is not done. */

.mo-stat {
  /* Anu, 12 October: "move the number to the middle of the line".
     A shared baseline between a 44-72px figure and 17px body text
     left the number hanging off the top of a three-line sentence. */
  display: flex; align-items: center; gap: clamp(18px, 2.4vw, 32px);
  margin: var(--sp-6) 0;
  padding-left: 18px;
  border-left: 3px solid var(--mim-purple-aa);
  max-width: var(--measure);
}
.mo-stat__figure {
  flex: 0 0 auto; margin: 0;
  font-family: var(--font-feature); font-weight: var(--weight-regular);
  font-size: calc(clamp(44px, 5vw, 72px) * var(--fs-scale));
  line-height: 0.95; letter-spacing: -0.03em;
  color: var(--mim-purple-aa-dark);
  font-variant-numeric: tabular-nums;
}
body.night-mode .mo-stat__figure { color: var(--mim-purple); }
.mo-stat__text {
  margin: 0;
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: var(--fs-body); line-height: 1.55; color: var(--fg);
}
body.night-mode .mo-stat__text { color: rgba(255,255,255,0.92); }

@media (max-width: 600px) {
  .mo-stat { flex-direction: column; gap: 10px; }
}

/* ── video tile ────────────────────────────────────────── */
/* MIM Pro for GPs Part 1 screen 14 - Tom's "LE Tiles" design of 20 September
   2026. A 16:9 still with a purple rule round it and a white light travelling
   that rule, then a solid caption strip beneath carrying the instruction and a
   filled purple play disc with a ring pulsing out of it.

   One still, not a cross-fading reel. MIM Pro rotates nine lived-experience
   portraits through some of its tiles and uses a single static image for the
   rest - Tom: "just use this static image" - and that is this case, because
   there is one frame from Anthony's film rather than a set.

   The engine's own .video-poster is absolutely positioned and .video-poster
   --styled adds big side padding to centre serif copy over a dark plate, so
   both have to be undone here or the picture is inset from its own frame. */

/* The engine's .video-frame is locked to aspect-ratio 16/9 with
   overflow: hidden, sized for a bare player. This tile is a 16:9 picture PLUS
   a caption strip, so the frame has to size to its content or the strip is
   clipped off at exactly the 16:9 line - which is what it did: the box
   measured 700x112 at y=839 while the frame ended at 839.

   MIM Pro gets there with a floated ::before of padding-top: 56.25%, which
   reserves a 16:9 minimum without setting aspect-ratio. The ratio here already
   comes from .vp-stage, so the frame just stops constraining. */
.video-frame[data-happy-frame] {
  aspect-ratio: auto;
  height: auto;
  overflow: visible;
}

.video-frame[data-happy-frame] > .video-poster {
  position: relative; inset: auto;
  display: block; height: auto;
  padding: 0;
  background: #0b1519;
  aspect-ratio: auto;
  overflow: hidden;
}

/* The picture window. It held a black screen for as long as there was no
   usable still: a frame of the wrong person is worse than no frame at all,
   and the only ones available were of other men while the copy beside this
   one names Anthony.

   Anu supplied frames from the films themselves on 12 October, so the window
   now carries one per poster, set inline on the element because each names a
   single file. The black stays underneath as the colour behind a picture that
   has not loaded yet. */
.vp-stage {
  position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  background: #000 center / cover no-repeat;
}
.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 */
  max-width: none;
  object-fit: cover;
  filter: saturate(0.82) contrast(1.06);
}
.happy-reel[data-n="1"] img { opacity: 1; }

/* The purple rule, and the white light handed from edge to edge. Each edge
   holds the light for a quarter of the 5200ms lap and is invisible for the
   other three quarters.

   .video-poster .vp-rule rather than .vp-rule alone: the engine's
   `.video-poster > div` is 0,2,0 and outranks a single class, which pulls the
   rule into the flow - an empty div with a 2px border, giving a stripe above
   the picture and no rule around it. */
.video-poster .vp-rule {
  position: absolute; inset: 0; z-index: 2;
  pointer-events: none;
  border: 2px solid rgba(183, 163, 252, 0.45);
  animation: vpRuleDraw 1600ms cubic-bezier(0.2, 0.7, 0.2, 1) 600ms both;
}
.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; }

/* 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;
  /* scaled, not the artboard's hard-coded 16px, 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 sets text-align: center on this element, so inheriting left
     from .vp-box never reaches it */
  text-align: left;
}
.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 vpRuleDraw {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}
@keyframes vpTraceR {
  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 {
  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 {
  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 {
  0%           { opacity: 1; background-position: 0 120%; }
  25%          { opacity: 1; background-position: 0 -20%; }
  25.01%, 100% { opacity: 0; background-position: 0 -20%; }
}
@keyframes vpPlayPulse {
  0%, 100% { transform: scale(1);    opacity: 0.5; }
  50%      { transform: scale(1.22); opacity: 0; }
}

/* Nothing here hides content at rest, so the reduced-motion handling only has
   to stop things moving. The still is opaque either way. */
@media (prefers-reduced-motion: reduce) {
  .video-poster .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 .video-poster .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; }

@media (max-width: 600px) {
  .video-poster .vp-box { flex-direction: column; align-items: flex-start; gap: 16px; padding: 16px 18px; }
  .video-poster .vp-box .video-poster__play { width: 60px; height: 60px; }
}

/* ── learning outcomes (MIM Pro .screen--lo) ──────────────── */
/* MIM Pro for GPs Part 1 screen 6: dark photocopy surface, a portrait band
   across the top, display title with the purple highlighter mark behind one
   word, arrow bullets in two columns.

   THE BAND IS FIVE PANELS OFF ONE PHOTOGRAPH. MIM Pro cycles nine separate
   images through each of its five panels; this shows five slices of a single
   image, positioned across it, so the hairline gaps and the divided-strip look
   are MIM Pro's while the storyboard's single brief - PLACEHOLDER-16,
   "portrait band, five faces" - stays a single file.

   display goes on .screen--lo.active, never on the bare class: the engine's
   .screen { display: none } is equal specificity and earlier in the cascade,
   so a bare display leaves this screen rendered while inactive. */

.screen--lo {
  padding: 0;
  background: var(--mim-black) var(--tex-photocopy-black) center / cover;
}
.screen--lo.active { display: flex; align-items: stretch; justify-content: flex-start; }
.lo-wrap { display: flex; flex-direction: column; width: 100%; }

/* MIM Pro's own height. The portraits are cut at 600x750, so a shallow band
   crops them through the chest and, at the height this was, through the top of
   a head. */
.lo-band {
  position: relative; flex: none;
  display: flex; gap: 2px; overflow: hidden;
  height: clamp(240px, 40vh, 420px);
  background: #0b1519;
}
.lo-portrait {
  position: relative; flex: 1 1 0; min-width: 0; height: 100%;
  overflow: hidden; background: #0b1519;
}
.lo-portrait img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; max-width: none;
  object-fit: cover;
  filter: contrast(1.04) saturate(0.9);
}
/* FIVE PANELS, NINE PORTRAITS EACH, CYCLING - MIM Pro's band as built.

   Every panel carries all nine portraits and cross-fades through them, eight
   seconds a picture, so one turn is 72s. The stagger is what keeps the strip
   from changing all at once, and what keeps a face off it twice over: panel i
   reaches picture j at t = 8j + 1.6i, so two panels can only coincide when i
   is the same, and no two are.

   ⚠ THE DELAYS ARE NEGATIVE, so every panel is already mid-cycle at load.
   Tom's note records what a positive stagger did: panels 3, 4 and 5 sat blank
   for their first seconds, and the first render was two photographs and three
   dark boxes.

   ⚠ THE CROSS-FADE PERCENTAGES ARE COMPUTED FROM THE NUMBER OF PICTURES.
   loSwap is nine: each is visible 11.111% of the turn and fades in over
   1.111%. A set of a different size needs its own keyframes, or the reel shows
   a black gap once a lap.

   object-position: center 22% frames the faces, because the portraits carry
   headroom above them. */
.lo-portrait img { object-position: center 22%; opacity: 0; }

@keyframes loSwap {
  0%      { opacity: 0; }
  1.111%  { opacity: 1; }
  11.111% { opacity: 1; }
  12.222% { opacity: 0; }
  100%    { opacity: 0; }
}

@media (prefers-reduced-motion: no-preference) {
  .lo-portrait img {
    animation: loSwap 72s linear infinite;
    animation-delay: calc(var(--j) * -8s - var(--i) * 1.6s);
  }
}
/* Nothing cycles for a learner who has asked for less motion, in either the
   OS setting or the module's own: the first portrait in each panel simply
   stays. Without this the reel leaves every image at opacity 0, because that
   is where loSwap starts and where the base rule above puts them. */
@media (prefers-reduced-motion: reduce) {
  .lo-portrait img:first-child { opacity: 1; }
}
body.reduced-motion .lo-portrait img { animation: none; opacity: 0; }
body.reduced-motion .lo-portrait img:first-child { opacity: 1; }

.lo-band::before {
  content: ""; position: absolute; inset: auto 0 0 0; z-index: 1;
  height: clamp(30px, 4.5vw, 64px);
  background: linear-gradient(to bottom, rgba(11,11,13,0), rgba(11,11,13,0.9) 78%, #0b0b0d);
  pointer-events: none;
}
.lo-band::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  height: 2px; background: var(--mim-purple);
  transform-origin: left center;
}
@media (max-width: 680px) {
  .lo-band { height: clamp(120px, 20vh, 190px); }
  .lo-portrait:nth-child(n+4) { display: none; }
}

.lo-body {
  flex: 1 1 auto;
  display: flex; flex-direction: column; justify-content: center;
  padding: clamp(20px, 3vh, 40px) clamp(24px, 5.5vw, 80px) clamp(24px, 3.5vh, 48px);
}

.lo-title {
  font-family: var(--font-feature); font-weight: var(--weight-regular);
  font-size: calc(clamp(34px, 3.9vw, 50px) * var(--fs-scale));
  line-height: 1.08; letter-spacing: -0.02em;
  margin: 0 0 clamp(8px, 1.2vw, 16px); color: var(--mim-white);
  text-wrap: balance;
}
.lo-hl {
  background: url('./assets/mim/mark-highlighter-line-v2.png') center 64% / 100% 76% no-repeat;
  padding: 0 0.12em 0.04em;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}

.lo-intro {
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(clamp(16px, 1.5vw, 21px) * var(--fs-scale));
  line-height: 1.3; letter-spacing: -0.01em;
  margin: 0 0 clamp(8px, 1.2vw, 16px); max-width: 82ch;
  color: rgba(255,255,255,0.9);
}
.lo-leadin {
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(16px * var(--fs-scale)); line-height: 1.4;
  margin: 0 0 clamp(10px, 1.4vw, 20px); color: rgba(255,255,255,1);
}

.lo-list-wrap {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: clamp(24px, 3vw, 52px); row-gap: clamp(8px, 1vw, 14px);
  align-items: start;
}
@media (max-width: 680px) { .lo-list-wrap { grid-template-columns: minmax(0, 1fr); } }

.lo-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: clamp(8px, 1vw, 14px);
}
.lo-list li {
  position: relative;
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(16px * var(--fs-scale)); line-height: 1.42;
  padding-left: clamp(18px, 2vw, 26px); color: rgba(255,255,255,0.85);
}
.lo-list li::before {
  content: ""; position: absolute; left: 0; top: 0.3em;
  width: clamp(9px, 1vw, 13px); height: clamp(7px, 0.8vw, 10px);
  background: url('./assets/mim/mark-arrow-1.png') center / contain no-repeat;
}

@keyframes lo-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes lo-fade { from { opacity: 0; transform: scale(1.04); } to { opacity: 1; transform: none; } }
@keyframes mimRule { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* The engine adds .lo-play on entry to any screen carrying .screen--lo, keyed
   off the class rather than a screen number. Every reveal sits inside
   no-preference: these start at opacity 0 with fill `both`, the shape that
   strands content when the animation never runs, and qa-reduced-motion.js does
   not inspect any of it. Written for any list length, unlike MIM Pro's fixed
   3 + 2 nth-child chain. */
@media (prefers-reduced-motion: no-preference) {
  /* The panel's own entrance. The pictures inside it are on loSwap, which is a
     separate animation on a separate element, so the two do not fight. */
  .screen--lo.lo-play .lo-portrait { animation: lo-fade 0.8s cubic-bezier(0.16,1,0.3,1) both; }
  .screen--lo.lo-play .lo-portrait:nth-child(1) { animation-delay: 0.05s; }
  .screen--lo.lo-play .lo-portrait:nth-child(2) { animation-delay: 0.14s; }
  .screen--lo.lo-play .lo-portrait:nth-child(3) { animation-delay: 0.23s; }
  .screen--lo.lo-play .lo-portrait:nth-child(4) { animation-delay: 0.34s; }
  .screen--lo.lo-play .lo-portrait:nth-child(5) { animation-delay: 0.45s; }
  .screen--lo.lo-play .lo-band::after { animation: mimRule 900ms cubic-bezier(0.2,0.7,0.2,1) 700ms both; }
  .screen--lo.lo-play .lo-title  { animation: lo-rise 0.55s cubic-bezier(0.16,1,0.3,1) 0.23s both; }
  .screen--lo.lo-play .lo-intro  { animation: lo-rise 0.55s cubic-bezier(0.16,1,0.3,1) 0.34s both; }
  .screen--lo.lo-play .lo-leadin { animation: lo-rise 0.55s cubic-bezier(0.16,1,0.3,1) 0.45s both; }
  .screen--lo.lo-play .lo-list li {
    animation: lo-rise 0.55s cubic-bezier(0.16,1,0.3,1) both;
    animation-delay: calc(0.5s + (var(--k, 0) * 0.06s));
  }
}

/* ── "what this course covers" ───────────────────────── */
/* A full-screen photograph with the four module tiles over it, sized so the
   whole screen arrives at once with nothing below the fold.

   The image is an <img> rather than a CSS background so the design brief can
   live in its alt, where the designer reads it, and so it keeps the
   placeholder-first convention - a real file dropped in at the same name needs
   no code change.

   display goes on .screen--covers.active, never on the bare class: the
   engine's .screen { display: none } is equal specificity and earlier in the
   cascade, so a bare display leaves this screen rendered while inactive. Third
   time this trap has come up in this build; mim-gp-shared.css:191 documents it.

   NOT sized with overflow: hidden. Every size here scales through --fs-scale,
   and a learner who turns the text up has to be able to reach the last tile,
   so this fits by being smaller and scrolls again once the text outgrows it. */
/* The dark ground is on the SCREEN, not only in the scrim. Two reasons, and
   neither is cosmetic: audit.js resolves an element's effective background by
   walking its ancestors, and an absolutely-positioned scrim is a sibling
   rather than an ancestor - so it read white type on the white page and called
   the title invisible. And if the photograph ever fails to load, the type is
   still on something it can be read against. */
.screen--covers { background-color: #08080a; }

/* No overflow: hidden here. On a flex container that centres its content, it
   clips at BOTH ends once the content is taller than the box, and the top of
   it becomes unreachable - the trap that cost the landing its title at v0.11.
   The image is clipped by its own wrapper instead, which is what actually
   needs clipping. */
.screen--covers.active {
  display: flex; flex-direction: column; justify-content: center;
  position: relative;
  padding: 0;
}

.covers__media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.covers__media img {
  width: 100%; height: 100%; max-width: none;
  object-fit: cover; object-position: center;
}
/* Dark enough for white type at AA, light enough that the photograph still
   reads as a photograph. */
.covers__scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(8,8,10,0.86) 0%, rgba(8,8,10,0.72) 45%, rgba(8,8,10,0.88) 100%);
}

.screen--covers .screen-inner {
  position: relative; z-index: 2;
  flex: none;
  max-width: 1100px;
  padding-top: clamp(20px, 3vh, 40px); padding-bottom: clamp(20px, 3vh, 40px);
}

/* The screen is a dark surface now, and the engine colours .title and the
   closing line from var(--fg), which night mode does not redefine either. */
/* Standard heading size - the engine's --fs-h1 - not a size cut down to help
   the screen fit. */
.screen--covers .title { color: var(--mim-white); text-align: center; }

/* A short purple rule under the title. Drawn rather than borrowed: the
   highlighter mark and the circle are both used elsewhere in the module, and a
   third word-level mark would start to read as a tic. A rule instead echoes
   the purple top edge on the four tiles below it and the rule under the
   outcomes band.

   The kit's --mim-purple, not the AA-dark recolour: this sits on the scrim,
   where the darker purple disappears. The tiles keep the dark one because they
   are light cards. Decoration, so contrast does not apply either way. */
.screen--covers .title::after {
  content: "";
  display: block;
  width: clamp(48px, 5vw, 72px); height: 3px;
  margin: clamp(14px, 1.6vh, 22px) auto 0;
  border-radius: 2px;
  background: var(--mim-purple);
}

/* margin-inline: auto as well as text-align. The engine gives .body
   max-width: var(--measure), so its BOX is narrower than this screen's 1100px
   container and sits hard left; centring the text inside that box still leaves
   the line off-centre on the screen. */
.screen--covers .body {
  color: rgba(255,255,255,0.82);
  text-align: center;
  margin-inline: auto;
}

/* Tighter than the default tile, because four of them plus a heading and the
   closing line have to share one screen. */
.screen--covers .mo-tiles { margin: clamp(18px, 2.6vh, 30px) 0; gap: 14px; }
.screen--covers .mo-tile { padding: 16px 18px; gap: 6px; }
.screen--covers .mo-tile__title { font-size: calc(20px * var(--fs-scale)); }
.screen--covers .mo-tile__body { font-size: calc(14px * var(--fs-scale)); line-height: 1.5; }

/* ── acknowledgement of country ────────────────────────── */
/* MIM Pro for GPs Part 1 screen 4, and deliberately plain there: flat black
   with the photocopy texture switched off, a purple title, white body copy
   centred on a 60ch measure. No figure and no animation. */

.screen--aoc { background-image: none; background-color: var(--mim-black); }

.aoc { max-width: 60ch; margin: 0 auto; }

.aoc__title {
  font-family: var(--font-feature);
  font-weight: 400;
  font-size: calc(clamp(34px, 3.9vw, 50px) * var(--fs-scale));
  line-height: 1.08;
  letter-spacing: -0.02em;
  color: var(--mim-purple);
  margin: 0 0 clamp(18px, 2.2vw, 32px);
}

.aoc__text {
  font-family: var(--font-primary);
  font-weight: 300;
  font-size: calc(clamp(18px, 1.72vw, 23px) * var(--fs-scale));
  line-height: 1.52;
  letter-spacing: -0.005em;
  color: rgba(255,255,255,0.84);
  margin: 0;
}
.aoc__text + .aoc__text { margin-top: 1.1em; }

/* ── FAQ accordion ────────────────────────────────────── */
/* Matching MIM Pro for GPs Part 1 screen 3. The card geometry is already
   right - this module uses the engine's promoted FAQ, which is the same look
   MIM Pro spends a block of its own stylesheet getting back to. Three things
   differ.

   1. THE SHADOW BAND UNDER AN OPEN QUESTION.
   The engine gives every pressable thing depth at `.screen button` (0,1,1),
   and that OUTRANKS its own `.accordion__summary { box-shadow: none }`
   (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, lying over the
   answer as soon as the question is expanded.

   Fixed by specificity rather than !important, as Tom does in MIM Pro: each
   selector beats exactly the engine rule it has to beat and disturbs nothing
   else.
     .screen .accordion__summary                  0,2,0  beats  .screen button
                                                                 0,1,1
     body.night-mode .screen .accordion__summary  0,3,0  beats  body.night-mode
                                                                 .screen button
                                                                 0,2,1
   Both halves, because the engine ships a night variant of the depth rule. */
.screen .accordion__summary,
.screen .accordion__summary:hover { box-shadow: none; }
body.night-mode .screen .accordion__summary,
body.night-mode .screen .accordion__summary:hover { box-shadow: none; }

/* THE SAME BAND, ON THE EVIDENCE PANEL. Tom's audit of 19 September found this
   in all 15 modules: the engine gives .evidence__row depth both through
   `.screen button` and through its own rule, and .evidence clips, so the
   shadow is cropped into a grey band lying across the citations as soon as the
   panel opens. Measured here before the fix: a 14px/30px shadow on the row of
   an open panel with the pointer nowhere near it.

   The rule Tom states, worth keeping rather than patching a third component
   later: A LIFTED, CLIPPING PANEL CARRIES THE ONLY SHADOW, and any control
   nested inside it is flat. Both halves again, because night mode ships its
   own variant of the depth rule. */
.screen .evidence__row,
.screen .evidence__row:hover { box-shadow: none; }
body.night-mode .screen .evidence__row,
body.night-mode .screen .evidence__row:hover { box-shadow: none; }

/* 2. NIGHT MODE.
   The engine's card takes `background: var(--bg)`, which stays white, while
   its own night rule turns the question text white - so the FAQ is a column of
   white cards carrying white text. The value is MIM Pro's. */
body.night-mode .accordion__item { background: #17171b; }

/* 3. THE PURPLE MOUSTACHE, Tom's round of 15 September 2026: "for the
   accordion buttons throughout the entire suite of modules - i'd like to
   implement a purple moustache on the left hand side".

   --img-mo-mark is an SVG, and an SVG loaded as a background cannot be
   recoloured, so it is used as a MASK with purple painted through it. Same
   artwork, same token, one colour different.

   The spacer it replaces is load-bearing: the engine puts a 22px pseudo
   element 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 without widening the right shifts 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; }

/* The purple has to lift off a near-black card, and the engine's 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 - a single tinted panel with its own left rule, not a question in a
   card - so it keeps the plain spacer and takes no moustache. This module has
   none today; the rule is here so that adding 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; }
}

/* ── the navigation screen's surface ──────────────────────── */
/* Anu, 12 October: "Screen 3 - can you remove the textured background and
   make it white." Flat white, and that settles it.

   FOURTH AND LAST ATTEMPT AT THIS SURFACE, so the history is worth keeping:
   black (v0.38) read as too dark; the purple texture (v0.40) separated it
   from the FAQ but the lavender was too much; the white photocopy grain
   separated the two by texture instead of tone, and the grain is now gone as
   well. The nav screen and the FAQ both sit on flat white, and what
   distinguishes them is the cards and the moustache marks - which the note
   here already said was doing the real work.

   .screen--nav is on screen 3 and nothing else in this module, so the rule is
   changed rather than overridden. */
.screen--nav {
  background-color: var(--mim-white);
  background-image: none;
}

/* ── navigation tutorial ─────────────────────────────── */
/* The engine styles the boxes themselves - .tutorial-step, __icon, __body,
   __title, __text, the hover and the focus ring. Everything here is what MIM
   Pro for GPs Part 1 adds on top, from Tom's round of 15 September 2026: each
   icon is a REPLICA of the control its row describes, so the learner is
   looking at the thing they will be looking for, rather than at seven
   identical purple chips.

   The header controls are transparent glyphs on a near-black bar, so a
   faithful copy on this light screen has to bring its own dark plate with it -
   otherwise it is a white glyph on white.

   Values are the live controls' own, per Tom's note:
     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 */

.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 points at a GESTURE, so there is no control to replicate.
   It keeps the engine's purple chip - which is now the thing that says so -
   and takes the same depth as the rest 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); }

/* Night mode. The engine has no rules for these boxes, so without this the
   card stays var(--mim-grey-light) on a dark screen - a light panel on black.
   Darkening the card means the title and body have to come with it: the engine
   sets them from var(--fg) and var(--fg-muted), and night mode redefines
   neither, which is the dark-on-dark trap. */
body.night-mode .tutorial-step { background: #17171b; border-color: rgba(255,255,255,0.18); }
body.night-mode .tutorial-step__title { color: rgba(255,255,255,0.92); }
body.night-mode .tutorial-step__text { color: rgba(255,255,255,0.7); }

/* Stack the icon above the copy on a phone, as MIM Pro does. */
@media (max-width: 640px) {
  .tutorial-step { flex-direction: column; gap: 12px; }
}

/* ── "how this course works" ─────────────────────────── */
/* Three statements and no image. After the two duplicated bullets came out at
   v0.29 it was a narrow column of black text hanging off the top of a wide
   white screen, so this is a composition as much as a colour.

   The purple is ATTACHED to content rather than floated as decoration - a
   highlighter mark behind one word of the heading, and the three lead
   sentences in the AA-dark purple. Every mark in the MiM kit is attached to
   something; a smear in an empty corner reads as a stray graphic.

   --mim-purple-aa-dark, not --mim-purple: these are 16px sentences on white,
   which is the small-text case. The kit's own purple measures about 2:1 here. */

.screen--works.active {
  display: flex; flex-direction: column; justify-content: center;
}
.screen--works .screen-inner {
  flex: none;
  max-width: 900px;
  padding-top: clamp(24px, 4vh, 56px); padding-bottom: clamp(24px, 4vh, 56px);
}

.screen--works .body strong { color: var(--mim-purple-aa-dark); }
body.night-mode .screen--works .body strong { color: var(--mim-purple); }

/* The kit's artwork as a background behind a word, stretched past the text
   box so the mark reads as a stroke across it rather than a block under it.
   Named for the mark rather than for one screen, because more than one screen
   wants it. */
.mo-hl {
  background: url('./assets/mim/mark-highlighter-line-v2.png') center 66% / 100% 74% no-repeat;
  padding: 0 0.14em 0.04em;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}

/* The highlighter carries 0.14em of padding each side so the pen mark
   clears the word. Immediately before a comma or a full stop that reads as
   a typed space - Anu, 12 October, of screen 40's "sequence ,".

   ⚠ THIS MUST SIT AFTER `.mo-hl`, NOT BEFORE IT. Both selectors are
   0,1,0, so source order decides, and the first attempt put this at line
   1902 while `.mo-hl` is declared at 2320 - the padding simply came back.
   Applied by markup to the three highlights that punctuation follows. */
.mo-hl--tight { padding-right: 0; }

/* ── course objectives ────────────────────────────────── */
/* Arrow-marked text, no cards. The front matter had grown four boxed screens
   in a row and the boxes had stopped meaning anything, so the arrangement
   stays and the boxes go.

   One class, two shapes: a single column by default, two with --split. The
   marker is the outcomes screen's arrow in the AA-dark recolour, because these
   sit on light surfaces. Naming it for the arrow rather than for the
   objectives screen is what stops the next list minting a third class for the
   same rule - the mistake .works-hl made before it became .mo-hl. */

.mo-arrows {
  /* ⚠ NOT `margin: 0`. That is a shorthand, so it also zeroes the top, and
     the engine's stacking rhythm for blocks inside .screen-inner is a
     `margin-top` at the same specificity in an earlier file - which this
     would silently win. The list then sits flush against the paragraph
     introducing it, which is the bug this replaced. */
  list-style: none; margin: var(--sp-5) 0; padding: 0;
  display: grid; grid-template-columns: minmax(0, 1fr);
  row-gap: clamp(14px, 1.8vh, 24px);
  align-items: start;
}
/* Anu, 29 September 2026: screen 15 "is very busy". Four reasons, each a bold
   lead plus two or three lines of explanation, stacked tight enough that the
   leads stopped doing their job. The list stays fully visible - it is clinical
   content and putting it behind clicks would be the wrong fix - and instead
   each lead breaks onto its own line with real air between the items, so the
   screen reads as four short sections rather than four dense paragraphs. */
/* Second pass, 29 September: airier bullets were still bullets. The markers
   come off and the four reasons run two across, each its own short section.
   No box and no fill - a text grid, not cards, which the standing decision
   keeps for screen 7's tiles. */
.mo-reasons {
  list-style: none; margin: var(--sp-6) 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: clamp(30px, 4vw, 60px);
  row-gap: clamp(26px, 3.2vh, 40px);
  align-items: start;
}
.mo-reasons li {
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(15.5px * var(--fs-scale)); line-height: 1.55;
  color: var(--fg);
  padding-top: 13px;
  border-top: 2px solid var(--mim-purple-aa);
}
.mo-reasons li > strong:first-child {
  display: block;
  font-family: var(--font-feature);
  font-weight: var(--weight-regular);
  font-size: calc(18px * var(--fs-scale));
  line-height: 1.25;
  letter-spacing: -0.01em;
  margin-bottom: 7px;
  color: var(--fg);
}
body.night-mode .mo-reasons li,
body.night-mode .mo-reasons li > strong:first-child { color: rgba(255,255,255,0.9); }
body.night-mode .mo-reasons li { border-top-color: #cdbcff; }
@media (max-width: 720px) {
  .mo-reasons { grid-template-columns: minmax(0, 1fr); row-gap: 24px; }
}

/* The five actions run two across on a wide screen, so the take-home point is
   a band under the grid rather than another tall column. */
.keypoint-list--wide { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(24px, 3vw, 48px); }
@media (max-width: 720px) {
  .keypoint-list--wide { grid-template-columns: minmax(0, 1fr); }
}

/* The take-home point: five instructions that were one paragraph. Same words,
   one per line, inside the same purple-ruled block. */
.keypoint--label { margin-bottom: 10px; }
.keypoint-list {
  list-style: none;
  margin: 0; padding: 0;
  display: grid; row-gap: 9px;
  max-width: var(--measure);
}
.keypoint-list li {
  position: relative; padding-left: 18px;
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(16px * var(--fs-scale)); line-height: 1.5;
  color: var(--fg);
}
.keypoint-list li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 7px; height: 7px; border-radius: 999px;
  background: var(--mim-purple-aa);
}
body.night-mode .keypoint-list li { color: rgba(255,255,255,0.9); }
body.night-mode .keypoint-list li::before { background: #cdbcff; }

.mo-arrows--split { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(28px, 4vw, 64px); row-gap: clamp(16px, 2.2vh, 30px); }
@media (max-width: 680px) {
  .mo-arrows--split { grid-template-columns: minmax(0, 1fr); row-gap: 16px; }
}

.mo-arrows li {
  position: relative;
  padding-left: clamp(22px, 2.2vw, 30px);
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(16px * var(--fs-scale)); line-height: 1.5;
  color: var(--fg);
}
body.night-mode .mo-arrows li { color: rgba(255,255,255,0.88); }

.mo-arrows li::before {
  content: ""; position: absolute; left: 0; top: 0.34em;
  width: 24px; height: 19px;
  background: url('./assets/mim/mark-arrow-1-aa.png') center / contain no-repeat;
}
body.night-mode .mo-arrows li::before {
  background-image: url('./assets/mim/mark-arrow-1.png');
}

/* ── the objectives screen, sized to one view ───────────────── */
/* Banner, title and four tiles inside calc(100vh - header - footer) at the
   default text size, so the screen arrives whole with nothing below the fold.

   NOT done with overflow: hidden. The engine's text-size control scales every
   size here through --fs-scale, and a learner who turns it up has to be able to
   reach the last tile. So this fits by being smaller, and still scrolls when
   the text outgrows it - which is the reflow that accessibility actually
   requires. */
/* Scales with viewport HEIGHT, not width: what this screen is short of is
   vertical room. A short laptop gets a shallow banner so the last tile stays
   clear of the footer; a tall monitor gets a deeper one so the screen is not
   two thirds empty. */
/* The banner grows to fill whatever the text block does not use, instead of
   the slack sitting between them as white space. Centring the block put equal
   space above the heading and below the tiles, and the space above read as a
   gap between two things rather than as breathing room.
   
   So: the figure flexes, .screen-inner is sized to its content, and the text
   stays exactly where centring put it. The band above the heading becomes
   photograph.

   display goes on .screen--objectives.active, not on the class alone: the
   engine's .screen { display: none } is equal specificity and earlier in the
   cascade, so a bare display here would leave this screen rendered while
   inactive, below the live one. Same trap .screen--lo hit at v0.13.

   The banner keeps a min-height and yields space back as the text grows, so a
   learner on a larger text size loses banner rather than losing tiles. */
.screen--objectives.active { display: flex; flex-direction: column; }

/* flex-basis 0, not auto. With auto the figure's base size is the image's own
   height at full width - 411px for a 21:6 crop on a 1440px screen - and
   flex-grow then adds the leftover on top, which overflowed the screen and
   brought back the scrollbar. Based at 0 it takes only what the text leaves,
   with min-height as the floor. */
.screen--objectives .mo-figure--bleed {
  flex: 1 1 0;
  min-height: clamp(110px, 16vh, 240px);
  overflow: hidden;
}
.screen--objectives .mo-figure--bleed img {
  height: 100%; max-height: none; aspect-ratio: auto;
  object-fit: cover;
}

.screen--objectives .screen-inner {
  flex: none;
  max-width: 1100px;
  padding-top: clamp(22px, 3vh, 40px);
  padding-bottom: clamp(30px, 6vh, 92px);
}

/* This screen is sized to one view, so the list takes no bottom margin: it is
   the last block on it, and the default would push the screen into scroll. */
.screen--objectives .mo-arrows { margin: clamp(24px, 4vh, 52px) 0 0; }

/* ── rehearsal ─────────────────────────────────────────────────────────────
   Practice is the spine of this course: 3 rehearsals here, 14 across the four
   modules. Authored once as a pattern so every later one matches. */
.reveal-btn {
  display: inline-block; margin: var(--sp-5) 0;
  padding: 12px 22px; border: 2px solid var(--mim-purple-aa);
  border-radius: var(--radius-pill); background: none; cursor: pointer;
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(15px * var(--fs-scale)); color: var(--mim-purple-aa-dark);
}
.reveal-btn:hover { background: rgba(132,99,248,.10); }
.rehearsal-panel[hidden] { display: none; }
.rehearsal-panel {
  border-left: 3px solid var(--mim-purple-aa); padding: var(--sp-4) 0 var(--sp-2) var(--sp-5);
  max-width: var(--measure);
}
/* Example phrasings are pull-quotes now (see above), nested one indent
   further in - drop the border so two purple bars don't sit side by side. */
.rehearsal-panel .pull-quote {
  border-left: none; padding-left: 0; margin: var(--sp-3) 0;
  font-family: var(--font-feature);
  font-size: calc(clamp(17px,1.7vw,20px) * var(--fs-scale)); line-height: 1.45;
}
body.night-mode .reveal-btn { color: var(--mim-purple); border-color: var(--mim-purple); }
body.night-mode .rehearsal-panel { border-left-color: var(--mim-purple); }

/* ── authored quiz ─────────────────────────────────────────────────────────
   A wrong answer ALWAYS reveals the correct one, in purple. Never green/red. */
.quiz-question { font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(17px * var(--fs-scale)); color: var(--fg); max-width: var(--measure); }
.quiz-options { display: flex; flex-direction: column; gap: var(--sp-3);
  max-width: var(--measure); margin: var(--sp-5) 0; }
.quiz-option {
  text-align: left; padding: 16px 20px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--mim-grey-light); font-family: var(--font-primary);
  font-size: calc(15px * var(--fs-scale)); line-height: 1.45; color: var(--fg);
}
.quiz-option:hover:not(:disabled) { border-color: var(--mim-purple-aa); }
.quiz-option:disabled { cursor: default; }
.quiz-option.correct,
.quiz-option.revealed-correct {
  border-color: var(--mim-purple-aa); background: rgba(132,99,248,.14);
  color: var(--mim-purple-aa-dark); font-weight: var(--weight-semibold);
}
.quiz-option.incorrect { border-color: var(--border-strong); opacity: .75; }
/* qa-quiz.js requires the revealed answer to carry a tick as well as the purple:
   colour alone must not be the only signal (WCAG 1.4.1). It looks for a
   ::after painted with mark-tick, which ships with the MiM design system. */
.quiz-option.correct, .quiz-option.revealed-correct { position: relative; padding-right: 56px; }
.quiz-option.correct::after, .quiz-option.revealed-correct::after {
  content: ""; position: absolute; right: 18px; top: 50%; transform: translateY(-50%);
  width: 22px; height: 22px;
  background: url("./assets/mim/mark-tick.png") center / contain no-repeat;
}
.quiz-feedback { max-width: var(--measure); margin-top: var(--sp-4);
  padding: var(--sp-4) var(--sp-5); border-radius: var(--radius-md);
  background: var(--mim-grey-light); }
body.night-mode .quiz-question { color: rgba(255,255,255,.92); }
body.night-mode .quiz-option { background: #17171b; border-color: rgba(255,255,255,.18); color: rgba(255,255,255,.9); }
body.night-mode .quiz-option.correct,
body.night-mode .quiz-option.revealed-correct { color: var(--mim-purple); border-color: var(--mim-purple); background: rgba(183,163,252,.16); }
body.night-mode .quiz-feedback { background: #17171b; }

/* ── part divider ──────────────────────────────────────────────────────── */

/* ── reduced motion ────────────────────────────────────────────────────────
   Never a blanket animation:none - it permanently hides opacity:0 reveals.
   Compress instead. Both entry points must stay in step. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-delay: 0ms !important; transition-duration: .01ms !important; }
}
body.reduced-motion *, body.reduced-motion *::before, body.reduced-motion *::after {
  animation-duration: .01ms !important; animation-delay: 0ms !important; transition-duration: .01ms !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE FILM PLAYER
   Added 2 October 2026, when screen 51's pause-and-choose went live on the
   shared component `_components/rtl-film-player.js`. Lifted verbatim from
   SHAReT Module 2's module.css so the two modules present the same interaction
   identically - a learner moving from one to the other should not be able to
   tell they were built two weeks apart.
   ═══════════════════════════════════════════════════════════════════════════ */
/* [screen 40] The few seconds to read the feedback before the film carries on.

   Anu, 1 October 2026: *"Once they choose the correct answer, give it a few
   seconds for them to read the options before resuming the film again."*

   A line and a control, not a modal: the feedback underneath it is what the
   learner is reading, so nothing may cover it. The button is there because
   anyone who has finished reading should not have to wait out a clock, and
   because a countdown with no way past it is the kind of small rudeness that
   accumulates over seventy-nine screens. */
.film-resume {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin: var(--sp-4) 0 0; padding: 10px 14px;
  border-left: 3px solid var(--mim-purple-aa);
  background: var(--mim-grey-light);
  font-family: var(--font-primary);
  font-size: calc(14px * var(--fs-scale)); line-height: 1.4;
  color: var(--fg);
}
.film-resume__text { flex: 1 1 auto; }
.screen .film-resume__now {
  flex: none; box-shadow: none;
  padding: 7px 14px; cursor: pointer;
  border: 1px solid var(--mim-purple-aa); border-radius: var(--radius-sm);
  background: transparent;
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(13px * var(--fs-scale));
  color: var(--mim-purple-aa-dark);
}
.screen .film-resume__now:hover { background: rgba(132,99,248,.12); }
body.night-mode .film-resume {
  background: #17171b; border-left-color: var(--mim-purple);
  color: rgba(255,255,255,.9);
}
body.night-mode .screen .film-resume__now {
  border-color: var(--mim-purple); color: var(--mim-purple);
}

/* [screen 40] The pause-and-choose rehearsal.

   The question is hidden with the `hidden` attribute rather than a class, so it
   is out of the accessibility tree as well as off the screen while the film is
   still running - a learner on a screen reader should not be read four options
   to a question they have not been asked yet. Nothing here may set `display` on
   `.film-question` without honouring `[hidden]`, or the attribute stops working
   and the answer appears above the film.

   When it arrives it arrives all at once, after the film has stopped, so it
   gets a little space above it and a short fade. The fade is suppressed under
   reduced motion by the engine's own global rule. */
.film-question { margin-top: var(--sp-5); }
.film-question:not([hidden]) { animation: filmQuestionIn .28s ease-out both; }
@keyframes filmQuestionIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* ⚠ THIS LINE IS THE ONLY THING A LEARNER SEES WHEN AN EMBED IS REFUSED, so it
   has to be legible in both themes. Night mode does not redefine `--fg`, which
   has already shipped as dark-on-dark three times in this module. */
.film-failed {
  margin: var(--sp-4) 0 0; padding: 12px 16px;
  border-left: 3px solid var(--mim-purple-aa);
  background: var(--mim-grey-light);
  font-family: var(--font-primary);
  font-size: calc(15px * var(--fs-scale)); line-height: 1.45;
  color: var(--fg);
}
body.night-mode .film-failed {
  background: #17171b; border-left-color: var(--mim-purple);
  color: rgba(255,255,255,.9);
}

/* ⚠ THE PLAYER NEEDS THE FRAME'S 16:9 RATIO PUT BACK. The engine gives
   `.video-frame` `aspect-ratio: 16/9`; the block at the top of this file
   overrides it to `auto` for `[data-happy-frame]`, because the poster there is
   a picture PLUS a caption strip and the frame has to size to its content. The
   consequence only appears once a film actually plays: all of the frame's
   height comes from the poster, the iframe is `position: absolute; inset: 0`
   and contributes none, so hiding the poster leaves the frame at 700x0 and the
   whole container disappears. Anu, 1 October 2026: *"When I press the play
   button, the whole video container disappears and nothing happens."*
   
   `PLACEHOLDER_VIDEO: true` concealed this for as long as nothing in this
   module ever built an iframe. The engine's own player would have hit it too.
   
   `.is-playing` is set by rtl-film-player.js when it mounts the player.
   Specificity: two classes (0,2,0) against a class and an attribute (0,1,1),
   so this wins without !important. */
.video-frame[data-happy-frame].is-playing {
  aspect-ratio: 16 / 9;
  height: auto;
  overflow: hidden;
}
/* The engine already absolutely positions `.video-frame iframe` to inset 0, so
   with the ratio restored the player fills the frame. This only removes the
   border and makes it a block. */
.video-frame iframe { display: block; border: 0; }

/* ── [screen 10] plain white behind the transcript ─────────────────────────
   The engine gives every video screen the photocopy texture —
   `.screen[data-type="video"]:not(.screen--multimedia)` in mim-gp-shared.css,
   repointed there on 2026-08-08 at the white texture that actually ships.

   The transcript panel has no surface of its own: `.hifh__transcript` is
   styled for width and margin only, so its background computes to
   rgba(0,0,0,0) and nine paragraphs of body copy land straight on the grain.
   Anu, 5 October 2026: *"make the background plain white — it's hard to read
   the transcript on a textured background."*

   Scoped to the attribute, not `#screen-10`: a rebuild renumbers screens, and
   `data-type="video"` is screen 10 and only screen 10 in this module. Same
   selector as the engine's, and module.css is imported after
   mim-gp-shared.css, so it wins on order without !important.

   ⚠ The colour is day-mode only. In night mode the screen keeps a transparent
   background and takes its colour from the body; forcing --mim-white here
   would light the screen up. Dropping the texture is right in both, since a
   white photocopy grain over the night background was never intentional. */
.screen[data-type="video"]:not(.screen--multimedia) {
  background-image: none;
  background-color: var(--mim-white);
}
body.night-mode .screen[data-type="video"]:not(.screen--multimedia) {
  background-color: transparent;
}

/* ── [screen 10] keep the frame when the ENGINE mounts the player ──────────
   The rule above restores the ratio on `.is-playing`, which rtl-film-player.js
   sets when IT mounts a player — that is screen 51. Screen 10 is on the
   engine's own `playVideo()` (`data-action="playVideo"`), and the engine never
   sets that class: `mim-gp-shared.js` appends the iframe and then does
   `poster.style.display = 'none'` and nothing else. Measured 2026-10-05: the
   frame goes 700x506 -> 700x0 and the film vanishes, the same fault Anu
   reported on 1 October for screen 51.

   `:has(iframe)` covers it without an engine change — the ratio comes back the
   moment a player exists, however it got there. Adding `.is-playing` inside
   `playVideo()` would fix it too, but that is `_components/`, so it would land
   in every module in the suite and is Tom's call rather than ours.

   `:has()` is already used three times in mim-gp-shared.css, so this needs no
   browser support the engine does not already assume. */
.video-frame[data-happy-frame]:has(iframe) {
  aspect-ratio: 16 / 9;
  height: auto;
  overflow: hidden;
}

/* ── [screen 3] the tutorial highlight must not follow the learner ─────────
   Anu, 5 October 2026: *"Screen 3 highlights the different buttons. When I
   click screen 4 the highlight still continues. It shouldn't."*

   `pulseTarget()` in mim-gp-shared.js puts `.btn-tutorial-hl--large` on the
   REAL header and footer buttons — `btnNext`, `btnPrev`, the menu, support,
   bug and settings icons — and takes it off again on a `setTimeout` of
   **9200ms**. Those buttons are page chrome: they live outside the screen and
   survive the screen change. Leave screen 3 inside that window and the outline
   travels with the learner. Reproduced: on screen 4, `btnNext` still computes
   `outline: rgb(183,163,252) solid 3px`.

   Worse, the animation is 0.9s x 6 = 5.4s while the class is removed at 9.2s,
   so the last ~3.8s is a STATIC purple ring, which reads as a stuck UI rather
   than a hint.

   The engine's own `goTo()` is the right home for a cleanup, but that is
   `_components/` and would land in every module in the suite - Tom's call.
   This does it with presentation only: the classes may linger, they simply do
   not render unless the tutorial screen is the one on screen.

   Keyed on `data-type="onboarding"` rather than `#screen-3` because a rebuild
   renumbers screens. `pulseTarget` has exactly two callers, `runNavTutorial`
   and the `tutorialStep` buttons, and both only run on this screen, so nothing
   else can want this highlight. Specificity (0,4,1) against the engine's
   (0,1,0), so no !important. */
body:not(:has(.screen[data-type="onboarding"].active)) .btn-tutorial-hl,
body:not(:has(.screen[data-type="onboarding"].active)) .btn-tutorial-hl--large {
  outline: none;
  animation: none;
  box-shadow: none;
}

/* ── transcripts start closed ──────────────────────────────────────────────
   Anu, 5 October 2026: *"the transcript is visible straightaway. It should
   only be visible once a learner clicks on read video transcript."*

   `toggleTranscript()` in mim-gp-shared.js flips `.open` on the panel and
   swaps the button label between "Read video transcript" and "Hide video
   transcript" — but **nothing in the engine's CSS ever responds to `.open`**,
   so the panel has always been visible and the button only ever changed its
   own wording. Measured 2026-10-05, every transcript in both modules:

     M1 screen 10  1141px   M1 screen 51   373px
     M2 screen  6  1697px   M2 screen 40   661px   M2 screen 42  2619px

   all `display: block` with `.open` absent. Screen 42 ships 2,619px of
   transcript under the film, under a button inviting the learner to read it.

   `display: none` rather than visibility or height, so the panel is out of the
   accessibility tree while closed — the toggle already carries
   `aria-expanded` and `aria-controls`, and a collapsed panel that screen
   readers still walk through would contradict both.

   The engine's own stylesheet is the right home, and ⚠ **Module 2 has the
   same fault and is not fixed by this** — it is module-local. Raised for Tom. */
.hifh__transcript:not(.open),
.transcript-panel:not(.open) { display: none; }

/* ── purple emphasis in body copy ──────────────────────────────────────────
   Anu, 5 October 2026, replacing black bold on screen 53.
   `--mim-purple-aa-dark`, NOT `--mim-purple-aa`: this sits in body copy at
   ~17px, and the AA-large purple is only good from 24px up. Same rule that
   caught the tile labels at 4.1:1. Weight stays at 600 so the sentence keeps
   the emphasis the bold was carrying. */
.mo-purple {
  color: var(--mim-purple-aa-dark);
  font-weight: var(--weight-semibold, 600);
}
body.night-mode .mo-purple { color: var(--accent-on-dark); }

/* ── [screen 5] Acknowledgement of Country, fit to the screen ──────────────
   Anu, 5 October 2026: *"Screen 5 - fit to screen."*

   The block was sized off viewport WIDTH - `clamp(28px, 3.4vw, 48px)` on the
   title, `clamp(15px, 1.42vw, 21px)` on the text - while the thing it has to
   fit inside is viewport HEIGHT. So it fitted at 1920x1080 and at 1280x800
   (narrow enough to shrink the type) and overran on the wide-but-short sizes
   in between. Measured overflow before this rule:

     1920x1080   0px        1536x864   94px
     1680x1050   0px        1440x900   44px
     1280x800    0px        1366x768  116px

   At 1440x900 the screen measured 816px into 772px of room, and 192px of that
   was `.screen-inner` padding, so the padding is the biggest lever.

   Scoped to short viewports and driven by `vh`, so tall screens keep the
   original composition untouched. `--fs-scale` is still honoured: at the
   larger text sizes this will scroll again, which is correct - the setting
   exists to be obeyed, not designed around. */
@media (max-height: 950px) {
  .screen--aoc .screen-inner {
    padding-top: clamp(24px, 4.2vh, 60px);
    padding-bottom: clamp(24px, 4.2vh, 60px);
  }
  .screen--aoc .aoc__title {
    font-size: calc(clamp(30px, 4.4vh, 48px) * var(--fs-scale));
    margin-bottom: clamp(10px, 1.7vh, 20px);
  }
  .screen--aoc .aoc__text {
    font-size: calc(clamp(18px, 2.7vh, 24px) * var(--fs-scale));
    line-height: 1.46;
  }
  .screen--aoc .aoc__text + .aoc__text { margin-top: 0.85em; }
}

/* ── Replay clip ───────────────────────────────────────────────────────────
   Anu, 5 October 2026. The pause mechanic takes Vimeo's scrubber away, so a
   learner gets one pass at a twenty-second clip and then has to answer a
   question that turns on what was said in it. This gives the pass back.

   Set on `.transcript-toggle`'s pill rather than a look of its own: the two
   sit side by side in `.video-controls`, which already centres them on the
   film, and two different pills on one row would read as two different kinds
   of control. Built by `_components/rtl-film-player.js`, which only adds it to
   pause-and-choose screens - a film played whole still has Vimeo's scrubber. */
.film-replay {
  background: none; border: 1px solid rgba(0,0,0,0.25); 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;
  transition: border-color var(--dur-base) var(--ease-standard),
              color var(--dur-base) var(--ease-standard);
}
.film-replay:hover { border-color: var(--mim-purple); color: var(--mim-purple-aa-dark); }
body.night-mode .film-replay { border-color: rgba(255,255,255,0.28); color: rgba(255,255,255,0.7); }
body.night-mode .film-replay:hover { border-color: var(--mim-purple); color: var(--mim-purple); }

/* ── the evidence accordions carry a book, not a Mo ────────────────────────
   Anu, 5 October 2026: *"The Mo icon appears in the evidence and references.
   I don't want this to appear on each accordion. Also can we change the icon
   itself from a Mo to a book?"*

   Nine accordions across seven screens carried the moustache mark, twice over
   on two of them. A brand mark repeated nine times inside one module stops
   reading as branding and starts reading as a bullet.

   Done as a MASK rather than the background image the engine uses, so the
   glyph takes its colour from this rule. That covers both themes in one
   declaration and lets the engine's night-mode `filter: invert(1)
   brightness(2)` be switched off - it was there to make a black PNG legible
   on dark, and inverting a colour chosen for dark would undo it.

   ⚠ THE SVG IS PERCENT-ENCODED. The first attempt inlined it raw; the
   unescaped < and > made the whole declaration invalid, the browser dropped
   it, and the Mo was still there with `mask: none` computed.

   The 44px grid column and the 28px box are untouched, so the row geometry
   and the centred label do not move. The glyph draws at 22px inside that box,
   the same optical weight as the mark it replaces.

   ⚠ The class is still `.evidence__mo`. Renaming it means touching the
   engine, both modules' markup and three builders for a cosmetic gain, so the
   name stays and this comment is the explanation. */
.evidence__mo {
  background-image: none;
  background-color: var(--fg-muted);
  -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='1.7'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%207C10.5%205.7%208.6%205%206.5%205H3v12h3.5c2.1%200%204%20.7%205.5%202'/%3E%3Cpath%20d='M12%207c1.5-1.3%203.4-2%205.5-2H21v12h-3.5c-2.1%200-4%20.7-5.5%202'/%3E%3Cpath%20d='M12%207v12'/%3E%3C/svg%3E") left center / 22px 22px no-repeat;
          mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='1.7'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%207C10.5%205.7%208.6%205%206.5%205H3v12h3.5c2.1%200%204%20.7%205.5%202'/%3E%3Cpath%20d='M12%207c1.5-1.3%203.4-2%205.5-2H21v12h-3.5c-2.1%200-4%20.7-5.5%202'/%3E%3Cpath%20d='M12%207v12'/%3E%3C/svg%3E") left center / 22px 22px no-repeat;
}
body.night-mode .evidence__mo {
  filter: none;                       /* the engine inverts a PNG that is gone */
  background-color: rgba(255, 255, 255, 0.72);
}

/* ── [screen 62] the resource list lies flat ───────────────────────────────
   Anu, 5 October 2026: *"Screen 62 - can we remove the shadow from the
   boxes?"*

   The engine gives `.screen label.resource-item__label` its `--depth-1`
   shadow, the same two-layer lift every pressable thing gets
   (mim-gp-shared.css:1644). Twenty-four of them stacked reads as twenty-four
   floating cards rather than one list to tick down.

   ⚠ THE SHADOW WAS THE ONLY THING GIVING THESE ROWS A SHAPE. Measured before
   touching it: background transparent, border none, radius 0. Take the shadow
   away on its own and the list collapses into twenty-four runs of text with
   nothing between them, which is worse than the problem. So a hairline
   replaces it - enough to separate the rows, no depth, and it does not move
   anything, because the border sits inside the padding the rows already have.

   The engine offers `.no-depth` for exactly this, but using it means adding a
   class in the builder for every item. One rule here is the smaller change
   and it keeps the opt-out visible beside its reason.

   The three buttons on this screen (Select all, Email all of them, View my
   reflections) keep their lift. They are buttons, and a button that still
   looks pressable while the list around it lies flat is the hierarchy, not an
   inconsistency. Said to Anu, hers to overrule. */
.screen label.resource-item__label,
.screen label.resource-item__label:hover {
  box-shadow: none;
}
.resources-list > li > .resource-item__label {
  border-bottom: 1px solid rgba(0, 0, 0, 0.10);
}
.resources-list > li:last-child > .resource-item__label {
  border-bottom: none;
}
body.night-mode .resources-list > li > .resource-item__label {
  border-bottom-color: rgba(255, 255, 255, 0.14);
}
body.night-mode .resources-list > li:last-child > .resource-item__label {
  border-bottom: none;
}

/* ── [screen 62] the primary resources action reads as the action ──────────
   Anu, 5 October 2026: *"change the colour of the text email my ticked
   resources to purple."*

   `--mim-purple-aa-dark`, not the decorative purple: this is a 15px button
   label and the AA-large pair is only good from 24px up.

   The disabled state needs nothing of its own. The engine greys the button
   out with `opacity: 0.45` rather than by setting a colour, so the purple
   fades with it and still reads as unavailable until a resource is ticked.

   The border is left black. Anu asked for the text; say the word and the
   border follows it. */
#emailTaggedBtn { color: var(--mim-purple-aa-dark); }
body.night-mode #emailTaggedBtn { color: var(--accent-on-dark); }

/* ── the wrong-answer cross is a glyph, not a disc ─────────────────────
   Anu, 7 October 2026, on Module 2 screen 19: *"the cross button doesn't look
   right. Can we just have the x without the circle?"* Carried here because the
   two modules share this component and she asked for her changes to flow
   through. Module 2 carries the identical rule.

   ⚠ THE TICK KEEPS ITS DISC, in both modules. She asked about the cross and
   only the cross. */
.quiz-option[data-fb].incorrect::after {
  background: none; color: #B3261E;
  width: auto; height: auto; border-radius: 0;
  font-size: calc(19px * var(--fs-scale)); font-weight: var(--weight-regular);
}
body.night-mode .quiz-option[data-fb].incorrect::after { color: #FF8A80; }

/* ── the film screen is plain, not textured ────────────────────
   Anu, 9 October 2026, on Module 2 screen 42: *"make it a plain white
   background instead of a textured one."* Carried here because screen 42 was
   built to match THIS module's pause-and-play screen, and leaving the texture
   on here would undo that match. Module 2 carries the identical rule.

   ⚠ THE TEXTURE IS TOM'S, NOT OURS. mim-gp-shared.css:243 puts the white
   photocopy texture on `.screen[data-type="video"]:not(.screen--multimedia)`.
   _components/ is off-limits, so this overrides it instead: the shared sheet
   is @imported at the top of this file, so an equal-specificity rule here
   wins on order. One screen in this module matches, screen 10. */
.screen[data-type="video"]:not(.screen--multimedia) {
  background-image: none; background-color: var(--mo-white, #fff);
}
body.night-mode .screen[data-type="video"]:not(.screen--multimedia) {
  background-color: transparent;
}


/* screen 53, six sentences in two columns
   Anu, 12 October: "can we present this information differently? It's a long
   list." The point of the screen is that there are six and that every one of
   them is ordinary, so they have to be visible together. A grid, not a
   reveal. */
.mo-unsaid {
  list-style: none; margin: var(--sp-5) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: var(--sp-4);
}
.mo-unsaid__item {
  background: var(--mim-grey-light); border-left: 4px solid var(--mim-purple);
  border-radius: var(--radius-md); padding: 14px 16px;
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(15px * var(--fs-scale)); line-height: 1.5; color: var(--fg);
}
body.night-mode .mo-unsaid__item { background: #17171b; }

/* screen 59, an image-quote with no quote
   The engine darkens the foot of every .image-quote so caption text stays
   legible. Screen 59 no longer carries a caption, so the gradient would be
   dimming the photograph for nothing. Equal specificity to the engine rule,
   and this sheet @imports that one at the top, so order decides it. */
.image-quote--plain::after { content: none; }


/* screen 45, bigger type and a monochrome purple ramp
   Anu, 12 October: "increase the font size of the text in the grey tiles. Can
   we have the tiles in monochrome purple shades?"

   The darkest step is --mim-purple-aa-dark and not --mim-purple-aa, because
   white on #8463F8 is 4.1:1 and fails AA at this size; white on #5D3CC9 is
   7.1:1. The text colour flips with that tile and only that tile. */
.mo-treat { font-size: calc(19px * var(--fs-scale)); }
.mo-treats .mo-treat { border-top-color: var(--mim-purple-aa-dark); }
.mo-treats .mo-treat:nth-child(1) { background: #EDE9FE; }
.mo-treats .mo-treat:nth-child(2) { background: #D5C9FD; }
.mo-treats .mo-treat:nth-child(3) { background: var(--mim-purple); }
/* Anu, 12 October, later the same day: "let's change the dark purple back to
   the lightest shade." The white-on-dark pair goes with it - the tile is pale
   again, so it takes the same body colour as the other three. */
.mo-treats .mo-treat:nth-child(4) { background: #EDE9FE; }
/* body.night-mode .mo-treat is (0,2,1) and the tints above are (0,3,0), so the
   tints survive into night mode but its near-white text would not be legible
   on them. Restated higher. */
body.night-mode .mo-treats .mo-treat { color: var(--mim-black); }

/* screen 46, rounder corners
   The engine rounds the two faces to --radius-lg and leaves .flipcard and
   .flipcard__inner square, and the square inner is what clips the card
   mid-flip. All four are rounded together. */
.effect-cards .flipcard,
.effect-cards .flipcard__inner,
.effect-cards .flipcard__front,
.effect-cards .flipcard__back { border-radius: 22px; }


/* lesson 1.2's photographs
   Anu, 12 October: "Lesson 1.2 doesn't have any images which makes it a bit
   monotonous compared to the other lessons."

   The accordion band is 3:1, cropped that way in make_lesson12_photos.py. A
   16:9 frame in a 656px accordion body opens to 369px of photograph above two
   lines of text, and the row stops being an accordion and becomes a slide. */
.accordion__img {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius-md); margin: 0 0 var(--sp-4);
}


/* screen 57, six reports as flip cards
   Anu, 12 October: "this is a long list too - can we present the info in a
   different way?"

   Its own class rather than .effect-cards. That one carries screen 46's icon
   sizing and its hand-placed nth-child columns for five cards, and borrowing
   another screen's arithmetic is exactly how screen 46 ended up with two sets
   of rules fighting each other. Six divides by three, so this needs no
   placement at all. */
.partner-cards { grid-template-columns: repeat(3, 1fr); gap: 16px; }
.partner-cards .flipcard { min-height: 230px; }
.partner-cards .flipcard,
.partner-cards .flipcard__inner,
.partner-cards .flipcard__front,
.partner-cards .flipcard__back { border-radius: 22px; }
/* The same override as screen 46, and for the same reason recorded there: the
   engine makes .flipcard__front black on purpose, which is wrong for a pale
   card carrying dark type. */
.partner-cards .flipcard__front {
  background: var(--mim-white); border-color: var(--border); color: var(--fg);
}
.partner-cards .flipcard__front,
.partner-cards .flipcard__back { padding: 18px 16px; }
.partner-cards .flipcard__front .partner-cards__name {
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(16px * var(--fs-scale)); line-height: 1.3;
  color: var(--fg); text-align: center;
}
.partner-cards .flipcard__front .flip-hint { margin-top: 12px; }
.partner-cards .flipcard__back p {
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(13px * var(--fs-scale)); line-height: 1.45; margin: 0;
  color: var(--fg); text-align: left;
}
@media (max-width: 600px) {
  .partner-cards { grid-template-columns: minmax(0, 1fr); }
}

/* A figure placed straight after a section-lead needs its own top margin.
   `.mo-figure` has `margin: 0 0 var(--sp-6)` - no top - which is right where a
   figure follows the h1, because the title brings its own space. `.section-lead`
   has no bottom margin either, so the two new photographs in lesson 1.2 sat
   hard against the copy above them. Scoped to the adjacency rather than added
   to .mo-figure: only screens 28 and 31 match, and widening it would reopen
   the gap on screen 47 that Anu asked to have closed. */
.section-lead + .mo-figure { margin-top: var(--sp-5); }


/* screen 25, the photograph in front of the click
   Anu, 12 October: "I want the image to be visible like what we had in module
   2 accordion I think." The banner sits above the summary row inside the
   item, so it is on screen from the start and the row still opens on to the
   text. .accordion__item has overflow visible and a radius, so the banner
   needs the top corners clipped to match it. */
.accordion__item--image { overflow: hidden; }
/* Held to a 5:1 band rather than shown at the crop's own 3:1. Three 219px
   photographs plus three rows plus the copy made screen 25 about 1050px tall
   CLOSED, so the third assumption was below the fold before a learner had
   touched anything. At 5:1 the whole screen fits, and the band still shows
   the clinician, which is the part of the frame that is doing the work. */
.accordion__banner {
  display: block; width: 100%; margin: 0;
  aspect-ratio: 5 / 1; object-fit: cover; object-position: center 42%;
}
.accordion__item--image .accordion__summary { padding-top: 16px; }

/* screen 57, six observations with nothing to click
   Anu, 12 October: "I am not liking this. Too many clicks. What else can we
   do?" Same answer as screen 53 - two columns, everything visible - but these
   carry a label as well as a sentence, so each tile has a heading. */
.mo-reports {
  list-style: none; margin: var(--sp-5) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: var(--sp-4);
}
.mo-reports__item {
  background: var(--mim-grey-light); border-left: 4px solid var(--mim-purple);
  border-radius: var(--radius-md); padding: 16px 18px;
}
.mo-reports__name {
  display: block; margin-bottom: 6px;
  font-family: var(--font-primary); font-weight: var(--weight-semibold);
  font-size: calc(15px * var(--fs-scale)); line-height: 1.3; color: var(--fg);
}
.mo-reports__item p {
  margin: 0;
  font-family: var(--font-primary); font-weight: var(--weight-light);
  font-size: calc(14px * var(--fs-scale)); line-height: 1.5; color: var(--fg);
}
body.night-mode .mo-reports__item { background: #17171b; }


/* a statement inside a content screen
   Anu, 12 October, of screen 57's last line: "let's have it like a
   statement." It was an <h2 class="heading">, the same element used for
   section labels like "Some phrasings that work", and it is not a label - it
   is the point the lesson has been building to.

   The proportions come from `.screen--statement .title`, which is screen 13,
   the module's one full-screen dramatic beat. This sits a step below it on
   purpose: centred, large and balanced, but inside a content screen rather
   than taking one over. Screen 13 stays the only statement screen. */
.mo-statement {
  /* --sp-5, not --sp-6: at 32px the statement pushed screen 57 to
     921px against a 900px viewport, which put a scrollbar on a screen
     that had just been rebuilt to fit without one. */
  margin: var(--sp-5) auto 0; max-width: 28ch;
  font-family: var(--font-feature); font-weight: var(--weight-regular);
  font-size: calc(clamp(24px, 2.9vw, 36px) * var(--fs-scale));
  letter-spacing: -0.02em; line-height: 1.14;
  text-align: center; text-wrap: balance; color: var(--fg);
}
.screen--dark .mo-statement, .screen--multimedia .mo-statement {
  color: var(--mim-white);
}


/* screen 17, a hotspot graphic built on an inline SVG
   Anu, 12 October: "let's make this a hotspot as the icons look nice. Similar
   to screen 48."

   Screen 48's picture is an <img> and takes `.mim-hotspots__img` from the
   engine. This one is an inline <svg>, which that rule does not reach, so the
   three declarations that matter are restated for it. Without them the SVG
   keeps its intrinsic size inside a figure that is line-height: 0, and the
   markers - positioned as percentages of the figure box - land nowhere near
   the cards. */
.mim-hotspots--diagram .mim-hotspots__figure { max-width: 640px; margin-inline: auto; }
.mim-hotspots--diagram svg { width: 100%; height: auto; display: block; overflow: visible; }


/* ── night mode, 12 October ────────────────────────────────────────────────
   From `node tools/audit.js "SHAReT Module 1 v6" --night`: 4 invisible, 29
   low-contrast. Day mode was clean.

   ⚠ THIS ENGINE'S NIGHT MODE DOES NOT REDEFINE --fg. It names selectors one
   at a time and sets white on each, so a component written the obvious way -
   `color: var(--fg)` - stays BLACK when night turns its background dark.
   Every component added on 12 October was written that way and needed its own
   rule. There is no token to inherit; the next new component will need one
   too. */

/* screen 3. .screen--nav has forced white since before 12 October, and night
   mode turns the text white, so the title and the lead were white on white.
   Transparent lets the page's own dark through. */
body.night-mode .screen--nav { background-color: transparent; }

/* screen 62. `.summary-resource-item.tagged .resource-item__text` is three
   classes and beats the engine's two-class night rule, so a TICKED resource
   went black on the dark panel. Invisible only since the conversation guide
   started arriving pre-ticked. */
body.night-mode .summary-resource-item.tagged .resource-item__text {
  color: rgba(255,255,255,0.92);
}

/* screens 53 and 57, the two visible-tile grids. Dark tile, light text. */
body.night-mode .mo-unsaid__item,
body.night-mode .mo-reports__name,
body.night-mode .mo-reports__item p { color: rgba(255,255,255,0.92); }

/* screen 57's closing statement. */
body.night-mode .mo-statement { color: rgba(255,255,255,0.92); }

/* screen 46's flip cards. ⚠ THE CARD STAYS PALE AT NIGHT. A dark card with
   light text would match the tiles above and hide all five icons, which are
   dark line drawings - the same reason the front overrides the engine's black
   default in day mode. Pale face, dark text, both themes. */
body.night-mode .effect-cards .flipcard__front {
  background: var(--mim-white); border-color: var(--border);
}
body.night-mode .effect-cards .flipcard__front .effect-cards__name,
body.night-mode .effect-cards .flipcard__front .flip-hint {
  color: var(--mim-black);
}
body.night-mode .effect-cards .flipcard__back {
  background: #17171b; border-color: rgba(255,255,255,0.18);
}
body.night-mode .effect-cards .flipcard__back p {
  color: rgba(255,255,255,0.92);
}


/* The activity library labels its inputs `visually-hidden`; the engine's
   stylesheet only ever defined `.sr-only`, so those labels have been rendering
   as visible body text - "Your estimate" on 14, "Your answer" on 16 and 25,
   and "the situation" / "the action" inside the sentence on 58.

   Same declarations as mim-gp-shared.css:928. Belongs in rtl-activities.css
   beside the markup that asks for it; that is the shared engine, so it sits
   here until Tom takes it. */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}


/* The questions join the module type scale.
   Anu, 12 October: "Screen 32 - the font is too big."

   `.reflect__prompt` is already on `--t-lead` up at line 75, with
   `.section-lead` and the rest of the lead voice. The LIST never joined the
   scale - it is still the engine's raw 20px (mim-gp-shared.css:536), a fifth
   of a pixel off being a lead itself, so the instruction and the questions it
   introduces carry the same weight. On screen 32 that is 113 words and five
   questions at near-lead size in a tinted panel.

   The questions become body copy, which is what they are. The prompt above
   them is left alone: it is not too big, it was never far enough above them.
   The numeral at :538 follows the text down or it ends up larger than the
   question it numbers.

   ⚠ One component, one size - so this is the box on 22, 27, 32, 43 and 60,
   though only 27 and 32 carry a list. See
   tools/sharet/m1_reflect_type_scale.py.

   FONT-SIZE ONLY, no colour: night mode names .reflect__prompt explicitly at
   :1048 and a var(--fg) here would black the box out after dark. */
.reflect ol li { font-size: var(--t-body); }
/* The numeral is absolutely positioned at the top of its item and sets a size
   but no line-height, so it inherited 1.35 and built an 18.9px line box against
   the question's 21.6px - same top edge, shorter box, baseline riding ~3px high.
   Anu: "the numbers ... appear out of sync with the questions." They were.
   Matching the question's line box puts the two baselines on the same line. */
.reflect ol li::before { font-size: 14px; line-height: calc(var(--t-body) * 1.35); }


/* A resource with nothing behind it keeps its place in the list but loses the
   checkbox, so it has to pick up the indent the label was providing.
   Anu, 12 October: "If it's something they aren't getting, then let's not have
   a checkbox for them to tick." See tools/sharet/m1_s62_resource_links.py. */
.resources-item--plain { padding-left: 34px; }
.resource-item__link--dl { margin-left: 12px; }


/* Room for the sticky footer when a hotspot scrolls itself into view.
   The Back/Continue bar is position:sticky and 68px tall, so a panel scrolled
   flush to the bottom of the viewport has its last lines underneath the
   navigation - which reads as the text being cut off rather than as something
   to scroll. scrollIntoView honours scroll-margin, so the listener added by
   tools/sharet/m1_hotspot_scroll_into_view.py needs to know nothing about it. */
.mim-hotspots__panel { scroll-margin-bottom: 84px; }
