/**
 * LoyaltyDog customer-facing widget (Sprint 2 Task 7).
 *
 * Design tokens come from ld-brand.css — loaded as a WordPress
 * dependency of this handle (see
 * Plugin::enqueue_frontend_assets()), NOT via @import. The dep edge
 * gives the browser a parallel-fetchable graph instead of a
 * parse-time waterfall.
 *
 * Fade-in: driven entirely by CSS keyframes on first paint so the
 * widget stays visible even when JavaScript is disabled or fails —
 * Seer flagged JS-dependent visibility as a high-severity regression
 * during the PR #56 review. The animation is zeroed out under
 * prefers-reduced-motion (ld-brand.css's global * selector also does
 * this; the local rule is belt-and-suspenders).
 *
 * @since 2.5.0
 */

@keyframes ld-widget-fade-in {
	from {
		opacity: 0;
		transform: translateY(8px);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

.loyaltydog-widget {
	font-family: var(--ld-font-body);
	color: var(--ld-text);
	background: var(--ld-surface);
	border: 1px solid var(--ld-border);
	border-radius: var(--ld-radius-lg);
	padding: var(--ld-space-6);
	box-shadow: var(--ld-shadow);
	max-width: 360px;
	animation: ld-widget-fade-in var(--ld-duration) var(--ld-ease-out) both;
}

/* Balance — points + tier */
.ld-balance {
	background: linear-gradient(
		135deg,
		var(--ld-blue-subtle) 0%,
		var(--ld-surface-alt) 100%
	);
	border-radius: var(--ld-radius-md);
	padding: var(--ld-space-5);
	margin-bottom: var(--ld-space-4);
	text-align: center;
	font-size: var(--ld-fs-base);
}
.ld-points {
	display: block;
	font-family: var(--ld-font-display);
	font-weight: var(--ld-fw-display);
	font-size: var(--ld-fs-4xl);
	color: var(--ld-blue);
	line-height: var(--ld-lh-tight);
	/* SWE-648 (Lee 2026-06-15): the points number must never break across
	   lines — in a narrow/floating card a theme's global overflow-wrap /
	   word-break rule was splitting "545" into "54" + "5". Keep it on one
	   line and immune to inherited break rules. */
	white-space: nowrap;
	overflow-wrap: normal;
	word-break: normal;
}
.ld-tier {
	display: inline-block;
	margin-top: var(--ld-space-2);
	padding: 0 var(--ld-space-2);
	border-radius: var(--ld-radius-sm);
	font-style: normal;
	font-size: var(--ld-fs-sm);
	color: var(--ld-text-muted);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	/* Per-tier background/foreground colors are applied inline by
	   widget.js from the server-validated hex values in
	   project_customer_response. Inline styles win the cascade so
	   merchants whose program defines tier colors see them; merchants
	   without configured colors fall back to these neutral defaults. */
}

/* Active discount — shown when the customer has claimed an offer and
   has a discount code waiting to use at checkout. Mirrors Shopify's
   ActiveOffer card visual hierarchy: subtle highlight + monospace code. */
.ld-active-discount {
	margin-top: var(--ld-space-3);
	padding: var(--ld-space-2) var(--ld-space-3);
	background: var(--ld-surface-alt);
	border: 1px dashed var(--ld-border);
	border-radius: var(--ld-radius-md);
	font-size: var(--ld-fs-sm);
}
.ld-discount-label {
	color: var(--ld-text-muted);
}
.ld-discount-code {
	font-family: var(--ld-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
	font-weight: 600;
	color: var(--ld-text);
	background: var(--ld-surface);
	padding: 0 var(--ld-space-1);
	border-radius: var(--ld-radius-sm);
	user-select: all;
}

/* Claimed offer name — narrates which reward the discount code came
   from, so the customer recognizes it ("Currently claimed: Free shipping"). */
.ld-claimed-offer {
	margin-top: var(--ld-space-2);
	margin-bottom: 0;
	font-size: var(--ld-fs-sm);
	color: var(--ld-text-muted);
	font-style: italic;
}

/* Transactions list */
.ld-transactions {
	list-style: none;
	margin: 0;
	padding: 0;
	font-size: var(--ld-fs-sm);
	color: var(--ld-text-muted);
}
.ld-transactions li {
	padding: var(--ld-space-2) 0;
	border-bottom: 1px solid var(--ld-border);
}
.ld-transactions li:last-child {
	border-bottom: none;
}

/* Join-CTA fallback (shown when customer isn't enrolled) */
.ld-join-wrap {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--ld-space-3);
	text-align: center;
}

/* SWE-559: layout modifiers.
   Same DOM tree, two flex-direction modes — switching is CSS-only
   so widget.js stays oblivious to the layout choice. The modifier
   is emitted on both the outer placeholder (server-rendered) and
   the inner ld-join-wrap (mirrored by widget.js), so either hook
   can be targeted. We attach the rules to the inner wrap since
   that's the element actually doing the flex layout.

   Default (no modifier) stays `column` for backward compatibility
   with sites whose CSS extends .ld-join-wrap without specifying a
   layout. The --vertical variant is therefore a no-op alias of the
   default — it exists so the class hook is always present
   (assertable from tests + DOM inspection).
*/
.ld-join-wrap--vertical {
	flex-direction: column;
	align-items: center;
	text-align: center;
}
.ld-join-wrap--horizontal {
	flex-direction: row;
	align-items: center;
	justify-content: center;
	gap: var(--ld-space-4);
	text-align: left;
}
/* Horizontal: collapse to vertical on narrow viewports (sidebars,
   mobile) so the QR doesn't overflow. ~480px matches the existing
   widget breakpoint below. */
@media (max-width: 480px) {
	.ld-join-wrap--horizontal {
		flex-direction: column;
		align-items: center;
		text-align: center;
		gap: var(--ld-space-3);
	}
}
.ld-join-cta {
	margin: 0;
	color: var(--ld-text);
	font-size: var(--ld-fs-base);
	font-style: normal;
}
.ld-join-cta a {
	display: inline-block;
	padding: var(--ld-space-3) var(--ld-space-5);
	background: var(--ld-blue);
	color: var(--ld-text-on-brand);
	border-radius: var(--ld-radius);
	font-family: inherit;
	font-weight: var(--ld-fw-semibold);
	text-decoration: none;
	transition: background var(--ld-duration-fast) var(--ld-ease);
}
.ld-join-cta a:hover {
	background: var(--ld-blue-hover);
}

/* QR image inside join fallback */
.ld-qr {
	display: block;
	border: 1px solid var(--ld-border);
	border-radius: var(--ld-radius-sm);
	max-width: 100%;
	height: auto;
}

/* Dark mode: the balance-card gradient collapses to a very dark
   navy→near-black range via ld-brand.css's dark-block overrides.
   --ld-blue on that dark gradient falls below WCAG AA for normal
   text — rescue contrast on the big points display by switching to
   --ld-text (which flips to a light gray in dark mode). */
@media (prefers-color-scheme: dark) {
	.ld-points {
		color: var(--ld-text);
	}
}

/* Reduced motion: suppress the first-paint fade entirely. */
@media (prefers-reduced-motion: reduce) {
	.loyaltydog-widget {
		animation: none;
	}
}

/* Narrow viewports */
@media (max-width: 480px) {
	.loyaltydog-widget {
		max-width: 100%;
		padding: var(--ld-space-5);
	}
	.ld-points {
		font-size: var(--ld-fs-3xl);
	}
}

/* SWE-625 Finding B — explicit "Your points balance" panel on the
   WooCommerce My Account → Loyalty page. Reuses the same brand tokens as
   the widget's .ld-balance so the two surfaces read as one system. */
.ld-account-balance {
	margin-bottom: var(--ld-space-4);
	/* SWE-648 (Lee 2026-06-15 #4&5): keep the loyalty sections to a
	   comfortable reading width instead of stretching full-page-wide. */
	max-width: 32rem;
}
/* SWE-648 (Lee 2026-06-15 #1&2): the section headings read too faint and
   small. Make them larger, bolder, and full-contrast. */
.ld-account-balance-title {
	margin: 0 0 var(--ld-space-2);
	font-size: var(--ld-fs-lg);
	font-weight: var(--ld-fw-bold);
	color: var(--ld-text);
}
.ld-account-balance-value {
	margin: 0;
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: var(--ld-space-2);
}
.ld-account-points {
	font-family: var(--ld-font-display);
	font-weight: var(--ld-fw-display);
	font-size: var(--ld-fs-4xl);
	color: var(--ld-blue);
	line-height: var(--ld-lh-tight);
	/* SWE-648: same anti-wrap guard as the widget's .ld-points. */
	white-space: nowrap;
	overflow-wrap: normal;
	word-break: normal;
}
.ld-account-points-unit {
	font-size: var(--ld-fs-base);
	color: var(--ld-text-muted);
}
.ld-account-tier {
	display: inline-block;
	padding: 0 var(--ld-space-2);
	border-radius: var(--ld-radius-sm);
	font-size: var(--ld-fs-sm);
	color: var(--ld-text-muted);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	/* Per-tier colors are applied inline by account-balance.js from the
	   server-validated hex values, exactly as the widget does. */
}

/* SWE-625 Finding B3 — "Awards you can claim" section on the WooCommerce
   My Account → Loyalty page. Server-rendered from /wordpress/ui/eligible-awards.
   Reuses the same brand tokens + .ld-account-* family as the balance panel so
   the surfaces read as one system. */
.ld-account-awards {
	margin-bottom: var(--ld-space-4);
	/* SWE-648 (Lee 2026-06-15 #4&5): cap the awards "table" width. */
	max-width: 32rem;
}
.ld-account-awards-title {
	margin: 0 0 var(--ld-space-2);
	font-size: var(--ld-fs-lg);
	font-weight: var(--ld-fw-bold);
	color: var(--ld-text);
}
.ld-account-awards-empty {
	margin: 0;
	font-size: var(--ld-fs-sm);
	color: var(--ld-text-muted);
}
.ld-account-awards-list {
	list-style: none;
	margin: 0;
	padding: 0;
}
.ld-account-award {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: var(--ld-space-2);
	padding: var(--ld-space-2) var(--ld-space-3);
	margin-top: var(--ld-space-2);
	background: var(--ld-surface-alt);
	border: 1px solid var(--ld-border);
	border-radius: var(--ld-radius-md);
}
.ld-account-award-name {
	font-size: var(--ld-fs-base);
	color: var(--ld-text);
}
.ld-account-award-points {
	font-family: var(--ld-font-display);
	font-weight: var(--ld-fw-display);
	font-size: var(--ld-fs-sm);
	color: var(--ld-blue);
	white-space: nowrap;
}

/* SWE-631 / SWE-648 — "Your active reward" panel. Previously had no CSS and
   inherited theme defaults; give it the same heading treatment + width cap as
   the balance/awards sections so the loyalty tab reads as one system. */
.ld-account-active-offer {
	margin-bottom: var(--ld-space-4);
	max-width: 32rem;
}
.ld-account-active-offer-title {
	margin: 0 0 var(--ld-space-2);
	font-size: var(--ld-fs-lg);
	font-weight: var(--ld-fw-bold);
	color: var(--ld-text);
}
.ld-account-active-offer-body {
	margin: 0;
}
.ld-account-active-offer-name {
	font-size: var(--ld-fs-base);
	color: var(--ld-text);
}
.ld-account-active-offer-discount {
	font-family: var(--ld-font-display);
	font-weight: var(--ld-fw-display);
	color: var(--ld-blue);
	white-space: nowrap;
}
.ld-account-active-offer-hint {
	margin: var(--ld-space-1) 0 0;
	font-size: var(--ld-fs-sm);
	color: var(--ld-text-muted);
}

/* ---------------------------------------------------------------------------
   SWE-590: interactive member panel — "View rewards" toggle opens an offers
   list with Claim buttons. Reuses the same design tokens as the balance card
   and the My Account awards list so the surfaces read as one system.
--------------------------------------------------------------------------- */
.ld-offers-toggle {
	display: inline-block;
	margin-top: var(--ld-space-2);
	padding: var(--ld-space-1) var(--ld-space-3);
	font-size: var(--ld-fs-sm);
	font-weight: var(--ld-fw-display);
	color: var(--ld-blue);
	background: transparent;
	border: 1px solid var(--ld-border);
	border-radius: var(--ld-radius-md);
	cursor: pointer;
}
.ld-offers-toggle:hover,
.ld-offers-toggle:focus-visible {
	background: var(--ld-surface-alt);
}
.ld-offers-panel {
	margin-top: var(--ld-space-2);
}
.ld-offers-panel[hidden] {
	display: none;
}
.ld-offers-list {
	list-style: none;
	margin: 0;
	padding: 0;
}
.ld-offer {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: var(--ld-space-2);
	padding: var(--ld-space-2) var(--ld-space-3);
	margin-top: var(--ld-space-2);
	background: var(--ld-surface-alt);
	border: 1px solid var(--ld-border);
	border-radius: var(--ld-radius-md);
}
.ld-offer-name {
	font-size: var(--ld-fs-base);
	color: var(--ld-text);
}
.ld-offer-cost {
	font-family: var(--ld-font-display);
	font-weight: var(--ld-fw-display);
	font-size: var(--ld-fs-sm);
	color: var(--ld-blue);
	white-space: nowrap;
}
.ld-offer-claim {
	padding: var(--ld-space-1) var(--ld-space-3);
	font-size: var(--ld-fs-sm);
	font-weight: var(--ld-fw-display);
	color: var(--ld-text-on-brand);
	background: var(--ld-blue);
	border: none;
	border-radius: var(--ld-radius-md);
	cursor: pointer;
}
.ld-offer-claim:hover,
.ld-offer-claim:focus-visible {
	filter: brightness(0.95);
}
.ld-offer-claim:disabled {
	opacity: 0.6;
	cursor: default;
}
.ld-panel-note {
	font-size: var(--ld-fs-sm);
	color: var(--ld-text-muted);
	margin: var(--ld-space-2) 0 0;
}
.ld-panel-error {
	font-size: var(--ld-fs-sm);
	color: var(--ld-error);
	margin: var(--ld-space-2) 0 0;
}

/* SWE-590 phase 2: tier-progress bar in the balance header. */
.ld-tier-progress {
	margin-top: var(--ld-space-2);
}
.ld-tier-progress-track {
	height: 8px;
	background: var(--ld-surface-sunken);
	border-radius: var(--ld-radius-md);
	overflow: hidden;
}
.ld-tier-progress-fill {
	height: 100%;
	background: var(--ld-blue);
	border-radius: var(--ld-radius-md);
}
.ld-tier-progress-label {
	font-size: var(--ld-fs-sm);
	color: var(--ld-text-muted);
	margin: var(--ld-space-1) 0 0;
}

/* ---------------------------------------------------------------------------
   SWE-590 phase 2: popup display mode. The "View rewards" launcher opens the
   rewards panel in a centered modal dialog (backdrop + fade/scale animation).
   Falls back to a no-animation show under prefers-reduced-motion.
--------------------------------------------------------------------------- */
.ld-modal-overlay {
	position: fixed;
	inset: 0;
	z-index: 100000;
	/* Always laid out (display:flex); visibility + opacity gate it so BOTH the
	   open and close transitions render. Using display:none would yank the
	   element from the render tree before the close fade could play, and
	   animating from display:none is spec-fragile (needs @starting-style).
	   visibility:hidden keeps the same AT semantics as display:none. The
	   visibility transition is delayed on close so it flips only after the
	   opacity fade finishes. */
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--ld-space-3);
	background: rgba(0, 0, 0, 0.5);
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}
.ld-modal-overlay.is-open {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	transition: opacity 0.18s ease, visibility 0s linear 0s;
}
.ld-modal {
	width: 100%;
	max-width: 420px;
	max-height: 85vh;
	overflow-y: auto;
	position: relative;
	padding: var(--ld-space-4, 24px) var(--ld-space-3);
	background: var(--ld-surface);
	color: var(--ld-text);
	border: 1px solid var(--ld-border);
	border-radius: var(--ld-radius-lg, 12px);
	box-shadow: 0 10px 40px rgba(0, 0, 0, 0.25);
	transform: scale(0.96);
	transition: transform 0.18s ease;
}
.ld-modal-overlay.is-open .ld-modal {
	transform: scale(1);
}
.ld-modal-close {
	position: absolute;
	top: var(--ld-space-2);
	right: var(--ld-space-2);
	width: 32px;
	height: 32px;
	line-height: 1;
	font-size: 22px;
	color: var(--ld-text-muted);
	background: transparent;
	border: none;
	border-radius: var(--ld-radius-md);
	cursor: pointer;
}
.ld-modal-close:hover,
.ld-modal-close:focus-visible {
	background: var(--ld-surface-alt);
}
.ld-modal-header {
	margin-bottom: var(--ld-space-2);
}
@media (prefers-reduced-motion: reduce) {
	.ld-modal-overlay,
	.ld-modal {
		transition: none;
	}
}

/* SWE-590 phase 2: redeem-points form in the rewards panel. */
.ld-redeem {
	margin-top: var(--ld-space-3);
	padding-top: var(--ld-space-3);
	border-top: 1px solid var(--ld-border);
}
.ld-redeem-heading {
	font-size: var(--ld-fs-sm);
	font-weight: var(--ld-fw-display);
	color: var(--ld-text);
	margin: 0 0 var(--ld-space-2);
}
.ld-redeem-row {
	display: flex;
	gap: var(--ld-space-2);
	align-items: center;
	/* SWE-655: wrap the button below in a narrow panel/sidebar rather than
	   squeezing the input — keeps the typed points visible on small widths. */
	flex-wrap: wrap;
}
.ld-redeem-input {
	/* SWE-655 (#1/#2): the input previously had min-width:0 and could collapse
	   below the digits being typed (the customer couldn't see their entry).
	   Give it a readable floor and let it grow; the row wraps if space is tight. */
	flex: 1 1 6em;
	min-width: 6em;
	padding: var(--ld-space-1) var(--ld-space-2);
	font-size: var(--ld-fs-base);
	color: var(--ld-text);
	background: var(--ld-surface);
	border: 1px solid var(--ld-border);
	border-radius: var(--ld-radius-md);
}
.ld-redeem-btn {
	flex: 0 0 auto;
	padding: var(--ld-space-1) var(--ld-space-3);
	font-size: var(--ld-fs-sm);
	font-weight: var(--ld-fw-display);
	color: var(--ld-text-on-brand);
	background: var(--ld-blue);
	border: none;
	border-radius: var(--ld-radius-md);
	cursor: pointer;
}
.ld-redeem-btn:hover,
.ld-redeem-btn:focus-visible {
	filter: brightness(0.95);
}
.ld-redeem-btn:disabled {
	opacity: 0.6;
	cursor: default;
}
/* SWE-653: live points→dollars preview under the redeem input. */
.ld-redeem-preview {
	margin: var(--ld-space-1) 0 0;
	font-size: var(--ld-fs-sm);
	color: var(--ld-text-muted);
	min-height: 1.2em; /* reserve space so the row doesn't jump as text toggles */
}
.ld-redeem-result {
	margin-top: var(--ld-space-2);
}
.ld-redeem-code-line {
	font-size: var(--ld-fs-sm);
	color: var(--ld-text);
	margin: 0;
}
.ld-redeem-code {
	font-weight: var(--ld-fw-display);
	background: var(--ld-surface-alt);
	padding: 2px 6px;
	border-radius: var(--ld-radius-md);
}
