/* Homepage sections (ticker, sponsor row, pillars, shop banner, blurb).
   Rebuilt to match design_handoff_cbm_marketplace/pages/CBM Homepage.dc.html
   exactly. Mobile-first overrides at ≤1024px / ≤640px. */

/* "Go Back to Search Results" — cbm_render_back_to_search_button() in
   inc/template-tags.php, shown on any page reached from a search result
   (new vehicle model, used/rent listing, Depot/Services listing). Styled
   deliberately louder than a plain text link — the user asked for it to
   be "easily visible", not a quiet breadcrumb — sitting on its own line
   above the page's own title/content. */
.cbm-back-to-search {
	display: inline-flex; align-items: center; gap: 6px; margin-bottom: 20px;
	background: var(--cbm-red); color: #fff; font-family: var(--cbm-font-body);
	font-weight: 700; font-size: 13px; letter-spacing: 0.02em; text-transform: uppercase;
	padding: 10px 18px; border-radius: 4px; text-decoration: none;
}
.cbm-back-to-search:hover { background: var(--cbm-red-hover); color: #fff; }

/* Standard bottom-right CONTACT ME / VISIT WEBSITE button pair — every
   supplier/manufacturer dedicated page (manufacturer showroom, dealer
   profile, Depot/Services listing detail). Red background, white letters,
   side by side, each with its own caption underneath — per the user
   (2026-08-26). See cbm_render_supplier_action_buttons() in
   inc/template-tags.php. */
.cbm-supplier-actions { display: flex; flex-direction: column; align-items: flex-end; gap: 20px; padding: 40px 0; }
.cbm-supplier-actions__item { display: flex; flex-direction: column; align-items: center; text-align: center; max-width: 220px; }
.cbm-supplier-actions__item form { margin: 0; }
.cbm-supplier-actions__btn {
	display: inline-block; background: var(--cbm-red); color: #fff; font-family: var(--cbm-font-body);
	font-weight: 700; font-size: 13px; letter-spacing: 0.02em; text-transform: uppercase;
	padding: 13px 30px; border-radius: 4px; border: none; text-decoration: none; cursor: pointer;
}
.cbm-supplier-actions__btn:hover { background: var(--cbm-red-hover); color: #fff; }
.cbm-supplier-actions__btn--whatsapp { background: #25D366; } /* WhatsApp green (2026-10-13) */
/* 2026-10-19: client brand colours (button_colour / button_text_colour meta), set as inline vars */
.cbm-supplier-actions--brand .cbm-supplier-actions__btn:not(.cbm-supplier-actions__btn--whatsapp) { background: var(--cbm-btn-bg, var(--cbm-red)); color: var(--cbm-btn-fg, #fff); }
.cbm-supplier-actions--brand .cbm-supplier-actions__btn:not(.cbm-supplier-actions__btn--whatsapp):hover { background: var(--cbm-btn-bg, var(--cbm-red)); color: var(--cbm-btn-fg, #fff); filter: brightness(0.9); }
.cbm-supplier-actions__btn--whatsapp:hover { background: #1DA851; }
.cbm-supplier-actions__caption { font-size: 12px; color: var(--cbm-muted-grey); line-height: 1.4; margin: 10px 0 0; }
@media (max-width: 640px) {
	.cbm-supplier-actions { align-items: center; }
}

/* Boxed "contact card" treatment - without this the CONTACT ME / VISIT WEBSITE
   pair sits right-aligned in a full-width row with nothing to its left to balance
   it, which reads as broken/empty on a listing with no gallery photos (Jonathan,
   2026-09-26: AK Carpets "not good in terms of layout design"). Scoped by body
   class (WordPress's own single-{post_type} class) so the manufacturer context,
   which already looks right (logo/text fill the row above it), is untouched.
   Dealer pages briefly got this same treatment 2026-09-28 but it was the wrong
   fix - see .cbm-dealer-sidebar below, which sits the buttons IN the sidebar
   column instead (same structural fix directory listings already use), so this
   boxed/right-aligned row treatment never applies to them. */
body.single-workshop_listing .cbm-supplier-actions,
body.single-service_listing .cbm-supplier-actions {
	width: fit-content;
	margin-left: auto;
	padding: 24px 32px;
	background: #f7f7f7;
	border: 1px solid #e5e5e5;
	border-radius: 8px;
	margin-right: 0;
}

/* Subscriber Contact Me confirmation pop-up (cbm_render_subscriber_contact_modal()
   in cbm-core, printed in the footer) - subscribers' details are only passed on
   if they complete this form. */
.cbm-supplier-actions__caption--sent { color: var(--cbm-near-black); font-weight: 600; }
.cbm-contact-modal {
	position: fixed; inset: 0; z-index: 100000; display: flex; align-items: center; justify-content: center;
	padding: 16px; background: rgba(0, 0, 0, 0.55);
}
.cbm-contact-modal__box {
	background: #fff; width: 100%; max-width: 460px; max-height: 92vh; overflow-y: auto;
	border-radius: 8px; padding: 28px; display: flex; flex-direction: column; gap: 12px;
}
.cbm-contact-modal__text { margin: 0 0 4px; font-size: 15px; line-height: 1.5; }
.cbm-contact-modal__box label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; font-weight: 600; }
.cbm-contact-modal__box input[type="text"],
.cbm-contact-modal__box input[type="email"],
.cbm-contact-modal__box textarea {
	font: inherit; font-weight: 400; padding: 9px 10px; border: 1px solid var(--cbm-hairline); border-radius: 4px; width: 100%; box-sizing: border-box;
}
.cbm-contact-modal__actions { display: flex; align-items: center; gap: 20px; margin-top: 4px; }
.cbm-contact-modal__cancel { font-size: 14px; color: var(--cbm-muted-grey); }

/* Dealer page sidebar (single-dealer.php's <aside class="cbm-dealer-sidebar">) -
   CONTACT ME/VISIT WEBSITE then the contact card, stacked in the narrow right
   column, exactly like a supplier's Editorial sidebar (directory.css's
   ".cbm-dd-style-editorial .cbm-dd-editorial__sidebar .cbm-supplier-actions" -
   same override, reused here rather than re-derived). Without this the buttons
   keep their full-width-row styling (fit-content, right-aligned, boxed) even
   though they now sit in a column already only as wide as the box wants to be -
   that made the box narrower than the contact card below it, so their left
   edges didn't line up and the column read as messy (Jonathan, 2026-09-28:
   "layout on the right margin is not clean either"). Stretching it to the
   sidebar's full width instead lines both blocks up on both edges. */
/* 20px top padding matches the intro text's own top offset in the left column,
   so both columns start level and the CONTACT ME button clears the search bar
   above it (Jonathan, 2026-09-28: "virtually touching the search bar"). */
.cbm-dealer-sidebar { padding-top: 20px; }
/* Heading over the dealer's stock grid, with a rule under it to separate the
   intro text from the vehicles (2026-09-28, whole-page design review). */
.cbm-dealer-stock-title {
	font-size: 20px;
	margin: 28px 0 0;
	padding-bottom: 10px;
	border-bottom: 1px solid var(--cbm-hairline);
}
.cbm-dealer-sidebar .cbm-supplier-actions {
	width: 100%;
	margin: 0;
	padding: 0;
	align-items: stretch;
	background: none;
	border: none;
	border-radius: 0;
}
.cbm-dealer-sidebar .cbm-supplier-actions__item { max-width: none; align-items: stretch; text-align: left; }
.cbm-dealer-sidebar .cbm-supplier-actions__btn { text-align: center; }
.cbm-dealer-sidebar .cbm-supplier-actions__item form { width: 100%; }
.cbm-dealer-sidebar .cbm-supplier-actions__item form .cbm-supplier-actions__btn { display: block; width: 100%; }

/* Standard sitewide BACK button — header.php, every page except the
   homepage. Deliberately a small, quiet utility (not styled like
   .cbm-back-to-search above, which is a loud red CTA reserved for the
   specific "return to these exact search results" case) — this one is a
   generic "wherever you came from" utility, so it shouldn't visually
   compete with a page's own prominent buttons. Right-aligned to the same
   true right margin as everything else (.cbm-container), sitting just
   under the CBW News ticker's own right-hand "Get CBW" link — per the
   user (2026-08-26): "I want it to be located just under the words GET
   CBW on the news ticker". Styling and size deliberately match the New
   Buses Showroom page's category pills (.cbm-nv-search-switch a, see
   new-vehicles.css) — same rounded-pill shape, border, font and padding —
   per the user, rather than inventing a third link/button style. */
/* align-items: flex-start (was center, 2026-09-26 fix) - centering meant a
   taller title (e.g. a supplier/manufacturer logo slot) pushed the search
   box and Back pill down to stay vertically centred against it, so pages
   with a big logo sat further from the ticker than plain-text-title pages.
   Jonathan: "gap... should be same as all other pages". Top-aligning keeps
   the actions row a fixed distance from the ticker regardless of title
   height. */
.cbm-back-wrap { display: flex; align-items: flex-start; padding-top: 10px; }
.cbm-back-wrap__title {
	flex: 1 1 auto; min-width: 0; margin: 0;
	font-family: var(--cbm-font-body); font-weight: 700; font-size: 20px; text-transform: uppercase;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: left;
}
.cbm-back-wrap__actions { flex: 0 0 auto; display: flex; align-items: center; gap: 12px; margin-left: auto; }
/* --tight: margin-bottom:-50px pulls the page's own top content (a
   breadcrumb) up into the same visual row as this button, since this wrap
   lives in header.php, generically, BEFORE any page-specific markup — per
   the user (2026-08-26): "line it with the breadcrumbs". Approximated
   against the New Buses Showroom page's own breadcrumb spacing.
   Deliberately a SEPARATE modifier class, applied by header.php only on
   the one template that actually has a breadcrumb immediately following
   (page-templates/template-new-vehicles-search.php) — not the base
   .cbm-back-wrap rule. Found live, 2026-08-26: applying it sitewide pulled
   the button up into whatever really comes next on other templates — on
   the Depot/Services directory pages (template-directory.php) that's the
   full-height "Latest Tech" ticker bar, not a thin breadcrumb line, so the
   button ended up visually overlapping it instead of lining up with
   anything. */
.cbm-back-wrap--tight { margin-bottom: -50px; position: relative; z-index: 1; }
.cbm-back-wrap--titled { margin-bottom: 24px; }

/* Sitewide breadcrumb trail (cbm_set_page_breadcrumb() / cbm_render_breadcrumb()),
   rendered by header.php just above the title/back row on any page that sets
   one — added 2026-09-04 to replace several pages' own hand-duplicated
   "Home » X" markup with one shared, styled component. */
.cbm-page-breadcrumb-row { padding-top: 10px; }
/* funnel.css already has its own bare .cbm-breadcrumb rule (padding-block:
   14px 0, font-size: 13px) tuned for that page's own layout - loads AFTER
   this file, so at equal specificity it silently won here too, stacking
   its 14px on top of this row's own 10px padding-top and inflating the
   whole row to 43.5px (found live, 2026-09-04, per Jonathan: "taking a
   complete page width row"). Scoped to .cbm-page-breadcrumb-row
   specifically (higher specificity, wins regardless of file order) rather
   than editing the funnel rule, which still needs its own padding there. */
.cbm-page-breadcrumb-row .cbm-breadcrumb { font-size: 12px; color: var(--cbm-muted-grey); padding: 0; }
.cbm-page-breadcrumb-row .cbm-breadcrumb a { color: var(--cbm-muted-grey); text-decoration: none; }
.cbm-page-breadcrumb-row .cbm-breadcrumb a:hover { color: var(--cbm-red); }
.cbm-page-breadcrumb-row .cbm-breadcrumb__sep { margin: 0 6px; }
/* A breadcrumb row already establishes the top gap under the ticker —
   the title row below it doesn't need its own on top of that. */
.cbm-page-breadcrumb-row + .cbm-back-wrap { padding-top: 4px; }
.cbm-back-btn {
	display: inline-flex; align-items: center; gap: 6px;
	/* Switched from --cbm-font-heading (Space Grotesk) to --cbm-font-body
	   (Inter) 2026-09-17 - Jonathan spotted the bold "B" reading as
	   serif-ish at this 13px size, reproduced in incognito too (ruled out
	   cache/extensions - genuinely how Space Grotesk Bold renders small on
	   his system, not a CSS bug). Inter is a plainer face with no such
	   ambiguity at small sizes. */
	font-family: var(--cbm-font-body); font-weight: 700; font-size: 13px; letter-spacing: 0.03em;
	padding: 7px 16px; border-radius: 999px; border: 1px solid var(--cbm-hairline);
	color: var(--cbm-near-black-alt); text-decoration: none; text-transform: uppercase;
}
.cbm-back-btn:hover { border-color: var(--cbm-red); color: var(--cbm-red); }
.cbm-back-btn__arrow { font-size: 14px; line-height: 1; }

/* Shared page title, used with cbm_render_intro_textwrap() below. */
.cbm-page-title { font-family: var(--cbm-font-body); font-weight: 700; font-size: 28px; margin: 0; text-transform: uppercase; }
.cbm-page-title__subtitle { font-family: var(--cbm-font-heading); font-weight: 700; font-size: 24px; color: #333; letter-spacing: 0.02em; text-transform: none; }

/* Section headers (New/Used/Rental) on the "all conditions for one
   vehicle type" results page — each section keeps its own condition's
   native card design below it rather than mixing card styles together. */
.cbm-vta-section-title {
	font-family: var(--cbm-font-body); font-weight: 700; font-size: 18px; text-transform: uppercase;
	letter-spacing: 0.04em; color: var(--cbm-red); margin: 0 0 14px; padding-top: 8px;
	border-top: 1px solid var(--cbm-hairline);
}

/* Shared "intro text wraps around the sponsor ad" component — New Vehicles,
   Used Vehicles, Rent Vehicles, Depot/Services. See
   inc/template-tags.php's cbm_render_intro_textwrap() for the full
   rationale: one continuous paragraph, one floated *invisible* shape
   element, `shape-outside` to make the paragraph's first two lines render
   full width before the ad's exclusion zone begins. `flow-root` is a
   modern clearfix: without it, the floated child wouldn't contribute to
   this container's height, and the next section would overlap it.

   Two separate elements do the ad's job, not one:
   - .cbm-textwrap__float is float+shape-outside only, invisible — its job
     is purely to tell surrounding text where not to go. shape-outside
     cannot expand past its own element's box (a negative inset(), tried
     first, is silently clamped to 0 rather than expanding it — confirmed
     empirically), so its width has to already include the side gap
     (ad width + --cbm-tw-ad-gap-side), which rules out also using it as
     the *visible* ad box at exactly half-page width.
   - .cbm-textwrap__ad is the real, visible ad, absolutely positioned
     against .cbm-textwrap itself (not nested in .cbm-textwrap__float) so
     its width:50% resolves against the actual page content width, giving
     the exact half-page box size regardless of the float's own width.

   `--cbm-tw-lines: 2` is how many lines render full width above the ad —
   change this one variable, not any pixel value, to reflow more/fewer.
   The gap between the last full-width line and the ad's own top is its own
   variable, `--cbm-tw-ad-gap-top`, not baked into --cbm-tw-lines via a
   "lines+1" or "lines+2" trick — earlier versions tried exactly that
   (twice — first +1, then +2 after +1 was reported as reading like no gap
   at all) and both round-tripped through "looks wrong" feedback before
   settling back on a plain one-line-space value. Keeping it a directly
   readable, directly adjustable value (matching how --cbm-tw-ad-gap-side
   already works below) means the next adjustment is a straightforward
   value change, not a re-derivation of an integer-multiplier theory that's
   already been wrong twice. Confirm any change here against an actual
   screenshot, not just the computed pixel value — this specific gap has a
   track record of measuring out correct while still reading wrong.
   The ad box is `120px` tall (.cbm-tbf-banner's own fixed height) plus
   `12px` of breathing room below it before normal-flow content resumes;
   the side gap (ad to the text beside it) is two line spaces — `3em`, i.e.
   2 × the 1.5em used for the top gap. Expressed in em (not px) like
   everything else here so it's correct at both 14px and 15px call sites
   with no per-page tuning. */
.cbm-textwrap {
	--cbm-tw-lines: 2;
	--cbm-tw-ad-width: 50%;
	--cbm-tw-ad-height: 120px;
	--cbm-tw-ad-gap-top: 1em; /* reads as one line space visually — 1.5em (a full line-height) looked like 1.5 lines, confirmed against a live screenshot */
	--cbm-tw-ad-gap-below: 12px;
	--cbm-tw-ad-gap-side: 3em;
}
/* .cbm-textwrap__ad's percentage width/left need to resolve against the
   true content width — but percentages on an absolutely positioned
   element resolve against its containing block's *padding* box, and
   .cbm-container (the outer element) carries side padding, which silently
   widened and left-shifted the ad box past the real content edge. This
   inner wrapper carries no padding of its own, so it's a clean, exact
   stand-in for the content box as the ad's positioning context. */
.cbm-textwrap__inner { position: relative; display: flow-root; }
.cbm-textwrap__float {
	float: left;
	width: calc( var(--cbm-tw-ad-width) + var(--cbm-tw-ad-gap-side) );
	/* 1.5em, not 1lh — mathematically identical given the sitewide fixed
	   line-height:1.5 (layout.css), but `lh` is a newer unit with real gaps
	   in browser support (only landed in Safari 16.4, for example) where it
	   silently fails rather than erroring, collapsing this whole offset to
	   0 and reproducing the "gap too small" bug this was built to fix —
	   confirmed as the actual cause after this measured correct here but
	   was reported wrong live. em has been universally supported forever. */
	height: calc( ( var(--cbm-tw-lines) * 1.5em ) + var(--cbm-tw-ad-gap-top) + var(--cbm-tw-ad-height) + var(--cbm-tw-ad-gap-below) );
	/* +4px safety buffer on the shape only (2026-09-07), not on the box's
	   own top-offset or this float's total height above -- those still use
	   the bare lines*1.5em so the ad box's position is untouched. Found via
	   a real live bug: the actual rendered top of the first line of text is
	   never quite flush with this float's own box top (a small, consistent
	   leading gap from the font's own metrics, measured ~1-2px on every
	   page using this component, New Vehicles/Used Vehicles/Rent Vehicles
	   alike) -- so N lines of real text are always very slightly taller
	   than N*1.5em exactly. Most instances get away with it by a hair
	   (confirmed on Rent Vehicles: line 2 lands 1.25px past the unbuffered
	   boundary and still renders full-width). New Vehicles' own intro,
	   after gaining a "New" badge on its first line, tipped just past that
	   same hairline margin -- Jonathan: "Badge still stopping second line
	   of text from being full width," confirmed live via exact line-rect
	   measurement, not guessed at. A few px of buffer here is one-directional
	   (only ever gives text MORE room to stay full-width, never less), so it
	   can only fix marginal cases like this one and can't break anything
	   currently rendering correctly elsewhere. */
	shape-outside: inset( calc( ( var(--cbm-tw-lines) * 1.5em ) + 4px ) 0 0 0 );
}
.cbm-textwrap__ad {
	position: absolute;
	top: calc( ( var(--cbm-tw-lines) * 1.5em ) + var(--cbm-tw-ad-gap-top) );
	left: 0;
	width: var(--cbm-tw-ad-width);
}
.cbm-textwrap__ad .cbm-tbf-banner { width: 100%; }
/* Unsold intro banner: same 120px box as a live .cbm-tbf-banner, styled
   like the other empty ad slots (dashed placeholder), so the wrapped text
   never surrounds an invisible hole. */
.cbm-textwrap__ad .cbm-ad-empty-slot,
.cbm-textwrap-simple__ad .cbm-ad-empty-slot { display: flex; height: 120px; background: var(--cbm-fill-light); border: 1px dashed var(--cbm-muted-grey); border-radius: 2px; }
.cbm-textwrap__text { margin: 0; color: var(--cbm-body-grey); }
/* Breathing room around any image that lands inline within the flowing
   text (e.g. a manufacturer's 2nd photo, allowed inline per the up-to-10-
   photos policy) - without this, an inline image can land with zero gap
   against whatever's directly above/below it, including the floated hero
   photo itself if the flow happens to resume right at its bottom edge
   (found live, 2026-09-15). Generic fix, not manufacturer-scoped - any
   future textwrap usage with more than one image needs this too. */
.cbm-textwrap__text .wp-block-image {
	margin: 1.5em 0;
	/* Without this, an inline image appearing before the hero float's
	   bottom edge clears gets squeezed into the narrow column beside it
	   instead of spanning full width below - found live, 2026-09-15
	   ("second image has reduced in size and moved across to range from
	   the right"). clear: left forces it to always drop below the float
	   first, full width, regardless of how much text precedes it. */
	clear: left;
}
.cbm-textwrap--reversed .cbm-textwrap__float { float: right; }
.cbm-textwrap--reversed .cbm-textwrap__ad { left: auto; right: 0; }
@media (max-width: 640px) {
	.cbm-textwrap__float { float: none; width: 100%; height: auto; shape-outside: none; }
	.cbm-textwrap__ad { position: static; width: 100%; margin-bottom: 16px; }
}

/* Plain side-by-side variant of the intro (cbm_render_intro_textwrap()'s
   layout => 'simple') — text in one column, the ad box beside it, no
   wrap/shape-outside. Used on Used Vehicles (2026-09-03); other pages
   using this function keep the default wrap layout above. */
.cbm-textwrap-simple { display: flex; gap: 24px; align-items: flex-start; }
.cbm-textwrap-simple__text { flex: 1 1 0; min-width: 0; margin: 0; color: var(--cbm-body-grey); }
.cbm-textwrap-simple__ad { flex: 1 1 0; min-width: 0; }
@media (max-width: 640px) {
	.cbm-textwrap-simple { flex-direction: column; }
	.cbm-textwrap-simple__ad { flex-basis: auto; width: 100%; }
}
/* Same .cbm-textwrap mechanism, swapped from a fixed-width ad box to a
   photo — same two-element float/shape-outside technique, same variables,
   just overridden to a photo's own box size instead of the ad's 50%/120px.
   Doubled from the original 180x66 per the user (2026-08-26) — "100%
   larger". Unlike the ad box, .cbm-textwrap__ad itself carries no height of
   its own in the base rule (the ad relies on .cbm-tbf-banner's own fixed
   height to size the box); a photo has no such child, so without an
   explicit height here `height:100%` on the <img> below resolves against
   nothing determinate and the browser falls back to the image's natural
   aspect ratio at this width — 120px tall on the original photo, well past
   the float's own calculated height, which is exactly why the image was
   rendering over the page's Buses/Coaches/Minibuses switcher below it
   (reported live, confirmed via getBoundingClientRect: ad box measured
   180x120 against a float box of only 134px total height). */
/* --cbm-tw-ad-gap-below zeroed here (base value is 12px, tuned for the ad
   box's own use) so the float's bottom edge lands exactly at the photo's
   own bottom edge, with nothing padding it out further - the page's
   Buses/Coaches/Minibuses pills nav, first in normal flow after the float,
   then needs zero margin-top of its own too (see .cbm-nv-search-switch in
   new-vehicles.css) to actually sit flush against that edge, per the user
   (2026-08-26): "line up with the bottom of the image". */
.cbm-textwrap--photo { --cbm-tw-ad-width: 360px; --cbm-tw-ad-height: 132px; --cbm-tw-ad-gap-below: 0px; }
.cbm-textwrap--photo .cbm-textwrap__ad { height: var(--cbm-tw-ad-height); }
.cbm-textwrap--photo .cbm-textwrap__ad img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Ticker */
.cbm-ticker-wrap { padding: 14px 16px 4px; }
/* Two stacked ticker bars (e.g. News + Latest Tech) don't actually have any
   gap between them as elements — the visible white space is each bar's own
   padding (this bar's bottom + the next one's top). Halved on both sides
   here for a bar that's immediately followed by another ticker bar, so the
   reduction only affects the gap *between* the pair, not either bar's
   spacing against whatever's above/below the pair as a whole. */
.cbm-ticker-wrap:has(+ .cbm-ticker-wrap) { padding-bottom: 2px; }
.cbm-ticker-wrap + .cbm-ticker-wrap { padding-top: 7px; }
/* No overflow:hidden here (was clipping the "More info" dropdown panel,
   which deliberately renders below this box via top:100% — an ancestor's
   overflow:hidden clips absolutely-positioned descendants even when they're
   positioned outside its own box, not just ones still inside it). The
   scrolling ticker text is already independently clipped by
   .cbm-ticker__track-wrap's own overflow:hidden below, well inside this
   bar's edges, so nothing relies on this element's own clipping. */
.cbm-ticker { background: #1A1A1A; border-radius: 2px; display: flex; align-items: center; }
.cbm-ticker__label {
	flex: 0 0 auto; display: flex; align-items: center; gap: 4px;
	padding: 2.4px 8px 2.4px 16px; border-right: 1px solid rgba(255,255,255,0.15); white-space: nowrap;
}
.cbm-ticker__label span { font-weight: 700; font-size: 13px; color: #fff; }
.cbm-ticker__label img { height: 13px; }
.cbm-ticker__track-wrap { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; padding: 2.4px 0 2.4px 16px; }
.cbm-ticker__track {
	display: inline-block; font-family: var(--cbm-font-mono); font-size: 13px; letter-spacing: 0.04em;
	color: #fff; animation: cbm-ticker-scroll 6.5s linear infinite;
}
.cbm-ticker__item-label { color: var(--cbm-red); font-weight: 700; margin: 0 10px 0 32px; }
@keyframes cbm-ticker-scroll { 0% { transform: translateX(0); } 100% { transform: translateX(-50%); } }
.cbm-ticker__get {
	flex: 0 0 auto; display: flex; align-items: center; justify-content: center; gap: 6px;
	/* Symmetric padding, not the original 16px/8px split - 2026-09-17,
	   Jonathan: "centre 'Get CBW' within its black space" - the uneven
	   padding was quietly pushing the text 8px right of true center. */
	padding: 2.4px 12px; border-left: 1px solid rgba(255,255,255,0.15); white-space: nowrap;
	font-weight: 700; font-size: 13px; color: #fff;
}
.cbm-ticker__get img { height: 13px; }

/*
 * "Get CBW" sparkle - added 2026-09-17, Jonathan: make it more obvious,
 * "a gentle release of warm-coloured stars from within the letters,
 * disappearing as they reach the top margin." Deliberately not a copy of
 * the Awards starburst (.cbm-awards-box__spark below) - that bursts
 * radially outward from one center point; this rises straight up from
 * several points spread across the text width and fades out before it
 * clears the top of this small bar, one at a time rather than all at once.
 */
.cbm-ticker__get--sparkle { position: relative; overflow: visible; }
.cbm-ticker__get-sparkles { position: absolute; inset: 0; pointer-events: none; }
.cbm-ticker__get-spark {
	position: absolute; bottom: 50%; font-size: 8px; line-height: 1;
	color: var(--cbm-gold); opacity: 0; pointer-events: none;
	animation: cbm-ticker-get-rise 3.2s ease-out infinite;
}
@keyframes cbm-ticker-get-rise {
	0%   { opacity: 0; transform: translateY(2px) scale(0.6); }
	20%  { opacity: 1; transform: translateY(-2px) scale(1); }
	100% { opacity: 0; transform: translateY(-14px) scale(0.7); }
}
.cbm-ticker__get-spark--1 { left: 6%;  animation-delay: 0s; }
.cbm-ticker__get-spark--2 { left: 22%; animation-delay: 0.6s; }
.cbm-ticker__get-spark--3 { left: 40%; animation-delay: 1.2s; }
.cbm-ticker__get-spark--4 { left: 56%; animation-delay: 1.8s; }
.cbm-ticker__get-spark--5 { left: 74%; animation-delay: 2.4s; }
.cbm-ticker__get-spark--6 { left: 90%; animation-delay: 3.0s; }
@media (prefers-reduced-motion: reduce) {
	.cbm-ticker__get-spark { animation: none; opacity: 0; }
}

/*
 * Sitewide search folded into the ticker bar, homepage only - added
 * 2026-09-17 per Jonathan's sketch ("always be able to just search what
 * you want immediately" from the MHP, which has no back-row for the
 * usual .cbm-search-box home). .cbm-ticker has no fixed height (flex,
 * align-items:center) and no other child is this tall, so simply adding
 * it here grows the whole bar to match automatically - no separate
 * "increase ticker depth" rule needed, that's a natural flex consequence
 * of this box being the tallest child now.
 */
.cbm-ticker__search {
	flex: 0 0 auto; display: flex; align-items: center;
	/* Reduced from 12px - 2026-09-17, Jonathan: "Get CBW" only looked
	   off-centre because of the black gap here before the red search box
	   started, not any actual asymmetry in "Get CBW" itself (that was
	   fixed separately, see .cbm-ticker__get's own padding). Less black
	   buffer here lets the red box sit closer, removing the extra dark
	   zone that was reading as part of "Get CBW"'s own space. */
	padding: 0 0 0 4px; border-left: 1px solid rgba(255,255,255,0.15);
}
.cbm-ticker__search .cbm-search-box { margin: 4px 4px 4px 0; }
@media (max-width: 640px) { .cbm-ticker__label span { display: none; } }

/* Fade mode (mode:'fade' in cbm_render_ticker_bar()) — items stack directly
   on top of each other (position:absolute inset:0 inside a relative
   container) and cross-fade via opacity, never moving horizontally. Used
   for a ticker bar sitting right under a scrolling one, where two lots of
   sideways motion at once read as too busy. */
/* align-self:stretch (overriding .cbm-ticker's own align-items:center for
   just this item) rather than a hardcoded height — the fade items inside
   are position:absolute so they don't establish this element's own height
   themselves, and without something forcing a real height it collapses to
   near-zero, clipping the text to roughly half its line-height. Stretching
   to the row's real height (set by the label/get siblings, which do have
   normal in-flow content) fixes that without a magic-number height that'd
   drift out of sync if the row's other sizing ever changes. */
.cbm-ticker__track-wrap--fade { position: relative; align-self: stretch; }
.cbm-ticker__fade-item {
	position: absolute; inset: 0; display: flex; align-items: center;
	font-family: var(--cbm-font-mono); font-size: 13px; letter-spacing: 0.04em; color: #fff;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
	animation-timing-function: ease-in-out; animation-iteration-count: infinite;
}
.cbm-ticker__fade-item .cbm-ticker__item-label { margin-left: 0; }
/* Fade mode with a single message: static, wraps rather than clipping (2026-10-19). */
.cbm-ticker__track-wrap--single { white-space: normal; padding-top: 6px; padding-bottom: 6px; }
.cbm-ticker__single-item {
	display: block; font-family: var(--cbm-font-mono); font-size: 13px; letter-spacing: 0.04em; line-height: 1.4; color: #fff;
}
.cbm-ticker__single-item .cbm-ticker__item-label { margin-left: 0; }

/* "More info"-style dropdown (right_dropdown in cbm_render_ticker_bar()) —
   a native <details>/<summary> disclosure, so the menu needs no JS. */
.cbm-ticker__dropdown { position: relative; flex: 0 0 auto; }
.cbm-ticker__dropdown > summary { cursor: pointer; list-style: none; }
.cbm-ticker__dropdown > summary::-webkit-details-marker { display: none; }
/* Explicit display:none/flex toggle rather than relying on <details>'s
   native "hide children when closed" behaviour — that turned out not to
   apply reliably here (computed display stayed "block" even while closed),
   so hiding it outright by default and only showing it under [open] is the
   safe, unambiguous version. */
.cbm-ticker__dropdown-panel {
	display: none; position: absolute; top: 100%; right: 0; z-index: 20; margin-top: 4px;
	background: #fff; border-radius: 2px; box-shadow: 0 6px 18px rgba(0,0,0,0.18);
	flex-direction: column; min-width: 160px; overflow: hidden;
}
.cbm-ticker__dropdown[open] .cbm-ticker__dropdown-panel { display: flex; }
.cbm-ticker__dropdown-panel a {
	padding: 10px 14px; font-size: 13px; font-weight: 600; color: var(--cbm-near-black-alt);
	border-bottom: 1px solid var(--cbm-hairline-light); white-space: nowrap;
}
.cbm-ticker__dropdown-panel a:last-child { border-bottom: none; }
.cbm-ticker__dropdown-panel a:hover { background: var(--cbm-fill-light); }

/* Sponsor + socials */
.cbm-sponsor-wrap { padding: 16px 32px 10px; }
.cbm-sponsor-row { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }

/* Shell + inner split for the same reason as .cbm-topbar__ad above — a
   single ad puts .cbm-tbf-banner-inner's layout directly on the <a>; a
   carousel wraps N absolutely-positioned copies inside the shell. */
.cbm-tbf-banner {
	/* display:block matters beyond flex contexts (where flex items get
	   block-like sizing automatically regardless of their own display) —
	   this is an <a>, inline by default, and height:120px silently does
	   nothing on an inline element outside a flex row (e.g. floated inside
	   .cbm-textwrap__float), collapsing it to its content's intrinsic
	   height instead. */
	display: block; position: relative;
	flex: 1 1 0; min-width: 220px; height: 120px;
	background: linear-gradient(120deg,#0B3D5C 0%,#0e4d73 100%); border-radius: 2px;
	overflow: hidden; text-decoration: none;
}
.cbm-tbf-banner-inner { display: flex; align-items: center; gap: 10px; padding-inline: 14px; height: 100%; }
.cbm-tbf-banner__logo { background: #fff; border-radius: 2px; padding: 6px 8px; flex-shrink: 0; }
/* width:auto is load-bearing — see the matching comment on
   .cbm-topbar__ad-logo img in layout.css for why (srcset/sizes forcing a
   150px width otherwise). */
.cbm-tbf-banner__logo img, .cbm-tbf-banner__logo video { height: 36px; width: auto; }
.cbm-tbf-banner__divider { width: 1px; height: 36px; background: rgba(255,255,255,0.3); flex-shrink: 0; }
.cbm-tbf-banner__copy { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.cbm-tbf-banner__title { font-weight: 700; font-size: 12px; color: #fff; line-height: 1.25; }
.cbm-tbf-banner__sub { font-size: 10px; color: #cfe0ea; margin-top: 1px; }
.cbm-tbf-banner__cta { flex-shrink: 0; background: #fff; color: #0B3D5C; font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: 0.02em; padding: 7px 12px; border-radius: 2px; white-space: nowrap; }

/* 340×117 — matches the source's own 640×220 canvas scaled by 0.53125
   (340 = 640 × 0.53125 exactly; 117 ≈ 220 × 0.53125), not an arbitrary size. */
.cbm-anim-crossfade { flex: 0 0 340px; height: 117px !important; overflow: hidden; border-radius: 2px; position: relative; }
.cbm-anim-crossfade > div { position: absolute; inset: 0; overflow: hidden; }

.cbm-stats-box {
	background: #1A1A1A; display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
	padding: 8px 8px 12px; animation: cbm-crossfade-stats 45.2s ease-in-out infinite;
}
.cbm-stats-box__eyebrow { font-weight: 800; font-size: 24px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--cbm-red); margin-bottom: 5px; }
.cbm-stats-box__row { display: flex; align-items: center; justify-content: space-around; width: 100%; }
.cbm-stats-box__item { text-align: center; }
/* Speed matched to the bus-sale animation: one sequence of that animation
   (4 frames staggered 2.8s apart, last one finishing its fade) takes
   22.6s / 2 = 11.3s, so one gold→silver→gold colour-change cycle here also
   takes 11.3s. 11.3s × 4 = 45.2s divides the master loop exactly, so this
   independent infinite loop always lands on a fresh cycle-start the moment
   the stats box fades in (22.6s and 45.2s/0s into the loop) and completes
   exactly 2 full colour-change cycles before the box fades out again. */
.cbm-stats-box__number { display: block; font-weight: 800; font-size: 26px; color: #E8B84B; animation: cbm-gold-silver 11.3s ease-in-out infinite; }
.cbm-stats-box__label { display: block; font-size: 10px; color: #cfcfcf; text-transform: uppercase; letter-spacing: 0.03em; margin-top: 1px; }
@keyframes cbm-gold-silver { 0%, 100% { color: #E8B84B; } 50% { color: #C9CBCD; } }

/* CBW Awards 2027 page title — reuses the exact same gold glow treatment
   as the homepage's Awards banner (.cbm-awards-box__title / cbm-awards-glow
   below), per the user's request for one consistent "gold logo" across
   both places, rather than this page's earlier separate red/grey
   letter-toggle style. */
/* 50% bigger than the shared .cbm-page-title base (28px × 1.5 = 42px) —
   scoped to this modifier class, not the base rule, so every other page
   using .cbm-page-title (New/Rent Vehicles, etc.) is unaffected. */
.cbm-page-title--sparkle { position: relative; font-size: 42px; white-space: nowrap; }
.cbm-page-title--gold {
	color: #F4D993; font-weight: 800; letter-spacing: 0.02em;
	animation: cbm-awards-glow 2.4s ease-in-out infinite;
}
/* Red-to-black gradient bar (also reused, unchanged, as the homepage
   Awards box's background — see .cbm-awards-box below) with a transparent
   positioning wrapper inside it holding the title — the stars (below) are
   positioned relative to that wrapper (position:relative on
   .cbm-awards-title-box), each point's left/top set inline in the template
   (0–100% = inside the wrapper, <0%/>100% = just outside it), so together
   they read as scattered "in and around" the title rather than only above
   the lettering. */
.cbm-awards-title-bar {
	width: 100%; margin: 0 auto; background: linear-gradient(to bottom, #000 0%, var(--cbm-red) 100%);
	display: flex; justify-content: center; padding: 48px; border-radius: 2px; box-sizing: border-box;
}
.cbm-awards-title-box {
	position: relative; text-align: center; white-space: nowrap; max-width: 100%; overflow: visible;
}
.cbm-awards-title-bar { min-width: 0; }
@media (max-width: 768px) { .cbm-awards-title-bar { width: 90%; } }
/* Half speed (5.2s, double the homepage box's 2.6s) per the user's request —
   only this page's title stars, not the homepage banner's. */
.cbm-page-title__spark {
	position: absolute; font-size: 15px; color: var(--cbm-gold); line-height: 1;
	opacity: 0; pointer-events: none; animation: cbm-awards-spark 5.2s ease-out infinite;
}
/* --tx/--ty, animation-delay and animation-duration are all randomised
   per-star, inline, in the template (page-templates/template-cbw-awards.php)
   — genuinely independent per-star timing (not fixed evenly-spaced values)
   is what makes the shower read as continuous and organic. */
@media (prefers-reduced-motion: reduce) {
	.cbm-page-title__spark { display: none; }
}

/* CBW Awards 2027 voting boxes (template-cbw-awards.php + cbm-core's
   awards-voting.php) — four cards, each a category. "Cast Your Vote"
   reveals the nominee shortlist in place (site.js toggles [hidden] on the
   sibling list); each nominee is its own real submit button, not a select,
   so the whole thing works as plain forms with JS off too. */
.cbm-award-voting { margin-top: 32px; }
.cbm-award-voting__title { font-family: var(--cbm-font-body); font-weight: 700; font-size: 20px; margin: 0 0 8px; }
.cbm-award-voting__intro,
.cbm-award-voting__voting-as { font-size: 14px; color: var(--cbm-body-grey); margin: 0 0 16px; }
.cbm-award-voting__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin-bottom: 16px; }
.cbm-award-voting__attestation { max-width: 560px; border: 1px solid var(--cbm-hairline); border-radius: var(--cbm-radius); padding: 20px; background: #fff; }
.cbm-award-voting__attestation .cbm-checkbox-row { margin: 12px 0 16px; align-items: flex-start; }
.cbm-award-voting__attestation .cbm-award-vote-box__toggle { display: inline-block; width: auto; padding: 10px 20px; }
.cbm-award-vote-box { border: 1px solid var(--cbm-hairline); border-radius: var(--cbm-radius); padding: 16px; display: flex; flex-direction: column; gap: 10px; background: #fff; }
.cbm-award-vote-box__title { font-family: var(--cbm-font-body); font-weight: 700; font-size: 15px; margin: 0; }
.cbm-award-vote-box__sponsor { font-size: 12px; color: var(--cbm-muted-grey); margin: 2px 0 0; }
.cbm-award-vote-box__status { font-size: 13px; color: var(--cbm-body-grey); margin: 0; }
.cbm-award-vote-box__status--voted { color: var(--cbm-green); font-weight: 600; }
.cbm-award-vote-box__toggle {
	background: var(--cbm-red); color: #fff; font-weight: 700; font-size: 13px; text-transform: uppercase;
	letter-spacing: 0.02em; padding: 10px; border: none; border-radius: 2px; cursor: pointer;
}
.cbm-award-vote-box__toggle:hover { background: var(--cbm-red-hover); }
.cbm-award-vote-box__nominees[hidden] { display: none; }
.cbm-award-vote-box__nominees { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.cbm-award-vote-box__nominee-form { margin: 0; }
.cbm-award-vote-box__nominee-btn {
	width: 100%; text-align: left; background: var(--cbm-fill-light); border: 1px solid var(--cbm-hairline);
	border-radius: 2px; padding: 8px 10px; font-size: 13px; cursor: pointer;
}
.cbm-award-vote-box__nominee-btn:hover { background: #fff; border-color: var(--cbm-red); color: var(--cbm-red); }
.cbm-award-voting__thanks { font-size: 14px; font-weight: 600; text-align: center; margin: 8px 0 0; }

/* CBW Awards 2027 page (page-templates/template-cbw-awards.php) — sponsor
   tier boxes, from the user's own sketch: one wider "Main Sponsor" box,
   then a stack of equal-width "Award Sponsor" boxes below it, each with its
   paired award category's title on the right (one each, in list order —
   see the $cbm_awards_sponsors comment in the template for why). */
.cbm-awards-sponsors { margin-top: 32px; }
.cbm-awards-sponsors__title { font-family: var(--cbm-font-body); font-weight: 700; font-size: 18px; margin: 0 0 16px; }
.cbm-awards-sponsors__list { display: flex; flex-direction: column; gap: 12px; }
/* Bars 25% deeper than their original 14px top/bottom padding (14 × 1.25 = 17.5px). */
.cbm-awards-sponsors__item {
	display: flex; align-items: center; justify-content: space-between; gap: 16px;
	border: 1px solid var(--cbm-hairline); border-radius: 4px; padding: 17.5px 18px; background: #fff;
}
.cbm-awards-sponsors__item--main { border-color: var(--cbm-gold, #E8B84B); border-width: 2px; background: #FFFBF0; }
.cbm-awards-sponsors__brand { display: flex; align-items: center; gap: 14px; }
.cbm-awards-sponsors__name { font-family: var(--cbm-font-body); font-weight: 700; font-size: 17px; }
.cbm-awards-sponsors__logo { height: 22px; width: auto; max-width: 140px; object-fit: contain; }
.cbm-awards-sponsors__item--main .cbm-awards-sponsors__logo { height: 28px; max-width: 170px; }
/* Barclays sponsors Operator of the Year — the top individual award — so
   its logo runs noticeably bigger than the other Award Sponsor logos. The
   downloaded SVG's declared width/height didn't match its own viewBox
   (1200×800 declared vs a 6478×1260 viewBox), so the intrinsic aspect
   ratio browsers used for auto-width was wrong and most of any given
   height was empty letterboxing around a thin strip of visible mark —
   fixed at the source (assets/images/sponsor-logos/barclays.svg) rather
   than just cranking the height higher and getting more empty space too. */
.cbm-awards-sponsors__logo--big { height: 56px; max-width: 280px; }
.cbm-awards-sponsors__tier { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--cbm-muted-grey); white-space: nowrap; }
.cbm-awards-sponsors__item--main .cbm-awards-sponsors__tier { color: #A9791C; }
.cbm-awards-sponsors__award {
	font-family: var(--cbm-font-body); font-weight: 600; font-size: 18.75px; color: var(--cbm-near-black-alt);
	text-align: right; white-space: nowrap; flex-shrink: 0;
}

/* CBW Awards banner — another mode for the .cbm-anim-crossfade box
   (front-page.php), replacing the animation/stats cross-fade the same way
   the poll does (see homepage-ad-box.php for the on/off control). Same
   340×117 footprint and dark background as the boxes it replaces. Six
   small star spans sit centered on the title (position:relative on the
   title is what they're absolutely positioned against) and each shoots
   outward to its own --tx/--ty offset and fades, staggered so it reads as
   a continuous twinkle rather than one single burst. */
.cbm-awards-box {
	/* Same gradient as the CBW Awards page's own title bar
	   (.cbm-awards-title-bar) — reused here per the user's request so the
	   two "Awards" surfaces share one consistent look, not just the gold
	   title text. */
	background: linear-gradient(to bottom, #000 0%, var(--cbm-red) 100%);
	display: flex; flex-direction: column; align-items: center; justify-content: center;
	gap: 8px; padding: 10px; text-align: center; height: 100%; box-sizing: border-box; cursor: pointer;
}
/* Full-cover click target — same overlay pattern as .cbm-pillar__link-overlay
   further down this file. Everything the box shows stays inside its real,
   unchanged 117px footprint (no hover-expand/overflow tricks — an earlier
   version used one, and it let visible text render outside this overlay's
   actual clickable bounds, which is exactly the bug this replaced). z-index:1
   puts it above the title/CTA text for click purposes without hiding them
   (it has no background). */
.cbm-awards-box__link-overlay { position: absolute; inset: 0; z-index: 1; text-decoration: none; }
.cbm-awards-box__title {
	position: relative; display: inline-block; margin: 0; font-family: var(--cbm-font-heading); font-weight: 800;
	font-size: 25.5px; letter-spacing: 0.02em; color: #F4D993; text-transform: uppercase; line-height: 1.25;
	animation: cbm-awards-glow 2.4s ease-in-out infinite;
}
@keyframes cbm-awards-glow {
	0%, 100% { text-shadow: 0 0 4px rgba(244,217,147,0.35); }
	50% { text-shadow: 0 0 10px rgba(244,217,147,0.95), 0 0 20px rgba(232,184,75,0.6); }
}
/* Single line, deliberately — this box is a fixed 117px tall
   (.cbm-anim-crossfade) with overflow:hidden, so a taller/wrapped CTA gets
   silently clipped top-and-bottom instead of just looking cramped. An
   earlier version put "OPERATORS" on its own larger line and the content
   overflowed the box by ~12px each way, clipping the title and cutting the
   click target out from under part of the text. */
.cbm-awards-box__cta { margin: 6px 0 0; font-size: 13px; line-height: 1.3; color: #cfcfcf; white-space: nowrap; }
/* Bolder and a size up from the rest of the line, but still inline —
   "OPERATORS" (this is an operator vote specifically, not open to everyone)
   and "VOTE now" both get the same treatment so they read as the two things
   that matter most in that line, not just one. */
.cbm-awards-box__cta-highlight { font-size: 15px; font-weight: 800; letter-spacing: 0.03em; color: #F4D993; }

/* --live: applied only while cbm_awards_voting_state() === 'open' (real
   voting window, cbm-core/includes/awards-voting.php). The "jump"
   scale-pulse to catch the eye while there's actually somewhere to vote
   is scoped to just the "VOTE NOW" span, not the whole box — distinct
   from the constant title glow above which runs regardless. */
.cbm-awards-box--live .cbm-awards-box__cta-highlight--vote { display: inline-block; animation: cbm-awards-jump 1.73s ease-in-out infinite; }
@keyframes cbm-awards-jump {
	0%, 70%, 100% { transform: scale(1); }
	76% { transform: scale(1.11); }
	82% { transform: scale(0.94); }
	88% { transform: scale(1.06); }
	93% { transform: scale(0.97); }
	97% { transform: scale(1.02); }
}
@media (prefers-reduced-motion: reduce) {
	.cbm-awards-box--live .cbm-awards-box__cta-highlight--vote { animation: none; }
}
.cbm-awards-box__spark {
	position: absolute; top: 50%; left: 50%; font-size: 11px; color: #F4D993; line-height: 1;
	opacity: 0; pointer-events: none; animation: cbm-awards-spark 2.6s ease-out infinite;
}
@keyframes cbm-awards-spark {
	0%   { opacity: 0; transform: translate(-50%, -50%) translate(0, 0) scale(0.2) rotate(0deg); }
	10%  { opacity: 1; transform: translate(-50%, -50%) translate(calc(var(--tx) * 0.4), calc(var(--ty) * 0.4)) scale(1) rotate(30deg); }
	40%  { opacity: 0; transform: translate(-50%, -50%) translate(var(--tx), var(--ty)) scale(0.4) rotate(70deg); }
	100% { opacity: 0; transform: translate(-50%, -50%) translate(var(--tx), var(--ty)) scale(0.4) rotate(70deg); }
}
.cbm-awards-box__spark--1  { --tx: -46px; --ty: -30px; animation-delay: 0s; }
.cbm-awards-box__spark--2  { --tx: 42px;  --ty: -34px; animation-delay: 0.45s; }
.cbm-awards-box__spark--3  { --tx: -52px; --ty: -16px; animation-delay: 0.9s; }
.cbm-awards-box__spark--4  { --tx: 50px;  --ty: -12px; animation-delay: 1.35s; }
.cbm-awards-box__spark--5  { --tx: -18px; --ty: -44px; animation-delay: 1.8s; }
.cbm-awards-box__spark--6  { --tx: 20px;  --ty: -46px; animation-delay: 2.25s; }
.cbm-awards-box__spark--7  { --tx: 0px;   --ty: -40px; animation-delay: 0.18s; }
.cbm-awards-box__spark--8  { --tx: -34px; --ty: -32px; animation-delay: 0.61s; }
.cbm-awards-box__spark--9  { --tx: 34px;  --ty: -30px; animation-delay: 1.06s; }
.cbm-awards-box__spark--10 { --tx: -56px; --ty: -6px;  animation-delay: 1.5s; }
.cbm-awards-box__spark--11 { --tx: 56px;  --ty: -4px;  animation-delay: 1.95s; }
.cbm-awards-box__spark--12 { --tx: 2px;   --ty: -50px; animation-delay: 2.4s; }
.cbm-awards-box__spark--13 { --tx: -30px; --ty: -16px; animation-delay: 0.09s; }
.cbm-awards-box__spark--14 { --tx: 30px;  --ty: -18px; animation-delay: 0.33s; }
.cbm-awards-box__spark--15 { --tx: -14px; --ty: -46px; animation-delay: 0.76s; }
.cbm-awards-box__spark--16 { --tx: 16px;  --ty: -48px; animation-delay: 1.2s; }
.cbm-awards-box__spark--17 { --tx: -46px; --ty: -40px; animation-delay: 1.65s; }
.cbm-awards-box__spark--18 { --tx: 46px;  --ty: -38px; animation-delay: 2.08s; }
@media (prefers-reduced-motion: reduce) {
	.cbm-awards-box__title { animation: none; }
	.cbm-awards-box__spark { display: none; }
}

/* CBM Poll — third mode for the .cbm-anim-crossfade box (front-page.php),
   replaces the animation/stats cross-fade entirely while a poll is running
   (cbm_poll_state() !== 'none') rather than joining its rotation, so no
   animation/keyframes are needed here — the box is static either way
   (voting form, or frozen percentage results). Same 340×117 footprint and
   dark background as the boxes it replaces, for a seamless swap. */
.cbm-poll-box {
	background: #1A1A1A; display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
	gap: 2px; padding: 4px 10px 6px; text-align: center;
	/* Some mobile browsers auto-boost font sizes in text blocks for
	   readability, which can blow past a fixed-height box's intended sizing
	   regardless of the font-size actually set here. */
	-webkit-text-size-adjust: 100%; text-size-adjust: 100%;
}
/* MHP2 sandbox topbar variant - see header.php. Same component, sized for
   the topbar's ~90px-tall slot instead of the sponsor row's 340x117 box.
   Box itself ranges right (justify-self:end, matching exactly where
   .cbm-topbar__search used to sit); its title/CTA text is centered on
   their own two lines, not left- or right-aligned.

   Narrowed from 320px to 200px (2026-08-26, per the user) so the
   leaderboard ad (.cbm-topbar__ad) has room to sit at a genuinely fixed
   728px without the two ever needing to negotiate space - this box's
   own width doesn't change in reaction to the ad, and vice versa.
   overflow:hidden added since the animated spark decorations
   (.cbm-awards-box__spark, tuned for the wider 340px standalone box) can
   travel further than this box's own width/height at the extremes of
   their animation; clipping them at the edge reads as fine (they're
   already fading out near their max travel) rather than letting them
   spill visibly outside the box. */
.cbm-awards-box--topbar {
	grid-column: 3; justify-self: end;
	align-items: center; text-align: center;
	width: 200px; max-width: 100%; height: 90px;
	padding: 8px 12px;
	overflow: hidden;
	/* position:relative is load-bearing, not decorative - .cbm-awards-box
	   itself has no position of its own; in its original sponsor-row
	   context, .cbm-anim-crossfade (position:relative) was the box's
	   containing block for its absolutely-positioned __link-overlay
	   (inset:0). This topbar variant sits directly in .cbm-topbar with no
	   such wrapper, so without this, the overlay's inset:0 resolved
	   against .cbm-sticky-header (position:sticky) instead - the nearest
	   actual positioned ancestor - stretching the click target to cover
	   the ENTIRE sticky header, including the logo. That's why clicking
	   the CBM logo was landing on the Awards teaser link instead of home. */
	position: relative;
}
.cbm-awards-box--topbar .cbm-awards-box__title { font-size: 14px; }
.cbm-awards-box--topbar .cbm-awards-box__cta { font-size: 10px; margin-top: 3px; white-space: normal; }
.cbm-awards-box--topbar .cbm-awards-box__cta-highlight { font-size: 11px; }
/* Mobile: layout.css's media query DOES also try to reset this element's
   grid-column/justify-self back to 1/center (alongside the logo/ad/search,
   which it successfully resets) — but since this file (components.css)
   loads after layout.css, THIS file's unconditional desktop rule above
   (grid-column:3; justify-self:end) wins the cascade back regardless of
   layout.css's media query, the same trap the width override below hit.
   Every override for this specific class has to live here to actually
   take effect — repeating the grid-column/justify-self reset, not just
   the width, is what actually makes it stack instead of floating. */
@media (max-width: 1024px) {
	.cbm-awards-box--topbar { grid-column: 1; justify-self: center; width: 100%; height: auto; padding: 10px 16px; }
}

/* Poll and Stats topbar variants - same 200x90 footprint contract as
   .cbm-awards-box--topbar above. Added 2026-09-16 (Jonathan: "the CBM
   stats displaying in the poll box ... there's a problem, they're
   changing the shape of the box") - root cause: these two never got this
   sizing when the topbar mode-branching was restored on 2026-09-15 (see
   project memory "cbm_homepage_poll_reinstated"). Only Awards had a
   pre-existing --topbar rule from before that fix, so Poll and Stats
   rendered completely unconstrained (full natural content width/height
   instead of this fixed box) - the topbar visibly changed shape depending
   on which mode happened to be showing. Typography below is tuned for
   THIS 200x90 box specifically, separate from the larger !important sizes
   above/below tuned for the 340x117 sidebar/crossfade box these same
   classes are also used in on the MHP2 sandbox page.
   The combined .cbm-poll-box--teaser.cbm-poll-box--topbar selector below
   is required, not decorative: .cbm-poll-box--teaser (further down this
   file) sets position:absolute + inset:0 + width/height:100%, sized for
   sitting inside a positioned 340x117 wrapper - without a selector at
   least as specific to override it back to this box's own 200x90/
   position:relative contract, the expanded-poll teaser button would try
   to fill its nearest positioned ancestor (.cbm-sticky-header) instead. */
.cbm-poll-box--topbar,
.cbm-poll-box--teaser.cbm-poll-box--topbar {
	grid-column: 3; justify-self: end;
	width: 200px; max-width: 100%; height: 90px;
	padding: 6px 10px;
	overflow: hidden;
	position: relative;
	gap: 1px;
}
.cbm-poll-box--topbar .cbm-poll-box__eyebrow { font-size: 10px !important; line-height: 1.1 !important; }
.cbm-poll-box--topbar .cbm-poll-box__question {
	font-size: 11px !important; line-height: 1.15 !important;
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.cbm-poll-box--topbar .cbm-poll-box__form label { font-size: 9px !important; }
.cbm-poll-box--topbar .cbm-poll-box__form button { padding: 1px 10px; font-size: 9px; }
.cbm-poll-box--topbar .cbm-poll-box__result { font-size: 9px; }
.cbm-poll-box--topbar .cbm-poll-box__login a { font-size: 9px; }
.cbm-poll-box--topbar .cbm-poll-box__teaser-cta { font-size: 9px; margin-top: 1px; }
@media (max-width: 1024px) {
	.cbm-poll-box--topbar,
	.cbm-poll-box--teaser.cbm-poll-box--topbar { grid-column: 1; justify-self: center; width: 100%; height: auto; padding: 10px 16px; }
}

.cbm-stats-box--topbar {
	grid-column: 3; justify-self: end;
	width: 200px; max-width: 100%; height: 90px;
	padding: 10px 10px 4px;
	overflow: hidden;
	position: relative;
	/* Changed 2026-09-17 (Jonathan): "CBM Monthly Stats" heading moved up
	   towards the top margin rather than vertically centred, so the
	   rotator/stat row(s) below get their own breathing room beneath it. */
	justify-content: flex-start;
	/* The base .cbm-stats-box's crossfade animation is for the sidebar
	   .cbm-anim-crossfade context (cycling this box's opacity against its
	   sibling frames) - meaningless here, where the topbar already
	   decides server-side which one mode to show. Left unset, it would
	   make this box invisible for the first ~22s of every 45.2s cycle. */
	animation: none;
	opacity: 1;
}
.cbm-stats-box--topbar .cbm-stats-box__eyebrow {
	/* +20% (10px -> 12px) and +50% line-space to the row(s) below
	   (margin-bottom 1px -> 1.5px) - 2026-09-17, Jonathan. */
	font-size: 12px; margin-bottom: 1.5px;
}
/* Changed 2026-09-17 (Jonathan, recalling the 09-16 "toggle, don't cram"
   plan - see cbm_stats_carousel_future_idea memory): the 2x2 grid this
   rule used to force (added same day the 4th stat slot was built) crammed
   up to 4 stats into one static grid. Removed that override entirely so
   this inherits the base class's plain flex row - any 3rd/4th stat now
   shows as a second .cbm-stats-box__row that crossfades against the
   first instead of squeezing in alongside it. See .cbm-stats-box__rotator
   below. */
.cbm-stats-box--topbar .cbm-stats-box__number { font-size: 13px; line-height: 1.1; }
.cbm-stats-box--topbar .cbm-stats-box__label { font-size: 7.5px; line-height: 1.1; margin-top: 0; }
/* Holds the stat row(s) below the eyebrow. With only the two base stats
   this is just a plain flex container (.cbm-stats-box__row renders
   exactly as it always did); once a 3rd/4th stat is filled in,
   .cbm-stats-box--rotating makes it position:relative so the two rows
   can crossfade in the same space rather than both showing at once. */
.cbm-stats-box__rotator { flex: 1; width: 100%; display: flex; align-items: center; justify-content: center; }
.cbm-stats-box--rotating .cbm-stats-box__rotator { position: relative; }
.cbm-stats-box--rotating .cbm-stats-box__row {
	position: absolute; inset: 0;
	animation: cbm-stats-row-crossfade 12s ease-in-out infinite;
}
.cbm-stats-box--rotating .cbm-stats-box__row:nth-of-type(2) { animation-delay: -6s; }
@keyframes cbm-stats-row-crossfade {
	0%, 42% { opacity: 1; }
	50%, 92% { opacity: 0; }
	100% { opacity: 1; }
}
@media (max-width: 1024px) {
	.cbm-stats-box--topbar { grid-column: 1; justify-self: center; width: 100%; height: auto; padding: 10px 16px; }
	/* Auto height here means the rows can't crossfade-overlap (nothing to
	   overlap against) - just stack both rows normally instead of hiding
	   the second one. */
	.cbm-stats-box--rotating .cbm-stats-box__row { position: static; animation: none; opacity: 1; }
	.cbm-stats-box--rotating .cbm-stats-box__rotator { display: block; }
}

/* !important on the sizes here: this box has a hard 117px ceiling (it must
   swap seamlessly with the fixed-size animation/stats states), so nothing
   is allowed to silently override these regardless of cascade order. */
.cbm-poll-box__eyebrow { font-weight: 800; font-size: 20px !important; line-height: 1.1 !important; letter-spacing: 0.05em; text-transform: uppercase; color: var(--cbm-red); }
.cbm-poll-box__question { font-size: 15px !important; font-weight: 600; color: #fff; line-height: 1.1 !important; }
.cbm-poll-box__form { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; width: 100%; }
.cbm-poll-box__form label { display: flex; align-items: center; gap: 5px; font-size: 14px !important; line-height: 1.1 !important; color: #E8E8E8; cursor: pointer; }
.cbm-poll-box__form input[type="radio"] { width: 11px; height: 11px; margin: 0; cursor: pointer; flex-shrink: 0; }
.cbm-poll-box__form button {
	align-self: center; margin-top: 0; background: var(--cbm-red); color: #fff; border: none; border-radius: 2px;
	font-weight: 700; font-size: 10px; line-height: 1; letter-spacing: 0.03em; text-transform: uppercase; padding: 2px 16px; cursor: pointer;
}
.cbm-poll-box__result { display: flex; justify-content: space-between; width: 100%; font-size: 14px; line-height: 1.15; color: #E8E8E8; }
.cbm-poll-box__result span:last-child { font-weight: 700; color: #E8B84B; }
.cbm-poll-box__login a { font-size: 14px; color: #E8B84B; font-weight: 600; }

/* Expanded-layout poll: a clickable teaser (same 340×117 footprint, styled
   as a <button> so it needs a full reset) that opens the full poll in an
   overlay panel above the page. See assets/js/site.js for the open/close
   click handling. */
/* .cbm-anim-crossfade > div is what normally pins/clips a mode to the
   340×117 box (see below) — doesn't match this <button>, so it needs the
   same position/inset/overflow explicitly, or a long question just grows
   the box instead of being clipped. */
.cbm-poll-box--teaser {
	position: absolute; top: 0; right: 0; bottom: 0; left: 0; overflow: hidden;
	border: none; font: inherit; width: 100%; height: 100%; cursor: pointer;
}
.cbm-poll-box--teaser .cbm-poll-box__question {
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.cbm-poll-box__teaser-cta { font-size: 12px; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase; color: #E8B84B; margin-top: 2px; }

/* !important on position/inset here: .cbm-anim-crossfade > div (written
   earlier for the animation/stats swap) has HIGHER specificity than this
   class-only selector and also matches this element (a direct-child div of
   .cbm-anim-crossfade), silently downgrading it from fixed to absolute and
   confining a full-screen overlay to the tiny 117px box instead. */
.cbm-poll-overlay {
	position: fixed !important; top: 0 !important; right: 0 !important; bottom: 0 !important; left: 0 !important;
	z-index: 200; display: flex; align-items: center; justify-content: center;
}
.cbm-poll-overlay[hidden] { display: none; }
.cbm-poll-overlay__backdrop { position: absolute; top: 0; right: 0; bottom: 0; left: 0; background: rgba(0,0,0,0.6); }
.cbm-poll-overlay__panel {
	position: relative; background: #1A1A1A; border-radius: 4px; padding: 32px 28px; width: 100%; max-width: 440px;
	margin: 16px; text-align: center; box-shadow: 0 20px 60px rgba(0,0,0,0.4);
}
.cbm-poll-overlay__close {
	position: absolute; top: 8px; right: 12px; background: none; border: none; color: #B0B2B5; font-size: 26px;
	line-height: 1; cursor: pointer; padding: 4px;
}
.cbm-poll-overlay__close:hover { color: #fff; }
/* Roomier sizing than the compact box — no 117px ceiling to fit inside here. */
.cbm-poll-overlay__panel .cbm-poll-box__eyebrow { font-size: 26px; }
.cbm-poll-overlay__panel .cbm-poll-box__question { font-size: 22px; line-height: 1.35; margin: 14px 0 20px; }
.cbm-poll-overlay__panel .cbm-poll-box__form { gap: 12px; align-items: stretch; }
.cbm-poll-overlay__panel .cbm-poll-box__form label { font-size: 17px; padding: 10px 14px; border: 1px solid #3a3a3a; border-radius: 2px; }
.cbm-poll-overlay__panel .cbm-poll-box__form input[type="radio"] { width: 16px; height: 16px; }
.cbm-poll-overlay__panel .cbm-poll-box__form button { font-size: 14px; padding: 12px 32px; margin-top: 8px; }
.cbm-poll-overlay__panel .cbm-poll-box__result { font-size: 18px; padding: 8px 0; }
.cbm-poll-overlay__panel .cbm-poll-box__login a { font-size: 17px; }

/* Bus-sale scene — 4 frames from Design (assets/images/bus-sale-frames/, see
   front-page.php's comment for the full rationale, including why frame 2 is
   a flat "CBM MAGIC!!" card rather than a photographic render), crossfading
   against CBM Statistics. Per-frame timing is user-specified: 1s fade-in,
   1s hold, 1s fade-out (linear), with the next frame starting the instant
   the current one's fade-out reaches 20% (0.8s into it) — a 2.8s stagger
   between frame starts. 4 frames play, then repeat once more (8 starts,
   still 2.8s apart, no reset at the repeat), ending at 22.6s. Stats then
   takes over for an equal 22.6s — a master 45.2s loop. */
.cbm-magic-box {
	background: #1A1A1A;
	animation: cbm-crossfade-magic 45.2s ease-in-out infinite;
}
.cbm-magic-frames { position: relative; width: 100%; height: 100%; overflow: hidden; }
/* Design's first export padded the real ~640×220 artwork into a 924×540
   canvas with transparent margin, which needed a scale-then-clip hack to
   crop out (see git history if you need it). The current export is
   natively 640×220 — almost exactly the box's own 340:117 aspect ratio —
   so a plain cover fit is all that's needed now. */
.cbm-magic-frame {
	position: absolute; inset: 0;
	width: 100%; height: 100%;
	object-fit: cover;
	opacity: 0;
	animation-duration: 45.2s;
	/* Linear, not ease — the 2.8s stagger is derived assuming a straight-line
	   fade, so an eased curve would shift the real "current frame at 20%"
	   crossing point away from the timestamp the math below assumes. */
	animation-timing-function: linear;
	animation-iteration-count: infinite;
}
.cbm-magic-frame--1 { animation-name: cbm-frame-for-sale; }
.cbm-magic-frame--2 { animation-name: cbm-frame-cbm-magic; }
.cbm-magic-frame--3 { animation-name: cbm-frame-sold; }
.cbm-magic-frame--4 { animation-name: cbm-frame-pound-sign; }

/* Box-level crossfade between the whole magic-box and the whole stats-box,
   at the halfway point of the 45.2s master loop (22.6s in). This is a
   separate, smaller cosmetic blend (~0.5s each side) from the per-frame
   crossfades below — it just softens the handover between the two boxes. */
@keyframes cbm-crossfade-magic { 0%, 48.8938% { opacity: 1; } 51.1062%, 100% { opacity: 0; } }
@keyframes cbm-crossfade-stats { 0%, 48.8938% { opacity: 0; } 51.1062%, 100% { opacity: 1; } }

/* Per-frame timing, precisely per the user's spec: each frame's own arc is
   0%→100% opacity over 1s, hold at 100% for 1s, then 100%→0% over 1s
   (linear). The next frame starts fading in the moment the current frame's
   fade-out reaches 20% — 0.8s into that 1s fade-out, i.e. 2.8s after the
   current frame's own start (1s in + 1s hold + 0.8s). That 2.8s stagger
   applies uniformly across all 8 frame-starts (4 frames × 2 plays, no
   reset at the repeat boundary): starts at 0, 2.8, 5.6, 8.4, 11.2, 14.0,
   16.8, 19.6s. The last frame's fade-out completes at 19.6 + 3 = 22.6s,
   which is exactly the animation/stats 50% split point of the 45.2s master
   cycle — all percentages below are each timestamp ÷ 45.2 × 100. */
@keyframes cbm-frame-for-sale {
	0%              { opacity: 0; }
	2.2124%         { opacity: 1; }
	4.4248%         { opacity: 1; }
	6.6372%         { opacity: 0; }
	24.7788%        { opacity: 0; }
	26.9912%        { opacity: 1; }
	29.2035%        { opacity: 1; }
	31.4159%        { opacity: 0; }
	100%            { opacity: 0; }
}
@keyframes cbm-frame-cbm-magic {
	0%, 6.1947%     { opacity: 0; }
	8.4071%         { opacity: 1; }
	10.6195%        { opacity: 1; }
	12.8319%        { opacity: 0; }
	30.9735%        { opacity: 0; }
	33.1858%        { opacity: 1; }
	35.3982%        { opacity: 1; }
	37.6106%, 100%  { opacity: 0; }
}
@keyframes cbm-frame-sold {
	0%, 12.3894%    { opacity: 0; }
	14.6018%        { opacity: 1; }
	16.8142%        { opacity: 1; }
	19.0265%        { opacity: 0; }
	37.1681%        { opacity: 0; }
	39.3805%        { opacity: 1; }
	41.5929%        { opacity: 1; }
	43.8053%, 100%  { opacity: 0; }
}
@keyframes cbm-frame-pound-sign {
	0%, 18.5841%    { opacity: 0; }
	20.7965%        { opacity: 1; }
	23.0088%        { opacity: 1; }
	25.2212%        { opacity: 0; }
	43.3628%        { opacity: 0; }
	45.5752%        { opacity: 1; }
	47.7876%        { opacity: 1; }
	50%, 100%       { opacity: 0; }
}

.cbm-social-follow { display: flex; flex-direction: column; align-items: flex-end; justify-content: space-between; height: 120px; flex-shrink: 0; margin-left: auto; }
.cbm-social-follow a { font-size: 11px; font-weight: 700; padding: 6px 14px; border: 1px solid var(--cbm-hairline); border-radius: 4px; color: #222; background: #fff; white-space: nowrap; }
@media (max-width: 1024px) {
	.cbm-sponsor-row { flex-direction: column; align-items: stretch; }
	/* .cbm-anim-crossfade's `flex: 0 0 340px` sets its WIDTH in the desktop
	   row layout, but flex-direction:column above flips the main axis, so
	   that same 340px silently becomes its HEIGHT instead — overriding the
	   explicit height:117px and making the box (and everything inside it,
	   including the poll) 340px tall and full-width instead of the intended
	   slim banner. Pin both explicitly here so the column layout can't
	   reinterpret the flex-basis. */
	.cbm-anim-crossfade { flex: none; width: 100%; height: 117px; }
	.cbm-stats-box { flex: none; width: 100%; }
	.cbm-social-follow { flex-direction: row; flex-wrap: wrap; height: auto; align-items: flex-start; margin-left: 0; gap: 8px; }
}

/* Pillars */
.cbm-pillars-wrap { padding: 6px 16px 24px; }
.cbm-pillars__heading {
	text-align: center; margin: 0 0 6px;
	font-family: var(--cbm-font-body); font-weight: 700; font-size: clamp(28px, 4vw, 46.5px);
	color: #333; text-transform: uppercase;
}
.cbm-hub-word { animation: cbm-hub-pulse 6s ease-in-out infinite; }
@keyframes cbm-hub-pulse { 0%, 100% { color: #333; } 50% { color: var(--cbm-red); } }

.cbm-pillars__grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 18px; }
@media (max-width: 1024px) { .cbm-pillars__grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 640px) { .cbm-pillars__grid { grid-template-columns: repeat(2, 1fr); } }

/* .cbm-pillar is a <div>, not an <a> — its own "go to this pillar's page"
   link is .cbm-pillar__link-overlay, a full-cover invisible link BEHIND
   the ad slot (see z-index below). It can't be the outer element itself:
   the ad slot's real per-ad <a> tags need to sit inside it, and a nested
   <a> inside another <a> is invalid HTML — browsers silently auto-close
   the outer one and relocate everything after it up the tree, which is
   exactly the bug this structure exists to avoid. */
.cbm-pillar {
	border: 1px solid var(--cbm-hairline); border-radius: 2px; background: #fff; overflow: hidden;
	display: flex; flex-direction: column; color: inherit; position: relative;
	transition: box-shadow 0.15s, border-color 0.15s;
}
.cbm-pillar:hover { box-shadow: 0 4px 14px rgba(0,0,0,0.12); border-color: var(--cbm-muted-grey); }
.cbm-pillar__link-overlay { position: absolute; inset: 0; z-index: 1; text-decoration: none; }
.cbm-pillar__media { aspect-ratio: 4/3; overflow: hidden; position: relative; display: block; transition: filter 0.15s; }
.cbm-pillar:hover .cbm-pillar__media { filter: brightness(0.85); }
.cbm-pillar__media img { width: 100%; height: 100%; object-fit: cover; }
.cbm-pillar__media--icon { background: #1c2622; display: flex; align-items: center; justify-content: center; }
.cbm-pillar__icon { width: 55%; height: 55%; }
.cbm-pillar__pound { font-family: var(--cbm-font-heading); font-weight: 700; font-size: 48px; color: #E8B84B; line-height: 1; margin-bottom: 12px; }
/* A dedicated title bar below the image, not an overlay on top of it — the
   pillars are the whole site's main navigation, so the label needs to read
   clearly at a glance rather than compete with the photo underneath it.
   Two-word labels ("NEW VEHICLES" etc.) break onto their own two lines via
   an explicit <br> in the markup rather than relying on word-wrap, so it's
   always exactly "NEW" over "VEHICLES", never wrapping at the wrong point
   at a different viewport width. min-height keeps single-word labels
   (DEPOT, SERVICES) the same depth as the two-line ones, so the row of 5
   stays visually even. */
.cbm-pillar__label {
	display: flex; flex-direction: column; align-items: center; justify-content: center;
	min-height: 76px; padding: 8px 6px;
	background: var(--cbm-red); color: #fff; font-family: var(--cbm-font-heading); font-weight: 700;
	font-size: 26px; line-height: 1.15; letter-spacing: 0.03em; text-align: center;
	transition: background 0.15s;
}
.cbm-pillar:hover .cbm-pillar__label { background: var(--cbm-red-hover); }
@media (max-width: 640px) { .cbm-pillar__label { font-size: 20px; min-height: 62px; } }

.cbm-pillar__body { padding: 16px; text-align: center; flex: 1; display: flex; flex-direction: column; }
.cbm-pillar__desc { font-size: 14px; color: var(--cbm-body-grey); margin-top: 2px; }
.cbm-pillar__desc--grow { margin-top: 4px; flex: 1; }
.cbm-pillar__adslot {
	aspect-ratio: 300/250; margin-top: 6px; background: var(--cbm-fill-light);
	border: 1px dashed var(--cbm-muted-grey); border-radius: 2px; position: relative; z-index: 2; overflow: hidden; display: block;
}

/* Ad Space Manager (wp-content/plugins/cbm-core/includes/ad-rendering.php):
   a space with one ad renders it directly filling the shell above. Several
   ads scroll continuously right-to-left, the same mechanism as the
   homepage's CBW news ticker (.cbm-ticker__track) — .cbm-ad-carousel-track
   is twice as wide as it needs to be (the ad list rendered twice back to
   back) and animates from translateX(0) to translateX(-50%), so it wraps
   to a visually identical position with no jump. Scoped to these two
   specific parents because the leaderboard ad spaces (topbar/TBF banner)
   instead give .cbm-ad-carousel their own shell class directly — see
   cbm_render_ad_carousel()'s $shell_classes — which already provides its
   own sizing, so this generic 100%-fill rule would be wrong there. */
.cbm-pillar__adslot > .cbm-ad-carousel,
.cbm-sponsor-card > .cbm-ad-carousel { display: block; width: 100%; height: 100%; }
.cbm-ad-carousel__track {
	display: flex; height: 100%;
	animation-name: cbm-ad-scroll; animation-timing-function: linear; animation-iteration-count: infinite;
}
.cbm-ad-carousel__item { flex-shrink: 0; height: 100%; }
@keyframes cbm-ad-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }

.cbm-ad-image-link { display: block; width: 100%; height: 100%; }
.cbm-ad-image-link img, .cbm-ad-image-link video { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Cross-fade ad (cbm_render_ad_fade() in ad-rendering.php): the first image
   sizes the box, the rest sit on top of it. The incoming image fades in over
   the outgoing one, which stays fully visible until the fade ends. */
.cbm-ad-fade { position: relative; overflow: hidden; }
.cbm-ad-fade img { position: relative; opacity: 0; transition: none; }
.cbm-ad-fade img + img { position: absolute; inset: 0; }
.cbm-ad-fade img.is-prev { opacity: 1; z-index: 1; }
.cbm-ad-fade img.is-active { opacity: 1; z-index: 2; transition: opacity var(--cbm-ad-fade, 3s) ease-in-out; }

.cbm-ad-empty-slot {
	display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;
	font-family: var(--cbm-font-mono); font-size: 9px; letter-spacing: 0.05em; text-transform: uppercase;
	color: var(--cbm-body-grey); text-align: center; padding: 6px;
}

/* Vehicle test videos */
.cbm-video-tests-wrap { padding: 0 32px 32px; }
.cbm-video-tests { display: flex; gap: var(--cbm-gap); }
.cbm-video-test { flex: 1 1 0; min-width: 0; }
.cbm-video-test__label {
	font-family: var(--cbm-font-body); font-weight: 700; font-size: 15px; letter-spacing: 0.04em;
	margin: 0 0 8px;
}
.cbm-video-test__player { aspect-ratio: 16/9; border-radius: 2px; overflow: hidden; background: #000; }
.cbm-video-test__player iframe { width: 100%; height: 100%; border: 0; display: block; }
.cbm-video-test__full-link {
	display: inline-block; margin-top: 8px; font-size: 13px; font-weight: 700; color: var(--cbm-red);
}
.cbm-video-test__placeholder {
	aspect-ratio: 16/9; display: flex; align-items: center; justify-content: center;
	background: var(--cbm-fill-light); border: 1px dashed var(--cbm-muted-grey); border-radius: 2px;
	font-family: var(--cbm-font-mono); font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase;
	color: var(--cbm-body-grey);
}
/* MPU (300×250) slot between the two video boxes — fixed width, not
   flex:1 like the videos, so it holds its own size and the two videos
   shrink to share whatever width is left either side of it. */
.cbm-mhp2-mpu-placeholder {
	/* flex: 0 0 300px was wrong here — this sits in a column-direction flex
	   parent (.cbm-mhp2-col-mpu-video), so a flex-basis of 300px sets its
	   HEIGHT (the main axis in a column), silently overriding height: 250px
	   right below it. Rendered 300x300 instead of the true 300x250 MPU spec
	   (Jonathan, 2026-09-02: "too big"). flex: 0 0 auto lets the explicit
	   width/height rule actually apply. */
	flex: 0 0 auto; width: 300px; height: 250px; box-sizing: border-box;
	display: flex; align-items: center; justify-content: center; text-align: center;
	background: var(--cbm-fill-light); border: 1px dashed var(--cbm-muted-grey); border-radius: 2px;
	font-family: var(--cbm-font-mono); font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase;
	color: var(--cbm-body-grey); line-height: 1.6;
}
@media (max-width: 640px) {
	.cbm-video-tests { flex-direction: column; }
	.cbm-mhp2-mpu-placeholder { width: 100%; max-width: 300px; margin: 0 auto; }
}

/* Shop banner */
.cbm-shop-wrap { margin: 0 auto 48px; padding-inline: 16px; }
.cbm-shop-banner {
	display: flex; align-items: center; justify-content: space-between; gap: 24px;
	background: #1A1A1A; border-radius: 2px; padding: 24px 32px; color: #fff; transition: background 0.15s;
}
.cbm-shop-banner:hover { background: #242424; }
.cbm-shop-banner__left { display: flex; align-items: center; gap: 20px; }
.cbm-shop-banner__icons { display: flex; gap: 10px; flex-shrink: 0; }
.cbm-shop-banner__icon { width: 96px; height: 96px; border-radius: 4px; background: #2b2b2b; border: 1px solid #3a3a3a; display: flex; align-items: center; justify-content: center; padding: 15px; }
@media (max-width: 640px) {
	.cbm-shop-banner__icon { width: 76px; height: 76px; padding: 11px; }
}
.cbm-shop-banner__icon svg { width: 100%; height: 100%; }
.cbm-shop-banner__icon img { width: 100%; height: 100%; object-fit: contain; display: block; }
.cbm-shop-banner__eyebrow { font-size: 28px; letter-spacing: 0.02em; text-transform: uppercase; color: var(--cbm-red); font-weight: 700; }
.cbm-shop-banner__title { font-weight: 700; font-size: 20px; margin-top: 2px; }
.cbm-shop-banner__sub { font-size: 13px; color: #c9c9c9; margin-top: 2px; }
.cbm-shop-banner__cta { background: var(--cbm-red); color: #fff; font-weight: 700; font-size: 13px; letter-spacing: 0.02em; text-transform: uppercase; padding: 13px 24px; border-radius: 4px; white-space: nowrap; }
@media (max-width: 640px) {
	.cbm-shop-banner { flex-direction: column; align-items: stretch; text-align: center; }
	.cbm-shop-banner__left { flex-direction: column; }
}

/* Blurb */
.cbm-blurb-wrap { max-width: 900px; margin: 0 auto; padding: 32px; font-size: 12px; color: var(--cbm-body-grey); text-align: center; }

/* Advertise — Ad Specs page (page-templates/template-advertise-specs.php).
   A plain, print/link-friendly reference table — deliberately no visual
   flourish since its whole job is to be legible when forwarded to a
   client, not to sell the site. */
.cbm-page__intro { font-size: 15px; color: var(--cbm-body-grey); max-width: 720px; margin: 12px 0 24px; line-height: 1.5; }
.cbm-ad-specs-table { width: 100%; border-collapse: collapse; margin-top: 8px; }
.cbm-ad-specs-table th {
	text-align: left; font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em;
	color: var(--cbm-muted-grey); padding: 10px 12px; border-bottom: 2px solid var(--cbm-near-black, #1A1A1A);
}
.cbm-ad-specs-table td { padding: 12px; border-bottom: 1px solid var(--cbm-hairline); font-size: 14px; vertical-align: top; }
.cbm-ad-specs-table td:nth-child(2) { white-space: nowrap; font-weight: 600; }
.cbm-ad-specs-table td:nth-child(3) { color: var(--cbm-body-grey); font-size: 13px; }
@media (max-width: 640px) {
	.cbm-ad-specs-table, .cbm-ad-specs-table tbody, .cbm-ad-specs-table tr, .cbm-ad-specs-table td { display: block; width: 100%; }
	.cbm-ad-specs-table thead { display: none; }
	.cbm-ad-specs-table tr { border-bottom: 1px solid var(--cbm-hairline); padding: 12px 0; }
	.cbm-ad-specs-table td { border: none; padding: 2px 0; }
	.cbm-ad-specs-table td:first-child { font-weight: 700; }
}

/* MHP2 Homepage Sandbox — see page-templates/template-mhp2-sandbox.php.
   Layout only for this pass: no real nav targets yet. Two independent
   columns, not a locked grid — FIND VEHICLES and FIND EVERYTHING ELSE each
   stay their own natural (short) height in the left column, while the
   billboard (portrait, 300×600) and Latest Used Vehicles run down the
   right column at their own pace underneath it, with no need for either
   column's boxes to line up row-by-row with the other's. */
.cbm-mhp2-wrap { padding: 6px 16px 24px; display: flex; gap: 20px; align-items: flex-start; }
.cbm-mhp2-col-left { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 20px; }
.cbm-mhp2-col-right { flex: 0 0 160px; min-width: 0; display: flex; flex-direction: column; gap: 20px; }

/* Each panel splits into a content side (title/choices/search) and an
   image side. The image now grows with the panel's own width (flex:2 vs
   the content's flex:3, roughly a 60/40 split) rather than staying a fixed
   180px, since narrowing the billboard column (portrait, not landscape)
   freed up extra width here that the image should take advantage of. */
.cbm-mhp2-panel {
	border-radius: var(--cbm-radius); background: #fff;
	overflow: hidden; display: flex; align-items: stretch; gap: 20px;
}

/* SELL VEHICLES — text-only panel, no image column (unlike the panels
   above it) — now uses the same fade-preview background-photo pattern as
   FIND VEHICLES/FIND EVERYTHING ELSE/FIND ALL OPERATORS once a real photo
   was supplied, for visual consistency across the column. */
.cbm-mhp2-sell-panel__text { margin: 0; font-size: 15px; color: var(--cbm-body-grey); line-height: 1.5; }
.cbm-mhp2-sell-panel__cta { display: inline-block; width: auto; align-self: flex-start; padding: 10px 20px; font-size: 16px; margin-top: 4px; }
.cbm-mhp2-panel__content { flex: 3 1 0; min-width: 0; padding: 24px; display: flex; flex-direction: column; gap: 16px; }
/* Trims the panel's own top/bottom padding to pull the title up toward
   the top edge and the bottom edge up toward the content above it, since
   panel height here is driven entirely by content height (the fade-bg
   photo is an absolutely positioned background, not a normal-flow
   sibling setting the height). FIND EVERYTHING ELSE matches FIND
   VEHICLES' padding so the two panels' top/bottom margins read the same. */
.cbm-mhp2-panel--vehicles .cbm-mhp2-panel__content,
.cbm-mhp2-panel--else .cbm-mhp2-panel__content,
.cbm-mhp2-panel--operators .cbm-mhp2-panel__content,
.cbm-mhp2-panel--sell .cbm-mhp2-panel__content { padding-top: 12px; padding-bottom: 14px; }
.cbm-mhp2-panel__image { flex: 2 1 0; min-width: 140px; align-self: stretch; }
.cbm-mhp2-panel__image img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* PREVIEW ONLY — see the file header comment in template-mhp2-sandbox.php.
   Whole photo visible (object-fit:contain, not cover), anchored right,
   sitting as a full-panel background behind the content rather than in
   its own cropped column. A mask fades it to transparent moving left, so
   it's fully visible on the right and faded out by the time it reaches
   under the New/Used/Rental buttons — those buttons' own backgrounds
   (solid red/grey) mean the fade doesn't need to fully vanish before
   reaching them, just enough that it reads as "behind" them, not
   competing for attention with the actual controls. */
.cbm-mhp2-panel--fade-preview { position: relative; }
.cbm-mhp2-panel__fade-bg {
	position: absolute; inset: 0; width: 100%; height: 100%;
	object-fit: contain; object-position: right center;
	/* Fully opaque for the last 100px before the right edge (two "black"
	   stops, not one) — the fade transitions entirely to the left of that,
	   so it never actually touches the panel's right border. */
	-webkit-mask-image: linear-gradient(to right, transparent 0%, transparent 45%, black calc(100% - 100px), black 100%);
	mask-image: linear-gradient(to right, transparent 0%, transparent 45%, black calc(100% - 100px), black 100%);
	z-index: 0;
}
/* Content keeps its EXACT original width — replicating the same formula
   the normal panel's flex:3-vs-image's-flex:2 split produced, (available
   width) × 3/5, as an explicit flex-basis. max-width alone (tried first)
   didn't work: with flex-grow:0 and no sibling competing for space, the
   content just shrank to its own natural/intrinsic size instead of being
   pulled up to fill that cap — flex-basis forces the width directly,
   regardless of content size, matching the original buttons' size and
   position exactly rather than approximately. */
.cbm-mhp2-panel--fade-preview .cbm-mhp2-panel__content { position: relative; z-index: 1; background: transparent; flex: 0 0 calc((100% - 20px) * 3 / 5); }
/* FIND EVERYTHING ELSE's content column needs a bit more horizontal room
   than FIND VEHICLES' — its title is the longest of the three ("FIND
   EVERYTHING ELSE" vs "FIND VEHICLES") and was wrapping onto two lines at
   the shared 40px size. Widening this one panel's content share (at the
   fade photo's expense) fixes it without adding any vertical depth or
   shrinking the title below the other two sections' size. */
.cbm-mhp2-panel--else.cbm-mhp2-panel--fade-preview .cbm-mhp2-panel__content { flex-basis: calc((100% - 20px) * 0.72); }
.cbm-mhp2-panel__title {
	font-family: var(--cbm-font-heading); font-weight: 800; font-size: 40px;
	letter-spacing: 0.03em; color: var(--cbm-near-black); white-space: nowrap;
}
@media (max-width: 640px) {
	.cbm-mhp2-panel { flex-direction: column; }
	.cbm-mhp2-panel__image { flex-basis: 140px; }
}

/* FIND VEHICLES and SELL VEHICLES side by side, per Jonathan's sketch —
   two separate .cbm-mhp2-panel boxes sharing one flex row, each keeping
   its own normal box styling rather than being merged into one shared
   panel. */
.cbm-mhp2-row-find-sell { display: flex; gap: 20px; align-items: stretch; }
/* Explicit calc()-based width, not flex:1 1 0 — despite identical flex
   values and min-width:0 on both, they were rendering 48px apart
   (measured: 414.5px vs 462.5px) for reasons that didn't trace back to
   any padding/border/box-sizing difference between them. An explicit
   width sidesteps whatever was causing that distribution to skew and
   guarantees the two are pixel-identical regardless. */
.cbm-mhp2-row-find-sell > .cbm-mhp2-panel--vehicles,
.cbm-mhp2-row-find-sell > .cbm-mhp2-panel--sell {
	flex: 0 0 auto; width: calc((100% - 20px) / 2); min-width: 0;
}
@media (max-width: 640px) {
	.cbm-mhp2-row-find-sell > .cbm-mhp2-panel--vehicles,
	.cbm-mhp2-row-find-sell > .cbm-mhp2-panel--sell { width: 100%; }
}
/* Smaller than the 40px full-row panel titles below — two of these side
   by side at the full size wouldn't fit without wrapping or crowding the
   buttons beneath. */
.cbm-mhp2-panel__title--small { font-size: 26px; white-space: normal; }

/* FIND VEHICLES and SELL VEHICLES title badges — explicit matching width
   AND height (not content-based auto-sizing), so they're guaranteed
   pixel-identical regardless of the two words' widths or any layout
   quirk. SELL VEHICLES' title used to BE the whole clickable box (a
   small standalone badge, no room for a background photo beyond its own
   tiny 400×59) — now it's just the badge INSIDE a real full-height panel
   (matching FIND VEHICLES' own height via align-items:stretch on the row
   above), same as FIND VEHICLES' own title sits inside its panel. That's
   what actually gives the photo real space to show in, rather than being
   squeezed into the badge itself. align-self:flex-start keeps the badge
   at its own natural size rather than stretching to fill the now-taller
   panel — the same flex-column-stretch fix used elsewhere on this page. */
.cbm-mhp2-panel--sell .cbm-mhp2-panel__title,
.cbm-mhp2-row-find-sell .cbm-mhp2-panel--vehicles .cbm-mhp2-panel__title {
	display: inline-flex; align-self: flex-start; align-items: center; justify-content: center;
	width: 400px; height: 59px; box-sizing: border-box;
	border-radius: 2px; text-align: center;
	/* 2026-10-13: "NEW & USED VEHICLES" is longer than "FIND VEHICLES" - on
	   small laptops/tablets (panel narrower than 400px) the badge ran past the
	   panel and the words were cut off. Never wider than its panel, text eases
	   down from 26px with the window. */
	max-width: 100%; font-size: clamp(18px, 2.4vw + 6px, 26px);
}
/* Padding matches FIND VEHICLES' own content padding exactly (12px top,
   14px bottom, 24px sides — see .cbm-mhp2-panel--vehicles .cbm-mhp2-
   panel__content below) so both titles' top edges line up without
   needing a compensating margin. Background transparent so the fade-bg
   photo (added as a direct child, same pattern as every other
   fade-preview panel on this page) actually shows through the panel —
   only the badge itself stays solid green. */
.cbm-mhp2-panel--sell {
	display: flex; padding: 12px 24px 14px; box-sizing: border-box;
	text-decoration: none; cursor: pointer; background: transparent;
}
.cbm-mhp2-panel--sell:hover .cbm-mhp2-panel__title,
.cbm-mhp2-panel--sell:focus-visible .cbm-mhp2-panel__title { color: #000; } /* 2026-10-19: black letters on hover, matching NEW/USED */
/* position:relative + z-index:1 is load-bearing, not decorative — the
   fade-bg image is position:absolute, and an absolutely-positioned
   element paints ABOVE a static-positioned sibling regardless of DOM
   order or z-index:auto, even one that comes later in the markup. Without
   this the badge was being silently painted over by the photo (only
   :hover's filter happened to force a repaint that made it visible). */
.cbm-mhp2-panel--sell .cbm-mhp2-panel__title {
	background: var(--cbm-green); color: #fff; margin: 0; position: relative; z-index: 1;
}
/* A real gradient this time, not a flat overlay or a blurred halo — mask-
   image on the IMAGE itself, radial and centered on where the badge sits
   (top:12px, left:24px, 400×59 — centre ≈ 224px, 42px). Ellipse sized 50%
   larger (480x240, up from 320x160) per Jonathan so the fade genuinely
   extends further before reaching full opacity. Grades smoothly from
   fully transparent at the centre out to fully opaque, so the photo
   thins out gradually under the badge rather than crossing any edge. */
.cbm-mhp2-panel--sell .cbm-mhp2-panel__fade-bg {
	-webkit-mask-image: radial-gradient(ellipse 480px 240px at 224px 42px, transparent 0%, black 100%);
	mask-image: radial-gradient(ellipse 480px 240px at 224px 42px, transparent 0%, black 100%);
}

/* FIND VEHICLES — NOT a single link (it holds the live Buses/Coaches/
   Minibuses/etc. controls, same as before), so only its title reads as a
   solid red box with white lettering, matching SELL VEHICLES' colour
   treatment without making the whole panel a (non-functional) link. */
.cbm-mhp2-row-find-sell .cbm-mhp2-panel--vehicles .cbm-mhp2-panel__title {
	background: var(--cbm-red); color: #fff;
}
/* No fade at all, per Jonathan — the fade-position tuning wasn't landing
   right, so this drops the mask entirely: the WHOLE image shows at full
   opacity across the whole panel. It still sits behind every button/label
   (the shared .cbm-mhp2-panel__fade-bg z-index:0 + .cbm-mhp2-panel--fade-
   preview .cbm-mhp2-panel__content's z-index:1 already handle that
   stacking correctly — this rule only removes the mask, it doesn't touch
   stacking). object-fit:cover (matching SELL VEHICLES exactly, no
   transform/scale trick layered on top) — with both boxes now the same
   pixel size, using the same fit mode on both is what actually makes the
   two photos read as the same size/zoom level, rather than one being
   letterboxed (contain) and scaled down while the other fills edge to
   edge (cover) at full scale. */
/* Same mask-image linear-gradient pattern already proven on FIND
   EVERYTHING ELSE and FIND ALL OPERATORS below (see .cbm-mhp2-panel__
   fade-bg's shared rule) — a real gradient on the image itself, not an
   overlay box or a blurred halo, so it thins out smoothly across the
   content area rather than crossing any hard edge. */
/* Two gradients combined, not one — the existing left-to-right fade
   (still there, unchanged) PLUS a new vertical fade running from the
   panel's vertical midpoint upward to fully transparent at the top,
   specifically thinning the photo out under the title badge. mask-
   composite:intersect (+ the older -webkit-mask-composite:source-in
   equivalent) makes the final result the OVERLAP of both — an area only
   stays fully opaque if BOTH gradients say so, so either fade condition
   (near the left edge, or near the top under the badge) thins the photo. */
/* 2026-10-19: mask removed, per Jonathan - the fade made the photo look
   like a misty day. Full-strength photo now, same as SELL VEHICLES. */
.cbm-mhp2-row-find-sell .cbm-mhp2-panel--vehicles .cbm-mhp2-panel__fade-bg {
	-webkit-mask-image: none;
	mask-image: none;
	object-fit: cover;
}
/* The shared .cbm-mhp2-panel--fade-preview .cbm-mhp2-panel__content rule
   reserves the photo its own ~40% width lane (flex:0 0 60%) — that made
   sense for the original side-by-side content+photo panels, but this
   photo now fills the WHOLE panel as a cover background, so there's no
   separate photo lane to reserve space for any more. Left uncorrected,
   that 60% cap squeezed the Buses/Coaches/Minibuses + New/Used/Rental
   columns into too little width, wrapping the second column onto its
   own row below the first instead of sitting beside it. The content
   (and everything in it) should sit over the image, not be constrained
   by it — full width. */
.cbm-mhp2-row-find-sell .cbm-mhp2-panel--vehicles .cbm-mhp2-panel__content {
	flex-basis: 100%;
}
@media (max-width: 640px) {
	.cbm-mhp2-row-find-sell { flex-direction: column; }
	/* 2026-09-12: the FIND/SELL VEHICLES title badge has a fixed
	   width:400px (desktop-only figure, no mobile override existed) —
	   inside a stacked ~340px-wide mobile panel that overflowed the
	   badge text off the right edge of the screen. Same selector as the
	   400px rule in components.css so this genuinely overrides it rather
	   than losing on specificity. */
	.cbm-mhp2-panel--sell .cbm-mhp2-panel__title,
	.cbm-mhp2-row-find-sell .cbm-mhp2-panel--vehicles .cbm-mhp2-panel__title {
		width: 100%;
		/* 2026-10-13: "NEW & USED VEHICLES" wrapped to two lines and spilled out
		   of the fixed 59px height - grow instead, slightly smaller text. */
		height: auto; min-height: 59px; font-size: 22px; padding: 6px 10px;
	}
	/* Same 2026-09-12 pass: the inline "OR SEARCH" button + text input
	   (both fixed widths, sized for the desktop-width panel) sat side by
	   side inside a panel now only ~162px wide, so the input (was
	   width:250px) got clipped to an unusable ~19px sliver by the panel's
	   own overflow:hidden — invisible and unusable, not just cramped.
	   Stack them instead of trying to fit both on one line. */
	.cbm-mhp2-search-row { flex-direction: column; }
	.cbm-mhp2-search-input { width: 100%; }
	.cbm-mhp2-choice--search { width: 100%; }
}

/* FIND EVERYTHING ELSE + FIND ALL OPERATORS, each narrowed to make room
   for a fixed-width box beside them (MPU, then the stacked Video boxes
   below it) — the left/middle columns of the 3-column layout under
   Latest Tech, per Jonathan's sketch. Both rows reuse
   .cbm-mhp2-mpu-placeholder's existing flex:0 0 300px so the two boxes
   line up in one continuous middle column. */
/* ONE shared row, not two — the left sub-column (FIND EVERYTHING ELSE +
   FIND ALL OPERATORS, stacked) beside the middle sub-column (MPU + both
   Vehicle Test Videos, stacked), each sub-column with its own uniform
   20px gap. This is what makes the MPU-to-video gap match the
   video-to-video gap: with two independent rows (an earlier version of
   this), the MPU sat inside a row as tall as the whole FIND EVERYTHING
   ELSE panel, leaving a lot of dead space below it before the next row
   even started. One real flex column removes that dead space instead of
   patching it with a fragile negative margin. */
.cbm-mhp2-row-else-operators { display: flex; gap: 20px; align-items: flex-start; }
.cbm-mhp2-col-else-operators { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 20px; }
.cbm-mhp2-col-mpu-video { flex: 0 0 300px; width: 300px; display: flex; flex-direction: column; gap: 20px; }
.cbm-mhp2-col-mpu-video .cbm-video-test { flex: 0 0 auto; width: 100%; min-width: 0; }
/* 2026-09-13: this row never got a mobile treatment at all (found live
   on a real phone — Jonathan: "something is stopping the screen from
   being organised item by item, mixing elements together"). At a real
   375px width the row itself doesn't overflow the page (343px, fits) —
   which is exactly why the scrollWidth-based sweep on 09-12 missed it —
   but .cbm-mhp2-col-else-operators (FIND EVERYTHING ELSE + FIND ALL
   OPERATORS) was being crushed to a ~23px sliver beside the fixed
   300px .cbm-mhp2-col-mpu-video column, same underlying cause as the
   sitewide nav bug: a fixed-width flex sibling with nothing making the
   other column stack properly. */
/* 2026-10-13: tablets / small laptops too - beside the fixed 300px column the
   FIND EVERYTHING ELSE panel was squeezed to ~350px, so its 207px tiles and
   one-line title ran off the right edge. Stack the same way as phones. */
@media (max-width: 1100px) {
	.cbm-mhp2-row-else-operators { flex-direction: column; align-items: stretch; }
	.cbm-mhp2-col-mpu-video { width: 100%; flex-basis: auto; }
}
@media (max-width: 640px) {
	.cbm-mhp2-row-else-operators { flex-direction: column; align-items: stretch; }
	.cbm-mhp2-col-mpu-video { width: 100%; flex-basis: auto; }
	.cbm-mhp2-panel--else .cbm-mhp2-search { flex-direction: column; align-items: stretch; max-width: 100%; }
	.cbm-mhp2-panel--else .cbm-mhp2-search input { width: 100%; }
}

/* Shared red-badge title treatment — same size/colour as FIND VEHICLES'
   title, reused here for FIND EVERYTHING ELSE and FIND ALL OPERATORS.
   align-self:flex-start is what actually makes this size to its own text
   rather than stretching full-width — the same flex-column-stretch bug
   documented above on FIND VEHICLES' title, fixed here without needing a
   hardcoded width since these two titles don't need to match a specific
   sibling's size the way FIND VEHICLES/SELL VEHICLES do. white-space:
   nowrap overrides .cbm-mhp2-panel__title--small's own white-space:normal
   (combined on the same element) — both labels read as one line, not two,
   even though the panel narrowed to make room for the MPU/video column. */
.cbm-mhp2-panel__title--red-badge {
	display: inline-flex; align-self: flex-start; align-items: center;
	background: var(--cbm-red); color: #fff; padding: 10px 18px; border-radius: 2px;
	white-space: nowrap;
}
@media (max-width: 640px) {
	.cbm-mhp2-panel__title--red-badge { white-space: normal; }
}

/* Two side-by-side columns (Buses/Coaches/Minibuses/All, then All/New/
   Used/Rental), each a single stack of boxes — not a 2-col grid, and not
   stretched to split the panel 50/50. Both columns are "ranged left":
   sized to their own content width (flex: 0 0 auto), so the type-step
   column sits tight against the left edge and the listing-step column,
   once revealed, appears directly beside it rather than off across a big
   gap left by a stretched, half-empty flex item. */
/* flex-wrap:wrap kept as a safety net for very narrow viewports only —
   the real fix for the search box sitting properly on the same row is
   the reduced choice-box width (190px→160px) and gap (16px→10px) below,
   which free up genuine room for it instead of relying on wrap to hide
   a too-tight fit. */
.cbm-mhp2-steps { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start; }
.cbm-mhp2-step { display: flex; flex-direction: column; gap: 8px; flex: 0 0 auto; }

/* OR SEARCH + the actual typeable search box, side by side, as the type
   column's own 4th row — self-contained inside .cbm-mhp2-step[type],
   independent of the listing column entirely (not affected by whether
   it's revealed, not competing with it for space, no cross-column
   alignment tricks needed). Always visible, since OR SEARCH is a
   constant alternative to picking a type/condition, not gated behind a
   selection. This row is allowed to be wider than the 135px choice
   boxes above it — .cbm-mhp2-step has no forced uniform width, so it
   simply sizes to fit its widest child. */
.cbm-mhp2-search-row { display: flex; gap: 8px; flex-basis: 100%; }
.cbm-mhp2-search-input {
	width: 250px; box-sizing: border-box; border: 1px solid var(--cbm-red); border-radius: 2px;
	padding: 9px 8px; font-size: 13px; color: var(--cbm-body-grey); background: var(--cbm-fill-light);
}
.cbm-mhp2-choice {
	/* Switched from --cbm-font-heading (Space Grotesk) to --cbm-font-body
	   (Inter) 2026-09-17 - same known issue as .cbm-back-btn (see
	   cbm_back_button_font_fixed memory): Jonathan spotted the same
	   serif-ish "B" on the Buses/Coaches/Minibuses choice buttons. This
	   class is shared sitewide across every MHP2 "choice" button (Find
	   Vehicles, Find Everything Else grid, etc.), so this one change
	   fixes all of them at once. */
	font-family: var(--cbm-font-body); font-weight: 700; font-size: 21px;
	letter-spacing: 0.02em; padding: 10px 14px; border-radius: 2px; border: 1px solid transparent;
	cursor: pointer; text-decoration: none; text-align: center; transition: background 0.15s, color 0.15s;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cbm-mhp2-choice.is-lit { background: var(--cbm-red); color: #fff; }
.cbm-mhp2-choice.is-lit:hover { background: var(--cbm-red-hover); }
.cbm-mhp2-panel--vehicles .cbm-mhp2-choice.is-lit:not(.is-selected):not(.is-coming):hover,
.cbm-mhp2-panel--vehicles .cbm-mhp2-choice.is-lit:not(.is-selected):not(.is-coming):focus-visible,
.cbm-mhp2-choice--search.is-lit:hover,
.cbm-mhp2-choice--search.is-lit:focus-visible { background: var(--cbm-red); color: #000; } /* 2026-10-19: black letters instead of the darker red, matching the panel titles */
.cbm-mhp2-choice.is-selected { background: var(--cbm-near-black); color: #fff; }
/* Solid logo-grey (--cbm-muted-grey, the same grey as the CBM logo's "M"
   and "Market" wordmark) with white text — same solid treatment as the
   red is-lit buttons, not the earlier pale/washed-out grey, so All/New/
   Used/Rental read as an equally solid second color rather than a weaker,
   disabled-looking version of the red set. */
.cbm-mhp2-choice.is-grey { background: var(--cbm-muted-grey); color: #fff; cursor: not-allowed; border-color: var(--cbm-muted-grey); }
/* The ones NOT picked in a step — fades to 20% opacity rather than
   turning solid grey, so the black is-selected button reads clearly as
   "this one's chosen" by contrast. Still fully clickable (cursor:pointer,
   no disabled state) so a visitor can change their mind. */
.cbm-mhp2-choice.is-faded { opacity: 0.2; }
.cbm-mhp2-choice.is-faded:hover { opacity: 0.5; }

/* Fixed, content-driven width rather than stretching to fill the flex
   column — box-shaped per Jonathan's sketch, and lets text wrap onto a
   second line for longer words like "Minibuses" instead of clipping. */
.cbm-mhp2-step .cbm-mhp2-choice, .cbm-mhp2-search-row .cbm-mhp2-choice {
	width: 135px; box-sizing: border-box;
	white-space: normal; line-height: 1.15; overflow: visible; text-overflow: clip;
}

/* Type (Buses/Coaches/Minibuses) and listing (New/Used/Rental) steps now
   share the same shorter padding — Reset has been removed (clicking a
   different type button already fully re-selects without needing it), so
   both steps are back to 3 boxes each and there's no longer a reason for
   type to run taller than listing. This also shrinks FIND VEHICLES'
   overall depth, and SELL VEHICLES with it (it stretches to match via
   align-items:stretch on .cbm-mhp2-row-find-sell). */
[data-cbm-mhp2-step="type"] .cbm-mhp2-choice,
[data-cbm-mhp2-step="listing"] .cbm-mhp2-choice { padding-top: 3px; padding-bottom: 3px; }

/* New/Used/Rental aren't shown at all on the default view — they only
   appear once a vehicle type is picked in the step beside it. */
[data-cbm-mhp2-step="listing"] { display: none; }
[data-cbm-mhp2-step="listing"].is-revealed { display: flex; }

/* OR SEARCH — a real submit button now (was a disabled placeholder input),
   always available regardless of type/listing selection — same red is-lit
   styling/dimensions as Buses/Coaches/Minibuses above it, but structurally
   its own row (see .cbm-mhp2-search-row above), independent of both step
   columns. Submits .cbm-mhp2-search-row (a <form> now) to /search/, same
   destination as the topbar search. */
.cbm-mhp2-choice--search {
	border: none; outline: none; font-family: var(--cbm-font-body);
	font-weight: 700; font-size: 14px; letter-spacing: 0.02em; cursor: pointer;
}

.cbm-mhp2-search { display: flex; align-items: center; gap: 10px; margin-top: auto; padding-top: 8px; }
/* FIND EVERYTHING ELSE's search bar was stretching to the full content
   column width, past the right-hand edge of the else-grid's two 230px
   boxes — capped to that same width (230+230+8 gap) so it lines up with
   them instead of overshooting. */
.cbm-mhp2-panel--else .cbm-mhp2-search { max-width: 468px; }
.cbm-mhp2-search input {
	flex: 1; min-width: 0; border: 1px solid var(--cbm-red); border-radius: 2px;
	padding: 8px 12px; font-size: 13px; color: var(--cbm-body-grey); background: var(--cbm-fill-light);
}

/* No else-grid-specific colour override — the markup already carries
   is-lit on each link (same as FIND VEHICLES' buttons), so removing the
   override here lets .cbm-mhp2-choice.is-lit's solid red/white styling
   apply directly, matching FIND VEHICLES' colour scheme exactly rather
   than this section's own lighter outline treatment. */
.cbm-mhp2-else-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
/* Widened from FIND VEHICLES' 190px so "Industry Bodies" — the longest
   label here — fits on one line rather than wrapping; the other five
   boxes widen to match so the grid stays uniform. Column gap matches
   FIND VEHICLES' box gap (8px, set above on .cbm-mhp2-else-grid) rather
   than the previous 10px. */
.cbm-mhp2-else-grid .cbm-mhp2-choice {
	width: 207px; box-sizing: border-box;
	padding-top: 9px; padding-bottom: 9px;
	white-space: normal; line-height: 1.15; overflow: visible; text-overflow: clip;
}
@media (max-width: 640px) {
	.cbm-mhp2-else-grid .cbm-mhp2-choice { width: 100%; min-width: 0; }
}
/* Section not live yet (Settings > CBM Sections): faded, unclickable tile that
   says only "New Section Coming" - no section name, so nothing is given away
   (Jonathan, 2026-10-13). Smaller uppercase text keeps it to one line. */
.cbm-mhp2-else-grid .cbm-mhp2-choice.is-coming { opacity: 0.35; cursor: default; min-height: 44px; font-size: 13px; letter-spacing: 0.05em; text-transform: uppercase; display: flex; align-items: center; justify-content: center; }
.cbm-mhp2-else-grid .cbm-mhp2-choice.is-coming:hover { background: var(--cbm-red); }
/* Same faded, dead look for the MHP Rental button while the Rent section is off. */
.cbm-mhp2-step .cbm-mhp2-choice.is-coming { opacity: 0.35; cursor: default; }
.cbm-mhp2-step .cbm-mhp2-choice.is-coming:hover { background: var(--cbm-red); }

/* MHP Highlight Slots — see cbm-core's ad-management.php for the data
   model, front-page.php for where these classes get applied. A staff-
   sold, opt-in feature: deliberately understated (a small notification
   dot, not a shimmer/glow) so it reads as professional business software,
   not a gaming hint — per the user, 2026-08-29/30.
   The popup is a SIBLING of the tile's own <a>, not nested inside it
   (nested <a> tags are invalid HTML and click behaviour is unreliable),
   so the wrapper needs its own position:relative for the popup to anchor
   against; the tile itself is unstyled by the wrapper, kept exactly as
   it renders unwrapped. */
.cbm-mhp2-choice-wrap { position: relative; display: inline-flex; }
.cbm-mhp2-choice.is-highlighted { position: relative; }
.cbm-mhp2-choice.is-highlighted::after {
	content: ''; position: absolute; top: -4px; right: -4px; width: 12px; height: 12px;
	background: var(--cbm-gold); border: 2px solid #fff; border-radius: 50%;
	animation: cbm-highlight-pulse 2.4s ease-in-out infinite;
}
@keyframes cbm-highlight-pulse {
	0%, 100% { box-shadow: 0 0 0 0 rgba(232, 184, 75, 0.55); }
	50% { box-shadow: 0 0 0 6px rgba(232, 184, 75, 0); }
}
@media (prefers-reduced-motion: reduce) {
	.cbm-mhp2-choice.is-highlighted::after { animation: none; }
}

.cbm-highlight-popup {
	position: absolute; z-index: 20; bottom: calc(100% + 10px); left: 50%; transform: translateX(-50%);
	background: var(--cbm-near-black); color: #fff; padding: 10px 14px; border-radius: var(--cbm-radius);
	font-family: var(--cbm-font-body); font-size: 13px; line-height: 1.4; text-align: center;
	box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
	opacity: 0; visibility: hidden; transition: opacity 0.15s ease;
	pointer-events: none;
	/* Capped width + normal wrapping, not white-space:nowrap — a longer
	   company name on the leftmost tile (Finance/Insurance/Products, see
	   .cbm-mhp2-else-grid's 2-column layout) centered under a 207px-wide
	   tile could force the box wide enough to overflow off the left edge
	   of the page entirely. Found live testing (2026-08-30): "Test Finance
	   Co (delete me)" pushed the box to left:-48px, genuinely off-screen. */
	width: max-content; max-width: 220px; white-space: normal;
}
.cbm-highlight-popup strong { color: var(--cbm-gold); }
.cbm-highlight-popup a { color: #fff; font-weight: 700; text-decoration: underline; pointer-events: auto; }
.cbm-mhp2-choice-wrap:hover .cbm-highlight-popup,
.cbm-mhp2-choice-wrap:focus-within .cbm-highlight-popup { opacity: 1; visibility: visible; pointer-events: auto; }
.cbm-highlight-popup::after {
	content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
	border: 6px solid transparent; border-top-color: var(--cbm-near-black);
}
@media (max-width: 640px) {
	/* No hover on touch — the popup would be unreachable, so on narrow
	   viewports it just shows permanently instead of hiding until hover. */
	.cbm-highlight-popup { position: static; opacity: 1; visibility: visible; transform: none; margin-top: 6px; white-space: normal; }
	.cbm-highlight-popup::after { display: none; }
}

/* FIND ALL OPERATORS — a link-out panel, not a choice grid, so it just
   needs intro copy and one CTA rather than the box styling above. */
.cbm-mhp2-operators__intro { font-size: 15px; line-height: 1.4; color: var(--cbm-body-grey); max-width: 380px; }
/* cover, not the other panels' contain — vehicle-sample.jpg's aspect
   ratio leaves it narrower than the panel under contain, so its own photo
   edge shows as a hard cutoff well before the mask's fade zone even
   starts. cover guarantees it fills the full panel width so the shared
   mask gradient is what's visible, not a premature photo boundary. */
.cbm-mhp2-panel--operators .cbm-mhp2-panel__fade-bg { object-fit: cover; }
/* Same fix as --operators above — a wide establishing shot (dealership
   forecourt, signage, sky) makes any under-fill from `contain` far more
   visible than FIND VEHICLES' own tighter interior close-up does, even at
   a similar aspect ratio. cover guarantees it fills edge-to-edge so the
   fade reads the same way FIND VEHICLES' does. */
.cbm-mhp2-panel--sell .cbm-mhp2-panel__fade-bg { object-fit: cover; }
/* ~20% shorter than the shared padding/gap — trimmed via layout (padding
   and the gap between title/intro/CTA), not by shrinking the intro text
   itself, since this panel's simple stack doesn't need as much breathing
   room as the choice-grid panels above it. */
.cbm-mhp2-panel--operators .cbm-mhp2-panel__content { padding-top: 6px; padding-bottom: 8px; gap: 8px; }
.cbm-mhp2-panel--operators .cbm-mhp2-operators__cta { padding-top: 3px; padding-bottom: 3px; }
.cbm-mhp2-operators__cta { display: inline-block; width: auto; white-space: nowrap; align-self: flex-start; padding: 6px 20px; font-size: 16px; }

.cbm-mhp2-billboard-placeholder {
	width: 300px; height: 600px; max-width: 100%;
	border-radius: var(--cbm-radius);
	background: repeating-linear-gradient(45deg, var(--cbm-fill-light), var(--cbm-fill-light) 10px, #fff 10px, #fff 20px);
	border: 1px dashed var(--cbm-muted-grey);
	display: flex; align-items: center; justify-content: center; text-align: center;
	font-family: var(--cbm-font-mono); font-size: 12px; letter-spacing: 0.05em; text-transform: uppercase;
	color: var(--cbm-muted-grey);
}

/* TBF ad, restacked for the skyscraper slot — same brand gradient as
   .cbm-tbf-banner (the real horizontal version) but vertical: logo, then
   headline/sub, then CTA pinned to the bottom. 160×600 — a true
   skyscraper shape (tall/narrow), not the wider "billboard" shape this
   was originally built at; renamed and re-sized to match per Jonathan.
   Padding/font-sizes trimmed down from the old 300px-wide version so the
   headline still wraps sensibly in the narrower box. */
.cbm-mhp2-tbf-skyscraper {
	width: 160px; height: 600px; max-width: 100%;
	background: linear-gradient(160deg,#0B3D5C 0%,#0e4d73 100%); border-radius: var(--cbm-radius);
	display: flex; flex-direction: column; align-items: center; text-align: center;
	padding: 28px 16px; text-decoration: none; box-sizing: border-box;
}
.cbm-mhp2-tbf-skyscraper__logo { background: #fff; border-radius: 4px; padding: 10px 14px; margin-bottom: 24px; }
.cbm-mhp2-tbf-skyscraper__logo img { height: 36px; width: auto; display: block; }
.cbm-mhp2-tbf-skyscraper__headline { font-family: var(--cbm-font-body); font-weight: 700; font-size: 17px; line-height: 1.3; color: #fff; }
.cbm-mhp2-tbf-skyscraper__sub { font-size: 12px; color: #cfe0ea; margin-top: 10px; }
.cbm-mhp2-tbf-skyscraper__cta {
	margin-top: auto; background: #fff; color: #0B3D5C; font-weight: 700; font-size: 13px;
	text-transform: uppercase; letter-spacing: 0.02em; padding: 12px 14px; border-radius: 3px;
}

/* Deliberately unboxed — just a title and a list, not a bordered card like
   the panels above it. Stacked (image on top, text below) rather than
   side-by-side — the column narrowed from 300px to 160px to match the
   skyscraper above it, and there's no longer room for a thumbnail and
   two lines of text sitting next to each other at that width. */
.cbm-mhp2-latest-used { display: flex; flex-direction: column; gap: 12px; }
.cbm-mhp2-latest-used__list { display: flex; flex-direction: column; gap: 14px; }
.cbm-mhp2-latest-used__item {
	display: flex; flex-direction: column; gap: 6px; text-decoration: none; color: inherit;
	padding: 6px; border-radius: 2px; transition: background 0.15s;
}
.cbm-mhp2-latest-used__item:hover { background: var(--cbm-fill-light); }
.cbm-mhp2-latest-used__thumb {
	flex-shrink: 0; width: 100%; height: 90px; border-radius: 2px; overflow: hidden;
	background: repeating-linear-gradient(45deg, var(--cbm-fill-light), var(--cbm-fill-light) 6px, #fff 6px, #fff 12px);
	border: 1px dashed var(--cbm-hairline);
}
.cbm-mhp2-latest-used__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cbm-mhp2-latest-used__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cbm-mhp2-latest-used__title { font-size: 13px; font-weight: 600; color: var(--cbm-near-black-alt); }
.cbm-mhp2-latest-used__price { font-size: 12px; color: var(--cbm-muted-grey); }
/* The section heading reuses the shared .cbm-mhp2-panel__title class,
   which is white-space:nowrap by default (built for the wide panels
   elsewhere on the page) — at this 160px column width "LATEST USED
   VEHICLES" doesn't fit on one line and was overflowing past the column's
   right edge. Scoped to this heading only, letting it wrap to two lines. */
.cbm-mhp2-latest-used > .cbm-mhp2-panel__title { white-space: normal; line-height: 1.25; }

/* .cbm-video-tests-wrap is the same shared class the real homepage uses
   (front-page.php) — its base rule keeps its own 32px side padding for
   that full-width context, unchanged. Nested inside .cbm-mhp2-col-left it
   already sits within .cbm-mhp2-wrap's own padding, so it's overridden
   here (scoped to this parent only) rather than editing the shared rule. */
.cbm-mhp2-col-left .cbm-video-tests-wrap { padding: 0; }

/* .cbm-ticker-wrap's shared 16px side padding is narrower than the 24px
   the panels above/below it (FIND VEHICLES/SELL VEHICLES, FIND EVERYTHING
   ELSE) use on their own content, so "Latest Tech"/"More info" sat 8px
   inboard of those panels' titles instead of lining up with them. Scoped
   override, not an edit to the shared rule — the real homepage's ticker
   still needs its own 16px in that full-width context. */
.cbm-mhp2-col-left__ticker .cbm-ticker-wrap { padding-left: 0; padding-right: 0; }
.cbm-mhp2-col-left__ticker .cbm-ticker__label { padding-left: 24px; }
.cbm-mhp2-col-left__ticker .cbm-ticker__get { padding-right: 24px; }

@media (max-width: 1024px) {
	.cbm-mhp2-wrap { flex-direction: column; align-items: stretch; }
	.cbm-mhp2-col-right { flex-basis: auto; }
}

/* Reusable "Start typing…" search box — see cbm_render_sitewide_search_box()
   in inc/template-tags.php. Meant to appear consistently across the site
   (the topbar's own search slot was replaced by the CBW Awards banner —
   see header.php), so this is one shared, small component rather than a
   per-page one-off. */
/* Styled as one single red button — same design/size as .cbm-rv-cat-btn
   (the "Find Buses" etc. buttons: background, padding, radius, type
   treatment all match) — with the "Start typing…" field built directly
   into the button rather than sitting beside it as a separate control,
   the label on the left and the typing area ranged to its right. Per
   Jonathan 2026-09-04. No visible submit button — Enter submits the form
   natively; a screen-reader-only one (see cbm_render_sitewide_search_box())
   keeps it a real accessible control for assistive tech and keyboard use. */
.cbm-search-box {
	display: flex; align-items: center; gap: 10px;
	background: var(--cbm-red); border-radius: 2px; padding: 5px 10px 5px 18px;
}
.cbm-search-box:hover, .cbm-search-box:focus-within { filter: brightness(1.1); }
.cbm-search-box__label {
	flex: 0 0 auto; color: #fff; font-weight: 700; font-size: 14px;
	letter-spacing: 0.03em; text-transform: uppercase; white-space: nowrap;
}
/* The typing area itself is a real white box inset within the red
   button — not blended into the red — per Jonathan 2026-09-04. */
.cbm-search-box__input {
	flex: 1 1 auto; min-width: 0; background: #fff; border: none; outline: none;
	border-radius: 2px; color: var(--cbm-near-black-alt); font-size: 14px; font-family: inherit;
	padding: 5px 10px;
}
.cbm-search-box__input::placeholder { color: var(--cbm-muted-grey); }

/* In the header's back-button row (header.php), the search box sits
   compact and to the left of the Back pill, rather than stretching the
   full row width. */
.cbm-back-wrap { gap: 12px; }
.cbm-back-wrap .cbm-search-box { flex: 0 0 auto; width: 280px; }
@media (max-width: 640px) {
	.cbm-back-wrap .cbm-search-box { width: 180px; }
	.cbm-back-wrap { flex-direction: column; align-items: flex-start; gap: 8px; }
	.cbm-back-wrap__title { white-space: normal; }
}

/* Standard Company Name / Address / Email / Telephone contact card,
   cbm_render_supplier_contact_card() in inc/template-tags.php - Jonathan,
   2026-09-27: "a contact section that we can standardise... always has
   those elements in one place". Two placements, same data: --sidebar
   (compact, stacked, sits in a column alongside the content) and --band
   (full-width horizontal strip, sits just above the site footer regardless
   of what layout the page above it uses). */
.cbm-supplier-contact-card__heading {
	font-size: 15px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--cbm-body-grey);
	margin: 0 0 12px;
}
.cbm-supplier-contact-card p {
	margin: 0 0 6px;
	font-size: 14px;
	line-height: 1.5;
}
.cbm-supplier-contact-card__name {
	font-size: 16px;
}
.cbm-supplier-contact-card__address {
	color: var(--cbm-body-grey);
	white-space: pre-line;
}

.cbm-supplier-contact-card--sidebar {
	margin-top: 20px;
}

.cbm-supplier-contact-card--band {
	margin-top: 48px;
	padding: 28px 0;
	border-top: 1px solid var(--cbm-hairline);
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 8px 32px;
}
.cbm-supplier-contact-card--band .cbm-supplier-contact-card__heading {
	margin: 0;
	flex: 0 0 auto;
}
.cbm-supplier-contact-card--band p {
	margin: 0;
}
@media (max-width: 640px) {
	.cbm-supplier-contact-card--band { flex-direction: column; align-items: flex-start; gap: 4px; }
}

/* Dealer page layout (single-dealer.php). Was an inline 2fr/1fr grid with no mobile rule, so on a
   phone the intro text and vehicle cards were squeezed into a ~120px strip beside the buttons
   (found 2026-09-28). Same two columns on desktop; on tablet/phone one column, with the
   CONTACT ME / VISIT WEBSITE sidebar first so it stays near the top of the page. */
.cbm-dealer-layout { padding-block: 0 56px; display: grid; grid-template-columns: 2fr 1fr; gap: 32px; }
@media (max-width: 900px) {
	.cbm-dealer-layout { grid-template-columns: minmax(0, 1fr); gap: 16px; }
	.cbm-dealer-layout .cbm-dealer-sidebar { order: -1; padding-top: 16px; }
}

/* Dealer stock showcase cards (2026-10-13, David Fishwick's own layout from their
   reply): one large photo over two small ones, make, model line, price bar with
   arrow. Two per row; one on phones. Photos carry the hairline border. */
.cbm-dealer-showcase { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin: 20px 0 28px; }
.cbm-dealer-showcase__card { display: flex; flex-direction: column; background: #fff; border: 1px solid var(--cbm-hairline); padding: 6px; color: var(--cbm-near-black); text-decoration: none; transition: box-shadow 0.15s; }
.cbm-dealer-showcase__card:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.12); }
.cbm-dealer-showcase__link { display: flex; flex-direction: column; color: inherit; text-decoration: none; min-width: 0; }
.cbm-dealer-showcase__price, .cbm-dealer-showcase__go { text-decoration: none; }
.cbm-dealer-showcase__price:hover, .cbm-dealer-showcase__go:hover { color: #fff; filter: brightness(1.08); }
.cbm-dealer-showcase__photos { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
.cbm-dealer-showcase__photos img { display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: cover; border: 1px solid var(--cbm-hairline); box-sizing: border-box; margin: 0; }
.cbm-dealer-showcase__photos img.cbm-dealer-showcase__main { grid-column: 1 / -1; aspect-ratio: 3 / 2; }
.cbm-dealer-showcase__make { margin: 14px 0 2px; text-align: center; font-weight: 700; font-size: 16px; letter-spacing: 0.12em; text-transform: uppercase; }
.cbm-dealer-showcase__model { text-align: center; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--cbm-body-grey); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding: 0 8px; }
.cbm-dealer-showcase__bar { display: flex; gap: 4px; margin-top: 14px; }
.cbm-dealer-showcase__price { flex: 1; display: flex; align-items: center; justify-content: center; min-height: 46px; background: #F39200; color: #fff; font-weight: 700; font-size: 16px; letter-spacing: 0.1em; }
.cbm-dealer-showcase__price small { font-size: 11px; margin-left: 4px; }
.cbm-dealer-showcase__go { display: flex; align-items: center; justify-content: center; width: 46px; background: #222; color: #fff; font-size: 20px; }
.cbm-dealer-showcase__wa { display: flex; align-items: center; justify-content: center; width: 46px; background: #25D366; color: #fff; font-weight: 700; font-size: 11px; text-decoration: none; }
.cbm-dealer-showcase__wa:hover { background: #1DA851; color: #fff; }
@media (max-width: 640px) {
	.cbm-dealer-showcase { grid-template-columns: minmax(0, 1fr); }
}

/* Sticky floating button ad space (sticky_button) — replicates legacy CBM's
   floating Approach button, 2026-10-06. Bottom-left so it never collides
   with the Tawk.to chat bubble bottom-right. */
.cbm-sticky-ad { position: fixed; left: 16px; bottom: 8rem; z-index: 9990; width: 170px; line-height: 0; }
.cbm-sticky-ad > .cbm-ad-carousel { display: block; width: 100%; overflow: hidden; }
.cbm-sticky-ad .cbm-ad-image-link img, .cbm-sticky-ad .cbm-ad-image-link video { width: 100%; height: auto; object-fit: contain; }
@media (max-width: 640px) {
	.cbm-sticky-ad { width: 120px; left: 8px; bottom: 5rem; }
}

/* Finished-artwork mode for the leaderboard shapes (see ad-rendering.php
   cbm_render_single_ad()): the advertiser's own banner shown whole, scaled
   to fit the box — contain, not cover, so no edge text is ever cropped. */
.cbm-ad-artwork { display: flex; align-items: center; justify-content: center; background: #fff; }
.cbm-ad-artwork img, .cbm-ad-artwork video { width: 100%; height: 100%; max-width: 100%; object-fit: contain; display: block; }

/* Homepage 160×600 skyscraper ad space (homepage_skyscraper), replacing the
   static TBF test artwork 2026-10-06 — same footprint as .cbm-mhp2-tbf-skyscraper. */
.cbm-mhp2-skyscraper-slot { width: 160px; height: 600px; max-width: 100%; border: 1px dashed var(--cbm-hairline); border-radius: var(--cbm-radius); overflow: hidden; box-sizing: border-box; }
.cbm-mhp2-skyscraper-slot > .cbm-ad-carousel { display: block; width: 100%; height: 100%; }

/* 2026-10-19, per Jonathan: in the MHP "NEW & USED VEHICLES" label, NEW links
   to the New Vehicles hub and USED to the Used Vehicles Showroom. */
.cbm-mhp2-title-link { color: inherit; text-decoration: none; }
.cbm-mhp2-title-link:hover,
.cbm-mhp2-title-link:focus-visible { color: #000; }
