/**
 * Mobile bottom tab bar — parts/mobile-bar.html.
 *
 * Five fixed tabs (Home, Downloads, Search, Help, Account) pinned to the bottom of
 * the viewport on phones, and the search panel the Search tab opens. Option A of
 * .mockups/mobile-bottom-bar.html; the contextual CTA variants in that file are
 * deliberately NOT implemented.
 *
 * 782px and not 899px, which is the breakpoint the site header uses. They are
 * answering different questions: the header collapses when a three-column row
 * stops fitting, which happens on tablets, while this bar is a PHONE affordance
 * borrowed from iOS and Android. 782px is also the width WordPress core itself
 * treats as the mobile boundary, so an iPad in portrait keeps the ordinary
 * header navigation and gets no app-style chrome.
 *
 * The part renders on every request (it is nested in parts/footer.html), so the
 * markup exists at every width and this stylesheet alone decides whether it is
 * seen. `display: none` above the breakpoint rather than a conditional render:
 * the bar is one flex row of five links, and a server-side viewport test does
 * not exist to be correct about.
 *
 * Layer: `header` (20) from the scale written down at the top of
 * site-header.css. This is persistent chrome and has to beat page content, but
 * it must lose to the filter drawer and the skip link, which take over the
 * screen.
 */
.f32-mobile-bar {
	display: none;
}

@media (max-width: 782px) {
	/*
	 * The bar's arithmetic, stated once so the body's compensation below cannot
	 * drift from it: top pad + tab min-height + bottom pad + hairline.
	 */
	:root {
		--f32-mobile-bar-height: calc(8px + 44px + 10px + 1px);
	}

	.f32-mobile-bar {
		position: fixed;
		inset-inline: 0;
		bottom: 0;
		z-index: var(--wp--custom--z-index--header, 20);
		display: flex;
		background-color: var(--wp--preset--color--contrast, #ffffff);
		/*
		 * Border only, no shadow: the site header is the bar's mirror at the top of
		 * the viewport and separates itself with this same hairline. A shadow here
		 * would be the only floating chrome on the site.
		 */
		border-top: 1px solid var(--wp--preset--color--border-subtle, #e0e0e0);

		/*
		 * The home indicator on a notched iPhone sits INSIDE the viewport, so a
		 * bar flush to `bottom: 0` puts its labels under the system gesture
		 * area. The inset is added to the bottom padding rather than to the
		 * bottom offset: growing the offset would leave a strip of page content
		 * showing beneath the bar as it scrolls. On every device that has no
		 * inset the value resolves to 0 and this is a plain 10px/12px bar.
		 */
		padding-block: 8px calc(10px + env(safe-area-inset-bottom, 0px));
		padding-inline: env(safe-area-inset-left, 0px) env(safe-area-inset-right, 0px);
	}

	.f32-mobile-bar__tab {
		flex: 1;
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 2px;
		padding-block: 2px;

		/*
		 * 44px is the minimum touch target both platform guidelines ask for,
		 * and the icon plus an 11px label does not reach it on its own.
		 */
		min-height: 44px;
		color: var(--wp--preset--color--muted, #6b7280);
		font-size: 0.6875rem;
		line-height: 1.2;
		font-weight: 500;
		text-align: center;
		text-decoration: none;
	}

	.f32-mobile-bar__icon {
		display: block;
		flex: none;
	}

	/*
	 * THE FIFTH TAB MADE THE LONGEST LABEL THE TIGHT ONE. Five equal tabs on a 320px
	 * screen - the narrowest phone still worth answering for - are 61px each, and
	 * "Downloads" measures 59px at the size above. Two pixels is not a margin.
	 *
	 * The failure it guards against is not clipping, it is WRAPPING: a label that
	 * takes two lines makes the bar taller than the arithmetic at the top of this
	 * file, and `body` is padded by that arithmetic - so the last line of the footer
	 * would sit under a bar that grew without telling anyone.
	 *
	 * One step down below 360px buys about 5px per label and costs nothing legible;
	 * the tab's own 44px floor holds the row height, so the bar is the same height
	 * either way and the compensation still matches.
	 *
	 * It does NOT protect against a visitor who has raised their system font size,
	 * which scales this rem along with everything else. That case wraps, the bar
	 * grows by one line, and the page keeps working - which is the right way for a
	 * type-size preference to fail.
	 */
	@media (max-width: 360px) {
		.f32-mobile-bar__tab {
			font-size: 0.625rem;
		}
	}

	/*
	 * ACTIVE TAB, and why three of the four selectors are body classes rather
	 * than `aria-current`.
	 *
	 * `aria-current="page"` is written server-side by patterns/mobile-bar.php,
	 * which resolves the query the way a static part never could - including for
	 * the Account tab, whose page has no stable body class. One attribute is
	 * both the accessible state and the style hook, so the body-class selectors
	 * this rule once carried are gone with the limitation that required them.
	 */
	.f32-mobile-bar__tab[aria-current] {
		color: var(--wp--preset--color--action, #1d4ed8);
		font-weight: 600;
	}

	/*
	 * The bar is fixed, so it covers whatever the last thing on the page is -
	 * the footer's Legal column, or the final row of a product grid. The page
	 * pays for the bar's own height plus the safe-area inset it was given above.
	 */
	body {
		padding-bottom: calc(var(--f32-mobile-bar-height, 63px) + env(safe-area-inset-bottom, 0px));
	}
}

/* === The search panel ==================================================== */

/*
 * A BOTTOM SHEET, sitting on top of the bar that opened it.
 *
 * It used to be a strip at the top of the screen behind a full-viewport scrim.
 * That asked the visitor to touch the bottom of the phone and then read the top
 * of it, and it painted the bar itself dark - so five tabs sat there looking
 * touchable while showModal() had made them inert. The panel now opens a
 * finger's width above the thumb that opened it, and the bar below it stays lit
 * and stays live.
 *
 * A `<dialog>` opened TWO ways, and both of them have to be styled here.
 *
 *   [open]  - assets/js/mobile-search.js called show(). NOT showModal(): a modal
 *             dialog makes everything outside it inert, and a bar that is visible
 *             but cannot be touched is worse than a bar that is covered. show()
 *             leaves the tabs reachable, so a visitor who opened search by mistake
 *             can go straight to Downloads instead of cancelling first.
 *   :target - no JavaScript. The tab is a plain link to this element's id, so the
 *             fragment alone opens the panel.
 *
 * Both are now ordinary fixed elements and both take `modal` (40) out of the scale
 * at the top of site-header.css, above the bar's own `header` (20). One rule set
 * serves both, which the top-layer version could not do.
 *
 * The dialog box is the region ABOVE the bar, not the whole viewport - that is what
 * keeps the scrim off the bar without a second element to draw it. The panel is the
 * only thing in that box, so `justify-content: flex-end` puts it at the bottom of
 * it, which is directly on the bar's top edge.
 *
 * PHONES ONLY. Above 782px the bottom bar is gone, so nothing can open this and the
 * header carries a real search field instead.
 */
.f32-search-modal {
	display: none;
}

@media (max-width: 782px) {
	.f32-search-modal[open],
	.f32-search-modal:target {
		display: flex;
		flex-direction: column;
		justify-content: flex-end;
		position: fixed;
		top: 0;
		inset-inline: 0;

		/*
		 * WHERE THE FLOOR IS, and it is not always the bar.
		 *
		 * With the keyboard closed the floor is the bar's own height, safe-area
		 * inset included, exactly as `body` pays for it above - so the panel rests
		 * on the bar.
		 *
		 * With the keyboard OPEN the bar is behind the keyboard and cannot be the
		 * floor. Neither iOS Safari nor Chrome shrinks the layout viewport for an
		 * on-screen keyboard - the default `interactive-widget` is `resizes-visual`
		 * and the theme's viewport meta (functions.php) does not change it, on
		 * purpose: that meta covers every page, the checkout's Stripe iframe
		 * included. So a `bottom: 0` element goes UNDER the keyboard, which is
		 * where this panel would have gone.
		 *
		 * mobile-search.js measures the keyboard with the VisualViewport API and
		 * writes it here. `max()` picks whichever floor is higher, so one rule
		 * covers both states and the fallback of 0px is the keyboard-closed case.
		 */
		bottom: max(
			calc(var(--f32-mobile-bar-height, 63px) + env(safe-area-inset-bottom, 0px)),
			var(--f32-search-lift, 0px)
		);
		z-index: var(--wp--custom--z-index--modal, 40);

		/*
		 * The UA gives `<dialog>` `width: fit-content`, `height: fit-content` and a
		 * max of `calc(100% - 6px - 2em)`. All four of them have to go, or the
		 * insets above size nothing.
		 */
		width: auto;
		max-width: none;
		height: auto;
		max-height: none;
		margin: 0;
		padding: 0;
		border: 0;

		/*
		 * Darker than the filter drawer's 0.28. That scrim is deliberately light so
		 * the grid can be watched changing behind it; nothing behind THIS panel is
		 * worth reading while it is open.
		 *
		 * It covers the content and STOPS at the bar, because the box does. The
		 * `::backdrop` reset the top-layer version needed is gone with it: show()
		 * renders no backdrop and `:target` never had one.
		 */
		background-color: rgba(17, 22, 32, 0.44);

		/*
		 * The motion is the point of the sheet: it comes up out of the bar the
		 * visitor just touched, so the eye is carried to it instead of having to
		 * find it. The scrim fades and only the panel travels - a scrim that slides
		 * shows a seam at the bottom of the screen.
		 */
		animation: f32-search-scrim 160ms ease-out;
	}

	@keyframes f32-search-scrim {
		from {
			background-color: rgba(17, 22, 32, 0);
		}
	}

	@keyframes f32-search-sheet {
		from {
			transform: translateY(100%);
		}
	}

	/*
	 * The sheet itself. Everything outside this box is the dialog element, which is
	 * what mobile-search.js tests for to close on a scrim tap.
	 *
	 * `flex: none` because the dialog is a column flex container now: without it the
	 * panel would stretch to fill the whole scrim.
	 */
	.f32-search-modal__panel {
		flex: none;
		display: flex;
		align-items: center;
		gap: 10px;
		padding-block: 12px;
		padding-inline: calc(
				var(--wp--preset--spacing--gutter, 16px) + env(safe-area-inset-left, 0px)
			)
			calc(var(--wp--preset--spacing--gutter, 16px) + env(safe-area-inset-right, 0px));
		background-color: var(--wp--preset--color--contrast, #ffffff);

		/*
		 * A hairline on TOP now, not underneath: the panel's bottom edge meets the
		 * bar, and the bar draws this same hairline on its own top edge already.
		 */
		border-top: 1px solid var(--wp--preset--color--border-subtle, #e0e0e0);
		animation: f32-search-sheet 180ms cubic-bezier(0.32, 0.72, 0, 1);
	}

	@media (prefers-reduced-motion: reduce) {
		.f32-search-modal[open],
		.f32-search-modal:target,
		.f32-search-modal__panel {
			animation: none;
		}
	}

	/*
	 * `min-width: 0` is the same load-bearing rule the header search carries: a flex
	 * item's automatic minimum size is its content, so without it the field refuses
	 * to shrink below its placeholder and pushes Cancel off the row.
	 */
	.f32-search-modal__search {
		flex: 1 1 auto;
		min-width: 0;
		margin: 0;
	}

	/*
	 * THE SUGGESTION LIST OPENS UPWARDS, which is the one thing a bottom sheet costs.
	 *
	 * The block hangs its listbox off the bottom of the field - `top: calc(100% +
	 * offset)` in the block's own style.scss - because in the site header there is a
	 * page below it to open into. Here there is a keyboard below it. Turned over, the
	 * list grows into the scrim, which is the only free space on the screen.
	 *
	 * The shadow is turned over with it. A panel above the field lit from below is
	 * the giveaway that a menu was flipped and nobody moved its light.
	 *
	 * HEIGHT is measured, not guessed. The block's own cap is `min(22rem, 60vh)`, and
	 * `vh` is the LAYOUT viewport - the whole screen, keyboard included - so a list
	 * that obeyed it would run behind the keyboard and off the top of the screen.
	 * mobile-search.js writes the real space above the sheet into
	 * `--f32-search-suggest-max`. With no script the 45vh fallback is deliberately
	 * short, because that is the case where the keyboard's size is unknown.
	 */
	.f32-search-modal .wp-block-sparklestock-product-search__suggestions {
		top: auto;
		bottom: calc(100% + var(--ss-search-suggestions-offset, 6px));
		max-height: min(22rem, var(--f32-search-suggest-max, 45vh));
		box-shadow: var(--ss-search-picker-shadow-up, 0 -12px 32px rgba(0, 0, 0, 0.18));
	}

	.f32-search-modal__close {
		flex: none;

		/* 44px is the minimum touch target both platform guidelines ask for. */
		display: inline-flex;
		align-items: center;
		min-height: 44px;
		color: var(--wp--preset--color--action, #1d4ed8);
		font-size: 0.9375rem;
		font-weight: 500;
		text-decoration: none;
	}

	/*
	 * The page behind the sheet must not scroll. `<dialog>` does not do this on its
	 * own - and show() does even less for it than showModal() did - so on iOS Safari
	 * a touch that starts over the scrim pans the document under the panel. Set by
	 * mobile-search.js, so it applies to the show() case only; the `:target` fallback
	 * has no script to set it and degrades to a page that still scrolls behind an
	 * open panel.
	 *
	 * The BAR is deliberately left out of this. It is fixed chrome, it is outside the
	 * scrim, and it stays live for as long as the sheet is open.
	 */
	:root[data-f32-search="open"] {
		overflow: hidden;
	}
}
