/* The hidden attribute has to beat every display rule below it, or an element
   we mark hidden in JS still shows. Cheap to state once here. */
[hidden] { display: none !important; }

:root {
  /* Telegram injects these on the WebView; the fallbacks keep the page usable
     in a plain browser during development. */
  --bg:      var(--tg-theme-bg-color, #17212b);
  --fg:      var(--tg-theme-text-color, #f5f5f5);
  --muted:   var(--muted);
  --card:    var(--tg-theme-secondary-bg-color, #232e3c);
  --accent:  var(--tg-theme-button-color, #2ea6ff);
  --accent-fg: var(--tg-theme-button-text-color, #ffffff);
  --link:    var(--tg-theme-link-color, #6ab7ff);
  --danger:  #e5484d;
  --ok:      #30a46c;
  --hair:    color-mix(in srgb, var(--muted) 22%, transparent);
}

* { box-sizing: border-box; }

html, body { height: 100%; }

/* The app owns the whole viewport and nothing scrolls it. Only the recents
   list scrolls, inside itself. Set by JS from Telegram's own viewport height,
   because vh inside a WebView includes chrome the page cannot draw under. */
:root { --app-h: 100dvh; }

body { overflow: hidden; overscroll-behavior: none; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 16px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

.screen {
  max-width: 460px;
  height: var(--app-h);
  margin: 0 auto;
  padding: 12px 18px calc(10px + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  /* Children may shrink below their content size rather than overflow. */
  min-height: 0;
  overflow: hidden;
}

/* Onboarding is genuinely longer than a screen, so it is the one place that
   may scroll - within itself, not by moving the page. */
#onboarding { overflow-y: auto; }
.screen--center { align-items: center; justify-content: center; gap: 16px; }

.muted { color: var(--muted); }

/* Boot ------------------------------------------------------------------- */
.spinner {
  width: 28px; height: 28px;
  border: 2px solid var(--hair);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 2.4s; }
}

/* Onboarding ------------------------------------------------------------- */
.ob__head { margin: 12px 0 20px; }
.ob__head h1 { font-size: 26px; font-weight: 600; margin: 0 0 6px; }
.ob__head p  { margin: 0; font-size: 15px; }

.card {
  background: var(--card);
  border-radius: 14px;
  padding: 16px;
  margin-bottom: 14px;
}
.card__title { font-size: 16px; font-weight: 600; margin: 0 0 10px; }
.card__body  { font-size: 14px; margin: 0 0 12px; }

.terms {
  max-height: 168px;
  overflow-y: auto;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--muted);
  padding-right: 6px;
  margin-bottom: 14px;
  overscroll-behavior: contain;
}
.terms p { margin: 0 0 10px; }

.check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 14.5px;
  cursor: pointer;
  padding-top: 4px;
}
.check input { width: 20px; height: 20px; margin: 0; accent-color: var(--accent); flex: none; }
.check em { color: var(--muted); font-style: normal; }

/* Buttons ---------------------------------------------------------------- */
.btn {
  width: 100%;
  padding: 15px;
  font: inherit;
  font-size: 17px;
  font-weight: 600;
  color: var(--accent-fg);
  background: var(--accent);
  border: 0;
  border-radius: 12px;
  cursor: pointer;
  transition: opacity .15s, transform .06s;
}
.btn:active:not(:disabled) { transform: scale(.985); }
.btn:disabled { opacity: .4; cursor: default; }
.btn--primary { margin-top: auto; }

.btn--call { margin-top: clamp(6px, calc(var(--app-h) * .014), 14px); }

.btn--hangup {
  width: 68px; height: 68px;
  margin: 0 auto;
  border-radius: 50%;
  background: var(--danger);
  display: grid;
  place-items: center;
  padding: 0;
}
.btn__glyph { font-size: 28px; transform: rotate(135deg); line-height: 1; }

/* Phone: balance bar ----------------------------------------------------- */
.bar {
  display: flex;
  align-items: baseline;
  /* The balance, its trial chip and the top-up button travel together on the
     right; only the label is pinned left. space-between would spread the
     three of them across the bar and break the pairing. */
  justify-content: flex-start;
  gap: 8px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--hair);
  margin-bottom: 10px;
}
/* Only the expanded panel ever sits between the bar and the keypad, and it is
   its own card - so the bar keeps one spacing rule rather than two. */
.bar:has(+ .claim__panel:not([hidden])) { margin-bottom: 8px; }
.barchip, .bar__topup { align-self: center; }
.bar__label { font-size: 12px; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }
.bar__value {
  margin-left: auto;
  font-size: 19px; font-weight: 600; font-variant-numeric: tabular-nums;
}

.tab { display: flex; flex-direction: column; flex: 1; min-height: 0; }

/* Country picker --------------------------------------------------------- */
.picker {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 11px 13px;
  margin-top: 4px;
  font: inherit;
  color: var(--fg);
  background: var(--card);
  border: 1px solid transparent;
  border-radius: 11px;
  cursor: pointer;
  text-align: left;
}
.picker:active { border-color: var(--accent); }
.picker--sm { width: auto; flex: none; padding: 12px 11px; margin: 0; }

.picker__flag { font-size: 19px; line-height: 1; flex: none; }
.picker__name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.picker__code { color: var(--muted); font-variant-numeric: tabular-nums; flex: none; }
.picker--sm .picker__code { color: var(--fg); }
.picker__caret { color: var(--muted); font-size: 11px; flex: none; }

/* The chosen code is fixed text beside the input, not part of it, so the
   keypad cannot delete it and the user cannot edit it. */
/* Pinned left rather than sitting in the flow, so the number can be centred
   on the display itself. In the flow it pushed the "centred" number to the
   right by its own width, which is exactly the sort of near-miss that reads
   as sloppy without being obviously wrong. */
.display__cc {
  position: absolute;
  left: 4px;
  font-size: clamp(18px, calc(var(--app-h) * .03), 24px);
  font-weight: 500;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  flex: none;
}

/* The per-minute price for the number as typed. It sits between the number and
   the keypad, where the eye already is, and reserves no space when empty so the
   keypad does not jump as quotes arrive. */
.rateline {
  margin: 2px 0 0;
  text-align: center;
  font-size: 13px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-height: 17px;
  /* Always present, never wrapping: the line holds its height whether or not
     it has text, so the keypad below it cannot shift. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rateline--warn { color: var(--danger, #e05545); }
/* A number that cannot be dialled at all, as opposed to one we cannot price. */
.rateline--bad { color: var(--danger); font-weight: 500; }

/* Bottom sheet ----------------------------------------------------------- */
.sheet {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(0, 0, 0, .45);
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.sheet__panel {
  width: 100%;
  max-width: 460px;
  max-height: 78vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border-radius: 16px 16px 0 0;
  padding-bottom: env(safe-area-inset-bottom);
  animation: rise .18s ease-out;
}
@keyframes rise { from { transform: translateY(14px); opacity: .6; } }
@media (prefers-reduced-motion: reduce) { .sheet__panel { animation: none; } }

.sheet__head { display: flex; gap: 8px; padding: 14px 14px 10px; }
.sheet__search {
  flex: 1;
  padding: 11px 13px;
  font: inherit;
  font-size: 16px;
  color: var(--fg);
  background: var(--card);
  border: 1px solid transparent;
  border-radius: 10px;
  outline: none;
}
.sheet__search:focus { border-color: var(--accent); }
.sheet__close {
  border: 0;
  background: var(--card);
  color: var(--muted);
  font-size: 16px;
  width: 42px;
  border-radius: 10px;
  cursor: pointer;
}

.sheet__list {
  list-style: none;
  margin: 0;
  padding: 0 8px 12px;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.sheet__item {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 10px;
  border-radius: 10px;
  cursor: pointer;
}
.sheet__item:active { background: var(--card); }
.sheet__item.is-on { background: var(--card); }
.sheet__flag { font-size: 20px; line-height: 1; width: 24px; flex: none; }
.sheet__name { flex: 1; }
.sheet__limited {
  font-size: 10.5px;
  color: var(--muted);
  border: 1px solid var(--hair);
  border-radius: 999px;
  padding: 1px 7px;
  margin-left: 6px;
}
.sheet__code { color: var(--muted); font-variant-numeric: tabular-nums; }
.sheet__empty { text-align: center; color: var(--muted); padding: 28px 0; }

/* Number display --------------------------------------------------------- */
.display {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: clamp(42px, calc(var(--app-h) * .075), 62px);
  margin: clamp(2px, calc(var(--app-h) * .007), 6px) 0 2px;
}
/* The typed number and the ghost pattern behind it occupy the same box and
   must be laid out identically, or the two drift apart as digits are added. */
.display__field {
  position: relative;
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
}
.display__ghost,
.cid__ghost {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  pointer-events: none;
  white-space: pre;
  overflow: hidden;
}
/* The destination draws its own number, so it is centred as one piece. */
.display__ghost { justify-content: center; }

/* What has been entered: full strength, this is the number. */
.num__typed { color: var(--fg); }
/* What is still to come. Well below the hint colour - it is the shape of a
   number, not text to be read - and mixed toward the background so it stays
   right in both themes. */
.num__rest {
  color: color-mix(in srgb, var(--muted) 45%, var(--bg));
  font-weight: 400;
  letter-spacing: .08em;
}
/* Occupies the width of what has been typed without being seen, so the
   remainder begins exactly at the caret. Used by the caller-ID field, which
   draws its own text and needs the hint aligned behind it. */
.ghost__typed { color: transparent; }
.cid__ghost { color: color-mix(in srgb, var(--muted) 45%, var(--bg)); }
.display__ghost {
  font: inherit;
  font-size: clamp(22px, calc(var(--app-h) * .037), 31px);
  font-weight: 500;
  letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
  padding: 0 36px 0 6px;
}

/* The card surface belongs to the wrapper, not the input: an opaque input
   would paint over the ghost sitting behind it. */
.cid__field {
  position: relative;
  flex: 1;
  min-width: 0;
  display: flex;
  background: var(--card);
  border: 1px solid transparent;
  border-radius: 11px;
}
.cid__field:focus-within { border-color: var(--accent); }
.cid__ghost {
  font: inherit;
  font-size: 16px;
  padding: 12px 14px;
  font-variant-numeric: tabular-nums;
}

.display__num {
  width: auto;
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: clamp(22px, calc(var(--app-h) * .037), 31px);
  font-weight: 500;
  letter-spacing: .02em;
  outline: none;
  font-variant-numeric: tabular-nums;
  text-align: center;
  padding: 0 40px;
  /* The keypad is the input method; a system keyboard would cover it. */
  caret-color: transparent;
  /* The number is drawn by the layer behind, in two colours. This element
     still holds the value - every other part of the app reads it - but
     showing its text as well would double every digit. */
  color: transparent;
}
.display__num::placeholder { color: var(--muted); font-weight: 400; }
/* Too many digits for the country now selected. Applied to the layer that
   actually draws the number, since the input's own text is invisible. */
.display__ghost--bad .num__typed { color: var(--danger); }
.display__back {
  position: absolute;
  right: 0;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 22px;
  padding: 10px;
  cursor: pointer;
  line-height: 1;
}

/* Keypad ----------------------------------------------------------------- */
.keypad {
  display: grid;
  min-height: 0;
  grid-template-columns: repeat(3, 1fr);
  /* Both gap and key size are driven by the real viewport height, so a short
     screen gets a smaller keypad rather than one that runs off the bottom. */
  gap: clamp(5px, calc(var(--app-h) * .014), 10px);
  margin: clamp(2px, calc(var(--app-h) * .006), 6px) 0 clamp(6px, calc(var(--app-h) * .016), 14px);
  justify-items: center;
}
.key {
  width: 100%;
  aspect-ratio: 1 / 1;
  /* The one rule that keeps everything on screen: keys are capped against
     viewport height, so the column below them always has room. */
  max-height: clamp(38px, calc(var(--app-h) * .082), 74px);
  max-width: clamp(38px, calc(var(--app-h) * .082), 74px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  border: 0;
  border-radius: 50%;
  background: var(--card);
  color: var(--fg);
  font: inherit;
  cursor: pointer;
  user-select: none;
  transition: background .12s, transform .06s;
}
.key:active { background: var(--accent); color: var(--accent-fg); transform: scale(.94); }
.key b { font-size: clamp(17px, calc(var(--app-h) * .031), 26px); font-weight: 500; line-height: 1; }
.key i {
  font-size: 9.5px;
  font-style: normal;
  letter-spacing: .1em;
  color: var(--muted);
  min-height: 11px;
}
.key:active i { color: var(--accent-fg); opacity: .8; }

/* Caller ID -------------------------------------------------------------- */
.cid { display: block; margin-top: auto; flex: none; }
.cid__label {
  display: block;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--muted);
  margin-bottom: 6px;
}
.cid__row { display: flex; gap: 8px; }
.cid input {
  flex: 1;
  min-width: 0;
  padding: 12px 14px;
  font: inherit;
  font-size: 16px;
  color: var(--fg);
  background: transparent;
  border: 0;
  border-radius: 11px;
  outline: none;
  position: relative;
  font-variant-numeric: tabular-nums;
}
.cid__preview--bad { color: var(--danger); }
.cid__preview {
  display: block;
  font-size: 12.5px;
  color: var(--muted);
  margin-top: 7px;
  font-variant-numeric: tabular-nums;
}

/* Recents ---------------------------------------------------------------- */
.recents { list-style: none; margin: 0; padding: 0; flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.rec {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 2px;
  border-bottom: 1px solid var(--hair);
}
.rec__icon { font-size: 15px; width: 20px; text-align: center; flex: none; }
.rec__icon--out { color: var(--ok); }
.rec__icon--fail { color: var(--danger); }
.rec__body { flex: 1; min-width: 0; }
.rec__num {
  font-size: 16px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rec__meta { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.rec__dur { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; flex: none; }
.rec__redial {
  border: 0; background: transparent; color: var(--link);
  font: inherit; font-size: 13px; cursor: pointer; padding: 6px; flex: none;
}
.empty { text-align: center; padding: 40px 0; }

/* Tab bar ---------------------------------------------------------------- */
.tabs {
  display: flex;
  gap: 6px;
  border-top: 1px solid var(--hair);
  padding-top: clamp(6px, calc(var(--app-h) * .012), 10px);
  margin-top: clamp(6px, calc(var(--app-h) * .012), 12px);
  flex: none;
}
.tabs__btn {
  flex: 1;
  padding: 9px;
  border: 0;
  border-radius: 9px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.tabs__btn.is-active { background: var(--card); color: var(--fg); }

/* In call ---------------------------------------------------------------- */
.screen--call { justify-content: space-between; text-align: center; }
.call__top { padding-top: 44px; }
.call__avatar {
  width: 88px; height: 88px;
  margin: 0 auto 22px;
  border-radius: 50%;
  background: var(--card);
  display: grid;
  place-items: center;
  font-size: 34px;
  font-weight: 500;
  color: var(--muted);
}
.call__num {
  font-size: 29px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  word-break: break-all;
}
.call__cid { font-size: 13.5px; color: var(--muted); margin-top: 8px; }
.call__state {
  font-size: 17px;
  color: var(--muted);
  margin-top: 26px;
  font-variant-numeric: tabular-nums;
  min-height: 24px;
}
.call__state--live { color: var(--ok); }
.call__hint {
  font-size: 12px;
  line-height: 1.4;
  color: var(--muted);
  max-width: 30ch;
  margin: 0 auto 22px;
}

/* Status ----------------------------------------------------------------- */
.status {
  margin-top: 14px;
  padding: 11px 13px;
  font-size: 13.5px;
  border-radius: 10px;
  background: var(--card);
  color: var(--muted);
  white-space: pre-wrap;
}
.status--error { background: color-mix(in srgb, var(--danger) 16%, transparent); color: #ff9ea1; }

/* Short screens - a small Android inside Telegram's sheet, or any phone with
   the keyboard open. Every fixed piece of chrome gives up a few pixels so the
   keypad and the call button stay on screen without scrolling. */
@media (max-height: 680px) {
  .screen { padding-top: 8px; padding-bottom: calc(6px + env(safe-area-inset-bottom)); }
  .bar { padding-bottom: 6px; margin-bottom: 6px; }
  .bar__value { font-size: 17px; }
  .picker { padding-top: 7px; padding-bottom: 7px; }
  .cid__label { font-size: 10.5px; margin-bottom: 3px; }
  .cid input, .picker--sm { padding-top: 8px; padding-bottom: 8px; }
  .btn { padding: 12px 16px; }
  .tabs__btn { padding: 7px; font-size: 13px; }
  .rateline { min-height: 15px; font-size: 12px; }
}

/* Very short - landscape, or a small device with the keyboard up. The letters
   under each digit are the first thing that can go: they are decoration, the
   digits are the function. */
@media (max-height: 560px) {
  .key i { display: none; }
  .cid__label { display: none; }
}

/* Phone-screen errors float over the layout instead of joining it: the dial
   pad is sized to the exact viewport, so anything that adds height pushes the
   call button off the bottom. */
.toast {
  position: fixed;
  left: 50%;
  bottom: calc(78px + env(safe-area-inset-bottom));
  transform: translate(-50%, 8px);
  z-index: 40;
  width: min(420px, calc(100vw - 32px));
  margin: 0;
  text-align: center;
  box-shadow: 0 6px 22px rgba(0, 0, 0, .35);
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s, transform .18s;
}
.toast.is-on { opacity: 1; transform: translate(-50%, 0); }

@media (prefers-reduced-motion: reduce) {
  .toast { transition: none; }
}

#remote { display: none; }

/* Selecting recents ------------------------------------------------------ */

.selbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 2px 10px;
  border-bottom: 1px solid var(--hair);
}
.selbar__count { flex: 1; font-size: 14px; font-weight: 600; }
.selbar__cancel,
.selbar__delete {
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 14px;
  padding: 6px 2px;
  cursor: pointer;
}
.selbar__cancel { color: var(--link); }
.selbar__delete { color: var(--danger); font-weight: 600; }
.selbar__delete:disabled { opacity: .4; cursor: default; }

/* Zero-width until selection starts, so turning it on slides the tick in
   instead of shifting every row at once. */
.rec__tick {
  width: 0;
  flex: none;
  overflow: hidden;
  opacity: 0;
  text-align: center;
  color: var(--accent);
  font-size: 14px;
  transition: width .15s, opacity .15s;
}
.rec.is-selecting .rec__tick { width: 18px; opacity: .28; }
.rec.is-selected .rec__tick { opacity: 1; }
.rec.is-selected { background: color-mix(in srgb, var(--accent) 12%, transparent); }

/* While selecting, the row is a checkbox - the redial button must not look
   like it is still offering to place a call. */
.rec.is-selecting { cursor: pointer; user-select: none; }
.rec.is-selecting .rec__redial { opacity: .35; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .rec__tick { transition: none; }
}

/* Top up ----------------------------------------------------------------- */

.bar__topup {
  border: 0;
  flex: 0 0 auto;
  background: var(--accent);
  color: var(--accent-fg);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 5px 11px;
  border-radius: 999px;
  cursor: pointer;
}

/* The one place in the app that may scroll: an address, a QR and a status
   line together exceed a short screen, and none of it can be shrunk away. */
.topup__scroll { flex: 1; min-height: 0; overflow-y: auto; }

.topup__lead { font-size: 14px; color: var(--muted); margin: 4px 0 16px; }
.topup__note { font-size: 12px; color: var(--muted); text-align: center; margin: 10px 0 14px; }

.chips { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0 18px; }
.chip {
  border: 1px solid var(--hair);
  background: transparent;
  color: var(--fg);
  font: inherit;
  font-size: 13px;
  padding: 7px 13px;
  border-radius: 999px;
  cursor: pointer;
}
.chip:active { background: var(--card); }

.paybox {
  background: var(--card);
  border-radius: 12px;
  padding: 10px 12px;
  margin-bottom: 10px;
}
.paybox__label {
  display: block;
  font-size: 11px;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 4px;
}
.paybox__row { display: flex; align-items: center; gap: 10px; }
.paybox__value {
  flex: 1;
  min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 15px;
  /* An address must wrap rather than be truncated: a customer checking it
     against their wallet needs to see all of it. */
  word-break: break-all;
}
.paybox__value--addr { font-size: 12.5px; line-height: 1.4; }
.copy {
  flex: none;
  border: 0;
  background: transparent;
  color: var(--link);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 6px 2px;
  cursor: pointer;
}

/* White plate behind the QR: a dark theme would otherwise invert it and most
   scanners cannot read an inverted code. */
.qr {
  width: 200px;
  margin: 6px auto 12px;
  padding: 10px;
  background: #fff;
  border-radius: 12px;
  line-height: 0;
}
.qr svg { width: 100%; height: auto; display: block; }

.paystatus { text-align: center; font-size: 14px; font-weight: 600; margin: 6px 0; }
.paystatus--busy { color: var(--muted); }
.paystatus--ok   { color: var(--ok); }
.paystatus--warn { color: var(--danger); }

/* Top-up: success ---------------------------------------------------------- */

.done {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  text-align: center;
  padding-bottom: 40px;
}
.done__tick {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 34px;
  color: #fff;
  background: var(--ok);
  margin-bottom: 6px;
}
.done__tick.is-in { animation: tickIn .42s cubic-bezier(.2, .9, .3, 1.2); }
@keyframes tickIn {
  from { transform: scale(.4); opacity: 0; }
  to   { transform: scale(1);  opacity: 1; }
}
.done__amount  { font-size: 22px; font-weight: 700; margin: 0; }
.done__balance { font-size: 14px; color: var(--muted); margin: 0; }

@media (prefers-reduced-motion: reduce) {
  .done__tick.is-in { animation: none; }
}

/* Top-up: history ---------------------------------------------------------- */

.topup__history { margin-top: 26px; }
.topup__h {
  font-size: 12px;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
  margin: 0 0 6px;
}
.paylist { list-style: none; margin: 0; padding: 0; }
.payrow {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 2px;
  border-bottom: 1px solid var(--hair);
}
.payrow__body { flex: 1; min-width: 0; }
.payrow__amount { font-size: 15px; font-variant-numeric: tabular-nums; }
.payrow__when { font-size: 12.5px; color: var(--muted); margin-top: 2px; }

/* An unfinished top-up can be reopened, so it has to look touchable. */
.payrow--open { cursor: pointer; }
.payrow--open .payrow__amount { color: var(--link); }

.paytag {
  flex: none;
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--card);
  color: var(--muted);
}
.paytag--credited { background: color-mix(in srgb, var(--ok) 20%, transparent); color: var(--ok); }
.paytag--seen     { background: color-mix(in srgb, var(--accent) 20%, transparent); color: var(--accent); }
.paytag--expired  { opacity: .6; }

/* Currency / network choices ---------------------------------------------- */

.choices { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.choice {
  border: 1px solid var(--hair);
  background: transparent;
  color: var(--fg);
  font: inherit;
  font-size: 13.5px;
  padding: 9px 15px;
  border-radius: 10px;
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
/* The selected one has to read as chosen at a glance, since getting the
   network wrong is how funds go missing. */
.choice.is-on {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  font-weight: 600;
}

/* Pre-call notices -------------------------------------------------------- */

.noticebox {
  border-radius: 16px;
  margin: auto 12px;
  max-height: 82vh;
  padding: 20px 18px 16px;
  overflow-y: auto;
}
.notice__title { margin: 0 0 12px; font-size: 18px; font-weight: 700; }
.notice__body { font-size: 14.5px; line-height: 1.5; color: var(--fg); }
.notice__body p { margin: 0 0 12px; }
.notice__again {
  display: flex; align-items: center; gap: 9px;
  font-size: 13.5px; color: var(--muted);
  margin: 4px 0 14px; cursor: pointer;
}
.notice__actions { display: flex; gap: 10px; }
.notice__actions .btn { flex: 1; margin-top: 0; }
.notice__step { text-align: center; font-size: 12px; color: var(--muted); margin: 10px 0 0; }

/* Opened outside Telegram ------------------------------------------------- */

.gate { text-align: center; max-width: 320px; }
.gate__mark {
  width: 62px; height: 62px;
  margin: 0 auto 18px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent);
  color: var(--accent-fg);
}
.gate__title { font-size: 21px; font-weight: 700; margin: 0 0 10px; }
.gate__text { font-size: 14.5px; line-height: 1.55; color: var(--muted); margin: 0 0 22px; }
.gate__cta { display: block; margin-top: 0; text-decoration: none; text-align: center; }
.gate__hint {
  font-size: 12.5px; color: var(--muted); margin: 12px 0 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* Free credit ------------------------------------------------------------- */



@media (prefers-reduced-motion: reduce) { .invite__fill { transition: none; } }


/* Group seeding ----------------------------------------------------------- */




/* Trial credit --------------------------------------------------------------
   In the balance bar, not above the keypad. The phone screen is a fixed
   height and the keypad has to reach the bottom of it, so a banner here costs
   exactly the space the dial pad needs. The chip is the state; the sentence
   is a tap away and floats. */
.barchip {
  flex: 0 0 auto;
  margin-left: 8px;
  padding: 3px 9px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .02em;
  white-space: nowrap;
  cursor: pointer;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.barchip--spent {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 16%, transparent);
}

/* The unclaimed offer, in the slot the trial chip takes once it is claimed.
   Allowed to shrink: on a narrow phone the balance and the top-up button are
   what must survive intact, and the gift alone still reads as an offer. */
.barchip--offer {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  /* Overrides the base chip's 0 0 auto: without a shrink factor the label can
     never ellipsis and the bar overflows instead. */
  flex: 0 1 auto;
  min-width: 0;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.barchip__gift { flex: 0 0 auto; font-size: 12px; line-height: 1; }
.barchip__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.barchip__caret { flex: 0 0 auto; font-size: 8px; opacity: .75; transition: transform .15s ease; }
.barchip--offer[aria-expanded="true"] .barchip__caret { transform: rotate(180deg); }

/* The offer, unfolded.
   The chip that opens this lives in the balance bar, so shut it costs the
   keypad nothing at all. Open, there is room to say what the deal actually is
   rather than compress it into the chip. Rendered only for an unclaimed
   account: once taken, both halves are gone for good. */
.claim__panel {
  padding: 10px 12px;
  border-radius: 12px;
  background: var(--card);
  border: 1px solid var(--hair);
}
.claim__text {
  margin: 0 0 9px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--muted);
}
.claim__text b { color: var(--accent); font-weight: 700; }

.claim__actions { display: flex; align-items: center; gap: 8px; }
.claim__join, .claim__get {
  flex: 0 0 auto;
  border: 0;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
}
.claim__join { color: var(--link); background: transparent; padding-inline: 4px; }
.claim__get { color: var(--accent-fg); background: var(--accent); }
.claim__get:disabled { opacity: .55; }

.claim__msg {
  margin: 8px 0 0;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--muted);
}
.claim__msg--warn { color: var(--danger); }

@media (prefers-reduced-motion: reduce) {
  .barchip__caret { transition: none; }
}

/* Earn ---------------------------------------------------------------------- */
.earn { padding: 4px 12px 20px; }
.earn__hero { text-align: center; padding: 8px 0 14px; }
.earn__gift { font-size: 40px; line-height: 1; }
.earn__title {
  margin: 6px 0 4px; font-size: 20px; font-weight: 700;
  color: var(--fg);
}
.earn__lead {
  margin: 0; font-size: 13px; line-height: 1.5;
  color: var(--muted);
}
.earn__note {
  margin: 8px 0 0; font-size: 12px; text-align: center;
  color: var(--muted);
}
.earn__note--warn { color: var(--danger); }

.earn__link { margin-top: 14px; }
.earn__linklabel {
  display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); margin-bottom: 5px;
}
.earn__linkrow { display: flex; gap: 8px; align-items: center; }
.earn__linktext {
  flex: 1; min-width: 0; overflow-x: auto; white-space: nowrap;
  font-size: 12px; padding: 9px 10px; border-radius: 9px;
  background: var(--card);
  color: var(--fg);
}

.earn__stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  margin: 16px 0 10px;
}
.earn__stat {
  text-align: center; padding: 10px 4px; border-radius: 12px;
  background: var(--card);
}
.earn__num {
  display: block; font-size: 17px; font-weight: 700;
  color: var(--fg);
}
.earn__cap {
  display: block; margin-top: 2px; font-size: 10px;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted);
}

.earn__people, .earn__payouts { list-style: none; margin: 8px 0 0; padding: 0; }
.earnrow {
  display: flex; justify-content: space-between; gap: 10px; align-items: baseline;
  padding: 9px 2px; font-size: 13px;
  border-bottom: 1px solid var(--hair);
}
.earnrow__name {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--fg);
}
.earnrow__amt { font-variant-numeric: tabular-nums; font-weight: 600; }

.earn__cashbox, .earn__groups { margin-top: 20px; }
.earn__h {
  margin: 0 0 6px; font-size: 14px; font-weight: 600;
  color: var(--fg);
}
.earn__hint {
  margin: 0 0 10px; font-size: 12px; line-height: 1.5;
  color: var(--muted);
}
.earn__form { display: grid; gap: 8px; }
.earn__form input {
  width: 100%; padding: 11px 12px; border-radius: 10px; font-size: 15px;
  border: 1px solid var(--hair);
  background: var(--bg);
  color: var(--fg);
}
.earn__msg { margin: 8px 0 0; font-size: 12px; line-height: 1.4; }
.earn__msg--ok { color: var(--ok); }
.earn__msg--warn { color: var(--danger); }

/* First-run tour -------------------------------------------------------------
   A hole punched over the real control, using one element with an enormous
   spread shadow: no SVG mask, no four-panel scrim to keep in sync, and the
   hole moves by moving one box. */
.tour {
  position: fixed;
  inset: 0;
  z-index: 60;
}
.tour__hole {
  position: absolute;
  border-radius: 12px;
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, .72);
  transition: all .22s cubic-bezier(.4, 0, .2, 1);
  pointer-events: none;
}
.tour__card {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: min(340px, calc(100vw - 32px));
  padding: 16px 18px;
  border-radius: 15px;
  background: var(--card);
  border: 1px solid var(--hair);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .45);
  transition: top .22s cubic-bezier(.4, 0, .2, 1);
}
.tour__step {
  margin: 0 0 4px;
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}
.tour__title { margin: 0 0 6px; font-size: 17px; font-weight: 700; color: var(--fg); }
.tour__body { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--muted); }
.tour__actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 14px;
}
.tour__skip {
  border: 0;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 13.5px;
  padding: 8px 4px;
  cursor: pointer;
}
.tour__next {
  border: 0;
  background: var(--accent);
  color: var(--accent-fg);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 9px 18px;
  border-radius: 999px;
  cursor: pointer;
}

/* Tapping outside the card points at the way forward rather than leaving.
   Two beats of scale and glow: enough to catch the eye without looking like
   an error. */
@keyframes tour-nudge {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 transparent; }
  30%      { transform: scale(1.07); box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 30%, transparent); }
  60%      { transform: scale(1); box-shadow: 0 0 0 0 transparent; }
  80%      { transform: scale(1.045); box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 22%, transparent); }
}
.tour__next.is-nudge { animation: tour-nudge .62s ease-out; }

@media (prefers-reduced-motion: reduce) {
  .tour__hole, .tour__card { transition: none; }
  .tour__next.is-nudge { animation: none; outline: 2px solid var(--accent); outline-offset: 3px; }
}
