homepage/public/assets/zapret-moe/home.css
loop-uh 6d8aefc21b Homepage: "Где сайт открывается" section — the git and wiki addresses with charts and a check from your own device
Replaces the status bar that was pinned to the top of every page. The section shows:
- how many addresses open from Russia right now and the working address;
- per address, a 24-hour column chart of availability from Russia, with tooltips and a table view;
- a "Проверить с моего устройства" button: the browser tries every address itself, and a packet
  runs along each address's line to it or gets dropped. The result is not sent anywhere.
The widget is the shared module /_sites/mirrors-widget.js (sites.js loads it when the page has
a [data-zapret-mirrors] slot); the data is /_sites/mirrors.json from zapret-mirror-manager. The
wiki main page has the same widget. Colors and fonts are passed in through --zm-*.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:03:10 -04:00

5220 lines
111 KiB
CSS
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Главная git.zapret.moe.
Файл подключается только из templates/home.tmpl, поэтому на остальные страницы
Forgejo не влияет. Всё общее для сайта — в site.css. */
@font-face {
font-family: "Unbounded";
font-style: normal;
font-weight: 200 900;
font-display: swap;
src: url("fonts/unbounded-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: "Unbounded";
font-style: normal;
font-weight: 200 900;
font-display: swap;
src: url("fonts/unbounded-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Onest объявлен в site.css — он нужен на всех страницах. */
@property --zang {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}
/* ── Окружение страницы: тёмные шапка и подвал Forgejo ─────────────── */
body {
background: #07080c;
}
#navbar {
background: rgba(7, 8, 12, 0.86);
backdrop-filter: blur(12px);
}
#navbar .item,
#navbar a.item {
color: #cfccc5;
}
#navbar .item.active,
#navbar a.item.active {
color: #fff;
background: none;
box-shadow: inset 0 -2px 0 #5b7fff;
}
#navbar .item:hover,
#navbar a.item:hover {
color: #fff;
background: rgba(242, 238, 230, 0.06);
}
/* у вошедших «+» и меню профиля — не .item, а <details class="dropdown"> */
#navbar details.dropdown > summary {
color: #cfccc5;
}
#navbar details.dropdown > summary:hover,
#navbar details.dropdown[open] > summary {
color: #fff;
background: rgba(242, 238, 230, 0.06);
}
.page-footer {
color: #6f6d69;
background: #07080c;
border-top: 1px solid rgba(242, 238, 230, 0.12);
}
.page-footer a,
.page-footer .item {
color: #a9a69f;
}
.zpm-wikibar {
background: #07080c;
border-top-color: rgba(242, 238, 230, 0.12);
}
.zpm-wikibar-label {
color: #6f6d69;
}
.zpm-wikibar a {
color: #a9a69f;
}
.zpm-wikibar a:hover {
color: #5b7fff;
}
/* ── Основа ─────────────────────────────────────────────────────────── */
.page-content.home.zpm-home {
/* тушь, бумага и одна краска. Свечений и переливов в интерфейсе нет:
цвет несут арты, а не обводки. */
--bg: #07080c;
--bg2: #0d0f16;
--bg3: #161925;
--ink: #f2eee6;
--mut: #a9a69f;
--dim: #6f6d69;
--acc: #5b7fff;
--red: #ff3b5c;
--gold: #e9bd55;
--line: rgba(242, 238, 230, 0.12);
--line2: rgba(242, 238, 230, 0.28);
--disp: "Unbounded", "Onest", system-ui, sans-serif;
--txt: "Onest", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--mono: ui-monospace, "JetBrains Mono", "Cascadia Code", "SF Mono", Consolas, monospace;
width: 100%;
margin: 0;
padding: 0;
overflow-x: clip;
color: var(--ink);
font-family: var(--txt);
font-size: 16px;
line-height: 1.6;
background: var(--bg);
}
.zpm-home *,
.zpm-home *::before,
.zpm-home *::after {
box-sizing: border-box;
}
.zpm-home a {
color: inherit;
text-decoration: none;
}
.zpm-home :where(img) {
display: block;
max-width: 100%;
height: auto;
}
.zpm-home ::selection {
color: #fff;
background: rgba(155, 123, 255, 0.5);
}
.zpm-home :is(a, button):focus-visible {
outline: 3px solid var(--acc);
outline-offset: 3px;
}
.zpm-home :where(h1, h2, h3) {
margin: 0;
color: var(--ink);
font-family: var(--disp);
font-weight: 700;
letter-spacing: -0.02em;
}
.zpm-home :where(p) {
margin: 0;
}
.zs {
width: min(1180px, calc(100% - 40px));
margin-inline: auto;
}
/* надзаголовок: пакет бежит по проводу */
.zeb {
display: inline-flex;
align-items: center;
gap: 10px;
margin-bottom: 14px;
color: var(--acc);
font-family: var(--mono);
font-size: 13px;
letter-spacing: 0.04em;
}
.zeb::before {
width: 28px;
height: 7px;
content: "";
background:
radial-gradient(circle, var(--acc) 0 3px, transparent 3.5px) no-repeat -7px 0 / 7px 7px,
linear-gradient(rgba(91, 127, 255, 0.35), rgba(91, 127, 255, 0.35)) no-repeat 0 50% / 100% 1px;
animation: zeb-run 2.4s ease-in-out infinite;
}
@keyframes zeb-run {
0% { background-position: -7px 0, 0 50%; }
60%, 100% { background-position: 28px 0, 0 50%; }
}
.zsec-head {
display: grid;
gap: 0;
max-width: 720px;
margin-bottom: 44px;
}
.zsec-head h2 {
font-size: clamp(28px, 4.2vw, 48px);
line-height: 1.08;
}
.zsec-note {
margin-top: 16px;
color: var(--mut);
font-size: 17px;
}
.zpm-home .zmore {
margin-top: 18px;
color: var(--acc);
font-family: var(--mono);
font-size: 14px;
}
.zmore:hover {
text-decoration: underline;
text-underline-offset: 4px;
}
/* ── Кнопки ─────────────────────────────────────────────────────────── */
/* Главное действие — залитая кнопка, всё остальное — ссылка со стрелкой:
обводок и пилюль на странице нет. */
.zb {
position: relative;
display: inline-flex;
align-items: center;
gap: 8px;
min-height: 48px;
padding: 12px 0;
color: var(--ink);
font-family: var(--txt);
font-size: 15px;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
cursor: pointer;
border: 0;
background: none;
transition: color 0.2s;
}
.zb:not(.zb-main)::after {
color: var(--acc);
content: "→";
transition: transform 0.2s;
}
.zpm-home .zb:not(.zb-main):hover {
color: var(--acc);
}
.zb:not(.zb-main):hover::after {
transform: translateX(4px);
}
.zb svg {
width: 18px;
height: 18px;
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
transition: transform 0.2s;
}
.zb:hover svg {
transform: translateX(3px);
}
.zb-main {
padding: 12px 24px;
color: var(--bg);
border-radius: 6px;
background: var(--ink);
transition: background 0.2s;
}
.zpm-home .zb-main,
.zpm-home .zb-main:hover {
color: var(--bg);
}
.zb-main:hover {
background: #fff;
}
.zb-sm {
min-height: 40px;
font-size: 14px;
}
.zb-main.zb-sm {
padding: 9px 18px;
}
/* ═══════════════════════════════════════════════════════════════════
Заставка-презентация
═══════════════════════════════════════════════════════════════════ */
/* прокрутку блокирует только сам home.js: если он не загрузился, страница листается */
html.zpm-intro-lock,
html.zpm-intro-lock body {
overflow: hidden;
}
/* страховка: если скрипт не запустился, заставка не должна закрыть сайт */
/* прогресс, как у сторис */
/* подписи */
/* 6–7: полёт Запрет-тян мимо проектов */
/* карточка выплывает из глубины, замирает рядом с Запрет-тян и улетает за камеру */
/* 8: год в цифрах */
/* ── сцена: базовые состояния ── */
/* слой с персонажами: его положение считает home.js так, чтобы он совпадал с SVG-сценой */
/* края кадра растворяются в темноте. Раньше это была mask-image, но маска
на контейнере с анимированными слоями заставляла браузер заново растрировать
всю сцену каждый кадр. Статичная виньетка поверх выглядит так же и ничего не стоит. */
/* звёздная пыль: два слоя точек-теней, мерцают только прозрачностью (видеокарта) */
.zi-dust2 {
position: absolute;
inset: 0;
pointer-events: none;
}
.zi-dust2 i {
position: absolute;
top: 0;
left: 0;
width: 2px;
height: 2px;
border-radius: 50%;
box-shadow: 9vw 13vh #9bb4ff, 19vw 29vh #9bb4ff, 33vw 10vh #9bb4ff, 68vw 16vh #9bb4ff, 83vw 9vh #9bb4ff, 92vw 33vh #9bb4ff,
14vw 47vh #9bb4ff, 87vw 51vh #9bb4ff, 43vw 84vh #9bb4ff, 63vw 91vh #9bb4ff, 24vw 91vh #9bb4ff, 78vw 84vh #9bb4ff;
opacity: 0.4;
will-change: opacity;
animation: zi-twinkle 3s ease-in-out infinite alternate;
}
.zi-dust2 i + i {
box-shadow: 5vw 70vh #cfd9ff, 27vw 62vh #cfd9ff, 55vw 5vh #cfd9ff, 72vw 40vh #cfd9ff, 96vw 72vh #cfd9ff, 38vw 30vh #cfd9ff,
58vw 58vh #cfd9ff, 12vw 24vh #cfd9ff, 90vw 18vh #cfd9ff, 48vw 96vh #cfd9ff;
animation-delay: -1.5s;
}
@keyframes zi-twinkle {
to { opacity: 0.08; }
}
/* ── шаг 1: интернет ── */
/* ── шаг 2: РКН-тян выходит из тьмы ── */
/* ── шаг 3: смотрит в каждый пакет ── */
/* ── шаг 4: фейк летит ей в лицо, она хватает пустоту ── */
/* ── шаг 5: РКН-тян глючит и исчезает, влетает Запрет-тян ── */
/* ТСПУ разваливается: половинки разлетаются и полностью исчезают */
/* лицо Запрет-тян в круге героя полёта */
/* прогресс-полоски: текущая заполняется, пройденные — полные */
/* ═══════════════════════════════════════════════════════════════════
Шапка
═══════════════════════════════════════════════════════════════════ */
.zh {
position: relative;
padding-top: clamp(48px, 7vw, 96px);
}
.zh-grid {
display: grid;
grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
gap: clamp(32px, 5vw, 72px);
align-items: center;
}
.zh-kicker {
display: inline-flex;
align-items: center;
gap: 10px;
margin-bottom: 26px;
color: #a9a69f;
font-size: 14px;
}
.zh-live {
position: relative;
width: 9px;
height: 9px;
border-radius: 50%;
background: #37e39a;
}
.zh-live::after {
position: absolute;
inset: -5px;
content: "";
border: 1px solid #37e39a;
border-radius: 50%;
animation: zh-ping 2s ease-out infinite;
}
@keyframes zh-ping {
from { opacity: 1; transform: scale(0.4); }
to { opacity: 0; transform: scale(1.6); }
}
.zh h1 {
font-size: clamp(38px, 6.2vw, 82px);
font-weight: 800;
line-height: 1.02;
letter-spacing: -0.035em;
}
/* ── «Интернет должен быть свободным»: сцена при открытии ──────────────
0.15–0.45 с — слова выезжают из-под маски
0.6–1.6 с — буквы «свободным» падают по одной
1.5–2.3 с — РКН вешает цепь с замком, буквы дрожат
2.35 с — искры, замок раскрывается и падает, цепь рвётся
2.5–3.1 с — буквы подпрыгивают волной, рисуется подчёркивание
дальше — по буквам течёт градиент, иногда пробегает блик */
.zh-w {
display: inline-block;
margin-bottom: -0.16em;
padding-bottom: 0.16em;
overflow: hidden;
vertical-align: bottom;
}
.zh-w > span {
display: inline-block;
animation: zh-rise 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) calc(0.15s + var(--i) * 0.13s) both;
}
@keyframes zh-rise {
from { opacity: 0; transform: translateY(105%) rotate(4deg); }
}
.zh-free {
position: relative;
display: inline-block;
padding-bottom: 0.08em;
white-space: nowrap;
}
.zh-l {
display: inline-block;
color: var(--acc);
animation:
zh-drop 0.65s cubic-bezier(0.2, 0.9, 0.3, 1.35) calc(0.6s + var(--i) * 0.055s) both,
zh-shiver 0.5s linear calc(1.85s + var(--i) * 0.02s) both,
zh-jump 0.6s cubic-bezier(0.3, 0, 0.3, 1) calc(2.5s + var(--i) * 0.045s) both;
}
/* разные свойства трансформации — чтобы анимации складывались, а не перебивали друг друга */
@keyframes zh-drop {
from { opacity: 0; translate: 0 -0.9em; rotate: -18deg; }
60% { opacity: 1; }
}
@keyframes zh-shiver {
0%, 100% { rotate: 0deg; }
20% { rotate: -3deg; }
40% { rotate: 2.5deg; }
60% { rotate: -2deg; }
80% { rotate: 1.5deg; }
}
@keyframes zh-jump {
0%, 100% { transform: translateY(0) scale(1); }
35% { transform: translateY(-0.22em) scale(1.08, 0.94); }
70% { transform: translateY(0.02em) scale(0.97, 1.04); }
}
/* цепь: появляется слева направо, рвётся посередине */
.zh-chain {
position: absolute;
top: 46%;
left: -4%;
width: 108%;
height: 0.4em;
overflow: visible;
pointer-events: none;
clip-path: inset(-50% 100% -50% 0);
animation: zh-chain-in 0.4s cubic-bezier(0.4, 0, 0.2, 1) 1.5s forwards;
}
@keyframes zh-chain-in {
to { clip-path: inset(-50% 0 -50% 0); }
}
.zh-chain path {
fill: none;
stroke: #ff3b5c;
stroke-width: 7;
stroke-dasharray: 14 9;
stroke-linecap: round;
filter: drop-shadow(0 0 6px rgba(255, 59, 92, 0.85));
}
.zh-chain .zh-chain-b {
stroke: #ffc2cc;
stroke-width: 2.5;
stroke-dasharray: 9 14;
stroke-dashoffset: -11;
filter: none;
}
.zh-chain-l,
.zh-chain-r {
transform-box: fill-box;
animation: zh-cut 1s cubic-bezier(0.5, 0, 0.8, 0.4) 2.38s forwards;
}
.zh-chain-l {
transform-origin: 0% 50%;
}
.zh-chain-r {
transform-origin: 100% 50%;
animation-name: zh-cut-r;
}
@keyframes zh-cut {
0% { transform: none; opacity: 1; }
25% { transform: rotate(5deg); }
100% { transform: translateY(90px) rotate(28deg); opacity: 0; }
}
@keyframes zh-cut-r {
0% { transform: none; opacity: 1; }
25% { transform: rotate(-5deg); }
100% { transform: translateY(90px) rotate(-28deg); opacity: 0; }
}
/* навесной замок РКН */
.zh-lock {
position: absolute;
top: 46%;
left: 50%;
width: 0.46em;
opacity: 0;
pointer-events: none;
translate: -50% -38%;
animation:
zh-lock-in 0.45s cubic-bezier(0.2, 0.9, 0.3, 1.5) 1.6s both,
zh-lock-shake 0.45s linear 1.95s both,
zh-lock-fall 0.9s cubic-bezier(0.5, 0, 0.8, 0.5) 2.5s forwards;
}
.zh-lock svg {
display: block;
width: 100%;
overflow: visible;
filter: drop-shadow(0 0 10px rgba(255, 59, 92, 0.8));
}
.zh-lock rect {
fill: #2a0712;
stroke: #ff3b5c;
stroke-width: 3;
}
.zh-shackle {
fill: none;
stroke: #ffb3c0;
stroke-width: 4;
stroke-linecap: round;
transform-box: fill-box;
transform-origin: 100% 100%;
animation: zh-unlock 0.3s cubic-bezier(0.3, 1.6, 0.5, 1) 2.35s both;
}
.zh-key {
fill: none;
stroke: #ff6b83;
stroke-width: 3;
stroke-linecap: round;
}
@keyframes zh-lock-in {
0% { opacity: 0; scale: 0.2; rotate: -30deg; }
100% { opacity: 1; scale: 1; rotate: 0deg; }
}
@keyframes zh-lock-shake {
0%, 100% { rotate: 0deg; }
25% { rotate: -12deg; }
50% { rotate: 10deg; }
75% { rotate: -8deg; }
}
@keyframes zh-lock-fall {
0% { opacity: 1; transform: none; }
100% { opacity: 0; transform: translateY(1.4em) rotate(70deg); }
}
@keyframes zh-unlock {
from { transform: none; }
to { transform: translate(8%, -18%) rotate(38deg); }
}
/* искры от разрыва */
.zh-bits {
position: absolute;
top: 46%;
left: 50%;
width: 0;
height: 0;
pointer-events: none;
}
.zh-bits i {
position: absolute;
width: 0.09em;
height: 0.09em;
border-radius: 50%;
background: #fff3c4;
box-shadow: 0 0 8px 2px var(--gold);
opacity: 0;
animation: zh-bit 0.7s cubic-bezier(0.2, 0.7, 0.4, 1) 2.36s both;
}
.zh-bits i:nth-child(1) { --dx: -1.1em; --dy: -0.6em; }
.zh-bits i:nth-child(2) { --dx: 1.2em; --dy: -0.5em; }
.zh-bits i:nth-child(3) { --dx: -0.7em; --dy: 0.7em; }
.zh-bits i:nth-child(4) { --dx: 0.8em; --dy: 0.75em; }
.zh-bits i:nth-child(5) { --dx: -1.5em; --dy: 0.1em; animation-delay: 2.42s; }
.zh-bits i:nth-child(6) { --dx: 1.6em; --dy: 0.05em; animation-delay: 2.42s; }
.zh-bits i:nth-child(7) { --dx: 0.2em; --dy: -0.95em; animation-delay: 2.4s; }
.zh-bits i:nth-child(8) { --dx: -0.3em; --dy: 1em; animation-delay: 2.4s; }
@keyframes zh-bit {
0% { opacity: 0; transform: translate(0, 0) scale(1.6); }
4% { opacity: 1; transform: translate(0, 0) scale(1.6); }
100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(0.4); }
}
.zh-free::after {
position: absolute;
top: 46%;
left: 50%;
width: 1.3em;
height: 1.3em;
content: "";
border-radius: 50%;
background: radial-gradient(circle, #fff 0, var(--gold) 22%, rgba(255, 90, 60, 0.4) 45%, transparent 68%);
opacity: 0;
transform: translate(-50%, -50%);
animation: zh-spark 0.5s ease-out 2.33s 2;
pointer-events: none;
}
@keyframes zh-spark {
0% { opacity: 0; transform: translate(-50%, -50%) scale(0.2); }
30% { opacity: 1; }
100% { opacity: 0; transform: translate(-50%, -50%) scale(1.5); }
}
/* подчёркивание — без non-scaling-stroke: с ним Chrome рисует его только до середины */
.zh-under {
position: absolute;
bottom: -0.12em;
left: 0;
width: 100%;
height: 0.28em;
overflow: visible;
}
.zh-under path {
fill: none;
stroke: var(--acc);
stroke-width: 5;
stroke-linecap: round;
stroke-dasharray: 460;
stroke-dashoffset: 460;
animation: zh-underline 0.9s cubic-bezier(0.6, 0, 0.2, 1) 2.95s forwards;
}
@keyframes zh-underline {
to { stroke-dashoffset: 0; }
}
/* подзаголовок, бегущая строка, цифры, кнопки, картинка */
.zh-kicker {
animation: zh-in-left 0.7s cubic-bezier(0.2, 0.8, 0.2, 1) 0.05s both;
}
@keyframes zh-in-left {
from { opacity: 0; translate: -30px 0; }
}
.zh-lead,
.zh-ticker,
.zh-stats {
animation: zh-in-up 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) 1.15s both;
}
.zh-ticker { animation-delay: 1.35s; }
.zh-stats { animation-delay: 1.5s; }
@keyframes zh-in-up {
from { opacity: 0; translate: 0 18px; filter: blur(6px); }
}
.zh-actions > * {
animation: zh-pop 0.6s cubic-bezier(0.2, 0.9, 0.3, 1.4) calc(1.7s + var(--k, 0) * 0.1s) both;
}
.zh-actions > :nth-child(2) { --k: 1; }
.zh-actions > :nth-child(3) { --k: 2; }
@keyframes zh-pop {
from { opacity: 0; scale: 0.7; translate: 0 12px; }
}
.zh-art {
animation:
zh-art-in 1.2s cubic-bezier(0.2, 0.8, 0.2, 1) 0.35s both,
zh-float 7s ease-in-out 1.6s infinite;
}
@keyframes zh-art-in {
from { opacity: 0; translate: 80px 20px; rotate: 6deg; scale: 0.9; filter: blur(12px); }
}
.zh-ticker {
margin-top: 18px;
color: var(--mut);
font-size: clamp(15px, 1.4vw, 18px);
}
.zh-flip {
display: inline-grid;
vertical-align: bottom;
height: 1.45em;
overflow: hidden;
}
.zh-flip > span {
grid-area: 1 / 1;
color: var(--acc);
font-weight: 700;
opacity: 0;
animation: zh-flip 12s cubic-bezier(0.3, 0, 0.2, 1) infinite;
animation-delay: calc(var(--f) * 2s);
}
.zh-flip > span:nth-child(1) { --f: 0; }
.zh-flip > span:nth-child(2) { --f: 1; }
.zh-flip > span:nth-child(3) { --f: 2; }
.zh-flip > span:nth-child(4) { --f: 3; }
.zh-flip > span:nth-child(5) { --f: 4; }
.zh-flip > span:nth-child(6) { --f: 5; color: #37e39a; }
@keyframes zh-flip {
0% { opacity: 0; transform: translateY(100%); }
3%, 14% { opacity: 1; transform: none; }
17%, 100% { opacity: 0; transform: translateY(-100%); }
}
.zh-stats {
display: flex;
flex-wrap: wrap;
gap: 8px 22px;
margin-top: 14px;
color: var(--dim);
font: 13px var(--mono);
}
.zh-stats[hidden] {
display: none;
}
.zh-stats b {
color: var(--ink);
font: 700 15px var(--disp);
font-variant-numeric: tabular-nums;
}
/* пока идёт заставка, вся сцена шапки ждёт */
.zpm-intro-on .zh *,
.zpm-intro-on .zh *::before,
.zpm-intro-on .zh *::after {
animation-play-state: paused !important;
}
.zh-lead {
max-width: 560px;
margin-top: 22px;
color: var(--mut);
font-size: clamp(16px, 1.5vw, 19px);
line-height: 1.65;
}
.zh-actions {
display: flex;
flex-wrap: wrap;
gap: 4px 28px;
margin-top: 34px;
}
.zh-replay {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin: 22px 0 0;
color: var(--dim);
font: 500 14px var(--txt);
}
.zh-replay[hidden] {
display: none;
}
.zh-replay svg {
width: 14px;
height: 14px;
fill: currentColor;
}
.zh-replay button {
margin-left: 6px;
padding: 6px 0;
color: var(--mut);
font: 600 14px/1.2 var(--txt);
text-decoration: underline dotted;
text-underline-offset: 5px;
cursor: pointer;
border: 0;
background: none;
transition: color 0.2s;
}
.zh-replay button:hover {
color: var(--acc);
}
/* арт с Запрет-тян */
.zh-art {
position: relative;
margin: 0;
}
@keyframes zh-float {
50% { transform: translateY(-10px) rotate(0.6deg); }
}
/* арт без рамки: края растворяются в фоне страницы */
.zh-art-frame {
position: relative;
aspect-ratio: 1;
overflow: hidden;
-webkit-mask-image: linear-gradient(to right, transparent, #000 14%, #000 86%, transparent), linear-gradient(to bottom, transparent, #000 12%, #000 84%, transparent);
-webkit-mask-composite: source-in;
mask-image: linear-gradient(to right, transparent, #000 14%, #000 86%, transparent), linear-gradient(to bottom, transparent, #000 12%, #000 84%, transparent);
mask-composite: intersect;
}
.zh-art-frame img {
width: 100%;
height: 100%;
object-fit: cover;
}
.zh-art-fx {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.zh-eyes ellipse {
fill: #ff2b4f;
mix-blend-mode: screen;
filter: blur(3px);
animation: zh-eyes 3.2s ease-in-out infinite;
}
@keyframes zh-eyes {
0%, 100% { opacity: 0.25; }
45% { opacity: 0.9; }
50% { opacity: 0.1; }
55% { opacity: 0.85; }
}
.zh-sparks path {
fill: none;
stroke: var(--gold);
stroke-width: 2.5;
stroke-linecap: round;
stroke-dasharray: 10 60;
stroke-dashoffset: 10;
filter: drop-shadow(0 0 4px #ffb020);
animation: zh-spk 0.7s linear infinite;
}
.zh-sparks path:nth-child(2) { animation-delay: -0.12s; }
.zh-sparks path:nth-child(3) { animation-delay: -0.25s; }
.zh-sparks path:nth-child(4) { animation-delay: -0.4s; }
.zh-sparks path:nth-child(5) { animation-delay: -0.52s; }
.zh-sparks path:nth-child(6) { animation-delay: -0.6s; }
@keyframes zh-spk {
to { stroke-dashoffset: -60; }
}
.zh-scan {
stroke: rgba(91, 127, 255, 0.45);
stroke-width: 2;
animation: zh-scan 6s linear infinite;
}
@keyframes zh-scan {
from { transform: translateY(0); opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
to { transform: translateY(640px); opacity: 0; }
}
.zh-art figcaption {
margin-top: 14px;
color: var(--dim);
font: 13px var(--mono);
text-align: center;
}
/* ═══════════════════════════════════════════════════════════════════
Персонажи: слоёные риги РКН-тян и Запрет-тян (заставка и дуэль)
Координаты слоёв — в системе 1600×900, как у сцены заставки.
═══════════════════════════════════════════════════════════════════ */
.zrig {
position: relative;
width: 100%;
aspect-ratio: 16 / 9;
}
.zr-in {
position: absolute;
inset: 0;
transform-origin: 50% 100%;
animation: zr-breathe 4.2s ease-in-out infinite;
}
.zpm-home .zr-l,
.zx .zr-l {
position: absolute;
top: calc(var(--y) / 9 * 1%);
left: calc(var(--x) / 16 * 1%);
width: calc(var(--w) / 16 * 1%);
max-width: none;
height: calc(var(--h) / 9 * 1%);
transform-origin: var(--o, 50% 50%);
pointer-events: none;
user-select: none;
}
@keyframes zr-breathe {
0%, 100% { transform: translateY(0) scale(1); }
50% { transform: translateY(-0.6%) scale(1.008); }
}
/* контровой свет */
.zr-rim {
animation: zr-rim 2.8s ease-in-out infinite alternate;
}
.zr-rkn .zr-rim {
animation: zr-rim-rkn 3.4s linear infinite;
}
@keyframes zr-rim {
from { opacity: 0.12; }
to { opacity: 0.3; }
}
@keyframes zr-rim-rkn {
0%, 18%, 22%, 60%, 100% { opacity: 0.9; }
20% { opacity: 0.35; }
61% { opacity: 0.5; }
63% { opacity: 1; }
}
/* волосы */
/* всё, что анимируется у персонажей, — на своих слоях видеокарты:
анимируются только transform и opacity, без перерисовки */
.zr-hair,
.zr-hand,
.zr-in,
.zr-eye,
.zr-eye::after,
.zr-embers i,
.zr-sparks i {
will-change: transform, opacity;
}
.zr-rim {
will-change: opacity;
}
.zr-hair {
animation: zr-sway var(--sd, 4.2s) ease-in-out infinite alternate;
animation-delay: var(--sdl, 0s);
}
@keyframes zr-sway {
from { transform: rotate(var(--sa, -1.4deg)) skewX(var(--sk, 0deg)); }
to { transform: rotate(var(--sb, 1.2deg)) skewX(calc(var(--sk, 0deg) * -1)); }
}
.zr-zt .zr-hair-r { --sa: -2.2deg; --sb: 1.6deg; --sk: -1deg; --sd: 3.2s; }
.zr-zt .zr-hair-t { --sa: -3deg; --sb: 2.4deg; --sd: 2.4s; --sdl: -0.6s; }
.zr-zt .zr-hair-l { --sa: 1.8deg; --sb: -1.4deg; --sk: 0.8deg; --sd: 3.6s; --sdl: -1.2s; }
/* РКН-тян: руки — отдельные слои поверх основы без рук, поэтому их можно
поворачивать от плеча. Цикл: замах когтями вверх → удар к зрителю → отдача.
Арт обрезан краями кадра (левая кисть — слева, правая — сверху и справа):
левая рука поворачивается только по часовой, правая — против, и всегда с
ростом к зрителю, иначе срез заехал бы внутрь кадра. */
.zr-arm {
will-change: transform;
}
.zr-rkn .zr-arm-l {
animation: zr-claw-l 3.2s cubic-bezier(0.4, 0, 0.3, 1) infinite;
}
.zr-rkn .zr-arm-r {
animation: zr-claw-r 3.2s cubic-bezier(0.4, 0, 0.3, 1) -1.6s infinite;
}
@keyframes zr-claw-l {
0%, 100% { transform: rotate(1deg) scale(1.02); }
22% { transform: rotate(7deg) scale(1.06); animation-timing-function: cubic-bezier(0.6, 0, 0.9, 0.5); }
31% { transform: rotate(-2deg) scale(1.15); animation-timing-function: cubic-bezier(0.2, 0.8, 0.3, 1); }
40% { transform: rotate(-1deg) scale(1.11); }
58% { transform: rotate(2deg) scale(1.03); }
}
@keyframes zr-claw-r {
0%, 100% { transform: rotate(-1deg) scale(1.02); }
22% { transform: rotate(-7deg) scale(1.06); animation-timing-function: cubic-bezier(0.6, 0, 0.9, 0.5); }
31% { transform: rotate(2deg) scale(1.15); animation-timing-function: cubic-bezier(0.2, 0.8, 0.3, 1); }
40% { transform: rotate(1deg) scale(1.11); }
58% { transform: rotate(-2deg) scale(1.03); }
}
.zr-zt .zr-hand {
animation: zr-peace 1.15s ease-in-out infinite;
}
.zr-zt .zr-hand-r {
animation-delay: -0.57s;
}
@keyframes zr-peace {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
/* глаза */
.zr-eye {
position: absolute;
top: calc(var(--ey) / 9 * 1%);
left: calc(var(--ex) / 16 * 1%);
width: 6.5%;
aspect-ratio: 1;
border-radius: 50%;
background: radial-gradient(circle, #fff 0 4%, var(--ec) 12%, color-mix(in srgb, var(--ec) 40%, transparent) 32%, transparent 68%);
pointer-events: none;
transform: translate(-50%, -50%);
animation: zr-eye 2.2s ease-in-out infinite;
}
.zr-eye-1 {
animation-delay: -0.3s;
}
@keyframes zr-eye {
0%, 100% { opacity: 0.7; transform: translate(-50%, -50%) scale(0.95); }
50% { opacity: 1; transform: translate(-50%, -50%) scale(1.25); }
}
/* световой шлейф, как у светящихся глаз в аниме */
.zr-eye::after {
position: absolute;
top: 50%;
left: 50%;
width: 340%;
height: 12%;
content: "";
border-radius: 50%;
background: linear-gradient(90deg, transparent, var(--ec) 40%, #fff 50%, var(--ec) 60%, transparent);
opacity: 0;
transform: translate(-50%, -50%) scaleX(0);
animation: zr-streak 5.2s ease-out infinite;
}
.zr-zt .zr-eye::after {
width: 120%;
height: 120%;
background:
linear-gradient(90deg, transparent 44%, #fff 50%, transparent 56%),
linear-gradient(0deg, transparent 44%, #fff 50%, transparent 56%);
animation: zr-twinkle 3.1s ease-in-out infinite;
}
.zr-zt .zr-eye-1::after {
animation-delay: -1.5s;
}
@keyframes zr-streak {
0%, 78% { opacity: 0; transform: translate(-50%, -50%) scaleX(0); }
84% { opacity: 1; transform: translate(-50%, -50%) scaleX(1); }
100% { opacity: 0; transform: translate(-50%, -50%) scaleX(1.5); }
}
@keyframes zr-twinkle {
0%, 70%, 100% { opacity: 0; transform: translate(-50%, -50%) rotate(0) scale(0.3); }
80% { opacity: 1; transform: translate(-50%, -50%) rotate(45deg) scale(1); }
}
/* ── дуэль на главной ── */
.zd {
position: relative;
display: flex;
align-items: flex-end;
justify-content: center;
margin-top: clamp(40px, 6vw, 72px);
overflow: hidden;
background:
radial-gradient(38rem 24rem at 22% 62%, rgba(59, 130, 255, 0.24), transparent 70%),
radial-gradient(38rem 24rem at 78% 62%, rgba(255, 59, 92, 0.2), transparent 70%),
linear-gradient(180deg, #07080c, #070a18);
}
.zd {
display: block;
}
/* сцена 1600×700: бойцы в полный рост лицом друг к другу; координаты — в процентах */
.zd-stage {
position: relative;
z-index: 2;
aspect-ratio: 16 / 7;
}
.zf {
position: absolute;
transform-origin: 52% 97%;
transition: opacity 1.1s, transform 1.3s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.zf-zt {
z-index: 2;
}
.zf-in {
position: absolute;
inset: 0;
transform-origin: 52% 97%;
animation: zf-stance 1.6s ease-in-out infinite alternate;
}
.zf-rkn .zf-in {
animation-duration: 1.9s;
animation-delay: -0.7s;
}
@keyframes zf-stance {
from { transform: translateY(0) scale(1, 1); }
to { transform: translateY(0.8%) scale(1.005, 0.99); }
}
.zf-l {
position: absolute;
max-width: none;
pointer-events: none;
user-select: none;
will-change: transform;
}
/* волосы развеваются: наклон закреплён на линии среза, поэтому шов не двигается */
.zf-hair {
animation: zf-hair 2.3s ease-in-out infinite alternate;
}
.zf-rkn .zf-hair {
animation-duration: 2.7s;
animation-delay: -1.1s;
}
@keyframes zf-hair {
0% { transform: skewY(-1.4deg) scaleX(0.99); }
50% { transform: skewY(0.6deg) scaleX(1.02); }
100% { transform: skewY(1.6deg) scaleX(0.995); }
}
/* руки в стойке: лёгкое покачивание вокруг плеча; удары задаёт home.js */
.zf-arm0,
.zf-arm1 {
animation: zf-guard 1.6s ease-in-out infinite alternate;
}
.zf-arm1 {
animation-delay: -0.8s;
}
@keyframes zf-guard {
from { rotate: -2deg; }
to { rotate: 2.5deg; }
}
/* появление: выезжают с боков */
.zd-js .zf-zt {
opacity: 0;
transform: translateX(-30%);
}
.zd-js .zf-rkn {
opacity: 0;
transform: translateX(30%);
}
.zd-js.zd-on .zf {
opacity: 1;
transform: none;
}
/* низ сцены растворяется в фон секции */
.zd::before {
position: absolute;
right: 0;
bottom: 0;
left: 0;
z-index: 3;
height: 16%;
content: "";
pointer-events: none;
background: linear-gradient(to top, #060914, rgba(6, 9, 20, 0));
}
/* получила удар: вспышка и дрожь */
.zf-hit .zf-in {
animation: zf-hit 0.5s steps(1);
}
@keyframes zf-hit {
0% { transform: translateX(-1.5%); opacity: 0.55; }
20% { transform: translateX(1.5%); opacity: 1; }
40% { transform: translateX(-0.8%); opacity: 0.7; }
60%, 100% { transform: none; opacity: 1; }
}
@keyframes zd-float {
from { transform: translateY(0); }
to { transform: translateY(-2%); }
}
.zd-card {
position: absolute;
bottom: 7%;
z-index: 4;
display: grid;
gap: 2px;
max-width: 280px;
margin: 0;
text-shadow: 0 0 14px #07080c, 0 0 4px #07080c;
}
.zd-card b {
font: 700 18px var(--disp);
}
.zd-card span {
color: var(--mut);
font-size: 13.5px;
line-height: 1.4;
}
.zd-card-zt {
left: 4%;
}
.zd-card-zt b {
color: var(--acc);
}
.zd-card-rkn {
right: 4%;
text-align: right;
}
.zd-card-rkn b {
color: #ff6b83;
}
.zd-vs {
position: absolute;
top: 0;
bottom: 0;
left: 50%;
z-index: 1; /* разряд — позади бойцов; сами они сходятся в центре */
display: grid;
place-items: start center;
padding-top: 3%;
width: clamp(90px, 11vw, 170px);
transform: translateX(-50%);
pointer-events: none;
}
.zd-vs svg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.zd-glow,
.zd-bolt,
.zd-branch {
fill: none;
stroke-linejoin: round;
stroke-linecap: round;
vector-effect: non-scaling-stroke;
}
/* мягкий ореол — горит всегда */
.zd-glow {
stroke: rgba(160, 200, 255, 0.35);
stroke-width: 14;
filter: blur(6px);
animation: zd-hum 0.18s steps(2) infinite;
}
/* основной разряд — горит всегда и потрескивает */
.zd-bolt {
stroke: #f2f9ff;
stroke-width: 4;
filter: drop-shadow(0 0 4px #fff) drop-shadow(0 0 10px #5b7fff) drop-shadow(0 0 22px #ff3b5c);
}
.zd-bolt-a {
animation: zd-crackle 0.9s steps(1) infinite;
}
/* второй разряд и ответвления — короткими вспышками */
.zd-bolt-b,
.zd-branch {
opacity: 0;
animation: zd-bolt 1.9s steps(1) infinite;
}
.zd-branch {
stroke: #dff4ff;
stroke-width: 2.5;
filter: drop-shadow(0 0 6px #5b7fff);
}
.zd-bolt-b { animation-delay: -0.95s; }
.zd-br-2 { animation-delay: -0.5s; }
.zd-br-3 { animation-delay: -1.3s; }
.zd-br-4 { animation-delay: -0.2s; }
@keyframes zd-hum {
50% { opacity: 0.7; }
}
@keyframes zd-crackle {
0%, 100% { opacity: 1; }
30% { opacity: 0.55; }
34% { opacity: 1; }
70% { opacity: 0.75; }
}
@keyframes zd-bolt {
0%, 60%, 100% { opacity: 0; }
62%, 70% { opacity: 1; }
66% { opacity: 0.2; }
}
/* живая молния на canvas (home.js); SVG остаётся запасным вариантом без JS */
.zd-canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
display: none;
}
.zd-live .zd-canvas {
display: block;
}
.zd-live .zd-vs svg {
display: none;
}
/* в момент столкновения молния вспыхивает во всю силу */
.zd-on .zd-vs svg {
animation: zd-surge 6s ease-out 1.5s infinite;
}
@keyframes zd-surge {
0%, 86%, 100% { filter: none; transform: scaleX(1); }
88% { filter: brightness(1.8); transform: scaleX(1.6); }
92% { filter: brightness(1.2); transform: scaleX(1.1); }
}
.zd-vs span {
position: relative;
font: 900 clamp(28px, 4.2vw, 60px) var(--disp);
letter-spacing: -0.04em;
color: var(--ink);
animation: zd-vs 1.6s ease-in-out infinite alternate;
}
@keyframes zd-vs {
to { transform: scale(1.08); }
}
@media (max-width: 760px) {
/* на телефоне сцена шире экрана: по краям обрезаются только кончики волос */
.zd-stage {
width: 170%;
margin-left: -35%;
}
/* подписи — под сценой в две колонки, чтобы не закрывать бойцов */
.zd {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
padding-bottom: 12px;
}
.zd-stage {
grid-column: 1 / -1;
}
.zd-card {
position: relative;
right: auto;
bottom: auto;
left: auto;
max-width: none;
margin: 0 16px;
}
.zd-card b {
font-size: 15px;
}
.zd-card span {
font-size: 12px;
}
.zd::before {
display: none;
}
}
/* ── Живость персонажей ─────────────────────────────────────────────────
--px/--py (−1…1) выставляет home.js по положению курсора: слои сдвигаются
на разную глубину — волосы сзади, руки ближе всего к зрителю. */
.zrig {
--px: 0;
--py: 0;
}
/* Персонаж сдвигается целиком: руки, пряди, контур и глаза вырезаны из основы,
и любой их сдвиг относительно неё выдаёт копию под слоем — двоение и шов на
запястье. Проценты translate считаются от самого слоя, поэтому у слоёв
разного размера «одинаковый» сдвиг расходился — сдвигаем все слои на одно
и то же расстояние в единицах ширины рига (cqw). translate самого .zr-in
и .zrig заняты подпрыгиванием и столкновением в дуэли. */
.zrig {
container-type: inline-size;
}
.zr-in > * {
translate: calc(var(--px) * 0.8cqw) calc(var(--py) * 0.45cqw);
}
/* РКН-тян: срывы сигнала */
.zr-gl {
opacity: 0;
pointer-events: none;
will-change: transform, clip-path, opacity;
}
.zr-gl-a {
animation: zr-glitch-a 5.3s steps(1) infinite;
}
.zr-gl-b {
animation: zr-glitch-b 5.3s steps(1) infinite;
}
@keyframes zr-glitch-a {
0%, 70%, 100% { opacity: 0; clip-path: inset(0); transform: none; }
71% { opacity: 0.85; clip-path: inset(18% 0 62% 0); transform: translateX(-2.4%); }
73% { opacity: 0.85; clip-path: inset(44% 0 38% 0); transform: translateX(3%); }
75% { opacity: 0.7; clip-path: inset(66% 0 20% 0); transform: translateX(-1.4%); }
77% { opacity: 0.85; clip-path: inset(30% 0 55% 0); transform: translateX(1.8%); }
79% { opacity: 0; }
}
@keyframes zr-glitch-b {
0%, 71%, 100% { opacity: 0; clip-path: inset(0); transform: none; }
72% { opacity: 0.75; clip-path: inset(20% 0 60% 0); transform: translateX(2.2%); }
74% { opacity: 0.75; clip-path: inset(46% 0 36% 0); transform: translateX(-2.8%); }
76% { opacity: 0.6; clip-path: inset(64% 0 22% 0); transform: translateX(1.6%); }
78% { opacity: 0; }
}
.zr-rkn .zr-in {
animation: zr-breathe 4.2s ease-in-out infinite;
}
.zr-fx {
position: absolute;
inset: 0;
pointer-events: none;
}
.zr-embers i {
position: absolute;
bottom: 4%;
left: calc(var(--ex2) / 16 * 1%);
width: 0.45%;
aspect-ratio: 1;
border-radius: 50%;
background: #ffb199;
box-shadow: 0 0 6px 2px #ff3b5c, 0 0 14px 4px rgba(255, 59, 92, 0.5);
opacity: 0;
scale: var(--s);
animation: zr-ember var(--dur) linear var(--d) infinite;
}
@keyframes zr-ember {
0% { opacity: 0; transform: translate(0, 0); }
10% { opacity: 0.9; }
50% { transform: translate(1.2vw, -30vh); }
100% { opacity: 0; transform: translate(-0.8vw, -62vh); }
}
/* Запрет-тян: искры на пальцах */
.zr-sparks i {
position: absolute;
top: calc(var(--ey) / 9 * 1%);
left: calc(var(--ex) / 16 * 1%);
width: 3.2%;
aspect-ratio: 1;
translate: -50% -50%;
background:
linear-gradient(90deg, transparent 46%, #fff 50%, transparent 54%),
linear-gradient(0deg, transparent 46%, #fff 50%, transparent 54%),
radial-gradient(circle, #fff 0 6%, rgba(91, 127, 255, 0.9) 12%, transparent 40%);
filter: drop-shadow(0 0 6px #5b7fff);
opacity: 0;
animation: zr-twinkle2 2.2s ease-in-out var(--d) infinite;
}
@keyframes zr-twinkle2 {
0%, 60%, 100% { opacity: 0; transform: scale(0.2) rotate(0); }
75% { opacity: 1; transform: scale(1) rotate(45deg); }
90% { opacity: 0.4; transform: scale(0.6) rotate(90deg); }
}
.zr-zt .zr-in {
animation: zr-breathe 4.2s ease-in-out infinite, zr-hop 3.4s cubic-bezier(0.3, 0, 0.3, 1) infinite;
}
@keyframes zr-hop {
0%, 70%, 100% { translate: 0 0; }
78% { translate: 0 -1.6%; }
86% { translate: 0 0.3%; }
92% { translate: 0 -0.5%; }
}
/* реакции на наведение / касание (класс ставит home.js) */
.zr-rkn.zr-poke .zr-in {
animation: zr-lunge 0.7s cubic-bezier(0.3, 0, 0.2, 1);
}
@keyframes zr-lunge {
0% { transform: none; }
30% { transform: scale(1.07) translateY(1.5%); }
100% { transform: none; }
}
.zr-rkn.zr-poke .zr-eye {
animation: zr-flare 0.7s ease-out;
}
@keyframes zr-flare {
30% { opacity: 1; transform: translate(-50%, -50%) scale(2.4); }
}
.zr-zt.zr-poke .zr-in {
animation: zr-jump 0.7s cubic-bezier(0.3, 0, 0.3, 1);
}
@keyframes zr-jump {
0%, 100% { transform: none; }
35% { transform: translateY(-4%) rotate(-1.5deg) scale(1.03); }
65% { transform: translateY(0.6%) scale(0.99, 1.01); }
}
.zr-zt.zr-poke .zr-sparks i {
animation: zr-burst 0.8s ease-out;
}
@keyframes zr-burst {
0% { opacity: 1; transform: scale(0.3) rotate(0); }
50% { opacity: 1; transform: scale(2.2) rotate(90deg); }
100% { opacity: 0; transform: scale(0.5) rotate(180deg); }
}
/* ── дуэль: драку ведёт хореография в home.js (класс zd-fight) ── */
/* слой эффектов драки: следы когтей, щит, удар, искры */
.zd-fx {
position: absolute;
inset: 0;
z-index: 4;
width: 100%;
height: 100%;
pointer-events: none;
}
/* ── заставка: камера на РКН-тян и влёт Запрет-тян ── */
/* ═══════════════════════════════════════════════════════════════════
Пульс
═══════════════════════════════════════════════════════════════════ */
.zp {
padding: clamp(56px, 7vw, 88px) 0 0;
}
.zp[hidden] {
display: none;
}
/* цифры стоят прямо на странице: одна огромная и строка поменьше */
.zp-kpis {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 28px 32px;
margin: 0 0 48px;
}
.zp-kpi {
display: flex;
flex-direction: column-reverse;
justify-content: flex-end;
gap: 6px;
min-width: 0;
}
.zp-kpi[hidden] {
display: none;
}
.zp-kpi dt {
color: var(--dim);
font: 12.5px/1.3 var(--mono);
}
.zp-kpi dd {
margin: 0;
color: var(--ink);
font: 700 clamp(22px, 2.4vw, 32px) / 1.1 var(--disp);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.zp-kpi-main {
display: grid;
grid-column: 1 / -1;
grid-template-columns: auto minmax(0, 1fr);
gap: 4px 24px;
align-items: end;
margin-bottom: 8px;
}
.zp-kpi-main dd {
grid-row: 1 / 3;
grid-column: 1;
font-size: clamp(56px, 10vw, 128px);
line-height: 0.9;
letter-spacing: -0.04em;
}
.zp-kpi-main dt {
grid-column: 2;
align-self: end;
font-size: 14px;
}
.zp-kpi-sub {
grid-column: 2;
padding-bottom: 6px;
color: var(--mut);
font-size: 14px;
}
.zp-kpi-sub b {
color: var(--acc);
}
/* ── На связи: программы, которые ждут сигнал о новой версии ──────────
Те же крупные цифры, что у «Пульса». Версии лежат на одном проводе:
длина отрезка — доля программ, синий отрезок — последняя версия. */
.zw {
padding: clamp(56px, 7vw, 88px) 0 0;
}
.zw[hidden],
.zw [hidden] {
display: none;
}
.zw-cap {
margin: 0 0 12px;
color: var(--dim);
font: 12.5px/1.3 var(--mono);
}
.zw-wire {
margin: 0 0 44px;
}
.zw-bar {
display: flex;
gap: 2px;
height: 14px;
}
.zw-bar i {
display: block;
flex: 1 1 0;
min-width: 3px;
background: var(--line2);
transition: flex-grow 0.6s ease;
}
.zw-bar i.zw-now {
background: var(--acc);
}
.zw-list {
display: flex;
flex-wrap: wrap;
gap: 6px 28px;
margin: 14px 0 0;
padding: 0;
color: var(--mut);
font: 13px/1.5 var(--mono);
list-style: none;
}
.zw-list b {
color: var(--ink);
font-weight: 600;
}
.zw-list .zw-now b {
color: var(--acc);
}
.zw {
/* два канала — две краски: синий акцент страницы и янтарь. Пара проверена
на различимость при нарушениях цветового зрения. */
--zw-stable: #5b7fff;
--zw-dev: #c2803a;
}
.zw-bar i {
cursor: pointer;
}
.zw-bar i:focus-visible {
outline: 2px solid var(--ink);
outline-offset: 2px;
}
.zw-wire {
position: relative;
}
/* отрезок под курсором приподнимается, остальные гаснут */
.zw-bar i {
transition: flex-grow 0.6s ease, opacity 0.15s ease, transform 0.15s ease;
}
.zw-bar.zw-hov i {
opacity: 0.35;
}
.zw-bar.zw-hov i.zw-hot {
opacity: 1;
transform: scaleY(1.6);
}
.zw-list li {
padding: 2px 0;
cursor: default;
box-shadow: inset 0 -1px 0 transparent;
transition: color 0.15s ease, box-shadow 0.15s ease;
}
.zw-list li.zw-hot,
.zw-list li:focus-visible {
color: var(--ink);
outline: none;
box-shadow: inset 0 -1px 0 var(--line2);
}
.zw-rel {
transition: color 0.15s ease, box-shadow 0.15s ease, padding-left 0.15s ease;
}
.zw-rel[aria-pressed="true"] {
padding-left: 20px;
color: var(--ink);
}
.zw-ctl {
display: flex;
flex-wrap: wrap;
gap: 12px 28px;
align-items: center;
margin: 0 0 22px;
}
.zw-legend .zp-lg[data-c="stable"] i {
background: var(--zw-stable);
}
.zw-legend .zp-lg[data-c="dev"] i {
background: var(--zw-dev);
}
.zw-day,
.zw-days {
margin: 0 0 44px;
}
.zw-chart {
position: relative;
height: clamp(180px, 20vw, 260px);
touch-action: pan-y;
}
.zw-chart-s {
height: clamp(150px, 15vw, 200px);
}
.zw .zp-tip b {
color: var(--ink);
}
.zw .zp-tip p {
display: flex;
gap: 8px;
align-items: center;
margin: 2px 0 0;
color: var(--mut);
white-space: nowrap;
}
.zw .zp-tip p:first-child {
margin: 0 0 4px;
color: var(--dim);
font: 12px var(--mono);
}
.zw .zp-tip i {
flex: none;
width: 12px;
height: 2px;
}
.zw-a-stable {
fill: var(--zw-stable);
fill-opacity: 0.2;
}
.zw-a-dev {
fill: var(--zw-dev);
fill-opacity: 0.22;
}
.zw-l-stable,
.zw-l-dev,
.zw-l-roll {
fill: none;
stroke-width: 2;
stroke-linejoin: round;
}
.zw-l-stable,
.zw-l-roll {
stroke: var(--zw-stable);
}
.zw-l-dev {
stroke: var(--zw-dev);
}
.zw-b-stable {
fill: var(--zw-stable);
}
.zw-b-dev {
fill: var(--zw-dev);
}
.zw-hit {
fill: transparent;
cursor: crosshair;
}
.zw-bcol.zw-hot rect:not(.zw-hit) {
filter: brightness(1.25);
}
.zw-mark {
stroke: var(--line2);
stroke-dasharray: 2 5;
}
.zw-mark-l {
fill: var(--dim);
font: 11px var(--mono);
}
.zw-tbl {
margin-top: 10px;
color: var(--mut);
font-size: 13px;
}
.zw-tbl summary {
width: fit-content;
color: var(--dim);
font: 12.5px var(--mono);
cursor: pointer;
}
.zw-tbl summary:hover {
color: var(--ink);
}
.zw-tbl table {
margin-top: 10px;
font-variant-numeric: tabular-nums;
border-collapse: collapse;
}
.zw-tbl th,
.zw-tbl td {
padding: 4px 24px 4px 0;
font-weight: 400;
text-align: right;
}
.zw-tbl th {
color: var(--dim);
font: 12px var(--mono);
}
.zw-tbl th:first-child,
.zw-tbl td:first-child {
text-align: left;
}
.zw-roll {
display: grid;
grid-template-columns: minmax(260px, 1fr) minmax(0, 2fr);
gap: 24px 48px;
margin: 0 0 12px;
}
.zw-rels {
display: grid;
gap: 2px;
}
.zw-rel {
display: grid;
gap: 2px;
padding: 10px 0 10px 14px;
color: var(--mut);
font: inherit;
font-size: 13px;
text-align: left;
cursor: pointer;
background: none;
border: 0;
box-shadow: inset 2px 0 0 var(--line);
}
.zw-rel b {
color: var(--ink);
font: 600 15px var(--mono);
}
.zw-rel:hover {
box-shadow: inset 2px 0 0 var(--line2);
}
.zw-rel[aria-pressed="true"] {
box-shadow: inset 2px 0 0 var(--acc);
}
.zw-rel[aria-pressed="true"] b {
color: var(--acc);
}
@media (max-width: 760px) {
.zw-roll {
grid-template-columns: minmax(0, 1fr);
}
}
/* ── На связи: обновления, ступени раздачи, таблицы ───────────────────
«Обновились» и «не вышло» — пара, проверенная на различимость при
нарушениях цветового зрения; рядом с цветом всегда стоит подпись. */
.zw {
--zw-done: #2f9fc4;
--zw-fail: var(--red);
}
.zw-upd {
margin: 0 0 44px;
}
.zw-keys {
display: flex;
flex-wrap: wrap;
gap: 6px 22px;
margin: 0 0 12px;
padding: 0;
color: var(--mut);
font-size: 13px;
list-style: none;
}
.zw-keys li {
display: flex;
gap: 8px;
align-items: center;
}
.zw-keys i {
flex: none;
width: 12px;
height: 12px;
}
.zw-k-grant {
box-shadow: inset 0 0 0 1.5px var(--mut);
}
.zw-k-done {
background: var(--zw-done);
}
.zw-k-fail {
background: var(--zw-fail);
}
.zw-b-grant {
fill: none;
stroke: var(--mut);
stroke-width: 1;
stroke-opacity: 0.55;
}
.zw-b-done {
fill: var(--zw-done);
}
.zw-b-fail {
fill: var(--zw-fail);
}
.zw-chart-xs {
height: clamp(120px, 11vw, 150px);
}
.zw-took {
margin-top: 28px;
}
.zw-roll-head {
display: flex;
flex-wrap: wrap;
gap: 8px 20px;
align-items: baseline;
justify-content: space-between;
margin: 0 0 12px;
}
.zw-roll-head .zw-cap {
margin: 0;
}
.zw-a-roll {
fill: var(--zw-stable);
fill-opacity: 0.12;
}
.zw-dot {
fill: var(--bg);
stroke: var(--zw-stable);
stroke-width: 2;
pointer-events: none;
}
.zw-stage-l {
stroke: var(--gold);
stroke-opacity: 0.55;
stroke-dasharray: 3 4;
}
.zw-stage-t {
fill: var(--gold);
font: 11px var(--mono);
}
.zw-facts {
margin: 12px 0 0;
color: var(--mut);
font-size: 13px;
font-variant-numeric: tabular-nums;
}
.zw-facts-halt,
.zw-rel-halt span:last-child {
color: var(--red);
}
/* лестница ступеней: пройденные залиты, идущая мигает, остальные ждут */
.zw-stage {
margin: 0 0 44px;
}
.zw-stage-rows {
display: grid;
gap: 22px;
}
.zw-st {
display: grid;
grid-template-columns: minmax(160px, auto) minmax(0, 1fr);
gap: 10px 28px;
align-items: center;
}
.zw-st > b {
color: var(--ink);
font: 600 15px var(--mono);
}
.zw-st > p {
grid-column: 2;
margin: 0;
color: var(--mut);
font-size: 13px;
font-variant-numeric: tabular-nums;
}
.zw-st-halt > p {
color: var(--red);
}
.zw-steps {
display: flex;
gap: 3px;
margin: 0;
padding: 0;
list-style: none;
}
.zw-step {
display: grid;
flex: 1 1 0;
gap: 2px;
min-width: 0;
padding: 9px 0 0;
color: var(--dim);
box-shadow: inset 0 3px 0 var(--line);
}
.zw-step span {
font: 600 17px var(--mono);
}
.zw-step small {
overflow: hidden;
font-size: 12px;
white-space: nowrap;
text-overflow: ellipsis;
}
.zw-step-done {
color: var(--mut);
box-shadow: inset 0 3px 0 var(--acc);
}
.zw-step-done span,
.zw-step-now span {
color: var(--ink);
}
.zw-step-now {
color: var(--gold);
box-shadow: inset 0 3px 0 var(--gold);
animation: zw-pulse 1.6s ease-in-out infinite;
}
.zw-step-halt {
color: var(--red);
box-shadow: inset 0 3px 0 var(--red);
}
.zw-step-halt span {
color: var(--red);
}
@keyframes zw-pulse {
50% {
box-shadow: inset 0 3px 0 rgba(233, 189, 85, 0.3);
}
}
@media (max-width: 760px) {
.zw-st {
grid-template-columns: minmax(0, 1fr);
}
.zw-st > p {
grid-column: 1;
}
}
/* таблицы: сортировка по заголовку, полоска-доля в ячейке, строка под курсором */
.zw-hist {
margin: 20px 0 0;
}
.zw-tbl-scroll {
max-width: 100%;
overflow-x: auto;
}
.zw-tbl th button {
padding: 0;
color: inherit;
font: inherit;
white-space: nowrap;
cursor: pointer;
background: none;
border: 0;
}
.zw-tbl th button:hover,
.zw-tbl th[aria-sort="ascending"] button,
.zw-tbl th[aria-sort="descending"] button {
color: var(--ink);
}
.zw-tbl th[aria-sort="ascending"] button::after {
content: " ↑";
}
.zw-tbl th[aria-sort="descending"] button::after {
content: " ↓";
}
.zw-tbl td {
white-space: nowrap;
box-shadow: inset 0 -1px 0 var(--line);
}
.zw-tbl tbody tr:hover td {
color: var(--ink);
background-color: rgba(255, 255, 255, 0.035);
}
.zw-tbl td.zw-barc {
background-image: linear-gradient(to left, rgba(91, 127, 255, 0.2) calc(var(--v, 0) * 100%), transparent 0);
background-repeat: no-repeat;
background-position: right 24px center;
background-size: calc(100% - 24px) 62%;
}
.zw-tbl td.zw-td-name {
color: var(--ink);
font-family: var(--mono);
}
.zw-tbl td.zw-td-bad {
color: var(--red);
}
/* плавное появление: линия прочерчивается, заливка проступает, столбцы растут */
.zw-anim .zw-draw {
stroke-dasharray: 1;
stroke-dashoffset: 1;
animation: zw-draw 0.9s cubic-bezier(0.3, 0.7, 0.2, 1) forwards;
}
.zw-anim .zw-fade {
animation: zw-fade 0.7s ease-out 0.25s both;
}
.zw-anim .zw-grow {
transform-box: fill-box;
transform-origin: 50% 100%;
animation: zw-grow 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) both;
animation-delay: calc(var(--i, 0) * 9ms);
}
@keyframes zw-draw {
to {
stroke-dashoffset: 0;
}
}
@keyframes zw-fade {
from {
opacity: 0;
}
}
@keyframes zw-grow {
from {
opacity: 0;
transform: scaleY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.zw-step-now,
.zw-anim .zw-draw,
.zw-anim .zw-fade,
.zw-anim .zw-grow {
animation: none;
}
.zw-anim .zw-draw {
stroke-dasharray: none;
}
}
/* ── На связи: живая сценка ──────────────────────────────────────────
Сервер в середине, программы вокруг. Тонкая нить — открытое соединение;
по ней бегут вопрос «есть новее?» и ответ сервера. */
.zw .zp-kpis {
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
/* длинное значение («меньше минуты») переносится, а не наезжает на соседа */
.zw .zp-kpi dd {
white-space: normal;
overflow-wrap: anywhere;
}
/* переключатель программы и пустое состояние: у программы ещё нет ни одной
установки, которая держит соединение с сервером */
.zw-prod {
margin-top: 18px;
}
.zw-empty {
max-width: 62ch;
margin: 0 0 12px;
color: var(--mut);
font-size: 16px;
line-height: 1.55;
}
.zw.zw-none > .zs > :not(.zsec-head):not(.zw-empty) {
display: none;
}
.zw-scene {
display: grid;
grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr);
gap: 24px 48px;
margin: 0 0 44px;
}
.zw-scene-main {
min-width: 0;
}
.zw-scene-cv {
display: block;
width: 100%;
height: clamp(260px, 30vw, 400px);
}
.zw-scene-keys {
margin: 12px 0 0;
}
.zw-scene-keys i {
width: 9px;
height: 9px;
border-radius: 50%;
}
.zw-k-new {
background: var(--acc);
}
.zw-k-old {
background: var(--zw-dev);
}
.zw-k-tray {
background: var(--acc);
opacity: 0.4;
}
/* чем заняты программы: открытое окно — акцент, трей — нейтральный, дело — золото */
.zw-bar i.zw-busy {
background: var(--gold);
}
.zw-list .zw-busy b {
color: var(--gold);
}
.zw-act .zw-bar i {
cursor: default;
}
/* почему обновление не прошло: две колонки — не поставилось и не скачалось */
.zw-why-cols {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
gap: 8px 32px;
}
.zw-why-col {
min-width: 0;
}
.zw-why-head {
margin: 0 0 6px;
font-weight: 600;
}
.zw-why-head span {
font-weight: 400;
color: var(--mut);
}
.zw-why .zw-list {
display: grid;
gap: 4px;
}
/* число — своя колонка: перенос длинной причины не уезжает под него */
.zw-why .zw-list li {
display: grid;
grid-template-columns: 5ch minmax(0, 1fr);
}
.zw-why .zw-list b {
font-variant-numeric: tabular-nums;
}
.zw-scene-keys .zw-k-busy {
background: none;
box-shadow: inset 0 0 0 1.5px var(--mut);
}
.zw-scene-keys .zw-k-ask,
.zw-scene-keys .zw-k-grant {
width: 10px;
height: 7px;
border-radius: 0;
box-shadow: none;
}
.zw-k-ask {
background: #bff0ff;
}
.zw-scene-keys .zw-k-grant {
background: var(--gold);
}
.zw-scene-side {
display: grid;
gap: 0;
align-content: start;
min-width: 0;
}
.zw-flow {
display: grid;
gap: 16px;
margin: 0 0 28px;
}
.zw-flow div {
display: flex;
flex-direction: column-reverse;
gap: 4px;
}
.zw-flow div[hidden] {
display: none;
}
.zw-flow dt {
color: var(--dim);
font: 12.5px/1.3 var(--mono);
}
.zw-flow dd {
margin: 0;
color: var(--ink);
font: 700 clamp(22px, 2.4vw, 32px) / 1.1 var(--disp);
font-variant-numeric: tabular-nums;
}
.zw-log {
display: grid;
gap: 10px;
min-height: 150px;
margin: 0;
padding: 0;
list-style: none;
}
.zw-log li {
display: grid;
gap: 2px;
padding-left: 12px;
color: var(--mut);
font-size: 13px;
box-shadow: inset 2px 0 0 var(--line);
animation: zw-log-in 0.35s ease-out both;
}
.zw-log li:first-child {
box-shadow: inset 2px 0 0 var(--acc);
}
.zw-log li.zw-log-grant:first-child {
box-shadow: inset 2px 0 0 var(--gold);
}
.zw-log li:nth-child(n + 3) {
opacity: 0.45;
}
.zw-log code {
overflow: hidden;
color: var(--ink);
font: 12px/1.4 var(--mono);
white-space: nowrap;
text-overflow: ellipsis;
background: none;
}
.zw-scene-note {
margin: 18px 0 0;
color: var(--dim);
font-size: 12.5px;
line-height: 1.5;
}
@keyframes zw-log-in {
from {
opacity: 0;
transform: translateY(-6px);
}
}
@media (max-width: 900px) {
.zw-scene {
grid-template-columns: minmax(0, 1fr);
}
}
@media (prefers-reduced-motion: reduce) {
.zw-log li {
animation: none;
}
}
.zw-chart svg {
display: block;
width: 100%;
height: 100%;
overflow: visible;
}
.zw-ln {
fill: none;
stroke: var(--acc);
stroke-width: 1.6;
stroke-linejoin: round;
}
.zw-ar {
fill: rgba(91, 127, 255, 0.12);
}
.zp-ctl {
display: flex;
flex-wrap: wrap;
gap: 12px 32px;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
.zp-range {
display: inline-flex;
gap: 20px;
}
.zp-range button {
padding: 7px 0;
color: var(--dim);
font: 600 14px var(--txt);
cursor: pointer;
border: 0;
background: none;
transition: color 0.2s, box-shadow 0.2s;
}
.zp-range button:hover {
color: var(--ink);
}
.zp-range button[aria-pressed="true"] {
color: var(--ink);
box-shadow: inset 0 -2px 0 var(--acc);
}
.zp-legend {
display: flex;
flex-wrap: wrap;
gap: 2px 20px;
}
.zp-lg {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 0;
color: var(--mut);
font: 500 13px var(--txt);
cursor: pointer;
border: 0;
background: none;
transition: opacity 0.2s, color 0.2s;
}
.zp-lg:hover {
color: var(--ink);
}
.zp-lg i {
width: 10px;
height: 10px;
border-radius: 2px;
background: var(--c);
}
.zp-lg small {
color: var(--dim);
font: 12px var(--mono);
}
.zp-lg[aria-pressed="false"] {
opacity: 0.45;
}
.zp-lg[aria-pressed="false"] i {
background: transparent;
box-shadow: inset 0 0 0 2px var(--c);
}
.zp-chart {
position: relative;
height: clamp(240px, 30vw, 340px);
touch-action: pan-y;
}
.zp-chart svg {
display: block;
width: 100%;
height: 100%;
overflow: visible;
cursor: crosshair;
}
.zp-gl {
stroke: rgba(120, 160, 255, 0.1);
stroke-dasharray: 3 6;
}
.zp-yl,
.zp-xl {
fill: var(--dim);
font: 11px var(--mono);
}
.zp-yl {
text-anchor: end;
}
.zp-xl {
text-anchor: middle;
}
.zp-ar {
opacity: 0.8;
}
.zp-ln {
fill: none;
stroke-width: 1.6;
}
.zp-cur {
stroke: rgba(255, 255, 255, 0.35);
stroke-dasharray: 4 4;
}
.zp-dot {
fill: #07080c;
stroke-width: 2.5;
}
.zp-best circle {
fill: var(--gold);
animation: zp-best 1.6s ease-in-out infinite alternate;
}
.zp-best text {
fill: var(--gold);
font: 600 12px var(--mono);
text-anchor: middle;
}
@keyframes zp-best {
to { opacity: 0.45; }
}
.zp-tip {
position: absolute;
top: 6px;
z-index: 2;
min-width: 200px;
padding: 10px 14px;
font-size: 13px;
pointer-events: none;
border-radius: 8px;
background: rgba(7, 8, 12, 0.95);
box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.9);
transform: translateX(-50%);
}
.zp-tip[hidden] {
display: none;
}
.zp-tip h4 {
margin: 0 0 4px;
color: var(--dim);
font: 12px var(--mono);
}
.zp-tt {
font: 700 20px var(--disp);
}
.zp-tt small {
color: var(--mut);
font: 500 13px var(--txt);
}
.zp-tip ul {
display: grid;
gap: 3px;
margin: 8px 0 0;
padding: 8px 0 0;
list-style: none;
border-top: 1px solid var(--line);
}
.zp-tip li {
display: flex;
justify-content: space-between;
gap: 14px;
color: var(--mut);
white-space: nowrap;
}
.zp-tip li i {
display: inline-block;
width: 8px;
height: 8px;
margin-right: 8px;
border-radius: 2px;
background: var(--c);
}
.zp-tip li b {
color: var(--ink);
font-variant-numeric: tabular-nums;
}
@media (max-width: 980px) {
.zp-kpis {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@media (max-width: 560px) {
.zp-kpis {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.zp-kpi-main {
grid-template-columns: minmax(0, 1fr);
}
.zp-kpi-main dd,
.zp-kpi-main dt,
.zp-kpi-sub {
grid-row: auto;
grid-column: 1;
}
.zp-ctl {
flex-direction: column;
align-items: stretch;
}
.zp-range {
align-self: flex-start;
}
}
/* ═══════════════════════════════════════════════════════════════════
Арсенал
═══════════════════════════════════════════════════════════════════ */
.za {
padding: clamp(56px, 7vw, 88px) 0;
}
.za-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: clamp(48px, 6vw, 80px) 40px;
}
/* проект — обложка и текст прямо на странице, без карточки */
.zc {
position: relative;
display: flex;
flex-direction: column;
}
.zc-cover {
width: 100%;
aspect-ratio: 2.35;
object-fit: cover;
-webkit-mask-image: linear-gradient(to bottom, #000 60%, transparent);
mask-image: linear-gradient(to bottom, #000 60%, transparent);
transition: filter 0.4s;
}
.zc:hover .zc-cover {
filter: brightness(1.12);
}
.zc-body {
display: flex;
flex: 1;
flex-direction: column;
gap: 12px;
}
.zc-body > p:not(.zc-tags) {
max-width: 520px;
color: var(--mut);
}
.zc h3 {
font-size: clamp(22px, 2.4vw, 30px);
line-height: 1.15;
}
.zc-tags {
display: flex;
flex-wrap: wrap;
color: var(--acc);
font: 12.5px var(--mono);
}
.zc-tags span + span::before {
margin: 0 8px;
color: var(--dim);
content: "/";
}
.zc-links {
display: flex;
flex-wrap: wrap;
gap: 4px 24px;
align-items: center;
margin-top: auto;
padding-top: 8px;
}
/* версии под платформы — строки списка */
.zc-vers {
margin: auto 0 0;
padding: 8px 0 0;
list-style: none;
}
.zc-vers li {
display: flex;
align-items: stretch;
border-top: 1px solid var(--line);
}
.zc-vers a:first-child {
display: grid;
flex: 1;
grid-template-columns: 88px minmax(0, 1fr);
gap: 12px;
align-items: baseline;
min-width: 0;
padding: 13px 0;
color: var(--mut);
font-size: 14.5px;
line-height: 1.35;
transition: color 0.2s;
}
.zc-vers a:first-child b {
color: var(--ink);
font-family: var(--mono);
font-size: 13px;
font-weight: 600;
}
.zc-vers a:first-child:hover {
color: var(--ink);
}
.zpm-home .zc-dl {
display: grid;
flex: 0 0 44px;
place-items: center end;
color: var(--acc);
font-size: 20px;
font-weight: 700;
transition: color 0.2s;
}
.zpm-home .zc-dl:hover {
color: var(--ink);
animation: zc-bounce 0.6s ease-in-out infinite;
}
@keyframes zc-bounce {
50% { transform: translateY(3px); }
}
/* флагман: текст и снимок окна программы */
.zc-gui {
grid-column: 1 / -1;
display: grid;
grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
gap: 28px 48px;
align-items: center;
}
.zc-gui h3 {
font-size: clamp(28px, 3.4vw, 44px);
}
.zc-win {
display: block;
overflow: hidden;
border-radius: 8px;
}
/* широкий блок Magisk */
.zc-wide {
grid-column: 1 / -1;
display: grid;
grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
gap: 20px 40px;
}
.zc-wide .zc-cover {
height: 100%;
min-height: 300px;
-webkit-mask-image: linear-gradient(to right, #000 55%, transparent);
mask-image: linear-gradient(to right, #000 55%, transparent);
}
.zc-wide .zc-body {
justify-content: center;
}
.zc-wide .zc-links {
margin-top: 0;
}
/* ═══════════════════════════════════════════════════════════════════
Инвентарь
═══════════════════════════════════════════════════════════════════ */
.zt {
padding: 0 0 clamp(56px, 7vw, 88px);
}
.zt-grid {
display: grid;
grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.4fr);
gap: 48px;
align-items: start;
}
.zt-head {
position: sticky;
top: 90px;
}
.zt-list {
margin: 0;
padding: 0;
list-style: none;
border-top: 1px solid var(--line);
}
.zt-list li {
border-bottom: 1px solid var(--line);
}
.zt-list a {
position: relative;
display: grid;
grid-template-columns: 40px minmax(0, 1fr) auto;
gap: 20px;
align-items: center;
padding: 20px 0;
overflow: hidden;
}
.zt-list a::before {
position: absolute;
inset: 0;
z-index: -1;
content: "";
background: rgba(242, 238, 230, 0.05);
transform: scaleX(0);
transform-origin: left;
transition: transform 0.45s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.zt-list a:hover::before {
transform: scaleX(1);
}
.zt-t {
display: grid;
gap: 2px;
}
.zt-t strong {
font-family: var(--disp);
font-size: 17px;
font-weight: 600;
letter-spacing: -0.01em;
}
.zt-t span {
color: var(--mut);
font-size: 14.5px;
}
.zt-list em {
color: var(--dim);
font: normal 12.5px var(--mono);
}
.zt-ico {
width: 40px;
height: 40px;
fill: none;
stroke: var(--acc);
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
transition: transform 0.3s;
}
.zt-fill {
fill: var(--acc);
stroke: none;
}
.zt-list a:hover .zt-ico {
transform: rotate(-6deg) scale(1.06);
}
.zt-list a:hover .zt-fill {
animation: zt-blink 0.9s ease-in-out infinite;
}
@keyframes zt-blink {
50% { opacity: 0.35; }
}
.zt-onion circle {
transform-box: fill-box;
transform-origin: center;
}
.zt-list a:hover .zt-onion circle:nth-child(1) { animation: zt-ring 1.2s ease-in-out infinite; }
.zt-list a:hover .zt-onion circle:nth-child(2) { animation: zt-ring 1.2s 0.2s ease-in-out infinite; }
@keyframes zt-ring {
50% { transform: scale(0.88); }
}
.zt-pupil {
animation: zt-look 4s ease-in-out infinite;
}
@keyframes zt-look {
0%, 20%, 100% { transform: translateX(0); }
35%, 50% { transform: translateX(-6px); }
65%, 80% { transform: translateX(6px); }
}
.zt-hand {
transform-origin: 20px 21px;
animation: zt-tick 6s steps(12) infinite;
}
.zt-list a:hover .zt-hand {
animation-duration: 1s;
}
@keyframes zt-tick {
to { transform: rotate(360deg); }
}
.zt-status .zt-beat {
stroke-dasharray: 42;
stroke-dashoffset: 42;
animation: zt-trace 2.2s linear infinite;
}
.zt-list a:hover .zt-status .zt-beat {
animation-duration: 0.9s;
}
@keyframes zt-trace {
0% { stroke-dashoffset: 42; }
60%, 100% { stroke-dashoffset: -42; }
}
/* DNS: запрос спускается по дереву имён от корня к нужному узлу. */
.zt-dns circle {
fill: var(--bg);
}
.zt-dns .zt-fill {
fill: var(--acc);
}
.zt-dns .zt-resolve {
stroke-width: 4;
stroke-dasharray: 5 40;
stroke-dashoffset: 5;
animation: zt-resolve 2.4s linear infinite;
}
.zt-list a:hover .zt-dns .zt-resolve {
animation-duration: 1s;
}
@keyframes zt-resolve {
0% { stroke-dashoffset: 5; }
70%, 100% { stroke-dashoffset: -29; }
}
.zt-book path:last-child {
transform-origin: 20px 20px;
transition: transform 0.5s;
}
.zt-list a:hover .zt-book path:last-child {
transform: scaleX(-1);
}
/* ═══════════════════════════════════════════════════════════════════
Сборки
═══════════════════════════════════════════════════════════════════ */
.zr {
padding: clamp(56px, 7vw, 88px) 0;
}
/* ── Досмотр на ТСПУ. Слева — что видит цензор: пакет притворяется
разрешённым сайтом (поддельный SNI) и шумит байтами. Посередине — рамка
ТСПУ с лучом сканера. Справа — что на самом деле доехало: релиз.
По проводу каждой строки едет пакет: до рамки красный, после — синий.
Сетка общая на все строки (subgrid), поэтому рамка стоит ровно в колонке.
Версии и даты подставляет home.js из API релизов. ── */
.zr-net {
display: grid;
grid-template-columns: minmax(0, 0.62fr) 104px minmax(0, 1.5fr) auto;
column-gap: 24px;
margin: 0 0 clamp(48px, 6vw, 72px);
}
.zr-leg,
.zrn {
display: grid;
grid-template-columns: subgrid;
grid-column: 1 / -1;
}
.zr-leg {
grid-row: 1;
padding-bottom: 12px;
color: var(--dim);
font: 12.5px var(--mono);
}
.zr-leg-gate {
color: var(--red);
letter-spacing: 0.12em;
text-align: center;
}
/* рамка досмотра: две стойки и луч, который ходит вверх-вниз */
.zr-gate {
position: relative;
grid-row: 2 / span 6;
grid-column: 2;
overflow: hidden;
pointer-events: none;
background:
linear-gradient(var(--red), var(--red)) no-repeat 0 0 / 1px 100%,
linear-gradient(var(--red), var(--red)) no-repeat 100% 0 / 1px 100%,
rgba(255, 59, 92, 0.05);
}
.zr-gate::after {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 2px;
content: "";
background: var(--red);
animation: zr-sweep 2.8s ease-in-out infinite alternate;
}
@keyframes zr-sweep {
to { top: calc(100% - 2px); }
}
.zrn {
grid-row: calc(var(--i) + 1);
align-items: center;
min-height: 76px;
}
/* провод от левого края через рамку до названия */
.zrn-in {
position: relative;
display: flex;
grid-row: 1;
grid-column: 1 / 3;
align-items: center;
align-self: stretch;
}
.zrn-in::before {
position: absolute;
top: 50%;
right: -16px;
left: 0;
height: 1px;
content: "";
background: var(--line2);
}
/* что видит цензор: имя разрешённого сайта над проводом, шум байтов под ним */
.zrn-fake {
display: grid;
gap: 16px;
max-width: calc(100% - 128px);
overflow: hidden;
font: 12px/1 var(--mono);
white-space: nowrap;
}
.zrn-fake b {
color: var(--mut);
font-weight: 400;
transition: color 0.2s;
}
.zrn-fake i {
color: var(--dim);
font-style: normal;
}
.zrn:hover .zrn-fake b {
color: var(--red);
}
/* пакет: середина рамки — в 52px от правого края провода */
.zrn-pk {
position: absolute;
top: calc(50% - 4px);
left: 0;
width: 9px;
height: 9px;
background: var(--red);
animation: zrn-pk var(--t, 3.4s) linear var(--d, 0s) infinite;
}
@keyframes zrn-pk {
0% { left: 0; background: var(--red); opacity: 0; }
5% { opacity: 1; }
70% { left: calc(100% - 100px); background: var(--red); }
76% { left: calc(100% - 57px); background: var(--red); }
80% { left: calc(100% - 57px); background: var(--ink); }
84% { left: calc(100% - 57px); background: var(--acc); }
96% { opacity: 1; }
100% { left: calc(100% + 8px); background: var(--acc); opacity: 0; }
}
/* вердикт сканера появляется, когда пакет стоит в рамке */
.zrn-ok {
z-index: 1;
grid-row: 1;
grid-column: 2;
align-self: end;
justify-self: center;
padding-bottom: 10px;
color: #37e39a;
font: 11px var(--mono);
letter-spacing: 0.08em;
animation: zrn-ok var(--t, 3.4s) linear var(--d, 0s) infinite;
}
@keyframes zrn-ok {
0%, 78% { opacity: 0; }
82%, 97% { opacity: 1; }
100% { opacity: 0; }
}
.zrn-line {
display: flex;
flex-wrap: wrap;
grid-column: 3;
gap: 0 0.5em;
font: 700 clamp(19px, 2.3vw, 30px) / 1.2 var(--disp);
letter-spacing: -0.02em;
}
.zrn strong,
.zrn-ver {
font: inherit;
white-space: nowrap;
transition: color 0.2s;
}
.zrn-ver {
color: var(--acc);
font-variant-numeric: tabular-nums;
}
.zrn:hover strong {
color: var(--acc);
}
.zrn-meta {
display: grid;
grid-column: 4;
grid-template-columns: 112px 130px 88px;
gap: 12px;
color: var(--dim);
font: 12.5px var(--mono);
white-space: nowrap;
}
.zrn-meta span:last-child {
text-align: right;
}
.zrn-os {
color: var(--mut);
}
/* сборке меньше трёх дней */
.zrn-fresh [data-f="age"] {
color: var(--acc);
}
.zrn-fresh [data-f="age"]::before {
display: inline-block;
width: 7px;
height: 7px;
margin-right: 8px;
content: "";
background: var(--acc);
animation: zrn-new 1.2s steps(2, jump-none) infinite;
}
@keyframes zrn-new {
to { background: var(--ink); }
}
/* ── F-Droid: телефон, на который прилетает обновление ── */
.zfd {
display: grid;
grid-template-columns: 86px minmax(0, 1fr) auto;
gap: 28px;
align-items: center;
}
.zfd-copy strong {
transition: color 0.2s;
}
.zfd:hover .zfd-copy strong {
color: #37e39a;
}
.zfd-phone svg {
display: block;
width: 86px;
overflow: visible;
}
.zfd-body { fill: #0a1226; stroke: #37e39a; stroke-width: 2.5; }
.zfd-screen { fill: #05110f; }
.zfd-notch { fill: #1d3b33; }
.zfd-apps rect { fill: rgba(55, 227, 154, 0.25); stroke: rgba(55, 227, 154, 0.6); stroke-width: 1.2; }
.zfd-label { fill: #7fe8bd; font: 9px var(--mono); text-anchor: middle; }
.zfd-track { fill: rgba(55, 227, 154, 0.15); }
.zfd-bar {
fill: #37e39a;
transform-box: fill-box;
transform-origin: left;
animation: zfd-bar 4s ease-in-out infinite;
}
.zfd-ok {
fill: none;
stroke: #37e39a;
stroke-width: 4;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 32;
animation: zfd-ok 4s ease-out infinite;
}
.zfd-pkt {
fill: #37e39a;
animation: zfd-pkt 4s ease-in infinite;
}
.zfd-apps rect {
transform-box: fill-box;
transform-origin: center;
animation: zfd-app 4s ease-out infinite;
}
.zfd-apps rect:nth-child(2) { animation-delay: 0.1s; }
.zfd-apps rect:nth-child(3) { animation-delay: 0.2s; }
@keyframes zfd-pkt {
0% { opacity: 0; transform: translateY(0); }
8% { opacity: 1; }
24% { opacity: 1; transform: translateY(64px); }
28%, 100% { opacity: 0; transform: translateY(64px); }
}
@keyframes zfd-bar {
0%, 26% { transform: scaleX(0); }
62%, 100% { transform: scaleX(1); }
}
@keyframes zfd-ok {
0%, 62% { stroke-dashoffset: 32; opacity: 0; }
64% { opacity: 1; }
74%, 94% { stroke-dashoffset: 0; opacity: 1; }
100% { opacity: 0; }
}
@keyframes zfd-app {
0%, 64%, 100% { transform: none; fill: rgba(55, 227, 154, 0.25); }
70% { transform: scale(1.25); fill: #37e39a; }
78% { transform: none; }
}
.zfd-copy {
display: grid;
gap: 4px;
}
.zfd-copy strong {
font: 700 22px var(--disp);
}
.zfd-copy > span:last-child {
color: var(--mut);
font-size: 15px;
}
.zfd-tag {
color: #37e39a;
font: 12.5px var(--mono);
}
.zfd-go {
color: #37e39a;
font-size: 26px;
transition: transform 0.3s;
}
.zfd:hover .zfd-go {
transform: translateX(6px);
}
@media (max-width: 860px) {
/* на узком экране рамка ТСПУ — узкая колонка слева, пакеты пролетают сквозь неё */
.zr-net {
grid-template-columns: 40px minmax(0, 1fr);
column-gap: 16px;
}
.zr-leg span:not(.zr-leg-gate),
.zrn-fake,
.zrn-ok {
display: none;
}
.zr-leg-gate {
letter-spacing: 0;
font-size: 11px;
}
.zr-gate {
grid-column: 1;
}
.zrn {
min-height: 0;
padding: 12px 0;
}
.zrn-in {
grid-row: 1 / span 2;
grid-column: 1;
}
.zrn-in::before {
right: -10px;
left: -6px;
}
.zrn-pk {
animation-name: zrn-pk-m;
}
.zrn-line,
.zrn-meta {
grid-column: 2;
}
.zrn-meta {
display: flex;
flex-wrap: wrap;
gap: 2px 14px;
}
}
@keyframes zrn-pk-m {
0% { left: -6px; background: var(--red); opacity: 0; }
10% { opacity: 1; }
40% { left: 15px; background: var(--red); }
55% { left: 15px; background: var(--ink); }
65% { left: 15px; background: var(--acc); }
95% { opacity: 1; }
100% { left: 44px; background: var(--acc); opacity: 0; }
}
@media (max-width: 560px) {
.zfd {
grid-template-columns: 60px minmax(0, 1fr);
gap: 16px;
}
.zfd-phone svg {
width: 60px;
}
.zfd-go {
display: none;
}
}
/* ═══════════════════════════════════════════════════════════════════
Доверие
═══════════════════════════════════════════════════════════════════ */
.zci {
padding: clamp(56px, 7vw, 88px) 0;
}
/* ── Сборка в прямом эфире: вывод терминала без окна. Шаги печатаются
построчно (pending → run → ok переключает home.js), потом посимвольно
сверяются контрольные суммы. ── */
.zci-lab {
display: grid;
grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
gap: 48px clamp(40px, 7vw, 104px);
align-items: start;
}
.zci-run {
font-family: var(--mono);
}
/* строка-команда */
.zci-cmd {
color: var(--ink);
font: 600 14px/1.6 var(--mono);
}
.zci-cmd b {
margin-right: 10px;
color: var(--acc);
}
.zci-cmd small {
margin-left: 12px;
color: var(--dim);
font-weight: 400;
font-size: 12.5px;
}
.zci-log {
margin: 0;
padding: 6px 0 22px;
list-style: none;
}
.zci-log li {
display: grid;
grid-template-columns: 18px minmax(0, 1fr) auto;
gap: 12px;
align-items: center;
padding: 8px 0;
}
.zci-log li span {
display: grid;
min-width: 0;
}
.zci-log strong {
color: var(--ink);
font-size: 14px;
font-weight: 600;
}
.zci-log small {
overflow: hidden;
color: var(--dim);
font-size: 12px;
white-space: nowrap;
text-overflow: ellipsis;
}
.zci-log em {
color: var(--dim);
font-size: 12px;
font-style: normal;
}
/* значок шага: крутится → галочка */
.zci-sp {
position: relative;
width: 16px;
height: 16px;
}
.zci-log li.ok .zci-sp::after {
position: absolute;
inset: 0;
display: grid;
place-items: center;
color: #37e39a;
content: "✓";
font: 700 15px var(--txt);
animation: zci-pop 0.35s cubic-bezier(0.3, 1.8, 0.5, 1);
}
.zci-log li.run .zci-sp {
border: 2px solid var(--line2);
border-top-color: var(--acc);
border-radius: 50%;
animation: zci-spin 0.6s linear infinite;
}
/* ещё не напечатано */
.zci-log li.pending {
visibility: hidden;
}
.zci-log li.run em {
visibility: hidden;
}
@keyframes zci-spin {
to { transform: rotate(360deg); }
}
@keyframes zci-pop {
from { transform: scale(0.2); }
}
/* сверка хешей */
.zci-hash {
display: grid;
gap: 12px;
}
.zci-h {
display: grid;
gap: 3px;
}
.zci-h span {
color: var(--dim);
font-size: 12.5px;
}
.zci-h code {
display: block;
padding: 0;
color: #37e39a;
font: 500 14.5px/1.5 var(--mono);
letter-spacing: 0.03em;
word-break: break-all;
background: none;
}
.zci-h code i {
font-style: normal;
}
.zci-live .zci-h code {
color: var(--dim);
}
.zci-live .zci-h code i.lk {
color: var(--ink);
}
.zci-live.zci-match .zci-h code i.lk {
color: #37e39a;
transition: color 0.3s calc(var(--n) * 6ms);
}
/* итог сверки */
.zci-ok {
color: #37e39a;
font: 700 14px var(--mono);
}
.zci-live .zci-ok {
opacity: 0;
}
.zci-live .zci-ok.on {
opacity: 1;
}
.zci-points {
display: grid;
gap: 26px;
}
.zci-points strong {
font-family: var(--disp);
font-size: 18px;
font-weight: 600;
}
.zci-points strong::before {
margin-right: 10px;
color: #37e39a;
content: "✓";
}
.zci-points p {
max-width: 460px;
margin-top: 6px;
color: var(--mut);
font-size: 15px;
}
@media (max-width: 860px) {
.zci-lab {
grid-template-columns: minmax(0, 1fr);
}
}
/* ═══════════════════════════════════════════════════════════════════
Поддержка и участие
═══════════════════════════════════════════════════════════════════ */
.zj {
padding: 0 0 clamp(56px, 7vw, 88px);
}
/* поддержка и замок-игра стоят в один ряд: слева призыв, справа игра */
.zj-pair {
display: grid;
grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
gap: 40px clamp(32px, 5vw, 72px);
align-items: center;
}
.zj-help {
position: relative;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: clamp(20px, 2.6vw, 36px);
align-items: center;
padding: 28px 0;
overflow: hidden;
}
/* ── Объёмное сердце: 22 слоя-сечения на разной глубине ──────────────
Средние слои крупнее крайних — получается «надутая» форма, а не плоская
табличка. Сердце покачивается в 3D и бьётся в ритме ЭКГ под ним. */
.zj-heart {
--heart: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 110'%3E%3Cpath d='M60 104C20 76 6 56 6 34 6 18 18 6 33 6c12 0 21 7 27 18C66 13 75 6 87 6c15 0 27 12 27 28 0 22-14 42-54 70z'/%3E%3C/svg%3E");
position: relative;
display: grid;
place-items: center;
width: clamp(150px, 15vw, 200px);
aspect-ratio: 1;
perspective: 700px;
}
.zh3-glow {
position: absolute;
inset: 5%;
border-radius: 50%;
background: radial-gradient(circle, rgba(255, 59, 92, 0.55), rgba(255, 59, 92, 0.12) 45%, transparent 70%);
filter: blur(10px);
animation: zh3-glow 1.4s ease-in-out infinite;
}
.zh3-spin {
width: 72%;
aspect-ratio: 120 / 110;
transform-style: preserve-3d;
animation: zh3-spin 7s ease-in-out infinite;
}
.zh3-beat {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
animation: zh3-beat 1.4s cubic-bezier(0.3, 0, 0.3, 1) infinite;
}
.zh3-beat i,
.zh3-face {
position: absolute;
inset: 0;
-webkit-mask: var(--heart) center / contain no-repeat;
mask: var(--heart) center / contain no-repeat;
}
.zh3-beat i {
transform: translateZ(calc((var(--z) - 10.5) * 2.4px)) scale(var(--k));
background: linear-gradient(160deg,
hsl(350 85% calc(22% + var(--z) * 1.4%)),
hsl(345 80% calc(12% + var(--z) * 0.9%)));
}
/* лицевая поверхность: глянец, блик и тонкая неоновая кромка */
.zh3-face {
transform: translateZ(26px) scale(0.99);
background:
radial-gradient(ellipse 34% 26% at 32% 26%, rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0) 70%),
radial-gradient(ellipse 60% 55% at 40% 38%, #ff7a92, transparent 70%),
linear-gradient(160deg, #ff4d6d, #c3113a 55%, #6d0620);
filter: drop-shadow(0 0 1px #ffb3c0);
}
.zh3-face::after {
position: absolute;
inset: 0;
content: "";
background: linear-gradient(105deg, transparent 35%, rgba(255, 255, 255, 0.55) 48%, transparent 60%);
background-size: 300% 100%;
animation: zh3-shine 4.2s ease-in-out infinite;
}
@keyframes zh3-spin {
0%, 100% { transform: rotateY(-32deg) rotateX(8deg); }
50% { transform: rotateY(32deg) rotateX(-4deg); }
}
@keyframes zh3-beat {
0%, 100% { transform: scale(1); }
8% { transform: scale(1.12); }
16% { transform: scale(0.98); }
26% { transform: scale(1.07); }
40% { transform: scale(1); }
}
@keyframes zh3-glow {
0%, 45%, 100% { opacity: 0.55; transform: scale(0.95); }
10% { opacity: 1; transform: scale(1.12); }
28% { opacity: 0.85; transform: scale(1.04); }
}
@keyframes zh3-shine {
0%, 55% { background-position: 150% 0; }
85%, 100% { background-position: -50% 0; }
}
/* ЭКГ под сердцем: пик совпадает с ударом */
.zh3-ecg {
position: absolute;
right: -8%;
bottom: -2%;
left: -8%;
width: 116%;
height: 22%;
overflow: visible;
}
.zh3-ecg path {
fill: none;
stroke-linejoin: round;
stroke-linecap: round;
vector-effect: non-scaling-stroke;
}
.zh3-ecg-base {
stroke: rgba(255, 90, 116, 0.18);
stroke-width: 1.5;
}
.zh3-ecg-line {
stroke: #ff6b83;
stroke-width: 2.5;
filter: drop-shadow(0 0 5px #ff3b5c);
animation: zh3-trace 1.4s linear -0.18s infinite;
}
.zh3-ecg-line {
stroke-dasharray: 60 460;
stroke-dashoffset: 60;
}
@keyframes zh3-trace {
0% { stroke-dashoffset: -60; }
100% { stroke-dashoffset: -440; }
}
.zj-help-copy h2 {
font-size: clamp(24px, 2.6vw, 34px);
line-height: 1.12;
}
.zj-help-copy > p:not(.zeb) {
max-width: 560px;
margin: 16px 0 26px;
color: var(--mut);
font-size: 17px;
}
.zj-help-copy b {
color: var(--ink);
}
/* ── «Как присоединиться»: TCP-рукопожатие. Слева вы, справа сервер,
три шага — три пакета: SYN туда, SYN-ACK обратно, ACK туда. ── */
.zj-join {
max-width: 880px;
margin-top: clamp(72px, 9vw, 120px);
}
.zj-join h2 {
font-size: clamp(26px, 3.6vw, 40px);
}
.zj-sub {
margin: 12px 0 36px;
color: var(--mut);
font-size: 17px;
}
.zj-ends {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
color: var(--dim);
font: 12.5px var(--mono);
}
/* две «линии жизни» по краям */
.zj-hs {
display: grid;
gap: 30px;
margin: 0;
padding: 18px 0;
list-style: none;
background:
linear-gradient(var(--line2), var(--line2)) no-repeat 0 0 / 1px 100%,
linear-gradient(var(--line2), var(--line2)) no-repeat 100% 0 / 1px 100%;
}
.zj-hs li {
display: grid;
gap: 4px;
padding: 0 26px;
}
.zj-hs b {
color: var(--acc);
font: 700 13px var(--mono);
letter-spacing: 0.1em;
}
/* провод между сторонами со стрелкой и бегущим пакетом */
.zj-wire {
position: relative;
height: 9px;
margin: 4px -26px 10px;
background: linear-gradient(var(--line2), var(--line2)) no-repeat 0 50% / 100% 1px;
}
.zj-wire::after {
position: absolute;
top: 0;
right: 1px;
content: "";
border: solid transparent;
border-width: 4.5px 0 4.5px 8px;
border-left-color: var(--mut);
}
.zj-wire::before {
position: absolute;
top: 0;
left: 0;
width: 9px;
height: 9px;
content: "";
background: var(--acc);
opacity: 0;
animation: zj-pk 5.4s cubic-bezier(0.5, 0, 0.3, 1) calc(var(--n) * 1.6s) infinite;
}
@keyframes zj-pk {
0% { left: 0; opacity: 0; }
3% { opacity: 1; }
26% { left: calc(100% - 18px); opacity: 1; }
30%, 100% { left: calc(100% - 18px); opacity: 0; }
}
/* ответ сервера идёт справа налево */
.zj-back {
text-align: right;
}
.zj-back .zj-wire {
scale: -1 1;
}
.zj-hs strong {
font-family: var(--disp);
font-size: clamp(17px, 2vw, 21px);
font-weight: 600;
}
.zj-hs li > span {
color: var(--mut);
font-size: 15px;
}
.zj-cta {
display: flex;
flex-wrap: wrap;
gap: 16px 36px;
align-items: center;
margin-top: 30px;
}
.zj-cta p {
flex: 1 1 320px;
color: var(--mut);
}
.zj-cta p b {
display: block;
margin-bottom: 4px;
color: #37e39a;
font: 700 13px var(--mono);
letter-spacing: 0.1em;
}
/* ═══════════════════════════════════════════════════════════════════
Мини-игры
═══════════════════════════════════════════════════════════════════ */
.zg-badge {
display: inline-block;
width: max-content;
color: var(--gold);
font: 12.5px var(--mono);
letter-spacing: 0.04em;
}
/* ── «Спасите пакеты» ── */
.zg {
position: relative;
margin-top: clamp(40px, 5vw, 64px);
overflow: hidden;
}
.zg-top {
display: flex;
flex-wrap: wrap;
gap: 12px 24px;
align-items: flex-end;
justify-content: space-between;
}
.zg-title {
display: grid;
gap: 4px;
}
.zg-title strong {
font: 700 20px var(--disp);
}
.zg-title > span:last-child {
color: var(--mut);
font-size: 14px;
}
.zg-score {
display: flex;
gap: 18px;
color: var(--dim);
font: 12.5px var(--mono);
}
.zg-score b {
display: block;
color: var(--ink);
font: 700 22px var(--disp);
font-variant-numeric: tabular-nums;
}
.zg-score span:first-child b { color: var(--acc); }
.zg-score span:nth-child(2) b { color: #ff6b83; }
.zg-score span:nth-child(3) b { color: var(--gold); }
.zg-canvas {
display: block;
width: 100%;
height: 170px;
cursor: crosshair;
touch-action: manipulation;
}
.zg-toast {
position: absolute;
bottom: 14px;
left: 50%;
display: flex;
flex-wrap: wrap;
gap: 4px 8px;
align-items: center;
justify-content: center;
width: max-content;
max-width: calc(100% - 28px);
padding: 10px 16px;
font-size: 14px;
text-align: center;
border-radius: 8px;
background: rgba(10, 12, 26, 0.94);
transform: translateX(-50%);
animation: zg-toast 0.5s cubic-bezier(0.3, 1.6, 0.5, 1);
}
.zg-toast[hidden] {
display: none;
}
.zg-toast b {
color: var(--gold);
}
.zg-toast span {
color: var(--mut);
}
.zpm-home .zg-toast a {
color: var(--acc);
font-weight: 700;
text-decoration: underline;
text-underline-offset: 3px;
}
@keyframes zg-toast {
from { opacity: 0; transform: translate(-50%, 20px) scale(0.9); }
}
/* ── «Сломайте замок РКН» ── */
.zlock {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: clamp(20px, 2.6vw, 36px);
align-items: center;
}
.zlock-hit {
position: relative;
padding: 0;
cursor: pointer;
border: 0;
background: none;
-webkit-tap-highlight-color: transparent;
user-select: none;
}
.zlock-svg {
display: block;
width: clamp(120px, 12vw, 160px);
overflow: visible;
filter: drop-shadow(0 0 24px rgba(255, 59, 92, 0.45));
transition: transform 0.1s;
}
.zlock-hit:hover .zlock-svg {
transform: scale(1.04) rotate(-2deg);
}
.zlock-hit:active .zlock-svg {
transform: scale(0.94);
}
.zl-shackle {
fill: none;
stroke: #c9cfe0;
stroke-width: 12;
stroke-linecap: round;
transform-box: fill-box;
transform-origin: 100% 100%;
}
.zl-body {
fill: #2a0712;
stroke: #ff3b5c;
stroke-width: 3;
}
.zl-half {
transform-box: fill-box;
}
.zl-label {
fill: #ff6b83;
font: 800 20px var(--disp);
text-anchor: middle;
letter-spacing: 0.1em;
}
.zl-key {
fill: none;
stroke: #ff6b83;
stroke-width: 4;
stroke-linecap: round;
}
.zl-crack {
fill: none;
stroke: #ffe3a3;
stroke-width: 2.5;
stroke-linejoin: round;
opacity: 0;
filter: drop-shadow(0 0 4px var(--gold));
transition: opacity 0.2s;
}
.zl-crack.on {
opacity: 1;
}
.zlock.hit .zlock-svg {
animation: zl-shake 0.25s;
}
@keyframes zl-shake {
25% { transform: translate(-5px, 2px) rotate(-4deg); }
50% { transform: translate(5px, -2px) rotate(3deg); }
75% { transform: translate(-3px, 1px) rotate(-2deg); }
}
.zlock.broken .zl-shackle {
animation: zl-fly 0.9s cubic-bezier(0.3, 0, 0.7, 1) forwards;
}
.zlock.broken .zl-half-l {
animation: zl-fall-l 1s cubic-bezier(0.5, 0, 0.8, 0.4) 0.1s forwards;
}
.zlock.broken .zl-half-r {
animation: zl-fall-r 1s cubic-bezier(0.5, 0, 0.8, 0.4) 0.1s forwards;
}
.zlock.broken .zl-label,
.zlock.broken .zl-key,
.zlock.broken .zl-crack {
opacity: 0;
transition: opacity 0.2s;
}
@keyframes zl-fly {
to { transform: translate(40px, -90px) rotate(70deg); opacity: 0; }
}
@keyframes zl-fall-l {
to { transform: translate(-30px, 80px) rotate(-35deg); opacity: 0; }
}
@keyframes zl-fall-r {
to { transform: translate(30px, 80px) rotate(35deg); opacity: 0; }
}
.zlock-open {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
overflow: visible;
opacity: 0;
pointer-events: none;
filter: drop-shadow(0 0 24px rgba(55, 227, 154, 0.55));
transform: scale(0.4);
}
.zlock.broken .zlock-open {
opacity: 1;
transform: none;
transition: opacity 0.4s 0.8s, transform 0.6s cubic-bezier(0.3, 1.7, 0.5, 1) 0.8s;
animation: zo-float 3s ease-in-out 1.5s infinite;
}
@keyframes zo-float {
50% { translate: 0 -6px; }
}
.zo-shackle {
fill: none;
stroke: #c9ffe6;
stroke-width: 12;
stroke-linecap: round;
}
.zo-body {
fill: rgba(55, 227, 154, 0.18);
stroke: #37e39a;
stroke-width: 3;
}
.zo-ok {
fill: none;
stroke: #37e39a;
stroke-width: 9;
stroke-linecap: round;
stroke-linejoin: round;
}
.zlock-fx {
position: absolute;
inset: 0;
pointer-events: none;
}
.zlock-fx i {
position: absolute;
top: 55%;
left: 50%;
width: 7px;
height: 7px;
border-radius: 50%;
background: #fff3c4;
box-shadow: 0 0 8px 2px var(--gold);
animation: zl-spark 0.6s ease-out forwards;
}
.zlock-fx i.cf {
width: 8px;
height: 12px;
border-radius: 2px;
box-shadow: none;
background: var(--c);
animation: zl-confetti 1.6s cubic-bezier(0.2, 0.6, 0.4, 1) forwards;
}
.zlock-fx b {
position: absolute;
top: 30%;
left: 50%;
color: var(--gold);
font: 800 20px var(--disp);
white-space: nowrap;
text-shadow: 0 0 10px rgba(255, 159, 67, 0.8);
animation: zl-num 0.8s ease-out forwards;
}
.zlock-fx b.crit {
color: #ff5a74;
font-size: 26px;
}
@keyframes zl-spark {
to { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(0.3); }
}
@keyframes zl-confetti {
to { opacity: 0; transform: translate(var(--dx), var(--dy)) rotate(var(--r)); }
}
@keyframes zl-num {
from { opacity: 1; transform: translate(-50%, 0) scale(1.3); }
to { opacity: 0; transform: translate(calc(-50% + var(--dx, 0px)), -60px) scale(1); }
}
.zlock-copy {
display: grid;
gap: 10px;
}
.zlock-name {
font-size: clamp(22px, 2.2vw, 28px);
line-height: 1.15;
}
.zlock-t {
color: var(--mut);
}
.zlock-t b {
color: var(--gold);
font-variant-numeric: tabular-nums;
}
.zlock-hp {
height: 10px;
max-width: 420px;
overflow: hidden;
border-radius: 999px;
background: rgba(255, 59, 92, 0.15);
}
.zlock-hp i {
display: block;
width: 100%;
height: 100%;
border-radius: inherit;
background: var(--red);
transition: width 0.25s cubic-bezier(0.3, 1.4, 0.5, 1);
}
.zlock-win {
display: grid;
gap: 14px;
animation: zh-pop 0.6s cubic-bezier(0.2, 0.9, 0.3, 1.4);
}
.zlock-win[hidden] {
display: none;
}
.zlock-win b {
color: #37e39a;
}
.zlock-btns {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.zlock.broken .zlock-win .zb-main {
animation: zl-glow 1.4s ease-in-out infinite;
}
@keyframes zl-glow {
50% { background: var(--gold); }
}
@media (max-width: 640px) {
.zlock {
grid-template-columns: minmax(0, 1fr);
justify-items: center;
text-align: center;
}
.zlock-hp {
margin-inline: auto;
width: 100%;
}
.zlock-btns {
justify-content: center;
}
.zg-canvas {
height: 150px;
}
.zg-score {
gap: 14px;
}
}
/* ═══════════════════════════════════════════════════════════════════
Появление при прокрутке. Классы ставит home.js и только тем блокам,
что ниже первого экрана, — без JS всё видно сразу.
Анимируются отдельные свойства translate/rotate/scale: так они не
перебивают transform, который блоки используют при наведении.
═══════════════════════════════════════════════════════════════════ */
.rv-wait {
opacity: 0;
}
.rv-in {
animation: rv-up 0.85s cubic-bezier(0.2, 0.8, 0.2, 1) calc(var(--rv, 0) * 90ms) both;
}
.rv-in.rv-card {
animation-name: rv-card;
animation-duration: 1s;
}
.rv-in.rv-side {
animation-name: rv-side;
}
.rv-in.rv-pop {
animation-name: rv-pop;
animation-duration: 0.6s;
animation-timing-function: cubic-bezier(0.2, 0.9, 0.3, 1.45);
}
.za-grid {
perspective: 1400px;
}
@keyframes rv-up {
from { opacity: 0; translate: 0 34px; }
}
@keyframes rv-card {
from { opacity: 0; translate: 0 70px; rotate: x 16deg; scale: 0.96; }
}
@keyframes rv-side {
from { opacity: 0; translate: 48px 0; }
}
@keyframes rv-pop {
from { opacity: 0; scale: 0.75; translate: 0 14px; }
}
/* заголовки секций — по словам */
.rv-words .rw {
display: inline-block;
}
.rv-in .rv-words .rw,
.rv-in.rv-words .rw {
animation: rv-word 0.7s cubic-bezier(0.2, 0.8, 0.2, 1) calc(0.1s + var(--w) * 70ms) both;
}
@keyframes rv-word {
from { opacity: 0; translate: 0 0.55em; rotate: 6deg; filter: blur(4px); }
}
/* ═══════════════════════════════════════════════════════════════════
Адаптив
═══════════════════════════════════════════════════════════════════ */
@media (max-width: 980px) {
.zh-grid,
.zt-grid,
.zj-pair {
grid-template-columns: minmax(0, 1fr);
}
.zh-art {
width: min(460px, 100%);
margin-inline: auto;
}
.zt-head {
position: static;
}
.zc-gui,
.zc-wide {
grid-template-columns: minmax(0, 1fr);
}
.zc-wide .zc-cover {
min-height: 0;
height: auto;
-webkit-mask-image: linear-gradient(to bottom, #000 60%, transparent);
mask-image: linear-gradient(to bottom, #000 60%, transparent);
}
}
@media (max-width: 760px) {
.za-grid {
grid-template-columns: minmax(0, 1fr);
}
.zj-help {
grid-template-columns: minmax(0, 1fr);
}
.zt-list a {
grid-template-columns: 40px minmax(0, 1fr);
padding: 18px 0;
}
.zt-list em {
display: none;
}
}
@media (max-width: 460px) {
.zs {
width: calc(100% - 32px);
}
.zh-actions .zb-main {
flex: 1 1 100%;
justify-content: center;
}
}
/* ═══════════════════════════════════════════════════════════════════
Меньше движения — по просьбе системы
═══════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
.zpm-home *,
.zpm-home *::before,
.zpm-home *::after {
animation: none !important;
transition: none !important;
}
.zh-chain,
.zh-lock,
.zh-bits,
.zh-free::after,
.zh-sparks,
.zh-scan,
.zh3-ecg-line,
.zfd-pkt {
display: none;
}
.zh-under path {
stroke-dashoffset: 0;
}
.zh-flip > span:first-child {
opacity: 1;
}
}
/* ═══════════════════════════════════════════════════════════════════
Своё контекстное меню (правая кнопка). Shift + ПКМ — меню браузера.
═══════════════════════════════════════════════════════════════════ */
.zcm {
position: fixed;
z-index: 10001;
min-width: 250px;
max-width: 320px;
padding: 6px;
color: #e8efff;
font: 14px/1.3 "Onest", system-ui, sans-serif;
border-radius: 10px;
background: rgba(13, 15, 22, 0.94);
box-shadow: 0 24px 60px -12px rgba(0, 0, 0, 0.8);
backdrop-filter: blur(16px) saturate(1.4);
transform-origin: var(--ox, 0) var(--oy, 0);
animation: zcm-in 0.18s cubic-bezier(0.2, 0.9, 0.3, 1.2);
user-select: none;
}
.zcm[hidden] {
display: none;
}
@keyframes zcm-in {
from { opacity: 0; transform: scale(0.88); filter: blur(4px); }
}
.zcm-head {
display: flex;
gap: 10px;
align-items: center;
margin: 2px 2px 6px;
padding: 8px 10px;
border-radius: 11px;
background: linear-gradient(100deg, rgba(91, 127, 255, 0.14), rgba(155, 123, 255, 0.12));
}
.zcm-head img {
width: 28px;
height: 28px;
border-radius: 50%;
box-shadow: 0 0 0 2px #5b7fff;
}
.zcm-head b {
display: block;
font: 700 13px "Unbounded", sans-serif;
}
.zcm-head small {
color: #a9a69f;
font-size: 11.5px;
}
.zcm-row {
display: flex;
gap: 4px;
margin: 0 2px 4px;
}
.zcm-row button {
flex: 1;
display: grid;
place-items: center;
height: 36px;
padding: 0;
color: #cbd6f5;
cursor: pointer;
border: 0;
border-radius: 10px;
background: rgba(255, 255, 255, 0.04);
}
.zcm-row button:hover,
.zcm-row button.on {
color: #031024;
background: #5b7fff;
}
.zcm-row button:disabled {
opacity: 0.35;
pointer-events: none;
}
.zcm svg {
width: 17px;
height: 17px;
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
.zcm-sep {
height: 1px;
margin: 5px 8px;
background: rgba(120, 160, 255, 0.16);
}
.zcm-lbl {
padding: 6px 12px 3px;
overflow: hidden;
color: #6f6d69;
font: 11px ui-monospace, monospace;
white-space: nowrap;
text-overflow: ellipsis;
}
.zcm-it {
position: relative;
display: flex;
gap: 12px;
align-items: center;
width: 100%;
padding: 9px 12px;
color: inherit;
font: inherit;
text-align: left;
cursor: pointer;
border: 0;
border-radius: 10px;
background: none;
transition: background 0.12s;
}
.zcm-it svg {
flex: none;
color: #5b7fff;
}
.zcm-it kbd {
margin-left: auto;
color: #6f6d69;
font: 11px ui-monospace, monospace;
}
.zcm-it:hover,
.zcm-it.on {
background: rgba(91, 127, 255, 0.14);
}
.zcm-it.on::before {
position: absolute;
top: 8px;
bottom: 8px;
left: 0;
width: 3px;
content: "";
border-radius: 3px;
background: #5b7fff;
}
.zcm-it.hot svg {
color: #ff6b83;
}
.zcm-it.hot {
background: linear-gradient(100deg, rgba(255, 59, 92, 0.14), transparent);
}
.zcm-it.hot:hover,
.zcm-it.hot.on {
background: linear-gradient(100deg, rgba(255, 59, 92, 0.28), rgba(255, 59, 92, 0.06));
}
.zcm-foot {
padding: 6px 12px 4px;
color: #6f6d69;
font-size: 11px;
}
.zcm-toast {
position: fixed;
bottom: 24px;
left: 50%;
z-index: 10002;
padding: 9px 16px;
color: #031024;
font: 600 13px "Onest", sans-serif;
border-radius: 999px;
background: #f2eee6;
transform: translateX(-50%);
animation: zcm-toast 1.8s ease forwards;
pointer-events: none;
}
@keyframes zcm-toast {
0% { opacity: 0; transform: translate(-50%, 12px); }
12%, 80% { opacity: 1; transform: translate(-50%, 0); }
100% { opacity: 0; transform: translate(-50%, -6px); }
}
@media (prefers-reduced-motion: reduce) {
.zcm, .zcm-toast { animation: none; }
}
/* ═══════════════════════════════════════════════════════════════════
Курсор-пакет и «блокировка» по клику (home.js включает на мыши)
═══════════════════════════════════════════════════════════════════ */
html.zcur-on {
--zheart: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 110'%3E%3Cpath d='M60 104C20 76 6 56 6 34 6 18 18 6 33 6c12 0 21 7 27 18C66 13 75 6 87 6c15 0 27 12 27 28 0 22-14 42-54 70z'/%3E%3C/svg%3E");
}
html.zcur-on,
html.zcur-on body,
html.zcur-on a,
html.zcur-on button,
html.zcur-on [role="button"],
html.zcur-on .zx,
html.zcur-on canvas,
html.zcur-on .zlock-hit,
html.zcur-on .zp-chart svg {
cursor: none !important;
}
html.zcur-on input,
html.zcur-on textarea {
cursor: text !important;
}
.zcur-fx {
position: fixed;
inset: 0;
z-index: 10003;
width: 100vw;
height: 100vh;
pointer-events: none;
}
.zcur-dot,
.zcur-ring {
position: fixed;
top: 0;
left: 0;
z-index: 10004;
pointer-events: none;
will-change: transform;
}
.zcur-dot {
width: 12px;
height: 9px;
margin: -4.5px 0 0 -6px;
border-radius: 3px;
background: #f2eee6;
transition: width 0.2s, height 0.2s, margin 0.2s, background 0.2s, border-radius 0.2s, opacity 0.2s;
}
.zcur-ring {
width: 34px;
height: 34px;
margin: -17px 0 0 -17px;
border: 1.5px solid rgba(91, 127, 255, 0.55);
border-radius: 50%;
transition: width 0.25s cubic-bezier(0.3, 1.4, 0.5, 1), height 0.25s cubic-bezier(0.3, 1.4, 0.5, 1), margin 0.25s cubic-bezier(0.3, 1.4, 0.5, 1), border-color 0.2s, background 0.2s, border-radius 0.25s;
}
.zcur-link .zcur-ring {
width: 54px;
height: 54px;
margin: -27px 0 0 -27px;
border-color: #5b7fff;
background: rgba(91, 127, 255, 0.1);
}
.zcur-link .zcur-dot {
width: 6px;
height: 6px;
margin: -3px 0 0 -3px;
border-radius: 50%;
}
/* над РКН-тян: вращающийся красный прицел ТСПУ.
Пунктир — conic-gradient с поворотом через --zang: свойство rotate
нельзя, оно повернуло бы и смещение курсора из transform. */
.zcur-rkn .zcur-ring {
width: 62px;
height: 62px;
margin: -31px 0 0 -31px;
border: 0;
background: repeating-conic-gradient(from var(--zang), #ff3b5c 0 14deg, transparent 14deg 28deg);
-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2px));
mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2px));
filter: drop-shadow(0 0 6px #ff3b5c);
animation: zcur-spin 2.2s linear infinite;
}
@keyframes zcur-spin {
to { --zang: 360deg; }
}
.zcur-rkn .zcur-dot {
background: #ffb3c0;
box-shadow: 0 0 8px #ff3b5c;
}
.zcur-rkn .zcur-dot::before,
.zcur-rkn .zcur-dot::after {
position: absolute;
top: 50%;
left: 50%;
content: "";
background: rgba(255, 59, 92, 0.85);
}
.zcur-rkn .zcur-dot::before { width: 80px; height: 1px; margin-left: -40px; }
.zcur-rkn .zcur-dot::after { width: 1px; height: 80px; margin-top: -40px; }
.zcur-text .zcur-ring {
width: 3px;
height: 28px;
margin: -14px 0 0 -1.5px;
border: 0;
border-radius: 2px;
background: #5b7fff;
}
.zcur-text .zcur-dot {
opacity: 0;
}
.zcur-down .zcur-ring {
width: 22px;
height: 22px;
margin: -11px 0 0 -11px;
}
.zcur-hide .zcur-dot,
.zcur-hide .zcur-ring {
opacity: 0;
}
/* пока идёт заставка, всё под ней стоит на паузе — вся мощность уходит на заставку */
.zpm-intro-on .zpm-home > :not(.zx) *,
.zpm-intro-on .zpm-home > :not(.zx) *::before,
.zpm-intro-on .zpm-home > :not(.zx) *::after {
animation-play-state: paused !important;
}
/* ── сердечки, всплывающие из сердца в блоке поддержки ── */
.zj-hearts {
position: absolute;
inset: auto -10% 25%;
height: 10px;
pointer-events: none;
}
.zj-hearts i {
position: absolute;
bottom: 0;
left: var(--x);
width: 18px;
height: 16px;
background: hsl(var(--h) 90% 66%);
-webkit-mask: var(--heart) center / contain no-repeat;
mask: var(--heart) center / contain no-repeat;
opacity: 0;
scale: var(--s);
will-change: transform, opacity;
animation: zj-float var(--t) ease-in var(--d) infinite;
}
@keyframes zj-float {
0% { opacity: 0; transform: translate(0, 0) rotate(0); }
12% { opacity: 0.95; }
50% { transform: translate(var(--w), -120px) rotate(12deg); }
100% { opacity: 0; transform: translate(calc(var(--w) * -0.6), -250px) rotate(-10deg); }
}
.zj-help {
overflow: visible;
}
/* ── курсор-сердечко: в поддержке, у замка и на ссылках на донат ── */
.zcur-love .zcur-dot {
width: 22px;
height: 20px;
margin: -10px 0 0 -11px;
border-radius: 0;
background: transparent;
box-shadow: none;
}
.zcur-love .zcur-dot::before {
position: absolute;
inset: 0;
content: "";
background: linear-gradient(160deg, #ff8fa8, #ff3b5c);
-webkit-mask: var(--zheart) center / contain no-repeat;
mask: var(--zheart) center / contain no-repeat;
filter: drop-shadow(0 0 6px #ff3b5c);
animation: zcur-beat 0.9s cubic-bezier(0.3, 0, 0.3, 1) infinite;
}
@keyframes zcur-beat {
0%, 100% { transform: scale(1); }
14% { transform: scale(1.3); }
28% { transform: scale(0.95); }
42% { transform: scale(1.15); }
}
.zcur-love .zcur-ring {
width: 46px;
height: 46px;
margin: -23px 0 0 -23px;
border-color: rgba(255, 107, 131, 0.6);
background: rgba(255, 59, 92, 0.08);
}
/* блоки вне экрана стоят на паузе (класс ставит home.js): бесконечные анимации
не пересчитывают стили, пока их никто не видит */
.zoff *,
.zoff *::before,
.zoff *::after {
animation-play-state: paused !important;
}
/* ── WebGL-риг (rig.js): пока он рисует, CSS-слои персонажа спрятаны ── */
.zr-glc {
pointer-events: none;
}
.zr-gl-on .zr-base,
.zr-gl-on .zr-rim,
.zr-gl-on .zr-hair,
.zr-gl-on .zr-hand,
.zr-gl-on .zr-arm {
visibility: hidden;
animation: none;
}
/* ── Адреса сайта ───────────────────────────────────────────────────
Виджет общий с вики (/_sites/mirrors-widget.js): цвета и шрифты он берёт отсюда. */
.zm-sec {
padding: clamp(56px, 7vw, 88px) 0 0;
}
.zm-sec [data-zapret-mirrors] {
--zm-ink: var(--ink);
--zm-mut: var(--mut);
--zm-dim: var(--dim);
--zm-acc: var(--acc);
--zm-line: var(--line);
--zm-bg: var(--bg);
--zm-on-acc: #fff;
--zm-disp: var(--disp);
--zm-txt: var(--txt);
--zm-mono: var(--mono);
min-height: 420px;
}