/* Copper & Ink — site chrome and utility CSS that theme.json / block settings can't express. */

/* Photo-hero cover blocks (Home + Shop hero): the ink-scrim gradient tapers to
   only ~15-22% dark near the top of the bottom-anchored content block, right
   where the small blush-colored eyebrow label sits. At a portrait mobile crop
   (object-fit:cover with no custom focal point on the Home hero), that spot
   can land on the photo's brightest area (blonde hair), dropping the blush
   text's contrast against the photo well below a comfortable reading level.
   A text-shadow keeps the eyebrow and heading legible no matter what part of
   the photo ends up behind them, independent of crop or future image swaps. */
.wp-block-cover__inner-container h1,
.wp-block-cover__inner-container p {
	text-shadow: 0 1px 3px rgba(28, 25, 23, 0.55);
}

/* Site header. WordPress wraps the "header" template part in its own semantic
   <header class="wp-block-template-part"> (from theme.json's templateParts
   area:"header"); that outer wrapper has zero extra height beyond our own
   content, so position:sticky has to go on IT, not on our inner .site-header
   div, or there's no room in the containing block for the stick to hold. */
header.wp-block-template-part {
	position: sticky;
	top: 0;
	z-index: 50;
}

/* Logged-in visitors also have WordPress's own admin bar fixed to the true
   top of the viewport (position:fixed, z-index:99999 — far above this
   header's z-index:50), at whatever height core currently gives it: 32px
   on desktop, 46px at core's own <=782px breakpoint. Core tracks both
   values in --wp-admin--admin-bar--height on :root, so reading that here
   instead of hardcoding either number keeps this in sync with core rather
   than duplicating its breakpoint. Our header still sticks to a literal
   top:0 above, though, so once scrolled its top few dozen pixels — the
   site title, the top of the Book Now button — land directly underneath
   the admin bar's much higher stacking context and get visibly sliced
   off. Scoped to body.admin-bar so a logged-out visitor's header, which
   never shares the viewport with an admin bar, keeps sticking to the true
   top exactly as before. */
body.admin-bar header.wp-block-template-part {
	top: var(--wp-admin--admin-bar--height, 32px);
}

/* ...except at core's own "Smartphone" breakpoint (max-width:600px, set by
   core's admin-bar.css, not this theme's own 599px mobile line — they're a
   pixel apart by coincidence, not the same rule), where core switches the
   admin bar from position:fixed to position:absolute so it scrolls away
   with the rest of the page instead of staying pinned. Reserving 46px for
   a bar that's no longer fixed there just leaves an empty 46px gap above
   the header once scrolled — confirmed live, and exactly what this
   reverts back to a plain top:0 for. */
@media (max-width: 600px) {
	body.admin-bar header.wp-block-template-part {
		top: 0;
	}
}

/* Anchor-jump targets (nav's "Contact" link -> /about/#contact; also covers
   browser "find on page" and any future in-page anchor) land at scrollY=0
   by default, which puts their top few dozen pixels directly underneath
   this sticky header instead of below it — confirmed live, the #contact
   section's own heading was fully hidden. scroll-margin-top reserves that
   space so the browser stops short of the header instead of behind it.
   139px covers the header's tallest state (2-line wordmark on narrow
   phones); 100px covers its normal single-line height above 599px. */
#contact {
	scroll-margin-top: 160px;
}
@media (min-width: 600px) {
	#contact {
		scroll-margin-top: 100px;
	}
}
body.admin-bar #contact {
	scroll-margin-top: calc(160px + var(--wp-admin--admin-bar--height, 32px));
}
@media (min-width: 600px) {
	body.admin-bar #contact {
		scroll-margin-top: calc(100px + var(--wp-admin--admin-bar--height, 32px));
	}
}
@media (max-width: 600px) {
	body.admin-bar #contact {
		scroll-margin-top: 160px;
	}
}

/* The Navigation block's mobile/tablet menu overlay (core's own
   #modal-N, z-index:100000) renders as a descendant of this header — and
   because the header above is itself positioned with an explicit z-index,
   it creates a stacking context that traps the overlay's huge z-index
   inside it. The overlay can then only out-rank other things INSIDE the
   header; it can't out-rank a fixed, higher-stacked sibling elsewhere on
   the page, like the floating chat launcher (assets/css/chatbot.css,
   z-index:1000) or the mobile action bar. Opening the overlay adds
   `has-modal-open` to <html> for exactly as long as it's open (also core's
   own doing) — raise the header's own stacking level only for that window
   so the whole subtree, overlay included, actually paints on top. */
html.has-modal-open header.wp-block-template-part {
	z-index: 100000;
}

.site-header .wp-block-navigation__responsive-container-open {
	color: #fff;
}

/* text-decoration:none is enough for the native wp:site-title block, but
   parts/header.html now uses a plain paragraph+link instead (see the
   header layout comment further down for why) so the wordmark can show
   shortened text without changing the site's real name elsewhere — and a
   plain <a> gets its own explicit color from theme.json's global link
   style (terracotta), which — same root cause as the customer-account
   icon fix above — wins over the porcelain color inherited from this
   paragraph's own textColor. Re-asserting it here is what actually makes
   the wordmark porcelain instead of terracotta. */
.site-header .wp-block-site-title a {
	color: inherit;
	text-decoration: none;
}

.ci-logo-mark {
	width: 36px;
	height: 36px;
	flex-shrink: 0;
}

/* Customer Account icon (parts/header.html, placed explicitly inside
   .ci-header-icons — see the header layout comment further down for why).
   The block's own style attribute sets color:#f8f3ee (porcelain) on the
   OUTER wrapper, the same way the Mini-Cart block next to it gets its
   porcelain color — but unlike Mini-Cart, that alone isn't enough here:
   theme.json's global link color gives every <a> its own explicit color
   (terracotta), and an element's own explicit color always wins over one
   merely inherited from an ancestor, so the wrapper's porcelain never
   reaches the actual ".wc-block-customer-account__link" anchor inside it
   (confirmed by comparing computed color at each level — the wrapper
   reads porcelain, the link and everything inside it reads terracotta).
   Re-asserting it here, right on the link, is what actually makes the icon
   porcelain like its neighbor. (A rule here once tried to color a class
   called ".wc-block-customer-account__account-icon" — inspecting the
   rendered DOM shows that class doesn't exist anywhere on this block's
   markup, so that rule was dead weight and has been removed.) */
.wp-block-woocommerce-customer-account {
	display: flex;
	align-items: center;
	flex-shrink: 0;
}

.wc-block-customer-account__link {
	display: flex;
	color: inherit;
}

/* Guest-facing icon only — skip the gravatar image swap for logged-in testing. */
.wc-block-customer-account__avatar {
	display: none;
}

/* Header layout: three top-level groups in parts/header.html — the logo
   (.ci-header-brand), the nav, and .ci-header-icons (which explicitly
   contains the customer-account, mini-cart, and Book Now button). The
   customer-account block is placed there deliberately rather than left to
   WordPress's Block Hooks auto-insertion, which anchors to the nav block
   rather than the mini-cart and would otherwise land it as a fourth,
   separate top-level item between the nav and this wrapper — splitting it
   away from the cart icon it's meant to sit beside. Since the block
   already exists in the template, Block Hooks detects that and skips its
   own insertion (confirmed live: exactly one
   .wp-block-woocommerce-customer-account renders, not two).

   With exactly those three top-level items, the block's own declared
   justifyContent:space-between (site-header's own attributes, above)
   already centers the nav in the space between the logo and the icon
   cluster at desktop widths — no override needed there.

   Below desktop widths the nav only ever shows its hamburger toggle (the
   tablet rule further down and the <600px mobile behavior both collapse
   its real links into the overlay), so centering it in a now near-empty
   middle region reads as stranded; group it with the icon cluster instead
   via margin-left:auto on the nav, which overrides space-between's own
   distribution at that breakpoint. */
.ci-header-icons {
	gap: 14px;
}

/* The 14px gap above is uniform, but the visible spacing it produces isn't:
   the account and cart icons each carry their own 30px glyph inside a
   50px clickable box (WooCommerce's default 10px padding on every side),
   while the Book Now button's colored background fills its box edge to
   edge with no such inset. Measured against each element's actual visible
   pixels (not its clickable box), the account-to-cart gap comes out to
   ~44.5px — both icons' 10px insets plus the 14px gap — while the
   cart-to-button gap is only ~29.3px — one icon inset plus the 14px gap,
   since the button has none of its own.

   Shifting the cart icon closes the wider gap on its left, but (since
   whatever's after it in the row shifts along with it) leaves the
   narrower gap on its right completely untouched — margin-left and
   margin-right pull two different, independent gaps, not one shared
   one, so both are needed together: -8px on the left brings the account
   gap down to ~36.5px, +8px on the right pushes the button gap up to
   ~37.3px, landing the two within a pixel of each other without
   touching the already-correct 14px flex-gap or either element's own
   proportions. */
.ci-header-icons > .wc-block-mini-cart {
	margin-left: -8px;
	margin-right: 8px;
}

@media (max-width: 1023px) {
	.site-header {
		justify-content: flex-start;
		gap: 14px;
	}
	.site-header > .ci-primary-nav {
		margin-left: auto;
	}
}

/* Site title: keeps to one line at narrow mobile widths instead of wrapping
   under the squeeze from the hamburger/account icons sharing the row. */
@media (max-width: 400px) {
	.site-header .wp-block-site-title {
		font-size: 18px !important;
	}
}

/* Persistent mobile action bar (Book / Shop): shown inline right under the
   header on load, then pins to the viewport bottom once scrolled past its
   natural position (assets/js/mobile-actionbar.js toggles .is-fixed and
   body.has-fixed-actionbar) — matching the source design's own note ("shown
   above; reappears fixed to viewport bottom while browsing/booking"). Hidden
   above mobile widths. !important beats core's own .is-layout-flex{display:
   flex} utility class, which the Group block's layout support prints after
   theme stylesheets. */
.ci-mobile-actionbar {
	display: none !important;
}

@media (max-width: 599px) {
	.ci-mobile-actionbar {
		display: flex !important;
	}
	/* The buttons' own 50% width is relative to this wrapper, not the bar —
	   without stretching it full-width first, core's flex default (0 1 auto)
	   leaves the wrapper (and so both buttons) shrunk to their content size. */
	.ci-mobile-actionbar .wp-block-buttons {
		width: 100%;
		/* Core's width-50 class is calc(50% - var(--wp--style--block-gap)*.5) —
		   it reads this custom property directly, not the literal `gap` the
		   layout's own blockGap:0 setting applies, so it still subtracts half
		   of the theme's global 24px gap unless this is zeroed too. Must be a
		   unit (0px), not a bare 0 — calc() can't subtract a unitless number
		   from a percentage, so an unitless zero here invalidates the whole
		   width declaration and silently falls back to content-box sizing. */
		--wp--style--block-gap: 0px;
	}
	.ci-mobile-actionbar .wp-block-button__link {
		white-space: nowrap;
	}
	.ci-mobile-actionbar.is-fixed {
		position: fixed;
		inset: auto 0 0;
		z-index: 40;
	}
	body.has-fixed-actionbar {
		padding-bottom: 56px;
	}
	.ci-header-desktop-actions {
		display: none !important;
	}
	/* The mini-cart sits outside .ci-header-desktop-actions so phones keep a
	   cart entry point (the action bar's "Shop" goes to the landing page, not
	   the cart). Five items now share the row — logo, title, hamburger,
	   account, cart — so pull the header's 28px side padding and the block
	   gap in to keep the title on one line at 375px. */
	.site-header {
		padding-left: 16px !important;
		padding-right: 16px !important;
		gap: 14px;
	}
	/* The cart icon's own margin-right:8px (further up, alongside its
	   matching margin-left:-8px) exists to balance its visible gap against
	   the Book Now button next to it. With Book Now hidden here, that
	   margin has nothing left to balance — it just pushes the cart icon
	   8px further from the header's right edge than the logo sits from the
	   left, breaking the symmetry between them. Zeroing it only at this
	   width, where Book Now is actually gone, restores that match without
	   touching the desktop/tablet spacing it's still doing real work for. */
	.ci-header-icons > .wc-block-mini-cart {
		margin-right: 0;
	}
}

/* Tablet / small-laptop header (600–1023px). Between the phone action bar
   and a full desktop there is no room for the logo, five nav links, the
   account + cart icons, and the Book Now button on one row: the site title
   wraps to three lines and "Book Now" wraps letter-by-letter on an iPad in
   portrait (768px), pushing the sticky header to ~210px tall. Collapse the
   nav into its hamburger overlay (already styled via the block's overlay
   colors) until desktop widths, and keep the title and button on one line.
   Core only shows the hamburger below 600px, so both its open button and
   its inline container need overriding here (specificity beats core's
   `.x:not(.hidden-by-default):not(.is-menu-open)` rules). */
@media (min-width: 600px) and (max-width: 1023px) {
	.site-header .ci-primary-nav .wp-block-navigation__responsive-container:not(.is-menu-open) {
		display: none;
	}
	.site-header .ci-primary-nav .wp-block-navigation__responsive-container-open {
		display: flex;
	}
	.site-header .wp-block-site-title,
	.ci-header-desktop-actions .wp-block-button__link {
		white-space: nowrap;
	}
}

/* Footer contact lines: phone and email are real tap-to-call / mailto links
   (not just text), styled to sit flush with the surrounding stone-colored
   copy rather than picking up the global link color on the ink background. */
.ci-footer-contact a {
	color: inherit;
	text-decoration: none;
}

.ci-footer-contact a:hover {
	text-decoration: underline;
}

/* Order confirmation "What happens next" note (inc/woocommerce/woocommerce-setup.php),
   printed by the thank-you page's Additional Information block. */
.ci-order-next-steps {
	margin: 32px 0 0;
	padding: 20px 24px;
	border: 1px solid var(--wp--preset--color--hairline);
	border-top: 1.5px solid var(--wp--preset--color--copper);
	background: var(--wp--preset--color--porcelain);
	font-size: 14px;
	line-height: 1.7;
}

.ci-order-next-steps__title {
	margin: 0 0 8px;
	font-family: var(--wp--preset--font-family--display);
	font-size: 22px;
	font-weight: 400;
}

.ci-order-next-steps p {
	margin: 0 0 10px;
}

.ci-order-next-steps__hours {
	color: var(--wp--preset--color--text-secondary);
	font-size: 13px;
}

/* Generic "hide on mobile" utility for sections the source design's own
   mobile frames omit outright (not just reflow) — e.g. Home's gallery and
   trust row, the PDP fulfillment line, Shop Landing's secondary CTA, its
   Colorsafe concern tile, and its pickup/delivery info row, and the PLP
   sort control. */
@media (max-width: 599px) {
	.ci-hide-mobile {
		display: none !important;
	}
}

/* Every template/pattern uses a consistent 56px desktop side edge-padding
   (page <main> wrappers, section groups/columns), matching an attribute
   selector on the inline style since patterns author padding inline. On a
   375px phone, 56px+56px alone already eats a third of the viewport, and
   patterns that nest a second 56px-padded element inside (e.g. About's
   hero column, which sits inside the root's own auto side padding) leave
   so little width that headings wrap mid-word. Scale it down uniformly for
   every page instead of patching each pattern's padding individually. */
@media (max-width: 599px) {
	[style*="padding-left:56px"] {
		padding-left: 20px !important;
	}
	[style*="padding-right:56px"] {
		padding-right: 20px !important;
	}
}

/* WooCommerce: style the native Local Pickup / flat-rate shipping radios to read as
   the two fulfillment cards from the source design (exact custom UI would require
   overriding WooCommerce Blocks' Checkout extensibility points).
   The radio <input> is absolutely positioned at top:16px;left:16px (20x20px) by
   WooCommerce's own CSS, expecting the option's left padding to clear it — a
   uniform padding here overlaps the input right over the label text, so the
   left side needs enough room (20px input + a gap) while the rest stays even. */
.wc-block-components-radio-control__option {
	border: 1px solid var(--wp--preset--color--hairline);
	border-radius: 4px;
	padding: 16px 16px 16px 48px !important;
	margin-bottom: 10px;
}

.wc-block-components-radio-control__option-checked {
	border-color: var(--wp--preset--color--copper);
	border-width: 1.5px;
	background: var(--wp--preset--color--porcelain);
}

/* Shop by concern: the source design's mobile frame drops to a 2-column grid
   and drops the 5th (Colorsafe) tile entirely -- it resurfaces in the More
   to Explore grid below instead of vanishing outright (.ci-mobile-only-tile,
   just below), so mobile still gets a clean 2x2 here and a clean 2x3 there. */
@media (max-width: 599px) {
	.ci-concern-grid {
		grid-template-columns: repeat(2, 1fr) !important;
	}
	.ci-concern-grid > :nth-child(5) {
		display: none !important;
	}
}

/* Shop more categories (patterns/shop-more-categories.php): same tile
   treatment as Shop by Concern. On desktop this is a 5-tile row; the
   Colorsafe tile (.ci-mobile-only-tile) only joins it at mobile widths, so
   it isn't shown twice on the same page. */
/* !important on both rules below: the tile itself carries an inline
   display:block (same shared markup as every other tile in this pattern),
   which otherwise beats a plain external class on specificity regardless
   of the media query. */
.ci-mobile-only-tile {
	display: none !important;
}

@media (max-width: 599px) {
	.ci-more-categories-grid {
		grid-template-columns: repeat(2, 1fr) !important;
	}
	.ci-more-categories-grid .ci-mobile-only-tile {
		display: block !important;
	}
}

/* Salon favorites (patterns/shop-favorites.php): a real WooCommerce Product
   Collection block showing whatever 3 products are marked "Featured", not
   static markup — so at mobile widths core's own product-template grid CSS
   is what actually applies, and it steps a 3-column layout down to 2 fixed
   155px columns rather than 1. With exactly 3 items that leaves the 3rd
   product stranded alone on its own half-empty row. Forcing a single column
   below 600px gives every product the full row and matches how product
   grids read elsewhere on the site at this width. */
@media (max-width: 599px) {
	.ci-favorites-grid .wc-block-product-template {
		grid-template-columns: 1fr !important;
	}
}

/* Book page: the two tap-to-call buttons sit side by side on desktop, but at
   phone widths that leaves each one ~180px wide and the phone number wraps
   mid-string ("Call for Hair · 865-" / "982-9911"). Stack them full-width so
   the number a caller is about to tap reads on one line. */
@media (max-width: 599px) {
	/* The section only sets top/bottom padding inline, so core's default for
	   a Group with a background (`:where(.wp-block-group.has-background)
	   { padding: 1.25em 2.375em }`) adds 47.5px side gutters — a quarter of a
	   375px phone — before the card's own padding even starts. */
	.ci-book-phone-section {
		padding-left: 20px !important;
		padding-right: 20px !important;
	}
	/* The card keeps its desktop 48px inner padding on a phone, which leaves
	   a ~180px column for the copy and the call buttons inside a ~280px card. */
	.ci-book-phone-card {
		padding: 32px 20px !important;
	}
	/* The buttons block is itself a child of the card's vertical, center-
	   aligned flex layout, so it shrinks to the widest button unless it is
	   told to fill the card. */
	.ci-book-phone-buttons {
		width: 100%;
		flex-direction: column;
		align-items: stretch;
	}
	.ci-book-phone-buttons .wp-block-button,
	.ci-book-phone-buttons .wp-block-button__link {
		width: 100%;
		text-align: center;
	}
}

/* Color chart download card: the source design's mobile frame stacks the
   swatch grid, copy, and button instead of a nowrap flex row (which has no
   room for all three on a narrow viewport and forces the button off-screen). */
@media (max-width: 599px) {
	.ci-color-chart-card {
		flex-direction: column !important;
		align-items: flex-start !important;
		margin-left: 20px !important;
		margin-right: 20px !important;
		padding: 24px !important;
	}
}

/* Home gallery: the tall mosaic tile spans 2 grid rows via the Image
   block's own rowSpan control, but the block's "aspect ratio + scale"
   feature fixes the <img> to a flat 3:4 box computed from its rendered
   WIDTH — it has no way to know the taller, row-spanned box its own
   figure ends up in, so the image stops short and leaves empty space
   below it. Once both width and height are pinned to 100% here, the
   image's own aspect-ratio no longer drives sizing (only object-fit's
   crop does), so it fills the actual grid cell instead. */
.ci-gallery-tall img {
	width: 100%;
	height: 100%;
}

/* Reusable line-length constraints for headings/paragraphs. "max-width" has
   no corresponding block attribute in core, so applying it as inline style
   (as several patterns originally did) leaves the block's saved markup
   unrepresentable from its own attributes — WordPress's block validator
   then flags it as "unexpected or invalid content" the moment an editor
   re-parses it, even though the front end still renders fine. Routing the
   same values through named classes keeps every block re-editable without
   a recovery prompt. */
.ci-max-w-380 {
	max-width: 380px;
}
.ci-max-w-420 {
	max-width: 420px;
}
/* Senior pricing card: centred, capped at the design's 520px, and never wider
   than the 64px page gutters the other service cards use. */
.ci-max-w-520 {
	max-width: 520px;
	width: calc(100% - 128px);
}
.ci-max-w-600 {
	max-width: 600px;
}
.ci-max-w-620 {
	max-width: 620px;
}
.ci-max-w-640 {
	max-width: 640px;
}
.ci-max-w-700 {
	max-width: 700px;
}
.ci-hero-heading {
	max-width: 780px;
}
.ci-min-h-340 {
	min-height: 340px;
}
.ci-max-w-380-center {
	max-width: 380px;
	margin-left: auto;
	margin-right: auto;
}

/* Buttons whose label must never wrap to a second line inside a tight
   flex row (same reasoning as above — "white-space" isn't a supported
   button block style, so it has to live in a class, not inline). */
.ci-nowrap {
	white-space: nowrap;
}

/* Short copper divider dash used above section sub-headings. The block's
   own dimensions support only exposes height, not width, so the 28px
   short-dash width (vs. the full-bleed default for "is-style-wide") is
   set here instead of as an unrepresented inline style. */
.ci-divider-short {
	width: 28px;
}

/* About hero portrait: a real wp:image block (replaceable via the Site
   Editor / Media Library) filling its column at the source design's
   min-height, instead of a fixed aspect-ratio box. */
.ci-about-portrait {
	height: 100%;
	min-height: 340px;
	margin: 0;
}

.ci-about-portrait img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Nails by Jacki: the two small work-sample thumbnails next to the heading.
   Real wp:image blocks (replaceable via the Site Editor / Media Library);
   this just pins the on-page box to the source design's 52x52 icon size.

   The crop is done by clipping, not object-fit, on purpose: the core lightbox
   sizes its enlarged view to the <img> element's rendered aspect ratio, so an
   object-fit:cover square would enlarge to a square crop of the photo. A
   portrait photo (the shipped ones are 240x427) is scaled to the box width and
   keeps its natural ratio; flex centres it and the figure's overflow clips it,
   which looks the same on the page but lets the lightbox show the whole photo.
   A landscape photo can't fill the box that way, so min-height + object-fit
   turn it into a centred square crop instead (no distortion; the lightbox then
   shows that square, which is core's default behaviour anyway). */
.ci-nail-icons {
	flex-shrink: 0;
}

.ci-nail-icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 52px;
	height: 52px;
	flex-shrink: 0;
	margin: 0;
	overflow: hidden;
	border-radius: 10px;
}

.ci-nail-icon img {
	flex-shrink: 0;
	width: 100%;
	height: auto;
	min-height: 100%;
	object-fit: cover;
}

/* Both thumbnails use the core Image block lightbox ("Expand on click"), so a
   click/tap opens the full-size photo in an overlay. Core drops a 20px zoom
   button 16px from the top-right corner, which lands mid-image on a 52px box;
   tuck it into the corner so it reads as a badge on hover/focus. The whole
   image is still the click target (core sets cursor: zoom-in on the img).
   Core writes top/right as inline styles from its view script
   (callbacks.setButtonStyles), so these need !important to win. */
.ci-nail-icon.wp-lightbox-container button {
	top: 4px !important;
	right: 4px !important;
}

/* Product descriptions: imported All-Nutrient ingredient lists contain long
   unbreakable words ("Octylacrylamide/Acrylates/Butylaminoethyl"), and any
   pasted URL is one too. At phone widths one of those sets the paragraph's
   min-content width wider than its column, which pushes the whole document
   wider than the viewport and leaves the product page horizontally
   scrollable. Let long words break inside the product description/summary. */
.woocommerce-Tabs-panel,
.wp-block-woocommerce-product-details,
.wp-block-woocommerce-product-summary,
.woocommerce-product-details__short-description {
	overflow-wrap: anywhere;
	word-break: break-word;
}

/* Product cards */
.ci-product-figure {
	background: var(--wp--preset--color--white);
	display: flex;
	align-items: center;
	justify-content: center;
}

.ci-product-figure img {
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
}

/* Shop sorting dropdown (WooCommerce's Catalog Sorting block on the product
   archive) ships as a bare native <select> -- no border-radius, no padding,
   default OS arrow. Replacing the native arrow (appearance:none) needs its
   own drawn chevron, since a custom border otherwise sits oddly next to it. */
.woocommerce-ordering select.orderby {
	appearance: none;
	-webkit-appearance: none;
	padding: 10px 36px 10px 14px;
	border: 1px solid var(--wp--preset--color--hairline);
	border-radius: 4px;
	background-color: var(--wp--preset--color--white);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23B86943' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 12px center;
	background-size: 12px;
	font-family: inherit;
	font-size: 13px;
	color: var(--wp--preset--color--ink);
	cursor: pointer;
}
.woocommerce-ordering select.orderby:focus {
	outline: none;
	border-color: var(--wp--preset--color--copper);
	box-shadow: 0 0 0 1px var(--wp--preset--color--copper);
}

/* Product archive pagination ("1 2 3 4 Next Page"): WordPress core's
   Query Pagination block ships each number as a bare inline link/span with no
   padding, so a single digit is only as wide as its own glyph -- confirmed
   live at ~6-12px wide, well under a usable touch target -- while "Next Page"
   right next to them is comfortably sized just from its own text. */
.wp-block-query-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 40px;
	height: 40px;
	padding: 0 6px;
	border-radius: 4px;
	font-size: 14px;
	font-weight: 600;
	color: var(--wp--preset--color--text-secondary);
	text-decoration: none;
}
.wp-block-query-pagination .page-numbers.current {
	background: var(--wp--preset--color--terracotta);
	color: var(--wp--preset--color--white);
}
.wp-block-query-pagination a.page-numbers:hover {
	background: var(--wp--preset--color--porcelain);
	color: var(--wp--preset--color--ink);
}

/* Product grid cards (WooCommerce's Product Collection block -- Shop,
   category archives, salon favorites): each card just stacks image, title,
   price, and button top-to-bottom with nothing holding a shared baseline, so
   a title that wraps to 2 lines ("Colorsafe Leave-In Detangler") pushes that
   card's price and button visibly lower than its 1-line-title neighbors in
   the same row -- confirmed live, a 32px title-height difference carried
   straight through to the button position. The button is pinned to the
   card's bottom edge (margin-top:auto) so it lands at the same Y in every
   card regardless of title length; line-clamp caps a title at 2 lines
   (ellipsis beyond that) so one absurdly long name can't still break it.
   Deliberately NOT reserving a fixed 2-line height on every title (an
   earlier version of this rule did) -- that kept price/button position
   identical across cards too, but left visible dead space under every
   short, single-line title, which read as an odd gap above the star
   rating. Letting the title size naturally is the more common tradeoff in
   real product grids -- but price and button still need to land on the
   same line as each other across cards (requested separately), so the
   margin-top:auto that anchors them to the bottom lives on the PRICE, not
   the button: price absorbs all the leftover flexible space above it
   (whether that's a short title, a long one, or a title plus a star
   rating), and the button just follows immediately after at its own fixed
   size -- so price and button move down together as one fixed-position
   unit regardless of what's above them. */
.wc-block-product-template li.wc-block-product {
	display: flex;
	flex-direction: column;
}
.wc-block-product-template li.wc-block-product .wp-block-post-title {
	display: -webkit-box;
	overflow: hidden;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
}
.wc-block-product-template li.wc-block-product .wp-block-woocommerce-product-price {
	margin-top: auto;
}
.wc-block-product-template li.wc-block-product .wp-block-woocommerce-product-button {
	padding-top: 16px;
}

/* Product Rating block (grid cards, once a product has reviews -- hidden
   entirely otherwise). Uses the same "WooCommerce" icon-font two-layer trick
   as the classic .star-rating display: the outer element's own ::before
   draws a full 5-star row as the empty/background layer, and a width-
   clipped inner <span> plus its own ::before draws the filled row on top.
   Both ::before pseudo-elements inherit color from their real host element,
   so setting color on the two hosts (rather than the pseudo-elements
   directly) is enough to two-tone it -- confirmed live it otherwise inherits
   plain ink/black text color with no accent at all. */
.wc-block-components-product-rating__stars {
	color: var(--wp--preset--color--hairline);
}
.wc-block-components-product-rating__stars span {
	color: var(--wp--preset--color--terracotta);
}
