/* ============================================================================
   main.css — async-loaded. ONLY interaction states + content typography +
   deeper component styles that never appear in the initial viewport. Anything
   that can render above the fold lives in critical.css (so the async swap
   causes zero layout shift). Product/shop/cart component styles land here in
   Week 2.
   ============================================================================ */

/* ---- Focus visibility (a11y; only after interaction, never a CLS source) ---- */
:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

/* ---- Button extra variants ---- */
.btn--block { width: 100%; }
/* "Dark" button on a dark site is really the secondary/quiet button. It used to
   be background:var(--ink) — which now resolves to parchment, giving a washed
   beige fill under near-white text. Raised panel + brass edge instead. */
.btn--dark { background: var(--void-800); color: var(--glow-50); border-color: color-mix(in oklab, var(--brass-600) 50%, transparent); }
.btn--dark:hover { background: var(--void-700); border-color: color-mix(in oklab, var(--brass-400) 70%, transparent); }

/* ---- Mobile nav panel (revealed only on tap via Alpine .is-open) ---- */
@media (max-width: 767px) {
	.site-nav {
		position: absolute; left: 0; right: 0; top: var(--header-h);
		background: var(--surface-dark); border-top: 1px solid rgba(255,255,255,.08);
		padding: var(--sp-4); box-shadow: 0 12px 24px rgba(0,0,0,.35);
		max-height: calc(100vh - var(--header-h)); overflow-y: auto; overscroll-behavior: contain;
	}
	.site-nav.is-open { display: block; }
	.site-nav__list { flex-direction: column; align-items: stretch; gap: 0; }
	.site-nav__list li { border-bottom: 1px solid rgba(255,255,255,.08); }
	.site-nav__list li:last-child { border-bottom: 0; }
	.site-nav__list a { display: block; padding: var(--sp-3) 0; border-bottom: 0; }
	.site-nav__list a:hover, .site-nav__list .current-menu-item > a { border-bottom: 0; }
}

/* ---- Shop interactions (entertaining, motion-safe) ---- */
.chip { transition: background-color .15s ease, border-color .15s ease, color .15s ease; }
.chip:hover { border-color: var(--ink); }
.product-card__media { box-shadow: 0 1px 2px rgba(0,0,0,.06); }
.product-card__add { width: 100%; }

@media (prefers-reduced-motion: no-preference) {
	.product-card__img { transition: transform .45s cubic-bezier(.2,.7,.2,1); will-change: transform; }
	.product-card:hover .product-card__media .product-card__img { transform: scale(1.06); }
	.product-card__media::after {
		content: ""; position: absolute; inset: 0; z-index: 1;
		background: linear-gradient(to top, rgba(16,15,12,.28), transparent 45%);
		opacity: 0; transition: opacity .3s ease;
	}
	.product-card:hover .product-card__media::after { opacity: 1; }
}

.shop__noresults { padding: var(--sp-8) 0; text-align: center; color: var(--muted); }

.made-to-order, .in-stock { font-size: var(--fs-300); color: var(--muted); margin: 0; }
.made-to-order strong { color: var(--ink); }
/* "In stock" earns the accent; made-to-order is the neutral default state. */
.in-stock strong { color: var(--accent); }

/* ---- Add-to-cart toast ---- */
.cart-toast {
	position: fixed; left: 50%; bottom: var(--sp-5); transform: translateX(-50%); z-index: 100;
	/* Both background and colour resolved to parchment after the remap, which
	   made the confirmation text invisible on the one element whose entire job
	   is confirming the add-to-cart worked. Raised panel, brass edge. */
	background: var(--void-700); color: var(--glow-50); padding: var(--sp-3) var(--sp-5);
	border: 1px solid color-mix(in oklab, var(--brass-400) 55%, transparent);
	border-radius: var(--radius); box-shadow: 0 12px 30px rgba(0,0,0,.5);
	font-weight: 600; font-size: var(--fs-300); max-width: calc(100% - 2rem);
}
.cart-toast.is-error { background: #8a2b1f; }

/* ---- Default page/post content (index.php — long, below the fold) ---- */
.entry { padding-block: var(--sp-8); }
.entry-title { font-size: var(--fs-800); }
.entry-content > *, .service__body > * { max-width: 42rem; }
.entry-content h2, .service__body h2 { font-size: var(--fs-600); margin-top: var(--sp-7); }
.entry-content h3, .service__body h3 { font-size: var(--fs-500); margin-top: var(--sp-6); }
.entry-content ul, .entry-content ol, .service__body ul, .service__body ol { padding-left: var(--sp-5); }
.entry-content li, .service__body li { margin-bottom: var(--sp-2); }

/* ---- Mini-cart drawer (hidden until opened; no CLS) ---- */
.minicart {
	position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
	width: min(360px, calc(100vw - 2rem));
	/* Was #fff. A white panel would now sit under parchment text — and would
	   flare against the void canvas every time the cart opens. */
	background: var(--void-850); color: var(--glow-100);
	border: 1px solid color-mix(in oklab, var(--brass-600) 45%, transparent);
	border-radius: var(--radius); box-shadow: 0 18px 50px rgba(0,0,0,.55); padding: var(--sp-4);
}
.minicart__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--sp-3); }
.minicart__close { background: none; border: 0; font-size: 1.5rem; line-height: 1; cursor: pointer; color: var(--muted); }
.minicart__empty { color: var(--muted); margin: var(--sp-3) 0; }
.minicart__items { list-style: none; margin: 0; padding: 0; max-height: 50vh; overflow: auto; display: grid; gap: var(--sp-3); }
.minicart__item { display: grid; grid-template-columns: 52px 1fr auto; gap: var(--sp-3); align-items: center; }
.minicart__img { border-radius: var(--radius-sm); object-fit: cover; background: var(--surface); }
.minicart__detail { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.minicart__name { font-weight: 600; font-size: var(--fs-300); }
.minicart__qty { color: var(--muted); font-size: var(--fs-300); }
.minicart__remove { background: none; border: 0; color: var(--muted); font-size: 1.15rem; line-height: 1; cursor: pointer; }
.minicart__remove:hover { color: #f0796a; } /* light enough to read on the dark panel */
.minicart__foot { border-top: 1px solid var(--border); margin-top: var(--sp-3); padding-top: var(--sp-3); display: grid; gap: var(--sp-3); }
.minicart__subtotal { display: flex; justify-content: space-between; font-size: var(--fs-400); }
@media (max-width: 767px) {
	.minicart { position: fixed; top: auto; bottom: 0; left: 0; right: 0; width: auto; max-height: 80vh; overflow: auto; border-radius: var(--radius) var(--radius) 0 0; }
}

/* ---- WooCommerce cart/checkout theming (layered over WC's base CSS) ---- */

/* Form controls.
   These rules previously set border, size and font but never background or
   colour, so every checkout text field fell through to the user-agent default:
   pure white with black text, sitting on the near-black order panel. Checkout is
   the most conversion-critical page on the site and it was the only place the
   dark theme broke. Tokens match the search field and the review form, so all
   inputs on the site now look like one system.

   `<select>` needs `appearance: none` as well: a native select paints its own
   background regardless of a transparent background-color, which is why the
   State and Country dropdowns rendered white while computing to transparent.
   Dropping the native appearance means supplying the arrow, hence the inline
   SVG below (a data URI, so it costs no request). */
.woocommerce form .form-row input.input-text,
.woocommerce form .form-row textarea,
.woocommerce .select2-container,
.woocommerce form .form-row select,
.woocommerce-cart .quantity input {
	border: 1px solid var(--border) !important; border-radius: var(--radius-sm); font: inherit;
}
/* Drive WooCommerce's own form tokens rather than out-specifying its rules.
   woocommerce.css styles fields as `background: var(--wc-form-color-background,#fff)`,
   and it is enqueued AFTER main.css, so an equal-specificity override of ours
   loses on source order every time (the same trap that made the review submit
   button render as a native grey widget). Setting the variables wins everywhere
   at once, including the selectors we would otherwise have missed. */
.woocommerce {
	--wc-form-color-background: var(--void-850);
	--wc-form-color-text: var(--glow-100);
	--wc-form-border-color: var(--border);
	--wc-form-border-radius: var(--radius-sm);
}
.woocommerce form .form-row input.input-text,
.woocommerce form .form-row select,
.woocommerce form .form-row textarea,
.woocommerce-cart .quantity input,
.woocommerce-page form .checkout_coupon input.input-text,
.woocommerce .coupon input.input-text {
	background: var(--void-850); color: var(--glow-100);
}

/* The cart's coupon field sits outside a .form-row, so it missed the width rule
   below and kept WooCommerce's default ~80px box, which clipped its own
   placeholder to "Coupon co". Sized to fit the label it is asking for. */
.woocommerce .coupon input.input-text {
	width: auto; min-width: 12rem; padding: .6rem .7rem; min-height: 44px;
	border: 1px solid var(--border) !important; border-radius: var(--radius-sm); font: inherit;
}
.woocommerce form .form-row input.input-text::placeholder,
.woocommerce form .form-row textarea::placeholder,
.woocommerce-page form .checkout_coupon input.input-text::placeholder {
	color: var(--mist-600); opacity: 1; /* Firefox dims placeholders by default. */
}
.woocommerce form .form-row input.input-text,
.woocommerce form .form-row select,
.woocommerce form .form-row textarea { width: 100%; padding: .6rem .7rem; min-height: 44px; }

.woocommerce form .form-row select {
	-webkit-appearance: none; appearance: none;
	padding-right: 2.25rem;
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'><path d='M1 1.5 6 6.5l5-5' stroke='%23d4c9a8' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/></svg>");
	background-repeat: no-repeat;
	background-position: right .8rem center;
}

/* US-only store, so WooCommerce collapses the country field to a single option
   and sets pointer-events:none on it — it is a label, not a control. Our generic
   select rules were still giving it a border, a 44px control box and a dropdown
   arrow, so a field nobody can change looked like a disabled input. Render it as
   the plain text it actually is. Revisit if international shipping ever opens. */
.woocommerce form .form-row select.country_to_state--single {
	border: 0 !important;
	padding: 0; min-height: 0; width: auto;
	background: none;
	color: var(--glow-100); font-weight: 600;
}

/* Chrome paints autofilled fields with its own near-white fill and ignores
   background-color, which would undo everything above the moment a returning
   customer's details drop in. The inset shadow is the only way to override it;
   the absurd transition delay stops Chrome animating its yellow flash on top. */
.woocommerce form .form-row input:-webkit-autofill,
.woocommerce form .form-row input:-webkit-autofill:hover,
.woocommerce form .form-row input:-webkit-autofill:focus {
	-webkit-text-fill-color: var(--glow-100);
	-webkit-box-shadow: 0 0 0 100vw var(--void-850) inset;
	box-shadow: 0 0 0 100vw var(--void-850) inset;
	caret-color: var(--glow-100);
	transition: background-color 9999s ease-out 0s;
}

/* Focus has to read clearly against a dark field, and the global :focus-visible
   ring alone is easy to miss on a large input. */
.woocommerce form .form-row input.input-text:focus,
.woocommerce form .form-row select:focus,
.woocommerce form .form-row textarea:focus {
	outline: 2px solid var(--accent); outline-offset: 1px;
	border-color: var(--accent) !important;
}

/* Native checkboxes and radios render as browser-blue chrome on a dark panel.
   accent-color recolours them without rebuilding the controls, so they keep
   their native semantics and keyboard behaviour.
   Deliberately NOT scoped to `form`: the cart's shipping-method radios live in
   the totals table outside any form, which is why they stayed blue while the
   identical control on checkout went amber. */
.woocommerce input[type="checkbox"],
.woocommerce input[type="radio"] { accent-color: var(--accent); }
.woocommerce .button, .woocommerce a.button, .woocommerce button.button,
.woocommerce input.button, .woocommerce #place_order {
	background: var(--accent); color: var(--on-accent); border: 0; border-radius: var(--radius);
	padding: .8rem 1.25rem; font-weight: 700; font-size: var(--fs-400); cursor: pointer; line-height: 1.2;
}
.woocommerce .button:hover, .woocommerce a.button:hover, .woocommerce button.button:hover,
.woocommerce input.button:hover, .woocommerce #place_order:hover { background: var(--accent-hover); }
.woocommerce table.shop_table { border-collapse: collapse; border-radius: var(--radius); }
.woocommerce table.shop_table th, .woocommerce table.shop_table td { padding: var(--sp-3); }
.woocommerce .cart_totals, .woocommerce-checkout #order_review {
	background: var(--surface); border-radius: var(--radius); padding: var(--sp-5);
}
.woocommerce-checkout #order_review_heading { margin-top: 0; }
/* Scope link recolor to cart/checkout CONTENT only — WooCommerce puts a
   .woocommerce class on <body>, so an unscoped `.woocommerce a` would repaint
   the header brand + footer links dark-on-dark. */
.page__content .woocommerce a { color: var(--ink); text-decoration: underline; }
.page__content .woocommerce a:hover { color: var(--accent); }
.woocommerce .woocommerce-message, .woocommerce .woocommerce-info {
	border-top-color: var(--accent); border-radius: var(--radius-sm);
}
@media (min-width: 62rem) {
	/*
	 * Rows are declared explicitly. With only grid-column set, auto-placement put
	 * #order_review_heading in row 1 and #order_review in row 2 — and row 1 is as
	 * tall as the entire billing form, so "Your order" floated at the top of the
	 * column with its own table stranded ~1000px below it.
	 *
	 * Billing spans both rows; the heading and the table stack in column 2.
	 */
	.woocommerce-checkout form.checkout {
		display: grid;
		grid-template-columns: 1fr 24rem;
		grid-template-rows: auto 1fr;
		gap: 0 var(--sp-7);
		align-items: start;
	}
	.woocommerce-checkout form.checkout #customer_details { grid-column: 1; grid-row: 1 / span 2; }
	.woocommerce-checkout form.checkout #order_review_heading { grid-column: 2; grid-row: 1; margin-bottom: var(--sp-4); }
	.woocommerce-checkout form.checkout #order_review { grid-column: 2; grid-row: 2; }
	.woocommerce-checkout form.checkout #order_review { position: sticky; top: calc(var(--header-h) + 1rem); }
}

/* WC "alt" buttons (Proceed to checkout / Place order) — beat WC's default purple */
.woocommerce a.button.alt, .woocommerce button.button.alt, .woocommerce input.button.alt,
.woocommerce .checkout-button, .woocommerce #place_order, .woocommerce #respond input#submit.alt {
	background: var(--accent); color: var(--on-accent);
}
.woocommerce a.button.alt:hover, .woocommerce button.button.alt:hover, .woocommerce input.button.alt:hover,
.woocommerce .checkout-button:hover, .woocommerce #place_order:hover { background: var(--accent-hover); color: var(--on-accent); }

/* Stack billing/shipping in the left checkout column (cleaner than WC's floats) */
.woocommerce-checkout .col2-set,
.woocommerce-checkout .col2-set .col-1,
.woocommerce-checkout .col2-set .col-2 { width: 100%; float: none; margin: 0; }
.woocommerce-checkout .col2-set .col-2 { margin-top: var(--sp-5); }

/* Coupon prompt: strip the woocommerce-info panel chrome so the "Have a code?"
   link reads as a quiet aside instead of the loudest element on the page. The
   field still works — see the woocommerce_checkout_coupon_message filter in
   inc/woocommerce.php for the copy change and the reasoning. */
/* Left-aligned, not right. The toggle renders above form.checkout and spans the
   full width of both columns, so flex-end parked it in the top-right corner
   floating over the order summary, disconnected from anything. Flush left puts
   it on the same edge as the "Billing details" heading directly beneath it. */
/* !important, reluctantly, and on both properties. The generic notice styling in
   critical-woo.css is `.woocommerce .woocommerce-info { background: ... !important;
   border-top: 3px solid var(--accent) }` — same specificity as this rule, and the
   !important on background cannot be outranked any other way. Without these the
   toggle rendered as a 1200x28px dark slab with a gold hairline across the top
   and no padding: not a panel, not a link, just a bar that looks broken. */
.woocommerce .woocommerce-form-coupon-toggle .woocommerce-info,
.woocommerce-form-coupon-toggle .woocommerce-info {
	background: none !important; border: 0 !important; border-radius: 0;
	padding: 0; margin: 0 0 var(--sp-4);
	font-size: var(--fs-300); color: var(--muted);
	display: flex; justify-content: flex-start;
}
/* WC draws an icon via ::before on its notices; there is no panel left to hang it on. */
.woocommerce-form-coupon-toggle .woocommerce-info::before { display: none; }
.woocommerce-form-coupon-toggle .showcoupon {
	color: var(--muted); text-decoration: underline; text-underline-offset: 3px;
	/* Keeps the link a compliant touch target without adding visual weight. */
	display: inline-flex; align-items: center; min-height: 24px;
}
.woocommerce-form-coupon-toggle .showcoupon:hover { color: var(--accent); }

/* ---- Contact form ---- */
.contact-form { max-width: 38rem; }
.contact-form .form-row { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.contact-form label { font-weight: 600; }
.contact-form input, .contact-form textarea { width: 100%; padding: .6rem .7rem; min-height: 44px; border: 1px solid var(--border); border-radius: var(--radius-sm); font: inherit; }
.contact-form textarea { min-height: auto; }
.contact-form__hp { position: absolute !important; left: -9999px; }
.form-notice { padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-sm); margin-bottom: var(--sp-5); }
/* Tinted dark rather than the old pastel blocks: a pale green panel on this
   canvas reads as a rendering error, not as success. */
.form-notice--ok  { background: color-mix(in oklab, #2e7d32 26%, var(--void-850)); color: #a6dcaa; border: 1px solid color-mix(in oklab, #2e7d32 45%, transparent); }
.form-notice--err { background: color-mix(in oklab, #c0392b 26%, var(--void-850)); color: #f0a79c; border: 1px solid color-mix(in oklab, #c0392b 45%, transparent); }

/* ---- Your Privacy Choices (footer link + opt-out modal) ---- */
.site-footer__legal-wrap { display: contents; }
.pc-link { background: none; border: 0; padding: 0; font: inherit; color: inherit; cursor: pointer; text-align: left; }
.pc-link:hover { color: var(--accent); }
.pc-modal { position: fixed; inset: 0; z-index: 200; display: grid; place-items: center; padding: var(--sp-4); }
.pc-modal__backdrop { position: absolute; inset: 0; background: rgba(16,15,12,.62); }
.pc-modal__panel {
	position: relative; width: 100%; max-width: 30rem;
	background: var(--void-850); color: var(--glow-100); border-radius: var(--radius);
	border: 1px solid color-mix(in oklab, var(--brass-600) 45%, transparent);
	padding: var(--sp-6); box-shadow: 0 20px 60px rgba(0,0,0,.6);
}
.pc-modal__title { font-size: var(--fs-600); margin: 0 0 var(--sp-3); }
.pc-toggle { display: flex; gap: var(--sp-3); align-items: flex-start; margin: var(--sp-5) 0 var(--sp-3); font-weight: 600; cursor: pointer; }
.pc-toggle input { margin-top: 3px; width: 18px; height: 18px; flex: none; }
.pc-gpc { font-size: var(--fs-300); color: var(--muted); margin: 0; }
.pc-modal__actions { display: flex; gap: var(--sp-3); justify-content: flex-end; margin-top: var(--sp-5); }

/* ---- Search results ---- */
.search-page { padding-block: var(--sp-7); }
.search-list { list-style: none; margin: var(--sp-6) 0 0; padding: 0; display: grid; gap: var(--sp-5); }
.search-item__title { font-size: var(--fs-500); font-weight: 700; }
.search-item__title:hover { color: var(--accent); }
.search-item__excerpt { color: var(--muted); margin: var(--sp-1) 0 0; max-width: 46rem; }
/* Products and posts each get their own band so the two result types read as
   separate answers rather than one interleaved list. */
.search-section + .search-section { margin-top: var(--sp-8); }
.search-section .product-grid { margin-top: var(--sp-6); }
.search-empty { color: var(--muted); font-size: var(--fs-500); margin-top: var(--sp-6); }

/* ---- Empty cart ---- */
.cart-empty-state { text-align: center; padding: var(--sp-8) 0; display: grid; gap: var(--sp-4); justify-items: center; }
.cart-empty-state__title { font-size: var(--fs-700); margin: 0; }
.cart-empty-state__text { color: var(--muted); margin: 0; }

/* ---- My Account ---- */
@media (min-width: 48rem) {
	.woocommerce-account .woocommerce { display: grid; grid-template-columns: 14rem 1fr; gap: var(--sp-7); align-items: start; }
}
.woocommerce-MyAccount-navigation, .woocommerce-MyAccount-content { float: none; width: auto; }
.woocommerce-MyAccount-navigation ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.woocommerce-MyAccount-navigation li a { display: block; padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-sm); color: var(--ink); text-decoration: none; }
.woocommerce-MyAccount-navigation li a:hover { background: var(--surface); }
.woocommerce-MyAccount-navigation li.is-active a { background: var(--accent); color: var(--on-accent); }
.woocommerce-MyAccount-content { min-width: 0; }

/* ---- Product gallery: tap-to-open + swipeable lightbox ---- */
.pgallery__open { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; background: none; cursor: zoom-in; display: block; }
.pgallery__open[disabled] { cursor: default; }
.pgallery__stage .badge { pointer-events: none; } /* let taps fall through to open */

.lightbox { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; }
.lightbox__backdrop { position: absolute; inset: 0; background: rgba(16,15,12,.93); }
.lightbox__panel { position: relative; z-index: 1; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; padding: clamp(1rem, 4vw, 3.5rem); }
.lb-anim { transition: opacity .22s ease, transform .22s ease; }
.lb-hidden { opacity: 0; transform: scale(.92); }
.lb-shown { opacity: 1; transform: scale(1); }
.lightbox__img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: var(--radius-sm); cursor: zoom-in; user-select: none; -webkit-user-select: none; transition: transform .25s ease; }
.lightbox__img.is-zoomed { transform: scale(2); cursor: zoom-out; }
.lightbox__close, .lightbox__nav { display: flex; align-items: center; justify-content: center; color: var(--on-dark); background: rgba(0,0,0,.4); border: 0; border-radius: 50%; cursor: pointer; line-height: 1; z-index: 2; -webkit-tap-highlight-color: transparent; }
.lightbox__close { position: absolute; top: 1rem; right: 1rem; width: 46px; height: 46px; font-size: 26px; }
.lightbox__nav { position: absolute; top: 50%; transform: translateY(-50%); width: 46px; height: 46px; font-size: 30px; }
.lightbox__nav--prev { left: 1rem; }
.lightbox__nav--next { right: 1rem; }
.lightbox__counter { position: absolute; bottom: 1rem; left: 50%; transform: translateX(-50%); margin: 0; color: var(--on-dark-muted); font-size: var(--fs-300); letter-spacing: .04em; }
@media (hover: hover) {
	.lightbox__close:hover, .lightbox__nav:hover { background: rgba(0,0,0,.65); }
}
@media (prefers-reduced-motion: reduce) {
	.lb-anim, .lightbox__img { transition: none; }
}

/* ---- Shop mega menu ---- */
/* The caret glyph is ~11x14, which fails the Lighthouse `target-size` audit and
   is a genuinely poor touch target. Grow the BOX to the 24px minimum and pull
   the extra width back out with negative inline margin, so the hit area is
   compliant while the header spacing stays pixel-identical. justify-content
   keeps the glyph optically where it was. */
.mega-toggle {
	display: inline-flex; align-items: center; justify-content: center;
	min-width: 24px; min-height: 24px;
	margin-left: -3px; margin-right: -7px;
	padding: 0; background: none; border: 0; color: inherit; cursor: pointer;
	font-size: .7em; transition: transform .2s ease;
}
.mega-toggle.is-open { transform: rotate(180deg); }
.mega { position: absolute; left: 0; right: 0; top: 100%; z-index: 60; background: var(--surface-dark); border-top: 1px solid rgba(255,255,255,.08); box-shadow: 0 16px 30px rgba(0,0,0,.3); max-height: calc(100vh - var(--header-h)); overflow-y: auto; overscroll-behavior: contain; }
.mega__inner { width: min(100% - 2rem, var(--container)); margin-inline: auto; display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 1fr) minmax(0, 1.15fr); gap: var(--sp-7); padding-block: var(--sp-7); }
.mega__title { font-size: var(--fs-300); text-transform: uppercase; letter-spacing: .12em; color: var(--on-dark-muted); margin: 0 0 var(--sp-3); font-weight: 700; }
.mega__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.mega__link { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); color: var(--on-dark); padding: var(--sp-2) 0; font-weight: 500; }
.mega__link:hover { color: var(--accent); }
.mega__count { color: var(--on-dark-muted); font-size: var(--fs-300); }
/* DOM order keeps Featured first (mobile accordion). On desktop the Shop nav
   item sits on the right, so order it last → the promo lands under the cursor. */
.mega__col--featured { order: 3; border-left: 1px solid rgba(255,255,255,.08); padding-left: var(--sp-6); }
.mega__col--featured .mega__link { font-weight: 600; }
/* Every leaf category stacked in one list ran the panel to ~1626px against ~711px
   of viewport, so it scrolled by more than a screen while the other two columns
   sat empty. Flowing into three sub-columns fixed the width; dropping to the
   second level only (the third now lives on /armies/) fixed the count. Each
   group columnises independently, so Fantasy's 15 land in five rows and Sci-Fi's
   two in one, instead of one 17-row block. display:block is required —
   column-count does nothing on a grid — and break-inside stops a flex link
   splitting across a column boundary. */
.mega__col--armies .mega__list { display: block; column-count: 3; column-gap: var(--sp-6); }
.mega__col--armies .mega__list li { break-inside: avoid; }
/* Few enough armies that three sub-columns and a 3fr track just make holes. Set
   from the link count in yellowimp_mega_panel(), so it reverts by itself. */
.mega__inner--compact { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1.15fr); }
.mega__inner--compact .mega__col--armies .mega__list { column-count: 1; }
.mega__group { margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-300); text-transform: uppercase; letter-spacing: .08em; color: var(--on-dark-muted); font-weight: 700; }
.mega__group:first-of-type { margin-top: 0; }
.mega__group a { color: inherit; }
.mega__group a:hover { color: var(--accent); }
.mega__more { margin: var(--sp-4) 0 0; padding-top: var(--sp-3); border-top: 1px solid rgba(255,255,255,.08); }
.mega__more .mega__link { justify-content: flex-start; color: var(--accent); font-weight: 700; }
.mega__promo { display: block; border-radius: var(--radius); overflow: hidden; margin: 0 0 var(--sp-4); background: var(--surface-dark-2); }
.mega__promo-img { width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; display: block; transition: transform .4s cubic-bezier(.2,.7,.2,1); }
.mega__promo:hover .mega__promo-img { transform: scale(1.05); }
.mega__promo-cap { display: block; padding: var(--sp-3) var(--sp-4); }
.mega__promo-name { display: block; color: var(--on-dark); font-weight: 700; line-height: 1.2; }
.mega__promo-go { display: block; margin-top: 2px; font-size: var(--fs-300); font-weight: 700; color: var(--accent); }

@media (max-width: 767px) {
	/* In-flow accordion under "Shop" and "Services" in the slide-down nav.
	   Both rows lay out the same way: the label takes the space, the caret sits
	   beside it. .has-submenu was left out when this was written, so its link —
	   display:block at this width — pushed the caret onto its own line. */
	.has-mega,
	.has-submenu { display: flex; flex-wrap: wrap; align-items: center; }
	.has-mega > .site-nav__link,
	.has-submenu > .site-nav__link { flex: 1; }
	.submenu-toggle { padding: var(--sp-3) var(--sp-2); font-size: 1rem; line-height: 1; }
	/* Full width so it sits under both, rather than beside the caret. */
	.has-submenu > .submenu { flex-basis: 100%; }
	.mega-toggle { font-size: 1rem; padding: var(--sp-3) var(--sp-2); margin: 0; }
	.mega { position: static; flex-basis: 100%; background: var(--surface-dark-2); box-shadow: none; border-top: 0; border-radius: var(--radius); margin: 0 0 var(--sp-3); max-height: none; overflow: visible; }
	.mega__inner { width: auto; grid-template-columns: 1fr; gap: var(--sp-5); padding: var(--sp-4); }
	.mega__title { margin-bottom: var(--sp-2); }
	.mega__col--armies .mega__list { column-count: 1; }
	.mega__col--featured { order: 0; border-left: 0; padding-left: 0; border-bottom: 1px solid rgba(255,255,255,.08); padding-bottom: var(--sp-4); }
	.mega__promo-img { aspect-ratio: 16 / 9; }
}

/* ---- Instant search palette ---- */
.search-overlay {
	position: fixed; inset: 0; z-index: 100;
	display: flex; justify-content: center; align-items: flex-start;
	padding: 10vh var(--sp-4) var(--sp-4);
	background: rgba(8,7,5,.6); backdrop-filter: blur(3px);
}
.search-panel {
	width: min(100%, 38rem); background: var(--surface-dark); color: var(--on-dark);
	border: 1px solid rgba(255,255,255,.08); border-radius: var(--radius);
	box-shadow: 0 24px 60px rgba(0,0,0,.5); overflow: hidden;
	display: flex; flex-direction: column; max-height: 80vh;
}
.search-box { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid rgba(255,255,255,.08); }
.search-box__icon { color: var(--on-dark-muted); flex: none; }
.search-box__input { flex: 1; min-width: 0; background: none; border: 0; outline: none; color: var(--on-dark); font: inherit; font-size: var(--fs-500); min-height: 44px; }
.search-box__input::placeholder { color: var(--on-dark-muted); }
.search-box__close { flex: none; width: 32px; height: 32px; display: grid; place-items: center; background: none; border: 0; color: var(--on-dark-muted); font-size: 1.5rem; line-height: 1; cursor: pointer; border-radius: var(--radius-sm); }
.search-box__close:hover { color: var(--on-dark); background: var(--surface-dark-2); }
.search-results { overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.search-status { margin: 0; padding: var(--sp-3) var(--sp-4); color: var(--on-dark-muted); font-size: var(--fs-300); text-transform: uppercase; letter-spacing: .1em; font-weight: 700; }
.cmd-list { list-style: none; margin: 0; padding: var(--sp-2); display: grid; gap: 2px; }
.cmd-item { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-sm); color: var(--on-dark); }
.cmd-item.is-active { background: var(--surface-dark-2); }
.cmd-item__thumb { flex: none; width: 48px; height: 32px; border-radius: var(--radius-sm); overflow: hidden; background: var(--surface-dark-2); }
.cmd-item__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cmd-item__badge { flex: none; width: 48px; height: 32px; display: grid; place-items: center; border-radius: var(--radius-sm); background: var(--surface-dark-2); color: var(--on-dark-muted); font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; }
.cmd-item__body { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.cmd-item__title { font-weight: 600; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmd-item.is-active .cmd-item__title { color: var(--accent); }
.cmd-item__meta { color: var(--on-dark-muted); font-size: var(--fs-300); }
.cmd-item__cat::before { content: ' · '; }
.cmd-seeall { display: flex; align-items: center; gap: var(--sp-3); width: 100%; margin: 0; padding: var(--sp-3) var(--sp-4); background: none; border: 0; border-top: 1px solid rgba(255,255,255,.08); color: var(--on-dark); font: inherit; font-weight: 600; text-align: left; cursor: pointer; }
.cmd-seeall.is-active, .cmd-seeall:hover { background: var(--surface-dark-2); color: var(--accent); }
.cmd-seeall__icon { flex: none; color: var(--on-dark-muted); }
.cmd-seeall.is-active .cmd-seeall__icon, .cmd-seeall:hover .cmd-seeall__icon { color: var(--accent); }
.cmd-seeall__arrow { margin-left: auto; color: var(--on-dark-muted); }
.cmd-seeall.is-active .cmd-seeall__arrow, .cmd-seeall:hover .cmd-seeall__arrow { color: var(--accent); }

@media (max-width: 767px) {
	.search-overlay { padding: 0; }
	.search-panel { width: 100%; max-height: 100%; height: 100%; border: 0; border-radius: 0; }
	.search-results { flex: 1; }
}

/* ===========================================================================
   HOMEPAGE SECTIONS
   Everything here paints below the fold on every viewport, so it lives in the
   async stylesheet rather than the inlined critical block. Each section is
   independent — reordering front-page.php needs no CSS changes.
   =========================================================================== */

.section__title span { display: block; }
.section__more { text-align: center; margin: var(--sp-7) 0 0; }

/* ---- Shop by army ----
   Written for a homepage band that the 2026-08-13 Bellwoken rebuild removed, and
   revived for /armies/. The card is unchanged; the sub-range list below it is new. */
.army-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-5); grid-template-columns: repeat(2, 1fr); }
.army-card { border-radius: var(--radius); overflow: hidden; display: flex; flex-direction: column; }
/* flex:1, NOT height:100%. That was harmless when the link was the card's only
   child; with a sub-range list below it the link claimed the card's full height
   and pushed the list out through overflow:hidden. Growing instead keeps the
   sub-lists bottom-aligned across a row of unevenly-titled cards. */
.army-card__link { display: flex; flex-direction: column; flex: 1 0 auto; min-height: 0; }
/* Fixed ratio + explicit image dimensions from wp_get_attachment_image = no CLS. */
.army-card__media { display: block; aspect-ratio: 4 / 3; background: var(--stage); overflow: hidden; }
/* Ranges with no photographed product yet get a monogram rather than a hole. */
.army-card__media--empty { display: grid; place-items: center; background: linear-gradient(160deg, var(--void-800), var(--void-950)); }
.army-card__mark { font-family: var(--font-display); font-size: 3.5rem; line-height: 1; color: color-mix(in oklab, var(--brass-500) 55%, transparent); }
.army-card__img { width: 100%; height: 100%; object-fit: cover; transition: transform .3s ease; }
.army-card:hover .army-card__img { transform: scale(1.04); }
.army-card__body { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-4); }
.army-card__name { font-family: var(--font-display); font-size: var(--fs-500); color: var(--glow-50); line-height: 1.2; }
.army-card__count { font-family: var(--font-ui); font-size: var(--fs-300); color: var(--mist-500); }
.army-card:hover .army-card__name { color: var(--flame-300); }
@media (prefers-reduced-motion: reduce) { .army-card__img, .army-card:hover .army-card__img { transition: none; transform: none; } }
/* Sub-ranges. Outside the card link (see page-armies.php), so they get their own
   hit targets — 44px rows, because these are the deepest links on the site and
   the most likely to be tapped on a phone. */
.army-card__subs { list-style: none; margin: 0; padding: 0 var(--sp-4) var(--sp-3); display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); }
.army-card__subs a { display: inline-flex; align-items: center; gap: var(--sp-1); min-height: 44px; font-size: var(--fs-300); color: var(--muted); }
.army-card__subs a:hover { color: var(--accent); }
.army-card__subcount { color: var(--brass-400); font-variant-numeric: tabular-nums; }

/* ---- /armies/ ---- */
.armies__intro { max-width: 46rem; margin: 0 auto var(--sp-7); color: var(--muted); text-align: center; }
.armies__group { margin-bottom: var(--sp-8); }
.armies__group:last-child { margin-bottom: 0; }
.armies__group-title { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-3); margin: 0 0 var(--sp-5); font-size: var(--fs-600); }
.armies__group-title a:hover { color: var(--accent); }
.armies__group-count { font-family: var(--font-ui); font-size: var(--fs-300); color: var(--brass-400); text-transform: uppercase; letter-spacing: .08em; }

/* ---- 4. Bundles banner ---- */
.bundle-banner { display: grid; gap: var(--sp-6); padding: var(--sp-6); border-radius: var(--radius); align-items: center; }
.bundle-banner__eyebrow { font-family: var(--font-ui); font-size: var(--fs-300); font-weight: 700; text-transform: uppercase; letter-spacing: 0.14em; color: var(--flame-400); margin: 0 0 var(--sp-3); }
.bundle-banner__title { font-size: var(--fs-700); margin: 0 0 var(--sp-4); }
.bundle-banner__text { color: var(--glow-200); margin: 0 0 var(--sp-5); max-width: 42rem; }
.bundle-banner__media { border-radius: var(--radius); overflow: hidden; background: var(--stage); }
.bundle-banner__img { width: 100%; height: auto; display: block; }

/* ---- 4b. Bundle spotlight (above the Popular Minis grid) ----
   Distinct from .bundle-banner further down: that one is prose about bundles in
   general, this one is a real product with a real price on it. */
.spotlight { display: grid; gap: var(--sp-5); padding: var(--sp-5); align-items: center; margin: 0 0 var(--sp-7); }
.spotlight__media { display: block; aspect-ratio: 3 / 2; background: var(--stage); border-radius: var(--radius-sm); overflow: hidden; }
.spotlight__img { width: 100%; height: 100%; object-fit: contain; display: block; }
.spotlight__eyebrow { font-family: var(--font-ui); font-size: var(--fs-300); font-weight: 700; text-transform: uppercase; letter-spacing: 0.14em; color: var(--flame-400); margin: 0 0 var(--sp-2); }
.spotlight__title { font-size: var(--fs-600); margin: 0 0 var(--sp-3); }
.spotlight__title a:hover { color: var(--accent); }
.spotlight__price { margin: 0 0 var(--sp-3); display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }
.spotlight__price del { color: var(--muted); font-weight: 400; }
.spotlight__price ins { text-decoration: none; font-weight: 700; color: var(--accent); font-size: var(--fs-500); }
.spotlight__save { font-family: var(--font-ui); font-size: var(--fs-300); text-transform: uppercase; letter-spacing: .08em; color: var(--brass-400); }
.spotlight__text { color: var(--glow-200); margin: 0 0 var(--sp-5); max-width: 46rem; }
.spotlight__cta { align-self: start; }
@media (min-width: 48rem) {
	/* Same capped-track reasoning as .bundle-banner: a fixed rem track cannot give
	   way at 200% text, so the media column is a share of the container. */
	.spotlight { grid-template-columns: min(18rem, 34%) minmax(0, 1fr); gap: var(--sp-6); padding: var(--sp-6); }
}

/* ---- 5. Why Yellow Imp ---- */
.usp-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-6); grid-template-columns: 1fr; }
.usp__title { font-size: var(--fs-500); margin: 0 0 var(--sp-2); color: var(--glow-50); }
.usp__text { color: var(--glow-200); margin: 0; }
.usp__brands { display: block; margin-top: var(--sp-2); }
.usp__brands a { color: var(--flame-300); text-decoration: underline; text-underline-offset: 2px; }
.usp__brands a:hover { color: var(--glow-50); }

/* ---- 6. Social proof ---- */
.review-grid, .proof-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-5); grid-template-columns: repeat(2, 1fr); }
.review { padding: var(--sp-5); border-radius: var(--radius); display: flex; flex-direction: column; gap: var(--sp-3); }
.review__stars { color: var(--flame-400); margin: 0; letter-spacing: .1em; }
.review__text { margin: 0; font-style: italic; color: var(--glow-100); }
.review__meta { margin: 0; font-family: var(--font-ui); font-size: var(--fs-300); display: flex; flex-direction: column; gap: 2px; }
.review__author { color: var(--glow-50); font-weight: 700; }
.review__product { color: var(--mist-500); }
.review__product:hover { color: var(--flame-300); }
/* Placeholder tiles until real customer photos exist — reserved space, so
   dropping images in later shifts nothing. */
.proof-tile { aspect-ratio: 1 / 1; border-radius: var(--radius); border-style: dashed; }
.proof-note { text-align: center; color: var(--mist-500); margin: var(--sp-5) 0 0; }
/* Standing alone (no gallery yet), it is the section's only body, so it does not
   need the top margin that separates it from a grid above. */
.proof-note--alone { margin-top: 0; }
/* Underlined, not colour-only: this link sits inside a paragraph, so WCAG 1.4.1
   needs it distinguishable by more than hue. */
.proof-note a { color: var(--flame-300); text-decoration: underline; text-underline-offset: 2px; }
.review__product { text-decoration: underline; text-underline-offset: 2px; }

/* ---- 7. About teaser ---- */
.about-teaser { display: grid; gap: var(--sp-6); align-items: center; }
.about-teaser__media { border-radius: var(--radius); overflow: hidden; background: var(--stage); border: 1px solid var(--stage-edge); }
.about-teaser__img { width: 100%; height: auto; display: block; }
.about-teaser__title { font-size: var(--fs-700); margin: 0 0 var(--sp-4); }
.about-teaser__body p { color: var(--glow-200); }
.about-teaser__body .btn { margin-top: var(--sp-3); }

/* ---- 9. Newsletter ---- */
.newsletter { max-width: 40rem; margin-inline: auto; text-align: center; }
.newsletter__title { font-size: var(--fs-700); margin: 0 0 var(--sp-3); }
.newsletter__text { color: var(--glow-200); margin: 0 0 var(--sp-5); }
.newsletter__form { display: flex; flex-wrap: wrap; gap: var(--sp-3); justify-content: center; }
.newsletter__input {
	flex: 1 1 16rem; min-width: 0; min-height: 48px; padding: .6rem .9rem;
	font-family: var(--font-ui); font-size: var(--fs-400);
	background: var(--void-850); color: var(--glow-100);
	border: 1px solid color-mix(in oklab, var(--brass-600) 45%, transparent);
	border-radius: var(--radius-sm);
}
.newsletter__input::placeholder { color: var(--mist-600); }
.newsletter__btn { flex: none; min-height: 48px; }
.newsletter .form-notice { text-align: left; }
/* The stacking/unsubscribe line under the field. Quiet on purpose: it is
   reassurance, not a second pitch. */
.newsletter__fine { margin: var(--sp-3) 0 0; font-size: var(--fs-300); color: var(--muted); }

/* ---- Homepage responsive ---- */
@media (min-width: 48rem) {
	.army-grid { grid-template-columns: repeat(3, 1fr); }
	/* Also three here: at two columns the odd panel sat alone on its own row. */
	.usp-grid { grid-template-columns: repeat(3, 1fr); }
	.review-grid, .proof-grid { grid-template-columns: repeat(3, 1fr); }
	.proof-grid { gap: var(--sp-4); }
}
@media (min-width: 62rem) {
	/* WCAG 1.4.4. A fixed 30rem track cannot shrink, and media queries resolve rem
	   against the initial 16px root — so at 200% text the desktop layout stays active
	   while this track doubles to 960px and pushes the page to 1354px. Capping it as a
	   share of the container keeps the intent and lets it give way. */
	.bundle-banner { grid-template-columns: minmax(0, 1fr) min(30rem, 45%); padding: var(--sp-7); }
	.about-teaser { grid-template-columns: 26rem 1fr; gap: var(--sp-8); }
	/* Until Matt's workshop photo lands, the text owns the row rather than
	   sitting beside an empty 26rem column. */
	.about-teaser--noimg { grid-template-columns: 1fr; max-width: 46rem; }
	/* Three, not four: the "works with the game you already play" panel was
	   removed on 2026-08-19 and four columns left the row a quarter empty. */
	.usp-grid { grid-template-columns: repeat(3, 1fr); }
	.review-grid { grid-template-columns: repeat(3, 1fr); }
}

/* ---- Ember particles ------------------------------------------------------
   The layer is created by assets/js/particles.js on idle, so these styles are
   in main.css rather than the inlined critical block — nothing here is needed
   at first paint.
--------------------------------------------------------------------------- */
.ember-particles {
	position: fixed; inset: 0;
	/* z-index -1 puts the field BEHIND page content and above the body canvas,
	   so embers show through the gaps between sections and never speckle text,
	   cards, or product photography. The one place they read as an overlay is
	   the homepage hero, arranged from the other side: the hero's fill and art
	   are their own z-index -1 layers, and this one wins on tree order because
	   it is appended to <body> after the page content. See the .hero note in
	   critical.css before changing either number. */
	z-index: -1;
	overflow: hidden; pointer-events: none;
	/* Isolate the field so ember repaints never invalidate page layout/paint. */
	contain: layout paint style;
	/* Promote once, for the whole field — not once per span. */
	will-change: transform;
}

.ember-particles span {
	position: absolute; top: 0; left: 0;
	color: var(--ember-color, var(--flame-400));
	font-family: var(--font-display);
	font-size: 14px; line-height: 1;
	opacity: 0;
	/* `screen` is doing real merchandising work, not just looking pretty: over
	   the near-black canvas an ember shows at full strength, but over a bright
	   product photo the blend approaches a no-op and the glyph disappears. So
	   embers fill the dark gaps and never speckle the miniatures. */
	mix-blend-mode: screen;
	text-shadow: 0 0 6px var(--ember-color, var(--flame-400));
}

@media (prefers-reduced-motion: reduce) { .ember-particles { display: none; } }

/* ---- Product reviews -------------------------------------------------------
   Below the fold on every PDP, so it lives here rather than in critical.css.

   Stars are text glyphs (U+2605) in two stacked rows: a muted row underneath
   and a gold row on top, clipped by width. That gives exact fractional averages
   without an icon font, an SVG sprite, or an image request — and because both
   rows contain the same five glyphs, they align regardless of font metrics.
--------------------------------------------------------------------------- */
.reviews { width: min(100% - 2rem, var(--container)); margin-inline: auto; padding-block: var(--sp-8); }
.reviews__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-3) var(--sp-5); margin-bottom: var(--sp-6); }
.reviews__head .section__title { margin: 0; }
.reviews__summary { display: inline-flex; align-items: baseline; gap: var(--sp-3); }
.reviews__average { font-weight: 700; color: var(--ink); }
.reviews__count { color: var(--muted); font-size: var(--fs-300); }
.reviews__empty, .reviews__gate { color: var(--muted); margin: 0 0 var(--sp-6); }

/* The two rows are overlaid, so the wrapper is sized by the empty row and the
   filled row is taken out of flow on top of it. white-space:nowrap stops a
   clipped row from wrapping mid-way and breaking the overlay. */
.stars { position: relative; display: inline-block; white-space: nowrap; line-height: 1; font-size: 1.05rem; letter-spacing: .12em; }
.stars--sm { font-size: .85rem; }
.stars__empty { color: var(--mist-600, #55514a); }
.stars__filled { position: absolute; inset-block-start: 0; inset-inline-start: 0; overflow: hidden; color: var(--accent); }

.reviews__list { list-style: none; margin: 0 0 var(--sp-7); padding: 0; display: grid; gap: var(--sp-5); }
.reviews__list .review { padding-bottom: var(--sp-5); border-bottom: 1px solid var(--border); }
.reviews__list .review:last-child { border-bottom: 0; padding-bottom: 0; }
.review__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-3); }
.review__author { font-weight: 700; color: var(--ink); }
.review__verified {
	font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
	padding: 3px 8px; border-radius: 999px;
	background: color-mix(in oklab, var(--brass-400) 22%, transparent); color: var(--brass-400);
}
.review__date { color: var(--muted); font-size: var(--fs-300); margin-inline-start: auto; }
.review__text { color: var(--ink); }
.review__text p:last-child { margin-bottom: 0; }
.review__pending { color: var(--muted); }

/* ---- Review form ---- */
.reviews__form-title { font-size: var(--fs-600); margin: 0 0 var(--sp-4); }
.reviews__form { max-width: 38rem; }
.reviews__form p { margin: 0 0 var(--sp-4); }
.reviews__form label, .comment-form-rating__label { display: block; font-weight: 600; margin-bottom: var(--sp-2); }
.reviews__form input[type="text"], .reviews__form input[type="email"], .reviews__form textarea {
	width: 100%; padding: .6rem .7rem; min-height: 44px;
	border: 1px solid var(--border); border-radius: var(--radius-sm);
	font: inherit; background: var(--void-850); color: var(--glow-100);
}
.reviews__form textarea { min-height: auto; }
.reviews__form .required { color: var(--accent); }
/* WordPress prints a cookie-consent checkbox row; keep it quiet and inline. */
.reviews__form .comment-form-cookies-consent { display: flex; align-items: flex-start; gap: var(--sp-2); font-size: var(--fs-300); color: var(--muted); }
.reviews__form .comment-form-cookies-consent label { font-weight: 400; margin: 0; }
.reviews__form .comment-form-cookies-consent input { margin-top: .25rem; }

/* Star input: radios are in the DOM 5→1 so `:checked ~ label` can fill every
   star BEFORE the checked one; row-reverse puts them back in reading order.
   Tab order therefore runs 1→5 visually left→right. Pure CSS — the control
   works before Alpine hydrates, and without any JS at all. */
.stars-input { display: inline-flex; flex-direction: row-reverse; justify-content: flex-end; border: 0; margin: 0; padding: 0; gap: 2px; }
.stars-input input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.stars-input label {
	margin: 0; cursor: pointer; font-size: 1.6rem; line-height: 1;
	color: var(--mist-600, #55514a); transition: color .12s ease;
	/* 24px minimum touch target without inflating the glyph. */
	display: inline-flex; align-items: center; justify-content: center; min-width: 28px; min-height: 28px;
}
.stars-input input:checked ~ label,
.stars-input label:hover,
.stars-input label:hover ~ label { color: var(--accent); }
/* Keyboard focus must be visible even though the radio itself is off-screen. */
.stars-input input:focus-visible + label { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

@media (prefers-reduced-motion: reduce) { .stars-input label { transition: none; } }

/* The submit button carries .btn .btn--primary, but woocommerce.css ships
   `.woocommerce:where(body:not(...)) #respond input#submit` with a grey fill.
   :where() contributes ZERO specificity, so that selector scores (1,1,1) —
   exactly the same as `.reviews__form input#submit` — and wins purely on being
   later in source order. Adding #respond (which comment_form() wraps this in)
   takes us to (2,1,1) and breaks the tie without resorting to !important.
   appearance:none stops the native widget styling coming back underneath.
   This can be simplified once the PDP asset diet drops woocommerce.css. */
.reviews__form #respond input#submit,
.reviews #respond input#submit {
	-webkit-appearance: none; appearance: none;
	display: inline-flex; align-items: center; justify-content: center;
	background: var(--accent); color: var(--on-accent);
	border: 2px solid transparent; border-radius: var(--radius);
	padding: var(--sp-3) var(--sp-5);
	font-family: var(--font-ui); font-weight: 700; font-size: var(--fs-400); line-height: 1;
	cursor: pointer; transition: background-color .15s ease;
}
.reviews__form #respond input#submit:hover,
.reviews #respond input#submit:hover { background: var(--accent-hover); }
@media (prefers-reduced-motion: reduce) {
	.reviews__form #respond input#submit,
	.reviews #respond input#submit { transition: none; }
}

/* Toast action button (Undo after removing a cart line). The toast is now a
   flex row of message + optional button rather than a bare x-text node. */
.cart-toast { display: flex; align-items: center; gap: var(--sp-4); }
.cart-toast__undo {
	flex: none; background: none; border: 0; cursor: pointer;
	font: inherit; font-weight: 700; color: var(--accent);
	text-decoration: underline; text-underline-offset: 3px;
	/* Compliant touch target without giving the toast a second button box. */
	min-height: 24px; padding: 0 2px;
}
.cart-toast__undo:hover { color: var(--glow-50); }

/* ---- About page -----------------------------------------------------------
   Intro is two columns on desktop and stacks on mobile with the portrait first,
   so the page opens on a face rather than a wall of text. Every block below the
   intro is data-driven (see page-about.php) and hides itself when empty. */
.about-page { padding-block: var(--sp-7) 0; }
.about-hero { display: grid; gap: var(--sp-6); align-items: start; margin-bottom: var(--sp-8); }
@media (min-width: 62rem) {
	.about-hero { grid-template-columns: minmax(0, 1fr) 28rem; gap: var(--sp-8); }
	/* Body first in source for reading order; portrait sits right on desktop. */
	.about-hero__media { order: 2; }
}
.about-hero__title { font-size: var(--fs-800); margin: 0 0 var(--sp-5); }
.about-hero__story { max-width: 42rem; }
.about-hero__story p { margin: 0 0 var(--sp-4); }
.about-hero__img { width: 100%; height: auto; border-radius: var(--radius); border: 1px solid var(--stage-edge); display: block; }

/* Editor-only nudge. Dashed, unstyled-looking on purpose — it should read as
   scaffolding, not as part of the design. */
.about-hero__todo { border: 1px dashed var(--brass-400); border-radius: var(--radius); padding: var(--sp-5); color: var(--muted); }
.about-hero__todo p { margin: 0 0 var(--sp-3); }
.about-hero__todo p:last-child { margin-bottom: 0; }

.about-brands { list-style: none; margin: var(--sp-6) 0 0; padding: 0; display: grid; gap: var(--sp-5); grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.about-brand { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); }
.about-brand__name { margin: 0; font-size: var(--fs-500); }
.about-brand__name a:hover { color: var(--accent); }
.about-brand__desc { margin: 0; color: var(--muted); font-size: var(--fs-300); }
.about-brand__count { margin: auto 0 0; color: var(--brass-400); font-size: var(--fs-300); text-transform: uppercase; letter-spacing: 0.08em; }

.about-shots { list-style: none; margin: var(--sp-6) 0 0; padding: 0; display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
.about-shot__img { width: 100%; height: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius); border: 1px solid var(--stage-edge); display: block; }

.about-facts { margin: var(--sp-6) 0 0; display: grid; gap: var(--sp-5); grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
.about-fact dt { font-size: var(--fs-300); text-transform: uppercase; letter-spacing: 0.1em; color: var(--brass-400); margin-bottom: var(--sp-2); }
.about-fact dd { margin: 0; color: var(--glow-100); }
.about-fact dd a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.about-cta { margin: var(--sp-7) 0 0; }

/* ---------- The Bellwoken lead ------------------------------------------
   The Core Set gets a full-width split rather than a bigger card, because the
   thing that sells a $107 box is the photo at a size you can read the models
   in. Stacks on mobile with the photo first. */
.bw-lead { display: grid; gap: var(--sp-5); margin-bottom: var(--sp-8); }
.bw-lead__media { display: block; border-radius: var(--radius); overflow: hidden; background: var(--stage); border: 1px solid var(--stage-edge); }
.bw-lead__img { width: 100%; height: auto; display: block; }
.bw-lead__title { font-size: var(--fs-700); margin: 0 0 var(--sp-3); }
.bw-lead__title a { color: inherit; text-decoration: none; }
.bw-lead__title a:hover { color: var(--accent); }
.bw-lead__desc p { color: var(--glow-200); margin: 0 0 var(--sp-3); }
.bw-lead__price { font-size: var(--fs-600); margin: 0 0 var(--sp-2); }
.bw-lead__meta { color: var(--muted); font-size: var(--fs-300); margin: 0 0 var(--sp-4); }
.home-bellwoken__grid { margin-bottom: var(--sp-6); }

/* ---------- Contact -------------------------------------------------------
   Form first at a readable measure, the two fallbacks beside it, the help pages
   underneath. The order is deliberate: a contact page that opens by pointing
   somewhere else reads as "do not contact me". */
.contact-layout { display: grid; gap: var(--sp-6); align-items: start; }
.contact-aside { display: grid; gap: var(--sp-5); align-content: start; }
.contact-aside__card { padding: var(--sp-5); border-radius: var(--radius); }
.contact-aside__title { font-size: var(--fs-500); margin: 0 0 var(--sp-2); }
.contact-aside__text { color: var(--muted); font-size: var(--fs-300); margin: 0 0 var(--sp-3); }
.contact-aside__email { margin: 0; font-size: var(--fs-500); word-break: break-word; }
.contact-aside__email a { color: var(--accent); font-weight: 600; }
.contact-aside__links { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
/* 44px rows: these sit low on a page people reach on a phone mid-problem. */
.contact-aside__links a { display: flex; align-items: center; min-height: 44px; color: var(--glow-200); }
.contact-aside__links a:hover { color: var(--accent); }

.contact-help { margin-top: var(--sp-8); }
.help-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-5); }
.help-card { border-radius: var(--radius); display: flex; }
.help-card__link { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-5); width: 100%; }
.help-card__title { font-size: var(--fs-500); margin: 0; color: var(--glow-50); }
.help-card:hover .help-card__title { color: var(--flame-300); }
.help-card__text { color: var(--muted); font-size: var(--fs-300); margin: 0; }
/* Pushed to the bottom so the arrows line up across a row of uneven blurbs. */
.help-card__go { margin-top: auto; padding-top: var(--sp-2); color: var(--accent); font-size: var(--fs-300); font-weight: 700; }

/* ---------- Services ------------------------------------------------------
   Three equal cards. The media well is sized to the final crop now so that
   dropping a photo in later changes nothing about the layout, and it is
   labelled rather than blank: an empty slot should read as "photo pending",
   never as a broken image. */
.svc-grid { list-style: none; display: grid; gap: var(--sp-5); margin: 0; padding: 0; }
.svc-card { display: flex; }
.svc-card__link { display: flex; flex-direction: column; width: 100%; text-decoration: none; color: inherit; border: 1px solid var(--stage-edge); border-radius: var(--radius); overflow: hidden; background: var(--stage); transition: border-color .2s ease, transform .2s ease; }
.svc-card__link:hover { border-color: var(--accent); transform: translateY(-2px); }
.svc-card__media { display: block; aspect-ratio: 3 / 2; background: var(--void-900); }
.svc-card__media--pending { display: grid; place-items: center; padding: var(--sp-4); background: repeating-linear-gradient(135deg, var(--void-900) 0 10px, var(--void-950) 10px 20px); }
.svc-card__pending { color: var(--muted); font-size: var(--fs-300); text-align: center; letter-spacing: .04em; text-transform: uppercase; }
.svc-card__body { display: block; padding: var(--sp-5); }
.svc-card__title { font-size: var(--fs-600); margin: 0 0 var(--sp-3); }
.svc-card__text { display: block; color: var(--glow-200); margin-bottom: var(--sp-4); }
.svc-card__cta { color: var(--accent); font-weight: 600; }

@media (min-width: 48rem) {
	.svc-grid { grid-template-columns: repeat(3, 1fr); }
	/* Two, and it stays two at every width above this. Four would fit the four
	   help pages in one row, but nothing on this site is four columns any more;
	   three would leave an orphan on its own row. Two also keeps the blurbs —
	   the pages' own opening lines, so their length is not ours to control — to
	   about two rows each. */
	.help-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 62rem) {
	.bw-lead { grid-template-columns: 1.15fr 1fr; gap: var(--sp-8); align-items: center; }
	/* The form column is capped by .page__content's 46rem measure already; the
	   aside takes what is left rather than a fixed width, so it never squeezes
	   the form below a comfortable line length. */
	.contact-layout { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: var(--sp-8); }
}
@media (prefers-reduced-motion: reduce) {
	.svc-card__link:hover { transform: none; }
}

/* ---------- Nav submenu (Services) ---------------------------------------
   Plainer sibling of the Shop mega panel. Desktop: a panel under the item.
   Mobile: the nav is already a stacked drawer, so it just indents in flow
   rather than floating over anything. */
.site-nav__item.has-submenu { position: relative; }
.submenu { list-style: none; margin: 0; padding: var(--sp-2) 0 0 var(--sp-4); }
.submenu__link { display: block; padding: var(--sp-2) 0; color: var(--glow-200); text-decoration: none; }
.submenu__link:hover, .submenu__link:focus-visible { color: var(--accent); }
.submenu-toggle { background: none; border: 0; color: inherit; cursor: pointer; padding: 0 var(--sp-2); font-size: var(--fs-300); line-height: 1; transition: transform .2s ease; }
.submenu-toggle.is-open { transform: rotate(180deg); }

/* 48rem, not 62rem: the desktop nav appears at 768px (.site-nav is hidden below
   that) and the mega uses the same breakpoint, but this one used to start at
   992px. In the 768-991px band the panel stayed position:static, so opening it
   inflated the header from 72px to as much as 215px. Reachable before only by
   clicking the caret; once the item opens on hover it fires on mouse movement. */
@media (min-width: 48rem) {
	.submenu {
		position: absolute; top: 100%; left: 0; z-index: 60; min-width: 16rem;
		background: var(--void-950); border: 1px solid var(--stage-edge);
		border-radius: var(--radius); padding: var(--sp-3);
		box-shadow: 0 10px 30px rgba(0,0,0,.45);
	}
	.submenu__link { padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-sm); }
	.submenu__link:hover { background: var(--void-900); }
}
@media (prefers-reduced-motion: reduce) { .submenu-toggle { transition: none; } }


/* ---------- Service page shell -------------------------------------------
   The three /services/ pages. The template shipped with these class names and
   no rules behind any of them, so the pages had been rendering as bare prose
   in a full-width column. The measure and the photo well are in critical.css
   because they move the layout; everything here is below the fold.

   The media well is labelled rather than blank while the photos are pending,
   for the same reason the homepage service cards are: an empty slot should
   read as "photo coming", never as a broken image. */
.service__head { margin-bottom: var(--sp-6); }
.service__eyebrow { color: var(--accent); font-size: var(--fs-300); text-transform: uppercase; letter-spacing: .12em; margin: 0 0 var(--sp-2); }
.service__title { font-size: var(--fs-800); margin: 0; }
.service__media--pending { display: grid; place-items: center; padding: var(--sp-4); background: repeating-linear-gradient(135deg, var(--void-900) 0 10px, var(--void-950) 10px 20px); }
.service__pending { color: var(--muted); font-size: var(--fs-300); text-align: center; letter-spacing: .04em; text-transform: uppercase; }

.service__cta { margin-top: var(--sp-8); padding: var(--sp-6); border: 1px solid var(--stage-edge); border-radius: var(--radius); background: var(--stage); text-align: center; }
.service__cta-title { font-size: var(--fs-600); margin: 0 0 var(--sp-3); }
.service__cta-text { color: var(--glow-200); margin: 0 auto var(--sp-5); max-width: 34rem; }

/* ---------- Rate table ----------------------------------------------------
   Commission prices. Four columns do not fit 375px however hard you squeeze
   them, so the table scrolls inside its own wrapper rather than forcing the
   page body to scroll sideways — the row labels stay put and the numbers move.
   It is allowed past the 42rem prose measure for the same reason. */
.rate-table__wrap { max-width: none; overflow-x: auto; margin: var(--sp-5) 0; border: 1px solid var(--stage-edge); border-radius: var(--radius); background: var(--stage); }
.rate-table { width: 100%; border-collapse: collapse; font-size: var(--fs-400); }
.rate-table th, .rate-table td { padding: var(--sp-3) var(--sp-4); text-align: right; border-bottom: 1px solid var(--stage-edge); white-space: nowrap; }
.rate-table thead th { color: var(--muted); font-size: var(--fs-300); font-weight: 600; text-transform: uppercase; letter-spacing: .08em; vertical-align: bottom; }
.rate-table tbody th { text-align: left; font-weight: 400; color: var(--ink); white-space: normal; min-width: 14rem; }
.rate-table thead th:first-child { text-align: left; }
.rate-table tbody tr:last-child th, .rate-table tbody tr:last-child td { border-bottom: 0; }
.rate-table tbody td { font-variant-numeric: tabular-nums; color: var(--ink); }
/* No opacity here: --muted (#988e80) dimmed to .75 over --void-900 resolves to
   #776f64 = 3.75:1, under the 4.5:1 AA floor for this 13px text. Undimmed it is
   5.77:1 and still reads as the quieter line. */
.rate-table__sub { display: block; font-size: var(--fs-300); text-transform: none; letter-spacing: 0; font-weight: 400; }


/* ---------- Post cards ----------------------------------------------------
   These live in critical-blog.css too, and that overlap is deliberate.

   critical-blog.css is inlined only on blog views (yellowimp_is_blog_page()),
   where the cards are the page and sit above the fold. The front page also
   renders post cards, in the "from the blog" band at the very bottom — and it
   was getting none of these rules, so .post-grid fell back to display:block
   with list-style:disc and the band rendered as a bulleted list of unstyled
   links. Inlining the whole 7KB blog file on the home page to fix a band nobody
   sees until they have scrolled past ten sections is the wrong trade; the async
   stylesheet is exactly right for below-the-fold content.

   Keep the two copies in step. */
.post-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-7) var(--sp-6); grid-template-columns: 1fr; }
.post-card { display: flex; flex-direction: column; }
.post-card__media { display: block; aspect-ratio: 16 / 9; background: var(--surface); border-radius: var(--radius); overflow: hidden; }
.post-card__img { width: 100%; height: 100%; object-fit: cover; }
.post-card__body { padding-top: var(--sp-3); }
.post-card__cat { display: inline-block; color: var(--muted); text-transform: uppercase; letter-spacing: 0.1em; font-size: var(--fs-300); font-weight: 700; padding-block: 0.3rem; }
.post-card__cat:hover { color: var(--accent); }
.post-card__title { font-size: var(--fs-600); font-weight: 700; line-height: 1.2; margin: var(--sp-2) 0; }
.post-card__title a:hover { color: var(--accent); }
.post-card__excerpt { color: var(--muted); margin: 0 0 var(--sp-4); }
@media (min-width: 48rem) { .post-grid { grid-template-columns: repeat(2, 1fr); } }


/* ---------- Mini of the Month --------------------------------------------
   One compact card above the signup block. The well is square and the image is
   contained rather than cropped, matching the product cards: this catalogue
   arrives on every background there is, and a centre crop decapitates the
   tightly framed shots. */
.motm { display: grid; gap: var(--sp-5); align-items: center; border: 1px solid var(--stage-edge); border-radius: var(--radius); background: var(--stage); padding: var(--sp-5); }
.motm__media { aspect-ratio: 1; background: var(--plinth); border-radius: var(--radius-sm); overflow: hidden; display: grid; place-items: center; }
.motm__img { width: 100%; height: 100%; object-fit: contain; }
.motm__eyebrow { color: var(--accent); font-size: var(--fs-300); text-transform: uppercase; letter-spacing: .12em; margin: 0 0 var(--sp-2); }
.motm__title { font-size: var(--fs-700); margin: 0 0 var(--sp-3); }
.motm__price { margin: 0 0 var(--sp-3); display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }
.motm__price del { color: var(--muted); }
.motm__price ins { text-decoration: none; font-weight: 700; color: var(--accent); font-size: var(--fs-500); }
.motm__text { color: var(--glow-200); margin: 0 0 var(--sp-5); }
.motm__cta { align-self: start; }
@media (min-width: 48rem) {
	.motm { grid-template-columns: 14rem 1fr; gap: var(--sp-6); padding: var(--sp-6); }
}

/* Post-purchase nudge. Deliberately quiet: they have already paid. */
.newsletter-nudge { margin: var(--sp-5) 0 0; font-size: var(--fs-300); color: var(--muted); }
.newsletter-nudge a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }

/* WCAG 2.5.8. WooCommerce ships .show-password-input at 22x22; it is core markup we
   do not template-override, so it is corrected here rather than in a copied file. */
.show-password-input,
.woocommerce form .show-password-input {
	width: 24px; height: 24px; min-width: 24px; min-height: 24px;
	background-position: center; background-size: 16px 16px;
}
