:root {
  --bg: #0a1518;
  --card: rgba(20, 40, 45, 0.86);
  --card-edge: rgba(255, 255, 255, 0.08);
  --ink: #f3f7f6;
  --muted: #9bb0b4;
  --accent: #3db8a7;
  --accent-bright: #5ff0da;
  --accent-ink: #06221e;
  --danger: #ff8f8f;
  --gold: #f0c36a;
  --radius: 16px;
  --font: "Segoe UI", "Avenir Next", "Trebuchet MS", sans-serif;
}

@property --holo-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100vh;
  padding: 28px clamp(16px, 5vw, 64px) 48px;
  background:
    radial-gradient(90% 60% at 85% -10%, rgba(122, 168, 255, 0.14), transparent 60%),
    radial-gradient(110% 70% at 0% 0%, rgba(61, 184, 167, 0.16), transparent 55%),
    linear-gradient(170deg, #081215 0%, #10262b 55%, #0a191d 100%);
  color: var(--ink);
  font-family: var(--font);
}

/* ambient layers */
.bg-grid {
  position: fixed;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(95, 240, 218, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(95, 240, 218, 0.045) 1px, transparent 1px);
  background-size: 44px 44px;
  mask-image: radial-gradient(75% 60% at 50% 30%, #000 30%, transparent 100%);
}

.bg-glow {
  position: fixed;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(50% 30% at 50% 12%, rgba(63, 214, 255, 0.09), transparent 70%);
  animation: breathe 7s ease-in-out infinite;
}

@keyframes breathe {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 1; }
}

.dim { color: var(--muted); }
.small { font-size: 12px; margin: 2px 0 0; }
.hidden { display: none !important; }

/* header */
.top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  margin-bottom: 30px;
}

.brand {
  display: flex;
  gap: 12px;
  align-items: center;
}

.brand img {
  border-radius: 9px;
  background: #efe8d8;
}

.brand h2 {
  margin: 0;
  font-size: 17px;
  letter-spacing: 0.01em;
}

/* header right side: language picker sits beside the account chip */
.top-right {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 10px;
}

.lang-picker {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px 6px 14px;
  border-radius: 999px;
  border: 1px solid var(--card-edge);
  background: rgba(15, 32, 36, 0.8);
}

.lang-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.lang-picker select {
  appearance: none;
  border: 1px solid var(--card-edge);
  border-radius: 999px;
  padding: 5px 12px;
  max-width: 190px;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  color: var(--ink);
  background: rgba(8, 20, 23, 0.9);
}

.lang-picker select:focus-visible {
  outline: 2px solid var(--accent-bright);
  outline-offset: 1px;
}

/* Native option lists render on the OS surface, which is light on most
   platforms — force readable colors so the list is not white-on-white. */
.lang-picker select option {
  color: #10262b;
  background: #f3f7f6;
}

.account-chip {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border-radius: 999px;
  border: 1px solid var(--card-edge);
  background: rgba(15, 32, 36, 0.8);
}

.chip-text {
  display: grid;
  line-height: 1.3;
}

.chip-email {
  font-size: 12px;
  font-weight: 600;
}

.chip-balance {
  font-size: 11px;
  color: var(--accent-bright);
}

/* plan badges (shared look with the popup) */
.plan-badge {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 4px 11px;
  border-radius: 999px;
  white-space: nowrap;
}

.plan-badge.trial {
  color: var(--gold);
  border: 1px solid rgba(240, 195, 106, 0.45);
  background: rgba(240, 195, 106, 0.12);
}

.plan-badge.premium {
  color: #eafffb;
  border: 2px solid transparent;
  background:
    linear-gradient(#0d2a2e, #0d2a2e) padding-box,
    conic-gradient(from var(--holo-angle), #59f2dc, #7aa8ff, #d78cff, #ffd08a, #59f2dc) border-box;
  animation: holo-spin 3.2s linear infinite, holo-glow 3.2s ease-in-out infinite;
}

@keyframes holo-spin {
  to { --holo-angle: 360deg; }
}

@keyframes holo-glow {
  0%, 100% { box-shadow: 0 0 6px rgba(122, 168, 255, 0.35); }
  50% { box-shadow: 0 0 14px rgba(215, 140, 255, 0.55); }
}

/* hero */
.hero {
  max-width: 640px;
  margin: 0 auto 34px;
  text-align: center;
}

.hero h1 {
  margin: 0 0 12px;
  font-size: clamp(26px, 4.5vw, 40px);
  letter-spacing: 0.01em;
}

.holo-text {
  background: linear-gradient(100deg, #5ff0da 10%, #7aa8ff 38%, #d78cff 62%, #5ff0da 90%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: holo-sheen 5s linear infinite;
}

@keyframes holo-sheen {
  to { background-position: 220% 0; }
}

.lede {
  margin: 0 auto 18px;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.6;
}

.assurance {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 20px;
  margin: 0;
  padding: 0;
  font-size: 13px;
  color: #cfe8e4;
}

.tick {
  color: var(--accent-bright);
  font-weight: 800;
  margin-right: 5px;
}

/* notices */
.notice {
  max-width: 460px;
  margin: 0 auto 26px;
  padding: 18px 20px;
  text-align: center;
  border-radius: var(--radius);
  border: 1px solid var(--card-edge);
  background: var(--card);
}

.notice p {
  margin: 0 0 12px;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.5;
}

.buy-error {
  max-width: 560px;
  margin: 0 auto 20px;
  text-align: center;
  color: var(--danger);
  font-size: 13px;
  line-height: 1.4;
}

/* --------------------------------------------------------------------------
   Referral code entry. Deliberately quiet: it sits above the packs so it is
   read before a buy button is pressed, but it is not the offer — anyone
   without a code should be able to skip straight past it.
--------------------------------------------------------------------------- */
.referral-bar {
  max-width: 560px;
  margin: 0 auto 22px;
  text-align: center;
}

/*
 * The form wore the same muted grey as every hint on the page and read as
 * disabled chrome — people scrolled past an offer worth 25% of their pack.
 * It now carries the holo edge the premium plan badge uses, so the two read
 * as the same class of thing: something good, not something broken.
 */
.referral-form {
  position: relative;
  padding: 14px 16px 16px;
  border: 2px solid transparent;
  border-radius: 18px;
  background:
    linear-gradient(rgba(13, 42, 46, 0.92), rgba(13, 42, 46, 0.92)) padding-box,
    conic-gradient(from var(--holo-angle), #59f2dc, #7aa8ff, #d78cff, #ffd08a, #59f2dc) border-box;
  animation: holo-spin 4.6s linear infinite, referral-glow 4.6s ease-in-out infinite;
}

@keyframes referral-glow {
  0%, 100% { box-shadow: 0 0 10px rgba(122, 168, 255, 0.22); }
  50% { box-shadow: 0 0 20px rgba(215, 140, 255, 0.34); }
}

/* The edge is the whole point, so it stays; only the travelling gradient and
   the pulse stop. */
@media (prefers-reduced-motion: reduce) {
  .referral-form {
    animation: none;
    box-shadow: 0 0 12px rgba(122, 168, 255, 0.22);
  }
}

.referral-prompt {
  display: block;
  margin: 0 0 10px;
  color: var(--ink);
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.4;
}

.referral-entry {
  display: flex;
  justify-content: center;
  gap: 8px;
}

.referral-entry input {
  width: 190px;
  padding: 9px 12px;
  border-radius: 10px;
  border: 1px solid var(--card-edge);
  background: rgba(0, 0, 0, 0.28);
  color: var(--ink);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-align: center;
  text-transform: uppercase;
}

.referral-entry input::placeholder {
  color: rgba(155, 176, 180, 0.45);
  letter-spacing: 0.16em;
}

.referral-entry input:focus-visible {
  outline: 2px solid var(--accent-bright);
  outline-offset: 2px;
}

.referral-apply {
  appearance: none;
  padding: 9px 18px;
  border-radius: 10px;
  border: 1px solid var(--card-edge);
  background: rgba(61, 184, 167, 0.16);
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.referral-apply:hover:not(:disabled) {
  background: rgba(61, 184, 167, 0.28);
}

.referral-apply:disabled {
  opacity: 0.55;
  cursor: default;
}

.referral-error {
  margin: 8px 0 0;
  color: var(--danger);
  font-size: 13px;
  line-height: 1.4;
}

/* The confirmation the buyer sees right up until they pay — it is what makes
   the bonus feel attached to the button they are about to press. */
.referral-applied {
  margin: 0;
  padding: 10px 14px;
  border-radius: var(--radius);
  border: 1px solid rgba(95, 240, 218, 0.32);
  background: rgba(61, 184, 167, 0.12);
  color: var(--accent-bright);
  font-size: 13px;
  line-height: 1.45;
}

/* --------------------------------------------------------------------------
   Repriced figures.
   A number a referral code has changed: the new value leads, the old one is
   struck out beside it. The settled look is the base state, so once the
   animation classes come off nothing has to be undone.
--------------------------------------------------------------------------- */
.reprice {
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px;
}

.reprice-new {
  color: var(--accent-bright);
  white-space: nowrap;
}

.reprice-old {
  position: relative;
  color: var(--muted);
  font-weight: 400;
  white-space: nowrap;
  /* The native line cannot be animated, so it is drawn below instead. */
  text-decoration: none;
  transition: color 300ms ease-out 320ms;
}

.reprice-old::after {
  content: "";
  position: absolute;
  left: -1px;
  right: -1px;
  top: 52%;
  height: 1.5px;
  background: currentColor;
  transform-origin: left center;
}

/* Armed: precisely how the row looked a second ago, before the code landed. */
.reprice-armed .reprice-new {
  opacity: 0;
  transform: translateX(-14px);
}
.reprice-armed .reprice-old {
  color: inherit;
  transition: none;
}
.reprice-armed .reprice-old::after {
  transform: scaleX(0);
}

/* Playing: the strike sweeps left to right, then the new value arrives from
   the left into the space ahead of it. */
.reprice-playing .reprice-old::after {
  animation: reprice-strike 300ms ease-out both;
}
.reprice-playing .reprice-new {
  animation: reprice-arrive 420ms cubic-bezier(0.2, 1.2, 0.4, 1) 320ms both;
}

@keyframes reprice-strike {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

@keyframes reprice-arrive {
  from { opacity: 0; transform: translateX(-14px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .reprice-playing .reprice-old::after,
  .reprice-playing .reprice-new { animation: none; }
  .reprice-old { transition: none; }
}

/* --------------------------------------------------------------------------
   Referral confirmation. Same furniture as the purchase dialog — this is the
   other moment on the page where something good just happened — with a
   draining bar, because a panel that leaves on its own owes the reader that
   much warning.
--------------------------------------------------------------------------- */
.referral-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(4, 10, 12, 0.72);
  backdrop-filter: blur(6px);
  animation: purchase-fade 220ms ease-out;
}

.referral-dialog {
  position: relative;
  width: min(400px, 100%);
  padding: 26px 26px 0;
  border: 2px solid transparent;
  border-radius: 20px;
  background:
    linear-gradient(rgba(13, 42, 46, 0.97), rgba(13, 42, 46, 0.97)) padding-box,
    conic-gradient(from var(--holo-angle), #59f2dc, #7aa8ff, #d78cff, #ffd08a, #59f2dc) border-box;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5);
  text-align: center;
  overflow: hidden;
  animation: purchase-pop 320ms cubic-bezier(0.2, 1.2, 0.4, 1), holo-spin 4.6s linear infinite;
}

.referral-dialog-mark {
  display: block;
  font-size: 26px;
  line-height: 1;
  color: var(--accent-bright);
  margin-bottom: 10px;
}

.referral-dialog h2 {
  margin: 0 0 8px;
  font-size: 22px;
}

.referral-dialog-body {
  margin: 0 0 14px;
  color: var(--ink);
  font-size: 14px;
  line-height: 1.5;
}

.referral-dialog-code {
  display: inline-block;
  margin: 0 0 18px;
  padding: 6px 14px;
  border-radius: 8px;
  border: 1px dashed rgba(255, 255, 255, 0.22);
  background: rgba(0, 0, 0, 0.26);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.16em;
  color: var(--accent-bright);
}

.referral-dialog .cta { width: 100%; }

/* Sits flush in the dialog's bottom edge. */
.referral-dialog-timer {
  height: 3px;
  margin: 22px -26px 0;
  background: rgba(255, 255, 255, 0.08);
}

.referral-dialog-timer > span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-bright));
  transform-origin: left center;
  animation: referral-drain 4s linear forwards;
}

@keyframes referral-drain {
  from { transform: scaleX(1); }
  to { transform: scaleX(0); }
}

@media (prefers-reduced-motion: reduce) {
  .referral-overlay, .referral-dialog { animation: none; }
  .referral-dialog-timer > span { animation-timing-function: linear; }
}

/* pack rail: one row, scrolls sideways */
/*
 * The store: three fixed offers side by side (weekly free minutes, Premium
 * unlock, starter deal), then the minute-pack configurator as a wide panel
 * beneath them. No sideways scrolling — everything is on screen.
 */
.store {
  max-width: 1320px;
  margin: 0 auto 44px;
  padding: 0 6px;
  display: flex;
  flex-direction: column;
  gap: 22px;
}

/* One row of four (fewer once one-time offers are claimed — the count comes
   from pricing.js so the row widens instead of leaving holes). */
.store-row {
  display: grid;
  grid-template-columns: repeat(var(--store-cols, 4), minmax(0, 1fr));
  gap: 18px;
  align-items: stretch;
}

/* Down to two, the plan card keeps the third of the row it had at three and
   the configurator takes the rest, rather than both stretching to half. */
.store-row[data-cols="2"] {
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
}

@media (max-width: 1080px) {
  .store-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 600px) {
  .store-row {
    grid-template-columns: 1fr;
  }
}

.pack {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  padding: 18px 18px 22px;
  border-radius: var(--radius);
  border: 1px solid var(--card-edge);
  background: var(--card);
  text-align: center;
  transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
}

.pack:hover {
  transform: translateY(-4px);
  border-color: rgba(255, 255, 255, 0.16);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.35);
}

/* hover sheen sweep */
.pack::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(115deg, transparent 30%, rgba(159, 248, 255, 0.09) 48%, transparent 62%);
  background-size: 240% 100%;
  background-position: 120% 0;
  pointer-events: none;
  transition: background-position 0.8s ease;
}

.pack:hover::after {
  background-position: -120% 0;
}

/*
 * Graded holo edge — faintest on the 60-minute pack, full glow on the 960.
 * Speed, glow radius and alpha come per card from pricing.js.
 *
 * It only runs under the pointer: six cards shimmering at once was something
 * you had to read *through*, and this page is a comparison first.
 */
.pack.holo {
  border: 2px solid transparent;
  background:
    linear-gradient(var(--card), var(--card)) padding-box,
    linear-gradient(rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.06)) border-box;
}

/* Softened on purpose: at full strength the moving edge pulled the eye away
   from the words, and this page is read before it is admired. */
.pack.holo:hover {
  background:
    linear-gradient(var(--card), var(--card)) padding-box,
    conic-gradient(
      from var(--holo-angle),
      rgba(89, 242, 220, 0.55),
      rgba(122, 168, 255, 0.55),
      rgba(215, 140, 255, 0.55),
      rgba(255, 208, 138, 0.55),
      rgba(89, 242, 220, 0.55)
    ) border-box;
  animation: holo-spin var(--holo-speed, 4s) linear infinite;
  box-shadow:
    0 14px 34px rgba(0, 0, 0, 0.35),
    0 0 var(--holo-glow, 12px) rgba(122, 168, 255, var(--holo-alpha, 0.12));
}

.pack.featured:hover {
  box-shadow:
    0 14px 34px rgba(0, 0, 0, 0.35),
    0 0 20px rgba(95, 240, 218, 0.15);
}

.pack.trial-tier {
  border-style: dashed;
}

/* Premium unlock: a calm gradient edge that only lights up on hover, like the
   rest — clearly special, never competing with the text. */
.pack.premium-unlock {
  border: 2px solid transparent;
  background:
    linear-gradient(var(--card), var(--card)) padding-box,
    linear-gradient(150deg, rgba(215, 140, 255, 0.3), rgba(122, 168, 255, 0.2), rgba(95, 240, 218, 0.25)) border-box;
}

.pack.premium-unlock:hover {
  background:
    linear-gradient(var(--card), var(--card)) padding-box,
    linear-gradient(150deg, rgba(215, 140, 255, 0.75), rgba(122, 168, 255, 0.5), rgba(95, 240, 218, 0.6)) border-box;
}

.pack.premium-unlock .pack-badge {
  background: linear-gradient(90deg, #d78cff, #7aa8ff);
  color: #1c0d2b;
}

.unlock-emblem {
  display: grid;
  place-items: center;
  min-height: 96px;
  margin: 20px 0 0;
  padding: 6px 0 2px;
  font-size: 46px;
  line-height: 1;
  color: #d78cff;
  text-shadow:
    0 0 18px rgba(215, 140, 255, 0.65),
    0 0 40px rgba(122, 168, 255, 0.35);
}

.pack:hover .unlock-emblem {
  animation: cell-bob 4.2s ease-in-out infinite;
}

/* Twinkles pinned over the one-time offer card. */
.sparkles {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.sparkle {
  position: absolute;
  color: #ffd08a;
  text-shadow:
    0 0 8px rgba(255, 208, 138, 0.9),
    0 0 18px rgba(215, 140, 255, 0.5);
  opacity: 0;
  animation: sparkle-twinkle 3s ease-in-out infinite;
}

@keyframes sparkle-twinkle {
  0%, 100% { opacity: 0; transform: scale(0.4) rotate(0deg); }
  50% { opacity: 1; transform: scale(1.15) rotate(180deg); }
}

/* Its own row, so a card with no badge still starts its name at the same
   height as one that has a badge. */
.badge-slot {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  min-height: 22px;
  margin-bottom: 12px;
}

.pack-badge {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  padding: 4px 14px 5px;
  border-radius: 999px;
  color: var(--accent-ink);
  background: linear-gradient(90deg, #5ff0da, #7aa8ff);
}

.pack.one-time .pack-badge {
  background: linear-gradient(90deg, #ffd08a, #d78cff);
  color: #2b1035;
}

.pack.trial-tier .pack-badge {
  background: rgba(240, 195, 106, 0.9);
  color: #2a2108;
}

.pack-name {
  margin: 0;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.25;
}

.pack-minutes {
  margin: 8px 0 0;
  font-size: 11px;
  color: var(--accent-bright);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.4;
}

/* the cell bay: more cells = bigger charge */
.cell-bay {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: 3px;
  min-height: 96px;
  margin: 20px 0 0;
  padding: 6px 0 2px;
}

/* Still, until the pointer arrives — same reasoning as the holo edge. */
.cell {
  width: 34px;
  height: 54px;
  filter: drop-shadow(0 0 5px rgba(63, 214, 255, 0.45));
}

/* The idle pulse is for the decorative bays only. On the configurator's stage
   the cells have their own choreography (drop in, eject), and an infinite
   hover animation here outranked those one-shot classes — which left ejected
   cells stuck on the stage for ever, because animationend never fires for an
   animation that does not end. */
.pack:hover .cell-bay:not(.stage-bay) .cell {
  animation: cell-pulse 2.8s ease-in-out infinite, cell-bob 4.2s ease-in-out infinite;
}

.pack:hover .cell-bay:not(.stage-bay) .cell:nth-child(2n) { animation-delay: 0.35s, 0.6s; }
.pack:hover .cell-bay:not(.stage-bay) .cell:nth-child(3n) { animation-delay: 0.7s, 1.1s; }
.pack:hover .cell-bay:not(.stage-bay) .cell:nth-child(4n) { animation-delay: 1.05s, 1.7s; }
.pack:hover .cell-bay:not(.stage-bay) .cell:nth-child(5n) { animation-delay: 1.4s, 2.2s; }

.cell-bay.big .cell { width: 30px; height: 48px; }

.pack.trial-tier .cell {
  filter: drop-shadow(0 0 4px rgba(240, 195, 106, 0.4)) saturate(0.55) brightness(0.9);
}

@keyframes cell-pulse {
  0%, 100% { filter: drop-shadow(0 0 4px rgba(63, 214, 255, 0.35)); }
  50% { filter: drop-shadow(0 0 10px rgba(63, 214, 255, 0.75)); }
}

@keyframes cell-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-3px); }
}

.pack-blurb {
  margin: 18px 0 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--muted);
}

/* A hairline on its own row, so the sections divide at the same height in
   every column. */
.pack-rule {
  height: 1px;
  margin: 26px 0;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.14) 15%,
    rgba(255, 255, 255, 0.14) 85%,
    transparent
  );
}

/* the numbers, read as a spec sheet */
.pack-specs {
  display: grid;
  gap: 9px;
  font-size: 13px;
  text-align: start;
}

.spec {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

/* The label must never wrap mid-word — it did when the "Best value" chip shared
   this row and squeezed the column. Long translations wrap the value instead. */
.spec .k {
  flex: 0 1 auto;
  min-width: 0;
  color: var(--muted);
  white-space: nowrap;
}

.spec .v {
  flex: 1 1 auto;
  min-width: 0;
  text-align: end;
  font-weight: 700;
  color: #d7fff7;
  overflow-wrap: anywhere;
}

/* The tier a purchase grants, graded by how much it is worth: Premium gets the
   full holo sheen, Paid a slower two-tone one. Text-only — a background here
   would out-shout the price. */
.spec .v.tier-premium,
.spec .v.tier-paid {
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: holo-sheen 6s linear infinite;
}

.spec .v.tier-premium {
  background-image: linear-gradient(100deg, #5ff0da 10%, #7aa8ff 38%, #d78cff 62%, #5ff0da 90%);
}

.spec .v.tier-paid {
  background-image: linear-gradient(100deg, #bfe3ff 15%, #8fb6dd 50%, #bfe3ff 85%);
  animation-duration: 9s;
}

/* Chips get their own row so they can never reflow the price. */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: 6px;
  min-height: 20px;
  margin-top: 10px;
}

.pack-price {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 10px;
  margin-top: 22px;
}

.price-main {
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

/* What the minutes would cost at the 60-minute pack's rate. */
.price-compare {
  font-size: 15px;
  font-weight: 600;
  color: var(--muted);
  opacity: 0.65;
  text-decoration-thickness: 2px;
}

/* "% cheaper than the 60-minute pack!" — highlighted savings callout */
.cheaper-chip {
  display: inline-block;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 999px;
  color: #2a2108;
  background: linear-gradient(90deg, #ffd08a, #f0c36a);
  box-shadow: 0 0 10px rgba(240, 195, 106, 0.35);
}

.best-chip {
  display: inline-block;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 999px;
  color: var(--accent-ink);
  background: linear-gradient(90deg, #5ff0da, #7aa8ff);
}

/* ---- what you get: every feature named and explained, in the same order in
   every column, so the rows read straight across ---- */
.feat-title {
  margin: 0 0 4px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: start;
}

.feat {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 14px 0 0;
  text-align: start;
}

/* Muted fills rather than the full accent: six solid ticks per card, five
   cards across, read as a wall of teal before any of the words landed. */
.feat-mark {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  margin-top: 1px;
  border-radius: 50%;
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
  color: var(--accent-bright);
  border: 1px solid rgba(95, 240, 218, 0.4);
  background: rgba(95, 240, 218, 0.13);
}

.feat.is-trial .feat-mark {
  color: var(--gold);
  border-color: rgba(240, 195, 106, 0.4);
  background: rgba(240, 195, 106, 0.13);
}

.feat.is-no .feat-mark {
  color: var(--muted);
  border-color: rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
}

.feat-text {
  min-width: 0;
}

.feat-name {
  margin: 0;
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.35;
}

.feat-desc {
  margin: 3px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}

/* Locked features stay legible — greyed, not hidden. Someone has to be able to
   see what they'd be buying. */
.feat.is-no .feat-name,
.feat.is-no .feat-desc {
  color: rgba(155, 176, 180, 0.62);
}

.pack-note {
  margin: 18px 0 0;
  padding: 9px 11px;
  border-radius: 9px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  background: rgba(8, 20, 23, 0.5);
  font-size: 12px;
  line-height: 1.45;
  color: var(--muted);
  text-align: start;
}

/* An empty footnote still holds its row so the cards end level. */
.pack-note:empty {
  padding: 0;
  border: none;
  background: none;
}

/* Visually hidden, still read out — carries the tick/dash meaning. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.buy-btn {
  position: relative;
  overflow: hidden;
  appearance: none;
  border: none;
  border-radius: 999px;
  margin-top: 18px;
  padding: 12px 16px;
  font: inherit;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.01em;
  cursor: pointer;
  color: var(--accent-ink);
  background: linear-gradient(180deg, #4ecbb8 0%, #2fa894 100%);
  transition: transform 0.2s ease, box-shadow 0.25s ease, filter 0.2s ease;
}

/* light streak that sweeps across on hover */
.buy-btn::before {
  content: "";
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: -55%;
  width: 45%;
  transform: skewX(-22deg) translateX(0);
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.5),
    rgba(159, 248, 255, 0.35),
    transparent
  );
  opacity: 0;
  pointer-events: none;
}

.buy-btn:hover:not(:disabled) {
  transform: translateY(-2px) scale(1.02);
  filter: brightness(1.06);
  box-shadow:
    0 6px 18px rgba(61, 184, 167, 0.4),
    0 0 22px rgba(95, 240, 218, 0.3);
}

.buy-btn:hover:not(:disabled)::before {
  opacity: 1;
  animation: btn-shine 0.7s ease forwards;
}

.buy-btn:active:not(:disabled) {
  transform: translateY(0) scale(0.99);
}

@keyframes btn-shine {
  to {
    transform: skewX(-22deg) translateX(390%);
  }
}

.buy-btn:disabled { opacity: 0.55; cursor: default; }

/* The label and the busy text are stacked, not swapped: replacing the button's
   text would throw the PayPal mark away on the first click. */
.buy-label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.buy-busy {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0 12px;
}

.buy-btn.busy .buy-label { visibility: hidden; }
.buy-btn.busy .buy-busy { display: flex; }

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

   PayPal's own gold button, to its brand guidelines: #FFC439, a full pill, and
   the colour logo alone on the face. It deliberately does not wear the rest of
   the page's holo styling -- the whole point is that it looks like PayPal's
   button and not like ours, because that is what tells the buyer where their
   money is going before they click. Sizing follows PayPal's spec too: 45px
   tall in the responsive range, and the mark held to a proportion of the
   height so a taller button never stretches the logo.
   --------------------------------------------------------------------------- */
.buy-btn.paypal {
  min-height: 45px;
  padding: 10px 20px;
  background: #ffc439;
  color: #142c8e;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.buy-btn.paypal:hover:not(:disabled) {
  background: #f2ba36;
  transform: translateY(-1px);
  filter: none;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
}

/* The house button's white shine sweep would read as a gimmick on PayPal's
   button, which is the one control on this page that should look borrowed. */
.buy-btn.paypal:hover:not(:disabled)::before { animation: none; opacity: 0; }

.buy-btn.paypal:active:not(:disabled) {
  transform: translateY(0) scale(0.995);
  background: #eab134;
}

.buy-btn.paypal:focus-visible {
  outline: 2px solid #142c8e;
  outline-offset: 2px;
}

.paypal-mark {
  display: block;
  height: 22px;
  width: auto;
}

.buy-btn.paypal .buy-busy { color: #142c8e; }

/* Where the payment actually happens. Stated under the button because the
   reassurance only works if it is read before the click, not after. */
.pay-secure {
  margin: 8px 0 0;
  font-size: 11.5px;
  line-height: 1.45;
  text-align: center;
  color: var(--muted);
}

/* Inline rather than a flex sibling: the note wraps to two lines in most
   languages, and a flex lock would sit centred against the whole block
   instead of riding the first line. */
.pay-lock {
  margin-right: 5px;
  font-size: 10.5px;
}

@media (prefers-reduced-motion: reduce) {
  .buy-btn.paypal:hover:not(:disabled) { transform: none; }
}

.pack.one-time .buy-btn:not(.paypal):hover:not(:disabled) {
  box-shadow:
    0 6px 18px rgba(232, 160, 78, 0.4),
    0 0 22px rgba(255, 208, 138, 0.35);
}

.pack.one-time .buy-btn:not(.paypal) {
  background: linear-gradient(180deg, #ffd08a 0%, #e8a04e 100%);
  color: #2b1a03;
}

.current-plan {
  text-align: center;
  border: 1px dashed rgba(240, 195, 106, 0.5);
  border-radius: 999px;
  margin-top: 18px;
  padding: 12px 14px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold);
}

.cta {
  appearance: none;
  border: none;
  border-radius: 11px;
  padding: 11px 20px;
  font: inherit;
  font-weight: 800;
  font-size: 13px;
  cursor: pointer;
  color: var(--accent-ink);
  background: linear-gradient(180deg, #4ecbb8 0%, #2fa894 100%);
}

.cta:hover { filter: brightness(1.08); }
.cta:disabled { opacity: 0.55; cursor: default; }

.foot {
  max-width: 640px;
  margin: 0 auto;
  text-align: center;
}

/* ---------------------------------------------------------------------------
   Purchase outcome
   Shown when the buyer comes back from checkout — a celebration on success, a
   plain "that didn't finish" on an abandoned one. The count-up, the Premium
   reveal and the confetti are driven from JS; everything here is the look.
   --------------------------------------------------------------------------- */

.purchase-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(4, 10, 12, 0.72);
  backdrop-filter: blur(6px);
  animation: purchase-fade 220ms ease-out;
}

.purchase-overlay.hidden {
  display: none;
}

/* Sits behind the dialog and spans the whole overlay, so the confetti falls
   past the card rather than being clipped by it. */
.confetti {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.purchase-dialog {
  position: relative;
  width: min(460px, 100%);
  padding: 28px 28px 24px;
  border: 1px solid var(--card-edge);
  border-radius: 20px;
  background: var(--card);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5);
  text-align: center;
  animation: purchase-pop 320ms cubic-bezier(0.2, 1.2, 0.4, 1);
}

.purchase-dialog h2 {
  margin: 0 0 10px;
  font-size: 24px;
  min-height: 1.4em;
}

/* ---- Split-flap heading ----
   One cell per character. A change scrambles each cell through a few glyphs
   drawn from the two words involved — so the shuffle stays in the right script
   — and every step flips the cell on its horizontal axis, the way a departure
   board does. The line across the middle is what sells it. */

.flap-board {
  display: flex;
  justify-content: center;
}

.flap-cells {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px;
}

.flap-cell {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 0.62em;
  padding: 2px 1px;
  border-radius: 3px;
  background: linear-gradient(#12262b 0 50%, #0c1c20 50% 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
  transform-origin: center;
  backface-visibility: hidden;
}

/* The hinge. */
.flap-cell::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: rgba(0, 0, 0, 0.55);
}

/* A space keeps the rhythm of the board without looking like a blank card. */
.flap-cell.is-gap {
  background: none;
  box-shadow: none;
}

.flap-cell.is-gap::after {
  display: none;
}

.flap-cell.is-turning {
  animation: flap-turn 90ms ease-in;
}

@keyframes flap-turn {
  0% { transform: rotateX(0deg); }
  49% { transform: rotateX(-90deg); }
  50% { transform: rotateX(90deg); }
  100% { transform: rotateX(0deg); }
}

/* The dialog carries the same moving edge the Premium pack cards do, so the
   moment of arrival looks like the thing that was bought. */
.purchase-dialog.is-holo {
  border: 2px solid transparent;
  background:
    linear-gradient(var(--card), var(--card)) padding-box,
    conic-gradient(
      from var(--holo-angle),
      rgba(89, 242, 220, 0.75),
      rgba(122, 168, 255, 0.75),
      rgba(215, 140, 255, 0.75),
      rgba(255, 208, 138, 0.75),
      rgba(89, 242, 220, 0.75)
    ) border-box;
  animation:
    purchase-pop 320ms cubic-bezier(0.2, 1.2, 0.4, 1),
    holo-spin 4s linear infinite;
  box-shadow:
    0 30px 80px rgba(0, 0, 0, 0.5),
    0 0 28px rgba(122, 168, 255, 0.22);
}

/* Clipping a gradient to the text does not survive here — each flap card paints
   its own background over it and the glyphs vanish. Cycling the inherited text
   colour instead keeps the cards and shimmers the letters, and it leaves the
   cell's own transform animation free for the flip. */
.purchase-dialog.is-holo .flap-cells {
  animation: flap-holo 5s linear infinite;
}

@keyframes flap-holo {
  0%, 100% { color: #5ff0da; }
  33% { color: #7aa8ff; }
  66% { color: #d78cff; }
}

.purchase-body {
  margin: 0 0 20px;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.55;
}

.purchase-stat {
  display: grid;
  gap: 6px;
  margin-bottom: 18px;
}

.purchase-stat.hidden {
  display: none;
}

.purchase-label {
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

.purchase-plan,
.purchase-count {
  position: relative;
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -0.01em;
}

/* While the number is climbing it gets a small tremor — the value is moving,
   and standing still would read as a static figure. */
.purchase-count.is-counting {
  animation: purchase-tremor 110ms linear infinite;
}

/* Landed: the figure turns holographic and throws sparks. */
.purchase-plan.is-landed,
.purchase-count.is-landed {
  background: linear-gradient(100deg, #5ff0da 10%, #7aa8ff 38%, #d78cff 62%, #5ff0da 90%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: holo-sheen 4s linear infinite;
}

.sparkle {
  position: absolute;
  width: 10px;
  height: 10px;
  pointer-events: none;
  color: #ffe9a8;
  font-size: 10px;
  line-height: 1;
  animation: sparkle-pop 900ms ease-out forwards;
}

@keyframes purchase-fade {
  from { opacity: 0; }
}

@keyframes purchase-pop {
  from { opacity: 0; transform: translateY(14px) scale(0.96); }
}

@keyframes purchase-tremor {
  0% { transform: translate(0, 0); }
  25% { transform: translate(-1.5px, 1px); }
  50% { transform: translate(1.5px, -1px); }
  75% { transform: translate(-1px, -1.5px); }
  100% { transform: translate(0, 0); }
}

@keyframes sparkle-pop {
  0% { opacity: 0; transform: scale(0.4) rotate(0deg); }
  30% { opacity: 1; transform: scale(1.15) rotate(45deg); }
  100% { opacity: 0; transform: scale(0.5) rotate(140deg); }
}

@media (prefers-reduced-motion: reduce) {
  .purchase-overlay,
  .purchase-dialog {
    animation: none;
  }

  .purchase-count.is-counting,
  .purchase-plan.is-landed,
  .purchase-count.is-landed,
  .purchase-dialog.is-holo,
  .flap-cell.is-turning {
    animation: none;
  }

  /* Still needs a colour, just not a moving one. */
  .purchase-dialog.is-holo .flap-cells {
    animation: none;
    color: #7fe6d6;
  }

  .sparkle {
    display: none;
  }
}

.spec .spec-was,
.pack-minutes .spec-was {
  color: var(--muted, #9aafb3);
  opacity: 0.75;
  margin-inline-end: 4px;
}

.spec .spec-bonus,
.pack-minutes .spec-bonus {
  font-weight: 800;
  background: linear-gradient(92deg, #59f2dc, #7aa8ff);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ---- The plan card, in its Premium state ----
   Unlike the graded holo on the pack cards this one runs unprompted: it is
   the badge of something already owned, not an invitation to hover. */
.pack.plan-premium {
  border: 2px solid transparent;
  background:
    linear-gradient(var(--card), var(--card)) padding-box,
    conic-gradient(
      from var(--holo-angle),
      rgba(89, 242, 220, 0.7),
      rgba(122, 168, 255, 0.7),
      rgba(215, 140, 255, 0.7),
      rgba(255, 208, 138, 0.7),
      rgba(89, 242, 220, 0.7)
    ) border-box;
  animation: holo-spin 6s linear infinite;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.35), 0 0 18px rgba(122, 168, 255, 0.18);
}

.pack.plan-premium .pack-name,
.pack.plan-premium .price-main {
  background: linear-gradient(96deg, #9ff8ff, #c9b6ff 40%, #ffd08a 70%, #9ff8ff);
  background-size: 260% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: holo-sheen 7s linear infinite;
}

.pack.plan-premium .pack-badge {
  color: #eafffb;
  border: 1px solid rgba(159, 248, 255, 0.5);
  background: rgba(122, 168, 255, 0.16);
}

.pack.plan-premium .cell {
  filter: drop-shadow(0 0 6px rgba(159, 248, 255, 0.6));
}

@media (prefers-reduced-motion: reduce) {
  .pack.plan-premium,
  .pack.plan-premium .pack-name,
  .pack.plan-premium .price-main {
    animation: none;
  }
}

.feat-list {
  display: flex;
  flex-direction: column;
  text-align: start;
}

/* ---- The minute-pack configurator ---- */
.standard-panel {
  text-align: center;
  /* Queried by .standard-body below: this card is a third of the row while the
     starter is on sale and two thirds once it is claimed, and the picker/stage
     split should follow the card, not the viewport. */
  container-type: inline-size;
}

.standard-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  margin: 8px 0 10px;
}

@container (min-width: 430px) {
  .standard-body {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 18px;
  }

  /* Match the picker's height so the pair reads as one panel, with the cells
     landing on a shelf in the middle of it rather than at the top. */
  .standard-body .standard-stage {
    justify-content: center;
  }
}

.standard-picker {
  display: flex;
  flex-direction: column;
  gap: 8px;
  text-align: start;
}

.standard-foot {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  flex: 1;
  gap: 10px;
}

/* The last thing in every card is its call to action, pushed to the bottom so
   the buttons sit on one line across the row. */
.pack > .buy-block,
.pack > .current-plan,
.standard-foot > .buy-block {
  margin-top: auto;
}

/* A column so the button still stretches to the card width now that it is
   wrapped rather than a flex child of the card itself. */
.buy-block {
  display: flex;
  flex-direction: column;
}

.pick-label {
  margin: 0;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/*
 * The stage. Cells fall in from above and stack on the shelf — the bay clips
 * nothing vertically so the drop starts out of frame.
 */
.standard-stage {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  min-height: 128px;
  padding: 10px 10px 6px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  background:
    radial-gradient(80% 60% at 50% 100%, rgba(63, 214, 255, 0.09), transparent 70%),
    rgba(8, 20, 24, 0.55);
  overflow: hidden;
}

.stage-bay {
  min-height: 76px;
  margin: 0;
  gap: 2px;
  align-items: flex-end;
}

/* Five cells have to fit a quarter-width card. */
.stage-bay .cell {
  width: 26px;
  height: 42px;
}

.stage-bay.big .cell {
  width: 22px;
  height: 36px;
}

.stage-count {
  margin: 6px 0 2px;
  font-size: 13px;
  font-weight: 700;
  color: var(--accent-bright);
}

/* The Hearthstone drop: fall from above the frame, land with a squash, settle. */
@keyframes cell-drop {
  0% {
    transform: translateY(-140px) rotate(-7deg);
    opacity: 0;
  }
  55% {
    transform: translateY(0) rotate(0deg) scaleY(1);
    opacity: 1;
  }
  70% {
    transform: translateY(0) scaleY(0.82) scaleX(1.12);
  }
  85% {
    transform: translateY(-7px) scaleY(1.04);
  }
  100% {
    transform: translateY(0) scale(1);
    opacity: 1;
  }
}

.cell.drop-in {
  animation: cell-drop 0.46s cubic-bezier(0.3, 0.7, 0.4, 1) both;
  transform-origin: bottom center;
}

/* A deselected cell tips over the edge and falls out of frame. */
@keyframes cell-eject {
  0% {
    transform: translateY(0) rotate(0);
    opacity: 1;
  }
  100% {
    transform: translateY(130px) rotate(12deg);
    opacity: 0;
  }
}

.cell.leaving {
  animation: cell-eject 0.32s ease-in both;
}

/* ---- Pack radios ---- */
.pack-radios {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.pack-radio {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 1px 10px;
  padding: 9px 12px;
  border-radius: 11px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(10, 24, 28, 0.6);
  cursor: pointer;
  transition: border-color 0.18s ease, background 0.18s ease, transform 0.18s ease;
}

.pack-radio:hover {
  border-color: rgba(95, 240, 218, 0.4);
  background: rgba(12, 30, 34, 0.85);
}

.pack-radio:has(:checked) {
  border-color: var(--accent-bright);
  background: rgba(95, 240, 218, 0.1);
  box-shadow: inset 0 0 0 1px rgba(95, 240, 218, 0.3);
}

/* Keyboard focus lands on the visually-hidden input, so the ring is drawn on
   the label that stands in for it. */
.pack-radio:has(:focus-visible) {
  outline: 2px solid var(--accent-bright);
  outline-offset: 2px;
}

.radio-dot {
  grid-row: 1 / span 2;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.28);
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}

.pack-radio:has(:checked) .radio-dot {
  border-color: var(--accent-bright);
  box-shadow: inset 0 0 0 3px var(--accent-bright);
}

.radio-main {
  grid-column: 2;
  font-weight: 700;
  font-size: 14.5px;
  white-space: nowrap;
}

.radio-price {
  grid-column: 3;
  font-weight: 700;
  font-size: 14.5px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.radio-meta {
  grid-column: 2 / span 2;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 8px;
}

.radio-sub {
  font-size: 11.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.radio-tag {
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--accent-ink);
  background: linear-gradient(180deg, #4ecbb8, #2fa894);
}

.radio-tag.best {
  background: linear-gradient(180deg, #ffe29a, #f0c36a);
}

/* ---- Animated numbers ---- */
.standard-price {
  justify-content: center;
  margin: 2px 0 0;
}

/* ---- "Welcome to the club." ---- */
.plan-welcome {
  margin: 8px 0 0;
  font-size: 12.5px;
  font-style: italic;
  letter-spacing: 0.01em;
  color: #9ff8ff;
  opacity: 0.85;
}

/* ---- Shared "What you get" strip under the row ---- */
.feature-panel {
  padding: 20px 24px 18px;
  border-radius: var(--radius);
  border: 1px solid var(--card-edge);
  background: var(--card);
}

.feature-panel .feat-title {
  margin-top: 0;
}

.feat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 2px 28px;
  text-align: start;
}

.feature-panel .pack-note {
  text-align: start;
}

.standard-permin {
  margin: 0;
  font-size: 12.5px;
  color: var(--muted);
}

@keyframes price-pop {
  0% {
    transform: translateY(-16px) scale(0.9);
    opacity: 0;
  }
  60% {
    transform: translateY(2px) scale(1.05);
    opacity: 1;
  }
  100% {
    transform: translateY(0) scale(1);
  }
}

.price-main.pop-in,
.stage-count.pop-in {
  animation: price-pop 0.4s cubic-bezier(0.3, 0.7, 0.4, 1) both;
  display: inline-block;
}

/* The strikethrough draws itself across the reference price. */
.price-compare {
  position: relative;
  text-decoration: none;
}

.price-compare::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 52%;
  height: 2px;
  border-radius: 2px;
  background: var(--danger);
  transform: none;
}

.price-compare.strike-in::after {
  animation: strike-draw 0.5s ease-out 0.25s both;
  transform-origin: 0 50%;
}

[dir="rtl"] .price-compare.strike-in::after {
  transform-origin: 100% 50%;
}

@keyframes strike-draw {
  0% {
    transform: scaleX(0);
  }
  100% {
    transform: scaleX(1);
  }
}

/* The savings chip drops in like a card being played. */
@keyframes chip-drop {
  0% {
    transform: translateY(-26px) rotate(-4deg);
    opacity: 0;
  }
  60% {
    transform: translateY(3px) rotate(1deg);
    opacity: 1;
  }
  100% {
    transform: translateY(0) rotate(0);
  }
}

.cheaper-chip.chip-drop {
  animation: chip-drop 0.42s cubic-bezier(0.3, 0.7, 0.4, 1) 0.35s both;
}

@media (prefers-reduced-motion: reduce) {
  .cell.drop-in,
  .cell.leaving,
  .price-main.pop-in,
  .stage-count.pop-in,
  .price-compare.strike-in::after,
  .cheaper-chip.chip-drop,
  .pack-radio,
  .radio-dot {
    animation: none;
    transition: none;
  }
}
