/**
 * Commerce: product card, badges, price rows, grid, quantity stepper.
 *
 * From the canvas — Components.dc.html for the card and the price block,
 * Category.dc.html for the grid and toolbar, Main.dc.html for the featured row.
 *
 * The card styles address two selectors on purpose. `ul.products li.product` is
 * what WooCommerce prints on every archive, and this theme ships no template
 * overrides, so that is the production card. `.hp-product-card` is the same card
 * where the theme renders one itself (the home page featured row). Both resolve
 * to one treatment rather than two that drift apart.
 *
 * The brand line, club price and unit price are not core WooCommerce output.
 * They come from theme callbacks on the loop hooks — see inc/class-commerce.php
 * — so no core template is copied to add them.
 */

/* ---- grid ----
 *
 * Four across is the canvas's number and it was drawn against a 1248px
 * container. The catalogue pages now run to 1408px, where four cards are 337px
 * wide each — a card the size of a small poster for a 500ml bottle. Five above
 * 85rem brings that back to 265px, which is a card, and it fits a third more of
 * the catalogue on the first screen without shrinking anything below the size
 * the design was drawn at.
 */

.woocommerce ul.products{
	display: grid;
	grid-template-columns: repeat(var(--hp-grid-columns, 4), minmax(0, 1fr));
	gap: var(--hp-space-4);
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (min-width: 85rem) {
	.woocommerce ul.products{
		grid-template-columns: repeat(var(--hp-grid-columns, 5), minmax(0, 1fr));
	}
}

.woocommerce ul.products::before,
.woocommerce ul.products::after {
	content: none;
}

@media (max-width: 60rem) {
	.woocommerce ul.products{
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

@media (max-width: 45rem) {
	.woocommerce ul.products{
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--hp-space-4);
	}
}

/**
 * WooCommerce's small-screen sizing, neutralised.
 *
 * inc/assets.php dequeues that sheet, so normally nothing here matches. It is
 * kept because the sheet is one `wp_enqueue_style` away from returning — a
 * plugin, a filter, a WooCommerce update — and when it does it out-specifies
 * the card rule below by one attribute selector and puts float sizing back on
 * the grid items. Matching its selector shape exactly means the theme wins on
 * load order, with no !important.
 */
@media (max-width: 768px) {
	.woocommerce ul.products[class*="columns-"] li.product,
	.woocommerce-page ul.products[class*="columns-"] li.product {
		width: auto;
		float: none;
		clear: none;
		margin: 0;
	}
}

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

.woocommerce ul.products li.product{
	display: flex;
	flex-direction: column;
	width: auto;
	margin: 0;
	padding: 0;
	background: var(--hp-surface);
	border: 1px solid var(--hp-border);
	border-radius: var(--hp-radius);
	overflow: hidden;
	text-align: start;
	transition:
		border-color var(--hp-duration-fast) var(--hp-ease),
		box-shadow var(--hp-duration) var(--hp-ease-out),
		transform var(--hp-duration) var(--hp-ease-out);
}

.woocommerce ul.products li.product:hover,
/* Keyboard users get the same treatment: the card reacts when anything inside
 * it takes focus, so tabbing through a grid is as legible as pointing at it. */
.woocommerce ul.products li.product:focus-within{
	border-color: var(--hp-border-strong);
	transform: translateY(var(--hp-lift-card));
	box-shadow: var(--hp-shadow-lift);
}

/* ---- the media frame ----
 * Printed by Commerce::open_loop_media around core's thumbnail. It is the box
 * that clips the image's hover zoom; see the comment on that method for why the
 * card itself cannot do the clipping.
 */

.hp-loop-media {
	display: block;
	position: relative;
	overflow: hidden;
	background: var(--hp-surface-subtle);
}

.woocommerce ul.products li.product .hp-loop-media img,
.woocommerce ul.products li.product-category .hp-loop-media img {
	/* The margin that separated image from text moves to the frame, so the
	 * zoom happens inside the frame rather than inside the gap. */
	margin: 0;
	transition: transform var(--hp-duration-slow) var(--hp-ease-out);
}

.woocommerce ul.products li.product:hover .hp-loop-media img,
.woocommerce ul.products li.product:focus-within .hp-loop-media img,
.woocommerce ul.products li.product-category:hover .hp-loop-media img,
.woocommerce ul.products li.product-category:focus-within .hp-loop-media img {
	transform: scale(1.045);
}

.woocommerce ul.products li.product .hp-loop-media {
	margin-block-end: var(--hp-space-3);
}

/* WooCommerce wraps the thumbnail and title in one anchor; it becomes the media
 * frame so the badge and wishlist dot can sit over it. */
.woocommerce ul.products li.product a.woocommerce-LoopProduct-link{
	position: relative;
	display: block;
	color: inherit;
}

.woocommerce ul.products li.product img{
	display: block;
	width: 100%;
	/* Slightly wider than tall. A square frame on a 337px card is 337px of
	 * photograph before a single word of the product, which is what made the
	 * grid feel airy rather than dense. These are bottles shot centred with
	 * headroom, so taking 12% off the height crops background, not product. */
	aspect-ratio: 1 / 0.88;
	margin: 0;
	object-fit: cover;
	background: var(--hp-surface-subtle);
}

/* Everything below the image shares one padded column.
 *
 * Core's content-product.php wraps the image, brand, title, price and the
 * plugin's club block in a single anchor, and leaves the add-to-cart button
 * outside it as a sibling. So the card is a column at two levels, and the
 * padding cannot live on the anchor -- that would inset the image too. It goes
 * on the anchor's non-image children and on the li's non-anchor children
 * instead, which keeps the image flush to the card edge while every text row
 * lines up.
 */
.woocommerce ul.products li.product a.woocommerce-LoopProduct-link{
	display: flex;
	flex-direction: column;
	gap: var(--hp-space-2);
}

/* The anchor absorbs the slack in a short card, so the buttons across a row
 * land on one line even when only some products carry a club price. */
.woocommerce ul.products li.product a.woocommerce-LoopProduct-link {
	flex: 1;
	padding: 0;
}

.woocommerce ul.products li.product .hairport-club-pricing {
	margin-block-start: auto;
}

/* The media frame is excluded alongside the bare <img> it replaced: the image
 * stays flush to the card edge, every text row is inset. */
.woocommerce ul.products li.product a.woocommerce-LoopProduct-link > :not(img):not(.hp-loop-media) {
	padding-inline: var(--hp-space-3);
}

/* Inside a card the label is fine print and the amount is the price. */
.woocommerce ul.products li.product .hairport-club-pricing .hairport-club-member-price {
	font-size: var(--hp-text-xs);
	font-weight: 600;
	letter-spacing: normal;
}

.woocommerce ul.products li.product .hairport-club-pricing .hairport-club-member-price__amount {
	/* Its own line, always: see the note above the panel. */
	flex: 0 0 100%;
	font-size: var(--hp-text-lg);
	font-weight: 800;
	line-height: 1.2;
}

/* The club panel draws its own ground, so the card's inset becomes a margin on
 * it — the shared padding rule above would put the wash edge to edge inside the
 * card. It stays last in the anchor, pushed down by `auto`. */
.woocommerce ul.products li.product a.woocommerce-LoopProduct-link > .hairport-club-pricing {
	margin-inline: var(--hp-space-3);
	margin-block-start: auto;
	padding-inline: var(--hp-space-3);
}

/* The button is inset with margin, not padding: padding here would override the
 * button's own and squeeze its label. */
.woocommerce ul.products li.product > :not(a.woocommerce-LoopProduct-link) {
	margin-inline: var(--hp-space-3);
}

/* The first text row clears the image, and the card closes below the button.
 * Kept for a loop rendered without the media frame — a plugin that prints its
 * own thumbnail on a different hook, for instance. */
.woocommerce ul.products li.product a.woocommerce-LoopProduct-link > img {
	margin-block-end: var(--hp-space-4);
}

.woocommerce ul.products li.product {
	padding-block-end: var(--hp-space-3);
}

/* Absolutely positioned marks are outside the padded flow and must not inherit
 * the inline padding, or they shift away from the image corner. */
.woocommerce ul.products li.product .onsale,
.woocommerce ul.products li.product .hp-badge--floating {
	padding-inline: var(--hp-space-3);
}

/* Core prints the title as an h2 inside the loop; it is a card label, not a
 * section heading, so it takes the UI face and card sizing. */
.woocommerce ul.products li.product .woocommerce-loop-product__title{
	margin: 0;
	padding: 0;
	font-family: var(--hp-font-ui);
	font-size: var(--hp-text-sm); /* 14px — down from 15 with the card */
	font-weight: 600;
	line-height: 1.4;
	letter-spacing: normal;
	color: var(--hp-text);

	/* Exactly two lines, always.
	 *
	 * A minimum alone only handled the short names; this shop's product titles
	 * run to fifteen Hebrew words ("HS שמפו המועשר בקרטין טהור לשימור החלקה
	 * בשיער מוחלק ולהורדת נפח לא רצוי בשיער 500 מ\"ל") and took three and four
	 * lines, which is where most of the card's height was going. Clamping to two
	 * both shortens the card and makes every card in a row the same height, so
	 * the prices and the buttons line up across the grid.
	 *
	 * The full name is one tap away on the product page, and the title attribute
	 * core prints on the link carries it for a pointer. */
	display: -webkit-box;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	min-height: calc(2 * 1.4 * var(--hp-text-sm));
}
.hp-loop-brand {
	font-size: var(--hp-text-xs);
	font-weight: 600;
	color: var(--hp-text-muted);
	text-transform: uppercase;
	letter-spacing: 0.02em;
}

/* ---- badges ---- */

.hp-badge {
	display: inline-flex;
	align-items: center;
	padding: var(--hp-space-1) var(--hp-space-3);
	border-radius: var(--hp-radius-sm);
	font-size: 0.75rem; /* 12px */
	font-weight: 700;
	line-height: 1.4;
	color: var(--hp-text-inverse);
	background: var(--hp-brand);
}

.hp-badge--sale {
	background: var(--hp-sale);
}

.hp-badge--new {
	background: var(--hp-success);
}

.hp-badge--club {
	background: var(--hp-club);
}

.hp-badge--low-stock {
	background: var(--hp-accent-soft);
	color: var(--hp-link);
}
.woocommerce ul.products li.product .onsale,
.woocommerce span.onsale {
	position: absolute;
	inset-block-start: var(--hp-space-3);
	inset-inline-start: var(--hp-space-3);
	z-index: 2;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--hp-space-1);
	margin: 0;
	min-width: 0;
	min-height: 0;
	padding: var(--hp-space-1) var(--hp-space-3);
	border-radius: var(--hp-radius-sm);
	background: var(--hp-sale);
	color: var(--hp-text-inverse);
	font-size: 0.75rem;
	font-weight: 700;
	line-height: 1.4;
}

/* ---- price block ----
 * Order is fixed by the canvas: current price, was-price, discount, then the
 * club line, then the unit price. Numerals are tabular and LTR-isolated by
 * 05-typography so a shekel sign cannot reorder them on a Hebrew page.
 */

.woocommerce ul.products li.product .price{
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: var(--hp-space-3);
	margin: 0;
	font-family: var(--hp-font-ui);
	font-size: var(--hp-text-lg);
	font-weight: 800;
	color: var(--hp-text);
}

/* Core wraps the old price in <del> and the new one in <ins>. */
.woocommerce ul.products li.product .price del,
.woocommerce div.product p.price del{
	order: 2;
	font-size: var(--hp-text-sm);
	font-weight: 400;
	color: var(--hp-text-muted);
	text-decoration: line-through;
	opacity: 1;
}

.woocommerce ul.products li.product .price ins,
.woocommerce div.product p.price ins{
	order: 1;
	font-size: var(--hp-text-lg);
	font-weight: 800;
	color: var(--hp-text);
	text-decoration: none;
	background: none;
}

/* ---- the plugin's club price ----
 * hairport-partners-core renders the club and unit price itself, on
 * `woocommerce_after_shop_loop_item_title` and `woocommerce_single_product_summary`.
 * The theme adopts that markup rather than rendering a second copy.
 *
 * It also prints an inline <style> on `wp_head`, which lands after these
 * stylesheets and so wins at equal specificity -- including a club gold of
 * #b9972f that predates the unified #b88a1f in TOKEN_DECISIONS.md. The
 * selectors below carry a class more than the plugin's, which is enough to win
 * honestly; none of this needs !important. Fixing the hardcoded colour at
 * source in the plugin is the real repair and is tracked separately.
 */

/**
 * On a card, the club block is a panel rather than two more lines of text, and
 * the label sits above the amount rather than beside it.
 *
 * Beside it was the first attempt and it wrapped: "מחיר לחברי מועדון: ₪160.17"
 * does not fit one line inside a 256px card, so the label broke across two and
 * the panel grew by 30px. Stacking is both stable at every width and better —
 * a small label over a large number is a price, where a label and a number on
 * one line at the same size is a sentence.
 *
 * Three prices stacked as bare lines — the shelf price, the club price in gold
 * with a star, the per-100ml in grey — read as one undifferentiated column of
 * numbers, and the club price is the single most persuasive thing on the card.
 * Putting it on the club wash gives it an edge to sit inside, so it reads as an
 * offer attached to the product rather than as another figure about it, and it
 * separates the fine print below from the price above without a rule.
 *
 * Scoped to the loop: the product page has room to set these out and gets the
 * plain treatment below.
 */
.woocommerce ul.products li.product .hairport-club-pricing,
.hp-product-card .hairport-club-pricing {
	gap: 0;
	padding: var(--hp-space-2) var(--hp-space-3);
	border-radius: var(--hp-radius-sm);
	background: var(--hp-club-tint);
}

.woocommerce .hairport-club-pricing,
.hp-product-card .hairport-club-pricing {
	display: flex;
	flex-direction: column;
	gap: var(--hp-space-1);
}

.woocommerce .hairport-club-pricing .hairport-club-member-price,
.hp-product-card .hairport-club-pricing .hairport-club-member-price {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 0 var(--hp-space-1);
	margin-block-start: 0;
	font-size: var(--hp-text-sm);
	font-weight: 700;
	line-height: 1.4;
	color: var(--hp-club);
}

.woocommerce .hairport-club-pricing .hairport-club-member-price__amount,
.hp-product-card .hairport-club-pricing .hairport-club-member-price__amount {
	color: var(--hp-club);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

.woocommerce .hairport-club-pricing .hairport-club-member-unit-price,
.hp-product-card .hairport-club-pricing .hairport-club-member-unit-price {
	margin-block-start: 0;
	font-size: var(--hp-text-xs);
	font-weight: 400;
	line-height: 1.4;
	/* A shade of the club colour rather than the page's grey: inside a gold
	 * panel, neutral grey reads as a different component that happens to
	 * overlap. */
	color: color-mix(in srgb, var(--hp-club) 62%, var(--hp-text));
	opacity: 0.85;
}

.woocommerce .hairport-club-pricing .hairport-club-member-unit-price__amount,
.hp-product-card .hairport-club-pricing .hairport-club-member-unit-price__amount {
	font-weight: 400;
	font-variant-numeric: tabular-nums;
}

/* The canvas puts a star ahead of the club line. It is decorative, so it is a
 * generated mark rather than markup the plugin would have to learn to emit. */
.woocommerce .hairport-club-pricing .hairport-club-member-price::before,
.hp-product-card .hairport-club-pricing .hairport-club-member-price::before {
	content: "";
	flex: none;
	width: 0.875rem;
	height: 0.875rem;
	background: currentColor;
	mask: var(--hp-icon-star) center / contain no-repeat;
	-webkit-mask: var(--hp-icon-star) center / contain no-repeat;
}

/* ---- theme-rendered badge over the card image ---- */

.hp-badge--floating {
	position: absolute;
	inset-block-start: var(--hp-space-3);
	inset-inline-start: var(--hp-space-3);
	z-index: 2;
}

/* ---- brand line ---- */

.woocommerce ul.products li.product .hp-loop-brand {
	display: block;
}

.hp-product-brand {
	display: block;
	margin-block-end: var(--hp-space-2);
	font-size: var(--hp-text-sm);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.02em;
	color: var(--hp-text-muted);
}

/* ---- add to cart in the loop ---- */

/**
 * The card's add-to-cart button.
 *
 * `display` is restated here, and it is the whole bug this rule was missing.
 * WooCommerce styles this button as
 * `.woocommerce ul.products li.product .button { display: inline-block }` —
 * (0,4,2) — while the theme's button treatment is `.woocommerce a.button` at
 * (0,2,1). WooCommerce won, so the button never became a flex box, its
 * `align-items: center` did nothing, and the 14px label sat hard against the
 * top edge of a 42px pill with 26px of empty space under it. That is what read
 * as the buttons being cut off, and it was on every product card on the site.
 *
 * This selector matches WooCommerce's own shape, so it wins on load order.
 *
 * The card is a flex column, so the button already stretches to the content
 * width; an explicit 100% would fight the inline margin that insets it.
 */
.woocommerce ul.products li.product .button,
.woocommerce ul.products li.product a.add_to_cart_button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--hp-space-2);
	width: auto;
	height: 2.625rem; /* 42px */
	margin-block-start: var(--hp-space-1);
	padding-inline: var(--hp-space-6);
	font-size: var(--hp-text-sm);
	line-height: 1;
	text-align: center;
}

/* Core's "View cart" follow-up link is a quiet text link, not a second button. */
.woocommerce ul.products li.product .added_to_cart {
	font-size: var(--hp-text-xs);
	font-weight: 600;
	text-decoration: underline;
}
.woocommerce .quantity .qty {
	width: 3rem;
	height: 2.75rem;
	padding: 0;
	background: transparent;
	border: none;
	text-align: center;
	font-size: var(--hp-text-base);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	-moz-appearance: textfield;
	appearance: textfield;
}
.woocommerce .quantity .qty::-webkit-outer-spin-button,
.woocommerce .quantity .qty::-webkit-inner-spin-button {
	margin: 0;
	-webkit-appearance: none;
	appearance: none;
}

/* WooCommerce's bare quantity wrapper gets the same pill as the theme's. */
.woocommerce .quantity {
	display: inline-flex;
	align-items: center;
	height: 2.75rem;
	border: 1px solid var(--hp-border);
	border-radius: var(--hp-radius-pill);
	overflow: hidden;
}

/* ---- result count and ordering ---- */

.woocommerce .woocommerce-result-count,
.woocommerce .woocommerce-ordering {
	margin: 0;
	font-size: var(--hp-text-sm);
	color: var(--hp-text-muted);
}

.woocommerce .woocommerce-ordering select {
	height: 2.625rem;
	padding-inline: var(--hp-space-4);
	background: var(--hp-surface);
	border: 1px solid var(--hp-border);
	border-radius: var(--hp-radius-pill);
	font-family: var(--hp-font-ui);
	font-size: var(--hp-text-sm);
	font-weight: 600;
	color: var(--hp-text);
}

/* ---- stock, notices ---- */

.woocommerce .stock.in-stock {
	color: var(--hp-success);
	font-weight: 600;
}

.woocommerce .stock.out-of-stock {
	color: var(--hp-sale);
	font-weight: 600;
}

/* =========================================================================
 * Single product — Product.dc.html
 * ========================================================================= */

/**
 * The gallery column is capped rather than left at half the page.
 *
 * The artboard draws two equal columns, which at the 1184px measure makes a
 * 568px square photograph — and on a real product page, next to a short summary,
 * that reads as a poster with a price beside it. Capping the gallery at 480px
 * and giving the remainder to the summary keeps the artboard's proportions on a
 * long product page and stops a short one being swallowed by its own picture.
 *
 * `minmax(0, ...)` on both columns so a narrow viewport still shrinks them
 * rather than overflowing.
 */
.woocommerce div.product {
	display: grid;
	/* 26rem, down from 30. Capping the column's WIDTH was never enough on its
	 * own — see the square frame below — but 480px of width also meant a
	 * portrait bottle shot ran past 700px tall and the summary beside it ended
	 * halfway up the picture. */
	grid-template-columns: minmax(0, 26rem) minmax(0, 1fr);
	gap: var(--hp-space-12);
	align-items: start;
	margin-block-start: var(--hp-space-8);
}

/* The breadcrumb, and anything else core prints before the two columns, spans
 * the full width above them. */
.woocommerce div.product > .woocommerce-breadcrumb,
.woocommerce div.product > .woocommerce-notices-wrapper,
.woocommerce div.product > .related,
.woocommerce div.product > .upsells {
	grid-column: 1 / -1;
}

@media (max-width: 55rem) {
	.woocommerce div.product {
		grid-template-columns: 1fr;
		gap: var(--hp-space-8);
	}
}

/* ---- gallery ---- */

.woocommerce div.product div.images {
	display: flex;
	flex-direction: column;
	gap: var(--hp-space-4);
	width: auto;
	float: none;
	margin: 0;
}

/**
 * The main shot is framed, not merely sized.
 *
 * Capping the column at a width does not cap the picture: the shop's photographs
 * are portrait bottles, so a 480px-wide column produced a 700px-tall image and
 * the product page became a poster with a price beside it. Worse, every product
 * page was a different height, because the height was whatever the photographer
 * happened to shoot.
 *
 * So the frame is a square with the image contained inside it. Three things
 * follow: no picture can be taller than it is wide, every product page has the
 * same shape, and a portrait bottle is shown whole rather than cropped through
 * the cap — which `cover` would have done.
 *
 * The frame carries the background, so the letterboxing a contained image
 * leaves reads as a deliberate mount rather than as a gap.
 */
.woocommerce div.product div.images .woocommerce-product-gallery__image {
	display: flex;
	align-items: center;
	justify-content: center;
	aspect-ratio: 1;
	padding: var(--hp-space-6);
	background: var(--hp-surface-warm);
	border-radius: var(--hp-radius-lg);
	overflow: hidden;
}

.woocommerce div.product div.images .woocommerce-product-gallery__image > a {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
}

.woocommerce div.product div.images .woocommerce-product-gallery__image img {
	width: auto;
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
	background: none;
	border-radius: 0;
}

/* Any other image core prints in the gallery — a variation swap, a plugin's
 * extra shot — keeps the plain treatment. */
.woocommerce div.product div.images img {
	border-radius: var(--hp-radius);
	background: var(--hp-surface-subtle);
}

.woocommerce div.product div.images .flex-control-thumbs {
	display: flex;
	flex-wrap: wrap;
	gap: var(--hp-space-3);
	margin: 0;
	padding: 0;
	list-style: none;
}

.woocommerce div.product div.images .flex-control-thumbs li {
	width: 5.375rem; /* 86px */
	margin: 0;
	list-style: none;
}

.woocommerce div.product div.images .flex-control-thumbs img {
	width: 100%;
	aspect-ratio: 1;
	object-fit: cover;
	border: 1px solid var(--hp-border);
	border-radius: var(--hp-radius-sm);
	opacity: 1;
	cursor: pointer;
	transition: border-color var(--hp-duration-fast) var(--hp-ease);
}

.woocommerce div.product div.images .flex-control-thumbs img.flex-active,
.woocommerce div.product div.images .flex-control-thumbs img:hover {
	border: 2px solid var(--hp-brand);
}

/* ---- summary column ---- */

.woocommerce div.product div.summary {
	display: flex;
	flex-direction: column;
	gap: var(--hp-space-5);
	width: auto;
	float: none;
	margin: 0;
}

.woocommerce div.product .product_title {
	margin: 0;
	font-size: 1.875rem; /* 30px */
	line-height: var(--hp-leading-heading);
}

/* Core prints the brand, title and rating as separate siblings; they read as
 * one block, so the gaps between them close up. */
.woocommerce div.product .hp-product-brand,
.woocommerce div.product .product_title,
.woocommerce div.product .woocommerce-product-rating {
	margin-block-end: calc(-1 * var(--hp-space-3));
}

.woocommerce div.product .woocommerce-product-rating {
	display: flex;
	align-items: center;
	gap: var(--hp-space-2);
	font-size: var(--hp-text-sm);
	color: var(--hp-text-muted);
}

.woocommerce div.product .woocommerce-product-rating .star-rating {
	color: var(--hp-club);
	margin: 0;
}

/* ---- price panel ----
 * Wraps core's price (10) and the plugin's club and unit prices (11).
 */

.hp-price-panel {
	display: flex;
	flex-direction: column;
	gap: var(--hp-space-2);
	padding: var(--hp-space-5) var(--hp-space-6);
	background: var(--hp-surface-warm);
	border: 1px solid var(--hp-border);
	border-radius: var(--hp-radius);
}

.woocommerce div.product .hp-price-panel p.price {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: var(--hp-space-3);
	margin: 0;
	font-size: 1.875rem; /* 30px */
	font-weight: 800;
	color: var(--hp-text);
}

.woocommerce div.product .hp-price-panel p.price del {
	font-size: var(--hp-text-base);
	font-weight: 400;
}

.woocommerce div.product .hp-price-panel p.price ins {
	font-size: 1.875rem;
	font-weight: 800;
}

/* The club line is larger here than in a card, per the canvas. */
.woocommerce div.product .hp-price-panel .hairport-club-member-price {
	font-size: var(--hp-text-base);
}

.woocommerce div.product .hp-price-panel .hairport-club-member-unit-price {
	font-size: var(--hp-text-sm);
}

.hp-price-panel__join {
	align-self: flex-start;
	font-size: var(--hp-text-xs);
	font-weight: 600;
}

/* ---- variations ---- */

.woocommerce div.product form.cart {
	display: flex;
	flex-direction: column;
	gap: var(--hp-space-5);
	margin: 0;
}

.woocommerce div.product form.cart table.variations {
	margin: 0;
	border: none;
}

.woocommerce div.product form.cart table.variations,
.woocommerce div.product form.cart table.variations tbody,
.woocommerce div.product form.cart table.variations tr,
.woocommerce div.product form.cart table.variations th,
.woocommerce div.product form.cart table.variations td {
	display: block;
	padding: 0;
	border: none;
	background: none;
}

.woocommerce div.product form.cart table.variations th.label {
	margin-block-end: var(--hp-space-2);
	font-size: 0.9375rem;
	font-weight: 700;
	text-align: start;
}

.woocommerce div.product form.cart table.variations td.value select {
	width: 100%;
	max-width: 22rem;
	height: 2.75rem;
	padding-inline: var(--hp-space-4);
	background: var(--hp-surface);
	border: 1px solid var(--hp-border);
	border-radius: var(--hp-radius-pill);
	font-family: var(--hp-font-ui);
	font-size: 0.9375rem;
	font-weight: 600;
}

.woocommerce div.product form.cart .reset_variations {
	display: inline-block;
	margin-block-start: var(--hp-space-2);
	font-size: var(--hp-text-xs);
}

/* ---- quantity and CTA row ---- */

.woocommerce div.product form.cart .hp-cart-row,
.woocommerce div.product form.cart > .quantity + button.single_add_to_cart_button {
	/* Core prints .quantity and the button as consecutive siblings with no
	 * wrapper, so the row is made by turning the form into a grid for those
	 * two children only. */
	margin: 0;
}

.woocommerce div.product form.cart:has(> .quantity) {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	gap: var(--hp-space-4) var(--hp-space-4);
	align-items: center;
}

.woocommerce div.product form.cart:has(> .quantity) > :not(.quantity):not(button.single_add_to_cart_button) {
	grid-column: 1 / -1;
}

/**
 * Both cells are placed explicitly rather than left to auto-placement.
 *
 * Core prints other children into this form — a stock line, a variation table,
 * a plugin's notice — and any of them landing before the quantity takes the
 * first cell and pushes the pair round: the stepper stretched to 413px in the
 * flexible column while the add-to-cart button shrank to 144px in the fixed
 * one, which is the reverse of the artboard.
 *
 * Naming the columns makes the row independent of what else the form contains.
 */
.woocommerce div.product form.cart:has(> .quantity) > .quantity {
	grid-column: 1;
	width: auto;
}

.woocommerce div.product form.cart:has(> .quantity) > button.single_add_to_cart_button {
	grid-column: 2;
}

.woocommerce div.product form.cart .quantity {
	height: 3.25rem;
}

.woocommerce div.product form.cart .quantity .qty {
	height: 3.25rem;
	width: 3.5rem;
	font-size: var(--hp-text-md);
}

.woocommerce div.product button.single_add_to_cart_button {
	width: 100%;
	height: 3.25rem;
	font-size: var(--hp-text-md);
	font-weight: 700;
}

/* ---- product notices ----
 * Rendered by woo-custom-product-notices, styled here.
 */

.woocommerce div.product .hp-notice,
.woocommerce div.product .wcpn-notice {
	display: flex;
	align-items: center;
	gap: var(--hp-space-3);
	padding: var(--hp-space-3) var(--hp-space-4);
	background: var(--hp-surface-subtle);
	border-radius: var(--hp-radius);
	font-size: var(--hp-text-sm);
	line-height: 1.5;
}

/* ---- tabs as accordions ----
 * Relocated into the summary column by inc/class-product.php. Core prints a
 * tab list plus one panel per tab; the list is hidden and each panel carries
 * its own heading, which is what the canvas draws.
 */

.woocommerce div.product .woocommerce-tabs {
	border: 1px solid var(--hp-border);
	border-radius: var(--hp-radius);
	overflow: hidden;
}

.woocommerce div.product .woocommerce-tabs ul.tabs {
	display: none;
}

.woocommerce div.product .woocommerce-tabs .panel {
	margin: 0;
	padding: var(--hp-space-4);
	border: none;
	border-radius: 0;
	box-shadow: none;
	font-size: var(--hp-text-sm);
	line-height: var(--hp-leading-body);
	color: var(--hp-text-muted);
}

.woocommerce div.product .woocommerce-tabs .panel + .panel {
	border-block-start: 1px solid var(--hp-border);
}

.woocommerce div.product .woocommerce-tabs .panel > h2 {
	margin: 0;
	font-family: var(--hp-font-ui);
	font-size: 0.9375rem;
	font-weight: 700;
	color: var(--hp-text);
}

/* With JavaScript off the heading stays a plain heading and every body is
 * visible, so the content is never trapped behind a control that cannot run. */
.woocommerce div.product .woocommerce-tabs .panel > h2:not(.hp-accordion__heading) {
	margin-block-end: var(--hp-space-3);
}

/* ---- accordion ----
 * assets/js/theme.js turns each panel heading into this button and wraps the
 * rest of the panel as its body.
 */

.hp-accordion__toggle {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--hp-space-3);
	width: 100%;
	padding: 0;
	background: transparent;
	border: none;
	color: inherit;
	font: inherit;
	text-align: start;
	cursor: pointer;
}

.hp-accordion__toggle:focus-visible {
	outline: 2px solid var(--hp-focus);
	outline-offset: 4px;
}

.hp-accordion__chevron {
	flex: none;
	width: 1rem;
	height: 1rem;
	background: currentColor;
	mask: var(--hp-icon-chevron) center / contain no-repeat;
	-webkit-mask: var(--hp-icon-chevron) center / contain no-repeat;
	transition: transform var(--hp-duration-fast) var(--hp-ease);
}

.hp-accordion__toggle[aria-expanded="true"] .hp-accordion__chevron {
	transform: rotate(180deg);
}

.hp-accordion__body {
	padding-block-start: var(--hp-space-3);
}

/* A folded row's heading recedes, matching the canvas. */
.woocommerce div.product .woocommerce-tabs .panel:not(.is-open) .hp-accordion__toggle {
	color: var(--hp-text-muted);
}

.woocommerce div.product .woocommerce-tabs .panel > :last-child {
	margin-block-end: 0;
}

/* ---- related products ---- */

.woocommerce div.product .related,
.woocommerce div.product .upsells {
	margin-block-start: var(--hp-space-14);
}

.woocommerce div.product .related > h2,
.woocommerce div.product .upsells > h2 {
	margin: 0 0 var(--hp-space-7);
	font-size: var(--hp-text-h2);
}

/* =========================================================================
 * Subcategory tiles
 *
 * WooCommerce prints category tiles as `li.product-category.product`, so they
 * land inside the same `ul.products` grid as products and inherit the product
 * card's rules — which expect an image, a brand line, a price and a button, and
 * get a name and a count instead. Nothing styled them, which is why the brands
 * page (38 tiles) and every archive that lists its children read as broken.
 *
 * They are given their own treatment here, and they reset the product-card
 * rules they were wrongly inheriting.
 * ========================================================================= */

.woocommerce ul.products li.product-category {
	padding-block-end: 0;
	background: var(--hp-surface);
	border: 1px solid var(--hp-border);
	border-radius: var(--hp-radius);
	overflow: hidden;
	transition:
		border-color var(--hp-duration-fast) var(--hp-ease),
		box-shadow var(--hp-duration) var(--hp-ease-out),
		transform var(--hp-duration) var(--hp-ease-out);
}

.woocommerce ul.products li.product-category:hover,
.woocommerce ul.products li.product-category:focus-within {
	border-color: var(--hp-accent);
	transform: translateY(var(--hp-lift-card));
	box-shadow: var(--hp-shadow-lift);
}

/* A brand index is read by scanning names, so the name is what changes colour;
 * the image is a logo and stays as it is. */
.woocommerce ul.products li.product-category:hover h2.woocommerce-loop-category__title,
.woocommerce ul.products li.product-category:focus-within h2.woocommerce-loop-category__title {
	color: var(--hp-link);
}

.woocommerce ul.products li.product-category .hp-loop-media {
	margin-block-end: var(--hp-space-4);
}

.woocommerce ul.products li.product-category > a {
	display: flex;
	flex-direction: column;
	height: 100%;
	padding: 0;
	color: var(--hp-text);
}

.woocommerce ul.products li.product-category img {
	width: 100%;
	aspect-ratio: 1;
	margin: 0 0 var(--hp-space-4);
	object-fit: cover;
	background: var(--hp-surface-subtle);
}

/* Core prints the name as an h2 with the count in a <mark>. The card rule gave
 * it a two-line minimum meant for product names; a category name needs one. */
.woocommerce ul.products li.product-category h2.woocommerce-loop-category__title {
	display: flex;
	align-items: baseline;
	justify-content: center;
	gap: var(--hp-space-2);
	min-height: 0;
	margin: 0;
	padding: 0 var(--hp-space-4) var(--hp-space-4);
	font-family: var(--hp-font-ui);
	font-size: 0.9375rem;
	font-weight: 600;
	line-height: 1.4;
	text-align: center;
	transition: color var(--hp-duration-fast) var(--hp-ease);
}

/* The count arrives as <mark>, which the UA paints yellow. */
.woocommerce ul.products li.product-category .count,
.woocommerce ul.products li.product-category mark {
	background: none;
	color: var(--hp-text-muted);
	font-size: var(--hp-text-xs);
	font-weight: 400;
}

/* A tile that has no image should not collapse to a bare name. */
.woocommerce ul.products li.product-category > a:not(:has(img))::before {
	content: "";
	display: block;
	aspect-ratio: 1;
	margin-block-end: var(--hp-space-4);
	background: var(--hp-surface-subtle);
}

/* A brand index is a long list of short names, so it takes a denser grid than
 * the product grid it shares a wrapper with. */
.woocommerce ul.products:has(li.product-category:nth-child(9)) {
	grid-template-columns: repeat(6, minmax(0, 1fr));
}

@media (max-width: 60rem) {
	.woocommerce ul.products:has(li.product-category:nth-child(9)) {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

@media (max-width: 40rem) {
	.woocommerce ul.products:has(li.product-category:nth-child(9)) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}
