/**
 * WooCommerce presentation.
 *
 * WooCommerce block themes render the catalogue through the Product Collection / Product Template
 * blocks, which ship their own unstyled-ish defaults. This file maps that markup onto the Claude
 * Design kit's ProductCard and ProductScreen, using only tokens from tokens.css.
 *
 * Enqueued by inc/enqueue.php, and only in a WooCommerce context — editorial pages never load it.
 */

/* ============================================================== catalogue grid ==== */

/*
 * `loop_shop_columns` cannot set this in a block theme — the Product Template block hardcodes a
 * `columns-N` class — so the grid is corrected here. The selector carries a tag prefix purely to
 * outrank WooCommerce's own `.columns-3` rule.
 *
 * auto-fill against the kit's minmax(230px) track rather than a fixed column count. Since the
 * filter sidebar landed, the results column is ~885px rather than the full width, and a hardcoded
 * four gave 209px cards — too narrow for the card's own two-button action row. Letting the track
 * decide keeps the card at its designed size whatever the column is doing.
 */
ul.wc-block-product-template,
ul.wc-block-product-template.columns-1,
ul.wc-block-product-template.columns-2,
ul.wc-block-product-template.columns-3,
ul.wc-block-product-template.columns-4,
ul.wc-block-product-template.columns-5,
ul.wc-block-product-template.columns-6 {
	/*
	 * `display: grid` must be declared here, not inherited from WooCommerce's default (audit V-30).
	 *
	 * This rule set grid-template-columns and nothing else, which worked on the shop archive only
	 * because that Product Template happens to default to grid. The **related products** collection
	 * on every product page is configured flex, so WooCommerce emits `is-flex-container` and its own
	 * inline `.wc-block-product-template.is-flex-container { display: flex }` applied — making
	 * `grid-template-columns` inert, because a grid property on a flex container does nothing.
	 *
	 * The result was five related-product cards at 1185x1329 each: full container width, taller than
	 * a laptop screen, 6,741px stacked — 79% of the entire product page.
	 *
	 * This selector is (0,2,1) against their (0,2,0), so it already outranked them; it just never
	 * said `display`. Declaring it is the whole fix, and it is a no-op on the archive, which was
	 * already grid.
	 */
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
	gap: var(--space-4);
	margin: 0;
	padding: 0;
	list-style: none;
}

.woocommerce ul.products {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
	gap: var(--space-4);
	margin: 0;
	padding: 0;
	list-style: none;
}

.woocommerce ul.products::before,
.woocommerce ul.products::after { content: none; }

/* ================================================================ product card ==== */

/* Both the block loop (li.wc-block-product) and the classic loop (li.product) get the card. */
li.wc-block-product,
.woocommerce ul.products li.product {
	display: flex;
	flex-direction: column;
	gap: 0;
	width: auto !important;   /* WooCommerce's classic float grid sets a percentage width. */
	margin: 0 !important;
	float: none !important;
	background: var(--surface-card);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-lg);
	overflow: hidden;
	transition: var(--transition-surface);
	text-align: left;
}

li.wc-block-product:hover,
.woocommerce ul.products li.product:hover { box-shadow: var(--shadow-md); }

/* Media panel — contained on a tint, matching the kit's 4:3 product frame. */
li.wc-block-product .wc-block-components-product-image,
.woocommerce ul.products li.product a img {
	margin: 0;
	background: var(--surface-subtle);
	border-bottom: var(--border-width) solid var(--border-subtle);
}

/*
 * Square, not the kit's 4:3 — a client decision, and the right one for a catalogue of manufacturer
 * shots that mostly arrive square.
 *
 * archive-product.html now sets the Product Image block's own `aspectRatio` and `scale` attributes,
 * so the !important that used to be needed here is gone: the block writes those as inline styles
 * and a stylesheet could not otherwise reach them. `contain` matters as much as the ratio —
 * `cover` crops manufacturer photography that already ships with its own padding.
 *
 * The classic-loop selector keeps the declarations, since related products and shortcode loops
 * render without the block's attributes.
 */
li.wc-block-product .wc-block-components-product-image img,
.woocommerce ul.products li.product a img {
	width: 100%;
	height: auto;
	padding: var(--space-4);
	border-radius: 0;
	display: block;
}

.woocommerce ul.products li.product a img {
	aspect-ratio: 1 / 1;
	object-fit: contain;
}

/* Everything below the image shares one padded column. */
/*
 * `.wp-block-woocommerce-product-image`, not `.wc-block-components-product-image`: the front-end image
 * carries both, but in the Site Editor the card's direct child is the block's edit wrapper, which
 * carries only the first. Keyed on the second, the editor padded the image and left the brand flush
 * against it (review, session 56).
 */
li.wc-block-product > :not(.wp-block-woocommerce-product-image),
.woocommerce ul.products li.product > :not(a:first-of-type, .fb-card-actions) {
	padding-inline: var(--space-4);
	text-align: left;
	margin-block: 0;
}

/*
 * The space between the image and the text belongs to the image, not to whichever text row comes
 * first (session 56).
 *
 * The rule here used to be `:not(image):first-of-type { padding-top }`, meant for "the first text
 * row". But `:first-of-type` counts by tag, and the image block is a `<div>`, so the brand line — the
 * first text row, also a `<div>` — never matched. The title did, being the first `<h2>`. The brand
 * therefore sat flush against the photo (0px, measured) with the 16px under it instead of above it,
 * and a card without a brand started its text 16px higher than one with.
 */
li.wc-block-product > .wp-block-woocommerce-product-image { margin-bottom: var(--space-4); }

/*
 * The classic card keeps image, brand and title inside its product link, so those two text rows
 * need the padding the rule above only reaches direct children with. The image is excluded: it is
 * full-bleed against the card edge in both loops.
 */
.woocommerce ul.products li.product > a:first-of-type > :not(img) {
	padding-inline: var(--space-4);
	text-align: left;
}

/*
 * The Product Template block ships its title with `has-medium-font-size`, whose generated class
 * carries `!important` — so without one here the card title rendered at core's fluid Medium
 * (14px→20px with the viewport) instead of the kit's fixed 14px. Same reason the price rule
 * below needs one.
 */
li.wc-block-product .wp-block-post-title,
.woocommerce ul.products li.product .woocommerce-loop-product__title {
	font-family: var(--font-body);
	font-size: var(--text-body-sm) !important;
	font-weight: var(--fw-semibold);
	line-height: var(--lh-snug);
	letter-spacing: 0;
	text-align: left;
	text-wrap: pretty;
	margin: var(--space-1) 0 0;
	padding-top: 0;
}

li.wc-block-product .wp-block-post-title a,
.woocommerce ul.products li.product .woocommerce-loop-product__title {
	color: var(--text-primary);
	text-decoration: none;
}

li.wc-block-product .wp-block-post-title a:hover { text-decoration: underline; }

li.wc-block-product .wp-block-woocommerce-product-price,
.woocommerce ul.products li.product .price {
	font-family: var(--font-display);
	font-size: var(--text-h3) !important;
	font-weight: var(--fw-bold);
	letter-spacing: var(--ls-heading);
	color: var(--text-primary);
	text-align: left;
	margin: var(--space-3) 0 0;
}

li.wc-block-product .wp-block-woocommerce-product-price .wc-block-components-product-price__value { font-size: inherit; }

/* Metadata injected by the theme's loop hooks (brand, SKU, certifications, stock). */
.fb-loop-brand {
	font-size: var(--text-micro);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
	color: var(--text-muted);
	margin-top: var(--space-4);
}

/* Inside the block card the wrapper carries the top padding; the margin would double it. */
.fb-product-meta .fb-loop-brand { margin-top: 0; }

.fb-loop-sku {
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	color: var(--text-muted);
	margin-top: var(--space-1);
}

.fb-loop-certs {
	display: flex;
	gap: var(--space-1);
	flex-wrap: wrap;
	margin-top: var(--space-3);
}

.fb-loop-stock { margin-top: var(--space-3); }

/*
 * Actions at the card foot, with the two CTAs side by side as the kit has them: Add to Cart takes the
 * space, Quote takes what it needs.
 *
 * `margin-top: auto` pins them on the classic card. On the block card the price now carries the auto
 * margin instead, so price, stock and buttons travel as one group — see "card rows" below.
 */
li.wc-block-product .fb-card-actions,
.woocommerce ul.products li.product .fb-card-actions {
	display: flex;
	gap: var(--space-2);
	padding-inline: var(--space-4);
	margin-top: auto;
	padding-bottom: var(--space-4);
	padding-top: var(--space-3);
}

li.wc-block-product .fb-card-actions > *,
.woocommerce ul.products li.product .fb-card-actions > * { margin: 0; min-width: 0; }

/*
 * The two loops name their buttons differently — the block card wraps Add to Cart in a block, the
 * classic card emits WooCommerce's own `a.button` — so both are listed. The rule is the same one:
 * Add to Cart takes the space, Quote takes what it needs.
 */
li.wc-block-product .fb-card-actions .wp-block-woocommerce-product-button,
.woocommerce ul.products li.product .fb-card-actions > .button,
.woocommerce ul.products li.product .fb-card-actions > .added_to_cart { flex: 1; }

li.wc-block-product .fb-card-actions .wp-block-fischer-bell-add-to-quote,
.woocommerce ul.products li.product .fb-card-actions > form.fb-quote-add { flex: 0 0 auto; }

/*
 * A quote-only product has no Add to Cart, so the quote button is the only child and takes the
 * full width — which is the kit's quote-only card exactly.
 */
li.wc-block-product .fb-card-actions .wp-block-fischer-bell-add-to-quote:only-child { flex: 1; }

/*
 * Side by side only while Add to cart keeps a usable width; otherwise Quote drops beneath it, full
 * width — the phone's stack, reached by the card's own width rather than the viewport's (client: "the
 * quantity is still overflowing and break its border").
 *
 * Add to cart used to take whatever Quote left, and between about 1100 and 1250px, or 861 and 960px,
 * that was 93–100px: room for the words, and "Select options" in two lines, but not for the − n +
 * control it turns into, whose two 44px steps left the number a 9px box. The basis is that control's
 * minimum — both steps and four digits — so a trade quantity of 1000 still reads: "1000" is 33.6px
 * in the input's semibold, plus 8px of padding and two hairline borders, so 2.875rem leaves 2px spare.
 * Measured, not rounded up — 3rem stacked the row at 1280px, a common laptop, by a fraction of a
 * pixel. Every card in a row
 * is the same width and every Quote the same label, so a row wraps together or not at all; and the
 * basis is the same before and after adding to cart, so pressing it never moves anything.
 *
 * The grow factors keep the kit's rule on one line — Add to cart takes the space, Quote what it needs
 * — and let Quote take the whole line once it is alone on it.
 */
li.wc-block-product .fb-card-actions { flex-wrap: wrap; }

li.wc-block-product .fb-card-actions .wp-block-woocommerce-product-button { flex: 999 1 calc(2 * var(--tap-min) + 2.875rem); }

li.wc-block-product .fb-card-actions .wp-block-fischer-bell-add-to-quote { flex: 1 0 auto; }

/*
 * `:only-child` cannot do this job on the classic card: WooCommerce emits an out-of-flow
 * `span.screen-reader-text` beside the buttons, so the quote form is never an only child even on a
 * product that has no Add to Cart. Ask the question that is actually being asked — "is there a
 * cart button in this row?" — rather than counting elements.
 */
.woocommerce ul.products li.product .fb-card-actions:not(:has(> .button)) > form.fb-quote-add { flex: 1; }

/*
 * The quote form defaults to inline-block, so it shrank to its label inside the flex child and the
 * button's `width: 100%` then resolved against *that* rather than the card. On a quote-only card,
 * where the button should span the full width, it came out two-thirds wide.
 */
li.wc-block-product .fb-card-actions form.fb-quote-add {
	display: block;
	width: 100%;
	margin: 0;
}

.woocommerce ul.products li.product .fb-card-actions > form.fb-quote-add {
	display: block;
	width: auto;
	margin: 0;
}

/* With no cart button beside it the quote form is the row, so it takes the width back. */
.woocommerce ul.products li.product .fb-card-actions:not(:has(> .button)) > form.fb-quote-add { width: 100%; }

li.wc-block-product .fb-card-actions .fb-btn,
li.wc-block-product .fb-card-actions .wc-block-components-product-button__button,
.woocommerce ul.products li.product .fb-card-actions .fb-btn,
.woocommerce ul.products li.product .fb-card-actions > .button { width: 100%; }

/*
 * The card's Add to cart, and the − n + control it turns into once the product is in the cart
 * (inc/card-cart.php, card-cart.js; client, 2026-09-27). The control takes the button's place and its
 * size exactly — same slot, same height — so a card never grows when something is added, which is the
 * layout WooCommerce's "View cart" link broke.
 *
 * `[hidden]` has to be restated: the button carries `display: inline-flex !important` from the CTA
 * rules above, which beats the browser's own `[hidden]` rule, so without this both would show.
 *
 * The control is the cart's own stepper (`.fb-qty`, "quantity stepper" below), stretched to the slot:
 * the number takes whatever width − and + leave.
 */
.fb-card-cart [hidden] { display: none !important; }

li.wc-block-product .fb-card-actions .fb-card-cart__qty {
	display: flex;
	width: 100%;
	height: var(--control-h-md);
	min-height: var(--tap-min);
}

li.wc-block-product .fb-card-cart__qty .quantity {
	flex: 1 1 auto;
	min-width: 0;
}

/*
 * Inside the border, not 44px each (client: "the quantity button has been cut off"). The control is
 * 44px tall border included, level with Quote beside it; − and + kept the cart stepper's own 44px
 * minimum, so they and the number stood 1.3px taller than the space inside the border and painted
 * over its bottom edge — the box never closed. Stretched to the inside instead: the whole control is
 * still the 44px target.
 */
li.wc-block-product .fb-card-cart__qty .fb-qty__step {
	min-height: 0;
	height: auto;
}

/*
 * The number too (client, a second time: "the border is still missing"). `.woocommerce .quantity
 * input.qty` gives every quantity field `min-height: var(--tap-min)`, which beat `height: 100%`: the
 * field stood 44px in a 42px inside and its white background painted over the bottom border beneath
 * the number. The first fix measured the field's wrapper, which was 42px, not the field.
 */
li.wc-block-product .fb-card-cart__qty .quantity input.qty {
	width: 100%;
	min-width: 0;
	min-height: 0;
	height: 100%;
	font-weight: var(--fw-semibold);
}

/*
 * "Added to cart · View cart" (card-cart.js). The quote list's toast, restated for the cart: same
 * place, 88px up so it clears the phone buy bar; same ink panel and green link; same fade. The two
 * actions of collecting a product confirm the same way.
 *
 * Unlike the quote toast it also leaves the page when it fades: `visibility` goes with the opacity,
 * so an invisible toast cannot take a click meant for the card beneath it or be read out again.
 */
.fb-toast {
	position: fixed;
	right: 20px;
	bottom: 88px;
	z-index: 70;
	display: flex;
	align-items: center;
	gap: var(--space-3);
	max-width: min(320px, calc(100vw - 40px));
	padding: var(--space-3) var(--space-4);
	background: var(--fb-ink);
	color: var(--text-inverse);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-lg);
	font-size: var(--text-body-sm);
	transform: translateY(8px);
	opacity: 0;
	visibility: hidden;
	transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out), visibility 0s linear var(--dur-base);
}

.fb-toast.is-visible {
	opacity: 1;
	visibility: visible;
	transform: none;
	transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out), visibility 0s;
}

.fb-toast a { color: var(--fb-green); font-weight: var(--fw-semibold); white-space: nowrap; }
.fb-toast--error { background: var(--status-danger); }

/*
 * "Only 3 in stock" (client, 2026-09-27): something to notice, not something that failed, so the
 * warning palette rather than the error red — pale amber, an amber edge, ink text.
 */
.fb-toast--warning {
	background: var(--status-warning-bg);
	color: var(--text-primary);
	border: var(--border-width) solid var(--status-warning);
}

/* The header's cart count, when a card changes it: a brief pulse so the eye finds the new number. */
.fb-header-action--cart .fb-count.is-bumped { animation: fb-count-bump var(--dur-slow) var(--ease-out); }

@keyframes fb-count-bump {
	0% { transform: scale(1); }
	40% { transform: scale(1.35); }
	100% { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
	.fb-toast,
	.fb-toast.is-visible { transition: none; }

	.fb-header-action--cart .fb-count.is-bumped { animation: none; }
}

/* ================================================================== card rows ==== */

/*
 * Price and stock status line up across every card in a row (client, 2026-09-26).
 *
 * They did not, because only the buttons were pinned to the card's foot. Price and stock simply
 * followed whatever sat above them, so they moved with it. Measured on page 1 at 1440px:
 * - a card with no brand line had its price and stock 16px higher than its neighbours;
 * - a two-line title pushed them 17px lower;
 * - the ExoFit's "Sign in to see wholesale pricing" doubled its price block;
 * - the 103 unpriced products render an empty price, so their stock label rides up into the gap.
 *
 * Two layers.
 *
 * 1. **The design kit's own card**, as the base. `ProductCard.jsx` groups price, stock and buttons
 *    and gives the group `marginTop: 'auto'`, so all three sit at the foot and the free space
 *    goes above them. Here that is the price block's auto margin, and the buttons' margin comes
 *    off. The 12px the price's old margin gave is kept as padding, so the tallest card in a row
 *    still has the gap.
 * 2. **A subgrid**, wherever the browser has one — every current browser. Each card spans seven
 *    rows of the product grid and takes them as its own, so every card in a row shares one height
 *    per row: image, brand, title, SKU, price, stock, buttons. Every price starts on the same line,
 *    and so does every stock status, even beside a two-line title, a missing brand, a price with a
 *    trade prompt under it, or no price at all. Layer 1 cannot do the last two: bottom-anchoring
 *    lines up the stock row, but a two-line price then starts higher than a one-line one.
 *
 * **Rows follow the blocks' order, so the card stays editable.** Every card renders the same seven
 * blocks. `fischer_bell_render_product_meta()` prints an empty placeholder where a product has no
 * brand or SKU, rather than nothing, so the grid can simply place them in order, and a block moved
 * in the Site Editor moves on the page. A first version placed rows by class name instead. An
 * independent review found that this ignored any reorder, collided rows for a meta block given two
 * parts, and gave a block the client *added* nowhere to go: it was squeezed into the last row, on
 * top of the buttons.
 *
 * **And only a card made of exactly those blocks becomes a subgrid.** The guard below — no child
 * outside the known set, and no eighth child — means an added block, or the Site Editor's own
 * markup, where the meta blocks render as notes, gets the Layer 1 card instead of an overlap. Losing
 * row alignment is visible and harmless; losing the buttons under a paragraph was neither.
 * **Adding a block to this card means adding its class to the list, and 7 becomes 8.**
 *
 * **The subgrid is scoped to grids that draw this card, and that is not optional:** the eStore's
 * `.fb-catalog__results`, the product page's `.fb-related-products` (patterns/related-products.php)
 * and the product search results' `.fb-search-results` (templates/product-search-results.html),
 * all three drawing this same card. Any other Product Template carries WooCommerce's own contents. When
 * related products still did — image, title, price and a plain button, with no brand, no SKU and no
 * `.fb-card-actions` — the unscoped subgrid auto-placed the unplaced button into the empty brand row
 * and rendered it *above the product name* (measured: button at 259px, title at 303px). Layer 1
 * stays global: on such cards it puts price and button together at the foot, which is the kit's card.
 */
li.wc-block-product > .wp-block-woocommerce-product-price {
	margin-top: auto;
	padding-top: var(--space-3);
}

li.wc-block-product > .fb-card-actions { margin-top: 0; }

@supports (grid-template-rows: subgrid) {
	/*
	 * The guard is `:has()`, which every browser with subgrid now has. One that has subgrid but not
	 * `:has()` (Firefox 71-120) drops these rules as unparseable and keeps Layer 1, which is the
	 * right failure.
	 */
	:is(.fb-catalog__results, .fb-related-products, .fb-search-results) ul.wc-block-product-template > li.wc-block-product:not(:has(> :not(.wp-block-woocommerce-product-image, .fb-product-meta, .wp-block-post-title, .wp-block-woocommerce-product-price, .fb-card-actions), > :nth-child(8))) {
		display: grid;
		grid-row: span 7;
		grid-template-rows: subgrid;

		/*
		 * Stated, not relied on: the card's base rule already sets `gap: 0`, and a subgrid only takes
		 * its parent's 16px gutter between its own rows when its own gap is `normal`. Said here so that
		 * nobody deletes that `gap: 0` believing it only mattered to the flex card.
		 */
		row-gap: 0;
	}

	/*
	 * Two lines reserved for every title, so rows agree with each other as well as within themselves.
	 * The subgrid lines up the cards in a row, but a row of one-line names still put its prices 17px
	 * higher than the next row's — and most names in this catalogue run to two lines. Reserved, never
	 * clamped: a three-line name still shows in full, and takes its row down with it. `2lh` is two of
	 * the title's own line-heights; the `calc` is for Safari 16.0-16.3 and Firefox before 120, which
	 * have subgrid but not `lh`.
	 */
	:is(.fb-catalog__results, .fb-related-products, .fb-search-results) ul.wc-block-product-template > li.wc-block-product:not(:has(> :not(.wp-block-woocommerce-product-image, .fb-product-meta, .wp-block-post-title, .wp-block-woocommerce-product-price, .fb-card-actions), > :nth-child(8))) > .wp-block-post-title {
		min-height: calc(2em * var(--lh-snug));
		min-height: 2lh;
	}

	/* Top of its row, not the foot: Layer 1's auto margin would sink a short price under a tall one. */
	:is(.fb-catalog__results, .fb-related-products, .fb-search-results) ul.wc-block-product-template > li.wc-block-product:not(:has(> :not(.wp-block-woocommerce-product-image, .fb-product-meta, .wp-block-post-title, .wp-block-woocommerce-product-price, .fb-card-actions), > :nth-child(8))) > .wp-block-woocommerce-product-price {
		margin-top: 0;
	}

	/* Guarded too: on the flex fallback, `align-self: end` would push the buttons to the right edge. */
	:is(.fb-catalog__results, .fb-related-products, .fb-search-results) ul.wc-block-product-template > li.wc-block-product:not(:has(> :not(.wp-block-woocommerce-product-image, .fb-product-meta, .wp-block-post-title, .wp-block-woocommerce-product-price, .fb-card-actions), > :nth-child(8))) > .fb-card-actions {
		align-self: end;
	}
}

/* ==================================================================== buttons ==== */

/*
 * WooCommerce's catalogue and single-product CTAs rendered at ~20px tall — less than half the
 * design system's 44px minimum tap target. They are mapped onto .fb-btn's cart variant here.
 */
.wc-block-components-product-button__button,
.woocommerce a.button.add_to_cart_button,
.woocommerce button.button.alt,
.woocommerce .single_add_to_cart_button,
.woocommerce #respond input#submit,
.wc-block-cart__submit-button,
.wc-block-components-checkout-place-order-button {
	display: inline-flex !important;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	height: var(--control-h-md);
	min-height: var(--tap-min);
	padding: 0 var(--space-5) !important;
	font-family: var(--font-body) !important;
	font-size: var(--text-body-sm) !important;
	font-weight: var(--fw-semibold) !important;
	letter-spacing: var(--ls-button);
	line-height: 1 !important;
	border: var(--border-width) solid transparent;
	border-radius: var(--radius-md) !important;
	background: var(--cta-cart-bg) !important;
	color: var(--cta-cart-fg) !important;
	text-decoration: none;
	white-space: nowrap;
	cursor: pointer;
	transition: var(--transition-control);
}

.wc-block-components-product-button__button:hover,
.woocommerce a.button.add_to_cart_button:hover,
.woocommerce button.button.alt:hover,
.woocommerce .single_add_to_cart_button:hover,
.wc-block-cart__submit-button:hover,
.wc-block-components-checkout-place-order-button:hover {
	background: var(--steel-700) !important;
	color: var(--cta-cart-fg) !important;
}

.woocommerce .single_add_to_cart_button {
	height: var(--control-h-lg);
	font-size: var(--text-body) !important;
}

/* Secondary/outline treatment for WooCommerce's non-primary buttons. */
.woocommerce a.button:not(.add_to_cart_button):not(.alt),
.woocommerce button.button:not(.alt) {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: var(--tap-min);
	padding: 0 var(--space-5);
	border-radius: var(--radius-md);
	border: var(--border-width) solid var(--border-strong);
	background: var(--surface-card);
	color: var(--text-primary);
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	text-decoration: none;
}

/* Confirmation state after an AJAX add-to-quote. */
.fb-btn.is-added {
	background: var(--fb-green-100);
	color: var(--fb-green-700);
	border-color: transparent;
}

/* ============================================================ quantity input ==== */

.woocommerce .quantity input.qty,
.wc-block-components-quantity-selector input {
	height: var(--control-h-lg);
	min-height: var(--tap-min);
	width: 88px;
	padding-inline: var(--space-3);
	font-family: var(--font-mono);
	font-size: var(--text-body-sm);
	color: var(--text-primary);
	background: var(--surface-card);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
	text-align: center;
}

/* =========================================================== quantity stepper ==== */

/*
 * − and + either side of the quantity field (client, 2026-09-26), built to the design kit's
 * `QuantityStepper`: one bordered control, icon buttons, a small centred mono number between
 * dividers. `fischer_bell_quantity_stepper_html()` renders the markup for the cart and the product
 * page alike; cart.js or product.js reveals the buttons and adds `is-enhanced`, so without JavaScript
 * nothing here applies and the field above is WooCommerce's, spinner and all.
 *
 * Here, not in cart.css, since the product page gained the same control: this is the one theme
 * stylesheet both pages load. Moved verbatim — each rule outscores everything cart.css and this file
 * say about the same elements, so loading earlier than cart.css changes nothing on /cart/. The product
 * page's own adjustments, for WooCommerce's single-product rules, are under "buy row" below.
 *
 * Departure from the kit: its buttons are 38px, and this site's tap target is `--tap-min`, 44px —
 * the height the field already has. The constraint wins.
 *
 * No `overflow: hidden` on the wrapper, which the kit uses to clip the corners: `--focus-ring` is an
 * outer box-shadow and would be clipped with them. The end buttons take the corner radius instead.
 */
.fb-qty {
	display: inline-flex;
	align-items: stretch;
	vertical-align: middle;
}

/*
 * `[hidden]` is a user-agent rule, and any author `display` beats it whatever the specificity
 * (gotcha 106). Stated outright, so no future `display` on the buttons can reveal them early.
 */
.fb-qty__step[hidden] { display: none; }

.fb-qty.is-enhanced {
	background: var(--surface-card);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
}

.fb-qty__step {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: var(--tap-min);
	min-height: var(--tap-min);
	margin: 0;
	padding: 0;
	color: var(--text-primary);
	background: transparent;
	border: 0;
	cursor: pointer;
}

.fb-qty__step:first-child {
	border-start-start-radius: var(--radius-md);
	border-end-start-radius: var(--radius-md);
}

.fb-qty__step:last-child {
	border-start-end-radius: var(--radius-md);
	border-end-end-radius: var(--radius-md);
}

.fb-qty__step:hover { background: var(--surface-subtle); }

.fb-qty__step:focus-visible {
	position: relative;
	z-index: 1;
	outline: none;
	box-shadow: var(--focus-ring);
}

.fb-qty__step[aria-disabled="true"] {
	color: var(--text-muted);
	background: transparent;
	cursor: not-allowed;
}

/*
 * The field inside the control. Outscores this file's `.woocommerce .quantity input.qty` (0,3,1) and
 * cart.css's phone rule that stretches it to 100% (0,3,2) — inside the stepper the control, not the
 * field, sets the width.
 */
.fb-qty.is-enhanced .quantity input.qty {
	width: 52px;
	min-width: 52px;
	max-width: none;
	height: auto;
	padding-inline: var(--space-1);
	border: 0;
	border-inline: var(--border-width) solid var(--border-subtle);
	border-radius: 0;
	-moz-appearance: textfield;
	appearance: textfield;
}

/* The native spinner, now that − and + do its job. */
.fb-qty.is-enhanced .quantity input.qty::-webkit-inner-spin-button,
.fb-qty.is-enhanced .quantity input.qty::-webkit-outer-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

.fb-qty.is-enhanced .quantity { display: flex; }

/* ================================================================ breadcrumbs ==== */

.woocommerce-breadcrumb,
.wc-block-breadcrumbs {
	font-size: var(--text-caption) !important;
	color: var(--text-muted);
	margin-bottom: var(--space-5);
}

.woocommerce-breadcrumb a,
.wc-block-breadcrumbs a {
	color: var(--text-secondary);
	text-decoration: none;
}

.woocommerce-breadcrumb a:hover,
.wc-block-breadcrumbs a:hover { color: var(--text-primary); text-decoration: underline; }

/* ============================================================ sorting / count ==== */

.woocommerce-ordering select,
.wc-block-catalog-sorting select {
	height: var(--control-h-md);
	min-height: var(--tap-min);
	padding-inline: var(--space-3);
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	color: var(--text-primary);
	background: var(--surface-card);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
}

.woocommerce-result-count,
.wc-block-product-results-count {
	font-size: var(--text-body-sm) !important;
	color: var(--text-secondary);
	margin: 0;
}

/* ============================================================= single product ==== */

.woocommerce div.product .product_title {
	font-family: var(--font-display);
	font-size: var(--text-h1);
	font-weight: var(--fw-bold);
	letter-spacing: var(--ls-heading);
	line-height: var(--lh-snug);
	text-wrap: pretty;
	margin: var(--space-2) 0 0;
}

/* Price sits in its own ruled band, as in the kit's ProductScreen. */
.woocommerce div.product p.price,
.woocommerce div.product span.price {
	font-family: var(--font-display);
	font-size: var(--text-h1);
	font-weight: var(--fw-bold);
	letter-spacing: var(--ls-heading);
	color: var(--text-primary);
	margin: 0;
}

/* ------------------------------------------------------------ PDP price ----
   The single-product template is a BLOCK template, so the price is
   `.wp-block-woocommerce-product-price`, not the classic `p.price` the rules
   above target — those never matched here. Left to itself the block rendered in
   the body face at weight 400 and at core's fluid Large (22px→36px with the
   viewport), while the same price in the shop loop was display/bold. The
   `!important` is to beat `.has-large-font-size`, which core emits with one.

   Scoped to `.fb-pdp-main`, the product's own columns (2026-09-27). Unscoped it also matched every
   related-product card further down the page, and printed their prices at this 36px instead of the
   eStore card's size, so the "same card" in related products was not the same card. */
body.single-product .fb-pdp-main .wp-block-woocommerce-product-price {
	font-family: var(--font-display);
	font-size: var(--text-h1) !important;
	font-weight: var(--fw-bold);
	letter-spacing: var(--ls-heading);
	line-height: var(--lh-snug);
	color: var(--text-primary);
}

/* The gate and quote-only notes sit inside the price block but are prose, not a figure. */
body.single-product .fb-pdp-main .wp-block-woocommerce-product-price .fb-price__gate,
body.single-product .fb-pdp-main .wp-block-woocommerce-product-price .fb-price__on-request {
	font-size: var(--text-body-sm) !important;
	font-weight: var(--fw-semibold);
	letter-spacing: 0;
}

/* WooCommerce prints its own stock line on the PDP in addition to the one the theme renders in
   the price band. Two stock statements, in two type treatments, sometimes disagreeing ("Low
   stock" vs "6 in stock"). The theme's is the design-kit treatment, so this one goes.

   NOT the line inside .woocommerce-variation-availability, which the variation script writes when a
   size is chosen. That one is the only thing on the page that speaks for the CHOSEN SIZE — the price
   band above states the parent's aggregate status, so with this hidden, picking a size that is out
   of stock greyed the Add to cart button and said nothing at all while the band still read "In
   stock". Reachable on 155 products since the J-1 stock repair. Paired with the matching exemption
   in fischer_bell_suppress_core_stock_html(); both had to be lifted, PHP and CSS. */
body.single-product div.product p.stock {
	display: none;
}

/* Re-shown by a longer selector rather than a `:not()`, so the specificity is plainly higher
   (0,3,2 against 0,2,2) and it does not rely on Selectors Level 4 inside `:not()`. */
body.single-product div.product .woocommerce-variation-availability p.stock {
	display: block;
	margin: var(--space-3) 0 0;
	font-size: var(--text-caption);
	font-weight: var(--fw-medium);
}

body.single-product div.product .woocommerce-variation-availability p.in-stock { color: var(--status-success); }
body.single-product div.product .woocommerce-variation-availability p.available-on-backorder { color: var(--status-warning); }
body.single-product div.product .woocommerce-variation-availability p.out-of-stock { color: var(--status-danger); }

/*
 * The product name, a step down from the page-title size (client, 2026-09-26).
 *
 * At the global h1's 36px, with everything else that sat above the buttons, Add to cart landed below
 * the fold of a 1440 x 900 screen (measured at y = 1002 before this rework). h-2 on desktop, h-3 on a
 * phone; the class is the template's, so the h3 titles of the related-product cards further down are
 * untouched.
 */
.wp-block-post-title.fb-pdp-title {
	font-size: var(--text-h2);
	text-wrap: pretty;
}

@media (max-width: 600px) {
	.wp-block-post-title.fb-pdp-title { font-size: var(--text-h3); }
}

/*
 * The price band: price, then stock and the GST note beneath it, ruled off above and below.
 *
 * A group block in templates/single-product.html since 2026-09-26, holding the Product Price block and
 * `fischer-bell/product-meta` with its `stock` and `gst` parts. It used to be a `<div>` opened and
 * closed by two summary hooks, which WooCommerce's block template fires after the price block — so
 * the band never contained the price it was drawn to set off.
 *
 * Two classes on every margin here: the band is a child of the column's flow layout and its own
 * children are in another, and core's `:root :where(.is-layout-flow) > *` scores (0,1,0).
 */
.wp-block-group.fb-pdp-priceband {
	border-top: var(--border-width) solid var(--border-subtle);
	border-bottom: var(--border-width) solid var(--border-subtle);
	margin-block: var(--space-6);
	padding-block: var(--space-5);
}

.fb-pdp-priceband .wp-block-woocommerce-product-price { margin: 0; }

.fb-pdp-priceband .fb-product-meta.fb-pdp-availability { margin-block: var(--space-3) 0; }

/* No price at all (it cannot be bought and is not quote-only): no gap above the stock line. */
.fb-pdp-priceband .wp-block-woocommerce-product-price:not(:has(.wc-block-components-product-price > *)) + .fb-product-meta.fb-pdp-availability {
	margin-block-start: 0;
}

.fb-pdp-availability .fb-loop-stock { margin-top: 0; }
.fb-pdp-gst { font-size: var(--text-caption); color: var(--text-muted); margin-top: var(--space-2); }

/* "Sold per box" (inc/product-fields.php): the unit, read just before choosing a quantity. */
.fb-pdp-packing {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	margin-top: var(--space-2);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	color: var(--text-secondary);
}

.fb-pdp-packing .fb-icon { flex: none; color: var(--text-muted); }

/*
 * Brand and part number, directly under the title (client, 2026-09-26).
 *
 * The card's own block (`fischer-bell/product-meta`) and the card's own treatment: uppercase brand
 * eyebrow, monospaced part number. On one line here rather than the card's two, which keeps the buy
 * controls higher, and the part number a step up from the card's micro size, because on this page
 * it stands alone rather than repeating down a grid.
 */
.fb-pdp-identity {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	column-gap: var(--space-3);
	row-gap: var(--space-1);
	margin-top: var(--space-3);
}

/* The block prints an empty placeholder for the card's row grid; on this page it would only add a gap. */
.fb-pdp-identity.is-empty { display: none; }

.fb-pdp-identity .fb-loop-brand,
.fb-pdp-identity .fb-loop-sku { margin-top: 0; }

.fb-pdp-identity .fb-loop-sku { font-size: var(--text-caption); }

.fb-pdp-identity .fb-loop-brand + .fb-loop-sku::before {
	content: "·";
	margin-right: var(--space-3);
	color: var(--text-muted);
}

.fb-pdp-certs {
	display: flex;
	gap: var(--space-2);
	flex-wrap: wrap;
	margin-top: var(--space-4);
}

/* ------------------------------------------------------------------ buy row ----
 *
 * The quantity stepper and Add to cart on one row, Add to cart taking whatever the stepper leaves;
 * Add to quote across the full width beneath (client, 2026-09-26). Every control 48px, above the
 * 44px floor.
 *
 * A simple product's `form.cart` is that row. A variable product's form is a column — the options,
 * then the chosen variation's availability, then the row — and its row is WooCommerce's own
 * `.woocommerce-variation-add-to-cart`, where it prints the field and the buttons for a variation.
 * The whole form used to be the flex row, which made the options table and the variation panel two
 * more items in it.
 *
 * Three of WooCommerce's rules have to be answered here rather than lived with:
 * - its clearfix puts a `content: " "` box before and after `form.cart`, and in a flex row each one
 *   is an item with a gap after it — every simple product's quantity field sat 12px in from the
 *   column's edge;
 * - the add-to-cart-form block's own sheet makes both rows a three-column grid, which the flex below
 *   replaces;
 * - its single-product sheet margins the field's wrapper (0,4,3) and the field (0,5,3), which inside
 *   the stepper are gaps between the number and "+". The theme's old `.quantity { margin: 0 }` scored
 *   (0,4,2) and never won.
 */
.woocommerce div.product form.cart { margin-bottom: var(--space-6); }

.woocommerce div.product form.cart::before,
.woocommerce div.product form.cart::after { content: none; }

.woocommerce div.product form.cart:not(.variations_form):not(.grouped_form),
.woocommerce div.product form.cart .woocommerce-variation-add-to-cart {
	display: flex;
	flex-wrap: wrap;
	align-items: stretch;
	gap: var(--space-3);
}

.woocommerce div.product form.cart div.quantity { margin: 0; }

/*
 * A product with exactly one unit gets a hidden quantity input and nothing to show. Its wrapper would
 * still be an empty flex item with a gap after it.
 */
.woocommerce div.product form.cart div.quantity:has(> input[type="hidden"]) { display: none; }

.woocommerce div.product form.cart .fb-qty { flex: none; }

/* product.js hides the stepper where WooCommerce hides the field: a variation sold one at a time. */
.woocommerce div.product form.cart .fb-qty[hidden] { display: none; }

.woocommerce div.product form.cart .fb-qty .quantity input.qty {
	box-sizing: border-box;
	margin: 0;
	/* The add-to-cart-form block pads `.input-text` by 0.9rem top and bottom, which the stretched field cannot fit. */
	padding-block: 0;
}

.woocommerce div.product form.cart .single_add_to_cart_button {
	flex: 1 1 auto;
	height: var(--control-h-lg);
	margin: 0;
}

.woocommerce div.product form.cart .fb-btn[data-fb-quote-add] {
	flex: 1 1 100%;
	height: var(--control-h-lg);
	font-size: var(--text-body);
}

/*
 * The standalone Add to quote — the whole call to action of a product that cannot be bought, printed in
 * the summary slot after the buy form — at the same size and width as the buy row's.
 * `.fb-quote-add--compact` is a card's; related products sit outside `.fb-pdp-main` anyway.
 */
.fb-pdp-main form.fb-quote-add:not(.fb-quote-add--detached):not(.fb-quote-add--compact) {
	display: block;
	margin-bottom: var(--space-6);
}

.fb-pdp-main form.fb-quote-add:not(.fb-quote-add--detached):not(.fb-quote-add--compact) .fb-btn {
	width: 100%;
	height: var(--control-h-lg);
	font-size: var(--text-body);
}

form.fb-quote-add--detached { display: none; }

/* --------------------------------------------------------- variation options ----
 *
 * The options table as a column: each attribute's name above its choices, full width. WooCommerce's
 * table puts the name in a cell beside the control, which left a row of option buttons a third of the
 * column narrower than the buy row beneath it.
 */
.woocommerce div.product form.cart table.variations {
	display: block;
	width: 100%;
	margin: 0 0 var(--space-4);
	border: 0;
}

.woocommerce div.product form.cart table.variations > tbody,
.woocommerce div.product form.cart table.variations tr,
.woocommerce div.product form.cart table.variations th,
.woocommerce div.product form.cart table.variations td {
	display: block;
	width: auto;
	padding: 0;
	border: 0;
	line-height: var(--lh-normal);
	text-align: left;
}

.woocommerce div.product form.cart table.variations tr + tr { margin-top: var(--space-5); }

.woocommerce div.product form.cart table.variations th.label label,
.fb-options .fb-options__legend {
	display: block;
	margin: 0 0 var(--space-2);
	padding: 0;
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	color: var(--text-primary);
}

/*
 * Once product.js has shown the buttons, the fieldset's legend names the group and the header cell
 * would only say it twice — and its `<label for>` would point at a select nobody can see. The select
 * stays in the form, because the form posts it and WooCommerce's script reads it.
 */
.woocommerce div.product form.cart table.variations tr.has-fb-options > th.label { display: none; }
.woocommerce div.product form.cart table.variations select[hidden] { display: none; }

.woocommerce div.product form.cart .reset_variations {
	display: inline-block;
	margin-top: var(--space-2);
	padding-block: var(--space-2);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-medium);
}

/*
 * The option buttons (inc/product-options.php): native radios, visually replaced.
 *
 * Chosen: ink border doubled to 2px and a green tint — the doubled border says "chosen" to someone who
 * cannot tell the tint from white. Not available with the other options chosen: dashed border, the name
 * struck through, and the radio disabled so it cannot be chosen at all. That is the combination
 * WooCommerce removes from its dropdown; out of stock is not that, and stays choosable, so the buyer
 * can see it is out of stock and still ask for a quote.
 */
.fb-options {
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
}

.fb-options[hidden] { display: none; }

.fb-options__list {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
}

.fb-option {
	position: relative;
	display: flex;
	max-width: 100%;
	margin: 0;
	cursor: pointer;
}

/* Hidden, not removed: the radio keeps the tab stop, the arrow keys and the label association. */
.fb-option__input {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	border: 0;
	white-space: nowrap;
}

.fb-option__face {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	min-width: var(--tap-min);
	min-height: var(--tap-min);
	padding: var(--space-2) var(--space-4);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
	background: var(--surface-card);
	color: var(--text-primary);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-medium);
	line-height: var(--lh-snug);
	text-align: center;
	overflow-wrap: anywhere;
	transition: var(--transition-control);
}

.fb-option:hover .fb-option__face { border-color: var(--border-strong); }

.fb-option__input:checked + .fb-option__face {
	border-color: var(--fb-ink);
	background: var(--fb-green-100);
	box-shadow: inset 0 0 0 1px var(--fb-ink);
}

.fb-option__input:focus-visible + .fb-option__face { box-shadow: var(--focus-ring); }

.fb-option__input:checked:focus-visible + .fb-option__face {
	box-shadow: inset 0 0 0 1px var(--fb-ink), var(--focus-ring);
}

.fb-option:has(.fb-option__input:disabled) { cursor: not-allowed; }

.fb-option__input:disabled + .fb-option__face,
.fb-option:hover .fb-option__input:disabled + .fb-option__face {
	border-style: dashed;
	border-color: var(--border-strong);
	background: var(--surface-subtle);
	color: var(--text-muted);
}

.fb-option__input:disabled + .fb-option__face .fb-option__name { text-decoration: line-through; }
.fb-option__input:disabled + .fb-option__face .fb-option__swatch { opacity: 0.4; }

/*
 * Out of stock (client, 2026-09-27): greyed, but still a solid-bordered button that can be chosen,
 * because choosing it is how a buyer asks for a quote on it. "Not available" above is the other state
 * — dashed, struck and disabled — and the two must never read the same. A screen reader hears ", out of
 * stock" from the option's status text; the grey is only for the eye.
 *
 * Chosen while out of stock: the chosen border (ink, doubled) on the grey, not the green tint, so it
 * still reads as chosen and still reads as out of stock.
 */
.fb-option.is-out-of-stock .fb-option__face {
	background: var(--surface-subtle);
	color: var(--text-muted);
}

.fb-option.is-out-of-stock .fb-option__swatch { opacity: 0.5; }

.fb-option.is-out-of-stock .fb-option__input:checked + .fb-option__face {
	background: var(--surface-subtle);
	color: var(--text-primary);
}

/*
 * The colour dot. A hairline ring on every dot, from a border token, so white, yellow, silver and
 * fluorescent yellow show against the white button without a list of which colours are "light".
 */
.fb-option__swatch {
	flex: none;
	width: 16px;
	height: 16px;
	border-radius: var(--radius-pill);
	background: var(--fb-swatch, transparent);
	box-shadow: inset 0 0 0 1px var(--border-strong);
}

/*
 * The chosen variation's price, in the price band (product.js). Shown in an element of its own beside
 * the block's, rather than written into it, because on a price-range product the block's inner element
 * belongs to WooCommerce's Interactivity API, which rewrites it from its own store at start-up.
 *
 * WooCommerce's own copy of the same price, which its script writes under the options, is hidden once
 * the band is showing it — only when product.js has said so, so a page whose band has no price block
 * keeps WooCommerce's.
 */
.wp-block-woocommerce-product-price.has-variation-price > .wc-block-components-product-price { display: none; }
.fb-pdp-price-variation:empty { display: none; }
.woocommerce div.product form.variations_form.has-fb-price .woocommerce-variation-price { display: none; }

/*
 * The buy bar (fischer_bell_render_buy_bar(), product.js): price and one button along the bottom of a
 * phone's screen while the page's own buy buttons are out of sight (client, 2026-09-26).
 *
 * `md` and below only, and only once product.js has found something for it to press — it sets
 * `has-fb-buybar` on the body then, which reserves the bar's height at the foot of the page so the
 * footer's last line is never under it. The space is reserved for as long as the bar can appear, not
 * only while it is showing: toggling it with the bar would move the page by 72px under the reader's
 * thumb every time the buttons scrolled in or out of view.
 *
 * Slides rather than appears; `visibility` goes with the slide, so the hidden bar is out of the tab order
 * and the accessibility tree without a second attribute to keep in step.
 *
 * z-index 30: above the page, under the sticky header (40) and its menu, and under the quote toast (70),
 * which sits 88px up and clears the bar's height.
 */
.fb-buybar[hidden] { display: none; }

@media (max-width: 860px) {
	body.has-fb-buybar { padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px)); }

	.fb-buybar {
		position: fixed;
		right: 0;
		bottom: 0;
		left: 0;
		z-index: 30;
		display: flex;
		align-items: center;
		gap: var(--space-4);
		padding: var(--space-3) var(--gutter) calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
		border-top: var(--border-width) solid var(--border-default);
		background: var(--surface-card);
		box-shadow: var(--shadow-sticky);
		transform: translateY(100%);
		visibility: hidden;
		transition: transform var(--dur-base) var(--ease-out), visibility 0s linear var(--dur-base);
	}

	.fb-buybar.is-shown {
		transform: none;
		visibility: visible;
		transition: transform var(--dur-base) var(--ease-out), visibility 0s;
	}

	.fb-buybar__price {
		flex: 1 1 auto;
		min-width: 0;
		font-family: var(--font-display);
		font-size: var(--text-h4);
		font-weight: var(--fw-bold);
		line-height: var(--lh-snug);
		color: var(--text-primary);
	}

	/* A sale price arrives as <del> then <ins>: the old price small and struck, the new one as the price. */
	.fb-buybar__price del { display: block; font-size: var(--text-caption); font-weight: var(--fw-regular); color: var(--text-muted); }
	.fb-buybar__price ins { text-decoration: none; }
	.fb-buybar__price .screen-reader-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

	.fb-buybar .fb-buybar__action {
		flex: 0 0 auto;
		max-width: 60%;
		margin: 0;
	}
}

@media (max-width: 860px) and (prefers-reduced-motion: reduce) {
	.fb-buybar,
	.fb-buybar.is-shown { transition: none; }
}

/*
 * One column up to 860px, the theme's `md` breakpoint (2026-09-26).
 *
 * Core's Columns block only stacks below 782px — from 782px up it sets `flex-wrap: nowrap !important`
 * — so between 782px and 860px the 512px gallery kept its column and squeezed the buy box into what
 * was left. Two classes and `!important` to beat core's `!important`, and `flex-basis` over the
 * gallery column's inline 512px.
 */
@media (max-width: 860px) {
	.wp-block-columns.fb-pdp-main { flex-wrap: wrap !important; }
	.wp-block-columns.fb-pdp-main > .wp-block-column { flex-basis: 100% !important; }
}

/* ------------------------------------------------------------ product details ----
   Description and Specifications, both always visible (fischer-bell/product-details, 2026-09-26),
   where WooCommerce's tabs used to be. Side by side from 861px — the description wider, because it
   is prose and the table is two short columns — and stacked below that, Description first. Either
   one takes the full width when the other is missing; the block's `has-*` classes say which. */
.wp-block-fischer-bell-product-details.fb-pdp-details {
	margin-block-start: var(--space-12);
	/* A pasted URL or a long unspaced part code must wrap, not widen a 375px page. */
	overflow-wrap: break-word;
}

.fb-pdp-details .fb-spec-table td { overflow-wrap: anywhere; }

.fb-pdp-details__section {
	min-width: 0;
	/* Arrive below the sticky header, not under it, when linked to (#fb-description, #fb-specifications). */
	scroll-margin-top: calc(var(--sticky-offset) + var(--space-4));
}

/* A reading measure when a section has the whole row to itself. */
.fb-pdp-details:not(.has-specifications) .fb-pdp-details__description,
.fb-pdp-details:not(.has-description) .fb-pdp-details__specifications { max-width: 820px; }

.fb-pdp-details .fb-pdp-details__title {
	font-size: var(--text-h3);
	margin: 0 0 var(--space-4);
}

.fb-pdp-details__body > :first-child { margin-top: 0; }
.fb-pdp-details__body > :last-child { margin-bottom: 0; }

/*
 * The short description's key points, leading the one Description (2026-09-27). Nearly always a bullet
 * list. Part of the same section, so no heading of its own; spaced from the prose that follows it.
 */
.fb-pdp-details__summary { margin-bottom: var(--space-5); }
.fb-pdp-details__summary > :first-child { margin-top: 0; }
.fb-pdp-details__summary > :last-child { margin-bottom: 0; }

@media (min-width: 861px) {
	.fb-pdp-details.has-description.has-specifications {
		display: grid;
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
		column-gap: var(--space-12);
		align-items: start;
	}

	/* The table's fixed 260px label column would leave the values ~80px in a 5fr column at 900px. */
	.fb-pdp-details.has-description.has-specifications .fb-spec-table th { width: 45%; }
}

@media (max-width: 860px) {
	.fb-pdp-details__section + .fb-pdp-details__section { margin-top: var(--space-10); }
}

/* Specification and bulk-pricing tables. */
.fb-spec-table,
.fb-bulk-table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--text-body-sm);
}

.fb-spec-table th {
	text-align: left;
	width: 260px;
	padding: var(--space-3) var(--space-4) var(--space-3) 0;
	color: var(--text-secondary);
	font-weight: var(--fw-medium);
}

.fb-spec-table td { padding: var(--space-3) 0; }
.fb-spec-table tr,
.fb-bulk-table tbody tr { border-bottom: var(--border-width) solid var(--border-subtle); }
.fb-spec-table td.is-mono, .fb-bulk-table td + td { font-family: var(--font-mono); }

.fb-bulk-table thead tr { border-bottom: var(--border-width-strong) solid var(--border-default); }

.fb-bulk-table th {
	text-align: left;
	padding: var(--space-3) 0;
	font-size: var(--text-micro);
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
	color: var(--text-muted);
	font-weight: var(--fw-semibold);
}

.fb-bulk-table td { padding: var(--space-3) 0; }

/* ================================================================= responsive ==== */

@media (max-width: 860px) {
	/*
	 * auto-fill picks the column count on its own now, so only the track floor and the gap need
	 * adjusting: 230px would drop a phone to a single column, and two-up reads better.
	 */
	ul.wc-block-product-template,
	ul.wc-block-product-template.columns-1,
	ul.wc-block-product-template.columns-2,
	ul.wc-block-product-template.columns-3,
	ul.wc-block-product-template.columns-4,
	ul.wc-block-product-template.columns-5,
	ul.wc-block-product-template.columns-6 {
		grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
		gap: var(--space-3);
	}

	/* Too little width for two buttons abreast; stack them. */
	li.wc-block-product .fb-card-actions,
	.woocommerce ul.products li.product .fb-card-actions { flex-direction: column; }

	li.wc-block-product .fb-card-actions .wp-block-fischer-bell-add-to-quote,
	.woocommerce ul.products li.product .fb-card-actions > form.fb-quote-add { flex: 1; }

	/* In a column the basis above would be a height: a 134px-tall Add to cart. */
	li.wc-block-product .fb-card-actions .wp-block-woocommerce-product-button { flex: 1; }

	.fb-spec-table th { width: 45%; }
}

/*
 * ⚠️ These two blocks MUST stay below the phone block above.
 *
 * They were written above it first, and at equal specificity the later rule wins — so
 * `max-width: 860px`'s 150px floor overrode the 200px one on every tablet and the fix did nothing
 * at all. The stylesheet looked correct and the tablet was unchanged. Same shape as gotcha 39.
 */
/*
 * The two widths between a phone and a desktop (responsive audit R-1 and R-2).
 *
 * The site had a phone rule and a desktop rule and nothing in between, so `auto-fill` gave a
 * 768px tablet **four columns of 167px** — the same card size a 375px phone gets — and gave iPad
 * landscape at 1024px only **two**, because the 260px sidebar and its 40px gap leave 644px.
 *
 * Two steps, both chosen by arithmetic rather than by eye:
 *
 *   600-860px   floor 200px  ->  768px = 3 x 225px, 834px = 3 x 245px
 *   861-1151px  floor 200px  ->  1024px = 3 x 204px, 1151px = 3 x 246px
 *
 * The upper step **stops at 1151px on purpose**. Above it the 230px floor already produces three
 * columns, and leaving 200px in place would produce four — a change to the desktop catalogue that
 * belongs to the design kit, not to a responsive fix (open question 22). The handover is seamless:
 * 1151px gives 3 x 246px and 1152px gives 3 x 247px.
 */
@media (min-width: 600px) and (max-width: 860px) {
	ul.wc-block-product-template,
	ul.wc-block-product-template.columns-1,
	ul.wc-block-product-template.columns-2,
	ul.wc-block-product-template.columns-3,
	ul.wc-block-product-template.columns-4,
	ul.wc-block-product-template.columns-5,
	ul.wc-block-product-template.columns-6,
	.woocommerce ul.products {
		grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
		gap: var(--space-4);
	}
}

@media (min-width: 861px) and (max-width: 1151px) {
	ul.wc-block-product-template,
	ul.wc-block-product-template.columns-1,
	ul.wc-block-product-template.columns-2,
	ul.wc-block-product-template.columns-3,
	ul.wc-block-product-template.columns-4,
	ul.wc-block-product-template.columns-5,
	ul.wc-block-product-template.columns-6,
	.woocommerce ul.products {
		grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
	}
}

/*
 * Related products: the same floors at every width, but `auto-fit` where the grid elsewhere uses
 * `auto-fill` (session 56).
 *
 * The eStore always has more products than columns, so the two behave the same there. Related
 * products are four (patterns/related-products.php) in a 1280px-wide row with room for five 230px
 * tracks, and `auto-fill` keeps the fifth track even when it is empty. Measured: four 243px cards and
 * an empty column on the right, and at 243px "Select options" wrapped onto two lines, which it does
 * not at the eStore's 289px. `auto-fit` collapses the empty track, so the four share the row at
 * 308px each.
 *
 * ⚠️ Below the responsive blocks above, for the reason their own comment gives. Equal specificity, so
 * the later rule wins — written first beside "card rows", it lost to the 861-1151px block, which
 * would have brought the empty fifth column back just under 1151px.
 */
.fb-related-products ul.wc-block-product-template { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }

/*
 * Product search results: a 280px floor on desktop, where the eStore's is 230px (session 56b).
 *
 * The eStore's grid sits beside the 260px filter sidebar and gets three 289px cards. Search results
 * have no sidebar and run the full 1280px, where a 230px floor makes **five** columns of 243px — the
 * width at which this card's "Select options" wraps onto two lines (measured on related products).
 * 280px gives four of about 308px, the related-products card exactly. Tablets and phones keep the
 * same steps as everywhere else, below.
 */
.fb-search-results ul.wc-block-product-template { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }

@media (max-width: 860px) {
	.fb-related-products ul.wc-block-product-template { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
	.fb-search-results ul.wc-block-product-template { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}

@media (min-width: 600px) and (max-width: 1151px) {
	.fb-related-products ul.wc-block-product-template { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
	.fb-search-results ul.wc-block-product-template { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
}


/*
 * Phones keep the stepper and Add to cart on one row (client, 2026-09-26) — a narrower gap is all that
 * changes. This used to stretch the quantity field and each button to 100%, one per row, which would
 * now pull the field out of its stepper and push Add to cart onto a row of its own.
 */
@media (max-width: 480px) {
	.woocommerce div.product form.cart:not(.variations_form):not(.grouped_form),
	.woocommerce div.product form.cart .woocommerce-variation-add-to-cart { gap: var(--space-2); }
}

/* ==========================================================================
   MY ACCOUNT
   The design kit's Account screen: an identity header, stat tiles and tables,
   with the endpoint menu presented as the kit's Tabs component.
   Markup comes from inc/account.php, woocommerce/myaccount/dashboard.php, and
   the wholesale + quotes plugins' account endpoints.
   ========================================================================== */

/* WooCommerce floats the navigation into a 30% left column and the content beside it. The kit
   runs the endpoints along the top instead, so both floats are cancelled outright. */
.woocommerce-account .woocommerce-MyAccount-navigation,
.woocommerce-account .woocommerce-MyAccount-content {
	float: none;
	width: 100%;
	margin: 0;
}

/* --- Endpoint menu as Tabs ---------------------------------------------- */

/*
 * No scrolling (client, 2026-09-27). The strip was `overflow-x: auto` so it could scroll sideways on a
 * phone, and that made it a scroll container on both axes: each tab is pulled 1px down onto the
 * border (below), which is 1px of vertical overflow, so every screen size showed a vertical
 * scrollbar beside the tabs. The tabs wrap to a second line instead where they do not fit.
 */
.woocommerce-account .woocommerce-MyAccount-navigation {
	margin-bottom: var(--space-8);
	border-bottom: var(--border-width) solid var(--border-default);
}

.woocommerce-account .woocommerce-MyAccount-navigation ul {
	display: flex;
	flex-wrap: wrap;
	column-gap: var(--space-6);
	row-gap: 0;
	margin: 0;
	padding: 0;
	list-style: none;
}

.woocommerce-account .woocommerce-MyAccount-navigation a {
	display: inline-flex;
	align-items: center;
	/* The tab sits ON the container's border, so its own 3px rule replaces it when active. */
	margin-bottom: calc(var(--border-width) * -1);
	padding: var(--space-3) 0;
	min-height: var(--tap-min);
	border-bottom: 3px solid transparent;
	color: var(--text-muted);
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-medium);
	white-space: nowrap;
	text-decoration: none;
	transition: var(--transition-control);
}

.woocommerce-account .woocommerce-MyAccount-navigation a:hover,
.woocommerce-account .woocommerce-MyAccount-navigation a:focus-visible {
	color: var(--text-primary);
}

.woocommerce-account .woocommerce-MyAccount-navigation .is-active a {
	border-bottom-color: var(--fb-green);
	color: var(--text-primary);
	font-weight: var(--fw-semibold);
}

/* Logging out is not a peer of the other tabs; keep it available but quiet. */
.woocommerce-account .woocommerce-MyAccount-navigation-link--customer-logout {
	margin-left: auto;
}

/* --- Dashboard header ---------------------------------------------------- */

.fb-account-header {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--space-4);
	margin-bottom: var(--space-8);
}

.fb-account-header__name {
	margin: var(--space-2) 0 0;
	font-family: var(--font-display);
	font-size: var(--text-h2);
	font-weight: var(--fw-black);
	line-height: var(--lh-tight);
}

.fb-account-header__badges {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin-top: var(--space-3);
}

.fb-account-header__whoami {
	margin: var(--space-3) 0 0;
	color: var(--text-muted);
	font-size: var(--text-body-sm);
}

/* --- Stat tiles ---------------------------------------------------------- */

.fb-account-stats {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
	gap: var(--space-4);
	margin-bottom: var(--space-8);
}

.fb-account-stat {
	padding: var(--space-5);
}

.fb-account-stat__value {
	margin-top: var(--space-2);
	font-family: var(--font-display);
	font-size: var(--text-h2);
	font-weight: var(--fw-black);
	line-height: var(--lh-tight);
}

/* wc_price() wraps the figure in its own span, which would otherwise inherit the body face. */
.fb-account-stat__value .woocommerce-Price-amount {
	font-family: inherit;
	font-weight: inherit;
}

.fb-account-stat__note {
	margin-top: var(--space-1);
	color: var(--text-muted);
	font-size: var(--text-caption);
}

/* --- Tables -------------------------------------------------------------- */

/* Wide tables scroll inside their own container rather than pushing the page sideways. */
.fb-table-scroll {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

.fb-account-table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--text-body-sm);
}

.fb-account-table th {
	padding: var(--space-3) var(--space-3) var(--space-3) 0;
	border-bottom: var(--border-width-strong) solid var(--border-default);
	color: var(--text-muted);
	font-size: var(--text-micro);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-eyebrow);
	text-align: left;
	text-transform: uppercase;
	white-space: nowrap;
}

.fb-account-table td {
	padding: var(--space-3) var(--space-3) var(--space-3) 0;
	border-bottom: var(--border-width) solid var(--border-subtle);
	vertical-align: middle;
}

.fb-account-table tr:last-child td {
	border-bottom: 0;
}

/* Numbers and references are data — the mono face makes them scannable down a column. */
.fb-account-table .is-mono {
	font-family: var(--font-mono);
}

.fb-account-table .is-actions {
	padding-right: 0;
	text-align: right;
}

.fb-account-table__detail {
	display: block;
	margin-top: 2px;
	color: var(--text-muted);
	font-size: var(--text-caption);
}

/* --- Sections and empty states ------------------------------------------- */

.fb-account-section {
	margin-top: var(--space-10);
}

.fb-account-section__title {
	margin: 0 0 var(--space-4);
	font-family: var(--font-display);
	font-size: var(--text-h3);
	font-weight: var(--fw-bold);
}

.fb-account-section__more {
	margin-top: var(--space-4);
	font-size: var(--text-body-sm);
}

.fb-account-empty {
	padding: var(--space-8);
	border: var(--border-width) solid var(--border-subtle);
	border-radius: var(--radius-md);
	background: var(--surface-subtle);
	color: var(--text-secondary);
}

.fb-account-empty p {
	margin: 0 0 var(--space-3);
}

.fb-account-empty p:last-of-type {
	margin-bottom: var(--space-4);
}

/* --- Mobile -------------------------------------------------------------- */

/*
 * 860px, not 782px (responsive audit R-3).
 *
 * 782px is **WordPress's admin-bar breakpoint**, borrowed for a front-end layout it has nothing to
 * do with. It sat 78px below the site's own mobile breakpoint, so between 783 and 860px the account
 * pages were in desktop layout while the header above them was in mobile layout.
 */
@media (max-width: 860px) {
	.fb-account-header {
		align-items: flex-start;
	}

	/* A full-width primary action is easier to hit than one floated beside the name. */
	.fb-account-header > .fb-btn {
		width: 100%;
		justify-content: center;
	}

	.fb-account-stats {
		grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
	}

	.fb-account-stat {
		padding: var(--space-4);
	}

	.fb-account-stat__value {
		font-size: var(--text-h3);
	}

	/* On a phone the tabs wrap; logout takes its place in the flow rather than the far right of
	   whichever line it lands on. */
	.woocommerce-account .woocommerce-MyAccount-navigation-link--customer-logout {
		margin-left: 0;
	}
}

/* --------------------------------------------------------- account alignment ---
   WooCommerce's woocommerce-blocktheme.css caps the page title and the .woocommerce
   wrapper at 1000px on account, cart and checkout. The constrained layout then applies
   `margin: auto !important`, so those three pages sat ~90px inside the header's edge
   while every other page lined up with it.

   The shell already governs width, so the cap is removed. Prefixed with `body` purely to
   outrank WooCommerce's own selector without depending on stylesheet order.

   "The shell governs width" was only true of account. Cart and checkout render WooCommerce's
   own page-cart / page-checkout templates, which have no .fb-shell — so on the cart this rule
   also lifted the wide-size cap off an `alignwide` title, and above ~1360px wide "Cart" ran to
   the window edge while the table sat inside it. The cart now uses the theme's own
   templates/page-cart.html (session 56), a copy of page.html, and lines up. Checkout still
   uses WooCommerce's distraction-free template deliberately. */
body.woocommerce-account .wp-block-post-title,
body.woocommerce-account main .woocommerce,
body.woocommerce-cart .wp-block-post-title,
body.woocommerce-cart main .woocommerce,
body.woocommerce-checkout .wp-block-post-title,
body.woocommerce-checkout main .woocommerce {
	max-width: none;
}

/* WooCommerce pads each account nav item by 1em for its stacked list. The tab bar sets its
   own padding on the link; `body` outranks WooCommerce regardless of load order. */
body.woocommerce-account .woocommerce-MyAccount-navigation ul {
	margin: 0;
	padding: 0;
}

body.woocommerce-account .woocommerce-MyAccount-navigation li {
	margin: 0;
	padding: 0;
	list-style: none;
}

body.woocommerce-account .woocommerce-MyAccount-navigation li.is-active a {
	text-decoration: none;
}

/* Now that the shell governs width rather than a 1000px cap, account forms would otherwise stretch
   the full page. The kit presents them as cards, so they keep a form-shaped measure — capped, and
   flush with the page edge rather than centred. */
body.woocommerce-account .woocommerce-form-login,
body.woocommerce-account .woocommerce-form-register,
body.woocommerce-account .woocommerce-ResetPassword {
	max-width: 480px;
	padding: var(--space-6);
	border: var(--border-width) solid var(--border-subtle);
	border-radius: var(--radius-md);
	background: var(--surface-card);
}

body.woocommerce-account .woocommerce-EditAccountForm,
body.woocommerce-account .woocommerce-address-fields,
body.woocommerce-edit-address .woocommerce-MyAccount-content form {
	max-width: 640px;
}

/* WooCommerce stacks login and register side by side on some configurations; keep them from
   inheriting the card treatment twice. */
body.woocommerce-account .u-columns .woocommerce-form-login,
body.woocommerce-account .u-columns .woocommerce-form-register {
	max-width: none;
}

/* ------------------------------------------------- legacy product grid ----
   WooCommerce has two product-loop blocks. The shop archive uses Product
   Collection (`li.wc-block-product`, styled above); the empty-cart "New in
   store" strip still uses the older Product Grid, which ships its own type
   scale — 12px titles, prices and buttons. That is off the design scale and
   looks nothing like the cards on the shop page. Same treatment, same tokens.

   Scoped through the grid wrapper for specificity (0,2,0) so it wins over
   WooCommerce's own single-class rules without needing !important. */
.wc-block-grid .wc-block-grid__product-title {
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	line-height: var(--lh-snug);
	color: var(--text-primary);
}

.wc-block-grid .wc-block-grid__product-price {
	font-family: var(--font-display);
	font-size: var(--text-h3);
	font-weight: var(--fw-bold);
	letter-spacing: var(--ls-heading);
	color: var(--text-primary);
}

/* Gate and quote-only notes are prose sitting inside the price slot, not a figure. */
.wc-block-grid .wc-block-grid__product-price .fb-price__gate,
.wc-block-grid .wc-block-grid__product-price .fb-price__on-request {
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	letter-spacing: 0;
}

.wc-block-grid .wc-block-grid__product-add-to-cart .wp-block-button__link {
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
}

/* ------------------------------------------------------------------ catalogue ---- */

/*
 * The eStore archive: filter sidebar beside the product grid, matching CatalogScreen.jsx.
 *
 * Filtering is navigation — every option is a link carrying WooCommerce's own `filter_*` query
 * vars — so nothing here depends on JavaScript. The only scripted part is turning the sidebar
 * into a sheet on a phone, and that is additive.
 */

.fb-catalog-page {
	padding-block: var(--space-6) var(--space-16);
}

.fb-catalog-head {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: var(--space-4);
	margin-block: var(--space-5) var(--space-6);
}

.fb-catalog-head__description {
	max-width: 640px;
	margin-block: var(--space-2) 0;
}

.fb-catalog-head__tools {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--space-3);
}

/*
 * The sort form carries WooCommerce's `margin: 0 0 1em` (13px at its small font size). In this centred
 * row that margin was centred with it, so the select sat 6.5px above the Filters button beside it
 * (client, 2026-09-27: "align the Sorting Dropdown Box with the Filters Box"). The row's gap does the
 * spacing; the form needs none of its own.
 */
.fb-catalog-head__tools .wc-block-catalog-sorting .woocommerce-ordering { margin: 0; }

/*
 * On phones, where the Filters button shows (.fb-only-sm, ≤860px), the two share one full-width row:
 * Filters at its natural width, the sort box taking the rest up to the page edge. Before, the row was
 * only as wide as its contents and the sort box stopped 21px short of the edge the cards below reach.
 */
@media (max-width: 860px) {
	.fb-catalog-head__tools {
		width: 100%;
		flex-wrap: nowrap;
	}

	.fb-catalog-head__tools .wc-block-catalog-sorting {
		flex: 1 1 auto;
		min-width: 0;
	}

	/* WooCommerce floats the form right, which shrinks it to its content: unfloated, it fills the space. */
	.fb-catalog-head__tools .wc-block-catalog-sorting .woocommerce-ordering {
		float: none;
		width: 100%;
	}

	.fb-catalog-head__tools .wc-block-catalog-sorting select { width: 100%; }
}

.fb-catalog {
	display: grid;
	grid-template-columns: 260px minmax(0, 1fr);
	gap: var(--space-10);
	align-items: start;
}

/*
 * Sticky under the sticky header. 150px clears the top bar, masthead and nav; anything less and
 * the first facet hides behind the header once the page is scrolled.
 */
.fb-catalog__aside {
	position: sticky;
	top: var(--sticky-offset, 160px);
}

.fb-catalog__meta {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin-bottom: var(--space-5);
}

/* ---- the filter panel ---- */

.fb-filters__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	padding-bottom: var(--space-3);
}

.fb-filters__title {
	font-family: var(--font-display);
	font-weight: var(--fw-bold);
	font-size: var(--text-body);
	color: var(--text-primary);
}

.fb-filters__clear {
	font-size: var(--text-caption);
	color: var(--text-muted);
	text-decoration: none;
	margin-left: auto;
}

.fb-filters__clear:hover { color: var(--text-primary); text-decoration: underline; }

/* Only meaningful once the panel is a sheet. */
.fb-filters__close,
.fb-filters__done { display: none; }

/* ---- one facet ---- */

.fb-facet {
	border-bottom: var(--border-width) solid var(--border-subtle);
	padding-block: var(--space-4);
}

.fb-facet__summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	min-height: 32px;
	cursor: pointer;
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	color: var(--text-primary);

	/* Suppress the native disclosure triangle in every engine. */
	list-style: none;
}

.fb-facet__summary::-webkit-details-marker { display: none; }
.fb-facet__summary::marker { content: ""; }
.fb-facet__summary:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.fb-facet__chevron {
	color: var(--steel-500);
	transition: transform var(--dur-fast) var(--ease-out);
}

.fb-facet[open] .fb-facet__chevron { transform: rotate(180deg); }

.fb-facet__list {
	list-style: none;
	margin: var(--space-2) 0 0;
	padding: 0;
}

.fb-facet__list li { margin: 0; }

/* ---- search within the results ---- */

/*
 * Sits above the facets, because a keyword is the broadest cut and everything below narrows what it
 * leaves. Input and button share a row; the button takes only what it needs so the field keeps the
 * width, which matters in a 260px sidebar.
 */
.fb-filters__search {
	padding-bottom: var(--space-4);
	margin-bottom: var(--space-2);
	border-bottom: var(--border-width) solid var(--border-subtle);
}

.fb-filters__search-row {
	display: flex;
	gap: var(--space-2);
	align-items: stretch;
}

.fb-filters__search-input {
	flex: 1 1 auto;
	min-width: 0;
}

.fb-filters__search-go {
	flex: 0 0 auto;
	padding-inline: var(--space-3);
}

/*
 * Find is exactly as tall as the box beside it (client, 2026-09-27). `.fb-btn` gives every button a
 * fixed 44px and a 44px minimum — the tap target — while the field is the 40px control height, so Find
 * hung 4px below it. Without its own height it stretches to the row, which is the field's.
 *
 * Where the pointer is a finger, the field grows to the 44px target instead and Find follows it, so
 * the pair is level there too and neither drops below the site's tap size.
 */
.fb-filters__search-row .fb-filters__search-go {
	height: auto;
	min-height: 0;
}

@media (pointer: coarse) {
	.fb-filters__search-row .fb-filters__search-input { min-height: var(--tap-min); }
}

/* Safari renders a search input's clear affordance inside the field; ours is the link below. */
.fb-filters__search-input::-webkit-search-decoration,
.fb-filters__search-input::-webkit-search-cancel-button {
	-webkit-appearance: none;
	appearance: none;
}

.fb-filters__search-clear {
	display: inline-block;
	margin-top: var(--space-2);
	font-size: var(--text-micro);
	color: var(--text-muted);
}

.fb-filters__search-clear:hover { color: var(--text-primary); }

.fb-filters__search-clear:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
	border-radius: var(--radius-sm);
}

/* ---- the category tree ---- */

/*
 * A parent category carries two controls on one row, and they must not be confusable: the row
 * itself filters by that category, the chevron beside it opens the subcategories without filtering
 * anything. Browsing the tree and committing to a branch are different intentions and the
 * competitor's catalogue is good precisely because it separates them.
 *
 * The chevron is a <summary>, so it works with no JavaScript and every subcategory link stays in
 * the served HTML. It is positioned out of the link's flow rather than nested inside it — a link
 * inside a summary would fire both actions on one click.
 */
.fb-facet__list li.fb-branch {
	position: relative;
}

.fb-branch > .fb-check {
	/* Clear the chevron, so a long category name never runs under it. */
	padding-right: 34px;
}

.fb-branch__disclosure > summary {
	position: absolute;
	top: 0;
	right: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 40px;
	cursor: pointer;
	color: var(--text-muted);
	list-style: none;
}

/* Safari draws its own marker unless both of these are set. */
.fb-branch__disclosure > summary::-webkit-details-marker { display: none; }
.fb-branch__disclosure > summary::marker { content: ""; }

.fb-branch__disclosure > summary:hover { color: var(--text-primary); }

.fb-branch__disclosure > summary:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
	border-radius: var(--radius-sm);
}

.fb-branch__disclosure[open] > summary .fb-branch__chevron {
	transform: rotate(180deg);
}

@media (prefers-reduced-motion: no-preference) {
	.fb-branch__chevron { transition: transform 120ms ease; }
}

/*
 * Subcategories. The indent is the whole signal that these belong to the category above them, so
 * it has to clear the 18px checkbox rather than being a token few pixels, and the hairline at the
 * indent line reads as "inside this" without needing a second heading.
 */
.fb-facet__list--sub {
	list-style: none;
	margin: 0;
	padding: 0;
	position: relative;
}

.fb-facet__list--sub > li > .fb-check {
	padding-left: calc(var(--space-3) + 18px);
	position: relative;
}

.fb-facet__list--sub > li > .fb-check::before {
	content: "";
	position: absolute;
	left: var(--space-3);
	top: 6px;
	bottom: 6px;
	width: 1px;
	background: var(--border-default);
}

/* ---- the overflow disclosure on a long facet (audit M-9) ---- */

/*
 * Brand brings several hundred terms after the product import, which is unusable as a flat list.
 * The overflow is a nested <details> so it stays real, crawlable markup and opens with no
 * JavaScript — the same reasoning as the facet groups themselves.
 */
.fb-facet__more { margin-top: var(--space-2); }

.fb-facet__more-summary {
	display: inline-flex;
	align-items: center;
	min-height: 32px;
	cursor: pointer;
	font-family: var(--font-body);
	font-size: var(--text-caption);
	font-weight: var(--fw-semibold);
	color: var(--brand-700);
	text-decoration: underline;
	text-underline-offset: 2px;
	list-style: none;
}

.fb-facet__more-summary::-webkit-details-marker { display: none; }
.fb-facet__more-summary::marker { content: ""; }
.fb-facet__more-summary:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.fb-facet__more[open] .fb-facet__more-summary { margin-bottom: var(--space-1); }

/* ---- a checkbox that is really a link ---- */

/*
 * Rendered as an anchor, not an input, because ticking a facet navigates. It is drawn as a
 * checkbox because that is what the control means to a buyer, and it is how the design kit draws
 * it. `aria-current` carries the checked state to assistive tech.
 *
 * Two classes on these rules: the theme and WooCommerce both style bare links inside the
 * catalogue, and either would recolour the row.
 */
.fb-filters .fb-check {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	min-height: var(--tap-min);
	font-size: var(--text-body-sm);
	color: var(--text-primary);
	text-decoration: none;
	cursor: pointer;
}

.fb-filters .fb-check:hover { color: var(--text-primary); text-decoration: none; }
.fb-filters .fb-check:hover .fb-check__label { text-decoration: underline; }

.fb-filters .fb-check:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
	border-radius: var(--radius-sm);
}

.fb-check__box {
	width: 18px;
	height: 18px;
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: var(--border-width-strong) solid var(--border-strong);
	border-radius: var(--radius-sm);
	background: var(--surface-card);
	transition: var(--transition-control);
}

.fb-check.is-checked .fb-check__box {
	border-color: var(--fb-ink);
	background: var(--fb-ink);
	color: var(--fb-green);
}

.fb-check__label { flex: 1; }

.fb-check__count {
	font-size: var(--text-caption);
	color: var(--text-muted);
}

/* ---- active filter chips ---- */

.fb-active-filters {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--space-2);
}

.fb-tag {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	height: 28px;
	padding-inline: var(--space-3);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-pill);
	background: var(--surface-card);
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-medium);
	text-decoration: none;
	transition: var(--transition-control);
}

.fb-active-filters .fb-tag--active {
	border-color: var(--fb-ink);
	background: var(--fb-ink);
	color: var(--text-inverse);
}

.fb-active-filters .fb-tag--active:hover {
	background: var(--steel-700);
	border-color: var(--steel-700);
	color: var(--text-inverse);
	text-decoration: none;
}

.fb-active-filters__clear {
	font-size: var(--text-caption);
	color: var(--text-muted);
	text-decoration: none;
}

.fb-active-filters__clear:hover { color: var(--text-primary); text-decoration: underline; }

/* ---- empty state ---- */

.fb-empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: var(--space-3);
	padding: var(--space-16) var(--space-6);
	border: var(--border-width) dashed var(--border-default);
	border-radius: var(--radius-lg);
	background: var(--surface-subtle);
}

.fb-empty .fb-icon { color: var(--steel-400); }

.fb-empty__title {
	font-family: var(--font-display);
	font-size: var(--text-h3);
	font-weight: var(--fw-bold);
	margin: 0;
}

.fb-empty__text {
	color: var(--text-secondary);
	max-width: 44ch;
	margin: 0;
}

.fb-empty__actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--space-3);
	margin-top: var(--space-2);
}

/* ---- the mobile sheet ---- */

@media (max-width: 860px) {
	.fb-catalog { grid-template-columns: minmax(0, 1fr); gap: 0; }

	/* The sidebar stops being a column and becomes a sheet over the results. */
	.fb-catalog__aside { position: static; }

	.fb-filters {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 80;
		max-height: 82vh;
		overflow-y: auto;
		padding: var(--space-5);
		background: var(--surface-card);
		border-radius: var(--radius-lg) var(--radius-lg) 0 0;
		box-shadow: var(--shadow-lg);

		/* Off-canvas rather than display:none, so the panel slides rather than blinks. */
		transform: translateY(100%);
		visibility: hidden;
		transition: transform var(--dur-base) var(--ease-out), visibility var(--dur-base);
	}

	.fb-filters.is-open {
		transform: translateY(0);
		visibility: visible;
	}

	.fb-filters__head {
		position: sticky;
		top: calc(var(--space-5) * -1);
		z-index: 1;
		background: var(--surface-card);
		padding-block: var(--space-2) var(--space-3);
	}

	.fb-filters__close { display: inline-flex; }

	.fb-filters__done {
		display: block;
		position: sticky;
		bottom: calc(var(--space-5) * -1);
		background: var(--surface-card);
		padding-block: var(--space-4);
	}

	.fb-filters__done .fb-btn { width: 100%; }

	/* Injected by site.js, so it only exists when it can actually be dismissed. */
	.fb-filters-scrim {
		position: fixed;
		inset: 0;
		z-index: 79;
		background: rgba(44, 46, 53, 0.55);
		border: 0;
		padding: 0;
		opacity: 0;
		visibility: hidden;
		transition: opacity var(--dur-base) linear, visibility var(--dur-base);
	}

	.fb-filters-scrim.is-open { opacity: 1; visibility: visible; }
}

@media (prefers-reduced-motion: reduce) {
	.fb-filters { transition: none; }
}

/* Above the sheet breakpoint the scrim has no job. */
@media (min-width: 861px) {
	.fb-filters-scrim { display: none; }
}

/* =============================================== account: lists and documents ===
   My Account → Orders and → Quotes share the dashboard's table (`fb-account-table--list`), and one
   order (woocommerce/myaccount/view-order.php) and one quote (the quotes plugin's detail view)
   share the `fb-doc` layout, which is the cart's and the quote list's: the lines as a table with
   64px thumbnails on a tint, a sticky 340px summary card with mono figures, and at 720px the rows
   turn into cards and the card follows them (client, 2026-09-30). Values are the cart's, measured
   from cart.css, not re-derived. */

.woocommerce-account .fb-account-lede {
	max-width: 62ch;
	margin: 0 0 var(--space-6);
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	text-wrap: pretty;
}

.fb-account-table--list td.is-mono a { font-weight: var(--fw-semibold); color: var(--text-primary); }
.fb-account-table--list .is-actions { white-space: nowrap; }
.fb-account-table--list .is-actions .fb-btn + .fb-btn { margin-left: var(--space-2); }

.fb-account-pager {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	margin-top: var(--space-6);
}

.fb-account-pager__count { color: var(--text-muted); font-size: var(--text-body-sm); }

/* --- One order or quote -------------------------------------------------- */

.fb-doc__back {
	display: inline-flex;
	gap: var(--space-2);
	margin-bottom: var(--space-4);
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	text-decoration: none;
}

.fb-doc__back:hover { color: var(--text-primary); text-decoration: underline; }

.fb-doc__head {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--space-3) var(--space-6);
	padding-bottom: var(--space-5);
	margin-bottom: var(--space-6);
	border-bottom: 1px solid var(--border-default);
}

.fb-doc__head .fb-eyebrow { margin: 0 0 var(--space-1); }

.fb-doc__title {
	margin: 0;
	font-family: var(--font-mono);
	font-size: var(--text-h2);
	line-height: var(--lh-tight);
	letter-spacing: -0.01em;
}

.fb-doc__meta { margin: var(--space-2) 0 0; color: var(--text-muted); font-size: var(--text-body-sm); }
.fb-doc__meta span { margin-inline: var(--space-1); }

.fb-doc__head .fb-badge { margin-top: var(--space-2); }

.fb-doc__grid {
	display: grid;
	grid-template-columns: minmax( 0, 1fr ) 340px;
	gap: var(--space-10);
	align-items: start;
}

.fb-doc__main { min-width: 0; }

/* Lines: the cart's table. */
.fb-lines {
	width: 100%;
	margin: 0 0 var(--space-8);
	border-collapse: collapse;
	font-size: var(--text-body-sm);
}

.fb-lines th {
	padding: var(--space-3);
	border-bottom: 1px solid var(--border-default);
	color: var(--text-muted);
	font-size: var(--text-micro);
	font-weight: 600;
	letter-spacing: var(--ls-eyebrow, 0.09em);
	text-align: left;
	text-transform: uppercase;
	white-space: nowrap;
}

.fb-lines td {
	padding: var(--space-4) var(--space-3);
	border-bottom: 1px solid var(--border-subtle);
	vertical-align: middle;
}

.fb-lines th:first-child,
.fb-lines td:first-child { padding-left: 0; }

.fb-lines th:last-child,
.fb-lines td:last-child { padding-right: 0; }

.fb-lines__thumb { width: 88px; min-width: 88px; }

.fb-lines__thumb img,
.fb-lines__img {
	display: block;
	width: 64px;
	height: 64px;
	object-fit: contain;
	background: var(--surface-subtle);
	border-radius: var(--radius-md);
}

td.fb-lines__product { width: 100%; min-width: 200px; }

.fb-lines__name {
	display: block;
	color: var(--text-primary);
	font-weight: 600;
	text-decoration: none;
	text-wrap: pretty;
}

a.fb-lines__name:hover { text-decoration: underline; }

.fb-lines__meta {
	margin: var(--space-1) 0 0;
	padding: 0;
	list-style: none;
	color: var(--text-secondary);
	font-size: var(--text-caption);
}

.fb-lines__meta p { display: inline; margin: 0; }
.fb-lines__meta strong { font-weight: 600; }

.fb-lines__sku {
	display: block;
	margin-top: var(--space-1);
	color: var(--text-muted);
	font-family: var(--font-mono);
	font-size: var(--text-caption);
}

.fb-lines__num {
	text-align: right !important;
	white-space: nowrap;
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
}

.fb-lines__total { font-weight: 600; }
.fb-lines__note { display: block; color: var(--status-danger); font-size: var(--text-caption); }

/* Details under the lines. */
.fb-doc__cards {
	display: grid;
	grid-template-columns: repeat( auto-fit, minmax( 220px, 1fr ) );
	gap: var(--space-4);
	margin-bottom: var(--space-6);
}

.fb-doc__card,
.fb-doc__section {
	padding: var(--space-5);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-lg);
	background: var(--surface-subtle);
	font-size: var(--text-body-sm);
	color: var(--text-secondary);
}

.fb-doc__section { margin-bottom: var(--space-6); }

.fb-doc__card-title {
	margin: 0 0 var(--space-3);
	color: var(--text-muted);
	font-family: var(--font-body);
	font-size: var(--text-micro);
	font-weight: 600;
	letter-spacing: var(--ls-eyebrow, 0.09em);
	text-transform: uppercase;
}

.fb-doc__card-title:not(:first-child) { margin-top: var(--space-4); }
.fb-doc__card p,
.fb-doc__card address { margin: 0 0 var(--space-2); font-style: normal; line-height: var(--lh-normal, 1.5); }
.fb-doc__card-lead { color: var(--text-primary); font-weight: 600; }
.fb-doc__files { margin: 0; padding-left: var(--space-5); }
.fb-doc__prose > :last-child { margin-bottom: 0; }

.fb-doc__timeline { margin: 0; padding: 0; list-style: none; }
.fb-doc__timeline li { padding: var(--space-3) 0 var(--space-3) var(--space-4); border-left: 2px solid var(--fb-green); }
.fb-doc__timeline li + li { margin-top: var(--space-2); }
.fb-doc__timeline time { display: block; margin-bottom: var(--space-1); color: var(--text-muted); font-size: var(--text-caption); }

/* The summary: the cart totals card. */
.fb-doc__panel {
	position: sticky;
	top: var(--sticky-offset, 160px);
	padding: var(--space-5);
	border: 1px solid var(--border-default);
	border-radius: var(--radius-lg);
	background: var(--surface-card);
}

.fb-doc__panel-title {
	margin: 0 0 var(--space-4);
	color: var(--text-muted);
	font-family: var(--font-body);
	font-size: var(--text-micro);
	font-weight: 600;
	letter-spacing: var(--ls-eyebrow, 0.09em);
	text-transform: uppercase;
}

.fb-doc__status {
	margin: 0 0 var(--space-4);
	padding: var(--space-3);
	border-radius: var(--radius-md);
	background: var(--fb-green-100);
	color: var(--text-primary);
	font-size: var(--text-body-sm);
}

.fb-doc__totals { margin: 0; font-size: var(--text-body-sm); }

.fb-doc__row {
	display: flex;
	justify-content: space-between;
	gap: var(--space-4);
	padding: var(--space-2) 0;
}

.fb-doc__row dt { color: var(--text-secondary); }

.fb-doc__row dd {
	margin: 0;
	text-align: right;
	font-family: var(--font-mono);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}

.fb-doc__row dd small { display: block; font-weight: 400; color: var(--text-muted); }

.fb-doc__row--total {
	margin-top: var(--space-1);
	padding-top: var(--space-3);
	border-top: 1px solid var(--border-default);
	font-size: var(--text-body);
}

.fb-doc__row--total dt { color: var(--text-primary); font-weight: 600; }

.fb-doc__actions { display: grid; gap: var(--space-2); margin-top: var(--space-5); }

.fb-doc__help { margin: var(--space-4) 0 0; color: var(--text-muted); font-size: var(--text-caption); text-align: center; }

@media ( max-width: 1080px ) {
	.fb-doc__grid { grid-template-columns: minmax( 0, 1fr ); gap: var(--space-6); }
	.fb-doc__panel { position: static; }
}

@media ( max-width: 720px ) {
	/* Lines become cards: thumbnail beside the name, the figures on one row beneath. */
	.fb-lines thead { display: none; }

	.fb-lines,
	.fb-lines tbody { display: block; }

	.fb-lines tr {
		display: grid;
		grid-template-columns: 72px 1fr;
		gap: var(--space-2) var(--space-3);
		padding: var(--space-4) 0;
		border-bottom: 1px solid var(--border-subtle);
	}

	.fb-lines td { display: block; padding: 0 !important; border: 0; }
	.fb-lines__thumb { width: 72px; min-width: 0; grid-row: span 2; }
	td.fb-lines__product { min-width: 0; }

	.fb-lines td.fb-lines__num {
		display: inline-flex;
		justify-content: space-between;
		grid-column: 2;
		font-size: var(--text-body-sm);
	}

	.fb-lines td.fb-lines__num::before {
		content: attr(data-title);
		color: var(--text-muted);
		font-family: var(--font-body);
		font-weight: 400;
	}

	/* The lists: each row a card, each cell labelled. */
	.fb-account-table--list thead { display: none; }

	.fb-account-table--list,
	.fb-account-table--list tbody,
	.fb-account-table--list tr,
	.fb-account-table--list td { display: block; width: 100%; }

	.fb-account-table--list tr {
		margin-bottom: var(--space-3);
		padding: var(--space-4);
		border: 1px solid var(--border-subtle);
		border-radius: var(--radius-lg);
	}

	.fb-account-table--list td {
		display: flex;
		justify-content: space-between;
		gap: var(--space-4);
		padding: var(--space-1) 0;
		border: 0;
		text-align: right;
	}

	.fb-account-table--list td[data-title]::before {
		content: attr(data-title);
		color: var(--text-muted);
		font-family: var(--font-body);
		text-align: left;
	}

	.fb-account-table--list .fb-account-table__detail { display: none; }

	.fb-account-table--list td.is-actions { justify-content: flex-end; padding-top: var(--space-3); }
}

/* ============================================================ account: addresses ===
   My Account → Addresses in the checkout's design (client, 2026-09-30). The overview is two
   `fb-doc__card`s, Delivery then Billing; the edit form is the checkout's address section. The
   field rules below are a copy of checkout.css "fields", whose selectors are scoped to the checkout
   page — keep the two in step. */

.fb-addresses { margin-bottom: 0; }

.fb-address-card { background: var(--surface-card); border-color: var(--border-default); }

.fb-address-card__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	margin-bottom: var(--space-3);
}

.fb-address-card__head .fb-doc__card-title { margin: 0; }
.fb-address-card address { font-style: normal; line-height: var(--lh-normal, 1.5); color: var(--text-primary); }

.fb-address-form__title {
	margin: 0 0 var(--space-1);
	font-family: var(--font-display);
	font-size: var(--text-h3);
	font-weight: var(--fw-bold);
	line-height: 1.25;
}

.fb-address-form__hint { margin: 0 0 var(--space-5); color: var(--text-muted); font-size: var(--text-caption); }

.fb-address-form .fb-checkout__fields {
	display: grid;
	grid-template-columns: repeat(6, minmax(0, 1fr));
	gap: var(--space-3);
	align-items: end; /* a pair's boxes line up even when one label wraps ("Company name (optional)") */
}

.fb-address-form .fb-checkout__fields > * { grid-column: 1 / -1; }

.fb-address-form .fb-checkout__fields > .form-row {
	float: none;
	width: auto;
	margin: 0;
	padding: 0;
}

.fb-address-form .fb-checkout__fields > .form-row-first { grid-column: 1 / span 3; }
.fb-address-form .fb-checkout__fields > .form-row-last { grid-column: 4 / span 3; }
.fb-address-form .fb-checkout__fields > [id$="_city_field"] { grid-column: 1 / span 3; }
.fb-address-form .fb-checkout__fields > [id$="_postcode_field"] { grid-column: 4 / span 3; }
.fb-address-form .fb-checkout__fields:has(> [id$="_state_field"]:not([style*="none"])) > [id$="_city_field"] { grid-column: 1 / span 2; }
.fb-address-form .fb-checkout__fields:has(> [id$="_state_field"]:not([style*="none"])) > [id$="_state_field"] { grid-column: 3 / span 2; }
.fb-address-form .fb-checkout__fields:has(> [id$="_state_field"]:not([style*="none"])) > [id$="_postcode_field"] { grid-column: 5 / span 2; }

.fb-address-form .form-row label {
	display: block;
	margin: 0 0 var(--space-1);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	line-height: 1.4;
	color: var(--text-primary);
}

.fb-address-form .form-row label.screen-reader-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.fb-address-form .form-row label .optional { font-weight: var(--fw-regular); color: var(--text-muted); }
.fb-address-form .form-row .required { border: 0; color: var(--status-danger); text-decoration: none; }
.fb-address-form .form-row .woocommerce-input-wrapper { display: block; position: relative; }

.fb-address-form .form-row input.input-text,
.fb-address-form .form-row select,
.fb-address-form .form-row textarea {
	width: 100%;
	height: var(--control-h-lg);
	min-height: var(--tap-min);
	margin: 0;
	padding: 0 var(--space-3);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
	background: var(--surface-card);
	color: var(--text-primary);
	font-family: var(--font-body);
	font-size: var(--text-body);
	line-height: 1.4;
	box-shadow: none;
	transition: var(--transition-control);
}

.fb-address-form .form-row input.input-text:hover,
.fb-address-form .form-row select:hover { border-color: var(--border-strong); }

.fb-address-form .form-row input.input-text:focus,
.fb-address-form .form-row select:focus {
	border-color: var(--border-focus);
	outline: none;
	box-shadow: var(--focus-ring);
}

.fb-address-form .form-row input.input-text::placeholder { color: var(--text-muted); }

/*
 * WooCommerce's country and state pickers are selectWoo widgets. The chosen value is centred with
 * flex rather than a line-height that has to allow for the border — a line-height equal to the
 * box height sat the text on the bottom border (client, 2026-09-30).
 */
body.woocommerce-account .fb-address-form .form-row .select2-container .select2-selection--single {
	display: flex;
	align-items: center;
	box-sizing: border-box;
	height: var(--control-h-lg);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
	background: var(--surface-card);
}

body.woocommerce-account .fb-address-form .form-row .select2-container .select2-selection--single .select2-selection__rendered {
	flex: 1;
	padding: 0 var(--space-8) 0 var(--space-3);
	line-height: 1.4;
	font-size: var(--text-body);
	color: var(--text-primary);
}

body.woocommerce-account .fb-address-form .form-row .select2-container .select2-selection--single .select2-selection__arrow {
	top: 50%;
	right: var(--space-2);
	height: 26px;
	transform: translateY(-50%);
}

body.woocommerce-account .fb-address-form .form-row .select2-container--open .select2-selection--single,
body.woocommerce-account .fb-address-form .form-row .select2-container--focus .select2-selection--single {
	border-color: var(--border-focus);
	box-shadow: var(--focus-ring);
}

.fb-address-form .form-row.woocommerce-invalid input.input-text,
.fb-address-form .form-row.woocommerce-invalid select { border-color: var(--status-danger); }

.fb-address-form__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin-top: var(--space-6);
}

/* Pairs stay side by side on a phone, as they do at the checkout. */
@media ( max-width: 520px ) {
	.fb-address-form__actions .fb-btn { flex: 1 1 auto; }
}
