/* Kingdom Advisors Elementor Widgets — Button
   Osmo "Button 009" hover choreography, adapted to Elementor. Pure CSS, no JS.

   TWO HOVER MOTIONS, chosen by the Hover Motion control:

     Slide Across (default, `.kaw-button` on its own) — at rest the icon sits on the right; on hover
     the right icon slides out and fades while a matching icon slides in from the left and the text
     shifts over. One continuous motion, identical for every icon.

     Cycle Down (`.kaw-button--down`) — for a downward-pointing icon. The icon leaves through the
     bottom of its own box while an identical one arrives from above and lands exactly where the
     first one started. The label does not move, and there is no reverse on mouseout. See the
     section near the foot of this file for how that is arranged.

     Cycle Down → Full Button (`.kaw-button--down.kaw-button--down-full`, v1.43.0, opt-in) — the
     same cycle, but the window is the whole button: the icon drops out through the bottom edge and
     its twin arrives from the top edge. The last section of this file; every rule in it needs both
     classes, so nothing above it changes for a button without the new class.

   Every tunable value is a CSS custom property (--kaw-btn-*) that the widget's Elementor controls
   set on {{WRAPPER}} .kaw-button, so the animation math (which depends on icon size, gap, and
   padding) always stays in sync with the styling. The structure, transitions, and easings follow
   Osmo 009 verbatim — only the fixed :root values were swapped for the control-driven variables.

   Both motions are gated behind (hover: hover) and (pointer: fine), so touch devices show the
   clean resting state (icon on the right, fully tappable), and both respect prefers-reduced-motion. */

.kaw-button-wrap,
.kaw-button-wrap *,
.kaw-button-wrap *::before,
.kaw-button-wrap *::after {
  box-sizing: border-box;
}

/* Alignment: one full-width grid cell whose single item is placed/sized by justify-items —
   start / center / end hug the content; stretch makes the button fill the width. */
.kaw-button-wrap {
  display: grid;
  grid-template-columns: 100%;
  justify-items: start;
}

.kaw-button {
  --kaw-btn-color: #ffffff;
  --kaw-btn-bg: #147bd1;
  --kaw-btn-focus: #051c2c;
  --kaw-btn-icon-size: 18px;
  --kaw-btn-gap: 10px;
  --kaw-btn-pad-top: 18px;
  --kaw-btn-pad-right: 28px;
  --kaw-btn-pad-bottom: 18px;
  --kaw-btn-pad-left: 28px;
  --kaw-btn-radius: 8px;
  --kaw-btn-overflow: hidden;   /* upgraded to `clip` by the @supports gate below */
  --kaw-btn-focus-inset: -0.125em;
  --kaw-btn-click-scale: 0.97 0.94;
  --kaw-btn-fade: 0.3s;
  --kaw-btn-blur: 0px;
  /* How far the icons travel on the swap — the full icon width plus the gap, so they clear out. */
  --kaw-btn-icon-travel: calc(var(--kaw-btn-icon-size) + var(--kaw-btn-gap));
  /* Cycle Down travel is one icon height, so it is expressed as a percentage of the glyph itself
     and needs no variable (Full Button adds --kaw-btn-drop-* on its slots, at the foot of the file).
     This is only its duration — deliberately the same 0.5s as the swap. */
  --kaw-btn-cycle: 0.5s;
  --kaw-btn-ease-hover: cubic-bezier(0.32, 0.72, 0, 1);
  --kaw-btn-ease-click: cubic-bezier(0.4, 0, 0.2, 1);
  --kaw-btn-ease-focus: cubic-bezier(0.32, 0.72, 0, 1);

  color: var(--kaw-btn-color);
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  /* Reset native <button> chrome so the element works identically whether rendered as <a> or
     <button> (the Folio "See Bio" control is a <button class="kaw-button">). */
  border: 0;
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
  outline-style: none;
  padding: 0;
  line-height: 1;
  text-decoration: none;
  display: inline-grid;
  position: relative;
  -webkit-tap-highlight-color: transparent;
  transition: scale 0.15s var(--kaw-btn-ease-click), color var(--kaw-btn-fade) ease;
}

/* `overflow: clip` is Baseline (Chrome 90, Firefox 81, Safari 16.0). It cannot be guarded with a
   preceding `overflow: hidden` at the point of use — see the note in .kaw-button__inner — so the
   VARIABLE is gated instead. Every engine at this pack's support floor passes the test and computes
   exactly what it computed before; Safari 15 and older keep `hidden`, which clips identically. It
   matters most on Call to Action, which ships --kaw-btn-pad-right: 0, so without any clipping its
   incoming arrow parks outside the box at full opacity beside every card. */
@supports (overflow: clip) {
  .kaw-button { --kaw-btn-overflow: clip; }
}

/* Focus ring (keyboard only) — a ring just outside the button, same radius. */
.kaw-button::after {
  content: '';
  display: block;
  position: absolute;
  inset: var(--kaw-btn-focus-inset);
  border-radius: var(--kaw-btn-radius);
  transition: box-shadow 0.3s var(--kaw-btn-ease-focus);
  pointer-events: none;
  z-index: 2;
}

.kaw-button:focus-visible::after {
  box-shadow: 0 0 0 0.125em var(--kaw-btn-focus);
}

.kaw-button:active {
  scale: var(--kaw-btn-click-scale);
}

/* The label + icons live here. The inner fills the button and uses space-between, so a normal
   (content-sized) button keeps the label and icon snug together — there is no free space to
   distribute — while a stretched (full-width) button pins the label left and the icon right, like
   the Conference full-width CTA. */
.kaw-button__inner {
  pointer-events: none;
  gap: var(--kaw-btn-gap);
  padding: var(--kaw-btn-pad-top) var(--kaw-btn-pad-right) var(--kaw-btn-pad-bottom) var(--kaw-btn-pad-left);
  z-index: 1;
  border-radius: var(--kaw-btn-radius);
  /* The value arrives through the variable, which is gated by @supports where it is declared. Do NOT
     "simplify" this to `overflow: hidden; overflow: clip;` via the variable — that shape looks like a
     fallback and is not one. A declaration containing var() is valid at PARSE time, so the cascade
     keeps it and discards the plain `hidden` above it; an unsupported substituted keyword is then
     invalid at COMPUTED-VALUE time, which resolves to the property's initial value — `visible` — not
     to the earlier declaration. Measured: that shape computes `visible` in a browser without `clip`.
     v1.30.0 shipped exactly that mistake here and it did nothing. */
  overflow: var(--kaw-btn-overflow);
  grid-area: 1 / 1;
  justify-self: stretch;
  justify-content: space-between;
  align-items: center;
  display: flex;
  position: relative;
}

.kaw-button__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--kaw-btn-icon-size);
  height: var(--kaw-btn-icon-size);
  flex: none;
  color: currentColor;
  transition: translate 0.5s var(--kaw-btn-ease-hover), opacity 0.15s ease-out, color var(--kaw-btn-fade) ease;
}

/* Icons render inline (SVG uploads / the built-in arrow), so fill and stroke follow the colour
   controls. Uploaded font icons fall back to font-size. */
.kaw-button__icon svg {
  width: 100%;
  height: 100%;
  display: block;
}

.kaw-button__icon i {
  font-size: var(--kaw-btn-icon-size);
  line-height: 1;
}

/* The incoming (left) icon is out of flow and hidden until hover, so at rest the button reads as
   text + right icon only. */
.kaw-button__icon.is--left {
  position: absolute;
  left: var(--kaw-btn-pad-right);
  opacity: 0;
  translate: calc(-1 * var(--kaw-btn-icon-travel)) 0;
}

/* --nofade: the incoming icon slides in at full opacity instead of fading up.
   What hides the icon at rest is CLIPPING, not opacity: it parks at `left: var(--kaw-btn-pad-right)`
   minus its travel, i.e. at `pad-right - gap - icon-size`, and `overflow: clip` on the inner cuts
   anything left of zero. So it is only safe while `pad-right <= gap` — beyond that the icon peeks out
   before hover, which is why this is opt-in rather than the default.
   The OUTGOING icon still fades: it exits past the label with no edge to disappear behind. */
.kaw-button--nofade .kaw-button__icon.is--left {
  opacity: 1;
  transition: translate 0.5s var(--kaw-btn-ease-hover), color var(--kaw-btn-fade) ease;
}

.kaw-button__text {
  flex: none;
  transition: translate 0.5s var(--kaw-btn-ease-hover);
}

/* Background layer (colour, border, radius) behind the clipped content. */
.kaw-button__bg {
  background-color: var(--kaw-btn-bg);
  border-radius: var(--kaw-btn-radius);
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  padding: 0;
  transition: background-color var(--kaw-btn-fade) ease, border-color var(--kaw-btn-fade) ease;
}

/* Frosted glass, opt-in — only emitted when the Background Blur control is above 0.

   THE BLUR GOES ON __bg AND NOT ON .kaw-button. In WebKit an element with a backdrop-filter clips
   its descendants to its own border box, and the focus ring is drawn by .kaw-button::after at
   inset: -0.125em — i.e. deliberately OUTSIDE the button. Put the blur on the button and the ring
   is swallowed, silently, for keyboard users only. __bg has no descendants, so nothing can be lost.

   __bg is also the right layer for a second reason: __inner carries z-index: 1, so the label and
   icons paint above this element and are never themselves blurred.

   Gated on the attribute rather than always emitting blur(0px), because a backdrop-filter costs a
   compositing layer even at zero and buttons repeat down a page. */
.kaw-button[data-blur="on"] .kaw-button__bg {
  -webkit-backdrop-filter: blur(var(--kaw-btn-blur));
          backdrop-filter: blur(var(--kaw-btn-blur));
}

/* --------------------------------------------------------------------- Slide Across (default)
   Every selector here is scoped with :not(.kaw-button--down). Cycle Down reuses the same two icon
   elements, so without the exclusion the sideways choreography would run underneath it — the label
   would shift and the resting icon would slide out to the right.

   .kaw-button--noicon is excluded from the LABEL rule below and from that one only. Every other rule
   in this block descends into .kaw-button__icon, and render() emits no icon spans for a text-only
   button, so those rules have nothing left to match and need no exclusion. The label rule is the
   exception: it targets .kaw-button__text, which is still there, and would slide the label sideways
   over empty space on hover. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .kaw-button:not(.kaw-button--down, .kaw-button--noicon):is(:hover, :focus-visible) .kaw-button__text,
  [data-hover]:is(:hover, :focus-visible) .kaw-button:not(.kaw-button--down, .kaw-button--noicon) .kaw-button__text {
    /* Shift the label right by exactly icon + gap + (padding-right − padding-left) so it lands
       right after the incoming left icon and its gap. */
    translate: calc(var(--kaw-btn-icon-size) + var(--kaw-btn-gap) + var(--kaw-btn-pad-right) - var(--kaw-btn-pad-left)) 0;
    transition: translate 0.5s 0.075s var(--kaw-btn-ease-hover);
  }

  .kaw-button:not(.kaw-button--down):is(:hover, :focus-visible) .kaw-button__icon.is--left,
  [data-hover]:is(:hover, :focus-visible) .kaw-button:not(.kaw-button--down) .kaw-button__icon.is--left {
    translate: 0 0;
    opacity: 1;
    transition: translate 0.5s 0.075s var(--kaw-btn-ease-hover), opacity 0.15s 0.075s ease-out;
  }

  /* --nofade: same slide, but never animate opacity in either direction. */
  .kaw-button--nofade:not(.kaw-button--down):is(:hover, :focus-visible) .kaw-button__icon.is--left,
  [data-hover]:is(:hover, :focus-visible) .kaw-button--nofade:not(.kaw-button--down) .kaw-button__icon.is--left {
    transition: translate 0.5s 0.075s var(--kaw-btn-ease-hover);
  }

  .kaw-button:not(.kaw-button--down):is(:hover, :focus-visible) .kaw-button__icon.is--right,
  [data-hover]:is(:hover, :focus-visible) .kaw-button:not(.kaw-button--down) .kaw-button__icon.is--right {
    translate: var(--kaw-btn-icon-travel) 0;
    opacity: 0;
    transition: translate 0.5s 0.05s var(--kaw-btn-ease-hover), opacity 0.15s 0.075s ease-out;
  }
}

/* ================================================================================== Cycle Down
   The second hover motion, for a downward-pointing icon: the icon leaves through the bottom of its
   own box while an identical one arrives from above and lands exactly where the first one started.
   The label does not move. Same two icon elements as Slide Across — no extra markup.

   WHY THERE IS NO REVERSE ON MOUSEOUT. The two icons swap roles the instant hover begins, and
   because they are the same icon in the same place, the swap itself is invisible:

                        is--right glyph        is--left glyph
     at rest            0      (visible)       100%   (below, clipped)
     hover frame 0      -100%  (above)         0      (visible)   <- identical pixels to "at rest"
     hover frame 1      0      (visible)       100%   (below)     <- identical to "at rest" again

   So the animation ENDS on the resting state. When the pointer leaves, the animation is torn down
   and the element lands on exactly what it was already showing — nothing happens, which is the
   design. It also means a pointer that leaves MID-animation jumps FORWARD to the finished position
   rather than rewinding: the motion reads as "finished early", never as "undone".

   THIS IS WHY IT IS @keyframes AND NOT A TRANSITION. A transition would run backwards on mouseout,
   which is the one thing this motion must not do. */

/* Each icon slot becomes its own window and the glyph inside it is what moves. __inner cannot do
   this job: its clip is at the padding edge, so a glyph parked one icon-height above centre still
   sits inside the top padding (18px by default, against an 18px icon) and would show at rest. */
.kaw-button--down .kaw-button__icon {
  overflow: hidden;   /* Safari < 16 fallback — see the note on __inner's overflow above. */
  overflow: clip;
}

/* Stack the incoming icon exactly on top of the resting one — same right edge, same (static,
   flex-centred) vertical position. `translate: none` cancels the sideways parking that Slide
   Across uses, and the icon is opaque here because clipping, not opacity, is what hides it. */
.kaw-button--down .kaw-button__icon.is--left {
  left: auto;
  right: var(--kaw-btn-pad-right);
  opacity: 1;
  translate: none;
}

/* Resting positions of the glyphs — and, deliberately, the END of the keyframes below.
   `> *` covers both an inline <svg> and a font-icon <i>. */
.kaw-button--down .kaw-button__icon.is--right > * { translate: 0 0; }
.kaw-button--down .kaw-button__icon.is--left > *  { translate: 0 100%; }

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .kaw-button--down:is(:hover, :focus-visible) .kaw-button__icon.is--right > *,
  [data-hover]:is(:hover, :focus-visible) .kaw-button--down .kaw-button__icon.is--right > * {
    animation: kaw-btn-cycle-in var(--kaw-btn-cycle) var(--kaw-btn-ease-hover);
  }

  .kaw-button--down:is(:hover, :focus-visible) .kaw-button__icon.is--left > *,
  [data-hover]:is(:hover, :focus-visible) .kaw-button--down .kaw-button__icon.is--left > * {
    animation: kaw-btn-cycle-out var(--kaw-btn-cycle) var(--kaw-btn-ease-hover);
  }
}

/* No fill-mode on either: landing back on the base state IS the point (see above). */
@keyframes kaw-btn-cycle-in {
  from { translate: 0 -100%; }
  to   { translate: 0 0; }
}

@keyframes kaw-btn-cycle-out {
  from { translate: 0 0; }
  to   { translate: 0 100%; }
}

/* ================================================================= Cycle Down → Full Button travel
   Opt-in (v1.43.0, the Travel control): `.kaw-button--down-full` is added beside `.kaw-button--down`.
   EVERY selector below requires both classes, so a button without the new class matches none of it
   and the Icon Height motion above is untouched. No rule above this section was edited for it (two
   comments were); tools/test-button-render.php row E.1 checks that against the 1.42.0 file.

   Same cycle, bigger window. In Icon Height each icon slot is its own clip window, so the glyph
   vanishes one icon-height below where it started. On a 60px button with a 16px icon that reads as
   being cut off by the label's line. Here the slots stop clipping and __inner's own clip is the
   window. That clip is its padding edge, which is the button's edge, rounded by the Border Radius.
   The resting icon drops out through the bottom edge while its twin arrives from just above the top
   edge and lands in the middle.

   THE DISTANCE, WITHOUT JS. The glyphs still run the Icon Height keyframes above, which move them one
   glyph height. What is missing is the distance from the icon to the button's edge. It depends on the
   label's line height, which no variable carries. So each SLOT is made exactly as tall as the button
   and carries the rest of the trip, as a percentage of itself:

     is--right (in flow) stretches to the flex line, and negative block margins cancel its block
     padding. Its margin box still equals the line, so the button keeps its height, while its border
     box spans the whole padding box of __inner, 0 to H.
     is--left (absolutely positioned) gets top: 0 / bottom: 0 and the same padding.

   The padding keeps each glyph centred on the content band (C = H - pad-top - pad-bottom) exactly
   where it sits in Icon Height, so the two glyphs still stack pixel-identically. With the glyph
   h = icon-size tall, its top at pad-top + (C - h) / 2:

     out: the glyph's top must reach H      slot + glyph = 50% + (pad-bottom - pad-top + h) / 2
          the glyph keyframe supplies h  ->  slot = 50% + (pad-bottom - pad-top - h) / 2   (+ 1px)
     in:  the glyph's bottom starts at 0    slot = -50% - (pad-top - pad-bottom - h) / 2  (- 1px)

   THE 1px OVERSHOOT. Without it the twins would sit exactly on the edges, and that has no margin.
   The paddings and the label line are laid out in 1/64px units while the percentages are resolved
   in floats, so on fractional geometry (padding 18.4 / 19.1px, a 17.5px icon, a 21.3px line) the
   parked glyph's top lands about 0.01px INSIDE the clip. The clip is pixel-snapped, and the glyph's
   antialiased top row then shows as a hairline just inside the bottom edge. That was measured at
   DPR 1 and 2 with a top-edge stroke. One whole pixel beyond each edge means no pixel row is ever
   shared. The cost is nothing visible: the arriving icon starts 1px above the edge and crosses that
   pixel in well under one frame. With equal top and bottom padding both trips grow by the same 1px,
   so the twins still travel as one belt. The slot and the glyph inside it share duration, easing and
   start, so the two animations add up to one motion. Same no-reverse rule: both end on the resting
   state.

   Each glyph is clipped to its own box (overflow: hidden). In Icon Height the slot did that, because
   the glyph fills the slot. Some uploaded SVGs carry overflow="visible" with strokes beyond the
   viewBox edge. Unclipped, the resting icon would show strokes that Icon Height cuts off, and a
   heavy enough stroke on a parked twin would reach past the 1px margin. With the clip and the
   margin, a Full Button at rest paints its resting icon, cut exactly as in Icon Height, and nothing
   of the parked twin.

   Reduced motion and touch: the hover rules sit in the same media query as Icon Height's, and the
   resting positions (is--left parked below the bottom edge, clipped by __inner) sit outside it. */
.kaw-button--down.kaw-button--down-full .kaw-button__icon {
  --kaw-btn-drop-out: calc(50% + (var(--kaw-btn-pad-bottom) - var(--kaw-btn-pad-top) - var(--kaw-btn-icon-size)) / 2 + 1px);
  --kaw-btn-drop-in: calc(-50% - (var(--kaw-btn-pad-top) - var(--kaw-btn-pad-bottom) - var(--kaw-btn-icon-size)) / 2 - 1px);
  overflow: visible;
  height: auto;
  padding-top: var(--kaw-btn-pad-top);
  padding-bottom: var(--kaw-btn-pad-bottom);
  /* No translate transition: the slot's translate only ever comes from the keyframes or from the
     fixed parking below, and a breakpoint change to the padding must not glide a parked icon. */
  transition: color var(--kaw-btn-fade) ease;
}

.kaw-button--down.kaw-button--down-full .kaw-button__icon.is--right {
  align-self: stretch;
  margin-top: calc(-1 * var(--kaw-btn-pad-top));
  margin-bottom: calc(-1 * var(--kaw-btn-pad-bottom));
}

.kaw-button--down.kaw-button--down-full .kaw-button__icon.is--left {
  top: 0;
  bottom: 0;
  translate: 0 var(--kaw-btn-drop-out);
}

/* The glyph keeps the Icon Height box. An inline SVG is height: 100% of its slot, and the slot's
   content band is now the label's line, so it is pinned back to the icon size. A font icon is already
   one icon-size line tall (line-height: 1 on its own font-size) and is left alone, because an em
   icon size would resolve against the icon's own font-size here. */
.kaw-button--down.kaw-button--down-full .kaw-button__icon > svg,
.kaw-button--down.kaw-button--down-full .kaw-button__icon > img {
  height: var(--kaw-btn-icon-size);
}

.kaw-button--down.kaw-button--down-full .kaw-button__icon > * {
  overflow: hidden;
}

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .kaw-button--down.kaw-button--down-full:is(:hover, :focus-visible) .kaw-button__icon.is--right,
  [data-hover]:is(:hover, :focus-visible) .kaw-button--down.kaw-button--down-full .kaw-button__icon.is--right {
    animation: kaw-btn-drop-in var(--kaw-btn-cycle) var(--kaw-btn-ease-hover);
  }

  .kaw-button--down.kaw-button--down-full:is(:hover, :focus-visible) .kaw-button__icon.is--left,
  [data-hover]:is(:hover, :focus-visible) .kaw-button--down.kaw-button--down-full .kaw-button__icon.is--left {
    animation: kaw-btn-drop-out var(--kaw-btn-cycle) var(--kaw-btn-ease-hover);
  }
}

/* No fill-mode, as above: the end of each is the resting state. */
@keyframes kaw-btn-drop-in {
  from { translate: 0 var(--kaw-btn-drop-in); }
  to   { translate: 0 0; }
}

@keyframes kaw-btn-drop-out {
  from { translate: 0 0; }
  to   { translate: 0 var(--kaw-btn-drop-out); }
}
