/*
  "Nocturne" — design system built and approved in Claude Design
  (project 221ba9d6-43a8-4d6d-b93f-bcd81d79fa85, "VPN Telegram WebApp
  redesign"). Deliberately single-theme dark — not every page needs a
  light/dark toggle; this one commits to one visual world instead.
  Ported here from the approved .dc.html mockup + its Nocturne token sheet.
*/
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

:root {
  color-scheme: dark;

  --color-bg: #161826;
  --color-surface: #232532;
  --color-text: #e9e9ed;
  --color-accent: #9184d9;
  --color-divider: color-mix(in srgb, #e9e9ed 16%, transparent);

  --color-neutral-100: #f3f5fe;
  --color-neutral-500: #9397ab;
  --color-accent-100: #f5f4ff;
  --color-accent-300: #d2cefd;
  --color-accent-800: #423a6a;

  /* Status colors — deliberate, scoped exception to the accent-only rule
     above, used only for the subscription-active/inactive hero on Home
     (see context.md). Muted to match the rest of the dark palette rather
     than pulling in saturated stock red/green. */
  --color-success: #6fcf97;
  --color-danger: #e08585;

  --font-heading: "Inter", system-ui, sans-serif;
  --font-heading-weight: 500;
  --font-body: "Inter", system-ui, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, "Cascadia Code", monospace;

  --space-1: 2.8px;
  --space-2: 5.6px;
  --space-3: 8.4px;
  --space-4: 11.2px;
  --space-6: 16.8px;
  --space-8: 22.4px;

  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 14px;

  --shadow-sm: 0 0 0 1px #3f424d;
  --tabbar-height: 60px;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, h4 {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  line-height: 1.2;
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-2);
  text-wrap: balance;
}
h2 { font-size: 22px; }
h3 { font-size: 16px; font-weight: 600; }

p { margin: 0 0 var(--space-3); font-size: 14px; }
p:last-child { margin-bottom: 0; }

a { color: var(--color-accent); text-underline-offset: 3px; }
.text-muted { color: color-mix(in srgb, var(--color-text) 55%, transparent); }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }

.page {
  /* width:100% is load-bearing, not redundant with max-width. #app is a flex
     column (it uses .view → display:flex), and .page's `margin:0 auto` are
     cross-axis auto margins on a flex item — which DISABLE align-items:stretch
     and make .page shrink-to-fit its active view's content. Home (short text)
     then collapsed narrow while long-text tabs looked full-width. An explicit
     width:100% gives .page a definite size (viewport, capped at 480) instead. */
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  position: relative;
}

.nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--color-bg);
}
.nav-brand {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 16px;
  margin-right: auto;
}
.nav-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--color-accent); }

/* — star field — ambient falling-particle background, ported from the
   approved Nocturne mockup (Claude Design project 221ba9d6, "VPN WebApp
   redesign"). Pure CSS, no JS/canvas: a fixed layer of small dots, each
   falling on its own randomized duration/delay/opacity via CSS custom
   properties set per-instance in index.html. z-index:0 puts it behind
   .content (z-index:1 below) and .tabbar (already position:fixed,
   translucent + blurred — sits above by DOM order, no z-index needed there;
   see its backdrop-filter, which already assumes something's moving behind it). */
.star-field {
  position: fixed;
  inset: 0;
  max-width: 480px;
  margin: 0 auto;
  pointer-events: none;
  overflow: hidden;
  z-index: 0;
}
.star {
  position: absolute;
  left: var(--star-left);
  top: 0;
  width: var(--star-size, 2px);
  height: var(--star-size, 2px);
  border-radius: 50%;
  background: var(--star-color, var(--color-neutral-100));
  animation: starFall var(--star-duration, 10s) linear infinite;
  animation-delay: var(--star-delay, 0s);
}
@keyframes starFall {
  0% { transform: translateY(-6px); opacity: 0; }
  12% { opacity: var(--star-op, .5); }
  88% { opacity: var(--star-op, .5); }
  100% { transform: translateY(720px); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .star { animation: none; opacity: 0; }
}

.content {
  flex: 1;
  /* nav header removed — Telegram's own chrome sits above the webapp, so this
     modest top padding is enough separation without the wasted brand bar.
     Bottom clears the fixed tab bar, whose own height grows by the home-
     indicator safe-area — so add that here too, or the last card is clipped. */
  padding: var(--space-4) var(--space-4) calc(96px + env(safe-area-inset-bottom, 0px));
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  position: relative;
  z-index: 1;
}

.view { display: none; }
.view.active { display: flex; flex-direction: column; gap: var(--space-4); }
/* Force each tab view to fill .content's width. Without this, WebKit (Telegram
   iOS) sizes a flex-column view to its content's max-content width whenever
   nothing inside pins full width — which made the Home tab (all short-text
   cards) render narrower than Connect/Тариф/Ещё, each of which already has a
   width:100% seg / disclosure-row / long step line forcing it wide. */
.content > .view { width: 100%; }

/* — cards — */
.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  border: 1px solid transparent;
}
.elev-sm { box-shadow: var(--shadow-sm); }

.card-btn {
  cursor: pointer;
  text-align: left;
  color: var(--color-text);
  font: inherit;
}
.card-btn.row { flex-direction: row; align-items: center; }

/* Button-based cards must stretch to full width like the <div> cards do.
   WebKit (Telegram's iOS engine) doesn't reliably stretch a <button> flex
   item to align-items:stretch, so without this the Home tab's cards and the
   Тариф tier buttons render narrower than every <div class="card"> elsewhere. */
button.card { width: 100%; }

.hero-card {
  align-items: center;
  text-align: center;
  padding: var(--space-8) var(--space-4);
  gap: var(--space-2);
}
.hero-icon {
  width: 84px;
  height: 84px;
  border-radius: 50%;
  border: 1.5px solid var(--color-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--space-3);
  transition: border-color 0.15s;
}
.hero-title { font-family: var(--font-heading); font-weight: 700; font-size: 26px; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }

.icon-btn-label { align-items: center; gap: var(--space-2); }
.icon-btn-label .label { font-size: 13px; font-weight: 500; }

.row-card { display: flex; flex-direction: row; align-items: center; gap: var(--space-3); }
.row-card .row-icon { flex-shrink: 0; }
.row-card .row-body { flex: 1; }
.row-card .row-title { font-size: 14px; font-weight: 500; }
.row-card .row-meta { font-size: 12px; }
.chevron { transition: transform 0.15s; }
.chevron.open { transform: rotate(90deg); }

/* Collapsible "more" cards — the disclosure row shares the card, the body
   drops below a divider only while open. */
.disclosure { padding: 0; overflow: hidden; }
.disclosure > .row-card { width: 100%; padding: var(--space-4); border: none; background: transparent; }
.disclosure-body {
  padding: 0 var(--space-4) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  border-top: 1px solid var(--color-divider);
  font-size: 13px;
}
.disclosure-body > *:first-child { padding-top: var(--space-3); }

/* Smooth expand/collapse — animates height instead of snapping between
   display:none/block, so opening a guide reads as a deliberate reveal
   rather than the page jumping. max-height (not the CSS-grid 0fr/1fr
   trick) — that grid technique is unreliable in WebKit/iOS Safari, which
   is exactly what Telegram's in-app browser runs on, and rendered the
   guides permanently open regardless of state. 600px comfortably covers
   the longest guide (4 steps) with room to spare. */
.collapse {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.25s ease;
}
.collapse.open { max-height: 600px; }
.collapse-inner { overflow: hidden; }

/* Spacing between the QR card, the guide-toggle button, and the revealed
   guide content — these panels are plain divs, not flex containers, so
   gap has to be declared explicitly rather than inherited from a parent.
   Nocturne's own --space-3 (8.4px) reads as "touching" at mobile touch-UI
   scale, so this uses a deliberately larger fixed value instead. */
.protocol-panel { display: flex; flex-direction: column; gap: 16px; }

/* — numbered guide steps — a real sequence, so numbering is earned — */
.guide-step { display: flex; gap: var(--space-3); }
.guide-step .num {
  width: 18px; height: 18px; border-radius: 50%;
  border: 1px solid var(--color-accent); color: var(--color-accent);
  font-size: 10px; font-weight: 600;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.guide-step .text { font-size: 13px; line-height: 1.5; }

/* — Подключение / INCY connect view — the whole tab is now: an app-icon-style
   hero, one generate/copy action, and a numbered import guide. */
.connect-hero {
  align-items: center;
  text-align: center;
  padding: var(--space-6) var(--space-4) var(--space-4);
  gap: var(--space-1);
}
.connect-badge {
  width: 52px; height: 52px;
  border-radius: 15px; /* app-icon squircle feel */
  display: flex; align-items: center; justify-content: center;
  margin-bottom: var(--space-2);
  background: radial-gradient(120% 120% at 30% 22%,
    color-mix(in srgb, var(--color-accent) 26%, var(--color-surface)),
    var(--color-surface));
  border: 1px solid color-mix(in srgb, var(--color-accent) 45%, transparent);
  box-shadow: 0 8px 30px color-mix(in srgb, var(--color-accent) 20%, transparent);
}
.connect-hero-title {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 20px;
}
.connect-steps { gap: var(--space-4); padding: var(--space-6) var(--space-4); }
.steps-title {
  font-size: 11px; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--color-neutral-500); margin-bottom: var(--space-1);
}
/* dedicated instruction list — a touch more air + larger body than the inline
   collapsible guides elsewhere (source order beats .guide-step's equal
   specificity, so these win). */
.connect-steps .guide-step { gap: var(--space-4); align-items: flex-start; }
.connect-steps .text { font-size: 14px; line-height: 1.5; padding-top: 1px; }

/* — segmented control — */
.seg { display: flex; width: 100%; border: 1px solid var(--color-divider); border-radius: var(--radius-md); overflow: hidden; }
.seg-opt {
  flex: 1;
  display: flex; align-items: center; justify-content: center;
  padding: 7px 12px; font: inherit; font-size: 13px;
  color: var(--color-neutral-500);
  border: none; background: transparent; cursor: pointer;
}
.seg-opt + .seg-opt { border-left: 1px solid var(--color-divider); }
.seg-opt.active { color: var(--color-accent); box-shadow: inset 0 0 0 1px var(--color-accent); }

/* — buttons — */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  cursor: pointer; text-decoration: none;
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 14px; color: var(--color-text);
  background: transparent; border: 1px solid transparent;
  padding: var(--space-3) calc(var(--space-3) * 1.2);
  border-radius: var(--radius-md);
  width: 100%;
}
.btn svg { display: block; flex-shrink: 0; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-primary { color: var(--color-accent); border-color: var(--color-accent); }
.btn-primary:active { background: color-mix(in srgb, var(--color-accent) 22%, transparent); }
.btn-secondary { border-color: var(--color-divider); }
.btn-secondary:active { background: color-mix(in srgb, var(--color-text) 14%, transparent); }
.btn-ghost { color: var(--color-neutral-500); border: 1px dashed var(--color-divider); }
.btn-icon { width: 44px; flex: none; padding: 0; }
.btn-row { display: flex; gap: var(--space-3); }
.btn-row .btn:not(.btn-icon) { flex: 1; }

/* — tags — */
.tag { display: inline-flex; align-items: center; font-size: 11px; letter-spacing: 0.02em; padding: 3px 10px; border-radius: 6px; }
.tag-accent { background: var(--color-accent-800); color: var(--color-accent-100); }
.tag-outline { border: 1px solid var(--color-accent); color: var(--color-accent); }
.tag-banner { width: 100%; box-sizing: border-box; padding: var(--space-3); font-size: 12px; justify-content: center; }

/* — plan tier rows — */
.tier {
  flex-direction: row; align-items: center; justify-content: space-between;
  position: relative;
}
.tier.recommended { border: 1px solid var(--color-accent); }
.tier .tier-badge { position: absolute; top: -9px; left: 12px; }
.tier .tier-name { font-size: 14px; font-weight: 500; }
.tier .tier-sub { font-size: 12px; }
.tier .tier-price { text-align: right; }
.tier .tier-final { font-size: 15px; font-weight: 600; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.tier .tier-was { font-size: 11px; text-decoration: line-through; }

/* — data blocks (config text, uri, referral link) — */
.data-block {
  background: var(--color-bg);
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.6;
  margin: 0;
  white-space: pre-wrap;
  word-break: break-all;
}
/* Fixed-size box — placeholder and loaded QR occupy the exact same
   footprint, so filling it in never reflows the rest of the card. */
.qr-box {
  height: 220px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.qr-placeholder {
  display: flex; align-items: center; justify-content: center; flex-direction: column;
  gap: var(--space-2);
  width: 100%;
  height: 100%;
  border: 1.5px dashed var(--color-divider);
  border-radius: var(--radius-md);
}
.qr-placeholder .label { font-family: var(--font-mono); font-size: 11px; }
img.qr {
  display: block;
  width: auto;
  height: 100%;
  max-width: 100%;
  margin: 0 auto;
  border-radius: var(--radius-md);
  background: #fff;
  padding: var(--space-2);
  object-fit: contain;
}

.eyebrow {
  font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-neutral-500);
  margin: var(--space-2) 0 0;
}
.eyebrow:first-child { margin-top: 0; }

.center { text-align: center; }

/* — bottom tab bar — */
.tabbar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  max-width: 480px;
  margin: 0 auto;
  display: flex;
  background: color-mix(in srgb, var(--color-bg) 90%, transparent);
  backdrop-filter: blur(16px);
  border-top: 1px solid var(--color-divider);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  /* Must sit above .content (z-index:1, added for the star field): .content's
     box extends down over this fixed bar's area via its bottom padding, so
     without a higher z-index here .content paints on top and swallows every
     tap on the tab bar. */
  z-index: 10;
}
.tab {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 10px 0 12px;
  border: none; background: transparent; cursor: pointer;
  font-family: var(--font-body);
  color: var(--color-neutral-500); /* currentColor — cascades to tab-icon svg strokes too */
}
.tab.active { color: var(--color-accent); }
.tab .tab-label { font-size: 10px; font-weight: 500; }
