/* Безопасные зоны экрана одной парой переменных. По умолчанию — системные.
   В полноэкранном мини-аппе Telegram свои: вырез экрана плюс его кнопки
   «Закрыть» и «⋯» сверху; их подставляет скрипт (fitSafeArea). */
:root{--sa-top:env(safe-area-inset-top,0px);--sa-bottom:env(safe-area-inset-bottom,0px)}

/* Columbian — личный кабинет. Тема собрана по фирменным шапкам экранов:
   синее стекло, белые карточки на светло-голубом листе, Inter. Цвета взяты
   с самих баннеров, а не подобраны на глаз, — экран и картинка над ним
   должны читаться как одна вещь. */

/* `swap` здесь безопасен только потому, что первой отрисовки не случится,
   пока шрифт не готов: `boot` ждёт `document.fonts.load` и лишь потом
   показывает кабинет (см. app.js, fontsReady). Без этого ожидания вебвью
   рисовал текст системным шрифтом — тот шире, подписи в полосе тарифа
   ломались на две строки, — а через сотню миллисекунд подменял на Inter, и
   всё схлопывалось обратно. Замер показал это как рост карточки со 166 до
   180 точек при неизменном кегле.

   `optional` вместо ожидания не подходит: он оставляет системный шрифт на
   весь показ страницы, и на медленной сети человек видел бы не «на миг
   криво», а «криво до перезахода». */
@font-face{font-family:'Inter';font-style:normal;font-weight:400 800;font-display:swap;
  src:url('fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
/* latin-ext подключён ради одного знака: рубль (U+20BD) живёт именно здесь,
   и без этого файла все цены показывались квадратиком. */
@font-face{font-family:'Inter';font-style:normal;font-weight:400 800;font-display:swap;
  src:url('fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+1D00-1DBF,
  U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'Inter';font-style:normal;font-weight:400 800;font-display:swap;
  src:url('fonts/inter-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+20AC,U+2122,U+2212,U+FEFF,U+FFFD}

:root{
  /* Синий взят с фирменных шапок: заливка кадра, свет на стекле и белый
     текст поверх. Ниже он же держит кнопки, ссылки и активные состояния. */
  --brand:#1877FF; --brand-deep:#0B4FD0; --brand-soft:#E7F0FF; --brand-glow:#5AA7FF;
  --cta:#1877FF; --cta-deep:#0B4FD0;
  /* Лист чуть голубее белого: на нём белая карточка читается поднятой, а
     синяя кнопка не тонет. Линии на полтона темнее листа — по той же
     причине. */
  --page:#E4EEFF; --card:#FFFFFF; --line:#D3E1F8; --line-2:#B7CDEC;
  /* Подложка вложенных плашек. Была плотная #F5F9FF — на стеклянных
     карточках она читалась белой наклейкой поверх прозрачного. Теперь это
     тот же материал, что и всё остальное внутри карточек. */
  --tint:rgba(255,255,255,.34);
  --ink:#0C1626; --soft:#3B4A63; --mute:#54637D; --line-strong:#8698B4;
  --warn:#B26B12; --bad:#B3261E;
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
  --r-sm:10px; --r:14px; --r-lg:20px; --pill:999px;
  /* Три слоя, а не один: контактная тень под краем, мягкая на отлёте и
     светлая линия сверху. Без неё карточка выглядит наклейкой. */
  --sh-1:0 1px 1px rgba(10,22,44,.05),0 2px 6px rgba(10,22,44,.06),0 12px 28px rgba(10,22,44,.07);
  --sh-lift:0 2px 4px rgba(10,22,44,.07),0 10px 22px rgba(10,22,44,.10),0 24px 48px rgba(10,22,44,.08);
  --sh-2:0 2px 4px rgba(11,79,208,.24),0 8px 18px rgba(11,79,208,.28);
  --edge:inset 0 1px 0 rgba(255,255,255,.9);
  /* Стекло. Один материал на весь кабинет: карточка первого шага, карточки
     управления и всё, что лежит внутри них. Держать его в токенах, а не
     переписывать заливку в каждом правиле, — иначе экраны разъезжаются по
     оттенку при первой же правке.

     Два уровня: `glass` — сама карточка, `glass-in` — то, что лежит на ней
     (плитки, строки, кружки). Внутренний светлее внешнего, иначе вложенное
     тонет в поверхности и перестаёт читаться отдельной вещью. */
  --glass:rgba(255,255,255,.45); --glass-edge:rgba(255,255,255,.95);
  --glass-in:rgba(255,255,255,.34); --glass-in-edge:rgba(255,255,255,.78);
  --glass-hi:rgba(255,255,255,.5); --glass-hi-edge:rgba(255,255,255,.9);
  --glass-blur:blur(26px) saturate(180%);
  --glass-lift:inset 0 0 22px rgba(255,255,255,.5),
               0 0 0 1px rgba(96,132,190,.13),
               0 12px 30px rgba(10,22,44,.11);
  --glass-in-lift:inset 0 1px 0 rgba(255,255,255,.7),0 1px 2px rgba(10,22,44,.05);
  /* Движение. Держится в токенах по той же причине, что и стекло: пять
     разных кривых на одном экране читаются как пять разных приложений.
     `out` — для всего, что появляется и отпускается само (карточки, шаги);
     `snap` — для отклика на палец: короче и жёстче, чтобы нажатие не
     «доезжало» после того, как человек уже убрал руку. */
  --ease-out:cubic-bezier(.22,1,.36,1); --ease-snap:cubic-bezier(.2,.8,.3,1);
  --dur-1:.16s; --dur-2:.28s; --dur-3:.34s;
  --bar-h:72px; --bar-gap:18px;
  --font:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;height:100%}
/* Цвет страницы держит html, а не body: при перетягивании за край экрана
   виден именно он, и без этого из-под страницы проглядывала белая полоса. */
/* Автоподбор кегля вебвью — выключен.

   Мобильный движок считает себя вправе увеличить шрифт в блоке, который
   показался ему узким, и пересчитывает это при каждой смене размеров.
   Возврат из тарифа на витрину меняет раскладку карточек — и цифры цены на
   кадр становились крупнее, а потом сами уменьшались. Своих размеров у нас
   хватает: кегль задан для каждой ступени высоты, и помогать здесь нечем.
   Оба написания нужны: короткое понимает Chromium, префиксное — WebKit. */
html{background:var(--page);
  -webkit-text-size-adjust:100%;text-size-adjust:100%}

/* Подложка фона отдельным закреплённым слоем.

   Раньше градиент лежал на body с background-attachment:fixed — и уезжал
   вместе с прокруткой: вебвью на iOS это свойство игнорирует, и ниже первого
   экрана страница становилась плоской заливкой. Закреплённый элемент такой
   болезни не имеет и всегда закрывает ровно видимую область. */
html::before{content:'';position:fixed;inset:0;z-index:0;pointer-events:none;
  background:radial-gradient(1000px 460px at 82% -14%,#C9DEFF,transparent 62%),
             linear-gradient(180deg,#D8E8FF,var(--page) 46%)}
body{
  font-family:var(--font);color:var(--ink);font-size:15px;line-height:1.45;letter-spacing:-.005em;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  font-optical-sizing:auto;font-feature-settings:'calt' 1;
  background:transparent;
  overscroll-behavior-y:none;
}

/* Виньетка по краям: без неё светлый фон и белая карточка сливаются в одно
   молочное пятно, и никакая тень уже не спасает. */
body::after{content:'';position:fixed;inset:0;z-index:0;pointer-events:none;
  background:radial-gradient(120% 80% at 50% 30%,transparent 45%,rgba(12,30,64,.10) 100%)}

/* Зерно поверх фона. Рисуется фильтром, а не файлом: пара сотен байт против
   запроса за картинкой, и не мылится на плотных экранах. Без него плоская
   заливка читается как «сделано по шаблону». */
/* Базовый слой — только мелкое зерно. Оно даёт материал, но ни за что не
   цепляет взгляд и не спорит с текстом. */
/* Базовый слой — только мелкое зерно. Оно даёт материал, но ни за что не
   цепляет взгляд и не спорит с текстом. */
body::before{content:'';position:fixed;inset:0;z-index:0;pointer-events:none;opacity:.1;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
  background-size:160px 160px;
  mix-blend-mode:multiply}

/* Раскиданные по фону травинки с главной убраны: узор просвечивал в щелях
   между карточками и рябил. Место занял свет — он даёт ту же «не пустую»
   страницу, но ни за что не цепляет взгляд. Зерно осталось одно на все
   вкладки. */

/* ─────────────────────────── свет фона

   Три пятна поверх заливки. Живут собственным очень медленным движением:
   один проход занимает от сорока секунд до полутора минут, поэтому в кадре
   ничего не «едет» — страница просто не выглядит замершей. Двигаются они
   только `transform`, то есть даром для кадра: ни перекраски, ни пересчёта
   раскладки.

   На каждой вкладке ярче своё пятно — переход занимает полторы секунды и
   успевает случиться, пока человек смотрит на новый экран. Это и есть вся
   «динамика»: смена света, а не смена картинки. */
/* `contain`: слой живёт сам по себе — его анимация не поднимает перерасчёт
   раскладки и отрисовки страницы. */
.aura{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;
  contain:layout paint size}
/* Свет вкладки переезжает вместе с самой вкладкой, а не догоняет её.

   Полторы секунды задумывались как «смена света, пока человек смотрит на
   новый экран», но сквозь стеклянное нижнее меню это читается иначе: экран
   уже стоит, а цвет под панелью ещё ползёт — и выглядит не переходом, а
   недогруженной страницей. Теперь длительность и кривая те же, что у
   появления самого экрана (.3s, `animation:in`), и цвет приезжает одним
   движением вместе с ним. */
.aura i{position:absolute;display:block;border-radius:50%;
  transition:opacity .28s cubic-bezier(.22,1,.36,1);will-change:transform}
/* Белый свет сверху справа — блик на стекле, главный на главной. */
.aura i:nth-child(1){width:112vw;height:112vw;top:-46vw;right:-34vw;opacity:.5;
  background:radial-gradient(circle at 50% 50%,rgba(255,255,255,.85),transparent 66%);
  animation:aura-a 52s ease-in-out infinite alternate}
/* Синева снизу слева: продолжает фирменную заливку вверх по листу. */
.aura i:nth-child(2){width:126vw;height:126vw;bottom:-58vw;left:-40vw;opacity:.42;
  background:radial-gradient(circle at 50% 50%,rgba(24,119,255,.30),transparent 64%);
  animation:aura-b 71s ease-in-out infinite alternate}
/* Голубое пятно у горизонта: включается там, где речь про деньги. */
.aura i:nth-child(3){width:92vw;height:92vw;top:44vh;left:-32vw;opacity:.16;
  background:radial-gradient(circle at 50% 50%,rgba(90,167,255,.34),transparent 58%);
  animation:aura-c 43s ease-in-out infinite alternate}
@keyframes aura-a{from{transform:translate3d(0,0,0) scale(1)}
  to{transform:translate3d(-7vw,5vh,0) scale(1.1)}}
@keyframes aura-b{from{transform:translate3d(0,0,0) scale(1.06)}
  to{transform:translate3d(9vw,-6vh,0) scale(.96)}}
@keyframes aura-c{from{transform:translate3d(0,0,0) scale(.94)}
  to{transform:translate3d(12vw,-4vh,0) scale(1.12)}}

body[data-tab="shop"] .aura i:nth-child(3){opacity:.42}
body[data-tab="shop"] .aura i:nth-child(2){opacity:.3}
body[data-tab="ref"] .aura i:nth-child(2){opacity:.6}
body[data-tab="profile"] .aura i:nth-child(1){opacity:.62}
body[data-tab="profile"] .aura i:nth-child(2){opacity:.3}

/* Падающий слой (травинки, позже — стеклянные пластины) убран целиком:
   владелец попросил снять его из мини-аппа. Фон держат свет `.aura` и зерно;
   двадцать четыре анимированных элемента за карточками стоили по слою
   компоновщика каждый и ни на один вопрос экрана не отвечали. */

/* Трава на дне страницы. Рисуется один раз и стоит на месте: в мини-аппе
   фон прокручивается вместе с содержимым, и «живая» трава при каждом свайпе
   отвлекала бы от цифр. */
/* Трава доходит до самого низа экрана и уходит ЗА панель меню. Раньше она
   обрывалась над баром — тогда бар был сплошной полосой во всю ширину и
   сам закрывал стык. Приподнятая панель этот стык открыла: под ней
   оставалась светлая полоса, из-за которой отражение читалось приклеенным
   поверх пустоты. Высота растёт вместе с отступом панели, поэтому верхняя
   кромка остаётся там же, где была. */
.floor{position:fixed;left:0;right:0;bottom:0;z-index:0;pointer-events:none;
  height:calc(196px + var(--bar-h) + var(--bar-gap) + var(--sa-bottom));
  opacity:.66;mask-image:linear-gradient(180deg,transparent,#000 36%)}

.floor svg{display:block;width:100%;height:100%}

.app{position:relative;z-index:1;max-width:460px;margin:0 auto;
  padding:calc(var(--sa-top) + 6px) 16px
          calc(var(--bar-h) + var(--bar-gap) + var(--sa-bottom) + 12px)}

/* ─────────────────────────── шапка */
.top{display:flex;align-items:center;gap:10px;padding:2px 2px 0}
.top .ava{position:relative;width:38px;height:38px;border-radius:50%;flex:0 0 auto;overflow:hidden;
  background:linear-gradient(135deg,#3D8BFF,#0B4FD0);color:#fff;
  display:grid;place-items:center;font-weight:800;font-size:15px;
  box-shadow:0 1px 3px rgba(10,22,44,.28),inset 0 0 0 1px rgba(255,255,255,.35)}
.top .ava img{width:100%;height:100%;object-fit:cover;display:block}
.top .who{min-width:0}
.top .who b{display:block;font-size:16px;font-weight:800;color:var(--brand-deep);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.top .who span{display:block;font-size:12.5px;font-weight:500;color:var(--mute)}
.top .sp{flex:1}
.top a.sup{height:34px;padding:0 13px;border-radius:var(--pill);display:inline-flex;align-items:center;gap:7px;
  color:var(--brand-deep);background:var(--glass-hi);
  border:1px solid var(--glass-hi-edge);text-decoration:none;
  font-size:13px;font-weight:800;box-shadow:var(--glass-in-lift)}
.top a.sup:active{transform:translateY(1px)}

/* ─────────────────────────── карточки */
/* Все карточки кабинета — из одного стекла. Плотно-белые плашки стояли на
   том же светящемся листе и читались другим интерфейсом: на главной стекло,
   на соседнем экране пластик. Размытие живёт только здесь, на карточке;
   всё, что лежит внутри, берёт полупрозрачную заливку поверх уже размытой
   подложки и своего слоя не заводит — иначе вебвью считало бы по десятку
   живых слоёв на прокрутку. */
.card{position:relative;background:var(--glass);
  border:1px solid var(--glass-edge);border-radius:var(--r-lg);
  -webkit-backdrop-filter:var(--glass-blur);
          backdrop-filter:var(--glass-blur);
  box-shadow:var(--glass-lift);padding:13px 14px 14px;margin-top:11px}
/* Где размытия нет (старый Android-вебвью) — заливка плотнее: полупрозрачное
   белое без блюра превращается в мутное пятно. */
@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){
  .card{background:linear-gradient(180deg,#fff,rgba(255,255,255,.92))}
}
.card.flat{box-shadow:none;background:transparent;border:0;padding:2px 2px 0;margin-top:14px;
  -webkit-backdrop-filter:none;backdrop-filter:none}
.lbl{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.09em;
  color:var(--mute)}

/* Карточка подписки — главный объект экрана. Цветной грани сверху больше
   нет: на стекле трёхточечная полоса читалась наклейкой на прозрачном, а
   не краем карточки. Вес карточка держит размером и содержимым. */
.card.lead{overflow:hidden}
.card h2{margin:0 0 2px;font-size:17.5px;font-weight:800;letter-spacing:-.014em}
/* Пояснения под заголовками: 13px четвёртой толщины серым — самая тонкая
   строка кабинета, и читать её на телефоне тяжело. Кегль и вес подняты, цвет
   взят на тон темнее (--soft вместо --mute): на белой карточке это разница
   между «подпись» и «еле видно». */
.card p.sub{margin:0;color:var(--soft);font-size:14px;font-weight:500}

/* Баннер и полоса с устройствами и гигабайтами — один блок. Скругление,
   рамка и тень переезжают на обёртку, а у баннера внутри неё снимаются:
   иначе на стыке с полосой оставался бы двойной кант. Сам `.hero` их
   сохраняет — тот же баннер стоит на витрине (`buy.html`), где обёртки нет
   и рамка ему нужна своя. */
.herow{margin-top:14px;border-radius:var(--r-lg);overflow:hidden;
  border:1px solid rgba(27,40,59,.55);
  box-shadow:0 3px 8px rgba(10,22,44,.16),0 16px 34px rgba(10,22,44,.22)}
.hero{position:relative;margin-top:14px;border-radius:var(--r-lg);overflow:hidden;
  background:linear-gradient(135deg,#3D8BFF,#0B4FD0 72%);
  border:1px solid rgba(27,40,59,.55);
  box-shadow:0 3px 8px rgba(10,22,44,.16),0 16px 34px rgba(10,22,44,.22);
  color:#fff;aspect-ratio:2000/688;isolation:isolate}
.herow .hero{margin-top:0;border:0;border-radius:0;box-shadow:none}
/* Тонкая светлая грань по верхнему краю — от неё карточка «поднимается». */
.hero::after{content:'';position:absolute;inset:0;z-index:3;pointer-events:none;
  border-radius:inherit;box-shadow:inset 0 1px 0 rgba(255,255,255,.26)}
/* Содержимое прижато вправо: слева на снимке сидит Кузя, и текст поверх него
   закрывал единственную живую деталь баннера. */
.hero-in{position:relative;z-index:2;height:100%;min-height:138px;
  display:flex;flex-direction:column;align-items:flex-end;justify-content:center;
  text-align:right;padding:20px 18px;max-width:64%;margin-left:auto}
/* Сумеречный вариант: зелёная заливка на синем небе выглядела грязью,
   поэтому у закончившейся подписки и градиент, и подложка холодные. */
.hero.dusk{background:linear-gradient(135deg,#3E4A63,#232C3D 72%);
  border-color:rgba(24,30,44,.6)}
/* Сумерки красят и кант всего блока: зелёная рамка вокруг синего снимка
   читалась как чужая. */
.herow:has(.hero.dusk){border-color:rgba(24,30,44,.6)}
.hero.dusk::before{background:linear-gradient(90deg,rgba(18,24,38,.10) 0%,
  rgba(18,24,38,.28) 26%,rgba(18,24,38,.70) 52%,rgba(18,24,38,.90) 76%,
  rgba(18,24,38,.95) 100%)}
.hero.dusk .chip i{background:#F2C14E;box-shadow:0 0 0 3px rgba(242,193,78,.22)}

/* Луг за текстом. Тот же приём, что на странице подписки: снимок во всю
   карточку и градиент поверх — иначе белые буквы теряются в траве. */
/* Цветокор кадра. Фирменные шапки и так насыщенные, поэтому добавляем
   немного света и совсем чуть-чуть контраста: кадр остаётся фоном и не
   спорит с тем, что под ним нажимают. */
/* Кадр закрывает плашку целиком: предметы слева, стеклянные углы справа —
   это один снимок, собранный из двух разных мест шапки, поэтому ничего не
   двоится и справа не остаётся пустой заливки. Маска больше не нужна. */
/* Без `filter`: он поднимает картинку в отдельный слой, и Android-вебвью
   растрирует такой слой ниже плотности экрана — на буквах шапки это
   читается лесенкой. Цвет у фирменных кадров и так свой, править его
   ценой резкости незачем. */
/* Заголовок и подпись нарисованы на самой шапке, поэтому экранных надписей
   поверх неё нет. Без `filter` — он поднимает картинку в отдельный слой,
   который Android-вебвью растрирует ниже плотности экрана, и буквы на
   снимке шли лесенкой. */
.hero .hero-in{display:none}
.hero .art{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  /* Кадр прижат левым краем, а не серединой: надписи на нём стоят слева, и
     при обрезке по центру — а она тем сильнее, чем выше шапка, — у экрана
     без подписки от «Личный» оставалось «ный». Режется теперь правый край,
     где только фон и стекло. */
  object-position:50% 50%;z-index:0}
/* Затемнения под текстом больше нет: надписи с баннера убраны, а шапка
   нарисована со своим заголовком. Градиент поверх неё гасил ровно то, ради
   чего её и рисовали. Правило оставлено пустым — вернуть его будет куда,
   если поверх снимка снова понадобится текст. */
/* Затемнения нет: оно существовало под экранный текст, а тот убран.
   Правило оставлено пустым — вернуть его будет куда. */
.hero::before{content:none}
.hero .k{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.09em;
  opacity:.86;text-shadow:0 1px 2px rgba(16,23,34,.5)}
.hero .v{font-size:28px;font-weight:800;line-height:1.08;margin-top:6px;
  text-shadow:0 2px 6px rgba(16,23,34,.45)}
.hero .m{margin-top:6px;font-size:13px;opacity:.92;text-shadow:0 1px 3px rgba(16,23,34,.45)}
/* Чип статуса. Общая деталь: стоит и на баннере главной, и на визитке
   профиля, поэтому к .hero не привязан. */
.chip[hidden]{display:none}
.chip{display:inline-flex;align-items:center;gap:7px;margin-top:12px;padding:6px 13px;
  border-radius:var(--pill);background:rgba(14,21,32,.34);border:1px solid rgba(255,255,255,.5);
  font-size:12px;font-weight:800;
  /* Единственное место с настоящим размытием: чип лежит поверх картинки, и
     без него читается наклейкой. Слой маленький и один на экран — столько
     стекла кадры выдерживают, в отличие от размытия под каждой кнопкой. */
  -webkit-backdrop-filter:blur(10px) saturate(150%);
          backdrop-filter:blur(10px) saturate(150%);
  box-shadow:0 2px 8px rgba(14,21,32,.3),inset 0 1px 0 rgba(255,255,255,.32)}
.chip i{width:6px;height:6px;border-radius:50%;background:#77AAF3;
  box-shadow:0 0 0 3px rgba(119,170,243,.22);animation:pulse 2.6s ease-in-out infinite}
.chip.off i{background:#F2C14E;animation:none}
@keyframes pulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(.72);opacity:.65}}

/* ─────────────────────────── баннер без подписки

   Тот же баннер, что и с подпиской, только выше: полосы с устройствами и
   гигабайтами под ним нет, считать нечего, и освободившееся место уходит
   картинке — до первой покупки Кузя на лугу и есть всё, что человек видит.
   Раскладка текста не меняется: предложение и условия стоят справа, где им
   и место на всех остальных экранах. */
.hero.solo{aspect-ratio:2000/688}
.hero.solo .hero-in{min-height:216px}
.hero.solo .v{font-size:32px;letter-spacing:-.02em}
.hero.solo .m{margin-top:7px;font-size:13.5px}
.hero.solo .chip{margin-top:14px}

/* Шапка продления. Отдельный вид, потому что это не карточка товара, а
   напоминание о том, что у человека уже есть. */
.card.renew{margin-top:12px;padding:12px 14px 13px}
.card.renew h2{margin-top:2px}
.card.renew .now{display:flex;align-items:baseline;gap:7px;margin-top:8px;padding:6px 10px;
  border-radius:var(--pill);background:var(--brand-soft);align-self:flex-start;
  width:-moz-fit-content;width:fit-content}
.card.renew .now span{font-size:11px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--mute)}
.card.renew .now b{font-size:13.5px;font-weight:800;color:var(--brand-deep)}
.card.renew .sub{margin-top:8px}
/* Короткое поле: карточка продления сжимается, чтобы под ней поместились
   все пять сроков и «Сменить тариф» — раньше список уезжал под меню. */
body.h-800 .card.renew{margin-top:10px;padding:10px 13px 11px}
body.h-800 .card.renew h2{font-size:19px}
body.h-800 .card.renew .now{margin-top:6px;padding:5px 9px}
body.h-800 .card.renew .sub{margin-top:6px;font-size:12.5px}
body.h-730 .card.renew{margin-top:8px;padding:9px 12px 10px}
body.h-730 .card.renew h2{font-size:18px}
body.h-730 .card.renew .now{margin-top:5px;padding:4px 8px}
body.h-730 .card.renew .now b{font-size:12.5px}
body.h-730 .card.renew .sub{margin-top:5px;font-size:12px}

/* ─────────────────────────── блок подписки */

/* Три числа в ряд с разделителями. Строчный список «ключ — значение» на
   главной проигрывает: там всё одинаково важно, а тут видно главное. */
.stats{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);margin:11px -4px 0;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.stats .c{padding:9px 4px;text-align:center;position:relative}
.stats .c+.c::before{content:'';position:absolute;left:0;top:14px;bottom:14px;
  width:1px;background:var(--line)}
.stats .c b{display:block;font-size:17px;font-weight:800;letter-spacing:-.02em;line-height:1.1}
.stats .c span{display:block;font-size:11px;font-weight:700;color:var(--mute);margin-top:4px;
  text-transform:uppercase;letter-spacing:.05em}
.stats .c b.low{color:var(--warn)}
.stats .c b.out{color:var(--bad)}

#home-body .card p.sub.top{margin-bottom:9px}
/* Пауза между главной кнопкой и второй больше обычной: так они читаются как
   первое и второе, а не как пара. */
#home-body .card>.btns{gap:10px}
/* Ссылка и дата сброса стоят под кнопками, поэтому отбиваются от них так же,
   как кнопки друг от друга. */
#home-body .card>.link{margin-top:9px}
#home-body .card>.reset{margin-top:9px}

/* Срок, устройства и гигабайты под баннером. Три числа, а не два: надписи
   поверх снимка больше нет — шапки нарисованы со своим заголовком, и срок
   переехал сюда. Значок отвечает на «о чём это» раньше подписи, число
   держит вес строки. */
/* Полоса под баннером — последняя плотно-белая плашка кабинета; переведена
   на общее стекло. Своего размытия не заводит: под ней ровный градиент
   страницы, размывать там нечего. */
.hstats{background:var(--glass);display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  border-top:1px solid rgba(27,40,59,.2)}
/* Спрятанная полоса обязана исчезать: `display:grid` выше сильнее атрибута
   `hidden`, и под баннером у человека без подписки висела пустая белая
   лента — считать в ней нечего, а читается она как ошибка. */
.hstats[hidden]{display:none}
/* minmax(0,1fr) и min-width:0 ниже — без них колонка не сжимается меньше
   своего содержимого, и третья ячейка уезжала за край плашки. */
.hstats .c{display:flex;align-items:center;gap:6px;padding:9px 8px;position:relative;
  min-width:0}
.hstats .c+.c::before{content:'';position:absolute;left:0;top:9px;bottom:9px;
  width:1px;background:var(--line)}
.hstats .c .i{display:grid;place-items:center;width:24px;height:24px;flex:0 0 auto;
  border-radius:8px;background:var(--brand-soft);color:var(--brand-deep)}
.hstats .c .i svg{width:15px;height:15px}
/* Столбик «подпись — число»: подпись мелкая и приглушённая, число крупное.
   min-width:0 — чтобы длинное значение сжималось, а не распирало колонку. */
.hstats .c .b{min-width:0}
/* Строчными, а не капсом. «УСТРОЙСТВА» — самая длинная подпись полосы: в
   капсе на 9,5 точки она шире своей колонки (треть плашки минус значок и
   отступы), обрывалась многоточием и на узком телефоне от неё оставалось
   «УСТРО…». Строчные той же ширины колонки хватает с запасом, и читаются
   они на мелком кегле лучше капса. */
.hstats .c .k{display:block;font-size:10.5px;font-weight:700;color:var(--mute);
  letter-spacing:0;line-height:1;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hstats .c b{display:block;font-size:15px;font-weight:800;letter-spacing:-.02em;
  line-height:1.15;margin-top:3px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.hstats .c b.low{color:var(--warn)}
.hstats .c b.out{color:var(--bad)}
/* Расход — швом между снимком и числами, во всю ширину и без скруглений:
   полоса принадлежит блоку, а не висит в нём отдельной деталью. */
.hmeter{grid-column:1/-1;height:4px;background:var(--brand-soft)}
.hmeter i{display:block;height:100%;
  background:linear-gradient(90deg,#5AA7FF,#1877FF);transition:width .5s cubic-bezier(.22,1,.36,1)}
.hmeter i.warn{background:linear-gradient(90deg,#E8B14C,#C8892A)}
.hmeter i.bad{background:linear-gradient(90deg,#D9705F,#B3261E)}

.traffic{margin-top:11px}
.traffic .t{display:flex;justify-content:space-between;align-items:baseline;font-size:13px}
.traffic .t span{color:var(--mute)}
.traffic .t b{font-weight:800}
/* Дата сброса LTE-трафика. Строка «что — когда» на своей подложке: серая
   строчка под полосой читалась как обрывок, и было непонятно, чья это дата.
   Значок слева отвечает на «что это», дата справа — единственное число в
   строке, поэтому она и держит вес. */
.traffic .reset,#s-manage .card>.reset,#home-body .card>.reset{display:flex;align-items:center;gap:7px;margin-top:9px;
  padding:7px 10px;border-radius:var(--r-sm);background:var(--tint);
  border:1px solid var(--line-2);font-size:12px}
.traffic .reset .i,#s-manage .card>.reset .i,#home-body .card>.reset .i{display:grid;place-items:center;width:16px;height:16px;
  flex:0 0 auto;color:var(--brand)}
.traffic .reset .i svg,#s-manage .card>.reset .i svg,#home-body .card>.reset .i svg{width:14px;height:14px}
.traffic .reset .k,#s-manage .card>.reset .k,#home-body .card>.reset .k{color:var(--soft);font-weight:600}
.traffic .reset b,#s-manage .card>.reset b,#home-body .card>.reset b{margin-left:auto;font-weight:800;color:var(--ink)}
/* На главной у этой строки нет подложки и рамки: под полем ссылки вторая
   такая же плашка читается как второе поле, хотя это справка на одну строку.
   В «Управлении» она остаётся плашкой — там над ней ссылки нет. */
#home-body .card>.reset{padding:0 2px;background:none;border:0}


/* Низкое поле: на главной плитка «Управление подпиской» обязана быть видна
   целиком, без прокрутки — за ней устройства, трафик, докупки и оплаты, а
   на телефоне она уезжала под нижнее меню. Жертвуем воздухом, а не
   строками: тот же приём, что у витрины и экрана продления. */
body.h-760 .hero{aspect-ratio:2000/688}
body.h-760 .hero-in{min-height:126px;padding:16px 16px}
body.h-760 .hero .v{font-size:26px;margin-top:4px}
body.h-760 .hero .m{margin-top:4px}
body.h-760 .hero-in .chip{margin-top:9px}
body.h-760 .hstats .c{padding:8px 12px}
body.h-760 #home-body .card.lead{padding:11px 13px 12px}
body.h-760 #home-body .card>.link,#home-body .card>.reset{margin-top:7px}
body.h-760 #home-body .card>.reset{padding:6px 10px}
body.h-760 #home-body .link .txt,#home-body .link a{padding:6px 11px}
body.h-760 #home-body .btns{margin-top:9px;gap:7px}
body.h-760 #home-body .btn{height:43px}
body.h-760 #home-body .card.lead.start .btn.big{height:52px}
body.h-760 .card.lead.start h2{font-size:23px}
body.h-760 .facts{margin-top:11px}
body.h-700 .hero{aspect-ratio:2000/688}
body.h-700 .hero-in{min-height:114px;padding:13px 15px}
body.h-700 .hero.solo{aspect-ratio:2000/688}
body.h-700 .hero .v{font-size:24px}
body.h-700 .hstats .c{padding:7px 12px}
body.h-700 .hstats .c .i{width:28px;height:28px}
body.h-700 #home-body .btns{margin-top:8px}
body.h-700 #home-body .btn{height:41px;font-size:15px}
body.h-700 #home-body .card.lead.start .btn.big{height:52px;font-size:16.5px}
body.h-700 .card.lead.start h2{font-size:21.5px;margin-top:7px}
body.h-700 .facts{margin-top:10px;gap:6px}
body.h-700 .facts .f{padding:8px 9px}
body.h-700 .facts .f b{font-size:12px}
/* Сплит-экран и клавиатура поверх мини-аппа. Высоту здесь отдаёт уже сам
   баннер: ниже 640 его собственное содержимое, а не min-height, держит
   карточку и уводит плитку под меню. */
body.h-640 .hero-in{padding:11px 14px}
/* Только на совсем низком поле (клавиатура, сплит-экран) баннер отдаёт
часть роста — кнопки и текст остаются макетными. */
body.h-640 .hero.solo{aspect-ratio:2000/688}
body.h-640 .card.lead.start{padding:14px 14px 14px}
body.h-640 .card.lead.start .btns{margin-top:12px}
body.h-640 .card.lead.start .note.chan{margin-top:9px}
body.h-640 .hero.solo .v{font-size:29px}
body.h-640 .hero.solo .m{font-size:13px;margin-top:5px}
body.h-640 .hero.solo .chip{margin-top:10px}
body.h-640 .hero .v{font-size:22px;margin-top:3px}
body.h-640 .hero .m{font-size:12px;margin-top:3px}
body.h-640 .hero-in .chip{margin-top:7px;padding:4px 11px}
body.h-640 .hstats .c{padding:6px 11px}
body.h-640 .hstats .c b{font-size:15px}
body.h-640 #home-body .card>.link,#home-body .card>.reset{margin-top:6px}
body.h-640 #home-body .card>.reset{padding:5px 9px}
body.h-640 #home-body .link .txt,#home-body .link a{padding:5px 11px}
body.h-640 #home-body .btns{margin-top:7px;gap:6px}
body.h-640 #home-body .btn{height:39px}
body.h-640 #home-body .card.lead.start .btn.big{height:52px}
body.h-640 .card.lead.start h2{font-size:20px;margin-top:6px}
body.h-640 .card.lead.start p.sub{margin-top:5px;font-size:13px}
body.h-640 .facts{margin-top:9px}
body.h-640 .tip.pane{margin-top:9px;padding:8px 11px}

/* Ссылка подписки. Тёмная вдавленная панель: это не текст и не кнопка, а
   то, что уносят в другое приложение, и выглядеть должна как поле с данными. */
.link{margin-top:10px;display:flex;align-items:stretch;gap:0;
  border:1px solid var(--line-2);border-radius:var(--r);overflow:hidden;
  background:linear-gradient(180deg,#EAEEF4,#DFE5ED);
  box-shadow:inset 0 2px 5px rgba(10,22,44,.10)}
.link .txt{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;
  padding:8px 11px;color:var(--brand-deep)}
.link .txt i{font-style:normal;font-size:10px;font-weight:800;text-transform:uppercase;
  letter-spacing:.08em;color:var(--mute)}
.link .txt b{font-weight:700;font-size:13px;line-height:1.3;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.link a{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;
  padding:8px 11px;text-decoration:none;color:var(--brand-deep)}
.link a i{font-style:normal;font-size:10px;font-weight:800;text-transform:uppercase;
  letter-spacing:.08em;color:var(--mute)}
.link a b{font-weight:700;font-size:13px;line-height:1.3;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.link button{position:relative;flex:0 0 auto;width:56px;border:0;
  border-left:1px solid var(--line-2);
  background:linear-gradient(180deg,#fff,#ECF0F7);color:var(--cta);cursor:pointer;
  display:grid;place-items:center;font-family:var(--font);overflow:hidden;
  transition:background .22s ease,color .22s ease}
.link button:active{background:var(--brand-soft)}
/* Обе иконки лежат в одной клетке сетки — так они меняются на месте, без
   скачка ширины. */
.link button svg{grid-area:1/1;width:19px;height:19px;
  transition:transform .3s cubic-bezier(.34,1.56,.64,1),opacity .18s ease}
.link button svg.ok{transform:scale(.4) rotate(-25deg);opacity:0}
.link button.done{background:linear-gradient(180deg,#1877FF,#0B4FD0);color:#fff}
.link button.done svg{transform:scale(.4) rotate(25deg);opacity:0}
.link button.done svg.ok{transform:none;opacity:1}

/* Волна по полю ссылки: короткая подсветка слева направо, чтобы было видно,
   что скопировалось именно оно. */
.link{position:relative}
.link.flash::after{content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(90deg,transparent,rgba(67,97,140,.22),transparent);
  animation:flash .7s ease-out}
@keyframes flash{from{transform:translateX(-100%)}to{transform:translateX(100%)}}

/* Кнопка «Скопировать ссылку» в профиле отвечает тем же зелёным. */
.btn.ghost.done{background:linear-gradient(180deg,#E7F0FF,#CFE0FA);
  border-color:var(--cta);color:var(--brand-deep)}

/* Нумерованные шаги. Кружок с цифрой рисуется счётчиком: обычный список
   даёт мелкие цифры без выравнивания. */
.steps{list-style:none;counter-reset:step;margin:10px 0 0;padding:0;display:grid;gap:9px}
.steps li{counter-increment:step;display:flex;align-items:flex-start;gap:10px;
  font-size:13.5px;color:var(--soft);line-height:1.35}
.steps li::before{content:counter(step);flex:0 0 auto;width:22px;height:22px;border-radius:50%;
  background:linear-gradient(180deg,#E4EEFF,#CFE0FA);color:var(--brand-deep);
  font-size:12px;font-weight:800;display:grid;place-items:center;margin-top:1px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.8)}

/* ─────────────────────────── профиль */

/* Визитка. Без снимка: знак уже стоит на первом экране, и второй раз он
   читается как повтор. Материал — то же стекло, что у карточек: узор,
   который держал её раньше, снят вместе со всей травой. */
.me{position:relative;display:grid;grid-template-columns:auto 1fr auto;
  align-items:center;gap:11px 13px;margin-top:14px;
  padding:15px 16px;border-radius:var(--r-lg);overflow:hidden;isolation:isolate;
  /* Светлая визитка вместо тёмно-зелёной плиты. Тёмный блок был
     единственным на весь кабинет и читался как чужой кусок: остальные
     карточки белые на светлом лугу. Цвет остался фирменным — он ушёл в
     кайму, подпись и узор. */
  color:var(--ink);
  background:var(--glass);
  border:1px solid var(--glass-edge);
  box-shadow:var(--glass-lift)}
.me::after{content:'';position:absolute;inset:0;z-index:2;pointer-events:none;
  border-radius:inherit;box-shadow:inset 0 1px 0 rgba(255,255,255,.9)}
.me>*{position:relative;z-index:1}
/* Кружок остаётся зелёным пятном: на светлой визитке он единственная
   опора для взгляда, и без него карточка расплывается. */
.me .ava{width:56px;height:56px;border-radius:50%;flex:0 0 auto;overflow:hidden;
  display:grid;place-items:center;font-size:22px;font-weight:800;color:#fff;
  background:linear-gradient(180deg,#1877FF,var(--brand-deep));
  box-shadow:0 2px 6px rgba(11,79,208,.28),0 0 0 3px rgba(255,255,255,.9)}
.me .ava img{width:100%;height:100%;object-fit:cover;display:block}
.me .tx{min-width:0;flex:1}
.me .tx b{display:block;font-size:19px;font-weight:800;letter-spacing:-.015em;
  color:var(--brand-deep);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Номер. Подпись словами и цифры в одну строку: «id 123456» одним размером
   читалось как служебная строка отладки, хотя это ровно то, что человек
   присылает в поддержку. Цифры табличные — иначе номер «прыгает» шириной при
   смене состояния. */
.me .cid{grid-column:1/-1;display:flex;align-items:center;gap:9px;padding:6px 7px 6px 13px;
  border-radius:var(--pill);cursor:pointer;font-family:var(--font);
  background:var(--tint);border:1px solid var(--line-2);color:var(--soft);
  box-shadow:inset 0 1px 2px rgba(10,22,44,.06);
  transition:background .16s ease,transform .1s ease}
.me .cid i{font-style:normal;font-size:10.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.07em;color:var(--mute)}
.me .cid b{margin-left:auto;font-size:14.5px;font-weight:800;letter-spacing:.03em;color:var(--brand-deep);
  font-variant-numeric:tabular-nums;font-feature-settings:'tnum' 1}
/* Кружок с иконкой: копирование и его подтверждение — одно место, две
   картинки одна поверх другой, как у кнопки рядом со ссылкой. */
.me .cid .ic{position:relative;flex:0 0 auto;width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;background:var(--brand-soft);color:var(--brand-deep)}
.me .cid .ic svg{grid-area:1/1;width:13px;height:13px;
  transition:transform .18s cubic-bezier(.2,.8,.3,1),opacity .18s ease}
.me .cid .ic svg.ok{transform:scale(.4) rotate(-25deg);opacity:0}
.me .cid:active{background:var(--brand-soft);transform:translateY(1px)}
.me .cid.done{background:#E7F0FF;border-color:var(--cta)}
.me .cid.done .ic{background:var(--cta);color:#fff}
.me .cid.done svg{transform:scale(.4) rotate(25deg);opacity:0}
.me .cid.done svg.ok{transform:none;opacity:1}
/* Чип статуса на светлой визитке: тёмный из шапки на белом не читался —
   он рассчитан на фотографию под собой. */
.me .chip{margin-top:0;flex:0 0 auto;align-self:center;
  background:var(--brand-soft);border-color:var(--line-2);color:var(--brand-deep);
  backdrop-filter:none;box-shadow:none}
.me .chip.off i{background:var(--warn)}
/* Без подписки визитка остаётся светлой — она была тёмно-синей плитой и
   выбивалась из кабинета сильнее всего именно у новичка, который видит её
   первой. Отсутствие доступа показывает не цвет карточки, а её чип и
   приглушённая кайма: цветом кричать не о чем, человек просто ещё не начал. */
.me.dusk{background:var(--glass);border-color:rgba(255,255,255,.8)}
.me.dusk .ava{background:linear-gradient(180deg,#828C9B,#656F7D);color:#fff}
.me.dusk .tx b{color:var(--soft)}
.me.dusk .chip{background:#FDF4E6;border-color:#E6CE9F;color:#8A5310}
.me.dusk .chip i{background:var(--warn);box-shadow:0 0 0 3px rgba(178,107,18,.18)}

/* Датчики расхода. На главной те же числа стоят счётчиками — там важно
   «сколько осталось». Здесь важно «сколько из сколького», а это показывает
   полоса, а не цифра. */
.gauges{display:grid;gap:12px;margin-top:13px}
.gauge .t{display:flex;align-items:baseline;justify-content:space-between;gap:10px;font-size:13px}
.gauge .t span{color:var(--mute)}
.gauge .t b{font-weight:800;letter-spacing:-.01em}
.gauge .t b.warn{color:var(--warn)}
.gauge .t b.bad{color:var(--bad)}

/* Состав тарифа списком с галочками — та же деталь, что на витрине: человек
   уже видел её при покупке и узнаёт, что читает про то же самое. */
.card>.feat{margin:11px 0 0;padding:0;list-style:none;display:grid;gap:7px;
  font-size:13.5px;color:var(--soft)}
.card>.feat li{display:flex;gap:9px;align-items:flex-start;line-height:1.35}
.card>.feat li svg{flex:0 0 auto;margin-top:3px;color:var(--brand)}

/* Флаги стран. Крупно и в один ряд: это единственная строка экрана, которую
   читают картинкой, а не текстом. */
.locs{display:flex;align-items:center;gap:11px;margin-top:12px;padding:9px 12px;
  border-radius:var(--r);background:var(--tint);border:1px solid var(--line)}
.locs b{flex:0 0 auto;font-size:17px;letter-spacing:.08em;line-height:1.2}
.locs span{font-size:12.5px;font-weight:500;color:var(--mute)}

/* Действия профиля. Главная кнопка во всю ширину, остальное — плитками по
   две: «докупить трафик» и «поддержка» одинаково важны и одинаково редки,
   и список строк ради них занимал пол-экрана. */
.acts-wrap{margin-top:12px;display:grid;gap:8px}
.acts{display:grid;grid-template-columns:1fr 1fr;gap:8px}
/* Нечётная последняя плитка растягивается: дыра в половину ряда читается как
   недогруженный экран. */
.acts>:last-child:nth-child(odd){grid-column:1/-1}
/* Иконка слева от подписи, а не над ней: столбиком плитка вырастала вдвое,
   и нижняя пара уезжала под нижний бар — а это ровно «поддержка», за которой
   идут в самый неудачный момент. */
.act{display:flex;align-items:center;gap:9px;
  padding:9px 10px;border:1px solid var(--line);border-radius:var(--r);cursor:pointer;
  font-family:var(--font);text-align:left;color:var(--ink);
  background:linear-gradient(180deg,#fff,#FBFDFF);
  box-shadow:0 1px 2px rgba(10,22,44,.06),0 6px 16px rgba(10,22,44,.06),var(--edge);
  transition:transform .1s ease,box-shadow .16s ease}
.act .ic{flex:0 0 auto;width:31px;height:31px;border-radius:10px;display:grid;place-items:center;
  background:var(--brand-soft);color:var(--brand-deep)}
.act .ic svg{width:17px;height:17px}
/* Подпись в одну строку: перенос делал соседние плитки разной плотности и
   ряд читался как случайно свёрстанный. */
.act b{min-width:0;font-size:13px;font-weight:800;letter-spacing:-.02em;line-height:1.2;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.act:active{transform:translateY(1px);
  box-shadow:inset 0 2px 6px rgba(10,22,44,.10)}

/* ─────────────────────────── кнопки */
.btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;
  height:45px;border:0;border-radius:var(--r);cursor:pointer;
  font-family:var(--font);font-size:16px;font-weight:800;letter-spacing:-.01em;
  text-decoration:none;
  /* Верхний стоп темнее чистого #1877FF ровно настолько, чтобы белая
     подпись прошла 4.5:1: на глаз кнопка та же, читается — лучше. */
  background:linear-gradient(180deg,#2E86FF,var(--cta-deep) 62%,#0A44B4);color:#fff;
  /* Стеклянная кнопка: блик по верхней кромке, тёплый свет внутри сверху и
     тень по нижней. Размытия под ней нет намеренно — она лежит на плотном
     листе, размывать нечего, а живой слой стоил бы кадров на каждой
     прокрутке. Стекло здесь делает свет, а не блюр. */
  box-shadow:var(--sh-2),inset 0 1px 0 rgba(255,255,255,.42),
             inset 0 6px 14px rgba(255,255,255,.16),
             inset 0 -1px 0 rgba(0,0,0,.22);
  position:relative;overflow:hidden;isolation:isolate;
  transition:transform .1s ease,box-shadow .16s ease,filter .16s ease}
/* Верхняя половина светлее нижней — та самая «капля стекла» с iOS.
   Псевдоэлемент, а не второй фон: градиент фона держит цвет кнопки, а этот
   слой только свет, и его не надо пересчитывать при смене состояния. */
.btn::after{content:'';position:absolute;left:0;right:0;top:0;height:52%;z-index:-1;
  background:linear-gradient(180deg,rgba(255,255,255,.22),rgba(255,255,255,0));
  border-radius:var(--r) var(--r) 40% 40%/var(--r) var(--r) 12px 12px;
  pointer-events:none}
/* Нажатие вдавливает, а не сдвигает: сдвиг на пиксель на телефоне не читается. */
.btn:active{transform:translateY(1px);filter:brightness(.96);
  box-shadow:0 1px 3px rgba(11,79,208,.3),inset 0 3px 7px rgba(0,0,0,.24)}
.btn[disabled]{opacity:.55;box-shadow:none;pointer-events:none}
/* Кнопка в работе. Гасить её прозрачностью нельзя: подпись «Проверяем…» —
   самый долгий кадр сценария, и человек смотрит именно на неё, а на 55%
   белое по зелёному даёт 2.3:1. Занятость показывает свет, бегущий по
   кнопке, а не выцветший текст. */
.btn.busy{pointer-events:none;position:relative;overflow:hidden}
.btn.busy::after{content:'';position:absolute;left:0;top:0;bottom:0;width:40%;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.38),transparent);
  animation:sweep 1s linear infinite}
.btn.ghost.busy{border-color:var(--line-strong)}
.btn.ghost.busy::after{background:linear-gradient(90deg,transparent,rgba(67,97,140,.16),transparent)}
/* Ответ «сделано» на той же кнопке, куда человек смотрит. */
.btn.ok{pointer-events:none;background:linear-gradient(180deg,#E7F0FF,#CFE0FA);
  border:1px solid var(--cta);color:var(--brand-deep);box-shadow:none}
/* Отказ виден там же, где нажали, а не только всплывашкой снизу. */
.btn.no{animation:no .32s cubic-bezier(.36,.07,.19,.97)}
@keyframes no{10%,90%{transform:translateX(-3px)}30%,70%{transform:translateX(4px)}
  50%{transform:translateX(-4px)}}
/* Вторая кнопка — белая с зелёным контуром. Светло-зелёной заливкой она
   становилась близнецом поля ссылки под ней: две одинаковые плашки, и
   непонятно, какая из них нажимается. Контур говорит «кнопка», заливка —
   «поле». */
.btn.ghost{background:linear-gradient(180deg,#fff,#F2F7FF);color:var(--brand-deep);
  border:1.5px solid rgba(51,83,129,.34);
  box-shadow:0 1px 2px rgba(10,22,44,.05),inset 0 1px 0 rgba(255,255,255,.9)}
.btn.ghost::after{background:linear-gradient(180deg,rgba(255,255,255,.75),rgba(255,255,255,0))}
.btn.ghost:active{filter:none;background:var(--brand-soft);
  box-shadow:inset 0 2px 6px rgba(10,22,44,.12)}
/* Главная кнопка экрана. Выше обычной, со значком слева и с зелёным
   отсветом под ней: рядом со второй кнопкой того же роста, отличавшейся
   только заливкой, человек выбирал между двумя равными, вместо того чтобы
   нажать очевидное. Разницу держат три вещи сразу — рост, значок и тень. */
.btn.lead{height:54px;font-size:17px;gap:10px;
  box-shadow:0 2px 4px rgba(11,79,208,.28),0 12px 24px rgba(43,71,112,.34),
             inset 0 1px 0 rgba(255,255,255,.30),inset 0 -1px 0 rgba(0,0,0,.16)}
.btn.lead:active{box-shadow:0 1px 3px rgba(11,79,208,.3),inset 0 3px 7px rgba(0,0,0,.24)}
.btn .bic{display:grid;place-items:center;width:22px;height:22px;flex:0 0 auto}
.btn .bic svg{width:20px;height:20px}
/* Вторая кнопка тише главной: ниже ростом и на светлом поле, а не на белом.
   Белая на белой карточке она выглядела такой же важной. */
.btn.ghost{height:44px;font-size:15.5px}
.btn.soft{background:var(--brand-soft);color:var(--brand-deep);box-shadow:none}
.btn.sm{height:44px;font-size:15px}
.btns{display:grid;gap:8px;margin-top:11px}
.btns.two{grid-template-columns:1fr 1fr}

/* ─────────────────────────── первый шаг

   Карточка человека без подписки — единственное, что он читает целиком, и
   набрана она крупнее остальных: здесь не сводка по своему тарифу, где
   мелкий кегль экономит место, а объяснение, ради которого экран и открыт. */
/* Стекло, а не белая заливка. Все числа ниже сняты пипеткой с макета
   владельца, а не подобраны на глаз:

   — заливка на макете 30% белого: внутри карточки пиксель (214,234,253)
     при фоне под ней (199,224,252). У нас лист светлее макетного
     (--page #E4EEFF против (199,224,252)), и на нём те же 30% почти не
     читались — заливка поднята до 45%, чтобы разница с фоном осталась
     такой же, как на макете;
   — кант в один пиксель чистого белого — на макете слева стоит (255,255,255);
   — свечение внутрь примерно на восемь точек от края: у канта (226,241,253),
     а к середине карточка садится до (214,233,253);
   — тени под карточкой нет вовсе: пиксель слева от канта (207,227,253) —
     это чистый фон страницы, без потемнения. Оставлена только мягкая
     подсветка отлёта, иначе на светлом листе карточка теряет край.

   Размытый слой на экране один: пилюля, плитки и кружки внутри берут
   стекло полупрозрачной заливкой поверх уже размытой подложки, своего
   backdrop-filter у них нет — иначе вебвью считало бы шесть живых слоёв
   на каждую прокрутку. */
.card.lead.start{padding:18px 18px 16px}
.card.lead.start .lbl{font-size:10.5px;letter-spacing:.1em;color:var(--soft)}
/* Заголовок первого шага крупнее всех остальных на экране. Это не
   подпись к карточке, а само предложение — единственное, ради чего
   человек без подписки сюда пришёл, и набрано оно как заголовок
   страницы, а не как строка списка. */
.card.lead.start h2{margin-top:9px;font-size:25px;line-height:1.14;
  letter-spacing:-.028em}
.card.lead.start p.sub{margin-top:7px;font-size:14px;line-height:1.42}
/* Срок и объём — единственные числа экрана: тёмным и жирным, чтобы их
   находили, не читая строку целиком. */
.card.lead.start p.sub b{font-weight:800;color:var(--ink)}
.card.lead.start .btns{margin-top:12px;gap:8px}
/* Условие названо до нажатия, но громким оно быть не должно: это сноска к
   кнопке, а не второе предложение экрана. */
.card.lead.start .note.chan{margin-top:9px;font-size:11.5px;font-weight:500;
  color:var(--mute);gap:6px}
.card.lead.start .note.chan svg{width:13px;height:13px}

/* Две кнопки первого шага — одного роста и одной формы, как на макете
   владельца: разницу между ними держат заливка и порядок, а не рост со
   значком. Значка на них нет вовсе — подпись и так называет действие
   целиком, а тележка на бесплатном пробном ещё и обещала оплату. */
/* Метка и состояние одной строкой: слева о чём карточка, справа что
   сейчас. Чип статуса переехал сюда с баннера — надписей поверх шапки нет. */
.st-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.pill{display:inline-flex;align-items:center;gap:7px;flex:0 0 auto;
  padding:6px 12px;border-radius:var(--pill);
  /* На макете пилюля (219,230,251) при карточке (215,234,253) — тот же
     материал, чуть плотнее и чуть холоднее. */
  background:rgba(255,255,255,.40);
  border:1px solid rgba(255,255,255,.85);
  box-shadow:var(--glass-in-lift);
  font-size:12.5px;font-weight:800;color:var(--soft);white-space:nowrap}
.pill i{width:7px;height:7px;border-radius:50%;background:var(--brand);flex:0 0 auto}
/* Серый, а не красный: подписки просто ещё нет, ничего не сломалось. */
.pill.off i{background:#8698B4}

/* Три условия плитками. Подписи короткие и в одну строку — на узком
   экране «Без карты» переносом разгонял бы полосу на две строки. */
/* Не три равные колонки, а строка по содержимому. «Без карты» длиннее
   двух других подписей, и в равной трети оно не помещалось — обрезалось
   многоточием ровно на том слове, ради которого плитка и стоит. Теперь
   каждая плитка берёт свою ширину, а остаток делится поровну; на совсем
   узком экране третья уходит на вторую строку, а не режется. */
.facts{display:flex;flex-wrap:wrap;gap:7px;margin-top:13px}
.facts .f{display:flex;align-items:center;justify-content:center;gap:6px;
  flex:1 1 auto;min-width:max-content;padding:10px 11px;
  border-radius:16px;
  background:var(--glass-in);border:1px solid var(--glass-in-edge);
  box-shadow:var(--glass-in-lift)}
.facts .f .i{display:grid;place-items:center;width:18px;height:18px;flex:0 0 auto;
  color:var(--brand-deep)}
.facts .f .i svg{width:17px;height:17px}
/* Без обрезки многоточием: плитка теперь растёт под подпись, и прятать
   в ней нечего. */
.facts .f b{font-size:12.5px;font-weight:800;letter-spacing:-.018em;white-space:nowrap}

/* Главная кнопка первого шага. Стрелка прижата к правому краю, а не стоит
   за подписью: подпись остаётся по центру кнопки, как на всех остальных
   экранах, и кружок читается отдельной деталью «уводит дальше». */
/* Кнопка макета — не наш общий синий: он глуше и темнеет книзу, а на
   макете синий электрический и снизу снова светлеет ободком.

   Тринадцать стопов, снятых пипеткой, на кнопке в 54 точки давали полосы:
   между соседними стопами оставалось по три-четыре пикселя, и вебвью
   рисовал не переход, а лесенку из заливок. Профиль тот же, но собран
   из трёх частей, каждая из которых плавная сама по себе:
   градиент в три стопа держит цвет, блик сверху рисует ::after,
   а светлый ободок снизу — внутренняя тень. Резких границ в самой
   заливке не осталось, и полосить нечему. */
.btn.big.go{margin-top:13px;
  background:linear-gradient(180deg,#3A8BFF 0%,#1A56F6 60%,#1E5CF0 100%);
  /* Ободок снизу короткий: на макете он в полторы точки, а не в треть
     кнопки. Растянутый на 12–16 точек он превращал нижнюю треть в молоко —
     синий под ним выцветал, и кнопка переставала быть синей. */
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45),
             inset 0 -5px 7px -5px rgba(255,255,255,.5),
             inset 0 -1px 0 rgba(255,255,255,.40),
             0 2px 6px rgba(11,79,208,.28),0 12px 26px rgba(24,90,200,.32)}
/* Блик верхней половины — свой, а не общий кнопочный: на макете он ярче
   общего, но гаснет быстро, и белым кнопку не заливает. */
.btn.big.go::after{height:52%;
  background:linear-gradient(180deg,rgba(255,255,255,.26),
    rgba(255,255,255,.04) 70%,rgba(255,255,255,0))}
.btn.big.go:active{box-shadow:inset 0 3px 7px rgba(0,0,0,.22),
             0 1px 3px rgba(11,79,208,.3)}
/* Кружок стрелки: на макете 36 точек при кнопке в 54, внутри (78,126,240)
   на поле (36,99,253) — примерно .19 белого. */
.btn.big.go .arw{position:absolute;right:9px;top:50%;margin-top:-18px;
  width:36px;height:36px;border-radius:50%;display:grid;place-items:center;
  background:rgba(255,255,255,.19);
  border:1px solid rgba(255,255,255,.26)}
.btn.big.go .arw svg{width:18px;height:18px}
/* Черта между главным действием и вторым путём: без неё строка «Купить
   сразу» читалась продолжением кнопки. */
/* Второй путь — своим блоком на стекле, а не голой строкой. Материал тот
   же, что у плиток условий: заливка в треть белого и кант, — чтобы блок
   читался вложенным в карточку, а не наклеенным сверху другой вещью.
   Черты над ним нет: кант блока уже отделяет его от кнопки, а черта плюс
   кант давали два шва подряд. */
.tip.pane{margin-top:12px;padding:10px 12px;border-radius:16px;
  background:var(--glass-in);border:1px solid var(--glass-in-edge);
  box-shadow:var(--glass-in-lift)}
.tip.pane:active{transform:translateY(1px);
  box-shadow:inset 0 2px 6px rgba(10,22,44,.09)}

.btn.big{height:54px;border-radius:14px;font-size:16.5px;letter-spacing:-.012em;
  background:linear-gradient(180deg,#3C5D8C,var(--cta-deep) 60%,#263F65);
  box-shadow:0 2px 5px rgba(11,79,208,.26),0 10px 22px rgba(43,71,112,.28),
             inset 0 1px 0 rgba(255,255,255,.30),inset 0 -1px 0 rgba(0,0,0,.16)}
.btn.big.ghost{height:54px;font-size:16.5px;background:#fff;
  box-shadow:0 1px 2px rgba(10,22,44,.05)}

/* ─────────────────────────── полосы */
.meter{margin-top:6px;height:8px;border-radius:var(--pill);background:var(--brand-soft);overflow:hidden}
.meter i{display:block;height:100%;border-radius:var(--pill);
  background:linear-gradient(90deg,#5AA7FF,#1877FF);transition:width .5s cubic-bezier(.22,1,.36,1)}
.meter i.warn{background:linear-gradient(90deg,#E8B14C,#C8892A)}
.meter i.bad{background:linear-gradient(90deg,#D9705F,#B3261E)}


/* ─────────────────────────── магазин */

/* Переключатель разделов. Бегунок отдельным элементом, а не рамкой на
   кнопке: так он едет между разделами, и переход виден движением, а не
   перекраской. */
/* Авторское display:grid сильнее браузерного правила для [hidden], поэтому
   скрытие приходится объявлять самим — иначе переключатель оставался
   висеть на внутренних шагах покупки. */
.seg[hidden]{display:none}
.seg{position:relative;display:grid;grid-template-columns:repeat(3,1fr);gap:0;
  margin-top:14px;padding:4px;border-radius:var(--pill);
  background:rgba(255,255,255,.26);
  border:1px solid rgba(255,255,255,.66);
  box-shadow:inset 0 2px 6px rgba(10,22,44,.10)}
.seg .pin{position:absolute;top:4px;bottom:4px;left:4px;width:calc((100% - 8px)/3);
  /* Капсула выбранного раздела — плотная, а не стеклянная. Полупрозрачной
     она пропускала сквозь себя вдавленную тень дорожки, и под её нижним
     краем оставалась светлая полоса: дорожка там светлее самой капсулы.
     Это единственная деталь кабинета, которая обязана быть непрозрачной, —
     она не поверхность, а положение переключателя.

     Отлётная тень `0 4px 10px` убрана по той же причине: на стеклянной
     дорожке она читалась не тенью, а мутным пятном под капсулой. Осталась
     контактная в одну точку — её хватает, чтобы капсула лежала сверху. */
  border-radius:var(--pill);background:linear-gradient(180deg,#fff,#F1F6FF);
  box-shadow:0 1px 2px rgba(10,22,44,.14),inset 0 1px 0 rgba(255,255,255,.95);
  transition:transform .28s cubic-bezier(.22,1,.36,1)}
.seg button{position:relative;z-index:1;border:0;background:none;cursor:pointer;
  font-family:var(--font);font-size:13.5px;font-weight:800;letter-spacing:-.01em;
  color:var(--mute);height:38px;transition:color .2s ease}
.seg button.on{color:var(--brand-deep)}

/* Строка тарифа. Свёрнутая — это одна строка: название, короткая суть и цена
   «от». Развёрнутая добавляет сроки и кнопку. */
.tar{position:relative;background:var(--glass);
  border:1px solid var(--glass-edge);border-radius:var(--r-lg);margin-top:10px;
  box-shadow:var(--glass-lift);overflow:hidden}
/* Карточка тарифа — целиком кнопка: попасть по строке проще, чем по
   стрелке, а промах здесь стоит покупки. */
.tar.pick{display:block;width:100%;text-align:left;font-family:var(--font);
  padding:14px 15px;cursor:pointer;margin-top:10px}
/* Рекомендованный тариф весит больше соседей: зелёная грань, тёплая
   подложка и своя тень. Раньше все три карточки были одинаковыми, и метка
   «выбирают» мелким шрифтом внутри строки названия эту разницу не делала. */
.tar.pick.hot{border-color:var(--cta);
  background:linear-gradient(180deg,#F6F9FE,#E9EFF8);
  box-shadow:0 2px 5px rgba(11,79,208,.10),0 12px 26px rgba(11,79,208,.13),var(--edge)}
.tar.pick.mine{border-color:rgba(122,158,214,.75);background:var(--glass-hi)}
/* Лента поверх верхней грани: она объявляет карточку до того, как её
   начнут читать, и не отнимает место у названия. */
.tar .flag{position:absolute;top:-1px;right:12px;z-index:2;
  font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  color:#fff;background:linear-gradient(180deg,#2E86FF,var(--cta-deep));
  padding:4px 10px 5px;border-radius:0 0 var(--r-sm) var(--r-sm);
  box-shadow:0 2px 6px rgba(11,79,208,.28)}
.tar .flag.own{background:linear-gradient(180deg,#828C9B,#656F7D)}
.tar.pick.hot,.tar.pick.mine{padding-top:20px}
.tar.pick:active{transform:translateY(1px);box-shadow:inset 0 2px 8px rgba(10,22,44,.10)}
.tar.pick .hd{padding:0;cursor:default;align-items:center}
/* Стрелка стоит в шапке, у цены: подвал держался только на флагах, а без
   них это была строка ради одной стрелки. */
.tar .hd .ch{flex:0 0 auto;color:var(--line-strong);display:flex;align-self:center}
/* Метка стоит в строке с названием, а не поверх карточки: в углу она
   наезжала на цену и на стрелку. */
.tar .hd .nm b .mark{display:inline-block;margin-left:6px;vertical-align:2px;
  font-size:8px;font-weight:800;text-transform:uppercase;letter-spacing:.02em;
  color:#fff;background:linear-gradient(180deg,#2E86FF,var(--cta-deep));padding:2px 6px 3px;
  border-radius:var(--pill);box-shadow:0 1px 3px rgba(11,79,208,.22)}
.tar .hd .nm b .mark.hot{background:#FBEFD6;color:#8A5A0F}
.tar .hd{display:flex;align-items:flex-start;gap:12px;padding:14px 15px;cursor:pointer;
  width:100%;border:0;background:none;font-family:var(--font);text-align:left}
.tar .hd .nm{min-width:0;flex:1}
.tar .hd .nm b{display:block;font-size:16.5px;font-weight:800;letter-spacing:-.015em;
  color:var(--ink)}
.tar.pick.hot .hd .nm b{color:var(--brand-deep)}
/* Узкий экран: цена и стрелка на ступень мельче. */
@media (max-width:400px){
  .tar .hd .pr b{font-size:19px}
  .tar .hd .pr u{font-size:9.5px}
  .tar .hd .ch{width:26px;height:26px}
  .tar .hd{gap:8px}
  .tar.pick{padding:13px 12px}
}
.tar .hd .pr{flex:0 0 auto;text-align:right}
.tar .hd .pr b{display:block;font-size:22px;font-weight:800;color:var(--cta);
  letter-spacing:-.025em;line-height:1.05}
.tar.pick.hot .hd .pr b{color:var(--cta-deep)}
/* За какой срок эта цена. Без неё «от 159 ₽» и «от 99 ₽» сравнивались как
   равные, хотя короткий срок у тарифов разный. */
.tar .hd .pr u{display:block;text-decoration:none;margin-top:2px;
  font-size:10.5px;font-weight:600;color:var(--mute);white-space:nowrap}
.tar .hd .pr i{font-style:normal;display:block;font-size:10px;color:var(--mute);
  text-transform:uppercase;letter-spacing:.06em}
/* Стрелка в кружке: у неё появляется вес, и промах по карточке перестаёт
   выглядеть промахом по пустому месту. */
.tar .hd .ch{flex:0 0 auto;width:28px;height:28px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--brand-soft);color:var(--brand-deep);
  transition:transform .26s cubic-bezier(.22,1,.36,1),background .2s ease}
.tar.pick.hot .hd .ch{background:linear-gradient(180deg,#2E86FF,var(--cta-deep));color:#fff}
.tar.pick:active .hd .ch{transform:translateX(2px)}
.tar.on .hd .ch{transform:rotate(90deg)}

/* Раскрытая часть отделяется от шапки материалом: тон, внутренняя тень и
   линия сверху.

   Травяного узора здесь нет намеренно. Он стоял ровно под ценами и
   галочками — не за карточками, как на фоне страницы, а прямо под текстом,
   и рябил так, что цифры переставали читаться. Фактура нужна там, где на
   неё не смотрят. */
.tar.on .body>*{opacity:1;transform:none}
.tar .feat{margin:9px 0 0;padding:0;list-style:none;display:grid;gap:4px;
  font-size:12.5px;font-weight:500;color:var(--soft)}
.tar .feat li{display:flex;gap:7px;align-items:flex-start}
.tar .feat li svg{flex:0 0 auto;margin-top:2px;color:var(--brand)}

/* Список тарифов: три карточки делят высоту экрана и помещаются в него
   целиком — витрину не листают.

   Прошлый заход прятал на низком поле строку отличия, полку и иконки, и от
   карточки оставались название с ценой на полторы сотни пикселей. Теперь
   ничего не исчезает: на коротком экране ступенями (`max-height` ниже)
   мельчает кегль и сжимаются отступы. */
/* Высота берётся из переменной, которую ставит скрипт по данным Telegram;
   `100svh` остаётся запасным значением для обычного браузера. */
/* Высота экрана, а не «не меньше экрана». С `min-height` лист охотно рос
   ниже видимой области, и разделы, которые обязаны вставать целиком, всё
   равно листались: ужиматься содержимому было некуда — место всегда
   находилось. Теперь высота ровно та, что отдал Telegram, и остаток делят
   между собой карточки. */
body[data-tab="shop"] .app{height:var(--app-h,100svh);
  min-height:var(--app-h,100svh);display:flex;flex-direction:column}
body[data-tab="shop"] #s-shop{flex:1;display:flex;flex-direction:column;min-height:0}
/* Замок ставится только на разделы, чьё содержимое умеет ужиматься (класс
   вешает renderShop). На объясняющих карточках его нет — там прокрутка
   честнее срезанного низа. */
body[data-tab="shop"] #s-shop.lock{overflow:hidden}
body[data-tab="shop"] #s-shop.lock #shop-body{min-height:0}
/* Единственная карточка раздела (счётчик слотов) делит высоту так же, как
   три карточки витрины: содержимое расходится по ней, а не жмётся кверху. */
/* Заголовок раздела (.card.flat) — тоже .card, но растягивать его нельзя:
   подпись уезжала вниз, между ней и заголовком зияла пустота, а срез по краю
   съедал первую букву («Слоты» → «лоты»). */
#shop-body.fill.solo>.card:not(.flat){flex:1 1 auto;min-height:0;display:flex;
  flex-direction:column;justify-content:space-between;overflow:hidden}
#shop-body.fill.solo>.card:not(.flat)>.swap{margin-top:0}
#shop-body.fill.solo>.card.flat{flex:none}
/* Остаток высоты собирается ПОД списком, а не раскидывается между
   карточками. С `space-between` каждая лишняя точка экрана уходила в щели:
   на высоком поле карточки упирались в свой потолок, и между Стандартом и
   Семейным зияла дыра в полсотни точек — тем большая, чем выше телефон.
   Теперь промежуток всегда один и тот же, восемь точек, а излишек стоит
   внизу, где его закрывает нижнее меню. */
#shop-body.fill{flex:1;display:flex;flex-direction:column;min-height:0;
  justify-content:flex-start;padding-bottom:2px}
/* Свой отступ вместо общего у `.tar`: три карточки по десять пикселей
   съедали ровно ту высоту, которой не хватало третьей на низком экране. */
#shop-body.fill .tar.pick.grow{margin-top:8px}
#shop-body.fill .tar.pick.grow:first-child{margin-top:8px}
/* Потолок высоты есть: без него на высоком экране карточка растягивалась
   и дыра возвращалась уже внутрь неё. Излишек уходит в промежутки. */
/* `align-items:stretch` обязательно: без него секции сжимались по своему
   содержимому и карточка стояла полупустой при полной ширине. */
/* Высоту карточка делит только там, где витрина её делит, — то есть под
   `#shop-body.fill`. В базовом наборе `flex:1 1 0` стоять не может: в
   широком макете (от 960 px) все ленты экранов сами становятся flex-
   колонками по высоте содержимого, и `flex-basis:0` схлопывал карточку до
   `min-height`, а `overflow:hidden` срезал ей низ — плитка состава уходила
   под нижнюю грань на семь точек. Ровно это и читалось как «бар обрезан». */
.tar.pick.grow{flex:0 0 auto;min-height:126px;max-height:190px;
  display:flex;flex-direction:column;align-items:stretch;
  padding:0;overflow:hidden;margin-top:10px}
#shop-body.fill .tar.pick.grow{flex:1 1 0;max-height:230px}
/* Полка состава прижата к нижнему краю карточки. Карточки растянуты до
   одной высоты, а содержимого у них разное количество — и лишнее место
   падало под полку дырой внутри карточки, ровно той, что читалась как
   кривой отступ между тарифами. Теперь полки всех трёх стоят на одной
   линии, а воздух распределён над ними. */
#shop-body.fill .tar.grow>.spec{margin-top:auto}

/* Карточка по макету: знак тарифа в кружке слева, название со строкой
   отличия, цена справа, состав — отдельной светлой плиткой внизу.
   Рекомендованный тариф идёт тёмной шапкой в золотой грани: он должен
   отличаться от соседей материалом, а не одной лентой. */
.tar.pick.grow{border-radius:var(--r-lg)}
.tar.grow .sec{padding:11px 13px 10px}
.tar.grow .sec.lead{flex:0 0 auto}
/* Шапка внутри секции: ширину задаём явно — без неё цена не уезжала
   вправо и стояла впритык к названию. */
.tar.grow .hd{padding:0;width:100%;gap:10px;align-items:center}
/* Блок цены опущен на пару точек: сумма набрана крупнее названия, и по
   верхнему краю она вставала выше него. */
.tar.grow .hd .pr{padding-left:2px;margin-top:3px}
/* Знак тарифа. Кружок, а не голая иконка: на светлой карточке иконка без
   подложки читается как случайная закорючка рядом с названием. */
.tar .emb{flex:0 0 auto;width:38px;height:38px;border-radius:50%;
  display:grid;place-items:center;color:var(--brand-deep);
  background:linear-gradient(180deg,#E4EBF4,#CFE0FA);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 1px 2px rgba(10,22,44,.08)}
.tar .emb svg{width:20px;height:20px}
.tar.grow .hd .nm{flex:1 1 auto;min-width:0}
.tar.grow .hd .nm b{font-size:18px;line-height:1.2;display:block}
.tar.grow .hd .pr b{font-size:24px}
/* «от» — приставка к сумме, а не строка над ней: строкой оно стоило
   двенадцати точек высоты в каждой карточке. */
.tar.grow .hd .pr b{display:flex;align-items:baseline;justify-content:flex-end;gap:4px}
.tar.grow .hd .pr b i{font-style:normal;display:inline;font-size:11px;font-weight:800;
  color:var(--mute);text-transform:uppercase;letter-spacing:.06em}
.tar.grow .hd .pr>i{font-size:10px}
.tar.grow .hd .pr u{font-size:11px;margin-top:2px;font-weight:600}
.tar.grow .hd .ch{width:26px;height:26px;align-self:center;
  background:var(--tint);border:1px solid var(--line);color:var(--line-strong)}
/* Строка отличия: у каждого тарифа своя. Стоит под названием, в одной с
   ним колонке — иначе уходит под знак тарифа и ломает левый край. */
.tar.grow .why{display:block;margin:6px 0 0;padding-left:48px;font-size:13px;
  line-height:1.3;color:var(--mute);font-weight:500}

/* Состав — плитка внутри карточки: свой тон, своё скругление и отступ от
   краёв. Волосяной линией это читалось как подвал, плиткой — как состав.

   Тон заметно темнее карточки (владелец, 05.09.2026: «бар будто не бар»):
   на прежнем почти белом фоне плитка сливалась с белым полем вокруг, и три
   колонки читались как продолжение карточки, а не как отдельная полоса. */
.tar.grow .spec{flex:1;display:grid;grid-template-columns:repeat(3,1fr);
  align-items:center;gap:0;margin:0 10px 10px;padding:8px 2px;
  background:#E4ECFB;border:1px solid var(--line-2);border-radius:var(--r);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.55)}
.tar.grow .sec+.sec{border-top:0}
/* Значок слева, цифра с подписью — по центру своей колонки: цифра короче
   подписи, и по левому краю она висела сбоку от неё. */
.tar .cl{position:relative;display:flex;align-items:center;justify-content:center;
  gap:7px;text-align:center;padding:0 4px;min-width:0}
.tar .cl+.cl::before{content:'';position:absolute;left:0;top:50%;
  transform:translateY(-50%);height:30px;width:1px;background:var(--line-2)}
/* Значок состава в кружке — как на макете: он держит строку и отделяет
   цифру от соседней колонки лучше, чем один разделитель. */
.tar .cl .ic{flex:0 0 auto;width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;color:var(--brand);background:#fff;
  border:1px solid var(--line);line-height:0}
.tar .cl .ic svg{width:15px;height:15px}
.tar .cl .tx{min-width:0;text-align:center}
.tar .cl b{display:block;font-size:17px;font-weight:800;letter-spacing:-.02em;
  color:var(--ink);line-height:1.1;white-space:nowrap}
/* Знак безлимита. Крупнее цифр и с прижатой строкой: у ∞ нет выносных, в
   один кегль с «50 ГБ» он читается мельче соседей, а высоты плитке при
   этом не прибавляет — line-height держит строку на месте. */
.tar .cl b.inf{font-size:23px;line-height:.81;letter-spacing:0}
/* Подпись целиком, а не многоточием: «LTE-СЕРВЕРА» и «УСТРОЙСТВА» в трети
   ширины не помещались, и на экране висело «LTE-СЕРВЕР…». Кегль мельче,
   разрядка почти снята, перенос разрешён. */
/* Слово не рвётся посреди себя. `overflow-wrap:anywhere` разрешал разрыв в
   любом месте, и «УСТРОЙСТВА» не влезало ровно на одну букву: на экране
   стояло «УСТРОЙСТВ» и «А» отдельной строкой. Подпись здесь всегда одно
   слово (или «LTE-СЕРВЕРА» через дефис), переносить в ней нечего — значит
   она обязана поместиться целиком, и место ей даёт кегль и разрядка, а не
   разрыв. */
.tar .cl span{display:block;margin-top:2px;font-size:8.5px;font-weight:700;
  text-transform:uppercase;letter-spacing:0;color:var(--mute);
  line-height:1.15;white-space:nowrap;overflow-wrap:normal}

/* ── рекомендованный тариф: тёмная шапка в золотой грани */
.tar.pick.grow.hot{border-color:#C9B072;background:#fff;
  box-shadow:0 2px 5px rgba(11,79,208,.12),0 14px 30px rgba(11,79,208,.16),
    inset 0 0 0 1px rgba(212,183,116,.5)}
.tar.grow.hot .sec.lead{position:relative;
  background:linear-gradient(135deg,#082B6E 0%,#0B4FD0 55%,#1877FF 100%);
  border-radius:calc(var(--r-lg) - 1px) calc(var(--r-lg) - 1px) 0 0;
  padding:12px 13px 11px}
.tar.grow.hot .hd,.tar.grow.hot .why{position:relative;z-index:1}
/* Между тёмной шапкой и плиткой состава — светлое поле: без него плитка
   читается продолжением шапки, а не вложенной в карточку. */
.tar.grow.hot .spec{margin-top:9px}
.tar.grow.hot .hd .nm b{color:#fff}
.tar.grow.hot .why{color:#CFE3FF}
.tar.grow.hot .hd .pr b{color:#fff}
.tar.grow.hot .hd .pr b i{color:#A5BAD7}
.tar.grow.hot .hd .pr u{color:#CFE3FF}
.tar.grow.hot .emb{color:#F2E3B4;background:linear-gradient(180deg,#364D6F,#263852);
  box-shadow:inset 0 0 0 1px rgba(226,203,138,.55),0 2px 6px rgba(0,0,0,.25)}
.tar.grow.hot .hd .ch{background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.35);
  color:#fff}
.tar.pick.hot:active .hd .ch{transform:translateX(2px)}
/* У рекомендованного низ карточки светлый, поэтому плитке нужен тот же
   шаг темнее — иначе на нём она пропадала сильнее, чем на обычном. */
.tar.grow.hot .spec{background:#CCD9EB;border-color:#ABBEDA}
.tar.grow.hot .cl+.cl::before{background:#A8BAD4}
.tar.grow.hot .cl b{color:var(--brand-deep)}
.tar.grow.hot .cl .ic{border-color:#BBD5FA}
/* Метка на тёмной шапке: своя, светлая — зелёная пилюля на зелёном фоне
   не читалась. */
.tar.grow.hot .hd .nm b .mark{background:rgba(255,255,255,.14);color:#DBE6F5;
  box-shadow:inset 0 0 0 1px rgba(187,205,232,.55)}

/* ── свой тариф */
.tar.pick.grow.mine{border-color:var(--line-2)}
.tar.grow.mine .emb{background:linear-gradient(180deg,#EAEDF1,#D9DEE5);color:var(--soft)}

/* Ступени по высоте поля: три карточки должны встать в экран целиком, и
   ради этого сжимаются отступы и кегль. Порядок жертв — от того, что
   ничего не сообщает, к тому, что сообщает меньше всех: сначала иконка в
   ячейке, потом кегль, и только на совсем коротком поле — строка отличия. */
body.h-760 .tar.grow .sec{padding:8px 14px 7px}
body.h-760 .tar.grow .spec{margin:0 10px 8px}
body.h-760 .tar.grow .hd .nm b{font-size:18.5px}
body.h-760 .tar.grow .hd .pr b{font-size:24px}
body.h-760 .tar.grow .why{margin-top:4px;font-size:12.5px}
body.h-760 .tar.grow .spec{padding:6px 4px}
body.h-760 .tar .emb{width:36px;height:36px}
body.h-760 .tar .cl .ic svg{width:17px;height:17px}
body.h-760 .tar .cl b{font-size:17px}
body.h-680 .tar.pick.grow{min-height:112px}
body.h-680 .tar .emb{width:36px;height:36px}
body.h-680 .tar.grow .hd .pr{margin-top:2px}
body.h-680 .tar.grow .sec{padding:8px 13px 7px}
body.h-680 .tar.grow .spec{margin:0 9px 7px;padding:6px 2px}
body.h-680 .tar.grow .hd .nm b{font-size:18px}
body.h-680 .tar.grow .hd .pr b{font-size:23px}
body.h-680 .tar.grow .hd .ch{width:26px;height:26px}
body.h-680 .tar.grow .why{font-size:12px;margin-top:4px}
body.h-680 .tar.grow .spec{padding:6px 4px}
/* Кружок значка меньше, но остаётся: он стоит слева от текста, а не над
   ним, и высоты карточки не прибавляет. */
body.h-680 .tar .cl .ic{width:26px;height:26px}
body.h-680 .tar .cl .ic svg{width:15px;height:15px}
body.h-680 .tar .cl{gap:7px;padding:0 4px}
body.h-680 .tar.grow.hot .spec{margin-top:6px}
body.h-680 .tar .cl b{font-size:16px}
/* Ниже 620 строка отличия уходит: без неё карточка теряет объяснение, с
   ней — не помещается, а обрезанная карточка хуже. */
body.h-700 .tar.grow .why{display:none}
body.h-700 .tar.grow.hot .spec{margin-top:4px}
body.h-700 .tar .emb{width:34px;height:34px}
body.h-700 .tar .emb svg{width:18px;height:18px}
body.h-700 .tar.grow .hd .pr{margin-top:1px}
/* Совсем короткое поле — сплит-экран, клавиатура поверх мини-аппа. */
body.h-590 .tar.pick.grow{min-height:96px}
body.h-590 .tar.grow .sec{padding:6px 12px 5px}
body.h-590 .tar.grow .spec{margin:0 8px 8px;padding:5px 2px}
body.h-590 .tar.grow.hot .spec{margin-top:3px}
body.h-590 .tar.grow .spec{padding:4px 2px}
body.h-590 .tar .cl .ic{width:22px;height:22px}
body.h-590 .tar .cl .ic svg{width:13px;height:13px}
body.h-590 .tar .emb{width:30px;height:30px}
body.h-590 .tar .emb svg{width:16px;height:16px}
body.h-590 .tar .cl b{font-size:15px}
body.h-590 .tar.pick.grow{min-height:100px}
body.h-590 .tar.grow .sec{padding:8px 13px}
body.h-590 .tar.grow .spec{padding:5px 4px}

/* Узкий экран: кегль на ступень ниже, ничего не исчезает. Подписям в
   колонках это важнее всего — «УСТРОЙСТВА» и «LTE-СЕРВЕРА» рвались
   посреди слова, когда на них оставалось семьдесят точек. */
@media (max-width:400px){
  .tar .cl{gap:5px;padding:0 2px}
  .tar .cl .ic{width:23px;height:23px}
  .tar .cl .ic svg{width:13px;height:13px}
  /* Подпись и число в ячейке объявлены здесь по одному разу. Раньше в этом
     же блоке стояли два набора подряд — 8px/16px выше и 9.5px/14.5px ниже,
     — и работал только нижний. Верхний читался как действующий и врал про
     то, каким кеглем набрана полоса на узком экране. */
  .tar .cl span{font-size:8.5px;letter-spacing:0}
  .tar .cl b{font-size:14.5px}
  .tar .emb{width:34px;height:34px}
  .tar .emb svg{width:18px;height:18px}
  .tar.grow .spec{margin:0 8px 9px}
  .tar.grow .hd .nm b{font-size:17px}
  .tar.grow .hd .pr b{font-size:22px}
  .tar.grow .why{font-size:12px}
  .tar.grow .sec{padding:10px 12px 9px}
}

@media (max-width:369px){
  .tar .cl{gap:3px;padding:0}
  .tar .cl .ic{width:20px;height:20px}
  .tar .cl span{font-size:6.5px;letter-spacing:-.01em}
  .tar .cl b{font-size:15px}
  .tar.grow .spec{margin:0 7px 8px}
}

/* ── розницу купить нельзя: тёмная карточка с причиной и три шага

   Экран показывается тому, у кого нет действующей подписки, — то есть
   человеку, который пришёл покупать и получил отказ. Поэтому здесь не
   строка-предупреждение, а объяснение порядка: сначала тариф, потом
   гигабайты, и что купленное живёт до конца оплаченного срока. */
.card.stop{position:relative;overflow:hidden;margin-top:14px;padding:17px 16px 16px;
  border:0;border-radius:var(--r-lg);color:#fff;
  background:linear-gradient(135deg,#082B6E 0%,#0B4FD0 58%,#1877FF 100%);
  box-shadow:0 2px 6px rgba(11,79,208,.16),0 16px 34px rgba(11,79,208,.18)}
/* Крупный знак справа — то же, что на кнопке раздела: он говорит, о чём
   карточка, раньше заголовка. Под текст не лезет: у него своя половина. */
.card.stop .art{position:absolute;right:16px;top:46px;width:86px;height:86px;
  color:#7A9CCC;opacity:.55;pointer-events:none}
.card.stop .art svg{width:100%;height:100%;stroke-width:1.6}
.card.stop .lbl,.card.stop h2,.card.stop .sub,.card.stop .btn{position:relative;z-index:1}
.card.stop .lbl{color:#99B1D4}
.card.stop h2{margin:5px 0 0;font-size:23px;font-weight:800;letter-spacing:-.025em;
  color:#fff;line-height:1.15}
.card.stop .sub{margin:8px 0 0;max-width:74%;font-size:13.5px;line-height:1.45;
  color:#C7D5E8}
.card.stop .btn{margin-top:14px}
/* Белая кнопка на тёмном: зелёная на зелёном не читается как действие. */
.btn.light{background:#fff;color:var(--brand-deep);
  box-shadow:0 2px 4px rgba(0,0,0,.18),0 8px 18px rgba(0,0,0,.16)}
.btn.light:active{filter:brightness(.97)}

.card.how{margin-top:12px;padding:16px 16px 14px}
.card.how h3{margin:0;font-size:16.5px;font-weight:800;letter-spacing:-.015em;color:var(--ink)}
/* Три шага в ряд. Линия между ними рисуется псевдоэлементом номера, а не
   отдельным узлом: узел пришлось бы прятать на переносе. */
/* Имя `steps` уже занято списком на экране друзей — там нумерованный
   столбец, а здесь ряд из трёх шагов. */
.flow{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:14px}
.stp{position:relative;display:flex;flex-direction:column;align-items:center;
  text-align:center;gap:7px}
.stp .n{position:relative;z-index:1;width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;font-size:12px;font-weight:800;
  color:var(--brand-deep);background:var(--brand-soft);
  box-shadow:inset 0 0 0 1px #CFE0FA}
.stp+.stp .n::before{content:'';position:absolute;right:100%;top:50%;
  width:calc((100vw - 32px) / 3 - 26px);max-width:96px;height:1px;
  background:var(--line);z-index:-1}
.stp .ic{color:var(--brand-deep);line-height:0}
.stp .ic svg{width:30px;height:30px}
.stp b{font-size:13px;font-weight:700;line-height:1.25;color:var(--soft)}

/* Сноска — утопленной полосой: это не шаг и не кнопка, а условие. */
.card.how .hint{display:flex;align-items:center;gap:9px;margin-top:13px;
  padding:9px 11px;border-radius:var(--r);background:var(--tint);
  border:1px solid var(--line)}
.card.how .hint .i{flex:0 0 auto;color:var(--brand);line-height:0}
.card.how .hint .i svg{width:17px;height:17px}
.card.how .hint span+span{font-size:12.5px;font-weight:600;color:var(--mute);line-height:1.3}

@media (max-width:400px){
  .card.stop h2{font-size:21px}
  .card.stop .sub{max-width:100%;font-size:13px}
  /* Знак убираем совсем: на узком экране текст занимает всю ширину, и
     знак оказывается прямо под строкой, а не рядом с ней. */
  .card.stop .art{display:none}
  .stp b{font-size:11.5px}
  .stp .ic svg{width:24px;height:24px}
}

/* ── шаг оплаты: счёт и способы

   Экран последний перед кассой, и держится на двух вещах: сколько платить
   и чем. Всё остальное — сноска. */
.card.bill{position:relative;overflow:hidden;margin-top:12px;padding:14px 16px 15px;
  border:0;border-radius:var(--r-lg);color:#fff;
  background:linear-gradient(135deg,#082B6E 0%,#0B4FD0 58%,#1877FF 100%);
  box-shadow:0 2px 6px rgba(11,79,208,.16),0 14px 30px rgba(11,79,208,.18)}
.card.bill .lbl{position:relative;z-index:1;color:#99B1D4}
.card.bill .sum{position:relative;z-index:1;display:block;margin-top:3px;
  font-size:40px;font-weight:800;letter-spacing:-.03em;line-height:1.05}
/* Прежняя цена и напоминание об акции под суммой: сумма со скидкой без
   объяснения читается как «а где обещанные проценты». */
.card.bill .was{position:relative;z-index:1;display:flex;align-items:baseline;gap:8px;
  margin-top:6px;font-size:12.5px;color:#CFE3FF}
.card.bill .was s{font-weight:700;text-decoration-thickness:1px}
/* `display` в правиле выше сильнее браузерного `[hidden]`, и без этой строки
   зачёркнутая цена срока оставалась на экране рядом с суммой, в которую уже
   вошла доплата за места: «20 280 ₽ / 4 080 ₽ скидка учтена». */
.card.bill .was[hidden]{display:none}

/* Разбивка суммы: из чего она сложилась. Нужна только там, где к сроку
   прибавилась доплата за места — иначе строка «подписка N ₽» повторяла бы
   саму сумму. */
.card.bill .split{position:relative;z-index:1;margin-top:9px;padding-top:9px;
  border-top:1px solid rgba(255,255,255,.18)}
.card.bill .split .row{display:flex;align-items:baseline;justify-content:space-between;
  gap:12px;font-size:13px;color:#CFE3FF}
.card.bill .split .row + .row{margin-top:4px}
.card.bill .split .row b{font-weight:700;color:#fff}

/* Доплата за места сверх тарифа — строкой-переключателем над способами
   оплаты. Отдельным экраном этот вопрос стоял бы между человеком и кассой;
   здесь он на глазах и меняет сумму в счёте тем же нажатием.

   Выключен по умолчанию: доплату человек включает сам, как и в переписке,
   где стоят две кнопки с двумя ценами. Включённый вид — не «ошибка» и не
   серость, а подтверждённый выбор. */
/* Подсказка под текстом шторки «письмо ушло»: тише основного объяснения,
   но на глазах — «нет письма» почти всегда означает «лежит в спаме». */
.sent-tip{margin-top:6px;font-size:12.5px;color:var(--mute)}

.keep{display:flex;align-items:center;gap:12px;width:100%;margin-top:10px;
  padding:12px 13px;text-align:left;cursor:pointer;
  border:1px solid var(--line-2);border-radius:var(--r);background:var(--card);
  animation:rise .2s ease-out both;
  transition:border-color var(--dur-1) var(--ease-snap),
    background var(--dur-1) var(--ease-snap),transform var(--dur-1) var(--ease-snap)}
.keep.on{border-color:var(--cta);background:#F2F7FF}
.keep:active{transform:scale(.99)}
.keep .tx{min-width:0;flex:1 1 auto}
.keep .tx b{display:block;font-size:14px;font-weight:800;letter-spacing:-.01em;color:var(--ink)}
.keep .tx span{display:block;margin-top:2px;font-size:12px;font-weight:500;color:var(--mute)}
.keep .bx{flex:0 0 auto;width:24px;height:24px;border-radius:8px;
  display:grid;place-items:center;color:transparent;
  border:1px solid var(--line-2);background:var(--tint);
  transition:border-color var(--dur-1) var(--ease-snap),
    background var(--dur-1) var(--ease-snap),color var(--dur-1) var(--ease-snap)}
.keep.on .bx{border-color:var(--cta);background:var(--cta);color:#fff}
/* Галочка рисуется росчерком, а не появляется целиком: включение —
   единственное движение на этом экране, и его стоит показать. */
.keep .bx svg path{stroke-dasharray:24;stroke-dashoffset:24;
  transition:stroke-dashoffset var(--dur-2) var(--ease-out)}
.keep.on .bx svg path{stroke-dashoffset:0}
/* Сумма в счёте меняется тем же нажатием, и без отклика правка читается
   как сбой отрисовки. Короткий подскок — ровно столько, чтобы взгляд
   вернулся к цифре. */
.card.bill .sum{transition:transform var(--dur-1) var(--ease-snap)}
.card.bill .sum.bump{transform:scale(1.04)}

.pay-h{display:flex;align-items:baseline;gap:8px;margin:16px 2px 0;flex-wrap:wrap}
.pay-h b{font-size:16.5px;font-weight:800;letter-spacing:-.015em;color:var(--ink)}
.pay-h span{font-size:12.5px;font-weight:500;color:var(--mute)}

/* Три способа в ряд: колонками они сравниваются одним взглядом, а списком
   читались бы сверху вниз, хотя выбор здесь равнозначный. */
.ways{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin-top:10px}
.way{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:7px;padding:14px 6px 12px;border-radius:var(--r);text-align:center;
  background:var(--glass-in);border:1px solid var(--glass-in-edge);
  box-shadow:var(--glass-in-lift);font-family:var(--font);
  animation:rise .18s ease-out both}
.way .ic{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;
  color:var(--brand-deep);background:linear-gradient(180deg,#E4EBF4,#CFE0FA);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9)}
.way .ic svg{width:21px;height:21px}
.way b{font-size:13.5px;font-weight:800;letter-spacing:-.01em;color:var(--ink)}
.way span{font-size:10.5px;font-weight:600;color:var(--mute);line-height:1.25}
/* Кнопкой плитка выглядит только там, где она правда кнопка. */
.way.hit{cursor:pointer;transition:transform .12s ease,box-shadow .16s ease,
  border-color .14s ease,background .14s ease}
/* Выбранный способ. Плитка — переключатель, платит кнопка внизу, и без
   явной отметки человек не видит, чем именно он сейчас заплатит. Отметка
   не только рамкой: цветом залит и значок, потому что рамка в 2 точки на
   светлом фоне теряется на солнце. */
.way.on{border-color:var(--cta);background:linear-gradient(180deg,#fff,#EAF0F8);
  box-shadow:0 0 0 2px rgba(51,83,129,.16),var(--sh-1),var(--edge)}
.way.on .ic{color:#fff;background:linear-gradient(180deg,var(--brand),var(--brand-deep))}
.way.hit:active{transform:translateY(1px);box-shadow:inset 0 2px 8px rgba(10,22,44,.10)}
.way.wait{pointer-events:none;opacity:.6}

@media (max-width:400px){
  .card.bill .sum{font-size:34px}
  .way{padding:12px 4px 10px;gap:6px}
  .way .ic{width:34px;height:34px}
  .way .ic svg{width:19px;height:19px}
  .way b{font-size:12.5px}
}

/* ─────────────────────────── тарифы */
.plans{display:grid;gap:12px;margin-top:12px}
.plan{position:relative;background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:16px;box-shadow:var(--sh-1);transition:border-color .15s ease,box-shadow .15s ease}
.plan.on{border-color:var(--brand);box-shadow:0 0 0 2px rgba(67,97,140,.16),var(--sh-1)}
.plan .hd{display:flex;align-items:baseline;gap:8px}
.plan .hd b{font-size:17px;font-weight:800}
.plan .badge{margin-left:auto;font-size:11px;font-weight:800;padding:4px 9px;border-radius:var(--pill);
  background:var(--brand-soft);color:var(--brand-deep);text-transform:uppercase;letter-spacing:.04em}
.plan .badge.best{background:#FDF0D8;color:#8A5A0F}
.plan .feat{margin:10px 0 0;padding:0;list-style:none;display:grid;gap:6px;font-size:13px;color:var(--soft)}
.plan .feat li{display:flex;gap:8px;align-items:flex-start}
.plan .feat li svg{flex:0 0 auto;margin-top:2px;color:var(--brand)}

/* Ровно три в ряд. Пять сроков при автоподборе вставали как 4+1, и
   одинокая карточка во втором ряду читалась как обрезанный список. */
.terms{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:12px}
.term{border:1px solid var(--line-2);background:var(--tint);border-radius:var(--r-sm);
  padding:9px 6px;text-align:center;cursor:pointer;transition:all .14s ease}
.term.on{border-color:var(--cta);background:var(--glass-hi);
  box-shadow:0 0 0 2px rgba(51,83,129,.14)}
.term b{display:block;font-size:14px;font-weight:800}
.term span{display:block;font-size:11.5px;font-weight:500;color:var(--mute);margin-top:2px}
.term .save{display:block;font-size:10px;font-weight:800;color:var(--cta);margin-top:3px}

/* «Сейчас → станет». Два одинаковых блока со стрелкой между ними: разница
   читается за один взгляд, а число в счётчике перестаёт быть отвлечённым. */
.swap{display:flex;align-items:stretch;gap:10px;margin-top:4px}
.swap .box{flex:1;text-align:center;padding:12px 6px 11px;border-radius:var(--r);
  border:1px solid var(--line-2);background:linear-gradient(180deg,#F6F8FC,#EAEFF6)}
.swap .box.next{border-color:var(--cta);
  background:linear-gradient(180deg,#E7F0FF,#CFDBEC);
  box-shadow:0 0 0 2px rgba(51,83,129,.12),inset 0 1px 0 rgba(255,255,255,.7)}
.swap .box i{display:block;font-style:normal;font-size:10px;font-weight:800;
  text-transform:uppercase;letter-spacing:.08em;color:var(--mute)}
.swap .box.next i{color:var(--cta)}
.swap .box b{display:block;font-size:30px;font-weight:800;line-height:1.05;margin-top:5px;
  letter-spacing:-.03em}
.swap .box.next b{color:var(--brand-deep)}
.swap .box span{display:block;font-size:11.5px;font-weight:500;color:var(--mute);margin-top:2px}
.swap .arrow{flex:0 0 auto;align-self:center;color:var(--line-strong);display:flex}

.busy{margin-top:9px;text-align:center;font-size:12.5px;font-weight:500;color:var(--mute)}

/* Счётчик слотов: две кнопки и число между ними. */
.step{display:flex;align-items:center;gap:14px;justify-content:center;padding:12px 0 2px}
.step button{width:52px;height:52px;border-radius:16px;border:1px solid var(--line-2);
  background:linear-gradient(180deg,#fff,#ECF0F7);color:var(--brand-deep);
  font-family:var(--font);font-size:26px;font-weight:800;line-height:1;cursor:pointer;
  box-shadow:0 1px 2px rgba(10,22,44,.08),var(--edge)}
.step button:active{background:var(--brand-soft);box-shadow:inset 0 2px 6px rgba(10,22,44,.14)}
.step button[disabled]{opacity:.4;pointer-events:none}
.step .val{min-width:118px;text-align:center}
.step .val b{display:block;font-size:30px;font-weight:800;line-height:1;letter-spacing:-.03em;
  color:var(--cta)}
.step .val span{display:block;font-size:12px;font-weight:500;color:var(--mute);margin-top:4px}

/* Строка выбора: срок или способ оплаты. Одна высота, одна логика нажатия —
   на обоих шагах человек делает одно и то же движение. */
/* Плашка выданной акции над сроками и тарифами. Тон отличается от зелёного
   интерфейса намеренно: это не состояние подписки, а временное предложение,
   и оно обязано читаться как отдельная новость. Процент — крупным, срок —
   строкой ниже: без срока скидка перестаёт торопить. */
.sale{display:flex;align-items:center;gap:11px;margin-bottom:2px;padding:10px 13px;
  border-radius:var(--r);color:#fff;
  background:linear-gradient(135deg,#8A6A22,#B08A2E 72%);
  box-shadow:0 2px 8px rgba(90,68,16,.22)}
.sale>b{flex:0 0 auto;font-size:19px;font-weight:800;letter-spacing:-.02em}
.sale .tx{min-width:0}
.sale .k{display:block;font-size:13px;font-weight:800;letter-spacing:-.01em}
.sale .w{display:block;margin-top:1px;font-size:11.5px;color:#F0E2BC}
/* Низкое поле мини-аппа. Сначала плашка ложится в одну строку — процент и
   срок, пояснение уходит первым: скидка уже посчитана в ценах ниже. Дальше
   она исчезает совсем: список сроков и витрина из трёх тарифов упираются в
   нижний край и без неё, а скидка и без плашки видна — зачёркнутой суммой в
   каждой строке и ценой «от N ₽» на карточке тарифа. */
body.h-700 .sale{padding:8px 12px;gap:9px;align-items:baseline}
body.h-700 .sale>b{font-size:17px}
body.h-700 .sale .k{display:none}
body.h-700 .sale .w{margin-top:0;font-size:12px;font-weight:700;color:#F6EBD0}
body.h-650 .sale{display:none}

.opt{position:relative;display:flex;align-items:center;gap:12px;width:100%;margin-top:9px;
  padding:13px 15px;border:1px solid var(--glass-edge);border-radius:var(--r);
  background:var(--glass);box-shadow:var(--glass-lift);
  font-family:var(--font);text-align:left;cursor:pointer;
  animation:rise .18s ease-out both;
  transition:transform .12s ease,box-shadow .16s ease}
.opt:active{transform:translateY(1px);box-shadow:inset 0 2px 8px rgba(10,22,44,.10)}
.opt .nm{flex:1;min-width:0}
.opt .nm b{display:block;font-size:17px;font-weight:800;letter-spacing:-.015em;line-height:1.2}
.opt .nm span{display:block;font-size:12.5px;font-weight:500;color:var(--mute);margin-top:2px}
.opt .pr{flex:0 0 auto;text-align:right}
.opt .pr b{display:block;font-size:21px;font-weight:800;color:var(--cta);
  letter-spacing:-.025em;line-height:1.15}
.opt .pr i{font-style:normal;display:block;font-size:11px;font-weight:800;margin-top:3px;
  color:var(--brand-deep);background:var(--brand-soft);border-radius:var(--pill);padding:1px 6px}
/* Прежняя цена над скидочной: мелко, серым и зачёркнуто — она нужна как
   точка отсчёта, а не как второе число, которое надо читать. */
.opt .pr s{display:block;font-size:11.5px;font-weight:700;color:var(--mute);
  text-decoration-thickness:1px;line-height:1.1}
.opt .ch{flex:0 0 auto;width:30px;height:30px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--brand-soft);color:var(--brand-deep);
  transition:transform .2s cubic-bezier(.22,1,.36,1)}
.opt:active .ch{transform:translateX(2px)}
/* Ступени по высоте и здесь: список сроков — пять строк плюс шапка, и на
   коротком поле он уезжал под нижнее меню. Уменьшается кегль и отступы,
   строки не пропадают. */
body.h-800 .opt{margin-top:7px;padding:11px 14px}
body.h-800 .opt .nm b{font-size:16px}
body.h-800 .opt .nm span{font-size:12px}
body.h-800 .opt .pr b{font-size:19px}
body.h-800 .opt .ch{width:28px;height:28px}
body.h-800 .opt.best{padding-top:17px}
body.h-730 .opt{margin-top:6px;padding:9px 13px}
body.h-730 .opt .nm b{font-size:15px}
body.h-730 .opt .nm span{font-size:11.5px}
body.h-730 .opt .pr b{font-size:18px}
body.h-730 .opt .pr i{font-size:10px;margin-top:2px}
body.h-730 .opt .ch{width:26px;height:26px}
body.h-730 .opt.best{padding-top:15px}

/* Совсем короткое поле: продление — самый длинный из экранов покупки
   (карточка, пять сроков и «Сменить тариф»), и здесь он ужимается до
   предела. Ничего не пропадает: сроков всегда пять. */
body.h-670 .opt{margin-top:5px;padding:7px 12px}
body.h-670 .opt .nm b{font-size:14.5px}
body.h-670 .opt .nm span{font-size:11px}
body.h-670 .opt .pr b{font-size:17px}
body.h-670 .opt .ch{width:24px;height:24px}
body.h-670 .opt.best{padding-top:13px}
body.h-670 .card.renew{margin-top:7px;padding:8px 12px 9px}
body.h-670 .card.renew h2{font-size:17px}
body.h-670 .card.renew .sub{font-size:11.5px;margin-top:4px}
body.h-670 .card.renew .now{margin-top:4px;padding:3px 8px}
body.h-670 .tip{margin-top:5px;padding:6px 12px}
body.h-670 .tip .ic{width:28px;height:28px}

/* Самый выгодный срок. Выделен так же, как рекомендованный тариф на
   предыдущем экране: зелёная грань, тёплая подложка, лента поверх. */
.opt.best{border-color:var(--cta);padding-top:19px;
  background:linear-gradient(180deg,#F6F9FE,#E9EFF8);
  box-shadow:0 2px 5px rgba(11,79,208,.10),0 10px 22px rgba(11,79,208,.12),var(--edge)}
.opt.best .ch{background:linear-gradient(180deg,#2E86FF,var(--cta-deep));color:#fff}
.opt.best .pr b{color:var(--cta-deep)}
.opt.best .pr i{background:linear-gradient(180deg,#2E86FF,var(--cta-deep));color:#fff}
/* У строки срока лента слева: справа стоит цена, и вдвоём они там
   слипались. У карточки тарифа справа пусто — там лента остаётся справа. */
.opt .flag{position:absolute;top:-1px;left:12px;z-index:2;
  font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  color:#fff;background:linear-gradient(180deg,#2E86FF,var(--cta-deep));
  padding:3px 9px 4px;border-radius:0 0 var(--r-sm) var(--r-sm);
  box-shadow:0 2px 6px rgba(11,79,208,.28)}

/* Шапка внутреннего шага: стрелка назад и то, что уже выбрано. */
.back{display:flex;align-items:center;gap:12px;margin-top:14px;padding:2px 0 6px}
.back .ico{flex:0 0 auto;width:40px;height:40px;border-radius:14px;cursor:pointer;
  border:1px solid var(--glass-hi-edge);background:var(--glass-hi);
  color:var(--brand-deep);display:grid;place-items:center;
  box-shadow:var(--glass-in-lift)}
.back .ico:active{background:var(--brand-soft);box-shadow:inset 0 2px 6px rgba(10,22,44,.12)}
.back .tx{min-width:0}
.back .tx b{display:block;font-size:19px;font-weight:800;letter-spacing:-.02em}
.back .tx span{display:block;font-size:12.5px;font-weight:500;color:var(--mute);margin-top:1px}

/* Кнопка в ожидании ответа кассы: текст остаётся, поверх идёт полоска. */
/* Ожидание кассы у строки срока и плитки пакета: та же полоска, что у
   кнопки. Раньше класс был описан только для .btn, и нажатие на строку или
   плитку внешне не менялось всё время, пока выставляется счёт. */
.opt.wait,.tile.wait{pointer-events:none;position:relative;overflow:hidden;opacity:.6}
.opt.wait::after,.tile.wait::after{content:'';position:absolute;left:0;top:0;bottom:0;width:40%;
  background:linear-gradient(90deg,transparent,rgba(67,97,140,.20),transparent);
  animation:sweep 1s linear infinite}
.btn.wait{pointer-events:none;position:relative;overflow:hidden;color:transparent}
.btn.wait::after{content:'';position:absolute;left:0;top:0;bottom:0;width:40%;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.45),transparent);
  animation:sweep 1s linear infinite}
@keyframes sweep{from{transform:translateX(-100%)}to{transform:translateX(350%)}}

/* ─────────────────────────── сетка мелких товаров */
/* Пакеты трафика делят высоту экрана, как тарифы на витрине: семь штук в
   два столбца — четыре ряда, и в мини-аппе они уходили под нижнее меню.
   Ряды равной высоты, цена прижата к нижнему краю плитки: суммы в ряду
   стоят на одной линии. Излишек высоты уходит в плитки, а не в пустоту
   под ними. */
#shop-body.fill.packs{justify-content:flex-start}
#shop-body.fill.packs>.card.flat{flex:0 0 auto}
#shop-body.fill.packs .tiles{flex:1 1 0;min-height:0;grid-auto-rows:1fr;
  margin-top:10px;gap:8px}
#shop-body.fill.packs .tile{display:flex;flex-direction:column;
  justify-content:space-between;min-height:0;overflow:hidden;padding:10px 12px}
#shop-body.fill.packs .tile em{margin-top:0}
/* Низкое поле: плитки ужимаются кеглем и отступами, а не числом — выбор из
   семи пакетов не должен превращаться в выбор из четырёх. */
body.h-700 #shop-body.fill.packs .tiles{gap:7px;margin-top:9px}
body.h-700 #shop-body.fill.packs .tile{padding:8px 11px}
body.h-700 #shop-body.fill.packs .tile b{font-size:14px}
body.h-700 #shop-body.fill.packs .tile span{font-size:11.5px}
body.h-700 #shop-body.fill.packs .tile em{font-size:14px}
body.h-640 #shop-body.fill.packs .tiles{gap:6px;margin-top:8px}
body.h-640 #shop-body.fill.packs .tile{padding:7px 10px}
body.h-640 #shop-body.fill.packs .tile b{font-size:13.5px}
body.h-640 #shop-body.fill.packs .tile span{font-size:11px}
body.h-640 #shop-body.fill.packs .tile em{font-size:13.5px}
/* ── компактная витрина розницы

   Трафик и устройства обязаны вставать в экран целиком: выбирают здесь
   одним взглядом, а не листанием. Ужимаются отступы и кегль, содержимое
   остаётся всё — ни одного пакета и ни одной строки не убрано. */
#s-shop .tiles{gap:8px;margin-top:10px}
#s-shop .tile{padding:9px 11px}
#s-shop .tile b{font-size:14px}
#s-shop .tile span{font-size:11.5px}
#s-shop .tile em{margin-top:6px;font-size:14px}
#s-shop .tile .row{margin-top:6px}
/* Счётчик слотов. Числа «сейчас» и «станет» набраны крупно намеренно —
   ради них экран и открыт, — но 30 точек на каждое плюс полусотенные
   кнопки уводили кнопку оплаты под нижнее меню. */
#s-shop .swap .box{padding:9px 6px 8px}
#s-shop .swap .box b{font-size:26px;margin-top:4px}
#s-shop .swap .box span{font-size:11px}
#s-shop .busy{margin-top:7px;font-size:12px}
#s-shop .step{gap:12px;padding:9px 0 0}
#s-shop .step button{width:46px;height:46px;border-radius:14px;font-size:23px}
#s-shop .step .val{min-width:104px}
#s-shop .step .val b{font-size:26px}
#s-shop .step .val span{font-size:11.5px;margin-top:3px}
#s-shop .step+.btn.sm{margin-top:11px}
#s-shop .card>.note{margin-top:9px;font-size:12px;line-height:1.35}
/* Шапка раздела — метка и одна строка: своей карточки ей не надо, и место
   она занимать не должна. */
#s-shop .card.flat{margin-top:11px;padding:0 2px}
#s-shop .card.flat p.sub{margin-top:3px;font-size:12.5px;line-height:1.35}

.tiles{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px}
.tile{border:1px solid var(--glass-edge);background:var(--glass);border-radius:var(--r);
  padding:12px;text-align:left;cursor:pointer;box-shadow:var(--glass-lift);
  font-family:var(--font)}
.tile b{display:block;font-size:15px;font-weight:800}
.tile span{display:block;font-size:12.5px;font-weight:500;color:var(--mute);margin-top:2px}
.tile em{display:block;font-style:normal;margin-top:8px;font-size:15px;font-weight:800;color:var(--cta)}
/* Нажатие на карточку — лёгкое сжатие с возвратом, а не сдвиг: сдвиг на
   пиксель на телефоне не читается, а палец в этот момент закрывает добрую
   треть плитки. Отпускание отыгрывается тем же переходом, иначе карточка
   возвращается рывком. */
.tile,.tar,.act,.opt,.tip{transition:transform var(--dur-1) var(--ease-snap)}
.tile:active,.tar:active,.act:active,.opt:active,.tip:active{transform:scale(.985)}

/* ─────────────────────────── витрина по ссылке подписки (buy.html)

   Отдельной страницы у неё нет: те же карточки, плитки и счётчики, что в
   кабинете. Своего здесь ровно две вещи — нижней панели нет вовсе, и в
   плитке товара рядом с ценой стоит выгода.

   --bar-h обнуляем на уровне страницы, а не правим три отступа поимённо:
   от неё считают своё место и поле страницы, и трава, и подсказка. */
body.buy-page{--bar-h:0px;--bar-gap:0px}
body.buy-page .app{padding-bottom:calc(var(--sa-bottom) + 28px)}
body.buy-page .toast{bottom:calc(var(--sa-bottom) + 20px)}
/* Та же ловушка, что у .seg и .gate: авторский display сильнее браузерного
   правила для [hidden], и кнопка «Подписка» оставалась на экране даже там,
   куда возвращаться некуда — например у того, у кого подписки нет вовсе. */
.top a.sup[hidden]{display:none}

/* Фото владельца ссылки вместо буквы. */
body.buy-page .top .ava.photo{padding:0;overflow:hidden;background:#dfe8f5}
body.buy-page .top .ava.photo img{width:100%;height:100%;object-fit:cover;display:block}

/* Витрина чуть компактнее кабинета: сюда приходят со страницы подписки за
   одной покупкой, и крупные блоки уводили кнопку оплаты за край экрана.
   zoom, а не transform: браузер заново раскладывает и рисует текст, а не
   растягивает готовую картинку — ничего не мылится. */
body.buy-page .top, body.buy-page #head, body.buy-page #body{zoom:.9}
/* Карточка счётчиков на витрине стоит без заголовка: отступ и линия сверху
   (в кабинете они отделяют счётчики от заголовка) давали пустую полосу. */
body.buy-page .card.lead > .stats:first-child{margin-top:-4px;border-top:0}

/* На широком экране кабинет отводит место левой панели и прижимает колонку к
   ней. У витрины панели нет, и то же правило уводило страницу вправо от
   центра — здесь колонка просто стоит посередине. */
@media (min-width: 960px) {
  body.buy-page .app{margin:0 auto;max-width:720px;padding:26px 40px 56px}
  body.buy-page .floor{left:0}
  body.buy-page .toast{left:50%}
}

/* Метка «выбирают» — строкой рядом с названием, как в карточке тарифа.
   Поверх угла плитки она наезжала бы на цену: на широком экране плитка
   становится строкой, и угол занят. */
.tile b .mark{display:inline-block;margin-left:6px;vertical-align:1px;
  font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  color:var(--brand-deep);background:var(--brand-soft);padding:2px 7px;
  border-radius:var(--pill)}
.tile b .mark.hot{background:#FBEFD6;color:#8A5A0F}

/* Цена и выгода — одной строкой: «−48 %» без цены рядом ни о чём не говорит,
   а под ценой отдельной строкой удлиняет плитку на треть. */
.tile .row{display:flex;align-items:baseline;gap:7px;margin-top:8px}
.tile .row em{margin-top:0}
.tile .row i{font-style:normal;font-size:10.5px;font-weight:800;color:var(--brand-deep);
  background:var(--brand-soft);border-radius:var(--pill);padding:2px 7px}

/* ─────────────────────────── нижний бар */
/* Полоса приподнята над краем и стоит отдельной панелью, а не приклеена
   к низу экрана: у телефона внизу своя полоса жеста, и меню, прижатое к
   ней вплотную, читается как её продолжение.

   Стекло вернули по просьбе владельца (09.09.2026) — но только сюда.
   `backdrop-filter` пересчитывает всё, что под ним, на каждый кадр
   прокрутки, и когда-то он стоял на половине интерфейса; здесь это один
   маленький слой поверх статичного фона, и такую цену панель отрабатывает:
   содержимое проезжает под ней и видно, что она стеклянная, а не наклеена
   поверх. Больше нигде размытия нет — см. кнопки и чип. */
.bar{position:fixed;left:0;right:0;z-index:5;background:none;border-top:0;
  bottom:calc(var(--sa-bottom) + var(--bar-gap));
  padding:0 10px;pointer-events:none}
/* Опора под панелью: мягкое зелёное затухание к самому низу экрана. Оно же
   уводит вниз содержимое, которое проезжает под меню, — иначе строка
   карточки обрывается на полуслове ровно под её краем. Один статичный
   градиент: ни слоя, ни кадров он не стоит. */
.bar::before{content:'';position:fixed;left:0;right:0;bottom:0;z-index:-1;
  height:calc(var(--bar-h) + var(--bar-gap) + var(--sa-bottom) + 24px);
  background:linear-gradient(180deg,rgba(179,194,215,0),rgba(139,160,191,.34) 46%,
    rgba(104,129,164,.62));
  pointer-events:none}
/* `touch-action:none`: по полосе капсулу тянут, и вертикаль тут не нужна —
   иначе движение уходило бы в прокрутку страницы. */
.bar .in{position:relative;max-width:444px;margin:0 auto;height:var(--bar-h);
  display:grid;grid-template-columns:repeat(5,1fr);touch-action:none;
  pointer-events:auto;border-radius:26px;
  /* Стекло: полупрозрачная белая подложка, размытие и лёгкое усиление
     цвета — под панелью проезжает синий фон, и без saturate он выцветает
     в серый. Блик по верхней кромке и тонкая светлая грань дают тот самый
     край, по которому стекло и узнаётся. */
  background:linear-gradient(180deg,rgba(255,255,255,.46),rgba(255,255,255,.30));
  /* Размытие сильнее прозрачности: чем меньше белого в подложке, тем
     больше работы делает блюр — иначе сквозь панель читается текст
     карточек, а не размытое пятно, и подписи вкладок теряются. */
  -webkit-backdrop-filter:blur(34px) saturate(185%);
          backdrop-filter:blur(34px) saturate(185%);
  border:1px solid rgba(255,255,255,.62);
  box-shadow:0 1px 2px rgba(10,22,44,.06),0 10px 26px rgba(10,22,44,.16),
             inset 0 1px 0 rgba(255,255,255,.9),
             inset 0 -1px 0 rgba(10,22,44,.06)}
/* Телефон без поддержки размытия (старый WebView) получит плотную подложку:
   полупрозрачная белая без блюра превратилась бы в мутное пятно, сквозь
   которое просвечивает текст карточек. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .bar .in{background:rgba(255,255,255,.96)}
}
/* Полоска активной вкладки. Едет сдвигом — это композиция, без перерисовки
   и без пересчёта раскладки, поэтому кадры не проседают даже на слабом
   телефоне. Кривая и длительность те же, что у переключателя разделов
   магазина: две бегающие полоски в одном интерфейсе обязаны вести себя
   одинаково. */
/* Активная вкладка — светлая капсула во всю высоту полосы, с зелёной
   чертой на верхней грани. Одна полоска сверху говорила, где ты, слишком
   тихо: на светлом фоне она читалась как декоративная линия. */
/* Пока капсулу тянут, она чуть крупнее: жест видно и на глаз, а не только
   по тому, что экран сменился. */
.bar.drag .pin::before{transform:scale(1.04)}
.bar.drag button{transition:color .12s ease}
.bar .pin{position:absolute;top:6px;bottom:6px;left:0;width:20%;pointer-events:none;
  display:flex;align-items:stretch;justify-content:center;
  transition:transform .26s cubic-bezier(.22,1,.36,1)}
.bar.drag .pin{transition:none;will-change:transform}
.bar .pin::before{content:'';display:block;width:calc(100% - 8px);max-width:104px;
  border-radius:20px;background:linear-gradient(180deg,#EDF4FF,#DCE8FB);
  transition:transform .18s ease;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.85),0 1px 2px rgba(10,22,44,.08)}
/* Черта лежит на верхней грани капсулы и чуть выходит за неё: так видно,
   что это метка положения, а не рамка кнопки. */
.bar .pin::after{content:'';position:absolute;top:-2px;left:50%;width:30px;height:3px;
  margin-left:-15px;border-radius:var(--pill);background:var(--cta);
  box-shadow:0 1px 4px rgba(44,72,112,.35)}
/* Имя продукта в панели — только для широкого экрана (см. конец файла).
   Внизу телефона оно занимало пятую колонку, и «Профиль» уезжал за край. */
.bar .brand{display:none}
.bar button{border:0;background:none;font-family:var(--font);cursor:pointer;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  color:var(--mute);font-size:11.5px;font-weight:700;padding:0;position:relative;z-index:1}
.bar button svg{width:25px;height:25px;transition:transform .2s cubic-bezier(.22,1,.36,1)}
/* Подпись в одну строку и без переносов: «Управление» — самое длинное слово
   в баре, и на узком телефоне оно ломало ряд надвое. */
.bar button .lb{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media (max-width:359px){ .bar button{font-size:10px} }
/* «Купить» выделена обводкой, а не размером: это единственная кнопка бара,
   за которой стоят деньги, и в ряду одинаковых значков её приходилось
   искать. Значок при этом того же размера, что у соседей, — крупнее он
   ломал общую линию ряда. Колонки тоже остаются равными: капсула активной
   вкладки ездит шагом ровно в одну колонку. */
.bar button[data-tab="shop"]{color:var(--cta-deep);font-weight:800;
  /* Рамка кнопки совпадает с капсулой активной вкладки до пикселя.

     Капсула лежит по `top:6px;bottom:6px` и шириной в колонку минус восемь
     точек (по четыре с боков). У «Купить» была своя рамка по `margin:8px 5px`
     — то есть на две точки уже и на четыре ниже. Когда вкладка становилась
     активной, светлая капсула торчала из-под её рамки снизу и сверху. */
  margin:6px 4px;border:1.5px solid var(--cta);border-radius:20px;
  background:linear-gradient(180deg,#DFE6F1,#CAD7E9)}
/* Активная — та же кнопка, но темнее: светлая капсула вкладки под ней не
   видна, и без своего отличия «Купить» выглядела бы одинаково открытой и
   закрытой. */
.bar button[data-tab="shop"].on{border-color:var(--cta-deep);
  background:linear-gradient(180deg,#C2D1E6,#ADBFDA)}

/* «Управление» — самое длинное слово в баре: на узком телефоне подпись
   вылезала за края капсулы активной вкладки. Кегль меньше соседних. */
.bar button[data-tab="manage"] .lb{font-size:10px}
@media (max-width:359px){ .bar button[data-tab="manage"] .lb{font-size:9px} }
/* Цвет и подпись меняются мягко: резкая смена читается как подмена
   картинки, а не как переход. */
.bar button{transition:color .22s ease}
.bar button.on{color:var(--brand-deep)}
.bar button.on svg{transform:scale(1.06)}
/* Нажатие видно до того, как экран успел смениться. */
.bar button:active svg{transform:translateY(0) scale(.92);transition-duration:.08s}
.bar button span{transition:opacity .22s ease,transform .22s cubic-bezier(.22,1,.36,1)}
.bar button.on span{transform:none}

/* ─────────────────────────── экраны и переходы */
.screen{display:none}
.screen.on{display:block}
/* Первый кадр не анимируется: экран, который въезжает при открытии
   страницы, читается как «страница ещё грузится», хотя она уже готова.
   Класс `ready` ставит скрипт после первой отрисовки, дальше переключение
   вкладок анимируется как прежде.

   Движения в анимации нет намеренно, только проявление. Пока едет
   `transform`, система рисует слой один раз и возит готовую картинку:
   буквы в этот момент без субпиксельного сглаживания, а в конце кадр
   пересобирается — на телефоне это читается как «сначала мутно, через
   секунду резко». */
/* Появления экрана прозрачностью больше нет — и вот почему.

   Стекло карточки (`backdrop-filter`) берёт подложку из того, что нарисовано
   ПОД ней. Пока на экране висит анимация прозрачности, система держит его
   отдельным composited-слоем, и подложкой карточке служит этот слой, а не
   фоновый свет страницы: стекло стоит пустым. Слой отпускается не в конце
   анимации, а когда системе удобно, — отсюда и «цвет прогружается через
   секунду» на карточке главной, где стекло крупнее всего.

   Переключение вкладки и без того видно: едет полоска активной кнопки и
   переезжает свет фона. Ради этой пары кадров ломать материал, из которого
   собран весь кабинет, нечего.

   `rise` у карточек тарифов и плиток розницы оставлен: своего размытия у
   них нет, подложку они не берут, и портить им нечего. */
@keyframes in{from{opacity:0}to{opacity:1}}

/* Карточки появляются по очереди. Задержку каждой проставляет скрипт — в CSS
   пришлось бы плодить :nth-child под неизвестное число тарифов.

   Движения здесь нет намеренно, по той же причине, что и у экранов выше.
   Пока карточка едет, система рисует её отдельным слоем и возит готовую
   картинку: буквы в этот момент без субпиксельного сглаживания, а полу-
   прозрачная заливка берёт подложку из слоя, а не из света страницы. На
   телефоне это читается ровно как «сначала мутно, через секунду резко» —
   и читалось, пока подъём здесь стоял.

   Длительность короткая, а очередь плотная: три карточки обязаны встать
   за четверть секунды. Появление, растянутое на секунду, человек видит не
   как оформление, а как медленную загрузку. */
.tar{animation:rise .2s ease-out both}
@keyframes rise{from{opacity:0}to{opacity:1}}

/* Плитки товаров — тем же проявлением, но ещё короче: их много, и длинная
   очередь превращается в ожидание. */
.tiles .tile{animation:rise .18s ease-out both}
.tiles .tile:nth-child(2n){animation-delay:.02s}
.tiles .tile:nth-child(n+3){animation-delay:.04s}
.tiles .tile:nth-child(n+5){animation-delay:.06s}
.tiles .tile:nth-child(n+7){animation-delay:.08s}

@media (prefers-reduced-motion: reduce){
  .screen.on,.tar,.tiles .tile{animation:none}
  /* Всё, что добавлено движением: очередь привязок, шаги покупки,
     заполнение полосы, отклик переключателя и подскок суммы. Экран обязан
     остаться рабочим — меняется только то, что двигалось. */
  .dev,.keep,#shop-body.step-fwd,#shop-body.step-back,
  #s-manage .mng>.phd .tbar i{animation:none}
  .keep,.keep .bx,.card.bill .sum{transition:none}
  .keep .bx svg path{stroke-dashoffset:0;transition:none}
  .card.bill .sum.bump{transform:none}
  /* Свет остаётся, движение — нет. Слои под него держать тоже незачем. */
  .aura i{animation:none;will-change:auto;transition:none}
  /* Без бегущего света `.wait` оставалась зелёной плашкой без подписи:
     движение убираем, но тогда возвращаем текст и статичную подсветку. */
  .btn.wait{color:#fff}
  .btn.ghost.wait{color:var(--brand-deep)}
  .btn.wait::after,.btn.busy::after{animation:none;width:100%;opacity:.5}
  .btn.no{animation:none;border:1px solid var(--bad)}
  .btn,.tile,.tip,.act,.tar.pick,.opt,.seg .pin,.link button,.link button svg,
  .me .cid,.me .cid .ic svg,.bar .pin,.bar button,.bar button svg,
  .bar button span{transition:none}
  .link.flash::after{animation:none}
  .opt{animation:none}
  .chip i{animation:none}
}

/* Шаги покупки: витрина → срок → оплата. Переход отмечается коротким
   проявлением содержимого — иначе шаг читается как подмена на месте.

   Поездки содержимого здесь нет намеренно, по той же причине, что и у
   карточек: пока блок едет, текст внутри рисуется отдельным слоем и
   теряет субпиксельное сглаживание, то есть весь переход человек видит
   мутным. Направление и без движения понятно: сменился заголовок шага, а
   назад ведёт своя кнопка.

   Анимируется контейнер, а не каждая карточка: у карточек своя очередь
   появления, и две анимации на одном элементе спорили бы между собой. */
#shop-body.step-fwd,#shop-body.step-back{animation:rise .16s ease-out both}
/* Отключение движения стоит здесь, а не в общем блоке выше: тот идёт по
   файлу раньше, специфичность у правил одинаковая, и позднее объявление
   анимации его перебивало — «меньше движения» на этом переходе не
   работало вовсе. */
@media (prefers-reduced-motion: reduce){
  #shop-body.step-fwd,#shop-body.step-back{animation:none}
}

.skel{border-radius:var(--r);background:linear-gradient(90deg,#E4ECFB,#F3F7FF,#E4ECFB);
  background-size:200% 100%;animation:sk 1.2s linear infinite;height:14px;margin:8px 0}
@keyframes sk{from{background-position:200% 0}to{background-position:-200% 0}}

/* Карточка-подсказка: короткая, с иконкой, кликабельная целиком. */
.tip{display:flex;align-items:center;gap:12px;margin-top:8px;padding:10px 14px;
  background:var(--glass);border:1px solid var(--glass-edge);
  border-radius:var(--r-lg);box-shadow:var(--glass-lift);
  cursor:pointer;width:100%;text-align:left;font-family:var(--font);
  transition:transform .12s ease,box-shadow .16s ease}
.tip:active{transform:translateY(1px);box-shadow:inset 0 2px 6px rgba(10,22,44,.10)}
.tip .ic{flex:0 0 auto;width:36px;height:36px;border-radius:11px;display:grid;place-items:center;
  background:linear-gradient(180deg,#E4EEFF,#CFE0FA);color:var(--brand-deep);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.8),0 1px 2px rgba(10,22,44,.08)}
.tip b{display:block;font-size:15px;font-weight:800}
.tip span{display:block;font-size:13px;font-weight:500;color:var(--soft);margin-top:1px}
/* Короткое поле: строка-подсказка сжимается — на экране продления она
   стоит последней, и из-за неё список сроков уезжал под нижнее меню. */
body.h-800 .tip{margin-top:7px;padding:8px 13px;gap:10px}
body.h-800 .tip .ic{width:32px;height:32px;border-radius:10px}
body.h-800 .tip b{font-size:14.5px}
body.h-800 .tip span{font-size:12px}
body.h-730 .tip{margin-top:6px;padding:7px 12px}
body.h-730 .tip .ic{width:30px;height:30px}
body.h-730 .tip b{font-size:14px}
body.h-730 .tip span{font-size:11.5px}
.tip .go{margin-left:auto;color:var(--line-strong)}
/* На строке внутри карточки шеврон сидит в кружке: без своего поля у
   строки нет правого края, и голая галка висела в воздухе. */
/* Кружок шеврона внутри блока светлее самого блока — иначе он тонет в нём
   и строка снова перестаёт выглядеть нажимаемой. */
.tip.pane .go{display:grid;place-items:center;width:32px;height:32px;flex:0 0 auto;
  border-radius:50%;background:var(--glass-hi);border:1px solid var(--glass-hi-edge);
  box-shadow:var(--glass-in-lift);color:var(--mute)}
/* Плитка значка: единственная деталь карточки с синевой — на макете внутри
   (185,211,253), то есть примерно .16 фирменного синего поверх стекла. */
.tip.pane .ic{background:rgba(24,119,255,.20);
  border:1px solid rgba(255,255,255,.8);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.7),0 1px 2px rgba(10,22,44,.05);
  color:var(--brand-deep)}

.note{margin-top:10px;font-size:12.5px;font-weight:500;color:var(--soft);text-align:center}
.copy{display:flex;gap:8px;align-items:center;margin-top:12px;padding:12px;border-radius:var(--r);
  background:var(--tint);border:1px dashed var(--line-2);font-size:13px;word-break:break-all}
.copy b{font-weight:700;color:var(--soft)}

.toast{position:fixed;left:50%;bottom:calc(var(--bar-h) + var(--bar-gap) + var(--sa-bottom) + 16px);
  transform:translate(-50%,20px);z-index:40;opacity:0;pointer-events:none;
  background:rgba(33,39,48,.94);color:#fff;font-size:14px;font-weight:700;
  padding:11px 18px;border-radius:var(--pill);box-shadow:0 8px 24px rgba(33,39,48,.28);
  transition:opacity .22s ease,transform .22s cubic-bezier(.22,1,.36,1)}
.toast.on{opacity:1;transform:translate(-50%,0)}

/* ─────────────────────────── окно входа (обычный браузер)

   Карточка стоит по центру видимой области, а не «сверху с отступом»: на
   десктопе поле в полтора экрана высотой, и прижатый к верху блок посреди
   пустого луга выглядит недогруженной страницей. */
/* Вход стоит на фирменной заливке, а не на светлом листе кабинета: снаружи
   у бренда синий мир, внутри — белые карточки. Ровно так устроены шапки
   экранов, и человек попадает в кабинет из того же кадра, что видел в
   переписке. Заливка своя, поверх страничной: гасить общий фон ради одного
   экрана значило бы перекрашивать всё приложение. */
.gate{position:relative;z-index:1;min-height:100svh;display:flex;align-items:center;
  justify-content:center;padding:32px 18px calc(120px + var(--sa-bottom))}
/* Своей заливки у окна входа больше нет.

   Раньше оно закрывало страницу глубоким синим во всю высоту и ставило
   поверх одну плотно-белую карточку. Это был отдельный мир: человек,
   открывший кабинет в браузере, видел один дизайн, а после входа — другой.
   Теперь под окном тот же светлый лист, тот же свет `.aura` и то же
   стекло, что на всех экранах кабинета, — вход перестал быть чужой
   страницей перед входом.

   Правило оставлено пустым, а не удалено: если фирменный синий на вход
   когда-нибудь вернут, возвращать его будет куда. */
/* Та же история, что у переключателя разделов выше: авторское display:flex
   сильнее браузерного правила для [hidden], и без этой строки окно входа
   оставалось висеть поверх кабинета — уже после того, как человек вошёл. */
.gate[hidden]{display:none}
.gate-card{width:100%;max-width:404px;background:var(--glass);border-radius:var(--r-lg);
  /* Сверху отступа нет: шапка стоит вплотную к краю карточки, как баннер
     на главной. `overflow:hidden` режет её углы по радиусу карточки. */
  padding:0 22px 22px;overflow:hidden;text-align:left;
  border:1px solid var(--glass-edge);
  -webkit-backdrop-filter:var(--glass-blur);
          backdrop-filter:var(--glass-blur);
  /* Появления прозрачностью нет — по той же причине, что у экранов
     кабинета: пока на карточке висит анимация opacity, система держит её
     отдельным слоем, и стекло берёт подложку из него, а не из фона.
     Окно входа — первое, что человек видит, и мутная карточка на полсекунды
     читается как незагрузившаяся страница. */
  box-shadow:var(--glass-lift)}
@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){
  .gate-card{background:linear-gradient(180deg,#fff,rgba(255,255,255,.92))}
}

/* Шапка входа — та же деталь `.hero`, что на главной и у друзей. Своей
   вёрстки здесь нет намеренно: прошлое окно входа как раз и разъехалось с
   кабинетом, когда кабинет перестроили, а оно осталось. */
.gate-hero{margin:0 -22px 16px;border-radius:0;border:0;box-shadow:none;
  aspect-ratio:2000/688}
.gate-hero::after{box-shadow:none}

.gate-card .lbl{font-size:10.5px;letter-spacing:.1em;color:var(--soft)}
.gate h1{font-size:23px;font-weight:800;color:var(--ink);margin:7px 0 0;
  letter-spacing:-.028em;line-height:1.16;text-wrap:balance}
.gate-lead{color:var(--soft);margin:7px 0 18px;font-size:14px;line-height:1.45}

/* Наша кнопка и настоящий виджет — один стек. Виджет прозрачный и растянут
   чуть шире кнопки: его iframe меньше, а кликать человек будет по краям
   тоже. Без растяжения углы кнопки просто не отвечают. */
.tgwrap{position:relative;isolation:isolate}
/* Геометрия, блик и ободок — как у главной кнопки кабинета (`.btn.big.go`).
   Цвет остаётся телеграмным: человек узнаёт эту кнопку по цвету мессенджера,
   и перекрашивать её в фирменный синий значит спрятать, чем он входит. */
.tgbtn{position:relative;display:flex;align-items:center;justify-content:center;gap:9px;
  width:100%;height:54px;overflow:hidden;isolation:isolate;
  border:0;border-radius:var(--r);cursor:pointer;font-family:var(--font);
  font-size:16.5px;font-weight:800;letter-spacing:-.01em;color:#fff;
  background:linear-gradient(180deg,#37B5F0,#1E95D2 60%,#2299D6);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45),
             inset 0 -5px 7px -5px rgba(255,255,255,.5),
             inset 0 -1px 0 rgba(255,255,255,.40),
             0 2px 6px rgba(20,110,160,.28),0 12px 26px rgba(20,110,160,.30);
  transition:transform .1s ease,box-shadow .16s ease,filter .16s ease}
.tgbtn::after{content:'';position:absolute;left:0;right:0;top:0;height:52%;z-index:-1;
  pointer-events:none;
  border-radius:var(--r) var(--r) 40% 40%/var(--r) var(--r) 12px 12px;
  background:linear-gradient(180deg,rgba(255,255,255,.26),
    rgba(255,255,255,.04) 70%,rgba(255,255,255,0))}
.tgbtn svg{width:22px;height:22px;flex:none}
.tgwrap:hover .tgbtn{filter:brightness(1.04)}
.tgwrap:active .tgbtn{transform:translateY(1px);filter:brightness(.96);
  box-shadow:0 1px 3px rgba(20,110,160,.3),inset 0 3px 7px rgba(0,0,0,.2)}
/* Пока виджета нет, подложка не должна притворяться нажимаемой: прогиб под
   пальцем на мёртвой кнопке читается как «нажал, и не сработало». */
.tgwrap.wait{cursor:progress}
.tgwrap.wait:active .tgbtn{transform:none;filter:none;
  box-shadow:0 2px 4px rgba(20,110,160,.26),0 10px 22px rgba(20,110,160,.28),
             inset 0 1px 0 rgba(255,255,255,.32),inset 0 -1px 0 rgba(0,0,0,.14)}
.tgreal{position:absolute;left:50%;top:50%;z-index:2;opacity:0;
  transform:translate(-50%,-50%) scale(1.6);overflow:hidden}
.tgreal iframe{display:block}
/* Виджет ещё грузится. Кнопку при этом не гасим: серая кнопка читается как
   сломанная, а ждать тут доли секунды — достаточно бегунка справа. */
.tgspin{position:absolute;right:16px;top:50%;width:18px;height:18px;margin-top:-9px;z-index:3;
  border:2px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;
  opacity:0;pointer-events:none;animation:tgspin .8s linear infinite}
.tgwrap.wait .tgspin{opacity:1}
@keyframes tgspin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){
  .tgspin{animation-duration:2.4s}
}

/* ── вход по почте

   Разделитель «или» между двумя дорогами: без него кнопка почты читается
   продолжением телеграмной. Черта светлая — стекло режут светом. */
.gate-or{display:flex;align-items:center;gap:10px;margin:14px 0 10px;
  font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.1em;
  color:var(--mute)}
.gate-or::before,.gate-or::after{content:'';flex:1;height:1px;
  background:rgba(255,255,255,.85)}

/* Вторая кнопка тише первой: рост тот же, но поле стеклянное, а не залитое
   цветом — вход через Telegram остаётся главным. */
.gate-mail{display:flex;align-items:center;justify-content:center;gap:9px;
  width:100%;height:48px;border-radius:var(--r);cursor:pointer;
  font-family:var(--font);font-size:15.5px;font-weight:800;letter-spacing:-.01em;
  color:var(--brand-deep);background:var(--glass-in);
  border:1px solid var(--glass-in-edge);box-shadow:var(--glass-in-lift);
  transition:transform .12s ease,box-shadow .16s ease}
.gate-mail[hidden]{display:none}
.gate-mail svg{width:19px;height:19px;flex:none}
.gate-mail:active{transform:translateY(1px);
  box-shadow:inset 0 2px 6px rgba(10,22,44,.10)}

/* Переключатель на две колонки: общий `.seg` собран на три. */
.mailf-seg{grid-template-columns:repeat(2,1fr);margin-top:2px;margin-bottom:2px}
.mailf-seg .pin{width:calc((100% - 8px)/2)}
.mailf-seg button{height:36px;font-size:13px}

/* Условие регистрации — сноска к кнопке, а не второе предложение экрана. */
.mailf-hint{display:flex;align-items:flex-start;gap:7px;margin:0;
  font-size:11.5px;font-weight:500;line-height:1.4;color:var(--mute);text-align:left}
.mailf-hint[hidden]{display:none}
#bind .mailf-hint{margin-top:11px}
.mailf-hint svg{width:14px;height:14px;flex:none;margin-top:1px;color:var(--brand)}

.mailf{display:grid;gap:10px;margin-top:4px}
.mailf[hidden]{display:none}
.mailf .btn{margin-top:2px}
/* Ссылка, а не кнопка: сбросить пароль — не то же действие, что войти, и
   выглядеть одинаково они не должны. */
.mailf-forgot{border:0;background:none;padding:2px 0;cursor:pointer;
  font-family:var(--font);font-size:13px;font-weight:700;color:var(--brand-deep);
  text-align:center}
.mailf-forgot[disabled]{opacity:.5;pointer-events:none}
.mailf-forgot[hidden]{display:none}
.mailf-msg{margin:0;font-size:12.5px;font-weight:600;line-height:1.4;
  color:var(--soft);text-align:left}
.mailf-msg[hidden]{display:none}
.mailf-msg.bad{color:var(--bad)}

/* Поле с подписью. Одна деталь на окно входа и на шторку привязки: два
   почти одинаковых набора правил разъехались бы при первой же правке. */
.fld{display:grid;gap:5px;text-align:left}
.fld>span{font-size:11px;font-weight:800;text-transform:uppercase;
  letter-spacing:.08em;color:var(--mute)}
.fld>input{width:100%;height:48px;border-radius:12px;padding:0 13px;
  font-family:var(--font);font-size:15.5px;font-weight:600;color:var(--ink);
  background:var(--glass-hi);border:1px solid var(--glass-hi-edge);
  box-shadow:var(--glass-in-lift)}
.fld>input::placeholder{color:var(--line-strong);font-weight:500}
.fld>input:focus{outline:2px solid var(--brand);outline-offset:1px;
  border-color:transparent}

.gate-fall{margin:12px 0 0;font-size:13.5px;color:var(--mute)}
.gate-fall a{color:var(--brand-deep);font-weight:700}

.gate-list{list-style:none;margin:20px 0 0;padding:16px 0 0;
  border-top:1px solid rgba(255,255,255,.85);
  display:grid;gap:11px;text-align:left}
.gate-list li{display:flex;align-items:center;gap:10px;font-size:14px;color:var(--soft)}
.gate-list svg{width:19px;height:19px;flex:none;color:var(--brand)}

.gate-note{display:flex;align-items:flex-start;gap:8px;text-align:left;margin:16px 0 0;
  padding:11px 12px;border-radius:var(--r-sm);
  background:var(--glass-in);border:1px solid var(--glass-in-edge);
  box-shadow:var(--glass-in-lift);
  font-size:12.5px;font-weight:500;line-height:1.45;color:var(--mute)}
.gate-note svg{width:15px;height:15px;flex:none;margin-top:1px;color:var(--brand)}


/* ─────────────────────────── широкий экран

   Кабинет родился внутри Telegram, поэтому по умолчанию он — узкая колонка
   под большой палец. На мониторе та же колонка посреди пустого луга выглядит
   недоделанной страницей, и дело не в ширине: на телефоне навигация внизу
   потому, что там её достаёт палец, а на мониторе руки лежат на клавиатуре,
   и низ экрана — самое далёкое от взгляда место.

   Поэтому на широком порог меняется не размер, а расстановка: панель уезжает
   влево колонкой и становится оглавлением, содержимое раскладывается в две
   колонки, а у всего, что нажимается, появляется наведение — курсор на
   мониторе есть, и без отклика интерфейс кажется мёртвым.

   Порог 960: до него две колонки по 340 не помещаются, и раскладка
   разъезжается раньше, чем начинает помогать. */
@media (min-width: 960px) {
  :root { --rail: 252px; }

  /* Панель: из нижней полосы — в левую колонку. */
  .bar { top: 0; right: auto; width: var(--rail); height: 100vh;
    padding: 20px 14px calc(20px + var(--sa-bottom));
    border-top: 0; border-right: 1px solid var(--line);
    background: rgba(255,255,255,.72) }
  .bar .in { max-width: none; height: auto; display: flex; flex-direction: column; gap: 3px }
  .bar .brand { display: flex; align-items: center; gap: 10px; padding: 6px 12px 18px }
  .bar .brand img { width: 34px; height: 34px; border-radius: 50%; object-fit: cover;
    object-position: 50% 50%; box-shadow: 0 0 0 2px #fff, 0 2px 6px rgba(10,22,44,.18) }
  .bar .brand b { font-size: 15.5px; font-weight: 800; color: var(--brand-deep);
    letter-spacing: -.01em }
  .bar button { flex-direction: row; justify-content: flex-start; gap: 12px;
    height: 46px; padding: 0 12px; border-radius: 13px; font-size: 14.5px; font-weight: 700 }
  .bar button .lb { font-size: 14.5px }
  .bar button:hover { background: rgba(230,235,242,.7); color: var(--brand-deep) }
  .bar button.on { background: var(--brand-soft) }
  .bar button.on svg { transform: none }
  /* Капсула-указатель — только у нижней полосы: в столбце её роль играет
     фон самой кнопки, и вторая подложка поверх первой рябила. */
  .bar .pin { display: none }
  /* Метка активного пункта переезжает с верхнего края на левый: в столбце
     подчёркивание сверху читается как отрыв кнопки от списка. */
  .bar button.on::before { top: 50%; left: 2px; width: 3px; height: 22px;
    transform: translateY(-50%) }

  /* Содержимое встаёт правее панели и держит свою ширину по центру
     оставшегося поля, а не растекается на весь монитор. */
  /* Колонка одна и узкая: кнопка во всю ширину монитора не становится
     заметнее, она становится непонятной — глаз не связывает подпись слева с
     ценой у правого края. 640 — ширина, на которой строка ещё читается одним
     взглядом.

     Стоит колонка по центру ЭКРАНА, а не по центру поля справа от панели:
     во втором случае она заметно уезжает вправо, и страница выглядит
     сдвинутой. Прижаться к панели ближе, чем на её ширину, max() не даст —
     на узком мониторе колонка просто встаёт сразу за ней. */
  .app { max-width: none; margin: 0;
    margin-left: max(var(--rail), calc(50vw - 360px));
    padding: 26px 40px 56px }
  .app > .top, .app > .screen { max-width: 640px; margin-left: 0; margin-right: 0 }
  .top { gap: 12px; padding: 0 2px 6px }
  .top .ava { width: 44px; height: 44px; font-size: 17px }
  .top .who b { font-size: 18px }
  .top .who span { font-size: 13px }
  .top a.sup { height: 38px; font-size: 13.5px }
  .top a.sup:hover { border-color: var(--line-strong); color: var(--cta-deep) }

  /* Трава начинается за панелью, иначе она лезет под её нижние пункты. Но
     только когда панель на экране: на окне входа её нет, и сдвинутая трава
     оставляла у левого края пустую полосу шириной ровно с панель. */
  .floor { bottom: -6px }
  body:has(#bar:not([hidden])) .floor { left: var(--rail) }
  .toast { left: calc(50% + var(--rail) / 2); bottom: 28px }

  /* Баннер на широком экране может позволить себе рост: это единственная
     картинка кабинета, и в 138 пикселей от неё остаётся полоска.

     Кроме шапки окна входа: её ширину держит карточка в 404 точки, а
     `min-height:224px` ломал ей пропорцию — коробка становилась 404×224
     вместо 404×139, и `object-fit:cover` срезал кадру бока вместе с
     надписью «Личный кабинет». Ростом здесь распоряжается только
     `aspect-ratio`. */
  .herow, .hero { margin-top: 8px }
  .hero:not(.gate-hero) { min-height: 224px }
  .gate-hero { margin: 0 -22px 16px }
  .hero-in { min-height: 224px; max-width: 54%; padding: 28px 30px }
  .hero .v { font-size: 40px }
  .hero .m { font-size: 14.5px }
  .hero .k { font-size: 12px }

  /* Всё содержимое — одной лентой сверху вниз, каждый блок во всю ширину
     колонки. Ряды из двух кнопок заставляли глаз метаться влево-вправо,
     а разная ширина соседних блоков ломала общую левую границу — то самое,
     по чему страница и читается как аккуратная. */
  #home-body, #profile-body, #ref-body, #shop-body, #manage-body {
    display: flex; flex-direction: column; gap: 12px; margin-top: 16px }
  #home-body > *, #profile-body > *, #ref-body > *, #shop-body > *,
  #manage-body > * { margin-top: 0 }

  /* Плитки трафика и действия профиля — тоже в столбик: они соседи по
     экрану, и сетка из двух колонок посреди списка выбивается. */
  .tiles { display: flex; flex-direction: column; gap: 10px }
  .acts { grid-template-columns: 1fr }

  /* Внутри плитки объём и цена встают в строку — как у сроков продления.
     Столбиком, как на телефоне, цена оказывалась под названием, а справа
     оставалось полкарточки пустоты, и список сбивался с общего ритма
     «слева что, справа сколько». */
  .tile { display: flex; align-items: center; gap: 12px; padding: 13px 16px }
  .tile b { flex: 0 0 auto }
  .tile span { margin-top: 0; flex: 1 }
  .tile em { margin-top: 0; margin-left: auto; font-size: 16px }
  /* цена с выгодой едет вправо целым блоком, а не одной ценой */
  .tile .row { margin-top: 0; margin-left: auto }

  /* Магазин: тарифы и плитки — рядами, карточки-объяснения — во всю ширину. */

  .card { padding: 16px 18px 18px }

  /* Наведение. На телефоне его нет вовсе, и весь отклик жил в :active —
     на мониторе от этого интерфейс кажется неживым до самого нажатия. */
  .btn:hover { filter: brightness(1.05) }
  .btn.ghost:hover { border-color: var(--line-strong); background: #fff }
  .tar:hover, .tile:hover, .tip:hover, .act:hover, .opt:hover {
    border-color: var(--line-strong); box-shadow: var(--sh-lift);
    transform: translateY(-1px) }
  .tar, .tile, .tip, .act, .opt { transition: transform .14s ease, box-shadow .18s ease,
    border-color .18s ease }
  .link button:hover { background: var(--brand-soft) }
  .cid:hover { border-color: var(--line-strong) }

  @media (prefers-reduced-motion: reduce) {
    .tar:hover, .tile:hover, .tip:hover, .act:hover, .opt:hover { transform: none }
  }
}


/* ─────────────────────────── окно подписки на канал

   Шторка снизу, как системные окна Telegram: кабинет остаётся за ней, и
   человек видит, что никуда не ушёл — замок стоит перед подарком, а не
   перед страницей. На широком экране шторке снизу не за что держаться,
   там она становится карточкой по центру. */
/* ─────────────────────────── страница подписки в кадре

   Выше шторок: пока она открыта, кабинет под ней недоступен целиком, и
   шторка, всплывшая из-под кадра, была бы окном без хозяина. */
/* Слой лежит в разметке всегда и прячется видимостью, а не `display:none`:
   спрятанному так кадру браузер не считает вёрстку, и подогретая заранее
   страница подписки пересчитывалась бы на глазах в момент показа. Ради
   этого подогрев и делался. Нажатий невидимый слой не ловит и в озвучку
   не попадает — вести себя как отсутствующий он не перестаёт.

   Появление мгновенное, без затухания: слой во весь экран и с кадром внутри
   — самое дорогое, что можно анимировать, а выигрыш от него нулевой. */
/* Фон слоя — фон самой страницы подписки (#010711), а не кабинета.
   Страница тёмная и задаёт тему сама, и светлая подложка под ней читалась
   как рамка чужого сайта: белая полоса сверху, белые края по бокам, пока
   кадр не дорисовался. */
/* Высота — видимая часть мини-аппа, а не всё окно: `inset:0` в Telegram
   уходит под системную панель и полосу жеста, и низ страницы подписки
   оказывался за краем экрана — как раз там, где у неё кнопки. */
.conn{position:fixed;top:0;left:0;right:0;z-index:40;display:block;
  height:var(--app-h,100svh);
  background:#E3EDFD;visibility:hidden}
.conn.on{visibility:visible}
/* Своей шапки у слоя нет. Она была второй подряд: сразу под ней страница
   подписки рисует собственную — с логотипом и названием, — и экран
   начинался с двух полос заголовков и полусотни пикселей воздуха между
   ними. Возврат остаётся: системная кнопка Telegram, а для клиентов без
   неё — та же круглая кнопка, только теперь поверх страницы. */
.conn-back{position:absolute;z-index:2;
  top:calc(var(--sa-top) + 10px);left:12px;
  width:36px;height:36px;border-radius:50%;
  display:grid;place-items:center;cursor:pointer;
  border:1px solid rgba(134,172,230,.28);
  background:rgba(15,25,42,.94);color:#dceaff;
  box-shadow:0 8px 24px rgba(0,0,0,.34)}
.conn-back:active{transform:translateY(1px)}
/* Своя стрелка теперь в шапке страницы подписки, слева от аватарки: эта,
   поверх кадра, закрывала аватарку. Возврат остаётся и системной кнопкой. */
.conn-back{display:none}
/* Кадр и скелет занимают всё, что осталось, и лежат друг на друге: скелет
   не двигает кадр и уходит, ничего не перерисовывая. `min-height:0` — иначе
   flex-элемент не даёт себя сжать ниже содержимого кадра. */
/* Кадр — с самого верха экрана, фон страницы подписки уходит под кнопки
   Telegram. Высоту этих кнопок кабинет сообщает странице (connInset), и её
   шапка встаёт сразу под ними. */
.conn-body{position:absolute;inset:0}
/* Своя прокрутка у страницы подписки есть, и вторую полосу рядом с ней
   рисовать незачем. До готовности кадр прозрачен: пустой кадр — это белое
   поле, а под ним уже лежит скелет. */
.conn-frame{position:absolute;inset:0;width:100%;height:100%;border:0;display:block;
  background:#E3EDFD;opacity:0;transition:opacity .2s ease}
.conn.ready .conn-frame{opacity:1}

/* Скелет страницы подписки: шапка с приветствием, две строки, две карточки.
   Повторять её точно незачем — нужно только обещание, что место занято. */
.conn-wait{position:absolute;inset:0;overflow:hidden;
  padding:calc(var(--sa-top) + 64px) 16px 14px;
  display:flex;flex-direction:column;gap:12px;
  transition:opacity .2s ease}
/* Плитки скелета — в тёмной гамме страницы подписки: светлые на её фоне
   вспыхивали белым ровно там, где через миг окажется тёмная карточка. */
.conn-wait span{display:block;border-radius:var(--r);
  background:linear-gradient(90deg,rgba(255,255,255,.55),rgba(255,255,255,.9),rgba(255,255,255,.55));
  background-size:200% 100%;
  animation:sk 1.2s linear infinite}
.conn-wait .w-hero{height:136px;border-radius:var(--r-lg)}
.conn-wait .w-row{height:14px;width:62%}
.conn-wait .w-row.short{width:38%}
.conn-wait .w-card{height:100px;border-radius:var(--r-lg)}
.conn.ready .conn-wait{opacity:0}
/* Бег полосы у невидимого скелета — это кадры в пустоту; после показа
   страницы он должен замолчать. */
.conn.ready .conn-wait span{animation:none}
@media (prefers-reduced-motion:reduce){
  .conn-frame,.conn-wait{transition:none}
  .conn-wait span{animation:none}
}

.sheet{position:fixed;inset:0;z-index:30;display:flex;align-items:flex-end;justify-content:center}
.sheet[hidden]{display:none}

/* Появление и уход держатся на классе .on, а не на keyframes: анимация,
   заданная кадрами, не умеет останавливаться на полпути, а шторку тянут
   пальцем — и она обязана слушаться руки в любой момент. */
/* Плотность и размытие подобраны так, чтобы за шторкой перестал читаться
   баннер главной: он слово в слово повторяет её заголовок, и на четырёх
   пикселях размытия крупные буквы оставались разборчивыми. Плотность при
   этом умеренная: кабинет должен угадываться, иначе отъезд страницы вглубь
   (см. `body.sheeted` ниже) не виден, а он и создаёт ощущение слоя. */
.sheet-dim{position:absolute;inset:0;background:rgba(16,22,30,.46);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  opacity:0;transition:opacity .34s ease}
.sheet.on .sheet-dim{opacity:1}

.sheet-card{position:relative;width:100%;max-width:460px;background:var(--card);
  border-radius:var(--r-lg) var(--r-lg) 0 0;padding:10px 20px calc(16px + var(--sa-bottom));
  text-align:center;border:1px solid var(--line);border-bottom:0;
  max-height:calc(100svh - 16px);overflow-y:auto;-webkit-overflow-scrolling:touch;
  /* Палец тянет шторку, а не страницу под ней; горизонтальные жесты клиента
     при этом остаются рабочими. */
  touch-action:pan-y;
  /* Выезд считан с задемпфированной пружины: быстрый старт, длинный мягкий
     довод и ни одного отскока — шторка прокручивается внутри, и перелёт
     выше своего места открыл бы полосу фона под ней. Обычная кривая на
     таком пути садится к середине хронометража и вторую половину времени
     двигает карточку на десяток пикселей: движения уже нет, а «переход»
     ещё идёт. Уход быстрее прихода, как у всех системных шторок.

     Две строки подряд намеренно: браузер, не знающий linear(), оставит
     себе кривую сверху и просто получит выезд попроще. */
  transform:translate3d(0,100%,0);
  transition:transform .56s cubic-bezier(.22,.8,.3,1),box-shadow .56s ease;
  transition-timing-function:linear(0,0.0467,0.1504,0.2741,0.3976,0.5106,0.6089,0.6915,0.7592,0.8138,0.8572,0.8913,0.9178,0.9383,0.954,0.966,0.9751,0.982,0.9872,0.9911,0.9941,0.9963,0.9979,0.9991,1),ease;
  box-shadow:0 -2px 10px rgba(10,22,44,.10);
  will-change:transform;backface-visibility:hidden}
/* Тень набирает глубину по мере подъёма: у приехавшей шторки она заметно
   гуще, чем у той, что ещё в пути, и край над кабинетом читается сразу. */
.sheet.on .sheet-card{box-shadow:0 -12px 40px rgba(10,22,44,.24),var(--edge)}
.sheet.on .sheet-card{transform:translate3d(0,0,0)}
/* Пока шторку ведёт палец, переход мешает: он сглаживал бы то, что и так
   идёт за рукой, и карточка отставала бы от пальца на треть секунды. */
.sheet.drag .sheet-card{transition:none}
.sheet.drag .sheet-dim{transition:opacity .1s linear}
/* Возврат на место после недотянутого свайпа — короче выезда: человек уже
   видел шторку, ждать её второй раз он не должен. */
.sheet.snap .sheet-card{transition:transform .3s cubic-bezier(.22,1,.36,1)}
/* Уход — ровный разгон. С прежней кривой (.4,0,.9,.3) шторка первые
   250 мс почти стояла, а последнюю треть пути пролетала за 30 мс: глазом
   это читалось как «нажал — подвисло — исчезло». */
.sheet.out .sheet-card{transition:transform .26s cubic-bezier(.4,0,1,1),box-shadow .26s ease}
/* Затемнение уходит чуть позже карточки: иначе кабинет вспыхивает раньше,
   чем шторка договорила. */
.sheet.out .sheet-dim{transition:opacity .3s ease .04s}

/* Содержимое едет вместе со шторкой и ничем не анимируется отдельно.

   Была лесенка: семь блоков всплывали по очереди со сдвигом в 45 мс. На
   бумаге она разбивала «приехал кусок картона», на живом телефоне читалась
   рванью — семь анимаций поверх едущей карточки, размытой подложки и
   уменьшающегося кабинета не укладываются в кадр, и текст дёргается. Да и
   по существу: содержимое написано НА шторке, ехать отдельно от неё ему
   незачем.

   Исключение одно — Кузя. Он тут не элемент раскладки, а лицо разговора, и
   это единственная анимация внутри карточки. */
.sheet.on .sheet-card>.chan-art{animation:art-in .42s cubic-bezier(.34,1.35,.5,1) .06s both}
@keyframes art-in{from{opacity:0;transform:translateY(6px) scale(.9)}}

@media (min-width:520px){
  .sheet{align-items:center;padding:24px}
  /* По центру экрана «выезду снизу» не за что держаться: карточка
     проявляется на месте. */
  .sheet-card{max-width:404px;border-radius:var(--r-lg);border-bottom:1px solid var(--line);
    padding-top:22px;box-shadow:var(--sh-lift),var(--edge);
    transform:translate3d(0,14px,0) scale(.985);opacity:0;
    transition:transform .42s cubic-bezier(.22,1,.36,1),opacity .3s ease}
  .sheet.on .sheet-card{transform:none;opacity:1}
  .sheet.out .sheet-card{transition:transform .26s ease-in,opacity .22s ease}
  .sheet-grip{display:none}
}

/* Кабинет уходит вглубь, пока шторка поверх него: чуть меньше, чуть ниже и
   с закруглёнными углами — так ведут себя системные окна, и именно это
   читается как слой, а не как всплывший поверх картинки прямоугольник.
   Начало координат вверху: низ экрана занят шторкой, и отъезд должен быть
   виден там, где на него смотрят. */
body.sheeted .app{transform:scale(.94) translateY(-4px);
  border-radius:var(--r-lg);overflow:hidden}
/* Центр уменьшения — середина видимой области, а не верх страницы: иначе
   у прокрученного вниз кабинета «отъезд» превращался бы в скачок тем
   больший, чем дальше человек ушёл от начала. Точку считает openChannel.
   Траву не трогаем: она приклеена к низу экрана, и от уменьшения у неё
   отрывался бы нижний край — ровно там, откуда выходит шторка. */
.app{transform-origin:50% var(--recede,50vh);
  transition:transform .56s cubic-bezier(.22,.8,.3,1);
  transition-timing-function:linear(0,0.0467,0.1504,0.2741,0.3976,0.5106,0.6089,0.6915,0.7592,0.8138,0.8572,0.8913,0.9178,0.9383,0.954,0.966,0.9751,0.982,0.9872,0.9911,0.9941,0.9963,0.9979,0.9991,1)}
body.sheet-out .app{transition:transform .3s cubic-bezier(.3,0,.2,1)}

/* Полоска-ручка: и подсказка «меня можно тянуть», и сама область захвата.
   Она одна с touch-action:none — на ней жест точно наш, а не прокрутка. */
.sheet-grip{display:block;width:40px;height:5px;border-radius:var(--pill);
  background:var(--line-2);margin:0 auto 16px;touch-action:none;
  transition:background .2s ease,transform .2s ease}
.sheet.drag .sheet-grip{background:var(--line-strong);transform:scaleX(1.12)}

/* Кольцо фокуса. Его не было нигде в кабинете: браузерное гасили не мы, но
   поверх фирменных теней и зелёной заливки оно всё равно неразличимо. */
:where(.btn,.chan-later,.tip,.act,.opt,.tile,.top a.sup):focus-visible{
  outline:2px solid var(--cta);outline-offset:2px}
.btn:not(.ghost):focus-visible{outline-color:#fff;outline-offset:-4px}
.sheet-card:focus{outline:none}

@media (prefers-reduced-motion:reduce){
  /* Движение убираем, появление — нет: без него шторка возникает из ниоткуда
     и человек не понимает, откуда она взялась. */
  .sheet-dim{transition:opacity .16s ease}
  .sheet.out .sheet-dim{transition:opacity .14s ease}
  .sheet.on .sheet-card>.chan-art,.chan-miss{animation:none}
  .app{transition:none}
  body.sheeted .app{transform:none}
  .sheet-card{transform:none;opacity:0;transition:opacity .2s ease}
  .sheet.on .sheet-card{transform:none;opacity:1}
  .sheet.out .sheet-card{transition:opacity .16s ease}
  .sheet-grip{transition:none}
}

/* Кузя в кружке с рупором — тот же снимок и та же кайма, что в окне входа:
   два окна одного кабинета должны быть родственниками на глаз. */
.chan-art{position:relative;width:88px;height:88px;margin:2px auto 12px}
.chan-art img{width:100%;height:100%;object-fit:cover;object-position:50% 50%;border-radius:50%;
  box-shadow:0 0 0 3px #fff,0 0 0 5px var(--brand-glow),var(--sh-1)}
.chan-badge{position:absolute;right:-3px;bottom:-1px;width:31px;height:31px;border-radius:50%;
  display:grid;place-items:center;background:linear-gradient(180deg,#2E86FF,var(--cta-deep));
  box-shadow:0 0 0 3px #fff,0 2px 6px rgba(11,79,208,.32)}
.chan-badge svg{width:16px;height:16px}
/* Восьмисотое начертание в шторке одно — у заголовка. Когда полужирным
   набрано всё, выделять нечем: вторая кнопка кричала так же громко, как
   первая, а «Позже» весила больше объяснения. Переменный Inter даёт 500 и
   600 бесплатно, файл за них уже заплачен. */
.sheet-card .lbl{font-weight:700;letter-spacing:.075em}
.sheet-card h2{margin:5px 0 6px;font-size:22px;font-weight:800;color:var(--brand-deep);
  letter-spacing:-.015em;line-height:1.15;text-wrap:balance}
.chan-lead{margin:0 0 14px;color:var(--soft);font-size:14.5px;line-height:1.5;
  text-wrap:balance;max-width:33ch;margin-inline:auto}
.chan-list li{font-weight:500}
/* Обведённой кнопке край нужен виден: на --line-2 он давал 1.55:1 и она
   читалась плашкой без контура. */
.sheet-card .btn.ghost{font-weight:700;border-color:var(--line-strong)}
.chan-list{margin:0;padding:13px 14px;border-top:0;border-radius:var(--r);
  background:var(--tint);border:1px solid var(--line)}
.sheet-card .btns{margin-top:14px}
/* Единственный способ отказаться — и он был самой мелкой целью на экране:
   38 px в высоту при минимуме 44. */
/* Строка отказа. Тон предупреждающий, а не тревожный: человек ничего не
   сломал, он просто ещё не подписался. Текст слева, иконка отдельной
   колонкой — так вторая строка встаёт под первой, а не под значком. */
.chan-miss{display:grid;grid-template-columns:auto 1fr;align-items:start;gap:9px;
  margin:10px 0 0;padding:11px 13px;border-radius:var(--r);text-align:left;
  background:#FDF4E6;border:1px solid #E6CE9F;color:#8A5310;
  font-size:13.5px;line-height:1.45;font-weight:500;
  animation:miss-in .26s cubic-bezier(.22,1,.36,1) both}
/* Две строки заданы явно, а не отданы переносу: у одной фразы в две строки
   разрыв приходился на середину предложения, и полоска выглядела обрывком.
   Сверху — что произошло, снизу — что делать. */
.chan-miss b{display:block;font-weight:700;margin-bottom:1px}
.chan-miss span{text-wrap:balance}
.chan-miss[hidden]{display:none}
.chan-miss svg{width:17px;height:17px;margin-top:1px;color:var(--warn)}
@keyframes miss-in{from{opacity:0;transform:translateY(-5px)}}

.chan-later{margin-top:4px;background:none;border:0;font-family:var(--font);font-size:14px;
  font-weight:600;color:var(--mute);min-height:44px;padding:12px 20px;cursor:pointer;
  border-radius:var(--pill)}
.chan-later:active{background:var(--brand-soft)}

/* Подпись под кнопкой пробного на главной: условие названо до нажатия,
   чтобы окно с каналом не выглядело подвохом. */
.note.chan{margin-top:9px;display:flex;align-items:center;justify-content:center;gap:6px}
.note.chan svg{width:14px;height:14px;color:var(--brand)}


/* ─────────────────────────── панель

   Раздел для двоих, а не для всех, и читают в нём цифры, а не выбирают
   тариф. Отсюда и вид: плотнее остального кабинета, числа моноширинными
   цифрами Inter, карточки без праздничных теней. Токены те же — это всё ещё
   один продукт, а не второй интерфейс со своей палитрой. */

/* Кнопка панели в меню появляется только у админа: разметка есть всегда,
   право показать её даёт класс на body после ответа сервера. */
.bar button.adm-tab{display:none}
body.is-adm .bar button.adm-tab{display:flex}
body.is-adm .bar .in{grid-template-columns:repeat(6,1fr)}
body.is-adm .bar .pin{width:16.6667%}
/* Шесть колонок вместо пяти: подписи ужимаются, иначе «Управление» встаёт
   в две строки и ряд кнопок получается разной высоты. Только для нижней
   полосы — в левой колонке широкого экрана места хватает, и ужимать там
   нечего. */
@media (max-width:959px){
  body.is-adm .bar button{font-size:10px;gap:2px}
  body.is-adm .bar button svg{width:23px;height:23px}
  /* Тот же зазор по вертикали, что у капсулы активной вкладки (`top:6px;
     bottom:6px`). Здесь оставалось 8px от прежней раскладки, и у админа —
     а колонок у него шесть — светлая капсула по-прежнему торчала из-под
     рамки «Купить» снизу и сверху. По горизонтали рамка чуть шире капсулы
     (3px против 4px): лучше пусть кнопка перекрывает капсулу, чем наоборот. */
  body.is-adm .bar button[data-tab="shop"]{margin:6px 3px}
  body.is-adm .bar button[data-tab="manage"] .lb{font-size:9px}
}

.atop{display:flex;align-items:flex-end;justify-content:space-between;gap:12px;
  padding:2px 2px 0}
.atop h1{margin:1px 0 0;font-size:24px;font-weight:800;letter-spacing:-.02em;
  color:var(--brand-deep);line-height:1.1}
/* Кнопка обновления — иконкой: подпись «Обновить» рядом с заголовком раздела
   спорит с ним за внимание, а значок читается как служебный. */
.aico{display:grid;place-items:center;width:40px;height:40px;flex:0 0 auto;
  border:1px solid var(--line);border-radius:12px;background:var(--card);
  color:var(--brand-deep);cursor:pointer;box-shadow:var(--sh-1)}
.aico svg{width:19px;height:19px}
.aico:active{transform:translateY(1px);background:var(--brand-soft)}
.aico.spin svg{animation:aspin .7s linear infinite}
@keyframes aspin{to{transform:rotate(360deg)}}

/* Полоса живых чисел над разделами.

   Карточка светлая, как весь кабинет: сплошная зелёная плашка забирала себе
   весь верх экрана и делала одинаково важными число в сети и «денег за
   день». Зелёным залит только блок онлайна — он один и меняется сам.

   Первым — сколько человек прямо сейчас в сети: единственная цифра панели,
   которая шевелится, пока на неё смотрят. Поэтому рядом дышит точка, справа
   идёт искра последних замеров, а изменение показывается разницей. */
.ahero{margin-top:14px;border-radius:var(--r-lg);overflow:hidden;
  background:var(--glass);
  border:1px solid var(--glass-edge);box-shadow:var(--glass-lift)}

/* Блок онлайна. Свет под числом, а не заливка во всю карточку: зелёное
   пятно держит взгляд там, где живая цифра, и не спорит с остальными. */
.ahero-live{position:relative;padding:14px 16px 13px;
  background:radial-gradient(120% 150% at 0% 0%,#E2E9F3,#F0F4F9 62%,transparent);
  border-bottom:1px solid var(--line)}
.ahero-t{display:flex;align-items:center;gap:8px}
.ahero-dot{width:8px;height:8px;border-radius:50%;background:var(--brand);flex:0 0 auto;
  box-shadow:0 0 0 4px rgba(67,97,140,.16);animation:apulse 2.4s ease-in-out infinite}
.ahero-dot.off{background:#E0A93B;animation:none;box-shadow:0 0 0 4px rgba(224,169,59,.18)}
.ahero-k{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.09em;
  color:var(--mute)}
/* Разница появляется на четыре секунды и уходит: постоянная «+3» рядом с
   числом читается как часть числа. */
.ahero-d{font-size:11.5px;font-weight:800;color:var(--brand-deep);opacity:0;
  transform:translateY(-2px);transition:opacity .3s ease,transform .3s ease;
  font-variant-numeric:tabular-nums}
.ahero-d.on{opacity:1;transform:none}
.ahero-d.down{color:var(--mute)}
.ahero-n{display:flex;align-items:flex-end;gap:12px;margin-top:2px}
.ahero-n b{font-size:38px;font-weight:800;letter-spacing:-.03em;line-height:1;
  color:var(--brand-deep);font-variant-numeric:tabular-nums}
.ahero-spark{display:block;margin-bottom:3px;line-height:0}
.ahero-spark svg{display:block}
.ahero-sub{margin-top:5px;font-size:12px;font-weight:600;color:var(--mute);
  font-variant-numeric:tabular-nums;min-height:16px}
@keyframes apulse{50%{box-shadow:0 0 0 8px rgba(67,97,140,.05)}}
@media (prefers-reduced-motion:reduce){.ahero-dot{animation:none}}

/* Числа под онлайном. Разделены волосяными линиями, а не воздухом: пять
   значений подряд без границ читаются как одна длинная строка. */
.ahero-g{display:grid;grid-template-columns:repeat(4,1fr)}
.ahero-c{min-width:0;text-align:center;padding:11px 4px 12px;
  border-left:1px solid var(--line)}
.ahero-c:first-child{border-left:0}
.ahero-c b{display:block;font-size:17px;font-weight:800;letter-spacing:-.02em;
  color:var(--ink);font-variant-numeric:tabular-nums;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ahero-c span{display:block;margin-top:3px;font-size:9.5px;font-weight:700;
  text-transform:uppercase;letter-spacing:.045em;color:var(--mute);line-height:1.25}
/* Два числа из пяти цветные: пробные — тем же синим, что и метка «пробный» в
   списке людей, деньги — золотом. Остальные чернилами: если выделено всё,
   не выделено ничего. */
.ahero-c.trial b{color:#2C5A8A}
.ahero-c.paid b{color:var(--brand-deep)}
.ahero-c.money{grid-column:span 4;border-left:0;border-top:1px solid var(--line);
  display:flex;align-items:baseline;justify-content:center;gap:8px;padding:9px 4px 10px}
.ahero-c.money b{display:inline;font-size:16px;color:#8A5A0F}
.ahero-c.money span{display:inline;margin:0}

/* Возврат из раздела. Своей строкой над содержимым, а не в шапке: шапка одна
   на все экраны, и стрелка в ней спорила бы с кнопкой обновления. */
.aback-row{margin-bottom:-4px}

#adm-body{margin-top:14px;display:flex;flex-direction:column;gap:12px}

/* Карточка раздела. Тень слабее общей: на экране их по пять штук сразу, и
   полная тень превращает список в стопку наклеек. */
/* Статистика: блок онлайна с кривой за сутки. Тот же материал, что и полоса
   на корне, — крупная цифра, три ячейки под ней и график во всю ширину. */
.aonline{margin-top:14px;border-radius:var(--r-lg);overflow:hidden;
  background:var(--glass);border:1px solid var(--glass-edge);box-shadow:var(--glass-lift);
  padding:14px 16px 10px}
.aonline-t{display:flex;align-items:center;gap:8px}
.aonline-n b{display:block;margin-top:4px;font-size:44px;font-weight:800;letter-spacing:-.03em;
  line-height:1;color:var(--ink);font-variant-numeric:tabular-nums}
.aonline-g{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:12px;
  padding-top:10px;border-top:1px solid var(--line)}
.aonline-c{min-width:0}
.aonline-c b{display:block;font-size:15px;font-weight:800;letter-spacing:-.02em;color:var(--ink);
  font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.aonline-c span{display:block;margin-top:2px;font-size:9.5px;font-weight:700;
  text-transform:uppercase;letter-spacing:.07em;color:var(--mute)}
.aonline-chart{margin:12px -6px 0;line-height:0}
.aonline-chart svg{display:block;width:100%;height:auto}
.aonline-chart .g{stroke:var(--line);stroke-width:1}
.aonline-chart .ax{font-size:8.5px;font-weight:700;fill:var(--mute);font-variant-numeric:tabular-nums}
.aonline-chart .ln{fill:none;stroke:var(--brand);stroke-width:1.8;stroke-linejoin:round;stroke-linecap:round}
.aonline-chart .ln-dot{fill:var(--brand)}
.aonline-chart .pk{fill:var(--brand);stroke:var(--card);stroke-width:1.5}
.aonline-chart .now{fill:var(--brand);stroke:#fff;stroke-width:2}
.aonline-chart .tag{font-size:9.5px;font-weight:800;fill:var(--ink)}
.aonline-chart{position:relative;touch-action:pan-y;cursor:crosshair}
.aonline-chart .hv line{stroke:var(--ink);stroke-width:1;stroke-dasharray:3 3;opacity:.45}
.aonline-chart .hv circle{fill:#fff;stroke:var(--brand);stroke-width:2.4}
.aonline-tip{position:absolute;left:50%;top:0;transform:translate(-50%,-100%) scale(.96);
  padding:6px 10px 5px;border-radius:10px;background:var(--ink);color:#fff;
  box-shadow:0 6px 18px rgba(10,22,44,.28);white-space:nowrap;text-align:center;
  pointer-events:none;opacity:0;transition:opacity .12s,transform .12s;z-index:2;line-height:1.1}
.aonline-tip.on{opacity:1;transform:translate(-50%,-100%) scale(1)}
.aonline-tip b{display:block;font-size:17px;font-weight:800;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.aonline-tip span{display:block;margin-top:2px;font-size:10.5px;font-weight:700;opacity:.72;letter-spacing:.04em}
.aonline-tip::after{content:'';position:absolute;left:50%;bottom:-5px;width:10px;height:10px;
  background:var(--ink);transform:translateX(-50%) rotate(45deg);border-radius:2px}
.aonline-upd{margin:4px 0 2px;font-size:11px;font-weight:600;color:var(--mute);text-align:center}
.aonline-empty{padding:26px 8px;text-align:center;font-size:12.5px;font-weight:600;color:var(--mute);line-height:1.4}
.astats.pair{grid-template-columns:repeat(2,1fr);gap:12px 10px}
.astats.pair .astat{text-align:left;padding-left:2px}
.astats.pair .astat b{font-size:19px}
.aconv{margin-top:12px;padding-top:10px;border-top:1px solid var(--line)}

.acard{background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:13px 14px 14px;box-shadow:0 1px 2px rgba(10,22,44,.05)}
.acard>.lbl{margin-bottom:9px}
.acard .anote{margin:8px 0 0;font-size:12.5px;font-weight:500;color:var(--mute)}

/* Плитки чисел. Три колонки на телефоне — это предел, при котором «12 480 ₽»
   ещё не переносится. */
.astats{display:grid;grid-template-columns:repeat(3,1fr);gap:11px 8px}
.astat{min-width:0;text-align:center}
.astat b{display:block;font-size:16px;font-weight:800;letter-spacing:-.02em;
  color:var(--brand-deep);font-variant-numeric:tabular-nums;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Цифра, требующая решения: возвраты, зависшие счета, баны. Не «плохая», но
   теряться среди зелёных ей нельзя. */
.astat b.warn{color:var(--warn)}
.astat b.bad{color:var(--bad)}
.astat b.mute{color:var(--soft)}
.astat span{display:block;margin-top:2px;font-size:10px;font-weight:700;
  text-transform:uppercase;letter-spacing:.04em;color:var(--mute);line-height:1.25}

/* Строка списка: слева кто или что, справа сколько. Одна деталь на людей,
   платежи, кампании и проверки — списки в панели читаются одинаково. */
.arow{display:grid;grid-template-columns:1fr auto;align-items:center;gap:10px;
  width:100%;text-align:left;font-family:var(--font);
  padding:10px 2px;border:0;border-top:1px solid var(--line);background:none;
  cursor:pointer;color:inherit}
.arow:first-of-type{border-top:0}
.arow.flat{cursor:default}
.arow .who{min-width:0}
.arow .who b{display:block;font-size:14px;font-weight:700;letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.arow .who span{display:block;margin-top:1px;font-size:12.5px;font-weight:500;color:var(--mute);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.arow .val{text-align:right;font-size:13.5px;font-weight:700;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.arow .val .good{color:var(--brand-deep)}
.arow .val .bad{color:var(--bad)}
.arow .val i{display:block;font-style:normal;font-size:11px;font-weight:600;
  color:var(--mute);margin-top:1px}
.arow:active{background:var(--tint)}
/* Разделы — списком по группам, а не плитками.

   Плитка хороша, когда в ряду сравнивают равные величины. Разделы сравнивать
   не нужно: это разные места, и человек ищет глазами название. Группы дают
   карту целиком — видно, что вообще есть в панели, без блужданий по
   промежуточным экранам.

   Цвет группы живёт только в шапке и в полоске сверху: раскрасить сами
   строки значило бы превратить список в светофор. */
.agrp{position:relative;background:var(--glass);
  border:1px solid var(--glass-edge);border-radius:var(--r);overflow:hidden;
  box-shadow:var(--glass-in-lift)}
.agrp::before{content:'';position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,var(--gt),transparent)}
.agrp.an{--gt:var(--brand);--gb:linear-gradient(160deg,#4E9BFF,var(--cta-deep))}
.agrp.us{--gt:#3E6FA8;--gb:linear-gradient(160deg,#4E80B8,#2C5A8A)}
.agrp.sl{--gt:#A8607F;--gb:linear-gradient(160deg,#B87494,#8A4A66)}
.agrp.sy{--gt:#C08A2E;--gb:linear-gradient(160deg,#D6A244,#8A5A0F)}
.agrp-h{display:flex;align-items:center;gap:11px;padding:13px 14px 12px}
.agrp-h b{font-size:16.5px;font-weight:800;letter-spacing:-.015em}
/* Сколько внутри — подписью справа: это справка, а не имя группы. */
.agrp-c{margin-left:auto;font-size:11px;font-weight:700;color:var(--mute);
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* В квадрате номер группы: по нему её называют вслух — «второй блок». */
.agrp-n{display:grid;place-items:center;width:30px;height:30px;flex:0 0 auto;
  border-radius:9px;background:var(--gb);color:#fff;
  font-size:14px;font-weight:800;font-variant-numeric:tabular-nums;
  box-shadow:0 2px 5px rgba(10,22,44,.16)}

.amrow{display:flex;align-items:center;gap:12px;width:100%;min-height:58px;
  padding:10px 14px;border:0;border-top:1px solid var(--line);background:none;
  font-family:var(--font);color:inherit;text-align:left;cursor:pointer}
.amrow:active{background:var(--tint)}
/* Значок обведён, а не залит: заливка на каждой строке спорит с квадратом
   группы, и шапка перестаёт быть шапкой. */
.amrow-i{display:grid;place-items:center;width:36px;height:36px;flex:0 0 auto;
  border-radius:10px;border:1px solid var(--glass-hi-edge);color:var(--brand-deep);
  background:var(--glass-hi)}
.amrow-i svg{width:19px;height:19px}
.amrow-t{min-width:0;flex:1}
.amrow-t b{display:block;font-size:15px;font-weight:700;letter-spacing:-.01em}
/* Пояснение в одну строку: вторая раздвигает соседей и ломает ритм списка.
   Не влезло — обрезаем многоточием. */
.amrow-t span{display:block;margin-top:1px;font-size:12px;color:var(--mute);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Справа число и подпись под ним: «14 730 ₽» без подписи требует держать в
   голове, за месяц это или за всё время. Подпись мелкая и приглушённая —
   она объясняет число, а не спорит с ним. */
.amrow-v{flex:0 0 auto;text-align:right;white-space:nowrap}
.amrow-v b{display:block;font-size:14.5px;font-weight:800;letter-spacing:-.015em;
  color:var(--brand-deep);font-variant-numeric:tabular-nums}
.amrow-v i{display:block;margin-top:1px;font-style:normal;font-size:10px;font-weight:700;
  text-transform:uppercase;letter-spacing:.045em;color:var(--mute)}
.amrow.warn .amrow-v b{color:var(--warn)}
.amrow.bad .amrow-v b{color:var(--bad)}
.amrow.bad .amrow-i{border-color:#E8CFCB;color:var(--bad)}
.amrow.warn .amrow-i{border-color:#E6CE9F;color:var(--warn)}
.amrow.mute .amrow-v b{color:var(--soft)}
.amrow.mute .amrow-i{color:var(--mute)}

/* Поиск на корне — отдельной строкой над группами. */
.asearch .ain{height:46px;font-size:15.5px}

/* Плитки чисел внутри карточки — подпись к ней, а не отдельная карточка:
   отбиваются чертой и живут теснее. */
.acard .astats{margin-top:0}

/* Состояние — словом и цветом сразу: цвет один читается только тем, кто уже
   знает легенду. */
.apill{display:inline-block;padding:2px 8px;border-radius:var(--pill);
  font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.04em}
.apill.active{background:var(--brand-soft);color:var(--brand-deep)}
.apill.trial{background:#EAF0FA;color:#2C5A8A}
.apill.expired{background:#F3F1EA;color:var(--soft)}
.apill.banned{background:#FBE9E7;color:var(--bad)}
.apill.none{background:#F3F1EA;color:var(--mute)}

/* Поиск и фильтры. */
.asearch{display:flex;gap:8px;align-items:center}
.ain{flex:1;min-width:0;height:42px;border:1px solid var(--line);border-radius:12px;
  background:var(--card);padding:0 13px;font-family:var(--font);font-size:15px;
  color:var(--ink)}
.ain:focus{outline:2px solid var(--brand);outline-offset:1px;border-color:transparent}
.ain::placeholder{color:var(--mute)}
.achips{display:flex;gap:6px;margin-top:10px;overflow-x:auto;scrollbar-width:none}
.achips::-webkit-scrollbar{display:none}
.achips button{flex:0 0 auto;border:1px solid var(--line);background:var(--card);
  font-family:var(--font);font-size:12.5px;font-weight:700;color:var(--mute);
  padding:6px 11px;border-radius:var(--pill);cursor:pointer;min-height:34px}
.achips button.on{background:var(--brand-soft);border-color:transparent;color:var(--brand-deep)}
.achips button i{font-style:normal;font-weight:800;opacity:.65;margin-left:5px;
  font-variant-numeric:tabular-nums}

/* Полосы: воронка и деньги по дням. Подпись всегда рядом с полосой, а не под
   осью — на телефоне ось читать нечем. */
.abar{margin-top:9px}
.abar:first-of-type{margin-top:0}
.abar .t{display:flex;justify-content:space-between;align-items:baseline;gap:8px;
  font-size:12.5px;color:var(--soft)}
.abar .t b{font-weight:800;color:var(--ink);font-variant-numeric:tabular-nums}
.abar .t i{font-style:normal;font-size:11px;color:var(--mute);font-variant-numeric:tabular-nums}
.abar .m{margin-top:4px;height:8px;border-radius:var(--pill);background:var(--brand-soft);
  overflow:hidden}
.abar .m i{display:block;height:100%;border-radius:var(--pill);
  background:linear-gradient(90deg,var(--brand-glow),var(--brand));
  transition:width .4s cubic-bezier(.22,1,.36,1)}
/* День без денег — не ошибка, но и полосой в ноль пикселей он выглядит как
   пропуск данных. Минимальная засечка говорит «ноль», а не «неизвестно». */
.abar .m i.zero{width:2px !important;background:var(--line-2)}

/* Карточка человека. */
.aback{display:inline-flex;align-items:center;gap:7px;border:0;background:none;
  font-family:var(--font);font-size:13.5px;font-weight:700;color:var(--brand-deep);
  padding:8px 10px 8px 2px;min-height:40px;cursor:pointer}
.aback svg{width:16px;height:16px}
.aid{display:flex;align-items:center;gap:8px;margin-top:6px;flex-wrap:wrap}
.aid .apill{vertical-align:1px}
.aid button{border:1px solid var(--line);background:var(--card);border-radius:var(--pill);
  font-family:var(--font);font-size:12px;font-weight:700;color:var(--soft);
  padding:4px 10px;min-height:30px;cursor:pointer;font-variant-numeric:tabular-nums}
.aid button:active{background:var(--brand-soft)}

/* Пары «что — сколько» в карточке: подписи слева узкой колонкой, значения
   справа. Двоеточий нет — их роль выполняет колонка. */
.afacts{display:grid;grid-template-columns:auto 1fr;gap:7px 12px;font-size:13.5px}
.afacts dt{color:var(--mute);font-size:12.5px}
.afacts dd{margin:0;font-weight:600;text-align:right;font-variant-numeric:tabular-nums}
.afacts dd.warn{color:var(--warn)}
.afacts dd.bad{color:var(--bad)}

/* Действия. Разрушающие отделены чертой и покрашены: «Удалить» рядом с
   «Написать» одинаковой кнопкой — приглашение к ошибке. */
.aacts{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.aact{display:flex;align-items:center;justify-content:center;gap:7px;min-height:44px;
  border:1px solid var(--line);border-radius:12px;background:var(--card);
  font-family:var(--font);font-size:13.5px;font-weight:700;color:var(--brand-deep);
  cursor:pointer;padding:0 10px;text-align:center}
.aact:active{background:var(--brand-soft);transform:translateY(1px)}
.aact.danger{color:var(--bad);border-color:#E8CFCB}
.aact.danger:active{background:#FBE9E7}
.aact.wide{grid-column:1 / -1}
.aacts.sep{margin-top:10px;padding-top:10px;border-top:1px solid var(--line)}

/* Пустой раздел и ошибка — одной деталью: и то и другое отвечает на вопрос
   «почему тут ничего нет». */
.aempty{margin:0;padding:18px 4px;text-align:center;color:var(--mute);font-size:13.5px}

/* Поле в окне действия. */
/* Поля шторки привязки: подписи слева, как в окне входа, а не по центру —
   шторка тут форма, а не вопрос «сколько дней». */
#bind .sheet-card{text-align:left}
#bind .lbl,#bind h2,#bind .chan-lead{text-align:left}
#bind .fld{margin-top:11px}
#bind .btns{margin-top:14px}

.ask-in{width:100%;height:46px;border:1px solid var(--line);border-radius:12px;
  background:var(--card);padding:0 13px;font-family:var(--font);font-size:16px;
  color:var(--ink);margin-top:4px}
.ask-in:focus{outline:2px solid var(--brand);outline-offset:1px;border-color:transparent}
.ask-area{height:auto;padding:11px 13px;line-height:1.45;resize:vertical;min-height:96px}
.ask-in[hidden]{display:none}
/* Готовые величины: «30 дней» нажимают в девяти случаях из десяти, и
   набирать их руками на телефоне — лишний экран клавиатуры. */
.ask-quick{display:flex;gap:7px;flex-wrap:wrap;justify-content:center;margin-top:10px}
.ask-quick button{border:1px solid var(--line);background:var(--card);border-radius:var(--pill);
  font-family:var(--font);font-size:13.5px;font-weight:700;color:var(--brand-deep);
  padding:7px 14px;min-height:38px;cursor:pointer;font-variant-numeric:tabular-nums}
.ask-quick button.on{background:var(--brand-soft);border-color:transparent}
.ask-quick[hidden]{display:none}

@media (max-width:400px){
  .astats{gap:10px 6px}
  .astat b{font-size:15px}
}

@media (min-width: 960px) {
  /* Панель шире остальных экранов: здесь читают таблицы, и колонка в 640
     пикселей заставляла бы прокручивать то, что помещается рядом. */
  #s-adm{max-width:940px}
  #adm-body{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}
  /* Во всю ширину — то, что читается строками: списки людей, платежей и
     журнал. Плитки и короткие сводки живут в половине. */
  #adm-body>.wide{grid-column:1 / -1}
  /* Полоса живых чисел на мониторе — одной строкой: пять клеток помещаются,
     и переносить деньги вниз незачем. */
  .ahero{grid-column:1 / -1}
  .ahero-g{grid-template-columns:repeat(5,1fr)}
  .ahero-c.money{grid-column:auto;display:block;border-top:0;border-left:1px solid var(--line);
    padding:11px 4px 12px}
  .ahero-c.money b{display:block;font-size:17px}
  .ahero-c.money span{display:block;margin-top:3px}
  .astats{grid-template-columns:repeat(4,1fr)}
  .amrow:hover{background:var(--tint)}
  .amrow:hover .amrow-i{border-color:var(--line-strong)}
  .arow:hover{background:var(--tint)}
  .aact:hover{border-color:var(--line-strong);background:#fff}
  .aico:hover{border-color:var(--line-strong)}
}

/* Кнопка разрушающего действия в окне: бан, закрытие доступа, возврат,
   удаление. Обведённая зелёная читалась как «продолжить», хотя за ней стоит
   то, что нельзя отменить. */
.btn.danger{background:linear-gradient(180deg,#C0392B,#A5301F);
  box-shadow:0 2px 4px rgba(120,30,20,.24),0 8px 18px rgba(120,30,20,.22)}
.btn.danger:active{filter:brightness(.94)}

/* ─── список людей и карточка */

/* Буква в кружке: список из двадцати одинаковых строк глазом не делится, а
   по букве и цвету человек находит того, кого уже открывал. Цвет считается
   из номера, поэтому у одного человека он всегда один и тот же. */
.aava{display:grid;place-items:center;width:38px;height:38px;flex:0 0 auto;
  border-radius:50%;font-size:15px;font-weight:800;color:#fff;
  box-shadow:inset 0 -1px 0 rgba(0,0,0,.12)}
.aava.t0{background:linear-gradient(160deg,#4E9BFF,#0B4FD0)}
.aava.t1{background:linear-gradient(160deg,#4E80B8,#2C5A8A)}
.aava.t2{background:linear-gradient(160deg,#B87494,#8A4A66)}
.aava.t3{background:linear-gradient(160deg,#D6A244,#8A5A0F)}
.aava.t4{background:linear-gradient(160deg,#6FA8A0,#356F68)}

/* Строка человека: аватарка, имя с номером, справа метка и хвост цифр. */
.arow.aperson{display:grid;grid-template-columns:auto 1fr auto;gap:11px;
  padding:9px 2px}
.arow.aperson .val{display:flex;flex-direction:column;align-items:flex-end;gap:3px}
.arow.aperson .val i{margin-top:0;font-size:11px}

/* Шапка карточки — визитка: лицо, имя, состояние. */
.aperson-h{display:flex;align-items:center;gap:12px;margin-bottom:10px}
.aperson-h .aava{width:48px;height:48px;font-size:19px}
.aperson-h h2{margin:0;font-size:19px;font-weight:800;letter-spacing:-.015em;
  overflow-wrap:anywhere}
.aperson-h .aid{margin-top:5px}

/* Партнёрская сеть. Сумма заявки — крупно и зелёным: список заявок читают
   ради сумм. Адрес кошелька — своей плашкой моноширинным: его копируют,
   а не читают, и он не должен ломать сетку фактов. */
.apsum{font-size:15px;font-weight:800;color:var(--brand-deep);font-variant-numeric:tabular-nums}
.apaddr{display:block;width:100%;margin-top:12px;padding:10px 12px;text-align:left;
  border:1px dashed var(--line-2);border-radius:12px;background:var(--tint);
  font-family:var(--font);color:inherit;cursor:pointer}
.apaddr:active{background:var(--brand-soft)}
.apaddr span{display:block;font-size:10.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--mute)}
.apaddr code{display:block;margin-top:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:12.5px;font-weight:600;overflow-wrap:anywhere;line-height:1.35}
.aflag{display:flex;gap:10px;align-items:flex-start;padding:8px 0;border-top:1px solid var(--line);
  font-size:13.5px;line-height:1.35}
.aflag:first-of-type{border-top:0;padding-top:0}
.aflag b{display:grid;place-items:center;flex:0 0 auto;width:22px;height:22px;border-radius:50%;
  background:#FBEFD9;color:var(--warn);font-size:13px;font-weight:900}
.apnet-i{width:48px;height:48px;border-radius:14px;background:var(--brand-soft);color:var(--brand-deep)}
.apnet-i svg{width:24px;height:24px}
.astat b.good{color:var(--brand-deep)}
.acard .astats.aconv{margin-top:12px}
/* Итоговая строка потока денег: то, ради чего карточку открыли. */
.arow.aptotal{margin-top:4px;padding-top:12px;border-top:2px solid var(--line-2)}
.arow.aptotal .who b{font-size:15px}
.arow.aptotal .val{font-size:16px}
.arow .val .warn{color:var(--warn)}

/* Порядок сортировки — своей строкой под срезами: «кого показывать» и «в
   каком порядке» это разные вопросы, вперемешку они читаются одним длинным
   рядом кнопок. */
.achips.sorts{margin-top:8px;align-items:center}
.achips-k{flex:0 0 auto;font-size:10.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--mute);padding-right:2px}

/* ─────────────────────────── управление подпиской

   Четыре карточки: тариф, устройства, трафик, покупки. Всё внутри выровнено
   по середине — заголовок раздела, число под ним, привязки, плитки оплат:
   экран читается сверху вниз одной колонкой, и глазу не приходится каждый
   раз искать, где на этот раз начинается строка. Своих цветов и своих форм
   здесь нет: те же карточки, полосы и счётчики, что на главной и в профиле.

   Кнопка обновления вынута из потока в угол карточки: в потоке она сдвигала
   заголовок с середины, и соседние карточки читались как разная вёрстка. */

/* Карточки управления — из того же стекла, что карточка первого шага на
   главной. Белые непрозрачные плашки стояли на том же светящемся листе и
   читались другим экраном: тот же кабинет, а материал разный.

   Снаружи одна размытая поверхность на карточку; всё, что внутри (строки,
   плитки привязок, кружки значков, кнопка обновления), берёт полупрозрачную
   заливку поверх уже размытой подложки, своего backdrop-filter не заводит. */
#s-manage .card{text-align:center}
#s-manage .card.mng{position:relative}

/* Строка «что — сколько», плитки привязок и свободный слот — внутренний
   уровень стекла. */
#s-manage .kv,#s-manage .dev{background:var(--glass-in);
  border:1px solid var(--glass-in-edge);box-shadow:var(--glass-in-lift)}
#s-manage .kv .i,#s-manage .dev .ic,#s-manage .dev .un,
#s-manage .card>.hd .sic{background:var(--glass-hi);
  border:1px solid var(--glass-hi-edge);box-shadow:var(--glass-in-lift)}
/* Свободный слот остаётся пунктиром — это единственная плитка, которая
   обещает место, а не показывает занятое. */
#s-manage .dev.free{background:var(--glass-hi);border-style:dashed;
  border-color:rgba(122,158,214,.7);box-shadow:none}
#s-manage .dev.free .ic{border-style:dashed}
#s-manage .nrow{background:var(--glass-in);border:1px solid var(--glass-in-edge);
  box-shadow:var(--glass-in-lift)}
#s-manage .card>.rfr{background:var(--glass-hi);border-color:var(--glass-hi-edge);
  box-shadow:var(--glass-in-lift)}
#s-manage .card>.rfr:active{background:rgba(231,240,255,.8);
  box-shadow:inset 0 2px 6px rgba(10,22,44,.12)}


/* Заголовок экрана по центру, стрелка «назад» — поверх, слева: в потоке она
   съедала половину строки, и заголовок стоял не по середине. */
#s-manage .back{position:relative;justify-content:center;text-align:center;
  min-height:40px;padding-left:48px;padding-right:48px}
#s-manage .back .ico{position:absolute;left:0;top:0}

/* Шапка раздела: метка капсом и одно число под ней. */
#s-manage .card>.hd .lbl{display:block}
#s-manage .card>.hd b{display:block;margin-top:3px;font-size:16px;font-weight:800;
  letter-spacing:-.02em;line-height:1.25}
#s-manage .card.lead>.hd b{font-size:20px}
#s-manage .card>.hd+.sub{margin-top:5px}

#s-manage .card>.rfr{position:absolute;top:10px;right:10px;width:30px;height:30px;
  border-radius:9px;border:1px solid var(--line);cursor:pointer;
  background:var(--tint);color:var(--soft);display:grid;place-items:center;padding:0}
#s-manage .card>.rfr svg{width:15px;height:15px}
#s-manage .card>.rfr:active{background:var(--brand-soft);
  box-shadow:inset 0 2px 6px rgba(10,22,44,.12)}
/* Запрос в полёте виден на самой кнопке: список при обновлении не мигает, и
   без этого нажатие выглядит как несработавшее. */
#s-manage .card>.rfr.spin svg{animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(-360deg)}}

/* Подписи полос — тоже по центру, одной строкой «что» и «сколько». */
#s-manage .gauges{margin-top:14px;gap:13px}
#s-manage .gauge .t{justify-content:center;gap:7px}
/* Число полосы не переносится: «31,4 из 50 ГБ», разорванное на «31,4 из 50»
   и «ГБ», читается как две разные величины. Ломаться при нехватке места
   разрешено подписи — она длиннее и на смысл строки не влияет. */
#s-manage .gauge .t b{white-space:nowrap}
@media (max-width:359px){ #s-manage .gauge .t{font-size:12px;gap:6px} }
@media (max-width:359px){
  .hstats .c{gap:5px;padding:9px 7px}
  .hstats .c .i{width:22px;height:22px}
  .hstats .c .i svg{width:14px;height:14px}
  .hstats .c .k{font-size:10px}
  .hstats .c b{font-size:14px}
}
#s-manage .card>.meter{margin-top:12px}
#s-manage .card>.under{margin-top:7px;font-size:12px;color:var(--mute)}
#s-manage .card>.stats{margin-top:13px;margin-bottom:2px}
#s-manage .card>.reset{justify-content:center;margin-top:11px}
#s-manage .card>.reset b{margin-left:0}
#s-manage .btns{margin-top:12px}
#s-manage .card>.note{margin-top:11px;line-height:1.4}

/* ── привязанные устройства

   Плитка столбиком, а не строка: имя приезжает из заголовков клиента
   («DESKTOP-К7ПЕТРОВ · Windows 11 24H2») и на узком экране отжимало кнопку
   «Отвязать» за правый край — нажать её было нечем. Столбиком ширина имени
   ни на что не влияет, а кнопка занимает всю плитку. */
/* Слоты точками: закрашенная — занятый, пустая — свободный. Заголовок
   отвечает словом («1 слот свободен»), точки — рисунком, и вместе они
   говорят ещё и «из скольких», не занимая на это строки. */
/* Карточка той же формы, что тариф, трафик и оплаты: шапка от края до края,
   под ней список и кнопки. Отступ держит каждая строка сама. */
#s-manage .card.devs-card{padding:0;overflow:hidden;text-align:left}
#s-manage .mng>.phd.dphd{display:block}
#s-manage .card.devs-card>.devs{margin:12px 12px 0}
#s-manage .card.devs-card>.dev.free{width:auto;margin:8px 12px 0}
#s-manage .card.devs-card>.nrow{margin:12px 12px 0}
#s-manage .card.devs-card>.btns{margin:11px 12px 0}
#s-manage .card.devs-card>.note{margin:11px 12px 12px;text-align:center}
/* Кнопка обновления стоит теперь на тёмной шапке: белая плашка на ней
   читалась как заплатка. */
#s-manage .card.devs-card>.rfr{background:rgba(255,255,255,.14);border-color:transparent;
  color:#CBD8EA;z-index:2}
#s-manage .card.devs-card>.rfr:active{background:rgba(255,255,255,.26);box-shadow:none}

/* Слоты точками — в самой шапке, под строкой: они уточняют её число, и
   отдельной строкой на белом читались как самостоятельный прибор. */
.slots{position:relative;z-index:1;display:flex;gap:6px;margin-top:10px}
.slots i{width:9px;height:9px;border-radius:50%;background:transparent;
  border:1.5px solid rgba(255,255,255,.4);box-sizing:border-box}
.slots i.on{background:linear-gradient(180deg,#C3D5F0,#84A3D0);border-color:transparent;
  box-shadow:0 1px 2px rgba(0,0,0,.25)}

/* Привязка — строкой: значок, имя с уточнением под ним, кнопка справа.

   Столбиком по центру плитка занимала полторы сотни точек на одно
   устройство, и три привязки не помещались в экран. Имя режется
   многоточием, поэтому длинное «DESKTOP-К7ПЕТРОВ · Windows 11 24H2»
   кнопку за правый край больше не отжимает — ради чего столбик и был. */
.devs{display:grid;gap:8px;margin-top:12px}
/* Привязки появляются очередью, как и плитки витрины: список из восьми
   строк, возникший разом, читается как перерисовка экрана. Задержка
   лесенкой по четыре строки — дальше очередь превращается в ожидание. */
.dev{display:flex;align-items:center;flex-wrap:wrap;gap:11px;
  padding:9px 10px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--tint);text-align:left;
  animation:rise .18s ease-out both}
.dev:nth-child(2){animation-delay:.03s}
.dev:nth-child(3){animation-delay:.06s}
.dev:nth-child(4){animation-delay:.09s}
.dev:nth-child(n+5){animation-delay:.12s}
.dev .ic{flex:0 0 auto;display:grid;place-items:center;width:36px;height:36px;
  border-radius:11px;background:#fff;border:1px solid var(--line);color:var(--brand-deep)}
.dev .ic svg{width:19px;height:19px}
.dev .tx{flex:1 1 auto;min-width:0}
.dev .tx b{display:block;font-size:14px;font-weight:800;letter-spacing:-.01em;
  line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dev .when{display:block;margin-top:2px;font-size:11.5px;color:var(--mute);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dev .un{flex:0 0 auto;height:32px;padding:0 13px;
  border:1px solid var(--line-2);border-radius:var(--pill);
  background:#fff;color:var(--soft);cursor:pointer;font-family:var(--font);
  font-size:12.5px;font-weight:800}
.dev .un:active{background:var(--brand-soft);color:var(--brand-deep)}

/* Свободный слот — та же плитка пунктиром: список показывает не только то,
   что подключено, но и то, куда влезет ещё. Она же кнопка подключения. */
.dev.free{width:100%;margin-top:8px;border-style:dashed;border-color:var(--line-strong);
  background:#fff;cursor:pointer;font-family:var(--font);text-align:left}
.dev.free .ic{border-style:dashed;color:var(--cta)}
.dev.free .tx b{color:var(--brand-deep)}
.dev.free:active{background:var(--brand-soft);transform:translateY(1px)}

.dev.skel{height:56px;border-style:dashed;
  background:linear-gradient(90deg,#E4ECFB,#F3F7FF,#E4ECFB);
  background-size:200% 100%;animation:sk 1.2s linear infinite}

/* Низкое поле мини-аппа: раздел с одной-двумя привязками обязан вставать
   целиком — из-за пары точек человек не должен листать список из одной
   строки. Длинный список листается и должен: восемь привязок в экран не
   поместятся никак. */
body.h-700 .slots{margin-top:8px}
/* Поле мини-аппа — около шестисот точек, и раздел с двумя привязками
обязан вставать целиком. Первой уходит объясняющая строка: её читают
один раз, а слоты, список и кнопки нужны каждый раз. */
body.h-700 #s-manage .card.devs-card>.note{display:none}
body.h-700 #s-manage .card.devs-card>.devs{margin-top:10px;gap:7px}
body.h-700 .dev{padding:8px 10px}
body.h-700 #s-manage .card.devs-card>.dev.free{margin-top:7px}
body.h-700 #s-manage .card.devs-card>.btns{margin-top:9px}
body.h-700 #s-manage .card.devs-card .btn.sm{height:40px}
body.h-700 #s-manage .card.devs-card>.note{margin:9px 12px 10px}
body.h-640 .slots{margin-top:7px}
body.h-640 #s-manage .card.devs-card>.devs{margin-top:9px;gap:6px}
body.h-640 .dev{padding:7px 10px;gap:9px}
body.h-640 .dev .ic{width:34px;height:34px;border-radius:10px}
body.h-640 #s-manage .card.devs-card>.dev.free{margin-top:6px}
body.h-640 #s-manage .card.devs-card>.btns{margin-top:8px}
body.h-640 #s-manage .card.devs-card .btn.sm{height:38px}
body.h-640 #s-manage .card.devs-card>.note{margin:8px 12px 9px}

/* Вопрос — в самой плитке: окно поверх экрана закрывало бы ровно то
   устройство, про которое спрашивает. */
.dev.ask{border-color:var(--line-strong);background:#fff}
/* Вопрос встаёт под строкой во всю её ширину: плитка теперь строка, и
   уместить его рядом с именем негде. */
.dev.ask .sure{flex:1 0 100%;margin-top:9px;padding-top:10px;border-top:1px solid var(--line)}
.dev.ask .sure>span{display:block;font-size:12.5px;font-weight:600;color:var(--soft)}
.dev.ask .sure .pair{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:9px}
.dev.ask .sure button{height:38px;border-radius:var(--r-sm);cursor:pointer;
  font-family:var(--font);font-size:13px;font-weight:800;border:1px solid transparent}
.dev.ask .sure .yes{background:linear-gradient(180deg,#C4463C,#A32A22);color:#fff;
  box-shadow:0 2px 6px rgba(140,30,24,.28)}
.dev.ask .sure .yes:active{filter:brightness(.95)}
.dev.ask .sure .yes.busy{opacity:.7;pointer-events:none}
.dev.ask .sure .no{background:#fff;border-color:var(--line-2);color:var(--soft)}
.dev.ask .sure .no:active{background:var(--brand-soft)}

/* ── история оплат

   Карточка той же формы, что тариф и трафик: тёмная шапка с итогом за всё
   время, под ней список. Строки — без подложки и рамки: восемь плиток
   подряд занимали два экрана, а разделять их и так есть чем — линией и
   месяцем. Столбик сумм у правого края читается сверху вниз сам. */
#s-manage .card.buys-card{padding:0;overflow:hidden;text-align:left}
#s-manage .card.buys-card>.buys{margin:2px 12px 11px}
#s-manage .card.buys-card>.note{margin:9px 12px 12px;text-align:center}
#s-manage .card.buys-card>.nrow{margin:12px 12px 12px}
#s-manage .card.buys-card>.btns{margin:11px 12px 12px}

.buys{display:block}
/* Разделитель месяца: список идёт от свежих к старым, и без него восемь
   одинаковых строк не отвечали на «когда это было». Итог справа — то, чего
   в списке нет: складывать восемь сумм в уме человек не станет. */
.bmo{display:flex;align-items:baseline;gap:8px;padding:11px 2px 5px}
.bmo>span{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.09em;
  color:var(--mute)}
/* Итог месяца — мельче и глуше сумм самих оплат: рядом с ними в один вес
   он читался как ещё одна покупка. */
.bmo>b{margin-left:auto;font-size:11px;font-weight:700;color:var(--mute);
  letter-spacing:-.01em}
.bmo:first-child{padding-top:9px}

.buy{display:flex;align-items:center;gap:11px;padding:9px 2px;
  border-top:1px solid var(--line);background:none;text-align:left}
.bmo+.buy{border-top:0}
.buy .ic{flex:0 0 auto;display:grid;place-items:center;width:32px;height:32px;
  border-radius:10px;background:var(--brand-soft);color:var(--brand-deep)}
.buy .ic svg{width:16px;height:16px}
/* Докупки отличаются тоном от продлений: в списке из восьми строк это
   единственный способ увидеть, на что уходят деньги, не читая названий. */
.buy .ic.traffic{background:#F3EEDC;color:#8A5A0F}
.buy .ic.devices{background:#E7EDF6;color:#2F4F7A}
.buy .tx{flex:1 1 auto;min-width:0}
.buy b{display:block;font-size:13.5px;font-weight:800;letter-spacing:-.01em;
  line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.buy span{display:block;margin-top:2px;font-size:11.5px;color:var(--mute)}
.buy em{flex:0 0 auto;font-style:normal;font-size:15px;font-weight:800;
  color:var(--brand-deep);white-space:nowrap}
.buy.skel{height:52px;border-top:0;margin-top:8px;border-radius:var(--r);
  border:1px dashed var(--line);
  background:linear-gradient(90deg,#E4ECFB,#F3F7FF,#E4ECFB);
  background-size:200% 100%;animation:sk 1.2s linear infinite}

/* Низкое поле: короткая история оплат обязана вставать в экран целиком. */
body.h-700 .bmo{padding:9px 2px 4px}
body.h-700 .buy{padding:8px 2px}
body.h-700 #s-manage .card.buys-card>.buys{margin-bottom:9px}
body.h-700 #s-manage .card.buys-card>.note{margin:8px 12px 10px}
body.h-640 .bmo{padding:8px 2px 4px}
body.h-640 .buy{padding:7px 2px;gap:9px}
body.h-640 .buy .ic{width:30px;height:30px;border-radius:9px}

/* Строка вместо списка: «пусто», «панель молчит» — человеку в обоих случаях
   нужен не перечень, а фраза. Значок над текстом, а не сбоку: сбоку он
   ломал бы середину, по которой выстроен весь экран. */
.nrow{margin-top:13px;padding:13px 12px;border-radius:var(--r);background:var(--tint);
  border:1px solid var(--line);font-size:12.5px;color:var(--soft);line-height:1.4}
.nrow .i{display:grid;place-items:center;width:26px;height:26px;margin:0 auto 7px;
  border-radius:9px;background:#fff;border:1px solid var(--line);color:var(--brand)}
.nrow .i svg{width:16px;height:16px}
.nrow>span{display:block}

/* Свет на этом экране тот же, что в профиле: разговор про своё, а не про
   покупку. */
body[data-tab="manage"] .aura i:nth-child(1){opacity:.62}

@media (prefers-reduced-motion:reduce){
  #s-manage .card>.rfr.spin svg{animation:none}
  .dev.skel,.buy.skel{animation:none}
}

/* Значок раздела над меткой. Четыре карточки одной формы подряд сливались в
   ленту: где кончился раздел и начался следующий, было видно только по
   чтению заголовка. */
#s-manage .card>.hd .sic{display:grid;place-items:center;width:38px;height:38px;
  margin:0 auto 9px;border-radius:12px;background:var(--brand-soft);color:var(--brand-deep);
  border:1px solid var(--line)}
#s-manage .card>.hd .sic svg{width:20px;height:20px}

/* ── переключатель разделов

   Экран перестал быть лентой из четырёх карточек: сводка стоит всегда, а
   тариф, устройства, трафик и оплаты живут за вкладками. Тот же вид, что и
   в витрине, только со значками и на переменное число колонок — на
   безлимите раздела трафика нет, и вкладок остаётся три. */
.mseg{grid-template-columns:repeat(var(--n,4),1fr);margin-top:12px}
.mseg .pin{width:calc((100% - 8px)/var(--n,4))}
.mseg button{display:grid;grid-template-rows:auto auto;gap:4px;place-items:center;
  height:54px;padding:0 3px;font-size:11px;letter-spacing:0}
.mseg button .i{display:grid;place-items:center;width:19px;height:19px}
.mseg button .i svg{width:19px;height:19px}
/* Подпись в одну строку: «Устройства» на узком экране переносилось и делало
   вкладки разной высоты — бегунок под ними съезжал. */
.mseg button .t{display:block;max-width:100%;line-height:1;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.mseg button.on .i{color:var(--brand)}
/* На узких телефонах «Устройства» не влезало и обрывалось многоточием —
   именно на том слове, ради которого вкладку и ищут. */
@media (max-width:359px){
  .mseg button{font-size:10px;letter-spacing:-.02em}
  .mseg button .i,.mseg button .i svg{width:18px;height:18px}
}

/* Счётчики считаются по числу ячеек. С двумя они держали три колонки от
   общего правила и стояли прижатыми влево — ровно то, что на экране,
   выстроенном по середине, читается как сломанная вёрстка. */
#s-manage .card>.stats.n2{grid-template-columns:repeat(2,1fr)}
#s-manage .card>.stats.n3{grid-template-columns:repeat(3,1fr)}

/* Строка «что — сколько» в разделе тарифа: страны и мобильные сервера. Не
   счётчиком, потому что значение здесь не число, и не примечанием, потому
   что читают его как факт о своей подписке. */
#s-manage .kv{display:flex;justify-content:center;align-items:baseline;gap:8px;
  flex-wrap:wrap;margin-top:9px;padding:10px 12px;border:1px solid var(--line);
  border-radius:var(--r);background:var(--tint)}
#s-manage .kv .k{font-size:12.5px;font-weight:600;color:var(--mute)}
#s-manage .kv b{font-size:13.5px;font-weight:800;color:var(--ink);letter-spacing:-.01em}
#s-manage .kv b.off{color:var(--mute);font-weight:700}
/* Значок в начале строки: он отвечает раньше подписи, и две одинаковые
   плашки подряд перестают читаться как одна. */
#s-manage .kv{align-items:center}
#s-manage .kv .i{display:grid;place-items:center;width:22px;height:22px;flex:0 0 auto;
  border-radius:50%;background:#fff;border:1px solid var(--line);color:var(--brand);
  line-height:0}
#s-manage .kv .i svg{width:14px;height:14px}

/* ── карточка своего тарифа

   Тёмная шапка тем же материалом, что у рекомендованного тарифа на витрине:
   знак тарифа в кружке, название, срок пилюлей справа. Раньше здесь стоял
   белый заголовок по центру и под ним четыре одинаковые серые плашки — по
   такой карточке не читалось, что это твой купленный тариф. */
#s-manage .card.plan{padding:0;overflow:hidden;text-align:left}
#s-manage .mng>.phd{position:relative;display:flex;align-items:center;gap:11px;
  padding:12px 13px;color:#fff;
  background:linear-gradient(135deg,#082B6E 0%,#0B4FD0 55%,#1877FF 100%)}
/* У закончившейся подписки шапка сумеречная — та же логика, что у баннера
   главной: зелёный луг под словом «закончилась» обещает не то. */
#s-manage .mng>.phd.off{background:linear-gradient(135deg,#3E4A63,#232C3D 72%)}
#s-manage .mng>.phd .emb{position:relative;z-index:1;flex:0 0 auto;width:40px;height:40px;
  border-radius:50%;display:grid;place-items:center;color:#F2E3B4;
  background:linear-gradient(180deg,#364D6F,#263852);
  box-shadow:inset 0 0 0 1px rgba(226,203,138,.55),0 2px 6px rgba(0,0,0,.25)}
#s-manage .mng>.phd.off .emb{background:linear-gradient(180deg,#4A5573,#2C3448);
  box-shadow:inset 0 0 0 1px rgba(214,222,240,.4),0 2px 6px rgba(0,0,0,.25)}
#s-manage .mng>.phd .emb svg{width:21px;height:21px}
#s-manage .mng>.phd .nm{position:relative;z-index:1;min-width:0;flex:1}
/* Метка в одну строку: перенос делал шапку одного раздела выше остальных. */
#s-manage .mng>.phd .nm .lbl{display:block;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;font-size:10px;font-weight:800;
  text-transform:uppercase;letter-spacing:.09em;color:#A5BAD7}
#s-manage .mng>.phd.off .nm .lbl{color:#B9C4DC}
#s-manage .mng>.phd .nm b{display:block;margin-top:2px;font-size:18px;font-weight:800;
  letter-spacing:-.015em;color:#fff;line-height:1.2;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Срок пилюлей: число дней держит вес, дата под ним — подпись. */
#s-manage .mng>.phd .till{position:relative;z-index:1;flex:0 0 auto;text-align:right;
  padding:5px 11px;border-radius:var(--r-sm);background:rgba(255,255,255,.13);
  box-shadow:inset 0 0 0 1px rgba(187,205,232,.42)}
#s-manage .mng>.phd.off .till{box-shadow:inset 0 0 0 1px rgba(214,222,240,.35)}
#s-manage .mng>.phd .till b{display:block;font-size:13.5px;font-weight:800;color:#fff;
  white-space:nowrap;line-height:1.15}
#s-manage .mng>.phd .till span{display:block;margin-top:1px;font-size:10.5px;color:#CFE3FF;
  white-space:nowrap}
#s-manage .mng>.phd.off .till span{color:#B9C4DC}

/* Состав — та же плитка со значками, что на витрине. */
#s-manage .card.plan>.spec{display:grid;grid-template-columns:repeat(2,1fr);align-items:center;
  margin:11px 12px 0;padding:9px 2px;background:#E4ECFB;border:1px solid var(--line-2);
  border-radius:var(--r);box-shadow:inset 0 1px 0 rgba(255,255,255,.55)}
#s-manage .card.plan .cl{position:relative;display:flex;align-items:center;justify-content:center;
  gap:8px;text-align:center;padding:0 4px;min-width:0}
#s-manage .card.plan .cl+.cl::before{content:'';position:absolute;left:0;top:50%;
  transform:translateY(-50%);height:30px;width:1px;background:#A8BAD4}
#s-manage .card.plan .cl .ic{flex:0 0 auto;width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;color:var(--brand);background:#fff;
  border:1px solid #BBD5FA;line-height:0}
#s-manage .card.plan .cl .ic svg{width:15px;height:15px}
#s-manage .card.plan .cl .tx{min-width:0;text-align:center}
#s-manage .card.plan .cl b{display:block;font-size:17px;font-weight:800;letter-spacing:-.02em;
  color:var(--brand-deep);line-height:1.1;white-space:nowrap}
#s-manage .card.plan .cl b.inf{font-size:23px;line-height:.81;letter-spacing:0}
#s-manage .card.plan .cl span{display:block;margin-top:2px;font-size:9px;font-weight:700;
  text-transform:uppercase;letter-spacing:.01em;color:var(--mute);line-height:1.15;
  overflow-wrap:anywhere}

/* Карточка без общего паддинга: шапка идёт от края до края, поэтому отступ
   держит каждая строка сама. */
#s-manage .card.plan>.kv{margin:9px 12px 0}
#s-manage .card.plan>.btns{margin:12px 12px 12px}

/* ── раздел трафика

   Та же карточка, что и у тарифа: тёмная шапка от края до края, под ней
   плитка и кнопка. Полоса расхода лежит в самой шапке, её нижним краем:
   порознь число и полоса читались двумя приборами про одно и то же. */
#s-manage .card.traf{padding:0;overflow:hidden;text-align:left}
/* Шапка трафика — колонка: строка с числом, под ней полоса и подпись. */
#s-manage .mng>.phd.tphd,#s-manage .mng>.phd.bphd{display:block}
#s-manage .mng>.phd .rw{position:relative;z-index:1;display:flex;align-items:center;gap:11px}
/* Пакет на исходе — шапка отвечает цветом, как и полоса: зелёный луг под
   словами «осталось 2 ГБ» обещает не то. */
#s-manage .mng>.phd.warm{background:linear-gradient(135deg,#6B5320,#8A6A22 70%)}
#s-manage .mng>.phd.hot{background:linear-gradient(135deg,#6E2C24,#8C3A2C 72%)}
#s-manage .mng>.phd.warm .emb,#s-manage .mng>.phd.hot .emb{
  background:linear-gradient(180deg,#7D6428,#5B4718)}
#s-manage .mng>.phd.hot .emb{background:linear-gradient(180deg,#8A4034,#63271F)}
#s-manage .mng>.phd.warm .nm .lbl,#s-manage .mng>.phd.hot .nm .lbl{color:#EBD9AE}
#s-manage .mng>.phd.hot .nm .lbl{color:#EFCFC5}
#s-manage .mng>.phd.warm .till span{color:#EBD9AE}
#s-manage .mng>.phd.hot .till span{color:#EFCFC5}

/* Полоса на тёмном: своя дорожка и свой заливной цвет — зелёная на зелёном
   не видна вовсе. */
#s-manage .mng>.phd .tbar{position:relative;z-index:1;margin-top:11px;height:7px;
  border-radius:var(--pill);background:rgba(255,255,255,.2);overflow:hidden;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.14)}
/* Полоса набирает свою длину, а не появляется готовой: заполнение за треть
   секунды показывает, что это счётчик, а не нарисованная черта. Ширину
   задаёт разметка, поэтому едет масштаб — и кадры не стоят вёрстки. */
#s-manage .mng>.phd .tbar i{animation:fill var(--dur-3) var(--ease-out) both;
  transform-origin:left center}
@keyframes fill{from{transform:scaleX(0)}to{transform:none}}
#s-manage .mng>.phd .tbar i{display:block;height:100%;border-radius:var(--pill);
  background:linear-gradient(90deg,#A6C2E9,#84A3D0)}
#s-manage .mng>.phd.warm .tbar i{background:linear-gradient(90deg,#F2D89A,#E0B45C)}
#s-manage .mng>.phd.hot .tbar i{background:linear-gradient(90deg,#FBD9CF,#F0A48C)}
#s-manage .mng>.phd .tsub{position:relative;z-index:1;margin-top:6px;font-size:11.5px;
  font-weight:600;color:#CFE3FF}
#s-manage .mng>.phd.warm .tsub{color:#EBD9AE}
#s-manage .mng>.phd.hot .tsub{color:#EFCFC5}

/* Плитка докупки — та же, что состав тарифа. Карточка без общего паддинга,
   поэтому отступ держит каждая строка сама. */
#s-manage .card.traf>.spec{display:grid;grid-template-columns:repeat(2,1fr);
  align-items:center;margin:11px 12px 0;padding:9px 2px;background:#E4ECFB;
  border:1px solid var(--line-2);border-radius:var(--r);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.55)}
#s-manage .card.traf .cl{position:relative;display:flex;align-items:center;
  justify-content:center;gap:8px;text-align:center;padding:0 4px;min-width:0}
#s-manage .card.traf .cl+.cl::before{content:'';position:absolute;left:0;top:50%;
  transform:translateY(-50%);height:30px;width:1px;background:#A8BAD4}
#s-manage .card.traf .cl .ic{flex:0 0 auto;width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;color:var(--brand);background:#fff;
  border:1px solid #BBD5FA;line-height:0}
#s-manage .card.traf .cl .ic svg{width:15px;height:15px}
#s-manage .card.traf .cl .tx{min-width:0;text-align:center}
#s-manage .card.traf .cl b{display:block;font-size:17px;font-weight:800;
  letter-spacing:-.02em;color:var(--brand-deep);line-height:1.1;white-space:nowrap}
#s-manage .card.traf .cl span{display:block;margin-top:2px;font-size:9px;font-weight:700;
  text-transform:uppercase;letter-spacing:.01em;color:var(--mute);line-height:1.15}
#s-manage .card.traf>.note{margin:10px 12px 0;text-align:center}
#s-manage .card.traf>.nrow{margin:11px 12px 0}
#s-manage .card.traf>.btns{margin:11px 12px 12px}
body.h-700 #s-manage .card.traf>.spec{margin-top:10px;padding:8px 2px}
body.h-700 #s-manage .card.traf>.note{margin-top:9px}
body.h-700 #s-manage .card.traf>.nrow{margin-top:9px}
body.h-700 #s-manage .card.traf>.btns{margin:9px 12px 10px}
body.h-640 #s-manage .card.traf>.spec{margin-top:9px;padding:7px 2px}
body.h-640 #s-manage .card.traf>.note{margin-top:8px}
body.h-640 #s-manage .card.traf>.nrow{margin-top:8px}
body.h-640 #s-manage .card.traf>.btns{margin:8px 12px 9px}
body.h-640 #s-manage .card.traf .btn.sm{height:40px}
body.h-640 #s-manage .mng>.phd .tbar{margin-top:9px}
body.h-640 #s-manage .mng>.phd .tsub{margin-top:5px}

/* Низкое поле: карточка тарифа обязана вставать в экран целиком — раздел
   открывают ради неё, и прокручивать её на пару точек человеку незачем.
   Отдаются только отступы: строки, флаги и кнопки остаются как есть. */
body.h-760 .mseg{margin-top:10px}
body.h-760 #s-manage .mng>.phd{padding:10px 13px}
body.h-760 #s-manage .mng>.phd .emb{width:38px;height:38px}
body.h-760 #s-manage .card.plan>.spec{margin-top:9px;padding:8px 2px}
body.h-760 #s-manage .card.plan>.kv{margin-top:8px}
body.h-760 #s-manage .card.plan>.kv{padding:8px 12px}
body.h-760 #s-manage .card.plan>.btns{margin:10px 12px 10px}
body.h-760 #s-manage .card.plan .btn{height:43px}
body.h-700 .mseg{margin-top:9px}
body.h-700 #s-manage .mng>.phd{padding:9px 12px}
body.h-700 #s-manage .mng>.phd .emb{width:36px;height:36px}
body.h-700 #s-manage .mng>.phd .nm b{font-size:17px}
body.h-700 #s-manage .card.plan>.spec{margin-top:8px;padding:7px 2px}
body.h-700 #s-manage .card.plan>.kv{margin-top:7px;padding:7px 12px}
body.h-700 #s-manage .card.plan>.btns{margin:9px 12px 9px}
body.h-700 #s-manage .card.plan .btn{height:41px;font-size:15px}
/* Мини-апп с шапкой Telegram и безопасной зоной снизу: поля остаётся около
   шестисот точек, и карточка упиралась в меню последней кнопкой. */
body.h-640 .mseg{margin-top:8px}
body.h-640 #s-manage .back{min-height:36px}
body.h-640 #s-manage .mng>.phd{padding:8px 12px}
body.h-640 #s-manage .mng>.phd .emb{width:34px;height:34px}
body.h-640 #s-manage .mng>.phd .emb svg{width:19px;height:19px}
body.h-640 #s-manage .card.plan>.spec{margin-top:7px;padding:6px 2px}
body.h-640 #s-manage .card.plan .cl .ic{width:24px;height:24px}
body.h-640 #s-manage .card.plan>.kv{margin-top:6px;padding:6px 12px}
body.h-640 #s-manage .card.plan>.btns{margin:8px 12px 7px;gap:7px}
body.h-640 #s-manage .card.plan .btn{height:39px}
body.h-600 .mseg{margin-top:7px}
body.h-600 .mseg button{height:48px}
body.h-600 #s-manage .mng>.phd .nm b{font-size:16px}
body.h-600 #s-manage .card.plan>.spec{margin-top:6px}
body.h-600 #s-manage .card.plan>.kv{margin-top:5px;padding:5px 12px}
body.h-600 #s-manage .card.plan>.btns{margin:7px 12px 7px;gap:6px}
body.h-600 #s-manage .card.plan .btn{height:38px}

/* ─────────────────────────── документы

   Оферта и политика на экране кабинета. Разметка приезжает от сервера
   (section / h2 с номером / p.cl с номером пункта / ul), здесь только
   одежда: карточки те же, что у остального кабинета, номера разделов —
   плашками в цвет бренда, номера пунктов — на полях серым. */
.doc-seg{grid-template-columns:repeat(2,1fr)}
.doc-seg .pin{width:calc((100% - 8px)/2)}
.doc-wait{margin:22px 4px 12px;color:var(--soft);font-size:14px;font-weight:600;text-align:center}
.doc{padding-bottom:8px}
.doc .stamp{display:inline-block;margin:12px 0 0;padding:5px 12px;border-radius:var(--pill);
  background:var(--brand-soft);color:var(--brand-deep);font-size:12.5px;font-weight:700}
.doc-toc{margin-top:12px;padding:0 14px;background:var(--glass);border:1px solid var(--glass-edge);
  border-radius:var(--r-lg);box-shadow:var(--glass-lift)}
.doc-toc>summary{list-style:none;cursor:pointer;padding:12px 0;font-size:14.5px;font-weight:800;
  color:var(--ink);display:flex;align-items:center;justify-content:space-between}
.doc-toc>summary::-webkit-details-marker{display:none}
.doc-toc>summary::after{content:"";width:8px;height:8px;border-right:2px solid var(--mute);
  border-bottom:2px solid var(--mute);transform:rotate(45deg);margin-right:4px;transition:transform .2s ease}
.doc-toc[open]>summary::after{transform:rotate(-135deg)}
.doc-toc ol{margin:0 0 10px;padding:0;list-style:none;counter-reset:doctoc}
.doc-toc li{counter-increment:doctoc}
.doc-toc li button{display:flex;gap:10px;align-items:baseline;width:100%;padding:8px 2px;border:0;
  background:none;text-align:left;font-family:var(--font);font-size:14px;font-weight:600;
  color:var(--soft);cursor:pointer}
.doc-toc li button::before{content:counter(doctoc);flex:0 0 22px;color:var(--brand-deep);
  font-weight:800;font-variant-numeric:tabular-nums}
.doc-toc li button:active{color:var(--brand-deep)}
.doc section{margin-top:11px;padding:6px 14px 12px;background:var(--glass);
  border:1px solid var(--glass-edge);border-radius:var(--r-lg);box-shadow:var(--glass-lift);
  scroll-margin-top:12px}
@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){
  .doc section,.doc-toc{background:linear-gradient(180deg,#fff,rgba(255,255,255,.92))}
}
.doc h2{display:flex;align-items:center;gap:10px;margin:10px 0 6px;font-size:16.5px;
  font-weight:800;letter-spacing:-.014em;line-height:1.25;color:var(--ink)}
.doc h2 .num{flex:none;min-width:26px;height:26px;padding:0 7px;border-radius:9px;
  display:inline-grid;place-items:center;background:var(--brand-soft);color:var(--brand-deep);
  font-size:13px;font-weight:800;font-variant-numeric:tabular-nums}
.doc p{margin:8px 0;font-size:14.5px;line-height:1.55;color:var(--ink)}
.doc p.cl{position:relative;padding-left:46px}
.doc p.cl .n{position:absolute;left:0;top:.12em;color:var(--mute);font-size:13px;font-weight:800;
  font-variant-numeric:tabular-nums}
.doc p.sub{margin:14px 0 6px;font-weight:800;color:var(--ink)}
.doc section ul{margin:6px 0 8px;padding:0 0 0 2px;list-style:none}
.doc section li{position:relative;margin:5px 0 5px 18px;font-size:14.5px;line-height:1.5;color:var(--ink)}
.doc section li::before{content:"";position:absolute;left:-16px;top:.6em;width:6px;height:6px;
  border-radius:50%;background:var(--brand-glow)}
.doc b{font-weight:800}
.doc code{font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;background:var(--brand-soft);
  padding:1px 6px;border-radius:6px}
