diff --git a/frontend/src/components/QuestionReadingLinks.jsx b/frontend/src/components/QuestionReadingLinks.jsx
index 775721b..1ae7ec9 100644
--- a/frontend/src/components/QuestionReadingLinks.jsx
+++ b/frontend/src/components/QuestionReadingLinks.jsx
@@ -9,7 +9,7 @@ import api from '../api/client'
* the article's own sections for it — this used to ask for every linked
* article in full, prose and all, to print a title and a heading.
*/
-export default function QuestionReadingLinks({ questionId }) {
+export default function QuestionReadingLinks({ questionId, variant = 'list' }) {
const [links, setLinks] = useState(null)
useEffect(() => {
if (!questionId) { setLinks([]); return }
@@ -17,6 +17,25 @@ export default function QuestionReadingLinks({ questionId }) {
.then(res => setLinks(res.data)).catch(() => setLinks([]))
}, [questionId])
if (!links || links.length === 0) return null
+
+ // Under the right answer in the player, the same links are a row of chips —
+ // one control, plainly a door to an article — rather than a headed list,
+ // which at that point in the page reads as another section of explanation.
+ if (variant === 'chips') {
+ return (
+
Topic reading
diff --git a/frontend/src/pages/QuizPage.jsx b/frontend/src/pages/QuizPage.jsx
index 5db20f8..dcdcfce 100644
--- a/frontend/src/pages/QuizPage.jsx
+++ b/frontend/src/pages/QuizPage.jsx
@@ -2104,6 +2104,14 @@ const timerStarted = timeLeft !== null
)}
+ {/* The topic behind the right answer, offered where the
+ learner is already looking. Outside the option's
+ button rather than inside it, because a link nested
+ in a button is neither: the click would toggle the
+ explanation instead of opening the article. */}
+ {showCorrect && (
+
+ )}
{/* Outside the option, so ruling one out is never
mistaken for choosing it. Gone once the question is
marked — there is nothing left to narrow down. */}
@@ -2183,7 +2191,12 @@ const timerStarted = timeLeft !== null
)}
)}
- {current.option_explanations && Object.keys(current.option_explanations).length > 0 && (
+ {/* Gated on key points, not on option explanations. It asked
+ whether the *other* field was populated, so a question
+ with key points and no per-option reasoning showed none of
+ them — which is most of the bank, once anybody writes
+ them. */}
+ {(current.key_points || []).length > 0 && (
Correct Answer: {current.correct_answer}
diff --git a/frontend/src/pages/QuizPlayer.css b/frontend/src/pages/QuizPlayer.css
index 8a1c559..7dde923 100644
--- a/frontend/src/pages/QuizPlayer.css
+++ b/frontend/src/pages/QuizPlayer.css
@@ -932,3 +932,21 @@ body:has(.quiz-player.is-exam-chrome) .site-footer { display: none; }
/* The clocks, at the foot of the rail with everything else about the session
rather than about the question in front of you. */
.quiz-rail-foot { display: flex; align-items: center; }
+
+/* The topic behind the right answer, in the player. A chip rather than a
+ headed list: at that point on the page a heading reads as another section of
+ explanation, and what this is is a door. */
+.question-reading-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 4px 42px; }
+.question-reading-chip {
+ display: inline-flex; align-items: center; gap: 8px;
+ padding: 7px 13px; border: 1px solid var(--border); border-radius: 8px;
+ background: var(--card-bg); color: var(--text); text-decoration: none;
+ font-size: 0.85rem; font-weight: 600;
+}
+.question-reading-chip:hover { border-color: var(--primary); color: var(--primary); }
+.question-reading-chip span { color: var(--text-muted); font-size: 0.9rem; }
+.question-reading-chip:hover span { color: var(--primary); }
+
+@media (max-width: 640px) {
+ .question-reading-chips { margin-left: 0; }
+}