/* ============================================================================
   NABUX — FX LAYER  (motion · micro-interactions · skeletons · icons)
   ----------------------------------------------------------------------------
   Loads LAST (after nabux-glue.css) so it never has to fight the cascade with
   !important. Everything here animates only compositor-friendly properties
   (transform / opacity / box-shadow / filter) so the site stays at 60-120fps.

   HARD RULE FOR FUTURE EDITS: never set `color` on a bare `button` selector in
   this file. nabux-glue.css carries `button{color:var(--text)!important}` as the
   root fix for style.css's over-broad brand-CTA rule. Overriding it here would
   re-introduce the black-on-black regression. Style chrome by class only.
   ========================================================================== */

/* ---------------------------------------------------------------- 1. TOKENS */
:root{
	/* Duration scale — M3 / Apple HIG. Micro 150-300ms, structural 400-600ms. */
	--nx-d-xs:120ms;
	--nx-d-sm:180ms;
	--nx-d-md:240ms;
	--nx-d-lg:320ms;
	--nx-d-xl:460ms;
	--nx-d-2xl:600ms;

	/* Standard easings */
	--nx-e-standard:cubic-bezier(.4,0,.2,1);      /* M3 standard — most transitions */
	--nx-e-decel:cubic-bezier(0,0,.2,1);          /* entering  */
	--nx-e-accel:cubic-bezier(.4,0,1,1);          /* exiting   */
	--nx-e-emph:cubic-bezier(.2,0,0,1);           /* M3 emphasized */
	--nx-e-snap:cubic-bezier(.34,1.56,.64,1);     /* snappy overshoot */

	/* Physics easings. linear() is Baseline widely available (2023-12-11).
	   Every use declares a cubic-bezier first so old engines still animate. */
	--nx-e-spring:linear(0,.009 .8%,.035 1.7%,.148 3.7%,.734 9.4%,.938 11.7%,1.079 14.1%,1.129 15.5%,1.157 17%,1.16 18.6%,1.14 20.4%,1.098 22.4%,.999 26.5%,.96 28.6%,.938 30.7%,.933 33%,.947 35.9%,.998 41.6%,1.018 44.5%,1.026 47.7%,1.018 52.3%,.995 60.2%,.999 70.8%,1.004 80%,1);
	--nx-e-bounce:linear(0,.214 14.7%,.386 23.7%,.598 31.9%,.999 44.7%,.807 52.6%,.762 56%,.747 59.4%,.758 62.4%,.793 65.6%,.999 77.4%,.961 81.2%,.949 84.8%,.956 88%,.993 95.5%,1);

	/* Layered elevation — two shadows read as real depth, one reads as a blur. */
	--nx-lift-1:0 1px 2px rgba(0,0,0,.30), 0 4px 12px rgba(0,0,0,.22);
	--nx-lift-2:0 2px 4px rgba(0,0,0,.34), 0 12px 30px rgba(0,0,0,.30);
	--nx-lift-3:0 4px 8px rgba(0,0,0,.36), 0 22px 50px rgba(0,0,0,.38);

	/* Brand glow — the "خفن" signature. Ring + bloom, both in brand hue. */
	--nx-glow-brand:0 0 0 1px rgba(183,255,60,.40), 0 6px 18px rgba(183,255,60,.20), 0 14px 40px rgba(183,255,60,.10);
	--nx-glow-cyan:0 0 0 1px rgba(0,212,255,.40), 0 6px 18px rgba(0,212,255,.18), 0 14px 40px rgba(0,212,255,.10);

	/* Skeleton surface + sweep */
	--nx-skel-base:rgba(255,255,255,.055);
	--nx-skel-edge:rgba(255,255,255,.085);
	--nx-skel-sweep:linear-gradient(100deg,transparent 18%,rgba(255,255,255,.11) 42%,rgba(183,255,60,.085) 52%,rgba(255,255,255,.07) 62%,transparent 84%);
	--nx-skel-speed:1.45s;
}
html[data-theme="light"]{
	--nx-lift-1:0 1px 2px rgba(13,21,38,.08), 0 4px 12px rgba(13,21,38,.07);
	--nx-lift-2:0 2px 4px rgba(13,21,38,.10), 0 12px 30px rgba(13,21,38,.10);
	--nx-lift-3:0 4px 8px rgba(13,21,38,.12), 0 22px 50px rgba(13,21,38,.14);
	--nx-skel-base:rgba(13,21,38,.07);
	--nx-skel-edge:rgba(13,21,38,.11);
	--nx-skel-sweep:linear-gradient(100deg,transparent 18%,rgba(13,21,38,.07) 42%,rgba(60,138,0,.09) 52%,rgba(13,21,38,.05) 62%,transparent 84%);
}

/* ------------------------------------------------- 2. GLOBAL INTERACTION BASE */

/* Kill the grey flash on tap; we provide our own press feedback. */
a,button,[role="button"],.productCard,.vendorCard,summary,label{-webkit-tap-highlight-color:transparent}

/* One precise, always-visible focus ring. Keyboard only — never on mouse press. */
:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{
	outline:2px solid var(--brand,#b7ff3c);
	outline-offset:3px;
	border-radius:inherit;
}
/* High-contrast fallback for elements that sit on brand-filled surfaces. */
.primaryButton:focus-visible,.buyPill:focus-visible,.searchBox button:focus-visible,
.single_add_to_cart_button:focus-visible,.wc-block-components-button.contained:focus-visible{
	outline-color:var(--on-brand,#07100a);
	box-shadow:0 0 0 5px rgba(183,255,60,.45);
}

/* ------------------------------------------------------------- 3. ICON SYSTEM */
.nxi{
	width:1em;height:1em;flex:none;
	display:inline-block;vertical-align:-.125em;
	fill:none;stroke:currentColor;
	stroke-width:2;stroke-linecap:round;stroke-linejoin:round;
	overflow:visible;
	pointer-events:none;
}
.nxi-sm{width:.875em;height:.875em}
.nxi-lg{width:1.25em;height:1.25em}
.nxi-xl{width:1.5em;height:1.5em}
.nxi-fill{fill:currentColor;stroke:none}
/* Brand-tinted icon (delivery bolt, escrow shield, rating star …) */
.nxi-brand{color:var(--brand,#b7ff3c)}
.nxi-cyan{color:var(--brand-2,#00d4ff)}
/* Icons inside a text run get optical spacing without touching line-height. */
.delivery .nxi,.sellerRow .nxi,.utilItem .nxi,.vendorRow .nxi,.nxChip .nxi{margin-inline-end:.45em}
/* Mirror directional icons in RTL; symmetric ones must NOT flip. */
[dir="rtl"] .nxi-flip{transform:scaleX(-1)}
/* The sprite host itself is never visible or focusable. */
#nx-icon-sprite{position:absolute;width:0;height:0;overflow:hidden;visibility:hidden}

/* Small labelled chip used for warranty / delivery / stock facts. */
.nxChip{
	display:inline-flex;align-items:center;
	padding:7px 12px;border-radius:999px;
	background:rgba(255,255,255,.055);border:1px solid var(--line);
	font-size:12.5px;font-weight:750;letter-spacing:-.01em;
	line-height:1.2;
}
.nxChip--brand{background:rgba(183,255,60,.10);border-color:rgba(183,255,60,.28);color:var(--brand,#b7ff3c)}
.nxChip--cyan{background:rgba(0,212,255,.10);border-color:rgba(0,212,255,.28);color:var(--brand-2,#00d4ff)}

/* ============================================================================
   4. BUTTONS — hover lift · brand bloom · spring press · icon nudge · shine
   All motion is transform/opacity/box-shadow only. `color` is NEVER declared
   here (see the hard rule at the top of this file).
   ========================================================================== */

/* Shared geometry so icon + label align optically on every button variant. */
.primaryButton,.ghostButton,.buyPill,.button,.wp-element-button,.wp-block-button__link,
.wc-block-components-button,.single_add_to_cart_button,.searchBox button,
.comment-form .form-submit .submit,.nx-langdd__btn,.themeToggle{
	position:relative;
	isolation:isolate;
	display:inline-flex;align-items:center;justify-content:center;gap:.55em;
	transform:translateZ(0);            /* own compositor layer, no repaint jank */
	transition:
		transform var(--nx-d-md) var(--nx-e-standard),
		box-shadow var(--nx-d-md) var(--nx-e-standard),
		filter    var(--nx-d-sm) var(--nx-e-standard),
		border-color var(--nx-d-sm) var(--nx-e-standard),
		background-color var(--nx-d-sm) var(--nx-e-standard);
}

@media (prefers-reduced-motion:no-preference){

	/* ---- Brand CTAs: rise, bloom, and brighten ---- */
	.primaryButton:hover,.buyPill:hover,.button:hover,.wp-element-button:hover,
	.wp-block-button__link:hover,.wc-block-components-button.contained:hover,
	.single_add_to_cart_button:hover,.searchBox button:hover,
	.comment-form .form-submit .submit:hover,
	.productCard:hover .buyPill{
		transform:translateY(-2px) scale(1.022);
		box-shadow:var(--nx-glow-brand);
		filter:brightness(1.07) saturate(1.05);
	}

	/* ---- Ghost / chrome: rise + brand-tinted edge, no bloom ---- */
	.ghostButton:hover,.nx-langdd__btn:hover,.themeToggle:hover,
	.wc-block-components-button:not(.contained):hover,.sellerTabs button:hover{
		transform:translateY(-2px);
		box-shadow:var(--nx-lift-2);
		border-color:var(--brand-border,rgba(183,255,60,.4));
	}

	/* ---- Press: a real spring, snapping back past rest ---- */
	.primaryButton:active,.ghostButton:active,.buyPill:active,.button:active,
	.wp-element-button:active,.wp-block-button__link:active,
	.wc-block-components-button:active,.single_add_to_cart_button:active,
	.searchBox button:active,.comment-form .form-submit .submit:active,
	.nx-langdd__btn:active,.themeToggle:active{
		transform:scale(.965);
		transition-duration:var(--nx-d-xs);
		transition-timing-function:var(--nx-e-standard);
	}
	/* Release animates back on the spring curve, not the press curve. */
	.primaryButton,.ghostButton,.buyPill,.button,.wp-element-button,
	.wp-block-button__link,.wc-block-components-button,.single_add_to_cart_button,
	.searchBox button,.comment-form .form-submit .submit{
		transition-timing-function:var(--nx-e-standard);      /* fallback first */
		transition-timing-function:var(--nx-e-spring);        /* modern engines */
		transition-duration:var(--nx-d-xl);
	}

	/* ---- Trailing icon nudges forward on hover (direction-aware) ---- */
	.primaryButton .nxi-go,.ghostButton .nxi-go,.buyPill .nxi-go,.button .nxi-go,
	.nxLink .nxi-go{
		transition:translate var(--nx-d-md) var(--nx-e-snap);
	}
	.primaryButton:hover .nxi-go,.ghostButton:hover .nxi-go,.button:hover .nxi-go,
	.productCard:hover .buyPill .nxi-go,.nxLink:hover .nxi-go{translate:3px 0}
	[dir="rtl"] .primaryButton:hover .nxi-go,[dir="rtl"] .ghostButton:hover .nxi-go,
	[dir="rtl"] .button:hover .nxi-go,[dir="rtl"] .productCard:hover .buyPill .nxi-go,
	[dir="rtl"] .nxLink:hover .nxi-go{translate:-3px 0}

	/* ---- Specular shine sweeping across brand CTAs on hover ---- */
	.primaryButton::after,.buyPill::after,.single_add_to_cart_button::after,
	.wc-block-components-button.contained::after{
		content:"";position:absolute;inset:0;z-index:-1;
		border-radius:inherit;pointer-events:none;
		background:linear-gradient(105deg,transparent 30%,rgba(255,255,255,.55) 48%,transparent 66%);
		translate:-130% 0;opacity:0;
	}
	.primaryButton:hover::after,.buyPill:hover::after,
	.single_add_to_cart_button:hover::after,
	.wc-block-components-button.contained:hover::after,
	.productCard:hover .buyPill::after{
		translate:130% 0;opacity:1;
		transition:translate var(--nx-d-2xl) var(--nx-e-decel),opacity var(--nx-d-sm) linear;
	}

	/* ---- Cart pill: the count badge pops when it changes ---- */
	.cartCount{transition:transform var(--nx-d-md) var(--nx-e-snap)}
	.ghostButton:hover .cartCount{transform:scale(1.14)}
	.cartCount.nx-bump{animation:nxBump .45s var(--nx-e-bounce)}
	@keyframes nxBump{0%{transform:scale(1)}38%{transform:scale(1.42)}100%{transform:scale(1)}}
}

/* Disabled + busy states must read as non-interactive, never as invisible. */
.primaryButton[disabled],.button[disabled],.wc-block-components-button[disabled],
.single_add_to_cart_button[disabled],.ghostButton[aria-disabled="true"]{
	opacity:.52;filter:saturate(.6);transform:none!important;
	box-shadow:none!important;cursor:not-allowed;
}
/* In-flight CTA: label holds its place, a spinner rides alongside it. */
.nx-busy{pointer-events:none;position:relative}
.nx-busy>*{opacity:.35}
.nx-busy::before{
	content:"";position:absolute;inset:0;margin:auto;
	width:1.15em;height:1.15em;border-radius:999px;
	border:2px solid currentColor;border-top-color:transparent;
	animation:nxSpinFx .7s linear infinite;
}
@keyframes nxSpinFx{to{transform:rotate(1turn)}}

/* ---- 4b. Per-component bloom tint ----
   Not every CTA is brand-filled. .buyPill is white-on-dark and .ghostButton is
   translucent, so a lime bloom around them reads as a colour mismatch rather
   than a glow. Each gets a bloom in its own hue. */
@media (prefers-reduced-motion:no-preference){
	.buyPill:hover,.productCard:hover .buyPill{
		box-shadow:
			0 0 0 1px rgba(255,255,255,.55),
			0 6px 18px rgba(255,255,255,.18),
			0 14px 40px rgba(183,255,60,.10);
	}
	html[data-theme="light"] .buyPill:hover,
	html[data-theme="light"] .productCard:hover .buyPill{
		box-shadow:0 0 0 1px rgba(13,21,38,.45),0 6px 18px rgba(13,21,38,.18);
	}
	/* The white pill's shine must be dark, or it is invisible against itself. */
	.buyPill::after{
		background:linear-gradient(105deg,transparent 30%,rgba(7,16,10,.30) 48%,transparent 66%);
	}
}

/* ============================================================================
   5. CARDS — lift · brand edge · art zoom · sheen
   ========================================================================== */
.productCard,.vendorCard,.wc-block-grid__product,.nxPanel{
	transform:translateZ(0);
	transition:
		transform var(--nx-d-lg) var(--nx-e-standard),
		box-shadow var(--nx-d-lg) var(--nx-e-standard),
		border-color var(--nx-d-lg) var(--nx-e-standard);
}
@media (prefers-reduced-motion:no-preference){
	.productCard:hover,.vendorCard:hover,.wc-block-grid__product:hover{
		transform:translateY(-6px);
		box-shadow:var(--nx-lift-3),0 0 0 1px rgba(183,255,60,.22);
		border-color:var(--brand-border,rgba(183,255,60,.4));
	}
	.productCard:active,.vendorCard:active{transform:translateY(-2px) scale(.994);transition-duration:var(--nx-d-xs)}

	/* Art tile: the image zooms inside a clipped frame — the frame never moves. */
	.productCard .cardArt,.wc-block-grid__product .wc-block-grid__product-image{overflow:hidden}
	.productCard .cardArt img,.productCard .cardArt .artChip,
	.productCard .cardArt .artLogo,.productCard .cardArt .artMono,
	.wc-block-grid__product img{
		transition:transform var(--nx-d-2xl) var(--nx-e-emph);
	}
	.productCard:hover .cardArt img,.productCard:hover .cardArt .artChip,
	.productCard:hover .cardArt .artLogo,.productCard:hover .cardArt .artMono,
	.wc-block-grid__product:hover img{transform:scale(1.07)}

	/* A slow diagonal sheen crosses the art on hover — reads as glass. */
	.productCard .cardArt::after{
		content:"";position:absolute;inset:0;pointer-events:none;
		background:linear-gradient(115deg,transparent 38%,rgba(255,255,255,.14) 50%,transparent 62%);
		translate:-120% 0;opacity:0;
	}
	.productCard:hover .cardArt::after{
		translate:120% 0;opacity:1;
		transition:translate 900ms var(--nx-e-decel),opacity 160ms linear;
	}

	/* Discount / featured badges settle in with a small pop. */
	.artDiscount,.artBadge{transition:transform var(--nx-d-md) var(--nx-e-snap)}
	.productCard:hover .artDiscount,.productCard:hover .artBadge{transform:scale(1.08) rotate(-2deg)}
}
.productCard .cardArt{position:relative}

/* ============================================================================
   6. SKELETONS — shimmer primitives
   ----------------------------------------------------------------------------
   STRUCTURAL PRINCIPLE: a skeleton never re-declares layout. It reuses the very
   same classes as the finished component (.productCard, .cardArt, .categoryLabel,
   h3, .productDescription, .cardFooter …) and only paints bars *inside* those
   boxes. Geometry, aspect ratio, border-radius and rhythm are therefore
   identical by construction, not by transcription — so the swap to real content
   costs exactly 0 layout shift (CLS 0) and can never drift when the card is
   restyled later.
   ========================================================================== */

.nxSkel{
	position:relative;
	display:block;
	overflow:hidden;
	background:var(--nx-skel-base);
	border-radius:8px;
	/* The bar itself must never inherit text colour or be read aloud. */
	color:transparent;
	user-select:none;
}
.nxSkel::after{
	content:"";
	position:absolute;inset:0;
	translate:-100% 0;
	background:var(--nx-skel-sweep);
	will-change:transform;              /* the one legitimate use: infinite loop */
}
@media (prefers-reduced-motion:no-preference){
	.nxSkel::after{animation:nxShimmer var(--nx-skel-speed) var(--nx-e-standard) infinite}
}
/* Reduced motion keeps the skeleton, drops the movement — a static, slightly
   brighter block still communicates "loading" without vestibular risk. */
@media (prefers-reduced-motion:reduce){
	.nxSkel{background:var(--nx-skel-edge)}
	.nxSkel::after{display:none}
}
@keyframes nxShimmer{
	0%  {translate:-100% 0}
	60% {translate:100% 0}
	100%{translate:100% 0}
}

/* Bars stagger their sweep so a card reads as one wave, not N loops in lockstep. */
.nxSkel:nth-of-type(2)::after{animation-delay:.08s}
.nxSkel:nth-of-type(3)::after{animation-delay:.16s}
.nxSkel:nth-of-type(4)::after{animation-delay:.24s}
.nxSkel:nth-of-type(5)::after{animation-delay:.32s}

/* Shapes */
.nxSkel--fill{position:absolute;inset:0;border-radius:inherit}
.nxSkel--text{height:.72em;margin:.26em 0;border-radius:6px}
.nxSkel--text+.nxSkel--text{margin-top:.4em}
.nxSkel--pill{border-radius:999px}
.nxSkel--circle{border-radius:999px;aspect-ratio:1}
.nxSkel--w90{width:90%}.nxSkel--w80{width:80%}.nxSkel--w70{width:70%}
.nxSkel--w60{width:60%}.nxSkel--w50{width:50%}.nxSkel--w40{width:40%}.nxSkel--w30{width:30%}

/* A skeleton is decorative: no hover, no pointer, no focus, no announcement. */
.nxSkelCard,.nxSkelRow,.nxSkelPanel{pointer-events:none;user-select:none}
.nxSkelCard:hover,.nxSkelRow:hover,.nxSkelPanel:hover{
	transform:none!important;box-shadow:none!important;border-color:var(--line)!important;
}
.nxSkelCard .cardArt{background:var(--nx-skel-base)!important;box-shadow:none}
.nxSkelCard .cardArt::after{display:none}
.nxSkelCard .cardFooter{border-top:1px solid var(--line)}

/* The whole skeleton region announces itself once, politely, then goes quiet. */
.nxSkelHost{position:relative}
.nxSkelHost[aria-busy="true"]{cursor:progress}

/* Cross-fade: skeleton out, content in — no flash of empty box between them. */
@media (prefers-reduced-motion:no-preference){
	.nxSkelHost>.nxSkelLayer{animation:nxSkelIn var(--nx-d-md) var(--nx-e-decel) both}
	.nxSkelHost>.nxSkelLayer.is-out{animation:nxSkelOut var(--nx-d-lg) var(--nx-e-accel) forwards}
	@keyframes nxSkelIn {from{opacity:0}to{opacity:1}}
	@keyframes nxSkelOut{to{opacity:0;transform:translateY(-4px)}}
}

/* ---- Grid of skeleton cards reuses the real grid, so columns match exactly -- */
.nxSkelGrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;margin:6px 0 26px}
@media (max-width:1000px){.nxSkelGrid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:640px){.nxSkelGrid{grid-template-columns:1fr;gap:16px}}

/* ---- Row skeleton: order lines, transactions, withdrawals, account tables --- */
.nxSkelRow{
	display:grid;grid-template-columns:44px 1fr auto;align-items:center;gap:14px;
	background:rgba(7,10,18,.4);border:1px solid var(--line);border-radius:14px;
	padding:12px 14px;margin-bottom:10px;
}
.nxSkelRow .nxSkelRow__icon{width:36px;height:36px;border-radius:10px}
.nxSkelRow .nxSkelRow__amt{width:84px;height:16px}

/* ---- Panel skeleton: seller dashboard stat tiles + chart block -------------- */
.nxSkelStats{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin-bottom:18px}
@media (max-width:860px){.nxSkelStats{grid-template-columns:repeat(2,minmax(0,1fr))}}
.nxSkelStat{
	background:var(--surface-1,rgba(255,255,255,.04));border:1px solid var(--line);
	border-radius:18px;padding:16px;
}
.nxSkelStat .nxSkel--text:first-child{height:11px;width:52%}
.nxSkelStat .nxSkel--text:last-child{height:26px;width:72%;margin-top:.7em}

/* ---- Cart / Checkout skeleton mirrors the Blocks two-column sidebar layout -- */
.nxSkelCommerce{display:grid;grid-template-columns:minmax(0,1fr) 380px;gap:36px;align-items:start}
@media (max-width:1000px){.nxSkelCommerce{grid-template-columns:1fr;gap:24px}}
.nxSkelLine{
	display:grid;grid-template-columns:76px 1fr 90px;gap:16px;align-items:center;
	padding:18px 0;border-bottom:1px solid var(--line);
}
.nxSkelLine__art{width:76px;height:76px;border-radius:16px}
.nxSkelSummary{
	background:var(--surface-1,rgba(255,255,255,.04));border:1px solid var(--line);
	border-radius:22px;padding:22px;
}
.nxSkelSummary__row{display:flex;justify-content:space-between;gap:20px;margin:14px 0}
.nxSkelSummary__row .nxSkel{height:13px}
.nxSkelSummary__row .nxSkel:first-child{width:38%}
.nxSkelSummary__row .nxSkel:last-child{width:22%}
.nxSkelSummary__cta{height:52px;border-radius:14px;margin-top:20px}

/* ============================================================================
   7. IMAGES — shimmer underneath, fade + settle on decode
   ========================================================================== */
.nx-img{position:relative;overflow:hidden;background:var(--nx-skel-base)}
.nx-img::after{
	content:"";position:absolute;inset:0;pointer-events:none;
	background:var(--nx-skel-sweep);translate:-100% 0;
}
@media (prefers-reduced-motion:no-preference){
	.nx-img::after{animation:nxShimmer var(--nx-skel-speed) var(--nx-e-standard) infinite}
}
.nx-img.is-loaded::after{animation:none;opacity:0;transition:opacity var(--nx-d-sm) linear}
.nx-img.is-loaded{background:none}
/* The image itself lifts into place rather than snapping on. */
.nx-img img{opacity:0}
.nx-img.is-loaded img{opacity:1}
@media (prefers-reduced-motion:no-preference){
	.nx-img img{transform:scale(1.04);transition:opacity var(--nx-d-lg) var(--nx-e-decel),transform var(--nx-d-2xl) var(--nx-e-emph)}
	.nx-img.is-loaded img{transform:scale(1)}
}
/* Belt and braces: if JS never runs, images must still be visible. */
html:not(.nx-js) .nx-img img{opacity:1;transform:none}
html:not(.nx-js) .nx-img::after{display:none}
html:not(.nx-js) .nx-img{background:none}

/* ============================================================================
   8. ENTRY CHOREOGRAPHY — staggered fade-in-up on reveal
   ----------------------------------------------------------------------------
   Index-driven delay: JS sets --nx-i on each item, CSS multiplies it. One rule
   covers a grid of any length, and the cap keeps the last card from arriving
   late enough to feel broken.
   ========================================================================== */
@media (prefers-reduced-motion:no-preference){
	.nx-reveal{
		opacity:0;
		translate:0 22px;
		scale:.985;
		transition:
			opacity var(--nx-d-2xl) var(--nx-e-decel),
			translate var(--nx-d-2xl) var(--nx-e-emph),
			scale var(--nx-d-2xl) var(--nx-e-emph);
		transition-delay:calc(var(--nx-i,0) * 55ms);
	}
	.nx-reveal.is-in{opacity:1;translate:0 0;scale:1}

	/* Elements that appear in the DOM after load (toasts, injected skeletons,
	   async notices) animate from a defined start rather than popping in. */
	.nx-enter{
		transition:opacity var(--nx-d-lg) var(--nx-e-decel),translate var(--nx-d-lg) var(--nx-e-emph);
	}
	@supports (transition-behavior:allow-discrete){
		@starting-style{
			.nx-enter{opacity:0;translate:0 10px}
		}
	}

	/* Section headings lead their content by a beat. */
	.sectionHeader.nx-reveal{transition-delay:0ms}
}
/* No JS, no reveal — content is never hidden behind a class that never lands. */
html:not(.nx-js) .nx-reveal{opacity:1;translate:none;scale:none}

/* ============================================================================
   9. HEADER · NAV · SWITCHER — chrome micro-interactions
   ========================================================================== */
.topbar{transition:box-shadow var(--nx-d-lg) var(--nx-e-standard),background-color var(--nx-d-lg) var(--nx-e-standard),backdrop-filter var(--nx-d-lg) linear}
.topbar.is-scrolled{box-shadow:0 12px 34px rgba(0,0,0,.34)}

/* Nav links grow a brand underline from the centre out. */
.topbar nav a{position:relative;transition:color var(--nx-d-sm) var(--nx-e-standard)}
.topbar nav a::after{
	content:"";position:absolute;left:0;right:0;bottom:-6px;height:2px;
	border-radius:2px;background:var(--grad-brand,linear-gradient(135deg,#b7ff3c,#00d4ff));
	transform:scaleX(0);transform-origin:center;
}
@media (prefers-reduced-motion:no-preference){
	.topbar nav a::after{transition:transform var(--nx-d-md) var(--nx-e-emph)}
	.topbar nav a:hover::after,.topbar nav a:focus-visible::after,
	.topbar nav a[aria-current]::after{transform:scaleX(1)}
}

/* Language pill: the caret rotates, the flag gets a subtle parallax. */
@media (prefers-reduced-motion:no-preference){
	.nx-langdd__caret{transition:transform var(--nx-d-md) var(--nx-e-snap)}
	.nx-langdd.is-open .nx-langdd__caret{transform:rotate(180deg)}
	.nx-langdd__menu{transform-origin:top center}
	.nx-langdd.is-open .nx-langdd__menu{animation:nxMenuIn var(--nx-d-md) var(--nx-e-snap) both}
	@keyframes nxMenuIn{from{opacity:0;transform:translateY(-6px) scale(.97)}to{opacity:1;transform:none}}
	[dir="rtl"] .nx-langdd__menu{transform-origin:top center}
}

/* Mobile bottom nav: the active item's icon springs. */
@media (prefers-reduced-motion:no-preference){
	.mnItem .nxi,.mnItem svg{transition:transform var(--nx-d-lg) var(--nx-e-snap)}
	.mnItem.on .nxi,.mnItem.on svg{transform:translateY(-2px) scale(1.12)}
	.mnItem:active{transform:scale(.9);transition-duration:var(--nx-d-xs)}
}

/* The live "vendors online" dot breathes instead of blinking. */
@media (prefers-reduced-motion:no-preference){
	.utilDot,.onlineDot{animation:nxBreathe 2.6s var(--nx-e-standard) infinite}
	@keyframes nxBreathe{
		0%,100%{opacity:1;box-shadow:0 0 0 0 rgba(183,255,60,.55)}
		50%    {opacity:.75;box-shadow:0 0 0 6px rgba(183,255,60,0)}
	}
}

/* ============================================================================
   10. FORMS — inputs that respond, errors that arrive gently
   ========================================================================== */
input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]),
select,textarea,.wc-block-components-text-input input{
	transition:
		border-color var(--nx-d-sm) var(--nx-e-standard),
		box-shadow var(--nx-d-sm) var(--nx-e-standard),
		background-color var(--nx-d-sm) var(--nx-e-standard);
}
input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):focus,
select:focus,textarea:focus{
	border-color:var(--brand-border,rgba(183,255,60,.4));
	box-shadow:0 0 0 4px rgba(183,255,60,.14);
}
/* Only flag a field once the user has actually engaged with it. */
input:user-invalid,select:user-invalid,textarea:user-invalid{
	border-color:rgba(255,77,125,.65);
	box-shadow:0 0 0 4px rgba(255,77,125,.12);
}
@media (prefers-reduced-motion:no-preference){
	input:user-invalid,select:user-invalid,textarea:user-invalid{animation:nxShake .32s var(--nx-e-standard)}
	@keyframes nxShake{
		0%,100%{transform:translateX(0)}
		25%{transform:translateX(-4px)}
		75%{transform:translateX(4px)}
	}
}

/* ============================================================================
   11. WOOCOMMERCE BLOCKS — real skeletons while React hydrates
   ----------------------------------------------------------------------------
   The blocks ship `is-loading` on the wrapper until hydration completes.
   nabux-motion.js inserts a real shimmering placeholder of the right shape in
   front of the block and hides the block until that class clears; these rules
   suppress the half-painted block underneath it.

   EVERY rule here is gated on html.nx-js. Ungated, `color:transparent` would
   leave the cart permanently invisible for anyone whose JavaScript failed to
   load — an empty black rectangle with no way out. Without JS there is no
   skeleton to show, so the honest fallback is the unstyled block, visible.
   ========================================================================== */
html.nx-js .wp-block-woocommerce-cart.is-loading,
html.nx-js .wp-block-woocommerce-checkout.is-loading{position:relative;min-height:420px}
html.nx-js .wp-block-woocommerce-cart.is-loading *,
html.nx-js .wp-block-woocommerce-checkout.is-loading *{color:transparent!important;border-color:transparent!important}
html.nx-js .wp-block-woocommerce-cart.is-loading img,
html.nx-js .wp-block-woocommerce-checkout.is-loading img{opacity:0}

/* Blocks' own placeholder boxes get the brand shimmer instead of flat grey. */
.wc-block-components-skeleton,
.wc-block-components-loading-mask__children,
.is-loading .wc-block-components-sidebar,
.is-loading .wc-block-cart-items{position:relative}
.wc-block-components-loading-mask{position:relative}
.wc-block-components-loading-mask .components-spinner{opacity:0}
.wc-block-components-loading-mask::after{
	content:"";position:absolute;inset:0;pointer-events:none;
	background:var(--nx-skel-sweep);translate:-100% 0;border-radius:inherit;
}
@media (prefers-reduced-motion:no-preference){
	.wc-block-components-loading-mask::after{animation:nxShimmer var(--nx-skel-speed) var(--nx-e-standard) infinite}
}

/* Quantity stepper: tactile, and the number settles after the press. */
@media (prefers-reduced-motion:no-preference){
	.wc-block-components-quantity-selector__button{transition:transform var(--nx-d-xs) var(--nx-e-standard),background-color var(--nx-d-sm) linear}
	.wc-block-components-quantity-selector__button:active{transform:scale(.86)}
	.wc-block-components-quantity-selector__input{transition:transform var(--nx-d-md) var(--nx-e-snap)}
	.wc-block-components-quantity-selector.is-bumped .wc-block-components-quantity-selector__input{transform:scale(1.14)}
}
/* Removing a line item animates out instead of vanishing. */
@media (prefers-reduced-motion:no-preference){
	.wc-block-cart-items__row.is-removing{
		animation:nxRowOut var(--nx-d-xl) var(--nx-e-accel) forwards;
		overflow:hidden;
	}
	@keyframes nxRowOut{to{opacity:0;transform:translateX(-24px);max-height:0;padding-block:0;margin-block:0}}
	[dir="rtl"] .wc-block-cart-items__row.is-removing{animation-name:nxRowOutRtl}
	@keyframes nxRowOutRtl{to{opacity:0;transform:translateX(24px);max-height:0;padding-block:0;margin-block:0}}
}

/* Notices slide in rather than jolting the layout. */
@media (prefers-reduced-motion:no-preference){
	.wc-block-components-notice-banner,.woocommerce-message,.woocommerce-info,.woocommerce-error{
		animation:nxNotice var(--nx-d-xl) var(--nx-e-emph) both;
	}
	@keyframes nxNotice{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
}

/* ============================================================================
   12. PRODUCT PAGE — tabs, gallery, sticky buy bar
   ========================================================================== */
@media (prefers-reduced-motion:no-preference){
	.wc-tabs li a{position:relative;transition:color var(--nx-d-sm) var(--nx-e-standard)}
	.wc-tabs li::after{
		content:"";position:absolute;left:12px;right:12px;bottom:0;height:2px;border-radius:2px;
		background:var(--grad-brand,linear-gradient(135deg,#b7ff3c,#00d4ff));
		transform:scaleX(0);transform-origin:center;
		transition:transform var(--nx-d-lg) var(--nx-e-emph);
	}
	.wc-tabs li.active::after,.wc-tabs li:hover::after{transform:scaleX(1)}
	.woocommerce-Tabs-panel{animation:nxPanelIn var(--nx-d-xl) var(--nx-e-decel) both}
	@keyframes nxPanelIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

	/* Rating stars fill left-to-right on hover of the rating control. */
	.woocommerce p.stars a{transition:transform var(--nx-d-sm) var(--nx-e-snap)}
	.woocommerce p.stars a:hover{transform:scale(1.25)}
}

/* ============================================================================
   13. RTL + REDUCED MOTION SAFETY NET
   ========================================================================== */
/* Sweeps are direction-aware so the shimmer runs with the reading direction. */
[dir="rtl"] .nxSkel::after,[dir="rtl"] .nx-img::after,
[dir="rtl"] .wc-block-components-loading-mask::after{animation-name:nxShimmerRtl}
@keyframes nxShimmerRtl{
	0%  {translate:100% 0}
	60% {translate:-100% 0}
	100%{translate:-100% 0}
}
[dir="rtl"] .primaryButton::after,[dir="rtl"] .buyPill::after,
[dir="rtl"] .single_add_to_cart_button::after,
[dir="rtl"] .wc-block-components-button.contained::after{translate:130% 0}
[dir="rtl"] .primaryButton:hover::after,[dir="rtl"] .buyPill:hover::after,
[dir="rtl"] .single_add_to_cart_button:hover::after,
[dir="rtl"] .wc-block-components-button.contained:hover::after,
[dir="rtl"] .productCard:hover .buyPill::after{translate:-130% 0}
[dir="rtl"] .productCard .cardArt::after{translate:120% 0}
[dir="rtl"] .productCard:hover .cardArt::after{translate:-120% 0}

/* ============================================================================
   14. DEFECTS CAUGHT BY THE VERIFICATION SWEEP
   ========================================================================== */

/* The sale badge painted #fff on --danger (#ff4d7d) = 3.18:1. At 12px/900 that
   is normal text, so it needed 4.5:1 and missed on every card on every page.
   Near-black on the same pink measures 6.08:1 — comfortably over the bar, with
   the badge exactly as loud as it was: only the label changes, never the colour
   that carries the "this is a discount" signal. */
.artDiscount,.dealSave{
	color:var(--on-brand,#07100a);
	/* "-28%" is LTR content. Inside an RTL paragraph the leading hyphen is a
	   neutral character, so bidi reordering moved it to the far end and the badge
	   read "28%-" on every fa/ar page. Isolating the run pins it back. */
	unicode-bidi:isolate;
	direction:ltr;
}

/* The marketplace plugin's offer badge paints #fff on #16a34a = 3.30:1, under
   the 4.5:1 that 11px/400 needs. Darkening the green to #0f7a35 keeps the badge
   unmistakably "good price" green and lifts it to 5.45:1.
   Source of the original: plugins/nabux-marketplace/assets/front.css */
.nabux-offer__badge{background:#0f7a35}

/* A bare <table> inside a product description (the "Plans" table) measures
   501px and dragged the whole product page to a 540px scrollWidth at a 390px
   viewport — a horizontal scrollbar on every phone. Let the table scroll inside
   its own box instead of widening the document. */
.woocommerce-Tabs-panel table,.entry-content table,.nx-single-wrap table,
.productDescription table{
	display:block;
	width:100%;
	max-width:100%;
	overflow-x:auto;
	-webkit-overflow-scrolling:touch;
	overscroll-behavior-x:contain;
}
.woocommerce-Tabs-panel table>thead,.woocommerce-Tabs-panel table>tbody,
.entry-content table>thead,.entry-content table>tbody{min-width:max-content}

/* Nothing may widen the viewport. `clip` rather than `hidden` on purpose:
   overflow:hidden would turn <html> into a scroll container and silently kill
   position:sticky on .topbar. overflow:clip does not, so the sticky header and
   the smooth-scroll behaviour both survive. */
html,body{overflow-x:clip}

/* Price and CTA share one row. Give the price column permission to shrink and
   the pill permission not to, so a long price wraps inside its own column
   instead of shouldering the button out of the card. */
.cardFooter{grid-template-columns:minmax(0,1fr) auto;gap:12px}
.cardFooter>div{min-width:0}
.buyPill{white-space:nowrap;flex:none}

/* ============================================================================
   15. SHOP / ARCHIVE GRID — the archive was never actually converted
   ----------------------------------------------------------------------------
   The home page builds its grid with .cardsGrid, but every WooCommerce archive
   (shop, category, search, related products, up-sells) outputs
   `ul.products > li.product`, which the theme never styled. WooCommerce's own
   woocommerce-layout.css was therefore still laying them out with
   `float:left; width:22.05%`, and the result count and sort control were
   floating beside the grid — which is why the shop page rendered as a narrow
   column of 191px cards with empty gutters either side.
   ========================================================================== */
.woocommerce ul.products,.woocommerce-page ul.products{
	display:grid;
	grid-template-columns:repeat(3,minmax(0,1fr));
	gap:20px;
	margin:6px 0 26px;
	padding:0;
	list-style:none;
	float:none;
}
/* The clearfix pseudo-elements become stray grid items once display:grid wins. */
.woocommerce ul.products::before,.woocommerce ul.products::after,
.woocommerce-page ul.products::before,.woocommerce-page ul.products::after{display:none}

.woocommerce ul.products li.product,.woocommerce-page ul.products li.product{
	float:none;
	width:auto;
	margin:0;
	padding:0;
	display:flex;
	flex-direction:column;
}
.woocommerce ul.products li.product>.productCard{flex:1}

@media (max-width:1000px){
	.woocommerce ul.products,.woocommerce-page ul.products{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:640px){
	.woocommerce ul.products,.woocommerce-page ul.products{grid-template-columns:1fr;gap:16px}
}

/* Unfloat the archive toolbar so it sits above the grid instead of inside it. */
.woocommerce .woocommerce-products-header,
.screen>.woocommerce-result-count,.screen>.woocommerce-ordering,
.woocommerce .woocommerce-result-count,.woocommerce .woocommerce-ordering{float:none}
.screen>.woocommerce-ordering,.woocommerce .woocommerce-ordering{
	display:flex;justify-content:flex-end;
	/* margin-block only — the `margin` shorthand would wipe the
	   `margin-inline:var(--page-pad-x,5vw)` gutter nabux-glue.css sets, and the
	   sort control would run edge-to-edge while everything else stayed inset. */
	margin-block:0 18px;
}
/* spa.css sets `input, textarea, select { width:100% }` for form fields. The
   sort control is chrome, not a form field, so it sizes to its content. */
.woocommerce .woocommerce-ordering select,.screen>.woocommerce-ordering select{
	width:auto;min-width:210px;margin-top:0;
}

/* Clamp the blurb to three lines with a real ellipsis. It was hard-limited by
   `min-height:76px` and simply sliced mid-word at narrow card widths. */
.productCard .productDescription{
	display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
	overflow:hidden;
}
.cardFooter .price{white-space:nowrap}

/* Final backstop. nabux-glue.css already zeroes durations globally under
   reduce; this removes the remaining *displacement* so nothing can drift. */
@media (prefers-reduced-motion:reduce){
	.nx-reveal{opacity:1!important;translate:none!important;scale:none!important}
	.primaryButton::after,.buyPill::after,.productCard .cardArt::after,
	.single_add_to_cart_button::after,.wc-block-components-button.contained::after{display:none}
	.utilDot,.onlineDot{animation:none}
	.nx-img img{opacity:1;transform:none}
}
