/*
Theme Name:   AltBev Bricks Child
Theme URI:    https://altbev.example/
Description:  Child theme of Bricks for the AltBev wholesale portal. Holds site-specific styling; all wholesale logic lives in the altbev-core plugin.
Author:       AltBev
Template:     bricks
Version:      1.0.0
Text Domain:  altbev-bricks-child
*/

/* =========================================================================
   DIRECTION CONTRACT — "Open Case"  (see DESIGN.md)

   THESIS: The case is open and the room is bright. Still a real beverage
   brand with published lab data, but read by a buyer scanning rather than
   studying: one thing louder than the next, air between the parts, and
   nothing set so small or so tight that it has to be decoded. It refuses
   the arrangement it replaced - 2px ink rules on everything, radius 0,
   hard die-cut offset shadows, condensed caps at line-height 0.86, and
   four saturated bands alternating with four dark compliance bars down a
   single page, which made every region shout at the same volume.

   OWN-WORLD: A bright stock #F6F7F2 with white panels floating on it,
   petrol ink #0C2C39 for words and one hairline rule, 20px surface radius,
   pill controls, and soft ink-tinted elevation with real blur. Exactly one
   full-strength SATURATED field per page - the hero - with mid-page
   sections carrying tints instead; the flavor fields survive only where
   they name a product. Ink is not a saturated field: it stays available as
   a structural ground for the story band and the footer, which are the
   page's two dark anchors and are deliberate. One voltage, acid #D8F340,
   only ever on an action. Gabarito set wide and in sentence case for
   lettering, Hanken Grotesk for prose, DM Mono for measured values.

   STORY: A trade buyer sees a real beverage brand with published
   lab data, understands it ships by the case at their negotiated price,
   and applies for an account.

   FIRST VIEWPORT: The site's only full-strength saturated field.
   Lettering fills the left seven columns with room to breathe, the real
   four-pack photograph is plated into the right five, and the volt
   application block sits under the lettering. No eyebrow above it.

   FORM: Brief-pinned by the client (modern, upbeat, airy, Paleovalley as
   reference) and confirmed on two decisions: replace the display face, and
   calm the mid-page bands. A pinned direction beats the roll.

   FINISH: unreviewed and undocumented is unfinished; this build ends with
   the finish review, the verdict, and DESIGN.md.
   ========================================================================= */

/* ----- Design tokens ---------------------------------------------------- */

:root {
	/* Structure */
	--ab-ink: #0c2c39;
	--ab-ink-2: #2a5464;
	--ab-paper: #f6f7f2; /* the bright stock; was #eceee7, which read gray */
	--ab-paper-2: #edf0e6; /* a banded zone, still light enough to be air */
	--ab-label: #ffffff;
	--ab-rule-soft: #dfe4d6;

	/*
	 * The hairline. Structure used to be carried by a 2px ink border on every
	 * surface, which is what welded the page into a grid of boxes. Weight now
	 * comes from elevation and space; the line only has to say "edge".
	 */
	--ab-line: #e0e5d7;
	--ab-line-strong: #c6cdba; /* interior table rules, input edges */

	/* Text */
	--ab-text: #0c2c39;
	--ab-text-dim: #46626d; /* 5.6:1 on paper, 6.1:1 on label */

	/* Voltage — actions only, never text on paper */
	--ab-volt: #d8f340;
	--ab-volt-deep: #bcd621;

	/* Flavor and category fields — flat, saturated, white text */
	--ab-field-raspberry: #d8003f;
	--ab-field-grape: #5b2b8a;
	--ab-field-orange: #c24a05;
	--ab-field-hop: #1e7a34;
	--ab-field-cbd: #1e7a34;
	--ab-field-delta9: #d8003f;
	--ab-field-mushroom: #9a4a12;
	--ab-field-roots: #8a6a00;
	--ab-field-peach: #b83a4a;
	--ab-field-lime: #2e7d32;
	--ab-field-citrus: #a85d00;
	--ab-field-lavender: #4a3e9e;

	/*
	 * Tints. A field still owns a whole region mid-page, but at a weight the
	 * eye can pass over: the ground carries the category, the field color
	 * carries the heading on top of it. Four full-strength bands in one scroll
	 * gave every section the same shout and left the page unscannable, so the
	 * hero keeps the only saturated field and these carry the rest.
	 */
	--ab-tint-hop: #e7f1e4;
	--ab-tint-mushroom: #f8ece1;
	--ab-tint-raspberry: #fdeaef;


	/* Status */
	--ab-success: #0a6e4e;
	--ab-error: #b3121f;
	--ab-warning: #8a5a00;

	/* Type */
	--ab-font: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	--ab-font-display: "Gabarito", "Hanken Grotesk", system-ui, sans-serif;
	--ab-font-spec: "DM Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

	/*
	 * Type ramp - every literal size in this system resolves to one of these.
	 * Adding a step means adding it to DESIGN.md too.
	 *
	 * The fixed steps were raised across the board. The old ramp bottomed out
	 * at 0.58rem, which put the regulated statements, every table header and
	 * every spec label at 9px: the two things a buyer most needs to read were
	 * the two smallest things on the page. Nothing here now sets below 11px.
	 */
	--ab-t-display: clamp(3.25rem, 8vw, 6.5rem);
	--ab-t-headline: clamp(1.9rem, 4vw, 3rem);
	--ab-t-title: clamp(1.6rem, 3.2vw, 2.4rem);
	--ab-t-subhead: clamp(1.3rem, 2.4vw, 1.8rem);
	--ab-t-2xs: 0.72rem;
	--ab-t-xs: 0.79rem;
	--ab-t-sm: 0.88rem;
	--ab-t-md: 0.97rem;
	--ab-t-lg: 1.06rem;
	--ab-t-xl: 1.2rem;
	--ab-t-2xl: 1.38rem;
	--ab-t-3xl: 1.55rem;
	--ab-t-4xl: 1.75rem;
	--ab-t-5xl: 2.1rem;

	/* Text and surfaces on a dark or saturated ground. */
	--ab-on-ink: #c3d2d7; /* 9.45:1 on ink */
	--ab-on-field: #fff0f3; /* 4.73:1 on the raspberry field */
	--ab-added: #f2fbe0; /* the just-added order row */

	/*
	 * Structure metrics.
	 *
	 * SHAPE: one scale, three roles, and no fourth. Surfaces that hold content
	 * take `--ab-radius`; anything a buyer types into takes
	 * `--ab-radius-control`; anything they press or that reads as a token takes
	 * `--ab-radius-pill`. A square corner is now the exception that has to
	 * argue for itself, which is the inverse of the system this replaced.
	 */
	--ab-radius: 20px;
	--ab-radius-sm: 14px; /* compact panels nested in a padded surface */
	--ab-radius-control: 12px;
	--ab-radius-pill: 999px;

	--ab-rule: 1px solid var(--ab-line);
	--ab-rule-heavy: 1px solid var(--ab-line-strong);

	/*
	 * Depth is lit, not printed. The names are inherited from the die-cut
	 * system so the 20-odd call sites did not all have to move, but the values
	 * are ordinary elevation: an offset, a real blur, and a tint pulled from
	 * the ink so nothing casts a neutral gray shadow on a warm ground.
	 */
	--ab-diecut: 0 2px 4px rgba(12, 44, 57, 0.04), 0 18px 40px -18px rgba(12, 44, 57, 0.2);
	--ab-diecut-sm: 0 1px 2px rgba(12, 44, 57, 0.05), 0 8px 20px -10px rgba(12, 44, 57, 0.18);
	--ab-diecut-lift: 0 4px 8px rgba(12, 44, 57, 0.05), 0 28px 56px -20px rgba(12, 44, 57, 0.26);

	--ab-maxw: 1240px;
	--ab-pad: clamp(1.25rem, 4vw, 2.75rem);
	--ab-section-y: clamp(4.5rem, 8vw, 7.5rem);

	/*
	 * Motion. The press that moved a surface into its own hard shadow went with
	 * the shadow; a lit surface lifts instead. Exponential ease-out from an
	 * already-visible default - nothing on this page depends on JS or scroll
	 * position to become visible.
	 */
	--ab-press: 220ms cubic-bezier(0.16, 1, 0.3, 1);

	/* The sticky header's own height. Anything the browser scrolls to owes it
	   this much clearance, or it lands underneath the header. */
	--ab-header-h: 68px;

	/*
	 * Control metrics. Every field a buyer types into resolves to one of two
	 * sizes and no others: the standard control, and the compact one used in
	 * dense rows (the order sheet's quantity, the docket's B2B fields). See
	 * "Control metrics" at the foot of this file for why they are enforced
	 * there rather than at each call site.
	 */
	--ab-control-py: 0.7rem;
	--ab-control-px: 0.85rem;
	--ab-control-lh: 1.4;
	--ab-control-h: 3rem;

	--ab-control-py-sm: 0.45rem;
	--ab-control-px-sm: 0.6rem;
	--ab-control-h-sm: 2.5rem;
}

/* ----- Base ------------------------------------------------------------- */

html {
	-webkit-text-size-adjust: 100%;
}

/*
 * Bricks ships the 62.5% convention (`html { font-size: 10px }`), which
 * silently shrinks every rem in this stylesheet to 62.5% of its intended
 * size. Restore a 16px root, but only on our own front-end pages - the
 * `:has()` scope keeps the builder and any non-AltBev screen untouched.
 */
html:has(body.altbev) {
	font-size: 100%;
}

body.altbev {
	background: var(--ab-paper);
	color: var(--ab-text);
	font-family: var(--ab-font);
	font-size: 17px;
	line-height: 1.65;
	margin: 0;
	overflow-x: clip; /* lets full-bleed fields exist without a scrollbar */
	-webkit-font-smoothing: antialiased;
}

.altbev * {
	box-sizing: border-box;
}

/*
 * Headings are sentence case. The uppercase transform used to be global, which
 * meant every heading, every table header and every nav link arrived as a run
 * of capitals with no word shapes to recognize - the single biggest reason the
 * page could not be skimmed. Capitals survive in exactly one place now, the
 * tracked `.ab-spec` label, where the string is two or three words long.
 */
.altbev h1,
.altbev h2,
.altbev h3,
.altbev h4 {
	font-family: var(--ab-font-display);
	font-weight: 700;
	line-height: 1.08;
	letter-spacing: -0.02em;
	text-wrap: balance;
	color: var(--ab-ink);
	margin: 0 0 0.5em;
}

.altbev h1 {
	letter-spacing: -0.03em;
}

.altbev p {
	max-width: 68ch;
}

.altbev a {
	color: var(--ab-ink);
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
}

.altbev a:hover {
	color: var(--ab-ink);
	text-decoration-color: var(--ab-field-raspberry);
}

.altbev ::selection {
	background: var(--ab-volt);
	color: var(--ab-ink);
}

.altbev :focus-visible {
	outline: 3px solid var(--ab-ink);
	outline-offset: 2px;
	border-radius: var(--ab-radius-control);
}

.altbev img,
.altbev video {
	max-width: 100%;
}

/* Bricks section/container wrappers are shrink-to-fit; neutralise so our
   own components can own their width and self-center. */
.altbev .brxe-section,
.altbev .brxe-container {
	display: block;
	width: 100%;
	max-width: 100%;
	padding-inline: 0;
}

.altbev .brxe-container > * {
	width: 100%;
}

/* WooCommerce ships the empty cart as a cartoon face above a heading set
   smaller than the cross-sell heading below it, which ranks "new in store"
   above the answer to the question the buyer actually arrived with. */
.altbev .wp-block-woocommerce-empty-cart-block > .wp-block-image:first-child {
	display: none;
}

.altbev .wc-block-cart__empty-cart__title {
	font-size: var(--ab-t-headline);
	margin-bottom: 0.6rem;
}

/* WooCommerce's empty-cart block ships a dotted `<hr>` between its heading and
   the product grid below. It is stock block-library decoration that reads as a
   row of stray marks, and the change of content is its own separator - so the
   rule goes and the interval it was holding open is restated as space. */
.altbev .wp-block-woocommerce-empty-cart-block .wp-block-separator {
	display: none;
}

.altbev .wp-block-woocommerce-empty-cart-block .wp-block-separator + h2 {
	margin-top: 2.5rem;
}

/* ----- The price gate --------------------------------------------------- */

/*
 * What stands where a price would be for a viewer with no approved account.
 * It is deliberately not styled as a price: no mono, no tabular figures, no
 * measured-value voice - it is a sentence explaining an absence, and dressing
 * it up as a figure is how a gate starts reading like a number.
 */
/*
 * The gate lands inside whatever element WooCommerce reserved for the price, and
 * every one of those is styled as a measured value: mono, tabular figures, often
 * bold. So each price container is named here and the mono explicitly unset -
 * without it the sentence renders in DM Mono and reads as a figure that failed
 * to load rather than as an explanation.
 */
.altbev .ab-price-gate,
.altbev .wc-block-grid__product-price .ab-price-gate,
.altbev ul.products li.product .price .ab-price-gate,
.altbev.single-product div.product p.price .ab-price-gate {
	display: inline-block;
	font-family: var(--ab-font);
	font-size: var(--ab-t-sm);
	font-weight: 500;
	letter-spacing: 0;
	text-transform: none;
	font-variant-numeric: normal;
	line-height: 1.4;
	color: var(--ab-text-dim);
}

/* ----- Surfaces --------------------------------------------------------- */

/*
 * The shape system lives here rather than on twenty separate selectors, because
 * one radius applied inconsistently is worse than no radius at all: a rounded
 * card next to a square one reads as a bug, not as a variation. Everything that
 * carries elevation is a surface and takes the same corner.
 *
 * `overflow: hidden` goes on the ones that hold an image or a full-bleed color
 * panel, so the child squares off inside the rounded parent instead of poking
 * through its corners.
 */
.ab-hero__plate,
.altbev .woocommerce-MyAccount-navigation,
.altbev .woocommerce-MyAccount-content,
.altbev .wc-block-cart__sidebar,
.altbev .wp-block-woocommerce-checkout-order-summary-block,
.altbev .wp-block-woocommerce-empty-cart-block,
.altbev.single-product div.product .woocommerce-product-gallery,
.altbev .woocommerce-order > p:first-of-type,
.altbev .woocommerce-thankyou-order-received,
.altbev-product,
.ab-facts__infographic,
.ab-bs,
.ab-tearoff__card {
	border-radius: var(--ab-radius);
}

.ab-hero__plate,
.altbev.single-product div.product .woocommerce-product-gallery,
.altbev-product,
.ab-facts__infographic,
.ab-bs {
	overflow: hidden;
}

/* ----- Shared primitives ------------------------------------------------ */

/*
 * The tracked label: the one place capitals survive. It stays mono because the
 * strings it carries are codes and category names sitting next to figures, but
 * it is no longer the voice of every small thing on the page - table headers,
 * card blurbs and captions were all wearing it, which is monospace as a costume
 * rather than as measurement.
 */
.ab-spec {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-xs);
	font-weight: 500;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	line-height: 1.4;
}

/*
 * The FDA line is regulated copy, so it is ruled off and given the width of the
 * sheet it belongs to rather than left floating. It is set in the body face now:
 * a four-line legal paragraph in tracked uppercase mono was the single least
 * readable block on the site, and legibility is what a compliance statement is
 * for. `rem` rather than `ch` because the measure has to stay predictable across
 * a face change, and the class needs the `.altbev` prefix to outrank the
 * `.altbev p` measure cap.
 */
.altbev .ab-disclaimer {
	font-size: var(--ab-t-sm);
	line-height: 1.65;
	color: var(--ab-text-dim);
	max-width: 62rem;
	border-top: var(--ab-rule);
	padding-top: 1.25rem;
	margin: 2rem 0 0;
}

/* ----- The mandatory panel (signature) ---------------------------------- */

/*
 * The regulated statements still appear wherever product is shown - that
 * requirement has not moved - but they are no longer four full-bleed ink bars
 * stacked down one scroll. At that weight the panel competed with the sections
 * it was annotating, and a reader scanning for "what do you sell" hit a dark
 * band every 900px. It is now a hairline strip on the page's own ground: quiet
 * enough to pass over, legible enough to read, and set two steps larger than it
 * used to be.
 *
 * The one exception is `--onfield`, welded to the bottom of the hero, where the
 * ground beneath it is saturated and only an ink bar will hold contrast.
 */
.ab-mandatory {
	background: var(--ab-paper-2);
	color: var(--ab-text-dim);
	border-top: var(--ab-rule);
	border-bottom: var(--ab-rule);
	margin: 0;
	padding: 0;
}

.ab-mandatory__list {
	list-style: none;
	margin: 0;
	padding: 0.85rem var(--ab-pad);
	max-width: var(--ab-maxw);
	margin-inline: auto;
	font-size: var(--ab-t-2xs);
	font-weight: 500;
	letter-spacing: 0.03em;
	text-transform: uppercase;
	line-height: 1.9;
}

/*
 * Each statement is an inline run, not a flex item: a flex row forces its
 * text and trailing dot onto one nowrap line, so once a statement is too long
 * for the viewport (any width under ~700px) the text wraps internally while
 * the dot — centered on the now two-line-tall flex item — floats detached to
 * the right of both lines. Inline layout lets the dot sit as part of the same
 * text run, so it wraps to exactly where the statement's last word ends.
 */
.ab-mandatory__list li {
	display: inline;
}

.ab-mandatory__list li:not(:first-child) {
	margin-inline-start: 1.6rem;
}

/*
 * The separator trails its own statement rather than leading the next one. As
 * a leading mark it wrapped with the item it belonged to, so at 1440px the
 * fourth statement started line two with an orphaned dot sitting in the left
 * margin. Trailing, a wrap simply ends the line after a mark, the way a run-in
 * list is set in print.
 */
.ab-mandatory__list li:not(:last-child)::after {
	content: "";
	display: inline-block;
	width: 4px;
	height: 4px;
	border-radius: var(--ab-radius-pill);
	background: currentcolor;
	opacity: 0.45;
	margin-inline-start: 0.55rem;
	vertical-align: middle;
}

/*
 * On the hero the panel is drawn from the field itself rather than dropped on
 * top of it. An ink bar welded under the raspberry put a second heavy band in
 * the first viewport and split the one saturated moment the page is allowed
 * into two. A hairline and a faint wash keep the hero reading as a single
 * field.
 *
 * The wash and the text opacity are both load-bearing. At `rgba(255,255,255,
 * 0.1)` over the raspberry the ground lightens to #dc1a52, and 95% white on
 * that measures 4.51:1 - passing AA by a hundredth, on letter-spaced 11.5px
 * uppercase carrying the two most legally load-bearing statements on the site.
 * A 0.06 wash and solid white restore it to 5.05:1. Neither value is cosmetic;
 * raising the wash means lowering the type's claim on this strip, and the
 * statements do not have that to give.
 */
.ab-mandatory--onfield {
	background: rgba(255, 255, 255, 0.06);
	color: #fff;
	border-top: 1px solid rgba(255, 255, 255, 0.3);
	border-bottom: 0;
}

/* ----- Buttons ---------------------------------------------------------- */

/*
 * A button is a pill with a lit edge. The volt fill and the ink text are
 * unchanged - that pairing is the brand's action color at 11.6:1 - but the
 * 2px ink outline and the hard offset that used to fence it are gone, and the
 * label is set in sentence case at the display face's own width rather than
 * tracked capitals.
 */
.altbev .ab-btn,
.altbev button.altbev-button,
.altbev .altbev-qo-checkout {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 600;
	letter-spacing: -0.005em;
	line-height: 1;
	padding: 0.95rem 1.75rem;
	border: 1px solid transparent;
	border-radius: var(--ab-radius-pill);
	background: var(--ab-volt);
	color: var(--ab-ink) !important;
	box-shadow: var(--ab-diecut-sm);
	text-decoration: none;
	cursor: pointer;
	transition: transform var(--ab-press), box-shadow var(--ab-press), background var(--ab-press);
}

/*
 * Nothing presses into its own shadow any more; surfaces lift. Bounded to 2px
 * so a grid of catalog rows does not jitter as the pointer crosses it.
 */
.altbev .ab-btn:hover,
.altbev button.altbev-button:hover,
.altbev .altbev-qo-checkout:hover,
.altbev .ab-btn:focus-visible,
.altbev button.altbev-button:focus-visible {
	background: var(--ab-volt-deep);
	transform: translateY(-2px);
	box-shadow: var(--ab-diecut);
}

.altbev .ab-btn:active,
.altbev button.altbev-button:active {
	transform: translateY(0);
	box-shadow: var(--ab-diecut-sm);
}

.altbev .ab-btn--ghost {
	background: transparent;
	color: var(--ab-ink) !important;
	border-color: var(--ab-line-strong);
	box-shadow: none;
}

/*
 * Inverts to an ink fill, which is what the system has always said a secondary
 * button does on hover. The ground here was `--ab-paper-2` against the paper
 * text it already set, which is 1.05:1 - the label vanished the moment a
 * pointer touched it, on every secondary button on the site.
 */
.altbev .ab-btn--ghost:hover,
.altbev .ab-btn--ghost:focus-visible {
	background: var(--ab-ink);
	border-color: var(--ab-ink);
	color: var(--ab-paper) !important;
	transform: translateY(-2px);
	box-shadow: var(--ab-diecut-sm);
}

/* Secondary action sitting on a saturated field. */
.altbev .ab-btn--onfield {
	background: transparent;
	color: #fff !important;
	border-color: rgba(255, 255, 255, 0.65);
	box-shadow: none;
}

.altbev .ab-btn--onfield:hover,
.altbev .ab-btn--onfield:focus-visible {
	background: #fff;
	border-color: #fff;
	color: var(--ab-ink) !important;
	transform: translateY(-2px);
	box-shadow: none;
}

.altbev .ab-btn--compact {
	font-size: var(--ab-t-sm);
	padding: 0.55rem 1.1rem;
	box-shadow: none;
}

.altbev .ab-btn--compact:hover {
	transform: translateY(-1px);
	box-shadow: var(--ab-diecut-sm);
}

/* ----- Skip link -------------------------------------------------------- */

.ab-skip {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 100;
	background: var(--ab-volt);
	color: var(--ab-ink) !important;
	border-radius: var(--ab-radius-pill);
	box-shadow: var(--ab-diecut);
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 600;
	padding: 0.8rem 1.5rem;
	text-decoration: none;
}

.ab-skip:focus {
	left: 0.75rem;
	top: 0.75rem;
}

#ab-main:focus {
	outline: none;
}

/* ----- Header ----------------------------------------------------------- */

/*
 * Everything the browser scrolls to has to clear the sticky header. The
 * category bars anchor to `#botanicals` and `#adaptogenics`, and both landed
 * with the field band's heading buried under the header. Any new sticky
 * furniture must keep `--ab-header-h` honest.
 */
.altbev :target,
.altbev [id],
.altbev .woocommerce-notices-wrapper,
.altbev .woocommerce-error,
.altbev .woocommerce-message,
.altbev .woocommerce-info {
	scroll-margin-top: calc(var(--ab-header-h) + 1.25rem);
}

/*
 * The checkout notice is the same failure with a different cause, so it needs a
 * different fix. On a rejected submit WooCommerce Blocks scrolls the window to
 * the notice's own computed offset rather than calling `scrollIntoView`, so
 * `scroll-margin-top` never applies and a 60px notice landed entirely behind
 * the 62px header: a rejected delivery date read as the Place Order button
 * doing nothing at all. Pinning the notice below the header puts it back where
 * the scroll intended, and keeps the error in sight while the buyer scrolls
 * back down to the field it names. `z-index` stays under the header's 50.
 *
 * It is the notices *wrapper* that sticks, not the notice. A sticky element
 * cannot travel outside its own containing block, and the notice's wrapper is
 * exactly as tall as the notice - so sticking the notice itself moved it
 * nowhere. The wrapper's containing block is the whole checkout, which is tall
 * enough to have somewhere to travel.
 */
.altbev .wc-block-checkout .wc-block-components-notices {
	position: sticky;
	top: calc(var(--ab-header-h) + 0.75rem);
	z-index: 40;
}

.altbev .wc-block-store-notice,
.altbev .wc-block-components-notice-banner.is-error {
	scroll-margin-top: calc(var(--ab-header-h) + 1.25rem);
}

.ab-header {
	position: sticky;
	top: 0;
	z-index: 50;
	display: flex;
	align-items: stretch;
	gap: 1rem;
	background: rgba(246, 247, 242, 0.86);
	backdrop-filter: saturate(180%) blur(12px);
	-webkit-backdrop-filter: saturate(180%) blur(12px);
	border-bottom: var(--ab-rule);
	padding: 0 var(--ab-pad);
	min-height: 68px;
}

/* Blur is an effect here, not decoration: the header sits over a saturated
   hero and full-bleed photography, and an opaque bar cuts a hard line across
   both. Where the browser cannot composite it, the ground goes solid. */
@supports not (backdrop-filter: blur(12px)) {
	.ab-header {
		background: var(--ab-paper);
	}
}

.ab-brand {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-2xl);
	font-weight: 700;
	letter-spacing: -0.02em;
	color: var(--ab-ink) !important;
	text-decoration: none;
	margin-right: auto;
	padding: 0.5rem 0;
}

.ab-brand .ab-brand-logo {
	width: 38px;
	height: 38px;
	display: block;
	background: var(--ab-ink);
	border-radius: var(--ab-radius-control);
	object-fit: contain;
}

.ab-brand .ab-brand-mark {
	width: 38px;
	height: 38px;
	display: grid;
	place-items: center;
	background: var(--ab-ink);
	color: var(--ab-volt);
	border-radius: var(--ab-radius-control);
	font-size: var(--ab-t-xl);
}

.ab-nav {
	display: flex;
	align-items: center;
	gap: 0.15rem;
}

.ab-nav a {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 500;
	letter-spacing: -0.005em;
	color: var(--ab-ink) !important;
	text-decoration: none;
	padding: 0.5rem 0.85rem;
	border: 1px solid transparent;
	border-radius: var(--ab-radius-pill);
	transition: background var(--ab-press), color var(--ab-press);
}

.ab-nav a:hover {
	background: var(--ab-paper-2);
}

/* The current page is stated in ink, not volt: volt is reserved for the
   one action in the header, and two adjacent volt blocks read as two CTAs. */
.ab-nav a.ab-current {
	background: var(--ab-ink);
	color: var(--ab-paper) !important;
	font-weight: 600;
}

.ab-nav a.ab-current:hover {
	background: var(--ab-ink-2);
}

.ab-nav a.ab-nav-cta {
	background: var(--ab-volt);
	font-weight: 600;
	box-shadow: var(--ab-diecut-sm);
	margin-left: 0.6rem;
	transition: transform var(--ab-press), box-shadow var(--ab-press), background var(--ab-press);
}

.ab-nav a.ab-nav-cta:hover {
	background: var(--ab-volt-deep);
	transform: translateY(-2px);
	box-shadow: var(--ab-diecut);
}

/* The cart chip is the header's volt block whenever a buyer has a live cart,
   which is why My Account demotes to a plain link in that state: the one-volt
   rule holds. Count sits in an ink counterblock so the figure reads first, and
   the subtotal is set in the spec mono reserved for measured values. */
.ab-nav a.ab-cart-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
}

/* Empty cart: nothing to check out, so the chip goes away and My Account takes
   the volt slot back. Both states are in the markup at all times, so an AJAX
   add only toggles `is-empty` - and exactly one volt block survives either way. */
.ab-nav a.ab-cart-chip.is-empty {
	display: none;
}

.ab-nav:has(.ab-cart-chip.is-empty) a.ab-account-link {
	background: var(--ab-volt);
	border: var(--ab-rule);
	box-shadow: var(--ab-diecut-sm);
	margin-left: 0.6rem;
	transition: transform var(--ab-press), box-shadow var(--ab-press), background var(--ab-press);
}

.ab-nav:has(.ab-cart-chip.is-empty) a.ab-account-link:hover {
	background: var(--ab-volt-deep);
	transform: translateY(-2px);
	box-shadow: var(--ab-diecut);
}

/*
 * On a page that carries the running cart bar, the bar is the checkout block
 * and the header chip is duplicate furniture: two volt Checkout buttons with
 * the same total, plus the row's own volt Add, put three volt blocks in one
 * view against a stated ceiling of two. The chip demotes to ink and keeps
 * doing the job only it does - counting the load from anywhere on the page.
 */
body.altbev:has(.altbev-qo-cartbar.is-visible) .ab-nav a.ab-cart-chip {
	background: var(--ab-ink);
	color: var(--ab-paper) !important;
	box-shadow: none;
}

body.altbev:has(.altbev-qo-cartbar.is-visible) .ab-nav a.ab-cart-chip:hover {
	background: var(--ab-ink-2);
	transform: none;
}

body.altbev:has(.altbev-qo-cartbar.is-visible) .ab-cart-chip-count {
	background: var(--ab-paper);
	color: var(--ab-ink);
}

.ab-cart-chip-count {
	display: grid;
	place-items: center;
	min-width: 1.55em;
	padding: 0.1em 0.3em;
	background: var(--ab-ink);
	color: var(--ab-volt);
	font-variant-numeric: tabular-nums;
}

.ab-cart-chip-total {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-weight: 700;
	letter-spacing: 0;
	font-variant-numeric: tabular-nums;
}

/* The subtotal is the first thing to go when the header runs out of room; the
   count and the word Checkout still carry the meaning. */
@media (max-width: 1100px) {
	.ab-cart-chip-total {
		display: none;
	}
}

.ab-burger {
	display: none;
	width: 44px;
	height: 44px;
	align-self: center;
	place-items: center;
	background: var(--ab-paper);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	color: var(--ab-ink);
	cursor: pointer;
	padding: 0;
}

/* ----- Footer ----------------------------------------------------------- */

/* The footer is a full-bleed change of ground, so it is its own seam. The
   section above it already spends `--ab-section-y` below its last element;
   adding the same interval here stacked two of them into a 192px void and
   left the ink edge floating at the end of a run of dead paper. One interval
   before a ground change, never two. See "Single interval" in Layout. */
.ab-footer {
	background: var(--ab-ink);
	color: var(--ab-paper);
	border-top: var(--ab-rule);
}

.ab-footer__inner {
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding: 2.5rem var(--ab-pad);
	display: flex;
	flex-wrap: wrap;
	gap: 1.6rem 2.5rem;
	align-items: flex-start;
	justify-content: space-between;
}

.ab-footer__brand {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-2xl);
	font-weight: 700;
}

.ab-footer__brand img {
	width: 44px;
	height: 44px;
	display: block;
	border-radius: var(--ab-radius-control);
	object-fit: contain;
}

.ab-footer__copy {
	font-size: var(--ab-t-sm);
	font-weight: 400;
	letter-spacing: 0;
	color: var(--ab-on-ink);
}

.ab-footer__links {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem 1.4rem;
}

.ab-footer__links a {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-paper) !important;
	text-decoration: none;
	border-bottom: 2px solid transparent;
}

.ab-footer__links a:hover {
	border-bottom-color: var(--ab-volt);
	color: var(--ab-volt) !important;
}

.ab-footer .ab-mandatory {
	background: transparent;
	color: var(--ab-on-ink);
	border-bottom: 0;
	border-top: 1px solid var(--ab-ink-2);
}

/* ----- Hero (home) — the first viewport --------------------------------- */

.ab-hero {
	background: var(--ab-field-raspberry);
	color: #fff;
	position: relative;
	margin-inline: calc(50% - 50vw);
	width: 100vw;
	max-width: 100vw;
}

/*
 * The photo is the second full-bleed edge in this section: the field already
 * runs to the viewport edge, and the plate now runs with it, all the way to
 * the right edge rather than sitting boxed inside the 1240px measure. The
 * copy column keeps the page's usual left edge by reusing the same inset a
 * centered `--ab-maxw` container would have, via `max()` so narrow viewports
 * fall back to the ordinary side pad instead of going negative.
 */
.ab-hero__inner {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(320px, 40vw);
	gap: clamp(1.25rem, 3vw, 2.25rem);
	align-items: stretch;
	padding-block: clamp(4.5rem, 8vw, 6.5rem) clamp(3.5rem, 6vw, 4.5rem);
	padding-inline-start: max(var(--ab-pad), calc((100vw - var(--ab-maxw)) / 2 + var(--ab-pad)));
}

.ab-hero__copy {
	align-self: center;
}

.ab-hero h1 {
	font-size: var(--ab-t-display);
	line-height: 1.02;
	letter-spacing: -0.035em;
	color: #fff;
	margin: 0 0 1.4rem;
	/*
	 * `balance` earns its place only while the headline is short enough to set
	 * in two lines. It equalises line lengths, and to do that it will add a
	 * line: on a 47-character headline needing 897px in a 635px column it
	 * resolved to four short lines where natural wrapping gave three. On the
	 * two-line headline this hero actually carries it does the opposite and
	 * breaks on the comma, where the phrase wants to break, instead of
	 * stranding "by" at the end of the first line.
	 *
	 * So this rule is coupled to the copy. A materially longer headline needs
	 * `pretty` here instead, or a smaller display step.
	 */
	text-wrap: balance;
}

.ab-hero__sub {
	font-size: var(--ab-t-xl);
	line-height: 1.55;
	color: var(--ab-on-field);
	max-width: 46ch;
	margin: 0 0 2.2rem;
}

.ab-hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.8rem;
}

/*
 * The plated product photograph. Rounded only on the two corners that meet
 * the copy column - the right edge is the viewport edge, and a radius there
 * would just be cut off. `overflow: hidden` is what makes that left radius
 * actually clip the image instead of leaving it a square photo in a rounded
 * frame.
 *
 * It also runs taller than its own grid row, pulled up past the row's top
 * edge into the section's top pad. A plate that matched the copy column's
 * height exactly read as two boxes obeying the same row - breaking that
 * alignment is what makes it a composition instead of a form layout. It
 * overhangs upward, into the hero's own empty top padding, rather than
 * downward into the mandatory-statements strip, so it never risks covering
 * the compliance copy welded to the hero's foot.
 */
.ab-hero__plate {
	position: relative;
	z-index: 1;
	align-self: stretch;
	overflow: hidden;
	/*
	 * `margin`, not `margin-top`. This is a <figure>, which carries the UA
	 * default `margin: 1em 40px` - and that 40px silently cancelled the whole
	 * edge-bleed, holding the plate 40px short of the viewport edge so it read
	 * as an ordinary boxed image. Zero the inline margins explicitly; the
	 * negative top is the row overhang.
	 */
	margin: -2.5rem 0 0;
	border-radius: var(--ab-radius) 0 0 var(--ab-radius);
	box-shadow: var(--ab-diecut-lift);
}

.ab-hero__plate img {
	display: block;
	width: 100%;
	height: 100%;
	min-height: 320px;
	object-fit: cover;
}

/*
 * The caption used to be a full-width bar welded under the photo, in the mono
 * face set uppercase - including the product name, which the Measurement Rule
 * reserves for actual measured values, not for a name. It now floats as a
 * tucked-in surface card over the photo's lower-left corner: the name in the
 * display face at sentence case, the measured line in mono underneath it.
 */
.ab-hero__platecap {
	position: absolute;
	left: 1.1rem;
	bottom: 1.1rem;
	max-width: calc(100% - 2.2rem);
	background: var(--ab-label);
	color: var(--ab-ink);
	border-radius: var(--ab-radius-sm);
	box-shadow: var(--ab-diecut);
	padding: 0.75rem 1rem;
	display: flex;
	flex-direction: column;
	gap: 0.2rem;
}

.ab-hero__platecap span:first-child {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: -0.01em;
}

.ab-hero__platecap span:last-child {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 500;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
}

/*
 * Category index. These four are the catalog's real top-level navigation, but
 * as a seamless four-color band welded under the hero they read as decoration
 * and buyers did not take them for links. They are separated cards on the page
 * ground now, with the color kept as a filled disc rather than as the whole
 * tile: enough to code the category, little enough that four of them side by
 * side no longer form a second hero.
 */
.ab-catbars {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 1rem;
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding: clamp(2rem, 4vw, 3rem) var(--ab-pad) 0;
}

.ab-catbar {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	padding: 1.25rem 1.4rem;
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius);
	text-decoration: none;
	color: var(--ab-ink) !important;
	transition: transform var(--ab-press), box-shadow var(--ab-press);
}

.ab-catbar::before {
	content: "";
	width: 34px;
	height: 34px;
	border-radius: var(--ab-radius-pill);
	background: var(--ab-cat, var(--ab-ink));
	margin-bottom: 0.5rem;
}

.ab-catbar--cbd { --ab-cat: var(--ab-field-cbd); }
.ab-catbar--delta9 { --ab-cat: var(--ab-field-delta9); }
.ab-catbar--mushroom { --ab-cat: var(--ab-field-mushroom); }
.ab-catbar--roots { --ab-cat: var(--ab-field-roots); }

.ab-catbar:hover {
	transform: translateY(-3px);
	box-shadow: var(--ab-diecut);
}

.ab-catbar__label {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 600;
	letter-spacing: -0.02em;
	line-height: 1.15;
}

.ab-catbar__desc {
	font-size: var(--ab-t-sm);
	letter-spacing: 0;
	color: var(--ab-text-dim);
}

.ab-catbar svg {
	display: none;
}

@media (prefers-reduced-motion: no-preference) {
	@keyframes ab-wipe {
		from { clip-path: inset(0 100% 0 0); }
		to { clip-path: inset(0 0 0 0); }
	}

	.ab-hero h1 {
		animation: ab-wipe 600ms cubic-bezier(0.2, 0, 0, 1);
	}

	/* Same wipe, same direction, on the plate: the one authored moment
	   playing across both hero elements instead of just the headline. */
	.ab-hero__plate {
		animation: ab-wipe 700ms cubic-bezier(0.2, 0, 0, 1) 80ms both;
	}
}

/* ----- Hero (interior page header) -------------------------------------- */

.altbev-hero {
	background: var(--ab-ink);
	color: var(--ab-paper);
	border-bottom: var(--ab-rule);
	margin-inline: calc(50% - 50vw);
	width: 100vw;
	max-width: 100vw;
}

.altbev-hero__inner {
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding: clamp(2rem, 5vw, 3.2rem) var(--ab-pad);
}

/* The outlined label is the same device as the home hero's, so it carries the
   same weight of line. At `--ab-ink-2` the box measured 1.7:1 against the ink
   ground and effectively was not there. */
/*
 * The eyebrow is gone, on the home hero and on every interior page head.
 * "Wholesale beverage portal", "Catalog", "Trade application" in a boxed
 * outline above the headline told a buyer nothing the headline and the nav were
 * not already saying, and a small tracked label above a heading is the single
 * device that makes a page look assembled from a template rather than written.
 * Hidden rather than cut from the templates, so the strings stay in the DOM for
 * anything auditing the markup.
 */
.ab-hero__eyebrow,
.altbev-hero__eyebrow {
	display: none;
}

/*
 * The two-tone heading runs lead-dim, accent-bright. It was the other way
 * round, which put the full-strength ink on "Apply for a" and dimmed
 * "wholesale account" - the emphasis landed on the preposition and the subject
 * receded. The accent is the half that names the thing.
 */
.altbev-hero h1 {
	font-size: var(--ab-t-headline);
	line-height: 1.08;
	color: var(--ab-on-ink);
	margin: 0 0 0.8rem;
}

.altbev-hero h1 .ab-hero-accent,
.altbev-hero h1 .ab-grad-text,
.altbev-hero h1 .ab-red-text {
	color: var(--ab-paper);
}

.altbev-hero__sub {
	color: var(--ab-on-ink);
	font-size: var(--ab-t-lg);
	margin: 0;
	max-width: 62ch;
}

.altbev-hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.8rem;
	margin-top: 1.5rem;
}

.altbev-hero__actions .ab-btn--ghost {
	color: var(--ab-paper) !important;
	border-color: var(--ab-paper);
}

.altbev-hero__actions .ab-btn--ghost:hover {
	background: var(--ab-paper);
	color: var(--ab-ink) !important;
}

/* WooCommerce's own pages (cart, checkout, account) have no AltBev hero, so
   their first heading would otherwise sit flush against the sticky header. */
/* `woocommerce-account` and `woocommerce-order-received` are body classes, so
   they compound with `altbev` instead of nesting under it. Written as
   descendants these matched nothing and both pages opened with their title
   flush against the sticky header. */
.altbev .wp-block-woocommerce-checkout,
.altbev .wp-block-woocommerce-cart,
.altbev.woocommerce-account #ab-main,
.altbev.woocommerce-order-received #ab-main {
	padding-top: clamp(1.75rem, 4vw, 3rem);
}

/* ----- Account (WooCommerce my-account) --------------------------------- */

/* WooCommerce ships this surface as gray chrome that belongs to no system.
   Dressed here as the account folder it is: an index panel of tabs beside a
   ruled sheet, using the same panel, form and button vocabulary as the rest
   of the portal so nothing about it reads as a different product. */

/* `altbev` and `woocommerce-account` are both body classes, so these compound
   rather than nest. Written as a descendant selector this never matches and
   WooCommerce's own flex layout silently wins. */
/* The page title and the account grid are siblings, so the measure lives on
   their shared parent - otherwise the title aligns to the viewport and the
   panels align to their own inset, and the column edge visibly disagrees. */
.altbev.woocommerce-account .type-page {
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding-inline: var(--ab-pad);
	width: 100%;
}

/* Two columns only when there is a tab index to put in the first one. Logged
   out this element holds a heading and the login form instead, and an
   unconditional grid drops the heading into a 15rem column on its own. */
.altbev.woocommerce-account .woocommerce {
	padding-bottom: var(--ab-section-y);
	width: 100%;
}

.altbev.woocommerce-account .woocommerce:has(.woocommerce-MyAccount-navigation) {
	display: grid;
	grid-template-columns: 15rem minmax(0, 1fr);
	gap: 1.75rem;
	align-items: start;
}

/* Signed out: a single column held to a form's width, left-aligned to the
   same measure as the page title. Every other page in the portal opens on
   that edge, and a centred island here would read as a different site.
   WooCommerce centers this form and its heading itself, hence the resets. */
.altbev.woocommerce-account .woocommerce:not(:has(.woocommerce-MyAccount-navigation)) {
	display: block;
	max-width: 30rem;
	margin-inline: 0;
}

.altbev.woocommerce-account .woocommerce:not(:has(.woocommerce-MyAccount-navigation)) > h2 {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-2xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	text-align: start;
	margin: 0 0 0.9rem;
}

.altbev .woocommerce-form-login,
.altbev .woocommerce-form-login label,
.altbev .woocommerce-form-login .form-row {
	text-align: start;
}

/* The submit is the page's one action, so it owns the full column. */
.altbev .woocommerce-form-login .woocommerce-form-login__submit,
.altbev .woocommerce-ResetPassword .button {
	width: 100%;
}

.altbev .woocommerce-form-login .woocommerce-form-login__rememberme {
	flex-direction: row;
	align-items: center;
	gap: 0.5rem;
}

.altbev .woocommerce-LostPassword {
	margin: 1rem 0 0;
	font-size: var(--ab-t-sm);
}

/* --- The tab index --- */

.altbev .woocommerce-MyAccount-navigation {
	background: var(--ab-label);
	border: var(--ab-rule);
	box-shadow: var(--ab-diecut-sm);
	position: sticky;
	top: calc(62px + 1rem);
}

.altbev .woocommerce-MyAccount-navigation ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.altbev .woocommerce-MyAccount-navigation li + li {
	border-top: 1px solid var(--ab-rule-soft);
}

.altbev .woocommerce-MyAccount-navigation a {
	display: block;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
	text-decoration: none;
	padding: 0.7rem 0.9rem;
	transition: background var(--ab-press), color var(--ab-press);
}

.altbev .woocommerce-MyAccount-navigation a:hover {
	background: var(--ab-paper-2);
}

.altbev .woocommerce-MyAccount-navigation a:focus-visible {
	outline: 2px solid var(--ab-ink);
	outline-offset: -4px;
}

/* Current tab is an ink block, never volt: volt is the one action on a
   screen, and a selected state is not an action. Same rule as the header. */
.altbev .woocommerce-MyAccount-navigation li.is-active a {
	background: var(--ab-ink);
	color: var(--ab-paper);
}

/* --- The sheet --- */

.altbev .woocommerce-MyAccount-content {
	background: var(--ab-label);
	border: var(--ab-rule);
	box-shadow: var(--ab-diecut);
	padding: clamp(1.4rem, 3vw, 2.2rem);
	min-width: 0;
}

.altbev .woocommerce-MyAccount-content > p {
	max-width: 68ch;
	color: var(--ab-text);
}

/*
 * The opening line of the sheet reads as its masthead: ruled off from the body
 * beneath it. It is prose, so it stays in the body face - it was set in Martian Mono,
 * which the Measurement Rule reserves for values that are measured, coded or
 * counted, and "Hello Test Buyer (not Test Buyer? Log out)" is none of those.
 * A notices wrapper precedes it in the markup, so this is the first paragraph,
 * not the first child.
 */
.altbev .woocommerce-MyAccount-content > p:first-of-type {
	font-size: var(--ab-t-lg);
	color: var(--ab-text);
	border-bottom: 1px solid var(--ab-rule-soft);
	padding-bottom: 0.9rem;
	margin-bottom: 1.2rem;
	max-width: none;
}

/* The names and the log-out action inside it are the addressable parts. */
.altbev .woocommerce-MyAccount-content > p:first-of-type strong {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
}

.altbev .woocommerce-MyAccount-content h2,
.altbev .woocommerce-Address-title h2 {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-2xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	margin: 0 0 0.8rem;
}

/* --- Notices: stamped panels, not tinted bars --- */

.altbev .woocommerce-info,
.altbev .woocommerce-message,
.altbev .woocommerce-error,
.altbev .woocommerce-notice {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.9rem 1.2rem;
	background: var(--ab-paper);
	border: var(--ab-rule);
	border-left-width: 2px;
	color: var(--ab-ink);
	font-size: var(--ab-t-md);
	list-style: none;
	margin: 0 0 1.2rem;
	padding: 1rem 1.1rem;
}

.altbev .woocommerce-error {
	background: var(--ab-paper-2);
}

.altbev .woocommerce-info::before,
.altbev .woocommerce-message::before,
.altbev .woocommerce-error::before {
	content: none;
}

/* Bricks ships unscoped `.woocommerce-error a` / `.woocommerce-message a` defaults
   (background: var(--bricks-text-danger) / var(--bricks-text-success)) that turn any bare,
   unclassed link inside a notice - e.g. the classic "Lost your password?" recovery link on a
   failed login, or a plain link WooCommerce drops into a success/info notice - into a solid
   color block. `:not(.button)` keeps this off the real `.button`-classed action links (e.g.
   "View cart" on an add-to-cart notice), which already get the volt button treatment below.
   Restore bare links to the plain underlined ink link used everywhere else on the portal. */
.altbev .woocommerce-error a:not(.button),
.altbev .woocommerce-message a:not(.button),
.altbev .woocommerce-info a:not(.button) {
	all: unset;
	display: inline;
	color: var(--ab-ink);
	font-weight: 700;
	text-decoration: underline;
	cursor: pointer;
}

.altbev .woocommerce-error a:not(.button):hover,
.altbev .woocommerce-error a:not(.button):focus-visible,
.altbev .woocommerce-message a:not(.button):hover,
.altbev .woocommerce-message a:not(.button):focus-visible,
.altbev .woocommerce-info a:not(.button):hover,
.altbev .woocommerce-info a:not(.button):focus-visible {
	color: var(--ab-error);
}

/* The empty Orders and Downloads tabs are notices carrying the action that
   resolves them, so the action sits at the end of the line, not below it. */
.altbev .woocommerce-info .button {
	margin-inline-start: auto;
}

/* --- Buttons: the portal's primary, not WooCommerce's --- */

.altbev .woocommerce-MyAccount-content .button,
.altbev .woocommerce-MyAccount-content .woocommerce-Button,
.altbev .woocommerce-form-login .button,
.altbev .woocommerce-form-login .woocommerce-Button,
.altbev .woocommerce-ResetPassword .button,
.altbev .woocommerce-ResetPassword .woocommerce-Button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1;
	padding: 0.85rem 1.5rem;
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: var(--ab-volt);
	color: var(--ab-ink);
	box-shadow: var(--ab-diecut-sm);
	text-decoration: none;
	cursor: pointer;
	transition: transform var(--ab-press), box-shadow var(--ab-press), background var(--ab-press);
}

.altbev .woocommerce-MyAccount-content .button:hover,
.altbev .woocommerce-MyAccount-content .woocommerce-Button:hover,
.altbev .woocommerce-form-login .button:hover,
.altbev .woocommerce-form-login .woocommerce-Button:hover,
.altbev .woocommerce-MyAccount-content .button:focus-visible,
.altbev .woocommerce-MyAccount-content .woocommerce-Button:focus-visible,
.altbev .woocommerce-form-login .button:focus-visible,
.altbev .woocommerce-form-login .woocommerce-Button:focus-visible,
.altbev .woocommerce-ResetPassword .button:hover,
.altbev .woocommerce-ResetPassword .button:focus-visible {
	background: var(--ab-volt-deep);
	transform: translateY(-2px);
	box-shadow: var(--ab-diecut);
}

/* The add/edit link on an address panel carries no `button` class, so it gets
   the secondary form in full rather than overrides on top of the primary.
   Secondary because it must not outrank the panel it sits in. */
.altbev .woocommerce-Address-title .edit {
	display: inline-flex;
	align-items: center;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-sm);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1;
	padding: 0.45rem 0.75rem;
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: transparent;
	color: var(--ab-ink);
	text-decoration: none;
	white-space: nowrap;
	transition: background var(--ab-press), color var(--ab-press);
}

.altbev .woocommerce-Address-title .edit:hover,
.altbev .woocommerce-Address-title .edit:focus-visible {
	background: var(--ab-ink);
	color: var(--ab-paper);
}

/* --- Forms: same control vocabulary as the application form --- */

/* `.woocommerce-ResetPassword` is the lost-password form. It is reached from
   the login screen, so it gets the same panel, controls and button rather
   than dropping back to WooCommerce's bare defaults halfway through. Both of
   these are standalone pages - they are not inside the account sheet, so the
   panel is theirs to draw. */
.altbev .woocommerce-form-login,
.altbev .woocommerce-ResetPassword {
	border: var(--ab-rule);
	background: var(--ab-label);
	padding: 1.6rem 1.4rem 1.2rem;
	margin: 1.8rem 0 0;
}

/*
 * Account Details is already inside the white account sheet, so its password
 * fieldset drew a second 2px box within a 2px box - a panel inside a panel,
 * which this system does not do. The group becomes a ruled band instead, and
 * the identity fields above it get a matching head, so the screen reads as two
 * labeled sections of one sheet rather than loose fields followed by a box.
 */
.altbev .woocommerce-EditAccountForm fieldset {
	border: 0;
	border-top: var(--ab-rule);
	background: transparent;
	padding: 1.5rem 0 0;
	margin: 2.2rem 0 0;
	min-width: 0;
}

.altbev .ab-account-head,
.altbev .woocommerce-EditAccountForm legend {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-text-dim);
	background: transparent;
	padding: 0;
	margin: 0 0 1.3rem;
}

/*
 * A legend interrupts its fieldset's border by design, which left the group's
 * top rule running out of the words like a strikethrough. Floating it to full
 * width takes it out of the border flow, so the rule stays whole above the head
 * and reads as the seam between the two groups.
 */
.altbev .woocommerce-EditAccountForm legend {
	float: left;
	width: 100%;
}

/* Something upstream leaves this form a half-width flex box. It is the whole
   page when signed out, so it fills the column it was given. */
.altbev .woocommerce-form-login {
	display: flex;
	flex-direction: column;
	width: 100%;
	margin-top: 0;
}

/* WooCommerce still floats these rows at a percentage width. Inside the grid
   columns below that left First and Last name at half the cell they were given
   - two stunted boxes with empty paper beside them. The grid owns the columns. */
.altbev .woocommerce-form-row,
.altbev .woocommerce-form-login .form-row,
.altbev .woocommerce-ResetPassword .form-row {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	margin: 0 0 1rem;
	float: none;
	width: 100%;
}

.altbev .woocommerce-form-row label,
.altbev .woocommerce-form-login label,
.altbev .woocommerce-ResetPassword label {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-ink);
}

.altbev .woocommerce-form-row .required,
.altbev .woocommerce-form-login .required {
	color: var(--ab-error);
	text-decoration: none;
}

.altbev .woocommerce-MyAccount-content .input-text,
.altbev .woocommerce-form-login .input-text,
.altbev .woocommerce-ResetPassword .input-text,
.altbev .woocommerce-MyAccount-content select {
	font-family: var(--ab-font);
	font-size: var(--ab-t-md);
	color: var(--ab-text);
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.7rem 0.85rem;
	width: 100%;
}

.altbev .woocommerce-MyAccount-content .input-text:focus,
.altbev .woocommerce-form-login .input-text:focus,
.altbev .woocommerce-ResetPassword .input-text:focus,
.altbev .woocommerce-MyAccount-content select:focus {
	outline: none;
	border-color: var(--ab-ink);
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

.altbev .woocommerce-MyAccount-content em,
.altbev .woocommerce-form-login em {
	display: block;
	font-family: var(--ab-font);
	font-style: normal;
	font-size: var(--ab-t-sm);
	color: var(--ab-text-dim);
	margin-top: 0.3rem;
}

/* Two-up on the paired rows the markup already declares. A grid rather than
   inline-flex halves: two 50% inline boxes plus the whitespace between them
   overflow the line and wrap, which reads as one narrow column of stacked
   half-width fields. */
@media (min-width: 621px) {
	.altbev .woocommerce-EditAccountForm {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 1.2rem;
	}

	.altbev .woocommerce-EditAccountForm > * {
		grid-column: 1 / -1;
	}

	.altbev .woocommerce-EditAccountForm > .woocommerce-form-row--first {
		grid-column: 1;
	}

	.altbev .woocommerce-EditAccountForm > .woocommerce-form-row--last {
		grid-column: 2;
	}
}

/* --- Classic payment methods: add a card, and pay an open invoice --------- */

/*
 * WooCommerce ships two entirely separate payment-method components. The Blocks
 * checkout uses `.wc-block-components-radio-control`, which this system already
 * restates; `/my-account/add-payment-method/` and the `order-pay` screen a buyer
 * lands on to settle an invoice both use the *classic* `ul.payment_methods`
 * markup, which inherited nothing and arrived as a bulleted list with native
 * 13px radios, body-size labels stacked under them, and the gateway's own 1px
 * gray box. On a portal whose whole promise is ordering on terms, the screen
 * where a buyer hands over a card cannot be the one that looks unfinished.
 *
 * Same construction as the Order Sheet: 2px ink frame, rows divided by a hairline.
 */
.altbev ul.payment_methods {
	list-style: none;
	margin: 0 0 1.6rem;
	padding: 0;
	border: var(--ab-rule);
	background: var(--ab-label);
}

.altbev ul.payment_methods > li {
	display: block;
	margin: 0;
	padding: 0;
	border-bottom: 1px solid var(--ab-rule-soft);
}

.altbev ul.payment_methods > li:last-child {
	border-bottom: 0;
}

/* The row itself is the label, so the whole strip is the hit target. */
.altbev ul.payment_methods > li > label {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
	padding: 0.85rem 1.1rem;
	cursor: pointer;
	transition: background var(--ab-press);
}

.altbev ul.payment_methods > li > label:hover {
	background: var(--ab-paper-2);
}

/* The chosen method is stated in ink, the same way the selected method reads on
   the Blocks checkout, so the two screens agree. */
.altbev ul.payment_methods > li:has(input:checked) > label {
	background: var(--ab-ink);
	color: var(--ab-paper);
}

.altbev ul.payment_methods > li > input.input-radio {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* Round, because a radio is a radio - the Square Rule governs surfaces, not
   native affordances. Drawn rather than native so it survives the ink row. */
.altbev ul.payment_methods > li > label::before {
	content: "";
	flex: none;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	border: 2px solid currentColor;
	background: transparent;
	transition: box-shadow var(--ab-press);
}

.altbev ul.payment_methods > li:has(input:checked) > label::before {
	box-shadow: inset 0 0 0 3px var(--ab-ink), inset 0 0 0 12px var(--ab-volt);
}

/* Keyboard focus has to reach the drawn control, since the real radio is
   visually hidden. */
.altbev ul.payment_methods > li > input.input-radio:focus-visible + label::before {
	outline: 3px solid var(--ab-ink);
	outline-offset: 2px;
}

.altbev ul.payment_methods > li:has(input:checked) > input.input-radio:focus-visible + label::before {
	outline-color: var(--ab-volt);
}

/* The expanded panel belongs to the row above it, so it changes ground rather
   than drawing a second box - a panel inside a panel is always wrong, and the
   gateway shipped exactly that as a 1px gray rectangle. */
.altbev .woocommerce-PaymentBox,
.altbev .payment_box {
	background: var(--ab-paper-2);
	border-top: 1px solid var(--ab-rule-soft);
	padding: 1.2rem 1.1rem;
	margin: 0;
}

.altbev .payment_box > p:first-child {
	margin-top: 0;
}

.altbev fieldset.wc-payment-form,
.altbev .payment_box fieldset {
	border: 0;
	padding: 0;
	margin: 0;
	background: transparent;
}

/* The gateway's rows carry WooCommerce's own `form-row` classes, not the
   `woocommerce-form-row` the account forms use, so they need naming here to
   pick up the label voice every other field on the site speaks. */
/* WooCommerce still floats these rows at a percentage width, which inside a
   grid cell left each paired field at 47% of 47%. The grid owns the columns. */
.altbev .payment_box .form-row {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	margin: 0 0 1rem;
	float: none;
	width: 100%;
}

.altbev .payment_box .form-row:last-child {
	margin-bottom: 0;
}

.altbev .payment_box .form-row label {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-ink);
}

.altbev .payment_box .form-row .required {
	color: var(--ab-error);
	text-decoration: none;
}

.altbev .payment_box .input-text {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	color: var(--ab-text);
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.7rem 0.85rem;
	width: 100%;
	font-variant-numeric: tabular-nums;
}

.altbev .payment_box .input-text::placeholder {
	color: var(--ab-text-dim);
}

.altbev .payment_box .input-text:focus {
	outline: none;
	border-color: var(--ab-ink);
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

/* Expiry and card code are a pair, and the markup already says so. */
@media (min-width: 621px) {
	.altbev .payment_box:has(.form-row-first) {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 1.2rem;
	}

	.altbev .payment_box:has(.form-row-first) > *,
	.altbev .payment_box:has(.form-row-first) > fieldset > .form-row-wide {
		grid-column: 1 / -1;
	}

	.altbev .payment_box fieldset:has(.form-row-first) {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 1.2rem;
	}

	.altbev .payment_box fieldset > .form-row-wide {
		grid-column: 1 / -1;
	}

	.altbev .payment_box fieldset > .form-row-first {
		grid-column: 1;
	}

	.altbev .payment_box fieldset > .form-row-last {
		grid-column: 2;
	}
}

/*
 * The address editor is a third WooCommerce form family: bare `.form-row`, no
 * `woocommerce-form-row`, so it inherited neither the label voice nor the
 * required marker and arrived at body size with a plain ink asterisk -
 * one screen away from Account Details, which speaks the tracked mono the whole
 * rest of the portal uses. Its selects also render borderless.
 */
.altbev .woocommerce-address-fields .form-row,
.altbev .woocommerce-address-fields .form-row-wide {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	margin: 0 0 1rem;
	float: none;
	width: 100%;
}

.altbev .woocommerce-address-fields .form-row > label {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-ink);
}

.altbev .woocommerce-address-fields .form-row .required,
.altbev .woocommerce-address-fields .form-row abbr.required {
	color: var(--ab-error);
	text-decoration: none;
	border: 0;
}

.altbev .woocommerce-address-fields select,
.altbev .woocommerce-address-fields .select2-selection {
	font-family: var(--ab-font);
	font-size: var(--ab-t-md);
	color: var(--ab-text);
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.7rem 0.85rem;
	width: 100%;
	height: auto;
}

/* Select2 carries its own metrics: a 40px line-height on the rendered value
   made the country and state boxes 13px taller than every input beside them,
   and its arrow is pinned to `top: 1px` at zero height, which left a stray
   triangle poking out of the top-right corner instead of a centred chevron. */
.altbev .woocommerce-address-fields .select2-selection__rendered {
	line-height: 1.4;
	padding: 0;
	color: var(--ab-text);
}

.altbev .woocommerce-address-fields .select2-selection__arrow {
	top: 0;
	right: 0.7rem;
	height: 100%;
	display: flex;
	align-items: center;
}

.altbev .woocommerce-address-fields .select2-selection__arrow b {
	border-top-color: var(--ab-ink);
	margin-top: 0;
	position: static;
}

.altbev .woocommerce-address-fields select:focus,
.altbev .woocommerce-address-fields .select2-container--focus .select2-selection {
	outline: none;
	border-color: var(--ab-ink);
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

.altbev .woocommerce-address-fields input::placeholder {
	color: var(--ab-text-dim);
}

@media (min-width: 621px) {
	.altbev .woocommerce-address-fields__field-wrapper {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 1.2rem;
	}

	.altbev .woocommerce-address-fields__field-wrapper > * {
		grid-column: 1 / -1;
	}

	.altbev .woocommerce-address-fields__field-wrapper > .form-row-first {
		grid-column: 1;
	}

	.altbev .woocommerce-address-fields__field-wrapper > .form-row-last {
		grid-column: 2;
	}
}

/* --- Addresses --- */

.altbev .woocommerce-Addresses {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
	gap: 1.25rem;
	margin-top: 1.2rem;
}

.altbev .woocommerce-Addresses .u-column1,
.altbev .woocommerce-Addresses .u-column2 {
	width: auto;
	float: none;
	border: var(--ab-rule);
	background: var(--ab-paper);
	padding: 1.2rem 1.1rem;
}

/* Wraps rather than squeezing: in a narrow column the title would otherwise
   break mid-phrase to make room for the action. */
.altbev .woocommerce-Address-title {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 0.7rem 1rem;
	border-bottom: 1px solid var(--ab-rule-soft);
	padding-bottom: 0.7rem;
	margin-bottom: 0.9rem;
}

.altbev .woocommerce-Address-title h2 {
	margin: 0;
}

.altbev .woocommerce-Address address {
	font-style: normal;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	line-height: 1.7;
	color: var(--ab-text);
}

/* --- Orders table: the same order sheet used across the portal --- */

.altbev .woocommerce-orders-table {
	width: 100%;
	border-collapse: collapse;
	border: var(--ab-rule);
	margin-top: 1.2rem;
}

/*
 * `thead th`, not `th`: WooCommerce marks the order-number cell in each body
 * row as `<th scope="row">` too. Painted with the column-head treatment it
 * became an ink block containing an ink link - the order number, the one
 * thing the row exists to give you, rendered invisible.
 */
.altbev .woocommerce-orders-table thead th {
	background: var(--ab-ink);
	color: var(--ab-paper);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	text-align: left;
	padding: 0.7rem 0.8rem;
}

.altbev .woocommerce-orders-table td,
.altbev .woocommerce-orders-table tbody th {
	border-top: 1px solid var(--ab-rule-soft);
	padding: 0.75rem 0.8rem;
	font-size: var(--ab-t-md);
	font-weight: 400;
	text-align: left;
}

.altbev .woocommerce-orders-table tbody th a {
	font-family: var(--ab-font-spec);
	font-variant-numeric: tabular-nums;
	font-weight: 600;
	color: var(--ab-ink);
}

/* Order status is a measured fact about the order, in the same voice as the
   figures beside it. */
.altbev .woocommerce-orders-table .woocommerce-orders-table__cell-order-status {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.altbev .woocommerce-orders-table tbody tr:nth-child(even) {
	background: var(--ab-paper-2);
}

/* Every measured value in the system is mono with tabular figures. */
.altbev .woocommerce-orders-table .woocommerce-orders-table__cell-order-number,
.altbev .woocommerce-orders-table .woocommerce-orders-table__cell-order-date,
.altbev .woocommerce-orders-table .woocommerce-orders-table__cell-order-total {
	font-family: var(--ab-font-spec);
	font-variant-numeric: tabular-nums;
}

@media (max-width: 880px) {
	/* Must carry the same `:has()` as the rule it overrides - a media query
	   adds no specificity, so the plainer selector loses and the sidebar
	   stays beside the content. */
	.altbev.woocommerce-account .woocommerce:has(.woocommerce-MyAccount-navigation) {
		grid-template-columns: minmax(0, 1fr);
	}

	/* Stacked, the tab index stops being a sidebar and stops sticking. A grid
	   rather than wrapped flex, so the cells keep an even measure instead of
	   sizing to their labels and leaving a ragged edge. */
	.altbev .woocommerce-MyAccount-navigation {
		position: static;
	}

	.altbev .woocommerce-MyAccount-navigation ul {
		display: grid;
		grid-template-columns: repeat(2, 1fr);
	}

	.altbev .woocommerce-MyAccount-navigation li,
	.altbev .woocommerce-MyAccount-navigation li + li {
		border-top: 1px solid var(--ab-rule-soft);
	}

	.altbev .woocommerce-MyAccount-navigation li:nth-child(odd) {
		border-right: 1px solid var(--ab-rule-soft);
	}

	.altbev .woocommerce-MyAccount-navigation li:nth-child(-n + 2) {
		border-top: 0;
	}

	.altbev .woocommerce-orders-table {
		display: block;
		overflow-x: auto;
	}
}

@media (max-width: 620px) {
	.altbev .woocommerce-MyAccount-navigation ul {
		grid-template-columns: minmax(0, 1fr);
	}

	.altbev .woocommerce-MyAccount-navigation li:nth-child(odd) {
		border-right: 0;
	}

	.altbev .woocommerce-MyAccount-navigation li:nth-child(2) {
		border-top: 1px solid var(--ab-rule-soft);
	}
}

/* =========================================================================
   Commerce surfaces (cart, checkout, shop, product, order)
   -------------------------------------------------------------------------
   WooCommerce ships these as its own product: gray chrome, rounded controls,
   system-sans typography, and a measure that belongs to no page in this
   portal. They are dressed here in the same vocabulary as the order sheet -
   ruled document, ink header bar, mono measured values - so a buyer moving
   from Quick Order into checkout never leaves the same piece of stationery.
   ========================================================================= */

/* --- The shared shell --------------------------------------------------- */

/*
 * Bricks holds `#brx-content` to its own 1100px content width, while the
 * cart and checkout blocks carry `alignwide` and break back out to 1320px.
 * The result is a page title on one left edge and the block beneath it on
 * another. Both are pulled onto the portal measure instead. The account
 * pages set their own measure on `.type-page` and are excluded.
 */
.altbev.woocommerce-page:not(.woocommerce-account) #brx-content {
	max-width: var(--ab-maxw);
	width: 100%;
	margin-inline: auto;
	padding-inline: var(--ab-pad);
	padding-bottom: var(--ab-section-y);
}

.altbev.woocommerce-page:not(.woocommerce-account) #brx-content .alignwide,
.altbev.woocommerce-page:not(.woocommerce-account) #brx-content .alignfull {
	max-width: 100%;
	width: 100%;
	margin-inline: 0;
}

/* These pages have no AltBev hero, so their first element would otherwise
   sit flush against the sticky header. */
.altbev.woocommerce-page:not(.woocommerce-account) #ab-main {
	padding-top: clamp(1.75rem, 4vw, 3rem);
}

.altbev.woocommerce-page:not(.woocommerce-account) #brx-content > h1,
.altbev.woocommerce-shop .bricks-archive-title-wrapper .title {
	font-size: var(--ab-t-title);
	text-align: start;
	margin: 0 0 1.5rem;
}

/* --- The docket: the panel every total and summary is written on -------- */

/* On the cart the sidebar *is* the docket; on the checkout the sidebar also
   holds the notices area, so the panel goes on the summary block itself and
   nothing that is not part of the summary is framed by it. */
.altbev .wc-block-cart__sidebar,
.altbev .wp-block-woocommerce-checkout-order-summary-block {
	background: var(--ab-label);
	border: var(--ab-rule);
	box-shadow: var(--ab-diecut);
	padding: 0;
	overflow: hidden;
}

/* The two-column split. WooCommerce's own flex sizing collapses awkwardly
   between its breakpoints and ours; an explicit grid keeps the docket at a
   readable width instead of letting it track a percentage. */
.altbev .wc-block-components-sidebar-layout {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 23rem;
	gap: 2rem;
	align-items: start;
}

.altbev .wc-block-cart__main,
.altbev .wc-block-checkout__main,
.altbev .wc-block-cart__sidebar,
.altbev .wc-block-checkout__sidebar {
	width: auto;
	max-width: none;
	padding: 0;
	min-width: 0;
}

.altbev .wc-block-cart__sidebar,
.altbev .wc-block-checkout__sidebar {
	position: sticky;
	top: calc(62px + 1.5rem);
}

/* The docket's own heading is an ink bar across the top of the panel, the
   same device the order sheet uses for its column head. */
.altbev .wc-block-cart__totals-title,
.altbev .wc-block-components-checkout-order-summary__title {
	background: var(--ab-ink);
	color: var(--ab-paper);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	text-align: left;
	margin: 0;
	padding: 0.7rem 1rem;
}

.altbev .wc-block-components-checkout-order-summary__title-text {
	font-size: inherit;
	font-weight: inherit;
	letter-spacing: inherit;
	text-transform: inherit;
	color: inherit;
}

.altbev .wc-block-components-checkout-order-summary__content,
.altbev .wc-block-cart__sidebar .wc-block-components-totals-wrapper,
.altbev .wc-block-checkout__sidebar .wc-block-components-totals-wrapper {
	padding-inline: 1rem;
}

.altbev .wc-block-components-totals-wrapper {
	border-top: 1px solid var(--ab-rule-soft);
	padding-block: 0.85rem;
}

.altbev .wc-block-components-totals-wrapper:first-child {
	border-top: 0;
}

/* WooCommerce always renders the discount and fee wrappers, empty or not.
   Left alone they read as two blank ruled rows in the middle of the docket. */
.altbev .wc-block-components-totals-wrapper:empty {
	display: none;
}

.altbev .wc-block-components-totals-item__label {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-text-dim);
}

.altbev .wc-block-components-totals-item__value,
.altbev .wc-block-components-formatted-money-amount {
	font-family: var(--ab-font-spec);
	font-variant-numeric: tabular-nums;
	font-weight: 600;
	color: var(--ab-text);
}

/* The one figure the buyer is actually deciding on. */
.altbev .wc-block-components-totals-footer-item {
	border-top: var(--ab-rule);
	padding-top: 0.9rem;
}

.altbev .wc-block-components-totals-footer-item .wc-block-components-totals-item__label {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
}

/* The amount itself carries `…-footer-item-tax-value` in this WooCommerce
   version - it is the total *including* tax, not a footnote about tax - so it
   is sized here with the value it lives in. The tax note is the sibling
   `__description`. */
.altbev .wc-block-components-totals-footer-item .wc-block-components-totals-item__value,
.altbev .wc-block-components-totals-footer-item .wc-block-components-formatted-money-amount {
	font-size: var(--ab-t-3xl);
	font-weight: 700;
	color: var(--ab-ink);
}

.altbev .wc-block-components-totals-footer-item .wc-block-components-totals-item__description {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	color: var(--ab-text-dim);
}

/* --- The pick list: cart line items ------------------------------------- */

.altbev .wc-block-cart-items {
	border: var(--ab-rule);
	background: var(--ab-label);
	border-collapse: collapse;
	margin: 0;
}

/*
 * The ink bar goes on the row, not the cells. WooCommerce ships
 * `table.wc-block-cart-items th { background: none !important }`, so a cell
 * background is unreachable without an `!important` of our own - and it also
 * marks the middle header cell `visibility: hidden`, which would punch a
 * white gap through the middle of the bar. The `tr` is not in either rule,
 * so it carries the ink cleanly behind cells that are transparent anyway.
 */
.altbev .wc-block-cart-items .wc-block-cart-items__header {
	background: var(--ab-ink);
}

/* WooCommerce hides the middle header cell, which with the ink on the row
   leaves a gap punched through the middle of the bar. Restored so the bar is
   continuous and the column actually gets a name. */
.altbev .wc-block-cart-items .wc-block-cart-items__header .wc-block-cart-items__header-product {
	visibility: visible;
}

.altbev .wc-block-cart-items .wc-block-cart-items__header th {
	color: var(--ab-paper);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	text-align: left;
	padding: 0.7rem 0.9rem;
	border: 0;
}

.altbev .wc-block-cart-items__row td {
	border-top: 1px solid var(--ab-rule-soft);
	padding: 1.1rem 0.9rem;
}

.altbev .wc-block-cart-items__row:first-child td {
	border-top: 0;
}

/* The case photograph sits on its own plate rather than floating on the
   sheet, which also gives the placeholder a deliberate frame when a product
   has no label image on file yet. */
.altbev .wc-block-cart-item__image img,
.altbev .wc-block-components-order-summary-item__image img {
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: var(--ab-paper-2);
	border-radius: var(--ab-radius-control);
	width: 100%;
}

/* A 52px thumbnail is lost against a 117px row. The case is the thing being
   ordered, so the plate gets enough of the row to be recognized. */
.altbev table.wc-block-cart-items .wc-block-cart-items__header-image,
.altbev table.wc-block-cart-items .wc-block-cart-item__image {
	width: 104px;
}

/* WooCommerce sizes this from `table.wc-block-cart-items .…__row .…name`,
   which is (0,3,1) - the element selector is what a three-class rule of ours
   loses to. Matching the `table` puts us at (0,4,1). */
.altbev table.wc-block-cart-items .wc-block-cart-items__row .wc-block-components-product-name,
.altbev .wc-block-components-order-summary-item__description .wc-block-components-product-name,
.altbev .wc-block-components-product-name {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.1;
	color: var(--ab-ink);
	text-decoration: none;
}

.altbev .wc-block-components-product-price,
.altbev .wc-block-cart-item__total,
.altbev .wc-block-components-order-summary-item__total-price {
	font-family: var(--ab-font-spec);
	font-variant-numeric: tabular-nums;
	font-weight: 600;
	color: var(--ab-text);
}

.altbev .wc-block-components-product-price__regular {
	color: var(--ab-text-dim);
	font-weight: 500;
}

/* The saving is a stamped chip, not a tinted pill: this system states
   measured facts in ink on paper, and volt belongs to the action. */
.altbev .wc-block-components-sale-badge {
	background: var(--ab-ink);
	color: var(--ab-paper);
	border: 0;
	border-radius: var(--ab-radius-control);
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	padding: 0.25rem 0.5rem;
}

/* The saved amount is written inside a money element that otherwise takes the
   system's ink color - which on the ink chip is ink on ink. */
.altbev .wc-block-components-sale-badge .wc-block-components-formatted-money-amount {
	color: inherit;
	font-size: inherit;
}

/* Quantity: the same square, ink-ruled control as the order sheet. */
.altbev .wc-block-components-quantity-selector {
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: var(--ab-label);
	overflow: hidden;
	max-width: 7.5rem;
}

.altbev .wc-block-components-quantity-selector::after {
	content: none;
}

.altbev .wc-block-components-quantity-selector__input {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--ab-text);
	background: transparent;
	border: 0;
	padding-block: 0.4rem;
}

.altbev .wc-block-components-quantity-selector__button {
	color: var(--ab-ink);
	background: var(--ab-paper);
	border: 0;
	font-size: var(--ab-t-lg);
	font-weight: 700;
	opacity: 1;
	transition: background var(--ab-press);
}

.altbev .wc-block-components-quantity-selector__button--minus {
	border-right: 1px solid var(--ab-rule-soft);
}

.altbev .wc-block-components-quantity-selector__button--plus {
	border-left: 1px solid var(--ab-rule-soft);
}

.altbev .wc-block-components-quantity-selector__button:hover:not(:disabled) {
	background: var(--ab-ink);
	color: var(--ab-paper);
}

.altbev .wc-block-cart-item__remove-link {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-text-dim);
	text-decoration-thickness: 1px;
}

.altbev .wc-block-cart-item__remove-link:hover {
	color: var(--ab-error);
}

/* --- Order summary lines (checkout docket) ------------------------------ */

.altbev .wc-block-components-order-summary-item {
	border-bottom: 1px solid var(--ab-rule-soft);
	padding-block: 0.9rem;
}

.altbev .wc-block-components-order-summary-item__quantity {
	background: var(--ab-ink);
	color: var(--ab-paper);
	border: 0;
	border-radius: var(--ab-radius-control);
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}

.altbev .wc-block-components-order-summary-item__individual-prices {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	color: var(--ab-text-dim);
}

/* --- Coupons and disclosure panels -------------------------------------- */

.altbev .wc-block-components-panel__button {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-ink);
	padding-block: 0.35rem;
}

/* --- Checkout form: the portal's control vocabulary --------------------- */

.altbev .wc-block-components-checkout-step {
	border: 0;
	padding: 0;
	margin: 0 0 2rem;
}

.altbev .wc-block-components-checkout-step__heading {
	margin: 0 0 1rem;
	padding-bottom: 0.55rem;
	border-bottom: var(--ab-rule);
}

.altbev .wc-block-components-checkout-step__title {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-2xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
	margin: 0;
}

/*
 * WooCommerce floats its labels inside the input. Every other form in this
 * portal states its label as tracked mono above the field, and a checkout
 * that reads as a different form language is exactly the seam this pass
 * exists to remove. The label is returned to the normal flow and locked in
 * its resting position, so it no longer depends on the `is-active` class
 * the block toggles as the field gains content.
 */
/*
 * WooCommerce separates rows with `margin-top` on the field wrapper, sized
 * for a floating label that lives inside the box. With the label back above
 * the field that gap is now doing double duty and is far too tight, so the
 * rhythm is restated here rather than removed.
 */
.altbev .wc-block-components-text-input,
.altbev .wc-blocks-components-select {
	position: static;
	margin-top: 1.15rem;
}

.altbev .wc-block-components-checkout-step__content > .wc-block-components-address-form > *:first-child,
.altbev .wc-block-components-checkout-step__content > .wc-block-components-text-input:first-child,
.altbev .wc-block-components-address-form > *:first-child .wc-block-components-text-input,
.altbev .wc-block-components-address-form > *:first-child .wc-blocks-components-select {
	margin-top: 0;
}

/* The markup is input-then-label, because the float relies on the label being
   painted over the field. Once the label is back in the flow that order puts
   it underneath, so the pair is reversed visually. */
.altbev .wc-block-components-text-input {
	display: flex;
	flex-direction: column-reverse;
}

.altbev .wc-block-components-text-input label,
.altbev .wc-blocks-components-select__label {
	position: static;
	transform: none;
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-ink);
	line-height: 1.4;
	max-width: none;
	overflow: visible;
	padding: 0;
	margin: 0 0 0.4rem;
	display: block;
}

.altbev .wc-block-components-text-input input[type="text"],
.altbev .wc-block-components-text-input input[type="email"],
.altbev .wc-block-components-text-input input[type="tel"],
.altbev .wc-block-components-text-input input[type="number"],
.altbev .wc-blocks-components-select__select {
	font-family: var(--ab-font);
	font-size: var(--ab-t-md);
	color: var(--ab-text);
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.7rem 0.85rem;
	height: auto;
	line-height: 1.4;
	width: 100%;
}

.altbev .wc-block-components-text-input input:focus,
.altbev .wc-blocks-components-select__select:focus {
	outline: none;
	border-color: var(--ab-ink);
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

.altbev .wc-blocks-components-select__container {
	background: transparent;
	border: 0;
	border-radius: var(--ab-radius-control);
	height: auto;
}

.altbev .wc-blocks-components-select__expand {
	top: auto;
	bottom: 1rem;
}

.altbev .wc-block-components-address-form__address_2-toggle {
	display: inline-block;
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-ink);
	margin-top: 0.6rem;
}

/* --- Payment options: a ruled list, current row in ink ------------------ */

.altbev .wc-block-components-radio-control {
	border: var(--ab-rule);
	background: var(--ab-label);
}

.altbev .wc-block-components-radio-control-accordion-option,
.altbev .wc-block-components-radio-control__option {
	border: 0;
	border-radius: var(--ab-radius-control);
	margin: 0;
}

.altbev .wc-block-components-radio-control-accordion-option + .wc-block-components-radio-control-accordion-option,
.altbev .wc-block-components-radio-control__option + .wc-block-components-radio-control__option {
	border-top: 1px solid var(--ab-rule-soft);
}

.altbev .wc-block-components-radio-control__label {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: inherit;
}

/* The chosen method is stated in ink, the same way the current tab and the
   current nav item are. Its explanatory content stays on paper below. */
.altbev .wc-block-components-radio-control__option-checked {
	background: var(--ab-ink);
	color: var(--ab-paper);
}

.altbev .wc-block-components-radio-control__option-checked .wc-block-components-radio-control__input {
	border-color: var(--ab-paper);
	background: transparent;
}

.altbev .wc-block-components-radio-control__option-checked .wc-block-components-radio-control__input::before {
	background: var(--ab-volt);
}

.altbev .wc-block-components-radio-control-accordion-content {
	background: var(--ab-paper);
	border-top: 1px solid var(--ab-rule-soft);
	font-size: var(--ab-t-sm);
	color: var(--ab-text);
	margin: 0;
	padding: 0.9rem 1rem;
}

.altbev .wc-block-components-radio-control__input {
	border: var(--ab-rule-heavy);
	box-shadow: none;
}

/* --- Checkboxes and the terms line -------------------------------------- */

.altbev .wc-block-components-checkbox__mark {
	fill: var(--ab-ink);
}

.altbev .wc-block-components-checkbox__input[type="checkbox"] {
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: var(--ab-label);
}

.altbev .wc-block-components-checkbox__input[type="checkbox"]:checked {
	background: var(--ab-volt);
	border-color: var(--ab-ink);
}

.altbev .wc-block-components-checkbox__label {
	font-size: var(--ab-t-md);
	color: var(--ab-text);
}

/* Body face, not mono: this is a running sentence, and the mono voice in this
   system is reserved for measured values. */
.altbev .wc-block-checkout__terms {
	font-family: var(--ab-font);
	font-size: var(--ab-t-sm);
	line-height: 1.6;
	color: var(--ab-text-dim);
	border-top: 1px solid var(--ab-rule-soft);
	padding-top: 1.1rem;
	margin-top: 1.5rem;
}

.altbev .wc-block-checkout__terms a {
	color: var(--ab-ink);
}

/* --- The saved ship-to card --------------------------------------------- */

.altbev .wc-block-components-address-card {
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: var(--ab-paper);
	padding: 1rem 1.1rem;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	line-height: 1.7;
}

.altbev .wc-block-components-address-card__edit {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-ink);
}

/* --- The two actions that carry a buyer through checkout ---------------- */

/* The block cart/checkout ship their own button colors, which land ink text
   on WooCommerce's default dark gray - about 1.2:1, so the primary action of
   the whole portal reads as disabled. */
.altbev .wc-block-cart__submit-button,
.altbev .wc-block-components-checkout-place-order-button {
	background: var(--ab-volt);
	color: var(--ab-ink);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	box-shadow: var(--ab-diecut-sm);
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 700;
	letter-spacing: -0.01em;
	padding-block: 0.85rem;
	transition: transform var(--ab-press), box-shadow var(--ab-press), background var(--ab-press);
}

.altbev .wc-block-cart__submit-button:hover,
.altbev .wc-block-components-checkout-place-order-button:hover {
	background: var(--ab-volt-deep);
	color: var(--ab-ink);
	transform: translateY(-2px);
	box-shadow: var(--ab-diecut);
}

/* The cart's submit sits inside the docket, so it needs the panel's inset. */
.altbev .wc-block-cart__submit-container {
	padding: 0 1rem 1rem;
}

/* --- The B2B fields inside the docket ----------------------------------- */

/*
 * The plugin gives `.altbev-checkout-fields` its own ink border so it stands
 * as a panel wherever WooCommerce drops it. Inside the docket that would be a
 * panel within a panel; here it is flattened back to a ruled band that shares
 * the docket's edges, and its heading takes the same mono column-head voice
 * as the totals above it.
 */
.altbev .wc-block-cart__sidebar .altbev-checkout-fields,
.altbev .wp-block-woocommerce-checkout-order-summary-block .altbev-checkout-fields {
	border: 0;
	border-top: var(--ab-rule);
	background: transparent;
	margin: 0;
	padding: 0.95rem 1rem;
}

.altbev .wc-block-cart__sidebar .altbev-checkout-fields .altbev-section-title,
.altbev .wp-block-woocommerce-checkout-order-summary-block .altbev-checkout-fields .altbev-section-title {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.1em;
	color: var(--ab-text-dim);
	border-bottom: 0;
	padding-bottom: 0;
	margin-bottom: 0.75rem;
}

/* --- The empty cart's product grid -------------------------------------- */

/*
 * WooCommerce's grid block lands ink text on its own dark gray button -
 * about 1.2:1, the same defect the checkout button had. The cards are given
 * the shop's label-panel treatment so the empty cart is not the one screen
 * in the portal running WooCommerce's default look.
 */
.altbev .wc-block-grid__products {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
	gap: 1.25rem;
	list-style: none;
	margin: 1.5rem 0 0;
	padding: 0;
}

/* `.wc-block-grid.has-N-columns .wc-block-grid__product` sizes each card with
   `flex: 1 0 25%; max-width: 25%`, which inside a grid track collapses the
   card to a quarter of its own column. Matching that depth to release it. */
.altbev .wc-block-grid .wc-block-grid__product {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius);
	padding: 1rem;
	margin: 0;
	max-width: none;
	width: auto;
	flex: 1 1 auto;
	text-align: start;
}

/* `.woocommerce-placeholder` carries its own hairline border, so the plate
   has to name it or a product with no label image on file loses its frame. */
.altbev .wc-block-grid__product-image img,
.altbev .wc-block-grid__product-image img.woocommerce-placeholder,
.altbev ul.products li.product img.woocommerce-placeholder {
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: var(--ab-paper-2);
	border-radius: var(--ab-radius-control);
	width: 100%;
	aspect-ratio: 1;
	object-fit: cover;
}

.altbev .wc-block-grid__product-title {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.05;
	margin: 0;
}

.altbev .wc-block-grid__product-price {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	margin: 0;
}

.altbev .wc-block-grid__product-link {
	text-decoration: none;
}

.altbev .wc-block-grid__product-add-to-cart {
	margin-top: auto;
}

.altbev .wc-block-grid__product .wp-block-button__link,
.altbev .wc-block-components-product-button .wp-block-button__link {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-sm);
	font-weight: 700;
	letter-spacing: -0.01em;
	background: var(--ab-volt);
	color: var(--ab-ink);
	/* Pill and a transparent edge, like every other pressable thing here. These
	   carried the control radius and a visible hairline, which left the catalog
	   the one surface whose buttons were shaped unlike the rest of the site. */
	border: 1px solid transparent;
	border-radius: var(--ab-radius-pill);
	box-shadow: var(--ab-diecut-sm);
	padding: 0.5rem 1.1rem;
	transition: background var(--ab-press);
}

.altbev .wc-block-grid__product .wp-block-button__link:hover,
.altbev .wc-block-components-product-button .wp-block-button__link:hover {
	background: var(--ab-volt-deep);
	color: var(--ab-ink);
}

/* --- The empty cart panel ----------------------------------------------- */

.altbev .wc-block-cart__empty-cart__title {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-4xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
	text-align: start;
	margin: 0 0 0.6rem;
}

.altbev .wc-block-cart__empty-cart__title.with-empty-cart-icon::before {
	display: block;
	margin: 0 0 0.9rem;
}

.altbev .wp-block-woocommerce-empty-cart-block .wp-block-heading,
.altbev .wp-block-woocommerce-empty-cart-block .wp-block-separator {
	text-align: start;
	margin-inline: 0;
}

/* --- Block notices ------------------------------------------------------ */

.altbev .wc-block-components-notice-banner {
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: var(--ab-paper);
	color: var(--ab-ink);
	font-size: var(--ab-t-md);
}

.altbev .wc-block-components-notice-banner.is-error {
	background: var(--ab-paper-2);
	border-color: var(--ab-error);
}

.altbev .wc-block-components-validation-error {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	letter-spacing: 0.04em;
	color: var(--ab-error);
}

/* --- The empty cart ----------------------------------------------------- */

.altbev .wp-block-woocommerce-empty-cart-block {
	border: var(--ab-rule);
	background: var(--ab-label);
	box-shadow: var(--ab-diecut);
	padding: clamp(1.6rem, 4vw, 2.6rem);
}

/* --- Shop archive ------------------------------------------------------- */

.altbev .bricks-before-shop-loop {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.9rem 1.5rem;
	border-bottom: var(--ab-rule);
	padding-bottom: 0.85rem;
	margin-bottom: 1.75rem;
}

.altbev .woocommerce-result-count {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-text-dim);
	margin: 0;
}

.altbev .woocommerce-ordering select {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-text);
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.5rem 0.7rem;
	width: auto;
}

.altbev ul.products {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
	gap: 1.5rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

/* Each case is a label panel, not a floating thumbnail: bordered, seated on
   the sheet, and lifted only on approach. */
.altbev ul.products li.product {
	display: flex;
	flex-direction: column;
	gap: 0.55rem;
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius);
	padding: 1rem;
	margin: 0;
	width: auto;
	transition: transform var(--ab-press), box-shadow var(--ab-press);
}

/* The Lift Rule: a whole card rises 4px into the deeper shadow, not 3px into
   the shallower one. These are cards, so they take the card values. */
.altbev ul.products li.product:hover {
	transform: translateY(-4px);
	box-shadow: var(--ab-diecut-lift);
}

.altbev ul.products li.product img {
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: var(--ab-paper-2);
	border-radius: var(--ab-radius-control);
	margin: 0 0 0.35rem;
	width: 100%;
	aspect-ratio: 1;
	object-fit: cover;
}

.altbev ul.products li.product .woocommerce-loop-product__title {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.05;
	margin: 0;
}

.altbev ul.products li.product .price {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--ab-text);
	margin: 0;
}

.altbev ul.products li.product a {
	text-decoration: none;
}

/* Matches the order sheet's row-level add: on a catalog every card owns
   its own action, so volt stays per-row rather than per-page. */
.altbev ul.products li.product .button,
.altbev .single_add_to_cart_button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-sm);
	font-weight: 700;
	letter-spacing: -0.01em;
	background: var(--ab-volt);
	color: var(--ab-ink);
	/* Pill and a transparent edge, like every other pressable thing here. These
	   carried the control radius and a visible hairline, which left the catalog
	   the one surface whose buttons were shaped unlike the rest of the site. */
	border: 1px solid transparent;
	border-radius: var(--ab-radius-pill);
	box-shadow: var(--ab-diecut-sm);
	padding: 0.5rem 1.1rem;
	margin-top: auto;
	cursor: pointer;
	transition: background var(--ab-press);
}

.altbev ul.products li.product .button:hover,
.altbev .single_add_to_cart_button:hover {
	background: var(--ab-volt-deep);
	color: var(--ab-ink);
}

.altbev ul.products li.product .added_to_cart {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

/*
 * Gated-catalog empty state. The shop archive is empty for anyone without an
 * approved account, and WooCommerce's stock "no products matched your
 * selection" made that read as a broken store rather than a closed one. This
 * is the same empty-state shape the order sheet uses - a heading, one sentence
 * of guidance, and the action that resolves it - on a surface rather than in a
 * bare notice box.
 */
.ab-catalog-gate {
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius);
	box-shadow: var(--ab-diecut);
	padding: clamp(2rem, 5vw, 3.25rem);
	max-width: 46rem;
}

.ab-catalog-gate h2 {
	font-size: var(--ab-t-headline);
	line-height: 1.08;
	letter-spacing: -0.02em;
	margin: 0 0 0.75rem;
}

.ab-catalog-gate p {
	font-size: var(--ab-t-lg);
	line-height: 1.6;
	color: var(--ab-text-dim);
	margin: 0;
	max-width: 54ch;
}

.ab-catalog-gate__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.8rem;
	margin-top: 1.75rem;
}

/* --- Single product ----------------------------------------------------- */

/*
 * No Bricks template is assigned to the Product post type, so this page
 * renders through the parent theme's native template hierarchy instead of
 * `#brx-content` — the rule that gives every other WooCommerce page (shop,
 * cart, checkout) its horizontal gutter targets that id and never fires here.
 * Below the theme's ~1100px boxed layout the content was bleeding flush to
 * both viewport edges, so title, price, breadcrumb and the wholesale spec
 * table all touched the screen edge with zero padding on mobile.
 */
.altbev.single-product #primary {
	max-width: var(--ab-maxw);
	width: 100%;
	margin-inline: auto;
	padding-inline: var(--ab-pad);
}

.altbev .woocommerce-breadcrumb {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-text-dim);
	margin: 0 0 1.4rem;
}

.altbev .woocommerce-breadcrumb a {
	color: var(--ab-ink);
	text-decoration: none;
}

.altbev .woocommerce-breadcrumb a:hover {
	text-decoration: underline;
}

.altbev.single-product div.product {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: clamp(1.5rem, 4vw, 3rem);
	align-items: start;
}

.altbev.single-product div.product .woocommerce-product-gallery {
	width: auto;
	float: none;
	margin: 0;
	border: var(--ab-rule);
	background: var(--ab-paper-2);
	box-shadow: var(--ab-diecut);
}

.altbev.single-product div.product .woocommerce-product-gallery img {
	display: block;
	width: 100%;
}

.altbev.single-product div.product .summary {
	width: auto;
	float: none;
	margin: 0;
}

.altbev.single-product .product_title {
	font-size: var(--ab-t-headline);
	margin: 0 0 0.6rem;
}

.altbev.single-product .summary > .price {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-3xl);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	color: var(--ab-ink);
	margin: 0 0 0.4rem;
}

.altbev.single-product .stock {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	margin: 0 0 1.3rem;
}

.altbev.single-product .stock.in-stock {
	color: var(--ab-success);
}

.altbev.single-product .stock.out-of-stock {
	color: var(--ab-error);
}

.altbev.single-product form.cart {
	display: flex;
	flex-wrap: wrap;
	align-items: stretch;
	gap: 0.7rem;
	margin: 0 0 1.6rem;
}

.altbev.single-product form.cart .quantity {
	display: flex;
}

.altbev.single-product form.cart .quantity input[type="number"] {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	text-align: center;
	width: 5.5rem;
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: var(--ab-label);
	color: var(--ab-text);
	padding: 0.45rem 0.35rem;
}

.altbev.single-product .single_add_to_cart_button {
	font-size: var(--ab-t-lg);
	padding: 0.6rem 1.6rem;
	box-shadow: var(--ab-diecut-sm);
	margin-top: 0;
}

/* The spec line: the same measured-fact voice as the label panels. */
.altbev.single-product .product_meta {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
	line-height: 2;
	border-top: 1px solid var(--ab-rule-soft);
	padding-top: 1.1rem;
}

.altbev.single-product .product_meta > span {
	display: block;
}

.altbev.single-product .product_meta a {
	color: var(--ab-ink);
	text-decoration: none;
}

.altbev.single-product .woocommerce-tabs {
	grid-column: 1 / -1;
	margin-top: clamp(2rem, 5vw, 3.5rem);
}

.altbev.single-product .woocommerce-tabs ul.tabs {
	display: flex;
	flex-wrap: wrap;
	gap: 0;
	list-style: none;
	margin: 0;
	padding: 0;
	border-bottom: var(--ab-rule);
}

.altbev.single-product .woocommerce-tabs ul.tabs::before,
.altbev.single-product .woocommerce-tabs ul.tabs li::before,
.altbev.single-product .woocommerce-tabs ul.tabs li::after {
	content: none;
}

.altbev.single-product .woocommerce-tabs ul.tabs li {
	background: transparent;
	border: 0;
	border-radius: var(--ab-radius-control);
	margin: 0;
	padding: 0;
}

.altbev.single-product .woocommerce-tabs ul.tabs li a {
	display: block;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
	text-decoration: none;
	padding: 0.55rem 1rem;
}

.altbev.single-product .woocommerce-tabs ul.tabs li.active a {
	background: var(--ab-ink);
	color: var(--ab-paper);
}

.altbev.single-product .woocommerce-Tabs-panel {
	padding-top: 1.5rem;
}

.altbev #reviews .comment-form input[type="text"],
.altbev #reviews .comment-form input[type="email"],
.altbev #reviews .comment-form textarea {
	font-family: var(--ab-font);
	font-size: var(--ab-t-md);
	color: var(--ab-text);
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.7rem 0.85rem;
	width: 100%;
	max-width: 46rem;
}

.altbev #reviews .comment-form label {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-ink);
}

/* WooCommerce styles this through `#respond input#submit`, so the id has to
   be matched to reach it at all. */
.altbev #reviews #respond input#submit {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-md);
	font-weight: 700;
	letter-spacing: -0.01em;
	background: var(--ab-ink);
	color: var(--ab-paper);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.6rem 1.3rem;
	cursor: pointer;
}

.altbev #reviews #respond input#submit:hover {
	background: var(--ab-ink-2);
}

/* Same reason: `#respond .comment-reply-title` outranks the theme's heading
   rule, so this one heading was left in the body face. */
.altbev #reviews #respond .comment-reply-title {
	display: block;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-2xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
	margin: 0 0 0.8rem;
}

/* --- Order confirmation and view-order ---------------------------------- */

/* The receipt strip: the facts of the order stated as measured values, not
   as a gray table. */
.altbev ul.woocommerce-order-overview {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
	gap: 0;
	list-style: none;
	border: var(--ab-rule);
	background: var(--ab-label);
	margin: 0 0 clamp(1.8rem, 4vw, 2.6rem);
	padding: 0;
}

.altbev ul.woocommerce-order-overview li {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
	border-inline-start: 1px solid var(--ab-rule-soft);
	padding: 0.9rem 1rem;
}

.altbev ul.woocommerce-order-overview li:first-child {
	border-inline-start: 0;
}

.altbev ul.woocommerce-order-overview li strong {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
}

/* Body face: the confirmation line is a sentence, not a measured value. */
.altbev .woocommerce-order > p:first-of-type,
.altbev .woocommerce-thankyou-order-received {
	font-family: var(--ab-font);
	font-size: var(--ab-t-lg);
	color: var(--ab-text);
	border: var(--ab-rule);
	background: var(--ab-label);
	box-shadow: var(--ab-diecut-sm);
	padding: 1rem 1.1rem;
	margin: 0 0 clamp(1.8rem, 4vw, 2.6rem);
	max-width: none;
}

/* The order sheet, shared by the confirmation page and view-order. */
.altbev table.woocommerce-table--order-details,
.altbev table.woocommerce-table--order-downloads {
	width: 100%;
	border-collapse: collapse;
	border: var(--ab-rule);
	background: var(--ab-label);
	font-size: var(--ab-t-md);
	margin: 0 0 clamp(1.8rem, 4vw, 2.6rem);
}

.altbev table.woocommerce-table--order-details thead th {
	background: var(--ab-ink);
	color: var(--ab-paper);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	text-align: left;
	padding: 0.7rem 0.9rem;
	border: 0;
}

.altbev table.woocommerce-table--order-details td,
.altbev table.woocommerce-table--order-details tfoot th {
	border-top: 1px solid var(--ab-rule-soft);
	padding: 0.75rem 0.9rem;
	text-align: left;
}

.altbev table.woocommerce-table--order-details tfoot th {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-text-dim);
	background: var(--ab-paper);
}

.altbev table.woocommerce-table--order-details tfoot td {
	background: var(--ab-paper);
	font-family: var(--ab-font-spec);
	font-variant-numeric: tabular-nums;
	font-weight: 600;
}

/*
 * No emphasis on any single tfoot row. WooCommerce's order-details template
 * renders every one as a bare `<tr>` with no key on it, so "the total" is not
 * addressable in CSS - an nth-child guess lands on whichever row happens to
 * be last, which here is the payment method. The receipt strip above the
 * table already states the total at headline size, so this table stays an
 * even ledger rather than being marked up by position.
 */

.altbev table.woocommerce-table--order-details .product-name {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.1;
}

.altbev table.woocommerce-table--order-details .product-name a {
	text-decoration: none;
}

.altbev table.woocommerce-table--order-details .product-quantity {
	display: inline-block;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	background: var(--ab-ink);
	color: var(--ab-paper);
	border-radius: var(--ab-radius-control);
	padding: 0.2rem 0.45rem;
	margin-inline-start: 0.5rem;
	vertical-align: middle;
}

.altbev table.woocommerce-table--order-details .product-total {
	font-family: var(--ab-font-spec);
	font-variant-numeric: tabular-nums;
	font-weight: 600;
	white-space: nowrap;
}

.altbev .woocommerce-customer-details address {
	font-style: normal;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	line-height: 1.8;
	color: var(--ab-text);
	border: var(--ab-rule);
	background: var(--ab-paper);
	padding: 1rem 1.1rem;
	max-width: 32rem;
}

.altbev .woocommerce-column__title,
.altbev .woocommerce-order-details__title {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-2xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	margin: 0 0 0.9rem;
}

/* The h2 in this block inherits `margin: 0 0 0.8rem` from the generic
   MyAccount-content rule (zero top margin), so without this it sits flush
   against the die-cut shadow of the "Order again" button above it - the
   shadow is visual only and adds no layout space of its own to clear. */
.altbev .altbev-order-shipment {
	margin-top: 2rem;
}

/* --- What happens next: the confirmation page's way out ------------------ */

.altbev .ab-next {
	border-top: var(--ab-rule);
	padding-top: 1.6rem;
	margin-top: 2.4rem;
}

.altbev .ab-next h2 {
	font-size: var(--ab-t-2xl);
	letter-spacing: 0.02em;
	margin: 0 0 0.6rem;
}

.altbev .ab-next p {
	color: var(--ab-text-dim);
	margin: 0 0 1.3rem;
}

.altbev .ab-next__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.8rem;
}

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

@media (max-width: 980px) {
	.altbev .wc-block-components-sidebar-layout {
		grid-template-columns: minmax(0, 1fr);
	}

	.altbev .wc-block-cart__sidebar,
	.altbev .wc-block-checkout__sidebar {
		position: static;
	}

	/* The docket is the summary of what is above it, so on one column it
	   follows the pick list rather than preceding it. */
	.altbev .wc-block-cart__sidebar {
		order: 2;
	}

	.altbev.single-product div.product {
		grid-template-columns: minmax(0, 1fr);
	}
}

@media (max-width: 620px) {
	.altbev ul.products {
		grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
		gap: 1rem;
	}

	.altbev table.woocommerce-table--order-details {
		display: block;
		overflow-x: auto;
	}

	.altbev ul.woocommerce-order-overview li {
		border-inline-start: 0;
		border-top: 1px solid var(--ab-rule-soft);
	}

	.altbev ul.woocommerce-order-overview li:first-child {
		border-top: 0;
	}
}

/* ----- Sections --------------------------------------------------------- */

.altbev-landing {
	width: 100%;
}

.ab-section,
.altbev-products,
.ab-botanicals,
.ab-adapto,
.ab-subs,
.ab-routes {
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding: var(--ab-section-y) var(--ab-pad);
	width: 100%;
}

.ab-section__head,
.altbev-products__head {
	max-width: 62ch;
	margin: 0 0 2.6rem;
	padding-top: 0.5rem;
}

.ab-section__head h2,
.altbev-products__head h2 {
	font-size: var(--ab-t-headline);
	margin: 0 0 0.7rem;
}

.ab-section__head p,
.altbev-products__head p {
	color: var(--ab-text-dim);
	margin: 0;
	font-size: var(--ab-t-lg);
}

/* ----- About: editorial feature bands ---------------------------------- */

/*
 * Three alternating photo/copy bands. Three stacked centre-column sections
 * gave the page one rhythm and half its canvas to empty paper; the feature
 * layout gives each band a figure at a real size and swaps the sides so the
 * alternation reads as rhythm rather than indecision.
 *
 * The rail is positioned against this element, so it establishes the
 * containing block for it.
 */
/*
 * No horizontal padding here - `.ab-about__bandinner` carries it instead, so a
 * tinted band's bled 100vw ground and a plain band's ambient one end up flush
 * at the same 1240px content edge rather than the plain band sitting an extra
 * `--ab-pad` deeper than the tinted one either side of it.
 */
.ab-about {
	position: relative;
	max-width: var(--ab-maxw);
	margin-inline: auto;
	width: 100%;
}

.ab-about__band {
	position: relative;
	border-bottom: 1px solid var(--ab-rule-soft);
}

.ab-about__band:last-child {
	border-bottom: 0;
}

/*
 * Colour as rhythm, not decoration: the middle band sits on Paper 2, the
 * banded-zone tone DESIGN.md already reserves for the compliance strip and
 * inset panels, full-bleed the way `.ab-fieldband` bleeds inside a section
 * that is itself centred exactly like `.ab-about` is here. Three identical
 * Paper grounds in a row read as one long, undifferentiated scroll;
 * this is the smallest push that gives the page a felt cadence without
 * spending the One Field Rule's single saturated moment, which stays with
 * the hero where the rule reserves it. The grid itself lives one level in,
 * on `.ab-about__bandinner`, because a bled 100vw element cannot also be the
 * 1240px column - the same split `.ab-fieldband__inner` makes.
 */
.ab-about__band--tint {
	background: var(--ab-paper-2);
	margin-inline: calc(50% - 50vw);
	width: 100vw;
	max-width: 100vw;
}

.ab-about__bandinner {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: clamp(2rem, 5vw, 4.5rem);
	align-items: center;
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding: var(--ab-section-y) var(--ab-pad);
}

.ab-about__band--noart .ab-about__bandinner {
	grid-template-columns: minmax(0, 1fr);
}

/*
 * The mission opens with a portrait product render and a longer piece of
 * copy. Giving it the same two equal columns as the landscape photographs
 * made the image short, stranded midway down the text, and forced blank
 * gutters around the source. The opening needs a narrower product column,
 * a wider reading column, and a frame that follows the photograph's real
 * portrait ratio.
 */
#mission .ab-about__bandinner {
	grid-template-columns: minmax(16rem, 0.82fr) minmax(0, 1.18fr);
	align-items: start;
}

#mission .ab-about__art--product {
	width: min(100%, 26rem);
	justify-self: start;
	align-self: start;
	margin-top: 0.45rem;
	background: transparent;
}

/*
 * The flip is a source-order swap, not a `direction` or float trick, so the
 * reading order stays heading-then-figure in the document while the figure
 * paints on the opposite side.
 */
.ab-about__band--flip .ab-about__art {
	order: 2;
}

.ab-about__art {
	margin: 0;
	border-radius: var(--ab-radius);
	overflow: hidden;
	background: var(--ab-paper-2);
	box-shadow: var(--ab-diecut);
}

.ab-about__art img {
	display: block;
	width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	/* The lift is the system's one motion moment; on a photograph it reads as
	   the image settling rather than a hover effect looking for a job. */
	transition: transform var(--ab-press);
}

@media (prefers-reduced-motion: no-preference) {
	.ab-about__art:hover img {
		transform: scale(1.03);
	}
}

/*
 * A product render, not a photograph. It arrives on its own near-white studio
 * ground with its own shadow, so it sits whole on a white plate at the source
 * ratio rather than being cropped to fill a 4/3 photographic one - a crop here
 * would cut the can, which is the one thing the frame exists to show. The
 * hover zoom goes with it: scaling a studio render only crops it.
 */
.ab-about__art--product {
	background: var(--ab-label);
}

.ab-about__art--product img {
	aspect-ratio: 825 / 1024;
	object-fit: cover;
	transition: none;
}

.ab-about__art--product:hover img {
	transform: none;
}

/*
 * A band whose figure is a running canning line rather than a photograph. It
 * fills the same frame at the same ratio as a still, so the alternating band
 * rhythm is unaffected - the only difference is that this one moves. No hover
 * zoom: the clip is already the moving thing in the frame, and scaling it on
 * hover would be a second animation fighting the first.
 */
.ab-about__art--video video {
	display: block;
	width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
}

.ab-about__copy h2 {
	font-size: var(--ab-t-headline);
	margin: 0 0 0.9rem;
	text-wrap: balance;
}

.ab-about__body {
	color: var(--ab-text-dim);
	font-size: var(--ab-t-lg);
	max-width: 46ch;
}

.ab-about__body p {
	margin: 0 0 1rem;
}

.ab-about__body p:last-child {
	margin-bottom: 1.6rem;
}

/* Inside a half-width band the points are a ruled list, not cards - three
   cards in a 1fr column would be three nested surfaces on a surface. */
.ab-about__points {
	list-style: none;
	margin: 0;
	padding: 0;
	border-top: var(--ab-rule);
}

.ab-about__point {
	display: flex;
	align-items: baseline;
	gap: 0.75rem;
	padding: 0.7rem 0;
	border-bottom: 1px solid var(--ab-rule-soft);
	font-size: var(--ab-t-md);
	line-height: 1.5;
}

.ab-about__point::before {
	content: "";
	width: 8px;
	height: 8px;
	flex: none;
	border-radius: 999px;
	background: var(--ab-field-raspberry);
	transform: translateY(-1px);
}

/*
 * The marker rail: a position indicator for a long feature scroll, not a jump
 * menu. The whole rail is one sticky block - three individually-sticky items
 * would all pin at the same offset and stack on top of each other - and it
 * only appears once the page margin is genuinely wide enough to hold it
 * outside the 1240px measure, so it never crowds or clips the bands.
 */
.ab-about__rail {
	display: none;
}

/* 1480px is where the page margin clears the rail's own width plus its gutter
   with room to spare. Below it the rail would sit against the viewport edge -
   at 1420 it clipped outright - so it simply does not appear. */
@media (min-width: 1480px) {
	.ab-about__rail {
		display: block;
		position: absolute;
		top: 0;
		bottom: 0;
		right: calc(100% + 1rem);
		width: max-content;
	}

	.ab-about__railinner {
		position: sticky;
		top: calc(var(--ab-header-h) + 3rem);
		display: flex;
		flex-direction: column;
		gap: 0.7rem;
	}

	/*
	 * The spine turns three floating markers into one track: the read
	 * position is a point on a line, not a loose list with one item lit. It
	 * sits behind the dots (z-index below `.ab-about__railitem`'s) and stops
	 * short of the first and last dot's centre rather than running edge to
	 * edge, so it reads as connective tissue between markers, not a ruler.
	 */
	.ab-about__railinner::before {
		content: "";
		position: absolute;
		left: 3px;
		top: 0.5em;
		bottom: 0.5em;
		width: 1px;
		background: var(--ab-line-strong);
	}

	.ab-about__railitem {
		position: relative;
		z-index: 1;
		display: flex;
		align-items: center;
		gap: 0.55rem;
		font-family: var(--ab-font-spec);
		font-size: var(--ab-t-2xs);
		letter-spacing: 0.08em;
		text-transform: uppercase;
		color: var(--ab-text-dim);
		opacity: 0.45;
		transition: opacity var(--ab-press), color var(--ab-press);
	}

	/* The read position. Set by script; without it every marker simply stays
	   at rest, which is still a legible contents list. */
	.ab-about__railitem.is-active {
		opacity: 1;
		color: var(--ab-ink);
	}

	.ab-about__raildot {
		width: 7px;
		height: 7px;
		border-radius: 999px;
		background: currentColor;
		flex: none;
		transition: transform var(--ab-press);
	}

	.ab-about__railitem.is-active .ab-about__raildot {
		background: var(--ab-field-raspberry);
		transform: scale(1.3);
	}
}

/*
 * The closing production photograph. Full-bleed, edge to edge, no radius and no
 * plate: every other figure on this page sits in a rounded frame inside the
 * measure, so the one that breaks the frame is legible as the page ending
 * rather than as a fourth band. Its height is capped in vh as well as px so it
 * stays a band on a short laptop screen instead of eating the viewport.
 */
.ab-about__closing {
	margin: 0;
	margin-inline: calc(50% - 50vw);
	width: 100vw;
	max-width: 100vw;
	border-top: var(--ab-rule);
	overflow: hidden;
}

.ab-about__closing img {
	display: block;
	width: 100%;
	height: clamp(180px, 32vh, 340px);
	object-fit: cover;
	object-position: center 40%;
}

/* Section index number: only where the reader needs the count. */
.ab-section__count {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
	display: block;
	border-bottom: var(--ab-rule);
	padding-bottom: 0.5rem;
	margin-bottom: 1.4rem;
}

/* ----- Field band: color owns a whole region mid-page ------------------ */

/*
 * The band still owns its region edge to edge, but at a tenth of the weight.
 * Full-strength hop and mushroom fields put two more saturated regions in a
 * scroll that already opened on raspberry, and with a dark compliance bar
 * closing each one the page became five shouted zones with no quiet between
 * them - the reason a buyer could not get an overview of it. The tint carries
 * the category; the heading, set in the field's own color, carries the
 * identity. The hero keeps the only saturated field on the site.
 */
.ab-fieldband {
	margin-inline: calc(50% - 50vw);
	width: 100vw;
	max-width: 100vw;
	border-top: var(--ab-rule);
	border-bottom: var(--ab-rule);
	color: var(--ab-text);
	margin-bottom: clamp(3rem, 5vw, 4.5rem);
}

/* A section that opens on a field band has its seam built in: the band bleeds
   edge to edge, so the change of ground *is* the join with the section above.
   The section's own top padding sat between them as a second interval, so the
   two sections met across 192px of dead paper with the band stranded below
   it - separation by gap alone, which this system does not do. Dropping the
   padding lets the color meet the paper it is supposed to cut against. */
.altbev section:has(> .ab-fieldband:first-child) {
	padding-top: 0;
}

.ab-fieldband--hop {
	background: var(--ab-tint-hop);
	--ab-band-ink: var(--ab-field-hop); /* 4.9:1 on its own tint */
}

.ab-fieldband--mushroom {
	background: var(--ab-tint-mushroom);
	--ab-band-ink: var(--ab-field-mushroom); /* 5.6:1 on its own tint */
}

.ab-fieldband__inner {
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding: clamp(3rem, 5.5vw, 4.25rem) var(--ab-pad);
}

.altbev .ab-fieldband h2 {
	color: var(--ab-band-ink, var(--ab-ink));
	font-size: var(--ab-t-headline);
	margin: 0 0 0.8rem;
}

.ab-fieldband p {
	color: var(--ab-text);
	margin: 0;
	font-size: var(--ab-t-lg);
	max-width: 62ch;
}

/*
 * The band's one link out. It takes the band's own field ink and a rule under
 * it rather than a button: a volt pill here would sit a second call to action
 * beside the page's real one, and volt is spent on actions a buyer takes, not
 * on further reading.
 */
.ab-fieldband__more {
	margin-top: 1.1rem !important;
}

.altbev .ab-fieldband__more a {
	color: var(--ab-band-ink, var(--ab-ink));
	font-weight: 600;
	text-decoration: underline;
	text-underline-offset: 4px;
	text-decoration-thickness: 2px;
}

.altbev .ab-fieldband__more a:hover {
	text-decoration-color: var(--ab-ink);
}

/*
 * The category index sends four doors to two rooms - CBD and Delta 9 both
 * land on #botanicals, Mushrooms and Roots both land on #adaptogenics - so a
 * buyer who clicked "Functional Mushrooms" has no confirmation the jump
 * landed on the right catalog. A single warm-up of the band's own tint on
 * arrival answers that without adding a color: it is the field the buyer
 * already asked for, just breathing once to say "you're here."
 */
@media (prefers-reduced-motion: no-preference) {
	@keyframes ab-arrive {
		from { filter: brightness(1.16); }
		to { filter: brightness(1); }
	}

	#botanicals:target > .ab-fieldband,
	#adaptogenics:target > .ab-fieldband {
		animation: ab-arrive 900ms cubic-bezier(0.16, 1, 0.3, 1);
	}
}

/* ----- The lab seal ----------------------------------------------------- */

.ab-seal {
	position: absolute;
	top: 1.1rem;
	right: 1.1rem;
	z-index: 2;
	width: 82px;
	height: 82px;
	display: grid;
	place-items: center;
	color: #fff;
}

.ab-seal svg {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	animation: ab-seal-turn 28s linear infinite;
}

.ab-seal__arc {
	font-family: var(--ab-font-spec);
	font-size: 8.5px;
	font-weight: 600;
	letter-spacing: 0.06em;
	fill: currentColor;
}

.ab-seal__core {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	text-transform: uppercase;
	line-height: 1;
}

@keyframes ab-seal-turn {
	to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
	.ab-seal svg {
		animation: none;
	}
}

/* Over a photograph the seal needs its own ground to stay legible. */
.altbev-product--has-photo .ab-seal {
	background: var(--ab-ink);
	border-radius: 50%;
}

/* ----- Product labels (signature) --------------------------------------- */

.altbev-products__grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 2rem 2.2rem;
}

.altbev-product {
	background: var(--ab-label);
	border: var(--ab-rule);
	box-shadow: var(--ab-diecut);
	display: flex;
	flex-direction: column;
	transition: transform var(--ab-press), box-shadow var(--ab-press);
}

.altbev-product:hover {
	transform: translateY(-4px);
	box-shadow: var(--ab-diecut-lift);
}

/*
 * The label face: a flat flavor field carrying the lettering.
 *
 * The height is fixed rather than min-content because these are labels printed
 * side by side, and the ruled spec panels under them have to line up across a
 * row. They did not: a photographed card ran 50px taller than a field card, so
 * the two "nutrition panels" in a row started 74px apart and the pair read as
 * a layout accident rather than as two labels off the same press.
 */
.altbev-product__art {
	position: relative;
	padding: 1.6rem 1.6rem 1.3rem;
	min-height: 275px;
	display: flex;
	flex-direction: column;
	/*
	 * `space-between` distributed three children evenly, which left the
	 * descriptor stranded in the middle of the panel once it moved below the
	 * name. The name and its caption are one group at the top; the potency row
	 * is pushed to the foot by its own auto margin.
	 */
	justify-content: flex-start;
	color: #fff;
	overflow: hidden;
}

.altbev-product--raspberry .altbev-product__art { background: var(--ab-field-raspberry); }
.altbev-product--grape .altbev-product__art { background: var(--ab-field-grape); }
.altbev-product--orange .altbev-product__art { background: var(--ab-field-orange); }
.altbev-product--hop .altbev-product__art { background: var(--ab-field-hop); }

.altbev-product__artstyle {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	/*
	 * Full-strength white, and not dimmed. This was `rgba(255,255,255,0.95)`
	 * with `opacity: 0.85` under it, which is not a 0.95 label - the two
	 * multiply to an effective 0.8075, and at that alpha the caption fails WCAG
	 * AA on three of the four fields: raspberry 3.71, orange 3.73, hop 4.11.
	 * They need 0.915, 0.940 and 0.870 respectively, so no single dimmed value
	 * clears the palette with any margin worth having. Solid white clears all
	 * four (4.91 on orange, the tightest).
	 *
	 * The caption still reads quieter than the name without the dimming: it is
	 * the mono spec face at `--ab-t-2xs` in caps against the display face at
	 * `--ab-t-3xl`. Opacity was the one hierarchy device here that was not
	 * doing work the type was not already doing, and it was the one breaking
	 * contrast.
	 */
	color: #fff;
	/*
	 * The descriptor reads under the name, not over it. Above the `<h3>` it was
	 * a kicker - the one device that makes a card look templated - and the rule
	 * it carried ran across to the seal, which made the pairing look like a
	 * header band rather than like a label. Below, it is a caption on the thing
	 * it describes. `__art` is a flex column, so ordering does the work without
	 * touching the markup or the reading order in the accessibility tree.
	 */
	order: 2;
	border-bottom: 0;
	padding-bottom: 0;
	margin-top: 0.55rem;
}

.altbev .altbev-product__artname {
	order: 1;
	/* The seal is absolutely positioned 82px wide at the top right. With the
	   name now at the top of the panel it shares that row, so it reserves the
	   column rather than relying on the four current names being short enough. */
	padding-right: 5.75rem;
}


.altbev .altbev-product__artname {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-title);
	font-weight: 700;
	line-height: 1.05;
	letter-spacing: -0.005em;
	color: #fff;
	margin: 1.1rem 0 0;
	display: block;
	text-wrap: balance;
}

.altbev-product__artfoot {
	order: 3;
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: 0.8rem;
	/* Auto, so the potency row sits on the foot of the panel whatever height the
	   name wraps to, and the name plus its caption stay one group at the top. */
	margin-top: auto;
	padding-top: 1rem;
}

.altbev-product__mg {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-5xl);
	font-weight: 700;
	line-height: 0.9;
	color: #fff;
	display: flex;
	align-items: baseline;
	gap: 0.35rem;
}

.altbev-product__mg small {
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.altbev-product__net {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	text-align: right;
	/* Same lettering on the same fields as `__artstyle`, so the same rule: spec
	   type on a colour field is full-strength white. It was passing at 0.95,
	   but by 0.09 on orange - close enough to the 4.5 line that a nudge to any
	   field token would have taken it under without anything else changing. */
	color: #fff;
}

/* Real photography replaces the field; the numerals get an ink plate. */
.altbev-product--has-photo .altbev-product__art {
	padding: 0;
	background: var(--ab-paper-2);
	justify-content: flex-end;
}

.altbev-product__photo {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.altbev-product--has-photo .altbev-product__artstyle,
.altbev-product--has-photo .altbev-product__artname,
.altbev-product--has-photo .altbev-product__artfoot {
	position: relative;
	z-index: 1;
}

.altbev-product--has-photo .altbev-product__artstyle {
	align-self: flex-start;
	background: var(--ab-ink);
	border-bottom: 0;
	border-radius: var(--ab-radius-pill);
	padding: 0.4rem 0.85rem;
	margin: 1.3rem 0 0 1.3rem;
}

.altbev-product--has-photo .altbev-product__artname {
	background: var(--ab-ink);
	align-self: flex-start;
	border-radius: var(--ab-radius-control);
	padding: 0.5rem 0.85rem 0.6rem;
	margin: 0.5rem 0 0 1.3rem;
}

.altbev-product--has-photo .altbev-product__artfoot {
	background: var(--ab-ink);
	padding: 0.85rem 1.3rem;
	margin-top: 1.3rem;
	align-items: center;
}

.altbev-product__body {
	padding: 1.5rem 1.6rem 1.6rem;
	display: flex;
	flex-direction: column;
	gap: 1rem;
	flex: 1;
}

/* Two lines' worth of room whether the blurb needs it or not, so the compliance
   row and the COA link stay level across a row of cards. */
.altbev-product__body > p {
	margin: 0;
	color: var(--ab-text-dim);
	font-size: var(--ab-t-md);
	min-height: 3.2em;
}

/*
 * One row, so the ruled panel is gone with it: three hairlines around a single
 * fact is furniture. It sits on a tinted band instead, which reads as one
 * object next to the COA link rather than as the remains of a table.
 */
.altbev-product__specs {
	margin: 0;
	display: flex;
	flex-direction: column;
}

.altbev-product__specs > div {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	padding: 0.7rem 0.95rem;
	background: var(--ab-paper);
	border-radius: var(--ab-radius-control);
}

.altbev-product__specs dt {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
	margin: 0;
}

.altbev-product__specs dd {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-weight: 700;
	color: var(--ab-ink);
	margin: 0;
	font-variant-numeric: tabular-nums;
}

.altbev-product__pass {
	color: var(--ab-success) !important;
}

.altbev-product__coa {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--ab-ink) !important;
	text-decoration: none;
	border-bottom: 1px solid var(--ab-ink);
	align-self: flex-start;
	padding-bottom: 2px;
	margin-top: auto;
	transition: color var(--ab-press), border-bottom-color var(--ab-press), transform var(--ab-press);
}

/*
 * This link is the one place a skeptical buyer converts "trust us" into
 * "checked it myself" - it is the proof PRODUCT.md leans on to say AltBev is
 * not a faceless private-label supplier. It was styled like any other
 * footnote link; a claim this load-bearing gets a response that feels like
 * it was handed over, not passed by. Hover and focus share the state so
 * keyboard buyers get the same moment.
 */
.altbev-product__coa:hover,
.altbev-product__coa:focus-visible {
	color: var(--ab-field-raspberry) !important;
	border-bottom-color: var(--ab-field-raspberry);
	transform: translateY(-1px);
}

.altbev-product__coa svg {
	width: 15px;
	height: 15px;
	flex: none;
	transition: transform var(--ab-press);
}

.altbev-product__coa:hover svg,
.altbev-product__coa:focus-visible svg {
	transform: scale(1.14);
}

.altbev-products__foot {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 1.2rem 2rem;
	margin-top: 2.4rem;
	border-top: var(--ab-rule);
	padding-top: 1.6rem;
}

.altbev-products__legal {
	font-size: var(--ab-t-xs);
	letter-spacing: 0;
	color: var(--ab-text-dim);
	margin: 0;
	flex: 1 1 24ch;
	max-width: 70ch;
}

/* ----- Botanicals: the flavor index ------------------------------------ */

.ab-botanicals__media {
	display: grid;
	grid-template-columns: 3fr 2fr;
	gap: 1.4rem;
	margin-bottom: 2.6rem;
}

.ab-botanicals__fig {
	margin: 0;
	border: var(--ab-rule);
	background: var(--ab-label);
	display: flex;
	flex-direction: column;
}

.ab-botanicals__fig img,
.ab-botanicals__fig video {
	display: block;
	width: 100%;
	height: 320px;
	object-fit: cover;
	border-bottom: var(--ab-rule);
}

.ab-botanicals__fig figcaption {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-ink);
	padding: 0.6rem 0.8rem;
}

/*
 * The index's own heading. It sits close to the list it names and takes the
 * spec face rather than the display face, so it reads as the label on a
 * draught board and not as a third section heading competing with the two H2s
 * either side of it.
 */
.ab-flavors__title {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
	margin: 0 0 0.9rem;
}

/* A ruled draught list, not a card grid. */
.ab-flavors {
	border-top: var(--ab-rule);
	border-bottom: var(--ab-rule);
	display: grid;
	grid-template-columns: 1fr 1fr;
	column-gap: 2.5rem;
}

.ab-flavor {
	display: grid;
	grid-template-columns: 1fr auto;
	align-items: baseline;
	gap: 0.2rem 1rem;
	padding: 0.95rem 0;
	border-bottom: 1px solid var(--ab-rule-soft);
}

.ab-flavor h3 {
	font-size: var(--ab-t-2xl);
	margin: 0;
	line-height: 1;
}

.ab-flavor p {
	grid-column: 1 / -1;
	margin: 0;
	color: var(--ab-text-dim);
	font-size: var(--ab-t-md);
}

.ab-flavor__meta {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ab-ink);
	text-align: right;
	white-space: nowrap;
}

/* ----- Delta-9 facts ---------------------------------------------------- */

.ab-facts {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 2.5rem;
	margin-top: 3rem;
	align-items: start;
}

/* With no figure alongside it the facts run as a single ruled column rather
   than a half-width one stranded against empty paper. */
.ab-facts:not(:has(.ab-facts__infographic)) {
	grid-template-columns: minmax(0, 1fr);
	max-width: 64rem;
}

.ab-facts__copy h3 {
	font-size: var(--ab-t-subhead);
	margin: 0 0 0.8rem;
}

.ab-facts__copy > p {
	color: var(--ab-text-dim);
	margin: 0 0 1.2rem;
}

.ab-facts__list {
	list-style: none;
	margin: 0 0 1.4rem;
	padding: 0;
	border-top: var(--ab-rule);
}

.ab-facts__list li {
	display: flex;
	align-items: baseline;
	gap: 0.7rem;
	padding: 0.55rem 0;
	border-bottom: 1px solid var(--ab-rule-soft);
	font-size: var(--ab-t-md);
}

.ab-facts__list li::before {
	content: "";
	width: 8px;
	height: 8px;
	flex: none;
	background: var(--ab-field-raspberry);
	transform: translateY(-1px);
}

.ab-facts__more {
	border: var(--ab-rule);
	background: var(--ab-label);
	padding: 0.9rem 1.1rem;
}

.ab-facts__more summary {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	cursor: pointer;
	color: var(--ab-ink);
}

.ab-facts__more[open] summary {
	margin-bottom: 0.7rem;
	border-bottom: var(--ab-rule);
	padding-bottom: 0.6rem;
}

.ab-facts__more p {
	margin: 0;
	color: var(--ab-text-dim);
	font-size: var(--ab-t-md);
}

.ab-facts__infographic {
	margin: 0;
	border: var(--ab-rule);
	background: var(--ab-label);
	box-shadow: var(--ab-diecut);
}

/* The only image on the page whose height comes purely from its own intrinsic
   ratio, so it was the only one that shifted the layout when it lazy-loaded.
   Reserving the ratio holds the box before the bytes arrive. */
.ab-facts__infographic img {
	display: block;
	width: 100%;
	aspect-ratio: 1024 / 640;
	border-bottom: var(--ab-rule);
}

.ab-facts__infographic figcaption {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-text-dim);
	padding: 0.6rem 0.8rem;
}

/* ----- Adaptogenics: Brightside label panels ---------------------------- */

.ab-adapto__grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 1.6rem;
}

.ab-bs {
	border: var(--ab-rule);
	background: var(--ab-label);
	box-shadow: var(--ab-diecut);
	display: flex;
	flex-direction: column;
	transition: transform var(--ab-press), box-shadow var(--ab-press);
	/* Containing block for the stretched card link. */
	position: relative;
}

/*
 * The whole card is the hit area, but the product name is the link, so the
 * accessible name is "Brightside Calm" rather than a bare "read more". The
 * chips and blurb stay plain text and are not in the tab order.
 */
.altbev .ab-bs__link {
	color: inherit;
	text-decoration: none;
}

.altbev .ab-bs__link::after {
	content: "";
	position: absolute;
	inset: 0;
}

.altbev .ab-bs__link:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* The stretched pseudo-element has no size of its own to outline, so the
   focus ring is drawn on the card the link covers. */
.ab-bs:has(.ab-bs__link:focus-visible) {
	outline: 3px solid var(--ab-volt);
	outline-offset: 2px;
	box-shadow: var(--ab-diecut-lift), 0 0 0 5px var(--ab-ink);
}

.altbev .ab-bs__link:focus-visible {
	outline: none;
}

.ab-bs:hover {
	transform: translateY(-4px);
	box-shadow: var(--ab-diecut-lift);
}

.ab-bs__head {
	padding: 1.1rem 1.2rem;
	border-bottom: var(--ab-rule);
	color: #fff;
}

.ab-bs--peach .ab-bs__head { background: var(--ab-field-peach); }
.ab-bs--lime .ab-bs__head { background: var(--ab-field-lime); }
.ab-bs--citrus .ab-bs__head { background: var(--ab-field-citrus); }
.ab-bs--lavender .ab-bs__head { background: var(--ab-field-lavender); }

.ab-bs__head h3 {
	font-size: var(--ab-t-4xl);
	margin: 0;
	color: #fff;
	line-height: 0.95;
}

.ab-bs__flavor {
	display: block;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.95);
	margin-top: 0.45rem;
}

.ab-bs > p {
	color: var(--ab-text-dim);
	font-size: var(--ab-t-md);
	margin: 0;
	padding: 1.1rem 1.2rem 0.9rem;
	flex: 1;
}

.ab-bs__chips {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	border-top: var(--ab-rule);
}

.ab-bs__chips li {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--ab-ink);
	padding: 0.55rem 0.75rem;
	border-right: 1px solid var(--ab-rule-soft);
}

.ab-bs__chips li.ab-bs__size {
	margin-left: auto;
	border-right: 0;
	color: var(--ab-text-dim);
}

.altbev .ab-adapto__subhead {
	font-size: var(--ab-t-subhead);
	margin: 3.5rem 0 1.6rem;
	border-bottom: var(--ab-rule);
	padding-bottom: 0.7rem;
}

.ab-ingredients {
	display: grid;
	grid-template-columns: repeat(5, 1fr);
	gap: 1rem;
}

.ab-ingredient {
	margin: 0;
	border: var(--ab-rule);
	background: var(--ab-label);
	display: flex;
	flex-direction: column;
}

/*
 * The ground shows only where an image is missing, so it must not be ink.
 * `Marketing::image_url()` returns an empty string when the attachment slug
 * misses - which happens after a DB resync, since the media is re-imported by
 * slug - and the template then renders no `<img>` at all. Against an ink ground
 * that failure painted a 140px solid black tile at full width, twice, in the
 * middle of the ingredient strip, and it read as a deliberate design element
 * rather than as a missing file. On the page's own stock it reads as an empty
 * frame, which is what it is.
 */
.ab-ingredient__media {
	border-bottom: var(--ab-rule);
	background: var(--ab-paper-2);
	min-height: 140px;
}

.ab-ingredient__media img,
.ab-ingredient__media video {
	display: block;
	width: 100%;
	height: 140px;
	object-fit: cover;
}

/* Bricks styles bare `figcaption` at #9e9e9e (2.67:1 on white), which the
   ingredient names were inheriting. State the ink explicitly. */
.ab-ingredient figcaption {
	padding: 0.7rem 0.8rem 0.9rem;
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	color: var(--ab-text);
}

.ab-ingredient figcaption strong {
	color: var(--ab-ink);
}

.ab-ingredient figcaption strong {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1;
}

.ab-ingredient figcaption span {
	font-size: var(--ab-t-sm);
	color: var(--ab-text-dim);
	line-height: 1.45;
}

.ab-ingredients__extras {
	list-style: none;
	margin: 1.4rem 0 0;
	padding: 0;
	border-top: var(--ab-rule);
}

.ab-ingredients__extras li {
	padding: 0.6rem 0;
	border-bottom: 1px solid var(--ab-rule-soft);
	font-size: var(--ab-t-md);
	color: var(--ab-text-dim);
}

.ab-ingredients__extras strong {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
	margin-right: 0.5rem;
}

/* ----- Substance reference page (adaptogens, CBD and Δ9 next) ----------- */

/*
 * The ingredient-first spread. The five-across `.ab-ingredient` strip above is
 * the *index* of these substances and stays what it is; this is the detail
 * page behind it, and it exists because the client's entries run 100+ words
 * each. Dropped into that strip's tiles the copy would set at caption size in
 * a 200px column, which is how a spec page turns back into decoration.
 *
 * So each substance takes a full spread: a media plate at a real size on one
 * side, the prose at reading measure on the other, sides alternating down the
 * page. The alternation is the rhythm - six identical left-figure rows read as
 * a list, and a list is what the index already is.
 */

.ab-subs__list {
	display: flex;
	flex-direction: column;
	gap: clamp(3rem, 6vw, 5rem);
}

.ab-sub {
	display: grid;
	grid-template-columns: minmax(0, 27rem) minmax(0, 1fr);
	gap: clamp(1.6rem, 3.5vw, 3rem);
	align-items: start;
	/* Anything the browser scrolls to owes the sticky header its clearance. */
	scroll-margin-top: calc(var(--ab-header-h) + 1.25rem);
}

/* The swap is done with `direction`-free explicit column placement rather than
   `flex-direction: row-reverse`, so the DOM order (media, then copy) stays the
   reading order for a screen reader and for the stacked layout. */
.ab-sub:nth-child(even) .ab-sub__media {
	grid-column: 2;
	grid-row: 1;
}

.ab-sub:nth-child(even) .ab-sub__body {
	grid-column: 1;
	grid-row: 1;
}

/*
 * Sticky, and it earns its keep on exactly one entry: Ginseng runs three times
 * the length of the others since the client's libido copy landed, and a 4:3
 * plate pinned to the top of a 900px column leaves most of the spread as empty
 * paper. The grid area is the full row height even under `align-items: start`,
 * so the plate travels the length of the copy beside it and every shorter
 * entry is unaffected. Released at the stacked breakpoint, where a plate that
 * follows the scroll would sit on top of the copy instead of beside it.
 */
@media (min-width: 881px) {
	.ab-sub__media {
		position: sticky;
		top: calc(var(--ab-header-h) + 1.5rem);
	}
}

.ab-sub__media {
	margin: 0;
	border: var(--ab-rule);
	border-radius: 12px;
	overflow: hidden;
	background: var(--ab-paper-2);
	box-shadow: var(--ab-diecut);
	/* Same reasoning as `.ab-ingredient__media`: the ground shows through when
	   an attachment slug misses after a DB resync, so it must read as an empty
	   frame rather than as a deliberate black plate. */
	aspect-ratio: 4 / 3;
}

.ab-sub__media img,
.ab-sub__media video {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.altbev .ab-sub__body h2 {
	font-size: var(--ab-t-title);
	margin: 0 0 0.6rem;
}

/* `.altbev` prefixed, not bare: `.altbev p` carries a 68ch measure cap and
   outranks a single class, so an unprefixed rule here silently lost its
   max-width and the lede set to the full column. */
.altbev .ab-sub__lede {
	font-size: var(--ab-t-xl);
	line-height: 1.45;
	color: var(--ab-ink);
	margin: 0 0 1rem;
	max-width: 42ch;
}

/* Full ink, not `--ab-text-dim`. This is the longest continuous prose on the
   site and dimming 100 words of it to a secondary tone is how a reference page
   stops being read. Dim is for captions and support copy. */
.altbev .ab-sub__prose {
	font-size: var(--ab-t-md);
	line-height: 1.7;
	color: var(--ab-text);
	margin: 0;
	/* 60ch measures ~70 rendered characters in this face - the `ch` unit is the
	   width of "0", and lowercase Hanken Grotesk runs narrower than that. At the
	   68ch it started on, the line ran to 79 characters. */
	max-width: 60ch;
}

/*
 * The long form, and only one substance has one: a lead-in, the client's
 * labelled mechanisms, and his conclusion. It sets to the same 60ch measure as
 * the prose above it so the entry reads as one column of copy, not as a prose
 * block with a widget bolted under it.
 */
.altbev .ab-sub__more {
	margin-top: 1rem;
}

.ab-sub__points {
	margin: 1.1rem 0 0;
	padding: 0;
	max-width: 60ch;
}

/* The term is what the eye is scanning for, so it takes the display face - the
   same dt/dd treatment as the Delta 9 briefing panels, one step down in size
   because these sit inside a spread rather than owning their own panel. */
.altbev .ab-sub__points dt {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-md);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
	margin: 0;
}

.altbev .ab-sub__points dd {
	margin: 0.25rem 0 0;
	font-size: var(--ab-t-md);
	line-height: 1.7;
	color: var(--ab-text);
}

.altbev .ab-sub__points dd + dt {
	margin-top: 0.95rem;
	padding-top: 0.95rem;
	border-top: 1px solid var(--ab-line);
}

/* The conclusion is the client's own summing-up and is labelled as one, so it
   is set off on the label ground rather than running on as a fourth paragraph
   a reader cannot tell apart from the mechanisms above it. */
.ab-sub__conclusion {
	margin-top: 1.4rem;
	padding: 1rem 1.15rem 1.1rem;
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: 12px;
	max-width: 60ch;
}

.ab-sub__conclusion > .ab-spec {
	display: block;
	color: var(--ab-text-dim);
	margin-bottom: 0.45rem;
}

/*
 * No rule of its own, unlike `.ab-can__fda`: `.ab-sub__cans` draws one
 * immediately below, and two hairlines a line apart read as a mistake.
 */
.altbev .ab-sub__fda {
	margin: 1.1rem 0 0;
	font-size: var(--ab-t-2xs);
	line-height: 1.5;
	color: var(--ab-text-dim);
	max-width: 60ch;
}

/*
 * The cross-reference is this page's signature: it is what makes the entry a
 * spec rather than a glossary line. Substance -> the cans that carry it -> the
 * dose in each, and the link lands on that can's own panel further down.
 */
.ab-sub__cans {
	margin-top: 1.5rem;
	padding-top: 1.1rem;
	border-top: var(--ab-rule);
}

.ab-sub__cans > .ab-spec {
	display: block;
	color: var(--ab-text-dim);
	margin-bottom: 0.7rem;
}

.ab-sub__cans ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem;
}

.altbev .ab-sub__cans a {
	display: inline-flex;
	align-items: baseline;
	gap: 0.5rem;
	background: var(--ab-label);
	border: 1px solid var(--ab-line-strong);
	border-radius: 999px;
	padding: 0.5rem 0.95rem;
	color: var(--ab-ink);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	text-decoration: none;
	box-shadow: var(--ab-diecut-sm);
	transition: transform var(--ab-press), box-shadow var(--ab-press), background var(--ab-press);
}

.altbev .ab-sub__cans a:hover {
	transform: translateY(-2px);
	box-shadow: var(--ab-diecut);
	background: var(--ab-paper-2);
}

/* The dose is a measured value, so it wears the mono - the one thing on this
   page that is counted rather than described. */
.ab-sub__dose {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-xs);
	font-weight: 500;
	color: var(--ab-text-dim);
	white-space: nowrap;
}

/* ----- The per-can panels ----------------------------------------------- */

.ab-subs__turn {
	max-width: 62ch;
	margin: clamp(4rem, 7vw, 6rem) 0 2.4rem;
}

.altbev .ab-subs__turn h2 {
	font-size: var(--ab-t-headline);
	margin: 0 0 0.7rem;
	/* "Delta 9 THC, the / straight facts" broke after the article; balancing
	   splits it on the comma instead. */
	text-wrap: balance;
}

.altbev .ab-subs__turn p {
	color: var(--ab-text-dim);
	font-size: var(--ab-t-lg);
	margin: 0;
}

.ab-cans {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1.6rem;
	align-items: start;
}

.ab-can {
	border: var(--ab-rule);
	border-radius: 20px;
	overflow: hidden;
	background: var(--ab-label);
	box-shadow: var(--ab-diecut);
	scroll-margin-top: calc(var(--ab-header-h) + 1.25rem);
}

/*
 * Full saturation survives here because the colour names a specific thing a
 * buyer can order - the Field-Names-A-Product rule - and it is the same field
 * the Brightside card on the landing page already uses for that can, so a
 * buyer arriving from there recognises the panel as the same product.
 */
.ab-can__head {
	padding: 1.1rem 1.3rem;
	border-bottom: var(--ab-rule);
	color: #fff;
}

.ab-can--peach .ab-can__head { background: var(--ab-field-peach); }
.ab-can--lime .ab-can__head { background: var(--ab-field-lime); }
.ab-can--citrus .ab-can__head { background: var(--ab-field-citrus); }
.ab-can--lavender .ab-can__head { background: var(--ab-field-lavender); }

.altbev .ab-can__head h3 {
	font-size: var(--ab-t-4xl);
	margin: 0;
	color: #fff;
	line-height: 0.95;
}

.ab-can__flavor {
	display: block;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.95);
	margin-top: 0.45rem;
}

.ab-can__body {
	padding: 1.2rem 1.3rem 1.4rem;
}

.altbev .ab-can__summary {
	font-size: var(--ab-t-md);
	color: var(--ab-text);
	margin: 0 0 1.2rem;
}

/*
 * The panel is the pick list's vocabulary, not a new table: hairline frame, an
 * ink column-head bar, interior rules in `--ab-line`, mono tabular figures. A
 * white card inside this white card would be a panel inside a panel, so the
 * table is a ruled band flush inside the surface it already has.
 */
/*
 * No radius and no `overflow: hidden` here, deliberately. With
 * `border-collapse: collapse` the radius only ever showed because the overflow
 * was clipping the corners - and that same clip cut the first stem off the
 * caption's "P", because the caption's box starts on the table's border edge
 * and the 1px frame sits inside it. The pick list is a hairline ruled frame in
 * this system, not a rounded surface; the 20px panel around it carries the
 * roundness, and a table nested inside a rounded panel does not need its own.
 */
.ab-can__panel {
	width: 100%;
	border-collapse: collapse;
	border: var(--ab-rule);
}

.ab-can__panel caption {
	text-align: left;
	color: var(--ab-text-dim);
	padding-bottom: 0.5rem;
}

.ab-can__panel thead th {
	background: var(--ab-ink);
	color: var(--ab-paper);
	font-family: var(--ab-font);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	text-align: left;
	padding: 0.55rem 0.8rem;
	letter-spacing: 0;
	text-transform: none;
}

.ab-can__panel thead th:not(:first-child) {
	text-align: right;
}

.ab-can__panel tbody th {
	font-family: var(--ab-font);
	font-size: var(--ab-t-md);
	font-weight: 400;
	color: var(--ab-text);
	text-align: left;
	padding: 0.5rem 0.8rem;
	border-bottom: 1px solid var(--ab-line);
	letter-spacing: 0;
	text-transform: none;
}

.ab-can__panel tbody td {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-variant-numeric: tabular-nums;
	color: var(--ab-ink);
	text-align: right;
	padding: 0.5rem 0.8rem;
	border-bottom: 1px solid var(--ab-line);
	white-space: nowrap;
}

.ab-can__panel tbody tr:last-child th,
.ab-can__panel tbody tr:last-child td {
	border-bottom: 0;
}

/* The actives are the reason the can exists; the vitamin stack supports them.
   A weight step separates the two without splitting the panel in half. */
.ab-can__panel tbody .ab-can__active th {
	font-weight: 700;
	color: var(--ab-ink);
}

.ab-can__panel tbody .ab-can__active {
	background: var(--ab-paper-2);
}

/*
 * Adaptogens have no FDA daily value, so their cell in the % DV column says so
 * rather than borrowing the column for something else. It previously carried
 * the standardisation basis ("beta glucan", "powder"), which put a non-numeric
 * qualifier under a header reading "% DV" - the column stopped describing its
 * own cells. The basis moved into the ingredient name, where it belongs.
 */
.ab-can__panel tbody td.ab-can__nodv {
	font-family: var(--ab-font);
	font-size: var(--ab-t-sm);
	color: var(--ab-text-dim);
}

/*
 * A withheld % daily value, not a missing one - the client's stated figure for
 * that row is arithmetically wrong (see Marketing::brightside_specs()). Marked
 * rather than blank, because a blank cell in a spec table reads as an oversight
 * and invites someone to "fix" it by pasting the wrong number back in.
 */
.ab-can__pending {
	font-family: var(--ab-font);
	font-size: var(--ab-t-xs);
	color: var(--ab-warning);
	font-style: italic;
}

/* The reason the cell above is marked rather than filled. Warning ink, so it
   reads as the same thread as the marker, on the panel's own inset ground. */
.altbev .ab-can__pendingnote {
	font-size: var(--ab-t-sm);
	color: var(--ab-warning);
	background: var(--ab-paper-2);
	border-radius: 14px;
	padding: 0.7rem 0.85rem;
	margin: 1rem 0 0;
}

.altbev .ab-can__why {
	font-size: var(--ab-t-md);
	color: var(--ab-text-dim);
	margin: 1.1rem 0 0;
}

.altbev .ab-can__fda {
	font-size: var(--ab-t-2xs);
	color: var(--ab-text-dim);
	margin: 0.9rem 0 0;
	padding-top: 0.7rem;
	border-top: 1px solid var(--ab-line);
}

/*
 * A buyer who clicked "Focus Clarity - 25 mg beta glucan" from an ingredient
 * entry needs to know the jump landed on the right can, and four panels of the
 * same shape do not answer that on their own. Same warm-up the field bands use
 * when the category index sends someone to a section: the panel's own colour,
 * breathing once. No new colour, no new device.
 */
@media (prefers-reduced-motion: no-preference) {
	.ab-can:target {
		animation: ab-arrive 900ms cubic-bezier(0.16, 1, 0.3, 1);
	}
}

.ab-subs__close {
	margin-top: clamp(3rem, 5vw, 4rem);
	padding: clamp(1.6rem, 3vw, 2.2rem) clamp(1.4rem, 3vw, 2rem);
	background: var(--ab-paper-2);
	border: var(--ab-rule);
	border-radius: 20px;
}

.altbev .ab-subs__close p {
	margin: 0;
	font-size: var(--ab-t-xl);
	line-height: 1.5;
	color: var(--ab-ink);
	max-width: 54ch;
}

.ab-subs .ab-mandatory {
	margin-top: 2rem;
}

/* ----- Cannabinoid builds (Delta 9 / CBD page) -------------------------- */

/*
 * The buyer picks a build before a flavour, so the build is the page's first
 * object. Three peers, same shape: the landing section already ships the
 * eight-flavour card grid, and repeating it here would answer a question the
 * buyer has not asked yet.
 */
/* Stretched, not `align-items: start`. Three cards of different copy lengths
   left ragged read as three unequal things; matched heights read as three
   choices, which is what they are. */
.ab-builds {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 1.4rem;
}

.ab-build {
	border: var(--ab-rule);
	border-radius: 20px;
	overflow: hidden;
	background: var(--ab-label);
	box-shadow: var(--ab-diecut);
	display: flex;
	flex-direction: column;
}

/* Saturated because the colour names an orderable build, which is the
   Field-Names-A-Product rule, and they are the catalogue's own CBD and Delta 9
   fields so a buyer meets the same two colours here as on the category doors. */
.ab-build__head {
	padding: 1.1rem 1.25rem;
	border-bottom: var(--ab-rule);
	color: #fff;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.5rem 0.75rem;
}

.ab-build--cbd .ab-build__head { background: var(--ab-field-cbd); }
.ab-build--delta9 .ab-build__head { background: var(--ab-field-delta9); }

.altbev .ab-build__head h3 {
	font-size: var(--ab-t-2xl);
	margin: 0;
	color: #fff;
	line-height: 1.1;
}

/* The THC figure is the reason to pick one build over another, and it is a
   measured value, so it takes the mono. */
.ab-build__thc {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-weight: 500;
	color: #fff;
	white-space: nowrap;
}

.altbev .ab-build > p {
	margin: 0;
	padding: 1.1rem 1.25rem 1.3rem;
	font-size: var(--ab-t-md);
	color: var(--ab-text);
	flex: 1;
}

/* ----- The lineup table ------------------------------------------------- */

/* The pick list again, at full width: hairline frame, ink column-head bar,
   interior rules, mono on the only measured column. No radius, same reason as
   `.ab-can__panel` - collapse plus a clip is what cut the caption there. */
.ab-lineup {
	width: 100%;
	border-collapse: collapse;
	border: var(--ab-rule);
	background: var(--ab-label);
}

.ab-lineup thead th {
	background: var(--ab-ink);
	color: var(--ab-paper);
	font-family: var(--ab-font);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	text-align: left;
	padding: 0.6rem 0.9rem;
	letter-spacing: 0;
	text-transform: none;
}

.ab-lineup tbody th,
.ab-lineup tbody td {
	padding: 0.65rem 0.9rem;
	border-bottom: 1px solid var(--ab-line);
	font-size: var(--ab-t-md);
	text-align: left;
	letter-spacing: 0;
	text-transform: none;
}

.ab-lineup tbody th {
	font-family: var(--ab-font-display);
	font-weight: 700;
	color: var(--ab-ink);
	white-space: nowrap;
}

.ab-lineup tbody td {
	font-family: var(--ab-font);
	font-weight: 400;
	color: var(--ab-text);
}

.ab-lineup tbody td.ab-num {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-variant-numeric: tabular-nums;
	color: var(--ab-ink);
	white-space: nowrap;
}

.ab-lineup tbody tr:nth-child(even) th,
.ab-lineup tbody tr:nth-child(even) td {
	background: var(--ab-paper-2);
}

.ab-lineup tbody tr:last-child th,
.ab-lineup tbody tr:last-child td {
	border-bottom: 0;
}

/* ----- The editorial plate ---------------------------------------------- */

/* One image between the page's two densest regions. Without it the table and
   the three briefing panels read as a single undifferentiated block. */
.ab-subs__plate {
	margin: clamp(3rem, 5vw, 4.5rem) 0 0;
	border-radius: 20px;
	overflow: hidden;
	border: var(--ab-rule);
	box-shadow: var(--ab-diecut);
	aspect-ratio: 21 / 9;
	background: var(--ab-paper-2);
}

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

/* ----- The Delta 9 briefing --------------------------------------------- */

/*
 * Benefits, effects, and risks as three peers in one shape. A page that gives
 * the benefits a panel and puts impairment, dependence, pregnancy and drug
 * interactions in a `<details>` has editorialised a psychoactive product's
 * safety information by layout alone. Equal weight is the design decision here,
 * and it is deliberate - see Marketing::delta9_facts().
 */
/*
 * Stretched on purpose, and this is the load-bearing part of the equal-weight
 * decision. Benefits carries six entries, risks carries three; left ragged, the
 * risks panel ends visibly the smallest object on the page and the layout says
 * "this matters least" about the impairment and pregnancy warnings. Matched
 * heights cost nothing and stop the panel sizes from editorialising.
 */
.ab-briefs {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 1.4rem;
}

.ab-brief {
	border: var(--ab-rule);
	border-radius: 20px;
	overflow: hidden;
	background: var(--ab-label);
	box-shadow: var(--ab-diecut);
}

/* Ink, not a flavour field: these name information, not a product a buyer can
   order, so the Field-Names-A-Product rule keeps saturation off them. */
.altbev .ab-brief__head {
	margin: 0;
	background: var(--ab-ink);
	color: var(--ab-paper);
	font-size: var(--ab-t-xl);
	padding: 0.85rem 1.15rem;
}

.ab-brief__list {
	margin: 0;
	padding: 1.1rem 1.15rem 1.25rem;
}

.altbev .ab-brief__list dt {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-lg);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ab-ink);
	margin: 0;
}

.altbev .ab-brief__list dd {
	margin: 0.3rem 0 0;
	font-size: var(--ab-t-md);
	line-height: 1.6;
	color: var(--ab-text);
}

.altbev .ab-brief__list dd + dt {
	margin-top: 1.1rem;
	padding-top: 1.1rem;
	border-top: 1px solid var(--ab-line);
}

/* ----- Story ------------------------------------------------------------ */

.ab-story {
	background: var(--ab-ink);
	color: var(--ab-paper);
	border-top: var(--ab-rule);
	border-bottom: var(--ab-rule);
	margin-inline: calc(50% - 50vw);
	width: 100vw;
	max-width: 100vw;
}

.ab-story__inner {
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding: clamp(3.5rem, 6vw, 5rem) var(--ab-pad);
	display: grid;
	grid-template-columns: 5fr 7fr;
	gap: clamp(2rem, 4vw, 3.5rem);
	align-items: center;
}

/* The 2px paper frame around the label art was the print system's mount board.
   On a lit surface the artwork sits in its own panel instead. */
.ab-story__art {
	background: rgba(255, 255, 255, 0.06);
	border-radius: var(--ab-radius);
	overflow: hidden;
	padding: 0;
	margin: 0;
	display: block;
}

.ab-story__art img {
	display: block;
	width: 100%;
	aspect-ratio: 1024 / 825;
	object-fit: cover;
	border-bottom: 1px solid rgba(255, 255, 255, 0.14);
}

/*
 * The emblem is line art on transparency, not a photograph: it has to be shown
 * whole, because the drawing's whole point is the path from the hemp at the top
 * to the can, cask and glass at the bottom, and `cover` on a 1024/825 frame cut
 * everything below the fist. So: square frame, `contain`, and generous inner
 * padding so the mark sits in the panel rather than butting against it. No
 * bottom rule either - that rule separates a photograph from its caption, and
 * this figure has no caption to separate.
 */
.ab-story__art--emblem {
	display: grid;
	place-items: center;
	padding: clamp(1.5rem, 4vw, 2.75rem);
}

.ab-story__art--emblem img {
	aspect-ratio: 1 / 1;
	object-fit: contain;
	border-bottom: 0;
}

.ab-story__art figcaption {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-on-ink);
	padding: 0.6rem 0.75rem;
	line-height: 1.6;
}

.ab-story__copy h2 {
	color: var(--ab-paper);
	font-size: var(--ab-t-headline);
	margin: 0 0 1rem;
}

.ab-story__copy p {
	color: var(--ab-on-ink);
	margin: 0 0 1rem;
	font-size: var(--ab-t-lg);
}

.ab-story__flagship {
	display: block;
	border-top: 2px solid var(--ab-ink-2);
	padding-top: 1rem;
	margin-top: 1.4rem;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ab-on-ink);
	line-height: 1.9;
}

.ab-story__flagship strong {
	color: var(--ab-paper);
	display: block;
	font-weight: 700;
}

/* ----- Terms ledger (replaces the icon bento and the stat band) --------- */

.ab-ledger {
	border-top: var(--ab-rule);
	border-bottom: var(--ab-rule);
}

.ab-ledger__row {
	display: grid;
	grid-template-columns: minmax(0, 11rem) minmax(0, 1fr) minmax(0, 2fr);
	gap: 0.6rem 2rem;
	align-items: baseline;
	padding: 1.4rem 0;
	border-bottom: 1px solid var(--ab-rule-soft);
}

.ab-ledger__row:last-child {
	border-bottom: 0;
}

/*
 * The value column is lettering, not measurement. Five of these six rows carry
 * a phrase ("Your rate", "PO and terms", "By the case"), and setting a phrase
 * in Martian Mono is exactly what the Measurement Rule forbids - mono is for a
 * value that is measured, coded or counted. It also wrapped mid-phrase in an
 * 8rem column, so "PO and terms" broke as "PO and / terms". Big Shoulders is
 * the face that carries a phrase; the one genuinely counted value keeps mono
 * via `--numeric` below.
 */
.ab-ledger__value {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-3xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.05;
	color: var(--ab-ink);
	text-wrap: balance;
}

/* A real count, so it keeps the measured voice. */
.ab-ledger__value--numeric {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-3xl);
	font-weight: 700;
	letter-spacing: 0;
	line-height: 1;
	text-transform: none;
	font-variant-numeric: tabular-nums;
}

.ab-ledger__value small {
	display: block;
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
	margin-top: 0.45rem;
}

/*
 * The term names the category, the value answers it, so the value leads. They
 * used to be told apart by face - mono against display - and once the value
 * moved to display for the Measurement Rule, two columns of identical Big
 * Shoulders sat side by side with nothing choosing between them. The step is
 * now size and color instead of face.
 */
.ab-ledger__term {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.1;
	color: var(--ab-text-dim);
}

.ab-ledger__detail {
	margin: 0;
	color: var(--ab-text-dim);
	font-size: var(--ab-t-md);
}

/* ----- Tear-off close (replaces the dark CTA band) ---------------------- */

.ab-tearoff {
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding: 0 var(--ab-pad) var(--ab-section-y);
	width: 100%;
}

.ab-tearoff__card {
	border: var(--ab-rule);
	background: var(--ab-label);
	border-radius: var(--ab-radius);
	box-shadow: var(--ab-diecut);
	display: grid;
	grid-template-columns: 1fr auto;
	gap: 1.5rem 2.5rem;
	align-items: center;
	padding: clamp(1.6rem, 4vw, 2.6rem);
	position: relative;
}

/*
 * The perforation and the "Trade application" kicker both go. The dashed rule
 * was the printed system's tear-off gimmick, and a small tracked label above a
 * heading is the device that makes a page look assembled rather than written -
 * "Ready to pour something new?" needs no introduction from a smaller line.
 */
.ab-tearoff__label,
.ab-section__count {
	display: none;
}

.ab-tearoff h2 {
	font-size: var(--ab-t-headline);
	margin: 0 0 0.7rem;
}

.ab-tearoff p {
	margin: 0;
	color: var(--ab-text-dim);
}

.ab-tearoff__actions {
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
	align-items: stretch;
}

/* ----- Forms ------------------------------------------------------------ */

.altbev-application-form,
.altbev-rfq-form {
	max-width: 940px;
	margin-inline: auto;
	padding: clamp(2rem, 4vw, 3.25rem) var(--ab-pad) var(--ab-section-y);
	width: 100%;
}

/*
 * The build form carries a docket beside it, so it takes the page's full
 * measure rather than the single-column form width. The application form keeps
 * 940px - it is one column and a wider one would only stretch its fields.
 */
.altbev-rfq-form {
	max-width: var(--ab-maxw);
}

/*
 * A fieldset is a surface, not a stencilled carton. It takes the page's radius
 * and its soft elevation, and the legend sits inside it as a heading rather
 * than as an ink block straddling the border - that block was the printed
 * system's stencil, and against a hairline frame it now outweighs everything
 * it introduces.
 */
.altbev-form fieldset {
	border: var(--ab-rule);
	border-radius: var(--ab-radius);
	background: var(--ab-label);
	box-shadow: var(--ab-diecut-sm);
	padding: 1.9rem 1.8rem 1.6rem;
	margin: 0 0 2rem;
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 1.15rem 1.5rem;
}

.altbev-form legend {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-2xl);
	font-weight: 600;
	letter-spacing: -0.02em;
	color: var(--ab-ink);
	padding: 0;
	margin: 0 0 0.4rem;
	/*
	 * Two quirks, two declarations, and both are needed.
	 *
	 * A legend keeps "rendered legend" status while it is unfloated and
	 * statically positioned, which is what parks it in a notch cut out of the
	 * fieldset's top border - on a rounded panel it reads as a caption that has
	 * come loose. A computed float takes that status away and drops it into the
	 * padding box. Inside a grid container the float is then dropped again and
	 * the legend blockifies into a grid item, so it also has to be told to span
	 * the row, or it takes the first cell and shunts the opening field into
	 * column two.
	 */
	float: left;
	grid-column: 1 / -1;
}

.altbev-form p {
	margin: 0;
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	max-width: none;
}

.altbev-form label {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ab-ink);
}

.altbev-form .required {
	color: var(--ab-error);
}

/*
 * Field hint. Sits under the control, so the flex column puts it after the
 * input on its own line without further layout work. Sentence case and the
 * body face deliberately - the uppercase spec face above it is the label's
 * job, and repeating it would give the hint equal weight to the question.
 */
.altbev-form .altbev-field-hint {
	font-size: var(--ab-t-xs);
	line-height: 1.5;
	color: var(--ab-text-dim);
	text-transform: none;
	letter-spacing: normal;
}

.altbev-form input[type="text"],
.altbev-form input[type="email"],
.altbev-form input[type="tel"],
.altbev-form input[type="password"],
.altbev-form input[type="number"],
.altbev-form input[type="date"],
.altbev-form input[type="search"],
.altbev-form select,
.altbev-form textarea {
	font-family: var(--ab-font);
	font-size: var(--ab-t-md);
	color: var(--ab-text);
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.7rem 0.85rem;
	width: 100%;
}

.altbev-form textarea {
	min-height: 8rem;
	resize: vertical;
}

.altbev-form textarea::placeholder,
.altbev-form input::placeholder {
	color: var(--ab-text-dim);
}

.altbev-form input:focus,
.altbev-form select:focus,
.altbev-form textarea:focus {
	outline: none;
	border-color: var(--ab-ink);
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

.altbev-form input[readonly] {
	background: var(--ab-paper-2);
	color: var(--ab-text-dim);
}

/*
 * Chrome paints autofilled fields its own pale blue, which every returning
 * buyer meets on the login form - the label panel arrives already off-system
 * before they have touched anything. The background is not settable on an
 * autofilled control, so it is covered with an inset shadow the size of the
 * box, which is the only thing that reliably wins.
 */
.altbev input:-webkit-autofill,
.altbev input:-webkit-autofill:hover,
.altbev input:-webkit-autofill:focus,
.altbev input:-webkit-autofill:active {
	-webkit-text-fill-color: var(--ab-text);
	box-shadow: inset 0 0 0 100px var(--ab-label);
	caret-color: var(--ab-text);
}

.altbev-form input:-webkit-autofill:focus,
.altbev .woocommerce-MyAccount-content input:-webkit-autofill:focus,
.altbev form.woocommerce-form input:-webkit-autofill:focus {
	box-shadow: inset 0 0 0 100px var(--ab-label), 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

.altbev-form input[type="file"] {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-xs);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.5rem;
	background: var(--ab-label);
	width: 100%;
}

.altbev-form input[type="file"]::file-selector-button {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-sm);
	font-weight: 700;
	letter-spacing: -0.01em;
	background: var(--ab-ink);
	color: var(--ab-paper);
	border: 0;
	border-radius: var(--ab-radius-control);
	padding: 0.45rem 0.8rem;
	margin-right: 0.7rem;
	cursor: pointer;
}

/* The submit row: a button sizes to its label, it does not span the grid.
   Bricks sets a blanket `width: 100%` on form controls, so state it here. */
.altbev .altbev-form button[type="submit"] {
	width: auto;
	align-self: flex-start;
}

.altbev-form > p:last-child {
	grid-column: 1 / -1;
	margin-top: 0.5rem;
	align-items: flex-start;
}

/* Full-width fields inside the two-column fieldset grid. */
.altbev-form fieldset > p:has(textarea),
.altbev-form fieldset > p:has(input[type="file"]) {
	grid-column: 1 / -1;
}

/* The spam honeypot must be genuinely non-visible, not merely parked
   off-screen, so assistive tech and automation both treat it as hidden.
   It stays in the DOM and still submits, which is the point. */
.altbev-hp {
	width: 0;
	height: 0;
	overflow: hidden;
}

.altbev .altbev-hp label,
.altbev .altbev-hp input {
	width: 0;
	height: 0;
	padding: 0;
	border: 0;
	overflow: hidden;
	opacity: 0;
}

/* ----- The three buying routes ------------------------------------------ */

/*
 * Not three equal cards. Only the stock route transacts, so it takes the whole
 * first row and lays out horizontally - figure, copy, action - while the two
 * quoted routes sit beneath it as a pair and stack their parts vertically.
 * Three identical tiles read as three identical journeys, which is the one
 * thing this section exists to correct: a buyer can finish the first route
 * today and the other two end at a person.
 *
 * The minimums are set in the spec face at display size, because they are the
 * fact a buyer is scanning this section for, and the system sets every
 * measured value in DM Mono.
 */
.ab-routes__grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 1.5rem;
}

.ab-route {
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius);
	box-shadow: var(--ab-diecut-sm);
	padding: 1.9rem 1.8rem;
	display: flex;
	flex-direction: column;
	gap: 1rem;
	transition: transform var(--ab-press), box-shadow var(--ab-press);
}

.ab-route:hover,
.ab-route:focus-within {
	transform: translateY(-4px);
	box-shadow: var(--ab-diecut-lift);
}

.ab-route--primary {
	grid-column: 1 / -1;
	flex-direction: row;
	align-items: center;
	gap: 2.25rem;
	padding: 2.1rem 2rem;
}

.ab-route__figure {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	flex: 0 0 auto;
}

/*
 * The display face by default, and the spec face only when the value is an
 * actual measured quantity. "By quote" set in DM Mono at 2.1rem read as a
 * batch code rather than as a sentence, and the system reserves the mono face
 * for measured values - mg, fl oz, case counts, prices, dates - not for any
 * text that happens to sit in a figure slot. Same split the terms ledger makes.
 */
.ab-route__value {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-4xl);
	font-weight: 700;
	line-height: 1.05;
	letter-spacing: -0.02em;
	color: var(--ab-ink);
}

.ab-route__value--numeric {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-5xl);
	font-weight: 500;
	line-height: 1;
	font-variant-numeric: tabular-nums;
}

.ab-route__unit {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 500;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
}

.ab-route--primary .ab-route__figure {
	border-right: var(--ab-rule);
	padding-right: 2.25rem;
	min-width: 8.5rem;
}

.ab-route__body {
	flex: 1 1 auto;
}

.ab-route__body h3 {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-2xl);
	font-weight: 700;
	letter-spacing: -0.02em;
	margin: 0 0 0.4rem;
	color: var(--ab-ink);
}

.ab-route__body p {
	margin: 0;
	color: var(--ab-text-dim);
	font-size: var(--ab-t-md);
	max-width: 52ch;
}

.ab-route__action {
	align-self: flex-start;
	flex: 0 0 auto;
}

/* ----- The guided build (white-label and custom recipe) ------------------ */

/*
 * The form is a two-column working surface, not a column of nine identical
 * panels. Nine stacked cards of the same size and weight is the lazy structure
 * - it gives a buyer no sense of where they are and no way to see what they
 * already chose - so the steps take the working column and the docket takes the
 * rail beside them.
 *
 * The width matches the checkout's sidebar layout exactly (23rem rail, 2rem
 * gutter), because a buyer who fills this in and later checks out should be
 * reading the same piece of stationery both times.
 */
.altbev-rfq-form .altbev-build {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 23rem;
	gap: 2rem;
	align-items: start;
}

.ab-build__steps {
	min-width: 0;
}

/*
 * Every step is a fieldset, so it inherits the form surface already defined
 * above and nothing new is invented for it. The step index is the one addition:
 * a long form needs the reader to know where they are, and a mono token beside
 * the legend does that without turning into a wizard that can lose their work.
 *
 * It is not a decorative counter. Once the step has an answer the token fills
 * to ink, so the column of badges reads down the page as what is done and what
 * is left - the information a nine-step form actually owes the reader. A label
 * that only repeated its own position would be an ornament.
 */
.ab-step__index {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-xs);
	font-weight: 500;
	letter-spacing: 0.1em;
	color: var(--ab-text-dim);
	margin-right: 0.7rem;
	padding: 0.15rem 0.5rem;
	border: 1px solid var(--ab-line-strong);
	border-radius: var(--ab-radius-pill);
	vertical-align: middle;
	transition: background var(--ab-press), color var(--ab-press), border-color var(--ab-press);
}

.ab-step:has( input:checked ) .ab-step__index,
.ab-step:has( textarea:not( :placeholder-shown ) ) .ab-step__index {
	background: var(--ab-ink);
	border-color: var(--ab-ink);
	color: var(--ab-paper);
}

/*
 * The opening step is the branch that changes the two after it, so it is set
 * apart from the run of build steps rather than being the first of nine
 * identical panels. Paper 2 ground, no elevation: it reads as the question the
 * form asks before it starts, not as another card in the stack.
 */
.altbev-form fieldset.ab-step--route {
	background: var(--ab-paper-2);
	box-shadow: none;
	border-color: var(--ab-line-strong);
}

/*
 * The flavour fork. Both halves are in the document so the swap needs no
 * script; the form's own checked route decides which one is in the flow.
 * `display: none` also takes the hidden half out of the accessibility tree and
 * the tab order, which is the behaviour we want - the server drops whichever
 * half does not belong to the route.
 */
.altbev-form fieldset.ab-step--brief {
	display: none;
}

.altbev-build:has( input[ name="route" ][ value="custom_recipe" ]:checked ) fieldset.ab-step--flavors {
	display: none;
}

.altbev-build:has( input[ name="route" ][ value="custom_recipe" ]:checked ) fieldset.ab-step--brief {
	display: grid;
}

/* --- The docket: what the build looks like so far ------------------------ */

.ab-docket {
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius);
	box-shadow: var(--ab-diecut);
	overflow: hidden;
	position: sticky;
	top: calc(var(--ab-header-h) + 1.5rem);
}

/*
 * The ink bar, the same head the cart docket and the order sheet both use.
 * Scoped to `.altbev` so it outranks the base heading colour set near the top
 * of this file; unscoped it lost, and paper-on-ink came out ink-on-ink.
 */
.altbev .ab-docket__title {
	background: var(--ab-ink);
	color: var(--ab-paper);
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	margin: 0;
	padding: 0.85rem 1.15rem;
}

.ab-docket__list {
	margin: 0;
	padding: 0.5rem 1.15rem;
}

.ab-docket__row {
	display: grid;
	grid-template-columns: 5.5rem minmax(0, 1fr);
	gap: 0.75rem;
	align-items: baseline;
	padding: 0.6rem 0;
	border-bottom: 1px solid var(--ab-rule-soft);
}

.ab-docket__row:last-child {
	border-bottom: 0;
}

.ab-docket__row dt {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 500;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
}

.ab-docket__row dd {
	margin: 0;
	font-size: var(--ab-t-sm);
	line-height: 1.45;
	color: var(--ab-text-dim);
	overflow-wrap: anywhere;
}

/*
 * An answered row goes to full ink and semibold. The unanswered ones stay dim,
 * so the panel reads as a filling form rather than as a finished list where
 * every line looks equally settled.
 */
.ab-docket__row.is-answered dd {
	color: var(--ab-ink);
	font-weight: 600;
}

.ab-docket__foot {
	margin: 0;
	padding: 0.85rem 1.15rem;
	border-top: var(--ab-rule);
	background: var(--ab-paper-2);
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
}

.altbev-form .ab-step__lede,
.altbev-form .ab-step__foot {
	grid-column: 1 / -1;
	margin: 0;
	font-size: var(--ab-t-sm);
	color: var(--ab-text-dim);
	display: block;
	max-width: 72ch;
}

.altbev-form .ab-step__lede {
	margin-top: -0.3rem;
	margin-bottom: 0.4rem;
}

.altbev-form .ab-step__foot {
	margin-top: 0.9rem;
	padding-top: 0.9rem;
	border-top: var(--ab-rule);
}

.altbev-form .ab-step__foot a {
	color: var(--ab-ink);
	text-decoration: underline;
	text-underline-offset: 3px;
	margin-right: 1.25rem;
}

.altbev-form .ab-step__span {
	grid-column: 1 / -1;
}

/*
 * The choice grid. A radio on its own line is fine for two options; these
 * steps run to ten, and the answer is the substance of the page rather than a
 * detail of it, so each option gets a pressable surface. The input itself
 * stays in the box and keeps its drawn ring - hiding it would take the state
 * away from anyone not seeing the highlight.
 */
/*
 * `min(Xrem, 100%)` on every track floor, never the bare rem. A bare
 * `minmax(22rem, 1fr)` cannot shrink below its floor, so at 390px the route
 * step's two cards pushed the page 41px wider than the viewport and the whole
 * document scrolled sideways. The `min()` lets the floor collapse to the
 * container once the container is the smaller of the two.
 */
.altbev-form .ab-choices {
	grid-column: 1 / -1;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
	gap: 0.7rem;
}

.altbev-form .ab-choices--wide {
	grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
}

.altbev-form .ab-choices--dense {
	grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
}

.altbev-form .ab-choice {
	display: flex;
	align-items: flex-start;
	gap: 0.7rem;
	padding: 0.85rem 1rem;
	border: var(--ab-rule-heavy);
	border-radius: var(--ab-radius-control);
	background: var(--ab-label);
	cursor: pointer;
	font-weight: 400;
	transition: border-color var(--ab-press), background var(--ab-press), transform var(--ab-press);
}

.altbev-form .ab-choice--compact {
	padding: 0.7rem 0.85rem;
}

.altbev-form .ab-choice:hover {
	transform: translateY(-2px);
	border-color: var(--ab-ink-2);
}

.altbev-form .ab-choice input[type="radio"],
.altbev-form .ab-choice input[type="checkbox"] {
	margin: 0.15rem 0 0;
	flex: 0 0 auto;
}

/*
 * The checked surface. `:has()` carries it where supported; where it is not,
 * the drawn control is still checked and still legible, so nothing is lost
 * beyond the tint.
 */
.altbev-form .ab-choice:has(input:checked) {
	border-color: var(--ab-ink);
	background: var(--ab-paper-2);
}

.altbev-form .ab-choice:has(input:focus-visible) {
	outline: none;
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

.ab-choice__body {
	display: flex;
	flex-direction: column;
	gap: 0.2rem;
}

.ab-choice__name {
	font-size: var(--ab-t-md);
	font-weight: 600;
	color: var(--ab-ink);
	line-height: 1.35;
}

.ab-choice__name--spec {
	font-family: var(--ab-font-spec);
	letter-spacing: 0.02em;
}

.ab-choice__note {
	font-size: var(--ab-t-sm);
	color: var(--ab-text-dim);
	line-height: 1.5;
}

/* --- Artwork: the upload and the sizes it has to meet, side by side ------ */

.altbev-form .ab-artwork {
	grid-column: 1 / -1;
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 1.5rem;
	align-items: start;
	margin-top: 1.1rem;
	padding-top: 1.3rem;
	border-top: var(--ab-rule);
}

.altbev-form .ab-artwork__field {
	margin: 0;
}

/*
 * A compact panel nested inside a padded surface, so it takes the small radius
 * rather than the surface one - a panel inside a panel at the same radius
 * reads as a mistake.
 */
.ab-artwork__specs {
	background: var(--ab-paper-2);
	border-radius: var(--ab-radius-sm);
	padding: 1.1rem 1.2rem;
}

.ab-artwork__specs h4 {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
	margin: 0 0 0.7rem;
}

.ab-artwork__specs dl {
	margin: 0 0 0.8rem;
	display: flex;
	flex-direction: column;
	gap: 0.45rem;
}

.ab-artwork__specs dl > div {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 1rem;
}

.ab-artwork__specs dt {
	font-size: var(--ab-t-sm);
	color: var(--ab-text);
	font-weight: 600;
}

.ab-artwork__specs dd {
	margin: 0;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-xs);
	color: var(--ab-ink);
	font-variant-numeric: tabular-nums;
	text-align: right;
}

.ab-artwork__specs p {
	margin: 0;
	font-size: var(--ab-t-xs);
	line-height: 1.55;
	color: var(--ab-text-dim);
}

/* --- The fridge range --------------------------------------------------- */

.altbev-form .ab-fridges {
	grid-column: 1 / -1;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
	gap: 0.9rem;
	align-items: stretch;
}

.altbev-form .ab-fridge {
	display: block;
	cursor: pointer;
	font-weight: 400;
}

.ab-fridge__card {
	height: 100%;
	display: flex;
	flex-direction: column;
	gap: 0.55rem;
	padding: 0.95rem;
	border: var(--ab-rule-heavy);
	border-radius: var(--ab-radius-control);
	background: var(--ab-label);
	transition: border-color var(--ab-press), background var(--ab-press), transform var(--ab-press);
}

.altbev-form .ab-fridge:hover .ab-fridge__card {
	transform: translateY(-2px);
	border-color: var(--ab-ink-2);
}

.altbev-form .ab-fridge:has(input:checked) .ab-fridge__card {
	border-color: var(--ab-ink);
	background: var(--ab-paper-2);
}

.altbev-form .ab-fridge:has(input:focus-visible) .ab-fridge__card {
	outline: none;
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

/*
 * The control belongs beside the name, inside the card. Left as a direct child
 * of the label it rendered above the card entirely, reading as a stray radio
 * floating over a picture of a fridge rather than as the way to pick one.
 */
.ab-fridge__head {
	display: flex;
	align-items: flex-start;
	gap: 0.55rem;
}

.altbev-form .ab-fridge input[type="radio"] {
	margin: 0.15rem 0 0;
	flex: 0 0 auto;
}

.ab-fridge__plate {
	display: block;
	border-radius: var(--ab-radius-control);
	overflow: hidden;
	background: var(--ab-paper-2);
	aspect-ratio: 4 / 3;
}

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

.ab-fridge__name {
	font-size: var(--ab-t-sm);
	font-weight: 600;
	color: var(--ab-ink);
	line-height: 1.35;
}

.ab-fridge__specs {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	margin-top: auto;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	letter-spacing: 0.05em;
	color: var(--ab-text-dim);
}

/*
 * The form's `p` is a flex column, so a submit left to its own devices
 * stretches the full 940px. It keeps its own width instead.
 */
.altbev-form .ab-build__submit {
	margin-top: 0.5rem;
	align-items: flex-start;
}

/*
 * The Turnstile widget sits between the last field and the submit row, as a
 * sibling of both - it is a div, and a div inside a `p` makes the parser close
 * the paragraph early and eject everything after it.
 *
 * Cloudflare renders it at a fixed 300px in its default size, but the div it
 * injects fills whatever it is given, so the width is capped here rather than
 * left to stretch the full 940px form. The reserved height stops the submit row
 * jumping down when the widget finishes loading, which on a slow connection
 * lands right as someone is reaching for the button.
 */
.ab-turnstile {
	max-width: 300px;
	margin-block: 1.1rem 0.2rem;
	min-height: 65px;
}

/* ----- Notices ---------------------------------------------------------- */

.altbev-notice {
	border: var(--ab-rule);
	background: var(--ab-label);
	padding: 0.9rem 1.1rem 0.9rem 1.1rem;
	margin: 0 0 1.6rem;
	font-size: var(--ab-t-md);
	display: flex;
	align-items: baseline;
	gap: 0.7rem;
}

.altbev-notice::before {
	content: "";
	width: 10px;
	height: 10px;
	flex: none;
	background: var(--ab-ink);
	transform: translateY(-1px);
}

.altbev-notice--success::before { background: var(--ab-success); }
.altbev-notice--error::before { background: var(--ab-error); }
.altbev-notice--info::before { background: var(--ab-field-raspberry); }

/* ----- Company switcher -------------------------------------------------- */

.altbev-company-switcher {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.7rem;
	max-width: var(--ab-maxw);
	margin: 0 auto 1.4rem;
	padding: 0 var(--ab-pad);
	width: 100%;
}

.altbev-company-switcher label {
	font-size: var(--ab-t-xs);
	letter-spacing: 0;
	color: var(--ab-text-dim);
}

.altbev-company-switcher select {
	font-family: var(--ab-font);
	font-size: var(--ab-t-md);
	color: var(--ab-text);
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	min-height: var(--ab-control-h-sm);
	padding: var(--ab-control-py-sm) var(--ab-control-px-sm);
	width: auto;
}

.altbev-company-switcher select:focus {
	outline: none;
	border-color: var(--ab-ink);
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

/* ----- Impersonation banner ----------------------------------------------- */

/* Fixed, not placed on individual pages, so a rep acting as a company can
   never navigate somewhere that hides it (roadmap 4.1/4.2's security
   requirement). Sits above WP admin's #wpadminbar (z-index 99999) too. */
.altbev-impersonation-banner {
	position: fixed;
	inset-inline: 0;
	bottom: 0;
	z-index: 100000;
	background: var(--ab-warning);
	border-top: var(--ab-rule);
}

.altbev-impersonation-banner p {
	max-width: var(--ab-maxw);
	margin: 0 auto;
	padding: 0.8rem var(--ab-pad);
	font-size: var(--ab-t-md);
	color: var(--ab-ink);
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.5rem;
}

.altbev-impersonation-banner a {
	color: var(--ab-ink);
	text-decoration: underline;
	margin-left: auto;
	white-space: nowrap;
}

/* Leave room at the bottom of the viewport so the fixed banner never
   occludes page content or a sticky footer CTA. */
body.altbev-impersonating {
	padding-bottom: 3.5rem;
}

/* ----- Order sheet (quick order + order history) ------------------------ */

.altbev-quick-order,
.altbev-order-history {
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding: var(--ab-section-y) var(--ab-pad) 6rem;
	width: 100%;
}

.altbev-qo-filters {
	display: flex;
	flex-wrap: wrap;
	gap: 0.7rem;
	margin-bottom: 1.4rem;
	align-items: stretch;
}

.altbev-qo-filters input[type="search"],
.altbev-qo-filters select {
	font-family: var(--ab-font);
	font-size: var(--ab-t-md);
	color: var(--ab-text);
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.6rem 0.8rem;
}

/* Bricks sets a blanket `width: 100%` on form controls, which pushes each
   filter onto its own row. Size them from flex instead so the bar stays
   one line. */
.altbev-qo-filters input[type="search"] {
	flex: 1 1 18rem;
	width: auto;
	min-width: 0;
}

.altbev-qo-filters select {
	flex: 0 1 15rem;
	width: auto;
	min-width: 0;
}

.altbev-qo-filters input:focus,
.altbev-qo-filters select:focus {
	outline: none;
	border-color: var(--ab-ink);
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

.altbev .altbev-qo-filters button[type="submit"] {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-md);
	font-weight: 700;
	letter-spacing: -0.01em;
	background: var(--ab-ink);
	color: var(--ab-paper);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.6rem 1.2rem;
	cursor: pointer;
}

.altbev .altbev-qo-filters button[type="submit"]:hover {
	background: var(--ab-ink-2);
}

.altbev-qo-table {
	width: 100%;
	border-collapse: collapse;
	border: var(--ab-rule);
	background: var(--ab-label);
	font-size: var(--ab-t-md);
}

.altbev-qo-table thead th {
	background: var(--ab-ink);
	color: var(--ab-paper);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	letter-spacing: 0;
	text-align: left;
	padding: 0.7rem 0.75rem;
	white-space: nowrap;
}

.altbev-qo-table td {
	padding: 0.65rem 0.75rem;
	border-bottom: 1px solid var(--ab-rule-soft);
	vertical-align: middle;
}

.altbev-qo-table tbody tr:nth-child(even) {
	background: var(--ab-paper);
}

.altbev-qo-table tbody tr:hover {
	background: var(--ab-paper-2);
}

.altbev-qo-table tbody tr:last-child td {
	border-bottom: 0;
}

.altbev-qo-name {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.1;
}

.altbev-qo-price,
.altbev-qo-subtotal,
.altbev-qo-table td .amount,
.altbev-qo-total {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.altbev-qo-stock {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
}

.altbev-qo-stock--instock { color: var(--ab-success); }
.altbev-qo-stock--onbackorder { color: var(--ab-warning); }
.altbev-qo-stock--outofstock { color: var(--ab-error); }

.altbev-qo-table input[type="number"],
.altbev-qo-qty {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	width: 5.5rem;
	text-align: center;
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	background: var(--ab-label);
	color: var(--ab-text);
	padding: 0.45rem 0.35rem;
}

.altbev-qo-qty:focus {
	outline: none;
	border-color: var(--ab-ink);
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

.altbev .altbev-qo-add,
.altbev .altbev-reorder-btn {
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-sm);
	font-weight: 700;
	letter-spacing: -0.01em;
	background: var(--ab-volt);
	color: var(--ab-ink);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.4rem 0.9rem;
	cursor: pointer;
	transition: background var(--ab-press);
}

.altbev .altbev-qo-add:hover,
.altbev .altbev-reorder-btn:hover {
	background: var(--ab-volt-deep);
}

.altbev .altbev-qo-add:disabled,
.altbev .altbev-reorder-btn:disabled {
	background: var(--ab-paper-2);
	color: var(--ab-text-dim);
	border-color: var(--ab-rule-soft);
	cursor: not-allowed;
}

/*
 * The add is confirmed at the button, not only in the bar at the foot of the
 * window: the row being ordered can sit a screen away from it. Ink-on-volt
 * inverts to ink-on-paper with a tick, so the change is unmistakable without
 * introducing a color the system does not already own.
 *
 * Reorder owes the same debt and for a stronger reason: its own confirmation
 * box is rendered above the table, so on a long history the only feedback was
 * off-screen in both directions.
 */
.altbev .altbev-qo-add.is-added,
.altbev .altbev-qo-add.is-added:hover,
.altbev .altbev-reorder-btn.is-added,
.altbev .altbev-reorder-btn.is-added:hover {
	background: var(--ab-ink);
	color: var(--ab-volt);
}

.altbev .altbev-qo-add.is-added::before,
.altbev .altbev-reorder-btn.is-added::before {
	content: "\2713";
	margin-right: 0.4em;
}

/* Empty states: the sheet with no lines on it still has to say something.
   Specificity is raised past the plugin's `text-align: left` on table cells. */
.altbev .altbev-qo-table .altbev-qo-empty td {
	padding: clamp(2rem, 5vw, 3.25rem) 1.25rem;
	text-align: center;
}

.altbev-qo-empty strong {
	display: block;
	font-family: var(--ab-font-display);
	font-size: var(--ab-t-2xl);
	font-weight: 700;
	letter-spacing: -0.01em;
	margin-bottom: 0.5rem;
}

.altbev-qo-empty span {
	display: block;
	max-width: 52ch;
	margin: 0 auto 1.4rem;
	color: var(--ab-text-dim);
	font-size: var(--ab-t-md);
}

.altbev-qo-error {
	display: block;
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ab-error);
	margin-top: 0.3rem;
}

.altbev-qo-row.altbev-added {
	background: var(--ab-added) !important;
}

.altbev-reorder-warnings:not(:empty) {
	border: var(--ab-rule);
	background: var(--ab-label);
	padding: 0.9rem 1.1rem;
	margin-bottom: 1.4rem;
	font-size: var(--ab-t-md);
}

/*
 * Open-invoices summary (roadmap 3.3). Same recipe as the reorder-warnings
 * box above on purpose — both are "something ops needs you to notice before
 * the table" — but gets its own class because it also carries the statement
 * download link and, when over the credit limit, the error border.
 */
.altbev-ar-summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	flex-wrap: wrap;
	border: var(--ab-rule);
	background: var(--ab-label);
	padding: 0.9rem 1.1rem;
	margin-bottom: 1.4rem;
	font-size: var(--ab-t-md);
}

.altbev-ar-summary p {
	margin: 0;
}

.altbev-ar-summary--over {
	border-color: var(--ab-error);
}

.altbev-ar-overdue {
	color: var(--ab-error);
}

/*
 * The invoice total line.
 *
 * Pinned to the foot of the window, and the footer is ink too, so a plain ink
 * bar reads as part of the footer and the buyer sees no change. The volt rule
 * is the seam that keeps them separate; it is also the only place volt is
 * spent on this surface besides the Add button, tying the action to its result.
 */
.altbev-qo-cartbar {
	position: fixed;
	inset-inline: 0;
	bottom: 0;
	z-index: 60;
	display: none;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	background: var(--ab-ink);
	color: var(--ab-paper);
	border-top: 3px solid var(--ab-volt);
	box-shadow: 0 -14px 28px -18px rgba(12, 44, 57, 0.4);
	padding: 0.8rem var(--ab-pad);
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-xs);
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
}

.altbev-qo-cartbar.is-visible {
	display: flex;
}

/*
 * The bar covers the end of the document, which on the portal is the mandatory
 * compliance panel. `--ab-cartbar-h` is published by cart-bar.js once the bar
 * has rendered; spending it as footer padding keeps the page scrollable clear
 * of the bar so nothing regulated is ever trapped underneath it.
 */
body.altbev:has(.altbev-qo-cartbar.is-visible) .ab-footer {
	padding-bottom: calc(var(--ab-cartbar-h, 0px) + 1.5rem);
}

@media (prefers-reduced-motion: no-preference) {
	.altbev-qo-cartbar {
		animation: ab-cartbar-in 260ms ease-out;
	}

	.altbev-qo-cartbar.is-bumped .altbev-qo-count,
	.altbev-qo-cartbar.is-bumped .altbev-qo-total {
		animation: ab-tally-bump 900ms ease-out;
	}
}

@keyframes ab-cartbar-in {
	from {
		transform: translateY(100%);
	}
}

@keyframes ab-tally-bump {
	30% {
		transform: scale(1.18);
	}
}

.altbev-qo-count,
.altbev-qo-cartbar .altbev-qo-total {
	color: var(--ab-volt);
	font-size: var(--ab-t-sm);
	display: inline-block; /* the tally bump is a transform; inline ignores it */
}

.altbev .altbev-qo-checkout {
	padding: 0.55rem 1.1rem;
	font-size: var(--ab-t-md);
	box-shadow: none;
}

.altbev .altbev-qo-checkout:hover {
	transform: none;
}

/* ----- Account: team, locations, saved lists, standing orders ------------ */

/*
 * Four sections stack on one page (/wholesale-account/) with nothing between
 * them, so each owns its own generous top+bottom interval - the same
 * symmetric rhythm every other content section in the system uses, rather
 * than relying on the browser's near-zero default spacing.
 *
 * `.altbev-saved-lists`/`.altbev-standing-orders` also carry
 * `.altbev-quick-order` for its table styling. This rule wins on `padding`
 * by appearing later in the cascade at equal specificity, replacing that
 * shared class's asymmetric "leave room above the fixed cart bar" bottom
 * padding - neither section renders a cart bar, so that space would just be
 * dead paper.
 */
.altbev-account-team,
.altbev-account-locations,
.altbev-saved-lists,
.altbev-standing-orders {
	max-width: var(--ab-maxw);
	margin-inline: auto;
	padding: var(--ab-section-y) var(--ab-pad);
	width: 100%;
}

.altbev .altbev-account-team h2,
.altbev .altbev-account-locations h2,
.altbev .altbev-saved-lists h2,
.altbev .altbev-standing-orders h2 {
	font-size: var(--ab-t-subhead);
	margin: 0 0 1.4rem;
}

/* The roster/location table sits right under the h2; the form panel that
   follows needs its own clearance rather than crowding the last row. */
.altbev-account-team table,
.altbev-account-locations table {
	margin-bottom: 2.4rem;
}

.altbev-pending-invites {
	margin-bottom: 2.2rem;
}

.altbev .altbev-pending-invites h2 {
	font-size: var(--ab-t-xl);
	margin: 0 0 0.9rem;
}

.altbev-pending-invites .altbev-notice {
	align-items: center;
	flex-wrap: wrap;
}

.altbev-pending-invites .altbev-notice p {
	margin: 0;
	flex: 1 1 auto;
	min-width: 16rem;
}

/* Saved-lists / standing-orders inline action rows - the same recipe as the
   quick-order filter bar (`.altbev-qo-filters`), since both are one row of
   controls sitting above a table. */
.altbev-sl-save-form,
.altbev-so-create-form {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.7rem;
	margin-bottom: 1.6rem;
}

.altbev-sl-save-form .altbev-sl-name {
	flex: 1 1 18rem;
	width: auto;
	min-width: 0;
}

.altbev-so-create-form select,
.altbev-so-create-form input[type="date"] {
	width: auto;
	min-width: 0;
}

/* Same recipe as `.altbev-reorder-warnings` - "something the buyer needs to
   notice before the table" gets a stamped, bordered panel, never a bare
   floating paragraph. */
.altbev-sl-warnings:not(:empty),
.altbev-so-warnings:not(:empty) {
	border: var(--ab-rule);
	background: var(--ab-label);
	padding: 0.9rem 1.1rem;
	margin-bottom: 1.4rem;
	font-size: var(--ab-t-md);
}

.altbev-so-error {
	color: var(--ab-error);
	margin-left: 0.4rem;
	cursor: help;
}

/* ----- Quick order: CSV/paste upload -------------------------------------- */

.altbev-qo-csv {
	border: var(--ab-rule);
	background: var(--ab-label);
	padding: 0.9rem 1.1rem;
	margin-bottom: 1.6rem;
}

.altbev-qo-csv summary {
	font-size: var(--ab-t-xs);
	font-weight: 600;
	letter-spacing: 0;
	cursor: pointer;
}

.altbev-qo-csv[open] summary {
	margin-bottom: 0.9rem;
}

.altbev-qo-csv-text {
	font-family: var(--ab-font);
	font-size: var(--ab-t-md);
	color: var(--ab-text);
	background: var(--ab-label);
	border: var(--ab-rule);
	border-radius: var(--ab-radius-control);
	padding: 0.6rem 0.8rem;
}

.altbev-qo-csv-text:focus {
	outline: none;
	border-color: var(--ab-ink);
	box-shadow: 0 0 0 3px var(--ab-volt), 0 0 0 5px var(--ab-ink);
}

.altbev-qo-csv-warnings:not(:empty) {
	border: var(--ab-rule);
	background: var(--ab-paper);
	padding: 0.8rem 1rem;
	margin-top: 0.9rem;
	font-size: var(--ab-t-sm);
}

/* The per-unit sub-line is a secondary, derived figure - it stays mono (its
   parent already sets that) but drops a size and dims, the same relationship
   `--ab-text-dim` gives every other secondary value on a measured surface. */
.altbev-qo-price-unit {
	font-size: var(--ab-t-xs);
	font-weight: 500;
	color: var(--ab-text-dim);
	margin-top: 0.15rem;
}

.altbev-qo-retail {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	color: var(--ab-text-dim);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

/* ----- Responsive ------------------------------------------------------- */

@media (max-width: 1024px) {
	.ab-ingredients {
		grid-template-columns: repeat(3, 1fr);
	}

	.ab-catbars {
		grid-template-columns: repeat(2, 1fr);
	}

	/*
	 * Three-up steps through two rather than straight to one. The briefing
	 * panels hold 3 to 6 definition pairs each; at three columns on a tablet
	 * the terms start wrapping mid-phrase, and dropping to a single column
	 * this early would put the risks panel two full screens below the
	 * benefits, which is exactly the imbalance the equal-weight rule exists
	 * to prevent.
	 */
	.ab-builds,
	.ab-briefs {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 1080px) {
	/*
	 * Below this the 23rem rail stops paying for itself: the working column is
	 * squeezed to about 400px, and the choice grids inside the steps - which
	 * are what the form is - collapse to one option per row. The docket is an
	 * aid, the steps are the task, so the rail goes and the steps take the
	 * width. The step badges still carry progress at every size.
	 */
	.altbev-rfq-form .altbev-build {
		grid-template-columns: minmax(0, 1fr);
	}

	.altbev-rfq-form {
		max-width: 940px;
	}

	.ab-docket {
		display: none;
	}
}

@media (max-width: 880px) {
	/*
	 * The routes collapse to one column, and the primary route stops being a
	 * row: at this width its figure, copy and action were fighting over about
	 * 240px each and the case minimum lost.
	 */
	.ab-routes__grid {
		grid-template-columns: 1fr;
	}

	.ab-route--primary {
		flex-direction: column;
		align-items: flex-start;
		gap: 1rem;
	}

	.ab-route--primary .ab-route__figure {
		border-right: 0;
		padding-right: 0;
		min-width: 0;
	}

	/* The upload and the sizes it has to meet stack rather than halve. */
	.altbev-form .ab-artwork {
		grid-template-columns: 1fr;
	}

	.ab-header {
		flex-wrap: wrap;
		align-items: center;
	}

	.ab-burger {
		display: grid;
	}

	.ab-nav {
		display: none;
		/*
		 * The drawer breaks out of the header's side padding to paint edge to
		 * edge, and the negative margin alone does not do that here. This is a
		 * flex item, so a `100%` basis resolves against the header's *content*
		 * box - already 2 * --ab-pad narrower than the viewport - and negative
		 * margins shift the box without widening it. The drawer therefore
		 * started at the left edge but stopped --ab-pad short on the right,
		 * leaving a strip of the hero field showing down the side of an open
		 * menu. The basis has to add back what it is breaking out of.
		 */
		flex-basis: calc(100% + 2 * var(--ab-pad));
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		border-top: var(--ab-rule);
		margin-inline: calc(-1 * var(--ab-pad));
		padding-inline: var(--ab-pad);
		background: var(--ab-paper);
	}

	.ab-nav.is-open {
		display: flex;
	}

	.ab-nav a {
		padding: 0.9rem 0;
		font-size: var(--ab-t-xl);
		border: 0;
		border-bottom: 1px solid var(--ab-line);
	}

	.ab-nav a:hover {
		background: transparent;
		border-color: var(--ab-rule-soft);
	}

	.ab-nav a.ab-current {
		background: transparent;
		color: var(--ab-ink) !important;
		box-shadow: inset 5px 0 0 var(--ab-ink);
		padding-left: 0.7rem;
	}

	.ab-nav a.ab-nav-cta {
		margin: 0.9rem 0 1.1rem;
		text-align: center;
		padding: 0.8rem;
		border: var(--ab-rule);
	}

	.ab-hero__inner,
	.ab-story__inner,
	.ab-facts,
	.ab-botanicals__media,
	.altbev-products__grid,
	.ab-adapto__grid,
	.ab-sub,
	.ab-cans,
	.ab-builds,
	.ab-briefs,
	.ab-flavors,
	.ab-about__bandinner {
		grid-template-columns: 1fr;
	}

	/* Four columns of prose in ~340px is unreadable, so the lineup drops its
	   two descriptive columns into the row header as a stacked block and keeps
	   only the measured size beside it. `::before` carries the label the
	   column head no longer supplies. */
	.ab-lineup thead {
		display: none;
	}

	.ab-lineup tbody tr {
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		gap: 0.15rem 0.9rem;
		padding: 0.85rem 0.9rem;
		border-bottom: 1px solid var(--ab-line);
	}

	.ab-lineup tbody th,
	.ab-lineup tbody td {
		border-bottom: 0;
		padding: 0;
		white-space: normal;
	}

	/*
	 * The stripe moves from the cells to the row. Once the row is a grid its
	 * cells no longer span it, so a per-cell background painted three
	 * disconnected blocks with white gutters between them - it read as broken
	 * rendering rather than as banding.
	 */
	.ab-lineup tbody tr:nth-child(even) {
		background: var(--ab-paper-2);
	}

	.ab-lineup tbody tr:nth-child(even) th,
	.ab-lineup tbody tr:nth-child(even) td {
		background: transparent;
	}

	.ab-lineup tbody th {
		grid-column: 1;
		font-size: var(--ab-t-lg);
	}

	.ab-lineup tbody td.ab-num {
		grid-column: 2;
		grid-row: 1;
		text-align: right;
		align-self: baseline;
	}

	.ab-lineup tbody td:not(.ab-num) {
		grid-column: 1;
		font-size: var(--ab-t-sm);
		color: var(--ab-text-dim);
	}

	.ab-subs__plate {
		aspect-ratio: 16 / 9;
	}

	/*
	 * Stacked, the alternation has nothing left to alternate against, so the
	 * explicit placement is dropped and every spread leads with its figure -
	 * the DOM order. Left in place, the even rows would put the copy in row 1
	 * and the media in row 2 on some spreads and not others, which reads as a
	 * bug rather than as rhythm.
	 */
	.ab-sub:nth-child(even) .ab-sub__media,
	.ab-sub:nth-child(even) .ab-sub__body {
		grid-column: 1;
		grid-row: auto;
	}

	/* The plate no longer shares the row with the copy, so 4:3 at full width
	   takes most of a phone viewport before a word is read. */
	.ab-sub__media {
		aspect-ratio: 16 / 9;
	}

	#mission .ab-about__bandinner {
		grid-template-columns: 1fr;
	}

	#mission .ab-about__art--product {
		width: min(100%, 25rem);
		justify-self: center;
		margin-top: 0;
	}

	/* Stacked, the figure leads its band rather than trailing the copy it
	   belongs to - the flip only means anything while there are two columns. */
	.ab-about__band--flip .ab-about__art {
		order: 0;
	}

	.ab-hero__inner {
		padding-inline-end: var(--ab-pad);
		padding-bottom: 2rem;
	}

	/* Stacked, the plate is no longer the viewport's own right edge, so all
	   four corners round like an ordinary surface, and it drops back into
	   the document flow below the copy instead of overhanging above it -
	   stacked, that overhang would pull it up into the CTAs. */
	.ab-hero__plate {
		border-radius: var(--ab-radius);
		margin: 1.5rem 0 0;
	}

	.ab-story__art {
		max-width: 320px;
	}

	.ab-tearoff__card {
		grid-template-columns: 1fr;
	}

	.ab-ledger__row {
		grid-template-columns: 1fr;
		gap: 0.45rem;
	}

	.ab-ledger__value small {
		display: inline;
		margin-left: 0.6rem;
	}

	.altbev-form fieldset {
		grid-template-columns: 1fr;
	}

	/* Order sheet becomes a stack of order lines on narrow screens. */
	.altbev-qo-table,
	.altbev-qo-table tbody,
	.altbev-qo-table tr,
	.altbev-qo-table td {
		display: block;
		width: 100%;
	}

	.altbev-qo-table thead {
		display: none;
	}

	.altbev-qo-table tr {
		border-bottom: var(--ab-rule);
		padding: 0.6rem 0;
	}

	.altbev-qo-table tbody tr:last-child {
		border-bottom: 0;
	}

	.altbev-qo-table td {
		border-bottom: 0;
		padding: 0.3rem 0.75rem;
		display: flex;
		justify-content: space-between;
		align-items: center;
		gap: 1rem;
	}

	.altbev-qo-table td::before {
		content: attr(data-label);
		font-size: var(--ab-t-sm);
		font-weight: 600;
		letter-spacing: 0;
		color: var(--ab-text-dim);
	}

	.altbev-qo-table td.altbev-qo-name {
		justify-content: flex-start;
		padding-top: 0.6rem;
	}

	/*
	 * The empty-state cell (no label/value pair, just a heading, a sentence and
	 * a button) isn't a data row, so the label/value flex split above splits its
	 * heading to the left and its sentence + button to the right instead of
	 * stacking them centered.
	 */
	.altbev-qo-table .altbev-qo-empty td {
		display: block;
	}

	.altbev-qo-table .altbev-qo-empty td::before {
		content: none;
	}

	.altbev-qo-table td.altbev-qo-name::before {
		content: none;
	}
}

@media (max-width: 620px) {
	body.altbev {
		font-size: 16px;
	}

	.ab-ingredients {
		grid-template-columns: repeat(2, 1fr);
	}

	.ab-catbars {
		grid-template-columns: 1fr;
	}

	.ab-hero__plate img {
		min-height: 200px;
	}

	.ab-mandatory__list li:not(:first-child) {
		margin-inline-start: 1rem;
	}

	.altbev-qo-cartbar {
		flex-wrap: wrap;
		gap: 0.6rem;
	}
}

/* ----- Control metrics (authoritative) ---------------------------------- */

/*
 * Every text control on the portal, at one of two sizes and no others.
 *
 * This block exists because control geometry could not be held at the call
 * site. Three things were fighting it:
 *
 * 1. Bricks' `frontend-layer.min.css` sets `line-height: 40px` on
 *    `.input, input:not([type=submit]), select, textarea`. A 40px line box
 *    inside our 0.7rem padding produced 66px-tall boxes across the whole site
 *    - the single largest cause of the "weird dimensions". It is the third
 *    Bricks trap in this project, after the 10px root and shrink-to-fit
 *    containers, and like those it is silent: nothing looks broken, everything
 *    just sits wrong.
 * 2. WooCommerce Blocks reserves `padding-top: 24px` on its checkout inputs
 *    for a floating label this system moved back above the field, so those
 *    boxes were 57px with the text sitting low in them.
 * 3. Bricks also forces `border-width: 1px` on controls, which surfaced on any
 *    field our per-component rules had not named individually - the checkout's
 *    "add apartment, suite" input among them.
 *
 * Written last in the file and prefixed with `body.altbev` so it outranks both
 * the layered Bricks defaults and WooCommerce's own component styles without
 * `!important`. Adding a new form anywhere in the portal now inherits correct
 * geometry for free; the only thing a component still chooses is whether a
 * control is standard or compact.
 */
/*
 * The `:not()` takes a selector list rather than a chain of six, and
 * `.select2-selection` is handled separately below. Both are deliberate: a
 * chain of six `:not([type=...])` scores six classes, and a `.select2-selection`
 * inside the `:is()` raises the whole compound to that class's weight. Either
 * one makes this rule outrank the compact override that follows it, which is
 * exactly what happened first time round - the quantity cell silently took the
 * standard height. Keep this at two classes so the compact block can win on
 * order.
 */
body.altbev :is(input, select, textarea):not([type="checkbox"], [type="radio"], [type="submit"], [type="button"], [type="file"], [type="range"]) {
	box-sizing: border-box;
	min-height: var(--ab-control-h);
	padding: var(--ab-control-py) var(--ab-control-px);
	font-size: var(--ab-t-md);
	line-height: var(--ab-control-lh);
	border-width: 2px;
	border-radius: var(--ab-radius-control);
}

body.altbev .select2-selection {
	box-sizing: border-box;
	min-height: var(--ab-control-h);
	padding: var(--ab-control-py) var(--ab-control-px);
	font-size: var(--ab-t-md);
	line-height: var(--ab-control-lh);
	border-width: 2px;
	border-radius: var(--ab-radius-control);
}

/* A textarea is sized by its rows, not by the control height. */
body.altbev textarea {
	min-height: 8rem;
	line-height: 1.6;
}

/* The spam honeypots are off-screen in a 0x0 wrapper and are not controls a
   buyer ever sees. Nothing here affects layout, but giving them a control's
   geometry is meaningless and it makes them noise in any audit of the forms. */
body.altbev .altbev-hp input {
	min-height: 0;
	padding: 0;
}

/*
 * The compact size, for controls that sit inside a dense row rather than a
 * form: the order sheet's quantity cell and the docket's B2B fields, both of
 * which are read as part of a table line and would break its rhythm at the
 * full height.
 */
body.altbev input.altbev-qo-qty,
body.altbev input#altbev-po-number,
body.altbev input#altbev-delivery-date,
body.altbev select#altbev-ship-to,
body.altbev input.wc-block-components-quantity-selector__input {
	min-height: var(--ab-control-h-sm);
	padding: var(--ab-control-py-sm) var(--ab-control-px-sm);
	font-size: var(--ab-t-sm);
}

/* The quantity stepper sits between two buttons and owns no border of its own. */
body.altbev input.wc-block-components-quantity-selector__input {
	border-width: 0;
	min-height: 2rem;
	text-align: center;
	font-family: var(--ab-font-spec);
	font-variant-numeric: tabular-nums;
}

/*
 * WooCommerce Blocks reserves the floating label's space with
 * `padding: 24px 9px 8px`, applied only once a field goes `.is-active` or gets
 * autofilled - which is why the checkout looked correct while empty and shifted
 * its text down the moment a buyer typed. This system moved the label out of
 * the box, so that reservation is dead space.
 *
 * The branch that actually wins is
 * `.wc-block-components-form .wc-block-components-text-input.is-active input[type="text"]`,
 * scoring (0,4,1) - the attribute selector counts as a class, so a `body.altbev`
 * prefix alone only reached (0,3,2) and still lost. The trailing
 * `:not([type="hidden"])` buys the fourth class without enumerating every input
 * type, landing at (0,4,2). Found with `CSS.getMatchedStylesForNode` over CDP,
 * which is worth reaching for again: none of these rules are visible to a
 * `document.styleSheets` walk, so guessing at the source wastes more time than
 * asking the engine.
 */
body.altbev .wc-block-components-text-input.is-active input:not([type="hidden"]),
body.altbev .wc-block-components-text-input input:-webkit-autofill:not([type="hidden"]),
body.altbev .wc-block-components-text-input input:focus:not([type="hidden"]) {
	padding: var(--ab-control-py) var(--ab-control-px);
}

/*
 * A file input is a control plus a button, so it is taller than a text field by
 * nature. It gets the standard height as a floor and its own padding, rather
 * than being left at whatever the browser chose.
 */
body.altbev input[type="file"] {
	box-sizing: border-box;
	min-height: var(--ab-control-h);
	padding: 0.5rem;
	border-width: 2px;
	border-radius: var(--ab-radius-control);
	line-height: var(--ab-control-lh);
}

/*
 * Select2 computes its own height from `--bricks-woo-input-height` and pins a
 * 40px line box on the rendered value. Both are neutralised so the country and
 * state controls match the inputs they sit between.
 */
body.altbev .select2-selection--single {
	height: auto;
	display: flex;
	align-items: center;
}

body.altbev .select2-selection__rendered {
	line-height: var(--ab-control-lh);
	padding: 0;
}

/* ----- Single product: the wholesale spec ------------------------------- */

/*
 * The same ruled nutrition-panel construction the product labels use, so a
 * buyer arriving from the order sheet reads the case, the potency and the stock
 * in the format they already know.
 */
.altbev .ab-product-spec {
	margin: 1.4rem 0;
	border-top: var(--ab-rule);
	display: flex;
	flex-direction: column;
	max-width: 34rem;
}

.altbev .ab-product-spec > div {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	padding: 0.55rem 0;
	border-bottom: 1px solid var(--ab-rule-soft);
}

.altbev .ab-product-spec dt {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
	margin: 0;
}

.altbev .ab-product-spec dd {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-sm);
	font-weight: 700;
	color: var(--ab-ink);
	margin: 0;
	text-align: right;
	font-variant-numeric: tabular-nums;
}

/* Stock is a mono word in status ink, never a colored dot. */
.altbev .ab-product-spec__stock.is-instock {
	color: var(--ab-success);
}

.altbev .ab-product-spec__stock.is-outofstock {
	color: var(--ab-error);
}

.altbev .ab-product-spec__stock.is-onbackorder {
	color: var(--ab-warning);
}

/* The rider that stops a case price reading as a unit price. */
.altbev .ab-price-unit {
	font-family: var(--ab-font-spec);
	font-size: var(--ab-t-2xs);
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ab-text-dim);
	margin-left: 0.5rem;
	white-space: nowrap;
}

/* ----- Order sheet: the product name is the route to its page ----------- */

.altbev .altbev-qo-name a {
	color: var(--ab-ink) !important;
	text-decoration: none;
	border-bottom: 2px solid transparent;
	transition: border-color var(--ab-press);
}

.altbev .altbev-qo-name a:hover,
.altbev .altbev-qo-name a:focus-visible {
	border-bottom-color: var(--ab-field-raspberry);
}
