/**
 * Block Hover — Effects + Hover Colors
 *
 * Button effects (59 across 16 groups): each targets
 * `.wp-block-button.has-hover-{slug} .wp-block-button__link`.
 * Container effects (curated subset for core/group and core/column): each
 * targets `.wp-block-{group|column}.has-hover-{slug}` directly — see the
 * CONTAINER EFFECTS section near the bottom of this file.
 * Hover colors (all three blocks): see the HOVER COLORS section at the end.
 * All opt-in via the unified Hover panel in the block inspector.
 *
 * The structural setup that the reference's `.fx` base class provided
 * (position, overflow, isolation, transition) is folded into each effect's
 * CSS rather than applied globally — buttons without a hover effect should
 * pay zero cost.
 *
 * Per-style defaults (bottom of file): each of the 10 button styles in the
 * button-styles extension gets a default hover behavior chosen from this
 * effect catalogue. Defaults apply only when the button has no `has-hover-*`
 * class — picking any effect (or "None") in the dropdown suppresses the
 * default via the `:not([class*="has-hover-fx-"]):not(.has-hover-none)` gate.
 *
 * "None" sentinel: the dropdown's None option sets the attribute to "none",
 * which applies `has-hover-none` to the wrapper. There is no CSS for that
 * class — it exists only to defeat `:not([class*="has-hover-fx-"]):not(.has-hover-none)` and turn
 * off the per-style default. A button with `hoverEffect=""` (legacy or
 * unconfigured) keeps the default; a button with `hoverEffect="none"` does not.
 *
 * Token strategy:
 * - Every color references a semantic role token via CSS custom properties.
 * - Reveal/swipe/fill/radius-flip effects read the hover background color via
 *   `var(--le-hover-bg, var(--hover-bg, fallback))` — preferring the unified
 *   `--le-hover-bg` set by the Color panel's "Hover background" control, then
 *   the legacy `--hover-bg` (kept for back-compat with existing
 *   `hoverBackgroundColor` data), then the preset fallback (accent for most;
 *   text for fx-fill / Ghost / Dashed). Users pick once in the Color panel
 *   and that one color drives both the always-on hover background and any
 *   effect's reveal animation.
 * - The rainbow border effects (Group N) hardcode a literal gradient. This is
 *   the only hardcoded color in the entire system — by design, since "rainbow"
 *   has no semantic equivalent. See the comment block above those rules.
 */

/* ============================================================
   Shared transition baseline.
   Applied to:
   - any button carrying a has-hover-* class (including has-hover-none —
     harmless, since none has no CSS to transition)
   - any of the 10 named block styles when no has-hover-* class is present,
     so the per-style default's hover transition animates smoothly
   ============================================================ */
.wp-block-button[class*="has-hover-"] > .wp-block-button__link,
.wp-block-button:is(
	.is-style-solid,
	.is-style-ghost,
	.is-style-pill,
	.is-style-brutal,
	.is-style-slanted,
	.is-style-3d-press,
	.is-style-soft,
	.is-style-dashed,
	.is-style-asymmetric,
	.is-style-editorial
):not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link {
	position: relative;
	transition:
		transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1),
		background-color 0.45s ease,
		color 0.35s ease,
		box-shadow 0.45s ease,
		border-radius 0.45s ease,
		letter-spacing 0.35s ease,
		top 0.15s ease,
		opacity 0.35s ease,
		padding 0.35s ease,
		filter 0.35s ease;
}

/* ============================================================
   GROUP A — Translation
   ============================================================ */
.wp-block-button.has-hover-fx-lift > .wp-block-button__link:hover {
	transform: translateY(-6px);
	box-shadow: 0 14px 28px -10px rgba(0, 0, 0, 0.45);
}

/* Subtle 1–2px lift, distinct from the larger fx-lift. Used as Solid's default. */
.wp-block-button.has-hover-fx-lift-soft > .wp-block-button__link:hover {
	transform: translateY(-2px);
	filter: brightness(0.92);
}

.wp-block-button.has-hover-fx-push > .wp-block-button__link:hover {
	transform: translateY(6px);
	box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
}

.wp-block-button.has-hover-fx-slide-l > .wp-block-button__link:hover {
	transform: translateX(-6px);
	box-shadow: 8px 0 18px -8px rgba(0, 0, 0, 0.35);
}

.wp-block-button.has-hover-fx-slide-r > .wp-block-button__link:hover {
	transform: translateX(6px);
	box-shadow: -8px 0 18px -8px rgba(0, 0, 0, 0.35);
}

/* Padding-based shift, no transform. Designed for text-link style buttons
   (Editorial). On buttons with non-zero padding-right at rest, the visual
   effect is a shrink rather than a shift — preset is meant for editorial
   buttons whose at-rest padding-right is 0. */
.wp-block-button.has-hover-fx-shift-r > .wp-block-button__link:hover {
	padding-right: 0.5em;
}

/* ============================================================
   GROUP B — Scale & Zoom
   ============================================================ */
.wp-block-button.has-hover-fx-zoom-in > .wp-block-button__link:hover {
	transform: scale(1.08);
}

.wp-block-button.has-hover-fx-zoom-out > .wp-block-button__link:hover {
	transform: scale(0.92);
}

.wp-block-button.has-hover-fx-stretch-x > .wp-block-button__link:hover {
	transform: scaleX(1.12);
}

.wp-block-button.has-hover-fx-stretch-y > .wp-block-button__link:hover {
	transform: scaleY(1.18);
}

/* ============================================================
   GROUP C — Rotate & Skew
   ============================================================ */
.wp-block-button.has-hover-fx-rot-cw > .wp-block-button__link:hover {
	transform: rotate(2.5deg);
}

.wp-block-button.has-hover-fx-rot-ccw > .wp-block-button__link:hover {
	transform: rotate(-2.5deg);
}

.wp-block-button.has-hover-fx-skew-r > .wp-block-button__link:hover {
	transform: skewX(-8deg);
}

.wp-block-button.has-hover-fx-skew-l > .wp-block-button__link:hover {
	transform: skewX(8deg);
}

/* ============================================================
   GROUP D — 3D Perspective
   3D effects need perspective on a parent. We add it to the
   .wp-block-button wrapper for any 3D effect.
   ============================================================ */
.wp-block-button[class*="has-hover-fx-3d-"] {
	perspective: 700px;
}

.wp-block-button.has-hover-fx-3d-r > .wp-block-button__link:hover {
	transform: rotateY(18deg);
}

.wp-block-button.has-hover-fx-3d-l > .wp-block-button__link:hover {
	transform: rotateY(-18deg);
}

.wp-block-button.has-hover-fx-3d-up > .wp-block-button__link:hover {
	transform: rotateX(18deg);
}

.wp-block-button.has-hover-fx-3d-down > .wp-block-button__link:hover {
	transform: rotateX(-18deg);
}

/* ============================================================
   GROUP E — Press & Depth
   ============================================================ */
.wp-block-button.has-hover-fx-press > .wp-block-button__link {
	box-shadow:
		0 4px 0 0 var(--wp--preset--color--ink),
		0 6px 14px -4px rgba(0, 0, 0, 0.4);
	top: 0;
}

.wp-block-button.has-hover-fx-press > .wp-block-button__link:hover {
	top: 4px;
	box-shadow:
		0 0 0 0 var(--wp--preset--color--ink),
		0 1px 3px rgba(0, 0, 0, 0.25);
}

.wp-block-button.has-hover-fx-lift-shadow > .wp-block-button__link:hover {
	transform: translateY(-3px);
	box-shadow:
		0 24px 40px -16px rgba(0, 0, 0, 0.55),
		0 6px 12px -6px rgba(0, 0, 0, 0.3);
}

/* Lift + colored halo. Shadow color derives from primary via color-mix
   so it adapts to palette changes. Used as Pill's default. */
.wp-block-button.has-hover-fx-lift-glow > .wp-block-button__link:hover {
	transform: translateY(-3px);
	box-shadow:
		0 12px 24px -8px color-mix(in srgb, var(--wp--preset--color--primary) 60%, transparent),
		0 6px 14px -10px color-mix(in srgb, var(--wp--preset--color--primary) 35%, transparent);
}

/* ============================================================
   GROUP F — Background Directional Swipe
   All 8 directions use a ::before overlay revealing --hover-bg
   (defaulting to accent role). Iris effects (Group G) reuse this base.
   Curtain effects (split/clamp) use their own setup, so they're
   excluded from this base via :not().

   Stacking technique: `isolation: isolate` on the link establishes a new
   stacking context. The ::before then uses `z-index: -1` to sit BEHIND
   the link's text content but still within the link's own stacking
   context, so it stays inside the button visually. This way the link's
   text renders above the swipe overlay without needing extra markup.
   ============================================================ */
.wp-block-button[class*="has-hover-fx-bg-"] > .wp-block-button__link {
	position: relative;
	overflow: hidden;
	isolation: isolate;
}

.wp-block-button[class*="has-hover-fx-bg-"]:not(.has-hover-fx-bg-split):not(.has-hover-fx-bg-clamp) > .wp-block-button__link::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--accent)));
	z-index: -1;
	transition: transform 0.55s cubic-bezier(0.7, 0, 0.2, 1);
}

/* From left */
.wp-block-button.has-hover-fx-bg-l > .wp-block-button__link::before {
	transform: translateX(-101%);
}
.wp-block-button.has-hover-fx-bg-l > .wp-block-button__link:hover::before {
	transform: translateX(0);
}

/* From right */
.wp-block-button.has-hover-fx-bg-r > .wp-block-button__link::before {
	transform: translateX(101%);
}
.wp-block-button.has-hover-fx-bg-r > .wp-block-button__link:hover::before {
	transform: translateX(0);
}

/* From top */
.wp-block-button.has-hover-fx-bg-t > .wp-block-button__link::before {
	transform: translateY(-101%);
}
.wp-block-button.has-hover-fx-bg-t > .wp-block-button__link:hover::before {
	transform: translateY(0);
}

/* From bottom */
.wp-block-button.has-hover-fx-bg-b > .wp-block-button__link::before {
	transform: translateY(101%);
}
.wp-block-button.has-hover-fx-bg-b > .wp-block-button__link:hover::before {
	transform: translateY(0);
}

/* From top-left */
.wp-block-button.has-hover-fx-bg-tl > .wp-block-button__link::before {
	transform: translate(-101%, -101%);
}
.wp-block-button.has-hover-fx-bg-tl > .wp-block-button__link:hover::before {
	transform: translate(0, 0);
}

/* From top-right */
.wp-block-button.has-hover-fx-bg-tr > .wp-block-button__link::before {
	transform: translate(101%, -101%);
}
.wp-block-button.has-hover-fx-bg-tr > .wp-block-button__link:hover::before {
	transform: translate(0, 0);
}

/* From bottom-left */
.wp-block-button.has-hover-fx-bg-bl > .wp-block-button__link::before {
	transform: translate(-101%, 101%);
}
.wp-block-button.has-hover-fx-bg-bl > .wp-block-button__link:hover::before {
	transform: translate(0, 0);
}

/* From bottom-right */
.wp-block-button.has-hover-fx-bg-br > .wp-block-button__link::before {
	transform: translate(101%, 101%);
}
.wp-block-button.has-hover-fx-bg-br > .wp-block-button__link:hover::before {
	transform: translate(0, 0);
}

/* ============================================================
   GROUP G — Background Radial & Reveal
   Iris effects reuse the Group F base ::before; curtain effects use
   their own ::before + ::after pair (defined below).
   ============================================================ */

/* Iris open — hover-bg circle scales up from center, corners square out as it grows */
.wp-block-button.has-hover-fx-bg-iris-out > .wp-block-button__link::before {
	border-radius: 50%;
	transform: scale(0);
	transform-origin: center;
	transition:
		transform 0.6s cubic-bezier(0.7, 0, 0.2, 1),
		border-radius 0.4s ease 0.2s;
}
.wp-block-button.has-hover-fx-bg-iris-out > .wp-block-button__link:hover::before {
	transform: scale(2.6);
	border-radius: 0;
}

/* Iris close — hover-bg starts covering everything, recedes to a center circle on hover.
   The button's original background (whatever the user picked) shows through as the
   ::before shrinks. Inverse motion of iris-out. */
.wp-block-button.has-hover-fx-bg-iris-in > .wp-block-button__link::before {
	transform: scale(1);
	transform-origin: center;
	border-radius: 0;
	transition:
		transform 0.55s cubic-bezier(0.7, 0, 0.2, 1),
		border-radius 0.4s ease;
}
.wp-block-button.has-hover-fx-bg-iris-in > .wp-block-button__link:hover::before {
	transform: scale(0);
	border-radius: 50%;
}

/* Curtain part — two halves of hover-bg slide in from top and bottom,
   meeting at the middle on hover. The button's natural background stays
   visible at rest. */
.wp-block-button.has-hover-fx-bg-split > .wp-block-button__link::before,
.wp-block-button.has-hover-fx-bg-split > .wp-block-button__link::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	height: 50%;
	background: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--accent)));
	z-index: -1;
	transition: transform 0.55s cubic-bezier(0.7, 0, 0.2, 1);
}
.wp-block-button.has-hover-fx-bg-split > .wp-block-button__link::before {
	top: 0;
	transform: translateY(-101%);
}
.wp-block-button.has-hover-fx-bg-split > .wp-block-button__link::after {
	bottom: 0;
	transform: translateY(101%);
}
.wp-block-button.has-hover-fx-bg-split > .wp-block-button__link:hover::before,
.wp-block-button.has-hover-fx-bg-split > .wp-block-button__link:hover::after {
	transform: translateY(0);
}

/* Curtain close — two halves of hover-bg slide in from left and right,
   meeting at the middle on hover. */
.wp-block-button.has-hover-fx-bg-clamp > .wp-block-button__link::before,
.wp-block-button.has-hover-fx-bg-clamp > .wp-block-button__link::after {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	width: 50%;
	background: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--accent)));
	z-index: -1;
	transition: transform 0.55s cubic-bezier(0.7, 0, 0.2, 1);
}
.wp-block-button.has-hover-fx-bg-clamp > .wp-block-button__link::before {
	left: 0;
	transform: translateX(-101%);
}
.wp-block-button.has-hover-fx-bg-clamp > .wp-block-button__link::after {
	right: 0;
	transform: translateX(101%);
}
.wp-block-button.has-hover-fx-bg-clamp > .wp-block-button__link:hover::before,
.wp-block-button.has-hover-fx-bg-clamp > .wp-block-button__link:hover::after {
	transform: translateX(0);
}

/* ============================================================
   GROUP — Background Fill (cross-fade)
   No motion, no pseudo-element. The link's background-color cross-fades
   to --hover-bg and the text color flips to background, making it
   readable against the new fill. Default --hover-bg is text color (the
   "Ghost-style fill" pattern); user can override via the inspector
   color picker. Used as Ghost's and Dashed's default.
   ============================================================ */
.wp-block-button.has-hover-fx-fill > .wp-block-button__link:hover {
	background-color: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--ink)));
	color: var(--wp--preset--color--background);
}

/* ============================================================
   GROUP H — Border Edges
   Horizontal and vertical edge lines that grow from one side.
   ============================================================ */
.wp-block-button[class*="has-hover-fx-bd-"] > .wp-block-button__link {
	overflow: hidden;
	isolation: isolate;
}

/* Edges from left — top + bottom edge lines grow rightward */
.wp-block-button.has-hover-fx-bd-l > .wp-block-button__link::before,
.wp-block-button.has-hover-fx-bd-l > .wp-block-button__link::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	height: 2px;
	background: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--accent)));
	z-index: 2;
	transform-origin: left;
	transform: scaleX(0);
	transition: transform 0.5s cubic-bezier(0.7, 0, 0.2, 1);
}
.wp-block-button.has-hover-fx-bd-l > .wp-block-button__link::before { top: 0; }
.wp-block-button.has-hover-fx-bd-l > .wp-block-button__link::after { bottom: 0; }
.wp-block-button.has-hover-fx-bd-l > .wp-block-button__link:hover::before,
.wp-block-button.has-hover-fx-bd-l > .wp-block-button__link:hover::after {
	transform: scaleX(1);
}

/* Edges from right */
.wp-block-button.has-hover-fx-bd-r > .wp-block-button__link::before,
.wp-block-button.has-hover-fx-bd-r > .wp-block-button__link::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	height: 2px;
	background: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--accent)));
	z-index: 2;
	transform-origin: right;
	transform: scaleX(0);
	transition: transform 0.5s cubic-bezier(0.7, 0, 0.2, 1);
}
.wp-block-button.has-hover-fx-bd-r > .wp-block-button__link::before { top: 0; }
.wp-block-button.has-hover-fx-bd-r > .wp-block-button__link::after { bottom: 0; }
.wp-block-button.has-hover-fx-bd-r > .wp-block-button__link:hover::before,
.wp-block-button.has-hover-fx-bd-r > .wp-block-button__link:hover::after {
	transform: scaleX(1);
}

/* Edges from top — left + right edge lines grow downward */
.wp-block-button.has-hover-fx-bd-t > .wp-block-button__link::before,
.wp-block-button.has-hover-fx-bd-t > .wp-block-button__link::after {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	width: 2px;
	background: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--accent)));
	z-index: 2;
	transform-origin: top;
	transform: scaleY(0);
	transition: transform 0.5s cubic-bezier(0.7, 0, 0.2, 1);
}
.wp-block-button.has-hover-fx-bd-t > .wp-block-button__link::before { left: 0; }
.wp-block-button.has-hover-fx-bd-t > .wp-block-button__link::after { right: 0; }
.wp-block-button.has-hover-fx-bd-t > .wp-block-button__link:hover::before,
.wp-block-button.has-hover-fx-bd-t > .wp-block-button__link:hover::after {
	transform: scaleY(1);
}

/* Edges from bottom */
.wp-block-button.has-hover-fx-bd-b > .wp-block-button__link::before,
.wp-block-button.has-hover-fx-bd-b > .wp-block-button__link::after {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	width: 2px;
	background: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--accent)));
	z-index: 2;
	transform-origin: bottom;
	transform: scaleY(0);
	transition: transform 0.5s cubic-bezier(0.7, 0, 0.2, 1);
}
.wp-block-button.has-hover-fx-bd-b > .wp-block-button__link::before { left: 0; }
.wp-block-button.has-hover-fx-bd-b > .wp-block-button__link::after { right: 0; }
.wp-block-button.has-hover-fx-bd-b > .wp-block-button__link:hover::before,
.wp-block-button.has-hover-fx-bd-b > .wp-block-button__link:hover::after {
	transform: scaleY(1);
}

/* Border draw — two L-shaped pseudo elements grow to form a full border */
.wp-block-button.has-hover-fx-bd-draw > .wp-block-button__link {
	overflow: visible;
	background: transparent;
	color: var(--wp--preset--color--ink);
	border: 1px solid color-mix(in srgb, var(--wp--preset--color--ink) 12%, transparent);
}
.wp-block-button.has-hover-fx-bd-draw > .wp-block-button__link::before,
.wp-block-button.has-hover-fx-bd-draw > .wp-block-button__link::after {
	content: "";
	position: absolute;
	pointer-events: none;
	border: 1.5px solid var(--wp--preset--color--ink);
	width: 0;
	height: 0;
	transition:
		width 0.25s ease,
		height 0.25s ease 0.25s;
}
.wp-block-button.has-hover-fx-bd-draw > .wp-block-button__link::before {
	top: -1px;
	left: -1px;
	border-right: 0;
	border-bottom: 0;
}
.wp-block-button.has-hover-fx-bd-draw > .wp-block-button__link::after {
	bottom: -1px;
	right: -1px;
	border-left: 0;
	border-top: 0;
}
.wp-block-button.has-hover-fx-bd-draw > .wp-block-button__link:hover::before {
	width: calc(100% + 2px);
	height: calc(100% + 2px);
}
.wp-block-button.has-hover-fx-bd-draw > .wp-block-button__link:hover::after {
	width: calc(100% + 2px);
	height: calc(100% + 2px);
	transition:
		width 0.25s ease 0.5s,
		height 0.25s ease 0.75s;
}

/* Outline grow — soft outline expands outward */
.wp-block-button.has-hover-fx-bd-thick > .wp-block-button__link {
	box-shadow: 0 0 0 0 var(--wp--preset--color--ink);
	transition: box-shadow 0.35s ease;
}
.wp-block-button.has-hover-fx-bd-thick > .wp-block-button__link:hover {
	box-shadow: 0 0 0 4px var(--wp--preset--color--ink);
}

/* ============================================================
   GROUP — Shape (radius flip)
   Diagonal border-radius flip + background swap to --hover-bg.
   Used as Asymmetric's default — designed to pair with asymmetric
   corner styles. On uniform-corner buttons the flip is invisible
   (radii rotate to the same shape); the background swap is what
   most users will see in that case.
   ============================================================ */
.wp-block-button.has-hover-fx-radius-flip > .wp-block-button__link:hover {
	border-radius: 4px 22px 4px 22px;
	background-color: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--accent)));
}

/* ============================================================
   GROUP I — Shine Sweep
   Diagonal/linear gradient sweeps across button on hover.
   ============================================================ */
.wp-block-button[class*="has-hover-fx-shine-"] > .wp-block-button__link {
	overflow: hidden;
	isolation: isolate;
}

.wp-block-button.has-hover-fx-shine-r > .wp-block-button__link::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: -120%;
	width: 120%;
	background: linear-gradient(
		120deg,
		transparent 30%,
		rgba(255, 255, 255, 0.55) 50%,
		transparent 70%
	);
	z-index: 1;
	pointer-events: none;
	transition: transform 0.9s cubic-bezier(0.2, 0.6, 0.2, 1);
}
.wp-block-button.has-hover-fx-shine-r > .wp-block-button__link:hover::before {
	transform: translateX(200%);
}

.wp-block-button.has-hover-fx-shine-l > .wp-block-button__link::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	right: -120%;
	width: 120%;
	background: linear-gradient(
		-120deg,
		transparent 30%,
		rgba(255, 255, 255, 0.55) 50%,
		transparent 70%
	);
	z-index: 1;
	pointer-events: none;
	transition: transform 0.9s cubic-bezier(0.2, 0.6, 0.2, 1);
}
.wp-block-button.has-hover-fx-shine-l > .wp-block-button__link:hover::before {
	transform: translateX(-200%);
}

.wp-block-button.has-hover-fx-shine-d > .wp-block-button__link::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	top: -120%;
	height: 120%;
	background: linear-gradient(
		180deg,
		transparent 30%,
		rgba(255, 255, 255, 0.55) 50%,
		transparent 70%
	);
	z-index: 1;
	pointer-events: none;
	transition: transform 0.9s cubic-bezier(0.2, 0.6, 0.2, 1);
}
.wp-block-button.has-hover-fx-shine-d > .wp-block-button__link:hover::before {
	transform: translateY(200%);
}

.wp-block-button.has-hover-fx-shine-u > .wp-block-button__link::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -120%;
	height: 120%;
	background: linear-gradient(
		0deg,
		transparent 30%,
		rgba(255, 255, 255, 0.55) 50%,
		transparent 70%
	);
	z-index: 1;
	pointer-events: none;
	transition: transform 0.9s cubic-bezier(0.2, 0.6, 0.2, 1);
}
.wp-block-button.has-hover-fx-shine-u > .wp-block-button__link:hover::before {
	transform: translateY(-200%);
}

/* ============================================================
   GROUP J — Glow
   ============================================================ */
.wp-block-button.has-hover-fx-glow-out > .wp-block-button__link {
	box-shadow: 0 0 0 0 transparent;
	transition: box-shadow 0.45s ease;
}
.wp-block-button.has-hover-fx-glow-out > .wp-block-button__link:hover {
	box-shadow:
		0 0 0 1px color-mix(in srgb, var(--wp--preset--color--primary) 40%, transparent),
		0 0 28px 4px color-mix(in srgb, var(--wp--preset--color--primary) 55%, transparent),
		0 0 60px 10px color-mix(in srgb, var(--wp--preset--color--primary) 25%, transparent);
}

.wp-block-button.has-hover-fx-glow-in > .wp-block-button__link {
	overflow: hidden;
	isolation: isolate;
}
.wp-block-button.has-hover-fx-glow-in > .wp-block-button__link::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: radial-gradient(
		120% 80% at 50% 50%,
		rgba(255, 255, 255, 0.55) 0%,
		rgba(255, 255, 255, 0) 60%
	);
	opacity: 0;
	transition: opacity 0.4s ease;
	z-index: 1;
}
.wp-block-button.has-hover-fx-glow-in > .wp-block-button__link:hover::before {
	opacity: 1;
}

/* Ambient neutral shadow expands. Implemented via filter: drop-shadow so
   the effect is additive — it composes with whatever box-shadow the host
   button-style already has at rest, instead of replacing it. Used as
   Soft's default, where preserving Soft's layered box-shadow matters. */
.wp-block-button.has-hover-fx-shadow-grow > .wp-block-button__link:hover {
	filter: drop-shadow(0 14px 18px rgba(0, 0, 0, 0.18));
}

/* ============================================================
   GROUP K — Text Swap
   Uses a CSS pseudo-element to hold the hover text — no markup injection
   required. The `data-hover-text` attribute on the link feeds the pseudo
   via attr(). Original button text stays as-is (plain text in the anchor),
   so this works identically in the editor and on the front end.

   On hover: original text slides out, ::before slides in carrying the
   hover text. If the user hasn't entered hover text, ::before is empty
   and the original text simply slides out and back.
   ============================================================ */
.wp-block-button[class*="has-hover-fx-tx-"] > .wp-block-button__link {
	overflow: hidden;
	isolation: isolate;
}

.wp-block-button[class*="has-hover-fx-tx-"] > .wp-block-button__link::before {
	content: var(--hover-text-content, "");
	position: absolute;
	left: 0;
	right: 0;
	top: 0;
	bottom: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	color: inherit;
	pointer-events: none;
	transition: transform 0.45s cubic-bezier(0.7, 0, 0.2, 1),
		opacity 0.25s ease 0.15s;
}

/* Swap up — original text fades, hover text rises from below */
.wp-block-button.has-hover-fx-tx-up > .wp-block-button__link::before {
	transform: translateY(100%);
}
.wp-block-button.has-hover-fx-tx-up > .wp-block-button__link:hover::before {
	transform: translateY(0);
}
.wp-block-button.has-hover-fx-tx-up > .wp-block-button__link:hover {
	color: transparent;
}

/* Swap down — original text fades, hover text descends from above */
.wp-block-button.has-hover-fx-tx-down > .wp-block-button__link::before {
	transform: translateY(-100%);
}
.wp-block-button.has-hover-fx-tx-down > .wp-block-button__link:hover::before {
	transform: translateY(0);
}
.wp-block-button.has-hover-fx-tx-down > .wp-block-button__link:hover {
	color: transparent;
}

/* Swap left — original text fades, hover text comes from the right */
.wp-block-button.has-hover-fx-tx-left > .wp-block-button__link::before {
	transform: translateX(120%);
}
.wp-block-button.has-hover-fx-tx-left > .wp-block-button__link:hover::before {
	transform: translateX(0);
}
.wp-block-button.has-hover-fx-tx-left > .wp-block-button__link:hover {
	color: transparent;
}

/* Swap right — original text fades, hover text comes from the left */
.wp-block-button.has-hover-fx-tx-right > .wp-block-button__link::before {
	transform: translateX(-120%);
}
.wp-block-button.has-hover-fx-tx-right > .wp-block-button__link:hover::before {
	transform: translateX(0);
}
.wp-block-button.has-hover-fx-tx-right > .wp-block-button__link:hover {
	color: transparent;
}

/* ============================================================
   GROUP L — Letter Spacing
   ============================================================ */
.wp-block-button.has-hover-fx-track-out > .wp-block-button__link:hover {
	letter-spacing: 0.22em;
}

.wp-block-button.has-hover-fx-track-in > .wp-block-button__link {
	letter-spacing: 0.22em;
}
.wp-block-button.has-hover-fx-track-in > .wp-block-button__link:hover {
	letter-spacing: 0.01em;
}

/* ============================================================
   GROUP M — Underline
   Animated underline that grows from a side or center.
   ============================================================ */
.wp-block-button.has-hover-fx-und-l > .wp-block-button__link {
	background: transparent;
	color: var(--wp--preset--color--ink);
	border-radius: 0;
	overflow: visible;
}
.wp-block-button.has-hover-fx-und-l > .wp-block-button__link::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 4px;
	height: 2px;
	background: var(--wp--preset--color--ink);
	transform-origin: left;
	transform: scaleX(0);
	transition: transform 0.45s cubic-bezier(0.7, 0, 0.2, 1);
}
.wp-block-button.has-hover-fx-und-l > .wp-block-button__link:hover::after {
	transform: scaleX(1);
}

.wp-block-button.has-hover-fx-und-c > .wp-block-button__link {
	overflow: visible;
}
.wp-block-button.has-hover-fx-und-c > .wp-block-button__link::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 4px;
	height: 2px;
	background: var(--wp--preset--color--ink);
	transform-origin: center;
	transform: scaleX(0);
	transition: transform 0.45s cubic-bezier(0.7, 0, 0.2, 1);
}
.wp-block-button.has-hover-fx-und-c > .wp-block-button__link:hover::after {
	transform: scaleX(1);
}

/* ============================================================
   GROUP N — Animated Rainbow Border
   ----------------------------------------------------------------
   ⚠️ DESIGN EXCEPTION: hardcoded gradient colors.
   Per the project owner's decision, the rainbow effect uses literal
   hex colors because "rainbow" has no semantic equivalent in the
   color role system. This is the ONLY place in the entire button
   styles + hover system where colors are not token-referenced.
   ----------------------------------------------------------------
   ============================================================ */
@keyframes theme-fx-rainbow-pan {
	to {
		background-position: -200% 0;
	}
}

@keyframes theme-fx-rainbow-pulse {
	0%, 100% { box-shadow: 0 0 14px 1px rgba(255, 91, 46, 0.55); }
	25%      { box-shadow: 0 0 14px 1px rgba(255, 225, 74, 0.55); }
	50%      { box-shadow: 0 0 14px 1px rgba(31, 138, 91, 0.55); }
	75%      { box-shadow: 0 0 14px 1px rgba(74, 108, 255, 0.55); }
}

.wp-block-button[class*="has-hover-fx-rb-"] > .wp-block-button__link {
	overflow: visible;
	isolation: auto;
}
.wp-block-button[class*="has-hover-fx-rb-"] > .wp-block-button__link::before {
	content: "";
	position: absolute;
	inset: -2px;
	border-radius: inherit;
	padding: 2px;
	background: linear-gradient(
		90deg,
		#ff5b2e, #ffe14a, #1f8a5b, #4a6cff, #c084fc, #ff5b2e
	);
	background-size: 200% 100%;
	-webkit-mask:
		linear-gradient(#000 0 0) content-box,
		linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	opacity: 0;
	pointer-events: none;
	z-index: 1;
	transition: opacity 0.3s ease;
}

/* Bottom rainbow — clip-path keeps only the bottom half */
.wp-block-button.has-hover-fx-rb-bot > .wp-block-button__link::before {
	clip-path: inset(50% -4px -4px -4px);
}
.wp-block-button.has-hover-fx-rb-bot > .wp-block-button__link:hover::before {
	opacity: 1;
	animation: theme-fx-rainbow-pan 2.4s linear infinite;
}

/* Top rainbow */
.wp-block-button.has-hover-fx-rb-top > .wp-block-button__link::before {
	clip-path: inset(-4px -4px 50% -4px);
}
.wp-block-button.has-hover-fx-rb-top > .wp-block-button__link:hover::before {
	opacity: 1;
	animation: theme-fx-rainbow-pan 2.4s linear infinite;
}

/* All-sides rainbow (with pulse) */
.wp-block-button.has-hover-fx-rb-all > .wp-block-button__link:hover::before {
	opacity: 1;
	animation: theme-fx-rainbow-pan 2.4s linear infinite;
}
.wp-block-button.has-hover-fx-rb-all > .wp-block-button__link:hover {
	animation: theme-fx-rainbow-pulse 3.2s linear infinite;
}

/* ============================================================
   ============================================================
   PER-STYLE DEFAULTS
   ============================================================
   When a button uses one of the 10 named block styles AND has no
   has-hover-* class on its wrapper, the default rules below kick in.
   The :not([class*="has-hover-fx-"]):not(.has-hover-none) gate guarantees:
     - explicit has-hover-{slug}  → preset wins, default suppressed
     - explicit has-hover-none    → :not() fails, default suppressed
     - empty hoverEffect attr     → :not() succeeds, default applies

   Each default mirrors the named preset's :hover declarations. Hover
   text (`fx-tx-*`) and hover background color (`fx-fill`,
   `fx-radius-flip`, `fx-bg-*`) — which depend on user-supplied
   per-instance attributes — are not used by any default mapping, so
   the rules below don't read from --hover-bg or --hover-text-content.

   When updating a preset's :hover declarations, update the matching
   default below. Or — for presets that need at-rest pseudo setup
   (fx-bg-b for Slanted) — refer back to the preset's full rule set.
   ============================================================
   ============================================================ */

/* Solid → fx-lift-soft */
.wp-block-button.is-style-solid:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link:hover {
	transform: translateY(-2px);
	filter: brightness(0.92);
}

/* Ghost → fx-fill (default --hover-bg = text color) */
.wp-block-button.is-style-ghost:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link:hover {
	background-color: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--ink)));
	color: var(--wp--preset--color--background);
}

/* Pill → fx-lift-glow */
.wp-block-button.is-style-pill:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link:hover {
	transform: translateY(-3px);
	box-shadow:
		0 12px 24px -8px color-mix(in srgb, var(--wp--preset--color--primary) 60%, transparent),
		0 6px 14px -10px color-mix(in srgb, var(--wp--preset--color--primary) 35%, transparent);
}

/* Brutal → fx-press (hover-only — Brutal keeps its resting drop shadow;
   the press animates from the resting shadow → flat) */
.wp-block-button.is-style-brutal:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link:hover {
	top: 4px;
	box-shadow:
		0 0 0 0 var(--wp--preset--color--ink),
		0 1px 3px rgba(0, 0, 0, 0.25);
}

/* Slanted → fx-bg-b (curtain from bottom)
   This preset requires ::before pseudo at-rest setup, so the rule set is
   self-contained rather than borrowing fx-bg-b's selectors. Slanted's own
   button-styles CSS already provides position: relative + overflow: hidden;
   we add isolation: isolate so the ::before's z-index: -1 stays inside
   the link's stacking context. */
.wp-block-button.is-style-slanted:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link {
	isolation: isolate;
}
.wp-block-button.is-style-slanted:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--accent)));
	z-index: -1;
	transform: translateY(101%);
	transition: transform 0.55s cubic-bezier(0.7, 0, 0.2, 1);
}
.wp-block-button.is-style-slanted:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link:hover::before {
	transform: translateY(0);
}

/* 3D Press → fx-press (hover-only, same shape as Brutal default) */
.wp-block-button.is-style-3d-press:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link:hover {
	top: 4px;
	box-shadow:
		0 0 0 0 var(--wp--preset--color--ink),
		0 1px 3px rgba(0, 0, 0, 0.25);
}

/* Soft → fx-shadow-grow (drop-shadow so Soft's layered box-shadow stays intact) */
.wp-block-button.is-style-soft:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link:hover {
	filter: drop-shadow(0 14px 18px rgba(0, 0, 0, 0.18));
}

/* Dashed → fx-fill (default --hover-bg = text color) */
.wp-block-button.is-style-dashed:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link:hover {
	background-color: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--ink)));
	color: var(--wp--preset--color--background);
}

/* Asymmetric → fx-radius-flip */
.wp-block-button.is-style-asymmetric:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link:hover {
	border-radius: 4px 22px 4px 22px;
	background-color: var(--le-hover-bg, var(--hover-bg, var(--wp--preset--color--accent)));
}

/* Editorial → fx-shift-r */
.wp-block-button.is-style-editorial:not([class*="has-hover-fx-"]):not(.has-hover-none) > .wp-block-button__link:hover {
	padding-right: 0.5em;
}

/* ============================================================
   ============================================================
   CONTAINER EFFECTS — core/group & core/column
   ============================================================
   A curated subset of the button catalogue, applied directly to
   the container element (not an inner link). Only self-contained
   transform / box-shadow / filter effects are included. Effects
   that rely on the button's inner-link structure, pseudo-element
   overlays, overflow clipping, or text behavior are intentionally
   excluded — they cannot apply cleanly to an arbitrary container
   without risking clipped child content or layout interference.

   The same has-hover-{slug} class drives both buttons and
   containers; no collision, because the selectors are scoped by
   block class. Scale/rotate magnitudes are gentler than the button
   equivalents to avoid overflow or scrollbars on large blocks.

   Keep the slug list in sync with CONTAINER_EFFECTS in editor.js.
   ============================================================
   ============================================================ */

/* Shared transition baseline — only on containers carrying an effect. */
.wp-block-group[class*="has-hover-fx-"],
.wp-block-column[class*="has-hover-fx-"] {
	transition:
		transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1),
		box-shadow 0.45s ease,
		filter 0.35s ease;
}

/* Translation */
.wp-block-group.has-hover-fx-lift:hover,
.wp-block-column.has-hover-fx-lift:hover {
	transform: translateY(-6px);
	box-shadow: 0 14px 28px -10px rgba(0, 0, 0, 0.45);
}
.wp-block-group.has-hover-fx-lift-soft:hover,
.wp-block-column.has-hover-fx-lift-soft:hover {
	transform: translateY(-2px);
	filter: brightness(0.96);
}
.wp-block-group.has-hover-fx-push:hover,
.wp-block-column.has-hover-fx-push:hover {
	transform: translateY(6px);
}
.wp-block-group.has-hover-fx-slide-l:hover,
.wp-block-column.has-hover-fx-slide-l:hover {
	transform: translateX(-6px);
}
.wp-block-group.has-hover-fx-slide-r:hover,
.wp-block-column.has-hover-fx-slide-r:hover {
	transform: translateX(6px);
}

/* Scale & zoom (gentler than the button equivalents) */
.wp-block-group.has-hover-fx-zoom-in:hover,
.wp-block-column.has-hover-fx-zoom-in:hover {
	transform: scale(1.03);
}
.wp-block-group.has-hover-fx-zoom-out:hover,
.wp-block-column.has-hover-fx-zoom-out:hover {
	transform: scale(0.97);
}
.wp-block-group.has-hover-fx-stretch-x:hover,
.wp-block-column.has-hover-fx-stretch-x:hover {
	transform: scaleX(1.04);
}
.wp-block-group.has-hover-fx-stretch-y:hover,
.wp-block-column.has-hover-fx-stretch-y:hover {
	transform: scaleY(1.05);
}

/* Rotate & skew */
.wp-block-group.has-hover-fx-rot-cw:hover,
.wp-block-column.has-hover-fx-rot-cw:hover {
	transform: rotate(2deg);
}
.wp-block-group.has-hover-fx-rot-ccw:hover,
.wp-block-column.has-hover-fx-rot-ccw:hover {
	transform: rotate(-2deg);
}
.wp-block-group.has-hover-fx-skew-r:hover,
.wp-block-column.has-hover-fx-skew-r:hover {
	transform: skewX(-6deg);
}
.wp-block-group.has-hover-fx-skew-l:hover,
.wp-block-column.has-hover-fx-skew-l:hover {
	transform: skewX(6deg);
}

/* 3D perspective — perspective folded into the transform so no parent setup is
   required (self-contained). */
.wp-block-group.has-hover-fx-3d-r:hover,
.wp-block-column.has-hover-fx-3d-r:hover {
	transform: perspective(900px) rotateY(10deg);
}
.wp-block-group.has-hover-fx-3d-l:hover,
.wp-block-column.has-hover-fx-3d-l:hover {
	transform: perspective(900px) rotateY(-10deg);
}
.wp-block-group.has-hover-fx-3d-up:hover,
.wp-block-column.has-hover-fx-3d-up:hover {
	transform: perspective(900px) rotateX(10deg);
}
.wp-block-group.has-hover-fx-3d-down:hover,
.wp-block-column.has-hover-fx-3d-down:hover {
	transform: perspective(900px) rotateX(-10deg);
}

/* Depth */
.wp-block-group.has-hover-fx-lift-shadow:hover,
.wp-block-column.has-hover-fx-lift-shadow:hover {
	transform: translateY(-3px);
	box-shadow:
		0 24px 40px -16px rgba(0, 0, 0, 0.55),
		0 6px 12px -6px rgba(0, 0, 0, 0.3);
}
.wp-block-group.has-hover-fx-lift-glow:hover,
.wp-block-column.has-hover-fx-lift-glow:hover {
	transform: translateY(-3px);
	box-shadow:
		0 12px 24px -8px color-mix(in srgb, var(--wp--preset--color--primary) 60%, transparent),
		0 6px 14px -10px color-mix(in srgb, var(--wp--preset--color--primary) 35%, transparent);
}

/* Glow */
.wp-block-group.has-hover-fx-glow-out:hover,
.wp-block-column.has-hover-fx-glow-out:hover {
	box-shadow:
		0 0 0 1px color-mix(in srgb, var(--wp--preset--color--primary) 40%, transparent),
		0 0 28px 4px color-mix(in srgb, var(--wp--preset--color--primary) 55%, transparent),
		0 0 60px 10px color-mix(in srgb, var(--wp--preset--color--primary) 25%, transparent);
}
.wp-block-group.has-hover-fx-shadow-grow:hover,
.wp-block-column.has-hover-fx-shadow-grow:hover {
	filter: drop-shadow(0 14px 18px rgba(0, 0, 0, 0.18));
}

/* Outline grow */
.wp-block-group.has-hover-fx-bd-thick:hover,
.wp-block-column.has-hover-fx-bd-thick:hover {
	box-shadow: 0 0 0 4px var(--wp--preset--color--ink);
}

/* ============================================================
   ============================================================
   HOVER COLORS (Text + Background)
   ============================================================
   A separate, effect-independent feature: a hover Text color and
   hover Background color exposed in the same Hover panel for
   core/button, core/group, and core/column.

   Activated by le-has-hover-* classes; the color arrives via the
   --le-hover-text / --le-hover-bg custom properties applied to the
   block wrapper (editor: editor.BlockListBlock; front end: render_block).

   !important is required because a custom (non-palette) Text/Background
   color is applied by core as an inline style, which would otherwise win
   over these :hover rules.

   Targets:
     - core/group, core/column → the element itself is the styled wrapper
     - core/button             → wrapper is .wp-block-button, but the colored
                                 element is the inner link; the custom
                                 properties cascade from wrapper to link.
   ============================================================
   ============================================================ */

/* Transition baseline for group/column hover colors. Buttons are intentionally
   excluded — the shared transition baseline at the top of this file already
   covers any .wp-block-button with a `has-hover-*` class (including the
   `le-has-hover-*` ones), and it transitions the full property list (transform,
   top, box-shadow, etc.) so default and explicit effects animate smoothly even
   when a hover color is also set. */
.wp-block-group.le-has-hover-text,
.wp-block-group.le-has-hover-bg,
.wp-block-column.le-has-hover-text,
.wp-block-column.le-has-hover-bg {
	transition: color 0.25s ease, background-color 0.25s ease;
}

/* Group / Column — the element itself. */
.wp-block-group.le-has-hover-text:hover,
.wp-block-column.le-has-hover-text:hover {
	color: var(--le-hover-text) !important;
}

.wp-block-group.le-has-hover-bg:hover,
.wp-block-column.le-has-hover-bg:hover {
	background-color: var(--le-hover-bg) !important;
}

/* Button — inner link is the colored surface. */
.wp-block-button.le-has-hover-text > .wp-block-button__link:hover {
	color: var(--le-hover-text) !important;
}

/* Generic always-on hover background. Two cases must be excluded so the
   color doesn't double up with an effect that animates the bg itself —
   if both fire, the link bg snaps to the target color underneath, so the
   effect's ::before overlay swipes in against a matching color and is
   invisible. The excluded cases are:
   1. Explicit has-hover-fx-bg-* (all 12 swipe/reveal effects).
   2. Slanted with no explicit effect — its per-style default is fx-bg-b,
      a ::before swipe. Slanted with an explicit non-swipe effect (e.g.
      fx-zoom-in) still gets the generic rule via the second selector. */
.wp-block-button.le-has-hover-bg:not([class*="has-hover-fx-bg-"]):not(.is-style-slanted) > .wp-block-button__link:hover,
.wp-block-button.le-has-hover-bg.is-style-slanted[class*="has-hover-fx-"]:not([class*="has-hover-fx-bg-"]) > .wp-block-button__link:hover {
	background-color: var(--le-hover-bg) !important;
}
