/*
Theme Name: 15Zine Child (handbag.reviews refresh)
Template: 15zine
Description: Child theme for the handbag.reviews type/colour refresh. Overrides load after the parent theme's compiled stylesheet.
Version: 2.60.1
*/

/* ==========================================================================
   Design tokens (DESIGN-SPEC.md)
   ========================================================================== */

:root {
	/* Colour */
	--ink: #16130F;
	--ink-body: #26221D;
	--ink-soft: #3A342D;
	--muted: #4A443C;
	--muted-2: #6B6459;
	--muted-3: #8A8278;
	--accent: #8E2A2A;
	--good: #2F6B4F;
	--page: #E8E4DE;
	--surface: #FFFFFF;
	--surface-2: #F7F4F1;
	--line: #E4DED6;
	--line-2: #CFC8BE;
	--placeholder: #DED8D0;

	/* Type */
	--font-serif: 'Bodoni Moda', Georgia, serif;
	--font-sans: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
}

/* ==========================================================================
   Headings — real headlines get Bodoni, sentence case, weight 400.
   Parent theme applies uppercase/letter-spacing/Montserrat via highly
   specific contextual selectors, so overrides here use matching specificity
   plus !important on the handful of properties Step 1 is scoped to change.
   ========================================================================== */

/* Review post H1 */
.entry-title.title {
	font-family: var(--font-serif) !important;
	font-size: 56px !important;
	font-weight: 400 !important;
	line-height: 1.05 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
	margin-top: 14px !important;
	margin-bottom: 18px !important;
}

/* Round 2 punch list, item 18: rendered around 68px on mobile (the theme's
   own responsive scaling, on top of the 56px above), wrapping to three
   lines and filling the screen before any content. */
@media (max-width: 767px) {
	.entry-title.title {
		font-size: 34px !important;
		line-height: 1.15 !important;
	}
}

/* Card / list / grid post titles (home, archive, related posts, widgets) */
.cb-post-title,
.title-m .title,
.title-l .title,
.title-xl .title,
.preview-classic .title,
.preview-thumbnail .title,
.block-wrap .cb-article-small .cb-post-title,
.block-wrap-fs.block-wrap-51 .block-title-wrap .title,
.codetipi-15zine-widget .block-wrap .preview-slider .title,
.codetipi-15zine-widget .block-wrap .preview-grid .title {
	font-family: var(--font-serif) !important;
	font-weight: 400 !important;
	line-height: 1.15 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
}

.title-m .title,
.preview-classic .title,
.preview-thumbnail .title,
.cb-post-title {
	font-size: 23px !important;
}

.title-l .title {
	font-size: 32px !important;
}

.title-xl .title {
	font-size: 44px !important;
}

/* In-article section headings (Gutenberg block headings written into the
   post body, e.g. "Materials and colour-ways") — Section H2 role */
.entry-content h2.wp-block-heading {
	font-family: var(--font-serif) !important;
	font-size: 32px !important;
	font-weight: 400 !important;
	line-height: normal !important;
	text-transform: none !important;
	letter-spacing: normal !important;
	margin-top: 36px !important;
	margin-bottom: 16px !important;
}

/* Review-article H2s specifically (e.g. "Practicality and Functionality",
   "Mombasa Bag Sizes and Dimensions") read too large/wrapped awkwardly
   on a real phone at the shared 32px/line-height:normal desktop value --
   per Christa's on-device check. Bumped and tightened for mobile only,
   review posts only; non-review articles and desktop both keep the
   unscoped 32px rule above untouched. */
@media (max-width: 767px) {
	body.hr-has-review .entry-content h2.wp-block-heading {
		font-size: 35px !important;
		line-height: 1.1 !important;
	}
}

.entry-content h3.wp-block-heading {
	font-family: var(--font-serif) !important;
	font-size: 23px !important;
	font-weight: 400 !important;
	line-height: 1.15 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
}

/* 404 page title — a real headline, not a label */
.error404-title-wrap,
.error404-title-wrap p {
	font-family: var(--font-serif) !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
}

/* Author bio box: name + job title read as normal text, not a shout */
.author-box .title,
.author-box .author-job {
	text-transform: none !important;
	letter-spacing: normal !important;
}

/* Next/previous post navigation: only the linked article's real title
   converts — the "Previous Article" / "Next Article" caption stays a
   label. Fixed in round 2 (item 13): this originally targeted
   .cb-read-title, which is actually the caption's own class
   (.cb-read-previous-title.cb-read-title) -- the real title link uses
   .cb-previous-title/.cb-next-title.cb-title.title instead, so the
   caption was wrongly getting Bodoni treatment while the actual title
   never did. */
.cb-next-previous .cb-previous-title.cb-title.title,
.cb-next-previous .cb-next-title.cb-title.title {
	font-family: var(--font-serif) !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
}

/* FAQ / accordion headers */
.cb-toggler .cb-toggle,
.cb-accordion a {
	text-transform: none !important;
	letter-spacing: normal !important;
}

/* Archive/tag/category description — despite carrying a "subtitle" class
   (which elsewhere means a small-caps label), this is genuine body copy
   introducing the listing, not a label. */
.taxonomy-description {
	text-transform: none !important;
	letter-spacing: normal !important;
	font-size: 17px !important;
	line-height: 1.65 !important;
}

/* ==========================================================================
   Body copy — DM Sans, comfortable measure
   ========================================================================== */

.entry-content {
	font-family: var(--font-sans);
	font-size: 18px;
	line-height: 1.7;
	color: var(--ink-body);
}

/* Cap prose measure only — score widgets, disclosure banners, and other
   UI modules are not body text and should keep their own natural width.
   Widened 620->680px per Christa's direct request; still a max-width, so
   mobile padding/behavior below this breakpoint is unaffected. */
.entry-content > p,
.entry-content > ul,
.entry-content > ol,
.entry-content > blockquote,
.entry-content > h2,
.entry-content > h3,
.entry-content > h4 {
	max-width: 680px;
}

/* Non-review articles get a wider 760px measure -- review posts keep 680px
   (an intentional difference, not an inconsistency to fix). */
body.single:not(.hr-has-review) .entry-content > p,
body.single:not(.hr-has-review) .entry-content > ul,
body.single:not(.hr-has-review) .entry-content > ol,
body.single:not(.hr-has-review) .entry-content > blockquote,
body.single:not(.hr-has-review) .entry-content > h2,
body.single:not(.hr-has-review) .entry-content > h3,
body.single:not(.hr-has-review) .entry-content > h4 {
	max-width: 760px;
}

/* Inline media: same 760px cap as body copy, unless a block is deliberately
   marked full/wide-width -- native aspect ratio and height are left alone
   either way, only the max-width changes. */
body.single:not(.hr-has-review) .entry-content > figure:not(.alignfull):not(.alignwide),
body.single:not(.hr-has-review) .entry-content > img:not(.alignfull):not(.alignwide) {
	max-width: 760px;
	height: auto;
}

/* ==========================================================================
   Meta / byline
   ========================================================================== */

.byline-part.author,
.byline-part.cb-date.date,
.byline-part.separator {
	text-transform: none !important;
	letter-spacing: normal !important;
	font-family: var(--font-sans);
	font-size: 13px;
	color: var(--muted-2);
}

/* Round 2 punch list, item 11: this row read as grey filled pills
   (REVIEWS / <3 2 / 3 VIEWS), and the like/view counts were noise directly
   under the H1. Revises the original Step 1 call to keep the category
   eyebrow uppercase+tracked as "the one legitimate label" here -- the spec
   colour table's --accent eyebrow is for card contexts; in this single-post
   meta row it reads as plain metadata alongside author/date, not a design
   accent competing with the H1. */
.byline-part.cats {
	font-family: var(--font-sans);
	font-size: 13px;
}

.byline-shaded .cats a {
	background-color: transparent !important;
	color: var(--muted-2) !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
	padding: 0 !important;
	height: auto !important;
}

.byline-shaded .cats a:hover {
	color: var(--ink) !important;
}

/* Likes/views still dropped everywhere else (card-loop bylines, the
   hidden byline-10 mobile strip) -- restored ONLY in the single-post
   primary meta row (byline-3), per Christa's later instruction, styled
   as plain muted metadata rather than the "grey filled pill" look that
   got them dropped the first time. !important on both rules below: the
   parent theme's own compiled CSS targets these same classes at higher
   specificity than a bare .byline-part.likes-count selector, so without
   !important the base hide rule silently lost and byline-10's copy of
   the like count rendered as a second, duplicate heart next to the
   category tag -- confirmed live on both staging and production. */
.byline-part.likes-count,
.byline-part.view-count {
	display: none !important;
}

article .cb-byline.byline-3 .byline-part.likes-count,
article .cb-byline.byline-3 .byline-part.view-count {
	display: inline-flex !important;
	align-items: center;
	font-family: var(--font-sans);
	font-size: 13px;
	color: var(--muted-2);
}

article .cb-byline.byline-3 .tipi-like-count {
	color: var(--muted-2);
	text-decoration: none;
}

article .cb-byline.byline-3 .likes-heart {
	font-size: 13px;
}

article .cb-byline.byline-3 .codetipi-15zine-i-heart-o {
	color: var(--muted-2);
}

article .cb-byline.byline-3 .codetipi-15zine-i-heart {
	color: var(--accent);
}

article .cb-byline.byline-3 .tipi-value {
	margin-left: 4px;
}

/* ==========================================================================
   Comment form labels — sentence case reads more natural
   ========================================================================== */

.comment-form label {
	text-transform: none !important;
	letter-spacing: normal !important;
}

/* ==========================================================================
   Search field — never force-uppercase what someone is typing
   ========================================================================== */

.content-search .search-field {
	text-transform: none !important;
	letter-spacing: normal !important;
}

/* ==========================================================================
   Step 2 — Colour and spacing tokens
   ========================================================================== */

/* Page background outside the content column. Was --page (cream), but that
   put a visible seam between the resting-state margin (correctly cream)
   and the header/footer areas, which independently render white/--surface
   or --ink depending on component -- chasing every place that seam could
   show through (nav sticky states, page-builder templates, etc.) added up
   fast for a difference that's barely perceptible anyway. --surface
   (white) removes the seam entirely and matches the spec's own steer
   toward keeping this to two background colours total, not three. */
html,
body {
	background-color: var(--surface);
}

.content-bg {
	background-color: var(--surface);
	border: 1px solid var(--line-2);
}

/* The masthead (wordmark row + nav row) is the top of the same white
   surface as the article, not a separate band — their background layers
   are transparent by default, which let the cream page colour show through
   as a stray strip between the logo and the nav links. */
#masthead .bg-area,
.menu-bg-area.main-navigation-border {
	background-color: var(--surface);
}

#masthead .bg-area {
	border-bottom: 1px solid var(--line);
}

/* No rounded corners or drop shadows anywhere, except things that are
   circular by convention (avatars, profile photos) — those keep their
   border-radius so a headshot doesn't get squared off. */
*:not(img.avatar):not(.avatar img):not([class*="avatar"]) {
	border-radius: 0 !important;
	box-shadow: none !important;
}

/* Content links: accent red, underlined, ink on hover. Scoped to actual
   article/content areas — nav, buttons, and tags keep their own colour
   treatment and are untouched here. Christa's call: underline body-copy
   links everywhere regardless of what the design reference shows, so
   they read as links on their own rather than relying on colour alone. */
.entry-content a,
.author-box a,
.commentlist a {
	color: var(--accent);
	text-decoration: underline;
}

.entry-content a:hover,
.author-box a:hover,
.commentlist a:hover {
	color: var(--ink);
}

.entry-content a:focus-visible,
.author-box a:focus-visible,
.commentlist a:focus-visible {
	color: var(--ink);
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

/* ==========================================================================
   Step 4 — Breadcrumbs
   ========================================================================== */

.breadcrumbs-wrap {
	font-family: var(--font-sans) !important;
	font-size: 12px !important;
	color: var(--muted-2) !important;
	margin-bottom: 20px;
}

.breadcrumbs-wrap a {
	color: var(--muted-2);
}

.breadcrumbs-wrap a:hover {
	color: var(--ink);
}

/* ==========================================================================
   Step 10 — Navigation
   ========================================================================== */

/* Search sits in the same row as the wordmark, positioned top-right --
   #masthead needs a positioning context for that (it's static by default). */
#masthead {
	position: relative !important;
}

/* Desktop only: absolute top:40px/right:40px is measured against the
   desktop masthead's own height. The mobile header collapses into a
   hamburger menu with a completely different (much shorter) box, so this
   same fixed offset was pushing the link below the header entirely,
   floating over whatever content came next -- the escaping "SEARCH" label
   from the round 2 punch list, item 17. Hidden on mobile instead of
   repositioned: the theme's own search icon already lives correctly inside
   the mobile menu (restored below), so nothing is lost. */
@media (min-width: 768px) {
	.hr-search-link {
		position: absolute;
		top: 40px;
		right: 40px;
		font-family: var(--font-sans);
		font-size: 12px;
		font-weight: 500;
		letter-spacing: 0.14em;
		text-transform: uppercase;
		color: var(--muted-2);
		text-decoration: none;
		cursor: pointer;
		z-index: 5;
	}

	.hr-search-link:hover {
		color: var(--ink);
	}

	/* The old nav-row search icon is redundant on desktop now that Search
	   lives in the utility row above -- but it's the only way to search on
	   mobile, so this is desktop-only, not global. */
	.main-navigation .menu-icons .cb-icon-search {
		display: none;
	}
}

@media (max-width: 767px) {
	.hr-search-link {
		display: none;
	}
}

/* Active nav item: flat ink text with an accent underline, not a filled
   block -- the filled block read as a rendering fault. Only covered
   .current-menu-item (true when the page itself is that nav target),
   which is why category/contact pages got the underline but individual
   posts didn't -- a post under Trending gets current-menu-parent (and
   current-post-parent, WordPress's post-specific equivalent) instead,
   never current-menu-item itself. Same treatment extended to those. */
.main-menu-bar-color-1 .current-menu-item > a,
.main-menu-bar-color-1 .current-menu-parent > a,
.main-menu-bar-color-1 .current-menu-ancestor > a,
.main-menu-bar-color-1 .current-post-parent > a,
.main-menu-bar-color-1 .current-post-ancestor > a {
	background: transparent !important;
	color: var(--ink) !important;
	border-bottom: 2px solid var(--accent) !important;
}

/* Brand list row, after the header. Same white-surface treatment. */
.hr-brand-row {
	max-width: 1280px;
	margin: 0 auto;
	background-color: var(--surface);
	border-top: 1px solid var(--line);
}

.hr-brand-row ul {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 22px;
	list-style: none;
	margin: 0;
	padding: 14px 40px;
}

.hr-brand-row a {
	font-family: var(--font-sans);
	font-size: 12px;
	color: var(--muted-2);
	text-decoration: none;
}

.hr-brand-row a:hover {
	color: var(--accent);
}

/* Mobile: the search utility row still folds into the existing mobile
   menu. Item 15: the brand row doesn't -- it was hidden entirely, putting
   brand pages two taps deep on phones. Single-line horizontally
   scrollable strip instead, hidden scrollbar, momentum scrolling on iOS. */
@media (max-width: 767px) {
	.hr-utility-row {
		display: none;
	}

	.hr-brand-row {
		max-width: 100%;
		border-bottom: 1px solid var(--line);
	}

	.hr-brand-row ul {
		flex-wrap: nowrap;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		padding: 21px 16px;
		align-items: center;
		/* Desktop's justify-content:center (see the base .hr-brand-row ul
		   rule) is wrong for a horizontally-scrollable strip: centering a
		   row wider than its container splits the overflow evenly on both
		   sides, so scrollLeft:0 shows the MIDDLE of the strip, not the
		   true start -- "Saint Laurent" sat ~72px off-screen to the left
		   even at rest. flex-start puts the first link flush against the
		   row's own left padding, reachable immediately; the row still
		   scrolls normally to reach the last link ("All brands"). */
		justify-content: flex-start !important;
	}

	.hr-brand-row ul::-webkit-scrollbar {
		display: none;
	}

	.hr-brand-row li {
		flex-shrink: 0;
	}

	/* Mock-up's mobile brand typography: uppercase, lightly tracked --
	   the desktop/mobile-shared base rule (.hr-brand-row a, further up)
	   is plain sentence case with no tracking. */
	.hr-brand-row a {
		text-transform: uppercase;
		letter-spacing: 0.06em;
		font-size: 11px;
	}
}

/* ==========================================================================
   Step 11 — Sidebar (home page half; review-post half waits on Step 8)
   ========================================================================== */

/* Widget titles: small-caps label, not the theme's default heavier
   treatment. Emoji hidden -- WordPress renders them as <img class="emoji">,
   so this is a real, safe removal, not just visual. */
.cb-sidebar-widget-title {
	font-family: var(--font-sans) !important;
	font-size: 11px !important;
	font-weight: 600 !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase;
	border-bottom: 1px solid var(--ink) !important;
	padding-bottom: 10px !important;
}

.cb-sidebar-widget-title img.emoji {
	display: none !important;
}

/* "Highest Rated" widget: drop the bar visualisation entirely -- title
   left, Bodoni score right, hairline between rows. (A thumbnail was
   tried here per earlier design feedback, then reverted -- Christa
   prefers the plain title/score row.) */
.cb-widget-post.lets-review__widget__design-1 {
	display: flex;
	align-items: center;
	padding: 14px 0;
	border-bottom: 1px solid var(--line);
}

.cb-widget-post.lets-review__widget__design-1:last-child {
	border-bottom: none;
}

.cb-widget-post .score-bar,
.cb-widget-post .score-overlay {
	display: none;
}

.cb-widget-post .cb-title.lr-font-h {
	flex: 1;
	min-width: 0;
	font-family: var(--font-sans);
	font-size: 14px;
	text-transform: none;
	letter-spacing: normal;
}

.cb-widget-post .score.cb-format-2 {
	font-family: var(--font-serif);
	font-size: 19px;
	font-weight: 400;
	color: var(--ink);
	flex-shrink: 0;
	margin-left: 14px;
}

/* Newsletter block: dark surface per spec. */
.widget_mc4wp_form_widget {
	background-color: var(--ink);
	padding: 26px;
}

.widget_mc4wp_form_widget .cb-sidebar-widget-title {
	color: var(--surface-2) !important;
	border-bottom-color: var(--surface-2) !important;
	font-family: var(--font-serif) !important;
	font-size: 26px !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
	margin-bottom: 16px !important;
}

/* The mc4wp plugin's own "dark theme" class sets label text to a near-black
   grey (#2e2e2e), meant for a light card, not our true --ink background --
   contrast ratio was ~1.4:1 against it, effectively invisible. */
.widget_mc4wp_form_widget .mc4wp-form label {
	color: var(--surface-2) !important;
}

/* Home template feedback, item 6: no gap between the input and the
   button, label on the theme's default font. Targets the shared
   .mc4wp-form markup directly (not scoped to one wrapper) so it covers
   both places this form appears -- this sidebar widget and the
   post-footer instance already styled above (Step 13). */
.mc4wp-form input[type="email"],
.mc4wp-form input[type="text"] {
	margin-bottom: 10px;
	display: block;
}

.mc4wp-form label {
	font-family: var(--font-sans);
	font-size: 13px;
}

/* ==========================================================================
   Step 8 — Verdict panel
   ========================================================================== */

/* Sidebar box: 1px ink border, 22px padding, 72px Bodoni score, CTA. */
.hr-score-box {
	border: 1px solid var(--ink);
	padding: 22px;
	margin-bottom: 26px;
}

.hr-score-box-label {
	font-family: var(--font-sans);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--muted-2);
}

.hr-score-box-score {
	font-family: var(--font-serif);
	font-size: 72px;
	font-weight: 400;
	line-height: 1;
	color: var(--ink);
	margin-top: 6px;
}

.hr-score-box-rule {
	border: none;
	border-top: 1px solid var(--line);
	margin: 18px 0;
}

.hr-score-box-cta {
	display: block;
	width: 100%;
	box-sizing: border-box;
	background-color: var(--accent);
	color: #fff;
	text-align: center;
	text-decoration: none;
	text-transform: uppercase;
	font-family: var(--font-sans);
	font-size: 12px;
	font-weight: 500;
	letter-spacing: 0.1em;
	padding: 14px;
}

.hr-score-box-cta:hover {
	background-color: var(--ink);
}

.hr-score-box-disclosure {
	font-family: var(--font-sans);
	font-size: 11px;
	color: var(--muted-3);
	margin: 12px 0 0;
	line-height: 1.5;
}

/* Compact rating preview (formerly mobile-only): review-post template
   refresh replaces the sidebar's Editor's Rating box with this shown at
   ALL widths, between the header and hero. Rough responsive pass for
   the structural review -- exact spacing/border/CTA-column layout is
   pass 2, not this commit. */
.hr-mobile-strip {
	display: block;
	margin: 20px 0;
}

.hr-mobile-strip-row {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 14px;
	padding: 18px 0;
	border-top: 1px solid var(--line);
	border-bottom: 1px solid var(--line);
}

@media (min-width: 768px) {
	.hr-mobile-strip {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 24px;
		padding: 20px 0;
		border-top: 1px solid var(--line);
		border-bottom: 1px solid var(--line);
		margin: 24px 0;
	}

	.hr-mobile-strip-row {
		padding: 0;
		border: none;
		flex: 1;
	}

	.hr-mobile-strip-cta {
		width: auto;
		flex-shrink: 0;
	}
}

.hr-mobile-strip-score {
	font-family: var(--font-serif);
	font-size: 44px;
	font-weight: 400;
	color: var(--ink);
	flex-shrink: 0;
}

.hr-mobile-strip-summary {
	font-family: var(--font-sans);
	font-size: 15px;
	line-height: 1.4;
	color: var(--ink-soft);
}

/* !important: these buttons live inside .entry-content (mobile strip, verdict
   panel), where the Step 2 rule ".entry-content a { color: var(--accent) }"
   is more specific (class+tag) than a bare class selector and would
   otherwise win, rendering accent-on-accent invisible text. */
.hr-mobile-strip-cta {
	display: block;
	width: 100%;
	box-sizing: border-box;
	background-color: var(--accent);
	color: #fff !important;
	text-align: center;
	text-decoration: none;
	text-transform: uppercase;
	font-family: var(--font-sans);
	font-size: 12px;
	font-weight: 500;
	letter-spacing: 0.1em;
	padding: 14px;
	margin-top: 14px;
}

/* End-of-article verdict panel: surface-2 background, 3px ink top border.
   Pros/cons live inside this same panel (below a hairline), not as a
   separate block after it -- the surface-2 background has to run under
   the whole verdict, not just the score/criteria half of it. */
.hr-verdict-panel {
	background-color: var(--surface-2);
	border-top: 3px solid var(--ink);
	padding: 38px 40px;
	margin: 40px 0;
}

/* Score/criteria row -- top-aligned so a short criteria list doesn't
   centre oddly next to a big numeral. */
.hr-verdict-top {
	display: flex;
	align-items: flex-start;
	gap: 40px;
}

.hr-verdict-left {
	width: 230px;
	flex-shrink: 0;
}

.hr-verdict-label {
	font-family: var(--font-sans);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--muted-2);
}

.hr-verdict-score {
	font-family: var(--font-serif);
	font-size: 104px;
	font-weight: 400;
	line-height: 1;
	color: var(--ink);
	margin-top: 4px;
}

.hr-verdict-summary {
	font-family: var(--font-sans);
	font-size: 15px;
	line-height: 1.5;
	color: var(--ink-soft);
	margin-top: 10px;
}

.hr-verdict-criteria {
	flex: 1;
	min-width: 0;
}

/* Item 14: no row rules in the spec -- was reading as a table (a hairline
   under every row). Spacing carries the rhythm instead: 16px between
   criterion rows. */
.hr-verdict-criterion {
	display: flex;
	align-items: center;
	gap: 14px;
	margin-bottom: 16px;
}

.hr-verdict-criterion:last-child {
	margin-bottom: 0;
}

.hr-verdict-criterion-label {
	font-family: var(--font-sans);
	font-size: 14px;
	color: var(--ink-body);
	width: 160px;
	max-width: 160px;
	flex-shrink: 0;
}

.hr-verdict-criterion-track {
	flex: 1;
	height: 2px;
	background-color: var(--placeholder);
	display: block;
}

.hr-verdict-criterion-fill {
	display: block;
	height: 100%;
	background-color: var(--ink);
}

.hr-verdict-criterion-num {
	font-family: var(--font-serif);
	font-size: 16px;
	color: var(--ink);
	flex-shrink: 0;
	width: 32px;
	text-align: right;
}

/* Mobile: no responsive rule existed at all for this panel, so the
   104px score and the fixed-230px-left/flex-1-right side-by-side row
   both carried straight down to a 400px viewport unchanged. At that
   width the 160px-wide criterion label alone left the flex:1 track
   almost no room to render into (effectively 0px, hence "the bars
   disappear completely" -- the element was still there, just too
   narrow to see). Score+summary stack above a full-width criteria
   list instead of sitting side by side; each criterion keeps its own
   row (label + bar + number) but now has the full panel width to lay
   out in. Desktop (.hr-verdict-top's flex row) is untouched. */
@media (max-width: 767px) {
	.hr-verdict-top {
		flex-direction: column;
		gap: 20px;
	}

	.hr-verdict-left {
		width: 100%;
	}

	.hr-verdict-score {
		font-size: 68px;
	}

	.hr-verdict-criteria {
		width: 100%;
	}

	/* ShopMy embed: the iframe's min-height:340px is an inline style
	   baked into the post content itself (the retailer widget's own
	   embed code, not theme markup), so it needs !important to beat --
	   at mobile widths the widget's real rendered content runs to
	   ~356px, just past that fixed height, producing a small nested
	   scrollbar. 380px gives enough headroom without touching the
	   iframe's own (cross-origin, third-party) contents. */
	iframe[src*="shopmy"] {
		min-height: 380px !important;
	}
}

/* What works / What doesn't -- two columns, one full-width column when
   cons are empty (never render an empty column or a bare heading).
   Sits inside .hr-verdict-panel, below a hairline, not as its own block. */
.hr-verdict-proscons {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 40px;
	margin-top: 32px;
	padding-top: 32px;
	border-top: 1px solid var(--line);
}

.hr-verdict-proscons--single {
	grid-template-columns: 1fr;
}

.hr-verdict-proscons-title {
	font-family: var(--font-sans) !important;
	font-size: 11px !important;
	font-weight: 600 !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase !important;
	margin-bottom: 12px;
}

.hr-verdict-pros-title {
	color: var(--good) !important;
}

.hr-verdict-cons-title {
	color: var(--accent) !important;
}

.hr-verdict-proscons ul {
	list-style: none;
	margin: 0;
	padding: 0;
	font-family: var(--font-sans);
	font-size: 16px;
	line-height: 1.6;
	color: var(--ink-body);
}

/* Item 14: same as the criterion rows above -- 10px between pros/cons
   items, no hairlines. A custom dash marker restores "this is a list"
   legibility (list-style:none alone read as unmarked paragraphs) without
   falling back to a default browser disc that clashes with the rest of
   the panel's typography. */
.hr-verdict-proscons li {
	margin-bottom: 10px;
	padding-left: 18px;
	position: relative;
}

.hr-verdict-proscons li::before {
	content: "\2013";
	position: absolute;
	left: 0;
	color: var(--muted-2);
}

.hr-verdict-proscons li:last-child {
	margin-bottom: 0;
}

/* Full affiliate set -- only shown here and in the mobile early strip;
   never all three inline near the top of desktop body copy. Grouped
   inside .hr-verdict-panel (heading, buttons, disclosure together), so
   it needs the same top border/spacing the pros/cons block above it
   uses to separate from whatever came before -- proscons if present,
   otherwise straight after the score/criteria row. */
.hr-verdict-aff-title {
	flex-basis: 100%;
	font-family: var(--font-sans) !important;
	font-size: 11px !important;
	font-weight: 600 !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase !important;
	color: var(--ink);
	margin: 0 0 12px;
}

.hr-verdict-aff {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	margin-bottom: 14px;
	margin-top: 32px;
	padding-top: 32px;
	border-top: 1px solid var(--line);
}

/* One primary retailer in --accent; the rest outlined so six buttons don't
   read as a block of red -- red stops meaning anything when everything is
   red (round 2 punch list, item 4). */
.hr-verdict-aff-btn {
	background-color: transparent;
	border: 1px solid var(--ink);
	color: var(--ink) !important;
	text-align: center;
	text-decoration: none;
	text-transform: uppercase;
	font-family: var(--font-sans);
	font-size: 12px;
	font-weight: 500;
	letter-spacing: 0.1em;
	padding: 13px 22px;
}

.hr-verdict-aff-btn:hover {
	background-color: var(--ink);
	color: #fff !important;
}

.hr-verdict-aff-btn--primary {
	background-color: var(--accent);
	border-color: var(--accent);
	color: #fff !important;
}

/* Primary CTA hover/focus stays burgundy (a touch darker than resting,
   so it still reads as a state change), never black -- outlined
   secondary retailer buttons (.hr-verdict-aff-btn without --primary)
   keep their existing ink-fill hover, untouched. */
.hr-verdict-aff-btn--primary:hover,
.hr-verdict-aff-btn--primary:focus-visible {
	background-color: #6F1F1F;
	border-color: #6F1F1F;
	color: #fff !important;
}

.hr-verdict-aff-disclosure {
	font-family: var(--font-sans);
	font-size: 12px;
	color: var(--muted-2);
	margin: 0;
}

@media (max-width: 767px) {
	.hr-verdict-panel {
		padding: 26px 20px;
		/* The gap before this panel (meta-wrap's own 20px bottom padding +
		   the metadata divider's 24px margin + this panel's 40px margin-
		   top, ~84-109px measured live) read as excess dead space on a
		   real phone. Panel position/the Let's Review placement setting
		   are untouched -- only the margin contributing to the gap above
		   it shrinks. Paired with the metadata-divider and meta-wrap
		   reductions below to land the total gap at ~32px. */
		/* Adjacent-sibling margin collapse: meta-wrap's own bottom padding
		   is 0 (see below), so .meta's 12px margin-bottom collapses
		   straight through it and then collapses AGAIN with this margin-
		   top against .hr-verdict-panel's true previous sibling
		   (.meta-wrap, not .meta directly) -- collapsed sibling margins
		   take the larger value, not the sum (confirmed live: 12px+8px
		   measured as a 12px gap, not 20px). Set to the actual target
		   directly rather than fighting the collapse. */
		margin-top: 32px;
	}

	.hr-verdict-top {
		flex-direction: column;
	}

	.hr-verdict-left {
		width: 100%;
	}

	.hr-verdict-proscons {
		grid-template-columns: 1fr;
	}

	.hr-verdict-aff-btn {
		width: 100%;
	}

	/* Same gap fix, other two contributors: the wrapper around the meta
	   row (parent-theme default, padding:20px 0 both sides -- only the
	   bottom is this gap's concern, top spacing above the meta row is
	   untouched) and the metadata divider's own margin/padding (kept as
	   a visible rule, just tighter). */
	.meta-wrap.hero-meta {
		padding-bottom: 0;
	}

	/* !important: this rule sits earlier in the file than the base
	   article .meta:has(> .title-wrap) divider rule it's overriding
	   (that one lives with the rest of the single-post header CSS,
	   further down) -- same selector/specificity, so without
	   !important the later base rule wins on source order despite this
	   media query correctly matching. */
	article .meta:has(> .title-wrap) {
		padding-bottom: 12px !important;
		margin-bottom: 12px !important;
	}
}

/* ==========================================================================
   Step 9 — "At a glance" spec panel
   ========================================================================== */

.hr-spec-panel {
	border-top: 1px solid var(--ink);
	border-bottom: 1px solid var(--ink);
	padding: 26px 0;
	margin: 32px 0;
}

.hr-spec-panel-label {
	font-family: var(--font-sans);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--accent);
	margin-bottom: 20px;
}

.hr-spec-panel-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	column-gap: 40px;
	row-gap: 24px;
	margin: 0;
}

.hr-spec-panel-cell dt {
	font-family: var(--font-sans);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--muted-2);
	margin: 0 0 4px;
}

.hr-spec-panel-cell dd {
	font-family: var(--font-sans);
	font-size: 16px;
	color: var(--ink-body);
	margin: 0;
	padding: 0;
	text-align: left;
}

@media (min-width: 768px) and (max-width: 1019px) {
	.hr-spec-panel-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 767px) {
	.hr-spec-panel-grid {
		grid-template-columns: 1fr;
		row-gap: 14px;
	}
}

/* ==========================================================================
   Step 11 — Sidebar (review-post half): sticky score box + table of contents
   ========================================================================== */

/* The theme's own "light skin" default (.cb-body-light .sidebar { background:
   #f2f2f2 }) is a third background colour outside the two the whole design
   is built on. It was already there on every sidebar, just short enough
   not to draw attention -- stretching the sidebar column to full height
   below turned it into a ~1,400px grey block. Sidebar modules sit directly
   on --surface, no wrapper background, on every page this sidebar template
   is used (home included), not just review posts. */
.cb-body-light .sidebar {
	background: transparent;
}

/* The main/sidebar row is float-based (.tipi-col { float: left }), so the
   short sidebar column never matches the tall article column's height --
   position: sticky has nowhere to travel. Converting just this one row to
   flex (align-items: stretch is the default) makes both columns match the
   taller one, without touching the shared .tipi-col/.tipi-m-* classes used
   elsewhere on the site -- scoped to .hr-has-review (added only on posts
   that get this sidebar) and to the single-post template's own wrapper, so
   no other .tipi-cols row anywhere else is affected. Desktop only (768px,
   the same point the theme's own grid already collapses to one column) --
   below that, sticky is off entirely per the step's own instruction, and
   the sidebar keeps its normal stacked float behaviour. */
@media (min-width: 768px) {
	body.hr-has-review .single-content.contents-wrap > .tipi-cols {
		display: flex;
		align-items: stretch;
	}

	body.hr-has-review .single-content.contents-wrap > .tipi-cols > .tipi-col {
		float: none;
	}

	body.hr-has-review .sidebar-wrap .cb-sidebar.sidebar {
		height: 100%;
	}
}

/* "In this review" table of contents. A plain div/button, not a native
   <details> -- Chrome constrains a closed <details>'s own generated box to
   just the <summary>'s height at a level below the CSS cascade, so no
   author CSS on the child list can make its content actually paint while
   closed. A div sidesteps that entirely: closed by default (mobile),
   toggled via a two-line click handler (wp_footer script), forced open on
   desktop with a plain media query -- no native quirks either way. */
.hr-toc {
	margin-top: 26px;
}

.hr-toc-summary {
	display: block;
	width: 100%;
	background: none;
	border: none;
	border-bottom: 1px solid var(--ink);
	margin: 0;
	font-family: var(--font-sans);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	text-align: left;
	color: var(--ink);
	padding: 0 0 10px;
	cursor: pointer;
}

.hr-toc-list {
	display: none;
	list-style: none;
	margin: 14px 0 0;
	padding: 0;
}

.hr-toc.is-open .hr-toc-list {
	display: block;
}

@media (min-width: 768px) {
	.hr-toc-list {
		display: block !important;
	}

	.hr-toc-summary {
		cursor: default;
		pointer-events: none;
	}
}

.hr-toc-list li {
	border-bottom: 1px solid var(--line);
}

.hr-toc-list li:last-child {
	border-bottom: none;
}

.hr-toc-link {
	display: block;
	padding: 10px 0;
	font-family: var(--font-sans);
	font-size: 14px;
	line-height: 1.4;
	color: var(--muted-2);
	text-decoration: none;
}

.hr-toc-link:hover {
	color: var(--ink);
}

.hr-toc-link.is-active {
	color: var(--accent);
}

/* ==========================================================================
   Round 2 punch list
   ========================================================================== */

/* Item 5: social share buttons were four saturated brand colours (Facebook
   blue, Twitter blue, Pinterest red, near-black) at 130px wide each --
   nothing in the mockup, and off-palette in a one-accent design. Restyled
   as labelled outline buttons per the review-template spec (icon-only
   wasn't enough on its own) -- the theme's own data-title attribute reads
   as an action verb ("Share"/"Tweet"/"Pin it"), not a platform name, so
   the visible label text is added directly via ::after per button class
   rather than relying on that attribute. Existing share URLs untouched. */
.cb-social-sharing.cb-color-buttons a {
	width: auto !important;
	min-width: 150px;
	height: auto;
	padding: 10px 16px !important;
	margin: 0 10px 10px 0 !important;
	background: transparent !important;
	border: 1px solid var(--ink);
	color: var(--ink) !important;
	font-size: 15px !important;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	box-sizing: border-box;
}

.cb-social-sharing.cb-color-buttons a::after {
	font-family: var(--font-sans);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

.cb-social-sharing.cb-color-buttons a.cb-social-fb::after {
	content: "Facebook";
}

.cb-social-sharing.cb-color-buttons a.cb-social-tw::after {
	content: "X";
}

/* The icon font's Twitter glyph is the old bird -- wrong mark for a
   button already labelled "X" (see ::after above). No X-shaped glyph
   in this icon set to swap in, so text-only per Christa's own fallback
   -- the "X" label alone reads as the button's identity, no icon
   needed. */
.cb-social-sharing.cb-color-buttons a.cb-social-tw i {
	display: none;
}

.cb-social-sharing.cb-color-buttons a.cb-social-pin::after {
	content: "Pinterest";
}

.cb-social-sharing.cb-color-buttons a.cb-social-em::after {
	content: "Email";
}

.cb-social-sharing.cb-color-buttons a:hover {
	background: var(--ink) !important;
	color: #fff !important;
}

/* Mobile: width:auto (base rule above) made each button as wide as its
   own label, so "Facebook" and "X" sat at very different widths in the
   same row. Tidy 2x2 grid of equal-width buttons instead. */
@media (max-width: 767px) {
	.cb-social-sharing.cb-color-buttons .cb-color-sharing-buttons {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: 10px;
	}

	.cb-social-sharing.cb-color-buttons a {
		width: 100% !important;
		margin: 0 !important;
	}
}

/* Item 6: card score badges (home, category, tag, author, mega-menu --
   .lets-review-api-wrap is the shared badge box every image-overlay
   card score uses) render solid black (#222, set inline by the theme)
   with white numerals -- reads as a printed sticker rather than the
   spec's surface-2 tag. The background colour is set via an inline
   style attribute, which only !important in a stylesheet can beat.
   Translucent rgba background (not CSS opacity, which would fade the
   score digits themselves) -- the number stays fully opaque/crisp
   regardless of what photo sits behind the badge. */
.lets-review-api-wrap {
	background-color: rgba(247, 244, 241, 0.88) !important;
	color: var(--ink) !important;
}

/* Items 7-9: nav/wordmark chrome. The theme renders two different header
   layouts depending on template -- single posts get a two-row #masthead
   (wordmark row, then a separate nav row); home/archive/author pages
   render the logo inline inside the nav bar itself, no #masthead at all.
   These selectors target classes shared by both layouts. */

/* Item 7: nav renders at the theme's own weight 700 with ~1.9px tracking,
   reading as ~20px bold and competing with the wordmark. Spec: 13px,
   weight 500, 0.14em. */
.main-menu.nav > li > a {
	font-size: 13px !important;
	font-weight: 500 !important;
	letter-spacing: 0.14em !important;
}

/* Item 8: both the wordmark row (single posts) and the nav links row are
   centred by theme defaults (.logo-main-wrap-center, and .main-menu-wrap's
   justify-content) rather than left-aligned. Overridden with !important
   since the exact source rule sits in a stylesheet this session couldn't
   introspect directly (likely proxied by the caching/optimisation layer) --
   confirmed by computed style before and after, not guessed. */
.logo-main-wrap-center {
	justify-content: flex-start !important;
}

/* Primary nav links centred as a group per Christa's later call (item 8
   originally left-aligned them). .main-menu-wrap is a 3-item flex row
   (logo, the nav-links <ul>, the icons <ul>) -- centering the WRAP
   itself would bunch all three together in the middle, not center just
   the links between a left logo and right icons. space-between pins
   logo/icons to the outer edges; flex:1 + justify-content:center on the
   nav <ul> itself (also its own flex container) centers the links in
   whatever space that leaves. Safe to change on its own: confirmed live
   that the mega-menu panel (.mm-art > .menu, position:absolute; left:
   50%; transform:translateX(-50%)) resolves against .main-navigation
   itself (the nearest positioned ancestor, position:sticky), not
   against any individual nav link -- so re-justifying the links inside
   it doesn't move where the panel centres. */
.main-menu-wrap {
	justify-content: space-between !important;
}

.main-menu-wrap .main-menu {
	flex: 1;
	justify-content: center;
}

/* .main-navigation (its own ancestor) already carries side-spacing's
   40px padding once -- .main-menu-wrap has side-spacing too, adding a
   SECOND 40px on top (95 -> 135 -> 175), which is what actually pushed
   the nav 40px right of the logo/brand-row (both of which only pick up
   side-spacing's padding once). Zeroing the duplicate -- needed the
   compound .main-menu-wrap.side-spacing selector (2 classes) rather
   than plain .main-menu-wrap (1 class): both this rule and the global
   .side-spacing gutter rule are !important with otherwise-equal
   specificity, and .side-spacing's own !important, appearing later in
   the file, was winning the tie on source order alone. */
.main-menu-wrap.side-spacing {
	padding-left: 0 !important;
}

/* Item 9: the rule under the nav is the theme's default 3px black border,
   not a hairline. Same class is used in both header layouts. */
.menu-bg-area.main-navigation-border {
	border-bottom: 1px solid var(--line) !important;
}

/* The 1280px page-width fix (.wrap, .tipi-row) missed this specific nav
   background wrapper -- it has its own explicit width:1200px, not a
   max-width inherited from those classes, so it stayed at the old width
   while the logo's own container (which DOES use .wrap-style 1280px
   centering) moved -- two different-width containers centered in the
   same viewport land at different left edges, which is what actually
   caused the logo/nav/brand-row misalignment (not a padding mismatch,
   despite that being the first, wrong diagnosis). */
/* width:1280px (an absolute value, not just a cap) sitting inside an
   ancestor that has its own side-spacing padding forces this wrapper
   wider than the actual space available, which is exactly what was
   producing a permanent sitewide horizontal scrollbar -- the fixed
   1280px box didn't know to shrink for its parent's own padding.
   width:100% + max-width:1280px reaches the same 1280px column when
   there's room for it, without ever demanding more than its parent
   actually has. */
.menu-bg-area {
	max-width: 1280px !important;
	width: 100% !important;
	margin: 0 auto !important;
	box-sizing: border-box !important;
}

/* Item 12: standfirst -- only renders when a post has a real excerpt
   (see functions.php); most posts won't show anything yet. */
.hr-standfirst {
	font-family: var(--font-serif);
	font-style: italic;
	font-size: 22px;
	font-weight: 400;
	line-height: 1.45;
	max-width: 680px;
	color: var(--ink-soft);
	margin: 14px 0 0;
}

/* Review deck specifically: slightly oversized on mobile, running to too
   many lines under the H1. H1 itself untouched. */
@media (max-width: 767px) {
	body.hr-has-review .hr-standfirst {
		font-size: 20px;
		line-height: 1.45;
	}
}

/* Item 13: prev/next and author box share the theme's default
   "cb-post-block-bg" grey panel treatment (the same #f2f2f2 fixed in item
   2's sidebar). Replaced with a hairline, matching how every other module
   in this design separates from its neighbours. */
.cb-post-block-bg {
	background-color: transparent !important;
	border-top: 1px solid var(--line);
	padding-top: 26px;
}

/* "Previous/Next Article" caption: --muted-2 (#6B6459) read as washed out
   against the page background -- darkened to --muted, still visibly
   secondary to the linked title below it, just no longer illegible. */
.cb-next-previous .cb-read-title {
	font-family: var(--font-sans) !important;
	font-size: 11px !important;
	font-weight: 600 !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase !important;
	color: var(--muted);
}

.author-box .cb-title.title {
	font-family: var(--font-serif);
	font-size: 23px;
	font-weight: 400;
}

/* Single posts (review and non-review, both use this exact wrapper) had
   a 1px border around the entire content+sidebar area from the parent
   theme's "boxed content" default -- removed per Christa's call, without
   adding a compensating border anywhere else. The nav's own hairline
   (.main-menu-wrap) and the internal section dividers used throughout
   (article header, footer sequence, etc.) are separate rules and are
   untouched by this. */
.single-content.contents-wrap {
	border: none !important;
}

/* The parent theme gives .author-box .cb-meta a fixed computed height
   (sized for a shorter bio than some authors actually have) plus
   overflow:hidden, clipping the last line of a longer biography at
   certain container widths -- the exact wrapping depends on how many
   lines the bio takes, so it doesn't reproduce at every viewport. Let
   the box grow to fit its real content instead of a fixed box the text
   may not fit inside. Unscoped: same fix applies to both the single-
   post author box and the author-archive header, both of which inherit
   the identical parent-theme rule. */
.author-box .cb-meta.meta {
	height: auto !important;
	overflow: visible !important;
}

/* Single-post author box avatar: ~72px per spec, not the 96px meant only
   for the author archive's full-width band (see body.author rule below). */
body:not(.author) .author-box .mask img.avatar {
	width: 72px !important;
	height: 72px !important;
}

/* Single-post author card: the avatar was float:left, which wraps the
   name/bio text AROUND it rather than giving them their own aligned
   column -- looks fine only by accident when the bio happens to clear
   past the avatar's height. Explicit flex two-column layout on desktop
   only (mobile's existing centred/stacked look comes from the parent
   theme's own responsive CSS, untouched here, and is already correct
   per Christa's call). Name and bio share the same left edge once the
   float is gone -- no extra alignment rule needed for that. */
@media (min-width: 768px) {
	body:not(.author) .author-box {
		display: flex;
		align-items: flex-start;
		gap: 22px;
	}

	body:not(.author) .author-box .mask {
		float: none;
		flex: 0 0 72px;
	}

	body:not(.author) .author-box .cb-meta.meta {
		flex: 1;
		min-width: 0;
	}
}

/* Author name link: no underline, recognisable via the existing serif
   type + a subtle burgundy hover/focus instead -- overrides the general
   ".author-box a" underline-everywhere rule above, which is otherwise
   still correct for the bio's own inline links. Unscoped by viewport
   (desktop and mobile both use the same serif name styling). */
.author-box .cb-title.title a {
	text-decoration: none;
	color: inherit;
}

.author-box .cb-title.title a:hover,
.author-box .cb-title.title a:focus-visible {
	color: var(--accent);
}

/* Cookie Policy page (page-id-655) only: the Cookie Law Info plugin
   inserts its own "Manage your consent." link into this specific page's
   content -- redundant/confusing on the policy page itself. Hidden here
   only; the plugin's real consent banner, controls, and settings
   mechanism elsewhere on the site are untouched. */
body.page-id-655 .cli_manage_current_consent {
	display: none !important;
}

/* The reused homepage sidebar (Search/Top Bags/Latest Posts/Newsletter)
   already carries a Newsletter widget on every single post -- review and,
   since the sidebar was unified, non-review articles too -- so this
   separate post-footer subscribe block is always a second, duplicate
   newsletter CTA on the same page now. Hidden site-wide on single posts. */
body.single .cb-post-large.cb-post-footer-block {
	display: none;
}

/* Newsletter block in the post footer -- a theme "subscribe" feature using
   an mc4wp shortcode directly, not the widget instance already styled
   above, so it needs its own dark-surface treatment. Same near-invisible
   label-colour issue as the sidebar instance: mc4wp-form-theme-dark sets
   label text to a near-black grey meant for a light card. Kept in case
   this block is ever unhidden for a template that doesn't share the
   sidebar. */
/* Footer sequence (tags -> sharing -> prev/next -> author box -> Related
   Posts) all share this class, each with a flat 60px margin-bottom from
   the parent theme -- excessive when five sections stack in a row.
   Tightened uniformly rather than per-section; still enough to read as
   distinct blocks, just not enormous gaps between them. */
.cb-post-footer-block {
	margin-bottom: 32px !important;
}

.cb-post-large.cb-post-footer-block {
	background-color: var(--ink);
	color: var(--surface-2);
	padding: 32px;
}

.cb-post-large.cb-post-footer-block h2 {
	font-family: var(--font-serif) !important;
	font-size: 26px !important;
	font-weight: 400 !important;
	color: var(--surface-2) !important;
}

.cb-post-large.cb-post-footer-block p {
	color: var(--surface-2);
	font-family: var(--font-sans);
}

.cb-post-large.cb-post-footer-block .mc4wp-form label {
	color: var(--surface-2) !important;
}

/* Comparison-image captions (side-by-side wp-block-columns figures) --
   rendered at 18px/normal/black, same weight as body copy, so a caption
   competed with the prose instead of reading as secondary. Layout itself
   (the column split) is untouched, only the caption's own type. */
.entry-content .wp-block-columns figcaption {
	font-family: var(--font-sans);
	font-size: 12px;
	font-style: italic;
	color: var(--muted-2);
}

/* Item 19: in-body tables (Gutenberg's "Stripes" block style) had cool-grey
   zebra striping, a heavy 3px rule under the header, centred header labels
   over left-aligned values, and an unconstrained width (up to 748px on this
   post) that let table-layout:auto's already-proportional column split read
   as a huge empty gap before the values. Capped to the same body measure
   as everything else (680px), which alone tightens that gap considerably. */
.entry-content .wp-block-table {
	max-width: 680px;
}

.entry-content .wp-block-table.is-style-stripes tbody tr:nth-child(odd) {
	background-color: transparent;
}

.entry-content .wp-block-table table {
	border-collapse: collapse;
}

.entry-content .wp-block-table td,
.entry-content .wp-block-table th {
	font-variant-numeric: tabular-nums;
	border-bottom: 1px solid var(--line) !important;
	padding: 14px 10px !important;
}

.entry-content .wp-block-table td:first-child,
.entry-content .wp-block-table th:first-child {
	padding-left: 0 !important;
}

.entry-content .wp-block-table thead th,
.entry-content .wp-block-table tr:first-child th {
	font-family: var(--font-sans) !important;
	font-size: 11px !important;
	font-weight: 600 !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase !important;
	color: var(--muted-2) !important;
	background-color: var(--surface) !important;
	border-bottom: 2px solid var(--ink) !important;
}

.entry-content .wp-block-table td {
	font-family: var(--font-sans);
	font-size: 16px;
	color: var(--ink-body);
}

/* Left-align by default, but never override a cell the editor has
   explicitly aligned (Gutenberg's own per-cell alignment controls --
   e.g. right-aligning a price column). */
.entry-content .wp-block-table td:not([class*="has-text-align"]),
.entry-content .wp-block-table th:not([class*="has-text-align"]) {
	text-align: left;
}

/* Hero image: full column width, ~16:9, capped at 440px tall on desktop --
   was previously unconstrained (rendering at the source photo's native 3:2,
   ~525px tall on this post). object-fit:cover was already set on the img
   but inert without an explicit box to crop into.
   Scoped to body.hr-has-review: .hero-wrap/.hero is shared markup used
   sitewide (including pages with no featured image at all, like Contact),
   and aspect-ratio alone reserves height even for a completely empty box
   -- an unscoped rule here left a blank ~440px grey rectangle on every
   page without a hero image. Review posts always have one, so this is
   safe to scope tightly rather than guard against emptiness generically. */
@media (min-width: 769px) {
	body.hr-has-review .hero-wrap .hero {
		aspect-ratio: 16 / 9;
		max-height: 440px;
		overflow: hidden;
	}
	body.hr-has-review .hero-wrap .hero img {
		width: 100%;
		height: 100%;
		object-fit: cover;
	}
}

@media (max-width: 767px) {
	body.hr-has-review .hero-wrap .hero {
		height: 220px;
		overflow: hidden;
	}
	body.hr-has-review .hero-wrap .hero img {
		width: 100%;
		height: 100%;
		object-fit: cover;
	}
}

/* Item 20: hero image caption moved below the image (see functions.php --
   it's a structural move, not just a position change, since the theme's
   own .hero-wrap .caption rule pins it absolute over the photo). */
.hero-wrap + .caption {
	position: static;
	z-index: auto;
	background: none;
	padding: 14px 0 0;
	text-align: left;
	font-family: var(--font-sans);
	font-size: 12px;
	color: var(--muted-2);
}

/* ==========================================================================
   Step 12 — Mega-menu
   ========================================================================== */

/* 1-2. Panel: --surface background, 1px --line border, no dark fill.
   Width/position: the theme sizes the dropdown to its immediate wrap
   (1140px, inset 30px each side from the site's 1200px column) rather
   than the column itself -- widened and re-centred to match the same
   135-1335 edges the masthead, brand row, and article wrap all already
   align to. */
.menu-wrap.menu-wrap-more-10 {
	background-color: var(--surface) !important;
	border: 1px solid var(--line);
}

/* The brand-list column (a nested .sub-menu) carries its own separate
   dark background layered on top of the panel above, not inherited from
   it -- found by testing, not visible from the panel-level fix alone.
   It also carries its own border-top: 5px solid #222 -- a second,
   separate source of the same dark-line symptom as the #block-wrap-NNN
   divs fixed elsewhere (confirmed live on the tag archive's mega-menu,
   where the brand-list column is the ONLY thing in the panel, so there's
   no block-wrap div to have caught it). */
.menu-wrap.menu-wrap-more-10 .sub-menu {
	background-color: var(--surface) !important;
	border-top: 1px solid var(--line) !important;
}

.mm-art > .menu {
	width: 1200px !important;
}

/* .mm-art > .menu (above) is the 1200px reference frame, but the panel
   inside it (.menu-wrap-more-10) sits at width:100% of that frame's
   *content* box -- the frame's own .side-spacing class eats padding on
   each side first, so the panel itself was inset from the edges it's
   meant to match. Breaks out of that padding to reach the true column
   edges. Originally compensated for .side-spacing's old 30px gutter;
   .side-spacing is 40px now (the site-wide 1280px/40px page-width pass),
   so the panel had drifted ~20px out of alignment with the header/
   content grid again without this value being updated alongside it. */
.menu-wrap.menu-wrap-more-10 {
	width: calc(100% + 80px) !important;
	margin-left: -40px !important;
}

/* Every piece of text inside was styled for the old dark panel (explicit
   white on the heading, "See all" link, card titles, and brand list --
   none of it inherited, so a blanket override is the only way to
   guarantee nothing renders dark-on-dark... or now light-on-light). */
.menu-wrap.menu-wrap-more-10,
.menu-wrap.menu-wrap-more-10 * {
	color: var(--ink) !important;
}

/* 4. Hover/focus inside the panel: --surface-2 fill, --ink text (already
   covered by the rule above). */
.menu-wrap.menu-wrap-more-10 a:hover,
.menu-wrap.menu-wrap-more-10 .menu-item:hover > a {
	background-color: var(--surface-2) !important;
}

/* 3. Active top-level item while its dropdown is open: same 2px --accent
   underline as step 10's "currently on this page" state, not a filled
   block. (.current-menu-item itself was already fixed in step 10 --
   this is the separate "dropdown is open" state, which doesn't require
   the page to literally be that section.) */
.main-menu-bar-color-1 .main-menu > .dropper.active:not(.current-menu-item) > a {
	background: transparent !important;
	color: var(--ink) !important;
	border-bottom: 2px solid var(--accent);
}

/* KNOWN ISSUE, not yet fixed: a thick dark (~3-4px) line spans the full
   nav width, appearing only while a mega-menu dropdown is open, sitting
   right at the seam between the nav row and the dropdown panel. Checked
   every element in the stack at that position (.dropper.active and its
   <a>, .main-menu, .main-menu-wrap, .main-navigation, .menu-bg-area,
   .mm-art > .menu, .menu-wrap.menu-wrap-more-10, and each one's ::before/
   ::after) -- none report a border, box-shadow, or background at that
   position. Hiding .mm-art > .menu (display:none) does make the line
   disappear, but that closes the whole dropdown as a side effect, so it
   isn't proof the line lives in that element specifically rather than
   being a side effect of the dropdown's open/closed state some other
   way. Needs a real DevTools element-picker session (this was all done
   via programmatic getComputedStyle/elementsFromPoint probing) rather
   than more guessing -- flagged in the completion report rather than
   shipping a speculative fix that was never confirmed to work. */
.main-menu-wrap {
	border-bottom: 1px solid var(--line);
}

/* RESOLVED: the mega-menu dark line was the block-builder's own default
   content-block border (border-top: 5px solid #222 on the numbered
   #block-wrap-NNN divs the theme generates one per block instance) --
   not a border/shadow on any of the wrapper elements checked earlier.
   IDs are unique per instance, so targeted by the shared parent context
   instead of any one block-wrap-NNN id. */
.menu-wrap.menu-wrap-more-10 [id^="block-wrap-"] {
	border-top: 1px solid var(--line) !important;
}

/* Mega-menu typography: panel heading was Montserrat uppercase 16px (a
   plain widget-title style), "See All" and the brand-list links were the
   same Montserrat treatment at two different sizes. Panel heading moves
   to serif title case at design scale; "See All" and brand links move to
   DM Sans, keeping "See All" uppercase/tracked (it's a UI action) but
   setting the brand links to sentence case (they're content, not labels)
   with a pale solid hairline instead of a dark dotted one. Card titles
   (~23px Bodoni) are untouched -- already correct. */
.menu-wrap.menu-wrap-more-10 .block-title.cb-module-title.title {
	font-family: var(--font-serif) !important;
	font-size: 30px !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
}

.menu-wrap.menu-wrap-more-10 .see-all {
	font-family: var(--font-sans) !important;
	font-size: 12px !important;
	font-weight: 500 !important;
	letter-spacing: 0.12em !important;
	text-transform: uppercase !important;
}

.menu-wrap.menu-wrap-more-10 .sub-menu li {
	border-bottom: 1px solid var(--line) !important;
}

.menu-wrap.menu-wrap-more-10 .sub-menu a {
	font-family: var(--font-sans) !important;
	font-size: 14px !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
	color: var(--ink) !important;
}

/* ==========================================================================
   Home template fixes
   ========================================================================== */

/* Item 3: home loop excerpt was on the theme's default Open Sans, not the
   type system. Title was already correct (Bodoni 23px, matches the card
   title rule from step 1) -- only the excerpt needed fixing. */
.excerpt.body-color {
	font-family: var(--font-sans);
	font-size: 16px;
	line-height: 1.65;
	color: var(--ink-soft);
}

/* Items 4 & 12: comment count on the home loop rendered at 8px in a grey
   filled pill -- unlike likes/views (dropped entirely per step 08's "no
   vote count" rule), comment counts are real engagement data, so this
   restyles rather than removes it. Same grey-pill mechanism as the
   category label already fixed (item 11 of the round 2 punch list) --
   .byline-part.comments just wasn't covered by that fix since it's a
   different class. */
.byline-part.comments {
	background-color: transparent !important;
	padding: 0 !important;
	height: auto !important;
}

.byline-part.comments a {
	font-family: var(--font-sans) !important;
	font-size: 13px !important;
	text-transform: lowercase !important;
	letter-spacing: normal !important;
	color: var(--muted-2) !important;
}

/* Item 6 covered above (.mc4wp-form input/label, shared by both this
   post-footer instance and the sidebar widget). */

/* Item 7: pagination numbers had no accent state at all on hover/focus. */
a.page-numbers:hover,
a.page-numbers:focus {
	color: var(--accent) !important;
}

/* Item 8: the SEO intro block ("Welcome to handbag.reviews...") was on
   the theme's default Open Sans/grey, not body type. Homepage item 20:
   16px / ~1.65 line-height specifically, tightened from an earlier
   18px/1.7 pass -- copy itself untouched, still the same editable
   cb_custom_a post meta on the front page (post 2537). */
.block-html-content p {
	font-family: var(--font-sans);
	font-size: 16px;
	line-height: 1.65;
	color: var(--ink-body);
}

/* Item 9 (original pass): footer font-family fix, superseded by the
   full footer refinement below -- kept as a no-op-safe base rule since
   nothing later re-sets font-family away from var(--font-sans). */
.cb-footer-links a,
.cb-copyright {
	font-family: var(--font-sans) !important;
}

/* Item 11: "Read more..." was a solid black filled button -- nothing in
   the spec calls for a filled button outside the primary affiliate CTA.
   Plain text link in --accent, consistent with "All brands ->" elsewhere,
   not a second button competing with the real CTAs. */
.read-more {
	background: none !important;
	color: var(--accent) !important;
	text-transform: uppercase;
	font-family: var(--font-sans);
	font-size: 12px;
	font-weight: 500;
	letter-spacing: 0.1em;
	padding: 0 !important;
}

.read-more:hover {
	color: var(--ink) !important;
}

/* Item 1: the theme's own sticky/"stuck" nav state removes its max-width
   entirely (.main-navigation.wrap.stuck:not(.slidedown) { max-width: none })
   so once the nav pins itself while scrolling, it bleeds white edge-to-edge
   across the full viewport instead of staying within the same 1200px
   column as everything else -- this is what read as "white instead of
   cream" in a scrolled screenshot. Restores the same 1200px/centred box
   the resting state already uses. */
.main-navigation.wrap.stuck:not(.slidedown) {
	max-width: 1200px !important;
	margin-left: auto !important;
	margin-right: auto !important;
}

/* ==========================================================================
   Archive headers (tag, category, author, search) — shared theme component
   ========================================================================== */

/* Every archive-type page (tag, category, author, search results) uses the
   same .cb-category-header/.cb-section-header title component: Montserrat
   bold uppercase with tracking, plus a decorative ::after bar stretching
   1920px off to the right -- neither is in the design, and the bar isn't
   attached to any real content, just a leftover section-divider effect. */
.cb-category-header .title,
.cb-section-header .title {
	font-family: var(--font-serif) !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
}

.cb-category-header .title:after,
.cb-section-header .title:after {
	display: none !important;
}

/* Sentence-case headline sizes per template -- tag/category archives are a
   64px brand-page headline (DESIGN-SPEC), author pages are smaller (40px),
   matching the reference mockup for each. */
body.tag .cb-category-header .title,
body.category .cb-category-header .title {
	font-size: 64px !important;
	line-height: 1;
}

body.author .cb-category-header .title {
	font-size: 40px !important;
	line-height: 1.1;
}

/* Author box (the theme's own grey card, both the post-footer widget and
   the bigger author-archive-page header) -- no third background colour. */
.author-box {
	background-color: transparent !important;
}

/* Search results: single-column list of compact horizontal rows (~140x100
   thumbnail), not the 2-column grid used before this pass -- search spans
   reviews/guides/trending so rows need room for a readable title + excerpt
   + category label, which a half-width grid column doesn't give. */
body.search-results .block-inner-box.contents .block {
	display: flex;
	flex-direction: column;
}

body.search-results article.preview-classic {
	width: 100% !important;
	padding: 20px 0 !important;
	margin-bottom: 0 !important;
	border-bottom: 1px solid var(--line-2);
}

body.search-results article.preview-classic:last-child {
	border-bottom: none;
}

body.search-results article.preview-classic .cb-mask.mask,
body.search-results article.preview-classic .mask-img {
	width: 140px !important;
	height: 100px !important;
	flex: 0 0 140px !important;
}

body.search-results article.preview-classic .mask-img img {
	width: 140px !important;
	height: 100px !important;
}

body.search-results article.preview-classic .cb-meta.cb-article-meta.meta {
	width: auto;
	flex: 1;
	min-width: 0;
}

body.search-results article.preview-classic .cb-meta .title.cb-post-title {
	font-family: var(--font-serif) !important;
	font-size: 20px !important;
	font-weight: 400 !important;
	line-height: 1.2 !important;
}

body.search-results article.preview-classic .cb-meta .excerpt.body-color {
	font-family: var(--font-sans);
	font-size: 14px;
	line-height: 1.55;
	color: #3A342D;
}

/* Title/image already link to the post -- no separate "Read More". */
body.search-results article.preview-classic .read-more-wrap {
	display: none;
}

@media (max-width: 767px) {
	body.search-results article.preview-classic .cb-mask.mask,
	body.search-results article.preview-classic .mask-img {
		width: 100% !important;
		height: auto !important;
		aspect-ratio: 4 / 3;
		flex: none !important;
	}
	body.search-results article.preview-classic .mask-img img {
		width: 100% !important;
		height: 100% !important;
	}
	body.search-results article.preview-classic {
		flex-direction: column;
	}
}

/* Author archive: the real post-loop container is .block-wrap.block-is-
   archive: confirmed live by tracing up from an actual .preview-1 card
   (article.parentElement) rather than querying the class names directly
   -- .block-inner-box.contents .block matched by class-name lookup
   turned out to be a sidebar widget's own duplicate copy of the same
   classes (the same "wrong duplicate instance" trap documented for the
   tag-archive debugging), not the real loop container. The real
   container genuinely is .block-inner-box.contents .block, natively
   display:flex with no wrapping, which is why cards were stacking full-
   width one-per-row instead of two-per-row. Switched to grid here; each
   card keeps its native image-left/text-right row layout (just resized
   to ~160x120) rather than stacking image-above-text, since 160px image
   + ~200px remaining text width per ~400px column is enough to avoid
   the "extremely tall and narrow" card problem without giving up the
   two-column count the spec asked for. */
body.author .block-inner-box.contents .block {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 32px 40px;
}

body.author article.preview-classic.preview-1 {
	width: 100% !important;
	padding: 0 !important;
	margin-bottom: 0 !important;
	border-bottom: none;
}

body.author article.preview-classic.preview-1 .cb-mask.mask,
body.author article.preview-classic.preview-1 .mask-img {
	width: 160px !important;
	height: 120px !important;
	flex: 0 0 160px !important;
}

body.author article.preview-classic.preview-1 .mask-img img {
	width: 160px !important;
	height: 120px !important;
}

body.author article.preview-classic.preview-1 .cb-meta.cb-article-meta.meta {
	width: auto;
	flex: 1;
	min-width: 0;
}

body.author article.preview-classic.preview-1 .cb-meta .title.cb-post-title {
	font-family: var(--font-serif) !important;
	font-size: 22px !important;
	font-weight: 400 !important;
	line-height: 1.2 !important;
}

body.author article.preview-classic.preview-1 .cb-meta .excerpt.body-color {
	font-family: var(--font-sans);
	font-size: 15px;
	line-height: 1.55;
	color: #3A342D;
}

/* The whole page already represents this one author -- "By [name]" in
   every card is redundant. Date/comments stay. */
body.author article.preview-classic.preview-1 .cb-meta .cb-byline.byline-3 .byline-part.author,
body.author article.preview-classic.preview-1 .cb-meta .cb-byline.byline-3 .byline-part.separator {
	display: none;
}

/* Spec calls for no separate "Read More" link here (title/image already
   link to the post) -- unlike tag/category archives, which keep it. */
body.author article.preview-classic.preview-1 .read-more-wrap {
	display: none;
}

@media (max-width: 900px) {
	body.author .block-inner-box.contents .block {
		grid-template-columns: 1fr;
	}
}

@media (max-width: 767px) {
	body.author article.preview-classic.preview-1 .cb-mask.mask,
	body.author article.preview-classic.preview-1 .mask-img {
		width: 100% !important;
		height: auto !important;
		aspect-ratio: 4 / 3;
		flex: none !important;
	}
	body.author article.preview-classic.preview-1 .mask-img img {
		width: 100% !important;
		height: 100% !important;
	}
	body.author article.preview-classic.preview-1 {
		flex-direction: column;
	}
}

/* ==========================================================================
   Tag + category archives -- shared single-row horizontal listing
   (Page Templates.dc.html, "Tag / brand archive" artboard). One
   treatment for both templates, not a per-template duplicate -- a 3 (tag)
   and 2 (category) column grid attempt both forced the theme's existing
   flex-row card (220px image + flexible text, already fixed non-shrinking
   by the earlier flex-basis fix) into a column far narrower than its own
   min-content width, which was the actual cause of the "extremely tall
   and narrow" cards: the text side had nowhere near enough room. Simply
   giving the row the full main-column width -- instead of forcing a
   grid -- removes that fight entirely; .preview-1 is the theme's real
   loop-card design id here (distinct from .preview-61, the sidebar's own
   Latest Posts card, which shares the same .preview-classic base markup
   but title-only). */
body.tag .block-inner-box.contents .block,
body.category .block-inner-box.contents .block {
	display: flex;
	flex-direction: column;
}

body.tag article.preview-classic.preview-1,
body.category article.preview-classic.preview-1 {
	width: 100% !important;
	gap: 24px;
	padding: 24px 0 !important;
	margin-bottom: 0 !important;
	border-bottom: 1px solid var(--line-2);
}

body.tag article.preview-classic.preview-1:last-child,
body.category article.preview-classic.preview-1:last-child {
	border-bottom: none;
}

body.tag article.preview-classic.preview-1 .cb-meta.cb-article-meta.meta,
body.category article.preview-classic.preview-1 .cb-meta.cb-article-meta.meta {
	width: auto;
	flex: 1;
	min-width: 0;
}

@media (max-width: 767px) {
	body.tag article.preview-classic.preview-1,
	body.category article.preview-classic.preview-1 {
		flex-direction: column;
	}
}

/* Card content typography -- eyebrow/title/byline are already ordered
   category-eyebrow -> title -> excerpt -> metadata by the shared "Post
   preview headers" rules further up (order:-1/0/1/2), and the eyebrow
   and byline/date colours are already set there too. Excerpt and the
   relocated read-more link (see functions.php) are the only genuinely
   unstyled pieces here. */
body.tag article.preview-classic.preview-1 .cb-meta .title.cb-post-title,
body.category article.preview-classic.preview-1 .cb-meta .title.cb-post-title {
	font-family: var(--font-serif) !important;
	font-size: 24px !important;
	font-weight: 400 !important;
	line-height: 1.15 !important;
}

body.tag article.preview-classic.preview-1 .cb-meta .excerpt.body-color,
body.category article.preview-classic.preview-1 .cb-meta .excerpt.body-color {
	font-family: var(--font-sans);
	font-size: 16px;
	line-height: 1.6;
	color: #3A342D;
}

/* "Read more" stays in its existing theme position (end of the excerpt)
   rather than merged into the byline/metadata row -- see the long comment
   in functions.php for why the relocated version was reverted. Restyled
   in place instead: sentence case, thin weight, burgundy, arrow instead
   of "...", quiet like a continuation of the excerpt rather than a
   competing all-caps button. */
body.tag article.preview-classic.preview-1 .cb-meta .read-more-wrap,
body.category article.preview-classic.preview-1 .cb-meta .read-more-wrap {
	display: inline-block;
	margin-left: 4px;
}

/* The theme's literal text is "Read More..." (an editable option, default
   value) -- font-size:0 hides that text visually without touching markup
   or content, and ::after supplies the sentence-case "Read more ->" in
   its place at the real size. */
body.tag article.preview-classic.preview-1 .cb-meta .read-more,
body.category article.preview-classic.preview-1 .cb-meta .read-more {
	font-size: 0 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
	color: var(--accent) !important;
}

body.tag article.preview-classic.preview-1 .cb-meta .read-more::after,
body.category article.preview-classic.preview-1 .cb-meta .read-more::after {
	content: "Read more \2192";
	font-family: var(--font-sans);
	font-size: 13px;
	font-weight: 400;
}

body.tag article.preview-classic.preview-1 .cb-meta .read-more:hover,
body.category article.preview-classic.preview-1 .cb-meta .read-more:hover {
	color: var(--ink) !important;
}

/* Shared archive score badge: cream badge inset 10px from the image's
   top-right corner, Bodoni Moda ~19px, per the Tag/Brand Archive
   artboard -- was previously unstyled theme default. One shared rule
   across every archive/listing template (tag, category, author, search)
   rather than a per-template copy, so any future change to it only
   needs to happen once. */
body.tag article.preview-classic.preview-1 .lets-review-api-score-box,
body.category article.preview-classic.preview-1 .lets-review-api-score-box,
body.author article.preview-classic.preview-1 .lets-review-api-score-box,
body.search-results article.preview-classic .lets-review-api-score-box {
	position: absolute;
	top: 10px;
	right: 10px;
	background-color: rgba(247, 244, 241, 0.88);
	font-family: var(--font-serif);
	font-size: 19px;
	padding: 4px 9px;
	height: auto;
	width: auto;
	line-height: 1.2;
}

/* Tag description: dynamic WordPress term description, styled per the
   artboard. May contain multiple paragraphs (WYSIWYG term descriptions
   support this) -- spacing is per-paragraph, not assumed single-block. */
.taxonomy-description {
	max-width: 760px;
	color: #3A342D;
	margin-bottom: 32px;
}

.taxonomy-description p {
	margin: 0 0 17px;
}

.taxonomy-description p:last-child {
	margin-bottom: 0;
}

/* Pagination: theme default 50px top/bottom padding was a large empty
   block above and below a single line of page numbers. */
.pagination.font-2 {
	padding: 32px 0 0 !important;
}

/* ==========================================================================
   404 (see 404.php -- full template override, not just restyled)
   ========================================================================== */

.hr-404 {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: 18px;
	padding: 100px 40px;
}

.hr-404-numeral {
	font-family: var(--font-serif);
	font-size: 96px;
	font-weight: 400;
	line-height: 1;
	color: var(--ink);
}

.hr-404-title {
	margin: 0;
	font-family: var(--font-serif);
	font-size: 32px;
	font-weight: 400;
}

.hr-404-intro {
	margin: 0;
	max-width: 420px;
	font-family: var(--font-sans);
	font-size: 16px;
	color: var(--ink-soft);
}

.hr-404 form.search {
	margin-top: 10px;
	width: 360px;
	max-width: 100%;
	position: relative;
}

.hr-404 form.search .search-field {
	width: 100%;
	box-sizing: border-box;
	border: 1px solid var(--line-2);
	padding: 12px 40px 12px 14px;
	font-family: var(--font-sans);
	font-size: 14px;
	color: var(--ink);
}

.hr-404 form.search .search-submit {
	position: absolute;
	right: 10px;
	top: 50%;
	transform: translateY(-50%);
	background: none;
	border: none;
	color: var(--muted-2);
	cursor: pointer;
}

.hr-404-links {
	display: flex;
	gap: 20px;
	margin-top: 6px;
	font-family: var(--font-sans);
	font-size: 14px;
}

.hr-404-links a {
	color: var(--accent);
	text-decoration: none;
}

.hr-404-links a:hover {
	color: var(--ink);
}

@media (max-width: 767px) {
	.hr-404 {
		padding: 60px 24px;
	}

	.hr-404-numeral {
		font-size: 64px;
	}

	.hr-404-title {
		font-size: 24px;
	}
}

/* ==========================================================================
   Contact page
   ========================================================================== */

/* The intro copy is classic-editor content (a plain <h2>, no wp-block-
   heading class), so step 01's Gutenberg-scoped heading rule never
   reached it -- broadened here rather than there, to avoid loosening
   that rule's scope for every other post. */
/* Static-page H1 scale: 44px, not the theme's default 56px single-post size. */
body.page-id-149 .entry-title.title {
	font-size: 44px !important;
}

body.page-id-149 .entry-content h2:not(.wp-block-heading) {
	font-family: var(--font-serif) !important;
	font-size: 28px !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
}

/* Info + form side by side without restructuring the page's own content.
   Two bugs, fixed in two rounds:
   1. Auto-flow alone doesn't work: giving the form grid-row:1/-1 while
      leaving the intro h2/p's on implicit auto-placement caused the
      browser to skip column-2 rows the form's span occupies, scattering
      the intro paragraphs onto extra rows below the form instead of
      keeping them together to its left.
   2. grid-column:1 alone (round 1's fix) put each intro element on its
      OWN auto-placed row, and row 1's height is set by the tallest item
      IN row 1 -- since the form (grid-row:1, ~470px tall) shares row 1
      with only the H2, row 1 itself became ~470px tall, leaving a large
      blank gap in column 1 below the short H2 before row 2 (the first
      paragraph) even starts.
   3. Giving every intro element grid-row:1 (an attempt to make them
      "stack normally" by sharing one cell) was wrong -- grid items
      sharing a row/column stretch to fill and cover that same area by
      default; confirmed live, it made the H2 and all three paragraphs
      render on top of each other instead of stacking.
   The actual fix: each intro element gets its OWN explicit row (H2 =
   row 1, each <p> the next row in source order, via :nth-of-type since
   there's no wrapper to select by), and the form SPANS all of those
   rows in column 2 (grid-row: span 4) instead of being confined to row
   1 alone -- so row 1's height is set by the H2 alone, not fighting the
   form's full height. */
@media (min-width: 768px) {
	body.page-id-149 .entry-content {
		display: grid;
		grid-template-columns: 1fr 1fr;
		grid-template-rows: repeat(4, auto);
		gap: 12px 56px;
		align-items: start;
	}

	body.page-id-149 .entry-content > h2 {
		grid-column: 1;
		grid-row: 1;
	}

	body.page-id-149 .entry-content > p:nth-of-type(1) {
		grid-column: 1;
		grid-row: 2;
	}

	body.page-id-149 .entry-content > p:nth-of-type(2) {
		grid-column: 1;
		grid-row: 3;
	}

	body.page-id-149 .entry-content > p:nth-of-type(3) {
		grid-column: 1;
		grid-row: 4;
	}

	body.page-id-149 .entry-content .wpforms-container {
		grid-column: 2;
		grid-row: 1 / span 4;
		align-self: start;
		width: 100% !important;
		max-width: 340px;
	}
}

@media (max-width: 767px) {
	/* Mobile: explanatory copy first, form second -- plain document order
	   already gives this (h2/p's precede the form in source), so no grid
	   is needed here at all; this rule just makes sure the desktop grid
	   above doesn't leak into mobile via any inherited display:grid. */
	body.page-id-149 .entry-content {
		display: block;
	}
}

/* WPForms: underline fields, small-caps labels, --accent submit --
   matching the site's own form language instead of WPForms' boxed
   default (border, bold black labels). */
body.page-id-149 .wpforms-field-label {
	font-family: var(--font-sans) !important;
	font-size: 11px !important;
	font-weight: 600 !important;
	letter-spacing: 0.1em !important;
	text-transform: uppercase !important;
	color: var(--muted-2) !important;
}

/* WPForms' own "medium" size class caps both the field-row wrapper (Name)
   and the input itself (Email) at a fixed ~214px -- overridden to fill
   the column, which is already the intended field width in this layout. */
body.page-id-149 .wpforms-field-medium,
body.page-id-149 .wpforms-field-small,
body.page-id-149 .wpforms-field-large {
	width: 100% !important;
	max-width: 100% !important;
}

body.page-id-149 .wpforms-field {
	margin-bottom: 20px !important;
}

body.page-id-149 .wpforms-field input[type="text"],
body.page-id-149 .wpforms-field input[type="email"],
body.page-id-149 .wpforms-field textarea {
	width: 100% !important;
	max-width: 100% !important;
	border: none !important;
	border-bottom: 1px solid var(--ink) !important;
	border-radius: 0 !important;
	padding: 10px 0 !important;
	font-family: var(--font-sans) !important;
	font-size: 16px !important;
	box-sizing: border-box !important;
}

body.page-id-149 .wpforms-field textarea {
	height: 80px !important;
}

body.page-id-149 .wpforms-submit {
	background-color: var(--accent) !important;
	border: none !important;
	color: #fff !important;
	text-transform: uppercase;
	font-family: var(--font-sans);
	font-size: 12px;
	letter-spacing: 0.12em;
	padding: 13px 24px !important;
}

body.page-id-149 .wpforms-submit:hover,
body.page-id-149 .wpforms-submit:focus-visible {
	background-color: #6F1F1F !important;
	color: #fff !important;
}

/* ==========================================================================
   Search results (see search.php -- a dedicated search field + result
   count didn't exist on the results page itself, only in the header)
   ========================================================================== */

.hr-search-results-head {
	max-width: 760px;
	margin-bottom: 24px;
}

.hr-search-results-head form.search {
	display: block;
	position: relative;
	border-bottom: 1px solid var(--ink);
	margin-bottom: 24px;
}

.hr-search-results-head form.search .search-field {
	width: 100%;
	box-sizing: border-box;
	border: none;
	padding: 12px 30px 12px 0;
	font-family: var(--font-sans);
	font-size: 20px;
	color: var(--ink);
}

.hr-search-results-head form.search .search-submit {
	position: absolute;
	right: 0;
	top: 50%;
	transform: translateY(-50%);
	background: none;
	border: none;
	color: var(--muted-2);
	cursor: pointer;
}

/* Icon removed from this main query field only -- the sidebar search
   widget keeps its own icon untouched (different selector entirely). */
.hr-search-results-head form.search .search-submit .codetipi-15zine-i-search {
	display: none;
}

/* The results page had zero H1 elements at all -- the search field and a
   plain count line, no heading. Matches the tag/category archive H1
   scale (64px Bodoni) for consistency with other archive-style listing
   pages, rather than inventing a third heading size. */
.hr-search-results-title {
	margin: 0 0 8px;
	font-family: var(--font-serif);
	font-size: 64px;
	font-weight: 400;
	line-height: 1;
}

.hr-search-results-count {
	font-family: var(--font-sans);
	font-size: 13px;
	color: var(--muted-2);
}

/* "Nothing found" fallback -- theme default is a bold sans H2 + plain
   paragraph + a second, unstyled search form. */
#post-not-found h2 {
	font-family: var(--font-serif) !important;
	font-size: 28px !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
	margin-bottom: 12px;
}

#post-not-found .entry-content p {
	font-family: var(--font-sans);
	font-size: 16px;
	color: var(--ink-soft);
}

#post-not-found .article-footer form.search {
	position: relative;
	max-width: 360px;
}

#post-not-found .article-footer .search-field {
	width: 100%;
	box-sizing: border-box;
	border: 1px solid var(--line-2);
	padding: 12px 40px 12px 14px;
	font-family: var(--font-sans);
	font-size: 14px;
}

#post-not-found .article-footer .search-submit {
	position: absolute;
	right: 10px;
	top: 50%;
	transform: translateY(-50%);
	background: none;
	border: none;
	color: var(--muted-2);
}

/* Custom "no results" block (search.php) -- the theme's own
   codetipi_15zine_main_layout_none() fallback wasn't rendering when
   found_posts was 0 on this template, so this replaces it outright
   rather than debugging a hook order issue in vendor code for a
   low-traffic page. */
.hr-search-no-results {
	max-width: 620px;
	padding: 80px 0;
}

.hr-search-no-results h1 {
	margin: 0 0 12px;
	font-family: var(--font-serif);
	font-size: 28px;
	font-weight: 400;
}

.hr-search-no-results p {
	margin: 0 0 20px;
	font-family: var(--font-sans);
	font-size: 16px;
	color: var(--ink-soft);
}

.hr-search-no-results-links {
	display: flex;
	gap: 20px;
	font-family: var(--font-sans);
	font-size: 14px;
}

.hr-search-no-results-links a {
	color: var(--accent);
	text-decoration: none;
}

.hr-search-no-results-links a:hover {
	color: var(--ink);
}

/* ==========================================================================
   Author page (see author.php -- full-width horizontal band instead of a
   narrow sidebar-style vertical card)

   Scoped to body.author: these selectors were previously bare ".author-box",
   which also matches the single-post author box at the bottom of a review
   (same markup, different context). That leak forced a 96px avatar and a
   40px !important name onto the single-post box everywhere, overriding the
   23px name size meant for it (see .author-box .cb-title.title further up)
   and conflicting with the review-template spec's ~72px, not-oversized box.
   ========================================================================== */

body.author .author-box-wrap {
	margin-bottom: 28px;
	padding-bottom: 32px;
	border-bottom: 1px solid var(--line);
}

body.author .author-box.tipi-flex {
	flex-wrap: nowrap;
	align-items: center;
	text-align: left;
	gap: 26px;
	/* Parent theme renders this as a padded sidebar "card" (30px 20px);
	   stripped so the avatar/name/bio sit flush with the shared left edge
	   (heading + post cards below both start at the same x) instead of
	   indented 20px, and so the box doesn't carry an extra 60px of
	   top+bottom padding on top of its own content height. */
	padding: 0;
}

body.author .author-box .mask {
	flex-shrink: 0;
}

body.author .author-box .mask img.avatar {
	width: 96px !important;
	height: 96px !important;
}

body.author .author-box .cb-meta.meta {
	flex: 1;
	min-width: 0;
}

body.author .author-box .cb-title.title {
	margin: 0 0 8px;
	font-family: var(--font-serif) !important;
	font-size: 40px !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
}

body.author .author-box .cb-author-bio.biography {
	margin: 0;
	max-width: 560px;
	font-family: var(--font-sans);
	font-size: 16px;
	line-height: 1.6;
	color: var(--ink-soft);
}

.hr-author-posts-heading {
	font-family: var(--font-sans);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--muted-2);
	margin-bottom: 16px;
}

@media (max-width: 767px) {
	body.author .author-box.tipi-flex {
		flex-direction: column;
		align-items: flex-start;
	}

	body.author .author-box .mask img.avatar {
		width: 72px !important;
		height: 72px !important;
	}

	body.author .author-box .cb-title.title {
		font-size: 30px !important;
	}
}

/* ==========================================================================
   Post preview headers -- category eyebrow above the title, author/date/
   comments (or read-time) combined into one meta row below the excerpt.
   Covers TWO contexts with different markup: loop cards (home, archives --
   article.preview-classic > .cb-meta.cb-article-meta.meta, with
   title.cb-post-title + excerpt.body-color + byline-10 with cats/
   comments) and the single review post's own header (a *different*,
   plainly-classed .meta container -- found the hard way: the single-post
   article ALSO contains a hidden .cb-meta.cb-article-meta.meta elsewhere
   on the page (the mobile floating strip, title-only), so that selector
   silently never matched the real header at all. .meta:has(>.title-wrap)
   targets the real one specifically, keyed off hr-standfirst/title-wrap,
   both unique to the single-post header). The :is() below applies the
   shared rules to both; only one signature matches on any given element,
   so the two contexts don't collide.

   The theme renders title -> byline(author/date) -> excerpt/standfirst ->
   byline(category[/comments]), in that DOM order. Grid was tried first,
   but items spanning all columns inflate max-content column widths -- CSS
   grid distributes a spanning item's intrinsic width across every track it
   crosses, so the row-4 columns ended up ~equal-width instead of content-
   sized. flex-wrap sidesteps this: cats/title/excerpt(-or-standfirst) get
   flex-basis:100% so each forces its own line, while byline-3 (author/
   date, left intact) and comments/read-time (order 2, no forced basis)
   fall onto the next line together, side by side, in DOM order. Only
   byline-10 is unwrapped (display:contents) since just its cats part
   needs to escape to the top row. */
article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
}

article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) > .cb-byline.byline-10 {
	display: contents;
}

article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) .byline-part.cats {
	order: -1;
	flex-basis: 100%;
	font-family: var(--font-sans);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--accent);
}

/* .byline-shaded .cats a sets color/letter-spacing with !important
   (see above, for the plugin's own category pills) -- match it here so
   the eyebrow isn't silently overridden back to the muted pill color. */
article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) .byline-part.cats a {
	color: inherit !important;
	letter-spacing: inherit !important;
	text-transform: inherit !important;
}

/* Loop cards: h2/h3 title + excerpt are direct children of .cb-meta. */
article.preview-classic .cb-meta.cb-article-meta.meta > .title.cb-post-title {
	order: 0;
	flex-basis: 100%;
}

article.preview-classic .cb-meta.cb-article-meta.meta > .excerpt.body-color {
	order: 1;
	flex-basis: 100%;
}

/* Single review post header: h1 is wrapped in .title-wrap, and the
   standfirst (Step 12's excerpt injection) stands in for the excerpt. */
article .meta:has(> .title-wrap) > .title-wrap {
	order: 0;
	flex-basis: 100%;
}

article .meta:has(> .title-wrap) > .hr-standfirst {
	order: 1;
	flex-basis: 100%;
}

article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) > .cb-byline.byline-3 {
	order: 2;
	align-self: flex-end;
}

/* Pale divider under the single-post header (breadcrumbs/eyebrow/H1/deck/
   meta), before the hero -- shared by review and non-review articles
   alike, since both use this same .meta:has(>.title-wrap) header. */
article .meta:has(> .title-wrap) {
	padding-bottom: 24px;
	margin-bottom: 24px;
	border-bottom: 1px solid var(--line);
}

/* "By " prefix on the author name, matching the design reference's
   "By Agnes" byline format -- content-only, no markup change needed. */
article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) .byline-part.author::before {
	content: "By ";
}

/* The theme's own byline-part spans render with no spacing around the
   separator dot ("Agnes·August 14, 2026") -- give every dot breathing
   room. Covers both the native separator-date and the injected
   separator-readtime/separator-comments dots. */
article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) .byline-part.separator {
	margin: 0 6px;
}

/* The theme hides its own separator-comments span in this context;
   a ::before dot on .comments replaces it rather than fighting that. */
article.preview-classic .cb-meta.cb-article-meta.meta .byline-part.comments {
	order: 2;
}

article.preview-classic .cb-meta.cb-article-meta.meta .byline-part.comments::before {
	content: "\00b7";
	margin: 0 6px;
	color: var(--muted-2);
}

/* .byline-shaded .byline-part (parent theme) sets line-height:26px, a
   leftover from when this text sat inside a rounded pill badge --
   .comments inherits it since it lives inside .byline-10 (class
   byline-shaded), which visibly misaligned it against the 16.9px-
   line-height author/date text next to it in the same row. (font-size
   and text-transform:lowercase are already forced above, at the original
   .byline-part.comments a rule -- !important was fighting !important
   there, so lowercase belongs at the source, not layered on top.) */
article.preview-classic .cb-meta.cb-article-meta.meta .byline-part.comments,
article.preview-classic .cb-meta.cb-article-meta.meta .byline-part.comments a {
	line-height: inherit;
}

article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) .byline-part.read-time {
	order: 2;
	color: var(--muted-2);
	text-transform: none;
}

/* Multi-category eyebrow: two adjacent .cat links had no separator
   ("Brand SpotlightTrending"). */
article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) .byline-part.cats a.cat + a.cat::before {
	content: " | ";
	color: var(--muted-2);
	font-weight: 400;
}

/* ==========================================================================
   Live feedback round -- nav centering, score badge font, newsletter
   widget, pagination, homepage intro heading, post-loop divider colour.
   ========================================================================== */

/* Nav row was visually centered instead of flush-left under the logo: the
   flex row is [mini-logo spacer | nav ul | search-icon spacer], and both
   spacers have flex-grow:1/flex-basis:0% (theme default), splitting the
   remaining space evenly on both sides of the fixed-width nav like a
   3-column centered layout. The mini logo duplicates the real logo shown
   in the row above and isn't in the design reference at all, so it's
   dropped rather than fixed; the search icon's spacer is un-grown and
   pushed flush right with margin-left:auto instead, so the nav ul (now
   the first visible child) sits flush left. */
.main-menu-wrap > .logo-menu-wrap {
	display: none;
}

.main-menu-wrap > ul.menu-icons {
	flex-grow: 0 !important;
	flex-basis: auto !important;
	margin-left: auto;
}

/* Score badge (Let's Review's own corner badge on card thumbnails) was
   unstyled Montserrat -- design reference uses Bodoni Moda everywhere a
   score appears. The "8" vs "8.0" formatting is handled in PHP (see
   functions.php) since it's plugin-rendered plain text, not something
   CSS can reformat. */
.lets-review-final-score {
	font-family: var(--font-serif) !important;
	font-weight: 400 !important;
}

/* Post-loop divider was the theme's own default 1px dotted near-white
   border (rgb(242,242,242)), not the --line token the rest of the site
   (and the design reference's own between-post divider) uses. */
body.home article.preview-classic.separation-border-style,
body.blog article.preview-classic.separation-border-style {
	border-bottom: 1px solid var(--line) !important;
}

/* Pagination was fully untouched theme default: 10px Open Sans, current
   page rendered as a solid filled button (border+black background+white
   text) instead of plain text with an accent underline. */
.pagination.font-2 .page-numbers {
	font-family: var(--font-sans);
	font-size: 13px;
	color: var(--muted-2);
	border: none !important;
	background: none !important;
	padding: 4px 6px;
}

.pagination.font-2 .page-numbers.current {
	color: var(--ink) !important;
	border-bottom: 2px solid var(--accent) !important;
	padding-bottom: 2px;
}

.pagination.font-2 .page-numbers:hover {
	color: var(--accent) !important;
}

/* Homepage SEO intro block ("handbag.reviews" + welcome copy): item 8
   only styled the paragraph text, not the heading (still theme default
   sans-serif) or the inline links (still default underlined black). */
.block-html-content h1,
.block-html-content h2,
.block-html-content h3,
.block-html-content h4 {
	font-family: var(--font-serif);
	font-size: 22px;
	font-weight: 400;
}

/* #homepage-content a { text-decoration:underline } is a separate,
   inline (no-href) stylesheet -- likely Customizer Additional CSS --
   whose ID selector outranks a plain class rule regardless of source
   order, hence !important here. */
/* Christa's call: underline body-copy links everywhere, overriding the
   design reference's colour-only treatment here too -- !important still
   needed to beat the inline #homepage-content a rule's ID specificity. */
.block-html-content a {
	color: var(--accent);
	text-decoration: underline !important;
}

/* Newsletter widget: title/background/dark-label contrast were already
   fixed (Step 8 area above) -- the label and submit button were still
   the mc4wp plugin's own default styling (sentence case label with a
   trailing colon, plain grey button), not the design reference's small-
   caps label and filled accent button. */
.mc4wp-form label {
	font-family: var(--font-sans);
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: 0.1em;
}

.mc4wp-form input[type="submit"],
.mc4wp-form button[type="submit"] {
	background-color: var(--accent) !important;
	color: #fff !important;
	border: none !important;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	font-family: var(--font-sans);
	font-size: 13px;
	font-weight: 600;
	padding: 14px 24px;
	cursor: pointer;
}

/* Sign Up button turned solid black on hover -- kept burgundy per
   Christa's call, just a touch darker than the resting state so the
   hover state still reads as a state change. #6F1F1F matches the same
   darker-burgundy shade used for every other primary CTA's hover/focus
   (WPForms submit, verdict panel's primary retailer button). */
.mc4wp-form input[type="submit"]:hover,
.mc4wp-form button[type="submit"]:hover,
.mc4wp-form input[type="submit"]:focus-visible,
.mc4wp-form button[type="submit"]:focus-visible {
	background-color: #6F1F1F !important;
	color: #fff !important;
}

/* Newsletter widget: label-to-input and input-to-button gaps were tight
   (6px/10px) compared to the reference's more generous spacing. */
.widget_mc4wp_form_widget .mc4wp-form label {
	margin-bottom: 10px;
}

.widget_mc4wp_form_widget .mc4wp-form input[type="email"],
.widget_mc4wp_form_widget .mc4wp-form input[type="text"] {
	margin-bottom: 20px;
}

/* Nav links had padding:50px 6px (inline/Customizer CSS, no href) --
   ballooning the whole row to ~116px tall, versus the reference's
   padding:16px 40px on the row itself. Overriding just the vertical
   padding here keeps the existing horizontal spacing/hit area.

   The active item's own border-bottom:2px (see .current-menu-item > a,
   above) makes ONLY that link 2px taller than its siblings (51px vs
   49px), since none of the others reserve that space -- with
   align-items:center on the row, each link centers around its own box,
   so the active item's text sits ~1px lower than its neighbours'. A
   transparent 2px border on every link reserves the same space
   regardless of active state, so the row's baseline stays level when
   the accent-coloured indicator swaps in. */
.main-menu > li > a,
.main-menu-wrap .menu-icons > li > a {
	padding-top: 18px !important;
	padding-bottom: 18px !important;
	border-bottom: 2px solid transparent !important;
}

/* Comment count's separator dot: the ::before pseudo-element is attached
   to .byline-part.comments itself (the span, not the <a> inside it), so
   the earlier font-size/text-transform fixes -- which only targeted the
   span and its anchor's *text* -- never reached it. The parent theme's
   .byline-shaded .byline-part still sets font-size:0.8em directly on the
   span, which the pseudo inherits, keeping the dot tiny and its line-box
   mismatched against the 13px text around it.

   align-items:baseline (tried first) didn't fix the visible offset: the
   span is ALSO display:flex (parent theme's .byline-part rule), and a
   flex item that is itself a flex container reports its baseline from
   its own internal layout, which didn't line up with .byline-3's
   baseline in the outer row (measured ~7-12px apart).

   display:inline (tried second) fixed the baseline but collapsed all
   spacing from .byline-3 -- a flex item's display gets blockified for
   layout purposes when it participates in a flex container, so the
   outer row's (nonexistent) gap was the only thing providing separation
   before, and removing this item from flex layout removed that too,
   jamming "2026" directly against "0 comments".

   display:inline-block is the fix: still governed by normal baseline
   alignment (a non-replaced inline-block's baseline is its last line
   box's baseline, same mechanism as plain inline text, so it lines up
   with .byline-3 correctly), but keeps real box-model margins working
   predictably like a normal inline element, so an explicit margin-left
   restores the separation that display:inline lost. */
article.preview-classic .cb-meta.cb-article-meta.meta .byline-part.comments {
	display: inline-block !important;
	align-self: flex-end;
	margin-left: 6px;
	font-size: 13px !important;
	line-height: 16.9px !important;
}

/* The <a> itself is display:block (parent theme's own byline-part
   styling), which pushed it onto its own line below the ::before dot
   (inline) instead of sharing a line with it -- the actual source of
   the dot floating disconnected above the text, not a flex/baseline
   issue at all. */
article.preview-classic .cb-meta.cb-article-meta.meta .byline-part.comments a {
	display: inline !important;
}

/* Meta row (author/date/comments/read-time) renders at the parent
   theme's default bold weight -- the design reference's byline text has
   no font-weight set, i.e. normal/400. Excludes .cats: that's the
   eyebrow above the title, deliberately 600 (see rule above). */
article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) .byline-part:not(.cats),
article :is(.cb-meta.cb-article-meta.meta, .meta:has(> .title-wrap)) .byline-part:not(.cats) a {
	font-weight: 400 !important;
}

/* Search overlay: "Search" placeholder was theme-default Montserrat at
   20px/3px border -- reference calls for DM Sans 700 at 32px/2px border.
   The helper line ("Type to search...") was Open Sans 12px in --ink --
   reference wants --font-sans 14px in --muted-2. */
.content-search .search-field.font-h {
	font-family: var(--font-sans) !important;
	font-size: 32px !important;
	font-weight: 700 !important;
	border-bottom-width: 2px !important;
	border-bottom-color: var(--ink) !important;
}

.content-search .search-hints .search-hint {
	font-family: var(--font-sans) !important;
	font-size: 14px !important;
	color: var(--muted-2) !important;
}

/* Mobile header: same symmetric-spacer centering pattern as the desktop
   nav fix above -- [menu-left][logo][menu-right] with menu-left/right
   both flex-grow:1/flex-basis:0%, splitting space evenly and forcing the
   logo to the horizontal center. The design reference wants the logo
   flush left and the hamburger + search icons grouped together on the
   right instead. Reordered via flex `order`, with margin-left:auto on
   the now-first right-side item (search) to push that whole group to
   the end -- same technique as the desktop search-icon spacer.
   Round 2: the order fix alone wasn't enough -- .logo-main-wrap itself
   is flex/justify-content:center (centering the <img> WITHIN its own
   box) and, despite flex-grow:0, was still sizing itself to 244px, far
   wider than the ~204px logo it contained, so the image read as
   centered in the row rather than flush left. Pinned the wrapper's own
   justify-content to flex-start and capped the image to the requested
   ~145px, and compacted the row's own top/bottom padding (the 114px
   header height was mostly padding around a much shorter logo). */
@media (max-width: 768px) {
	header.site-mob-header .bg-area.header-padding {
		padding-top: 0;
		padding-bottom: 0;
		min-height: 0;
	}

	header.site-mob-header .tipi-row.tipi-vertical-c {
		min-height: 115px;
	}

	header.site-mob-header .logo-main-wrap {
		order: -1;
		flex: 0 0 auto;
		justify-content: flex-start;
		text-align: left;
	}

	header.site-mob-header .logo-main-wrap img {
		width: 145px !important;
		height: auto !important;
	}

	header.site-mob-header .menu-right.icons-wrap {
		flex-grow: 0;
		order: 1;
		margin-left: auto;
	}

	header.site-mob-header .menu-left.icons-wrap {
		flex-grow: 0;
		order: 2;
	}
}

/* Mobile drawer backdrop: the theme already has a full-viewport overlay
   element for exactly this (.tipi-overlay-dark, position:fixed, inset:0)
   but nothing ever switches it on for the drawer specifically -- it sat
   at opacity:0/visibility:hidden the whole time the drawer was open.
   Reusing it (rather than adding a new element) keeps the same z-index
   stack the theme already manages elsewhere; the drawer itself (z-index:1
   natively) needs raising above the overlay's z-index:101 so it isn't
   the overlay covering the drawer instead of the page behind it. Body
   scroll lock (overflow:hidden while body.mob-open) was already working
   natively -- confirmed live, not something this adds. */
@media (max-width: 767px) {
	body.mob-open .mob-menu-wrap {
		z-index: 150;
	}

	body.mob-open .tipi-overlay.tipi-overlay-base.tipi-overlay-dark {
		opacity: 0.4 !important;
		visibility: visible !important;
	}

	/* Expandable drawer items (Reviews, Trending, Guides, ...): the
	   theme's own .child-is-open rule rotates the down-chevron -90deg,
	   which reads as a right-facing arrow rather than "now pointing up".
	   180deg turns the same down-chevron glyph upside down instead --
	   unscoped to any one menu item, so every expandable item gets the
	   same closed-down/open-up behaviour automatically. */
	.mobile-navigation-dd .child-is-open i {
		transform: rotate(180deg);
	}
}

/* Sidebar search widget: Christa asked for it back (was removed at some
   point). Uses the theme's own shared search-form markup (same as the
   header search modal), restyled to the design reference's bordered box
   + "GO" text button instead of the theme's icon-only button. */
.widget_search .search.tipi-flex {
	display: flex;
	align-items: center;
	gap: 10px;
	border: 1px solid var(--ink);
	padding: 10px 14px;
}

.widget_search .search-field {
	flex: 1;
	height: auto !important;
	border: none !important;
	background: transparent !important;
	font-family: var(--font-sans) !important;
	font-size: 14px !important;
	font-weight: 400 !important;
	padding: 0 !important;
	line-height: 1.4 !important;
}

.widget_search .search-submit {
	position: static !important;
	height: auto !important;
	width: auto !important;
	min-height: 0 !important;
	background: none !important;
	border: none !important;
	padding: 0 !important;
	display: flex;
	align-items: center;
	cursor: pointer;
}

.widget_search .search-submit i {
	display: none;
}

.widget_search .search-submit::after {
	content: "GO";
	font-family: var(--font-sans);
	font-size: 12px;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--muted-2);
}

/* Mobile hamburger menu (the full-screen slide-out panel): links were
   still Open Sans, the theme's pre-redesign default -- untouched by any
   earlier fix since this panel isn't visible/reachable at desktop
   widths where verification happens. Swapped to the site's DM Sans. */
.mobile-navigation .menu-mobile a {
	font-family: var(--font-sans) !important;
}

/* Back-to-top button: spec from Christa (via a design pass) -- 42px
   square, 1px #CFC8BE border, transparent background, slim #F7F4F1
   chevron, centred with 24px top margin, #F7F4F1 fill / #16130F arrow
   on hover, visible focus ring. The theme's default was a bulky 60px
   icon with a 2px solid white border baked directly onto the <i>
   itself (the "thick white outline"), at 30px font-size. */
.to-top.cb-to-top {
	display: flex;
	justify-content: center;
	margin-top: 24px !important;
}

.to-top.cb-to-top a#to-top-a {
	display: flex;
}

.to-top.cb-to-top i.cb-circle {
	display: flex !important;
	align-items: center !important;
	justify-content: center !important;
	width: 42px !important;
	height: 42px !important;
	border: 1px solid #CFC8BE !important;
	border-radius: 0 !important;
	background-color: transparent !important;
	color: #F7F4F1 !important;
	font-size: 16px !important;
	line-height: 1 !important;
	position: static !important;
	top: auto !important;
	margin: 0 !important;
	padding: 0 !important;
	transform: none !important;
	box-sizing: border-box !important;
	transition: background-color 0.2s ease, color 0.2s ease;
}

.to-top.cb-to-top a#to-top-a:hover i.cb-circle {
	background-color: #F7F4F1 !important;
	color: #16130F !important;
}

.to-top.cb-to-top a#to-top-a:focus-visible i.cb-circle {
	outline: 2px solid #F7F4F1;
	outline-offset: 2px;
}

/* ==========================================================================
   External design QA pass (ChatGPT), 2026-08-20 -- confirmed each item
   against computed styles before fixing, not taken on faith.
   ========================================================================== */

/* 1. Page width: theme default is max-width:1200px / 30px gutters
   (.wrap, .tipi-row + .side-spacing, both parent-theme globals) --
   reference is 1280px / 40px gutters, giving a noticeably wider article
   column (1200px content vs the current 1140px). Global, site-wide
   change since both rules are used everywhere, not just home. */
.wrap,
.tipi-row {
	max-width: 1280px !important;
}

.side-spacing {
	padding-left: 40px !important;
	padding-right: 40px !important;
}

/* Main/sidebar column proportions: the theme's own two-column wrapper
   (#cb-content > .tipi-cols, shared by every template with a sidebar --
   home, archives, author, search, contact, single posts) is a Bootstrap-
   style 8/4 percentage split (tipi-m-8/tipi-m-4) with negative-margin
   gutters, confirmed live to produce a ~819px main / ~409px sidebar / 0px
   visible gap at 1200px content width -- not the spec's fixed 844px main /
   56px gap / 300px sidebar. A percentage split can't give a fixed sidebar
   width at every viewport, so this replaces it with a real grid: sidebar
   pinned to 300px, gap a real 56px, main taking whatever's left (844px at
   the standard 1200px inner width). Scoped to min-width:769px, the same
   desktop breakpoint used elsewhere in this file -- mobile keeps the
   theme's own stacked single-column behavior untouched. */
@media (min-width: 769px) {
	#cb-content .tipi-cols {
		display: grid;
		grid-template-columns: minmax(0, 1fr) 300px;
		column-gap: 56px;
		margin-left: 0;
		margin-right: 0;
	}

	#cb-content .tipi-cols > #main,
	#cb-content .tipi-cols > .sidebar-wrap {
		width: auto;
		max-width: none;
		flex: none;
		float: none;
		padding-left: 0;
		padding-right: 0;
	}
}

/* 4. Primary nav was still Montserrat (theme default) -- font-weight/
   size/letter-spacing were already fixed to spec earlier this session,
   but font-family itself was never actually checked until this pass. */
.main-menu > li > a {
	font-family: var(--font-sans) !important;
}

/* 4. Newsletter input falls back to Arial -- only the label had a
   font-family override, never the input itself. */
.mc4wp-form input[type="email"],
.mc4wp-form input[type="text"] {
	font-family: var(--font-sans) !important;
}

/* 2. Card thumbnails were 260x173 (the raw codetipi-15zine-360-240 image
   size scaled by its .mask-img wrapper) -- reference uses 220x160 for
   the DESKTOP layout specifically. Scoped to min-width:769px (the site's
   mobile breakpoint used elsewhere) after this fixed size caused mobile
   cards to overflow horizontally -- mobile images need to stay fluid/
   full-width within their own narrower card, not a desktop-sized
   fixed box.
   The .mask-img <a> wrapper itself is theme-default width:100% of ITS
   OWN parent (not tied to the img), so shrinking only the img left the
   wrapper at its original ~248px width -- exposing a solid black gap
   next to the now-narrower photo. Its own parent, .cb-mask.mask, is a
   separate 248px-wide box with a dark placeholder background
   (rgb(34,34,34)) that was the actual source of the visible black
   strip. Constraining both the wrapper and this outer mask box to the
   same 220x160 removes the gap entirely.

   Round 2: this only fixed "stack"-layout cards. "split"-layout cards
   (most homepage cards below the first) size .cb-mask via
   flex: 0 0 34.666667% (see parent theme style-1020px.css:1752), not
   width -- flex-basis wins over width in a flex container, so the
   width:220px !important above was silently ignored there, leaving the
   234px-wider box exposing the same dark background again. Confirmed via
   CSSOM inspection (matched rule had no !important, but flex-basis beats
   width regardless of specificity). Overriding flex-basis directly here
   fixes both layouts. */
@media (min-width: 769px) {
	article.preview-classic .cb-mask.mask,
	article.preview-classic .mask-img {
		width: 220px !important;
		height: 160px !important;
		flex: 0 0 220px !important;
	}
	article.preview-classic .mask-img img {
		width: 220px !important;
		height: 160px !important;
	}
}

/* Mombasa review card thumbnail: not a sizing bug -- confirmed via pixel
   sampling of the source file itself that the dark region on the right
   is a genuinely dark part of the photo (a shadowed elevator/door
   interior), not an empty gap. Default center crop favoured that dark
   doorway over the model; shifted the crop left so the model and lit
   tiled wall are the focus instead. Scoped to this one post's thumbnail
   only, since it's specific to this photo's own composition. */
article.preview-classic.post-3623 .mask-img img {
	object-position: 20% center;
}

/* 5. Homepage SEO intro block stretched across the full 1140/1200px
   column -- reference constrains it to ~760px, keeping the H1 but
   giving it a readable line length instead of near-full-width lines. */
.block-html-content {
	max-width: 760px;
}

/* Top Bags widget heading: border-bottom only spanned the text's own
   width ("Top Bags", ~69px) since the H3 is inline-sized by default --
   reference extends the rule across the full widget width. */
.lets-review-widget .cb-sidebar-widget-title {
	display: block;
}

/* Desktop pagination was centred (inherited text-align/flex centering
   from an ancestor) -- reference left-aligns it under the article
   column, matching the "loop continues" note above it. */
.pagination.font-2 {
	display: flex;
	justify-content: flex-start;
}

/* "All brands" link: originally left off the brand-tag row because no
   index page existed to point it at (see functions.php) -- reusing the
   Reviews category page as the closest existing "browse everything"
   destination, same fallback already used on the 404 page. */
.hr-brand-row-all-link {
	color: var(--accent);
	font-family: var(--font-sans);
	font-size: 12px;
}

/* Top Bags rows: each .cb-widget-post already has 14px top/bottom
   padding matching the reference (rows separated by their own
   border-bottom), but ALSO had a 20px margin-bottom stacked on top,
   nearly tripling the visual gap between rows (61px measured vs an
   expected ~28px). */
.lets-review-widget .cb-widget-post {
	margin-bottom: 0 !important;
}

/* ==========================================================================
   Global footer refinement (full spec from Christa) -- consolidates
   three earlier rounds of iterative .cb-footer-lower padding tightening
   (100px -> 60px -> 40px -> 32px, each fixing part of the problem
   without ever settling the whole footer's spacing model) into one
   deliberate set of rules covering every element instead of trimming
   whatever looked tallest each time. Same shared footer partial is used
   on every template already (footer.php, unconditional), so no
   per-template CSS is needed for this to apply everywhere. */
.cb-footer-lower {
	background-color: var(--ink) !important;
	padding: 48px 40px 36px !important;
	height: auto !important;
	min-height: 0 !important;
}

.cb-footer-lower .wrap.clearfix {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
}

.cb-footer-lower .wrap.clearfix > div:first-child {
	margin-bottom: 0 !important;
}

.cb-footer-lower .wrap.clearfix > div:first-child img {
	max-width: 220px;
	height: auto;
}

.cb-footer-links {
	margin-top: 30px !important;
	margin-bottom: 0 !important;
}

.cb-footer-nav {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 24px;
	list-style: none;
	margin: 0;
	padding: 0;
}

/* Kills the theme's "/" separators between footer nav items regardless
   of exactly which selector injects them (search across the parent
   theme's CSS turned up nothing definitive -- broad ::before/::after
   reset is the reliable way to guarantee they're gone). */
.cb-footer-nav li::before,
.cb-footer-nav li::after,
.cb-footer-nav li > *::before,
.cb-footer-nav li > *::after {
	content: none !important;
}

.cb-footer-links a {
	font-size: 12px !important;
	letter-spacing: 0.12em;
	color: #F7F4F1 !important;
	text-decoration: none;
}

.cb-footer-links a:hover,
.cb-footer-links a:focus-visible {
	text-decoration: underline;
	color: #F7F4F1 !important;
}

.cb-footer-links a:focus-visible {
	outline: 2px solid #F7F4F1;
	outline-offset: 2px;
}

.cb-copyright {
	margin-top: 18px !important;
	margin-bottom: 0 !important;
	font-size: 12px !important;
	letter-spacing: 0.1em;
	color: #8A8278 !important;
}

/* Cookie settings footer link: removed per Christa's instruction (kept
   the plugin's own floating "show again" tab hidden below rather than
   restoring it -- removing the footer link was a deliberate call, not
   an oversight to patch around). */
#cookie-law-info-again {
	display: none !important;
}

@media (max-width: 768px) {
	.cb-footer-lower {
		padding: 40px 20px 28px !important;
	}

	.cb-footer-lower .wrap.clearfix > div:first-child img {
		max-width: 190px;
	}

	.cb-footer-links {
		margin-top: 28px !important;
	}

	.cb-footer-nav {
		display: grid;
		grid-template-columns: 1fr 1fr;
		row-gap: 16px;
		column-gap: 24px;
		justify-items: center;
	}

	.cb-footer-links a {
		font-size: 11px !important;
		letter-spacing: 0.1em;
	}

	.cb-copyright {
		margin-top: 24px !important;
	}

	.to-top.cb-to-top {
		margin-top: 24px !important;
	}
}

/* ==========================================================================
   Cookie consent banner (Cookie Law Info plugin) -- restyled to spec,
   real functionality (accept/reject/remembered choice, all handled by
   the plugin's own JS) untouched. Message text + all three action links
   are the plugin's own single-span markup (no wrapper elements to hook
   into), so layout relies on flex order rather than restructuring it.

   The plugin's "Settings" button/shortcode ([cookie_settings], button_4)
   exists in the schema but has no click handler wired up anywhere in
   this plugin version (1.8.3) -- it would be a dead button if shown, so
   it's deliberately left out rather than faked. The plugin's "show
   again" mechanism (the small tab that reopens the bar, already
   functional) is reused as the real "Cookie settings" control instead,
   moved into the footer -- see the PHP hook below. Its own floating-tab
   position is hidden so it isn't shown twice.
   ========================================================================== */
#cookie-law-info-bar {
	position: fixed !important;
	inset: auto 0 0 0 !important;
	width: 100% !important;
	max-width: none !important;
	background-color: #16130F !important;
	border-top: 1px solid #CFC8BE !important;
	border-radius: 0 !important;
	box-shadow: none !important;
	padding: 0 !important;
}

#cookie-law-info-bar > span {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 20px;
	max-width: 1280px;
	margin: 0 auto;
	padding: 18px 40px;
	font-family: var(--font-sans);
	font-size: 14px;
	line-height: 1.5;
	color: #F7F4F1;
}

#cookie-law-info-bar #cookie_action_close_header {
	order: 1;
	margin-left: auto;
}

#cookie-law-info-bar #cookie_action_close_header_reject {
	order: 2;
}

#cookie-law-info-bar #CONSTANT_OPEN_URL {
	order: 3;
}

#cookie-law-info-bar .cli-plugin-button {
	display: inline-flex !important;
	align-items: center;
	justify-content: center;
	min-height: 44px;
	padding: 0 24px !important;
	font-family: var(--font-sans) !important;
	font-size: 13px !important;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	border-radius: 0 !important;
	white-space: nowrap;
	transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

#cookie-law-info-bar #cookie_action_close_header {
	background-color: #8E2A2A !important;
	border: 1px solid #8E2A2A !important;
	color: #fff !important;
}

#cookie-law-info-bar #cookie_action_close_header:hover {
	background-color: #16130F !important;
	border-color: #F7F4F1 !important;
	color: #F7F4F1 !important;
}

#cookie-law-info-bar #cookie_action_close_header_reject {
	background-color: transparent !important;
	border: 1px solid #F7F4F1 !important;
	color: #F7F4F1 !important;
}

#cookie-law-info-bar #cookie_action_close_header_reject:hover {
	background-color: #F7F4F1 !important;
	color: #16130F !important;
}

#cookie-law-info-bar #cookie_action_close_header:focus-visible,
#cookie-law-info-bar #cookie_action_close_header_reject:focus-visible,
#cookie-law-info-bar #CONSTANT_OPEN_URL:focus-visible {
	outline: 2px solid #F7F4F1;
	outline-offset: 2px;
}

#cookie-law-info-bar #CONSTANT_OPEN_URL {
	color: #CFC8BE !important;
	font-family: var(--font-sans) !important;
	font-size: 13px !important;
	text-decoration: underline !important;
	white-space: nowrap;
}

#cookie-law-info-bar #CONSTANT_OPEN_URL:hover {
	color: #F7F4F1 !important;
}

@media (max-width: 768px) {
	#cookie-law-info-bar > span {
		flex-direction: column;
		align-items: stretch;
		padding: 16px;
		gap: 14px;
	}

	#cookie-law-info-bar #cookie_action_close_header,
	#cookie-law-info-bar #cookie_action_close_header_reject {
		order: unset;
		margin-left: 0;
		flex: 1;
		width: 100%;
	}

	/* Accept + Reject sit as an equal-width pair on their own row,
	   Cookie policy link stays full-width beneath them. */
	#cookie-law-info-bar #cookie_action_close_header,
	#cookie-law-info-bar #cookie_action_close_header_reject {
		display: inline-flex !important;
		width: calc(50% - 7px);
	}

	#cookie-law-info-bar #cookie_action_close_header {
		margin-right: 7px;
	}

	#cookie-law-info-bar #CONSTANT_OPEN_URL {
		text-align: center;
		width: 100%;
	}
}

/* ==========================================================================
   Review-template spec, section 10 -- Related Posts (single-post block).
   Two problems, both from the theme's "overlay" slider tile style:
   1. Heading used the theme's heavy uppercase Montserrat + a 6px black
      underline bar, not this site's editorial type system.
   2. Each card's title/category sat position:absolute, bottom:0 over the
      photo in white text -- explicitly against spec ("no large white
      titles over the images"). Converted to a normal stacked card: image
      on top at a fixed aspect ratio, eyebrow + Bodoni title below it in
      normal ink tones. Scoped to block-wrap-52, this block's specific
      instance id on the single-post template, so other slider/overlay
      blocks elsewhere on the site (if any) are untouched.
   ========================================================================== */

.block-title-wrap.singular-block-header .block-title.cb-module-title.title {
	font-family: var(--font-serif) !important;
	font-size: 30px !important;
	font-weight: 400 !important;
	text-transform: none !important;
	letter-spacing: normal !important;
	padding-bottom: 14px;
	border-bottom: 1px solid var(--ink);
}

.block-title-wrap.singular-block-header .block-title.cb-module-title.title::after {
	display: none !important;
}

/* Related Posts overlay cards: the category label (e.g. "Reviews",
   "Trending") sits directly on the photo in burgundy text with no
   background of its own, so it goes unreadable against a busy image.
   Compact semi-transparent warm-white chip behind just the label --
   title treatment and the existing image gradient are untouched.
   .block-wrap-slider.cb-style-overlay is the theme's stable class for
   this overlay-tile block design (not a per-instance block-wrap-NNN
   id), so this applies to every Related Posts block on the site. */
.block-wrap-slider.cb-style-overlay .byline-part.cats {
	display: inline-block;
	background-color: rgba(255, 255, 255, 0.85);
	padding: 3px 5px;
	border-radius: 0;
}

/* Card layout (image/eyebrow/title stacked, no white overlay text) is not
   fixed yet -- attempted converting the theme's absolute overlay slide to
   a normal stacked flow, but the slide's JS-driven height left a large
   blank gap and the title effectively invisible. Reverted rather than
   ship it broken; needs a proper fix (likely switching this block's own
   "Overlay" design setting to a non-overlay tile style, rather than
   fighting the slider's height calculation with CSS overrides). */

