/* Payment page — one card, light & dark via prefers-color-scheme. */
:root {
  --bg: #f5f6f8;
  --card: #ffffff;
  --ink: #16181d;
  --ink-2: #5b6069;
  --line: #e3e5ea;
  --accent: #16181d;        /* pay button */
  --accent-ink: #ffffff;
  --error: #b3261e;
  --error-bg: #fdecea;
  --success: #0a7d3f;
  --success-bg: #e7f5ec;
  --waiting: #8a6100;       /* payment still processing */
  --waiting-bg: #fdf3e0;
  --ring: rgba(22, 24, 29, 0.12);   /* focus glow, shared with Stripe's inputs */
  --radius: 14px;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0e0f12;
    --card: #17181d;
    --ink: #f2f3f5;
    --ink-2: #9aa0aa;
    --line: #2a2c33;
    --accent: #f2f3f5;
    --accent-ink: #16181d;
    --error: #ff8a80;
    --error-bg: #2c1615;
    --success: #56d68d;
    --success-bg: #12271b;
    --waiting: #fbbf24;
    --waiting-bg: #291f0d;
    --ring: rgba(242, 243, 245, 0.16);
  }
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
/* Hides the checkout form until Stripe's Element reports ready, WITHOUT
   collapsing it. Stripe sizes its tab strip from the container's width at
   mount time; display:none would hand it a zero-width box and can bury the
   Apple Pay tab in the overflow. visibility also removes the subtree from
   tab order and pointer events, so nothing is interactive early. */
.is-loading { visibility: hidden; }
html, body { margin: 0; }
body {
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans", "Noto Sans",
        "Microsoft YaHei", sans-serif;
  -webkit-font-smoothing: antialiased;
  display: grid;
  place-items: start center;
  min-height: 100dvh;
  padding: 40px 16px;
}

.card {
  width: 100%;
  max-width: 440px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px;
}

.product {
  display: flex;
  align-items: center;
  gap: 14px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 20px;
}
.product img { border-radius: 12px; }
.product-meta { flex: 1; min-width: 0; }
.product h1 {
  margin: 0;
  font-size: 18px;
  font-weight: 650;
  line-height: 1.3;
}
.product p {
  margin: 2px 0 0;
  color: var(--ink-2);
  font-size: 13px;
}
/* The narrow-screen rule that used to live here gave the amount its own line,
   because it competed with the subtitle for width and squeezed the longer
   locales to four lines. With the amount gone from this row, the subtitle has
   the width to itself and the rule has nothing left to fix. */

.status { color: var(--ink-2); margin: 8px 0; }
.status.error { color: var(--error); }

.field { margin-bottom: 16px; }
/* Pinned to the same size/weight Stripe's .Label is pinned to in pay.js, so
   "Email" sits level with "Card number" instead of a notch smaller. */
.field label {
  display: block;
  font-size: 14px;
  font-weight: 500;
  margin-bottom: 6px;
}
/* Matched to Stripe's .Input, which measures 44.4px tall: 12px padding top and
   bottom, 1px border each side, leaving 18.4px of line box — 1.15 at our 16px
   font size. Stripe publishes no default metrics, so this was derived from the
   rendered height; re-measure the card field if Stripe ever changes it.
   16px rather than the body's 15px is Stripe's own floor on mobile, and iOS
   Safari zooms the page on a focused input below 16px. */
.field input {
  width: 100%;
  padding: 12px;
  font: inherit;
  font-size: 16px;
  line-height: 1.15;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 8px;
  outline: none;
}
.field input:focus {
  border-color: var(--ink-2);
  box-shadow: 0 0 0 3px var(--ring);
}
.help { margin: 6px 0 0; font-size: 12px; color: var(--ink-2); }
.help.error { color: var(--error); }

#payment-element { margin-bottom: 18px; }

#submit {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 13px 16px;
  font: inherit;
  font-weight: 650;
  color: var(--accent-ink);
  background: var(--accent);
  border: 0;
  border-radius: 10px;
  cursor: pointer;
}
#submit:hover { opacity: 0.92; }
#submit:disabled { opacity: 0.55; cursor: default; }

.spinner {
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Success page */
.result { text-align: center; padding: 12px 0 4px; }
.result .mark {
  width: 52px;
  height: 52px;
  margin: 0 auto 16px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 26px;
  font-weight: 650;
  line-height: 1;
  background: var(--bg);
}
/* The glyph carries the outcome before the text is read. */
.result .mark[data-state="paid"] { color: var(--success); background: var(--success-bg); }
.result .mark[data-state="processing"] { color: var(--waiting); background: var(--waiting-bg); }
.result .mark[data-state="failed"] { color: var(--error); background: var(--error-bg); }
.result h1[data-state="paid"] { color: var(--success); }
.result h1[data-state="failed"] { color: var(--error); }
/* Inline links in the result text: default browser blue fights the card. */
.result p a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.result p a:hover { color: var(--ink); }
.result h1 { font-size: 20px; margin: 0 0 8px; }
.result p { color: var(--ink-2); margin: 0 0 20px; }
/* Small print in the result card — quieter than the body line. */
.result .hint { font-size: 12px; }
/* The spam note qualifies the body directly above it, so it sits close. */
.result #spam-note { margin-top: -12px; }
/* The support line follows the retry button and needs room from it. */
.result #support-line { margin-top: 16px; }
.result a.button {
  display: inline-block;
  padding: 11px 20px;
  font-weight: 650;
  color: var(--accent-ink);
  background: var(--accent);
  border-radius: 10px;
  text-decoration: none;
}
