/**
 * Kimera Chems — site-wide UI layer.
 *
 * Two jobs:
 *
 * 1. Declare the design tokens every other Kimera stylesheet reads. Colours are
 *    the existing brand values, moved here so a change lands in one place
 *    instead of a dozen literals. Geometry, motion and elevation are new, and
 *    are what make the surfaces read as current rather than 2019.
 *
 * 2. Apply the small set of global refinements that are safe on top of a parent
 *    theme we do not control: focus rings, selection, link underlines, control
 *    geometry, and the notice components used at checkout.
 *
 * Deliberately conservative about colour on parent-theme surfaces. Anything
 * whose background this file cannot see gets geometry and motion changes only,
 * never a colour swap, so nothing can end up dark-on-dark.
 *
 * @package kimera-chems
 */

:root {
	/* Brand — purple. From theme.json, unchanged. */
	--kc-purple: #8958fe;
	--kc-purple-strong: #562bda;
	--kc-purple-soft: #cec0f6;
	--kc-purple-deep: #220773;
	--kc-purple-ink: #12033f;

	/*
	 * Brand — red. Retained for one job only: the alert notice's left stripe,
	 * where red means warning rather than brand. Everything decorative that used
	 * to be red is now purple, so the site reads as one palette.
	 *
	 * #c10000 lands at 3.1:1 on the near-black research surfaces, under the
	 * 4.5:1 AA minimum, which is why --kc-red-bright existed. Both tokens stay
	 * declared: the alert stripe uses --kc-red, and removing the others would
	 * break any block still referencing them from the editor.
	 */
	--kc-red: #c10000;
	--kc-red-bright: #ff4d4d;
	--kc-red-bright-hover: #ff7a7a;

	/*
	 * Purple is not in the 2024 brand kit — those 13 logo SVGs use only
	 * #000000, #ffffff and #c10000, and that kit governs the logo marks rather
	 * than the wider palette. It comes from the compound card artwork, where the
	 * molecular structures are drawn in it.
	 *
	 * It is now the accent everywhere: links, list markers, eyebrows, hero corner
	 * ticks, hover, focus and glow. Measured, that also improves legibility
	 * rather than costing it — #8958fe is 6.91:1 on --kc-ink-900 against
	 * #ff4d4d at 6.15:1, and 6.41:1 against 5.71:1 on the card surface.
	 *
	 * Two shades do specific jobs. --kc-purple-soft (#cec0f6, 11.96:1) is the
	 * hover lift on dark. --kc-purple-strong (#562bda, 5.36:1 on white) is the
	 * one for light surfaces, because --kc-purple is 4.29:1 there and fails.
	 */

	/* Attention wash, from the existing checkout notices. */
	--kc-amber-pale: #fff4e5;

	/* Neutrals */
	--kc-black: #000000;
	--kc-white: #ffffff;
	--kc-ink-900: #07070a;
	--kc-ink-800: #0d0d12;
	--kc-ink-700: #121218;
	--kc-ink-600: #15141b;
	--kc-ink-500: #1c1b22;
	--kc-text: #f4f2f7;
	--kc-text-muted: #d8d5df;
	--kc-text-dim: #c9c5d1;
	--kc-border: #3c3c3c;
	--kc-border-light: #d9d9d9;

	/* Hairlines and washes, as alphas so they sit on any dark surface */
	--kc-line: rgba(255, 255, 255, 0.09);
	--kc-line-strong: rgba(255, 255, 255, 0.16);
	--kc-line-brand: rgba(137, 88, 254, 0.38);
	--kc-wash-brand: rgba(137, 88, 254, 0.08);

	/*
	 * Monospace, for anything that is data rather than prose: counts, formulae,
	 * CAS numbers, lot IDs. System stack, so it costs no font request. This is
	 * the strongest technical signal available without loading a fourth family.
	 */
	--kc-mono: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

	/* Geometry */
	--kc-radius-sm: 8px;
	--kc-radius: 12px;
	--kc-radius-lg: 18px;
	--kc-radius-pill: 999px;

	/* Spacing. Fluid at the top end so section rhythm tracks the viewport. */
	--kc-space-1: 4px;
	--kc-space-2: 8px;
	--kc-space-3: 12px;
	--kc-space-4: 16px;
	--kc-space-5: 24px;
	--kc-space-6: 32px;
	--kc-space-7: clamp(40px, 5vw, 56px);
	--kc-space-8: clamp(56px, 8vw, 96px);

	/* Elevation. Layered rather than one blur, so edges stay crisp. */
	--kc-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
	--kc-shadow: 0 4px 12px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.3);
	--kc-shadow-lg: 0 18px 40px rgba(0, 0, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.35);
	--kc-glow-brand: 0 0 0 1px var(--kc-line-brand), 0 12px 32px rgba(86, 43, 218, 0.18);

	/* Motion */
	--kc-ease: cubic-bezier(0.2, 0, 0.2, 1);
	--kc-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
	--kc-duration-fast: 140ms;
	--kc-duration: 220ms;
	--kc-duration-slow: 380ms;

	/* Focus */
	--kc-focus: var(--kc-purple);
	--kc-focus-width: 2px;
	--kc-focus-offset: 3px;
}

/*
 * One switch for every animation in the Kimera stylesheets. Components read
 * these two custom properties instead of hardcoding durations, so honouring the
 * reduced-motion preference is a single override rather than a rule per
 * component.
 */
@media (prefers-reduced-motion: reduce) {
	:root {
		--kc-duration-fast: 1ms;
		--kc-duration: 1ms;
		--kc-duration-slow: 1ms;
	}
}

/* Global refinements
   ========================================================================== */

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

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

/* Anything linked to by fragment clears the header instead of hiding under it. */
:target {
	scroll-margin-top: 6rem;
}

::selection {
	background: var(--kc-purple-strong);
	color: var(--kc-white);
}

/*
 * The parent theme leaves focus to the browser default, which is a thin ring
 * that all but vanishes on black. :focus-visible keeps it off mouse clicks.
 */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
	border-radius: var(--kc-radius-sm);
	outline: var(--kc-focus-width) solid var(--kc-focus);
	outline-offset: var(--kc-focus-offset);
}

/*
 * theme.json underlines every link. Pulling the line off the baseline and
 * thinning it is the difference between a link and a default-styled link.
 */
a {
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
}

/* Site-wide link colour
   ==========================================================================
   Something upstream emits `a:where(:not(.wp-element-button)) { color: #c10000 }`
   into the global-styles block, and it is what makes product grid titles,
   breadcrumbs and nav items red. Traced by matching every readable stylesheet
   rule against a product title link: two rules match, both in
   #global-styles-inline-css, and the red one wins on order.

   It is not ours. Zero occurrences in the styles.css field of post 104076,
   in the child theme.json, in oigny-lite's theme.json, or in any of the 45
   external stylesheets. Most likely a style variation or a plugin filter.

   Overriding is safe rather than a fight: `:where()` contributes no
   specificity, so that rule is (0,0,1), and this stylesheet is appended after
   it inside the same block. The checkout-scoped copy at (0,1,1) needs the
   second selector to clear it.

   Light surfaces are handled after this by higher-specificity rules —
   `.kc-notice a` takes --kc-purple-strong, because --kc-purple is 2.91:1 on
   white and fails. */

a:where(:not(.wp-element-button)),
body.woocommerce-checkout a:where(:not(.wp-element-button)) {
	color: var(--kc-purple);
}

/* Buttons and controls
   ==========================================================================
   Geometry and motion only. Backgrounds and text colour stay with whatever
   the parent theme and the block editor set, because this file cannot see
   what surface any given button sits on. */

.wp-element-button,
.wp-block-button__link,
.woocommerce a.button,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce #respond input#submit {
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration-fast) var(--kc-ease);
}

.wp-element-button:hover,
.wp-block-button__link:hover,
.woocommerce a.button:hover,
.woocommerce button.button:hover,
.woocommerce input.button:hover,
.woocommerce #respond input#submit:hover {
	box-shadow: var(--kc-shadow);
	transform: translateY(-1px);
}

.wp-element-button:active,
.wp-block-button__link:active,
.woocommerce a.button:active,
.woocommerce button.button:active,
.woocommerce input.button:active {
	box-shadow: var(--kc-shadow-sm);
	transform: translateY(0);
}

/*
 * Tokens collapse the tween to 1ms under reduced motion, which leaves the lift
 * as an untweened jump. Suppress the movement itself; the shadow still reads.
 */
@media (prefers-reduced-motion: reduce) {
	.wp-element-button:hover,
	.wp-block-button__link:hover,
	.woocommerce a.button:hover,
	.woocommerce button.button:hover,
	.woocommerce input.button:hover,
	.woocommerce #respond input#submit:hover {
		transform: none;
	}
}

/* Form controls: rounded, and they respond when focused. */
.woocommerce form .form-row input.input-text,
.woocommerce form .form-row textarea,
.woocommerce form .form-row select,
.woocommerce-page form .form-row input.input-text,
.woocommerce-page form .form-row textarea,
.woocommerce-page form .form-row select,
.woocommerce .select2-container .select2-selection--single {
	border-radius: var(--kc-radius-sm);
	transition:
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease);
}

.woocommerce form .form-row input.input-text:focus,
.woocommerce form .form-row textarea:focus,
.woocommerce form .form-row select:focus,
.woocommerce-page form .form-row input.input-text:focus,
.woocommerce-page form .form-row textarea:focus,
.woocommerce-page form .form-row select:focus {
	border-color: var(--kc-purple);
	box-shadow: 0 0 0 3px var(--kc-wash-brand);
	outline: none;
}

/* WooCommerce's own notices: geometry only, colours left alone. */
.woocommerce-message,
.woocommerce-info,
.woocommerce-error {
	border-radius: var(--kc-radius);
}

/* Kimera notices
   ==========================================================================
   Used by the checkout and order-review messages in functions.php. Colours are
   the ones those notices already used as inline styles; what is new is the
   geometry, the accent rule, and consistent spacing between them. */

.kc-notice {
	border-radius: var(--kc-radius);
	color: var(--kc-black);
	font-size: 0.95rem;
	line-height: 1.6;
	margin: 0 0 var(--kc-space-5);
	padding: var(--kc-space-4) var(--kc-space-5);
	position: relative;
}

.kc-notice > :first-child {
	margin-top: 0;
}

.kc-notice > :last-child {
	margin-bottom: 0;
}

.kc-notice a {
	color: var(--kc-purple-strong);
	font-weight: 600;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
}

.kc-notice a:hover,
.kc-notice a:focus {
	color: var(--kc-purple-strong);
}

/* Informational: shipping policy, how to pay. */
.kc-notice--info {
	background: var(--kc-white);
	box-shadow: inset 3px 0 0 var(--kc-purple-strong), 0 0 0 1px rgba(0, 0, 0, 0.08);
}

/* Attention: shipping restrictions, fulfilment delays. */
.kc-notice--alert {
	background: var(--kc-amber-pale);
	box-shadow: inset 3px 0 0 var(--kc-red);
}

.kc-notice--alert strong {
	font-weight: 700;
	letter-spacing: 0.01em;
}

/* Long-form content pages
   ==========================================================================
   One rule set, two hooks. These were two separate blocks that had drifted
   apart: same intent, different values for the same properties.

   .kc-prose is ours, applied deliberately per page, and it is the one to
   prefer. A page opts in, and the apply page uses it to style its long-form
   sections while leaving the centred sign-in panel and buttons alone.

   .entry-content is the class WordPress core puts on the post-content block.
   It catches the pages nobody has tagged: how-to-pay, wholesale, about-us,
   contact-us. Neither hook can simply be dropped: removing .entry-content
   strips those four, removing .kc-prose strips the apply page.

   Listing both on every rule is what stops them diverging again. Once every
   page carries kc-prose, delete the .entry-content half of each selector.

   The measure sits on the text, not the container. Constraining the wrapper
   would squeeze the Fluent Forms embedded in shipping-claim and the account
   application, which are prose pages in every other respect. */

:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) {
	font-size: 1.02rem;
	line-height: 1.78;
}

:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) :is(p, li) {
	color: var(--kc-text-muted);
	max-width: 68ch;
}

:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) p { margin: 0 0 1.25em; }

/* The opening paragraph carries the document. Two shapes to match: raw-HTML
   pages wrap their copy in a div, block pages do not. */
:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) > p:first-child,
:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) > div > p:first-of-type {
	color: var(--kc-text);
	font-size: 1.14rem;
	line-height: 1.7;
}

/* Space above a heading is what gives a 17-section policy visible structure.
   Below it, close up so the heading binds to its own text. scroll-margin keeps
   a linked clause clear of the sticky header. */
:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) :is(h2, h3) {
	color: var(--kc-white);
	font-family: var(--wp--preset--font-family--michroma, inherit);
	font-weight: 500;
	letter-spacing: -0.015em;
	line-height: 1.28;
	/*
	 * !important, and measured before reaching for it. The Customizer layer
	 * (post 37298, served inside global-styles-inline-css) carries
	 * `.entry-content h1..h4 { margin: 20px 0 !important }` from the red era,
	 * so every policy page was rendering a flat 20px above and below each
	 * heading and the section rhythm this rule exists to create never landed —
	 * measured at 20px on terms-conditions, refund-returns and
	 * do-not-sell-or-share on 2026-08-16.
	 *
	 * An !important can only be beaten by another !important, so specificity
	 * was not an option. Deleting the Customizer declaration would have been
	 * the tidier fix, except it also governs blog posts, which are
	 * `.entry-content` but not `body.page` and would drop to the theme's 0.5rem.
	 * Escalating here keeps the blast radius to prose pages.
	 */
	margin: 2.4em 0 0.7em !important;
	scroll-margin-top: 6rem;
}

:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) h2 { font-size: clamp(1.15rem, 2vw, 1.6rem); }
:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) h3 { font-size: clamp(1.05rem, 1.6vw, 1.3rem); }

:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) h4 {
	color: var(--kc-white);
	font-size: 1.02rem;
	font-weight: 600;
	margin-top: 1.9em;
}

:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) :is(ul, ol) { margin: 0 0 1.25em; padding-left: 1.35em; }
:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) li { line-height: 1.7; }
:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) li + li { margin-top: 0.5em; }
:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) li::marker { color: var(--kc-purple); }
:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) strong { color: var(--kc-white); }

/* These pages already set color:#ff4d4d inline on every link, the same value
   as --kc-red-bright. This covers links added later without it. */
:is(.kc-prose, body.page:not(.woocommerce-page) .entry-content) a {
	color: var(--kc-purple);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
}

/* Archive, search and 404 heroes
   ==========================================================================
   These three templates render their title in a core Cover block whose dim
   layer carries has-background-dim-0 — zero opacity. The image underneath is
   one of the parent theme's stock heroes, a blue and green aurora, so they read
   as stock while the research pages read as Kimera.

   All three are covered because none of them is `archive`: search results carry
   body.search, the 404 carries body.error404, and only category, tag, date and
   author archives carry body.archive. Scoping to archive alone missed two.

   That seam is visible: the research library's "Browse by Mechanism" cards link
   straight into these archives, so a styled page hands off to an unstyled one.
   This gives the dim layer the same wash the research hero uses, plus the red
   corner ticks and the brand hairline, so both ends of that link match.

   Scoped away from WooCommerce: a category archive carries `archive` without
   `woocommerce`, while the shop carries both, so :not() keeps the catalog out. */

body:is(.archive, .search, .error404):not(.woocommerce) .wp-block-cover > .wp-block-cover__background {
	background:
		radial-gradient(115% 85% at 12% 0%, rgba(86, 43, 218, 0.26), transparent 62%),
		linear-gradient(135deg, rgba(7, 7, 10, 0.72), rgba(7, 7, 10, 0.96));
	/* Beats .has-background-dim-0 at (0,2,0); this selector is (0,4,1). */
	opacity: 1;
}

/* The cover already has position:relative and overflow:clip, so these are
   contained without any extra scaffolding. */
body:is(.archive, .search, .error404):not(.woocommerce) .wp-block-cover::before {
	background: linear-gradient(90deg,
		var(--kc-purple) 0 min(150px, 14%),
		transparent min(150px, 14%) calc(100% - min(150px, 14%)),
		var(--kc-purple) calc(100% - min(150px, 14%)) 100%);
	content: "";
	height: 2px;
	left: 0;
	position: absolute;
	right: 0;
	top: 0;
	z-index: 2;
}

body:is(.archive, .search, .error404):not(.woocommerce) .wp-block-cover::after {
	background: linear-gradient(90deg, transparent, var(--kc-line-brand), transparent);
	bottom: 0;
	content: "";
	height: 1px;
	left: 0;
	position: absolute;
	right: 0;
	z-index: 2;
}

/* My Account: register text and column order on small screens
   ==========================================================================
   Moved here from an inline <style> in functions.php. Same rules, now cached
   with the rest of the CSS instead of re-sent inside every page of HTML. */

@media (max-width: 768px) {
	.register-text {
		display: none !important;
	}

	.register-compliance-text {
		display: block !important;
		margin-bottom: var(--kc-space-5);
	}

	/* Login above registration, both full width. */
	.woocommerce-account .col2-set {
		display: flex;
		flex-direction: column;
	}

	.woocommerce-account .u-column1.col-1 {
		margin-bottom: 30px;
		order: 1;
		width: 100% !important;
	}

	.woocommerce-account .u-column2.col-2 {
		order: 2;
		width: 100% !important;
	}
}

@media (min-width: 769px) {
	.register-compliance-text {
		display: none !important;
	}
}

/* Product page tables — stop two tables forcing a horizontal scrollbar
   ==========================================================================
   Two tables on single-product overflow their column. Neither has ever had a
   rule in this stylesheet, so both of these are new.

   1. Woo's `table.variations`. Core sizes the <select> from its longest
      <option>: woocommerce-blocktheme.css sets min-width:70% at (0,4,5) and
      woocommerce.css sets min-width:75% at (0,4,3). min-width beats the
      max-width:100% that core also sets, so the select cannot shrink, and with
      table-layout:auto and no cap on the table that floor propagates upward.
      Measured on /product/slu-pp-332/ (90-char option labels): the table
      rendered 746px inside a 265px column at a 345px viewport, and the page
      overflowed at every width up to 1440 — including 960, which is what a
      1920 monitor reports at 200% display scaling. This is not a phone-only
      bug.

   2. `.product-table`, emitted by [product_specs_table]. It now loops the ACF
      repeater and renders 2-12 rows rather than a fixed 5, and Compound Class
      is newly visible on 182 products with values like
      "Spiro[indoline-3,4'-piperidine] scaffold". Measured 453px inside a 285px
      column at the same viewport.

   `min-width: 0` on the select is the load-bearing declaration; without it
   nothing else here changes the outcome. `table-layout: fixed` stops the
   remaining columns sizing from their content.

   Specificity: woocommerce.css loads AFTER the global-styles block, so beating
   it needs more than (0,4,3), and blocktheme loads before, so (0,4,5) would tie
   and win on order. These land at (0,4,6).

   `body.woocommerce`, not `body .woocommerce`: WooCommerce puts that class on
   <body>, and the inner .woocommerce group div is the same element as
   div.product. With a descendant combinator the chain cannot match and the
   whole block silently does nothing — which is exactly what the first draft of
   this did. */

body.woocommerce div.product form.cart table.variations {
	max-width: 100%;
	table-layout: fixed;
	width: 100%;
}

body.woocommerce div.product form.cart table.variations td select {
	max-width: 100%;
	min-width: 0;
	width: 100%;
}

body .product-table {
	max-width: 100%;
	table-layout: fixed;
	width: 100%;
}

/* Chemical names have no spaces to break on. */
body .product-table td {
	overflow-wrap: break-word;
	word-break: break-word;
}

body .product-table td.static-label {
	width: 42%;
}

/* Header — stop the leftover reds fighting the purple wash
   ==========================================================================
   Two things in the header still carried red after the accent swap, and both
   sit directly on the purple gradient. Measured against the wash, sampled at
   three points down the gradient (#6a15a2, #440a5f, #20022d):

     active nav item  #c10000   1.46 / 2.25 / 2.95   fails at every stop
     cart badge       #ff3b3b   3.53:1 with white text

   That is the clash. Red at 1.46:1 on purple reads as a mistake rather than an
   accent, and it is the loudest thing in the header.

   The active item does not become white, because white is what the inactive
   items already are and the active state would disappear. --kc-purple-soft
   measures 5.57 / 8.58 / 11.27, passes AA at every stop, and stays clearly
   distinct from the white siblings.

   The badge inverts instead: --kc-purple-soft ground with --kc-purple-ink text
   is 10.42:1, against 3.53:1 for white-on-red, and it still pops off the wash
   because it is lighter than everything around it.

   The submenu is deliberately untouched. Its items compute black, which looks
   wrong in a colour audit until you measure the dropdown itself: it has a white
   background, so black is correct there.

   Neither is fixed here, deliberately. Both are set by ID-scoped selectors the
   page builders generate:

     nav active  #guten-yHBZb5 … > li.current-menu-item … → theme-2
     badge       #selectors_css_uc_woo_mini_cart_ax_elementor17570 … → #ff3b3b

   Class selectors lose to those outright. Matching the ids was tried and lost
   too — the header renders more than one nav instance, so the id is not always
   on the ancestor chain of the link you can see. Escalating further means
   !important or a longer id chain, which trades a visible red for an invisible
   dependency on markup that changes whenever the block is rebuilt.

   These belong in the editor, where the block's own colour setting is the thing
   that is wrong, not in a stylesheet fighting it. That is item 05, which is the
   header and footer work and already needs staging. The measurements above are
   the brief for it. */

/* Footer — carry the accent through to the bottom of the page
   ==========================================================================
   The footer template part is seven Gutenverse sections, four of which paint
   the same black-to-red-to-black hairline:

     linear-gradient(125deg, rgba(0,0,0,1) 0%, rgba(193,0,0,1) 14.2%, rgba(0,0,0,1) 95.6%)

   That is the last red left in the page chrome once the header, hero and links
   are purple, and it reads as a leftover rather than a deliberate contrast.
   Same gradient geometry, brand purple in place of the red stop, so the shape
   of the design is unchanged and only the hue moves.

   #562bda is --kc-purple-strong, the same value the hero wash is built from, so
   header, hero and footer are all one hue.

   All four ids verified present on every page type measured, including cart and
   my-account, so this is one rule for the whole site.

   Gutenverse's own rule is `.guten-XXXX:not(.background-animated)` at (0,2,0)
   and loads after global styles, so the `body` prefix at (0,2,1) is what wins.

   Generated ids again, same fragility as the header and hero: recreate a footer
   section in the editor and its id changes and this stops matching silently.
   Item 05 should move all three onto real classes together. */

body .guten-efDoZ3:not(.background-animated),
body .guten-fP18u6:not(.background-animated),
body .guten-V4hsIl:not(.background-animated),
body .guten-w5g2oR:not(.background-animated) {
	background: linear-gradient(
		125deg,
		rgba(0, 0, 0, 1) 0%,
		rgba(86, 43, 218, 1) 14.2%,
		rgba(0, 0, 0, 1) 95.6%
	);
}

/* Shop and product hero — same purple wash as the archives
   ==========================================================================
   `.guten-2hrek2` is the title section shared by shop-title and product-title,
   so this one rule covers the catalog, every product category archive, and
   every single product page. Verified present on all three.

   What was actually there, measured rather than taken from the notes: the
   section carries `background-color: #000` plus a `bg-hero-home.webp`
   background image. There is no red in any stylesheet and there is no
   `.guten-background-overlay` element in the DOM — zero matches on a
   class-attribute search. The earlier note describing the red as painted by
   `.guten-2hrek2 > .guten-background-overlay` was a stylesheet-text false
   positive, the same inlining trap documented in HANDOFF.md. The red lives in
   the image.

   So this washes over the image rather than replacing it, using the empty
   `::before` Gutenverse already renders at `position:absolute; inset:0` across
   the full section. Same two gradients as the archive heroes, so a product
   category and an article category now read the same.

   Checked that the overlay does not cover the title: `elementFromPoint` at the
   heading's centre still returns the `h1` on all three page types, and the
   heading stays `#fff`.

   `body` prefix because Gutenverse's own CSS loads after global styles.

   Same fragility as the header rule: `guten-2hrek2` is a generated id, and if
   either title template part is recreated in the editor it changes and this
   silently stops matching. Item 05 should move both onto real classes. */

/* `guten-eqFkmf` is the SECOND title section, added here 2026-08-16. It is the
   page-title hero for ordinary pages and it carries the same red photograph
   (`bg-hero-home.webp`) that 2hrek2 did, so /my-account/, /cart/, /apply/,
   /coas/ and /how-to-pay/ all still showed red long after the shop and product
   heroes were washed. Reported from a screenshot of /my-account/, then found by
   walking the DOM for painted reds rather than by reading any stylesheet.

   Measured the same shape as 2hrek2 before reusing the rule: `position:
   relative`, an empty `::before` at `position: absolute; inset: 0`, and no
   `.guten-background-overlay` element. */
body .guten-2hrek2::before,
body .guten-eqFkmf::before {
	background-image:
		radial-gradient(115% 85% at 12% 0%, rgba(86, 43, 218, 0.26), transparent 62%),
		linear-gradient(135deg, rgba(7, 7, 10, 0.72), rgba(7, 7, 10, 0.96));
}

/* Site header — carry the brand purple on every page
   ==========================================================================
   The header section is transparent by design: Gutenverse emits
   `.guten-u1u02U:not(.background-animated) { background-color: rgba(0,0,0,0) }`
   for it. That is why purple only ever showed on pages whose hero happened to
   sit behind the header. This puts the wash on the header itself, so the
   homepage and catalog read the same as the research pages.

   background-image, not background-color: Gutenverse's rule owns the colour and
   loads from its own stylesheet. Painting a different property sidesteps the
   conflict entirely, so this holds regardless of which sheet loads last.

   Targets `guten-u1u02U`, the header block's generated id — verified identical
   across catalog and research-library. If that block is ever recreated in the
   editor the id changes, this rule stops matching, and the header silently
   returns to transparent with no obvious cause. Item 05 moves it onto a real
   class; until then this selector is the only thing holding the purple.

   Backported from production. This rule was written straight into the
   global-styles record (post 104076, field styles.css) and existed nowhere in
   the repo, so clearing that field after a theme-file deploy — which HANDOFF.md
   instructs — would have deleted the purple header site-wide with no source to
   restore it from. It is in the build now, so the bundle and the database
   agree. */

.guten-u1u02U:not(.background-animated) {
	/* The research-library BAND is the header treatment, owner's pick from
	   three rendered options on 2026-08-16: radial purple over translucent
	   ink, brand hairline below (set in the section's border attribute). A
	   flat-ink version lived here for an hour first and read as the same
	   surface as the now-opaque hero. Still background-image rather than
	   background-color, for the cascade sidestep documented above; the linear
	   layer is two identical stops, a flat paint delivered through the
	   property Gutenverse does not own.

	   The DB copy (post 104076) still carries the old purple gradient at equal
	   specificity; this file is later in document order and wins. Verified
	   rendered, not assumed — if the header ever shows purple again, check
	   which copy the page is serving before touching either. */
	background-image:
		radial-gradient(140% 200% at 8% 0%, rgba(86, 43, 218, 0.42), transparent 58%),
		linear-gradient(180deg, rgba(13, 13, 18, 0.92), rgba(13, 13, 18, 0.92));
	border-bottom: 1px solid var(--kc-line);
}

/*
 * DESKTOP ONLY, and this is load-bearing rather than a preference.
 *
 * `backdrop-filter` makes an element a CONTAINING BLOCK for its
 * `position: fixed` descendants. The mobile drawer is one: Gutenverse gives
 * `.gutenverse-menu-wrapper` `position: fixed; height: 100%`, expecting 100%
 * of the VIEWPORT. With the blur on the header, that 100% resolved against the
 * header instead, so the drawer opened 89px tall — its identity panel and
 * nothing else — and every menu link rendered outside it and was clipped.
 * Reported as "the hamburger side bar still isn't rendering the links".
 *
 * Proven rather than argued: with the filter the wrapper computes 89px, with
 * it removed 812px, on the same 812px viewport.
 *
 * 1025px is the floor because Gutenverse's own drawer breakpoint is
 * `break-point-tablet` at max-width 1024. Above it there is no fixed drawer to
 * trap, so the frost is free.
 *
 * The lesson generalises: any transform, filter, perspective or backdrop-filter
 * added to a wrapper silently re-parents fixed positioning underneath it.
 * Check for fixed descendants before adding one.
 */
@media (min-width: 1025px) {
	@supports (backdrop-filter: blur(1px)) {
		.guten-u1u02U:not(.background-animated) {
			backdrop-filter: blur(14px);
			background-image:
				radial-gradient(140% 200% at 8% 0%, rgba(86, 43, 218, 0.42), transparent 58%),
				linear-gradient(180deg, rgba(13, 13, 18, 0.82), rgba(13, 13, 18, 0.82));
		}
	}
}

/* Pill nav: the research library's pill vocabulary on the header menu.
   Additive properties only — Gutenverse's ID-scoped rules own the text
   colours and keep them; padding, radius and the hover wash are properties
   it leaves unset, so a class selector is enough and there is no cascade
   fight to lose. */
body .guten-u1u02U .gutenverse-menu > li > a {
	border: 1px solid transparent;
	border-radius: var(--kc-radius-pill);
	/* !important against Gutenverse's own menu rule, which loads later and was
	   measured winning: computed padding stayed 0px 20px without it. The
	   hairline had the same fight and moved into the section's border
	   attribute instead, where there is no fight at all. */
	padding: 0.45em 1.05em !important;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease);
}

/* The full library pill on hover: wash, brand hairline, pill radius. The
   transparent border above reserves the space so nothing shifts when it
   appears. */
body .guten-u1u02U .gutenverse-menu > li > a:hover {
	background-color: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
}

/* The Catalog dropdown — a research card holding all fifteen categories
   ==========================================================================
   It was a WHITE panel with black text on a near-black site: the last piece
   of the old header design. Two mechanisms, because Gutenverse splits them:

   - the PANEL is painted `background: var(--guten-bg-color)` at (0,5,1), so
     redefining that variable on the nav is enough and no override is needed.
     Same approach as `--guten-border-color` on the FAQ accordion.
   - the LINK COLOUR is `#guten-yHBZb5 … .sub-menu …` — an ID selector at
     (1,3,2) that no class rule can beat, so it is a block attribute
     (`submenuTextNormalColor` and friends), set alongside this.

   The menu itself grew from 6 categories to all 15 on 2026-08-16, which took
   the panel to 701px tall in one column. Two columns keep it on screen; the
   `max-height` with `overflow-y: auto` is the belt for short viewports, since
   a dropdown that runs off the bottom of the window cannot be scrolled to.
   ========================================================================== */

body .guten-u1u02U .guten-nav-menu,
body .guten-u1u02U .gutenverse-menu {
	--guten-bg-color: var(--kc-ink-800);
}

/* Single column, deliberately. A two-column pass was tried and reverted: the
   panel's WIDTH and RADIUS come from `#guten-yHBZb5…` at (1,5,1), which no
   class rule beats, so the columns rendered inside a 180px box and the longer
   category names overflowed it. The width is a block attribute instead
   (`submenuPanelWidth`, 180 -> 270px, sized against the 28-character
   "Phosphodiesterase Inhibitors"), and the list stays one column.

   `max-height` needs `!important`: Gutenverse sets `max-height: none` at
   (0,5,1) and this rule is (0,3,1). Without it a fifteen-item panel runs off
   the bottom of a short viewport with no way to scroll to the rest. */
body .guten-u1u02U .gutenverse-menu .sub-menu {
	background-color: var(--kc-ink-800);
	border: 1px solid var(--kc-line);
	box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
	max-height: min(72vh, 620px) !important;
	overflow-y: auto;
	padding: 8px;
}

body .guten-u1u02U .gutenverse-menu .sub-menu li > a {
	border-radius: var(--kc-radius-sm);
	padding: 0.55em 0.9em !important;
	transition:
		background-color var(--kc-duration-fast) var(--kc-ease),
		color var(--kc-duration-fast) var(--kc-ease);
}

body .guten-u1u02U .gutenverse-menu .sub-menu li > a:hover {
	background-color: var(--kc-wash-brand);
}

@media (max-width: 1024px) {
	/* In the drawer the submenu is a stacked list, not a floating panel, and
	   the drawer scrolls on its own. */
	body .guten-u1u02U .gutenverse-menu .sub-menu {
		border: 0;
		box-shadow: none;
		max-height: none !important;
		width: auto;
	}
}


/* Homepage hero - carry the purple wash onto the front page
   ==========================================================================
   The homepage hero was the last surface still reading red, which is what made
   the purple header above it look like two designs meeting.

   The red is not CSS. Both hero sections paint
   `background-image: url('/wp-content/themes/kimera-chems/assets/css/.../2025/08/hero-home.webp')`, a red photograph, so no
   colour rule anywhere could have changed it. Measured, not inferred.

   Two sections rather than one: the front page splits on a Gutenverse
   login_status condition, `guten-vSySf9` for signed-in and `guten-TpxhI7` for
   signed-out, and both carry the same image. Styling only one would fix the
   page for half the audience.

   Same treatment as `.guten-2hrek2::before`, deliberately, so the homepage,
   catalog, product categories and product pages share one hero language.

   `::before` rather than the section's own `.guten-background-overlay`:
   Gutenverse pins that overlay at `opacity: 0.7` and holds it against an
   `!important`, which would weaken the wash. The section is `position:
   relative` and its content sits in a `position: relative` container that
   paints after the pseudo-element, so the wash lands between photo and text.
   ========================================================================== */
body .guten-vSySf9::before,
body .guten-TpxhI7::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	/* The ink layer is fully opaque since 2026-08-16: the photo behind carries
	   the old mark baked in, and at 0.72 it ghosted through under the new
	   watermark. The radial purple above is what survives of the hero's
	   texture — the same band vocabulary as the research library. */
	background-image:
		radial-gradient(115% 85% at 12% 0%, rgba(86, 43, 218, 0.26), transparent 62%),
		linear-gradient(135deg, rgba(7, 7, 10, 1), rgba(7, 7, 10, 1));
}

/* Hero watermark: the ram, above the wash rather than baked into the photo.
   The photo still carries the old head; the wash above dims it to nothing, and
   this puts the current mark back as a deliberate element. `::after` because
   `::before` is the wash: both are positioned with z-index auto, so document
   order paints photo, wash, watermark. Ghost opacity keeps the text on top
   readable where they overlap, and pointer-events none keeps it decorative.
   media 107104, uploaded 2026-08-16. */
body .guten-vSySf9::after,
body .guten-TpxhI7::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-image: url('/wp-content/uploads/2026/08/kimera-hero-watermark-white.png');
	/* Anchored to the bottom edge in PIXELS, not centred in percentages, and
	   this is why. A percentage size is a percentage of the hero, and the two
	   heroes are wildly different heights — the signed-out one measured 1005px
	   at 1280 and 1569px at 375 — so `auto 34%` drew a 342px mark on one and a
	   533px mark on the other. A percentage POSITION then places it in the
	   middle of the box, which is exactly where the centred headline, subtext
	   and buttons live, so it collided at every size. Both heroes were measured
	   instead: content ends at 75% of the hero and leaves 245-255px clear below
	   it at both widths, on desktop and mobile. 160px + 24px sits inside that
	   clear band with room to spare, and being absolute it is the same mark on
	   every page and viewport. */
	background-position: center bottom 24px;
	background-repeat: no-repeat;
	background-size: auto 160px;
	opacity: 1;
}

/* Narrow viewports get a smaller mark. The hero does NOT grow proportionally
   with the content it holds: measured at 375 it is 986px tall with content
   ending at 861, so the clear band below is 125px against desktop's 255px.
   88px + 16px fits inside that; 160px + 24px overlapped the Apply button by
   59px. (An earlier reading claimed 245px clear at 375 and was wrong — the
   viewport had been resized without reloading, so the page was still in the
   previous layout. Reload after any resize before believing a number.) */
@media (max-width: 1024px) {
	body .guten-vSySf9::after,
	body .guten-TpxhI7::after {
		background-position: center bottom 16px;
		background-size: auto 88px;
	}
}


/* Purple accent, Michroma, and motion
   ==========================================================================
   Replaces the red accent on every interactive and lettering surface, puts
   Michroma on headings and UI, and adds motion that uses transform/opacity
   only so nothing reflows.

   Token names matter here. `--kc-violet` and `--kc-violet-strong` do NOT exist
   as custom properties: those two are theme *palette* entries and resolve only
   as `--wp--preset--color--kc-violet`. A first pass used them and every
   declaration silently dropped, which is why the COA icon stayed white and its
   button lost its gradient. The real tokens are the `--kc-purple-*` family
   below, all confirmed resolving at runtime.

   `!important` appears only against inline styles or a later same-specificity
   rule. The manifesto band sets colour inline, the WooCommerce cart button sets
   its own background, and the variation select is repainted `#fff` further down
   the document.
   ========================================================================== */

/* 1. Lettering: red becomes purple ---------------------------------------- */

.kimera-manifesto .kimera-eyebrow,
.kimera-manifesto .kimera-statement span[style*="e11d2e"],
.kimera-manifesto .kimera-statement span[style*="E11D2E"],
.kimera-manifesto .kimera-statement span[style*="c10000"] {
	color: var(--kc-purple) !important;
}

.guten-advanced-heading .heading-focus,
.guten-icon .guten-icon-wrapper i,
.woocommerce .price,
.woocommerce div.product p.price,
.woocommerce div.product span.price {
	color: var(--kc-purple) !important;
}

/* 2. Michroma on headings and UI ------------------------------------------ */

.kimera-manifesto .kimera-eyebrow,
.kimera-manifesto .kimera-statement,
.guten-advanced-heading .heading-title,
.wp-block-gutenverse-heading,
.woocommerce div.product .product_title,
.woocommerce ul.products li.product .woocommerce-loop-product__title,
.wp-block-post-title,
.kc-coa__title,
.wp-element-button,
.wp-block-button__link,
button.single_add_to_cart_button,
.kc-coa__btn,
.woocommerce div.product form.cart .variations label,
.woocommerce div.product form.cart .variations select {
	font-family: var(--wp--preset--font-family--michroma, "Michroma", sans-serif) !important;
}

/* Michroma is wide and has no italic, so anything sized for a text face runs
   long. The manifesto is stepped down to hold the same visual block. */
.kimera-manifesto .kimera-statement {
	font-style: normal !important;
	font-weight: 400 !important;
	font-size: clamp(19px, 2.3vw, 28px) !important;
	line-height: 1.6 !important;
}

.kimera-manifesto .kimera-eyebrow {
	font-size: 12px !important;
	letter-spacing: 5px !important;
}

/* 3. Product copy in white ------------------------------------------------ */

.woocommerce div.product .woocommerce-product-details__short-description,
.woocommerce div.product .woocommerce-product-details__short-description p,
.woocommerce div.product #tab-description,
.woocommerce div.product #tab-description p,
.woocommerce div.product #tab-description li,
.woocommerce-Tabs-panel p,
.woocommerce-Tabs-panel li,
.product-table td,
.product-table th {
	color: #fff;
}

.woocommerce div.product .woocommerce-product-details__short-description strong,
.woocommerce-Tabs-panel strong {
	color: #fff;
}

/* 4. Buttons -------------------------------------------------------------- */

.woocommerce div.product form.cart button.single_add_to_cart_button,
.woocommerce div.product form.cart button[name="add-to-cart"],
.wc-block-components-product-button__button,
a.add_to_cart_button,
.kc-coa__btn {
	background: linear-gradient(135deg, var(--kc-purple-strong), var(--kc-purple-deep)) !important;
	border: 1px solid var(--kc-line-brand) !important;
	border-radius: var(--kc-radius-pill, 999px) !important;
	color: #fff !important;
	font-weight: 600;
	letter-spacing: 0.4px;
	box-shadow: none !important;
	transition: transform var(--kc-duration) var(--kc-ease), box-shadow var(--kc-duration) var(--kc-ease), filter var(--kc-duration) var(--kc-ease);
}

.woocommerce div.product form.cart button.single_add_to_cart_button:hover,
.wc-block-components-product-button__button:hover,
a.add_to_cart_button:hover,
.kc-coa__btn:hover {
	background: linear-gradient(135deg, var(--kc-purple), var(--kc-purple-strong)) !important;
	filter: brightness(1.05);
	transform: translateY(-2px);
	box-shadow: var(--kc-glow-brand) !important;
}

.woocommerce div.product form.cart button.single_add_to_cart_button.disabled,
.woocommerce div.product form.cart button.single_add_to_cart_button:disabled {
	background: linear-gradient(135deg, var(--kc-purple-ink), #0d0620) !important;
	border-color: rgba(137, 88, 254, 0.18) !important;
	color: rgba(255, 255, 255, 0.55) !important;
	transform: none;
	box-shadow: none !important;
}

/* 5. COA card ------------------------------------------------------------- */

.kc-coa__icon {
	border-color: var(--kc-line-brand) !important;
	color: var(--kc-purple) !important;
	background: radial-gradient(circle at 50% 35%, rgba(86, 43, 218, 0.24), rgba(0, 0, 0, 0) 70%) !important;
	transition: transform var(--kc-duration) var(--kc-ease), box-shadow var(--kc-duration) var(--kc-ease);
}

.kc-coa:hover .kc-coa__icon {
	transform: scale(1.06);
	box-shadow: var(--kc-glow-brand);
}

/* 6. Variation dropdown ---------------------------------------------------- */

.woocommerce div.product form.cart .variations select,
.woocommerce div.product form.cart select {
	appearance: none !important;
	-webkit-appearance: none !important;
	background-color: var(--kc-ink-700, #121218) !important;
	background-image: linear-gradient(45deg, transparent 50%, var(--kc-purple) 50%),
		linear-gradient(135deg, var(--kc-purple) 50%, transparent 50%) !important;
	background-position: calc(100% - 20px) calc(50% - 2px), calc(100% - 14px) calc(50% - 2px) !important;
	background-size: 6px 6px, 6px 6px !important;
	background-repeat: no-repeat !important;
	border: 1px solid rgba(137, 88, 254, 0.28) !important;
	border-radius: 10px !important;
	color: #fff !important;
	font-size: 0.88rem;
	min-height: 46px;
	padding: 10px 46px 10px 14px !important;
	width: 100%;
	transition: border-color var(--kc-duration-fast) var(--kc-ease), box-shadow var(--kc-duration-fast) var(--kc-ease);
}

.woocommerce div.product form.cart .variations select:hover {
	border-color: rgba(137, 88, 254, 0.55) !important;
}

.woocommerce div.product form.cart .variations select:focus {
	border-color: var(--kc-purple) !important;
	box-shadow: 0 0 0 3px rgba(86, 43, 218, 0.25) !important;
	outline: none;
}

/* The open list is the browser's own control and cannot be restyled beyond
   this, so the closed state carries the design and the list stays legible. */
.woocommerce div.product form.cart .variations select option {
	background: #14141b;
	color: #fff;
}

.woocommerce div.product form.cart .reset_variations {
	color: var(--kc-purple) !important;
}

/* 7. The commitment band: darker, purple, minimal red ---------------------- */

.guten-OUzfxD,
.guten-MQYRvN {
	background-color: var(--kc-ink-900, #0b0b10) !important;
}

.guten-OUzfxD .guten-icon-wrapper,
.guten-MQYRvN .guten-icon-wrapper,
.guten-eRLrc2 .guten-icon-wrapper {
	background: rgba(86, 43, 218, 0.12) !important;
	border: 1px solid var(--kc-line-brand) !important;
	color: var(--kc-purple) !important;
	transition: transform var(--kc-duration) var(--kc-ease), background var(--kc-duration) var(--kc-ease), box-shadow var(--kc-duration) var(--kc-ease);
}


/* 8. Motion: the research library's vocabulary, applied site-wide ---------
   The research library already defines a complete motion system and it is the
   part of the site that feels current. Rather than invent timings, this reuses
   its tokens and its four gestures verbatim:

     cards   lift 3px, border to --kc-line-brand, --kc-glow-brand
     links   go --kc-purple-soft
     arrows  slide 4px on the parent's hover
     media   scale 1.045 over --kc-duration-slow

   Every transition uses --kc-duration / --kc-ease so the whole site shares one
   rhythm. Transform and opacity only, so none of it triggers layout.
   ========================================================================== */

.woocommerce ul.products li.product,
.wp-block-post-template li,
.wc-block-product-template__responsive-wrapper > *,
.guten-eRLrc2 .guten-column-wrapper,
.kc-coa,
.wp-block-group.is-layout-grid .wp-block-gutenverse-image .guten-image-wrapper {
	border-radius: var(--kc-radius-lg, 18px);
	transition:
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration) var(--kc-ease),
		background-color var(--kc-duration) var(--kc-ease);
}

.woocommerce ul.products li.product:hover,
.woocommerce ul.products li.product:focus-within,
.wp-block-post-template li:hover,
.guten-eRLrc2 .guten-column-wrapper:hover,
.kc-coa:hover,
.wp-block-group.is-layout-grid .wp-block-gutenverse-image .guten-image-wrapper:hover {
	border-color: var(--kc-line-brand);
	box-shadow: var(--kc-glow-brand);
	transform: translateY(-3px);
}

.wp-block-group.is-layout-grid .wp-block-gutenverse-image .guten-image-wrapper {
	display: block;
	overflow: hidden;
}

.wp-block-group.is-layout-grid .wp-block-gutenverse-image img,
.woocommerce ul.products li.product img {
	transition: transform var(--kc-duration-slow) var(--kc-ease-out);
}

.wp-block-group.is-layout-grid .wp-block-gutenverse-image .guten-image-wrapper:hover img,
.woocommerce ul.products li.product:hover img {
	transform: scale(1.045);
}

a:where(:not(.wp-element-button)) {
	transition: color var(--kc-duration-fast) var(--kc-ease);
}

a:where(:not(.wp-element-button)):hover {
	color: var(--kc-purple-soft);
}

.woocommerce ul.products li.product h2:hover,
.woocommerce ul.products li.product .woocommerce-loop-product__title:hover {
	text-decoration: underline;
	text-decoration-color: var(--kc-purple);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.22em;
}

.guten-eRLrc2 .guten-column-wrapper:hover {
	background-color: var(--kc-wash-brand);
}

.guten-icon-wrapper {
	transition: transform var(--kc-duration) var(--kc-ease), box-shadow var(--kc-duration) var(--kc-ease);
}

.guten-eRLrc2 .guten-column-wrapper:hover .guten-icon-wrapper {
	transform: translateY(-2px) scale(1.05);
	box-shadow: var(--kc-glow-brand);
}

@media (prefers-reduced-motion: reduce) {
	.woocommerce ul.products li.product,
	.wp-block-post-template li,
	.guten-eRLrc2 .guten-column-wrapper,
	.kc-coa,
	.wp-block-group.is-layout-grid .wp-block-gutenverse-image .guten-image-wrapper,
	.wp-block-group.is-layout-grid .wp-block-gutenverse-image img,
	.woocommerce ul.products li.product img,
	.guten-icon-wrapper,
	.wp-element-button,
	button.single_add_to_cart_button {
		transition: none !important;
		transform: none !important;
	}
}


/* The research library surface, applied to the rest of the site
   ==========================================================================
   The research library is the part of the site that reads as current, and it
   is a system rather than a look: one card, one pill, one band, one eyebrow,
   all built from tokens. This carries that vocabulary onto the catalogue and
   product pages so the two stop looking like different sites.

   Values are copied from research-library.css rather than re-picked, so the
   two stay identical by construction. Every token below was confirmed
   resolving at runtime first; --kc-muted and --kc-dim do not exist and are
   deliberately not used.

   Motion for these surfaces is already defined in the block above and is not
   repeated here.
   ========================================================================== */

/* Cards: the archive product tile gets the research card treatment ---------- */

.woocommerce ul.products li.product,
.wp-block-post-template li.product,
.wc-block-product-template li,
.wp-block-post-template li.wp-block-post {
	background: linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-800));
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-lg);
	overflow: hidden;
	padding: var(--kc-space-3);
}

.woocommerce ul.products li.product img,
.wc-block-product-template li img,
.wp-block-post-template li img {
	border-radius: calc(var(--kc-radius-lg) - 6px);
}

/* Product titles read as the research card's heading ------------------------ */

.woocommerce ul.products li.product .woocommerce-loop-product__title,
.wc-block-product-template li .wp-block-post-title,
.wc-block-product-template li .wc-block-components-product-name {
	color: var(--kc-white);
	line-height: 1.3;
}

/* Eyebrow: the small uppercase purple label -------------------------------- */

.kimera-eyebrow,
.woocommerce ul.products li.product .posted_in,
.wc-block-product-template li .wc-block-components-product-category-list {
	color: var(--kc-purple);
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/* Pills: filters, pagination, tabs ----------------------------------------- */

.woocommerce nav.woocommerce-pagination ul li a,
.woocommerce nav.woocommerce-pagination ul li span,
.wp-block-query-pagination a,
.wp-block-query-pagination span.current,
.woocommerce div.product .woocommerce-tabs ul.tabs li a {
	background: rgba(255, 255, 255, 0.03);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-pill);
	color: var(--kc-text);
	display: inline-flex;
	font-size: 0.9rem;
	font-weight: 600;
	line-height: 1.2;
	padding: 0.62em 1.15em;
	text-decoration: none;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease);
}

.woocommerce nav.woocommerce-pagination ul li a:hover,
.wp-block-query-pagination a:hover,
.woocommerce div.product .woocommerce-tabs ul.tabs li a:hover,
.woocommerce div.product .woocommerce-tabs ul.tabs li.active a {
	background: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
	color: var(--kc-white);
	text-decoration: none;
}

.woocommerce nav.woocommerce-pagination ul li span.current,
.wp-block-query-pagination span.current {
	background: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
	color: var(--kc-white);
}

/* Woo draws its own tab chrome; it has to go or the pill sits inside a box. */
.woocommerce div.product .woocommerce-tabs ul.tabs {
	border: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin: 0 0 var(--kc-space-5);
	padding: 0;
}

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

.woocommerce div.product .woocommerce-tabs ul.tabs li {
	background: none;
	border: 0;
	margin: 0;
	padding: 0;
}

/* Panels: the spec table and the tab body sit on a research card ----------- */

.woocommerce div.product .woocommerce-tabs .panel,
.product-table,
.woocommerce div.product form.cart .variations {
	background: linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-800));
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-lg);
	padding: clamp(18px, 2.4vw, 28px);
}

/* No `overflow: hidden`. Nothing inside carries a background to clip against
   the rounded corners, so it bought nothing, and clipping a `display: table`
   box is the likeliest reason the bottom edge was reported cut off. */
.product-table {
	border-collapse: separate;
	border-spacing: 0;
	/*
	 * `visible` is set EXPLICITLY, not merely omitted, and that distinction is
	 * the whole point. The global-styles record (post 104076) holds a second,
	 * older copy of this stylesheet which still declares
	 * `.product-table { overflow: hidden }`. Deleting the declaration here
	 * leaves the database copy as the only one making a claim, so it wins by
	 * default and nothing changes. **Removing a rule from this file does not
	 * remove it from the site — it has to be overridden.** That is the
	 * three-copy duplication the top of HANDOFF warns about, seen live.
	 */
	overflow: visible;
	width: 100%;
}

.product-table tr {
	transition: background-color var(--kc-duration) var(--kc-ease);
}

.product-table tr:hover {
	background-color: var(--kc-wash-brand);
}

.product-table td,
.product-table th {
	border-bottom: 1px solid var(--kc-line);
	padding: 11px 14px;
	vertical-align: top;
}

.product-table tr:last-child td,
.product-table tr:last-child th {
	border-bottom: 0;
}

.product-table td.static-label {
	color: var(--kc-purple);
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

/* The covers workstream emits td.static-label and keys its width off it, so
   the 42% rule elsewhere still governs the column. Only paint is set here. */

/* Bands: any full-width call to action reads like the COA band ------------- */

.wp-block-group.kimera-band-login,
.woocommerce-message,
.woocommerce-info {
	background:
		radial-gradient(120% 160% at 0% 0%, rgba(86, 43, 218, 0.28), transparent 62%),
		linear-gradient(135deg, var(--kc-ink-700), var(--kc-ink-900));
	border: 1px solid var(--kc-line-brand);
	border-radius: var(--kc-radius-lg);
	color: var(--kc-white);
}

.woocommerce-message::before,
.woocommerce-info::before {
	color: var(--kc-purple);
}

/* Homepage: browse-by-chemistry pill row ------------------------------------
   The nine structural-chemistry categories, demoted from grid tiles on
   2026-08-16. Same pill recipe as pagination/tabs above; kept as its own
   block because these live on the front-page template, not in Woo chrome. */

.kc-chem-browse {
	margin-top: 34px;
}

.kc-chem-browse .kimera-eyebrow {
	margin: 0 0 14px;
}

.kc-chem-pills {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin: 0;
}

.kc-chem-pills a {
	background: rgba(255, 255, 255, 0.03);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-pill);
	color: var(--kc-text);
	display: inline-flex;
	font-size: 0.9rem;
	font-weight: 600;
	line-height: 1.2;
	padding: 0.62em 1.15em;
	text-decoration: none;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease);
}

.kc-chem-pills a:hover {
	background: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
	color: var(--kc-white);
	text-decoration: none;
}

/* My Account — the whole page, on the library
   ==========================================================================
   Audited 2026-08-16 at 1440. The field colours and the submit were fixed in
   an earlier pass; this is the surrounding page, which was still WooCommerce
   default sitting on black:

     form.login        1px solid rgb(207,200,216) at 5px radius — a light-grey
                       box outline, from `.woocommerce form.login` (0,2,1)
     labels            22px, and the submit 22px Michroma in a 143x71 button,
                       because neither declares a size and both INHERIT the
                       page's base. Nothing was setting them; that is why a
                       search for the rule came back empty.
     panels            no card anywhere — the form, the account nav and the
                       content column were all bare

   Everything below is the research card and pill vocabulary applied to the
   parts WooCommerce actually renders. The signed-in half — the account
   navigation, the orders table, the address cards, the edit-account form —
   could not be opened from a signed-out session, so those selectors were
   verified by building WooCommerce's own markup in a live page and reading the
   computed styles back, the same method used for the FAQ accordion.

   `body .woocommerce …` throughout: WooCommerce's own rules sit at (0,2,1) and
   this clears them by one element without `!important`.
   ========================================================================== */

/* Panels — every box on the page becomes a research card ---------------------- */

body.woocommerce-account .woocommerce form.login,
body.woocommerce-account .woocommerce form.register,
body.woocommerce-account .woocommerce .woocommerce-EditAccountForm,
body.woocommerce-account .woocommerce .woocommerce-Address,
body.woocommerce-account .woocommerce .woocommerce-MyAccount-content {
	background: linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-800));
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-lg);
	padding: 28px;
}

body.woocommerce-account .woocommerce .woocommerce-Address {
	transition:
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration) var(--kc-ease);
}

body.woocommerce-account .woocommerce .woocommerce-Address:hover {
	border-color: var(--kc-line-brand);
	box-shadow: var(--kc-glow-brand);
	transform: translateY(-3px);
}

/* Account navigation — a card of pills --------------------------------------- */

body.woocommerce-account .woocommerce-MyAccount-navigation ul {
	background: linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-800));
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-lg);
	list-style: none;
	margin: 0;
	overflow: hidden;
	padding: 8px;
}

body.woocommerce-account .woocommerce-MyAccount-navigation li {
	border: 0;
	list-style: none;
	margin: 0;
}

body.woocommerce-account .woocommerce-MyAccount-navigation li a {
	border-radius: var(--kc-radius);
	color: var(--kc-text);
	display: block;
	font-size: 0.92rem;
	padding: 0.72em 1em;
	text-decoration: none;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease);
}

body.woocommerce-account .woocommerce-MyAccount-navigation li a:hover {
	background-color: var(--kc-wash-brand);
	color: var(--kc-white);
}

body.woocommerce-account .woocommerce-MyAccount-navigation li.is-active a {
	background-color: var(--kc-wash-brand);
	box-shadow: inset 2px 0 0 var(--kc-purple);
	color: var(--kc-purple-soft);
}

/* Form typography — the labels and the submit were inheriting 22px ------------ */

body.woocommerce-account .woocommerce form .form-row label,
body.woocommerce-account .woocommerce label.woocommerce-form-login__rememberme,
body.woocommerce-account .woocommerce .woocommerce-form-row label {
	color: var(--kc-text-dim);
	font-size: 0.86rem;
	font-weight: 500;
	letter-spacing: 0.01em;
	line-height: 1.4;
	margin-bottom: 6px;
}

body.woocommerce-account .woocommerce button.button,
body.woocommerce-account .woocommerce input.button {
	font-size: 0.86rem;
	letter-spacing: 0.02em;
	padding: 0.9em 1.9em;
}

/* Orders table — hairline rows, eyebrow header ------------------------------- */

/* `separate` rather than `collapse`, deliberately: a collapsed table ignores
   border-radius, so the card corners would not render. Spacing is zeroed so it
   still reads as one solid block.

   And `border: 0` before the hairline, because the Customizer layer carries a
   bare `td, th { border: 1px solid rgb(160,160,160) }`. Setting only
   `border-bottom` leaves that grey on the other three sides and the table
   comes out as a grey grid. */
:is(body.woocommerce-account, body.woocommerce-cart) .woocommerce table.shop_table {
	border: 1px solid var(--kc-line);
	border-collapse: separate;
	border-radius: var(--kc-radius-lg);
	border-spacing: 0;
	overflow: hidden;
	width: 100%;
}

:is(body.woocommerce-account, body.woocommerce-cart) .woocommerce table.shop_table th {
	background-color: rgba(255, 255, 255, 0.03);
	border: 0;
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-purple);
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	padding: 14px 16px;
	text-align: left;
	text-transform: uppercase;
}

:is(body.woocommerce-account, body.woocommerce-cart) .woocommerce table.shop_table td {
	border: 0;
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-text-dim);
	padding: 14px 16px;
}

:is(body.woocommerce-account, body.woocommerce-cart) .woocommerce table.shop_table tbody tr:last-child td {
	border-bottom: 0;
}

:is(body.woocommerce-account, body.woocommerce-cart) .woocommerce table.shop_table tbody tr {
	transition: background-color var(--kc-duration) var(--kc-ease);
}

:is(body.woocommerce-account, body.woocommerce-cart) .woocommerce table.shop_table tbody tr:hover {
	background-color: var(--kc-wash-brand);
}

/* Address headings take the library's eyebrow; the greeting stays prose. */
body.woocommerce-account .woocommerce .woocommerce-Address h3,
body.woocommerce-account .woocommerce .woocommerce-column__title {
	color: var(--kc-purple);
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

@media (prefers-reduced-motion: reduce) {
	body.woocommerce-account .woocommerce .woocommerce-Address:hover {
		transform: none;
	}
}

/* Quantity spinners, footer chips, compliance blocks, card overlays
   ==========================================================================
   The number spinner is the honest limit in this file. A `<input
   type="number">` renders its own stepper and the ONLY parts CSS can reach
   are `::-webkit-inner-spin-button` and its Firefox equivalent — the arrows
   themselves are drawn by the browser in its own colours, which is why they
   read as pale grey nubs on a dark field. They are inverted and given room
   here, which makes them legible and clickable.

   Replacing them with real -/+ buttons is possible but is NOT a CSS job: it
   needs markup and a script to keep the value, the min/max and the WooCommerce
   change events in sync. That is a separate piece of work, and doing it badly
   would break add-to-cart. Recorded rather than half-done.

   The compliance copy runs to 1296px per line at 1440 — roughly double a
   comfortable measure — and is the same `.text-content-inner` block used four
   times a page, so the measure is applied to all of them rather than to one
   generated id.
   ========================================================================== */

/* Number steppers: make the browser's own arrows visible on a dark field. */
body .quantity input[type="number"]::-webkit-inner-spin-button,
body .quantity input[type="number"]::-webkit-outer-spin-button,
body .cuw-qty::-webkit-inner-spin-button,
body .ue_mini_input::-webkit-inner-spin-button {
	cursor: pointer;
	filter: invert(1) brightness(1.6);
	margin-left: 4px;
	opacity: 1;
	width: 16px;
}

body .quantity input[type="number"] {
	-moz-appearance: number-input;
}

/* Compliance and colophon copy — a measure, then a block ---------------------- */

/* A REM cap, not `ch`. This block sets a wide display face, so its "0" glyph
   is about 17px and `78ch` computed to 1316px — barely narrower than the
   1296px it was already running. `ch` is only a reading measure when the font
   is a normal-width text face; here it is meaningless and rem is honest. */
body .gutenverse-text-editor .text-content-inner p {
	max-width: 46rem;
}

/* The Research Use Only band. Generated section id, same fragility as the
   header and footer rules above: recreate the section in the editor and this
   stops matching silently. */
body .guten-3Oe5Hr .text-content-inner {
	background:
		radial-gradient(120% 160% at 0% 0%, rgba(137, 88, 254, 0.12) 0%, rgba(0, 0, 0, 0) 60%),
		linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-900));
	border: 1px solid var(--kc-line);
	border-left: 2px solid var(--kc-line-brand);
	border-radius: var(--kc-radius-lg);
	padding: 26px 30px;
	transition: border-color var(--kc-duration) var(--kc-ease);
}

body .guten-3Oe5Hr .text-content-inner:hover {
	border-color: var(--kc-line-brand);
}

body .guten-3Oe5Hr .text-content-inner p {
	color: var(--kc-text-dim);
}

body .guten-3Oe5Hr .text-content-inner strong {
	color: var(--kc-white);
}

/* Footer policy links become chips, matching the breadcrumb trail. */
body .guten-icon-list .list-wrapper .guten-icon-list-item > a {
	border: 1px solid transparent;
	border-radius: var(--kc-radius-pill);
	display: inline-block;
	padding: 0.34em 0.9em;
}

body .guten-icon-list .list-wrapper .guten-icon-list-item > a:hover {
	background-color: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
}

/* The card image's empty overlay div is a ready-made hover surface — the
   library's media treatment, without touching the image itself. */
body .wc-block-components-product-image__inner-container {
	background: linear-gradient(180deg, rgba(137, 88, 254, 0) 40%, rgba(137, 88, 254, 0.18) 100%);
	inset: 0;
	opacity: 0;
	pointer-events: none;
	position: absolute;
	transition: opacity var(--kc-duration) var(--kc-ease);
}

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

body li.wc-block-product:hover .wc-block-components-product-image__inner-container {
	opacity: 1;
}

/* Description column, section headings, and the header lockup
   ==========================================================================
   Measured 2026-08-16. Four things in this pass, and one of them finally gets
   the research card's LIFT — because unlike the title and price in the block
   below, these are genuinely clickable.

     header lockup       an <a> to the home page with no hover state at all.
                         It IS a link, so it takes the lift and a glow.
     h2#h-description    `border-bottom: 2px solid WHITE` — a heavy red-era
                         rule. Becomes the library's section header: hairline
                         plus a purple accent that grows on hover.
     h2#h-related-products  15.7px against the Description heading's 32px, for
                         two headings at the same level on the same page.
                         Normalised.
     table.variations    already a card, but `transition: all` from Gutenverse
                         and no hover state to transition to.

   The related-compound links become chips with a sliding arrow — the library's
   `translateX(4px)` on `::after`, which is its established motion for "this
   goes somewhere".
   ========================================================================== */

/* The header lockup — a link, so it earns the lift. */
body .guten-u1u02U .guten-image-wrapper,
body .guten-u1u02U .gutenverse-nav-logo {
	display: inline-block;
	transition:
		filter var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration) var(--kc-ease);
}

body .guten-u1u02U .guten-image-wrapper:hover,
body .guten-u1u02U .gutenverse-nav-logo:hover {
	filter: drop-shadow(0 6px 18px rgba(137, 88, 254, 0.45));
	transform: translateY(-2px) scale(1.02);
}

/* Section headings in the description column ---------------------------------- */

/* "Related products" is NOT in this column — it sits inside
   `.wp-block-woocommerce-product-collection` further down — and it measured
   15.75px against Description's 32px, two headings at the same level on the
   same page. Both are matched here so they finally agree. */
body.single-product .guten-kuheTl > .guten-column-wrapper > h2.wp-block-heading,
body.single-product .wp-block-woocommerce-product-collection > h2.wp-block-heading {
	border-bottom: 1px solid var(--kc-line) !important;
	border-bottom-width: 1px !important;
	color: var(--kc-white);
	font-family: var(--wp--preset--font-family--michroma, inherit);
	font-size: 1.5rem !important;
	padding-bottom: 14px;
	position: relative;
}

body.single-product .guten-kuheTl > .guten-column-wrapper > h2.wp-block-heading::after,
body.single-product .wp-block-woocommerce-product-collection > h2.wp-block-heading::after {
	background: var(--kc-purple);
	bottom: -1px;
	content: "";
	height: 1px;
	left: 0;
	position: absolute;
	transition: width var(--kc-duration-slow) var(--kc-ease-out);
	width: 64px;
}

body.single-product .guten-kuheTl > .guten-column-wrapper > h2.wp-block-heading:hover::after,
body.single-product .wp-block-woocommerce-product-collection > h2.wp-block-heading:hover::after {
	width: 140px;
}

/* The variations table had a card and nothing to hover into. */
body.single-product .woocommerce div.product form.cart .variations,
body.single-product table.variations {
	transition:
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease) !important;
}

body.single-product table.variations:hover {
	border-color: var(--kc-line-brand);
	box-shadow: var(--kc-glow-brand);
}

/* Related-compound links: chips that slide, the library's "goes somewhere". */
body.single-product .guten-post-content h3 + ul li {
	list-style: none;
	margin-bottom: 8px;
}

body.single-product .guten-post-content h3 + ul li > a {
	background-color: rgba(255, 255, 255, 0.03);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-pill);
	color: var(--kc-text);
	display: inline-block;
	padding: 0.4em 1em;
	text-decoration: none;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration) var(--kc-ease);
}

body.single-product .guten-post-content h3 + ul li > a::after {
	content: "→";
	display: inline-block;
	margin-left: 8px;
	transition: transform var(--kc-duration) var(--kc-ease);
}

body.single-product .guten-post-content h3 + ul li > a:hover {
	background-color: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
	color: var(--kc-white);
}

body.single-product .guten-post-content h3 + ul li > a:hover::after {
	transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
	body .guten-u1u02U .guten-image-wrapper:hover,
	body .guten-u1u02U .gutenverse-nav-logo:hover {
		transform: none;
	}

	body.single-product .guten-kuheTl > .guten-column-wrapper > h2.wp-block-heading:hover::after {
		width: 64px;
	}

	body.single-product .guten-post-content h3 + ul li > a:hover::after {
		transform: none;
	}
}

/* Product identity blocks — hero, title, price, summary
   ==========================================================================
   These four were loose text on a black page: an H1 in an empty band, an H2,
   a bare price and an unstyled disclaimer paragraph. They now read as blocks
   in the library's vocabulary.

   ONE DELIBERATE DEPARTURE, and it is worth knowing. The research card's
   hover is `translateY(-3px)` + brand border + glow, and that lift is reserved
   here for things you can actually click. A title, a price and a disclaimer
   are not links, and lifting them on hover promises a click that never
   happens. They animate on the two properties that carry the same brand
   signal without the false affordance — border to `--kc-line-brand` and
   `--kc-glow-brand` — over the shared timing tokens. Cards that ARE links
   keep the lift everywhere else in this file.

   The price container is styled, not the amount, because it holds two
   different children: `.woocommerce-Price-amount` signed in and
   `span.login-to-see-price` signed out. Both need the same chip, and the
   signed-out state is the one most visitors see.
   ========================================================================== */

/* The hero becomes the library's band. */
body.single-product .guten-yhBEdm {
	background:
		radial-gradient(115% 130% at 8% 0%, rgba(137, 88, 254, 0.16) 0%, rgba(0, 0, 0, 0) 58%),
		linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-900)) !important;
	border: 1px solid var(--kc-line-brand);
	border-radius: var(--kc-radius-lg);
	transition:
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease);
}

body.single-product .guten-yhBEdm:hover {
	border-color: var(--kc-purple);
	box-shadow: var(--kc-glow-brand);
}

/* The details-column title gets an accent rule, so it opens a block rather
   than floating above one. */
body.single-product .product-details > h2.wp-block-post-title {
	border-bottom: 1px solid var(--kc-line);
	padding-bottom: 14px;
	position: relative;
}

body.single-product .product-details > h2.wp-block-post-title::after {
	background: var(--kc-purple);
	bottom: -1px;
	content: "";
	height: 1px;
	left: 0;
	position: absolute;
	transition: width var(--kc-duration-slow) var(--kc-ease-out);
	width: 64px;
}

body.single-product .product-details:hover > h2.wp-block-post-title::after {
	width: 120px;
}

/* The price is a chip — in both its signed-in and signed-out states. */
body.single-product .product-details .wp-block-woocommerce-product-price {
	background-color: rgba(255, 255, 255, 0.04);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius);
	display: inline-block;
	padding: 10px 18px !important;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease);
}

body.single-product .product-details .wp-block-woocommerce-product-price:hover {
	background-color: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
	box-shadow: var(--kc-glow-brand);
}

body.single-product .product-details .woocommerce-Price-amount {
	color: var(--kc-purple);
	font-family: var(--kc-mono);
	font-weight: 600;
}

/* The gated state — what most visitors actually see, since prices are behind
   the B2B gate. Colour is left to the shared `.price` rule, which paints it
   `--kc-purple`: an attempt to mute it here lost the cascade, and on measuring
   the result the purple is the better answer anyway — "Login to view price" is
   a prompt, and reading as actionable is correct. Only the type is set. */
body.single-product .product-details .login-to-see-price {
	font-size: 0.92rem;
	letter-spacing: 0.02em;
}

/* The RUO summary is a notice, and now looks like one. */
body.single-product .wc-block-components-product-summary {
	background-color: rgba(255, 255, 255, 0.03);
	border: 1px solid var(--kc-line);
	border-left: 2px solid var(--kc-line-brand);
	border-radius: var(--kc-radius);
	padding: 16px 18px;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease);
}

body.single-product .wc-block-components-product-summary:hover {
	border-color: var(--kc-line-brand);
}

body.single-product .wc-block-components-product-summary p {
	color: var(--kc-text-dim);
	font-size: 0.92rem;
	line-height: 1.65;
	margin: 0;
	max-width: 68ch;
}

@media (prefers-reduced-motion: reduce) {
	body.single-product .product-details:hover > h2.wp-block-post-title::after {
		width: 64px;
	}
}

/* Product hero spec strip, and the description prose
   ==========================================================================
   The hero was a bare H1 on an empty full-width band. CAS, molecular weight
   and compound class — the three things a buyer checks first — sat in the spec
   table far below the fold. They are now emitted beside the title by
   `kimera_ui_product_spec_strip()` in inc/kimera-ui.php, read from real ACF
   fields rather than scraped out of the description markup.

   Values take `--kc-mono`, which the token block reserves for "anything that
   is data rather than prose: counts, formulae, CAS numbers, lot IDs". A CAS
   number is the canonical case for it.

   AND THE DESCRIPTION HAD NO PROSE LAYER AT ALL. `kc-prose`'s second hook is
   `body.page:not(.woocommerce-page) .entry-content`, and a product page IS
   `.woocommerce-page`, so every product description — the longest reading on
   the site — fell through both hooks. Its measure, leading and heading rhythm
   are applied here instead of widening that selector, because the exclusion is
   deliberate: it keeps the prose rules off cart and checkout.
   ========================================================================== */

.kc-spec-strip {
	display: flex;
	flex-wrap: wrap;
	gap: 10px 28px;
	margin: 18px 0 0;
}

.kc-spec-strip__item {
	min-width: 0;
}

.kc-spec-strip__label {
	color: var(--kc-purple);
	font-size: 0.68rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	margin: 0 0 3px;
	text-transform: uppercase;
}

.kc-spec-strip__value {
	color: var(--kc-text);
	font-family: var(--kc-mono);
	font-size: 0.92rem;
	margin: 0;
}

/* Title left, specs right, once there is room for both. */
@media (min-width: 782px) {
	body.single-product .guten-yhBEdm .guten-column-wrapper {
		align-items: flex-end;
		display: flex;
		flex-wrap: wrap;
		gap: 12px 40px;
		justify-content: space-between;
	}

	body.single-product .guten-yhBEdm .kc-spec-strip {
		margin: 0 0 6px;
	}
}

/* Product description — the prose contract kc-prose never reached ------------ */

body.single-product .guten-post-content,
body.single-product .woocommerce-Tabs-panel {
	font-size: 1.02rem;
	line-height: 1.78;
}

body.single-product .guten-post-content :is(p, li),
body.single-product .woocommerce-Tabs-panel :is(p, li) {
	color: var(--kc-text-muted);
	max-width: 68ch;
}

body.single-product .guten-post-content :is(h2, h3),
body.single-product .woocommerce-Tabs-panel :is(h2, h3) {
	color: var(--kc-white);
	font-family: var(--wp--preset--font-family--michroma, inherit);
	font-weight: 500;
	letter-spacing: -0.015em;
	line-height: 1.28;
	margin: 2.4em 0 0.7em !important;
	scroll-margin-top: 6rem;
}

body.single-product .guten-post-content > :first-child {
	margin-top: 0 !important;
}

/* Unclassed tables in the description get the same card as everywhere else.
   `border: 0` first, because the Customizer layer paints every bare td/th
   with a grey 1px border and only setting `border-bottom` leaves a grid. */
body.single-product .guten-post-content table {
	border: 1px solid var(--kc-line);
	border-collapse: separate;
	border-radius: var(--kc-radius-lg);
	border-spacing: 0;
	width: 100%;
}

body.single-product .guten-post-content table th {
	background-color: rgba(255, 255, 255, 0.03);
	border: 0;
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-purple);
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	padding: 12px 16px;
	text-align: left;
	text-transform: uppercase;
}

body.single-product .guten-post-content table td {
	border: 0;
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-text-muted);
	max-width: none;
	padding: 12px 16px;
}

body.single-product .guten-post-content table tr:last-child td {
	border-bottom: 0;
}

body.single-product .guten-post-content table tr:hover td {
	background-color: var(--kc-wash-brand);
}

/* The RUO disclaimer reads as a band, not as a quotation. */
body.single-product .guten-post-content blockquote {
	background:
		radial-gradient(120% 140% at 100% 0%, rgba(137, 88, 254, 0.14) 0%, rgba(0, 0, 0, 0) 55%),
		linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-900));
	border: 1px solid var(--kc-line-brand);
	border-radius: var(--kc-radius-lg);
	margin: 2em 0 0;
	padding: 20px 24px;
}

body.single-product .guten-post-content blockquote p {
	color: var(--kc-text-dim);
	margin: 0;
	max-width: none;
}

/* The COA band, the order-bump section, and the spec table
   ==========================================================================
   Reported 2026-08-16 and all three measured before touching.

   **The COA band was still the red design.** Not a leftover hex in markup —
   a whole rule, `radial-gradient(… rgba(150,20,22,0.16) …)` over
   `linear-gradient(rgb(13,5,5), rgb(5,2,2))` with a `rgb(110,22,24)` border.
   It lives in an inline `<style>` with no id, at bare `.kc-coa` (0,1,0), which
   is why grepping this file for it found nothing: the rule is not in this
   file. A `body` prefix takes it at (0,1,1) with no `!important`. Its button
   was already purple from the shared button rule, which is exactly what made
   the red band look deliberate rather than stale.

   **The order-bump section had no styling at all.** It also carries INLINE
   `border-width: 0; padding: 0`, so the card needs `!important` to exist —
   inline styles outrank any selector. Its rows become sub-cards inside the
   panel, one surface step down, which is how the library nests.

   The `.product-table` keeps its card but drops `overflow: hidden`. Nothing
   inside it has a background to clip, so the overflow bought nothing, and
   clipping on a `display: table` box is the most likely cause of the bottom
   edge being reported as cut off. Row hover is added to match every other
   table on the site.
   ========================================================================== */

body .kc-coa {
	background:
		radial-gradient(120% 140% at 100% 0%, rgba(137, 88, 254, 0.18) 0%, rgba(0, 0, 0, 0) 55%),
		linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-900));
	border: 1px solid var(--kc-line-brand);
	border-radius: var(--kc-radius-lg);
}

body .kc-coa:hover {
	border-color: var(--kc-purple);
	box-shadow: var(--kc-glow-brand);
}

body .kc-coa__text {
	color: var(--kc-text-dim);
}

/* Order bump / product add-ons ------------------------------------------------ */

body .cuw-product-addons {
	background: linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-800)) !important;
	border: 1px solid var(--kc-line) !important;
	border-radius: var(--kc-radius-lg) !important;
	padding: 22px !important;
}

body .cuw-product-addons .cuw-template-title {
	font-family: var(--wp--preset--font-family--michroma, inherit);
	font-size: 1rem;
	letter-spacing: 0.01em;
}

/* Each offered product is a sub-card, one step up from the panel. */
body .cuw-product-addons .cuw-product-row {
	background-color: rgba(255, 255, 255, 0.03);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius);
	padding: 12px !important;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease);
}

body .cuw-product-addons .cuw-product-row:hover {
	background-color: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
}

body .cuw-product-addons .cuw-product-image img {
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-sm);
}

body .cuw-product-addons .cuw-product-title {
	color: var(--kc-white);
	font-family: inherit;
	font-weight: 500;
}

body .cuw-product-addons .cuw-product-price,
body .cuw-product-addons .cuw-product-price .amount,
body .cuw-product-addons .cuw-total-price {
	color: var(--kc-purple);
	font-weight: 600;
}

body .cuw-product-addons .cuw-product-checkbox {
	accent-color: var(--kc-purple);
	height: 17px;
	width: 17px;
}

body .cuw-product-addons .cuw-product-addons-pricing-section {
	border-top: 1px solid var(--kc-line);
	padding-top: 12px;
}

/* The stepper inside a bump row, which is the same control as everywhere else. */
body .cuw-product-addons .quantity-input .cuw-qty {
	background-color: rgba(255, 255, 255, 0.04);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-sm);
	color: var(--kc-text);
}

/* Single product — the four gaps left after the archive pass
   ==========================================================================
   Audited 2026-08-16 against the real signed-in markup (the page renders its
   content at 0x0 to a signed-out visitor — the B2B gate). Most of it was
   already right: Michroma 40px title, purple price, purple gradient
   add-to-cart, and a variation `select` that is already dark with a brand
   border and `appearance: none`. Four things were not.

   The `table.variations` carried a 1px hairline AND `border-radius: 18px`
   while still `border-collapse: collapse`, so the corners never rendered —
   the same silent conflict already fixed on the cart, account and attributes
   tables. That is four tables in this file now; a collapsed table always
   ignores its radius.

   The quantity field was the raw browser default here, white on black. Its
   rule existed but was scoped to `body.woocommerce-cart`, so the identical
   control on the product page missed it; the selector is now shared.
   ========================================================================== */

body.single-product .woocommerce table.variations {
	border-collapse: separate;
	border-spacing: 0;
	overflow: hidden;
}

/* The attribute label is a form label, so it matches the ones on My Account
   rather than staying 15px bold white. */
body.single-product .woocommerce table.variations th.label label {
	color: var(--kc-text-dim);
	font-size: 0.86rem;
	font-weight: 500;
	letter-spacing: 0.01em;
}

/* The short description gets a MEASURE only. Its white is deliberate and set
   further up this file at (0,3,2): the short description is the product's lead
   copy, and kc-prose makes the same distinction — lead paragraphs take
   --kc-text, body copy takes --kc-text-muted. A first pass here tried to mute
   it and lost the cascade, which was the right outcome; the rule was wrong,
   not the specificity. Only the unbounded line length needed fixing. */
body.single-product .woocommerce-product-details__short-description p {
	max-width: 68ch;
}

/* Stock reads as status, not prose. In stock stays quiet; out of stock keeps a
   warning tone, the same call as the cart's remove control. */
body.single-product .woocommerce p.stock.in-stock {
	color: var(--kc-text-dim);
	font-size: 0.86rem;
}

body.single-product .woocommerce p.stock.out-of-stock {
	color: #ff6b6b;
	font-size: 0.86rem;
}

/* Category archive chrome — the furniture around the cards
   ==========================================================================
   Second pass, 2026-08-16, after the cards were done and the page still did
   not read as the library. The cards were only ever half of it; everything
   framing them was untouched. Measured at 1440 on
   /product-category/nootropics/:

     select.orderby     white background, black text, 1px #767676, 0 radius,
                        26px tall and `appearance: auto` — the raw operating
                        system dropdown sitting on a black page. The single
                        loudest thing on the archive.
     result count       Michroma 15px in plain white, styled as body copy
                        where it is really section meta
     breadcrumb         Michroma 15.7px white — as heavy as the content
     term description   20px/36px across a 900px measure in white, against the
                        prose contract of 19px/1.78 at 68ch in --kc-text-muted
     pagination current WHITE background with BLACK text

   That last one is the parent theme: `oigny-lite-custom-styling` carries
   `.wp-block-query-pagination .page-numbers.current` at (0,3,0) with `color`
   marked `!important`, which beat the existing pill rule at (0,2,1) — so the
   border and nothing else had been landing. Prefixing with `body` clears the
   specificity and the colour needs its own `!important` to answer theirs.

   The select drops `appearance: none`, which removes the native arrow, so one
   is supplied as an inline SVG. A data URI cannot read `currentColor`, so the
   chevron is `--kc-text-dim`'s literal value; if that token moves, this moves
   with it by hand.
   ========================================================================== */

body .woocommerce-ordering select.orderby,
body .wc-block-catalog-sorting select.orderby,
body .woocommerce .woocommerce-ordering select {
	appearance: none;
	-webkit-appearance: none;
	background-color: rgba(255, 255, 255, 0.04);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%23c9c5d1' stroke-width='1.6' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
	background-position: right 14px center;
	background-repeat: no-repeat;
	background-size: 11px;
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-pill);
	color: var(--kc-text);
	font-family: inherit;
	font-size: 0.9rem;
	height: auto;
	padding: 0.62em 2.6em 0.62em 1.15em;
	transition:
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease);
}

body .woocommerce-ordering select.orderby:hover {
	border-color: var(--kc-line-brand);
}

body .woocommerce-ordering select.orderby:focus {
	border-color: var(--kc-purple);
	box-shadow: 0 0 0 3px var(--kc-wash-brand);
	outline: none;
}

/* The open dropdown is drawn by the OS on some platforms and by the page on
   others; setting the options covers the second case. */
body .woocommerce-ordering select.orderby option {
	background-color: var(--kc-ink-800);
	color: var(--kc-text);
}

/* Result count reads as section meta, so it takes the eyebrow. */
body .woocommerce-result-count,
body .wc-block-product-results-count {
	color: var(--kc-purple);
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/* Breadcrumb — a trail of chips rather than a line of slashed text
   ==========================================================================
   The markup half of this is in `kimera_ui_breadcrumb_markup()`: WooCommerce
   emits bare text with "/" between crumbs and leaves the FINAL crumb as an
   unwrapped text node, which CSS cannot reach at all. Each crumb is now a
   span and the "/" is gone, so the trail can be built here.

   Links are pills on the library's recipe; the current page is the same shape
   without a border, so it reads as "you are here" rather than as another
   control. The separator is a `::before` chevron on every item after the
   first, so it never enters the accessibility tree or a copy-paste.
   ========================================================================== */

body .woocommerce-breadcrumb,
body .wc-block-breadcrumbs {
	align-items: center;
	color: var(--kc-text-dim);
	display: flex;
	flex-wrap: wrap;
	font-size: 0.8rem;
	gap: 2px;
}

body .kc-crumbs .kc-crumbs__item {
	align-items: center;
	display: inline-flex;
}

/* The chevron, drawn rather than typed. */
body .kc-crumbs .kc-crumbs__item + .kc-crumbs__item::before {
	color: var(--kc-text-dim);
	content: "";
	display: inline-block;
	height: 6px;
	margin: 0 8px;
	opacity: 0.5;
	transform: rotate(45deg);
	width: 6px;
	border-right: 1.5px solid currentColor;
	border-top: 1.5px solid currentColor;
}

/* Every crumb is a chip; only the linked ones respond. */
body .kc-crumbs .kc-crumbs__item > a,
body .kc-crumbs .kc-crumbs__item {
	border-radius: var(--kc-radius-pill);
	line-height: 1.2;
}

body .kc-crumbs .kc-crumbs__item > a {
	background-color: rgba(255, 255, 255, 0.03);
	border: 1px solid var(--kc-line);
	color: var(--kc-text-dim);
	display: inline-block;
	padding: 0.34em 0.85em;
	text-decoration: none;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease);
}

body .kc-crumbs .kc-crumbs__item > a:hover {
	background-color: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
	color: var(--kc-white);
}

/* The current page: same chip, no border, so it reads as position not action. */
body .kc-crumbs .kc-crumbs__item:last-child {
	background-color: transparent;
	color: var(--kc-text);
	padding: 0.34em 0.5em;
}

/* The block breadcrumb on archives has no spans to work with, so it keeps the
   quieter text treatment; only its links become chips. */
body .wc-block-breadcrumbs a {
	background-color: rgba(255, 255, 255, 0.03);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-pill);
	color: var(--kc-text-dim);
	display: inline-block;
	padding: 0.34em 0.85em;
	text-decoration: none;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease);
}

body .wc-block-breadcrumbs a:hover {
	background-color: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
	color: var(--kc-white);
}

/* Checkout prose — carried over deliberately, and NOT with a blanket rule
   ==========================================================================
   `kc-prose` excludes `.woocommerce-page` for a reason, and measuring checkout
   shows what it is: of 100 `<p>` elements on the page, **28 are `.form-row`
   field wrappers**, not prose. A blanket `p { max-width: 68ch }` would
   constrain the billing form, and HANDOFF already records the review table as
   having no slack at 345px.

   So the prose contract is applied to the containers that genuinely hold
   reading — the privacy notice, the terms text and the payment-method
   descriptions — and to nothing that wraps a field. Font size is set on those
   containers only, never on a checkout ancestor, so it cannot cascade into
   inputs, labels or the order table.
   ========================================================================== */

body.woocommerce-checkout .woocommerce-privacy-policy-text,
body.woocommerce-checkout .woocommerce-terms-and-conditions,
body.woocommerce-checkout .woocommerce-terms-and-conditions-wrapper .woocommerce-terms-and-conditions-checkbox-text,
body.woocommerce-checkout .payment_box {
	font-size: 0.95rem;
	line-height: 1.7;
}

body.woocommerce-checkout .woocommerce-privacy-policy-text :is(p, li),
body.woocommerce-checkout .woocommerce-terms-and-conditions :is(p, li),
body.woocommerce-checkout .payment_box :is(p, li) {
	color: var(--kc-text-muted);
	max-width: 68ch;
}

/* THIS RULE LOST FOR AS LONG AS IT EXISTED, and the signed-in look is how it
   was caught. The version here was `body.woocommerce-checkout .payment_box` at
   (0,2,1). WooCommerce ships
   `.woocommerce-checkout #payment div.payment_box { background-color: #dcd7e2;
   color: #515151; border-radius: 2px; padding: 1em; font-size: .92em }`
   at (1,2,1), and an ID cannot be beaten by adding classes.

   Measured signed in before the fix: the panel painted rgb(220,215,226) with
   rgb(81,81,81) text — a light lilac card with grey type, sitting on the dark
   checkout. Every declaration below was being ignored, not just the colour.

   Matching the plugin's own selector shape and adding `body` takes this to
   (1,3,1), which is cascade-guide step 5 and needs no `!important`. */
body.woocommerce-checkout #payment div.payment_box {
	background-color: rgba(255, 255, 255, 0.03);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius);
	color: var(--kc-text-muted);
	padding: 14px 16px;
}

/* The pointer WooCommerce draws from the selected method into its panel is a
   CSS triangle built from border colours, so it stayed #dcd7e2 and would have
   left a pale arrow above a dark box. */
body.woocommerce-checkout #payment div.payment_box::before {
	border-bottom-color: rgba(255, 255, 255, 0.03);
}

/* The order review table — the same card as every other table on the site.
   `border: 0` first, because the Customizer layer paints every bare td/th with
   a grey 1px border: measured rgb(160,160,160) on these headers, which is the
   grid this file has already had to reset three times elsewhere. */
body.woocommerce-checkout .woocommerce-checkout-review-order-table {
	border: 1px solid var(--kc-line);
	border-collapse: separate;
	border-radius: var(--kc-radius-lg);
	border-spacing: 0;
	width: 100%;
}

body.woocommerce-checkout .woocommerce-checkout-review-order-table th {
	background-color: rgba(255, 255, 255, 0.03);
	border: 0;
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-purple);
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	padding: 12px 16px;
	text-align: left;
	text-transform: uppercase;
}

body.woocommerce-checkout .woocommerce-checkout-review-order-table td {
	border: 0;
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-text-muted);
	padding: 12px 16px;
}

body.woocommerce-checkout .woocommerce-checkout-review-order-table tfoot tr:last-child :is(th, td) {
	border-bottom: 0;
}

/* The order total is the number a buyer checks twice; it should not be the
   same weight as the line items above it. */
body.woocommerce-checkout .woocommerce-checkout-review-order-table tr.order-total :is(th, td) {
	color: var(--kc-text);
	font-size: 1.02rem;
}

/* PLACE ORDER HAD NO PADDING AT ALL. It picked up the brand ground and the
   pill radius from the generic button rule but nothing else, so it measured
   `padding: 1px 6px` — the browser's default for a bare `<button>` — and came
   out 111px wide and about as tall as a line of text. The single most
   important control on the site was the smallest thing on the page. */
body.woocommerce-checkout #place_order {
	border: 1px solid var(--kc-line-brand);
	font-size: 0.95rem;
	font-weight: 600;
	letter-spacing: 0.02em;
	min-height: 3rem;
	padding: 0.9em 2.2em;
	width: 100%;
}

body.woocommerce-checkout #place_order:hover {
	box-shadow: var(--kc-glow-brand);
	transform: translateY(-1px);
}

/* The order-note warning is inline-styled `#856404` — an amber that measures
   badly on the dark page. Inline beats any selector, so this needs the flag. */
body.woocommerce-checkout .woocommerce-additional-fields p[style*="856404"],
body.woocommerce-checkout p[style*="856404"] {
	color: var(--kc-amber-pale, #fff4e5) !important;
	font-size: 0.86rem !important;
	line-height: 1.6 !important;
}

/* The category description is prose and takes the prose contract. */
body .woocommerce-term-description,
body .woocommerce-product-details__short-description {
	color: var(--kc-text-muted);
	font-size: 1.02rem;
	line-height: 1.78;
}

/* The paragraph carries its own 20px/36px, so setting the container alone left
   the size untouched — the measure applied and the type did not. */
body .woocommerce-term-description p {
	color: var(--kc-text-muted);
	font-size: 1.02rem;
	line-height: 1.78;
	max-width: 68ch;
}

/* Pagination: the current page was white-on-black-text. See the note above. */
body .wp-block-query-pagination .page-numbers,
body .wp-block-query-pagination .wp-block-query-pagination-next,
body .wp-block-query-pagination .wp-block-query-pagination-previous {
	border-radius: var(--kc-radius-pill);
}

body .wp-block-query-pagination .page-numbers.current {
	background-color: var(--kc-wash-brand);
	border: 1px solid var(--kc-line-brand);
	border-radius: var(--kc-radius-pill);
	color: var(--kc-purple-soft) !important;
}

/* Product archive and single product — the gaps after the block migration
   ==========================================================================
   Audited 2026-08-16. Neither page shows a product to a signed-out visitor —
   the archive renders its chrome with an empty loop and the single product
   renders its content at 0x0 — because the whole catalogue is behind the B2B
   gate. Both were read as their real signed-in markup, fetched with a
   short-lived server-side session, and the class names below are copied from
   that rather than assumed.

   THE ARCHIVE IS BLOCK-BASED, not the classic loop. It is
   `woocommerce/product-collection`: `li.wc-block-product` inside
   `ul.wc-block-product-template`, with `.wp-block-post-title` where
   `.woocommerce-loop-product__title` used to be and
   `.wp-block-woocommerce-product-price` where `.price` used to be. The card
   lift, the 1.045 media scale and the title colour already had block-aware
   selectors from earlier work; these are the two things that did not.

   One alarm that turned out to be nothing, recorded so it is not re-raised:
   the archive button carries `has-theme-2-background-color`, and theme-2 is
   now `#8958FE`, which would be 4.22:1 under white text and would fail. It
   does NOT apply — the button rule above paints a
   `purple-strong -> purple-deep` gradient through the `background` shorthand
   with `!important`, measuring 7.63:1 at the light end. Reading
   `backgroundColor` on it returns `rgba(0,0,0,0)` because the shorthand resets
   the colour and puts the gradient in `background-image`; measure
   `backgroundImage` or the conclusion inverts.
   ========================================================================== */

/* The card's title is white; its link was inheriting the site purple, so the
   heading read as a link rather than as a card title. Research-card manners:
   white, purple underline on hover. */
.wc-block-product-template li .wp-block-post-title a,
.woocommerce ul.products li.product .woocommerce-loop-product__title a {
	color: var(--kc-white);
	text-decoration: none;
}

.wc-block-product-template li .wp-block-post-title a:hover,
.woocommerce ul.products li.product .woocommerce-loop-product__title a:hover {
	color: var(--kc-white);
	text-decoration: underline;
	text-decoration-color: var(--kc-purple);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.22em;
}

/* Price: purple, as it is in the cart, the mini-cart and the carousel. The
   block price is its own element and never matched the `.price` rule. */
.wc-block-product-template li .wp-block-woocommerce-product-price,
.wc-block-product-template li .wp-block-woocommerce-product-price .woocommerce-Price-amount,
.wc-block-product-template li .wc-block-components-product-price {
	color: var(--kc-purple);
	font-weight: 600;
}

/* The single product's attributes table — Weight, Form and so on. It had NO
   rule in this file, so it fell to the Customizer's bare
   `td, th { border: 1px solid rgb(160,160,160) }` and rendered as a grey grid.
   Same card as the cart and account tables, but the `th` here is a row LABEL
   rather than a column header, so it stays dim prose rather than taking the
   uppercase eyebrow. */
body.single-product .woocommerce table.shop_attributes,
body.single-product table.woocommerce-product-attributes {
	border: 1px solid var(--kc-line);
	border-collapse: separate;
	border-radius: var(--kc-radius-lg);
	border-spacing: 0;
	overflow: hidden;
	width: 100%;
}

body.single-product .woocommerce table.shop_attributes th,
body.single-product table.woocommerce-product-attributes th {
	background-color: rgba(255, 255, 255, 0.03);
	border: 0;
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-text-dim);
	font-size: 0.86rem;
	font-style: normal;
	font-weight: 500;
	padding: 12px 16px;
	text-align: left;
	width: 34%;
}

body.single-product .woocommerce table.shop_attributes td,
body.single-product table.woocommerce-product-attributes td {
	border: 0;
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-text);
	font-style: normal;
	padding: 12px 16px;
}

body.single-product .woocommerce table.shop_attributes tr:last-child th,
body.single-product .woocommerce table.shop_attributes tr:last-child td,
body.single-product table.woocommerce-product-attributes tr:last-child th,
body.single-product table.woocommerce-product-attributes tr:last-child td {
	border-bottom: 0;
}

/* Cart page — the controls the shared table rules do not reach
   ==========================================================================
   Audited 2026-08-16. The cart cannot be populated from a signed-out session
   — adding to cart returns "Sorry, this product cannot be purchased", which is
   the B2B gate working — so the table was rebuilt from WooCommerce's own
   markup in the live page and read back, the same method used for the account
   dashboard and the FAQ accordion.

   The shop_table card, eyebrow header and hairline rows are shared with My
   Account: that selector now reads
   `:is(body.woocommerce-account, body.woocommerce-cart)`. **Checkout is
   deliberately excluded.** Its review table is recorded in HANDOFF.md as
   having "no slack" at 345px, and these rules change cell padding, so it wants
   the iframe measurement rather than being swept in here.

   What the shared rules do NOT cover, measured on the rebuilt cart:

     input.qty       `2px inset rgb(118,118,118)` — the raw browser default,
                     white on black, nothing styling it at all
     #coupon_code    white with a #cfc8d8 border; the --wc-form-* variables set
                     earlier do not reach it because WooCommerce styles the
                     coupon field on its own id rather than through .form-row
     a.remove        `rgb(170,0,0)` — --wc-red again, at ~2.2:1 on the page.
                     Left red-ish ON HOVER only: removing a line item is the
                     one destructive control here, the same call already made
                     for the mini-cart bin and validation errors.
     prices          plain white; purple everywhere else on the site
   ========================================================================== */

body.woocommerce-cart .woocommerce td.product-price .amount,
body.woocommerce-cart .woocommerce td.product-subtotal .amount,
body.woocommerce-cart .woocommerce .cart_totals .amount {
	color: var(--kc-purple);
	font-weight: 600;
}

body.woocommerce-cart .woocommerce td.product-name a {
	color: var(--kc-white);
}

body.woocommerce-cart .woocommerce td.product-name a:hover {
	color: var(--kc-purple-soft);
}

body.woocommerce-cart .woocommerce td.product-thumbnail img {
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-sm);
}

/* The quantity stepper and the coupon field. The quantity selector is shared
   with the single product, where the identical control was still the raw
   browser default because this rule was originally cart-only. */
:is(body.woocommerce-cart, body.single-product) .woocommerce .quantity input.qty,
body.woocommerce-cart .woocommerce #coupon_code.input-text,
body.woocommerce-cart .woocommerce input#coupon_code {
	background-color: rgba(255, 255, 255, 0.04);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius);
	color: var(--kc-text);
	font-family: inherit;
	padding: 0.6em 0.8em;
}

:is(body.woocommerce-cart, body.single-product) .woocommerce .quantity input.qty:focus,
body.woocommerce-cart .woocommerce input#coupon_code:focus {
	border-color: var(--kc-purple);
	box-shadow: 0 0 0 3px var(--kc-wash-brand);
	outline: none;
}

body.woocommerce-cart .woocommerce input#coupon_code::placeholder {
	color: var(--kc-text-dim);
	opacity: 1;
}

/* Real minus/plus controls — the follow-through on the note at line 1707
   ==========================================================================
   That note recorded the honest limit: `<input type="number">` draws its own
   arrows, CSS can only reach the spin-button pseudo-elements, and inverting
   them was a stopgap. `assets/js/kimera-quantity-stepper.js` now wraps the
   field with two real buttons.

   EVERYTHING HERE IS GATED ON `[data-kc-stepper]`, the attribute the script
   sets once it has actually enhanced a field. Without that gate a visitor with
   JavaScript off would get a field whose native arrows had been hidden by CSS
   and no buttons to replace them, leaving no way to change quantity at all.
   The gate means the stopgap inversion above stays in force whenever the
   script has not run.
   ========================================================================== */

.quantity[data-kc-stepper] {
	align-items: stretch;
	display: inline-flex;
	gap: 0;
}

/* Now that there are real controls, the browser's arrows are duplication. */
.quantity[data-kc-stepper] input[type="number"]::-webkit-inner-spin-button,
.quantity[data-kc-stepper] input[type="number"]::-webkit-outer-spin-button {
	appearance: none;
	-webkit-appearance: none;
	margin: 0;
}

.quantity[data-kc-stepper] input[type="number"] {
	-moz-appearance: textfield;
	appearance: textfield;
	border-radius: 0;
	text-align: center;
	width: 3.5em;
}

.kc-qty__button {
	background-color: rgba(255, 255, 255, 0.04);
	border: 1px solid var(--kc-line);
	color: var(--kc-text);
	cursor: pointer;
	font-family: inherit;
	font-size: 1rem;
	line-height: 1;
	min-width: 2.4em;
	padding: 0.6em 0.7em;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease);
	user-select: none;
}

/* The three controls read as one object, so only the outer corners round. */
.kc-qty__button--minus {
	border-radius: var(--kc-radius) 0 0 var(--kc-radius);
	border-right-width: 0;
}

.kc-qty__button--plus {
	border-left-width: 0;
	border-radius: 0 var(--kc-radius) var(--kc-radius) 0;
}

.kc-qty__button:hover:not(:disabled) {
	background-color: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
	color: var(--kc-white);
}

.kc-qty__button:focus-visible {
	border-color: var(--kc-purple);
	box-shadow: 0 0 0 3px var(--kc-wash-brand);
	outline: none;
	position: relative;
}

/* At the end of the range: dimmed, but still visible, so the limit reads as a
   limit rather than as a control that vanished. */
.kc-qty__button:disabled {
	cursor: not-allowed;
	opacity: 0.4;
}

/* Remove: quiet until you reach for it.
   `!important` because WooCommerce ships `.woocommerce a.remove { color:
   var(--wc-red) !important }`, and an !important is only beaten by another —
   a first pass at (0,3,2) against its (0,2,1) lost, and the × stayed #a00 at
   2.71:1. `--wc-red` itself is left defined, since it still paints genuine
   validation errors. */
body.woocommerce-cart .woocommerce a.remove {
	color: var(--kc-text-dim) !important;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease);
}

body.woocommerce-cart .woocommerce a.remove:hover {
	background-color: rgba(255, 107, 107, 0.12);
	color: #ff6b6b !important;
}

/* Totals panel becomes a card of its own, beside the line items. */
body.woocommerce-cart .woocommerce .cart_totals h2 {
	color: var(--kc-purple);
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

body.woocommerce-cart .woocommerce .cart_totals table.shop_table th {
	background-color: transparent;
	color: var(--kc-text-dim);
	font-size: 0.86rem;
	letter-spacing: normal;
	text-transform: none;
}

body.woocommerce-cart .woocommerce .cart_totals tr.order-total th,
body.woocommerce-cart .woocommerce .cart_totals tr.order-total td {
	color: var(--kc-white);
	font-size: 1rem;
}

/* Mobile drawer and mini-cart — the last two white panels
   ==========================================================================
   Both measured 2026-08-16 with the drawer forced open at 375px, because
   neither renders until it is opened.

     .gutenverse-menu-wrapper   background rgb(255,255,255) — a WHITE drawer on
                                a near-black site, with its menu items in
                                --kc-purple, which is 4.29:1 on white. The
                                token notes at the top of this file record that
                                exact number as failing and mark --kc-purple
                                dark-only, so the drawer was shipping the one
                                combination the palette forbids.
     .ue-mini-cart              background white AND color white — the panel
                                was white text on a white box, the same defect
                                the FiboSearch dropdown had.

   Taking both surfaces to ink fixes the contrast rather than re-picking a
   purple: on --kc-ink-800 the same --kc-purple is 4.69:1 and passes, and the
   white text becomes legible with no colour change at all.

   The drawer logo could not be fixed here — it was swapped to a BLACK lockup
   earlier *because* the drawer was white, so reversing the surface reverses
   the mark. That is a block attribute and is handled by
   bin/fix_header_dark_drawer.py, along with the mini-cart title colour.

   The identity panel gets a hairline and real padding: it measured 340x68 with
   `padding: 10px 0`, so the logo and close button sat on the panel edge with
   nothing separating them from the menu beneath.
   ========================================================================== */

/* The drawer SURFACE and the menu text are not here — Gutenverse paints both
   from an ID selector (`#guten-yHBZb5…`), which no class rule beats, so they
   are block attributes handled by bin/fix_drawer_dark_attrs.py. Only what
   Gutenverse styles by class is winnable here, and this selector matches its
   own chain plus `body` to clear (0,4,0). */
body .guten-nav-menu.break-point-tablet .gutenverse-menu-wrapper .gutenverse-nav-identity-panel {
	align-items: center;
	border-bottom: 1px solid var(--kc-line);
	display: flex;
	justify-content: space-between;
	padding: 12px 16px;
}

body .gutenverse-nav-identity-panel .gutenverse-nav-logo img {
	display: block;
	height: auto;
	max-width: 100%;
}

body .gutenverse-menu-wrapper .gutenverse-menu > li > a {
	color: var(--kc-text);
}

body .gutenverse-menu-wrapper .gutenverse-menu > li.current-menu-item > a {
	color: var(--kc-purple-soft);
}

/* Mini-cart ------------------------------------------------------------------ */

/* Unlimited Elements scopes the panel with
   `.ue-widget-root.uc_woo_mini_cart_ax_elementorNNNNN-root .ue-mini-cart`,
   where NNNNN is a per-instance number — 12769, 16102 and 17570 have all been
   seen on this site, so the class cannot be written out literally. The
   attribute-substring match gives the same (0,3,x) weight without pinning a
   number that changes whenever the widget is rebuilt. A plain
   `body .ue-mini-cart` lost, and because the panel's own colour came from a
   lighter rule, it took the text and left the background — white on white. */
body .ue-widget-root[class*="uc_woo_mini_cart"] .ue-mini-cart,
body .ue-mini-cart {
	background-color: var(--kc-ink-800);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-lg);
	color: var(--kc-text);
	overflow: hidden;
}

body .ue-mini-cart .ue_cart_header {
	border-bottom: 1px solid var(--kc-line);
}

body .ue-mini-cart .ue-mini-cart-item {
	border-bottom: 1px solid var(--kc-line);
}

body .ue-mini-cart .ue-mini-cart-item-image {
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-sm);
}

body .ue-mini-cart .ue-mini-cart-item-title-text {
	color: var(--kc-white);
	transition: color var(--kc-duration) var(--kc-ease);
}

body .ue-mini-cart .ue-mini-cart-item-title-text:hover {
	color: var(--kc-purple-soft);
}

body .ue-mini-cart .ue_mini_qty,
body .ue-mini-cart .ue-mini-cart-subtotal,
body .ue-mini-cart .ue-mini-cart-empty-message p {
	color: var(--kc-text-dim);
}

body .ue-mini-cart .ue_mini_price,
body .ue-mini-cart .ue_subtotal_amount,
body .ue-mini-cart .woocommerce-Price-amount {
	color: var(--kc-purple);
}

/* The quantity stepper: three separate controls, all of them unstyled. */
body .ue-mini-cart .ue_mini_quantity_input {
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-pill);
	overflow: hidden;
}

body .ue-mini-cart .ue_mini_input {
	background-color: transparent;
	border: 0;
	color: var(--kc-text);
}

body .ue-mini-cart .ue_mini_minus,
body .ue-mini-cart .ue_mini_plus,
body .ue-mini-cart .ue-mini-cart-item-delete,
body .ue-mini-cart .ue_cart_close_button {
	color: var(--kc-text-dim);
	cursor: pointer;
	transition: color var(--kc-duration) var(--kc-ease);
}

body .ue-mini-cart .ue_mini_minus:hover,
body .ue-mini-cart .ue_mini_plus:hover,
body .ue-mini-cart .ue_cart_close_button:hover {
	color: var(--kc-purple-soft);
}

/* Delete is the one destructive control here, so it keeps a warning tone
   rather than joining the purple — the same call made for validation errors. */
body .ue-mini-cart .ue-mini-cart-item-delete:hover {
	color: #ff6b6b;
}

/* Header controls — a two-tier button system, library manners
   ==========================================================================
   Measured 2026-08-16. The mini-cart's two actions were **identical**: both
   flat `#562BDA` at 5px radius, so "View Cart" and "Go to Checkout" carried
   the same weight and the panel had no primary action. The library's own hero
   already answers this — a solid button beside an outline one — so the same
   two tiers apply here:

     Go to Checkout   primary: the purple gradient pill used by add-to-cart
     View Cart        secondary: ghost pill, hairline border, wash on hover

   Also fixed, all measured rather than guessed:
     .ue_cart_close_button   a WHITE circle on the dark panel
     .ue-product-count       #e8b5ff lilac at 4px radius; now a brand pill
     .ue_mini_cart_toggle    no hit area at all
     hamburger               25px/40px padding and no hover affordance
     search svg              `fill` computing to BLACK; it now takes
                             currentColor so it follows the link colour it
                             sits in, instead of being painted separately

   The per-instance root class (`uc_woo_mini_cart_ax_elementorNNNNN-root`,
   seen as 12769 / 16102 / 17570 / 18882) is matched on a substring, never
   written out — it changes whenever the widget is rebuilt.
   ========================================================================== */

body .ue-mini-cart .ue-mini-cart-viewcart-btn,
body .ue-mini-cart .ue-mini-cart-checkout-btn,
body .ue-widget-root[class*="uc_woo_mini_cart"] .ue-mini-cart-viewcart-btn,
body .ue-widget-root[class*="uc_woo_mini_cart"] .ue-mini-cart-checkout-btn {
	border: 1px solid transparent;
	border-radius: var(--kc-radius-pill) !important;
	font-weight: 600;
	letter-spacing: 0.02em;
	text-align: center;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration-fast) var(--kc-ease);
}

/* Primary. */
body .ue-widget-root[class*="uc_woo_mini_cart"] .ue-mini-cart-checkout-btn {
	background: linear-gradient(135deg, var(--kc-purple-strong), var(--kc-purple-deep)) !important;
	border-color: var(--kc-line-brand);
	color: var(--kc-white) !important;
}

body .ue-widget-root[class*="uc_woo_mini_cart"] .ue-mini-cart-checkout-btn:hover {
	box-shadow: var(--kc-glow-brand);
	transform: translateY(-1px);
}

/* Secondary: ghost, so the primary reads as the primary. */
body .ue-widget-root[class*="uc_woo_mini_cart"] .ue-mini-cart-viewcart-btn {
	background: transparent !important;
	border-color: var(--kc-line-strong);
	color: var(--kc-text) !important;
}

body .ue-widget-root[class*="uc_woo_mini_cart"] .ue-mini-cart-viewcart-btn:hover {
	background: var(--kc-wash-brand) !important;
	border-color: var(--kc-line-brand);
	color: var(--kc-white) !important;
	transform: translateY(-1px);
}

/* The cart toggle gets a real hit area and a hover, like a pill. */
body .ue-widget-root[class*="uc_woo_mini_cart"] .ue_mini_cart_toggle {
	border: 1px solid transparent;
	border-radius: var(--kc-radius-pill);
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease);
}

body .ue-widget-root[class*="uc_woo_mini_cart"] .ue_mini_cart_toggle:hover {
	background-color: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
}

/* The count badge: a pill in brand colours, not lilac at 4px.
   INVERTED deliberately — soft ground, ink text. This file's own header notes
   already worked it out: "--kc-purple-soft ground with --kc-purple-ink text is
   10.42:1". A first pass here used the base purple as the ground and measured
   4.40:1, marginally under AA, which is the trap those notes exist to prevent.
   It also stays lighter than everything around it, so it still pops. */
body .ue-widget-root[class*="uc_woo_mini_cart"] .ue-product-count {
	background-color: var(--kc-purple-soft) !important;
	border-radius: var(--kc-radius-pill) !important;
	color: var(--kc-purple-ink) !important;
	font-size: 0.72rem;
	font-weight: 700;
	line-height: 1;
	min-width: 20px;
	padding: 3px 6px;
	text-align: center;
}

/* Kill the white circle. */
body .ue-widget-root[class*="uc_woo_mini_cart"] .ue_cart_close_button {
	background-color: transparent !important;
	border-radius: var(--kc-radius-pill);
	color: var(--kc-text-dim);
	height: 30px;
	line-height: 30px;
	text-align: center;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		color var(--kc-duration) var(--kc-ease);
	width: 30px;
}

body .ue-widget-root[class*="uc_woo_mini_cart"] .ue_cart_close_button:hover {
	background-color: var(--kc-wash-brand);
	color: var(--kc-purple-soft);
}

/* Nav controls ---------------------------------------------------------------- */

body .guten-u1u02U .gutenverse-hamburger-menu {
	border: 1px solid transparent;
	border-radius: var(--kc-radius-pill);
	padding: 10px 12px !important;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease);
}

body .guten-u1u02U .gutenverse-hamburger-menu:hover {
	background-color: var(--kc-wash-brand);
	border-color: var(--kc-line-brand);
}

/* The Catalog chevron follows its link and turns with the panel. */
body .guten-u1u02U .gutenverse-menu > li > a > i {
	transition: transform var(--kc-duration) var(--kc-ease);
}

body .guten-u1u02U .gutenverse-menu > li:hover > a > i {
	transform: rotate(180deg);
}

/* Search glyphs inherit the colour of whatever they sit in, rather than
   defaulting to SVG's black fill. */
body .dgwt-wcas-ico-magnifier,
body .dgwt-wcas-ico-magnifier-handler,
body .dgwt-wcas-search-icon svg {
	fill: currentColor;
}

@media (prefers-reduced-motion: reduce) {
	body .ue-mini-cart .ue-mini-cart-viewcart-btn:hover,
	body .ue-mini-cart .ue-mini-cart-checkout-btn:hover {
		transform: none;
	}
}

/* Search — both search UIs, onto the library
   ==========================================================================
   Two separate search interfaces ship on this site and neither had been
   touched. Measured 2026-08-16 with the overlay open on `/?s=gw-501516`:

     Jetpack Instant Search   white panel, #0a112d navy text, results with no
                              card at all (transparent, no border, no radius,
                              no padding), and `mark` highlights in #FFC
                              YELLOW on black text
     FiboSearch               white input, black text, #ddd border, 3px radius,
                              Arial, and a #333 submit

   Both are stock light-theme defaults sitting on a near-black site, which is
   why they read as another design.

   Jetpack ships an `--overlay--light` modifier and its own palette, so this
   restates the surfaces rather than nudging them. The result rows become the
   research card — ink gradient, hairline, 18px radius, lift and brand glow on
   hover — because a search result IS a card in the library's language.

   THE YELLOW MARK NEEDS THE LONG SELECTOR. Jetpack injects an inline `<style>`
   INSIDE the overlay at runtime, carrying
   `.jetpack-instant-search .jetpack-instant-search__search-results
    .jetpack-instant-search__search-results-primary
    .jetpack-instant-search__search-result mark` — four classes and an element,
   and it lands in the DOM after this file. Matching it and adding `body` is
   what wins; anything shorter loses and the highlight stays yellow.

   `accent-color` handles the filter checkboxes in one line rather than
   rebuilding them out of pseudo-elements.
   ========================================================================== */

/* Jetpack Instant Search — the overlay ---------------------------------------- */

body .jetpack-instant-search__overlay {
	background-color: rgba(7, 7, 10, 0.82);
}

body .jetpack-instant-search .jetpack-instant-search__search-results {
	background-color: var(--kc-ink-900);
	color: var(--kc-text);
}

body .jetpack-instant-search .jetpack-instant-search__box-input,
body .jetpack-instant-search .jetpack-instant-search__search-sort-select {
	background-color: rgba(255, 255, 255, 0.04);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius);
	color: var(--kc-text);
	font-family: inherit;
}

body .jetpack-instant-search .jetpack-instant-search__box-input:focus,
body .jetpack-instant-search .jetpack-instant-search__search-sort-select:focus {
	border-color: var(--kc-purple);
	box-shadow: 0 0 0 3px var(--kc-wash-brand);
	outline: none;
}

body .jetpack-instant-search .jetpack-instant-search__box-gridicon svg,
body .jetpack-instant-search .jetpack-instant-search__overlay-close {
	color: var(--kc-text);
	fill: currentColor;
	transition: color var(--kc-duration) var(--kc-ease);
}

body .jetpack-instant-search .jetpack-instant-search__overlay-close:hover {
	color: var(--kc-purple-soft);
}

/* A result row is a research card. */
body .jetpack-instant-search .jetpack-instant-search__search-result {
	background: linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-800));
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-lg);
	margin-bottom: var(--kc-space-3, 12px);
	overflow: hidden;
	padding: 18px 20px;
	transition:
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration) var(--kc-ease);
}

body .jetpack-instant-search .jetpack-instant-search__search-result:hover,
body .jetpack-instant-search .jetpack-instant-search__search-result:focus-within {
	border-color: var(--kc-line-brand);
	box-shadow: var(--kc-glow-brand);
	transform: translateY(-3px);
}

body .jetpack-instant-search .jetpack-instant-search__search-result-title-link {
	color: var(--kc-white);
}

body .jetpack-instant-search .jetpack-instant-search__search-result-title-link:hover {
	color: var(--kc-white);
	text-decoration: underline;
	text-decoration-color: var(--kc-purple);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.22em;
}

body .jetpack-instant-search .jetpack-instant-search__product-price,
body .jetpack-instant-search .jetpack-instant-search__product-price .amount {
	color: var(--kc-purple);
	font-family: inherit;
	font-weight: 600;
}

body .jetpack-instant-search .jetpack-instant-search__search-results-title,
body .jetpack-instant-search .jetpack-instant-search__search-filters-title {
	color: var(--kc-white);
}

/* Filter headings take the library's eyebrow. */
body .jetpack-instant-search .jetpack-instant-search__search-filter-sub-heading {
	color: var(--kc-purple);
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

body .jetpack-instant-search .jetpack-instant-search__search-filter-list-label,
body .jetpack-instant-search .jetpack-instant-search__search-results-filter-button,
body .jetpack-instant-search .jetpack-instant-search__search-sort label {
	color: var(--kc-text-dim);
}

body .jetpack-instant-search .jetpack-instant-search__search-filter-list-input {
	accent-color: var(--kc-purple);
}

/* The colophon bar keeps its own white ground, so dimming only the text put
   #d8d5df on white — 1.45:1, caught on all four policy pages by the contrast
   sweep. The bar goes dark with the rest of the overlay instead. */
body .jetpack-instant-search .jetpack-instant-search__jetpack-colophon {
	background-color: var(--kc-ink-900);
	border-top: 1px solid var(--kc-line);
}

/* The link WRAPPER carries its own #0a112d navy, so colouring only the inner
   span left the anchor at 1.08:1 on the new dark bar. Both are set. */
body .jetpack-instant-search .jetpack-instant-search__jetpack-colophon-link,
body .jetpack-instant-search .jetpack-instant-search__jetpack-colophon-text {
	color: var(--kc-text-muted);
	opacity: 0.75;
}

/* The yellow highlight. Long selector deliberately — see the note above. */
body .jetpack-instant-search .jetpack-instant-search__search-results .jetpack-instant-search__search-results-primary .jetpack-instant-search__search-result mark,
body .jetpack-instant-search mark {
	background-color: var(--kc-wash-brand);
	border-radius: 3px;
	color: var(--kc-purple-soft);
	padding: 0 2px;
}

/* FiboSearch — the header product search ------------------------------------- */

/* The attribute selector is deliberate and load-bearing. FiboSearch paints the
   field with `.dgwt-wcas-sf-wrapp input[type="search"].dgwt-wcas-search-input`
   at (0,3,1). A first pass used `.dgwt-wcas-search-form .dgwt-wcas-search-input`
   at (0,2,1), which lost the background but WON the colour, because the
   plugin sets those in two rules of different weight — so the field went white
   text on a white box for one deploy. Matching their shape and adding `body`
   takes this to (0,3,2) and both land together. */
/* OPAQUE, not translucent, and that is the fix rather than a preference.
   A `rgba(255,255,255,0.04)` field takes the colour of whatever sits behind
   it. The search form is the one field on the site that FLOATS — FiboSearch
   slides it out of the header and can render it over the page, an overlay bar
   or a mobile panel — so on a light surface the 4 % wash became near-white and
   the near-white text typed into it disappeared. Reported as "you can't read
   what's typed because the background is too light".
   An opaque ink ground cannot be affected by what it lands on. Fields that
   live inside a known dark panel (account, cart) keep the translucent wash. */
body .dgwt-wcas-sf-wrapp input[type="search"].dgwt-wcas-search-input {
	background-color: var(--kc-ink-700);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-pill);
	color: var(--kc-text);
	font-family: inherit;
	padding-left: 1.1em;
	transition:
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease);
}

body .dgwt-wcas-sf-wrapp input[type="search"].dgwt-wcas-search-input::placeholder {
	color: var(--kc-text-dim);
	opacity: 1;
}

/* THE FOCUS STATE MUST REPAINT THE GROUND, and leaving it out is what brought
   the white-on-white field back after the rule above was thought to have fixed
   it. FiboSearch carries a SECOND ground declaration,
   `.dgwt-wcas-sf-wrapp input[type="search"].dgwt-wcas-search-input:focus
   { background: #fff }` at (0,4,1). The rule above is only (0,3,2), so it
   never reaches the focus state: the moment the field is focused the plugin
   repaints it white, while `color: var(--kc-text)` from the base rule stays
   near-white. The field is therefore readable until you click into it and
   unreadable exactly while you type, which is the only time it matters.

   So this restates BOTH the ground and the ink rather than only the trim.
   Reported from a screenshot of the header dropdown mid-search. Same lesson as
   the comment above, one state further in: with this plugin, find every rule
   that paints, not the first one. */
body .dgwt-wcas-sf-wrapp input[type="search"].dgwt-wcas-search-input:focus {
	background-color: var(--kc-ink-700);
	border-color: var(--kc-purple);
	box-shadow: 0 0 0 3px var(--kc-wash-brand);
	color: var(--kc-text);
	outline: none;
}

/* Age gate — the first page anyone sees
   ==========================================================================
   It is not an overlay. The plugin renders its own full page, so this is the
   first and sometimes only impression of the site, and it was the last thing
   still wearing the old design.

   Measured before changing, at 1280px:
     ground        white, from `div.age-gate`, against a site that is dark
                   everywhere else
     headline      #562BDA Michroma 24px — the legacy print purple, not the
                   #8958fe this theme uses
     body copy     black on white, a 189px block of compliance text set to
                   the full 630px
     both buttons  identical #562BDA, Arial 16px, 20px radius

   THE TWO BUTTONS ARE THE REAL PROBLEM. "I am 21+ and agree" and "I do not
   agree, Leave" measured identical: same ground, same ink, same 7.63:1. The
   panel gave leaving exactly the weight of entering. That is the same fault
   item 32 records for the mini-cart, where View Cart and Go to Checkout were
   both flat #562BDA, and it takes the same fix: the primary becomes the
   gradient pill this file already uses for add-to-cart, the other becomes a
   ghost.

   The headline takes `--kc-purple-soft` rather than `--kc-purple`. The token
   notes at the top of this file record why: the base purple as INK on a dark
   ground lands near 4.4:1, which is under AA for anything that is not large
   text. The soft tint is the tone this file already uses when purple has to
   be read rather than painted, as with the WooCommerce required asterisk.

   NOT FIXABLE FROM HERE: the logo is `email-logo.png`, the legacy mark. CSS
   can size it but cannot swap the file; that is a plugin setting.
   ========================================================================== */

body .age-gate {
	background-color: var(--kc-ink-900);
	color: var(--kc-text);
}

body .age-gate__background {
	background-color: var(--kc-black);
}

/* The card, so the gate reads as a panel rather than a bare page. */
body .age-gate__form {
	background-color: var(--kc-ink-800);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-lg);
	box-shadow: var(--kc-shadow-lg);
	color: var(--kc-text);
	padding: var(--kc-space-7, 32px);
}

body .age-gate__headline {
	color: var(--kc-purple-soft);
	font-family: var(--wp--preset--font-family--michroma, "Michroma", sans-serif);
	letter-spacing: 0.02em;
}

/* The compliance paragraph is the longest text on the page and was running the
   full width of the card. It takes the prose contract like every other block
   of reading on the site. */
body .age-gate__subheadline {
	color: var(--kc-text-muted);
	font-size: 1.02rem;
	line-height: 1.78;
	margin-left: auto;
	margin-right: auto;
	max-width: 68ch;
}

body .age-gate__buttons {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	justify-content: center;
}

body .age-gate__submit {
	border: 1px solid transparent;
	border-radius: var(--kc-radius-pill);
	font-family: var(--wp--preset--font-family--michroma, "Michroma", sans-serif);
	font-size: 0.82rem;
	font-weight: 600;
	letter-spacing: 0.04em;
	padding: 14px 28px;
	transition:
		background-color var(--kc-duration) var(--kc-ease),
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration-fast) var(--kc-ease);
}

/* THE BACKGROUNDS NEED THE FLAG, the rest does not. The plugin emits its
   admin colour setting as an inline rule,
   `button.age-gate-button, button.age-gate-submit-no, button.age-gate-submit-yes
   { background: rgb(86,43,218) !important }`, so no selector wins this on
   specificity. Sixth `!important` fight in this file.

   A first pass without the flag was a worked example of why the ghost matters:
   the gradient still PAINTED on the primary, because a background-image sits
   above a background-colour, so that button looked correct. The secondary
   went on rendering solid purple, and the two stayed identical, which was the
   whole fault being fixed. Only font and colour are left unflagged, because
   the plugin does not set those. */

/* Primary: entering. Same gradient pill as add-to-cart and checkout. */
body .age-gate__submit--yes {
	background: linear-gradient(135deg, var(--kc-purple-strong), var(--kc-purple-deep)) !important;
	border-color: var(--kc-line-brand);
	color: var(--kc-white);
}

body .age-gate__submit--yes:hover {
	box-shadow: var(--kc-glow-brand);
	transform: translateY(-1px);
}

/* Secondary: leaving. A ghost, so the two stop competing. Deliberately still
   legible and still easy to hit — this is a compliance choice, not a dark
   pattern, and it must stay obvious that leaving is available. */
body .age-gate__submit--no {
	background: transparent !important;
	border-color: var(--kc-line-strong);
	color: var(--kc-text);
}

body .age-gate__submit--no:hover {
	background: var(--kc-wash-brand) !important;
	border-color: var(--kc-line-brand);
	color: var(--kc-white);
	transform: translateY(-1px);
}

body .age-gate__errors,
body .age-gate__error {
	color: var(--kc-purple-soft);
}

body .dgwt-wcas-search-form .dgwt-wcas-search-submit {
	background-color: var(--kc-purple-strong);
	border-radius: 0 var(--kc-radius-pill) var(--kc-radius-pill) 0;
	color: var(--kc-white);
	transition: background-color var(--kc-duration) var(--kc-ease);
}

body .dgwt-wcas-search-form .dgwt-wcas-search-submit:hover {
	background-color: var(--kc-purple);
}

body .dgwt-wcas-search-form .dgwt-wcas-search-submit svg {
	fill: currentColor;
}

/* The suggestions dropdown, which measured white-on-white. */
body .dgwt-wcas-suggestions-wrapp {
	background-color: var(--kc-ink-800);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius);
	color: var(--kc-text);
	overflow: hidden;
}

body .dgwt-wcas-suggestions-wrapp .dgwt-wcas-suggestion {
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-text);
	transition: background-color var(--kc-duration-fast) var(--kc-ease);
}

body .dgwt-wcas-suggestions-wrapp .dgwt-wcas-suggestion:hover,
body .dgwt-wcas-suggestions-wrapp .dgwt-wcas-suggestion-selected {
	background-color: var(--kc-wash-brand);
}

body .dgwt-wcas-suggestions-wrapp .dgwt-wcas-st--title,
body .dgwt-wcas-suggestions-wrapp .dgwt-wcas-st-title {
	color: var(--kc-white);
}

body .dgwt-wcas-suggestions-wrapp .dgwt-wcas-sp,
body .dgwt-wcas-suggestions-wrapp .dgwt-wcas-st--price {
	color: var(--kc-purple);
}

@media (prefers-reduced-motion: reduce) {
	body .jetpack-instant-search .jetpack-instant-search__search-result:hover {
		transform: none;
	}
}

/* Header and footer chrome — the library's manners on the site furniture
   ==========================================================================
   Audited 2026-08-16 by walking every link and control in both parts and
   reading computed styles, not by looking at them.

   THE FOOTER WAS THE REAL FIND. Its 13 links had **no hover response at all**.
   Gutenverse colours them with
   `.guten-icon-list .list-wrapper .guten-icon-list-item a` at (0,3,1), and the
   site-wide `a:where(...):hover` sits at (0,1,1), so the hover lost outright
   and nothing moved on any of them. The `<a>` itself also computed
   `rgb(87,90,95)` — 3.03:1 on black, under the 4.5:1 minimum — though what a
   visitor actually sees is the white `span.list-text` inside it. Both are
   handled: the anchor gets a legible resting colour, and the hover targets the
   span, because colouring only the anchor would keep losing to it.

   The 3px slide is the footer's version of the library's arrow, which moves
   `translateX(4px)`; 3px reads right on a list item that carries no arrow.

   Header controls are additive only — opacity and transform, which Gutenverse
   and the cart/search plugins never set — so there is no cascade fight and no
   `!important`. The nav pills, band and hairline are handled further up.

   The focus ring is new and deliberate. Everything here had hover states and
   nothing had a visible keyboard state; the library's cards already answer to
   `:focus-within`, so this extends the same courtesy to every control.
   ========================================================================== */

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

body .guten-icon-list .list-wrapper .guten-icon-list-item a,
body .guten-icon-list .list-wrapper .guten-icon-list-item a .list-text {
	color: var(--kc-text);
	transition:
		color var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration) var(--kc-ease);
}

body .guten-icon-list .list-wrapper .guten-icon-list-item a:hover,
body .guten-icon-list .list-wrapper .guten-icon-list-item a:hover .list-text {
	color: var(--kc-purple-soft);
}

body .guten-icon-list .list-wrapper .guten-icon-list-item a:hover {
	transform: translateX(3px);
}

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

body .guten-u1u02U .dgwt-wcas-search-icon,
body .guten-u1u02U .ue-widget-root.minicart {
	transition:
		opacity var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration) var(--kc-ease);
}

body .guten-u1u02U .dgwt-wcas-search-icon:hover,
body .guten-u1u02U .ue-widget-root.minicart:hover {
	opacity: 0.82;
	transform: translateY(-1px);
}

/* Keyboard focus, site-wide -------------------------------------------------- */

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
.wp-element-button:focus-visible,
summary:focus-visible {
	outline: 2px solid var(--kc-purple);
	outline-offset: 3px;
}

/* The post-card category chip — and the reason the Poppins request could go.
   Gutenverse sets it in Poppins with NO fallback in the stack, so dequeuing
   that font without this would have dropped it to the browser's default
   serif. Inheriting instead keeps it in the site face, and the tracking gives
   it the library's eyebrow manner without touching the colour, which sits on
   a thumbnail overlay. */
body .guten-post-block .guten-postblock .guten-post-category a {
	font-family: inherit;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

@media (prefers-reduced-motion: reduce) {
	body .guten-icon-list .list-wrapper .guten-icon-list-item a:hover,
	body .guten-u1u02U .dgwt-wcas-search-icon:hover,
	body .guten-u1u02U .ue-widget-root.minicart:hover {
		transform: none;
	}
}

/* Carousel controls — the one interactive surface with no library manners
   ==========================================================================
   Audited 2026-08-16 against the research library's vocabulary. The carousel's
   product cards already behave: its wrapper carries `.woocommerce` and its
   items are `ul.products li.product`, so they inherit the card lift, the
   1.045 media scale and the title underline from the block above. Its own
   controls inherited nothing — the arrows and dots had colour and no manners.

   Additive properties only. The plugin writes the arrow and dot COLOURS from
   the block attributes as ID-scoped inline CSS, which no class selector here
   would beat; transform, box-shadow and transition are properties it never
   sets, so there is no cascade fight and no !important. Change the colours in
   the block attributes, not here.
   ========================================================================== */

.wpmozo-product-carousel-wrap .swiper-navigation {
	transition:
		transform var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease);
}

.wpmozo-product-carousel-wrap .swiper-navigation:hover {
	box-shadow: var(--kc-glow-brand);
	transform: scale(1.08);
}

.wpmozo-product-carousel-wrap .swiper-pagination-bullet {
	transition:
		opacity var(--kc-duration) var(--kc-ease),
		transform var(--kc-duration) var(--kc-ease);
}

.wpmozo-product-carousel-wrap .swiper-pagination-bullet:hover {
	opacity: 1;
	transform: scale(1.3);
}

@media (prefers-reduced-motion: reduce) {
	.wpmozo-product-carousel-wrap .swiper-navigation:hover,
	.wpmozo-product-carousel-wrap .swiper-pagination-bullet:hover {
		transform: none;
	}
}

/* Accordion — the FAQ, on the research library's card
   ==========================================================================
   The block carries no style attributes at all (`{"elementId":"guten-6XZSFw"}`
   and nothing else), so every pixel of it is a Gutenverse default: square
   corners, a flat `--guten-border-color` box per item, and a hairline under
   each heading that reads as a stray rule when the item is closed. That is the
   old design the FAQ was still wearing.

   Every selector here is prefixed with `body`. Gutenverse's stylesheet loads
   AFTER this one — measured in the served page, the order is global-styles,
   kimera-ui, research-library, gutenverse — so at equal specificity Gutenverse
   wins on source order. Its rules are `.guten-accordions .accordion-item` at
   (0,2,0); `body` takes these to (0,2,1) and no `!important` is needed.

   `--guten-border-color` is redefined on the wrapper rather than each border
   being restated, so the item box and the heading rule move together through
   the plugin's own variable.

   The divider sits on `.accordion-content`, not on `.accordion-heading` where
   Gutenverse puts it. The body is `height: 0; overflow: hidden` when closed, so
   a border on the content is invisible until the item opens — which is the
   behaviour wanted, and it costs no `.active` class we would have to guess at.
   ========================================================================== */

body .guten-accordions {
	--guten-border-color: rgba(255, 255, 255, 0.09);
	display: flex;
	flex-direction: column;
	gap: 12px;
}

body .guten-accordions .accordion-item {
	background: linear-gradient(180deg, var(--kc-ink-700), var(--kc-ink-800));
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-lg);
	overflow: hidden;
	transition:
		border-color var(--kc-duration) var(--kc-ease),
		box-shadow var(--kc-duration) var(--kc-ease);
}

body .guten-accordions .accordion-item:hover {
	border-color: var(--kc-line-brand);
}

body .guten-accordions .accordion-item .accordion-heading {
	border-bottom: 0;
	color: var(--kc-white);
	font-family: var(--wp--preset--font-family--michroma, "Michroma", sans-serif);
	font-size: 0.95rem;
	font-weight: 500;
	gap: 14px;
	line-height: 1.45;
	padding: 18px 22px;
}

body .guten-accordions .accordion-item .accordion-icon i {
	color: var(--kc-purple);
	font-size: 0.8rem;
	transition: color var(--kc-duration) var(--kc-ease);
}

body .guten-accordions .accordion-item:hover .accordion-icon i {
	color: var(--kc-purple-soft);
}

body .guten-accordions .accordion-item .accordion-content {
	border-top: 1px solid var(--kc-line);
	color: var(--kc-text-dim);
	margin: 0 22px;
	padding: 16px 0 20px;
}

body .guten-accordions .accordion-item .accordion-content p {
	color: var(--kc-text-dim);
	margin: 0;
}

/* WooCommerce forms and buttons — the last red-era controls
   ==========================================================================
   Reported from /my-account/ on 2026-08-16: white input boxes on a black
   page, and a submit button in dead grey. Measured before touching anything,
   which found the mechanism for both and meant neither needed !important.

   The inputs are WooCommerce's own, painted through its form variables:
   `background-color: var(--wc-form-color-background, #fff)`. The border was
   `rgba(32,7,7,0.8)` — WooCommerce's stock near-black red. So the fix is to
   define the variables rather than out-specify the selector, which is the
   mechanism WooCommerce provides and covers input, select and textarea at
   once.

   ONLY the three colour variables are set. `--wc-form-border-width` and
   `--wc-form-border-radius` are deliberately left alone so no box changes
   size: HANDOFF records the checkout review table at 345px having "no slack",
   and a colour-only change cannot cost it any.

   The grey button came from the parent theme.json via
   `:root :where(.wp-element-button, .wp-block-button__link)`. `:where()`
   contributes zero specificity, so that rule computes at (0,1,0) and a single
   class selector beats it outright — the same property PROGRESS.md records as
   a trap is what makes this cheap. Scoped to WooCommerce's own buttons rather
   than `.wp-element-button` site-wide, because core's outline button style is
   also low-specificity and a blanket fill would have turned the hero's COA
   Archive outline button into a solid purple slab.

   `a.button` is included unqualified. A first pass restricted it to `.alt` and
   to account pages, which left /cart/'s "Return to shop" still grey — measured,
   not assumed. WooCommerce's link-buttons are all primary actions here, and the
   ones already painted by the Customizer layer carry the same #562BDA, so this
   changes their colour nowhere and only fills the ones nothing had reached.
   ========================================================================== */

body.woocommerce,
body.woocommerce-page {
	--wc-form-color-background: rgba(255, 255, 255, 0.04);
	--wc-form-color-text: #f4f2f7;
	--wc-form-border-color: rgba(255, 255, 255, 0.09);
}

body.woocommerce input.input-text::placeholder,
body.woocommerce-page input.input-text::placeholder,
body.woocommerce textarea::placeholder,
body.woocommerce-page textarea::placeholder {
	color: var(--kc-text-dim);
	opacity: 1;
}

/* Primary actions take the same fill as the add-to-cart and place-order
   buttons, so every button that submits something is one colour. Geometry
   matches the hero buttons; the lift and shadow come from the shared button
   transition block further up. */
.woocommerce button.button,
.woocommerce input.button,
.woocommerce a.button,
.woocommerce #respond input#submit {
	background-color: var(--kc-purple-strong);
	border-radius: var(--kc-radius-pill);
	color: var(--kc-white);
}

.woocommerce button.button:hover,
.woocommerce input.button:hover,
.woocommerce a.button:hover,
.woocommerce #respond input#submit:hover {
	background-color: var(--kc-purple);
	color: var(--kc-white);
}

/* WooCommerce marks required fields with `var(--wc-red)`, which resolves to
   #a00 — 2.2:1 on the near-black page, so this is a contrast fix as much as a
   palette one.

   Two things were measured here. The selector is
   `.woocommerce form .form-row .required` at (0,3,1), so a first attempt at
   `body.woocommerce-page .required` (0,2,1) lost and the star stayed red; the
   form matched below is one element deeper and wins at (0,3,2). And the value
   is a variable, so redefining `--wc-red` on the body would have been the
   cheaper fix — deliberately not done, because that same variable paints
   validation errors and "danger" states, which should keep reading as danger.
   Same call already made for the chatbot's admin screens. */
body .woocommerce form .form-row .required,
body .woocommerce-page form .form-row .required,
body.woocommerce .required,
body.woocommerce-page .required {
	color: var(--kc-purple-soft);
	text-decoration: none;
}

/* Blog articles — the reading page
   ==========================================================================
   The archive at /blog/ already borrows the research library's cards, and the
   header, footer and drawer arrived with the rest of the site. The article
   body never did. It was still the parent theme's default prose.

   Measured on /blog/otr-ac-research/, a representative long one: 75 `<p>`,
   14 `<h2>`, 13 `<h3>`, 2 tables, 91 posts published in the same shape.

   THREE THINGS WERE WRONG, all of them structural rather than decorative.

   1. NO HIERARCHY. Every child of the content div carries `margin-top:
      19.2px`; headings carry 20px. So a section heading opened with the same
      gap as a paragraph break, and 27 headings in one article did nothing to
      show the reader where a section began. This is the change that matters
      most, and it is why the top margins below are large.

   2. NO MEASURE. The column runs the full 850px at 15px, about 113 characters
      a line, against the 68ch this file already applies to the category
      description and the checkout prose.

   3. TABLES WERE RAW. `border-collapse: collapse` with a 2px grey the
      Customizer paints on bare `td, th`.

   SCOPED TO `body.single-post .guten-post-content`, deliberately parallel to
   the `body.single-product .guten-post-content` rules above, and deliberately
   NOT to the section's generated id (`guten-UqJKZ1` on the article measured),
   which changes silently if the section is ever recreated.

   THE `ch` TRAP APPLIES HERE. Prose takes `68ch` because it is set in the
   text face. The headings are Michroma, where `ch` is enormous — HANDOFF
   records `78ch` computing to 1316px — so they take a rem value chosen to
   land on the same column edge. Do not "tidy" these to matching units.
   ========================================================================== */

body.single-post .guten-post-content :is(p, li) {
	color: var(--kc-text-muted);
	font-size: 1.02rem;
	line-height: 1.78;
	max-width: 68ch;
}

/* Open a section. The gap above a heading is the whole point: it collapses
   against the previous element's zero bottom margin, so this value is the gap
   the reader actually sees.

   THE FLAGS ARE REQUIRED, and a first pass without them lost silently — the
   rules shipped, matched, and changed nothing. The Customizer layer carries
   `.entry-content h1/h2/h3 { margin: 20px 0 !important }`, served inside
   `global-styles-inline-css`, so no selector can win this on specificity.
   That makes it the fifth `!important` fight this file records; HANDOFF lists
   the other four. Only the margins are flagged. The Customizer also sets
   `font-size` on those headings without a flag, and that is left to win. */
body.single-post .guten-post-content h2 {
	margin-bottom: 0 !important;
	margin-top: 3.2rem !important;
	max-width: 34rem;
}

body.single-post .guten-post-content h3 {
	margin-bottom: 0 !important;
	margin-top: 2.1rem !important;
	max-width: 34rem;
}

/* And bind the heading to the text under it. Without this the collapsed gap
   below a heading stays 19.2px, identical to a paragraph break, and the
   heading floats between two sections instead of belonging to one. */
body.single-post .guten-post-content :is(h2, h3) + * {
	margin-top: 0.7rem;
}

body.single-post .guten-post-content > :first-child {
	margin-top: 0;
}

/* Data is not prose: tables keep the full column. */
body.single-post .guten-post-content :is(figure.wp-block-table, table) {
	max-width: none;
}

/* Same card as the product description, same reason for `border: 0` first —
   the Customizer paints every bare td/th, so setting only `border-bottom`
   leaves a grey grid behind. A collapsed table also ignores border-radius. */
body.single-post .guten-post-content table {
	border: 1px solid var(--kc-line);
	border-collapse: separate;
	border-radius: var(--kc-radius-lg);
	border-spacing: 0;
	width: 100%;
}

body.single-post .guten-post-content table th {
	background-color: rgba(255, 255, 255, 0.03);
	border: 0;
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-purple);
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	padding: 12px 16px;
	text-align: left;
	text-transform: uppercase;
}

body.single-post .guten-post-content table td {
	border: 0;
	border-bottom: 1px solid var(--kc-line);
	color: var(--kc-text-muted);
	max-width: none;
	padding: 12px 16px;
}

body.single-post .guten-post-content table tr:last-child td {
	border-bottom: 0;
}

/* Identifiers, CAS numbers and SMILES strings run inline through these
   articles and were rendering in the browser's default monospace at body
   size, which reads as an accident rather than a citation. */
body.single-post .guten-post-content code {
	background-color: var(--kc-wash-brand);
	border: 1px solid var(--kc-line);
	border-radius: var(--kc-radius-sm);
	color: var(--kc-purple-soft);
	font-family: var(--kc-mono);
	font-size: 0.88em;
	padding: 0.1em 0.38em;
}

/* 20 `<sub>` on the article measured, all chemical formulae. Without the zero
   line-height each one grows its own line box and the paragraph rhythm ripples
   wherever a formula appears. */
body.single-post .guten-post-content :is(sub, sup) {
	line-height: 0;
}

body.single-post .guten-post-content a {
	text-underline-offset: 0.18em;
}

body.single-post .guten-post-content a:hover {
	color: var(--kc-purple-soft);
}
