/* Choosing how to pay.
 *
 * The button used to go straight to Stripe, which quietly decided for everybody
 * that they were paying by card. Crypto existed and nothing on the page said so,
 * and Robux, which is how a lot of Roblox players actually have money, was not
 * offered at all.
 *
 * A dialog rather than three buttons on the card, for the same reason the free
 * key picker is one: the choice changes what happens next, and two of the three
 * routes leave the site. That is worth a moment rather than a row of icons
 * somebody clicks by accident.
 *
 * Visual language deliberately matched to gateway.css. Two pickers that make the
 * same kind of choice should not look like they came from different products.
 */

.paypick {
  position: fixed;
  inset: 0;
  z-index: 220;
  display: grid;
  place-items: center;
  padding: var(--s-5);
  background: var(--scrim-mid);
  backdrop-filter: blur(3px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-move) var(--ease), visibility 0s linear var(--t-move);
}
.paypick[data-open="1"] {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--t-move) var(--ease), visibility 0s;
}

/* Two columns once there is room, and never taller than the window.
 *
 * The dialog was one 660px column with everything stacked, which is fine for a
 * plan and falls apart for a game: a customer holding five licences got five
 * destination options above the payment methods, so the thing they came to do
 * was below the fold and the dialog ran off the bottom of the screen.
 *
 * Above 900px the destination question takes the left column and the payment
 * choice takes the right, so both are on screen at once and the dialog stops
 * growing with the number of licences somebody owns. Below that it stays a
 * single column, which is correct on a phone.
 *
 * `:has(.paydest)` because a plan or bundle purchase has no destination
 * question at all, and a two-column grid with one empty column would be a
 * worse layout than the one this replaces. */
.paydialog {
  width: min(660px, 100%);
  background: var(--sur);
  border: 1px solid var(--ln);
  border-radius: var(--rad-large);
  box-shadow: 0 40px 90px -50px var(--bloom);
  transform: translateY(10px) scale(0.985);
  transition: transform var(--t-enter) var(--ease);
  /* X hidden to clip the rounded corners, Y auto so a tall dialog scrolls
     inside itself. The single `overflow: hidden` that used to be here did both
     jobs and made the second one impossible, which is how the dialog came to
     run off the bottom of the screen instead of scrolling. */
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  max-height: min(88vh, 900px);
}
.paypick[data-open="1"] .paydialog { transform: none; }

@media (min-width: 900px) {
  .paydialog:has(.paydest) {
    width: min(1020px, 100%);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-content: start;
  }
  .paydialog:has(.paydest) > .payhead,
  .paydialog:has(.paydest) > .paymsg,
  .paydialog:has(.paydest) > .payfoot { grid-column: 1 / -1; }
  /* The destination question spans both rows on the left, so a long licence
     list scrolls inside itself instead of stretching the dialog. */
  .paydialog:has(.paydest) > .paydest {
    grid-column: 1; grid-row: 2 / span 2;
    border-right: 1px solid var(--ln);
  }
  .paydialog:has(.paydest) > .paylist { grid-column: 2; grid-row: 2; }
  .paydialog:has(.paydest) > .paycoupon { grid-column: 2; grid-row: 3; align-self: start; }
}

/* However many licences somebody owns, the list is bounded, so the payment
   methods beside it never move.
 *
 * The cap is on `.destopts` and NOT on `.destinner`. That element carries
 * `overflow: hidden` for the 0fr to 1fr height animation, and giving it a
 * scroller would have fought the collapse it exists to perform. The list
 * inside it takes no part in that animation and can scroll freely. */
.destopts { max-height: min(44vh, 400px); overflow-y: auto; overscroll-behavior: contain; }

.payhead { padding: var(--s-5) var(--s-6) var(--s-4); border-bottom: 1px solid var(--ln); }
.payhead h3 { margin-bottom: var(--s-1); }
.payhead p { margin: 0; color: var(--mut); font-size: var(--t-sm); }
/* What is being bought and what it costs, restated at the moment of decision.
   Somebody who opened three product pages should not have to remember which
   one this dialog belongs to. */
.payhead .payfor { color: var(--fg); font-weight: 500; }

/* ── where the game goes ───────────────────────────────────────────────────
 *
 * A different question from "how do you want to pay", so it gets its own ground
 * rather than being a fourth row in the method list. Recessed instead of raised:
 * this is a setting on the purchase, and the purchase is the thing below it.
 *
 * The height animates through grid-template-rows 0fr -> 1fr, which is a real
 * height transition with nothing measured in JavaScript. The alternative,
 * max-height with a guessed ceiling, eases against a number that is wrong for
 * every count of options and shows it as a stall at the end.
 */
.paydest {
  display: grid;
  grid-template-rows: 0fr;
  border-bottom: 1px solid var(--ln);
  background: var(--barbg);
  transition: grid-template-rows var(--t-grow) var(--ease), opacity var(--t-move) var(--ease);
  opacity: 0;
}
.paydest[data-in="1"] { grid-template-rows: 1fr; opacity: 1; }
.destinner { overflow: hidden; padding: 0 var(--s-6); }
.paydest[data-in="1"] .destinner { padding: var(--s-5) var(--s-6); }
/* Padding is on the inner element and animates with it, so a collapsed section
   is genuinely zero high rather than the height of its own padding. */
.destinner { transition: padding var(--t-grow) var(--ease); }

.destlead {
  margin: 0 0 var(--s-3);
  font-size: var(--t-label);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--mut);
}

.destopts { display: grid; gap: var(--s-2); }

.destopt {
  appearance: none;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  background: var(--sur);
  border: 1px solid var(--ln);
  border-radius: var(--rad-soft);
  padding: var(--s-3) var(--s-4);
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: var(--s-3);
  transition:
    border-color var(--t-tint) var(--ease),
    background-color var(--t-tint) var(--ease),
    box-shadow var(--t-tint) var(--ease);
}
.destopt:hover { border-color: var(--edge); background: var(--hov); }
.destopt[aria-pressed="true"] {
  border-color: var(--acc);
  background: var(--hov);
  box-shadow: inset 0 0 0 1px var(--acc), 0 10px 26px -22px var(--bloom);
}

/* The mark fills from the middle, so selecting reads as a state settling rather
   than as a second element appearing. */
.destmark {
  width: 1rem;
  height: 1rem;
  margin-top: 0.15em;
  border-radius: 50%;
  border: 1px solid var(--edge);
  display: grid;
  place-items: center;
  transition: border-color var(--t-tint) var(--ease);
}
.destmark::after {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--acc);
  transform: scale(0);
  transition: transform var(--t-step) var(--ease);
}
.destopt[aria-pressed="true"] .destmark { border-color: var(--acc); }
.destopt[aria-pressed="true"] .destmark::after { transform: scale(1); }

.destopt b { display: block; font-weight: 600; font-size: var(--t-body); }
.destopt code {
  font-family: var(--mono);
  font-size: 0.95em;
  color: var(--acc-txt);
  letter-spacing: var(--track-label);
}
.destopt i { display: block; margin-top: 0.15em; font-style: normal; color: var(--mut); font-size: var(--t-sm); }

.destnote { margin: var(--s-3) 0 0; color: var(--mut); font-size: var(--t-label); }

.paylist { display: grid; }

.paymethod {
  appearance: none;
  text-align: left;
  cursor: pointer;
  background: none;
  border: 0;
  padding: var(--s-5) var(--s-6);
  font: inherit;
  color: inherit;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--s-4);
  transition: background-color var(--t-tint) ease;
}
.paymethod + .paymethod { border-top: 1px solid var(--ln); }
.paymethod:hover, .paymethod:focus-visible { background: var(--hov); }
.paymethod[disabled] { opacity: 0.5; cursor: default; }
.paymethod[disabled]:hover { background: none; }

.paymethod .ic { width: 1.5rem; height: 1.5rem; color: var(--acc-txt); }
.paymethod b {
  display: block;
  font-size: var(--t-h3);
  font-weight: 600;
  letter-spacing: var(--track-display);
}
.paymethod p { margin: var(--s-1) 0 0; color: var(--mut); font-size: var(--t-sm); }
.paymethod .paygo { color: var(--acc-txt); font-size: var(--t-sm); white-space: nowrap; }

/* A tag only where it says something true. "Instant" on the card route is a
   fact about the flow, not a nudge. */
.paytag {
  display: inline-block;
  margin-left: var(--s-2);
  padding: 0.1em 0.5em;
  border-radius: var(--rad-pill);
  font-size: var(--t-label);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  vertical-align: middle;
}
.paytag.fast { background: var(--acc); color: var(--on-acc); }
.paytag.manual { background: var(--hov); color: var(--mut); }

/* Robux leans on the second accent, so "handled by a person" reads as a
   different kind of route rather than a lesser version of the first. */
.paymethod[data-method="robux"] .ic,
.paymethod[data-method="robux"] .paygo { color: var(--acc2); }

.payfoot {
  padding: var(--s-4) var(--s-6);
  border-top: 1px solid var(--ln);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
}
.payfoot .paynote { margin: 0; color: var(--mut); font-size: var(--t-label); }

/* Failures land inside the dialog, next to the choice that caused them, rather
   than on the page behind it where nobody is looking. */
.paymsg { margin: 0; padding: 0 var(--s-6) var(--s-5); font-size: var(--t-sm); }
.paymsg:empty { display: none; }
.paymsg[data-kind="bad"] { color: var(--warn); }

/* The discount code. Above the methods, because a discount has to be entered
   before the choice that leaves the page, and quiet, because most buyers do not
   have one and it must not read as a field they are failing to fill in. */
.paycoupon { padding: 0 var(--s-6) var(--s-4); display: grid; gap: var(--s-2); }
.paycoupon .field { display: grid; gap: 6px; }
.paycoupon .field > span {
  font-size: var(--t-label); color: var(--mut);
  text-transform: uppercase; letter-spacing: var(--track-label);
}
.paycoupon input {
  width: 100%; box-sizing: border-box;
  padding: 9px var(--s-3); border-radius: var(--rad-sharp);
  border: 1px solid var(--ln); background: var(--inp); color: var(--fg);
  font: inherit; font-family: var(--mono); font-size: var(--t-sm);
  letter-spacing: .04em; text-transform: uppercase;
  transition: border-color var(--t-tint) ease;
}
.paycoupon input::placeholder { color: var(--mut); text-transform: none; letter-spacing: normal; }
.paycoupon input:focus { border-color: var(--acc); outline: none; box-shadow: 0 0 0 3px var(--spot); }
.paycoupmsg { margin: 0; font-size: var(--t-label); }
.paycoupmsg:empty { display: none; }
.paycoupmsg[data-kind="ok"] { color: var(--ok); }
.paycoupmsg[data-kind="bad"] { color: var(--warn); }
@media (prefers-reduced-motion: reduce) { .paycoupon input { transition: none; } }

@media (max-width: 560px) {
  .paymethod { grid-template-columns: auto 1fr; }
  .paymethod .paygo { grid-column: 2; }
}
@media (prefers-reduced-motion: reduce) {
  .paypick, .paydialog, .paydest, .destinner, .destopt, .destmark::after { transition: none; }
}

/* ── the Robux quote ──────────────────────────────────────────────────────
   Shown before the ticket, because everything on this site is priced in baht
   and the trade is settled in Robux: choosing it used to send somebody to a
   Discord ticket with no idea what they were about to be asked for. */
.robuxquote { padding: var(--s-5) var(--s-6); display: grid; gap: var(--s-5); }
.rqamt {
  display: grid; gap: 4px; justify-items: center; text-align: center;
  padding: var(--s-5) var(--s-4);
  border: 1px solid var(--ln); border-radius: var(--rad-large);
  background: var(--inp);
  position: relative; overflow: hidden;
}
/* One lit edge along the top, the same device the account stats use, so the
   number reads as the answer rather than as another row. */
.rqamt::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: var(--acc); box-shadow: 0 0 12px -1px var(--acc);
}
.rqamt > span {
  color: var(--mut); font-size: var(--t-label);
  letter-spacing: var(--track-label); text-transform: uppercase;
}
.rqamt > b {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: clamp(30px, 6vw, 44px); font-weight: 650; letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums; color: var(--fg);
}
.rqamt > b .ic { width: 0.72em; height: 0.72em; color: var(--acc-txt); }
.rqamt > u { text-decoration: none; color: var(--mut); font-size: var(--t-xs); }

.rqsteps { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--s-3); counter-reset: rq; }
.rqsteps li { color: var(--mut); font-size: var(--t-sm); padding-left: 30px; position: relative; }
.rqsteps li:first-child { padding-left: 0; color: var(--fg); font-weight: 600; }
.rqsteps li:not(:first-child)::before {
  counter-increment: rq; content: counter(rq);
  position: absolute; left: 0; top: 0;
  width: 20px; height: 20px; border-radius: var(--rad-pill);
  border: 1px solid var(--ln); background: var(--inp);
  display: grid; place-items: center;
  font-size: 11px; font-variant-numeric: tabular-nums; color: var(--acc-txt);
}

/* Said only when a code was typed: the Robux figure above is undiscounted,
   because nothing on this route applies a code automatically. */
.rqnote {
  margin: 0; padding: var(--s-3) var(--s-4);
  border: 1px dashed var(--ln); border-radius: var(--rad-soft);
  background: var(--inp); color: var(--mut); font-size: var(--t-xs);
}
