/**
 * `bd/products-catalog` component CSS.
 *
 * Ships from the theme, not the plugin: per architecture.md §3.1/§3.2 the
 * theme owns markup and presentation. Ported from
 * `products.dc.html`'s `.fm-searchbar`/`.fm-prod-grid`/pill-button inline
 * styles, re-expressed against tokens.css — reasonable-fidelity, not
 * pixel-perfect, same instinct as this theme's other ported blocks
 * (`bd/site-header`/`bd/site-footer`, `bd/industry-tabs`).
 *
 * Grid breakpoints (3 col desktop / 2 col tablet / 1 col mobile) copy
 * `bd-card-grid__grid`'s own breakpoints (assets/css/blocks/card-grid.css)
 * exactly, so this block's grid behaves identically to every other card grid
 * in the theme rather than drifting to its own values.
 */

/*
 * The mockup runs the search bar's section flush against the hero above it
 * (`products.dc.html:46-48`: no margin between the two `<section>`s, and the
 * bar's own `padding: 40px 0 20px` is the whole gap). Here the block gets the
 * `bd-spacing-normal` chrome class *and* sits in a flow layout, so it arrived
 * with 24px of block-gap + 64px of chrome padding on top of the bar's own
 * padding — 112px above the search input against the mockup's 40px.
 *
 * So the section owns its own vertical rhythm, the same neutralise-the-chrome
 * move `.bd-page-header` and `.bd-hero` already make; the 96px foot is the
 * mockup's own `padding: 60px 0 96px` on the grid section below the bar.
 */
.bd-products-catalog {
	/*
	 * `!important` because WP's own global flow-gap rule
	 * (`:root :where(.is-layout-flow) > * { margin-block: 24px 0 }`) is printed
	 * inline in `<head>` at the same specificity as this class and wins on
	 * order — the 24px it adds is the mockup's zero gap.
	 */
	margin-block-start: 0 !important;
	padding-top: 0 !important;
	padding-bottom: var(--space-24) !important;
}

.bd-products-catalog__inner {
	/*
	 * No vertical padding here — the section's `bd-spacing-*` chrome class
	 * owns the rhythm. Setting it in both places stacked them and left ~64px
	 * of dead whitespace above and below this block on every page it appears.
	 */
	display: flex;
	flex-direction: column;
	gap: var(--space-16);
}

.bd-placeholder {
	color: var(--text-muted);
	font-style: italic;
}

/* --------------------------------------------------- search + pills == */

/*
 * Sticky, same as the mockup's own `.fm-searchbar` section. The docking itself
 * comes from `bd-sticky-under-header` in site-chrome.css, which pins it to the
 * measured header height rather than a second copy of `72px` — and, because
 * that class is also what header-height.js counts, keeps this bar included in
 * the anchor scroll offset. Only the bar's own layout is left here.
 */
.bd-products-catalog__bar {
	z-index: 20;
	/* The mockup section's own `padding: 40px 0 20px`. */
	padding: var(--space-10) 0 var(--space-5);
	/*
	 * The mockup's 60px grid-section `padding-top`, standardised up to the
	 * scale's 64px. It lives on the bar because full-bleed made the bar a
	 * sibling of `__inner` rather than a flex child of it, so there is no
	 * container `gap` left to carry the separation.
	 */
	margin-bottom: var(--space-16);
	background: var(--surface-page);
	border-bottom: var(--border-width) solid var(--border);
}

/*
 * The bar itself is full-bleed (it sits outside `__inner`); its content is
 * re-contained here. Full-bleed is load-bearing, not cosmetic: a container-width
 * bar left the page gutters transparent, so a hovered card's `--shadow-lg`
 * showed through beside the bar as it scrolled under.
 */
/*
 * `justify-content: center` is inert on one line — the field is `flex: 1` and
 * eats the slack, so there is none left to distribute. It only shows once the
 * bar wraps: the capped field and the pill row then each centre on their own
 * line instead of both hugging the left gutter under a wide empty right half.
 */
.bd-products-catalog__bar-inner {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--space-4);
}

/*
 * `flex: 1` for the width it takes, `max-width` for the width it refuses.
 *
 * The bar wraps once the pills no longer fit beside the field — around 1120px
 * with the current category names. Without the cap the field then grew into the
 * whole of its own row: a 1000px input stacked above a short line of pills,
 * which reads as a broken layout rather than a search box.
 *
 * The cap has to sit on `max-width` rather than the flex basis. A basis of
 * `320px` is the size the field asks for when the line is measured, so it makes
 * the bar wrap ~70px earlier than it needs to — the field is happy to be
 * narrower than 320px while both still fit on one line, and only the
 * zero-basis `flex: 1` expresses that.
 */
.bd-products-catalog__search {
	position: relative;
	flex: 1;
	/*
	 * The floor is the placeholder, not a round number: "Search products" is
	 * ~124px at `--fs-base`, plus the 42px inset for the magnifier and the 16px
	 * right padding. That arithmetic gives 182px and it is not enough — at
	 * 195px the trailing "s" was still being clipped, because the measured text
	 * width is the glyph advance and the field needs the caret's width and a
	 * pixel of side bearing on top of it. 220px is the width at which the
	 * placeholder is whole with room to spare; below it the field stops giving
	 * ground and the bar wraps instead, which is the cheaper of the two.
	 */
	min-width: 200px;
	max-width: 320px;
}

/* Visually hidden, still announced: the search field needs a real label. */
.bd-products-catalog__search-label {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.bd-products-catalog__search-input {
	width: 100%;
	height: 46px;
	/* Room for the inset magnifier. */
	padding: 0 var(--space-4) 0 42px;
	border: var(--border-width) solid var(--border-strong);
	border-radius: var(--radius-md);
	font-family: var(--font-sans);
	/*
	 * Mockup is a raw 15px/400; `--fs-base` (15 → 16) is the scale step that
	 * standardises it. `--fs-md` (16 → 18) was a step too big and made the
	 * field read heavier than the pills next to it.
	 */
	font-size: var(--fs-base);
	font-weight: var(--fw-regular);
	color: var(--text-primary);
	background: var(--surface-page);
	box-sizing: border-box;
}

.bd-products-catalog__search-input:focus {
	outline: none;
	border-color: var(--color-primary);
	box-shadow: var(--shadow-focus);
}

/*
 * Inline flow rather than a flex row, so the rows can be balanced.
 *
 * `text-wrap: balance` evens out the lines of a *block* container's inline
 * content; it has no effect on flex line-breaking. As a flex row the six pills
 * broke 5 + 1, leaving "Software" alone on a second line under a full one.
 * Inline-blocks in a balanced block break 3 + 3 instead.
 *
 * The cost of leaving flex is that `gap` no longer applies, so the spacing
 * moves onto the pills as a 4px margin (8px between two of them, the
 * `--space-2` the gap was). `font-size: 0` collapses the source whitespace
 * between the anchors — the line still *breaks* there, it just no longer adds
 * a stray space to the margin — and `line-height: 0` stops the inline boxes
 * sitting on a text baseline taller than they are.
 *
 * Browsers without `text-wrap: balance` fall back to ordinary inline wrapping:
 * the same 5 + 1 as before, never a broken bar.
 */
.bd-products-catalog__pills {
	display: block;
	/* Centred for the same reason as the bar: only visible once they wrap. */
	text-align: center;
	text-wrap: balance;
	font-size: 0;
	line-height: 0;
}

/*
 * The pills are `<a>` elements, not `<button>`s — each one links to that
 * category's archive (`/products/scanning/`), so the selection lives in the URL
 * and is shareable, linkable from the nav, and crawlable. See the PILLS ARE
 * LINKS note in blocks/products-catalog.php.
 *
 * `display: inline-flex` + `align-items: center` replace the vertical centring
 * a `<button>` gets from the UA stylesheet for free; without them the label
 * sits on the text baseline and rides high inside the 38px capsule.
 * `text-decoration: none` likewise: `appearance: none` never applied to an
 * anchor, and the underline is the giveaway that this rule was written for a
 * button.
 */
.bd-products-catalog__pill {
	appearance: none;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	vertical-align: middle;
	text-decoration: none;
	height: 38px;
	/* Half of `--space-2`: two adjacent margins make the row's old 8px gap. */
	margin: var(--space-1);
	padding: 0 var(--space-5);
	border: var(--border-width) solid var(--border-strong);
	border-radius: var(--radius-pill);
	background: var(--surface-page);
	color: var(--text-secondary);
	font-family: var(--font-sans);
	font-weight: var(--fw-semibold);
	font-size: var(--fs-sm);
	white-space: nowrap;
	transition: var(--transition-base);
}

.bd-products-catalog__pill:hover {
	border-color: var(--color-primary);
	color: var(--color-primary);
}

.bd-products-catalog__pill.is-active {
	border-color: var(--color-primary);
	background: var(--color-primary);
	color: var(--text-inverse);
}

/* ------------------------------------------------------------ sections == */

.bd-products-catalog__sections {
	display: flex;
	flex-direction: column;
	gap: var(--space-16);
}

.bd-products-catalog__section[hidden] {
	display: none;
}

/*
 * NO MEASURE CAP — the head runs the full container width, same as the card
 * grid under it.
 *
 * It used to be held at `48em` (~768px) on the usual readable-measure
 * argument, which left ~460px of dead space to its right against a ~1232px
 * grid and read as copy hugging the left edge. A cap is only worth a number if
 * that number buys readability, and here it cannot: `.bd-container` is already
 * capped at `--container-xl` (1280px, ~1232px inside its gutters), so the
 * widest this can ever get is ~155 characters — an intermediate cap like 72em
 * would give ~145, past the comfortable 45-90 range either way. So the cap was
 * only ever an inset, and an arbitrary one. The container is the measure.
 */
.bd-products-catalog__section-head {
	margin-bottom: var(--space-8);
	padding-top: var(--space-5);
	border-top: var(--border-accent-width) solid var(--color-primary);
}

.bd-products-catalog__heading {
	font-size: var(--fs-2xl);
	font-weight: var(--fw-extrabold);
	letter-spacing: var(--ls-tight);
	color: var(--text-primary);
	margin: 0 0 var(--space-2);
}

/*
 * The short coloured line directly under the section heading — the term's
 * `description`. Blue, per products.dc.html; it reads as a strapline for the
 * category rather than as body copy, which is what distinguishes it from the
 * `__intro` paragraph below it.
 *
 * Its own class rather than reusing `.bd-products-catalog__tagline`: that one
 * styles a *product card's* tagline at `--fs-sm`/secondary, and sharing the
 * name would couple two things that only coincidentally read alike today.
 */
.bd-products-catalog__section-tagline {
	font-size: var(--fs-md);
	line-height: var(--lh-relaxed);
	/* 500 in the export (products.dc.html §68), not 600 — at this size the
	   heavier weight made the strapline compete with the h2 above it. */
	font-weight: var(--fw-medium);
	color: var(--color-primary);
	margin: 0 0 var(--space-3);
	/*
	 * Wrapping comes from tokens.css's site-wide `text-wrap: pretty`. Measured
	 * at this block's then-768px measure (1440px viewport, Automated Solutions'
	 * strapline) — the head is full-width now, so the word counts have moved,
	 * but the ranking of the three modes has not:
	 *
	 *   default   11 words / 1  — "metrology." hanging alone
	 *   balance     5 words / 7  — even halves, first line ends early
	 *   pretty     10 words / 2  — full first line, "3D metrology." below
	 *
	 * which is the measurement the site-wide choice rests on.
	 */
}

/*
 * The long paragraph under the strapline — the term description.
 * Runs the container's full width, like the rest of `__section-head` — the
 * container cap is what bounds it.
 *
 * `--fs-base` (15 → 16), a step below the strapline: the export sets 15px here
 * against the strapline's 16.5 (products.dc.html §68-69), so the two lines are
 * deliberately different sizes. `--fs-md` for both flattened that.
 */
.bd-products-catalog__intro {
	font-size: var(--fs-base);
	line-height: var(--lh-relaxed);
	color: var(--text-secondary);
	margin: 0;
}

/*
 * The intro arrives as `wpautop()`-generated paragraphs (see the block), so the
 * gap between them is a real margin rather than the full blank line
 * `white-space: pre-wrap` used to produce.
 */
.bd-products-catalog__intro p {
	margin: 0;
}

.bd-products-catalog__intro p+p {
	margin-top: var(--space-3);
}

/* ---------------------------------------------------------------- grid == */

.bd-products-catalog__grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--space-6);
}

.bd-products-catalog__card {
	display: flex;
	flex-direction: column;
	border: var(--border-width) solid var(--border);
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: var(--surface-page);
	text-decoration: none;
	color: inherit;
	transition: var(--transition-base);
}

.bd-products-catalog__card:hover {
	transform: translateY(-4px);
	box-shadow: var(--shadow-lg);
	border-color: var(--border-strong);
}

.bd-products-catalog__card[hidden] {
	display: none;
}

.bd-products-catalog__media {
	height: 190px;
	background: var(--surface-subtle);
	overflow: hidden;
}

.bd-products-catalog__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.bd-products-catalog__content {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	padding: var(--space-6);
	flex: 1;
}

/*
 * No `__kicker` rule: the small blue uppercase line above each product name was
 * removed from the card on client feedback (it read as confusing next to the
 * product name). The value is still carried in the block's Interactivity
 * context so search keeps matching on it — see blocks/products-catalog.php.
 */

.bd-products-catalog__name {
	font-size: var(--fs-md);
	font-weight: var(--fw-bold);
	letter-spacing: var(--ls-tight);
	color: var(--text-primary);
	margin: 0;
}

.bd-products-catalog__tagline {
	font-size: var(--fs-sm);
	line-height: var(--lh-relaxed);
	color: var(--text-secondary);
	margin: 0;
}

.bd-products-catalog__cta {
	margin-top: auto;
	padding-top: var(--space-2);
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	color: var(--color-primary);
	font-weight: var(--fw-semibold);
	font-size: var(--fs-sm);
}

/* ----------------------------------------------------------- empty state == */

.bd-products-catalog__empty {
	text-align: center;
	padding: var(--space-16) 0;
	color: var(--text-secondary);
	font-size: var(--fs-md);
}

.bd-products-catalog__empty[hidden] {
	display: none;
}

/*
 * The "search all products" escape hatch, shown inside the empty state on a
 * category URL only — where a search can find nothing simply because the
 * matching product lives in another category.
 */
.bd-products-catalog__empty-link {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	margin-left: var(--space-2);
	color: var(--color-primary);
	font-weight: var(--fw-semibold);
	text-decoration: none;
}

.bd-products-catalog__empty-link:hover {
	text-decoration: underline;
}

/*
 * The pills keep their 20px padding at every width, on purpose.
 *
 * Two steps of tighter padding (12px, then 8px) did hold the bar on one line
 * down to ~1060px, but the capsules read as cramped for the whole 1000-1200px
 * range to buy it — a worse trade than the second row, which is centred and
 * costs one line of a bar that is only ever glanced at. Below ~1200px the bar
 * simply wraps: field on top, all six pills on one row under it.
 */
@media (max-width: 860px) {
	.bd-products-catalog__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 560px) {
	.bd-products-catalog__grid {
		grid-template-columns: 1fr;
	}

	/*
	 * The desktop cap exists to stop the field eating a whole row next to the
	 * pills. On phones the field *is* the row, so the cap only leaves dead
	 * space at the right of the gutter.
	 */
	.bd-products-catalog__search {
		max-width: none;
	}

	/*
	 * Packed from the left, not balanced.
	 *
	 * Balancing assumes the rows it evens out are close to equal already. Six
	 * capsules of six different widths in a 342px column are not: balancing
	 * them just moves the raggedness around (2 / 1 / 3 on a 390px phone) and
	 * leaves a lone centred category reading as a heading for the row beneath.
	 * Greedy left-packed wrapping fills each line as far as it goes and keeps
	 * every pill on the same left edge as the search field above them.
	 */
	.bd-products-catalog__pills {
		text-wrap: wrap;
		text-align: left;
	}

	/*
	 * No `top: 0` override here. The header stays `position: fixed` at every
	 * width, so docking this bar at 0 parked its first 72px permanently behind
	 * the header — the search field was the part that disappeared. It docks at
	 * `var(--header-h)` on mobile for the same reason it does on desktop.
	 */
}

.bd-products-catalog__search-icon {
	position: absolute;
	left: 14px;
	top: 50%;
	transform: translateY(-50%);
	color: var(--text-muted);
	pointer-events: none;
}

/* The arrow is drawn by `.bd-arrow::after` (tokens.css); this just lets it
   sit on the same baseline as the label. */
.bd-products-catalog__cta {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
}

.bd-products-catalog__card:hover .bd-arrow::after {
	transform: translateX(4px);
}