/* ==========================================================================
   WBI Button
   The gradient-bordered button of WBI Form as an element of its own: a pill
   (.wbi-button__text) and, optionally, a circle holding an icon
   (.wbi-button__icon) drawn over the pill's right end.

   Mobile first. The base rules are what every screen gets: the button alone,
   or the whole design when the circle is set to always show. Everything that
   moves lives in one `(hover: hover) and (pointer: fine)` block — a mouse or
   a trackpad, not a screen width — so a phone or a tablet never computes a
   transition, a hover state or a parked circle. No script on any device.

   Every visual value is a `--wbi-btn-*` custom property, so the Bricks
   element only overrides variables (typography, gradients and shadows
   excepted). Tokens live in :where() (zero specificity) so any rule Bricks
   generates on the root (#brxe-xxx { --token: ... }) always wins, regardless
   of the order in which the stylesheets load.

   Gradient borders: the gradient paints the whole border box and an ::after
   fills the inside with --wbi-btn-fill, so a single background-image (the
   one the Bricks gradient control writes) is enough for both parts. Not an
   inset box-shadow: Safari 26 has painted it over the whole button, or not
   at all (WebKit bugs 298341 and 300477), hiding the gradient or flooding
   the button with it. With "Apply to: Overlay" that control paints in a
   ::before of each part instead, spread over the border box under the fill.

   Sizes are in px or in `em` against --wbi-btn-base (16px), never in rem:
   Bricks sets the root to 10px. Every measure is multiplied by
   --wbi-btn-size (the Size control) where it is used, so one number scales
   the whole button, values set in the editor included — except Width and
   Height, which are exact once set.

   Markup:
     a.wbi-button            (span when it has no link)
       span.wbi-button__text
         ::before            (the border, with Apply to: Overlay)
         ::after             (the fill)
       span.wbi-button__icon (not rendered with Icon → No icon; the same
                              two layers)
   ========================================================================== */

:where(.wbi-button) {
  /* Size control. Every measure below is the design at 1 and gets
     multiplied by it where it is used, the text included (through the
     root font size). Unitless: a percentage cannot multiply a length
     inside calc(). Width (--wbi-btn-w) and Height (--wbi-btn-height) have
     no default here: unset, the button follows its text and the design
     height; set, they are exact and Size leaves them alone. */
  --wbi-btn-size: 1;
  --wbi-btn-base: 16px;
  /* Theme Styles > WBI Elements > Font (see wbi-fonts.css) */
  --wbi-btn-font: var(--wbi-font), system-ui, -apple-system, "Segoe UI", sans-serif;

  /* --- Button ---------------------------------------------------------- */
  --wbi-btn-fill: #0D1115;
  /* Default only: the Typography control writes `color` on the pill and wins. */
  --wbi-btn-color: #FFFFFF;
  /* The factory gradient comes from the Bricks control; this one covers an
     element inserted by code. */
  --wbi-btn-gradient: radial-gradient(ellipse 64% 41% at 100% 100%, #E1951B 0%, #C05507 100%);
  --wbi-btn-border-w: 2px;
  --wbi-btn-radius: 8px;
  --wbi-btn-h: 52px; /* design height at Size 1; the Height control writes --wbi-btn-height */
  --wbi-btn-pad-x: 32px;

  /* --- Icon circle ----------------------------------------------------- */
  /* --wbi-btn-circle (Circle size) has no default: unset, the circle is as
     tall as the button, as in the design. */
  --wbi-btn-overlap: 12px;
  --wbi-btn-icon-size: 24px;
  --wbi-btn-icon-color: #FFFFFF;
  --wbi-btn-icon-stroke: 2;

  /* --- States ---------------------------------------------------------- */
  --wbi-btn-hover-fill: var(--wbi-btn-fill);
  --wbi-btn-glow: rgb(224 149 27 / 0.5);
  --wbi-btn-focus: #C05507;

  /* --- Motion ----------------------------------------------------------
     Leaving takes two thirds of entering. A cleared Duration slider comes
     out as a unitless `0`: `calc(0 * .65)` is a number, not a time, so every
     transition declaration drops and the button changes instantly — which is
     what a zero duration asks for. */
  --wbi-btn-duration: 320ms;
  --wbi-btn-exit: calc(var(--wbi-btn-duration) * 0.65);
  --wbi-btn-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* The hover fill of each effect, still below any Fill set in the element. */
:where(.wbi-button--hover-lighten) {
  --wbi-btn-hover-fill: color-mix(in srgb, var(--wbi-btn-fill) 85%, #7F7F7F);
}

:where(.wbi-button--hover-gradient) {
  --wbi-btn-hover-fill: transparent;
}

/* ==========================================================================
   Root
   ========================================================================== */

.wbi-button {
  position: relative;
  /* The pill sits at z-index 1 and the circle at 2: without a stacking
     context of its own the pair would interleave with the page. */
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  /* Resolved on the root, the node where Bricks writes the tokens.
     A Height set in the element is exact; the design height scales with
     Size. The circle, unless it has a size of its own, is as tall as the
     button: a Circle size is the value at Size 1, so the fallback divides
     by Size what the multiplication puts back. */
  --wbi-btn-body-h: var(--wbi-btn-height, calc(var(--wbi-btn-h) * var(--wbi-btn-size)));
  --wbi-btn-circle-r: calc(var(--wbi-btn-circle, calc(var(--wbi-btn-body-h) / var(--wbi-btn-size))) * var(--wbi-btn-size));
  /* Follows the text unless Width sets one (exact, in any unit). Bricks'
     own Width in Style > Layout writes on #brxe-xxx and wins, and works
     too: the pill fills whatever width the root gets. */
  width: var(--wbi-btn-w, fit-content);
  max-width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  font-family: var(--wbi-btn-font);
  /* Never below 14px, the smallest text the design system allows: a small
     Size keeps shrinking the shapes, not the label. */
  font-size: max(14px, calc(var(--wbi-btn-base) * var(--wbi-btn-size)));
  font-style: normal;
  letter-spacing: 0;
  line-height: 1.5;
  text-align: center;
  text-decoration: none;
  text-transform: none;
  color: var(--wbi-btn-color);
  -webkit-tap-highlight-color: transparent;
}

/* Written as :where() so it never beats the `.wbi-button__*` rules below
   (a tag reset inside the component outranks its own classes otherwise). */
.wbi-button:where(a, button) {
  cursor: pointer;
}

.wbi-button:where(button) {
  appearance: none;
  font: inherit;
}

.wbi-button:focus-visible {
  outline: 2px solid var(--wbi-btn-focus);
  outline-offset: 4px;
  border-radius: calc(var(--wbi-btn-radius) * var(--wbi-btn-size));
}

/* ==========================================================================
   Pill and circle, as the design draws them
   ========================================================================== */

.wbi-button__text,
.wbi-button__icon {
  box-sizing: border-box;
  border: calc(var(--wbi-btn-border-w) * var(--wbi-btn-size)) solid transparent;
  background-color: transparent;
  background-image: var(--wbi-btn-gradient);
  background-origin: border-box;
  /* !important: "Apply to: Text" in the Gradient control clips the
     background to the label and makes the label transparent. */
  -webkit-background-clip: border-box !important;
  background-clip: border-box !important;
  -webkit-text-fill-color: initial !important;
}

/* The fill covers the part's border box and paints inside a padding as wide
   as the border, so its edge meets the inner edge of the border and its
   corners follow the inner curve at any radius. Padding, not a transparent
   border as in WBI Filter: browsers round a border width to whole device
   pixels and a margin not, so at 125% or 175% the fill would cover half a
   pixel of the border. Each part is a stacking context of its own
   (position and z-index below): at -1 the fill paints over the gradient
   and under the label. Longhands rather than `inset`, which Safari only
   reads from 14.1. A cleared width comes as a unitless 0 that voids the
   calc(): margin and padding fall back to 0, as the part's border does. */
.wbi-button__text::after,
.wbi-button__icon::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: -1;
  margin: calc(var(--wbi-btn-border-w) * var(--wbi-btn-size) * -1);
  padding: calc(var(--wbi-btn-border-w) * var(--wbi-btn-size));
  border-radius: inherit;
  background-color: var(--wbi-btn-fill);
  background-clip: content-box;
}

/* "Apply to: Overlay": Bricks paints the gradient in a ::before of its own
   (content, position and the four sides at 0), over the label. Spread over
   the border box and under the fill, it draws the same border. Never there
   otherwise: nothing here gives it content. */
.wbi-button__text::before,
.wbi-button__icon::before {
  z-index: -2;
  margin: calc(var(--wbi-btn-border-w) * var(--wbi-btn-size) * -1);
  border-radius: inherit;
}

.wbi-button__text {
  position: relative;
  z-index: 1;
  display: inline-flex;
  /* Fills the root. With a width set, it takes whatever the circle leaves:
     the button stays that wide and the circle makes room inside it. */
  flex: 1 1 auto;
  align-items: center;
  justify-content: center;
  min-height: var(--wbi-btn-body-h);
  padding: 0 calc(var(--wbi-btn-pad-x) * var(--wbi-btn-size));
  border-radius: calc(var(--wbi-btn-radius) * var(--wbi-btn-size));
  font-size: 1em;
  font-weight: 600;
  line-height: 1.5;
  color: inherit;
}

/* Over the pill's right end, overlapping it by --wbi-btn-overlap. Out of the
   page until something asks for it: touch screens show the button alone,
   and computers show the circle on hover (see the block at the end). */
.wbi-button__icon {
  position: relative;
  z-index: 2;
  display: none;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: var(--wbi-btn-circle-r);
  height: var(--wbi-btn-circle-r);
  margin-inline-start: calc(-1 * var(--wbi-btn-overlap) * var(--wbi-btn-size));
  border-radius: 50%;
  color: var(--wbi-btn-icon-color);
}

/* Always there, on every screen: the "Always show" switch, and a button with
   no text, which would otherwise leave nothing to see or click. */
.wbi-button--static .wbi-button__icon {
  display: inline-flex;
}

/* Only child: with no pill to overlap, the circle sits in its own box. */
.wbi-button__icon:first-child {
  margin-inline-start: 0;
}

/* ==========================================================================
   Icon
   ========================================================================== */

/* Font icons size with the font; SVGs and images with the box. */
.wbi-button__icon > :where(i) {
  font-size: calc(var(--wbi-btn-icon-size) * var(--wbi-btn-size));
  line-height: 1;
}

.wbi-button__icon > :where(svg, img) {
  display: block;
  width: calc(var(--wbi-btn-icon-size) * var(--wbi-btn-size));
  height: calc(var(--wbi-btn-icon-size) * var(--wbi-btn-size));
}

.wbi-button__icon > :where(img) {
  object-fit: contain;
}

.wbi-button__icon--builtin > svg {
  stroke-width: var(--wbi-btn-icon-stroke);
}

/* SVG icons from the Media Library keep their own colors unless asked. */
.wbi-button[data-icon-recolor="stroke"] .wbi-button__icon--svg :is(svg[stroke], [stroke]):not([stroke="none"]),
.wbi-button[data-icon-recolor="both"] .wbi-button__icon--svg :is(svg[stroke], [stroke]):not([stroke="none"]) {
  stroke: currentColor;
}

.wbi-button[data-icon-recolor="fill"] .wbi-button__icon--svg svg,
.wbi-button[data-icon-recolor="both"] .wbi-button__icon--svg svg,
.wbi-button[data-icon-recolor="fill"] .wbi-button__icon--svg [fill]:not([fill="none"]),
.wbi-button[data-icon-recolor="both"] .wbi-button__icon--svg [fill]:not([fill="none"]) {
  fill: currentColor;
}

/* ==========================================================================
   Computers: hover, focus and the reveal of the circle
   ========================================================================== */

@media (hover: hover) and (pointer: fine) {

  /* Where the circle waits, per "When the circle appears". Grow: out of the
     flow, a circle's width to the right of where it docks, so the button
     measures the pill alone. Keep its space and Overflow: in its final slot,
     one overlap to the right. Either way it only ever travels the overlap
     on screen and never crosses the label. */
  .wbi-button {
    --wbi-btn-park-margin: calc(-1 * var(--wbi-btn-circle-r));
    --wbi-btn-park-shift: var(--wbi-btn-circle-r);
    transition:
      filter var(--wbi-btn-duration) ease,
      translate var(--wbi-btn-duration) var(--wbi-btn-ease);
  }

  .wbi-button--reserve,
  .wbi-button--overflow {
    --wbi-btn-park-margin: calc(-1 * var(--wbi-btn-overlap) * var(--wbi-btn-size));
    --wbi-btn-park-shift: calc(var(--wbi-btn-overlap) * var(--wbi-btn-size));
  }

  .wbi-button__text::after,
  .wbi-button__icon::after {
    transition: background-color var(--wbi-btn-duration) ease;
  }

  /* Parked. Grow and Overflow keep it at display: none — out of the layout,
     of the page's scrollable width and of the pointer — and `allow-discrete`
     holds the display until the exit has played. */
  .wbi-button:not(.wbi-button--static) .wbi-button__icon {
    margin-inline-start: var(--wbi-btn-park-margin);
    translate: var(--wbi-btn-park-shift) 0;
    opacity: 0;
    transition:
      margin-inline-start var(--wbi-btn-exit) ease-in,
      translate var(--wbi-btn-exit) ease-in,
      opacity var(--wbi-btn-exit) ease-in,
      display var(--wbi-btn-exit),
      visibility var(--wbi-btn-exit);
    transition-behavior: allow-discrete;
  }

  /* Keep its space: in the layout from the start, only invisible (hidden
     also keeps it from catching the pointer). */
  .wbi-button--reserve:not(.wbi-button--static) .wbi-button__icon {
    display: inline-flex;
    visibility: hidden;
  }

  /* Overflow: out of the flow, over whatever sits to the right. */
  .wbi-button--overflow:not(.wbi-button--static) .wbi-button__icon {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 100%;
    margin-block: auto;
  }

  /* Docked. `.is-active-element` is the Bricks canvas marking the selected
     element: the circle stays out while it is being edited. It never
     reaches the frontend. */
  .wbi-button:not(.wbi-button--static):is(:hover, :focus-visible, .is-active-element) .wbi-button__icon {
    display: inline-flex;
    margin-inline-start: calc(-1 * var(--wbi-btn-overlap) * var(--wbi-btn-size));
    translate: 0 0;
    opacity: 1;
    visibility: visible;
    transition:
      margin-inline-start var(--wbi-btn-duration) var(--wbi-btn-ease),
      translate var(--wbi-btn-duration) var(--wbi-btn-ease),
      opacity var(--wbi-btn-duration) linear,
      display var(--wbi-btn-duration),
      visibility var(--wbi-btn-duration);
    transition-behavior: allow-discrete;
  }

  /* Coming out of display: none there is no previous style to transition
     from: this is it. */
  @starting-style {
    .wbi-button:not(.wbi-button--static):is(:hover, :focus-visible, .is-active-element) .wbi-button__icon {
      margin-inline-start: var(--wbi-btn-park-margin);
      translate: var(--wbi-btn-park-shift) 0;
      opacity: 0;
    }
  }

  /* --- Hover effects -------------------------------------------------- */

  .wbi-button:hover .wbi-button__text::after,
  .wbi-button:hover .wbi-button__icon::after {
    background-color: var(--wbi-btn-hover-fill);
  }

  /* A filter on the root follows the outline of pill and circle together,
     where a box-shadow per shape would paint the circle's over the pill. */
  .wbi-button--hover-glow:hover {
    filter: drop-shadow(0 8px 14px var(--wbi-btn-glow));
  }

  .wbi-button--hover-lift:hover {
    translate: 0 -3px;
    filter: drop-shadow(0 10px 10px rgb(13 17 21 / 0.3));
  }
}

/* !important, not a longer selector: the rules above set `transition` as a
   shorthand with up to four classes. The circle still appears; it just does
   not travel, and nothing lifts. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: reduce) {
  .wbi-button,
  .wbi-button .wbi-button__icon,
  .wbi-button .wbi-button__text::after,
  .wbi-button .wbi-button__icon::after {
    transition-duration: 1ms !important;
    transition-delay: 0s !important;
  }

  .wbi-button--hover-lift:hover {
    translate: none;
  }
}
