/*
 * 300Hours theme
 *
 * The design tokens below are not invented. Every value is lifted from the settings the
 * live site actually runs on, so this build matches it rather than approximating it.
 * Where a value came from the GeneratePress customizer the setting name is named next to
 * it, which makes it possible to check any one of them against the original.
 *
 * Bootstrap 5.3 exposes its own theming through custom properties, so the site palette is
 * declared once here and Bootstrap's variables are pointed at it. That way a colour is
 * changed in one place and the framework follows.
 */

/* ---------------------------------------------------------------------------
 * 1. Fonts
 * ------------------------------------------------------------------------ */

@font-face {
	font-family: "Barlow";
	src: url("../fonts/barlow-regular-webfont.woff2") format("woff2"),
	     url("../fonts/barlow-regular-webfont.woff") format("woff");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: "Barlow";
	src: url("../fonts/barlow-semibold-webfont.woff2") format("woff2"),
	     url("../fonts/barlow-semibold-webfont.woff") format("woff");
	font-weight: 600;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: "Barlow";
	src: url("../fonts/barlow-bold-webfont.woff2") format("woff2"),
	     url("../fonts/barlow-bold-webfont.woff") format("woff");
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: "Roboto";
	src: url("../fonts/roboto-regular-webfont.woff2") format("woff2"),
	     url("../fonts/roboto-regular-webfont.woff") format("woff");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: "Roboto";
	src: url("../fonts/roboto-bold-webfont.woff2") format("woff2"),
	     url("../fonts/roboto-bold-webfont.woff") format("woff");
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}


/* ---------------------------------------------------------------------------
 * 2. Tokens
 * ------------------------------------------------------------------------ */

:root {
	/* Brand. The green is the button and call to action colour, the blue is
	   navigation and links. Both taken from form_button_background_color and
	   navigation_background_color. */
	--h-green:            #009966;
	--h-green-dark:       #006a3b;
	--h-blue:             #1976d2;
	--h-blue-dark:        #004ba0;
	--h-blue-link:        #1976c2;
	--h-blue-light:       #63a4ff;
	--h-blue-meta-hover:  #008ed6;

	/* Neutrals. content_text_color, h1_color and the greys the stylesheet leans on. */
	--h-body-text:        #616161;
	--h-heading:          #212121;
	--h-white:            #ffffff;
	--h-off-white:        #fafafa;
	--h-page-bg:          #ffffff;
	--h-rule:             #dfe1e5;
	--h-panel:            #f7f8f9;
	--h-panel-alt:        #f0f0f0;

	/* Supporting colours used by cards and badges in the existing stylesheet. */
	--h-red:              #d75367;
	--h-purple:           #8a75d9;
	--h-sky:              #bbdefb;

	/* Type. body_font_size 20, body_line_height 1.8, heading_1_font_size 42,
	   heading_2_font_size 35 with mobile_heading_2_font_size 27. */
	--h-font-body:        "Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
	--h-font-heading:     "Barlow", -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
	--h-fs-body:          20px;
	--h-lh-body:          1.8;
	--h-fs-h1:            42px;
	--h-fs-h2:            35px;
	--h-fs-h2-mobile:     27px;
	--h-fs-h3:            28px;
	--h-fs-h4:            22px;
	--h-fs-nav:           14px;
	--h-fs-small:         14px;
	--h-fs-button:        16px;
	--h-lh-heading:       1.2;
	--h-paragraph-gap:    1.5em;

	/* Layout. container_width 1200, logo_width 200. */
	--h-container:        1200px;
	--h-logo-width:       200px;
	--h-gutter:           20px;
	--h-radius:           4px;

	/* Point Bootstrap at the site palette so the framework and the theme agree. */
	--bs-primary:         var(--h-blue);
	--bs-body-color:      var(--h-body-text);
	--bs-body-bg:         var(--h-page-bg);
	--bs-body-font-family: var(--h-font-body);
	--bs-body-font-size:  var(--h-fs-body);
	--bs-body-line-height: var(--h-lh-body);
	--bs-link-color:      var(--h-blue-link);
	--bs-link-hover-color: var(--h-blue-light);
	--bs-border-color:    var(--h-rule);
	--bs-heading-color:   var(--h-heading);
	--bs-border-radius:   var(--h-radius);
}


/* ---------------------------------------------------------------------------
 * 3. Base
 * ------------------------------------------------------------------------ */

body {
	font-family: var(--h-font-body);
	font-size: var(--h-fs-body);
	font-weight: 400;
	line-height: var(--h-lh-body);
	color: var(--h-body-text);
	background-color: var(--h-page-bg);
	-webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
	font-family: var(--h-font-heading);
	color: var(--h-heading);
	line-height: var(--h-lh-heading);

	/*
	 * Headings fill the line before they wrap.
	 *
	 * This carried text-wrap: balance, which evens the lines of a wrapped heading out
	 * rather than filling each one. On /cfa/ at 1280 that put the break in the middle of
	 * a heading with 744px of room: 447px on the first line and 360px on the second,
	 * where filling gives 705 and 103. It is a real typographic technique and it reads,
	 * to anyone looking at the page, as the heading breaking long before it needs to.
	 *
	 * The site this replaces fills the line, so wrapping now matches it. Left as the
	 * browser default rather than stated, because that default is the filling behaviour.
	 */
}

h1 { font-size: var(--h-fs-h1); font-weight: 400; }
h2 { font-size: var(--h-fs-h2); font-weight: 600; }
h3 { font-size: var(--h-fs-h3); font-weight: 600; }
h4 { font-size: var(--h-fs-h4); font-weight: 600; }

p { margin-bottom: var(--h-paragraph-gap); }

a {
	color: var(--h-blue-link);
	text-decoration: none;
}

a:hover,
a:focus {
	color: var(--h-blue-light);
	text-decoration: underline;
}

/* Keyboard users need to be able to see where they are. GeneratePress supplies its own
   focus ring and this replaces it, rather than removing it and leaving nothing. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
	outline: 2px solid var(--h-blue);
	outline-offset: 2px;
}

img {
	max-width: 100%;
	height: auto;
}


/* ---------------------------------------------------------------------------
 * 4. Shell
 * ------------------------------------------------------------------------ */

.h-container {
	width: 100%;
	max-width: var(--h-container);
	margin-inline: auto;
	padding-inline: var(--h-gutter);
}

.site-header {
	background-color: var(--h-white);
}

.site-branding img,
.custom-logo {
	width: var(--h-logo-width);
	max-width: 100%;
	height: auto;
}


/* ---------------------------------------------------------------------------
 * 5. Navigation
 * ------------------------------------------------------------------------ */

.main-navigation {
	background-color: var(--h-blue);
	font-family: var(--h-font-heading);
	font-size: var(--h-fs-nav);
	font-weight: 400;
}

.main-navigation .nav-link,
.main-navigation .navbar-brand {
	color: var(--h-off-white);
	padding: 12px 16px;
	line-height: 1.4;
}

.main-navigation .nav-link:hover,
.main-navigation .nav-link:focus {
	background-color: var(--h-blue-dark);
	color: var(--h-white);
	text-decoration: none;
}

.main-navigation .nav-item.current-menu-item > .nav-link,
.main-navigation .nav-link.active {
	background-color: var(--h-blue);
	color: var(--h-white);
}

.main-navigation .dropdown-menu {
	background-color: var(--h-blue);
	border: 0;
	border-radius: 0;
	padding: 0;
	margin: 0;
}

.main-navigation .dropdown-item {
	color: var(--h-off-white);
	padding: 12px 16px;
	font-size: var(--h-fs-nav);
	white-space: normal;
}

.main-navigation .dropdown-item:hover,
.main-navigation .dropdown-item:focus {
	background-color: var(--h-blue-dark);
	color: var(--h-white);
}

/*
 * Search sits in the navigation bar as a toggle, matching the live site. A details element
 * rather than a script, so it still opens with JavaScript off.
 */
.nav-search {
	position: relative;
	flex: 0 0 auto;
}

.nav-search__toggle {
	list-style: none;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	color: var(--h-off-white);
	border-radius: var(--h-radius);
}

.nav-search__toggle::-webkit-details-marker { display: none; }
.nav-search__toggle::marker { content: ""; }

.nav-search__toggle:hover,
.nav-search[open] .nav-search__toggle {
	background-color: var(--h-blue-dark);
	color: var(--h-white);
}

.nav-search__form {
	position: absolute;
	right: 0;
	top: 100%;
	z-index: 30;
	padding: 10px;
	background-color: var(--h-blue-dark);
	border-radius: 0 0 var(--h-radius) var(--h-radius);
	min-width: 260px;
}

.nav-search__form .form-control {
	background-color: var(--h-off-white);
	color: var(--h-body-text);
	border: 0;
	font-size: var(--h-fs-nav);
}

/* Inside the mobile collapse there is room, so the field sits in the flow. */
@media (max-width: 991.98px) {
	.nav-search__form {
		position: static;
		min-width: 0;
		padding: 10px 0;
		background: transparent;
	}
}

.navbar-toggler {
	border-color: rgba(255, 255, 255, .5);
	color: var(--h-off-white);
}


/* ---------------------------------------------------------------------------
 * 6. Buttons
 * ------------------------------------------------------------------------ */

/*
 * The theme button only. .wp-block-button__link is deliberately not included: the block
 * editor button carries its own shape, and styling it here turned the pill shaped topic
 * links on the hub pages into square 66px blocks.
 */
.btn-h,
input[type="submit"],
button[type="submit"] {
	display: inline-block;
	background-color: var(--h-green);
	border: 0;
	border-radius: var(--h-radius);
	color: var(--h-white);
	font-family: var(--h-font-body);
	font-size: var(--h-fs-button);
	font-weight: 400;
	line-height: 45px;
	padding-inline: 24px;
	text-align: center;
	text-decoration: none;
	transition: background-color .2s ease-in-out;
}

.btn-h:hover,
.btn-h:focus,
input[type="submit"]:hover,
button[type="submit"]:hover {
	background-color: var(--h-green-dark);
	color: var(--h-white);
	text-decoration: none;
}


/* ---------------------------------------------------------------------------
 * 7. Article cards
 * ------------------------------------------------------------------------ */

.h-card {
	background-color: var(--h-white);
	border: 1px solid var(--h-rule);
	border-radius: var(--h-radius);
	overflow: hidden;
	height: 100%;
	display: flex;
	flex-direction: column;
}

/* The image slot keeps a fixed ratio so a row of cards lines up. Intrinsic width and
   height are set on the img itself in the template as well, so the browser reserves the
   space before the image loads and the page does not jump. */
.h-card__media {
	display: block;
	aspect-ratio: 16 / 9;
	overflow: hidden;
	background-color: var(--h-panel-alt);
}

.h-card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.h-card__body {
	padding: 18px 20px 22px;
	display: flex;
	flex-direction: column;
	gap: 10px;
	flex: 1 1 auto;
}

.h-card__title {
	font-size: 22px;
	font-weight: 600;
	line-height: 1.25;
	margin: 0;
}

.h-card__title a {
	color: var(--h-heading);
}

.h-card__title a:hover {
	color: var(--h-blue-link);
	text-decoration: none;
}

.h-card__excerpt {
	font-size: 16px;
	line-height: 1.6;
	margin: 0;
}

.h-card__meta {
	font-size: var(--h-fs-small);
	color: var(--h-body-text);
	margin-top: auto;
}

.h-card__meta a { color: var(--h-body-text); }
.h-card__meta a:hover { color: var(--h-blue-meta-hover); }


/* ---------------------------------------------------------------------------
 * 8. Entry meta and breadcrumb
 * ------------------------------------------------------------------------ */

.entry-meta {
	font-size: var(--h-fs-small);
	color: var(--h-body-text);
}

.entry-meta a { color: var(--h-body-text); }
.entry-meta a:hover { color: var(--h-blue-meta-hover); }

.h-breadcrumb {
	font-size: var(--h-fs-small);
	color: var(--h-body-text);
	margin-bottom: 20px;
}

.h-breadcrumb a { color: var(--h-body-text); }
.h-breadcrumb a:hover { color: var(--h-blue-meta-hover); }


/* ---------------------------------------------------------------------------
 * 9. Pagination
 * ------------------------------------------------------------------------ */

.h-pagination {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	align-items: center;
	margin: 40px 0 10px;
	padding: 0;
	list-style: none;
}

.h-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	padding: 0 12px;
	border: 1px solid var(--h-rule);
	border-radius: var(--h-radius);
	color: var(--h-body-text);
	font-size: 16px;
	text-decoration: none;
}

.h-pagination .page-numbers:hover {
	background-color: var(--h-panel);
	color: var(--h-blue-link);
	text-decoration: none;
}

.h-pagination .page-numbers.current {
	background-color: var(--h-blue);
	border-color: var(--h-blue);
	color: var(--h-white);
}

.h-pagination .page-numbers.dots {
	border-color: transparent;
	min-width: auto;
	padding: 0 4px;
}


/* ---------------------------------------------------------------------------
 * 10. Content
 * ------------------------------------------------------------------------ */

.entry-content > * + * { margin-top: var(--h-paragraph-gap); }

.entry-content ul,
.entry-content ol {
	padding-left: 1.4em;
}

.entry-content li + li { margin-top: .4em; }

.entry-content img { border-radius: var(--h-radius); }

.entry-content table {
	width: 100%;
	border-collapse: collapse;
	font-size: 16px;
}

.entry-content th,
.entry-content td {
	border: 1px solid var(--h-rule);
	padding: 10px 12px;
	text-align: left;
}

.entry-content th { background-color: var(--h-panel); }

/* Wide content must scroll inside its own box rather than pushing the page sideways. */
.entry-content .table-scroll,
.entry-content figure.wp-block-table {
	overflow-x: auto;
	max-width: 100%;
}

.entry-content pre {
	overflow-x: auto;
	background-color: var(--h-panel);
	padding: 14px 16px;
	border-radius: var(--h-radius);
}


/* ---------------------------------------------------------------------------
 * 11. Sidebar
 * ------------------------------------------------------------------------ */

.h-sidebar .widget {
	margin-bottom: 32px;
	font-size: 16px;
}

.h-sidebar .widget-title {
	font-size: 20px;
	font-weight: 600;
	margin-bottom: 12px;
}

.h-sidebar ul {
	list-style: none;
	padding: 0;
	margin: 0;
}

.h-sidebar li + li {
	margin-top: 8px;
	padding-top: 8px;
	border-top: 1px solid var(--h-rule);
}


/* ---------------------------------------------------------------------------
 * 12. Footer
 * ------------------------------------------------------------------------ */

.site-footer {
	background-color: var(--h-panel);
	border-top: 1px solid var(--h-rule);
	font-size: 16px;
	padding: 40px 0 30px;
	margin-top: 60px;
}

.site-footer .widget-title {
	font-size: 18px;
	font-weight: 600;
	margin-bottom: 10px;
}

.site-footer ul {
	list-style: none;
	padding: 0;
	margin: 0;
}

.site-info {
	border-top: 1px solid var(--h-rule);
	margin-top: 28px;
	padding-top: 18px;
	font-size: var(--h-fs-small);
}


/* ---------------------------------------------------------------------------
 * 13. Accessibility helpers
 * ------------------------------------------------------------------------ */

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

.skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	background: var(--h-white);
	color: var(--h-blue);
	padding: 10px 16px;
	z-index: 1000;
}

.skip-link:focus {
	left: 8px;
	top: 8px;
}


/* ---------------------------------------------------------------------------
 * 14. Responsive
 *
 * The one size the live site changes by breakpoint is the h2, which drops from 35px to
 * 27px. Both sides of that boundary are worth checking rather than only the mobile side.
 * ------------------------------------------------------------------------ */

@media (max-width: 768px) {
	:root {
		--h-fs-body: 18px;
		--h-fs-h1: 32px;
		--h-fs-h3: 24px;
	}

	h2 { font-size: var(--h-fs-h2-mobile); }

	.site-footer { margin-top: 40px; padding: 30px 0 24px; }
}

@media (max-width: 480px) {
	:root { --h-fs-h1: 28px; }
}

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

/* Smooth scrolling replaces the GeneratePress filter the old snippet used. */
@media (prefers-reduced-motion: no-preference) {
	html { scroll-behavior: smooth; }
}


/* ---------------------------------------------------------------------------
 * 15. Header corrections
 *
 * The logo sits inside the navigation bar, as on the live site, so it needs its own
 * sizing there rather than inheriting the branding block's.
 * ------------------------------------------------------------------------ */

.main-navigation .site-branding {
	flex: 0 0 auto;
	padding-block: 8px;
}

.main-navigation .custom-logo-link,
.main-navigation .navbar-brand {
	display: inline-flex;
	align-items: center;
	color: var(--h-white);
	font-family: var(--h-font-heading);
	font-size: var(--h-fs-h4);
	font-weight: 700;
	text-decoration: none;
	margin: 0;
	padding: 0;
}

.main-navigation .custom-logo {
	/* The desktop size is set in section 57, which is where the reasoning lives.
	   Read that before changing this.

	   Short version, because this rule said 235px for a while and the comment under it argued
	   the case well: live draws the logo 118 by 30 at desktop, on the home page and on an
	   article alike, measured on the bar that is actually visible. 235 by 60 is the intrinsic
	   size of the SVG in this theme and was never a measurement of live.

	   Only the height follows the width here. The width itself is stated per breakpoint, since
	   the phone bar uses a different mark entirely. */
	height: auto;
	max-height: none;
}

/*
 * The heading weight the live site actually renders.
 *
 * The customiser records heading_1_weight as "normal", but the stylesheet overrides it and
 * the site draws headings bold. Matching what is on screen rather than what the setting
 * says, since the screen is the thing being copied.
 */
h1,
.entry-title,
.cloudflare-title {
	font-weight: 700;
}

/*
 * The three column layout does not use .h-container at all: it builds its own full width
 * grid. An earlier attempt to widen the shell for it stripped the padding from every
 * container on the page, footer included, and Bootstrap rows there push 12px past the
 * viewport once that padding is gone. Left alone, both are correct.
 */


/* ---------------------------------------------------------------------------
 * 16. The reading column and its sidebar
 *
 * Measured off the live site rather than guessed. At both 1280 and 1600 the shell caps at
 * 1240, the reading column is 890, the gap is 40 and the advert sidebar is 310.
 *
 * The sidebar is a quarter of the shell, not a fixed 310px. Those two agree only while the
 * shell is capped: below 1280 the shell is the window less its gutters, live's quarter
 * shrinks with it and a fixed 310 does not. Measured, at 834 the reading column here was
 * 444 against live's 555.5, and everything in it inherited the difference. 25% reproduces
 * live at every width, and still resolves to 310 wherever the shell is capped.
 * ------------------------------------------------------------------------ */

:root {
	--h-shell:        1240px;
	--h-sidebar-w:    25%;
	--h-column-gap:   40px;
}

.h-container {
	max-width: calc(var(--h-shell) + (var(--h-gutter) * 2));
}

.h-content-row {
	display: flex;
	flex-direction: column;
	gap: var(--h-column-gap);
}

.h-content-row > .h-main {
	min-width: 0; /* without this a long word in the content sets a floor under the column */
	flex: 1 1 auto;
}

.h-content-row > .h-sidebar {
	flex: 0 0 auto;
	width: 100%;
}

@media (min-width: 992px) {
	.h-content-row {
		flex-direction: row;
		align-items: flex-start;
	}

	.h-content-row > .h-sidebar {
		flex: 0 0 var(--h-sidebar-w);
		width: var(--h-sidebar-w);
	}
}

/* The card grid the [categorypost] shortcode builds fills the reading column. */
.h-main .card-container {
	width: 100%;
}


/* ---------------------------------------------------------------------------
 * 17. Comments
 * ------------------------------------------------------------------------ */

.comments-area {
	margin-top: 48px;
	padding-top: 32px;
	border-top: 1px solid var(--h-rule);
}

.comments-title {
	font-size: 24px;
	margin-bottom: 24px;
}

.comment-list {
	list-style: none;
	padding: 0;
	margin: 0 0 32px;
}

.comment-list .children {
	list-style: none;
	padding-left: 28px;
	margin-top: 16px;
}

.comment-body {
	padding: 16px 0;
	border-bottom: 1px solid var(--h-rule);
	font-size: 16px;
	line-height: 1.65;
}

.comment-meta {
	display: flex;
	align-items: center;
	gap: 10px;
	margin-bottom: 8px;
	font-size: var(--h-fs-small);
}

.comment-author .avatar {
	border-radius: 50%;
}

.comment-metadata,
.comment-metadata a {
	color: var(--h-body-text);
}

.comment-form label {
	display: block;
	font-size: var(--h-fs-small);
	margin-bottom: 4px;
}

.comment-form input[type="text"],
.comment-form input[type="email"],
.comment-form input[type="url"],
.comment-form textarea {
	width: 100%;
	max-width: 100%;
	border: 1px solid var(--h-rule);
	border-radius: var(--h-radius);
	padding: 8px 10px;
	font-family: var(--h-font-body);
	font-size: 16px;
}

.comment-form p { margin-bottom: 14px; }

.comment-respond .comment-reply-title { font-size: 22px; }


/* ---------------------------------------------------------------------------
 * 18. Formulas on a narrow screen
 *
 * The KaTeX display blocks are the widest thing on the site. A five term DuPont
 * decomposition is around 880px of unbreakable maths, and a formula cannot wrap the way a
 * sentence can. On a phone the live site lets those push the article column out to roughly
 * 760px, which drags the surrounding text with them and makes the whole page feel broken
 * even though the maths itself is fine.
 *
 * Each formula gets its own horizontal scroller instead, so it stays readable at full size
 * and the article column keeps the viewport width. This is a fix rather than a copy: the
 * live site does not do it.
 * ------------------------------------------------------------------------ */

.wp-block-katex-display-block,
.katex-display {
	overflow-x: auto;
	overflow-y: hidden;
	max-width: 100%;
	/* Room for the scrollbar so it never sits on top of a denominator. */
	padding-bottom: 4px;
}

/* KaTeX sets this to 100% of its own content, which defeats the scroller above. */
.katex-display > .katex {
	max-width: none;
	text-align: initial;
}

.entry-content .katex {
	max-width: 100%;
}


/* ---------------------------------------------------------------------------
 * 19. The archive card grid
 *
 * Matches the live site: the first card spans the full column, everything after it sits
 * two across. A CSS grid rather than Bootstrap columns, because the cards are printed
 * straight into the centre column of the three column layout, which is a plain block with
 * no row wrapper. Columns need a flex parent, and without one every card collapsed to a
 * quarter of the column width with the rest of the row left empty.
 * ------------------------------------------------------------------------ */

.h-card-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 20px;
	margin-bottom: 20px;
}

.h-card-cell {
	min-width: 0; /* a long unbroken title must not set a floor under the track */
	display: flex;
}

.h-card-cell > .h-card {
	width: 100%;
}

/*
 * The breakpoints are the ones the live site actually uses, measured off it rather than
 * chosen: one card per row below 768, two across from 768, and the lead article only
 * spans the full width from 1025 up. Between 768 and 1024 the reading column is too
 * narrow for a full width lead to be worth the space, and the live site agrees.
 */
@media (min-width: 768px) {
	.h-card-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1025px) {
	.h-card-grid > .h-card-cell:first-child {
		grid-column: 1 / -1;
	}

	/* The lead image is wider, so it is given a shallower ratio to sit in. */
	.h-card-grid > .h-card-cell:first-child .h-card__media {
		aspect-ratio: 2 / 1;
	}

	.h-card-grid > .h-card-cell:first-child .h-card__title {
		font-size: 30px;
	}
}

/* Only the lead article carries its opening lines, on a category list
   -------------------------------------------------------------------------
   Held to .archive on purpose. Search results use the same grid, and there
   the opening lines are the whole point: somebody scanning fifty results is
   reading them to decide which one they want. Without the scope this took
   them off the search page too.
   The live site shows the excerpt on the first card and not on the ones below
   it, which is what keeps a row of cards the same height and the page short
   enough to scan. Every card prints one, because the template cannot know
   which of them the grid will make the lead, so the rest are hidden here.

   Below 1025 there is no lead card, since the grid stops giving the first one
   the full width, so no card shows an excerpt there either. */
.archive .h-card-grid .h-card__excerpt {
	display: none;
}

@media (min-width: 1025px) {
	.archive .h-card-grid > .h-card-cell:first-child .h-card__excerpt {
		display: block;
	}
}

/* The byline sits between the title and the rest, so it needs a little air
   rather than the gap the excerpt used to supply. */
.h-card__meta {
	margin: 2px 0 10px;
}

/*
 * Card titles follow the live site: Roboto at 30px for the lead, 22px for the rest. The
 * heading face is Barlow everywhere else, but the article lists are set in the body face.
 */
.h-card__title {
	font-family: var(--h-font-body);
	font-size: 22px;
	font-weight: 600;
}

/* Read more, which the live cards carry and this build was missing. */
.h-card__more {
	display: block;
	width: 100%;
	margin-top: 14px;
	padding: 8px 0;
	border: none;
	border-radius: 3px;
	background: var(--h-green);
	color: var(--h-off-white);
	font-size: 16px;
	text-align: center;
	text-decoration: none;
}

.h-card__more:hover,
.h-card__more:focus {
	background: #005e3f;
	color: var(--h-white);
	text-decoration: none;
}


/* ---------------------------------------------------------------------------
 * 20. Third level navigation
 *
 * The menu is three levels deep. Bootstrap has no nested dropdown, so the third level is
 * opened here: on a wide screen it flies out to the side of its parent, and inside the
 * mobile collapse it simply indents, because a flyout on a touch screen means the parent
 * item can never be tapped.
 * ------------------------------------------------------------------------ */

.main-navigation .dropdown-submenu-parent {
	position: relative;
}

/* The arrow on a submenu entry that opens a further level.
   -------------------------------------------------------------------------
   This was a solid triangle built out of borders, 4px by 8px. The site this
   replaces draws the same thin chevron it uses on the top level entries,
   turned to point right. A filled triangle and a thin chevron read as two
   different pieces of furniture sitting in the same menu, which is what was
   spotted.

   Same SVG as the top level arrow above, masked so it takes the text colour,
   rotated a quarter turn. 10px rather than 14, because a second level entry is
   smaller than a top level one and the arrow should sit below the label in
   weight rather than next to it. */
/* The entry itself is the row, so the arrow can be centred on the words and
   pushed to the right edge rather than trailing the text by a fixed gap. All
   three were asked for after the first pass: the arrow sat high against a
   short label like ACCA, it was a different size from the one pointing down,
   and it followed the word instead of lining up with the others. */
.main-navigation .dropdown-menu .dropdown-submenu-toggle {
	display: flex;
	align-items: center;
	gap: .75em;
}

.main-navigation .dropdown-submenu-toggle::after {
	content: "";
	flex: 0 0 auto;
	/* Pushed to the right edge of the entry, so a column of them lines up. */
	margin: 0 0 0 auto;
	/* The same size as the arrow on the level above, which is what the live
	   site does: one icon, set in the text size wherever it appears. */
	width: 1em;
	height: 1em;
	border: 0;
	transform: rotate(-90deg);
	background-color: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 330 512'%3E%3Cpath d='M305.913 197.085c0 2.266-1.133 4.815-2.833 6.514L171.087 335.593c-1.7 1.7-4.249 2.832-6.515 2.832s-4.815-1.133-6.515-2.832L26.064 203.599c-1.7-1.7-2.832-4.248-2.832-6.514s1.132-4.816 2.832-6.515l14.162-14.163c1.7-1.699 3.966-2.832 6.515-2.832 2.266 0 4.815 1.133 6.515 2.832l111.316 111.317 111.316-111.317c1.7-1.699 4.249-2.832 6.515-2.832s4.815 1.133 6.515 2.832l14.162 14.163c1.7 1.7 2.833 4.249 2.833 6.515z'/%3E%3C/svg%3E") center / 1em 1em no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 330 512'%3E%3Cpath d='M305.913 197.085c0 2.266-1.133 4.815-2.833 6.514L171.087 335.593c-1.7 1.7-4.249 2.832-6.515 2.832s-4.815-1.133-6.515-2.832L26.064 203.599c-1.7-1.7-2.832-4.248-2.832-6.514s1.132-4.816 2.832-6.515l14.162-14.163c1.7-1.699 3.966-2.832 6.515-2.832 2.266 0 4.815 1.133 6.515 2.832l111.316 111.317 111.316-111.317c1.7-1.699 4.249-2.832 6.515-2.832s4.815 1.133 6.515 2.832l14.162 14.163c1.7 1.7 2.833 4.249 2.833 6.515z'/%3E%3C/svg%3E") center / 1em 1em no-repeat;
}


@media (min-width: 992px) {
	.main-navigation .dropdown-menu.dropdown-submenu {
		position: absolute;
		top: 0;
		left: 100%;
		margin: 0;
		display: none;
	}

	.main-navigation .dropdown-submenu-parent:hover > .dropdown-menu.dropdown-submenu,
	.main-navigation .dropdown-submenu-parent:focus-within > .dropdown-menu.dropdown-submenu {
		display: block;
	}

	/* Near the right edge there is no room to fly out, so it goes the other way. */
	.main-navigation .nav-item:nth-last-child(-n+3) .dropdown-menu.dropdown-submenu {
		left: auto;
		right: 100%;
	}
}

@media (max-width: 991.98px) {
	.main-navigation .dropdown-menu.dropdown-submenu {
		display: block;
		position: static;
		padding-left: 16px;
		background: transparent;
	}

	.main-navigation .dropdown-submenu-toggle::after {
		display: none;
	}

	/* Inside the collapse every level is shown, so the menu is one scrollable list. */
	.main-navigation .navbar-collapse .dropdown-menu {
		display: block;
		position: static;
		float: none;
		width: 100%;
	}
}


/* ---------------------------------------------------------------------------
 * 21. Editable regions
 *
 * These only appear when somebody fills the matching field in, so on a site with nothing
 * entered none of this ever renders.
 * ------------------------------------------------------------------------ */

.entry-standfirst {
	font-size: 1.05em;
	color: var(--h-ink-2, var(--h-body-text));
	margin-bottom: 1.5em;
	padding-left: 16px;
	border-left: 3px solid var(--h-green);
}

.entry-standfirst p:last-child { margin-bottom: 0; }

.entry-cta {
	margin-top: 40px;
	padding: 26px 28px;
	background-color: var(--h-panel);
	border: 1px solid var(--h-rule);
	border-radius: var(--h-radius);
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 12px;
}

.entry-cta__heading {
	font-size: 24px;
	margin: 0;
}

.entry-cta__text {
	margin: 0;
	font-size: 17px;
}

.footer-note {
	flex: 1 1 100%;
	font-size: var(--h-fs-small);
	margin-bottom: 8px;
}

.footer-note p:last-child { margin-bottom: 0; }

.footer-social a { color: inherit; }


/* ---------------------------------------------------------------------------
 * 22. Details the framework reset away
 *
 * Bootstrap normalises a few things the site relies on. These put them back to what the
 * live site renders, checked with getComputedStyle rather than by eye.
 * ------------------------------------------------------------------------ */

/* Pull quotes inside articles are italic on the live site. Bootstrap resets that. */
.entry-content blockquote,
.cloudflare-content blockquote {
	font-style: italic;
}

/* The block editor button keeps its own pill shape. */
.entry-content .wp-block-button__link {
	line-height: inherit;
}


/* ---------------------------------------------------------------------------
 * 23. Meta separators
 *
 * One separator between items, drawn by the stylesheet rather than printed into the
 * markup, so a screen reader reads "Zee Tan, 27 August 2026, 3" rather than announcing a
 * bullet between each.
 *
 * The carried over stylesheet puts its own separator after the byline. That is switched
 * off here, otherwise the two appear together and the line reads with a doubled dot.
 * ------------------------------------------------------------------------ */

.entry-meta .byline::after {
	content: none;
}

/* The separator itself, and why it lives here rather than where it was written
   -------------------------------------------------------------------------
   These two rules were in inc/global-ads-single.css, next to the rest of the
   agreed scheme. That file is only loaded when the global ads layout is active,
   which is true on articles, category archives and the exam lists, and false on
   search results.

   So search results had the rule above switching the carried-over separator off
   and nothing putting ours back. Every search result read "Sophie Macon05 Oct
   2026CFA, How To Study": no dot, and no space either, because the gap was
   coming from the dot's own margins. Measured at 0.0px between the author and
   the date on every card.

   A separator between an author and a date is typography, not advert layout, so
   it belongs in the stylesheet that loads on every page. Moved rather than
   copied: a second copy is what put two dots on the exam lists once already,
   and the note in that file says so in as many words.

   The exam lists are still untouched. They draw their own ::after on each item
   and are not matched by either selector here. */

body:not(.single) .entry-meta .byline::after {
	content: "∙";
	/* Space on both sides. With it only on the left the dot leaned against the
	   date instead of sitting between the two, which is what was reported as
	   the separator being aligned left. */
	margin-left: .35em;
	margin-right: .35em;
}

body:not(.single) .entry-meta > a:not(:last-child)::after {
	content: "∙";
	margin: 0 .35em;
}

/* Dots between the items of a byline, on an article page only.
   -------------------------------------------------------------------------
   Held to a single post deliberately. The article lists already draw their own
   separator, as an ::after on each item, and that scheme is the one that was
   agreed: a dot after the author, and a dot after the date only when a comment
   count follows it, so an article nobody has replied to does not end on a
   stray dot. Drawing a ::before here as well put two dots between every field
   on every list. The note in inc/global-ads-single.css records the same thing
   happening once before. */
body.single .entry-meta > * + *::before {
	content: "\2219";
	margin: 0 7px;
	color: var(--h-body-text);
	opacity: .6;
}

/* The separator sits in the middle of the gap, not against the word after it.
   -------------------------------------------------------------------------
   It was drawn with space on its left and none on its right, so it leaned
   against the date rather than sitting between the two. Reported as the dot
   being aligned left, which is exactly what it was.

   The size is stated rather than inherited, because the element it hangs off
   is set to font-size 0 elsewhere to kill a stray text node, and a dot at zero
   pixels is a dot nobody can see. */
/* The dot in front of the last item on the line.
   -------------------------------------------------------------------------
   The scheme in inc/global-ads-single.css puts a dot after the author and
   after a link that has something following it. The date is a time element
   and the categories are last, so neither of those rules reaches the gap
   between them and it closed up entirely.

   The size is stated rather than inherited, because the element this hangs
   off is set to font-size 0 elsewhere to kill a stray text node, and a dot at
   zero pixels is a dot nobody can see. */
body:not(.single) .entry-meta > .entry-categories::before {
	content: "\2219";
	margin: 0 .35em;
	font-size: 14px;
	color: var(--h-body-text);
}

.entry-meta > a.comments-link::before {
	font-size: 14px;
}

.wp-show-posts .wp-show-posts-entry-meta > *::after {
	margin-left: .4em;
	margin-right: .4em;
}

/* The one gap in the agreed scheme. It puts a dot after the author and after a
   link that has something following it, which covers the date, but the comment
   count is the last item and so never gets one in front of it. */
body:not(.single) .entry-meta > a.comments-link::before {
	content: "\2219";
	margin: 0 .35em;
	color: var(--h-body-text);
	opacity: .6;
}

/* Each item is inline so the separators sit on the same line as the text. */
.entry-meta > * {
	display: inline;
}

/* Long unbroken strings in article copy and in comments
   -------------------------------------------------------------------------
   Readers paste bare URLs into comments and they are rendered as their own
   link text. With nothing telling them to break, one measured 993px inside a
   390px screen and pushed the whole page sideways at every width below 1280.
   The article body has the same exposure wherever a long URL appears in the
   copy.

   GeneratePress set overflow-wrap on .entry-content and .comments-area, and
   that is what kept them in bounds, so the same rule is carried over. Capping
   a width or hiding the overflow would cut the text off instead of wrapping
   it. */
.entry-content,
.entry-content p,
.entry-content li,
.entry-content a,
.entry-content dd,
.entry-content td,
.comments-area,
.comment-content,
.comment-content p,
.comment-content a,
.comment-metadata,
.comment-metadata a {
	overflow-wrap: break-word;
}

/* Sidebar offer card and exam calendar
   -------------------------------------------------------------------------
   These two blocks replace the Affiliate Coupons and Simple Calendar plugins.
   The measurements are taken from the live site's rendering rather than
   invented, so the sidebar keeps the proportions it was designed around:
   310px column, 6px corners, the same green button and the same dashed code
   box.

   The card is a flex column with the button pinned to the bottom, so two
   cards of different description lengths still finish level. */

.th-offer {
	position: relative;
	display: flex;
	flex-direction: column;
	background: #fff;
	border-radius: 6px;
	overflow: hidden;
	box-shadow: 0 1px 3px rgba(0, 0, 0, .2), 0 1px 1px rgba(0, 0, 0, .14), 0 2px 1px -1px rgba(0, 0, 0, .12);
}

.th-offer + .th-offer {
	margin-top: 20px;
}

.th-offer__header {
	position: relative;
	line-height: 0;
}

.th-offer__header--nomedia {
	line-height: normal;
	padding: 20px 20px 0;
}

.th-offer__thumbnail {
	display: block;
}

.th-offer__image {
	display: block;
	width: 100%;
	height: auto;
}

/* The corner flash sits slightly outside the card, which is what gives it the
   stuck-on look rather than looking like part of the image. */
.th-offer__badge {
	position: absolute;
	top: 8px;
	left: 0;
	background: #8a75d9;
	color: #fff;
	font-size: 16px;
	line-height: 1.2;
	padding: 8px 13px 6px;
	border-radius: 0 3px 3px 0;
	white-space: nowrap;
}

.th-offer__badge--inline {
	position: static;
	display: inline-block;
	border-radius: 3px;
}

.th-offer__content {
	padding: 20px;
	flex: 1 1 auto;
}

.th-offer__title {
	display: block;
	font-family: var(--h-font-heading, "Barlow", sans-serif);
	font-size: 20px;
	line-height: 26px;
	font-weight: 700;
	color: #212121;
	text-decoration: none;
}

.th-offer__title:hover,
.th-offer__title:focus {
	text-decoration: underline;
}

.th-offer__brand {
	margin-top: 6px;
	font-size: 14px;
	font-weight: 700;
	color: rgba(0, 0, 0, .54);
}

.th-offer__description {
	margin-top: 10px;
	font-size: 16px;
	line-height: 25.6px;
	color: #616161;
}

.th-offer__code {
	margin-top: 15px;
}

/* A button rather than a div, because it is genuinely clickable and has to be
   reachable from the keyboard. */
.th-offer__copy {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	width: 100%;
	padding: 6px 12px;
	background: #e6e9f7;
	border: 2px dashed #d2d5e3;
	border-radius: 3px;
	cursor: pointer;
	text-align: left;
}

.th-offer__code-text {
	font-family: var(--h-font-heading, "Barlow", sans-serif);
	font-size: 14px;
	font-weight: 700;
	color: #616161;
	word-break: break-all;
}

.th-offer__code-hint {
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .04em;
	color: #8a8f9e;
	flex: 0 0 auto;
}

.th-offer__copy.is-copied {
	border-style: solid;
	border-color: #009966;
}

.th-offer__copy.is-copied .th-offer__code-hint {
	color: #009966;
}

/* The discount code has to stay readable while the pointer is on it
   -------------------------------------------------------------------------
   Hovering this control painted it a solid green and left the code and the
   word "Copy" in the greys they use against the pale background they normally
   sit on. Measured on an offer panel: the code dropped to 1.09 to 1 and the
   hint to 1.18 to 1, which is invisible. The button's own colour did turn
   white, so anything reading the button rather than the two spans inside it
   saw nothing wrong. That is the same shape as the guide button that had green
   behind its words, and it is worth remembering that a button and its label
   are two different elements with two different colours.

   The practical version: the code disappeared at the exact moment somebody put
   the pointer on it in order to copy it.

   The green is also set here rather than inherited, so this control matches the
   darker green every other button on the site now uses on hover. The copied
   state is covered too: its hint is green, which would be just as unreadable
   against a green button. */

.th-offer__copy:hover,
.th-offer__copy:focus-visible {
	background: #005e3f;
	border-color: #005e3f;
	color: #fff;
}

.th-offer__copy:hover .th-offer__code-text,
.th-offer__copy:hover .th-offer__code-hint,
.th-offer__copy:focus-visible .th-offer__code-text,
.th-offer__copy:focus-visible .th-offer__code-hint,
.th-offer__copy.is-copied:hover .th-offer__code-hint,
.th-offer__copy.is-copied:focus-visible .th-offer__code-hint {
	color: #fff;
}

.th-offer__footer {
	padding: 0 20px 20px;
	margin-top: auto;
}

.th-offer__button {
	display: block;
	width: 100%;
	padding: 11px 15px;
	background: #009966;
	color: #fff;
	font-size: 16px;
	font-weight: 700;
	line-height: 1.4;
	text-align: center;
	text-transform: uppercase;
	text-decoration: none;
	border-radius: 5px;
}

.th-offer__button:hover,
.th-offer__button:focus {
	background: #006a3b;
	color: #fff;
}

/* Exam calendar
   ------------------------------------------------------------------------- */

.th-calendar__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.th-calendar__item {
	display: flex;
	align-items: flex-start;
	gap: 14px;
	padding: 12px 0;
	border-bottom: 1px solid #eceff1;
}

.th-calendar__item:first-child {
	padding-top: 0;
}

.th-calendar__item:last-child {
	border-bottom: 0;
	padding-bottom: 0;
}

/* Fixed width so the titles line up down the column whatever the date is. */
.th-calendar__date {
	flex: 0 0 48px;
	text-align: center;
	line-height: 1.1;
	padding-top: 2px;
}

.th-calendar__day {
	display: block;
	font-family: var(--h-font-heading, "Barlow", sans-serif);
	font-size: 22px;
	font-weight: 700;
	color: #212121;
	font-variant-numeric: tabular-nums;
}

.th-calendar__month {
	display: block;
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .06em;
	color: #009966;
}

.th-calendar__year {
	display: block;
	font-size: 11px;
	color: #90a4ae;
	font-variant-numeric: tabular-nums;
}

.th-calendar__title {
	font-size: 15px;
	line-height: 22px;
	color: #616161;
}

.th-calendar__title a {
	color: inherit;
}

.th-calendar__empty,
.th-calendar__more {
	margin: 0;
	font-size: 15px;
	color: #78909c;
}

.th-calendar__more {
	margin-top: 12px;
}

/* Header geometry, measured off the live site
   -------------------------------------------------------------------------
   Three things here were wrong and all three are visible.

   1. The header is not as wide as the content below it. The content shell caps
      at 1240, the header caps at 1200, so the logo sits 20px in from the
      reading column's left edge rather than flush with it. Measured on live at
      a 1920 window: reading column starts at 333, logo at 353, menu at 470,
      header container ends at 1553.

   2. The flex gap put 16px between the logo and the first menu item. On live
      the menu begins at exactly the logo's right edge, no gap at all.

   3. The logo is the same SVG on both sites, but live draws it 30px tall, not
      at its natural 60. Height is set rather than width so the ratio is kept
      whatever the file becomes later. That in turn gives the 60px bar live
      has, rather than 69px. */

.main-navigation > .h-container {
	max-width: calc(1200px + (var(--h-gutter) * 2));
	gap: 0;

	/* The row has to be allowed to wrap. Without this the collapsed menu cannot drop
	   onto its own line below the logo, and Bootstrap squeezes it into whatever space is
	   left beside the logo instead. Opened at 390 it came out 168px wide with not a
	   single menu item visible. */
	flex-wrap: wrap;
}

.site-branding img,
.custom-logo {
	width: 176px;
	height: auto;
}

/* The menu sits against the logo and the search follows straight after the last
   item, exactly as live has it. Neither an auto margin on the left (which would
   shove the menu right) nor one on the right (which would strand the search out
   at the far edge). The spare room simply falls at the end. */
.main-navigation .navbar-nav {
	margin-left: 0;
	margin-right: 0;
}

@media (min-width: 992px) {

	/* Desktop only. Below the collapse breakpoint the panel needs Bootstrap's own
	   flex-basis:100% and grow to take a full row of its own. */
	.main-navigation .navbar-collapse {
		flex-grow: 0;
	}
}

/* Nav bar height, taken from how live builds it
   -------------------------------------------------------------------------
   Live does not pad the links to make the bar tall. It sets line-height to the
   full bar height, 60px, and pads only on the left by 15px. Building the same
   height out of vertical padding gets close but not equal, which is why the bar
   was 55px here against 60px there.

   Desktop only. Below the collapse breakpoint the menu is a stacked panel and a
   60px line box would space it out wrongly, so the existing rules stand. */

@media (min-width: 992px) {

	.main-navigation .navbar-nav > .nav-item > .nav-link {
		padding: 0 0 0 15px;
		line-height: 60px;
	}

	.main-navigation .navbar-nav > .nav-item > .nav-link.dropdown-toggle {
		padding-right: 0;
	}
}

/* Restore the mobile menu that the ported stylesheet hides
   -------------------------------------------------------------------------
   legacy.css carries this, straight from GeneratePress:

       @media (max-width: 1020px) { .main-navigation ul, .gen-sidebar-nav { display: none } }

   That is correct for GeneratePress, which swaps the menu for its own slide-out
   panel below 1020. This theme uses Bootstrap's collapse instead, so the rule
   silently emptied the mobile menu: tapping the hamburger opened a full width
   panel containing nothing but the search box, at every width up to 1020.

   Scoped to the menu inside the collapse so the legacy rule still governs
   anything else it was written for. */

@media (max-width: 1020px) {

	.main-navigation .navbar-collapse .navbar-nav {
		display: flex;
	}
}

/*
 * The stacked submenu has to stop where the collapse stops, not at 1020. The bar
 * is navbar-expand-lg, so the desktop menu appears at 992, but this block ran to
 * 1020: between those two widths the desktop menu was on screen while its
 * submenus were still being told to sit in the flow at full width. Opening one
 * there tore the header open from 60px to just over 600 and shoved every item
 * after it 84px to the right. The two thresholds now agree.
 *
 * The rule above still runs to 1020, and has to. legacy.css hides
 * .main-navigation ul all the way up to 1020, so narrowing that one as well
 * would blank the desktop menu across the very band it just stopped tearing.
 */
@media (max-width: 991.98px) {

	/* Submenus stay in the flow on a phone rather than floating, so a parent item
	   and its children read as one list. */
	.main-navigation .navbar-collapse .dropdown-menu {
		position: static;
		float: none;
		width: 100%;
	}
}

/* The second header layout, the one live uses on hubs and articles
   -------------------------------------------------------------------------
   The block above sets the contained header: 1200px, logo at its left edge.
   That is right for the home page, the blog, search and the 404, and wrong
   for everything else, because live runs a second layout on singular content.

   There the container is not capped at all. It spans the window and the logo
   and menu are centred together as one group, so the logo moves inward as the
   window widens rather than staying pinned to a 1200px column. Measured on
   live in a 1600px frame: contained pages put the logo at 192, singular pages
   put it at 316, and the bar is the same 60px tall on both.

   Only the horizontal rule changes. Height, logo size, link padding and the
   collapse behaviour are shared, which is why this is a two property override
   rather than a second copy of the header. */
body.th-nav-full .main-navigation > .h-container {
	max-width: 100%;
	justify-content: center;
}

@media (max-width: 991.98px) {

	/* Below the collapse point the group is no longer a row of logo and menu,
	   it is a logo with a toggle opposite it. Centring that would pull the two
	   together into the middle and leave the ends empty, so the contained
	   behaviour is kept and only the cap is lifted. Live does the same. */
	body.th-nav-full .main-navigation > .h-container {
		justify-content: flex-start;
	}
}

/* The dropdown arrow, and the width it is supposed to occupy
   -------------------------------------------------------------------------
   Every top level menu item came out 27px narrower here than on live, which
   over five items dragged the whole menu 108px out of position. The text was
   never the problem: measured on both, "Articles" is 49px of type in each
   case. The gap was entirely the arrow.

   Live gives the arrow a block of its own 39px wide: a 14px chevron with 10px
   between it and the word and 15px after it, which is where the item's right
   hand breathing room comes from. Bootstrap's built in caret is a 8px CSS
   triangle with a 3.57px margin, so 11.6px, and it carries no trailing space
   at all.

   The chevron is live's own path rather than an approximation, painted through
   a mask so it takes the link colour and keeps taking it on hover and on the
   current item. Bootstrap draws its caret out of borders, so those have to be
   cleared or the triangle sits inside the mask box.

   Items without a submenu have no arrow to supply that trailing 15px, so they
   are given it directly. Offers was 54px here against 69px on live, which is
   exactly the missing pair of 15s minus the arrow it never had. */
.main-navigation .navbar-nav > .nav-item > .nav-link.dropdown-toggle::after {
	content: "";
	display: inline-block;
	width: 14px;
	height: 14px;
	margin: 0 15px 0 10px;
	border: 0;
	vertical-align: middle;
	background-color: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 330 512'%3E%3Cpath d='M305.913 197.085c0 2.266-1.133 4.815-2.833 6.514L171.087 335.593c-1.7 1.7-4.249 2.832-6.515 2.832s-4.815-1.133-6.515-2.832L26.064 203.599c-1.7-1.7-2.832-4.248-2.832-6.514s1.132-4.816 2.832-6.515l14.162-14.163c1.7-1.699 3.966-2.832 6.515-2.832 2.266 0 4.815 1.133 6.515 2.832l111.316 111.317 111.316-111.317c1.7-1.699 4.249-2.832 6.515-2.832s4.815 1.133 6.515 2.832l14.162 14.163c1.7 1.7 2.833 4.249 2.833 6.515z'/%3E%3C/svg%3E") center / 14px 14px no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 330 512'%3E%3Cpath d='M305.913 197.085c0 2.266-1.133 4.815-2.833 6.514L171.087 335.593c-1.7 1.7-4.249 2.832-6.515 2.832s-4.815-1.133-6.515-2.832L26.064 203.599c-1.7-1.7-2.832-4.248-2.832-6.514s1.132-4.816 2.832-6.515l14.162-14.163c1.7-1.699 3.966-2.832 6.515-2.832 2.266 0 4.815 1.133 6.515 2.832l111.316 111.317 111.316-111.317c1.7-1.699 4.249-2.832 6.515-2.832s4.815 1.133 6.515 2.832l14.162 14.163c1.7 1.7 2.833 4.249 2.833 6.515z'/%3E%3C/svg%3E") center / 14px 14px no-repeat;
}

@media (min-width: 992px) {

	.main-navigation .navbar-nav > .nav-item > .nav-link:not(.dropdown-toggle) {
		padding-right: 15px;
	}
}

/* Which typeface each heading is actually set in
   -------------------------------------------------------------------------
   The build put Barlow on every heading. Live does not do that. Live uses
   Barlow in exactly two places, the navigation and the page title, and sets
   everything else in Roboto: the subheadings inside an article, the card
   titles on the listings, the sidebar widget titles and the comments heading.
   Measured on live, an article's h2 is Roboto and its h1 is barlowbold, which
   is why the page title is left alone here.

   The token itself is not touched, because the navigation reads it and the
   navigation genuinely is Barlow. These are the places that are not.

   Sizes and spacing come from the same measurements and are corrected in the
   same pass, since a heading in the wrong face at the wrong size is one fault
   to a reader, not two. */
.entry-content h2,
.entry-content h3,
.entry-content h4,
.entry-content h5,
.entry-content h6,
.widget-title,
.comments-title,
.wp-show-posts-entry-title,
.inner-post-card h2,
.card h2,
.card h3 {
	font-family: var(--h-font-subhead, "Roboto", "Helvetica Neue", Arial, sans-serif);
}

/* Live opens the space under a subheading, not above it. The build had 52.5px
   on both sides, which pushed every section down by an extra line and made an
   article measurably longer than the same article on live. */
.entry-content h2 {
	margin-top: 0;
}

.entry-content h3 {
	font-size: 29px;
	font-weight: 400;
	line-height: 43.5px;
	margin-top: 0;
	margin-bottom: 43.5px;
}

/* The sidebar widget headings were rendering at the base h2 size, 35px, which
   is nearly twice what live sets and made the sidebar shout over the article
   beside it. The rule meant to catch them was written for .h-sidebar, and the
   sidebar on this build is .cloudflare-right, so it never matched anything. */
.widget-title {
	font-size: 20px;
	font-weight: 400;
	line-height: 30px;
	margin-top: 0;
	margin-bottom: 30px;
}

.comments-title {
	font-size: 20px;
	font-weight: 700;
	line-height: 30px;
	margin-top: 0;
	margin-bottom: 20px;
}

/* Card titles on the listings. The face was wrong above; the gap under the
   title was 8px against live's 20px, which ran the title into its excerpt. */
.wp-show-posts-entry-title,
.inner-post-card h2 {
	margin-bottom: 20px;
}

/* The footer is a blue bar, not a white panel
   -------------------------------------------------------------------------
   The build gave the footer the light panel colour and left the link colour
   where it had been when the panel behind it was blue. The result was
   rgb(187,222,251) on rgb(247,248,249): a contrast ratio of 1.32 to 1 against
   a 4.5 requirement, which in practice means the footer menu is not readable
   at all. Every link in it was affected.

   Live paints the bar in the site blue and sets the links near white, so the
   fix is to put the background back rather than to invent a darker blue for
   the text. Measured on live: background rgb(25,118,210), links rgb(250,250,250)
   at 15px Roboto. */
.site-footer {
	background-color: var(--h-blue);
	border-top: 0;
	color: var(--h-off-white);
}

.site-footer a {
	font-size: 15px;
	line-height: 27px;
	font-family: var(--h-font-subhead, "Roboto", "Helvetica Neue", Arial, sans-serif);
}

/*
 * Live splits the two levels rather than colouring them alike: the column
 * heading is near white and bold, the links under it are the pale blue. That
 * pale blue was never the problem. On the blue bar it clears 4.5 to 1
 * comfortably; it only failed when the bar behind it had been turned white.
 */
.site-footer .footer-bar-widgets .menu > li > a {
	color: #fafafa;
	font-weight: 700;
}

.site-footer .footer-bar-widgets .sub-menu a {
	color: #bbdefb;
	font-weight: 400;
}

/*
 * Three columns along the bottom right, which is how live lays this menu out.
 * The build stacked every item in one tall list instead, so the footer came out
 * around 350px deep against live's 126.
 */
.site-footer .footer-bar-widgets .menu {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: 0;
	text-align: right;
}

.site-footer .footer-bar-widgets .menu > li {
	width: 136px;
}

.site-footer .footer-bar-widgets .sub-menu {
	display: block;
	margin: 5px 0 0 15px;
	padding: 0;
}

.site-footer a:hover,
.site-footer a:focus {
	color: #fff;
	text-decoration: underline;
}

.site-footer,
.site-footer p,
.site-footer .site-info {
	color: #fafafa;
}


/* The sidebar comes alongside at 769, as it does on live
   -------------------------------------------------------------------------
   This was switching at 992, so between 769 and 991 a tablet reader got the
   phone layout: the entire ad rail dumped below the article instead of beside
   it, for a 223px band. Live goes side by side at 769 and so does the old
   build, which is how the difference was isolated to the rebuild rather than
   to the content. */
@media (min-width: 769px) {
	.h-content-row {
		flex-direction: row;
		align-items: flex-start;
	}

	.h-content-row > .h-sidebar {
		flex: 0 0 var(--h-sidebar-w);
		width: var(--h-sidebar-w);
	}
}


/* The header stays with the reader
   -------------------------------------------------------------------------
   Live's navigation sticks to the top of the window once it is scrolled past.
   That came from a plugin module this build drops, so it is rebuilt here.

   Sticky rather than fixed, deliberately: fixed takes the bar out of the flow
   and needs a spacer element behind it to stop the page jumping upward by the
   bar's own height at the moment it engages. Sticky keeps the bar in the flow
   and there is nothing to compensate for.

   The admin bar has to be accounted for or the navigation sits underneath it
   for a signed in user. WordPress fixes that bar at 32px from 783 up, at 46px
   between 601 and 782, and lets it scroll away below 601, so the offset
   follows the same three cases. */
.main-navigation {
	position: sticky;
	top: 0;
	z-index: 100;
}

body.admin-bar .main-navigation {
	top: 32px;
}

@media (max-width: 782px) {
	body.admin-bar .main-navigation {
		top: 46px;
	}
}

@media (max-width: 600px) {
	body.admin-bar .main-navigation {
		top: 0;
	}
}


/* Tap targets in the header
   -------------------------------------------------------------------------
   The hamburger was 50 by 34, under the 44px minimum on the axis that matters
   for a thumb, and well under live's own 54 by 60. The items inside the opened
   panel were 43.6px against live's 60, and the search field in there was 31px
   tall, which is difficult to hit and looks wrong beside the items above it. */
.main-navigation .navbar-toggler {
	min-width: 54px;
	min-height: 48px;
	padding: 4px 12px;
}

@media (max-width: 991.98px) {

	.main-navigation .navbar-collapse .navbar-nav > .nav-item > .nav-link {
		min-height: 48px;
		display: flex;
		align-items: center;
	}

	.main-navigation .nav-search__toggle,
	.main-navigation .nav-search__form input[type="search"],
	.main-navigation .nav-search__form input[type="text"] {
		min-height: 44px;
	}
}


/* Contrast on three small pieces of text
   -------------------------------------------------------------------------
   All three are the theme's own, none exist on live, and each was under the
   4.5 to 1 needed at its size. The year under a calendar entry was 2.59, the
   word Copy beside an offer code 2.67, and Read more on a card 3.5 because the
   near white sat on the mid green rather than on something darker. */
.th-calendar__year {
	color: #546e7a;
}

.th-offer__code-hint {
	color: #4a5164;
}

.h-card__more {
	background: #007a52;
	color: #fff;
}


/* The offer artwork is capped once the sidebar stacks
   -------------------------------------------------------------------------
   In the rail the card is 310px wide and the image is bounded by the column.
   Once the rail drops below the article the card has the full reading width to
   fill, and it filled it: at 1024 the image rendered 994 by 745 against live's
   400 by 225, two and a half times as wide and three times as tall, and in 4:3
   rather than 16:9 because the box no longer constrained it.

   Live caps the card at 400 and centres it, so the same is done here, and only
   below the width at which the rail returns to the side. */
@media (max-width: 991.98px) {

	.h-content-row > .h-sidebar .th-offer,
	.h-sidebar .th-offer {
		max-width: 400px;
		margin-left: auto;
		margin-right: auto;
	}

}


/* The listing pagination matches the search pagination
   -------------------------------------------------------------------------
   .h-pagination was already built to a 44px minimum. The listings use the
   ported .pagination markup instead, which came in at 42px tall, so the same
   floor is applied there. */
.pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
}

/* Footer depth
   -------------------------------------------------------------------------
   With the columns laid out correctly the bar was still 223px deep against
   live's 126. The rest was the build's own padding and the 60px it pushed the
   footer away from the content. Live sets neither: the bar is 40px of padding
   around an 86px block, and it begins where the content ends. */
.site-footer {
	padding: 20px 0;
	margin-top: 0;
}

@media (max-width: 768px) {
	.site-footer {
		margin-top: 0;
		padding: 20px 0;
	}
}

/* The last 67px of it were the inner row's own spacing: a 28px top margin and
   18/20px of padding on .site-info, which live does not have at all. Its
   equivalent row is flush, and the only breathing room in the bar is the
   padding on the bar itself.

   The border has to go with them. .site-info carries a top rule for its use
   elsewhere on the site, and zeroing only the margin and padding left that rule
   drawn hard against the content with no space around it: a pale grey line
   across a blue bar, stopping at the container edge rather than spanning it.
   Live has no rule here at all. */
.site-footer .site-info {
	margin-top: 0;
	padding: 0;
	border-top: 0;
}

/* The phone bar, laid out the way live lays it out
   -------------------------------------------------------------------------
   Measured on live at 390 (375 of usable width): the toggle runs 0 to 54 hard
   against the left edge, the square 3H mark 64 to 117, and the search icon sits
   at the right hand end, 331 to 375. The bar is 60px tall, the same as it is on
   a desktop.

   This build had the wordmark at 118px wide, the toggle pushed over to 301 on
   the right, and no search in the bar at all. The wordmark is the reason the
   rest could not fit: at 118px it takes a third of the bar on its own. */
@media (max-width: 991.98px) {

	/* Flush to both edges, as live is. The gutter belongs to the content, not
	   to this bar. */
	.main-navigation > .h-container {
		padding-left: 0;
		padding-right: 0;
		flex-wrap: wrap;
	}

	.main-navigation .navbar-toggler {
		width: 54px;
		min-width: 54px;
		height: 60px;
		min-height: 60px;
		padding: 0;
		margin: 0;
		border: 0;
		display: inline-flex;
		align-items: center;
		justify-content: center;
	}

	.main-navigation .site-branding {
		margin-left: 10px;
		margin-right: auto;
		padding-block: 0;
	}

	/* One mark or the other, never both. */
	.main-navigation .custom-logo-link,
	.main-navigation .site-title-link {
		display: none;
	}

	.main-navigation .site-mark {
		display: inline-flex;
		align-items: center;
	}

	.main-navigation .site-mark img {
		height: 60px;
		width: auto;
		max-height: 60px;
	}

	/* Flush to the right edge, where live has it: measured on live the icon runs
	   331 to 375 in a 375 wide bar. */
	.main-navigation .nav-search--bar {
		display: block;
		margin: 0;
	}

	.main-navigation .nav-search--bar .nav-search__toggle {
		width: 44px;
		height: 60px;
		min-height: 60px;
	}

	/* The copy inside the menu panel would otherwise be a second search box
	   directly under the one in the bar. */
	.main-navigation .navbar-collapse .nav-search {
		display: none;
	}
}

@media (min-width: 992px) {

	/* Above the collapse the bar carries the wordmark and a single search, so
	   the phone mark and the phone search are both out of the way. */
	.main-navigation .site-mark,
	.main-navigation .nav-search--bar {
		display: none;
	}
}


/* Body copy does not shrink on a phone
   -------------------------------------------------------------------------
   The build dropped it to 18px below 768. Live holds 20px all the way down:
   measured on live at 390 an article paragraph is still 20px, the same as it
   is at 1600. Reading text getting smaller on the smaller screen is the wrong
   way round, and it is not what is being copied. */
@media (max-width: 768px) {
	:root {
		--h-fs-body: 20px;
	}
}

/* Search results are a single column, and a compact one
   -------------------------------------------------------------------------
   The card grid is shared with the category archives, and there it is right:
   one column below 768, two above it, lead card full width from 1025, all of
   which matches live exactly. Live's search page is not built that way. It is
   one result per row at every width from 375 to 1600, with a small square
   thumbnail beside the text rather than a banner above it: measured on live at
   1280, 49 results, each thumbnail 108 by 108.

   So the grid is overridden on the search template only, and the card is laid
   out as a row there. Everywhere else it is untouched. */
body.search .h-card-grid {
	grid-template-columns: 1fr;
	gap: 24px;
}

body.search .h-card-grid > .h-card-cell:first-child {
	grid-column: auto;
}


/* The phone bar keeps its 60px
   -------------------------------------------------------------------------
   Two things were adding to it. The search field is set to sit in the flow
   below 992, which was correct while search only ever appeared inside the
   opened menu panel; now that there is a copy in the bar itself, in the flow
   means it adds its own height to the bar, which came out at 76px against
   live's 60. The bar copy drops back to being a panel hanging off the bar,
   and only the copy inside the menu stays in the flow.

   The other few pixels were the gap under an inline image. The mark is a block
   inside a flex row instead, so there is no baseline for a descender to leave
   room under. Live draws the mark 53 by 60. */
@media (max-width: 991.98px) {

	.main-navigation > .h-container {
		min-height: 60px;
	}

	.main-navigation .site-branding {
		display: flex;
		align-items: center;
	}

	.main-navigation .site-mark img {
		display: block;
		width: 53px;
		height: 60px;
		object-fit: contain;
	}

	.main-navigation .nav-search--bar {
		position: relative;
	}

	.main-navigation .nav-search--bar .nav-search__form {
		position: absolute;
		right: 0;
		top: 100%;
		min-width: 260px;
		padding: 10px;
		background-color: var(--h-blue-dark);
		border-radius: 0 0 var(--h-radius) var(--h-radius);
	}
}

/* Air between the navigation bar and the page title
   -------------------------------------------------------------------------
   The title was starting at exactly the pixel the bar ends, with nothing
   between them, so on an article it read as though it had been shoved up
   under the menu. Live leaves 20px: measured on live the bar ends at 60 and
   the heading starts at 80, on every article and hub and at every width from
   1100 up.

   Put on the layout wrapper rather than on the heading, because the same gap
   has to hold for the left contents column and the right advert rail, which
   both begin at the top of that wrapper too. Giving it to the heading alone
   would leave the two columns still touching the bar. */
body .cloudflare-page-layout {
	/* Scoped through body deliberately. inc/global-ads-single.css loads after this file and
	   sets padding on the same selector, so an unscoped rule here is simply overwritten and
	   silently does nothing, which is exactly what happened on the first attempt. */
	padding-top: 20px;
}

/* The bar stays 60px whatever the logo is
   -------------------------------------------------------------------------
   Sizing the logo up to live's 176 by 44.9 pushed the bar from 60px to 70,
   because the branding block was sized by its contents plus its own padding
   and an inline image's baseline gap underneath it.

   The height is now the row's, not the logo's: a 60px minimum with everything
   centred in it, so the logo can be any height up to that without the bar
   moving. Live is 60px with the same 44.9px logo inside it. */
@media (min-width: 992px) {

	.main-navigation > .h-container {
		min-height: 60px;
	}

	.main-navigation .site-branding {
		display: flex;
		align-items: center;
		padding-block: 0;
	}

	.main-navigation .custom-logo-link {
		display: flex;
		align-items: center;
	}

	/* Block, so there is no baseline for a descender to reserve space under. */
	.main-navigation .custom-logo {
		display: block;
	}
}

/* Phone fixes from the responsive sweep
   ========================================================================= */

/* Comments were flush against both screen edges
   -------------------------------------------------------------------------
   The whole comments section sat at left 0 with the full width of the screen:
   avatars, the text of every comment, and the reply form. Measured at 375, the
   section, the paragraphs and the textarea were all 360 wide starting at 0.

   The reason is structural rather than a missing value. The comments block is
   a sibling of the page layout, not a child, and the layout is the only thing
   carrying a horizontal gutter, so the comments never inherited one. It is
   given the same 15px the article beside it uses, so the two line up.

   Only below the width where the layout supplies its own gutter. Above that
   the comments sit inside a centred column and already have room. */
@media (max-width: 1024px) {

	.comments-area {
		padding-left: 15px;
		padding-right: 15px;
	}
}

/* Tap targets that were too small to hit
   -------------------------------------------------------------------------
   Reply measured 39 by 22 against a 44px minimum, on 261 links in one thread.
   Read more came out between 26 and 35 tall, because legacy.css pads it 8px
   vertically with no floor under it.

   Both are given a real minimum and centred inside it, rather than more
   padding, so the text stays where it is and only the hit area grows. */
@media (max-width: 1024px) {

	.comment-reply-link {
		display: inline-flex;
		align-items: center;
		min-height: 44px;
		padding-right: 8px;
	}
}

.read-more,
a.read-more.button,
button.read-more {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 44px;
}

/* Contrast on the green, where white text sits on it
   -------------------------------------------------------------------------
   White on #009966 is 3.65 to 1, against the 4.5 needed at this size. It
   affects the search and form buttons, the offer button, and the month label
   on the exam calendar.

   The brand green is deliberately left alone everywhere it is decoration: the
   rule above a card, a left hand accent, a border. Only the places where text
   has to be read off it are darkened, to #007a52, which is 5.4 to 1 and close
   enough that the two do not read as different greens side by side.

   Worth knowing: the live site has the same 3.65 to 1, so this is a small
   deliberate departure from it rather than a difference that crept in. */
:root {
	--h-green-text: #007a52;
}

.btn-h,
input[type="submit"],
button[type="submit"],
.th-offer__button {
	background-color: var(--h-green-text);
}

.th-calendar__month {
	color: var(--h-green-text);
}

/* The offer badge, white on purple, was 3.73 to 1. Same treatment. */
.th-offer__badge {
	background-color: #7a63cf;
}

/* The navigation and footer links were 4.41 to 1, a hair under.
   Pure white on the same blue is 4.62 and is not distinguishable from the
   near white it replaces, so this costs nothing visually. */
.main-navigation .nav-link,
.main-navigation .navbar-brand,
.site-footer .footer-bar-widgets .menu > li > a {
	color: #fff;
}

/* The sticky header, at the level that can actually stick
   -------------------------------------------------------------------------
   It was set on .main-navigation, whose parent is header.site-header, and that
   parent is 60px tall. A sticky element can only travel inside its own
   parent's box, so the bar had 0px of room: it sat at the top, then left with
   the header the moment the page scrolled. The computed style said "sticky"
   the whole time, which is exactly why checking the property rather than the
   behaviour missed it.

   Moved up one level. header.site-header is a child of body, which is the full
   height of the document, so it has the whole page to travel through. */
.main-navigation {
	position: static;
}

.site-header {
	position: sticky;
	top: 0;
	z-index: 100;
}

body.admin-bar .site-header {
	top: 32px;
}

@media (max-width: 782px) {
	body.admin-bar .site-header {
		top: 46px;
	}
}

@media (max-width: 600px) {
	body.admin-bar .site-header {
		top: 0;
	}
}


/* The rest of the green, which the first pass missed
   -------------------------------------------------------------------------
   button.read-more is more specific than the .read-more I used, so legacy.css
   kept winning: #fafafa on #009966 is 3.5 to 1. The current page number is the
   same colour pairing. */
button.read-more,
a.read-more.button,
.wpsp-read-more,
a.wpsp-read-more,
ul.page-numbers li.current,
.page-numbers.current {
	background-color: var(--h-green-text);
	background: var(--h-green-text);
	color: #fff;
}

/* The search toggle was raised to 44px below the collapse point but nothing
   put it back at desktop, where it stayed 40 by 40. Tablets in landscape are
   above that breakpoint and are still touch devices. */
@media (min-width: 992px) {

	.main-navigation .nav-search__toggle {
		min-width: 44px;
		min-height: 44px;
	}
}

/* Read more on the search results was 35px tall, because that template's
   compact row gives it a tighter line height than the card grids do. The
   floor is restored without touching the row layout. */
body.search .h-card__more,
body.search .read-more,
body.search button.read-more {
	min-height: 44px;
	line-height: 1.4;
}


/* The open state the touch handler sets, alongside the hover it cannot use.
   Kept in the same media query as the hover rule so the two agree about when
   a flyout is a flyout at all. */
@media (min-width: 992px) {

	.main-navigation .dropdown-submenu-parent.is-submenu-open > .dropdown-menu.dropdown-submenu {
		display: block;
	}
}

/* The offer artwork is 16:9, at every width
   -------------------------------------------------------------------------
   The card was coming out enormous: measured 310 wide by 1500 tall, because
   the image was left at its natural proportions and one of the creatives is a
   tall vertical banner. Scoping a crop to phone widths only, which is what I
   did first, left the desktop card unconstrained, and then relaxing it further
   turned the height into blank space above the artwork.

   Live settles it: its offer image is 400 by 225, a flat 16:9, at every width.
   Same here now, cropped to fill rather than stretched, so a creative of any
   shape produces the same card. */
.th-offer__image,
.h-sidebar .th-offer__image {
	/* Capped by height, not forced into a shape.

	   Two earlier attempts got this wrong in opposite directions. Left at its own
	   proportions the artwork set the height of the whole card: 506 wide by 380
	   tall here, and 310 by 1500 with a tall creative, which is what looked
	   stretched. Forced to 16:9 it cropped a quarter off creatives that are
	   actually 4:3, landing on the empty middle so the card looked blank.

	   A height cap does neither. Nothing is cropped, nothing is squashed, and no
	   creative of any shape can make the card taller than this. Live sits at 400
	   by 225 for the same slot, so 240 keeps the card in the same territory while
	   letting a 4:3 image show in full at 320 by 240. */
	display: block;
	width: auto;
	max-width: 100%;
	height: auto;
	max-height: 240px;
	margin-inline: auto;
	object-fit: contain;
	aspect-ratio: auto;
}

/* Search results, built to match live
   -------------------------------------------------------------------------
   The search page was rendering the ordinary article card: a full width green
   Read more button under every result and a thumbnail stranded on its own
   line, because the text block was being given the full width of the card and
   so wrapped underneath the image instead of sitting beside it. Measured, the
   card was 890 by 353 with a 108 image and an 888 wide body inside it.

   Live is a compact row: 800 by 109, the text on the left, a 108 square
   thumbnail on the right, a 20px title, and no button at all. The whole row is
   the link, so a separate Read more is redundant and is what made the page
   look so heavy. */
body.search .h-card {
	display: flex;
	flex-direction: row;
	align-items: flex-start;
	gap: 20px;
	border: 0;
	padding: 0;
	background: none;
	box-shadow: none;
}

/* Thumbnail to the right of the text, as live has it. Order rather than
   row-reverse, so the reading order in the markup stays title first. */
body.search .h-card__media {
	order: 2;
	flex: 0 0 108px;
	width: 108px;
	height: 108px;
	aspect-ratio: 1 / 1;
	margin: 0;
	border-radius: var(--h-radius);
	overflow: hidden;
}

body.search .h-card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * flex-basis 0 rather than auto. With auto the body asks for the width of its
 * own content, which was wider than the card, so it wrapped onto its own line
 * and pushed the thumbnail up alone. min-width 0 lets a long title shrink
 * instead of setting a floor under the column.
 */
body.search .h-card__body {
	order: 1;
	flex: 1 1 0;
	min-width: 0;
	padding: 0;
}

body.search .h-card__title,
body.search .h-card-grid > .h-card-cell:first-child .h-card__title {
	font-size: 20px;
	line-height: 1.3;
	margin: 0 0 6px;
}

/* Live has no button on a search result: the row itself is the link. */
body.search .h-card__more,
body.search .read-more,
body.search button.read-more {
	display: none;
}

body.search .h-card__excerpt {
	margin: 0 0 6px;
	font-size: 16px;
	line-height: 1.5;
}

body.search .h-card-grid {
	gap: 28px;
}

/* On a phone the thumbnail keeps its place beside the text rather than
   stacking, because at 108px it still leaves a readable column next to it. */
@media (max-width: 575.98px) {

	body.search .h-card {
		gap: 14px;
	}

	body.search .h-card__media {
		flex: 0 0 84px;
		width: 84px;
		height: 84px;
	}

	body.search .h-card__title {
		font-size: 17px;
	}
}

/* The bar has to grow with the logo
   =========================================================================
   The logo is 235 by 60 to match what live draws on an article. At that size it
   exactly fills a 60px bar, so it sits edge to edge with nothing above or below
   it and reads as cramped rather than as a bigger logo.

   Superseded by section 57, which sets this back to nothing. The claim above,
   that live's bar is 69px around a 60px logo, came from the same bad reading as
   the 235px width: live's bar is 60px and its logo is 30px tall, so the air is
   15px either side and comes from the logo being half the size rather than from
   padding. Left here with the correction rather than deleted, because the 69px
   number appears in the notes of two earlier rounds. */
@media (min-width: 992px) {
	.main-navigation .custom-logo-link {
		padding-top: 4.5px;
		padding-bottom: 4.5px;
	}
}


/* ---------------------------------------------------------------------------
 * 40. Contrast, read off the painted page, and wide tables on a phone
 *
 * The earlier contrast pass named class names that sounded right rather than
 * the ones this build renders, so several of its rules matched nothing and the
 * components stayed where they were. Every selector below was taken from the
 * browser at 390px: the element, its own colour, and the colour actually
 * behind it, rather than from the palette.
 * ------------------------------------------------------------------------ */

/* Words on the brand green.
   The green itself is untouched wherever it is decoration: a rule above a
   card, an accent, a border. Only the pieces a reader has to read words off
   move to the darker mix, which is 5.4 to 1 and sits close enough that the two
   do not read as different greens side by side. */
a.wp-show-posts-read-more,
a.wp-show-posts-read-more:visited,
[id^="wpsp-hub-"] a.wp-show-posts-read-more,
[id^="wpsp-hub-"] a.wp-show-posts-read-more:visited,
a.affcoups-coupon__button,
a.affcoups-coupon__button:visited,
a.wp-block-button__link:not(.has-background),
div#gform_wrapper_1 {
	background-color: var(--h-green-text);
	color: #fff;
}

[id^="wpsp-hub-"] a.wp-show-posts-read-more:hover,
[id^="wpsp-hub-"] a.wp-show-posts-read-more:focus,
a.affcoups-coupon__button:hover,
a.affcoups-coupon__button:focus,
a.wp-block-button__link:not(.has-background):hover,
a.wp-block-button__link:not(.has-background):focus,
a.wp-block-button__link:not(.has-background):active {
	background-color: #005e3f;
	color: #fff;
}

/* The same pairing the other way round: green words on the white submit
   button inside the green panel.

   Stated on the id alone rather than on input#..., because the forms plugin
   draws this control as a button element now and a tag qualified selector
   quietly stops matching. The full treatment is in section 56. */
#gform_submit_button_1 {
	color: var(--h-green-text);
}

/* Gravity Forms prints its "(Required)" marker in a warning red that is meant
   for a white form. On the green panel it was 1.6 to 1. */
div#gform_wrapper_1 .gfield_required,
div#gform_wrapper_1 .gfield_required_text {
	color: #fff;
}

/* The discount badge, white on purple. */
.affcoups-coupon__discount,
span.affcoups-coupon__discount {
	background-color: #7a63cf;
}

/* The footer bar.
   The pale blue was carried over from a time when it sat on a white panel. On
   the blue bar it is 3.28 to 1, and the copyright line at near white is 4.41.
   The two levels of the menu stay distinct by weight, which is how the rest of
   the site separates them. */
.site-footer,
.site-footer p,
.site-footer .footer-bar-widgets .sub-menu a {
	color: #fff;
}


/* Wide tables on a phone
   -------------------------------------------------------------------------
   The wrapper already scrolls. The table inside it was told to be exactly the
   width of the wrapper and to lay its columns out equally, so five columns
   became five 72px columns and a date wrapped over four lines while the
   scrollbar had nothing to scroll.

   Below the tablet breakpoint the table is allowed its own width again, with a
   floor under each column, so it keeps readable columns and the wrapper does
   the work it was always there to do. */
@media (max-width: 767px) {

	.entry-content figure.wp-block-table > table,
	.entry-content .table-scroll > table,
	.cloudflare-content figure.wp-block-table > table {
		width: auto;
		min-width: 100%;
		table-layout: auto;
	}

	.entry-content figure.wp-block-table > table th,
	.entry-content figure.wp-block-table > table td,
	.entry-content .table-scroll > table th,
	.entry-content .table-scroll > table td,
	.cloudflare-content figure.wp-block-table > table th,
	.cloudflare-content figure.wp-block-table > table td {
		min-width: 128px;
	}

	/* The first column is the row label and carries the longest words. */
	.entry-content figure.wp-block-table > table th:first-child,
	.entry-content figure.wp-block-table > table td:first-child,
	.entry-content .table-scroll > table th:first-child,
	.entry-content .table-scroll > table td:first-child,
	.cloudflare-content figure.wp-block-table > table th:first-child,
	.cloudflare-content figure.wp-block-table > table td:first-child {
		min-width: 156px;
	}
}

/* Three the first attempt could not reach, each for its own reason.
   -------------------------------------------------------------------------
   The footer sub-menu colour is set on an id in the carried over stylesheet,
   which outranks anything written with classes. The offer button and the
   discount badge are painted by the offers plugin from its own settings, in a
   style block that wins on specificity; those settings have been changed as
   well, and these rules hold the result whatever the plugin is set to. */
#menu-footer-bar .sub-menu a {
	color: #fff;
}

body .affcoups a.affcoups-coupon__button,
body .affcoups a.affcoups-coupon__button:visited {
	background-color: var(--h-green-text);
	color: #fff;
}

body .affcoups a.affcoups-coupon__button:hover,
body .affcoups a.affcoups-coupon__button:focus,
body .affcoups a.affcoups-coupon__button:active {
	background-color: #005e3f;
	color: #fff;
}

body .affcoups .affcoups-coupon__discount {
	background-color: #7a63cf;
	color: #fff;
}

/* The copy-code control inherits white text from the button reset, and is only
   legible because both pieces of text inside it set a colour of their own. */
.th-offer__copy {
	color: #616161;
}

/* Touch targets, measured at 390px
   -------------------------------------------------------------------------
   The opt-in fields came in at 38px tall and the copy-code control at 41,
   both under the 44 a finger needs, and the comment consent box was the
   browser default 13 square. */
.gform_wrapper input[type="text"],
.gform_wrapper input[type="email"],
.gform_wrapper input[type="tel"],
.gform_wrapper input[type="url"],
.gform_wrapper input[type="number"],
.gform_wrapper select,
.gform_wrapper input[type="submit"],
.gform_wrapper button[type="submit"] {
	/* The forms plugin resets its own fields with all: unset behind a selector that
	   outranks anything reasonable to write, so this is one of the few places where
	   the flag is the honest answer rather than a shortcut. */
	min-height: 44px !important;
}

.th-offer__copy {
	min-height: 44px;
}

/* Both of these sit in a flex row, so a width alone is shrunk straight back to
   the browser default; the floor is what holds them. */
.comment-form-cookies-consent input[type="checkbox"],
.comment-form-subscriptions input[type="checkbox"] {
	flex: 0 0 auto;
	width: 24px;
	height: 24px;
	min-width: 24px;
	min-height: 24px;
	vertical-align: -6px;
	margin-right: 6px;
}


/* ---------------------------------------------------------------------------
 * 41. Dropdowns, the comment reply overlay, the comments, and quotes
 * ------------------------------------------------------------------------ */

/* The dropdowns were 160px wide and every single item wrapped
   -------------------------------------------------------------------------
   Measured: every item in every menu ran onto two lines or more, and the
   longest, "CFA Minimum Passing Score (MPS) Tracker", needs 297px to sit on
   one. The floor goes to 240, half again as wide as it was, and the box is
   then allowed to grow to whatever its longest item needs up to a cap, so a
   short menu stays neat and a long one stops wrapping.

   Only above the collapse point. Below it the menu is one stacked list at full
   width and a fixed width would push it off the screen. */
@media (min-width: 992px) {

	.main-navigation .dropdown-menu {
		min-width: 240px;
		width: max-content;
		max-width: min(380px, 92vw);
	}

	.main-navigation .dropdown-menu.dropdown-submenu {
		min-width: 220px;
		max-width: min(340px, 80vw);
	}

	/* A little more room around each line now there is room to have it. */
	.main-navigation .dropdown-item {
		padding: 11px 18px;
		line-height: 1.35;
	}
}


/* An invisible 1440 by 900 overlay was swallowing clicks on the article
   -------------------------------------------------------------------------
   The carried over stylesheet makes the whole Reply row clickable with an
   absolutely positioned ::after at 100% by 100%. The anchor itself is static,
   so "100%" is measured against the page rather than the link, and the result
   is a transparent sheet the size of the window sitting over the article. A
   click anywhere in the middle of the page landed on a comment reply link and
   jumped the reader down to the comments.

   Giving the anchor a position of its own is the whole fix: the overlay then
   covers the link it belongs to, which is what it was written to do.

   The forum rule below is the same pattern, written for the same reason. The
   forum is retired here so nothing renders it, but it is corrected too rather
   than left as a trap for whatever reuses that markup. */
a.comment-reply-link,
a#cancel-comment-reply-link,
.forum-nav a {
	position: relative;
}


/* The comments
   -------------------------------------------------------------------------
   They were the browser's defaults with a hairline between them: no space
   around a comment, the name and the date set at odd distances, and the reply
   link hanging under the text with nothing separating one exchange from the
   next. */
.comments-area {
	padding-top: 40px;
	margin-top: 40px;
	border-top: 1px solid var(--h-rule);
}

.comments-area .comments-title {
	font-size: 22px;
	font-weight: 600;
	margin: 0 0 24px;
}

.comments-area ol.comment-list,
.comments-area ol.children {
	list-style: none;
	padding: 0;
	margin: 0;
}

.comments-area li.comment {
	margin: 0 0 8px;
}

.comments-area article.comment-body {
	padding: 20px 22px;
	background-color: var(--h-panel);
	border: 1px solid var(--h-rule);
	border-radius: 10px;
}

/* The name, the word "says" and the date on one line, evenly spaced, rather
   than three fragments at whatever distance the markup happened to leave. */
.comments-area .comment-meta,
.comments-area .comment-author {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px;
	margin: 0 0 10px;
	font-size: 14px;
	line-height: 1.3;
}

.comments-area .comment-author .fn,
.comments-area .comment-author b {
	font-weight: 600;
	font-style: normal;
}

.comments-area .comment-metadata,
.comments-area .comment-meta .comment-metadata a {
	color: var(--h-body-text);
	font-size: 13px;
}

.comments-area .avatar {
	border-radius: 50%;
	flex: 0 0 auto;
}

.comments-area .comment-content {
	font-size: 16px;
	line-height: 1.65;
}

.comments-area .comment-content > *:first-child { margin-top: 0; }
.comments-area .comment-content > *:last-child { margin-bottom: 0; }

/* Reply reads as an action rather than as another sentence. */
.comments-area .reply {
	margin-top: 14px;
}

.comments-area a.comment-reply-link {
	/* 44px, because this is a pill a reader presses on its own rather than a link
	   inside a line of prose. It was 34. */
	display: inline-flex;
	align-items: center;
	padding: 11px 16px;
	min-height: 44px;
	line-height: 22px;
	border: 1px solid var(--h-rule);
	border-radius: 999px;
	font-size: 13.5px;
	font-weight: 500;
	text-decoration: none;
}

.comments-area a.comment-reply-link:hover,
.comments-area a.comment-reply-link:focus {
	background-color: var(--h-panel-alt);
	text-decoration: none;
}

/* A reply is indented and carries a quiet rule, so the shape of a conversation
   is readable at a glance instead of being guessed from the margins. */
.comments-area ol.children {
	margin: 8px 0 0 22px;
	padding-left: 18px;

	/*
	 * No rule down the left.
	 *
	 * It was a threading guide, but it starts immediately below the parent comment's
	 * Reply button and reads as a line trailing out of it. The indent and the reply's
	 * own card already say "this is a reply", so the guide was adding a mark without
	 * adding meaning. The current site draws one as well, at a 5px indent where this
	 * build uses 22px, which is why it is conspicuous here and not there.
	 */
	border-left: 0;
}

.comments-area .comment-respond {
	margin-top: 32px;
	padding-top: 28px;
	border-top: 1px solid var(--h-rule);
}

.comments-area .comment-respond .comment-reply-title {
	font-size: 19px;
	font-weight: 600;
	margin: 0 0 14px;
}

@media (max-width: 575.98px) {

	.comments-area article.comment-body {
		padding: 16px;
	}

	/* Replies stop stepping off the right edge once they are a few deep. */
	.comments-area ol.children {
		margin-left: 10px;
		padding-left: 12px;
	}
}


/* Quotes sat hard against their own line
   -------------------------------------------------------------------------
   A blockquote carries a 5px rule down its left and had no padding at all, so
   the first letter of every line touched it.

   The padding goes on the left only. The block already measures exactly the
   same width as the body text and the image above it, and padding on both
   sides would have pulled the text in from the right for no reason. */
.entry-content blockquote,
.cloudflare-content blockquote,
blockquote.wp-block-quote {
	padding: 2px 0 2px 26px;
	margin-top: 30px;
	margin-bottom: 30px;
}

.entry-content blockquote > *:first-child,
.cloudflare-content blockquote > *:first-child { margin-top: 0; }

.entry-content blockquote > *:last-child,
.cloudflare-content blockquote > *:last-child { margin-bottom: 0; }

.entry-content blockquote cite,
.cloudflare-content blockquote cite {
	display: block;
	margin-top: 10px;
}

@media (max-width: 575.98px) {

	.entry-content blockquote,
	.cloudflare-content blockquote,
	blockquote.wp-block-quote {
		padding-left: 18px;
	}
}


/* A listing's heading and its cards did not line up
   -------------------------------------------------------------------------
   This used to centre the listing's heading, breadcrumbs and green box on an
   850px measure so they met cards that were capped at 800 inside a wider
   column. It worked in the sense that the two edges stopped disagreeing by
   97px, and it was the wrong end of the problem: the cards were the thing in
   the wrong place, and 850 met neither the cards nor the column.

   The cap on the cards is gone, so all four now share the column's own measure
   with nothing to compensate for. Left as a note rather than as a rule,
   because this is the third time this alignment has been looked at and the
   reason it kept coming back is worth keeping. */


/* Two more pieces of text on the green, found in the September sweep
   -------------------------------------------------------------------------
   The earlier contrast pass reached the article lists because it was written
   against the id the theme gives them. The block on /esg-certifications/ is a
   second instance with an id of its own, so the plugin's own green survived
   there: #fafafa on #009966 is 3.5 to 1. Scoped to the component rather than
   to one id this time, so a third instance cannot slip through the same gap.

   The floating video player's button was 4.13 to 1, just under, for the same
   reason: a slightly different green from the one everything else uses. */
a.wp-show-posts-read-more,
a.wp-show-posts-read-more:visited,
.wp-show-posts a.wp-show-posts-read-more,
.wp-show-posts a.wp-show-posts-read-more:visited {
	background-color: var(--h-green-text);
	border-color: var(--h-green-text);
	color: #fff;
}

a.wp-show-posts-read-more:hover,
a.wp-show-posts-read-more:focus,
.wp-show-posts a.wp-show-posts-read-more:hover,
.wp-show-posts a.wp-show-posts-read-more:focus {
	background-color: #005e3f;
	border-color: #005e3f;
	color: #fff;
}

a.cloudflare-video-cta,
a.cloudflare-video-cta:visited {
	background-color: var(--h-green-text);
	color: #fff;
}

/* The same block's byline broke onto four lines with single characters
   stranded on their own, because only the hub instance had been given the
   one-line treatment. Same reasoning: scope it to the component. */
.wp-show-posts .wp-show-posts-entry-meta {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 6px;
	line-height: 1.4;
}

.wp-show-posts .wp-show-posts-entry-meta > *:not(.wp-show-posts-separator):not(.wp-show-posts-updated) {
	display: inline;
}

/* Two pieces of that meta line are meant to be off, and this is where they were being
   switched back on. The rule above used to name every child, which outranks the
   display:none each of these carries in hub-list.css, so both reappeared: a literal
   pipe between the name and the date, and the modified date printed straight after the
   published one, which read as the same date twice.

   The separator is not wanted because the dot between the items is drawn below, the
   same dot the article lists use. The modified date is not shown on the live site. */
.wp-show-posts .wp-show-posts-entry-meta > .wp-show-posts-separator,
.wp-show-posts .wp-show-posts-entry-meta .wp-show-posts-updated {
	display: none;
}

/* The dot between the name, the date and the comment count, so the exam hub lists read
   the same way the category lists do. Drawn rather than written into the markup, so a
   screen reader is not made to announce it. */
/* Nothing here draws a separator on the exam lists. They have always had their
   own, an ::after on each item with the last one blanked, which is why adding
   one in front gave every field two dots. The comment count added to those
   cards carries the same class as the other items, so it joins that scheme
   rather than needing one of its own. */

/* The byline on that block carries literal <br> tags inside its own markup, which is what
   pushed it onto seven lines with single characters stranded on their own. They come from
   the plugin's meta template rather than from anything here, so they are switched off at
   the point they do damage rather than chased through the plugin. */
.wp-show-posts .wp-show-posts-entry-meta br {
	display: none;
}


/* ===========================================================================
 * 42. Round 28: what the responsive audit turned up
 * ======================================================================== */

/* The open phone menu is a scroller, not a taller header
   -------------------------------------------------------------------------
   Opening the hamburger took the header from 60px to 3,818px, and the header is
   sticky at top 0, so it pinned there and the page behind it could not move it.
   On a 390x844 phone that left 15 of the 76 links reachable and the other 61
   with no way to get to them: no scroll, no swipe, nothing. At 320 the list
   stopped four items into Articles, so Free Resources, Exam Materials, Partner
   Providers and Offers were simply gone.

   The panel now stops at the window and scrolls inside itself. The cap is on the
   element rather than on .show so Bootstrap's open animation finishes at the same
   height it settles at, instead of growing to 3,818 and snapping back. The one
   thing that has to be put back is the hidden overflow the animation relies on
   while it runs. */

@media (max-width: 991.98px) {

	.main-navigation .navbar-collapse {
		max-height: calc(100vh - 60px);
		overflow-y: auto;
		overscroll-behavior: contain;
	}

	.main-navigation .navbar-collapse.collapsing {
		overflow-y: hidden;
	}

	/* The phone address bar comes and goes, and 100vh does not notice. */
	@supports (height: 100dvh) {
		.main-navigation .navbar-collapse {
			max-height: calc(100dvh - 60px);
		}
	}

	/* A menu and the items under it started at the same x, so the list read as one
	   flat run of 76 links rather than five groups. The third level already had its
	   own indent; this gives the second one the same. */
	.main-navigation .navbar-collapse .navbar-nav > .nav-item > .dropdown-menu {
		padding-left: 16px;
	}
}

/* A flyout stops at the bottom of the window
   -------------------------------------------------------------------------
   Free Resources > CFA Cheat Sheets is eleven items and 450px tall, and it opens
   from a bar near the top of the window, so its bottom sat at 819px no matter how
   short the window was: 219px off the bottom at 992x600, and the five items below
   "L1 Fixed Income" could not be reached, because the menu closes as soon as the
   pointer leaves it. */

@media (min-width: 992px) {

	/* Only the flyouts. A first-level box holds the flyouts as absolutely positioned
	   children, and an overflow on it would clip every one of them out of existence.
	   Nothing on this menu goes deeper than two levels, so the flyouts can scroll. */
	.main-navigation .dropdown-menu.dropdown-submenu {
		max-height: calc(100vh - 90px);
		overflow-y: auto;
		overscroll-behavior: contain;
	}
}

/* A submenu flips left only where there is no room to open right
   -------------------------------------------------------------------------
   The old rule flipped the last three top-level menus by their position in the
   list, which is not the same question. Measured across 992 to 1600, the only
   case that genuinely runs out of room is Exam Materials at 992, where opening
   right would end at 1004 in a 992 window. At 1024 and above every menu fits,
   and Partner Providers has no submenu at all, so the rule was flipping panels
   that had 671px of clear space beside them and leaving them floating over the
   article. */

@media (min-width: 1024px) {

	.main-navigation .nav-item:nth-last-child(-n+3) .dropdown-menu.dropdown-submenu {
		left: 100%;
		right: auto;
	}
}

/* The footer menu below 480
   -------------------------------------------------------------------------
   Three fixed 136px columns need 408px. Between 320 and 479 the bar is 280 to
   390 wide, so the third column wrapped, and because the row is right aligned
   the orphan landed under the middle column with a gap beside it. Two even
   columns fit at every width in that band. */

@media (max-width: 479.98px) {

	.site-footer .footer-bar-widgets .menu {
		justify-content: flex-start;
		text-align: left;
	}

	.site-footer .footer-bar-widgets .menu > li {
		width: 50%;
	}

	.site-footer .footer-bar-widgets .sub-menu {
		margin-left: 0;
	}
}

/* Standalone controls reach 44px
   -------------------------------------------------------------------------
   Both of these are pills a reader presses on their own, rather than links
   inside a line of prose, so the target size applies to them. */

/* An in-page jump clears the sticky bar
   -------------------------------------------------------------------------
   The contents links already carried scroll-margin-top, but "Skip to content"
   did not, so the one link on the page written for somebody who cannot see it
   landed the target underneath the 69px bar. Setting it on the document covers
   every anchor rather than the ones somebody remembered. */

html {
	scroll-padding-top: 90px;

	/* A build stamp. A headless browser will happily keep serving a cached copy of this
	   file, and then every check made against it describes the previous build. Bumped on
	   each deploy and asserted before any measurement is believed. */
	--th-css-build: "r45-01";
}

/* Embedded videos and forms narrow with the column
   -------------------------------------------------------------------------
   Two pages carried iframes with a hard width attribute and no max-width:
   eleven 800px YouTube embeds on the finance films article and a 700px Google
   form on the salary article. Below 782px the page could not contain them, and
   since nothing here scrolls sideways the far side of every video was simply cut
   off and unreachable. The video rule keeps the shape while the width comes
   down; the form has its own height and only needs to narrow. */

.entry-content iframe,
.cloudflare-content iframe,
.comment-content iframe {
	max-width: 100%;
}

.entry-content iframe[src*="youtube.com/embed"],
.entry-content iframe[src*="youtube-nocookie.com/embed"],
.entry-content iframe[src*="player.vimeo.com"],
.cloudflare-content iframe[src*="youtube.com/embed"],
.cloudflare-content iframe[src*="youtube-nocookie.com/embed"],
.cloudflare-content iframe[src*="player.vimeo.com"] {
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
}

/* A label with no field behind it
   -------------------------------------------------------------------------
   legacy.css hides the comment form's Website input and leaves its label on
   screen, so every article shows the word "Website" over nothing. */

.comment-form label[for="url"],
.comment-form p.comment-form-url {
	display: none;
}

/* The frozen full-bleed bands on the partner pages
   -------------------------------------------------------------------------
   These sections came from a page builder that is no longer installed, and what
   was copied across was the CSS it had already worked out: a negative margin of
   half the viewport each side, meant to break the band out to the full window.
   The article column is not centred in the window here, it sits between two
   rails, so the sum is wrong at every width. At 1440 the band runs from -14 to
   1306 instead of edge to edge; at 390 it is 270px wide starting hard against
   the left of the window, with 60px of padding inside it, which leaves the text
   150px wide while the rest of the article has 360.

   The band is now simply the width of the article, like everything else in it. */

/*
 * legacy.css carries the usual full-bleed trick: left 50%, then pull back by half
 * the viewport. It only holds when the column it sits in is itself centred in the
 * window. In the three column layout the article is not centred, it sits between
 * two rails, so the two halves do not cancel and the band lands to one side. Every
 * declaration there is !important, so this has to be as well.
 */
.cloudflare-page-layout .full-width,
.cloudflare-page-layout .full-width-margin,
.entry-content .uagb-section__wrap,
.cloudflare-content .uagb-section__wrap {
	position: static !important;
	left: auto !important;
	right: auto !important;
	width: auto !important;
	max-width: 100% !important;
	margin-left: 0 !important;
	margin-right: 0 !important;
	padding-left: clamp(16px, 5vw, 60px) !important;
	padding-right: clamp(16px, 5vw, 60px) !important;
}

.entry-content .uagb-section__inner-wrap,
.cloudflare-content .uagb-section__inner-wrap {
	width: auto;
	max-width: 100%;
}

/* A page-builder table from the old site stacks on a phone
   -------------------------------------------------------------------------
   /december-2020-cfa-exams-cancelled/ carries a two column layout table left
   over from the site before this one. It is 446px wide with the width written
   into the markup, so at 390 it started hard against the window edge, 56px past
   the other side, and at 320 it ran 126px past. Nothing here scrolls sideways,
   so the right hand column was cut off and there was no way to read it.

   A layout table has no rows and columns worth keeping on a phone, so the two
   columns become two blocks. */

@media (max-width: 767.98px) {

	.entry-content .wsite-multicol-table,
	.entry-content .wsite-multicol-tbody,
	.entry-content .wsite-multicol-tr,
	.entry-content .wsite-multicol-col,
	.cloudflare-content .wsite-multicol-table,
	.cloudflare-content .wsite-multicol-tbody,
	.cloudflare-content .wsite-multicol-tr,
	.cloudflare-content .wsite-multicol-col {
		display: block;
		width: 100% !important;
		max-width: 100%;
		padding-left: 0;
		padding-right: 0;
	}
}

/* A formula that scrolls says so
   -------------------------------------------------------------------------
   The display formulas already scroll sideways when they are wider than the
   column, which is what keeps the cheat sheets readable at 320. What they did
   not do is admit it: on a phone there is no scrollbar to see, so a formula that
   ended mid-bracket looked broken rather than continued. The class is set by
   theme.js on the ones that actually overflow, so nothing is marked that does
   not need it. */

.katex-display.is-scrollable {
	position: relative;
	mask-image: linear-gradient(to right, #000 calc(100% - 42px), transparent 100%);
	-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 42px), transparent 100%);
}

.katex-display.is-scrollable.is-scrolled-end {
	mask-image: none;
	-webkit-mask-image: none;
}

.katex-display.is-scrollable::-webkit-scrollbar {
	height: 6px;
}

.katex-display.is-scrollable::-webkit-scrollbar-thumb {
	background: rgba(0, 0, 0, .28);
	border-radius: 3px;
}

/* The bands that lost their background, and took their copy with them
   -------------------------------------------------------------------------
   Six pages carry sections the old page builder painted: a photograph on the
   provider pages, a flat colour on /advertising/. The builder wrote that paint
   into a stylesheet it generated per block, and that stylesheet went with the
   plugin. The markup kept the class and the copy kept its colour, so whole
   sections are now white text on white: the first paragraph of every provider
   page, the jump links under it, and six paragraphs of the advertising pitch.
   Only the words are gone, the space they take is still there, so the page
   reads as a tall empty gap rather than as anything broken.

   The same thing is true on the live site, and the artwork is not recoverable
   from the page content: the sections are stored as raw HTML with only the
   class left, so there is no image URL to put back.

   Every one of these sections was checked for what is inside it, and all of
   them hold pale text and nothing else, so a dark band restores all of them
   without hiding anything. White on this blue is 8.3 to 1.

   Worth Zee deciding whether to supply the original artwork, in which case this
   becomes the fallback behind it rather than the whole treatment. */

.entry-content .uagb-section__wrap.uagb-section__background-image,
.entry-content .uagb-section__wrap.uagb-section__background-color,
.cloudflare-content .uagb-section__wrap.uagb-section__background-image,
.cloudflare-content .uagb-section__wrap.uagb-section__background-color {
	background-color: var(--h-blue-dark, #004ba0);
}

/* Those sections ran edge to edge before, so their copy never needed room of
   its own. Now that they are the width of the article, they do. */
.entry-content .uagb-section__wrap.uagb-section__background-image,
.entry-content .uagb-section__wrap.uagb-section__background-color,
.cloudflare-content .uagb-section__wrap.uagb-section__background-image,
.cloudflare-content .uagb-section__wrap.uagb-section__background-color {
	padding-top: 8px;
	padding-bottom: 8px;
}

/* The free guides gallery, and the tab strip above it
   -------------------------------------------------------------------------
   Thirty-two cards in a Bootstrap 2 .span3 grid, carried over from the site
   before this one along with a tab strip that switches between four sets of
   them. None of the stylesheet that drove either came across, so the strip
   printed its four labels with nothing between them, all four sets of cards
   showed at once down a page three times longer than it should be, and the
   cards had no card around them.

   This is the live page's treatment rebuilt: a white rounded card with the
   artwork square at the top, the title on a strip across the bottom of it and
   the blurb hidden behind that strip until the pointer is over the card.

   What is deliberately not copied is live's fixed 350px card in a float. It
   cannot fit at 320 and nothing scrolls sideways to reach the rest of it, so
   the row is a grid that fits as many as there is room for, and the slide is
   driven by a transform rather than live's fixed -136px, which only lands
   correctly at one card width.
   ------------------------------------------------------------------------ */

.entry-content .row-gallery,
.cloudflare-content .row-gallery {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
	gap: 30px;
	width: auto !important;
	max-width: 100%;
	margin-left: 0;
	margin-right: 0;
}

.entry-content .row-gallery > .span3,
.cloudflare-content .row-gallery > .span3 {
	position: relative;
	overflow: hidden;
	width: auto !important;
	max-width: 100%;
	float: none;
	margin: 0;
	background-color: #fff;
	border-radius: 15px;
	box-shadow: 0 1px 3px rgba(34, 25, 25, .4);
	transition: box-shadow .3s ease-in-out;
}

.entry-content .row-gallery > .span3:hover,
.entry-content .row-gallery > .span3:focus-within,
.cloudflare-content .row-gallery > .span3:hover,
.cloudflare-content .row-gallery > .span3:focus-within {
	box-shadow: 0 3px 7px rgba(34, 25, 25, .5);
}

/* The whole card is one link, so it is the column that holds the three rows. */
.entry-content .row-gallery > .span3 > a,
.cloudflare-content .row-gallery > .span3 > a {
	display: flex;
	flex-direction: column;
	height: 100%;
	text-decoration: none;
}

/* The artwork, square as it is on the live page, with the title strip over it. */
.entry-content .row-gallery .media-centered-large,
.cloudflare-content .row-gallery .media-centered-large {
	position: relative;
	overflow: hidden;
	width: 100%;
	aspect-ratio: 1 / 1;
	float: none;
	padding-bottom: 0;
	height: auto;
}

.entry-content .row-gallery .media-centered-large > img,
.cloudflare-content .row-gallery .media-centered-large > img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* Only the title shows; the blurb sits below the fold of the card until the
   pointer arrives. Driven off the panel's own height so the amount left
   showing is the same whatever the blurb runs to. */
.entry-content .row-gallery .store-title-block,
.cloudflare-content .row-gallery .store-title-block {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	width: auto;
	padding: 12px 14px;
	background: #fff;
	color: #000;
	font-size: 16px;
	text-align: center;
	transform: translateY(calc(100% - 46px));
	transition: transform .3s ease-in-out;
}

.entry-content .row-gallery > .span3:hover .store-title-block,
.entry-content .row-gallery > .span3:focus-within .store-title-block,
.cloudflare-content .row-gallery > .span3:hover .store-title-block,
.cloudflare-content .row-gallery > .span3:focus-within .store-title-block {
	transform: translateY(0);
}

/* An empty div the old markup leaves between the artwork and the button. */
.entry-content .row-gallery > .span3 > a > div:empty,
.cloudflare-content .row-gallery > .span3 > a > div:empty {
	display: none;
}

.entry-content .row-gallery img,
.cloudflare-content .row-gallery img {
	width: 100%;
	height: auto;
}

.entry-content .wsite-button,
.cloudflare-content .wsite-button {
	max-width: 100%;
}

/* White on the old green was 3.65 to 1. The same green the rest of the site
   uses for a button clears 4.5. Orange under the pointer, as on the live page
   and as asked for on the other buttons. */
.entry-content .wsite-button,
.cloudflare-content .wsite-button {
	background-color: var(--h-green-text, #007a52);
}

/* The label inside the button carries no colour of its own.
   -------------------------------------------------------------------------
   It used to be painted green as well, which is invisible while the button is
   green and very visible the moment the button turns orange: a green pill sat
   inside an orange one. The button is the thing that is coloured; the label
   sits on it. */
.entry-content .wsite-button .wsite-button-inner,
.cloudflare-content .wsite-button .wsite-button-inner {
	background-color: transparent;
}

.entry-content .row-gallery > .span3:hover .store-button,
.entry-content .row-gallery > .span3:focus-within .store-button,
.cloudflare-content .row-gallery > .span3:hover .store-button,
.cloudflare-content .row-gallery > .span3:focus-within .store-button {
	background-color: #005e3f;
	transition: background-color .3s ease-in-out;
}

/* legacy.css sets this margin with !important, so matching it is the only way. */
.entry-content .row-gallery .wsite-button,
.cloudflare-content .row-gallery .wsite-button {
	margin-top: auto !important;
	margin-bottom: 14px !important;
}

/* The tab strip over the gallery
   -------------------------------------------------------------------------
   Four labels that switch which set of cards is shown. Without the rules
   below the list rendered as four words run together, and .hide, which is
   what marks the three sets that are not showing, meant nothing at all, so
   every card on the page was on screen at once.

   .hide is a name general enough to belong to anything, so every rule here is
   held inside the strip's own id rather than loose in the stylesheet. */

#storetabs .nav {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 4px;
	list-style: none;
	margin: 0 0 26px;
	padding: 0;
	text-align: center;
}

#storetabs .nav li {
	display: inline-block;
	margin: 0;
}

#storetabs .nav li a {
	display: block;
	padding: 12px 18px;
	min-height: 44px;
	font-weight: 700;
	color: #525252;
	text-decoration: none;
	border-radius: 4px;
	transition: background-color .2s ease-in-out, color .2s ease-in-out;
}

#storetabs .nav li a:hover,
#storetabs .nav li a:focus-visible,
#storetabs .nav li a.current {
	background-color: #fff;
	color: #000;
}

#storetabs .nav li a.current {
	box-shadow: inset 0 -3px 0 var(--h-green-text, #007a52);
}

#storetabs .list-wrap > ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* The three sets that are not showing. Taken off screen rather than hidden,
   which is how the page this was carried from did it, so anything measuring
   the cards still gets real numbers back. */
#storetabs .hide {
	position: absolute;
	top: -9999px;
	left: -9999px;
}

/* The last three controls under 44px
   -------------------------------------------------------------------------
   All three are pressed on their own rather than sitting in a line of prose,
   so the floor applies to them. The header search field is the one people use
   most and was the shortest of the lot at 31px. */

.main-navigation .nav-search input.form-control,
.main-navigation .nav-search input.form-control-sm,
.nav-search input.form-control {
	min-height: 44px;
}

a.affcoups-toggle-desc,
.affcoups a.affcoups-toggle-desc {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	padding: 10px 4px;
}

.h-card__meta a.comments-link,
a.comments-link,
body.search a.comments-link {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	padding: 10px 6px;
}

/* The email capture on /about/
   -------------------------------------------------------------------------
   The two fields are styled as a dotted underline on a transparent ground, so
   they read as part of the sentence rather than as somewhere to type, and both
   were 37px tall against the submit button's 45. */

form[action*="getresponse"] input[type="text"],
form[action*="getresponse"] input[type="email"],
form[action*="getresponse"] select {
	min-height: 44px;
}

/* The admin bar takes its height out of the menu too
   -------------------------------------------------------------------------
   Signed in, WordPress puts a bar above everything: 46px below 783 and 32px
   above it. The open menu is capped against the window, so without this it
   would run that much past the bottom of the screen for the only three people
   who ever edit the site. */

@media (max-width: 782.98px) {

	body.admin-bar .main-navigation .navbar-collapse {
		max-height: calc(100vh - 106px);
	}

	@supports (height: 100dvh) {
		body.admin-bar .main-navigation .navbar-collapse {
			max-height: calc(100dvh - 106px);
		}
	}
}

@media (min-width: 783px) and (max-width: 991.98px) {

	body.admin-bar .main-navigation .navbar-collapse {
		max-height: calc(100vh - 92px);
	}

	@supports (height: 100dvh) {
		body.admin-bar .main-navigation .navbar-collapse {
			max-height: calc(100dvh - 92px);
		}
	}
}

/* The star ratings
   -------------------------------------------------------------------------
   Gold on white measures 2.0 to 1, where a graphic that carries meaning needs
   3. Darkening far enough for 4.5 turns gold into brown and stops it reading
   as a star, so the colour moves only as far as it has to: this amber is
   3.3 to 1 and is still the same thing. The value in words, which is the part
   that actually matters, is added by inc/star-ratings.php. */

.th-rating {
	/* The gold is written into each span as an inline style, so nothing short of this
	   reaches it. Scoped to a class that exists only where inc/star-ratings.php put it,
	   so it cannot affect anything else. */
	color: #cc7a00 !important;
}

/* The advert inside the article
   -------------------------------------------------------------------------
   The live site carries one a fifth of the way down every article and the
   rebuild had no in-content position at all, which was the last real
   difference between the two. It is labelled, because an advert sitting in a
   column of editorial should say what it is, and it is capped well below the
   reading width so it reads as a break in the article rather than as part of
   it. */

.ga-in-content {
	display: block;
	margin: 30px auto;
	max-width: 600px;
	text-align: center;
}

.ga-in-content__label {
	display: block;
	margin-bottom: 6px;
	font-family: var(--h-font-subhead, "Roboto", Arial, sans-serif);
	font-size: 11px;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: #6b6b6b;
}

.ga-in-content__stack {
	display: block;
}

.ga-in-content__stack > div {
	margin: 0 auto;
}

.ga-in-content__stack img {
	display: block;
	width: 100%;
	height: auto;
}

/* The card inside an article
   -------------------------------------------------------------------------
   The position used to draw the same banner the side column draws, which is a
   picture and a link. The live site draws something else there: a square
   picture on the left, then a headline, a line of copy, who it is from and a
   green button. That is what this is.

   It is wider than the banner version was, because a card with copy in it
   needs the room, and it is left aligned rather than centred, since it reads
   as a paragraph-sized insert in the article rather than as a billboard. */

.ga-ina {
	max-width: none;
	text-align: left;
}

.ga-ina .ga-in-content__label {
	text-align: left;
}

.ga-ina__card {
	display: flex;
	align-items: flex-start;
	gap: 18px;
	padding: 18px;
	border: 1px solid var(--h-rule, #e2e2e2);
	border-radius: 8px;
	background: #fff;
}

.ga-ina__media {
	flex: 0 0 120px;
	width: 120px;
	display: block;
	overflow: hidden;
	border-radius: 6px;
	line-height: 0;
}

.ga-ina__media img {
	width: 100%;
	height: auto;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	display: block;
}

.ga-ina__body {
	flex: 1 1 auto;
	min-width: 0;
}

.ga-ina__headline {
	margin: 0 0 6px;
	font-family: var(--h-font-body, "Roboto", Arial, sans-serif);
	font-size: 19px;
	font-weight: 700;
	line-height: 1.3;
}

.ga-ina__headline a {
	color: var(--h-heading, #212121);
	text-decoration: none;
}

.ga-ina__headline a:hover,
.ga-ina__headline a:focus-visible {
	text-decoration: underline;
}

.ga-ina__summary {
	margin: 0 0 8px;
	font-size: 15px;
	line-height: 1.55;
}

/* Who the advert is from, and that it is one. Smaller and quieter than the
   copy, the same way the live site sets it. */
.ga-ina__byline {
	margin: 0 0 12px;
	font-size: 13px;
	font-weight: 700;
	color: #6b6b6b;
}

.ga-ina__cta {
	margin: 0;
}

/* Written on two classes so it outranks .inside-article a, which is a class and
   an element and was colouring these words link blue on a green button. */
.ga-ina .ga-ina__button,
.ga-ina .ga-ina__button:visited,
.ga-ina .ga-ina__button:link {
	color: #fff;
}

.ga-ina .ga-ina__button:hover,
.ga-ina .ga-ina__button:focus-visible,
.ga-ina .ga-ina__button:active {
	color: #fff;
}

.ga-ina__button {
	display: inline-block;
	min-height: 44px;
	padding: 11px 26px;
	border-radius: 5px;
	background-color: var(--h-green-text, #007a52);
	color: #fff;
	font-size: 16px;
	font-weight: 400;
	line-height: 1.4;
	text-align: center;
	text-decoration: none;
	transition: background-color .2s ease-in-out, color .2s ease-in-out;
}

.ga-ina__button:hover,
.ga-ina__button:focus-visible {
	background-color: #005e3f;
	color: #fff;
	text-decoration: none;
}

/* On a phone the picture goes above the words rather than beside them, since
   120px of picture and the rest of a sentence do not both fit on one line. */
@media (max-width: 520px) {

	.ga-ina__card {
		flex-direction: column;
	}

	.ga-ina__media {
		flex: 0 0 auto;
		width: 100%;
		max-width: 160px;
	}

	.ga-ina__button {
		display: block;
	}
}

/* ===========================================================================
 * 43. The menu behaves the way the old one does
 * ======================================================================== */

/* Hovering the tab you are already on
   -------------------------------------------------------------------------
   The current tab did not react to the pointer at all. The rule that paints it
   is `.nav-item.current-menu-item > .nav-link`, three classes deep, and the
   hover rule beside it is two, so the current state won in both states and the
   tab sat still while every other one darkened. On the old site every item
   darkens to the same blue, current or not.

   Stated at the same depth as the rule it has to beat rather than with an
   !important, so the next person can still see which rule wins and why. */

.main-navigation .nav-item.current-menu-item > .nav-link:hover,
.main-navigation .nav-item.current-menu-item > .nav-link:focus,
.main-navigation .nav-item.current-menu-ancestor > .nav-link:hover,
.main-navigation .nav-item.current-menu-ancestor > .nav-link:focus,
.main-navigation .nav-item.current_page_ancestor > .nav-link:hover,
.main-navigation .nav-item.current_page_ancestor > .nav-link:focus,
.main-navigation .nav-link.active:hover,
.main-navigation .nav-link.active:focus {
	background-color: var(--h-blue-dark);
	color: var(--h-white);
}

/* The same blue, solid
   -------------------------------------------------------------------------
   The hover came out at 90% alpha against the old site's solid colour, which
   reads as a slightly different blue rather than as the same one. */

.main-navigation .nav-link:hover,
.main-navigation .nav-link:focus,
.main-navigation .dropdown-item:hover,
.main-navigation .dropdown-item:focus {
	background-color: rgb(0, 75, 160);
}

/* No underline inside the dropdown
   -------------------------------------------------------------------------
   A submenu item picked up the underline that the carried-over stylesheet puts
   on any hovered link. The top level items already say otherwise; the dropdown
   items did not, so they were the only part of the menu that underlined. */

.main-navigation .dropdown-item,
.main-navigation .dropdown-item:hover,
.main-navigation .dropdown-item:focus,
.main-navigation .dropdown-item:active,
.main-navigation .dropdown-menu a,
.main-navigation .dropdown-menu a:hover,
.main-navigation .dropdown-menu a:focus {
	text-decoration: none;
}

/* The current item inside a dropdown
   -------------------------------------------------------------------------
   Bootstrap paints `.dropdown-item.active` in its own blue, which is not one of
   this site's colours and is not what the old menu does: there the current entry
   carries no panel of its own, it is simply the one in pure white rather than
   the off-white the rest use. */

.main-navigation .dropdown-item.active,
.main-navigation .dropdown-menu .current-menu-item > .dropdown-item,
.main-navigation .dropdown-menu .current_page_item > .dropdown-item {
	background-color: transparent;
	color: var(--h-white);
}

.main-navigation .dropdown-item.active:hover,
.main-navigation .dropdown-item.active:focus,
.main-navigation .dropdown-menu .current-menu-item > .dropdown-item:hover,
.main-navigation .dropdown-menu .current-menu-item > .dropdown-item:focus,
.main-navigation .dropdown-menu .current_page_item > .dropdown-item:hover,
.main-navigation .dropdown-menu .current_page_item > .dropdown-item:focus {
	background-color: rgb(0, 75, 160);
	color: var(--h-white);
}


/* ---------------------------------------------------------------------------
 * 56. The "Get the free guides" box: its button
 *
 * Everything else in that green panel already measures the same as the live
 * site, at every width: the same 10px by 20px inset, the same 12 column grid
 * folding to one column, the same field heights, the same copy sizes. The
 * button was the one piece that did not, and it is what made the whole block
 * read as cramped and off: a flat blue bar, 38px tall, sitting hard against
 * the fields with nothing between them, where live carries a white button in
 * the panel's own green, 47px tall, with 10px of air above and below it.
 *
 * The reason is a tag name. The forms plugin used to draw the submit control
 * as <input type="submit"> and now draws it as <button type="submit">, so
 * every rule written as input#gform_submit_button_1 matches nothing at all.
 * Nothing errors and nothing looks broken in the stylesheet; the rules simply
 * stop applying and the plugin's own button styling shows through.
 *
 * So these are stated on the id, which matches whichever element the plugin
 * decides to draw, and which outranks the plugin's own .gform-theme...
 * .button chain without needing a flag. Values are the live site's own, read
 * off the painted page rather than copied from the old stylesheet, with two
 * deliberate departures: the green is this build's darker mix, which clears
 * 4.5 to 1 where live's does not, and a 44px floor is stated outright so the
 * control cannot fall under a finger's width if the line height ever moves.
 * ------------------------------------------------------------------------ */

#gform_submit_button_1,
.gform_wrapper #gform_submit_button_1 {
	display: block;
	margin: 10px auto;
	background-color: #fff;
	color: var(--h-green-text);
	line-height: 45px;
	min-height: 44px;
	cursor: pointer;
}

/* Live reverses the pairing on hover: the panel shows through and the button
   is drawn as an outline. Keyboard focus gets the same, which live does not
   do, because a control you cannot see the focus on is worse than a small
   departure from the old site. */
#gform_submit_button_1:hover,
#gform_submit_button_1:focus,
.gform_wrapper #gform_submit_button_1:hover,
.gform_wrapper #gform_submit_button_1:focus {
	background-color: transparent;
	border: 1px solid #fff;
	color: #fff;
}


/* 57. The exam calendar panel
   -------------------------------------------------------------------------
   Matched against the calendar this build replaces: a head with an arrow each
   side of the date, a blue band naming the date, then the event itself with
   its body, the organiser and the links written into the event in Google.

   The body of the event is the part that was missing. It was parsed and then
   dropped, so the panel showed a date and a title and nothing a reader could
   act on, while the calendar it replaces showed the whole thing.
   ------------------------------------------------------------------------ */

.th-calendar__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	margin: 0 0 14px;
}

.th-calendar__current {
	flex: 1 1 auto;
	margin: 0;
	font-size: 1.35rem;
	line-height: 1.3;
	font-weight: 400;
	text-align: center;
	color: #616161;
}

.th-calendar__nav {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;

	/* The touch floor this build holds everywhere. */
	width: 44px;
	height: 44px;

	padding: 0;
	border: 0;
	border-radius: 4px;
	background: transparent;
	color: #616161;
	font-size: 1.6rem;
	line-height: 1;
	cursor: pointer;
	transition: background-color .15s ease, color .15s ease;
}

.th-calendar__nav:hover,
.th-calendar__nav:focus-visible {
	background: #eef3f9;
	color: #1976d2;
}

.th-calendar__nav[disabled] {
	opacity: .35;
	cursor: default;
}

.th-calendar__nav[disabled]:hover {
	background: transparent;
	color: #616161;
}

.th-calendar__day-label {
	margin: 0 0 12px;
	border-bottom: 1px solid #1976d2;
	line-height: 1;
}

.th-calendar__day-label span {
	display: inline-block;
	padding: 5px 8px;
	background-color: #1976d2;
	color: #fff;
	font-size: .95rem;
}

.th-calendar__events {
	margin: 0;
	padding: 0;
	list-style: none;
}

.th-calendar__event + .th-calendar__event {
	margin-top: 22px;
	padding-top: 22px;
	border-top: 1px solid #e6e6e6;
}

.th-calendar__event-head {
	margin: 0 0 10px;
	font-size: 1rem;
	line-height: 1.5;
	color: #616161;
}

.th-calendar__event-date {
	margin: 0 0 10px;
	font-size: .95rem;
	line-height: 1.5;
	color: #616161;
}

.th-calendar__event-body {
	font-size: .95rem;
	line-height: 1.6;
	color: #616161;
}

.th-calendar__event-body p {
	margin: 0 0 12px;
}

.th-calendar__event-body p:last-child {
	margin-bottom: 0;
}

.th-calendar__event-body a,
.th-calendar__event-more a {
	color: #1976d2;
	text-decoration: none;
	overflow-wrap: anywhere;
}

.th-calendar__event-body a:hover,
.th-calendar__event-more a:hover {
	text-decoration: underline;
}

.th-calendar__event-more {
	margin: 12px 0 0;
	font-size: .95rem;
}

/* The link under the whole calendar, which is set in the theme options. */
.th-calendar__more {
	margin: 18px 0 0;
	padding-top: 14px;
	border-top: 1px solid #e6e6e6;
	font-size: .95rem;
}

.th-calendar__more a {
	color: #1976d2;
	text-decoration: none;
	font-weight: 600;
}

.th-calendar__more a:hover {
	text-decoration: underline;
}


/* 58. Two things the comparison against the live site turned up
   -------------------------------------------------------------------------
   Measured on /cfa-exam-dates/, which carries 532 comments.
   ------------------------------------------------------------------------ */

/*
 * Let the browser skip the comments until the reader is near them.
 *
 * Both sites put all 532 comments in the page. The live site tells the browser
 * it may leave them unlaid out until they are scrolled towards; this build did
 * not, so the browser measured and positioned every one of them before showing
 * anything. Measured at 390 wide: the page was 108,425px tall here against
 * 11,489px there, with the comment area alone accounting for 97,026px.
 *
 * It costs nothing visually. The comments are in the page, they are found by
 * search engines and by find in page, and a link straight to a comment still
 * lands on it. The only difference is when the work is done.
 *
 * contain-intrinsic-size is the one place this goes further than live, which
 * leaves it at none. Without an estimate the browser treats the unrendered
 * comments as zero tall and the scrollbar jumps as it scrolls into them. A
 * remembered size, falling back to a rough guess, keeps that steady.
 */
.comments-area {
	content-visibility: auto;
	contain-intrinsic-size: auto 1200px;
}

/*
 * The byline and category links are big enough to hit.
 *
 * Under every article title the author and the category sat at 53x20 and 25x19,
 * against the 44px floor this build holds everywhere else. They are inline, in
 * a line of text, so they cannot simply be made taller without pushing that
 * line apart.
 *
 * Padding on an inline element grows what can be tapped without changing the
 * line box, and the matching negative margin keeps the spacing on either side
 * exactly as it was. The line looks identical and the target is 44px.
 */
.cloudflare-meta a,
.entry-meta a,
.wp-show-posts-entry-meta a {
	/* 13 rather than 12. The exam hub byline sets its line at 19px, so twelve either
	   side came to 43 and missed the floor by a single pixel. Thirteen clears it on
	   that row and on the taller rows the article lists use. */
	padding: 13px 3px;
	margin: -13px -3px;

	/* Without this the expanded area of one link can sit over its neighbour. */
	position: relative;
}

.cloudflare-meta a:hover,
.cloudflare-meta a:focus-visible,
.entry-meta a:hover,
.entry-meta a:focus-visible,
.wp-show-posts-entry-meta a:hover,
.wp-show-posts-entry-meta a:focus-visible {
	z-index: 1;
}

/* The exam hub lists were left out of the treatment above when it was written,
   so their byline links stayed at 19px against the 44 a finger needs, the same
   as the site this replaces. Adding the comment count to those cards put one
   more short target in the row, which is what turned it up. The whole row gets
   the same padding and matching negative margin as the category lists: the
   line looks identical and every link in it is now 44px. */


/* 59. Items 10 and 13 off the October feedback list
   -------------------------------------------------------------------------
   Both are "make it look like the site it replaces", measured there first.
   ------------------------------------------------------------------------ */

/*
 * Every button on the site goes to the same darker green under the pointer.
 *
 * Asked for directly: the offers button turned orange and the article lists did not, so the
 * site disagreed with itself. Measured before changing anything, and it was worse than the
 * one place reported. Five different behaviours were in play:
 *
 *     exam list Read more        rgb(0, 94, 63)      the darker green
 *     category list Read more    rgb(99, 164, 255)   a light blue
 *     offers, coupons, guides,
 *     in-article                 rgb(255, 163, 0)    orange
 *
 * All of them are the darker green now, which is the one the exam lists already used and the
 * one the rest of the site reads as a pressed state. The orange is gone from the hover, which
 * reverses what was asked for on 9 October; the request to harmonise came later and is the
 * one being followed.
 */

/*
 * Item 13. The button on an offer.
 *
 * Two things, both asked for directly. The site this replaces turns the button
 * orange under the pointer, and this one went a darker green, which reads as
 * nothing happening. And the label was being forced into capitals by the
 * stylesheet, so "Activate Offer" arrived as a shout.
 *
 * The green at rest stays as it is here, which is the darker one from the
 * contrast pass: the lighter green the old site uses fails against white at
 * 3.65 to 1.
 */
.th-offer__button {
	text-transform: none;
	transition: background-color .2s ease-in-out, color .2s ease-in-out;
}

.th-offer__button:hover,
.th-offer__button:focus-visible {
	background-color: #005e3f;
	color: #fff;
	/* The underline that came with it was not on the old button. Asked for
	   directly once the orange was in. */
	text-decoration: none;
}


/* 60. Item 14. The partner page
   -------------------------------------------------------------------------
   Two separate faults on /kaplan-schweser/, both visible against the live
   page.

   The offers row stacked. The old offers plugin is not installed here, and
   when the coupon markup was frozen into the page its stylesheet came with it,
   but only partly: of the per column widths the plugin ships, the copy that
   came across carries the four column one and nothing else. The row on this
   page is a three column one, so every card fell back to the full width base
   rule and sat one above the other down the middle of the article.

   The widths below are the plugin's own, restated here so the page no longer
   depends on a stylesheet that is not installed. Stated with the grid class in
   the selector, which outranks the frozen base rule whichever order the two
   are read in, since the frozen copy is printed inside the article and so
   comes after this file.
   ------------------------------------------------------------------------ */

@media (min-width: 481px) {

	.affcoups .affcoups-coupons-grid--col-2 .affcoups-coupons-grid__item {
		width: 46%;
	}

	.affcoups .affcoups-coupons-grid--col-3 .affcoups-coupons-grid__item {
		width: 29.33333333%;
	}

	.affcoups .affcoups-coupons-grid--col-4 .affcoups-coupons-grid__item {
		width: 21%;
	}

	.affcoups .affcoups-coupons-grid--col-5 .affcoups-coupons-grid__item {
		width: 16%;
	}

	.affcoups .affcoups-coupons-grid--col-6 .affcoups-coupons-grid__item {
		width: 12.66666667%;
	}
}

/* On a tablet the three and four column rows go to two across, as they do on
   the live site. Below 481px they stack, which is the base rule and correct. */
@media (min-width: 481px) and (max-width: 768px) {

	.affcoups .affcoups-coupons-grid--col-3 .affcoups-coupons-grid__item,
	.affcoups .affcoups-coupons-grid--col-4 .affcoups-coupons-grid__item,
	.affcoups .affcoups-coupons-grid--col-5 .affcoups-coupons-grid__item,
	.affcoups .affcoups-coupons-grid--col-6 .affcoups-coupons-grid__item {
		width: 46%;
	}
}

/* The offer button under the pointer, the same change item 13 asked for on the
   offer panel. The frozen stylesheet already turns it orange; the contrast
   pass had overridden that to a darker green here, which is the one place the
   two rules disagreed. */
body .affcoups a.affcoups-coupon__button:hover,
body .affcoups a.affcoups-coupon__button:focus,
body .affcoups a.affcoups-coupon__button:active {
	background-color: #005e3f;
	color: #fff;
}

/* The row of four links at the top of a partner page.
   On the live site these sit in a four column grid drawn by a layout plugin
   that is not part of this build. The blocks came across on their own, so each
   illustration took the full width of the article and the four of them ran
   down the page at a thousand pixels each. They are in a columns block now;
   this holds the proportions the live page has, which is the image at the
   column width and the caption small and centred under it. */
.th-tile-row {
	gap: 0;
}

/* The live page keeps the four across on a tablet and only breaks them to one
   column on a phone, so the row below the title stays a row at the width most
   tablets report. The columns block would otherwise stack everything below
   782px. */
@media (max-width: 767px) {

	/* Carries the body tag as well. The rule that keeps the row unstacked is
	   written on the same two classes, so a tie there is settled by which
	   stylesheet the browser read last, and that is not this one. */
	body .wp-block-columns.th-tile-row {
		flex-wrap: wrap !important;
	}

	body .wp-block-columns.th-tile-row > .wp-block-column {
		flex-basis: 100% !important;
		flex-grow: 0;
	}
}

.entry-content .th-tile-row .wp-block-image {
	margin-bottom: 0;
}

.entry-content .th-tile-row .wp-block-image figcaption {
	margin-top: .6em;
	font-size: 14px;
	line-height: 1.4;
	text-align: center;
}


/* ===========================================================================
 * 57. The header, measured against live rather than described
 *
 * Reported as the logo being much bigger than live's and not sitting centred,
 * the current section losing the white line under it once you are inside a
 * sub-item, and the header not being the same size.
 *
 * All three are real and all three are measured below. The reason the logo was
 * wrong is worth keeping, because the note above the rule it replaces argues
 * confidently for the wrong number:
 *
 * That note says live draws the logo 235 by 60 inside a 69px bar on an article,
 * and that the home page cannot be trusted as a reference. The second half is
 * right and the number is not. Both sites ship two navigation bars, a phone one
 * and a desktop one, and the phone one comes first in the document. A probe that
 * takes the first match measures the phone bar, which is hidden at desktop and
 * reports a zero-sized box and the phone logo's own intrinsic size. 235 by 60 is
 * the intrinsic size of the SVG this build ships, not anything live paints.
 *
 * Measured at 1440 on the bar that is actually visible, on both templates:
 *
 *                      live              this build, before
 *     logo             118 x 30          235 x 60
 *     bar height       60px              69px
 *     logo top         y=10              y=5
 *     first menu item  x=238             x=355
 *     current item     3px solid white   no line at all
 *
 * Live is 118 by 30 on the home page and on an article, so there is no
 * per-template difference to accommodate. The bar is 60px on both.
 * ======================================================================== */

/* The logo is the size live draws it
   -------------------------------------------------------------------------
   Width pinned and height left to follow, so replacing the file cannot stretch
   it. The SVG is intrinsically 235 by 60 and scales cleanly to half that. */
@media (min-width: 992px) {
	.main-navigation .custom-logo {
		width: 118px;
		height: auto;
		max-height: none;
	}

	/* The bar is 60px, as live's is.
	   The 4.5px of padding here was added to give a 60px logo some air inside a
	   60px bar, which is what made the bar 69. With the logo at 30px the air is
	   already there: 15px above and below, centred by the flex alignment the
	   wrapper already carries. */
	.main-navigation .custom-logo-link {
		padding-top: 0;
		padding-bottom: 0;
	}

	/* The search fills the bar's height, where live has it 44 by 60 rather than
	   44 by 44 floating in the middle. */
	.main-navigation .navbar-collapse .nav-search__toggle {
		height: 60px;
		min-height: 60px;
		border-radius: 0;
	}
}

/* The white line under the section you are in
   -------------------------------------------------------------------------
   Live puts a 3px white line under the top-level item for the section you are
   reading, and keeps it there when you are on a page inside one of that
   section's sub-items. That second half is the part that was missing here: the
   item lit up on its own page and went dark as soon as you opened anything
   underneath it, so the menu stopped telling you where you were.

   WordPress marks the parent in that situation with current-menu-ancestor,
   current-menu-parent and current_page_ancestor, depending on whether the child
   is a page, a post or a taxonomy, so all of them are named here. Missing one
   means the line works in some sections and not others, which reads as random.

   Drawn as an inset shadow rather than a border, on purpose. A 3px border is
   3px of box, so it would push each item to 63px tall and the bar with it, and
   only the current one, which makes the items different heights. An inset shadow
   paints in exactly the same place and occupies nothing. */
.main-navigation .nav-item.current-menu-item > .nav-link,
.main-navigation .nav-item.current-menu-ancestor > .nav-link,
.main-navigation .nav-item.current-menu-parent > .nav-link,
.main-navigation .nav-item.current_page_ancestor > .nav-link,
.main-navigation .nav-item.current_page_parent > .nav-link,
.main-navigation .nav-link.active {
	box-shadow: inset 0 -3px 0 var(--h-white);
}

/* It has to survive the pointer, or hovering the section you are in takes the
   line away and the menu says you are nowhere. Stated at the same depth as the
   hover rule it sits beside. */
.main-navigation .nav-item.current-menu-item > .nav-link:hover,
.main-navigation .nav-item.current-menu-item > .nav-link:focus,
.main-navigation .nav-item.current-menu-ancestor > .nav-link:hover,
.main-navigation .nav-item.current-menu-ancestor > .nav-link:focus,
.main-navigation .nav-item.current-menu-parent > .nav-link:hover,
.main-navigation .nav-item.current-menu-parent > .nav-link:focus,
.main-navigation .nav-item.current_page_ancestor > .nav-link:hover,
.main-navigation .nav-item.current_page_ancestor > .nav-link:focus,
.main-navigation .nav-link.active:hover,
.main-navigation .nav-link.active:focus {
	box-shadow: inset 0 -3px 0 var(--h-white);
}

/* Only the current section is in pure white
   -------------------------------------------------------------------------
   Live holds the other items a shade back, at rgb(250, 250, 250), and brings
   only the current one to pure white, so the line and the brightness say the
   same thing together. Every item here was pure white, which left the line
   doing that work alone. */
.main-navigation .nav-link {
	color: var(--h-off-white);
}

.main-navigation .nav-item.current-menu-item > .nav-link,
.main-navigation .nav-item.current-menu-ancestor > .nav-link,
.main-navigation .nav-item.current-menu-parent > .nav-link,
.main-navigation .nav-item.current_page_ancestor > .nav-link,
.main-navigation .nav-item.current_page_parent > .nav-link,
.main-navigation .nav-link.active {
	color: var(--h-white);
}
