/* ==========================================================================
   Blog
   Listing, article and author profile.
   Card internals reuse .content-card from style.css where possible.
   ========================================================================== */

/* Typography -------------------------------------------------------------
   Scales from the wireframe. The theme's own --text-size-* ladder is a
   different scale, so the blog sets its own tokens rather than bending
   those and breaking every other template. */

.blog-archive,
.blog-featured,
.blog-article {
	--blog-text-meta: 15px;
	--blog-text-caption: 13px;
	--blog-text-body-lg: 18px;
	--blog-text-h4: 17px;
	--blog-text-h2: 36px;
	--blog-text-h1: 52px;
}

/* Meta: post meta row, result count, applied-filter label and chips.
   Reused anywhere the wireframe calls for Body 15px. */

.meta,
.meta p,
.blog-archive .facetwp-facet-blog_count,
.blog-filters .facetwp-facet-blog_count {
	font-family: 'Inter', sans-serif;
	font-style: normal;
	font-weight: 400;
	font-size: var(--blog-text-meta, 15px);
	line-height: 155%;
	color: var(--color-primary);
}

/* Page title (Wireframe H1) */

.blog-page-title {
	font-family: 'Lexend Deca', sans-serif;
	font-weight: 700;
	font-size: var(--blog-text-h1, 52px);
	line-height: 110%;
	letter-spacing: -1.5px;
	color: var(--color-primary);
}

/* Section heading, e.g. "All articles" (Wireframe H2). Overrides .title.lg. */

.blog-section-title,
.blog-archive .title.lg {
	font-family: 'Lexend Deca', sans-serif;
	font-weight: 700;
	font-size: var(--blog-text-h2, 36px);
	line-height: 115%;
	letter-spacing: -1px;
	color: var(--color-primary);
}

/* "All articles" carries a rule across the container beneath it. The
   heading is a block in a full-width column, so the border it draws is
   already the container width. */

.blog-archive .title.lg {
	padding-bottom: var(--default-gutter-y);
	border-bottom: 1px solid var(--color-grey-darker);
}

/* The featured band and the archive each bring 90px of section padding,
   stacking to 180px between the last featured card and the heading.
   Halved by dropping the featured section's bottom padding. */

.content-section.blog-featured {
	padding-bottom: 0;
}

/* Hidden while the listing is filtered, by home.php on load and by blog.js on
   every refresh after it. Spelled out because .content-section carries its own
   display, which an author rule would otherwise win against the [hidden]
   the browser supplies. */

.content-section.blog-featured[hidden] {
	display: none;
}

/* Where a category change scrolls to. The band rather than the grid, so the
   filter bar comes with it; the offset clears the sticky header. */

.blog-archive {
	scroll-margin-top: calc(var(--default-gutter-y) * 2);
}

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

.blog-card {
	display: flex;
	flex-direction: column;
	gap: 1rem;
}

.blog-card-media {
	display: block;
	overflow: hidden;
	border-radius: 0.75rem;
	line-height: 0;
}

.blog-card-media img {
	display: block;
	width: 100%;
	height: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	transition: transform 0.4s ease;
}

.blog-card:hover .blog-card-media img {
	transform: scale(1.03);
}

.blog-card-body {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	flex: 1 1 auto;
}

/* Meta row: author sits inline to the right when author-position is "meta" */

.blog-card-meta-row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.75rem 1.5rem;
}

.blog-card-meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	margin: 0;
}

.blog-card-separator {
	opacity: 0.45;
}

.blog-card-title {
	margin: 0;
}

.blog-card-title a {
	color: inherit;
	text-decoration: none;
}

.blog-card-title a:hover {
	text-decoration: underline;
}

.blog-card-excerpt {
	margin: 0;
	font-family: 'Inter', sans-serif;
	font-weight: 400;
	font-size: var(--blog-text-body-lg, 18px);
	line-height: 155%;
	color: var(--color-primary);
}

/* Card titles. Hero, large and secondary take Wireframe H2; the small grid
   card takes H4. Both need to beat .title.lg / .title from style.css. */

.blog-card .blog-card-title {
	font-family: 'Lexend Deca', sans-serif;
	font-weight: 700;
	font-size: var(--blog-text-h2, 36px);
	line-height: 115%;
	letter-spacing: -1px;
	color: var(--color-primary);
}

.blog-card-small .blog-card-title,
.blog-card-grid .blog-card-title {
	font-weight: 600;
	font-size: var(--blog-text-h4, 17px);
	line-height: 140%;
	letter-spacing: normal;
}

/* "Read article" (Wireframe Caption) */

.blog-card-link {
	font-family: 'Inter', sans-serif;
	font-weight: 400;
	font-size: var(--blog-text-caption, 13px);
	line-height: 120%;
	color: var(--color-primary);
}

/* Author ----------------------------------------------------------------- */

.blog-card-author {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	flex: 0 0 auto;
}

.blog-card-author-image {
	width: 28px;
	height: 28px;
	flex: 0 0 28px;
	overflow: hidden;
	border-radius: 50%;
}

.blog-card-author-image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.blog-card-author-name {
	font-family: 'Inter', sans-serif;
	font-weight: 400;
	font-size: var(--blog-text-meta, 15px);
	line-height: 155%;
	color: var(--color-primary);
	text-decoration: none;
}

.blog-card-author-name:hover {
	text-decoration: underline;
}

.blog-card-link {
	align-self: flex-start;
	text-decoration: none;
}

/* Where the author sits on its own row, the body's gap alone left the byline
   and "Read article" reading as one block. */

.blog-card-author + .blog-card-link {
	margin-top: 1rem;
}

.blog-card-link:hover {
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

/* Hero: image beside the content ----------------------------------------- */

.blog-card-hero {
	flex-direction: row;
	align-items: flex-start;
	gap: 4rem;
}

.blog-card-hero .blog-card-body {
	padding: 4rem 0;
}

.blog-card-hero .blog-card-media {
	flex: 0 0 58%;
	max-width: 58%;
}

.blog-card-hero .blog-card-body {
	flex: 1 1 0;
}

/* Card row gutters -------------------------------------------------------
   The theme's .col-gap-2 opens a 90px trough between columns, which is
   twice what the blog cards want. Halved for the secondary pair, the archive
   grid, the cards band and the related articles grid; the negative row
   margins come down to match so the outer edges stay flush with the content
   beside them. Scoped to these rows so the rest of the site keeps its own
   spacing. */

@media (min-width: 1200px) {

	.blog-featured .row.col-gap-2,
	.blog-archive .blog-grid.col-gap-2,
	.blog-cards .blog-cards-grid.col-gap-2,
	.blog-related .blog-related-grid.col-gap-2 {
		margin-left: calc((var(--default-gutter-x) * 1.5) / -1);
		margin-right: calc((var(--default-gutter-x) * 1.5) / -1);
	}

	.blog-featured .row.col-gap-2 > *,
	.blog-archive .blog-grid.col-gap-2 > *,
	.blog-cards .blog-cards-grid.col-gap-2 > *,
	.blog-related .blog-related-grid.col-gap-2 > * {
		padding-left: calc(var(--default-gutter-x) * 1.5);
		padding-right: calc(var(--default-gutter-x) * 1.5);
	}
}

/* Bootstrap's .mt-3 is 1rem !important, so the gap under the hero card
   needs to outrank it. */

.blog-featured .row.mt-3 {
	margin-top: 4rem !important;
}

/* Filters ---------------------------------------------------------------- */

.blog-filters .facetwp-facet {
	margin-bottom: 0;
}

.blog-filters .form-select {
	min-width: 12rem;
}

.blog-chips {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
}

.blog-chips[hidden] {
	display: none;
}

.blog-chips .applied-label {
	opacity: 0.7;
}

.filter-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.25rem 0.75rem;
	border: 1px solid currentColor;
	border-radius: 100px;
	background: none;
	font-family: 'Inter', sans-serif;
	font-weight: 400;
	font-size: var(--blog-text-meta, 15px);
	line-height: 155%;
	cursor: pointer;
}

.filter-chip i {
	font-size: 0.625rem;
}

.filter-chip:hover {
	background: #000;
	color: #fff;
}

.filter-chip-clear {
	background: none;
	border: 0;
	padding: 0;
	text-decoration: underline;
	text-underline-offset: 0.25em;
	cursor: pointer;
}

/* Pager ------------------------------------------------------------------ */

.blog-archive .facetwp-facet.facetwp-facet-blog_pager .facetwp-load-more,
.blog-archive .facetwp-facet.facetwp-facet-blog_pager a.facetwp-load-more {
	display: inline-block;
	box-sizing: border-box;
	padding: 0.75rem 2rem;
	margin: 0;
	border: 1px solid #000;
	border-radius: 100px;
	background-color: transparent;
	background-image: none;
	color: #000;
	font-family: inherit;
	font-size: 0.9375rem;
	line-height: 1.4;
	text-decoration: none;
	cursor: pointer;
	appearance: none;
	-webkit-appearance: none;
}

.blog-archive .facetwp-facet.facetwp-facet-blog_pager .facetwp-load-more:hover,
.blog-archive .facetwp-facet.facetwp-facet-blog_pager a.facetwp-load-more:hover {
	background-color: #000;
	color: #fff;
}

.facetwp-facet-blog_count {
	margin-bottom: 0;
}

/* Loading state ---------------------------------------------------------- */

.facetwp-template.is-loading {
	opacity: 0.4;
	transition: opacity 0.2s ease;
}

/* ==========================================================================
   Article
   ========================================================================== */

/* Header ----------------------------------------------------------------- */

.blog-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0;
}

.blog-tag {
	display: inline-block;
	padding: 0.25rem 0.75rem;
	border: 1px solid var(--color-grey-darker);
	border-radius: 100px;
	color: var(--color-secondary);
	text-decoration: none;
	transition: var(--transition);
}

.blog-tag:hover {
	border-color: var(--color-primary);
	background-color: var(--color-primary);
	color: var(--color-white);
}

/* Byline column. Author block, then a ruled row carrying the date and read
   time, then the share row underneath. */

.blog-byline {
	display: flex;
	align-items: center;
	gap: 0.75rem;
}

.blog-byline-image {
	width: 48px;
	height: 48px;
	flex: 0 0 48px;
	overflow: hidden;
	border-radius: 50%;
}

.blog-byline-image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.blog-byline-detail {
	display: flex;
	flex-direction: column;
	gap: 0.125rem;
}

.blog-byline-name {
	color: var(--color-primary);
	font-family: 'Lexend Deca', sans-serif;
	font-weight: 500;
}

.blog-byline-link {
	color: var(--color-secondary);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.blog-byline-link:hover {
	color: var(--color-primary);
}

.blog-byline-meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	margin-top: var(--default-gutter-y);
	padding-top: var(--default-gutter-y);
	border-top: 1px solid var(--color-grey-darker);
	color: var(--color-secondary);
}

.blog-article-header .blog-share {
	margin-top: calc(var(--default-gutter-y) / 1.5);
}

/* Share ------------------------------------------------------------------ */

.blog-share {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.75rem;
}

.blog-share-label {
	color: var(--color-secondary);
}

.blog-share-list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.blog-share-list li {
	margin: 0;
}

.blog-share-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border: 1px solid var(--color-grey-darker);
	border-radius: 50%;
	color: var(--color-primary);
	text-decoration: none;
	transition: var(--transition);
}

.blog-share-link i {
	font-size: var(--text-size-sm);
	line-height: 1;
}

.blog-share-link:hover {
	border-color: var(--color-primary);
	background-color: var(--color-primary);
	color: var(--color-white);
}

.blog-share-copy {
	padding: 0.5rem 1rem;
	border: 1px solid var(--color-grey-darker);
	border-radius: 100px;
	background: none;
	color: var(--color-primary);
	font-family: inherit;
	line-height: 1.4;
	cursor: pointer;
	transition: var(--transition);
}

.blog-share-copy:hover {
	border-color: var(--color-primary);
	background-color: var(--color-primary);
	color: var(--color-white);
}

.blog-share-copy[hidden] {
	display: none;
}

.blog-share-copy-done {
	display: none;
}

.blog-share-copy.copied .blog-share-copy-idle {
	display: none;
}

.blog-share-copy.copied .blog-share-copy-done {
	display: inline;
}

/* Featured image --------------------------------------------------------- */

.blog-article-image {
	margin: 0;
}

/* Letterbox. The markup carries Bootstrap's .ratio-16x9, which at the
   container width stands over 800px tall and pushes the whole article below
   the fold. The design crops it much shallower, so the ratio variable is
   reset here rather than changing the class in the markup, which would lose
   the .ratio fallback. */

.blog-article-image .ratio {
	--bs-aspect-ratio: 45%;
}

/* The header's 90px bottom padding and the body's 60px top padding stacked to
   150px of white between the image caption and the first line of the article.
   The design leaves a couple of lines, so the pair is brought down to 45px
   together. */

.content-section.blog-article-header {
	padding-bottom: var(--default-gutter-y);
}

.content-section.blog-article-body {
	padding-top: calc(var(--default-gutter-y) * 2);
}

.blog-article-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.blog-caption {
	margin: 0.75rem 0 0;
	color: var(--color-secondary);
	opacity: 0.8;
}

/* In this article -------------------------------------------------------- */

/* The panel is flat in the design, a heading over a ruled list, so it takes
   no padding-wrapper, border or shadow of its own. Bootstrap's .sticky-top
   is top: 0 and the theme only offsets it for padding-wrapper, so the
   offset is set here. */

.blog-toc.sticky-top {
	top: calc(var(--default-gutter-y) * 2);
	z-index: 1;
}

.blog-toc-list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.blog-toc-item {
	margin: 0;
	border-bottom: 1px solid var(--color-grey-darker);
}

.blog-toc-item:first-child {
	border-top: 1px solid var(--color-grey-darker);
}

.blog-toc-level-3 .blog-toc-link {
	padding-left: 1rem;
}

.blog-toc-link {
	display: block;
	padding: 0.625rem 0;
	color: var(--color-secondary);
	line-height: 1.4;
	text-decoration: none;
	transition: var(--transition);
}

.blog-toc-link:hover,
.blog-toc-link.active {
	color: var(--color-primary);
}

.blog-toc-link.active {
	font-weight: 500;
}

/* Body ------------------------------------------------------------------- */

.blog-content > *:not(:last-child) {
	margin-bottom: var(--default-gutter-y);
}

.blog-content :is(h2, h3, h4) {
	margin-top: calc(var(--default-gutter-y) * 2.5);
	scroll-margin-top: calc(var(--default-gutter-y) * 6);
}

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

.blog-content h2 {
	font-size: var(--text-size-lg);
}

.blog-content h3 {
	font-size: var(--text-size-md);
}

.blog-content img {
	max-width: 100%;
	height: auto;
	border-radius: 12px;
}

.blog-content .wp-caption {
	max-width: 100%;
	margin: calc(var(--default-gutter-y) * 2) 0;
}

.blog-content .wp-caption img {
	display: block;
	width: 100%;
}

.blog-content .wp-caption-text,
.blog-content figcaption {
	margin: 0.75rem 0 0;
	color: var(--color-secondary);
	font-size: var(--text-size-sm);
	line-height: 1.5;
	opacity: 0.8;
}

.blog-content .alignleft,
.blog-content .alignright,
.blog-content .aligncenter {
	display: block;
	margin-left: auto;
	margin-right: auto;
}

/* Pull quote ------------------------------------------------------------- */

/* Scoped through .blog-content for the same reason as the course CTA below:
   the body's "> *:not(:last-child)" bottom margin is more specific and cut
   the space under the quote to a third of the space above it. */

.pull-quote,
.blog-content > .pull-quote:not(:last-child) {
	margin: calc(var(--default-gutter-y) * 3) 0;
	padding-left: calc(var(--default-gutter-x) * 2);
	border-left: 3px solid var(--color-grey-darker);
}

.pull-quote .title {
	margin-bottom: 0;
	line-height: 1.3;
}

.pull-quote-attribution {
	margin: var(--default-gutter-y) 0 0;
	color: var(--color-secondary);
	opacity: 0.8;
}

/* Featured product -------------------------------------------------------
   Not a card: no panel, rounding or shadow, and no padding wrapper, so the
   block sits straight on the white column aligned to the body copy. */

/* The row's .col-gap-2 puts 45px of padding on both columns, which on the
   detail column is an indent the design does not have — the image's own
   right padding is already the whole gutter between the two. Left only: the
   right padding still holds the block off the edge of the column.

   Written long enough to beat the theme's own ".row.col-gap-2 > *", and from
   sm up only: below that the two columns are stacked full width, where the
   padding is what keeps the text aligned with the image above it. */

@media (min-width: 576px) {

	.blog-product-card .row.col-gap-2 > .blog-product-card-detail {
		padding-left: 0;
	}
}

.blog-product-card-image img {
	display: block;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: 12px;
}

.blog-product-card-label {
	margin: 0;
	text-transform: uppercase;
	letter-spacing: 0.08em;
}

/* Course CTA band -------------------------------------------------------- */

/* Two wrappers, one band. The full width section at the foot of the article
   and the contained panel the [course_cta] shortcode drops into the body
   share everything below; only the background and the text colour switch
   with the style, so nothing here is written twice. */

.blog-course-cta-dark {
	background-color: var(--color-primary);
}

.blog-course-cta-dark .title,
.blog-course-cta-dark .boxen p {
	color: var(--color-white);
}

/* The light variant sits on the white article column, so it takes the same
   grey as .panel rather than a colour of its own, and leaves the text at the
   body colour. */

.blog-course-cta-light {
	background-color: var(--color-grey);
}

/* Dropped into the body by the shortcode the card is a sibling of the
   paragraphs, so it needs its own rhythm. Scoped through .blog-content to
   outrank the body's own "> *:not(:last-child)" bottom margin, which is the
   more specific selector and would otherwise leave a larger gap above the
   card than below it. */

.blog-content > .blog-course-cta,
.blog-content > .blog-course-cta:not(:last-child) {
	margin: calc(var(--default-gutter-y) * 2) 0;
}

/* The button on this band is the shared dark-band inversion, defined once
   with the newsletter band further down. Nothing bespoke here. */

/* Related articles ------------------------------------------------------- */

.blog-related-all {
	color: var(--color-secondary);
	text-decoration: underline;
	text-underline-offset: 0.2em;
	white-space: nowrap;
}

.blog-related-all:hover {
	color: var(--color-primary);
}

/* Author bio card --------------------------------------------------------
   A rounded grey card on white in the design, not a grey band across the
   page, so the section is white and the card takes the theme's
   padding-wrapper panel rounded pattern.

   The section carries no padding of its own: the article body above it and
   the related band below it already bring 90px and 60px, and the section's
   own padding on top of those pushed the card far too far from both. */

.content-section.blog-author-bio {
	padding-top: 0;
	padding-bottom: 0;
}

.blog-author-bio-image {
	width: 120px;
	height: 120px;
	overflow: hidden;
	border-radius: 50%;
}

.blog-author-bio-image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.blog-author-bio-label {
	margin: 0;
	text-transform: uppercase;
	letter-spacing: 0.08em;
}
/* Cards band -------------------------------------------------------------
   The repeatable three-up component. The band itself only owns the header
   row; the cards inside are either .blog-card (articles) or the device card
   below, so nothing here duplicates the article card styles. */

.blog-cards-all {
	display: inline-flex;
	align-items: center;
	gap: 0.6em;
	color: var(--color-secondary);
	text-decoration: none;
	white-space: nowrap;
}

.blog-cards-all-label {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* Bare arrow rather than the button's 34px chip, so the control still reads
   as a text link. Same glyph as the button icon. */

.blog-cards-all:after {
	content: '\f101';
	font-family: 'flaticon_plasma_pen';
	font-style: normal;
	font-weight: normal;
	font-variant: normal;
	line-height: 100%;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	transition: transform 0.4s ease;
}

.blog-cards-all:hover {
	color: var(--color-primary);
}

.blog-cards-all:hover:after {
	transform: translateX(0.25em);
}

/* Cards stretch so a short blurb still leaves the actions on a common line
   across the row. */

.blog-cards-grid > [class*="col-"] {
	display: flex;
}

.blog-cards-grid > [class*="col-"] > * {
	width: 100%;
}

/* Device card ------------------------------------------------------------
   White panel on the grey band, matching the padded card pattern used by
   the highlighted content cards. */

.blog-device-card {
	display: flex;
	flex-direction: column;
	overflow: hidden;
	background-color: var(--color-white);
	border-radius: 0.75rem;
	box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
}

.blog-device-card-media {
	display: block;
	overflow: hidden;
	line-height: 0;
}

.blog-device-card-media img {
	display: block;
	width: 100%;
	height: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	transition: transform 0.4s ease;
}

.blog-device-card:hover .blog-device-card-media img {
	transform: scale(1.03);
}

.blog-device-card-body {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	flex: 1 1 auto;
	padding: calc(var(--default-gutter-y) * 1.5) calc(var(--default-gutter-x) * 1.5);
}

.blog-device-card-title {
	margin: 0;
}

.blog-device-card-title a {
	color: var(--color-primary);
	text-decoration: none;
}

.blog-device-card-title a:hover {
	color: var(--color-secondary);
}

.blog-device-card-description p {
	margin: 0;
}

/* Price row: the "+ VAT" suffix is secondary to the figure, so it drops back
   to body weight and the muted colour rather than carrying the title style. */

.blog-device-card-price {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.5rem;
	margin: 0;
	margin-top: auto;
}

.blog-device-card-price del {
	opacity: 0.5;
}

.blog-device-card-vat {
	font-weight: 400;
	font-size: var(--blog-text-body-lg, 18px);
	opacity: 0.55;
}

/* Shared with the featured product card in the article body, which carries
   the same finance line. */

.blog-device-card-finance,
.blog-product-card-finance {
	margin: 0;
	font-size: var(--blog-text-caption, 13px);
}

/* Side by side, each growing to share the row. flex-basis stays auto so a
   button can never be squeezed narrower than its own label plus icon chip;
   the pair wraps to two rows instead when the card is too narrow. */

.blog-device-card-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
}

/* Natural width, exactly as on the homepage. The buttons must NOT be sized
   by the row: the hover animation works by the arrow chip's margin growing
   and carrying the pill's right edge with it, which is only possible while
   the width is content-driven. Give them a flex-basis and the pill is stuck
   at the row's width, so the extra margin pushes the label left instead.

   Shrinking has to be off too, not just the basis. The pair very nearly
   fills the card, so with shrink enabled the row absorbs the growing margin
   by squeezing the pills and the hover does nothing. They keep their natural
   width and wrap to two rows when the card is too narrow. */

.blog-device-card-actions .button {
	flex: 0 0 auto;
}

/* Newsletter band --------------------------------------------------------
   Sits directly on the footer, so it carries no bottom rounding and the
   footer provides the next edge. */

.blog-newsletter {
	background-color: var(--color-primary);
}

.blog-newsletter .title,
.blog-newsletter .boxen p {
	color: var(--color-white);
}

/* The site's .newsletter-signup is a single merged control: the footer
   absolutely positions the submit inside the field. This band wants the two
   as separate elements, so the footer's positioning is undone here and the
   form laid out as a row. Scoped to .blog-newsletter, so the footer column
   keeps the merged treatment. */

.blog-newsletter .newsletter-signup {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.75rem;
}

/* Not allowed to grow: the field is capped at its 320px design width, so a
   growing wrapper would only open dead space between it and the button. */

.blog-newsletter .newsletter-signup .gform_body {
	flex: 0 1 320px;
	min-width: 0;
}

.blog-newsletter .newsletter-signup .gform_footer {
	position: static;
	top: auto;
	right: auto;
	flex: 0 0 auto;
	width: auto;
	margin: 0;
	padding: 0;
}

/* Field */

.blog-newsletter .gform_wrapper .newsletter-signup .gform_fields .gfield input[type="email"] {
	box-sizing: border-box;
	width: 100%;
	max-width: 320px;
	height: 51px;
	padding: 20px;
	background-color: var(--color-white);
	border: 1px solid var(--color-white);
	border-radius: 12px;
	font-size: var(--blog-text-meta, 15px);
	font-weight: 400;
	line-height: 155%;
	color: var(--color-primary);
}

.blog-newsletter .gform_wrapper .newsletter-signup .gform_fields .gfield input[type="email"]::placeholder {
	color: var(--color-primary);
	opacity: 1;
}

/* Dark-band buttons -------------------------------------------------------
   The base solid pill inverted for a primary ground, with the arrow chip
   inverted to match. Same treatment the landing page gives its dark bands.
   Hover is left entirely to the base .button, so the only thing that moves
   is the arrow chip sliding right and taking the pill's width with it.

   The :not(.outline) guard keeps the outline/reverse variant available on
   these bands for a secondary action.

   Specificity matters here. The base hover selector is five classes
   (.button:not(.label, .outline, :disabled):hover), so these must stay below
   that or they win the hover too and the button goes inert. Hence the short
   .blog-newsletter .gform_footer selector rather than the full path. */

.blog-course-cta-dark .button:not(.outline),
.blog-newsletter .gform_footer .button:not(.outline) {
	background-color: var(--color-white);
	color: var(--color-primary);
}

.blog-course-cta-dark .button:not(.outline):after,
.blog-newsletter .gform_footer .button:not(.outline):after {
	background-color: var(--color-primary);
	color: var(--color-white);
}

/* Re-rendered submit ------------------------------------------------------
   The rules above dress the button this band renders, which carries .button
   and a real "Sign up" label. That markup only survives the first render:
   the form posts over AJAX, and on a validation error Gravity Forms rebuilds
   the button on the server, outside the template, so it comes back as the
   site's bare icon button with no .button class and no label.

   These rules rebuild the same pill from the element itself, so the button
   looks identical whichever way it arrived. Matched on :has(> .icon-wrapper),
   which is true only of the bare version, so the labelled button is left
   entirely to the rules above and the label is never generated twice. */

.blog-newsletter .gform_footer button:has(> .icon-wrapper) {
	display: flex;
	align-items: center;
	justify-content: space-between;
	min-height: 46px;
	padding: 6px 6px 6px calc(var(--default-gutter-x) * 2);
	background-color: var(--color-white);
	border: 0;
	border-radius: 50vh;
	font-size: var(--text-size);
	font-weight: 500;
	color: var(--color-primary);
	white-space: nowrap;
	cursor: pointer;
	transition: var(--transition-background), var(--transition-color);
}

/* The label has to be generated here because the rebuilt markup has none.
   The button keeps its own aria-label either way, so the accessible name
   never depends on generated content. */

.blog-newsletter .gform_footer button:has(> .icon-wrapper):before {
	content: 'Sign up';
}

/* Base .icon-wrapper is 60px; the footer scopes it to 34px for its own
   merged control, and that scoping does not reach this band. Colours already
   come from .newsletter-signup .gform_footer .icon-wrapper in style.css.

   The spacing is a margin rather than a flex gap so it can animate: the base
   .button grows its chip's margin-left on hover and lets the pill widen with
   it, and a gap would leave nothing to transition. Values and easing match
   .button:not(.iconless):after so both versions move identically. */

.blog-newsletter .gform_footer button > .icon-wrapper {
	flex: 0 0 34px;
	width: 34px;
	height: 34px;
	margin-left: var(--default-gutter-x);
	transition: var(--transition-background), var(--transition-color), margin 0.5s ease-in-out;
}

.blog-newsletter .gform_footer button:hover > .icon-wrapper {
	margin-left: calc(var(--default-gutter-x) * 2);
}

/* =========================================================================
   Author profile
   ========================================================================= */

/* Header ------------------------------------------------------------------
   Portrait on the left, everything else in the column beside it. The
   breadcrumb is the first line of that column rather than the grey band the
   article template uses, so it loses the band's own type colour and sits on
   the white with the rest of the text. */

.blog-author-profile-crumbs p {
	margin: 0;
}

/* Half the usual band padding underneath. Whichever of the two columns runs
   longer sets the bottom of this section, and on most profiles that is the
   portrait rather than the copy: the full amount under an image that is
   already taller than the text beside it drops the stats band much further
   down the page than the design puts it. The stats band's own top padding
   carries the rest of the distance. */

.content-section.blog-author-profile {
	padding-bottom: calc(var(--default-gutter-y) * 2);
}

/* A portrait crop, not the letterbox the article hero uses. The ratio is set
   on the wrapper and the image fills it, so a square or landscape upload
   still fills the frame instead of leaving the column short. */

.blog-author-profile-image {
	aspect-ratio: 4 / 5;
}

.blog-author-profile-image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.blog-author-profile-role {
	margin: 0;
}

.blog-author-profile-bio p:last-child {
	margin-bottom: 0;
}

/* Credentials -------------------------------------------------------------
   Label and detail on one line with a rule under each. The rule is drawn on
   the top of every row plus the bottom of the last, which gives the closed
   set of lines in the design without a border on a wrapper that would sit
   tight against the rows. */

.blog-author-credentials {
	margin: 0;
}

.blog-author-credential {
	display: flex;
	gap: var(--default-gutter-x);
	padding: calc(var(--default-gutter-y) * 0.8) 0;
	border-top: 1px solid var(--color-grey-darker);
}

.blog-author-credential:last-child {
	border-bottom: 1px solid var(--color-grey-darker);
}

.blog-author-credential dt {
	flex: 0 0 30%;
	font-weight: normal;
	color: var(--color-secondary);
}

.blog-author-credential dd {
	flex: 1 1 auto;
	margin: 0;
	color: var(--color-secondary);
}

/* Stats band --------------------------------------------------------------
   A rounded black card at container width, the same shape as the dark course
   CTA, not a full bleed band: the white page runs down both sides of it.

   No bottom padding on the section. The cards band underneath already brings
   its own 90px, and the design does not leave anything like the 180px that
   two full sections back to back would give. */

.content-section.blog-author-stats {
	padding-bottom: 0;
}

/* Deeper than the padding-wrapper's own 30px: the figures need room above
   and below them to read as a band rather than a strip. */

.blog-author-stats-band {
	padding-top: calc(var(--default-gutter-y) * 3);
	padding-bottom: calc(var(--default-gutter-y) * 3);
	background-color: var(--color-primary);
}

.blog-author-stat {
	display: flex;
	flex-direction: column;
	gap: 0.4em;
}

.blog-author-stat-figure,
.blog-author-stat-label {
	color: var(--color-white);
}

.blog-author-stat-label {
	opacity: 0.8;
}

/* Two cards bands back to back ------------------------------------------
   "Also by this author" and "Related Courses" are the same component twice,
   so left alone they put a full section's padding on both sides of the join
   and open a trough about twice what the design leaves. The second band's top
   padding comes down; the pair then reads as two rows of one block rather
   than two unrelated bands. Scoped to the adjacency, so a cards band anywhere
   else keeps its own spacing.

   The first band's 90px already reads as a full band break, so the second
   contributes nothing rather than doubling it.

   Scoped to the author archive rather than to the adjacency alone: an article
   can carry two cards bands from its own repeater, and those are already
   signed off with a full break between them. */

body.author .blog-cards + .blog-cards {
	padding-top: 0;
}

/* The band's own footer control. Bootstrap's .mt-3 is 1rem here, which is the
   right step between a heading and the grid under it but far too tight under
   a whole row of cards. */

.blog-cards-footer {
	margin-top: calc(var(--default-gutter-y) * 4) !important;
}

/* The base .button is display: flex, so on its own in a full width column it
   stretches to the whole container. It is a pill that fits its label, so it
   goes inline and the column's text-align centres it. */

.blog-cards-footer .button {
	display: inline-flex;
}

/* Course card -------------------------------------------------------------
   The video still, the course, and who wrote it. No price and no buy control:
   this card sends people to the training, not to the basket, which is what
   separates it from the device card above. */

.blog-course-card {
	display: flex;
	flex-direction: column;
	gap: var(--default-gutter-y);
}

.blog-course-card-media {
	position: relative;
	display: block;
	aspect-ratio: 4 / 3;
}

.blog-course-card-media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;

	/* Greyscale in the design, so the colour in the row comes from the
	   article cards above rather than from the stills. Restored on hover so
	   the card still answers the pointer. */

	filter: grayscale(1);
	transition: filter 0.4s ease, transform 0.4s ease;
}

.blog-course-card-media:hover img {
	filter: grayscale(0);
	transform: scale(1.03);
}

.blog-course-card-play {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	display: flex;
	align-items: center;
	justify-content: center;
	width: 72px;
	height: 72px;
	border-radius: 50%;
	background-color: var(--color-white);
	color: var(--color-primary);
	font-size: 1.5rem;
	transition: transform 0.4s ease;
}

/* The glyph's own bearing sits it left of centre in the disc. */

.blog-course-card-play i {
	transform: translateX(0.08em);
}

.blog-course-card-media:hover .blog-course-card-play {
	transform: translate(-50%, -50%) scale(1.08);
}

.blog-course-card-duration {
	position: absolute;
	right: var(--default-gutter-x);
	bottom: var(--default-gutter-x);
	padding: 0.35em 0.9em;
	border-radius: 999px;
	background-color: var(--color-white);
	color: var(--color-primary);
	line-height: 1;
}

.blog-course-card-body {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	gap: calc(var(--default-gutter-y) * 0.6);
}

.blog-course-card-title {
	margin: 0;
}

.blog-course-card-title a {
	color: var(--color-primary);
	text-decoration: none;
}

.blog-course-card-title a:hover {
	color: var(--color-secondary);
}

.blog-course-card-description p:last-child {
	margin-bottom: 0;
}

/* A credit, not a link: it names the author whose page the reader is already
   on. Matches the card byline's typography without taking .blog-card-author-name,
   which carries a hover underline and so reads as a link that does nothing. */

.blog-course-card-credit {
	font-family: 'Inter', sans-serif;
	font-weight: 400;
	font-size: var(--blog-text-meta, 15px);
	line-height: 155%;
	color: var(--color-primary);
}

/* The byline is pushed to the foot of the card so it lands on a common line
   across the row however long each blurb runs. */

.blog-course-card-author {
	margin-top: auto;
	padding-top: calc(var(--default-gutter-y) * 0.4);
}
