/* Design tokens + the button system.
 *
 * THIS SHEET LOADS FIRST, before every other child stylesheet (see
 * $child_stylesheets in functions.php). Everything here is either a custom
 * property for others to consume or a component they can override. Nothing in
 * here should need to win a specificity fight against another CHILD sheet —
 * if it does, the rule is in the wrong file.
 *
 * ── Where the values come from ────────────────────────────────────────────────
 * The Figma button export (2026-09-15): three variants — Black, Grey 200 and
 * White — each with Default / Hover / Pressed / Disabled, plus the 46px round
 * arrow button.
 *
 * Scale factor is 1.0. Every number in that export is a clean integer (46, 20,
 * 16, 14, 1) and the text style reads 16px / 100% / -0.01em, which is what the
 * layers themselves report. Nothing needs a --scale multiplier. The one
 * inconsistency is called out at .wv-btn-arrow below.
 *
 * ── Why these tokens are on :root ─────────────────────────────────────────────
 * --gcp-* got here first and holds the same palette, but it is declared on
 * `.postid-6666` — the BODY element — because it was written for one page. That
 * scoping is load-bearing there and documented in giftCardProduct.css, but it
 * also means nothing outside that page can read it, which is why
 * ecoswapBulkRecipients.css had to re-alias every colour it wanted.
 *
 * :root is <html>, an ancestor of body, so these inherit everywhere including
 * into .postid-6666. --gcp-* now aliases these (with literal fallbacks intact),
 * making this the one place a brand colour is written down.
 *
 * Custom properties only inherit DOWNWARD. Declaring a token here and reading it
 * from a sheet that runs on an element outside <html> is fine; declaring one on
 * `body` and reading it from `:root` is the bug that cost a day in the bulk
 * sheet. Add new tokens HERE, not on body.
 */

:root {
	/* ── Neutral ramp ─────────────────────────────────────────────────────────
	 * Named for what they ARE, not for where they are used, so a second
	 * component can reach for grey-500 without inheriting button semantics.
	 * Figma calls #f5f5f5 "Grey 200"; the name is kept so the export and the
	 * stylesheet can be read side by side. */
	--wv-ink: #101011;         /* primary fill, and all text on light */
	--wv-white: #ffffff;
	--wv-grey-200: #f5f5f5;    /* secondary fill; also the page ground */
	--wv-grey-300: #e5e5e5;    /* disabled fill on light variants */
	--wv-grey-400: #c4c4c4;    /* disabled label on light variants */
	--wv-grey-500: #8d8b8b;    /* pressed border + label; disabled fill on ink */

	/* ── Button geometry ──────────────────────────────────────────────────────
	 * THESE ARE THE SITE DEFAULT, NOT THE FIGMA EXPORT. Set by Paul on
	 * 2026-09-16 after the export's size went live and was too big.
	 *
	 * The button export draws a 46px pill: 15px padding around 16px type. That
	 * is genuinely the right size ON THE GIFT CARD PAGE, which is what it was
	 * drawn for — a wide, uncluttered product page with three large controls.
	 * Applied site-wide it was wrong: the legacy buttons it replaced were 27px
	 * (the _green family) and 40px (_primary), so every button on the site grew,
	 * some by 92%, and the dense furniture — the sidebar, the mobile filter bar,
	 * the redeem modal — had been laid out around the smaller box.
	 *
	 * So the DEFAULT is now the compact tier, and the export's 46px is declared
	 * where the export actually applies: `.postid-6666` in giftCardProduct.css
	 * redeclares all four of these. That is the right way round — the value most
	 * buttons need is the default, and the one page with a different need opts
	 * out. It used to be the reverse, which is why every page paid for it.
	 *
	 * Height is reproduced through PADDING rather than a fixed height, so a
	 * label that wraps or a larger user font size grows the button instead of
	 * overflowing it. 10 + 14 + 10 = 34 exactly, with line-height 1.
	 * --wv-btn-min-h is the floor for the empty/icon-only case, and is a token
	 * so the compact tiers can lower it further (see ecoswapBulkRecipients.css).
	 *
	 * The RADIUS is not part of this: 9999px is a pill at any height, and it is
	 * the one geometry value the export and this page always agreed on. */
	--wv-btn-pad-y: 10px;
	--wv-btn-pad-x: 18px;
	--wv-btn-min-h: 34px;
	--wv-btn-radius: 9999px;

	/* Every state in the export is either borderless or carries a 1px border,
	 * and Figma grows the box to 92px when the border appears. We do NOT
	 * reproduce that growth: the base carries a transparent 1px border and
	 * box-sizing: border-box, so gaining a border on hover recolours it instead
	 * of reflowing the row. A 2px jump under the cursor is a worse bug than a
	 * 2px disagreement with the export. */
	--wv-btn-border-w: 1px;

	/* ── Button type ──────────────────────────────────────────────────────────
	 * DEFAULTS TO inherit, NOT TO GEIST, and that is deliberate.
	 *
	 * The export specifies Geist 500. Geist is only enqueued on the gift card
	 * page (functions.php — guarded by wayvo_gcp_is_gift_card_page), so naming
	 * it here would leave every other page asking for a font it never
	 * downloads and rendering the OceanWP customizer face at these metrics
	 * instead — silently, and looking almost right.
	 *
	 * So: inherit by default, and any page that HAS Geist opts in by setting
	 * --wv-btn-font. giftCardProduct.css does exactly that. If Geist is ever
	 * loaded site-wide, this one line becomes var(--wv-font) and every button
	 * follows.
	 *
	 * THAT HAPPENED ON 2026-09-16. Geist is now enqueued unconditionally in
	 * functions.php, so the reason for `inherit` — a font the page never
	 * downloads, rendering the customizer face at these metrics and looking
	 * almost right — no longer applies, and this is the line the note above
	 * said to change. Every button on the site now carries the export's face.
	 * giftCardProduct.css still sets it too; that is now a redundant restatement
	 * rather than an opt-in, and is harmless.
	 *
	 * This changes BUTTONS ONLY. Body copy and headings still come from the
	 * OceanWP customizer — putting the whole site into Geist is a customizer
	 * change, not this line. Revert to `inherit` to undo it. */
	--wv-btn-font: "Geist", "Geist Sans", sans-serif;
	/* 14px is the SITE DEFAULT; the export's 16px is restored on the gift card
	   page alongside the rest of its geometry. 14px is also what the _green
	   family and .dinkm_button_brand were already using, so the commonest
	   button on the site keeps the type size it has always had. */
	--wv-btn-size: 14px;
	--wv-btn-weight: 500;
	--wv-btn-tracking: -0.01em;

	/* Not in the export — the export has no notion of time. 150ms matches what
	 * the bulk sheet already used, and it is scoped to the three properties
	 * that actually change between states rather than `all`, which would also
	 * animate layout. */
	--wv-btn-duration: 150ms;

	/* ── Content width (Paul, 2026-10-21) ─────────────────────────────────────
	 * Boxes, titles and text stop at 1440 — the laptop frame every section is
	 * drawn on. Backgrounds, photos and carousels still run to the screen edge.
	 *
	 * Two ways a section uses it:
	 *
	 * 1. Nothing in it is full-bleed except a flat colour. The -wrap (the
	 *    container query container) is capped at --wv-content-max, so every
	 *    `100cqw / 1440` unit in the sheet stops at 1 by itself, and the colour
	 *    is painted past the box with a border-image outset — paint only, no
	 *    layout and no scrollbar.
	 *
	 * 2. Something in it must stay full-bleed (a photo, a carousel). The -wrap
	 *    stays 100vw, the sheet's units read --wv-cw instead of 100cqw, and the
	 *    content box is capped by hand.
	 *
	 * --wv-cw is "the container's width, but no more than the content max". It
	 * works from :root because an unregistered custom property is passed down
	 * as text: the cqw is resolved where it is USED, against that element's
	 * container, not here. Do not register it with @property — that would
	 * resolve it once, on <html>. */
	--wv-content-max: 1440px;
	--wv-cw: min(100cqw, var(--wv-content-max));

	/* The empty margin either side of a centred --wv-cw column: 0 up to the
	 * content width, then half of whatever is left over. Added to a section's
	 * own side padding to line its copy up with the column (pattern 2). */
	--wv-content-gutter: calc((100cqw - var(--wv-cw)) / 2);

	/* ── Scroll reveal (Paul, 2026-10-21: subtle) ─────────────────────────────
	 * Read by stylesheets/wayvo-reveal.css; which parts of which section move
	 * is listed in js/wayvo-reveal.js. "Make it all subtler / stronger" is
	 * these numbers and nothing else. An ease-OUT, not the hero's ease-in-out:
	 * things arriving should land softly rather than start slowly. */
	--wv-reveal-distance: 16px;
	--wv-reveal-scale: 0.98;      /* settle: panels grow from this */
	--wv-reveal-zoom: 1.04;       /* zoom: full-bleed photos shrink from this */
	--wv-reveal-duration: 700ms;
	--wv-reveal-stagger: 80ms;
	--wv-reveal-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* Phones: the same moves, shorter travel. */
@media (max-width: 767px) {
	:root {
		--wv-reveal-distance: 10px;
		--wv-reveal-scale: 0.985;
	}
}

/* ────────────────────────────────────────────────────────────────────────────
 * .wv-btn — the base
 *
 * Carries geometry and type ONLY. Colour lives on the variants, at two classes,
 * for a cascade reason that is easy to miss:
 *
 * OceanWP renders the customizer's Theme Buttons settings as an inline <style>
 * on wp_head at priority 9999 (oceanwp/functions.php:97) — AFTER every
 * enqueued stylesheet, including this one. Load order cannot win that fight.
 * And its colour rules are prefixed with `body`:
 *
 *     body .theme-button, body button, body .button { background-color: … }
 *
 * which is specificity 0,1,1. A rule on `.wv-btn` is 0,1,0 and LOSES on any
 * element that also carries `.button` — which on this site means every
 * WooCommerce button. `.wv-btn.wv-btn-primary` is 0,2,0 and wins, with no
 * !important anywhere. That is why the variants below repeat their properties
 * instead of the base reading var(--wv-btn-bg): a var() indirection would put
 * the real declaration back at 0,1,0 and hand the fight to the customizer.
 *
 * The customizer's own values should still be kept in step with these tokens —
 * see tests/test-buttons.js, which pins them.
 * ──────────────────────────────────────────────────────────────────────────── */

.wv-btn {
	display: inline-flex;
	flex-direction: row;
	justify-content: center;
	align-items: center;
	box-sizing: border-box;
	min-height: var(--wv-btn-min-h);
	padding: var(--wv-btn-pad-y) var(--wv-btn-pad-x);
	border: var(--wv-btn-border-w) solid transparent;
	border-radius: var(--wv-btn-radius);

	font-family: var(--wv-btn-font);
	font-size: var(--wv-btn-size);
	font-weight: var(--wv-btn-weight);
	font-style: normal;
	line-height: 1;
	letter-spacing: var(--wv-btn-tracking);
	/* The export's labels are single-line and the pill has no room to wrap
	   gracefully. Callers that genuinely need a wrapping button override this. */
	white-space: nowrap;
	text-align: center;
	/* Both resets are aimed at inherited styling rather than at nothing:
	   .dinkm_* buttons were uppercase with 0.1em tracking, and OceanWP
	   underlines <a> inside content. */
	text-decoration: none;
	text-transform: none;

	cursor: pointer;
	/* Safari draws its own pill on <button> and <input type=submit> and ignores
	   background-color until appearance is cleared. */
	-webkit-appearance: none;
	appearance: none;
	transition:
		background-color var(--wv-btn-duration) ease,
		color var(--wv-btn-duration) ease,
		border-color var(--wv-btn-duration) ease;
}

/* Anchors styled as buttons inherit OceanWP's link colour on hover otherwise,
   which beats the variant on colour alone and produces a black pill with a blue
   label. Specificity 0,2,0 to match the variants. */
a.wv-btn:hover,
a.wv-btn:focus {
	text-decoration: none;
}

@media (prefers-reduced-motion: reduce) {
	.wv-btn {
		transition: none;
	}
}

/* ── Primary — the export's Button_Black ──────────────────────────────────────
 *
 * HOVER INVERTS: the export declares no background at all on Button_Black's
 * hover and pressed states, only a border and dark text. That is a real
 * inversion to an outline button, not an omission — Grey 200 and White both
 * keep their fill on hover, so the file is being specific.
 *
 * It does mean the primary's hover state ASSUMES A LIGHT BACKDROP. On a dark
 * section it inverts to #101011 text on whatever is behind it and disappears.
 * Use .wv-btn-white there instead, or set a local hover override. */
.wv-btn.wv-btn-primary {
	background-color: var(--wv-ink);
	color: var(--wv-white);
	border-color: transparent;
}

/* :not(...) rather than ordering, so a disabled button can never pick up a
   hover or pressed state no matter what order these rules end up in after a
   refactor. [aria-disabled] is here because :disabled does not apply to <a>,
   and several of these buttons are anchors. */
.wv-btn.wv-btn-primary:hover:not(:where([disabled], [aria-disabled="true"])) {
	background-color: transparent;
	color: var(--wv-ink);
	border-color: var(--wv-ink);
}

.wv-btn.wv-btn-primary:active:not(:where([disabled], [aria-disabled="true"])) {
	background-color: transparent;
	color: var(--wv-grey-500);
	border-color: var(--wv-grey-500);
}

/* The export calls this one "State4" rather than Disabled, and it is the only
   variant whose disabled state is not the grey-300/grey-400 pair — a black
   button greys to #8d8b8b with #e5e5e5 on it. */
.wv-btn.wv-btn-primary[disabled],
.wv-btn.wv-btn-primary[aria-disabled="true"] {
	background-color: var(--wv-grey-500);
	color: var(--wv-grey-300);
	border-color: transparent;
}

/* ── Secondary — the export's Button_Grey 200 ─────────────────────────────── */
.wv-btn.wv-btn-secondary {
	background-color: var(--wv-grey-200);
	color: var(--wv-ink);
	border-color: transparent;
}

.wv-btn.wv-btn-secondary:hover:not(:where([disabled], [aria-disabled="true"])) {
	background-color: var(--wv-grey-200);
	color: var(--wv-ink);
	border-color: var(--wv-ink);
}

.wv-btn.wv-btn-secondary:active:not(:where([disabled], [aria-disabled="true"])) {
	background-color: var(--wv-grey-200);
	color: var(--wv-grey-500);
	border-color: var(--wv-grey-500);
}

.wv-btn.wv-btn-secondary[disabled],
.wv-btn.wv-btn-secondary[aria-disabled="true"] {
	background-color: var(--wv-grey-300);
	color: var(--wv-grey-400);
	border-color: transparent;
}

/* ── White — the export's Button_White ────────────────────────────────────────
 *
 * NEEDS A NON-WHITE BACKDROP. Its default state is #ffffff with NO border, so
 * on a white panel it is an invisible control with floating text — it only
 * becomes an outline on hover. The export is drawn on grey, and this variant
 * exists for dark sections, tinted bands and card artwork. On white use
 * .wv-btn-secondary, which is the same shape with a fill you can see. */
.wv-btn.wv-btn-white {
	background-color: var(--wv-white);
	color: var(--wv-ink);
	border-color: transparent;
}

.wv-btn.wv-btn-white:hover:not(:where([disabled], [aria-disabled="true"])) {
	background-color: var(--wv-white);
	color: var(--wv-ink);
	border-color: var(--wv-ink);
}

.wv-btn.wv-btn-white:active:not(:where([disabled], [aria-disabled="true"])) {
	background-color: var(--wv-white);
	color: var(--wv-grey-500);
	border-color: var(--wv-grey-500);
}

.wv-btn.wv-btn-white[disabled],
.wv-btn.wv-btn-white[aria-disabled="true"] {
	background-color: var(--wv-grey-300);
	color: var(--wv-grey-400);
	border-color: transparent;
}

/* ── Focus ───────────────────────────────────────────────────────────────────
 * Not in the export, which has no focus state for any variant. Omitting it is
 * not an option: these are buttons, some are the only way to complete a
 * purchase, and clearing the UA outline without a replacement makes the site
 * unusable by keyboard.
 *
 * :focus-visible so it shows for keyboard and not on mouse click. Drawn as an
 * outline with an offset rather than as a border, because a border would have
 * to fight the state rules above for the same property. */
.wv-btn:focus-visible {
	outline: 2px solid var(--wv-ink);
	outline-offset: 2px;
}

/* ── Arrow button ────────────────────────────────────────────────────────────
 *
 * 46x46 ink circle holding a 16x14 white glyph — the carousel/stepper control.
 *
 * Fixed square, and padding: 0 overriding the base. The export reports
 * `padding: 0px 20px` on a 46px-wide box, which is impossible with a 16px
 * glyph inside; the 46 is the number that appears in the PNGs and in
 * --gcp-button-height, so the padding is what gets dropped.
 *
 * The export also puts transform: rotate(-180deg) on BOTH the button and the
 * glyph. That is Figma recording a flipped instance — the two cancel out, and
 * neither belongs here. Direction comes from the markup: use two instances and
 * rotate the GLYPH, or ship left and right SVGs. Rotating this class would
 * also rotate the focus outline.
 *
 * MARKUP IS `class="wv-btn wv-btn-arrow"` — both classes, exactly like the
 * three text variants, and for the same reason. Written as `.wv-btn-arrow`
 * alone this is 0,1,0, which loses to the customizer's `body button` (0,1,1)
 * on an arrow button that is a <button> element — which it always is. The
 * arrow is a variant of the system, not a sibling of it. */
.wv-btn.wv-btn-arrow {
	display: inline-flex;
	justify-content: center;
	align-items: center;
	box-sizing: border-box;
	width: var(--wv-btn-min-h);
	height: var(--wv-btn-min-h);
	min-height: 0;
	padding: 0;
	border: var(--wv-btn-border-w) solid transparent;
	border-radius: var(--wv-btn-radius);
	background-color: var(--wv-ink);
	color: var(--wv-white);
	cursor: pointer;
	-webkit-appearance: none;
	appearance: none;
	transition: background-color var(--wv-btn-duration) ease,
		border-color var(--wv-btn-duration) ease;
}

/* The export gives the glyph `background: #FFFFFF`, which is Figma's way of
   reporting a vector FILL. Reproduced as currentColor on the SVG so the glyph
   follows the button's colour through its states, and as a size cap so an
   oversized asset cannot blow the circle open. */
.wv-btn-arrow > svg,
.wv-btn-arrow > img {
	width: 16px;
	height: 14px;
	fill: currentColor;
	flex: none;
}

.wv-btn.wv-btn-arrow:hover:not(:where([disabled], [aria-disabled="true"])) {
	background-color: transparent;
	color: var(--wv-ink);
	border-color: var(--wv-ink);
}

.wv-btn.wv-btn-arrow[disabled],
.wv-btn.wv-btn-arrow[aria-disabled="true"] {
	background-color: var(--wv-grey-500);
	color: var(--wv-grey-300);
	border-color: transparent;
	cursor: not-allowed;
}

/* Disabled cursor for the text variants. Separate from the colour rules so it
   applies to all three without repeating. pointer-events is deliberately NOT
   set to none — that would also suppress the cursor and any tooltip. */
.wv-btn[disabled],
.wv-btn[aria-disabled="true"] {
	cursor: not-allowed;
}

/* ────────────────────────────────────────────────────────────────────────────
 * LEGACY — .dinkm_button_primary
 *
 * MOVED HERE FROM style.css 2026-09-15, and REBUILT on the tokens above.
 *
 * It had to move sheets, not just change values: style.css is enqueued LAST
 * (functions.php), so while this rule lived there it outranked every
 * token-based rule in the sheets before it on load order alone. A legacy
 * component that cannot be overridden from the token layer is the thing this
 * refactor exists to remove.
 *
 * What it used to be: #0a0a0a, 12px, weight 600, UPPERCASE, 0.1em tracking,
 * 14px/20px padding, and a mint #00f0a7 hover. Nothing in the current design
 * system has a mint hover or uppercase button labels — it predates it.
 *
 * WHAT THIS CHANGES ON THE SITE: three <button> elements, in
 * partials/balanceBar.php, partials/balanceBar_brands.php and
 * partials/brands/redemption2.php — the "redeem" control on the balance bar and
 * on a brand page. They are now mixed-case 16px pills that invert on hover
 * instead of turning mint.
 *
 * The WIDER .dinkm_button_* family (_green, _white, _grey, _toggle, _brand) is
 * used from many more templates and is NOT migrated — those rules are still in
 * style.css on the old palette. Do not assume this class's siblings look like
 * it does.
 *
 * Kept as an alias rather than renamed because those templates are not in this
 * pass. New markup should use .wv-btn .wv-btn-primary directly; this is a
 * shim, and every template converted is one step closer to deleting it.
 *
 * ── WHY THE CLASS IS DOUBLED ────────────────────────────────────────────────
 *
 * `.dinkm_button_primary.dinkm_button_primary` is the same element twice. It
 * matches exactly what the single class matches and changes nothing about which
 * buttons are selected — it only raises specificity from 0,1,0 to 0,2,0.
 *
 * It is needed because all three usages are <button> elements
 * (dinkm-wallet.php, partials/balanceBar*.php, partials/brands/*), and the
 * customizer's generated block contains `body button` at 0,1,1 and
 * `body button[type="submit"]` at 0,1,2. At one class this rule LOSES both, so
 * the buttons would take their colours and hover from the admin panel while
 * appearing to be styled here. With the customizer set to the same ink the
 * default state would look correct and only the hover would be wrong, which is
 * the worst version of this bug — it looks fine until someone points.
 *
 * The alternative was !important, which would make the next override
 * unwinnable. THE REAL FIX is converting those templates to
 * `class="wv-btn wv-btn-primary"`, which needs no specificity trick at all;
 * this doubling exists to be deleted with the shim. Pinned in
 * tests/test-buttons.js so it cannot be "tidied" back to one class.
 * ──────────────────────────────────────────────────────────────────────────── */

.dinkm_button_primary.dinkm_button_primary {
	display: inline-flex;
	justify-content: center;
	align-items: center;
	box-sizing: border-box;
	min-height: var(--wv-btn-min-h);
	margin: 0;
	padding: var(--wv-btn-pad-y) var(--wv-btn-pad-x);
	border: var(--wv-btn-border-w) solid transparent;
	border-radius: var(--wv-btn-radius);

	font-family: var(--wv-btn-font);
	font-size: var(--wv-btn-size);
	font-weight: var(--wv-btn-weight);
	line-height: 1;
	letter-spacing: var(--wv-btn-tracking);
	text-align: center;
	text-decoration: none;
	/* Explicitly none: the old rule set uppercase and these templates are
	   written in sentence case expecting it. */
	text-transform: none;

	background-color: var(--wv-ink);
	color: var(--wv-white);
	cursor: pointer;
	-webkit-appearance: none;
	appearance: none;
	transition:
		background-color var(--wv-btn-duration) ease,
		color var(--wv-btn-duration) ease,
		border-color var(--wv-btn-duration) ease;
}

.dinkm_button_primary.dinkm_button_primary:hover {
	background-color: transparent;
	color: var(--wv-ink);
	border-color: var(--wv-ink);
	text-decoration: none;
}

.dinkm_button_primary.dinkm_button_primary[disabled],
.dinkm_button_primary.dinkm_button_primary[aria-disabled="true"] {
	background-color: var(--wv-grey-500);
	color: var(--wv-grey-300);
	border-color: transparent;
	cursor: not-allowed;
}

.dinkm_button_primary.dinkm_button_primary:focus-visible {
	outline: 2px solid var(--wv-ink);
	outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
	.dinkm_button_primary.dinkm_button_primary {
		transition: none;
	}
}

/* ── The rest of the .dinkm_button_* family ───────────────────────────────────
 * Migrated 2026-09-16, finishing what the _primary shim started. Their rules
 * are GONE from style.css — see the note at the top of that file.
 *
 * Mapping, decided with Paul:
 *
 *     .dinkm_button_green        x21  ->  primary    (ink, inverts on hover)
 *     .ecoswap_button_lightGreen x1   ->  primary
 *     .dinkm_button_white        x5   ->  secondary  (grey 200 fill)
 *     .dinkm_button_grey         x2   ->  tertiary   (neutral, muted label)
 *     .dinkm_button_toggle       x0   ->  deleted, it had no usages
 *     .dinkm_button_brand        x6   ->  untouched; geometry only, and it is
 *                                        always paired with _green, so it
 *                                        follows along
 *
 * Teal #00514B and mint #00f0a7 are now absent from every button on the site.
 *
 * ── WHY display: flex, WHEN .wv-btn USES inline-flex ─────────────────────────
 *
 * Not an oversight, and not copied carelessly. The old rules set `display:
 * flex`, which makes a <button> BLOCK-level and therefore full-bleed in a block
 * container. `inline-flex` shrinks it to its label. Every one of these 29
 * elements is a <button>, and several sit in layouts that were built around the
 * full-width box — the redeem modal, the sidebar, the mobile filter bar.
 *
 * _primary could safely become inline-flex because its old value was
 * `inline-block`: inline-level either way, so the box never moved. That is not
 * true here. This migration changes PALETTE AND TYPE ONLY; relayouting 29
 * buttons is a separate decision and should be taken one template at a time.
 *
 * ── WHAT THIS VISIBLY CHANGES ────────────────────────────────────────────────
 *
 * Beyond the colour: these were 14px labels in 5px/15px padding, a ~28px tall
 * control. They now take the system's 46px pill. In tight furniture — the
 * mobile filter bar especially — that is a real size jump. The escape hatch is
 * the one ecoswapBulkRecipients.css already uses: override the TOKENS on a
 * local wrapper rather than re-hardcoding the button.
 *
 *     .mobile_filters_btn { --wv-btn-pad-y: 10px; --wv-btn-size: 14px; }
 *
 * ── Doubled classes, same reason as _primary ─────────────────────────────────
 *
 * All 29 are <button>, so they meet `body button` (0,1,1) and several are
 * type="submit", meeting `body button[type="submit"]` (0,1,2). One class is
 * 0,1,0 and loses both. Doubling buys 0,2,0 and wins with no !important.
 * Pinned in tests/test-buttons.js so it cannot be "tidied" back.
 * ──────────────────────────────────────────────────────────────────────────── */

/* Shared box. Kept separate from the colour rules below so the three mappings
   read as nothing but a palette. */
.dinkm_button_green.dinkm_button_green,
.ecoswap_button_lightGreen.ecoswap_button_lightGreen,
.dinkm_button_white.dinkm_button_white,
.dinkm_button_grey.dinkm_button_grey {
	display: flex;
	justify-content: center;
	align-items: center;
	box-sizing: border-box;
	min-height: var(--wv-btn-min-h);
	padding: var(--wv-btn-pad-y) var(--wv-btn-pad-x);
	border: var(--wv-btn-border-w) solid transparent;
	border-radius: var(--wv-btn-radius);

	font-family: var(--wv-btn-font);
	font-size: var(--wv-btn-size);
	font-weight: var(--wv-btn-weight);
	line-height: 1;
	letter-spacing: var(--wv-btn-tracking);
	text-align: center;
	text-decoration: none;
	text-transform: none;

	cursor: pointer;
	-webkit-appearance: none;
	appearance: none;
	transition:
		background-color var(--wv-btn-duration) ease,
		color var(--wv-btn-duration) ease,
		border-color var(--wv-btn-duration) ease;
}

/* ── _green and _lightGreen -> primary ─────────────────────────────────────── */
.dinkm_button_green.dinkm_button_green,
.ecoswap_button_lightGreen.ecoswap_button_lightGreen {
	background-color: var(--wv-ink);
	color: var(--wv-white);
	border-color: transparent;
}

.dinkm_button_green.dinkm_button_green:hover:not(:where([disabled], [aria-disabled="true"])),
.ecoswap_button_lightGreen.ecoswap_button_lightGreen:hover:not(:where([disabled], [aria-disabled="true"])) {
	background-color: transparent;
	color: var(--wv-ink);
	border-color: var(--wv-ink);
	text-decoration: none;
}

.dinkm_button_green.dinkm_button_green:active:not(:where([disabled], [aria-disabled="true"])),
.ecoswap_button_lightGreen.ecoswap_button_lightGreen:active:not(:where([disabled], [aria-disabled="true"])) {
	background-color: transparent;
	color: var(--wv-grey-500);
	border-color: var(--wv-grey-500);
}

/* #redeem_btn ships with the `disabled` attribute set in the markup and is
   enabled from JS, so this state is on screen before any interaction. */
.dinkm_button_green.dinkm_button_green[disabled],
.dinkm_button_green.dinkm_button_green[aria-disabled="true"],
.ecoswap_button_lightGreen.ecoswap_button_lightGreen[disabled],
.ecoswap_button_lightGreen.ecoswap_button_lightGreen[aria-disabled="true"] {
	background-color: var(--wv-grey-500);
	color: var(--wv-grey-300);
	border-color: transparent;
	cursor: not-allowed;
}

/* ── _white -> secondary ──────────────────────────────────────────────────────
 * The old rule was a WHITE fill with a 3px teal border, and it is used on white
 * dashboard panels, where the system's .wv-btn-white would be an invisible
 * control with floating text. Secondary is the variant with a fill you can see
 * on white — see the note at .wv-btn-white above. */
.dinkm_button_white.dinkm_button_white {
	background-color: var(--wv-grey-200);
	color: var(--wv-ink);
	border-color: transparent;
}

.dinkm_button_white.dinkm_button_white:hover:not(:where([disabled], [aria-disabled="true"])) {
	background-color: var(--wv-grey-200);
	color: var(--wv-ink);
	border-color: var(--wv-ink);
	text-decoration: none;
}

.dinkm_button_white.dinkm_button_white:active:not(:where([disabled], [aria-disabled="true"])) {
	background-color: var(--wv-grey-200);
	color: var(--wv-grey-500);
	border-color: var(--wv-grey-500);
}

.dinkm_button_white.dinkm_button_white[disabled],
.dinkm_button_white.dinkm_button_white[aria-disabled="true"] {
	background-color: var(--wv-grey-300);
	color: var(--wv-grey-400);
	border-color: transparent;
	cursor: not-allowed;
}

/* ── _grey -> tertiary ────────────────────────────────────────────────────────
 * The one family that is NOT a variant of the export. It was #f4f4f4 with a
 * #d6d6d6 border and a #656565 label — a deliberately quiet control, and both
 * usages are filter toggles that must not compete with the primary action.
 * So it stays quiet, just on the neutral ramp instead of on loose hex. It
 * keeps a RESTING border, which secondary does not: without one it is
 * indistinguishable from the grey-200 panel it sits on. */
.dinkm_button_grey.dinkm_button_grey {
	background-color: var(--wv-grey-200);
	color: var(--wv-grey-500);
	border-color: var(--wv-grey-300);
}

.dinkm_button_grey.dinkm_button_grey:hover:not(:where([disabled], [aria-disabled="true"])) {
	background-color: var(--wv-grey-200);
	color: var(--wv-ink);
	border-color: var(--wv-ink);
	text-decoration: none;
}

.dinkm_button_grey.dinkm_button_grey:active:not(:where([disabled], [aria-disabled="true"])) {
	background-color: var(--wv-grey-200);
	color: var(--wv-grey-500);
	border-color: var(--wv-grey-500);
}

.dinkm_button_grey.dinkm_button_grey[disabled],
.dinkm_button_grey.dinkm_button_grey[aria-disabled="true"] {
	background-color: var(--wv-grey-300);
	color: var(--wv-grey-400);
	border-color: transparent;
	cursor: not-allowed;
}

/* Anchors styled as buttons: OceanWP underlines <a> in content and its link
   colour beats the mapping on colour alone. Same guard the base carries. */
a.dinkm_button_green:hover,
a.dinkm_button_green:focus,
a.ecoswap_button_lightGreen:hover,
a.ecoswap_button_lightGreen:focus,
a.dinkm_button_white:hover,
a.dinkm_button_white:focus,
a.dinkm_button_grey:hover,
a.dinkm_button_grey:focus {
	text-decoration: none;
}

.dinkm_button_green.dinkm_button_green:focus-visible,
.ecoswap_button_lightGreen.ecoswap_button_lightGreen:focus-visible,
.dinkm_button_white.dinkm_button_white:focus-visible,
.dinkm_button_grey.dinkm_button_grey:focus-visible {
	outline: 2px solid var(--wv-ink);
	outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
	.dinkm_button_green.dinkm_button_green,
	.ecoswap_button_lightGreen.ecoswap_button_lightGreen,
	.dinkm_button_white.dinkm_button_white,
	.dinkm_button_grey.dinkm_button_grey {
		transition: none;
	}
}

/* ── FOCUS GUARD — Elementor Site Settings paints `button:focus` ──────────────
 * Added 2026-10-15. Elementor's Site Settings -> Buttons writes
 *
 *     .elementor-kit-N button:hover, .elementor-kit-N button:focus { … }
 *
 * at 0,2,1, in a sheet that loads after this one. The hovers above are 0,3,0
 * and win; the RESTING colours are 0,2,0 and do not — so a <button> that has
 * just been clicked takes the kit's hover colours and keeps them until it
 * loses focus. Every one of the families below has <button> usages.
 *
 * :not(:hover, :active, …) rather than ordering: it is 0,4,0, and it simply
 * stops matching once the hover, pressed or disabled rule should take over.
 * (A :not() list is as specific as its most specific argument — one class.)
 *
 * .wv-btn-arrow is deliberately NOT here. Both of its consumers recolour it at
 * 0,3,0 (.wv-fbs / .wv-afb, white circles), which already beats the kit; a
 * guard here at 0,4,0 would paint them ink whenever focused.
 * ──────────────────────────────────────────────────────────────────────────── */

.wv-btn.wv-btn-primary:focus:not(:hover, :active, [disabled], [aria-disabled="true"]),
.dinkm_button_primary.dinkm_button_primary:focus:not(:hover, :active, [disabled], [aria-disabled="true"]),
.dinkm_button_green.dinkm_button_green:focus:not(:hover, :active, [disabled], [aria-disabled="true"]),
.ecoswap_button_lightGreen.ecoswap_button_lightGreen:focus:not(:hover, :active, [disabled], [aria-disabled="true"]) {
	background-color: var(--wv-ink);
	color: var(--wv-white);
	border-color: transparent;
}

.wv-btn.wv-btn-secondary:focus:not(:hover, :active, [disabled], [aria-disabled="true"]),
.dinkm_button_white.dinkm_button_white:focus:not(:hover, :active, [disabled], [aria-disabled="true"]) {
	background-color: var(--wv-grey-200);
	color: var(--wv-ink);
	border-color: transparent;
}

.wv-btn.wv-btn-white:focus:not(:hover, :active, [disabled], [aria-disabled="true"]) {
	background-color: var(--wv-white);
	color: var(--wv-ink);
	border-color: transparent;
}

.dinkm_button_grey.dinkm_button_grey:focus:not(:hover, :active, [disabled], [aria-disabled="true"]) {
	background-color: var(--wv-grey-200);
	color: var(--wv-grey-500);
	border-color: var(--wv-grey-300);
}

/* ── ELEMENTOR BRIDGE ─────────────────────────────────────────────────────────
 * Added 2026-09-16 so a button built in Elementor can take the system's look
 * without anyone hand-writing CSS.
 *
 * ── HOW TO USE IT ───────────────────────────────────────────────────────────
 *
 *   Select the Button widget -> Advanced -> CSS Classes, and type ONE of:
 *
 *       wv-btn-primary       ink, inverts to an outline on hover
 *       wv-btn-secondary     grey 200 fill, gains an ink border on hover
 *       wv-btn-white         white, for dark sections ONLY
 *
 *   Then LEAVE THE STYLE TAB ALONE. That is not a style preference, it is the
 *   one thing that breaks this — see the specificity note below.
 *
 * ── WHY A BRIDGE IS NEEDED AT ALL ───────────────────────────────────────────
 *
 * Two problems, and neither is obvious from looking at the page.
 *
 * 1. ELEMENTOR LOADS AFTER EVERY CHILD STYLESHEET. Verified on the live site:
 *    the child sheets are links 8-22 in the head and elementor-frontend is 29.
 *    So anything that merely TIES with Elementor on specificity loses. Plain
 *    `.wv-btn` is 0,1,0 and `.elementor-button` is also 0,1,0 — and Elementor's
 *    sets padding: 12px 24px, border-radius: 3px and font-size: 15px. The
 *    colours would land (the variants are 0,2,0) and the geometry would not, so
 *    the button would look almost right, which is the worst outcome.
 *
 * 2. THE CLASS DOES NOT GO WHERE YOU THINK. Elementor's CSS Classes field puts
 *    the class on the widget WRAPPER, not on the <a class="elementor-button">
 *    that actually draws the button. So the bridge is a DESCENDANT selector.
 *    The second form below also matches the class landing directly on the
 *    anchor, for an HTML widget or a template that writes its own markup.
 *
 * `.elementor-widget.wv-btn-primary .elementor-button` is 0,3,0, which clears
 * `.elementor-button.elementor-size-md` (0,2,0) — the size classes are the ones
 * that carry min-height, padding and radius.
 *
 * ── THE ONE THING THAT DEFEATS IT ───────────────────────────────────────────
 *
 * Setting anything in the widget's STYLE tab. Elementor then writes a per-page
 * rule like
 *
 *     .elementor-2887 .elementor-element.elementor-element-abc .elementor-button
 *
 * which is 0,4,0 AND loads later still, so it beats everything here. If a
 * bridged button looks wrong, check the Style tab before checking this file.
 * Use the CSS Classes field and nothing else.
 * ──────────────────────────────────────────────────────────────────────────── */

.elementor-widget.wv-btn-primary .elementor-button,
.elementor-widget.wv-btn-secondary .elementor-button,
.elementor-widget.wv-btn-white .elementor-button,
.elementor-button.wv-btn.wv-btn {
	display: inline-flex;
	justify-content: center;
	align-items: center;
	box-sizing: border-box;
	min-height: var(--wv-btn-min-h);
	padding: var(--wv-btn-pad-y) var(--wv-btn-pad-x);
	border: var(--wv-btn-border-w) solid transparent;
	border-radius: var(--wv-btn-radius);

	font-family: var(--wv-btn-font);
	font-size: var(--wv-btn-size);
	font-weight: var(--wv-btn-weight);
	line-height: 1;
	letter-spacing: var(--wv-btn-tracking);
	text-transform: none;
	text-decoration: none;

	/* Elementor animates `all` for .3s, which includes padding and min-height —
	   so a hover that changes nothing but colour still animates the box. */
	transition:
		background-color var(--wv-btn-duration) ease,
		color var(--wv-btn-duration) ease,
		border-color var(--wv-btn-duration) ease;
}

/* Elementor sets `fill: #fff` alongside colour for button icons. Left as
   currentColor it follows the label through the inverted hover instead of
   staying white on a transparent background. */
.elementor-widget.wv-btn-primary .elementor-button svg,
.elementor-widget.wv-btn-secondary .elementor-button svg,
.elementor-widget.wv-btn-white .elementor-button svg,
.elementor-button.wv-btn.wv-btn svg {
	fill: currentColor;
}

/* ── Primary ─────────────────────────────────────────────────────────────── */
.elementor-widget.wv-btn-primary .elementor-button,
.elementor-button.wv-btn.wv-btn-primary {
	background-color: var(--wv-ink);
	color: var(--wv-white);
	border-color: transparent;
}

/* :visited is in here because Elementor's own rule is
   `.elementor-button:focus, .elementor-button:hover, .elementor-button:visited`
   at 0,2,0, forcing color:#fff on all three. An inverted hover needs INK text,
   so each state has to be named explicitly to outrank it. */
.elementor-widget.wv-btn-primary .elementor-button:hover:not(:where([disabled], [aria-disabled="true"], .disabled)),
.elementor-widget.wv-btn-primary .elementor-button:focus:not(:where([disabled], [aria-disabled="true"], .disabled)),
.elementor-button.wv-btn.wv-btn-primary:hover:not(:where([disabled], [aria-disabled="true"], .disabled)),
.elementor-button.wv-btn.wv-btn-primary:focus:not(:where([disabled], [aria-disabled="true"], .disabled)) {
	background-color: transparent;
	color: var(--wv-ink);
	border-color: var(--wv-ink);
}

/* ── Secondary ───────────────────────────────────────────────────────────── */
.elementor-widget.wv-btn-secondary .elementor-button,
.elementor-button.wv-btn.wv-btn-secondary {
	background-color: var(--wv-grey-200);
	color: var(--wv-ink);
	border-color: transparent;
}

.elementor-widget.wv-btn-secondary .elementor-button:hover:not(:where([disabled], [aria-disabled="true"], .disabled)),
.elementor-widget.wv-btn-secondary .elementor-button:focus:not(:where([disabled], [aria-disabled="true"], .disabled)),
.elementor-button.wv-btn.wv-btn-secondary:hover:not(:where([disabled], [aria-disabled="true"], .disabled)),
.elementor-button.wv-btn.wv-btn-secondary:focus:not(:where([disabled], [aria-disabled="true"], .disabled)) {
	background-color: var(--wv-grey-200);
	color: var(--wv-ink);
	border-color: var(--wv-ink);
}

/* ── White — dark sections only, see the note at .wv-btn-white ───────────── */
.elementor-widget.wv-btn-white .elementor-button,
.elementor-button.wv-btn.wv-btn-white {
	background-color: var(--wv-white);
	color: var(--wv-ink);
	border-color: transparent;
}

.elementor-widget.wv-btn-white .elementor-button:hover:not(:where([disabled], [aria-disabled="true"], .disabled)),
.elementor-widget.wv-btn-white .elementor-button:focus:not(:where([disabled], [aria-disabled="true"], .disabled)),
.elementor-button.wv-btn.wv-btn-white:hover:not(:where([disabled], [aria-disabled="true"], .disabled)),
.elementor-button.wv-btn.wv-btn-white:focus:not(:where([disabled], [aria-disabled="true"], .disabled)) {
	background-color: var(--wv-white);
	color: var(--wv-ink);
	border-color: var(--wv-ink);
}

@media (prefers-reduced-motion: reduce) {
	.elementor-widget.wv-btn-primary .elementor-button,
	.elementor-widget.wv-btn-secondary .elementor-button,
	.elementor-widget.wv-btn-white .elementor-button,
	.elementor-button.wv-btn.wv-btn {
		transition: none;
	}
}

/* ────────────────────────────────────────────────────────────────────────────
 * PHONES: ONE BUTTON SIZE, SITE-WIDE (Paul, 2026-10-21)
 *
 * Every button on a phone is the home hero's: 15px label (14, then one
 * size up the same day), 35 tall, 7 / 14 padding. Most sections had drawn their phone buttons at 12px (the exports'
 * scaled-down S button) and on a real phone they read too small.
 *
 * Set ON THE BUTTON, with !important, rather than on :root. The sections set
 * these tokens on their own containers (and a few on the button itself), and
 * an element's own declaration beats an inherited one — !important then beats
 * the few section rules that target the button directly. The tokens are still
 * the only thing set, so colour, radius and type family stay each button's own.
 *
 * NOT the hero's own buttons: js/wayvo-hero-section.js (fitButtons) shrinks
 * those only when the pair would not fit on one line, and an !important here
 * would stop it. They are already this size. Not the round arrow buttons,
 * which take their width and height from --wv-btn-min-h.
 *
 * Elementor's STYLE tab still beats this (see the bridge above) — a button
 * whose size is set there keeps it.
 * ──────────────────────────────────────────────────────────────────────────── */
@media (max-width: 767px) {
	.wv-btn:not(.wv-btn-arrow):not(.wv-hero__actions > *),
	.dinkm_button_primary.dinkm_button_primary,
	.dinkm_button_green.dinkm_button_green,
	.ecoswap_button_lightGreen.ecoswap_button_lightGreen,
	.dinkm_button_white.dinkm_button_white,
	.dinkm_button_grey.dinkm_button_grey,
	.elementor-widget.wv-btn-primary .elementor-button,
	.elementor-widget.wv-btn-secondary .elementor-button,
	.elementor-widget.wv-btn-white .elementor-button {
		--wv-btn-size: 15px !important;
		--wv-btn-min-h: 35px !important;
		--wv-btn-pad-y: 7px !important;
		--wv-btn-pad-x: 14px !important;
	}
}
