/**
 * Product Forms — trigger button, on-demand modal, and the server-rendered form.
 *
 * Neutral and theme-friendly, scoped under .lwpf-trigger / .lwpf-modal /
 * .lwpf-form so nothing bleeds.
 *
 * ⚠️ SIZING: never use bare `rem` in this file. Automatic.css sets
 * `--root-font-size: 62.5%`, so on shoplw.ca/.com `1rem` is **10px**, not 16px.
 * The first cut of this file was written in rem and rendered at ~62% of intent
 * everywhere — 10px body text, a 340px-wide dialog, 6px control padding. Two
 * rules keep it correct on any root size:
 *
 *   1. **Font sizes come from ACSS type tokens** (--text-s / --text-m / --h3),
 *      consumed through the scoped --lwpf-* tokens below. Those tokens are
 *      calibrated against whatever root size the site runs, so they are right by
 *      construction. The rem values in the var() fallbacks are for a site with NO
 *      ACSS, where the root is 100% and 1rem really is 16px — do not "simplify"
 *      them to match the ACSS pixel values.
 *   2. **Everything else is `em`** — padding, gaps, dialog width, textarea
 *      height. `em` resolves against the element's own (now correct) font-size,
 *      so the whole component scales together and never depends on the root at
 *      all. Borders, outlines and shadows stay in px, where hairlines belong.
 *
 * ⚠️ COLOUR: likewise no bare hex below — every colour resolves through a
 * --lwpf-* token onto the ACSS palette, so each store's own branding drives the
 * component and there is no second copy of the brand to drift. The literals in
 * the fallbacks are the no-ACSS defaults only.
 *
 * Retheme by overriding the --lwpf-* tokens (theme/ACSS/builder global CSS),
 * not by editing this file — the pattern lw-google-reviews and Typesense Search
 * already use.
 *
 * ⚠️ LAYOUT: defaults are stated EXPLICITLY, never inherited. Automatic.css
 * targets bare elements (e.g. `section > div { align-items: flex-start }`), so
 * plugin markup rendered inside a section silently loses the flex/grid defaults
 * you'd otherwise get for free. Every flex container below restates
 * flex-direction / align-items / justify-content on purpose — do not trim them
 * back to "the initial value anyway".
 */

/* ------------------------------------------------------------------ tokens */

/**
 * Declared on BOTH roots: the trigger sits in the product markup, the modal is
 * printed at body level in wp_footer, so neither contains the other.
 */
.lwpf-trigger,
.lwpf-modal {
	/* Type — ACSS tokens first, no-ACSS rem fallbacks second. Only the three
	   sizes actually used are defined; --text-l / --text-xl / --h2 are there in
	   ACSS if a future element wants them. */
	--lwpf-text-s: var(--text-s, 0.89rem);
	--lwpf-text: var(--text-m, 1rem);
	--lwpf-title: var(--h3, 1.27rem);

	/* Radii — ACSS ships these in px, so no fallback maths needed. --radius-l
	   exists on .ca but not .com, hence the second hop. */
	--lwpf-radius: var(--radius-m, 6px);
	--lwpf-radius-l: var(--radius-l, var(--radius, 10px));

	/**
	 * Colour — ACSS palette tokens, so the component adopts each store's own
	 * branding instead of carrying a second, drifting copy of it.
	 *
	 * ⚠️ The two stores do NOT run the same ACSS. shoplw.ca is 3.3.6 with hex
	 * values and an `--action` token; shoplw.com is newer, uses oklch(), and has
	 * **no `--action`**. Hence the two-hop chain on the accent: `--action` on .ca
	 * (#163158 — the Living Waters brand navy, and what ACSS's own
	 * `--btn-background` resolves to there), `--primary` on .com, and the
	 * order-tracker navy when there is no ACSS at all. Verify a token exists on
	 * BOTH stores before depending on it; several don't.
	 *
	 * All of these are declared at `:root` on both sites (checked), so they
	 * inherit into the modal even though it prints at body level in wp_footer.
	 * On .ca they also sit on `.color-scheme--main`/`--alt`, so a re-scoped
	 * colour scheme carries the dialog with it for free.
	 */
	--lwpf-accent: var(--action, var(--primary, #1e3a5f));
	--lwpf-accent-hover: var(--primary-hover, #16314f);
	--lwpf-on-accent: var(--white, #fff);
	--lwpf-ink: var(--text-color, #222);
	--lwpf-ink-soft: var(--neutral-dark, #444);
	--lwpf-border: var(--neutral-light, #c7c7c7);
	--lwpf-surface: var(--white, #fff);
	--lwpf-surface-alt: var(--neutral-ultra-light, #f4f4f4);
	--lwpf-danger: var(--danger, #b00020);
	--lwpf-danger-bg: var(--danger-ultra-light, #fdf2f4);
	--lwpf-success: var(--success, #15803d);
	--lwpf-success-bg: var(--success-ultra-light, #f0fdf4);
	/* Pale, not full-strength — this outlines the success panel, it isn't text. */
	--lwpf-success-border: var(--success-light, #bbf7d0);
	/* Scrim, not brand — a literal by design; override if a site wants lighter. */
	--lwpf-backdrop: rgba(15, 23, 35, 0.55);
}

/* ---------------------------------------------------------------- trigger */

/**
 * Baseline appearance only, wrapped in :where() so its specificity is zero.
 * The shortcode's `class` att exists precisely so the button can wear an
 * ACSS/Bricks button class (class="btn btn--outline"); at zero specificity that
 * class always wins, with no !important and no stylesheet load-order luck.
 */
:where(.lwpf-trigger) {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5em;
	box-sizing: border-box;
	padding: 0.65em 1.3em;
	font: inherit;
	font-size: var(--lwpf-text);
	font-weight: 600;
	line-height: 1.2;
	text-align: center;
	text-decoration: none;
	color: var(--lwpf-on-accent);
	background: var(--lwpf-accent);
	border: 0;
	border-radius: var(--lwpf-radius);
}

:where(.lwpf-trigger:hover) {
	background: var(--lwpf-accent-hover);
}

/**
 * Variants — the module painting its own button so a store doesn't have to
 * borrow a framework's.
 *
 * ⚠️ On these stores Automatic.css opts an element into its whole button system
 * via `[class*="btn--"]`, so passing even `btn--outline` in the `class` att
 * imports ACSS's padding/font/radius/colour package — and its `--btn-*` defaults
 * differ per ACSS version, so the same shortcode renders differently on .ca and
 * .com. These variants avoid that entirely: no framework class, no opt-in.
 *
 * Every rule stays inside :where() so specificity remains ZERO. That is what
 * lets `class="btn btn--primary btn--outline"` still win outright when a store
 * genuinely wants the framework look — and lets any site-level override win with
 * a single class, no !important needed. Ordered AFTER the base rule above so it
 * wins the zero-specificity tie.
 */
:where(.lwpf-trigger--outline) {
	color: var(--lwpf-accent);
	background: transparent;
	/* box-sizing: border-box is set on the base rule, so the border doesn't
	   change the button's outer size relative to the solid variant. */
	border: 2px solid var(--lwpf-accent);
}

:where(.lwpf-trigger--outline:hover) {
	color: var(--lwpf-on-accent);
	background: var(--lwpf-accent);
	border-color: var(--lwpf-accent);
}

/* Text-only. Keeps the underline so it still reads as actionable without a box. */
:where(.lwpf-trigger--plain) {
	padding-inline: 0;
	color: var(--lwpf-accent);
	background: transparent;
	border: 0;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

:where(.lwpf-trigger--plain:hover) {
	color: var(--lwpf-accent-hover);
	background: transparent;
	text-decoration: none;
}

/* Not negotiable by the theme: it must look clickable and must show focus. */
.lwpf-trigger {
	cursor: pointer;
}

.lwpf-trigger:focus-visible {
	outline: 3px solid var(--lwpf-accent);
	outline-offset: 2px;
}

/* ------------------------------------------------------------------ modal */

/**
 * The shell is printed empty on wp_footer with the `hidden` attribute. Builder
 * and framework rules that set `display` on bare divs happily out-specify the
 * UA's `[hidden] { display: none }` — without this !important the empty shell
 * renders as a full-screen overlay on every page load and eats every click.
 */
.lwpf-modal[hidden] {
	display: none !important;
}

.lwpf-modal {
	position: fixed;
	inset: 0;
	z-index: 999999;
	display: flex;
	flex-direction: row;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	padding: 1em;
	overflow: hidden;
	/* Sets the em basis for the whole dialog — every size below cascades off it. */
	font-size: var(--lwpf-text);
	line-height: 1.5;
	opacity: 0;
	transition: opacity 160ms ease;
}

.lwpf-modal * {
	box-sizing: border-box;
}

.lwpf-modal--open {
	opacity: 1;
}

.lwpf-modal__backdrop {
	position: absolute;
	inset: 0;
	background: var(--lwpf-backdrop);
}

.lwpf-modal__dialog {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	align-items: stretch;
	justify-content: flex-start;
	width: 100%;
	/* em, so the dialog widens with the type rather than with the root size:
	   ~576px against ACSS's 18px body, ~512px with no ACSS. In rem this was
	   34rem = 340px on these stores. */
	max-width: 32em;
	max-height: 85vh;
	padding: 1.6em;
	color: var(--lwpf-ink);
	background: var(--lwpf-surface);
	border-radius: var(--lwpf-radius-l);
	box-shadow: 0 18px 48px rgba(0, 0, 0, 0.28);
	overflow: hidden; /* the body scrolls, not the dialog */
	transform: translateY(8px);
	transition: transform 180ms ease;
}

.lwpf-modal--open .lwpf-modal__dialog {
	transform: none;
}

.lwpf-modal__dialog:focus {
	outline: none; /* tabindex="-1", focused programmatically only */
}

.lwpf-modal__close {
	position: absolute;
	top: 0.35em;
	right: 0.35em;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 1.6em;
	height: 1.6em;
	padding: 0;
	font: inherit;
	font-size: var(--lwpf-title);
	line-height: 1;
	color: var(--lwpf-ink-soft);
	background: transparent;
	border: 0;
	border-radius: var(--lwpf-radius);
	cursor: pointer;
}

.lwpf-modal__close:hover {
	color: var(--lwpf-ink);
	background: var(--lwpf-surface-alt);
}

.lwpf-modal__close:focus-visible {
	outline: 3px solid var(--lwpf-accent);
	outline-offset: -1px;
}

.lwpf-modal__title {
	flex: 0 0 auto;
	margin: 0 0 0.4em;
	padding-right: 1.8em; /* clear of the close button */
	font-size: var(--lwpf-title);
	font-weight: 700;
	line-height: 1.3;
	color: var(--lwpf-accent);
}

/* Empty while the form is loading — don't reserve its margin. */
.lwpf-modal__title:empty {
	display: none;
}

.lwpf-modal__body {
	flex: 1 1 auto;
	min-height: 0; /* required, or the flex child refuses to shrink and scroll */
	padding-top: 0.4em;
	overflow-y: auto;
	overscroll-behavior: contain;
}

/* Loading + load-failure notices (written via textContent by forms.js). */
.lwpf-modal__loading,
.lwpf-modal__error {
	margin: 0;
	padding: 0.9em 1em;
	font-size: var(--lwpf-text-s);
	background: var(--lwpf-surface-alt);
	border-radius: var(--lwpf-radius);
}

.lwpf-modal__error {
	color: var(--lwpf-danger);
	background: var(--lwpf-danger-bg);
}

/* ------------------------------------------------------------------- form */

/* Everything from .lwpf-form down is the server-rendered markup injected on
   open. Element selectors are scoped inside .lwpf-form as well as the BEM
   classes, so the fields still render correctly if a field type ships without
   its class. */

.lwpf-form {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	justify-content: flex-start;
	gap: 0.9em;
	margin: 0;
}

.lwpf-form__intro {
	margin: 0;
	font-size: var(--lwpf-text-s);
	color: var(--lwpf-ink-soft);
}

.lwpf-form__row {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	justify-content: flex-start;
	gap: 0.35em;
}

.lwpf-form__label,
.lwpf-form label {
	display: block;
	font-size: var(--lwpf-text-s);
	font-weight: 600;
	color: var(--lwpf-ink);
}

.lwpf-form__req {
	margin-left: 0.15em;
	color: var(--lwpf-danger);
}

.lwpf-form__input,
.lwpf-form__select,
.lwpf-form__textarea,
.lwpf-form input[type="text"],
.lwpf-form input[type="email"],
.lwpf-form input[type="tel"],
.lwpf-form input[type="url"],
.lwpf-form select,
.lwpf-form textarea {
	width: 100%;
	max-width: 100%;
	/* font-size FIRST, so the em padding below resolves against it and not
	   against the inherited size. */
	font: inherit;
	font-size: var(--lwpf-text);
	padding: 0.6em 0.75em;
	line-height: 1.4;
	color: var(--lwpf-ink);
	background: var(--lwpf-surface);
	border: 1px solid var(--lwpf-border);
	border-radius: var(--lwpf-radius);
	box-sizing: border-box;
}

.lwpf-form__textarea,
.lwpf-form textarea {
	min-height: 6.5em;
	resize: vertical;
}

.lwpf-form :is(input, select, textarea):focus {
	border-color: var(--lwpf-accent);
}

.lwpf-form :is(input, select, textarea):focus-visible {
	outline: 3px solid var(--lwpf-accent);
	outline-offset: 1px;
	border-color: var(--lwpf-accent);
}

/**
 * Honeypot. MUST be off-screen rather than display:none / hidden / [hidden]:
 * bots skip fields they can detect as hidden, which is exactly what a real
 * visitor does, so a display:none trap catches nobody. Off-screen keeps it
 * real to a naive form-filler while sighted users never see it (the PHP marks
 * the wrapper aria-hidden and the input tabindex="-1" for AT and keyboard).
 */
.lwpf-form__hp {
	position: absolute !important;
	left: -9999px !important;
	top: auto;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.lwpf-form__submit,
.lwpf-form button[type="submit"] {
	align-self: flex-start;
	font: inherit;
	font-size: var(--lwpf-text);
	padding: 0.65em 1.5em;
	font-weight: 600;
	line-height: 1.2;
	color: var(--lwpf-on-accent);
	background: var(--lwpf-accent);
	border: 0;
	border-radius: var(--lwpf-radius);
	cursor: pointer;
}

.lwpf-form__submit:hover,
.lwpf-form button[type="submit"]:hover {
	background: var(--lwpf-accent-hover);
}

.lwpf-form__submit:disabled,
.lwpf-form button[type="submit"]:disabled {
	opacity: 0.6;
	cursor: default;
}

.lwpf-form__submit:focus-visible,
.lwpf-form button[type="submit"]:focus-visible {
	outline: 3px solid var(--lwpf-accent);
	outline-offset: 2px;
}

/* Inline validation / throttle / expired-session message. */
.lwpf-form__msg {
	margin: 0;
	font-size: var(--lwpf-text-s);
}

.lwpf-form__msg:empty {
	display: none;
}

.lwpf-form__msg--error {
	color: var(--lwpf-danger);
}

/* Replaces the whole form once the submit succeeds. */
.lwpf-form__success {
	margin: 0;
	padding: 0.9em 1em;
	font-size: var(--lwpf-text);
	font-weight: 600;
	color: var(--lwpf-success);
	background: var(--lwpf-success-bg);
	border: 1px solid var(--lwpf-success-border);
	border-radius: var(--lwpf-radius);
}

.lwpf-form__success:focus {
	outline: none; /* tabindex="-1", focused programmatically after submit */
}

.lwpf-form__success:focus-visible {
	outline: 3px solid var(--lwpf-accent);
	outline-offset: 2px;
}

/* ------------------------------------------------------------ scroll lock */

/**
 * forms.js adds .lwpf-modal-open to <html> while the dialog is open and sets
 * --lwpf-scrollbar to the width of the scrollbar the lock removes, so the page
 * behind the backdrop doesn't shift sideways on open. Both are cleared on close.
 */
html.lwpf-modal-open,
html.lwpf-modal-open body {
	overflow: hidden;
}

html.lwpf-modal-open {
	padding-right: var(--lwpf-scrollbar, 0px);
}

/* --------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
	.lwpf-modal {
		opacity: 1;
		transition: none;
	}

	.lwpf-modal__dialog {
		transform: none;
		transition: none;
	}
}

/* ----------------------------------------------------------------- mobile */

@media (max-width: 540px) {
	.lwpf-modal {
		padding: 0.5em;
	}

	.lwpf-modal__dialog {
		width: 100%;
		max-width: none;
		max-height: calc(100vh - 1em);
		max-height: calc(100dvh - 1em); /* survives mobile browser chrome */
		padding: 1.3em 1.1em;
	}

	.lwpf-form__submit,
	.lwpf-form button[type="submit"] {
		align-self: stretch;
		width: 100%;
	}
}
