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

@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{
  --grass:#4C8A45; --grass-deep:#2C5A2A; --grass-soft:#EDF2E6; --chartreuse:#86A84E;
  --cta:#357F41; --cta-deep:#2E6E38;
  /* Фон светлее прежнего #E6EBDD: карточки на нём читались как чуть более
     белые пятна, а не как поднятые листы, и зелёная кнопка тонула в общей
     зелени. Линии на полтона темнее — по той же причине. */
  --page:#EAEEE2; --card:#FFFFFF; --tint:#F7F9F1; --line:#DBE1CF; --line-2:#C4CDB2;
  --ink:#1E2719; --soft:#46543E; --mute:#505E49; --line-strong:#7F8F76;
  --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(30,39,25,.05),0 2px 6px rgba(30,39,25,.06),0 12px 28px rgba(30,39,25,.07);
  --sh-lift:0 2px 4px rgba(30,39,25,.07),0 10px 22px rgba(30,39,25,.10),0 24px 48px rgba(30,39,25,.08);
  --sh-2:0 2px 4px rgba(30,66,32,.24),0 8px 18px rgba(30,66,32,.28);
  --edge:inset 0 1px 0 rgba(255,255,255,.9);
  --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: при перетягивании за край экрана
   виден именно он, и без этого из-под страницы проглядывала белая полоса. */
html{background:var(--page)}

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

   Раньше градиент лежал на body с background-attachment:fixed — и уезжал
   вместе с прокруткой: вебвью на iOS это свойство игнорирует, и ниже первого
   экрана страница становилась плоской заливкой. Закреплённый элемент такой
   болезни не имеет и всегда закрывает ровно видимую область. */
html::before{content:'';position:fixed;inset:0;z-index:0;pointer-events:none;
  background:radial-gradient(1000px 420px at 82% -12%,#E4EBE7,transparent 60%),
             linear-gradient(180deg,#E7ECE0,var(--page) 42%)}
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(40,54,34,.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}
.aura i{position:absolute;display:block;border-radius:50%;
  transition:opacity 1.5s ease;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(124,170,102,.38),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(226,196,124,.36),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}

/* ─────────────────────────── травинки в воздухе

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

   Летят ЗА карточками (`z-index:0`), в просветах фона: сверху, по бокам,
   между блоками и в пустоте под последней карточкой. Ради этого их и
   двадцать четыре, а не девять — девять на фоне попросту терялись.

   Сама травинка нарисована двумя скатами от общего стебля, поэтому у неё
   виден залом и она поворачивается «на ребро», а не крутится пятном.

   Каждая — один элемент с одной анимацией: и снос, и поворот, и появление
   лежат в тех же кадрах, поэтому браузер держит один слой на травинку, а
   не три. Задержки отрицательные: без них первые полминуты после запуска
   экран пустой, а потом всё сыплется разом. */
.motes{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;
  contain:layout paint size}
.motes i{position:absolute;top:0;display:block;
  background-repeat:no-repeat;background-size:100% 100%}
/* Четыре вида по кругу: три травинки и семечко. Картинка объявлена один
   раз на вид, а не на каждую штуку, иначе один и тот же рисунок лежал бы в
   файле двадцать четыре раза. */
.motes i:nth-child(4n+1){background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 30'><path d='M7 .5 C3.4 9 2.2 20 5.2 29.5 C6.1 20 6.6 9.5 7 .5Z' fill='%234C8A45'/><path d='M7 .5 C10.6 9 11.8 20 8.8 29.5 C7.9 20 7.4 9.5 7 .5Z' fill='%238FBF6A'/></svg>")}
.motes i:nth-child(4n+2){background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 30'><path d='M7 .5 C3.4 9 2.2 20 5.2 29.5 C6.1 20 6.6 9.5 7 .5Z' fill='%232C5A2A'/><path d='M7 .5 C10.6 9 11.8 20 8.8 29.5 C7.9 20 7.4 9.5 7 .5Z' fill='%236FAE55'/></svg>")}
.motes i:nth-child(4n+3){background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 30'><path d='M7 .5 C3.4 9 2.2 20 5.2 29.5 C6.1 20 6.6 9.5 7 .5Z' fill='%23A8912F'/><path d='M7 .5 C10.6 9 11.8 20 8.8 29.5 C7.9 20 7.4 9.5 7 .5Z' fill='%23D9C489'/></svg>")}
.motes i:nth-child(4n){background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><circle cx='6' cy='6' r='5' fill='%23D6E7BC'/><circle cx='4.4' cy='4.4' r='1.7' fill='%23FFFFFF' opacity='.55'/></svg>")}

.motes i:nth-child(1){left:1.0%;width:11px;height:22px;--o:0.26;animation:mote-a 67.4s linear -62.3s infinite}
.motes i:nth-child(2){left:4.1%;width:15px;height:33px;--o:0.46;animation:mote-c 43.1s linear -25.3s infinite}
.motes i:nth-child(3){left:7.5%;width:20px;height:42px;--o:0.58;animation:mote-b 28.1s linear -17.7s infinite}
.motes i:nth-child(4){left:13.3%;width:6px;height:6px;--o:0.26;animation:mote-a 56.3s linear -17.1s infinite}
.motes i:nth-child(5){left:15.5%;width:17px;height:35px;--o:0.46;animation:mote-c 48.6s linear -33.7s infinite}
.motes i:nth-child(6){left:19.6%;width:20px;height:44px;--o:0.58;animation:mote-b 33.8s linear -32.6s infinite}
.motes i:nth-child(7){left:25.4%;width:9px;height:20px;--o:0.26;animation:mote-a 68.8s linear -10.8s infinite}
.motes i:nth-child(8){left:27.8%;width:9px;height:9px;--o:0.46;animation:mote-c 43.5s linear -2.6s infinite}
.motes i:nth-child(9){left:32.5%;width:21px;height:47px;--o:0.58;animation:mote-b 24.9s linear -0.7s infinite}
.motes i:nth-child(10){left:37.4%;width:9px;height:20px;--o:0.26;animation:mote-a 64.6s linear -54.4s infinite}
.motes i:nth-child(11){left:41.7%;width:15px;height:32px;--o:0.46;animation:mote-c 45.5s linear -22.7s infinite}
.motes i:nth-child(12){left:46.3%;width:13px;height:13px;--o:0.58;animation:mote-b 27.5s linear -7.6s infinite}
.motes i:nth-child(13){left:51.4%;width:11px;height:22px;--o:0.26;animation:mote-a 77.9s linear -65.5s infinite}
.motes i:nth-child(14){left:54.7%;width:15px;height:33px;--o:0.46;animation:mote-c 39.7s linear -9.1s infinite}
.motes i:nth-child(15){left:57.7%;width:20px;height:42px;--o:0.58;animation:mote-b 22.8s linear -17.5s infinite}
.motes i:nth-child(16){left:62.2%;width:6px;height:6px;--o:0.26;animation:mote-a 74.3s linear -28.7s infinite}
.motes i:nth-child(17){left:67.9%;width:17px;height:35px;--o:0.46;animation:mote-c 49.3s linear -0.0s infinite}
.motes i:nth-child(18){left:70.0%;width:20px;height:44px;--o:0.58;animation:mote-b 32.9s linear -15.5s infinite}
.motes i:nth-child(19){left:76.3%;width:9px;height:20px;--o:0.26;animation:mote-a 63.5s linear -4.6s infinite}
.motes i:nth-child(20){left:79.5%;width:9px;height:9px;--o:0.46;animation:mote-c 48.0s linear -12.9s infinite}
.motes i:nth-child(21){left:82.2%;width:21px;height:47px;--o:0.58;animation:mote-b 26.0s linear -25.1s infinite}
.motes i:nth-child(22){left:88.2%;width:9px;height:20px;--o:0.26;animation:mote-a 56.8s linear -14.0s infinite}
.motes i:nth-child(23){left:90.5%;width:15px;height:32px;--o:0.46;animation:mote-c 35.1s linear -28.0s infinite}
.motes i:nth-child(24){left:94.9%;width:13px;height:13px;--o:0.58;animation:mote-b 28.7s linear -12.8s infinite}

/* Три дороги вместо одной: одинаковый снос у всех читается как дождь. */
/* Половина травинок на узком экране: за карточками их всё равно не видно,
   а слоёв компоновщик держит столько же. */
@media (max-width:400px){.motes i:nth-child(2n){display:none}}

@keyframes mote-a{
  0%{transform:translate3d(0,-8vh,0) rotate(0);opacity:0}
  9%{opacity:var(--o,.32)}
  28%{transform:translate3d(16px,22vh,0) rotate(52deg)}
  55%{transform:translate3d(-12px,55vh,0) rotate(128deg)}
  80%{transform:translate3d(14px,82vh,0) rotate(196deg)}
  92%{opacity:var(--o,.32)}
  100%{transform:translate3d(2px,108vh,0) rotate(248deg);opacity:0}}
@keyframes mote-b{
  0%{transform:translate3d(0,-8vh,0) rotate(20deg);opacity:0}
  11%{opacity:var(--o,.32)}
  33%{transform:translate3d(-19px,26vh,0) rotate(-38deg)}
  61%{transform:translate3d(11px,60vh,0) rotate(46deg)}
  86%{transform:translate3d(-9px,88vh,0) rotate(-24deg)}
  93%{opacity:var(--o,.32)}
  100%{transform:translate3d(4px,108vh,0) rotate(30deg);opacity:0}}
@keyframes mote-c{
  0%{transform:translate3d(0,-8vh,0) rotate(0);opacity:0}
  12%{opacity:var(--o,.32)}
  40%{transform:translate3d(9px,34vh,0) rotate(84deg)}
  72%{transform:translate3d(-14px,70vh,0) rotate(168deg)}
  90%{opacity:var(--o,.32)}
  100%{transform:translate3d(6px,108vh,0) rotate(232deg);opacity:0}}

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

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

.app{position:relative;z-index:1;max-width:460px;margin:0 auto;
  padding:calc(env(safe-area-inset-top) + 6px) 16px
          calc(var(--bar-h) + var(--bar-gap) + env(safe-area-inset-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,#57A04C,#2C5A2A);color:#fff;
  display:grid;place-items:center;font-weight:800;font-size:15px;
  box-shadow:0 1px 3px rgba(30,39,25,.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(--grass-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(--grass-deep);background:#fff;border:1px solid var(--line-2);text-decoration:none;
  font-size:13px;font-weight:800;box-shadow:0 1px 3px rgba(38,48,33,.06)}
.top a.sup:active{transform:translateY(1px)}

/* ─────────────────────────── карточки */
.card{position:relative;background:linear-gradient(180deg,#fff,#FCFDF9);
  border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--sh-1),var(--edge);padding:13px 14px 14px;margin-top:11px}
.card.flat{box-shadow:none;background:transparent;border:0;padding:2px 2px 0;margin-top:14px}
.lbl{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.09em;
  color:var(--mute)}

/* Карточка подписки — главный объект экрана, и выглядеть должна тяжелее
   остальных: глубже тень и зелёная грань сверху. */
.card.lead{box-shadow:var(--sh-lift),var(--edge);overflow:hidden}
.card.lead::before{content:'';position:absolute;left:0;right:0;top:0;height:3px;
  background:linear-gradient(90deg,var(--chartreuse),var(--cta) 45%,var(--grass-deep))}
.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(30,58,28,.55);
  box-shadow:0 3px 8px rgba(30,39,25,.16),0 16px 34px rgba(30,39,25,.22);
  isolation:isolate}
.hero{position:relative;margin-top:14px;border-radius:var(--r-lg);overflow:hidden;
  background:linear-gradient(135deg,#57A04C,#2C5A2A 72%);
  border:1px solid rgba(30,58,28,.55);
  box-shadow:0 3px 8px rgba(30,39,25,.16),0 16px 34px rgba(30,39,25,.22);
  color:#fff;min-height:138px;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)}

/* Луг за текстом. Тот же приём, что на странице подписки: снимок во всю
   карточку и градиент поверх — иначе белые буквы теряются в траве. */
/* Цветокор снимка: прежние saturate(1.5) contrast(1.12) делали траву
   кислотной и забивали зелёным весь верх экрана — рядом с ней зелёная
   кнопка переставала быть самым ярким пятном. Теперь насыщенность ближе к
   натуральной, а света чуть больше: снимок остаётся фоном, а не спорит с
   тем, что под ним нажимают. */
.hero .kuz{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:22% 46%;z-index:0;filter:saturate(1.22) contrast(1.05) brightness(1.03)}
/* Градиент кладётся ПОВЕРХ снимка, а не под ним: одинаковый z-index красит
   псевдоэлемент раньше картинки, и белые буквы оказывались на ярком небе. */
.hero::before{content:'';position:absolute;inset:0;z-index:1;
  /* Слева темнее, справа луг проступает: текст читается, а картинка не
   превращается в однотонную заливку. */
/* Темнеет ВПРАВО, к тексту: слева снимок остаётся чистым, и Кузя виден
   целиком. Раньше было наоборот, и градиент закрашивал именно его. */
background:linear-gradient(90deg,rgba(20,46,20,.10) 0%,rgba(20,46,20,.24) 26%,
             rgba(20,46,20,.68) 52%,rgba(20,46,20,.90) 76%,rgba(20,46,20,.95) 100%)}
.hero .k{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.09em;
  opacity:.86;text-shadow:0 1px 2px rgba(16,34,16,.5)}
.hero .v{font-size:28px;font-weight:800;line-height:1.08;margin-top:6px;
  text-shadow:0 2px 6px rgba(16,34,16,.45)}
.hero .m{margin-top:6px;font-size:13px;opacity:.92;text-shadow:0 1px 3px rgba(16,34,16,.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,32,14,.42);border:1px solid rgba(255,255,255,.44);
  font-size:12px;font-weight:800;
  /* Размытия под чипом нет намеренно: `backdrop-filter` держит слой живым
     на всё время показа баннера, а плотности фона хватает и без него. */
  box-shadow:0 2px 8px rgba(14,32,14,.3)}
.chip i{width:6px;height:6px;border-radius:50%;background:#C7F07A;
  box-shadow:0 0 0 3px rgba(199,240,122,.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{min-height:216px}
.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(--grass-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(--grass-deep)}
.card.renew .sub{margin-top:8px}
/* Короткое поле: карточка продления сжимается, чтобы под ней поместились
   все пять сроков и «Сменить тариф» — раньше список уезжал под меню. */
@media (max-height:799px){
  .card.renew{margin-top:10px;padding:10px 13px 11px}
  .card.renew h2{font-size:19px}
  .card.renew .now{margin-top:6px;padding:5px 9px}
  .card.renew .sub{margin-top:6px;font-size:12.5px}
}
@media (max-height:729px){
  .card.renew{margin-top:8px;padding:9px 12px 10px}
  .card.renew h2{font-size:18px}
  .card.renew .now{margin-top:5px;padding:4px 8px}
  .card.renew .now b{font-size:12.5px}
  .card.renew .sub{margin-top:5px;font-size:12px}
}

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

/* Три числа в ряд с разделителями. Строчный список «ключ — значение» на
   главной проигрывает: там всё одинаково важно, а тут видно главное. */
.stats{display:grid;grid-template-columns:repeat(3,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(--card);display:grid;grid-template-columns:1fr 1fr;
  border-top:1px solid rgba(30,58,28,.2)}
.hstats .c{display:flex;align-items:center;gap:9px;padding:10px 13px;position:relative}
.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:30px;height:30px;flex:0 0 auto;
  border-radius:9px;background:var(--grass-soft);color:var(--grass-deep)}
.hstats .c .i svg{width:17px;height:17px}
/* Столбик «подпись — число»: подпись мелкая и приглушённая, число крупное.
   min-width:0 — чтобы длинное значение сжималось, а не распирало колонку. */
.hstats .c .b{min-width:0}
.hstats .c .k{display:block;font-size:10.5px;font-weight:700;color:var(--mute);
  text-transform:uppercase;letter-spacing:.05em;line-height:1}
.hstats .c b{display:block;font-size:16px;font-weight:800;letter-spacing:-.02em;
  line-height:1.15;margin-top:3px;white-space:nowrap}
.hstats .c b.low{color:var(--warn)}
.hstats .c b.out{color:var(--bad)}
/* Расход — швом между снимком и числами, во всю ширину и без скруглений:
   полоса принадлежит блоку, а не висит в нём отдельной деталью. */
.hmeter{grid-column:1/-1;height:4px;background:var(--grass-soft)}
.hmeter i{display:block;height:100%;
  background:linear-gradient(90deg,#6FAE55,#3E8E49);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(--grass)}
.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}


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

/* Ссылка подписки. Тёмная вдавленная панель: это не текст и не кнопка, а
   то, что уносят в другое приложение, и выглядеть должна как поле с данными. */
.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,#F1F4EA,#E9EDDF);
  box-shadow:inset 0 2px 5px rgba(30,39,25,.10)}
.link .txt{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;
  padding:8px 11px;color:var(--grass-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(--grass-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,#F4F7EC);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(--grass-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,#3E8E49,#2E6E38);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(76,138,69,.22),transparent);
  animation:flash .7s ease-out}
@keyframes flash{from{transform:translateX(-100%)}to{transform:translateX(100%)}}

/* Кнопка «Скопировать ссылку» в профиле отвечает тем же зелёным. */
.btn.ghost.done{background:linear-gradient(180deg,#EAF3DF,#DCE7CC);
  border-color:var(--cta);color:var(--grass-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,#E9F0DE,#DCE7CC);color:var(--grass-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:linear-gradient(180deg,#fff,#F6F9F0);
  border:1px solid var(--line);
  box-shadow:var(--sh-lift),var(--edge)}
/* Узор проступает только справа: под аватаркой и именем он мешал бы читать. */
.me::before{content:'';position:absolute;inset:0;z-index:0;pointer-events:none;opacity:.1;
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'><g fill='none' stroke='%234A7040' stroke-width='1.5' stroke-linecap='round'><path d='M14 78 C15 66 13 58 8 50'/><path d='M14 78 C17 68 21 63 27 59'/><path d='M14 78 C12 70 9 66 5 63'/><path d='M62 40 C63 30 61 24 57 18'/><path d='M62 40 C65 32 69 28 74 25'/><path d='M88 88 C89 80 87 75 83 71'/><path d='M38 20 C39 13 37 9 34 6'/></g><g fill='%234A7040'><circle cx='76' cy='58' r='1.5'/><circle cx='30' cy='40' r='1.3'/><circle cx='52' cy='86' r='1.2'/></g></svg>");background-size:96px 96px;
  -webkit-mask-image:linear-gradient(90deg,transparent 34%,#000);
  mask-image:linear-gradient(90deg,transparent 34%,#000)}
.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,#4C8A45,var(--grass-deep));
  box-shadow:0 2px 6px rgba(30,66,32,.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(--grass-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(30,39,25,.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(--grass-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(--grass-soft);color:var(--grass-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(--grass-soft);transform:translateY(1px)}
.me .cid.done{background:#EAF3DF;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(--grass-soft);border-color:var(--line-2);color:var(--grass-deep);
  backdrop-filter:none;box-shadow:none}
.me .chip.off i{background:var(--warn)}
/* Без подписки визитка остаётся светлой — она была тёмно-синей плитой и
   выбивалась из кабинета сильнее всего именно у новичка, который видит её
   первой. Отсутствие доступа показывает не цвет карточки, а её чип и
   приглушённая кайма: цветом кричать не о чем, человек просто ещё не начал. */
.me.dusk{background:linear-gradient(180deg,#fff,#F4F6EF);border-color:var(--line-2)}
.me.dusk .ava{background:linear-gradient(180deg,#8C9A83,#6E7C66);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(--grass)}

/* Флаги стран. Крупно и в один ряд: это единственная строка экрана, которую
   читают картинкой, а не текстом. */
.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,#FCFDF9);
  box-shadow:0 1px 2px rgba(30,39,25,.06),0 6px 16px rgba(30,39,25,.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(--grass-soft);color:var(--grass-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(30,39,25,.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;
  /* Верхний стоп темнее прежнего #3E8E49 ровно настолько, чтобы белая
     подпись прошла 4.5:1: на глаз кнопка та же, читается — лучше. */
  background:linear-gradient(180deg,#3A8544,var(--cta-deep) 62%,#2A6634);color:#fff;
  box-shadow:var(--sh-2),inset 0 1px 0 rgba(255,255,255,.28),
             inset 0 -1px 0 rgba(0,0,0,.16);
  transition:transform .1s ease,box-shadow .16s ease,filter .16s ease}
/* Нажатие вдавливает, а не сдвигает: сдвиг на пиксель на телефоне не читается. */
.btn:active{transform:translateY(1px);filter:brightness(.96);
  box-shadow:0 1px 3px rgba(30,66,32,.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(76,138,69,.16),transparent)}
/* Ответ «сделано» на той же кнопке, куда человек смотрит. */
.btn.ok{pointer-events:none;background:linear-gradient(180deg,#EAF3DF,#DCE7CC);
  border:1px solid var(--cta);color:var(--grass-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:#fff;color:var(--grass-deep);
  border:1.5px solid rgba(53,127,65,.42);
  box-shadow:0 1px 2px rgba(30,39,25,.05)}
.btn.ghost:active{filter:none;background:var(--grass-soft);
  box-shadow:inset 0 2px 6px rgba(30,39,25,.12)}
/* Главная кнопка экрана. Выше обычной, со значком слева и с зелёным
   отсветом под ней: рядом со второй кнопкой того же роста, отличавшейся
   только заливкой, человек выбирал между двумя равными, вместо того чтобы
   нажать очевидное. Разницу держат три вещи сразу — рост, значок и тень. */
.btn.lead{height:54px;font-size:17px;gap:10px;
  box-shadow:0 2px 4px rgba(30,66,32,.28),0 12px 24px rgba(45,110,55,.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(30,66,32,.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(--grass-soft);color:var(--grass-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}

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

   Карточка человека без подписки — единственное, что он читает целиком, и
   набрана она крупнее остальных: здесь не сводка по своему тарифу, где
   мелкий кегль экономит место, а объяснение, ради которого экран и открыт. */
/* Зелёной грани сверху у этой карточки нет: под баннером она читалась как
   обрезок его же рамки. */
.card.lead.start::before{display:none}
.card.lead.start{padding:13px 15px 14px}
.card.lead.start .lbl{font-size:10.5px;letter-spacing:.1em;color:var(--soft)}
.card.lead.start h2{margin-top:3px;font-size:17.5px;letter-spacing:-.016em}
.card.lead.start p.sub{margin-top:6px;font-size:12.5px;line-height:1.5}
/* Срок и объём — единственные числа экрана: тёмным и жирным, чтобы их
   находили, не читая строку целиком. */
.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}

/* Две кнопки первого шага — одного роста и одной формы, как на макете
   владельца: разницу между ними держат заливка и порядок, а не рост со
   значком. Значка на них нет вовсе — подпись и так называет действие
   целиком, а тележка на бесплатном пробном ещё и обещала оплату. */
.btn.big{height:51px;border-radius:14px;font-size:16.5px;letter-spacing:-.012em;
  background:linear-gradient(180deg,#3E8A48,var(--cta-deep) 60%,#27632F);
  box-shadow:0 2px 5px rgba(30,66,32,.26),0 10px 22px rgba(45,110,55,.28),
             inset 0 1px 0 rgba(255,255,255,.30),inset 0 -1px 0 rgba(0,0,0,.16)}
.btn.big.ghost{height:51px;font-size:16.5px;background:#fff;
  box-shadow:0 1px 2px rgba(30,39,25,.05)}

/* ─────────────────────────── полосы */
.meter{margin-top:6px;height:8px;border-radius:var(--pill);background:var(--grass-soft);overflow:hidden}
.meter i{display:block;height:100%;border-radius:var(--pill);
  background:linear-gradient(90deg,#6FAE55,#3E8E49);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:linear-gradient(180deg,#E4E9DA,#DDE3D1);
  border:1px solid var(--line-2);
  box-shadow:inset 0 2px 5px rgba(30,39,25,.10)}
.seg .pin{position:absolute;top:4px;bottom:4px;left:4px;width:calc((100% - 8px)/3);
  border-radius:var(--pill);background:linear-gradient(180deg,#fff,#F5F8EE);
  box-shadow:0 1px 2px rgba(30,39,25,.10),0 4px 10px rgba(30,39,25,.10),
             inset 0 1px 0 rgba(255,255,255,.9);
  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(--grass-deep)}

/* Строка тарифа. Свёрнутая — это одна строка: название, короткая суть и цена
   «от». Развёрнутая добавляет сроки и кнопку. */
.tar{position:relative;background:linear-gradient(180deg,#fff,#FBFDF7);
  border:1px solid var(--line);border-radius:var(--r-lg);margin-top:10px;
  box-shadow:var(--sh-1),var(--edge);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,#FBFEF6,#F2F8E9);
  box-shadow:0 2px 5px rgba(30,66,32,.10),0 12px 26px rgba(30,66,32,.13),var(--edge)}
.tar.pick.mine{border-color:var(--line-2);background:linear-gradient(180deg,#fff,#F7F9F1)}
/* Лента поверх верхней грани: она объявляет карточку до того, как её
   начнут читать, и не отнимает место у названия. */
.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,#3A8544,var(--cta-deep));
  padding:4px 10px 5px;border-radius:0 0 var(--r-sm) var(--r-sm);
  box-shadow:0 2px 6px rgba(30,66,32,.28)}
.tar .flag.own{background:linear-gradient(180deg,#8C9A83,#6E7C66)}
.tar.pick.hot,.tar.pick.mine{padding-top:20px}
.tar.pick:active{transform:translateY(1px);box-shadow:inset 0 2px 8px rgba(30,39,25,.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,#3A8544,var(--cta-deep));padding:2px 6px 3px;
  border-radius:var(--pill);box-shadow:0 1px 3px rgba(30,66,32,.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(--grass-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(--grass-soft);color:var(--grass-deep);
  transition:transform .26s cubic-bezier(.22,1,.36,1),background .2s ease}
.tar.pick.hot .hd .ch{background:linear-gradient(180deg,#3A8544,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(--grass)}

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

   Прошлый заход прятал на низком поле строку отличия, полку и иконки, и от
   карточки оставались название с ценой на полторы сотни пикселей. Теперь
   ничего не исчезает: на коротком экране ступенями (`max-height` ниже)
   мельчает кегль и сжимаются отступы. */
/* Высота берётся из переменной, которую ставит скрипт по данным Telegram;
   `100svh` остаётся запасным значением для обычного браузера. */
body[data-tab="shop"] .app{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}
#shop-body.fill{flex:1;display:flex;flex-direction:column;min-height:0;
  justify-content:space-between;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}

/* Карточка по макету: знак тарифа в кружке слева, название со строкой
   отличия, цена справа, состав — отдельной светлой плиткой внизу.
   Рекомендованный тариф идёт тёмной шапкой в золотой грани: он должен
   отличаться от соседей материалом, а не одной лентой. */
.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(--grass-deep);
  background:linear-gradient(180deg,#EEF4E4,#DCE7CC);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 1px 2px rgba(30,39,25,.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:#E7EDDA;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(--grass);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-СЕРВЕР…». Кегль мельче,
   разрядка почти снята, перенос разрешён. */
.tar .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}

/* ── рекомендованный тариф: тёмная шапка в золотой грани */
.tar.pick.grow.hot{border-color:#C9B072;background:#fff;
  box-shadow:0 2px 5px rgba(30,66,32,.12),0 14px 30px rgba(30,66,32,.16),
    inset 0 0 0 1px rgba(212,183,116,.5)}
.tar.grow.hot .sec.lead{position:relative;
  background:linear-gradient(135deg,#1F3D1E 0%,#2C5A2A 55%,#376B31 100%);
  border-radius:calc(var(--r-lg) - 1px) calc(var(--r-lg) - 1px) 0 0;
  padding:12px 13px 11px}
/* Тот же травяной узор, что на фоне страницы, но здесь он лежит в правом
   углу и почти не виден: шапка должна читаться как материал, а не как
   заливка. Узор под текстом рябит, поэтому он справа и слабый. */
.tar.grow.hot .sec.lead::after{content:'';position:absolute;inset:0;pointer-events:none;
  border-radius:inherit;opacity:.22;
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'><g fill='none' stroke='%23A9CE86' stroke-width='1.5' stroke-linecap='round'><path d='M14 78 C15 66 13 58 8 50'/><path d='M14 78 C17 68 21 63 27 59'/><path d='M62 40 C63 30 61 24 57 18'/><path d='M62 40 C65 32 69 28 74 25'/><path d='M88 88 C89 80 87 75 83 71'/></g><g fill='%23A9CE86'><circle cx='76' cy='58' r='1.5'/><circle cx='30' cy='40' r='1.3'/></g></svg>");
  background-size:96px 96px;
  -webkit-mask-image:linear-gradient(100deg,transparent 45%,#000 100%);
  mask-image:linear-gradient(100deg,transparent 45%,#000 100%)}
.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:#D6E7BC}
.tar.grow.hot .hd .pr b{color:#fff}
.tar.grow.hot .hd .pr b i{color:#BFD6A6}
.tar.grow.hot .hd .pr u{color:#C7DCAE}
.tar.grow.hot .emb{color:#F2E3B4;background:linear-gradient(180deg,#3E6E37,#2A5127);
  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:#DFEACD;border-color:#C6D9AC}
.tar.grow.hot .cl+.cl::before{background:#C2D3A9}
.tar.grow.hot .cl b{color:var(--grass-deep)}
.tar.grow.hot .cl .ic{border-color:#D8E7C4}
/* Метка на тёмной шапке: своя, светлая — зелёная пилюля на зелёном фоне
   не читалась. */
.tar.grow.hot .hd .nm b .mark{background:rgba(255,255,255,.14);color:#EAF4DC;
  box-shadow:inset 0 0 0 1px rgba(214,231,188,.55)}

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

/* Ступени по высоте поля: три карточки должны встать в экран целиком, и
   ради этого сжимаются отступы и кегль. Порядок жертв — от того, что
   ничего не сообщает, к тому, что сообщает меньше всех: сначала иконка в
   ячейке, потом кегль, и только на совсем коротком поле — строка отличия. */
@media (max-height:759px){
  .tar.grow .sec{padding:8px 14px 7px}
  .tar.grow .spec{margin:0 10px 8px}
  .tar.grow .hd .nm b{font-size:18.5px}
  .tar.grow .hd .pr b{font-size:24px}
  .tar.grow .why{margin-top:4px;font-size:12.5px}
  .tar.grow .spec{padding:6px 4px}
  .tar .emb{width:36px;height:36px}
  .tar .cl .ic svg{width:17px;height:17px}
  .tar .cl b{font-size:17px}
}
@media (max-height:679px){
  .tar.pick.grow{min-height:112px}
  .tar .emb{width:36px;height:36px}
  .tar.grow .hd .pr{margin-top:2px}
  .tar.grow .sec{padding:8px 13px 7px}
  .tar.grow .spec{margin:0 9px 7px;padding:6px 2px}
  .tar.grow .hd .nm b{font-size:18px}
  .tar.grow .hd .pr b{font-size:23px}
  .tar.grow .hd .ch{width:26px;height:26px}
  .tar.grow .why{font-size:12px;margin-top:4px}
  .tar.grow .spec{padding:6px 4px}
  /* Кружок значка меньше, но остаётся: он стоит слева от текста, а не над
     ним, и высоты карточки не прибавляет. */
  .tar .cl .ic{width:26px;height:26px}
  .tar .cl .ic svg{width:15px;height:15px}
  .tar .cl{gap:7px;padding:0 4px}
  .tar.grow.hot .spec{margin-top:6px}
  .tar .cl b{font-size:16px}
}
/* Ниже 620 строка отличия уходит: без неё карточка теряет объяснение, с
   ней — не помещается, а обрезанная карточка хуже. */
@media (max-height:699px){
  .tar.grow .why{display:none}
  .tar.grow.hot .spec{margin-top:4px}
  .tar .emb{width:34px;height:34px}
  .tar .emb svg{width:18px;height:18px}
  .tar.grow .hd .pr{margin-top:1px}
}
/* Совсем короткое поле — сплит-экран, клавиатура поверх мини-аппа. */
@media (max-height:589px){
  .tar.pick.grow{min-height:96px}
  .tar.grow .sec{padding:6px 12px 5px}
  .tar.grow .spec{margin:0 8px 8px;padding:5px 2px}
  .tar.grow.hot .spec{margin-top:3px}
  .tar.grow .spec{padding:4px 2px}
  .tar .cl .ic{width:22px;height:22px}
  .tar .cl .ic svg{width:13px;height:13px}
  .tar .emb{width:30px;height:30px}
  .tar .emb svg{width:16px;height:16px}
  .tar .cl b{font-size:15px}
  .tar.pick.grow{min-height:100px}
  .tar.grow .sec{padding:8px 13px}
  .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}
  .tar .cl span{font-size:8px;letter-spacing:0}
  .tar .cl b{font-size:16px}
  .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 .cl b{font-size:14.5px}
  .tar .cl span{font-size:9.5px;letter-spacing:.02em}
  .tar.grow .sec{padding:10px 12px 9px}
}

@media (max-width:369px){
  .tar .cl{gap:4px;padding:0 1px}
  .tar .cl .ic{width:21px;height:21px}
  .tar .cl span{font-size:7.5px}
  .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,#1F3D1E 0%,#2C5A2A 58%,#376B31 100%);
  box-shadow:0 2px 6px rgba(30,66,32,.16),0 16px 34px rgba(30,66,32,.18)}
.card.stop::before{content:'';position:absolute;inset:0;pointer-events:none;opacity:.2;
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'><g fill='none' stroke='%23A9CE86' stroke-width='1.5' stroke-linecap='round'><path d='M14 78 C15 66 13 58 8 50'/><path d='M14 78 C17 68 21 63 27 59'/><path d='M62 40 C63 30 61 24 57 18'/><path d='M62 40 C65 32 69 28 74 25'/><path d='M88 88 C89 80 87 75 83 71'/></g><g fill='%23A9CE86'><circle cx='76' cy='58' r='1.5'/><circle cx='30' cy='40' r='1.3'/></g></svg>");
  background-size:96px 96px;
  -webkit-mask-image:linear-gradient(120deg,transparent 40%,#000 100%);
  mask-image:linear-gradient(120deg,transparent 40%,#000 100%)}
/* Крупный знак справа — то же, что на кнопке раздела: он говорит, о чём
   карточка, раньше заголовка. Под текст не лезет: у него своя половина. */
.card.stop .art{position:absolute;right:16px;top:46px;width:86px;height:86px;
  color:#9FCA7C;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:#B7D39A}
.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:#D9E7C8}
.card.stop .btn{margin-top:14px}
/* Белая кнопка на тёмном: зелёная на зелёном не читается как действие. */
.btn.light{background:#fff;color:var(--grass-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(--grass-deep);background:var(--grass-soft);
  box-shadow:inset 0 0 0 1px #DCE7CC}
.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(--grass-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(--grass);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,#1F3D1E 0%,#2C5A2A 58%,#376B31 100%);
  box-shadow:0 2px 6px rgba(30,66,32,.16),0 14px 30px rgba(30,66,32,.18)}
.card.bill::before{content:'';position:absolute;inset:0;pointer-events:none;opacity:.2;
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'><g fill='none' stroke='%23A9CE86' stroke-width='1.5' stroke-linecap='round'><path d='M14 78 C15 66 13 58 8 50'/><path d='M14 78 C17 68 21 63 27 59'/><path d='M62 40 C63 30 61 24 57 18'/><path d='M62 40 C65 32 69 28 74 25'/><path d='M88 88 C89 80 87 75 83 71'/></g><g fill='%23A9CE86'><circle cx='76' cy='58' r='1.5'/><circle cx='30' cy='40' r='1.3'/></g></svg>");
  background-size:96px 96px;
  -webkit-mask-image:linear-gradient(120deg,transparent 42%,#000 100%);
  mask-image:linear-gradient(120deg,transparent 42%,#000 100%)}
.card.bill .lbl{position:relative;z-index:1;color:#B7D39A}
.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:#C7DCAE}
.card.bill .was s{font-weight:700;text-decoration-thickness:1px}

.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:linear-gradient(180deg,#fff,#FBFDF7);border:1px solid var(--line);
  box-shadow:var(--sh-1),var(--edge);font-family:var(--font);
  animation:rise .3s cubic-bezier(.22,1,.36,1) both}
.way .ic{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;
  color:var(--grass-deep);background:linear-gradient(180deg,#EEF4E4,#DCE7CC);
  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,#F2F8EA);
  box-shadow:0 0 0 2px rgba(53,127,65,.16),var(--sh-1),var(--edge)}
.way.on .ic{color:#fff;background:linear-gradient(180deg,var(--grass),var(--grass-deep))}
.way.hit:active{transform:translateY(1px);box-shadow:inset 0 2px 8px rgba(30,39,25,.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(--grass);box-shadow:0 0 0 2px rgba(76,138,69,.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(--grass-soft);color:var(--grass-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(--grass)}

/* Ровно три в ряд. Пять сроков при автоподборе вставали как 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:#fff;box-shadow:0 0 0 2px rgba(53,127,65,.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,#FAFCF6,#F2F6EA)}
.swap .box.next{border-color:var(--cta);
  background:linear-gradient(180deg,#EAF3DF,#DFEBD0);
  box-shadow:0 0 0 2px rgba(53,127,65,.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(--grass-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,#F4F7EC);color:var(--grass-deep);
  font-family:var(--font);font-size:26px;font-weight:800;line-height:1;cursor:pointer;
  box-shadow:0 1px 2px rgba(30,39,25,.08),var(--edge)}
.step button:active{background:var(--grass-soft);box-shadow:inset 0 2px 6px rgba(30,39,25,.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 ₽» на карточке тарифа. */
@media (max-height:699px){
  .sale{padding:8px 12px;gap:9px;align-items:baseline}
  .sale>b{font-size:17px}
  .sale .k{display:none}
  .sale .w{margin-top:0;font-size:12px;font-weight:700;color:#F6EBD0}
}
@media (max-height:649px){ .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(--line);border-radius:var(--r);
  background:linear-gradient(180deg,#fff,#FBFDF7);box-shadow:var(--sh-1),var(--edge);
  font-family:var(--font);text-align:left;cursor:pointer;
  animation:rise .3s cubic-bezier(.22,1,.36,1) both;
  transition:transform .12s ease,box-shadow .16s ease}
.opt:active{transform:translateY(1px);box-shadow:inset 0 2px 8px rgba(30,39,25,.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(--grass-deep);background:var(--grass-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(--grass-soft);color:var(--grass-deep);
  transition:transform .2s cubic-bezier(.22,1,.36,1)}
.opt:active .ch{transform:translateX(2px)}
/* Ступени по высоте и здесь: список сроков — пять строк плюс шапка, и на
   коротком поле он уезжал под нижнее меню. Уменьшается кегль и отступы,
   строки не пропадают. */
@media (max-height:799px){
  .opt{margin-top:7px;padding:11px 14px}
  .opt .nm b{font-size:16px}
  .opt .nm span{font-size:12px}
  .opt .pr b{font-size:19px}
  .opt .ch{width:28px;height:28px}
  .opt.best{padding-top:17px}
}
@media (max-height:729px){
  .opt{margin-top:6px;padding:9px 13px}
  .opt .nm b{font-size:15px}
  .opt .nm span{font-size:11.5px}
  .opt .pr b{font-size:18px}
  .opt .pr i{font-size:10px;margin-top:2px}
  .opt .ch{width:26px;height:26px}
  .opt.best{padding-top:15px}
}

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

/* Самый выгодный срок. Выделен так же, как рекомендованный тариф на
   предыдущем экране: зелёная грань, тёплая подложка, лента поверх. */
.opt.best{border-color:var(--cta);padding-top:19px;
  background:linear-gradient(180deg,#FBFEF6,#F2F8E9);
  box-shadow:0 2px 5px rgba(30,66,32,.10),0 10px 22px rgba(30,66,32,.12),var(--edge)}
.opt.best .ch{background:linear-gradient(180deg,#3A8544,var(--cta-deep));color:#fff}
.opt.best .pr b{color:var(--cta-deep)}
.opt.best .pr i{background:linear-gradient(180deg,#3A8544,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,#3A8544,var(--cta-deep));
  padding:3px 9px 4px;border-radius:0 0 var(--r-sm) var(--r-sm);
  box-shadow:0 2px 6px rgba(30,66,32,.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(--line-2);background:linear-gradient(180deg,#fff,#F5F8EE);
  color:var(--grass-deep);display:grid;place-items:center;
  box-shadow:0 1px 2px rgba(30,39,25,.08),var(--edge)}
.back .ico:active{background:var(--grass-soft);box-shadow:inset 0 2px 6px rgba(30,39,25,.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(76,138,69,.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%)}}

/* ─────────────────────────── сетка мелких товаров */
.tiles{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px}
.tile{border:1px solid var(--line);background:var(--card);border-radius:var(--r);padding:12px;
  text-align:left;cursor:pointer;box-shadow:var(--sh-1);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:active{transform:translateY(1px)}

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

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

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

/* На широком экране кабинет отводит место левой панели и прижимает колонку к
   ней. У витрины панели нет, и то же правило уводило страницу вправо от
   центра — здесь колонка просто стоит посередине. */
@media (min-width: 960px) {
  body.buy-page .app{margin:0 auto;max-width:720px;padding:26px 40px 56px}
  body.buy-page .grass{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(--grass-deep);background:var(--grass-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(--grass-deep);
  background:var(--grass-soft);border-radius:var(--pill);padding:2px 7px}

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

   Размытия под панелью больше нет: `backdrop-filter` пересчитывает всё,
   что под ним, на каждый кадр прокрутки — это был самый дорогой элемент
   кабинета. Плотный фон стоит ноль и выглядит так же. */
.bar{position:fixed;left:0;right:0;z-index:5;background:none;border-top:0;
  bottom:calc(env(safe-area-inset-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) + env(safe-area-inset-bottom) + 24px);
  background:linear-gradient(180deg,rgba(198,214,180,0),rgba(160,190,140,.34) 46%,
    rgba(126,163,105,.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;background:rgba(255,255,255,.96);
  border:1px solid var(--line);
  box-shadow:0 1px 2px rgba(30,39,25,.06),0 10px 26px rgba(30,39,25,.14)}
/* Полоска активной вкладки. Едет сдвигом — это композиция, без перерисовки
   и без пересчёта раскладки, поэтому кадры не проседают даже на слабом
   телефоне. Кривая и длительность те же, что у переключателя разделов
   магазина: две бегающие полоски в одном интерфейсе обязаны вести себя
   одинаково. */
/* Активная вкладка — светлая капсула во всю высоту полосы, с зелёной
   чертой на верхней грани. Одна полоска сверху говорила, где ты, слишком
   тихо: на светлом фоне она читалась как декоративная линия. */
/* Пока капсулу тянут, она чуть крупнее: жест видно и на глаз, а не только
   по тому, что экран сменился. */
.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:var(--grass-soft);transition:transform .18s ease;
  box-shadow:inset 0 0 0 1px #DDE7CD,0 1px 2px rgba(30,39,25,.05)}
/* Черта лежит на верхней грани капсулы и чуть выходит за неё: так видно,
   что это метка положения, а не рамка кнопки. */
.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(46,110,56,.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;
  margin:8px 5px;border:1.5px solid var(--cta);border-radius:18px;
  background:linear-gradient(180deg,#E8F1DF,#D9E8CB)}
/* Активная — та же кнопка, но темнее: светлая капсула вкладки под ней не
   видна, и без своего отличия «Купить» выглядела бы одинаково открытой и
   закрытой. */
.bar button[data-tab="shop"].on{border-color:var(--cta-deep);
  background:linear-gradient(180deg,#D3E5C3,#C2D9AE)}

/* «Управление» — самое длинное слово в баре: на узком телефоне подпись
   вылезала за края капсулы активной вкладки. Кегль меньше соседних. */
.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(--grass-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` ставит скрипт после первой отрисовки, дальше переключение
   вкладок анимируется как прежде. */
body.ready .screen.on{animation:in .3s cubic-bezier(.22,1,.36,1) both}
@keyframes in{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}

/* Карточки въезжают по очереди. Задержку каждой проставляет скрипт — в CSS
   пришлось бы плодить :nth-child под неизвестное число тарифов. */
.tar{animation:rise .34s cubic-bezier(.22,1,.36,1) both}
@keyframes rise{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}

/* Плитки товаров — тем же движением, но короче: их много, и длинная
   очередь превращается в ожидание. */
.tiles .tile{animation:rise .3s cubic-bezier(.22,1,.36,1) both}
.tiles .tile:nth-child(2n){animation-delay:.04s}
.tiles .tile:nth-child(n+3){animation-delay:.08s}
.tiles .tile:nth-child(n+5){animation-delay:.12s}
.tiles .tile:nth-child(n+7){animation-delay:.16s}

@media (prefers-reduced-motion: reduce){
  .screen.on,.tar,.tiles .tile{animation:none}
  /* Свет остаётся, движение — нет. Слои под него держать тоже незачем. */
  .aura i{animation:none;will-change:auto}
  /* Летящее убираем целиком: остановленная в воздухе травинка — это мусор
     на экране, а не украшение. */
  .motes{display:none}
  /* Без бегущего света `.wait` оставалась зелёной плашкой без подписи:
     движение убираем, но тогда возвращаем текст и статичную подсветку. */
  .btn.wait{color:#fff}
  .btn.ghost.wait{color:var(--grass-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}
}

.skel{border-radius:var(--r);background:linear-gradient(90deg,#EAEEE2,#F4F6EF,#EAEEE2);
  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:linear-gradient(180deg,#fff,#FBFCF7);border:1px solid var(--line);
  border-radius:var(--r-lg);box-shadow:var(--sh-1),var(--edge);
  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(30,39,25,.10)}
.tip .ic{flex:0 0 auto;width:36px;height:36px;border-radius:11px;display:grid;place-items:center;
  background:linear-gradient(180deg,#E9F0DE,#DCE7CC);color:var(--grass-deep);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.8),0 1px 2px rgba(30,39,25,.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}
/* Короткое поле: строка-подсказка сжимается — на экране продления она
   стоит последней, и из-за неё список сроков уезжал под нижнее меню. */
@media (max-height:799px){
  .tip{margin-top:7px;padding:8px 13px;gap:10px}
  .tip .ic{width:32px;height:32px;border-radius:10px}
  .tip b{font-size:14.5px}
  .tip span{font-size:12px}
}
@media (max-height:729px){
  .tip{margin-top:6px;padding:7px 12px}
  .tip .ic{width:30px;height:30px}
  .tip b{font-size:14px}
  .tip span{font-size:11.5px}
}
.tip .go{margin-left:auto;color:var(--line-strong)}

.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) + env(safe-area-inset-bottom) + 16px);
  transform:translate(-50%,20px);z-index:40;opacity:0;pointer-events:none;
  background:rgba(38,48,33,.94);color:#fff;font-size:14px;font-weight:700;
  padding:11px 18px;border-radius:var(--pill);box-shadow:0 8px 24px rgba(38,48,33,.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 + env(safe-area-inset-bottom))}
/* Та же история, что у переключателя разделов выше: авторское display:flex
   сильнее браузерного правила для [hidden], и без этой строки окно входа
   оставалось висеть поверх кабинета — уже после того, как человек вошёл. */
.gate[hidden]{display:none}
.gate-card{width:100%;max-width:404px;background:var(--card);border-radius:var(--r-lg);
  padding:26px 24px 22px;text-align:center;box-shadow:var(--sh-lift),var(--edge);
  border:1px solid var(--line);
  animation:gate-in .42s cubic-bezier(.22,1,.36,1) both}
@keyframes gate-in{from{opacity:0;transform:translateY(14px) scale(.985)}}

/* Кузя в кружке с зелёной каймой и галочкой — тот же снимок, что на главной
   баннером, поэтому после входа экран не подменяется незнакомой картинкой.
   Кадр смещён влево: сам Кузя стоит в левой четверти снимка, и кружок по
   центру показывал бы пустой луг. */
.gate-kuz{position:relative;width:112px;height:112px;margin:0 auto 14px}
.gate-kuz img{width:100%;height:100%;object-fit:cover;object-position:24% 42%;border-radius:50%;
  background:var(--grass-soft);box-shadow:0 0 0 4px #fff,0 0 0 6px var(--grass-soft),
  0 10px 22px rgba(30,39,25,.14)}
.gate-badge{position:absolute;right:2px;bottom:2px;width:32px;height:32px;border-radius:50%;
  display:grid;place-items:center;background:linear-gradient(180deg,#54A04C,var(--cta-deep));
  box-shadow:0 0 0 3px #fff,0 4px 10px rgba(30,66,32,.32)}
.gate-badge svg{width:17px;height:17px}

.gate h1{font-size:25px;font-weight:800;color:var(--grass-deep);margin:0 0 6px;
  letter-spacing:-.02em}
.gate-lead{color:var(--soft);margin:0 0 20px;font-size:14.5px;line-height:1.5}

/* Наша кнопка и настоящий виджет — один стек. Виджет прозрачный и растянут
   чуть шире кнопки: его iframe меньше, а кликать человек будет по краям
   тоже. Без растяжения углы кнопки просто не отвечают. */
.tgwrap{position:relative;isolation:isolate}
.tgbtn{display:flex;align-items:center;justify-content:center;gap:9px;width:100%;height:52px;
  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,#31B0EE,#229ED9 62%,#1C8FC7);
  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);
  transition:transform .1s ease,box-shadow .16s ease,filter .16s ease}
.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){
  .gate-card{animation:none}
  .tgspin{animation-duration:2.4s}
}

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

.gate-list{list-style:none;margin:20px 0 0;padding:16px 0 0;border-top:1px solid var(--line);
  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(--grass)}

.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(--tint);
  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(--grass)}


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

   Кабинет родился внутри 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 + env(safe-area-inset-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: 24% 42%; box-shadow: 0 0 0 2px #fff, 0 2px 6px rgba(30,39,25,.18) }
  .bar .brand b { font-size: 15.5px; font-weight: 800; color: var(--grass-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(237,242,230,.7); color: var(--grass-deep) }
  .bar button.on { background: var(--grass-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) }

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

  /* Баннер на широком экране может позволить себе рост: это единственная
     картинка кабинета, и в 138 пикселей от неё остаётся полоска. */
  .herow, .hero { margin-top: 8px }
  .hero { min-height: 224px }
  .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(--grass-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`:
   спрятанному так кадру браузер не считает вёрстку, и подогретая заранее
   страница подписки пересчитывалась бы на глазах в момент показа. Ради
   этого подогрев и делался. Нажатий невидимый слой не ловит и в озвучку
   не попадает — вести себя как отсутствующий он не перестаёт.

   Появление мгновенное, без затухания: слой во весь экран и с кадром внутри
   — самое дорогое, что можно анимировать, а выигрыш от него нулевой. */
.conn{position:fixed;inset:0;z-index:40;display:flex;flex-direction:column;
  background:var(--page);visibility:hidden}
.conn.on{visibility:visible}
.conn-top{flex:0 0 auto;display:flex;align-items:center;gap:10px;
  padding:calc(env(safe-area-inset-top) + 8px) 12px 8px;
  background:var(--card);border-bottom:1px solid var(--line)}
.conn-top b{font-size:15.5px;font-weight:800;letter-spacing:-.01em;color:var(--ink)}
.conn-top .ico{flex:0 0 auto;width:34px;height:34px;border-radius:50%;
  display:grid;place-items:center;border:1px solid var(--line);
  background:var(--tint);color:var(--soft);cursor:pointer}
.conn-top .ico:active{transform:translateY(1px)}
/* Кадр и скелет занимают всё, что осталось, и лежат друг на друге: скелет
   не двигает кадр и уходит, ничего не перерисовывая. `min-height:0` — иначе
   flex-элемент не даёт себя сжать ниже содержимого кадра. */
.conn-body{position:relative;flex:1 1 auto;min-height:0}
/* Своя прокрутка у страницы подписки есть, и вторую полосу рядом с ней
   рисовать незачем. До готовности кадр прозрачен: пустой кадр — это белое
   поле, а под ним уже лежит скелет. */
.conn-frame{position:absolute;inset:0;width:100%;height:100%;border:0;display:block;
  background:var(--page);opacity:0;transition:opacity .2s ease}
.conn.ready .conn-frame{opacity:1}

/* Скелет страницы подписки: шапка с приветствием, две строки, две карточки.
   Повторять её точно незачем — нужно только обещание, что место занято. */
.conn-wait{position:absolute;inset:0;overflow:hidden;
  padding:14px 12px;display:flex;flex-direction:column;gap:12px;
  transition:opacity .2s ease}
.conn-wait span{display:block;border-radius:var(--r);
  background:linear-gradient(90deg,#EEF2E6,#FFFFFF,#EEF2E6);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(20,30,16,.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 + env(safe-area-inset-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(30,39,25,.10);
  will-change:transform;backface-visibility:hidden}
/* Тень набирает глубину по мере подъёма: у приехавшей шторки она заметно
   гуще, чем у той, что ещё в пути, и край над кабинетом читается сразу. */
.sheet.on .sheet-card{box-shadow:0 -12px 40px rgba(30,39,25,.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-kuz{animation:kuz-in .42s cubic-bezier(.34,1.35,.5,1) .06s both}
@keyframes kuz-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-kuz,.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-kuz{position:relative;width:88px;height:88px;margin:2px auto 12px}
.chan-kuz img{width:100%;height:100%;object-fit:cover;object-position:24% 42%;border-radius:50%;
  box-shadow:0 0 0 3px #fff,0 0 0 5px var(--chartreuse),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,#3A8544,var(--cta-deep));
  box-shadow:0 0 0 3px #fff,0 2px 6px rgba(30,66,32,.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(--grass-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(--grass-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(--grass)}


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

   Раздел для двоих, а не для всех, и читают в нём цифры, а не выбирают
   тариф. Отсюда и вид: плотнее остального кабинета, числа моноширинными
   цифрами 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}
  body.is-adm .bar button[data-tab="shop"]{margin:8px 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(--grass-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(--grass-deep);cursor:pointer;box-shadow:var(--sh-1)}
.aico svg{width:19px;height:19px}
.aico:active{transform:translateY(1px);background:var(--grass-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:linear-gradient(180deg,#fff,#FCFDF9);
  border:1px solid var(--line);box-shadow:var(--sh-lift),var(--edge)}

/* Блок онлайна. Свет под числом, а не заливка во всю карточку: зелёное
   пятно держит взгляд там, где живая цифра, и не спорит с остальными. */
.ahero-live{position:relative;padding:14px 16px 13px;
  background:radial-gradient(120% 150% at 0% 0%,#EAF3E2,#F6F9F0 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(--grass);flex:0 0 auto;
  box-shadow:0 0 0 4px rgba(76,138,69,.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(--grass-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(--grass-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(76,138,69,.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(--grass-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}

/* Карточка раздела. Тень слабее общей: на экране их по пять штук сразу, и
   полная тень превращает список в стопку наклеек. */
.acard{background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:13px 14px 14px;box-shadow:0 1px 2px rgba(30,39,25,.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(--grass-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(--grass-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:linear-gradient(180deg,#fff,#FCFDF9);
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden;
  box-shadow:0 1px 2px rgba(30,39,25,.05)}
.agrp::before{content:'';position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,var(--gt),transparent)}
.agrp.an{--gt:var(--grass);--gb:linear-gradient(160deg,#5EA455,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(30,39,25,.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(--line-2);color:var(--grass-deep);
  background:#fff}
.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(--grass-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(--grass-soft);color:var(--grass-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(--grass);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(--grass-soft);border-color:transparent;color:var(--grass-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(--grass-soft);
  overflow:hidden}
.abar .m i{display:block;height:100%;border-radius:var(--pill);
  background:linear-gradient(90deg,var(--chartreuse),var(--grass));
  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(--grass-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(--grass-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(--grass-deep);
  cursor:pointer;padding:0 10px;text-align:center}
.aact:active{background:var(--grass-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}

/* Поле в окне действия. */
.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(--grass);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(--grass-deep);
  padding:7px 14px;min-height:38px;cursor:pointer;font-variant-numeric:tabular-nums}
.ask-quick button.on{background:var(--grass-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,#5EA455,#2C5A2A)}
.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}

/* Порядок сортировки — своей строкой под срезами: «кого показывать» и «в
   каком порядке» это разные вопросы, вперемешку они читаются одним длинным
   рядом кнопок. */
.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}

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

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

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

#s-manage .card{text-align:center}
#s-manage .card.mng{position:relative}

/* Заголовок экрана по центру, стрелка «назад» — поверх, слева: в потоке она
   съедала половину строки, и заголовок стоял не по середине. */
#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(--grass-soft);
  box-shadow:inset 0 2px 6px rgba(30,39,25,.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} }
#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:#DCE9CC;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,#DCEFC4,#A9CE86);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}
.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(--grass-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(--grass-soft);color:var(--grass-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(--grass-deep)}
.dev.free:active{background:var(--grass-soft);transform:translateY(1px)}

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

/* Низкое поле мини-аппа: раздел с одной-двумя привязками обязан вставать
   целиком — из-за пары точек человек не должен листать список из одной
   строки. Длинный список листается и должен: восемь привязок в экран не
   поместятся никак. */
@media (max-height:699px){
  .slots{margin-top:8px}
  /* Поле мини-аппа — около шестисот точек, и раздел с двумя привязками
     обязан вставать целиком. Первой уходит объясняющая строка: её читают
     один раз, а слоты, список и кнопки нужны каждый раз. */
  #s-manage .card.devs-card>.note{display:none}
  #s-manage .card.devs-card>.devs{margin-top:10px;gap:7px}
  .dev{padding:8px 10px}
  #s-manage .card.devs-card>.dev.free{margin-top:7px}
  #s-manage .card.devs-card>.btns{margin-top:9px}
  #s-manage .card.devs-card .btn.sm{height:40px}
  #s-manage .card.devs-card>.note{margin:9px 12px 10px}
}
@media (max-height:639px){
  .slots{margin-top:7px}
  #s-manage .card.devs-card>.devs{margin-top:9px;gap:6px}
  .dev{padding:7px 10px;gap:9px}
  .dev .ic{width:34px;height:34px;border-radius:10px}
  #s-manage .card.devs-card>.dev.free{margin-top:6px}
  #s-manage .card.devs-card>.btns{margin-top:8px}
  #s-manage .card.devs-card .btn.sm{height:38px}
  #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(--grass-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(--grass-soft);color:var(--grass-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(--grass-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,#EAEEE2,#F4F6EF,#EAEEE2);
  background-size:200% 100%;animation:sk 1.2s linear infinite}

/* Низкое поле: короткая история оплат обязана вставать в экран целиком. */
@media (max-height:699px){
  .bmo{padding:9px 2px 4px}
  .buy{padding:8px 2px}
  #s-manage .card.buys-card>.buys{margin-bottom:9px}
  #s-manage .card.buys-card>.note{margin:8px 12px 10px}
}
@media (max-height:639px){
  .bmo{padding:8px 2px 4px}
  .buy{padding:7px 2px;gap:9px}
  .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(--grass)}
.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(--grass-soft);color:var(--grass-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(--grass)}
/* На узких телефонах «Устройства» не влезало и обрывалось многоточием —
   именно на том слове, ради которого вкладку и ищут. */
@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(--grass);
  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,#1F3D1E 0%,#2C5A2A 55%,#376B31 100%)}
/* Тот же травяной узор, что на шапке рекомендованного тарифа: лежит в
   правом углу и почти не виден — шапка читается как материал, а не заливка. */
#s-manage .mng>.phd::after{content:'';position:absolute;inset:0;pointer-events:none;
  opacity:.22;
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'><g fill='none' stroke='%23A9CE86' stroke-width='1.5' stroke-linecap='round'><path d='M14 78 C15 66 13 58 8 50'/><path d='M14 78 C17 68 21 63 27 59'/><path d='M62 40 C63 30 61 24 57 18'/><path d='M62 40 C65 32 69 28 74 25'/><path d='M88 88 C89 80 87 75 83 71'/></g><g fill='%23A9CE86'><circle cx='76' cy='58' r='1.5'/><circle cx='30' cy='40' r='1.3'/></g></svg>");
  background-size:96px 96px;
  -webkit-mask-image:linear-gradient(100deg,transparent 45%,#000 100%);
  mask-image:linear-gradient(100deg,transparent 45%,#000 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,#3E6E37,#2A5127);
  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:#BFD6A6}
#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(214,231,188,.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:#C7DCAE;
  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:#E7EDDA;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:#C2D3A9}
#s-manage .card.plan .cl .ic{flex:0 0 auto;width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;color:var(--grass);background:#fff;
  border:1px solid #D8E7C4;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(--grass-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{display:block;height:100%;border-radius:var(--pill);
  background:linear-gradient(90deg,#CDE7A8,#A9CE86)}
#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:#C7DCAE}
#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:#E7EDDA;
  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:#C2D3A9}
#s-manage .card.traf .cl .ic{flex:0 0 auto;width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;color:var(--grass);background:#fff;
  border:1px solid #D8E7C4;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(--grass-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}
@media (max-height:699px){
  #s-manage .card.traf>.spec{margin-top:10px;padding:8px 2px}
  #s-manage .card.traf>.note{margin-top:9px}
  #s-manage .card.traf>.nrow{margin-top:9px}
  #s-manage .card.traf>.btns{margin:9px 12px 10px}
}
@media (max-height:639px){
  #s-manage .card.traf>.spec{margin-top:9px;padding:7px 2px}
  #s-manage .card.traf>.note{margin-top:8px}
  #s-manage .card.traf>.nrow{margin-top:8px}
  #s-manage .card.traf>.btns{margin:8px 12px 9px}
  #s-manage .card.traf .btn.sm{height:40px}
  #s-manage .mng>.phd .tbar{margin-top:9px}
  #s-manage .mng>.phd .tsub{margin-top:5px}
}

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