/*
Theme Name: Nullifier
Theme URI: https://nullifier.io
Description: Nullifier — independent apparel label. Black, white, electric blue. Child theme of Twenty Twenty-Five.
Author: Nullifier
Version: 1.1.7
Template: twentytwentyfive
Requires at least: 6.6
Tested up to: 6.8
Requires PHP: 7.4
Text Domain: nullifier
*/

/* ==========================================================================
   NULLIFIER
   Colour and type live in theme.json. This file is for the details
   theme.json can't reach — WooCommerce internals, hover states, fine tuning.
   ========================================================================== */

:root {
	--nf-black: #0a0a0a;
	--nf-white: #ffffff;
	--nf-blue: #0000fe;
	--nf-blue-lit: #6b8aff;
	--nf-surface: #141414;
	--nf-line: #262626;
	--nf-muted: #a1a1a1;
	--nf-ease: cubic-bezier(0.2, 0.7, 0.3, 1);

	/* One gutter, used everywhere the page meets the edge of the screen. */
	--nf-gutter: clamp(1.25rem, 4vw, 3rem);

	/*
	 * The two fixed strips above the hero, now that the ticker has moved to
	 * the very top of the page. Order on arrival is ticker, header, hero, so
	 * the hero subtracts both and the first screen is exactly a screen.
	 *
	 * The ticker's height is set outright rather than left to fall out of
	 * padding and line-height, so this number is a fact rather than an
	 * estimate — see the note on .nf-ticker. The header is measured: 69px.
	 * Re-measure if either is restyled.
	 */
	--nf-header-h: 69px;
	--nf-ticker-h: 28px;
}

@media (max-width: 600px) {
	:root {
		/* The header stacks the wordmark above the nav below this width. */
		--nf-header-h: 94px;
	}
}

/* --- Foundations --------------------------------------------------------- */

html {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

body {
	background-color: var(--nf-black);
	color: var(--nf-white);
}

::selection {
	background: var(--nf-blue);
	color: var(--nf-white);
}

/* Visible focus. Keyboard users and screen readers depend on this —
   never remove it, only restyle it. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
	outline: 2px solid var(--nf-blue-lit);
	outline-offset: 3px;
}

/* --- Links --------------------------------------------------------------- */

a {
	text-decoration-thickness: 1px;
	text-underline-offset: 0.2em;
	transition: color 0.18s var(--nf-ease);
}

/*
 * WHITE TEXT, BLUE LINE. THE SAME EVERYWHERE.
 *
 * Links used to be blue and turn white on hover, which is the opposite of the
 * header and of the product grids, and it put the accent on every noun in a
 * paragraph — on the About page a sentence mentioning the Terms page and an
 * email address had two blue words in it competing with the writing.
 *
 * So the words are white like the words around them, and the blue is the line
 * that wipes in underneath when you point at one: the same gesture, the same
 * 0.25s, the same easing as the navigation. Blue means "this is what you are
 * pointing at", and nothing else.
 *
 * Drawn as a background gradient rather than ::after, because some of these
 * links already use their own pseudo-elements and because a background needs
 * no positioning context — it cannot re-anchor anything the way position:
 * relative on an anchor can.
 */
.wp-site-blocks a:where(:not(.wp-element-button):not(.wp-block-button__link)) {
	color: var(--nf-white);
}

.wp-site-blocks a:where(:not(.wp-element-button):not(.wp-block-button__link)):visited {
	color: var(--nf-white);
	text-decoration-color: transparent;
}

/*
 * The line itself, in page copy only.
 *
 * Scoped to the content rather than to every link on the site, because the
 * navigation, the product cards and the tile in the bag each draw their own
 * and would otherwise end up with two lines. The exclusions are the ones that
 * are not really links at all: buttons, and the anchor that wraps a whole
 * product tile — a gradient on that would rule a line under the photograph.
 */
.entry-content a:where(
	:not(.wp-element-button):not(.wp-block-button__link):not(.wc-block-grid__product-link)
) {
	text-decoration: none;
	background-image: linear-gradient( var(--nf-blue-lit), var(--nf-blue-lit) );
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0% 1px;
	transition: background-size 0.25s var(--nf-ease);
}

.entry-content a:where(
	:not(.wp-element-button):not(.wp-block-button__link):not(.wc-block-grid__product-link)
):hover,
.entry-content a:where(
	:not(.wp-element-button):not(.wp-block-button__link):not(.wc-block-grid__product-link)
):focus-visible {
	background-size: 100% 1px;
}

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

.wp-element-button,
.wp-block-button__link,
button,
input[type="submit"],
.woocommerce a.button,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce #respond input#submit,
.wc-block-components-button {
	font-family: "Outfit", system-ui, sans-serif;
	font-weight: 600;
	font-size: 0.875rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	border-radius: 0;
	border: 1px solid transparent;
	padding: 1rem 2rem;
	line-height: 1;
	cursor: pointer;
	transition: background-color 0.18s var(--nf-ease), color 0.18s var(--nf-ease),
		border-color 0.18s var(--nf-ease);
}

/* Primary — blue fill, white type. 8.6:1 contrast. */
.wp-element-button,
.wp-block-button__link,
.woocommerce a.button.alt,
.woocommerce button.button.alt,
.woocommerce #respond input#submit,
.wc-block-components-button:not(.is-secondary) {
	background-color: var(--nf-blue);
	color: var(--nf-white);
}

.wp-element-button:hover,
.wp-block-button__link:hover,
.woocommerce a.button.alt:hover,
.woocommerce button.button.alt:hover,
.woocommerce #respond input#submit:hover,
.wc-block-components-button:not(.is-secondary):hover {
	background-color: var(--nf-white);
	color: var(--nf-black);
}

/* Secondary — outline */
.is-style-outline > .wp-block-button__link,
.woocommerce a.button:not(.alt),
.woocommerce button.button:not(.alt) {
	background-color: transparent;
	color: var(--nf-white);
	border-color: var(--nf-line);
}

.is-style-outline > .wp-block-button__link:hover,
.woocommerce a.button:not(.alt):hover,
.woocommerce button.button:not(.alt):hover {
	background-color: var(--nf-white);
	color: var(--nf-black);
	border-color: var(--nf-white);
}

/* --- Type detail --------------------------------------------------------- */

h1, h2, h3,
.wp-block-post-title,
.wp-block-heading {
	text-wrap: balance;
}

/* Small uppercase label — use as a class on any block */
.nf-label {
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--nf-muted);
}

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

input[type="text"],
input[type="email"],
input[type="url"],
input[type="password"],
input[type="search"],
input[type="tel"],
input[type="number"],
select,
textarea,
.wc-block-components-text-input input {
	background-color: var(--nf-surface);
	border: 1px solid var(--nf-line);
	border-radius: 0;
	color: var(--nf-white);
	padding: 0.9rem 1rem;
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 1rem;
}

input::placeholder,
textarea::placeholder {
	color: var(--nf-muted);
	opacity: 1;
}

/*
 * Same doubled-outline problem as the sort control, everywhere else: the
 * browser's own outline sits directly against our border and reads as two
 * mismatched boxes. One indicator instead — the border brightens and a
 * box-shadow hugs it, so focus is obvious without looking broken.
 */
input:focus,
select:focus,
textarea:focus {
	outline: none;
	border-color: var(--nf-blue-lit);
}

input:focus-visible,
select:focus-visible,
textarea:focus-visible {
	outline: none;
	border-color: var(--nf-blue-lit);
	box-shadow: 0 0 0 1px var(--nf-blue-lit);
}

/* ==========================================================================
   WOOCOMMERCE
   ========================================================================== */

/* --- Product grid -------------------------------------------------------- */

.woocommerce ul.products li.product,
.wc-block-grid__product,
.wp-block-woocommerce-product-template li {
	text-align: left;
}

.woocommerce ul.products li.product a img,
.wc-block-grid__product-image img,
.wc-block-components-product-image img {
	border-radius: 0;
	background-color: var(--nf-surface);
	transition: opacity 0.3s var(--nf-ease);
}

.woocommerce ul.products li.product:hover a img,
.wc-block-grid__product:hover .wc-block-grid__product-image img {
	opacity: 0.82;
}

.woocommerce ul.products li.product .woocommerce-loop-product__title,
.wc-block-grid__product-title,
.wc-block-components-product-name {
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 1rem !important;
	font-weight: 500;
	letter-spacing: -0.01em;
	color: var(--nf-white);
	padding: 0.75rem 0 0.25rem !important;
}

/* --- Visited links ------------------------------------------------------- *
 *
 * NOTHING ON THIS SITE CHANGES COLOUR BECAUSE YOU HAVE BEEN THERE.
 *
 * The product grid was rendering some names white and others blue, which read
 * as a mistake rather than as information — and it was one. Every title was
 * styled for the default state only, so a browser's visited colour showed
 * through on the ones that had been opened, and the grid looked like a
 * half-finished list of hyperlinks.
 *
 * Visited is the wrong thing for a shop to signal anyway. On an article index
 * it tells you what you have already read, which is useful. On a catalogue it
 * tells a customer they looked at a hoodie once, which is not, and it does it
 * by changing how the product is presented — the pieces you were most
 * interested in end up looking different from the rest.
 *
 * So blue is reserved for the states that mean something is happening now:
 * hover, focus and active. Anything else stays the colour it was.
 *
 * Written with :where() so it adds no specificity and cannot outrank a
 * deliberate rule elsewhere; `color: inherit` makes a visited link take
 * whatever colour its own unvisited rule already gave it, rather than naming
 * a colour here that would then need keeping in step with the palette.
 */
:where(a:visited) {
	color: inherit;
}

/*
 * The shop archive renders through WooCommerce's *block* product template,
 * not the classic `ul.products` markup — so the card is `.wc-block-product`
 * with a `.wp-block-post-title` inside, and none of the classic selectors
 * above ever match it. Two consequences worth undoing:
 *
 * 1. The product name is an anchor, so it inherits the global link colour
 *    and every product in the grid renders in blue. It is legible (6.3:1 on
 *    our black) but it reads as a list of hyperlinks rather than a catalogue.
 *    Names in white, blue kept for hover — the accent should mark the thing
 *    you are about to interact with, not every noun on the page.
 * 2. The block template hard-centres its text. The cards were designed
 *    left-aligned, which is how the price sits under the name rather than
 *    floating away from it.
 */

body .wc-block-product .wp-block-post-title,
body .wc-block-product .wp-block-post-title a,
body .wc-block-product .wp-block-post-title a:visited,
body .wp-block-woocommerce-product-template .wp-block-post-title a,
body .wp-block-woocommerce-product-template .wp-block-post-title a:visited {
	color: var(--nf-white);
	text-decoration: none;
	font-weight: 500;
	letter-spacing: -0.01em;
}

/* --- The same line as the header nav, wiping in from the left ------------ *
 *
 * WHY THIS IS A BACKGROUND AND NOT A PSEUDO-ELEMENT
 *
 * The header does it with ::after — a 1px bar scaled from 0 to 1 on hover. The
 * same trick cannot be used here, because the title's ::after is already spoken
 * for: it is the stretched box that makes the whole card clickable. Using it
 * for a line would cost the card its click target, and moving the line to
 * ::before would need position:relative on the anchor, which would re-anchor
 * that stretched box to the text instead of the card and break it just as
 * thoroughly.
 *
 * A background gradient grown from 0% to 100% width gives the identical wipe
 * with no pseudo-element at all, and the same duration and easing so the two
 * read as one behaviour rather than two things that happen to be blue.
 *
 * It answers to the CARD's hover, not the link's, because the whole card is
 * the target — the line should appear wherever the customer is actually
 * pointing.
 *
 * THE SELECTOR LIST IS LONGER THAN IT NEEDS TO BE, ON PURPOSE
 *
 * The "New in" strip under the bag is WooCommerce's cross-sells, and which
 * markup it renders depends on whether the blocks cart or the classic one is
 * in use and on the WooCommerce version. Rather than pick one and find out
 * later, every name it plausibly uses is listed. A selector that matches
 * nothing costs nothing; a grid whose links behave differently from every
 * other grid on the site costs a customer's confidence in the page.
 */
body .wc-block-product .wp-block-post-title a,
body .wp-block-woocommerce-product-template .wp-block-post-title a,
body .wc-block-cart-cross-sells .wp-block-post-title a,
body .wc-block-cart-cross-sells-product__product-title a,
body .cross-sells .woocommerce-loop-product__title a {
	background-image: linear-gradient( var(--nf-blue-lit), var(--nf-blue-lit) );
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0% 1px;
	transition: background-size 0.25s var(--nf-ease), color 0.2s ease;
	text-decoration: none;
}

body .wc-block-product:hover .wp-block-post-title a,
body .wc-block-product .wp-block-post-title a:hover,
body .wc-block-product .wp-block-post-title a:focus-visible,
body .wp-block-woocommerce-product-template .wp-block-post-title a:focus-visible,
body .wc-block-cart-cross-sells .wp-block-post-title a:hover,
body .wc-block-cart-cross-sells .wp-block-post-title a:focus-visible,
body .wc-block-cart-cross-sells-product__product-title a:hover,
body .wc-block-cart-cross-sells-product__product-title a:focus-visible,
body .cross-sells .woocommerce-loop-product__title a:hover,
body .cross-sells .woocommerce-loop-product__title a:focus-visible {
	background-size: 100% 1px;
}

/*
 * THE TEXT STAYS WHITE. ONLY THE LINE IS BLUE.
 *
 * The name turning blue as well was left over from before there was a line to
 * do the work, and it made the two behaviours different: in the header the
 * label holds still and a blue rule wipes underneath it, while here the whole
 * thing changed colour. One gesture, two meanings.
 *
 * The line alone is also the better signal. The product name is information —
 * it should look the same whether or not a cursor happens to be near it — and
 * the blue is the accent saying "this is what you are pointing at", which is
 * exactly one job.
 */

/* --- The "New in" grid under an empty bag -------------------------------- *
 *
 * A different block from the cross-sells, and structurally different in the one
 * way that matters: the WHOLE TILE is a single link, and the title inside it is
 * a div rather than an anchor.
 *
 *   li.wc-block-grid__product
 *     a.wc-block-grid__product-link
 *       div.wc-block-grid__product-image
 *       div.wc-block-grid__product-title
 *
 * So the rules written for the other grids matched nothing here, and what was
 * on screen was WooCommerce's untouched default. Read off the page rather than
 * guessed at, after two rounds of guessing.
 *
 * The line is drawn on the title and triggered by hovering the tile, which is
 * the thing that is actually clickable. fit-content keeps the line the width of
 * the words instead of the width of the column — a block-level div would
 * otherwise underline the empty space after a short name.
 */

body .wc-block-grid__product-link,
body .wc-block-grid__product-link:hover,
body .wc-block-grid__product-link:focus,
body .wc-block-grid__product-link:visited {
	text-decoration: none;
	text-decoration-color: transparent;
	color: var(--nf-white);
}

body .wc-block-grid__product-title {
	width: fit-content;
	max-width: 100%;
	color: var(--nf-white);
	background-image: linear-gradient( var(--nf-blue-lit), var(--nf-blue-lit) );
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0% 1px;
	transition: background-size 0.25s var(--nf-ease);
}

body .wc-block-grid__product:hover .wc-block-grid__product-title,
body .wc-block-grid__product-link:focus-visible .wc-block-grid__product-title {
	background-size: 100% 1px;
}

/*
 * Whatever underline a visited link is given, made invisible.
 *
 * Browsers restrict what :visited may change — for privacy, a page must not be
 * able to measure it — and the short list is colours. text-decoration-line is
 * NOT on it, so a visited underline cannot be removed by setting it to none.
 * Its COLOUR can be changed, though, so transparent is the way to take a line
 * off that refuses to come off.
 */
body .wc-block-product .wp-block-post-title a:visited,
body .wp-block-woocommerce-product-template .wp-block-post-title a:visited,
body .wc-block-cart-cross-sells .wp-block-post-title a:visited,
body .wc-block-cart-cross-sells-product__product-title a:visited,
body .cross-sells .woocommerce-loop-product__title a:visited {
	text-decoration-color: transparent;
	color: var(--nf-white);
}

body .wc-block-product,
body .wc-block-product .wp-block-post-title,
body .wc-block-product .wp-block-woocommerce-product-price,
body .wc-block-product .wc-block-components-product-price,
body .wc-block-product .wp-block-woocommerce-product-button {
	text-align: left;
}

/*
 * The grid has no add-to-cart button any more — see nullifier_hide_grid_button()
 * in functions.php. The whole card is the link instead, which is both a bigger
 * target and what people already expect from a product grid. The stretched
 * pseudo-element on the title's anchor does that without wrapping the markup
 * in an outer <a>, which would nest links inside links.
 */

body .wc-block-product {
	position: relative;
}

body .wc-block-product .wp-block-post-title a::after {
	content: "";
	position: absolute;
	inset: 0;
}

/*
 * Hovering the card wipes the line in, exactly as hovering the link does. The
 * colour change that used to be here went with it — see above.
 */
body .wc-block-product:hover .wp-block-post-title a {
	background-size: 100% 1px;
}

body .wc-block-product .wp-block-woocommerce-product-price {
	padding-bottom: 0.5rem;
}

/* --- Price --------------------------------------------------------------- */

.woocommerce ul.products li.product .price,
.wc-block-grid__product-price,
.woocommerce div.product p.price,
.wc-block-components-product-price {
	color: var(--nf-muted);
	font-size: 0.9375rem;
	font-weight: 400;
}

.woocommerce div.product p.price {
	color: var(--nf-white);
	font-size: 1.5rem;
	font-weight: 500;
}

.woocommerce ul.products li.product .price del,
.wc-block-components-product-price del {
	color: var(--nf-muted);
	opacity: 0.6;
	margin-right: 0.4em;
}

.woocommerce ul.products li.product .price ins,
.wc-block-components-product-price ins {
	color: var(--nf-blue-lit);
	text-decoration: none;
	font-weight: 500;
}

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

.woocommerce span.onsale,
.wc-block-grid__product-onsale {
	background-color: var(--nf-blue);
	color: var(--nf-white);
	border: 0;
	border-radius: 0;
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 0.6875rem;
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	line-height: 1;
	padding: 0.5rem 0.75rem;
	min-height: 0;
	min-width: 0;
	top: 0;
	left: 0;
	right: auto;
	margin: 0;
}

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

.woocommerce div.product .product_title {
	letter-spacing: -0.03em;
}

.woocommerce div.product .woocommerce-tabs ul.tabs {
	border-bottom: 1px solid var(--nf-line);
	padding: 0;
	margin: 0 0 2rem;
}

.woocommerce div.product .woocommerce-tabs ul.tabs::before {
	display: none;
}

.woocommerce div.product .woocommerce-tabs ul.tabs li {
	background: transparent;
	border: 0;
	border-radius: 0;
	margin: 0 2rem 0 0;
	padding: 0 0 0.75rem;
}

.woocommerce div.product .woocommerce-tabs ul.tabs li::before,
.woocommerce div.product .woocommerce-tabs ul.tabs li::after {
	display: none;
}

.woocommerce div.product .woocommerce-tabs ul.tabs li a {
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--nf-muted);
	padding: 0;
}

.woocommerce div.product .woocommerce-tabs ul.tabs li.active a,
.woocommerce div.product .woocommerce-tabs ul.tabs li a:hover {
	color: var(--nf-white);
}

.woocommerce div.product .woocommerce-tabs ul.tabs li.active {
	box-shadow: inset 0 -2px 0 var(--nf-blue-lit);
}

/* Variation dropdowns — size and colour pickers */
.woocommerce div.product form.cart .variations {
	margin-bottom: 1.5rem;
}

.woocommerce div.product form.cart .variations label {
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--nf-muted);
}

.woocommerce div.product form.cart .variations select {
	min-width: 14rem;
}

/* Quantity */
.woocommerce .quantity .qty {
	background-color: var(--nf-surface);
	border: 1px solid var(--nf-line);
	color: var(--nf-white);
	border-radius: 0;
	padding: 0.9rem 0.5rem;
}

/* --- Notices ------------------------------------------------------------- */
/* WooCommerce ships these with a pale background and its own colour rules
   that beat a plain class selector, hence the specificity here. Left as
   light-on-light they are literally unreadable on this theme. */

.woocommerce-message,
.woocommerce-info,
.woocommerce-error,
.woocommerce-noreviews,
.wc-block-components-notice-banner,
.woocommerce .woocommerce-message,
.woocommerce .woocommerce-info,
.woocommerce .woocommerce-error {
	background-color: var(--nf-surface) !important;
	border: 1px solid var(--nf-line) !important;
	border-top: 2px solid var(--nf-blue-lit) !important;
	border-radius: 0 !important;
	color: var(--nf-white) !important;
	font-size: 0.9375rem;
	line-height: 1.5;
	padding: 1.1rem 3rem 1.1rem 1.25rem !important;
	margin: 0 0 1rem !important;
	list-style: none;
}

.woocommerce-message *,
.woocommerce-info *,
.woocommerce-error *,
.wc-block-components-notice-banner * {
	color: var(--nf-white) !important;
}

.woocommerce-error {
	border-top-color: var(--nf-crit, #ff5a5a) !important;
}

.woocommerce-message::before,
.woocommerce-info::before,
.woocommerce-error::before {
	display: none !important;
}

.woocommerce-message .button,
.woocommerce-info .button {
	float: none !important;
	display: inline-block;
	margin-top: 0.85rem;
	padding: 0.7rem 1.25rem !important;
	font-size: 0.75rem !important;
}

/* --- Floating notices ---------------------------------------------------- */

.nf-toast-host {
	position: fixed;
	right: clamp(0.75rem, 2vw, 1.5rem);
	bottom: clamp(0.75rem, 2vw, 1.5rem);
	z-index: 300;
	width: min(360px, calc(100vw - 1.5rem));
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	pointer-events: none;
}

.nf-toast-host > * {
	pointer-events: auto;
	position: relative;
	margin: 0 !important;
	box-shadow: 0 14px 36px rgba(0, 0, 0, 0.6);
	animation: nf-toast-in 0.28s var(--nf-ease) both;
}

.nf-toast-host .is-going {
	animation: nf-toast-out 0.32s var(--nf-ease) both;
}

@keyframes nf-toast-in {
	from {
		opacity: 0;
		transform: translateY(12px);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

@keyframes nf-toast-out {
	to {
		opacity: 0;
		transform: translateY(6px);
	}
}

.nf-toast-close {
	position: absolute;
	top: 0.4rem;
	right: 0.4rem;
	width: 1.9rem;
	height: 1.9rem;
	padding: 0 !important;
	background: transparent !important;
	border: 0 !important;
	color: var(--nf-muted) !important;
	font-size: 1.35rem !important;
	line-height: 1;
	letter-spacing: 0 !important;
	cursor: pointer;
}

.nf-toast-close:hover {
	color: var(--nf-white) !important;
	background: transparent !important;
}

/* The action inside a notice is the whole point of it, so it gets treated
   as a real button rather than a faint link. */
.woocommerce-message a.button,
.woocommerce-info a.button,
.nf-toast-host a.button {
	display: inline-block !important;
	float: none !important;
	margin: 0.9rem 0 0 !important;
	padding: 0.75rem 1.4rem !important;
	background: var(--nf-blue) !important;
	border: 1px solid var(--nf-blue) !important;
	color: var(--nf-white) !important;
	font-size: 0.75rem !important;
	font-weight: 600 !important;
	letter-spacing: 0.1em !important;
	text-transform: uppercase;
	text-decoration: none !important;
	opacity: 1 !important;
}

.woocommerce-message a.button:hover,
.nf-toast-host a.button:hover {
	background: var(--nf-white) !important;
	border-color: var(--nf-white) !important;
	color: var(--nf-black) !important;
}

@media (prefers-reduced-motion: reduce) {
	.nf-toast-host > *,
	.nf-toast-host .is-going {
		animation: none;
	}
}

/* --- Cart & checkout ----------------------------------------------------- */

.woocommerce table.shop_table,
.wc-block-cart-items {
	border: 1px solid var(--nf-line);
	border-radius: 0;
	border-collapse: collapse;
}

.woocommerce table.shop_table th,
.woocommerce table.shop_table td {
	border-color: var(--nf-line);
}

.woocommerce table.shop_table thead th {
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--nf-muted);
}

.wc-block-components-totals-item__value,
.order-total .amount {
	color: var(--nf-white);
	font-weight: 600;
}

/* --- Breadcrumb ---------------------------------------------------------- */

.woocommerce .woocommerce-breadcrumb {
	font-size: 0.8125rem;
	color: var(--nf-muted);
	margin-bottom: 2rem;
}

.woocommerce .woocommerce-breadcrumb a {
	color: var(--nf-muted);
}

.woocommerce .woocommerce-breadcrumb a:hover {
	color: var(--nf-white);
}

/* --- Result count / ordering -------------------------------------------- */

.woocommerce .woocommerce-result-count {
	font-size: 0.8125rem;
	color: var(--nf-muted);
}

.woocommerce .woocommerce-ordering select {
	font-size: 0.8125rem;
	padding: 0.6rem 0.75rem;
}

/* --- Sort by ------------------------------------------------------------- */

.nf-orderby {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	margin: 0;
}

.nf-orderby__label {
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--nf-muted);
	white-space: nowrap;
}

body .nf-orderby__select {
	appearance: none;
	-webkit-appearance: none;
	background-color: transparent;
	border: 0;
	border-bottom: 1px solid rgba(255, 255, 255, 0.28);
	border-radius: 0;
	padding: 0.5rem 1.75rem 0.5rem 0;
	color: var(--nf-white);
	font-size: 0.8125rem;
	line-height: 1.2;
	cursor: pointer;
	/* Chevron drawn in, since removing the appearance removes the native one. */
	background-image: linear-gradient(45deg, transparent 50%, var(--nf-muted) 50%),
		linear-gradient(135deg, var(--nf-muted) 50%, transparent 50%);
	background-position: calc(100% - 12px) 55%, calc(100% - 7px) 55%;
	background-size: 5px 5px, 5px 5px;
	background-repeat: no-repeat;
	transition: border-color 0.2s var(--nf-ease);
}

body .nf-orderby__select:hover {
	border-bottom-color: var(--nf-white);
}

/*
 * One focus line, not two.
 *
 * The browser draws its own outline and the field draws a border, and with
 * no offset between them they stacked into a doubled box that looked like a
 * rendering fault. Suppressing the outline entirely would strip the focus
 * state from keyboard users, so the border itself becomes the indicator:
 * a box-shadow sits flush outside it in the same colour, reading as a single
 * thicker edge.
 */
body .nf-orderby__select:focus {
	outline: none;
}

body .nf-orderby__select:focus-visible {
	outline: none;
	border-bottom-color: var(--nf-blue-lit);
	box-shadow: 0 1px 0 0 var(--nf-blue-lit);
}

/* The dropdown list itself is drawn by the OS — dark options on dark chrome. */
body .nf-orderby__select option {
	background-color: var(--nf-surface);
	color: var(--nf-white);
}

@media (max-width: 600px) {
	.nf-orderby {
		width: 100%;
		justify-content: space-between;
	}
}

/* --- Sort by: enhanced menu ---------------------------------------------- */

/*
 * Once the script runs, the native select is hidden and a button plus panel
 * take its place. The select is still in the DOM and still holds the value —
 * hidden with clip rather than display:none so it stays focusable if anything
 * ever needs it, and so the form still submits the right field.
 */

.nf-sort {
	position: relative;
	display: flex;
	align-items: center;
	gap: 0;
}

.nf-sort .nf-orderby__label,
.nf-sort .nf-sort__native {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.nf-sort__trigger {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	background: none;
	border: 0;
	padding: 0.5rem 0;
	margin: 0;
	color: var(--nf-white);
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 0.875rem;
	font-weight: 500;
	line-height: 1.2;
	cursor: pointer;
}

.nf-sort__value {
	color: var(--nf-muted);
	font-weight: 400;
}

/* Chevron drawn from a rotated corner so there is no icon file to load. */
.nf-sort__chevron {
	width: 0.5rem;
	height: 0.5rem;
	margin-left: 0.15rem;
	border-right: 1.5px solid currentColor;
	border-bottom: 1.5px solid currentColor;
	transform: translateY(-2px) rotate(45deg);
	transition: transform 0.2s var(--nf-ease);
}

.nf-sort.is-open .nf-sort__chevron {
	transform: translateY(2px) rotate(-135deg);
}

.nf-sort__trigger:focus-visible {
	outline: 2px solid var(--nf-blue-lit);
	outline-offset: 4px;
}

.nf-sort__menu {
	position: absolute;
	top: calc(100% + 0.65rem);
	right: 0;
	z-index: 40;
	min-width: 12rem;
	margin: 0;
	padding: 0.4rem 0;
	list-style: none;
	background-color: var(--nf-surface);
	border: 1px solid var(--nf-line);
	box-shadow: 0 18px 40px rgba(0, 0, 0, 0.55);
}

.nf-sort__option {
	padding: 0.7rem 1.15rem;
	font-size: 0.875rem;
	line-height: 1.2;
	color: var(--nf-white);
	text-align: right;
	white-space: nowrap;
	cursor: pointer;
	transition: background-color 0.15s var(--nf-ease), color 0.15s var(--nf-ease);
}

.nf-sort__option:hover,
.nf-sort__option:focus-visible {
	outline: none;
	background-color: rgba(255, 255, 255, 0.06);
}

.nf-sort__option.is-selected {
	color: var(--nf-blue-lit);
}

@media (max-width: 400px) {
	.nf-sort__menu {
		min-width: 10.5rem;
	}
}

/* --- Reduced motion ------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ==========================================================================
   LAYOUT — homepage, header, footer
   ========================================================================== */

.nf-container,
.nf-hero__inner,
.nf-section__inner,
.nf-band__inner,
.nf-manifesto__inner,
.nf-community__inner,
.nf-footer__top,
.nf-footer__bar,
.nf-cofoot__inner {
	width: 100%;
	max-width: 1400px;
	margin-inline: auto;
	padding-inline: var(--nf-gutter);
	box-sizing: border-box;
}

/*
 * Every template except the front page comes from the parent theme, and none
 * of them carry a gutter: root padding is off and theme.json sets padding to
 * zero, so on a phone the shop heading, the breadcrumb and the product cards
 * all sat hard against the left edge of the screen. The front page is excluded
 * because its sections are deliberately full-bleed and provide their own
 * padding on the inner wrappers.
 */
body:not(.home) .wp-site-blocks > main {
	padding-inline: var(--nf-gutter);
	box-sizing: border-box;
}

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

/*
 * Sticky goes on the wrapper, not on .nf-header.
 *
 * WordPress renders a template part inside an element of its own, so the
 * markup is <header class="wp-block-template-part"><header class="nf-header">.
 * position:sticky was on the inner one, which sticks relative to its parent —
 * and its parent is exactly its own height, so it had nowhere to travel. The
 * header scrolled away with the page and always had; measured at scrollY 400
 * it sat at top: -372.
 *
 * That it was meant to stick is not a guess: .nf-header is a translucent black
 * with a backdrop blur behind it, which is only worth paying for on a bar that
 * has content passing underneath it.
 *
 * So the wrapper sticks and .nf-header keeps the looks. Site-wide, since every
 * template pulls in the same part.
 */
.wp-site-blocks > header.wp-block-template-part {
	position: sticky;
	top: 0;
	z-index: 50;
}

.nf-header {
	background-color: rgba(10, 10, 10, 0.86);
	backdrop-filter: saturate(140%) blur(12px);
	-webkit-backdrop-filter: saturate(140%) blur(12px);
	border-bottom: 1px solid var(--nf-line);
}

/*
 * THE HEADER IS NOT CONTENT, SO IT DOES NOT SIT IN THE CONTENT COLUMN.
 *
 * Every other wrapper on the site shares one rule: 1400px, centred. The header
 * used to as well, which on a wide screen left the lockup starting 300px in
 * from the edge with nothing to its left — the bar looked like it was floating
 * in the middle of a black field rather than framing the page.
 *
 * It now runs the full width and keeps only the gutter, so the mark sits at the
 * left edge and the bag at the right, with the bar spanning between them. That
 * is what a header is: the frame, not a thing inside the frame.
 *
 * The trade is real and worth naming — the lockup no longer lines up with the
 * hero and the sections below it, because those are still in the 1400px column.
 * Chrome at the edges with content centred is a deliberate pairing and a common
 * one, but if the broken vertical line bothers you, putting max-width back is a
 * one-line change.
 */
.nf-header__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 2rem;
	width: 100%;
	padding-inline: var(--nf-gutter);
	padding-block: 1.125rem;
	box-sizing: border-box;
}

.nf-logo {
	display: inline-flex;
	align-items: center;
	gap: 0.625rem;
	font-size: 1.0625rem;
	font-weight: 800;
	letter-spacing: 0.24em;
	text-transform: uppercase;
	color: var(--nf-white) !important;
	text-decoration: none;
	line-height: 1;
	flex-shrink: 0;
}

/*
 * The mark, left of the wordmark.
 *
 * Sized by height rather than width, so it lines up with the type no matter how
 * the file is cropped. The glow is baked into the image, which means the visible
 * circle is noticeably smaller than the box — 2.25rem of box reads as roughly
 * the cap height of the wordmark doubled, which is the balance we want.
 *
 * The image is white-on-transparent, not white-on-black. A black square would
 * have sat a shade off the header behind it and shown its own edge; alpha
 * carries the glow's falloff instead, so it belongs to the header rather than
 * sitting on top of it.
 *
 * alt="" on purpose — the link already says NULLIFIER right next to it, so
 * naming the image again would have a screen reader announce the brand twice
 * for one link.
 */
/*
 * Scoped to .nf-header on purpose, and that is the whole fix.
 *
 * WooCommerce ships `.woocommerce-page img { height: auto }`, which matches
 * EVERY image on a shop page — the header logo included, because the selector
 * is about the body class, not about anything in the product grid. Two classes
 * beat one class and one element, so `.nf-header .nf-logo__mark` wins on
 * specificity without reaching for !important.
 *
 * A bare `.nf-logo__mark` lost that fight, which is why the mark was correct on
 * the front page and rendered at its full 120px on every page WooCommerce
 * touched.
 */
.nf-header .nf-logo__mark,
.nf-cohead .nf-logo__mark {
	display: block;
	width: auto;
	height: 2.25rem;
	max-width: none;
	flex-shrink: 0;
}

/*
 * Pulls the wordmark back by its own trailing letter-space.
 *
 * letter-spacing adds its gap AFTER the final R too, which with a flex gap on
 * one side only would leave the mark visibly closer to the N than the nav is to
 * the R. Nobody would name it, but the lockup looks off-centre until it is gone.
 */
.nf-logo__word {
	margin-right: -0.24em;
}

.nf-nav {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	justify-content: flex-end;
	row-gap: 0.5rem;
	gap: clamp(1.25rem, 2.6vw, 2.5rem);
	margin-left: auto;
}

.nf-nav a {
	position: relative;
	font-size: 0.8125rem;
	font-weight: 500;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--nf-white) !important;
	text-decoration: none;
	padding-block: 0.35rem;
	white-space: nowrap;
}

.nf-nav a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 1px;
	background: var(--nf-blue-lit);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.25s var(--nf-ease);
}

.nf-nav a:hover::after {
	transform: scaleX(1);
}

/*
 * Bag reads as one of the navigation links now, not a boxed button: same
 * white, same blue rule wiping in on hover. It keeps a little extra space to
 * its left so it still sits apart as the last item, and inherits the ::after
 * rule from .nf-nav a rather than overriding it.
 */
.nf-nav__cart {
	margin-left: 0.5rem;
}

/*
 * The account link, in both of its states.
 *
 * Signed out it reads "Sign in"; signed in it reads "Hi, <name>" — which is the
 * only thing in the chrome that tells a customer whether they are signed in,
 * and therefore whether their bag and saved pieces will follow them to another
 * device. It inherits everything else from .nf-nav a.
 *
 * The greeting makes the item's width depend on somebody's name. It was capped
 * at 14 characters, which was too mean by half: "Hi, omegacandle" is fifteen,
 * so a perfectly ordinary Discord handle came out trimmed. Greeting somebody by
 * a shortened version of their own name is worse than not greeting them.
 *
 * The cap is now 32 characters — the longest a Discord username can be, plus
 * the "Hi, " — so in practice nothing is ever cut. It stays as a backstop
 * rather than a design decision, for a display name somebody has deliberately
 * filled with junk.
 *
 * What used to justify a tight cap was the nav being a single unbreakable row,
 * where one long name pushed the bag count off the end. The nav now wraps, so
 * the worst case is a second line instead of a lost bag — which is the better
 * failure by a distance.
 */
.nf-nav__account {
	white-space: nowrap;
}

.nf-nav__account.is-in {
	display: inline-block;
	max-width: 32ch;
	overflow: hidden;
	text-overflow: ellipsis;
	vertical-align: bottom;
}

/* --- Hero ---------------------------------------------------------------- */

/*
 * The first screen is exactly one screen.
 *
 * Three things share it, and since the ribbon moved to the top of the page
 * the order is now ribbon, sticky header, hero. Guessing a percentage for
 * the hero can only ever be right at one window height — too tall and
 * something falls past the fold, too short and the Midnight band's blue top
 * edge creeps up into view underneath it. Both of those happened, in that
 * order.
 *
 * So the hero does not guess. It takes the screen and gives back the two
 * fixed strips above it, which lands the hero's own bottom edge on the fold
 * at any window height, with 4px to spare so sub-pixel rounding cannot leak
 * a hairline of the band below it.
 *
 * The sum did not change when the ribbon moved — it was above the fold
 * before and it is above the fold now, just at the other end of the stack —
 * only the value of --nf-ticker-h did, from 46px to 28px.
 *
 * svh rather than vh: on phones vh is measured against the browser with its
 * toolbar collapsed, so a vh-based hero is always slightly taller than the
 * screen you can actually see — which is this same bug, permanently, on
 * mobile.
 */
/*
 * The hero photograph starts at the header, not 24px under it.
 *
 * Twenty Twenty-Five puts a block gap above every direct child of
 * .wp-site-blocks, so <main> carried a 24px top margin. Measured: the
 * header's divider sat at 69px and the hero's top edge at 93px, which drew a
 * 24px strip of page background between the navigation and the picture — a
 * seam, and a visible one, because the hero is a photograph and the strip is
 * flat black.
 *
 * Interior pages already override this margin further down (they want a small
 * gap, just not 96px of it). The front page wants none at all: the hero is
 * edge-to-edge and should read as hanging directly off the header bar.
 */
/*
 * The same gap sat between every band on the front page — ticker to header,
 * header to hero, hero to Midnight, Midnight to the manifesto — because the
 * block gap applies between siblings as well as at the top. Measured at 24px
 * in every one of those places.
 *
 * These sections are full-bleed and each carries its own internal padding, so
 * a margin between them is not spacing, it is a 24px strip of page background
 * cutting across a band of colour. It also broke the hero's arithmetic: the
 * hero gives back exactly the ticker and the header so its bottom edge lands
 * on the fold, and an extra 24px pushed everything below that down past it.
 *
 * Both levels are needed. The ticker, the header, <main> and the footer are
 * children of .wp-site-blocks; the bands are children of <main>.
 *
 * Front page only. Interior pages stack normal content blocks where the gap
 * is doing real work.
 */
body.home .wp-site-blocks > *,
body.home .wp-site-blocks > main > * {
	margin-block-start: 0 !important;
}

.nf-hero {
	position: relative;
	display: flex;
	/*
	 * Top-aligned, not centred.
	 *
	 * Centring made sense when the hero held six elements including two
	 * buttons and filled most of its own height. It now holds three short
	 * ones, and centring a short block in a full-screen box puts half the
	 * leftover space above it — so the eyebrow started a long way under the
	 * navigation and the whole hero read as floating loose rather than
	 * hanging off the header.
	 *
	 * Anchored to the top, the copy belongs to the header above it and the
	 * photograph gets the room below, which is the right way round: the
	 * figure is lower in frame anyway.
	 *
	 * This also matches what phones were already doing — the narrow-screen
	 * rule further down has always used flex-start.
	 */
	align-items: flex-start;
	min-height: max( 400px, calc( 100vh - var(--nf-header-h) - var(--nf-ticker-h) - 4px ) );
	min-height: max( 400px, calc( 100svh - var(--nf-header-h) - var(--nf-ticker-h) - 4px ) );
	border-bottom: 1px solid var(--nf-line);
	overflow: hidden;
}

/* Faint grid — texture without decoration */
.nf-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background-image:
		linear-gradient(to right, rgba(255, 255, 255, 0.035) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
	background-size: 72px 72px;
	mask-image: radial-gradient(ellipse 80% 70% at 50% 45%, #000 20%, transparent 80%);
	-webkit-mask-image: radial-gradient(ellipse 80% 70% at 50% 45%, #000 20%, transparent 80%);
	pointer-events: none;
}

/* --- Hero photograph -----------------------------------------------------
 *
 * Four stacked layers, all decorative and all aria-hidden in the template:
 *
 *   media    the photograph itself
 *   eclipse  a faint blue glow behind the wordmark, the same motif as the icon
 *   grain    film noise, so a compressed JPEG does not read as flat digital
 *   scrim    the darkening that keeps white type legible over the picture
 *
 * The scrim is the load-bearing one. The figure sits to the right of frame,
 * so the gradient is heaviest on the left where the headline goes and lifts
 * across to nearly nothing over the subject. Without it the lede drops to
 * roughly 2:1 against the brighter parts of the photograph, which fails at
 * any size; with it the text keeps a near-solid ground and the picture still
 * reads.
 *
 * Everything is painted below the grid (z-index 1) and the copy (z-index 2).
 * ------------------------------------------------------------------------- */

.nf-hero__media {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
	/*
	 * The photograph is dark, but it is also 109KB arriving over the network.
	 * Painting the brand black underneath means the hero is never a white
	 * flash and the headline is readable from the first frame.
	 */
	background-color: var(--nf-black);
	background-image: url("assets/img/hero.jpg");
	background-repeat: no-repeat;
	background-position: 72% center;
	background-size: cover;
}

.nf-hero__eclipse {
	position: absolute;
	inset: 0;
	background: radial-gradient(
		circle at 68% 42%,
		rgba(0, 0, 254, 0.18) 0%,
		rgba(0, 0, 254, 0.07) 28%,
		transparent 62%
	);
	mix-blend-mode: screen;
	pointer-events: none;
}

.nf-hero__grain {
	position: absolute;
	inset: 0;
	opacity: 0.16;
	pointer-events: none;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
	background-size: 160px 160px;
}

.nf-hero__scrim {
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-image:
		linear-gradient(
			to right,
			rgba(10, 10, 10, 0.97) 0%,
			rgba(10, 10, 10, 0.94) 26%,
			rgba(10, 10, 10, 0.7) 52%,
			rgba(10, 10, 10, 0.34) 78%,
			rgba(10, 10, 10, 0.18) 100%
		),
		linear-gradient(
			to bottom,
			rgba(10, 10, 10, 0.55) 0%,
			transparent 22%,
			transparent 62%,
			rgba(10, 10, 10, 0.85) 100%
		);
}

.nf-hero__inner {
	position: relative;
	z-index: 2;
	/*
	 * Asymmetric on purpose. With the block anchored to the top, the first
	 * value is now the actual gap under the header divider, so it is small
	 * and deliberate — close enough that the eyebrow reads as hanging off
	 * the navigation. The larger bottom value keeps the copy clear of the
	 * ribbon and leaves the lower half of the frame to the photograph.
	 */
	padding-block: clamp(1.75rem, 4vh, 3rem) clamp(3rem, 8vh, 6rem);
}

/*
 * Grey type on a photograph is a different problem from grey type on black.
 *
 * The site's muted grey (#a1a1a1) sits at a comfortable 7:1 against the black
 * ground everywhere else. Over the hero picture it was measured at 2.4:1 at
 * its worst — the spots where the photograph is brightest behind the eyebrow
 * and the lede — which is a fail at any size and reads as washed out rather
 * than quiet.
 *
 * Two changes together fix it, and both were measured rather than eyeballed:
 * the scrim was strengthened through the middle of the frame, and these two
 * lines are lifted to #d4d4d4 inside the hero only. Worst case is now 5.6:1
 * on desktop and 5.3:1 on phones. The white headline was never in trouble —
 * it measures around 9:1.
 */
.nf-hero .nf-eyebrow {
	color: #d4d4d4;
}

.nf-eyebrow {
	font-size: 0.75rem !important;
	font-weight: 600;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: var(--nf-muted);
	margin: 0 0 1.75rem;
}

.nf-hero__title {
	font-size: clamp(3.5rem, 16vw, 15rem) !important;
	font-weight: 800 !important;
	line-height: 0.82 !important;
	letter-spacing: -0.055em !important;
	margin: 0;
	color: var(--nf-white);
}

.nf-hero__lede {
	max-width: 34ch;
	margin: 2rem 0 0;
	font-size: clamp(1.0625rem, 1.6vw, 1.375rem);
	line-height: 1.5;
	/* Lifted off --nf-muted for contrast over the photograph; see the note
	   above .nf-hero .nf-eyebrow. */
	color: #d4d4d4;
}

.nf-hero__cta {
	margin-top: 2.75rem;
	gap: 0.875rem;
}

/* --- Ticker (scrolling) -------------------------------------------------- */

/*
 * A stated height, not a height that happens.
 *
 * This used to be 0.875rem of padding above and below a line of text, which
 * came out at 45.6px — a number nobody chose, and one that quietly depended
 * on whatever line-height the text inherited. The hero's height is worked out
 * by subtracting this strip from the viewport, so a value that drifts when
 * the type is restyled is a real hazard, not a tidiness point.
 *
 * So the strip is told to be 28px and the text is centred inside it. The one
 * number here and --nf-ticker-h in :root are now the same fact, and the hero
 * arithmetic cannot fall out of step with what is on screen.
 */
.nf-ticker {
	display: flex;
	align-items: center;
	height: var(--nf-ticker-h);
	background-color: var(--nf-blue);
	overflow: hidden;
}

.nf-ticker__viewport {
	overflow: hidden;
	width: 100%;
	/* The strip is a flex row now, so the viewport has to be told to take
	   the whole of it rather than shrinking to its content. */
	flex: 1 1 auto;
	min-width: 0;
	/* Fade the text out at both edges so it slides away rather than
	   getting chopped off by the viewport. */
	mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
	-webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}

.nf-ticker__track {
	display: flex;
	width: max-content;
	animation: nf-marquee 38s linear infinite;
	will-change: transform;
}

.nf-ticker:hover .nf-ticker__track {
	animation-play-state: paused;
}

.nf-ticker__group {
	display: flex;
	align-items: center;
	gap: 3.5rem;
	padding-right: 3.5rem;
	flex-shrink: 0;
}

.nf-ticker__group span {
	position: relative;
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--nf-white);
	white-space: nowrap;
}

.nf-ticker__group span::after {
	content: "";
	position: absolute;
	right: -1.75rem;
	top: 50%;
	width: 3px;
	height: 3px;
	background: rgba(255, 255, 255, 0.55);
	transform: translateY(-50%);
}

@keyframes nf-marquee {
	from {
		transform: translateX(0);
	}
	to {
		transform: translateX(-50%);
	}
}

/* Anyone who has asked their system to reduce motion gets a still,
   centred strip instead of a moving one. */
@media (prefers-reduced-motion: reduce) {
	.nf-ticker__track {
		animation: none;
		width: 100%;
		justify-content: center;
	}

	.nf-ticker__group:last-child {
		display: none;
	}

	.nf-ticker__viewport {
		mask-image: none;
		-webkit-mask-image: none;
	}
}

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

.nf-section {
	padding-block: clamp(4.5rem, 11vw, 9rem);
}

.nf-section__head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 1rem;
	margin-bottom: clamp(2.5rem, 5vw, 4rem);
	padding-bottom: 1.5rem;
	border-bottom: 1px solid var(--nf-line);
}

.nf-section__head h2 {
	margin: 0;
	font-size: clamp(2rem, 4.5vw, 3.25rem) !important;
	letter-spacing: -0.035em;
}

.nf-section__link {
	margin: 0;
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/*
 * Matches the header navigation: white, with a blue rule that wipes in from
 * the left on hover. Same gesture in both places, so "this is a link to
 * somewhere else on the site" always looks the same.
 *
 * The rule is a pseudo-element rather than a border, so it can animate its
 * scale from zero without shifting anything around it.
 */
.nf-section__link a {
	position: relative;
	display: inline-block;
	color: var(--nf-white) !important;
	text-decoration: none;
	padding-block: 0.35rem;
}

.nf-section__link a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 1px;
	background: var(--nf-blue-lit);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.25s var(--nf-ease);
}

.nf-section__link a:hover::after,
.nf-section__link a:focus-visible::after {
	transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
	.nf-section__link a::after {
		transition: none;
	}
}

/* --- Range grid ---------------------------------------------------------- */
/* Deliberately asymmetric: a lead tile plus two supporting ones. Three equal
   cards is the single most template-looking layout on the internet. */

.nf-grid {
	display: grid;
	grid-template-columns: 1.35fr 1fr;
	grid-auto-rows: minmax(0, auto);
	gap: clamp(0.75rem, 1.4vw, 1.25rem);
}

.nf-tile {
	position: relative;
	display: flex;
	align-items: flex-end;
	min-height: clamp(200px, 24vw, 300px);
	padding: clamp(1.25rem, 2vw, 2rem);
	background-color: var(--nf-surface);
	border: 1px solid var(--nf-line);
	text-decoration: none !important;
	overflow: hidden;
	isolation: isolate;
	transition: border-color 0.3s var(--nf-ease), background-color 0.3s var(--nf-ease);
}

.nf-tile--lg {
	grid-row: span 2;
	min-height: clamp(420px, 50vw, 620px);
}

.nf-tile:hover {
	border-color: var(--nf-blue-lit);
	background-color: #171717;
}

/* The oversized outlined word stands in for product photography.
   Reads as a deliberate graphic, not a missing image. */
.nf-tile__ghost {
	position: absolute;
	inset: auto auto -0.18em -0.06em;
	z-index: -1;
	font-size: clamp(4.5rem, 11vw, 11rem);
	font-weight: 800;
	line-height: 0.8;
	letter-spacing: -0.05em;
	color: transparent;
	-webkit-text-stroke: 1px rgba(255, 255, 255, 0.16);
	user-select: none;
	transition: -webkit-text-stroke-color 0.35s var(--nf-ease), transform 0.5s var(--nf-ease);
}

.nf-tile--lg .nf-tile__ghost {
	font-size: clamp(6rem, 17vw, 17rem);
}

.nf-tile:hover .nf-tile__ghost {
	-webkit-text-stroke-color: rgba(107, 138, 255, 0.5);
	transform: translateY(-4px);
}

.nf-tile__body {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
}

.nf-tile__name {
	font-size: clamp(1.25rem, 2vw, 1.75rem);
	font-weight: 600;
	letter-spacing: -0.025em;
	color: var(--nf-white);
	line-height: 1.1;
}

.nf-tile__meta {
	font-size: 0.8125rem;
	color: var(--nf-muted);
	letter-spacing: 0.02em;
}

/* --- Blue band ----------------------------------------------------------- */

.nf-band {
	background-color: var(--nf-blue);
	padding-block: clamp(4.5rem, 10vw, 8rem);
}

.nf-band__inner {
	max-width: 1400px;
}

.nf-eyebrow--onblue {
	color: rgba(255, 255, 255, 0.72) !important;
}

.nf-band__title {
	margin: 0 !important;
	font-size: clamp(3rem, 10vw, 8rem) !important;
	font-weight: 800 !important;
	line-height: 0.85 !important;
	letter-spacing: -0.05em !important;
	color: var(--nf-white) !important;
}

.nf-band__text {
	max-width: 40ch;
	margin: 1.75rem 0 2.5rem;
	font-size: clamp(1rem, 1.6vw, 1.25rem);
	line-height: 1.5;
	color: rgba(255, 255, 255, 0.88);
}

.nf-band .wp-block-button__link {
	background-color: transparent !important;
	color: var(--nf-white) !important;
	border-color: rgba(255, 255, 255, 0.5) !important;
}

.nf-band .wp-block-button__link:hover {
	background-color: var(--nf-white) !important;
	color: var(--nf-blue) !important;
	border-color: var(--nf-white) !important;
}

/* --- Manifesto ----------------------------------------------------------- */

.nf-manifesto {
	border-top: 1px solid var(--nf-line);
}

.nf-manifesto__sub {
	max-width: 42ch;
	margin: 1.5rem 0 0;
	font-size: clamp(1rem, 1.4vw, 1.125rem);
	line-height: 1.55;
	color: var(--nf-muted);
}

.nf-manifesto__text {
	max-width: 46ch;
	margin: 0;
	font-size: clamp(1.375rem, 3vw, 2.125rem);
	font-weight: 400;
	line-height: 1.32;
	letter-spacing: -0.025em;
	color: var(--nf-white);
	text-wrap: pretty;
}

/* --- Community ----------------------------------------------------------- */

.nf-community {
	border-top: 1px solid var(--nf-line);
	text-align: center;
}

.nf-community__inner {
	display: flex;
	flex-direction: column;
	align-items: center;
}

.nf-community__title {
	margin: 0 !important;
	max-width: 18ch;
	font-size: clamp(2rem, 5vw, 3.5rem) !important;
	letter-spacing: -0.04em !important;
}

.nf-community__text {
	margin: 1.25rem 0 2.25rem;
	color: var(--nf-muted);
	font-size: 1.0625rem;
}

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

.nf-footer {
	border-top: 1px solid var(--nf-line);
	padding-top: clamp(3.5rem, 7vw, 5.5rem);
	background-color: var(--nf-black);
}

.nf-footer__cols {
	gap: clamp(2rem, 4vw, 4rem) !important;
}

.nf-footer__mark {
	margin: 0 0 1rem;
	font-size: 1rem;
	font-weight: 800;
	letter-spacing: 0.24em;
	text-transform: uppercase;
	color: var(--nf-white);
}

.nf-footer__blurb {
	margin: 0;
	max-width: 32ch;
	font-size: 0.875rem;
	line-height: 1.6;
	color: var(--nf-muted);
}

.nf-footer h6 {
	margin: 0 0 1.125rem !important;
	/*
	 * Column headings match the NULLIFIER wordmark above them: white, so the
	 * footer reads as headed groups rather than one field of grey. The links
	 * underneath stay muted, which is what makes the heading a heading.
	 */
	color: var(--nf-white) !important;
}

.nf-footer__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.625rem;
}

.nf-footer__list a {
	font-size: 0.875rem;
	color: var(--nf-muted) !important;
	text-decoration: none;
	transition: color 0.2s var(--nf-ease);
}

/*
 * Grey to blue, not grey to white.
 *
 * The navigation gets the wiping rule underneath because those links sit in a
 * single uppercase row where one line reads as a pointer. Down here they are
 * stacked lists of fourteen, and fourteen underlines sliding in and out is
 * fidget, not craft. Colour does the same job quietly, and it is the same
 * #6b8aff the rule up there is drawn in, so the two still rhyme.
 *
 * Grey to white said "highlighted". Grey to blue says "link".
 */
.nf-footer__list a:hover,
.nf-footer__list a:focus-visible {
	color: var(--nf-blue-lit) !important;
}

.nf-footer__bar {
	display: flex;
	justify-content: space-between;
	align-items: center;
	flex-wrap: wrap;
	gap: 0.75rem;
	margin-top: clamp(3rem, 6vw, 4.5rem);
	padding-block: 1.75rem;
	border-top: 1px solid var(--nf-line);
}

.nf-footer__fine {
	margin: 0;
	font-size: 0.75rem;
	letter-spacing: 0.02em;
	color: #6b6b6b;
}

/* --- Small screens ------------------------------------------------------- */

@media (max-width: 600px) {
	.nf-header__inner {
		flex-direction: column;
		align-items: center;
		gap: 0.875rem;
		padding-block: 1rem;
	}

	.nf-nav {
		margin-left: 0;
		gap: 1.125rem;
		flex-wrap: wrap;
		justify-content: center;
	}

	.nf-nav a {
		font-size: 0.75rem;
	}
}

@media (max-width: 781px) {
	/*
	 * Let the hero be as tall as its content instead of holding a
	 * viewport-height box open. On a phone the fixed height left a third of
	 * a screen of dead space under the buttons, which reads as the page
	 * having ended rather than as deliberate space.
	 */
	.nf-hero {
		min-height: 0;
		align-items: flex-start;
	}

	/*
	 * The landscape crop puts the figure off the side of a phone screen, so
	 * a portrait frame is served instead and the scrim turns to run top to
	 * bottom — the copy sits above the subject here rather than beside it.
	 */
	.nf-hero__media {
		background-image: url("assets/img/hero-mobile.jpg");
		background-position: center 18%;
	}

	.nf-hero__eclipse {
		background: radial-gradient(
			circle at 50% 30%,
			rgba(0, 0, 254, 0.16) 0%,
			rgba(0, 0, 254, 0.06) 30%,
			transparent 64%
		);
	}

	.nf-hero__scrim {
		background-image: linear-gradient(
			to bottom,
			rgba(10, 10, 10, 0.9) 0%,
			rgba(10, 10, 10, 0.84) 34%,
			rgba(10, 10, 10, 0.7) 58%,
			rgba(10, 10, 10, 0.9) 100%
		);
	}

	.nf-hero__inner {
		padding-block: clamp(3.25rem, 9vh, 5rem);
	}

	.nf-hero__lede {
		max-width: 100%;
		margin-top: 1.5rem;
	}

	.nf-hero__cta {
		margin-top: 2.25rem;
	}

	.nf-grid {
		grid-template-columns: 1fr;
	}

	.nf-tile--lg {
		grid-row: auto;
		min-height: clamp(300px, 62vw, 420px);
	}

	/*
	 * Core stacks every column to full width below 782px, which turned the
	 * footer into a screen and a half of single-file links. Grid instead:
	 * the brand block keeps the full row, the three link groups pair up.
	 */
	.nf-footer__cols {
		display: grid !important;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 2.25rem 1.5rem !important;
	}

	.nf-footer__cols > .wp-block-column {
		flex-basis: auto !important;
	}

	.nf-footer__cols > .wp-block-column:first-child {
		grid-column: 1 / -1;
	}

	.nf-footer__bar {
		justify-content: flex-start;
	}
}

/* --- Long-form pages (About, Terms, Privacy) ----------------------------- */

.nf-lede {
	font-size: clamp(1.25rem, 2.4vw, 1.75rem);
	line-height: 1.35;
	letter-spacing: -0.02em;
	color: var(--nf-white);
	margin-bottom: 2.5rem;
}

.wp-block-post-content h2 {
	margin-top: 3.5rem;
	padding-top: 1.75rem;
	border-top: 1px solid var(--nf-line);
}

.wp-block-post-content h2:first-child {
	margin-top: 0;
	padding-top: 0;
	border-top: 0;
}

.wp-block-post-content p,
.wp-block-post-content li {
	color: #d4d4d4;
	line-height: 1.65;
}

.wp-block-post-content strong {
	color: var(--nf-white);
}

.wp-block-post-content ul {
	padding-left: 1.1rem;
}

.wp-block-post-content li {
	margin-bottom: 0.75rem;
}

/* --- Tables in content --------------------------------------------------- */

.wp-block-table.nf-table table,
.wp-block-post-content table {
	width: 100%;
	border-collapse: collapse;
	border: 1px solid var(--nf-line);
	font-size: 0.9375rem;
}

.wp-block-post-content th {
	text-align: left;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--nf-muted);
	padding: 0.9rem 1rem;
	border-bottom: 1px solid var(--nf-line);
	background: var(--nf-surface);
}

.wp-block-post-content td {
	padding: 0.9rem 1rem;
	border-bottom: 1px solid var(--nf-line);
	color: #d4d4d4;
}

.wp-block-post-content tr:last-child td {
	border-bottom: 0;
}

.wp-block-table {
	overflow-x: auto;
}

/* Big contact email */

/*
 * The big contact address, brought into line with every other link.
 *
 * It was blue with a permanent faint underline, turning white on hover — the
 * old scheme, kept alive by its own !important long after the rule it was
 * copying had changed. That is what !important costs: it does not just win an
 * argument, it stops the element hearing about later ones.
 *
 * White words, and the blue line wipes in from the left like the navigation.
 * The gradient is declared here rather than inherited, because this is the
 * largest link on the site and it should not depend on which wrapper the
 * Contact page happens to put its content in.
 */
.nf-contact-email {
	display: inline-block;
	font-size: clamp(1.125rem, 2.6vw, 1.875rem);
	font-weight: 600;
	letter-spacing: -0.02em;
	color: var(--nf-white);
	text-decoration: none;
	padding-bottom: 0.15rem;
	margin-bottom: 1rem;
	background-image: linear-gradient( var(--nf-blue-lit), var(--nf-blue-lit) );
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0% 1px;
	transition: background-size 0.25s var(--nf-ease);
}

.nf-contact-email:visited {
	color: var(--nf-white);
	text-decoration-color: transparent;
}

.nf-contact-email:hover,
.nf-contact-email:focus-visible {
	color: var(--nf-white);
	background-size: 100% 1px;
}

/* ==========================================================================
   SINGLE PRODUCT
   ========================================================================== */

.woocommerce div.product {
	max-width: 1400px;
	margin-inline: auto;
	padding-inline: clamp(1.25rem, 4vw, 3rem);
	padding-block: clamp(2rem, 5vw, 4rem);
}

/* Gallery left, buy box right, and the buy box stays with you on scroll. */
@media (min-width: 900px) {
	.woocommerce div.product > .woocommerce-product-gallery {
		width: 56% !important;
		float: left;
		margin-right: 4%;
	}

	.woocommerce div.product > .summary {
		width: 40% !important;
		float: right;
		margin-bottom: 0 !important;
		position: sticky;
		top: 6rem;
		align-self: start;
	}
}

.woocommerce div.product .woocommerce-product-gallery__image img {
	width: 100%;
	background: var(--nf-surface);
	border: 1px solid var(--nf-line);
}

/* Title and price */

.woocommerce div.product .product_title {
	font-size: clamp(1.875rem, 3.5vw, 2.75rem) !important;
	font-weight: 700;
	line-height: 1.05;
	letter-spacing: -0.035em;
	margin: 0 0 0.75rem !important;
}

.woocommerce div.product .summary > p.price,
.woocommerce div.product .summary > span.price {
	display: block;
	margin: 0 0 1.5rem;
	font-size: 1.5rem !important;
	font-weight: 500;
	color: var(--nf-white) !important;
	font-variant-numeric: tabular-nums;
}

.woocommerce div.product .woocommerce-product-details__short-description {
	color: var(--nf-muted);
	font-size: 1rem;
	line-height: 1.6;
	max-width: 46ch;
	margin-bottom: 2rem;
	padding-bottom: 2rem;
	border-bottom: 1px solid var(--nf-line);
}

/* --- Size buttons -------------------------------------------------------- */

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

.nf-swatches {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0.75rem 0 0;
}

.nf-swatch {
	/* Share the row evenly. Five sizes sit on one line at any sensible
	   column width, and only wrap on very narrow phones. */
	flex: 1 1 auto;
	min-width: 3.25rem;
	appearance: none;
	background: transparent;
	border: 1px solid var(--nf-line);
	border-radius: 0;
	color: var(--nf-white);
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 0.875rem;
	font-weight: 500;
	letter-spacing: 0.04em;
	text-transform: none;
	padding: 0.85rem 0.5rem;
	line-height: 1;
	cursor: pointer;
	transition: border-color 0.15s var(--nf-ease), background-color 0.15s var(--nf-ease),
		color 0.15s var(--nf-ease);
}

.nf-swatch:hover:not(:disabled) {
	border-color: var(--nf-white);
}

.nf-swatch.is-selected {
	background: var(--nf-white);
	border-color: var(--nf-white);
	color: var(--nf-black);
	font-weight: 600;
}

/* Unavailable sizes stay visible and struck through, so you can see that the
   size exists and is simply gone, rather than wondering if it is made. */
.nf-swatch.is-unavailable,
.nf-swatch:disabled {
	color: #5a5a5a;
	border-color: #1e1e1e;
	cursor: not-allowed;
	text-decoration: line-through;
	text-decoration-thickness: 1px;
}

.woocommerce div.product form.cart .variations {
	border: 0;
	margin-bottom: 1.75rem;
}

.woocommerce div.product form.cart .variations tr,
.woocommerce div.product form.cart .variations td,
.woocommerce div.product form.cart .variations th {
	display: block;
	width: 100%;
	padding: 0;
	border: 0;
	background: transparent;
}

.woocommerce div.product form.cart .variations .label label {
	display: block;
	margin-bottom: 0;
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--nf-muted);
}

.woocommerce div.product form.cart .reset_variations {
	display: inline-block;
	margin-top: 0.75rem;
	font-size: 0.75rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--nf-muted) !important;
}

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

.nf-sizehead {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	margin: 0 0 0.85rem;
	padding-bottom: 0.6rem;
	border-bottom: 1px solid var(--nf-line);
}

.nf-sizehead__label {
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--nf-white);
}

.nf-sizehead__guide {
	font-size: 0.8125rem;
	color: var(--nf-muted) !important;
	text-decoration: underline;
	text-underline-offset: 0.25em;
	white-space: nowrap;
}

.nf-sizehead__guide:hover,
.nf-sizehead__guide:focus-visible {
	color: var(--nf-white) !important;
}

/*
 * WooCommerce prints its own "Size" label above the dropdown. The header row
 * above already says what to do, so the duplicate goes.
 */
.woocommerce div.product form.cart .variations label,
.woocommerce div.product form.cart .variations th.label {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
}

/* --- Product header lifted above the gallery on phones ------------------- */

.nf-product-head {
	margin-bottom: 1.5rem;
}

.nf-product-head .wp-block-post-title {
	margin: 0 0 0.4rem;
	font-size: clamp(1.75rem, 7vw, 2.5rem) !important;
	line-height: 1.05;
	letter-spacing: -0.02em;
}

.nf-product-head .wp-block-woocommerce-product-price,
.nf-product-head .wc-block-components-product-price {
	margin: 0;
	font-size: 1.125rem;
	color: var(--nf-white);
}

/* --- Buy row ------------------------------------------------------------- */

.woocommerce div.product form.cart {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	align-items: stretch;
	margin-bottom: 0;
}

.woocommerce div.product form.cart .variations_button,
.woocommerce div.product form.cart:not(.variations_form) {
	display: flex;
	gap: 0.75rem;
	width: 100%;
	align-items: stretch;
}

.woocommerce div.product form.cart .quantity {
	flex: 0 0 auto;
}

.woocommerce div.product form.cart .quantity .qty {
	width: 4.5rem;
	height: 100%;
	text-align: center;
	font-variant-numeric: tabular-nums;
}

.woocommerce div.product form.cart button.single_add_to_cart_button {
	flex: 1 1 auto;
	padding-block: 1.15rem;
	font-size: 0.875rem;
}

.woocommerce div.product .woocommerce-variation-price {
	margin-bottom: 1rem;
}

.woocommerce div.product .woocommerce-variation-availability p {
	font-size: 0.875rem;
	color: var(--nf-muted);
}

/* --- Assurances ---------------------------------------------------------- */

.nf-assurances {
	list-style: none;
	margin: 1.75rem 0 0;
	padding: 1.5rem 0 0;
	border-top: 1px solid var(--nf-line);
	display: grid;
	gap: 0.75rem;
}

.nf-assurances li {
	position: relative;
	padding-left: 1.25rem;
	font-size: 0.875rem;
	line-height: 1.5;
	color: var(--nf-muted);
}

.nf-assurances li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.55em;
	width: 5px;
	height: 5px;
	background: var(--nf-blue-lit);
}

.nf-assurances strong {
	color: var(--nf-white);
	font-weight: 600;
}

.nf-assurances a {
	color: var(--nf-blue-lit) !important;
}

/* --- Details section ----------------------------------------------------- */

.nf-product-details {
	clear: both;
	border-top: 1px solid var(--nf-line);
	margin-top: clamp(3rem, 6vw, 5rem);
	padding-top: clamp(2.5rem, 5vw, 4rem);
}

.nf-product-details__inner {
	display: grid;
	gap: clamp(1rem, 4vw, 3rem);
	grid-template-columns: 1fr;
}

@media (min-width: 900px) {
	.nf-product-details__inner {
		grid-template-columns: 20ch 1fr;
	}
}

.nf-product-details h2 {
	margin: 0 !important;
	font-size: 0.75rem !important;
	font-weight: 600 !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase;
	color: var(--nf-muted) !important;
}

.nf-product-details__body {
	max-width: 62ch;
}

.nf-product-details__body p {
	color: #d4d4d4;
	line-height: 1.7;
	margin: 0 0 1.1rem;
}

.nf-product-details__body strong {
	color: var(--nf-white);
}

/* --- Related ------------------------------------------------------------- */

.woocommerce .related.products {
	clear: both;
	border-top: 1px solid var(--nf-line);
	margin-top: clamp(3rem, 6vw, 5rem);
	padding-top: clamp(2.5rem, 5vw, 4rem);
}

.woocommerce .related.products > h2 {
	font-size: 0.75rem !important;
	font-weight: 600 !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase;
	color: var(--nf-muted) !important;
	margin-bottom: 2rem !important;
}

/* ==========================================================================
   CART AND CHECKOUT
   ========================================================================== */

.woocommerce-cart .wp-block-post-content,
.woocommerce-checkout .wp-block-post-content,
.woocommerce-account .wp-block-post-content {
	max-width: 1400px;
	margin-inline: auto;
	padding-inline: clamp(1.25rem, 4vw, 3rem);
	padding-block: clamp(2rem, 5vw, 3.5rem);
}

/* Shipping options as cards rather than bare radios. */

.wc-block-components-radio-control__option,
.woocommerce-shipping-methods li {
	position: relative;
	border: 1px solid var(--nf-line);
	background: var(--nf-surface);
	padding: 1rem 1.15rem !important;
	margin: 0 0 0.6rem !important;
	list-style: none;
	transition: border-color 0.18s var(--nf-ease);
}

.wc-block-components-radio-control__option:hover,
.woocommerce-shipping-methods li:hover {
	border-color: #3a3a3a;
}

/*
 * The chosen option is NOT highlighted. See the radio rules further down:
 * the filled circle is the only thing that marks a choice, deliberately.
 * These selectors stay so that WooCommerce's own highlight has something
 * more specific overriding it.
 */
.wc-block-components-radio-control__option--checked-option-highlighted,
.wc-block-components-radio-control__option:has(input:checked),
.woocommerce-shipping-methods li:has(input:checked) {
	border-color: var(--nf-line);
	background: var(--nf-surface);
}

.wc-block-components-radio-control__label,
.woocommerce-shipping-methods label {
	font-weight: 500;
	color: var(--nf-white);
}

.wc-block-components-radio-control__description {
	color: var(--nf-muted);
	font-size: 0.8125rem;
}

/* Order summary column, held in place while the form is filled in. */

@media (min-width: 1000px) {
	.wc-block-checkout__sidebar,
	.woocommerce-checkout-review-order {
		position: sticky;
		top: 6rem;
	}
}

.wc-block-components-sidebar,
.woocommerce-checkout-review-order {
	background: var(--nf-surface);
	border: 1px solid var(--nf-line);
	padding: clamp(1.25rem, 2.5vw, 1.75rem);
}

.wc-block-components-order-summary__content,
.woocommerce-checkout-review-order-table {
	background: transparent;
}

.wc-block-components-totals-item {
	padding-block: 0.6rem;
}

.wc-block-components-totals-footer-item,
.woocommerce-checkout-review-order-table tfoot .order-total {
	border-top: 1px solid var(--nf-line);
	font-size: 1.125rem;
}

.wc-block-components-product-metadata,
.wc-block-components-order-summary-item__description {
	color: var(--nf-muted);
	font-size: 0.8125rem;
}

.wc-block-components-order-summary-item__image img {
	border: 1px solid var(--nf-line);
	background: var(--nf-surface);
}

/* Step headings */

.wc-block-components-checkout-step__title,
.woocommerce-billing-fields > h3,
.woocommerce-shipping-fields > h3,
#order_review_heading {
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 1.125rem !important;
	font-weight: 600;
	letter-spacing: -0.02em;
	color: var(--nf-white);
}

.wc-block-components-checkout-step__description {
	color: var(--nf-muted);
	font-size: 0.875rem;
}

/* Payment methods */

.wc-block-components-radio-control-accordion-option,
.woocommerce-checkout #payment ul.payment_methods li {
	border: 1px solid var(--nf-line);
	background: var(--nf-surface);
	margin-bottom: 0.6rem;
	padding: 0.25rem 0;
	list-style: none;
}

.woocommerce-checkout #payment {
	background: transparent;
	border-radius: 0;
}

.woocommerce-checkout #payment div.payment_box {
	background: #0f0f0f;
	color: var(--nf-muted);
	font-size: 0.875rem;
	border-radius: 0;
}

.woocommerce-checkout #payment div.payment_box::before {
	display: none;
}

/* Place order */

.wc-block-components-checkout-place-order-button,
#place_order {
	width: 100%;
	padding-block: 1.15rem !important;
	font-size: 0.9375rem !important;
}

/* Cart table on the classic cart */

.woocommerce-cart table.cart img {
	width: 72px;
	border: 1px solid var(--nf-line);
}

.woocommerce-cart .cart_totals h2,
.cross-sells h2 {
	font-size: 0.75rem !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase;
	color: var(--nf-muted) !important;
}

/* Empty cart */

.wc-block-cart__empty-cart__title,
.cart-empty {
	font-size: 1.25rem;
	color: var(--nf-white);
}

/* Order received */

.woocommerce-order .woocommerce-thankyou-order-received {
	font-size: clamp(1.5rem, 3vw, 2.25rem);
	font-weight: 700;
	letter-spacing: -0.03em;
	color: var(--nf-white);
	margin-bottom: 2rem;
}

.woocommerce-order ul.order_details {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: 1px;
	background: var(--nf-line);
	border: 1px solid var(--nf-line);
	margin: 0 0 2.5rem;
	padding: 0;
}

.woocommerce-order ul.order_details li {
	flex: 1 1 160px;
	background: var(--nf-black);
	padding: 1rem 1.15rem;
	margin: 0;
	border: 0;
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--nf-muted);
}

.woocommerce-order ul.order_details li strong {
	display: block;
	margin-top: 0.4rem;
	font-size: 1rem;
	font-weight: 500;
	letter-spacing: 0;
	text-transform: none;
	color: var(--nf-white);
}

/* --- Gallery surface ----------------------------------------------------- */

.woocommerce div.product .woocommerce-product-gallery,
.woocommerce div.product .woocommerce-product-gallery__wrapper,
.woocommerce div.product .woocommerce-product-gallery__image {
	background: var(--nf-surface);
}

.woocommerce div.product .woocommerce-product-gallery__trigger {
	background: rgba(10, 10, 10, 0.75) !important;
	color: var(--nf-white) !important;
	border: 1px solid var(--nf-line);
	border-radius: 0 !important;
	box-shadow: none !important;
	text-indent: 0;
}

.woocommerce div.product .woocommerce-product-gallery__trigger::before,
.woocommerce div.product .woocommerce-product-gallery__trigger::after {
	border-color: var(--nf-white) !important;
	background: var(--nf-white) !important;
}

/* Breadcrumb sits tighter to the product */

.woocommerce .woocommerce-breadcrumb {
	max-width: 1400px;
	margin-inline: auto;
	padding-inline: clamp(1.25rem, 4vw, 3rem);
	padding-top: 1.5rem;
}

/* --- Price emphasis ------------------------------------------------------ */

.woocommerce div.product .summary .price,
.woocommerce div.product .summary .price .amount,
.woocommerce div.product .summary .price bdi,
.woocommerce div.product .woocommerce-variation-price .price,
.woocommerce div.product .woocommerce-variation-price .amount,
.woocommerce div.product .woocommerce-variation-price bdi {
	color: var(--nf-white) !important;
	font-size: 1.625rem !important;
	font-weight: 500 !important;
	letter-spacing: -0.02em;
	font-variant-numeric: tabular-nums;
}

.woocommerce div.product .summary .price del,
.woocommerce div.product .summary .price del bdi {
	color: var(--nf-muted) !important;
	font-size: 1.125rem !important;
	opacity: 0.7;
}

.woocommerce div.product .summary .price ins,
.woocommerce div.product .summary .price ins bdi {
	color: var(--nf-blue-lit) !important;
	text-decoration: none;
}

/* ==========================================================================
   PRODUCT PAGE CORRECTIONS
   ========================================================================== */

/* --- The block store-notice --------------------------------------------- */
/* WooCommerce ships two notice systems. This is the block one, which is what
   this template actually renders, and it needs styling in its own right. */

.wc-block-components-notice-banner,
.wc-block-store-notice {
	background-color: var(--nf-surface) !important;
	border: 1px solid var(--nf-line) !important;
	border-top: 2px solid var(--nf-blue-lit) !important;
	border-radius: 0 !important;
	color: var(--nf-white) !important;
	padding: 1.1rem 3rem 1.1rem 1.25rem !important;
	align-items: center;
}

.wc-block-components-notice-banner > .wc-block-components-notice-banner__content,
.wc-block-components-notice-banner p {
	color: var(--nf-white) !important;
	font-size: 0.9375rem;
}

/* The action link inside it is the only thing to do, so it reads as a button. */
.wc-block-components-notice-banner a,
.wc-block-store-notice a,
.wc-block-components-notice-banner a.wc-forward,
.woocommerce-message a.wc-forward {
	display: inline-block !important;
	margin: 0.85rem 0 0 !important;
	padding: 0.7rem 1.3rem !important;
	background: var(--nf-blue) !important;
	border: 1px solid var(--nf-blue) !important;
	color: var(--nf-white) !important;
	font-size: 0.75rem !important;
	font-weight: 600 !important;
	letter-spacing: 0.1em !important;
	text-transform: uppercase !important;
	text-decoration: none !important;
	opacity: 1 !important;
	float: none !important;
}

.wc-block-components-notice-banner a:hover,
.woocommerce-message a.wc-forward:hover {
	background: var(--nf-white) !important;
	border-color: var(--nf-white) !important;
	color: var(--nf-black) !important;
}

/* --- Close the dead gap before the buy row ------------------------------- */

.woocommerce div.product .woocommerce-variation,
.woocommerce div.product .single_variation {
	margin: 0;
}

.woocommerce div.product .woocommerce-variation:empty,
.woocommerce div.product .single_variation:empty,
.woocommerce div.product .woocommerce-variation-description:empty,
.woocommerce div.product .woocommerce-variation-availability:empty {
	display: none !important;
}

.woocommerce div.product .single_variation_wrap {
	margin-top: 1.25rem;
}

.woocommerce div.product form.cart .variations {
	margin-bottom: 1rem;
}

.woocommerce div.product form.cart .reset_variations {
	margin-top: 0.5rem;
}

/* Quantity box matches the button height exactly. */
.woocommerce div.product form.cart .quantity .qty {
	height: 100%;
	min-height: 3.4rem;
	padding-block: 0;
	border: 1px solid var(--nf-line);
	background: var(--nf-surface);
}

/* --- Tabs ---------------------------------------------------------------- */
/* The panel repeats the tab's own label as a huge heading. The tab is the
   label; the heading is noise. */

.woocommerce div.product .woocommerce-Tabs-panel > h2:first-child {
	display: none;
}

.woocommerce div.product .woocommerce-tabs {
	clear: both;
	max-width: 1400px;
	margin-inline: auto;
	padding-inline: clamp(1.25rem, 4vw, 3rem);
	padding-top: clamp(2.5rem, 5vw, 4rem);
	margin-top: clamp(2.5rem, 5vw, 4rem);
	border-top: 1px solid var(--nf-line);
}

.woocommerce div.product .woocommerce-Tabs-panel {
	max-width: 62ch;
	padding-top: 0.5rem;
}

.woocommerce div.product .woocommerce-Tabs-panel p {
	color: #d4d4d4;
	line-height: 1.7;
}

.woocommerce div.product .woocommerce-Tabs-panel strong {
	color: var(--nf-white);
}

/* --- Assurances now sit under the buy button ----------------------------- */

.woocommerce div.product form.cart .nf-assurances {
	flex-basis: 100%;
	margin-top: 1.5rem;
}

/* --- Product meta -------------------------------------------------------- */

.woocommerce div.product .product_meta {
	margin-top: 1.5rem;
	padding-top: 1.25rem;
	border-top: 1px solid var(--nf-line);
	font-size: 0.75rem;
	letter-spacing: 0.06em;
	color: var(--nf-muted);
}

.woocommerce div.product .product_meta > span {
	display: block;
	margin-bottom: 0.35rem;
}

.woocommerce div.product .product_meta .sku_wrapper,
.woocommerce div.product .product_meta .posted_in {
	text-transform: none;
}

/* --- Toast action button ------------------------------------------------- */
/* Scoped to our own container rather than to WooCommerce's classes, which
   differ between the classic and block notice systems. Whatever ends up in
   here, its link is the action and gets treated as one. */

.nf-toast-host > * {
	width: 100%;
	box-sizing: border-box;
	padding-right: 2.75rem !important;
}

.nf-toast-host a:not(.nf-toast-close) {
	display: inline-block !important;
	float: none !important;
	margin: 0.9rem 0 0 !important;
	padding: 0.75rem 1.4rem !important;
	background-color: var(--nf-blue) !important;
	background-image: none !important;
	border: 1px solid var(--nf-blue) !important;
	border-radius: 0 !important;
	color: #ffffff !important;
	font-family: "Outfit", system-ui, sans-serif !important;
	font-size: 0.75rem !important;
	font-weight: 600 !important;
	line-height: 1 !important;
	letter-spacing: 0.12em !important;
	text-transform: uppercase !important;
	text-decoration: none !important;
	opacity: 1 !important;
}

.nf-toast-host a:not(.nf-toast-close):hover {
	background-color: #ffffff !important;
	border-color: #ffffff !important;
	color: var(--nf-black) !important;
}

.nf-toast-host a:not(.nf-toast-close):focus-visible {
	outline: 2px solid var(--nf-blue-lit);
	outline-offset: 3px;
}

/* --- Toast action: plain blue text, no box ------------------------------- */
/* High specificity deliberately: WooCommerce's block stylesheet loads after
   the theme, so equal-weight rules lose to it. */

body .nf-toast-host a:not(.nf-toast-close),
body .nf-toast-host .woocommerce-message a:not(.nf-toast-close),
body .nf-toast-host .wc-block-components-notice-banner a:not(.nf-toast-close) {
	display: inline !important;
	margin: 0 !important;
	padding: 0 !important;
	background: none !important;
	background-color: transparent !important;
	border: 0 !important;
	/* White, not #0000fe. On this panel the electric blue measured 2.3:1 at
	   13px — unreadable, on the one thing in the toast worth clicking. The
	   blue moved to the rule underneath it instead; see the ::after below. */
	color: var(--nf-white) !important;
	font-family: "Outfit", system-ui, sans-serif !important;
	font-size: 0.8125rem !important;
	font-weight: 700 !important;
	letter-spacing: 0.12em !important;
	text-transform: uppercase !important;
	text-decoration: none !important;
	outline: 0 !important;
	box-shadow: none !important;
	opacity: 1 !important;
}

/* Keyboard users still need to see where focus is, so the ring returns for
   them only — it will not show on a mouse click. */
body .nf-toast-host a:not(.nf-toast-close):focus-visible {
	outline: 2px solid var(--nf-blue-lit) !important;
	outline-offset: 3px;
}

/* --- Cart item controls -------------------------------------------------- */
/* Remove was sitting flush against the "+" of the quantity stepper. A
   destructive action next to an incrementing one is a mis-tap waiting to
   happen, so it moves to its own line and takes a warning colour. */

:root {
	--nf-danger: #ff5a5a;
}

.wc-block-cart-item__quantity {
	display: flex !important;
	flex-direction: column;
	align-items: flex-start;
	gap: 0.9rem;
}

.wc-block-cart-item__remove-link,
.wc-block-cart-item__remove-icon,
.woocommerce-cart table.cart td.product-remove a.remove {
	display: inline-flex !important;
	align-items: center;
	gap: 0.4rem;
	margin: 0 !important;
	padding: 0.35rem 0.1rem !important;
	background: transparent !important;
	border: 0 !important;
	color: var(--nf-danger) !important;
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 0.75rem !important;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	text-decoration: none !important;
	opacity: 0.85;
	transition: opacity 0.15s var(--nf-ease), color 0.15s var(--nf-ease);
}

.wc-block-cart-item__remove-link:hover,
.wc-block-cart-item__remove-icon:hover,
.woocommerce-cart table.cart td.product-remove a.remove:hover {
	opacity: 1;
	color: #ff8080 !important;
	background: transparent !important;
}

/* Icon-only variants: colour the glyph itself and give it a real hit area. */
.wc-block-cart-item__remove-link svg,
.wc-block-cart-item__remove-icon svg,
.wc-block-cart-item__quantity button[class*="remove"] svg {
	width: 18px;
	height: 18px;
	fill: currentColor !important;
	stroke: currentColor;
}

.wc-block-cart-item__quantity button[class*="remove"] {
	min-width: 40px;
	min-height: 40px;
	color: var(--nf-danger) !important;
	background: transparent !important;
	border: 0 !important;
}

/* Keep the stepper visually separate from it. */
.wc-block-components-quantity-selector {
	border: 1px solid var(--nf-line) !important;
	border-radius: 0 !important;
	background: var(--nf-surface);
	max-width: 8.5rem;
}

.wc-block-components-quantity-selector__input {
	background: transparent !important;
	color: var(--nf-white) !important;
	font-variant-numeric: tabular-nums;
}

.wc-block-components-quantity-selector__button {
	background: transparent !important;
	border: 0 !important;
	color: var(--nf-muted) !important;
	font-size: 1.1rem !important;
	min-width: 2.4rem;
}

.wc-block-components-quantity-selector__button:hover {
	color: var(--nf-white) !important;
	background: transparent !important;
}

/* --- Cart row: remove sits at the far right ------------------------------ */
/* Corrects two things: the max-width above pushed the "+" out of the stepper
   box, and the remove control still sat beside it. It now lives at the
   opposite end of the row, as far from "+" as the row allows. */

.wc-block-components-quantity-selector {
	max-width: none !important;
	width: auto !important;
	display: inline-flex !important;
	align-items: stretch;
}

.wc-block-components-quantity-selector__input {
	width: 3rem !important;
	min-width: 3rem;
	text-align: center;
}

.wc-block-cart-item__quantity {
	display: block !important;
}

/* The row becomes the positioning context. */
.wc-block-cart-items__row,
.wc-block-cart-items .wc-block-cart-items__row {
	position: relative;
}

@media (min-width: 700px) {
	.wc-block-cart-items__row .wc-block-cart-item__remove-link,
	.wc-block-cart-items__row .wc-block-cart-item__remove-icon,
	.wc-block-cart-items__row button[class*="remove"] {
		position: absolute;
		right: 0;
		bottom: 1.5rem;
		margin: 0 !important;
	}
}

/* On narrow screens absolute placement would collide with the price, so it
   returns to the flow, still clear of the stepper. */
@media (max-width: 699px) {
	.wc-block-cart-item__remove-link,
	.wc-block-cart-item__remove-icon,
	.wc-block-cart-items__row button[class*="remove"] {
		display: inline-flex !important;
		margin-top: 0.9rem !important;
	}
}

/* ==========================================================================
   BLOCK CHECKOUT
   WooCommerce's block checkout uses its own class names and loads its
   stylesheet after the theme, so everything here is scoped from `body` to
   win on specificity. Without this the fields render white with white
   floating labels inside them, which is unusable.
   ========================================================================== */

/* --- Text fields --------------------------------------------------------- */

body .wc-block-components-text-input input[type="text"],
body .wc-block-components-text-input input[type="email"],
body .wc-block-components-text-input input[type="tel"],
body .wc-block-components-text-input input[type="number"],
body .wc-block-components-textarea,
body .wc-blocks-components-select__select,
body .wc-block-components-combobox input.components-combobox-control__input {
	background-color: var(--nf-surface) !important;
	border: 1px solid var(--nf-line) !important;
	border-radius: 0 !important;
	color: var(--nf-white) !important;
	font-family: "Outfit", system-ui, sans-serif !important;
	font-size: 1rem !important;
	padding: 1.4rem 1rem 0.55rem !important;
	height: auto !important;
	box-shadow: none !important;
}

body .wc-block-components-textarea {
	padding-top: 1rem !important;
}

body .wc-block-components-text-input input:focus,
body .wc-blocks-components-select__select:focus,
body .wc-block-components-combobox input:focus {
	border-color: var(--nf-blue-lit) !important;
	outline: 0 !important;
	box-shadow: none !important;
}

/* --- The floating labels, which were white on white ---------------------- */

body .wc-block-components-text-input label,
body .wc-blocks-components-select__label,
body .wc-block-components-combobox label {
	color: var(--nf-muted) !important;
	font-family: "Outfit", system-ui, sans-serif !important;
	font-size: 1rem !important;
	left: 1rem !important;
	right: auto !important;
	transition: transform 0.15s var(--nf-ease), font-size 0.15s var(--nf-ease);
}

body .wc-block-components-text-input.is-active label,
body .wc-block-components-text-input input:focus + label,
body .wc-blocks-components-select__label {
	font-size: 0.6875rem !important;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--nf-muted) !important;
	transform: translateY(-0.85rem) !important;
}

body .wc-block-components-text-input {
	margin-top: 1rem;
}

/* --- Selects ------------------------------------------------------------- */

body .wc-blocks-components-select {
	background: transparent;
}

body .wc-blocks-components-select__container {
	background-color: var(--nf-surface) !important;
	border: 1px solid var(--nf-line) !important;
	border-radius: 0 !important;
}

body .wc-blocks-components-select__select {
	border: 0 !important;
}

body .wc-blocks-components-select__expand {
	fill: var(--nf-muted) !important;
}

body .wc-blocks-components-select__select option {
	background: var(--nf-black);
	color: var(--nf-white);
}

/* --- Radios: the label was running underneath the button ----------------- */

body .wc-block-components-radio-control__option {
	position: relative;
	padding: 1.05rem 1.25rem 1.05rem 3.1rem !important;
	border: 1px solid var(--nf-line) !important;
	background: var(--nf-surface) !important;
	margin-bottom: 0.6rem !important;
	display: block;
}

body .wc-block-components-radio-control__input {
	position: absolute !important;
	left: 1.15rem !important;
	top: 1.15rem !important;
	margin: 0 !important;
	width: 18px !important;
	height: 18px !important;
	accent-color: var(--nf-blue);
	background: transparent !important;
	border: 1px solid #4a4a4a !important;
}

body .wc-block-components-radio-control__option:has(input:checked) {
	border-color: var(--nf-line) !important;
	background: var(--nf-surface) !important;
}

body .wc-block-components-radio-control__label-group,
body .wc-block-components-radio-control__label {
	color: var(--nf-white) !important;
	font-weight: 500;
}

body .wc-block-components-radio-control__description,
body .wc-block-components-radio-control__secondary-description {
	color: var(--nf-muted) !important;
	font-size: 0.8125rem !important;
	margin-top: 0.2rem;
}

body .wc-block-components-radio-control__option-checked-content,
body .wc-block-components-radio-control-accordion-content {
	padding: 0 1.25rem 1.1rem 3.1rem !important;
	color: var(--nf-muted) !important;
	font-size: 0.875rem;
	background: var(--nf-surface);
	border: 1px solid var(--nf-line);
	border-top: 0;
	margin: -0.6rem 0 0.6rem !important;
}

/* --- Checkboxes ---------------------------------------------------------- */

body .wc-block-components-checkbox__input[type="checkbox"] {
	width: 20px !important;
	height: 20px !important;
	border: 1px solid #4a4a4a !important;
	border-radius: 0 !important;
	background: var(--nf-surface) !important;
	accent-color: var(--nf-blue);
}

body .wc-block-components-checkbox__label {
	color: var(--nf-white) !important;
}

body .wc-block-components-checkbox__mark {
	fill: var(--nf-white) !important;
}

/* --- Headings and structure --------------------------------------------- */

body .wc-block-components-title,
body .wc-block-components-checkout-step__title {
	color: var(--nf-white) !important;
	font-family: "Outfit", system-ui, sans-serif !important;
	font-size: 1.125rem !important;
	font-weight: 600 !important;
	letter-spacing: -0.015em !important;
}

body .wc-block-checkout__form,
body .wc-block-components-checkout-step {
	border: 0;
}

body .wc-block-components-checkout-step {
	padding-bottom: 1.75rem;
	margin-bottom: 1.75rem;
	border-bottom: 1px solid var(--nf-line);
}

body .wc-block-components-checkout-step:last-child {
	border-bottom: 0;
}

/* Remove the doubled panel border around the summary. */
body .wc-block-components-sidebar .wc-block-components-panel,
body .wc-block-components-sidebar .wc-block-components-totals-wrapper {
	border-color: var(--nf-line) !important;
	background: transparent !important;
}

body .wc-block-components-order-summary__button-text,
body .wc-block-components-panel__button {
	color: var(--nf-white) !important;
}

body .wc-block-components-totals-item__label,
body .wc-block-components-totals-item__value {
	color: var(--nf-white) !important;
}

body .wc-block-components-totals-footer-item .wc-block-components-totals-item__value {
	font-size: 1.25rem;
	font-weight: 600;
}

/* --- Terms line and place order ----------------------------------------- */

body .wc-block-checkout__terms {
	color: var(--nf-muted) !important;
	font-size: 0.8125rem;
}

body .wc-block-checkout__terms a {
	color: var(--nf-blue-lit) !important;
}

body .wc-block-components-checkout-place-order-button {
	background: var(--nf-blue) !important;
	color: #ffffff !important;
	border-radius: 0 !important;
	font-weight: 600 !important;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

body .wc-block-components-checkout-place-order-button:hover {
	background: #ffffff !important;
	color: var(--nf-black) !important;
}

/* --- Validation ---------------------------------------------------------- */

body .wc-block-components-validation-error {
	color: var(--nf-danger) !important;
	font-size: 0.8125rem;
}

body .has-error input,
body .has-error .wc-blocks-components-select__container {
	border-color: var(--nf-danger) !important;
}

/* ==========================================================================
   ORDER RECEIVED
   ========================================================================== */

body .woocommerce-order {
	max-width: 1400px;
	margin-inline: auto;
	padding-inline: clamp(1.25rem, 4vw, 3rem);
}

body .woocommerce-notice--success,
body .woocommerce-thankyou-order-received {
	font-size: clamp(1.0625rem, 1.8vw, 1.25rem) !important;
	font-weight: 400 !important;
	color: var(--nf-muted) !important;
	letter-spacing: 0 !important;
	margin-bottom: 2.5rem !important;
	max-width: 52ch;
}

/* The order facts, as tiles rather than a run-on line. */

body .woocommerce-order ul.woocommerce-order-overview,
body .woocommerce-order ul.order_details {
	list-style: none !important;
	display: grid !important;
	grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
	gap: 1px !important;
	background: var(--nf-line) !important;
	border: 1px solid var(--nf-line) !important;
	margin: 0 0 3rem !important;
	padding: 0 !important;
}

body .woocommerce-order ul.order_details li {
	background: var(--nf-black) !important;
	padding: 1.1rem 1.25rem !important;
	margin: 0 !important;
	border: 0 !important;
	float: none !important;
	font-size: 0.625rem !important;
	font-weight: 600 !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase !important;
	color: var(--nf-muted) !important;
	line-height: 1.4;
}

body .woocommerce-order ul.order_details li strong {
	display: block !important;
	margin-top: 0.5rem;
	font-size: 1rem !important;
	font-weight: 500 !important;
	letter-spacing: 0 !important;
	text-transform: none !important;
	color: var(--nf-white) !important;
}

/* --- What happens now ---------------------------------------------------- */

.nf-next {
	margin-top: clamp(2.5rem, 5vw, 4rem);
	padding-top: clamp(2rem, 4vw, 3rem);
	border-top: 1px solid var(--nf-line);
}

.nf-next__title {
	font-size: 0.75rem !important;
	font-weight: 600 !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase;
	color: var(--nf-muted) !important;
	margin: 0 0 1.75rem !important;
}

.nf-next__steps {
	list-style: none;
	counter-reset: nf-step;
	margin: 0 0 2.5rem;
	padding: 0;
	display: grid;
	gap: 1px;
	background: var(--nf-line);
	border: 1px solid var(--nf-line);
}

@media (min-width: 800px) {
	.nf-next__steps {
		grid-template-columns: repeat(3, 1fr);
	}
}

.nf-next__steps li {
	counter-increment: nf-step;
	background: var(--nf-black);
	padding: 1.5rem 1.5rem 1.75rem;
	margin: 0;
}

.nf-next__steps li::before {
	content: counter( nf-step, decimal-leading-zero );
	display: block;
	margin-bottom: 0.9rem;
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 0.6875rem;
	font-weight: 700;
	letter-spacing: 0.16em;
	color: var(--nf-blue-lit);
}

.nf-next__steps strong {
	display: block;
	margin-bottom: 0.4rem;
	font-size: 1rem;
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--nf-white);
}

.nf-next__steps span {
	display: block;
	font-size: 0.875rem;
	line-height: 1.55;
	color: var(--nf-muted);
}

.nf-next__help {
	max-width: 60ch;
	font-size: 0.9375rem;
	color: var(--nf-muted);
	margin: 0 0 2rem;
}

.nf-next__help a {
	color: var(--nf-blue-lit) !important;
}

.nf-next__cta {
	margin: 0 0 clamp(3rem, 6vw, 5rem);
}

.nf-next__cta a {
	display: inline-block;
	text-decoration: none !important;
	color: #ffffff !important;
}

.nf-next__cta a:hover {
	color: var(--nf-black) !important;
}

/* --- Floating labels: keep them inside the box --------------------------- */
/* They were translating up onto the border and sitting across the line.
   Pinning them to an explicit position inside the field keeps the outline
   unbroken, which suits a design with no rounded corners anywhere. */

body .wc-block-components-text-input,
body .wc-blocks-components-select,
body .wc-block-components-combobox {
	position: relative;
}

body .wc-block-components-text-input label,
body .wc-block-components-combobox label {
	position: absolute !important;
	top: 50% !important;
	left: 1rem !important;
	right: auto !important;
	transform: translateY(-50%) !important;
	transform-origin: left top;
	line-height: 1 !important;
	margin: 0 !important;
	padding: 0 !important;
	background: transparent !important;
	pointer-events: none;
	transition: top 0.15s var(--nf-ease), font-size 0.15s var(--nf-ease),
		letter-spacing 0.15s var(--nf-ease);
}

/* Filled or focused: sit in the top of the field, not on its edge. */
body .wc-block-components-text-input.is-active label,
body .wc-block-components-combobox.is-active label,
body .wc-block-components-text-input input:focus + label,
body .wc-block-components-text-input input:not(:placeholder-shown) + label {
	top: 0.85rem !important;
	transform: none !important;
	font-size: 0.625rem !important;
	font-weight: 600 !important;
	letter-spacing: 0.16em !important;
	text-transform: uppercase !important;
	color: var(--nf-muted) !important;
}

/* Selects always show their label, so it is always in the small position. */
body .wc-blocks-components-select__label {
	position: absolute !important;
	top: 0.85rem !important;
	left: 1rem !important;
	transform: none !important;
	margin: 0 !important;
	padding: 0 !important;
	background: transparent !important;
	line-height: 1 !important;
	font-size: 0.625rem !important;
	font-weight: 600 !important;
	letter-spacing: 0.16em !important;
	text-transform: uppercase !important;
	color: var(--nf-muted) !important;
	pointer-events: none;
}

body .wc-blocks-components-select__container {
	position: relative;
}

body .wc-blocks-components-select__select {
	padding: 1.5rem 2.5rem 0.6rem 1rem !important;
}

/* The coupon field label had the same problem. */
body .wc-block-components-totals-coupon__form label,
body .wc-block-components-totals-coupon .wc-block-components-text-input label {
	left: 1rem !important;
}

body .wc-block-components-totals-coupon__input input {
	padding-top: 1.5rem !important;
	padding-bottom: 0.6rem !important;
}

/* --- Empty bag ----------------------------------------------------------- */

/*
 * WooCommerce ships a crying-face emoji here. It is a solid white disc on a
 * black page — the brightest thing on the screen, and the tone is wrong for a
 * label whose whole voice is understated. Replaced with a line-drawn bag of
 * our own, matching the hairline weight used by the ghost buttons and rules.
 */

body .wc-block-cart__empty-cart__title.with-empty-cart-icon::before,
body .with-empty-cart-icon::before {
	content: "";
	display: block;
	width: 5.5rem;
	height: 5.5rem;
	margin: 0 auto 1.5rem;
	background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCA2NCA2NCcgZmlsbD0nbm9uZScgc3Ryb2tlPScjZmZmZmZmJyBzdHJva2Utd2lkdGg9JzIuNicgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJyBzdHJva2UtbGluZWpvaW49J3JvdW5kJz48cGF0aCBkPSdNMjMgMjNWMTcuNWE5IDkgMCAwIDEgMTggMFYyMycvPjxwYXRoIGQ9J00xMi41IDIzaDM5bC0zLjEgMzIuNUgxNS42WicvPjxjaXJjbGUgY3g9JzI1LjUnIGN5PSczNycgcj0nMS42JyBmaWxsPScjZmZmZmZmJyBzdHJva2U9J25vbmUnLz48Y2lyY2xlIGN4PSczOC41JyBjeT0nMzcnIHI9JzEuNicgZmlsbD0nI2ZmZmZmZicgc3Ryb2tlPSdub25lJy8+PHBhdGggZD0nTTI1LjUgNDcuNWMxLjktMyA0LjItNC41IDYuNS00LjVzNC42IDEuNSA2LjUgNC41Jy8+PC9zdmc+");
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
	/*
	 * WooCommerce does not draw its icon as a background at all: it paints
	 * currentColor through a mask shaped like the crying face, at mask-size 0.
	 * Overriding background-image alone therefore changed nothing visible —
	 * the new artwork was being masked away. The mask has to go with it.
	 */
	mask-image: none !important;
	-webkit-mask-image: none !important;
	background-color: transparent !important;
	/* Undo the emoji font sizing WooCommerce uses to place its own icon. */
	font-size: 0 !important;
	line-height: 0 !important;
}

body .wc-block-cart__empty-cart__title {
	font-size: 1rem !important;
	font-weight: 500;
	letter-spacing: 0.02em;
	color: var(--nf-muted);
}

/*
 * The upsell grid under the empty bag reaches the page through a different
 * block than the shop archive, so removing the shop's button did not touch
 * it. Buttons belong on the product page, where a size can be chosen.
 */
body .wc-block-grid__product-add-to-cart {
	display: none;
}

/* --- Change size inside the bag ------------------------------------------ */

/*
 * The size on a bag line is a real control, not a label. Styled as an
 * underlined value rather than a boxed dropdown so the row still reads as a
 * summary of what you are buying — it only announces itself as editable on
 * hover and focus.
 */

.nf-bagsize {
	position: relative;
	display: inline-flex;
	align-items: center;
}

/*
 * Not a native <select>. Its dropdown panel is drawn by the operating
 * system — black on white, offset from the trigger — and CSS cannot reach
 * inside it. Button and list, same as Sort By.
 */

.nf-bagsize__trigger {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	background: none;
	border: 0;
	border-bottom: 1px dashed rgba(255, 255, 255, 0.35);
	border-radius: 0;
	padding: 0 0 1px;
	margin: 0;
	color: inherit;
	font: inherit;
	line-height: 1.3;
	cursor: pointer;
	transition: border-color 0.2s var(--nf-ease), color 0.2s var(--nf-ease);
}

.nf-bagsize__trigger:hover {
	border-bottom-color: var(--nf-white);
	color: var(--nf-white);
}

.nf-bagsize__trigger:focus {
	outline: none;
}

.nf-bagsize__trigger:focus-visible {
	outline: 2px solid var(--nf-blue-lit);
	outline-offset: 3px;
}

.nf-bagsize__chevron {
	width: 0.4rem;
	height: 0.4rem;
	border-right: 1.5px solid currentColor;
	border-bottom: 1.5px solid currentColor;
	transform: translateY(-2px) rotate(45deg);
	transition: transform 0.2s var(--nf-ease);
}

.nf-bagsize.is-open .nf-bagsize__chevron {
	transform: translateY(1px) rotate(-135deg);
}

/*
 * Scoped from body and stated explicitly: this list sits inside a cart table
 * cell, where WooCommerce's own list and cell rules were centring the sizes
 * and stretching each row to about three times its intended height.
 */
body .nf-bagsize__menu {
	position: absolute;
	top: calc(100% + 0.5rem);
	left: 0;
	z-index: 40;
	/* Sized to the longest label (2XL) rather than to a round number. */
	min-width: 3.5rem;
	margin: 0 !important;
	padding: 0.25rem 0 !important;
	list-style: none !important;
	background-color: var(--nf-surface);
	border: 1px solid var(--nf-line);
	box-shadow: 0 16px 36px rgba(0, 0, 0, 0.6);
	text-align: left !important;
}

body .nf-bagsize__option {
	display: block;
	margin: 0 !important;
	padding: 0.4rem 0.85rem !important;
	font-size: 0.875rem !important;
	line-height: 1.2 !important;
	color: var(--nf-white);
	text-align: left !important;
	white-space: nowrap;
	cursor: pointer;
	list-style: none !important;
	transition: background-color 0.15s var(--nf-ease);
}

body .nf-bagsize__option::marker,
body .nf-bagsize__option::before {
	content: none;
}

body .nf-bagsize__option:hover,
body .nf-bagsize__option:focus-visible {
	outline: none;
	background-color: rgba(255, 255, 255, 0.07);
}

body .nf-bagsize__option.is-selected {
	color: var(--nf-blue-lit);
}

/* Mid-swap: two network calls, so say something is happening. */
.nf-bagsize.is-working {
	opacity: 0.5;
	pointer-events: none;
}

.nf-bagsize.is-working::after {
	content: "";
	position: absolute;
	right: -1.15rem;
	top: 50%;
	width: 0.7rem;
	height: 0.7rem;
	margin-top: -0.35rem;
	border: 1.5px solid var(--nf-line);
	border-top-color: var(--nf-white);
	border-radius: 50%;
	animation: nf-spin 0.7s linear infinite;
}

/* If the swap failed, the original size is still in the bag — say so. */
.nf-bagsize.is-error .nf-bagsize__trigger {
	border-bottom-color: var(--nf-danger);
	color: var(--nf-danger);
}

@keyframes nf-spin {
	to {
		transform: rotate(360deg);
	}
}

@media (prefers-reduced-motion: reduce) {
	.nf-bagsize.is-working::after {
		animation: none;
	}
}

/* --- Bag line controls ---------------------------------------------------- */

/*
 * Size, quantity and remove on one row, replacing WooCommerce's plus/minus
 * stepper and its separately-placed bin. Three small controls where the row
 * had a wide stepper and a bin floated off to the right — and the quantity
 * is now one tap rather than up to eight presses of "+".
 */

.nf-bagline {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 0.35rem 1.25rem;
	margin-top: 0.5rem;
	font-size: 0.8125rem;
	color: var(--nf-muted);
}

.nf-bagfield {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	white-space: nowrap;
}

.nf-bagfield__label {
	color: var(--nf-muted);
}

/*
 * WooCommerce's own controls, superseded. Hidden rather than removed from the
 * DOM: React owns these nodes and tearing them out invites an error on its
 * next render.
 *
 * Keyed to a class on <body>, not to the row. It used to hang off the row's
 * own class, which meant that every time React destroyed and rebuilt a row —
 * which is exactly what a size change does — the new row briefly had no class
 * and WooCommerce's stepper and bin flashed into view before ours mounted.
 *
 * The class is added by the script, so if the script never runs the theme's
 * own controls are still there and the bag still works.
 */
body.nf-bag-enhanced .wc-block-cart-item__quantity .wc-block-components-quantity-selector,
body.nf-bag-enhanced .wc-block-cart-item__remove-link,
body.nf-bag-enhanced .wc-block-components-product-details {
	display: none !important;
}

/*
 * Holds the row's height steady while a rebuilt row waits for its controls,
 * so nothing below jumps up and back down.
 */
body.nf-bag-enhanced .wc-block-components-product-metadata {
	min-height: 2.6rem;
}

.nf-bagbin {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.9rem;
	height: 1.9rem;
	padding: 0;
	margin: 0;
	background: none;
	border: 0;
	border-radius: 0;
	color: var(--nf-muted);
	cursor: pointer;
	transition: color 0.2s var(--nf-ease);
}

.nf-bagbin svg {
	width: 1.05rem;
	height: 1.05rem;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.6;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.nf-bagbin:hover,
.nf-bagbin:focus-visible {
	color: var(--nf-danger);
}

.nf-bagbin:focus {
	outline: none;
}

.nf-bagbin:focus-visible {
	outline: 2px solid var(--nf-blue-lit);
	outline-offset: 2px;
}

.nf-bagbin.is-working {
	opacity: 0.4;
	pointer-events: none;
}

/*
 * Hide WooCommerce's own bin now that the bag line carries one.
 *
 * This needs more weight than it looks like it should. An earlier rule of
 * ours — `.wc-block-cart-items__row button[class*="remove"]` — scores higher
 * than a plain two-class selector, so `display: none` on the class alone lost
 * to it and the old red bin kept rendering under the new row.
 *
 * That same attribute selector is why the button above is called nf-bagbin
 * and not nf-bagremove: the substring match on "remove" was catching our own
 * control and applying WooCommerce's bin styling to it.
 */
body.nf-bag-enhanced button.wc-block-cart-item__remove-link,
body.nf-bag-enhanced .wc-block-cart-item__remove-icon,
body.nf-bag-enhanced .wc-block-cart-item__quantity button[class*="remove"] {
	display: none !important;
}

/* --- Product details: accordions ----------------------------------------- */

.nf-details {
	margin-top: clamp(2.5rem, 6vw, 4.5rem);
	padding-top: clamp(2rem, 4vw, 3rem);
	border-top: 1px solid var(--nf-line);
}

.nf-details__lead {
	max-width: 62ch;
	margin-bottom: clamp(2rem, 4vw, 3rem);
	color: var(--nf-muted);
	font-size: 1rem;
	line-height: 1.65;
}

.nf-details__lead p {
	margin: 0 0 1rem;
}

.nf-details__lead strong {
	color: var(--nf-white);
}

.nf-details__rows {
	max-width: 62ch;
	border-top: 1px solid var(--nf-line);
}

.nf-acc {
	border-bottom: 1px solid var(--nf-line);
}

.nf-acc__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding: 1.15rem 0;
	cursor: pointer;
	list-style: none;
	color: var(--nf-white);
	font-size: 0.9375rem;
	font-weight: 500;
	transition: color 0.2s var(--nf-ease);
}

/* Safari and Chrome each hide the native marker differently. */
.nf-acc__head::-webkit-details-marker {
	display: none;
}

.nf-acc__head::marker {
	content: "";
}

.nf-acc__head:hover {
	color: var(--nf-blue-lit);
}

.nf-acc__head:focus-visible {
	outline: 2px solid var(--nf-blue-lit);
	outline-offset: 3px;
}

/* A plus that becomes a minus, drawn rather than loaded. */
.nf-acc__mark {
	position: relative;
	flex: 0 0 auto;
	width: 0.75rem;
	height: 0.75rem;
}

.nf-acc__mark::before,
.nf-acc__mark::after {
	content: "";
	position: absolute;
	background-color: currentColor;
	transition: transform 0.2s var(--nf-ease), opacity 0.2s var(--nf-ease);
}

.nf-acc__mark::before {
	top: 50%;
	left: 0;
	width: 100%;
	height: 1.5px;
	margin-top: -0.75px;
}

.nf-acc__mark::after {
	left: 50%;
	top: 0;
	height: 100%;
	width: 1.5px;
	margin-left: -0.75px;
}

.nf-acc[open] .nf-acc__mark::after {
	transform: scaleY(0);
	opacity: 0;
}

.nf-acc__body {
	padding: 0 0 1.5rem;
	color: var(--nf-muted);
	font-size: 0.9375rem;
	line-height: 1.65;
}

.nf-acc__body p {
	margin: 0 0 0.9rem;
}

.nf-acc__body p:last-child {
	margin-bottom: 0;
}

.nf-acc__body a {
	color: var(--nf-blue-lit) !important;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.nf-acc__body a:hover {
	color: var(--nf-white) !important;
}

@media (prefers-reduced-motion: reduce) {
	.nf-acc__mark::before,
	.nf-acc__mark::after {
		transition: none;
	}
}

/* --- Link colour ---------------------------------------------------------- */

/* --- Link colour ---------------------------------------------------------- */

/*
 * Links are #6B8AFF — the same blue as the hover rules under the navigation
 * and the "View all" links. One interactive colour doing both jobs, rather
 * than two blues competing.
 *
 * True #0000FE is still the brand blue and still does the loud work: button
 * fills, the ticker, the Midnight band. It measures 8.64:1 as a background
 * behind white text. As *text on black* it is 2.29:1, against a 4.5:1
 * minimum, which is why it is not used for links. This one is 6.32:1.
 *
 * Underlines are kept on body-copy links, where a link inside a paragraph
 * needs to be identifiable without relying on colour. Navigation-style links
 * — breadcrumbs, product names in the grid — are not underlined, because
 * their position already says what they are.
 */

body .nf-acc__body a,
body .nf-details__lead a,
body .woocommerce-product-details__short-description a {
	color: var(--nf-blue-lit) !important;
	text-decoration: underline;
	text-underline-offset: 0.18em;
	text-decoration-thickness: 1px;
}

body .wc-block-components-product-name,
body .woocommerce-loop-product__link,
body .woocommerce-breadcrumb a,
body .posted_in a,
body .tagged_as a {
	color: var(--nf-blue-lit) !important;
	text-decoration: none;
}

body .nf-acc__body a:hover,
body .nf-acc__body a:focus-visible,
body .nf-details__lead a:hover,
body .woocommerce-breadcrumb a:hover,
body .wc-block-components-product-name:hover,
body .posted_in a:hover,
body .tagged_as a:hover {
	color: var(--nf-white) !important;
}

/* --- Email signup --------------------------------------------------------- */

.nf-signup {
	max-width: 30rem;
	margin: 2rem 0 0;
}

.nf-signup__row {
	display: flex;
	align-items: stretch;
	gap: 0;
	border-bottom: 1px solid rgba(255, 255, 255, 0.35);
	transition: border-color 0.2s var(--nf-ease);
}

.nf-signup__row:focus-within {
	border-bottom-color: var(--nf-white);
}

/* Present for screen readers; the placeholder carries it visually. */
.nf-signup__label {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
}

.nf-signup__input {
	flex: 1 1 auto;
	min-width: 0;
	background: none !important;
	border: 0 !important;
	border-radius: 0;
	padding: 0.85rem 0 !important;
	color: var(--nf-white);
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 1rem;
}

.nf-signup__input::placeholder {
	color: #6b6b6b;
}

.nf-signup__input:focus,
.nf-signup__input:focus-visible {
	outline: none !important;
	box-shadow: none !important;
	border: 0 !important;
}

.nf-signup__button {
	flex: 0 0 auto;
	background: none;
	border: 0;
	padding: 0.85rem 0 0.85rem 1.25rem;
	margin: 0;
	color: var(--nf-white);
	font-family: "Outfit", system-ui, sans-serif;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	cursor: pointer;
	transition: color 0.2s var(--nf-ease);
}

.nf-signup__button:hover {
	color: var(--nf-blue-lit);
}

.nf-signup__button:focus-visible {
	outline: 2px solid var(--nf-blue-lit);
	outline-offset: 3px;
}

.nf-signup__button[disabled] {
	opacity: 0.45;
	cursor: default;
}

/* The honeypot. Off-screen rather than display:none, because some bots skip
   anything hidden and this one needs to look fillable. */
.nf-signup__trap {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.nf-signup__fine {
	margin: 0.9rem 0 0;
	font-size: 0.75rem;
	line-height: 1.5;
	color: #6b6b6b;
}

.nf-signup__fine a {
	color: #6b6b6b !important;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.nf-signup__fine a:hover {
	color: var(--nf-white) !important;
}

.nf-signup__message {
	margin: 0.75rem 0 0;
	min-height: 1.2em;
	font-size: 0.875rem;
	color: var(--nf-white);
}

.nf-signup__message.is-error {
	color: var(--nf-danger);
}

.nf-signup.is-sent .nf-signup__row,
.nf-signup.is-sent .nf-signup__fine {
	display: none;
}

/* --- Midnight band: mark and collection name ------------------------------ */

/*
 * The hierarchy here is deliberate: Midnight's mark sits above the name at a
 * modest size, and "The Early Hours" is the heading. That reads as a
 * collection made for Midnight, rather than as a Midnight storefront — which
 * is both the honest framing and the one that matches the non-affiliation
 * line in the footer.
 *
 * The mark is a <p>, not the heading, so the page's outline is the collection
 * name. Its alt text still says Midnight for anything not looking at pixels.
 */

.nf-band__mark {
	margin: 0 0 1.1rem !important;
	line-height: 0;
}

.nf-band__mark img {
	display: block;
	width: clamp(150px, 20vw, 230px);
	height: auto;
	max-width: 100%;
	opacity: 0.92;
}

/* --- Bag count ------------------------------------------------------------ */

/*
 * The number is what makes the bag findable now the box is gone, so it only
 * appears when there is something to find. Tabular figures keep the header
 * from shifting as the count changes from 9 to 10.
 */

.nf-nav__count {
	display: inline-block;
	margin-left: 0.15rem;
	color: var(--nf-blue-lit);
	font-variant-numeric: tabular-nums;
	font-weight: 600;
}

.nf-nav__count.is-empty {
	display: none;
}

/*
 * Afterpay's instalment message, everywhere it appears.
 *
 * WooPayments renders this through two different containers: an id on the
 * product page, a class inside the totals on the bag. Both are here because
 * both were on the site and both were broken in the same way — a sliver of
 * a widget with a "See plans" link that opens a panel you cannot use.
 *
 * nullifier_remove_bnpl_messaging() in functions.php is the real fix on the
 * product page, since it stops the Stripe iframe loading at all. These rules
 * cover the bag, and stand as a guard in case a WooPayments update renames
 * the callback and quietly puts the widget back.
 *
 * Remove all of it the day the widget works. "4 payments of $25.89" is worth
 * showing a shopper — it just has to actually work.
 */
#payment-method-message,
.wc-block-components-bnpl-wrapper {
	display: none;
}

/* ==========================================================================
   CHECKOUT CHROME
   ========================================================================== */

/*
 * The checkout gets its own header and footer, defined in
 * templates/page-checkout.html. WooCommerce's version of that template used a
 * bare site title styled by the parent theme and shipped no footer at all,
 * which made the most important page on the site look like somebody else's.
 *
 * The rule these follow is different from the rest of the site: no navigation.
 * Every link at the top of a checkout is a way to abandon it, so the wordmark
 * is the only thing up there. The footer carries the four things a person
 * actually wants before typing a card number — how to send it back, the terms,
 * the privacy policy, and a real human address — and nothing else.
 */

.nf-cohead {
	border-bottom: 1px solid var(--nf-line);
	background-color: var(--nf-black);
}

/*
 * Full width, matching the main header.
 *
 * It was still sharing the 1400px content column while the site header had been
 * moved out of it, so the mark sat a few hundred pixels in on a wide screen and
 * the two headers disagreed about where the brand lives. Somebody moving from
 * the shop to the checkout would see the logo jump sideways — small, but it is
 * the one moment in the whole site where you least want anything to feel like
 * it slipped.
 */
.nf-cohead__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	width: 100%;
	padding-inline: var(--nf-gutter);
	padding-block: 1.125rem;
	box-sizing: border-box;
}

/* Matches .nf-logo exactly — the checkout is a quieter room, not a different
   building. */
.nf-cohead__mark {
	display: inline-flex;
	align-items: center;
	gap: 0.625rem;
	font-size: 1.0625rem;
	font-weight: 800;
	letter-spacing: 0.24em;
	text-transform: uppercase;
	color: var(--nf-white) !important;
	text-decoration: none;
	line-height: 1;
	flex-shrink: 0;
}

.nf-cohead__secure {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--nf-muted);
	white-space: nowrap;
}

.nf-cohead__lock {
	width: 14px;
	height: 14px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.6;
	stroke-linecap: round;
	stroke-linejoin: round;
	flex-shrink: 0;
}

.nf-cofoot {
	margin-top: clamp(3rem, 7vw, 5rem);
	border-top: 1px solid var(--nf-line);
	background-color: var(--nf-black);
}

.nf-cofoot__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 0.75rem 1.5rem;
	padding-block: 1.75rem;
}

.nf-cofoot__links {
	display: flex;
	flex-wrap: wrap;
	gap: 1.25rem;
	margin: 0;
	font-size: 0.8125rem;
}

.nf-cofoot__links a {
	color: var(--nf-muted) !important;
	text-decoration: none;
	transition: color 0.2s var(--nf-ease);
}

.nf-cofoot__links a:hover,
.nf-cofoot__links a:focus-visible {
	color: var(--nf-blue-lit) !important;
}

.nf-cofoot__fine {
	margin: 0;
	font-size: 0.75rem;
	letter-spacing: 0.02em;
	color: #6b6b6b;
}

@media (max-width: 600px) {
	.nf-cohead__inner {
		gap: 0.75rem;
	}

	/* The lock and the words cost more than they are worth on a small screen —
	   the padlock in the browser's own address bar is the reassurance that
	   actually counts. The wordmark stays. */
	.nf-cohead__secure {
		display: none;
	}

	.nf-cofoot__inner {
		flex-direction: column;
		align-items: flex-start;
	}
}

/* ==========================================================================
   BAG — POLISH
   ========================================================================== */

/*
 * What was wrong with the bag, in the order it hit the eye:
 *
 *   the product name was the only blue thing on the page and read as a
 *   stray link; the same price appeared twice, once under the name and once
 *   in the total column, which looks like a bug rather than a subtotal; the
 *   variant text said "Black Beauty / XS" directly above controls that said
 *   the same thing again; and the controls themselves were 13px labels on a
 *   dashed underline, which is a hint that something might be editable, not
 *   a control that says it is.
 *
 * Every one of those is a small thing. Together they are why it did not feel
 * like the rest of the internet.
 */

/* The name is the anchor of the row, so it gets the weight — white like the
   shop grid, blue only on hover, the same rule the header links follow. */
body .wc-block-cart-items .wc-block-components-product-name {
	color: var(--nf-white) !important;
	font-weight: 600;
	text-decoration: none;
}

body .wc-block-cart-items .wc-block-components-product-name:hover,
body .wc-block-cart-items .wc-block-components-product-name:focus-visible {
	color: var(--nf-blue-lit) !important;
}

/* One price per line. The unit price returns as soon as it differs from the
   total — the script writes the quantity onto the row for exactly this. */
body.nf-bag-enhanced .wc-block-cart-items__row[data-nf-qty="1"] .wc-block-cart-item__wrap > .wc-block-components-product-price {
	display: none;
}

/* The variant text is now said better by the menus underneath it. */
body.nf-bag-enhanced .wc-block-components-product-metadata__description {
	display: none !important;
}

/* Room to breathe, and big enough to read. */
body.nf-bag-enhanced .nf-bagline {
	gap: 0.5rem 0.875rem;
	margin-top: 0.875rem;
	font-size: 0.875rem;
}

/*
 * The controls become controls.
 *
 * A dashed underline is the web's way of saying "there might be something
 * here". A bordered chip says "this is a thing you press", which is what
 * these are. Square corners and a hairline border, the same vocabulary as
 * the sort menu and the form fields, so the bag stops looking like a page
 * where text has been made vaguely clickable.
 */
body.nf-bag-enhanced .nf-bagsize__trigger {
	border: 1px solid var(--nf-line);
	border-radius: 2px;
	padding: 0.34rem 0.6rem;
	color: var(--nf-white);
	background-color: rgba(255, 255, 255, 0.02);
	line-height: 1.2;
}

body.nf-bag-enhanced .nf-bagsize__trigger:hover {
	border-color: rgba(255, 255, 255, 0.42);
	background-color: rgba(255, 255, 255, 0.05);
}

body.nf-bag-enhanced .nf-bagsize.is-open .nf-bagsize__trigger {
	border-color: var(--nf-blue-lit);
}

/* The bin sits with them rather than floating loose beside them. */
body.nf-bag-enhanced .nf-bagbin {
	padding: 0.34rem;
	border: 1px solid transparent;
	border-radius: 2px;
	transition: border-color 0.2s var(--nf-ease), color 0.2s var(--nf-ease);
}

body.nf-bag-enhanced .nf-bagbin:hover {
	border-color: var(--nf-line);
	color: var(--nf-white);
}

/* ==========================================================================
   CHECKOUT — SHIPPING AND PAYMENT OPTIONS
   ========================================================================== */

/*
 * Two faults, both from WooCommerce styling these for a white page.
 *
 * First, the selected option was marked with a 1.5px PURE WHITE inset ring.
 * On a white background that is a soft highlight. On near-black it is the
 * brightest thing on the page — a hard box drawn around whatever you picked,
 * shouting louder than the price.
 *
 * Second, and worse: the dot inside a checked radio was painted BLACK, on a
 * transparent radio, on a black page. It was invisible. There was no way to
 * see which option you had chosen, which is the one job a radio button has.
 *
 * The fix puts all of the marking in one place: the radio itself. The boxes
 * around the options stay a quiet grey whether chosen or not — they are there
 * to group a label with its price, not to announce anything. Highlighting the
 * container as well meant two things competing to tell the shopper the same
 * fact, and the louder one won.
 *
 * This does not fall back on colour alone. An empty ring becoming a filled
 * ring is a change of shape, which survives colourblindness, a bad screen and
 * sunlight on a phone.
 */

/*
 * The white ring goes. The boxes themselves are set further up the file — the
 * checked-state colours there are neutralised rather than removed, so that
 * WooCommerce's own highlight always has something more specific beating it.
 */
body .wc-block-components-radio-control__option,
body .wc-block-components-radio-control-accordion-option,
body .wc-block-components-radio-control__option-checked,
body .wc-block-components-radio-control-accordion-option:has( .wc-block-components-radio-control__input:checked ) {
	box-shadow: none !important;
	border-radius: 3px !important;
}

/* The circle itself: a visible ring when empty... */
body .wc-block-components-radio-control__input {
	border: 1px solid rgba(255, 255, 255, 0.38) !important;
	background-color: transparent !important;
	box-shadow: none !important;
}

/* ...and a blue ring with a blue dot in it when chosen. */
body .wc-block-components-radio-control__input:checked {
	border-color: var(--nf-blue-lit) !important;
}

body .wc-block-components-radio-control__input:checked::before {
	background-color: var(--nf-blue-lit) !important;
	width: 9px !important;
	height: 9px !important;
	margin: 0 !important;
}

body .wc-block-components-radio-control__input:focus-visible {
	outline: 2px solid var(--nf-blue-lit);
	outline-offset: 2px;
}

/*
 * Last word on the option boxes.
 *
 * WooCommerce marks a chosen option by setting the accent colour on the
 * option itself and then drawing its border and inset ring from currentColor,
 * so neutralising the obvious border-color rules is not enough — the colour
 * comes back through the text colour. This resets all three on anything
 * carrying a checked input, in every place the checkout draws one.
 *
 * Deliberately the last rule in the file, so nothing quietly outranks it.
 */
body .wc-block-components-radio-control__option-checked,
body .wc-block-components-radio-control__option:has( input:checked ),
body .wc-block-components-radio-control-accordion-option:has( input:checked ),
body .wc-block-checkout__payment-method .wc-block-components-radio-control__option:has( input:checked ),
body .wc-block-components-shipping-rates-control .wc-block-components-radio-control__option:has( input:checked ),
body .woocommerce-shipping-methods li:has( input:checked ) {
	border-color: var(--nf-line) !important;
	background-color: var(--nf-surface) !important;
	box-shadow: none !important;
	color: inherit !important;
}

/*
 * Doubled lines.
 *
 * WooCommerce draws its radio lists two ways at once, and with our boxes on
 * top that made three lines where there should be one:
 *
 *   1. A hairline ::after inside every option — white at 20%, brighter than
 *      our own border, so it read as the "real" line and ours as a shadow.
 *      That separator exists to divide options in a list that shares one
 *      outline. We give each option its own outline, so it has nothing to do.
 *
 *   2. A payment method is an accordion option (the card) wrapping a radio
 *      option (its header). Both carried a border, five pixels apart.
 *      The wrapper is the card; the option inside it is only the top of it.
 *
 *   3. A grey rule under the expanded card's content, ending in mid-air.
 *
 * One box per choice, one line per box.
 */
body .wc-block-components-radio-control__option::after,
body .wc-block-components-radio-control-accordion-option::after {
	display: none !important;
}

body .wc-block-components-radio-control-accordion-option .wc-block-components-radio-control__option {
	border: 0 !important;
	border-radius: 0 !important;
	background-color: transparent !important;
	margin-bottom: 0 !important;
}

body .wc-block-components-radio-control-accordion-content,
body .wc-block-components-radio-control__option-checked-content {
	border: 0 !important;
}

/* ==========================================================================
   COLLECTIONS
   ========================================================================== */

/*
 * Same vocabulary as the range tiles — surface panel, hairline border, an
 * oversized ghost glyph standing in for photography — so a collection tile
 * and a category tile do not look like they came from two different sites.
 *
 * The difference is what the ghost says. On a range tile it repeats the name
 * underneath it. Here it is the collection number, which is what makes a wall
 * of these read as a sequence rather than a menu: 01, 02, 03 says there will
 * be more, and that you were early.
 */

.nf-cols {
	display: grid;
	grid-template-columns: repeat( auto-fit, minmax( 300px, 1fr ) );
	gap: clamp(0.75rem, 1.4vw, 1.25rem);
}

.nf-col {
	position: relative;
	display: flex;
	align-items: flex-end;
	min-height: clamp(280px, 30vw, 400px);
	padding: clamp(1.25rem, 2vw, 2rem);
	background-color: var(--nf-surface);
	border: 1px solid var(--nf-line);
	text-decoration: none !important;
	overflow: hidden;
	isolation: isolate;
	transition: border-color 0.3s var(--nf-ease), background-color 0.3s var(--nf-ease);
}

.nf-col:hover {
	border-color: var(--nf-blue-lit);
	background-color: #171717;
}

.nf-col__ghost {
	position: absolute;
	inset: auto auto -0.2em -0.05em;
	z-index: -1;
	font-size: clamp(7rem, 20vw, 15rem);
	font-weight: 800;
	line-height: 0.75;
	letter-spacing: -0.06em;
	color: transparent;
	-webkit-text-stroke: 1px rgba(255, 255, 255, 0.16);
	user-select: none;
	transition: -webkit-text-stroke-color 0.35s var(--nf-ease), transform 0.5s var(--nf-ease);
}

.nf-col:hover .nf-col__ghost {
	-webkit-text-stroke-color: rgba(107, 138, 255, 0.5);
	transform: translateY(-4px);
}

.nf-col__body {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
}

.nf-col__no {
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.22em;
	color: var(--nf-muted);
}

.nf-col__name {
	font-size: clamp(1.5rem, 2.4vw, 2.125rem);
	font-weight: 600;
	letter-spacing: -0.03em;
	line-height: 1.05;
	color: var(--nf-white);
}

/* The theme, not the title. The subtitle sits under the collection name rather
   than in place of it, which is the whole point of separating the two — so
   "Midnight Originals Collection" can sit under "01 — MIDNIGHT ORIGINALS". */
.nf-col__theme {
	margin-top: 0.15rem;
	font-size: 0.9375rem;
	color: #d4d4d4;
}

.nf-col__meta {
	margin-top: 0.5rem;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--nf-muted);
}

/* A collection with nothing in it yet keeps its place in the sequence,
   quieter, and says so rather than pretending. */
.nf-col.is-empty {
	opacity: 0.55;
}

.nf-col.is-empty:hover {
	opacity: 0.8;
}

@media (max-width: 600px) {
	.nf-col {
		min-height: clamp(220px, 52vw, 300px);
	}
}

/*
 * Buttons must not stay lit after a click.
 *
 * theme.json used to give buttons a :focus style identical to their hover —
 * white fill, black text. Hover is fine, it ends when the pointer leaves.
 * Focus does not: clicking a button leaves it focused, so it stayed a solid
 * white box until you clicked somewhere else. Every button on the site did
 * this, and it read as the page being stuck rather than as a state.
 *
 * That :focus block is gone from theme.json. This is the belt and braces —
 * a mouse click leaves no visual trace on the button, while a keyboard user
 * still gets the blue ring from the :focus-visible rule near the top of this
 * file. Focus is not being removed here, only the part of it that fired for
 * people who never needed it.
 */
:where( .wp-block-button__link, .wp-element-button, button ):focus:not( :focus-visible ) {
	outline: none;
}

.wp-block-button__link:focus:not( :focus-visible ),
.wp-element-button:focus:not( :focus-visible ) {
	background-color: var(--nf-blue);
	color: var(--nf-white);
	border-color: var(--nf-blue);
}

.is-style-outline > .wp-block-button__link:focus:not( :focus-visible ) {
	background-color: transparent;
	color: var(--nf-white);
	border-color: var(--nf-line);
}

/*
 * The focus ring, settled properly.
 *
 * The rule near the top of this file uses :where(), which has zero
 * specificity — deliberately, so anything could override it. The cost is that
 * it also loses to the browser's own default ring in any situation where both
 * apply, and Chrome on Windows draws that ring white. On a near-black header
 * a white rectangle around a nav link is the most conspicuous thing on the
 * page, and it stays there after a click because focus does not lift until
 * you click elsewhere.
 *
 * So: a real ring for people navigating by keyboard, in the brand blue, at a
 * specificity nothing casual will beat. And nothing at all after a mouse
 * click, which is what :focus:not(:focus-visible) means — the element is
 * focused, but the browser knows the person did not arrive by keyboard.
 *
 * This is not "removing focus styles". Tab through the site and every stop is
 * still clearly marked. It removes the ring only for the people who never
 * needed it and could not get rid of it.
 */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
	outline: 2px solid var(--nf-blue-lit) !important;
	outline-offset: 3px;
}

a:focus:not( :focus-visible ),
button:focus:not( :focus-visible ),
[tabindex]:focus:not( :focus-visible ),
summary:focus:not( :focus-visible ) {
	outline: none !important;
	box-shadow: none !important;
}

/* The nav links draw their own indicator — the blue rule wiping in under the
   word. Nothing else should be drawn on top of it. */
.nf-nav a:focus:not( :focus-visible ),
.nf-logo:focus:not( :focus-visible ) {
	outline: none !important;
	background-color: transparent !important;
}

/*
 * Collection names read as wordmarks, whatever case they were typed in.
 *
 * The names come from WooCommerce category titles, and those get typed by
 * hand over months — "FIRST FORM" one day, "The Early Hours" another. Left
 * alone, a row of tiles would mix shouting and sentence case for no reason a
 * visitor could see. Uppercasing here means the tile is consistent no matter
 * how the category was entered, while the category's own page keeps the name
 * exactly as written.
 */
.nf-col__name {
	text-transform: uppercase;
	letter-spacing: -0.01em;
}

/* ==========================================================================
   TOAST — LINES AND THE ACTION LINK
   ========================================================================== */

/*
 * One box, not two.
 *
 * WooCommerce has two notice systems and, depending on the template, renders
 * one nested inside the other — a store-notice wrapping a notice-banner, or
 * the reverse. Both carry our border rule, so both drew a box, and the result
 * was a hairline sitting a few pixels inside the real edge.
 *
 * Only the outer one is a box. Anything of the same kind inside it is just
 * content, so it gives up its border, background and padding.
 */
.wc-block-components-notice-banner .wc-block-components-notice-banner,
.wc-block-components-notice-banner .wc-block-store-notice,
.wc-block-store-notice .wc-block-components-notice-banner,
.wc-block-store-notice .wc-block-store-notice,
.nf-toast-host > * > .woocommerce-message,
.nf-toast-host > * > .wc-block-components-notice-banner {
	border: 0 !important;
	background: none !important;
	background-color: transparent !important;
	box-shadow: none !important;
	padding: 0 !important;
	margin: 0 !important;
}

/* The content block inside a notice is text, and text does not need edges. */
.wc-block-components-notice-banner > .wc-block-components-notice-banner__content {
	border: 0 !important;
	box-shadow: none !important;
	background: none !important;
}

/*
 * VIEW BAG reads like the header links.
 *
 * It was true #0000fe on a near-black panel — 2.3:1, which is unreadable at
 * 13px, and the one thing in the toast a person is meant to act on. It now
 * behaves exactly like SHOP or COLLECTIONS up in the header: white type with
 * the blue rule wiping in underneath on hover. Same gesture, same colour,
 * learned once and true everywhere.
 */
body .nf-toast-host a:not(.nf-toast-close) {
	position: relative !important;
	display: inline-block !important;
	padding-bottom: 2px !important;
	text-decoration: none !important;
}

body .nf-toast-host a:not(.nf-toast-close)::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 1px;
	background: var(--nf-blue-lit);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.25s var(--nf-ease);
}

body .nf-toast-host a:not(.nf-toast-close):hover::after,
body .nf-toast-host a:not(.nf-toast-close):focus-visible::after {
	transform: scaleX(1);
}

body .nf-toast-host a:not(.nf-toast-close):hover {
	color: var(--nf-white) !important;
}

/*
 * No focus ring around the toast itself.
 *
 * WooCommerce gives its notices tabindex="-1" so a screen reader can be sent
 * to them when they appear. A negative tabindex means "scriptable focus
 * target", not "tab stop" — but it still makes the element focusable by
 * click, and the focus rules further up were painting a 2px blue ring right
 * around the whole panel the moment you clicked it. A ring around a message
 * says "you have selected this", which is not a thing you can do to a
 * message.
 *
 * The rule is general because the reasoning is: anything with tabindex="-1"
 * is a scroll-and-announce target, never a control, so it never gets a ring.
 * Real controls inside it — VIEW BAG, the close button — are unaffected and
 * still show focus when tabbed to.
 */
[tabindex="-1"]:focus,
.nf-toast-host > *:focus,
.wc-block-components-notice-banner:focus,
.wc-block-store-notice:focus,
.woocommerce-message:focus,
.woocommerce-notices-wrapper:focus {
	outline: none !important;
	box-shadow: 0 14px 36px rgba(0, 0, 0, 0.6) !important;
}

/*
 * In-page anchors, landing properly.
 *
 * "Join the list" in the hero jumps to the signup form at the foot of the
 * same page. Two things make that jump feel like navigation rather than a
 * glitch:
 *
 * Smooth scrolling, so the reader keeps their bearings — a hard cut to a
 * different part of the same page reads as a page load, and they lose the
 * thread of where they came from. The reduced-motion block further up this
 * file already turns this off for anyone who has asked for less movement.
 *
 * And scroll-margin, because the header is sticky. Without it the browser
 * scrolls the form to y=0 and the header sits on top of it, so the thing you
 * were sent to see is the thing that is covered up.
 */
html {
	scroll-behavior: smooth;
}

/*
 * Measured, not guessed. The sticky header is 94px on a 390px phone and
 * around 62px on a desktop, and the first value here only cleared the phone
 * by seven pixels — technically visible, and close enough to the header edge
 * to read as clipped. 14vh puts roughly 25px of air above the form on a phone
 * and more on a desktop, which is enough for it to look placed rather than
 * jammed under the bar.
 */
#join,
.nf-community {
	scroll-margin-top: clamp(6.5rem, 14vh, 9rem);
}

/* ==========================================================================
   COLLECTIONS — LAYOUT AND CONTENT
   ========================================================================== */

/*
 * Three across, and the reason it was two.
 *
 * theme.json sets a content width of 720px. The Collections page puts its
 * content through WordPress's constrained layout, which caps every direct
 * child at that width — so .nf-section__inner's own max-width of 1400px never
 * got a chance, the grid had 720px to work in, and auto-fit could only fit
 * two 300px columns. It was not the grid being cautious; it was the container
 * being small.
 *
 * Letting .nf-section reach the wide width fixes the cause. The column count
 * is then stated outright rather than left to auto-fit, because three
 * collections should be one row of three, and a fourth should start a second
 * row of three — not silently become four-up on a wide screen.
 */
.is-layout-constrained > .nf-section,
.is-layout-constrained > .nf-section__inner {
	max-width: var( --wp--style--global--wide-size, 1400px );
	width: 100%;
}

.nf-cols {
	grid-template-columns: repeat( 3, 1fr );
}

@media (max-width: 900px) {
	.nf-cols {
		grid-template-columns: repeat( 2, 1fr );
	}
}

@media (max-width: 600px) {
	.nf-cols {
		grid-template-columns: 1fr;
	}
}

/*
 * The garments, named.
 *
 * A tile with a number, a title and "3 pieces" tells a shopper nothing about
 * whether this drop has the thing they want. Listing what is in it does, and
 * it gives the tile something to hold while there is no photography.
 */
.nf-col__pieces {
	margin-top: 0.55rem;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--nf-muted);
}

.nf-col:hover .nf-col__pieces {
	color: #d4d4d4;
}

/* ==========================================================================
   COLLECTIONS — BANDS
   ========================================================================== */

/*
 * The index layout.
 *
 * Cards in a row read as a menu: three equal rectangles, choose one. Bands
 * read as a sequence — 01 above 02 above 03, each the full width of the page,
 * which is what a collections index actually is. It also handles the missing
 * photography better: a full-width row of type looks composed, where an empty
 * card looks like a picture that failed to load.
 *
 * The right-hand column is deliberately left roomy. When there are garment
 * shots they go there, and nothing else has to move.
 *
 * The card version is still in functions.php — [nullifier_collections
 * layout="cards"] brings it back.
 */

.nf-rows {
	display: flex;
	flex-direction: column;
	border-top: 1px solid var(--nf-line);
}

.nf-row {
	position: relative;
	display: grid;
	/*
	 * The picture column keeps its width whether or not there is a picture in
	 * it. Every band is its own grid, so a row that skipped the column would
	 * start its name further left than the row above it — one collection
	 * standing out of line, for no reason a reader could work out.
	 */
	grid-template-columns: minmax(72px, 0.5fr) var( --nf-shot, clamp( 64px, 8vw, 104px ) ) minmax(0, 2fr) minmax(0, 1.6fr) auto;
	align-items: center;
	gap: clamp(1rem, 3vw, 2.5rem);
	padding-block: clamp(1.75rem, 4vw, 2.75rem);
	border-bottom: 1px solid var(--nf-line);
	text-decoration: none !important;
	transition: background-color 0.3s var(--nf-ease);
}

.nf-row::before {
	/* The tint bleeds past the row's own box so the hover reads as the whole
	   width of the page lighting up, not a box inside it. */
	content: "";
	position: absolute;
	inset: 0 calc(var(--nf-gutter) * -1);
	background-color: transparent;
	transition: background-color 0.3s var(--nf-ease);
	pointer-events: none;
}

.nf-row:hover::before {
	background-color: rgba(255, 255, 255, 0.025);
}

/* The number is the thing you see first, and the thing that says there will
   be more of these. */
.nf-row__no {
	position: relative;
	z-index: 1;
	font-size: clamp(2.25rem, 5vw, 4rem);
	font-weight: 800;
	line-height: 0.85;
	letter-spacing: -0.05em;
	color: transparent;
	-webkit-text-stroke: 1px rgba(255, 255, 255, 0.28);
	transition: -webkit-text-stroke-color 0.3s var(--nf-ease);
}

.nf-row:hover .nf-row__no {
	-webkit-text-stroke-color: var(--nf-blue-lit);
}

/*
 * Every part is placed by hand rather than left to fall into the next free
 * column, because a collection without a picture has one child fewer — and
 * with automatic placement its name would slide into the picture's column and
 * that one row would sit out of step with the rest of the page.
 */
.nf-row__no    { grid-column: 1; }
.nf-row__shot  { grid-column: 2; }
.nf-row__main  { grid-column: 3; }
.nf-row__side  { grid-column: 4; }
.nf-row__go    { grid-column: 5; }

.nf-row__main,
.nf-row__side {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	min-width: 0;
}

/* --- The picture --------------------------------------------------------- */

/*
 * Small on purpose. It is a marker for the eye running down an index, not the
 * subject of the row — the name and the number still lead. Square, so that a
 * product shot and a piece of artwork sit at the same size.
 */
.nf-row__shot {
	position: relative;
	z-index: 1;
	display: block;
	width: 100%;
	aspect-ratio: 1;
	overflow: hidden;
	border: 1px solid var( --nf-line );
	background-color: var( --nf-surface );
}

.nf-row__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.5s var( --nf-ease );
}

.nf-row:hover .nf-row__img {
	transform: scale( 1.05 );
}

.nf-row__name {
	font-size: clamp(1.375rem, 2.4vw, 2rem);
	font-weight: 600;
	line-height: 1.05;
	letter-spacing: -0.03em;
	text-transform: uppercase;
	color: var(--nf-white);
}

.nf-row__theme {
	font-size: 0.9375rem;
	color: #d4d4d4;
}

/*
 * Two lines and no more. The list is a glance at what is inside, and a drop
 * with eight pieces in it would otherwise push its own row out of shape —
 * which is why the fifth name onwards is replaced by a count in PHP, and why
 * anything that still overruns is cut here rather than allowed to wrap on.
 */
.nf-row__pieces {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	font-size: 0.875rem;
	line-height: 1.5;
	color: var(--nf-muted);
}

.nf-row__meta {
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: #6b6b6b;
}

.nf-row__go {
	position: relative;
	z-index: 1;
	font-size: 1.25rem;
	line-height: 1;
	color: var(--nf-muted);
	transition: transform 0.3s var(--nf-ease), color 0.3s var(--nf-ease);
}

.nf-row:hover .nf-row__go {
	color: var(--nf-blue-lit);
	transform: translateX(6px);
}

/* A collection with nothing in it yet keeps its place in the sequence and
   says so, rather than pretending or hiding. */
.nf-row.is-empty .nf-row__name,
.nf-row.is-empty .nf-row__theme {
	color: var(--nf-muted);
}

.nf-row.is-empty .nf-row__no {
	-webkit-text-stroke-color: rgba(255, 255, 255, 0.14);
}

@media (max-width: 782px) {
	.nf-row {
		grid-template-columns: minmax(52px, auto) 56px minmax(0, 1fr) auto;
		row-gap: 0.75rem;
	}

	/*
	 * Rows as well as columns here. The contents move to a line of their own,
	 * and without being told which line the arrow follows them down and ends
	 * up stranded on a third one by itself.
	 */
	.nf-row__no   { grid-column: 1; grid-row: 1; }
	.nf-row__shot { grid-column: 2; grid-row: 1; }
	.nf-row__main { grid-column: 3; grid-row: 1; }
	.nf-row__go   { grid-column: 4; grid-row: 1; }

	/* Contents move under the name rather than fighting it for width. */
	.nf-row__side {
		grid-column: 1 / -1;
		grid-row: 2;
	}

	/* A long description would otherwise be most of the row on a phone. */
	.nf-row__theme {
		display: -webkit-box;
		-webkit-line-clamp: 4;
		-webkit-box-orient: vertical;
		overflow: hidden;
	}
}

/* --- A collection's own page --------------------------------------------- */

/*
 * The line above the heading. It carries the three things the page could not
 * say before: which collection this is in the sequence, how much is in it,
 * and that there are others.
 */
.nf-arch {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: clamp( 0.75rem, 2vw, 1.5rem );
	margin-block: clamp( 1.5rem, 4vw, 2.5rem ) 0.35rem;
}

/* The same ghost numeral as the index, at reading size. */
.nf-arch__no {
	font-size: clamp( 1.75rem, 3.5vw, 2.75rem );
	font-weight: 800;
	line-height: 0.85;
	letter-spacing: -0.05em;
	color: transparent;
	-webkit-text-stroke: 1px rgba( 255, 255, 255, 0.28 );
}

.nf-arch__count {
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: #6b6b6b;
}

.nf-arch__back {
	margin-left: auto;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var( --nf-muted );
	text-decoration: none;
	transition: color 0.3s var( --nf-ease );
}

.nf-arch__back::before {
	content: "\2190";
	margin-right: 0.5rem;
}

.nf-arch__back:hover,
.nf-arch__back:focus-visible {
	color: var( --nf-blue-lit );
}

/* The number is beside the title now, so the title starts where it sits. */
.tax-product_cat .wp-block-query-title {
	margin-top: 0;
}

/* --- The top of an interior page ---------------------------------------- */

/*
 * There was 261px of empty page above the title and another 141px below it,
 * so the first thing on /collections/ sat more than a third of a screen down.
 * That spacing is inherited: the parent theme puts a 96px block gap above
 * <main>, and .nf-section adds its own generous padding designed for the
 * front page, where sections are separated bands rather than the first thing
 * under a heading.
 *
 * The front page keeps its air. Interior pages start closer to the top, where
 * the reader is already looking.
 */
body:not(.home) .wp-site-blocks > main {
	margin-top: clamp(1.5rem, 4vh, 2.75rem) !important;
}

body:not(.home) .wp-block-post-content > .nf-section:first-child,
body:not(.home) .entry-content > .nf-section:first-child {
	padding-top: 0;
}

/* ==========================================================================
   PAGE HEADER
   ========================================================================== */

/*
 * A page heading that matches the category pages.
 *
 * WordPress renders a page's title through the template, inside the
 * constrained 720px column — so "Collections" sat indented and small while
 * the bands beneath it ran the full width, and the two looked like they came
 * from different pages. A product category page already does it properly:
 * title flush with the gutter, scaled to the width it has.
 *
 * Where a .nf-pagehead block exists in the content, it IS the heading, so the
 * template's automatic title steps aside. Everywhere else the automatic title
 * behaves exactly as before.
 */
main:has( .nf-pagehead ) .wp-block-post-title {
	display: none;
}

.nf-pagehead {
	margin: 0 0 clamp(2.5rem, 6vw, 4.5rem);
}

.nf-pagehead__title {
	margin: 0;
	font-size: clamp(2.75rem, 8vw, 6rem) !important;
	font-weight: 800 !important;
	line-height: 0.9 !important;
	letter-spacing: -0.045em !important;
	text-transform: uppercase;
	color: var(--nf-white);
}

/*
 * The subtitle is the only place on this page that explains what a collection
 * means here, so it gets room to be a sentence rather than a label — wider
 * than the heading, and light enough to read as an aside to it.
 */
.nf-pagehead__sub {
	margin: clamp(1rem, 2vw, 1.5rem) 0 0;
	max-width: 46ch;
	font-size: clamp(1rem, 1.4vw, 1.1875rem);
	line-height: 1.55;
	color: #d4d4d4;
}

/*
 * The rest of the gap above a page header.
 *
 * The earlier fix trimmed two of the three contributors and I stopped
 * measuring too early. Walking the whole ancestor chain shows where 160px
 * above "Collections" actually came from:
 *
 *   40px   <main> margin-top          (already trimmed, was 96px)
 *   96px   the parent theme's page wrapper padding-top   <- the real one
 *   24px   .entry-content margin-top
 *
 * The 96px belongs to Twenty Twenty-Five's page template, not to anything in
 * this theme, which is why trimming our own spacing barely moved it.
 *
 * Scoped with :has() to pages that carry a .nf-pagehead, so every other page
 * keeps the parent theme's spacing exactly as it was.
 */
/*
 * !important, unwillingly but correctly. Block themes write spacing as an
 * INLINE style on the block wrapper — style="padding-top:var(--wp--preset--
 * spacing--60)" — and an inline style beats any selector in a stylesheet no
 * matter how specific. There is no cleaner hook: the padding is generated
 * markup, not CSS. This is the one case !important is actually for.
 */
main:has( .nf-pagehead ) > .wp-block-group {
	padding-top: clamp( 0.5rem, 2vh, 1.5rem ) !important;
}

main:has( .nf-pagehead ) .entry-content {
	margin-top: 0 !important;
}

/* ==========================================================================
   HERO LOCKUP
   ========================================================================== */

/*
 * NULLIFIER with the slogan locked underneath it, both exactly the same
 * width — the wordmark as a single object rather than a heading with a line
 * of text below it.
 *
 * Drawn as SVG text, not as an image and not as two HTML elements.
 *
 * Not an image, because a wordmark that is the largest thing on the page has
 * to stay sharp at every size, weigh nothing, and be selectable and readable
 * to a screen reader. This is live text; the aria-label carries the whole
 * lockup as one phrase.
 *
 * Not two HTML elements, because making two lines of different type end at
 * exactly the same pixel is not something CSS can promise. SVG can:
 * textLength sets the width each line must occupy, and lengthAdjust="spacing"
 * reaches that width by opening or closing the gaps between letters rather
 * than stretching the letterforms. Both lines are told 1000 units, so they
 * agree by construction — at any screen size, and even if the font fails to
 * load and the metrics change underneath it.
 */

.nf-lockup {
	margin: 0;
	width: 100%;
	max-width: min( 100%, 62rem );
}

.nf-lockup__svg {
	display: block;
	width: 100%;
	height: auto;
}

.nf-lockup__word,
.nf-lockup__line {
	font-family: "Outfit", system-ui, -apple-system, "Segoe UI", sans-serif;
	fill: var(--nf-white);
}

.nf-lockup__word {
	font-size: 200px;
	font-weight: 800;
}

/*
 * Size and tracking are the same dial here, and that is the useful part.
 *
 * Because textLength pins this line to 1000 units whatever happens, the type
 * size does not change how wide the slogan is — it changes how much of that
 * width is letterform and how much is air between letters. Shrink the type
 * and the tracking opens by exactly as much as the glyphs gave up. One
 * number moves both.
 *
 * Measured in the rendered SVG rather than assumed:
 *
 *   NULLIFIER at 200px       cap height 142 units
 *   the slogan at 72px       cap height  52 units   ->  37% of the wordmark
 *   the slogan at 63px       cap height  46 units   ->  32% of the wordmark
 *
 * At 72px the slogan was competing with the wordmark instead of sitting
 * under it — near enough in weight and presence to read as a second logo.
 * 63px is a 12.5% cut, and it takes the tracking from 0.154em to 0.265em,
 * which is the other half of the fix: letter-spaced display type reads as a
 * caption to the thing above it, not a rival to it. (Those two figures are
 * the real gaps between glyph positions in the rendered SVG, not an estimate
 * from advance widths — measuring the text in a canvas gives noticeably
 * smaller numbers because the side bearings are counted differently.)
 *
 * The floor is somewhere near 52px, where the natural width falls so far
 * short of 1000 that filling it needs about 0.435em per gap and the words
 * come apart into loose letters. 0.265em is comfortably clear of that.
 *
 * Weight stays at 800, matching the wordmark: in a lockup the two lines
 * should read as one object cut from the same block. Size and tracking carry
 * the hierarchy; the weight is what keeps them related.
 *
 * If the wordmark's size ever changes, this one moves with it — the ratio is
 * what holds the lockup together, not either number on its own. The baseline
 * in the template moves too; see the note there.
 */
.nf-lockup__line {
	font-size: 63px;
	font-weight: 800;
}

/* ==========================================================================
   EVERY REMAINING TEXT LINK
   ==========================================================================
 *
 * One behaviour for links, stated once, at the end so it settles the argument.
 *
 * These were each written at a different time and all say the same outdated
 * thing: blue words, turning white when you point at them. Every one of them
 * carries !important, which is why changing the rule they were copying did not
 * reach them — that is the real cost of !important. It does not only win the
 * argument it was written for, it stops the element hearing any later ones.
 *
 * So: white words, and the blue line wipes in underneath. The same 0.25s and
 * the same easing as the navigation, the product grids, the page copy and the
 * contact address. Five places, one idea.
 *
 * .woocommerce-loop-product__link is deliberately absent from the second list.
 * It wraps an entire product tile, image and all, so a gradient on it would
 * rule a line under the photograph rather than under the words.
 */

.nf-assurances a,
body .wc-block-checkout__terms a,
.nf-next__help a,
body .nf-acc__body a,
body .nf-details__lead a,
body .woocommerce-product-details__short-description a,
body .woocommerce-breadcrumb a,
body .posted_in a,
body .tagged_as a,
body .woocommerce-loop-product__link {
	color: var(--nf-white) !important;
	text-decoration: none;
}

.nf-assurances a:visited,
body .wc-block-checkout__terms a:visited,
.nf-next__help a:visited,
body .nf-acc__body a:visited,
body .nf-details__lead a:visited,
body .woocommerce-product-details__short-description a:visited {
	text-decoration-color: transparent;
}

.nf-assurances a,
body .wc-block-checkout__terms a,
.nf-next__help a,
body .nf-acc__body a,
body .nf-details__lead a,
body .woocommerce-product-details__short-description a,
body .woocommerce-breadcrumb a,
body .posted_in a,
body .tagged_as a {
	background-image: linear-gradient( var(--nf-blue-lit), var(--nf-blue-lit) );
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0% 1px;
	transition: background-size 0.25s var(--nf-ease);
}

.nf-assurances a:hover,
.nf-assurances a:focus-visible,
body .wc-block-checkout__terms a:hover,
body .wc-block-checkout__terms a:focus-visible,
.nf-next__help a:hover,
.nf-next__help a:focus-visible,
body .nf-acc__body a:hover,
body .nf-acc__body a:focus-visible,
body .nf-details__lead a:hover,
body .nf-details__lead a:focus-visible,
body .woocommerce-product-details__short-description a:hover,
body .woocommerce-product-details__short-description a:focus-visible,
body .woocommerce-breadcrumb a:hover,
body .woocommerce-breadcrumb a:focus-visible,
body .posted_in a:hover,
body .tagged_as a:hover {
	background-size: 100% 1px;
}

/* --- Size Guide: the measuring diagram ----------------------------------- *
 *
 * Sits in the text column rather than breaking out of it, because it is being
 * read alongside the three explanations underneath and should line up with
 * them. 620px is wide enough for the labels to be legible and narrow enough
 * that the whole drawing is on screen at once on a laptop.
 *
 * mix-blend-mode: screen is what removes the drawing's black background. The
 * artwork is line work on pure black, the page is #0A0A0A, and a rectangle of
 * one on the other shows its edges. Screen leaves the backdrop untouched
 * wherever the artwork is black and draws the strokes everywhere else — so the
 * drawing sits ON the page instead of on a black card, and the blue markers
 * keep their exact colour. Nothing is cut out, nothing is redrawn.
 */

.nf-measure {
	margin: 2rem 0 2.5rem;
	max-width: 620px;
}

.nf-measure__img {
	display: block;
	width: 100%;
	height: auto;
	mix-blend-mode: screen;
}

/*
 * A browser without blend-mode support gets the drawing on its own black
 * rectangle: not as neat, and perfectly usable. Nothing here is load-bearing.
 */
@supports not (mix-blend-mode: screen) {
	.nf-measure__img { mix-blend-mode: normal; }
}

/* ==========================================================================
   MIDNIGHT ORIGINALS — the collection's own sky
   ========================================================================== */

/*
 * A night-sky band behind the top of /product-category/midnight/.
 *
 * WHY IT SITS BEHIND THE HEADING RATHER THAN THE WHOLE PAGE
 *
 * The artwork carries Midnight's own wordmark in its upper left — which is the
 * point of using it, but it is also exactly where a page heading goes. Laid
 * flat behind everything, "01 — MIDNIGHT ORIGINALS" would print straight over
 * "midnight" and both would be unreadable.
 *
 * So the band occupies the top of <main> and the content is pushed down past
 * the wordmark by the padding below. The heading lands on the dark mountains
 * and water in the lower third, where there is nothing to fight with, and the
 * wordmark sits above it like a title card.
 *
 * WHY A PSEUDO-ELEMENT AND NOT A BACKGROUND ON main
 *
 * A background on main itself would need its height expressed in the same
 * breath as the image's aspect ratio, and the gradient that fades it into the
 * page would have to guess where the image ends. A pseudo-element has a height
 * this file decides, so `cover` and the gradient agree with each other at every
 * viewport width.
 *
 * The gradient is layered above the photograph in the same shorthand rather
 * than applied as a mask: masks need the -webkit- prefix in Safari and fail
 * open, and a hard-edged photograph is a worse failure than a slightly heavier
 * rule.
 *
 * Scoped to this one term. Another collection wanting the same treatment gets
 * its own block rather than a shared one — there is one collection today, and
 * a generic system for one case is a guess about the second.
 */
body.tax-product_cat.term-midnight main {
	position: relative;
	padding-top: clamp( 150px, 21vw, 300px );
}

body.tax-product_cat.term-midnight main::before {
	content: "";
	position: absolute;
	inset: 0 0 auto;
	height: clamp( 220px, 30vw, 420px );
	background-image:
		linear-gradient(
			to bottom,
			rgba( 10, 10, 10, 0.10 ) 0%,
			rgba( 10, 10, 10, 0.72 ) 62%,
			#0A0A0A 100%
		),
		url( "assets/img/midnight-sky.jpg" );
	background-repeat: no-repeat, no-repeat;
	background-position: center top, center top;
	background-size: cover, cover;
	pointer-events: none;
	z-index: 0;
}

/* Everything in the page sits above the sky, not under it. */
body.tax-product_cat.term-midnight main > * {
	position: relative;
	z-index: 1;
}

/* ==========================================================================
   THE PLEASE-WAIT OVERLAY
   ========================================================================== */

/*
 * WooCommerce covers a form with jQuery blockUI whenever it is waiting on the
 * server — a variation lookup, an add to bag, a quantity change in the cart.
 * blockUI's overlay is white at 60% opacity, which is invisible on the white
 * theme it was designed against and a grey box on this one.
 *
 * Same overlay, brand's colour. The contents dim rather than being buried, so
 * it reads as the page thinking rather than something going wrong, and
 * WooCommerce's spinner still turns on top of it.
 *
 * The variation lookup itself is gone — see nullifier_variation_threshold() —
 * so on a product page this should now only ever be seen on add to bag.
 */
.woocommerce .blockUI.blockOverlay,
.woocommerce-page .blockUI.blockOverlay,
.wc-block-components-form .blockUI.blockOverlay {
	background-color: var( --nf-black ) !important;
	cursor: progress;
}

/* blockUI draws a bordered white message panel by default. Nothing uses it. */
.woocommerce .blockUI.blockMsg,
.woocommerce-page .blockUI.blockMsg {
	background: transparent !important;
	border: 0 !important;
	color: var( --nf-white ) !important;
}
