/**
 * Product archive — Discount Pet Food
 *
 * Covers the Loop Grid's "Load More" control on category and shop archives.
 *
 * Why this file exists: the archive template's pagination was switched from
 * numbered pages to Load More, because 9 products in a 4-column grid left a
 * final row with three empty cells, and that blank band read as "out of stock"
 * even though 33 further pages existed. (The old numbered pagination also
 * capped at 5 linked pages, so most of a large category was unreachable by
 * clicking at all.)
 *
 * Elementor renders the button with its kit defaults — #61ce70, Roboto, 3px
 * radius — which belongs to no part of this design. Restyled here to the same
 * pill vocabulary as the header and mini cart.
 *
 * Tokens come from header.css, which is enqueued globally.
 */

/*
 * Spacing around the button.
 *
 * The top margin has to go through Elementor's variable, not a margin-top
 * declaration. Elementor sets it at
 *   .elementor-widget-loop-grid > .elementor-widget-container > .elementor-button-wrapper
 * which is (0,3,0) and loads after this file, and .e-loop__load-more carries
 * .elementor-button-wrapper too — so a plain margin-top here is silently
 * dropped. Note the variable name contains an em-dash (U+2014) rather than a
 * hyphen; that is a typo in Elementor's own stylesheet, but it is the real
 * name, so it has to be reproduced exactly.
 *
 * Nothing in Elementor sets a bottom margin, so that one is a normal rule.
 * Without it the button sat 10px off the dark footer band.
 */
.elementor-widget-loop-grid {
	--load-more—spacing: 40px;
	--load-more-message-color: var(--dpf-muted);
}

.elementor-widget-loop-grid > .elementor-widget-container > .e-loop__load-more,
.elementor-widget-loop-grid > .e-loop__load-more {
	margin-bottom: 64px;
	text-align: center;
}

/*
 * (0,3,0). Elementor's kit writes .elementor-button at a lower specificity, so
 * this clears it without !important. The widget has no per-element button
 * styles set, which is what makes that possible — if someone later sets them
 * in the editor, Elementor's (0,3,0)+ per-element rule will win and this file
 * will quietly stop applying. Style it here or there, not both.
 */
.elementor-widget-loop-grid .e-loop__load-more .elementor-button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	min-height: 52px;
	min-width: 240px;
	padding: 0 32px;
	border: 2px solid var(--dpf-green);
	border-radius: 999px;
	background-color: #fff;
	color: var(--dpf-green);
	/* The generic fallback matters: `Montserrat` on its own drops to the
	   browser default serif whenever the webfont fails to load. */
	font-family: "Montserrat", Sans-serif;
	font-size: 16px;
	font-weight: 700;
	line-height: 1.2;
	text-decoration: none;
	cursor: pointer;
	transition: background-color var(--dpf-speed) ease, color var(--dpf-speed) ease;
}

.elementor-widget-loop-grid .e-loop__load-more .elementor-button:hover {
	background-color: var(--dpf-green);
	color: #fff;
}

.elementor-widget-loop-grid .e-loop__load-more .elementor-button:active {
	transform: translateY(1px);
}

.elementor-widget-loop-grid .e-loop__load-more .elementor-button:focus,
.elementor-widget-loop-grid .e-loop__load-more .elementor-button:focus-visible {
	outline: 3px solid var(--dpf-green-mid);
	outline-offset: 3px;
}

.elementor-widget-loop-grid .e-loop__load-more .elementor-button:focus:not(:focus-visible) {
	outline: 0;
}

/* Elementor toggles this span while a batch is in flight. Keep the label and
   the spinner on one line so the button does not change width mid-load. */
.elementor-widget-loop-grid .e-loop__load-more .e-load-more-spinner {
	display: none;
}

.elementor-widget-loop-grid .e-loop__load-more .elementor-button[aria-disabled="true"] .e-load-more-spinner,
.elementor-widget-loop-grid .e-loop__load-more .elementor-button.e-loading .e-load-more-spinner {
	display: inline-flex;
}

/*
 * End-of-results message, revealed by Elementor adding
 * .e-load-more-pagination-end once nothing is left to load.
 *
 * The colour has to go through the custom property, not a colour declaration.
 * Elementor styles this at
 *   .elementor-widget-loop-grid > .elementor-widget-container .e-load-more-message
 * which is (0,3,0) and loads after this file, so a colour here is dropped —
 * and because --load-more-message-color is undefined, that rule resolves to
 * invalid-at-computed-value-time and the text inherits black from the page.
 * Declaring the variable sidesteps the cascade entirely.
 */
.elementor-widget-loop-grid .e-load-more-message {
	margin-bottom: 64px;
	font-family: "Montserrat", Sans-serif;
	font-size: 15px;
	text-align: center;
}

@media (prefers-reduced-motion: reduce) {
	.elementor-widget-loop-grid .e-loop__load-more .elementor-button {
		transition: none;
	}

	.elementor-widget-loop-grid .e-loop__load-more .elementor-button:active {
		transform: none;
	}
}

/* ------------------------------------------------------- bulk pricing */

/*
 * "Buy 6+ £4.77 each — save 29%" under the price on product cards.
 *
 * Bulk buying is a core part of this business but was invisible on archives:
 * the pricing plugin renders nothing in the loop, and the Elementor product
 * card is only image/title/price/button. The badge is appended to the price
 * HTML in inc/bulk-pricing.php.
 *
 * Yellow rather than green: the card is already dense with green (title link,
 * price, View Product button), so another green element would disappear into
 * it. The notice band uses the same yellow, so this reads as "pay attention"
 * in a vocabulary the site already has.
 */
.dpf-bulk-badge {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: center;
	gap: 6px;
	margin-top: 8px;
	/* The price sits inside a heading-ish context; reset so the badge is not
	   dragged into the price's size or weight. */
	font-family: "Montserrat", Sans-serif;
	font-size: 12px;
	font-weight: 600;
	line-height: 1.3;
	text-align: center;
	/* Prices are often wrapped in <del>/<ins> or a strikethrough on sale. */
	text-decoration: none;
}

.dpf-bulk-badge__qty {
	padding: 2px 8px;
	border-radius: 999px;
	background: var(--dpf-yellow);
	color: var(--dpf-ink);
	font-weight: 700;
	white-space: nowrap;
}

.dpf-bulk-badge__save {
	color: var(--dpf-muted);
	font-weight: 600;
}

/* On a 2-column phone grid the full sentence wraps awkwardly next to a
   68px-ish card width, so drop to the pill plus the saving only. */
@media (max-width: 480px) {
	.dpf-bulk-badge {
		gap: 4px;
		font-size: 11px;
	}
}

/*
 * Bulk pricing banner, under the category heading.
 *
 * Deliberately a quiet band rather than a loud callout: it appears on every
 * category page, so anything shoutier would become wallpaper within two clicks.
 * It names the yellow label so the badge on the cards below is recognisable.
 */
.dpf-bulk-note {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 8px;
	margin: 0 0 4px;
	padding: 10px 14px;
	border-radius: 10px;
	background: #f4f8f5;
	font-family: "Montserrat", Sans-serif;
	font-size: 14px;
	line-height: 1.4;
}

.dpf-bulk-note__title {
	flex: none;
	padding: 3px 10px;
	border-radius: 999px;
	background: var(--dpf-yellow);
	color: var(--dpf-ink);
	font-size: 13px;
	font-weight: 700;
}

.dpf-bulk-note__body {
	color: var(--dpf-ink);
	font-weight: 500;
}

@media (max-width: 480px) {
	.dpf-bulk-note {
		font-size: 13px;
	}
}

/* ------------------------------------------------------- product cards */

/*
 * The loop card was four widgets floating on the page background: no surface,
 * no border, nothing tying a photo to its own title and price. Worse, Elementor
 * sets --justify-content:flex-end on the card's container, which pushes all
 * four to the bottom and opens a tall empty band above every product — the same
 * "is anything even here?" effect the pagination fix was about.
 *
 * Overrides here go through Elementor's container variables rather than the
 * layout properties, because it writes those at
 *   .elementor-940392 .elementor-element.elementor-element-a6fbded
 * which is (0,3,0). The selectors below reach (0,4,0) by doubling .e-con
 * instead of naming that generated element id, so they survive the loop
 * template being rebuilt or duplicated.
 */

/* Gaps were sized for cards with no edges. With a surface they can close up. */
.elementor-widget-loop-grid .elementor-loop-container {
	--grid-row-gap: 28px;
	--grid-column-gap: 24px;
}

/* The card surface. Relative so the stretched link below can cover it. */
.elementor-loop-container > .e-loop-item {
	position: relative;
	display: flex;
	background: #fff;
	border: 1px solid var(--dpf-line);
	border-radius: 14px;
	overflow: hidden;
	transition: border-color var(--dpf-speed) ease, box-shadow var(--dpf-speed) ease, transform var(--dpf-speed) ease;
}

.elementor-loop-container > .e-loop-item:hover {
	border-color: var(--dpf-green-mid);
	box-shadow: 0 10px 24px -14px rgba(0, 40, 24, 0.45);
	transform: translateY(-2px);
}

/* Content starts at the top; the button is pushed down separately below, so
   the card reads image -> name -> price -> action with no floating band. */
.elementor-loop-container > .e-loop-item > .e-con.e-con {
	--justify-content: flex-start;
	--padding-top: 14px;
	--padding-bottom: 16px;
	--padding-left: 14px;
	--padding-right: 14px;
	/* Elementor resolves the gap as `var(--row-gap) var(--column-gap)`;
	   setting --gap alone does nothing. */
	--row-gap: 10px;
	--column-gap: 10px;
	width: 100%;
}

/*
 * Photo box.
 *
 * Fixed square regardless of the file's own proportions: the catalogue mixes
 * 300x341 and 300x300 originals, and left to themselves those give every card
 * a different image height, so titles and prices stop lining up across a row.
 * `contain` rather than `cover` because these are products on white — cropping
 * to fill would slice the edges off bags and tins.
 *
 * The box is sized explicitly so a missing image cannot collapse the row.
 */
.elementor-loop-container > .e-loop-item .elementor-widget-theme-post-featured-image {
	width: 100%;
}

/*
 * The square is held by the CONTAINER, not the <img>.
 *
 * Sizing the image itself looked right until a product whose file was missing:
 * a broken <img> has no intrinsic size, `width:100%` does not resolve against
 * it, and the card collapsed to a 22px icon with a tall empty gap beneath.
 * Three of the first four products on this archive did exactly that. Putting
 * aspect-ratio on the wrapper means the box exists whether or not the file
 * loads, so one bad image can no longer wreck the row.
 *
 * It sits inside the card padding rather than bleeding to the edge, because
 * Elementor's base CSS gives `.e-con-inner` `padding-inline: 0` and a
 * full-bleed image would mean negative margins fighting a rule that is not
 * ours.
 */
.elementor-loop-container > .e-loop-item .elementor-widget-theme-post-featured-image .elementor-widget-container {
	aspect-ratio: 1 / 1;
	overflow: hidden;
	border: 1px solid var(--dpf-line);
	border-radius: 10px;
	background: #f7faf8;
}

.elementor-loop-container > .e-loop-item .elementor-widget-theme-post-featured-image .elementor-widget-container > a {
	display: block;
	width: 100%;
	height: 100%;
}

.elementor-loop-container > .e-loop-item .elementor-widget-theme-post-featured-image img {
	display: block;
	width: 100%;
	height: 100%;
	padding: 10px;
	object-fit: contain;
}

/* Two lines for every title, so the price sits on the same baseline across a
   row whether the name is short or long. */
.elementor-loop-container > .e-loop-item .elementor-widget-woocommerce-product-title {
	width: 100%;
}

.elementor-loop-container > .e-loop-item .elementor-widget-woocommerce-product-title h2,
.elementor-loop-container > .e-loop-item .elementor-widget-woocommerce-product-title h3,
.elementor-loop-container > .e-loop-item .elementor-widget-woocommerce-product-title .elementor-heading-title {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	min-height: 2.6em;
	margin: 0;
	font-size: 15px;
	line-height: 1.3;
}

/* The action sits on the card floor whatever the title did above it. */
.elementor-loop-container > .e-loop-item .elementor-widget-button {
	width: 100%;
	margin-top: auto;
}

.elementor-loop-container > .e-loop-item .elementor-widget-button .elementor-button {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	min-height: 44px;
	border-radius: 999px;
	font-family: "Montserrat", Sans-serif;
	font-size: 14px;
	font-weight: 700;
}

/*
 * MAKE THE WHOLE CARD CLICKABLE
 *
 * The card lifts and greens its border on hover, but measured, only 52% of it
 * actually did anything: the image (3-53% down) and the button (87-96%) are
 * links, while the title, price and bulk badge between them were dead. The
 * title is not a link at all. So the hover was promising a target that was not
 * there through the middle third of every card.
 *
 * Rather than drop the hover, the image's own link is stretched over the card.
 * Both existing links already point at the same product URL, so nothing new is
 * introduced; the image link is the one chosen because its accessible name
 * comes from the img alt, which is the product name — stretching the button
 * instead would announce every card as "View Product".
 */
/*
 * The card must be the overlay's containing block. Elementor gives both its
 * containers and its widgets position:relative, so without this the overlay
 * anchors to the image widget and covers only the photo — measured at 47%
 * coverage, barely different from the 52% it was meant to fix.
 */
.elementor-loop-container > .e-loop-item > .e-con,
.elementor-loop-container > .e-loop-item > .e-con > .e-con-inner,
.elementor-loop-container > .e-loop-item .elementor-widget-theme-post-featured-image,
.elementor-loop-container > .e-loop-item .elementor-widget-theme-post-featured-image .elementor-widget-container {
	position: static;
}

.elementor-loop-container > .e-loop-item .elementor-widget-theme-post-featured-image a::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}

/*
 * The button is lifted above that overlay so it keeps its own hover, its own
 * focus ring and its own click. Without this the overlay would swallow the
 * pointer and the button would go inert-looking even though the card still
 * navigated.
 */
.elementor-loop-container > .e-loop-item .elementor-widget-button {
	position: relative;
	z-index: 2;
}

/* Keyboard focus lands on the stretched link, so draw the ring on the overlay
   — that outlines the whole card rather than just the photo. */
.elementor-loop-container > .e-loop-item .elementor-widget-theme-post-featured-image a:focus-visible {
	outline: 0;
}

.elementor-loop-container > .e-loop-item .elementor-widget-theme-post-featured-image a:focus-visible::after {
	outline: 3px solid var(--dpf-green-mid);
	outline-offset: -3px;
	border-radius: 14px;
}

/* The whole card is a link target in practice, so give the button a ring that
   is visible against the new surface. */
.elementor-loop-container > .e-loop-item .elementor-button:focus,
.elementor-loop-container > .e-loop-item .elementor-button:focus-visible,
.elementor-loop-container > .e-loop-item a:focus-visible {
	outline: 3px solid var(--dpf-green-mid);
	outline-offset: 2px;
}

.elementor-loop-container > .e-loop-item .elementor-button:focus:not(:focus-visible),
.elementor-loop-container > .e-loop-item a:focus:not(:focus-visible) {
	outline: 0;
}

@media (max-width: 480px) {
	.elementor-widget-loop-grid .elementor-loop-container {
		--grid-row-gap: 18px;
		--grid-column-gap: 14px;
	}

	.elementor-loop-container > .e-loop-item > .e-con.e-con {
		--padding-top: 10px;
		--padding-left: 10px;
		--padding-right: 10px;
		--padding-bottom: 12px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.elementor-loop-container > .e-loop-item,
	.elementor-loop-container > .e-loop-item:hover {
		transition: none;
		transform: none;
	}
}
