/* Cormorant Garamond */
@font-face {
    font-display: swap;
    font-family: 'Cormorant Garamond';
    font-style: normal;
    font-weight: 300;
    src: url('../fonts/cormorant-garamond-v21-cyrillic_latin-300.woff2') format('woff2');
}
@font-face {
    font-display: swap;
    font-family: 'Cormorant Garamond';
    font-style: italic;
    font-weight: 300;
    src: url('../fonts/cormorant-garamond-v21-cyrillic_latin-300italic.woff2') format('woff2');
}
@font-face {
    font-display: swap;
    font-family: 'Cormorant Garamond';
    font-style: normal;
    font-weight: 400;
    src: url('../fonts/cormorant-garamond-v21-cyrillic_latin-regular.woff2') format('woff2');
}

/* Inter */
@font-face {
    font-display: swap;
    font-family: 'Inter';
    font-style: normal;
    font-weight: 300;
    src: url('../fonts/inter-v20-cyrillic_latin-300.woff2') format('woff2');
}
@font-face {
    font-display: swap;
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400;
    src: url('../fonts/inter-v20-cyrillic_latin-regular.woff2') format('woff2');
}
/* JetBrains Mono — второй голос: номера, метки, технические подписи.
   Кириллица и латиница разными файлами: браузер возьмёт только нужный. */
@font-face {
    font-display: swap;
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-weight: 300;
    src: url('../fonts/jetbrains-mono-latin-300.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2070-209F, U+20A0-20AB, U+2113, U+2122, U+2190-2199;
}
@font-face {
    font-display: swap;
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-weight: 300;
    src: url('../fonts/jetbrains-mono-cyrillic-300.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-display: swap;
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-weight: 400;
    src: url('../fonts/jetbrains-mono-latin-400.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2070-209F, U+20A0-20AB, U+2113, U+2122, U+2190-2199;
}
@font-face {
    font-display: swap;
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-weight: 400;
    src: url('../fonts/jetbrains-mono-cyrillic-400.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

/* EB Garamond — голос документа: юридические страницы набраны им.
   Старая антиква с наклонными засечками: ближе всего к письму пером. */
@font-face {
    font-display: swap;
    font-family: 'EB Garamond';
    font-style: normal;
    font-weight: 400;
    src: url('../fonts/eb-garamond-latin-400.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2070-209F, U+20A0-20AB, U+2113, U+2122, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-display: swap;
    font-family: 'EB Garamond';
    font-style: normal;
    font-weight: 400;
    src: url('../fonts/eb-garamond-cyrillic-400.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-display: swap;
    font-family: 'EB Garamond';
    font-style: italic;
    font-weight: 400;
    src: url('../fonts/eb-garamond-latin-400-italic.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2070-209F, U+20A0-20AB, U+2113, U+2122, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-display: swap;
    font-family: 'EB Garamond';
    font-style: italic;
    font-weight: 400;
    src: url('../fonts/eb-garamond-cyrillic-400-italic.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

html {
    scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }
}

body {
    background-color: #ffffff;
    color: #0A0A0A;
    font-family: 'Inter', sans-serif;
}

/* ---------- Первый экран: надпись из точек ---------- */

/* Слово в 3,63 раза шире кегля. 23vw — это около восьмидесяти процентов
   ширины экрана; по высоте держим не больше 46svh, иначе на широком и
   низком окне оно налезет на шапку или подпись внизу. */
.hero-word {
    font-size: max(64px, min(23vw, 46svh));
    letter-spacing: -0.015em;
    line-height: 1;
    transition: opacity 0.5s ease;
}

/* На телефоне кегль мал, и светлое начертание даёт штрихи в пару точек:
   облако выходит бледным. Обычное начертание вдвое толще в штрихе.
   Класс font-light в разметке перебиваем здесь намеренно. */
@media (max-width: 767px) {
    .hero-word { font-weight: 400; }
}

/* Холст лежит поверх текста и повторяет его место. */
.hero-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}

/* Настоящий текст с самого начала невидим: иначе он мелькает целиком,
   пока грузится скрипт, а потом исчезает, и точки собираются уже на
   пустом месте.
   Показывается текст в трёх случаях. Без WebGL скрипт ставит is-static.
   При выключенных скриптах его открывает правило в <noscript> на главной.
   Если скрипты включены, но файл не пришёл или упал, текст проявится сам
   через восемь секунд. Срок с запасом: на медленном мобильном интернете
   скрипт честно добирается секунды за три-четыре, и раньше времени
   показанное слово мелькнуло бы перед точками. */
@media (prefers-reduced-motion: no-preference) {
    .hero-word {
        opacity: 0;
        animation: hero-word-fallback 0.6s ease 8s forwards;
    }
    .hero-word.is-drawn { opacity: 0; animation: none; }
    .hero-word.is-static { opacity: 1; animation: none; }
}

@keyframes hero-word-fallback {
    to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .hero-canvas { display: none; }
}

/* ---------- Полоса «Прокрутите вниз» ---------- */

.hero-cue-line {
    position: relative;
    flex: 1;
    height: 1px;
    background: #E4E7EA;
    overflow: hidden;
    transition: background-color 0.45s ease;
}

/* Блик: отрезок в четверть линии, к переднему краю наливается цветом.
   Чтобы пройти линию от края до края, ему нужно 400 % своей ширины. */
.hero-cue-line::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 25%;
    background: linear-gradient(90deg, rgba(14, 110, 107, 0), #0E6E6B);
    transform: translateX(-100%);
    animation: cue-run 3.6s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}

@keyframes cue-run {
    0%       { transform: translateX(-100%); }
    55%, 100% { transform: translateX(400%); }
}

.hero-cue-arrow {
    font-size: 16px;
    animation: cue-dip 3.6s ease-in-out infinite;
}

/* Стрелка ныряет, когда блик добегает до конца линии: оба цикла одной
   длины и стартуют вместе, поэтому не расходятся. */
@keyframes cue-dip {
    0%, 50%   { transform: translateY(0); }
    62%       { transform: translateY(5px); }
    78%, 100% { transform: translateY(0); }
}

.hero-cue:hover .hero-cue-line { background-color: rgba(14, 110, 107, 0.35); }

@media (prefers-reduced-motion: reduce) {
    .hero-cue-line::after { display: none; }
    .hero-cue-arrow { animation: none; }
}

/* Предупреждение под полем пароля в AutoWin. Тон приглушённый:
   это не ошибка ввода, а то, что человек обязан знать заранее. */
.pw-warning {
    color: rgb(var(--status-degraded));
    margin-top: 2px;
}

/* Держатель общих <defs> для SVG. Ничего не рисует, но должен быть
   вынут из потока, иначе занимает строку в начале страницы. */
.offscreen-defs {
    position: absolute;
}

/* Цвета состояний. Тройками, а не hex: от них нужны полупрозрачные
   версии для свечения огонька. */
:root {
    --status-ok: 18 161 80;
    --status-degraded: 198 124 32;
    --status-down: 193 62 46;
    /* Проверка ещё идёт или не удалась — серое, а не тревожное. */
    --status-idle: 138 148 156;
}

/* Подложка под выделение — та же вода. */
::selection {
    background: #0E6E6B;
    color: #ffffff;
}

/* Кусочки текста на время смены языка: каждый двигается сам по себе.
   Слово целиком — чтобы перенос не рвал его посередине. */
.t-word {
    display: inline-block;
    white-space: nowrap;
}

.t-piece {
    display: inline-block;
    will-change: transform, opacity, filter;
}

/* ===== Юридические страницы: набор как в бумажном документе =====
   EB Garamond, тёплые чернила вместо типографской чёрной и широкий
   интерлиньяж: такой текст читают, а не проглядывают. */
.doc-text {
    color: #26221D;
    font-family: 'EB Garamond', 'Cormorant Garamond', serif;
    font-size: 19px;
    letter-spacing: 0.004em;
    line-height: 1.82;
}

.doc-lead {
    font-size: 23px;
    line-height: 1.66;
}

@media (max-width: 767px) {
    .doc-text { font-size: 17.5px; line-height: 1.78; }
    .doc-lead { font-size: 20px; }
}

/* Буквица вводного абзаца. */
.doc-drop::first-letter {
    color: #0E6E6B;
    float: left;
    font-size: 3.3em;
    font-style: italic;
    line-height: 0.86;
    padding: 0.04em 0.1em 0 0;
}

/* Перечисления внутри разделов: маркер — тонкое перо, а не точка. */
.doc-list li {
    padding-left: 30px;
    position: relative;
}

.doc-list li::before {
    background: #0E6E6B;
    content: '';
    height: 1px;
    left: 0;
    opacity: 0.55;
    position: absolute;
    top: 0.92em;
    width: 14px;
}

/* Линии, которые прочерчиваются пером при прокрутке. */
.doc-draw {
    color: #0E6E6B;
    display: block;
    height: auto;
    opacity: 0.65;
    width: 100%;
}

.doc-rule-line {
    height: 1px;
}

.doc-flourish {
    margin: 0 auto;
    width: min(240px, 66%);
}

/* Инлайновые SVG-иконки вместо шрифта Material Symbols.
   Размер задан в em, поэтому его по-прежнему можно менять
   классами вида text-[16px], как было у шрифтовых иконок. */
.icon {
    display: inline-block;
    width: 1em;
    height: 1em;
    font-size: 24px;
    fill: currentColor;
    flex-shrink: 0;
    vertical-align: middle;
}

/* ---------- Переписка в блоке вопросов ---------- */

.bubble {
    position: relative;
    max-width: 30rem;
    padding: 14px 20px;
    border-radius: 22px;
    font-size: 15px;
    line-height: 1.6;
    letter-spacing: 0.01em;
}

.bubble-ask {
    margin-left: auto;
    background: #0E6E6B;
    color: #ffffff;
    border-bottom-right-radius: 6px;
}

.bubble-reply {
    margin-right: auto;
    background: #F1F3F4;
    color: #0A0A0A;
    border-bottom-left-radius: 6px;
}

.bubble-reply a {
    color: #0A4F4D;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* Три точки «собеседник печатает». */
.typing {
    display: inline-flex;
    gap: 5px;
    align-items: center;
    padding: 16px 20px;
    border-radius: 22px;
    border-bottom-left-radius: 6px;
    background: #F1F3F4;
    width: fit-content;
}

.typing span {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #9AA4AD;
    animation: typing-bounce 1.3s ease-in-out infinite;
}

.typing span:nth-child(2) { animation-delay: 0.18s; }
.typing span:nth-child(3) { animation-delay: 0.36s; }

@keyframes typing-bounce {
    0%, 60%, 100% { transform: translateY(0); opacity: 0.45; }
    30%           { transform: translateY(-5px); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .typing span { animation: none; opacity: 0.6; }
}

/* ---------- Водная сцена ---------- */

/* Сцена занимает нижнюю полосу секции и растворяется кверху, чтобы
   не спорить с текстом, который лежит выше. */
#water-canvas {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 62%;
    pointer-events: none;
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 34%, #000 82%, transparent 100%);
    mask-image: linear-gradient(to bottom, transparent 0%, #000 34%, #000 82%, transparent 100%);
}

@media (max-width: 768px) {
    #water-canvas { height: 46%; }
}

/* Пословное появление заголовка. Без inline-block трансформация
   по вертикали к строчному элементу не применяется.
   Начального скрытия здесь нет намеренно: если скрипт не доедет,
   заголовок должен остаться читаемым. */
.word {
    display: inline-block;
    will-change: transform, opacity, filter;
}

/* ---------- Шапка ---------- */

/* Размеры шапки в двух состояниях. Наверху она во всю ширину; при
   прокрутке (is-floating) отходит от краёв на --nav-inset, опускается
   на --nav-top, становится ниже и скругляется в плашку. Скругление —
   ровно половина высоты, тогда торцы выходят полукруглыми.
   На компьютере плашка ещё и сужается до --nav-max по центру: как у
   Google, полоса не тянется через весь экран. */
#site-nav {
    --nav-h: 76px;
    --nav-pad: 20px;
    --nav-inset: 0px;
    --nav-top: 0px;
    --nav-radius: 0px;
    --nav-max: 100%;
}

#site-nav.is-floating {
    --nav-h: 56px;
    --nav-pad: 16px;
    --nav-inset: 8px;
    --nav-top: 8px;
    --nav-radius: 28px;
}

@media (min-width: 768px) {
    #site-nav { --nav-h: 88px; --nav-pad: 32px; }
    #site-nav.is-floating {
        --nav-h: 60px;
        --nav-pad: 26px;
        --nav-inset: 24px;
        --nav-top: 14px;
        --nav-radius: 30px;
        --nav-max: 640px;
    }
}

/* Одна кривая на все свойства: плашка отрывается быстро и мягко
   дотягивает до места. */
.site-nav {
    --nav-ease: cubic-bezier(0.16, 1, 0.3, 1);
    padding: var(--nav-top) var(--nav-inset) 0;
    pointer-events: none;
    transition: padding 0.6s var(--nav-ease), top 0.5s var(--nav-ease);
}

/* Пока сверху висит плашка с языком, шапка стоит под ней. Плавающая
   плашка шапки уже оторвалась от верха, ей отступ не нужен. */
html.has-lang-banner .site-nav:not(.is-floating) { top: var(--banner-h); }

/* Тени заданы одним списком в обоих состояниях, меняется только
   прозрачность. Иначе браузер не сможет плавно перейти от линии снизу
   к тени вокруг и переключит их скачком. Тень плашки взята у Google:
   0 1px 3px и 0 4px 8px при 8 % чёрного. Обводка у плашки заметная —
   12 % чёрного: на белом фоне одной тени мало, край плашки терялся. */
.nav-shell {
    height: var(--nav-h);
    max-width: var(--nav-max);
    margin-inline: auto;
    border-radius: var(--nav-radius);
    background: rgba(255, 255, 255, 0.72);
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    box-shadow:
        inset 0 -1px 0 rgba(228, 231, 234, 1),
        0 0 0 1px rgba(10, 10, 10, 0),
        0 1px 3px 0 rgba(0, 0, 0, 0),
        0 4px 8px 0 rgba(0, 0, 0, 0);
    pointer-events: auto;
    transition: height 0.6s var(--nav-ease), max-width 0.6s var(--nav-ease),
                border-radius 0.6s var(--nav-ease),
                box-shadow 0.4s ease, background-color 0.4s ease;
}

.is-floating .nav-shell {
    background: rgba(255, 255, 255, 0.86);
    box-shadow:
        inset 0 -1px 0 rgba(228, 231, 234, 0),
        0 0 0 1px rgba(10, 10, 10, 0.12),
        0 1px 3px 0 rgba(0, 0, 0, 0.08),
        0 4px 8px 0 rgba(0, 0, 0, 0.08);
}

.nav-inner {
    padding-inline: var(--nav-pad);
    transition: padding 0.6s var(--nav-ease);
}

/* Слева стоит стрелка, у неё есть свой переход цвета из .nav-link:
   перечисляем его заново, иначе это правило его затрёт. */
.nav-edge-left {
    left: var(--nav-pad);
    transition: left 0.6s var(--nav-ease), color 0.45s ease;
}

.nav-edge-right {
    right: var(--nav-pad);
    transition: right 0.6s var(--nav-ease);
}

.nav-link {
    color: #0A0A0A;
    transition: color 0.45s ease, opacity 0.3s ease;
}

.nav-link:hover { color: #0E6E6B; }

.nav-link.is-current {
    color: #0E6E6B;
    border-bottom: 1px solid #0E6E6B;
}

@media (prefers-reduced-motion: reduce) {
    .site-nav, .nav-shell, .nav-inner, .nav-edge-left, .nav-edge-right,
    .nav-link { transition: none; }
}

/* ---------- Стрелка на главную ---------- */

/* Поле вокруг стрелки шире её самой, чтобы по ней было легко попасть;
   отрицательный отступ возвращает стрелку к краю. */
.nav-back {
    display: inline-flex;
    padding: 8px;
    margin-left: -8px;
}

/* Под пунктами меню оставлено место для линии текущего раздела, поэтому
   их буквы стоят чуть выше середины шапки. Лишний низ поднимает стрелку
   на ту же высоту. */
#site-nav .nav-back { padding-bottom: 14px; }

.nav-back .icon { font-size: 22px; }

/* Окно ровно в одну стрелку. Вторая ждёт за правым краем: при наведении
   первая уезжает влево, вторая приходит на её место. */
.nav-back-mask {
    display: block;
    width: 22px;
    height: 22px;
    overflow: hidden;
    animation: nav-back-in 0.9s cubic-bezier(0.16, 1, 0.3, 1) 0.15s both;
}

.nav-back-track {
    display: flex;
    width: 44px;
    transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1);
}

.nav-back:hover .nav-back-track,
.nav-back:focus-visible .nav-back-track { transform: translateX(-22px); }

/* При открытии страницы стрелка въезжает справа и проявляется. */
@keyframes nav-back-in {
    from { opacity: 0; transform: translateX(14px); }
}

@media (prefers-reduced-motion: reduce) {
    .nav-back-mask { animation: none; }
    .nav-back-track { transition: none; }
    .nav-back:hover .nav-back-track,
    .nav-back:focus-visible .nav-back-track { transform: none; }
}

/* ---------- Пункты меню: подмена строки ---------- */

/* На телефоне пункты стоят в той же строке, что стрелка и язык, поэтому
   промежутки между ними вдвое уже. На самых узких экранах (320–359 px)
   сжимается и разрядка, иначе AUTOWIN упирается в стрелку. */
.nav-items { gap: 24px; }

@media (min-width: 768px) {
    .nav-items { gap: 48px; }
}

@media (max-width: 359px) {
    .nav-items { gap: 16px; }
    .nav-items .nav-item { letter-spacing: 0.14em; }
}


.nav-item {
    display: inline-block;
    font-family: 'Cormorant Garamond', serif;
    font-size: 14px;
    font-weight: 300;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    padding-bottom: 5px;
    border-bottom: 1px solid transparent;
    transition: border-color 0.45s ease, color 0.45s ease;
}

/* Обрезка: наружу видна ровно одна строка. */
.nav-item-mask {
    display: block;
    overflow: hidden;
    height: 1.25em;
}

.nav-item-inner {
    display: block;
    transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}

.nav-item-line {
    display: block;
    line-height: 1.25em;
}

.nav-item:hover .nav-item-inner { transform: translateY(-1.25em); }

/* Текущий раздел отмечен линией, она остаётся на месте при наведении. */
.nav-item.is-current { border-bottom-color: #0E6E6B; }

@media (prefers-reduced-motion: reduce) {
    .nav-item, .nav-item-inner { transition: none; }
    .nav-item:hover .nav-item-inner { transform: none; }
    .nav-item:hover { color: #0E6E6B; }
}

/* ---------- Карточка с кодом ---------- */

.code-card {
    border: 1px solid #E4E7EA;
    background: #FBFCFC;
    overflow: hidden;
}

.code-card-bar {
    padding: 11px 18px;
    border-bottom: 1px solid #E4E7EA;
    background: #F4F6F7;
}

.code-card-body {
    margin: 0;
    padding: 22px 20px 24px;
    overflow-x: auto;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12.5px;
    font-weight: 400;
    line-height: 1.85;
    color: #0A0A0A;
    tab-size: 4;
}

@media (min-width: 768px) {
    .code-card-body { font-size: 13px; padding: 26px 26px 28px; }
}

/* Подсветка в палитре сайта, без посторонних цветов. */
.c-cm { color: #8A949C; font-style: italic; }   /* комментарий */
.c-kw { color: #0A4F4D; font-weight: 400; }     /* ключевое слово */
.c-fn { color: #0E6E6B; }                        /* вызов функции */
.c-st { color: #B84B78; }                        /* строка */
.c-re { color: #9A5A86; }                        /* регулярное выражение */
.c-op { color: #97A1A9; }                        /* знаки препинания */

/* ---------- Значки платформ в карточках продуктов ---------- */

.plat-icon {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    overflow: visible;
}

.plat-icon.apple { width: 30px; height: 30px; }

/* Створки загораются по очереди — продукт «собирается», а не просто лежит. */
.plat-icon .pane {
    animation: pane-glow 3.2s ease-in-out infinite;
    transform-origin: 50% 50%;
}

.plat-icon .pane:nth-child(1) { animation-delay: 0s; }
.plat-icon .pane:nth-child(2) { animation-delay: 0.16s; }
.plat-icon .pane:nth-child(3) { animation-delay: 0.48s; }
.plat-icon .pane:nth-child(4) { animation-delay: 0.32s; }

/* Второй значок идёт со сдвигом, иначе два значка мигали бы в такт
   и это читалось бы как мерцание, а не как движение. */
.plat-icon.win11 .pane { animation-delay: 1.6s; }
.plat-icon.win11 .pane:nth-child(2) { animation-delay: 1.76s; }
.plat-icon.win11 .pane:nth-child(3) { animation-delay: 2.08s; }
.plat-icon.win11 .pane:nth-child(4) { animation-delay: 1.92s; }

@keyframes pane-glow {
    0%, 100% { opacity: 0.42; }
    45%      { opacity: 1; }
}

/* По яблоку медленно проходит отблеск. Прямоугольник с градиентом
   едет под маской силуэта — так видно только внутри значка. */
.plat-icon.apple .sheen {
    animation: apple-sheen 4.6s ease-in-out infinite;
}

@keyframes apple-sheen {
    0%        { transform: translateX(0); }
    55%, 100% { transform: translateX(52px); }
}

/* Метка «скоро» */
.soon-pill {
    padding: 5px 11px;
    border: 1px solid #0E6E6B;
    color: #0E6E6B;
    border-radius: 999px;
    white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
    .plat-icon .pane { animation: none; opacity: 1; }
    .plat-icon.apple .sheen { animation: none; opacity: 0; }
}

/* ---------- Плашка «сайт есть на вашем языке» ---------- */

/* Лежит в начале страницы и уезжает вместе с ней при прокрутке, как у
   Apple. Высота задана числом: на неё же опускается шапка. */
:root { --banner-h: 48px; }

.lang-banner {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 51;
    height: var(--banner-h);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    padding: 0 56px;
    background: #F4F6F7;
    border-bottom: 1px solid #E4E7EA;
    font-family: 'Inter', sans-serif;
    font-size: 13px;
    font-weight: 400;
    color: #0A0A0A;
    transform: translateY(-100%);
    transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}

/* Атрибут hidden сам по себе проигрывает display: flex выше. */
.lang-banner[hidden] { display: none; }

html.has-lang-banner .lang-banner { transform: none; }

.lang-banner-flag { width: 21px; height: 14px; flex: none; }

.lang-banner-text { margin: 0; white-space: nowrap; }

.lang-banner-go {
    color: #0E6E6B;
    white-space: nowrap;
    border-bottom: 1px solid rgba(14, 110, 107, 0.35);
    transition: border-color 0.3s ease, color 0.3s ease;
}

.lang-banner-go:hover { color: #0A4F4D; border-color: #0A4F4D; }

.lang-banner-close {
    position: absolute;
    right: 14px;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    padding: 8px;
    color: #5A6570;
    background: none;
    border: 0;
    cursor: pointer;
    transition: color 0.3s ease;
}

.lang-banner-close:hover { color: #0A0A0A; }
.lang-banner-close .icon { font-size: 18px; }

@media (max-width: 639px) {
    .lang-banner { gap: 10px; padding: 0 44px 0 16px; font-size: 12.5px; }
    .lang-banner-close { right: 6px; }
}

@media (prefers-reduced-motion: reduce) {
    .lang-banner { transition: none; }
}

/* ---------- Выбор языка ---------- */

.lang-wrap { position: relative; }

.lang-btn {
    display: inline-flex;
    align-items: center;
    padding-bottom: 5px;
    cursor: pointer;
}

.lang-btn .icon { font-size: 21px; }

.lang-menu {
    position: absolute;
    top: calc(100% + 16px);
    right: 0;
    min-width: 212px;
    padding: 8px;
    background: rgba(255, 255, 255, 0.94);
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    border: 1px solid #E4E7EA;
    box-shadow: 0 18px 48px rgba(10, 10, 10, 0.10);
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity 0.32s ease, transform 0.32s cubic-bezier(0.16, 1, 0.3, 1);
    z-index: 60;
}

.lang-menu.is-open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.lang-item {
    /* Выпадающий список — не текст, выделять его нечего. Заодно
       подложка выделения (та же вода) не ляжет поверх флага. */
    -webkit-user-select: none;
    user-select: none;
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    padding: 9px 11px;
    background: none;
    border: 0;
    cursor: pointer;
    text-align: left;
    transition: background 0.25s ease;
}

.lang-item:hover:not(.is-current) { background: #F4F6F7; }

/* Текущий язык — не ссылка: на нём и так стоишь. */
.lang-item.is-current { cursor: default; }

.lang-name {
    font-family: 'Inter', sans-serif;
    font-size: 13px;
    font-weight: 300;
    color: #0A0A0A;
    flex-grow: 1;
}

.lang-item.is-current .lang-name { color: #0E6E6B; }

/* Галочка стоит у всех доступных языков, показывается только у текущего:
   при смене языка без перезагрузки она просто переезжает. */
.lang-check {
    display: inline-flex;
    flex-shrink: 0;
    color: rgb(var(--status-ok));
    font-size: 15px;
    opacity: 0;
    transform: scale(0.5);
    transition: opacity 0.3s ease,
                transform 0.45s cubic-bezier(0.16, 1, 0.3, 1);
}

.lang-item.is-current .lang-check {
    opacity: 1;
    transform: scale(1);
}

/* ---------- Флаги: ткань колышется ---------- */

.flag {
    width: 24px;
    height: 16px;
    flex-shrink: 0;
    border-radius: 1.5px;
    overflow: hidden;
    /* Тонкая рамка: белые полосы иначе сливаются с подложкой. */
    box-shadow: 0 0 0 1px rgba(10, 10, 10, 0.10);
}

/* Движение собрано из двух слоёв с разными периодами: внешний качает
   флаг у древка, внутренний тянет полотно. Периоды не кратны друг другу,
   поэтому рисунок не повторяется и не выглядит заводным.
   Смещение по шуму тут не годится: на 24 точках оно корёжит форму,
   а не создаёт рябь. */
.flag-cloth {
    transform-origin: 0% 50%;
    animation: flag-wave 3.4s ease-in-out infinite;
}

.flag-ripple {
    transform-origin: 0% 50%;
    animation: flag-ripple 2.3s ease-in-out infinite;
}

@keyframes flag-ripple {
    0%, 100% { transform: scaleY(1)    translateY(0);      }
    35%      { transform: scaleY(1.06) translateY(-0.25px); }
    70%      { transform: scaleY(0.95) translateY(0.3px);   }
}

/* Блик проходит по флагу — тот самый перелив. */
.flag-sheen {
    animation: flag-sheen 5.2s ease-in-out infinite;
}

@keyframes flag-sheen {
    0%       { transform: translateX(0); }
    45%      { transform: translateX(48px); }
    100%     { transform: translateX(48px); }
}

.lang-item:nth-child(2) .flag-cloth { animation-delay: 0.25s; }

.lang-item:nth-child(2) .flag-sheen { animation-delay: 0.6s; }

@keyframes flag-wave {
    0%, 100% { transform: skewY(0deg)    rotate(0deg);     }
    30%      { transform: skewY(-2.4deg) rotate(-0.5deg);  }
    65%      { transform: skewY(2.1deg)  rotate(0.4deg);   }
}

/* На наведении ткань ходит заметнее — флаг «оживает» под курсором. */
.lang-item:hover:not(:disabled) .flag-cloth  { animation-duration: 1.5s; }
.lang-item:hover:not(:disabled) .flag-ripple { animation-duration: 1s; }
.lang-item:hover:not(:disabled) .flag-sheen  { animation-duration: 2.4s; }

/* ---------- Lab: набор статьи ----------
   Раньше эти правила лежали прямо в шаблоне и держались на своей
   палитре. Теперь они здесь и пользуются теми же токенами, что и
   остальной сайт. */

.prose p,
.prose li {
    color: rgba(10, 10, 10, 0.82);
    font-family: 'Inter', sans-serif;
    font-size: 17px;
    font-weight: 300;
    line-height: 1.78;
    max-width: 660px;
}

.prose p { margin-bottom: 1.6em; }

.prose h2 {
    font-family: 'Cormorant Garamond', serif;
    font-size: 34px;
    font-weight: 300;
    line-height: 1.18;
    margin-bottom: 0.85em;
    margin-top: 2.6em;
    max-width: 660px;
}

/* Подзаголовок — моноширинная метка, как везде на сайте. */
.prose h3 {
    color: #5A6570;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 10px;
    font-weight: 400;
    letter-spacing: 0.18em;
    margin-bottom: 1.3em;
    margin-top: 2.4em;
    text-transform: uppercase;
}

.prose strong {
    color: #0A0A0A;
    font-weight: 400;
}

.prose code {
    background: #F4F6F7;
    border: 1px solid #E4E7EA;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 0.86em;
    /* Короткие имена не рвём, но длинные ссылки должны переноситься,
       иначе на телефоне они вылезают за экран. */
    overflow-wrap: anywhere;
    padding: 2px 6px;
}

/* Блок кода — тот же, что во фрагменте на главной. */
.prose pre {
    background: #FBFCFC;
    border: 1px solid #E4E7EA;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12.5px;
    line-height: 1.85;
    margin-bottom: 1.9em;
    max-width: 800px;
    overflow-x: auto;
    padding: 22px 20px;
    tab-size: 4;
}

.prose pre code {
    background: none;
    border: none;
    color: #0A0A0A;
    font-size: inherit;
    padding: 0;
    white-space: pre;
}

@media (min-width: 768px) {
    .prose pre { font-size: 13px; padding: 26px 26px; }
}

/* Вынос: отбивается водой, как и прочие акценты. */
.prose .note {
    border-left: 1px solid #0E6E6B;
    margin: 2.4em 0;
    max-width: 640px;
    padding-left: 24px;
}

.prose .note p {
    color: #5A6570;
    font-size: 15px;
    margin-bottom: 0;
}

.prose ul {
    margin-bottom: 1.9em;
}

.prose li {
    margin-bottom: 0.6em;
    padding-left: 26px;
    position: relative;
}

.prose li::before {
    background: #0E6E6B;
    content: '';
    height: 1px;
    left: 0;
    opacity: 0.55;
    position: absolute;
    top: 0.85em;
    width: 12px;
}

/* Полоса прочитанного вверху статьи. */
.read-progress {
    background: #0E6E6B;
    height: 2px;
    left: 0;
    position: fixed;
    top: 0;
    transition: width 0.1s linear;
    width: 0;
    z-index: 60;
}

@media (prefers-reduced-motion: reduce) {
    .read-progress { transition: none; }
}

/* ---------- Lab: указатель разборов ---------- */

.lab-row {
    border-top: 1px solid #E4E7EA;
    position: relative;
}

/* По верхней кромке при наведении прочерчивается вода. */
.lab-row::after {
    background: #0E6E6B;
    content: '';
    height: 1px;
    left: 0;
    position: absolute;
    top: -1px;
    transition: width 0.7s cubic-bezier(0.16, 1, 0.3, 1);
    width: 0;
}

.lab-row:hover::after { width: 100%; }

.lab-row .lab-arrow {
    transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}

.lab-row:hover .lab-arrow { transform: translateX(8px); }

@media (prefers-reduced-motion: reduce) {
    .lab-row::after,
    .lab-row .lab-arrow { transition: none; }
}

/* ---------- Значок соцсети в подвале ---------- */

.social-link {
    color: #5A6570;
    display: inline-flex;
    transition: color 0.35s ease, transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

.social-link svg {
    fill: currentColor;
    height: 20px;
    width: 20px;
}

/* Треугольник внутри знака должен остаться цветом подложки. */
.social-link .social-mark {
    fill: #ffffff;
}

.social-link:hover {
    color: #0E6E6B;
    transform: translateY(-2px);
}

/* ---------- Огоньки состояния сервисов ---------- */

/* Точка горит и раз в несколько секунд отпускает кольцо наружу:
   так видно, что показание живое, а не нарисованное.
   Цвет берётся из --status, его задаёт класс состояния. */
.status-dot {
    --status: var(--status-ok);
    position: relative;
    flex-shrink: 0;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: rgb(var(--status));
    animation: status-glow 2.9s ease-in-out infinite;
}

.status-dot::after {
    content: '';
    position: absolute;
    inset: -1px;
    border: 1px solid rgb(var(--status) / 0.7);
    border-radius: 50%;
    animation: status-ring 2.9s ease-out infinite;
}

.status-dot.is-degraded { --status: var(--status-degraded); }
.status-dot.is-down     { --status: var(--status-down); }

/* Пока нечего сообщать — точка не мигает и не светится. */
.status-dot.is-checking,
.status-dot.is-unknown {
    --status: var(--status-idle);
    animation: none;
    opacity: 0.7;
}

.status-dot.is-checking::after,
.status-dot.is-unknown::after { animation: none; opacity: 0; }

@keyframes status-glow {
    0%, 100% { box-shadow: 0 0 7px 0 rgb(var(--status) / 0.40); }
    50%      { box-shadow: 0 0 15px 2px rgb(var(--status) / 0.80); }
}

@keyframes status-ring {
    0%   { transform: scale(1);   opacity: 0.75; }
    65%  { transform: scale(3.1); opacity: 0;    }
    100% { transform: scale(3.1); opacity: 0;    }
}

.status-label {
    --status: var(--status-ok);
    color: rgb(var(--status));
}

.status-label.is-degraded { --status: var(--status-degraded); }
.status-label.is-down     { --status: var(--status-down); }
.status-label.is-checking,
.status-label.is-unknown  { --status: var(--status-idle); }

@media (prefers-reduced-motion: reduce) {
    .status-dot {
        animation: none;
        box-shadow: 0 0 8px 0 rgb(var(--status) / 0.55);
    }
    .status-dot::after { animation: none; opacity: 0.55; }
}

@media (prefers-reduced-motion: reduce) {
    /* Фильтр снимается вместе с анимацией: он задан из CSS
       именно ради этой возможности. */
    .flag-cloth, .flag-ripple { animation: none; }
    .flag-sheen { animation: none; opacity: 0; }
    .lang-menu { transition: none; }
}
