/* ══════════════════════════════════════════════════════════════════
   Токены — живой Supabase-2026 (oklch → flat hex), сверено 2026-08-31:
   фон .19/.0025/159, поверхности лестницей, бордеры = white-alpha,
   brand #3ecf8e, кнопка primary #006239, статусы #db8e00/#e54d2e.
   Нейтрали несут зелёный подтон hue 159 — фирменная колориметрия.
   ══════════════════════════════════════════════════════════════════ */
:root{
  --bg:#131413; --surface:#181a19; --surface-2:#1e201f; --surface-3:#282a29;
  --popover:#1b1d1c; --control:#1e1f1e;
  --fg:#edefee; --fg-2:#bcbdbc; --fg-3:#989a99;
  --border:rgba(255,255,255,.075); --border-strong:rgba(255,255,255,.135);
  --border-stronger:rgba(255,255,255,.174); --border-hover:rgba(255,255,255,.28);
  --brand:#3ecf8e; --brand-dim:#34b97d; --link:#00c573;
  --btn-green:#006239; --brand-tint:#00311d;
  --warn:#db8e00; --danger:#e54d2e; --danger-text:#f16a50;
  --r-xs:4px; --r-btn:6px; --r-card:8px; --r-panel:12px; --r-pill:999px;
  --sans:'Inter',system-ui,-apple-system,sans-serif;
  --disp:'Manrope',var(--sans);
  --mono:'Source Code Pro',ui-monospace,'SF Mono',monospace;
  --t-hero:min(clamp(40px,4vw,47px),calc(11.2vw - 6.4px)); --t-h2:clamp(28px,3.4vw,40px);   /* герой: кегль ≤47px (решение владельца). С 2026-09-28 заголовок — «SSH‑клиент / со сквозным шифрованием.»: обе строки
     входят в колонку 668px на 1440 при 47px. Формула для телефона осталась от прежнего «Инфраструктура —» (349px при 40px):
     11.2vw − 6.4px — с запасом, vw включает классическую полосу прокрутки; новому тексту она не мешает — самый длинный
     неразрывный кусок теперь «шифрованием.» */
  --t-h3:19px; --t-title-lg:clamp(21px,2.2vw,25px); --t-body:16.5px; --t-sm:14px; --t-xs:13px; --t-code:13.5px;
  --ease:cubic-bezier(.25,.1,.25,1);
  --nav-h:60px;   /* высота шапки без её 1px-рамки: из неё считается первый экран героя */
}
*{box-sizing:border-box}
html:focus-within{scroll-behavior:smooth}   /* плавно — только навигация по якорям (ссылка в фокусе); программная прокрутка мгновенная */
@media(prefers-reduced-motion:reduce){html:focus-within{scroll-behavior:auto}}
body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--sans);
  font-size:var(--t-body);line-height:1.6;-webkit-font-smoothing:antialiased}
a{color:inherit;text-decoration:none}
::selection{background:rgba(62,207,142,.25)}
:focus-visible{outline:2px solid var(--brand);outline-offset:3px;border-radius:4px}
h1,h2,h3{font-family:var(--disp);font-weight:600;letter-spacing:-.02em;margin:0;text-wrap:balance}
p{margin:0}
.wrap{max-width:1180px;margin:0 auto;padding:0 24px}
section{border-bottom:1px solid var(--border)}
section>.wrap{padding-top:88px;padding-bottom:88px}
[id]{scroll-margin-top:76px}
.h2{font-size:var(--t-h2);line-height:1.12;margin:0 0 14px}
.sub{color:var(--fg-2);font-size:var(--t-body);max-width:62ch;text-wrap:balance}   /* balance — строки ровные, без огрызка «не так.» в последней (было в «Что если…») */
.mono{font-family:var(--mono)}

/* ── кнопки: живой Supabase (тёмно-зелёная заливка + зелёная кромка) ── */
.btn{display:inline-flex;align-items:center;gap:8px;font-family:var(--sans);
  font-size:var(--t-sm);font-weight:500;border-radius:var(--r-btn);
  padding:0 18px;height:40px;border:1px solid transparent;cursor:pointer;
  transition:background .15s var(--ease),border-color .15s var(--ease)}
.btn.primary{background:var(--btn-green);color:#fff;border-color:rgba(62,207,142,.30)}
.btn.primary:hover{background:#00713f;border-color:rgba(62,207,142,.45)}
.btn.ghost{background:var(--surface-2);color:var(--fg);border-color:var(--border-strong)}
.btn.ghost:hover{border-color:var(--border-hover)}
.btn:active{transform:scale(.98)}

/* ── panel-конверт: p-px градиентная hairline, свет сверху ── */
.panel{padding:1px;border-radius:var(--r-panel);
  background:linear-gradient(180deg,var(--border),rgba(255,255,255,.02));
  transition:background .2s var(--ease)}
.panel>.inner{border-radius:11px;background:var(--surface);height:100%;overflow:hidden}   /* 11 = 12 − 1px padding конверта: внутренний угол концентричен внешнему; вне шкалы намеренно */
.panel:hover{background:linear-gradient(180deg,var(--border-strong),rgba(255,255,255,.04))}

/* ── навигация ── */
nav{position:sticky;top:0;z-index:50;background:rgba(19,20,19,.92);
  border-bottom:1px solid transparent;transition:border-color .2s}
nav.stuck{border-bottom-color:var(--border)}
nav .wrap{display:flex;align-items:center;gap:26px;height:var(--nav-h)}
.brand{display:flex;align-items:center;gap:9px;min-height:40px;font-weight:600;font-size:18px;letter-spacing:-.01em}
.brand svg{flex:none;width:28px;height:28px}
.brand .tm{color:var(--brand)}   /* «Term» в имени — брендовый зелёный (решение владельца 2026-09-06); контраст 9.25:1 на фоне шапки */
.navlinks{display:flex;gap:22px;font-size:var(--t-sm);color:var(--fg-2);margin-left:6px}
.navlinks a{display:inline-flex;align-items:center;height:40px;white-space:nowrap}
.navlinks a:hover{color:var(--fg)}
.nav-right{margin-left:auto;display:flex;align-items:center;gap:12px}
@media(max-width:900px){.navlinks a.opt{display:none}}
@media(max-width:640px){.navlinks{display:none}}
/* ── компактное меню ≤520: details «Разделы» вместо единственного пункта. summary — нативная кнопка (Enter/Space),
   пункт, Escape и клик снаружи закрывают (JS); без JS — обычный раскрывающийся список ── */
.mnav{display:none}
.mnav summary{list-style:none;display:inline-flex;align-items:center;gap:7px;height:40px;padding:0 12px;
  font-size:13.5px;font-weight:500;color:var(--fg);background:var(--surface-2);border:1px solid var(--border-strong);
  border-radius:var(--r-btn);cursor:pointer;user-select:none;white-space:nowrap;transition:border-color .15s var(--ease)}
.mnav summary::-webkit-details-marker{display:none}
.mnav summary:hover,.mnav[open] summary{border-color:var(--border-hover)}
.mnav-list{list-style:none;margin:0;position:absolute;left:0;right:0;top:100%;padding:4px 24px 10px;
  background:var(--popover);border-bottom:1px solid var(--border);box-shadow:0 24px 60px -20px rgba(0,0,0,.6)}   /* «правило одной тени»: список плавает над страницей — токен диалога */
.mnav-list a{display:flex;align-items:center;min-height:46px;font-size:15.5px;color:var(--fg-2);border-bottom:1px solid var(--border)}
.mnav-list li:last-child a{border-bottom:0}
.mnav-list a:hover{color:var(--fg)}

/* ── герой «планета справа» (вариант A — выбор владельца 2026-09-06): копия слева, планета справа на всю секцию ──
   Холст лежит на всю секцию; копия стоит поверх него (z-index), подписи движка обходят её (exclusion), суша под текстом приглушена.
   Ниже 860px холст встаёт в поток под кнопками; ≤640 и reduced-motion — статичный кадр движка. Классы — с префиксом va-. */
.va-hero{position:relative;overflow:hidden;--va-pad:44px;--va-frame:692px}
/* ПЕРВЫЙ ЭКРАН ВО ВСЁ ОКНО (владелец 2026-09-27: «при входе на страницу я вижу внизу окна уже следующий блок»).
   Прежде высоту задавал только утверждённый кадр — 604 + 2×44 = 692; вместе с шапкой 752, и на любом окне выше
   снизу выглядывала «Что это даёт вам». Теперь герой не ниже окна за вычетом шапки.
   --va-frame — высота холста в утверждённом кадре. Она же — предел размера планеты (опция sizeRef движка):
   герой растёт до окна, а планета нет. Иначе на высоком окне она уходит под текст целиком — это вариант C
   «Планета за текстом», а владелец выбрал A. Лишняя высота уходит в воздух вокруг композиции. */
.va-hero .wrap{padding-top:var(--va-pad);padding-bottom:var(--va-pad)}
.va-grid{display:grid;grid-template-columns:minmax(0,7.4fr) minmax(0,4.6fr);   /* 7.4: вторая строка H1 «со сквозным шифрованием.» при 47px входит в колонку одной строкой */
  grid-template-areas:". stage" "h1 stage" "lead stage" "cta stage" ". stage";
  grid-template-rows:var(--va-lift) auto auto auto 1fr;gap:0 48px;align-items:start}
/* КОПИЯ — У ВЕРХА ГЕРОЯ (владелец 2026-09-27: «поднимем это выше, иначе сверху большая чёрная область, и как раз
   избавимся от наложения на анимацию»). Прежде копию ставили доли 2fr/3fr свободной высоты: в кадре 692px заголовок
   стоял в 162px от верха героя, а когда герой вырос до окна — сползал вместе с ним (221 на 1440×900, 308 на 1728×1117,
   423 на 1100×1400). Над ним копилась пустота, а лид и кнопки уезжали в середину высоты — туда, где проходит левый край
   планеты. Теперь отступ постоянный: заголовок в 44 + 56 = 100px от верха героя (как заголовки разделов — 88), лишняя
   высота уходит вниз, под кнопки; планета стоит по центру высоты, как стояла */
.va-hero{--va-lift:56px}
.va-grid>h1{grid-area:h1;position:relative;z-index:1;align-self:end}
.va-lead{grid-area:lead;position:relative;z-index:1;color:var(--fg-2);font-size:var(--t-body);line-height:1.65;max-width:52ch;margin-top:26px;text-wrap:pretty}   /* pretty: без коротких огрызков строк на телефоне */
.va-lead b{color:var(--fg);font-weight:500}
.va-cta{grid-area:cta;position:relative;z-index:1;margin-top:30px}
.va-stage{grid-area:stage;   /* высота секции — min-height; холст absolute, потоковых потомков на десктопе нет */
  min-height:max(calc(var(--va-frame) - 2 * var(--va-pad)),
                 calc(100svh - var(--nav-h) - 2 * var(--va-pad) - 2px))}   /* 2px — рамка шапки и рамка самой секции; svh — чтобы на телефоне панель браузера не съедала низ */
/* планета: холст на всю секцию, под копией; без JS холст пуст — правая колонка не занимает место, копия в одну колонку */
.va-globe{position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none;z-index:0}
.va-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}
html:not(.js) .va-stage{display:none}   /* без JS планеты нет — описывать нечего */
html:not(.js) .va-grid{grid-template-columns:1fr;grid-template-areas:"h1" "lead" "cta";grid-template-rows:auto}
/* один пик движения при загрузке: заголовок → лид → кнопки (hero-in) → планета проявляется, первая дуга уходит через ~1 с; только при JS и без reduced-motion */
@keyframes hero-in{from{opacity:0;transform:translateY(10px)}}
@keyframes va-globe-in{from{opacity:0}}
@media(prefers-reduced-motion:no-preference){
  html.js .hero .hin{animation:hero-in .6s var(--ease) both}
  html.js .hero .hin.d2{animation-delay:.12s}
  html.js .hero .hin.d3{animation-delay:.24s}
  html.js .va-globe{animation:va-globe-in 1.1s var(--ease) .4s both}
}
h1{font-size:var(--t-hero);line-height:1.04;letter-spacing:-.03em}
h1 .line2{color:var(--brand)}
/* метка «E2EE» у названия (v38) снята владельцем 2026-09-28: «давай это пока уберём». Если вернётся: Source Code Pro 500, .56em,
   brand, vertical-align .52em, после «SSH‑клиент», без рамки и фона; в строку «со сквозным шифрованием» «(E2EE)» не входит (756 из 668px) */
/* строки заголовка без принудительного nowrap: где вторая в колонку не входит, она переносится честно («со сквозным» / «шифрованием.»)
   вместо наезда на планету (коробка исключения строится по блоку h1, хвост был бы незащищён) */
@media(max-width:1020px){.va-grid{gap:0 36px}.va-hero{--va-frame:648px}}   /* 560 + 2×44: утверждённый кадр этой ширины */
/* планшет и уже: планета в потоке под кнопками; ≤640 — статичный кадр движка */
@media(max-width:860px){
  /* планшет и уже: тоже во всё окно — на 768×1024 снизу торчало 176px следующей секции, на 820×1180 — 332px.
     Копия сверху, планета под ней забирает всю оставшуюся высоту (цепочка колонок: секция → .wrap → колонка копии),
     размер планеты — прежний (--va-frame 400/380 → sizeRef). На телефоне герой и так выше окна — ничего не меняется */
  .va-hero{--va-frame:400px;display:flex;flex-direction:column;min-height:calc(100svh - var(--nav-h) - 1px)}
  .va-hero>.wrap{flex:1 0 auto;display:flex;flex-direction:column;width:100%}
  .va-grid{flex:1 0 auto;display:flex;flex-direction:column;align-items:stretch}   /* кнопки над планетой: «Скачать» на первом экране.
     align-items — явно: у сетки start действовал по вертикали, а в колонке он по горизонтали и сжал бы область планеты до нуля */
  .va-grid>h1{align-self:stretch}   /* в колонке align-self:end от сетки прижал бы заголовок вправо */
  .va-lead{margin-top:24px}
  .va-cta{margin-top:28px}
  .va-stage{position:relative;flex:1 0 auto;min-height:var(--va-frame);margin-top:8px}
  .va-globe{position:absolute;top:0;left:-24px;width:calc(100% + 48px);height:100%;margin:0}   /* во всю ширину экрана: лимб уходит за край, а не обрывается на поле.
     Размеры — ЯВНО, в процентах от области планеты. У <canvas> размер «auto» берётся из его атрибутов width/height, а их выставляет
     сам движок по замеру холста: холст растёт → движок увеличивает атрибуты → холст растёт снова. Так было при width/height:auto —
     холст доходил до предела браузера 16 777 216 px (замер 2026-09-27). Проценты от блока-обёртки петлю разрывают */
  html:not(.js) .va-hero{min-height:0}   /* без JS планеты нет — растягивать нечего */
}
@media(max-width:520px){.va-hero{--va-frame:380px}}
.cta-row{display:flex;flex-wrap:wrap;gap:12px;align-items:center}   /* отступ сверху — у контейнера (.va-cta); финальный блок снят владельцем 2026-09-27 */
.cta-note{font-size:var(--t-xs);color:var(--fg-3);margin-top:12px;text-wrap:balance}

/* ── bento возможностей ── */
.bento{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:44px}
.bento .panel.w2{grid-column:span 2}
@media(max-width:1020px){.bento{grid-template-columns:repeat(2,1fr)}}
@media(max-width:640px){.bento{grid-template-columns:1fr}.bento .panel.w2{grid-column:auto}}
.bcard{display:flex;flex-direction:column;gap:10px;padding:22px;height:100%;min-height:260px}
.bcard .bh{display:flex;align-items:flex-start;gap:10px;font-family:var(--disp);
  font-weight:600;font-size:var(--t-h3);line-height:1.3;letter-spacing:-.01em}
.bcard .bh svg{color:var(--brand);flex:none;margin-top:4px}   /* (24.7 − 17) / 2: иконка по центру первой строки */
.bcard p{font-size:15.5px;color:var(--fg-2);line-height:1.6;max-width:70ch}
.bcard p b{color:var(--fg);font-weight:500}
.bviz{margin-top:auto;position:relative;overflow:hidden;border-radius:var(--r-card)}

/* hover-run: анимации живут в DOM, но стоят на паузе до ховера;
   на touch (hover:none) карточка оживает при появлении в кадре (.seen от IO) */
@media(hover:hover) and (prefers-reduced-motion:no-preference){
  .run-target{animation-play-state:paused!important}
  .panel:hover .run-target{animation-play-state:running!important}
}
@media(hover:none) and (prefers-reduced-motion:no-preference){
  .run-target{animation-play-state:paused!important}
  .panel.seen .run-target{animation-play-state:running!important}
}
@media(prefers-reduced-motion:reduce){.run-target{animation:none!important}}

/* мини-визуалы bento */
.tree-viz{border:1px solid var(--border);border-radius:var(--r-card);background:var(--bg);
  padding:10px;font-size:12px;font-family:var(--mono)}
.tree-viz .r{display:flex;align-items:center;gap:8px;padding:4px 6px;border-radius:4px;color:var(--fg-2)}
.tree-viz .r i{width:5px;height:5px;border-radius:50%;background:var(--fg-3);flex:none}
.tree-viz .r.live i{background:var(--brand)}
.tree-viz .r .tg{margin-left:auto;color:var(--fg-3);font-size:11px;border:1px solid var(--border-strong);
  border-radius:4px;padding:0 5px}
.jviz{display:block;width:100%}
/* подписи узлов — HTML под svg, привязаны процентами к тем же x, что и узлы; размер не зависит от ширины карточки */
.jviz-l{position:relative;height:18px;margin-top:2px;font:11.5px/18px var(--mono);color:var(--fg-3)}
.jviz-l span{position:absolute;top:0;white-space:nowrap}
.jviz-l .c{transform:translateX(-50%)}
.jviz-l .e{transform:translateX(-100%)}
@keyframes dashflow{to{stroke-dashoffset:-16}}
.jviz .dash{stroke-dasharray:4 4;animation:dashflow 1s linear infinite}
/* карточка «Один ключ — на все хосты разом» — v43 (2026-10-01, сверено с ru.json ветки v3: keys.deployAll «Развернуть на все ({{count}})»,
   deployed / notDeployed «развёрнут / не развёрнут», toast deployAllDone «Ключ развёрнут — хостов: {{count}}»). Владелец 2026-10-01
   вернул её вместо статичной «Ключ создаётся здесь»: развёртывание покажут в интерфейсе v3 до запуска сайта (отдельная задача desktop).
   Сцена: статусы хостов по очереди сменяются с «не развёрнут» на «развёрнут», затем итог. Запуск — как у остальных карточек bento
   (.run-target): по наведению, на touch — при появлении в кадре (.seen). Покой до наведения — честное начало: «не развёрнут»;
   при «уменьшить движение» — конечное состояние (см. блок reduced-motion ниже) */
/* снимок инспектора ключа v3 (решение владельца 2026-10-06; раскатка — после NEXTERM-82, разметка и стили — в ff6cc7c) */
.keyc{border:1px solid var(--border);border-radius:var(--r-card);background:var(--bg);padding:10px 12px}
.keyc .kh2{display:flex;align-items:center;justify-content:space-between;gap:10px;font:600 13px var(--sans);color:var(--fg)}
.keyc .ka{font:400 11.5px var(--mono);color:var(--fg-3)}
.keyc .kl{margin-top:8px;font:11px var(--sans);color:var(--fg-3)}
.keyc .row{display:flex;align-items:center;justify-content:space-between;gap:10px;font:12px var(--mono);color:var(--fg-2);margin:5px 0}
.keyc .row span{color:var(--fg-3);font-variant-numeric:tabular-nums}
.keyc .kp{margin-top:8px;font:11.5px var(--sans);color:var(--fg-3)}
.keyc .kb2{display:inline-block;margin-top:9px;font:500 11.5px var(--sans);color:var(--fg);background:var(--surface-2);border:1px solid var(--border-strong);border-radius:var(--r-xs);padding:2px 8px;white-space:nowrap}
.tunviz{display:block;width:100%}
.tunviz .tube{stroke:var(--surface-3)}   /* труба — верхняя ступень нейтралей, не серый #2e2e2e */
.tunviz .core{stroke:var(--surface)}
.tun-l{display:flex;justify-content:space-between;padding:0 2.7%;margin-bottom:4px;font:11.5px/18px var(--mono);color:var(--fg-3)}
.tunviz .pkt{fill:var(--brand)}
@keyframes pktmove{to{transform:translateX(260px)}}
.tunviz .pkt{animation:pktmove 1.8s linear infinite}
.snip{border:1px solid var(--border);border-radius:var(--r-card);background:var(--popover);
  padding:12px 14px;font:12px/1.8 var(--mono);color:var(--fg-2)}
.snip .v{color:var(--brand-dim);background:var(--brand-tint);border-radius:4px;padding:0 4px}
.sftp{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--border);
  border:1px solid var(--border);border-radius:var(--r-card);overflow:hidden;font:11.5px var(--mono)}
.sftp>div{background:var(--bg);padding:8px}
.sftp .hd{color:var(--fg-3);margin-bottom:6px;font-size:11px}
.sftp .f{display:flex;justify-content:space-between;color:var(--fg-2);padding:2.5px 4px}
@keyframes slidein{from{transform:translateX(-8px);opacity:.3}to{transform:none;opacity:1}}
.sftp .f.mv{color:var(--brand-dim);animation:slidein 1.2s var(--ease) infinite alternate}
.gridnote{margin-top:22px;font-size:var(--t-sm);color:var(--fg-3);max-width:72ch}
.gridnote b{color:var(--fg-2);font-weight:500}



/* ── триптих выгод: один конверт, три колонки через hairline, демо вместо иконок ── */
.gains{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--border);
  border:1px solid var(--border);border-radius:var(--r-panel);overflow:hidden;margin-top:44px}
@media(max-width:900px){.gains{grid-template-columns:1fr}}
.gain{background:var(--surface);padding:28px 26px 26px;display:flex;flex-direction:column;gap:12px;min-width:0}
.gain h3{font-size:var(--t-title-lg);line-height:1.15;letter-spacing:-.02em}
.gain>p{font-size:15px;color:var(--fg-2);line-height:1.55;max-width:38ch}
.gain>p b{color:var(--fg);font-weight:500}
.gain .demo{margin-top:auto;padding-top:16px}
.gain .tech{font-family:var(--mono);font-size:12px;color:var(--fg-3);margin-top:10px}
/* демо 1: хаос → порядок (строки выстраиваются по группам) */
html.js .gn1 .tree-viz .r{opacity:0;transform:translateX(-8px)}
.gn1.seen .tree-viz .r{animation:rise .5s var(--ease) forwards}
.gn1 .tree-viz .r:nth-child(2){animation-delay:.1s}.gn1 .tree-viz .r:nth-child(3){animation-delay:.2s}
.gn1 .tree-viz .r:nth-child(4){animation-delay:.3s}.gn1 .tree-viz .r:nth-child(5){animation-delay:.4s}
.gn1 .tree-viz .r:nth-child(6){animation-delay:.5s}
@keyframes rise{to{opacity:1;transform:none}}
/* демо 2: набор в командной палитре (владелец 2026-09-27: «у нас в интерфейсе такого нет» — строка «admin@db-01:~$ оболочка открыта»
   снята, подсказка поля и заголовок группы — как в палитре ветки v3: «Раздел, действие, сниппет или ssh user@host», «Хосты») */
.kdemo{border:1px solid var(--border);border-radius:var(--r-card);background:var(--popover);font:12px var(--mono)}
.kdemo .in{padding:9px 11px;border-bottom:1px solid var(--border);color:var(--fg);min-height:34px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.kdemo .in .ph{color:var(--fg-3)}
.kdemo .gh{padding:7px 11px 3px;font:11px var(--sans);color:var(--fg-3)}
.kdemo .it:last-child{margin-bottom:5px}
.kdemo .it{display:flex;justify-content:space-between;padding:6px 11px;color:var(--fg-2);opacity:.45;transition:opacity .25s,background .25s}
.kdemo .it.hit{opacity:1}
.kdemo .it.sel{background:var(--surface-2);color:var(--fg)}
.kdemo .it .k{color:var(--fg-3)}
/* демо 3: фрагмент раздела «Ключи» ветки v3 (владелец 2026-09-27: «это переделать, у нас в интерфейсе такого нет» — прежний
   список секретов со штампами «зашифровано · только у вас» был выдуман). Строки и тексты — из интерфейса: метка и тип ключа
   (ed25519, rsa 4096; аппаратных FIDO-ключей ed25519-sk клиент не поддерживает — строки с ними нет), статус «открыто · мастер-пароль» из меню хранилища, пустое состояние закрытого хранилища.
   Сцена: список ключей → хранилище блокируется → «Хранилище закрыто / Ключи зашифрованы и без мастер-пароля не читаются».
   Без JS — только список; при «уменьшить движение» смена мгновенная, без сдвигов */
.krail{border:1px solid var(--border);border-radius:var(--r-card);background:var(--bg);overflow:hidden;container-type:inline-size}
.krail .kh{display:flex;align-items:center;gap:8px;padding:8px 11px;border-bottom:1px solid var(--border)}
.krail .kh b{font-size:13px;font-weight:600;color:var(--fg)}
.krail .kh .kc{font:11.5px var(--mono);color:var(--fg-3);white-space:nowrap;transition:opacity .3s var(--ease)}
/* пороги шапки — по ширине самой рамки, не окна (правило лендинга: полоса прокрутки и колонки триптиха ломают оконный порог).
   Шапке «Ключи · 3 ключа · открыто · мастер-пароль» нужно ~300 px, без «3 ключа» — ~227 px; рамка бывает 218–288 px.
   Порог 285 (а не 299): на 390 рамка 288 px, и «3 ключа» там видно — шапка входит без переполнения (замер 2026-10-01);
   на 360 (258 px) и в три колонки на 1000 (264 px) подпись скрыта */
@container (max-width:285px){.krail .kh .kc{display:none}}
@container (max-width:228px){.krail .kst .km{display:none}}
.krail .kst{margin-left:auto;display:inline-flex;align-items:center;gap:6px;font:11px var(--mono);color:var(--fg-3);white-space:nowrap}
.krail .kst{transition:opacity .3s var(--ease)}
.krail .kst i{width:6px;height:6px;border-radius:50%;background:var(--brand)}
.krail .kb{position:relative}
.krail .klist{padding:4px 0;transition:opacity .4s var(--ease),transform .4s var(--ease)}
.krail .kr{display:flex;align-items:center;gap:8px;padding:5px 11px;font:12px var(--mono);color:var(--fg-2)}
.krail .kr>i{width:5px;height:5px;border-radius:50%;background:var(--fg-3);opacity:.6;flex:none}
.krail .kr svg{flex:none;color:var(--fg-3)}
.krail .kr .kk{margin-left:auto;color:var(--fg-3);font-size:11.5px}
.krail .klock{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:center;gap:3px;padding:0 14px;
  opacity:0;transform:translateY(6px);pointer-events:none;transition:opacity .4s var(--ease) .12s,transform .4s var(--ease) .12s}
.krail .klock b{font-size:13.5px;font-weight:600;color:var(--fg)}
.krail .klock span{font-size:12.5px;line-height:1.45;color:var(--fg-3)}
.gn3.locked .krail .klist{opacity:0;transform:translateY(-6px)}
.gn3.locked .krail .klock{opacity:1;transform:none}
.gn3.locked .krail .kc{opacity:0}
.gn3.locked .krail .kst{opacity:0}   /* у закрытого хранилища статуса «открыто» нет, а своей подписи в интерфейсе нет — статус просто уходит */
@media(prefers-reduced-motion:reduce){
  .gn1 .tree-viz .r{opacity:1;transform:none;animation:none}
  .krail .klist,.krail .klock,.krail .kc,.krail .kst{transition:none}
}

/* ── как устроено 01–04 (шаг 05 «Сервер узнаётся в лицо» владелец снял 2026-09-27) ── */
.how{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,6fr);gap:40px 64px;align-items:center;
  padding:60px 0}
.hairline{height:1px;background:linear-gradient(to right,transparent,var(--border-strong) 50%,transparent);border:0;margin:0}
.how.flip>.hviz{order:-1}
@media(max-width:860px){.how{grid-template-columns:1fr}.how.flip>.hviz{order:0}}
.how .num{font-family:var(--mono);font-size:14px;font-weight:400;color:var(--brand);margin-right:14px;vertical-align:middle}
.how h3{font-size:var(--t-title-lg);line-height:1.15;margin-bottom:10px}
.how .txt p{color:var(--fg-2);font-size:15px;margin-top:8px;max-width:70ch}
.how .note{font-size:var(--t-xs);color:var(--fg-3);margin-top:14px;border-left:1px solid var(--border-stronger);padding-left:12px;max-width:70ch}
.hviz .inner{padding:22px;overflow-x:auto}
/* 01: память argon2id */
.mem{display:grid;grid-template-columns:repeat(24,1fr);gap:3px;margin-bottom:16px}
.mem i{aspect-ratio:1;background:var(--surface-3);border-radius:var(--r-xs);opacity:.5}
.mem i.on,html:not(.js) .mem i{background:var(--brand-dim);opacity:var(--o,1);transition:background .4s,opacity .4s}
.duel{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.duel p{border:1px solid var(--border);border-radius:var(--r-card);padding:12px 14px;background:var(--bg);font-size:var(--t-sm);line-height:1.5;color:var(--fg-2)}
.duel b{font-weight:600;color:var(--fg);font-variant-numeric:tabular-nums}
.duel .win b{color:var(--brand)}
.duel code{font-family:var(--mono);font-size:12.5px;color:var(--brand-dim)}
@media(max-width:480px){.duel{grid-template-columns:1fr}}
/* 02: конверт */
.env-svg{display:block;width:100%;max-width:420px;margin:0 auto}
.env-cap,.fan-cap{font-size:12px;color:var(--fg-3);text-align:center;margin-top:12px;font-family:var(--mono);min-height:18px}
/* АНИМАЦИЯ КОНВЕРТА (владелец 2026-09-27: «тут анимацию нужно поменять и сделать эффектнее»). Прежде при смене пароля
   контур просто мигал и вставал штамп. Теперь — рассказ за 2 с: клапан открывается (SMIL-анимация d, её умеет и Safari) →
   ключ хранилища выходит из конверта и светится: он тот же → старый конверт стирается (контур пути с pathLength=1
   гаснет по dashoffset), подпись KEK сменяется на новую версию → новый конверт рисуется заново → ключ возвращается,
   клапан закрывается, встаёт штамп «resealed ✓». Попытка без пароля: клапан дёргается и захлопывается, конверт
   краснеет и трясётся, ключ гаснет. При первом появлении в кадре схема один раз сама показывает смену пароля.
   При «уменьшить движение» — без движения: меняются подписи и штампы. */
.env-key,.env-stamp{transform-box:fill-box;transform-origin:center}
@keyframes envKeyOut{0%,14%{transform:none;filter:none}38%,56%{transform:translateY(-22px);filter:drop-shadow(0 0 9px rgba(62,207,142,.6))}78%,100%{transform:none;filter:none}}
@keyframes envOutline{0%,22%{stroke-dashoffset:0}40%,46%{stroke-dashoffset:1}68%,100%{stroke-dashoffset:0}}
@keyframes envKek{0%,20%{opacity:1}34%,46%{opacity:0}62%,100%{opacity:1}}
@keyframes envStamp{0%,70%{opacity:0;transform:scale(1.4)}84%{opacity:1;transform:scale(.96)}100%{opacity:1;transform:scale(1)}}
.resealing .env-key{animation:envKeyOut 2s var(--ease)}
.resealing .env-outline{stroke-dasharray:1;animation:envOutline 2s var(--ease)}
.resealing .env-kek{animation:envKek 2s var(--ease)}
.resealing .env-stamp{animation:envStamp 2s var(--ease) forwards}
.sealed .env-stamp{opacity:1}
/* 03: веер ключей */
.fan-svg{display:block;width:100%;min-width:398px;max-width:520px;margin:0 auto}   /* 398/468 = .85 → подписи 13 ед. не тоньше 11px; на узкой панели — «дерево» .fan-n (см. «СХЕМЫ НЕ ВЫЛЕЗАЮТ»). pathLength 260 у линий — прорисовка идёт всю анимацию при любой длине линии */
.fan-svg .links{opacity:.55}
html.js .fan-svg .ln{stroke-dasharray:260;stroke-dashoffset:260}
html.js .fan-svg .fk{opacity:0;transform:translateY(8px);transform-box:fill-box}
.fan.in .fan-svg .ln{animation:draw .9s var(--ease) forwards}
.fan.in .fan-svg .ln:nth-child(2){animation-delay:.12s}.fan.in .fan-svg .ln:nth-child(3){animation-delay:.24s}
.fan.in .fan-svg .ln:nth-child(4){animation-delay:.36s}.fan.in .fan-svg .ln:nth-child(5){animation-delay:.48s}
.fan.in .fan-svg .fk{animation:rise .5s var(--ease) forwards}
.fan.in .fan-svg .fk:nth-of-type(2){animation-delay:.48s}.fan.in .fan-svg .fk:nth-of-type(3){animation-delay:.6s}
.fan.in .fan-svg .fk:nth-of-type(4){animation-delay:.72s}.fan.in .fan-svg .fk:nth-of-type(5){animation-delay:.84s}
.fan.in .fan-svg .fk:nth-of-type(6){animation-delay:.96s}   /* nth-of-type считает и <g class="links">: блоки записей — со 2-го по 6-й.
   Прежде задержки стояли на 1–5, и последний блок (folder) поднимался первым, раньше своей линии */
@keyframes draw{to{stroke-dashoffset:0}}
@media(prefers-reduced-motion:no-preference){.fan.in .fan-svg .links{animation:linkglow 3s ease-in-out 1.4s infinite alternate}}
@keyframes linkglow{to{opacity:.95}}
@media(prefers-reduced-motion:reduce){html.js .fan-svg .ln{stroke-dashoffset:0;animation:none}html.js .fan-svg .fk{opacity:1;transform:none;animation:none}}
/* 04: что на диске */
.disk{border:1px solid var(--border);border-radius:var(--r-card);overflow:hidden;font-size:12.5px}
.disk .row{display:grid;grid-template-columns:1fr 1.3fr;border-bottom:1px solid var(--border)}
.disk .row:last-child{border-bottom:0}
.disk .row>div{padding:9px 13px}
.disk .in-c{color:var(--fg-2);background:var(--surface)}
.disk .out-c{font-family:var(--mono);color:var(--fg-3);background:var(--bg);font-size:11.5px;
  overflow-wrap:anywhere;text-wrap:balance}   /* balance: байты делятся на ровные строки, а не «9 + одинокий» */
.disk .hd{font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--fg-3);background:var(--popover)}

/* ── следствия ── */
.cons{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:40px}
@media(max-width:900px){.cons{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.cons{grid-template-columns:1fr}}
.con{padding:20px;display:flex;flex-direction:column;gap:10px}
/* РАЗМЕРЫ «ЧТО ЕСЛИ…» (владелец 2026-09-27: «тут что-то с размером шрифтов вроде бы не то»). Вопрос был 19px при ответе
   15.5px — разница в 3.5px, а жирные фразы ответа (500, fg) спорили с ним по весу: иерархии почти не было. Теперь вопрос —
   21px (нижняя ступень --t-title-lg, как у заголовков карточек выгод и шагов, но без роста: самый длинный вопрос
   «сервер вдруг «сменил ключ»?» на 1440 так входит в одну строку), ответ — 15px, как текст карточек выгод и шагов */
.con .q{position:relative;padding-left:18px;font-family:var(--disp);font-size:21px;line-height:1.25;font-weight:600;letter-spacing:-.015em;color:var(--fg);text-wrap:balance}
.con .q::before{content:"";position:absolute;left:0;top:.62em;width:8px;height:2px;background:var(--warn)}   /* черта — висячая: перенос вопроса встаёт под текст, а не под черту; .62em — середина первой строки */
.con .a{font-size:15px;color:var(--fg-2);line-height:1.6;max-width:70ch}
.con .a b{color:var(--fg);font-weight:500}

/* ── проверка ── */
.verify{margin-top:36px;border:1px solid var(--border);border-radius:var(--r-panel);overflow:hidden}
.vrow{display:flex;gap:18px;padding:18px 22px;border-bottom:1px solid var(--border);background:var(--surface)}
.vrow:last-child{border-bottom:0}
/* две группы: «Проверите сами» (с командой прямо в строке) и «Подтверждаем документом» — разбор 2026-09-27 */
.vgh{font-size:var(--t-h3);line-height:1.3;letter-spacing:-.01em;margin:36px 0 0}
.vgh+.verify{margin-top:14px}
.vrow .vn{font-family:var(--mono);font-size:12px;color:var(--brand);flex:none;padding-top:2px}
.vrow .vt{font-size:15.5px;color:var(--fg-2);max-width:72ch}
.vrow .vt b{color:var(--fg);font-weight:500}
.vrow .vt code{font-family:var(--mono);font-size:12.5px;color:var(--brand-dim)}
.vrow .vl{display:block;margin-top:6px;font-size:var(--t-sm)}
.vrow .vl .sep{color:var(--fg-3);margin:0 .5em}
.vt a,.os .sum,.dl-foot a,.cta-note a{color:var(--fg);text-decoration:underline;text-decoration-color:var(--border-hover);
  text-underline-offset:3px;transition:text-decoration-color .15s var(--ease)}
.vt a,.dl-foot a,.cta-note a{padding-block:12px}
.vt a:hover,.os .sum:hover,.dl-foot a:hover,.cta-note a:hover{text-decoration-color:var(--brand)}

/* ── загрузка ── */
.os-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;margin-top:22px}
@media(max-width:760px){.os-grid{grid-template-columns:minmax(0,1fr)}}   /* minmax(0,…): длинное имя установщика не распирает колонку */   /* 760, а не 720: на 721–731 «Скачать .AppImage» ломалось в кнопке 40px */
.os{padding:22px;display:flex;flex-direction:column;gap:10px}
.os .oh{display:flex;align-items:center;gap:10px;font-weight:600;font-family:var(--disp);font-size:var(--t-h3);line-height:1.3;letter-spacing:-.01em}
.os p{font-size:var(--t-sm);color:var(--fg-3);max-width:70ch}
.os .first{font-size:var(--t-xs);color:var(--fg-3);line-height:1.5;border-left:1px solid var(--border-stronger);padding-left:12px}
.os .first code{font-family:var(--mono);font-size:12px;color:var(--fg-2);white-space:nowrap}
/* проверка файла до запуска (разбор 2026-09-27): команда — отдельной плашкой, выделяется целиком одним щелчком;
   переносится только по пробелам (самый длинный токен ~27 знаков входит в карточку от 320px), вбок не прокручивается */
.os .chk{font-size:var(--t-xs);color:var(--fg-3);line-height:1.5}
.os .chk code{display:block;margin-top:5px;padding:6px 9px;font-family:var(--mono);font-size:12px;line-height:1.5;color:var(--fg-2);
  background:var(--bg);border:1px solid var(--border);border-radius:6px;overflow-wrap:anywhere;user-select:all;-webkit-user-select:all}
.os .chk .nw{white-space:nowrap}   /* имя файла и ключ не рвутся по дефису; при копировании дефис остаётся обычным ASCII */
/* имя установщика Windows «.\NexTerm-<версия>-windows-x64-setup.exe» (38 знаков) шире карточки и на 320, и в три колонки на 761–1000 — рвётся только по <wbr>: версия и хвост «windows-x64-setup.exe» (~150px) — в .nw, по дефису не переносятся */
.os .acts{margin-top:auto;padding-top:8px;display:flex;flex-direction:column;gap:4px}
.os .btns{display:flex;gap:10px;flex-wrap:wrap}
.os .btn{flex:1 1 auto;justify-content:center;margin:0}
.os .sum{display:inline-flex;flex-wrap:wrap;align-items:center;align-self:flex-start;min-height:40px;column-gap:8px;
  font-family:var(--mono);font-size:12px;color:var(--fg-2)}
.os .sum .f{color:var(--fg-3)}
.dl-foot{margin-top:18px;font-size:var(--t-sm);color:var(--fg-3);max-width:70ch}
/* без JS release.js не прочитан: есть ли в бакете файлы сумм, неизвестно — сверка, ссылки на суммы и фраза о них скрыты
   (с JS их прячет app.js, пока REL.sums не true). Класс .js на <html> ставит boot.js */
html:not(.js) .os .chk,html:not(.js) .os .sum,html:not(.js) .dl-foot .sumtxt{display:none}
/* ── загрузка с телефона: сборки — для компьютера; блок виден только на узких или touch-экранах и только с JS ── */
.dl-phone{display:none;margin-top:22px}
@media (max-width:720px),(hover:none) and (pointer:coarse){html.js .dl-phone{display:block}}
.dl-phone .inner{height:auto;padding:18px 20px 16px}   /* конверт вне грида: глобальное height:100% в quirks-режиме резолвится в высоту окна */
.dl-phone p{font-size:var(--t-sm);color:var(--fg-2);max-width:52ch}
.dl-phone-btns{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px}
.dl-phone-btns .btn{flex:1 1 auto;justify-content:center;height:auto;min-height:40px;padding-block:8px;text-align:center}   /* на 320–364 подпись в две строки — кнопка растёт, а не зажимает её */
.dl-phone .btn.ok{color:var(--brand);border-color:rgba(62,207,142,.45)}
.dl-msg{font-family:var(--mono);font-size:12px;color:var(--fg-3);min-height:18px;margin-top:10px;overflow-wrap:anywhere}

/* ── подвал: сведения о владельце сайта и правовые оговорки:
   · сведения о владельце сайта — ч. 2 ст. 10 149-ФЗ: наименование, место нахождения и адрес, e-mail для заявлений
     по ст. 15.7 (о нарушении авторских прав). Это обязательно для любого сайта;
   · сайт не использует cookies, счётчики и сторонние сервисы и не собирает персональные данные — поэтому ни баннера,
     ни политики обработки ПД сейчас не нужно (понадобятся вместе с формой или учётными записями, 152-ФЗ);
   · не публичная оферта (ст. 437 ГК РФ); чужие товарные знаки — только для обозначения совместимости;
   · ИП не открыт — незаполненные поля помечены в разметке меткой, которую блокирует scripts/check.py (выката с ними нет).
     Лицензионное соглашение и строка реестра российского ПО — когда появятся;
   · намеренно нет слов «средство защиты информации», сертификатов и лицензий ФСБ/ФСТЭК (ADR-051 §3).
   Подвал простых страниц (/security/, /docs/install/) — одна строка в footer>.wrap>p; правила .ft и .ft-* его не касаются. */
/* ПОДВАЛ v3 (владелец 2026-09-28: «футер переделай, выглядит ужасно»). Было: подпись висела слева в пустоте без знака, колонки
   ссылок жались к правому краю, заголовки строчными («продукт»), правовая часть — стена из пяти мелких абзацев, заглушки в
   пунктирных рамках читались как ошибки вёрстки, страница обрывалась без нижней строки.
   Стало три яруса: (1) знак и имя, как в шапке, с подписью — слева; колонки «Продукт» и «Безопасность» — справа;
   (2) сведения о владельце сайта — таблицей «поле — значение» (ч. 2 ст. 10 149-ФЗ: наименование, адрес, почта), рядом —
   короткие оговорки; (3) нижняя строка: © и «Наверх». Содержание правовой части прежнее, изменилась только подача.
   Заглушки .ft-ph — спокойная плашка surface-2 вместо пунктира; с ними на боевой сайт не выходим. Почта станет ссылкой
   mailto, когда появится адрес (пустой mailto: открывал пустое письмо). */
footer{padding:48px 0 44px;color:var(--fg-3);font-size:var(--t-sm)}   /* простой подвал /security/ и /docs/install/ */
footer.ft{padding:64px 0 24px}   /* подвал v3 главной */
.ft-top{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,6fr);column-gap:clamp(40px,6vw,96px);row-gap:36px;align-items:start}   /* та же сетка, что у .ft-legal: ссылки стоят на одной вертикали с оговорками */
.ft-brand .brand{display:inline-flex;color:var(--fg)}   /* подвал приглушает текст — имя держит цвет шапки */
.ft-brand p{margin-top:14px;max-width:34ch;color:var(--fg-2);line-height:1.6}
.ft-links{display:grid;grid-template-columns:repeat(2,max-content);column-gap:clamp(40px,6vw,96px)}
.ft-h{font:600 13.5px/1.4 var(--sans);color:var(--fg);margin:0 0 8px}
.ft-links a{display:block;width:fit-content;max-width:100%;padding:5px 0;line-height:1.5;color:var(--fg-3);transition:color .15s var(--ease)}
.ft-links a:hover{color:var(--fg)}
@media(pointer:coarse){.ft-links a{padding:9.5px 0}}   /* палец: 21 + 19 = 40px */
.ft-legal{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,6fr);gap:24px clamp(40px,6vw,96px);margin-top:52px;padding-top:28px;
  border-top:1px solid var(--border);font-size:var(--t-xs);line-height:1.6}
.ft-owner{margin:0;display:grid;gap:10px;align-content:start}
.ft-owner>div{display:grid;grid-template-columns:8.5em minmax(0,1fr);column-gap:14px}
.ft-owner dt{color:var(--fg-3)}
.ft-owner dd{margin:0;color:var(--fg-2)}
.ft-notes{display:grid;gap:8px;align-content:start;color:var(--fg-3)}
.ft-legal>.ft-notes:only-child{grid-column:1/-1}   /* пока сведений о владельце нет (2026-10-06) — оговорки на всю ширину */
.ft-notes p{max-width:36em}   /* em, а не ch: ch — ширина цифры «0», кириллица на ch даёт на 15–25% длиннее строку */
.ft-ph{display:inline-block;padding:0 7px;border-radius:var(--r-xs);background:var(--surface-2);box-shadow:inset 0 0 0 1px var(--border);
  color:var(--fg-2);white-space:nowrap}
.ft-bottom{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:4px 16px;margin-top:28px;padding-top:16px;
  border-top:1px solid var(--border);font-size:var(--t-xs)}
.ft-top+.ft-bottom{margin-top:52px}   /* на случай, если правового блока нет: нижняя строка сразу под колонками */
.ft-up{display:inline-flex;align-items:center;gap:6px;min-height:40px;color:var(--fg-3);transition:color .15s var(--ease)}
.ft-up:hover{color:var(--fg)}
@media(max-width:860px){.ft-legal{grid-template-columns:1fr;margin-top:44px}}
@media(max-width:860px){.ft-top{grid-template-columns:1fr}}
@media(max-width:640px){.ft-links{grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:24px}}   /* minmax(0,…) и max-width:100% у ссылки — длинная «Сетевые обращения клиента» переносится, а не распирает колонку на 320 */
@media(max-width:420px){.ft-owner>div{grid-template-columns:1fr;row-gap:2px}}

/* reveal — точечный, не ковровый; без JS контент виден всегда */
.io{transition:opacity .6s var(--ease),transform .6s var(--ease)}
html.js .io{opacity:0;transform:translateY(10px)}
html.js .io.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){html.js .io{opacity:1;transform:none;transition:none}}

/* reduced-motion: честные конечные состояния вместо вечно пустых визуалов */
@media(prefers-reduced-motion:reduce){
  .sftp .f.mv{animation:none}
}

/* узкие экраны: навигация сжимается; схемы перестраиваются (см. «СХЕМЫ НЕ ВЫЛЕЗАЮТ») */
/* шапка сжимается ступенями: знак и имя уступают место ссылкам и кнопке */
@media(max-width:860px){.brand{font-size:17px}.brand svg{width:26px;height:26px}}
@media(max-width:640px){
  .navlinks{display:flex;gap:12px;margin-left:0;min-width:0}
  .brand{flex:none;font-size:16px;gap:8px}
  .brand svg{width:24px;height:24px}
  .navlinks a{font-size:12.5px}
  .nav-right .btn{height:40px;padding:0 14px;font-size:13.5px}
  .nav-right .btn .os-l{display:none}
}
.nav-right .btn{white-space:nowrap}
@media(max-width:700px){.nav-right .btn .os-l{display:none}}   /* на 641–695 «Скачать для Windows» ломалось на две строки в плашке 40px */
@media(max-width:520px){nav .wrap{gap:14px}.navlinks{display:none}.mnav{display:block}
  .brand{font-size:15.5px}.brand svg{width:22px;height:22px}}   /* компактное меню и кнопка рядом: на 390 запас ~10px, знак остаётся прежним */   /* до 496 три пункта (245px) не помещаются рядом с кнопкой, до 519 стоят к ней вплотную */
@media(max-width:480px){
  .env-svg{min-width:320px}
  .scx-viz .inner{padding-left:10px;padding-right:10px}   /* 320 + 2×10 = 340: на 390 схема входит без прокрутки */
  .how>.txt,.how>.hviz{min-width:0}
}
@media(max-width:380px){.mnav summary .lbl{display:none}}   /* совсем узко: только иконка, имя несёт aria-label. 380, а не 360: на 361–362 кнопка «Скачать» заходила за поле */
/* СХЕМЫ НЕ ВЫЛЕЗАЮТ (владелец 2026-09-27). Решает ширина самой панели (контейнер hviz), а не окна: на ≥861 панель —
   6/11 колонки у схем 01/03/05 и 5/11 у 02/04 (.how.flip), и тесно ей бывает и на планшете, и на телефоне.
   Прежде схема держала min-width и панель прокручивалась.
   · веер 03: широкая схема — только в панели от 468px, где её подписи не мельче 13px (13 ед. × 468/468); уже — вторая
     раскладка, «дерево»: ключ хранилища слева, пять записей столбиком справа (подписи 12–14.5px). Один порог 468,
     а не 398: при 398 схема прыгала дерево → широкая → дерево на 466–492 (поле панели ≤480 — 10px, шире — 22px),
     и подписи широкой там были на грани, 11px. Анимация та же: классы и порядок элементов те же;
   · конверт 02: уже 340px — кадр по содержимому (x 23…317, y 22…188 из 340×210): поля вокруг рамки уходят. Рамка кадра
     не шире 294px — так подписи не крупнее 13px и размер конверта у порога не прыгает; на 320px (панель 250) — 11.05px.
     Тряска «без пароля» (±4 ед.) в кадр входит: рамка — от 30 до 310;
   · подпись под конвертом держит высоту под самую длинную из трёх фраз (74 знака), чтобы кнопки не прыгали под пальцем. */
.hviz .inner{container:hviz/inline-size}
.fan-svg.fan-n{display:none;min-width:0;max-width:300px}
@container hviz (max-width:467.98px){
  .fan-svg.fan-w{display:none}
  .fan-svg.fan-n{display:block}
}
@container hviz (max-width:339.98px){
  .env-frame{overflow:hidden;max-width:294px;margin:0 auto}
  .env-svg{width:calc(100% * 340 / 294);max-width:none;min-width:0;
    margin:calc(100% * -22 / 294) 0 calc(100% * -22 / 294) calc(100% * -23 / 294)}
}
@container hviz (max-width:559.98px){.env-cap{min-height:3.2em}}   /* две строки по 1.6em */
@container hviz (max-width:301.98px){.env-cap{min-height:4.8em}}   /* три строки */

/* ── браузерные поверхности: скроллбары, табличные цифры, подчёркивания ── */
.hviz .inner{scrollbar-width:thin;scrollbar-color:var(--surface-3) transparent}
/* ── подсказка прокрутки: fade-край справа + моно-подпись «→ прокрутите»; JS показывает их только при переполнении
   (.can — есть что прокручивать вправо, .hint — ещё не прокручивали). С 2026-09-27 это страховка: схемы
   перестраиваются и не переполняются ни на одной ширине от 320px; подсказка всплывёт, только если что-то сломают ── */
.scx{position:relative}
.scx::after{content:"";position:absolute;top:1px;right:1px;bottom:1px;width:56px;pointer-events:none;opacity:0;
  border-radius:0 11px 11px 0;background:linear-gradient(90deg,rgba(24,26,25,0),var(--surface) 78%);transition:opacity .2s var(--ease)}   /* 11 = 12 − 1px конверта панели: та же геометрия вложенности */
.scx.can::after{opacity:1}
.scx-hint{display:none;position:absolute;right:12px;top:7px;pointer-events:none;        /* правый верх: содержимое не накрывается */
  font:11.5px/1 var(--mono);letter-spacing:.02em;color:var(--fg-2);background:var(--surface-2);
  border:1px solid var(--border-strong);border-radius:999px;padding:5px 10px}
.panel.scx .scx-hint{top:12px}
.scx.hint .scx-hint{display:block}
[hidden]{display:none!important}

/* ── конверт, второй акт: попытка вскрытия без пароля ── */
@keyframes deny{0%,100%{transform:none}20%{transform:translateX(-4px)}40%{transform:translateX(4px)}60%{transform:translateX(-3px)}80%{transform:translateX(3px)}}
.denying .env-outer{animation:deny .5s var(--ease)}
.denying .env-outline,.denying .env-flap{stroke:var(--danger)!important;transition:stroke .2s}
.denying .env-deny{opacity:1}
@keyframes envKeyDeny{0%{opacity:1}18%,78%{opacity:.35}100%{opacity:1}}
.denying .env-key{animation:envKeyDeny 1.8s var(--ease)}
.denying .env-key rect{stroke:var(--danger);transition:stroke .2s}
.env-deny{opacity:0;transition:opacity .3s}
.env-btns{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:14px}
.env-btns .btn{margin:0}
@media(prefers-reduced-motion:reduce){.denying .env-outer,.denying .env-key,.resealing .env-key,.resealing .env-outline,.resealing .env-kek,.resealing .env-stamp{animation:none}}

/* ── кнопки загрузки до первого релиза: не ссылки, приглушены ── */
.os .btn[aria-disabled="true"]{flex:1 1 auto;justify-content:center;color:var(--fg-3);cursor:default;pointer-events:none}
