/* Heaxabell Combo Offers — "pilih combo & jimat" modal (multi-combo cards) + cart combo line + fee bar. Author: Bingkai Hitam. */

/* ---------------------------------------------------------------------------
 * Modal (bottom sheet) — base
 * ------------------------------------------------------------------------- */
.hx-upsell {
	position: fixed;
	inset: 0;
	z-index: 6000;
	display: flex;
	align-items: flex-end;
	justify-content: center;
}
.hx-upsell[hidden] { display: none; }
.hx-upsell__scrim {
	position: absolute;
	inset: 0;
	background: rgba(0, 0, 0, .5);
	opacity: 0;
	transition: opacity .22s ease;
}
.hx-upsell__sheet {
	position: relative;
	width: 100%;
	max-width: 520px;
	max-height: 86vh;
	display: flex;
	flex-direction: column;
	background: #fff;
	border-radius: 20px 20px 0 0;
	padding: 20px 18px calc(18px + env(safe-area-inset-bottom));
	transform: translateY(102%);
	transition: transform .3s cubic-bezier(.22, .9, .3, 1);
}
.hx-upsell.is-open .hx-upsell__scrim { opacity: 1; }
.hx-upsell.is-open .hx-upsell__sheet { transform: translateY(0); }
.hx-upsell__close {
	position: absolute;
	top: 14px;
	right: 14px;
	width: 34px;
	height: 34px;
	border: 0;
	border-radius: 50%;
	background: #f1f1f2;
	color: var(--ink-2, #6b6b74);
	font-size: 20px;
	line-height: 1;
	cursor: pointer;
}
.hx-upsell__badge {
	display: inline-block;
	align-self: flex-start;
	padding: 4px 10px;
	font-size: 11.5px;
	font-weight: 700;
	letter-spacing: .03em;
	color: #c81e43;
	background: #fff0f3;
	border: 1px solid #ffc2cd;
	border-radius: 999px;
	margin-bottom: 10px;
}
.hx-upsell__title {
	font-size: 18px;
	font-weight: 800;
	color: var(--ink, #161823);
	line-height: 1.3;
	margin: 0 34px 6px 0;
}
.hx-upsell__sub {
	font-size: 13px;
	color: var(--ink-2, #6b6b74);
	line-height: 1.4;
	margin: 0 0 12px;
}
.hx-upsell__skip {
	display: block;
	width: 100%;
	margin-top: 10px;
	padding: 10px;
	border: 0;
	background: transparent;
	color: var(--ink-2, #6b6b74);
	font-size: 13.5px;
	font-weight: 600;
	cursor: pointer;
	flex-shrink: 0;
}
@media (min-width: 820px) {
	.hx-upsell {
		align-items: center;
		padding: 24px;
	}
	.hx-upsell__sheet {
		border-radius: 20px;
		margin-bottom: 0;
	}
}

/* ---------------------------------------------------------------------------
 * Modal — combo cards (one per combo)
 * ------------------------------------------------------------------------- */
.hx-upsell__combos {
	display: flex;
	flex-direction: column;
	gap: 12px;
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;
}
.hx-combo-card {
	padding: 12px 14px;
	background: #fff;
	border: 1.5px solid #ffd6de;
	border-radius: 12px;
	box-shadow: 0 1px 3px rgba(0,0,0,.05);
}
.hx-combo-card__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	margin-bottom: 8px;
}
.hx-combo-card__title {
	font-size: 13.5px;
	font-weight: 800;
	color: var(--ink, #161823);
	line-height: 1.3;
	flex: 1;
}
.hx-upsell__save {
	display: inline-block;
	padding: 3px 10px;
	font-size: 11.5px;
	font-weight: 700;
	color: #0a8a4e;
	background: #eaf7ee;
	border: 1px solid #b7e4c7;
	border-radius: 999px;
	white-space: nowrap;
}
.hx-combo-card__body {
	display: flex;
	align-items: center;
	gap: 12px;
}
.hx-combo-card__items {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 6px;
}
.hx-combo-card__row {
	display: flex;
	align-items: center;
	gap: 10px;
}
.hx-combo-card__thumb {
	width: 46px;
	height: 46px;
	object-fit: cover;
	border-radius: 8px;
	flex-shrink: 0;
	background: #f1f1f2;
}
.hx-combo-card__thumb--ph {
	display: block;
}
.hx-combo-card__info {
	display: flex;
	flex-direction: column;
	gap: 1px;
	min-width: 0;
}
.hx-combo-card__name {
	font-size: 12.5px;
	font-weight: 600;
	color: var(--ink, #161823);
	line-height: 1.3;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}
.hx-combo-card__hint {
	font-size: 11px;
	font-weight: 700;
	color: #c81e43;
}
.hx-combo-card__total {
	display: flex;
	align-items: baseline;
	gap: 8px;
	margin-top: 10px;
}
.hx-combo-card__was {
	font-size: 13px;
	color: var(--ink-3, #a1a1aa);
	text-decoration: line-through;
}
.hx-combo-card__now {
	font-size: 16px;
	font-weight: 800;
	color: #c81e43;
}
.hx-combo-card__add {
	flex-shrink: 0;
	height: 38px;
	padding: 0 18px;
	border: 0;
	border-radius: 10px;
	background: var(--accent, #fe2c55);
	color: #fff;
	font-weight: 700;
	font-size: 13.5px;
	cursor: pointer;
	white-space: nowrap;
	transition: transform .12s ease;
}
.hx-combo-card__add:hover { transform: translateY(-1px); }

/* ---------------------------------------------------------------------------
 * Quick-view — "Complete the set & save" block (hx_combo_quickview_html)
 *
 * Rendered into `.qv__combo` in the footer, which app.js fills from `combo_html`
 * on every quick-view open. Without these styles the block inherits the sheet's
 * body styles and the Combo tag collapses onto the text line.
 * ------------------------------------------------------------------------- */
.qv__combo:not(:empty) { margin-top: 12px; }
.qv__combo__box {
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding: 12px;
	border: 1px solid var(--line, #e6e6ea);
	border-radius: 12px;
	background: var(--accent-soft, #fff0f3);
}
.qv__combo__head {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 11px;
	font-weight: 800;
	letter-spacing: .06em;
	text-transform: uppercase;
	color: var(--accent, #fe2c55);
}
.qv__combo__headtxt { min-width: 0; }

/* ---------------------------------------------------------------------------
 * v2.10.0 — combo RAIL (mirrors the PDP block)
 *
 * The sheet is narrow — a phone sheet on mobile, a ~420px column on desktop —
 * so STACKING 2-3 cards made the modal taller than the viewport and pushed the
 * Add button out of reach. A horizontal rail keeps the modal height fixed and
 * reuses the exact gesture the PDP combo block already taught the shopper.
 *
 * Card sizing differs from the PDP on purpose: the PDP is a wide 2-up column,
 * this is a narrow sheet, so the rail shows ONE card plus a peek at every
 * width. Two 210px cards side by side in a 420px sheet would put the item
 * names, the price pair AND the Add button into a column narrower than the
 * thumbs they describe.
 * ------------------------------------------------------------------------- */
.qv__combo__rail {
	position: relative;
	/* Clip so the right-edge fade is the true edge. Without this the track's
	   own inset (see margin below) overhangs the rail and paints un-faded
	   card over the fade — the same sliver that bit the PDP block. */
	overflow: hidden;
}

/* Right-edge fade = the second slide affordance. Pointer-events off so it can
   never eat a swipe. Ends at 92% so the ramp reaches FULL opacity before the
   rim; at 72% the next card's 1px border showed through as a hairline. */
.qv__combo__rail::after {
	content: '';
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	width: 34px;
	pointer-events: none;
	background: linear-gradient(to right, rgba(255, 240, 243, 0), var(--accent-soft, #fff0f3) 92%);
	opacity: 0;
	transition: opacity .18s;
}
.qv__combo__rail.is-scrollable::after { opacity: 1; }

.qv__combo__track {
	display: flex;
	gap: 10px;
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	-webkit-overflow-scrolling: touch;
	scrollbar-width: none;
	-ms-overflow-style: none;
	/* Vertical breathing room so a focused card's ring is not clipped. */
	padding: 2px 2px 4px;
	margin: 0 -2px;
}
.qv__combo__track::-webkit-scrollbar { display: none; }
.qv__combo__track:focus-visible { outline: 2px solid var(--accent, #fe2c55); outline-offset: 2px; }

/* 88% so the NEXT card peeks in at the right edge — a wordless "there is
   more". A full-width card leaves nothing to see past the edge and the pill
   becomes the only signal. */
.qv__combo__track .qv__combo__card {
	flex: 0 0 88%;
	min-width: 0;
	scroll-snap-align: start;
}
/* A lone card has nothing to peek at, and half a card next to dead space
   reads like a broken row. :only-child is 0,2,0 — it also beats the 88% above
   even though this rule comes first, which is the point. */
.qv__combo__track .qv__combo__card:only-child { flex: 0 0 100%; }

/* Desktop drag-to-slide. Hidden scrollbars kill Chrome's native drag, and a
   mouse has no pan gesture, so without this the rail is a dead row on a
   desktop sheet. `grab` signals "this moves" before any click. */
.qv__combo__track.is-grabbable { cursor: grab; }
.qv__combo__track.is-grabbable.is-dragging { cursor: grabbing; scroll-snap-type: none; }

/* SWIPE pill. Sits in the head so it never scrolls out of view.
   ⚠ NOT `.qv__combo__hint` — that name was ALREADY taken by the
   "Select size/colour" caption inside the item rows. Reusing it made the pill's
   `display:inline-flex` + `margin-left:auto` + white bg + animation leak onto
   the caption, which is why "Select size/colour" jumped to the right edge. */
.qv__combo__swipe {
	display: inline-flex;
	align-items: center;
	gap: 3px;
	margin-left: auto;
	padding: 3px 7px 3px 8px;
	border: 1px solid var(--accent, #fe2c55);
	border-radius: 999px;
	background: #fff;
	color: var(--accent, #fe2c55);
	font-size: 9px;
	font-weight: 800;
	letter-spacing: .07em;
	line-height: 1;
	white-space: nowrap;
	animation: qvNudge 1.9s ease-in-out infinite;
}
.qv__combo__swipe svg { display: block; }
@keyframes qvNudge {
	0%, 72%, 100% { transform: translateX(0); }
	80%           { transform: translateX(3px); }
	88%           { transform: translateX(0); }
	94%           { transform: translateX(2px); }
}
@media (prefers-reduced-motion: reduce) {
	.qv__combo__swipe { animation: none; }
}

/* ---------------------------------------------------------------------------
 * v2.6.0 — combo CARD (was a single flex-wrap row)
 *
 * The old row selector was `display:flex; flex-wrap:wrap; align-items:center`
 * with `.qv__combo__save{margin-left:auto}`. The save badge therefore wrapped to
 * its own flex line and dropped to the BOTTOM of a 3-line row, leaving the tag
 * floating mid-height and ~66px of dead space. Measured on live: 101.7px row,
 * save at offset 83.6px, tag centre 42px above row centre.
 *
 * Cards fix it structurally: a 3-part stack (top / items / foot) where each part
 * owns its line, so nothing can wrap into a stranded position.
 * ------------------------------------------------------------------------- */
.qv__combo__card {
	background: #fff;
	border: 1px solid var(--line, #e6e6ea);
	border-radius: 10px;
	padding: 10px;
	display: flex;
	flex-direction: column;
	gap: 8px;
}
/* Row 1: COMBO tag · title · save badge, on ONE line that cannot wrap apart. */
.qv__combo__top {
	display: flex;
	align-items: center;
	gap: 7px;
	min-width: 0;
}
.qv__combo__tag {
	flex: 0 0 auto;
	padding: 2px 7px;
	border-radius: 999px;
	background: var(--accent, #fe2c55);
	color: #fff;
	font-size: 9.5px;
	font-weight: 800;
	letter-spacing: .05em;
	text-transform: uppercase;
	line-height: 1.6;
}
.qv__combo__title {
	flex: 1 1 auto;
	min-width: 0;
	font-size: 12.5px;
	font-weight: 700;
	color: var(--ink, #161823);
	/* Two lines allowed. Measured: at 390px a nowrap+ellipsis title left only
	   147px for the text ("ALVA 16.0 + Crystal Square" overflowed by 20-38px,
	   and 90-108px at 320px), so on a small phone the name was cut to
	   "ALVA 16.0 +". Wrapping two lines keeps the full combo name readable —
	   the item rows below carry the detail, so 2 lines is the ceiling. */
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	line-height: 1.3;
	overflow-wrap: anywhere;
}
/* The save badge lives in the FOOT row (with the prices), not beside the
   title. It used to share the title line and starve it of width. */
.qv__combo__save {
	flex: 0 0 auto;
	font-size: 11px;
	font-weight: 800;
	color: #0a8754;
	background: #e7f6ee;
	border-radius: 999px;
	padding: 3px 8px;
	white-space: nowrap;
}

/* Row 2: one photo row per item still needed. */
.qv__combo__items {
	display: flex;
	flex-direction: column;
	gap: 7px;
}
.qv__combo__item {
	display: flex;
	align-items: center;
	gap: 9px;
	min-width: 0;
}
/* In a satisfied card the item row is thumb + meta + optional flag, with the
   flag pushed to the right edge. */
.qv__combo__card.is-satisfied .qv__combo__meta { flex: 1 1 auto; }
/* The caption here is a STATEMENT, not a prompt. The shared .qv__combo__hint is
   accent-red because elsewhere it says "Select size/colour" (an action); in a
   satisfied card that red reads as a button. Mute it. */
.qv__combo__card.is-satisfied .qv__combo__hint {
	color: var(--ink-3, #a1a1aa);
	font-weight: 500;
}
.qv__combo__thumb {
	width: 38px;
	height: 38px;
	flex: 0 0 38px;
	border-radius: 8px;
	object-fit: cover;
	background: var(--bg, #f1f1f2);
}
.qv__combo__thumb--ph {
	display: block;
	background: var(--bg, #f1f1f2);
}
.qv__combo__meta {
	display: flex;
	flex-direction: column;
	gap: 1px;
	min-width: 0;
}
.qv__combo__name {
	font-size: 12.5px;
	font-weight: 600;
	color: var(--ink, #161823);
	line-height: 1.35;
	/* Two lines max, then ellipsis. The full SKU is on the product page. */
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}
.qv__combo__hint {
	font-size: 11px;
	color: var(--accent, #fe2c55);
	font-weight: 600;
}

/* Row 3: was/now + the Add button. */
.qv__combo__foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	border-top: 1px solid var(--line, #e6e6ea);
	padding-top: 8px;
}
.qv__combo__prices {
	display: flex;
	align-items: baseline;
	gap: 7px;
	min-width: 0;
}
.qv__combo__was {
	font-size: 12px;
	color: var(--ink-3, #a1a1aa);
	text-decoration: line-through;
	white-space: nowrap;
}
.qv__combo__now {
	font-size: 14.5px;
	font-weight: 800;
	color: var(--accent, #fe2c55);
	white-space: nowrap;
}
/* Already-satisfied card: the combo is complete the moment the shopper adds the
   product they are viewing, so there is nothing left to add. Muted, no button,
   and SORTED LAST by the renderer — a no-action card must never precede one that
   needs a tap. */
.qv__combo__card.is-satisfied {
	background: #fbfbfc;
	border-style: dashed;
}
.qv__combo__card.is-satisfied .qv__combo__name { color: var(--ink-2, #6b6b74); font-weight: 500; }
.qv__combo__card.is-satisfied .qv__combo__now { color: var(--ink-2, #6b6b74); }
/* The "Complete once added" pill: a sentence, not a status word, so it drops the
   uppercase/tracking treatment an all-caps badge needs. */
.qv__combo__done {
	padding: 4px 10px;
	border-radius: 999px;
	background: #eef0f2;
	color: var(--ink-2, #6b6b74);
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0;
	white-space: nowrap;
}
/* Marks the row that IS the product on screen, so the card reads as "this one is
   already in the deal" rather than "add this one too". */
.qv__combo__flag {
	flex: 0 0 auto;
	margin-left: auto;
	padding: 2px 7px;
	border-radius: 999px;
	background: #e7f6ee;
	color: #0a8754;
	font-size: 9.5px;
	font-weight: 800;
	letter-spacing: .04em;
	text-transform: uppercase;
	white-space: nowrap;
}
.qv__combo__footend {
	display: flex;
	align-items: center;
	gap: 7px;
	flex: 0 0 auto;
}
.qv__combo__add {
	flex: 0 0 auto;
	border: 0;
	background: var(--accent, #fe2c55);
	color: #fff;
	font-size: 12.5px;
	font-weight: 800;
	padding: 8px 18px;
	border-radius: 999px;
	cursor: pointer;
	line-height: 1;
	/* 40px tall = comfortable touch target on mobile. */
	min-height: 34px;
}
.qv__combo__add:active { transform: scale(.97); }
.qv__combo__add.is-loading { opacity: .6; pointer-events: none; }

/* ---------------------------------------------------------------------------
 * Cart — combo line under a cart item's name
 * ------------------------------------------------------------------------- */
.cartItem__combo {
	display: flex;
	align-items: baseline;
	gap: 6px;
	width: 100%;
	margin: 3px 0 2px;
	padding: 0;
	text-align: left;
	background: transparent;
	border: 0;
	cursor: pointer;
}
.cartItem__combo__tag {
	font-size: 10.5px;
	font-weight: 800;
	letter-spacing: .03em;
	text-transform: uppercase;
	color: #fff;
	background: #c81e43;
	border-radius: 5px;
	padding: 1px 6px;
	flex-shrink: 0;
	transform: translateY(-1px);
}
.cartItem__combo__txt {
	font-size: 12.5px;
	font-weight: 600;
	color: #c81e43;
	line-height: 1.35;
}

/* Cart summary — visible "Combo offer" fee line (theme summary doesn't render WC fees). */
.hx-combo-fees {
	margin: 0 0 8px;
}
.hx-combo-fees__row {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 10px;
	padding: 9px 12px;
	background: #eaf7ee;
	border: 1px solid #b7e4c7;
	border-radius: 10px;
	margin-bottom: 6px;
}
.hx-combo-fees__label {
	font-size: 13px;
	color: var(--ink, #161823);
}
.hx-combo-fees__amt {
	font-size: 13px;
	font-weight: 700;
	color: #0a8a4e;
	white-space: nowrap;
}

@media (max-width: 480px) {
	.hx-combo-fees__row {
		padding: 8px 10px;
		font-size: 12.5px;
	}
}

/* ---------------------------------------------------------------------------
 * Cart — locked combo line (product fully consumed by an applied combo)
 * ------------------------------------------------------------------------- */
.cartItem__combo--locked {
	cursor: default;
	align-items: center;
	gap: 7px;
}
.cartItem__combo__tag--lock {
	background: #eef1f5;
	color: #5b6472;
	border: 1px solid #d6dce5;
	font-size: 10px;
	letter-spacing: .02em;
}
.cartItem__combo__txt--lock {
	color: #6b7280;
	font-weight: 500;
	font-size: 12px;
}
.cartItem__combo__note {
	font-size: 11.5px;
	line-height: 1.4;
	color: #8a7280;
	margin: 2px 0 3px;
	padding-left: 2px;
}

/* ---------------------------------------------------------------------------
 * Checkout — combo summary as a ROW INSIDE the product list
 * ---------------------------------------------------------------------------
 * User decision 2026-09-13: no card floating above the products. The combo
 * summary is a table row in the same list, same two columns, so it reads as
 * part of the order. / */
.hx-combo-row > td {
	padding: 10px 0 !important;
	border-bottom: 1px solid var(--line, #e6e6ea) !important;
	vertical-align: middle;
}
/* Subtle green wash + a left rail so the row is findable without becoming a
 * separate widget. Inset shadow instead of a border so the table grid holds.
 *
 * The theme sets `.checkoutPage .hx-ocard--product table.shop_table td`
 * (specificity 0,3,2) with `text-align:left`, which beats a plain
 * `.hx-combo-row > td` rule. These selectors match that specificity so the
 * label stays left and the amount right-aligns with the prices above it. */
.checkoutPage .hx-ocard--product table.shop_table td.hx-combo-cell--label {
	text-align: left;
	padding-left: 10px !important;
	/* v2.8.11: was `4px 0 0 4px` — the left radius clipped the thumbnail's
	   top-left corner on checkout. The row is one full-width cell now, so no
	   rounding is wanted. */
	border-radius: 0;
	background: #f4fbf6;
	box-shadow: inset 3px 0 0 #0a8a4e;
}
.checkoutPage .hx-ocard--product table.shop_table td.hx-combo-cell {
	text-align: right;
	background: #f4fbf6;
	/* v2.8.11: was `0 4px 4px 0`. This is the THIRD place the combo cell carried
	   a 4px right radius (alongside --label and :last-child). It clipped the
	   product thumbnail's right corners on checkout, so the image looked rounded
	   there but square in the cart. All three are now 0. */
	border-radius: 0;
}
.hx-combo-row__label {
	display: flex;
	align-items: center;
	gap: 8px;
}
.hx-combo-row__tag {
	font-size: 10px;
	font-weight: 800;
	letter-spacing: .03em;
	text-transform: uppercase;
	color: #fff;
	background: #c81e43;
	border-radius: 5px;
	padding: 2px 6px;
	flex-shrink: 0;
	line-height: 1.4;
}
.hx-combo-row__txt {
	font-size: 13px;
	font-weight: 700;
	color: var(--ink, #161823);
}
.hx-combo-row__amt {
	color: #0a8a4e;
	font-weight: 800;
	font-size: 14px;
	white-space: nowrap;
}
/* WooCommerce still prints one tfoot fee row per combo (the total math needs
 * them) — fold those away so the shopper sees ONE combo number, not four.
 * Scoped by the fee label so shipping / tax / the discount-rule "You Saved"
 * row are never touched. */
.checkoutPage .hx-product-table tfoot tr.fee.hx-combo-fee,
.checkoutPage .hx-product-table tfoot tr.hx-combo-fee {
	display: none !important;
}
/* List price, struck through — the "before". */
.hx-line-list {
	display: inline-block;
	color: var(--ink-3, #a1a1aa);
	text-decoration: line-through;
	text-decoration-thickness: 1px;
	font-weight: 400;
	font-size: 12.5px;
	line-height: 1.2;
}
/* What the shopper actually pays — the "after". Always wins the eye. */
.hx-line-eff {
	display: inline-block;
	color: #0a8a4e;
	font-weight: 800;
	font-size: 14px;
	white-space: nowrap;
}
/* Keep the pair readable on narrow screens: stack them instead of squeezing. */
@media (max-width: 400px) {
	.hx-line-list,
	.hx-line-eff {
		display: block;
	}
	.hx-line-list {
		margin-bottom: 1px;
	}
}

/* ===========================================================================
 * COMBO DEAL - unified block across PDP, cart and checkout
 * ---------------------------------------------------------------------------
 * One visual language in three places, using the Heaxabell theme tokens:
 * accent #fe2c55 / accent-soft #fff0f3 / line #e6e6ea / ink #161823.
 * Every block is a soft bordered box with a gift icon, a COMBO tag, the item
 * cards, and the combo price against the struck list total.
 * ========================================================================= */

/* ---------------------------------------------------------------------------
 * PDP - Bundle & Save box
 * ------------------------------------------------------------------------ */
.pdpCombo {
	margin: 14px 0 4px;
	border: 1px solid var(--accent, #fe2c55);
	background: var(--accent-soft, #fff0f3);
	border-radius: var(--radius, 12px);
	padding: 12px;
}
.pdpCombo__head {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
}
.pdpCombo__ic {
	line-height: 1;
	/* v2.4.0: gift SVG (was the 🎁 emoji) — match the theme summary icon. */
	margin-right: 0;
}
/* Same specificity note as .cartCombo__ic above. */
.pdpCombo__ic.pdpCombo__ic svg {
	width: 16px;
	height: 16px;
}
.pdpCombo__title {
	font-size: 14.5px;
	font-weight: 800;
	color: var(--ink, #161823);
}
.pdpCombo__badge {
	margin-left: auto;
	font-size: 10.5px;
	font-weight: 800;
	letter-spacing: .02em;
	text-transform: uppercase;
	color: #fff;
	background: var(--accent, #fe2c55);
	border-radius: 999px;
	padding: 3px 9px;
	white-space: nowrap;
}
.pdpCombo__sub {
	margin-top: 3px;
	font-size: 12.5px;
	color: var(--ink-2, #6b6b74);
	line-height: 1.4;
}
/* v2.9.0 — PDP combo block is DISPLAY-ONLY and is a horizontal SLIDER.
   No CTA, no + separators, no Add button. All combos this product belongs to
   are shown as cards; the shopper swipes to see the rest.
   Desktop: 2 cards per view. Mobile: 1 card per view. Both slide. */

/* --- slide hint (lives in the HEAD so it never scrolls out of view) ------ */
.pdpCombo__hint {
	display: inline-flex;
	align-items: center;
	gap: 3px;
	margin-left: auto;
	font-size: 10.5px;
	font-weight: 800;
	letter-spacing: .04em;
	text-transform: uppercase;
	color: var(--accent, #fe2c55);
	background: #fff;
	border: 1px solid rgba(254, 44, 85, .35);
	border-radius: 999px;
	padding: 3px 9px 3px 10px;
	white-space: nowrap;
	animation: pdpNudge 2.4s ease-in-out infinite;
}
/* .pdpCombo__badge carries `margin-left:auto`; when the hint is present it must
   not, or both fight for the same free space and the hint gets shoved. */
.pdpCombo__badge:has(+ .pdpCombo__hint) {
	margin-left: 8px;
}
.pdpCombo__hint svg { width: 12px; height: 12px; display: block; }
/* A gentle nudge rightwards — reads as "there is more this way" without being
   a distraction. Disabled for reduced-motion users (same rule as elsewhere). */
@keyframes pdpNudge {
	0%, 60%, 100% { transform: translateX(0); }
	75%           { transform: translateX(3px); }
}

/* --- rail + track ------------------------------------------------------- */
.pdpCombo__rail {
	position: relative;
	/* FIX 1: the fade (::after) lives on the rail, but the track is inset by
	   margin 0 -2px + padding 2px, so the track OVERHANGS the rail by 2px and
	   the scroll content painted past the rail's right edge. With overflow
	   visible the overscroll area + the strip between the fade's end and the
	   rail edge showed the card UN-faded — a ~12px white sliver at the right.
	   Clipping the rail is what makes the fade the true edge. */
	overflow: hidden;
}

/* Right-edge fade is the second slide affordance: content visibly continues
   past the fade. Pointer-events off so it never eats a swipe. */
.pdpCombo__rail::after {
	content: '';
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	width: 34px;
	pointer-events: none;
	/* The fade must reach FULL opacity before the edge. At `72%` the last ~9px
	   were still semi-transparent, so the NEXT card's 1px #e6e6ea border showed
	   through as a hairline at the rim. Ending the ramp at 92% leaves 2.7px of
	   solid --accent-soft on the rim, which covers it. */
	background: linear-gradient(to right, rgba(255, 240, 243, 0), var(--accent-soft, #fff0f3) 92%);
	opacity: 0;
	transition: opacity .18s;
}
.pdpCombo__rail.is-scrollable::after { opacity: 1; }

.pdpCombo__track {
	display: flex;
	gap: 10px;
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	-webkit-overflow-scrolling: touch;
	scrollbar-width: none;
	-ms-overflow-style: none;
	/* Vertical breathing room so a focused card's ring is not clipped by the
	   scroll container. */
	padding: 2px 2px 4px;
	margin: 9px -2px 0;
}
.pdpCombo__track::-webkit-scrollbar { display: none; }
.pdpCombo__track:focus-visible { outline: 2px solid var(--accent, #fe2c55); outline-offset: 2px; }

/* DESKTOP: a horizontal rail with no visible scrollbar has NO pointer affordance
   — a mouse has no pan gesture, so the only ways across were a trackpad, shift+wheel
   or the arrow keys. Chrome's ::-webkit-scrollbar { display:none } also kills
   native drag-to-scroll. `grab`/`grabbing` signals "this row moves" before any
   click, and the JS below turns it into a real drag. Touch devices keep their
   native panning — the class is added by the JS only for a fine pointer. */
.pdpCombo__track.is-grabbable { cursor: grab; }
.pdpCombo__track.is-grabbable.is-dragging { cursor: grabbing; scroll-snap-type: none; }

/* DESKTOP BASE: exactly 2 cards per view.
   calc((100% - gap) / 2) with gap 10px. flex-shrink:0 is what makes it scroll
   rather than squeeze, and scroll-snap aligns each card into place. */
.pdpCombo__card {
	flex: 0 0 calc((100% - 10px) / 2);
	min-width: 0;
	display: flex;
	flex-direction: column;
	background: #fff;
	border: 1px solid var(--line, #e6e6ea);
	border-radius: 10px;
	padding: 9px;
	scroll-snap-align: start;
}

/* ONE combo only -> take the FULL width. Half a card next to dead space reads
   like a broken row. Only when there is a single card: with 2+ we still want
   2-per-view so the pair fills the rail and the swipe hint tells the truth.
   :only-child is exactly that test — no extra markup needed. */
.pdpCombo__card:only-child { flex: 0 0 100%; }

/* --- card internals ----------------------------------------------------- */
.pdpCombo__cardtop {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 8px;
}
.pdpCombo__save {
	flex: 0 0 auto;
	font-size: 10px;
	font-weight: 800;
	letter-spacing: .02em;
	text-transform: uppercase;
	color: #fff;
	background: var(--accent, #fe2c55);
	border-radius: 999px;
	padding: 3px 8px;
	white-space: nowrap;
}
/* The combo title uses the base .pdpCombo__name typography. It sits in a flex
   row here so it may shrink; min-width:0 stops long words blowing the card out. */
.pdpCombo__cardtop .pdpCombo__name {
	flex: 1 1 auto;
	min-width: 0;
	font-size: 12px;
	font-weight: 800;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

/* Items STACK top/bottom (matches the cart + checkout combo cards).
   No + separator between them — removed by request. */
.pdpCombo__items {
	display: flex;
	flex-direction: column;
	gap: 7px;
	margin: 9px 0 0;
	overflow: visible;
}
.pdpCombo__item {
	display: flex;
	align-items: center;
	gap: 8px;
	min-width: 0;
	background: transparent;
	border: 0;
	border-radius: 0;
	padding: 0;
	text-align: left;
}
.pdpCombo__thumb {
	display: block;
	width: 44px;
	height: 44px;
	border-radius: 8px;
	overflow: hidden;
	background: var(--bg, #f1f1f2);
	flex-shrink: 0;
}
.pdpCombo__thumb img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.pdpCombo__pname {
	font-size: 11.5px;
	font-weight: 600;
	color: var(--ink, #161823);
	line-height: 1.32;
	min-width: 0;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}
.pdpCombo__price {
	display: flex;
	align-items: baseline;
	gap: 7px;
	margin-top: auto;
	padding-top: 9px;
	line-height: 1.15;
}
.pdpCombo__now {
	font-size: 16px;
	font-weight: 800;
	color: var(--accent, #fe2c55);
}
.pdpCombo__was {
	font-size: 11.5px;
	color: var(--ink-3, #a1a1aa);
	text-decoration: line-through;
}

/* MOBILE: 1 card per view. Still slides — just a wider card.
   `100%` (not `calc(100% - 10px)`) so a mobile card fills the rail exactly and
   scroll-snap lands flush. */
@media (max-width: 639px) {
	/* 88% instead of 100% so the NEXT card peeks in at the right edge. With a
	   full-width card there is nothing to see past the edge, and the swipe hint
	   becomes the only affordance — a peek is the stronger, wordless signal that
	   this row scrolls. scroll-snap still lands each card flush. */
	.pdpCombo__card { flex: 0 0 88%; }
}

@media (prefers-reduced-motion: reduce) {
	.pdpCombo__hint { animation: none; }
}


/* ---------------------------------------------------------------------------
 * Cart - combo group box
 * ------------------------------------------------------------------------ */
.cartCombo {
	margin: 12px 0 0;
	border: 1px solid var(--accent, #fe2c55);
	background: var(--accent-soft, #fff0f3);
	border-radius: var(--radius, 12px);
	padding: 12px;
}
.cartCombo__head {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
}
.cartCombo__ic {
	line-height: 1;
	/* v2.4.0: switched from the 🎁 emoji to the same inline gift SVG the
	   "Combo discount" summary row uses, so one feature has one icon.
	   Override .hx-ic's 18px default (and its right margin) to match the
	   old glyph's visual weight inside the compact box header. */
	margin-right: 0;
}
/* ⚠️ SPECIFICITY: the theme's .hx-ic svg{width:18px;height:18px} is ALSO
   (0,1,1), and combo.css is enqueued BEFORE app.min.css, so at equal
   specificity the theme wins and the icon renders 18px. Double up the class
   to reach (0,2,1) and win outright without !important. */
.cartCombo__ic.cartCombo__ic svg {
	width: 15px;
	height: 15px;
}
.cartCombo__tag {
	font-size: 10px;
	font-weight: 800;
	letter-spacing: .03em;
	text-transform: uppercase;
	color: #fff;
	background: var(--accent, #fe2c55);
	border-radius: 5px;
	padding: 2px 6px;
	flex-shrink: 0;
}
.cartCombo__title {
	font-size: 13.5px;
	font-weight: 700;
	color: var(--ink, #161823);
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.cartCombo__badge {
	margin-left: auto;
	font-size: 10.5px;
	font-weight: 800;
	letter-spacing: .02em;
	text-transform: uppercase;
	color: #fff;
	background: var(--accent, #fe2c55);
	border-radius: 999px;
	padding: 3px 9px;
	white-space: nowrap;
}
.cartCombo__items {
	margin: 10px 0 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
}


.cartCombo__item {
	display: flex;
	align-items: stretch;
	/* v2.7.8: no gap and no left padding — the thumbnail is the first thing
	   inside the card and now bleeds to its left edge, full height.
	   ⚠️ min-height is REQUIRED. The images are loading="lazy", so before they
	   decode the row has no intrinsic content height. Without a floor the two
	   cards collapse to a ~2px sliver and the combo box shows a blank band
	   between the "Paired items" box and the "Combo total" footer. */
	gap: 0;
	min-height: 64px;
	background: #fff;
	border: 1px solid var(--line, #e6e6ea);
	border-radius: 10px;
	overflow: hidden;
	padding: 0;
}
.cartCombo__thumb {
	position: relative;
	/* Bleeds to the card's left edge at full usable height.
	   ⚠️ `display:block` is load-bearing: this is a <span>, and on an inline box
	   a percentage height does NOT resolve — the <img> inside then collapses to
	   its intrinsic ratio (a 400x400 source renders 46x46 in a 46x62 column,
	   leaving ~17px of white under the photo). Block makes `height:100%` real.
	   ⚠️ min-height is the collapse floor: the images are `loading="lazy"`, so
	   before decode the row has no intrinsic height and would fall back to the
	   2px border. Left/right corners stay square — the card clips the left via
	   overflow:hidden, and a radius on the right would notch against the body. */
	display: block;
	width: 46px;
	/* v2.8.5: HARD pixel height = the item's min-height (64px). Every percentage
	   approach failed: with `height:100%` or `auto`+stretch, the box measured 62px
	   but the <img>'s `height:100%` resolved against a NON-definite parent and
	   fell back to the source's intrinsic ratio — a 400x400 image rendered 46x46
	   and left 17px of white at the bottom. A literal px height is definite, so
	   the child's 100% finally resolves. */
	height: 64px;
	align-self: stretch;
	flex: 0 0 46px;
	/* v2.8.13: right corners rounded again (user request — the reset to 0 in
	   v2.8.11 was collateral from the checkout-cell fix). The card's own
	   border-radius:10px + overflow:hidden no longer reaches the image now that
	   the thumb fills the row's full height, so the radius is set here.
	   Left stays square: it sits flush against the card border. */
	border-radius: 0 10px 10px 0;
	overflow: hidden;
	background: var(--bg, #f1f1f2);
}
.cartCombo .cartCombo__thumb img {
	/* ⚠️ BOTH classes are required — do NOT "tidy" this to `.cartCombo__thumb img`.
	   WooCommerce's own sheet ships `.woocommerce img { height: auto }` = (0,1,1),
	   which ties with `.cartCombo__thumb img` (0,1,1); on a tie source order wins,
	   and WC's sheet loads AFTER combo.css, so the image reverted to its intrinsic
	   ratio — 400x400 rendered 46x46 inside a 64px thumb, leaving 17px of white.
	   Adding the real `.cartCombo` ancestor class reaches (0,2,1) and wins outright.
	   ⚠️ A comma list does NOT help: `.a img, .a img` is still (0,1,1) twice. */
	width: 46px;
	height: 64px;
	/* v2.8.13: mirror the thumb's right-hand radius so the two don't fight —
	   the thumb's overflow:hidden does the clipping. */
	border-radius: 0 10px 10px 0;
	object-fit: cover;
	display: block;
}
.cartCombo__qty {
	position: absolute;
	bottom: 0;
	right: 0;
	background: var(--ink, #161823);
	color: #fff;
	font-size: 10px;
	font-weight: 800;
	line-height: 1;
	padding: 2px 5px;
	border-radius: 6px 0 0 0;
}
.cartCombo__meta {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
	/* the card no longer pads, so the text column carries it.
	   Right padding keeps the text clear of the × button. */
	padding: 7px 9px;
	padding-right: 34px;
	justify-content: center;
}
.cartCombo__sub {
	display: flex;
	align-items: baseline;
	gap: 4px;
	flex-wrap: wrap;
	min-width: 0;
}
.cartCombo__dash {
	color: var(--ink-3, #a1a1aa);
	font-size: 11px;
	font-weight: 600;
	margin: 0 1px;
}
.cartCombo__name {
	font-size: 12.5px;
	font-weight: 600;
	color: var(--ink, #161823);
	line-height: 1.32;
	/* v2.8.0: no line clamp — combo product names are long ("HEAXABELL - ( AS IS)
	   ALVA 16.0 TOP ( RIBBON)") and 2-line clamping chopped the tail and the size.
	   Let it wrap to as many lines as it needs; the thumb has a fixed height so
	   the row still stays tidy. */
	overflow-wrap: anywhere;
}
.cartCombo__unit {
	font-size: 12px;
	color: var(--ink-2, #6b6b74);
	white-space: nowrap;
	/* v2.8.11: pin these or the checkout <td>'s uppercase/letter-spacing wins by
	   inheritance and the price line renders differently from the cart. */
	text-transform: none;
	letter-spacing: 0;
}
.cartCombo__foot {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 10px;
	margin-top: 11px;
	padding-top: 10px;
	border-top: 1px dashed rgba(254, 44, 85, .28);
}
.cartCombo__label {
	font-size: 12.5px;
	font-weight: 600;
	color: var(--ink-2, #6b6b74);
}
.cartCombo__amt {
	display: inline-flex;
	align-items: baseline;
	gap: 7px;
}
.cartCombo__amt b {
	font-size: 16px;
	font-weight: 800;
	color: var(--accent, #fe2c55);
}
.cartCombo__amt s {
	font-size: 12px;
	color: var(--ink-3, #a1a1aa);
}

@media (max-width: 400px) {
	.cartCombo__title { white-space: normal; }
}

/* ---------------------------------------------------------------------------
 * Checkout - combo contents list inside the summary row
 * ------------------------------------------------------------------------ */
.hx-combo-row__list {
	list-style: none;
	margin: 6px 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 3px;
}
.hx-combo-row__li {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 8px;
	font-size: 11.5px;
	line-height: 1.35;
}
.hx-combo-row__li-name {
	color: var(--ink-2, #6b6b74);
	min-width: 0;
}
.hx-combo-row__li-amt {
	color: var(--ink-3, #a1a1aa);
	white-space: nowrap;
	flex-shrink: 0;
}

/* ---------------------------------------------------------------------------
 * Pairing additions — the nested "which pairs with which" layer
 * ------------------------------------------------------------------------ */

/* Cart combo box: the pair line + the "+" between nested members */
.cartCombo__pair {
	margin: 9px 0 0;
	padding: 7px 9px;
	background: rgba(254, 44, 85, .07);
	border-radius: 8px;
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.cartCombo__pair-label {
	font-size: 9.5px;
	font-weight: 800;
	letter-spacing: .05em;
	text-transform: uppercase;
	color: var(--accent, #fe2c55);
	opacity: .85;
}
.cartCombo__pair-names {
	font-size: 12px;
	font-weight: 600;
	color: var(--ink, #161823);
	line-height: 1.35;
}
.cartCombo__items {
	/* v2.8.14: stacked top/bottom at EVERY width, including desktop. This was
	   `flex-direction: row` (side-by-side on desktop) with a max-width:560px
	   override back to column — phones stacked, desktop did not. User wants the
	   top/bottom layout everywhere, so this is now the single source of truth.
	   ⚠️ Do NOT reintroduce `flex-direction: row` here or on a wider breakpoint. */
	flex-direction: column;
	align-items: stretch;
	gap: 8px;
}
.cartCombo__item {
	/* Was `flex: 1 1 0` for the side-by-side row (equal-width columns). Once the
	   items stack, they take the full width and their natural height instead. */
	flex: 0 0 auto;
	width: 100%;
	min-width: 0;
}

/* Checkout contents list: the C1/C2 marker */
.hx-combo-row__li-no {
	flex-shrink: 0;
	font-size: 9.5px;
	font-weight: 800;
	letter-spacing: .03em;
	color: #fff;
	background: var(--accent, #fe2c55);
	border-radius: 4px;
	padding: 1px 5px;
	line-height: 1.5;
	align-self: center;
}
.hx-combo-row__li-name {
	flex: 1 1 auto;
}

/* Cart line locked badge: room for the pairing text */
.cartItem__combo__txt--lock {
	line-height: 1.4;
}

/* Stack the paired items on PHONES (not just <=400px).
   The old 400px cutoff missed the 414/428/430px phones (iPhone Plus / XR /
   Pro Max), which kept the side-by-side row on a screen far too narrow for
   it. 560px covers every phone in portrait with room to spare while leaving
   tablets and desktop on the row layout. */
@media (max-width: 560px) {
	/* v2.8.14: the .cartCombo__items direction override was removed — the base
	   rule is column at all widths now, so repeating it here only created two
	   places to keep in sync. */
	.hx-combo-row__li {
		flex-wrap: wrap;
	}
}

/* ---------------------------------------------------------------------------
 * v1.7.0 — variant display + hide combo-consumed product rows
 * ------------------------------------------------------------------------ */

/* Variant line inside a combo member row ("Walnut, (L/XL)") */
.cartCombo__var {
	/* v2.8.1: inline — sits beside the price on one line inside __sub.
	   v2.8.11: the checkout cell carries the theme's `text-transform: uppercase`,
	   which WINS over plain inheritance and made the variant render as caps on
	   checkout but lowercase in the cart (same markup, different look). Set the
	   text-transform on BOTH surfaces explicitly so the two match, and pin
	   letter-spacing/font-size too since those are also inherited in a <td>. */
	display: inline;
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0;
	color: var(--ink-2, #6b6b74);
	line-height: 1.3;
	text-transform: none;
}

/* Checkout: a product consumed by a combo is NOT listed as a loose row — the
   combo row above already names it with its variant. Server-side class, so this
   is a filter rather than a hide to avoid a flash of the wrong content. */
.checkoutPage table.shop_table tr.hx-in-combo,
.checkoutPage .hx-product-table tr.hx-in-combo,
.woocommerce-checkout table.shop_table tr.hx-in-combo {
	display: none !important;
}

/* Give the checkout pairing list a little more room now that variants appear */
.hx-combo-row__li-name {
	line-height: 1.45;
}
.hx-combo-row__li-no {
	min-width: 20px;
	text-align: center;
}

/* ---------------------------------------------------------------------------
 * v1.8.0 — cart hides combo rows; checkout reuses the cart combo boxes
 * ------------------------------------------------------------------------ */

/* CART: a product already consumed by a combo is not listed as a loose line —
   the combo box below already names it with its variant. Same marker as
   checkout, different container (.cartItem is the theme's own div, not a WC tr). */
.cartList .cartItem.hx-in-combo,
.cartPage .cartItem.hx-in-combo,
.cartItem.hx-in-combo {
	display: none !important;
}

/* CHECKOUT: the combo row now carries the cart's `.cartCombo` boxes. A table
   cell has no padding of its own here, and the box must not inherit the
   right-aligned price styling the product rows use. */
.checkoutPage .hx-ocard--product table.shop_table td.hx-combo-cell--label,
.hx-product-table td.hx-combo-cell--label {
	text-align: left !important;
	padding: 10px 12px 12px !important;
	background: transparent;
	box-shadow: none;
	border-radius: 0;
}

.hx-combo-row__head {
	display: flex;
	align-items: center;
	gap: 8px;
	margin-bottom: 9px;
}

.hx-combo-row__boxes {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

/* Inside checkout the box is full-width, not a flex row sibling */
.cartCombo--ck {
	width: 100%;
	box-sizing: border-box;
	margin: 0;
}

/* v2.8.13: the rounded right thumb corners are a CART-only look. On checkout the
   card sits in a table cell and the radius read as a stray clip against the row
   (the original complaint), so square it there. Scoped with the extra
   `.cartCombo--ck` class so it does not need !important. */
.cartCombo--ck .cartCombo__thumb,
.cartCombo--ck .cartCombo__thumb img {
	border-radius: 0;
}

/* v2.8.11: neutralised. This rule (from the two-column era) set a 4px
   right-hand radius on the combo cell. The row is now a single colspan=2 cell,
   so `:last-child` still matches it — and that 4px radius clipped the top-right
   and bottom-right of the product thumbnail inside .cartCombo__item, making the
   image corners look rounded on checkout while the cart (no cell radius) was
   square. The image itself has border-radius:0; the radius was coming from here. */
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-row td.hx-combo-cell:last-child,
.hx-product-table tr.hx-combo-row td.hx-combo-cell:last-child {
	text-align: right !important;
	vertical-align: top;
	padding-top: 16px !important;
	background: #f4fbf6;
	border-radius: 0;
}

/* Checkout contents list: same phone-stacking rule as the cart. */
@media (max-width: 560px) {
	.hx-combo-row__head {
		flex-wrap: wrap;
		gap: 6px;
	}
	/* v2.8.14: checkout items direction override removed — same reason as above. */
}

/* ---------------------------------------------------------------------------
 * v1.9.0 — checkout combo row full width; cart combo bottom spacing
 * ------------------------------------------------------------------------ */

/* CHECKOUT: the combo row is now a single colspan=2 cell (the outer "Subtotal"
   column was redundant — the box already shows its own Combo total + struck
   list price). Give the box the full row so it reads as one unit. */
.hx-product-table tr.hx-combo-row td.hx-combo-cell--label[colspan] {
	width: 100%;
}

/* The old right-hand amount cell is gone — make sure nothing reserves space
   for it and the box can use the whole width. */
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-row td.hx-combo-cell:last-child,
.hx-product-table tr.hx-combo-row td.hx-combo-cell:last-child {
	text-align: left !important;
	background: transparent !important;
	border-radius: 0 !important;
}

/* CART: the combo box is the last thing in the cart list, so it needs its own
   bottom margin before the subtotal / checkout button. Previously the shell
   hugged it and the button crowded the box. */
.cartForm .cartCombo:last-child,
.cartList > .cartCombo:last-child,
.cartCombo:last-of-type {
	margin-bottom: 18px;
}

/* When the combo box is the final child of the cart list, keep the list's own
   bottom padding from collapsing against it. */
.cartList {
	padding-bottom: 4px;
}

.cartList > .cartCombo:last-child {
	margin-top: 12px;
}

@media (max-width: 400px) {
	.cartForm .cartCombo:last-child,
	.cartList > .cartCombo:last-child,
	.cartCombo:last-of-type {
		margin-bottom: 22px;
	}
}

/* ---------------------------------------------------------------------------
 * v1.9.1 — cart combo bottom spacing (corrected selector)
 * ------------------------------------------------------------------------
 * The combo boxes render as SIBLINGS of `.cartForm` inside `.cartPage`, not
 * inside the cart list:
 *   .cartPage > .cartForm, .cartCombo [, .cartCombo], .cartSummary, .cart__bottombar
 * So `:last-child` never matches. The box that needs bottom air is any
 * `.cartCombo` that directly precedes `.cartSummary` (the subtotal block).
 * ------------------------------------------------------------------------ */

.cartPage .cartCombo + .cartSummary,
.cartPage .cartCombo ~ .cartSummary {
	margin-top: 18px;
}

/* Whichever combo box sits immediately before the summary gets the gap. */
.cartPage .cartCombo:has(+ .cartSummary) {
	margin-bottom: 18px;
}

/* Fallback for browsers without :has() — pad the summary instead, which is
   visually identical because the box is the element right above it. */
.cartPage .cartSummary {
	margin-top: 18px;
}

/* Tighten it back if there is no combo box: the summary after `.cartForm`
   already has its own rhythm. */
.cartPage .cartForm + .cartSummary {
	margin-top: 12px;
}

@media (max-width: 400px) {
	.cartPage .cartCombo:has(+ .cartSummary),
	.cartPage .cartCombo + .cartSummary,
	.cartPage .cartSummary {
		margin-top: 20px;
	}
	.cartPage .cartCombo:has(+ .cartSummary) {
		margin-bottom: 20px;
	}
}

/* ---------------------------------------------------------------------------
 * v2.0.0 — cart summary: combo discount + "You saved" line
 * ------------------------------------------------------------------------
 * The combo discount is a NEGATIVE CART FEE, so WC's own `--discount` row
 * (driven by get_cart_discount_total()) never rendered for it. These styles
 * dress the new row so it reads as a saving, not a charge.
 * ------------------------------------------------------------------------ */

/* Combo discount row — same green as WC's coupon discount row, with the tag
   icon inheriting the colour so it does not read as a normal line item. */
.cartSummary__row--combo {
	color: var(--green, #04b462);
	font-weight: 700;
}

.cartSummary__row--combo > span:first-child {
	display: inline-flex;
	align-items: center;
	color: var(--green, #04b462);
}

.cartSummary__row--combo .hx-ic {
	color: var(--green, #04b462);
	margin-right: 6px;
}

.cartSummary__row--combo .hx-ic svg {
	width: 16px;
	height: 16px;
}

.cartSummary__row--combo span:last-child {
	color: var(--green, #04b462);
	font-weight: 800;
	white-space: nowrap;
}

/* "You saved RMxx" reassurance line, under the total. */
.cartSummary__saved {
	display: flex;
	align-items: center;
	justify-content: center;
	margin-top: 10px;
	padding: 8px 12px;
	border-radius: 10px;
	background: #e6f7ef;
	color: #0a8a4e;
	font-size: 13px;
	font-weight: 700;
	line-height: 1.3;
	text-align: center;
}

.cartSummary__saved b {
	font-family: var(--font-price, inherit);
	font-weight: 800;
	margin-left: 4px;
}


@media (max-width: 400px) {
	.cartSummary__saved {
		font-size: 12.5px;
		padding: 7px 10px;
	}
}

/* The combo fee bar (moved into the summary by combo.js) is superseded by the
   dedicated "Combo discount" row the theme now renders. Hide it so the discount
   is not listed twice. */
.cartSummary .hx-combo-fees,
.cartPage .hx-combo-fees {
	display: none !important;
}

/* Checkout: the combo discount fee row is now SHOWN (relabelled by combo.js as
   "Combo discount") instead of hidden, so the Subtotal -> Total gap is explained.
   Style it to match the cart summary row. */
#order_review tr.hx-combo-fee th,
.checkoutPage tr.hx-combo-fee th,
tr.hx-combo-fee th {
	color: var(--green, #04b462) !important;
	font-weight: 700 !important;
}

#order_review tr.hx-combo-fee td,
.checkoutPage tr.hx-combo-fee td,
tr.hx-combo-fee td {
	color: var(--green, #04b462) !important;
	font-weight: 800 !important;
	white-space: nowrap;
}

tr.hx-combo-fee .hx-combo-fee__label {
	display: inline-flex;
	align-items: center;
}

tr.hx-combo-fee .hx-ic {
	color: var(--green, #04b462);
	margin-right: 6px;
}

tr.hx-combo-fee .hx-ic svg {
	width: 16px;
	height: 16px;
}

/* The older rule (`.checkoutPage .hx-product-table tfoot tr.hx-combo-fee`
   { display:none !important }) hid the fee row. Now that we WANT it shown and
   relabelled "Combo discount", that rule must be beaten — an inline
   style.display='' cannot override !important. */
.checkoutPage .hx-product-table tfoot tr.fee.hx-combo-fee,
.checkoutPage .hx-product-table tfoot tr.hx-combo-fee,
#order_review tfoot tr.fee.hx-combo-fee,
tr.hx-combo-fee {
	display: table-row !important;
}

/* ---------------------------------------------------------------------------
 * v2.0.5 — combo ABOVE the product list (cart + checkout), "You save" on checkout
 * ------------------------------------------------------------------------ */

/* Cart: the combo boxes now render BEFORE .cartForm, so they need a gap below
   rather than the old margin-top. */
.cartPage .cartCombo {
	margin-top: 0;
}

.cartPage .cartCombo + .cartForm {
	margin-top: 12px;
}

/* Now that the boxes sit above the list, the old ":has(+ .cartSummary)" bottom
   gap is only needed when there is NO product list between them. */
.cartPage .cartCombo:has(+ .cartSummary) {
	margin-bottom: 18px;
}

/* Checkout: combo row is the first <tr> in <tbody>, so kill its top margin and
   keep the boxes from butting against the PRODUCT/SUBTOTAL header. */
.hx-combo-row > td.hx-combo-cell {
	padding-top: 4px;
	padding-bottom: 12px;
}

.hx-combo-row__boxes {
	margin-top: 8px;
}

/* Checkout "You saved" row — same green pill as the cart summary. */
tr.hx-checkout-saved > td {
	padding: 10px 0 2px !important;
	border: 0 !important;
}

tr.hx-checkout-saved .cartSummary__saved {
	margin-top: 0;
}

/* ---------------------------------------------------------------------------
 * v2.0.6 — per-line combo hiding, header below combo, cart combo spacing
 * ------------------------------------------------------------------------ */

/* CART: gap BETWEEN combo boxes. They are siblings in `.cartPage`, and the base
   `.cartCombo` rule only sets `margin: 12px 0 0` — so two boxes sat flush against
   each other with no separation (user: "in cart need proper spacing between
   combo"). Space every box that follows another box. */
.cartPage .cartCombo + .cartCombo {
	margin-top: 14px;
}

/* First box sits directly under the page head — give it room. */
.cartPage .pageHead + .cartCombo,
.cartPage > .cartCombo:first-of-type {
	margin-top: 16px;
	margin-bottom: 0;
}

/* Last box before the product form needs air below, so the form does not butt
   against it. Earlier rules put the gap on `.cartSummary`; now that the boxes are
   ABOVE the form, the gap belongs on the box, not on the summary. */
.cartPage .cartCombo + .cartForm {
	margin-top: 16px;
}

.cartPage .cartCombo + .cartSummary,
.cartPage .cartCombo ~ .cartSummary {
	margin-top: 18px;
}

/* Reset the stale v1.9.1 expectation: the summary follows `.cartForm` now, so it
   must NOT inherit a large top margin from the combo rules. */
.cartPage .cartForm + .cartSummary {
	margin-top: 14px;
}

/* ---------------------------------------------------------------------------
 * CHECKOUT: PRODUCT / SUBTOTAL header moves BELOW the combo section
 * ------------------------------------------------------------------------ */

/* The real <thead> always renders above <tbody>, so it is suppressed while a
   combo is live and a matching `.hx-combo-head` row is emitted at the end of the
   combo row instead (see hx_combo_checkout_card()). */
.hx-product-table:has(.hx-combo-row) > thead,
.checkoutPage .hx-ocard--product table.shop_table:has(tr.hx-combo-row) > thead {
	display: none;
}

/* JS fallback for browsers without :has() — combo.js adds `.hx-has-combo` to the
   table when it finds the row. */
.hx-product-table.hx-has-combo > thead {
	display: none;
}

.hx-product-table tr.hx-combo-head > th,
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-head > th {
	font-size: 11px;
	font-weight: 600;
	letter-spacing: .04em;
	text-transform: uppercase;
	color: var(--ink-3, #a1a1aa);
	text-align: left;
	padding: 14px 12px 8px;
	border-bottom: 1px solid var(--line, #e6e6ea);
	background: transparent;
}

.hx-product-table tr.hx-combo-head > th.product-total,
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-head > th.product-total {
	text-align: right;
}

/* The combo cell's bottom padding already separates it from the header row. */
.hx-combo-row > td.hx-combo-cell {
	padding-bottom: 4px !important;
}

/* ---------------------------------------------------------------------------
 * v2.0.7 — checkout combo card aligns with the single-product rows
 * ------------------------------------------------------------------------
 * The theme's product cells are `padding: 10px 0` (see app.css:
 * `.checkoutPage .hx-ocard--product table.shop_table th, td { padding:10px 0 }`)
 * — they have NO left/right padding, so a product card sits flush with the table
 * edge. The combo cell instead carried `padding: 10px 12px 12px`, which pushed the
 * combo card 12px inward on both sides and made it look indented next to the
 * product rows (user: "fix combo padding to have same line with single product
 * padding on left right outside combo card").
 *
 * Measured before: table left 758 / combo card left 770 (12px in);
 *                  table right 1167 / combo card right 1155 (12px in).
 *
 * Zero the horizontal padding so the combo card's OUTER edge lines up with the
 * product card's outer edge. The vertical padding stays for breathing room.
 * ------------------------------------------------------------------------ */

.checkoutPage .hx-ocard--product table.shop_table td.hx-combo-cell--label,
.hx-product-table td.hx-combo-cell--label,
.hx-combo-row > td.hx-combo-cell {
	padding-left: 0 !important;
	padding-right: 0 !important;
}

/* The v1.9.x right-hand cell rules set `padding-top: 16px` and a tinted
   background for a column that no longer exists (the row is a single colspan=2
   cell). Neutralise them so nothing re-introduces the inset or a stray tint. */
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-row td.hx-combo-cell:last-child,
.hx-product-table tr.hx-combo-row td.hx-combo-cell:last-child {
	padding-left: 0 !important;
	padding-right: 0 !important;
	padding-top: 4px !important;
	background: transparent !important;
	border-radius: 0 !important;
}

/* The header row's own cells must land on the same vertical line as the combo
   card above them and the product rows below. It inherited the theme's 10px 0,
   which is already correct — this only guards against later overrides. */
.hx-product-table tr.hx-combo-head > th,
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-head > th {
	padding-left: 0;
	padding-right: 0;
}

/* `box-sizing: border-box` is already set on `.cartCombo--ck`; assert it here
   too so the card never overflows the cell if a border is added later. */
.cartCombo--ck {
	box-sizing: border-box;
	max-width: 100%;
}

/* ---------------------------------------------------------------------------
 * v2.0.8 — tighten the combo card to PRODUCT/SUBTOTAL header gap
 * ------------------------------------------------------------------------
 * Measured before: combo card bottom 2264 → header text top 2298 = 35px gap.
 * Every other vertical rhythm in this table is ~10-14px, so the seam read as a
 * hole (user: "fix spacing about product and subtotal header with combo card").
 *
 * Cause — TWO paddings stacked on the same seam:
 *   1. `.hx-product-table td.hx-combo-cell--label` → `padding: 10px 12px 12px !important`
 *   2. `.hx-combo-head > th` → `padding: 14px 12px 8px`
 * 12 + 14 = 26px of padding, plus line-height, before the header text appears.
 *
 * SPECIFICITY TRAP (cost two failed deploys — do not repeat): a later rule does
 * NOT win by source order when both are !important. Read live from the CSSOM, the
 * blocking rule is
 *   `.checkoutPage .hx-ocard--product table.shop_table td.hx-combo-cell--label`
 *   → !important, specificity (0,4,6)
 * while `.hx-combo-row > td.hx-combo-cell` is only (0,2,3). My earlier override
 * WAS also !important and WAS last in the file, and still lost — computed stayed
 * 12px both times. Specificity decides among !important declarations.
 *
 * Fix: match the winner's specificity (0,4,6) so the override actually applies.
 * The selector below is the same chain as the blocker, with an added
 * `.hx-combo-row` class on the <tr> to guarantee we also beat any future tie.
 * ------------------------------------------------------------------------ */

/* Header labels the loose products BELOW it, so it keeps a small top pad to
   separate it from the combo card — but not 14px on top of the cell's 12px. */
.hx-product-table tr.hx-combo-head > th,
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-head > th {
	padding-top: 0;
	padding-bottom: 6px;
	padding-left: 0;
	padding-right: 0;
}

/* Combo cell: 12px bottom pad → 4px. Selector specificity (0,5,7) > (0,4,6). */
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-row td.hx-combo-cell--label,
.hx-product-table tr.hx-combo-row td.hx-combo-cell--label,
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-row td.hx-combo-cell,
.hx-product-table tr.hx-combo-row td.hx-combo-cell {
	padding-bottom: 4px !important;
	padding-left: 0 !important;
	padding-right: 0 !important;
}

/* The card's OWN 12px bottom padding was the last contributor: measured content
   bottom 2251 → card box bottom 2264 → header text 2290. Trim the card's bottom
   padding on checkout only (the cart keeps its full card chrome), so the seam
   matches the ~10-14px rhythm the rest of the table uses. */
.cartCombo--ck {
	padding-bottom: 8px;
}

/* ROOT CAUSE of the remaining gap — a leftover CART rule was matching the
   checkout card: `.cartCombo:last-of-type { margin-bottom: 18px }` (from v1.9.0,
   written when the cart boxes sat last on the page). Specificity 0,2,0 beat
   `.cartCombo--ck { margin: 0 }` at 0,1,0, so computed margin-bottom was 22px and
   the card overflowed its own cell (card bottom 2260 vs container 2282).
   Scope that rule to the cart page only — the checkout card must never carry a
   bottom margin, its row spacing is handled by the cell padding and the boxes gap. */
.cartPage .cartCombo:last-of-type {
	margin-bottom: 18px;
}

.checkoutPage .cartCombo--ck,
tr.hx-combo-row .cartCombo--ck {
	margin-bottom: 0 !important;
}

/* Nothing inside the combo cell should escape the cell box. */
tr.hx-combo-row .hx-combo-row__boxes {
	margin-bottom: 0;
}

/* Now that every stray margin is gone the seam is only 5px — too tight, the card
   nearly touches the header. Restore a deliberate ~14px so the header reads as a
   new section (matching the table's 10-14px rhythm) without the old 35px hole. */
/* SAME specificity trap as above — must use the (0,5,7) selector or the (0,4,6)
   rule keeps winning despite !important. */
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-row td.hx-combo-cell--label,
.hx-product-table tr.hx-combo-row td.hx-combo-cell--label,
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-row td.hx-combo-cell,
.hx-product-table tr.hx-combo-row td.hx-combo-cell {
	padding-bottom: 14px !important;
}

/* ---------------------------------------------------------------------------
 * v2.0.9 — combo header row matches the Subtotal / Shipping / Total rhythm
 * ------------------------------------------------------------------------
 * User: "fix border top and bottom spacing with text product and subtotal same
 *        with other like subtotal, shipping, total"
 *
 * Measured (mobile, live):
 *   comboHead_th  padT 0px    padB 6px    h 24px
 *   product_td    padT 10px   padB 10px
 *   tfoot Subtotal padT 10px  padB 10px   h 42px
 *   tfoot Shipping padT 10px  padB 10px
 *   tfoot Total    padT 10px  padB 10px
 *
 * Every other row in the product table uses `padding: 10px 0`. The combo header
 * was left at `0 / 6px` from the v2.0.8 gap fix, so its text sat too close to the
 * card above and its border-bottom crowded the row below.
 *
 * Fix: give the header the SAME `10px 0` box as its siblings, and restore the
 * horizontal zero-padding (the label is a colspan cell aligned to the product rows,
 * so it must not inset).
 * ------------------------------------------------------------------------ */

.hx-product-table tr.hx-combo-head > th,
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-head > th {
	padding-top: 10px !important;
	padding-bottom: 10px !important;
	padding-left: 0 !important;
	padding-right: 0 !important;
	border-bottom: 1px solid var(--line, #e6e6ea);
}

/* The right-aligned SUBTOTAL label must keep the same box as its PRODUCT sibling;
   only its text alignment differs. */
.hx-product-table tr.hx-combo-head > th.product-total,
.checkoutPage .hx-ocard--product table.shop_table tr.hx-combo-head > th.product-total {
	padding-top: 10px !important;
	padding-bottom: 10px !important;
	text-align: right;
}

/* ===================================================================
   v2.3.0 — × on combo member rows
   ===================================================================
   One click removes ONE unit of that line. Small and quiet so it never
   competes with the product name, but padded to a comfortable tap
   target on mobile. Palette: pink #fe2c55 / soft #fff0f3 only.
   =================================================================== */

.cartCombo__item {
	position: relative;
}

/* v2.8.19 — the × is a CART-PAGE action only.
   Checkout is the review/commit step: letting a shopper delete a combo member
   there silently broke the combo and threw them back to an empty state. The
   renderer no longer emits the button on the checkout card, and this is the
   belt-and-braces guard so the control can never reappear there even if a
   template or a cached fragment is out of date.
   Scope is `.cartCombo--ck`, which ONLY the checkout card carries — the cart box
   (.cartCombo without the modifier) keeps its ×. */
.checkoutPage .cartCombo--ck .cartCombo__x,
tr.hx-combo-row .cartCombo--ck .cartCombo__x,
.cartCombo--ck .cartCombo__x {
	display: none;
}

.cartCombo__x {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	align-self: center;
	/* v2.8.0: real inset from the card's right edge + a proper tap target.
	   Was 22x22 with no right margin, so the circle sat flush against the border
	   and was below the 32px comfort minimum for a thumb. */
	margin: 0 10px 0 auto;
	width: 26px;
	height: 26px;
	min-width: 26px;
	padding: 0;
	border: 1px solid var(--line, #e6e6ea);
	border-radius: 50%;
	background: #fff;
	color: var(--ink-2, #6b6b74);
	font-size: 15px;
	line-height: 1;
	font-weight: 500;
	cursor: pointer;
	-webkit-appearance: none;
	appearance: none;
	transition: background .15s ease, color .15s ease, border-color .15s ease;
}

.cartCombo__x:hover,
.cartCombo__x:focus-visible {
	background: #fff0f3;
	border-color: #fe2c55;
	color: #fe2c55;
	outline: none;
}

.cartCombo__x:disabled,
.cartCombo__x.is-busy {
	opacity: .45;
	cursor: default;
}

/* Roomier tap target on phones without making it visually louder. */
@media (max-width: 480px) {
	.cartCombo__x {
		width: 26px;
		height: 26px;
		font-size: 16px;
	}
}
