/**
 * Fischer Bell — component layer.
 *
 * A CSS port of the Claude Design component library (components/core, /commerce, /forms,
 * /navigation). The design system expresses these as React inline styles; here they are
 * classes so block patterns, WooCommerce templates and PHP partials can all share them.
 *
 * Every value comes from tokens.css, which in turn aliases theme.json. No literal colours.
*/

/* ----------------------------------------------------------------- base ----
   Ported from the kit's tokens/base.css, whose very first rule this is. It was
   missed in the original port, leaving the whole theme on the content-box model:
   any element with padding plus a percentage or fixed dimension added the padding
   ON TOP of it. That is what made service cards overflow their own grid cell and
   overlap the row below by exactly padding*2 + border. */

*,
*::before,
*::after {
	box-sizing: border-box;
}

/* Form controls do not inherit type from their parent by default — left alone, a bare <button>
   or <input> renders in the browser's own UI font (Arial here) rather than IBM Plex Sans. */
button,
input,
select,
optgroup,
textarea {
	font-family: inherit;
	font-size: inherit;
}

/* ---------------------------------------------------------------- layout ---- */

.fb-shell {
	max-width: var(--container-max);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.fb-section {
	padding-block: var(--space-20);
}

.fb-section--subtle {
	background: var(--surface-subtle);
}

.fb-section--ink {
	background: var(--fb-ink);
	color: var(--text-inverse);
}

.fb-grid {
	display: grid;
	gap: var(--space-4);
}

/* Auto-fill grids sized to the design's minmax() tracks. */
.fb-grid--cats { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.fb-grid--products { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }
.fb-grid--services { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.fb-grid--steps { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.fb-grid--partners { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--space-3); }
.fb-grid--trust { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-6); }

/* ------------------------------------------------------------ typography ---- */

.fb-eyebrow {
	font-family: var(--font-body);
	font-size: var(--text-micro);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
	color: var(--text-muted);
}

.fb-eyebrow--brand { color: var(--fb-green); }
.fb-eyebrow--rule { display: flex; align-items: center; gap: var(--space-2); }
.fb-eyebrow--rule::before { content: ""; width: 24px; height: 3px; background: var(--fb-green); }
.fb-section-header--center .fb-eyebrow--rule { justify-content: center; }

.fb-mono {
	font-family: var(--font-mono);
	font-size: var(--text-caption);
}

.fb-display-1 {
	font-family: var(--font-display);
	font-size: var(--text-display-1);
	font-weight: var(--fw-black);
	letter-spacing: var(--ls-display);
	line-height: var(--lh-tight);
	margin: 0;
}

.fb-display-2 {
	font-family: var(--font-display);
	font-size: var(--text-display-2);
	font-weight: var(--fw-black);
	letter-spacing: var(--ls-display);
	line-height: var(--lh-tight);
	margin: 0;
}

.fb-lede {
	font-size: var(--text-body-lg);
	color: var(--text-secondary);
	line-height: var(--lh-relaxed);
	text-wrap: pretty;
}

/*
 * Inverted surfaces redefine the text token locally rather than overriding each component in turn.
 *
 * `.fb-lede` takes `--text-secondary`, which is a dark grey meant for light surfaces. The
 * dark-surface override used to be scoped `.fb-section--ink .fb-lede` — and the home hero is
 * wrapped in `.fb-hero`, not `.fb-section--ink`, so it never matched: the homepage's main lede
 * rendered at 1.65:1 against the ink panel (audit U-1).
 *
 * Setting the token means anything dropped into an ink surface inherits the right value, instead of
 * needing a new override each time. `--steel-300` on `--fb-ink` measures 6.5:1.
 */
.fb-hero,
.fb-section--ink {
	--text-secondary: var(--steel-300);
}

/* ------------------------------------------------------- section header ---- */

.fb-section-header {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--space-6);
	margin-bottom: var(--space-8);
	flex-wrap: wrap;
}

.fb-section-header--center {
	flex-direction: column;
	align-items: center;
	text-align: center;
}

.fb-section-header__title {
	font-family: var(--font-display);
	font-size: var(--text-h2);
	font-weight: var(--fw-bold);
	letter-spacing: var(--ls-heading);
	line-height: var(--lh-snug);
	margin: var(--space-2) 0 0;
	max-width: 34ch;
	text-wrap: balance;
}

.fb-section-header__description {
	font-size: var(--text-body);
	color: var(--text-secondary);
	margin: var(--space-3) 0 0;
	max-width: 62ch;
	text-wrap: pretty;
}

.fb-section--ink .fb-section-header__description { color: var(--steel-300); }

/* ------------------------------------------------- section header action ----
   The kit's SectionHeader renders its action as a text link underlined in brand
   green with a trailing arrow — not as an outlined button. */

.fb-section-header__action {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	padding-bottom: 3px;
	border-bottom: 2px solid var(--fb-green);
	color: var(--text-primary);
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	text-decoration: none;
	white-space: nowrap;
	transition: var(--transition-control);
}

.fb-section-header__action:hover,
.fb-section-header__action:focus-visible {
	color: var(--fb-green-700);
	border-bottom-color: var(--fb-green-700);
}

/* The link is only ~24px tall, which the kit's layout depends on. Enlarge the touch target
   invisibly rather than padding the box and pushing the underline away from the text. */
.fb-section-header__action::after {
	content: "";
	position: absolute;
	inset: -10px -6px;
}

.fb-section-header__action .fb-icon {
	transition: var(--transition-control);
}

.fb-section-header__action:hover .fb-icon {
	transform: translateX(2px);
}

/* ------------------------------------------------------- service card ----
   Icon-plus-text card. The kit tints the icon brand green, which is what
   separates a service from a product category at a glance. */

.fb-service-card {
	display: flex;
	gap: var(--space-4);
	align-items: flex-start;
}

.fb-service-card .fb-icon {
	color: var(--fb-green-700);
}

/* ---------------------------------------------------------------- button ---- */

.fb-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	font-family: var(--font-body);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-button);
	border-radius: var(--radius-md);
	border: var(--border-width) solid transparent;
	cursor: pointer;
	text-decoration: none;
	white-space: nowrap;
	transition: var(--transition-control);

	/* size md is the default */
	height: var(--control-h-md);
	min-height: var(--tap-min);
	padding-inline: var(--space-5);
	font-size: var(--text-body-sm);
}

.fb-btn:active { transform: scale(var(--press-scale)); }
.fb-btn[disabled],
.fb-btn[aria-disabled="true"] { opacity: 0.42; pointer-events: none; }
.fb-btn:hover { text-decoration: none; }

.fb-btn--sm { height: var(--control-h-sm); min-height: 0; padding-inline: var(--space-3); font-size: var(--text-body-sm); }
.fb-btn--lg { height: var(--control-h-lg); padding-inline: var(--space-6); font-size: var(--text-body); }
.fb-btn--block { width: 100%; }

.fb-btn--cart { background: var(--cta-cart-bg); color: var(--cta-cart-fg); }
.fb-btn--cart:hover { background: var(--steel-700); color: var(--cta-cart-fg); }

.fb-btn--quote { background: var(--cta-quote-bg); color: var(--cta-quote-fg); }
.fb-btn--quote:hover { background: var(--fb-green-600); color: var(--cta-quote-fg); }

.fb-btn--secondary { background: var(--surface-card); color: var(--text-primary); border-color: var(--border-strong); }
.fb-btn--secondary:hover { background: var(--surface-subtle); border-color: var(--steel-400); color: var(--text-primary); }

.fb-btn--ghost { background: transparent; color: var(--text-primary); }
.fb-btn--ghost:hover { background: var(--surface-subtle); color: var(--text-primary); }

.fb-btn--danger { background: var(--status-danger); color: var(--text-inverse); }
.fb-btn--danger:hover { background: #8f1c13; color: var(--text-inverse); }

.fb-btn--inverse { background: var(--surface-card); color: var(--fb-ink); }
.fb-btn--inverse:hover { background: var(--steel-100); color: var(--fb-ink); }

.fb-icon-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: var(--control-h-md);
	height: var(--control-h-md);
	min-width: var(--tap-min);
	min-height: var(--tap-min);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
	background: var(--surface-card);
	color: var(--text-primary);
	cursor: pointer;
	transition: var(--transition-control);
}

.fb-icon-btn:hover { background: var(--surface-subtle); }

/* ------------------------------------------------------------------ card ---- */

.fb-card {
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-lg);
	padding: var(--space-6);
	background: var(--surface-card);
	transition: var(--transition-surface);
}

.fb-card--subtle { background: var(--surface-subtle); border-color: var(--border-subtle); }
.fb-card--inverse { background: var(--surface-inverse); border-color: var(--border-inverse); color: var(--text-inverse); }
.fb-card--pad-5 { padding: var(--space-5); }
/* Fills the grid cell it is stretched into, so cards in a row share one height. */
.fb-card--fill { height: 100%; }

.fb-card--interactive:hover {
	box-shadow: var(--shadow-md);
	transform: translateY(-2px);
}

/*
 * Grid items stretch to their row by default, and the card inside carries height:100%. Adding
 * a percentage height HERE too made the anchor's height depend on a row that was sized from the
 * anchor - the card then overflowed its cell and overlapped the row beneath it.
 */
a.fb-card-link { text-decoration: none; color: inherit; display: block; }
a.fb-card-link:hover { text-decoration: none; color: inherit; }

/* ----------------------------------------------------------------- badge ---- */

.fb-badge {
	display: inline-flex;
	align-items: center;
	gap: var(--space-1);
	padding: 3px var(--space-2);
	border-radius: var(--radius-sm);
	font-family: var(--font-body);
	font-size: var(--text-micro);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
	background: var(--surface-sunken);
	color: var(--text-secondary);
}

.fb-badge--neutral { background: var(--surface-sunken); color: var(--text-secondary); }
.fb-badge--brand { background: var(--fb-green-100); color: var(--fb-green-700); }
.fb-badge--success { background: var(--status-success-bg); color: var(--status-success); }
.fb-badge--warning { background: var(--status-warning-bg); color: var(--status-warning); }
.fb-badge--danger { background: var(--status-danger-bg); color: var(--status-danger); }
.fb-badge--info { background: var(--status-info-bg); color: var(--status-info); }
.fb-badge--ink { background: var(--fb-ink); color: var(--text-inverse); }

/* Certification marks read as compliance data, so they get the mono face and a hard edge. */
.fb-cert {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 2px var(--space-2);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-sm);
	background: var(--surface-card);
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	font-weight: var(--fw-medium);
	color: var(--text-secondary);
	white-space: nowrap;
}

/* -------------------------------------------------------- step indicator ---- */

/*
 * The recommender's progress rail. An ordered list of real text rather than a row of dots: it
 * says how much is left, and it is the only part of a multi-step form that still makes sense
 * read out linearly.
 */
.fb-steps {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin: 0;
	padding: 0;
	list-style: none;
}

.fb-steps__item {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	font-size: var(--text-caption);
	font-weight: var(--fw-medium);
	color: var(--text-muted);
}

/* The connector belongs to the item, not to the gap, so it wraps along with it. */
.fb-steps__item::after {
	content: "";
	width: 24px;
	height: 1px;
	margin-left: var(--space-1);
	background: var(--border-default);
}

.fb-steps__item:last-child::after { content: none; }

.fb-steps__n {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 24px;
	height: 24px;
	border-radius: var(--radius-pill);
	background: var(--surface-sunken);
	color: var(--text-primary);
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	font-weight: var(--fw-semibold);
}

.fb-steps__item.is-current {
	color: var(--text-primary);
	font-weight: var(--fw-semibold);
}

.fb-steps__item.is-current .fb-steps__n { background: var(--fb-green); }

.fb-steps__item.is-done { color: var(--text-primary); }

.fb-steps__item.is-done .fb-steps__n {
	background: var(--fb-ink);
	color: var(--fb-green);
}

/*
 * On a phone six labels wrap to three lines and push the question off screen. Only the current
 * label stays visible — the rest are hidden the way .fb-visually-hidden hides things, so the rail
 * still reads as "Step 3 of 6, Hazards" to a screen reader.
 */
@media (max-width: 640px) {
	.fb-steps { gap: var(--space-2); }

	.fb-steps__item:not(.is-current) .fb-steps__label {
		position: absolute;
		width: 1px;
		height: 1px;
		padding: 0;
		margin: -1px;
		overflow: hidden;
		clip: rect(0 0 0 0);
		white-space: nowrap;
		border: 0;
	}

	.fb-steps__item::after { width: 12px; }
}

/* --------------------------------------------------------- choice rows ---- */

/*
 * The kit's card-shaped Radio and Checkbox, shared by the product recommender and the booking
 * panel. A real <label> wrapping a real input: the input is hidden but still focusable and still in
 * the tab order, so keyboard and screen-reader behaviour is the browser's own and only the painted
 * box is ours.
 *
 * `:has()` styles the row from its input's state. Where it is unsupported the row loses its
 * highlight but the tick still tracks the input — a legible degradation, not a broken form.
 *
 * The same class also renders as a plain link (the booking panel's session picker), where there is
 * no input at all and the mark carries an arrow instead.
 */
.fb-choices {
	display: grid;
	gap: var(--space-2);
	margin-top: var(--space-6);
}

.fb-choice {
	display: flex;
	align-items: flex-start;
	gap: var(--space-3);
	min-height: var(--tap-min);
	padding: var(--space-3) var(--space-4);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
	background: var(--surface-card);
	cursor: pointer;
	transition: var(--transition-control);
}

.fb-choice:hover { border-color: var(--border-strong); }

/* Hidden, not removed: the input keeps the focus ring, the tab order and the label association. */
.fb-choice__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-choice:has(.fb-choice__input:checked) {
	border-color: var(--fb-ink);
	background: var(--fb-green-100);
}

.fb-choice:has(.fb-choice__input:focus-visible) {
	box-shadow: var(--focus-ring);
	border-color: var(--fb-ink);
}

.fb-choice__mark {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 18px;
	height: 18px;
	margin-top: 2px;
	border: var(--border-width-strong) solid var(--border-strong);
	border-radius: var(--radius-sm);
	background: var(--surface-card);
	transition: var(--transition-control);
}

/* One question, one answer: a round mark says so before the buyer has clicked anything. */
.fb-choice__input[type="radio"] ~ .fb-choice__mark { border-radius: var(--radius-pill); }

.fb-choice__input:checked ~ .fb-choice__mark {
	border-color: var(--fb-ink);
	background: var(--fb-ink);
}

.fb-choice__input[type="radio"]:checked ~ .fb-choice__mark::after {
	content: "";
	width: 7px;
	height: 7px;
	border-radius: var(--radius-pill);
	background: var(--fb-green);
}

.fb-choice__input[type="checkbox"]:checked ~ .fb-choice__mark::after {
	content: "";
	width: 5px;
	height: 9px;
	margin-top: -2px;
	border: 2px solid var(--fb-green);
	border-top: 0;
	border-left: 0;
	transform: rotate(45deg);
}

.fb-choice__body {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}

.fb-choice__label {
	font-size: var(--text-body);
	font-weight: var(--fw-medium);
	color: var(--text-primary);
}

.fb-choice__desc {
	font-size: var(--text-body-sm);
	color: var(--text-secondary);
}

/* ------------------------------------------------------- step navigation ---- */

/*
 * Back on the left, forward on the right, on every multi-step flow. On a phone it stacks in
 * column-reverse so the forward action sits where the thumb is and Back below it, rather than
 * above the last option of the question.
 */
.fb-stepnav {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	margin-top: var(--space-8);
}

/* The placeholder that holds Back's slot on the first step. */
.fb-stepnav > span:empty { display: block; }

@media (max-width: 640px) {
	.fb-choices { margin-top: var(--space-5); }

	.fb-stepnav {
		flex-direction: column-reverse;
		align-items: stretch;
		margin-top: var(--space-6);
	}

	.fb-stepnav > span:empty { display: none; }

	.fb-stepnav .fb-btn { justify-content: center; }
}

/* ------------------------------------------------------------------ alert ---- */

.fb-alert {
	display: flex;
	gap: var(--space-3);
	padding: var(--space-4);
	border-radius: var(--radius-md);
	border-left: 3px solid var(--status-info);
	background: var(--status-info-bg);
	font-size: var(--text-body-sm);
	color: var(--text-primary);
}

.fb-alert .fb-icon {
	flex: none;
	margin-top: 1px;
	color: var(--status-info);
}

.fb-alert__body { flex: 1; min-width: 0; }

.fb-alert__title {
	margin: 0;
	font-weight: var(--fw-semibold);
}

.fb-alert__text {
	margin: var(--space-1) 0 0;
	color: var(--text-secondary);
}

.fb-alert--success { background: var(--status-success-bg); border-left-color: var(--status-success); }
.fb-alert--success .fb-icon { color: var(--status-success); }

.fb-alert--warning { background: var(--status-warning-bg); border-left-color: var(--status-warning); }
.fb-alert--warning .fb-icon { color: var(--status-warning); }

.fb-alert--danger { background: var(--status-danger-bg); border-left-color: var(--status-danger); }
.fb-alert--danger .fb-icon { color: var(--status-danger); }

/* ------------------------------------------------------------ price block ---- */

.fb-price__row {
	display: flex;
	align-items: baseline;
	gap: var(--space-2);
	flex-wrap: wrap;
}

.fb-price__now {
	font-family: var(--font-display);
	font-weight: var(--fw-bold);
	font-size: var(--text-h3);
	letter-spacing: var(--ls-heading);
	color: var(--text-primary);
}

.fb-price--lg .fb-price__now { font-size: var(--text-h1); }
.fb-price--wholesale .fb-price__now { color: var(--fb-green-700); }

.fb-price__was {
	font-size: var(--text-body-sm);
	color: var(--text-muted);
	text-decoration: line-through;
}

.fb-price__meta {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	margin-top: var(--space-2);
	font-size: var(--text-caption);
	color: var(--text-muted);
}

/* Logged-out wholesale prompt — the price slot is never simply blank. */
.fb-price__gate {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	color: var(--fb-green-700);
	text-decoration: none;
}

.fb-price__gate:hover { text-decoration: underline; color: var(--fb-green-700); }

/* ----------------------------------------------------------- stock status ---- */

.fb-stock {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	font-size: var(--text-caption);
	font-weight: var(--fw-medium);
}

.fb-stock--in-stock { color: var(--status-success); }
.fb-stock--low,
.fb-stock--back-order { color: var(--status-warning); }
.fb-stock--out { color: var(--status-danger); }
.fb-stock--made-to-order { color: var(--status-info); }

.fb-stock__qty {
	font-family: var(--font-mono);
	color: var(--text-muted);
	font-weight: var(--fw-regular);
}

/* ------------------------------------------------------------ product card ---- */

.fb-product-card {
	display: flex;
	flex-direction: column;
	background: var(--surface-card);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-lg);
	overflow: hidden;
	transition: var(--transition-surface);
	height: 100%;
}

.fb-product-card:hover { box-shadow: var(--shadow-md); }

.fb-product-card__media {
	position: relative;
	aspect-ratio: 4 / 3;
	background: var(--surface-subtle);
	display: flex;
	align-items: center;
	justify-content: center;
	border-bottom: var(--border-width) solid var(--border-subtle);
}

.fb-product-card__media img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	padding: var(--space-4);
}

.fb-product-card__flag {
	position: absolute;
	top: var(--space-3);
	left: var(--space-3);
}

.fb-product-card__body {
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	padding: var(--space-4);
	flex: 1;
}

.fb-product-card__brand {
	font-size: var(--text-micro);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
	color: var(--text-muted);
}

.fb-product-card__title {
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	line-height: var(--lh-snug);
	letter-spacing: 0;
	margin: var(--space-1) 0 0;
	text-wrap: pretty;
}

.fb-product-card__title a { color: inherit; text-decoration: none; }
.fb-product-card__title a:hover { text-decoration: underline; color: inherit; }

.fb-product-card__sku {
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	color: var(--text-muted);
	margin-top: var(--space-1);
}

.fb-product-card__certs {
	display: flex;
	gap: var(--space-1);
	flex-wrap: wrap;
}

.fb-product-card__foot {
	margin-top: auto;
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
}

/* Cart is the primary path; quote sits beside it, never above it. */
.fb-product-card__actions {
	display: grid;
	grid-template-columns: 1fr auto;
	gap: var(--space-2);
}

.fb-product-card__actions--quote-only { grid-template-columns: 1fr; }

/* ----------------------------------------------------------------- brand ---- */

.fb-brand { display: block; flex: 0 0 auto; }
.fb-brand__link { display: inline-flex; align-items: center; text-decoration: none; }
.fb-brand__link:hover { text-decoration: none; }
.fb-brand__img { display: block; }

/* Typographic stand-in until the client uploads the logo in Site Identity. */
.fb-brand__wordmark {
	font-family: var(--font-display);
	font-weight: var(--fw-black);
	letter-spacing: var(--ls-display);
	line-height: 1;
	color: var(--fb-ink);
	display: inline-flex;
	align-items: baseline;
	gap: 2px;
}

.fb-brand__dot {
	width: 0.32em;
	height: 0.32em;
	border-radius: var(--radius-mark);
	background: var(--fb-green);
	display: inline-block;
}

.fb-brand--knockout .fb-brand__wordmark { color: var(--steel-000); }

/* Knock a colour logo out to white so one uploaded asset serves both header and footer. */
.fb-brand--knockout .fb-brand__img { filter: brightness(0) invert(1); }

/* ---------------------------------------------------------------- header ---- */

.fb-header {
	position: sticky;
	top: 0;
	z-index: 40;
	background: var(--surface-card);
	box-shadow: var(--shadow-sticky);
}

.fb-topbar {
	background: var(--fb-ink);
	color: var(--steel-300);
	font-size: var(--text-caption);
}

.fb-topbar__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-4);
	min-height: 36px;
}

.fb-topbar a,
.fb-topbar button {
	color: inherit;
	background: transparent;
	border: 0;
	cursor: pointer;
	font-family: var(--font-body);
	font-size: var(--text-caption);
	text-decoration: none;
	display: inline-flex;
	align-items: center;
	gap: 6px;
}

.fb-topbar a:hover { color: var(--steel-000); text-decoration: none; }

.fb-masthead {
	display: flex;
	align-items: center;
	gap: var(--space-6);
	min-height: 76px;
}

.fb-masthead__logo img,
.fb-masthead__logo .custom-logo { height: 44px; width: auto; display: block; }

.fb-masthead__search { flex: 1; max-width: 520px; }

/*
 * Right-flushed against the shell edge, as the design kit has it.
 *
 * The `margin-left: auto` has to be scoped to `.fb-masthead` to land. Core's flex layout emits
 * `.is-layout-flex > :is(*, div) { margin: 0 }` — `:is()` takes the specificity of its heaviest
 * argument, so that rule scores (0,1,1) and beats a lone class no matter what order the
 * stylesheets load in. A descendant selector (0,2,0) outranks it. Without this the search box's
 * `flex: 1` stops growing at its 520px cap and the actions strand mid-header.
 */
.fb-masthead .fb-masthead__actions {
	margin-left: auto;
	display: flex;
	align-items: center;
	gap: var(--space-2);
}

/* Quote list and cart are visually distinct counters, matching the two CTA colours. */
.fb-header-action {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	height: var(--control-h-md);
	padding-inline: var(--space-3);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
	background: var(--surface-card);
	color: var(--text-primary);
	cursor: pointer;
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	text-decoration: none;
	white-space: nowrap;
	transition: var(--transition-control);
}

.fb-header-action:hover { background: var(--surface-subtle); color: var(--text-primary); text-decoration: none; }

.fb-header-action--cart {
	border: 0;
	background: var(--fb-ink);
	color: var(--text-inverse);
}

.fb-header-action--cart:hover { background: var(--steel-700); color: var(--text-inverse); }
.fb-header-action--cart .fb-count { font-family: var(--font-mono); color: var(--fb-green); }

.fb-primary-nav {
	border-top: var(--border-width) solid var(--border-subtle);
}

.fb-primary-nav__inner {
	display: flex;
	gap: var(--space-8);
	align-items: stretch;
}

.fb-primary-nav a {
	padding-block: var(--space-3);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-medium);
	color: var(--text-secondary);
	text-decoration: none;
	border-bottom: 3px solid transparent;
	margin-bottom: -1px;
	transition: var(--transition-control);
}

.fb-primary-nav a:hover { color: var(--text-primary); text-decoration: none; }

.fb-primary-nav .current-menu-item > a,
.fb-primary-nav a[aria-current="page"] {
	font-weight: var(--fw-semibold);
	color: var(--text-primary);
	border-bottom-color: var(--fb-green);
}

/*
 * Pushed to the far right of the nav, as the kit does with marginLeft:'auto'.
 *
 * Qualified by the parent on purpose. Core's flex layout emits
 * `.is-layout-flex > :is(*, div) { margin: 0 }`, and `:is(*, div)` resolves to specificity
 * (0,1,1) — deliberately higher than a bare class — so `.fb-primary-nav__recommender` alone
 * loses and the auto margin is silently dropped. Two classes take it to (0,2,0) and win
 * without reaching for !important.
 */
.fb-primary-nav__inner .fb-primary-nav__recommender {
	margin-left: auto;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-weight: var(--fw-semibold);
	color: var(--text-primary);
}

.fb-primary-nav__recommender .fb-icon { color: var(--fb-green-700); }

/* Mobile drawer */
.fb-mobile-nav {
	border-top: var(--border-width) solid var(--border-subtle);
	padding: var(--space-2) var(--gutter) var(--space-4);
}

.fb-mobile-nav a {
	display: flex;
	align-items: center;
	min-height: var(--tap-min);
	font-size: var(--text-body);
	color: var(--text-primary);
	text-decoration: none;
	border-bottom: var(--border-width) solid var(--border-subtle);
}

.fb-mobile-nav[hidden] { display: none; }

/*
 * Catalogue search inside the drawer. The masthead search is `fb-hide-sm`, so on a phone this is
 * the only way to search a 1,151-product catalogue (audit U-13).
 */
.fb-mobile-nav__search {
	padding-block: var(--space-3) var(--space-2);
	border-bottom: var(--border-width) solid var(--border-subtle);
	margin-bottom: var(--space-2);
}

/* ---------------------------------------------------------------- footer ---- */

.fb-footer {
	background: var(--fb-ink);
	color: var(--steel-300);
	margin-top: var(--space-24);
}

.fb-footer__cols {
	display: grid;
	gap: var(--space-10);
	grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
	padding-block: var(--space-16) var(--space-8);
}

 /*
 * Every column is a flex column with one shared gap, so the heading-to-body distance is identical
 * in all five and their first lines sit on one baseline.
 *
 * This replaces an accidental arrangement that did not survive contact with a second kind of
 * column. `.fb-footer p { margin: 0 }` (0,1,1) was quietly zeroing `.fb-footer__heading`'s
 * margin-bottom (0,1,0) — the heading is a <p> — so the gap under every heading was really core's
 * flow-layout `margin-block-start: 24px` on the following sibling. The contact block set its own
 * margin-top and therefore started 20px higher than the three link lists beside it.
 */
.fb-footer__brand,
.fb-footer__col {
	display: flex;
	flex-direction: column;
	gap: var(--space-5);
}

/* Cancel core's flow-layout margins; the gap above owns this spacing now. */
.fb-footer__brand > *,
.fb-footer__col > * {
	margin-block: 0;
}

/* The brand column has no heading, so its parts sit closer together than a heading-to-list gap. */
.fb-footer__brand { gap: var(--space-4); }

.fb-footer__heading {
	font-size: var(--text-micro);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
	color: var(--fb-green);
}

.fb-footer__links {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
}

.fb-footer a {
	font-size: var(--text-body-sm);
	color: var(--steel-300);
	text-decoration: none;
}

.fb-footer a:hover { color: var(--steel-000); text-decoration: underline; }

.fb-footer p { font-size: var(--text-body-sm); line-height: var(--lh-relaxed); margin: 0; }

.fb-footer__legal {
	border-top: 1px solid rgba(255, 255, 255, 0.1);
}

/*
 * Copyright on the left; the pricing note and the payment marks travel together on the right.
 * Grouping the two keeps `justify-content: space-between` a two-item problem — three loose items
 * would spread across the full width with the pricing note stranded in the middle.
 */
.fb-footer__legal-end {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--space-4);
}

.fb-footer__legal-inner {
	display: flex;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: var(--space-3);
	padding-block: var(--space-5);
	font-size: var(--text-caption);
}

/* --------------------------------------------------- contact + social ---- */

/*
 * Shared by the header top bar and the footer contact column. The values come from
 * Settings > Fischer Bell (see inc/contact.php), so a phone number is changed in one place and
 * updates the header, the footer and the Organization JSON-LD together.
 */
.fb-contact {
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
}

.fb-contact--inline {
	flex-direction: row;
	align-items: center;
	gap: 6px;
}

.fb-contact__item {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	margin: 0;
}

/*
 * The address runs to three lines, so its marker pins to the first line rather than centring on
 * the block. The 2px nudge sits the pin on the cap height instead of the line box.
 */
.fb-contact__item--address { align-items: flex-start; }
.fb-contact__item--address .fb-icon { margin-top: 2px; }

/* Brand green on the markers, as the kit tints the top bar's phone icon. */
.fb-contact .fb-icon { color: var(--fb-green-700); }
.fb-topbar .fb-contact .fb-icon,
.fb-footer .fb-contact .fb-icon { color: var(--fb-green); }

.fb-contact__address {
	/* <address> is italic by default in every browser; nothing else here is. */
	font-style: normal;
	font-size: var(--text-body-sm);
	line-height: var(--lh-relaxed);

	/*
	 * NOT `white-space: pre-line`. The renderer emits explicit <br> between lines precisely
	 * because pre-line also honoured the template's own indentation newlines, rendering the
	 * three-line address as six line boxes with a blank above and below it.
	 */

	/* Without this the address refuses to wrap inside the flex row on a narrow column. */
	min-width: 0;
}

.fb-footer .fb-contact__address { color: var(--steel-300); }
.fb-footer .fb-contact__fax { color: var(--steel-300); }

/*
 * Two classes so this outranks `.fb-footer a` (0,1,1), which would otherwise flatten the map link
 * back to plain body colour.
 */
.fb-contact .fb-contact__map {
	color: inherit;
	text-decoration: none;
}

.fb-contact .fb-contact__map:hover {
	color: var(--steel-000);
	text-decoration: underline;
}

.fb-contact .fb-contact__map:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
	border-radius: var(--radius-sm);
}

.fb-social {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	list-style: none;

	/* Spacing is the brand column's flex gap; a margin here would double it. */
	margin: 0;
	padding: 0;
}

.fb-social li { margin: 0; }

.fb-social__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	border: 1px solid rgba(255, 255, 255, 0.18);
	border-radius: var(--radius-md);
	color: var(--steel-300);
	transition: var(--transition-control);
}

/*
 * Two classes, because `.fb-footer a:hover` (0,2,1) would otherwise win and only recolour the
 * icon while leaving the plate untouched.
 */
.fb-social .fb-social__link:hover {
	background: var(--fb-green);
	border-color: var(--fb-green);
	color: var(--fb-ink);
	text-decoration: none;
}

.fb-social .fb-social__link:focus-visible { outline: none; box-shadow: var(--focus-ring); }


/* ------------------------------------------------------------- payment marks ---- */

/*
 * The accepted-payment row in the footer's legal bar.
 *
 * Until the official artwork is supplied each method renders as a text plate in the brand face —
 * the same stand-in the brand-partner strip uses. Nobody should be redrawing a trademarked
 * payment mark by hand, and a tidy plate reads better than a bad approximation. Dropping the real
 * files into assets/payment/ swaps them in with no code change.
 */
.fb-payments {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	flex-wrap: wrap;
}

/*
 * steel-300, not steel-400 (audit F-24).
 *
 * steel-400 (#8A8E99) against the footer's ink ground is 4.14:1 — under the 4.5:1 AA floor, and
 * this is micro-sized uppercase text, which is the hardest thing on the page to read already.
 * steel-300 reaches 6.69:1 and is the colour the footer body text already uses, so the heading
 * stays quieter than the green section headings above it without being the one label nobody can
 * read.
 */
.fb-payments__heading {
	font-size: var(--text-micro);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
	color: var(--steel-300);
}

.fb-payments__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-2);
	list-style: none;
	margin: 0;
	padding: 0;
}

.fb-payments__item {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 24px;
	min-width: 40px;
	padding-inline: var(--space-2);
	border: 1px solid rgba(255, 255, 255, 0.18);
	border-radius: var(--radius-sm);
	background: rgba(255, 255, 255, 0.06);
	font-family: var(--font-display);
	font-size: var(--text-micro);
	font-weight: var(--fw-bold);
	letter-spacing: 0.02em;
	line-height: 1;
	color: var(--steel-300);
	white-space: nowrap;
}

/*
 * Real marks sit on white. Every scheme's brand guidelines expect a light plate on a dark ground,
 * and it is what makes a row of six different logos read as one row.
 */
.fb-payments__item--artwork {
	background: var(--steel-000);
	border-color: transparent;
	padding-inline: 6px;
}

.fb-payments__art {
	display: block;
	height: 16px;
	width: auto;
	max-width: 46px;
	object-fit: contain;
}


/* ------------------------------------------------------------- editorial page ---- */

/*
 * Layout pieces for full-bleed editorial pages — About first, and Services detail next.
 * Everything here is composition only: colour, type and spacing all come from the tokens the
 * rest of the theme uses, so a Global Styles change still reaches this page.
 */

/* A page that opens on its own ink hero instead of the template's post title. */
.fb-page-hero {
	padding-block: var(--space-16);
}

.fb-page-hero__title {
	max-width: 820px;
	margin: var(--space-3) 0 0;
}

.fb-page-hero .fb-lede {
	max-width: 640px;
	margin: var(--space-5) 0 0;
}

/* Four capability cards. Sized to the kit's minmax(230px) track. */
.fb-grid--pillars {
	grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
	gap: var(--space-5);
}

/*
 * Two classes: `.fb-card-title { margin: 0 }` is declared further down the file, so a single
 * class ties on specificity and loses on source order.
 */
.fb-card .fb-pillar__title {
	margin-block: var(--space-4) var(--space-2);
}

/* The kit tints capability and statement icons brand green, as it does on the services cards. */
.fb-grid--pillars .fb-icon,
.fb-statement .fb-icon {
	color: var(--fb-green-700);
}

/*
 * Two columns of running prose. auto-fit rather than a media query, so it collapses on its own
 * measurement rather than on a breakpoint that has to be kept in sync.
 */
.fb-prose-cols {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
	gap: var(--space-12);
}

.fb-prose-cols__col {
	display: grid;
	gap: var(--space-5);
	align-content: start;
}

.fb-prose-cols p {
	font-size: var(--text-body);
	line-height: var(--lh-relaxed);
	color: var(--text-secondary);
	margin: 0;
	text-wrap: pretty;
}

/* Vision and mission: two statement cards, set in the display face rather than as body copy. */
.fb-grid--statement {
	grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
	gap: var(--space-6);
}

.fb-statement {
	padding: var(--space-8);
}

.fb-statement__label {
	margin-block: var(--space-4) var(--space-2);
}

.fb-statement__text {
	font-family: var(--font-display);
	font-size: var(--text-h4);

	/*
	 * No font-weight on purpose. The kit sets only family and size here, so the statement inherits
	 * the paragraph's regular weight — a large, quiet line rather than another bold heading, which
	 * is what distinguishes it from the card titles above it.
	 */
	letter-spacing: var(--ls-heading);
	line-height: var(--lh-snug);
	color: var(--text-primary);
	margin: 0;
	text-wrap: pretty;
}

/* Closing call to action: headline left, buttons right, stacking when there is no room. */
.fb-cta-band {
	/* The kit's closing band is shallower than a content section. */
	padding-block: var(--space-16);
}

.fb-cta-band__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-6);
}

.fb-cta-band__title {
	max-width: 520px;
	margin: 0;
}

.fb-cta-band__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
}

/* ------------------------------------------------------------------ hero ---- */

.fb-hero {
	background: var(--fb-ink);
	color: var(--text-inverse);
	position: relative;
	overflow: hidden;
}

.fb-hero__inner {
	display: grid;
	grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
	gap: var(--space-16);
	align-items: center;
	padding-block: var(--space-20);
}

.fb-hero__actions {
	display: flex;
	gap: var(--space-3);
	flex-wrap: wrap;
	margin-top: var(--space-8);
}

.fb-hero__stats {
	display: flex;
	gap: var(--space-8);
	margin-top: var(--space-10);
	flex-wrap: wrap;
}

.fb-hero__stat-n {
	font-family: var(--font-display);
	font-size: var(--text-h2);
	font-weight: var(--fw-black);
	color: var(--fb-green);
}

.fb-hero__stat-l { font-size: var(--text-caption); color: var(--steel-300); }

.fb-hero__media {
	aspect-ratio: 4 / 3;
	border-radius: var(--radius-lg);
	overflow: hidden;
}

.fb-hero__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Placeholder state while brand photography is outstanding. */
.fb-hero__media--empty {
	border: 1px dashed rgba(255, 255, 255, 0.24);
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	color: var(--steel-500);
	font-size: var(--text-caption);
}

/* -------------------------------------------------------------- trust bar ---- */

.fb-trustbar {
	border-bottom: var(--border-width) solid var(--border-subtle);
	background: var(--surface-card);
}

.fb-trustbar__inner { padding-block: var(--space-5); }

.fb-trustbar__item {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	font-size: var(--text-body-sm);
	font-weight: var(--fw-medium);
}

.fb-trustbar__item .fb-icon { color: var(--fb-green-700); }

/* ------------------------------------------------------------ step cards ---- */

.fb-step__n {
	width: 28px;
	height: 28px;
	border-radius: var(--radius-pill);
	background: var(--fb-green);
	color: var(--fb-ink);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	font-weight: var(--fw-bold);
}

/* --------------------------------------------------------- partner plates ---- */

.fb-partner {
	height: 72px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: var(--border-width) solid var(--border-subtle);
	border-radius: var(--radius-md);
	color: var(--text-muted);
	font-family: var(--font-display);
	font-weight: var(--fw-bold);
	font-size: var(--text-body-sm);
	letter-spacing: 0.02em;
	padding: var(--space-3);
	text-align: center;
}

.fb-partner img {
	max-width: 100%;
	max-height: 40px;
	object-fit: contain;
	filter: grayscale(1);
	opacity: 0.7;
	transition: var(--transition-control);
}

.fb-partner:hover img { filter: none; opacity: 1; }


/* --------------------------------------------------------------- carousel ---- */

/*
 * Looping horizontal carousel, used for the brand-partner strip.
 *
 * Every slide is server-rendered and stays in the DOM whether or not JavaScript runs, so crawlers
 * and answer engines see all twelve partner names. The AI-search requirement rules out anything
 * that only exists after hydration — which is also why the loop wraps the scroll position round
 * rather than cloning slides: cloned logos would duplicate every partner name in the markup.
 *
 * With JavaScript off the track is still a native swipe / scroll region. site.js adds the arrows
 * and the dot indicators on top, and only when the slides actually overflow.
 *
 * The track is an ordinary group block, so a maintainer adds, removes or replaces slides in the
 * editor exactly as they would in a grid.
 */
.fb-carousel {
	position: relative;
}

/*
 * Enhanced layout: arrows flank the track in their own grid columns and the dots sit in a second
 * row. Grid rather than absolute positioning so the arrows centre against the track's real height
 * instead of the whole component, which grows once the dots are added.
 *
 * Gated behind .is-enhanced so the no-JavaScript case stays a plain full-width track with no
 * empty columns reserved for arrows that were never added.
 */
.fb-carousel.is-enhanced {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr) auto;
	align-items: center;
	column-gap: var(--space-4);
	row-gap: var(--space-5);
}

/* Core's flow layout adds a top margin to every child but the first; row-gap owns that spacing. */
.fb-carousel.is-enhanced > * { margin-block: 0; }

.fb-carousel.is-enhanced .fb-carousel__track { grid-column: 2; grid-row: 1; }
.fb-carousel__nav--prev { grid-column: 1; grid-row: 1; }
.fb-carousel__nav--next { grid-column: 3; grid-row: 1; }
.fb-carousel__dots { grid-column: 1 / -1; grid-row: 2; }

.fb-carousel__track {
	display: flex;
	gap: var(--space-3);
	overflow-x: auto;
	overscroll-behavior-x: contain;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;

	/* The arrows and dots are the affordance; a native scrollbar under the logos is noise. */
	scrollbar-width: none;
	-ms-overflow-style: none;

	/* Room for a focus ring on a focusable slide, which would otherwise be clipped. */
	padding-block: 3px;
}

.fb-carousel__track::-webkit-scrollbar { display: none; }

/*
 * Slides are sized by count rather than a minmax() track, so one arrow press always advances a
 * whole number of slides and the snap points line up with it.
 *
 * `margin-block: 0` cancels core's flow-layout `* + *` top margin. Inside a flex row that margin
 * pushes every slide but the first downward — the same core rule documented under "grid gap
 * correction" below.
 */
.fb-carousel__track > * {
	flex: 0 0 calc((100% - (var(--fb-slides) - 1) * var(--space-3)) / var(--fb-slides));
	min-width: 0;
	margin-block: 0;
	scroll-snap-align: start;
}

.fb-carousel--partners { --fb-slides: 6; }

@media (max-width: 1100px) { .fb-carousel--partners { --fb-slides: 4; } }
@media (max-width: 720px) { .fb-carousel--partners { --fb-slides: 3; } }
@media (max-width: 520px) { .fb-carousel--partners { --fb-slides: 2; } }

@media (prefers-reduced-motion: reduce) {
	.fb-carousel__track { scroll-behavior: auto; }
}

/* ---- controls: added by site.js, and only when the track overflows ---- */

.fb-carousel__nav {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	padding: 0;
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-pill);
	background: var(--surface-card);
	color: var(--text-primary);
	cursor: pointer;
	transition: var(--transition-control);
}

.fb-carousel__nav:hover { background: var(--surface-subtle); border-color: var(--steel-400); }
.fb-carousel__nav:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* The carousel loops, so neither arrow is ever a dead end and neither is ever disabled. */

.fb-carousel__dots {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0;
}

/*
 * 8px dot inside a 20px button. The padding is the tap target and `background-clip: content-box`
 * keeps the paint on the dot itself, so the control stays comfortably clickable without drawing
 * a 20px blob.
 */
.fb-carousel__dot {
	box-sizing: border-box;
	width: 20px;
	height: 20px;
	padding: 6px;
	border: 0;
	border-radius: var(--radius-pill);
	background-color: var(--steel-200);
	background-clip: content-box;
	cursor: pointer;
	transition: var(--transition-control);
}

.fb-carousel__dot:hover { background-color: var(--steel-400); }
.fb-carousel__dot[aria-current="true"] { background-color: var(--fb-green); }
.fb-carousel__dot:focus-visible { outline: none; box-shadow: var(--focus-ring); }

@media (max-width: 720px) {
	/*
	 * Arrows cover too much of a two- or three-up track. Swipe and the dots carry it, and the
	 * track reclaims the columns they were occupying.
	 */
	.fb-carousel__nav { display: none; }

	.fb-carousel.is-enhanced { grid-template-columns: minmax(0, 1fr); }
	.fb-carousel.is-enhanced .fb-carousel__track { grid-column: 1 / -1; }
}

/* ----------------------------------------------------------------- forms ---- */

.fb-input,
.fb-select,
.fb-textarea {
	width: 100%;
	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);
	padding-inline: var(--space-3);
	transition: var(--transition-control);
}

.fb-input,
.fb-select { height: var(--control-h-md); }
.fb-textarea { padding-block: var(--space-3); min-height: 120px; line-height: var(--lh-normal); }

.fb-input::placeholder,
.fb-textarea::placeholder { color: var(--text-muted); }

.fb-input:hover,
.fb-select:hover,
.fb-textarea:hover { border-color: var(--border-strong); }

.fb-field { display: flex; flex-direction: column; gap: var(--space-2); }

.fb-field__label {
	font-size: var(--text-body-sm);
	font-weight: var(--fw-semibold);
	color: var(--text-primary);
}

.fb-field__hint { font-size: var(--text-caption); color: var(--text-muted); }
.fb-field__error { font-size: var(--text-caption); color: var(--status-danger); font-weight: var(--fw-medium); }
.fb-field--invalid .fb-input,
.fb-field--invalid .fb-select,
.fb-field--invalid .fb-textarea { border-color: var(--status-danger); }

.fb-required { color: var(--status-danger); }

/* Search combines an inset icon with the standard input shell. */
.fb-search { position: relative; display: block; }

.fb-search__icon {
	position: absolute;
	left: var(--space-3);
	top: 50%;
	transform: translateY(-50%);
	display: inline-flex;
	color: var(--text-muted);
	pointer-events: none;
}

.fb-search__input {
	width: 100%;
	height: var(--control-h-md);
	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);
	padding-inline: calc(var(--space-4) + 18px) var(--space-3);
	transition: var(--transition-control);
}

.fb-search__input::placeholder { color: var(--text-muted); }
.fb-search__input:hover { border-color: var(--border-strong); }

/* ------------------------------------------------------------------ icon ---- */

.fb-icon {
	display: inline-block;
	flex: 0 0 auto;
	/*
	 * No width/height here on purpose. fischer_bell_get_icon() writes the requested size as
	 * width/height attributes; a CSS width of 1em silently overrode every one of them, so every
	 * icon rendered at the inherited font size instead of the size the design asked for.
	 */
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
	fill: none;
	vertical-align: middle;
}

/* --------------------------------------------------------------- a11y/util ---- */

.fb-visually-hidden {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

.skip-link:focus {
	position: fixed;
	top: var(--space-2);
	left: var(--space-2);
	z-index: 100;
	padding: var(--space-3) var(--space-4);
	background: var(--fb-ink);
	color: var(--text-inverse);
	border-radius: var(--radius-md);
}

:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}

.fb-only-sm { display: none; }

/* ------------------------------------------------------------- responsive ---- */

@media (max-width: 860px) {
	.fb-hide-sm { display: none !important; }
	.fb-only-sm { display: inline-flex; }

	.fb-hero__inner {
		grid-template-columns: 1fr;
		gap: var(--space-8);
	}

	.fb-section { padding-block: var(--space-12); }
	.fb-masthead { min-height: 64px; gap: var(--space-3); }
	.fb-section-header { margin-bottom: var(--space-6); }
	.fb-hero__stats { gap: var(--space-6); }

	/* Two-up product grid holds up better than one-up on a phone. */
	.fb-grid--products { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--space-3); }
	.fb-grid--cats { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: var(--space-3); }
}

@media (max-width: 480px) {
	.fb-product-card__actions { grid-template-columns: 1fr; }

	.fb-footer__legal-inner { flex-direction: column; gap: var(--space-2); }

	/* Stack the pricing note above the marks rather than letting them wrap unevenly. */
	.fb-footer__legal-end {
		flex-direction: column;
		align-items: flex-start;
		gap: var(--space-3);
	}
}

/* ------------------------------------------------------- language switcher ---- */

/*
 * The design kit's LanguageSwitcher (components/navigation/LanguageSwitcher.jsx): a bordered
 * globe + code + chevron control that opens a right-aligned panel listing every language by its
 * native name with the code set in mono. It replaces TranslatePress's floating corner widget,
 * which the design does not use and which overlapped page content.
 *
 * Built on <details>/<summary> rather than button + JS so switching language still works with
 * JavaScript off, and so every option stays a real crawlable <a href>. site.js only adds the
 * niceties: close on outside click, close on Escape.
 *
 * Several rules below are deliberately written as two classes. `.fb-topbar a` (0,1,1) and
 * `.fb-topbar a:hover` (0,2,1) would otherwise capture the menu options and force them back to
 * inline-flex / inherited colour.
 */
.fb-langswitch {
	position: relative;
	display: inline-block;
}

.fb-langswitch__toggle {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	height: var(--control-h-sm);
	padding-inline: var(--space-2);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
	background: transparent;
	color: inherit;
	cursor: pointer;
	font-family: var(--font-body);
	font-size: var(--text-caption);
	font-weight: var(--fw-medium);
	line-height: 1;
	white-space: nowrap;
	transition: var(--transition-control);

	/* Suppress the native disclosure triangle in every engine. */
	list-style: none;
}

.fb-langswitch__toggle::-webkit-details-marker { display: none; }
.fb-langswitch__toggle::marker { content: ""; }

.fb-langswitch__toggle:hover { background: var(--surface-subtle); }
.fb-langswitch__toggle:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* On the ink top bar a light wash reads better than the light-surface hover. */
.fb-topbar .fb-langswitch__toggle:hover {
	background: rgba(255, 255, 255, 0.08);
	color: var(--steel-000);
}

.fb-langswitch__chevron { transition: transform var(--dur-fast) var(--ease-out); }
.fb-langswitch[open] .fb-langswitch__chevron { transform: rotate(180deg); }

.fb-langswitch__menu {
	position: absolute;
	top: calc(100% + 4px);
	right: 0;
	z-index: 20;
	min-width: 160px;
	margin: 0;
	padding: var(--space-1);
	list-style: none;
	background: var(--surface-card);
	color: var(--text-primary);
	border: var(--border-width) solid var(--border-default);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-lg);
}

.fb-langswitch__menu li { margin: 0; list-style: none; }

.fb-langswitch .fb-langswitch__opt {
	display: flex;
	width: 100%;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	min-height: var(--tap-min);
	padding-inline: var(--space-3);
	border-radius: var(--radius-sm);
	background: transparent;
	color: var(--text-primary);
	font-family: var(--font-body);
	font-size: var(--text-body-sm);
	text-align: left;
	text-decoration: none;
	transition: var(--transition-control);
}

.fb-langswitch .fb-langswitch__opt:hover {
	background: var(--surface-subtle);
	color: var(--text-primary);
	text-decoration: none;
}

.fb-langswitch .fb-langswitch__opt:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* The kit's listbox marks the current value by selection state; a link list has to say so. */
.fb-langswitch .fb-langswitch__opt[aria-current] { font-weight: var(--fw-semibold); }

.fb-langswitch__opt-short {
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	color: var(--text-muted);
}

/* ------------------------------------------------------- grid gap correction ---- */

/*
 * WordPress's flow layout adds `margin-block-start` to every child EXCEPT the first
 * (`:where(.is-layout-flow) > :where(* + *)`). Inside a CSS grid that is actively wrong: it shifts
 * every item down inside its own cell while the first keeps a zero margin, so the first card sits
 * a full block-gap higher AND stretches a block-gap taller than its siblings. Visually the first
 * item of every grid juts out.
 *
 * The grid's own `gap` already handles spacing, so the flow margins are cancelled here. Core's rule
 * is wrapped in :where() and therefore has zero specificity, so a single class selector wins.
 *
 * THIS LIST IS THE FIX. Every container the theme turns into a CSS grid while its children are
 * blocks has to appear here — the rule is not inherited and there is no marker class to key off.
 * It has already been missed twice: once for the footer columns, whose brand column sat a
 * block-gap above the other four, and once for the hero, whose media panel was pushed below
 * centre in an `align-items: center` grid. Adding a new grid class? Add it here as well.
 */
.fb-grid > *,
.fb-grid > * + *,
.fb-footer__cols > *,
.fb-footer__cols > * + *,
.fb-hero__inner > *,
.fb-hero__inner > * + *,
.fb-account-stats > *,
.fb-account-stats > * + *,
.fb-prose-cols > *,
.fb-prose-cols > * + *,
.fb-prose-cols__col > *,
.fb-prose-cols__col > * + * {
	margin-block-start: 0;
	margin-block-end: 0;
}

/* --------------------------------------------------------------- card type ---- */

/*
 * One card-title treatment shared by every card grid.
 *
 * The design kit expressed these as per-section inline styles and drifted: category cards used
 * body 14/600, step cards body 16/600, service cards display 18/700. Four grids stacked down one
 * page read as four different type systems. They are unified on the display face here, with size
 * carrying the hierarchy instead of the typeface.
 */
.fb-card-title {
	font-family: var(--font-display);
	font-weight: var(--fw-bold);
	font-size: var(--text-h4);
	letter-spacing: var(--ls-heading);
	line-height: var(--lh-snug);
	color: var(--text-primary);
	margin: 0;
	text-wrap: pretty;
}

/* Dense grids (8-up categories, 4-up steps) step down a size; the family stays constant. */
.fb-card-title--sm { font-size: var(--text-body); }

.fb-card-desc {
	font-size: var(--text-body-sm);
	color: var(--text-secondary);
	line-height: var(--lh-normal);
	margin: var(--space-1) 0 0;
	text-wrap: pretty;
}

/* Numeric/spec metadata stays in the mono face — it is data, not prose. */
.fb-card-meta {
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	color: var(--text-muted);
	margin-top: 2px;
}

/* --------------------------------------------------------------- measure ----
   The shell is the single alignment authority: every page's content begins at
   the same edge as the menu bar, exactly as the design kit's shellWrap does.
   theme.json's contentSize now matches the container width, so WordPress's
   constrained layout no longer narrows anything.

   Long-form prose still needs a readable line length, so it is capped here —
   on the text itself, flush left, never as a centred column. Structural blocks
   (groups, grids, patterns, the WooCommerce wrapper) are deliberately excluded
   and keep the full width.

   The !important on the margin matches core's own: the constrained-layout rule
   sets `margin-left/right: auto !important`, which would otherwise re-centre a
   capped paragraph and undo the alignment this whole block exists to fix. */
.entry-content > p,
.entry-content > h2,
.entry-content > h3,
.entry-content > h4,
.entry-content > h5,
.entry-content > h6,
.entry-content > ul,
.entry-content > ol,
.entry-content > blockquote,
.entry-content > .wp-block-list,
.entry-content > .wp-block-quote {
	max-width: var(--measure);
	margin-inline: 0 !important;
}

/* Headings that introduce a full-width section should not be pulled to prose width. */
.entry-content > .alignwide,
.entry-content > .alignfull {
	max-width: none;
}

/* First-run welcome on an account with no history yet (audit U-7). */
.fb-account-firstrun { margin-bottom: var(--space-5); }
