/*
 * The payment interaction, as components every Fire plugin can use.
 *
 * A payment looks the same wherever it happens: a button you press, a mark on
 * it, a spinner while the wallet is working, a line of text underneath saying
 * what is going on, and a prompt if the wallet is not installed. Fire Pay and
 * Fire Gates had each built all five, separately, and they had drifted:
 *
 *   gap            8px            vs  0.5em
 *   padding        12px 24px      vs  0.75em 1.5em
 *   border-radius  8px            vs  4px
 *   font           14px / 500     vs  1em / 600
 *   min-height     none           vs  44px
 *   hover          brightness+shadow  vs  opacity
 *   focus-visible  none           vs  2px solid currentColor
 *   spinner        ::after, 14px  vs  a real element, 16px
 *   reduced motion honoured       vs  ignored
 *
 * So this is not lifted from one of them. It is Fire Pay's implementation, which
 * is the more carefully built of the two, plus the one thing it was missing.
 * Fire Gates adopts it next and Fire Fund and Fire Shop after that, which is why
 * it lands before Gates is wired as a consumer rather than after: otherwise
 * Gates reinvents the components it is supposed to be consuming.
 *
 * NAMES. These are additive. A consumer keeps its own class and adds the Core
 * one beside it: `class="fire-core-btn fire-pay-btn"`. Renaming is not available:
 * kyoto/assets/css/fire-plugins.css styles .fire-pay-btn and .fire-gate-btn with
 * !important, both plugins' scripts query their own names, and a stylesheet
 * handle turned out to be a public contract once already.
 *
 * Consumers keep what is genuinely theirs. Fire Pay's return banner and its
 * "I did not pay" control are not payment components, they are Fire Pay's
 * answers to Fire Pay's problems, and they stay in fire-pay.css.
 *
 * SIZING IS em, not px. The button is the size of the text around it, so one
 * dropped into small print is small and one in a hero is big, and both follow a
 * reader who has turned their browser font up. Two values stay in pixels on
 * purpose and say why at the line: min-height, which measures a fingertip rather
 * than the text, and border-radius, which is a drawn detail rather than a unit
 * of type. Stroke widths likewise.
 *
 * The typeface comes from --fire-font-body, so this file depends on fire-tokens,
 * which depends on fire-fonts. It was a hardcoded Inter stack, and Inter was
 * never fetched by anything: the button has been rendering in whatever
 * -apple-system resolved to. The design system says Instrument Sans and now the
 * button is set in it.
 *
 * Everything else here is still the value Fire Pay shipped, apart from the three
 * noted at min-height and font-size. Colours have not moved onto tokens yet;
 * that is a visible change and gets its own commit.
 */

/* ------------------------------------------------------------------ button */

.fire-core-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  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: var(--fire-font-body);
  /*
   * 1em, so the button is the size of the text around it.
   *
   * Not 16px. A payment button dropped into a small print footer should be small,
   * and one in a hero should be big, and both should follow a reader who has
   * turned their browser font up. An absolute size ignores all three.
   *
   * This is what Fire Gates already rendered. Fire Pay was 14px / 500, so its
   * button gains a weight step and, on a default 16px page, 2px of text.
   */
  font-size: 1em;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  padding: 0.75em 1.5em;
  border: none;
  /* The other one that stays in pixels. A corner radius is a drawn detail, not a
     unit of text: scaled with the font it turns a small button into a lozenge
     and a large one into a near-square. */
  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 touch target floor, and one of the two things in this file that stays in
   * pixels on purpose.
   *
   * 44px is the smallest thing iOS treats as reliably tappable and the number
   * WCAG 2.5.5 asks for. It is a measurement of a fingertip, not of the text, so
   * it does not scale with either. Written as 2.75em it would hold at a 16px
   * base and quietly drop under the floor everywhere else, which is worse than
   * not having it: a rule that looks like a guarantee and is not.
   *
   * Fire Gates had this and Fire Pay did not, whose button stood about 38px.
   */
  min-height: 44px;
}

/* 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-core-btn:hover:not(:disabled):not([aria-disabled="true"]) {
  filter: brightness(0.9);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}

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

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

/*
 * The one thing Fire Pay did not have.
 *
 * .fire-pay-btn had no focus style of any kind, so the pay button was invisible
 * to anyone navigating by keyboard: it could be reached and activated, and
 * nothing on screen said where they were. Fire Gates had this and Fire Pay did
 * not, which is the argument for one component rather than two.
 *
 * currentColor rather than a fixed colour, for the same reason the spinner
 * derives its track from currentColor: the outline and minimal button variants
 * are transparent, and a ring in a fixed colour disappears on one of them.
 */
.fire-core-btn:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.fire-core-btn__icon {
  /* Square, and the height of one line of the label it sits next to. */
  width: 1em;
  height: 1em;
  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-core-btn[aria-busy="true"] > * {
  opacity: 0;
}

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

.fire-core-btn[aria-busy="true"]::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.875em;
  height: 0.875em;
  margin: -0.4375em 0 0 -0.4375em;
  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-spin 0.8s linear infinite;
}

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

/* ------------------------------------------------------------- status line */

.fire-core-status {
  font-family: var(--fire-font-body);
  font-size: 0.8125em;
  margin-top: 0.5em;
  /* One line's worth, reserved, so the box does not jump when a message
     arrives or clears. */
  min-height: 1.5em;
  transition: color 0.2s ease;

  /*
   * Muted at rest, which is what a status line is: secondary to the button
   * above it, and only worth reading when it says something.
   *
   * From Fire Gates. Fire Pay's had no colour and inherited the page's body
   * text, so a line reading "Waiting for your payment…" carried the same weight
   * as the article around it. The state classes below still override this, which
   * is the point: grey when idle, green when paid, red when not.
   */
  color: #666;
}

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

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

/* Not the brand red, which happens to be a near neighbour. This is the colour
   an error is, sitting beside the green above it, and the two have to read as a
   pair rather than as "brand" and "green". */
.fire-core-status.error {
  color: #FF4D6A;
}

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

/* ---------------------------------------------------------- no wallet yet */

.fire-core-install {
  font-size: 0.8125em;
  color: #666;
}

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

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

/* ---------------------------------------------------------- reduced motion */

/*
 * 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.
 *
 * Fire Gates has no equivalent block, so its spinner currently animates at full
 * speed whatever the visitor has asked for. Adopting these components is what
 * fixes that, and it is the second reason this is one component set and not two.
 */
@media (prefers-reduced-motion: reduce) {
  .fire-core-btn[aria-busy="true"]::after {
    animation-duration: 3s;
  }

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

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