/* Every full-width section carries its own vertical padding, so the root
   block gap between them (announcement bar, header, main's sections, footer)
   only ever added an unpainted strip on top of that padding — visible as a
   taller header band and looser seams than the design's, where sections meet
   edge to edge. Scoped to those two levels so block gaps inside content keep
   working. */
.wp-site-blocks > *,
main.wp-block-group > * {
	margin-block-start: 0;
}

/* Short pages — a one-item cart, a thin legal page — left the footer floating
   with bare canvas below it, since .wp-site-blocks is only ever as tall as its
   content. A column flex with a growing main pins the footer to the bottom of
   the viewport without stretching anything on a page that already fills it.
   Every template wraps its body in a single <main>, so that is the one child
   that absorbs the slack. The admin bar's strip is subtracted so the layout
   does not overshoot into a scrollbar while logged in; the variable is not set
   for logged-out visitors, hence the fallback. */
.wp-site-blocks {
	display: flex;
	flex-direction: column;
	min-height: calc(100vh - var(--wp-admin--admin-bar--height, 0px));
}

.wp-site-blocks > main {
	flex-grow: 1;
}

/* Uppercase mono label used for eyebrows and small links. */
.novacelle-label {
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--small);
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

/* Section-header links ("Ver las 4 líneas", "Ver todo el catálogo") read as
   links, unlike the global no-underline link style from theme.json. The class
   in the selector outweighs theme.json's :root-scoped :where() rule. */
p.novacelle-label a {
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-underline-offset: 0.3em;
}

/* Soft light behind the hero copy, in both mockups: a halo centred on the text
   block that lifts it off the flat brand green. Measured off the PDFs (page
   width 1920): the centre sits at ~25% of the band's width and ~45% of its
   height, the falloff dies out ~320px away, and at the centre every channel
   gains the same ~36/255 - which is why it reads as white light rather than a
   green tint. Hence the base token (the palette's near-white) at 20% rather
   than mint, which came up short on blue. The intermediate stops trace the
   mockup's measured falloff (76% / 43% / 19% of the peak at a quarter, half
   and three quarters of the radius), since a two-stop gradient fades linearly
   and leaves a visible ring instead. */
.novacelle-dots,
.novacelle-catalog-hero {
	--novacelle-hero-glow: radial-gradient(
		circle 320px at 25% 45%,
		rgba(250, 251, 249, 0.2) 0%,
		rgba(250, 251, 249, 0.152) 25%,
		rgba(250, 251, 249, 0.086) 50%,
		rgba(250, 251, 249, 0.038) 75%,
		rgba(250, 251, 249, 0) 100%
	);
}

/* Dotted texture behind the hero, under the glow. */
.novacelle-dots {
	background-image:
		var(--novacelle-hero-glow),
		radial-gradient(rgba(198, 246, 214, 0.18) 1px, transparent 1px);
	background-repeat: no-repeat, repeat;
	background-size: 100% 100%, 28px 28px;
}

/* Four-up rows collapse to 2 columns at <=900px and 1 at <=600px.
   The trust bar is a core wp-block-columns (flex), so the
   override targets flex-basis/flex-wrap, not grid-template-columns. */
@media (max-width: 900px) {
	.wp-block-columns.novacelle-grid-4 { flex-wrap: wrap !important; }
	.wp-block-columns.novacelle-grid-4 > .wp-block-column { flex-basis: calc(50% - 1rem) !important; }
}

/* Core only auto-stacks .wp-block-columns at <=781px (see core's own
   columns/style.css), but the hero row's bleed enhancement below is gated
   at >=901px to match this theme's own grid breakpoint. That leaves
   782-900px unstacked (core's side-by-side row layout) but unenhanced,
   where the hero photo and the howto vial get squeezed into their default
   flex share and collapse to a narrow sliver. Extending the stack to 900px
   for these two rows closes the gap: <=900px always gets the plain,
   contained mobile layout already verified to work there. !important is
   required to beat both core's inline flex-basis style (columns with an
   explicit width) and its own non-!important flex-basis:0 rule at >=782px. */
@media (max-width: 900px) {
	.novacelle-dots .wp-block-columns,
	.wp-block-columns.novacelle-howto-row {
		flex-wrap: wrap !important;
	}

	.novacelle-dots .wp-block-columns > .wp-block-column,
	.wp-block-columns.novacelle-howto-row > .wp-block-column {
		flex-basis: 100% !important;
	}
}

@media (max-width: 600px) {
	.wp-block-columns.novacelle-grid-4 > .wp-block-column { flex-basis: 100% !important; }
	.novacelle-step { flex-wrap: wrap; }
}

/* Featured products is a WooCommerce product-collection: the product-template
   renders as its own CSS grid (.wc-block-product-template__responsive), not a
   wp-block-columns flex row, so it needs a matching grid-template-columns
   override instead of flex-basis. The extra class in the selector matches
   core's own specificity (.wc-block-product-template__responsive.columns-4)
   so this override wins reliably. */
@media (max-width: 900px) {
	.novacelle-product-card.wc-block-product-template__responsive {
		grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
	}
}

@media (max-width: 600px) {
	.novacelle-product-card.wc-block-product-template__responsive {
		grid-template-columns: 1fr !important;
	}
}

/* woocommerce/product-collection is a dynamic block: its saved placeholder
   markup must be an empty wrapper div with nothing but the block's own class
   for block validation to pass, so spacing from the block's style attribute
   can't be serialized into the static markup. Reapplied here instead. The
   extra class matches the default child-gap rule's specificity
   (margin-block-start on .is-layout-constrained > *) so this wins reliably. */
.wp-block-woocommerce-product-collection.is-layout-flow {
	margin-top: var(--wp--preset--spacing--50);
}

/* Same constraint, for the catalog grid's own taller rhythm. */
.novacelle-catalog-body .wp-block-woocommerce-product-collection.is-layout-flow {
	margin-top: var(--wp--preset--spacing--60);
	margin-bottom: var(--wp--preset--spacing--60);
}

/* Hero photo bleeds past the constrained content column to the viewport's
   right edge, matching the design. The offset formula pushes the image's
   right edge from the content column's edge (contentSize/2 in from center)
   out to the true viewport edge: (100vw - contentSize) / 2 is the gutter
   width between the content column and the viewport edge on each side.
   Only applied above the core columns-block stacking breakpoint (900px,
   matching this theme's own grid breakpoint); the stacked layout gets its own,
   simpler bleed below. */

/* Stacked, the photo keeps the same anchor as at desktop width - its right
   edge on the viewport's, not on the content column's - but stays in flow, so
   a negative margin over the root padding is all it takes. Measured off the
   mobile design: the render is 78% of the viewport wide (narrower than the
   content column it sits in, hence the auto left margin pushing it right)
   and its bottom lands on the trust bar's frame rather than floating a
   padding step above it. */
@media (max-width: 900px) {
	.novacelle-hero-media .wp-block-image {
		width: 78vw;
		margin-left: auto;
		margin-right: calc(var(--wp--style--root--padding-right, 1.5rem) * -1);
	}

	/* The section's own bottom padding would leave the bled photo floating
	   over a strip of empty green instead of running into the trust bar.
	   !important beats the padding serialized inline on the section. */
	.novacelle-dots {
		padding-bottom: 0 !important;
	}
}

@media (min-width: 901px) {
	/* Shared by the figure's own width and by the row's min-height, which
	   derives the photo's rendered height from it. */
	.novacelle-dots {
		--novacelle-hero-photo-width: clamp(440px, 58.3vw, 1120px);
	}

	/* Positioning context is the columns row, not the image's own column:
	   the column collapses to zero height once its image is taken out of
	   flow for the bleed, so anchoring to it would place the image wherever
	   flex happened to center that empty box (which reached up over the
	   header). The row keeps real height from the text column instead. */
	.novacelle-dots .wp-block-columns {
		position: relative;
		/* Floor: the design's taller hero band, sized to fit the larger photo
		   rather than just the text column, which also lets the photo run
		   behind the trust bar without reaching past it. The band measures
		   910px in the design; 718px is that minus the 6rem of top/bottom
		   padding the section originally carried.

		   The second term is what lets the top padding shrink without
		   cropping the photo. The figure clips whatever of the photo's
		   width-driven height does not fit the band, so the band has to stay
		   at least as tall as the render: width x its 1800:1381 aspect, minus
		   the padding the band already contributes. Below ~1920px the floor
		   wins and the band keeps the design's proportions; past that the
		   photo hits its 1120px cap and this grows the row instead of
		   beheading the vial. */
		min-height: max(
			718px,
			calc(
				var(--novacelle-hero-photo-width) * 1381 / 1800
				- var(--wp--preset--spacing--40)
				- var(--wp--preset--spacing--70)
			)
		);
	}

	/* The editor gives every block wrapper position:relative
	   (.block-editor-block-list__layout .block-editor-block-list__block), which
	   makes the media column - not the row - the photo's containing block. That
	   column collapses to zero height once the photo is taken out of flow, so
	   the figure's height resolved to just its two padding terms and the render
	   was cropped to a sliver in the canvas while the front end was fine.
	   Restoring the front end's static column puts both back on the row. */
	.block-editor-block-list__layout .block-editor-block-list__block.novacelle-hero-media {
		position: static;
	}

	/* Positioned and clipped on the figure, not the img: the figure's fixed
	   height + overflow:hidden crop the photo's bottom instead of letting
	   its natural (width-driven) height spill past the hero section.
	   Height is derived from the row (100% + the section's own bottom
	   padding) rather than hardcoded, so it keeps landing exactly on the
	   hero section's bottom edge when the row's min-height or the spacing
	   token behind that padding changes. A fixed value overshot the edge
	   (photo spilling past the band) or fell short, leaving an uncovered
	   strip of plain background between photo and trust bar. */
	.novacelle-hero-media .wp-block-image {
		position: absolute;
		/* The photo bleeds to the band's top edge, not to the row's: anchored
		   at the row it sat a padding step too low, which pushed the
		   widest part of the mint blob down into the trust bar and left it
		   glowing under the band's text. Both offsets track the
		   section's own padding in hero.php (spacing 40 top, 70 bottom). */
		top: calc(var(--wp--preset--spacing--40) * -1);
		/* Push the image's right edge past the column's edge (at the
		   constrained content boundary) out to the true viewport edge. That
		   gutter is (100vw - contentSize) / 2 while the viewport is wide
		   enough to hold the full 1520px content size, and the root padding
		   once it is not — below ~1568px the column stops shrinking away from
		   the viewport and just sits inside the padding. Taking the larger of
		   the two (the more negative offset) covers both ranges: they meet
		   exactly at the width where the content size stops fitting. */
		right: min(
			calc(var(--wp--style--root--padding-right, 1.5rem) * -1),
			calc((100vw - 1520px) / -2)
		);
		width: var(--novacelle-hero-photo-width);
		height: calc(
			100% + var(--wp--preset--spacing--40) + var(--wp--preset--spacing--70)
		);
		overflow: hidden;
		margin: 0;
	}

	/* Pinned to the figure's bottom-right corner: the vial stands on the
	   render's own bottom edge, so that edge has to sit on the band's bottom
	   edge at every width. Top-aligned it floated instead, leaving a gap
	   between the glass and the trust bar whenever the width-driven height
	   came up short of the band. The render is a cutout with no background of
	   its own, so the room left above it is just the band showing through. */
	.novacelle-hero-media .wp-block-image img {
		position: absolute;
		right: 0;
		bottom: 0;
		display: block;
		width: 100%;
		max-width: none;
		height: auto;
	}


	/* The text column has no explicit width driving the media column's
	   flex-basis, so once the image is pulled out of flow for the bleed the
	   text column's own box (52% of the row) still spans well into the
	   image's horizontal territory — headline/paragraph lines that wrap
	   close to that box's right edge were painting UNDER the (later,
	   position:absolute) image instead of over it. Narrowing the column
	   (52% to 44%, see hero.php) reduces how often that happens; lifting the
	   text column
	   into its own stacking context above the image's default (auto) level
	   keeps every line readable regardless of where it wraps. */
	.novacelle-dots .wp-block-columns > .wp-block-column:first-child {
		position: relative;
		z-index: 2;
	}
}

/* Mobile keeps the previous flat, opaque band (same brand fill it always
   had) since below 901px the hero photo stays contained in flow and never
   reaches the trust bar, so there is nothing for a translucent band to
   reveal, and white text on the base-token translucent fill used at desktop
   width would be unreadable with no dark photo/hero backdrop behind it. */
.novacelle-trust-bar {
	background-color: var(--wp--preset--color--brand);
}

/* Below the grid overlay the stack is a plain constrained group, so its block
   gap reappears between hero and trust bar as an unpainted strip of page
   background across the seam the design has running edge to edge. The
   site-level reset above only reaches the two outermost levels, and global
   styles' own `:root :where(.is-layout-constrained) > *` ties this rule on
   specificity while winning on source order - hence the extra layout class. */
@media (max-width: 900px) {
	.novacelle-hero-stack.is-layout-constrained > * {
		margin-block-start: 0;
	}
}

@media (min-width: 901px) {
	/* Hero and trust bar are stacked into the same CSS Grid cell (see
	   novacelle-hero-stack below) so the trust bar's box genuinely overlaps
	   hero's, growing/shrinking with either one's actual content instead of
	   a hardcoded pixel pull-up. align-self:end pins the trust bar's own
	   bottom edge to the bottom of that shared cell, which is exactly the
	   hero's bottom edge (hero is always the taller of the two): flush at
	   every width, with no measured height anywhere. */
	.novacelle-hero-stack {
		display: grid;
	}

	.novacelle-hero-stack > .novacelle-dots,
	.novacelle-hero-stack > .novacelle-trust-bar {
		grid-area: 1 / 1;
	}

	.novacelle-hero-stack > .novacelle-trust-bar {
		align-self: end;
	}

	/* Frosted band over the tail of the hero photo, as in the design: a 21%
	   base-colored tint over a blurred backdrop. The blur is what makes the
	   tint work — it flattens the vial's highlight and the mint blob into a
	   soft field instead of leaving hard bright shapes under the text, and
	   it is visible in the design as the blob's edge going sharp above the
	   band and diffuse inside it.

	   z-index lifts the band (and its text) above the hero image, which is
	   positioned but otherwise painted later in the default stacking order;
	   without this the photo would draw over the trust-bar text instead of
	   showing through the band beneath it. */
	.novacelle-trust-bar {
		position: relative;
		z-index: 1;
		background-color: rgba(250, 251, 249, 0.21);
		-webkit-backdrop-filter: blur(6px);
		backdrop-filter: blur(6px);
	}
}

/* The blockGap set on the section reaches the columns row too, which would
   pull the four items together horizontally; the row keeps the wider gap the
   dividers need, and only the title/description pair inside each item takes
   the tighter one. */
.novacelle-trust-bar > .wp-block-columns {
	gap: var(--wp--preset--spacing--40);
}

/* Thin vertical dividers between trust-bar items, and the extra vertical
   breathing room the design uses versus a plain content row. */
.novacelle-trust-grid > .wp-block-column {
	border-left: 1px solid rgba(250, 251, 249, 0.25);
	padding-left: 1.5rem;
}

.novacelle-trust-grid > .wp-block-column:first-child {
	border-left: none;
	padding-left: 0;
}

/* Stacked, the band becomes a framed card in both of its layouts - the phone's
   single column and the tablet's two-up. The frame, the centred items and the
   type scale are shared here; only the grid and the hairlines differ, in the
   two blocks below.

   The desktop dividers have to come off every item, not just the odd ones: the
   columns are content-box, so the padding-left and border-left left on the even
   items added 25px to their outer width. Two items then measured 869px against
   an 852px row and every one of them wrapped onto its own line, which is why
   this range rendered as four full-width rows rather than the intended grid. */
@media (max-width: 900px) {
	.novacelle-trust-bar {
		/* So the frame's top edge meets the glass instead of leaving the photo
		   hanging over a strip of empty green. !important beats the section's
		   own serialized inline padding. */
		padding-top: 0 !important;
	}

	.novacelle-trust-bar > .wp-block-columns {
		border: 1px solid rgba(250, 251, 249, 0.85);
		background-color: rgba(250, 251, 249, 0.16);
	}

	.novacelle-trust-grid > .wp-block-column {
		border-left: none;
		padding-left: 0;
		text-align: center;
		position: relative;
	}

	/* Core's fluid typography takes both 1.375rem presets down to ~15px on a
	   phone, which flattens the item titles into their own descriptions; the
	   design keeps them at ~20px, a clear step above. The preset font-size
	   class the block carries is also !important and ties on specificity while
	   winning on source order, hence the parent in the selector. */
	.novacelle-trust-grid .novacelle-trust-title {
		font-size: 1.25rem !important;
	}

	/* The section's 0.5rem block gap only reaches the columns row, so the
	   title/description pair inside each item falls back to the root gap and
	   opens up to 24px. The design pairs them tightly. */
	.novacelle-trust-grid > .wp-block-column > * + * {
		margin-block-start: var(--wp--preset--spacing--20);
	}
}

/* Phone: one column, every item separated by the design's short centred rule. */
@media (max-width: 600px) {
	.novacelle-trust-bar > .wp-block-columns {
		padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40);
		gap: var(--wp--preset--spacing--70);
	}

	.novacelle-trust-grid > .wp-block-column {
		/* The design wraps the descriptions well before the frame's inner
		   edge, so the measure is the item's, not the box's. */
		max-width: 13.5rem;
		margin-inline: auto;
	}

	/* Hairline sitting in the middle of the row gap, drawn on the following
	   item so it never trails after the last one. */
	.novacelle-trust-grid > .wp-block-column + .wp-block-column::before {
		content: "";
		position: absolute;
		left: 50%;
		top: calc(var(--wp--preset--spacing--70) / -2);
		width: 4.25rem;
		border-top: 1px solid rgba(250, 251, 249, 0.5);
		transform: translateX(-50%);
	}
}

/* Tablet: the same frame, two-up, with the hairlines crossing - a full-height
   vertical rule between the columns (the desktop band's divider, kept) and the
   phone's short horizontal one between the rows. border-box is what makes the
   two-up hold: it keeps the items' own padding inside the 50% basis instead of
   adding to it. The basis is restated because the shared novacelle-grid-4 rule
   subtracts a column gap this layout does not use - the vertical rule sits in
   its place instead. */
@media (min-width: 601px) and (max-width: 900px) {
	.novacelle-trust-bar > .wp-block-columns {
		padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40);
		gap: var(--wp--preset--spacing--60) 0;
	}

	.wp-block-columns.novacelle-trust-grid > .wp-block-column {
		box-sizing: border-box;
		flex-basis: 50% !important;
		padding-inline: var(--wp--preset--spacing--40);
	}

	/* Wider measure than the phone's, since each item now has half a tablet
	   rather than a whole phone to sit in. */
	.novacelle-trust-grid > .wp-block-column > * {
		max-width: 15rem;
		margin-inline: auto;
	}

	.novacelle-trust-grid > .wp-block-column:nth-child(even)::before {
		content: "";
		position: absolute;
		left: 0;
		top: 0;
		bottom: 0;
		border-left: 1px solid rgba(250, 251, 249, 0.5);
	}

	.novacelle-trust-grid > .wp-block-column:nth-child(n+3)::after {
		content: "";
		position: absolute;
		left: 50%;
		top: calc(var(--wp--preset--spacing--60) / -2);
		width: 4.25rem;
		border-top: 1px solid rgba(250, 251, 249, 0.5);
		transform: translateX(-50%);
	}
}

.novacelle-trust-title {
	font-family: var(--wp--preset--font-family--heading);
	font-weight: 700;
	text-transform: uppercase;
}

/* Pill-shaped eyebrow badge used in the hero. */
.novacelle-pill {
	display: inline-block;
	border: 1px solid rgba(229, 255, 156, 0.35);
	border-radius: 999px;
	padding: 0.4rem 1rem;
}

/* The design centers the eyebrow pill and the CTA over the hero's text
   column while the headline and lead paragraph stay flush left. width:
   fit-content keeps the pill shrink-wrapped around its label (a plain
   display:block would stretch the border across the whole column). */
.novacelle-dots .novacelle-pill {
	display: block;
	width: fit-content;
	margin-inline: auto;
}

.novacelle-dots .wp-block-buttons {
	justify-content: center;
}

/* Once the hero stacks, that centering has no text column left to center
   over: the mobile design runs the eyebrow, headline, lead and CTA all flush
   to the same left edge. */
@media (max-width: 900px) {
	.novacelle-dots .novacelle-pill {
		margin-inline: 0;
	}

	.novacelle-dots .wp-block-buttons {
		justify-content: flex-start;
	}

	/* Fluid typography scales the lead preset down to ~15-17px across this
	   range, close enough to body copy that the hero's supporting line stops
	   reading as a lead; the design holds it at ~20px. The measure is capped
	   with it: left to the full column the line ran the whole 852px at the top
	   of the range, which reads as a caption stretched over the photo rather
	   than as the phone design's block of copy. */
	.novacelle-dots .has-lead-font-size {
		font-size: 1.28rem !important;
		max-width: 34rem;
	}
}

/* The eyebrow is a single line in the design at every width, but its label is
   long and the mono face carries 0.14em of tracking, so at the small preset
   (~14px) it needs ~450px and wraps into a two-line pill on any phone. Sizing
   it off the viewport keeps it on one line down to 320px; the rem term caps it
   so it stops growing once there is room to spare. Padding comes down with it
   to buy back the few pixels the tracking costs at the narrowest widths. */
@media (max-width: 600px) {
	.novacelle-dots .novacelle-pill {
		/* !important to beat core's own preset font-size class, which carries
		   it on .has-small-font-size. */
		font-size: min(0.6875rem, 2.5vw) !important;
		padding-inline: 0.85rem;
	}
}

/* Featured product cards. */
/* Fixed panel, sized to the design's 359x211. Product photos are whatever
   the store uploaded, and a portrait one used to size the panel itself and
   stretch every card in its grid row; here the panel holds its shape and the
   photo fits inside it. */
.novacelle-product-media {
	position: relative;
	/* Border-box so the ratio describes the panel the design drew, padding
	   included, rather than the box left inside it. */
	box-sizing: border-box;
	aspect-ratio: 359 / 211;
	border-radius: 14px 14px 0 0;
	padding: 2rem 1.5rem;
	overflow: hidden;
	display: grid;
	/* Fallback for a product outside the four research lines (the default
	   "Uncategorized" term, or none at all): a neutral tint that still reads
	   as the design's photo panel against the white card, without borrowing
	   a line's color and miscoding the product. The per-category rules below
	   match on specificity and win on source order. */
	background: color-mix(in srgb, var(--wp--preset--color--ink) 6%, var(--wp--preset--color--base));
}

/* The photo letterboxes inside the panel instead of sizing it. WooCommerce
   nests it two wrappers deep, and each one needs a definite height for the
   image's own 100% to resolve back to the panel's aspect-ratio box. */
.novacelle-product-media .wc-block-components-product-image,
.novacelle-product-media .wc-block-components-product-image a {
	display: block;
	height: 100%;
	min-height: 0;
}

/* Two classes deep on purpose: `.woocommerce img { height: auto }` ships in
   woocommerce.css, loads after this file and ties on specificity. The
   !important is for object-fit alone: woocommerce/product-image prints
   `style="object-fit:cover"` on the tag itself, which would crop a portrait
   photo's top and bottom instead of letterboxing it in the panel. */
.novacelle-product-media .wc-block-components-product-image img {
	width: 100%;
	height: 100%;
	object-fit: contain !important;
}

.novacelle-cat-peptidos-investigacion { background: var(--wp--preset--color--mint); }
.novacelle-cat-accesorios-laboratorio { background: var(--wp--preset--color--brand); }
.novacelle-cat-metabolismo  { background: var(--wp--preset--color--mint); }
.novacelle-cat-regeneracion { background: var(--wp--preset--color--brand); }
.novacelle-cat-cognicion    { background: var(--wp--preset--color--accent); }
.novacelle-cat-eje-gh       { background: var(--wp--preset--color--mint); }

.novacelle-badge {
	position: absolute;
	top: 1rem;
	left: 1rem;
	/* Media box padding is shorter than the pill's own footprint (top offset +
	   height), so the product image (a later sibling, also positioned) would
	   otherwise paint over the pill's bottom edge in normal DOM/paint order.
	   Lift it above the image explicitly rather than growing the box. */
	z-index: 1;
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--accent);
	border-radius: 999px;
	padding: 0.3rem 0.75rem;
	font-size: 0.6875rem;
}

.novacelle-cat-accesorios-laboratorio .novacelle-badge,
.novacelle-cat-regeneracion .novacelle-badge {
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--brand);
}

/* woocommerce/product-template's className lands on the <ul> list wrapper,
   not on each product — WooCommerce renders every product as its own <li
   class="wc-block-product ...">. Target those list items directly.

   Laid out as a grid (not flex-column) so the price and add-to-cart button,
   which are separate sibling blocks with no shared wrapper, can share a
   final row: "price" and "button" are placed in the same grid row via
   grid-template-areas, something flex-direction:column can't do without
   changing the pattern's block markup. */
.novacelle-product-card {
	/* Query container for the price/button degrade below: an element can't
	   respond to a container query evaluated against its own box, so the
	   container has to live on the <ul> (an ancestor of the <li>s), one
	   level up from the grid that actually needs to change. */
	container-type: inline-size;
}

.novacelle-product-card > li {
	border: 1px solid rgba(10, 10, 10, 0.08);
	border-radius: 14px;
	overflow: hidden;
	background: #FFFFFF;
	display: grid;
	grid-template-columns: max-content 1fr;
	grid-template-areas:
		"media media"
		"presentation presentation"
		"title title"
		"summary summary"
		"price button";
	/* Cards in a row stretch to the tallest one, and the leftover height was
	   being spread evenly over every auto row (align-content's grid default).
	   That pushed the media panel down inside its own row, so a card missing
	   the presentation line — the only optional row — opened a white strip
	   above its photo panel while a card that had one stayed flush. Parking
	   all the slack on the summary row instead keeps every panel at the card's
	   top edge and lands the price/button row at the same height across the
	   row. The narrow-container variants below add a sixth row (button on its
	   own); it inherits the implicit auto, which is what it needs. */
	grid-template-rows: auto auto auto 1fr auto;
	align-items: center;
	padding-bottom: 1.5rem;
}

/* Hover lift, sized for the product card's taller footprint. :focus-within is
   paired with :hover because the title and the add-to-cart are both real
   controls, so tabbing through a card raises it the same way. The card's
   overflow: hidden clips its children, not its own shadow. */
.novacelle-product-card > li {
	transition: box-shadow 240ms ease;
}

.novacelle-product-card > li:hover,
.novacelle-product-card > li:focus-within {
	box-shadow: 0 8px 24px rgba(3, 72, 69, 0.12);
}

@media (prefers-reduced-motion: reduce) {
	.novacelle-product-card > li {
		transition: none;
	}
}

/* The price's max-content column plus the button's own generous padding
   (below) need roughly 300px of card width to sit on one row; below that,
   in the 4-up grid (from ~901px up to ~1350px), the row was overflowing
   the card's own bounds — clipped by the overflow:hidden above instead of
   failing loudly. Scoped to the 4-up range (>=901px; 2-up and 1-up below
   900px already have enough room per card) and keyed to the row's own
   rendered width — not a guessed viewport breakpoint tied to an assumed
   column count — divided by 4 columns plus 3 gaps to get the per-card
   threshold. Stacks price above button, each taking the card's full
   width, so the row never needs more space than the card actually has. */
@media (min-width: 901px) {
	@container (max-width: 1330px) {
		.novacelle-product-card.columns-4 > li {
			grid-template-areas:
				"media media"
				"presentation presentation"
				"title title"
				"summary summary"
				"price price"
				"button button";
		}

		.novacelle-product-card.columns-4 > li > .wp-block-woocommerce-product-price {
			padding-inline-end: 1.5rem;
		}

		.novacelle-product-card.columns-4 > li > .wp-block-woocommerce-product-button {
			justify-self: stretch;
			padding-inline-start: 1.5rem;
			margin-top: 0.75rem;
		}

		/* Only the side padding changes: the pill keeps the base rule's
		   36px height and flex-centered label, it just gives up the wide
		   3rem flanks it cannot afford in a narrow card. */
		.novacelle-product-card.columns-4 .wc-block-components-product-button__button {
			padding-inline: 1.5rem;
		}
	}
}

/* Same degrade as the 4-up row above, re-derived for the catalog's 3-up
   grid: three cards plus two gaps, so the row runs out of room for a
   side-by-side price and button at a narrower container width. */
@media (min-width: 901px) {
	@container (max-width: 1000px) {
		.novacelle-product-card.columns-3 > li {
			grid-template-areas:
				"media media"
				"presentation presentation"
				"title title"
				"summary summary"
				"price price"
				"button button";
		}

		.novacelle-product-card.columns-3 > li > .wp-block-woocommerce-product-price {
			padding-inline-end: 1.5rem;
		}

		.novacelle-product-card.columns-3 > li > .wp-block-woocommerce-product-button {
			justify-self: stretch;
			padding-inline-start: 1.5rem;
			margin-top: 0.75rem;
		}

		/* Only the side padding changes: the pill keeps the base rule's
		   36px height and flex-centered label, it just gives up the wide
		   3rem flanks it cannot afford in a narrow card. */
		.novacelle-product-card.columns-3 .wc-block-components-product-button__button {
			padding-inline: 1.5rem;
		}
	}
}

/* In the editor canvas the card holds WooCommerce's own untouched blocks:
   inc/product-card.php shortens the add-to-cart label and collapses a variable
   product's price range on render_block, and that is PHP, which never runs in
   the editor. The default label plus the full range need ~95px more than the
   card is wide, and the card's overflow:hidden clips them instead of failing
   loudly. Apply the same degrade the container query gives narrow cards on the
   front end, keyed to the wrapper class only the editor adds. */
.novacelle-product-card.block-editor-block-list__block > li {
	grid-template-areas:
		"media media"
		"presentation presentation"
		"title title"
		"summary summary"
		"price price"
		"button button";
}

.novacelle-product-card.block-editor-block-list__block > li > .wp-block-woocommerce-product-price {
	padding-inline-end: 1.5rem;
}

.novacelle-product-card.block-editor-block-list__block > li > .wp-block-woocommerce-product-button {
	justify-self: stretch;
	padding-inline-start: 1.5rem;
	margin-top: 0.75rem;
}

.novacelle-product-card.block-editor-block-list__block .wc-block-components-product-button__button {
	padding-inline: 1.5rem;
}

/* Editor canvas only. assets/js/editor-product-card.js can add the badge as a
   sibling of the image block but not inside it, since a BlockEdit filter cannot
   reach past the block's own wrapper element. So the image block itself plays
   the media panel, and both it and the pill are parked in the card's media grid
   area, which stacks them the way the front end nests them. */
.novacelle-product-card.block-editor-block-list__block > li > .wp-block-woocommerce-product-image {
	grid-area: media;
	box-sizing: border-box;
	aspect-ratio: 359 / 211;
	border-radius: 14px 14px 0 0;
	padding: 2rem 1.5rem;
	overflow: hidden;
	display: grid;
	background: color-mix(in srgb, var(--wp--preset--color--ink) 6%, var(--wp--preset--color--base));
}

.novacelle-product-card.block-editor-block-list__block > li > .wp-block-woocommerce-product-image img {
	width: 100%;
	height: 100%;
	object-fit: contain !important;
}

/* Same offsets the front end's absolute positioning gives the pill, expressed
   as margins because here it is a grid item rather than a positioned child.
   position:relative earns it the stacking context its z-index needs to stay
   above the panel, which follows it in source order. */
.novacelle-product-card.block-editor-block-list__block > li > .novacelle-badge {
	grid-area: media;
	position: relative;
	top: auto;
	left: auto;
	align-self: start;
	justify-self: start;
	margin: 1rem 0 0 1rem;
}

/* The panel takes its tint from the slug the badge carries, since the filter
   cannot put a class on the image block's own wrapper. */
.novacelle-product-card > li:has(> [data-novacelle-cat="peptidos-investigacion"]) > .wp-block-woocommerce-product-image,
.novacelle-product-card > li:has(> [data-novacelle-cat="metabolismo"]) > .wp-block-woocommerce-product-image,
.novacelle-product-card > li:has(> [data-novacelle-cat="eje-gh"]) > .wp-block-woocommerce-product-image {
	background: var(--wp--preset--color--mint);
}

.novacelle-product-card > li:has(> [data-novacelle-cat="accesorios-laboratorio"]) > .wp-block-woocommerce-product-image,
.novacelle-product-card > li:has(> [data-novacelle-cat="regeneracion"]) > .wp-block-woocommerce-product-image {
	background: var(--wp--preset--color--brand);
}

.novacelle-product-card > li:has(> [data-novacelle-cat="cognicion"]) > .wp-block-woocommerce-product-image {
	background: var(--wp--preset--color--accent);
}

.novacelle-product-card > li > .novacelle-product-media { grid-area: media; }
.novacelle-product-card > li > .wp-block-post-title { grid-area: title; }
/* Start-aligned because the summary owns the card's flexible row (above):
   centering it there would float the teaser away from the title. */
.novacelle-product-card > li > .wp-block-woocommerce-product-summary {
	grid-area: summary;
	align-self: start;
}

.novacelle-product-card > li > .novacelle-presentation {
	grid-area: presentation;
	margin: 1.25rem 0 0;
	color: var(--wp--preset--color--teal);
}

/* Price sits in the max-content column so it never wraps; the button's
   1fr column absorbs the remaining width and pushes the pill to the
   card's right edge with justify-self. */
.novacelle-product-card > li > .wp-block-woocommerce-product-price {
	grid-area: price;
	white-space: nowrap;
}

.novacelle-product-card > li > .wp-block-woocommerce-product-button {
	grid-area: button;
	justify-self: end;
	margin: 0;
}

.novacelle-product-card > li > *:not(.novacelle-product-media) { padding-inline: 1.5rem; }

/* Price and button face each other across the same row: drop the padding
   between them (each already keeps the outer edge padding) so the shared
   row doesn't double that gap and starve the button's column of width. */
.novacelle-product-card > li > .wp-block-woocommerce-product-price { padding-inline-end: 0; }
.novacelle-product-card > li > .wp-block-woocommerce-product-button { padding-inline-start: 0; }

/* Wide pill to match the design, replacing the global button element's own
   padding just for these cards. The 36px comes from min-height with the
   block padding zeroed, not from vertical padding, so the pill holds that
   height regardless of the label's font size and line-height. */
.novacelle-product-card .wc-block-components-product-button__button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 36px;
	padding-block: 0;
	padding-inline: 3rem;
}

/* Once a product is in the cart, WooCommerce reveals a "Ver carrito" link it
   keeps hidden next to the button, which nearly triples the button row's
   height (36px to ~108px) and pulls the card out of line with its neighbours.
   The header's mini-cart is the storefront's route to the cart, so the link
   is redundant here. Hiding its unclassed wrapper span rather than the anchor
   itself: with only the anchor gone the span still lays out a line box, and
   the row keeps ~12px of the space back. */
.novacelle-product-card .wc-block-components-product-button > span:has(> .added_to_cart) {
	display: none;
}

/* Every card in the design carries the same two-line teaser. Product copy is
   whatever the store owner wrote, and one long paragraph stretches the whole
   grid row with it, so the lead paragraph is clamped. The bullet list below
   it is left alone — it is content the card is meant to show. */
.novacelle-product-card .wc-block-components-product-summary > p {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	overflow: hidden;
}

/* A bullet list or a second paragraph still stretched the row, so the whole
   teaser is capped at four lines and its last line fades out; the product
   page holds the rest. The mask is sized to the cap rather than to the box,
   so a teaser shorter than the cap never reaches the fade and stays solid.
   clip rather than hidden: hidden would start a formatting context, trap the
   paragraphs' margins inside the cap and spend a line of it on whitespace. */
.novacelle-product-card .wc-block-components-product-summary {
	max-height: 4lh;
	overflow: clip;
	mask-image: linear-gradient(to bottom, #000 3lh, transparent 4lh);
	mask-size: 100% 4lh;
	mask-repeat: no-repeat;
}

/* Bullets in the product summary: a small middot hugging the text instead
   of the browser's default disc/circle marker with its deep indent. */
.novacelle-product-card .wp-block-woocommerce-product-summary ul {
	list-style-type: "·  ";
	padding-inline-start: 1rem;
	margin-block: 0;
}

/* Struck-through regular price (on-sale products only): smaller and lighter
   than the active sale price, which keeps the card's own font-size/color. */
.novacelle-product-card .wc-block-components-product-price__regular {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--muted);
	font-weight: 400;
}

/* Vial cutout in "Cómo comprar": a transparent PNG standing directly on the
   section's gradient, not a framed photo, so it needs no bleed or edge fade.
   The column stretches to the row's height and the cutout is sized against
   that, top-aligned with the first step card. */
.novacelle-howto-media .wp-block-image {
	margin: 0;
	height: 100%;
	display: flex;
	align-items: flex-start;
	justify-content: center;
}

/* Height-bound, not width-bound: the cap decides the cutout's size and the
   width follows. A fixed value rather than a percentage of the row: a
   percentage max-height resolves to none while the row is being sized, so
   the cutout's full natural height would stretch the band instead of the
   steps column setting it. */
.novacelle-howto-media img {
	display: block;
	width: auto;
	max-width: 100%;
	max-height: 460px;
}

@media (max-width: 900px) {
	/* Stacked below the steps, the cutout has no row height to bound it and
	   would take most of a phone screen on its own. */
	.novacelle-howto-media img {
		max-height: 360px;
	}
}

.novacelle-step {
	border: 1px solid rgba(250, 251, 249, 0.14);
	border-radius: 12px;
	padding: 1.5rem;
	background: rgba(250, 251, 249, 0.04);
	/* The number pill lines up with the step's title in the design. Core's
	   flex layout centers it against the whole card instead, which drops it
	   down beside the description on every two-line step. */
	align-items: flex-start;
}

/* Steps carry no link, so the highlight is hover-only: on touch there is
   nothing to trigger it and :hover would stick after a tap. */
@media (hover: hover) {
	.novacelle-step,
	.novacelle-step .novacelle-step-number {
		transition: border-color 240ms ease, background-color 240ms ease;
	}

	.novacelle-step:hover {
		border-color: var(--wp--preset--color--accent);
		background-color: rgba(250, 251, 249, 0.08);
	}

	.novacelle-step:hover .novacelle-step-number {
		border-color: var(--wp--preset--color--accent);
	}
}

@media (prefers-reduced-motion: reduce) {
	.novacelle-step,
	.novacelle-step .novacelle-step-number {
		transition: none;
	}
}

.novacelle-step-number {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	height: 2rem;
	border: 1px solid rgba(250, 251, 249, 0.3);
	border-radius: 999px;
	flex-shrink: 0;
	white-space: nowrap;
}

/* FAQ section overlaps the dark "Cómo comprar" band above it and rounds its
   own top corners, so it reads as a light card sitting on top of the dark
   one instead of a straight seam between the two. The negative margin pulls
   it up by exactly the corner radius, so the flat middle of the top edge
   lands back where the two sections naturally meet, while the rounded
   corners recede and let the dark band show through underneath them. */
/* How far the FAQ panel rides up over the section above it. */
:root { --novacelle-faq-overlap: 64px; }
@media (max-width: 900px) { :root { --novacelle-faq-overlap: 32px; } }
@media (max-width: 600px) { :root { --novacelle-faq-overlap: 20px; } }

.novacelle-faq-section {
	position: relative;
	z-index: 1;
	border-radius: var(--novacelle-faq-overlap) var(--novacelle-faq-overlap) 0 0;
	margin-top: calc(var(--novacelle-faq-overlap) * -1) !important;
}

.novacelle-faq details {
	border-bottom: 1px solid rgba(10, 10, 10, 0.12);
	padding: 1rem 0;
	/* Each row already carries its own padding and rule, so the column's
	   block gap on top of that stretched every row past the design's pitch.
	   !important beats core's own layout-support selector for child spacing
	   (":root :where(.is-layout-constrained) > *"). */
	margin-block-start: 0 !important;
}

/* The first row still sits apart from the section intro, as in the design. */
.novacelle-faq details:first-of-type {
	margin-block-start: var(--wp--preset--spacing--40) !important;
}

/* Open answer: constrained to a shorter measure instead of running the full
   column width, matching the design's tighter rows. */
.novacelle-faq details > p {
	max-width: 32rem;
	margin: 0.5rem 0 0;
}

.novacelle-faq summary {
	cursor: pointer;
	list-style: none;
	font-size: var(--wp--preset--font-size--lead);
	font-weight: 500;
}

.novacelle-faq summary::-webkit-details-marker { display: none; }

/* The rows form an exclusive accordion: <details name> lets the browser close
   the open row when another one is opened, with no script. Browsers without
   that support simply keep several rows open. */

/* interpolate-size unlocks transitions to and from `auto`, which is what
   ::details-content resolves to while the row is open; without it the height
   jumps. Both this and ::details-content degrade to an instant open. */
:root { interpolate-size: allow-keywords; }

.novacelle-faq details::details-content {
	block-size: 0;
	overflow: hidden;
	transition:
		block-size 320ms cubic-bezier(0.22, 0.61, 0.36, 1),
		content-visibility 320ms allow-discrete;
}

.novacelle-faq details[open]::details-content { block-size: auto; }

/* The answer fades in on its own keyframes rather than a transition: it is
   only laid out once the row is open, so there is no closed state to
   transition from. This is also the motion browsers without
   ::details-content fall back to. */
@keyframes novacelle-faq-reveal {
	from { opacity: 0; transform: translateY(-6px); }
	to { opacity: 1; transform: none; }
}

.novacelle-faq details[open] > p {
	animation: novacelle-faq-reveal 320ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

/* Drawn from two gradient bars rather than a "+"/"−" glyph swap, so the
   vertical bar can collapse into the horizontal one as the row opens. */
.novacelle-faq summary::after {
	content: "";
	float: right;
	inline-size: 0.7em;
	block-size: 0.7em;
	margin-block-start: 0.35em;
	color: var(--wp--preset--color--muted);
	background:
		linear-gradient(currentColor, currentColor) center / 100% 2px no-repeat,
		linear-gradient(currentColor, currentColor) center / 2px 100% no-repeat;
	transition: background-size 320ms cubic-bezier(0.22, 0.61, 0.36, 1), transform 320ms ease;
}

.novacelle-faq details[open] summary::after {
	background-size: 100% 2px, 2px 0;
	transform: rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
	.novacelle-faq details::details-content,
	.novacelle-faq summary::after { transition: none; }
	.novacelle-faq details[open] > p { animation: none; }
}

/* The header rides along with the scroll; the announcement bar above it does
   not, so it scrolls away first. Sticky sits on the template-part wrapper
   rather than the <header> inside it: the wrapper is the only ancestor tall
   enough to stick against — pinning the <header> itself would let it scroll
   out with its own parent box. The z-index clears every stacking context the
   sections below open (all at 1-2), and it also becomes the layer of the
   mobile nav overlay and the mini-cart drawer, which are nested inside. */
.novacelle-sticky-header {
	position: sticky;
	top: 0;
	z-index: 100;
}

/* The admin bar is fixed above 600px and would cover the pinned header. */
@media (min-width: 783px) {
	.admin-bar .novacelle-sticky-header { top: 32px; }
}

@media (min-width: 601px) and (max-width: 782px) {
	.admin-bar .novacelle-sticky-header { top: 46px; }
}

/* Sections reached through a menu hash link would land under the pinned header. */
.novacelle-anchor-target {
	scroll-margin-top: 6rem;
}

/* WooCommerce auto-inserts a customer-account icon next to core/navigation in
   block themes (Block Hooks). The header already exposes account access via
   the mini-cart drawer and the footer's "Mi cuenta" link, so the extra icon
   is hidden rather than opting out of the hook with a markup change. */
header .wp-block-woocommerce-customer-account {
	display: none;
}

/* The mini-cart block's Interactivity API hydration overwrites the badge's
   server-rendered inline style (driven by the productCountColor attribute)
   with its own client-side default (an inline style, unthemed) once JS
   takes over, so the visible badge quietly reverts to unstyled colors after
   load. Force the intended colors past that inline style. */
header .wc-block-mini-cart__badge {
	background-color: var(--wp--preset--color--brand) !important;
	color: var(--wp--preset--color--base) !important;
}

/* core/navigation's overlayMenu:"mobile" only collapses to the hamburger below
   600px, but this header — nav, logotype, cart and CTA on one nowrap row —
   stops fitting just under 930px. In between, the nav wrapped to two lines and
   the CTA label broke mid-word, down to roughly one letter per line near 620px.

   The collapse is set at 960px rather than at the measured ~930px limit: 930 is
   where the current Spanish labels give out, so anything longer would break it
   again. The extra 30px is deliberate margin, not a measurement.

   Both rules below undo what core's own (min-width: 600px) block sets, leaving
   600-960px behaving exactly like <600px. The `header` prefix is what wins the
   override — one type selector more than core's, so stylesheet order does not
   matter — and it keeps the change scoped to the site header instead of every
   navigation block. */
@media (min-width: 600px) and (max-width: 960px) {
	header .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
		display: none;
		position: fixed;
		width: auto;
	}

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

/* At the hamburger breakpoint set above the header is already tight; drop the
   "Carrito" text and keep just the icon and badge. */
@media (max-width: 960px) {
	.novacelle-cart-trigger .novacelle-label {
		display: none;
	}
}

/* The checkout header is logotype plus a "Pago seguro" label and cart icon on
   a nowrap row. The logotype shrinks to its 110px floor and the label still
   pushes the row past 320px, so drop the label there and keep the icon. */
@media (max-width: 360px) {
	.novacelle-checkout-trust .novacelle-label {
		display: none;
	}
}

/* Header logotype. Width lives on the figure (the flex item) so the image can
   shrink with the row instead of pushing the CTA past the viewport edge; the
   image itself is width:100%/height:auto, keeping the wordmark's aspect ratio
   at any size. The figure's own margins would offset it from the row. */
.novacelle-logo {
	margin: 0;
	width: 287px;
	min-width: 110px;
}

/* The intrinsic width/height attributes cannot live on the <img> markup: core's
   image block no longer parses them back into attributes, so the editor flags
   the block as invalid. aspect-ratio reserves the same space before load. */
.novacelle-logo img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 287 / 30;
}

/* Below the hamburger-nav breakpoint the header is a single nowrap row of
   nav-toggle, logo, cart icon and CTA button. Pin the logotype to roughly the
   footprint the text logotype used to hold there. */
@media (max-width: 480px) {
	.novacelle-logo {
		width: 150px;
	}

	/* Even with the logotype at its 110px floor the row runs past the viewport
	   below 420px, and the CTA is the widest item in it (153px, wider than the
	   logotype). Dropping to an open-book icon alone clears the overflow down
	   to 320px. font-size:0 is what collapses the label: the pattern renders it
	   as a bare text node with no element to hide, and this leaves "Ver
	   catálogo" in the button's accessible name. The arrow span, already the
	   only element in the link, becomes the icon box; the PNG is applied as a
	   mask so the glyph takes the button's text color. With the logotype at
	   its floor, 320px leaves room for about 54px of button; the inline
	   padding squares the pill at 47x47 and keeps an 8px gutter at the edge. */
	header .wp-block-button__link {
		font-size: 0;
		padding-inline: 0.9rem;
	}

	header .wp-block-button__link .novacelle-arrow {
		width: 1.125rem;
		height: 1.125rem;
		vertical-align: middle;
		background-color: currentColor;
		mask: url("../images/icon-book-open.png") center / contain no-repeat;
	}

	header .wp-block-button .wp-block-button__link:is(:hover, :focus-visible) .novacelle-arrow {
		transform: none;
	}
}

/* Mark the nav item matching the current page: teal with a mint underline, so
   it stays distinct from the plain teal a hovered item takes below. The nav
   block's links are custom URLs (not page references), so core has no built-in
   current-item detection to hook into; matching on WordPress's own "home"
   body class instead. */
body.home .wp-block-navigation-item a[href="/"],
body.post-type-archive-product .wp-block-navigation-item a[href="/shop/"],
body.tax-product_cat .wp-block-navigation-item a[href="/shop/"],
body.tax-product_tag .wp-block-navigation-item a[href="/shop/"] {
	color: var(--wp--preset--color--teal);
	text-decoration: underline;
	text-decoration-color: var(--wp--preset--color--mint);
	text-underline-offset: 0.3em;
}

/* Contact card buttons (WhatsApp/Correo): label left, arrow pushed to the
   button's right edge, instead of the label+arrow centered together. */
.novacelle-contact-buttons .wp-block-button__link {
	display: flex;
	align-items: center;
	justify-content: space-between;
	text-align: left;
}

/* Badges normally show the short label from novacelle_product_category_short_label().
   This is a safety net for the fallback case: a category slug with no short
   label mapped prints its full name (e.g. "Hormona del crecimiento y
   rendimiento celular"), which would overflow the pill and get clipped by
   novacelle-product-media's overflow: hidden, leaving a jagged edge. */
.novacelle-badge {
	max-width: calc(100% - 2rem);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Footer nav/legal lists follow the design: plain underlined links in the
   footer's own text color, no bullets. */
footer.wp-block-group .wp-block-list {
	list-style: none;
	padding-left: 0;
}

footer.wp-block-group .wp-block-list a {
	color: inherit;
	text-decoration: underline;
}

/* Legal column reads plain in the design: no underline, unlike Navegación/Ayuda. */
footer.wp-block-group .novacelle-footer-plain a {
	text-decoration: none;
}

/* Contact line keeps the mono font for the phone/email digits but drops the
   novacelle-label treatment (uppercase, wide tracking) the design doesn't use here. */
.novacelle-footer-contact {
	font-family: var(--wp--preset--font-family--mono);
}

/* Footer logotype. Capped at the asset's native width so it never upscales,
   and allowed to shrink with the column below that. Same margin-0/width-100%
   treatment as the header logotype, so block layout owns the spacing. */
.novacelle-footer-logo {
	margin: 0;
	width: 317px;
	max-width: 100%;
}

.novacelle-footer-logo img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 317 / 28;
}

/* The design sets the footer tagline on a shorter measure than its column,
   breaking it over three lines under the logotype. */
.novacelle-footer-tagline {
	max-width: 21rem;
}

/* The announcement bar's three items need about 905px of content width, so they
   start wrapping below roughly 950px — not at 600px, where this tightening used
   to be gated, which left a stack of 3rem vertical gaps across the whole range
   in between. The pattern's blockGap applies to both axes; overriding only
   row-gap keeps the 3rem rhythm between items sharing a line and tightens the
   space between lines. No breakpoint: the rule is inert while the row fits. */
.novacelle-label.has-brand-background-color .wp-block-group {
	row-gap: 0.35rem;
}

/* Once the nav collapses to a hamburger, the header CTA is squeezed by
   flexWrap:nowrap and wraps word-by-word instead of shrinking cleanly. Matches
   the hamburger breakpoint set above. */
@media (max-width: 960px) {
	header .wp-block-buttons .wp-block-button__link {
		white-space: nowrap;
	}
}

/* Catalog hero: the dotted texture from the home hero, plus the same glow
   behind the copy and the mint molecule cluster anchored to the top-right
   corner. All three are background layers on one element so they can't fight
   over background-image the way a separate .novacelle-dots rule would. */
.novacelle-catalog-hero {
	overflow: hidden;
	/* Second light on the right of the band, mint rather than the near-white
	   of the copy's halo. Sampling the designer's export shows it is two
	   overlaid washes, not one: a corner ellipse that fades out ~300px in and
	   dies before the bottom, plus a narrow bleed down the whole right edge
	   that survives where the ellipse has gone. One gradient cannot be both
	   wide at the top and tight at the bottom, which is why there are two.
	   Both sit under the motif - it stays pure mint in the mockup. */
	--novacelle-hero-corner-glow: radial-gradient(
		ellipse 300px 85% at 100% 0%,
		rgba(198, 246, 214, 0.32) 0%,
		rgba(198, 246, 214, 0.3) 30%,
		rgba(198, 246, 214, 0.23) 55%,
		rgba(198, 246, 214, 0.09) 80%,
		rgba(198, 246, 214, 0) 100%
	);
	--novacelle-hero-edge-glow: linear-gradient(
		to left,
		rgba(198, 246, 214, 0.28) 0,
		rgba(198, 246, 214, 0.15) 60px,
		rgba(198, 246, 214, 0.03) 120px,
		rgba(198, 246, 214, 0) 170px
	);
	background-image:
		url("../images/catalog-hero-shape.png"),
		var(--novacelle-hero-corner-glow),
		var(--novacelle-hero-edge-glow),
		var(--novacelle-hero-glow),
		radial-gradient(rgba(198, 246, 214, 0.18) 1px, transparent 1px);
	background-repeat: no-repeat, no-repeat, no-repeat, no-repeat, repeat;
	/* Fitted to the designer's band: the motif stands 129% of the band's
	   height, so its top arms are cropped by the edge, it bleeds a sliver past
	   the right edge, and its foot lands just short of the bottom. */
	background-position: right -18px bottom 35px, top right, top right, center, center;
	background-size: auto 129%, 100% 100%, 100% 100%, 100% 100%, 28px 28px;
}

/* Measure matching the design's two-line lede. The pattern nests it in a flow
   group so this narrower box stays on the heading's left rail. */
.novacelle-catalog-hero .novacelle-catalog-hero-lead {
	max-width: 55rem;
}

/* Pagination row: results count left, numbers and "next" right. The current
   page is a filled disc and the rest are outlined, matching the design.

   With no products the row's blocks render empty (the results-count block
   still emits its wrapper div, so the count is what has to be tested for),
   and the group would paint as a bare hairline above the no-results copy. */
.novacelle-catalog-pagination:not(:has(.woocommerce-result-count)) {
	display: none;
}

.novacelle-catalog-pagination {
	align-items: center;
	gap: var(--wp--preset--spacing--40);
	margin-top: var(--wp--preset--spacing--50);
	padding-top: var(--wp--preset--spacing--40);
	border-top: 1px solid rgba(10, 10, 10, 0.08);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--small);
}

.novacelle-catalog-pagination .wp-block-query-pagination {
	gap: 0.5rem;
}

.novacelle-catalog-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.5rem;
	height: 2.5rem;
	border: 1px solid rgba(3, 72, 69, 0.16);
	border-radius: 999px;
	color: var(--wp--preset--color--brand);
	text-decoration: none;
}

.novacelle-catalog-pagination .page-numbers.current {
	background: var(--wp--preset--color--brand);
	border-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--accent);
}

.novacelle-catalog-pagination .wp-block-query-pagination-next {
	padding-inline: 1.25rem;
	border: 1px solid rgba(3, 72, 69, 0.16);
	border-radius: 999px;
	height: 2.5rem;
	display: inline-flex;
	align-items: center;
	color: var(--wp--preset--color--brand);
	text-decoration: none;
}

/* Below this width the shape would sit under the headline instead of beside
   it, so it drops out and the highlight and texture stay. */
@media (max-width: 900px) {
	.novacelle-catalog-hero {
		background-image:
			radial-gradient(circle at 25% 45%, rgba(198, 246, 214, 0.16), transparent 55%),
			radial-gradient(rgba(198, 246, 214, 0.18) 1px, transparent 1px);
		background-repeat: no-repeat, repeat;
		background-position: center, center;
		background-size: 100% 100%, 28px 28px;
	}
}

/* Filter pills. The strip is full-bleed mint; on narrow screens it scrolls
   sideways instead of wrapping, so the row keeps reading as one set. */
.novacelle-filters {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
}

.novacelle-filter {
	display: inline-flex;
	gap: 0.4rem;
	align-items: center;
	background: #FFFFFF;
	color: var(--wp--preset--color--brand);
	border: 1px solid rgba(3, 72, 69, 0.12);
	border-radius: 999px;
	padding: 0.55rem 1.1rem;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
}

.novacelle-filter:hover {
	border-color: var(--wp--preset--color--brand);
}

/* Colour alone can't carry focus, so the ring is an outline. */
.novacelle-filter:focus-visible {
	outline: 2px solid var(--wp--preset--color--brand);
	outline-offset: 2px;
}

.novacelle-filter.is-active {
	background: var(--wp--preset--color--brand);
	border-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--accent);
}

/* Empty lines stay visible so the set of research lines reads complete, but
   they are spans: no link, no focus stop. Recessed with a dimmer text color,
   not opacity: opacity composites the whole pill over the mint strip and takes
   the label to 2.5:1, and these are plain text, not disabled controls. An
   empty line that is the current page keeps the full active treatment. */
.novacelle-filter.is-empty:not(.is-active) {
	color: var(--wp--preset--color--muted);
	border-color: rgba(3, 72, 69, 0.08);
}

.novacelle-filter-count {
	font-weight: 700;
}

@media (max-width: 600px) {
	.novacelle-filters {
		flex-wrap: nowrap;
		overflow-x: auto;
		padding-bottom: 0.5rem;
		/* Without this, the row's own nowrap content (its max-content size)
		   gets read by ancestors sizing themselves off it, widening the whole
		   page instead of scrolling in place. inline-size containment stops
		   that upward read so the strip sizes from its container, not its
		   content. */
		contain: inline-size;
	}

	.novacelle-filter {
		flex: 0 0 auto;
	}
}

/* Grid toolbar: heading left, sort control right, hairline underneath. */
.novacelle-catalog-toolbar {
	align-items: flex-end;
	gap: var(--wp--preset--spacing--40);
	margin-top: var(--wp--preset--spacing--60);
	padding-bottom: var(--wp--preset--spacing--30);
	border-bottom: 1px solid rgba(10, 10, 10, 0.08);
}

.novacelle-catalog-sort {
	align-items: center;
	gap: 0.75rem;
}

/* WooCommerce renders no sorting control when the loop is empty, which would
   leave the static "Ordenar" label standing next to nothing. */
.novacelle-catalog-sort:not(:has(.woocommerce-ordering)) {
	display: none;
}

.novacelle-catalog-sort .woocommerce-ordering select {
	background: #FFFFFF;
	border: 1px solid rgba(3, 72, 69, 0.16);
	border-radius: 999px;
	padding: 0.55rem 1.1rem;
	font-family: var(--wp--preset--font-family--text);
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--ink);
	/* The design shows no dropdown arrow; the native one is the only chevron. */
	appearance: none;
}

/* Catalog body: aside left, grid right. Core stacks wp-block-columns at
   <=781px on its own, but the aside has to land after the grid, not before,
   so the stack is forced at the theme's own 900px breakpoint with an
   explicit order. */
.novacelle-catalog-body {
	/* The design's 35px below the filter strip. Padding, not margin: the
	   theme zeroes margin-block-start on every direct child of <main>, and no
	   token carries this value. */
	padding-top: 35px;
	/* Whichever column ends lowest -- the aside on a short grid, the grid on a
	   long one -- would otherwise butt against the band below, and the brand
	   card shares that band's fill, so the two dark blocks read as one. */
	padding-bottom: var(--wp--preset--spacing--60);
	gap: var(--wp--preset--spacing--50);
}

.novacelle-catalog-aside {
	display: grid;
	gap: var(--wp--preset--spacing--40);
}

.novacelle-quote-card,
.novacelle-brand-card {
	border-radius: 18px;
	padding: var(--wp--preset--spacing--40);
}

.novacelle-quote-card > *,
.novacelle-brand-card > * {
	margin-block-start: 1rem;
}

.novacelle-quote-card > :first-child,
.novacelle-brand-card > :first-child {
	margin-block-start: 0;
}

/* Brand card: brand fill with the molecule and vials anchored to the bottom.
   It runs the card
   to 806px so the column stays anchored past the second product row; 50rem is
   that height, and the copy only fills the top third. catalog-vials.png
   composes the designer's two pieces on a canvas as wide as the card itself,
   with the lattice, the vials and the 24px the design leaves under them
   already in place, so the image just fills the width and sits on the bottom
   edge. Once the card goes full width that would tower over the copy, so
   there it is capped by height instead (see the 900px breakpoint below). */
.novacelle-brand-card {
	min-height: 50rem;
	/* The hero's near-white wash, same falloff, moved up to sit under this
	   card's copy instead of the middle of the block. It cannot reuse
	   --novacelle-hero-glow: the position is baked into the gradient, and at
	   25% 45% the light would land on the artwork, not the text. */
	--novacelle-brand-card-glow: radial-gradient(
		circle 320px at 30% 18%,
		rgba(250, 251, 249, 0.2) 0%,
		rgba(250, 251, 249, 0.152) 25%,
		rgba(250, 251, 249, 0.086) 50%,
		rgba(250, 251, 249, 0.038) 75%,
		rgba(250, 251, 249, 0) 100%
	);
	background-image:
		url("../images/catalog-vials.png"),
		var(--novacelle-brand-card-glow);
	background-repeat: no-repeat, no-repeat;
	background-position: bottom center, center;
	background-size: 100% auto, 100% 100%;
}

.novacelle-brand-card-logo img {
	width: 100%;
	max-width: 317px;
	height: auto;
	aspect-ratio: 289 / 26;
}

/* Side by side, the aside sets the row's height, so a short grid leaves the
   results-count row stranded halfway up the column. Making the column and the
   collection flex boxes lets an auto top margin drop the row to the aside's
   bottom edge; the 24px above it moves onto the grid so the tall-grid case,
   where there is no free space to absorb, keeps the spacing it has today.
   WooCommerce's own 64px below the collection has to go with it, or the row
   stops short of the card -- the child combinator is what outranks it. */
@media (min-width: 901px) {
	.novacelle-catalog-body > .wp-block-column:last-child,
	.novacelle-catalog-body > .wp-block-column > .wp-block-woocommerce-product-collection {
		display: flex;
		flex-direction: column;
	}

	.novacelle-catalog-body > .wp-block-column > .wp-block-woocommerce-product-collection {
		flex: 1;
		margin-bottom: 0;
	}

	.novacelle-catalog-body .wc-block-product-template {
		margin-bottom: var(--wp--preset--spacing--40);
	}

	/* Full path, not the bare class: core's own
	   .wp-block-woocommerce-product-collection.is-layout-flow > * block-gap
	   rule outranks a single class and would keep the row at its 24px. */
	.novacelle-catalog-body > .wp-block-column > .wp-block-woocommerce-product-collection > .novacelle-catalog-pagination {
		margin-top: auto;
	}
}

@media (max-width: 900px) {
	.novacelle-catalog-body {
		flex-wrap: wrap !important;
	}

	.novacelle-catalog-body > .wp-block-column {
		flex-basis: 100% !important;
	}

	.novacelle-catalog-body > .wp-block-column:first-child {
		order: 2;
	}

	/* Full-width card: a width cap no longer bounds the artwork's height, so
	   cap the height directly and let the width follow. The desktop height
	   comes back down too — it exists to match the sidebar column, which no
	   longer sits beside the grid here. */
	.novacelle-brand-card {
		min-height: 34rem;
		background-size: auto 60%, 100% 100%;
	}
}

/* Closing band. The third card in the mockup shows the hover state, so all
   three take the same treatment: lime border and a lift in the fill. */
.novacelle-includes .wp-block-columns {
	gap: var(--wp--preset--spacing--40);
}

.novacelle-include-card {
	border: 1px solid rgba(198, 246, 214, 0.22);
	border-radius: 18px;
	padding: var(--wp--preset--spacing--40);
	transition: border-color 150ms ease, background-color 150ms ease;
}

.novacelle-include-card > * {
	margin-block-start: 0.75rem;
}

.novacelle-include-card > :first-child {
	margin-block-start: 0;
}

.novacelle-include-card:hover {
	border-color: var(--wp--preset--color--accent);
	background: rgba(229, 255, 156, 0.06);
}

@media (max-width: 900px) {
	.novacelle-includes .wp-block-columns {
		flex-wrap: wrap !important;
	}

	.novacelle-includes .wp-block-column {
		flex-basis: 100% !important;
	}
}

/* Button states. theme.json can express a button's resting fill but not its
   hover, so every state from the design lives here, keyed off the color class
   the block writes rather than off a per-pattern class: a new button reusing
   the same token inherits the state for free. */

/* Lime pill -> mint-to-lime gradient. A gradient cannot be interpolated by a
   transition, so the moving end is a registered custom property and only its
   color animates; without @property support the gradient swaps instantly,
   which is the same picture minus the fade. */
@property --novacelle-pill-from {
	syntax: "<color>";
	inherits: false;
	initial-value: #E5FF9C;
}

.wp-block-button__link.has-accent-background-color {
	background-image: linear-gradient(90deg, var(--novacelle-pill-from), var(--wp--preset--color--accent));
	transition: --novacelle-pill-from 200ms ease;
}

.wp-block-button__link.has-accent-background-color:hover,
.wp-block-button__link.has-accent-background-color:focus-visible {
	--novacelle-pill-from: var(--wp--preset--color--mint);
}

/* Dark fills invert on hover: the lime that was the label becomes the fill.
   Core prints its color classes with !important, so the swap has to match it;
   the lime pill above escapes this only because a background-image outranks a
   background-color regardless of importance. */
.wp-block-button__link.has-brand-background-color {
	transition: background-color 200ms ease, color 200ms ease;
}

.wp-block-button__link.has-brand-background-color:hover,
.wp-block-button__link.has-brand-background-color:focus-visible {
	background-color: var(--wp--preset--color--accent) !important;
	color: var(--wp--preset--color--brand) !important;
}

/* "Correo" sits on the mint contact card, so its hover is a mint tint rather
   than the full token, which would erase the button against the card. */
.wp-block-button__link.has-base-background-color {
	transition: background-color 200ms ease;
}

.wp-block-button__link.has-base-background-color:hover,
.wp-block-button__link.has-base-background-color:focus-visible {
	background-color: #E6F9EA !important;
}

/* Add to cart, in the catalog card and on the single product, takes its fill
   from theme.json's elements.button and so carries no color class to hang the
   inversion on. WooCommerce ships its own hover for both at a specificity the
   class alone cannot outrank. The checkout button is left on WooCommerce's
   own styling. */
.novacelle-product-card .wc-block-components-product-button__button,
.single_add_to_cart_button {
	transition: background-color 200ms ease, color 200ms ease;
}

.novacelle-product-card .wc-block-components-product-button__button:hover,
.novacelle-product-card .wc-block-components-product-button__button:focus-visible,
.single_add_to_cart_button:hover,
.single_add_to_cart_button:focus-visible {
	background-color: var(--wp--preset--color--accent) !important;
	color: var(--wp--preset--color--brand) !important;
}

/* The mini-cart's "Ver mi carrito de compra" is one of WooCommerce's outlined
   buttons, whose hover fills with its own near-black. It reads as the same
   control as "Comprar ahora" on the single product, so it inverts to brand
   the same way. Outranking `.wc-block-components-button:not(.is-link).is-style-outline:hover`
   takes the block's own class on top of it; the two outline class names are the
   old and the current markup for the same variant, and the states are matched
   one for one because WooCommerce paints active and focus near-black too. */
.wc-block-mini-cart__footer-cart.wc-block-components-button:not(.is-link):is(.is-style-outline, .outlined) {
	transition: background-color 200ms ease, color 200ms ease, box-shadow .1s linear;
}

.wc-block-mini-cart__footer-cart.wc-block-components-button:not(.is-link):is(.is-style-outline, .outlined):hover,
.wc-block-mini-cart__footer-cart.wc-block-components-button:not(.is-link):is(.is-style-outline, .outlined):focus,
.wc-block-mini-cart__footer-cart.wc-block-components-button:not(.is-link):is(.is-style-outline, .outlined):active {
	background-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--accent);
}

/* WooCommerce's filled cart buttons — "Ir al pago" in the drawer, "Proceder al
   pago" on the cart page and "Aplicar" in the coupon panel — take their brand
   fill from theme.json's elements.button, which defines no hover at all, so
   they sat inert. They invert like every other dark pill on the site: the
   accent that was the label becomes the fill.

   Only while the button can actually be pressed. WooCommerce marks the two it
   blocks with `disabled` and the link it blocks with aria-disabled, and dims
   just the label; a button that inverts under the pointer and then does
   nothing reads as broken, which is most of the coupon panel's life since its
   "Aplicar" starts out disabled until a code is typed. */
:is(
	.wc-block-mini-cart__footer-checkout,
	.wc-block-cart__submit-button,
	.wc-block-components-totals-coupon__button,
	.wc-block-order-confirmation-create-account-button
).wc-block-components-button:not(.is-link) {
	transition: background-color 200ms ease, color 200ms ease, box-shadow .1s linear;
}

:is(
	.wc-block-mini-cart__footer-checkout,
	.wc-block-cart__submit-button,
	.wc-block-components-totals-coupon__button,
	.wc-block-order-confirmation-create-account-button
).wc-block-components-button:not(.is-link):not(:disabled):not([aria-disabled="true"]):is(:hover, :focus-visible) {
	background-color: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--brand);
}

/* Section-header links: the resting underline is a muted brand rather than the
   text's own color, and hover lifts underline and arrow to mint. */
p.novacelle-label a {
	text-decoration-color: rgba(3, 72, 69, 0.3);
	transition: text-decoration-color 200ms ease;
}

p.novacelle-label a:hover,
p.novacelle-label a:focus-visible {
	text-decoration-color: var(--wp--preset--color--mint);
}

p.novacelle-label a:hover .novacelle-arrow,
p.novacelle-label a:focus-visible .novacelle-arrow {
	color: var(--wp--preset--color--mint);
}

/* Nav and cart lift to teal on hover. The current page is already teal and
   keeps its mint underline, so the two states never collapse into each other.
   Core pins the nav link to `color: inherit` through a doubled class, so the
   hover has to carry the navigation class as well to outweigh it; the cart
   label and icon carry core color classes, which are printed !important. */
header .wp-block-navigation .wp-block-navigation-item__content,
.novacelle-cart-trigger,
.novacelle-cart-trigger p,
.novacelle-cart-trigger .wc-block-mini-cart__button {
	transition: color 200ms ease;
}

/* The label forwards its clicks to the mini-cart button (assets/js/mini-cart-label.js),
   so it has to read as part of the same control rather than as stray text. */
.novacelle-cart-trigger .novacelle-label {
	cursor: pointer;
	user-select: none;
}

header .wp-block-navigation .wp-block-navigation-item__content:hover,
header .wp-block-navigation .wp-block-navigation-item__content:focus-visible {
	color: var(--wp--preset--color--teal);
}

.novacelle-cart-trigger:hover,
.novacelle-cart-trigger:focus-within {
	color: var(--wp--preset--color--teal);
}

.novacelle-cart-trigger:hover p,
.novacelle-cart-trigger:focus-within p,
.novacelle-cart-trigger:hover .wc-block-mini-cart__button,
.novacelle-cart-trigger:focus-within .wc-block-mini-cart__button {
	color: var(--wp--preset--color--teal) !important;
}

/* The arrow advances with the pointer. Inline-block so the transform takes:
   transforms do not apply to a non-replaced inline box. */
.novacelle-arrow {
	display: inline-block;
	transition: transform 200ms ease, color 200ms ease;
}

:is(.wp-block-button__link, p.novacelle-label a):hover .novacelle-arrow,
:is(.wp-block-button__link, p.novacelle-label a):focus-visible .novacelle-arrow {
	transform: translateX(3px);
}

@media (prefers-reduced-motion: reduce) {
	.wp-block-button__link,
	.novacelle-product-card .wc-block-components-product-button__button,
	.single_add_to_cart_button,
	.wc-block-mini-cart__footer-cart.wc-block-components-button:not(.is-link):is(.is-style-outline, .outlined),
	:is(.wc-block-mini-cart__footer-checkout, .wc-block-cart__submit-button, .wc-block-components-totals-coupon__button).wc-block-components-button:not(.is-link),
	p.novacelle-label a,
	header .wp-block-navigation .wp-block-navigation-item__content,
	.novacelle-cart-trigger,
	.novacelle-cart-trigger p,
	.novacelle-cart-trigger .wc-block-mini-cart__button,
	.novacelle-arrow {
		transition: none;
	}

	:is(.wp-block-button__link, p.novacelle-label a):hover .novacelle-arrow,
	:is(.wp-block-button__link, p.novacelle-label a):focus-visible .novacelle-arrow {
		transform: none;
	}
}

/* Single product page ------------------------------------------------------
   Breadcrumb, gallery panel, buy card, tab row and the closing advisory band.
   The catalog card component (novacelle-product-card) is reused verbatim for
   the related-products row, so nothing here restyles it. */

.novacelle-breadcrumbs {
	margin-block: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40);
}

.novacelle-breadcrumbs .woocommerce-breadcrumb {
	color: var(--wp--preset--color--muted);
}

.novacelle-breadcrumbs a {
	color: inherit;
}

.novacelle-breadcrumbs a:hover,
.novacelle-breadcrumbs a:focus-visible {
	color: var(--wp--preset--color--teal);
}

/* Gallery and buy card share the first row; the tab set sits under the gallery
   while the buy column is still running, which is why this is a grid and not a
   core columns row: those three are siblings here, so the tabs can be placed in
   the left track's second row and still follow the buy card in source order
   (the stacking order the design needs on a phone). */
.novacelle-product-layout {
	display: grid;
	grid-template-columns: 64% 1fr;
	/* The buy column spans both rows, so the second one is flexible: a spanning
	   item hands its extra height to a flexible track instead of padding out
	   the first row, which would otherwise push the tab set far below the
	   gallery it belongs to. */
	grid-template-rows: auto 1fr;
	column-gap: 5rem;
	row-gap: var(--wp--preset--spacing--60);
	align-items: start;
}

.novacelle-product-layout > * {
	margin-block: 0;
	min-width: 0;
}

.novacelle-gallery {
	grid-column: 1;
	grid-row: 1;
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
}

.novacelle-buy-column {
	grid-column: 2;
	grid-row: 1 / span 2;
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--40);
}

.novacelle-product-tabs {
	grid-column: 1;
	grid-row: 2;
}

@media (max-width: 900px) {
	.novacelle-product-layout {
		grid-template-columns: 1fr;
		grid-template-rows: none;
	}

	.novacelle-gallery,
	.novacelle-buy-column,
	.novacelle-product-tabs {
		grid-column: 1;
		grid-row: auto;
	}
}

/* Gallery panel. Same category tint and badge language as the catalog card, so
   a compound keeps its color from the grid to its own page. */
.novacelle-gallery-media {
	position: relative;
	box-sizing: border-box;
	aspect-ratio: 963 / 591;
	border-radius: 20px;
	/* The vial takes a little over half the panel's height in the design. Its
	   box fills what the padding leaves, so that share is set here, as a
	   percentage of the panel's width — the one length that always resolves —
	   rather than as a cap on the photo itself. */
	padding: 13.8% 2.5rem;
	overflow: hidden;
	display: grid;
}

/* Same neutral fallback the catalog card uses for a product outside the four
   research lines. Written as a :not() rather than a plain declaration because
   the .novacelle-cat-* tints are defined earlier in this file and would lose
   to it on source order. */
.novacelle-gallery-media:not([class*="novacelle-cat-"]) {
	background: color-mix(in srgb, var(--wp--preset--color--ink) 6%, var(--wp--preset--color--base));
}

/* WooCommerce nests the photo in a carousel <ul>/<li>, then the product-image
   block's own wrappers. Each needs a definite height for the image's 100% to
   resolve back to the panel's aspect-ratio box. */
.novacelle-gallery-media .wc-block-product-gallery-large-image,
.novacelle-gallery-media .wc-block-product-gallery-large-image__container,
.novacelle-gallery-media .wc-block-product-gallery-large-image__wrapper,
.novacelle-gallery-media .wc-block-components-product-image,
.novacelle-gallery-media .wc-block-components-product-image a {
	display: block;
	height: 100%;
	min-height: 0;
	margin: 0;
	padding: 0;
	list-style: none;
}

.novacelle-gallery-media .wc-block-product-gallery-large-image__container {
	overflow: hidden;
}

/* The photo fills that box and letterboxes inside it, which is what centres the
   vial on both axes. Two classes deep, like the card's own photo rule:
   `.woocommerce img { height: auto }` ships in woocommerce.css, which loads
   after this file, so a plain `img` selector would tie on specificity and lose
   the height the centring depends on. */
.novacelle-gallery-media .wc-block-components-product-image img {
	width: 100%;
	height: 100%;
	object-fit: contain !important;
}

.novacelle-lot-badge {
	position: absolute;
	top: 1.25rem;
	right: 1.25rem;
	z-index: 1;
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--accent);
	border-radius: 999px;
	padding: 0.3rem 0.75rem;
	font-size: 0.6875rem;
}

.novacelle-gallery-media > .novacelle-badge {
	top: 1.25rem;
	left: 1.25rem;
}

/* The lot pill would vanish against the dark panel a regeneración product
   gets, so it swaps to the lime fill the category badge already uses there. */
.novacelle-cat-accesorios-laboratorio .novacelle-lot-badge,
.novacelle-cat-regeneracion .novacelle-lot-badge {
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--brand);
}

.novacelle-gallery .wc-block-product-gallery-thumbnails {
	gap: 0.75rem;
}

.novacelle-gallery .wc-block-product-gallery-thumbnails__thumbnail {
	border: 1px solid rgba(10, 10, 10, 0.08);
	border-radius: 12px;
	overflow: hidden;
	background: var(--wp--preset--color--base);
	padding: 0.5rem;
}

.novacelle-gallery .wc-block-product-gallery-thumbnails__thumbnail--is-active {
	border-color: var(--wp--preset--color--brand);
	background: var(--wp--preset--color--mint);
}

/* Product intro ----------------------------------------------------------- */

.novacelle-product-intro {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--20);
}

.novacelle-product-eyebrow {
	color: var(--wp--preset--color--muted);
	margin: 0;
}

.novacelle-product-intro .wp-block-post-title {
	margin: 0;
}

.novacelle-product-lede {
	margin: 0;
	line-height: 1.5;
}

.novacelle-product-lede p {
	margin: 0;
}

.novacelle-product-rating {
	margin: 0;
	color: var(--wp--preset--color--muted);
}

/* Buy card ---------------------------------------------------------------- */

.novacelle-buy-card {
	border: 1px solid rgba(10, 10, 10, 0.08);
	border-radius: 14px;
	background: var(--wp--preset--color--base);
	padding: 1.5rem;
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
}

.novacelle-buy-card > * {
	margin: 0;
}

.novacelle-buy-card .wc-block-components-product-price {
	line-height: 1;
}

.novacelle-buy-note {
	margin-top: -0.5rem !important;
	color: var(--wp--preset--color--muted);
}

/* The add-to-cart block wraps its form in a store-notices region that ships
   with alignwide, which would break the card's padding on a wide viewport. */
.novacelle-buy-card .wc-block-components-notices {
	max-width: none;
	margin: 0;
}

.novacelle-buy-card .wc-block-add-to-cart-with-options {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
}

/* Presentation picker ----------------------------------------------------- */

.novacelle-variation {
	gap: 0.6rem !important;
	align-items: stretch !important;
}

.novacelle-variation > * {
	width: 100%;
}

.novacelle-variation .wp-block-woocommerce-add-to-cart-with-options-variation-selector-attribute-name {
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.6875rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--wp--preset--color--muted);
}

.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pills {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 0.5rem;
	width: 100%;
}

/* Each option is a two-line tile — presentation over its own price — instead
   of WooCommerce's single-line pill, so the visitor compares prices without
   changing the selection first. */
.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pill {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.15rem;
	min-height: 3.5rem;
	padding: 0.5rem;
	border: 1px solid rgba(10, 10, 10, 0.12);
	border-radius: 12px;
	background: var(--wp--preset--color--base);
	color: var(--wp--preset--color--ink);
	font-size: 0.8125rem;
	transition: border-color 200ms ease, background-color 200ms ease, color 200ms ease;
}

.novacelle-pill-label {
	font-weight: 700;
}

.novacelle-pill-price {
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.6875rem;
	color: var(--wp--preset--color--muted);
}

.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pill:hover {
	border-color: var(--wp--preset--color--teal);
	background: var(--wp--preset--color--base);
}

.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pill:has(.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pill-input:checked) {
	background: var(--wp--preset--color--brand);
	border-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--base);
}

.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pill:has(.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pill-input:checked) .novacelle-pill-price {
	color: var(--wp--preset--color--mint);
}

.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pill:focus-within {
	outline: 2px solid var(--wp--preset--color--teal);
	outline-offset: 2px;
}

/* A presentation with no purchasable variation is struck through by
   WooCommerce; keep it legible rather than letting the strike read as a price
   change. */
.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pill:has(.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pill-input:disabled) {
	opacity: 0.45;
	text-decoration: none;
}

/* Quantity, add to cart, buy now ------------------------------------------ */

.novacelle-buy-actions {
	gap: 0.75rem !important;
	align-items: stretch;
}

.novacelle-buy-actions .wc-block-components-quantity-selector {
	display: flex;
	align-items: center;
	border: 1px solid rgba(10, 10, 10, 0.12);
	border-radius: 999px;
	height: 100%;
	min-height: 3rem;
	width: 7rem;
	padding: 0 0.25rem;
	background: var(--wp--preset--color--base);
}

/* The stepper's own buttons come before and after the input in Woo's markup
   order (input, minus, plus); the design reads minus, value, plus. */
.novacelle-buy-actions .wc-block-components-quantity-selector__input {
	order: 2;
	flex: 1;
	min-width: 0;
	border: 0;
	background: transparent;
	text-align: center;
	font-family: var(--wp--preset--font-family--text);
	font-size: 0.9375rem;
	-moz-appearance: textfield;
	appearance: textfield;
}

.novacelle-buy-actions .wc-block-components-quantity-selector__input::-webkit-outer-spin-button,
.novacelle-buy-actions .wc-block-components-quantity-selector__input::-webkit-inner-spin-button {
	appearance: none;
	margin: 0;
}

.novacelle-buy-actions .wc-block-components-quantity-selector__button {
	order: 1;
	border: 0;
	background: transparent;
	color: var(--wp--preset--color--brand);
	cursor: pointer;
	font-size: 1rem;
	line-height: 1;
	padding: 0.5rem;
}

.novacelle-buy-actions .wc-block-components-quantity-selector__button--plus {
	order: 3;
}

.novacelle-buy-actions .wc-block-components-quantity-selector__button:disabled {
	opacity: 0.35;
	cursor: not-allowed;
}

.novacelle-buy-actions .wc-block-components-product-button {
	flex: 1;
	margin: 0;
}

/* WooCommerce prints an inline `.wp-block-button.wc-block-components-product-button
   .wp-block-button__link { width: auto }` that outranks a two-class selector, so the
   button has to be reached through its wrapper to fill the row beside the stepper. */
.novacelle-buy-actions .wp-block-button.wc-block-components-product-button .wc-block-components-product-button__button {
	width: 100%;
	min-height: 3rem;
}

/* Secondary action: the same pill as the primary button, drawn as an outline
   so the two read as one stacked pair. */
.novacelle-buy-now {
	display: block;
	padding: 0.9rem 1.75rem;
	border: 1px solid var(--wp--preset--color--brand);
	border-radius: 999px;
	text-align: center;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
	color: var(--wp--preset--color--brand);
	background: transparent;
	transition: background-color 200ms ease, color 200ms ease;
}

.novacelle-buy-now:hover,
.novacelle-buy-now:focus-visible {
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--accent);
}

.novacelle-buy-now[aria-disabled="true"] {
	opacity: 0.4;
	pointer-events: none;
}

.novacelle-stock-line {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	font-size: var(--wp--preset--font-size--fine);
	color: var(--wp--preset--color--muted);
}

.novacelle-stock-line .wc-block-components-product-stock-indicator {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	color: var(--wp--preset--color--brand);
}

/* Before hydration the indicator is an empty element the Interactivity API
   fills in, and a lone bullet would sit there on its own. */
.novacelle-stock-line .wc-block-components-product-stock-indicator:empty {
	display: none;
}

.novacelle-stock-line .wc-block-components-product-stock-indicator::before {
	content: "";
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 999px;
	background: var(--wp--preset--color--teal);
}

/* Assurances and advisory ------------------------------------------------- */

.novacelle-assurances {
	border-radius: 14px;
	padding: 1.25rem 1.5rem;
}

.novacelle-check-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	line-height: 1.4;
}

.novacelle-check-list li {
	position: relative;
	padding-left: 1.5rem;
}

.novacelle-check-list li::before {
	content: "✓";
	position: absolute;
	left: 0;
	color: var(--wp--preset--color--teal);
}

/* Dashed, and in the brand tint the section-header underlines already use:
   the advisory is the one panel in the column the design draws as a note
   pinned to the page rather than as another card. */
.novacelle-notice {
	border: 1px dashed rgba(3, 72, 69, 0.3);
	border-radius: 14px;
	padding: 1.25rem 1.5rem;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.novacelle-notice > * {
	margin: 0;
	line-height: 1.45;
}

/* Tabs -------------------------------------------------------------------- */

/* WooCommerce's is-style-minimal already strips its default folder tabs; these
   rules restyle what it leaves, and carry the same `html body` prefix its own
   stylesheet uses so they match on specificity rather than out-shout it (this
   file is enqueued after the block's own CSS, so a tie is enough). */
.novacelle-product-tabs .woocommerce-tabs {
	margin: 0;
}

html body .novacelle-product-tabs.is-style-minimal ul.tabs.wc-tabs {
	display: flex;
	flex-wrap: wrap;
	gap: 2rem;
	margin: 0;
	padding: 0 0 0.75rem;
	list-style: none;
	border-bottom: 1px solid rgba(10, 10, 10, 0.12);
}

html body .novacelle-product-tabs.is-style-minimal ul.tabs.wc-tabs li {
	margin: 0;
	padding: 0;
	opacity: 1;
	border: 0;
	font-weight: 400;
}

html body .novacelle-product-tabs.is-style-minimal ul.tabs.wc-tabs li a {
	display: inline-block;
	padding: 0 0 0.75rem;
	margin-bottom: -0.75rem;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 400;
	color: var(--wp--preset--color--muted);
	border-bottom: 2px solid transparent;
	transition: color 200ms ease, border-color 200ms ease;
}

/* The whole border is restated, not just its color: is-style-minimal clears it
   with a `border: none` shorthand that outranks the transparent placeholder
   above, so a color-only declaration lands on a zero-width border. */
html body .novacelle-product-tabs.is-style-minimal ul.tabs.wc-tabs li.active a,
html body .novacelle-product-tabs.is-style-minimal ul.tabs.wc-tabs li a:hover,
html body .novacelle-product-tabs.is-style-minimal ul.tabs.wc-tabs li a:focus-visible {
	color: var(--wp--preset--color--ink);
	border-bottom: 2px solid var(--wp--preset--color--brand);
}

.novacelle-product-tabs .woocommerce-Tabs-panel {
	padding-top: var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.6;
	color: var(--wp--preset--color--muted);
}

.novacelle-product-tabs .woocommerce-Tabs-panel > :first-child {
	margin-top: 0;
}

/* Specifications table: the same hairline rhythm as the tab row, with the
   attribute name in the label voice used across the store. */
.novacelle-product-tabs .shop_attributes {
	width: 100%;
	border-collapse: collapse;
}

.novacelle-product-tabs .shop_attributes th,
.novacelle-product-tabs .shop_attributes td {
	text-align: left;
	padding: 0.75rem 0;
	border-bottom: 1px solid rgba(10, 10, 10, 0.08);
	vertical-align: top;
}

.novacelle-product-tabs .shop_attributes th {
	width: 32%;
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.6875rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	font-weight: 400;
	color: var(--wp--preset--color--muted);
}

.novacelle-product-tabs .shop_attributes td p {
	margin: 0;
	color: var(--wp--preset--color--ink);
}

/* Related row and closing band -------------------------------------------- */

.novacelle-related .wp-block-columns {
	margin-bottom: 0;
}

.novacelle-product-cta .novacelle-cta-lead {
	max-width: 48ch;
	line-height: 1.5;
}

.novacelle-cta-buttons {
	gap: 0.75rem;
}

/* Outline variant on the dark band: core's is-style-outline draws a
   currentColor border, which here is the base fill the label already uses. */
.novacelle-cta-ghost .wp-block-button__link {
	border: 1px solid rgba(250, 251, 249, 0.4);
	background: transparent;
	transition: background-color 200ms ease, border-color 200ms ease;
}

.novacelle-cta-ghost .wp-block-button__link:hover,
.novacelle-cta-ghost .wp-block-button__link:focus-visible {
	background: rgba(250, 251, 249, 0.1);
	border-color: var(--wp--preset--color--mint);
}

@media (max-width: 900px) {
	.novacelle-product-cta .wp-block-columns {
		flex-wrap: wrap;
	}

	.novacelle-product-cta .wp-block-column {
		flex-basis: 100% !important;
	}

	.novacelle-cta-buttons {
		justify-content: flex-start;
	}
}

@media (prefers-reduced-motion: reduce) {
	.wc-block-add-to-cart-with-options-variation-selector-attribute-options__pill,
	.novacelle-buy-now,
	html body .novacelle-product-tabs.is-style-minimal ul.tabs.wc-tabs li a,
	.novacelle-cta-ghost .wp-block-button__link {
		transition: none;
	}
}

/* Checkout option lists. Shipping methods and payment methods are the same
   WooCommerce radio-control, which ships as joined rows ringed by a 1.5px ink
   shadow at a 4px radius. Here each option is its own card in the language the
   rest of the site uses, and the checked one takes the brand ring instead. */
.wc-block-checkout .wc-block-components-radio-control {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
}

/* Payment methods wrap each option in an accordion; shipping methods are the
   bare label, so the card is a different element on each list. */
.wc-block-checkout .wc-block-components-radio-control-accordion-option,
.wc-block-checkout .wc-block-components-radio-control > .wc-block-components-radio-control__option {
	background: #FFFFFF;
	border-radius: 14px;
	box-shadow: inset 0 0 0 1px rgba(10, 10, 10, 0.08);
	transition: box-shadow 200ms ease, background-color 200ms ease;
}

.wc-block-checkout .wc-block-components-radio-control-accordion-option--checked-option-highlighted,
.wc-block-checkout .wc-block-components-radio-control > .wc-block-components-radio-control__option--checked-option-highlighted {
	background: rgba(3, 72, 69, 0.03);
	box-shadow: inset 0 0 0 1.5px var(--wp--preset--color--brand);
}

/* The label is the whole clickable row, so the radius has to repeat here or
   the focus ring and hover fill square off the card's corners. */
.wc-block-checkout .wc-block-components-radio-control__option {
	border-radius: 14px;
}

.wc-block-checkout .wc-block-components-radio-control__input {
	accent-color: var(--wp--preset--color--brand);
}

.wc-block-checkout .wc-block-components-payment-method-label {
	font-weight: 500;
}

/* The accordion content carries the gateway's own description and, for
   Mercado Pago, its whole checkout container. */
.wc-block-checkout .wc-block-components-radio-control-accordion-content {
	color: var(--wp--preset--color--muted);
}

.wc-block-checkout .wc-block-components-radio-control-accordion-content p:last-child {
	margin-bottom: 0;
}

/* Gateways that ship a logo strip: keep it from setting the row's height. */
.wc-block-checkout .wc-block-components-payment-method-icons img {
	max-height: 1.5rem;
	width: auto;
}

@media (prefers-reduced-motion: reduce) {
	.wc-block-checkout .wc-block-components-radio-control-accordion-option,
	.wc-block-checkout .wc-block-components-radio-control > .wc-block-components-radio-control__option {
		transition: none;
	}
}

/* Order confirmation. WooCommerce's order-confirmation-* blocks ship almost
   unstyled and the theme's copy of the template drops their 24px inline
   headings, so everything below is the page's whole look: one mint band for
   the order's five facts, white cards for the rest. */
.novacelle-order .wp-block-woocommerce-order-confirmation-status h1 {
	font-size: var(--wp--preset--font-size--section);
	margin: 0 0 1rem;
}

.novacelle-order .wp-block-woocommerce-order-confirmation-status p {
	margin: 0;
}

/* The guest-verification copy and form render in a sibling block of the
   status, not inside it. */
.novacelle-order .wc-block-order-confirmation-status-description > p {
	margin: 0;
	max-width: 42rem;
	color: var(--wp--preset--color--muted);
}

/* Guests who open the link after the grace period get the verification form
   instead of the order, and in that state WooCommerce renders no heading: the
   first paragraph is the "Gracias" line, so it takes the title's role. */
.novacelle-order .wp-block-woocommerce-order-confirmation-status:not(:has(h1)) > p:first-child {
	font-family: var(--wp--preset--font-family--heading);
	font-size: var(--wp--preset--font-size--section);
	font-weight: 500;
	line-height: 1.05;
	letter-spacing: -0.02em;
	margin-bottom: 1rem;
}

.novacelle-order .wc-block-order-confirmation-status-description a.button {
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

.novacelle-order .woocommerce-verify-email {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	gap: 1rem;
	margin-top: var(--wp--preset--spacing--50);
}

.novacelle-order .woocommerce-verify-email .form-row {
	margin: 0;
}

.novacelle-order .woocommerce-verify-email .verify-email {
	flex: 1 1 18rem;
	max-width: 28rem;
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
}

.novacelle-order .woocommerce-verify-email label {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--muted);
}

.novacelle-order .woocommerce-verify-email .required {
	color: inherit;
	text-decoration: none;
}

/* WooCommerce pins the field to half its row by id, which no class selector
   can outrank. */
.novacelle-order .woocommerce-verify-email #verify-email,
.novacelle-order .woocommerce-verify-email .input-text {
	width: 100%;
	box-sizing: border-box;
	font: inherit;
	color: var(--wp--preset--color--ink);
	background: #FFFFFF;
	border: 1px solid rgba(10, 10, 10, 0.3);
	border-radius: 8px;
	padding: 0.85rem 1rem;
}

.novacelle-order .woocommerce-verify-email .input-text:focus-visible {
	outline: 2px solid var(--wp--preset--color--teal);
	outline-offset: 1px;
}

.novacelle-order .woocommerce-verify-email .woocommerce-error {
	flex-basis: 100%;
	margin: 0;
	padding: 0;
	list-style: none;
	color: #B3261E;
}

/* The five facts of the order as one band. WooCommerce emits them as a list
   of key/value pairs in a fixed order (number, date, total, email, payment);
   the first three are data, hence the mono face the footer uses for its own
   phone number and email. */
.novacelle-order .wc-block-order-confirmation-summary-list {
	list-style: none;
	margin: var(--wp--preset--spacing--50) 0 0;
	padding: 1.5rem 1.75rem;
	display: flex;
	flex-wrap: wrap;
	gap: 1.25rem 3rem;
	background: var(--wp--preset--color--mint);
	color: var(--wp--preset--color--brand);
	border-radius: 14px;
}

.novacelle-order .wc-block-order-confirmation-summary-list-item {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	min-width: 0;
	overflow-wrap: anywhere;
}

.novacelle-order .wc-block-order-confirmation-summary-list-item__key {
	font-size: var(--wp--preset--font-size--small);
	opacity: 0.8;
}

.novacelle-order .wc-block-order-confirmation-summary-list-item__value {
	font-weight: 500;
}

.novacelle-order .wc-block-order-confirmation-summary-list-item:nth-child(-n + 3) .wc-block-order-confirmation-summary-list-item__value {
	font-family: var(--wp--preset--font-family--mono);
	font-weight: 500;
}

.novacelle-order h2 {
	margin: var(--wp--preset--spacing--50) 0 1rem;
}

.novacelle-order .wp-block-columns h2 {
	margin-top: 0;
}

.novacelle-order .wp-block-columns {
	margin-top: var(--wp--preset--spacing--50);
}

/* Product table. border-spacing:0 rather than collapse so the rounded card
   can clip its corners. */
.novacelle-order .wc-block-order-confirmation-totals__table {
	width: 100%;
	border-collapse: separate;
	border-spacing: 0;
	border: 1px solid rgba(10, 10, 10, 0.08);
	border-radius: 14px;
	background: #FFFFFF;
	overflow: hidden;
}

.novacelle-order .wc-block-order-confirmation-totals__table :is(th, td) {
	padding: 1rem 1.5rem;
	text-align: left;
	border: 0;
	border-top: 1px solid rgba(10, 10, 10, 0.08);
	vertical-align: top;
}

.novacelle-order .wc-block-order-confirmation-totals__table thead th {
	border-top: 0;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
	color: var(--wp--preset--color--muted);
}

.novacelle-order .wc-block-order-confirmation-totals__table :is(th, td):last-child {
	text-align: right;
	white-space: nowrap;
}

.novacelle-order .wc-block-order-confirmation-totals__table tfoot th {
	font-weight: 500;
}

.novacelle-order .wc-block-order-confirmation-totals__table tfoot tr:last-child :is(th, td) {
	font-weight: 700;
}

.novacelle-order .wc-block-order-confirmation-totals__product a {
	color: var(--wp--preset--color--brand);
}

.novacelle-order .wc-block-order-confirmation-totals__product .product-quantity {
	color: var(--wp--preset--color--muted);
	font-weight: 400;
}

/* The address blocks carry WooCommerce's own 4px bordered box around the
   <address> plus the phone and email lines, so the card is that block, not
   the <address>. */
.novacelle-order .wc-block-order-confirmation-shipping-address,
.novacelle-order .wc-block-order-confirmation-billing-address,
.novacelle-order .woocommerce-bacs-bank-details,
.novacelle-order .wc-block-order-confirmation-additional-fields-wrapper > :not(h2) {
	border: 1px solid rgba(10, 10, 10, 0.08);
	border-radius: 14px;
	background: #FFFFFF;
	padding: 1.5rem 1.75rem;
	margin: 0;
}

.novacelle-order address {
	font-style: normal;
}

.novacelle-order .woocommerce-customer-details--phone,
.novacelle-order .woocommerce-customer-details--email {
	margin: 0.75rem 0 0;
	font-family: var(--wp--preset--font-family--mono);
}

.novacelle-order .woocommerce-bacs-bank-details {
	margin-top: var(--wp--preset--spacing--50);
}

.novacelle-order .woocommerce-bacs-bank-details h2 {
	margin-top: 0;
}

.novacelle-order .woocommerce-bacs-bank-details ul {
	list-style: none;
	padding: 0;
	margin: 0;
}

@media (max-width: 600px) {
	.novacelle-order .wc-block-order-confirmation-summary-list {
		padding: 1.25rem 1.5rem;
		gap: 1rem 2rem;
	}

	.novacelle-order .wc-block-order-confirmation-totals__table :is(th, td) {
		padding: 0.85rem 1rem;
	}

	.novacelle-order .wc-block-order-confirmation-shipping-address,
	.novacelle-order .wc-block-order-confirmation-billing-address,
	.novacelle-order .woocommerce-bacs-bank-details {
		padding: 1.25rem 1.5rem;
	}
}

/* Post-purchase account creation. WooCommerce ships the block as a grey
   two-column band with its own 36px margins; it becomes one more white card,
   the pitch on the left and the form on the right, the form capped so it does
   not stretch to half of 1520px. */
.novacelle-order .wc-block-order-confirmation-create-account {
	margin: var(--wp--preset--spacing--50) 0 0 !important;
	padding: 2rem 1.75rem;
	gap: 2rem 3rem;
	align-items: center;
	background: #FFFFFF;
	border: 1px solid rgba(10, 10, 10, 0.08);
	border-radius: 14px;
}

.novacelle-order .wc-block-order-confirmation-create-account-content {
	flex: 1 1 20rem;
}

.novacelle-order .wc-block-order-confirmation-create-account-form-wrapper {
	flex: 1 1 20rem;
	max-width: 30rem;
}

.novacelle-order .wc-block-order-confirmation-create-account-content h2 {
	margin-bottom: 0.75rem;
}

.novacelle-order .wc-block-order-confirmation-create-account-content p {
	color: var(--wp--preset--color--muted);
	margin-bottom: 1.25rem;
}

/* WooCommerce names the list style "checkmark" but registers no CSS for it. */
.novacelle-order .wc-block-order-confirmation-create-account-content ul {
	list-style: none;
	padding: 0;
	margin: 0;
}

.novacelle-order .wc-block-order-confirmation-create-account-content li {
	position: relative;
	padding-left: 2rem;
	margin-bottom: 0.65rem;
}

.novacelle-order .wc-block-order-confirmation-create-account-content li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.2em;
	width: 1.25rem;
	height: 1.25rem;
	border-radius: 50%;
	background: var(--wp--preset--color--mint) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M5.5 10.5l3 3 6-6.5' fill='none' stroke='%23034845' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 100% no-repeat;
}

.novacelle-order .wc-block-order-confirmation-create-account form {
	gap: 1rem;
}

.novacelle-order .wc-block-order-confirmation-create-account form > p {
	font-weight: 500;
}

.novacelle-order .wc-block-order-confirmation-create-account form > p strong {
	display: block;
	font-family: var(--wp--preset--font-family--mono);
	font-weight: 500;
	overflow-wrap: anywhere;
}

/* Same field as the guest email-verification form above it. */
.novacelle-order .wc-block-order-confirmation-create-account .wc-block-components-text-input input {
	border: 1px solid rgba(10, 10, 10, 0.3);
	border-radius: 8px;
	color: var(--wp--preset--color--ink);
}

.novacelle-order .wc-block-order-confirmation-create-account .wc-block-components-text-input input:focus {
	outline: 2px solid var(--wp--preset--color--teal);
	outline-offset: 1px;
	box-shadow: none;
}

/* The strength meter reads red until the password is strong; here it walks
   the site's own scale from error red through amber to teal. */
.novacelle-order .wc-block-components-password-strength {
	font-size: var(--wp--preset--font-size--fine);
	padding-top: 0.5rem;
}

/* WooCommerce keeps the empty meter visible to hold its space, tinted with
   the "too weak" red before anything has been typed. */
.novacelle-order .wc-block-components-password-strength.hidden .wc-block-components-password-strength__meter {
	color: var(--wp--preset--color--muted);
}

.novacelle-order .wc-block-components-password-strength .wc-block-components-password-strength__meter,
.novacelle-order .wc-block-components-password-strength .wc-block-components-password-strength__result,
.novacelle-order .wc-block-components-password-strength .wc-block-components-password-strength__meter[value="1"],
.novacelle-order .wc-block-components-password-strength .wc-block-components-password-strength__meter[value="1"] + .wc-block-components-password-strength__result,
.novacelle-order .wc-block-components-password-strength .wc-block-components-password-strength__meter[value="2"],
.novacelle-order .wc-block-components-password-strength .wc-block-components-password-strength__meter[value="2"] + .wc-block-components-password-strength__result {
	color: #B3261E;
}

.novacelle-order .wc-block-components-password-strength .wc-block-components-password-strength__meter[value="3"],
.novacelle-order .wc-block-components-password-strength .wc-block-components-password-strength__meter[value="3"] + .wc-block-components-password-strength__result {
	color: #B8860B;
}

.novacelle-order .wc-block-components-password-strength .wc-block-components-password-strength__meter[value="4"],
.novacelle-order .wc-block-components-password-strength .wc-block-components-password-strength__meter[value="4"] + .wc-block-components-password-strength__result {
	color: var(--wp--preset--color--teal);
}

.novacelle-order .wc-block-order-confirmation-create-account form .wc-block-order-confirmation-create-account-description p {
	font-size: var(--wp--preset--font-size--fine);
	color: var(--wp--preset--color--muted);
}

.novacelle-order .wc-block-order-confirmation-create-account-description a {
	color: var(--wp--preset--color--brand);
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

.novacelle-order .wc-block-order-confirmation-create-account .woocommerce-error {
	margin: 0 0 1rem;
	padding: 0;
	list-style: none;
	color: #B3261E;
}

/* After the account is created the block collapses to a centered message. */
.novacelle-order .wc-block-order-confirmation-create-account-success {
	padding: 1rem 0;
}

.novacelle-order .wc-block-order-confirmation-create-account-success h3 {
	color: var(--wp--preset--color--brand);
	font-size: var(--wp--preset--font-size--card-title);
	margin: 0 0 0.75rem;
}

.novacelle-order .wc-block-order-confirmation-create-account-success p {
	max-width: 42rem;
	margin: 0 auto;
	color: var(--wp--preset--color--muted);
}

.novacelle-order .wc-block-order-confirmation-create-account-success a {
	color: var(--wp--preset--color--brand);
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

@media (max-width: 600px) {
	.novacelle-order .wc-block-order-confirmation-create-account {
		padding: 1.5rem 1.25rem;
	}

	.novacelle-order .wc-block-order-confirmation-create-account-form-wrapper {
		max-width: none;
	}
}

/* WooCommerce's block-theme stylesheet caps the cart page's title at a
   centered 1000px, which pulls it off the header's left edge; the theme's
   page template already constrains it to the content width like every other
   page title. */
.woocommerce-cart main .wp-block-post-title {
	max-width: var(--wp--style--global--content-size);
}

/* Legal pages ------------------------------------------------------------- */

/* The legal pages (templates/page-legal.html) read as an open book: the text
   flows down the left column and continues at the top of the right one. */
.novacelle-legal > .wp-block-post-title,
.novacelle-legal > .wp-block-post-content {
	/* The theme's 1520px content width would leave each column near 740px, well
	   past a readable measure; 1100px puts them at about 500px. */
	max-width: 1100px;
}

.novacelle-legal > .wp-block-post-content {
	columns: 2;
	column-gap: var(--wp--preset--spacing--60);
	column-rule: 1px solid rgba(3, 72, 69, 0.14);
	/* Justified at the 20px body size a 500px column opens rivers; the label
	   size with automatic hyphenation is what gives the printed-page texture. */
	font-size: var(--wp--preset--font-size--small);
	text-align: justify;
	hyphens: auto;
}

/* Core's constrained layout spaces children with margin-block-start, and a top
   margin survives an unforced column break: whichever block lands at the top of
   the right column would start lower than the left one. Spacing moves to the
   bottom edge, where a column's trailing margin has nothing to push down. */
.novacelle-legal > .wp-block-post-content > * {
	margin-block-start: 0;
	margin-block-end: var(--wp--preset--spacing--30);
}

.novacelle-legal > .wp-block-post-content :is(h2, h3, h4) {
	text-align: left;
	margin-block-end: var(--wp--preset--spacing--20);
	/* No section title stranded at the foot of a column. */
	break-after: avoid;
}

/* What sets one section apart from the next is the air before its heading, and
   that air has to sit on the preceding block's bottom edge for the same reason
   the block spacing does: a top margin would survive the column break and drop
   the right column's first block out of line. At the foot of a column it simply
   goes unseen, which is the behavior a printed page has too. */
.novacelle-legal > .wp-block-post-content > :has(+ h2),
.novacelle-legal > .wp-block-post-content > :has(+ .wp-block-quote),
.novacelle-legal > .wp-block-post-content > :has(+ .novacelle-legal-colophon) {
	margin-block-end: var(--wp--preset--spacing--50);
}

.novacelle-legal > .wp-block-post-content > :has(+ :is(h3, h4)) {
	margin-block-end: var(--wp--preset--spacing--40);
}

.novacelle-legal > .wp-block-post-content h2 {
	font-size: var(--wp--preset--font-size--heading-sm);
}

.novacelle-legal > .wp-block-post-content .wp-block-list {
	padding-inline-start: 1.25rem;
	break-inside: avoid;
}

.novacelle-legal > .wp-block-post-content p {
	orphans: 3;
	widows: 3;
}

/* The opening and closing notices run as preambles across both columns. Core's
   quote rule draws them with a left bar, which reads as a pull quote rather
   than as part of the document; the legal pages want unmarked running text. */
.novacelle-legal > .wp-block-post-content > .wp-block-quote {
	column-span: all;
	text-align: left;
	margin-block-end: var(--wp--preset--spacing--50);
	break-inside: avoid;
	border: 0;
	padding-inline: 0;
}

/* A spanning block ends the column run rather than sitting inside it, so here a
   top margin is the only one that opens space above the closing notice — the
   preceding block's bottom margin is spent inside whichever column it ended in.
   The opening preamble is the first child and keeps hugging the title. */
.novacelle-legal > .wp-block-post-content > .wp-block-quote:not(:first-child) {
	margin-block-start: var(--wp--preset--spacing--50);
}

/* One column below the theme's wide breakpoint: two 45vw columns of justified
   15px text stop being a book and start being a newspaper clipping. */
@media (max-width: 900px) {
	.novacelle-legal > .wp-block-post-content {
		columns: 1;
		column-rule: none;
		text-align: left;
		hyphens: none;
	}
}
