/**
 * MicroBite POS — [stick1] sticky add-to-cart bar.
 *
 * Every rule is prefixed [data-mbpos] per the st73–st102 isolation rule, and
 * every length is px. Nothing here reaches outside the bar: Woo's own price
 * element and button belong to the theme and are left alone.
 *
 * The bar is moved to document.body at boot, so it is NOT nested inside any
 * theme container here — do not write descendant selectors that assume it is.
 */

[data-mbpos].mbpos-sticky {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 9990;

	background: var(--mbpos-color-surface, #fff);
	border-top: 1px solid var(--mbpos-color-border, #e5e7eb);
	box-shadow: 0 -2px 12px rgba(0, 0, 0, .10);

	font-family: var(--mbpos-font-body, inherit);
	font-size: var(--mbpos-font-size-base, 15px);
	color: var(--mbpos-color-text, #374151);

	/* Home indicator eats the button without this. */
	padding-bottom: env(safe-area-inset-bottom, 0px);

	/* Hidden until the real button leaves the viewport. translateY rather
	   than display so the bar animates on the compositor — no layout, no
	   paint of the page behind it. */
	transform: translateY(100%);
	transition: transform 160ms ease-out;
	will-change: transform;
	pointer-events: none;
}

[data-mbpos].mbpos-sticky.is-visible {
	transform: translateY(0);
	pointer-events: auto;
}

/* iOS soft keyboard — the bar must not float over the field being typed in. */
[data-mbpos].mbpos-sticky.is-suppressed {
	transform: translateY(100%);
	pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
	[data-mbpos].mbpos-sticky {
		transition: none;
	}
}

[data-mbpos] .mbpos-sticky__inner {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 10px 12px;
	max-width: 1200px;
	margin: 0 auto;
}

/* --- total ------------------------------------------------------------- */

/* --- quantity ---------------------------------------------------------- */

/* [stick3a] Ported from the POS product-modal footer
   (mbpos-pos-layout.css .mbpos-products-detail__qty) so a customer who has used
   the POS reads the same control twice. SAME TOKENS, SAME FALLBACKS — restated
   rather than imported, because mbpos-pos-layout.css is not loaded on the
   storefront and a var() with no fallback would resolve to nothing here.
   `overflow: hidden` is what clips the button fills to the radius; without it
   the corners show square fills inside a rounded box. */
[data-mbpos] .mbpos-sticky__qty {
	display: flex;
	align-items: center;
	box-sizing: border-box;
	flex: 0 0 auto;
	/* [stick3] LEFT, not right — the modal footer puts quantity first. */
	margin-right: auto;
	border: 1px solid var(--mbpos-qty-border-color, rgba(120, 113, 108, 0.38));
	border-radius: var(--mbpos-radius-btn, 8px);
	overflow: hidden;
}

[data-mbpos] .mbpos-sticky__step {
	/* [fix2] inline-flex + centring. A bare <button> whose min-height exceeds
	   its line box does NOT reliably centre its own text — the glyph sits on
	   the baseline of an anonymous box at the top. That is why the - and + sat
	   high in the pill. Ported from the POS stepper, which solved this already. */
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* [stick3a] The modal's button WIDTH (60px), the storefront's tap-target
	   HEIGHT (44px). Deliberately not a straight copy: the modal is 40px high,
	   which is below the 44px floor stick1 set and fix2 §1D still asserts —
	   and the modal is used by staff on a counter tablet while this is used by
	   customers on phones. Look ported, accessibility floor kept.
	   The qty cell below declares the SAME width so the three read as one
	   group (Peter, stick2a1). Literals both sides: jsdom cannot resolve var()
	   and the two sizes would stop being comparable — fix2 §1D caught exactly
	   that on the first attempt. stick2 §10 asserts the equality. */
	min-width: 60px;
	min-height: 44px;
	padding: 0;
	margin: 0;
	border: 0;
	border-radius: 0;
	/* [fix2] Theme-leak guard. Elementor and Bricks both style bare <button>,
	   and those rules reach ours. Everything a builder is likely to set is
	   restated here rather than left to chance. */
	-webkit-appearance: none;
	appearance: none;
	box-shadow: none;
	text-transform: none;
	letter-spacing: normal;
	/* [stick2a] The SAME resting token the POS stepper uses
	   (mbpos-pos-layout.css). This was `transparent`, so the bar's - and +
	   sat on the bare bar while the POS modal's sat on a faint fill — Peter
	   spotted the mismatch in Elementor. It also means this stepper now
	   follows the Appearance setting qb1 added, including a theme that
	   overrides it for a dark surface. */
	background: var(--mbpos-qty-btn-bg, rgba(0, 0, 0, 0.04));
	color: var(--mbpos-color-text, #374151);
	font: inherit;
	/* [stick3a] The modal's glyph size. 20px read as a different control. */
	font-size: var(--mbpos-qty-font-size, 14px);
	line-height: 1;
	cursor: pointer;
}

/* [fix2] THE rule this arc is really about: never change a background without
   restating its colour in the same place. Elementor's button styling left the
   + stuck purple after a click and turned the - the same shade as its own
   hover background, so it vanished. Both are the same mistake — a background
   moving while the text colour is decided somewhere else.

   rgba(), not a surface token: a relative darkening works on whatever the bar
   sits on and cannot collide with a theme hue. Same token the POS stepper uses. */
[data-mbpos] .mbpos-sticky__step:hover,
[data-mbpos] .mbpos-sticky__step:focus,
[data-mbpos] .mbpos-sticky__step:active {
	background: var(--mbpos-qty-btn-hover-bg, rgba(0, 0, 0, 0.08));
	color: var(--mbpos-color-text, #374151);
	box-shadow: none;
}

/* A mouse click must leave nothing behind. The keyboard ring is :focus-visible
   and is declared below, so clearing the mouse case here costs no a11y. */
[data-mbpos] .mbpos-sticky__step:focus:not(:focus-visible):not(:hover) {
	/* [stick2a] Back to the RESTING token, not transparent — otherwise a
	   clicked button ends up paler than the one beside it.
	   The colour is restated because fix2's invariant applies to every
	   interactive-state rule that moves a background, and it caught this one
	   the moment the background stopped being transparent. Fixed, not
	   exempted — which is fix2's own instruction. */
	background: var(--mbpos-qty-btn-bg, rgba(0, 0, 0, 0.04));
	color: var(--mbpos-color-text, #374151);
}

/* [stick2a1] The number cell is the SAME width as the - and + beside it, so
   the three read as one group the way the POS cart row and the product modal
   footer do. It was 28px against 44px buttons: visibly lopsided, and it grew
   again at two digits. tabular-nums keeps 1 and 10 the same width inside it,
   so nothing shifts as the quantity climbs. */
[data-mbpos] .mbpos-sticky__qty-value {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 60px;
	min-height: 44px;
	text-align: center;
	font-weight: 600;
	font-size: var(--mbpos-qty-font-size, 14px);
	font-variant-numeric: tabular-nums;
}

/* --- add --------------------------------------------------------------- */

/* [stick3a] Ported from .mbpos-products-detail__add. The gradient is derived
   from --mbpos-color-primary rather than being a second colour control, so
   recolouring Primary recolours this exactly as it does the modal (st85's
   reasoning, unchanged). color-mix has no IE-era fallback and needs none —
   a browser that cannot parse it drops the whole background declaration, so
   the flat `background-color` below it is what shows. Declared in that order
   deliberately. */
[data-mbpos] .mbpos-sticky__add {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	flex: 0 1 auto;
	-webkit-appearance: none;
	appearance: none;
	text-transform: none;
	min-height: 44px;
	padding: var(--mbpos-space-xs, 12px) var(--mbpos-space-m, 20px);
	border: none;
	border-radius: var(--mbpos-radius-btn, 8px);
	background-color: var(--mbpos-color-primary, #111827);
	background: linear-gradient(180deg,
		color-mix(in srgb, var(--mbpos-color-primary, #111827) 90%, #fff) 0%,
		var(--mbpos-color-primary, #111827) 55%,
		color-mix(in srgb, var(--mbpos-color-primary, #111827) 94%, #000) 100%);
	color: var(--mbpos-color-primary-text, #fff);
	font-family: inherit;
	font-size: var(--mbpos-font-size-base, 15px);
	font-weight: 600;
	cursor: pointer;
	white-space: nowrap;
	box-shadow: 0 1px 2px rgba(87, 60, 38, 0.18),
		inset 0 1px 0 rgba(255, 255, 255, 0.14);
	transition: transform .15s, opacity .15s, box-shadow .15s, filter .15s;
}

/* The label/price pair on one line, never breaking mid-price. */
[data-mbpos] .mbpos-sticky__add-label,
[data-mbpos] .mbpos-sticky__add-price {
	white-space: nowrap;
}

[data-mbpos] .mbpos-sticky__add-price {
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

/* [fix2] The add button gets the same guard — same builders, same leak. It
   brightens rather than recolouring, so the colour pair is preserved by
   construction, but the background and colour are restated anyway so a theme
   :focus/:active rule cannot take either of them. */
[data-mbpos] .mbpos-sticky__add:hover,
[data-mbpos] .mbpos-sticky__add:focus,
[data-mbpos] .mbpos-sticky__add:active {
	filter: brightness(1.08);
	background: var(--mbpos-color-primary, #111827);
	color: var(--mbpos-color-selected-text, #fff);
	box-shadow: none;
}

[data-mbpos] .mbpos-sticky__step:focus-visible,
[data-mbpos] .mbpos-sticky__add:focus-visible {
	outline: 2px solid var(--mbpos-color-focus, #2563eb);
	outline-offset: 2px;
}

/* Sold individually: no stepper, so the button takes the slack. */
[data-mbpos].mbpos-sticky[data-single] .mbpos-sticky__add {
	margin-left: auto;
}

/* ---------------------------------------------------------------------------
   [sfc1f] PHONES. This block is at 640px and that number is load-bearing.

   sfc1e put the badge-compacting rules at max-width:380px, inheriting the
   breakpoint stick3a used for its extra squeeze. 380px was chosen when the bar
   held three controls and already fitted — it is a "narrow phones" edge case,
   not "phones". An iPhone 14 is 390px and a Pixel is 412px, so on the actual
   devices customers use, none of it applied and the badge still rendered its
   full label. Reported from a real phone, not caught by any fence.

   Anything sized for a phone belongs here. The 380px block below is only for
   the further squeeze on genuinely small handsets.
   --------------------------------------------------------------------------- */
@media (max-width: 640px) {
	/* The badge collapses to icon + number. Four controls will not fit on one
	   row at this width and none of them could be dropped: the Add price is the
	   EPO running total, "Edit options" is stick5's persistent route back to the
	   options block, and the step buttons are at the 44px tap floor.

	   display:none rather than a width squeeze — a clipped "View ca…" reads as
	   broken, and the JS-set aria-label carries the full sentence for anyone not
	   reading it visually. */
	/* [sfc1h] flex 0 0 auto, not the default shrink. The badge is icon+number
	   here — about 48px — and when it was allowed to shrink the row stole width
	   from it and the anchor's overflow:hidden CLIPPED THE ICON. A control this
	   small has nothing to give; the row has to find its width elsewhere. */
	/* THE QTY READOUT IS NOT A TAP TARGET. The two step buttons keep their 44px
	   floor — they are tapped, and css-pair-test-fix2 §1D2 holds them there.
	   The number between them is a <span> nobody presses, and at 60px it was
	   costing the row more width than the badge ever did: 60+60+60 = 180px of
	   pill on a 390px screen. */
	/* [sfc1h] The pill down to 44+28+44 = 116px from 130. The STEPS sit exactly
	   on the 44px tap floor and go no lower — §10E holds that. The readout
	   between them is a <span> nobody presses, so it takes the cut. */
	[data-mbpos] .mbpos-sticky__qty-value {
		min-width: 28px;
	}
	[data-mbpos] .mbpos-sticky__step {
		min-width: 44px;
	}
	/* Padding, not the label or the price — the word says what the button does
	   and the price is the EPO running total. Neither is negotiable. */
	[data-mbpos] .mbpos-sticky__add {
		padding: var(--mbpos-space-xs, 12px) 12px;
		gap: 6px;
	}

	/* [sfc1g] The edit chip goes icon-only. Its aria-label has carried the
	   accessible name since stick4, so display:none on the text costs nothing
	   to a screen reader — unlike the badge, which needed a JS-set label.

	   min-width rises to 44px BECAUSE the text is gone: a text chip was wide
	   enough to tap by accident of its content, an icon is not. Same floor
	   css-pair-test-fix2 holds the steppers to, applied to the control that
	   just became the smallest thing on the row. */
	[data-mbpos] .mbpos-sticky__edit-label {
		display: none;
	}
	[data-mbpos] .mbpos-sticky__edit {
		min-width: 44px;
		min-height: 44px;
		padding: 0;
		justify-content: center;
	}

	/* The Add button and the qty pill do not give up width when the row
	   overflows — Add is what is being tapped and the pill is already at its
	   floor. Anything that has to shrink shrinks the badge. */
	[data-mbpos] .mbpos-sticky__add,
	[data-mbpos] .mbpos-sticky__qty {
		flex-shrink: 0;
	}
}

/* Narrow phones — the label is the first thing to go. */
@media (max-width: 380px) {
	[data-mbpos] .mbpos-sticky__inner {
		gap: 6px;
		padding: 8px 10px;
	}
	/* [stick3a] The stepper gives up width first — the Add button and its
	   price are the thing being tapped, and the old rule hid a Total label
	   that no longer exists. */
	/* [sfc1f] The STEP BUTTONS only. The value between them is not a tap
	   target and is narrowed at 640px; listing it here too put 60px back on
	   the pill at exactly the width that could least afford it. */
	[data-mbpos] .mbpos-sticky__step {
		min-width: 44px;
	}
	[data-mbpos] .mbpos-sticky__add {
		padding: var(--mbpos-space-xs, 12px) 14px;
	}
	/* [sfc1g] 360px holds four controls and the sums are tight. The gap and
	   the qty readout give up the last few px; the two step buttons stay on
	   the 44px floor and the Add price is never touched. */
	[data-mbpos] .mbpos-sticky__qty-value {
		min-width: 26px;
	}
}

/* ── [stick2] Reserved page space ──────────────────────────────────────── */

/* A permanently-fixed bar covers the bottom of the page. In `scroll` mode that
   lasts a moment; in `always` mode it is forever, so the page has to be padded
   by the bar's height. The class is added by JS only in always mode, so scroll
   mode is untouched.

   THE FALLBACK IS LOAD-BEARING. --mbpos-sticky-h is written from the bar's
   measured offsetHeight; if the script fails after the bar renders, or the
   measurement returns 0, `var(--mbpos-sticky-h)` with no fallback resolves to
   nothing and the footer sits under the bar. A slightly wrong pad leaves a
   small gap. No pad hides content. 76px is the bar at its default height with
   the quantity stepper present. */
body.mbpos-sticky-reserved {
	padding-bottom: var(--mbpos-sticky-h, 76px);
}

/* ── [stick4] The bar owns the buy action ──────────────────────────────── */

/* Added by mbpos-sticky-atc.js to form.cart ONLY in always mode, on a touch
   device, after the bar is live and when PHP permitted it (data-mbpos-sticky-owns
   / mbpos_sticky_atc_owns_cart). A JS-off page never gets this class, so Woo's
   own controls stay and the page still sells — the class is the whole guard.

   The native-control hides carry !important on purpose: these are FOREIGN
   elements (Woo/Bricks/Elementor), and a builder's own button rule can out-
   specify a plain descendant selector. Forcing a foreign element hidden is the
   one place !important earns its keep. The selectors target Woo CORE classes
   (.quantity, .single_add_to_cart_button), not theme wrappers, so the hide is
   theme-agnostic; a theme that renames them simply no-ops the rule and both
   controls stay — the safe direction.

   This is the sole exception to stick2 §6's "nothing hides Woo's button". That
   fence is narrowed to "no UNCONDITIONAL hide"; every hide here is behind the
   class. See MBPOS-STICK4-HANDOVER.md. */
.mbpos-sticky-owns-cart .quantity,
.mbpos-sticky-owns-cart .single_add_to_cart_button {
	display: none !important;
}

/* The inline Options/Total line is the plugin's OWN element — nothing else
   styles its display — so no !important is needed. It is only HIDDEN, never
   removed: it stays server-rendered as the JS-off and scroll-mode total. */
.mbpos-sticky-owns-cart .mbpos-epo__total {
	display: none;
}

/* ── [stick6] Pre-paint owns handoff ──────────────────────────────────────
   The inline <head> script (prepaint_boot) adds html.mbpos-js-owns BEFORE first
   paint, but ONLY on a page the server already decided is an always-mode,
   owns-permitted, eligible product page. So these fire at paint — Woo's controls
   are hidden and the bar is shown with no flash and no wait for the footer
   script. JS-off never sets the class, so it keeps Woo's controls and no bar
   (the JS-off contract). If the footer script never confirms ownership, the
   watchdog removes html.mbpos-js-owns on `load` and every rule below reverts.
   Same targets as .mbpos-sticky-owns-cart above; this is the SECOND sanctioned
   conditional hide of Woo's button (stick2 §6C permits both, and only these). */
html.mbpos-js-owns .quantity,
html.mbpos-js-owns .single_add_to_cart_button {
	display: none !important;
}
html.mbpos-js-owns .mbpos-epo__total {
	display: none;
}
/* Reveal the bar itself at paint. It renders `hidden` for the JS-off contract,
   so this overrides [hidden] and drops it into place — no slide, because in
   always mode it is pinned from load. wire() later adds .is-visible (transform
   translateY(0), a no-op here) and removes the `hidden` attribute so assistive
   tech sees it too; the AT gap is the pre-JS millisecond only. */
html.mbpos-js-owns [data-mbpos].mbpos-sticky[hidden] {
	display: block;
	transform: translateY(0);
	pointer-events: auto;
}

/* ── [stick4] "Edit options" affordance ────────────────────────────────── */

/* A ghost chip, deliberately quieter than the Add button so it reads as a
   secondary "jump back to your options" nudge, not a second buy control. It
   renders `hidden`; [stick5] the JS reveals it whenever an options block is
   present to scroll to (persistent wayfinding), and never when there is none.
   Shorter than the qty pill and the Add button, so its presence never changes
   the bar's height. */
[data-mbpos] .mbpos-sticky__edit {
	display: inline-flex;
	align-items: center;
	flex: 0 0 auto;
	min-height: 44px;
	padding: 0 12px;
	border: 1px solid var(--mbpos-color-primary, #111827);
	border-radius: var(--mbpos-radius-btn, 8px);
	background: transparent;
	color: var(--mbpos-color-primary, #111827);
	font-family: inherit;
	font-size: var(--mbpos-font-size-base, 15px);
	font-weight: 600;
	white-space: nowrap;
	cursor: pointer;
	-webkit-appearance: none;
	appearance: none;
	text-transform: none;
}

[data-mbpos] .mbpos-sticky__edit:hover,
[data-mbpos] .mbpos-sticky__edit:focus,
[data-mbpos] .mbpos-sticky__edit:active {
	/* [fix3] Restate the colour WITH the background. The base is dark text on a
	   transparent chip; this rule used to move only the background, so Elementor's
	   own `button:hover { color:#fff }` decided the text and the chip rendered
	   white-on-light — unreadable. The fix2 invariant: a background and its colour
	   move together, in the same rule. */
	background: color-mix(in srgb, var(--mbpos-color-primary, #111827) 8%, transparent);
	color: var(--mbpos-color-primary, #111827);
}

/* [fix3] A mouse click must leave nothing behind — the same rule .mbpos-sticky__step
   carries. Without it a tapped chip keeps the 8% tint (and, before the colour
   above, the theme's persisted focus colour) until the next blur. The keyboard
   ring stays on :focus-visible below, so accessibility is unaffected. */
[data-mbpos] .mbpos-sticky__edit:focus:not(:focus-visible):not(:hover) {
	background: transparent;
	color: var(--mbpos-color-primary, #111827);
}

[data-mbpos] .mbpos-sticky__edit:focus-visible {
	outline: 2px solid var(--mbpos-color-focus, #2563eb);
	outline-offset: 2px;
}

/* [hidden] must win regardless of the display above — same reason Woo's own
   forms restate it. */
[data-mbpos] .mbpos-sticky__edit[hidden] {
	display: none;
}

/* ---------------------------------------------------------------------------
   [sfc1] Storefront view-cart link.

   Sits FIRST in the row and shares it with the add button — it never replaces
   it. `margin-right: auto` pushes the qty pill and Add to the right edge while
   this stays left, so the two never compete for the same space.

   max-width caps it at just under half the bar so a long total can never crowd
   the Add button off a 360px phone; the ellipsis is the release valve. The
   count and total are the parts worth losing last, which is why the label is
   first in DOM order and therefore first to be clipped.

/* The count is the first thing to go on a narrow screen — the total is the
   number the customer is actually deciding on. */
/* [sfc1e] Badge parts. The icon and the count are the survivors; the words and
   the total are what a 360px screen gives up. See the phone block below. */
/* [sfc1g] Icon + label side by side above the phone breakpoint. */
[data-mbpos] .mbpos-sticky__edit-icon {
	display: inline-flex;
	align-items: center;
	flex: 0 0 auto;
}
[data-mbpos] .mbpos-sticky__edit {
	display: inline-flex;
	align-items: center;
	gap: 6px;
}
