/*
Theme Name: Capitalism Lab Core
Theme URI: https://www.capitalismlab.com/
Author: Built for Capitalism Lab
Description: Parent theme for capitalismlab.com. Holds all templates, navigation and layout; the three child themes (Boardroom, Ledger, Split) supply the palette and typography. Built for a 361-page documentation and marketing site with a 181-item, three-level menu. Not intended to be activated directly — activate a child theme instead.
Version: 1.0.0
Requires at least: 6.0
Tested up to: 7.0.2
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: caplab
Tags: documentation, responsive, accessibility-ready, custom-menu, translation-ready
*/

/* ==========================================================================
   0. WEBFONTS — self-hosted

   Inter for text, Poppins for display. Both SIL Open Font License, both served
   from this origin.

   Self-hosted rather than a font CDN, for three reasons:

     - Chrome 86 and Safari partitioned the HTTP cache by origin in 2020, so a
       Google-hosted font is downloaded fresh per site anyway. The shared-cache
       argument that justified font CDNs no longer exists.
     - A font CDN costs two extra origins and a four-hop critical path:
       HTML -> fonts.googleapis.com (CSS) -> fonts.gstatic.com (files), each with
       its own DNS lookup and TLS handshake. These files come from an origin the
       browser has already connected to, behind the same Cloudflare edge.
     - A Munich court ruled in January 2022 that passing visitor IP addresses to
       Google Fonts without consent breaches GDPR. This site sells into Europe.

   unicode-range is what keeps it cheap: a visitor loads the latin file only, and
   picks up latin-ext solely if an accented glyph actually appears on the page.
   Typical cost is 96 KB (inter-latin 47 + source-serif-4-latin 49).

   The site is English-only — the eleven languages advertised on the home page are
   in-game, not on the web. No Cyrillic or CJK subsets are shipped. If that ever
   changes, Cyrillic is two more @font-face blocks; CJK would not be self-hosted
   at all (Noto Sans SC is ~10 MB) and would fall through to the system face.

   Source Serif 4 was here and has been removed. Nothing in the active render path
   set it once Classic went back to Georgia, so it was two @font-face blocks and
   93 KB of files that no page could ever reach. Split, Boardroom and Ledger still
   name it in their tokens, and that is deliberately left as a loose end: if one
   of them wins D2 its fonts have to be wired up and verified anyway, and a
   dormant declaration sitting here would not have saved that work — it would only
   have hidden the fact that it was outstanding. See capitalism-lab-theme-plan.md
   section 7.4.

   font-display: swap everywhere — text paints immediately in the fallback and
   swaps when the file lands. A webfont must never hide content.
   ========================================================================== */

@font-face {
	font-family: "Inter";
	font-style: normal;
	font-weight: 100 900;      /* variable: one file covers the range */
	font-display: swap;
	src: url("assets/fonts/inter-latin.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
		U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122,
		U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: "Inter";
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url("assets/fonts/inter-latin-ext.woff2") format("woff2");
	unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
		U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* EXPERIMENT: Poppins, used only by page 10729 (/home-background-test2/).
   Delete with the rest of that experiment.

   A geometric sans in the mould of the typography EA uses on thesims.com —   near-circular bowls, wide apertures, heavy headings. It is the house style of
   consumer game marketing, and reads noticeably warmer and less corporate than
   Inter + Source Serif 4.

   Static weights rather than variable: Google publishes no variable cut of
   Poppins. That is unusually cheap here anyway — the Latin subset is only 7 KB a
   weight, so all three together cost less than half of Inter alone. */
/* --- COMPARISON ONLY: Plus Jakarta Sans and Figtree --------------------------
 *
 * Downloaded 2026-08-14 for the /font-comparison/ page, which sets the site's
 * real headings and card text in four faces side by side so a choice can be made
 * from the actual content rather than from a description.
 *
 * Both are variable — every weight in one file — which is why they undercut
 * Inter despite being newer: Figtree 20 KB, Plus Jakarta Sans 27 KB, Inter 47 KB.
 * Both are SIL OFL, so self-hosting is permitted.
 *
 * They are fetched ONLY by the comparison page, because nothing else names them.
 * DELETE these two blocks and the two files when the comparison is over, unless
 * one of them wins.
 */
@font-face {
	font-family: "Plus Jakarta Sans";
	font-style: normal;
	font-weight: 200 800;
	font-display: swap;
	src: url("assets/fonts/plus-jakarta-sans-latin.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
		U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122,
		U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: "Figtree";
	font-style: normal;
	font-weight: 300 900;
	font-display: swap;
	src: url("assets/fonts/figtree-latin.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
		U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122,
		U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "Poppins";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("assets/fonts/poppins-latin-400.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
		U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122,
		U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: "Poppins";
	font-style: normal;
	font-weight: 600;
	font-display: swap;
	src: url("assets/fonts/poppins-latin-600.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
		U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122,
		U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: "Poppins";
	font-style: normal;
	font-weight: 700;
	font-display: swap;
	src: url("assets/fonts/poppins-latin-700.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
		U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122,
		U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   1. DESIGN TOKENS
   Children override the values; nothing below this block hard-codes a colour.
   ========================================================================== */

:root {
	--clab-bg:            #ffffff;
	--clab-surface:       #f6f6f4;
	--clab-surface-2:     #ecebe8;

	/* Card index surfaces, as tokens rather than literals.
	   The resting and hover states were swapped on 2026-08-14 — cards used to sit
	   on --clab-surface and lift to white, and now rest on white and settle onto
	   the surface tone. The pair has to move together, and hard-coding #ffffff
	   for either end breaks the dark children, where a white card on a dark
	   ground is the wrong way round entirely. Boardroom and Split override both
	   in their own :root. */
	--clab-card-bg:       #ffffff;
	--clab-card-bg-hover: var(--clab-surface);
	--clab-text:          #1f2124;
	--clab-text-dim:      #5b6068;
	--clab-heading:       #14161a;
	--clab-accent:        #b8860b;
	--clab-accent-ink:    #14161a;
	--clab-link:          #1e5fbf;
	--clab-link-hover:    #14408a;
	--clab-border:        #d9d8d4;
	--clab-border-strong: #b9b8b3;

	--clab-header-bg:     #14161a;
	--clab-header-ink:    #f2f1ee;
	--clab-header-dim:    #a9adb4;
	--clab-header-border: rgba(255, 255, 255, .12);
	--clab-mega-bg:       #1c1f26;
	--clab-mega-ink:      #e6e5e1;
	--clab-drawer-bg:     #14161a;

	/* Separate from the header so a light theme can still ground the page
	   with a dark footer. */
	--clab-footer-bg:     #14161a;
	--clab-footer-ink:    #f2f1ee;
	--clab-footer-dim:    #a9adb4;
	--clab-footer-border: rgba(255, 255, 255, .12);

	/* The newsletter call to action in the footer. Orange on every direction,
	   as it is on the live site — it is the one button the site asks every
	   visitor to press, so it is deliberately not tied to the theme accent. */
	--clab-cta:           #e67e22;
	--clab-cta-hover:     #d2701a;
	--clab-cta-ink:       #ffffff;

	--clab-code-bg:       #f2f1ee;
	--clab-shadow:        0 10px 34px rgba(0, 0, 0, .18);
	--clab-focus:         #ffb100;

	/* Callout panels on the how-to pages (§13). Deliberately their own tokens
	   rather than a tint of the accent: Classic's accent is brown, and brown
	   mixed into its grey surface lands on taupe, which reads as "disabled"
	   rather than "read this". These two values are the pair the owner settled
	   on for the highlighted card on /tycoon-games/, so the two treatments
	   match. Boardroom overrides them — a cream panel on a dark page is wrong. */
	--clab-note-bg:       #fffcf3;
	--clab-note-border:   #e8c873;

	/* Both faces are real — see the @font-face blocks above. The fallbacks still
	   matter: they are what renders during `font-display: swap`, so they are
	   chosen to be metrically close rather than merely available.

	   Poppins for display, Inter for text. Decided 2026-08-14 after setting the
	   whole site in Poppins and reading it:

	     - Poppins earns its place in headings and navigation. Its near-circular
	       bowls and generous width give a headline real presence, and nav labels
	       are scanned rather than read, so the extra width helps there too.
	     - Those same round forms cost too much in body copy. a/e/o/c are built
	       from one shape, so there is less to tell letters apart and long
	       passages tire. Across 361 documentation pages that is a real expense,
	       and it is exactly where Inter's larger x-height and tighter, more
	       differentiated forms pay.

	   Source Serif 4 stops being downloaded as a result — a visitor now fetches
	   Inter 47 KB + Poppins 14 KB = 61 KB, against 96 KB before. Its @font-face
	   and files stay on disk deliberately: Split, Boardroom and Ledger all name it
	   in their own tokens, and an unused @font-face costs nothing, since a font is
	   only fetched when something actually sets it.

	   ONE FAMILY, 2026-08-14. --clab-font-display was "Poppins", "Inter", …and
	   is now Inter as well. Chosen after looking at a reference the owner liked
	   (vyond.com), which was measured rather than guessed — it loads a single
	   commercial face, Sailec, at four weights and uses it for headings AND body,
	   separating the two by weight alone. That is the arrangement being copied
	   here; Poppins stays on disk and in its @font-face block, costing nothing,
	   since a font is only fetched when something sets it. */
	--clab-font-body:     "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
	--clab-font-display:  "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
	--clab-font-mono:     ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

	--clab-radius:        6px;
	--clab-radius-lg:     12px;

	--clab-container:     1240px;
	/* The bar is wider than the reading container: capping it at 1240px left
	   room for only about five of the thirteen sections, pushing the rest
	   into the More panel even on a large monitor. */
	--clab-container-wide: 1600px;
	--clab-measure:       68ch;
	--clab-header-h:      64px;
	--clab-gap:           clamp(1rem, 2.5vw, 2rem);
}

/* ==========================================================================
   2. BASE
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
	scroll-padding-top: calc(var(--clab-header-h) + 1rem);
}

body {
	margin: 0;
	background: var(--clab-bg);
	color: var(--clab-text);
	font-family: var(--clab-font-body);
	font-size: 1.0625rem;
	line-height: 1.65;
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden; /* belt and braces against legacy fixed-width content */
}

img, video, iframe, embed, object, canvas, svg { max-width: 100%; }
img, video { height: auto; }

a { color: var(--clab-link); text-decoration-thickness: 1px; text-underline-offset: .16em; }
a:hover { color: var(--clab-link-hover); }

h1, h2, h3, h4, h5, h6 {
	font-family: var(--clab-font-display);
	color: var(--clab-heading);
	line-height: 1.2;
	margin: 2em 0 .6em;
	overflow-wrap: break-word;
}
h1 { font-size: clamp(1.9rem, 1.2rem + 2.6vw, 2.9rem); margin-top: 0; }
h2 { font-size: clamp(1.5rem, 1.1rem + 1.5vw, 2.05rem); }
h3 { font-size: clamp(1.25rem, 1.05rem + .8vw, 1.55rem); }
h4 { font-size: 1.2rem; }
h5, h6 { font-size: 1.05rem; }

p, ul, ol, dl, table, pre, blockquote, figure { margin: 0 0 1.15em; }

hr {
	border: 0;
	border-top: 1px solid var(--clab-border);
	margin: 2.5rem 0;
}

/* ==========================================================================
   3. ACCESSIBILITY
   ========================================================================== */

.screen-reader-text {
	border: 0;
	clip-path: inset(50%);
	height: 1px; width: 1px;
	margin: -1px; padding: 0;
	overflow: hidden;
	position: absolute !important;
	white-space: nowrap;
}

.clab-skip-link:focus {
	clip-path: none;
	height: auto; width: auto;
	margin: 0;
	padding: .75rem 1.25rem;
	position: fixed !important;
	top: .5rem; left: .5rem;
	z-index: 9999;
	background: var(--clab-accent);
	color: var(--clab-accent-ink);
	border-radius: var(--clab-radius);
	font-weight: 600;
}

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 3px solid var(--clab-focus);
	outline-offset: 2px;
	border-radius: 3px;
}

/* ==========================================================================
   4. LAYOUT
   ========================================================================== */

.clab-container {
	width: min(100% - 2.5rem, var(--clab-container));
	margin-inline: auto;
}

.clab-main { padding-block: clamp(1.5rem, 4vw, 3rem) 4rem; }

.clab-layout {
	display: grid;
	gap: clamp(1.5rem, 4vw, 3.5rem);
	align-items: start;
}

body.clab-has-sidebar .clab-layout { grid-template-columns: 1fr; }

@media (min-width: 1024px) {
	/* 224px — 80% of the original 280px. The titles in the tree wrap to two
	   lines either way, and the narrower column hands the width back to the
	   article, which is the part people came to read. */
	body.clab-has-sidebar .clab-layout { grid-template-columns: 224px minmax(0, 1fr); }
}

.clab-article { min-width: 0; }
.clab-article > * { max-width: var(--clab-measure); }

/* Media and tables are allowed to exceed the reading measure. */
.clab-article > figure,
.clab-article > table,
.clab-article > .wp-caption,
.clab-article > .gallery,
.clab-article > .clab-gallery,
.clab-article > iframe,
.clab-article > .clab-wide { max-width: 100%; }

body.clab-mode-marketing .clab-article > * { max-width: none; }

/* --- Content divs take part in the vertical rhythm --------------------------
 *
 * 361 pages of hand-written classic-editor HTML use bare <div> and
 * <div class="paragraph"> as block containers, and a div has no margin. Every
 * other block does: p carries margin-bottom 22.5px, h2 25px above, h3 22px, ul
 * 17.25px. So text in a div sat flush against whatever followed it.
 *
 * The authors worked around this by hand, with 378 copies of
 * `<div style="height: 20px; clear: both"></div>` across 118 pages. Measured on
 * the worst offenders, most of those sit between two divs — "after DIV(mb 0px)
 * before DIV(mt 0px)" — which is precisely the gap this rule closes.
 *
 * 1.45em rather than a pixel value, so the gap tracks the font size instead of
 * being 20px whether the text is 15px or 17px. At Classic's 15px that is 21.75px,
 * within a pixel and a half of what the spacers produced.
 *
 * Divs WITH a class are left alone — the card grids, the DLC call-to-action
 * panels and the theme's own components all carry their own spacing, and a blunt
 * rule would add to it. `.paragraph` is the exception because it is a content
 * class the authors used for exactly this purpose, not a component.
 *
 * Nested divs are safe: adjacent vertical margins collapse, so a div inside a
 * div produces one gap, not two.
 *
 * :not([style]) IS LOAD-BEARING, added after this rule caused a visible bug.
   Without it the selector also matched hand-written LAYOUT divs — the language
   cards on the home page and /buy-game/ are classless divs carrying an inline
   grid-card style, so each picked up 22px of bottom margin. That inflated every
   grid row from 50px to 72px, and because the last card in the grid is
   :last-child its margin was zeroed by the rule below, so it alone stretched to
   fill the row: "Russian Русский" rendered 22px taller than its neighbours with
   identical markup.

   A classless div WITH an inline style is layout the author positioned by hand.
   A classless div WITHOUT one is a content block, which is what needs the
   rhythm. That is the distinction, and it is expressible in a selector. */
.clab-article div.paragraph,
.clab-article div:not([class]):not([style]) {
	margin-bottom: 1.45em;
}

/* Nothing should add a trailing gap at the very end of the article. */
.clab-article div.paragraph:last-child,
.clab-article div:not([class]):not([style]):last-child {
	margin-bottom: 0;
}

/* --- Space under content images and loose buttons ----------------------------
 *
 * Two reports, one root cause: inline-level content with text immediately after
 * it. An inline box's vertical margins do not move the line boxes around it, so
 * until the element is block-level no stylesheet can put space under it.
 *
 * IMAGES. Content images are written as `<p><img …<br>caption text</p>`, and an
 * <img> is inline by default, so it sits on the text baseline and the following
 * line starts against it. Measured on /new-content/warehouse/: the text began
 * 15px ABOVE the image's bottom edge.
 *
 * :not(.emoji) is load-bearing. WordPress replaces emoji characters with
 * <img class="emoji"> — including every topic glyph on a heading and in a card,
 * 40 on a single page — so a blunt rule would put each glyph on its own line and
 * break the card grid. Content images carry wp-image-*; glyphs carry .emoji.
 *
 * Floats are unaffected: a floated element is already block-level, and `float`
 * is not touched here.
 *
 * :only-child is the other half of the guard. An image alone in its own <p>
 * already spaces correctly on the paragraph's margin, so it is left completely
 * alone — the rule only reaches images that share a parent with other content,
 * which is exactly the broken shape. That keeps the blast radius small across
 * 361 hand-written pages.
 *
 * BUTTONS. 156 of the site's 242 MaxButton placements are written bare in the
 * flow rather than inside a block, so they have no container to carry a margin.
 * A margin is enough and no display change is needed: MaxButtons renders
 * `display: inline-flex`, an ATOMIC inline-level box, whose vertical margins DO
 * count toward the line box (unlike a plain inline box). Do not try to force it
 * block-level anyway — MaxButtons' own inline <style> uses a three-class
 * selector, (0,3,0), and silently wins over anything of this specificity.
 *
 * Measured at 1440, before -> after: the image gap on /new-content/warehouse/
 * -15px -> 16px, the button gap on /improvements/natural-resources/ 0px -> 22px
 * and on /new-features/inflation/ 1px -> 23px.
 */
.clab-article img:not(.emoji):not(.wp-smiley):not(:only-child) {
	display: block;
	margin-bottom: 1em;
}

/* An exception, and it must outrank the rule above — that one is (0,4,1), so
 * these repeat the :not()s to reach (0,4,2). Two images written next to each
 * other are a deliberate row (there are 27 such pairs, e.g. /shopping-mall/);
 * blockifying them stacked the row and grew that page by 615px. */
.clab-article img:not(.emoji):not(.wp-smiley):not(:only-child):has(+ img),
.clab-article img:not(.emoji):not(.wp-smiley):not(:only-child) + img {
	display: inline;
	margin-bottom: 0;
}

/* Once the image is block-level it ends its own line, so the <br> the author
 * wrote after it is a second break — an empty line box worth ~22px on top of
 * the margin. That was the "too much space" on the warehouse page: 45px, not
 * the 16px the margin asks for. Skip it for images in a row, which still need
 * their break. NOTE: do NOT extend this to `a.maxbutton + br`. The button is
 * inline-flex, so that <br> is the only thing putting the text on the next
 * line; hiding it drove the inflation page to -26px, text over the button. */
.clab-article img:not(.emoji):not(.wp-smiley):not(:only-child):not(img + img) + br {
	display: none;
}

.clab-article a.maxbutton:not(:only-child) {
	margin-bottom: 1.45em;
}

/* A button alone inside a wrapper div fell through BOTH spacing rules, and the
 * gap under it measured 0px on /ces-dlc/ and its siblings.
 *
 *   <div style="…><a class="maxbutton">Buy — /a></div>
 *
 * The rule above skips it because the button IS an only child; the classless-
 * div rule skips it because the wrapper carries a style attribute. That
 * :not([style]) guard is load-bearing — without it, inline-styled grid cards
 * pick up a bottom margin and the language-card rows grow by 22px — so the fix
 * is not to relax it but to name this shape exactly.
 *
 * :has(> a.maxbutton:only-child) means "a div whose sole content is a button",
 * which a card never is: cards hold a heading, a description and a link. An
 * inline margin-bottom on the wrapper still wins over this, so a wrapper that
 * already spaces itself is left as it is rather than being doubled. */
.clab-article div:has(> a.maxbutton:only-child) {
	margin-bottom: 1.45em;
}

/* --- A float clear that carries no height ------------------------------------
 *
 * Three of the 378 hand-written spacers were genuinely clearing a float, on the
 * three pages that float anything at all. Those keep a clear; they do not keep a
 * 20px height, because the rule above now supplies the spacing.
 *
 * `display: flow-root` on the container would be the better answer and needs no
 * element at all — but the containers here are hand-written divs of unknown
 * shape across 361 pages, and adding a class to the markup that already exists
 * is the smaller, checkable change. Worth revisiting if the floats are ever
 * rebuilt as a grid, at which point all three can go.
 */
.clab-article .clab-clear {
	clear: both;
	height: 0;
	margin: 0;
}

/* --- Header: brand mark inline with the menu --------------------------------
   PROMOTED SITE-WIDE 2026-08-14. This began as an experiment on page 10729
   (/home-background-test2/) and was scoped to body.home while it was being
   compared against the control. It is now the site's header, so the scope is
   gone: there is one menu and every page gets it.

   What that changed in practice — the pages that were NOT the home page had a
   two-row header with the wordmark on its own line, the search field in the bar,
   and no BUY GAME button. They now match the home page exactly.

   The header BACKGROUND was already site-wide: caplab-classic sets #20243A on
   .clab-header unscoped, so only the layout was ever home-only.

   The mark was invisible on desktop, and not because of the artwork: the theme
   sets .clab-header__bar to display:none above 1024px. The whole logo row is
   mobile-only by design, because on desktop the banner underneath carries the
   identity. Traced by walking up from the img — it measured 0x0, its <a> measured
   0x0, and the .clab-container above them was display:none.

   Simply un-hiding it would restore Rundown's two-row header and cost ~48px of
   vertical space before the menu even starts. What was asked for is the icon
   BESIDE the menu, so the header becomes a single flex row: mark on the left,
   navigation taking the remaining width.

   Desktop only. Below 1024px the drawer already shows the mark in its own bar and
   this must not interfere with it. */
@media (min-width: 1024px) {
	.clab-header {
		display: flex;
		align-items: center;
		gap: .2rem;
	}
	.clab-header__bar{
		display: flex;
		/* .clab-container caps at 1180px and centres; neither is wanted for what
		   is now a fixed-width item in a flex row. */
		max-width: none;
		width: auto;
		flex: 0 0 auto;
		min-height: 0;
		/* Inline breathing room at the left end of the bar, so the mark is not
		   pressed against the window edge. The right end is handled by padding on
		   .clab-header itself, below — the two values must stay in step or the
		   header looks off-centre against the content column beneath it.

		   WIDENED 2026-08-15 at the owner's request, from a flat 2.25rem to the
		   clamp below. The header is full-bleed by design — see the note beside
		   .clab-header__navwrap .clab-container about giving the navigation the
		   whole window — so this gutter is the only thing separating the menu
		   from the screen edge, and 36px read as none at all beside a content
		   column that starts at 130px.

		   WHY IT STOPS AT 5vw. The menu's widest row needs 1,137px at 1440. The
		   navwrap gets what is left after this gutter on both sides and the
		   108px mark, so at 5vw (72px a side) it still has 1,221px and stays on
		   two rows. Matching the content column exactly (130px a side) would
		   leave 1,072px and push the header to three rows, making it taller on
		   every page. Measured, not estimated: header-widths.js reports the same
		   row counts before and after this change at 1024 through 2560.

		   LEFT ONLY. `padding-inline` would set the right side too, pushing the
		   navwrap away from the mark — which is exactly the 88px gap between the
		   icon and the first menu item that the navwrap note below records as a
		   past regression. */
		padding: 0 0 0 clamp(1.5rem, 8vw, 8rem);
	}
	.clab-header__navwrap{
		flex: 1 1 auto;
		min-width: 0;
		border-top: 0;
	}
	/* The matching space at the right end, where BUY GAME would otherwise run to
	   the window edge. Same clamp as the bar's left padding — change both or
	   neither. */
	.clab-header { padding-right: clamp(1.5rem, 8vw, 8rem); }

	/* The navwrap container's sizing lives beside the .clab-header__navwrap
	   .clab-container rule further down, so the two are not fighting at equal
	   specificity with the later one silently winning. */
	/* The wordmark would eat the width the menu needs — the icon alone is the
	   brief, and the site name is already in the banner below.

	   HIDDEN VISUALLY, NOT FROM ASSISTIVE TECHNOLOGY (fixed 2026-08-15). This
	   was `display: none`, which also removes the text from the accessibility
	   tree — and that left the brand link with NO ACCESSIBLE NAME AT ALL. It is
	   the only home link on the site: caplab_drop_home_menu_item() deliberately
	   removes the "Home" entry precisely because the mark carries it, and the
	   icon inside is alt="" aria-hidden="true". So on all 359 pages a screen
	   reader announced the home link as its bare URL (WCAG 2.4.4, 4.1.2).
	   The rule now uses the same clip technique as .screen-reader-text, which
	   takes NO layout space — position:absolute at 1px — so the menu keeps every
	   pixel the original rule was protecting.

	   The tagline stays fully hidden: it is a strapline, not part of the link's
	   purpose, and folding it in would make the name a sentence. The accessible
	   name is therefore the site title alone. */
	.clab-brand__text{
		border: 0;
		clip-path: inset(50%);
		height: 1px; width: 1px;
		margin: -1px; padding: 0;
		overflow: hidden;
		position: absolute;
		white-space: nowrap;
	}
	.clab-brand__text small{ display: none; }

	/* The mark's desktop size lives with the base .clab-brand__mark rule further
	   down, not here — a duplicate at equal specificity earlier in the file
	   simply loses on order. */

	/* Search is hidden at every width by the base .clab-header .clab-search rule
	   in the search section, not from here. A duplicate here would lose to the
	   1180px block that follows it, which is what made the header 465px tall for
	   a while — see the note beside that rule.

	   ⚠Desktop search is gone site-wide as a consequence of one header rather
	   than two. header.php is untouched and the mobile drawer still carries the
	   field, so it is one declaration away from returning once D5's menu
	   restructure frees the width. */

	}

/* --- BUY GAME as a button ----------------------------------------------------
   PROMOTED SITE-WIDE 2026-08-14, with the rest of the header. It was an
   experiment on page 10729; every page now carries the same commercial button.

   Modelled on the pattern Blizzard uses on diablo.com: every navigation label is
   plain text except the commercial one, which is a solid filled pill pushed to
   the far right of the bar. The contrast is the whole mechanism — one button
   cannot look like a call to action while sitting in a row of things that look
   the same as it.

   --clab-cta is used rather than a new red. That token already exists precisely
   for this: it is the one colour on the site reserved for "press this", which is
   why the newsletter button uses it and why it is deliberately not tied to the
   theme accent. A second commercial colour would dilute the first.

   The button sits in normal flow, directly after Download, rather than being
   pushed to the right edge with margin-left: auto. Diablo can pin Buy Now to the
   far right because its bar holds six items on one row; this menu has thirteen
   across two, so a right-pinned item lands under the middle of the first row
   with empty space beside it and reads as detached rather than deliberate. Next
   to the last item it still stands out — the fill is doing that work, not the
   position. */
@media (min-width: 1024px) {
	.clab-nav-cta > .clab-nav__link {
		background: var(--clab-cta);
		color: var(--clab-cta-ink);
		border-radius: 6px;
		padding: .5rem 1.15rem;
		margin-left: .5rem;
		font-weight: 700;
		letter-spacing: .01em;
		transition: background .18s ease, transform .18s ease;
	}
	.clab-nav-cta > .clab-nav__link:hover,
	.clab-nav-cta > .clab-nav__link:focus-visible{
		background: var(--clab-cta-hover);
		/* A press-like nudge rather than a colour change alone: the item is a
		   button, so it should behave like one under the pointer. */
		transform: translateY(-1px);
	}
	/* The accent-on-hover rule for ordinary items would repaint the label and
	   destroy the contrast the fill is providing. Classic's own #6fa8dc rule is
	   (0,3,0) and this is (0,4,0), so this still wins. */
	.clab-nav__item--depth-0.clab-nav-cta:hover > .clab-nav__link{
		color: var(--clab-cta-ink);
	}

	/* ON ITS OWN PAGE the button was rendering its label in Classic's
	   current-section blue, #4A9AE1, on the orange fill: **1.05:1**, which is not
	   low contrast but effectively no contrast. The label was invisible on
	   /buy-game/ — the one page where the button matters least, but also the one
	   where a broken-looking control is most costly.

	   The cause is ordinary specificity. Classic marks the current section with

	       .clab-nav__item--depth-0.current-menu-item > .clab-nav__link  (0,3,0)

	   which outranks the CTA's own (0,2,0) colour. Adding .clab-nav-cta makes this
	   (0,4,0) and settles it, the same way the hover rule above does.

	   BLACK, not the white used in the resting state. Measured on #E67E22:
	   black is 7.37:1 and white is 2.85:1 — so the selected state is now the most
	   legible version of this button, and it is the only one that clears 4.5:1.
	   Worth noting for the promotion button's recorded exception: black over that
	   orange is the fix there too, if the white is ever reconsidered. */
	.clab-nav__item--depth-0.clab-nav-cta.current-menu-item > .clab-nav__link,
	.clab-nav__item--depth-0.clab-nav-cta.current_page_item > .clab-nav__link,
	.clab-nav__item--depth-0.clab-nav-cta.current-menu-ancestor > .clab-nav__link{
		color: #000000;
	}
}

/* The navigation keeps a plain sans face, not Poppins.
   Originally set so the menu read identically to the control while the home page
   was being compared against it; kept, and now site-wide, because it is the face
   the live menu uses and Classic exists to reproduce that.

   Stated explicitly rather than left to inherit — the home page's body rule is
   Inter, so inheriting would give the bar Inter on one page and something else
   on the rest, which is the split this change exists to remove. */
.clab-nav__link,
.clab-mega__heading{
	font-family: sans-serif;
}
/* A heading that OPENS a container gets no top margin.
   The 1.7em above exists to separate one section from the previous one, which is
   right in flowing content and wrong at the top of a card — there it stacked on
   the card's own 28px of padding and opened roughly 77px above "Buy Capitalism
   Lab". The margin is for the gap BETWEEN sections, not the gap INSIDE one. */
body.clab-home-style .clab-article h1:first-child,
body.clab-home-style .clab-article h2:first-child,
body.clab-home-style .clab-article h3:first-child,
body.clab-home-style .clab-article > div > div > h2:first-child {
	margin-top: 0;
}

/* Breathing room between the top-level menu items.
   They currently sit flush, separated only by their own padding, which reads as
   crowded at thirteen items. Note this does NOT worsen the wrap: the bar is
   already two rows at 1,439px against 1,189px available, so a few px of gap
   changes nothing structural. Fixing that is menu-restructure-proposal.md. */
.clab-nav > .clab-menu{
	/* Split rather than a single `gap`, because the two axes want opposite things
	   here: the horizontal spacing was widened to stop the items reading as
	   crowded, while the vertical gap between the wrapped rows is dead space in a
	   header that is already over 100px tall.

	   8.8px -> 7.04px (-20%) -> 5.63px (-20% again). Below about 4px the two rows
	   start to read as one block of tangled labels rather than two rows, so there
	   is not much further to go by this route — the remaining height is the link
	   padding (10px top and bottom, matching production) and, ultimately, the
	   thirteen items that force a second row at all. */
	column-gap: .55rem;
	row-gap: .352rem;
}

/* The vertical padding is what actually separates the rows.

   row-gap alone could not do this. Between the two rows of labels sits
   10px of padding-bottom + the row-gap + 10px of padding-top, so at 8.8px the
   gap was barely a third of the total and every reduction to it moved the rows
   by a couple of pixels. Cutting the block padding from 10px to 6px takes the
   label-to-label distance from about 25.6px to 17.6px — a change that is
   actually visible.

   This is a deliberate departure from the production spec, now site-wide.
   10px top and bottom is what www.capitalismlab.com uses and what
   /home-measure-test/ still reproduces; here the header is carrying a 56px mark,
   twelve items and a filled button, so the vertical budget is tighter. Inline
   padding stays at 17px, so the horizontal rhythm is untouched.

   DESKTOP ONLY, and that was a real bug for a while. Without the media query it
   also applied to the mobile drawer, where each row is 44px tall from min-height
   rather than from padding — so cutting the padding did not shrink the row, it
   just left the label sitting near the top of it with a gap underneath, out of
   line with the chevron beside it. The two-row problem this solves does not exist
   in the drawer, which stacks one item per line.

   The value itself is set on the base .clab-nav__item--depth-0 rule in the
   desktop navigation section further down — which is inside the same 1024px
   media query, so the drawer is still unaffected. It was briefly duplicated
   here, which did nothing: an identical selector earlier in the file loses on
   order. */

/* MaxButtons labels take the site font.

   The plugin writes its own inline <style> and pins every button to Arial,
   through a selector built from three classes per button:

       .maxbutton-30.maxbutton.maxbutton-educational-uses-of-capita { font-family: Arial }

   That is 0,3,0 — and there is one of them for each of the thirty-odd buttons,
   named after the button's own label. There is no single rule to outrank and no
   stable list to enumerate, so !important is the honest tool here rather than a
   shortcut: any specificity war would have to be re-fought every time a button is
   renamed in the plugin.

   Family only. Size, weight and colour stay with the plugin, because those are
   configured per button in its own tables and overriding them here would silently
   detach the buttons from the interface the site owner actually edits them in.

   The face is named explicitly rather than taken from var(--clab-font-display).
   That token belongs to Classic again, now that the live page has gone back to
   being an unmodified control, so it resolves to Georgia. A page-scoped rule
   must not depend on a token the rest of the site owns. */
body.clab-home-style .maxbutton,
body.clab-home-style .maxbutton .mb-text {
	font-family: var(--clab-font-body) !important;
}

/* --- EXPERIMENT: background treatment, §5.3 --------------------------------
   Scoped to /home-background-test/ (page 10728), a throwaway copy of the home
   page. Delete this block, and the page, once D2 is settled.

   What it currently is, measured:

     body                      rgb(32,32,32) + black_twill.png (2017 upload)
     main > .clab-container    WHITE, 1180px, 8px radius, 26px padding
     footer > .clab-container  WHITE, 1180px, 12px radius
                               130px of dark twill visible either side

   A white sheet floating on a dark texture — the "paper on a desk" metaphor that
   dominated 2005–012 and has essentially vanished since.

   The awkward part is that the CONTENT already carries its own section cards:
   `background:#fff; border:1px solid #e3e7ee; border-radius:16px`. So today the
   page is white cards inside a white card, on a pattern. The inner borders are
   the only thing actually separating one section from the next, and they are
   doing it invisibly — white on white.

   The change is therefore mostly subtractive:

     1. Texture out, flat light neutral in. #f5f6f8 rather than pure white, so the
        content cards have something to sit against.
     2. The outer white sheet goes transparent. Its rounded corners and padding
        were what made the page look like an object on a surface; without them the
        background simply runs edge to edge behind a constrained column.
     3. Section separation now comes from background colour — the content's own
        white cards against the grey — which is what the inner borders were
        reaching for and could not achieve on white.

   Deliberately NOT full-bleed. "Runs edge to edge" describes the BACKGROUND, not
   the text. Content stays at 1180px; four attempts on the other test page
   established that this content does not survive being widened.

   The footer keeps a band of its own, dark, spanning the full width — a colour
   change to close the page rather than a second floating card. */
/* The production menu's own typography and spacing, measured off
   www.capitalismlab.com rather than reconstructed:

     font-family   sans-serif        (Arial)
     font-size     16px              — the rebuild renders 15px
     font-weight   700
     padding       10px 17.008px
     li margin     0, ul gap 0

   The spacing between labels is not a gap. Rundown sets none at all: every
   item's separation comes from ~17px of horizontal padding on the link itself,
   so adjacent items touch and the ~34px of visual air between words is padding
   meeting padding. Reproducing it with a flex gap would look similar at rest and
   behave differently on hover, because the hover target would stop short of the
   space around it.

   This treatment is now applied SITE-WIDE rather than here — see the desktop nav
   block further down. Nothing page-scoped remains for the menu on 10727. */

/* --- EXPERIMENT: Option 5, system fonts only, page 10728 --------------------
   No webfont at all. `system-ui` resolves to whatever the platform ships —   Segoe UI on Windows, SF Pro on macOS and iOS, Roboto on Android, and on Linux
   whatever fontconfig decides. Zero bytes, zero requests, zero render-blocking.

   Kept as a live comparison because the case is genuinely strong: the reason this
   site read as dated was Arial and Georgia SPECIFICALLY, not the absence of a
   webfont. system-ui fixes most of that for nothing.

   What it costs is consistency. Every platform renders a different typeface with
   different metrics, so text wraps at different points — a heading that fits one
   line on a Mac can wrap on Windows, and the measure tuned on one screen is not
   the measure visitors get. Linux is a lottery. That is the whole trade: 61 KB
   for a page that looks the same everywhere, or nothing for a page that does not.

   Set on the elements rather than the tokens, so it beats the token values
   without the child theme having to know this experiment exists.

   The navigation is deliberately absent from the list: it takes the site-wide
   production menu treatment instead, so the two colour tests differ only in
   colour. */
/* .clab-footer was in this list and is deliberately no longer (2026-08-15).
   The footer is one component shared by every page; scoping any part of it to
   the home page is what produced two different-looking footers in the first
   place. It sets its own family and measure below. */
body.clab-home-style,
body.clab-home-style .clab-article p,
body.clab-home-style .clab-article div,
body.clab-home-style .clab-article li,
body.clab-home-style .clab-brand__text,
body.clab-home-style .clab-article h1,
body.clab-home-style .clab-article h2,
body.clab-home-style .clab-article h3{
	/* The token, not a hard-coded stack. This block named system-ui literally,
	   which meant the redesigned home page bypassed --clab-font-body and could
	   never pick up a webfont however the tokens were set — one of the two
	   reasons nothing on this site had ever loaded one. */
	font-family: var(--clab-font-body);
}

/* system-ui carries no display weight of its own, so the scale has to do the
   work the typeface is not doing. Without this the page reverts to Classic's flat
   30px for both h1 and h2 and looks unstyled rather than deliberately plain. */
/* Heading colour: #1B2138, a deep navy drawn from the page's own ground.

   Classic inherits Rundown's #843C0B — a mid brown chosen to sit with Georgia.
   Against a geometric sans it reads muddy, and it belongs to no other colour on
   the page.

   Three things current practice agrees on, and this follows all three:

     - Headings are darker and more saturated than body text, not a separate hue.
       Body here is #222; the heading is darker still, so hierarchy comes from
       weight and depth rather than from colour contrast between them.
     - Not pure black. #000 on white is harsher than any printed page and reads
       as unset rather than chosen. A very dark tinted neutral is the convention —       #111827 and #0F172A are the two most widely used.
     - The tint is borrowed from something already in the design. #1B2138 is the
       page's #2B304F ground taken down in lightness, so the heading and the
       surround share a hue instead of introducing a fourth colour.

   Contrast on the white card is roughly 16:1 — far past the 4.5:1 minimum, and
   past the 7:1 AAA threshold as well. */
body.clab-home-style .clab-article h1,
body.clab-home-style .clab-article h2,
body.clab-home-style .clab-article h3{
	color: #343c61;
}

/* Weight, tracking and leading — the three things that make a heading read as
   set rather than merely enlarged.

   WEIGHT descends with size. h1 at 700 has to carry the page; h3 at 600 is a
   label inside a section and stops competing with the h2 above it. Nothing goes
   to 800 or 900: extra-bold at 42px in a geometric sans turns into a solid block
   and loses the letterforms. Nothing drops to 300 either — thin display weights
   are a 2015 habit that reads as anaemic on anything but very large type.

   TRACKING tightens as size grows, and this is the detail most often skipped.
   Typefaces are spaced for body text, so at 42px the default gaps look loose and
   the word falls apart into letters. -.02em at h1, -.015em at h2, and none at h3
   — by 21px the default spacing is already correct, and tightening further would
   start to hurt legibility rather than help it.

   LEADING tightens as size grows too, for the same reason in the other axis:
   1.12 at h1, 1.22 at h2, 1.3 at h3, against 1.62 for body copy. A two-line
   heading set at body leading reads as two separate lines rather than one
   thought.

   MARGIN belongs to h2 only. It is the element that separates sections, so it
   gets 1.7em above; h1 opens the page and h3 sits inside a block its parent has
   already spaced.

   h4 to h6 complete the scale, and they invert two of the rules above rather
   than continuing them:

     - TRACKING loosens below body size instead of tightening. The reason is the
       same one that makes it tighten at 42px: a typeface is spaced for reading
       at about 16px, so above that the gaps are too wide and below it they are
       too tight. h6 at 15px takes +.02em for the same reason h1 takes -.02em.
     - SIZE stops descending and WEIGHT takes over. h5 and h6 sit at or below
       body size, so shrinking them further would make a heading smaller than the
       text it introduces. They separate themselves by weight and colour instead.

   h6 is set in small caps rather than made smaller still — it is the level used
   for eyebrow labels above a block, and at 15px there is nowhere left to go
   downwards. */
body.clab-home-style .clab-article h1{ font-size: 42px; line-height: 1.12; font-weight: 700; letter-spacing: -.02em; }
body.clab-home-style .clab-article h2{ font-size: 28px; line-height: 1.22; font-weight: 700; letter-spacing: -.015em; margin-top: 1.7em; }
body.clab-home-style .clab-article h3{ font-size: 21px; line-height: 1.3;  font-weight: 600; letter-spacing: normal; margin-top: 1.5em; }
body.clab-home-style .clab-article h4{ font-size: 18px; line-height: 1.35; font-weight: 600; letter-spacing: normal; margin-top: 1.4em; }
body.clab-home-style .clab-article h5{ font-size: 16px; line-height: 1.4;  font-weight: 600; letter-spacing: .01em; margin-top: 1.3em; }
body.clab-home-style .clab-article h6{
	font-size: 15px;
	line-height: 1.4;
	font-weight: 700;
	letter-spacing: .06em;
	text-transform: uppercase;
	margin-top: 1.3em;
	/* One step lighter than the others. An eyebrow label should be findable, not
	   assertive — at full heading weight AND uppercase it would outshout the h2
	   it sits above. */
	color: #5a647d;
}

/* A heading that opens a card takes no top margin — the 1.7em is for the gap
   BETWEEN sections, and inside one it stacks on the card's own padding. */
body.clab-home-style .clab-article h1:first-child,
body.clab-home-style .clab-article h2:first-child,
body.clab-home-style .clab-article h3:first-child,
body.clab-home-style .clab-article > div > div > h2:first-child{
	margin-top: 0;
}
/* Size is set on the BODY, not on p and li.

   Setting it on those two left <div class="paragraph"> blocks behind — the "100%
   Risk Free Purchase" text is one, and it rendered at Classic's 15px beside
   17px paragraphs in the sections above and below it. This content is
   hand-written HTML and its text sits in whatever element the author reached
   for: <p>, <div class="paragraph">, and bare <div>. Enumerating them is a game
   of whack-a-mole.

   Inheriting from the body catches all of them at once. Anything that needs a
   different size — headings, the navigation, the buttons — already sets its own
   and is unaffected. */
body.clab-home-style{ font-size: 17px; line-height: 1.62; }

/* And p/li explicitly as well, which is not redundant.
   Classic sets `.clab-article p, .clab-article li { font-size: 15px }` — the same
   specificity as `body.home`, and its stylesheet loads after this one, and its stylesheet loads after this one,
   so it wins. Setting the body alone fixed the unclassed divs and knocked every
   real paragraph back to 15px. This selector is (0,2,2) against Classic's (0,1,1)
   and settles it. */
/* The :not() chain is load-bearing, added 2026-08-17.
   `.paragraph` is a CONTENT class, but it is written on a few headings as well as
   on divs — 8 of them site-wide, including the <h1 class="paragraph"> on
   /economics-simulation/. As a bare class it is (0,3,1); the h1 rule 40 lines
   above is (0,2,1). So on any page carrying clab-home-style, a heading with this
   class silently lost its heading size and rendered at 17px body text.
   Measured on /economics-simulation/ the moment it joined the home-style list:
   h1 42px -> 17px, while every sibling page stayed at 42px.
   The comment above says headings "already set their own and are unaffected".
   That is true of element selectors and false of this one, which is exactly the
   trap. Excluding them here is cheaper than editing the class off 8 headings, and
   it cannot regress the next page that carries it. */
body.clab-home-style .clab-article p,
body.clab-home-style .clab-article li,
body.clab-home-style .clab-article .paragraph:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6){ font-size: 17px; line-height: 1.62; }

/* The navigation font is NOT set here. It is set once, higher up, for both test
   pages together, so /home-background-test/ and /home-background-test2/ carry an
   identical bar. An override at this point used to give this page system-ui while
   the other kept sans-serif, and the two menus quietly diverged. */

/* MaxButtons labels take the page's font.

   Same problem as page 10729: the plugin writes an inline <style> pinning each
   button to Arial through a four-class selector built from that button's own
   label. There is no single rule to outrank and no stable list to enumerate, so
   !important is the honest tool rather than a shortcut.

   Size and weight are matched to body copy too, not just the family. The family
   alone was not enough — the labels still read as a different typeface because
   they were 16px/700 against 17px/400 around them, and weight reads louder than
   family at a glance.

   Colour is deliberately left with the plugin. It is the one property that
   distinguishes a button from a sentence once the type matches, and it is
   configured per button in MaxButtons' own admin, which is where the site owner
   expects to change it.

   SUPERSEDED 2026-08-14 by the consolidation. The five role buttons store
   `font: inherit` and their own size, so the family and size now arrive from
   MaxButtons and the button takes the site body font because it was told to,
   not because a theme rule was winning a fight. The reasoning above is kept
   because it is still why 17px/500 was chosen — only the mechanism changed. */

/* --- Button style: soft fill replacing the outline ---------------------------
   What was there: white background, a 1px orange rule, bold orange label, 4px
   radius. That is a ghost button, and it dates the page in two ways. The style
   peaked around 2014, and more practically it gives a large target almost no
   visual weight — most of the button is page, so it reads as a framed caption
   rather than something to press.

   What replaces it is the soft-filled secondary button that Stripe, GitHub and
   Linear all converged on: a light tint of the accent as the surface, a deep
   version of the same hue as the label, and no rule at all. The whole shape
   carries colour, so the target is obvious, while the tint keeps it clearly
   subordinate to a solid primary button.

   Colour matters here more than style. The old label was #D67531 on white —   3.26:1, below the 4.5:1 minimum, which is why these read as washed out. The
   deep orange below is roughly 6.9:1 on the tint: unambiguously legible, and
   still recognisably the brand orange rather than a brown.

   Weight is 500, not 400. Body text is 400, and at 17px a button set identically
   to the sentence above it stops looking pressable — 500 is the smallest step
   that reads as a control without shouting.

   !important throughout, for the same reason as the font: MaxButtons writes a
   four-class inline rule per button, named after that button's own label. 
   REVISED: solid fill, not a tint. The soft version was too quiet — a pale
   surface with a 500-weight label disappeared into the card behind it, which is
   the opposite of what a buy button needs. Soft fills work as SECONDARY actions
   beside a solid primary; used for every button on the page they simply mute
   everything.

   The colour is the constraint, and it is not a free choice. White text needs
   4.5:1, and the site's own orange tokens cannot carry it:

       #E67E22  the CTA token         2.85:1  fails
       #D2701A  the CTA hover token   3.46:1  fails
       #C2620F  one step deeper       4.16:1  fails
       #B45309  deeper still          5.02:1  passes

   So the fill is #B45309 — the same hue, taken deep enough that white sits on it
   legibly. It is still unmistakably the brand orange; it is simply the version
   of it that can hold text. The alternative, keeping #E67E22 and accepting
   2.85:1, is what the buttons on production already do, and it is why the
   existing labels read as washed out.

   SWAPPED at the owner's request: #B45309 at rest, deepening to #96450A on
   hover. Both carry white text at over 5:1, so the label never weakens
   mid-transition, and the button is unmistakable before the pointer arrives —   which is the part that matters, since hover is feedback rather than the moment
   a control becomes visible.

   The lighter resting fill also sits closer to the site's --clab-cta orange, so
   the buttons read as the same family as the newsletter call to action rather
   than as a darker cousin of it.

   SUPERSEDED 2026-08-14 by the consolidation. Fill, radius, padding, label
   colour and weight all now live on the five role buttons in MaxButtons, which
   is what plan §4 asked for and what makes the plugin's admin screen tell the
   truth again. The colour ladder above is the reason #B45309 was chosen and is
   kept for that reason; it is now stored on the Primary button rather than
   forced from here.

   What remains below is the part MaxButtons genuinely cannot express: a raised
   surface and a press response. Neither is a colour, so neither belongs in a
   per-button colour picker, and both are shared by every role. The shadow still
   needs !important — the plugin writes its own zero box-shadow with no field to
   change it — but the transform does not, because it sets no transform at all. */
.maxbutton{
	/* A shadow at this strength reads as a raised surface without looking like
	   2011 skeuomorphism — it is what separates a button from a coloured label.
	   !important because the plugin writes its own zero box-shadow at (0,3,0)
	   and offers no field to change it. */
	box-shadow: 0 1px 2px rgba(16, 24, 40, .12), 0 1px 3px rgba(16, 24, 40, .08) !important;
	transition: background .18s ease, transform .18s ease, box-shadow .18s ease;
}
.maxbutton:hover,
.maxbutton:focus-visible{
	transform: translateY(-1px);
	/* The shadow grows with the lift, so the button reads as rising off the page
	   rather than merely changing colour in place. */
	box-shadow: 0 4px 8px rgba(16, 24, 40, .16), 0 2px 4px rgba(16, 24, 40, .10) !important;
}
/* An outline on the page's own ground. A raised shadow would contradict that —
   these are the roles meant to sit flat.

   35 (Download) and then 34 (Utility) joined 33 (Secondary) here on 2026-08-16,
   when the owner asked for every download button, and then every utility
   button, to take the Secondary look. The three rows are now identical in
   appearance but deliberately kept separate, and every shortcode still points
   at its own role — so any one of them can be given a distinct treatment again
   by editing one row rather than dozens of shortcodes across the site. If that
   happens, take that id back out of this rule.

   The solid roles are NOT here and must not be added: 31 Primary, 32 Promotion
   and 36 Bundle are filled buttons, and the raised shadow is what separates a
   filled button from a coloured label. */
.maxbutton-33,
.maxbutton-33:hover,
.maxbutton-34,
.maxbutton-34:hover,
.maxbutton-35,
.maxbutton-35:hover{ box-shadow: none !important; }

/* --- Buttons size to their own label ----------------------------------------
   Several labels were wrapping onto two lines inside a fixed-width button — "View
   Details and DLC Bundle Deal" in 300px, "Check out what's new in the latest
   Version 12.0 of Capitalism Lab" in about 700px.

   No new MaxButtons template is needed, and no per-button widths either. The
   widths are coming from the plugin's own settings; letting the button size to
   its content instead fixes every one of them at once and keeps working when a
   label is edited. A fixed width per button would have to be re-tuned every time
   someone changes the wording.

   DESKTOP ONLY. caplab-core already forces `white-space: normal` on these
   buttons at every width, because MaxButtons renders them at a fixed 477px and
   that overflowed a 390px phone sideways. Wrapping is the correct behaviour
   there; this restores single-line only where there is room for it.

   NO LONGER SCOPED TO body.home (2026-08-14). The old buttons were sized
   per-page because only the home page had been redesigned; the five roles are
   sized the same everywhere, so this belongs to the role. width/height/display
   have also gone — the plugin now emits `width: auto` and `height: auto` itself,
   so repeating them here would be the theme claiming credit for the plugin's
   work and would hide it if that ever changed. */
@media (min-width: 1024px) {
	.maxbutton { gap: .55rem; }
	.mb-text{
		/* Single line where there is room. Below 1024px the base rule's
		   `white-space: normal` takes over and the label wraps instead. */
		white-space: nowrap;
		max-width: none;
		display: inline;
	}
}

/* The promotion button.

   The fill lives in MaxButtons (button 32, "CapLab Promotion"), not here. That
   was the point of the 2026-08-14 consolidation: this block used to select
   .maxbutton-18, .maxbutton-19 and .maxbutton-26[href*="-dlc/"], because the
   promotion was being delivered by three ordinary buy buttons wearing promotion
   labels, and the DLC ones could only be told apart by the URL they pointed at
   since CSS cannot match on text. There is now one Promotion button and those
   three ids no longer exist. Change the colour in the plugin, not here.

   REPAINTED 2026-08-15 at the owner's request: #E67E22 -> #8C36E2, hover
   #CF6F1C -> #7B30C7 (the same ~12% darkening step the orange pair used, so the
   hover feedback is unchanged in strength rather than picked by eye).

   THE STANDING CONTRAST WARNING IS RESOLVED, as a side effect rather than by
   design. White on the old #E67E22 was 2.85:1 and failed the 4.5:1 minimum —   recorded here for months as the one buy button a reader with reduced contrast
   sensitivity would struggle with. White on #8C36E2 is 5.61:1 and on the hover
   #7B30C7 is 6.79:1. Both pass AA outright, so the suggested fallbacks (#C2620F
   at 4.16:1, #B45309) are no longer needed.

   The label's text-shadow was removed with it. It was never decoration — it
   existed only to lift white off a fill too light to carry it, and it was a
   BROWN shadow, rgba(80, 38, 4, .45), tuned to the orange. Against purple it
   would be both unnecessary and the wrong hue. If a future repaint goes back to
   a light fill, the shadow is the thing to bring back, and it belongs keyed to
   the numeric id class: the label-derived class is built from the button's own
   text, so renaming the button in the plugin would silently drop it. */

/* --- A glyph on the promotion button ----------------------------------------
   Only on the discount button. An icon on every button is noise; on one it marks
   that button out as different, which is the whole point of a promotion.

   An inline SVG rather than an emoji or a webfont icon. Emoji render as a
   different picture on every platform and would be the one coloured thing in a
   white label; an icon font would be a whole file for a single glyph. This is a
   data URI, so it costs no request — and `currentColor` cannot be used inside
   one, hence the hard-coded white, which matches the label.

   WHY A BOLT. The first version used a price tag. It is the most literal
   choice and the least effective: a tag is a mid-weight outline that reads as
   "this concerns pricing", which the words already say. A bolt is a solid
   angular silhouette with no interior detail, so it survives being 17px of white
   on orange, and it carries urgency rather than category — the thing a
   time-limited discount actually needs to communicate.

   *** THE PARAGRAPH ABOVE DESCRIBES AN ICON THAT WAS NEVER SHIPPED. ***
   Noticed 2026-08-15 by looking at a screenshot of the button. The `d` below and
   the one listed as "tag — the original" are byte-identical, and the live rule
   uses it. So the button has been rendering the TAG all along, while this
   comment argued at length for a bolt and explained why the tag was rejected.
   Whoever made the swap updated the prose and the label but pasted the old path.
   Left as-is because changing the icon is a design decision, not a correction —   but the comment must not go on claiming otherwise. For a real bolt:
       M13 2L3 14h7l-1 8 10-12h-7z

   TO SWAP IT, replace the `d` attribute below. All are 24x24 and drawn to
   the same weight, so nothing else needs changing:

     bolt (LABEL IS WRONG — this is the tag path, see above)
       M21.41 11.58l-9-9A2 2 0 0 0 11 2H4a2 2 0 0 0-2 2v7a2 2 0 0 0 .59 1.42l9 9a2 2 0 0 0 2.82 0l7-7a2 2 0 0 0 0-2.84zM6.5 8A1.5 1.5 0 1 1 8 6.5 1.5 1.5 0 0 1 6.5 8z

     sparkle — reads "special / premium" rather than urgent
       M12 2l2.4 7.2L22 12l-7.6 2.8L12 22l-2.4-7.2L2 12l7.6-2.8z

     gift — better if the offer is framed as a bonus than as a discount
       M20 12v10H4V12M2 7h20v5H2zM12 22V7M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7zM12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z

     tag — the original, quietest of the four
       M21.41 11.58l-9-9A2 2 0 0 0 11 2H4a2 2 0 0 0-2 2v7a2 2 0 0 0 .59 1.42l9 9a2 2 0 0 0 2.82 0l7-7a2 2 0 0 0 0-2.84zM6.5 8A1.5 1.5 0 1 1 8 6.5 1.5 1.5 0 0 1 6.5 8z

   Fire and 100-point emoji were considered and rejected: both read as discount-
   store urgency, which is the wrong register for a product at this price.

   RE-KEYED 2026-08-14. This selected [class*="maxbutton-buy-caplab"] — the class
   MaxButtons derives from a button's label, which was "Buy CapLab" at the time.
   The consolidation renamed the role to "CapLab Promotion", so that class no
   longer exists and the glyph would have vanished with no error anywhere. It is
   now keyed to the numeric id, which is exactly the failure mode the comment
   below the fill rule warns about, demonstrated on this very rule.

   Also no longer scoped to body.home: the Promotion button now appears on eight
   pages, not just the home page, so the glyph should follow the role rather than
   the location. */
.maxbutton-32 .mb-text::before{
	content: "";
	display: inline-block;
	/* Slightly larger than the tag was. A bolt is a narrow shape, so at 1.05em it
	   carried noticeably less visual weight than a square icon at the same size. */
	width: 1.05em;
	height: 1.05em;
	margin-right: .5em;
	vertical-align: -.14em;
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffffff'%3E%3Cpath d='M21.41 11.58l-9-9A2 2 0 0 0 11 2H4a2 2 0 0 0-2 2v7a2 2 0 0 0 .59 1.42l9 9a2 2 0 0 0 2.82 0l7-7a2 2 0 0 0 0-2.84zM6.5 8A1.5 1.5 0 1 1 8 6.5 1.5 1.5 0 0 1 6.5 8z'/%3E%3C/svg%3E") no-repeat center / contain;
}

/* --- Rating stars at 80% -----------------------------------------------------
   The artwork is 300x56 and was rendering at its natural size, which put it out
   of scale with the 17px text beneath it. 240px is 80% of that.

   width only, with height:auto inherited from the base image rule — setting both
   would fight the aspect ratio if the file is ever replaced at a different size. */
body.clab-home-style .clab-article img[src*="five-stars"]{
	width: 240px;
	height: auto;
}

body.clab-home-style{
	background-color: #2b304f;
	background-image: none;
}

/* The white content card is KEPT on this page.

   An earlier pass here removed it — transparent container, no radius, full-width
   ground — as the section 5.3 experiment in stripping the "sheet of paper on a
   desk" look. That has been reverted at the owner's request: this page is now a
   ground-colour comparison against /home-measure-test/, and the two only compare
   if everything except the colour is the same.

   So the only things scoped to this page are the ground colour, the system-font
   stack and the type scale. Layout is Classic's, untouched. */


/* ==========================================================================
   5. HEADER
   ========================================================================== */

/*
 * RESTORED 2026-08-14. This rule was deleted by accident during one of the
 * experiment clean-ups, and the loss was silent because caplab-classic sets the
 * header's background separately — so the bar still looked right while having no
 * position at all.
 *
 * The consequence was not visible either, but it was severe: .clab-mega is
 * `position: absolute; top: 100%`, and it relies on this rule for its containing
 * block. Without it the panel resolved against the viewport instead, so
 * `top: 100%` meant 100% of the WINDOW height — every mega panel opened at
 * y=900 on a 900px screen, just below the fold. Hovering appeared to do nothing.
 *
 * nav-acceptance.js did not catch it: its check is "panel opens below the whole
 * header", and 900 is indeed below 97. Below the header and below the fold are
 * not the same thing, and the test only asserted the first.
 */
/* UNPINNED 2026-08-15 at the owner's request. The header now scrolls away with
   the page instead of staying at the top.

   ┌─ TO PIN IT AGAIN ───────────────────────────────────────────────────────┐
   │ 1. change `position: relative` below to `position: sticky`               │
   │ 2. uncomment the two body.admin-bar rules that follow                    │
   │ Nothing else needs touching: z-index and the background are wanted       │
   │ either way. nav.js already handles both cases — see layoutDocsNav().     │
   └──────────────────────────────────────────────────────────────────────────┘

   IT MUST NEVER BE `static`. It was, from 2026-08-15 until this was found, and
   the whole mega menu was broken by it: .clab-mega is `position: absolute;
   top: 100%`, so with a static header it resolved against the viewport and every
   panel opened at y=900 on a 900px screen — present, correct, and just below the
   fold. Hovering looked like it did nothing at all.

   `relative` is the value that satisfies both requirements. It establishes the
   containing block the panel needs while having no visual effect of its own, so
   the header still scrolls away exactly as unpinning intended. The choice here is
   sticky-or-relative, never static.

   A full copy of this file and of nav.js as they stood while pinned is kept at
   themes/_backups/*.pinned-header-2026-08-15. That folder is deliberately
   outside the caplab-* directories the sync script copies, so it never reaches
   the running site. */
.clab-header {
	position: relative;
	z-index: 100;
	background: var(--clab-header-bg);
	color: var(--clab-header-ink);
}

/*
 * ONLY MEANINGFUL WHILE THE HEADER IS STICKY — commented out with it above.
 *
 * When signed in, the WordPress admin bar is fixed at the top on wide screens,
 * so a sticky header at top:0 slides underneath it. Below 783px the admin bar
 * is positioned absolutely and scrolls away, so no offset is wanted there.
 *
 * body.admin-bar .clab-header { top: 32px; }
 * @media screen and (max-width: 782px) {
 *     body.admin-bar .clab-header { top: 0; }
 * }
 */

.clab-header__bar {
	display: flex;
	align-items: center;
	gap: 1rem;
	min-height: var(--clab-header-h);
}

/* Give the navigation the full window rather than the reading container.
 *
 * Scoped to the navwrap as of 2026-08-14. It used to be `.clab-header
 * .clab-container`, which also matched .clab-header__bar — the bar carries both
 * classes. Once the header became a single flex row on every page, that pinned
 * the bar to 1180px instead of letting it shrink to the width of the icon, and
 * the navigation was left with 221px: one menu item per row, a 465px header,
 * and no error anywhere. The bar's own sizing is set where the header row is
 * defined; this rule is only about the navigation. */
.clab-header__navwrap .clab-container {
	width: min(100% - 2rem, var(--clab-container-wide));
}
@media (min-width: 1024px) {
	/* In the flex header the navwrap has already been given exactly the space
	   left over by the icon, so capping it again at the wide container width
	   throws some of that away and re-centres what is left. max-width and the
	   auto side margins both have to go — max-width alone leaves .clab-container
	   still centring inside whatever width it is handed, which is what opened an
	   88px gap between the icon and the first menu item. */
	.clab-header__navwrap > .clab-container {
		max-width: none;
		width: 100%;
		margin-left: 0;
		margin-right: 0;
		padding-left: .25rem;
	}
}

/*
 * Wrapper for the navigation row. On mobile it contains only the fixed-
 * position drawer, so it collapses to nothing in the flow.
 */
.clab-header__navwrap { line-height: 0; }
@media (min-width: 1024px) {
	.clab-header__navwrap {
		line-height: normal;
		border-top: 1px solid var(--clab-header-border);
	}
	/* The logo row can be shorter once it no longer holds the menu. */
	.clab-header__bar { min-height: 48px; }
}

.clab-brand {
	display: inline-flex;
	align-items: center;
	gap: .6rem;
	text-decoration: none;
	color: inherit;
	flex: 0 0 auto;
	padding-block: .5rem;
}
/*
 * The app icon is square and already carries its own rounded corners.
 *
 * 48px on phones and tablets: the icon carries real detail — the dollar sign,
 * the spheres — and below about 44px it reads as a blue smudge. It costs no
 * height there, because the bar has a 64px floor anyway. On desktop the logo
 * row is deliberately shorter, so the icon comes down with it.
 */
.clab-brand__mark { width: 48px; height: 48px; display: block; }
@media (min-width: 1024px) {
	/* 56px, not the 40px this used to carry. The icon now sits inline with the
	   menu rather than in a logo row of its own, so it has the header's full
	   height to work with, and at 40px in a dark bar the artwork reads as a blue
	   smudge. 56px is as far as it goes without forcing the header taller than
	   the two menu rows already make it; the file is 180px, so this is still
	   comfortably within its resolution at 3x.

	   Set here rather than in a second rule further up: an identical (0,1,0)
	   selector earlier in the file loses to this one on order, which is how the
	   promoted header rules quietly failed the first time. */
	.clab-brand__mark { width: 56px; height: 56px; }
}
.clab-brand__text {
	font-family: var(--clab-font-display);
	font-weight: 700;
	font-size: 1.12rem;
	letter-spacing: .01em;
	line-height: 1.05;
	white-space: nowrap;
	background: linear-gradient(180deg, #fff4c6 0%, #f0c33c 46%, #c8901a 100%);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}
.clab-brand__text small {
	display: block;
	/* The wordmark above sets line-height: 1.05 to keep itself tight, which
	   left the tagline sitting directly against its descenders. .55em of the
	   tagline's own size is ~5px — enough to read as two deliberate lines
	   without making the bar any taller. */
	margin-top: .55em;
	font-family: var(--clab-font-body);
	font-size: .62rem;
	line-height: 1.25;
	letter-spacing: .18em;
	text-transform: uppercase;
	color: var(--clab-header-dim);
	background: none;
	-webkit-text-fill-color: currentColor;
}

/* Hide the wordmark on the narrowest phones; the mark alone is enough.

   Clipped rather than `display: none`, for the reason set out beside the other
   brand rule above: the mark is the ONLY home link on the site, its icon is
   aria-hidden, and removing this text from the accessibility tree leaves the
   link with no accessible name. Two separate rules were hiding it — this one at
   ≤00px and the one in the header media query — so fixing only the first left
   phones still broken, which the measurement caught. Clipping takes no layout
   space, so the mark still stands alone visually. */
@media (max-width: 400px) {
	.clab-brand__text {
		border: 0;
		clip-path: inset(50%);
		height: 1px; width: 1px;
		margin: -1px; padding: 0;
		overflow: hidden;
		position: absolute;
		white-space: nowrap;
	}
	.clab-brand__text small { display: none; }
}

.clab-header__tools {
	margin-left: auto;
	display: flex;
	align-items: center;
	gap: .35rem;
	flex: 0 0 auto;
}

/* -------------------------------------------------------- burger + search */

.clab-burger,
.clab-searchbtn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px; height: 44px;   /* accessibility floor for tap targets */
	padding: 0;
	background: none;
	border: 1px solid transparent;
	border-radius: var(--clab-radius);
	color: var(--clab-header-ink);
	cursor: pointer;
}
.clab-burger:hover,
.clab-searchbtn:hover { background: rgba(255, 255, 255, .1); }

@media (min-width: 1024px) { .clab-burger { display: none; } }

.clab-burger__box { position: relative; width: 22px; height: 16px; }
.clab-burger__box span {
	position: absolute; left: 0;
	height: 2px; width: 100%;
	background: currentColor;
	border-radius: 2px;
	transition: transform .22s ease, opacity .18s ease, top .22s ease;
}
.clab-burger__box span:nth-child(1) { top: 0; }
.clab-burger__box span:nth-child(2) { top: 7px; }
.clab-burger__box span:nth-child(3) { top: 14px; }

.clab-burger[aria-expanded="true"] .clab-burger__box span:nth-child(1) { top: 7px; transform: rotate(45deg); }
.clab-burger[aria-expanded="true"] .clab-burger__box span:nth-child(2) { opacity: 0; }
.clab-burger[aria-expanded="true"] .clab-burger__box span:nth-child(3) { top: 7px; transform: rotate(-45deg); }

/* An accented phrase inside a heading.

   #C84D16 on the white content card is about 4.7:1 — past the 4.5:1 body-text
   minimum, so it holds up even though headings would only need 3:1. That matters
   because this is the one place the site colours part of a sentence, and a phrase
   people are meant to read is not the place to spend the contrast budget.

   A class, not an inline style: the value lives here with the rest of the palette
   and follows whichever direction wins D2, rather than being a hex code buried
   in a page nobody thinks to search. */
.clab-article .clab-accent-text {
	color: #c84d16;
}

/* --- A topic glyph in front of a heading: WITHDRAWN 2026-08-17 ---------------
 *
 * There was a rule here for `.clab-article h2 > i[aria-hidden="true"]` and its
 * h3/h4 siblings — font-style: normal, .4em right margin, .92em — introduced by
 * the 2026-08-15 structural pass, which put an emoji inside
 * <i aria-hidden="true"> at the front of 512 headings across 166 pages.
 *
 * The owner withdrew it: they do not look good in front of a heading. All 512
 * were removed from the page content, so the rule matched nothing and has gone
 * with them rather than being left as dead CSS.
 *
 * NOT the same thing as the card-index glyphs, which STAY. Those are 142
 * <b><i aria-hidden="true">🖥️</i>New Display Modes</b> labels inside card grids
 * — a different element doing a different job, and the convention the heading
 * treatment was copied from in the first place. They carry no rule here and
 * never did.
 *
 * If a glyph is ever wanted on a heading again, restore this block rather than
 * writing an inline style: the reason it was em-based was that a fixed 6px reads
 * differently against a 42px h1 and an 18px h4.
 */

/* --- A comfortable measure on a long-form page -------------------------------
 *
 * Opt-in per page through caplab_narrow_measure_slugs (functions.php).
 *
 * /tycoon-games/ measured 154 characters per line at 1440 — 1132px of text at
 * 16px — for 1,900 words of continuous prose. Past roughly 100 characters the
 * eye starts losing the beginning of the next line on the way back.
 *
 * The width is in px and was tuned by measuring, not by arithmetic on an average
 * character: `ch` is the width of a zero, which in Inter is wider than the mean
 * glyph, so 100ch lands nearer 119 characters than 100.
 *
 * Applied to the article, not to individual paragraphs, so the cards, images and
 * headings all narrow together and the page keeps a single left edge. The cards
 * take 28px of padding each side, so text inside one sits ~56px narrower than
 * the intro paragraph above them.
 *
 * Tuned twice. At 900px it measured ~98 characters inside a card and ~105 above
 * them; the owner asked for nearer 120, so it is 1080px. Measured at 1440 with
 * clab-home-style's 17px prose (8.59px per character):
 *
 *                            900px        1080px
 *     inside a card       ~98 chars     ~119 chars   (20 paragraphs)
 *     above the cards    ~105 chars     ~126 chars   (2 paragraphs)
 *
 * The 20 are the page, so the card figure is the one aimed at. Uncapped, the
 * article is 1132px and the same text runs ~125 / ~132.
 */
body.clab-narrow-measure .clab-article {
	max-width: 1080px;
	margin-inline: auto;
}

/* --- A heading that carries the home page's treatment on any page ------------
 *
 * The home page styles its headings through `body.home` — system-ui, 28px, 700,
 * #343C61 — while every other page inherits Classic's Georgia 30px/500 #843C0B.
 * That is the split D2 settles by propagating the home treatment site-wide, and
 * until that happens a page cannot match it without a scope of its own.
 *
 * This class is that scope. It was added for the "100% Risk Free Purchase"
 * heading on /buy-game/, which sits in the same green guarantee card as the one
 * on the home page and looked like a different site beside it.
 *
 * It is a stopgap, deliberately narrow, and should be DELETED when the
 * typography propagation lands — at that point every heading gets these values
 * and the class becomes a no-op. It is not a place to add more page-specific
 * type.
 */
.clab-article h1.clab-home-heading,
.clab-article h2.clab-home-heading,
.clab-article h3.clab-home-heading {
	font-family: var(--clab-font-body);
	font-size: 28px;
	line-height: 1.22;
	font-weight: 700;
	letter-spacing: -.015em;
	color: #343c61;
}

/* REMOVED 2026-08-15. The home page carried its own #C84D16 variant of the
   footer subscribe button here — larger, darker, with a different hover — which
   meant the site had two footers depending on which page you were on.

   The owner asked for one footer everywhere, so these values now live in the
   single .clab-footer .clab-subscribe rule further down this file, and this
   override is gone rather than merely neutralised. Nothing should scope the
   footer to a page again: if the button needs to change, change it there. */

/* --------------------------------------------------------------- link cards

   For hub pages: a section index whose only job is to help the reader choose
   where to go next. /scripts/ is the first, and the pattern suits every
   equivalent page — MOD, Resources, each DLC.

   Why a theme component rather than markup written into the page: the layout
   then belongs to the theme and restyles for free when D2 lands. A grid built
   by hand in the editor bakes today's design into 361 pieces of content, which
   is the same trap as the flattened price cards on the home page.

   The markup a page has to write is deliberately plain, so it stays readable in
   the Classic editor's Text tab and survives being edited by hand:

       <ul class="clab-cards">
         <li><a href="…><b>Title</b><span>One line about it.</span></a></li>
       </ul>

   auto-fill with a 240px floor rather than a fixed column count: the article
   column is 852px with the sidebar and wider without it, so a fixed count would
   be wrong on one of them. */
.clab-article .clab-cards {
	list-style: none;
	margin: 1.25rem 0 2rem;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
	gap: .85rem;
}
.clab-article .clab-cards li { margin: 0; }

.clab-article .clab-cards a {
	display: flex;
	flex-direction: column;
	height: 100%;
	padding: .85rem 1rem;
	background: var(--clab-card-bg);
	border: 1px solid var(--clab-border);
	border-radius: var(--clab-radius);
	text-decoration: none;
	color: var(--clab-text);
	transition: border-color .15s ease, background .15s ease, transform .15s ease;
}
.clab-article .clab-cards a:hover,
.clab-article .clab-cards a:focus-visible {
	border-color: var(--clab-link);
	/* SWAPPED 2026-08-14: the card now rests on --clab-card-bg (white in Classic)
	   and settles onto --clab-card-bg-hover (the surface tone) under the pointer,
	   where it used to do the opposite.

	   Neither end is a literal, and specifically neither is var(--clab-bg). That
	   token is the PAGE background, and Classic sets it to #202020 — an earlier
	   version used it here and the card turned near-black on hover with dark text
	   still on it. The card sits on the white content panel, not on the page
	   ground. Third time this token has caught someone; the footer band was the
	   first. */
	background: var(--clab-card-bg-hover);
	transform: translateY(-1px);
	box-shadow: 0 2px 6px rgba(16, 24, 40, .07);
	/* The theme underlines links on hover. Correct for a link in a sentence,
	   wrong for a card — the whole tile is the target, and underlining its title
	   and description makes it read as broken text rather than a surface. */
	text-decoration: none;
}
.clab-article .clab-cards a:hover b,
.clab-article .clab-cards a:hover span,
.clab-article .clab-cards a:focus-visible b,
.clab-article .clab-cards a:focus-visible span {
	text-decoration: none;
}

/* The title is the only coloured part. Colouring the description as well would
   make the whole card read as one long link. */
.clab-article .clab-cards b {
	font-weight: 600;
	color: var(--clab-link);
	line-height: 1.3;
}

/* The topic glyph.
   <i aria-hidden="true"> rather than a ::before, because the character belongs
   to the item rather than to the component — a card about cities and a card
   about goals want different marks, and CSS cannot know which is which without
   a class per card.

   aria-hidden matters more than it looks: without it a screen reader announces
   "globe showing Europe-Africa" before every title, which turns a scannable
   index into a recital. The glyph is decoration, and it says so.

   font-style: normal because <i> is italic by default and emoji have no italic
   form — some platforms fake one by shearing the glyph. Fixed width keeps the
   titles aligned when the marks differ in width, which they do. */
.clab-article .clab-cards i {
	font-style: normal;
	display: inline-block;
	width: 1.35em;
	margin-right: .15em;
	line-height: 1;
	/* Emoji render at their own optical size and tend to sit slightly large
	   beside text set at the same nominal size. */
	font-size: .95em;
}
.clab-article .clab-cards span {
	display: block;
	margin-top: .3rem;
	font-size: .9em;
	line-height: 1.45;
	color: var(--clab-text-dim);
}

/* A group label above a run of cards. Small and quiet — it is a signpost, not a
   section heading competing with the h1. */
.clab-article .clab-cards-group {
	margin: 1.9rem 0 0;
	font-size: .78rem;
	font-weight: 700;
	letter-spacing: .07em;
	text-transform: uppercase;
	color: var(--clab-text-dim);
}
.clab-article .clab-cards-group + .clab-cards { margin-top: .7rem; }

/* --------------------------------------------------------- social links row
   A row of chips linking to the places the community actually gathers, using
   the real brand marks rather than an approximation in emoji.
   Markup:
       <ul class="clab-social">
         <li><a href="…"><img src="…" alt=""><span>Label</span></a></li>
       </ul>

   The icons live at /newsletter/social-icons/*.png — site-root assets that
   predate the WordPress install, 72px square, so they are sized down here and
   stay crisp on a retina screen.

   The image carries alt="" ON PURPOSE. The visible label beside it already
   names the destination, and repeating it in alt would make a screen reader
   announce the same words twice for one link.

   SPECIFICITY. The article's own image rule is
     .clab-article img:not(.emoji):not(.wp-smiley):not(:only-child)
   at (0,4,1), and it sets display:block with a 1em bottom margin — which would
   drop each icon onto its own line and space it away from its label. The rule
   below repeats the same :not() chain to reach (0,5,1) and win cleanly, rather
   than reaching for !important. Same lesson as the card grids: when a component
   image needs different treatment, out-weigh the article rule, do not disable
   it. */
.clab-article .clab-social {
	list-style: none;
	margin: .7rem 0 1.15em;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: .6rem;
}
.clab-article .clab-social li { margin: 0; }
.clab-article .clab-social a {
	display: inline-flex;
	align-items: center;
	gap: .55rem;
	padding: .5rem .9rem;
	border: 1px solid var(--clab-border);
	border-radius: 8px;
	background: var(--clab-surface);
	color: var(--clab-text);
	text-decoration: none;
	font-weight: 600;
	font-size: .95rem;
	line-height: 1.2;
}
.clab-article .clab-social a:hover,
.clab-article .clab-social a:focus-visible {
	border-color: var(--clab-accent);
	color: var(--clab-accent);
}
.clab-article .clab-social img:not(.emoji):not(.wp-smiley):not(:only-child) {
	display: block;
	width: 22px;
	height: 22px;
	margin: 0;
	flex: 0 0 auto;
}

/* ==========================================================================
   6. NAVIGATION
   One DOM, presented two ways.
   ========================================================================== */

.clab-nav__empty { color: var(--clab-header-dim); font-size: .9rem; }

.clab-menu, .clab-mega__grid, .clab-mega__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.clab-nav__link,
.clab-mega__heading {
	color: inherit;
	text-decoration: none;
	display: block;
	/* No font-family here on purpose. The navigation inherits --clab-font-body,
	   which is what Rundown does and what Classic must keep doing to remain a
	   control. Pointing it at --clab-font-display would have quietly turned the
	   live menu into Georgia. The test page sets its own nav font by page ID. */
}

/* `color: inherit` above is (0,1,0) and the global `a:hover` is (0,1,1), so every
   navigation label was repainted --clab-link-hover the moment a pointer touched
   it: a page-content link colour applied to a header surface. Measured in
   Classic that is #14406f on the drawer's flattened rgb(44,44,44) — 1.33:1,
   which is not a dim label but an invisible one, on both the drawer and the mega
   panel.

   Restating inherit at (0,2,1) is enough to outrank the global rule while still
   losing to the deliberate accent-on-hover for desktop depth-0 items further
   down (0,3,0), which is the one place the label is meant to change colour. */
.clab-nav a:hover,
.clab-nav a:focus-visible { color: inherit; }

/* ------------------------------------------------- mobile drawer (< 1024) */

@media (max-width: 1023.98px) {
	/* An explicit line-height, because the drawer inherits line-height: 0 from
	   .clab-header__navwrap — a trick that strips inline-block whitespace on the
	   desktop bar, overridden there by the depth-0 rule but not here. Without it
	   every label sat 5px from the top of its 44px row with 22px of space
	   underneath, out of line with the chevron beside it.

	   .clab-mega__heading was missed the first time, and that is what a depth-1
	   parent renders as — "Capitalism Lab shortcut keys" and the other eight
	   items that have children of their own. Their rows measured the correct
	   49.6px and their chevrons lined up perfectly, so a geometric check found
	   nothing; the LABEL inside sat wrong, because a zero line-height gives the
	   text no line box to be centred within. Worth remembering: measuring the
	   box does not measure the text in it. */
	.clab-nav .clab-nav__link,
	.clab-nav .clab-mega__heading { line-height: 1.4; }

	.clab-nav {
		/* One number for a row and for the chevron beside it. The link's box is
		   .85rem of padding above and below a 1rem/1.4 line — 1.7rem + 1.4rem =
		   3.1rem — with the 44px tap target as the floor.

		   The chevron used to be `height: 100%; max-height: 52px`. But 100%
		   resolves against .clab-nav__item, and an open item is as tall as all
		   its expanded children, so on any open section the clamp set the height
		   instead of the row: 52px of chevron against a 49.6px row, overhanging
		   by 2.4px. Closed rows looked correct, which is why it survived. */
		--clab-drawer-row: max(44px, 3.1rem);

		position: fixed;
		/* MUST out-rank the dimming scrim, which is z-index: 99.
		   Without this the drawer stacked at auto (0) and the scrim painted over
		   it, swallowing every tap: the panel was visible and completely
		   inert. It was not obvious because .clab-header is sticky with
		   z-index: 100 — but only from 1024px up. Below that the header is
		   static, so the drawer inherited no stacking context to lift it.

		   This is the defect the rebuild exists to fix, in a new form: 168 of
		   185 links were unreachable on touch before, and an unclickable drawer
		   put every one of them back out of reach. */
		z-index: 100;
		inset: var(--clab-header-h) 0 0 auto;
		width: min(88vw, 400px);
		background: var(--clab-drawer-bg);
		color: var(--clab-header-ink);
		transform: translateX(101%);
		transition: transform .26s ease;
		overflow-y: auto;
		overscroll-behavior: contain;
		box-shadow: var(--clab-shadow);
		padding: .5rem 0 4rem;
		visibility: hidden;
	}
	.clab-nav.is-open { transform: translateX(0); visibility: visible; }

	.clab-menu > li { border-bottom: 1px solid var(--clab-header-border); }

	.clab-nav__item { position: relative; }

	.clab-nav__item > .clab-nav__link,
	.clab-nav__item > .clab-mega__heading {
		padding: .85rem 3.25rem .85rem 1.25rem;
		min-height: var(--clab-drawer-row);
		font-size: 1rem;
	}

	.clab-nav__item--depth-1 > a { padding-left: 2.1rem; font-size: .96rem; }
	.clab-nav__item--depth-2 > a { padding-left: 3rem; font-size: .92rem; opacity: .92; }

	/* The disclosure is a separate target from the link, so a parent item is
	   both navigable and expandable — the failure mode of the old menu. */
	.clab-nav__toggle {
		position: absolute;
		top: 0; right: 0;
		width: 52px;
		/* Anchored to the top and sized to exactly one row, so it stays flush
		   whether the section is open or closed. A label long enough to wrap
		   now leaves the chevron aligned with its first line rather than
		   stretched down the whole item — the readable behaviour of the two. */
		height: var(--clab-drawer-row);
		display: flex;
		align-items: center;
		justify-content: center;
		background: none;
		border: 0;
		border-left: 1px solid var(--clab-header-border);
		color: inherit;
		cursor: pointer;
	}
	.clab-nav__toggle .clab-chevron { transition: transform .2s ease; }
	.clab-nav__toggle[aria-expanded="true"] .clab-chevron { transform: rotate(180deg); }

	.clab-mega,
	.clab-mega__list { display: none; }
	.clab-has-children.is-open > .clab-mega,
	.clab-has-children.is-open > .clab-mega__list { display: block; }

	.clab-mega__inner { padding: 0; }
	.clab-mega { background: rgba(255, 255, 255, .04); }
	.clab-mega__col { border-top: 1px solid var(--clab-header-border); }

	.clab-nav a:hover { background: rgba(255, 255, 255, .07); }
	.clab-nav [aria-current="page"] {
		background: rgba(255, 255, 255, .1);
		box-shadow: inset 3px 0 0 var(--clab-accent);
	}
}

/* Dim the page behind the open drawer. */
.clab-drawer-open body::after,
html.clab-drawer-open body::after {
	content: "";
	position: fixed;
	inset: 0;
	background: rgba(0, 0, 0, .5);
	z-index: 99;
}

/* -------------------------------------------------- mega menu (>= 1024px) */

@media (min-width: 1024px) {
	/*
	 * Every top-level section stays visible. Thirteen do not fit one row on
	 * most desktops, so the bar wraps to as many rows as it needs rather than
	 * hiding sections behind an overflow menu.
	 *
	 * Rows are sized by padding, not by line-height: at the old
	 * line-height: 64px a second row made the header 193px tall.
	 */
	.clab-nav {
		margin-left: -.55rem;   /* pull the first label flush with the logo */
		min-width: 0;
	}

	.clab-menu {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		row-gap: 1px;
		padding-block: .15rem;
	}

	/*
	 * static, so the mega panel is positioned against the header rather than
	 * against its own row. Anchored to the row, a panel would drop on top of
	 * the rows beneath it.
	 */
	.clab-nav__item--depth-0 {
		position: static;
		display: flex;
		align-items: center;
		flex: 0 0 auto;
	}

	/* Production's own values, measured off www.capitalismlab.com rather than
	   reconstructed:

	     font-size   16px          the rebuild had .875rem (14px)
	     font-weight 700           the rebuild had 500
	     padding     10px 17.008px the rebuild had .38rem .1rem .38rem .48rem
	     li margin   0, ul gap 0

	   The separation between labels is not a gap. Rundown sets none: every item's
	   air comes from ~17px of padding on the link itself, so adjacent items touch
	   and the ~34px between words is padding meeting padding. A flex gap would
	   look the same at rest and behave differently on hover, because the target
	   would stop short of the space around it.

	   This makes the bar wider — production wraps to two rows too, so that is
	   faithful rather than a regression. Getting it onto one row is a structural
	   problem, not a spacing one: see menu-restructure-proposal.md. */
	.clab-nav__item--depth-0 > .clab-nav__link {
		/* 6px block, not the 10px production uses. The header carries a 56px
		   mark, thirteen items and a filled button, so the vertical budget is
		   tighter here; see the note beside the menu gap rules further up for the
		   full reasoning. Inline padding stays at 17px, so the horizontal rhythm
		   is untouched. Set here rather than in a second rule earlier in the
		   file, which would lose to this one on order at equal specificity. */
		padding: 6px 17px;
		line-height: 1.35;
		font-size: 16px;
		font-weight: 700;
		letter-spacing: normal;
		white-space: nowrap;
	}
	/* Both sides equal. The chevron toggles that used to claim the right-hand
	   padding are hidden (see below), so reserving space for them would leave
	   every parent item visibly lopsided against its neighbours. */
	.clab-nav__item--depth-0.clab-has-children > .clab-nav__link,
	.clab-nav__item--depth-0:not(.clab-has-children) > .clab-nav__link { padding-right: 17px; }

	.clab-nav__item--depth-0 > .clab-nav__toggle {
		background: none;
		border: 0;
		color: inherit;
		padding: .38rem .42rem .38rem .16rem;
		line-height: 1.35;
		display: inline-flex;
		align-items: center;
		cursor: pointer;
	}
	.clab-nav__item--depth-0 > .clab-nav__toggle .clab-chevron { transition: transform .2s ease; }
	.clab-nav__item--depth-0.is-open > .clab-nav__toggle .clab-chevron { transform: rotate(180deg); }

	/* The chevrons are hidden on the desktop bar to reclaim width: 11 toggles at
	   25.3px was 278px of the 1,626px the thirteen items occupy.

	   Hidden, NOT removed. The chevron lives inside a <button> that is how a
	   keyboard or touch user opens each submenu — a pointer gets the same thing
	   from hover, but nothing else does. Deleting the button would recreate the
	   defect this whole rebuild exists to fix, where 168 of 185 links were
	   unreachable without a mouse.

	   So it is clipped rather than display:none — still in the accessibility tree,
	   still focusable, still announced — and it returns to full size the moment it
	   receives keyboard focus, because a focusable control the user cannot see is
	   a WCAG 2.4.7 failure. The small shift when that happens is the correct
	   trade: it only occurs for the person who needs the affordance.

	   NOTE: this does not by itself unwrap the two-row bar. 1,626 - 278 = 1,348px
	   against 1,189px available. Consolidating the three DLC entries (D5) is the
	   other half. */
	.clab-nav__item--depth-0 > .clab-nav__toggle {
		position: absolute;
		width: 1px;
		height: 1px;
		padding: 0;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}
	.clab-nav__item--depth-0 > .clab-nav__toggle:focus-visible {
		position: static;
		width: auto;
		height: auto;
		padding: .38rem .42rem .38rem .16rem;
		overflow: visible;
		clip-path: none;
	}
	/* Padding is set once above, symmetrically, for parents and leaves alike —
	   nothing extra is needed here now that the toggle contributes no width. */

	.clab-nav__item--depth-0:hover > .clab-nav__link,
	.clab-nav__item--depth-0.is-open > .clab-nav__link { color: var(--clab-accent); }

	.clab-nav__item--depth-0.current-menu-item > .clab-nav__link,
	.clab-nav__item--depth-0.current-menu-ancestor > .clab-nav__link {
		box-shadow: inset 0 -3px 0 var(--clab-accent);
	}

	/*
	 * The panel. Positioned against .clab-header (sticky, so it is the
	 * containing block) and dropped below the whole bar, so it never covers
	 * a second or third row of menu items. nav.js sets `left` to line the
	 * panel up with its trigger and clamps it to the viewport.
	 */
	.clab-mega {
		display: none;
		position: absolute;
		top: 100%;
		left: 0;
		min-width: 300px;
		background: var(--clab-mega-bg);
		color: var(--clab-mega-ink);
		border: 1px solid var(--clab-header-border);
		border-top: 3px solid var(--clab-accent);
		border-radius: 0 0 var(--clab-radius-lg) var(--clab-radius-lg);
		box-shadow: var(--clab-shadow);
	}
	.clab-nav__item--depth-0.is-open > .clab-mega { display: block; }

	/*
	 * The panel is shrink-to-fit, so an auto-fill grid alone always collapses
	 * to one column. Widen the panel in steps according to how many children
	 * the section has, and the grid then flows into 2-4 columns.
	 */
	.clab-mega__inner {
		padding: 1.35rem 1.6rem;
		max-height: min(72vh, 620px);
		overflow-y: auto;
		width: min(90vw, 300px);
	}
	.clab-mega:has(> .clab-mega__inner > .clab-mega__grid > li:nth-child(5)) > .clab-mega__inner { width: min(90vw, 560px); }
	.clab-mega:has(> .clab-mega__inner > .clab-mega__grid > li:nth-child(9)) > .clab-mega__inner { width: min(90vw, 820px); }
	.clab-mega:has(> .clab-mega__inner > .clab-mega__grid > li:nth-child(15)) > .clab-mega__inner { width: min(92vw, 1060px); }

	/*
	 * Columns, not a grid.
	 *
	 * A grid aligns its rows, so every row is as tall as the tallest section in
	 * it. In "New Content" that put "Scenario Games" (one line) in the same row
	 * as "User-defined Scripts" (13 links) and left a 470px hole underneath it,
	 * while pushing the panel past its own height limit so it scrolled.
	 *
	 * Multi-column flow packs each section directly under the one above it in
	 * the same column instead. Nothing is aligned, so nothing has to wait for
	 * the tallest neighbour, and the browser balances the column heights.
	 */
	.clab-mega__grid {
		columns: 230px;
		column-gap: 2rem;
	}

	/* A panel with more than a handful of columns needs room. */
	.clab-nav__item--depth-0 > .clab-mega { max-width: min(94vw, 1100px); }

	/* Edge clamping is done in nav.js: a positional guess here (right-aligning
	   the last few items) pushed wide panels off the LEFT edge instead. */

	.clab-mega__col { break-inside: avoid; margin-bottom: .9rem; }

	.clab-mega__heading,
	.clab-mega__col > .clab-nav__link {
		font-weight: 600;
		font-size: .9rem;
		color: var(--clab-accent);
		padding: .3rem 0;
		letter-spacing: .01em;
	}
	.clab-mega__heading:hover { text-decoration: underline; }

	/* Third level */
	.clab-mega__list { margin-top: .1rem; }
	.clab-mega__list .clab-nav__link {
		font-size: .875rem;
		padding: .3rem 0 .3rem .75rem;
		color: var(--clab-mega-ink);
		border-left: 2px solid var(--clab-header-border);
		opacity: .88;
	}
	.clab-mega__list .clab-nav__link:hover {
		opacity: 1;
		color: #fff;
		border-left-color: var(--clab-accent);
	}
	.clab-mega__list [aria-current="page"] {
		color: var(--clab-accent);
		border-left-color: var(--clab-accent);
		opacity: 1;
	}

	/* Nested toggles are redundant inside an always-expanded panel. */
	.clab-nav__item--depth-1 > .clab-nav__toggle,
	.clab-nav__item--depth-2 > .clab-nav__toggle { display: none; }
	.clab-nav__item--depth-1 > .clab-mega__list,
	.clab-nav__item--depth-2 > .clab-mega__list { display: block; }

}

/* ==========================================================================
   7. SEARCH
   ========================================================================== */

.clab-search { position: relative; }
.clab-search__form { display: flex; gap: .4rem; }

/* The .clab-nav__search selectors that used to be listed here alongside these
   were dropped on 2026-08-14 with the drawer field itself. They are recorded in
   header.php next to the removed markup, because the lesson survives the
   element: scoping these rules to .clab-search alone once left the drawer field
   with no theme styling whatsoever — browser-default 1px/2px padding, square
   corners, a 2px inset border and 13.33px text — and the colour overrides
   further down hid it, by making the field look deliberate while none of its box
   properties were set. If the drawer field ever returns, its wrapper has to be
   named here too. */
.clab-search input[type="search"],
.clab-search input[type="text"] {
	font: inherit;
	font-size: .95rem;
	padding: .55rem .8rem;
	min-height: 44px;
	border: 1px solid var(--clab-border);
	border-radius: var(--clab-radius);
	background: var(--clab-bg);
	color: var(--clab-text);
	width: 100%;
}

/* Hidden at every width, as of 2026-08-14.
 *
 * It used to reappear at 1180px, which is the rule that was quietly defeating
 * the site-wide header: the bar sizes to its contents, so a 190px search field
 * with `margin-left: auto` made the bar 1180px wide and left the navigation
 * 221px — enough for exactly one menu item per row. The header measured 465px
 * tall with thirteen stacked rows, and nothing errored.
 *
 * Removing the `display: block` is the fix rather than adding another rule to
 * hide it: a second hide rule would have to out-rank this block, and the reason
 * the field should not show is that there is no room for it, not that some other
 * rule wants it gone.
 *
 * The field styling below is deliberately kept. D5's menu restructure frees the
 * width to bring search back, and at that point this is one declaration away
 * from working again. */
.clab-header .clab-search { display: none; }
@media (min-width: 1180px) {
	.clab-header .clab-search { width: 190px; }
	.clab-header .clab-search input[type="search"] {
		min-height: 38px;
		padding: .35rem .7rem;
		background: rgba(255, 255, 255, .08);
		border-color: var(--clab-header-border);
		color: var(--clab-header-ink);
		font-size: .88rem;
	}
	.clab-header .clab-search input::placeholder { color: var(--clab-header-dim); }
}

/* The drawer's search field and its rules were removed on 2026-08-14 at the
   owner's request. It sat at the top of the drawer, took its colours from the
   header rather than the page — otherwise a light docs palette would have put a
   white input on a dark drawer — and was the last search entry point in the
   interface after the header's own field was hidden at every width above.

   searchform.php, search.php and /?s= are all untouched and still work. */

/* ==========================================================================
   8. BREADCRUMBS
   ========================================================================== */

.clab-crumbs {
	background: var(--clab-surface);
	border-bottom: 1px solid var(--clab-border);
	font-size: .875rem;
}
.clab-crumbs__inner {
	width: min(100% - 2.5rem, var(--clab-container));
	margin-inline: auto;
	padding: .7rem 0;
	color: var(--clab-text-dim);
	overflow-x: auto;
	white-space: nowrap;
	scrollbar-width: thin;
}
.clab-crumbs a { color: var(--clab-text-dim); text-decoration: none; }
.clab-crumbs a:hover { color: var(--clab-link); text-decoration: underline; }
.clab-crumbs__sep { margin: 0 .5rem; opacity: .5; }
.clab-crumbs [aria-current="page"] { color: var(--clab-text); font-weight: 500; }

/* ==========================================================================
   9. DOCUMENTATION SIDEBAR
   ========================================================================== */

.clab-docsnav { font-size: .925rem; }

@media (min-width: 1024px) {
	.clab-docsnav {
		padding-right: .5rem;
		border-right: 1px solid var(--clab-border);
	}

	/*
	 * Pinned only when it fits.
	 *
	 * It used to be pinned always, with a max-height and a scrollbar of its
	 * own. The space that max-height reserved for the header was the
	 * --clab-header-h guess rather than the header's real height — which
	 * changes when the menu bar wraps to a second row, and again by 32px when
	 * the admin bar is showing — so a tree that had room to be shown whole
	 * still got a scrollbar. nav.js measures the header for real and adds
	 * .is-pinned only when the whole tree fits beneath it; when it does not,
	 * the tree keeps its natural height and scrolls with the article, which is
	 * a better way to read a long list than a second scrollbar inside the page.
	 */
	.clab-docsnav.is-pinned { position: sticky; }

	/* Sticky needs room to travel, and .clab-layout start-aligns its items,
	   which would otherwise make this column exactly as tall as the tree. */
	body.clab-has-sidebar .clab-sidebar { align-self: stretch; }
}

@media (max-width: 1023.98px) {
	/* The drawer already carries the full tree; repeating it inline would
	   push the article far down the page. */
	.clab-docsnav { display: none; }
}

.clab-docsnav__title {
	font-family: var(--clab-font-body);
	font-size: .78rem;
	font-weight: 700;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--clab-text-dim);
	margin: 0 0 .75rem;
}
.clab-docsnav__title a { color: inherit; text-decoration: none; }
.clab-docsnav__title a:hover { color: var(--clab-link); }

.clab-docsnav__list { list-style: none; margin: 0; padding: 0; }
.clab-docsnav__list--1 { margin-left: .75rem; padding-left: .5rem; border-left: 1px solid var(--clab-border); }
.clab-docsnav__list--2 { margin-left: .6rem; padding-left: .5rem; border-left: 1px solid var(--clab-border); }

.clab-docsnav__item > a {
	display: block;
	padding: .34rem .5rem;
	border-radius: var(--clab-radius);
	color: var(--clab-text-dim);
	text-decoration: none;
	line-height: 1.4;
}
.clab-docsnav__item > a:hover { background: var(--clab-surface); color: var(--clab-text); }
.clab-docsnav__item.is-active > a { color: var(--clab-text); font-weight: 500; }
.clab-docsnav__item.is-current > a {
	background: var(--clab-surface-2);
	color: var(--clab-heading);
	font-weight: 600;
	box-shadow: inset 2px 0 0 var(--clab-accent);
}

/* ==========================================================================
   10. CONTENT
   Styles arbitrary classic-editor HTML written over nine years, including
   classes inherited from an old Weebly migration.
   ========================================================================== */

.clab-article :is(h2, h3, h4):first-child { margin-top: 0; }

/*
 * Heading normalisation. inc/headings.php relabels heading *levels* so that
 * every page has exactly one <h1> — 187 pages had none and 14 had several. It
 * marks what it rewrote with .clab-h1--promoted / .clab-h2--demoted.
 *
 * Those classes are deliberately left UNSTYLED here, and that is the whole
 * point of this comment, because the obvious thing to do with them is wrong.
 *
 * The first attempt pinned each rewritten heading to the metrics of the level
 * it used to be, so that relabelling could not resize anything. That broke the
 * active theme. caplab-classic reproduces Rundown, and Rundown styled
 * `.clab-article h1` and `.clab-article h2` identically — both 30px/39px. So in
 * Classic a relabel already changes nothing, while the pinning rules, at
 * specificity (0,2,1) against Classic's (0,1,1), beat the child theme and
 * forced caplab-core's own scale back in: demoted headings on the home page
 * jumped from 30px to 46.4px. The fix made the regression.
 *
 * Leaving the classes unstyled means each theme's own h1/h2 rules apply, which
 * is right in every case: Classic renders them identically to before because it
 * sizes h1 and h2 the same, and the three design directions render a promoted
 * page title as the <h1> it now is, which in a new design is what you want.
 *
 * If a future theme does need a rewritten heading to look like its old level,
 * style it in THAT theme, where it can sit at the right specificity.
 */

.clab-article ul, .clab-article ol { padding-left: 1.4rem; }

/* Bullets here are rarely one line — most carry a bold lead-in and two or three
   lines of explanation after it. At .35em the gap between items was smaller than
   the leading inside them (line-height 1.65 leaves roughly .65em between lines),
   so consecutive items merged into one grey block with nothing for the eye to
   group on. The gap between items has to beat the gap between lines, or the list
   stops reading as a list. */
.clab-article li { margin-bottom: .7em; }

/* Nested lists stay tight on purpose — a sublist hugging its parent reads as
   belonging to it, which is the opposite of what sibling items need. */
.clab-article li > ul, .clab-article li > ol { margin-top: .35em; }

.clab-article blockquote {
	margin: 1.6rem 0;
	padding: .3rem 0 .3rem 1.15rem;
	border-left: 3px solid var(--clab-accent);
	color: var(--clab-text-dim);
	font-style: italic;
}

/* Code and literal game syntax.
 *
 * The reference pages quote script syntax — `Developed City=<Yes,No>`, section
 * markers like `[CES DLC]`, file names. Before /scripts/script-dlcs/ was
 * rebuilt around <code> (2026-08-15) that page carried THREE different blues
 * plus a green as inline styles, applied to some settings and not others. The
 * green measured ~3.6:1 on white, under the 4.5:1 AA wants for body text, and
 * colour was the only thing marking what a piece of text was. Marking it up as
 * <code> says what it IS and lets this one rule treat it consistently.
 *
 * Size raised from .885em to 1em over two rounds at the owner's request: on
 * these pages the settings are the substance, not an aside. 1em matches the
 * surrounding prose numerically and still reads slightly smaller, because a
 * monospace face spends more of its em box on side bearings than Inter does.
 *
 * The border is what separates a setting from the prose around it now that no
 * colour does. Kept in relative units so it tracks the body size everywhere.
 */
.clab-article code, .clab-article kbd, .clab-article samp {
	font-family: var(--clab-font-mono);
	font-size: 1em;
	background: var(--clab-code-bg);
	border: 1px solid var(--clab-border);
	padding: .12em .38em;
	border-radius: 4px;
	color: var(--clab-text);
	overflow-wrap: break-word;
}

/* A whole setting line, as opposed to a term mentioned mid-sentence.
 *
 * 6px above and below, so the setting sits in its own space rather than
 * crowding the line that introduces it ("If the survival mode is disabled:")
 * or the description under it. The three lines share one paragraph, separated
 * by <br>, so there is no block box to carry a margin — but `display:
 * inline-block` makes this an ATOMIC inline box, and unlike a plain inline box
 * its vertical margins DO add to the line box, which moves the lines either
 * side. Same mechanism as the MaxButton spacing. */
.clab-article code.clab-setting {
	display: inline-block;
	margin-top: 6px;
	margin-bottom: 6px;
	font-weight: 500;
}

/* Inside a heading, code should not fight the heading's own styling. */
.clab-article h2 code,
.clab-article h3 code,
.clab-article h4 code {
	font-size: .9em;
	background: none;
	border: 0;
	padding: 0;
	color: inherit;
}
.clab-article pre {
	font-family: var(--clab-font-mono);
	font-size: .875rem;
	background: var(--clab-code-bg);
	border: 1px solid var(--clab-border);
	border-radius: var(--clab-radius);
	padding: 1rem 1.1rem;
	overflow-x: auto;
	line-height: 1.55;
}
/* A <pre> already carries its own frame; a bordered <code> inside it would draw
 * a box within a box. /run-caplab-linux/ has three. */
.clab-article pre code { background: none; border: 0; padding: 0; font-size: 1em; }

/* --- COMPARISON ONLY: the /font-comparison/ specimen page --------------------
 *
 * Four candidates set in the site's own headings, card text and body copy. The
 * point is to judge them on real content at real sizes — a specimen sheet of
 * pangrams tells you nothing about how a 15-word card title behaves in a 211px
 * grid cell, which is where this site's typography actually gets tested.
 *
 * Each block overrides the font for everything inside it, including the card
 * component, so the comparison covers the components and not just prose.
 *
 * DELETE this block, the two @font-face rules above and the page when a face is
 * chosen.
 */
.clab-fonttest { border-top: 2px solid var(--clab-border); padding-top: 1.2rem; margin-top: 2.4rem; }
.clab-fonttest__label {
	font-family: var(--clab-font-mono);
	font-size: 12px;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--clab-text-dim);
	margin-bottom: .8rem;
}

/* The heading selectors carry .clab-article deliberately, making them (0,3,0).
   Without it they were (0,2,0) — the same as caplab-classic's
   `.clab-article h1, .clab-article h2 { font-family: var(--clab-font-display) }`
   — and the child stylesheet loads second, so Classic won and all four blocks
   rendered their headings in the same face. The card titles differed and the
   headings did not, which is exactly the kind of half-working comparison that
   would have produced a confident wrong answer. */
.clab-fonttest--inter,
.clab-fonttest--inter .clab-cards a,
.clab-article .clab-fonttest--inter h2,
.clab-article .clab-fonttest--inter h3 { font-family: "Inter", sans-serif; }

.clab-fonttest--jakarta,
.clab-fonttest--jakarta .clab-cards a,
.clab-article .clab-fonttest--jakarta h2,
.clab-article .clab-fonttest--jakarta h3 { font-family: "Plus Jakarta Sans", sans-serif; }

.clab-fonttest--figtree,
.clab-fonttest--figtree .clab-cards a,
.clab-article .clab-fonttest--figtree h2,
.clab-article .clab-fonttest--figtree h3 { font-family: "Figtree", sans-serif; }

.clab-fonttest--poppins,
.clab-fonttest--poppins .clab-cards a,
.clab-article .clab-fonttest--poppins h2,
.clab-article .clab-fonttest--poppins h3 { font-family: "Poppins", sans-serif; }

/* Legacy Weebly heading class still present across many pages. */
.clab-article .wsite-content-title {
	font-family: var(--clab-font-display);
	color: var(--clab-heading);
}

/* -------------------------------------------------------------- alignment */

.alignnone { max-width: 100%; height: auto; }
.aligncenter, div.aligncenter {
	display: block;
	margin: 1.25rem auto;
}
.alignleft  { float: left;  margin: .4rem 1.4rem 1rem 0; max-width: 50%; }
.alignright { float: right; margin: .4rem 0 1rem 1.4rem; max-width: 50%; }

/* Floats collapse the layout on phones and were a source of overflow. */
@media (max-width: 640px) {
	.alignleft, .alignright {
		float: none;
		display: block;
		margin: 1.25rem auto;
		max-width: 100%;
	}
}

.clab-article img { border-radius: var(--clab-radius); height: auto; }

/* --- spacing beneath screenshots -------------------------------------------
   Until 2026-08 this content spaced its own screenshots, with a spacer div
   hand-placed after each one:

       <div style="height: 20px; clear: both;"></div>

   520 of them had accumulated across 129 pages in six slightly different
   spellings, and any screenshot whose author forgot one sat flush against the
   text below it. That is a theme's job, not the author's, so the rule moved here
   and the spacers that followed an image were removed from the content.

   20px, not an em value, and deliberately so: it is what 469 of those 520
   spacers used. Matching it exactly made their removal a visual no-op instead of
   a redesign of 374 pages.

   Margin on BOTH sides, not just the bottom. Nearly every text block in this
   content is a bare <div>, and the margin rule above covers p/ul/ol/table but
   not div — so a text block contributes no space of its own. If the image only
   pushed downwards, text would still run flush into the top of the next
   screenshot. The image has to hold both gaps open because it is the only
   element in the sequence with any margin at all.

   Adjacent margins collapse, so two consecutive screenshots get 20px between
   them rather than 40px, and the wrapper div passes the margin through since it
   has neither padding nor border.

   Excludes floated images. .alignleft/.alignright carry their own margins for
   text to wrap against, and this rule is more specific — it would otherwise
   quietly overwrite them. */
.clab-article div > img:not(.alignleft):not(.alignright),
.clab-article div > a:only-child > img:not(.alignleft):not(.alignright) {
	display: block;
	margin: 20px 0;
}

.wp-caption { max-width: 100%; }
.wp-caption img { display: block; }
.wp-caption-text, .clab-article figcaption {
	font-size: .875rem;
	color: var(--clab-text-dim);
	padding-top: .5rem;
	text-align: center;
}

/* ----------------------------------------------------------------- tables */

.clab-article table {
	width: 100%;
	border-collapse: collapse;
	font-size: .95rem;
	font-variant-numeric: tabular-nums;
}
.clab-article table th,
.clab-article table td {
	border: 1px solid var(--clab-border);
	padding: .55rem .7rem;
	text-align: left;
	vertical-align: top;
}
.clab-article table th {
	background: var(--clab-surface);
	font-weight: 600;
	color: var(--clab-heading);
}
.clab-article table tr:nth-child(even) td { background: color-mix(in srgb, var(--clab-surface) 45%, transparent); }

/* Wide legacy tables scroll inside their own box rather than the page. */
.clab-tablewrap { overflow-x: auto; margin-bottom: 1.15em; -webkit-overflow-scrolling: touch; }

/* ---------------------------------------------------------------- buttons */

.clab-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: .5rem;
	min-height: 46px;
	padding: .6rem 1.4rem;
	border-radius: var(--clab-radius);
	background: var(--clab-accent);
	color: var(--clab-accent-ink);
	font-weight: 600;
	text-decoration: none;
	border: 1px solid transparent;
	cursor: pointer;
	transition: transform .12s ease, filter .12s ease;
}
.clab-btn:hover { filter: brightness(1.08); color: var(--clab-accent-ink); }
.clab-btn:active { transform: translateY(1px); }

.clab-btn--ghost {
	background: transparent;
	color: var(--clab-link);
	border-color: var(--clab-border-strong);
}
.clab-btn--ghost:hover { background: var(--clab-surface); color: var(--clab-link-hover); }

/*
 * What the theme still has to do for MaxButtons, and why each piece is here
 * rather than in the plugin.
 *
 * The history: the thirty old buttons were drawn at fixed pixel widths — 477px
 * on a 390px viewport, which is what made /scripts/script-basics/ scroll
 * sideways — and the plugin centred a label vertically by pushing it down from
 * the top with `padding-top: (height - line-height) / 2` and then fixing the
 * height. Those two go together, so forcing `height: auto` to stop a wrapped
 * label overflowing removed one of the pair and left every label ~9px low.
 *
 * The five role buttons are authored rather than inherited, so most of that is
 * gone: they store `width: auto`, `height: auto` and symmetric padding, and the
 * plugin emits them. What is left is the genuinely cross-cutting behaviour.
 *
 * !important is now down to THREE properties, from the fourteen that were here
 * before. Each one is a property MaxButtons emits itself, at (0,3,0) through its
 * three-class per-button selector, with no field in its admin to change it:
 *
 *     display      the plugin hard-codes inline-block on the anchor
 *     box-shadow   the plugin writes a zero shadow, always
 *     line-height  the plugin hard-codes 1em on the label
 *
 * Everything else here is a property the plugin does not set at all, so it wins
 * on its own — which is the real evidence the styling moved rather than merely
 * being shouted over. If a rule without the keyword starts losing, the plugin
 * has begun setting that property and the answer is to change it there.
 */
.maxbutton,
a.maxbutton,
[class*="maxbutton-"] {
	/* Wrapping is the correct behaviour on a phone; the desktop rule further up
	   restores single-line where there is room. max-width keeps a long label
	   inside its column instead of widening the page. */
	max-width: 100%;
	box-sizing: border-box;
	white-space: normal;
	/* Flex centring rather than the plugin's one-sided padding trick, so a label
	   that wraps to two lines stays centred instead of sitting high. The plugin
	   writes inline-block at (0,3,0), so this is one of the three. */
	display: inline-flex !important;
	align-items: center;
	justify-content: center;
}
[class*="maxbutton-"] .mb-text {
	white-space: normal;
	max-width: 100%;
	display: block;
	/* 1em from the plugin puts wrapped lines hard against each other and clips
	   descenders. There is no line-height field in its admin to set instead. */
	line-height: 1.35 !important;
}

/* ------------------------------------------- legacy hand-authored cards ---
 * 30 of the 361 pages contain inline light backgrounds written by hand
 * (background: #ffffff / #fff8e8 / #f7f9fc … with dark text assumed. On a
 * dark surface those render as white blocks with near-white headings inside
 * them — unreadable. Re-tone them here rather than editing 30 pages, and
 * match only light values so deliberate dark or image backgrounds survive.
 *
 * Applied by any theme that renders content on a dark surface; see
 * .clab-dark-content below.
 */
.clab-dark-content .clab-article [style*="background: #f"],
.clab-dark-content .clab-article [style*="background:#f"],
.clab-dark-content .clab-article [style*="background: #e"],
.clab-dark-content .clab-article [style*="background:#e"],
.clab-dark-content .clab-article [style*="background-color: #f"],
.clab-dark-content .clab-article [style*="background-color:#f"],
.clab-dark-content .clab-article [style*="background-color: white"],
.clab-dark-content .clab-article [style*="background-color:white"] {
	background: var(--clab-surface) !important;
	border-color: var(--clab-border) !important;
	box-shadow: none !important;
	color: var(--clab-text) !important;
}

/* Text colours written inside those cards assume a light backdrop too. */
.clab-dark-content .clab-article [style*="color: #0"],
.clab-dark-content .clab-article [style*="color:#0"],
.clab-dark-content .clab-article [style*="color: #1"],
.clab-dark-content .clab-article [style*="color:#1"],
.clab-dark-content .clab-article [style*="color: #2"],
.clab-dark-content .clab-article [style*="color:#2"],
.clab-dark-content .clab-article [style*="color: #3"],
.clab-dark-content .clab-article [style*="color:#3"],
.clab-dark-content .clab-article [style*="color: black"],
.clab-dark-content .clab-article [style*="color:black"] {
	color: var(--clab-text) !important;
}

/* --------------------------------------------------------------- galleries */

.gallery {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
	gap: .75rem;
	margin-bottom: 1.5rem;
}
.gallery br { display: none; }
.gallery-item { margin: 0 !important; width: auto !important; }
.gallery-item img { border: 0 !important; width: 100%; }
.gallery-caption { font-size: .82rem; color: var(--clab-text-dim); }

/* justified-gallery and foogallery bring their own layout; just keep them
   inside the container. */
.justified-gallery, .fg-gallery { max-width: 100%; }

/* --- The native gallery, replacing Justified Gallery -------------------------
 *
 * The plugin cost 61.8 KB and 10 requests on the home page — 52% of its script
 * and style weight — to lay out three images, and it was the only thing on the
 * site pulling in jQuery. inc/gallery.php has the full measurement and the
 * reasoning; this is the layout half of the replacement, and it needs no
 * JavaScript at all.
 *
 * The numbers below are not a fresh design, they are what the plugin was
 * measured producing on 2026-08-16:
 *
 *   1440px  one row, 1132px wide: tiles of 373 / 373 / 374 by 160, 3px margins
 *    390px  three stacked tiles of 296 by 160
 *
 * auto-fit with a 280px minimum reproduces both exactly. At 1132px it fits three
 * tracks and the fourth collapses, so the three tiles share the full width; at
 * 296px only one track fits. It also behaves sensibly at the tablet widths
 * nobody measured, which a hard-coded column count would not.
 *
 * The shortcode's columns= attribute is ignored, as it was before — the plugin
 * derived its columns from row height and never read it either.
 */

.clab-gallery {
	/* Tunable rather than decided. The 160px comes from the plugin's own
	   row_height setting, so the page keeps the height it has today; it crops a
	   16:9 screenshot to 2.33:1, which is a question for D2 and not something to
	   change while swapping the mechanism underneath it. */
	--clab-gallery-row-h: 160px;
	--clab-gallery-gap:   6px;
	--clab-gallery-min:   280px;

	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(var(--clab-gallery-min), 100%), 1fr));
	gap: var(--clab-gallery-gap);
	margin: 0 0 1.5rem;
	max-width: 100%;
}

/* Every rule below repeats .clab-gallery, and that is not decoration.
 *
 * The parent sets `.clab-article img { border-radius: …; height: auto; }` and
 * caplab-classic sets its own `.clab-article img` — both (0,1,1), and the child
 * stylesheet is enqueued after the parent, so a bare `.clab-gallery__img`
 * (0,1,0) loses to both. It did: the first build of this grid rendered 373x210
 * tiles with 8px corners instead of the 373x160 square tiles it asked for,
 * because height:auto won and the fixed row height never applied.
 *
 * .clab-gallery .clab-gallery__img is (0,2,0), and two classes beat one class
 * plus an element. Scoping under the region rather than reaching for !important
 * is the convention in this file. */

.clab-gallery .clab-gallery__item {
	margin: 0;
	min-width: 0;
	overflow: hidden;
	background: var(--clab-surface-2);
}

.clab-gallery .clab-gallery__link {
	display: block;
	height: 100%;
	text-decoration: none;
}

.clab-gallery .clab-gallery__img {
	display: block;
	width: 100%;
	height: var(--clab-gallery-row-h);
	object-fit: cover;
	/* Square and flat: the tiles sit flush in a grid, and both the radius and the
	   shadow that .clab-article img would give them read as three separate cards
	   rather than one strip. */
	border-radius: 0;
	box-shadow: none;
	transition: filter .15s ease;
}

/* The tile is a link to a bigger version, so it needs to read as one. Kept to a
   brightness change: the plugin shipped hover effects and they are switched off
   in its settings, so anything more would be new behaviour, not a replacement. */
.clab-gallery .clab-gallery__link:hover .clab-gallery__img { filter: brightness(1.08); }

/* --------------------------------------------------------------- lightbox */
/*
 * Dark whatever the child theme is, exactly as the plugin's PhotoSwipe skin was.
 * A viewer is not page furniture — the surround exists to disappear so the
 * screenshot reads, and a light one competes with the image. So these are local
 * values, not the palette tokens a child theme swaps.
 */

.clab-lightbox {
	/* Opaque, which is what the plugin's photoswipe_bg_opacity setting said (100)
	   and what this page needs. At 96% the 4% getting through was clearly
	   readable — the page behind is bright cards and bright screenshots, so a
	   ghost of it sat on top of the screenshot being viewed. Verified by
	   measurement first: the backdrop was covering the full 1440x1000 viewport
	   and computing to the value asked for, so the transparency was the cause and
	   not a gap in the coverage. */
	--clab-lb-bg:  #090a0c;
	--clab-lb-ink: #f4f3f0;
	--clab-lb-dim: #a9adb4;
	--clab-lb-btn: rgba(255, 255, 255, .12);

	/* How far past its own resolution an image may be drawn. The screenshots are
	   1067x600, and on a 1900px screen stopping at 1067 left two-thirds of the
	   viewport empty. 1.35 lets the image use the height it has — which is what
	   actually binds — while staying close enough to native that a JPEG of a
	   game UI does not visibly soften. */
	--clab-lb-scale: 1.35;

	/* Held in a custom property because the image sizing below has to know it —
	   see the height calculation. Deliberately tight: this padding is pure loss,
	   it comes off the height, and height is what limits the picture. The 3rem a
	   side this started with cost about 100px of image. */
	--clab-lb-padx: clamp(.85rem, 2vw, 1.6rem);
	--clab-lb-avail-w: min(1800px, calc(100vw - 2 * var(--clab-lb-padx)));

	position: fixed;
	inset: 0;
	z-index: 200;                 /* over the header at 100 and its scrim at 99 */
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--clab-lb-padx);
	opacity: 0;
	transition: opacity .18s ease;
}

/* Signed in, the admin bar is fixed at the top on wide screens and paints over
   this — putting the close button underneath it. Below 783px it is positioned
   absolutely and scrolls away, so no offset is wanted there. */
body.admin-bar .clab-lightbox { top: 32px; }
@media screen and (max-width: 782px) {
	body.admin-bar .clab-lightbox { top: 0; }
}

/* display:flex beats the hidden attribute, so hidden has to be said in CSS.
   Leaving this out is why a "hidden" dialog covers the page. */
.clab-lightbox[hidden] { display: none; }
.clab-lightbox.is-open { opacity: 1; }

.clab-lightbox__backdrop {
	position: absolute;
	inset: 0;
	background: var(--clab-lb-bg);
}

.clab-lightbox__frame {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: .7rem;
	margin: 0;
	width: min(1800px, 100%);
	/* A definite height, not max-height: 100%. The image's max-height is a
	   percentage, and a percentage resolves to none against an auto-height
	   parent — which is what left flex free to size the picture instead. */
	height: 100%;
}

.clab-lightbox__img {
	display: block;
	min-height: 0;                /* or the image refuses to shrink inside flex */

	/*
	 * ONE SPECIFIED DIMENSION, DERIVED FROM ALL THREE LIMITS AT ONCE.
	 *
	 * The obvious spellings were tried first and each measured wrong, so they are
	 * recorded rather than left to be rediscovered:
	 *
	 *   height auto, shrink 1    can never exceed the file's own resolution, so a
	 *                            1067px screenshot stopped at 1067px and left a
	 *                            1900px screen two-thirds empty.
	 *   height set, shrink 1     measured 366x589 for a 1067x600 image at 390px:
	 *                            flex sized the height to fill the frame while
	 *                            max-width clamped the width, neither aware of
	 *                            the other. A landscape shot rendered portrait.
	 *   + aspect-ratio           no help. aspect-ratio only derives the dimension
	 *                            that is auto, and the height was not.
	 *   height set, shrink 0     still 366x588. The replaced-element rules that
	 *                            would rescale one axis when the other is clamped
	 *                            are not reliably applied to a flex item, so
	 *                            max-width and max-height each bit independently.
	 *
	 * So nothing is left to the browser to reconcile. The height is the smallest
	 * of the three things that could limit it, and the width simply follows from
	 * the intrinsic ratio — no clamp ever has to fire, so no clamp can fight
	 * another:
	 *
	 *   1. the file's own height times the scale — how large it may be drawn
	 *   2. what the caption leaves, measured and written by lightbox.js
	 *   3. the height at which the derived width would exactly fill the frame
	 *
	 * --clab-lb-nat-w and -nat-h are unitless and written per image by
	 * lightbox.js, because CSS cannot read a file's own dimensions. The generous
	 * fallbacks make terms 1 and 3 drop out if they are ever missing, leaving the
	 * available height; object-fit then keeps the picture undistorted.
	 */
	flex: 0 0 auto;
	align-self: center;           /* not stretch, which ignores the ratio */
	height: min(
		calc(var(--clab-lb-nat-h, 99999) * 1px * var(--clab-lb-scale)),
		calc(100% - var(--clab-lb-meta-h, 6rem) - .7rem),
		calc(var(--clab-lb-avail-w) * var(--clab-lb-nat-h, 99999) / var(--clab-lb-nat-w, 1))
	);
	width: auto;
	max-width: 100%;
	object-fit: contain;
	margin: 0 auto;
	border-radius: var(--clab-radius);
}

/* Caption and counter run as one line of text, so the reading measure and the
   centring belong here rather than on the caption — the two are inline now and
   an inline box takes no max-width.

   Capped and scrollable so a long caption can never push the image off screen:
   28vh of an 800px window is 224px, which was most of the picture. */
.clab-lightbox__meta {
	flex: 0 0 auto;
	max-width: 78ch;
	max-height: 22vh;
	margin: 0 auto;
	overflow-y: auto;
	text-align: center;
	color: var(--clab-lb-dim);
	font-size: .9rem;
	line-height: 1.5;
}
.clab-lightbox__caption { color: var(--clab-lb-ink); }
.clab-lightbox__count {
	/* The gap after the caption. A margin rather than a space in the markup, so
	   it survives however the string is built, and it is still right when there
	   is no caption at all. */
	margin-left: .4em;
	white-space: nowrap;    /* never break "(2 of 3)" across lines */
	font-variant-numeric: tabular-nums;
	letter-spacing: .04em;
}
.clab-lightbox__caption[hidden],
.clab-lightbox__count[hidden] { display: none; }

.clab-lightbox__btn {
	position: absolute;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: center;
	/* 48px, comfortably past the 44px touch minimum the mobile audit set. */
	width: 48px;
	height: 48px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	/* Now that the picture uses the full width, these sit over it rather than in
	   a gutter — so they need to read against a bright screenshot as well as
	   against the backdrop. A dark fill with a light ring does both; a plain
	   translucent white disc disappeared into pale artwork. */
	background: rgba(12, 14, 17, .55);
	border: 1px solid rgba(255, 255, 255, .3);
	color: var(--clab-lb-ink);
	font-size: 1.9rem;
	line-height: 1;
	cursor: pointer;
	transition: background .15s ease, border-color .15s ease;
}
.clab-lightbox__btn:hover {
	background: rgba(12, 14, 17, .82);
	border-color: rgba(255, 255, 255, .6);
}
.clab-lightbox__btn[hidden] { display: none; }

.clab-lightbox__close { top: 1rem; right: 1rem; }
.clab-lightbox__prev  { top: 50%; left: 1rem;  transform: translateY(-50%); }
.clab-lightbox__next  { top: 50%; right: 1rem; transform: translateY(-50%); }

/* On a phone there is no gutter to put the arrows in, so they go along the
   bottom instead of sitting on top of the image. Swipe is the main gesture at
   this width; the buttons are the accessible route to the same thing. */
@media (max-width: 600px) {
	.clab-lightbox {
		--clab-lb-padx: .75rem;
		padding: 4rem var(--clab-lb-padx) 5rem;
	}
	.clab-lightbox__prev,
	.clab-lightbox__next { top: auto; bottom: 1rem; transform: none; }
	.clab-lightbox__prev { left: 1.25rem; }
	.clab-lightbox__next { right: 1.25rem; }
}

/* Set on <html> while the overlay is open. */
.clab-lightbox-open { overflow: hidden; }

/* ==========================================================================
   11. PAGE FURNITURE
   ========================================================================== */

.clab-pagehead { margin-bottom: 1.75rem; }
.clab-pagehead__title { margin: 0; }
.clab-pagehead__meta {
	color: var(--clab-text-dim);
	font-size: .875rem;
	margin-top: .5rem;
}

.clab-prevnext {
	display: grid;
	gap: .75rem;
	grid-template-columns: 1fr;
	margin-top: 3rem;
	padding-top: 1.5rem;
	border-top: 1px solid var(--clab-border);
}
@media (min-width: 640px) { .clab-prevnext { grid-template-columns: 1fr 1fr; } }
.clab-prevnext a {
	display: block;
	padding: .9rem 1.1rem;
	border: 1px solid var(--clab-border);
	border-radius: var(--clab-radius);
	text-decoration: none;
	color: var(--clab-text);
	min-height: 44px;
}
.clab-prevnext a:hover { border-color: var(--clab-accent); background: var(--clab-surface); }
.clab-prevnext small { display: block; color: var(--clab-text-dim); font-size: .78rem; text-transform: uppercase; letter-spacing: .08em; }
.clab-prevnext .is-next { text-align: right; }

/* ==========================================================================
   12. MARKETING COMPONENTS
   ========================================================================== */

.clab-hero {
	position: relative;
	padding: clamp(2.5rem, 7vw, 5.5rem) 0;
	text-align: center;
	overflow: hidden;
}
.clab-hero__title {
	margin: 0 0 .75rem;
	font-size: clamp(2rem, 1.1rem + 3.6vw, 3.4rem);
}
.clab-hero__sub {
	max-width: 62ch;
	margin: 0 auto 1.75rem;
	font-size: clamp(1.02rem, .96rem + .35vw, 1.2rem);
	color: var(--clab-text-dim);
}
.clab-hero__actions { display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; }

.clab-grid {
	display: grid;
	gap: 1.25rem;
	grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
	/* Carries its own bottom spacing, the same way §2 gives p, ul, table and
	   blockquote theirs. Without it the gap under a grid is whatever the NEXT
	   element brings: measured on /award-winning-sim/, the h2 after the first
	   grid supplied 47.6px and looked right, while the MaxButton after the
	   second brought 0 and sat flush against the cards.

	   Safe for the h2 case: adjacent siblings collapse margins, and a grid
	   container collapses with its siblings (only its CHILDREN are exempt), so
	   that gap stays 47.6px rather than becoming 73px. */
	margin-bottom: 1.6rem;
}
.clab-card {
	background: var(--clab-surface);
	border: 1px solid var(--clab-border);
	border-radius: var(--clab-radius-lg);
	padding: 1.4rem;
}
.clab-card h3 { margin-top: 0; }

/* A quotation inside a card does not need the accent bar §10 gives it — the
   card frame already separates it, and the two together read as two nested
   boxes. (0,2,1) so it beats `.clab-article blockquote` (0,1,1) regardless of
   where either lands in the file. */
.clab-article .clab-card blockquote {
	margin: 0 0 .85rem;
	padding: 0;
	border-left: 0;
}
.clab-article .clab-card > :last-child { margin-bottom: 0; }

/* Press and partner logos. They arrive at whatever size the outlet published —
   on /recognition-and-awards/ nine of them, from 200×45 to 180×180 — so a
   single max-width would leave a square badge towering over a wordmark.
   Constraining BOTH axes fits each one into the same box instead, which is what
   makes a row of mixed logos read as a row.

   (0,4,1), matching the image-spacing rule at ~line 462. It also has to clear
   Classic's `.clab-article img { border-radius: 8px }` (0,1,1) — a logo on a
   transparent background must not be rounded off at the corners. */
.clab-article img.clab-logo:not(.emoji):not(.wp-smiley) {
	display: block;
	/* A FIXED height, not a max-height. Capping instead of fixing let each logo
	   keep its own height — measured on /recognition-and-awards/ at 1440, the
	   nine came out 60, 60, 60, 60, 60, 60, 60, 50 and 43px tall — so the quote
	   under each one started on a different line and the row looked ragged.
	   Pinning the box makes every quote start level.

	   object-fit letterboxes the picture inside that box rather than stretching
	   it, so a 200×45 wordmark is not distorted to fill a square. It also lifts
	   the near-square badges from 60×60 to 64×64: PC Gamer and CNET were
	   rendering at 3,600px² against GameSpot's 11,250px², and equal HEIGHT is
	   the closest a two-value box can get to equal weight. */
	width: auto;
	height: 64px;
	max-width: 190px;
	object-fit: contain;
	object-position: left center;
	margin: 0 0 1rem;
	border: 0;
	border-radius: 0;
}

/* ==========================================================================
   13. TUTORIAL COMPONENTS
   For the how-to pages: numbered steps, callouts, and framed screenshots.

   Built as theme components rather than inline markup on one page because the
   pattern is not rare — measured across the 345 published pages: 15 carry
   hand-numbered steps written as <strong>1)</strong>, and 15 carry an
   "Important:" warning. /caplab-porting-kit/ is simply the longest of them.
   ========================================================================== */

/* ------------------------------------------------------- numbered steps ---

   The number is a CSS counter, NOT text in the markup. That is the point of
   the component: /caplab-porting-kit/ had two steps both numbered "2)" and the
   rest of the page counting from the wrong base, which is what hand-numbering
   costs on a page that gets edited over four years. Insert or delete a step
   here and the rest renumber themselves.

   The reset lives on h2 and NOWHERE ELSE, so a page describing more than one
   procedure counts each from 1. /run-caplab-linux/ is the case: three methods,
   and its Lutris steps must not carry on into the virtual-machine ones.

   THE CONTAINER MUST NOT ALSO RESET IT. `.clab-article { counter-reset }` looks
   harmless — "start every page at 1" — and it silently defeats the h2 reset.
   Measured in Chromium on a three-case test page, two sections of two steps:

     .a { counter-reset } + .a h2 { counter-reset }      ->  1 2 3 4   wrong
     .a { counter-reset } + .a h2 { counter-reset: s 0 } ->  1 2 3 4   wrong
     h2 reset only, container does not reset             ->  1 2 1 2   right

   Dropping the container reset costs nothing: `counter-increment` on its own
   creates the counter implicitly, so a page whose steps start before any h2
   still numbers from 1. */
.clab-article h2 { counter-reset: clab-step; }

.clab-article h3.clab-step {
	counter-increment: clab-step;
	display: flex;
	align-items: flex-start;
	gap: .55em;
}

.clab-article h3.clab-step::before {
	content: counter(clab-step);
	flex: 0 0 auto;
	display: grid;
	place-items: center;
	width: 1.55em;
	height: 1.55em;
	font-size: .74em;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	line-height: 1;
	border-radius: 50%;
	background: var(--clab-accent);
	color: var(--clab-accent-ink);
	/* Both ends of this pair are tokens on purpose. Classic pairs #843c0b with
	   white (8.0:1); the parent's default pairs #b8860b with near-black
	   (6.1:1). Hard-coding either colour breaks one of them. */

	/* The badge is a fixed square, so flex-start pins it to the heading's top
	   edge rather than to the first line's optical centre. Nudge it down by
	   half the difference. Classic sets h3 to 24px/32px and the badge lands at
	   ~26px, so ~3px — expressed in em to track any child that resizes h3. */
	margin-top: .13em;
}

/* --------------------------------------------------------- callout note ---

   Replaces the <h4>Important: …</h4> shape these pages used. That was wrong
   twice over: it put body text in a heading, and it skipped a level (h2 -> h4)
   which a11y-sweep.js flags.

   Colours come from --clab-note-* rather than from a mix of --clab-accent, for
   the reason recorded at those tokens. Note that mixing against --clab-bg would
   be wrong here in any case: in Classic --clab-bg is #202020, the dark surround
   the white content card sits on, not the ground this panel actually sits on. */
.clab-article .clab-note {
	margin: 1.5rem 0;
	padding: .95rem 1.15rem;
	border: 1px solid var(--clab-note-border);
	border-left: 4px solid var(--clab-accent);
	border-radius: var(--clab-radius);
	background: var(--clab-note-bg);
}

/* (0,2,1) — deliberately one element up from a bare .clab-note child selector.
   Classic sets `.clab-article p { margin-bottom: 22.5px }` at (0,2,0) and loads
   AFTER the parent, so an equal-specificity rule here would lose and leave a
   ragged 22px gap under the last line inside every callout. */
.clab-article .clab-note > p:first-child,
.clab-article .clab-note > ul:first-child,
.clab-article .clab-note > ol:first-child { margin-top: 0; }
.clab-article .clab-note > p:last-child,
.clab-article .clab-note > ul:last-child,
.clab-article .clab-note > ol:last-child { margin-bottom: 0; }

/* --------------------------------------------------- framed screenshots ---

   The screenshots on a how-to page arrive at whatever size they were captured:
   on /caplab-porting-kit/ they run from a 302px dialog to a 1501px window. Left
   alone they read as thirteen unrelated pictures. Capping the wide ones and
   centring all of them gives the page a single column of evidence.

   NOT upscaled. A 302px dialog stays 302px — stretching it to a common width
   would only blur it.

   (0,4,1), matching `.clab-article img:not(.emoji):not(.wp-smiley):not(:only-child)`
   at line ~462, which sets display and margin-bottom and would otherwise win.
   Equal weight, so this must stay BELOW that rule in the file. It also has to
   clear Classic's `.clab-article img { border: 0 }` (0,1,1), which loads later —
   the border is the whole point of the frame. */
.clab-article img.clab-shot:not(.emoji):not(.wp-smiley) {
	display: block;
	max-width: min(100%, 900px);
	height: auto;
	margin: 1.35rem auto 1.7rem;
	border: 1px solid var(--clab-border);
	border-radius: var(--clab-radius);
}

/* ==========================================================================
   14. FOOTER
   Same content and order as the live site: newsletter call to action, one
   centred row of links, round social icons, copyright.
   ========================================================================== */

.clab-footer {
	background: var(--clab-footer-bg);
	color: var(--clab-footer-dim);
	padding: 3rem 0 2.5rem;
	font-size: .925rem;
	/* Pinned so the footer stops inheriting each page's measure. The home page
	   sets line-height 1.62 on the body and the rest of the site resolves to
	   about 1.49, which made the same footer 2px taller per line on one page
	   than on the other 357 — measured, not guessed. One footer means it sets
	   its own. */
	line-height: 1.5;
	margin-top: 4rem;
	text-align: center;
}
.clab-footer a { color: var(--clab-footer-ink); }
.clab-footer a:hover { color: var(--clab-accent); }

/* Optional widget area. The live footer carries no widgets, so this renders
   nothing unless one is added — it just gives the registered sidebar a home. */
.clab-footer__grid {
	display: grid;
	gap: 2rem;
	grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
	margin-bottom: 2.5rem;
	text-align: left;
}
.clab-widget__title,
.clab-footer h2 {
	font-family: var(--clab-font-body);
	font-size: .78rem;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--clab-footer-ink);
	margin: 0 0 .75rem;
}
.clab-footer ul { list-style: none; margin: 0; padding: 0; }
.clab-footer__grid li { margin-bottom: .4rem; }
.clab-footer__grid li a { text-decoration: none; }
.clab-footer__grid li a:hover { text-decoration: underline; }

/* ------------------------------------------------------- newsletter call --
 * The one thing the footer asks for, so it is a button rather than a link.
 * Scoped to .clab-footer so it outranks the "#footer a { colour }" rule above
 * — otherwise the button takes the footer's link colour instead of its own.
 */
/* ONE FOOTER, ONE BUTTON (2026-08-15, at the owner's request).
   The home page used to carry its own larger #C84D16 variant of this button
   through a body.clab-home-style override, so the footer looked like two
   different footers depending on the page. That override is gone and its values
   live here, which makes this the only rule that styles the subscribe button.

   WHY THE COLOURS ARE LITERAL RATHER THAN --clab-cta. That token is shared with
   the BUY GAME button in the header (.clab-nav-cta), and it is deliberately the
   one colour on the site reserved for "press this". Repointing it to #C84D16 to
   move this button would silently repaint the header's primary call to action
   too. Two components, one token, different intentions — so the footer states
   its own values.

   The change also improves contrast: white on the old --clab-cta (#E67E22)
   measured 2.85:1 against a 4.5:1 minimum on every page. White on #C84D16 is
   4.64:1 and passes. That was the home page's value all along; adopting it
   site-wide fixes the other 357 pages as a side effect. */
.clab-footer .clab-subscribe {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: .625rem;
	max-width: 100%;
	/* The home page's sizing, with the text brought down to 17px on 2026-08-16
	   to match the buy buttons — MaxButtons id 31 sets its label at 17px, and
	   the footer's call to action should not shout louder than "Buy Subsidiary
	   DLC for $9.99". It was 19px.

	   The padding is deliberately NOT reduced with it. This is still the only
	   call to action in the footer, and at the surrounding body size the button
	   read as a coloured strip rather than a button; the box keeps that
	   presence while the text sits in the site's button scale. */
	padding: 1rem 1.75rem;
	font-size: 17px;
	font-weight: 700;
	line-height: 1.35;
	color: var(--clab-cta-ink);
	background: #c84d16;
	border: 1px solid #c84d16;
	border-radius: 8px;
	text-decoration: none;
	box-shadow: 0 1px 2px rgba(16, 24, 40, .12), 0 1px 3px rgba(16, 24, 40, .08);
	transition: background-color .18s ease, box-shadow .18s ease, transform .18s ease;
}
.clab-footer .clab-subscribe:hover,
.clab-footer .clab-subscribe:focus-visible {
	color: var(--clab-cta-ink);
	background: #a83d0f;
	border-color: #a83d0f;
	text-decoration: none;
	box-shadow: 0 4px 8px rgba(16, 24, 40, .16), 0 2px 4px rgba(16, 24, 40, .10);
	transform: translateY(-1px);
}
.clab-footer .clab-subscribe:active { transform: translateY(0); }
.clab-footer .clab-subscribe svg { flex: 0 0 auto; width: 18px; height: 18px; display: block; }

/* ------------------------------------------------------------- link row -- */

.clab-footer__nav { margin-top: 1.5rem; }

.clab-footer__menu {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: .35rem .7rem;
	font-size: .875rem;
	line-height: 1.6;
}
.clab-footer__menu li { display: flex; align-items: center; margin: 0; }

/* Pipes between links, from CSS rather than markup, so a menu assigned in the
   Customizer gets the same separators as the built-in list. */
.clab-footer__menu li + li::before {
	content: "|";
	margin-right: .7rem;
	opacity: .4;
	user-select: none;
}

.clab-footer__menu a {
	color: var(--clab-footer-ink);
	text-decoration: none;
	border-bottom: 1px solid transparent;
	transition: color .2s ease, border-color .2s ease;
}
.clab-footer__menu a:hover,
.clab-footer__menu a:focus {
	color: var(--clab-accent);
	text-decoration: none;
	border-bottom-color: currentColor;
}

/* -------------------------------------------------------- social icons -- */

/* Scoped past `.clab-footer ul { margin: 0 }` above, which is one specificity
   point heavier than a lone class and was flattening this to nothing — the
   icons sat directly under the link row with no space at all. */
.clab-footer .clab-footer__social {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: .75rem;
	margin: 1.5rem 0 0;
}
.clab-footer__social li { margin: 0; }
.clab-footer__social a {
	display: block;
	border-radius: 50%;
	line-height: 0;
	transition: transform .2s ease, box-shadow .2s ease, opacity .2s ease;
}
.clab-footer__social a:hover,
.clab-footer__social a:focus {
	transform: translateY(-2px);
	box-shadow: 0 4px 10px rgba(0, 0, 0, .3);
	opacity: .92;
}
.clab-footer__social img {
	display: block;
	width: 34px;
	height: 34px;
	border: 0;
	border-radius: 50%;
	max-width: none;
}

/* ------------------------------------------------------------ copyright -- */

.clab-footer__legal {
	margin: 1.4rem 0 0;
	padding-top: 1.15rem;
	border-top: 1px solid var(--clab-footer-border);
	font-size: .8125rem;
	line-height: 1.6;
	color: var(--clab-footer-dim);
}

@media (max-width: 600px) {
	.clab-footer .clab-subscribe {
		display: flex;
		width: 100%;
		font-size: .875rem;
		padding: .75rem 1rem;
	}
	.clab-footer__menu { gap: .35rem .55rem; font-size: .8125rem; }
	.clab-footer__menu li + li::before { margin-right: .55rem; }
	.clab-footer__legal { font-size: .75rem; }
}

/* ==========================================================================
   15. SEARCH RESULTS / 404
   ========================================================================== */

.clab-result {
	padding: 1.15rem 0;
	border-bottom: 1px solid var(--clab-border);
}
.clab-result h2 { margin: 0 0 .35rem; font-size: 1.25rem; }
.clab-result__url { font-size: .82rem; color: var(--clab-text-dim); word-break: break-all; }

.clab-pagination { display: flex; gap: .4rem; flex-wrap: wrap; margin-top: 2rem; }
.clab-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px; min-height: 44px;
	padding: 0 .6rem;
	border: 1px solid var(--clab-border);
	border-radius: var(--clab-radius);
	text-decoration: none;
}
.clab-pagination .current {
	background: var(--clab-accent);
	color: var(--clab-accent-ink);
	border-color: transparent;
	font-weight: 600;
}

/* ==========================================================================
   16. MOTION / PRINT
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
	*, *::before, *::after {
		animation-duration: .001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .001ms !important;
	}
}

@media print {
	.clab-header, .clab-footer, .clab-docsnav, .clab-crumbs, .clab-prevnext { display: none !important; }
	body { background: #fff; color: #000; font-size: 11pt; }
	.clab-article > * { max-width: none; }
	a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .85em; word-break: break-all; }
}
