/*
Theme Name: Natural Elixir 2026
Theme URI: https://www.naturalelixir.co.za
Author: White House Inc
Description: Block (FSE) theme for Natural Elixir. Botanical Green direction: forest green on pale sage paper with a single turmeric accent. Built to replace Woodmart plus Elementor with a lean, native-block front end.
Version: 0.12.12
Requires at least: 6.7
Tested up to: 7.0
Requires PHP: 8.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: naturalelixir2026
Tags: block-templates, full-site-editing, e-commerce, one-column, custom-colors, custom-menu
*/

/* -------------------------------------------------------------------------
   Natural Elixir 2026
   Tokens live in theme.json. This file carries only what theme.json cannot
   express: composition utilities, the hero scrim, and interaction states.
   Design contract: docs/DESIGN.md (slug natural-elixir-botanical).
   ------------------------------------------------------------------------- */

:root {
	--ne-maxw: 1180px;
	--ne-line: var(--wp--preset--color--line);
	--ne-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
	--ne-mono: ui-monospace, Menlo, Consolas, monospace;

	/* CORNER RADIUS. --ne-radius is the one dial for the whole site; the
	   others are derived from it, so changing that single value re-rounds
	   buttons, inputs, images, cards and panels together and keeps them in
	   proportion. Set it to 0 for a hard-edged site. The pill is deliberately
	   absolute: it must stay fully round at any base value. */
	--ne-radius: 14px;
	--ne-radius-sm: calc(var(--ne-radius) * 0.5);
	--ne-radius-lg: calc(var(--ne-radius) * 1.5);
	--ne-radius-pill: 999px;
}

/* Radius applied site-wide in one place, so nothing has to remember to opt
   in. theme.json cannot express most of these selectors, which is why the
   rule lives here. Everything is a plain class selector, so it beats core's
   zero-specificity :where() defaults without !important. */
.wp-element-button,
.wp-block-button__link,
.wp-block-search__button,
.woocommerce button.button,
.woocommerce a.button,
.woocommerce input.button,
input[type="text"],
input[type="email"],
input[type="search"],
input[type="tel"],
input[type="number"],
input[type="password"],
select,
textarea,
.wp-block-search__input {
	border-radius: var(--ne-radius-sm);
}

.wp-block-image img,
.wp-block-post-featured-image img,
.wc-block-components-product-image img,
.woocommerce ul.products li.product img,
.ne-framed img {
	border-radius: var(--ne-radius);
}

.ne-card,
.wp-block-group.has-background,
.woocommerce ul.products li.product {
	border-radius: var(--ne-radius-lg);
}

/* Full-bleed sections butt against each other. Core's constrained layout puts
   a block gap between every child of <main>, which reads as a thin strip of
   page background between the hero and the band below it: a seam, not a
   designed gap. Every section already carries its own vertical padding. */
main.wp-block-group > .alignfull {
	margin-block-start: 0;
	margin-block-end: 0;
}

/* The same block gap sits between the header template part and <main>, which
   showed as a strip of page background under the header, above the hero. The
   header's own bottom hairline is the intended divider. */
main.wp-block-group {
	margin-block-start: 0;
}

/* And again inside the header itself, between the announce bar and the nav
   row. That 20px was why the logo and menu looked pushed to the bottom of the
   header: the row was centring its contents correctly, but the row itself sat
   9.5px below the centre of the visible band. */
.ne-header > * {
	margin-block-start: 0;
	margin-block-end: 0;
}

/* Full-bleed sections are edge-to-edge by definition; rounding them would
   leave slivers of the page background at the corners. */
.alignfull.has-background,
.ne-hero {
	border-radius: 0;
}

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

body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
}

/* Headings balance rather than orphan a single word. */
h1, h2, h3, h4 {
	text-wrap: balance;
}

/* Prose keeps a readable measure even inside a wide container. */
.ne-measure {
	max-width: 65ch;
}

.ne-measure-tight {
	max-width: 42ch;
}

/* Focus: visible, on-brand, never removed. */
:focus-visible {
	outline: 2.5px solid var(--wp--preset--color--accent);
	outline-offset: 3px;
	border-radius: 2px;
}

/* -- Eyebrow ------------------------------------------------------------ */
/* Rationed to one per three sections. accent-ink for AA contrast on paper. */
.ne-eyebrow {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.22em;
	color: var(--wp--preset--color--accent-ink);
}

/* On dark grounds the eyebrow flips to the light accent. */
.ne-on-dark .ne-eyebrow,
.ne-hero .ne-eyebrow {
	color: var(--wp--preset--color--accent-lt);
}

/* -- Header ------------------------------------------------------------- */
/* The frosted sticky header. The blur is on a pseudo-element, NOT on .ne-header,
   and that is the whole point of the extra rule.

   backdrop-filter makes an element a containing block for position:fixed
   descendants. The mobile navigation overlay is position:fixed;inset:0 and it is a
   descendant of the header, so with the filter on .ne-header the opened overlay was
   being sized against the header's own 60px-tall box instead of the viewport. The
   menu was opening correctly every time; it was being drawn inside the bar, which
   looked like a hamburger that did nothing.

   Putting the blur and the translucent fill on ::before keeps the effect identical
   and takes .ne-header back out of the containing-block chain. Same family of bug as
   the sticky contents rail: when a positioned element behaves strangely, look at what
   is establishing its containing block before touching the element itself. */
/* The template part wrapper is removed from layout on purpose.
   `wp:template-part {"tagName":"header"}` renders its own <header class=
   "wp-block-template-part"> around ours, and that wrapper is exactly as tall as the
   header inside it: 116px. A sticky element can only travel within its containing
   block, so .ne-header had nowhere to go and scrolled away with the page. Measured in
   Chrome 2026-08-17: header 116px, wrapper 116px, so zero travel.
   display:contents takes the wrapper out of the box tree and makes .ne-header a direct
   child of .wp-site-blocks, which is 3,855px tall. The sticky rule below then works as
   written and did not need changing.
   This predates the overflow guard: the header was never sticking. */
header.wp-block-template-part {
	display: contents;
}

.ne-header {
	position: sticky;
	top: 0;
	z-index: 20;
	border-bottom: 1px solid var(--ne-line);
}

.ne-header::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: color-mix(in srgb, var(--wp--preset--color--bg) 88%, transparent);
	backdrop-filter: blur(8px);
}

/* Brand wordmark. The asset is pre-tinted to Forest and Sage from the
   palette, so it needs no filter to sit on the paper header; height is
   fixed and the ratio is declared, which reserves the box before the file
   lands and keeps the header off the CLS budget. Scoped to .ne-header so it
   outranks core's .wp-block-image rules, which can print after the theme
   stylesheet when block assets load per block. */
.ne-header .ne-brandmark {
	margin: 0;
	line-height: 0;
	flex-shrink: 0;
}

.ne-header .ne-brandmark a {
	display: block;
}

/* The wordmark is a tight-crop transparent PNG, so it must not inherit the
   global image radius or any border: there is no plate behind it to round. */
.ne-header .ne-brandmark img {
	display: block;
	height: 22px;
	width: auto;
	max-width: none;
	aspect-ratio: 758 / 84;
	border: 0;
	border-radius: 0;
}

/* Right-hand utility link, set to match the nav. */
.ne-nav-right {
	align-items: center;
}

.ne-navlink {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	white-space: nowrap;
}

.ne-navlink a {
	color: var(--wp--preset--color--ink-soft);
	text-decoration: none;
}

.ne-navlink a:hover {
	color: var(--wp--preset--color--brand);
}

.ne-header .wp-block-navigation__responsive-container-open,
.ne-header .wp-block-navigation__responsive-container-close {
	color: var(--wp--preset--color--ink-soft);
}

.ne-header .wp-block-navigation-item__content {
	transition: color 0.2s var(--ne-ease);
}

.ne-header .wp-block-navigation-item__content:hover {
	color: var(--wp--preset--color--brand);
}

/* Navigation. The five items have to sit on one line at the container width,
   so they are set tighter than the old .ne-navlink and are explicitly stopped
   from wrapping: a wrapped nav pushes the header to two rows and shoves the
   logo out of line. */
.ne-header .wp-block-navigation {
	flex-wrap: nowrap;
	gap: 26px;
}

.ne-header .wp-block-navigation .wp-block-navigation-item {
	white-space: nowrap;
}

.ne-header .wp-block-navigation .wp-block-navigation-item__content {
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.82rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--ink-soft);
	/* The default line box is 30px tall against a 22px logo, so the row
	   centred two boxes of different heights and the caps read as sitting
	   low. line-height:1 makes the box hug the capitals, so the nav and the
	   wordmark are the same height and centre on the same line. */
	line-height: 1;
	position: relative;
	padding-block: 4px;
	border-bottom: 0;
}

/* Hover underline as a pseudo-element rather than a border, so it cannot add
   1.5px to the bottom of the box and push the text off centre. */
.ne-header .wp-block-navigation .wp-block-navigation-item__content::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -2px;
	height: 1.5px;
	background: var(--wp--preset--color--accent);
	opacity: 0;
	transition: opacity 200ms var(--ne-ease);
}

.ne-header .wp-block-navigation .wp-block-navigation-item__content:hover::after {
	opacity: 1;
}

/* Core switches the nav to an overlay only below 600px, which is far narrower
   than the point at which five uppercase items stop fitting beside a logo and
   a cart. This moves that switch to 960px by taking over the two rules core
   uses to decide. Both selectors are scoped to .ne-header so nothing else on
   the site is affected, and .is-menu-open is excluded so the opened overlay
   still displays normally. */
@media (max-width: 960px) {
	.ne-header .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
		display: none;
	}

	.ne-header .wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: flex;
	}
}

/* The overlay itself: full-height sheet, items large enough to hit. */
.ne-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	font-size: 1.1rem;
	letter-spacing: 0.06em;
}

/* WooCommerce injects a mini-cart and a customer-account link into the header
   at render time; neither is in parts/header.html. Both ship with generous
   padding, and the cart button at 43px was the tallest thing in the row, so it
   and not the logo was deciding the header height. Capped here so the logo and
   the nav set the height instead. */
.ne-header .wc-block-mini-cart__button,
.ne-header .wp-block-woocommerce-customer-account,
.ne-header .wp-block-woocommerce-customer-account a {
	padding: 2px;
	min-height: 0;
	line-height: 1;
}

.ne-header .wc-block-mini-cart__button svg,
.ne-header .wp-block-woocommerce-customer-account svg {
	width: 22px;
	height: 22px;
}

/* Header row. space-between across four children spread the account icon and
   the cart 146px apart, because WooCommerce injects them as two separate
   siblings rather than one group. The gap is dropped and the nav is given auto
   inline margins instead: the logo holds the left, the nav centres in what is
   left, and the two icons sit together on the right. */
.ne-headbar {
	gap: 0;
	justify-content: flex-start;
	align-items: center;
}

.ne-headbar .wp-block-navigation {
	margin-inline: auto;
}

.ne-headbar .wp-block-woocommerce-customer-account {
	margin-left: 0;
}

.ne-headbar .ne-nav-right {
	margin-left: 14px;
}

/* 4. Hamburger. Core draws two bars; this is three. The SVG cannot be edited
   from CSS, so it is hidden and the bars are drawn instead: the middle one as
   a centred background, the outer two as pseudo-elements. */
.ne-header .wp-block-navigation__responsive-container-open svg {
	display: none;
}

.ne-header .wp-block-navigation__responsive-container-open {
	position: relative;
	width: 24px;
	height: 16px;
	padding: 0;
	background-image: linear-gradient(currentColor, currentColor);
	background-size: 100% 1.5px;
	background-position: center;
	background-repeat: no-repeat;
}

.ne-header .wp-block-navigation__responsive-container-open::before,
.ne-header .wp-block-navigation__responsive-container-open::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	height: 1.5px;
	background: currentColor;
}

.ne-header .wp-block-navigation__responsive-container-open::before {
	top: 0;
}

.ne-header .wp-block-navigation__responsive-container-open::after {
	bottom: 0;
}

/* Announcement bar above the header. */
.ne-announce {
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--brand-on);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	text-align: center;
}

/* -- Hero --------------------------------------------------------------- */
/* Full-bleed image, directional scrim, copy held left. Not a centred hero. */
.ne-hero {
	position: relative;
	min-height: min(88vh, 780px);
	display: flex;
	align-items: center;
	overflow: hidden;
	background-color: var(--wp--preset--color--brand-deep);
}

/* Slide stack. Every image fills the hero; only the active one is opaque. */
.ne-hero-media {
	position: absolute;
	inset: 0;
	z-index: 0;
	margin: 0;
}

.ne-hero-media .ne-slide {
	position: absolute;
	inset: 0;
	margin: 0;
	opacity: 0;
	transition: opacity 900ms var(--ne-ease);
}

.ne-hero-media .ne-slide.is-active {
	opacity: 1;
}

.ne-hero-media .ne-slide img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 62% 50%;
}

/* THE SCRIM. Owned here rather than by core's dim overlay, because core
   applies a flat colour at a single opacity across the whole cover and that
   cannot be directional. Dark enough for AA text on the left, fully clear
   on the right so the photograph reads at full brightness. */
.ne-hero::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background: linear-gradient(
		100deg,
		color-mix(in srgb, var(--wp--preset--color--brand-deep) 92%, transparent) 0%,
		color-mix(in srgb, var(--wp--preset--color--brand-deep) 84%, transparent) 22%,
		color-mix(in srgb, var(--wp--preset--color--brand-deep) 52%, transparent) 42%,
		color-mix(in srgb, var(--wp--preset--color--brand-deep) 14%, transparent) 56%,
		transparent 66%
	);
}

.ne-hero-inner {
	position: relative;
	z-index: 2;
	width: 100%;
	max-width: var(--ne-maxw);
	margin-inline: auto;
}

/* Slide copy source. Hidden from view and from the accessibility tree. */
.ne-hero-slidecopy {
	display: none;
}

/* The heading and subline swap text, so reserve their height to stop the
   hero jumping between slides of different copy length. */
.ne-hero-title,
.ne-hero-sub {
	transition: opacity 300ms var(--ne-ease);
}

.ne-hero.is-swapping .ne-hero-title,
.ne-hero.is-swapping .ne-hero-sub {
	opacity: 0;
}

/* Slide controls. In normal flow at the foot of the copy column, so they
   share the left edge with the buttons and the rating line above them
   rather than floating loose over the photograph. The shift is a transform,
   not a negative margin, because the constrained layout sets the inline
   margins on its children with !important; it pulls the first dot's hit
   area back so the visible dot, not the button box, is what lines up. */
.ne-hero-dots {
	position: relative;
	z-index: 3;
	display: flex;
	align-items: center;
	gap: 2px;
	margin-top: var(--wp--preset--spacing--30);
	transform: translateX(-6.5px);
}

/* 24px target with a 9px dot inside it: the dots are now the only control,
   so they have to be comfortably hittable. */
.ne-hero-dot {
	display: grid;
	place-items: center;
	width: 24px;
	height: 24px;
	padding: 0;
	border: 0;
	background: transparent;
	cursor: pointer;
}

.ne-hero-dot::before {
	content: "";
	width: 9px;
	height: 9px;
	border-radius: 100px;
	border: 1px solid color-mix(in srgb, var(--wp--preset--color--brand-on) 65%, transparent);
	background: transparent;
	transition: background 200ms var(--ne-ease), transform 200ms var(--ne-ease);
}

.ne-hero-dot[aria-current="true"]::before {
	background: var(--wp--preset--color--accent);
	border-color: var(--wp--preset--color--accent);
}

.ne-hero-dot:hover::before {
	transform: scale(1.2);
}

.ne-hero h1 {
	color: var(--wp--preset--color--brand-on);
}

/* Italic emphasis in display type.
   Two things matter here and both were previously wrong.

   1. It must stay a plain inline box. As an inline-block with its own
      line-height it became a separate line box, and its baseline (the
      baseline of its last line) landed ~18px below the roman text beside
      it, so "life, naturally." sat on two different baselines.
   2. Newsreader is a variable font with an optical-size axis and NO weight
      axis. Inheriting the heading's 600 therefore got faux-bolded by the
      browser. It is set to its real 400 and synthesis is switched off, so
      the shapes are the designer's rather than a smeared approximation.

   Optical size needs no correction: measured at display size, Schibsted's
   cap is 70.3px against Newsreader's 71.5px, and x-heights are 52.7 vs
   52.2. They already match. */
.ne-hero h1 em {
	font-family: var(--wp--preset--font-family--body);
	font-style: italic;
	font-weight: 400;
	font-synthesis: none;
	color: var(--wp--preset--color--accent-lt);
	line-height: inherit;
}

/* Descender room for the y in "naturally", now that the em no longer
   carries its own padding. Applied to the heading so the line box grows
   rather than one word inside it. */
.ne-hero-title {
	padding-bottom: 0.06em;
}

/* Social proof line directly under the hero CTAs. */
.ne-hero-trust {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--sm);
	color: color-mix(in srgb, var(--wp--preset--color--brand-on) 88%, transparent);
	display: flex;
	align-items: center;
	gap: 12px;
	flex-wrap: wrap;
}

.ne-hero-trust strong {
	font-weight: 600;
	color: var(--wp--preset--color--brand-on);
}

.ne-hero .ne-stars {
	color: var(--wp--preset--color--accent-lt);
	letter-spacing: 2px;
	font-size: 1rem;
}

/* Batch marker, pinned to the hero's bottom-right corner. */
.ne-batch {
	position: absolute;
	right: 24px;
	bottom: 22px;
	z-index: 2;
	margin: 0;
	font-family: var(--ne-mono);
	font-size: 0.66rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--wp--preset--color--brand-on) 85%, transparent);
	background: color-mix(in srgb, var(--wp--preset--color--brand-deep) 42%, transparent);
	backdrop-filter: blur(3px);
	border: 1px solid color-mix(in srgb, var(--wp--preset--color--brand-on) 32%, transparent);
	border-radius: 100px;
	padding: 5px 12px;
}

/* -- Buttons ------------------------------------------------------------ */
.wp-block-button__link {
	transition: transform 0.15s var(--ne-ease), background-color 0.2s var(--ne-ease),
		color 0.2s var(--ne-ease);
}

.wp-block-button__link:hover {
	transform: translateY(-1px);
}

/* Outline button: fills on hover. */
.is-style-outline > .wp-block-button__link,
.wp-block-button__link.is-style-outline {
	background-color: transparent;
	border-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--brand);
}

.is-style-outline > .wp-block-button__link:hover,
.wp-block-button__link.is-style-outline:hover {
	background-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--brand-on);
}

/* On a dark ground the primary flips to turmeric, and the outline picks up a
   light stroke so it always clears contrast over photography. */
.ne-hero .wp-block-button:not(.is-style-outline) .wp-block-button__link {
	background-color: var(--wp--preset--color--accent);
	color: #241A06;
}

.ne-hero .wp-block-button:not(.is-style-outline) .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--accent-lt);
	color: #241A06;
}

.ne-hero .is-style-outline > .wp-block-button__link {
	border-color: color-mix(in srgb, var(--wp--preset--color--brand-on) 55%, transparent);
	color: var(--wp--preset--color--brand-on);
}

.ne-hero .is-style-outline > .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--brand-on);
	color: var(--wp--preset--color--brand);
}

/* -- Trust strip -------------------------------------------------------- */
/* Its own band below the hero, never inside it. */
.ne-trust {
	border-bottom: 1px solid var(--ne-line);
}

.ne-trust p {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--wp--preset--color--ink-soft);
}

.ne-stars {
	color: var(--wp--preset--color--accent-ink);
	letter-spacing: 2px;
}

.ne-on-dark .ne-stars {
	color: var(--wp--preset--color--accent-lt);
}

/* The card is a link. Only the image and the heading carry the anchor, so the
   description stays selectable, and the whole card lifts on hover from either
   one. No underline on the heading: the hover state and the Read more line
   already signal it. */
.ne-ing a {
	text-decoration: none;
	color: inherit;
}

.ne-ing .ne-ing-media a {
	display: block;
	height: 100%;
	border-radius: inherit;
}

.ne-ing h3 a:hover {
	color: var(--wp--preset--color--brand);
}

/* Read more sits in its own row at the foot of the card. margin-top:auto
   pushes it down, and because carousel items stretch to the tallest card in
   the row, every Read more lands on the same line no matter how long the
   description above it runs. The hairline makes that shared baseline read as
   deliberate rather than accidental. */
.ne-ing-more {
	margin: 18px 0 0;
	padding-top: 14px;
	margin-top: auto;
	border-top: 1px solid var(--ne-line);
}

.ne-ing-more a {
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.78rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--accent-ink);
}

.ne-ing-more a:hover {
	color: var(--wp--preset--color--brand);
}

.ne-ing-more span[aria-hidden] {
	display: inline-block;
	transition: transform 200ms var(--ne-ease);
}

.ne-ing:hover .ne-ing-more span[aria-hidden] {
	transform: translateX(3px);
}

/* Visually hidden, still read aloud. Gives each Read more link a unique
   accessible name instead of eight identical ones. */
.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* Drag to scroll, mouse only. The grab cursor is the affordance; while a drag
   is in flight text selection is suppressed so the gesture does not paint a
   selection across the cards. */
.ne-carousel-track {
	cursor: grab;
}

.ne-carousel-track.is-dragging {
	cursor: grabbing;
	user-select: none;
}

.ne-carousel-track.is-dragging a {
	pointer-events: none;
}

/* -- Rules and framing -------------------------------------------------- */
.ne-rule-top {
	border-top: 1px solid var(--ne-line);
}

.ne-framed img {
	border-radius: var(--ne-radius);
}

/* -- Ingredient carousel ------------------------------------------------ */
/* One row that scrolls, rather than a wrapping grid. Built on native
   overflow scrolling with scroll snapping, so with JavaScript disabled it is
   still a usable, swipeable, keyboard-scrollable row: the script only adds
   the dots, the arrows, the autoplay and the seamless loop on top.

   --ne-per-view is the single dial for how many cards are in view. The item
   width is derived from it, so the breakpoints only ever change that number
   and never touch the arithmetic. */
.ne-carousel {
	--ne-per-view: 4;
	--ne-gap: var(--wp--preset--spacing--40);
	position: relative;
}

.ne-carousel-track {
	display: flex;
	gap: var(--ne-gap);
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	scrollbar-width: none;
	-ms-overflow-style: none;
}

/* The track used to carry 4px of padding with a -4px margin, to stop the
   scroll container clipping focus rings. That pushed every card 4px left of
   the section heading above it, which was visible. The ring is pulled inside
   the card instead, so the card's left edge and the heading's left edge are
   the same line. */
.ne-carousel-track :focus-visible {
	outline-offset: -2px;
}

.ne-carousel-track::-webkit-scrollbar {
	display: none;
}

/* Honour the user's motion preference for the programmatic scrolls too. */
@media (prefers-reduced-motion: reduce) {
	.ne-carousel-track {
		scroll-behavior: auto;
	}
}

.ne-carousel-track > * {
	flex: 0 0 calc(
		(100% - (var(--ne-per-view) - 1) * var(--ne-gap)) / var(--ne-per-view)
	);
	scroll-snap-align: start;
	margin-block-start: 0;
	margin-block-end: 0;
}

@media (max-width: 1024px) {
	.ne-carousel {
		--ne-per-view: 2;
	}
}

@media (max-width: 640px) {
	.ne-carousel {
		--ne-per-view: 1;
	}
}

/* Controls. Injected by the script, so nothing here renders without it. */
.ne-carousel-controls {
	display: flex;
	justify-content: center;
	align-items: center;
	margin-top: var(--wp--preset--spacing--40);
}

.ne-carousel-dots {
	display: flex;
	align-items: center;
	gap: 2px;
}

.ne-carousel-dot {
	display: grid;
	place-items: center;
	width: 24px;
	height: 24px;
	padding: 0;
	border: 0;
	background: transparent;
	cursor: pointer;
}

.ne-carousel-dot::before {
	content: "";
	width: 9px;
	height: 9px;
	border-radius: var(--ne-radius-pill);
	border: 1px solid color-mix(in srgb, var(--wp--preset--color--ink) 40%, transparent);
	transition: background 200ms var(--ne-ease), transform 200ms var(--ne-ease);
}

.ne-carousel-dot[aria-current="true"]::before {
	background: var(--wp--preset--color--accent);
	border-color: var(--wp--preset--color--accent);
}

.ne-carousel-dot:hover::before {
	transform: scale(1.2);
}

/* One arrow either side of the row, clear of the cards, centred on the card
   photograph rather than on the whole card: the caption below the image makes
   a card much taller than its picture, so a true vertical centre would leave
   the arrows floating somewhere around the Read more link.

   --ne-arrow-top is measured by the script, because the image height is
   derived from the card width and CSS cannot read one axis off the other.
   The percentage is only a pre-measurement fallback.

   The row is 1180px wide, so the arrows need roughly 1300px of viewport
   before there is any margin to sit in. Below that they go, and the row is
   driven by swipe, drag and the dots instead. */
.ne-carousel {
	--ne-arrow-gap: 18px;
}

.ne-carousel-arrow {
	position: absolute;
	top: var(--ne-arrow-top, 33%);
	transform: translateY(-50%);
	display: grid;
	place-items: center;
	width: 42px;
	height: 42px;
	padding: 0;
	cursor: pointer;
	color: var(--wp--preset--color--brand-on);
	background: var(--wp--preset--color--brand-deep);
	border: 1px solid var(--wp--preset--color--brand-deep);
	border-radius: var(--ne-radius-pill);
	transition: background 200ms var(--ne-ease), border-color 200ms var(--ne-ease);
}

/* Hover lifts to the mid green rather than lightening toward the page, so the
   control stays a negative element throughout and never half-dissolves into
   the cream background it sits on. */
.ne-carousel-arrow:hover {
	background: var(--wp--preset--color--brand);
	border-color: var(--wp--preset--color--brand);
}

.ne-carousel-arrow--prev {
	inset-inline-end: 100%;
	margin-inline-end: var(--ne-arrow-gap);
}

.ne-carousel-arrow--next {
	inset-inline-start: 100%;
	margin-inline-start: var(--ne-arrow-gap);
}

@media (max-width: 1300px) {
	.ne-carousel-arrow {
		display: none;
	}
}

.ne-carousel-arrow svg {
	width: 16px;
	height: 16px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.75;
}

.ne-ing {
	display: flex;
	flex-direction: column;
}

.ne-ing-media {
	margin: 0 0 var(--wp--preset--spacing--30);
	aspect-ratio: 1 / 1;
	overflow: hidden;
	border-radius: var(--ne-radius);
	background: color-mix(in srgb, var(--ne-line) 45%, transparent);
}

.ne-ing-media img {
	display: block;
	border-radius: inherit;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 700ms var(--ne-ease);
}

.ne-ing:hover .ne-ing-media img {
	transform: scale(1.045);
}

@media (prefers-reduced-motion: reduce) {
	.ne-ing-media img,
	.ne-ing:hover .ne-ing-media img {
		transition: none;
		transform: none;
	}
}

/* An empty holder reads as "photograph still to come" rather than as a
   broken image. Editorial only, so it is hidden from assistive tech. */
.ne-ing-media.is-empty {
	display: grid;
	place-items: center;
}

.ne-ing-media.is-empty::after {
	content: "Image to come";
	font-family: var(--ne-mono);
	font-size: 0.7rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--ink-soft);
	opacity: 0.55;
}

.ne-ing h3 {
	margin: 0 0 6px;
}

/* The compound name inside the description. Newsreader carries an optical-size
   axis and no weight axis, so <strong> in body copy gets faux-bolded by the
   browser: a smeared approximation rather than a drawn bold. The compound is
   marked with the accent ink instead, which is a real distinction the font can
   actually deliver. The <strong> stays for semantics. */
.ne-ing strong {
	font-weight: inherit;
	font-synthesis: none;
	color: var(--wp--preset--color--accent-ink);
}

.ne-ing p:last-child {
	margin-bottom: 0;
}

/* The description keeps its natural height; the gap goes to the Read more row
   above, not inside the prose. */
.ne-ing > p {
	margin-bottom: 0;
}

/* -- Long-form article -------------------------------------------------- */
/* The magazine feel comes from the furniture around the column, not from
   splitting the prose. Multi-column body text works on paper because a page
   is taller than it is wide; on a screen it forces the eye back up the
   viewport on every column break. So the measure stays single and readable,
   and the pull quotes, citation cards and full-bleed images break out of it. */
.ne-article-grid {
	/* One dial for the measure. 82ch is a deliberate compromise: wide enough
	   that the column carries the extra page width rather than floating in it,
	   short enough that the eye still finds the start of the next line. */
	--ne-measure: 82ch;
	display: grid;
	/* The measure is a real column, not "whatever is left over". Sizing it here
	   and centring the set means there is no accidental empty column left over. */
	grid-template-columns: 190px minmax(0, var(--ne-measure));
	justify-content: center;
	gap: var(--wp--preset--spacing--60);
	/* NOT align-items: start. The rail box has to be as tall as the article
	   for position:sticky to have anywhere to travel; start-aligning it
	   collapsed the box to the height of the list, so the rail scrolled away
	   with the first screen and was useless from then on. */
	align-items: stretch;
}

.ne-article-grid > * {
	margin-block-start: 0;
	margin-block-end: 0;
}

/* Three columns once there is genuinely room for three. The column gap comes
   down from 104px to 64px here: at 104px the set needs about 1470px before
   padding, which a 1440 laptop does not have, and the rail would be pushed off
   on exactly the machines most likely to see it. */
@media (min-width: 1440px) {
	.ne-article-grid {
		grid-template-columns: 190px minmax(0, var(--ne-measure)) 280px;
		column-gap: var(--wp--preset--spacing--50);
	}
}

/* The ingredient rail is the first thing to go, well before the contents rail:
   it is a convenience, not a way through the article. */
@media (max-width: 1439px) {
	.ne-article-aside {
		display: none;
	}
}

/* Below the point where a rail would squeeze the measure, it goes away
   entirely rather than becoming a stubby list above the article. */
@media (max-width: 1023px) {
	.ne-article-grid {
		grid-template-columns: minmax(0, 1fr);
	}

	.ne-article-rail {
		display: none;
	}
}

.ne-article-prose {
	/* Width comes from the grid column. A max-width here would fight it. */
	max-width: none;
}

.ne-article-prose > * + * {
	margin-block-start: var(--wp--preset--spacing--30);
}

.ne-article-prose h2 {
	margin-block-start: var(--wp--preset--spacing--50);
	scroll-margin-top: 110px;
}

.ne-article-prose h3 {
	margin-block-start: var(--wp--preset--spacing--40);
}

/* Standfirst: the one paragraph that sets up the whole piece. */
.ne-article-head .ne-standfirst {
	max-width: 60ch;
	font-size: var(--wp--preset--font-size--lg);
	line-height: 1.55;
	color: var(--wp--preset--color--ink-soft);
	margin-top: var(--wp--preset--spacing--30);
	/* The head contents sit in a flow-layout inner group rather than directly
	   in the constrained one. Constrained layout centres every child narrower
	   than the content size, and it does so with !important, so a narrow
	   standfirst floated to the middle while the H1 stayed left. Flow layout
	   applies no inline margins at all, which is the fix: the wrapper holds
	   the content edge and everything inside it simply starts there. */
	margin-inline-start: 0;
}

.ne-article-head > * {
	margin-block-end: 0;
}

/* -- Article title and hero -------------------------------------------- */
.ne-article-title {
	font-size: clamp(2.8rem, 6.5vw, 5rem);
	line-height: 0.98;
	letter-spacing: -0.02em;
	max-width: 16ch;
}

/* Full-bleed hero under the head band. A fixed ratio so the band below it
   never jumps as the image loads. */
.ne-article-hero {
	margin-block: 0;
}

.ne-article-hero img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
	display: block;
}

@media (max-width: 782px) {
	.ne-article-hero {
		aspect-ratio: 16 / 10;
	}

	.ne-article-hero img {
		aspect-ratio: 16 / 10;
	}
}

/* -- Contents rail ------------------------------------------------------ */
.ne-toc {
	position: sticky;
	top: 110px;
	font-family: var(--wp--preset--font-family--display);
}

.ne-toc-title {
	margin: 0 0 10px;
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--wp--preset--color--muted);
}

.ne-toc-list {
	margin: 0;
	padding: 0;
	list-style: none;
	border-left: 1px solid var(--ne-line);
}

.ne-toc-list li {
	margin: 0;
}

.ne-toc-list a {
	display: block;
	padding: 7px 0 7px 14px;
	margin-left: -1px;
	border-left: 2px solid transparent;
	font-size: 0.84rem;
	line-height: 1.35;
	color: var(--wp--preset--color--ink-soft);
	text-decoration: none;
	transition: color 200ms var(--ne-ease), border-color 200ms var(--ne-ease);
}

.ne-toc-list a:hover {
	color: var(--wp--preset--color--brand);
}

.ne-toc-list a.is-current {
	color: var(--wp--preset--color--brand);
	border-left-color: var(--wp--preset--color--accent);
}

/* -- Ingredient rail ---------------------------------------------------- */
/* The right-hand column: the other eight ingredients, as a way across the set
   rather than back to the index.

   Deliberately NOT sticky, unlike the contents rail. Eight picture cards are
   far taller than any viewport, so pinning the column would just freeze a
   cropped third of it and make the rest unreachable. It scrolls with the
   article instead, which is also why running past the end of the prose is
   fine here: the reader arrives at it having finished reading.

   Rendered by the naturalelixir/ingredient-rail block, not written into the
   template, because the list has to drop whichever ingredient the reader is
   already on. */
/* The label itself is a .ne-badge span; this only positions it. Kept as a rule of
   its own because the ingredient rail, the post rail and the journal aside all use
   it and all want the same gap beneath. */
.ne-ing-rail-title {
	margin: 0 0 var(--wp--preset--spacing--30);
	line-height: 1;
}

.ne-ing-rail-list {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--40);
}

.ne-ing-rail-list li {
	margin: 0;
}

/* The whole card is the target, not just the title. */
.ne-ing-rail-list a {
	display: block;
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

.ne-ing-rail-thumb {
	display: block;
	aspect-ratio: 4 / 3;
	overflow: hidden;
	margin-bottom: 12px;
	border-radius: var(--ne-radius);
	background: color-mix(in srgb, var(--ne-line) 45%, transparent);
}

.ne-ing-rail-thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: inherit;
	transition: transform 700ms var(--ne-ease);
}

.ne-ing-rail-list a:hover .ne-ing-rail-thumb img {
	transform: scale(1.045);
}

.ne-ing-rail-name {
	display: block;
	font-family: var(--wp--preset--font-family--display);
	font-size: 1rem;
	font-weight: 600;
	line-height: 1.25;
	transition: color 200ms var(--ne-ease);
}

.ne-ing-rail-list a:hover .ne-ing-rail-name {
	color: var(--wp--preset--color--brand);
}

.ne-ing-rail-note {
	display: block;
	margin-top: 4px;
	font-size: 0.85rem;
	line-height: 1.4;
	color: var(--wp--preset--color--ink-soft);
}

@media (prefers-reduced-motion: reduce) {
	.ne-ing-rail-thumb img,
	.ne-ing-rail-list a:hover .ne-ing-rail-thumb img {
		transition: none;
		transform: none;
	}
}

/* -- Ingredients index grid --------------------------------------------- */
/* The hub. Deliberately built from the rail's card parts rather than from the
   homepage carousel's, so the two ingredient surfaces read as one family and
   there is a single set of card styles to maintain. Three across, because nine
   ingredients divide into three clean rows and a four-column grid would leave a
   widowed card on the last line. */
.ne-ing-grid {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40);
}

.ne-ing-grid li {
	margin: 0;
}

/* Ten ingredients into three columns leaves one card alone on the last row,
   hanging off the left edge like a mistake. Centre it. The selector only fires
   when the final card is also the first of its row, so nine items or twelve are
   untouched and the rule maintains itself as the list changes. */
.ne-ing-grid li:last-child:nth-child(3n + 1) {
	grid-column: 2;
}

@media (max-width: 1023px) {
	.ne-ing-grid li:last-child:nth-child(3n + 1) {
		grid-column: auto;
	}
}

.ne-ing-grid a {
	display: block;
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

.ne-ing-grid .ne-ing-rail-thumb {
	margin-bottom: var(--wp--preset--spacing--30);
}

.ne-ing-grid .ne-ing-rail-name {
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 400;
	margin: 0;
}

.ne-ing-grid .ne-ing-rail-note {
	margin-top: 6px;
	font-size: 0.95rem;
}

@media (max-width: 1023px) {
	.ne-ing-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 600px) {
	.ne-ing-grid {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* -- Pull quote --------------------------------------------------------- */
/* Breaks left out of the measure on wide screens, which is what makes the
   page read as edited rather than typed. Falls back to full width when there
   is no margin to break into. */
.ne-pullquote {
	margin-block: var(--wp--preset--spacing--60);
	padding: var(--wp--preset--spacing--30) 0;
	border-top: 2px solid var(--wp--preset--color--accent);
	border-bottom: 2px solid var(--wp--preset--color--accent);
	font-family: var(--wp--preset--font-family--body);
	font-size: 1.65rem;
	line-height: 1.32;
	font-style: italic;
	color: var(--wp--preset--color--brand-deep);
}

.ne-pullquote p {
	margin: 0;
}

/* -- Citation card ------------------------------------------------------ */
/* Where a claim rests on a specific paper, the paper gets its own box rather
   than a bare inline link. It signals "this is sourced" at a glance and gives
   the reader somewhere to go. */
.ne-cite {
	margin-block: var(--wp--preset--spacing--30);
	padding: 12px var(--wp--preset--spacing--30);
	background: var(--wp--preset--color--bg-alt);
	border-radius: var(--ne-radius-sm);
	border-left: 3px solid var(--wp--preset--color--brand);
	font-size: 0.86rem;
	line-height: 1.5;
}

/* -- Insert badges ------------------------------------------------------ */
/* Two kinds of insert interrupt an article, and a reader should be able to tell
   which is which before reading a word of it. Research is evidence from
   somewhere else; the tonic note is us talking about our own product. Keeping
   them visually distinct is an honesty device as much as a design one.

   Shared shape here, colour below. Both are reversed out rather than tinted,
   because a filled badge reads at a glance and a tinted one does not. */
/* block + fit-content, not inline-block: the badge has to hug its own text and
   still push the paragraph onto the next line. Inline-block leaves the copy
   sitting alongside it, and .ne-cite p is display:inline, so there is no line
   box to rely on. */
.ne-badge,
.ne-cite::before,
.ne-product-note .ne-cite-label {
	display: block;
	width: fit-content;
	margin-bottom: 10px;
	padding: 4px 10px 3px;
	border-radius: var(--ne-radius-pill);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	line-height: 1.2;
	text-transform: uppercase;
	letter-spacing: 0.12em;
}

/* Research: the brand green, because evidence is the serious voice on the page.
   The eyebrow is a pseudo-element rather than markup, so every citation card in
   every article gets it without touching the copy, and a new article cannot
   forget it. */
.ne-badge-research,
.ne-cite::before {
	content: "Research";
	background: var(--wp--preset--color--sage);
	color: var(--wp--preset--color--brand-deep);
}

/* In our tonic: the accent amber, which is the colour of the liquid, sitting on
   the dark panel below. Applied to the label already in the markup, so existing
   articles pick it up unchanged. */
.ne-badge-tonic,
.ne-product-note .ne-cite-label {
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--brand-deep);
}

/* Above the point where there is real margin to use, citations float into it.
   They then line up on a single right-hand edge and sit beside the paragraph
   that references them, instead of interrupting the read. This is the old
   sidenote pattern and it is what makes the column look edited rather than
   dumped. Below that width they fall back into the flow, full measure. */
/* Deliberately NOT floated into a margin column.
   That version looked right in isolation and fell apart in use: two citations
   in a row stacked into one tall float, everything after them had to clear it,
   and the page filled with holes in both columns. Across nine articles of
   different lengths that is unmanageable.
   These sit in the flow instead, one or two lines each, directly under the
   claim they support. Nothing clears anything, so the column stays dense
   whatever the content does. */
.ne-cite p {
	display: inline;
}

.ne-cite .ne-cite-label {
	margin-right: 6px;
}

.ne-cite p {
	margin: 0;
	font-size: 0.92rem;
	line-height: 1.5;
}

.ne-cite p + p {
	margin-top: 8px;
}

/* Shared by citation cards and product notes, so it is not scoped to either. */
.ne-cite-label {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--wp--preset--color--accent-ink);
}

/* -- In-article imagery ------------------------------------------------- */
/* Breaks the measure up. Figures never exceed the column: an image sitting
   past the content edge reads as a bug, not a device. */
.ne-figure {
	margin-block: var(--wp--preset--spacing--50);
}

/* Figures are always exactly the measure. They used to break past the right
   edge, which put them outside the content block and read as a mistake rather
   than a device.

   The fixed ratio does two jobs: images crop naturally at the content border
   instead of dictating their own height, and a portrait source can no longer
   push a single figure to a thousand pixels tall. Cropping is centred, so a
   subject in the middle of the frame survives. Anything where the right-hand
   side genuinely matters should be cropped before upload rather than fixed
   here. */
.ne-figure img {
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	object-position: center;
	display: block;
	border-radius: var(--ne-radius);
}

.ne-figure figcaption,
.ne-figure .ne-figcaption {
	margin-top: 10px;
	font-size: 0.82rem;
	line-height: 1.45;
	color: var(--wp--preset--color--muted);
}


/* -- Product note ------------------------------------------------------- */
/* The thin commercial layer. Deliberately quiet and visually distinct from
   the article, so a reader can tell at a glance which voice is speaking. */
/* Reversed out, so the one place we talk about our own product is the one place
   on the page a reader cannot mistake for editorial. It also gives a scanner a
   fixed landmark: once you have read one ingredient page you know the dark panel
   is where the tonic is discussed, and you can go straight to it. */
.ne-product-note {
	margin-block: var(--wp--preset--spacing--50);
	padding: var(--wp--preset--spacing--40);
	background: var(--wp--preset--color--brand-deep);
	border: 0;
	border-radius: var(--ne-radius);
	color: var(--wp--preset--color--brand-on);
}

.ne-product-note a {
	color: var(--wp--preset--color--accent-lt);
	text-underline-offset: 3px;
	text-decoration-thickness: 1px;
}

.ne-product-note a:hover {
	color: var(--wp--preset--color--brand-on);
}

.ne-product-note p {
	margin: 0;
}

.ne-product-note p + p {
	margin-top: 12px;
}

/* The badge shape and colour are set with the insert badges further up; this
   only has to break the label onto its own line, because .ne-cite-label is
   otherwise an inline accent used inside citation cards. */
.ne-product-note .ne-cite-label {
	margin-right: 0;
}

/* -- FAQ ---------------------------------------------------------------- */
.ne-faq {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--40);
	margin-block-start: var(--wp--preset--spacing--40);
}

@media (max-width: 782px) {
	.ne-faq {
		grid-template-columns: minmax(0, 1fr);
	}
}

.ne-faq > * {
	margin-block-start: 0;
}

.ne-faq h3 {
	margin: 0 0 8px;
	font-size: 1rem;
}

.ne-faq p {
	margin: 0;
	font-size: 0.94rem;
}

/* -- Disclaimer --------------------------------------------------------- */
.ne-disclaimer {
	margin-block-start: var(--wp--preset--spacing--60);
	padding-top: var(--wp--preset--spacing--30);
	border-top: 1px solid var(--ne-line);
	font-size: 0.86rem;
	line-height: 1.55;
	color: var(--wp--preset--color--muted);
}

/* -- Footer ------------------------------------------------------------- */
.ne-footer {
	background: var(--wp--preset--color--brand-deep);
	color: var(--wp--preset--color--brand-on);
}

.ne-footer a,
.ne-footer .wp-block-navigation-item__content {
	color: var(--wp--preset--color--brand-on);
	text-decoration: none;
}

.ne-footer a:hover,
.ne-footer .wp-block-navigation-item__content:hover {
	color: var(--wp--preset--color--accent-lt);
	text-decoration: underline;
}

.ne-footer h2,
.ne-footer h3,
.ne-footer h4 {
	color: var(--wp--preset--color--brand-on);
}

/* -- Motion ------------------------------------------------------------- */
/* motion dial 0.25: hover states and one gentle entrance, nothing more.
   Reveals degrade to visible if the observer never runs. */
@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;
	}

	.wp-block-button__link:hover {
		transform: none;
	}
}

/* -- Mobile collapse ---------------------------------------------------- */
@media (max-width: 781px) {
	/* The wordmark is a wide lockup; it has to give ground once the nav
	   collapses to a toggle and the row gets tight. */
	.ne-header .ne-brandmark img {
		height: 22px;
	}

	.ne-hero {
		min-height: min(78vh, 620px);
	}

	/* A left-to-right scrim has nowhere to go on a narrow column, so it turns
	   vertical and the copy sits on the dark end. */
	.ne-hero::after {
		background: linear-gradient(
			180deg,
			color-mix(in srgb, var(--wp--preset--color--brand-deep) 45%, transparent) 0%,
			color-mix(in srgb, var(--wp--preset--color--brand-deep) 82%, transparent) 100%
		);
	}

	.ne-hero-media .ne-slide img {
		object-position: 60% 50%;
	}

	.ne-trust {
		text-align: center;
	}
}

/* ============================================================
   PRODUCT PAGES
   ============================================================ */

/* MEASURED FACTS. Every figure in this strip comes off a laboratory certificate,
   so it is set as data rather than as prose: a fixed grid of equal cells, no
   adjectives, no icons. The restraint is the point. A claim that has a number
   behind it should not look like a marketing badge. */
.ne-facts {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
	gap: 1px;
	margin: var(--wp--preset--spacing--40) 0 0;
	padding: 0;
	list-style: none;
	background: var(--ne-line);
	border: 1px solid var(--ne-line);
	border-radius: var(--ne-radius);
	overflow: hidden;
}

.ne-facts li {
	display: flex;
	flex-direction: column;
	gap: 4px;
	margin: 0;
	padding: 16px 18px;
	background: var(--wp--preset--color--surface);
}

.ne-fact-head {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--md);
	font-weight: 600;
	line-height: 1.2;
	color: var(--wp--preset--color--brand-deep);
}

.ne-fact-note {
	font-size: var(--wp--preset--font-size--xs);
	line-height: 1.45;
	color: var(--wp--preset--color--ink-soft);
}

.ne-facts-source {
	margin-top: 10px;
	font-size: var(--wp--preset--font-size--xs);
	color: var(--wp--preset--color--muted);
}

/* INGREDIENT GRID. A 4x2 block of thumbnails, because a product page is scanned
   rather than read: a shopper wants to see what is in the bottle at a glance and
   click the one they care about. The descriptions that used to sit here moved to
   the ingredient pages themselves, which is where somebody who wants them is
   already heading. */
.ne-tonic-grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--wp--preset--spacing--20);
	margin: var(--wp--preset--spacing--30) 0 0;
	padding: 0;
	list-style: none;
}

.ne-tonic-grid li {
	margin: 0;
}

.ne-tonic-grid a {
	display: flex;
	flex-direction: column;
	gap: 10px;
	height: 100%;
	text-decoration: none;
	text-align: center;
}

.ne-tg-thumb {
	display: block;
	overflow: hidden;
	border-radius: var(--ne-radius);
	background: var(--wp--preset--color--bg-alt);
	aspect-ratio: 1;
}

.ne-tg-thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
	transition: transform 350ms var(--ne-ease);
}

.ne-tonic-grid a:hover .ne-tg-thumb img {
	transform: scale(1.06);
}

.ne-tg-name {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	line-height: 1.25;
	color: var(--wp--preset--color--brand-deep);
}

.ne-tonic-grid a:hover .ne-tg-name {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.ne-tg-note {
	font-size: var(--wp--preset--font-size--xs);
	line-height: 1.4;
	color: var(--wp--preset--color--ink-soft);
}

/* Whatever falls outside the eight cards is still named and linked, so the grid
   never silently contradicts a description that says ten botanicals. */
.ne-tonic-grid-rest {
	margin-top: var(--wp--preset--spacing--30);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--wp--preset--color--ink-soft);
}

@media (max-width: 781px) {
	.ne-tonic-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

/* VARIANT NOTE. The "how this one differs" panel. Same negative treatment as the
   ingredient pages' tonic callout, so a reader moving between the two recognises
   it as the same kind of statement. */
.ne-variant-note {
	margin: var(--wp--preset--spacing--40) 0 0;
	padding: 20px 22px;
	background: var(--wp--preset--color--brand-deep);
	color: var(--wp--preset--color--brand-on);
	border-radius: var(--ne-radius);
}

.ne-variant-note p {
	margin: 0;
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.6;
}

.ne-variant-note strong {
	color: var(--wp--preset--color--accent-lt);
}

.ne-variant-note a {
	color: var(--wp--preset--color--brand-on);
	text-underline-offset: 3px;
}

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

.ne-breadcrumbs {
	color: var(--wp--preset--color--muted);
}

.ne-breadcrumbs a {
	color: var(--wp--preset--color--ink-soft);
	text-underline-offset: 3px;
}

/* The gallery is the one image on the page a customer studies, so it gets the
   card radius rather than the tighter image radius, and the Woo default border
   is dropped: the product photography is on white and a border only fences it. */
.woocommerce-product-gallery__image img,
.wp-block-woocommerce-product-image-gallery img {
	border-radius: var(--ne-radius-lg);
}

/* THUMBNAIL STRIP. Woo ships these as 25%-wide floats with margin:0 and no
   gutter, so the tiles butt into each other and into the main image above.

   Woo's own selector is `.woocommerce div.product div.images .flex-control-thumbs`,
   specificity (0,4,2). A first attempt here was scoped from
   `.woocommerce-product-gallery` alone, (0,2,0), and lost: `gap` applied because
   Woo sets none, while `width` and `margin` did not. That is why four tiles at
   Woo's 25% plus gutters overflowed and wrapped to a second row, and why there
   was no space above the strip. These rules mirror Woo's chain and add one class
   so they clear it outright.

   The tile width is DERIVED, not typed, so four always fit one row: take the
   exact four-up width, subtract the gutters, then scale down so the strip reads
   as navigation under the main image rather than a second gallery competing with
   it. Retune the four dials below; leave the rules alone. */
.woocommerce-product-gallery {
	--ne-thumb-gap: 14px;
	--ne-thumb-top: 20px;
	--ne-thumb-cols: 4;
	--ne-thumb-scale: 0.9;
}

.woocommerce div.product div.images.woocommerce-product-gallery .flex-control-thumbs {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ne-thumb-gap);
	margin: var(--ne-thumb-top) 0 0;
	padding: 0;
	overflow: visible;
	list-style: none;
}

.woocommerce div.product div.images.woocommerce-product-gallery .flex-control-thumbs li {
	float: none;
	clear: none;
	width: calc(
		(100% - (var(--ne-thumb-cols) - 1) * var(--ne-thumb-gap))
		/ var(--ne-thumb-cols) * var(--ne-thumb-scale)
	);
	margin: 0;
	list-style: none;
}

.woocommerce div.product div.images.woocommerce-product-gallery .flex-control-thumbs img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--ne-radius);
}

/* BUY COLUMN. Woo's blocks each bring their own margins, which stack into an
   uneven ladder. One owned gap replaces all of them so title, price, summary
   and button sit on a single rhythm. */
.ne-product-buy > * {
	margin-block: 0;
}

.ne-product-buy {
	display: flex;
	flex-direction: column;
	gap: 18px;
}

.ne-product-buy .wp-block-post-title {
	font-family: var(--wp--preset--font-family--display);
	color: var(--wp--preset--color--brand-deep);
}

/* Price carries the accent, the only place on the page it appears, so the eye
   lands on it without the number needing to shout. */
.ne-product-buy .wc-block-components-product-price,
.ne-product-buy .price {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 600;
	color: var(--wp--preset--color--accent-ink);
}

/* A struck-through "was" price is a claim about history, so it is set quietly
   rather than as a flash of red. See docs/product-pages-audit.md: most of these
   sales have no end date, which is a question for the client before launch. */
.ne-product-buy del {
	font-weight: 400;
}

.ne-product-buy ins {
	text-decoration: none;
}

.ne-product-short {
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.6;
	color: var(--wp--preset--color--ink-soft);
}

.ne-product-buy .quantity input {
	padding: 10px;
	border: 1px solid var(--ne-line);
}

.ne-product-buy .single_add_to_cart_button {
	width: 100%;
	padding: 15px 22px;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--brand-on);
	border: 0;
	transition: background 200ms var(--ne-ease);
}

.ne-product-buy .single_add_to_cart_button:hover {
	background: var(--wp--preset--color--brand-deep);
}

/* PACK UPSELL. Sits directly under the add to cart button, which is the one
   moment the shopper has already decided to buy and is only choosing how much.
   Placed in the buy column rather than under the gallery on purpose: the two
   columns stack on mobile, and a left-column placement would push this above
   the price and the button instead of after them.

   Set quietly. The real saving on a four pack is around eight percent, which
   does not carry a loud treatment, so the figures are stated plainly and the
   free-delivery line is allowed to do the persuading. Every number in the
   markup is computed from live prices in ne2026_render_pack_upsell(). */
.ne-upsell {
	border: 1px solid var(--ne-line);
	border-radius: var(--ne-radius-sm);
	background: var(--wp--preset--color--bg-alt);
}

.ne-upsell-link {
	display: flex;
	gap: 14px;
	align-items: center;
	padding: 12px 14px;
	text-decoration: none;
	color: inherit;
	transition: background 200ms var(--ne-ease);
}

.ne-upsell-link:hover,
.ne-upsell-link:focus-visible {
	background: var(--wp--preset--color--surface);
}

/* Fixed-basis media well: the pack shots are all on white at the same scale, so
   a shared box keeps the row height identical across the three flavours. */
.ne-upsell-media {
	flex: 0 0 68px;
	display: block;
}

.ne-upsell-media img {
	display: block;
	width: 100%;
	height: auto;
	box-sizing: border-box;
}

.ne-upsell-body {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}

.ne-upsell-eyebrow {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--brand-deep);
}

.ne-upsell-name {
	font-size: var(--wp--preset--font-size--sm);
	color: var(--wp--preset--color--ink);
}

.ne-upsell-price {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 600;
	color: var(--wp--preset--color--accent-ink);
}

.ne-upsell-each {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 400;
	color: var(--wp--preset--color--muted);
}

.ne-upsell-save,
.ne-upsell-ship {
	font-size: var(--wp--preset--font-size--xs);
	color: var(--wp--preset--color--ink-soft);
}

/* The delivery line is the stronger argument of the two, so it gets the only
   emphasis in the block. */
.ne-upsell-ship {
	color: var(--wp--preset--color--brand-deep);
}

/* The block is inside .ne-upsell, whose own price rule would otherwise be
   caught by the buy column's .price selector. It is not, but the strike-through
   reset below is scoped anyway so a future sale price on a pack cannot leak the
   buy column's treatment into this card. */
.ne-upsell del {
	display: none;
}

/* Product meta is reference information, not selling copy. */
.ne-product-buy .product_meta {
	padding-top: 14px;
	font-size: var(--wp--preset--font-size--xs);
	color: var(--wp--preset--color--muted);
	border-top: 1px solid var(--ne-line);
}

/* BODY. The description is prose and takes the reading measure, but the facts
   strip is data and is allowed to run the full width of the column. */
.ne-product-body h2,
.ne-product-body h3 {
	margin-top: var(--wp--preset--spacing--50);
	color: var(--wp--preset--color--brand-deep);
}

.ne-product-body h3:first-child {
	margin-top: 0;
}

.ne-product-body .ne-disclaimer {
	margin-top: var(--wp--preset--spacing--50);
	padding-top: 16px;
	font-size: var(--wp--preset--font-size--xs);
	color: var(--wp--preset--color--muted);
	border-top: 1px solid var(--ne-line);
}

@media (max-width: 781px) {
	.ne-product-buy {
		gap: 14px;
	}
}

/* -- Reviews ------------------------------------------------------------ */

.ne-product-reviews {
	padding-top: var(--wp--preset--spacing--40);
	border-top: 1px solid var(--ne-line);
}

.wp-block-woocommerce-product-reviews-title {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--lg);
	color: var(--wp--preset--color--brand-deep);
}

/* REVIEW CARD. Five reviews across the catalogue is not enough to hide in a
   list, so each one is given a card and room to breathe. The quotation mark is
   set large and pale behind the text: it reads as a pull quote rather than a
   comment thread, which is what a handful of good reviews deserves. */
.ne-review {
	position: relative;
	margin-bottom: var(--wp--preset--spacing--30);
	padding: 26px 28px;
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--ne-line);
	border-radius: var(--ne-radius-lg);
}

.ne-review::before {
	content: "\201C";
	position: absolute;
	top: 4px;
	right: 22px;
	font-family: var(--wp--preset--font-family--display);
	font-size: 5rem;
	line-height: 1;
	color: var(--wp--preset--color--line);
	pointer-events: none;
}

.ne-review-head {
	align-items: center;
	gap: 12px;
}

/* Initials disc. Generated from the reviewer's name in PHP: no Gravatar
   request, no third party, and a stable colour per person. */
.ne-review-avatar {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 44px;
	height: 44px;
	border-radius: 50%;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--brand-on);
	user-select: none;
}

.ne-avatar-a { background: var(--wp--preset--color--brand); }
.ne-avatar-b { background: var(--wp--preset--color--brand-deep); }
.ne-avatar-c { background: var(--wp--preset--color--accent-ink); }
.ne-avatar-d { background: var(--wp--preset--color--muted); }
.ne-avatar-e { background: var(--wp--preset--color--sage); color: var(--wp--preset--color--brand-deep); }

.ne-review .wp-block-woocommerce-product-review-author-name {
	font-size: var(--wp--preset--font-size--md);
}

.ne-review .wp-block-woocommerce-product-review-rating {
	margin-top: 14px;
}

.ne-review .wp-block-woocommerce-product-review-content {
	margin-top: 10px;
	font-size: var(--wp--preset--font-size--md);
	line-height: 1.6;
	color: var(--wp--preset--color--ink);
}

.wp-block-woocommerce-product-review-author-name {
	font-weight: 600;
	color: var(--wp--preset--color--brand-deep);
}

.wp-block-woocommerce-product-review-date {
	color: var(--wp--preset--color--muted);
}

.wp-block-woocommerce-product-review-content {
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.65;
}

/* VERIFIED PURCHASE. Sage rather than the turmeric accent: this is a statement
   of fact about an order, not a promotion, and it should read as quiet
   corroboration rather than as a sticker. Deliberately understated, because a
   badge that shouts invites the question of who is checking. */
.ne-verified {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	margin-inline-start: 8px;
	padding: 2px 9px 1px;
	border-radius: var(--ne-radius-pill);
	background: var(--wp--preset--color--sage);
	color: var(--wp--preset--color--brand-deep);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.04em;
	white-space: nowrap;
	vertical-align: middle;
}

.ne-verified::before {
	content: "\2713";
	font-weight: 700;
}

/* The invitation matters more than the display while there are five reviews on
   the whole catalogue, so the form is given a panel of its own rather than
   trailing off the bottom of the list. */
.wp-block-woocommerce-product-review-form {
	margin-top: var(--wp--preset--spacing--40);
	padding: 22px 24px;
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--ne-line);
	border-radius: var(--ne-radius);
}

.wp-block-woocommerce-product-review-form .comment-reply-title {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--md);
	font-weight: 600;
	color: var(--wp--preset--color--brand-deep);
}

.ne-product-related .wp-block-woocommerce-product-template {
	list-style: none;
	padding: 0;
}

.ne-reviews-note {
	margin-top: var(--wp--preset--spacing--30);
	font-size: var(--wp--preset--font-size--xs);
	line-height: 1.6;
	color: var(--wp--preset--color--muted);
}

/* WIDTH. The product hero is alignwide (1180px) but the sections below inherit
   the 760px reading measure, so the grid and the facts table stopped short of
   the gallery above them and the page looked like two different documents.

   Redefining the content-size custom property on these containers is what lets
   one rule fix all of them: core's constrained layout reads that property, so
   every descendant including the nested post-content picks it up without having
   to target each block. Breakpoints are untouched. */
.ne-product-body,
.ne-product-reviews,
.ne-product-related {
	--wp--style--global--content-size: var(--ne-maxw);
}

/* Body copy keeps a readable measure inside the wider column rather than
   running to 1180px, which would be a 140 character line. It still starts on
   the same left edge as the grid and the gallery, so the alignment reads as
   intentional. Remove this rule if the text should fill the full width. */
/* TWO-COLUMN SECTIONS. Two short prose sections sit side by side, each keeping
   its own heading directly above its own text. Splitting heading from text
   across the columns was tried first and read as a caption beside a slab.

   This also avoids the specificity problem underneath: core's constrained
   layout sets margin-left/right to auto with !important, so a narrow max-width
   inside it can only ever centre itself. A grid child is positioned by the
   grid, so nothing has to argue with core. */
.ne-cols {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: var(--wp--preset--spacing--50);
	align-items: start;
	margin-top: var(--wp--preset--spacing--50);
}

.ne-cols > * > :first-child {
	margin-top: 0;
}

/* Same breakpoint the ingredient grid drops on, so the page reflows in one
   step rather than in two. */
@media (max-width: 781px) {
	.ne-cols {
		grid-template-columns: 1fr;
		row-gap: var(--wp--preset--spacing--40);
	}
}

/* Bottle spec. The last line of the short description, immediately above Add to
   Cart, where a shopper checks what they are actually buying. */
.ne-spec {
	display: inline-block;
	padding: 5px 12px 4px;
	border: 1px solid var(--ne-line);
	border-radius: var(--ne-radius-pill);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--ink-soft);
}

/* Related products reuse the ingredient card, so they only need the price. */
.ne-prod-price {
	margin-top: 6px;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--md);
	font-weight: 600;
	color: var(--wp--preset--color--accent-ink);
}

.ne-prod-price del {
	font-weight: 400;
}

.ne-prod-price ins {
	text-decoration: none;
}

.ne-related-carousel {
	margin-top: var(--wp--preset--spacing--30);
}

/* -- Journal posts ------------------------------------------------------ */
/* Posts run on the ingredient article's furniture: same head band, same
   full-bleed hero, same 190px / measure / 280px grid. What changes is the
   right-hand column, which carries other articles rather than other
   ingredients, and a grid of three at the foot so a reader who finishes has
   somewhere to go. See ne2026_render_post_rail(). */

/* Post titles run longer than ingredient names, which are one or two words.
   16ch turns "Where My Healing Journey Began" into five short lines. */
.ne-post .ne-article-title {
	max-width: 20ch;
}

/* post-terms renders links, so the eyebrow colour has to reach them. */
.ne-post .ne-eyebrow a {
	color: inherit;
	text-decoration: none;
}

.ne-post .ne-eyebrow a:hover {
	text-decoration: underline;
}

.ne-post-date {
	margin-top: var(--wp--preset--spacing--30);
}

/* -- Journal rail and foot grid ----------------------------------------- */
/* Both are the same block. The rail is the ingredient rail's cards unchanged;
   only the grid variant and the trailing link are new here. */
.ne-post-rail-more {
	margin-top: var(--wp--preset--spacing--40);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
}

.ne-post-rail-more a {
	color: var(--wp--preset--color--accent-ink);
	text-decoration: none;
	border-bottom: 1px solid currentColor;
	padding-bottom: 2px;
}

.ne-post-rail-more a:hover {
	color: var(--wp--preset--color--brand);
}

/* The foot band: the same cards, three across, so finishing an article opens
   onto the next one rather than onto the footer. */
/* Four across on desktop, and two across all the way down rather than collapsing to
   one. Dax, 2026-08-17: one card per row at the foot of an article was a lot of
   scrolling for very little, and a 2x2 block puts four ways out of the page in the
   space one used to take. The thumbnails get smaller, which at this size costs
   nothing. */
.ne-post-grid .ne-ing-rail-list {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--50);
}

@media (max-width: 1023px) {
	.ne-post-grid .ne-ing-rail-list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 600px) {
	.ne-post-grid .ne-ing-rail-list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--40) var(--wp--preset--spacing--30);
	}

	/* Two to a row at phone width means the note is the first thing to go. */
	.ne-post-grid .ne-ing-rail-note {
		display: none;
	}

	.ne-post-grid .ne-ing-rail-name {
		font-size: 0.92rem;
	}
}

.ne-post-grid .ne-ing-rail-title {
	margin-bottom: var(--wp--preset--spacing--40);
}

/* The foot band is hidden when it would duplicate the rail: below 1440px the
   aside is gone, so the grid is the only way on, and above it the grid still
   earns its place as the end-of-article move. Both stay. */
.ne-journal-foot {
	margin-top: 0;
}

/* -- The Journal index -------------------------------------------------- */
/* A featured lead, then category sections. Built from one card so the index,
   the category archives and the foot of every post all look like one family.
   Rendered by ne2026_render_journal(); the categories and their order come from
   ne2026_journal_categories(). */

.ne-journal-head .ne-eyebrow a {
	color: inherit;
	text-decoration: none;
}

.ne-journal-head .ne-article-title {
	max-width: 24ch;
}

/* -- The featured article ------------------------------------------------ */
/* Two columns rather than an image with text over it. An overlay needs a scrim
   to stay legible, the scrim fights the palette, and a headline set over a
   photograph cannot be trusted to hold contrast across an arbitrary featured
   image. Side by side always works. */
.ne-jfeature {
	display: grid;
	grid-template-columns: 1.15fr 1fr;
	gap: var(--wp--preset--spacing--50);
	align-items: center;
}

@media (max-width: 781px) {
	.ne-jfeature {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--wp--preset--spacing--40);
	}
}

.ne-jfeature-media {
	display: block;
	aspect-ratio: 4 / 3;
	overflow: hidden;
	border-radius: var(--ne-radius);
	background: color-mix(in srgb, var(--ne-line) 45%, transparent);
}

.ne-jfeature-media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: inherit;
	transition: transform 700ms var(--ne-ease);
}

.ne-jfeature-media:hover img {
	transform: scale(1.03);
}

.ne-jfeature-title {
	margin: 0;
	font-size: clamp(1.9rem, 3.4vw, 2.9rem);
	line-height: 1.08;
	letter-spacing: -0.015em;
}

.ne-jfeature-title a {
	color: inherit;
	text-decoration: none;
}

.ne-jfeature-title a:hover {
	color: var(--wp--preset--color--brand);
}

.ne-jfeature-excerpt {
	margin: var(--wp--preset--spacing--30) 0 0;
	max-width: 52ch;
	font-size: var(--wp--preset--font-size--md);
	line-height: 1.6;
	color: var(--wp--preset--color--ink-soft);
}

.ne-jfeature-more {
	margin: var(--wp--preset--spacing--40) 0 0;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
}

.ne-jfeature-more a {
	color: var(--wp--preset--color--accent-ink);
	text-decoration: none;
	border-bottom: 1px solid currentColor;
	padding-bottom: 2px;
}

.ne-jfeature-more a:hover {
	color: var(--wp--preset--color--brand);
}

/* -- Category sections -------------------------------------------------- */
.ne-jsection + .ne-jsection {
	margin-top: var(--wp--preset--spacing--60);
}

.ne-jsection-head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--30);
	padding-bottom: 10px;
	border-bottom: 1px solid var(--ne-line);
}

/* -- The category badge -------------------------------------------------- */
/* Dax, 2026-08-17: he preferred the rail label's treatment (all caps, display face,
   khaki green) to the plain section headings, and asked for it inverted as a badge.
   So there is now one .ne-badge and every category label on the site uses it: the
   journal section headings, the journal aside, the post rail and the ingredient rail.
   One label style, four places.

   On the colour. The rail label was `muted` (#79806C) as text on paper. Inverted
   directly, #79806C behind #EDEFE3 lands at about 3.1:1, which fails WCAG AA for
   text this small. Mixing sage toward brand-deep keeps it unmistakably the same
   khaki green, darkens it enough to reach roughly 4.9:1, and avoids falling back on
   forest, which would have read as the button colour rather than as a label. */
.ne-badge {
	display: inline-block;
	padding: 5px 12px 4px;
	border-radius: var(--ne-radius-pill);
	background: #5d6c57;
	background: color-mix(in srgb, var(--wp--preset--color--sage) 72%, var(--wp--preset--color--brand-deep));
	color: var(--wp--preset--color--brand-on);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	line-height: 1.25;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	transition: background 200ms var(--ne-ease);
}

a:hover .ne-badge {
	background: var(--wp--preset--color--brand);
}

.ne-jsection-title {
	margin: 0;
	font-size: 1rem;
	line-height: 1.2;
}

.ne-jsection-title a {
	color: inherit;
	text-decoration: none;
}

/* Sits on the baseline with the heading, so it must not wrap. */
.ne-jsection-more {
	flex: none;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--wp--preset--color--muted);
	text-decoration: none;
	white-space: nowrap;
}

.ne-jsection-more:hover {
	color: var(--wp--preset--color--brand);
}

.ne-jsection-note {
	margin: 12px 0 var(--wp--preset--spacing--40);
	max-width: 60ch;
	font-size: 0.92rem;
	line-height: 1.5;
	color: var(--wp--preset--color--ink-soft);
}

/* -- The card ----------------------------------------------------------- */
/* data-cols carries the column count from the block so one grid rule serves
   every placement, and the count is a template decision rather than a class. */
.ne-journal-grid {
	display: grid;
	grid-template-columns: repeat(var(--ne-jcols, 3), minmax(0, 1fr));
	gap: var(--wp--preset--spacing--50);
}

.ne-journal-grid[data-cols="2"] {
	--ne-jcols: 2;
}

.ne-journal-grid[data-cols="4"] {
	--ne-jcols: 4;
}

/* The responsive overrides carry [data-cols] so they match the specificity of the
   rules above and win on source order. Written as a bare .ne-journal-grid they lost
   to .ne-journal-grid[data-cols="2"] at every width, so a two-column grid stayed two
   columns on a phone: roughly 150px per card inside the split column, which is what
   made the index look broken rather than merely tight. Specificity beats media
   queries, and a media query is not a tiebreaker. */
@media (max-width: 1023px) {
	.ne-journal-grid[data-cols] {
		--ne-jcols: 2;
	}
}

@media (max-width: 599px) {
	.ne-journal-grid[data-cols] {
		--ne-jcols: 1;
		gap: var(--wp--preset--spacing--40);
	}
}

/* A series with exactly one card to show, which the render function now declares
   honestly as data-cols="1" instead of leaving a hole in a two-up row.

   There was no rule for it, so --ne-jcols fell back to 3 and the lone card rendered
   at a third of the column with two thirds of nothing beside it, which looked worse
   than the gap it was meant to fix. It gets a horizontal layout instead: image left,
   text right, filling the row and reading as a deliberate wide card.

   Not a media query, so it also applies while a series is young and grows out of it
   on its own the moment a second post lands. */
.ne-journal-grid[data-cols="1"] {
	--ne-jcols: 1;
}

@media (min-width: 600px) {
	.ne-journal-grid[data-cols="1"] .ne-jcard {
		display: grid;
		grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
		grid-template-rows: auto auto 1fr;
		column-gap: var(--wp--preset--spacing--40);
		align-items: start;
	}

	.ne-journal-grid[data-cols="1"] .ne-jcard-thumb {
		grid-column: 1;
		grid-row: 1 / span 3;
		margin-bottom: 0;
	}

	.ne-journal-grid[data-cols="1"] .ne-jcard-cat,
	.ne-journal-grid[data-cols="1"] .ne-jcard-title,
	.ne-journal-grid[data-cols="1"] .ne-jcard-excerpt {
		grid-column: 2;
	}
}

.ne-jcard {
	margin: 0;
	display: flex;
	flex-direction: column;
}

.ne-jcard-thumb {
	display: block;
	aspect-ratio: 3 / 2;
	overflow: hidden;
	margin-bottom: 14px;
	border-radius: var(--ne-radius);
	background: color-mix(in srgb, var(--ne-line) 45%, transparent);
}

.ne-jcard-thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: inherit;
	transition: transform 700ms var(--ne-ease);
}

.ne-jcard:hover .ne-jcard-thumb img {
	transform: scale(1.045);
}

.ne-jcard-cat {
	margin: 0 0 6px;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--wp--preset--color--accent-ink);
}

.ne-jcard-cat a {
	color: inherit;
	text-decoration: none;
}

.ne-jcard-title {
	margin: 0;
	font-size: 1.18rem;
	line-height: 1.25;
}

.ne-jcard-title a {
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

.ne-jcard-title a:hover {
	color: var(--wp--preset--color--brand);
}

.ne-jcard-excerpt {
	margin: 8px 0 0;
	font-size: 0.92rem;
	line-height: 1.5;
	color: var(--wp--preset--color--ink-soft);
}

/* -- Main column and aside ---------------------------------------------- */
.ne-journal-split {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 280px;
	gap: var(--wp--preset--spacing--50);
	align-items: start;
}

/* This used to hide the aside below 1024px, on the grounds that it was a
   convenience rather than a way through the journal. That stopped being true when
   the full-width band came off and Plant facts, Popular myths and Customer stories
   moved into the rail: hiding it would drop three of the six series from the index
   on every phone. So it stacks beneath the main column instead. The rail format is
   already a single column of thumb, title and note, which is what it would be on a
   phone anyway. */
@media (max-width: 1023px) {
	.ne-journal-split {
		grid-template-columns: minmax(0, 1fr);
	}

	.ne-journal-side {
		margin-top: var(--wp--preset--spacing--60);
	}
}

.ne-jaside .ne-ing-rail-list {
	gap: var(--wp--preset--spacing--40);
}

/* The rail keeps the site-wide card: image above, title, then excerpt. It is the
   same shape as the ingredient rail and the post rail, and Dax's instruction on
   2026-08-17 is that it stays the same shape everywhere.

   There WAS a compact variant here, a 76px square beside the text, invented to stop
   the journal index rail running a thousand pixels past the centre column. It solved
   that and broke consistency: the Our Story page then carried a rail that matched
   nothing else on the site. **Rail height is controlled by how many items a block
   asks for, not by giving one page its own card.** The index now asks each block for
   two. Adjust the `limit` attribute in the template, never this. */

/* -- Pagination on the category archives -------------------------------- */
.ne-journal-pagination {
	margin-top: var(--wp--preset--spacing--60);
	padding-top: var(--wp--preset--spacing--40);
	border-top: 1px solid var(--ne-line);
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.9rem;
}

/* The archive builds its cards from core blocks rather than from
   ne2026_journal_card(), because the query loop has to stay a real query for
   pagination to work. These three rules are what make core's output match the
   hand-built card. */
.ne-journal-archive .ne-jcard-thumb img {
	margin-bottom: 0;
}

.ne-journal-archive .ne-jcard-cat {
	font-style: normal;
}

.ne-journal-archive .ne-jcard-title a {
	color: var(--wp--preset--color--ink);
}

/* -- Story pages (Our Story and anything like it) ----------------------- */
/* Runs on the article furniture with the journal's aside and foot sections, so a
   nav-level page reads as part of the same publication rather than as an orphan.
   Registered as the "Story page" custom template. */
.ne-story-prose {
	max-width: 68ch;
}

.ne-story-prose > * + * {
	margin-block-start: var(--wp--preset--spacing--30);
}

.ne-story-prose h2 {
	margin-block-start: var(--wp--preset--spacing--50);
}

.ne-story-prose h3 {
	margin-block-start: var(--wp--preset--spacing--40);
	font-size: 1.15rem;
}

/* The practical block: address, shipping, contact. Set as data rather than prose,
   the same restraint as the product facts strip, because a reader scanning for a
   delivery cost should not have to read a sentence to find it. */
.ne-factlist {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: var(--wp--preset--spacing--40);
	margin-block-start: var(--wp--preset--spacing--40);
	padding-block: var(--wp--preset--spacing--40);
	border-top: 1px solid var(--ne-line);
	border-bottom: 1px solid var(--ne-line);
}

.ne-factlist > div {
	margin: 0;
}

.ne-factlist dt,
.ne-factlist .ne-factlist-label {
	margin: 0 0 6px;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--wp--preset--color--muted);
}

.ne-factlist dd,
.ne-factlist .ne-factlist-value {
	margin: 0;
	font-size: 0.98rem;
	line-height: 1.5;
}

.ne-factlist a {
	color: var(--wp--preset--color--accent-ink);
}

/* Empty category series on the journal index. */
.ne-jsection-empty {
	grid-column: 1 / -1;
	margin: 0;
	padding: var(--wp--preset--spacing--40) 0;
	font-size: 0.95rem;
	color: var(--wp--preset--color--muted);
}

/* -- Horizontal overflow guard ------------------------------------------ */
/* `clip` and deliberately not `hidden`. overflow:hidden on the root turns it into a
   scroll container, which silently kills position:sticky, and this theme depends on
   sticky in three places: the header, the article contents rail and the journal
   sidebar. overflow-x:clip stops the sideways drift without creating a scroll port,
   so all three keep working.

   This is a guard rather than a diagnosis. The mobile drift on the front page has not
   been traced to a single element yet: the hero crossfades in place inside
   overflow:hidden, the carousel is a self-contained scroller, and nothing in the
   stylesheet uses a viewport width or a negative margin big enough to do it. The
   likeliest remaining cause is one of the ~380KB of leftover ThemeREX and Elementor
   stylesheets that load AFTER this one. See docs/blog-migration-plan.md §11. */
/* Measured 2026-08-17 with headless Chrome on an iPhone 13 profile, after two wrong
   guesses. The front page does not overflow: the hero is exactly 390px wide with no
   child past the viewport. What pans is the **ingredient carousel track**, which the
   script clones for a seamless loop and which therefore reports a scrollWidth of
   about 10,580px against a 318px box. It is `overflow-x: auto` by design, so it is
   touch-pannable, and its size propagates up through every ancestor.

   The clip belongs on .wp-site-blocks, not on html. Two reasons:

   1. ThemeREX sets `html { overflow-y: scroll !important }`. Per CSS Overflow 3, a
      `clip` on one axis computes to `hidden` when the other axis is `scroll`, so the
      rule we wrote as `clip` was silently becoming `hidden` on the root. Measured:
      html resolved to `overflow-x: hidden`.
   2. Root-element overflow relies on propagation to the viewport, and iOS Safari does
      not honour that reliably when a descendant has a very large scrollWidth. A plain
      div does not depend on propagation, and .wp-site-blocks wraps everything.

   body keeps its clip, where it resolves as `clip` rather than `hidden` because its
   other axis is `visible`. html is left alone so nothing fights the plugin and so the
   sticky header keeps the viewport as its scroll container. */
body {
	overflow-x: clip;
	max-width: 100%;
}

.wp-site-blocks {
	overflow-x: clip;
}

/* -- The category index in the sidebar ---------------------------------- */
/* Every series in one column, so the index page does not need a full section
   for each. Rendered by ne2026_render_journal() in `categories` mode. */
.ne-jcatindex {
	margin-bottom: var(--wp--preset--spacing--50);
}

.ne-jcatindex-list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.ne-jcatindex-list li {
	margin: 0;
	border-bottom: 1px solid var(--ne-line);
}

.ne-jcatindex-list a,
.ne-jcatindex-list li.is-empty {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 10px;
	padding: 11px 0;
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.95rem;
	line-height: 1.3;
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

.ne-jcatindex-list a:hover {
	color: var(--wp--preset--color--brand);
}

/* An empty series is present but plainly not yet a destination. */
.ne-jcatindex-list li.is-empty {
	color: var(--wp--preset--color--muted);
}

.ne-jcatindex-count {
	flex: none;
	font-size: 0.78rem;
	font-variant-numeric: tabular-nums;
	color: var(--wp--preset--color--muted);
}

/* The sidebar is a stack of blocks, so it needs its own rhythm. Each block after
   the first also gets a rule above it, because five stacked rails with nothing
   between them read as one long undifferentiated list. */
.ne-journal-side > * + * {
	margin-top: var(--wp--preset--spacing--50);
	padding-top: var(--wp--preset--spacing--50);
	border-top: 1px solid var(--ne-line);
}

/* NOT sticky. It was, back when the column held two blocks and was shorter than the
   viewport. It now runs the length of the page by design, and pinning an element
   taller than the viewport freezes it part-scrolled and strands everything below
   the fold permanently out of reach. */

/* The lean state: a series whose posts all appear higher in the rail still shows its
   badge and its route in, so the column keeps its rhythm instead of dropping a
   block. See the `aside` branch of ne2026_render_journal(). */
.ne-jaside-note {
	margin: 10px 0 0;
	font-size: 0.9rem;
	line-height: 1.5;
	color: var(--wp--preset--color--ink-soft);
}

/* The category index again, laid out wide instead of as a column. Used at the foot
   of a category archive, where seven full sections would repeat the whole journal
   under every single series. The component is the same; only the list flows. */
.ne-journal-rest .ne-jcatindex-list {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
	gap: 0 var(--wp--preset--spacing--50);
}

.ne-journal-rest .ne-jcatindex {
	margin-bottom: 0;
}

/* -- The category digest ------------------------------------------------- */
/* The foot of a category archive: one card per other series, carrying its leading
   article's image and excerpt with the category name in bold. It replaced a
   compressed text list, which told a reader the other series existed without giving
   them a reason to open one. Rendered by ne2026_render_journal() in `digest` mode. */
.ne-jdigest-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
	gap: var(--wp--preset--spacing--50);
	margin-top: var(--wp--preset--spacing--40);
}

@media (max-width: 600px) {
	.ne-jdigest-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--40) var(--wp--preset--spacing--30);
	}
}

.ne-jdigest {
	margin: 0;
	display: flex;
	flex-direction: column;
}

.ne-jdigest-thumb {
	display: block;
	aspect-ratio: 3 / 2;
	overflow: hidden;
	margin-bottom: 14px;
	border-radius: var(--ne-radius);
	background: color-mix(in srgb, var(--ne-line) 55%, transparent);
}

.ne-jdigest-thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: inherit;
	transition: transform 700ms var(--ne-ease);
}

.ne-jdigest:hover .ne-jdigest-thumb img {
	transform: scale(1.045);
}

.ne-jdigest-cat {
	margin: 0 0 8px;
	line-height: 1;
}

.ne-jdigest-cat a {
	text-decoration: none;
}

/* Bold, per Dax. The badge above it carries the series; this carries the article. */
.ne-jdigest-title {
	margin: 0;
	font-size: 1.05rem;
	font-weight: 700;
	line-height: 1.25;
}

.ne-jdigest-title a {
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

.ne-jdigest-title a:hover {
	color: var(--wp--preset--color--brand);
}

.ne-jdigest-excerpt {
	margin: 8px 0 0;
	font-size: 0.9rem;
	line-height: 1.5;
	color: var(--wp--preset--color--ink-soft);
}

/* An empty series has no image to lead with, so it sits as a label and a line and
   does not pretend to be a card with something behind it. */
.ne-jdigest.is-empty {
	padding-top: 4px;
}

.ne-jdigest.is-empty .ne-jdigest-excerpt {
	color: var(--wp--preset--color--muted);
}

@media (max-width: 600px) {
	.ne-jdigest-excerpt {
		display: none;
	}

	.ne-jdigest.is-empty .ne-jdigest-excerpt {
		display: block;
	}
}

/* -- Customer story disclaimer, at the top ------------------------------- */
/* Above the story rather than under it. On a testimonial the disclaimer has to be
   read before the account, not after it: a reader who has already absorbed somebody's
   experience is not going to revise it on the strength of a footnote. Playbook §6
   calls for an adjacent disclaimer, and adjacent here means first. */
.ne-disclaimer-top {
	margin-bottom: var(--wp--preset--spacing--50);
	padding: var(--wp--preset--spacing--30);
	border: 1px solid var(--ne-line);
	border-radius: var(--ne-radius);
	background: color-mix(in srgb, var(--wp--preset--color--bg-alt) 60%, transparent);
}

.ne-disclaimer-top p {
	margin: 0;
	font-size: 0.85rem;
	line-height: 1.55;
	color: var(--wp--preset--color--ink-soft);
}

.ne-disclaimer-top strong {
	color: var(--wp--preset--color--ink);
}

/* -- Numbered key points ------------------------------------------------- */
/* Replaces the bullet lists whose items all began with a bold lead-in. Dax,
   2026-08-17: the lead-in is doing the work of a heading, so it should look like one,
   and a numbered sequence pulls the eye in further than a bullet.

   One component, two modes. `ne-steps` on an <ol> numbers itself with a CSS counter;
   `is-plain` on a <ul> drops the number and keeps everything else. The distinction is
   editorial rather than decorative: a number implies order or rank, so it belongs on
   advice, checklists and cautions, and not on a roster. Numbering the ten ingredients
   1 to 10 would read as a league table. */
.ne-steps {
	counter-reset: ne-step;
	list-style: none;
	margin: var(--wp--preset--spacing--40) 0 0;
	padding: 0;
	display: grid;
	gap: var(--wp--preset--spacing--30);
}

.ne-steps > li {
	counter-increment: ne-step;
	position: relative;
	margin: 0;
	padding-left: 46px;
}

/* The number, set in the display face and the turmeric ink so it reads as a marker
   rather than as body text. Tabular so 9 and 10 line up. */
.ne-steps > li::before {
	content: counter(ne-step);
	position: absolute;
	left: 0;
	top: 1px;
	width: 30px;
	text-align: right;
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.95rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--wp--preset--color--accent-ink);
}

.ne-steps.is-plain > li {
	padding-left: 0;
}

.ne-steps.is-plain > li::before {
	content: none;
}

/* The lead-in, on its own line. Slightly larger than the body and in full ink, so it
   holds as a heading without needing an actual heading tag: a real h4 inside every
   list item would clutter the document outline and the generated contents rail. */
.ne-steps-title {
	display: block;
	margin-bottom: 3px;
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.04rem;
	font-weight: 600;
	line-height: 1.3;
	color: var(--wp--preset--color--ink);
}

.ne-steps-body {
	display: block;
	color: var(--wp--preset--color--ink-soft);
	line-height: 1.6;
}

/* Inside the narrow journal sidebar and the product column there is no room for the
   hanging number, so it tucks in. */
@media (max-width: 600px) {
	.ne-steps > li {
		padding-left: 34px;
	}

	.ne-steps > li::before {
		width: 22px;
	}
}

/* -- Acronym list -------------------------------------------------------- */
/* For a mnemonic, where the initial letter IS the content. C.R.A.P. was briefly
   converted to .ne-steps, which split "C" from "arbonated" and destroyed the word;
   it went back to a plain list and then read as weaker than every upgraded list
   around it.

   So the letter is emphasised in place rather than pulled out into a column. The word
   stays whole, the mnemonic still works, and the list carries the same weight as its
   neighbours. Markup is unchanged: <strong>C</strong>arbonated drinks. */
.ne-acronym {
	list-style: none;
	margin: var(--wp--preset--spacing--40) 0 0;
	padding: 0;
	display: grid;
	gap: 10px;
}

.ne-acronym > li {
	margin: 0;
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.15rem;
	font-weight: 500;
	line-height: 1.3;
	color: var(--wp--preset--color--ink);
}

.ne-acronym > li strong {
	font-size: 1.5em;
	font-weight: 700;
	line-height: 1;
	color: var(--wp--preset--color--accent-ink);
}

/* -- Myth verdict -------------------------------------------------------- */
/* The answer, up front, before the explanation. A reader who came for the verdict
   should not have to scroll for it, and it is the paragraph most likely to be lifted
   into a search result. */
.ne-verdict {
	margin: 0 0 var(--wp--preset--spacing--40);
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border-left: 3px solid var(--wp--preset--color--accent-ink);
	background: color-mix(in srgb, var(--wp--preset--color--bg-alt) 55%, transparent);
	font-size: var(--wp--preset--font-size--md);
	line-height: 1.55;
}

.ne-verdict strong {
	color: var(--wp--preset--color--ink);
}

/* -- The sprout preloader ------------------------------------------------ */
/* Rendered by ne2026_sprout_preloader() on wp_body_open.

   ⚠ Read the guarantee before changing any timing here. The overlay's exit is
   written into the animation itself: `ne-preload-out` ends on visibility: hidden
   with `forwards`, so at 1.6s the overlay is gone whether or not a single line of
   JavaScript ran. The `.is-done` class only makes it leave EARLIER. Never move the
   exit into JavaScript alone: a preloader that fails to dismiss is a white screen,
   and it fails on exactly the slow connection it exists to reassure.

   ⚠ AND THE SECOND RULE, learned the hard way: the sprout cycle must be SHORTER
   than the overlay's life. The first version looped in 2.4s inside an overlay that
   left at 1.4s, so nobody ever saw a leaf open. One full grow and unfurl now
   completes by ~0.9s, and the script holds the overlay for 1.05s minimum so a fast
   load still shows the whole thing rather than a flash of bare stem. */
.ne-preload {
	position: fixed;
	inset: 0;
	z-index: 100000;
	display: grid;
	place-items: center;
	background: var(--wp--preset--color--bg);
	animation: ne-preload-out 1.6s var(--ne-ease) forwards;
}

.ne-preload.is-done {
	animation: ne-preload-out 0.4s var(--ne-ease) forwards;
}

@keyframes ne-preload-out {
	0%,
	70% {
		opacity: 1;
		visibility: visible;
	}
	100% {
		opacity: 0;
		visibility: hidden;
	}
}

.ne-sprout {
	width: 104px;
	height: 104px;
	overflow: visible;
}

/* The soil line sits still and gives the stem something to come out of. Without it
   the stem reads as a floating tick rather than as something growing. */
.ne-sprout-soil {
	stroke: var(--wp--preset--color--line);
	stroke-width: 2.5;
	stroke-linecap: round;
}

/* Drawn with dashoffset rather than scaleY so the tip travels and the base stays
   put, which is what growing looks like. 46 is a little longer than the path. */
.ne-sprout-stem {
	stroke: var(--wp--preset--color--brand);
	stroke-width: 3;
	stroke-linecap: round;
	stroke-dasharray: 46;
	stroke-dashoffset: 46;
	animation: ne-sprout-grow 1.5s var(--ne-ease) infinite;
}

@keyframes ne-sprout-grow {
	0% { stroke-dashoffset: 46; }
	34%, 80% { stroke-dashoffset: 0; }
	94%, 100% { stroke-dashoffset: 46; }
}

/* Each leaf unfurls from where it meets the stem, so transform-origin is the join
   and not the centre of the shape. Getting that wrong makes them slide in. The two
   origins are measured off the path bounding boxes in the markup; if you redraw a
   leaf you have to remeasure its join. */
.ne-sprout-leaf {
	fill: var(--wp--preset--color--sage);
	transform: scale(0);
	transform-box: fill-box;
	opacity: 0;
	animation: ne-sprout-unfurl 1.5s var(--ne-ease) infinite;
}

.ne-sprout-leaf-l {
	transform-origin: 100% 80%;
	animation-delay: 0.22s;
}

.ne-sprout-leaf-r {
	transform-origin: 0% 100%;
	animation-delay: 0.38s;
}

@keyframes ne-sprout-unfurl {
	0% { transform: scale(0); opacity: 0; }
	26%, 62% { transform: scale(1); opacity: 1; }
	76%, 100% { transform: scale(0); opacity: 0; }
}

/* No overlay at all for anyone who has asked for less movement: the whole point of
   it is decorative, and the page underneath is already there. */
@media (prefers-reduced-motion: reduce) {
	.ne-preload {
		display: none;
	}
}

/* The one this replaces. ThemeREX still renders its own page preloader, a ring of
   amber dots at #page_preloader / .preloader_wrap, and it was drawing on top of the
   sprout rather than instead of it. The body class goes in functions.php; this is
   the belt to that pair of braces, in case the plugin paints without it. */
#page_preloader,
.preloader_wrap,
body.preloader::before,
body.preloader::after {
	display: none !important;
}

/* The core loading bar for client-side navigation, which ships black. Same idea as
   the sprout, so it should at least be the same colour as the brand. */
.wp-interactivity-router-loading-bar {
	background-color: var(--wp--preset--color--brand) !important;
}

/* -- Article call-to-action buttons -------------------------------------- */
/* For hub pages, where Dax wanted the routes out of the article to carry real weight
   rather than being an underlined word in a sentence.

   ⚠ They are ONE SHAPE, ONE SIZE AND ONE COLOUR on purpose. The first version had a
   solid primary and two outlined secondaries, which Dax read off the page as three
   different components rather than one row of three choices. A row of buttons is a
   set: if one of them needs to look different, it belongs somewhere else.

   Sized to fit three labels of about twenty characters on a single line inside the
   836px prose column. Keep labels short or they wrap and the row stops reading as a
   set. Deliberately NOT used on ailment or ingredient pages, where a row of buttons
   would read as an advert interrupting the argument. */
.ne-ctarow {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px;
	margin: var(--wp--preset--spacing--40) 0;
}

/* Core's flow layout puts `margin-block-start` on every child after the first. Inside
   a flex row that is a top margin, so buttons two and three sat 24px lower than button
   one and the row measured 58px tall for 38px buttons. The block now declares
   layout:flex so core stops applying flow spacing at all; this reset is the belt to
   that brace, because the markup is hand-written and easy to paste wrong. */
.ne-ctarow > * {
	margin-block-start: 0;
	margin-block-end: 0;
}

.ne-cta {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 10px 16px;
	border-radius: var(--ne-radius-pill);
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--brand-on);
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.82rem;
	font-weight: 600;
	line-height: 1.2;
	white-space: nowrap;
	text-decoration: none;
	border: 1px solid var(--wp--preset--color--brand);
	transition: background 200ms var(--ne-ease), border-color 200ms var(--ne-ease);
}

/* The arrow is generated rather than typed so it can never end up in the excerpt,
   the RSS feed or a search result snippet. */
.ne-cta::after {
	content: "\2192";
	font-size: 1.05em;
	line-height: 1;
	transition: transform 200ms var(--ne-ease);
}

.ne-cta:hover,
.ne-cta:focus-visible {
	background: var(--wp--preset--color--brand-deep);
	border-color: var(--wp--preset--color--brand-deep);
	color: var(--wp--preset--color--brand-on);
}

.ne-cta:hover::after,
.ne-cta:focus-visible::after {
	transform: translateX(3px);
}

/* A button whose destination contains a video says so before the click. Dax: telling
   people there is something to watch is worth click-through, and it also stops the
   link feeling like one more thing to read. Play triangle instead of the arrow, not
   as well as it, so the button keeps exactly one glyph. */
.ne-cta.is-video::after {
	content: none;
}

.ne-cta.is-video::before {
	content: "";
	width: 0;
	height: 0;
	border-style: solid;
	border-width: 5px 0 5px 8px;
	border-color: transparent transparent transparent currentColor;
	flex: none;
}

@media (prefers-reduced-motion: reduce) {
	.ne-cta,
	.ne-cta::after {
		transition: none;
	}

	.ne-cta:hover::after,
	.ne-cta:focus-visible::after {
		transform: none;
	}
}

@media (max-width: 599px) {
	.ne-ctarow {
		flex-direction: column;
		align-items: stretch;
	}

	.ne-cta {
		justify-content: space-between;
	}

	.ne-cta.is-video {
		justify-content: flex-start;
	}
}

/* -- Verbatim quotation, in the founder's voice --------------------------- */
/* Distinct from .ne-pullquote on purpose, and the distinction carries meaning that
   matters more than the styling.

   .ne-pullquote is OUR emphasis: a line lifted out of the surrounding copy and made
   large because we chose to. .ne-voice is SOMEBODY ELSE SPEAKING, reproduced word for
   word, attributed. On the Our Story page the whole point is that the founder's
   account is his and not our paraphrase, so it has to look like testimony rather than
   like a design flourish. Marked up as a real <blockquote> with a <cite> so that is
   true for a screen reader and a search engine as well as for the eye.

   ⚠ Never put words in a .ne-voice block that the named person did not say. */
.ne-voice {
	margin: var(--wp--preset--spacing--50) 0;
	padding: var(--wp--preset--spacing--40) var(--wp--preset--spacing--40) var(--wp--preset--spacing--40) var(--wp--preset--spacing--50);
	border-left: 3px solid var(--wp--preset--color--accent);
	background: var(--wp--preset--color--surface);
	border-radius: 0 var(--ne-radius) var(--ne-radius) 0;
}

.ne-voice p {
	margin: 0 0 1em;
	font-size: 1.05rem;
	line-height: 1.65;
	color: var(--wp--preset--color--ink);
}

.ne-voice p:last-of-type {
	margin-bottom: 0;
}

.ne-voice cite {
	display: block;
	margin-top: var(--wp--preset--spacing--30);
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.8rem;
	font-style: normal;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--muted);
}

/* -- Accepted payment methods, footer ------------------------------------ */
/* South Africa's ECT Act requires an online supplier to disclose the payment
   methods it accepts, so this row is a legal element rather than decoration. It is
   built from the gateways actually switched on in WooCommerce: at the time of writing
   PayFast is the only one enabled, and bank transfer, cheque and cash on delivery are
   all off. If a gateway is enabled or disabled, this row changes with it.

   ⚠ The marks here are neutral pictograms with the scheme names in text, NOT the Visa
   and Mastercard brand logos. Redrawing a registered mark by hand is worse than not
   showing one. The licensed artwork comes from PayFast's merchant asset pack, and
   swapping these for it is a five minute job once someone downloads it. */
.ne-pay {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px 14px;
	margin-top: var(--wp--preset--spacing--30);
	font-size: 0.72rem;
	line-height: 1;
	color: color-mix(in srgb, var(--wp--preset--color--brand-on) 72%, transparent);
}

.ne-pay-label,
.ne-pay-note {
	font-family: var(--wp--preset--font-family--display);
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

.ne-pay-note {
	opacity: 0.75;
}

.ne-pay-mark {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	white-space: nowrap;
}

.ne-pay-mark svg {
	width: 26px;
	height: 17px;
	flex: none;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.5;
	stroke-linecap: round;
	stroke-linejoin: round;
}

@media (max-width: 599px) {
	.ne-pay {
		gap: 6px 10px;
		font-size: 0.68rem;
	}

	.ne-pay-note {
		flex-basis: 100%;
	}
}

/* -- The shop landing page ------------------------------------------------ */
/* /shop/ had no template at all in this block theme, so WooCommerce's archive fell back
   to bare WordPress: three category tiles, no styling, no hierarchy. It also gave equal
   billing to three top-level categories that are 98%, 0.09% and 0% of revenue.

   The page is composed by hand now, in sections, because ordering a shop is a
   merchandising decision rather than something to let a database answer. Rendered by
   ne2026_render_shop(). */
/* A strip, not a cover. It sets the tone and then gets out of the way: at full height
   it was costing a screen and a half of scrolling before anybody reached a product,
   which on a shop page is the wrong trade. Capped in viewport units as well as pixels
   so a short laptop screen never loses the whole fold to it.

   Raised from 340px to 460px in 0.12.5, when the beach scene was replaced by the
   product shot. The beach was a wide landscape that cropped happily to a short band.
   The replacement is a vertical composition: its bottle band measures ~589px at a
   1440px width, so a 340px strip discarded half the frame and cut the caps AND the
   bases. 460px is the agreed middle, chosen over the ~580px it would take to show the
   bottles whole, because that would have doubled the hero and pushed the products down
   the page. Caps are still clipped; `object-position` is set to 55% rather than centre
   so the bases and the table stay in frame, since bottles clipped at the foot read as
   floating while bottles clipped at the cap read as a deliberate band.
   max-height went to 60vh so the 460px is actually reachable on a normal laptop. */
/* ⚠ Selector carries .wp-block-image deliberately. Core ships
   `.wp-block-image img { height: auto }` and its stylesheet loads AFTER the theme's, so
   a bare `.ne-shop-hero img` ties on specificity and loses on source order. The height
   was silently ignored and only the max-height applied, which left a 540px hero rather
   than the 340px strip intended. */
figure.wp-block-image.ne-shop-hero img {
	display: block;
	width: 100%;
	height: clamp(260px, 34vw, 460px);
	max-height: 60vh;
	object-fit: cover;
	object-position: center 55%;
}

.ne-psection + .ne-psection {
	margin-top: var(--wp--preset--spacing--70, var(--wp--preset--spacing--60));
	padding-top: var(--wp--preset--spacing--60);
	border-top: 1px solid var(--ne-line);
}

.ne-psection-title {
	margin: 0 0 10px;
}

.ne-psection-note {
	margin: 0 0 var(--wp--preset--spacing--50);
	max-width: 62ch;
	font-size: 0.98rem;
	line-height: 1.6;
	color: var(--wp--preset--color--ink-soft);
}

/* The long tail sits quieter than the tonics on purpose. Between them these products
   are under one per cent of revenue, and the page should read that way. */
.ne-psection-minor .ne-psection-note,
.ne-psection-minor .ne-pcard-title {
	font-size: 0.92rem;
}

.ne-psection-minor {
	opacity: 0.92;
}

.ne-pgrid {
	display: grid;
	grid-template-columns: repeat(var(--ne-pcols, 3), minmax(0, 1fr));
	gap: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40);
}

.ne-pgrid[data-cols="1"] { --ne-pcols: 1; }
.ne-pgrid[data-cols="2"] { --ne-pcols: 2; }
.ne-pgrid[data-cols="3"] { --ne-pcols: 3; }
.ne-pgrid[data-cols="4"] { --ne-pcols: 4; }

/* Carrying [data-cols] so these match the specificity of the rules above and win on
   source order. A bare .ne-pgrid loses to .ne-pgrid[data-cols="4"] at every width,
   which is the bug that kept the journal two-up on phones. */
@media (max-width: 1023px) {
	.ne-pgrid[data-cols] { --ne-pcols: 3; }
}

@media (max-width: 781px) {
	.ne-pgrid[data-cols] { --ne-pcols: 2; }
}

@media (max-width: 479px) {
	.ne-pgrid[data-cols] { --ne-pcols: 1; }
}

.ne-pcard {
	margin: 0;
	display: flex;
	flex-direction: column;
}

/* Product shots are mostly a bottle on white, so the card gives them a tinted panel to
   sit in rather than letting a white square punch a hole in the page. */
.ne-pcard-thumb {
	display: block;
	aspect-ratio: 1;
	overflow: hidden;
	margin-bottom: 14px;
	border-radius: var(--ne-radius);
	background: var(--wp--preset--color--surface);
}

/* box-sizing MATTERS HERE. This stylesheet has no global `* { box-sizing:
   border-box }` reset, so every element is content-box by default. With
   width/height 100% AND padding 8%, the image box computed 311px inside a 268px
   card: it sat flush to the top left, overflowed 43px right and bottom, and was
   clipped by the card's `overflow: hidden`. That read as product shots pulled to
   the right, larger images cropped, and the card's surface tint showing as a
   pale strip down one side. Setting border-box makes the padding inset rather
   than additive, which is what the 8% was always meant to do.

   If another rule in this file combines a 100% dimension with padding, check it
   for the same fault before assuming the markup is wrong. */
.ne-pcard-thumb img {
	display: block;
	box-sizing: border-box;
	width: 100%;
	height: 100%;
	object-fit: contain;
	padding: 8%;
	transition: transform 500ms var(--ne-ease);
}

.ne-pcard:hover .ne-pcard-thumb img {
	transform: scale(1.04);
}

.ne-pcard-title {
	margin: 0;
	font-size: 1.02rem;
	line-height: 1.3;
}

.ne-pcard-title a {
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

.ne-pcard-title a:hover {
	color: var(--wp--preset--color--brand);
}

.ne-pcard-note {
	margin: 8px 0 0;
	font-size: 0.88rem;
	line-height: 1.5;
	color: var(--wp--preset--color--ink-soft);
}

.ne-pcard-price {
	margin: 10px 0 0;
	font-family: var(--wp--preset--font-family--display);
	font-size: 1rem;
	font-weight: 600;
	color: var(--wp--preset--color--brand);
}

.ne-pcard-price del {
	margin-right: 6px;
	font-weight: 400;
}

.ne-pcard-more {
	margin: 10px 0 0;
}

.ne-pcard-more a {
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.78rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--accent-ink);
}

@media (prefers-reduced-motion: reduce) {
	.ne-pcard-thumb img,
	.ne-pcard:hover .ne-pcard-thumb img {
		transition: none;
		transform: none;
	}
}

/* -- Price, and the discount badge --------------------------------------- */
/* ⚠ ONE RULE FOR EVERY PRICE STRIKETHROUGH ON THE SITE. Do not add another.
 *
 * This was fixed three times by enumerating containers, and each time another widget
 * turned up that had not been listed: the product page uses the
 * `woocommerce/product-price` BLOCK, the shop cards use .ne-pcard-price, the related
 * carousel uses .ne-prod-price, and the buy box uses .ne-product-buy. Enumeration was
 * always going to keep missing one.
 *
 * WooCommerce wraps every rendered amount in `.woocommerce-Price-amount`, wherever it
 * appears, so keying off that covers present and future widgets alike. Scoped inside
 * `del` so an editorial strikethrough in an article is untouched.
 *
 * ⚠ AND: three older rules put `opacity: 0.5` on the <del> itself. Opacity on a parent
 * multiplies everything inside it, so no colour set here could survive them. They have
 * been reduced to font-weight only. If a strikethrough ever looks washed out again,
 * look for an opacity on an ancestor before touching the colour. */
del .woocommerce-Price-amount,
del.woocommerce-Price-amount,
.wp-block-woocommerce-product-price del,
.ne-pcard-price del,
.ne-prod-price del,
.ne-product-buy del,
.woocommerce div.product p.price del,
.woocommerce div.product span.price del {
	color: var(--wp--preset--color--ink-soft);
	opacity: 0.75;
	text-decoration-thickness: 1.5px;
}

.wp-block-woocommerce-product-price ins,
.ne-pcard-price ins,
.ne-prod-price ins,
.ne-product-buy ins,
.woocommerce div.product p.price ins,
.woocommerce div.product span.price ins,
ins .woocommerce-Price-amount {
	text-decoration: none;
}

.ne-off {
	display: inline-block;
	margin-left: 10px;
	padding: 3px 9px;
	border-radius: var(--ne-radius-pill);
	background: var(--wp--preset--color--accent);
	color: #fff;
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.68rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	line-height: 1.4;
	white-space: nowrap;
	vertical-align: middle;
}

/* On the product page the price is large, so the badge drops onto its own line beneath
   it rather than fighting for room on the baseline. */
.wp-block-woocommerce-product-price .ne-off {
	display: block;
	width: fit-content;
	margin: 10px 0 0;
	font-size: 0.72rem;
	padding: 4px 11px;
}

.ne-pcard-price .ne-off,
.ne-prod-price .ne-off {
	margin-left: 6px;
	font-size: 0.62rem;
	padding: 2px 7px;
}

/* -------------------------------------------------------------------------
   Contact page. The message form sits in a card beside the preamble, the
   photograph and the direct contact details. Contact Form 7 emits bare
   <label> and <input> pairs, so the field styling lives here rather than in
   the form template, which carries only the field names the mail template
   depends on. Added 0.12.7, after launch: the old page was built from Woodmart
   Elementor widgets that do not exist under this theme.
   ------------------------------------------------------------------------- */
.ne-contact-card {
	padding: var(--wp--preset--spacing--50);
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--ne-line);
	border-radius: var(--ne-radius-lg);
}

.ne-contact-card > :first-child {
	margin-top: 0;
}

.ne-contact-form p {
	margin: 0 0 var(--wp--preset--spacing--30);
}

.ne-contact-form .ne-form-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: var(--wp--preset--spacing--30);
}

.ne-contact-form label {
	display: block;
	margin-bottom: 6px;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	line-height: 1.3;
}

.ne-contact-form input:not([type="checkbox"]):not([type="submit"]),
.ne-contact-form textarea {
	width: 100%;
	padding: 10px 14px;
	border: 1px solid var(--ne-line);
	background: #fff;
	font: inherit;
}

.ne-contact-form textarea {
	min-height: 160px;
	resize: vertical;
}

.ne-contact-form .mc4wp-checkbox label {
	display: flex;
	align-items: center;
	gap: 8px;
	font: inherit;
	font-weight: 400;
}

.ne-contact-form input[type="submit"] {
	cursor: pointer;
}

.ne-contact-form .wpcf7-not-valid-tip {
	font-size: var(--wp--preset--font-size--xs);
}

@media (max-width: 600px) {
	.ne-contact-form .ne-form-grid {
		grid-template-columns: 1fr;
	}
}

/* -------------------------------------------------------------------------
   Checkout. The classic [woocommerce_checkout] form, calmed down: the coupon
   notice on the palette instead of WooCommerce's blue, tighter field rhythm,
   a quieter "ship to a different address" toggle, and the order review and
   payment box in cards. The store's shipping destination is "billing" so the
   second address form stays closed unless the customer opens it. 0.12.8.
   ------------------------------------------------------------------------- */
.woocommerce-checkout .woocommerce-info,
.woocommerce-checkout .woocommerce-message,
.woocommerce-checkout .woocommerce-error {
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--ne-line);
	border-top: 1px solid var(--ne-line);
	border-radius: var(--ne-radius);
	color: inherit;
}

.woocommerce-checkout .woocommerce-info::before {
	color: var(--wp--preset--color--brand);
}

.woocommerce-checkout .form-row {
	margin-bottom: 14px;
}

.woocommerce-checkout .form-row label {
	margin-bottom: 4px;
	font-size: var(--wp--preset--font-size--sm);
}

.woocommerce-checkout .form-row .input-text,
.woocommerce-checkout .form-row select,
.woocommerce-checkout .select2-container--default .select2-selection--single {
	padding: 10px 14px;
	border: 1px solid var(--ne-line);
	background: #fff;
	min-height: 0;
}

.woocommerce-checkout h3#ship-to-different-address {
	font-size: var(--wp--preset--font-size--md);
	font-weight: 500;
}

.woocommerce-checkout h3#ship-to-different-address label {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	cursor: pointer;
}

.woocommerce-checkout #order_review_heading {
	margin-top: var(--wp--preset--spacing--50);
}

.woocommerce-checkout #order_review {
	padding: var(--wp--preset--spacing--40);
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--ne-line);
	border-radius: var(--ne-radius-lg);
}

.woocommerce-checkout #order_review table.shop_table {
	border: 0;
	margin-bottom: var(--wp--preset--spacing--40);
}

.woocommerce-checkout #order_review table.shop_table th,
.woocommerce-checkout #order_review table.shop_table td {
	border-color: var(--ne-line);
}

.woocommerce-checkout #payment {
	background: transparent;
	border-radius: var(--ne-radius);
}

.woocommerce-checkout #payment div.payment_box {
	background: #fff;
	border: 1px solid var(--ne-line);
	border-radius: var(--ne-radius-sm);
}

.woocommerce-checkout #payment div.payment_box::before {
	border-bottom-color: var(--ne-line);
}

.woocommerce-checkout #place_order {
	width: 100%;
}

/* Checkout layout, 0.12.9. Customer details as one card in a two-column field
   grid, the ship-elsewhere toggle and its fields beneath in the same card, the
   order review card below. Select2 makes the country and province dropdowns
   twice the height of a text input, which was most of the visual bulk. */
.woocommerce-checkout #customer_details.col2-set {
	display: block;
	padding: var(--wp--preset--spacing--40);
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--ne-line);
	border-radius: var(--ne-radius-lg);
}

.woocommerce-checkout #customer_details .col-1,
.woocommerce-checkout #customer_details .col-2 {
	float: none;
	width: 100%;
	max-width: none;
}

.woocommerce-checkout #customer_details .col-2 {
	margin-top: var(--wp--preset--spacing--40);
	padding-top: var(--wp--preset--spacing--40);
	border-top: 1px solid var(--ne-line);
}

.woocommerce-checkout .woocommerce-billing-fields > h3 {
	margin-top: 0;
}

.woocommerce-checkout .woocommerce-billing-fields__field-wrapper,
.woocommerce-checkout .woocommerce-shipping-fields__field-wrapper,
.woocommerce-checkout .woocommerce-additional-fields__field-wrapper {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: 20px;
}

.woocommerce-checkout .woocommerce-billing-fields__field-wrapper .form-row,
.woocommerce-checkout .woocommerce-shipping-fields__field-wrapper .form-row,
.woocommerce-checkout .woocommerce-additional-fields__field-wrapper .form-row {
	float: none;
	width: 100%;
	margin: 0 0 14px;
}

.woocommerce-checkout #billing_company_field,
.woocommerce-checkout #shipping_company_field,
.woocommerce-checkout .form-row.notes {
	grid-column: 1 / -1;
}

.woocommerce-checkout .form-row.notes textarea {
	min-height: 96px;
}

.woocommerce-checkout .select2-container--default .select2-selection--single {
	height: auto;
	padding: 10px 14px;
	line-height: 1.4;
}

.woocommerce-checkout .select2-container--default .select2-selection--single .select2-selection__rendered {
	padding: 0;
	line-height: inherit;
	color: inherit;
}

.woocommerce-checkout .select2-container--default .select2-selection--single .select2-selection__arrow {
	top: 0;
	height: 100%;
	right: 8px;
}

@media (max-width: 600px) {
	.woocommerce-checkout .woocommerce-billing-fields__field-wrapper,
	.woocommerce-checkout .woocommerce-shipping-fields__field-wrapper,
	.woocommerce-checkout .woocommerce-additional-fields__field-wrapper {
		grid-template-columns: 1fr;
	}
}

/* 0.12.10. Measured on the live checkout: WooCommerce's block-theme stylesheet
   pads the Select2 inner span like an input (about 14px 18px), so padding the
   outer box as well made the country and province boxes 69px against 44px for
   a text field. The padding now lives on the span alone and the box collapses
   to it. The two street address fields sit side by side, with the second one's
   label shown so the inputs line up. */
.woocommerce-checkout .select2-container--default .select2-selection--single {
	padding: 0;
	height: auto;
	min-height: 0;
	line-height: normal;
}

.woocommerce-checkout .select2-container--default .select2-selection--single .select2-selection__rendered {
	padding: 14px 40px 14px 18px !important;
	line-height: normal !important;
}

.woocommerce-checkout .select2-container--default .select2-selection--single .select2-selection__arrow {
	top: 0;
	right: 12px;
	height: 100%;
}

.woocommerce-checkout #billing_address_2_field label.screen-reader-text,
.woocommerce-checkout #shipping_address_2_field label.screen-reader-text {
	position: static !important;
	width: auto !important;
	height: auto !important;
	margin: 0 0 0.7em !important;
	overflow: visible !important;
	clip: auto !important;
	clip-path: none !important;
}

.woocommerce-checkout #billing_address_2::placeholder,
.woocommerce-checkout #shipping_address_2::placeholder {
	color: transparent;
}

/* 0.12.11. WooCommerce's screen-reader-text rule carries !important, so the
   apartment label needs the same weight to show. Field order in the grid reads
   as an address: street and apartment, town and province, postcode and country,
   then phone and email. Country stays last because it is South Africa only. */
.woocommerce-checkout #billing_first_name_field, .woocommerce-checkout #shipping_first_name_field { order: 1; }
.woocommerce-checkout #billing_last_name_field, .woocommerce-checkout #shipping_last_name_field { order: 2; }
.woocommerce-checkout #billing_company_field, .woocommerce-checkout #shipping_company_field { order: 3; }
.woocommerce-checkout #billing_address_1_field, .woocommerce-checkout #shipping_address_1_field { order: 4; }
.woocommerce-checkout #billing_address_2_field, .woocommerce-checkout #shipping_address_2_field { order: 5; }
.woocommerce-checkout #billing_city_field, .woocommerce-checkout #shipping_city_field { order: 6; }
.woocommerce-checkout #billing_state_field, .woocommerce-checkout #shipping_state_field { order: 7; }
.woocommerce-checkout #billing_postcode_field, .woocommerce-checkout #shipping_postcode_field { order: 8; }
.woocommerce-checkout #billing_country_field, .woocommerce-checkout #shipping_country_field { order: 9; }
.woocommerce-checkout #billing_phone_field, .woocommerce-checkout #shipping_phone_field { order: 10; }
.woocommerce-checkout #billing_email_field { order: 11; }
