@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700;800&display=swap');
body{margin:0;background:#070A09;color:#C9D6CF;font-family:'JetBrains Mono',monospace}
a{color:#3FB950;text-decoration:none}
a:hover{color:#7DFF9B}
::placeholder{color:#4E6156}
@keyframes blink{0%,49%{opacity:1}50%,100%{opacity:0}}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
@keyframes dogbob{0%,100%{transform:rotate(-2deg) translateY(0)}50%{transform:rotate(2deg) translateY(-4px)}}
@keyframes lpFloat{0%{transform:translateY(0) scale(1);opacity:0}8%{opacity:1}100%{transform:translateY(-46vh) scale(1.25);opacity:0}}
@keyframes lpPop{0%{transform:scale(.4);opacity:0}18%{transform:scale(1.25);opacity:1}70%{transform:scale(1);opacity:1}100%{transform:scale(.9);opacity:0}}
@keyframes lpRipple{0%{transform:scale(.2);opacity:.8}100%{transform:scale(1);opacity:0}}
@keyframes ctapulse{0%,100%{box-shadow:0 6px 18px rgba(63,185,80,.25)}50%{box-shadow:0 10px 32px rgba(63,185,80,.55)}}
@media (prefers-reduced-motion: reduce){*{animation:none !important;transition:none !important}}
/* ── ховеры (перенесены из style-hover макета) ── */
[data-on]{transition:filter .15s,border-color .15s,color .15s}
button[data-on]:hover{filter:brightness(1.12)}
.hv-cyan:hover{border-color:#56D4DD!important;color:#56D4DD!important}
.hv-grn:hover{border-color:#3FB950!important;color:#3FB950!important}
input:focus,textarea:focus{border-color:#3FB950!important}
[hidden]{display:none!important}

/* ── редактор раскладки (drag + resize) ── */
[data-block]{position:relative}
.lay-handle{position:absolute;top:6px;right:8px;z-index:20;display:flex;gap:5px;opacity:0;
  transform:translateY(-4px);transition:.16s;pointer-events:none}
body.lay-edit [data-block]{outline:1px dashed #2A4033;outline-offset:5px;border-radius:12px}
body.lay-edit .lay-handle,[data-block]:hover .lay-handle{opacity:1;transform:none;pointer-events:auto}
.lay-handle button{height:26px;min-width:26px;padding:0 8px;display:flex;align-items:center;
  justify-content:center;background:rgba(10,16,13,.94);border:1px solid #2A4033;color:#7F9488;
  border-radius:6px;cursor:pointer;font:12px/1 'JetBrains Mono',monospace}
.lay-handle button:hover{border-color:#3FB950;color:#3FB950}
.lay-grip{cursor:grab;touch-action:none}
.lay-resize{position:absolute;top:0;right:-13px;width:16px;height:100%;z-index:19;cursor:ew-resize;
  display:none;align-items:center;justify-content:center;touch-action:none}
body.lay-edit .lay-resize{display:flex}
.lay-resize::before{content:"";width:4px;height:44px;border-radius:3px;background:#2A4033}
.lay-resize:hover::before{background:#3FB950;height:68px}
[data-block].dragging{opacity:.4;outline:2px dashed #3FB950!important}
[data-block].lay-over{outline:2px dashed #56D4DD!important}
body.lay-dragging{user-select:none;cursor:grabbing}
.lay-bar{position:fixed;left:16px;bottom:16px;z-index:60;display:flex;align-items:center;gap:8px;
  background:rgba(10,16,13,.95);backdrop-filter:blur(12px);border:1px solid #2A4033;border-radius:10px;
  padding:7px 11px;font:11.5px 'JetBrains Mono',monospace;color:#7F9488}
.lay-bar b{color:#3FB950}
.lay-bar button{background:#0A100D;border:1px solid #2A4033;color:#56D4DD;border-radius:6px;
  padding:5px 10px;cursor:pointer;font:11.5px 'JetBrains Mono',monospace}
.lay-bar button:hover{border-color:#3FB950;color:#3FB950}
.lay-bar button.on{background:rgba(63,185,80,.14);border-color:#3FB950;color:#3FB950}
.lay-bar .x{border:none;background:none;color:#4E6156;font-size:14px}
@media(max-width:900px){.lay-resize{display:none!important}
  .lay-bar{left:10px;right:10px;bottom:auto;top:60px}}

/* контейнер списка не участвует в раскладке — дети встают прямо в сетку макета */
[data-for]{display:contents}

/* команда установки: одна строка без скролла на любой ширине */
#cmdline{font-variant-ligatures:none}
@media (max-width:900px){
  #cmdline + button{padding:7px 10px!important;font-size:10px!important}
}
/* Команда установки на телефоне. fitCmd() ужимает её так, чтобы влезла в
   одну строку, — на 360px это доходило до 6px, читать невозможно. Ниже 560px
   разрешаем перенос: команда переносится по словам нормальным кеглем, а
   кнопка «копировать» встаёт под ней во всю ширину. */
@media (max-width:560px){
  .cmdbody{flex-direction:column!important;align-items:stretch!important;padding:11px 12px!important}
  .cmdbody button{width:100%}
  #cmdline,#cmdline2{white-space:pre-wrap!important;word-break:break-word;
    font-size:11px!important;line-height:1.55!important;overflow:visible!important}
}

/* мобильные: от промо остаётся только сам пёс — 48 px в левом нижнем углу.
   Раньше он висел на top:190px во всю правую сторону и накрывал колонку
   вердиктов: «ДОСТУП ЕСТЬ» читалось наполовину. Правый нижний угол занят
   виджетами присутствия, поэтому уходим влево. Жёлтую плашку и QR прячем:
   картинка сама ссылка на клуб, а QR с телефона всё равно не сканируют. */
@media (max-width:760px){
  #dogpromo{width:48px!important;top:auto!important;bottom:74px!important;
    right:auto!important;left:5px!important;gap:2px!important;transform:none!important}
  /* картинка задана инлайном как height:140px/width:fit-content — сбрасываем */
  #dogpromo>a:first-child{height:auto!important;width:100%!important}
  #dogpromo img[alt="клубный пёс"]{width:100%!important;height:auto!important}
  #dogpromo [data-if="dogFull"],#dogpromo [data-if="dogCompact"]{display:none!important}
  /* «спрятать пса →» в 48 px переносилось на две строки — заменяем крестиком */
  #dogpromo button{font-size:0!important;padding:0!important;line-height:1!important;
    align-self:center;width:18px;height:18px;border-radius:50%!important;
    border:1px solid #2A4033!important;color:#4E6156!important}
  #dogpromo button::after{content:"✕";font:600 9px 'JetBrains Mono',monospace}
  /* язычок «спрятанного» пса тоже вниз-влево — вверху он налезал на шапку */
  [data-if="dogHiddenTab"] button[data-on="toggleDog"]{top:auto!important;bottom:78px!important;
    right:auto!important;left:0!important;border-radius:0 10px 10px 0!important;
    border-right:2px solid #B9E04A!important;border-left:none!important;padding:8px 6px!important}
}

/* Ноутбучные и планшетные ширины. Раньше пёс висел справа снизу и накрывал
   правый край контента: сперва кнопку «ПРОВЕРИТЬ», потом — когда пинг стал
   диаграммой — две последние колонки, Италию и Швейцарию. А это уже не просто
   картинки: каждая колонка ведёт к хостеру по реферальной ссылке.
   Уводим вниз-влево. Размер оставляем читаемым: мельчить нельзя, иначе
   призыв не прочитать и смысла в промо нет. Убираем только QR — на ноутбуке
   его не сканируют, зато он давал половину высоты блока. */
@media (min-width:761px) and (max-width:1620px){
  #dogpromo{top:auto!important;bottom:18px!important;left:14px!important;right:auto!important;
    width:150px!important;gap:8px!important;transform:none!important}
  /* картинка задана инлайном как height:140px/width:fit-content — сбрасываем */
  #dogpromo>a:first-child{height:auto!important;width:100%!important}
  #dogpromo img[alt="клубный пёс"]{width:100%!important;height:auto!important}
  #dogpromo img[alt="QR клуба"]{display:none!important}
  /* фиолетовая рамка без QR смотрится пустой коробкой — оставляем одну кнопку */
  #dogpromo [data-if="dogFull"]>div{background:transparent!important;border:0!important;
    padding:0!important;gap:0!important}
  #dogpromo [data-if="dogFull"] [style*="B9E04A"]{width:100%!important;box-sizing:border-box!important;
    font-size:11px!important;line-height:1.3!important;padding:10px 8px!important;
    white-space:normal!important;border-radius:10px!important;border-width:2px!important}
  #dogpromo button{font-size:10px!important}
  [data-if="dogHiddenTab"] button[data-on="toggleDog"]{top:auto!important;bottom:24px!important;
    right:auto!important;left:0!important;border-radius:0 10px 10px 0!important;
    border-right:2px solid #B9E04A!important;border-left:none!important;padding:10px 8px!important}
}

/* Команды меряются пробником при 100px и масштабируются. Межбуквенное
   расстояние задаётся в пикселях и при масштабировании не сжимается —
   поэтому строка вылезала на ~20px. Обнуляем его на самих командах. */
#cmdline, #cmdline2 { letter-spacing: 0 !important; }
@media (min-width:900px){
  /* правая команда длиннее левой почти вдвое — даём ей больше ширины,
     чтобы обе строки читались одним кеглем */
  [data-cta-grid]{grid-template-columns:1fr 1.45fr!important}
}


/* ── бегущая строка живого лога ─────────────────────────────────────────────
   Лента дублируется два раза, поэтому сдвиг ровно на половину даёт бесшовную
   петлю независимо от того, сколько событий сейчас в списке. */
@keyframes tick { from { transform: translateX(0) } to { transform: translateX(-50%) } }
#ticker:hover #tickertrack { animation-play-state: paused }
@media (prefers-reduced-motion: reduce) { #tickertrack { animation: none !important } }
@media (max-width: 760px) { #ticker { height: 30px; font-size: 11px } }


/* ── Подсветка хостера после плохого вердикта ───────────────────────────────
   Человек увидел «IP В БАНЕ» и не знает, что делать. Через три секунды —
   успел прочитать вердикт — страница везёт его к хостеру: фон гаснет, блок
   остаётся освещённым и объясняет, что менять надо адрес, а не сервер.
   Показываем один раз за сессию: при повторных проверках это уже назойливо. */
#spotlight{position:fixed;inset:0;z-index:110;background:rgba(3,5,4,.82);display:none}
#spotlight.on{display:block;animation:spotfade .35s ease}
@keyframes spotfade{from{opacity:0}to{opacity:1}}
#club.lit{position:relative;z-index:120;border-color:#3FB950 !important;
  box-shadow:0 0 0 1px rgba(63,185,80,.55),0 0 60px -8px rgba(63,185,80,.45) !important}
#whyhost{display:none}
#whyhost.on{display:block;animation:whyrise .45s cubic-bezier(.2,.7,.3,1)}
@keyframes whyrise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}


/* ── Пёс не должен воровать клики ───────────────────────────────────────────
   Промо висит fixed в правом нижнем углу, и на ноутбучных ширинах кнопка
   «ПРОВЕРИТЬ» после прокрутки оказывается ровно под ним: замер показал
   перекрытие 104×53 px на 1300 и 85×56 на 1366, а клик по центру кнопки
   уходил в картинку пса или в ссылку клуба. Поэтому сам блок кликов не ловит
   вовсе — их принимают только те элементы, по которым и надо нажимать:
   картинка-ссылка, QR, кнопки клуба и «спрятать пса». */
#dogpromo, #dogpromo a, #dogpromo img{pointer-events:none}
#dogpromo a[data-club-cta], #dogpromo button{pointer-events:auto}


/* ═══ телефоны ══════════════════════════════════════════════════════════════
   Строка ноды была сеткой из пяти колонок с жёсткими 26+108+58+128 px и
   четырьмя зазорами — минимум ~360 px. На экране 360 px она не влезала,
   страница начинала ездить вбок, а колонка вердикта уходила за край.
   Ниже 560 px строка разворачивается в две: сверху позывной, задержка и
   вердикт, снизу — провайдер с баннером. Ничего не режется. */
body{overflow-x:clip}

@media (max-width:560px){
  /* 24 px по бокам на узком экране — это 48 px из 360, седьмая часть ширины */
  .wrap{padding-left:12px!important;padding-right:12px!important}

  .noderow{grid-template-columns:18px minmax(0,1fr) auto auto!important;
    gap:3px 8px!important;padding:9px 10px!important;font-size:12px!important}
  .noderow>:nth-child(1){grid-area:1/1/auto/2}
  .noderow>:nth-child(2){grid-area:1/2/auto/3}
  .noderow>:nth-child(4){grid-area:1/3/auto/4;font-size:11px;text-align:right;white-space:nowrap}
  .noderow>:nth-child(5){grid-area:1/4/auto/5;padding:2px 5px!important;font-size:9.5px!important}
  .noderow>:nth-child(3){grid-area:2/2/auto/5;font-size:10.5px}

  /* список адресов — та же логика: адрес и процент сверху, вердикт снизу */
  .listhead{display:none!important}
  .listrow{grid-template-columns:minmax(0,1fr) auto!important;gap:2px 8px!important}
  .listrow>:nth-child(1){grid-area:1/1/auto/2}
  .listrow>:nth-child(4){grid-area:1/2/auto/3;text-align:right}
  .listrow>:nth-child(2){grid-area:2/1/auto/2;font-size:11px}
  .listrow>:nth-child(3){grid-area:2/2/auto/3;text-align:right;font-size:11px}

  /* подписи под цветной шкалой: пять слов по процентам ширины слипались */
  .scaleleg{font-size:8.5px!important;line-height:1.25}

  /* шапка: две строки статистики съедали треть первого экрана */
  .hdr>div>span,.hdr>div>a{font-size:11px}
  .hdr{padding-top:9px!important;padding-bottom:9px!important;gap:6px!important}
}

/* панель реакций «живого присутствия» прибита к низу экрана и накрывала
   последние строки — даём странице место, чтобы под неё можно было доскроллить */
@media (max-width:760px){ body{padding-bottom:72px} }

/* ── пинг до дата-центров: столбики ────────────────────────────────────────
   Двенадцать площадок должны стоять в один ряд при любой ширине, поэтому
   сетка жёстко на 12 колонок, а не auto-fit: иначе на ноутбуке получалось
   10 + 2 вторым рядом. Высота столбика — доля от самой большой задержки,
   так сравнение читается мгновенно, без чтения цифр. */
.pinggrid{display:grid;grid-template-columns:repeat(12,1fr);gap:8px;
  align-items:end;height:132px;margin-top:14px}
/* Вся колонка — одна ссылка к хостеру, поэтому и подсвечивается целиком:
   человек ведёт мышь к столбику, а кликабельна вся её площадь, включая
   цифру, флаг и подпись. */
.pingcell{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;
  height:100%;min-width:0;text-decoration:none;color:inherit;
  border-radius:9px;padding:5px 3px 4px;
  transition:background .15s,box-shadow .15s,transform .15s}
.pingcell .v{font-size:11px;font-weight:800;white-space:nowrap;margin-bottom:4px;
  font-variant-numeric:tabular-nums}
.pingcell .zone{flex:1;min-height:0;width:100%;display:flex;align-items:flex-end;justify-content:center}
/* Столбик занимает всю ширину колонки: при ограничении в 30 px между ними
   зияли шестьдесят, и это читалось как набор палочек, а не диаграмма. */
.pingcell .b{width:100%;min-height:3px;border-radius:5px 5px 0 0;
  transition:height .45s ease,filter .15s}
.pingcell .f{font-size:17px;line-height:1;margin-top:7px}
.pingcell .n{font-size:9.5px;color:var(--tx-mid,#7F9488);margin-top:3px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;max-width:100%;transition:color .15s}
.pingcell:hover .b{filter:brightness(1.18)}
.pingcell:hover .n,.pingcell:hover .v{color:#E6F2EA}

/* Подсказки по умолчанию нет в раскладке вовсе. visibility:hidden мало:
   скрытый элемент всё равно занимает место, и карточка в 206 px внутри
   двадцатипиксельной колонки растягивала страницу — на телефоне появлялся
   горизонтальный сдвиг на 24 px. */
.pingcell .tip{display:none}

/* Наведение — только настоящая мышь и только там, где блок достаточно широк.
   На тач-экране :hover залипает после касания и подсказка висела бы до тапа
   по пустому месту, а на узком экране ей просто негде поместиться. */
@media (hover:hover) and (pointer:fine) and (min-width:901px){
  .pingcell:hover{background:rgba(63,185,80,.09);box-shadow:inset 0 0 0 1px rgba(63,185,80,.32);
    transform:translateY(-3px)}
  .pingcell .tip{display:block;position:absolute;bottom:calc(100% + 10px);left:50%;
    transform:translateX(-50%) translateY(5px);width:206px;z-index:40;
    background:#0A100D;border:1px solid #2A4033;border-radius:11px;padding:11px 13px;
    box-shadow:0 16px 38px rgba(0,0,0,.6);text-align:left;
    opacity:0;visibility:hidden;pointer-events:none;
    transition:opacity .16s ease,transform .16s ease,visibility .16s}
  .pingcell:hover .tip{opacity:1;visibility:visible;transform:translateX(-50%) translateY(0)}
  .pingcell .tip::after{content:"";position:absolute;top:100%;left:50%;margin-left:-6px;
    border:6px solid transparent;border-top-color:#2A4033}
  .pingcell .tip .t{display:block;font-size:12px;font-weight:800;color:#3FB950;margin-bottom:6px;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pingcell .tip .l,.pingcell .tip .l2{display:block;font-size:10.5px;color:#7F9488;line-height:1.5}
  .pingcell .tip .l2{color:#F4C752;font-weight:700;margin-top:2px}
  /* Крайние колонки: подсказка не должна вылезать за рамку блока.
     Считаем позицию по обёрткам, а не по самим ячейкам: рендерер кладёт
     каждую строку в собственный div со style="display:contents", поэтому
     любая .pingcell — всегда первый ребёнок своей обёртки, и nth-child
     по ней срабатывал бы на всех двенадцати сразу. */
  [data-for="pings"] > div:nth-child(-n+2) .tip{left:0;transform:translateX(0) translateY(5px)}
  [data-for="pings"] > div:nth-child(-n+2) .pingcell:hover .tip{transform:translateX(0)}
  [data-for="pings"] > div:nth-child(-n+2) .tip::after{left:26px}
  [data-for="pings"] > div:nth-child(n+11) .tip{left:auto;right:0;transform:translateX(0) translateY(5px)}
  [data-for="pings"] > div:nth-child(n+11) .pingcell:hover .tip{transform:translateX(0)}
  [data-for="pings"] > div:nth-child(n+11) .tip::after{left:auto;right:20px}
}

/* На планшете двенадцать подписей уже не помещаются — оставляем флаг и число.
   Название страны никуда не девается: оно в подсказке при наведении. */
@media (max-width:900px){
  .pinggrid{height:112px;gap:5px}
  .pingcell{padding:4px 2px 3px}
  .pingcell .n{display:none}
  .pingcell .f{font-size:16px;margin-top:6px}
}
@media (max-width:560px){
  .pinggrid{height:96px;gap:3px}
  .pingcell{padding:3px 1px 2px;border-radius:6px}
  .pingcell .v{font-size:9px;margin-bottom:3px}
  .pingcell .f{font-size:13px;margin-top:5px}
  .pingcell .b{border-radius:4px 4px 0 0}
}
