/**
 * Product Search V2 — header autosuggest dropdown.
 *
 * Depends on gerbs-tokens for colour, radius and shadow. Every value here is a
 * token or derived from one; no new palette is introduced.
 *
 * 🚨 THE LITERAL IN EVERY var( --token, literal ) MUST EQUAL THE TOKEN.
 *
 * gerbs-tokens.css is deferred by WP Rocket, so on a deferred-sheet miss the
 * FALLBACK is what paints -- that failure has already shipped once on this site
 * (the hero CTA flashing the wrong yellow and blue, Wave-1 PR2). A fallback that
 * has drifted from its token is therefore not a harmless duplicate, it is an
 * off-brand render waiting for a cache miss. Five of the twelve here had drifted
 * and were corrected: hairline #e4e4e4 -> #ececec, blue-tint #eef4fb -> #eaf1ff,
 * fog #f5f5f5 -> #fafafa, error-ink #a32020 -> #a62b1f, and blue #1f5fa9 ->
 * #2F5EE6, which was a whole different blue. --shadow-lg was two layers out of
 * date as well. When you add a var() here, copy the literal out of
 * gerbs-tokens.css rather than typing the colour you remember.
 *
 * The panel is positioned against the search FORM, which is why the JS adds
 * .gsug-host to it. The three header forms already sit in different layout
 * contexts (desktop bar, mobile bar, drawer), so anchoring to the form rather than
 * to a shared wrapper is what lets one rule serve all three.
 */

.gsug-host {
	position: relative;
}

.gsug {
	position: absolute;
	z-index: 1000;
	top: calc( 100% + 6px );
	left: 0;
	right: 0;
	max-height: min( 70vh, 520px );
	overflow-y: auto;
	overscroll-behavior: contain;
	background: var( --gerbs-white, #fff );
	border: 1px solid var( --gerbs-hairline, #ececec );
	border-radius: var( --radius-md, 10px );
	box-shadow: var( --shadow-lg, 0 16px 40px rgba( 17, 17, 17, .10 ), 0 4px 12px rgba( 17, 17, 17, .06 ) );
	padding: 4px;
}

/* Rows -------------------------------------------------------------------- */

/*
 * 🚨 The .gnav qualifier on every colour rule below is REQUIRED, not stylistic.
 *
 * header-global.css carries `.gnav a { color: inherit }` at specificity (0,1,1),
 * and the desktop top row sets `color:#fff` on a blue ground. A bare `.gsug__row`
 * is only (0,1,0), so it LOSES, and every row renders white text on the white
 * panel — invisible. Shipped that way for one QA pass: thumbnails and prices were
 * visible and the product names simply were not there.
 *
 * `.gnav .gsug__row` is (0,2,0) and wins. This is the same trap, and the same fix,
 * that header-global.css already documents for `.gnav .gnav-btn--primary`.
 */
.gsug__row,
.gsug__all {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 8px 10px;
	border-radius: var( --radius-sm, 6px );
	text-decoration: none;
	/* Rows are keyboard-activated through aria-activedescendant while focus stays
	   in the input, so :focus never fires on them — .is-active is the only hover
	   equivalent the keyboard has, and must look identical to :hover. */
}

.gnav .gsug__row,
.gsug__row {
	color: var( --gerbs-ink, #111 );
}

.gnav .gsug__row:hover,
.gnav .gsug__row.is-active,
.gsug__row:hover,
.gsug__row.is-active,
.gnav .gsug__all:hover,
.gnav .gsug__all.is-active,
.gsug__all:hover,
.gsug__all.is-active {
	background: var( --gerbs-blue-tint, #eaf1ff );
	color: var( --gerbs-ink, #111 );
}

/*
 * The KEYBOARD-active row gets a ring; hover keeps the tint alone.
 *
 * They are not the same job. A mouse user has a cursor telling them where they
 * are, so a tint is a nicety. A keyboard user has ONLY this: focus never lands on
 * the row (aria-activedescendant keeps the caret in the input), so if the tint is
 * missed the shopper cannot tell what Enter will open. Measured, the tint alone is
 * 1.13:1 against the white panel -- far under the 3:1 that DESIGN.md rule 3 asks
 * of a non-text indicator, and effectively invisible in sunlight or on a cheap
 * panel. The ring on the tint measures 4.79:1.
 *
 * inset, so it does not enlarge the row or push its neighbours.
 */
.gnav .gsug__row.is-active,
.gsug__row.is-active,
.gnav .gsug__all.is-active,
.gsug__all.is-active {
	box-shadow: inset 0 0 0 var( --focus-ring-width, 2px ) var( --focus-ring-color, #2F5EE6 );
}

.gsug__img {
	flex: 0 0 auto;
	width: 48px;
	height: 48px;
	object-fit: cover;
	border-radius: var( --radius-sm, 6px );
	background: var( --gerbs-fog, #fafafa );
}

.gsug__img--none {
	display: block;
}

/*
 * Plain block: the title and the meta line stack, which is all a column flex
 * container was doing here.
 */
.gsug__body {
	min-width: 0; /* lets the title ellipsis instead of forcing the panel wider */
	display: block;
}

.gsug__title {
	font-size: var( --fs-14, 0.875rem );
	line-height: 1.35;
	font-weight: var( --fw-medium, 500 );
	/* Two lines then ellipsis: these titles run long ("Jumbo In-Shell Pumpkin
	   Seeds | Roasted & Unsalted") and a single line would cut most of them at the
	   packaging format, which is the part that distinguishes them.

	   Do not be alarmed that getComputedStyle() reports `flow-root` here rather
	   than `-webkit-box`. That is how current Chrome reports a line-clamped box,
	   and the clamp is working: measured on slot3 at a 260px panel width, a long
	   title gave clientHeight 38 against scrollHeight 113, i.e. exactly 2 lines of
	   the 18.9px line box. Verify clamping by measuring, not by reading `display`. */
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.gsug__hl {
	background: none;
	color: inherit;
	font-weight: 700;
}

.gsug__meta {
	display: flex;
	align-items: center;
	gap: 8px;
	margin-top: 2px;
	font-size: var( --fs-12, 12px );
}

/* Qualified for the same .gnav reason as the row colour above. */
.gnav .gsug__meta,
.gsug__meta {
	color: var( --gerbs-ink-70, #5c5c5c );
}

.gsug__oos {
	color: var( --gerbs-error-ink, #a62b1f );
	font-weight: var( --fw-medium, 500 );
}

/* Footer + empty ---------------------------------------------------------- */

.gsug__all {
	justify-content: center;
	/* 44px is the tap-target floor in DESIGN.md rule 4, and this row measured 42px
	   on desktop, in the 375px mobile bar and in the 390px drawer -- under it in
	   every context. It is also the row a shopper reaches for when none of the six
	   suggestions is right, so it is the worst one to make hard to hit. */
	min-height: 44px;
	font-size: var( --fs-14, 0.875rem );
	font-weight: var( --fw-medium, 500 );
	border-top: 1px solid var( --gerbs-hairline, #ececec );
	border-radius: 0 0 var( --radius-sm, 6px ) var( --radius-sm, 6px );
	margin-top: 4px;
}

/* Qualified: this link is an <a> inside .gnav and would otherwise inherit white. */
.gnav .gsug__all,
.gsug__all {
	color: var( --gerbs-blue, #2F5EE6 );
}

.gnav .gsug__empty,
.gsug__empty {
	margin: 0;
	padding: 14px 12px;
	font-size: var( --fs-14, 0.875rem );
	color: var( --gerbs-ink-70, #5c5c5c );
	text-align: center;
}

/*
 * T19 -- the empty state is a dead end, and a dead end is where a shopper leaves.
 * "No products match" on its own is a closed door; this is the door out. Sized as
 * a real tap target rather than an inline link, because on a phone it is the only
 * thing in the panel worth touching.
 */
.gnav .gsug__browse,
.gsug__browse {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 44px;
	padding: 0 4px;
	color: var( --gerbs-blue, #2F5EE6 );
	font-weight: var( --fw-medium, 500 );
	text-decoration: underline;
}

/* Loading ----------------------------------------------------------------- */

/*
 * T20 -- the search icon becomes a spinner, but only after 400ms (the delay lives
 * in the JS). A spinner on every keystroke would advertise latency that is not
 * there: a transient hit answers in single-digit milliseconds. Rows already on
 * screen stay put underneath, because stale-until-replaced is what a shopper
 * mid-read wants; a panel that blanks on every keystroke is unreadable.
 *
 * The listbox also carries aria-busy for the whole fetch, so assistive tech knows
 * regardless of whether the visual spinner ever appears.
 */
@media ( prefers-reduced-motion: no-preference ) {
	.gsug-loading > .gnav-i {
		visibility: hidden;
	}

	.gsug-loading::after {
		content: '';
		position: absolute;
		left: 14px;
		top: 50%;
		margin-top: -8px;
		width: 16px;
		height: 16px;
		box-sizing: border-box;
		border: 2px solid currentColor;
		border-right-color: transparent;
		border-radius: 50%;
		/* --gnav-muted is header-global.css's alias for --gerbs-ink-70; the
		   fallback is that token's literal, not a third grey. */
		color: var( --gnav-muted, #5c5c5c );
		opacity: .9;
		pointer-events: none;
		animation: gsug-spin 600ms linear infinite;
	}

	@keyframes gsug-spin {
		to {
			transform: rotate( 360deg );
		}
	}
}

/* Mobile ------------------------------------------------------------------ */

@media ( max-width: 980px ) {
	.gsug {
		/* The mobile bar is sticky and short; a tall panel would run off-screen
		   under the promo strip. */
		max-height: min( 60vh, 420px );
	}

	.gsug__img {
		width: 44px;
		height: 44px;
	}

	/* Mirrors .gnav-msearch .gnav-i in header-global.css, which shifts the icon by
	   the bar's own horizontal padding. The spinner replaces that icon, so it has
	   to move with it or it lands outside the field. */
	@media ( prefers-reduced-motion: no-preference ) {
		.gnav-msearch.gsug-loading::after {
			left: calc( var( --space-4, 16px ) + 14px );
		}
	}
}

@media ( prefers-reduced-motion: no-preference ) {
	.gsug__row,
	.gsug__all {
		transition: background-color 120ms ease;
	}
}
