/**
 * TJL UX Layer
 *
 * Section 1 — required-selection gating (product pages)
 * Section 2 — form control polish (checkbox / radio)
 *
 * Brand tokens. The storefront currently runs two competing accents: the
 * Taqwa magenta of the logo and a purple inherited from The Plus Addons'
 * defaults. These variables name the intended ones so later sections stop
 * hard-coding either.
 */
:root {
	--tjl-magenta: #e4097f;
	--tjl-plum: #3a1259;
	--tjl-purple: #8441c0;
	--tjl-ink: #2f363d;
	--tjl-muted: #6b7280;
	--tjl-line: #d9d2e0;
	--tjl-focus: #e4097f;
}

/* ------------------------------------------------------------------ 1. gate */

/**
 * A gated button stays visible, keyboard-reachable and legible — it is not
 * hidden and not `disabled`, so assistive tech still announces it and the
 * reason beside it. Only the click is refused.
 */
.single_add_to_cart_button.tjl-ux-gated,
button.tjl-ux-gated,
.tjl-ux-gated[name="tjl_pp_buy_now"],
.tjl-pp-buy-now.tjl-ux-gated {
	filter: grayscale(100%);
	opacity: 0.55;
	cursor: not-allowed;
	box-shadow: none;
	transition: opacity 0.18s ease, filter 0.18s ease;
}

/* Never let a greyed control look hoverable. */
.single_add_to_cart_button.tjl-ux-gated:hover,
button.tjl-ux-gated:hover,
.tjl-pp-buy-now.tjl-ux-gated:hover {
	filter: grayscale(100%);
	opacity: 0.55;
	transform: none;
}

.tjl-ux-gate-hint {
	margin: 0 0 10px;
	padding: 9px 12px;
	border-left: 3px solid var(--tjl-magenta);
	background: rgba(228, 9, 127, 0.06);
	border-radius: 4px;
	color: var(--tjl-ink);
	font-size: 14px;
	line-height: 1.45;
}

.tjl-ux-gate-hint[hidden] {
	display: none !important;
}

/* A short, non-looping pulse when someone taps the gated button. */
.tjl-ux-gate-hint-flash {
	animation: tjl-ux-pulse 0.6s ease 2;
}

.tjl-ux-gate-flash {
	animation: tjl-ux-ring 0.6s ease 2;
	border-radius: 6px;
}

@keyframes tjl-ux-pulse {
	50% {
		background: rgba(228, 9, 127, 0.18);
	}
}

@keyframes tjl-ux-ring {
	50% {
		box-shadow: 0 0 0 3px rgba(228, 9, 127, 0.35);
	}
}

/* ---------------------------------------------------- 2. form control polish */

/**
 * WooCommerce's "Remember me" and the checkout consent boxes render as the
 * raw 13x13 native control: too small to hit on a phone (44px is the floor),
 * and at 2x it reads as a grey dot rather than a checkbox. Restyle the box
 * itself and give the label a real hit area.
 */
.woocommerce form .form-row input[type="checkbox"],
.woocommerce-form__input-checkbox,
.woocommerce input[type="checkbox"],
.woocommerce input[type="radio"] {
	appearance: none;
	-webkit-appearance: none;
	width: 20px;
	height: 20px;
	margin: 0 10px 0 0;
	flex: 0 0 20px;
	border: 2px solid var(--tjl-line);
	background: #fff;
	vertical-align: middle;
	position: relative;
	cursor: pointer;
	transition: border-color 0.15s ease, background-color 0.15s ease;
}

.woocommerce input[type="checkbox"] {
	border-radius: 5px;
}

.woocommerce input[type="radio"] {
	border-radius: 50%;
}

.woocommerce input[type="checkbox"]:hover,
.woocommerce input[type="radio"]:hover {
	border-color: var(--tjl-magenta);
}

.woocommerce input[type="checkbox"]:checked,
.woocommerce input[type="radio"]:checked {
	background: var(--tjl-magenta);
	border-color: var(--tjl-magenta);
}

/* A real tick, drawn — not a dot. */
.woocommerce input[type="checkbox"]:checked::after {
	content: "";
	position: absolute;
	left: 5px;
	top: 1px;
	width: 5px;
	height: 10px;
	border: solid #fff;
	border-width: 0 2.5px 2.5px 0;
	transform: rotate(45deg);
}

.woocommerce input[type="radio"]:checked::after {
	content: "";
	position: absolute;
	inset: 3px;
	border-radius: 50%;
	background: #fff;
}

.woocommerce input[type="checkbox"]:focus-visible,
.woocommerce input[type="radio"]:focus-visible {
	outline: 2px solid var(--tjl-focus);
	outline-offset: 2px;
}

/**
 * The label is the tap target, not the 20px box. `inline-flex` also fixes the
 * zero-width label box the audit measured on "Remember me", which left the
 * words untappable.
 */
.woocommerce form .form-row label.woocommerce-form__label-for-checkbox,
.woocommerce label.woocommerce-form__label-for-checkbox,
.woocommerce-form-login__rememberme {
	display: inline-flex;
	align-items: center;
	gap: 2px;
	min-height: 44px;
	width: auto;
	margin: 0;
	padding: 4px 0;
	font-size: 15px;
	line-height: 1.4;
	color: var(--tjl-ink);
	cursor: pointer;
}

.woocommerce-form-login__rememberme span,
.woocommerce form .form-row label.woocommerce-form__label-for-checkbox span {
	font-size: 15px;
}

/* Respect a reduced-motion preference for every animation this layer adds. */
@media (prefers-reduced-motion: reduce) {
	.tjl-ux-gate-hint-flash,
	.tjl-ux-gate-flash {
		animation: none;
	}

	.single_add_to_cart_button.tjl-ux-gated,
	button.tjl-ux-gated {
		transition: none;
	}
}

/* ----------------------------------------------------- 3. checkout + cart */

/**
 * THE CLIPPING BUG.
 *
 * `form.checkout` ships as `display:inline-block`. An inline-block is a
 * shrink-to-fit box, so it grows to its content's max-content width — here the
 * order-review table's long product names and price strings push it to ~488px.
 * The viewport is 390px and `.tp-checkout-page-wrapper` sets
 * `overflow-x:hidden`, so the surplus is not scrolled, it is silently CUT OFF:
 * the Last name field, the right edge of every wide input and part of the
 * review column simply vanish off the right of the screen.
 *
 * A checkout form has no reason to be inline-block at any width.
 */
.woocommerce form.checkout,
.woocommerce-checkout form.checkout,
.tp-checkout-page-wrapper form.checkout {
	display: block;
	width: 100%;
	max-width: 100%;
}

.tp-checkout-page-wrapper .col2-set,
.tp-checkout-page-wrapper .col2-set .col-1,
.tp-checkout-page-wrapper .col2-set .col-2,
.woocommerce-checkout .col2-set,
.woocommerce-checkout .col2-set .col-1,
.woocommerce-checkout .col2-set .col-2 {
	width: 100%;
	max-width: 100%;
	float: none;
}

/* The review table is the element that sets the max-content width. */
.woocommerce-checkout .shop_table,
.woocommerce-cart .shop_table {
	width: 100%;
	max-width: 100%;
	table-layout: fixed;
}

.woocommerce-checkout .shop_table th,
.woocommerce-checkout .shop_table td {
	overflow-wrap: anywhere;
	word-break: break-word;
}

/* Select2 inherits the same over-width; keep it inside the column. */
.woocommerce-checkout .select2-container,
.woocommerce-checkout .select2-container .select2-selection {
	max-width: 100%;
}

.woocommerce-checkout .select2-container .select2-selection--single {
	min-height: 44px;
	display: flex;
	align-items: center;
}

/**
 * THE TWO NOTICE BARS.
 *
 * "Returning customer?" and "Have a coupon?" sit next to each other in two
 * unrelated visual languages: one grey with square corners, one a SOLID
 * magenta slab with white text and an 8px radius. Both carry a stray blue top
 * border that belongs to neither, and both run full-bleed to the viewport edge
 * while every other row on the page has a gutter.
 *
 * The solid magenta is the worst of it — on a checkout, a saturated full-width
 * block reads as an error or a warning, which is exactly the wrong signal at
 * the moment of payment. Both become the same quiet tinted bar with a magenta
 * rail, which is the same language as the product-page selection hint.
 */
.woocommerce-checkout .woocommerce-form-login-toggle .woocommerce-info,
.woocommerce-checkout .woocommerce-form-coupon-toggle .woocommerce-info {
	background: rgba(228, 9, 127, 0.05);
	color: var(--tjl-ink);
	border: 1px solid rgba(228, 9, 127, 0.18);
	border-left: 3px solid var(--tjl-magenta);
	border-radius: 8px;
	margin: 0 0 14px;
	padding: 14px 16px;
	font-size: 15px;
	line-height: 1.45;
}

.woocommerce-checkout .woocommerce-form-login-toggle .woocommerce-info a,
.woocommerce-checkout .woocommerce-form-coupon-toggle .woocommerce-info a {
	color: var(--tjl-magenta);
	font-weight: 600;
	text-decoration: underline;
	text-underline-offset: 2px;
}

/* The decorative square that reads as an unchecked checkbox. */
.woocommerce-checkout .woocommerce-form-login-toggle .woocommerce-info::before,
.woocommerce-checkout .woocommerce-form-coupon-toggle .woocommerce-info::before {
	display: none;
}

/**
 * Place Order is the page's terminal action and was 36px tall, 436px wide
 * (clipped), 3px radius, in a third pink (#ff00b6) that matches neither the
 * brand magenta nor the purple used by every other button.
 */
.woocommerce-checkout #place_order,
.woocommerce #place_order {
	display: block;
	width: 100%;
	max-width: 100%;
	min-height: 52px;
	margin: 4px 0 16px;
	padding: 14px 20px;
	background: var(--tjl-magenta);
	color: #fff;
	border: 0;
	border-radius: 999px;
	font-size: 16px;
	font-weight: 600;
	letter-spacing: 0.02em;
	cursor: pointer;
	transition: background-color 0.18s ease, transform 0.12s ease;
}

.woocommerce-checkout #place_order:hover {
	background: #c6076d;
}

.woocommerce-checkout #place_order:active {
	transform: translateY(1px);
}

/* The floating contact dock must not sit on top of the final CTA. */
.woocommerce-checkout .woocommerce-checkout-payment,
.woocommerce-cart .wc-proceed-to-checkout {
	padding-bottom: 8px;
}

@media (max-width: 767px) {
	.woocommerce-checkout .woocommerce,
	.woocommerce-cart .woocommerce {
		padding-bottom: 96px;
	}
}

/* --------------------------------------------------------------- 4. cart */

/**
 * Quantity steppers were 30x46 and "Remove item" 65x24 — both under the 44px
 * floor, and the remove control sat within 8px of the quantity field.
 */
.woocommerce-cart .quantity .qty,
.woocommerce-cart .quantity input[type="number"] {
	min-height: 44px;
}

.woocommerce-cart .quantity .plus,
.woocommerce-cart .quantity .minus,
.woocommerce-cart .quantity button {
	min-width: 44px;
	min-height: 44px;
}

.woocommerce-cart td.product-remove a.remove,
.woocommerce-cart a.remove {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	font-size: 20px;
	line-height: 1;
}

/**
 * The side-cart drawer parks itself off the right edge. Keep it from adding to
 * the document's scroll width while it is closed.
 */
.xoo-wsc-modal:not(.xoo-wsc-active) {
	max-width: 100vw;
}

.xoo-wsc-modal .xoo-wsc-header,
.xoo-wsc-modal .xoo-wsc-container {
	max-width: 100%;
}

/* ------------------------------------- 3b. cascade overrides (specificity) */

/**
 * Three rules above lost the cascade and had to be re-stated at a weight that
 * actually wins. Elementor's per-post CSS loads LAST, so a tie loses — the
 * override must be strictly more specific, not merely later.
 *
 * Specificity is raised by REPEATING A CLASS rather than by hardcoding
 * `.elementor-2576 .elementor-element-bc2c91c`. Repetition survives a page
 * rebuild or a new element id; the hardcoded pair does not. No `!important`:
 * that would also beat the editor, so a future change in the Elementor UI
 * would appear to do nothing.
 */

/* Beaten by `.tp-checkout-page-wrapper .checkout.woocommerce-checkout` (0,3,0). */
.tp-checkout-page-wrapper .checkout.woocommerce-checkout.woocommerce-checkout {
	display: block;
	width: 100%;
	max-width: 100%;
}

/**
 * The coupon bar's solid magenta comes from the widget's own `co_ac_bg_color`,
 * bound to Elementor global colour `2f167f7`. Measured, its selector is
 * `.elementor-2576 .elementor-element.elementor-element-bc2c91c
 * .tp-checkout-page-wrapper .woocommerce-form-coupon-toggle .woocommerce-info`
 * = (0,6,0). Four repetitions tied it at (0,6,0) and LOST, because Elementor's
 * post CSS is enqueued after ours. Five wins at (0,7,0).
 * Left alone it is a saturated full-width slab at the moment of payment, which
 * reads as an error.
 */
.tp-checkout-page-wrapper .woocommerce-form-coupon-toggle
	.woocommerce-info.woocommerce-info.woocommerce-info.woocommerce-info.woocommerce-info {
	background: rgba(228, 9, 127, 0.05);
	background-color: rgba(228, 9, 127, 0.05);
	color: var(--tjl-ink);
	border: 1px solid rgba(228, 9, 127, 0.18);
	border-left: 3px solid var(--tjl-magenta);
	border-radius: 8px;
}

.tp-checkout-page-wrapper .woocommerce-form-coupon-toggle
	.woocommerce-info.woocommerce-info.woocommerce-info.woocommerce-info.woocommerce-info a,
.tp-checkout-page-wrapper .woocommerce-form-coupon-toggle
	.woocommerce-info.woocommerce-info.woocommerce-info.woocommerce-info.woocommerce-info .showcoupon {
	color: var(--tjl-magenta);
}

/**
 * Place Order was painted #ff00b6 by a theme rule whose selector list also
 * carries pagination states. An id repeated outranks any class-based rule.
 */
.woocommerce-checkout #place_order#place_order,
.woocommerce #place_order#place_order {
	background: var(--tjl-magenta);
	background-color: var(--tjl-magenta);
	color: #fff;
	border-radius: 999px;
	min-height: 52px;
}

.woocommerce-checkout #place_order#place_order:hover {
	background-color: #c6076d;
}

/* --------------------------------------------- 3c. checkout page rhythm */

/**
 * Both notice bars ran full-bleed (x=0, w=390) while every form row below
 * them sits in a ~24px gutter, so the page had two different left edges.
 * Align them to the form.
 */
@media (max-width: 767px) {
	.woocommerce-checkout .woocommerce-form-login-toggle,
	.woocommerce-checkout .woocommerce-form-coupon-toggle {
		margin-left: 14px;
		margin-right: 14px;
	}

	/* The band between the hero wave and the first bar was ~65px of nothing. */
	.woocommerce-checkout .tp-checkout-page-wrapper,
	.woocommerce-cart .tp-cart-page-wrapper {
		padding-top: 18px;
	}

	.woocommerce-checkout h3,
	.woocommerce-checkout .woocommerce-billing-fields h3 {
		margin-top: 18px;
		margin-bottom: 10px;
		font-size: 26px;
		line-height: 1.2;
	}
}

/**
 * The floating WhatsApp/call dock is `position:fixed` bottom-left, so on a
 * long form it parks on top of whatever input happens to be at that height —
 * measured sitting over "Company name" — and the left edge of that field
 * cannot be tapped.
 *
 * It is hidden on CHECKOUT ONLY. Checkout is the payment funnel: a floating
 * distraction that also blocks a form control is a net loss there. It still
 * prints on every other page, cart included, so the client's "call button on
 * all pages" still holds everywhere a customer is browsing rather than paying.
 * Reverse by deleting this block.
 */
.woocommerce-checkout .tjl-pp-dock,
.woocommerce-checkout [class*="tjl-pp-dock"] {
	display: none;
}

/* ------------------------------------- 2b. checkbox sizing inside a flex label */

/**
 * `flex: 0 0 20px` was not enough. WooCommerce wraps the consent checkbox in
 * an `inline-flex` label, and a flex item defaults to `min-width: auto`, which
 * resolves to the control's content-based minimum — measured 44x24 — and that
 * floor overrides the 20px flex-basis. The box rendered as a wide empty
 * rectangle rather than a checkbox.
 *
 * Explicit min/max on both axes is what actually pins it.
 */
.woocommerce form .form-row input[type="checkbox"],
.woocommerce-form__input-checkbox,
.woocommerce input[type="checkbox"],
.woocommerce input[type="radio"],
.woocommerce-checkout #terms {
	flex: 0 0 20px;
	min-width: 20px;
	max-width: 20px;
	min-height: 20px;
	max-height: 20px;
	align-self: center;
	box-sizing: border-box;
}

/* ------------------------------------- 2c. the padding that floored the box */

/**
 * The real reason the consent boxes rendered as wide empty rectangles:
 * Elementor's global kit applies
 *
 *   .elementor-kit-27 input:not([type="button"]):not([type="submit"])
 *     { padding: 10px 20px }
 *
 * to EVERY input, checkboxes included. With `box-sizing: border-box` a box can
 * never be smaller than its own padding plus border, so 20+20 padding + 2+2
 * border floors the width at 44px and the height at 24px — `width`, `max-width`
 * and `flex-basis` are all powerless against it. Measured exactly 44x24.
 *
 * Specificity: the kit rule is (0,3,1). The attribute selector is repeated to
 * reach (0,4,1) rather than naming `.elementor-kit-27`, whose id changes if the
 * kit is ever regenerated.
 */
input[type="checkbox"][type="checkbox"][type="checkbox"][type="checkbox"],
input[type="radio"][type="radio"][type="radio"][type="radio"] {
	padding: 0;
	width: 20px;
	height: 20px;
	min-width: 20px;
	max-width: 20px;
	min-height: 20px;
	max-height: 20px;
	box-sizing: border-box;
}

/**
 * The checked fill lost the same fight: the kit's input `background-color`
 * rule ties with `.woocommerce input[type="checkbox"]:checked` at (0,3,1) and
 * wins on source order. Restate the checked state at (0,5,1), and redraw the
 * tick here so the box and its mark can never come from different rules.
 */
input[type="checkbox"][type="checkbox"][type="checkbox"][type="checkbox"]:checked,
input[type="radio"][type="radio"][type="radio"][type="radio"]:checked {
	background: var(--tjl-magenta);
	background-color: var(--tjl-magenta);
	border-color: var(--tjl-magenta);
}

input[type="checkbox"][type="checkbox"][type="checkbox"][type="checkbox"]:checked::after {
	content: "";
	position: absolute;
	left: 5px;
	top: 1px;
	width: 5px;
	height: 10px;
	border: solid #fff;
	border-width: 0 2.5px 2.5px 0;
	transform: rotate(45deg);
}

input[type="radio"][type="radio"][type="radio"][type="radio"]:checked::after {
	content: "";
	position: absolute;
	inset: 3px;
	border-radius: 50%;
	background: #fff;
}

/* Corner radius and resting border lost the same (0,3,1) tie — restate them. */
input[type="checkbox"][type="checkbox"][type="checkbox"][type="checkbox"] {
	border: 2px solid var(--tjl-line);
	border-radius: 5px;
	background-color: #fff;
	appearance: none;
	-webkit-appearance: none;
	position: relative;
	cursor: pointer;
}

input[type="radio"][type="radio"][type="radio"][type="radio"] {
	border: 2px solid var(--tjl-line);
	border-radius: 50%;
	background-color: #fff;
	appearance: none;
	-webkit-appearance: none;
	position: relative;
	cursor: pointer;
}

/* ------------------------------------------------- 5. entrance animations */

/**
 * The hiding rule is scoped to `html.tjl-ux-anim`, and ONLY assets/reveal.js
 * adds that class — after it has confirmed IntersectionObserver exists and
 * reduced motion is not requested. If the script never runs, nothing is ever
 * hidden. A stylesheet that hides content and trusts JS to reveal it is how a
 * page ships blank.
 */
html.tjl-ux-anim [data-tjl-anim] {
	opacity: 0;
	transform: translate3d(0, 28px, 0);
	will-change: opacity, transform;
}

html.tjl-ux-anim [data-tjl-anim].tjl-ux-in {
	opacity: 1;
	transform: none;
	transition:
		opacity 0.55s cubic-bezier(0.22, 0.61, 0.36, 1),
		transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Already on screen at load: present, not performed. */
html.tjl-ux-anim [data-tjl-anim].tjl-ux-instant {
	transition: none;
}

/* Once revealed, stop promoting the layer. */
html.tjl-ux-anim [data-tjl-anim].tjl-ux-in {
	will-change: auto;
}

@media (max-width: 767px) {
	/* Shorter travel and a quicker curve: on a phone a long rise reads as lag. */
	html.tjl-ux-anim [data-tjl-anim] {
		transform: translate3d(0, 18px, 0);
	}

	html.tjl-ux-anim [data-tjl-anim].tjl-ux-in {
		transition:
			opacity 0.4s cubic-bezier(0.22, 0.61, 0.36, 1),
			transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
	}
}

/**
 * Belt and braces. reveal.js already returns early under reduced motion, but
 * if the preference is toggled after load the class may already be on <html>.
 */
@media (prefers-reduced-motion: reduce) {
	html.tjl-ux-anim [data-tjl-anim] {
		opacity: 1;
		transform: none;
		transition: none;
	}
}
