/* ProxyData Mini App — stylesheet.
 *
 * THEME STRATEGY. Every colour is a token on :root defined as
 *   var(--tg-<something>, <V3.1 fallback>)
 * so the app adopts the surrounding Telegram client's palette when telegram.js has set those
 * variables, and falls back to the V3.1 dark design otherwise. Rules below reference only the
 * app's own tokens (--bg, --panel, --text, --accent, …) — never --tg-* directly — so there is
 * exactly one place to change when a token's meaning shifts, and a screen can never
 * accidentally hard-code a colour that ignores the user's theme.
 *
 * The accent stays ours in both modes: #00E5FF is brand, not chrome, and a Telegram theme's
 * button colour would make the product unrecognisable between clients.
 *
 * THE CHROME IS NOT THEMED. The header and the tab bar carry their own literal values from the
 * V3.1 reference — rgba(10,14,26,.9) and rgba(9,13,23,.97) — and deliberately not --panel. They
 * are the frame the product is recognised by; a client theme must not repaint them.
 *
 * No @import, no external font, no remote image — Phase 1 makes zero external requests, and a
 * stylesheet is the easiest place to leak one by accident.
 */

:root {
  /* ── V3 DESIGN TOKENS ──────────────────────────────────────────────────────────────────────
   * Extracted from the owner's visual source of truth, "ProxyData Mini App v3 EN": the cyan,
   * the purple, the 135° gradient, the alpha ladders and the glow radii are the reference's own
   * values, not an interpretation of them.
   *
   * The app got flat because it used ONE translucent white for every surface and reserved the
   * accent for buttons. v3 does the opposite: surfaces are tinted, depth comes from layered
   * alpha, and cyan→purple carries the eye to whatever matters most on the screen. These tokens
   * make that reproducible instead of a per-screen decision.
   *
   * TOKENS CARRY NO BUSINESS STATE. Nothing here knows what an access or a purchase is. */

  --bg:            var(--tg-bg, #05070c);
  --bg-grad-top:   #0c1322;

  /* Four surface depths, not one. A card on a card was previously invisible. */
  --surface:         rgba(255, 255, 255, .035);
  --surface-soft:    rgba(255, 255, 255, .022);
  --surface-elevated:rgba(255, 255, 255, .06);
  --surface-line:    rgba(255, 255, 255, .07);
  /* Tinted surfaces — the v3 signature: a card that belongs to the accent, not to grey. */
  --surface-cyan:    rgba(0, 229, 255, .06);
  --surface-purple:  rgba(124, 58, 237, .08);

  /* Back-compat aliases: existing rules keep working while screens migrate. */
  --panel:         var(--tg-secondary-bg, var(--surface));
  --panel-strong:  var(--surface-elevated);
  --panel-line:    var(--surface-line);

  --text:           var(--tg-text, #ffffff);
  --text-primary:   var(--tg-text, #eef1f6);
  --text-secondary: #c6cfdd;
  --text-muted:     var(--tg-hint, #8fa0b8);
  --muted:          var(--text-muted);
  --dim:            #4b5768;

  --cyan:          #00E5FF;
  --cyan-soft:     #8fd8e8;
  --purple:        #7C3AED;
  --purple-soft:   #a78bfa;
  /* Aliases kept so no existing rule has to change in the same commit as the tokens. */
  --accent:        var(--cyan);
  --accent-soft:   var(--cyan-soft);
  --accent-dim:    rgba(0, 229, 255, .12);
  --secondary:     var(--purple);

  --ok:            #34d399;
  --warn:          #ffb454;
  --danger:        #f87171;

  /* THE gradient. 135° for surfaces and CTAs, 90° for anything that reads as a track. */
  --gradient-primary: linear-gradient(135deg, #00E5FF 0%, #7C3AED 100%);
  --gradient-track:   linear-gradient(90deg, #00E5FF, #7C3AED);
  --gradient-wash:    linear-gradient(135deg, rgba(0,229,255,.10), rgba(124,58,237,.08));
  --gradient-wash-soft: linear-gradient(135deg, rgba(0,229,255,.06), rgba(124,58,237,.05));

  /* Glow, at the reference's radii. Used sparingly — on the ONE thing that matters per screen. */
  --shadow-cyan:   0 0 24px rgba(0, 229, 255, .22);
  --shadow-cyan-sm:0 0 10px rgba(0, 229, 255, .30);
  --shadow-purple: 0 0 44px rgba(124, 58, 237, .18);
  --shadow-card:   0 6px 20px rgba(0, 0, 0, .35);

  /* Chrome surfaces — reference values, never --surface. */
  --chrome-top:    rgba(10, 14, 26, .9);
  --chrome-bottom: rgba(9, 13, 23, .97);
  --chrome-line:   rgba(255, 255, 255, .05);

  --radius-sm: 10px;
  --radius-md: 14px;
  --radius-lg: 18px;
  --r-sm: var(--radius-sm);
  --r-md: var(--radius-md);
  --r-lg: var(--radius-lg);

  /* 50px is the reference header. --tabbar-h is a RESERVATION, not the bar's height: the bar
   * sizes itself from its content and the raised Buy button overhangs it, so the scroll area
   * reserves a little more than the bar actually occupies. Over-reserving is invisible (it is
   * trailing scroll space); under-reserving hides the last row of content. */
  --topbar-h: 50px;
  --tabbar-h: 62px;
  --col: 390px;

  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --font: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', system-ui, sans-serif;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  font-size: 14px;
  line-height: 1.45;
  overscroll-behavior-y: none;
  -webkit-tap-highlight-color: transparent;
}

/* main.js toggles the header's two states with the `hidden` attribute, and several rules below
 * give those same elements a display. Without this the attribute would lose, and the brand and
 * the back chevron would both be on screen at once. */
[hidden] { display: none !important; }

h1, h2, h3, p { margin: 0; font-size: inherit; font-weight: inherit; }
ul, ol { margin: 0; padding: 0; list-style: none; }

button {
  font: inherit; color: inherit; background: none; border: 0; padding: 0;
  cursor: pointer; text-align: inherit;
}
button:disabled { cursor: not-allowed; }

input, textarea, select { font: inherit; }

/* Icons are laid out inside flex rows constantly; never let one be squeezed to nothing. */
svg { flex-shrink: 0; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-soft); }

/* V3.1 hides scrollbars entirely — the app is a phone surface, not a document. */
::-webkit-scrollbar { width: 0; height: 0; }
* { scrollbar-width: none; }

@keyframes fadeIn  { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes sheetUp { from { transform: translateY(100%); }            to { transform: translateY(0); } }
@keyframes toastIn { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
@keyframes skel    { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }
@keyframes spin    { to { transform: rotate(360deg); } }

/* The live website's logo breathing, reproduced: a cyan drop-shadow travelling 4px → 10px.
 * It is on the orb only — the mark is the one thing that moves in an otherwise still shell. */
@keyframes logoPulse {
  0%, 100% { filter: drop-shadow(0 0 4px rgba(0, 229, 255, .45)); }
  50%      { filter: drop-shadow(0 0 10px rgba(0, 229, 255, .8)); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  /* An animation cut to 0.001ms leaves the mark on its FIRST frame, which is the dim one. Pin
   * the resting glow explicitly so a reduced-motion user still gets the lit logo, not a flat one. */
  .topbar__logo, .brandmark--pulse { filter: drop-shadow(0 0 6px rgba(0, 229, 255, .5)); }
}

/* ── shell ─────────────────────────────────────────────────────────────────────
 *
 * The app is a fixed-height column: header, scrolling middle, tab bar. The height comes from
 * --app-height, which main.js writes from Telegram's viewportStableHeight (100dvh in a plain
 * browser), because Telegram's own chrome is not part of the viewport dvh reports.
 *
 * The tab bar is position:fixed rather than a flex child on purpose. If --app-height is ever
 * wrong — a stale value between a viewport change and its event — a flex-child bar would sail
 * off the bottom of the screen and strand the user on whatever tab they were on. A fixed bar is
 * pinned to the real viewport whatever the custom property says, so the app cannot become
 * unnavigable. The scroll area pays for that with bottom padding.
 */

.app {
  position: relative;
  max-width: var(--col);
  margin: 0 auto;
  min-height: var(--app-height, 100dvh);
  max-height: var(--app-height, 100dvh);
  background: radial-gradient(circle at 50% 0%, var(--bg-grad-top), var(--bg) 70%);
  display: flex;
  flex-direction: column;
}

/* ── header ── */

.topbar {
  flex: 0 0 auto;
  position: sticky; top: 0; z-index: 30;
  height: calc(var(--topbar-h) + env(safe-area-inset-top));
  padding: env(safe-area-inset-top) 16px 0;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--chrome-top);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--chrome-line);
}

.topbar__left {
  display: flex; align-items: center; gap: 10px;
  flex: 1 1 auto; min-width: 0;
}

/* 44×44 tap target with no visible chrome, pulled left so the chevron itself lands on the
 * header's 16px padding line rather than 12px inside it. */
.topbar__back {
  flex: 0 0 auto;
  width: 44px; height: 44px; margin-left: -12px;
  display: grid; place-items: center;
  color: var(--text);
  border-radius: 50%;
}
.topbar__back:active { background: rgba(255, 255, 255, .07); }

/* The REAL ProxyData orb from /public/soxylogo.svg — width/height come from the markup. */
.topbar__logo {
  flex: 0 0 auto;
  display: block;
  width: 22px; height: 22px;
  animation: logoPulse 3s ease-in-out infinite;
}

.topbar__brand {
  flex: 0 0 auto;
  font-size: 15px; font-weight: 800; letter-spacing: -.2px; color: #fff;
  white-space: nowrap;
}

.topbar__title {
  flex: 1 1 auto; min-width: 0;
  font-size: 15.5px; font-weight: 700; color: #fff;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.topbar__right { flex: 0 0 auto; display: flex; align-items: center; gap: 10px; }

.avatar {
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-dim); color: var(--accent);
  font-size: 12.5px; font-weight: 700;
}
.avatar:active { background: rgba(0, 229, 255, .2); }

/* ── scroll area ── */

.screen {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  -webkit-overflow-scrolling: touch;
  padding: 14px 14px calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 18px);
  animation: fadeIn .22s ease both;
}

.screen-home, .screen-accesses, .screen-detail {
  display: flex; flex-direction: column; gap: 14px;
}

/* ── tab bar ── */

.tabbar {
  position: fixed; bottom: 0; left: 50%; transform: translateX(-50%); z-index: 30;
  width: 100%; max-width: var(--col);
  display: flex; align-items: flex-end;
  padding: 6px 4px 0;
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--chrome-bottom);
  border-top: 1px solid var(--chrome-line);
}

.tab {
  flex: 1 1 0; min-width: 0;
  min-height: 48px;
  padding: 7px 2px 6px;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 4px;
  color: var(--dim);
  transition: color .15s ease;
}
.tab:active { opacity: .65; }
.tab__icon { width: 21px; height: 21px; }
.tab__label {
  font-size: 10px; font-weight: 650; line-height: 1.2; letter-spacing: .1px;
  white-space: nowrap;
}

/* The raised Buy action. It overhangs the bar's top edge by 10px, which is why the bar must
 * never clip its overflow and why the scroll area reserves more than the bar's own height. */
.tab--center { color: var(--muted); }
.tab__fab {
  width: 40px; height: 40px; border-radius: 13px; margin-top: -10px;
  display: grid; place-items: center;
  background: linear-gradient(135deg, #00E5FF, #7C3AED);
  box-shadow: 0 6px 16px rgba(0, 229, 255, .25);
}
.tab__fab svg { width: 19px; height: 19px; }
.tab--center:active .tab__fab { transform: scale(.94); }

.tab--active { color: var(--accent); }

/* ── primitives ────────────────────────────────────────────────────────────── */

.stack { display: flex; flex-direction: column; gap: 12px; }

/* Screen roots. Each is rendered as `class="stack <name>"`; they breathe slightly wider than a
 * bare stack because every one of them is a full page rather than a group inside a card. */
.buy, .tools, .checker, .profile, .parser, .referral, .wallet { gap: 14px; }

.card {
  background: var(--panel);
  border: 1px solid var(--panel-line);
  border-radius: var(--r-lg);
  padding: 14px;
}

.row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 4px 0; }
.row__label { color: var(--muted); font-size: 12.5px; flex: 0 0 auto; }
.row__value { font-weight: 600; font-size: 13px; text-align: right; min-width: 0; word-break: break-all; }

.muted { color: var(--muted); font-size: 12.5px; line-height: 1.55; }

.section { display: flex; flex-direction: column; gap: 10px; }
.section__head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.section__title {
  font-size: 12px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase;
  color: var(--dim);
}
.section__count { font-size: 12px; color: var(--muted); flex: 0 0 auto; }
.section__link { font-size: 12px; font-weight: 600; color: var(--accent); flex: 0 0 auto; }
.section__link:active { color: var(--accent-soft); }

.btn {
  appearance: none;
  border-radius: var(--r-md); padding: 12px 16px;
  font-size: 13.5px; font-weight: 650; letter-spacing: .2px; text-align: center;
  min-height: 44px;
  transition: transform .1s ease, opacity .15s ease, background .15s ease;
}
.btn:active:not(:disabled) { transform: scale(.985); }
.btn:disabled { opacity: .42; }
.btn--primary { background: var(--accent); color: #041016; }
.btn--primary:hover:not(:disabled) { background: var(--accent-soft); }
.btn--ghost { background: var(--panel-strong); color: var(--text); }
.btn--danger { background: rgba(255, 107, 107, .16); color: var(--danger); }

.chip {
  display: inline-block; flex: 0 0 auto; padding: 3px 8px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .3px; text-transform: uppercase;
  white-space: nowrap;
}
.chip--ok     { background: rgba(61, 220, 151, .14); color: var(--ok); }
.chip--warn   { background: rgba(255, 180, 84, .14); color: var(--warn); }
.chip--muted  { background: var(--panel-strong); color: var(--muted); }
.chip--accent { background: var(--accent-dim); color: var(--accent); }

.bar { display: block; height: 6px; border-radius: 999px; background: rgba(255, 255, 255, .07); overflow: hidden; }
.bar__fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--accent), #2a6cff); transition: width .3s ease; }

.skeleton { display: flex; flex-direction: column; gap: 10px; }
.skeleton__line { height: 54px; border-radius: var(--r-md); background: var(--panel); animation: skel 1.3s ease-in-out infinite; }

/* The ProxyData orb wherever a screen needs the mark. Size comes from the markup, so this rule
 * must not set one. */
.brandmark { display: block; }
.brandmark--pulse { animation: logoPulse 3s ease-in-out infinite; }

/* ── states: empty, notice, error, blocked ─────────────────────────────────────
 *
 * The account the owner opens has zero accesses and no activity, so these ARE the product for
 * that first session. They share one shape — tinted disc, one-line title, one calm sentence,
 * optional action — so an empty screen reads as a designed destination rather than a gap.
 */

.empty, .notice, .errorstate {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: 32px 18px;
}

.empty__icon, .notice__icon, .errorstate__icon, .blocked__icon {
  width: 56px; height: 56px; border-radius: 50%;
  display: grid; place-items: center;
  margin-bottom: 14px;
}
.empty__icon     { background: var(--panel-strong); color: var(--muted); }
.notice__icon    { background: var(--accent-dim);   color: var(--accent); }
.errorstate__icon{ background: rgba(255, 107, 107, .1); color: var(--danger); }
.blocked__icon   { background: rgba(255, 180, 84, .12); color: var(--warn); }

.empty__title, .notice__title, .errorstate__title {
  font-size: 16px; font-weight: 700; letter-spacing: -.2px; line-height: 1.3;
  margin-bottom: 6px;
}
.empty__sub, .notice__body, .errorstate__body {
  color: var(--muted); font-size: 13px; line-height: 1.55; max-width: 32ch;
}
.empty__actions { display: flex; flex-direction: column; gap: 8px; margin-top: 18px; min-width: 190px; }

.errorstate__actions { display: flex; gap: 8px; margin-top: 18px; }
/* Support detail, never the headline. Small, dim, monospace, and last in reading order. */
.errorstate__code {
  margin-top: 14px;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .3px;
  color: var(--dim);
}

/* The honest-unavailability panel. Deliberately calm rather than alarming: a deferred feature
 * is a plan, not an error, and it must not read as a crash. */
.blocked {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  background: var(--panel); border: 1px dashed rgba(255, 180, 84, .35);
  border-radius: var(--r-lg); padding: 22px 18px;
}
.blocked__badge {
  margin-bottom: 10px; padding: 3px 10px; border-radius: 999px;
  background: rgba(255, 180, 84, .14); color: var(--warn);
  font-size: 10.5px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
}
.blocked__title { font-size: 16px; font-weight: 700; letter-spacing: -.2px; margin-bottom: 8px; }
.blocked__note { font-size: 12.5px; color: var(--muted); line-height: 1.6; max-width: 42ch; }
/* The API's own blocked_by. Small print under the explanation — it identifies the gate for
 * support, it does not explain anything to the reader. */
.blocked__reason {
  order: 5; margin-top: 12px;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .3px;
  color: var(--dim); word-break: break-word;
}

.note { border-radius: var(--r-md); padding: 11px 13px; font-size: 12.5px; line-height: 1.5; }
.note--info   { background: var(--accent-dim); color: var(--accent-soft); }
.note--warn   { background: rgba(255, 180, 84, .1); color: var(--warn); }
.note--muted  { background: var(--panel); color: var(--muted); }
.note__title  { font-weight: 650; margin-bottom: 3px; }
.note__sub    { opacity: .82; }

/* ── rows, fields, lists ───────────────────────────────────────────────────── */

.copyrow, .credrow {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--panel-line);
}
.copyrow:last-child, .credrow:last-child { border-bottom: 0; }
.copyrow__label, .credrow__label { color: var(--muted); font-size: 12px; flex: 0 0 76px; }
.copyrow__value, .credrow__value {
  flex: 1 1 auto; min-width: 0;
  font-family: var(--mono); font-size: 12px; word-break: break-all;
}
.credrow__value--masked { letter-spacing: 2px; color: var(--muted); }
.credrow__actions { flex: 0 0 auto; display: flex; gap: 6px; }
.copyrow__btn, .credrow__btn, .credrow__toggle, .connstr__btn {
  flex: 0 0 auto;
  background: var(--panel-strong); color: var(--accent);
  border-radius: var(--r-sm); padding: 6px 10px;
  font-size: 11.5px; font-weight: 650; white-space: nowrap;
}
.copyrow__btn:active, .credrow__btn:active, .credrow__toggle:active, .connstr__btn:active {
  background: var(--accent-dim);
}

/* A connection string is what people actually paste, and it is far too long for a single-line
 * row — it gets a block of its own with a full-width value and a thumb-sized copy control. */
.conn { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.connstr { background: rgba(0, 0, 0, .22); border-radius: var(--r-md); padding: 10px 12px; }
.connstr__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.connstr__label { font-size: 11.5px; font-weight: 650; color: var(--muted); min-width: 0; }
.connstr__value {
  font-family: var(--mono); font-size: 11.5px; line-height: 1.5;
  color: var(--text); word-break: break-all;
}

.field { display: flex; flex-direction: column; gap: 6px; }
.field__label { font-size: 12px; font-weight: 650; color: var(--muted); }
.field__hint { font-size: 11.5px; color: var(--dim); line-height: 1.5; }
.field__control {
  width: 100%;
  background: rgba(0, 0, 0, .28); color: var(--text);
  border: 1px solid var(--panel-line); border-radius: var(--r-md);
  padding: 10px 12px; font-size: 13px;
}
.field__control:focus { outline: none; border-color: var(--accent); }
/* -webkit-text-fill-color: iOS repaints a disabled control's text with its own grey otherwise,
 * and the parser's preview is made entirely of disabled controls. */
.field__control:disabled { opacity: .55; cursor: not-allowed; -webkit-text-fill-color: currentColor; }
.field__control--area {
  min-height: 92px; resize: vertical;
  font-family: var(--mono); font-size: 12px; line-height: 1.5;
}
.field__control--select { appearance: none; padding-right: 30px; }

.chipset { display: flex; flex-wrap: wrap; gap: 8px; }
.chipset__chip {
  display: flex; align-items: center; gap: 6px;
  background: var(--panel); border: 1px solid var(--panel-line); border-radius: var(--r-md);
  padding: 8px 11px; color: var(--text); font-size: 12.5px;
}
.chipset__chip--on { border-color: var(--accent); background: var(--accent-dim); color: var(--accent); }
.chipset__icon { font-size: 14px; line-height: 1; }
.chipset__label { font-weight: 600; }
.chipset__desc { color: var(--muted); font-size: 11.5px; }

.navlist { background: var(--panel); border: 1px solid var(--panel-line); border-radius: var(--r-lg); overflow: hidden; }
.navlist__item {
  display: flex; align-items: center; gap: 12px; width: 100%;
  border-bottom: 1px solid var(--panel-line);
  color: var(--text); padding: 13px 14px; min-height: 56px;
}
.navlist__item:last-child { border-bottom: 0; }
.navlist__item:active { background: var(--panel-strong); }
.navlist__item--external .navlist__chevron { color: var(--accent); }
.navlist__icon {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--accent-dim); color: var(--accent);
}
.navlist__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
/* The badge sits on the label's own line, not at the row's right edge: at 320px a right-aligned
 * "Coming soon" pill squeezes the label into an ellipsis, and the label is what has to survive. */
.navlist__labelrow { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.navlist__label { font-size: 13.5px; font-weight: 650; }
.navlist__badge {
  padding: 2px 7px; border-radius: 999px;
  background: rgba(255, 180, 84, .13); color: var(--warn);
  font-size: 9.5px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
  white-space: nowrap;
}
.navlist__sub { font-size: 11.5px; color: var(--muted); line-height: 1.45; }
.navlist__chevron { flex: 0 0 auto; margin-left: auto; color: var(--dim); font-size: 15px; }

.factlist, .speclist {
  background: var(--panel); border: 1px solid var(--panel-line);
  border-radius: var(--r-lg); padding: 2px 14px;
}
.factlist__item {
  display: flex; flex-direction: column; gap: 4px;
  padding: 13px 0; border-bottom: 1px solid var(--panel-line);
}
.factlist__item:last-child { border-bottom: 0; }
.factlist__label { font-size: 13px; font-weight: 650; line-height: 1.4; }
.factlist__body { font-size: 12.5px; color: var(--muted); line-height: 1.6; }

.speclist__row {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  padding: 11px 0; border-bottom: 1px solid var(--panel-line);
}
.speclist__row:last-child { border-bottom: 0; }
.speclist__label { flex: 0 0 auto; color: var(--muted); font-size: 12.5px; padding-top: 1px; }
.speclist__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; align-items: flex-end; }
.speclist__value { font-weight: 600; font-size: 13px; text-align: right; }
.speclist__value--pending { color: var(--dim); font-weight: 500; font-style: italic; }
.speclist__hint { font-size: 11.5px; color: var(--dim); text-align: right; line-height: 1.45; }

/* ── home: welcome (the zero-access primary state) ─────────────────────────── */

.welcome { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 12px 0 0; }
.welcome__mark {
  width: 78px; height: 78px; display: grid; place-items: center; margin-bottom: 14px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 45%, rgba(0, 229, 255, .16), rgba(0, 229, 255, 0) 70%);
}
.welcome__title { font-size: 22px; font-weight: 800; letter-spacing: -.6px; line-height: 1.2; margin-bottom: 9px; }
.welcome__body { font-size: 13px; color: var(--muted); line-height: 1.6; max-width: 34ch; margin-bottom: 20px; }
.welcome__actions { display: flex; flex-direction: column; gap: 9px; width: 100%; margin-bottom: 24px; }
.welcome__facts-title {
  align-self: stretch; text-align: left; margin-bottom: 10px;
  font-size: 12px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--dim);
}
.welcome__facts {
  width: 100%;
  background: var(--panel); border: 1px solid var(--panel-line); border-radius: var(--r-lg);
}

.fact {
  display: flex; align-items: flex-start; gap: 11px; text-align: left;
  padding: 12px 13px; border-bottom: 1px solid var(--panel-line);
}
.fact:last-child { border-bottom: 0; }
.fact__icon {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 9px;
  display: grid; place-items: center;
  background: var(--accent-dim); color: var(--accent);
}
.fact__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.fact__title { font-size: 13px; font-weight: 650; line-height: 1.35; }
.fact__sub { font-size: 11.5px; color: var(--muted); line-height: 1.5; overflow-wrap: anywhere; }
.fact__flags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.fact__flag { font-size: 15px; line-height: 1; }

/* ── home: hero, low-traffic strip, compact list ───────────────────────────── */

.hero, .summary { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 8px 0 4px; }
.hero__head, .summary__head { display: flex; align-items: center; justify-content: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
/* Two different things despite the shared shape. Home's is a caption over an aggregate; the
 * detail screen's is the access's own name, which is the card's title and must not be dressed
 * as small print. */
.hero__label {
  font-size: 11.5px; letter-spacing: .5px; text-transform: uppercase; color: var(--dim);
}
.summary__label {
  max-width: 100%; min-width: 0;
  font-size: 13.5px; font-weight: 650; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hero__figure, .summary__figure { display: flex; align-items: baseline; justify-content: center; gap: 6px; }
.hero__value, .summary__value { font-size: 42px; font-weight: 700; letter-spacing: -1.4px; line-height: 1; }
.hero__unit, .summary__unit { font-size: 17px; font-weight: 650; color: var(--muted); }
/* The V3.1 product rule: the sum is a display aggregate, NOT a shared pool. */
.hero__sub, .summary__meta { margin-top: 10px; font-size: 12px; color: var(--muted); line-height: 1.45; }
.summary__rule { margin-top: 6px; font-size: 11.5px; color: var(--dim); line-height: 1.45; }

.lowstrip {
  background: rgba(255, 180, 84, .09); border: 1px solid rgba(255, 180, 84, .22);
  border-radius: var(--r-md); padding: 11px 13px;
}
.lowstrip__title { font-size: 12.5px; font-weight: 650; color: var(--warn); margin-bottom: 8px; }
.lowstrip__list { display: flex; flex-direction: column; gap: 2px; }
.lowstrip__item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 6px 0; min-height: 36px;
}
.lowstrip__item:active { opacity: .65; }
.lowstrip__main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.lowstrip__label { font-size: 12.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lowstrip__id { font-family: var(--mono); font-size: 10.5px; color: var(--dim); }
.lowstrip__value { flex: 0 0 auto; font-size: 12px; color: var(--warn); font-weight: 650; }

.access-mini {
  display: flex; align-items: center; gap: 10px; width: 100%;
  color: var(--text); padding: 11px 0; min-height: 52px;
  border-bottom: 1px solid var(--panel-line);
}
.access-mini:last-child { border-bottom: 0; }
.access-mini:active { opacity: .65; }
.access-mini__main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.access-mini__label { font-size: 13px; font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.access-mini__meta { font-size: 11.5px; color: var(--muted); }
.access-mini__chevron { flex: 0 0 auto; color: var(--dim); font-size: 16px; }

.home__actions { display: flex; flex-direction: column; gap: 10px; }

/* ── accesses ──────────────────────────────────────────────────────────────── */

.access-row {
  display: flex; flex-direction: column; gap: 9px; width: 100%;
  background: var(--panel); border: 1px solid var(--panel-line); border-radius: var(--r-lg);
  color: var(--text); padding: 13px 14px;
}
.access-row:active { background: var(--panel-strong); }
.access-row__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
/* The label is the row's name, not its metadata — it stays at full contrast. */
.access-row__label {
  flex: 1 1 auto; min-width: 0;
  font-size: 13.5px; font-weight: 650;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.access-row__meta { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.access-row__left { font-size: 12.5px; color: var(--muted); min-width: 0; }
.access-row__pkg {
  flex: 0 0 auto;
  font-size: 10.5px; font-weight: 700; letter-spacing: .3px; text-transform: uppercase;
  color: var(--accent);
}
.access-row__bar { display: block; width: 100%; }
.access-row__foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.access-row__speed { font-size: 11.5px; color: var(--accent); font-weight: 600; }
.access-row__chevron { flex: 0 0 auto; color: var(--dim); font-size: 16px; }

/* ── access detail ─────────────────────────────────────────────────────────── */

.pool { display: flex; flex-direction: column; margin-top: 10px; }
.pool__row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--panel-line); }
.pool__row:last-child { border-bottom: 0; }
.pool__label { color: var(--muted); font-size: 12.5px; flex: 0 0 auto; }
.pool__value { font-weight: 600; font-size: 13px; text-align: right; min-width: 0; overflow-wrap: anywhere; }
.pool__hint { font-size: 11.5px; color: var(--dim); padding-top: 10px; }

.usage { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
/* Not 26px: this line is a percentage in the common case but a full sentence when there is no
 * package to measure against, and a sentence set at hero size wraps to four lines on a 320px
 * phone. 20px keeps both readings on the same visual footing. */
.usage__percent { font-size: 20px; font-weight: 700; letter-spacing: -.4px; line-height: 1.25; }
.usage__counters { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.usage__counter { background: rgba(0, 0, 0, .22); border-radius: var(--r-md); padding: 10px 12px; min-width: 0; }
.usage__counter-label { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: .4px; }
.usage__counter-value { font-size: 14px; font-weight: 650; margin-top: 3px; }

/* ── tools hub ─────────────────────────────────────────────────────────────── */

.tools__lead { font-size: 13px; color: var(--muted); line-height: 1.55; }
.tools__free { font-size: 12.5px; color: var(--ok); line-height: 1.55; }
.tools__list { display: flex; flex-direction: column; gap: 10px; }

.toolcard {
  display: flex; align-items: flex-start; gap: 12px; width: 100%;
  background: var(--panel); border: 1px solid var(--panel-line); border-radius: var(--r-lg);
  color: var(--text); padding: 13px 14px;
}
.toolcard:active { background: var(--panel-strong); }
.toolcard__icon {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 11px;
  display: grid; place-items: center;
}
.toolcard--checker .toolcard__icon { background: var(--accent-dim); color: var(--accent); }
/* The parser is gated, and its icon says so before the badge is read. */
.toolcard--parser .toolcard__icon { background: rgba(255, 180, 84, .12); color: var(--warn); }
.toolcard__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.toolcard__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.toolcard__title { font-size: 14px; font-weight: 650; }
.toolcard__badge {
  padding: 2px 7px; border-radius: 999px;
  background: rgba(255, 180, 84, .13); color: var(--warn);
  font-size: 9.5px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
  white-space: nowrap;
}
.toolcard__sub { font-size: 11.5px; color: var(--muted); line-height: 1.5; }
.toolcard__cap { font-size: 11px; color: var(--dim); margin-top: 2px; }
.toolcard__chevron { flex: 0 0 auto; align-self: center; color: var(--dim); }

/* ── checker ───────────────────────────────────────────────────────────────── */

.checker__input { width: 100%; min-height: 132px; }
.checker__meta { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-top: 8px; }
.checker__cap { font-size: 11.5px; color: var(--dim); }
.checker__count { font-size: 12px; font-weight: 600; color: var(--muted); margin-left: auto; }
/* Over the cap the request will be REJECTED, not trimmed — the count says so before the
 * blocker below explains how many lines to remove. */
.checker__count--over { color: var(--danger); }
.checker__blocker {
  margin-top: 10px; border-radius: var(--r-md); padding: 10px 12px;
  background: rgba(255, 107, 107, .1); color: var(--danger);
  font-size: 12px; line-height: 1.5;
}
.checker__controls { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; }
.checker__proto { display: flex; gap: 6px; }
.checker__proto-btn {
  background: var(--panel); border: 1px solid var(--panel-line); border-radius: var(--r-sm);
  padding: 9px 12px; min-height: 40px;
  color: var(--muted); font-size: 12px; font-weight: 600;
}
.checker__proto-btn--on { border-color: var(--accent); background: var(--accent-dim); color: var(--accent); }

.checker__results { display: flex; flex-direction: column; gap: 12px; }
.checker__summary { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.checker__summary-count { font-size: 12.5px; font-weight: 650; }
.checker__summary-count--alive { color: var(--ok); }
.checker__summary-count--dead { color: var(--danger); }
.checker__summary-actions { display: flex; gap: 6px; margin-left: auto; }
.checker__summary-actions .btn { padding: 8px 12px; min-height: 38px; font-size: 12px; }

.checker__group { display: flex; flex-direction: column; gap: 7px; }
.checker__group-title {
  display: flex; align-items: center; gap: 7px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
  color: var(--dim);
}
.checker__group--alive .checker__group-title { color: var(--ok); }
.checker__group--dead .checker__group-title { color: var(--danger); }
.checker__group-count {
  padding: 1px 7px; border-radius: 999px; background: var(--panel-strong);
  font-size: 10.5px; color: var(--muted); letter-spacing: 0;
}
.checker__group .card { padding: 4px 12px; }

.checker__row { padding: 10px 0; border-bottom: 1px solid var(--panel-line); }
.checker__row:last-child { border-bottom: 0; }
.checker__row--alive, .checker__row--dead { padding-left: 10px; }
.checker__row--alive { box-shadow: inset 2px 0 0 var(--ok); }
.checker__row--dead { box-shadow: inset 2px 0 0 var(--danger); }
.checker__row-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.checker__row-note { font-size: 11.5px; color: var(--muted); margin-top: 5px; }
.checker__line { font-family: var(--mono); font-size: 12px; min-width: 0; word-break: break-all; }
.checker__status {
  flex: 0 0 auto;
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .3px;
  color: var(--muted);
}
.checker__status--alive   { color: var(--ok); }
.checker__status--dead    { color: var(--danger); }
.checker__status--invalid { color: var(--warn); }
.checker__cols { display: flex; gap: 14px; margin-top: 6px; flex-wrap: wrap; }
.checker__col { display: flex; gap: 5px; align-items: baseline; min-width: 0; }
.checker__col-label { font-size: 10.5px; color: var(--dim); text-transform: uppercase; letter-spacing: .3px; }
.checker__col-value { font-size: 12px; font-weight: 600; overflow-wrap: anywhere; }

/* ── buy ───────────────────────────────────────────────────────────────────── */

.buy__blocked { display: flex; flex-direction: column; gap: 10px; }
.buy__lead { font-size: 13px; color: var(--muted); line-height: 1.55; }
.buy__packages { display: flex; flex-direction: column; gap: 8px; }
.buy__actions { display: flex; flex-direction: column; gap: 8px; }

.pkg {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--panel); border: 1px solid var(--panel-line); border-radius: var(--r-lg);
  padding: 13px 14px;
}
.pkg--unlimited { border-color: rgba(0, 229, 255, .28); }
.pkg__main { flex: 1 1 auto; min-width: 0; }
.pkg__title { font-size: 14px; font-weight: 650; }
.pkg__sub { font-size: 11.5px; color: var(--muted); margin-top: 2px; overflow-wrap: anywhere; }
.pkg__price { flex: 0 0 auto; text-align: right; }
/* Muted, not accent: this figure is a historical constant, and an accent-coloured number on a
 * catalogue card reads as the price you are about to pay. */
.pkg__price-amount { font-size: 14px; font-weight: 700; color: var(--muted); }
.pkg__price-amount--none { color: var(--dim); }
/* "REFERENCE ONLY" is the only thing stopping the number above from reading as a live price. */
.pkg__price-tag {
  display: block; margin-top: 2px;
  font-size: 9.5px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
  color: var(--dim);
}

/* ── profile ───────────────────────────────────────────────────────────────── */

.profile__head { display: flex; align-items: center; gap: 13px; }
.profile__avatar {
  flex: 0 0 auto; width: 52px; height: 52px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-dim); color: var(--accent);
  font-size: 21px; font-weight: 700;
}
.profile__ident { min-width: 0; }
.profile__name { font-size: 16px; font-weight: 700; letter-spacing: -.2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.profile__handle { font-size: 13px; color: var(--accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.profile__auth { display: flex; align-items: center; gap: 5px; margin-top: 4px; }
.profile__auth-icon { display: grid; place-items: center; color: var(--muted); }
.profile__auth-text { font-size: 11.5px; color: var(--muted); }
.profile__stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-top: 14px; }
.profile__stat { background: rgba(0, 0, 0, .22); border-radius: var(--r-md); padding: 11px 13px; min-width: 0; }
.profile__stat-value { font-size: 16px; font-weight: 700; }
.profile__stat-label { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: .4px; margin-top: 3px; }
/* Activity is empty by construction in this phase, so this section spends most of its life
 * holding an empty state. A dashed frame gives that state a bounded home instead of leaving it
 * floating on the background, and it does not fight the skeleton the way a filled panel would. */
.profile__activity {
  display: flex; flex-direction: column;
  border: 1px dashed var(--panel-line); border-radius: var(--r-lg);
}
.profile__activity .empty, .profile__activity .notice { padding: 24px 16px; }
.profile__activity .skeleton { padding: 12px; }
/* :has() is progressive — where it is unsupported the whole rule drops and the neutral frame
 * above stands, which is the correct fallback rather than a broken one. */
.profile__activity:has(.errorstate) { border-color: rgba(255, 107, 107, .25); }
/* Small print, not content: the one string support can ask for. */
.profile__support {
  text-align: center; font-family: var(--mono); font-size: 10.5px;
  color: var(--dim); word-break: break-all; padding: 2px 0 4px;
}

.legal { display: flex; flex-wrap: wrap; gap: 10px 16px; justify-content: center; padding: 6px 0 2px; }
.legal__link { font-size: 11.5px; color: var(--dim); }
.legal__link:hover { color: var(--muted); }

/* ── buy: selectable cards, confirmation, outcome ──────────────────────────── */

/* The card is a real control now, so it gets real affordances. It was a <div> while nothing
 * could be bought — a selectable-looking card that does nothing is a worse lie than a plain one. */
.pkg--selectable {
  width: 100%; text-align: left; cursor: pointer;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  transition: transform .08s ease, border-color .12s ease;
}
.pkg--selectable:active { transform: scale(.985); }
.pkg--selectable:disabled { cursor: default; opacity: .72; }
.pkg--selectable:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.confirm { gap: 12px; }
.purchase-done { gap: 12px; }

.confirm__pkg {
  font-size: 26px; font-weight: 720; letter-spacing: -.02em; line-height: 1.15;
}
/* Price and balance as a definition list: the pairing IS the content of this screen, and a
 * <dl> says "these labels belong to these values" without needing a table. */
.confirm__figures {
  display: grid; grid-template-columns: 1fr auto; gap: 6px 16px; margin: 14px 0 2px;
}
.confirm__figures dt { font-size: 13px; font-weight: 600; color: var(--muted); }
.confirm__figures dd {
  margin: 0; text-align: right; font-size: 15px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.confirm__price { font-size: 17px; }
.confirm__balance { color: var(--muted); }

.purchase-done__title { font-size: 20px; font-weight: 720; letter-spacing: -.01em; }
.purchase-done__what { margin-top: 6px; font-size: 14px; font-weight: 600; line-height: 1.5; }
/* Support detail, collapsed. An operation id on the success screen reads as something the
 * customer is supposed to act on. */
.purchase-done__details { margin-top: 10px; }
.purchase-done__details summary {
  font-size: 12.5px; font-weight: 650; color: var(--muted); cursor: pointer;
}

/* ── parser / referral / wallet (deferred screens) ─────────────────────────── */

/* TWO BALANCES, TWO TREATMENTS. The money figure and the traffic figure sit in separate
 * sections with separate headings, and they are styled as siblings rather than as a total and
 * its breakdown — a shared visual weight is how two unrelated numbers start reading as one. */
.wallet__money { text-align: center; padding: 6px 0 2px; }
.wallet__money-amount {
  font-size: 30px; font-weight: 720; line-height: 1.15; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.wallet__money-label { margin-top: 3px; font-size: 12.5px; font-weight: 600; color: var(--muted); }
/* The "Top up balance" action under the money card. Same stack as .buy__actions, so the button
   sits identically on both screens that offer it. */
.wallet__actions { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }

/* Deliberately NOT the size of the amount above. This is a sentence, not a figure, and giving it
 * headline weight would make an absent balance look like a reported one. */
.wallet__money-unavailable {
  text-align: center; padding: 8px 0 4px;
  font-size: 15px; font-weight: 650; color: var(--muted);
}

/* The traffic figure: what this product meters. Its own section, below the money block, so the
 * two can never be read as one total. */
.wallet__traffic { text-align: center; padding: 6px 0 2px; }
.wallet__traffic-total {
  font-size: 30px; font-weight: 720; line-height: 1.15; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.wallet__traffic-label { margin-top: 3px; font-size: 12.5px; font-weight: 600; color: var(--muted); }

.parser__lead { font-size: 13.5px; font-weight: 650; line-height: 1.5; margin-bottom: 6px; }
.parser__flags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.parser__flag {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--panel-strong); border-radius: 999px; padding: 5px 11px;
  font-size: 11.5px; font-weight: 600; color: var(--muted); white-space: nowrap;
}
.parser__flag-icon { display: grid; place-items: center; color: var(--accent); }

/* The disabled design preview: visible so the intent is legible, unmistakably inert so nobody
 * mistakes it for a working control. */
.preview { position: relative; opacity: .62; pointer-events: none; filter: saturate(.6); }
/* A banner rather than a corner pill: the sentence is far too long to float over the first
 * field at 320px, and it is the most important thing on the card. */
.preview__badge {
  display: block; margin: -2px 0 12px; padding: 7px 10px;
  border-radius: var(--r-sm); background: rgba(255, 180, 84, .12); color: var(--warn);
  font-size: 10px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
  text-align: center; line-height: 1.4;
}
.preview__grid { display: flex; flex-direction: column; gap: 14px; }

/* ── toasts + sheets ───────────────────────────────────────────────────────── */

.toasts {
  position: fixed; top: calc(var(--topbar-h) + env(safe-area-inset-top) + 8px);
  left: 50%; transform: translateX(-50%); z-index: 70;
  display: flex; flex-direction: column; gap: 6px;
  width: min(var(--col), 100%); padding: 0 14px; pointer-events: none;
}
.toast {
  background: rgba(20, 26, 38, .97); border: 1px solid var(--panel-line);
  border-radius: var(--r-md); padding: 9px 13px;
  font-size: 12.5px; text-align: center;
  animation: toastIn .18s ease both; box-shadow: 0 6px 22px rgba(0, 0, 0, .45);
}
.toast--info  { color: var(--text); }
.toast--ok    { color: var(--ok); }
.toast--error { color: var(--danger); }
.toast--warn  { color: var(--warn); }
.toast--out   { opacity: 0; transition: opacity .2s ease; }

.sheet-backdrop {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(0, 0, 0, .6);
  display: flex; align-items: flex-end; justify-content: center;
}
.sheet {
  width: 100%; max-width: var(--col); max-height: 86dvh;
  display: flex; flex-direction: column;
  background: #0f1420; border-radius: var(--r-lg) var(--r-lg) 0 0;
  animation: sheetUp .24s ease both;
  padding-bottom: env(safe-area-inset-bottom);
}
.sheet__head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 15px 16px 11px; border-bottom: 1px solid var(--panel-line);
}
.sheet__title { font-size: 15px; font-weight: 650; }
.sheet__close { color: var(--muted); font-size: 15px; padding: 8px; margin: -8px; }
.sheet__body { padding: 15px 16px 22px; overflow-y: auto; }

/* ── narrow viewports ──────────────────────────────────────────────────────── */
/* 320px is the floor (iPhone SE 1st gen / Android small). Only the two places where fixed
 * padding actually costs readable width give any of it back. */
@media (max-width: 359px) {
  .screen { padding-left: 11px; padding-right: 11px; }
  .card { padding: 12px; }
  .hero__value, .summary__value { font-size: 36px; letter-spacing: -1.1px; }
  .welcome__title { font-size: 20px; }
  .tab__label { font-size: 9.5px; letter-spacing: 0; }
  .copyrow__label, .credrow__label { flex-basis: 62px; }
}

/* ── wide viewports ────────────────────────────────────────────────────────── */
/* Telegram Desktop renders the Mini App in a narrow panel, but the dev server is opened in a
 * normal browser. Keep the phone column and give it an edge so it reads as a device rather than
 * a broken full-width page. */
@media (min-width: 430px) {
  .app { border-left: 1px solid var(--panel-line); border-right: 1px solid var(--panel-line); }
  .tabbar { border-left: 1px solid var(--panel-line); border-right: 1px solid var(--panel-line); }
}

/* ── Pool settings: tappable rows and their pickers ───────────────────────────
   A tappable row is a <button>, so it gets the same 44px target and focus ring
   as every other control rather than a div pretending to be one. */
.pool__row--tappable {
  display: flex; align-items: center; gap: 8px; width: 100%;
  background: none; border: 0; padding: 9px 0; margin: 0; text-align: left;
  color: inherit; font: inherit; cursor: pointer; min-height: 44px;
}
.pool__row--tappable:active { opacity: .6; }
.pool__chevron { color: var(--muted); font-size: 17px; line-height: 1; margin-left: 2px; }
.pool__row--tappable .pool__value { margin-left: auto; }

.picker { display: flex; flex-direction: column; }
.picker__row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; min-height: 46px; padding: 10px 2px; margin: 0;
  background: none; border: 0; border-bottom: 1px solid var(--panel-line);
  color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.picker__row:last-child { border-bottom: 0; }
.picker__row:active { opacity: .6; }
.picker__row--on { font-weight: 640; }
.picker__tick { color: var(--accent, currentColor); font-size: 15px; }
.picker__sub { display: block; font-size: 12px; color: var(--muted); font-weight: 400; margin-top: 1px; }

/* ══════════════════════════════════════════════════════════════════════════════
 * V3 VISUAL RESTORATION
 *
 * The screens were built correct and flat: one grey surface, accent reserved for buttons, every
 * number the same weight. v3's language is the opposite — tinted surfaces, one dominant figure
 * per screen, and cyan→purple used to point at it. These rules restore that WITHOUT touching a
 * single line of screen logic: they are all overrides on classes the screens already emit.
 * ═════════════════════════════════════════════════════════════════════════════ */

/* ── the hero figure: the one number a screen is about ── */
.hero__value,
.summary__value {
  background: var(--gradient-primary);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* A gradient on text loses the glow, so it is cast behind rather than on the glyphs. */
  filter: drop-shadow(0 0 18px rgba(0, 229, 255, .20));
  letter-spacing: -.03em;
}
.summary__value { font-size: 40px; font-weight: 760; line-height: 1.05; }
.summary__unit  { color: var(--text-secondary); font-weight: 600; }

/* The card carrying the hero gets a tinted wash instead of the same grey as everything else. */
.screen-home > .card:first-child,
.screen-detail > .card:first-child {
  background: var(--gradient-wash-soft), var(--surface);
  border: 1px solid rgba(0, 229, 255, .10);
  box-shadow: var(--shadow-card);
}

/* ── progress: a real gradient track, not a grey bar ── */
.progress__fill,
.bar__fill {
  background: var(--gradient-track);
  box-shadow: var(--shadow-cyan-sm);
}
.progress, .bar { background: rgba(255, 255, 255, .05); }

/* ── primary CTA: the gradient the reference uses for its one strong action ── */
.btn--primary {
  background: var(--gradient-primary);
  color: #04121a;
  font-weight: 700;
  border: 0;
  box-shadow: var(--shadow-cyan);
}
.btn--primary:active { filter: brightness(.94); }
.btn--secondary {
  background: var(--surface-elevated);
  border: 1px solid rgba(0, 229, 255, .18);
  color: var(--cyan);
}

/* ── package cards: a chosen package should look chosen ── */
.pkg { border: 1px solid var(--surface-line); background: var(--surface); transition: border-color .15s, background .15s; }
.pkg--selectable:active { background: var(--surface-elevated); }
.pkg--unlimited {
  background: var(--gradient-wash), var(--surface);
  border-color: rgba(124, 58, 237, .28);
}
.pkg__price-amount { color: var(--cyan); font-weight: 700; }
.pkg--unlimited .pkg__price-amount { color: var(--purple-soft); }

/* ── the wallet figure ── */
.wallet__money-amount {
  background: var(--gradient-primary);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 16px rgba(0, 229, 255, .18));
}

/* ── pool settings: a premium settings surface, not an admin form ── */
.pool__row--tappable { border-bottom: 1px solid var(--surface-line); }
.pool__row--tappable:last-of-type { border-bottom: 0; }
.pool__value { color: var(--text-secondary); font-weight: 600; }
.pool__chevron { color: var(--cyan); opacity: .55; }

/* ── segmented control: the v3 rotation selector ── */
.seg {
  display: flex; gap: 4px; padding: 4px;
  background: var(--surface-soft);
  border: 1px solid var(--surface-line);
  border-radius: var(--radius-md);
}
.seg__btn {
  flex: 1 1 0; min-height: 38px; padding: 8px 6px; border: 0; border-radius: 10px;
  background: transparent; color: var(--text-muted);
  font: inherit; font-size: 13px; font-weight: 640; cursor: pointer;
  transition: background .15s, color .15s, box-shadow .15s;
}
.seg__btn--on {
  background: var(--gradient-primary);
  color: #04121a;
  box-shadow: var(--shadow-cyan-sm);
}
.seg__btn:not(.seg__btn--on):active { background: var(--surface-elevated); color: var(--text-secondary); }

/* ── the picker sheet ── */
.picker__row--on { color: var(--cyan); }
.picker__tick { color: var(--cyan); }

/* ── chips and status ── */
.chip--accent {
  background: var(--surface-cyan);
  border: 1px solid rgba(0, 229, 255, .22);
  color: var(--cyan);
}

/* ── section headings: hierarchy, so a screen reads as sections not a list ── */
.section__title { color: var(--text-primary); font-weight: 700; letter-spacing: -.01em; }
.muted { color: var(--text-muted); }

/* ── welcome / NO_ACCESS: the strongest first impression in the app ── */
.welcome__title {
  background: var(--gradient-primary);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  font-weight: 780; letter-spacing: -.02em;
}
.welcome__facts .factlist__label,
.welcome__facts li > div:first-child { color: var(--text-primary); font-weight: 660; }

/* Reduced motion already disables transitions globally; nothing here animates on its own. */

/* The rotation block: a labelled segmented control with its own explanation. */
.pool__block { display: flex; flex-direction: column; gap: 8px; padding: 10px 0; }
.pool__block .pool__label { color: var(--text-muted); font-size: 12.5px; font-weight: 600; }
.seg--amounts .seg__btn { font-variant-numeric: tabular-nums; }
.pool__note { color: var(--text-muted); font-size: 12.5px; line-height: 1.45; }

/* ── Fraud score sheet: V3, not a browser range input ───────────────────────── */
.fraud { display: flex; flex-direction: column; gap: 16px; }
.fraud__state { display: flex; flex-direction: column; gap: 10px; }
.fraud__title { font-size: 15px; font-weight: 700; color: var(--text-primary); }

.fraud__bands { display: flex; flex-direction: column; gap: 8px; }
.fraud__band { display: grid; grid-template-columns: 1fr 48px 44px; align-items: center; gap: 10px; }
.fraud__band-bar { height: 8px; border-radius: 999px; background: rgba(255,255,255,.06); overflow: hidden; }
.fraud__band-fill { height: 100%; border-radius: 999px; }
.fraud__band-fill--ok   { background: linear-gradient(90deg, #34d399, #00E5FF); }
.fraud__band-fill--warn { background: linear-gradient(90deg, #00E5FF, #7C3AED); }
.fraud__band-fill--bad  { background: linear-gradient(90deg, #7C3AED, #f87171); }
.fraud__band-label { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.fraud__band-count { font-size: 12.5px; color: var(--text-secondary); text-align: right; font-variant-numeric: tabular-nums; }

.fraud__pick { display: flex; flex-direction: column; gap: 8px; }
.fraud__label { font-size: 12.5px; font-weight: 600; color: var(--text-muted); }
.fraud__value {
  font-size: 30px; font-weight: 760; letter-spacing: -.02em; font-variant-numeric: tabular-nums;
  background: var(--gradient-primary); -webkit-background-clip: text; background-clip: text;
  color: transparent; filter: drop-shadow(0 0 14px rgba(0,229,255,.18));
}
/* The native track/thumb repainted so the control belongs to the design rather than the OS. */
.fraud__range { -webkit-appearance: none; appearance: none; width: 100%; height: 28px; background: transparent; }
.fraud__range::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px; background: var(--gradient-track); opacity: .9;
}
.fraud__range::-moz-range-track { height: 6px; border-radius: 999px; background: var(--gradient-track); }
.fraud__range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 22px; height: 22px; margin-top: -8px;
  border-radius: 50%; background: #fff; border: 2px solid var(--cyan); box-shadow: var(--shadow-cyan-sm);
}
.fraud__range::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%; background: #fff;
  border: 2px solid var(--cyan); box-shadow: var(--shadow-cyan-sm);
}
.fraud__actions { display: flex; flex-direction: column; gap: 8px; }

/* ── Traffic usage by day: V3, not an enterprise dashboard ───────────────────── */
.hist { display: flex; flex-direction: column; gap: 12px; }
.hist__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.hist__range { padding: 3px; flex: 0 0 auto; }
.hist__range .seg__btn { min-height: 30px; font-size: 12px; padding: 5px 10px; }

.hist__total { display: flex; align-items: baseline; gap: 8px; }
.hist__total-value {
  font-size: 26px; font-weight: 740; letter-spacing: -.02em; font-variant-numeric: tabular-nums;
  background: var(--gradient-primary); -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.hist__total-label { font-size: 12.5px; color: var(--text-muted); }

.hist__chart { display: flex; align-items: flex-end; gap: 4px; height: 96px; }
.hist__chart--d30 { gap: 2px; }
.hist__col { flex: 1 1 0; height: 100%; display: flex; align-items: flex-end; }
.hist__bar-track { width: 100%; height: 100%; display: flex; align-items: flex-end; }
.hist__bar {
  width: 100%; border-radius: 3px 3px 2px 2px;
  background: var(--gradient-track);
  box-shadow: 0 0 8px rgba(0, 229, 255, .18);
}
/* A day with no usage still gets a tick, so the axis reads as a calendar rather than a gap. */
.hist__bar--zero { background: rgba(255, 255, 255, .10); box-shadow: none; }

.hist__axis { display: flex; justify-content: space-between; font-size: 11.5px; color: var(--dim); font-variant-numeric: tabular-nums; }
.hist__empty { display: flex; flex-direction: column; gap: 4px; padding: 6px 0 2px; }
.hist__empty-title { font-size: 14px; font-weight: 660; color: var(--text-secondary); }

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   V3 POLISH — the pass after the owner saw the build and called it dry.
   ═══════════════════════════════════════════════════════════════════════════════════════════

   NO NEW UX. Nothing here moves a control, changes the navigation or adds a screen. It is depth,
   hierarchy and accent distribution over the components that already exist — which is the whole
   brief, and also the reason it is one appended block rather than edits scattered through 1200
   lines: everything the polish changed is legible in one place, and revertible in one place.

   THE DIAGNOSIS was not "not enough colour". It was that every surface sat at the same elevation
   and every number at the same weight, so a screen full of real data read as a screen full of
   grey boxes. The fixes are in that order: elevation, then weight, then accent — accent last and
   least, because a cyan glow on a flat layout just makes a flat layout glow.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */

/* ── surface depth ─────────────────────────────────────────────────────────────────────────
   Cards used one background. Now they carry a top-lit gradient and a hairline that is brighter
   at the top edge than the bottom — the cheapest honest way to suggest a light source, and what
   separates a "panel" from a "rectangle". */
.card {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .045) 0%, rgba(255, 255, 255, .014) 100%),
    var(--panel);
  border: 1px solid var(--panel-line);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .05),
    0 1px 2px rgba(0, 0, 0, .28),
    0 8px 24px -14px rgba(0, 0, 0, .5);
}
/* The metadata card is deliberately the quietest thing on the screen. An order id must not look
   like a value the customer is meant to read. */
.card--meta {
  background: var(--surface-soft);
  box-shadow: none;
  opacity: .82;
}
.card--meta .row__value { font-size: 13px; color: var(--muted); }

/* ── the traffic hero ──────────────────────────────────────────────────────────────────────
   The one figure the access screen exists to answer, so it gets the gradient and the size. */
.hero__value, .summary__value {
  background: var(--gradient-primary);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* A fallback for engines that ignore background-clip:text — better a solid cyan number than an
     invisible one. */
  -webkit-text-fill-color: transparent;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero__value, .summary__value { color: var(--cyan); -webkit-text-fill-color: var(--cyan); }
}
.hero__label {
  text-transform: uppercase;
  letter-spacing: .08em;
  font-size: 11px;
  font-weight: 650;
  color: var(--muted);
}
.hero__split {
  display: flex;
  width: 100%;
  gap: 10px;
  margin-top: 14px;
}
.hero__stat {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 12px;
  border-radius: var(--r-md);
  background: var(--surface-soft);
  border: 1px solid var(--surface-line);
  text-align: left;
}
.hero__stat-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}
.hero__stat-value { font-size: 16px; font-weight: 650; }
.hero__stat-value--accent { color: var(--cyan); }
.hero__meta { margin-top: 12px; font-size: 12px; color: var(--muted); }
.summary__foot {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--surface-line);
}
.summary__rule { font-size: 11px; color: var(--muted); }

/* The progress bar carries the brand gradient rather than cyan→blue, so the hero and the CTA
   agree with each other. Thin on purpose: it supports the figure, it is not the figure. */
.bar { height: 5px; background: rgba(255, 255, 255, .06); }
.bar__fill { background: var(--gradient-primary); }
.bar--indeterminate { position: relative; overflow: hidden; }
.bar--indeterminate .bar__fill {
  width: 34%;
  position: absolute;
  animation: barSlide 1.15s ease-in-out infinite;
}
@keyframes barSlide { 0% { left: -34%; } 100% { left: 100%; } }

/* ── skeletons that mirror their destination ───────────────────────────────────────────────
   The four identical slabs are gone. These are shaped like the screen that replaces them, and
   they shimmer with a moving highlight rather than pulsing the whole block — a pulse says
   "something is here", a sweep says "something is loading". */
.sk-screen { display: flex; flex-direction: column; gap: 14px; }
.sk {
  position: relative;
  overflow: hidden;
  border-radius: 8px;
  background: rgba(255, 255, 255, .05);
}
.sk::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .07), transparent);
  animation: shimmer 1.4s ease-in-out infinite;
}
@keyframes shimmer { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) {
  .sk::after { animation: none; }
  .bar--indeterminate .bar__fill { animation: none; width: 100%; opacity: .4; }
}

.sk-card { display: flex; flex-direction: column; gap: 12px; }
.sk-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.sk--title  { width: 42%; height: 15px; }
.sk--label  { width: 30%; height: 12px; }
.sk--value  { width: 42%; height: 12px; }
.sk--chip   { width: 54px; height: 20px; border-radius: 999px; }
.sk--greet  { width: 46%; height: 20px; }
.sk-greeting { padding: 2px 2px 0; }

.sk-hero { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 20px 16px; }
.sk--hero-label  { width: 34%; height: 11px; }
.sk--hero-figure { width: 58%; height: 40px; border-radius: 12px; }
.sk--hero-figure-sm { width: 44%; height: 26px; }
.sk--bar { width: 100%; height: 5px; border-radius: 999px; }
.sk-hero .sk-row { width: 100%; }

.sk-actions { display: flex; gap: 10px; }
.sk--action { flex: 1 1 0; height: 46px; border-radius: var(--r-md); }

.sk-chart { display: flex; align-items: flex-end; gap: 6px; height: 96px; padding-top: 6px; }
.sk-chart__col { flex: 1 1 0; display: flex; align-items: flex-end; height: 100%; }
.sk--bar-v { width: 100%; border-radius: 4px 4px 2px 2px; }

.sk-packages { display: flex; flex-direction: column; gap: 10px; }
.sk-pkg { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.sk--pkg-size  { width: 36%; height: 18px; }
.sk--pkg-price { width: 24%; height: 18px; }

/* ── error states ──────────────────────────────────────────────────────────────────────────
   The raw machine code is gone; what remains is a reference, styled to read as a reference —
   monospaced, tiny, and clearly not a sentence. */
.errorstate__code { display: none; }   /* superseded by __ref; kept so any stale markup is quiet */
.errorstate__ref {
  margin-top: 14px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--muted);
  opacity: .65;
}
.errorstate__actions { justify-content: center; }
/* The icon tint follows the CLASS, so a dropped connection does not look like a server fault. */
.errorstate--network .errorstate__icon  { background: rgba(255, 255, 255, .06); color: var(--muted); }
.errorstate--rateLimit .errorstate__icon{ background: rgba(255, 184, 0, .12);  color: #ffb800; }
.errorstate--session .errorstate__icon  { background: var(--surface-cyan);      color: var(--cyan); }
.errorstate--notFound .errorstate__icon { background: rgba(255, 255, 255, .06); color: var(--muted); }

/* ── pool settings ─────────────────────────────────────────────────────────────────────────
   A two-line value, so an active target can show its domain AND its count without a second row. */
.pool__stack { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.pool__stack-main { font-size: 14px; }
.pool__stack-sub  { font-size: 11px; color: var(--cyan); }

/* ── target sheet ──────────────────────────────────────────────────────────────────────────
   One surface, many states. Padding and rhythm are constant across them so switching state does
   not resize the sheet under the customer's thumb. */
.tgt { display: flex; flex-direction: column; gap: 12px; }
.tgt__label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--muted);
}
.tgt__input {
  width: 100%;
  padding: 13px 14px;
  font-size: 16px;             /* 16px prevents iOS zooming the viewport on focus */
  color: var(--text);
  background: var(--surface-soft);
  border: 1px solid var(--surface-line);
  border-radius: var(--r-md);
  outline: none;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.tgt__input:focus {
  border-color: rgba(0, 229, 255, .45);
  box-shadow: 0 0 0 3px rgba(0, 229, 255, .1);
}
.tgt__hint:empty { display: none; }
.tgt__hint { font-size: 12px; color: var(--danger); }

.tgt__cost {
  font-size: 13px;
  padding: 10px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--surface-line);
  background: var(--surface-soft);
}
.tgt__cost--free,
.tgt__cost--unlimited { color: var(--cyan); background: var(--surface-cyan); border-color: rgba(0, 229, 255, .18); }
.tgt__cost--paid { color: var(--text); }
.tgt__cost--insufficient { color: #ffb800; background: rgba(255, 184, 0, .08); border-color: rgba(255, 184, 0, .22); }

.tgt__cta { width: 100%; }
.tgt__secondary { width: 100%; }
.tgt__headline { font-size: 19px; font-weight: 680; line-height: 1.3; text-align: center; }
.tgt__note { font-size: 13px; color: var(--muted); text-align: center; line-height: 1.5; }
.tgt__running-title { font-size: 16px; font-weight: 650; text-align: center; }
.tgt__domain { font-size: 13px; color: var(--muted); text-align: center; }
.tgt__domain--lg { font-size: 18px; font-weight: 650; color: var(--text); }
.tgt__count {
  font-size: 30px;
  font-weight: 700;
  text-align: center;
  letter-spacing: -.5px;
  background: var(--gradient-primary);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.tgt__breakdown { display: flex; gap: 10px; }
.tgt__stat {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 12px 8px;
  border-radius: var(--r-md);
  background: var(--surface-soft);
  border: 1px solid var(--surface-line);
}
.tgt__stat-value { font-size: 20px; font-weight: 700; }
.tgt__stat-value--ok { color: var(--cyan); }
.tgt__stat-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.tgt__active { text-align: center; display: flex; flex-direction: column; gap: 4px; }
.tgt__active-count { font-size: 13px; color: var(--cyan); }

/* ── fraud sheet ───────────────────────────────────────────────────────────────────────────
   The bands are the pool's shape; the slider is the answer to it. They are adjacent because
   they are read together. */
.fraud { display: flex; flex-direction: column; gap: 14px; }
.fraud__headline { font-size: 18px; font-weight: 680; text-align: center; line-height: 1.3; }
.fraud__note { font-size: 13px; color: var(--muted); text-align: center; line-height: 1.5; }
.fraud__count {
  font-size: 26px; font-weight: 700; text-align: center;
  background: var(--gradient-primary);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.fraud__bands { display: flex; flex-direction: column; gap: 10px; }
.fraud__band { display: flex; flex-direction: column; gap: 5px; }
.fraud__band-head { display: flex; align-items: baseline; gap: 8px; font-size: 12px; }
.fraud__band-name { font-weight: 650; }
.fraud__band-name--clean   { color: var(--cyan); }
.fraud__band-name--average { color: #ffb800; }
.fraud__band-name--bad     { color: var(--danger); }
.fraud__band-range { color: var(--muted); }
.fraud__band-count { margin-left: auto; font-variant-numeric: tabular-nums; font-weight: 650; }
.fraud__band-track { height: 6px; border-radius: 999px; background: rgba(255, 255, 255, .06); overflow: hidden; }
.fraud__band-fill { height: 100%; border-radius: 999px; transition: width .3s ease; }
.fraud__band-fill--clean   { background: linear-gradient(90deg, var(--cyan), #35d0e8); }
.fraud__band-fill--average { background: linear-gradient(90deg, #ffb800, #ff8a3d); }
.fraud__band-fill--bad     { background: linear-gradient(90deg, #ff6b6b, #c0392b); }

.fraud__active {
  font-size: 12px; color: var(--cyan); text-align: center;
  padding: 8px 10px; border-radius: var(--r-md);
  background: var(--surface-cyan); border: 1px solid rgba(0, 229, 255, .18);
}
.fraud__threshold { display: flex; flex-direction: column; gap: 8px; }
.fraud__threshold-head { display: flex; align-items: baseline; justify-content: space-between; }
.fraud__threshold-label { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); }
.fraud__threshold-value { font-size: 18px; font-weight: 700; color: var(--cyan); font-variant-numeric: tabular-nums; }
.fraud__slider {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 6px; border-radius: 999px;
  background: var(--gradient-primary);
  outline: none;
}
.fraud__slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 22px; height: 22px; border-radius: 50%;
  background: #fff; border: 2px solid var(--cyan);
  box-shadow: 0 0 10px rgba(0, 229, 255, .45);
  cursor: pointer;
}
.fraud__slider::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%;
  background: #fff; border: 2px solid var(--cyan);
  box-shadow: 0 0 10px rgba(0, 229, 255, .45);
  cursor: pointer;
}
.fraud__qualifying { font-size: 12px; color: var(--muted); }
.fraud__qualifying--none { color: var(--danger); }
.fraud__cta, .fraud__secondary { width: 100%; }

/* ── traffic history ───────────────────────────────────────────────────────────────────────
   Columns are buttons. The selected one lights, and its detail prints below the axis. */
.hist__col {
  flex: 1 1 0;
  display: flex;
  align-items: flex-end;
  height: 100%;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 4px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.hist__col--on .hist__bar { box-shadow: 0 0 12px rgba(0, 229, 255, .55); }
.hist__col--on .hist__bar--zero { background: var(--cyan); }
.hist__bar { background: var(--gradient-primary); }
.hist__detail {
  min-height: 16px;
  margin-top: 8px;
  font-size: 12px;
  color: var(--cyan);
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.hist__detail:empty { color: transparent; }
.hist__total-value {
  background: var(--gradient-primary);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  font-weight: 700;
}

/* ── primary CTA ───────────────────────────────────────────────────────────────────────────
   The gradient plus a restrained glow that is a lift, not a halo. Nothing else on a screen may
   carry this treatment — that is what makes it read as THE action. */
.btn--primary {
  background: var(--gradient-primary);
  color: #04121a;
  font-weight: 680;
  border: 0;
  box-shadow: 0 4px 16px -6px rgba(0, 229, 255, .5), inset 0 1px 0 rgba(255, 255, 255, .25);
}
.btn--primary:active { transform: translateY(1px); box-shadow: 0 2px 8px -4px rgba(0, 229, 255, .45); }
.btn--primary:disabled { opacity: .5; box-shadow: none; }
.btn--warn { background: linear-gradient(135deg, #ffb800 0%, #ff8a3d 100%); color: #1a0e00; }

/* ── header ────────────────────────────────────────────────────────────────────────────────
   Polish only: it keeps its height and its identity. A hairline and a faint cyan wash at the top
   stop it dissolving into the screen, which is what made it read as empty. */
.topbar {
  background:
    linear-gradient(180deg, rgba(0, 229, 255, .045) 0%, transparent 100%),
    var(--chrome, var(--panel));
  border-bottom: 1px solid var(--surface-line);
}
.topbar__brand { letter-spacing: -.2px; font-weight: 680; }

/* ── bottom navigation ─────────────────────────────────────────────────────────────────────
   STRUCTURE UNCHANGED: five tabs, Buy in the centre. The active tab gains a cyan dot above the
   label — a marker the eye finds without reading — and the central action gains the brand
   gradient and the same restrained glow as the primary CTA, because it IS the primary action. */
.tabbar {
  background: linear-gradient(180deg, rgba(255, 255, 255, .022) 0%, transparent 60%), var(--chrome, var(--panel));
  border-top: 1px solid var(--surface-line);
}
.tab { position: relative; transition: color .18s ease; }
.tab--active::before {
  content: "";
  position: absolute;
  top: 4px;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--cyan);
  box-shadow: 0 0 8px rgba(0, 229, 255, .8);
}
.tab--center::before { content: none; }   /* the centre action is its own marker */
.tab__fab {
  background: var(--gradient-primary);
  color: #04121a;
  box-shadow: 0 4px 18px -6px rgba(0, 229, 255, .55), inset 0 1px 0 rgba(255, 255, 255, .3);
}

/* ── sheets ────────────────────────────────────────────────────────────────────────────────
   A sheet is the most elevated surface in the app, so it is the only one with a visible top-edge
   highlight and a real drop shadow. */
.sheet {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .06) 0%, rgba(255, 255, 255, .015) 120px),
    var(--panel-strong, var(--panel));
  border-top: 1px solid rgba(255, 255, 255, .1);
  box-shadow: 0 -18px 48px -20px rgba(0, 0, 0, .75);
}
.sheet__title { font-weight: 680; }

/* ── empty states ──────────────────────────────────────────────────────────────────────────
   A dashed boundary makes an empty region read as deliberate rather than unfinished. */
.empty {
  border: 1px dashed var(--surface-line);
  border-radius: var(--r-lg);
  background: var(--surface-soft);
}
.hist__empty {
  padding: 18px 12px;
  text-align: center;
  border: 1px dashed var(--surface-line);
  border-radius: var(--r-md);
  background: var(--surface-soft);
}
.hist__empty-title { font-weight: 650; margin-bottom: 4px; }
