/*
 * Maths with Bhavana — the design system.
 *
 * WHY IT LOOKS LIKE THIS
 *
 * This is a teaching product. A student opens it to read a page of mathematics
 * for twenty minutes, often on a cheap Android phone, often on a school network,
 * sometimes in a classroom with the lights on and the screen at half brightness.
 * So the base is ink on paper rather than a dark gradient, the measure is capped
 * near 68 characters, the type scale is conservative, and there is exactly one
 * accent colour. Nothing here moves unless a person asked it to.
 *
 * NO EXTERNAL REQUESTS. There is no Google Fonts link and no CDN. The font stack
 * below is whatever the device already has, and the mathematics inherits KaTeX's
 * own fonts, which ship inside this plugin. A school network that blocks
 * fonts.googleapis.com — plenty do — must not be able to change how this reads.
 *
 * COLOUR IS NEVER THE SIGNAL ON ITS OWN. Every state that has a colour also has
 * a word, and usually a glyph as well: "Correct", "Mistake", "Instead". Around
 * one boy in twelve cannot separate the green from the red, and a revision page
 * whose whole meaning is carried by hue is useless to him. The greens, ambers
 * and reds below are additionally separated by lightness, so they stay distinct
 * in greyscale and on a projector.
 *
 * TOKENS FIRST. Everything below `:root` is stated once as a custom property.
 * Dark mode then redefines the tokens and nothing else — there is not a second
 * copy of the component rules anywhere in this file, which is the only way the
 * two themes can stay in agreement as the components grow.
 */

/* ------------------------------------------------------------------ */
/* Tokens                                                              */
/* ------------------------------------------------------------------ */

:root {
	/* Surfaces, from the page backwards. */
	--mwb-paper: #fbfaf7;
	--mwb-surface: #ffffff;
	--mwb-surface-sunken: #f2f1ec;
	--mwb-surface-raised: #ffffff;

	/* Ink. Body text sits above 12:1 on paper; muted stays above 4.5:1. */
	--mwb-ink: #1b1b1f;
	--mwb-ink-strong: #0c0c0f;
	--mwb-ink-muted: #5b5b66;
	--mwb-ink-faint: #74747f;
	--mwb-ink-inverse: #ffffff;

	/* Lines. */
	--mwb-line: #ddd9d0;
	--mwb-line-strong: #bcb7ac;

	/* One accent: a deep indigo that holds white text at any size. */
	--mwb-accent: #2f3a8f;
	--mwb-accent-strong: #232c6e;
	--mwb-accent-soft: #e8eaf6;
	--mwb-accent-ink: #ffffff;

	/*
	 * Semantic states. Each is given as a text colour, a background and a border
	 * so a component never has to invent a tint. The four hues are also four
	 * different lightnesses, which is what keeps them apart in greyscale.
	 */
	--mwb-correct: #10633f;
	--mwb-correct-bg: #e4f2ea;
	--mwb-correct-line: #93c4ac;

	--mwb-incorrect: #a11d15;
	--mwb-incorrect-bg: #fbe9e7;
	--mwb-incorrect-line: #e0a49e;

	--mwb-partial: #8a5000;
	--mwb-partial-bg: #fdf1dd;
	--mwb-partial-line: #ddb573;

	--mwb-pending: #414a56;
	--mwb-pending-bg: #eceef1;
	--mwb-pending-line: #b6bcc6;

	--mwb-danger: #a11d15;
	--mwb-danger-bg: #fbe9e7;
	--mwb-danger-line: #e0a49e;

	/* Type. A 1.2 scale — anything steeper turns a formula list into a poster. */
	--mwb-font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
		"Noto Sans", "Liberation Sans", Arial, sans-serif;
	--mwb-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
		"Liberation Mono", monospace;

	--mwb-text-xs: 0.75rem;
	--mwb-text-sm: 0.875rem;
	--mwb-text-base: 1rem;
	--mwb-text-lg: 1.125rem;
	--mwb-text-xl: 1.3125rem;
	--mwb-text-2xl: 1.5rem;
	--mwb-text-3xl: 1.875rem;

	--mwb-leading-tight: 1.25;
	--mwb-leading: 1.65;

	/* Space, on a 4px grid. */
	--mwb-space-1: 0.25rem;
	--mwb-space-2: 0.5rem;
	--mwb-space-3: 0.75rem;
	--mwb-space-4: 1rem;
	--mwb-space-5: 1.5rem;
	--mwb-space-6: 2rem;
	--mwb-space-7: 3rem;

	/* Radii and shadows. Restrained: this is paper, not glass. */
	--mwb-radius-sm: 4px;
	--mwb-radius: 8px;
	--mwb-radius-lg: 12px;
	--mwb-radius-pill: 999px;

	--mwb-shadow-sm: 0 1px 2px rgba(16, 16, 24, 0.06);
	--mwb-shadow: 0 1px 3px rgba(16, 16, 24, 0.08), 0 4px 12px rgba(16, 16, 24, 0.05);

	/* The reading measure, and the width of a page of cards. */
	--mwb-measure: 68ch;
	--mwb-page-width: 64rem;

	/* The smallest thing a finger may be asked to hit. */
	--mwb-touch: 44px;

	--mwb-focus: 0 0 0 3px var(--mwb-accent-soft), 0 0 0 5px var(--mwb-accent);
}

/*
 * Dark mode. Tokens only.
 *
 * The dark paper is a very dark blue-grey rather than black: pure black beside
 * KaTeX's hairline fraction rules makes them disappear on an OLED phone.
 */
@media (prefers-color-scheme: dark) {
	:root {
		--mwb-paper: #15161a;
		--mwb-surface: #1d1f25;
		--mwb-surface-sunken: #16171c;
		--mwb-surface-raised: #23262d;

		--mwb-ink: #e8e8ec;
		--mwb-ink-strong: #ffffff;
		--mwb-ink-muted: #a9aab4;
		--mwb-ink-faint: #8f909a;
		--mwb-ink-inverse: #15161a;

		--mwb-line: #33353d;
		--mwb-line-strong: #4b4e58;

		--mwb-accent: #9aa6f2;
		--mwb-accent-strong: #b6bef7;
		--mwb-accent-soft: #232945;
		--mwb-accent-ink: #12141f;

		--mwb-correct: #7fd3a8;
		--mwb-correct-bg: #14281f;
		--mwb-correct-line: #2f6047;

		--mwb-incorrect: #f5a29a;
		--mwb-incorrect-bg: #2c1815;
		--mwb-incorrect-line: #6d3630;

		--mwb-partial: #e8bd79;
		--mwb-partial-bg: #2a2013;
		--mwb-partial-line: #6b5227;

		--mwb-pending: #b9c0cc;
		--mwb-pending-bg: #1e2127;
		--mwb-pending-line: #444a55;

		--mwb-danger: #f5a29a;
		--mwb-danger-bg: #2c1815;
		--mwb-danger-line: #6d3630;

		--mwb-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
		--mwb-shadow: 0 1px 3px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.35);

		--mwb-focus: 0 0 0 3px var(--mwb-accent-soft), 0 0 0 5px var(--mwb-accent);
	}
}

/* ------------------------------------------------------------------ */
/* The root container                                                  */
/* ------------------------------------------------------------------ */

/*
 * Everything this plugin renders is inside `.mwb`, and every rule below is
 * scoped to it. The plugin lives inside somebody else's theme; it has no
 * business restyling that theme's header, and a bare `h2 { }` here would.
 */

.mwb {
	box-sizing: border-box;
	font-family: var(--mwb-font);
	font-size: var(--mwb-text-base);
	line-height: var(--mwb-leading);
	color: var(--mwb-ink);

	/*
	 * The container paints its own background, and this is the one place where
	 * this file deliberately imposes on the theme.
	 *
	 * The alternative — letting the theme's background show through — is fine
	 * until dark mode. The tokens above flip our ink to near-white when the
	 * device asks for a dark scheme, but a theme that has no dark mode of its own
	 * stays white underneath, and the whole page becomes pale grey text on white:
	 * measured at 2.3:1, which is unreadable and was a real result from a real
	 * screenshot, not a hypothetical. Painting `--mwb-paper` means our region is
	 * always internally consistent.
	 *
	 * In light mode the paper is a hair off white, so on an ordinary light theme
	 * the seam is invisible. On a dark theme the token is already dark and the
	 * seam is invisible the other way.
	 */
	background: var(--mwb-paper);

	max-width: var(--mwb-page-width);
	margin-inline: auto;
	/*
	 * A 16px gutter, and no horizontal page scroll at 360px. Every wide thing
	 * below — tables, the formula list — scrolls inside its own box instead.
	 */
	padding-inline: var(--mwb-space-4);
	padding-block: var(--mwb-space-4);
	overflow-wrap: break-word;
}

.mwb *,
.mwb *::before,
.mwb *::after {
	box-sizing: inherit;
}

/*
 * `hidden` has to keep working, and by default here it does not.
 *
 * The browser hides `[hidden]` with a `display: none` rule in its own stylesheet
 * — which any author `display` declaration beats, however low its specificity.
 * `.mwb-filter { display: grid }` is therefore enough to make the filter box
 * visible on a page with no JavaScript, where the whole point of rendering it
 * `hidden` was that it does nothing until the script reveals it. The same trap
 * catches the rows and chapter groups the filter hides as you type.
 *
 * An ancestor class rather than `!important`: (0,2,0) beats every component rule
 * in this file, and leaves `!important` available to whoever genuinely needs it.
 */
.mwb [hidden] {
	display: none;
}

.mwb > * + * {
	margin-block-start: var(--mwb-space-5);
}

.mwb p,
.mwb li {
	max-width: var(--mwb-measure);
}

/*
 * THE RULE THAT STOPS THE PAGE SCROLLING SIDEWAYS ON A PHONE.
 *
 * A grid or flex item defaults to `min-width: auto`, which means it refuses to
 * become narrower than its own content. A single long integral inside a card is
 * therefore enough to make its track 640px wide inside a 390px screen, and the
 * whole page — header, footer and all — acquires a horizontal scrollbar. The
 * `overflow-x: auto` further in, on the equation itself, never gets a chance to
 * apply because nothing ever asked the card to be narrow.
 *
 * Setting `min-width: 0` on the items lets them shrink, and the overflow is then
 * contained where it belongs: inside the equation's own scrolling box.
 */
.mwb-grid > *,
.mwb-list > li,
.mwb-topics > li,
.mwb-options > li,
.mwb-breadcrumbs li,
.mwb-badge-row li {
	min-width: 0;
}

.mwb h1,
.mwb h2,
.mwb h3,
.mwb h4 {
	line-height: var(--mwb-leading-tight);
	color: var(--mwb-ink-strong);
	margin-block: 0 var(--mwb-space-3);
	text-wrap: balance;
}

.mwb h1 { font-size: var(--mwb-text-3xl); }
.mwb h2 { font-size: var(--mwb-text-2xl); }
.mwb h3 { font-size: var(--mwb-text-xl); }
.mwb h4 { font-size: var(--mwb-text-lg); }

.mwb a {
	color: var(--mwb-accent);
	text-underline-offset: 2px;
}

.mwb a:hover {
	color: var(--mwb-accent-strong);
}

/* One focus treatment everywhere, and it is never removed. */
.mwb a:focus-visible,
.mwb button:focus-visible,
.mwb input:focus-visible,
.mwb select:focus-visible,
.mwb textarea:focus-visible,
.mwb [tabindex]:focus-visible {
	outline: 2px solid transparent;
	border-radius: var(--mwb-radius-sm);
	box-shadow: var(--mwb-focus);
}

.mwb code {
	font-family: var(--mwb-font-mono);
	font-size: 0.925em;
	background: var(--mwb-surface-sunken);
	padding: 0.1em 0.35em;
	border-radius: var(--mwb-radius-sm);
}

.mwb blockquote {
	margin: 0;
	padding: var(--mwb-space-3) var(--mwb-space-4);
	border-inline-start: 3px solid var(--mwb-accent);
	background: var(--mwb-surface-sunken);
	border-radius: 0 var(--mwb-radius) var(--mwb-radius) 0;
}

/* Screen-reader-only text, for the words that carry a state's meaning. */
.mwb-sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* ------------------------------------------------------------------ */
/* Page furniture                                                      */
/* ------------------------------------------------------------------ */

.mwb-page-head {
	border-block-end: 1px solid var(--mwb-line);
	padding-block-end: var(--mwb-space-4);
}

.mwb-page-head h1,
.mwb-page-head h2 {
	margin-block-end: var(--mwb-space-2);
}

/* The badges label the heading that follows, so they need to sit off it. */
.mwb-page-head .mwb-badge-row {
	margin-block-end: var(--mwb-space-3);
}

.mwb-lede {
	font-size: var(--mwb-text-lg);
	color: var(--mwb-ink-muted);
	margin: 0;
}

.mwb-meta {
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
	margin: 0;
}

/* Breadcrumbs. */
.mwb-breadcrumbs {
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
}

.mwb-breadcrumbs ol {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: var(--mwb-space-1) var(--mwb-space-2);
	margin: 0;
	padding: 0;
}

.mwb-breadcrumbs li {
	max-width: none;
	display: flex;
	align-items: center;
	gap: var(--mwb-space-2);
}

.mwb-breadcrumbs li + li::before {
	content: "/";
	color: var(--mwb-ink-faint);
}

.mwb-breadcrumbs [aria-current="page"] {
	color: var(--mwb-ink);
	font-weight: 600;
}

/* ------------------------------------------------------------------ */
/* Buttons                                                             */
/* ------------------------------------------------------------------ */

/*
 * Every button rule is scoped `.mwb .mwb-btn` rather than `.mwb-btn`, and that
 * is not tidiness — it is the fix for a bug that got as far as a screenshot.
 *
 * `.mwb a { color: … }` further up is specificity (0,1,1): one class plus one
 * element. A bare `.mwb-btn--primary` is (0,1,0), so the link colour won, and
 * every primary button rendered as an indigo block with indigo text on it. The
 * label was there, correctly marked up, and completely unreadable. Adding the
 * ancestor class takes these to (0,2,0), which beats it.
 */
.mwb .mwb-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--mwb-space-2);
	/* min-height, not height: the label must be allowed to wrap on a phone. */
	min-height: var(--mwb-touch);
	padding: var(--mwb-space-2) var(--mwb-space-5);
	border: 1px solid transparent;
	border-radius: var(--mwb-radius);
	font: inherit;
	font-weight: 600;
	line-height: 1.3;
	text-align: center;
	text-decoration: none;
	cursor: pointer;
	background: var(--mwb-surface);
	color: var(--mwb-ink);
	transition: background-color 120ms ease, border-color 120ms ease;
}

.mwb .mwb-btn--primary {
	background: var(--mwb-accent);
	border-color: var(--mwb-accent);
	color: var(--mwb-accent-ink);
}

.mwb .mwb-btn--primary:hover {
	background: var(--mwb-accent-strong);
	border-color: var(--mwb-accent-strong);
	color: var(--mwb-accent-ink);
}

.mwb .mwb-btn--secondary {
	background: var(--mwb-surface);
	border-color: var(--mwb-line-strong);
	color: var(--mwb-ink);
}

.mwb .mwb-btn--secondary:hover {
	border-color: var(--mwb-accent);
	color: var(--mwb-accent);
}

.mwb .mwb-btn--quiet {
	background: transparent;
	border-color: transparent;
	color: var(--mwb-accent);
	padding-inline: var(--mwb-space-3);
}

.mwb .mwb-btn--quiet:hover {
	background: var(--mwb-accent-soft);
}

.mwb .mwb-btn--danger {
	background: var(--mwb-danger-bg);
	border-color: var(--mwb-danger-line);
	color: var(--mwb-danger);
}

.mwb .mwb-btn--danger:hover {
	border-color: var(--mwb-danger);
}

.mwb .mwb-btn[disabled],
.mwb .mwb-btn[aria-disabled="true"] {
	opacity: 0.55;
	cursor: not-allowed;
}

.mwb .mwb-btn-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--mwb-space-3);
}

/* ------------------------------------------------------------------ */
/* Cards                                                               */
/* ------------------------------------------------------------------ */

.mwb-card {
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius-lg);
	padding: var(--mwb-space-5);
	box-shadow: var(--mwb-shadow-sm);
}

.mwb-card > * + * {
	margin-block-start: var(--mwb-space-3);
}

.mwb-card h2,
.mwb-card h3 {
	margin-block-end: 0;
}

/*
 * A responsive grid with no media query. `auto-fit` plus `minmax` means one
 * column at 360px and three on a laptop, and the `min()` stops the track from
 * demanding 18rem on a 360px screen — which is what produces a page that
 * scrolls sideways.
 */
.mwb-grid {
	display: grid;
	gap: var(--mwb-space-4);
	grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
}

.mwb-grid--wide {
	grid-template-columns: repeat(auto-fit, minmax(min(24rem, 100%), 1fr));
}

/* ------------------------------------------------------------------ */
/* The chapter card                                                    */
/* ------------------------------------------------------------------ */

.mwb-chapter-card {
	display: flex;
	flex-direction: column;
	gap: var(--mwb-space-3);
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius-lg);
	padding: var(--mwb-space-5);
	box-shadow: var(--mwb-shadow-sm);
	transition: border-color 120ms ease, box-shadow 120ms ease;
}

.mwb-chapter-card:hover,
.mwb-chapter-card:focus-within {
	border-color: var(--mwb-accent);
	box-shadow: var(--mwb-shadow);
}

.mwb-chapter-card__number {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.25rem;
	height: 2.25rem;
	padding-inline: var(--mwb-space-2);
	border-radius: var(--mwb-radius);
	background: var(--mwb-accent-soft);
	color: var(--mwb-accent);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

.mwb-chapter-card__title {
	font-size: var(--mwb-text-lg);
	margin: 0;
}

/*
 * The whole card is the target. The link is stretched over it so that a thumb
 * anywhere on the card works, while the accessible name stays the chapter name
 * rather than "click here" — screen readers still read one link.
 */
.mwb-chapter-card__title a {
	text-decoration: none;
	color: var(--mwb-ink-strong);
}

.mwb-chapter-card__title a::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
}

.mwb-chapter-card {
	position: relative;
}

.mwb-chapter-card__summary {
	color: var(--mwb-ink-muted);
	margin: 0;
	flex: 1 1 auto;
}

.mwb-chapter-card__stats {
	display: flex;
	flex-wrap: wrap;
	gap: var(--mwb-space-2) var(--mwb-space-4);
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
	border-block-start: 1px solid var(--mwb-line);
	padding-block-start: var(--mwb-space-3);
	margin: 0;
	list-style: none;
}

.mwb-chapter-card__stats li {
	max-width: none;
	font-variant-numeric: tabular-nums;
}

.mwb-chapter-card__stats strong {
	color: var(--mwb-ink);
}

/* ------------------------------------------------------------------ */
/* Badges and pills                                                    */
/* ------------------------------------------------------------------ */

/*
 * A badge always contains its own word. The colour repeats what the word says;
 * it never replaces it. See the file header.
 */
.mwb-badge {
	display: inline-flex;
	align-items: center;
	gap: var(--mwb-space-1);
	padding: 0.15em 0.6em;
	border: 1px solid var(--mwb-line-strong);
	border-radius: var(--mwb-radius-pill);
	background: var(--mwb-surface-sunken);
	color: var(--mwb-ink-muted);
	font-size: var(--mwb-text-xs);
	font-weight: 600;
	letter-spacing: 0.01em;
	line-height: 1.6;
	white-space: nowrap;
}

.mwb-badge--accent {
	background: var(--mwb-accent-soft);
	border-color: var(--mwb-accent);
	color: var(--mwb-accent);
}

.mwb-badge--correct {
	background: var(--mwb-correct-bg);
	border-color: var(--mwb-correct-line);
	color: var(--mwb-correct);
}

.mwb-badge--incorrect {
	background: var(--mwb-incorrect-bg);
	border-color: var(--mwb-incorrect-line);
	color: var(--mwb-incorrect);
}

.mwb-badge--partial {
	background: var(--mwb-partial-bg);
	border-color: var(--mwb-partial-line);
	color: var(--mwb-partial);
}

.mwb-badge--pending {
	background: var(--mwb-pending-bg);
	border-color: var(--mwb-pending-line);
	color: var(--mwb-pending);
}

/* Difficulty. Five bands, each with its own word already in the element. */
.mwb-badge--foundation,
.mwb-badge--basic {
	background: var(--mwb-correct-bg);
	border-color: var(--mwb-correct-line);
	color: var(--mwb-correct);
}

.mwb-badge--moderate {
	background: var(--mwb-partial-bg);
	border-color: var(--mwb-partial-line);
	color: var(--mwb-partial);
}

.mwb-badge--advanced,
.mwb-badge--higher_order {
	background: var(--mwb-incorrect-bg);
	border-color: var(--mwb-incorrect-line);
	color: var(--mwb-incorrect);
}

.mwb-badge-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--mwb-space-2);
	list-style: none;
	margin: 0;
	padding: 0;
}

.mwb-badge-row li {
	max-width: none;
}

/* ------------------------------------------------------------------ */
/* Tables                                                              */
/* ------------------------------------------------------------------ */

/*
 * `.mwb-table-scroll` is emitted by the Markdown renderer around every table it
 * produces. It is what stops a six-column table of standard integrals from
 * pushing the whole page sideways on a phone.
 */
.mwb-table-scroll {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
	max-width: 100%;
}

.mwb-table-scroll table {
	border-collapse: collapse;
	width: 100%;
	min-width: 28rem;
	font-size: var(--mwb-text-sm);
	background: var(--mwb-surface);
}

.mwb-table-scroll th,
.mwb-table-scroll td {
	text-align: start;
	padding: var(--mwb-space-3);
	border-block-end: 1px solid var(--mwb-line);
	vertical-align: top;
}

.mwb-table-scroll th {
	background: var(--mwb-surface-sunken);
	color: var(--mwb-ink-strong);
	font-weight: 700;
	white-space: nowrap;
}

.mwb-table-scroll tr:last-child td {
	border-block-end: 0;
}

/* ------------------------------------------------------------------ */
/* Forms                                                               */
/* ------------------------------------------------------------------ */

/*
 * Labels are always visible and always above the field. Placeholder-as-label
 * disappears the moment someone types, which on a contact form is how a person
 * ends up putting their telephone number in the subject box.
 */
.mwb-form {
	display: grid;
	gap: var(--mwb-space-5);
	max-width: 36rem;
}

.mwb-field {
	display: grid;
	gap: var(--mwb-space-2);
}

.mwb-field label {
	font-weight: 600;
	color: var(--mwb-ink-strong);
}

.mwb-field__hint {
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
	margin: 0;
}

.mwb-field__optional {
	font-weight: 400;
	color: var(--mwb-ink-muted);
}

.mwb-field input[type="text"],
.mwb-field input[type="email"],
.mwb-field input[type="tel"],
.mwb-field input[type="search"],
.mwb-field input[type="password"],
.mwb-field select,
.mwb-field textarea {
	width: 100%;
	min-height: var(--mwb-touch);
	padding: var(--mwb-space-3);
	font: inherit;
	/*
	 * 16px minimum. Mobile Safari zooms the whole page when a field's text is
	 * smaller than this, and the student then has to pinch back out to see the
	 * rest of the form.
	 */
	font-size: max(1rem, var(--mwb-text-base));
	color: var(--mwb-ink);
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line-strong);
	border-radius: var(--mwb-radius);
}

.mwb-field textarea {
	min-height: 10rem;
	resize: vertical;
	line-height: var(--mwb-leading);
}

.mwb-field--error input,
.mwb-field--error select,
.mwb-field--error textarea {
	border-color: var(--mwb-danger);
	border-width: 2px;
}

.mwb-field__error {
	display: flex;
	align-items: flex-start;
	gap: var(--mwb-space-2);
	font-size: var(--mwb-text-sm);
	font-weight: 600;
	color: var(--mwb-danger);
	margin: 0;
}

/* The word, not just the colour. */
.mwb-field__error::before {
	content: "!";
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 1.25em;
	height: 1.25em;
	border-radius: 50%;
	background: var(--mwb-danger);
	color: var(--mwb-ink-inverse);
	font-size: 0.8em;
	font-weight: 700;
}

/*
 * The honeypot. Hidden from people without `display: none`, which some bots
 * check for, and taken out of the tab order and the accessibility tree so a
 * screen-reader user is never asked to fill it in.
 */
.mwb-honeypot {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* A search or filter box that sits above a list. */
.mwb-filter {
	display: grid;
	gap: var(--mwb-space-2);
	max-width: 28rem;
}

.mwb-filter input[type="search"] {
	width: 100%;
	min-height: var(--mwb-touch);
	padding: var(--mwb-space-3);
	font: inherit;
	font-size: max(1rem, var(--mwb-text-base));
	color: var(--mwb-ink);
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line-strong);
	border-radius: var(--mwb-radius);
}

/* ------------------------------------------------------------------ */
/* Alerts                                                              */
/* ------------------------------------------------------------------ */

.mwb-alert {
	display: flex;
	gap: var(--mwb-space-3);
	padding: var(--mwb-space-4);
	border: 1px solid var(--mwb-line-strong);
	border-inline-start-width: 4px;
	border-radius: var(--mwb-radius);
	background: var(--mwb-surface-sunken);
	color: var(--mwb-ink);
}

.mwb-alert p {
	margin: 0;
}

.mwb-alert p + p {
	margin-block-start: var(--mwb-space-2);
}

.mwb-alert__label {
	font-weight: 700;
}

.mwb-alert--success {
	background: var(--mwb-correct-bg);
	border-color: var(--mwb-correct-line);
	border-inline-start-color: var(--mwb-correct);
	color: var(--mwb-correct);
}

.mwb-alert--error {
	background: var(--mwb-danger-bg);
	border-color: var(--mwb-danger-line);
	border-inline-start-color: var(--mwb-danger);
	color: var(--mwb-danger);
}

.mwb-alert--warning {
	background: var(--mwb-partial-bg);
	border-color: var(--mwb-partial-line);
	border-inline-start-color: var(--mwb-partial);
	color: var(--mwb-partial);
}

.mwb-alert--info {
	background: var(--mwb-accent-soft);
	border-color: var(--mwb-accent);
	border-inline-start-color: var(--mwb-accent);
	color: var(--mwb-ink);
}

/* ------------------------------------------------------------------ */
/* Progress                                                            */
/* ------------------------------------------------------------------ */

.mwb-progress {
	display: grid;
	gap: var(--mwb-space-2);
}

.mwb-progress__track {
	height: 0.625rem;
	border-radius: var(--mwb-radius-pill);
	background: var(--mwb-surface-sunken);
	border: 1px solid var(--mwb-line);
	overflow: hidden;
}

.mwb-progress__bar {
	display: block;
	height: 100%;
	background: var(--mwb-accent);
	border-radius: inherit;
	transition: width 200ms ease;
}

.mwb-progress__bar--strong { background: var(--mwb-correct); }
.mwb-progress__bar--fair { background: var(--mwb-partial); }
.mwb-progress__bar--weak { background: var(--mwb-incorrect); }
.mwb-progress__bar--none { background: var(--mwb-line-strong); }

/* The number is always printed too; the bar alone is not the value. */
.mwb-progress__label {
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
	font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ */
/* Tabs                                                                */
/* ------------------------------------------------------------------ */

/*
 * These are links, not scripted tabs: each one is a real page or a fragment, so
 * they work with JavaScript off and can be opened in a new tab.
 */
.mwb-tabs {
	display: flex;
	flex-wrap: wrap;
	gap: var(--mwb-space-1);
	border-block-end: 1px solid var(--mwb-line);
	list-style: none;
	margin: 0;
	padding: 0;
}

.mwb-tabs li {
	max-width: none;
}

.mwb-tabs a {
	display: inline-flex;
	align-items: center;
	min-height: var(--mwb-touch);
	padding: var(--mwb-space-2) var(--mwb-space-4);
	border: 1px solid transparent;
	border-block-end: 0;
	border-radius: var(--mwb-radius) var(--mwb-radius) 0 0;
	color: var(--mwb-ink-muted);
	text-decoration: none;
	font-weight: 600;
}

.mwb-tabs a:hover {
	background: var(--mwb-surface-sunken);
	color: var(--mwb-ink);
}

.mwb-tabs [aria-current="page"] {
	background: var(--mwb-surface);
	border-color: var(--mwb-line);
	color: var(--mwb-accent);
	/* Sits over the container's own border so the tab joins the panel. */
	margin-block-end: -1px;
	padding-block-end: calc(var(--mwb-space-2) + 1px);
}

/* ------------------------------------------------------------------ */
/* The question card and its options                                   */
/* ------------------------------------------------------------------ */

.mwb-question {
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius-lg);
	padding: var(--mwb-space-5);
	box-shadow: var(--mwb-shadow-sm);
}

.mwb-question__head {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--mwb-space-2) var(--mwb-space-3);
	margin-block-end: var(--mwb-space-4);
	padding-block-end: var(--mwb-space-3);
	border-block-end: 1px solid var(--mwb-line);
}

.mwb-question__number {
	font-weight: 700;
	color: var(--mwb-ink-strong);
	font-variant-numeric: tabular-nums;
}

.mwb-question__stem > :first-child {
	margin-block-start: 0;
}

.mwb-options {
	list-style: none;
	margin: var(--mwb-space-4) 0 0;
	padding: 0;
	display: grid;
	gap: var(--mwb-space-3);
}

.mwb-options li {
	max-width: none;
}

.mwb-option {
	display: flex;
	align-items: flex-start;
	gap: var(--mwb-space-3);
	min-height: var(--mwb-touch);
	padding: var(--mwb-space-3) var(--mwb-space-4);
	border: 1px solid var(--mwb-line-strong);
	border-radius: var(--mwb-radius);
	background: var(--mwb-surface);
	cursor: pointer;
}

.mwb-option:hover {
	border-color: var(--mwb-accent);
}

.mwb-option input {
	margin: 0.3em 0 0;
	width: 1.15rem;
	height: 1.15rem;
	flex: 0 0 auto;
	accent-color: var(--mwb-accent);
}

.mwb-option__letter {
	font-weight: 700;
	color: var(--mwb-ink-muted);
	flex: 0 0 auto;
}

.mwb-option--correct {
	background: var(--mwb-correct-bg);
	border-color: var(--mwb-correct);
}

.mwb-option--incorrect {
	background: var(--mwb-incorrect-bg);
	border-color: var(--mwb-incorrect);
}

/* ------------------------------------------------------------------ */
/* Revision lists: formulas, key points, common mistakes               */
/* ------------------------------------------------------------------ */

.mwb-section {
	margin-block-start: var(--mwb-space-7);
}

.mwb-section__head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--mwb-space-2) var(--mwb-space-4);
	border-block-end: 2px solid var(--mwb-line-strong);
	padding-block-end: var(--mwb-space-2);
	margin-block-end: var(--mwb-space-4);
}

.mwb-section__head h2,
.mwb-section__head h3 {
	margin: 0;
}

.mwb-section__count {
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.mwb-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--mwb-space-4);
}

.mwb-list > li {
	max-width: none;
}

/* One formula. */
.mwb-formula {
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
	padding: var(--mwb-space-4);
}

.mwb-formula__title {
	font-size: var(--mwb-text-base);
	font-weight: 700;
	color: var(--mwb-ink-strong);
	margin: 0 0 var(--mwb-space-3);
}

/* The expression itself gets the sunken surface, so it reads as the exhibit. */
.mwb-formula__latex {
	background: var(--mwb-surface-sunken);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius-sm);
	padding: var(--mwb-space-4) var(--mwb-space-3);
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	text-align: center;
}

/*
 * The equation is the only thing in this box, and the box already provides the
 * space around it. Left alone, display mathematics brings its own block margins
 * as well and every formula on the sheet gains half a centimetre of nothing top
 * and bottom — which over 128 of them is several screens of scrolling.
 */
.mwb-formula__latex .mwb-math--display {
	margin-block: 0;
}

.mwb-formula__description,
.mwb-formula__conditions {
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
	margin-block-start: var(--mwb-space-3);
}

.mwb-formula__description > :first-child,
.mwb-formula__conditions > :first-child {
	margin-block-start: 0;
}

.mwb-formula__conditions {
	display: flex;
	gap: var(--mwb-space-2);
	align-items: baseline;
}

.mwb-formula__conditions dt {
	font-weight: 700;
	color: var(--mwb-ink);
	white-space: nowrap;
}

.mwb-formula__conditions dd {
	margin: 0;
}

/* One key point. */
.mwb-key-point {
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-inline-start: 4px solid var(--mwb-accent);
	border-radius: var(--mwb-radius);
	padding: var(--mwb-space-4);
}

.mwb-key-point__point {
	font-weight: 600;
	color: var(--mwb-ink-strong);
}

.mwb-key-point__point > :first-child {
	margin-block-start: 0;
}

.mwb-key-point__detail {
	color: var(--mwb-ink-muted);
	margin-block-start: var(--mwb-space-3);
}

/*
 * One common mistake. The three parts are labelled in words — "Mistake",
 * "Instead", "Why" — and only then tinted. A student who cannot tell the red
 * band from the green one still reads the page correctly.
 */
.mwb-mistake {
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
	overflow: hidden;
}

.mwb-mistake__part {
	padding: var(--mwb-space-4);
	display: grid;
	gap: var(--mwb-space-2);
}

.mwb-mistake__part + .mwb-mistake__part {
	border-block-start: 1px solid var(--mwb-line);
}

.mwb-mistake__label {
	display: inline-flex;
	align-items: center;
	gap: var(--mwb-space-2);
	font-size: var(--mwb-text-xs);
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	width: fit-content;
}

.mwb-mistake__label::before {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.4em;
	height: 1.4em;
	border-radius: 50%;
	font-size: 0.95em;
	line-height: 1;
	border: 1px solid currentColor;
}

.mwb-mistake__part--wrong {
	background: var(--mwb-incorrect-bg);
}

.mwb-mistake__part--wrong .mwb-mistake__label {
	color: var(--mwb-incorrect);
}

/* A multiplication sign, not a cross-mark emoji — no emoji anywhere here. */
.mwb-mistake__part--wrong .mwb-mistake__label::before {
	content: "\00D7";
}

.mwb-mistake__part--right {
	background: var(--mwb-correct-bg);
}

.mwb-mistake__part--right .mwb-mistake__label {
	color: var(--mwb-correct);
}

.mwb-mistake__part--right .mwb-mistake__label::before {
	content: "\2713";
}

.mwb-mistake__part--why {
	background: var(--mwb-surface);
}

.mwb-mistake__part--why .mwb-mistake__label {
	color: var(--mwb-ink-muted);
}

.mwb-mistake__part--why .mwb-mistake__label::before {
	content: "?";
}

.mwb-mistake__body > :first-child {
	margin-block-start: 0;
}

.mwb-mistake__body > :last-child {
	margin-block-end: 0;
}

/* Topic tree on a chapter page. */
.mwb-topics {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--mwb-space-3);
}

.mwb-topics > li {
	max-width: none;
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
	padding: var(--mwb-space-4);
}

.mwb-topics__name {
	font-weight: 700;
	color: var(--mwb-ink-strong);
}

.mwb-topics__summary {
	color: var(--mwb-ink-muted);
	font-size: var(--mwb-text-sm);
	margin: var(--mwb-space-1) 0 0;
}

.mwb-topics__children {
	list-style: disc;
	margin: var(--mwb-space-3) 0 0;
	padding-inline-start: var(--mwb-space-5);
	color: var(--mwb-ink-muted);
}

.mwb-topics__children li {
	max-width: none;
}

/* ------------------------------------------------------------------ */
/* Empty states                                                        */
/* ------------------------------------------------------------------ */

/*
 * An empty state says what is missing and what to do next. "No results" on its
 * own reads like a fault in the site.
 */
.mwb-empty {
	text-align: center;
	padding: var(--mwb-space-6) var(--mwb-space-4);
	border: 1px dashed var(--mwb-line-strong);
	border-radius: var(--mwb-radius-lg);
	background: var(--mwb-surface-sunken);
	color: var(--mwb-ink-muted);
}

.mwb-empty p {
	margin: 0 auto;
	max-width: 44ch;
}

.mwb-empty p + p {
	margin-block-start: var(--mwb-space-3);
}

.mwb-empty__title {
	font-weight: 700;
	color: var(--mwb-ink);
}

/* ------------------------------------------------------------------ */
/* Pagination                                                          */
/* ------------------------------------------------------------------ */

.mwb-pagination {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--mwb-space-2);
	list-style: none;
	margin: 0;
	padding: 0;
}

.mwb-pagination li {
	max-width: none;
}

.mwb-pagination a,
.mwb-pagination span {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: var(--mwb-touch);
	min-height: var(--mwb-touch);
	padding-inline: var(--mwb-space-3);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
	background: var(--mwb-surface);
	color: var(--mwb-ink);
	text-decoration: none;
	font-variant-numeric: tabular-nums;
}

.mwb-pagination a:hover {
	border-color: var(--mwb-accent);
	color: var(--mwb-accent);
}

.mwb-pagination [aria-current="page"] {
	background: var(--mwb-accent);
	border-color: var(--mwb-accent);
	color: var(--mwb-accent-ink);
	font-weight: 700;
}

.mwb-pagination__gap {
	border-color: transparent;
	background: transparent;
	color: var(--mwb-ink-faint);
}

/* ------------------------------------------------------------------ */
/* Mathematics                                                         */
/* ------------------------------------------------------------------ */

/*
 * THE PRE-TYPESET STATE.
 *
 * Between the HTML arriving and KaTeX running, every `.mwb-math` holds its
 * LaTeX source as plain text. Two things are wrong with leaving that alone: the
 * source is much wider than the equation it becomes, so the page jumps when it
 * is replaced; and it reads as broken prose rather than as something still
 * loading.
 *
 * So until the element is marked typeset it is shown in monospace at a slightly
 * smaller size with a dotted underline — recognisably source, not a mistake —
 * and display mathematics reserves a line's height so the replacement moves the
 * page as little as possible. It is deliberately still *visible*: if JavaScript
 * never runs, or KaTeX cannot parse the expression, the student reads the LaTeX
 * instead of an empty gap.
 */
.mwb-math {
	font-family: var(--mwb-font-mono);
	font-size: 0.9em;
	color: var(--mwb-ink);
	text-decoration: underline dotted var(--mwb-line-strong);
	text-underline-offset: 3px;
	overflow-wrap: anywhere;
}

.mwb-math--display {
	display: block;
	min-height: 2.25em;
	margin-block: var(--mwb-space-4);
	text-align: center;
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

/*
 * Typeset. The monospace fallback is dropped so KaTeX's own bundled fonts show,
 * and the "still loading" underline goes with it.
 */
.mwb-math--typeset {
	font-family: inherit;
	font-size: inherit;
	text-decoration: none;
	overflow-wrap: normal;
}

/* An expression KaTeX refused. The source stays readable and is marked as such. */
.mwb-math--error {
	text-decoration: underline wavy var(--mwb-partial);
	cursor: help;
}

.mwb .katex {
	/* KaTeX's default 1.21 makes inline mathematics taller than the line it sits on. */
	font-size: 1.08em;
}

.mwb .katex-display {
	margin: 0;
	padding-block: var(--mwb-space-1);
	overflow-x: auto;
	overflow-y: hidden;
}

/* ------------------------------------------------------------------ */
/* The site-wide footer note                                           */
/* ------------------------------------------------------------------ */

.mwb-disclaimer {
	/*
	 * Paints its own surface for the same reason `.mwb` does: this sits in the
	 * theme's footer, outside any container of ours, and in dark mode it would
	 * otherwise be pale grey on the theme's white.
	 */
	background: var(--mwb-paper);
	color: var(--mwb-ink-muted);
	max-width: none;
	margin: var(--mwb-space-7) 0 0;
	padding: var(--mwb-space-5) var(--mwb-space-4);
	border-block-start: 1px solid var(--mwb-line);
	font-family: var(--mwb-font);
	font-size: var(--mwb-text-sm);
	line-height: var(--mwb-leading);
}

.mwb-disclaimer p {
	margin-inline: auto;
	margin-block: 0;
	max-width: var(--mwb-page-width);
}

.mwb-disclaimer p + p {
	margin-block-start: var(--mwb-space-3);
}

/* ------------------------------------------------------------------ */
/* Motion                                                              */
/* ------------------------------------------------------------------ */

/*
 * Someone who has asked their device for less motion has usually asked for a
 * reason — vestibular disorder, migraine, or simply a slow phone. Transitions
 * here are decoration, so they go entirely rather than being shortened.
 */
@media (prefers-reduced-motion: reduce) {
	.mwb *,
	.mwb *::before,
	.mwb *::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ------------------------------------------------------------------ */
/* Larger screens                                                      */
/* ------------------------------------------------------------------ */

/*
 * Mobile is the base above; this is the only breakpoint, and all it does is
 * give the page more air once there is room for it.
 */
@media (min-width: 48rem) {
	.mwb {
		padding-inline: var(--mwb-space-5);
	}

	.mwb h1 {
		font-size: 2.25rem;
	}

	.mwb-formula__conditions {
		align-items: baseline;
	}
}

/* ------------------------------------------------------------------ */
/* Print                                                               */
/* ------------------------------------------------------------------ */

/*
 * Revision pages get printed. A formula sheet on paper is still how a lot of
 * revision actually happens the week before the board exam.
 */
@media print {
	.mwb {
		max-width: none;
		padding: 0;
	}

	.mwb-filter,
	.mwb-btn,
	.mwb-tabs {
		display: none !important;
	}

	.mwb-card,
	.mwb-formula,
	.mwb-key-point,
	.mwb-mistake,
	.mwb-chapter-card {
		box-shadow: none;
		break-inside: avoid;
	}
}

/* ------------------------------------------------------------------ */
/* The portal                                                          */
/* ------------------------------------------------------------------ */

/*
 * Everything from here down is the signed-in study area. Tokens only, exactly
 * as above: not one colour in this section is written as a literal, so dark mode
 * needed no second copy of any rule.
 *
 * Three of these components were already being rendered by `Frontend\Ui` and by
 * `Portal\Routes` with no rules to hang on — the navigation, the figure grid and
 * the worked example. They are here rather than anywhere else because that is
 * where the rest of the design system lives, and a second stylesheet would be a
 * second place to forget.
 */

/* The portal navigation ------------------------------------------- */

/*
 * Wraps rather than scrolls. Eight destinations plus Sign out is two lines on a
 * 360px phone, and two readable lines beat one line with six of its entries off
 * the side of the screen — a horizontal scroller hides exactly the items nobody
 * thinks to look for.
 */
.mwb-portal-nav {
	border-block-end: 1px solid var(--mwb-line);
	padding-block-end: var(--mwb-space-2);
}

.mwb-portal-nav ul {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--mwb-space-1);
	list-style: none;
	margin: 0;
	padding: 0;
}

.mwb-portal-nav li {
	max-width: none;
}

.mwb-portal-nav a {
	display: inline-flex;
	align-items: center;
	min-height: var(--mwb-touch);
	padding: var(--mwb-space-2) var(--mwb-space-3);
	border-radius: var(--mwb-radius);
	color: var(--mwb-ink-muted);
	font-size: var(--mwb-text-sm);
	font-weight: 600;
	text-decoration: none;
}

.mwb-portal-nav a:hover {
	background: var(--mwb-surface-sunken);
	color: var(--mwb-ink);
}

/*
 * The current page is marked by weight and a background as well as by colour,
 * because `aria-current` is the only other signal and sighted students do not
 * get it.
 */
.mwb-portal-nav [aria-current="page"] {
	background: var(--mwb-accent-soft);
	color: var(--mwb-accent);
}

/* Sign out sits apart from the destinations; it is not one of them. */
.mwb-portal-nav__end {
	margin-inline-start: auto;
}

.mwb-portal-nav__end a {
	color: var(--mwb-ink-faint);
	font-weight: 400;
	text-decoration: underline;
}

/* Figures ---------------------------------------------------------- */

/*
 * `auto-fit` with a `min()` floor, the same shape as `.mwb-grid`: two tiles side
 * by side on a 360px phone and five in a row on a laptop, with no media query
 * and no track that can demand more width than the screen has.
 *
 * The floor is 8.5rem rather than the grid's 18rem because a figure is short.
 * At 10rem two tiles plus the gap no longer fitted inside the 16px gutters on a
 * 390px screen, and five figures became five full-width rows — measured, not
 * guessed.
 */
.mwb-stat-grid {
	display: grid;
	gap: var(--mwb-space-3);
	grid-template-columns: repeat(auto-fit, minmax(min(8.5rem, 100%), 1fr));
}

.mwb-stat {
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
	padding: var(--mwb-space-4);
}

.mwb-stat__value {
	margin: 0;
	max-width: none;
	font-size: var(--mwb-text-2xl);
	font-weight: 700;
	line-height: var(--mwb-leading-tight);
	color: var(--mwb-ink-strong);
	/* Tabular figures so a column of percentages does not shimmer as it updates. */
	font-variant-numeric: tabular-nums;
}

.mwb-stat__label {
	margin: var(--mwb-space-1) 0 0;
	max-width: none;
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
}

.mwb-stat__note {
	margin: var(--mwb-space-1) 0 0;
	max-width: none;
	font-size: var(--mwb-text-xs);
	color: var(--mwb-ink-faint);
}

/* Worked examples -------------------------------------------------- */

.mwb-example {
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
	padding: var(--mwb-space-4);
}

.mwb-example__title {
	margin: 0 0 var(--mwb-space-3);
	font-size: var(--mwb-text-lg);
	color: var(--mwb-ink-strong);
}

.mwb-example__problem {
	background: var(--mwb-surface-sunken);
	border-radius: var(--mwb-radius-sm);
	padding: var(--mwb-space-3);
	margin-block-end: var(--mwb-space-3);
}

.mwb-example__problem > :first-child {
	margin-block-start: 0;
}

.mwb-example__problem > :last-child {
	margin-block-end: 0;
}

.mwb-example__step + .mwb-example__step {
	margin-block-start: var(--mwb-space-2);
}

/*
 * The summary is the hit target, so it gets the full 44px and a pointer. The
 * marker is left to the browser: every one of them draws a disclosure triangle
 * that rotates on open, and a hand-drawn replacement is one more thing to get
 * wrong in right-to-left or in forced-colours mode.
 */
.mwb-example__step > summary {
	display: list-item;
	min-height: var(--mwb-touch);
	padding: var(--mwb-space-2) var(--mwb-space-2) var(--mwb-space-2) 0;
	margin-inline-start: var(--mwb-space-4);
	cursor: pointer;
	font-weight: 600;
	color: var(--mwb-accent);
}

.mwb-example__step > summary:hover {
	color: var(--mwb-accent-strong);
}

.mwb-example__step-body {
	border-inline-start: 3px solid var(--mwb-line);
	padding-inline-start: var(--mwb-space-4);
	margin-inline-start: var(--mwb-space-2);
}

.mwb-example__step-body > :first-child {
	margin-block-start: 0;
}

/* The answer is the last thing to open, and is marked as different. */
.mwb-example__step--answer > summary {
	color: var(--mwb-correct);
}

.mwb-example__step--answer .mwb-example__step-body {
	border-inline-start-color: var(--mwb-correct-line);
}

.mwb-example__learning {
	margin-block-start: var(--mwb-space-3);
	padding-block-start: var(--mwb-space-3);
	border-block-start: 1px solid var(--mwb-line);
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
}

.mwb-example__learning-label {
	font-weight: 700;
	color: var(--mwb-ink);
}

/* The resume banner ------------------------------------------------ */

/*
 * The one thing on the dashboard that is allowed to shout, and it earns it: an
 * unfinished paper is losing the student time while they read past it. Tinted
 * with the accent rather than with a warning colour, because it is an
 * invitation and not a fault.
 */
.mwb-resume {
	background: var(--mwb-accent-soft);
	border: 1px solid var(--mwb-accent);
	border-inline-start-width: 4px;
	border-radius: var(--mwb-radius-lg);
	padding: var(--mwb-space-5);
}

.mwb-resume__label {
	margin: 0;
	max-width: none;
	font-size: var(--mwb-text-xs);
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--mwb-accent);
}

.mwb-resume__title {
	margin: var(--mwb-space-1) 0 0;
	font-size: var(--mwb-text-xl);
}

.mwb-resume__meta {
	margin: var(--mwb-space-1) 0 0;
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
}

/* Small pieces used by the dashboard cards -------------------------- */

.mwb-steps {
	margin: 0;
	padding-inline-start: var(--mwb-space-5);
	display: grid;
	gap: var(--mwb-space-2);
}

.mwb-list--plain {
	gap: var(--mwb-space-2);
}

.mwb-suggestion__name {
	font-weight: 600;
}

.mwb-rule {
	border: 0;
	border-block-start: 1px solid var(--mwb-line);
	margin-block: var(--mwb-space-4);
}

/* A line of instruction between a section's heading rule and its list. */
.mwb-section__note {
	margin-block: 0 var(--mwb-space-4);
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
}

/* One finished attempt on the dashboard ---------------------------- */

.mwb-attempt-row {
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
	padding: var(--mwb-space-4);
}

.mwb-attempt-row__title {
	margin: 0;
	font-size: var(--mwb-text-lg);
}

.mwb-attempt-row__meta {
	margin: var(--mwb-space-1) 0 var(--mwb-space-3);
	max-width: none;
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
}

/* Chapter progress ------------------------------------------------- */

/*
 * Thirteen rows, so each one is a row rather than a card: at card size the list
 * is four screens tall on a phone and stops being a list of where you are.
 *
 * Flex with `flex-wrap` rather than a grid with named columns. The name needs
 * whatever width it needs, and at 360px the badge and the Practise link drop
 * onto a second line instead of squeezing the name into two characters.
 */
.mwb-chapter-progress {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--mwb-space-2);
}

.mwb-chapter-progress > li {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--mwb-space-2) var(--mwb-space-3);
	max-width: none;
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
	padding: var(--mwb-space-3) var(--mwb-space-4);
}

.mwb-chapter-progress__number {
	flex: 0 0 auto;
	min-width: 1.75rem;
	font-variant-numeric: tabular-nums;
	font-weight: 700;
	color: var(--mwb-ink-faint);
}

/* Takes the slack, so the badge and the link stay at their own size. */
.mwb-chapter-progress__body {
	flex: 1 1 10rem;
	display: flex;
	flex-direction: column;
}

.mwb-chapter-progress__name {
	font-weight: 600;
}

.mwb-chapter-progress__meta {
	font-size: var(--mwb-text-xs);
	color: var(--mwb-ink-faint);
}

.mwb-chapter-progress__state {
	flex: 0 0 auto;
}

.mwb-chapter-progress__practise {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	min-height: var(--mwb-touch);
	font-size: var(--mwb-text-sm);
	font-weight: 600;
}

/* A topic's lessons ------------------------------------------------ */

.mwb-lessons {
	display: grid;
	gap: var(--mwb-space-5);
}

.mwb-lesson {
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius-lg);
	padding: var(--mwb-space-5);
}

.mwb-lesson__head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--mwb-space-2) var(--mwb-space-3);
	margin-block-end: var(--mwb-space-3);
}

.mwb-lesson__title {
	margin: 0;
	font-size: var(--mwb-text-xl);
}

/* One test --------------------------------------------------------- */

.mwb-test-card {
	display: flex;
	flex-direction: column;
	gap: var(--mwb-space-3);
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius-lg);
	padding: var(--mwb-space-5);
	box-shadow: var(--mwb-shadow-sm);
}

.mwb-test-card > * {
	margin: 0;
}

.mwb-test-card__title {
	font-size: var(--mwb-text-lg);
	color: var(--mwb-ink-strong);
}

.mwb-test-card__scope,
.mwb-test-card__terms {
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
}

/* Pushed to the foot of the card so every card's terms line up. */
.mwb-test-card__terms {
	margin-block-start: auto;
	padding-block-start: var(--mwb-space-3);
	border-block-start: 1px solid var(--mwb-line);
}

.mwb-test-card__description {
	max-width: none;
}

/*
 * Three figures side by side. A definition list rather than three stat tiles:
 * these are small enough to read as a line, and three tiles inside a card that
 * is itself in a grid is one box too many.
 */
.mwb-test-card__record {
	display: flex;
	flex-wrap: wrap;
	gap: var(--mwb-space-2) var(--mwb-space-5);
	padding: var(--mwb-space-3);
	background: var(--mwb-surface-sunken);
	border-radius: var(--mwb-radius);
}

.mwb-test-card__record dt {
	font-size: var(--mwb-text-xs);
	color: var(--mwb-ink-muted);
}

.mwb-test-card__record dd {
	margin: 0;
	font-size: var(--mwb-text-lg);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	color: var(--mwb-ink-strong);
}

.mwb-test-card__record--none {
	display: block;
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
}

/* ------------------------------------------------------------------ */
/* Charts                                                              */
/* ------------------------------------------------------------------ */

/*
 * `Frontend\Ui::bar_chart()` has been emitting this markup with nothing to hang
 * on. It is here rather than in a file of its own for the reason the rest of
 * this stylesheet gives: one place to forget is better than two.
 *
 * A grid rather than a flex row, so every chart on the performance screen lines
 * its bars up at the same x even though "Integrals" and "Relations and
 * functions" are different lengths. The label column is capped in `ch` so a long
 * chapter name wraps instead of squeezing the bar to nothing.
 */
.mwb-chart {
	margin: 0;
	max-width: none;
}

.mwb-chart__caption {
	margin-block-end: var(--mwb-space-3);
	font-weight: 700;
	color: var(--mwb-ink-strong);
}

.mwb-chart__rows {
	display: grid;
	gap: var(--mwb-space-2);
	list-style: none;
	margin: 0;
	padding: 0;
}

.mwb-chart__row {
	display: grid;
	grid-template-columns: minmax(6rem, 14ch) 1fr auto;
	align-items: center;
	gap: var(--mwb-space-3);
	max-width: none;
}

.mwb-chart__label {
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink);
	overflow-wrap: anywhere;
}

.mwb-chart__track {
	height: 0.75rem;
	background: var(--mwb-surface-sunken);
	border-radius: var(--mwb-radius-pill);
	overflow: hidden;
}

.mwb-chart__bar {
	display: block;
	height: 100%;
	border-radius: var(--mwb-radius-pill);
	background: var(--mwb-line-strong);
}

/* The same four bands as the progress bar, and the same four tokens. */
.mwb-chart__bar--strong { background: var(--mwb-correct); }
.mwb-chart__bar--fair { background: var(--mwb-partial); }
.mwb-chart__bar--weak { background: var(--mwb-incorrect); }
.mwb-chart__bar--none { background: var(--mwb-line-strong); }

.mwb-chart__value {
	font-size: var(--mwb-text-sm);
	font-variant-numeric: tabular-nums;
	color: var(--mwb-ink-muted);
	white-space: nowrap;
}

/* Four charts, two up where there is room and one up on a phone. */
.mwb-chart-set {
	display: grid;
	gap: var(--mwb-space-6);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
}

/*
 * The progress bar gained four more bands with the mastery ladder, which colours
 * its rungs by state rather than by score. Same tokens as the badges of the same
 * names, so a rung and its badge agree.
 */
.mwb-progress__bar--correct { background: var(--mwb-correct); }
.mwb-progress__bar--partial { background: var(--mwb-partial); }
.mwb-progress__bar--pending { background: var(--mwb-pending); }
.mwb-progress__bar--accent { background: var(--mwb-accent); }

/* ------------------------------------------------------------------ */
/* The trend chart                                                     */
/* ------------------------------------------------------------------ */

/*
 * The SVG carries no colour attributes at all: every stroke and fill is set
 * here, from the tokens, which is what lets dark mode need no second copy of the
 * chart and no second code path in PHP.
 *
 * The table beneath it is the accessible version and is always present — see the
 * docblock of `Portal\Performance_Screen`.
 */
.mwb-trend {
	margin: 0;
	max-width: none;
}

/*
 * Capped rather than stretched to the column.
 *
 * The chart scales as a whole, its own text with it, so a very wide container
 * gives twenty-eight-pixel axis labels on a chart of four points. The cap keeps
 * the scale near 1:1 where there is room, and the table beneath carries every
 * figure where there is not.
 */
.mwb-trend__svg {
	display: block;
	width: 100%;
	max-width: 44rem;
	height: auto;
	margin-block-end: var(--mwb-space-4);
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
}

.mwb-trend__grid {
	stroke: var(--mwb-line);
	stroke-width: 1;
}

.mwb-trend__line {
	fill: none;
	stroke: var(--mwb-accent);
	stroke-width: 3;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.mwb-trend__dot {
	fill: var(--mwb-accent);
}

.mwb-trend__axis {
	fill: var(--mwb-ink-muted);
	font-family: var(--mwb-font);
	/* User units in the SVG's own 720 x 240 space, not pixels on the page. */
	font-size: 20px;
}

/* ------------------------------------------------------------------ */
/* The mastery ladder                                                  */
/* ------------------------------------------------------------------ */

.mwb-ladder {
	display: grid;
	gap: var(--mwb-space-3);
	list-style: none;
	margin: 0;
	padding: 0;
}

.mwb-ladder__rung {
	display: grid;
	grid-template-columns: auto 1fr;
	align-items: center;
	gap: var(--mwb-space-2) var(--mwb-space-3);
	max-width: none;
	padding-block-end: var(--mwb-space-3);
	border-block-end: 1px solid var(--mwb-line);
}

.mwb-ladder__rung:last-child {
	border-block-end: 0;
	padding-block-end: 0;
}

.mwb-ladder__count {
	justify-self: end;
	font-variant-numeric: tabular-nums;
	color: var(--mwb-ink-muted);
	font-size: var(--mwb-text-sm);
}

/* The bar spans both columns beneath the name and the count. */
.mwb-ladder__bar {
	grid-column: 1 / -1;
}

/*
 * The bar's own label repeats the rung's count, which is already printed beside
 * the badge. `display: none` rather than the visually-hidden treatment, because
 * the track above it is `role="img"` with the same words as its accessible name:
 * hiding it visually only would have a screen reader read the rung twice.
 */
.mwb-ladder__bar .mwb-progress__label {
	display: none;
}

/* ------------------------------------------------------------------ */
/* Weak areas                                                          */
/* ------------------------------------------------------------------ */

.mwb-weak-row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--mwb-space-3);
}

/* Grows to fill the row, but never so narrow that the bar is a dot. */
.mwb-weak-row__body {
	flex: 1 1 14rem;
	min-width: 0;
}

.mwb-weak-row__name {
	margin: 0 0 var(--mwb-space-2);
	font-weight: 700;
	color: var(--mwb-ink-strong);
}

.mwb-weak-row__action {
	flex: 0 0 auto;
}

/* ------------------------------------------------------------------ */
/* The practice indicator                                              */
/* ------------------------------------------------------------------ */

.mwb-readiness__value {
	font-size: var(--mwb-text-3xl);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	color: var(--mwb-ink-strong);
	line-height: var(--mwb-leading-tight);
}

/* The second line of a row heading: what that part of the indicator measures. */
.mwb-readiness__measure {
	display: block;
	margin-block-start: var(--mwb-space-1);
	font-weight: 400;
	font-size: var(--mwb-text-xs);
	color: var(--mwb-ink-muted);
	max-width: 22ch;
}

/* ------------------------------------------------------------------ */
/* Saved items                                                         */
/* ------------------------------------------------------------------ */

/* The count beside a filter tab's name. */
.mwb-tabs__count {
	margin-inline-start: var(--mwb-space-2);
	padding: 0 var(--mwb-space-2);
	border-radius: var(--mwb-radius-pill);
	background: var(--mwb-surface-sunken);
	font-size: var(--mwb-text-xs);
	font-variant-numeric: tabular-nums;
	color: var(--mwb-ink-muted);
}

.mwb-saved {
	display: grid;
	gap: var(--mwb-space-3);
	background: var(--mwb-surface);
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius-lg);
	padding: var(--mwb-space-4);
	box-shadow: var(--mwb-shadow-sm);
}

.mwb-saved__head {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--mwb-space-2);
}

.mwb-saved__meta {
	margin: 0;
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
}

.mwb-saved__body > :first-child {
	margin-block-start: 0;
}

.mwb-saved__title {
	margin: 0 0 var(--mwb-space-2);
	font-size: var(--mwb-text-lg);
}

.mwb-saved__excerpt {
	margin: 0;
	color: var(--mwb-ink-muted);
}

.mwb-saved__withdrawn {
	margin: 0;
	color: var(--mwb-ink-muted);
	font-style: italic;
}

.mwb-saved__remove {
	justify-self: start;
}

/*
 * The answer to a saved question, folded away. Styled to read as a lid on the
 * question rather than as a separate card: it belongs to the question above it.
 */
.mwb-solution {
	border: 1px solid var(--mwb-line);
	border-radius: var(--mwb-radius);
	background: var(--mwb-surface-sunken);
}

.mwb-solution > summary {
	padding: var(--mwb-space-3) var(--mwb-space-4);
	min-height: var(--mwb-touch);
	display: flex;
	align-items: center;
	cursor: pointer;
	font-weight: 600;
	color: var(--mwb-accent);
}

.mwb-solution > summary:hover {
	color: var(--mwb-accent-strong);
}

.mwb-solution__body {
	padding: 0 var(--mwb-space-4) var(--mwb-space-4);
}

.mwb-solution__body > :first-child {
	margin-block-start: 0;
}

.mwb-solution__heading {
	margin-block: var(--mwb-space-4) var(--mwb-space-2);
	font-size: var(--mwb-text-base);
	color: var(--mwb-ink-strong);
}

.mwb-solution__answer {
	padding: var(--mwb-space-3);
	background: var(--mwb-correct-bg);
	border: 1px solid var(--mwb-correct-line);
	border-radius: var(--mwb-radius);
}

.mwb-solution__label {
	font-weight: 700;
	color: var(--mwb-correct);
}

/* ------------------------------------------------------------------ */
/* Search results                                                      */
/* ------------------------------------------------------------------ */

.mwb-result__title {
	margin: 0 0 var(--mwb-space-2);
	font-size: var(--mwb-text-lg);
}

.mwb-result__snippet {
	margin: 0 0 var(--mwb-space-2);
	color: var(--mwb-ink);
}

.mwb-result__where {
	margin: 0;
	font-size: var(--mwb-text-sm);
	color: var(--mwb-ink-muted);
}

/*
 * The highlight. A tint rather than the browser's default yellow, which is a
 * fixed colour and disappears against the dark paper; the underline is what
 * carries the mark where colour cannot.
 */
.mwb mark {
	padding: 0 0.15em;
	border-radius: var(--mwb-radius-sm);
	background: var(--mwb-accent-soft);
	color: var(--mwb-ink-strong);
	text-decoration: underline;
	text-underline-offset: 2px;
}

/* ------------------------------------------------------------------ */
/* The profile screen                                                  */
/* ------------------------------------------------------------------ */

/*
 * Label above value, so a long date never collides with its own label, and each
 * pair is one grid cell rather than two — see the markup in `Profile_Screen`.
 */
.mwb-facts {
	display: grid;
	gap: var(--mwb-space-4) var(--mwb-space-5);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
	margin: 0;
}

.mwb-facts__item {
	display: grid;
	gap: var(--mwb-space-1);
	align-content: start;
}

.mwb-facts dt {
	font-size: var(--mwb-text-xs);
	color: var(--mwb-ink-muted);
}

.mwb-facts dd {
	margin: 0;
	font-weight: 600;
	color: var(--mwb-ink-strong);
}

.mwb-note {
	background: var(--mwb-surface-sunken);
}

/*
 * The browser's own 40px list indent is a seventh of a 390px phone, and this
 * list is the one place on the profile screen with a real paragraph in every
 * bullet. Pulled in to the space scale; the marker still sits outside the text.
 */
.mwb-note ul {
	margin: 0;
	padding-inline-start: var(--mwb-space-5);
}

.mwb-note p {
	color: var(--mwb-ink-muted);
}
