/**
 * Phänomen Shop AJAX
 *
 * Functional styling only: a screen-reader status region and a loading
 * affordance. No typography, no font-family, no decorative treatment — the
 * Breakdance template owns the visual design of the filter band and grid.
 *
 * Colours come from the Breakdance palette variables. The Accent tone
 * (--bde-palette-color-1-9fa87e18-…) is deliberately unused.
 */

/* -------------------------------------------------------------------------
 * Palette aliases
 * ---------------------------------------------------------------------- */
.ph-shop-ajax-host {
	--phsa-bar: var( --bde-palette-color-1-1941ae39-5fd1-488e-917f-5d78aaaed343 );
	--phsa-track: var( --bde-palette-color-1-6ff98eb0-e04c-47a7-8d7e-46a642ad5286 );

	position: relative;
}

/* -------------------------------------------------------------------------
 * aria-live status region
 *
 * The grid used to mutate silently. This announces the new result count
 * ("24 Artikel") after every swap, and "Produkte werden geladen …" while a
 * request is in flight.
 * ---------------------------------------------------------------------- */
.ph-shop-ajax-status {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: 0;
	padding: 0;
	overflow: hidden;
	clip: rect( 0 0 0 0 );
	clip-path: inset( 50% );
	white-space: nowrap;
	border: 0;
}

/* -------------------------------------------------------------------------
 * Loading affordance
 *
 * 1. An indeterminate progress bar pinned to the bottom edge of the filter
 *    band, so feedback appears next to the control the visitor just used.
 * 2. The grid dims and stops accepting pointer events.
 *
 * The filter controls themselves stay interactive on purpose: rapid changes
 * are debounced and the in-flight request is aborted, so there is no reason
 * to lock the visitor out of the band.
 * ---------------------------------------------------------------------- */
.ph-shop-ajax-progress {
	position: absolute;
	right: 0;
	bottom: 0;
	left: 0;
	height: 2px;
	overflow: hidden;
	pointer-events: none;
	opacity: 0;
	background-color: var( --phsa-track );
	transition: opacity 0.15s ease;
}

.ph-shop-loading .ph-shop-ajax-progress {
	opacity: 1;
}

.ph-shop-ajax-progress > span {
	display: block;
	width: 40%;
	height: 100%;
	background-color: var( --phsa-bar );
	transform: translateX( -100% );
}

.ph-shop-loading .ph-shop-ajax-progress > span {
	animation: ph-shop-ajax-slide 1.1s ease-in-out infinite;
}

@keyframes ph-shop-ajax-slide {
	0% {
		transform: translateX( -100% );
	}

	100% {
		transform: translateX( 250% );
	}
}

.bde-wooshoppage {
	transition: opacity 0.18s ease;
}

.ph-shop-loading .bde-wooshoppage {
	opacity: 0.45;
	pointer-events: none;
	cursor: progress;
}

.ph-shop-loading .ph-shop-ajax-host {
	cursor: progress;
}

/* -------------------------------------------------------------------------
 * Brand archives — the filter band is two rows.
 *
 * Everywhere else the band is a single row: pills on the left, count and sort
 * pushed to the right by the band's own justify-content: space-between. A brand
 * archive puts the pills on their own row and gives the count and sort a second
 * one, full width, count left and sort right.
 *
 * THE SELECTOR BUG THIS REPLACES — do not reintroduce it.
 * The previous rules were written as `.tax-product_brand .breakdance .ph-…`,
 * i.e. with a descendant combinator between the first two classes. Both of those
 * classes sit on the SAME element — <body class="… tax-product_brand … breakdance …">
 * — so the combinator required .breakdance to be a descendant of itself and the
 * rules never matched anything. They were present in the stylesheet, and dead.
 * Compound them (`body.tax-product_brand`) or the whole block silently no-ops.
 *
 * Breakdance's own rules, for reference:
 *   .breakdance .bde-div-531-8  { display:flex; flex-direction:row;
 *                                 justify-content:space-between;
 *                                 flex-wrap:nowrap; gap:24px; row-gap:16px }
 *   .breakdance .bde-div-531-21 { display:flex; flex-wrap:wrap;
 *                                 justify-content:flex-end; gap:40px }
 * With nowrap, six pills claimed 992px and left the meta group 148px, whose own
 * flex-wrap:wrap then stacked sort under count in that narrow column — one row,
 * not two.
 *
 * The fix is at the BAND, not inside the meta group: allow wrapping, then give
 * each child a 100% flex-basis so they cannot share a line. Row 2 is therefore
 * full width and its space-between actually has room to separate count from
 * sort. Breakdance's 16px row-gap supplies the gap between the rows.
 *
 * Confined to >=1024px on purpose. Breakdance already switches the band to
 * flex-direction:column at max-width:1023px, and in a column the 100% basis
 * would apply to HEIGHT rather than width. The mobile layout is correct as it
 * stands and must not be touched.
 *
 * Specificity: body.tax-product_brand .ph-filter-band > .ph-meta-group is
 * (0,3,1) against Breakdance's (0,2,0). No !important needed.
 * ---------------------------------------------------------------------- */
@media ( min-width: 1024px ) {
	body.tax-product_brand .ph-filter-band {
		flex-wrap: wrap;
		align-items: stretch;
	}

	body.tax-product_brand .ph-filter-band > .ph-filter-group {
		flex: 1 1 100%;
	}

	body.tax-product_brand .ph-filter-band > .ph-meta-group {
		flex: 0 0 100%;
		justify-content: space-between;
	}
}

/* -------------------------------------------------------------------------
 * Farbe — the empty wrapper on non-brand archives
 *
 * [ph_shop_filter type="farbe"] returns '' on /shop/, the category archives and
 * /new-arrivals/, but Breakdance still prints the Shortcode element's wrapper
 * div. An empty-but-present flex item consumes one of the filter group's column
 * gaps and leaves a phantom slot between Grösse and Preis — the same bug the
 * archive intro hit, fixed the same way.
 *
 * Scoped to the filter group, because a shortcode that legitimately prints a
 * bare text node elsewhere must not be caught by this.
 * ---------------------------------------------------------------------- */
.ph-filter-group > .bde-shortcode:not(:has(> *)) {
	display: none;
}

/* -------------------------------------------------------------------------
 * Farbe — the colour swatch
 *
 * Two separate mechanisms, because selectWoo renders the two places differently.
 *
 *   DROPDOWN ROWS — templateResult returns real nodes (.ph-color-opt), and each
 *   .ph-color-opt__dot carries its own --phsa-swatch set inline by the script.
 *
 *   CLOSED PILL — selectWoo sets the rendered label with .text(), so no node can
 *   survive there and templateSelection must return a plain string. The swatch is
 *   therefore a ::before on .select2-selection__rendered, filled from a
 *   --phsa-swatch that ph_paint() puts on the .ph-pill--color wrapper (the
 *   wrapper, because the library rewrites the rendered span on every update).
 *
 * The value is the API's own `css`: a hex for the twelve solid groups and a
 * conic-gradient for Mehrfarbig, so `background` (not background-color) is the
 * correct property and the multi-colour case needs no separate rule.
 *
 * No colour literal appears here by design — the palette belongs to
 * phaenomen-variation-ui and arrives at runtime. The ring is an inset
 * box-shadow rather than a border, matching the PDP swatch idiom, so it does not
 * affect the box size and stays visible on a white swatch. currentColor at low
 * alpha keeps it theme-driven rather than hard-coded.
 *
 * 14px in a dropdown row, against the PDP's 32px in a 44px control.
 * ---------------------------------------------------------------------- */
.ph-color-opt {
	display: flex;
	align-items: center;
	gap: 8px;
}

.ph-color-opt__dot {
	flex: 0 0 auto;
	width: 14px;
	height: 14px;
	border-radius: 50%;
	background: var( --phsa-swatch, transparent );
	box-shadow: inset 0 0 0 1px rgba( 0, 0, 0, 0.18 );
}

.ph-color-opt__label {
	min-width: 0;
}

/*
 * Closed pill — the swatch is an inline-block ::before, NOT a flex child.
 *
 * WHAT FAILED FIRST, so it is not rebuilt that way again:
 * this block used to set `display:flex; gap:8px` on .select2-selection__rendered
 * at (0,2,0). WooCommerce's own select2.css carries
 *   .select2-container .select2-selection--single .select2-selection__rendered
 *   { display:block; padding-left:8px; padding-right:20px;
 *     overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
 * at (0,3,0) and simply outranked it. `display` stayed `block`, so the ::before
 * fell back to `display:inline`, which ignores width/height — a 0x0 box that
 * painted nothing — and `gap` was inert for the same reason. The rendered span
 * measured 27.53px, exactly the text run of "Blau" with no room for a dot.
 *
 * ON LOAD ORDER, measured rather than assumed: select2-css is stylesheet #2 and
 * phaenomen-shop-ajax-css is #10, so ours loads LATER and would win any
 * specificity TIE. What it cannot do is win from below — (0,2,0) loses to
 * (0,3,0) no matter how late it loads. Equal-or-lower specificity against
 * WooCommerce or Breakdance is the trap in this project; check the weight, not
 * just the order.
 *
 * THE FIX deliberately does not fight that rule at all. Making the parent flex
 * would need (0,4,0)+ and would also break Woo's text-overflow:ellipsis, which
 * only applies to block containers. Instead the ::before is `inline-block` with
 * its own margin-right: that holds a real box in a `display:block` parent, and
 * still holds one if the parent ever becomes flex (where inline-block blockifies
 * and margin-right survives). Robust either way, with the ellipsis intact.
 *
 * The ✕ is not involved. The tree CSS gives it
 * `position:absolute; top:0; right:0; width:34px` inside a 34px reserved
 * gutter, so it is out of flow entirely — it was never orderable, and the
 * left-hand dot cannot collide with it.
 *
 * Only painted when ph_paint() has added .ph-has-color, so the placeholder
 * state ("Farbe", no selection) shows no empty circle.
 */
.ph-pill--color.ph-has-color .select2-selection__rendered::before {
	content: '';
	display: inline-block;
	vertical-align: middle;
	flex: 0 0 auto;
	width: 14px;
	height: 14px;
	margin-right: 8px;
	border-radius: 50%;
	background: var( --phsa-swatch, transparent );
	box-shadow: inset 0 0 0 1px rgba( 0, 0, 0, 0.18 );
}

/* -------------------------------------------------------------------------
 * „Mehr laden" / „Frühere Artikel laden"
 *
 * Structure only. Every colour comes from currentColor, which the archive
 * already sets — so there is no literal here, nothing to keep in sync with the
 * palette, and no font-family. The controls are anchors and are left looking
 * like the rest of the page rather than given a bespoke button treatment
 * nobody asked for.
 *
 * These class names are ours and appear nowhere in Breakdance's or
 * WooCommerce's stylesheets, so there is no specificity contest to lose here —
 * unlike .select2-selection__rendered, which had to be fought for.
 * ---------------------------------------------------------------------- */
/*
 * Native scroll anchoring OFF for the grid.
 *
 * overflow-anchor computed to `auto` on html, body, ul.products and li.product,
 * so Chrome was picking its own anchor node and applying its own correction on
 * top of the one mergePage() makes when prepending. Two mechanisms compensating
 * for the same insertion is one too many, and the browser's runs after ours.
 *
 * Scoped to the grid rather than the scroller: switching it off on html/body
 * would disable anchoring for every other part of the page, which is a real
 * feature everywhere we are NOT hand-correcting. The tiles reserve their height
 * before images resolve — verified, 0.0px drift with 12 images still loading —
 * so the grid gains nothing from native anchoring anyway.
 */
.bde-wooshoppage,
.bde-wooshoppage .products,
.bde-wooshoppage .products > li.product {
	overflow-anchor: none;
}

.ph-load {
	/*
	 * The aliases are re-declared here, not inherited.
	 *
	 * .ph-shop-ajax-host — where they are normally defined — is added by
	 * buildChrome() to the FILTER BAND, and these controls live in
	 * .bde-wooshoppage, a different Breakdance section entirely. Nothing
	 * connects the two, so var( --phsa-bar ) would resolve to nothing here and
	 * the hover state would silently do nothing. The palette variables they
	 * point at are declared on :root, so this indirection works anywhere.
	 */
	--phsa-bar: var( --bde-palette-color-1-1941ae39-5fd1-488e-917f-5d78aaaed343 );
	--phsa-track: var( --bde-palette-color-1-6ff98eb0-e04c-47a7-8d7e-46a642ad5286 );

	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	width: 100%;
	margin: 24px 0;
}

.ph-load--before {
	margin-top: 0;
}

.ph-load__progress {
	margin: 0;
	font-size: 13px;
	line-height: 1.2;
	opacity: 0.7;
}

.ph-load__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 40px;
	padding: 0 24px;
	border: 1px solid currentColor;
	border-radius: 3px;
	font-size: 13px;
	line-height: 1.2;
	letter-spacing: 0.01em;
	text-decoration: none;
	cursor: pointer;
}

/*
 * No underline — and the hover state has to be beaten too, not just the resting
 * one.
 *
 * These are anchors, so global-settings.css reaches them twice:
 *
 *   .breakdance a        { text-decoration-line: underline; color: Ink }     (0,1,1)
 *   .breakdance a:hover  { text-decoration-line: underline; color: #666 }    (0,2,1)
 *
 * Resetting only the first relocates the underline into :hover rather than
 * removing it. Both are answered here, and both selectors are STRICTLY above
 * their opponent — (0,3,1) and (0,4,1) — because our stylesheet loads before
 * Breakdance's generated CSS, so an equal-specificity rule would lose on source
 * order. `:hover` counts in the class column; that is what makes the hover
 * opponent (0,2,1) rather than (0,1,1).
 *
 * Checked before writing this: no page-level post-{ID}.css loaded on an archive
 * targets links inside these controls. post-531.css only styles
 * `.bde-woo-breadcrumb-531-5 … a`, and post-529.css only `.bde-text-529-7 a`
 * (the product card's brand link) — the trap post-220.css sprang on the account
 * page does not exist here.
 *
 * HOVER AFFORDANCE: a background fill, not a colour shift. The palette's link
 * hover is the accent (#666), which this project does not use as a hover colour
 * anywhere — the filter pills say so explicitly and the variable is called out
 * as deliberately unused at the top of this file. Letting it through would also
 * LIGHTEN the text and, through currentColor, the border — the wrong direction
 * for something that reads as a button. So the colour is pinned and the surface
 * changes instead. Geometry is untouched, so nothing shifts on hover.
 *
 * The focus ring is deliberately not mentioned: no outline is set here, so
 * :focus-visible keeps whatever the theme draws.
 */
.breakdance .ph-load a.ph-load__link {
	text-decoration: none;
}

.breakdance .ph-load a.ph-load__link:hover,
.breakdance .ph-load a.ph-load__link:focus {
	text-decoration: none;
	color: var( --phsa-bar );
	background-color: var( --phsa-track );
}

/*
 * Busy state. Keyed on aria-disabled because the control is an <a>: it has no
 * disabled property, and stripping href would remove the crawlable link that is
 * the entire point of building these as anchors.
 */
.ph-load__link[aria-disabled="true"] {
	opacity: 0.45;
	pointer-events: none;
}

/*
 * The focus target after a load is a product tile, focusable only because the
 * script gives it tabindex="-1". Keep the ring for keyboard users, suppress it
 * for the pointer click that caused the load.
 */
.products > li.product:focus:not(:focus-visible) {
	outline: none;
}

/* -------------------------------------------------------------------------
 * Reduced motion — keep the state change, drop the animation.
 * ---------------------------------------------------------------------- */
@media ( prefers-reduced-motion: reduce ) {
	.bde-wooshoppage {
		transition: none;
	}

	.ph-shop-ajax-progress {
		transition: none;
	}

	.ph-shop-loading .ph-shop-ajax-progress > span {
		width: 100%;
		animation: none;
		transform: none;
	}
}
