/* Styled after the Hormozi Coffee shop page (staging.hormozi.co.uk/shop/):
   a bounded filter card, box-styled selects rather than plain text
   toggles, a solid dark "Clear Filters" button. Final visual design
   still follows whatever Figma reference the client supplies — this
   gets the plugin to a genuinely finished-looking state in the
   meantime, not a placeholder. */

/* --- Shared filter card shell --- */

.vhf-filter-bar {
	position: relative;
}

.vhf-filter {
	position: static;
}

/* --- Top layout: a full-width bar of its own (its own 4_4 row, above
   the sidebar/grid row entirely) so its faint bottom border stretches
   across the whole page, over both the category sidebar and the grid
   below it — not confined to the grid column's width. Search now
   renders inside .vhf-layout--top itself (VHF_Search::render() is
   called from VHF_Filter_Bar::render() for the "top" slot), as a
   sibling of the filter dropdowns and Sort, so it's all one real
   flex row: margin-right: auto pins search to the far left while the
   dropdowns and Sort stay right-aligned via justify-content. Heading is
   a plain-language instruction, not a passive label. The top border and
   some of the top padding were removed per client feedback — the grey
   line above the search field wasn't wanted, and the space above it
   was reduced slightly along with it. --- */

.vhf-layout--top,
.vhf-toolbar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-end;
	gap: 10px;
	padding: 0 0 16px;
	border-bottom: 1px solid #e5e7eb;
}

/* Small deliberate gap before the sidebar/grid row starts — the Divi
   row/section wrapper's own padding-bottom had no visible effect
   (see the .et_pb_row:has(...) rule below), so the space is added
   directly on this element instead, which reliably shows since it's a
   real block box, not a Divi flex-row wrapper sized to its content. */
.vhf-layout--top {
	margin-bottom: 20px;
}

.vhf-layout--top .vhf-search-bar {
	margin-right: auto;
}

.vhf-filter-bar-heading {
	display: none;
}

.vhf-layout--top .vhf-filter,
.vhf-toolbar .vhf-filter {
	position: relative;
}

.vhf-layout--top .vhf-filter-toggle,
.vhf-toolbar .vhf-filter-toggle {
	display: block;
	padding: 0;
	border: none;
	background: none;
	cursor: pointer;
}

.vhf-layout--top .vhf-filter-label-row,
.vhf-toolbar .vhf-filter-label-row {
	display: flex;
	align-items: center;
	gap: 8px;
	height: 44px;
	padding: 0 14px;
	border: 1px solid #d1d5db;
	border-radius: 6px;
	background: #fff;
	font-size: 13px;
	font-weight: 600;
	color: #374151;
	white-space: nowrap;
	box-sizing: border-box;
	transition: border-color 0.15s ease;
}

.vhf-layout--top .vhf-filter-toggle[aria-expanded="true"] .vhf-filter-label-row,
.vhf-layout--top .vhf-filter-toggle.has-selection .vhf-filter-label-row,
.vhf-toolbar .vhf-filter-toggle[aria-expanded="true"] .vhf-filter-label-row,
.vhf-toolbar .vhf-filter-toggle.has-selection .vhf-filter-label-row {
	border-color: #111827;
	color: #111827;
}

.vhf-layout--top .vhf-filter-panel,
.vhf-toolbar .vhf-filter-panel {
	position: absolute;
	top: calc(100% + 8px);
	left: 0;
	z-index: 200;
	min-width: 220px;
	max-width: 320px;
	max-height: 320px;
	overflow-y: auto;
	padding: 14px;
	border: 1px solid #d1d5db;
	border-radius: 8px;
	background: #fff;
	box-shadow: 0 10px 28px rgba(17, 24, 39, 0.1);
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}

/* display: flex above has higher specificity than the browser's own
   [hidden] { display: none } rule, so it was winning even when the
   panel legitimately had the hidden attribute — every dropdown showed
   as open by default regardless of its actual toggle state. */
.vhf-layout--top .vhf-filter-panel[hidden],
.vhf-toolbar .vhf-filter-panel[hidden] {
	display: none;
}

/* Reset is a discreet secondary action inside the "Ausgewählt: …"
   summary line (vhf_selection_summary_markup()), not a toolbar button
   — per client feedback the previous solid dark button drew the eye as
   if it were a primary action. Styled as a subtle text link with a
   very light grey hover wash from the brand's own grey scale (#f4f4f4
   already used for Select2 option hover/selection elsewhere in this
   file). Display: inline keeps it on the same line as the values;
   margin-left separates it from the last value. The browsers' own
   [hidden] rule needs reinforcing here is NOT needed: unlike the
   filter panels (which this file sets to display: grid/flex), this
   link's inline display doesn't outrank [hidden]'s display: none, so
   the hidden attribute hides it on its own until any checkbox is
   checked (updateResetVisibility() in filter-bar.js). */
.vhf-filter-reset {
	padding: 0;
	margin-left: 8px;
	border: none;
	background: none;
	font-size: 13px;
	font-weight: 400;
	color: #6b7280;
	text-decoration: underline;
	text-underline-offset: 2px;
	cursor: pointer;
	white-space: nowrap;
}

.vhf-filter-reset:hover {
	color: #111827;
	background: #f4f4f4;
	text-decoration: none;
	border-radius: 4px;
}

/* --- Filter card shell, used by Sidebar and Tiered-sidebar --- */

.vhf-layout--sidebar,
.vhf-slot--tiered-sidebar {
	display: block;
	background: #fff;
	border: 1px solid #e5e7eb;
	border-radius: 10px;
	padding: 22px 20px;
	margin-bottom: 24px;
}

.vhf-filter-card-heading {
	font-size: 16px;
	font-weight: 700;
	color: #111827;
	margin: 0 0 18px;
	padding-bottom: 14px;
	border-bottom: 1px solid #e5e7eb;
}

.vhf-layout--sidebar .vhf-filter,
.vhf-slot--tiered-sidebar .vhf-filter {
	margin-bottom: 18px;
}

.vhf-layout--sidebar .vhf-filter-group-label,
.vhf-slot--tiered-sidebar .vhf-filter-group-label {
	display: block;
	font-size: 13px;
	font-weight: 600;
	color: #374151;
	margin-bottom: 8px;
}

.vhf-layout--sidebar .vhf-filter-panel,
.vhf-slot--tiered-sidebar .vhf-filter-panel {
	position: static;
	box-shadow: none;
	border: none;
	border-radius: 0;
	margin-top: 0;
	padding: 0;
	display: block;
}

.vhf-selection-summary .vhf-filter-reset {
	display: inline;
	width: auto;
	margin: 0 0 0 8px;
	padding: 0 2px;
	background: none;
	color: #6b7280;
	border: none;
	border-radius: 0;
	font-size: 13px;
	font-weight: 400;
	letter-spacing: normal;
	text-transform: none;
	text-decoration: underline;
	text-underline-offset: 2px;
	text-align: left;
	cursor: pointer;
}

.vhf-selection-summary .vhf-filter-reset:hover {
	background: #f4f4f4;
	border-radius: 4px;
	color: #111827;
	text-decoration: none;
}

/* Sidebar layout: the summary line (with the reset link) sits inside
   the sidebar card itself, below the filter pills — block layout, not
   the top bar's full-width flex row, and left-aligned to match the
   card's own flat-list style rather than the top bar's right-aligned
   summary. */
.vhf-layout--sidebar .vhf-selection-summary {
	flex-basis: auto;
	margin: 14px 0 0;
	padding-top: 12px;
	border-top: 1px solid #e5e7eb;
	text-align: left;
}

/* --- Shared bits: caret, count badge, option rows --- */

.vhf-filter-caret {
	flex: none;
	width: 0;
	height: 0;
	border-left: 4px solid transparent;
	border-right: 4px solid transparent;
	border-top: 5px solid currentColor;
	transition: transform 0.15s ease;
}

.vhf-filter-toggle[aria-expanded="true"] .vhf-filter-caret {
	transform: rotate(180deg);
}

.vhf-filter-placeholder {
	flex: 1;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	text-align: left;
}

.vhf-filter-toggle.has-selection .vhf-filter-placeholder {
	color: #111827;
	font-weight: 600;
}

.vhf-filter-count {
	font-weight: 600;
	color: #111827;
}

.vhf-filter-option {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 7px 6px;
	font-size: 13px;
	color: #374151;
	cursor: pointer;
	border-radius: 4px;
}

.vhf-filter-option:hover {
	background: #f8fafc;
}

.vhf-filter-option-count {
	color: #9ca3af;
	font-size: 11px;
}

/* An option that would produce zero results given the filters
   currently selected elsewhere — greyed out and unclickable rather
   than removed, so the full set of manufacturers/types/etc. in the
   category stays visible even when narrowed out by another
   selection. !important on hover since the pill-style hover rules
   (.vhf-filter-option--pill:hover and its Sidebar-scoped variant) are
   both more specific and would otherwise still show their normal
   interactive hover state on a disabled option. */
.vhf-filter-option.is-unavailable {
	opacity: 0.4;
	cursor: not-allowed;
}

.vhf-filter-option.is-unavailable:hover {
	background: none !important;
	border-color: #d1d5db !important;
	color: inherit !important;
}

/* Pill-style options (everything except Product Group): laid out as
   a wrapped row of rounded chips, matching the category pills,
   rather than a vertical list of checkbox rows. The checkbox itself
   stays in the DOM for accessibility/keyboard use but is visually
   hidden — the label styles as the pill, and its checked state shows
   the same way a category's "current" pill does. */
.vhf-filter-panel--pills {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}

/* Sidebar layout: one item per line, matching the category tree's
   list, not a wrapped row of chips. */
.vhf-layout--sidebar .vhf-filter-panel--pills {
	display: block;
}

.vhf-filter-option--pill {
	position: relative;
	display: inline-flex;
	padding: 5px 14px;
	border: 1px solid #d1d5db;
	border-radius: 999px;
	background: #fff;
	color: #374151;
	font-size: 13px;
	line-height: 1.4;
}

.vhf-filter-option--pill:hover {
	border-color: #9ca3af;
	background: #fff;
}

.vhf-filter-option--pill input[type="checkbox"] {
	position: absolute;
	opacity: 0;
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
	margin: 0;
	cursor: pointer;
}

.vhf-filter-option--pill:has(input:checked) {
	border-color: #111827;
	background: #111827;
	color: #fff;
}

.vhf-filter-option--pill:has(input:focus-visible) {
	outline: 2px solid #111827;
	outline-offset: 2px;
}

/* Sidebar layout only: match the category tree's plain flat-list
   style (dash marker, no border/pill shape, color-based state)
   instead of the rounded-chip look used in the Top layout's dropdown
   panels. Scoped to .vhf-layout--sidebar specifically since Top's own
   dropdown pills should keep the chip treatment — only one layout is
   ever active at a time, so this never has to coexist with the base
   rule above on the same page. */
.vhf-layout--sidebar .vhf-filter-option--pill {
	display: flex;
	align-items: baseline;
	gap: 6px;
	padding: 6px 0 6px 12px;
	border: none;
	border-radius: 0;
	background: none;
	color: #111827 !important;
}

.vhf-layout--sidebar .vhf-filter-option--pill::before {
	content: "–";
	flex: none;
	color: #d1d5db;
}

.vhf-layout--sidebar .vhf-filter-option--pill:hover {
	border: none;
	background: none;
	color: #cd0d21 !important;
}

.vhf-layout--sidebar .vhf-filter-option--pill:has(input:checked) {
	border: none;
	background: none;
	color: #cd0d21 !important;
	font-weight: 600;
}

@media (max-width: 640px) {
	.vhf-layout--top,
	.vhf-toolbar {
		flex-direction: column;
		align-items: stretch;
		gap: 10px;
	}

	.vhf-layout--top .vhf-search-bar {
		width: 100%;
		margin: 0;
	}

	.vhf-layout--top .vhf-filter-toggle,
	.vhf-toolbar .vhf-filter-toggle {
		width: 100%;
	}

	.vhf-layout--top .vhf-filter-label-row,
	.vhf-toolbar .vhf-filter-label-row {
		justify-content: space-between;
	}

	.vhf-layout--top .vhf-filter-panel,
	.vhf-toolbar .vhf-filter-panel {
		position: static;
		box-shadow: none;
		max-width: none;
		margin-top: 8px;
	}
}

/* --- Category tree (left sidebar, always present) ---
   Three real levels: grandparent (top-level category) > parent
   (group) > child (specific item), e.g. Augenchirurgie > Katarakt >
   IOL. Plain indented text list, matching the reference site's flat
   sidebar — no pill/card chrome, just links with a small chevron on
   top-level items that have children. */

.vhf-category-tree {
	display: block;
	font-size: 14px;
	margin-bottom: 24px;
	background: #fcfcfd;
	padding: 20px;
	border-radius: 10px;
}

.vhf-category-tree-heading-row {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
	margin: 0 0 18px;
	padding-bottom: 14px;
	border-bottom: 1px solid #e5e7eb;
}

.vhf-category-tree-heading {
	font-size: 16px;
	font-weight: 700;
	color: #111827;
	margin: 0;
}

.vhf-cat-top {
	border-bottom: 1px solid #f3f4f6;
}

.vhf-cat-top:last-child {
	border-bottom: none;
}

.vhf-cat-top-link {
	display: block;
	padding: 10px 0;
	color: #6b7280 !important;
	font-weight: 600;
	text-decoration: none;
}

.vhf-cat-top-link:hover {
	color: #cd0d21 !important;
}

.vhf-cat-top.is-current > .vhf-cat-top-link {
	color: #111827 !important;
}

/* A top-level category with children is now a link (its name, straight
   to the category's own archive page) plus a separate small toggle
   button (just the caret) side by side in one row — per client
   feedback that the name itself must be clickable, not only usable to
   expand/collapse. Previously both jobs lived on one <button>.
   .vhf-cat-top itself also wraps .vhf-cat-card (the expandable content
   below), so flex-wrap lets the link+toggle row take the full width on
   its own line while the card drops to a second line beneath it,
   rather than the card being squeezed in as a third flex item on the
   same row. */
.vhf-cat-top.has-children {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
}

.vhf-cat-top.has-children > .vhf-cat-top-link {
	flex: 1 1 auto;
	padding: 10px 0;
}

.vhf-cat-top.has-children > .vhf-cat-card {
	flex: 0 0 100%;
}

.vhf-cat-top-toggle {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: none;
	padding: 10px 4px;
	border: none;
	background: none;
	cursor: pointer;
	color: #6b7280 !important;
}

.vhf-cat-top.is-current > .vhf-cat-top-toggle {
	color: #111827 !important;
}

.vhf-cat-top-toggle[aria-expanded="true"] {
	color: #111827 !important;
}

.vhf-cat-top-caret {
	flex: none;
	width: 0;
	height: 0;
	border-left: 4px solid transparent;
	border-right: 4px solid transparent;
	border-top: 5px solid currentColor;
	color: #9ca3af;
	transition: transform 0.15s ease;
}

.vhf-cat-top-toggle[aria-expanded="true"] .vhf-cat-top-caret {
	transform: rotate(180deg);
	color: #111827;
}

.vhf-cat-card {
	padding: 0 0 8px 4px;
	margin: 0;
}

/* Sits next to the "Product Portfolio" heading, not nested in a card —
   only rendered once the current page is actually inside a
   subcategory, so it reads as "clear back to the top-level category"
   rather than a mystery link always present regardless of selection. */
.vhf-cat-reset {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	flex: none;
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: #6b7280;
	text-decoration: none;
}

.vhf-cat-reset::before {
	content: "×";
	font-size: 14px;
	line-height: 1;
}

.vhf-cat-reset:hover {
	color: #cd0d21;
}

.vhf-cat-group {
	margin: 4px 0;
}

/* Only the current category and its ancestors are bold AND dark — a
   group label or pill not on that path is plain weight and a lighter
   grey, so the active path actually stands out at a glance instead of
   everything reading as the same near-black text with only a subtle
   weight difference. Red is hover-only, on both states. */
.vhf-cat-group-label {
	display: flex;
	align-items: baseline;
	gap: 6px;
	font-size: 13px;
	font-weight: 400;
	color: #6b7280 !important;
	text-decoration: none;
	padding: 6px 0 6px 12px;
}

/* A group label (Katarakt — has its own children underneath, unlike a
   plain pill) sits at the same hierarchy level as the pills next to it
   (Glaukom, OP-Sets) and needs the same dash + indentation, per client
   feedback, even though it still expands to its own sub-row of pills
   rather than linking straight to a product list like a leaf pill
   does. */
.vhf-cat-group-label::before {
	content: "–";
	flex: none;
	color: #d1d5db;
	font-weight: inherit;
}

.vhf-cat-group-label:hover {
	color: #cd0d21 !important;
}

.vhf-cat-group-label.is-current {
	font-weight: 700;
	color: #111827 !important;
}

.vhf-cat-pill-row {
	display: block;
}

.vhf-cat-pill {
	display: flex;
	align-items: baseline;
	gap: 6px;
	padding: 6px 0 6px 12px;
	color: #6b7280 !important;
	font-size: 13px;
	font-weight: 400;
	line-height: 1.4;
	text-decoration: none;
}

/* A pill inside a .vhf-cat-group (e.g. IOL, under Katarakt) is one
   hierarchy level deeper than the group's own label (Katarakt) — it
   needs extra indentation to read as nested underneath it, rather
   than sitting at the same horizontal position as its parent. Pills
   in the top-level leaf row (Glaukom, OP-Sets — no parent group of
   their own) are unaffected, since they're not inside a .vhf-cat-group
   at all. */
.vhf-cat-group .vhf-cat-pill {
	padding-left: 24px;
}

.vhf-cat-pill::before {
	content: "–";
	flex: none;
	color: #d1d5db;
	font-weight: inherit;
}

.vhf-cat-pill:hover {
	color: #cd0d21 !important;
}

.vhf-cat-pill.is-current {
	font-weight: 700;
	color: #111827 !important;
}

.vhf-cat-pill.is-current::before {
	color: #111827;
}

.vhf-cat-group-label.is-current::before {
	color: #111827;
}

/* --- Tiered layout: Product Group as its own prominent row above
   the grid; Manufacturer (and future attributes) as refining filters
   in the sidebar card, alongside category. Two different kinds of
   decision get two different visual treatments, rather than being
   presented as equivalent choices in one row. --- */

.vhf-slot--tiered-group {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	gap: 16px;
	border-bottom: 2px solid #111827;
	padding-bottom: 20px;
	margin-bottom: 28px;
}

.vhf-slot--tiered-group .vhf-filter-toggle {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 6px;
	padding: 0;
	border: none;
	background: none;
	cursor: pointer;
	min-width: 200px;
}

.vhf-slot--tiered-group .vhf-filter-group-label {
	font-size: 12px;
	font-weight: 700;
	color: #111827;
}

.vhf-slot--tiered-group .vhf-filter-label-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 10px 14px;
	border: 2px solid #111827;
	border-radius: 6px;
	background: #fff;
	font-size: 13px;
	color: #374151;
	font-weight: 600;
}

.vhf-slot--tiered-group .vhf-filter-panel {
	position: absolute;
	top: calc(100% + 10px);
	left: 0;
	right: 0;
	z-index: 200;
	max-height: 360px;
	overflow-y: auto;
	padding: 18px 22px;
	border: 1px solid #d1d5db;
	border-radius: 8px;
	background: #fff;
	box-shadow: 0 10px 28px rgba(17, 24, 39, 0.1);
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
	gap: 4px 20px;
	align-content: start;
}

/* --- Selection summary: "You have selected: X, Y, Z" just above the
   grid — sits between the filter controls and the products regardless
   of which layout is active, so a visitor always knows what's
   currently filtering the grid even after a dropdown closes. Starts
   hidden (the shortcode itself renders [hidden]) and is toggled
   entirely by JS in updateSelectionSummary(). --- */

.vhf-selection-summary {
	/* Sits inside .vhf-layout--top/.vhf-toolbar's own flex row now
	   (alongside the filter buttons and Sort), rather than as a
	   separate block-level element — flex-basis: 100% forces it onto
	   its own line within that wrapping flex row instead of sitting
	   inline next to the last button. */
	flex-basis: 100%;
	margin: 10px 0 0;
	padding: 0;
	font-size: 13px;
	color: #374151;
	text-align: right;
}

.vhf-selection-summary-label {
	font-weight: 600;
	color: #111827;
	margin-right: 4px;
}

/* --- Product grid cards ---
   The default WooCommerce/Divi loop renders each product as a bare
   image + title with no card treatment at all. Styled to match the
   same bordered-card system used for Categories and Filters, so the
   whole page reads as one design rather than a styled sidebar next
   to unstyled default output.

   Deliberately NOT overriding ul.products to display: grid. An
   earlier version of this file did, to get clean gap-based spacing
   instead of doing the width/margin percentage math floats require —
   but Divi's own compiled + per-page dynamic CSS both still ship a
   full set of float-based width/margin/float rules for ul.products
   li.product at several breakpoints (this is how Divi's shop module
   has always laid out its grid), and those rules turned out to be
   completely unbeatable by any override in this file: confirmed via
   direct headless-Chrome testing that even a plain, maximally-specific
   selector with !important, injected as the literal last stylesheet
   on the live page, had zero effect on the rendered width — only
   setting the property directly via element.style (true inline style)
   ever worked. Rather than run a JS workaround on every page load and
   after every AJAX re-render just to fight a layout Divi already
   renders correctly on its own, this now works WITH Divi's native
   float grid: no display/width/margin overrides at all, just the
   card's visual styling (border, padding, hover, image sizing) layered
   on top of whatever box Divi's own CSS gives each <li>. */

/* Three products per row, consistently, on both the category archive
   template (post 730) and the Produktportfolio page (page 37) — per
   client feedback that the two pages showed a different column count.
   CSS Grid used here deliberately, a second attempt after an earlier
   one this session was reverted: that first attempt fought Divi's own
   float-grid CSS directly on ul.products/li.product with no reliable
   way to win the cascade. This time, grid is scoped to the real Divi
   ancestor chain (#et-boc .et-l .et_pb_shop, proven this session to
   actually out-specificity Divi's own rules) AND every product <li>
   carries .vhf-product-card, a class only this plugin's CSS ever
   references (added via the post_class filter in von-hoff-filters.php)
   — so grid handles both column count and row alignment natively,
   with no float/margin/nth-child math that can silently break when a
   card's height differs from its row neighbours (which is exactly what
   broke the earlier float-based attempt: floats don't wrap into evenly
   aligned rows the way grid does when items aren't all the same
   height). */
#et-boc .et-l .et_pb_shop ul.products {
	display: grid !important;
	grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
	gap: 16px !important;
	list-style: none;
}

/* WooCommerce's own clearfix (content:" "; display:table) on ::before
   and ::after was written for the old float-based product loop. Under
   display: grid it still generates as a real grid item, silently
   occupying the very first cell and pushing every product one slot to
   the right — the empty first square in the last screenshot. Not
   needed once the loop is a grid rather than floats, so switched off
   entirely. (This exact fix existed during the first grid attempt
   earlier this session and was removed along with everything else when
   that attempt was reverted — re-added here since it's needed again
   now that grid is back.) */
#et-boc .et-l .et_pb_shop ul.products::before,
#et-boc .et-l .et_pb_shop ul.products::after {
	content: none !important;
	display: none !important;
}

#et-boc .et-l .et_pb_shop ul.products li.product.vhf-product-card {
	width: auto !important;
	max-width: none !important;
	margin: 0 !important;
	float: none !important;
	clear: none !important;
}

@media (max-width: 767px) {
	#et-boc .et-l .et_pb_shop ul.products {
		grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
	}
}

@media (max-width: 479px) {
	#et-boc .et-l .et_pb_shop ul.products {
		grid-template-columns: minmax(0, 1fr) !important;
	}
}

/* Light grey border restored (was removed, then asked back per client
   feedback), and a fixed min-height so every card lines up evenly
   whether or not a product shows a price — WooCommerce only renders
   the .price element when a product has one set, so without a shared
   minimum, cards with a price are taller than cards without one and
   the row looks uneven. */
ul.products li.product {
	background: #fff;
	border: 1px solid #e5e7eb;
	border-radius: 8px;
	padding: 12px !important;
	box-sizing: border-box;
	min-height: 280px;
	display: flex;
	flex-direction: column;
}

/* .price only renders when a product actually has one set, so without
   this the <a> (image + title, always present) and .price (sometimes
   present) would otherwise be the only two children stacking unevenly
   inside the now-flex li. min-height above keeps every card the same
   overall height; margin-top: auto on .price pins it to the bottom of
   whichever card it's in, so titles align across a row regardless of
   how many text lines they wrap to, rather than .price floating
   directly under a short title while a long title's .price sits lower. */
ul.products li.product a {
	display: block;
	text-decoration: none;
}

ul.products li.product .price {
	margin-top: auto;
	padding-top: 8px;
}

/* Divi/WooCommerce renders the product thumbnail as <picture><source
   (avif)><img width="300" height="300" ...></picture>, not a bare
   <img>. Two earlier fixes here didn't work: sizing only the img
   left <picture> itself unstretched; adding width/height: 100%
   !important on both still didn't take effect, most likely because a
   percentage height on a flex child of an aspect-ratio-sized
   container (the previous display: flex + aspect-ratio: 1/1 setup) is
   a known fragile combination that doesn't reliably resolve across
   browsers. Switched to position: absolute + inset: 0 instead, which
   doesn't depend on percentage-height resolution at all — .et_shop_image
   is the positioned container (aspect-ratio still gives it its square
   shape) and picture/img are pinned to fill it directly. */
/* padding lives here only (not duplicated as inset on the picture
   below) — the picture fills 100% of the space padding leaves inside
   this box, rather than the two rules independently subtracting 24px
   each, which shrank the image to a few pixels when this container was
   still narrow (a symptom of the real bug above, not something wrong
   with this rule itself, but simplified regardless since one source
   of truth for the inset is safer than two that must stay in sync). */
ul.products li.product .et_shop_image {
	position: relative;
	aspect-ratio: 1 / 1;
	margin-bottom: 14px;
	padding: 24px;
	border-radius: 6px;
	overflow: hidden;
	background: #fff;
	box-sizing: border-box;
}

ul.products li.product .et_shop_image picture {
	position: absolute;
	inset: 0;
	display: block;
}

ul.products li.product .et_shop_image img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	display: block;
}

ul.products li.product .woocommerce-loop-product__title {
	font-size: 14px;
	font-weight: 600;
	color: #111827;
	margin: 0;
	line-height: 1.4;
	text-align: left;
}

@media (max-width: 640px) {
	ul.products {
		grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
		gap: 14px;
	}

	ul.products li.product {
		padding: 12px !important;
	}
}

/* --- Search: a real, always-visible input, not a dropdown button —
   renders inside .vhf-layout--top, which sits in its own full-width
   row above the sidebar/grid row, so it and the filter dropdowns/Sort
   read as one bar spanning the whole page rather than being confined
   to one column's width. Labelled "Produktsuche" to distinguish it
   from the separate site-wide search already in the main
   navigation. --- */

.vhf-category-tree {
	margin-top: 0 !important;
}


/* The [vhf_filter_bar slot="top"] row's own Divi block attributes
   already zero its own padding/margin, but Divi's row/column still
   leaves its default gap before the next row starts. Closing that
   default gap here — the deliberate small gap before the sidebar/grid
   row is added on .vhf-layout--top itself instead (margin-bottom,
   below), since padding-bottom on the Divi row wrapper here had no
   visible effect (Divi's row is a flex container sized to its content,
   not a box whose padding reliably shows as trailing space). */
.et_pb_row:has(> .et_pb_column > .et_pb_code .vhf-layout--top) {
	padding-top: 0 !important;
	padding-bottom: 0 !important;
	margin-bottom: 0 !important;
}

/* Kept for safety even though the real bug (below) turned out to be
   stacking order, not clipping — an open .vhf-filter-panel dropdown
   was rendering at full size in the right place but painting BEHIND
   the product grid, not cut off by any ancestor's overflow. */
.et_pb_section:has(> .et_pb_row > .et_pb_column > .et_pb_code .vhf-layout--top),
.et_pb_row:has(> .et_pb_column > .et_pb_code .vhf-layout--top),
.et_pb_column:has(> .et_pb_code .vhf-layout--top) {
	overflow: visible !important;
}

/* The dropdown lives in .et_pb_row_1_tb_body (the toolbar's own row);
   the product grid lives in a column of .et_pb_row_2_tb_body, a
   completely separate row below it. .vhf-filter-panel's z-index: 200
   only wins comparisons within its own stacking context — Divi's flex
   columns (et_flex_column) commonly create a new one of their own, so
   z-index set on the dropdown itself can't out-rank content sealed
   inside a sibling row's column. Raising the whole toolbar ROW's
   stacking context instead guarantees anything popping out of it (the
   dropdown) paints above the row below, regardless of what stacking
   contexts exist inside that other row's columns. Desktop-only
   (min-width: 641px): below that, .vhf-filter-panel switches to
   position: static (see the 640px breakpoint above) and just flows
   inline in normal document order, so there's no stacking conflict to
   fix — applying this row-level z-index unconditionally on mobile
   instead broke the page layout (content collapsed into a narrow
   column with dark margins either side), likely by putting this row
   into a new stacking/containing-block relationship that fought with
   the mobile menu/overlay system elsewhere on the page. */
@media (min-width: 641px) {
	.et_pb_row:has(> .et_pb_column > .et_pb_code .vhf-layout--top) {
		position: relative;
		z-index: 50;
	}
}

.et_pb_row:has(> .et_pb_column > .et_pb_code .vhf-layout--top) + .et_pb_row {
	margin-top: 0 !important;
}

/* Divi's own section flex container adds a row-gap between its child
   rows (separate from either row's own padding/margin), which is what
   was still showing as a blank strip below the toolbar even with both
   rows' own spacing zeroed out above. padding-top here closes down a
   further gap above the toolbar itself — Divi's default section
   preset (.preset--module--divi-section--default) sets its own
   padding-top/bottom via a CSS custom property (--gvid-ior5b4261x, a
   clamp() that's 50–100px depending on viewport), which the row-level
   padding overrides above never touched since it's set on the
   SECTION, not the row. Reduced to a deliberate small value rather
   than 0 — some breathing room above the toolbar is still wanted,
   just much less than Divi's default. */
.et_pb_section:has(> .et_pb_row > .et_pb_column > .et_pb_code .vhf-layout--top) {
	padding-top: 24px !important;
	row-gap: 0 !important;
	gap: 0 !important;
}

/* WooCommerce's own core stylesheet sets .woocommerce-breadcrumb to
   padding: 0 unconditionally (margin: 0 0 1em — bottom-only), which
   wins over the Divi block's own padding attributes regardless of
   what they're set to. Overriding the WooCommerce rule directly on
   the element itself. Lives inside the hero section's own column
   (first child, above the title), not a separate section — so this
   only needs to zero out WooCommerce's own spacing, not touch any
   section/row padding (that would wrongly zero out the hero's own
   64px padding too). */
.woocommerce-breadcrumb {
	padding-top: 0 !important;
	padding-bottom: 12px !important;
	margin: 0 !important;
}

/* Sizing only here — position/alignment (margin-right: auto, no
   padding of its own since it now sits inline inside .vhf-layout--top,
   which already provides the row's padding/border) is set on
   .vhf-layout--top .vhf-search-bar above. Width matches the sidebar
   column underneath it (6_24 of the 1_2,1_2 row's 24-unit grid = 25%),
   so the search box's edge lines up with the category tree's edge in
   the row below, rather than an arbitrary fixed width. */
.vhf-search-bar {
	width: 25%;
	max-width: 100%;
}

.vhf-search-input-wrap {
	position: relative;
}

.vhf-search-input {
	width: 100%;
	height: 40px;
	padding: 0 44px 0 18px;
	border: 1px solid #d1d5db;
	border-radius: 8px;
	background: #fff;
	color: #111827;
	font-size: 14px;
	line-height: 1.4;
	box-sizing: border-box;
}

.vhf-search-icon {
	position: absolute;
	right: 16px;
	top: 50%;
	transform: translateY(-50%);
	color: #cd0d21;
	pointer-events: none;
}

.vhf-search-input:focus {
	outline: none;
	border-color: #111827;
	box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.12);
}

.vhf-search-input::placeholder {
	color: #9ca3af;
}

/* --- Sort control: sits at the far right of the same horizontal row
   as the filter pills (Top layout only), matching the reference
   site's "Sortierung" dropdown position. "Sort by" is the select's own
   placeholder option, not a separate label. --- */

.vhf-sort-bar {
	display: flex;
	align-items: center;
	white-space: nowrap;
}

/* Base styling for the plain <select> — still used as a fallback for
   the brief moment before Select2 initialises (or if its JS fails to
   load for any reason), and as the sizing reference for the Select2
   container CSS below, which mirrors these exact values. */
.vhf-sort-select {
	height: 44px;
	padding: 0 32px 0 14px;
	border: 1px solid #d1d5db;
	border-radius: 8px;
	background: #fff;
	color: #111827;
	font-size: 13px;
	line-height: 1.4;
	cursor: pointer;
	appearance: none;
	box-sizing: border-box;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23374151' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 12px center;
}

.vhf-sort-select:focus {
	outline: none;
	border-color: #111827;
	box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.12);
}

@media (max-width: 640px) {
	.vhf-sort-bar {
		width: 100%;
	}

	.vhf-sort-select {
		width: 100%;
	}

	#vhf-sort-select + .select2-container {
		width: 100% !important;
	}
}

/* --- Select2 (replaces the plain <select> above): its own open
   options panel is a real, styled DOM element (unlike a native
   <select>'s browser-rendered one), so it can finally match
   Hersteller's dropdown exactly — same border colour, radius, and
   shadow — which was the actual point of switching to it. The plain
   .vhf-sort-select rules above still size the hidden original
   <select>; these mirror the same look onto Select2's own generated
   markup (.select2-container, .select2-selection, etc.), since
   Select2 renders its visible control as sibling elements next to the
   (now hidden) original, not by styling the <select> itself. --- */

/* Real DOM confirmed via computed-style debugging: Select2's
   containerCssClass option (set to vhf-select2-container in
   filter-bar.js) applies that class directly onto the element that
   ALREADY carries select2-selection/select2-selection--single — it's
   one compound element, not a wrapper around them. The earlier
   version of this block used a descendant combinator
   (".vhf-select2-container .select2-selection--single"), which never
   matched anything at all, silently leaving WooCommerce's own default
   Select2 styling in place (including its dark
   --wc-form-border-color border) — confirmed directly against the
   live page's actual computed border-color, which stayed
   rgba(32, 7, 7, 0.8) even with !important added. Every selector below
   is now compound (no space) to match the real single-element
   structure. */

/* The outer .select2-container span (Select2's real top-level wrapper,
   holding an inline width from its own auto-sizing) is a sibling
   generated right after the original, now-hidden <select> — targeted
   here via that relationship rather than vhf-select2-container, which
   only ever lands on the inner selection span, confirmed above. */
/* Fixed pixel width, not 100% or auto — per client feedback that the
   whole control visibly shifted width as a shorter/longer option got
   selected ("Name (A-Z)" vs. "Preis (absteigend)"). Sized to
   comfortably fit the longest real option label. Paired with
   width: 'style' in the JS Select2 init, which tells Select2 to
   respect this CSS width instead of computing its own from the
   selected option's text. */
#vhf-sort-select + .select2-container {
	width: 190px !important;
}

.vhf-sort-select {
	width: 190px;
}

.vhf-select2-container.select2-selection--single {
	height: 44px !important;
	padding: 0 32px 0 14px !important;
	border: 1px solid #d1d5db !important;
	border-radius: 6px !important;
	background: #fff;
	display: flex;
	align-items: center;
}

/* !important needed — confirmed via computed style that a WooCommerce
   default (likely #444, the same class of conflict as the border-color
   fix above) was winning over the plain version of this rule, keeping
   the text a lighter grey than the search input's own #111827. */
.vhf-select2-container .select2-selection__rendered {
	padding: 0;
	color: #111827 !important;
	font-size: 13px;
	line-height: 1.4;
}

.vhf-select2-container .select2-selection__arrow {
	height: 44px !important;
	right: 12px;
}

/* Kept the same light grey border on open as Hersteller's own trigger
   button uses at rest — no darker border/focus ring here, since that
   read as visually heavier than Hersteller and inconsistent with it,
   per client feedback. */
span[aria-expanded="true"].vhf-select2-container.select2-selection--single {
	border-color: #d1d5db !important;
}

/* The dropdown panel itself — appended to <body> by Select2, not
   nested inside .vhf-sort-bar, so it's styled globally by the
   dropdownCssClass set in filter-bar.js rather than scoped under
   .vhf-sort-bar the way the rest of this file's selectors are. */
.vhf-select2-dropdown {
	border: 1px solid #d1d5db !important;
	border-radius: 8px !important;
	box-shadow: 0 10px 28px rgba(17, 24, 39, 0.1);
	overflow: hidden;
}

.vhf-select2-dropdown .select2-results__option {
	padding: 10px 14px;
	font-size: 13px;
	color: #111827;
}

.vhf-select2-dropdown .select2-results__option--highlighted {
	background: #f4f4f4 !important;
	color: #111827 !important;
}

.vhf-select2-dropdown .select2-results__option[aria-selected="true"] {
	background: #f4f4f4;
	font-weight: 600;
}

/* --- Loading indicator: filter-bar.js sets aria-busy="true" on the
   grid's parent for the duration of every AJAX filter/search request
   and clears it afterwards — a spinner overlay hooks onto that
   existing attribute rather than a skeleton placeholder grid, so no JS
   changes are needed here. The current grid stays visible underneath
   (dimmed), rather than being blanked out, since a failed request
   leaves it in place. */
[aria-busy="true"] {
	position: relative;
	min-height: 120px;
}

[aria-busy="true"] > * {
	opacity: 0.4;
	pointer-events: none;
}

[aria-busy="true"]::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 36px;
	height: 36px;
	margin: -18px 0 0 -18px;
	border: 3px solid #e5e7eb;
	border-top-color: #cd0d21;
	border-radius: 50%;
	animation: vhf-spin 0.7s linear infinite;
}

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

/* --- Category description: bottom_title/bottom_text/bottom_button
   term meta, rendered via [vhf_category_description] with
   wp_kses_post() instead of Divi's own dynamic-content binding, since
   Divi forces that binding's HTML rendering off permanently (see the
   shortcode's own docblock in von-hoff-filters.php). Matches the
   heading/paragraph/button styling already used elsewhere on this
   template rather than introducing a new visual language. --- */
.vhf-category-description {
	margin: 24px 0 56px;
}

.vhf-category-description h2 {
	font-size: 1.5rem;
	line-height: 1.2em;
	margin: 0 0 12px;
	color: #111827;
}

.vhf-category-description p {
	margin: 0 0 12px;
	color: #374151;
	line-height: 1.6;
}

.vhf-category-description ul,
.vhf-category-description ol {
	margin: 0 0 12px;
	padding-left: 20px;
	color: #374151;
	line-height: 1.6;
}

.vhf-category-description a:not(.vhf-category-description-button) {
	color: #cd0d21;
}

/* margin-top matches the hero button's own top spacing (Divi CSS var
   --gvid-o5n17ey1pc, clamp(1.25rem, 0.893rem + 1.786vw, 2.5rem) —
   20-40px depending on viewport), per client feedback that this
   button sat too close to the final paragraph above it. Hover color
   matches the header button's blue (the site's secondary brand
   colour, --gcid-secondary-color) rather than a darker red. */
.vhf-category-description-button {
	display: table;
	margin-top: clamp(1.25rem, 0.893rem + 1.786vw, 2.5rem);
	padding: 12px 28px;
	background: #cd0d21;
	color: #ffffff !important;
	border-radius: 100px;
	text-decoration: none;
	font-weight: 600;
}

.vhf-category-description-button:hover {
	background: #0b4e80;
}

