/* 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; }

/* 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; }

/* 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 ad's own top sits one additional full line below that (lines+1, not
   lines) — a solid box has none of the leading a text line carries
   above/below its glyphs, so lining its top up exactly where line 3
   *would* start reads as a tighter gap than the line-to-line spacing
   above it, even though the measured distance is technically "one line";
   pushing it down by one whole further line makes the gap actually read
   as a full blank line. The paragraph itself still only gets
   var(--cbm-tw-lines) full-width lines — the shape-outside inset below is
   deliberately *not* increased to match.
   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;
   `24px` is the horizontal gap between the ad and the text beside it. All
   of it is relative to the paragraph's own font-size/line-height (`lh`
   units), 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-below: 12px;
	--cbm-tw-ad-gap-side: 24px;
}
/* .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) );
	height: calc( ( ( var(--cbm-tw-lines) + 1 ) * 1lh ) + var(--cbm-tw-ad-height) + var(--cbm-tw-ad-gap-below) );
	shape-outside: inset( calc( var(--cbm-tw-lines) * 1lh ) 0 0 0 );
}
.cbm-textwrap__ad {
	position: absolute;
	top: calc( ( var(--cbm-tw-lines) + 1 ) * 1lh );
	left: 0;
	width: var(--cbm-tw-ad-width);
}
.cbm-textwrap__ad .cbm-tbf-banner { width: 100%; }
.cbm-textwrap__text { margin: 0; color: var(--cbm-body-grey); }
.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; }
}

/* Ticker */
.cbm-ticker-wrap { padding: 14px 16px 4px; }
.cbm-ticker { background: #1A1A1A; border-radius: 2px; overflow: hidden; 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; 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; gap: 6px;
	padding: 2.4px 16px 2.4px 8px; 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; }
@media (max-width: 640px) { .cbm-ticker__label span { display: none; } }

/* Sponsor + socials */
.cbm-sponsor-wrap { padding: 16px 32px; }
.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 — same glow/shooting-star effect as the
   homepage's Awards banner (.cbm-awards-box__title / --spark below), but on
   a white page background rather than the dark box, so different colours;
   and spread across the full block width of the h1 via percentage `left`
   offsets on each spark instead of all sharing one centre point. */
/* 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; }
.cbm-page-title__letter {
	display: inline-block; animation-name: cbm-letter-toggle; animation-timing-function: linear;
	animation-iteration-count: infinite;
}
.cbm-page-title__letter--tight { margin-right: -0.164794921875em; }
/* Tighter than --tight (below) — the CBM logo's own lettering sits close
   enough to almost touch, so "CBW" is kerned tighter than "Awards 2027". */
.cbm-page-title__letter--brand { display: inline-block; margin-right: -0.24em; font-weight: 900; }
/* Smooth crossfade red→grey→red, not an instant cut (was steps(1,end)) —
   each letter still runs its own randomised duration/delay from the
   template, so the fades stay staggered/out-of-sync across the word. */
@keyframes cbm-letter-toggle {
	0%   { color: #D91E25; }
	50%  { color: #6D6E72; }
	100% { color: #D91E25; }
}
/* Red bar (half the page width, centred) with a white rectangle inside it
   holding the title — the stars (below) are positioned relative to the
   white box itself (position:relative on .cbm-awards-title-box), each
   point's left/top set inline in the template (0–100% = inside the box,
   <0%/>100% = just outside it), so together they read as scattered "in and
   around" the box 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; background: #fff; padding: 10.5px 21px; border-radius: 2px; text-align: center;
	white-space: nowrap; max-width: 100%; overflow: visible;
}
.cbm-awards-title-bar { min-width: 0; }
.cbm-page-title--sparkle { white-space: nowrap; }
@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-heading); 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-heading); 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-heading); 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-heading); 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-heading); 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 {
	background: #1A1A1A; 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) — a periodic "jump"
   scale-pulse to catch the eye while there's actually somewhere to vote,
   distinct from the constant title glow above which runs regardless. */
.cbm-awards-box--live { animation: cbm-awards-jump 2.6s ease-in-out infinite; }
@keyframes cbm-awards-jump {
	0%, 78%, 100% { transform: scale(1); }
	86% { transform: scale(1.06); }
	93% { transform: scale(0.98); }
}
@media (prefers-reduced-motion: reduce) {
	.cbm-awards-box--live { 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%;
}
/* !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: 9px 16px 24px; }
.cbm-pillars__heading {
	text-align: center; margin: 0 0 8px;
	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: #757880; }
.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 #757880; 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; }

.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-heading); 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 #757880; border-radius: 2px;
	font-family: var(--cbm-font-mono); font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase;
	color: var(--cbm-body-grey);
}
@media (max-width: 640px) {
	.cbm-video-tests { flex-direction: column; }
}

/* 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: 64px; height: 64px; border-radius: 4px; background: #2b2b2b; border: 1px solid #3a3a3a; display: flex; align-items: center; justify-content: center; padding: 10px; }
.cbm-shop-banner__icon svg { width: 100%; height: 100%; }
.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; }
