/* Colours come from /shared/tokens.css, linked before this sheet. */

/* The stem's reading measure travels with the question: 16.5px+ and a capped
   line length is what makes a passage comfortable for a 10-12 year old. */
.question-stem { line-height: 1.7; margin-bottom: 24px; font-size: 19px; max-width: 780px; }
.question-stem p { margin: 0 0 10px; }

/* ── Single-select options ─────────────────────────────────────────────── */
.question-options { display: flex; flex-direction: column; gap: 12px; max-width: 640px; }
.option-row { display: flex; align-items: center; gap: 14px; cursor: pointer; padding: 7px 6px; border-radius: 6px; border: 1.5px solid transparent; font-size: 17.5px; line-height: 1.6; }
.option-row input { appearance: none; -webkit-appearance: none; flex: 0 0 auto; width: 28px; height: 28px; border-radius: 50%; border: 1.5px solid #b9bec8; background: #fefefe; box-shadow: inset 0 1px 3px rgba(0,0,0,0.12); cursor: pointer; margin-top: -2px; }
.option-row input:checked { background: radial-gradient(circle, var(--navy) 0 45%, #fefefe 52%); border-color: var(--navy); }
.option-row input:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
.option-row.correct { border-color: var(--correct-border); background: var(--correct-bg); cursor: default; }
.option-row.incorrect { border-color: var(--incorrect-border); background: var(--incorrect-bg); cursor: default; }
.option-correct-tag { margin-left: auto; font-size: 12px; font-weight: 700; color: var(--correct-text); white-space: nowrap; }

/* ── Cloze (dropdown + drag) ───────────────────────────────────────────── */
.cloze-select {
  display: inline-block; margin: 0 2px; padding: 4px 8px; border: 1.5px solid var(--navy);
  border-radius: 4px; background: #fff; font-size: 15px; max-width: 240px;
}
.cloze-select.part-correct { border-color: var(--correct-border); background: var(--correct-bg); }
.cloze-select.part-incorrect { border-color: var(--incorrect-border); background: var(--incorrect-bg); }
.drag-gap {
  display: inline-block; min-width: 130px; min-height: 28px; margin: 0 2px; padding: 3px 10px;
  border: 1.5px dashed #8a93a6; border-radius: 4px; background: #f7f8fa; vertical-align: middle;
  font-size: 15px; cursor: pointer; text-align: center;
}
.drag-gap.filled { border-style: solid; border-color: var(--navy); background: #fff; }
.drag-gap.drop-target { border-color: var(--navy); background: #e8ecf2; }
.drag-gap.part-correct { border-color: var(--correct-border); background: var(--correct-bg); }
.drag-gap.part-incorrect { border-color: var(--incorrect-border); background: var(--incorrect-bg); }
.drag-pool { margin-top: 20px; display: flex; flex-wrap: wrap; gap: 10px; padding-top: 14px; border-top: 1px dashed var(--pane-border); }
.pool-chip {
  border: 1.5px solid var(--navy); border-radius: 4px; background: #fff; padding: 8px 12px;
  font-size: 15px; cursor: grab; max-width: 100%; text-align: left;
}
.pool-chip.used { opacity: 0.35; cursor: default; }
.pool-chip.picked { background: var(--navy); color: #fff; }
.pool-hint { width: 100%; font-size: 12px; color: #666; }
/* Inline, not block — a block note after an inline gap would break the
   sentence it sits in onto a new line mid-flow. */
.gap-correct-answer { display: inline-block; font-size: 12px; color: var(--correct-text); margin: 0 4px; white-space: nowrap; }

/* ── Gap-list drag layout (whole-sentence cloze) ───────────────────────────
   Pool on top, labelled drop rows below — the passage keeps only a marker. */
.gap-marker { font-weight: 700; white-space: nowrap; }
.gaplist-pool { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; }
.gaplist-chip {
  text-align: center; padding: 10px 14px; font-size: 14px; line-height: 1.45;
  background: linear-gradient(#fdfdfd, #eef0f4); border: 1.5px solid var(--navy);
  border-radius: 4px; color: #1a1a1a; font-weight: 600; cursor: grab;
}
.gaplist-chip.used { opacity: 0.25; cursor: default; }
.gaplist-chip.picked { background: var(--navy); color: #fff; }
.gaplist-rows { display: flex; flex-direction: column; gap: 8px; background: #7b8db3; padding: 10px; border-radius: 4px; }
.gaplist-row { display: grid; grid-template-columns: 84px 1fr; gap: 10px; align-items: stretch; }
.gaplist-label { color: #fff; font-weight: 700; font-size: 15px; display: flex; align-items: center; justify-content: center; }
.gaplist-slot {
  min-height: 52px; background: #fff; border: 1.5px solid var(--navy); border-radius: 4px;
  padding: 10px 14px; font-size: 14px; line-height: 1.45; font-weight: 600;
  display: flex; align-items: center; justify-content: center; text-align: center; cursor: pointer;
}
.gaplist-slot.drop-target { background: #e8ecf2; }
.gaplist-row.part-correct .gaplist-slot { border-color: var(--correct-border); background: var(--correct-bg); }
.gaplist-row.part-incorrect .gaplist-slot { border-color: var(--incorrect-border); background: var(--incorrect-bg); }
.gaplist-row .gap-correct-answer { grid-column: 2; white-space: normal; }

/* ── Extract matching ──────────────────────────────────────────────────── */
.match-rows { display: flex; flex-direction: column; gap: 6px; max-width: 720px; }
.match-head { display: grid; gap: 8px; font-size: 12px; font-weight: 700; color: var(--navy); text-align: center; }
.match-row { display: grid; gap: 8px; align-items: center; padding: 10px 8px; border-radius: 6px; border: 1.5px solid #e3e6ec; }
.match-row:nth-child(even) { background: #f7f8fa; }
.match-statement { font-size: 15px; line-height: 1.5; }
.match-row input { appearance: none; -webkit-appearance: none; width: 22px; height: 22px; border-radius: 50%; border: 1.5px solid #b9bec8; background: #fefefe; cursor: pointer; justify-self: center; }
.match-row input:checked { background: radial-gradient(circle, var(--navy) 0 45%, #fefefe 52%); border-color: var(--navy); }
.match-row input:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
.match-row.part-correct { border-color: var(--correct-border); background: var(--correct-bg); }
.match-row.part-incorrect { border-color: var(--incorrect-border); background: var(--incorrect-bg); }
.match-correct-note { font-size: 12px; color: var(--correct-text); font-weight: 700; }
/* Dropdown variant (desktop) — mirrors the real test's per-statement select.
   The row is flex here, not grid, so the statement takes the slack and the
   select stays a fixed, predictable target. */
.match-rows-select .match-row { display: flex; gap: 14px; align-items: center; }
.match-rows-select .match-statement { flex: 1 1 auto; }
.match-select {
  /* Own arrow, drawn as a background image, with padding-right reserved for
     it. The native control renders its arrow ON TOP of the text at this width,
     so "Extract C" came out as "Extract C⌄" with the letter half-hidden —
     exactly the character the student is choosing. */
  flex: 0 0 auto; width: 112px; padding: 8px 26px 8px 10px; font-size: 15px; font-weight: 700;
  color: var(--navy); background: #fff; border: 1.5px solid var(--navy); border-radius: 4px;
  appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%231d2a5c' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 9px center; background-size: 10px 6px;
}
.match-select:disabled { color: #555; border-color: #b9bec8; background: #f4f5f7; }
.match-select:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }

/* ── Written response ──────────────────────────────────────────────────── */
.writing-wrap { max-width: 820px; }
.writing-toolbar {
  display: flex; align-items: center; gap: 4px; padding: 6px 8px;
  border: 1px solid var(--pane-border); border-bottom: none; border-radius: 6px 6px 0 0; background: #f7f8fa;
  position: relative;
}
.writing-toolbar button {
  min-width: 34px; height: 30px; border: 1px solid transparent; background: none;
  border-radius: 4px; font-size: 15px;
}
.writing-toolbar button:hover { background: #e8ecf2; border-color: var(--pane-border); }
/* ON. Deliberately stronger than :hover — hover is where the pointer is,
   this is what the caret is sitting inside, and the second is a fact about
   the writing rather than about the mouse. Inset shadow reads as pressed
   rather than merely tinted, which is what tells a child bold is still on
   three sentences later. */
.writing-toolbar button.is-active {
  background: #d6dfeb; border-color: #a9b7c9; color: #16324f;
  box-shadow: inset 0 1px 2px rgba(22, 50, 79, 0.22);
}
.writing-toolbar button.is-active:hover { background: #cbd7e6; }
/* The drawn icons. 15px to sit level with the B / I / U letterforms beside
   them, and vertically centred so the row reads as one line of controls
   rather than two. currentColor: one ink for the whole toolbar. */
.writing-toolbar .wt-icon {
  width: 15px; height: 15px; display: block; margin: 0 auto; color: #2b3440;
}
/* The numerals in the ordered-list icon. Drawn as text so they stay legible
   at 15px, where a hand-built glyph turns to mud. */
.writing-toolbar .wt-num {
  font-family: inherit; font-size: 5.4px; font-weight: 700;
  fill: currentColor; stroke: none;
}
.writing-toolbar-sep { width: 1px; align-self: stretch; margin: 2px 4px; background: var(--pane-border); }
.writing-size { height: 30px; border: 1px solid var(--pane-border); border-radius: 4px; background: #fff; font-size: 13px; padding: 0 6px; margin-right: 2px; }
/* Floated over the toolbar's right end, not laid out inside it. As a flex
   item it was fine on a wide screen and a hazard on a narrow one: in the
   split view with a reading text, the sentence wrapped the toolbar onto a
   second line and shoved the editor — and the words being typed — down by a
   row, then back up 2.5 seconds later. A transient message must never move
   the thing it is commenting on. */
.paste-notice {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  font-size: 12px; color: #B3261E; font-weight: 600; white-space: nowrap;
  background: #f7f8fa; padding-left: 10px; box-shadow: -8px 0 8px #f7f8fa;
  max-width: calc(100% - 16px); overflow: hidden; text-overflow: ellipsis;
}
/* Student-authored lists need their markers back — the reset strips them. */
.writing-editor ul, .writing-readonly ul { list-style: disc; margin: 0 0 10px 24px; }
.writing-editor ol, .writing-readonly ol { list-style: decimal; margin: 0 0 10px 24px; }
.writing-editor li, .writing-readonly li { margin-bottom: 4px; }
.writing-editor {
  /* Fill the screen for a 30-minute essay instead of floating as a small
     fixed box in dead space — clamped so short viewports still scroll the
     page, not lose the toolbar. */
  min-height: max(340px, calc(100dvh - 350px)); max-height: calc(100dvh - 290px);
  overflow-y: auto; padding: 16px 18px;
  border: 1px solid var(--pane-border); border-radius: 0 0 6px 6px; background: #fff;
  font-size: 16px; line-height: 1.8; outline: none;
}
.writing-editor:focus { border-color: var(--navy); }
.writing-editor p { margin: 0 0 10px; }
.writing-readonly { border-radius: 6px; background: #fbfbfc; }
.writing-status { display: flex; justify-content: space-between; margin-top: 6px; font-size: 12px; color: #666; }
.writing-mark { margin-top: 14px; padding: 12px 14px; border: 1px solid var(--pane-border); border-radius: 6px; background: #f7f8fa; font-size: 14px; }
.writing-comment { margin-top: 6px; white-space: pre-line; }

/* ── Inert preview surface ─────────────────────────────────────────────────
   The authoring preview runs the real renderers, so it has real radios,
   selects and a real contenteditable in it. Nothing in the preview may be
   answered or typed into: the JS side already refuses to persist, and this
   stops the author from being invited to try. */
.qr-inert { pointer-events: none; user-select: none; }
.qr-inert .writing-editor { min-height: 160px; max-height: 260px; }

/* ── Touch devices ────────────────────────────────────────────────────────
   Scoped to `pointer: coarse` so a mouse keeps the tighter, exam-like
   density and a finger gets targets it can actually hit. Measured on an iPad
   viewport before this existed: the gaps in the text were 28px tall, the
   answer chips 35px, the extract tabs 33px — all comfortably wide but none
   tall enough. Apple's floor is 44pt, and the person tapping is ten years old
   with a clock running.

   Padding only. No layout, no font sizes, nothing that could reflow a passage
   differently on one device than another — a reading test that wraps
   differently per device is a different paper. */
@media (pointer: coarse) {
  .pool-chip { min-height: 44px; padding-top: 8px; padding-bottom: 8px; }
  /* The other draggable chip. Same control, same job, and it was the one
     thing in here still landing near 40px — 10px of padding either side of a
     14px line. A gap-list question is nothing BUT these chips. */
  .gaplist-chip { min-height: 44px; padding-top: 11px; padding-bottom: 11px; }
  .drag-gap { min-height: 40px; padding-top: 7px; padding-bottom: 7px; }
  .option-row { padding-top: 11px; padding-bottom: 11px; }
  .writing-toolbar button { min-width: 44px; height: 44px; }
  /* iOS zooms the ENTIRE page when a form control under 16px is focused, and
     the student then has to pinch back mid-essay. The only fix is 16px. */
  .writing-size { font-size: 16px; height: 44px; }
  .cloze-select, .match-select { min-height: 44px; font-size: 16px; }
}

/* ── Rendered stem and passage content ─────────────────────────────────────
   Both apps open with `* { margin: 0; padding: 0 }`, which strips a <ul> of
   the indent its markers sit in — so the bullets were drawn OUTSIDE the box,
   in the authoring preview and, more to the point, on the student's paper.
   Paragraphs had no spacing either, which made a stem the paper printed in
   three parts arrive as one wall again after all the work to keep them.

   Here rather than in player.css or authoring.css because those two have
   already drifted apart on .content-block-html once, and a preview styled
   differently from the paper is the exact failure this file exists to stop. */
.content-block-html p { margin: 0 0 10px; }
.content-block-html p:last-child { margin-bottom: 0; }
.content-block-html ul,
.content-block-html ol { margin: 8px 0 10px; padding-left: 26px; }
.content-block-html ul { list-style: disc outside; }
.content-block-html ol { list-style: decimal outside; }
.content-block-html li { margin: 3px 0; }
.content-block-html ul:last-child,
.content-block-html ol:last-child { margin-bottom: 0; }

/* An imported diagram, at a size that fits the column it is in.
   `max-width: 100%` lived in player.css ONLY, so the authoring preview drew
   every figure at its natural pixel size — a 1500px orbit diagram running off
   the side of the pane and pushing the answer options out of reach. Exactly
   the drift this shared sheet exists to stop: the preview has to be the paper.

   max-height as well as max-width, because a tall figure that fits the width
   can still be taller than the screen, which puts the options below it out of
   reach on a laptop. */
.content-block-html img {
  display: block; max-width: 100%; max-height: 46vh; width: auto; height: auto;
  margin: 10px 0; border-radius: 4px;
}
/* THE SIZE AN AUTHOR CHOSE, honoured where the student actually reads it.
   The editor has had S / M / Full buttons for a while, writing .img-small and
   .img-medium onto the picture — and the two classes were defined only in
   05-queues.css, an AUTHORING stylesheet. So the size applied in the editor,
   looked right in the editor, and was silently full-size in the exam room and
   in every preview built from this file. Nobody noticed because the default is
   the one that looks deliberate. */
.content-block-html img.img-small { max-width: 40%; }
.content-block-html img.img-medium { max-width: 70%; }

/* A ROW OF FIGURES, printed side by side and imported as one paragraph.
   Papers draw two people facing each other, or three shapes to compare, on one
   line. Every crop used to get its own paragraph, so the row became a pile and
   the two people ended up one above the other, looking past each other.

   ONE CLASS, put on by two things. The importer writes .fig-row on the rows it
   builds, which is explicit and survives an edit; markFigureRows in
   content-render.js adds it to any paragraph that ends up with more than one
   picture in it — including one an author assembled by hand, pasting a second
   image beside the first.

   That second half used to be `p:has(img + img)` here, and it only worked on a
   2023 browser. On anything older the pictures stacked, so a question asking
   which of two shapes is larger showed them one above the other, looking past
   each other — the exact failure this rule exists to stop, quietly back for
   whoever had an older machine. Said at render time, it works everywhere.

   align-items: flex-end so figures of different heights stand on one baseline,
   the way they sit on the paper rather than floating at different levels. */
.content-block-html p.fig-row {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  gap: 14px; margin: 10px 0;
}
.content-block-html p.fig-row img {
  /* Share the line rather than each claiming the full width. The height cap is
     lower than a lone figure's because two of them are on screen at once. */
  margin: 0; flex: 0 1 auto; max-height: 34vh; min-width: 0;
}

/* ── A ROW OF FIGURES THAT ARE LABELLED ────────────────────────────────────
   The paper prints three ways to buy chocolates side by side, each with its
   price UNDER its picture. Without the caption the three pictures are three
   unexplained photographs, and the question cannot be answered — the label is
   part of the figure, not decoration beside it.

   A <figure> cell rather than more images in the same paragraph, because the
   picture and its caption have to move, wrap and stay together as one thing.
   The bare-image row above is untouched: the importer builds those, and a row
   of unlabelled crops is still the right answer for "which shape is larger".

   align-items: flex-start here, not flex-end: cells own their whole column
   now, and captions of different lengths should hang from a common top rather
   than pushing their pictures to different heights. */
.content-block-html .fig-row {
  display: flex; flex-wrap: wrap; align-items: flex-start;
  gap: 18px; margin: 12px 0;
}
.content-block-html .fig-row figure {
  margin: 0; flex: 1 1 0; min-width: 120px;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
}
/* ONE PICTURE BAND, so every caption in the row starts on the same line.
   Without it each figure is only as tall as its own picture, so a tall box and
   a small chocolate push their prices to different heights and the row reads as
   three separate things that happen to be near each other (John, 23 Aug). The
   paper this copies puts all three labels on one line, and it is the labels
   being level that makes them scan as one set of choices.

   A fixed BAND rather than stretching each figure: caption heights differ too
   — "1 piece of chocolate for $1.50" wraps where "Box of 20" does not — so
   equalising the whole cell would still leave the captions ragged. Fixing the
   picture area is what puts a common line under every one of them.

   object-fit: contain crops nothing; object-position: bottom stands the
   pictures on the band's floor, the way objects sit on a shelf rather than
   floating at different heights. */
.content-block-html .fig-row figure img {
  margin: 0; width: 100%; height: 132px;
  object-fit: contain; object-position: center bottom;
}
.content-block-html .fig-row figcaption {
  text-align: center; line-height: 1.35;
}

/* Tables the importer rebuilt from the grid printed on the paper. In the SHARED
   sheet, not the player's: the editor preview strips padding globally, and the
   last time a block element was styled in one place only, its bullets hung
   outside the box in preview and nowhere else.

   A wide table scrolls inside its own box rather than pushing the question out
   — a timetable with four columns is wider than the stem on a laptop. */
.content-block-html .q-table {
  border-collapse: collapse; margin: 20px 0; font-size: 17px;
  display: block; max-width: 100%; overflow-x: auto;
}
.content-block-html .q-table th,
.content-block-html .q-table td {
  /* Roomier than it was (7px 12px). John, 25 Aug, holding ours beside the
     source paper: "it is very tight, it will look better if it was more
     spaced out." The paper gives a data row about half again the height of
     its text, and a table a child reads under time should not be dense. */
  border: 1px solid var(--border); padding: 11px 16px; text-align: left;
  vertical-align: middle;
}
.content-block-html .q-table th { background: var(--sand-soft); font-weight: 600; }

/* ── A highlighted phrase ──────────────────────────────────────────────────
   The words a question is about, marked in the passage and marked again where
   the question quotes them. The pairing is the point: a ten-year-old finds
   what they are being asked about instead of hunting the passage for it.

   LIVES HERE, in the shared sheet, because the student and the author must see
   the same thing — the exam, the authoring preview and the answer sheet all
   load this file, so there is one yellow rather than three.

   Not --flag-gold: that is the FLAG colour on the tutor's screens and means
   "something needs you". This is a reading aid on a child's paper and means
   nothing of the sort, so it gets its own value — a paper highlighter's
   yellow, light enough to keep black text at full contrast on top of it. */
mark, .qr mark {
  background: #FFF3A8;
  color: inherit;
  /* A little room so the fill reads as a highlighter stroke rather than as a
     table cell, without moving the line it sits in. */
  padding: 0 2px;
  border-radius: 2px;
}

/* ── A scenario in a box ───────────────────────────────────────────────────
   The ruled rectangle a selective paper fences a scenario in, with the
   question underneath asking about it. A container, not a table: a one-cell
   table would announce "table, 1 row, 1 column" before a word of it. */
.content-block-html .q-box {
  border: 1.5px solid var(--brown-ink); border-radius: 2px;
  padding: 14px 18px; margin: 16px 0;
}
.content-block-html .q-box > :first-child { margin-top: 0; }
.content-block-html .q-box > :last-child { margin-bottom: 0; }

/* Table and column alignment, authored on the table bar. The source papers
   centre the whole grid on the page and centre the numbers inside their
   columns; neither is inferred from content, because a column of short
   values is as often labels as numbers. */
.content-block-html .q-table.is-centred {
  width: fit-content; margin-left: auto; margin-right: auto;
}
.content-block-html .q-table .ta-c { text-align: center; }

/* A blank cell — the corner of a two-way table. Still in the grid so the
   columns line up; no border, no shading, nothing to read as unfilled. */
.content-block-html .q-table .is-blank {
  border: none; background: transparent;
}

/* ── A picture answer sits in the same box as every other picture answer ───
   The EDITOR already boxes them (.option-pic, 4:3, contain). The student's
   screen had no rule at all, so each picture fell through to the generic
   image rule and rendered at its own natural width — a 560px crop beside a
   380px crop, four options at four sizes (John, 25 Aug).

   Sizing here is a RULE rather than a per-option choice, and deliberately so:
   an option larger than its neighbours reads as the answer. prepareOptionImage
   caps what is uploaded; this is what makes them all the same on the way out.
   The printed paper already does it — equal cells in _draw_option_pictures. */
.option-row .content-block-html img {
  /* A FIXED width, not 100%. The option row is a flex container, so the
     picture's parent is sized by its content — and a percentage width against
     a content-sized parent is circular and resolves to ZERO. Measured in the
     browser: every option rendered 0x0. The stylesheet read correctly either
     way, which is why this was found by measuring the box and not the CSS. */
  width: 260px; max-width: 100%; aspect-ratio: 4 / 3;
  height: auto; max-height: none;
  object-fit: contain; object-position: left center;
  margin: 4px 0;
}
/* And the size classes are OVERRULED inside an option, not merely outranked
   by source order — measured in the real store, 5 of 32 option pictures carry
   img-medium and 27 carry nothing, which is a second reason four options came
   out four sizes. S/M/Full is a stem control; in an option the box is the
   rule, so a class left on one by the stem tools cannot reintroduce the bias. */
.option-row .content-block-html img.img-small,
.option-row .content-block-html img.img-medium { max-width: 260px; }

/* Superscripts and subscripts, sized so cm² does not shove its line apart. */
.content-block-html sup, .content-block-html sub { font-size: 0.72em; line-height: 0; }


/* ── Bigger pictures, for a board a child cannot read at its own size ──────
   The options are already one per row; what caps them is the container's
   640px and each picture's own intrinsic width. Zoom lifts both, and
   because the generated options are VECTOR the result is larger and
   exactly as sharp — which is the whole reason this is worth having now
   and was not before.

   Nothing here moves an option or changes what clicking one does. The
   rows stay rows: an exam room is the worst place for a control that can
   swallow a tap meant for an answer. */
.option-zoom-row { margin: 10px 0 0; }
.option-zoom-btn {
  background: none; border: 1px solid currentColor; border-radius: 6px;
  padding: 4px 10px; font: inherit; font-size: 0.9em; cursor: pointer;
  color: inherit; opacity: 0.75;
}
.option-zoom-btn:hover, .option-zoom-btn:focus-visible { opacity: 1; }

.opt-zoomed .question-options { max-width: none; }
.opt-zoomed .question-options .content-block-html img {
  width: 100%; max-width: 720px; max-height: none;
}

/* ── Picture options, side by side (N10) ─────────────────────────────────
   On a 937x718 viewport a generated question showed the stem, the figure
   and option A; B, C and D were below the fold, and a child compared four
   pictures by scrolling between them. The printed page has never done
   that and neither does the real CBT: the four sit together, the same
   size, and the comparison is the question.

   SAME SIZE MEANS EQUAL BOXES, not equal pictures. The drawings have
   different aspect ratios — a net is wide, a cube is square — so each
   gets an identical box and is scaled to fit inside it. Making the
   PICTURES equal instead would mean cropping or stretching one of them,
   and a stretched net is a different net.

   The column count comes from the question (--picture-option-count),
   because a paper may hold four-option and five-option questions
   together: the count belongs to the question, and a sheet that assumed
   one number would be wrong on the other. */
.question-options.options-pictures {
  display: grid;
  grid-template-columns: repeat(var(--picture-option-count, 4), 1fr);
  gap: 10px;
  max-width: none;
  align-items: stretch;
  /* THE HEIGHT A PICTURE MAY TAKE. One number, read by the box and by
     the picture inside it, so the two cannot be set to different things.
     See the two values below for how it is chosen. */
  --option-box: clamp(150px, 46vh, 420px);
  /* THE SHAPE OF THE BOX, one for every option, set by question-render.js
     from the tallest picture's own ratio once the pictures have loaded.
     `auto` until then, which is the old behaviour: the box takes the
     height of its own picture. Declared here so it is never undefined. */
  --option-aspect: auto;
}
.options-pictures .option-row {
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 10px 8px;
  border-color: var(--pane-border);
  background: #fff;
  min-width: 0;
}
/* The box every drawing is fitted into. A viewport-relative cap so the
   four still clear the fold on a short laptop, floored so they do not
   collapse to thumbnails on a tall one. */
/* THE BOX GETS THE ROOM THE QUESTION ACTUALLY HAS. Two sizes, because
   these are two different pages: an ask whose stem carries a figure is
   sharing the screen with it, and an ask whose options ARE the question
   — which of these nets folds into a cube — has the rest of the screen
   doing nothing. Measured on the nets paper: a die net is tall and thin,
   and in the figure-sized box it came out about 24px across with half
   the screen empty below it. */
.question-options.options-pictures.beside-a-figure {
  /* SMALLER WHERE THERE IS A STIMULUS TO READ FIRST. The options were
     capped at 230px beside a 150px stimulus, so the four things a child
     compares AFTER understanding the question were each larger than the
     thing the question is. Ten pixels of option buys nothing; the same
     ten on a nine-cell matrix is the difference between reading it and
     guessing. */
  --option-box: clamp(96px, 22vh, 200px);
}
/* A CAP, NOT A HEIGHT. Fixed at the cap, a wide drawing sat in a tall
   box with dead space above and below it — the five-option `middle`
   questions were a 105px picture centred in a 368px card. Letting the
   box take the height its picture actually needs removes that, and the
   options stay identical for the reason they were identical before: the
   grid stretches every cell to the tallest, and four drawings from one
   renderer have one aspect ratio anyway. */
.options-pictures .option-body {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: auto;
  /* ONE SHAPE FOR EVERY BOX ON THE QUESTION. The cap-not-a-height note
     above assumed four drawings share a ratio; hand-made pictures do
     not, and an unshared ratio meant unequal cards with the radios at
     different heights. The ratio is the question's tallest picture, so
     the dead space that note removed stays removed for a renderer's
     matched set and appears only where a mixed set actually needs it. */
  aspect-ratio: var(--option-aspect);
  max-height: var(--option-box);
  min-width: 0;
}
.options-pictures .option-body .content-block-html { width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center; }
.options-pictures .option-body .content-block-html p { margin: 0; width: 100%;
  height: 100%; display: flex; align-items: center; justify-content: center; }
/* FILL THE BOX, both ways. The base option rule is a 260px 4:3 frame
   with `object-fit: contain`, which is right for a row and wrong for a
   cell: dropping to `width: auto` left `aspect-ratio` nothing to size
   from, and a drawing whose intrinsic size is small then rendered at
   that size — the die nets came out 24px wide inside a 208px box. So the
   box is the frame and the picture fills it, up as well as down, with
   `contain` keeping every aspect ratio honest. Centred, not left, since
   the cell is centred: `object-position: left center` is a rule for
   pictures stacked in a column with a radio beside them. */
.options-pictures .option-body img {
  display: block;
  width: 100%;
  /* 100% of a box that has a shape, so `contain` has two edges to fit
     against; where the box is still `auto` this resolves to auto and the
     picture takes its own height, as before. */
  height: 100%;
  max-width: 100%;
  max-height: var(--option-box);
  aspect-ratio: auto;
  object-fit: contain;
  object-position: center;
  margin: 0;
}
/* The radio sits under its picture, which is where the eye ends up after
   looking at the drawing. It keeps its size: it is the target a child
   taps under exam pressure and shrinking it to fit a column would be
   paying for the layout with the control. */
.options-pictures .option-row input { margin-top: 0; }
/* THE LETTER THE STEM ALREADY NAMED. Under the picture and beside the
   radio, which is where the eye lands after looking at the drawing and
   where a child's finger is going anyway. Big enough to read across a
   desk, because the thing it is for is saying "I put C" out loud. */
.options-pictures .option-letter {
  font-weight: 700;
  font-size: 17px;
  line-height: 1;
  /* No fallback: --navy is defined in tokens.css, which every page loading
     this sheet also loads. A fallback would hide the token going missing
     forever, which is what test_tokens forbids. */
  color: var(--navy);
  letter-spacing: 0.02em;
}
.options-pictures .option-row {
  /* the radio and its letter sit on one line under the picture */
  position: relative;
}
.options-pictures .option-correct-tag { margin-left: 0; }

/* THE FIGURE'S SHARE OF THE SAME SCREEN. Only where the options below
   are pictures — a reading passage's illustration and a maths diagram are
   untouched. `height: auto` keeps the aspect ratio, so a wide fold strip
   loses height and width together rather than being squashed.

   The two caps are chosen against the shortest screen this has to work
   on. At 718px tall the pane holds about 596: a 30vh figure is 215, a
   26vh option box makes a 245px card, and 74px of stem text plus margins
   comes to 558. At 800 it is 604 against 678. Both clear. */
.question-stem.stem-with-picture-options img {
  /* THE THING TO READ IS NOT THE SMALLEST THING ON THE PAGE.
     Measured on a matrix question: the stimulus drew at 150px square
     while each option drew at 157 — and the stimulus holds NINE cells
     where an option holds one glyph, so a child was comparing 40px
     cells against 157px ones. A five-frame sequence had the same
     shape of problem and wrapped into two rows of about 60px.
     The 30vh cap did that, and it was chosen when a stimulus was one
     small figure beside four options.
     Width as well as height now, so a wide strip uses the line it is
     given and stays on ONE row, and a square matrix grows until its
     cells are worth reading. The option box below is unchanged. */
  max-height: min(56vh, 500px);
  max-width: 100%;
  /* WIDTH, NOT JUST HEIGHT, AND IT IS ALLOWED TO GROW.
     Measured on the page: the stimulus PNG is 333px square and was
     drawn at 333 — `width: auto` lets a picture shrink and never
     grow — while each option PNG is 129px drawn at 230, upscaled 1.8x.
     So the four things a child chooses BETWEEN were being enlarged and
     the thing they must read was not, and a nine-cell matrix came to
     111px a cell against 230px options.
     Filling the line it has puts a 3x3 matrix at about 250px a cell,
     which clears the options. Both pictures are now drawn above their
     own pixels; the durable fix is to RENDER the stimulus larger, in
     abstract_render.py, which is another chat's file — recorded rather
     than reached for. */
  width: 100%;
  height: auto;
  object-fit: contain;
}
/* THE AUTHOR'S SIZE STILL WINS. The rule above is the default for a
   stimulus nobody sized, and it outranked the S and M classes by
   specificity: on the free test's T-shaped box (a 333px hand-imported
   figure with four picture options) the editor honoured S at 40% and the
   preview and the exam room drew it edge to edge, and nothing said why.
   `width: auto` here undoes the grow-to-fill, because a picture an author
   made small must be allowed to shrink. */
.question-stem.stem-with-picture-options img.img-small { width: auto; max-width: 40%; }
.question-stem.stem-with-picture-options img.img-medium { width: auto; max-width: 70%; }

/* Narrow screens cannot hold four across. Two-by-two keeps every option
   on one screen, which is the point; one per row is the old defect. */
@media (max-width: 720px) {
  .question-options.options-pictures { grid-template-columns: repeat(2, 1fr); }
}

/* ZOOM STILL MEANS ONE AT A TIME. "Bigger pictures" exists for a child
   who cannot make out a detail, and the honest answer to that is a
   larger drawing, not four larger drawings squeezed into the same width.
   So the grid stands down while it is on. */
.opt-zoomed .question-options.options-pictures {
  grid-template-columns: 1fr;
}
.opt-zoomed .options-pictures .option-body { height: auto; }
.opt-zoomed .options-pictures .option-body img { max-height: none; }
