/* ==========================================================================
   Zoonum Products Archive — Frontend Base Layout
   Structure only. Visual styling lives in presets.css.
   ========================================================================== */

.zpa-archive {
	position: relative;
	width: 100%;
	box-sizing: border-box;
}

.zpa-archive *,
.zpa-archive *::before,
.zpa-archive *::after {
	box-sizing: border-box;
}

/* --- Controls (search + pills) ------------------------------------------- */
.zpa-controls {
	display: flex;
	flex-direction: column;
	gap: 14px;
	margin-bottom: 28px;
}

.zpa-archive.zpa-layout-split .zpa-controls {
	flex-direction: row;
	align-items: center;
	gap: 20px;
	flex-wrap: wrap;
}

.zpa-archive.zpa-layout-split .zpa-search {
	flex: 0 1 320px;
	min-width: 220px;
}

.zpa-archive.zpa-layout-split .zpa-pills {
	flex: 1 1 auto;
	justify-content: flex-end;
}

@media (max-width: 720px) {
	.zpa-archive.zpa-layout-split .zpa-controls {
		flex-direction: column;
		align-items: stretch;
	}
	.zpa-archive.zpa-layout-split .zpa-pills {
		justify-content: flex-start;
	}
}

/* --- Search bar ---------------------------------------------------------- */
.zpa-search {
	position: relative;
	display: flex;
	align-items: center;
}

.zpa-search-icon {
	position: absolute;
	left: 14px;
	top: 50%;
	transform: translateY(-50%);
	pointer-events: none;
	opacity: 0.6;
}

.zpa-search-input {
	width: 100%;
	padding: 12px 40px 12px 44px;
	font: inherit;
	/* 16px is the magic threshold: iOS Safari auto-zooms when focusing an
	   input with font-size < 16px. Setting it to exactly 16px keeps the
	   layout calm on mobile without changing the visual weight much. */
	font-size: 16px;
	border: 1px solid #d4d4d8;
	border-radius: 8px;
	background: #fff;
	color: inherit;
	outline: none;
	transition: border-color 0.15s, box-shadow 0.15s;
}

.zpa-search-input:focus {
	border-color: #4f46e5;
	box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15);
}

.zpa-search-clear {
	position: absolute;
	right: 10px;
	top: 50%;
	transform: translateY(-50%);
	width: 24px;
	height: 24px;
	border: none;
	background: transparent;
	cursor: pointer;
	font-size: 22px;
	line-height: 1;
	color: inherit;
	opacity: 0.5;
	padding: 0;
}

.zpa-search-clear:hover {
	opacity: 1;
}

/* --- Pills --------------------------------------------------------------- */
.zpa-pills {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	align-items: center;
}

.zpa-pill {
	display: inline-flex;
	align-items: center;
	padding: 8px 16px;
	font: inherit;
	font-size: 14px;
	font-weight: 500;
	line-height: 1;
	border: 1px solid #d4d4d8;
	border-radius: 999px;
	background: #fff;
	color: inherit;
	cursor: pointer;
	transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.15s;
	white-space: nowrap;
}

.zpa-pill:hover {
	border-color: #71717a;
}

.zpa-pill-active {
	background: #18181b;
	border-color: #18181b;
	color: #fff;
}

.zpa-pill:focus-visible {
	outline: 2px solid #4f46e5;
	outline-offset: 2px;
}

/* --- Product Grid -------------------------------------------------------- */
.zpa-results-region {
	position: relative;
	min-height: 200px;
}

.zpa-grid {
	display: grid;
	/* Desktop default: use --zpa-cols. Fallback to 4 if the inline style is
	   somehow stripped (caching plugin, custom field minifier). */
	grid-template-columns: repeat(var(--zpa-cols, 4), minmax(0, 1fr));
	gap: 24px;
	margin: 0;
	padding: 0;
}

/* Tablet — 721 to 1024px viewport. Reads --zpa-cols-tablet, which is set
   inline on the .zpa-grid by the shortcode. Lets the site owner pick e.g.
   3 columns on tablet even if desktop is 4 and mobile is 2. */
@media (max-width: 1024px) {
	.zpa-grid {
		grid-template-columns: repeat(var(--zpa-cols-tablet, 3), minmax(0, 1fr));
	}
}

/* Mobile — ≤720px viewport. Reads --zpa-cols-mobile. Gap shrinks to 16px
   so 2-column phone layouts don't waste horizontal space. */
@media (max-width: 720px) {
	.zpa-grid {
		grid-template-columns: repeat(var(--zpa-cols-mobile, 2), minmax(0, 1fr));
		gap: 16px;
	}
}

/* Tiny screens (≤420px) only force single-column IF the configured mobile
   count is 2 or higher AND the user explicitly didn't ask for stacked.
   Most products under 200px wide become unreadable on iPhone SE-class
   devices, so 2→1 is a sane safety override. If they picked 1 column
   mobile they already get it. */
@media (max-width: 420px) {
	.zpa-grid {
		grid-template-columns: repeat(min(var(--zpa-cols-mobile, 2), 2), minmax(0, 1fr));
	}
}

/* --- Product Card -------------------------------------------------------- */
.zpa-product-card {
	display: flex;
	flex-direction: column;
	/* height:100% guarantees the card fills its grid cell. Grid items default
	   to align-items:stretch, but some themes or media queries override that
	   and break "all cards in a row are the same height" — which is the only
	   way `margin-top: auto` on the button reliably anchors to the bottom
	   when the row has mixed-height content (1-line vs 3-line titles). */
	height: 100%;
	border-radius: 10px;
	overflow: hidden;
	background: #fff;
	transition: transform 0.2s, box-shadow 0.2s;
	position: relative;
	/* The whole card is clickable via JS (navigates to single product page) —
	   show the pointer cursor so users get the affordance. The actual <a>
	   children (image, title) still use their own cursors when hovered. */
	cursor: pointer;
}

.zpa-product-image {
	display: block;
	position: relative;
	aspect-ratio: 1 / 1;
	overflow: hidden;
	background: #f4f4f5;
	text-decoration: none;
}

.zpa-product-image img,
.zpa-product-image .zpa-product-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform 0.4s ease;
}

.zpa-product-card:hover .zpa-product-img {
	transform: scale(1.04);
}

.zpa-badge {
	position: absolute;
	top: 12px;
	left: 12px;
	padding: 4px 10px;
	font-size: 11px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	border-radius: 4px;
	background: #18181b;
	color: #fff;
	z-index: 2;
}

.zpa-badge-sale {
	background: #f97316;
}

/* Lightning emoji prepended via CSS so the PHP doesn't need to change.
   Why ::before instead of editing the PHP template: keeps the "Sale"
   text translatable (translators don't see the emoji), keeps presentation
   in the stylesheet, and one rule covers every preset. */
.zpa-badge-sale::before {
	content: "⚡";
	margin-right: 4px;
	display: inline-block;
}

/* Out-of-stock OVERLAY — covers the full image with a backdrop blur and
   centers "OUT OF STOCK" white text. Not a corner pill — see the original
   markup, this is the same <span class="zpa-badge zpa-badge-oos">, but
   the OOS variant overrides the pill defaults to fill its positioned
   parent (.zpa-product-image, which is position:relative) edge-to-edge. */
.zpa-badge-oos {
	/* Reset corner-pill positioning so the overlay fills the whole image. */
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	inset: 0;

	/* Flex-center the "Out of stock" text. */
	display: flex;
	align-items: center;
	justify-content: center;

	/* Blurred dark wash over whatever sits behind it (the product image). */
	background: rgba(0, 0, 0, 0.5);
	backdrop-filter: blur(6px);
	-webkit-backdrop-filter: blur(6px);

	/* Typography — white, uppercase, spaced out. */
	color: #fff;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: 0.18em;
	text-transform: uppercase;

	/* Wipe the pill defaults inherited from .zpa-badge. */
	padding: 0;
	border-radius: 0;
	border: none;

	/* Below the sale pill so both can coexist on an OOS-and-on-sale product. */
	z-index: 3;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SALE ACCENTS — high-conversion "specialty" product treatment
   ---------------------------------------------------------------------------
   Applied to cards carrying .zpa-accent plus one .zpa-accent-fx-{effect}
   class. Every effect drives an animated border + glow on the card. The
   patriot-mist effect additionally renders a .zpa-accent-mist drifting layer.

   Speed is controlled by --zpa-accent-speed (default 3s) so the accent
   custom-CSS box can retune every effect with a single variable.

   Performance notes:
   - We animate a pseudo-element's opacity/filter and a box-shadow, both of
     which the compositor can handle without triggering layout. No animating
     of width/top/left anywhere here.
   - The border color cycle uses `border-color` (cheap: paint only).
   ═══════════════════════════════════════════════════════════════════════════ */

.zpa-archive .zpa-product-card.zpa-accent {
	--zpa-accent-speed: 3s;
	/* The visible ring is driven by box-shadow (see per-effect rules below),
	   NOT a pseudo-element. box-shadow renders OUTSIDE the border box and is
	   immune to the card's own `overflow: hidden`, so it can never be clipped
	   or buried behind the card's opaque background — which is exactly what
	   went wrong with the earlier ::before-glow approach. */
	position: relative;
	z-index: 1;
	border-style: solid !important;
	border-width: 2px !important;
	/* Kill any inherited box-shadow/border-color transition so it doesn't
	   fight the keyframe animation and cause visible stutter. The animation
	   drives box-shadow directly, frame by frame. */
	transition: transform 0.2s !important;
	/* IMPORTANT: no `isolation: isolate` and no negative-z pseudo here. Both
	   trapped the glow inside the card's stacking context, hiding it. */
}

/* Reduced-motion: freeze the pulse but KEEP a static colored ring so the
   spotlight still reads. Each effect defines its own static fallback shadow. */
@media (prefers-reduced-motion: reduce) {
	.zpa-archive .zpa-product-card.zpa-accent,
	.zpa-archive .zpa-accent-mist {
		animation: none !important;
	}
}

/* ── Effect: Pulsating Rainbow ─────────────────────────────────────────────
   Border hue cycles the full wheel; the box-shadow ring pulses in the same
   hue. box-shadow (not a pseudo) = always visible outside the card. */
.zpa-archive .zpa-product-card.zpa-accent-fx-rainbow {
	animation: zpa-accent-rainbow var(--zpa-accent-speed) linear infinite;
}
@keyframes zpa-accent-rainbow {
	0%   { border-color: #ff0040; box-shadow: 0 0 0 2px rgba(255,0,64,0.55),   0 0 18px 4px rgba(255,0,64,0.65); }
	16%  { border-color: #ff8c00; box-shadow: 0 0 0 2px rgba(255,140,0,0.55),  0 0 18px 4px rgba(255,140,0,0.65); }
	33%  { border-color: #ffe600; box-shadow: 0 0 0 2px rgba(255,230,0,0.55),  0 0 18px 4px rgba(255,230,0,0.65); }
	50%  { border-color: #00e05a; box-shadow: 0 0 0 2px rgba(0,224,90,0.55),   0 0 18px 4px rgba(0,224,90,0.65); }
	66%  { border-color: #00c3ff; box-shadow: 0 0 0 2px rgba(0,195,255,0.55),  0 0 18px 4px rgba(0,195,255,0.65); }
	83%  { border-color: #b64bff; box-shadow: 0 0 0 2px rgba(182,75,255,0.55), 0 0 18px 4px rgba(182,75,255,0.65); }
	100% { border-color: #ff0040; box-shadow: 0 0 0 2px rgba(255,0,64,0.55),   0 0 18px 4px rgba(255,0,64,0.65); }
}

/* ── Effect: Pulsating Red / White / Blue ──────────────────────────────────
   Border + ring step R → W → B. Crisp, flag-like, no rotation. */
.zpa-archive .zpa-product-card.zpa-accent-fx-patriot {
	animation: zpa-accent-patriot var(--zpa-accent-speed) ease-in-out infinite;
}
@keyframes zpa-accent-patriot {
	0%, 100% { border-color: #b22234; box-shadow: 0 0 0 2px rgba(178,34,52,0.6),  0 0 20px 5px rgba(178,34,52,0.7); }   /* Old Glory Red */
	33%      { border-color: #ffffff; box-shadow: 0 0 0 2px rgba(255,255,255,0.7), 0 0 20px 5px rgba(255,255,255,0.6); } /* White */
	66%      { border-color: #3c3b6e; box-shadow: 0 0 0 2px rgba(60,59,110,0.7),  0 0 20px 5px rgba(60,59,110,0.75); }  /* Old Glory Blue */
}

/* ── Effect: Red / White / Blue + Blurry Mist ──────────────────────────────
   Same patriot ring PLUS a drifting blurred red/blue mist over the image.
   Built for the July 4th sale. */
.zpa-archive .zpa-product-card.zpa-accent-fx-patriot-mist {
	animation: zpa-accent-patriot var(--zpa-accent-speed) ease-in-out infinite;
}
/* The mist layer lives INSIDE .zpa-product-image (position:relative), fills
   it, blurs radial blobs, and drifts. Above the image, below the badges. */
.zpa-archive .zpa-accent-mist {
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	border-radius: inherit;
	overflow: hidden;
	background:
		radial-gradient(38% 46% at 22% 30%, rgba(178, 34, 52, 0.55), transparent 70%),
		radial-gradient(40% 48% at 78% 68%, rgba(60, 59, 110, 0.55), transparent 72%),
		radial-gradient(30% 36% at 60% 20%, rgba(255, 255, 255, 0.35), transparent 70%);
	filter: blur(14px);
	opacity: 0.85;
	animation: zpa-accent-mist-drift calc(var(--zpa-accent-speed) * 3) ease-in-out infinite alternate;
	mix-blend-mode: screen;
}
@keyframes zpa-accent-mist-drift {
	0%   { transform: translate3d(-6%, -4%, 0) scale(1.05); }
	50%  { transform: translate3d(5%, 3%, 0) scale(1.15); }
	100% { transform: translate3d(-3%, 6%, 0) scale(1.08); }
}

/* ── Effect: Gold Prestige Pulse ───────────────────────────────────────────
   Warm gold breathing ring. "Premium / best value." */
.zpa-archive .zpa-product-card.zpa-accent-fx-gold-pulse {
	animation: zpa-accent-gold var(--zpa-accent-speed) ease-in-out infinite;
}
@keyframes zpa-accent-gold {
	0%, 100% { border-color: #b8860b; box-shadow: 0 0 0 2px rgba(184,134,11,0.5), 0 0 14px 3px rgba(184,134,11,0.5); }
	50%      { border-color: #ffe680; box-shadow: 0 0 0 2px rgba(255,215,0,0.75), 0 0 26px 7px rgba(255,215,0,0.8); }
}

/* ── Effect: Ember Glow ────────────────────────────────────────────────────
   Orange↔red flicker. High urgency. Faster than the others. */
.zpa-archive .zpa-product-card.zpa-accent-fx-fire {
	animation: zpa-accent-fire calc(var(--zpa-accent-speed) * 0.5) ease-in-out infinite;
}
@keyframes zpa-accent-fire {
	0%, 100% { border-color: #ff4500; box-shadow: 0 0 0 2px rgba(255,69,0,0.6),  0 0 16px 4px rgba(255,69,0,0.7); }
	50%      { border-color: #ffae42; box-shadow: 0 0 0 2px rgba(255,174,66,0.8), 0 0 28px 8px rgba(255,120,0,0.85); }
}

/* ── Effect: Aurora Drift ──────────────────────────────────────────────────
   Slow teal → purple → blue sweep. On-brand for Petratide. */
.zpa-archive .zpa-product-card.zpa-accent-fx-aurora {
	animation: zpa-accent-aurora calc(var(--zpa-accent-speed) * 1.6) ease-in-out infinite;
}
@keyframes zpa-accent-aurora {
	0%, 100% { border-color: #1b8b8a; box-shadow: 0 0 0 2px rgba(27,139,138,0.6), 0 0 20px 5px rgba(27,139,138,0.7); }
	33%      { border-color: #a43fff; box-shadow: 0 0 0 2px rgba(164,63,255,0.6), 0 0 20px 5px rgba(164,63,255,0.7); }
	66%      { border-color: #4b6bff; box-shadow: 0 0 0 2px rgba(75,107,255,0.6), 0 0 20px 5px rgba(75,107,255,0.7); }
}

/* ── Effect: Custom ────────────────────────────────────────────────────────
   No built-in animation. The card still carries .zpa-accent (2px border) so
   the user's Accent Custom CSS has a hook to target. Border transparent by
   default so nothing shows until the user styles it. */
.zpa-archive .zpa-product-card.zpa-accent-fx-custom {
	border-color: transparent !important;
}

/* ── Accent badge — the custom "Most Valued" pill ──────────────────────────
   Inherits the base .zpa-badge positioning. Given a distinct look so it
   reads as more important than a plain Sale tag: gradient fill + subtle
   glow, sitting top-left like the sale pill. */
.zpa-archive .zpa-badge-accent {
	background: linear-gradient(120deg, #b22234, #3c3b6e);
	color: #fff;
	font-weight: 700;
	letter-spacing: 0.06em;
	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
	z-index: 4; /* above the sale pill and mist */
	white-space: nowrap;
	max-width: calc(100% - 24px);
	overflow: hidden;
	text-overflow: ellipsis;
}

/* The accent badge overrides the ::before emoji of the sale badge — it
   should NOT inherit the lightning bolt. (It's a different class, so it
   won't; this is just insurance if someone stacks classes.) */
.zpa-archive .zpa-badge-accent::before {
	content: none;
}

/* When BOTH the accent badge and the Sale pill show (replace-sale off),
   push the Sale pill down so they don't overlap. */
.zpa-archive .zpa-badge-sale--stacked {
	top: 44px;
}

.zpa-product-body {
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding: 16px;
	flex: 1;
}

.zpa-product-title {
	margin: 0;
	font-size: 15px;
	font-weight: 500;
	line-height: 1.35;
}

.zpa-product-title a {
	color: inherit;
	text-decoration: none;
}

.zpa-product-title a:hover {
	text-decoration: underline;
}

.zpa-product-price {
	font-size: 16px;
	font-weight: 600;
	line-height: 1;
}

.zpa-product-price del {
	opacity: 0.5;
	font-weight: 400;
	margin-right: 6px;
}

.zpa-product-price ins {
	text-decoration: none;
}

.zpa-product-button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 10px 16px;
	margin-top: auto;
	font-size: 13px;
	font-weight: 600;
	text-decoration: none;
	border-radius: 6px;
	background: #18181b;
	color: #fff;
	border: none;
	cursor: pointer;
	transition: background 0.15s;
}

.zpa-product-button:hover {
	background: #27272a;
	color: #fff;
}

/* --- No Results ---------------------------------------------------------- */
.zpa-no-results {
	grid-column: 1 / -1;
	text-align: center;
	padding: 60px 20px;
	color: inherit;
	opacity: 0.7;
}

.zpa-no-results h3 {
	margin: 0 0 8px;
	font-size: 18px;
}

.zpa-no-results p {
	margin: 0;
	font-size: 14px;
}

/* Circular frame for the optional no-results image. Square images crop to
   a perfect circle via overflow:hidden + border-radius:50%. The thin border
   is a 1px ring in a neutral grey — presets retune the color to match their
   palette (e.g. brand purple for glassmorphic). */
.zpa-no-results-image {
	width: 160px;
	height: 160px;
	margin: 0 auto 24px;
	border-radius: 50%;
	overflow: hidden;
	border: 1px solid rgba(0, 0, 0, 0.12);
	background: rgba(0, 0, 0, 0.03);
	display: flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
}

.zpa-no-results-image img,
.zpa-no-results-image .zpa-no-results-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	border-radius: 50%;
}

@media (max-width: 480px) {
	.zpa-no-results-image {
		width: 120px;
		height: 120px;
		margin-bottom: 18px;
	}
}

/* --- Pagination ---------------------------------------------------------- */
.zpa-pagination {
	margin-top: 32px;
	display: flex;
	justify-content: center;
}

.zpa-pagination-list {
	display: flex;
	gap: 4px;
	list-style: none;
	margin: 0;
	padding: 0;
	flex-wrap: wrap;
	justify-content: center;
}

.zpa-pagination-list li {
	margin: 0;
	padding: 0;
}

.zpa-page-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 38px;
	height: 38px;
	padding: 0 12px;
	font: inherit;
	font-size: 14px;
	font-weight: 500;
	background: #fff;
	color: inherit;
	border: 1px solid #d4d4d8;
	border-radius: 6px;
	cursor: pointer;
	transition: background 0.15s, border-color 0.15s;
}

.zpa-page-link:hover {
	border-color: #71717a;
	background: #fafafa;
}

.zpa-page-active {
	background: #18181b;
	border-color: #18181b;
	color: #fff;
	cursor: default;
}

.zpa-page-active:hover {
	background: #18181b;
}

.zpa-page-ellipsis {
	display: inline-flex;
	align-items: center;
	min-width: 24px;
	height: 38px;
	color: inherit;
	opacity: 0.5;
}

/* --- Loading state ------------------------------------------------------- */
.zpa-results-region[aria-busy="true"] .zpa-grid {
	opacity: 0.4;
	pointer-events: none;
	transition: opacity 0.2s;
}

.zpa-loading-overlay {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	display: flex;
	align-items: flex-start;
	justify-content: center;
	padding-top: 80px;
	z-index: 10;
	pointer-events: none;
}

/* Respect the `hidden` HTML attribute. Without this, the class selector
   `.zpa-loading-overlay { display: flex }` ties on specificity with the
   user-agent `[hidden] { display: none }` rule and wins because author
   CSS comes later in the cascade — which makes the spinner visible on
   initial page load before any AJAX fetch has fired. */
.zpa-loading-overlay[hidden] {
	display: none !important;
}

.zpa-spinner {
	width: 36px;
	height: 36px;
	border: 3px solid currentColor;
	border-top-color: transparent;
	border-radius: 50%;
	opacity: 0.6;
	animation: zpa-spin 0.7s linear infinite;
}

@keyframes zpa-spin {
	to { transform: rotate(360deg); }
}
