/* 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 {
  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;
}
.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); }
.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; }
}

/* Onboarding -----------------------------------------------------------------
   The first screen an advert sends somebody to. It has one job - explain the
   thing and get them past it - so the offer is the hero and the legal text is
   folded behind a summary. The button is pinned so it is reachable without
   scrolling the pitch first. */
/* Overrides the earlier rule that let the whole section scroll: with a pinned
   footer and a scrolling body, two scroll containers fight each other. */
#onboarding { padding: 0; display: flex; flex-direction: column; overflow: hidden; }
.ob__scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 18px 6px;
  -webkit-overflow-scrolling: touch;
}
.ob__hero { text-align: center; padding: 2px 0 14px; }
.ob__mark { color: var(--accent); }
.ob__title {
  margin: 9px 0 7px;
  font-size: clamp(21px, 5.8vw, 26px);
  font-weight: 700;
  line-height: 1.18;
  letter-spacing: -.02em;
}
.ob__lead {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--muted);
}
.ob__lead b { color: var(--fg); font-weight: 600; }

.ob__points { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 8px; }
.ob__points li {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 9px 12px;
  border-radius: 11px;
  background: var(--card);
  font-size: 13px;
  line-height: 1.42;
  color: var(--muted);
}
.ob__points b { color: var(--fg); font-weight: 600; }
.ob__ico {
  flex: 0 0 auto;
  width: 28px; height: 28px;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 15%, transparent);
}

.ob__terms {
  border: 1px solid var(--hair);
  border-radius: 12px;
  padding: 0 13px;
  margin-bottom: 10px;
}
.ob__terms summary {
  padding: 10px 0;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.ob__terms summary::-webkit-details-marker { display: none; }
.ob__terms summary::after {
  content: '▾';
  float: right;
  color: var(--muted);
  font-size: 11px;
  transition: transform .15s ease;
}
.ob__terms[open] summary::after { transform: rotate(180deg); }
.ob__terms .terms { padding-bottom: 12px; }

.ob__accept { margin-bottom: 7px; font-weight: 600; }
.ob__opt { margin-bottom: 5px; }
.ob__note {
  margin: 0 0 4px;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--muted);
}

/* Pinned, so the action never depends on how far they scrolled. */
.ob__foot {
  flex: 0 0 auto;
  padding: 10px 18px calc(12px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--hair);
  background: var(--bg);
}

/* Short screens - the icon tiles are decoration and the terms are not, so the
   tiles go first rather than pushing the acceptance below the fold. */
@media (max-height: 620px) {
  .ob__hero { padding-top: 0; padding-bottom: 10px; }
  .ob__mark { width: 34px; height: 34px; }
  .ob__ico { display: none; }
  .ob__points li { padding: 8px 11px; }
  .ob__points { gap: 6px; }
}

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

/* Out of credit ------------------------------------------------------------
   Centred and modal on purpose. A refused call is the moment somebody is most
   willing to pay, and the old toast said so at the bottom of the screen for
   six seconds and then took it back. */
.funds { text-align: center; }
.funds__icon {
  width: 52px; height: 52px; margin: 0 auto 12px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 14%, transparent);
}
.funds__title { margin: 0 0 8px; font-size: 19px; font-weight: 700; color: var(--fg); }
.funds__body { margin: 0 0 18px; font-size: 13.5px; line-height: 1.5; color: var(--muted); }
.funds__body b { color: var(--fg); font-weight: 600; }

.funds__opt {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 13px 14px; margin-bottom: 9px;
  border: 1px solid var(--hair); border-radius: 13px;
  background: var(--card); color: var(--fg);
  font: inherit; text-align: left; cursor: pointer;
}
.funds__opt:active { background: var(--hair); }
.funds__optIcon {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 15%, transparent);
}
.funds__optText { flex: 1; min-width: 0; }
.funds__optText b { display: block; font-size: 14.5px; font-weight: 600; }
.funds__optText em {
  display: block; font-style: normal; font-size: 12px;
  line-height: 1.4; color: var(--muted); margin-top: 2px;
}
.funds__chev { flex: 0 0 auto; color: var(--muted); font-size: 20px; line-height: 1; }
.funds__close {
  margin-top: 4px; border: 0; background: transparent;
  color: var(--muted); font: inherit; font-size: 14px; padding: 10px; cursor: pointer;
}

/* Top-up, inside the sheet -------------------------------------------------
   Reached either from the balance bar or from a refused call. In both cases
   the flow stays in the one dialog. */
.funds__pay { max-height: 82vh; overflow-y: auto; }
.funds__back {
  border: 0; background: transparent; color: var(--muted);
  font: inherit; font-size: 14px; padding: 2px 0 10px; cursor: pointer;
}
.pay__crumb {
  margin: 0 0 12px; font-size: 11.5px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted); font-weight: 600;
}

/* Claiming the trial, inside the sheet -------------------------------------- */
.funds__icon--gift { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.ft__steps {
  list-style: none; margin: 0 0 16px; padding: 0;
  display: grid; gap: 9px; text-align: left;
}
.ft__steps li { display: flex; align-items: center; gap: 10px; font-size: 13.5px; color: var(--muted); }
.ft__n {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
  color: var(--accent-fg); background: var(--accent);
}
.ft__join { display: block; margin-bottom: 9px; }
.funds__msg { margin: 12px 0 0; font-size: 12.5px; line-height: 1.45; color: var(--muted); }
.funds__msg--warn { color: var(--danger); }
.funds__msg--ok { color: var(--ok); }

/* Home-screen prompt --------------------------------------------------------
   Telegram can put a real icon on the phone's home screen, which turns a
   buried chat into something people see every day. Offered once, only where
   the client actually supports it, and dismissible - a bar that cannot be got
   rid of costs more goodwill than the icon is worth. */
.pin {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 8px;
  padding: 8px 10px;
  border-radius: 11px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
}
.pin__icon { flex: 0 0 auto; color: var(--accent); display: flex; }
.pin__text { flex: 1; min-width: 0; font-size: 12.5px; line-height: 1.35; color: var(--fg); }
.pin__go {
  flex: 0 0 auto; border: 0; border-radius: 999px; cursor: pointer;
  background: var(--accent); color: var(--accent-fg);
  font: inherit; font-size: 12.5px; font-weight: 600; padding: 6px 14px;
}
.pin__no {
  flex: 0 0 auto; border: 0; background: transparent; cursor: pointer;
  color: var(--muted); font-size: 18px; line-height: 1; padding: 2px 4px;
}

/* Pointing at what is missing ------------------------------------------------
   A ring that pulses twice around whatever is stopping the call. Deliberately
   short: it is a pointer, not a warning that has to be dismissed. */
@keyframes needs-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 60%, transparent); }
  40%  { box-shadow: 0 0 0 7px color-mix(in srgb, var(--accent) 0%, transparent); }
  60%  { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  100% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--accent) 0%, transparent); }
}
.needs {
  border-radius: 12px;
  animation: needs-pulse 1.3s ease-out 2;
  position: relative;
  z-index: 1;
}
@media (prefers-reduced-motion: reduce) {
  .needs { animation: none; outline: 2px solid var(--accent); outline-offset: 3px; }
}

/* Guidance bubble -----------------------------------------------------------
   Anchored to the control it is talking about. The old version reused the
   error toast, which is pinned 78px from the bottom - precisely where the
   caller-ID row lands once it is scrolled to, so the message covered the field
   it was asking somebody to fill in. */
.tip {
  position: fixed;
  z-index: 45;
  max-width: min(320px, calc(100vw - 28px));
  padding: 10px 13px;
  border-radius: 12px;
  background: var(--accent);
  color: var(--accent-fg);
  font-size: 13px;
  line-height: 1.45;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .32);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity .16s ease, transform .16s ease;
  pointer-events: none;
}
.tip.is-on { opacity: 1; transform: translateY(0); }
.tip__arrow {
  position: absolute;
  width: 10px; height: 10px;
  background: var(--accent);
  transform: rotate(45deg);
  left: var(--tip-arrow, 24px);
}
.tip--below .tip__arrow { top: -5px; }
.tip--above .tip__arrow { bottom: -5px; }

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

/* ---------------------------------------------------------------------------
   Joining, waiting, and the reseller screen
   --------------------------------------------------------------------------- */

.langpick { display: flex; gap: 8px; justify-content: center; margin: 4px 0 14px; }
.langpick__btn {
  border: 1px solid var(--line, #2a2f3a); background: transparent; color: inherit;
  border-radius: 999px; padding: 6px 16px; font: inherit; font-size: 14px; cursor: pointer;
}
.langpick__btn.is-active { background: var(--accent, #2f81f7); border-color: transparent; color: #fff; }

.join__box {
  border: 1px solid var(--line, #2a2f3a); border-radius: 14px;
  padding: 16px; margin: 12px 0 18px;
}
.join__title { font-size: 17px; margin: 0 0 6px; }
.join__body { margin: 0 0 14px; font-size: 14px; opacity: .8; line-height: 1.45; }
.join__label { display: block; font-size: 13px; opacity: .7; margin-bottom: 6px; }
.join__input {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 17px;
  letter-spacing: .04em; padding: 12px 14px; border-radius: 10px;
  border: 1px solid var(--line, #2a2f3a); background: var(--field, rgba(255,255,255,.04));
  color: inherit;
}
.join__mine {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 12px 0 4px; font-size: 13px; opacity: .85;
}
.join__hint { margin: 0; font-size: 12px; opacity: .6; line-height: 1.45; }
.join__banner {
  border-radius: 10px; padding: 10px 12px; margin: 0 0 12px; font-size: 13px;
  background: rgba(220, 80, 80, .12); border: 1px solid rgba(220, 80, 80, .3);
}

.pending__box { text-align: center; padding: 24px; max-width: 340px; }
.pending__title { font-size: 19px; margin: 14px 0 8px; }
.pending__body { font-size: 14px; opacity: .8; line-height: 1.5; margin: 0 0 14px; }
.pending__spin {
  width: 34px; height: 34px; margin: 0 auto; border-radius: 50%;
  border: 3px solid var(--line, #2a2f3a); border-top-color: var(--accent, #2f81f7);
  animation: pendingspin 900ms linear infinite;
}
@keyframes pendingspin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .pending__spin { animation-duration: 3s; } }

/* The destination picker is a label, not a control: Bangladesh is the only
   destination, so it must not look pressable. */
.picker--fixed { opacity: .75; pointer-events: none; }

.rs__scroll { overflow-y: auto; padding: 12px 14px 20px; -webkit-overflow-scrolling: touch; }
.rs__idcard {
  border: 1px solid var(--line, #2a2f3a); border-radius: 14px; padding: 14px; margin-bottom: 14px;
}
.rs__idlabel { font-size: 12px; opacity: .65; }
.rs__idrow { display: flex; align-items: center; gap: 10px; margin: 6px 0 8px; }
.rs__id { font-size: 21px; letter-spacing: .04em; }
.rs__hint { margin: 0; font-size: 12px; opacity: .6; line-height: 1.45; }

.rs__stats { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 16px; }
.rs__stats > div {
  border: 1px solid var(--line, #2a2f3a); border-radius: 12px; padding: 12px;
  display: flex; flex-direction: column; gap: 4px;
}
.rs__slabel { font-size: 12px; opacity: .65; }
.rs__snum { font-size: 20px; font-variant-numeric: tabular-nums; }

.rs__notice {
  border-radius: 10px; padding: 12px; font-size: 13px; line-height: 1.5;
  background: rgba(255,255,255,.05); margin-bottom: 16px;
}
.rs__section { margin-bottom: 22px; }
.rs__h { font-size: 13px; text-transform: uppercase; letter-spacing: .08em; opacity: .55; margin: 0 0 8px; }
.rs__list { list-style: none; margin: 0 0 10px; padding: 0; display: flex; flex-direction: column; gap: 8px; }

.rs__item { border: 1px solid var(--line, #2a2f3a); border-radius: 12px; padding: 12px; }
.rs__item.is-frozen { opacity: .72; border-style: dashed; }
.rs__item--pending { border-color: var(--accent, #2f81f7); }
.rs__head { display: flex; align-items: baseline; gap: 8px; }
.rs__name { font-size: 15px; font-weight: 600; flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rs__badge {
  font-size: 11px; padding: 2px 8px; border-radius: 999px;
  background: rgba(255,255,255,.08); opacity: .8;
}
.rs__bal { font-variant-numeric: tabular-nums; font-size: 15px; }
.rs__tid { font-size: 12px; opacity: .7; }
.rs__meta { margin: 6px 0 0; font-size: 12px; opacity: .7; }
.rs__frozen { margin: 6px 0 0; font-size: 12px; color: #e5a05a; }
.rs__actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.rs__act {
  font: inherit; font-size: 13px; padding: 7px 12px; border-radius: 9px; cursor: pointer;
  border: 1px solid var(--line, #2a2f3a); background: transparent; color: inherit;
}
.rs__act:disabled { opacity: .5; }
.rs__act--warn { color: #e5a05a; border-color: rgba(229,160,90,.4); }
.rs__msg { margin: 8px 0 0; font-size: 12px; }
.rs__msg--warn { color: #e08b8b; }
.rs__msg--ok { color: #7ec98f; }

.rs__ledger { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.rs__led { display: flex; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line, #2a2f3a); font-size: 13px; }
.rs__ledwho { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: .8; }
.rs__ledamt { font-variant-numeric: tabular-nums; }
.rs__ledamt.is-up { color: #7ec98f; }
.rs__ledamt.is-down { opacity: .7; }

/* The join screen's own id card, and the live wait ------------------------- */
.join__idcard {
  background: var(--field, rgba(255,255,255,.05));
  border: 1px solid var(--line, #2a2f3a);
  border-radius: 12px; padding: 12px 14px; margin: 14px 0 12px;
}
.join__idlabel { display: block; font-size: 12px; opacity: .6; margin-bottom: 4px; }
.join__idrow { display: flex; align-items: center; gap: 10px; }
.join__id {
  font-size: 24px; letter-spacing: .04em; font-variant-numeric: tabular-nums;
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
}
.join__waiting { display: flex; align-items: center; gap: 9px; margin: 0 0 6px; font-size: 13px; opacity: .85; }
.join__pulse {
  width: 9px; height: 9px; border-radius: 50%; background: #00A86B; flex: none;
  animation: joinpulse 1.6s ease-in-out infinite;
}
@keyframes joinpulse { 0%,100% { opacity: 1; transform: scale(1) } 50% { opacity: .35; transform: scale(.8) } }
@media (prefers-reduced-motion: reduce) { .join__pulse { animation: none } }

/* The reseller-id path, folded away: it is the fallback, not the way in. */
.join__alt { margin-top: 16px; }
.join__alt > summary {
  cursor: pointer; font-size: 13px; opacity: .7; padding: 6px 0; list-style: none;
}
.join__alt > summary::-webkit-details-marker { display: none }
.join__alt > summary::before { content: '＋ '; opacity: .6 }
.join__alt[open] > summary::before { content: '－ ' }
.join__alt .join__input { margin-bottom: 10px }
