/* Лендинг wyrd.link. Токены бренда, тёмная система, серый вместо белого.
   Скриптов на странице нет: сайт открывают в том числе через Tor. */
@font-face{font-family:'Oswald';font-style:normal;font-weight:700;font-display:swap;
  src:url(fonts/oswald-700-cyrillic.woff2) format('woff2');
  unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Oswald';font-style:normal;font-weight:700;font-display:swap;
  src:url(fonts/oswald-700-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}
@font-face{font-family:'Manrope';font-style:normal;font-weight:400;font-display:swap;
  src:url(fonts/manrope-400-cyrillic.woff2) format('woff2');
  unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Manrope';font-style:normal;font-weight:400;font-display:swap;
  src:url(fonts/manrope-400-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}
@font-face{font-family:'Manrope';font-style:normal;font-weight:800;font-display:swap;
  src:url(fonts/manrope-800-cyrillic.woff2) format('woff2');
  unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Manrope';font-style:normal;font-weight:800;font-display:swap;
  src:url(fonts/manrope-800-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}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url(fonts/plexmono-400-cyrillic.woff2) format('woff2');
  unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url(fonts/plexmono-400-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}

:root{
  --void:#080D14; --carbon:#0E1826; --graphite:#132234; --hairline:#22384F;
  --blue:#4A9FDA; --mark-net:#3A7EBB; --mark-node:#A5D6F5;
  --green:#86B86A;
  --fog:#D4DADE; --ash:#93A0AC; --steel:#5F6E7C;
  --font-display:"Oswald",sans-serif;
  --font-text:"Manrope",system-ui,sans-serif;
  --font-mono:"IBM Plex Mono",monospace;
  /* Шаг отступов. Всё вертикальное расстояние на странице берётся отсюда,
     поэтому ритм меняется в одном месте и не расползается по правилам. */
  --s1:8px; --s2:16px; --s3:24px; --s4:40px; --s5:56px; --s6:96px;
  --wrap:1200px;
  --pad:40px;
  --head:64px;
  /* Длительность движения: за это время решётка доворачивает свои 180 градусов,
     а паутина встаёт на место. Узлы садятся уже после - только в этот момент
     их места совпадают с атомами решётки. */
  --morph:1s;
  /* Пауза перед началом: знак GrapheneOS секунду стоит неподвижно. */
  --hold:1s;
  /* Совмещает атомы знака GrapheneOS с узлами знака Wyrd. */
  --seed-fit:0.789;
  /* Радиус кольца Wyrd в долях знака: столько же в assets/wyrd-mark-anim.svg. */
  --ring-r:37%;
}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--void);color:var(--fog);font-family:var(--font-text);
  font-size:17px;line-height:1.7;-webkit-text-size-adjust:100%}
a{color:var(--blue)}
a:focus-visible,.btn:focus-visible{outline:2px solid var(--blue);outline-offset:3px}
h1,h2{font-family:var(--font-display);font-weight:700;text-transform:uppercase;line-height:1.06}
h3{font-weight:800;font-size:18px;color:#E6EAEC}

/* Шапка */
.top{position:sticky;top:0;z-index:2;display:flex;align-items:center;gap:var(--s4);
  max-width:var(--wrap);margin:0 auto;padding:var(--s2) var(--pad);
  background:var(--void);border-bottom:1px solid var(--hairline)}
.top::before{content:"";position:absolute;left:0;right:0;top:0;bottom:0;
  background:var(--void);z-index:-1}
.brand{display:flex;align-items:center;gap:12px;text-decoration:none;color:var(--fog);
  font-family:var(--font-display);font-weight:700;text-transform:uppercase;
  letter-spacing:.16em;font-size:16px}
.mark{width:28px;height:28px;flex:none}
.nav{display:flex;gap:var(--s3);margin-left:auto;font-size:14px}
.nav a{color:var(--ash);text-decoration:none}
.nav a:hover{color:var(--fog)}
.langs{display:flex;gap:12px;font-family:var(--font-mono);font-size:12px}
.langs a{color:var(--steel);text-decoration:none}
.langs a:hover{color:var(--blue)}
.langs .on{color:var(--mark-node)}

main{max-width:var(--wrap);margin:0 auto;padding:0 var(--pad)}
section{padding:var(--s6) 0;border-top:1px solid var(--hairline)}
section:first-child{border-top:0}
h2{font-size:28px;letter-spacing:.02em;margin-bottom:var(--s4);position:relative;
  padding-bottom:var(--s2)}
h2::after{content:"";position:absolute;left:0;bottom:0;width:48px;height:2px;
  background:var(--mark-net)}
.lead{color:var(--ash);font-size:19px;max-width:70ch;margin-bottom:var(--s5)}
.note{color:var(--steel);font-size:15px;max-width:80ch;margin-top:var(--s4)}

/* Первый экран */
.hero{padding:var(--s6) 0}
.kicker{font-family:var(--font-mono);font-size:12px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--steel);margin-bottom:var(--s3)}
h1{font-size:clamp(30px,4.4vw,50px);letter-spacing:.01em;max-width:26ch;margin-bottom:var(--s3)}
.hero .lead{font-size:21px;line-height:1.6;max-width:62ch;margin-bottom:var(--s4)}
/* Опорные факты набраны как метки, а не как кнопки: рамка осталась только у
   действий, поэтому взгляд не путает их между собой. */
.facts{list-style:none;display:flex;flex-wrap:wrap;gap:var(--s2) var(--s4);
  margin-bottom:var(--s4)}
.facts li{font-family:var(--font-mono);font-size:12px;letter-spacing:.08em;color:var(--ash);
  position:relative;padding-left:16px}
.facts li::before{content:"";position:absolute;left:0;top:6px;width:5px;height:5px;
  background:var(--mark-net)}

/* Кнопки */
.actions{display:flex;flex-wrap:wrap;gap:var(--s2)}
.btn{display:inline-block;font-family:var(--font-mono);font-size:13px;letter-spacing:.08em;
  text-transform:uppercase;text-decoration:none;color:var(--fog);
  border:1px solid var(--hairline);padding:14px var(--s3)}
.btn:hover{border-color:var(--blue);color:var(--mark-node)}
.btn.primary{background:var(--mark-net);border-color:var(--mark-net);color:var(--void);
  font-weight:500}
.btn.primary:hover{background:var(--blue);border-color:var(--blue);color:var(--void)}

/* Карточки разделов */
.cards{display:grid;gap:var(--s5) var(--s4)}
.cards.c3{grid-template-columns:repeat(3,1fr)}
.cards.c2{grid-template-columns:repeat(2,1fr)}
.cards article{border-top:1px solid var(--hairline);padding-top:var(--s3)}
.cards h3{margin-bottom:var(--s2)}
.cards p{color:var(--ash);font-size:16px}
.cards ul{list-style:none;margin-top:var(--s1)}
.cards li{color:var(--ash);font-size:16px;padding-left:18px;position:relative;
  margin-bottom:var(--s2)}
.cards li::before{content:"";position:absolute;left:0;top:11px;width:5px;height:5px;
  background:var(--mark-net)}

/* Экран перехода: знак GrapheneOS сменяется знаком Wyrd. Движение живёт в CSS,
   поэтому работает и без скриптов; со скриптом оно ждёт, пока экран откроют. */
.morph-in{display:grid;grid-template-columns:1fr auto;gap:var(--s6);align-items:center}
.morph-in .lead{margin-bottom:0}
.morph-fig{--size:min(320px,46vw)}
.stage{position:relative;width:var(--size);height:var(--size)}
.stage svg{position:absolute;inset:0;width:100%;height:100%;transform-origin:center}
/* Решётка остаётся видимой: это фундамент, а не фон. */
/* Связи знака GrapheneOS длиннее кольца Wyrd и торчали наружу. Обрезаем их по
   линии кольца: срез прячется под его штрихом. Радиус задан до масштабирования,
   поэтому делится на тот же коэффициент. */
.seed{color:var(--ash);opacity:.55;rotate:180deg;scale:var(--seed-fit);
  clip-path:circle(calc(var(--ring-r) / var(--seed-fit)) at 50% 50%)}
/* Штрих чуть длиннее контура: ровно в длину мобильный рендер иногда
   оставляет щель в точке начала пути. */
.web .thread{stroke-dasharray:1.02}
.web .node,.web .core{transform-box:fill-box;transform-origin:center}
.legend{display:flex;justify-content:space-between;width:var(--size);margin-top:var(--s3);
  font-family:var(--font-mono);font-size:12px;letter-spacing:.1em;text-transform:uppercase}
.legend span:first-child{color:var(--steel)}
.legend span:last-child{color:var(--mark-node)}

/* Поворот и размер разведены по отдельным свойствам: у каждого своя плавность,
   и вращение идёт равномерно, без замедлений на промежуточных кадрах.
   Решётка поворачивается на 180 градусов - у неё шестигранная симметрия, после
   поворота атомы стоят там же, где стояли. */
@keyframes seed-spin{from{rotate:0deg}to{rotate:180deg}}
@keyframes seed-settle{
  from{opacity:1;scale:calc(var(--seed-fit) * 1.06)}
  to{opacity:.55;scale:var(--seed-fit)}
}
/* Паутина приходит шире решётки и, доворачивая, стягивается на неё. */
@keyframes web-spin{from{rotate:-90deg}to{rotate:0deg}}
@keyframes web-close{from{scale:1.32}to{scale:1}}
@keyframes thread-draw{from{stroke-dashoffset:1.02;opacity:1}to{stroke-dashoffset:0;opacity:1}}
/* Узел приходит сверху по размеру и садится на атом решётки. */
@keyframes node-clamp{from{opacity:0;transform:scale(1.9)}to{opacity:1;transform:scale(1)}}
/* Центр загорается первым: из него растёт вся паутина. */
@keyframes core-in{from{opacity:0;transform:scale(.3)}to{opacity:1;transform:scale(1)}}

/* Внедрение */
.steps{list-style:none;display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s5) var(--s4);
  counter-reset:s}
.steps li{counter-increment:s;border-top:1px solid var(--hairline);padding-top:var(--s3)}
.steps li::before{content:"0" counter(s);display:block;font-family:var(--font-display);
  font-size:22px;color:var(--mark-net);line-height:1;margin-bottom:var(--s2)}
.steps h3{margin-bottom:var(--s2)}
.steps p{color:var(--ash);font-size:16px}

/* Цены */
.tiers{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s3)}
.tier{border:1px solid var(--hairline);padding:var(--s4);display:flex;flex-direction:column}
.tier.accent{border-color:var(--mark-net);background:var(--carbon)}
.tier h3{font-family:var(--font-display);font-weight:700;font-size:21px;text-transform:uppercase;
  letter-spacing:.08em;color:var(--fog)}
/* Цена сжимается вместе с колонкой: словесная цена Enterprise длиннее числовой
   и на узком экране иначе вылезает за карточку. */
.price{font-family:var(--font-display);font-size:clamp(30px,3.4vw,42px);line-height:1.1;
  margin-top:var(--s2)}
.price .period{font-family:var(--font-mono);font-size:13px;color:var(--steel);
  margin-left:10px;letter-spacing:.04em}
.sub{color:var(--ash);font-size:15px;margin-top:var(--s1);line-height:1.5}
.devices{font-family:var(--font-mono);font-size:12px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--mark-node);margin:var(--s3) 0 var(--s3);padding-top:var(--s3);
  border-top:1px solid var(--hairline)}
.tier ul{list-style:none;margin-bottom:var(--s4)}
.tier li{color:var(--ash);font-size:16px;padding-left:18px;position:relative;
  margin-bottom:var(--s2)}
.tier li::before{content:"";position:absolute;left:0;top:11px;width:5px;height:5px;
  background:var(--mark-net)}
.tier .btn{margin-top:auto;text-align:center}

.start .lead{margin-bottom:var(--s4)}

/* Подвал */
.foot{max-width:var(--wrap);margin:0 auto;padding:var(--s4) var(--pad) var(--s6);
  border-top:1px solid var(--hairline);display:flex;flex-wrap:wrap;gap:var(--s2) var(--s4);
  align-items:baseline}
.foot-links{display:flex;gap:var(--s3);font-family:var(--font-mono);font-size:13px}
.foot-links a{color:var(--ash);text-decoration:none}
.foot-links a:hover{color:var(--blue)}
.foot p{color:var(--steel);font-size:13px;max-width:60ch;margin-left:auto}

@media (max-width:1080px){
  .cards.c3{grid-template-columns:repeat(2,1fr)}
  .steps{grid-template-columns:repeat(2,1fr)}
  .tier{padding:var(--s4) var(--s3)}
}
/* Три тарифа рядом: строки карточек общие, поэтому цена, предел устройств,
   список и кнопка стоят на одной линии, сколько бы строк ни занял перевод.
   В одну колонку это не нужно - там карточки идут друг за другом. */
@media (min-width:901px){
  .tiers{grid-template-rows:repeat(6,auto)}
  .tier{display:grid;grid-template-rows:subgrid;grid-row:span 6}
  .tier .btn{margin-top:0;align-self:end}
}
@media (max-width:900px){
  :root{--pad:32px;--s6:72px;--s5:44px}
  .tiers{grid-template-columns:1fr}
  .tier .btn{margin-top:var(--s3)}
}
@media (max-width:720px){
  /* На телефоне шаг сжимается целиком, по одному месту, а не по каждому правилу. */
  :root{--pad:20px;--s6:56px;--s5:36px;--s4:28px;--s3:20px}
  body{font-size:16px}
  .top{flex-wrap:wrap;gap:12px var(--s3);padding-bottom:10px}
  .nav{order:3;width:100%;margin-left:0;flex-wrap:wrap;gap:6px 18px;padding-bottom:2px;
    font-size:13px}
  .langs{margin-left:auto}
  .cards.c3,.cards.c2,.steps{grid-template-columns:1fr}
  h2{font-size:24px}
  .hero .lead{font-size:19px}
  .foot p{margin-left:0}
}

/* --- Улучшение при работающем JavaScript ---------------------------------
   Класс js ставит скрипт. Без него всё выше остаётся в силе: обычная страница,
   которую можно читать хоть с выключенными скриптами, хоть из Tor Browser.
   Содержимое не анимируется: движется только сама прокрутка. */

.js{scroll-behavior:smooth;scroll-padding-top:var(--head)}
.js .nav a.on{color:var(--mark-node)}

/* Кнопка возврата наверх. Её создаёт скрипт, поэтому в разметке страницы
   мёртвого элемента нет. */
.to-top{position:fixed;right:var(--pad);bottom:var(--pad);width:46px;height:46px;
  display:grid;place-items:center;cursor:pointer;
  background:rgba(19,34,52,.72);border:1px solid var(--hairline);color:var(--ash);
  opacity:0;visibility:hidden;transform:translateY(8px);
  transition:opacity .2s ease,transform .2s ease,visibility .2s,color .2s ease,
    border-color .2s ease}
.to-top svg{width:20px;height:20px}
.to-top:hover{color:var(--mark-node);border-color:var(--blue)}
.to-top.shown{opacity:1;visibility:visible;transform:none}

/* Страница загрузок. Обычный документ: экранов во всю высоту здесь нет, читают
   её сверху вниз. */
.release .version{font-family:var(--font-mono);font-size:12px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--mark-node);margin-bottom:var(--s2)}
.release p{color:var(--ash);font-size:16px}
.files{list-style:none;margin:var(--s3) 0}
.files li::before{content:none}
.files li{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px;
  padding:10px 0;border-bottom:1px solid var(--hairline)}
.files .file{font-family:var(--font-mono);font-size:14px;text-decoration:none;
  border-bottom:1px solid transparent;word-break:break-all}
.files .file:hover{border-bottom-color:var(--blue)}
.files span{font-size:13px;color:var(--steel);margin-left:auto}
.release .btn{margin-top:var(--s3)}
.cards-list{list-style:none;display:grid;gap:var(--s3);max-width:80ch}
.cards-list li{color:var(--ash);font-size:16px;padding-left:18px;position:relative}
.cards-list li::before{content:"";position:absolute;left:0;top:11px;width:5px;height:5px;
  background:var(--mark-net)}

/* Экран на смысловой блок. Включается там, где экран достаточно большой:
   на телефоне и в короткой полосе браузера подтягивание только мешает. */
@media (min-width:900px) and (min-height:640px){
  .js{scroll-snap-type:y mandatory}
  .js.hijack{scroll-snap-type:y proximity}
  /* В режиме экранов разделители не нужны: границу задаёт сам экран. Заодно
     уходит вторая полоска, которая вставала вплотную под шапкой. */
  .js main.doc > section{display:block;min-height:0;border-top:1px solid var(--hairline);
    padding:var(--s6) 0}
  .js main > section{display:flex;flex-direction:column;justify-content:center;
    min-height:calc(100vh - var(--head));min-height:calc(100svh - var(--head));
    scroll-snap-align:start;scroll-snap-stop:always;border-top:0}

  /* Подвал - такая же точка остановки, как экран. Без неё ближайшей точкой
     остаётся последний экран, и прокрутка до подвала откатывается назад: он
     виден, но ни по одной ссылке в нём не попасть. */
  .js .foot{scroll-snap-align:end}

  /* В режиме экранов воздух даёт сам экран, поэтому внутренние отступы блока
     сжимаются: иначе содержимое перестаёт помещаться на ноутбуке. */
  .js main > section{padding:var(--s4) 0}
  .js h2{margin-bottom:var(--s3)}
  .js .lead{margin-bottom:var(--s4)}
  .js .note{margin-top:var(--s3)}

  /* Тарифы обязаны помещаться в экран целиком: это тот блок, ради которого
     на страницу приходят, и листать его половинами нельзя. */
  .js #pricing{padding:var(--s3) 0}
  .js #pricing h2{margin-bottom:var(--s2)}
  .js #pricing .lead{margin-bottom:var(--s3)}
  .js #pricing .tier{padding:var(--s3)}
  .js #pricing .tier h3{font-size:18px}
  .js #pricing .price{font-size:clamp(26px,2.2vw,30px);margin-top:var(--s1)}
  .js #pricing .sub{font-size:14px}
  .js #pricing .devices{font-size:11px;margin:12px 0;padding-top:12px}
  .js #pricing .tier ul{margin-bottom:var(--s2)}
  .js #pricing .tier li{font-size:14px;line-height:1.55;margin-bottom:8px}
  .js #pricing .btn{padding:11px 18px;font-size:12px}
  .js #pricing .note{font-size:13px;margin-top:var(--s2)}

  /* Невысокий экран ноутбука: тарифам отдаётся всё, что можно отдать. */
  @media (max-height:880px){
    .js #pricing{padding:var(--s2) 0}
    .js #pricing h2{font-size:24px;margin-bottom:var(--s2)}
    .js #pricing .lead{font-size:16px;margin-bottom:var(--s2)}
    .js #pricing .tier{padding:var(--s2)}
    .js #pricing .devices{margin:10px 0;padding-top:10px}
    .js #pricing .tier ul{margin-bottom:12px}
    .js #pricing .tier li{margin-bottom:6px}
    .js #pricing .btn{padding:10px 16px}
    .js #pricing .note{font-size:12px;margin-top:12px}
  }

  .js #what .cards{gap:var(--s4)}
  /* Блок возможностей длиннее экрана по существу: девять пунктов в один экран
     влезают только ценой нечитаемого кегля. Он подтягивается началом и дальше
     листается как обычно. */
  .js #what{justify-content:flex-start}
}

/* Переход между знаками: до открытия экрана держим первый кадр, дальше играем
   один раз. Класс play ставит скрипт, когда экран попадает в поле зрения. */
.js .morph .seed{opacity:1;rotate:0deg;scale:calc(var(--seed-fit) * 1.06)}
/* Нити до начала не просто пустые, а скрыты: у линий круглые концы, и нулевой
   штрих рисует в центре точку. */
.js .morph .thread{stroke-dashoffset:1.02;opacity:0}
.js .morph .web{rotate:-90deg;scale:1.32}
.js .morph .node,.js .morph .core{opacity:0}
.js .morph.play .seed{animation:seed-spin var(--morph) linear var(--hold) both,
  seed-settle var(--morph) cubic-bezier(.4,0,.3,1) var(--hold) both}
.js .morph.play .web{animation:web-spin var(--morph) linear var(--hold) both,
  web-close var(--morph) cubic-bezier(.4,0,.25,1) var(--hold) both}
.js .morph.play .thread{animation:thread-draw .45s ease calc(var(--hold) + .3s) forwards}
.js .morph.play .node{animation:node-clamp .26s cubic-bezier(.2,.8,.3,1) both}
.js .morph.play .node:nth-of-type(1){animation-delay:calc(var(--hold) + 1.02s)}
.js .morph.play .node:nth-of-type(2){animation-delay:calc(var(--hold) + 1.07s)}
.js .morph.play .node:nth-of-type(3){animation-delay:calc(var(--hold) + 1.12s)}
.js .morph.play .node:nth-of-type(4){animation-delay:calc(var(--hold) + 1.17s)}
.js .morph.play .node:nth-of-type(5){animation-delay:calc(var(--hold) + 1.22s)}
.js .morph.play .node:nth-of-type(6){animation-delay:calc(var(--hold) + 1.27s)}
.js .morph.play .core{animation:core-in .28s cubic-bezier(.2,.8,.3,1) both;
  animation-delay:calc(var(--hold) + .18s)}

@media (prefers-reduced-motion:reduce){
  .js{scroll-behavior:auto}
  .js .morph .seed{opacity:.55;rotate:180deg;scale:var(--seed-fit)}
  .js .morph .web{rotate:0deg;scale:1}
  .js .morph .thread{stroke-dashoffset:0;opacity:1}
  .js .morph .node,.js .morph .core{opacity:1}
  .js .morph.play .seed,.js .morph.play .web,.js .morph.play .thread,
  .js .morph.play .node,.js .morph.play .core{animation:none}
}

@media (max-width:900px){
  .morph-in{grid-template-columns:1fr;gap:var(--s4)}
  .morph-fig{--size:min(280px,70vw);margin:var(--s2) auto 0}
}
