/**
 * 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;
	margin: 2.4em 0 0.7em;
	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);
}

@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-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),
		color var(--kc-duration) var(--kc-ease);
}

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


/* 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(.../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);
}

.product-table {
	border-collapse: separate;
	border-spacing: 0;
	overflow: hidden;
	width: 100%;
}

.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;
}

/* 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);
}

body .jetpack-instant-search .jetpack-instant-search__jetpack-colophon-text {
	color: var(--kc-text-muted);
	opacity: 0.55;
}

/* 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. */
body .dgwt-wcas-sf-wrapp input[type="search"].dgwt-wcas-search-input {
	background-color: rgba(255, 255, 255, 0.04);
	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;
}

body .dgwt-wcas-sf-wrapp input[type="search"].dgwt-wcas-search-input:focus {
	border-color: var(--kc-purple);
	box-shadow: 0 0 0 3px var(--kc-wash-brand);
	outline: none;
}

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;
}
