/*
 * WordPress/WooCommerce integration fixes ONLY. source.css / bootstrap.min.css /
 * font-awesome.min.css stay byte-for-byte unmodified (inc/assets.php). Most rules
 * below exist because we dropped Journal3's own JS engine (Swiper, its marquee
 * ticker, its off-canvas builder, its per-module instance CSS generated in its own
 * admin) and replaced it with plain WP/Woo + a small vanilla site.js — these rules
 * recreate the same visual result those engines produced. A few (search box, icon
 * links, pill buttons, trust badge) are new classes for pieces the source renders
 * via instance-specific generated CSS we can't reverse-engineer from static markup
 * (a module ID's own `.module-header_notice-56 {...}` block, Journal3 icomoon
 * codepoints assigned per module instance in its admin) — styled here to match the
 * real source screenshot instead (scrape/out/build/source-header-crop.png).
 */

/* Promo banner — real colour confirmed via computed style against the live source
   (scrape/check-source-colors.mjs): rgb(43,55,136), the brand navy. */
.notice-module {
	background: #2b3788;
	color: #fff;
	text-align: center;
	padding: 10px 16px;
}
.notice-module .ukp-nb-lg {
	font-size: 13px;
}
.notice-module b {
	font-weight: 700;
}

/* Hero slider: source.css's swiper rules expect Swiper's own JS to position and
   animate slides via transform; site.js only toggles .swiper-slide-active, so stack
   the slides and cross-fade on that class instead of relying on Swiper transforms. */
.ukp-hero-slider .swiper-wrapper {
	position: relative;
	display: block;
}
.ukp-hero-slider .swiper-slide {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity .6s ease;
	pointer-events: none;
}
.ukp-hero-slider .swiper-slide.swiper-slide-active {
	position: relative;
	opacity: 1;
	pointer-events: auto;
}

/* Hero slide text: source.css's .slide-text-item has no font-size/weight of its
   own — real typography comes from custom properties Journal3's admin/JS sets
   per-module-instance (same pattern as the product grid's --grid-gap below),
   undefined here, so it fell back to plain unstyled body text. Values below are
   the real computed styles read directly off the live source (50px/700/#2b3788
   headline, 16px/400/#000 subheadline), not a guess.
   .slide-cols itself also carries real left/right padding on source (measured:
   250px both sides, symmetric with the viewport — confirmed on both slides,
   not slide-specific) via a --content-gutter custom property Journal3 sets
   per-instance; undefined here, so the whole hero was flush against the true
   viewport edge instead of matching the site's standard content margin. */
.slide-cols {
	padding: 0 250px;
	box-sizing: border-box;
}
@media (max-width: 991px) {
	.slide-cols {
		padding: 0 16px;
	}
}
.slide-col-left {
	padding: 40px 0;
}
.module-subitem-2.slide-text .slide-text-item {
	font-family: 'Poppins', sans-serif;
	font-size: clamp(28px, 4vw, 50px);
	font-weight: 700;
	line-height: 1.15;
	color: #2b3788;
	margin-bottom: 16px;
}
.module-subitem-3.slide-text .slide-text-item {
	font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
	font-size: 16px;
	font-weight: 400;
	line-height: 1.5;
	color: #000;
}

/* Hero slide 2 (Same Day Dispatch) — same typography gap as slide 1, plus a
   pill badge around "Same Day" (a real <s> tag in the source markup, reused
   as a styling hook rather than a strikethrough). Pill values are the real
   computed styles read off the live source; heading/sub reuse slide 1's
   already-verified-correct treatment, since both slides share the same
   eyebrow+heading+subtext structure and there's no reason for slide 2's
   main heading to be a different size/weight from slide 1's. */
.ukp-slide2-eyebrow .slide-text-item {
	font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
	font-size: 15px;
	font-weight: 400;
	color: #2b3788;
	margin-bottom: 10px;
}
.ukp-slide2-eyebrow s {
	display: inline-flex;
	background: #2b3788;
	color: #f5f7f8;
	padding: 3px 8px;
	border-radius: 100px;
	text-decoration: none;
	font-size: 13px;
	margin-right: 4px;
}
.ukp-slide2-heading .slide-text-item {
	font-family: 'Poppins', sans-serif;
	font-size: clamp(24px, 3.2vw, 40px);
	font-weight: 700;
	line-height: 1.2;
	color: #2b3788;
	margin-bottom: 14px;
}
.ukp-slide2-sub .slide-text-item {
	font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
	font-size: 16px;
	font-weight: 400;
	line-height: 1.5;
	color: #000;
}

/* Marquee: source.css's ticker is JS-driven (duplicated item sets + a running
   translateX); recreate the same endless scroll with a pure CSS keyframe instead.
   Source's .marquee-item spacing/colour/bullet-separator all come from
   per-module custom properties and a bullet ::after Journal3's own admin/JS
   sets per-instance — undefined here, so values below are the real colours
   read directly off the live source (span1 #229df6 blue "Need It Fast?",
   span2 #f5f7f8 off-white "We Ship..."), not a guess, plus a literal bullet
   between every item matching the real source screenshot exactly.
   .marquee-slider is display:inline-block in source.css, which shrink-wraps
   it to its own content instead of the full bar — on source this is masked
   because Journal3's JS renders far more duplicate items than fit in any
   viewport, so the shrink-wrapped box is always wider than the bar anyway.
   Our build only duplicated the item pair twice (front-page.php), so the
   shrink-wrapped box stopped a third of the way across the bar, leaving the
   rest of the navy bar empty — reported by the owner via screenshot. Force
   the slider to the bar's full width so overflow:hidden actually clips a
   full-width window (front-page.php separately bumps the duplicate count so
   the scrolling track stays wide enough to fill that window at any viewport
   up to 4K, per the matching comment there). */
.marquee {
	background: #2b3788;
}
.marquee .marquee-slider {
	display: block;
	width: 100%;
	box-sizing: border-box;
	overflow: hidden;
	padding: 10px;
}
.marquee .marquee-items {
	display: flex;
	width: max-content;
	animation: ukp-marquee 18s linear infinite;
}
.marquee .marquee-item {
	margin-left: 10px;
}
.marquee .marquee-item:first-child {
	margin-left: 0;
}
.marquee .marquee-item::after {
	content: "\2022";
	display: inline-block;
	margin-left: 10px;
	color: rgba(245, 247, 248, .7);
}
.marquee .marquee-item-1 span {
	color: #229df6;
}
.marquee .marquee-item-2 span {
	color: #f5f7f8;
}
@keyframes ukp-marquee {
	from { transform: translateX(0); }
	to   { transform: translateX(-50%); }
}

/* Product grid: source.css's .product-grid.auto-grid is a CSS Grid driven by
   custom properties (--auto-grow-type, --grid-min-col, --grid-max-col, --grid-gap)
   that Journal3 sets per-breakpoint via its own admin/JS, keyed to that specific
   module's instance ID. Without those, the repeat(var(...)) expression doesn't
   resolve and it silently falls back to one column. Desktop happened to inherit
   workable fallback values; mobile didn't. Explicit, breakpoint-based grid instead. */
/* .product-grid.auto-grid is a single-item WRAPPER — its actual children (the
   product cards) live one level deeper, inside .auto-grid-items. Same bug class
   as the search-box fix above: target the real flex/grid parent, not its wrapper. */
.product-grid.auto-grid .auto-grid-items {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 20px 16px;
}
@media (min-width: 576px) {
	.product-grid.auto-grid .auto-grid-items {
		grid-template-columns: repeat(3, 1fr);
	}
}
@media (min-width: 992px) {
	.product-grid.auto-grid .auto-grid-items {
		grid-template-columns: repeat(5, 1fr);
	}
}
.product-grid .product-layout {
	min-width: 0;
}
.product-grid .product-thumb .image img {
	width: 100%;
	height: auto;
}

/* "See All Products" button under the Bestsellers carousel — not a source element
   (the source relies on its tab/carousel UI instead); simple centered spacing. */
.ukp-see-all {
	text-align: center;
	padding: 24px 0;
}

/* Logo: source.css's #logo sizing chain (#logo{height:100%} -> a{height:100%} ->
   img{max-height:100%}) depends on an ancestor establishing a real pixel height via
   Journal3's --desktop-header custom property, set by its own JS. Our simplified
   header markup doesn't run that JS, so the chain resolves against an auto-height
   ancestor and the logo renders at its native 1043x247 size. `#logo a>img` is an
   ID selector (1,0,2) — a plain class can't outrank it, so !important is the only
   lever here, same as source.css's own width/height:auto !important on this rule.
   The source's logo sits LEFT in the header row, not centered (confirmed against
   source-header-crop.png) — desktop-logo-wrapper gets margin-right:auto for that. */
.header-logo {
	/* 56px/40px were an early estimate from the P1 header pass; the full-site
	   layout audit measured the real source logo directly (90px desktop,
	   49px mobile) and found the estimate was significantly undersized —
	   explains a 19px header-height shortfall site-wide (.mid-bar is
	   height:auto, sized to its tallest child). */
	max-height: 90px !important;
	width: auto !important;
	height: auto !important;
}
.desktop-logo-wrapper {
	margin-right: auto;
}
@media (max-width: 767px) {
	.header-logo {
		max-height: 49px !important;
	}
}

/* Top bar: source.css absolutely-positions .language-currency at left:50% to
   centre it independently of the flex-flowed items either side (it floats
   OVER the top-bar, out of normal flow — confirmed by its DOM position not
   matching its visual position on the live source: it sits between the
   other two elements in markup order, but renders dead-centre of .top-bar's
   own box regardless of them). An earlier pass concluded this couldn't be
   made to work ("our simplified DOM nests it one level differently") and
   gave up in favour of plain flex space-between — but .top-bar IS its own
   containing block here (no nesting mismatch like #main-nav's full-bleed
   case), so the real absolute-centring technique works correctly once
   .top-bar has position:relative. Verified against real source measurements:
   currency centres on .top-bar's own midpoint; Check Order Status and
   Peptide Calculator flow normally on the left (in that order — matching
   source, not the previous swapped order); the trust badge is pushed to the
   right via margin-left:auto rather than space-between (space-between across
   3 flex items would spread them evenly, which isn't what source does). */
.top-bar {
	display: flex !important;
	position: relative !important;
	width: 100%;
	align-items: center;
	gap: 12px;
	padding: 6px 16px;
	background: #fff;
}
.top-bar .language-currency {
	position: absolute !important;
	left: 50% !important;
	top: 50% !important;
	transform: translate(-50%, -50%) !important;
	height: auto !important;
}
.top-bar .ukp-trust-badge {
	margin-left: auto;
}
.top-bar > .top-menu:not(.ukp-order-status-menu):not(.language-currency) a {
	color: #98a2b3;
	font-size: 13px;
}

/* Check Order Status + currency dropdown render as filled navy pills on the real
   source (source-header-crop.png) — the source's own .btn styling needs a class
   we never emit (it's picked per-instance in Journal3's admin), so match directly. */
.ukp-pill-btn {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	background: #2b3788 !important;
	color: #fff !important;
	border-radius: 6px;
	padding: 6px 14px;
	font-size: 13px;
	font-weight: 600;
	border: 0;
	text-decoration: none !important;
}

/* Currency switcher — real functionality (inc/currency.php), previously just a
   decorative "£ Pound Sterling" pill with no dropdown menu and no options at
   all. .dropdown needs position:relative so the menu anchors to the pill
   itself rather than whichever ancestor happens to be positioned. */
.currency .dropdown {
	position: relative;
}
.ukp-currency-toggle {
	cursor: pointer;
}
.ukp-currency-toggle .symbol {
	margin-right: 4px;
}
.ukp-currency-menu {
	display: none;
	position: absolute;
	top: calc(100% + 6px);
	left: 50%;
	transform: translateX(-50%);
	z-index: 200;
	min-width: 170px;
	background: #fff;
	border: 1px solid #eaecf0;
	border-radius: 6px;
	box-shadow: 0 8px 24px rgba(16, 24, 40, 0.12);
	overflow: hidden;
}
.dropdown.open .ukp-currency-menu {
	display: block;
}
.ukp-currency-menu .j-menu {
	list-style: none;
	margin: 0;
	padding: 0;
}
.ukp-currency-menu .menu-item + .menu-item {
	border-top: 1px solid #eaecf0;
}
.ukp-currency-menu .currency-select {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 10px 14px;
	color: #344054;
	text-decoration: none;
	font-size: 13px;
}
.ukp-currency-menu .menu-item.active .currency-select,
.ukp-currency-menu .currency-select:hover {
	background: #f2f4f7;
	color: #2b3788;
}
.ukp-currency-menu .currency-code-dropdown {
	margin-left: auto;
	color: #98a2b3;
	font-size: 12px;
}
/* Mobile drawer's own copy of the switcher — the desktop version is hidden on
   narrow viewports (header.php renders it twice: header.php:~96 for desktop,
   the drawer foot for mobile), styled to sit naturally in the drawer's
   stacked link list rather than as a floating header pill. */
.ukp-drawer-foot .currency {
	margin-top: 8px;
}
.ukp-drawer-foot .ukp-currency-toggle {
	width: 100%;
	justify-content: center;
}
.ukp-drawer-foot .ukp-currency-menu {
	position: static;
	transform: none;
	margin-top: 6px;
	width: 100%;
	box-shadow: none;
}

/* Trust badge: the source injects this client-side into the top bar on desktop
   only, suppressed on payment pages (RECON-FINDINGS.md §1). Rendered statically
   here for now — revisit as a conditional include once checkout exists (P6). */
.ukp-trust-badge {
	display: none;
	align-items: center;
	line-height: 0;
	flex: 0 0 auto;
}
.ukp-trust-badge img {
	display: block;
	width: 110px;
	height: auto;
}
@media (min-width: 992px) {
	.ukp-trust-badge {
		display: inline-flex;
	}
}

/* Search box: the source shows a full visible input + button in the header, not a
   collapsed icon that expands a dropdown on click (which is what #search's
   search-dropdown-default source class implies without Journal3's own JS wiring
   that toggle). Render it open/visible permanently instead — simpler and correct
   for a static build either way. */
.desktop-search-wrapper {
	/* max-width was an earlier pass's unmeasured guess (420px) — source's real
	   bar measures 661.6px wide at a 1920px viewport. */
	flex: 1 1 600px;
	max-width: 660px;
}
.ukp-search-box {
	width: 100%;
}
.ukp-search-box .header-search {
	display: flex;
	border: 1px solid #d0d5dd;
	border-radius: 6px;
	overflow: hidden;
}
.ukp-search-box .search-input {
	flex: 1;
	border: 0;
	padding: 10px 14px;
	font-size: 14px;
	outline: none;
}
.ukp-search-box .search-button {
	border: 0;
	background: #2b3788;
	color: #fff;
	padding: 0 16px;
	cursor: pointer;
}
/* Second icon fix: source.css's own .fa-search::before AND .search-button's own
   ::before both carry real icon content (one via FontAwesome, one via
   Journal3's icomoon font) — icomoon's @font-face points at a relative
   OpenCart path that doesn't exist in this WordPress build, so that font
   404s and the browser shows its "missing glyph" fallback box right next to
   our own FontAwesome icon: two icons in one button, confirmed by the
   owner's screenshot. Same fix as the wishlist/compare buttons below. */
#search .search-button::before {
	content: none !important;
}

/* Live search suggestions (inc/search.php + site.js's searchSuggest()) — the
   source shows a real-time typeahead dropdown as you type; this box had none
   at all. .ukp-search-box needs position:relative so the panel anchors to
   the search box itself, not some unrelated positioned ancestor. */
.ukp-search-box {
	position: relative;
}
.ukp-search-suggest {
	position: absolute;
	top: calc(100% + 6px);
	left: 0;
	right: 0;
	z-index: 200;
	background: #fff;
	border: 1px solid #eaecf0;
	border-radius: 6px;
	box-shadow: 0 8px 24px rgba(16, 24, 40, 0.12);
	overflow: hidden;
}
.ukp-search-suggest-list {
	list-style: none;
	margin: 0;
	padding: 0;
	max-height: 70vh;
	overflow-y: auto;
}
.ukp-search-suggest-list li + li {
	border-top: 1px solid #eaecf0;
}
.ukp-search-suggest-list a {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 10px 14px;
	text-decoration: none;
	color: #344054;
}
.ukp-search-suggest-list a:hover {
	background: #f2f4f7;
}
.ukp-search-suggest-list img {
	width: 40px;
	height: 40px;
	object-fit: contain;
	flex: 0 0 auto;
	background: #f9fafb;
	border-radius: 4px;
}
.ukp-search-suggest-name {
	flex: 1 1 auto;
	font-size: 13px;
	line-height: 1.3;
}
.ukp-search-suggest-price {
	flex: 0 0 auto;
	font-size: 13px;
	font-weight: 600;
	color: #2b3788;
	white-space: nowrap;
}
.ukp-search-suggest-viewall a {
	justify-content: center;
	font-size: 13px;
	font-weight: 600;
	color: #2b3788;
	background: #f9fafb;
}

/* Account / Wishlist / Blog: icon above a small label, matching the source's
   stacked icon+caption layout in the header-cart-group (source-header-crop.png).
   The <s> sub-labels (Login/Register, Edit your wishlist, Research Hub) are
   source copy kept for a tooltip/sr-only treatment, not struck-through text. */
.ukp-icon-link a {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2px;
	font-size: 12px;
	color: #344054;
	text-decoration: none;
	padding: 4px 10px;
}
.ukp-icon-link .fa {
	font-size: 17px;
}
.ukp-icon-link s {
	display: none !important;
}
.header-cart-group {
	display: flex;
	align-items: center;
	gap: 8px;
}
.secondary-menu .j-menu {
	display: flex;
	flex-wrap: nowrap;
	list-style: none;
	margin: 0;
	padding: 0;
}
.header-cart-group {
	flex-wrap: nowrap;
}

/* Main nav row: an earlier pass incorrectly concluded this should be a plain
   white bar ("some ambient rule... unclear exact source") and force-overrode
   it to white with dark text. Direct live-source inspection (full-site colour
   audit) confirms it's wrong — the real nav bar is a full-width navy bar with
   off-white uppercase links; source paints the navy via a `.menu-bar::after`
   pseudo-element (confirmed via getComputedStyle(el, '::after')), which is
   too fragile a mechanism to depend on in our simplified DOM, so it's set
   directly here instead, matching the project's established approach for
   every other "Journal3 paints this via a mechanism we don't have" case.
   #main-nav's own box is NOT full-width on source either (confirmed: same
   1460px-inside-a-230px-offset-container as this build) — the full-bleed
   effect comes entirely from that background layer extending independently
   of the nav's own (narrower, centred) box. A background set directly on
   #main-nav only painted up to the nav's own edge, stopping short of the
   viewport — the bug the user screenshotted. The standard CSS full-bleed
   trick (left:50%;margin-left:-50vw) only works when applied relative to an
   element that is ITSELF centred in the true viewport — #main-nav isn't
   (its own box sits flush against its parent's left edge, not centred
   within it), so that trick resolved against the wrong 850px-wide box and
   still fell short. Fixed in JS instead (ukpFullBleedNav() in site.js),
   which measures #main-nav's real offset from the true viewport edges and
   sizes a dedicated background layer to match exactly — robust regardless
   of how the surrounding header rows are centred/offset, and kept in sync
   on resize. */
#main-nav {
	position: relative;
	width: 100%;
	justify-content: center;
}
.ukp-nav-bleed-bg {
	position: absolute;
	top: 0;
	bottom: 0;
	background: #2b3788;
	z-index: -1;
}
#main-nav .j-menu {
	display: flex;
	gap: 4px;
	list-style: none;
	margin: 0;
	padding: 8px 16px;
}
#main-nav a {
	color: #f5f7f8 !important;
	text-decoration: none;
	text-transform: uppercase;
	padding: 8px 7px;
	font-size: 15px;
	font-weight: 500;
}
#main-nav a .links-text {
	color: inherit !important;
}
#main-nav a:hover,
#main-nav a:hover .links-text {
	color: #fff !important;
}

.mid-bar {
	display: flex;
	align-items: center;
	gap: 16px;
	padding: 10px 16px;
	/* source.css fixes this at var(--desktop-header,80px), which clips any wrapped
	   row (our mobile layout wraps; the source's JS-driven one never does) instead
	   of growing to fit it — the overflow then visually collides with the section
	   below. Let it size to content instead. */
	height: auto !important;
}

/* Hamburger trigger + mobile account icon: desktop-hidden, matches the source's
   real mobile top bar (source-mobile-header.png): hamburger + account (left),
   logo (center), wishlist + cart (right), full-width search below. */
.ukp-hamburger,
.ukp-mobile-account {
	display: none;
}
.ukp-hamburger {
	flex-direction: column;
	justify-content: center;
	gap: 4px;
	width: 32px;
	height: 32px;
	border: 0;
	background: none;
	cursor: pointer;
	padding: 0;
}
.ukp-hamburger span {
	display: block;
	height: 2px;
	background: #1d2939;
	border-radius: 1px;
}
.ukp-mobile-account {
	color: #1d2939;
	font-size: 18px;
	text-decoration: none;
}

/* Off-canvas mobile nav drawer (real implementation, not a horizontal-scroll
   stand-in — the source's own off-canvas markup needs its page-builder JS to
   drive, so this is a fresh, equivalent implementation: slide-in panel + overlay,
   toggled by assets/js/site.js's mobileDrawer()). */
.ukp-drawer-overlay {
	position: fixed;
	inset: 0;
	background: rgba(16, 24, 40, .5);
	z-index: 1000;
	opacity: 0;
	transition: opacity .25s ease;
}
.ukp-drawer-overlay.is-visible {
	opacity: 1;
}
.ukp-drawer {
	position: fixed;
	top: 0;
	left: 0;
	bottom: 0;
	width: 280px;
	max-width: 85vw;
	background: #fff;
	z-index: 1001;
	transform: translateX(-100%);
	transition: transform .25s ease;
	display: flex;
	flex-direction: column;
	box-shadow: 2px 0 12px rgba(16, 24, 40, .15);
}
.ukp-drawer.is-open {
	transform: translateX(0);
}
.ukp-drawer-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 16px;
	border-bottom: 1px solid #eaecf0;
	font-weight: 700;
}
.ukp-drawer-close {
	border: 0;
	background: none;
	font-size: 24px;
	line-height: 1;
	cursor: pointer;
	color: #667085;
}
.ukp-drawer-nav {
	display: flex;
	flex-direction: column;
	padding: 8px 0;
	overflow-y: auto;
}
.ukp-drawer-nav a {
	padding: 12px 16px;
	color: #1d2939;
	text-decoration: none;
	border-bottom: 1px solid #f2f4f7;
}
.ukp-drawer-foot {
	margin-top: auto;
	padding: 12px 0;
	border-top: 1px solid #eaecf0;
	display: flex;
	flex-direction: column;
}
.ukp-drawer-foot a {
	padding: 10px 16px;
	color: #2b3788;
	text-decoration: none;
	font-size: 14px;
}
body.ukp-drawer-locked,
body.ukp-cart-locked {
	overflow: hidden;
}

/* Cart drawer: same .ukp-drawer base as the nav drawer, opens from the RIGHT
   instead of the left, and styles WooCommerce's own default mini-cart markup
   (widget_shopping_cart_content / woocommerce-mini-cart) since there is no
   source reference for this component (STANDARDS: net-new, flag it).

   Every selector below is scoped through #ukpCartDrawer (the stable <aside>
   wrapper), NOT the "ukp-cart-drawer-body"/"ukp-widget_shopping_cart_content"
   classes cart-drawer.php puts on the inner div — WooCommerce's cart-fragments
   JS replaces that inner div's entire outerHTML (attributes included) with a
   fresh server-rendered fragment on every page load and after every AJAX add,
   which strips those custom classes immediately, before a user ever sees them.
   Confirmed live: even on a plain first page load, the DOM already shows
   `<div class="widget_shopping_cart_content">` with no "ukp-" classes at all.
   Every rule that depended on them never matched, which is why the drawer
   rendered as an unstyled bulleted list with full-width images and a stray
   "×" character — the actual bug the owner screenshotted. Also mapped to
   WooCommerce's real per-item markup (confirmed by reading its live HTML):
   the remove "×" is the FIRST child (not last, despite appearing on the
   right), and the thumbnail + product name share ONE anchor (not two
   separate elements), both different from what the old selectors assumed. */
.ukp-cart-drawer {
	left: auto;
	right: 0;
	width: 400px;
	transform: translateX(100%);
}
.ukp-cart-drawer.is-open {
	transform: translateX(0);
}
#ukpCartDrawer .widget_shopping_cart_content {
	padding: 16px;
	overflow-y: auto;
	flex: 1 1 auto;
	display: flex;
	flex-direction: column;
}
#ukpCartDrawer .woocommerce-mini-cart__empty-message {
	color: #667085;
	margin: 0;
}
#ukpCartDrawer ul.woocommerce-mini-cart {
	list-style: none;
	margin: 0;
	padding: 0;
}
#ukpCartDrawer .woocommerce-mini-cart-item {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 12px 28px 12px 0;
	border-bottom: 1px solid #f2f4f7;
	position: relative;
}
#ukpCartDrawer .woocommerce-mini-cart-item > a:not(.remove) {
	display: flex;
	align-items: center;
	gap: 10px;
	flex: 1;
	min-width: 0;
	color: #1e1e1f;
	text-decoration: underline;
	font-size: 14px;
}
#ukpCartDrawer .woocommerce-mini-cart-item img {
	width: 56px;
	height: 56px;
	object-fit: cover;
	border-radius: 6px;
	flex-shrink: 0;
}
#ukpCartDrawer .woocommerce-mini-cart-item a.remove {
	position: absolute;
	top: 12px;
	right: 0;
	width: 20px;
	height: 20px;
	display: flex;
	align-items: center;
	justify-content: center;
	color: #98a2b3;
	text-decoration: none;
	font-size: 16px;
	line-height: 1;
}
#ukpCartDrawer .quantity {
	display: block;
	font-size: 13px;
	color: #667085;
	white-space: nowrap;
	flex-shrink: 0;
}
#ukpCartDrawer .woocommerce-mini-cart__total.total {
	display: flex;
	justify-content: space-between;
	padding: 14px 16px;
	margin: 0 -16px;
	font-weight: 700;
	background: #f9fafb;
	border-top: 1px solid #eaecf0;
}
#ukpCartDrawer .woocommerce-mini-cart__buttons.buttons {
	display: flex;
	flex-direction: column;
	gap: 8px;
	margin: 10px -16px -16px;
	padding: 16px;
}
#ukpCartDrawer .woocommerce-mini-cart__buttons.buttons a {
	display: block;
	text-align: center;
	padding: 10px;
	border-radius: 6px;
	text-decoration: none;
}
#ukpCartDrawer .woocommerce-mini-cart__buttons.buttons a.checkout {
	background: #2b3788;
	color: #fff;
}
#ukpCartDrawer .woocommerce-mini-cart__buttons.buttons a:not(.checkout) {
	border: 1px solid #d0d5dd;
	color: #344054;
}

/* Mobile header: our header.php is a single desktop-shaped markup (no separate
   .mobile-header block like the source's Journal3 markup, which swaps to a whole
   different DOM for <992px). Rather than duplicate the header twice, collapse the
   same markup down to the source's real mobile arrangement. */
@media (max-width: 767px) {
	/* Every .top-menu in the top bar (Check Order Status, Peptide Calculator,
	   currency) moves into the hamburger drawer footer on mobile — not just
	   the first one. ":first-child" alone only ever matched the Check Order
	   Status menu (it genuinely is the first child), so Peptide Calculator
	   (the second .top-menu) was never actually caught by this rule: it sat
	   visible at the very top of the page, overlapping the logo/search row
	   below it (mobile sweep, 2026-10-28 — scrape/out/mobile-sweep2/home-0.png). */
	.top-bar > .top-menu,
	.top-bar .ukp-order-status-menu,
	.top-bar .language-currency,
	.ukp-trust-badge {
		display: none !important;
	}
	.ukp-hamburger,
	.ukp-mobile-account {
		display: flex;
	}
	/* Account + Blog move into the hamburger drawer footer on mobile; keep only
	   Wishlist + Cart in the top bar, icon-only (matches source-mobile-header.png). */
	.secondary-menu .ukp-icon-link:nth-child(1),
	.secondary-menu .ukp-icon-link:nth-child(3) {
		display: none;
	}
	.ukp-icon-link .links-text {
		font-size: 0 !important;
	}
	.ukp-icon-link .fa {
		font-size: 20px;
	}
	.header-logo {
		max-height: 24px !important;
	}
	.desktop-logo-wrapper {
		margin: 0 8px;
	}
	.desktop-search-wrapper {
		flex-basis: 100%;
		order: 3;
		max-width: 100%;
	}
	.mid-bar {
		flex-wrap: wrap;
		gap: 6px;
	}
	.header-cart-group {
		gap: 4px;
		margin-left: auto;
	}
	#main-nav {
		display: none;
	}
}

/* Bootstrap's broad `input` resets can give a type="hidden" field visible
   dimensions in some contexts (seen on the My Account login form: the nonce
   field rendered as an empty navy rectangle, inheriting button-ish styling
   from a parent selector) — hidden inputs must never be visible, full stop. */
input[type="hidden"] {
	display: none !important;
}

/* Belt-and-suspenders: nothing on this page should ever need to scroll sideways. */
html, body {
	max-width: 100%;
	overflow-x: hidden;
}

/* Shop / category archive (woocommerce/archive-product.php) — net-new layout,
   no direct source class names captured for the sidebar/toolbar at Phase 0, so
   styled plainly here rather than guessing at Journal3 class names that would
   never actually be targeted by source.css anyway. */
.ukp-breadcrumb {
	padding: 16px;
	font-size: 13px;
	color: #667085;
}
.ukp-breadcrumb a {
	color: #2b3788;
	text-decoration: none;
}
.ukp-shop-layout {
	display: flex;
	gap: 32px;
	padding: 0 16px 40px;
	align-items: flex-start;
}
.ukp-shop-sidebar {
	flex: 0 0 220px;
	border: 1px solid #eaecf0;
	border-radius: 8px;
	padding: 16px;
}
.ukp-filter-head {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 12px;
	padding-bottom: 12px;
	border-bottom: 1px solid #eaecf0;
}
.ukp-filter-head a {
	font-size: 13px;
	color: #2b3788;
}
.ukp-shop-sidebar h4 {
	font-size: 13px;
	text-transform: uppercase;
	letter-spacing: .04em;
	margin: 16px 0 8px;
}
.ukp-price-range {
	display: flex;
	gap: 8px;
}
.ukp-price-range input {
	width: 0;
	flex: 1;
	border: 1px solid #d0d5dd;
	border-radius: 6px;
	padding: 6px 8px;
}
.ukp-filter-check {
	display: flex;
	align-items: center;
	gap: 6px;
	font-size: 14px;
	margin-bottom: 6px;
	color: #475467;
}
.ukp-filter-check span {
	margin-left: auto;
	color: #98a2b3;
}
.ukp-filter-apply {
	width: 100%;
	margin-top: 12px;
}
.ukp-shop-main {
	flex: 1 1 auto;
	min-width: 0;
}
.ukp-shop-intro {
	color: #475467;
	max-width: 760px;
}
.ukp-shop-toolbar {
	display: flex;
	justify-content: flex-end;
	gap: 20px;
	padding: 12px 0;
	border-top: 1px solid #eaecf0;
	border-bottom: 1px solid #eaecf0;
	margin-bottom: 20px;
	font-size: 14px;
}
.ukp-sort-form {
	display: flex;
	gap: 20px;
}
.ukp-sort-form select {
	border: 1px solid #d0d5dd;
	border-radius: 6px;
	padding: 4px 8px;
	margin-left: 6px;
}
/* Consolidated: this was defined twice (shop/category pagination from P3,
   blog pagination from P9 duplicated the whole component instead of reusing
   it) with conflicting min-width/height/color/font-size — the second
   definition silently won the cascade for every overlapping property
   everywhere, making half of this block dead code with no visible effect.
   One definition, used by both — pagination is the same UI pattern on every
   page type, not something that should legitimately differ. */
.ukp-pagination {
	display: flex;
	gap: 8px;
	flex-wrap: wrap;
	justify-content: center;
	padding: 24px 0;
}
.ukp-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 36px;
	height: 36px;
	padding: 0 10px;
	border: 1px solid #d0d5dd;
	border-radius: 6px;
	text-decoration: none;
	color: #272c32;
	font-size: 14px;
}
.ukp-pagination .page-numbers.current {
	background: #2b3788;
	color: #fff;
	border-color: #2b3788;
}
@media (max-width: 767px) {
	.ukp-shop-layout {
		flex-direction: column;
	}
	.ukp-shop-sidebar {
		flex-basis: auto;
		width: 100%;
	}
}

/* Cart / checkout: classic WooCommerce markup (STANDARDS LOCKED #3d/#2 — never
   block checkout), restyled on-brand. A full pixel-match to the source's staged
   multi-step funnel (numbered step bar, sticky order summary, trust strip) is
   bigger follow-up work — this pass makes it presentable and on-brand, keeps
   every server-side mechanism WooCommerce's own (STANDARDS: restyle the FRONT
   END only, never hand-roll order creation). */
/* Outer container width: source measures 1440px (max-width 1500px, 40px
   padding) on cart/checkout same as every other WooCommerce page — found via
   the full-site layout audit. The 900px cap here was a deliberate, flagged
   simplification from the checkout redesign pass (comment above), not meant
   to be a real container-width match; widened to the sitewide standard.
   Checkout's own two-column form layout (below) already has its own natural
   width constraints, so this doesn't stretch the form content edge-to-edge. */
.woocommerce-cart .container,
.woocommerce-checkout .container {
	max-width: 1500px;
	margin: 0 auto;
	padding: 32px 40px 60px;
}
.woocommerce-checkout h1,
.woocommerce-cart h1 {
	margin-bottom: 4px;
}
.woocommerce form .form-row {
	margin: 0 0 16px;
}
.woocommerce form .form-row label {
	display: block;
	margin-bottom: 4px;
	font-size: 14px;
	font-weight: 600;
	color: #344054;
}
.woocommerce form .form-row .required {
	color: #d92d20;
}
.woocommerce form .input-text,
.woocommerce form select,
.woocommerce-additional-fields textarea {
	width: 100%;
	border: 1px solid #d0d5dd;
	border-radius: 6px;
	padding: 10px 12px;
	font-size: 14px;
}
.woocommerce-billing-fields,
.woocommerce-shipping-fields,
.woocommerce-additional-fields {
	max-width: 520px;
}
#order_review,
.cart_totals,
table.shop_table {
	border-collapse: collapse;
	width: 100%;
	border: 1px solid #eaecf0;
	border-radius: 8px;
	overflow: hidden;
}
table.shop_table th,
table.shop_table td {
	padding: 12px;
	border-bottom: 1px solid #eaecf0;
	text-align: left;
}
table.shop_table tfoot tr:last-child td,
table.shop_table tfoot tr:last-child th {
	font-weight: 700;
	font-size: 16px;
}
.wc_payment_methods {
	list-style: none;
	margin: 20px 0;
	padding: 0;
	border: 1px solid #eaecf0;
	border-radius: 8px;
}
.wc_payment_methods .wc_payment_method {
	padding: 14px 16px;
	border-bottom: 1px solid #eaecf0;
}
.wc_payment_methods .wc_payment_method:last-child {
	border-bottom: 0;
}
.wc_payment_methods label {
	font-weight: 600;
	cursor: pointer;
}
.wc_payment_methods .payment_box {
	margin-top: 10px;
	padding: 12px;
	background: #f9fafb;
	border-radius: 6px;
	font-size: 14px;
	color: #475467;
}
#place_order,
.checkout-button,
.wc-proceed-to-checkout a.checkout-button {
	display: block;
	width: 100%;
	background: #2b3788;
	color: #fff;
	border: 0;
	border-radius: 6px;
	padding: 14px;
	font-size: 16px;
	font-weight: 700;
	cursor: pointer;
	text-align: center;
	text-decoration: none;
}
.ukp-min-order-notice {
	background: #fef3cd;
	border: 1px solid #f0c674;
	border-radius: 6px;
	padding: 10px 14px;
	color: #7a5c00;
	font-size: 14px;
}
.woocommerce-error {
	background: #fef1f1;
	border: 1px solid #f3a7a7;
	border-radius: 6px;
	padding: 14px;
	color: #a11;
	list-style: none;
}

/* Checkout staged-funnel redesign (woocommerce/checkout/form-checkout.php):
   dispatch countdown -> delivery notice -> coupon -> two boxed columns,
   matching the source's real layout (scrape/out/shots/desktop/checkout-2.png). */
.ukp-countdown-bar {
	max-width: 900px;
	margin: 20px auto 0;
	padding: 12px 20px;
	border: 1px solid #2b3788;
	border-radius: 8px;
	text-align: center;
	font-weight: 600;
	color: #1d2939;
}
.ukp-countdown-bar #ukpCountdown {
	color: #d92d20;
	font-variant-numeric: tabular-nums;
}
.ukp-delivery-notice {
	max-width: 900px;
	margin: 16px auto 0;
	background: #fdf6e3;
	border: 1px solid #f0d78c;
	border-radius: 8px;
	padding: 10px 20px;
}
.ukp-delivery-notice summary {
	cursor: pointer;
	font-weight: 600;
	color: #7a5c00;
}
.ukp-delivery-notice p {
	margin: 10px 0 0;
	font-size: 14px;
	color: #7a5c00;
}
.ukp-coupon-box {
	max-width: 900px;
	margin: 16px auto 0;
	padding: 0 16px;
}
.ukp-coupon-form {
	display: flex;
	gap: 10px;
	max-width: 420px;
}
.ukp-coupon-form input {
	flex: 1;
	border: 1px solid #d0d5dd;
	border-radius: 6px;
	padding: 10px 12px;
}

.ukp-account-switcher {
	max-width: 900px;
	margin: 16px auto 0;
}
.ukp-account-switcher .ukp-account-radios {
	display: flex;
	gap: 24px;
	margin-bottom: 4px;
}
.ukp-account-switcher .ukp-account-radios label {
	display: flex;
	align-items: center;
	gap: 6px;
	font-weight: 500;
	cursor: pointer;
}
/* Our radios already do this job — the "Returning customer?" notice + its own
   .showlogin toggle link (woocommerce_checkout_login_form()'s own markup)
   would just duplicate it. */
.ukp-account-switcher .woocommerce-form-login-toggle {
	display: none;
}
.ukp-login-form-slot form.login {
	margin-top: 16px;
	padding-top: 16px;
	border-top: 1px solid #e4e7ec;
}
.ukp-login-form-slot .form-row {
	margin-bottom: 12px;
}
.ukp-login-form-slot input[type="text"],
.ukp-login-form-slot input[type="password"] {
	width: 100%;
	border: 1px solid #d0d5dd;
	border-radius: 6px;
	padding: 10px 12px;
}
.ukp-login-form-slot button[name="login"] {
	background: #2b3788;
	color: #fff;
	border: 0;
	border-radius: 6px;
	padding: 10px 18px;
	font-weight: 600;
	cursor: pointer;
}

.ukp-checkout-grid {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 24px;
	max-width: 900px;
	margin: 24px auto 0;
	padding: 0 16px 60px;
	align-items: start;
}
.ukp-checkout-col {
	display: flex;
	flex-direction: column;
	gap: 20px;
}
.ukp-box {
	background: #f2f4f7;
	border-radius: 8px;
	padding: 20px;
}
.ukp-box h3,
.ukp-box legend {
	margin: 0 0 16px;
	font-size: 16px;
}
/* Within the billing box, Woo renders "Billing details" (h3) then all fields in
   one block — the source splits Contact Info from Billing Address visually, but
   that split isn't a safe structural move (STANDARDS: splitting woocommerce_
   checkout_billing risks losing which fields belong to which saved customer
   data). Left as one labelled box rather than risk it; fields keep their own
   labels so it reads clearly either way. */
.ukp-box .woocommerce-billing-fields > h3,
.ukp-box .woocommerce-shipping-fields > h3 {
	font-size: 16px;
	margin: 0 0 16px;
}
/* form-billing.php override splits Billing into two headed groups (Contact
   Information / Billing Address) — the second heading needs its own top
   gap so it doesn't sit flush under the first group's last field. */
.ukp-box .woocommerce-billing-fields > h3:not(:first-child) {
	margin-top: 24px;
}

.ukp-checkout-upsell label.ukp-checkout-upsell-item {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 10px 0;
	border-bottom: 1px solid #e4e7ec;
	font-size: 14px;
	cursor: pointer;
}
.ukp-checkout-upsell label.ukp-checkout-upsell-item:last-child {
	border-bottom: 0;
}
.ukp-checkout-upsell-checkbox {
	width: 18px;
	height: 18px;
	flex-shrink: 0;
}
.ukp-checkout-upsell-checkbox:disabled {
	opacity: .5;
}

.ukp-shipping-table {
	width: 100%;
	border-collapse: collapse;
}
.ukp-shipping-table th,
.ukp-shipping-table td {
	border: 0;
	padding: 0;
	text-align: left;
	display: block;
}
.ukp-shipping-table th {
	/* "Delivery Options" (the box h3) already says what this is — Woo's own
	   package-name th ("Shipment") would just repeat it redundantly. */
	display: none;
}
.ukp-shipping-table ul#shipping_method {
	list-style: none;
	margin: 0;
	padding: 0;
}
.ukp-shipping-table ul#shipping_method li {
	padding: 10px 0;
	border-bottom: 1px solid #e4e7ec;
}
.ukp-shipping-table ul#shipping_method li:last-child {
	border-bottom: 0;
}

.ukp-payment-box #payment {
	background: transparent;
	border: 0;
	border-radius: 0;
	box-shadow: none;
	padding: 0;
}
.ukp-payment-box .form-row.place-order {
	margin-top: 16px;
}

@media (max-width: 900px) {
	.ukp-checkout-grid {
		grid-template-columns: 1fr;
	}
}

/* My Account (LOCKED standard #1: Dashboard/Orders/Addresses/Account
   details/Logout). No source reference for structure — WooCommerce's own
   templates, restyled on-brand. Flexbox throughout, not float: STANDARDS
   notes a float-based sidebar collapses to a sliver inside any ancestor
   grid context (percentage widths survive, float doesn't) — this container
   is never nested in one, but flex is the safer default regardless. */
/* .woocommerce-page is WooCommerce's generic body class — applied to every
   WooCommerce-touched page (products, shop, category, cart, checkout, My
   Account), not just My Account. This rule was written for My Account only
   but its original selector (.woocommerce-page .container) unintentionally
   capped every product, category, shop and cart page at 1000px too — source
   measures 1440px (max-width 1500px, 40px padding) on all of those. Scoped
   to .woocommerce-account only, WooCommerce's actual My-Account-specific
   body class, so the narrower width now only applies where it was intended. */
.woocommerce-account .container {
	max-width: 1000px;
	margin: 0 auto;
	padding: 32px 16px 60px;
}
.woocommerce-account .woocommerce {
	display: flex;
	gap: 32px;
	align-items: flex-start;
}
.woocommerce-MyAccount-navigation {
	flex: 0 0 220px;
}
.woocommerce-MyAccount-navigation ul {
	list-style: none;
	margin: 0;
	padding: 0;
	border: 1px solid #eaecf0;
	border-radius: 8px;
	overflow: hidden;
}
.woocommerce-MyAccount-navigation li {
	border-bottom: 1px solid #eaecf0;
}
.woocommerce-MyAccount-navigation li:last-child {
	border-bottom: 0;
}
.woocommerce-MyAccount-navigation li a {
	display: block;
	padding: 12px 16px;
	color: #344054;
	text-decoration: none;
	font-weight: 500;
}
.woocommerce-MyAccount-navigation li.is-active a,
.woocommerce-MyAccount-navigation li a:hover {
	background: #2b3788;
	color: #fff;
}
.woocommerce-MyAccount-content {
	flex: 1 1 auto;
	min-width: 0;
}
.woocommerce-MyAccount-content table.shop_table {
	width: 100%;
}
/* Login / Register (also used by inc/account.php's /login/ redirect target) */
.woocommerce-form-login,
.woocommerce-form-register {
	max-width: 420px;
	background: #f2f4f7;
	border-radius: 8px;
	padding: 24px;
	margin-bottom: 24px;
}
.woocommerce-form-login .form-row label,
.woocommerce-form-register .form-row label,
.woocommerce-EditAccountForm .form-row label,
.woocommerce-Address .form-row label,
.woocommerce-edit-address .form-row label {
	display: block;
	margin-bottom: 4px;
	font-weight: 600;
	font-size: 14px;
}
.woocommerce-form-login .woocommerce-Input,
.woocommerce-form-register .woocommerce-Input,
.woocommerce-EditAccountForm .woocommerce-Input,
.woocommerce-Address .woocommerce-Input,
.woocommerce-edit-address input[type="text"],
.woocommerce-edit-address input[type="email"],
.woocommerce-edit-address input[type="tel"],
.woocommerce-edit-address select {
	width: 100%;
	border: 1px solid #d0d5dd;
	border-radius: 6px;
	padding: 10px 12px;
}
/* button[type="submit"], never a bare "button" selector — WordPress's own
   password-visibility toggle (button.show-password-input, injected next to
   every password field) is also a <button> in this form, and a broad
   selector repaints its small icon toggle as a full-width navy rectangle. */
.woocommerce-form-login button[type="submit"],
.woocommerce-form-register button[type="submit"],
.woocommerce-EditAccountForm button[type="submit"],
.woocommerce-edit-address button[type="submit"],
.woocommerce-MyAccount-content .button {
	background: #2b3788;
	color: #fff;
	border: 0;
	border-radius: 6px;
	padding: 10px 20px;
	font-weight: 600;
	cursor: pointer;
	text-decoration: none;
	display: inline-block;
}
@media (max-width: 767px) {
	.woocommerce-account .woocommerce {
		flex-direction: column;
	}
	.woocommerce-MyAccount-navigation {
		flex-basis: auto;
		width: 100%;
	}
}

/* WP admin bar sits above the sticky-positioned header the source CSS expects at
   the very top of the viewport; push the header down by the admin bar's height
   rather than letting it overlap (logged-in admin view only, never a customer). */
body.admin-bar .header-slim {
	margin-top: 32px;
}
@media screen and (max-width: 782px) {
	body.admin-bar .header-slim {
		margin-top: 46px;
	}
}

/* P8 static pages (page.php) — source's own "Information" pages are a plain
   prose block (h1/h2/h3/p/ul inside #content .content, Phase 0 harvest), so
   this stays close to Journal3's own typography rather than a bespoke design. */
.ukp-page {
	max-width: 900px;
	margin: 0 auto;
	padding: 24px 16px 60px;
}
.ukp-page-title {
	font-size: 28px;
	font-weight: 700;
	color: #272c32;
	margin: 0 0 20px;
}
.ukp-page-content {
	font-size: 15px;
	line-height: 1.7;
	color: #272c32;
}
.ukp-page-content h2 {
	font-size: 20px;
	font-weight: 700;
	margin: 32px 0 12px;
	color: #2b3788;
}
.ukp-page-content h3 {
	font-size: 16px;
	font-weight: 700;
	margin: 24px 0 8px;
}
.ukp-page-content p {
	margin: 0 0 14px;
}
.ukp-page-content ul,
.ukp-page-content ol {
	margin: 0 0 14px;
	padding-left: 22px;
}
.ukp-page-content li {
	margin-bottom: 6px;
}
.ukp-page-content a {
	color: #266fd3;
}
.ukp-page-content img {
	max-width: 100%;
	height: auto;
	border-radius: 6px;
}
.ukp-page-content table {
	width: 100%;
	border-collapse: collapse;
	margin: 0 0 14px;
}
.ukp-page-content table th,
.ukp-page-content table td {
	border: 1px solid #e2e5e9;
	padding: 8px 10px;
	text-align: left;
}

/* /track-my-order order-lookup tool (inc/order-tracking.php) — net-new,
   no source markup to match, so styled plainly like the shop sidebar. */
.ukp-order-tracker {
	border: 1px solid #eaecf0;
	border-radius: 8px;
	padding: 20px;
	margin-top: 10px;
}
.ukp-order-tracker-form {
	display: flex;
	flex-wrap: wrap;
	gap: 16px;
	align-items: flex-end;
}
.ukp-tracker-row {
	display: flex;
	flex-direction: column;
	gap: 6px;
	flex: 1 1 200px;
}
.ukp-tracker-row label {
	font-size: 13px;
	font-weight: 600;
	color: #272c32;
}
.ukp-tracker-row input {
	padding: 10px 12px;
	border: 1px solid #d0d5dd;
	border-radius: 6px;
	font-size: 14px;
}
.ukp-order-tracker-form .button {
	background: #2b3788;
	color: #fff;
	border: none;
	border-radius: 6px;
	padding: 11px 24px;
	font-weight: 600;
	cursor: pointer;
}
.ukp-tracker-error {
	color: #b42318;
	margin-top: 16px;
}
.ukp-tracker-result {
	margin-top: 20px;
	padding-top: 20px;
	border-top: 1px solid #eaecf0;
}
.ukp-tracker-items {
	list-style: disc;
	padding-left: 20px;
	margin: 10px 0;
}

/* P9 blog (home.php archive, single.php post) — no source archive page was
   ever harvested (only individual post pages), so this grid is net-new,
   styled consistently with the shop sidebar / card components elsewhere. */
.ukp-blog-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 24px;
	margin-top: 24px;
}
@media screen and (max-width: 900px) {
	.ukp-blog-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}
@media screen and (max-width: 600px) {
	.ukp-blog-grid {
		grid-template-columns: 1fr;
	}
}
.ukp-blog-card {
	border: 1px solid #eaecf0;
	border-radius: 8px;
	overflow: hidden;
	display: flex;
	flex-direction: column;
}
.ukp-blog-card-thumb {
	position: relative;
	display: block;
	aspect-ratio: 16 / 9;
	background: #f2f4f7;
}
.ukp-blog-card-thumb img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.ukp-blog-card-thumb-fallback {
	display: block;
	width: 100%;
	height: 100%;
	background: linear-gradient(135deg, #266fd3 0%, #2b3788 100%);
}
.ukp-blog-card-date {
	position: absolute;
	top: 10px;
	left: 10px;
	background: #2b3788;
	color: #fff;
	font-size: 12px;
	font-weight: 700;
	padding: 4px 10px;
	border-radius: 4px;
}
.ukp-blog-card-body {
	padding: 16px;
	display: flex;
	flex-direction: column;
	gap: 8px;
	flex: 1;
}
.ukp-blog-card-body h2 {
	font-size: 16px;
	margin: 0;
	line-height: 1.4;
}
.ukp-blog-card-body h2 a {
	color: #272c32;
	text-decoration: none;
}
.ukp-blog-card-body p {
	font-size: 14px;
	color: #667085;
	margin: 0;
	flex: 1;
}
.ukp-blog-card-link {
	font-size: 13px;
	font-weight: 600;
	color: #266fd3;
	text-decoration: none;
}

.ukp-single-post .ukp-post-hero {
	margin: 0 0 20px;
	border-radius: 8px;
	overflow: hidden;
}
.ukp-single-post .ukp-post-hero img {
	width: 100%;
	height: auto;
	display: block;
}
.ukp-post-meta {
	color: #667085;
	font-size: 13px;
	margin: 0 0 20px;
}

/* Homepage mid-page section (front-page.php grid-row-top-3/4/5 ONLY — these
   three wrapper classes are unique to the homepage, unlike the Journal3
   component classes below them, which footer.php's copyright block also
   reuses verbatim; an earlier unscoped pass here leaked into the footer,
   boxing the copyright text in a stray white card). Source's real
   markup/classes are all faithfully present (.title-module, .module-banners_grid,
   .info_blocks-grid etc.) but source.css gives them no visual box/background of
   their own — Journal3 paints those via a per-module "row-bg"/background-image
   layer set in its own admin, which we don't have. Values below are read directly
   off the live source's computed styles and a side-by-side screenshot
   (scrape/out/build/SOURCE-features-crop.png), not guessed. */

/* "High Quality Research Peptides" intro — centred heading + small blue
   underline bar + centred prose, inside a light-grey rounded panel. */
.grid-row-top-3 .title-module {
	background: #eef0f3;
	border-radius: 10px;
	padding: 40px 60px;
	text-align: center;
}
.grid-row-top-3 .title-module .title-main {
	width: 100%;
}
.grid-row-top-3 .title-module .title-main h2 {
	font-family: 'Poppins', sans-serif;
	font-size: 22px;
	font-weight: 700;
	color: #000;
	width: 100%;
	margin: 0 0 14px;
}
.grid-row-top-3 .title-module .title-divider {
	width: 48px;
	height: 3px;
	background: #229df6;
	margin: 0 auto 20px;
}
.grid-row-top-3 .title-module .subtitle {
	max-width: 760px;
	margin: 0 auto;
	color: #333;
	font-size: 15px;
	line-height: 1.7;
}
.grid-row-top-3 .title-module .subtitle p {
	margin: 0 0 16px;
}

/* "#Research Peptides" / "#by the numbers" divider banners — full-width navy
   bar, large bold hollow/outlined white text. Same component reused by two
   different module wrappers (.module-banners_grid, .module-info_blocks), so
   target the shared .module-title class directly rather than duplicating. */
.grid-row-top-3 .module-title,
.grid-row-top-4 .module-title {
	background: #2b3788;
	color: transparent;
	-webkit-text-stroke: 1px #f5f7f8;
	text-stroke: 1px #f5f7f8;
	font-family: 'Poppins', sans-serif;
	font-size: clamp(28px, 4vw, 48px);
	font-weight: 700;
	text-align: center;
	margin: 0 0 24px;
	padding: 20px 16px;
}

/* Category promo tiles (Shop Peptides / Laboratory Supplies) — two large
   cards, light-grey background, text left / product image right. */
.grid-row-top-3 .banners-grid.auto-grid .auto-grid-items {
	display: grid;
	grid-template-columns: 1fr;
	gap: 20px;
}
@media (min-width: 768px) {
	.grid-row-top-3 .banners-grid.auto-grid .auto-grid-items {
		grid-template-columns: repeat(2, 1fr);
	}
}
.grid-row-top-3 .module-banners_grid .slide-content {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: space-between;
	background: #eef0f3;
	border-radius: 10px;
	padding: 32px 24px;
	min-height: 260px;
	overflow: hidden;
}
.grid-row-top-3 .module-banners_grid .slide-col-left .slide-text-layer {
	font-family: 'Poppins', sans-serif;
	font-size: 13px;
	font-weight: 500;
	color: #229df6;
	text-transform: uppercase;
	letter-spacing: -.2px;
}
.grid-row-top-3 .module-banners_grid .slide-col-left .slide-text:nth-child(2) .slide-text-item {
	font-size: 18px;
	font-weight: 600;
	color: #000;
	margin-top: 4px;
}
.grid-row-top-3 .module-banners_grid .slide-button {
	margin-top: 16px;
}
.grid-row-top-3 .module-banners_grid .slide-button a.btn {
	color: #2b3788;
	font-weight: 600;
	font-size: 14px;
	text-decoration: underline;
}
.grid-row-top-3 .module-banners_grid .slide-col-right {
	flex-shrink: 0;
}
.grid-row-top-3 .module-banners_grid .slide-col-right img {
	max-width: 220px;
	height: auto;
}

/* "Join researchers worldwide..." CTA banner (grid-row-bottom-5). Root cause
   of the "every word on its own line" layout traced all the way up the chain
   to the exact same bug already fixed for the footer disclaimer box and the
   product grid: ".banners-wrapper.auto-grid-items" is a CSS grid whose real
   column count source sets via a per-instance "--items" custom property —
   undefined here, so it fell back to a 5-column default and squeezed this
   module's single real slide into a 264px-wide 1/5 slice, which cascaded
   down through .slide-content-custom/.slide-cols/.slide-col-left and made
   every downstream flex/grid fix on those inner elements pointless (their
   container was already too narrow before any of them ran). Forcing a single
   column here is always correct since this module only ever has one slide. */
.grid-row-bottom-5 .banners-wrapper.auto-grid-items {
	grid-template-columns: 1fr;
}
.grid-row-bottom-5 .module-banners_grid .slide-content-custom {
	background: linear-gradient(to left, #fff 40%, #e5e9ea 100%);
	border-radius: 8px;
	padding: 40px;
}
.grid-row-bottom-5 .module-banners_grid .slide-cols {
	display: block !important;
}
.grid-row-bottom-5 .module-banners_grid .slide-col-left,
.grid-row-bottom-5 .module-banners_grid .slide-col-right {
	/* The flex layout here collapses to 0 width no matter what flex/width value
	   is set on these two items (even an inline !important style set directly
	   via JS had no effect) — traced to source.css's own ".module-banners_grid
	   .slide-col" rule's flex-basis, a calc() built from undefined per-instance
	   custom properties (--slides-cols-auto-stack / --stack-unit, JS-set, same
	   unreproducible pattern as elsewhere) that something in the nested flex
	   chain (.slide-layers/.slide-text are flex containers too) resolves to an
	   effective 0 main-size no override could reach. Breaking .slide-cols out
	   of flex layout entirely sidesteps the whole chain instead of continuing
	   to fight it. */
	display: block !important;
	width: 100% !important;
}
.grid-row-bottom-5 .module-banners_grid .slide-col-right {
	margin-top: 24px;
}
@media (min-width: 768px) {
	/* grid, not flex: source.css's ".module-banners_grid .slide-col" rule
	   (flex-basis from an undefined per-instance custom property) re-poisons
	   flex-basis the instant .slide-cols goes back to display:flex, even with
	   !important on every property tried (confirmed with an inline style set
	   directly on the element via JS — still collapsed to 0 width). Grid items
	   don't consult flex-basis at all, so this sidesteps it completely. */
	.grid-row-bottom-5 .module-banners_grid .slide-cols {
		display: grid !important;
		grid-template-columns: 1fr auto !important;
		align-items: center;
		gap: 24px;
	}
	.grid-row-bottom-5 .module-banners_grid .slide-col-left,
	.grid-row-bottom-5 .module-banners_grid .slide-col-right {
		width: auto !important;
		min-width: 0 !important;
	}
	.grid-row-bottom-5 .module-banners_grid .slide-col-right {
		margin-top: 0;
	}
}
.grid-row-bottom-5 .module-banners_grid .slide-col-right {
	display: flex;
	align-items: center;
	justify-content: center;
}
.grid-row-bottom-5 .module-banners_grid .slide-text-item span {
	display: inline;
	font-family: 'Poppins', sans-serif;
	font-size: 28px;
	font-weight: 700;
	line-height: 1.3;
	background-image: linear-gradient(to right, #2b3788 0%, #2b3788 60%, rgba(43, 55, 136, .25) 100%);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	-webkit-text-fill-color: transparent;
}
.grid-row-bottom-5 .module-banners_grid .slide-button a.btn {
	display: inline-flex;
	align-items: center;
	background: #2b3788;
	color: #fff;
	font-weight: 600;
	font-size: 15px;
	padding: 14px 24px;
	border-radius: 8px;
	text-decoration: none;
	white-space: nowrap;
}
@media (max-width: 767px) {
	.grid-row-bottom-5 .module-banners_grid .slide-cols {
		flex-direction: column;
		gap: 24px;
	}
	.grid-row-bottom-5 .module-banners_grid .slide-text-item span {
		font-size: 22px;
	}
}

/* Four feature cards (Same Day Dispatch / International Delivery / Track &
   Trace / Research Use Only) — equal-width, light-grey background boxes. */
.grid-row-top-4 .info_blocks-grid.auto-grid .auto-grid-items {
	display: grid;
	grid-template-columns: 1fr;
	gap: 16px;
}
@media (min-width: 576px) {
	.grid-row-top-4 .info_blocks-grid.auto-grid .auto-grid-items {
		grid-template-columns: repeat(2, 1fr);
	}
}
@media (min-width: 992px) {
	.grid-row-top-4 .info_blocks-grid.auto-grid .auto-grid-items {
		grid-template-columns: repeat(4, 1fr);
	}
}
.grid-row-top-4 .info-blocks-icon .info-block {
	background: #f7f7f8;
	border-radius: 8px;
	padding: 24px 20px;
	height: 100%;
}
.grid-row-top-4 .info-block-title {
	font-family: 'Poppins', sans-serif;
	font-size: 16px;
	font-weight: 600;
	color: #000;
	margin-bottom: 10px;
}
.grid-row-top-4 .info-block-text {
	font-size: 14px;
	line-height: 1.6;
	color: #475467;
}

/* "#by the numbers" stat cards (999+ / 11Y style counters) — bordered boxes,
   large bold number + smaller label beneath, matching the real source. */
.module-info_blocks.has-countup {
	background: #eef0f3;
	border-radius: 10px;
	padding: 40px;
}
.module-info_blocks.has-countup .module-title {
	margin: -40px -40px 24px;
}
.info-blocks-counter .info-block {
	background: transparent;
	border: 1px solid #d0d5dd;
	border-radius: 8px;
	padding: 32px 20px;
	text-align: center;
}
.info-block-counter {
	font-family: 'Poppins', sans-serif;
	font-size: 42px;
	font-weight: 700;
	color: #000;
	margin-bottom: 8px;
}
.ukp-counter-suffix {
	color: rgba(30, 30, 31, .7);
}
/* "#by the numbers" banner heading: source renders it as navy full-bleed-within-
   section bar with white-outline (transparent fill + text-stroke) text — gated
   behind a per-module-instance class again, so scoped through our own existing
   row class instead (measured: bg #2b3788, 48px/700, 1px #f5f7f8 stroke). */
.grid-row-bottom-4 .module-title {
	color: transparent;
	-webkit-text-stroke: 1px #f5f7f8;
	background: #2b3788;
	font-size: 48px;
	font-weight: 700;
	padding: 4px 0;
	text-align: center;
	width: 100%;
	box-sizing: border-box;
}
.info-blocks-counter .info-block-title {
	font-size: 15px;
	font-weight: 400;
	color: #475467;
	margin: 0;
}

/* /contact/ (page-contact.php) — found missing during the full-site audit:
   the main nav's "Contact" link 404'd, no page ever existed for it. Two
   columns matching the source: info blocks left, real working form right. */
.ukp-contact-layout {
	display: grid;
	grid-template-columns: 1fr;
	gap: 32px;
}
@media (min-width: 900px) {
	.ukp-contact-layout {
		grid-template-columns: 300px 1fr;
	}
}
.ukp-contact-info-block {
	margin-bottom: 24px;
}
.ukp-contact-info-title {
	font-family: 'Poppins', sans-serif;
	font-weight: 700;
	font-size: 15px;
	color: #000;
	margin-bottom: 6px;
}
.ukp-contact-info-text {
	font-size: 14px;
	line-height: 1.6;
	color: #475467;
}
.ukp-contact-info-text a {
	color: #266fd3;
}
.ukp-contact-form-col {
	background: #eef0f3;
	border-radius: 10px;
	padding: 32px;
}
.ukp-contact-title {
	font-family: 'Poppins', sans-serif;
	font-size: 22px;
	font-weight: 700;
	margin: 0 0 24px;
}
.ukp-form-row {
	margin-bottom: 18px;
}
.ukp-form-row label {
	display: block;
	font-size: 14px;
	font-weight: 600;
	margin-bottom: 6px;
	color: #272c32;
}
.ukp-form-row label span {
	color: #b42318;
}
.ukp-form-row input[type="text"],
.ukp-form-row input[type="email"],
.ukp-form-row select,
.ukp-form-row textarea {
	width: 100%;
	padding: 10px 12px;
	border: 1px solid #d0d5dd;
	border-radius: 6px;
	font-size: 14px;
	font-family: inherit;
	background: #fff;
}
.ukp-form-checkbox label {
	display: flex;
	gap: 8px;
	font-weight: 400;
	font-size: 13px;
	line-height: 1.5;
	align-items: flex-start;
}
.ukp-form-checkbox input {
	margin-top: 3px;
}
.ukp-contact-submit {
	background: #2b3788;
	color: #fff;
	border: none;
	border-radius: 6px;
	padding: 12px 32px;
	font-weight: 600;
	font-size: 15px;
	cursor: pointer;
}
.ukp-contact-success {
	background: #ecfdf3;
	border: 1px solid #abefc6;
	color: #067647;
	padding: 16px;
	border-radius: 8px;
}
.ukp-contact-error {
	background: #fef3f2;
	border: 1px solid #fecdca;
	color: #b42318;
	padding: 12px 16px;
	border-radius: 8px;
	margin-bottom: 16px;
}

/* Product-card / single-product wishlist & compare buttons. Source's real
   32x32px/white-bg/1px-border/8px-radius icon-button styling (measured live)
   turned out to be scoped to the ".main-products-style" grid context, same as
   several other things this project has hit — on the homepage bestseller
   grid and single-product.php's wishlist-compare block, which don't have
   that class, .btn-wishlist/.btn-compare fell through to a generic
   `.btn.btn-primary`-style default instead: solid navy, 42px tall, no
   border, no gap from the Add to Cart button — the "big blue blob" the owner
   screenshotted. Rather than re-scope per context (the pattern that kept
   causing this across the project), these rules are unscoped so the correct
   look applies everywhere .btn-wishlist/.btn-compare appear. Icon glyph
   itself is a Journal3 icomoon codepoint injected per-instance by admin JS,
   so this adds a real <em class="fa"> icon and hides the text with a
   standard accessible-only (sr-only) clip instead — but source.css's own
   ::before on these buttons ALSO has real (non-empty) content set to that
   codepoint, not empty as an earlier pass's quick read of the computed
   value assumed (a private-use character that prints invisibly in a
   terminal, easy to mistake for a genuine empty string). Journal3's own
   icomoon @font-face points at a relative OpenCart path
   ("catalog/view/theme/journal3/icons/fonts/icomoon.woff2") that doesn't
   exist anywhere in this WordPress build, so that font 404s and the browser
   renders its fallback "missing glyph" box instead — sitting right next to
   our added FontAwesome icon, i.e. two icons per button, confirmed by the
   owner's screenshot. Owner flagged open item: wishlist/compare have no
   backend here, visual only, same call already made for
   single-product.php's wishlist-compare block. */
/* Add to Cart on the product-card grid has the exact same bug as
   .btn-wishlist/.btn-compare below: the correct white/bordered/32px-tall look
   (measured on source's shop grid: transparent bg, 1px solid
   rgba(30,30,31,.5), 8px radius, 13px/400 text, 32px tall) is scoped to
   .main-products-style — off that grid (homepage bestsellers) it fell
   through to the generic .btn{padding:1em 2em} default: solid navy, 42px
   tall, 72px wide (too narrow for its own "Add to Cart" text, which is why
   only the cart icon was visible), confirmed by the owner's screenshot
   comparing the two pages side by side. Unscoped so it's correct everywhere,
   same approach as the wishlist/compare fix. No explicit width set — letting
   it size to its own content/padding is what already worked correctly on
   the shop grid; a fixed px value would just be wrong at a different grid
   density (5 columns on the homepage vs. 4 on the shop page). */
.btn-cart {
	display: inline-flex !important;
	align-items: center;
	justify-content: center;
	gap: 6px;
	height: 32px !important;
	padding: 0 14px !important;
	background: rgba(255, 255, 255, 0) !important;
	color: rgba(30, 30, 31, 1) !important;
	border: 1px solid rgba(30, 30, 31, .5) !important;
	border-radius: 8px !important;
	font-size: 13px !important;
	font-weight: 400 !important;
}
.no-touchevents .btn-cart:hover {
	/* source.css's generic ".no-touchevents .btn:hover{color:#f1faf8}" (near-
	   white, meant for buttons with a navy background elsewhere on the site)
	   was winning here too since .btn-cart also carries the bare ".btn"
	   class — on this white-background button that made the text nearly
	   invisible on hover, exactly the "text wants to disappear" the owner
	   flagged. Needed matching 3-class specificity (0,3,0) to beat it, not
	   just !important — a plain ".btn-cart:hover" (0,2,0) still lost despite
	   !important on both sides. Shop page avoids this via its own
	   .main-products-style-scoped hover rule (measured: text turns navy,
	   #2b3788, not white); matched that here instead. */
	color: #2b3788 !important;
}
.btn-cart .btn-text {
	/* source.css hides ALL .btn-text inside .product-layout by default
	   (".product-layout .btn-text{display:none}") and only re-shows it for
	   Add to Cart specifically via a ".main-products-style..." scoped
	   override — off that grid this collapsed to icon-only, matching the
	   owner's screenshot (cart icon with no "Add to Cart" label). */
	display: inline-block !important;
	color: inherit;
}
.btn-wishlist,
.btn-compare {
	display: inline-flex !important;
	align-items: center;
	justify-content: center;
	width: 32px !important;
	height: 32px !important;
	min-width: 0 !important;
	padding: 0 !important;
	background: rgba(255, 255, 255, 0) !important;
	border: 1px solid rgba(30, 30, 31, .5) !important;
	border-radius: 8px !important;
	flex-shrink: 0;
}
.btn-wishlist::before,
.btn-compare::before {
	content: none !important;
}
.btn-wishlist .btn-text,
.btn-compare .btn-text {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
}
.btn-wishlist .fa,
.btn-compare .fa {
	font-size: 14px;
	color: rgba(30, 30, 31, .8);
}
.wish-group,
.wishlist-compare {
	display: flex;
	gap: 8px;
}

/* Homepage bestseller grid product-name colour: source sets this via a
   per-module-instance class its own admin generates at runtime (measured live:
   ".module-products-448 .product-grid .product-thumb .name a{color:#000}" on
   one instance, "#1e1e1f" on another sampled instance — genuinely inconsistent
   between its own two copies of this same module, not something to chase
   exactly) which we have no numeric module ID to reproduce. #000/18px matches
   both the more common of those two instances and the main shop grid
   elsewhere on the site, so used here instead of leaving the generic link-blue
   `a{color:#127da8}` showing through (what rendered before this rule existed). */
.ukp-bestseller-grid .product-thumb .name a {
	color: #000;
	font-size: 18px;
}

/* Model line overflows its own card into the next column whenever the
   product's real model name is long enough (e.g. "Thymosin Beta 4 2mg
   (TB500)") — mobile sweep, 2026-10-28, scrape/out/mobile-sweep2/home-5.png.
   Source's own unscoped `.stats-group>span{flex-basis:calc((var(--stats-stack,0px)
   - 100%)*9999)}` is a "stack at this breakpoint" trick driven by a
   --stats-stack custom property that only ever gets a real pixel value from
   a `.main-products-style`-scoped rule — this grid deliberately doesn't
   carry that class (front-page.php: it breaks the column count), so the
   variable is always its 0px fallback, the calc() clamps to a 0% flex-basis,
   and with flex-grow:0 the span never expands to fill the row: it renders
   at literal 0 width with its text visibly overflowing out of that empty
   box instead of wrapping inside it. flex:1 1 auto replaces that broken
   calc() with a normal flex item that actually claims its row's width, so
   the text wraps inside its own column like any ordinary flex child. */
.ukp-bestseller-grid .product-thumb .stats-group > span {
	flex: 1 1 auto;
	min-width: 0;
}
/* Even at its now-correct 167px width, a long real model name ("Thymosin
   Beta 4 2mg (TB500)") still doesn't fit on one line — and .stats has a
   fixed single-line row height (source's own, not overridden here), so
   letting it wrap just bled the second line down into the product name
   below instead. Truncating with an ellipsis is the standard fix for a
   fixed-height grid-card meta row (and matches stat-1/"Stock: In Stock",
   which was already effectively single-line). .stat-2 is itself
   `display:flex` (label span + value span) — text-overflow only does
   anything on the element whose own text is overflowing, so this targets
   the value span specifically, not the flex wrapper around it, and keeps
   the "Model:" label itself always fully visible. */
.ukp-bestseller-grid .product-thumb .stats-group .stat-2 {
	min-width: 0;
}
.ukp-bestseller-grid .product-thumb .stats-group .stat-2 .stats-label {
	flex: 0 0 auto;
}
.ukp-bestseller-grid .product-thumb .stats-group .stat-2 .stats-label + span {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	min-width: 0;
}

/* Homepage bestseller grid column count: a flat, unresponsive 5 columns at
   every viewport (measured) because source.css's own
   ".product-grid.auto-grid .auto-grid-items{(min-width:992px){repeat(5,1fr)}}"
   rule (3 classes, 0,3,0) out-specifies a plain ".ukp-bestseller-grid
   .auto-grid-items" override (2 classes, 0,2,0) — our grid carries both
   ".product-grid.auto-grid" and ".ukp-bestseller-grid" together, so source's
   rule wins at any width ≥992px regardless of load order. Needs
   !important to win. Matched to the shop grid's own measured breakpoints
   instead of guessing (4 cols ≥1536px, 3 cols 1100–1535px, 2 cols below),
   since the owner asked for the homepage to behave the same as the
   already-correct shop page. */
.ukp-bestseller-grid .auto-grid-items {
	grid-template-columns: repeat(2, 1fr) !important;
}
@media (min-width: 1100px) {
	.ukp-bestseller-grid .auto-grid-items {
		grid-template-columns: repeat(3, 1fr) !important;
	}
}
@media (min-width: 1536px) {
	.ukp-bestseller-grid .auto-grid-items {
		grid-template-columns: repeat(4, 1fr) !important;
	}
}

/* "£ 6.00" vs source's solid "£6.00": source.css's real ".price{--price-gap:7px}"
   + ".product-thumb .price > div span{margin:calc(var(--price-gap,0)/2)}" is
   meant to space apart SIBLING price spans (e.g. a struck-through old price next
   to a new one) in source's own OpenCart markup, which is one flat
   <span class="price-normal">. WooCommerce's wc_price() instead nests an inner
   <span class="woocommerce-Price-currencySymbol"> INSIDE the amount span — a
   structure source never had — so that generic "span" selector unintentionally
   catches it too, margining the symbol away from its own digits. Needs higher
   specificity than source's (0,2,2) selector to win; .woocommerce-Price-amount
   is WC's own class, never present in source's markup, so targeting through it
   doesn't risk the sibling-price-span spacing source actually wants elsewhere. */
.product-thumb .price > div .woocommerce-Price-amount .woocommerce-Price-currencySymbol {
	margin: 0;
}

/* Product-card grid stats/description rows: markup added to match the live
   source's .product-thumb .caption exactly (stats, description excerpt).
   Source's own description-hiding rule is scoped to specific grid-type
   classes (confirmed display:none on the shop grid, category grid, and
   search results) but doesn't reach the homepage bestseller grid, which uses
   a different class combination (.ukp-bestseller-grid, not
   .main-products-style) — .description fell back to visible there, showing a
   paragraph of product copy the owner's reference screenshot confirmed
   should never appear on any grid card. Hidden outright, everywhere, rather
   than re-chasing source's per-context selector for a part of the card real
   source itself never actually shows. Rating stars deliberately NOT added:
   measured on 5 live grid cards, .rating.no-rating computes to display:none
   on every one (a more specific selector than source.css's own generic
   ".rating.no-rating{display:flex}" base rule overrides it on this
   particular grid/template) — the real site never shows star ratings on the
   product grid, so adding visible empty stars here would be less accurate
   than source, not more. */
.product-thumb .description {
	display: none;
}

/* "Selling fast" grid badge (ukp_is_selling_fast() in template-helpers.php
   decides which products get it — a measured list, not every card). Source
   gates this badge's actual visual styling (white bg, red border, flame icon)
   behind a per-module-instance selector too (same pattern as everywhere else
   in this file), computed as fully unstyled on the one instance checked — so
   this is built from the owner-supplied reference screenshot instead: white
   background, thin red border, compact red flame + "Selling fast" text,
   top-right of the image, small rounded corners. */
.ukp-selling-fast-badge {
	position: absolute;
	top: 8px;
	right: 8px;
	z-index: 2;
	display: inline-flex;
	align-items: center;
	gap: 5px;
	background: #fff;
	border: 1px solid #f04438;
	border-radius: 4px;
	padding: 3px 8px;
	color: #f04438;
	font-size: 12px;
	font-weight: 600;
	white-space: nowrap;
}
.ukp-selling-fast-badge .fa-fire {
	font-size: 11px;
}

/* Footer: disclaimer box, column headings/links, copyright strip. source.css
   already has a generic ".row-bg{position:absolute;inset:0;z-index:0}" rule —
   footer.php just never rendered the "<div class=row-bg>" each row needs as
   its first child, so the copyright row's own light background (measured
   live: #f4f4f4) never appeared and that whole row rendered on the navy
   background instead, with near-invisible dark-on-navy text. The disclaimer
   box border/background and the column-heading/link colours are gated behind
   per-module-instance classes Journal3's admin generates at runtime (e.g.
   ".module-info_blocks-441 .info-block", ".module-catalog-453 .catalog-title")
   that we have no reproducible ID for — same unreproducible-per-instance
   pattern as the homepage bestseller name colour — so hardcoded here instead
   from real measured values off the live source. */
footer .grid-row-4 .row-bg {
	background-color: #f4f4f4;
}
/* .auto-grid-items is a CSS grid whose real column count source sets via a
   per-instance "--items" custom property (JS/admin-generated, same
   unreproducible pattern as everywhere else) — undefined here, so it falls
   back to source.css's own multi-column default and squeezes this module's
   single disclaimer item into one of several equal slices (measured: 312px of
   a 985px row) instead of the full width. This module only ever has the one
   item, so forcing a single column is always correct here, not a guess. */
footer .info_blocks-grid .auto-grid-items {
	grid-template-columns: 1fr;
}
footer .grid-row-2 .info-block {
	border: 1px solid #fff;
	border-radius: 8px;
	padding: 36px 8px;
	background: #222c6d;
	width: 100%;
	max-width: 985px;
	margin: 0 auto;
	box-sizing: border-box;
	flex-direction: column;
}
footer .info-block-title,
footer .info-block-text {
	color: #fff;
}
footer .grid-row-4 .info-block-text {
	color: #697278;
}
footer .catalog-title {
	color: #f5f7f8;
	font-family: 'Poppins', 'Helvetica Neue', Helvetica, Arial, sans-serif;
	font-weight: 600;
	font-size: 18px;
}
/* Newsletter column heading rendered black (the generic unscoped `.title`
   default) instead of matching the other three footer column headings
   above (About Us/My Account/Customer Service, all .catalog-title, already
   fixed white above) — near-invisible against the navy footer background
   (mobile sweep, 2026-10-28, scrape/out/mobile-sweep2/home-6.png). Source's
   real per-instance rule is `.module-newsletter-67 .module-title{color:
   rgba(245,247,248,1)}` (confirmed present in the harvested source.css) —
   not added as a class here because that same instance selector also
   restyles the Subscribe button with source's own dead icomoon glyph
   (`.module-newsletter-67 .btn:before{content:'\ea18';font-family:icomoon}`),
   exactly the "missing glyph" bug this button was already fixed to avoid
   (see the real-FA-icon note below) — just the real colour value instead,
   same hardcoded-from-measured-source pattern as .catalog-title above. */
footer .module-newsletter .title {
	color: #f5f7f8;
}
footer .subitem a {
	color: #f5f7f8;
}
/* Newsletter "Subscribe" button: source's own is icon-only (empty <span>, icon
   via an unreproducible per-instance icomoon glyph, same substitution policy
   as the header/product-card icons) — ours now matches with a real FA icon
   instead of a text label the source never shows. Also needs the same
   dead-icomoon-font "missing glyph" box suppressed as the search/wishlist/
   compare buttons, or it shows twice. */
footer .newsletter-form .btn-primary {
	display: flex;
	align-items: center;
	justify-content: center;
}
footer .newsletter-form .btn-primary::before {
	content: none !important;
}

/* Cart page (woocommerce/cart/cart.php): full override of WooCommerce's
   default single-column stacked layout, rebuilt to match source's real
   two-column page (table + "what would you like to do next" sidebar). All
   values below are measured directly off the live source with items in
   the cart (scrape/measure-cart-page-styles2.mjs), not estimated. */
.ukp-cart-layout {
	display: flex;
	align-items: flex-start;
	gap: 32px;
	flex-wrap: wrap;
}
.ukp-cart-table-form {
	flex: 1 1 600px;
	min-width: 0;
}
.ukp-cart-table-wrapper {
	overflow-x: auto;
}
.ukp-cart-table {
	width: 100%;
	border-collapse: collapse;
	background: #fff;
}
.ukp-cart-table th,
.ukp-cart-table td {
	border: 1px solid #e0e2e6;
}
.ukp-cart-table thead td {
	padding: 12px;
	font-size: 14px;
	color: #1e1e1f;
	background: #f7f7f8;
	text-align: center;
}
.ukp-cart-table .ukp-td-name {
	text-align: left;
}
.ukp-cart-table tbody td {
	padding: 12px;
	font-size: 14px;
	color: #1e1e1f;
	text-align: center;
	vertical-align: middle;
}
.ukp-cart-table .ukp-td-name {
	font-size: 13px;
}
.ukp-cart-table .ukp-td-name a {
	color: #000;
}
.ukp-cart-table .ukp-td-image img {
	width: 64px;
	height: 64px;
	object-fit: cover;
	border: 1px solid #e0e2e6;
	border-radius: 4px;
}
.ukp-stepper-group {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	flex-wrap: wrap;
}
.ukp-stepper {
	display: flex;
	align-items: center;
	border: 1px solid #e0e2e6;
	border-radius: 4px;
	height: 36px;
	overflow: hidden;
}
.ukp-stepper-down,
.ukp-stepper-up {
	width: 34px;
	height: 100%;
	border: 0;
	background: #fff;
	color: #1e1e1f;
	font-size: 15px;
	cursor: pointer;
}
.ukp-stepper-input {
	width: 40px;
	height: 100%;
	border: 0;
	border-left: 1px solid #e0e2e6;
	border-right: 1px solid #e0e2e6;
	text-align: center;
	font-size: 13px;
}
.ukp-btn-update,
.ukp-btn-remove {
	width: 38px;
	height: 38px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: 4px;
	font-size: 14px;
	flex-shrink: 0;
}
.ukp-btn-update {
	background: transparent;
	border: 1px solid rgba(30, 30, 31, .5);
	color: #1e1e1f;
}
.ukp-btn-remove {
	background: #d55e6f;
	border: 0;
	color: rgba(255, 255, 255, .9);
	text-decoration: none;
}
/* Same dead-icomoon-font "missing glyph" issue as the search/wishlist/compare/
   newsletter buttons above, but these two icons never had a real FontAwesome
   icon showing underneath to fall back on — the element's own .fa rule (font:
   FontAwesome) wasn't matching either, only the icomoon ::before was, so
   suppressing icomoon alone left both buttons blank. Setting the real
   FontAwesome glyph + font directly bypasses whatever's blocking the base
   .fa rule, rather than chasing that separately. */
.ukp-btn-update em::before,
.ukp-btn-remove em::before {
	font-family: FontAwesome !important;
	speak: none;
	font-style: normal;
	font-weight: 400;
}
.ukp-btn-update em::before {
	content: "\f021" !important;
	color: #1e1e1f;
}
.ukp-btn-remove em::before {
	content: "\f057" !important;
	color: rgba(255, 255, 255, .9);
}

.ukp-cart-sidebar {
	flex: 0 0 380px;
	max-width: 100%;
	background: #e9ebed;
	border-radius: 4px;
	padding: 36px;
	box-sizing: border-box;
}
.ukp-cart-sidebar-title {
	margin: 0 0 8px;
	font-size: 18px;
}
.ukp-cart-sidebar-intro {
	margin: 0 0 16px;
	font-size: 14px;
	color: #475467;
}
.ukp-accordion-item {
	border-bottom: 1px solid #d0d5dd;
}
.ukp-accordion-toggle {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
	background: none;
	border: 0;
	padding: 18px 0;
	font-size: 15px;
	color: #1e1e1f;
	text-align: left;
	cursor: pointer;
}
.ukp-accordion-toggle .fa-caret-down {
	transition: transform .2s ease;
}
.ukp-accordion-toggle[aria-expanded="true"] .fa-caret-down {
	transform: rotate(180deg);
}
.ukp-accordion-body {
	padding: 0 0 18px;
}
.ukp-coupon-form {
	display: flex;
	gap: 8px;
}
.ukp-coupon-input {
	flex: 1;
	min-width: 0;
	padding: 10px 12px;
	border: 1px solid #d0d5dd;
	border-radius: 4px;
	font-size: 14px;
}
.ukp-coupon-apply {
	flex-shrink: 0;
	padding: 10px 16px;
	background: #2b3788;
	color: #fff;
	border: 0;
	border-radius: 4px;
	font-size: 13px;
	cursor: pointer;
}
.ukp-shipping-estimate .shipping-calculator-button {
	display: none;
}
.ukp-shipping-estimate .shipping-calculator-form {
	display: block !important;
}
.ukp-shipping-estimate select,
.ukp-shipping-estimate input[type="text"] {
	width: 100%;
	padding: 8px 10px;
	border: 1px solid #d0d5dd;
	border-radius: 4px;
	margin-top: 4px;
	box-sizing: border-box;
}
.ukp-shipping-estimate .form-row {
	margin-bottom: 12px;
}
.ukp-shipping-estimate button[type="submit"] {
	padding: 10px 16px;
	background: #2b3788;
	color: #fff;
	border: 0;
	border-radius: 4px;
	font-size: 13px;
	cursor: pointer;
}

.ukp-cart-totals-table {
	width: 100%;
	border-collapse: collapse;
	background: #fff;
	margin-top: 10px;
}
.ukp-cart-totals-table td {
	padding: 10px 12px;
	font-size: 14px;
	text-align: right;
	border: 1px solid #e0e2e6;
}
.ukp-cart-totals-table .ukp-total-label {
	font-weight: 700;
}

.ukp-cart-upsell {
	background: #fff;
	border: 1px solid #ddd;
	border-radius: 4px;
	padding: 20px;
	margin-top: 16px;
}
.ukp-cart-upsell-head {
	font-size: 15px;
	font-weight: 700;
	margin-bottom: 12px;
	padding-bottom: 10px;
	border-bottom: 1px solid #eee;
}
.ukp-cart-upsell-head .fa-plus-circle {
	color: #5cb85c;
	margin-right: 8px;
}
.ukp-cart-upsell-intro {
	color: #666;
	font-size: 13px;
	margin: 0 0 15px;
}
.ukp-cart-upsell-items {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
}
.ukp-cart-upsell-item {
	flex: 1;
	min-width: 220px;
	border: 1px solid #eee;
	border-radius: 4px;
	padding: 14px;
	display: flex;
	align-items: center;
	gap: 12px;
}
.ukp-cart-upsell-item .fa {
	font-size: 24px;
	flex-shrink: 0;
}
.ukp-cart-upsell-item-text {
	flex: 1;
	min-width: 0;
}
.ukp-cart-upsell-item-name {
	font-weight: 700;
	font-size: 13px;
}
.ukp-cart-upsell-item-blurb {
	color: #888;
	font-size: 12px;
	margin-top: 2px;
}
.ukp-cart-upsell-add {
	flex-shrink: 0;
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 6px 12px;
	background: #5cb85c;
	color: #fff;
	border-radius: 4px;
	font-size: 13px;
	text-decoration: none;
	border: 0;
	cursor: pointer;
}

.ukp-cart-sidebar-buttons {
	display: flex;
	flex-direction: column;
	gap: 8px;
	margin-top: 16px;
}
.ukp-cart-sidebar-buttons a {
	display: block;
	width: 100%;
	box-sizing: border-box;
	text-align: center;
	padding: 14px;
	border-radius: 8px;
	font-size: 14px;
	text-decoration: none;
}
.ukp-btn-continue {
	background: #fff;
	border: 1px solid rgba(30, 30, 31, .5);
	color: #1e1e1f;
}
.ukp-btn-checkout {
	background: #2b3788;
	border: 0;
	color: #fff;
}
@media (max-width: 991px) {
	.ukp-cart-sidebar {
		flex: 1 1 100%;
	}
}
