.fire-pay-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  /* Anchors the busy spinner below. Nothing else depends on it, and the theme
     override in kyoto/assets/css/fire-plugins.css does not touch position. */
  position: relative;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  padding: 12px 24px;
  border: none;
  border-radius: 8px;
  transition: filter 0.2s ease, box-shadow 0.2s ease, transform 0.1s ease;
  -webkit-user-select: none;
  user-select: none;
}

/* The button is an <a>, so :disabled never matches it and :not(:disabled) is
   always true. Both states are carried on aria-disabled instead, which is the
   attribute a screen reader reads anyway. The :disabled selectors stay for the
   block editor preview, which still renders a real <button>. */
.fire-pay-btn:hover:not(:disabled):not([aria-disabled="true"]) {
  filter: brightness(0.9);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}

.fire-pay-btn:active:not(:disabled):not([aria-disabled="true"]) {
  transform: scale(0.97);
}

.fire-pay-btn:disabled,
.fire-pay-btn[aria-disabled="true"] {
  opacity: 0.6;
  cursor: default;
  pointer-events: none;
}

.fire-pay-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

/* Work in flight.
 *
 * THE BOX MUST NOT MOVE. The button used to have its children replaced with
 * "Preparing…" and then "Open Fire Wallet", so a single tap resized it twice and
 * threw away both the merchant's mark and the words they chose. The label is
 * theirs; nothing here is allowed to rewrite it.
 *
 * So the children stay in the flow at full size and merely go transparent, and
 * the spinner is taken out of flow entirely. The button is then the same width,
 * the same height and the same colour busy as it is at rest, by construction
 * rather than by matching values that could drift apart later.
 *
 * Out of flow also means this works whether or not the shortcode drew a mark.
 * A spinner that took a real slot in the flex line would widen every button with
 * `show_logo` off, which is the bug this replaces wearing a different hat.
 *
 * Independent of aria-disabled on purpose. A button can be busy and still
 * tappable: that is the pointerdown warm, where the link is being minted and the
 * tap that follows must still be allowed to navigate. */
.fire-pay-btn[aria-busy="true"] > * {
  opacity: 0;
}

.fire-pay-btn > * {
  transition: opacity 0.15s ease;
}

.fire-pay-btn[aria-busy="true"]::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  /* Derived from the button's own text colour, never from a fixed one. The old
     spinner hardcoded a white track, and build_button_style() gives `outline`
     and `minimal` a transparent background, so on those two variants the track
     was white on a white page and the shopper saw a lone arc in space.
     The rgba line is the fallback for browsers without color-mix; it is a
     neutral grey precisely because it has to read on a button of any colour. */
  border: 2px solid rgba(128, 128, 128, 0.25);
  border-color: color-mix(in srgb, currentColor 25%, transparent);
  border-top-color: currentColor;
  animation: fire-pay-spin 0.8s linear infinite;
}

@keyframes fire-pay-spin {
  to { transform: rotate(360deg); }
}

.fire-pay-status {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 13px;
  margin-top: 8px;
  min-height: 20px;
  transition: color 0.2s ease;
}

.fire-pay-status.confirming {
  animation: fire-pay-pulse 2s ease-in-out infinite;
}

.fire-pay-status.success {
  color: #22c55e;
}

.fire-pay-status.error {
  color: #FF4D6A;
}

@keyframes fire-pay-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

/* The way out of waiting.
 *
 * Deliberately quiet. It sits under a Pay button while a payment may still be
 * in flight, and anything that competes with that button for attention is
 * inviting the one tap nobody wants. A text control reads as an escape hatch,
 * which is what it is.
 *
 * A sibling of .fire-pay-status rather than a child of it: that element is
 * aria-live, so a control inside it would be re-announced on every poll, and it
 * pulses its own opacity while confirming, which a child cannot opt out of. */
.fire-pay-stop {
  display: block;
  margin-top: 6px;
  padding: 0;
  background: none;
  border: none;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 13px;
  line-height: 1.4;
  color: #666;
  text-decoration: underline;
  cursor: pointer;
}

.fire-pay-stop:hover {
  color: #18181b;
}

.fire-pay-install {
  font-size: 13px;
  color: #666;
}

.fire-pay-install a {
  color: #FF4D6A;
  text-decoration: underline;
}

.fire-pay-install a:hover {
  color: #e63e58;
}

/* Returning from the Fire app lands on a fresh page load, and the button that
   started the payment may not be findable: the page can have changed, or the
   payment may have been started somewhere else entirely. This is the fallback
   the landing code uses when it has an outcome and nowhere sensible to attach
   it. A correct message at the top of the page beats the same message under the
   wrong price. */
.fire-pay-return-banner {
  padding: 12px 20px;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 14px;
  line-height: 1.4;
  text-align: center;
  background: #f4f4f5;
  color: #18181b;
  border-bottom: 1px solid #e4e4e7;
}

.fire-pay-return-banner.success {
  background: #ecfdf5;
  color: #065f46;
  border-bottom-color: #a7f3d0;
}

.fire-pay-return-banner.error {
  background: #fef2f2;
  color: #991b1b;
  border-bottom-color: #fecaca;
}

/* Slowed, not stopped, and last in the file so it wins over the rules above.
 *
 * Both animations here carry meaning rather than decoration: the spin is the
 * only thing on screen saying the button is working, and the pulse is what
 * separates "still confirming" from a line of text that has stopped changing.
 * Removing them outright would leave a blank button and a status that looks
 * settled when it is not, so they are slowed to a rate that reads as progress
 * without reading as motion. */
@media (prefers-reduced-motion: reduce) {
  .fire-pay-btn[aria-busy="true"]::after {
    animation-duration: 3s;
  }

  .fire-pay-btn > * {
    transition: none;
  }

  .fire-pay-status.confirming {
    animation-duration: 6s;
  }
}
