/**
 * AI Sales Assistant — storefront widget.
 *
 * Every class is namespaced `asa-widget__`. Nothing here styles a bare element
 * selector, because this stylesheet lands on somebody else's theme and a rule
 * on `button` or `p` would reach across the whole storefront.
 *
 * Direction is handled with CSS logical properties — padding-inline,
 * margin-inline, border-start-start-radius — so a Hebrew or Arabic shop gets a
 * correctly mirrored widget from the same file. There is no separate RTL
 * stylesheet and no `direction` is forced anywhere: the panel inherits the
 * document's, which is what makes shopper text read correctly in either
 * language.
 *
 * THE ONE DELIBERATE EXCEPTION IS THE SIDE THE WIDGET SITS ON. Placement uses
 * physical `left` / `right`, under .asa-widget--left and .asa-widget--right,
 * and nothing else in this file does. Until 0.12.0 placement was
 * inset-inline-end, which put the widget on the right in an LTR shop and on the
 * left in an RTL one. From 0.12.0 the side is a setting, and a setting that
 * reversed itself under RTL would be a broken setting: a shop owner who picks
 * "bottom right" means the right, in Hebrew as much as in English. Text inside
 * the panel still mirrors normally — only the anchor is physical.
 *
 * Every tunable a shop owner can reach is a CSS custom property with a
 * fallback, so an unstyled root, a stripped style attribute or a shop that
 * never opened the Appearance screen all still render correctly.
 *
 * ===========================================================================
 * 0.14.0 — THE FIGMA PASS
 * ===========================================================================
 *
 * The visual language below is taken from the `AI Chatbot` Figma document,
 * decoded frame by frame and written up in docs/FIGMA_DESIGN_SYSTEM.md. The
 * five things that carry that design, and that a later edit must not casually
 * undo, are:
 *
 *   1. TONE, NOT LINES. The panel ground is a soft off-white and the things
 *      on it — bubbles, cards, the composer — are white surfaces lifted by a
 *      hairline ring and a one-pixel shadow. The Figma has almost no borders
 *      and no dividing rules at all; separation comes from surface, not from
 *      strokes. That is why the header and the composer carry no border.
 *
 *   2. LAYERED SOFT SHADOWS. Every elevation in the file is three to six
 *      near-transparent layers, never one dark blur.
 *
 *   3. A GRADIENT ACCENT. User bubbles, the launcher, the send control and
 *      the card CTA are a two-stop gradient rather than a flat fill. The first
 *      stop is ALWAYS the merchant's primary colour: --asa-accent-2 is mixed
 *      from it, so a shop that picked orange gets an orange gradient and never
 *      the file's violet.
 *
 *   4. UNIFORM BUBBLE RADII. No tail, no tightened corner. The Figma's bubbles
 *      are evenly rounded capsules, which is most of what stops the widget
 *      reading as a support-chat plugin.
 *
 *   5. FULL-WIDTH PROMPT ROWS. Suggested openers are stacked rows, not wrapped
 *      pills — the shape the file draws, and the one that survives a long
 *      Hebrew sentence on a 320px screen.
 *
 * INTERNAL TOKENS VS MERCHANT SETTINGS. The --asa-space-*, --asa-surface*,
 * --asa-border*, --asa-shadow*, --asa-radius-* and --asa-text* properties below
 * are an internal design system: they exist so spacing and colour are decided
 * once instead of forty times, and they are deliberately NOT exposed in the
 * Appearance screen. The merchant-facing values — position, offsets, launcher
 * size, primary colour, icon colour, panel width and height, radius — remain
 * exactly the eight --asa-* properties ASA_Appearance renders, and those still
 * outrank everything here.
 *
 * Layering: z-index 999999. High enough to sit above ordinary theme chrome and
 * sticky headers, deliberately far below the 2147483647 that cookie banners and
 * support widgets fight over — a shop owner who needs the assistant underneath
 * something else can still win with a normal value.
 *
 * @package AI_Sales_Assistant
 */

.asa-widget {
	/*
	 * Spacing scale. Five steps, used everywhere, so vertical rhythm is a
	 * decision made once rather than a pile of one-off pixel values. The
	 * Figma is airier than 0.13.0 was, which is what --asa-space-xl is for.
	 */
	--asa-space-xs: 4px;
	--asa-space-sm: 8px;
	--asa-space-md: 12px;
	--asa-space-lg: 16px;
	--asa-space-xl: 20px;

	/*
	 * Surfaces.
	 *
	 * --asa-surface-soft is the panel ground, and --asa-surface is what sits
	 * ON it. The Figma achieves this with 80%-opaque white over a blurred
	 * backdrop; a storefront widget cannot, because whatever is behind it is
	 * somebody else's page and backdrop-filter over a scrolling list is a
	 * measurable cost on iOS. Two opaque tones a few percent apart give the
	 * same reading at none of the risk.
	 */
	--asa-surface: #ffffff;
	--asa-surface-soft: #f7f7fb;
	--asa-surface-muted: #ececf3;
	--asa-surface-sunken: #fbfbfd;

	/* Restrained by design: a hairline, never a rule. */
	--asa-border: #e9e9f1;
	--asa-border-soft: #f1f1f7;

	/*
	 * Ink. The Figma's typography is violet-grey rather than black, and that
	 * hue is most of its character — but its exact values (#70709F body,
	 * #82829E placeholder) measure 4.6:1 and 3.7:1 on white, and the second of
	 * those fails WCAG AA outright. Both are darkened here along the same hue
	 * so the character survives and the contrast is not borderline:
	 * --asa-text-body is 8.5:1 and --asa-text-muted is 4.9:1 on white.
	 */
	--asa-text: #14151a;
	--asa-text-body: #4a4a68;
	--asa-text-muted: #6e6e8c;

	/*
	 * Elevation. Each of these is layered, and the first layer of the card
	 * shadows is a zero-blur spread — a hairline ring drawn in shadow rather
	 * than a border, which is how the Figma's cards separate from their ground
	 * without a visible stroke.
	 */
	--asa-shadow-soft:
		0 0 0 1px rgba( 16, 18, 32, 0.04 ),
		0 1px 2px rgba( 16, 18, 32, 0.05 );
	--asa-shadow-card:
		0 0 0 1px rgba( 16, 18, 32, 0.05 ),
		0 1px 2px rgba( 16, 18, 32, 0.06 ),
		0 4px 10px rgba( 16, 18, 32, 0.04 );
	--asa-shadow-card-hover:
		0 0 0 1px rgba( 16, 18, 32, 0.07 ),
		0 2px 4px rgba( 16, 18, 32, 0.06 ),
		0 10px 24px rgba( 16, 18, 32, 0.08 );
	--asa-shadow:
		0 0 0 1px rgba( 16, 18, 32, 0.04 ),
		0 2px 4px rgba( 16, 18, 32, 0.04 ),
		0 12px 24px rgba( 16, 18, 32, 0.06 ),
		0 32px 64px rgba( 16, 18, 32, 0.1 );

	/* A one-pixel light along the top edge. The Figma puts one on every
	 * gradient surface; it is what stops a saturated fill reading as flat. */
	--asa-sheen: inset 0 1px 0 rgba( 255, 255, 255, 0.22 );

	--asa-danger-surface: #fff8f8;
	--asa-danger-border: #f2dcdc;
	--asa-danger-ink: #98292b;

	/*
	 * THE ACCENT, AND WHY IT IS STILL THE MERCHANT'S.
	 *
	 * The Figma's accent is a blue-to-violet gradient. Reproducing that as a
	 * literal pair of hex values would have thrown away the primary colour
	 * setting, so only the SHAPE of it is taken: stop one is the merchant's
	 * colour, and stop two is that colour carried part of the way towards the
	 * file's terminal violet. A shop on the default #1e40af gets very nearly
	 * the file's own gradient; a shop on orange gets orange into warm rose; a
	 * shop on green gets green into teal. Nobody gets a violet they did not
	 * choose.
	 *
	 * Every use site also states a flat `background: var( --asa-accent )` before
	 * the gradient, so a surface is never left unpainted while the gradient is
	 * resolving or if it fails to.
	 */
	--asa-accent: var( --asa-primary-color, #1e40af );
	--asa-accent-ink: var( --asa-launcher-icon-color, #ffffff );
	--asa-accent-far: #a16bf9;

	/*
	 * EVERY ACCENT TOKEN IS DECLARED TWICE, and this half is the one without
	 * color-mix().
	 *
	 * A custom property whose value fails to resolve does not fall back to the
	 * previous declaration — the property that USES it becomes invalid at
	 * computed-value time and resolves to `unset`, which for box-shadow and
	 * background-image means "none". So a single color-mix() in these tokens
	 * would not soften the design on a browser that lacks it; it would delete
	 * the launcher's shadow and the composer's focus ring outright. The values
	 * below are the plain ones every browser can compute: the gradient
	 * collapses to the merchant's flat colour and the glows become neutral
	 * grey. The @supports block after this rule upgrades them in place.
	 */
	--asa-accent-2: var( --asa-accent );
	--asa-accent-gradient: linear-gradient( 100deg, var( --asa-accent ) 0%, var( --asa-accent-2 ) 100% );
	--asa-accent-ring: rgba( 16, 18, 32, 0.14 );
	--asa-shadow-accent:
		0 1px 2px rgba( 16, 18, 32, 0.14 ),
		0 3px 8px rgba( 16, 18, 32, 0.1 ),
		0 10px 22px rgba( 16, 18, 32, 0.08 );
	--asa-shadow-launcher:
		0 2px 6px rgba( 16, 18, 32, 0.12 ),
		0 8px 20px rgba( 16, 18, 32, 0.16 ),
		0 16px 36px rgba( 16, 18, 32, 0.1 );
	--asa-shadow-launcher-hover:
		0 3px 8px rgba( 16, 18, 32, 0.14 ),
		0 12px 28px rgba( 16, 18, 32, 0.2 ),
		0 22px 48px rgba( 16, 18, 32, 0.12 );

	/*
	 * Radii, as a family rather than a list. The Figma runs 20 for the panel,
	 * 24 for the assistant bubble, 14 for cards and the input, 13 for the user
	 * bubble and 10.6 for a prompt row; those are measured on frames two to
	 * three times the size of this panel, so the bubble figures are scaled
	 * down and the rest are taken as drawn.
	 */
	--asa-radius: var( --asa-widget-radius, 20px );
	--asa-radius-bubble: 18px;
	--asa-radius-bubble-user: 16px;
	--asa-radius-card: 14px;
	--asa-radius-field: 18px;
	--asa-radius-chip: 12px;
	--asa-radius-thumb: 10px;
	--asa-radius-pill: 999px;

	--asa-motion: 180ms;
	--asa-ease: cubic-bezier( 0.2, 0, 0.2, 1 );

	/*
	 * The visible viewport, in pixels, while the panel is open on a phone.
	 *
	 * widget.js writes this from window.visualViewport so the panel shrinks to
	 * the space the software keyboard leaves. It is only ever READ inside the
	 * phone media query; on desktop it is inert. The fallback is 100dvh, so a
	 * browser that has visualViewport but never fires a resize, or a page where
	 * the script never ran, still gets correct full-height behaviour.
	 */

	/*
	 * Edge distances fold in the safe-area insets rather than replacing them.
	 * On an iPhone in landscape the notch eats into the side the widget may be
	 * anchored to, and on every iPhone the home indicator sits in the bottom
	 * strip; adding the inset keeps a 0px offset legible instead of putting the
	 * launcher under the hardware.
	 */
	--asa-edge-inline: calc( var( --asa-offset-inline, 20px ) + env( safe-area-inset-left, 0px ) );
	--asa-edge-inline-end: calc( var( --asa-offset-inline, 20px ) + env( safe-area-inset-right, 0px ) );
	--asa-edge-bottom: calc( var( --asa-offset-bottom, 20px ) + env( safe-area-inset-bottom, 0px ) );

	position: fixed;
	bottom: var( --asa-edge-bottom );
	z-index: 999999;
	/*
	 * The shop's own typeface, never one this plugin loads. A chat window in a
	 * different font than the storefront reads as a third-party bolt-on, which
	 * is exactly what it must not look like. The Figma is set in Inter; what
	 * carries over is its SCALE — 15/22 body, 18/26 titles — not its face.
	 */
	font-family: inherit;
	font-size: 15px;
	line-height: 1.5;
	color: var( --asa-text );
}

/*
 * The upgrade. Everything above still holds on a browser without color-mix();
 * everything here is the Figma's actual colour behaviour — a gradient that
 * leans towards the file's violet and glows tinted with the merchant's own
 * colour rather than neutral grey.
 *
 * The Figma's coloured glow is six layers; this is three. The three it drops
 * are 26px, 52px and 122px blurs at up to 39px offsets, sized for a hero shot
 * on a 1700px canvas — inside a 380px panel they are a coloured haze rather
 * than an edge.
 */
@supports ( color: color-mix( in srgb, red 50%, blue ) ) {
	.asa-widget {
		--asa-accent-2: color-mix( in srgb, var( --asa-accent ) 55%, var( --asa-accent-far ) );
		--asa-accent-ring: color-mix( in srgb, var( --asa-accent ) 14%, transparent );
		--asa-shadow-accent:
			0 1px 2px color-mix( in srgb, var( --asa-accent ) 30%, transparent ),
			0 3px 8px color-mix( in srgb, var( --asa-accent ) 16%, transparent ),
			0 10px 22px color-mix( in srgb, var( --asa-accent ) 12%, transparent );
		--asa-shadow-launcher:
			0 2px 6px rgba( 16, 18, 32, 0.12 ),
			0 8px 20px color-mix( in srgb, var( --asa-accent ) 26%, transparent ),
			0 16px 36px rgba( 16, 18, 32, 0.1 );
		--asa-shadow-launcher-hover:
			0 3px 8px rgba( 16, 18, 32, 0.14 ),
			0 12px 28px color-mix( in srgb, var( --asa-accent ) 32%, transparent ),
			0 22px 48px rgba( 16, 18, 32, 0.12 );
	}
}

/*
 * Border-box for everything inside the widget.
 *
 * The hard invariant is that no element may push the panel wider than the
 * viewport. Half of the ways that happens are a padding added to a 100% width
 * in a theme that never set box-sizing, so it is set here rather than hoped
 * for. Scoped to the widget subtree; it changes nothing else on the page.
 */
.asa-widget,
.asa-widget *,
.asa-widget *::before,
.asa-widget *::after {
	box-sizing: border-box;
}

/*
 * The chosen side, stated physically on purpose — see the file header. The
 * `auto` on the opposite side matters: without it a theme rule setting the
 * other edge would stretch the widget across the viewport.
 */
.asa-widget--right {
	right: var( --asa-edge-inline-end );
	left: auto;
}

.asa-widget--left {
	left: var( --asa-edge-inline );
	right: auto;
}

/*
 * Cart and checkout keep the assistant, but mobile checkouts put a sticky
 * "Place order" bar in exactly this corner. Lifting the launcher clear of it is
 * the difference between a helpful widget and one that costs the shop a sale.
 * Additive, so a shop that raised the bottom offset keeps that clearance too.
 */
.woocommerce-checkout .asa-widget,
.woocommerce-cart .asa-widget {
	bottom: calc( var( --asa-edge-bottom ) + 68px );
}

/* --- Launcher ---------------------------------------------------------- */

/*
 * The Figma's identity orb: a gradient sphere with a light along its top edge
 * and a soft coloured shadow under it, not a flat circle with a hard drop.
 */
.asa-widget__launcher {
	display: flex;
	align-items: center;
	justify-content: center;
	/*
	 * 56px comfortably clears the ~44px minimum touch target, and 44px is the
	 * floor the setting itself clamps to, so no configured size can shrink the
	 * launcher below an accessible target.
	 */
	inline-size: var( --asa-launcher-size, 56px );
	block-size: var( --asa-launcher-size, 56px );
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var( --asa-accent );
	background-image: var( --asa-accent-gradient );
	color: var( --asa-accent-ink );
	cursor: pointer;
	box-shadow: var( --asa-shadow-launcher ), var( --asa-sheen );
	transition:
		transform var( --asa-motion ) var( --asa-ease ),
		box-shadow var( --asa-motion ) var( --asa-ease );
}

.asa-widget__launcher:hover {
	transform: translateY( -2px );
	box-shadow: var( --asa-shadow-launcher-hover ), var( --asa-sheen );
}

/* Tap feedback: the press is felt, not just seen. */
.asa-widget__launcher:active {
	transform: scale( 0.95 );
	box-shadow: var( --asa-shadow-launcher ), var( --asa-sheen );
}

.asa-widget__launcher:focus-visible,
.asa-widget__close:focus-visible,
.asa-widget__send:focus-visible,
.asa-widget__retry:focus-visible,
.asa-widget__chip:focus-visible,
.asa-widget__card-cta:focus-visible,
.asa-widget__messages:focus-visible {
	outline: 2px solid var( --asa-accent );
	outline-offset: 2px;
}

.asa-widget__icon {
	inline-size: 24px;
	block-size: 24px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.8;
	stroke-linecap: round;
	stroke-linejoin: round;
	flex: 0 0 auto;
}

.asa-widget__launcher .asa-widget__icon {
	fill: currentColor;
	stroke: none;
	inline-size: 26px;
	block-size: 26px;
}

/*
 * Open: the launcher steps back rather than vanishing, so the panel has
 * something to have come from.
 */
.asa-widget--open .asa-widget__launcher {
	opacity: 0;
	pointer-events: none;
	transform: scale( 0.8 );
}

.asa-widget__icon--fallback {
	display: none;
}

.asa-widget__launcher--fallback .asa-widget__launcher-image {
	display: none;
}

.asa-widget__launcher--fallback .asa-widget__icon--fallback {
	display: block;
}

/*
 * A custom launcher image sits INSIDE the orb, at 60% and contained.
 *
 * Filling the button edge to edge would have been closer to the Figma, whose
 * orb is a full-bleed gradient sphere — and it would have cropped every logo a
 * shop uploads that is not square, which is most of them. `contain` at 60% is
 * the 0.11.7 behaviour and it is kept deliberately: the gradient becomes the
 * sphere the mark sits on, which is what the Figma's orb actually is anyway.
 * `pointer-events: none` keeps the click on the button rather than the picture.
 */
.asa-widget__launcher-image {
	display: block;
	inline-size: 60%;
	block-size: 60%;
	min-inline-size: 0;
	min-block-size: 0;
	object-fit: contain;
	/* A transparent PNG on a dark launcher should not gain a white box. */
	background: none;
	border-radius: 4px;
	pointer-events: none;
}

/* --- Panel ------------------------------------------------------------- */

/*
 * A floating card, not a docked window: soft ground, hairline edge, and an
 * elevation built from four near-transparent layers rather than one dark blur.
 */
.asa-widget__panel {
	display: flex;
	flex-direction: column;
	inline-size: var( --asa-widget-width, 380px );
	/*
	 * The viewport cap outranks the configured size, always. The width setting
	 * tops out at 520px and the height at 760px, but a 760px panel on a short
	 * laptop would still run off the screen and take the composer with it, so
	 * the max-* pair stays in charge and the setting only ever asks.
	 */
	max-inline-size: calc( 100vw - 40px );
	block-size: var( --asa-widget-height, 560px );
	max-block-size: calc( 100vh - 40px );
	max-block-size: calc( 100dvh - 40px );
	background: var( --asa-surface-soft );
	border: 0;
	border-radius: var( --asa-radius );
	box-shadow: var( --asa-shadow );
	overflow: hidden;
	animation: asa-panel-in 200ms var( --asa-ease ) both;
}

.asa-widget__panel[hidden] {
	display: none;
}

@keyframes asa-panel-in {
	from {
		opacity: 0;
		transform: translateY( 10px ) scale( 0.99 );
	}

	to {
		opacity: 1;
		transform: none;
	}
}

/* --- Header ------------------------------------------------------------- */

/*
 * Compact by design, and deliberately without a rule under it. The header is
 * chrome, not content: it identifies the assistant and offers the way out, and
 * every pixel it takes is a pixel of conversation a phone does not show. It
 * shares the panel's ground, which is what makes it read as part of the card
 * instead of a toolbar bolted to the top of one.
 */
.asa-widget__header {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: var( --asa-space-sm );
	padding-block: var( --asa-space-md );
	padding-inline: var( --asa-space-lg );
	background: transparent;
}

.asa-widget__identity {
	display: flex;
	align-items: center;
	gap: 10px;
	/* Without this a long assistant name pushes the close button off screen. */
	min-inline-size: 0;
	flex: 1 1 auto;
}

.asa-widget__titles {
	min-inline-size: 0;
	display: flex;
	flex-direction: column;
	gap: 1px;
}

.asa-widget__title {
	margin: 0;
	font-family: inherit;
	font-size: 15px;
	font-weight: 600;
	line-height: 1.35;
	letter-spacing: -0.01em;
	color: var( --asa-text );
	/* One line, whatever the shop called its assistant. */
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.asa-widget__subtitle {
	margin: 0;
	font-size: 12px;
	line-height: 1.35;
	color: var( --asa-text-muted );
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.asa-widget__avatar {
	display: block;
	inline-size: 34px;
	block-size: 34px;
	object-fit: cover;
	border-radius: 50%;
	background: var( --asa-surface );
	box-shadow: var( --asa-shadow-soft );
	flex: 0 0 auto;
}

/*
 * With no uploaded image the avatar is the Figma's orb — the same gradient,
 * sheen and soft shadow as the launcher, at header size.
 */
.asa-widget__avatar--default {
	padding: 7px;
	background: var( --asa-accent );
	background-image: var( --asa-accent-gradient );
	color: var( --asa-accent-ink );
	fill: currentColor;
	stroke: none;
	box-shadow:
		var( --asa-sheen ),
		0 2px 6px rgba( 16, 18, 32, 0.18 );
}

.asa-widget__close {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	/* A full 44px target, kept reachable by a thumb at the top corner. */
	inline-size: 44px;
	block-size: 44px;
	margin-inline-end: -10px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: var( --asa-text-muted );
	cursor: pointer;
	transition:
		background-color var( --asa-motion ) var( --asa-ease ),
		color var( --asa-motion ) var( --asa-ease );
}

.asa-widget__close:hover {
	background: var( --asa-surface-muted );
	color: var( --asa-text );
}

.asa-widget__close:active {
	background: var( --asa-surface-muted );
	transform: scale( 0.92 );
}

.asa-widget__close .asa-widget__icon {
	inline-size: 19px;
	block-size: 19px;
	stroke-width: 1.7;
}

/* --- Messages ---------------------------------------------------------- */

/*
 * THE SCROLL REGION, AND THE ONE DECLARATION THAT MAKES THE LAYOUT WORK.
 *
 * `min-block-size: 0` is not decoration. A flex item's automatic minimum size
 * is its content size, so without this the message list refuses to shrink below
 * the height of the whole conversation: it grows, the composer is pushed past
 * the bottom of the panel, and `overflow: hidden` on the panel clips the Send
 * button off the screen. That is the mobile bug 0.13.0 exists to fix, and it is
 * one line.
 */
.asa-widget__messages {
	flex: 1 1 auto;
	min-block-size: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	-webkit-overflow-scrolling: touch;
	padding-block: var( --asa-space-xs ) var( --asa-space-md );
	padding-inline: var( --asa-space-lg );
	display: flex;
	flex-direction: column;
	/* The Figma is airy. 14px between turns is its rhythm, not 10px. */
	gap: 14px;
	background: transparent;
	/*
	 * A hairline scrollbar instead of the platform's.
	 *
	 * On Windows and on Linux the default bar is a 15px light-grey channel
	 * pinned to the panel edge, and once the panel became a soft floating card
	 * it was by some distance the heaviest thing on it. Firefox takes the
	 * standard properties, Chrome and Safari take the -webkit- pseudo-elements,
	 * and a browser that honours neither simply keeps its own bar.
	 */
	scrollbar-width: thin;
	scrollbar-color: rgba( 16, 18, 32, 0.16 ) transparent;
}

.asa-widget__messages::-webkit-scrollbar {
	inline-size: 6px;
}

.asa-widget__messages::-webkit-scrollbar-track {
	background: transparent;
}

.asa-widget__messages::-webkit-scrollbar-thumb {
	border-radius: var( --asa-radius-pill );
	background: rgba( 16, 18, 32, 0.16 );
}

.asa-widget__messages::-webkit-scrollbar-thumb:hover {
	background: rgba( 16, 18, 32, 0.28 );
}

/*
 * ===========================================================================
 * SPEAKER SIDE IS PHYSICAL, AND THIS IS THE ONE PLACE IN THE PANEL THAT IS
 * DELIBERATELY NOT MIRRORED.
 * ===========================================================================
 *
 * The shopper's own messages sit on the RIGHT and the assistant's on the LEFT,
 * in a Hebrew shop exactly as in an English one.
 *
 * Until 0.14.0 the row used `justify-content: flex-end`, which is direction
 * relative: under dir="rtl" flex-end IS the left edge, so a Hebrew shopper's
 * own messages appeared on the left and the assistant's on the right — the
 * whole conversation reflected. That is what WhatsApp and Telegram do, and it
 * is deliberately not what this does: the speaker's position is a fixed
 * property of the interface, not of the language being typed into it.
 *
 * `margin-left: auto` / `margin-right: auto` on the BUBBLE is what pins it,
 * and the margins are physical on purpose — the same exception the launcher's
 * anchor makes, for the same reason. A value that reversed itself under RTL
 * would be the bug here, not the feature. There is no logical property that
 * means "the right edge, always"; `justify-content: right` does, but Firefox
 * only learned it in 125 and this has to hold on whatever a shopper is running.
 *
 * The bubble's own TEXT direction is a separate question with a separate
 * answer — see .asa-widget__bubble below. The side never moves; only the text
 * inside it adapts.
 */
.asa-widget__message {
	display: flex;
	animation: asa-bubble-in 160ms var( --asa-ease ) both;
}

.asa-widget__message--user .asa-widget__bubble {
	margin-left: auto;
	margin-right: 0;
}

.asa-widget__message--assistant .asa-widget__bubble {
	margin-right: auto;
	margin-left: 0;
}

/*
 * Message grouping. Two replies in a row from the same speaker are one turn as
 * far as a reader is concerned, so they sit closer together than a change of
 * speaker does.
 */
.asa-widget__message--assistant + .asa-widget__message--assistant,
.asa-widget__message--user + .asa-widget__message--user {
	margin-block-start: -8px;
}

@keyframes asa-bubble-in {
	from {
		opacity: 0;
		transform: translateY( 4px );
	}

	to {
		opacity: 1;
		transform: none;
	}
}

/*
 * EVENLY ROUNDED, WITH NO TAIL.
 *
 * 0.13.0 tightened one corner of each bubble on the speaker's side, the way a
 * messaging app does. The Figma does not: both of its bubbles are uniform
 * capsules, and dropping the notch is most of what stops this reading as a
 * support widget. The speaker is told apart by colour, weight and side, which
 * is enough and is what the file relies on.
 *
 * TEXT DIRECTION INSIDE THE BUBBLE IS THE CONTENT'S, NOT THE SHOP'S.
 *
 * widget.js puts dir="auto" on every bubble, so each message takes its
 * direction from its own first strong character: "אני רוצה AL-5213 עד 300 ₪"
 * reads as Hebrew with the model number embedded correctly, and an English
 * question typed into a Hebrew shop reads as English rather than as Hebrew
 * punctuation applied to Latin words.
 *
 * `text-align: start` is stated rather than left to inherit, because this
 * stylesheet lands on somebody else's theme and a theme that sets
 * `text-align: right` on a wrapper would otherwise drag every bubble with it.
 * Start resolves against the bubble's OWN resolved direction, which is exactly
 * what dir="auto" just decided — that is the whole point of stating it.
 *
 * This changes TEXT only. It can never move a bubble to the other side: the
 * side comes from the speaker class above, and a product code in an otherwise
 * Hebrew sentence must not make a message jump across the panel.
 */
.asa-widget__bubble {
	max-inline-size: 84%;
	min-inline-size: 0;
	padding-block: 11px;
	padding-inline: 15px;
	text-align: start;
	border-radius: var( --asa-radius-bubble );
	background: var( --asa-surface );
	box-shadow: var( --asa-shadow-soft );
	color: var( --asa-text-body );
	font-size: 14.5px;
	line-height: 1.6;
	/*
	 * Line breaks in a reply survive without ever building markup: pre-wrap
	 * renders them from the text node itself, so nothing has to translate "\n"
	 * into a <br> and reintroduce an HTML path.
	 */
	white-space: pre-wrap;
	overflow-wrap: anywhere;
}

/* The side is pinned above; these two rules only paint. */
.asa-widget__message--user .asa-widget__bubble {
	background: var( --asa-accent );
	background-image: var( --asa-accent-gradient );
	border-radius: var( --asa-radius-bubble-user );
	color: var( --asa-accent-ink );
	font-weight: 500;
	box-shadow: var( --asa-shadow-accent ), var( --asa-sheen );
}

.asa-widget__message--assistant .asa-widget__bubble {
	color: var( --asa-text-body );
}

/* --- Typing indicator ---------------------------------------------------- */

.asa-widget__bubble--typing {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	padding-block: 14px;
	min-block-size: 0;
}

.asa-widget__dot {
	inline-size: 6px;
	block-size: 6px;
	border-radius: 50%;
	background: var( --asa-accent );
	opacity: 0.45;
	animation: asa-typing 1.3s var( --asa-ease ) infinite;
}

.asa-widget__dot--2 {
	animation-delay: 0.16s;
}

.asa-widget__dot--3 {
	animation-delay: 0.32s;
}

@keyframes asa-typing {
	0%,
	60%,
	100% {
		opacity: 0.25;
		transform: translateY( 0 );
	}

	30% {
		opacity: 0.9;
		transform: translateY( -3px );
	}
}

/* --- Welcome state ------------------------------------------------------- */

/*
 * `margin-block-start: auto` is what keeps a one-line welcome from floating in
 * the middle of a tall empty panel: as the only child of a column flex box it
 * absorbs the free space and settles the greeting just above the composer,
 * exactly where a conversation starts. The moment real messages arrive and the
 * content overflows, the free space is gone and the margin resolves to zero, so
 * scrolling behaves normally.
 */
.asa-widget__welcome {
	margin-block-start: auto;
	display: flex;
	flex-direction: column;
	gap: var( --asa-space-md );
}

/*
 * FULL-WIDTH ROWS, NOT WRAPPED PILLS.
 *
 * The Figma stacks its suggested prompts as full-width rows, and that is also
 * the only shape that survives translation: "מה הכי פופולרי אצלכם השבוע?" as an
 * inline pill either wraps into a lumpy two-line capsule or forces a horizontal
 * overflow on a 320px screen. As a row it simply wraps inside its own box.
 */
.asa-widget__chips {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: var( --asa-space-sm );
}

.asa-widget__chip {
	max-inline-size: 100%;
	min-block-size: 40px;
	padding-block: 9px;
	padding-inline: 14px;
	border: 0;
	border-radius: var( --asa-radius-chip );
	background: var( --asa-surface );
	box-shadow: var( --asa-shadow-soft );
	color: var( --asa-text-body );
	font: inherit;
	font-size: 13.5px;
	line-height: 1.45;
	text-align: start;
	cursor: pointer;
	overflow-wrap: anywhere;
	transition:
		box-shadow var( --asa-motion ) var( --asa-ease ),
		color var( --asa-motion ) var( --asa-ease ),
		transform var( --asa-motion ) var( --asa-ease );
}

.asa-widget__chip:hover {
	box-shadow: var( --asa-shadow-card-hover );
	color: var( --asa-text );
	transform: translateY( -1px );
}

/*
 * PRESS FEEDBACK, BECAUSE A PHONE HAS NO HOVER.
 *
 * Every tappable surface in the panel had a :hover state and nothing else, so
 * on the device that matters most a shopper tapped an opener, a card or a
 * retry and got no acknowledgement at all until the network answered. The
 * launcher and the send control already had this; these are the four that
 * did not.
 */
.asa-widget__chip:active {
	transform: scale( 0.985 );
	box-shadow: var( --asa-shadow-soft );
}

/* --- Notices, errors and retry ------------------------------------------- */

/*
 * An error is a message in the conversation, not a system alarm bolted to the
 * side of it. Same rhythm, same rounding, same card elevation as everything
 * else on the ground — a calm tinted surface rather than a red box, with the
 * way out inside the same surface as the explanation.
 */
.asa-widget__notice {
	margin: 0;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 10px;
	padding-block: 12px;
	padding-inline: 14px;
	border: 1px solid var( --asa-danger-border );
	border-radius: var( --asa-radius-card );
	background: var( --asa-danger-surface );
	color: var( --asa-danger-ink );
	font-size: 13.5px;
	line-height: 1.55;
	overflow-wrap: anywhere;
	animation: asa-bubble-in 160ms var( --asa-ease ) both;
}

.asa-widget__notice-text {
	margin: 0;
}

.asa-widget__retry {
	align-self: flex-start;
	min-block-size: 36px;
	padding-block: 7px;
	padding-inline: var( --asa-space-lg );
	border: 0;
	border-radius: var( --asa-radius-pill );
	background: var( --asa-surface );
	box-shadow: var( --asa-shadow-soft );
	color: var( --asa-danger-ink );
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	cursor: pointer;
	transition:
		box-shadow var( --asa-motion ) var( --asa-ease ),
		transform var( --asa-motion ) var( --asa-ease );
}

.asa-widget__retry:hover {
	box-shadow: var( --asa-shadow-card-hover );
	transform: translateY( -1px );
}

.asa-widget__retry:active {
	transform: scale( 0.97 );
	box-shadow: var( --asa-shadow-soft );
}

/* --- Recommendation cards ---------------------------------------------- */

/*
 * The Figma has no WooCommerce card, so this is its answer card carried over:
 * the same white surface, the same 14px radius, the same hairline-ring-plus-
 * soft-lift shadow, a square thumbnail on a faintly tinted ground, and a text
 * column beside it. Nothing was invented; only the fields changed.
 *
 * Cards stay visually subordinate to the conversation — no accent border, no
 * heavier elevation than a bubble carries.
 */
.asa-widget__card {
	display: flex;
	gap: var( --asa-space-md );
	padding: var( --asa-space-md );
	border: 0;
	border-radius: var( --asa-radius-card );
	background: var( --asa-surface );
	box-shadow: var( --asa-shadow-card );
	transition:
		box-shadow var( --asa-motion ) var( --asa-ease ),
		transform var( --asa-motion ) var( --asa-ease );
}

/*
 * A run of recommendations is one answer, so the cards sit tighter to each
 * other than they do to the reply above them. Four compact cards read as a
 * short list rather than a wall.
 */
.asa-widget__card + .asa-widget__card {
	margin-block-start: -6px;
}

.asa-widget__card:hover {
	box-shadow: var( --asa-shadow-card-hover );
	transform: translateY( -1px );
}

.asa-widget__card:active {
	transform: scale( 0.995 );
}

.asa-widget__card:focus-within {
	box-shadow:
		0 0 0 1px var( --asa-accent ),
		var( --asa-shadow-card-hover );
}

.asa-widget__card-image {
	inline-size: 72px;
	block-size: 72px;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: var( --asa-radius-thumb );
	background: var( --asa-surface-sunken );
	flex: 0 0 auto;
}

.asa-widget__card-body {
	/* The one declaration that stops a long product name widening the panel. */
	min-inline-size: 0;
	flex: 1 1 auto;
	display: flex;
	flex-direction: column;
	gap: 3px;
}

.asa-widget__card-name {
	margin: 0;
	font-size: 14px;
	font-weight: 600;
	line-height: 1.4;
	letter-spacing: -0.01em;
	color: var( --asa-text );
	overflow-wrap: anywhere;
	/* Two lines, then an ellipsis. A ten-word SKU cannot own the card. */
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.asa-widget__card-price {
	margin: 0;
	font-size: 14px;
	font-weight: 700;
	/*
	 * Deliberately NOT the accent colour. A price is a fact, not an action, and
	 * when it wore the same blue as the CTA a run of three cards read as six
	 * competing things to click.
	 */
	color: var( --asa-text );
	/*
	 * ISOLATED, NOT PLAINTEXT — and the difference is visible in Hebrew.
	 *
	 * Both keep "₪189.00" together as one run instead of letting the currency
	 * mark drift to the far end of the line. But `plaintext` also takes the
	 * paragraph's DIRECTION from the first strong character, and a price has
	 * none: digits and ₪ are neutral, so the heuristic falls back to LTR and
	 * `text-align: start` then resolves to the LEFT — the price sat on the
	 * wrong edge of every card in a Hebrew shop while the name above it sat on
	 * the right. `isolate` keeps the element's inherited direction, so the run
	 * still cannot be reordered by its neighbours and the price lines up under
	 * the product name where a shopper is already looking.
	 */
	unicode-bidi: isolate;
}

.asa-widget__card-reason {
	margin: 0;
	font-size: 12.5px;
	line-height: 1.5;
	color: var( --asa-text-muted );
	overflow-wrap: anywhere;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

/*
 * The CTA carries the accent, but not the glow.
 *
 * With the full --asa-shadow-accent under it, three stacked cards read as
 * three heroes competing with the shopper's own message for the eye — the
 * opposite of "subordinate to the conversation". A flat gradient pill is still
 * unmistakably the thing to tap. The 40px floor is a tap target and is not
 * negotiable, so the card is made shorter by tightening the space above the
 * button rather than by shrinking the button.
 */
.asa-widget__card-cta {
	align-self: flex-start;
	margin-block-start: var( --asa-space-xs );
	min-block-size: 40px;
	display: inline-flex;
	align-items: center;
	padding-inline: var( --asa-space-md );
	border-radius: var( --asa-radius-pill );
	background: var( --asa-accent );
	background-image: var( --asa-accent-gradient );
	box-shadow: var( --asa-sheen );
	color: var( --asa-accent-ink );
	font-size: 13px;
	font-weight: 600;
	text-decoration: none;
	transition:
		transform var( --asa-motion ) var( --asa-ease ),
		box-shadow var( --asa-motion ) var( --asa-ease );
}

.asa-widget__card-cta:hover {
	transform: translateY( -1px );
	box-shadow: var( --asa-shadow-accent ), var( --asa-sheen );
	color: var( --asa-accent-ink );
	text-decoration: none;
}

.asa-widget__card-cta:active {
	transform: scale( 0.97 );
	color: var( --asa-accent-ink );
}

/* --- Card actions (0.15.0) ---------------------------------------------- */

/*
 * Two actions on one row, and they wrap rather than shrink.
 *
 * "הוסף לעגלה" beside "לצפייה במוצר" does not fit a 320px card in Hebrew, and a
 * flex row that squeezed them would give two buttons nobody can read. Wrapping
 * costs one line and keeps both labels whole. Logical properties throughout, so
 * the pair mirrors with the card.
 */
.asa-widget__card-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var( --asa-space-sm );
	margin-block-start: var( --asa-space-xs );
}

.asa-widget__card-actions .asa-widget__card-cta {
	margin-block-start: 0;
}

/*
 * The secondary action is the quiet one. "Choose options" sends a shopper to
 * the product page to pick a size; it is a real action but it is not the one
 * the card is selling, so it carries the accent as ink rather than as fill.
 */
.asa-widget__card-cta--ghost {
	background: transparent;
	background-image: none;
	box-shadow: inset 0 0 0 1px var( --asa-border );
	color: var( --asa-text-body );
}

.asa-widget__card-cta--ghost:hover {
	box-shadow: inset 0 0 0 1px var( --asa-text-muted );
	color: var( --asa-text );
}

/* A button, not a link: it has to look identical to the CTA beside it. */
.asa-widget__card-add {
	border: 0;
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	cursor: pointer;
}

.asa-widget__card-add[disabled] {
	opacity: 0.55;
	cursor: default;
	transform: none;
}

/*
 * Success is stated in the button's own words, so it does not depend on colour
 * alone — the label changes to "נוסף לעגלה ✓" and then to the cart link. The
 * green is confirmation for people who read colour, not the only signal.
 */
.asa-widget__card-add--done {
	background: #157f4d;
	background-image: none;
	box-shadow: none;
	opacity: 1;
}

.asa-widget__card-add--failed {
	background: var( --asa-danger-surface );
	background-image: none;
	box-shadow: inset 0 0 0 1px var( --asa-danger-border );
	color: var( --asa-danger-ink );
}

/* --- Coupon offer (0.15.0) ----------------------------------------------- */

/*
 * Same card family as everything else on the ground — surface, radius, ring —
 * with one departure: a hairline in the merchant's accent along the top edge,
 * because an offer is the one thing in the conversation that should catch the
 * eye. It is still quieter than the shopper's own message bubble.
 */
.asa-widget__coupon {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 10px;
	padding: var( --asa-space-md );
	border-radius: var( --asa-radius-card );
	background: var( --asa-surface );
	box-shadow:
		var( --asa-shadow-card ),
		inset 0 2px 0 var( --asa-accent );
	animation: asa-bubble-in 160ms var( --asa-ease ) both;
}

.asa-widget__coupon-intro {
	margin: 0;
	font-size: 13.5px;
	line-height: 1.5;
	color: var( --asa-text-body );
	text-align: start;
}

.asa-widget__coupon-row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var( --asa-space-sm );
}

/*
 * The code reads left-to-right in any shop — it is a token to copy, not a
 * sentence — so the element carries dir="ltr" and the monospace stack keeps a
 * 0 from an O. `user-select: all` makes one tap select the whole code on a
 * phone, which is how most people will use it.
 */
.asa-widget__coupon-code {
	padding-block: 5px;
	padding-inline: 10px;
	border-radius: var( --asa-radius-tight, 8px );
	background: var( --asa-surface-muted );
	color: var( --asa-text );
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 13.5px;
	font-weight: 700;
	letter-spacing: 0.04em;
	user-select: all;
	overflow-wrap: anywhere;
}

.asa-widget__coupon-value {
	font-size: 13.5px;
	font-weight: 600;
	color: var( --asa-text );
}

.asa-widget__coupon-apply {
	min-block-size: 40px;
	display: inline-flex;
	align-items: center;
	padding-inline: var( --asa-space-lg );
	border: 0;
	border-radius: var( --asa-radius-pill );
	background: var( --asa-accent );
	background-image: var( --asa-accent-gradient );
	box-shadow: var( --asa-sheen );
	color: var( --asa-accent-ink );
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	cursor: pointer;
	transition:
		transform var( --asa-motion ) var( --asa-ease ),
		box-shadow var( --asa-motion ) var( --asa-ease );
}

.asa-widget__coupon-apply:hover {
	transform: translateY( -1px );
	box-shadow: var( --asa-shadow-accent ), var( --asa-sheen );
}

.asa-widget__coupon-apply:active {
	transform: scale( 0.97 );
}

.asa-widget__coupon-apply--done {
	background: #157f4d;
	background-image: none;
	box-shadow: none;
	cursor: default;
	transform: none;
}

.asa-widget__coupon-apply--failed {
	background: var( --asa-danger-surface );
	background-image: none;
	box-shadow: inset 0 0 0 1px var( --asa-danger-border );
	color: var( --asa-danger-ink );
}

.asa-widget__coupon-apply:focus-visible {
	outline: 2px solid var( --asa-accent );
	outline-offset: 2px;
}

/* --- Challenge, status, composer --------------------------------------- */

/*
 * A challenge is part of the conversation, not a broken panel. It is drawn as
 * one more card on the same ground — no rule across the panel, no sunken
 * strip — with the human-readable explanation rendered into the message list
 * before it. Only the container is styled here; the Turnstile logic is
 * untouched.
 */
.asa-widget__challenge {
	flex: 0 0 auto;
	margin-block-end: var( --asa-space-sm );
	margin-inline: var( --asa-space-md );
	padding: var( --asa-space-md );
	border: 0;
	border-radius: var( --asa-radius-card );
	background: var( --asa-surface );
	box-shadow: var( --asa-shadow-card );
}

.asa-widget__challenge[hidden] {
	display: none;
}

.asa-widget__challenge-note {
	margin: 0;
	margin-block-end: var( --asa-space-sm );
	font-size: 13px;
	line-height: 1.5;
	color: var( --asa-text-muted );
}

.asa-widget__challenge-note:empty {
	display: none;
}

/* Cloudflare's iframe is 300px wide and must not widen a 320px panel. */
.asa-widget__challenge-mount {
	max-inline-size: 100%;
	overflow-x: auto;
}

.asa-widget__status {
	flex: 0 0 auto;
	margin: 0;
	padding-inline: var( --asa-space-lg );
	font-size: 12px;
	line-height: 1.45;
	color: var( --asa-text-muted );
}

/*
 * Nothing to say means no gap — but the element STAYS.
 *
 * An empty <p> with no block padding is already zero pixels tall, so there is
 * no dead strip to remove. `display: none` would also have looked right and
 * would have been a real bug: this is an aria-live region, and a live region
 * that is out of the accessibility tree when it changes is a live region whose
 * announcement is dropped. Rate-limit and verification messages are announced
 * here and nowhere else.
 */
.asa-widget__status:not( :empty ) {
	padding-block: 6px;
}

.asa-widget__composer {
	flex: 0 0 auto;
	display: flex;
	padding-block: 10px;
	padding-inline: var( --asa-space-md );
	background: transparent;
}

/*
 * ONE ROUNDED FIELD, WITH THE SEND CONTROL INSIDE IT.
 *
 * The composer used to be a bordered textarea sitting beside a rectangular
 * "Send" button, which is the shape a 2015 support widget has and is also how
 * the button ended up half off a 320px screen. Now the field is the Figma's
 * elevated white card — hairline ring, soft lift, no visible border — the
 * textarea is transparent inside it, and the send control is a child that
 * cannot leave the box it is drawn in.
 */
.asa-widget__field {
	flex: 1 1 auto;
	min-inline-size: 0;
	display: flex;
	align-items: flex-end;
	gap: 6px;
	padding: 4px;
	padding-inline-start: var( --asa-space-lg );
	border: 0;
	border-radius: var( --asa-radius-field );
	background: var( --asa-surface );
	box-shadow: var( --asa-shadow-card );
	transition: box-shadow var( --asa-motion ) var( --asa-ease );
}

/*
 * A composer that is switched off has to LOOK switched off.
 *
 * When the daily budget is spent, or the shop's key has been removed since the
 * page was cached, the textarea is disabled. Until 0.13.0 it still looked
 * exactly like a live composer — full-strength border, ordinary placeholder —
 * so a shopper tapped it, got no keyboard and no explanation, and the notice
 * telling them why was scrolled somewhere above. The refusal is explained in
 * the message list; this is what stops them arguing with the field first.
 */
.asa-widget__field--off {
	background: var( --asa-surface-muted );
	border-color: var( --asa-border );
	box-shadow: none;
	cursor: not-allowed;
}

.asa-widget__field--off .asa-widget__input,
.asa-widget__field--off .asa-widget__input::placeholder {
	color: var( --asa-text-muted );
	cursor: not-allowed;
}

.asa-widget__field--off:focus-within {
	box-shadow: none;
}

/*
 * Focus is a widening of the ring the field already has, in the merchant's
 * colour. The Figma's input has no focus state drawn; this is the quietest
 * treatment consistent with the rest of it, and it is still a visible 3px.
 */
.asa-widget__field:focus-within {
	box-shadow:
		0 0 0 1px var( --asa-accent ),
		0 0 0 4px var( --asa-accent-ring ),
		0 4px 10px rgba( 16, 18, 32, 0.05 );
}

/* Visually hidden, still read by assistive technology. */
.asa-widget__label {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset( 50% );
	white-space: nowrap;
	border: 0;
}

.asa-widget__input {
	flex: 1 1 auto;
	/*
	 * A textarea carries an intrinsic width from its `cols` default. Without
	 * min-inline-size:0 that intrinsic width becomes a flex floor and the
	 * composer overflows a narrow phone — the Send button leaving the screen is
	 * exactly this bug.
	 */
	min-inline-size: 0;
	inline-size: 100%;
	min-block-size: 36px;
	/* widget.js grows the field to fit and stops here. Keep the two in step. */
	max-block-size: 120px;
	padding-block: 8px;
	padding-inline: 0;
	border: 0;
	border-radius: 0;
	font: inherit;
	font-size: 14.5px;
	line-height: 1.45;
	color: var( --asa-text );
	background: transparent;
	resize: none;
	overflow-y: auto;
	box-shadow: none;
}

/* The field owns the focus treatment, so the textarea must not draw a second. */
.asa-widget__input:focus,
.asa-widget__input:focus-visible {
	outline: none;
	border: 0;
	box-shadow: none;
}

.asa-widget__input::placeholder {
	color: var( --asa-text-muted );
	opacity: 1;
}

/*
 * The Figma's send control: a circle inside the field, never a rectangle
 * beside it. The file draws it in near-black; here it wears the merchant's
 * colour, because the primary colour setting outranks the file.
 */
.asa-widget__send {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	inline-size: 44px;
	block-size: 44px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var( --asa-accent );
	background-image: var( --asa-accent-gradient );
	color: var( --asa-accent-ink );
	box-shadow: var( --asa-shadow-accent ), var( --asa-sheen );
	cursor: pointer;
	transition:
		opacity var( --asa-motion ) var( --asa-ease ),
		transform var( --asa-motion ) var( --asa-ease );
}

.asa-widget__send:hover {
	transform: scale( 1.04 );
}

.asa-widget__send:active {
	transform: scale( 0.94 );
}

.asa-widget__send .asa-widget__icon {
	inline-size: 20px;
	block-size: 20px;
	stroke-width: 2;
}

.asa-widget__send[disabled] {
	opacity: 0.35;
	box-shadow: none;
	cursor: not-allowed;
	transform: none;
}

/*
 * The send glyph points UP, not sideways.
 *
 * A sideways arrow has to be mirrored for Hebrew and Arabic, and every place
 * that mirroring is forgotten is a bug. An upward arrow means "send" in both
 * directions and needs no transform at all, which is why it is the one drawn in
 * the template.
 */

/* --- Phone --------------------------------------------------------------- */

@media ( max-width: 600px ) {
	/*
	 * Phones get a tighter edge than the desktop setting asks for, but the
	 * shop's offsets are still respected up to that cap: min() takes whichever
	 * is smaller, so lowering the offset moves the launcher in and raising it
	 * cannot push the launcher off a narrow screen.
	 *
	 * The cap is applied to the --asa-edge-* properties, never by redefining
	 * --asa-offset-* in terms of itself: a custom property that references
	 * itself is a cyclic dependency, and CSS drops the whole declaration rather
	 * than resolving it — which would silently take the offsets with it.
	 */
	.asa-widget {
		--asa-edge-inline: calc( min( var( --asa-offset-inline, 20px ), 16px ) + env( safe-area-inset-left, 0px ) );
		--asa-edge-inline-end: calc( min( var( --asa-offset-inline, 20px ), 16px ) + env( safe-area-inset-right, 0px ) );
		--asa-edge-bottom: calc( min( var( --asa-offset-bottom, 20px ), 16px ) + env( safe-area-inset-bottom, 0px ) );
	}

	/*
	 * The sheet's own geometry, in one place. The bottom distance folds in the
	 * home-indicator inset rather than replacing it, the same way the launcher
	 * edges do, so a notched phone gets clearance and a flat one gets 8px.
	 */
	.asa-widget {
		--asa-sheet-inset: 8px;
		--asa-sheet-bottom: calc( var( --asa-sheet-inset ) + env( safe-area-inset-bottom, 0px ) );
		/* Breathing space at the top: enough page showing to prove it is there. */
		--asa-sheet-gap-top: calc( 24px + env( safe-area-inset-top, 0px ) );
		--asa-sheet-max-inline: 430px;
		--asa-sheet-max-block: 680px;
		--asa-sheet-radius: 22px;
	}

	/*
	 * FULL SCREEN, AND ANCHORED TO THE TOP.
	 *
	 * The open widget is pinned to the top edge and given an explicit height,
	 * rather than being stretched between top and bottom. That is what lets the
	 * height come from the VISIBLE viewport when a software keyboard is up: a
	 * box stretched to `bottom: 0` is stretched to the bottom of the layout
	 * viewport, which on iOS is underneath the keyboard.
	 *
	 * The two WooCommerce selectors are repeated deliberately. The launcher
	 * clearance rule above is `.woocommerce-checkout .asa-widget`, which is more
	 * specific than `.asa-widget--open`; without matching that specificity here
	 * the open panel on a cart or checkout page keeps a 68px bottom offset,
	 * takes its full height from the top of that, and runs off the top of the
	 * screen — taking the start of the conversation with it. That was the
	 * reported "panel taller than the viewport" bug.
	 *
	 * NOTHING IN THIS BLOCK CHANGED IN 0.14.0. The 0.13.0 mobile viewport work
	 * is load-bearing and was carried across verbatim.
	 */
	.asa-widget--open,
	.woocommerce-cart .asa-widget--open,
	.woocommerce-checkout .asa-widget--open {
		top: 0;
		bottom: auto;
		inset-inline: 0;
		inline-size: auto;
		block-size: 100vh;
	}

	@supports ( height: 100dvh ) {
		.asa-widget--open,
		.woocommerce-cart .asa-widget--open,
		.woocommerce-checkout .asa-widget--open {
			/*
			 * dvh tracks the viewport as browser chrome slides in and out.
			 * --asa-viewport-block, when widget.js has measured it, tracks the
			 * software keyboard too, which dvh does not do on iOS.
			 */
			block-size: var( --asa-viewport-block, 100dvh );
			/*
			 * iOS scrolls the layout viewport out from under fixed elements
			 * when the keyboard opens. offsetTop, written by widget.js, is
			 * exactly how far, so this puts the panel back over the visible
			 * area instead of half off the top.
			 */
			transform: translateY( var( --asa-viewport-offset, 0px ) );
		}
	}

	/*
	 * THE FULL-VIEWPORT BOX IS THE STAGE, NOT THE PANEL. (0.17.2)
	 *
	 * Everything above still sizes .asa-widget itself to the visible viewport,
	 * because that measurement is what makes the keyboard handling work. What
	 * changed is what sits inside it: until 0.17.1 the panel filled that box
	 * edge to edge, and a shopper who tapped the launcher lost the shop. A chat
	 * widget that takes the whole screen has stopped being a widget.
	 *
	 * So the stage is now transparent and untouchable, and the panel is a sheet
	 * floating in the bottom of it — inset, rounded and shadowed, exactly the
	 * card the desktop shows, sized for a thumb. The page stays visible around
	 * it, which is the point: the shopper can see they are still in the shop.
	 *
	 * pointer-events: none on the stage is what keeps the rest of the page
	 * tappable through the parts of the box the sheet does not cover. The
	 * launcher already sets it while open; the panel takes it back.
	 */
	.asa-widget--open {
		pointer-events: none;
	}

	.asa-widget--open .asa-widget__panel {
		/*
		 * The desktop width and height settings are overridden — a 380px
		 * configured panel means nothing on a 360px screen — but the surface,
		 * the radius and the elevation are NOT. Those are the widget's
		 * appearance, and a phone is not a reason to ship a different product.
		 */
		pointer-events: auto;
		position: absolute;
		inset-inline: var( --asa-sheet-inset );
		inset-block-start: auto;
		inset-block-end: var( --asa-sheet-bottom );
		margin-inline: auto;
		inline-size: auto;
		max-inline-size: var( --asa-sheet-max-inline );

		/*
		 * Tall enough to hold a conversation, short enough to leave the page
		 * showing above it. The max-block-size is the one in charge: it is a
		 * percentage of the STAGE, and the stage is the visible viewport — so
		 * when the keyboard opens and the stage shrinks, the sheet shrinks with
		 * it instead of sliding under the keys.
		 */
		block-size: min( 78vh, var( --asa-sheet-max-block ) );
		max-block-size: calc( 100% - var( --asa-sheet-gap-top ) - var( --asa-sheet-bottom ) );

		border: 0;
		border-radius: var( --asa-sheet-radius );
		box-shadow: var( --asa-shadow );
		/* Landscape: keep every child clear of the notch on either side. */
		padding-left: env( safe-area-inset-left, 0px );
		padding-right: env( safe-area-inset-right, 0px );
		animation: asa-sheet-in 220ms var( --asa-ease ) both;
	}

	@supports ( height: 100dvh ) {
		.asa-widget--open .asa-widget__panel {
			block-size: min( 78dvh, var( --asa-sheet-max-block ) );
		}
	}

	/*
	 * With the keyboard up every pixel is worth having: the home-indicator
	 * inset is under the keys, so the sheet sits on the composer instead.
	 */
	.asa-widget--keyboard .asa-widget__panel {
		inset-block-end: var( --asa-sheet-inset );
	}

	/*
	 * THE FALLBACK, AND ONLY THE FALLBACK.
	 *
	 * A landscape phone, a very short window, or a keyboard that has left
	 * almost nothing behind: below this height the insets are the difference
	 * between a usable conversation and three visible lines, so the sheet gives
	 * them up and fills the stage. Portrait on any ordinary phone never reaches
	 * this, which is what keeps full screen a fallback rather than the default.
	 */
	@media ( max-height: 480px ) {
		.asa-widget--open .asa-widget__panel {
			inset-inline: 0;
			inset-block-end: 0;
			max-inline-size: none;
			block-size: 100%;
			max-block-size: 100%;
			border-radius: 0;
			box-shadow: none;
		}
	}

	/* A native-feeling app bar: it clears the status bar and the notch. */
	.asa-widget--open .asa-widget__header {
		padding-block-start: calc( 10px + env( safe-area-inset-top, 0px ) );
	}

	.asa-widget--open .asa-widget__messages {
		padding-inline: var( --asa-space-md );
	}

	.asa-widget--open .asa-widget__composer {
		padding-block-end: calc( 10px + env( safe-area-inset-bottom, 0px ) );
	}

	/*
	 * With the keyboard up there is no home indicator to clear — the keyboard
	 * is sitting where it would be — so the extra inset becomes dead space
	 * between the composer and the keys. widget.js sets this class only while
	 * the visible viewport is genuinely shortened.
	 */
	.asa-widget--keyboard .asa-widget__composer {
		padding-block-end: 10px;
	}

	.asa-widget--open .asa-widget__input {
		/* A phone has less to spare. widget.js caps growth to match. */
		max-block-size: 96px;
		/* 16px or larger: anything smaller makes iOS zoom the page on focus. */
		font-size: 16px;
	}

	.asa-widget--open .asa-widget__bubble {
		max-inline-size: 86%;
		font-size: 15px;
	}

	/* The card is already a row; on a narrow screen it gets a smaller thumb
	 * rather than a taller box, so four of them still read as a list. */
	.asa-widget--open .asa-widget__card-image {
		inline-size: 64px;
		block-size: 64px;
	}

	@keyframes asa-sheet-in {
		from {
			opacity: 0;
			transform: translateY( 12px );
		}

		to {
			opacity: 1;
			transform: none;
		}
	}
}

/* --- Tablet -------------------------------------------------------------- */

/*
 * Between the phone breakpoint and a comfortable laptop the panel stays a
 * floating card — an almost-full-screen sheet on a 700px window is the worst of
 * both. The only adjustment is a slightly tighter viewport cap so a tall
 * configured height cannot crowd the edges on a short tablet in landscape.
 */
@media ( min-width: 601px ) and ( max-width: 900px ) {
	.asa-widget__panel {
		max-inline-size: calc( 100vw - 32px );
		max-block-size: calc( 100vh - 32px );
		max-block-size: calc( 100dvh - 32px );
	}
}

/* --- Reduced motion ------------------------------------------------------ */

@media ( prefers-reduced-motion: reduce ) {
	/*
	 * `.asa-widget--open .asa-widget__panel` is what applies the phone sheet
	 * animation, and it is a two-class selector. A one-class `.asa-widget__panel`
	 * here loses to it, so the sheet kept sliding for the shoppers who asked
	 * their device not to move things. The compound selector below is what makes
	 * this rule actually win; it is not redundancy.
	 */
	.asa-widget--open .asa-widget__panel,
	.asa-widget--open .asa-widget__messages,
	.asa-widget__launcher,
	.asa-widget__panel,
	.asa-widget__message,
	.asa-widget__notice,
	.asa-widget__card,
	.asa-widget__chip,
	.asa-widget__close,
	.asa-widget__send,
	.asa-widget__field,
	.asa-widget__card-cta,
	.asa-widget__card-add,
	.asa-widget__coupon,
	.asa-widget__coupon-apply,
	.asa-widget__retry,
	.asa-widget__dot {
		transition: none;
		animation: none;
	}

	.asa-widget__launcher:hover,
	.asa-widget__launcher:active,
	.asa-widget__card:hover,
	.asa-widget__card:active,
	.asa-widget__chip:hover,
	.asa-widget__chip:active,
	.asa-widget__retry:hover,
	.asa-widget__retry:active,
	.asa-widget__card-cta:hover,
	.asa-widget__card-cta:active,
	.asa-widget__coupon-apply:hover,
	.asa-widget__coupon-apply:active,
	.asa-widget__close:active,
	.asa-widget__send:hover,
	.asa-widget__send:active {
		transform: none;
	}

	/* The dots stop moving but must still read as "working". */
	.asa-widget__dot {
		opacity: 0.5;
	}
}

/* -------------------------------------------------------------------------
 * Lead capture form (0.17.0)
 *
 * A form inside a 360px panel that is often on a phone, in Hebrew, with a
 * software keyboard covering half the screen. Three things follow:
 *
 * - Every control is a full-width block with its label above it. Side-by-side
 *   fields are what make a form overflow at 320px, and the panel must never
 *   scroll sideways.
 * - Logical properties throughout (padding-inline, text-align: start), so the
 *   whole thing mirrors under RTL without a single direction-specific rule.
 * - 44px minimum touch targets and a 16px font size on inputs. Anything below
 *   16px makes iOS Safari zoom the page on focus, which on a chat panel means
 *   the shopper loses sight of the conversation they were having.
 * ------------------------------------------------------------------------- */
.asa-widget__lead {
	display: flex;
	flex-direction: column;
	gap: var( --asa-space-sm );
	padding: var( --asa-space-md );
	border-radius: var( --asa-radius-card );
	background: var( --asa-surface );
	box-shadow:
		var( --asa-shadow-card ),
		inset 0 2px 0 var( --asa-accent );
	animation: asa-bubble-in 160ms var( --asa-ease ) both;
	text-align: start;
}

.asa-widget__lead-title {
	margin: 0;
	font-size: 14px;
	font-weight: 700;
	color: var( --asa-text );
}

.asa-widget__lead-field {
	display: flex;
	flex-direction: column;
	gap: 4px;
	min-inline-size: 0;
}

.asa-widget__lead-label {
	font-size: 12.5px;
	font-weight: 600;
	color: var( --asa-text-body );
}

.asa-widget__lead-optional {
	font-weight: 400;
	color: var( --asa-text-muted, var( --asa-text-body ) );
}

.asa-widget__lead-input {
	inline-size: 100%;
	max-inline-size: 100%;
	box-sizing: border-box;
	min-block-size: 44px;
	padding-block: 10px;
	padding-inline: 12px;
	border: 1px solid var( --asa-border, rgba( 0, 0, 0, 0.14 ) );
	border-radius: var( --asa-radius-tight, 8px );
	background: var( --asa-surface-muted );
	color: var( --asa-text );
	font: inherit;
	/* 16px or iOS zooms the page on focus. Not a taste decision. */
	font-size: 16px;
	line-height: 1.4;
}

textarea.asa-widget__lead-input {
	min-block-size: 60px;
	resize: vertical;
}

.asa-widget__lead-input:focus-visible {
	outline: 2px solid var( --asa-accent );
	outline-offset: 1px;
}

.asa-widget__lead-input:disabled {
	opacity: 0.7;
}

.asa-widget__lead-hint,
.asa-widget__lead-purpose {
	margin: 0;
	font-size: 12px;
	line-height: 1.5;
	color: var( --asa-text-body );
}

.asa-widget__lead-status {
	margin: 0;
	font-size: 12.5px;
	line-height: 1.5;
	color: var( --asa-text-body );
	overflow-wrap: anywhere;
}

.asa-widget__lead--failed .asa-widget__lead-status {
	color: var( --asa-danger-ink, #8a1c1c );
}

.asa-widget__lead--done .asa-widget__lead-status {
	color: #157f4d;
	font-weight: 600;
}

.asa-widget__lead-submit {
	min-block-size: 44px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding-inline: var( --asa-space-lg );
	border: 0;
	border-radius: var( --asa-radius-pill );
	background: var( --asa-accent );
	background-image: var( --asa-accent-gradient );
	box-shadow: var( --asa-sheen );
	color: var( --asa-accent-ink );
	font: inherit;
	font-size: 14px;
	font-weight: 600;
	cursor: pointer;
	transition:
		transform var( --asa-motion ) var( --asa-ease ),
		box-shadow var( --asa-motion ) var( --asa-ease );
}

.asa-widget__lead-submit:hover {
	transform: translateY( -1px );
	box-shadow: var( --asa-shadow-accent ), var( --asa-sheen );
}

.asa-widget__lead-submit:active {
	transform: scale( 0.97 );
}

.asa-widget__lead-submit:disabled {
	opacity: 0.75;
	cursor: default;
	transform: none;
	box-shadow: none;
}

/* --- Page lock (0.17.2) --------------------------------------------------
 *
 * The half of the scroll lock that belongs in a stylesheet. widget.js owns the
 * part that has to be computed — position: fixed and the negative top that
 * holds the page where the shopper left it — and puts back exactly what it
 * found on close.
 *
 * overscroll-behavior is what stops a drag that reaches the end of the message
 * list from chaining out to the document, which on a phone is the difference
 * between "the list stopped" and "the browser started a pull-to-refresh".
 * Scoped to a class this plugin adds and removes: nothing here applies to a
 * page with no chat open on it.
 */
html.asa-locked,
body.asa-locked {
	overscroll-behavior: none;
}

body.asa-locked {
	/* touch-action leaves taps, presses and pinch-zoom alone; only the pan the
	 * lock is meant to stop is refused. */
	touch-action: pan-x pinch-zoom;
}

/* The one region that still scrolls, and it keeps its momentum. */
.asa-widget__messages {
	-webkit-overflow-scrolling: touch;
}
