/* ==========================================================================
   Parkland content tiles + listing hub

   One card system for editorial listings: Learn & Discover articles, offers,
   and anything else that is "a picture, a label, and a headline". Deliberately
   separate from two existing card families that look similar but are not:

     .pk-card        WooCommerce product loop tiles (price, SKU, add-to-cart)
     .pk-relart-card the small related-articles card embedded in product pages

   Those stay as they are. A product tile carries commerce affordances an
   article tile must not, and merging them would drag price markup into the blog.

   Two variants, both driven from the same markup:

     .pk-tile--overlay  photograph fills the tile, text sits on a gradient.
                        Use for offers and anything with strong imagery.
     .pk-tile--panel    white card, inset image, headline plus excerpt.
                        Use when the words need to do the selling.

   Mixing variants in one grid is intentional and is what gives the listing its
   rhythm. Overlay tiles set the row height via aspect-ratio; panel tiles
   stretch to match, so rows stay flush without fixed pixel heights.

   Colour and type come from parkland-core/css/tokens.css.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Hub shell
   -------------------------------------------------------------------------- */

.pk-hub {
	--pk-hub-gap: 16px;
	--pk-hub-min: 240px;
	--pk-hub-radius: 10px;
}

/* The hub takes over whole archive templates, so it brings its own page shell
   rather than borrowing .pk-container from parkland-custom-plugin. Depending on
   that stylesheet is what pushed the colour palette out of reach in the first
   place. */
.pk-hub-page {
	padding: 40px 0 64px;
}

.pk-hub-inner {
	max-width: 1200px;
	margin: 0 auto;
	padding: 0 24px;
}

/* --- Fetching ------------------------------------------------------------
   .pk-hub-app is the region content-hub.js replaces when a filter changes, so
   it is also the only sensible place to show that something is happening.

   Dimmed and inert rather than blanked or replaced with a spinner: the previous
   results stay readable, nothing reflows, and the row you were looking at does
   not jump. Held back a moment so a fast response never flickers. */

.pk-hub-app {
	transition: opacity .18s ease;
}

.pk-hub-app.is-loading {
	opacity: .45;
	pointer-events: none;
	cursor: progress;
	transition-delay: .15s;
}

/* The count is re-rendered on every swap, so a live region has to sit outside
   the replaced markup to be announced at all. */
.pk-hub-live {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
}

/* Apply and Sort exist for visitors whose browser never ran the script. Once it
   has, the selects submit on change and a button beside them is one more thing
   to explain. Hidden off the ready flag rather than removed from the DOM, so a
   failed fetch can still fall back to a real form submission. */
[data-pk-hub-ready] .pk-hub-apply {
	display: none;
}

.pk-hub-head {
	margin: 0 0 22px;
}

.pk-hub-title {
	margin: 0 0 8px;
	color: var(--pk-ink);
	font-size: clamp(var(--pk-fs-lg), 3vw, var(--pk-fs-xl));
	font-weight: 700;
	line-height: 1.15;
	letter-spacing: -0.02em;
}

.pk-hub-intro {
	margin: 0;
	max-width: 60ch;
	color: var(--pk-muted);
	font-size: var(--pk-fs-base);
	line-height: 1.5;
}

/* --- Category tabs --------------------------------------------------------
   A horizontal scroller rather than a wrapping row: with eight Learn & Discover
   categories a wrap turns the header into three ragged lines on a tablet. */

.pk-hub-tabs {
	display: flex;
	gap: 22px;
	margin: 20px 0 0;
	padding: 0 0 2px;
	list-style: none;
	overflow-x: auto;
	scrollbar-width: none;
	-webkit-overflow-scrolling: touch;
}

.pk-hub-tabs::-webkit-scrollbar {
	display: none;
}

.pk-hub-tabs li {
	margin: 0;
	flex: 0 0 auto;
}

.pk-hub-tab {
	display: inline-block;
	padding: 4px 0;
	border-bottom: 2px solid transparent;
	color: var(--pk-muted);
	font-size: var(--pk-fs-sm);
	line-height: 1.4;
	text-decoration: none;
	white-space: nowrap;
	transition: color .18s, border-color .18s;
}

.pk-hub-tab:hover,
.pk-hub-tab:focus-visible {
	color: var(--pk-ink);
	border-bottom-color: var(--pk-border);
}

.pk-hub-tab.is-current {
	color: var(--pk-ink);
	border-bottom-color: var(--pk-ink);
	font-weight: 600;
}

/* --- Filter band ---------------------------------------------------------- */

.pk-hub-filters {
	margin: 0 0 18px;
	padding: 18px 0;
	background: var(--pk-surface);
}

.pk-hub-filters-row {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	align-items: center;
}

/* The filters are native <select>s dressed as pills. A custom dropdown would
   have matched the reference more exactly, but a select filters with plain GET
   — no JS needed, linkable, crawlable, and a real listbox for assistive tech.
   appearance is stripped and the chevron is a background image because a
   pseudo-element cannot be attached to a select. */

.pk-hub-field {
	display: inline-flex;
	margin: 0;
}

.pk-hub-select {
	appearance: none;
	-webkit-appearance: none;
	padding: 8px 34px 8px 14px;
	border: 1px solid var(--pk-border);
	border-radius: 999px;
	background-color: #fff;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23555' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 13px center;
	background-size: 10px 6px;
	color: var(--pk-muted);
	font-family: inherit;
	font-size: var(--pk-fs-sm);
	line-height: 1.2;
	cursor: pointer;
	transition: border-color .18s, color .18s;
}

.pk-hub-select:hover,
.pk-hub-select:focus-visible {
	border-color: var(--pk-ink);
	color: var(--pk-ink);
}

/* An applied filter has to be visible at a glance or people lose track of why
   the result count dropped. */
.pk-hub-select.is-active {
	border-color: var(--pk-ink);
	background-color: var(--pk-ink);
	color: var(--pk-ink-invert);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23fff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.pk-hub-select option {
	color: var(--pk-ink);
	background: #fff;
}

.pk-hub-apply {
	padding: 8px 16px;
	border: 1px solid var(--pk-ink);
	border-radius: 999px;
	background: var(--pk-ink);
	color: var(--pk-ink-invert);
	font-family: inherit;
	font-size: var(--pk-fs-sm);
	line-height: 1.2;
	cursor: pointer;
}

.pk-hub-sortform {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	margin: 0;
}

.pk-hub-sortform .pk-hub-select {
	border-color: transparent;
	background-color: transparent;
	padding-left: 4px;
	color: var(--pk-ink);
}

.pk-hub-sortform .pk-hub-select:hover {
	border-color: var(--pk-border);
	background-color: #fff;
}

.pk-hub-sortform .pk-hub-select.is-active {
	border-color: var(--pk-ink);
	background-color: var(--pk-ink);
	color: var(--pk-ink-invert);
}

/* Empty-state: a filter combination with no matches must say so, not show a
   blank page that reads as a broken listing. */
.pk-hub-empty {
	margin: 8px 0 0;
	padding: 32px 0;
	border-top: 1px solid var(--pk-border);
	color: var(--pk-muted);
	font-size: var(--pk-fs-base);
}

.pk-hub-empty a {
	color: var(--pk-accent);
}

/* --- Result count + sort -------------------------------------------------- */

.pk-hub-meta {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	align-items: baseline;
	justify-content: space-between;
	margin: 0 0 16px;
}

.pk-hub-count {
	margin: 0;
	color: var(--pk-muted);
	font-size: var(--pk-fs-sm);
}

/* --- Pagination ----------------------------------------------------------- */

.pk-hub-pagination {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	align-items: center;
	margin: 28px 0 0;
}

.pk-hub-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 38px;
	height: 38px;
	padding: 0 10px;
	border: 1px solid var(--pk-border);
	border-radius: 999px;
	color: var(--pk-ink);
	font-size: var(--pk-fs-sm);
	text-decoration: none;
}

.pk-hub-pagination .page-numbers:hover {
	border-color: var(--pk-ink);
}

.pk-hub-pagination .page-numbers.current {
	border-color: var(--pk-ink);
	background: var(--pk-ink);
	color: var(--pk-ink-invert);
}

.pk-hub-pagination .page-numbers.dots {
	border-color: transparent;
	color: var(--pk-muted);
}

/* --- Grid ---------------------------------------------------------------- */

/* The fallbacks matter: the grid is also dropped into ordinary pages that have
   no .pk-hub wrapper, such as "Discover more offers" on a deal. Without them
   the custom property resolves to nothing, which invalidates the whole
   declaration rather than just that value, and the grid collapses to one
   full-width column. */
.pk-hub-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(var(--pk-hub-min, 240px), 1fr));
	gap: var(--pk-hub-gap, 16px);
	align-items: stretch;
	margin: 0;
	padding: 0;
	list-style: none;
}

.pk-hub-grid > li {
	margin: 0;
	display: flex;
}

/* A tile can claim two columns for a lead story or headline offer. It drops
   back to one below the breakpoint or it would force a horizontal scroll. */
@media (min-width: 700px) {
	.pk-hub-grid > .is-wide {
		grid-column: span 2;
	}
}

/* Full-row lead: the homepage deals shortcode, or any listing that wants a
   banner above a grid rather than a double-width card in the first row. */
.pk-hub-grid > .is-full {
	grid-column: 1 / -1;
}

/* --------------------------------------------------------------------------
   Tile — shared
   -------------------------------------------------------------------------- */

.pk-tile {
	position: relative;
	display: flex;
	flex-direction: column;
	width: 100%;
	border-radius: var(--pk-hub-radius, 10px);
	overflow: hidden;
	color: inherit;
	text-decoration: none;
	transition: transform .22s ease, box-shadow .22s ease;
}

.pk-tile:hover {
	transform: translateY(-3px);
}

.pk-tile:focus-visible {
	outline: 2px solid var(--pk-accent);
	outline-offset: 3px;
}

.pk-tile-media {
	position: relative;
	display: block;
	overflow: hidden;
	background: var(--pk-surface);
}

.pk-tile-media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform .4s ease;
}

.pk-tile:hover .pk-tile-media img {
	transform: scale(1.04);
}

.pk-tile-eyebrow {
	display: block;
	font-size: var(--pk-fs-xs);
	line-height: 1.3;
}

.pk-tile-title {
	display: block;
	font-size: var(--pk-fs-base);
	font-weight: 700;
	line-height: 1.3;
}

.pk-tile-excerpt {
	display: block;
	margin: 8px 0 0;
	color: var(--pk-muted);
	font-size: var(--pk-fs-xs);
	line-height: 1.55;
}

/* Keeps ragged excerpt lengths from bullying the grid out of alignment. */
.pk-tile-excerpt {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 4;
	overflow: hidden;
}

/* Status chip for offers: "Ends 30 Sep", "Now on". */
.pk-tile-badge {
	position: absolute;
	top: 12px;
	left: 12px;
	z-index: 2;
	padding: 4px 10px;
	border-radius: 999px;
	background: var(--pk-accent);
	color: var(--pk-ink-invert);
	font-size: var(--pk-fs-xs);
	font-weight: 600;
	line-height: 1.4;
	letter-spacing: 0.01em;
}

.pk-tile-badge--ended {
	background: var(--pk-muted);
}

/* With no image there is nothing to float the chip over, so it joins the text
   flow rather than covering the headline. Offers routinely arrive without art. */
.pk-tile.has-no-media .pk-tile-badge {
	position: static;
	align-self: flex-start;
	margin: 0 0 10px;
}

/* --------------------------------------------------------------------------
   Tile — overlay variant
   -------------------------------------------------------------------------- */

.pk-tile--overlay {
	aspect-ratio: 3 / 4;
	background: var(--pk-ink);
	color: var(--pk-ink-invert);
}

.pk-tile--overlay .pk-tile-media {
	position: absolute;
	inset: 0;
	background: none;
}

/* The scrim is a pseudo-element on the body rather than a filter on the image,
   so the gradient never scales with the hover zoom. */
.pk-tile--overlay .pk-tile-body {
	position: relative;
	z-index: 1;
	margin-top: auto;
	padding: 18px 16px 16px;
}

.pk-tile--overlay .pk-tile-body::before {
	content: "";
	position: absolute;
	inset: -64px 0 0;
	z-index: -1;
	background: linear-gradient(
		to top,
		rgba(0, 0, 0, .82) 0%,
		rgba(0, 0, 0, .62) 32%,
		rgba(0, 0, 0, .18) 72%,
		rgba(0, 0, 0, 0) 100%
	);
	pointer-events: none;
}

.pk-tile--overlay .pk-tile-eyebrow {
	margin: 0 0 4px;
	color: rgba(255, 255, 255, .82);
}

.pk-tile--overlay .pk-tile-title {
	color: var(--pk-ink-invert);
	text-shadow: 0 1px 2px rgba(0, 0, 0, .35);
}

.pk-tile--overlay .pk-tile-excerpt {
	color: rgba(255, 255, 255, .88);
	-webkit-line-clamp: 3;
}

/* --------------------------------------------------------------------------
   Tile — panel variant
   -------------------------------------------------------------------------- */

.pk-tile--panel {
	padding: 8px;
	border: 1px solid var(--pk-border);
	background: #fff;
	box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
}

.pk-tile--panel:hover {
	box-shadow: 0 10px 26px rgba(0, 0, 0, .10);
}

.pk-tile--panel .pk-tile-media {
	border-radius: 6px;
	aspect-ratio: 16 / 10;
	flex: 0 0 auto;
}

.pk-tile--panel .pk-tile-body {
	display: flex;
	flex-direction: column;
	padding: 14px 8px 10px;
}

.pk-tile--panel .pk-tile-eyebrow {
	margin: 0 0 6px;
	color: var(--pk-muted);
}

.pk-tile--panel .pk-tile-title {
	color: var(--pk-ink);
}

/* Text-only panel: no image, so the headline carries the tile. */
.pk-tile--panel.has-no-media .pk-tile-body {
	padding-top: 18px;
}

.pk-tile--panel.has-no-media .pk-tile-title {
	font-size: var(--pk-fs-lg);
}

/* --------------------------------------------------------------------------
   Wide tile
   -------------------------------------------------------------------------- */

.pk-tile--wide.pk-tile--overlay {
	aspect-ratio: 16 / 10;
}

.pk-tile--wide .pk-tile-title {
	font-size: var(--pk-fs-lg);
}

@media (min-width: 700px) {
	.pk-tile--wide .pk-tile-body {
		max-width: 68%;
	}
}

/* --------------------------------------------------------------------------
   Full-row tile
   -------------------------------------------------------------------------- */

.pk-tile--full.pk-tile--overlay {
	aspect-ratio: 2.2 / 1;
	max-height: 480px;
}

.pk-tile--full.pk-tile--overlay .pk-tile-body {
	padding: 28px 24px 24px;
}

.pk-tile--full .pk-tile-title {
	font-size: clamp(var(--pk-fs-lg), 2.4vw, var(--pk-fs-xl));
}

/* Same idea as the deal-page hero: copy sits on the left, so the fade is
   strongest there and clears away to the right. The default overlay scrim is
   a short lift under the text, which is not enough once the tile is a banner. */
.pk-tile--full.pk-tile--overlay .pk-tile-media::after {
	content: "";
	position: absolute;
	inset: 0;
	background:
		linear-gradient(to right, rgba(0, 0, 0, .78) 0%, rgba(0, 0, 0, .55) 38%, rgba(0, 0, 0, .12) 72%, rgba(0, 0, 0, 0) 100%),
		linear-gradient(to top, rgba(0, 0, 0, .4) 0%, rgba(0, 0, 0, 0) 48%);
	pointer-events: none;
}

.pk-tile--full.pk-tile--overlay .pk-tile-body::before {
	content: none;
}

@media (min-width: 700px) {
	.pk-tile--full .pk-tile-body {
		max-width: 46%;
	}
}

/* --------------------------------------------------------------------------
   Small screens
   -------------------------------------------------------------------------- */

@media (max-width: 600px) {
	.pk-hub {
		--pk-hub-min: 100%;
	}

	.pk-tile--overlay {
		aspect-ratio: 4 / 3;
	}

	.pk-tile--wide.pk-tile--overlay,
	.pk-tile--full.pk-tile--overlay {
		aspect-ratio: 4 / 3;
	}
}

/* Respect a reduced-motion preference: the lift and zoom are decoration. */
@media (prefers-reduced-motion: reduce) {
	.pk-tile,
	.pk-tile-media img {
		transition: none;
	}

	.pk-tile:hover {
		transform: none;
	}

	.pk-tile:hover .pk-tile-media img {
		transform: none;
	}
}
