:root {
	color-scheme: light dark;

	--color-bg: #ffffff;
	--color-text: #000000;

	--color-link: #1d4ed8;
	--color-link-visited: #6366cc;
	--color-link-active: #0b1f5e;

	--color-header-bg: #993300;
	--color-header-text: #ffff00;
	--color-panel-bg: #ffffcc;
	--color-panel-text: #800000;
	--color-code-bg: #e1ffe1;
	--color-results-bg: #ddffff;
	--color-cell-label-bg: #e8e8e8;
	--color-emphasis: #000099;

	--site-header-height: 3em;
	/* site-header (--site-header-height) + secondary breadcrumb bar. Used by
	   sticky sidebars (page-toc, course-sidebar) so they sit below both bars
	   instead of slipping under the breadcrumbs. */
	--site-bar-height: calc(var(--site-header-height) + 2.5em);

	/* Anchor jumps (TOC links, hash navigation) park the target under both
	   sticky bars without it. The extra 0.5em prevents the heading from
	   sitting flush against the breadcrumb bar's bottom edge. */
	scroll-padding-top: calc(var(--site-bar-height) + 0.5em);

	--color-border: currentColor;
	--color-border-soft: #cccccc;
	--color-border-mute: #999999;

	--color-text-muted: #6a6a6a;
	--color-danger: #c00000;
	--color-inline-warm: #993300;
	--color-inline-green: #006600;
	--color-syntax-highlight: #c00000;
	--color-toc-marker: #2e7d32;

	--prism-bg: #f5f2f0;
	--prism-text: #000000;
	--prism-keyword: #006fa1;
	--prism-string: #447a00;
	--prism-punctuation: #6a6a6a;
	--prism-comment: #546e7a;
	--prism-function: #c03a58;
	--prism-number: currentColor;
	--prism-operator: currentColor;

	/* Dark-mode image inversion. Light/print leave it at `none`; the dark
	   rulesets override it to actually invert. Routing through a custom
	   property lets the print stylesheet reset it without `!important`. */
	--img-filter: none;
}

/* Tighten color-scheme when the user has explicitly chosen a theme so the
   browser's built-in UI (scrollbars, form controls) follows the override. */
:root[data-theme="light"] {
	color-scheme: light;
}
:root[data-theme="dark"] {
	color-scheme: dark;
}

@media (prefers-color-scheme: dark) {
	/* :not([data-theme="light"]) lets a manual Light override beat the OS. */
	:root:not([data-theme="light"]) {
		--color-bg: #1a1a1a;
		--color-text: #e6e6e6;

		--color-link: #93c5fd;
		--color-link-visited: #a5b4fc;
		--color-link-active: #bfdbfe;

		--color-header-bg: #6b2400;
		--color-header-text: #ffe066;
		--color-panel-bg: #3a3520;
		--color-panel-text: #ffd9d9;
		--color-code-bg: #1f2e1f;
		--color-results-bg: #1a2e2e;
		--color-cell-label-bg: #2d2d2d;
		--color-emphasis: #8aa8ff;

		--color-border-soft: #444444;
		--color-border-mute: #666666;

		--color-text-muted: #a0a0a0;
		--color-danger: #ff8a8a;
		--color-inline-warm: #ff9966;
		--color-inline-green: #7ec47e;
		--color-syntax-highlight: #ff8a8a;
		--color-toc-marker: #66bb6a;

		--prism-bg: #1f1f1f;
		--prism-text: #e6e6e6;
		--prism-keyword: #ff9d6e;
		--prism-string: #b5e8a3;
		--prism-punctuation: #c8c8c8;
		--prism-comment: #8a8a8a;
		--prism-function: #90c8ff;
		--prism-number: #f8d57e;
		--prism-operator: #d8a0ff;
	}
}

/* Manual dark override — same tokens, applied regardless of OS preference. */
:root[data-theme="dark"] {
	--color-bg: #1a1a1a;
	--color-text: #e6e6e6;

	--color-link: #6ea8ff;
	--color-link-visited: #a5b4fc;
	--color-link-active: #6ee06e;

	--color-header-bg: #6b2400;
	--color-header-text: #ffe066;
	--color-panel-bg: #3a3520;
	--color-panel-text: #ffd9d9;
	--color-code-bg: #1f2e1f;
	--color-results-bg: #1a2e2e;
	--color-cell-label-bg: #2d2d2d;
	--color-emphasis: #8aa8ff;

	--color-border-soft: #444444;
	--color-border-mute: #666666;

	--color-text-muted: #a0a0a0;
	--color-danger: #ff8a8a;
	--color-inline-warm: #ff9966;
	--color-inline-green: #7ec47e;
	--color-syntax-highlight: #ff8a8a;
	--color-toc-marker: #66bb6a;

	--prism-bg: #1f1f1f;
	--prism-text: #e6e6e6;
	--prism-keyword: #ff9d6e;
	--prism-string: #b5e8a3;
	--prism-punctuation: #c8c8c8;
	--prism-comment: #8a8a8a;
	--prism-function: #90c8ff;
	--prism-number: #f8d57e;
	--prism-operator: #d8a0ff;
}

body {
	margin: 0;
	background-color: var(--color-bg);
	color: var(--color-text);
	line-height: 1.55;
}

a:link {
	color: var(--color-link);
}

a:visited {
	color: var(--color-link-visited);
}

a:active {
	color: var(--color-link-active);
}

a:focus-visible,
button:focus-visible,
summary:focus-visible,
details:focus-visible {
	outline: 2px solid var(--color-link);
	outline-offset: 2px;
	box-shadow: 0 0 0 4px var(--color-bg);
}

img {
	max-width: 100%;
	height: auto;
	filter: var(--img-filter);
}

/* Photos and explicit opt-outs skip the dark-mode invert. Setting the custom
   property on the element itself (rather than a high-specificity `img { filter
   }` rule) means the same selectors work in light, dark, and print without
   needing to be repeated under each theme. */
img.no-invert,
img[src$=".jpg"],
img[src$=".jpeg"],
img[src$=".JPG"],
img[src$=".JPEG"] {
	--img-filter: none;
}

table {
	max-width: 100%;
}

body > table,
body > hr {
	margin-left: auto;
	margin-right: auto;
}

pre {
	overflow-x: auto;
	max-width: 100%;
	white-space: pre-wrap;
	word-wrap: break-word;
	overflow-wrap: break-word;
}

/* Force Prism-highlighted code to wrap by default rather than scroll. The
   `body` prefix bumps specificity to (0,1,2) so this rule wins against
   prism.min.css's `pre[class*="language-"]` (specificity 0,1,1), regardless
   of stylesheet load order. */
body pre[class*="language-"],
body code[class*="language-"] {
	white-space: pre-wrap;
	overflow-wrap: break-word;
}

/* Reserve room on the right for the absolutely-positioned .copy-button
   injected by components/copy-button.js (top: 0.4em; right: 0.4em). Without
   this, short one-line snippets and any line that reaches the right edge
   render directly under the button. 4em comfortably clears the button at
   its mobile tap-target size (50×44 from PR #606). */
body pre[class*="language-"] {
	padding-right: 4em;
}

body {
	-webkit-text-size-adjust: 100%;
}

@media (max-width: 600px) {
	body {
		margin: 4px;
		overflow-wrap: break-word;
		word-wrap: break-word;
	}

	/* These attribute selectors override HTML width="..." / height="..."
	   presentation attributes, which the cascade treats as having specificity
	   0 — so any author CSS selector wins without `!important`. Confirmed no
	   page sets an inline `style="width:..."` on these tags. */
	table[width] {
		width: 100%;
		height: auto;
	}

	td[width],
	th[width],
	td[height],
	th[height] {
		width: auto;
		height: auto;
	}

	td[bgcolor="#993300"] > h2,
	td[bgcolor="#993300"] > h3 {
		margin: 0.3em 0;
	}

	blockquote {
		margin-left: 12px;
		margin-right: 12px;
	}

	hr[width] {
		width: 100%;
	}

	img,
	iframe,
	video,
	embed,
	object {
		max-width: min(100%, calc(100vw - 16px));
		height: auto;
	}

	pre {
		max-width: min(100%, calc(100vw - 16px));
	}

	pre[class*="language-"] {
		font-size: 0.8em;
		line-height: 1.35;
		padding: 0.6em;
		overflow-x: auto;
	}

	#layout-table,
	#layout-table > tbody,
	#layout-table > tbody > tr,
	#layout-table > tbody > tr > td {
		display: block;
		width: auto;
	}
}

/* Skip-to-content link: visually hidden until focused, then visible at top-left */
.skip-link {
	position: absolute;
	left: -9999px;
	top: auto;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.skip-link:focus {
	position: fixed;
	top: 0;
	left: 0;
	width: auto;
	height: auto;
	overflow: visible;
	padding: 0.5em 1em;
	background-color: var(--color-header-bg);
	color: var(--color-header-text);
	font-weight: bold;
	z-index: 9999;
	text-decoration: none;
}

ul.toc {
	list-style-type: disc;
	padding-left: 2.5em;
	margin: 1em 0;
}

ul.toc ::marker {
	color: var(--color-toc-marker);
}

ul.toc > li {
	padding-left: 0.4em;
	margin-bottom: 0.6em;
	font-size: smaller;
}

ul.toc a {
	display: block;
	font-weight: bold;
	font-size: larger;
}

/* Recolor legacy <table>/<tr>/<td> bgcolor="..." attribute markup via CSS
   background-color, which wins over the deprecated HTML attribute. Lets the
   theme tokens drive colors on pages that haven't been migrated to component
   classes. */
table[bgcolor="#993300"],
table[bgcolor="#990000"],
tr[bgcolor="#993300"],
tr[bgcolor="#990000"],
td[bgcolor="#993300"],
td[bgcolor="#990000"] {
	background-color: var(--color-header-bg);
}

table[bgcolor="#FFFFCC"],
table[bgcolor="#ffffcc"],
tr[bgcolor="#FFFFCC"],
tr[bgcolor="#ffffcc"],
td[bgcolor="#FFFFCC"],
td[bgcolor="#ffffcc"],
th[bgcolor="#FFFFCC"],
th[bgcolor="#ffffcc"] {
	background-color: var(--color-panel-bg);
}

table[bgcolor="#FFFFFF"],
table[bgcolor="#ffffff"],
tr[bgcolor="#FFFFFF"],
tr[bgcolor="#ffffff"],
td[bgcolor="#FFFFFF"],
td[bgcolor="#ffffff"] {
	background-color: var(--color-bg);
}

table[bgcolor="#E1FFE1"],
table[bgcolor="#e1ffe1"],
table[bgcolor="#D2FFD2"],
table[bgcolor="#d2ffd2"],
table[bgcolor="#DDFFDD"],
table[bgcolor="#ddffdd"],
tr[bgcolor="#E1FFE1"],
tr[bgcolor="#e1ffe1"],
tr[bgcolor="#D2FFD2"],
tr[bgcolor="#d2ffd2"],
tr[bgcolor="#DDFFDD"],
tr[bgcolor="#ddffdd"],
td[bgcolor="#E1FFE1"],
td[bgcolor="#e1ffe1"],
td[bgcolor="#D2FFD2"],
td[bgcolor="#d2ffd2"],
td[bgcolor="#DDFFDD"],
td[bgcolor="#ddffdd"] {
	background-color: var(--color-code-bg);
}

table[bgcolor="#DDFFFF"],
table[bgcolor="#ddffff"],
tr[bgcolor="#DDFFFF"],
tr[bgcolor="#ddffff"],
td[bgcolor="#DDFFFF"],
td[bgcolor="#ddffff"] {
	background-color: var(--color-results-bg);
}

table[bgcolor="#E8E8E8"],
table[bgcolor="#e8e8e8"],
tr[bgcolor="#E8E8E8"],
tr[bgcolor="#e8e8e8"],
td[bgcolor="#E8E8E8"],
td[bgcolor="#e8e8e8"] {
	background-color: var(--color-cell-label-bg);
}

td[bgcolor="#993300"] h2,
td[bgcolor="#990000"] h2,
tr[bgcolor="#993300"] h2,
tr[bgcolor="#990000"] h2 {
	color: var(--color-header-text);
	font-family: Arial, Helvetica, sans-serif;
}

td[bgcolor="#FFFFCC"] h3,
td[bgcolor="#FFFFCC"] h4,
td[bgcolor="#ffffcc"] h3,
td[bgcolor="#ffffcc"] h4 {
	color: var(--color-panel-text);
	font-family: Arial, Helvetica, sans-serif;
}

/* Shared course-page layout */

.page-wrapper {
	max-width: 715px;
	margin: 0 auto;
	border: 1px solid;
	box-sizing: border-box;
}

.page-content {
	max-width: 700px;
	margin-inline: auto;
	padding: 2px;
}

.page-footer {
	padding: 2px;
}

/* When the footer sits inside a section-grid (rather than as a sibling of it),
   span all columns so it occupies a full row. */
.section-grid > .page-footer {
	grid-column: 1 / -1;
}

.section-grid {
	display: grid;
	grid-template-columns: 175px 1fr;
}

.section-header {
	grid-column: 1 / -1;
	background-color: var(--color-header-bg);
	padding: 4px;
	min-width: 0;
	text-align: center;
}

.section-header h2,
.section-header h3 {
	color: var(--color-header-text);
	font-family: Arial, Helvetica, sans-serif;
	margin: 0.3em 0;
}

.section-sidebar {
	background-color: var(--color-panel-bg);
	padding: 4px;
	min-width: 0;
}

.section-sidebar h3,
.section-sidebar h4 {
	color: var(--color-panel-text);
	font-family: Arial, Helvetica, sans-serif;
}

.section-content {
	padding: 4px;
	min-width: 0;
	align-self: start;
}

.section-full {
	grid-column: 1 / -1;
	padding: 4px;
	min-width: 0;
}

@media (max-width: 600px) {
	.section-grid {
		display: block;
	}

	.section-sidebar h3,
	.section-sidebar h4,
	.section-sidebar p {
		margin: 0.2em 0;
	}
}

/* Inline style colour corrections — light mode.
   Legacy <span style="color: #cccccc"> fails 4.5:1 against any light
   background. Remap to a dark grey that passes without the rule being
   visible in dark mode (the dark-mode block below uses higher-specificity
   :root:not([data-theme="light"]) selectors and overrides this).
   `!important` is required: attribute selectors only see the raw inline
   value, but the actual `color` declaration sits in the element's `style`
   attribute, whose specificity (1,0,0,0) outranks any author selector
   without `!important`. */
[style*="color:#cccccc"],
[style*="color: #cccccc"],
[style*="color:#CCCCCC"],
[style*="color: #CCCCCC"] {
	color: var(--color-text-muted) !important;
}

.cobol-highlight {
	color: var(--color-syntax-highlight);
}

/* Legacy <span style="color: #ff0000"> fails 4.5:1 against light backgrounds
   (#E1FFE1 gives 3.73:1, #FFFFCC gives 3.89:1, white gives 4:1). Remap to a
   darker red. Dark-mode override below uses higher-specificity selectors and
   maps to #ff8a8a for legibility on dark panel backgrounds. `!important` is
   required for the same reason as the #cccccc rule above — we're overriding
   an inline `style="color:..."` declaration. */
[style*="color:#ff0000"],
[style*="color: #ff0000"],
[style*="color:#FF0000"],
[style*="color: #FF0000"] {
	color: var(--color-danger) !important;
}

/* ============================================================================
   Prism token colour corrections — light mode
   Overrides the default Prism theme to meet WCAG 2.1 AA (≥ 4.5:1) against
   Prism's #f5f2f0 code-block background. The `body` prefix raises specificity
   to (0,2,1), beating prism.min.css's (0,2,0). Dark-mode overrides below use
   (0,3,1) selectors and are unaffected.
   ============================================================================ */
body .token.atrule,
body .token.attr-value,
body .token.keyword {
	color: var(--prism-keyword);
}

body .token.attr-name,
body .token.builtin,
body .token.char,
body .token.inserted,
body .token.selector,
body .token.string {
	color: var(--prism-string);
}

body .token.punctuation {
	color: var(--prism-punctuation);
}

body .token.comment,
body .token.prolog,
body .token.doctype,
body .token.cdata {
	color: var(--prism-comment);
}

body .token.class-name,
body .token.function {
	color: var(--prism-function);
}

/* ============================================================================
   Dark-mode overrides
   The :root token swap above handles backgrounds and text. The rules below
   handle three things tokens can't reach: Prism's token colors (defined in
   the vendor stylesheet), light-background images that need inversion, and
   inline `style="color: #..."` highlights baked into legacy code samples.
   ============================================================================ */
/* Dark-mode non-token overrides shared between system-dark and manual-dark.
   Defined as a ruleset that is applied under both conditions below. */
@media (prefers-color-scheme: dark) {
	/* :not([data-theme="light"]) lets a manual Light override beat the OS. */

	/* Prism syntax highlighting — re-color the vendor light theme. The `body`
	   prefix lifts specificity to (0,1,2) so these win against prism.min.css's
	   (0,1,1) selectors despite the vendor sheet loading after course.css. */
	:root:not([data-theme="light"]) body pre[class*="language-"],
	:root:not([data-theme="light"]) body code[class*="language-"] {
		background: var(--prism-bg);
		color: var(--prism-text);
		text-shadow: none;
	}

	:root:not([data-theme="light"]) body :not(pre) > code[class*="language-"] {
		background: var(--prism-bg);
	}

	:root:not([data-theme="light"]) body .token.comment,
	:root:not([data-theme="light"]) body .token.prolog,
	:root:not([data-theme="light"]) body .token.doctype,
	:root:not([data-theme="light"]) body .token.cdata {
		color: var(--prism-comment);
	}

	:root:not([data-theme="light"]) body .token.punctuation {
		color: var(--prism-punctuation);
	}

	:root:not([data-theme="light"]) body .token.keyword,
	:root:not([data-theme="light"]) body .token.tag,
	:root:not([data-theme="light"]) body .token.selector,
	:root:not([data-theme="light"]) body .token.atrule {
		color: var(--prism-keyword);
	}

	:root:not([data-theme="light"]) body .token.string,
	:root:not([data-theme="light"]) body .token.attr-value,
	:root:not([data-theme="light"]) body .token.char,
	:root:not([data-theme="light"]) body .token.builtin,
	:root:not([data-theme="light"]) body .token.inserted {
		color: var(--prism-string);
	}

	:root:not([data-theme="light"]) body .token.number,
	:root:not([data-theme="light"]) body .token.boolean,
	:root:not([data-theme="light"]) body .token.constant,
	:root:not([data-theme="light"]) body .token.symbol,
	:root:not([data-theme="light"]) body .token.deleted {
		color: var(--prism-number);
	}

	:root:not([data-theme="light"]) body .token.function,
	:root:not([data-theme="light"]) body .token.class-name {
		color: var(--prism-function);
	}

	:root:not([data-theme="light"]) body .token.operator,
	:root:not([data-theme="light"]) body .token.entity,
	:root:not([data-theme="light"]) body .token.url,
	:root:not([data-theme="light"]) body .token.variable,
	:root:not([data-theme="light"]) body .language-css .token.string,
	:root:not([data-theme="light"]) body .style .token.string {
		color: var(--prism-operator);
		background: transparent;
	}

	/* Light-background diagrams and decorative GIFs invert to read on dark.
	   `0.92` keeps blacks just shy of pure white so they merge into the page;
	   `hue-rotate(180deg)` recovers reds/greens. The photo / no-invert opt-out
	   lives at the base `img.no-invert` rule above, which resets the variable
	   on the element itself. */
	:root:not([data-theme="light"]) {
		--img-filter: invert(0.92) hue-rotate(180deg);
	}

	/* Override inline `style="color: #..."` spans baked into legacy code
	   samples. These attribute selectors target the raw inline value, so
	   `!important` is required to beat the inline declaration. */
	:root:not([data-theme="light"]) [style*="color:#0000ff"],
	:root:not([data-theme="light"]) [style*="color: #0000ff"],
	:root:not([data-theme="light"]) [style*="color:#0000FF"],
	:root:not([data-theme="light"]) [style*="color: #0000FF"] {
		color: var(--color-link) !important;
	}

	:root:not([data-theme="light"]) [style*="color:#993300"],
	:root:not([data-theme="light"]) [style*="color: #993300"] {
		color: var(--color-inline-warm) !important;
	}

	:root:not([data-theme="light"]) [style*="color:#000099"],
	:root:not([data-theme="light"]) [style*="color: #000099"] {
		color: var(--color-emphasis) !important;
	}

	:root:not([data-theme="light"]) [style*="color:#800000"],
	:root:not([data-theme="light"]) [style*="color: #800000"] {
		color: var(--color-panel-text) !important;
	}

	:root:not([data-theme="light"]) [style*="color:#ff0000"],
	:root:not([data-theme="light"]) [style*="color: #ff0000"],
	:root:not([data-theme="light"]) [style*="color:#FF0000"],
	:root:not([data-theme="light"]) [style*="color: #FF0000"] {
		color: var(--color-danger) !important;
	}

	:root:not([data-theme="light"]) [style*="color:#006600"],
	:root:not([data-theme="light"]) [style*="color: #006600"] {
		color: var(--color-inline-green) !important;
	}

	:root:not([data-theme="light"]) [style*="color:#cccccc"],
	:root:not([data-theme="light"]) [style*="color: #cccccc"],
	:root:not([data-theme="light"]) [style*="color:#CCCCCC"],
	:root:not([data-theme="light"]) [style*="color: #CCCCCC"] {
		color: var(--color-text-muted) !important;
	}

	/* Inline background-color: #ffffff stays white in dark mode, leaving light
	   inherited text on a white canvas — very low contrast. Map to the dark
	   page background so normal dark-mode text colours apply. */
	:root:not([data-theme="light"]) [style*="background-color: #ffffff"],
	:root:not([data-theme="light"]) [style*="background-color:#ffffff"],
	:root:not([data-theme="light"]) [style*="background-color: #FFFFFF"],
	:root:not([data-theme="light"]) [style*="background-color:#FFFFFF"] {
		background-color: var(--color-bg) !important;
	}

	/* #CCCCCC has no matching light-mode token (only used as decorative
	   spacer cells), so it's remapped only in dark mode. Uses the same
	   --color-cell-label-bg as #E8E8E8 since both are gray. */
	:root:not([data-theme="light"]) table[bgcolor="#CCCCCC"],
	:root:not([data-theme="light"]) table[bgcolor="#cccccc"],
	:root:not([data-theme="light"]) tr[bgcolor="#CCCCCC"],
	:root:not([data-theme="light"]) tr[bgcolor="#cccccc"],
	:root:not([data-theme="light"]) td[bgcolor="#CCCCCC"],
	:root:not([data-theme="light"]) td[bgcolor="#cccccc"] {
		background-color: var(--color-cell-label-bg);
	}
}

/* Manual dark override — same non-token rules as the @media block above,
   applied regardless of OS preference. The `[style*="..."]` overrides below
   need `!important` for the same reason as their @media-dark twins: they
   target the raw inline-style attribute, but the actual `color` /
   `background-color` declaration sits in `style=""` at specificity (1,0,0,0)
   and can't be beaten without it. */
:root[data-theme="dark"] body pre[class*="language-"],
:root[data-theme="dark"] body code[class*="language-"] {
	background: var(--prism-bg);
	color: var(--prism-text);
	text-shadow: none;
}

:root[data-theme="dark"] body :not(pre) > code[class*="language-"] {
	background: var(--prism-bg);
}

:root[data-theme="dark"] body .token.comment,
:root[data-theme="dark"] body .token.prolog,
:root[data-theme="dark"] body .token.doctype,
:root[data-theme="dark"] body .token.cdata {
	color: var(--prism-comment);
}

:root[data-theme="dark"] body .token.punctuation {
	color: var(--prism-punctuation);
}

:root[data-theme="dark"] body .token.keyword,
:root[data-theme="dark"] body .token.tag,
:root[data-theme="dark"] body .token.selector,
:root[data-theme="dark"] body .token.atrule {
	color: var(--prism-keyword);
}

:root[data-theme="dark"] body .token.string,
:root[data-theme="dark"] body .token.attr-value,
:root[data-theme="dark"] body .token.char,
:root[data-theme="dark"] body .token.builtin,
:root[data-theme="dark"] body .token.inserted {
	color: var(--prism-string);
}

:root[data-theme="dark"] body .token.number,
:root[data-theme="dark"] body .token.boolean,
:root[data-theme="dark"] body .token.constant,
:root[data-theme="dark"] body .token.symbol,
:root[data-theme="dark"] body .token.deleted {
	color: var(--prism-number);
}

:root[data-theme="dark"] body .token.function,
:root[data-theme="dark"] body .token.class-name {
	color: var(--prism-function);
}

:root[data-theme="dark"] body .token.operator,
:root[data-theme="dark"] body .token.entity,
:root[data-theme="dark"] body .token.url,
:root[data-theme="dark"] body .token.variable,
:root[data-theme="dark"] body .language-css .token.string,
:root[data-theme="dark"] body .style .token.string {
	color: var(--prism-operator);
	background: transparent;
}

:root[data-theme="dark"] {
	--img-filter: invert(0.92) hue-rotate(180deg);
}

:root[data-theme="dark"] [style*="color:#0000ff"],
:root[data-theme="dark"] [style*="color: #0000ff"],
:root[data-theme="dark"] [style*="color:#0000FF"],
:root[data-theme="dark"] [style*="color: #0000FF"] {
	color: var(--color-link) !important;
}

:root[data-theme="dark"] [style*="color:#993300"],
:root[data-theme="dark"] [style*="color: #993300"] {
	color: var(--color-inline-warm) !important;
}

:root[data-theme="dark"] [style*="color:#000099"],
:root[data-theme="dark"] [style*="color: #000099"] {
	color: var(--color-emphasis) !important;
}

:root[data-theme="dark"] [style*="color:#800000"],
:root[data-theme="dark"] [style*="color: #800000"] {
	color: var(--color-panel-text) !important;
}

:root[data-theme="dark"] [style*="color:#ff0000"],
:root[data-theme="dark"] [style*="color: #ff0000"],
:root[data-theme="dark"] [style*="color:#FF0000"],
:root[data-theme="dark"] [style*="color: #FF0000"] {
	color: var(--color-danger) !important;
}

:root[data-theme="dark"] [style*="color:#006600"],
:root[data-theme="dark"] [style*="color: #006600"] {
	color: var(--color-inline-green) !important;
}

:root[data-theme="dark"] [style*="color:#cccccc"],
:root[data-theme="dark"] [style*="color: #cccccc"],
:root[data-theme="dark"] [style*="color:#CCCCCC"],
:root[data-theme="dark"] [style*="color: #CCCCCC"] {
	color: var(--color-text-muted) !important;
}

:root[data-theme="dark"] [style*="background-color: #ffffff"],
:root[data-theme="dark"] [style*="background-color:#ffffff"],
:root[data-theme="dark"] [style*="background-color: #FFFFFF"],
:root[data-theme="dark"] [style*="background-color:#FFFFFF"] {
	background-color: var(--color-bg) !important;
}

:root[data-theme="dark"] table[bgcolor="#CCCCCC"],
:root[data-theme="dark"] table[bgcolor="#cccccc"],
:root[data-theme="dark"] tr[bgcolor="#CCCCCC"],
:root[data-theme="dark"] tr[bgcolor="#cccccc"],
:root[data-theme="dark"] td[bgcolor="#CCCCCC"],
:root[data-theme="dark"] td[bgcolor="#cccccc"] {
	background-color: var(--color-cell-label-bg);
}

/* ============================================================================
   Print stylesheet
   Produces a clean, single-column, light-on-white layout when the user
   prints or saves as PDF — regardless of the screen color scheme.
   ============================================================================ */
@media print {
	/* Force light theme so dark-mode users don't waste ink on dark backgrounds */
	:root {
		--color-bg: #fff;
		--color-text: #000;
		--color-link: #00c;
		--color-link-visited: #609;
		--color-link-active: #009b00;
		--color-header-bg: #993300;
		--color-header-text: #ffff00;
		--color-panel-bg: #ffffcc;
		--color-panel-text: #800000;
		--color-code-bg: #e1ffe1;
		--color-results-bg: #ddffff;
		--color-cell-label-bg: #e8e8e8;
		--color-emphasis: #000099;
		--color-border-soft: #cccccc;
		--color-border-mute: #999999;
	}

	/* Base print typography */
	body {
		font-size: 11pt;
		line-height: 1.4;
		color: #000;
		background: #fff;
	}

	/* Hide decorative chrome that doesn't belong on a printed page. None of
	   these elements have a competing `display` rule elsewhere in course.css,
	   so source order alone wins. */
	.hero img,
	.skip-link,
	theme-toggle,
	ul.toc,
	lesson-toc {
		display: none;
	}

	/* Expand multi-column section grid to a single column */
	.section-grid {
		display: block;
		grid-template-columns: none;
	}

	/* Reveal external link URLs after the anchor text */
	a[href^="http"]::after {
		content: " (" attr(href) ")";
		font-size: 90%;
	}

	/* Prevent code samples from splitting across page breaks */
	pre,
	.code-record {
		break-inside: avoid;
	}

	/* Undo any dark-mode invert filter on images. The dark-mode rulesets set
	   `--img-filter` on `:root[data-theme="dark"]` or
	   `:root:not([data-theme="light"])` (both specificity 0,2,0). Resetting on
	   the same selectors here matches that specificity, and source order
	   makes the print declarations win — no `!important` required. */
	:root,
	:root[data-theme="dark"],
	:root:not([data-theme="light"]) {
		--img-filter: none;
	}
}
