/* ============================================================================
   Показ ИИ-контура для закупок — в фирменном стиле FTD

   Композиция и токены взяты из шаблона коммерческих предложений
   (presentation-references/deck.html): те же гарнитуры, те же цвета, тот же
   слайд 1123×794 с шапкой, контентом и подвалом-сноской. Это не похожий
   стиль, а тот же самый — презентация должна читаться как документ FTD.

   Своего здесь три раскладки, которых в шаблоне не было и не могло быть:
   «live» — слайд с работающим экраном внутри, «figures» — строка цифр
   контура и «links» — плитка адресов, по которым зал уходит смотреть сам.
   Сделаны они в той же системе: те же размеры, те же пастельные акценты.
   ========================================================================== */

:root{
  --background:#F3F2EE;
  --surface:#FBFAF7;
  --text:#141414;
  --muted:#66645F;
  --border:#DEDAD2;
  --ink:#0E0E0E;
  --paper:#EDEBE4;
  --onInk:#A8A69E;
  --lilac:#DDD6FF;
  --peach:#F7D6C1;
  --mist:#CDE0F6;
  --lilacSoft:#EAE5FF;
  --peachSoft:#FBE7D9;
  --mistSoft:#E2EDF9;
  --heading-font:'Onest',sans-serif;
  --body-font:'Manrope',sans-serif;
  --mono-font:'JetBrains Mono',monospace;
  --cover-size:72px;
  --intro-size:60px;
  --heading-size:46px;
  --body-size:25px;
  --caption-size:16px;
  --folio-size:13px;
}

*{box-sizing:border-box}
html{color-scheme:light}
body{margin:0;background:var(--background);color:var(--text);
     font-family:var(--body-font);-webkit-font-smoothing:antialiased;
     print-color-adjust:exact;-webkit-print-color-adjust:exact}
a{color:inherit;text-decoration:none}
a:hover{text-decoration:underline}
:focus-visible{outline:3px solid var(--lilac);outline-offset:3px}

.deck{padding:32px 0;display:flex;flex-direction:column;align-items:center;gap:24px}
.slide{width:1123px;height:794px;flex:none;position:relative;
       background:var(--surface);overflow:hidden;padding:48px 64px 42px;
       isolation:isolate}

.bar{height:32px;display:flex;align-items:center;justify-content:space-between}
.logo{font-family:var(--heading-font);font-weight:700;font-size:23px;
      display:flex;align-items:center;gap:10px}
.logo svg{width:28px;height:28px}
.folio{font:13px var(--mono-font);color:var(--muted)}

.content{position:absolute;left:64px;right:64px;top:144px;bottom:96px;
         display:flex;flex-direction:column}

h1,h2,h3,p,figure,ol,ul{margin:0}
h1,h2,h3{font-family:var(--heading-font)}
h2{font-size:var(--heading-size);line-height:1.12;font-weight:700;
   letter-spacing:-1.4px;max-width:950px}
h3{font-size:29px;line-height:1.2;font-weight:600;letter-spacing:-.5px}
p{font-size:var(--body-size);line-height:1.5}
.lede{margin-top:24px;max-width:850px;color:var(--muted)}

.foot{position:absolute;left:64px;right:64px;bottom:40px;height:25px;
      border-top:1px solid var(--border);padding-top:12px;color:var(--muted);
      display:flex;justify-content:space-between;font-size:var(--folio-size);
      line-height:1;gap:24px}
.foot span{max-width:900px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* ------------------------------------------------------ обложка и контакты */

.cover,.closing{background:var(--ink);color:var(--paper)}
.cover{background:radial-gradient(800px 800px at 99% 114%,rgba(221,214,255,.44),transparent 60%),
       radial-gradient(500px 500px at 82% 107%,rgba(205,224,246,.30),transparent 62%),
       var(--ink)}
.cover-main{position:absolute;top:260px;left:64px;right:64px}
.cover h1,.closing h1{font-size:var(--cover-size);line-height:1.04;font-weight:800;
                      letter-spacing:-2.8px}
.cover-main p{color:var(--onInk);margin-top:30px;font-size:26px;line-height:1.5}
.cover-main .cover-note{font-family:var(--heading-font);font-weight:600;font-size:31px;
                        line-height:1.28;color:var(--lilac);margin-top:28px;max-width:820px}
.master-foot{position:absolute;bottom:48px;left:64px;right:64px;display:flex;
             justify-content:space-between;font-size:16px;color:var(--onInk)}
.closing-main{position:absolute;left:64px;right:64px;top:176px}
.closing-main>p{margin-top:26px;color:var(--onInk)}
.contacts{display:grid;grid-template-columns:1fr 1fr;gap:48px;margin-top:62px;
          border-top:1px solid #383837;padding-top:28px}
.contacts>div{display:flex;flex-direction:column;gap:8px}
.contact-label{font-size:16px;color:var(--onInk);margin-bottom:8px}
.contacts a{font-size:25px;line-height:1.4}

/* -------------------------------------------------------- титул и тезис */

.intro .content{justify-content:center}
.project{font:16px var(--mono-font);color:var(--text);background:var(--peachSoft);
         align-self:flex-start;padding:9px 15px;border-radius:999px;margin-bottom:28px}
.intro h2{font-size:var(--intro-size);line-height:1.08;max-width:900px;letter-spacing:-2px}
.intro .lede{max-width:760px}
.intro-meta{font:16px var(--mono-font);margin-top:56px;color:var(--muted)}

.statement .content{justify-content:center}
.statement h2{font-size:58px;line-height:1.13;max-width:900px;letter-spacing:-1.8px}
.statement .lede{margin-top:36px;max-width:760px}

.rec{display:inline-block;margin-left:14px;padding:6px 13px;border-radius:999px;
     background:var(--lilac);color:var(--text);font:600 15px/1 var(--body-font);
     letter-spacing:.01em;vertical-align:3px}
.rec--peach{background:var(--peach)}
.rec--mist{background:var(--mist)}

/* ------------------------------------------------------------- сравнение */

.compare-grid{display:grid;grid-template-columns:1fr 1fr;gap:52px;margin-top:44px}
.compare-side{border-top:4px solid var(--peach);padding:24px 0 18px;
              border-radius:0 0 14px 14px;min-width:0}
.compare-side:last-child{border-top-color:var(--mist)}
/* Цвет полосы иногда несёт смысл, а не порядок: «настоящее» должно быть
   спокойным, «подставлено» — тёплым, независимо от места в паре. */
.compare-side--mist{border-top-color:var(--mist)}
.compare-side--peach{border-top-color:var(--peach)}
.compare-side--lilac{border-top-color:var(--lilac)}
.compare-side.is-recommended{background:var(--lilacSoft);border-top-color:var(--lilac);
                             padding-left:22px;padding-right:22px}
.compare-side h3{margin-bottom:24px}
.compare-side p{margin-top:14px}
.compare-side .src{font:15px/1.4 var(--mono-font);color:var(--muted);margin-top:20px;
                   padding-top:14px;border-top:1px solid var(--border);white-space:normal}

/* --------------------------------------------------------------- конвейер */

.process-list{margin:46px 0 0;padding:0;list-style:none}
.process-list li{display:grid;grid-template-columns:60px 300px 1fr;gap:24px;
                 align-items:start;padding:24px 0;border-top:1px solid var(--border)}
.process-list .num{font:500 20px/1 var(--mono-font);color:var(--text);
                   background:var(--lilacSoft);border-radius:9px;padding:10px 0;
                   width:48px;text-align:center}
.process-list li:nth-child(2) .num{background:var(--peachSoft)}
.process-list li:nth-child(3) .num{background:var(--mistSoft)}
.process-list li:nth-child(5) .num{background:var(--peachSoft)}
.process-list p{font-size:23px;color:var(--muted);line-height:1.4}
.process-list--five li{padding:17px 0}
.process-list--five{margin-top:34px}

/* ----------------------------------------------------------------- цифры */

/* Строка цифр контура. Крупный моноширинный набор — тот же приём, что у
   .metric-value в шаблоне: числу верят, когда его видно. */
.figures{display:grid;grid-template-columns:repeat(5,1fr);gap:0;margin-top:60px;
         border-top:2px solid var(--lilac)}
.figures div{padding:32px 20px 0 0;min-width:0}
.figures div+div{padding-left:22px;border-left:1px solid var(--border)}
.fig-v{font:500 50px/1 var(--mono-font);letter-spacing:-2.5px;white-space:nowrap}
/* Подписи в столбцах разной длины. Две строки резервируются всегда, иначе
   нижняя строка гуляет по высоте и ряд перестаёт читаться рядом. */
.fig-l{font-size:20px;line-height:1.3;margin-top:22px;min-height:52px}
.fig-s{font-size:16px;line-height:1.35;color:var(--muted);margin-top:6px}

/* --------------------------------------------------------------- таблицы */

table{border-collapse:collapse;table-layout:fixed;width:100%;margin-top:44px;
      font-size:22px;line-height:1.4}
th{text-align:left;font-size:16px;font-weight:500;color:var(--muted);
   padding:0 18px 16px 0;border-bottom:2px solid var(--lilac)}
td{vertical-align:top;border-top:1px solid var(--border);padding:22px 18px 22px 0}
tbody tr:first-child td{border-top:none}
tr.is-recommended td{background:var(--lilacSoft)}
tr.is-recommended td:first-child{border-radius:12px 0 0 12px;padding-left:18px}
tr.is-recommended td:last-child{border-radius:0 12px 12px 0}
td:first-child{font-weight:600}
.t-mono{font-family:var(--mono-font);font-weight:400!important;font-size:17px}
.t-note{display:block;font-size:16px;color:var(--muted);margin-top:6px;font-weight:400}

/* Два варианта плотности. В шаблоне таблицы были на три строки, здесь бывает
   девять — воздух убирается раньше кегля, чтобы набор оставался в шкале. */
.table--tight{margin-top:34px}
.table--tight td{padding:16px 18px 16px 0}

.table--dense{margin-top:30px;font-size:18px}
.table--dense td{padding:10px 16px 10px 0}
.table--dense th{padding-bottom:12px}
.table--dense .t-note{font-size:14px;margin-top:3px}
.table--dense .t-mono{font-size:15px}

/* Метка состояния требования. Пастель фирменной палитры, а не светофор. */
.st{display:inline-block;padding:5px 11px;border-radius:999px;
    font:500 15px/1 var(--body-font);white-space:nowrap}
.st--ok{background:var(--mistSoft)}
.st--auto{background:var(--lilacSoft)}
.st--generated{background:var(--border)}
.st--attention{background:var(--peach)}

.disclosure{font-size:18px;line-height:1.45;color:var(--muted);margin-top:auto;
            padding-top:24px;max-width:950px}

/* ---------------------------------------------------------- основания */

.grounds{margin:34px 0 0;padding:0;list-style:none;display:grid;gap:14px}
.grounds li{display:grid;grid-template-columns:96px 130px 1fr;gap:20px;
            align-items:baseline;padding:14px 18px;border-radius:10px;
            background:var(--background)}
.grounds code{font:500 16px/1.3 var(--mono-font)}
.grounds em{font:400 15px/1.3 var(--mono-font);color:var(--muted);font-style:normal}
.grounds span{font-size:18px;line-height:1.4}

.party-head{display:flex;align-items:baseline;gap:16px;margin-top:40px;flex-wrap:wrap}
.party-head h3{margin:0}

/* --------------------------------------------------------- живой экран */

/* Вклейка с работающим экраном. Рамка тёмная и тонкая, адрес в ней — рабочая
   ссылка: зал уходит смотреть сам, и это единственная причина, по которой
   слайд вообще живой, а не картинка. */
.live .content{top:126px;bottom:88px}
.live h2{font-size:36px;letter-spacing:-1px;max-width:900px}
.win{margin-top:20px;height:452px;flex:none;display:flex;flex-direction:column;
     border-radius:12px;overflow:hidden;background:var(--ink)}
.win__bar{flex:none;height:44px;display:flex;align-items:center;gap:14px;padding:0 12px}
.win__url{font:500 15px/1 var(--mono-font);color:#fff;background:#ffffff1f;
          padding:7px 12px;border-radius:6px;min-width:0;overflow:hidden;
          text-overflow:ellipsis;white-space:nowrap}
.win__url:hover{background:#ffffff33;text-decoration:none}
.win__sub{font:400 14px/1 var(--body-font);color:var(--onInk);margin-left:auto;
          min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Экран внутри слайда уменьшается целиком, а не сжимается по ширине. Иначе
   приложению достаётся окно 995×408, оно переверстывается под узкое, и зал
   видит не тот экран, который откроет по ссылке. Кадр живёт в своей полосе
   1440×590 и масштабируется: 995 / 1440 = 0.691. */
.win__stage{position:relative;flex:1;min-height:0;overflow:hidden;background:#fff}
.win__frame{position:absolute;top:0;left:0;width:1440px;height:590px;border:0;
            background:#fff;display:block;transform:scale(.691);transform-origin:top left}
.win__print{display:none}
.win__shot{display:block;width:100%;height:auto;max-height:380px;
           object-fit:contain;object-position:top}
/* Только новая раскладка: окно и три шага помещаются на одном листе. */
.howto .content{top:126px}
.howto h2{font-size:36px;letter-spacing:-1px}
.howto .win{height:360px}
.howto .win__shot{height:100%;max-height:316px}
.howto .process-list{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:18px}
.howto .process-list li{display:block;padding:14px 0 0}
.howto .process-list h3{font-size:22px}
.howto .process-list p{font-size:18px;line-height:1.4;margin-top:8px}
.figures--four{grid-template-columns:repeat(4,1fr)}
.figures--four div{padding-top:20px}
.figures--four .fig-l,.figures--four .fig-s{padding:0;border:0}
.mobile-hint{display:none}
@media screen and (max-width:700px){
  .mobile-hint{display:block;position:fixed;top:12px;left:16px;right:16px;
    z-index:8;padding:12px 16px;border-radius:12px;background:var(--lilacSoft);
    color:var(--text);font-size:15px;line-height:1.4;text-align:center;pointer-events:none}
}
.win__cap{font-size:var(--caption-size);line-height:1.45;color:var(--muted);
          margin-top:14px;max-width:950px;flex:none}

/* ------------------------------------------------------------ плитка ссылок */

.links{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-top:44px}
.links--3{grid-template-columns:repeat(3,1fr)}
.links a{display:block;padding:24px 26px;border-radius:14px;background:var(--background);
         border-top:4px solid var(--lilac);min-width:0}
.links a:nth-child(2){border-top-color:var(--peach)}
.links a:nth-child(3){border-top-color:var(--mist)}
.links a:nth-child(4){border-top-color:var(--lilac)}
.links a:hover{background:var(--lilacSoft);text-decoration:none}
.links code{font:500 15px/1 var(--mono-font);color:var(--muted)}
.links b{display:block;font-family:var(--heading-font);font-weight:600;font-size:25px;
         line-height:1.2;letter-spacing:-.4px;margin:12px 0 10px}
.links span{font-size:18px;line-height:1.4;color:var(--muted)}

.links-slide .content{justify-content:center}
.links-slide .lede{max-width:800px}

/* ----------------------------------------------------- масштаб под экран */

/* Слайд фиксированный — 1123×794, как в шаблоне. На узком экране он не
   переверстывается, а уменьшается целиком: показ должен выглядеть одинаково
   и на проекторе, и на ноутбуке. zoom, а не transform, — чтобы высота
   страницы считалась сама. */
@media screen and (max-width:1187px){
  .deck{align-items:flex-start;padding:12px}
  .slide{zoom:var(--zoom,1)}
}

@media (prefers-reduced-motion:reduce){*{transition:none!important}}

@media print{
  @page{size:A4 landscape;margin:0}
  html,body{width:297mm;margin:0;background:white}
  .deck{display:block;padding:0;margin:0;gap:0}
  .slide{width:297mm;height:210mm;margin:0;break-after:page;break-inside:avoid;
         transform:none!important;zoom:1!important}
  .slide:last-child{break-after:auto}
  /* На бумаге живой экран показать нечем — вместо пустой рамки печатается
     адрес, по которому он открывается. */
  .win__frame,.slide .full__frame,.win__shot{display:none}
  .win__print{display:flex;position:absolute;inset:0;align-items:center;
              justify-content:center;background:var(--background);
              font:500 22px/1.4 var(--mono-font);color:var(--muted);
              text-align:center;padding:32px}
}

/* ============================================================================
   Заставка входа — нулевой слайд

   Тот же вход, что на ftd.by: марка рисуется обводкой, под ней световая линия,
   на уходе экран раскрывается двумя половинами. Половины — .op-curtain — лежат
   под содержимым слайда (z-index:-1 при isolation:isolate у .slide), поэтому
   пока они на месте, кадр выглядит сплошным.

   Статика описана здесь, движение — ниже, в разделе постраничного показа: без
   скрипта и на печати заставка должна быть просто первым слайдом.
   ========================================================================== */

/* Фона у заставки нет намеренно: тёмное дают половины экрана, и когда они
   разъезжаются, за ними должен показаться следующий слайд, а не подложка.
   Половины перекрываются (50.1% + 50.1%), поэтому щели по центру не бывает. */
.opening{background:transparent;color:var(--paper);padding:0}
.op-curtain{position:absolute;left:0;right:0;height:50.1%;background:var(--ink);
            z-index:-1;will-change:transform}
.op-up{top:0}
.op-down{bottom:0}
/* Светлая кромка по краю половины. За заставкой стоит обложка, и она тоже
   тёмная: без кромки раскрытие вышло бы чёрным по чёрному и его бы просто не
   заметили. Пока половины на месте, кромок нет — они зажигаются на уходе. */
.op-curtain::after{content:"";position:absolute;left:0;right:0;height:1px;
                   background:var(--lilac);opacity:0}
.op-up::after{bottom:0}
.op-down::after{top:0}

.op-top,.op-bottom{position:absolute;left:64px;right:64px;display:flex;
                   align-items:center;justify-content:space-between;gap:24px;
                   font-size:16px;color:var(--onInk)}
.op-top{top:46px}
.op-top>span:first-child{font-family:var(--heading-font);font-weight:700;
                         font-size:23px;color:var(--paper)}
.op-bottom{bottom:44px}
.op-hint{font:15px var(--mono-font)}

.op-identity{position:absolute;inset:0;display:flex;flex-direction:column;
             align-items:center;justify-content:center;padding-bottom:44px}
.op-mark{color:var(--lilac);line-height:0}
.op-word{font-family:var(--heading-font);font-weight:600;font-size:90px;
         line-height:1.1;letter-spacing:-.065em;margin-top:14px}
.op-word span{color:var(--onInk)}
.op-identity p{font-size:16px;color:var(--onInk);margin-top:26px}

/* Разделитель части: та же сборка, но вместо логотипа — название. Марка
   мельче, потому что главное здесь не знак, а то, что сейчас откроется. */
.op-mark--sm{margin-bottom:4px}
.op-kicker{font:15px var(--mono-font);color:var(--lilac);letter-spacing:.04em;
           margin-top:24px}
.op-title{font-family:var(--heading-font);font-weight:700;font-size:58px;
          line-height:1.08;letter-spacing:-2px;margin-top:18px;max-width:900px;
          text-align:center}
.op-title+p{font-size:22px;line-height:1.5;max-width:780px;text-align:center;
            margin-top:26px}

/* Живой экран во весь кадр: слайд перестаёт быть листом 1123×794 и занимает
   окно целиком. Приложению достаётся всё окно, и зал видит ровно ту страницу,
   которая откроется по ссылке, а не вклейку в слайд. */
.full__frame{position:absolute;inset:0;width:100%;height:100%;border:0;
             background:#fff;display:block}

/* Световая линия по центру — шов, по которому раскрывается экран. Пока
   заставка стоит, шва нет: по центру кадра марка, и линия резала бы её. */
.op-seam{position:absolute;left:0;right:0;top:50%;height:1px;background:#ddd6ff1f;
         opacity:0}
.op-seam span{display:block;height:100%;background:var(--lilac);transform:scaleX(0)}

/* Служебные слои показа. Без скрипта и на печати их нет вовсе. */
.deck-sweep,.deck-rail,.deck-nav{display:none}

/* ============================================================================
   Постраничный показ

   Колода листается, а не прокручивается: слайд занимает экран целиком, шаг
   делают клик, стрелки и колесо. Включает всё это app.js классом js-stage на
   <html> — без скрипта ниже ничего не применяется, и страница остаётся тем,
   чем была: колодой в столбик, которую можно прокрутить и распечатать.

   Раздел целиком в @media screen, поэтому печать (@page A4 landscape выше)
   работает по-прежнему: на бумаге нужны все слайды, а не текущий.
   ========================================================================== */

@media screen{

  :root{
    --t-in:660ms;      /* приход слайда */
    --t-out:440ms;     /* уход — короче прихода: внимание идёт вперёд */
    --t-rise:560ms;    /* появление блоков внутри слайда */
    --t-sweep:620ms;   /* световая полоса перехода */
    --stag:46ms;       /* шаг между блоками */
    --lag:150ms;       /* пауза перед первым блоком */
    --ease-slide:cubic-bezier(.22,.61,.36,1);
    --ease-curtain:cubic-bezier(.76,0,.24,1);
  }

  /* -------------------------------------------------------------- сцена */

  .js-stage,.js-stage body{height:100%;overflow:hidden}
  .js-stage .deck{position:fixed;inset:0;padding:0;gap:0;
                  display:grid;grid-template:1fr/1fr;place-items:center;
                  background:var(--background);overflow:hidden;overflow:clip;
                  transition:background-color 520ms ease}
  /* Тёмный слайд в светлой рамке на проекторе выглядит окном, а не кадром:
     поле вокруг слайда подстраивается под слайд. */
  .js-stage .deck[data-tone="dark"]{background:var(--ink)}

  /* Слайды лежат в одной ячейке сетки и по очереди выходят наверх. zoom, а не
     transform: живому кадру внутри слайда достаётся то же окно 1440×590, в
     каком приложение открывается по ссылке. */
  .js-stage .deck>.slide{grid-area:1/1;display:none;zoom:var(--zoom,1);
                         box-shadow:0 26px 64px -34px rgba(20,20,20,.45)}
  /* Пока app.js не встал — а если не встанет, то и все четыре секунды до
     возврата к обычной странице — на сцене стоит первый слайд. Это тот же
     кадр, который зал увидит и дальше, так что мигания на подмене нет. */
  .js-stage .deck>.slide:first-child{display:block}
  .js-live .deck>.slide:first-child{display:none}
  .js-stage .deck>.slide.is-active{display:block;z-index:2}
  /* Кадр во весь экран: ни масштаба листа, ни тени — окно целиком. */
  .js-stage .deck>.slide.live--full{width:100%;height:100%;zoom:1;padding:0;
                                    box-shadow:none;background:#fff}
  .js-stage .deck>.slide.is-leaving{display:block;z-index:1;pointer-events:none}
  /* Соседний слайд держится в кадре прозрачным: iframe с loading="lazy"
     успевает подняться до того, как ведущий до него дойдёт. */
  .js-stage .deck>.slide.is-armed{display:block;z-index:0;opacity:0;
                                  pointer-events:none}

  /* ------------------------------------------------------- смена слайда */

  .js-stage .slide.is-active[data-enter="fwd"]{
    animation:sl-in-fwd var(--t-in) var(--ease-slide) both}
  .js-stage .slide.is-active[data-enter="back"]{
    animation:sl-in-back var(--t-in) var(--ease-slide) both}
  .js-stage .slide.is-leaving[data-exit="fwd"]{
    animation:sl-out-fwd var(--t-out) cubic-bezier(.4,0,1,1) both}
  .js-stage .slide.is-leaving[data-exit="back"]{
    animation:sl-out-back var(--t-out) cubic-bezier(.4,0,1,1) both}

  @keyframes sl-in-fwd{from{opacity:0;transform:translate3d(48px,0,0) scale(.985)}
                       to{opacity:1;transform:none}}
  @keyframes sl-in-back{from{opacity:0;transform:translate3d(-48px,0,0) scale(.985)}
                        to{opacity:1;transform:none}}
  @keyframes sl-out-fwd{from{opacity:1;transform:none}
                        to{opacity:0;transform:translate3d(-40px,0,0) scale(.975)}}
  @keyframes sl-out-back{from{opacity:1;transform:none}
                         to{opacity:0;transform:translate3d(40px,0,0) scale(.975)}}

  /* Живой экран не двигаем: сдвиг и масштаб размывают работающее приложение,
     и переход выходит грязным. Меняется только прозрачность. */
  .js-stage .slide.live--full.is-active[data-enter]{
    animation:full-in var(--t-in) ease both}
  .js-stage .slide.live--full.is-leaving[data-exit]{
    animation:full-out var(--t-out) ease both}
  @keyframes full-in{from{opacity:0}to{opacity:1}}
  @keyframes full-out{from{opacity:1}to{opacity:0}}

  /* Содержимое въезжает по порядку чтения. Индекс --i проставляет app.js: у
     списков, таблиц и плиток шагом идут строки, а не блок целиком. */
  .js-stage .slide.is-active .rise{
    animation:rise var(--t-rise) var(--ease-slide) both;
    animation-delay:calc(var(--lag) + var(--i,0) * var(--stag))}
  @keyframes rise{from{opacity:0;transform:translate3d(0,20px,0)}
                  to{opacity:1;transform:none}}

  /* Слайд, который открывают раздвинутые половины заставки: он уже на месте,
     ему остаётся успокоить масштаб, а блокам — дождаться, пока откроют. */
  .js-stage .slide.is-active[data-enter="curtain"]{
    animation:sl-reveal 1900ms var(--ease-slide) both}
  .js-stage .slide.is-active[data-enter="curtain"] .rise{
    animation-delay:calc(940ms + var(--i,0) * var(--stag))}
  @keyframes sl-reveal{from{transform:scale(1.05)}to{transform:none}}

  /* Световая полоса поперёк экрана — то же движение, что у шва заставки:
     переход читается как одно движение, а не как подмена картинки. */
  .js-stage .deck-sweep{display:block;position:fixed;inset:0;z-index:5;
                        overflow:hidden;pointer-events:none}
  .js-stage .deck-sweep>span{position:absolute;top:0;bottom:0;left:0;width:190px;
    opacity:0;transform:translate3d(-240px,0,0);
    background:linear-gradient(90deg,transparent,rgba(198,186,255,.42),
               rgba(243,239,255,.72),rgba(198,186,255,.42),transparent)}
  .js-stage .deck-sweep[data-run="fwd"]>span{
    animation:sweep-fwd var(--t-sweep) cubic-bezier(.45,0,.35,1) both}
  .js-stage .deck-sweep[data-run="back"]>span{
    animation:sweep-back var(--t-sweep) cubic-bezier(.45,0,.35,1) both}
  @keyframes sweep-fwd{0%{transform:translate3d(-240px,0,0);opacity:0}
                       16%{opacity:1}84%{opacity:1}
                       100%{transform:translate3d(100vw,0,0);opacity:0}}
  @keyframes sweep-back{0%{transform:translate3d(100vw,0,0);opacity:0}
                        16%{opacity:1}84%{opacity:1}
                        100%{transform:translate3d(-240px,0,0);opacity:0}}

  /* Полоса пройденного по нижнему краю: в зале видно, сколько ещё осталось. */
  .js-stage .deck-rail{display:block;position:fixed;left:0;right:0;bottom:0;
                       height:2px;z-index:6;pointer-events:none;
                       background:rgba(20,20,20,.07)}
  .js-stage .deck[data-tone="dark"]~.deck-rail{background:rgba(237,235,228,.12)}
  .js-stage .deck-rail>span{display:block;height:100%;width:0;background:#B9AAFF;
                            transition:width 520ms var(--ease-slide)}

  /* ----------------------------------------------------------- заставка */

  /* Своей смены у заставки нет: движение несут марка, шов и половины экрана.
     Правило идёт после общих и с тем же весом — оно их и снимает. */
  .js-stage .opening.is-active[data-enter]{animation:none}

  /* Половины и шов живут внутри слайда, а слайд — лист 1123×794, уменьшенный
     под окно: на широком экране он уже окна, и раскрытие шло не во всю ширину,
     а по краю листа — за кромкой был виден следующий экран. Здесь половины
     выходят за лист: вширь с запасом, а вглубь — ровно на половину окна, чтобы
     уход на 101% своей высоты уводил кромку за край и не дальше. Деление на
     --zoom переводит размеры окна в координаты листа, который этим же --zoom и
     уменьшен. Перекрытие в 1px по центру держит шов сплошным на дробном
     масштабе. На печати и без скрипта половины остаются в границах листа. */
  .js-stage .deck>.slide.opening{overflow:visible}
  .js-stage .opening .op-curtain,
  .js-stage .opening .op-seam{left:calc(-60vw / var(--zoom,1));
                              right:calc(-60vw / var(--zoom,1))}
  .js-stage .opening .op-curtain{height:calc(50vh / var(--zoom,1) + 2px)}
  .js-stage .opening .op-up{top:auto;bottom:calc(50% - 1px)}
  .js-stage .opening .op-down{top:calc(50% - 1px);bottom:auto}

  /* Обводка спрятана только при живом скрипте: он её и рисует. На печати и
     пока app.js не встал марка стоит сплошной. */
  .js-live .op-draw path{stroke-dasharray:280;stroke-dashoffset:280}
  .js-live .op-draw path:nth-child(4){stroke-dasharray:360;stroke-dashoffset:360}
  .js-stage .opening.is-active .op-draw path{
    animation:op-draw 1500ms cubic-bezier(.65,.05,.36,1) both}
  .js-stage .opening.is-active .op-draw path:nth-child(2){animation-delay:180ms}
  .js-stage .opening.is-active .op-draw path:nth-child(3){animation-delay:360ms}
  .js-stage .opening.is-active .op-draw path:nth-child(4){animation-delay:540ms}
  @keyframes op-draw{to{stroke-dashoffset:0}}

  /* Марку несёт обводка, остальное поднимается по очереди. Порядок один и у
     заставки (логотип, строка), и у разделителя (метка, название, строка). */
  .js-stage .opening.is-active .op-identity>*+*{
    animation:rise 900ms var(--ease-slide) both}
  .js-stage .opening.is-active .op-identity>*:nth-child(2){animation-delay:900ms}
  .js-stage .opening.is-active .op-identity>*:nth-child(3){animation-delay:1350ms}
  .js-stage .opening.is-active .op-identity>*:nth-child(4){animation-delay:1750ms}
  .js-stage .opening.is-active .op-top,
  .js-stage .opening.is-active .op-bottom{animation:op-fade 800ms ease 2050ms both}
  @keyframes op-fade{from{opacity:0}to{opacity:1}}

  /* Возврат на заставку: половины сходятся и закрывают обложку. */
  .js-stage .opening.is-active[data-enter="back"] .op-up{
    animation:op-close-up 900ms var(--ease-curtain) both}
  .js-stage .opening.is-active[data-enter="back"] .op-down{
    animation:op-close-down 900ms var(--ease-curtain) both}
  @keyframes op-close-up{from{transform:translateY(-101%)}to{transform:none}}
  @keyframes op-close-down{from{transform:translateY(101%)}to{transform:none}}

  /* Уход заставки: марка гаснет, шов вспыхивает, экран раскрывается. Заставка
     держится поверх обложки (z-index:3) — открывают именно её. op-hold ничего
     не двигает: она задаёт длину ухода целиком, и по её концу app.js убирает
     слайд со сцены. */
  .js-stage .deck>.slide.opening.is-leaving{z-index:3}
  .js-stage .opening.is-leaving[data-exit]{animation:op-hold 2050ms linear both}
  @keyframes op-hold{0%,97%{opacity:1}100%{opacity:0}}
  .js-stage .opening.is-leaving .op-identity{
    animation:op-brand-out 1150ms cubic-bezier(.4,0,.2,1) both}
  .js-stage .opening.is-leaving .op-top,
  .js-stage .opening.is-leaving .op-bottom{animation:op-caption-out 800ms 240ms both}
  .js-stage .opening.is-leaving .op-seam{animation:op-flash 1000ms both}
  .js-stage .opening.is-leaving .op-seam span{
    animation:op-seam-open 900ms cubic-bezier(.2,0,.2,1) both}
  @keyframes op-seam-open{to{transform:scaleX(1)}}
  .js-stage .opening.is-leaving .op-curtain::after{
    animation:op-edge 1500ms 520ms both}
  @keyframes op-edge{0%{opacity:0}12%{opacity:.9}72%{opacity:.55}100%{opacity:0}}
  .js-stage .opening.is-leaving .op-up{
    animation:op-open-up 1500ms var(--ease-curtain) 520ms both}
  .js-stage .opening.is-leaving .op-down{
    animation:op-open-down 1500ms var(--ease-curtain) 520ms both}
  @keyframes op-brand-out{0%{opacity:1;transform:none}45%{opacity:1}
                          100%{opacity:0;transform:scale(.94) translateY(-16px)}}
  @keyframes op-caption-out{to{opacity:0}}
  @keyframes op-flash{0%,65%{opacity:1}100%{opacity:0}}
  @keyframes op-open-up{to{transform:translateY(-101%)}}
  @keyframes op-open-down{to{transform:translateY(101%)}}

  /* Стрелки листания. Живой экран занимает всё окно, клик внутрь кадра до
     колоды не доходит — мышью такой слайд листается только отсюда. Панель
     крупная, но в покое гаснет вместе с курсором и показу не мешает. */
  .js-stage .deck-nav{display:flex;position:fixed;left:0;right:0;bottom:26px;
    z-index:7;justify-content:center;align-items:center;gap:12px;
    pointer-events:none;transition:opacity 380ms ease}
  .js-stage .deck-nav>*{pointer-events:auto}
  .deck-nav__b{width:60px;height:60px;padding:0;border-radius:999px;
    border:1px solid var(--border);background:rgba(251,250,247,.9);
    -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
    color:var(--text);font:400 27px/1 var(--body-font);cursor:pointer;
    display:flex;align-items:center;justify-content:center;
    transition:background 160ms ease,border-color 160ms ease,opacity 160ms ease}
  .deck-nav__b:hover{background:var(--lilacSoft);border-color:var(--lilac)}
  .deck-nav__b[disabled]{opacity:.22;cursor:default}
  .deck-nav__folio{font:13px var(--mono-font);color:var(--muted);min-width:88px;
    text-align:center;padding:12px 0;border-radius:999px;
    border:1px solid var(--border);background:rgba(251,250,247,.9);
    -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}
  .deck-nav__folio:empty{display:none}
  /* На тёмном слайде та же панель, вывернутая. */
  .js-stage .deck[data-tone="dark"]~.deck-nav .deck-nav__b,
  .js-stage .deck[data-tone="dark"]~.deck-nav .deck-nav__folio{
    background:rgba(237,235,228,.10);border-color:rgba(237,235,228,.20);
    color:var(--paper)}
  .js-stage .deck[data-tone="dark"]~.deck-nav .deck-nav__b:hover{
    background:rgba(237,235,228,.2)}

  /* Показ идёт с проектора: курсор и панель, забытые на кадре, только мешают. */
  .js-stage.is-idle .deck{cursor:none}
  /* Погасшая панель ещё и не ловит клики: она висит над живым экраном, и
     невидимая кнопка перехватывала бы нажатие, адресованное приложению.
     Мышь будит панель раньше, чем доедет до кнопки. */
  .js-stage.is-idle .deck-nav,
  .js-stage.is-idle .deck-nav>*{opacity:0;pointer-events:none}

  /* Кому движение мешает — тому слайды просто сменяются. app.js в этом режиме
     не ждёт конца анимации, а убирает ушедший слайд сразу. */
  @media (prefers-reduced-motion:reduce){
    .js-stage .slide,.js-stage .slide *{animation:none!important}
    .js-live .op-draw path{stroke-dashoffset:0!important}
    .js-stage .deck-sweep{display:none}
  }
}

/* FTD hosting: native fallback until the Labs cursor is positioned. */
html, body, .deck, .deck * { cursor: auto; }
a, a *, button, button * { cursor: pointer; }
button:disabled { cursor: default; }
.js-stage.is-idle .deck { cursor: auto; }
.js-stage.is-idle .deck-nav, .js-stage.is-idle .deck-nav > * { opacity: 1; }
.js-stage.is-idle .deck-nav > * { pointer-events: auto; }
.host-exit { position: fixed; top: 16px; right: 18px; z-index: 20; padding: 10px 16px;
 border: 1px solid #dedad2; border-radius: 30px; background: #fbfaf7; color: #141414;
 font: 500 13px/1.3 var(--body-font); }
.demo-launch { width: 100%; height: 100%; min-height: 260px; display: flex;
 flex-direction: column; justify-content: center; align-items: center; gap: 20px;
 padding: 48px; text-align: center; background: #eae5ff; color: #141414; }
.demo-launch strong { font: 700 36px/1.2 var(--heading-font); }
.demo-launch p { max-width: 660px; font: 20px/1.5 var(--body-font); }
.demo-launch__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 14px; }
.demo-launch a, .demo-launch button { padding: 14px 22px; border: 1px solid #141414;
 border-radius: 10px; background: #141414; color: #fbfaf7; font: 600 18px/1.3 var(--body-font); }
.demo-launch button { background: transparent; color: #141414; }
.demo-popout { position: absolute; right: 18px; bottom: 92px; z-index: 12;
 padding: 10px 16px; background: #fbfaf7; color: #141414; border: 1px solid #dedad2;
 border-radius: 30px; font: 500 14px/1.3 var(--body-font); }
.demo-launch + .demo-popout { display: none; }
@media (max-width: 500px) {
 .demo-launch { padding: 24px; } .demo-launch strong { font-size: 28px; }
 .host-exit { top: auto; bottom: 24px; right: 12px; padding: 10px 12px; }
 .js-stage .deck-nav { justify-content: flex-start; padding-left: 12px; gap: 8px; }
 .js-stage .deck-nav__b { width: 44px; height: 44px; }
 .js-stage .deck-nav__folio { min-width: 68px; }
}
@media print { .host-exit, .demo-popout, .demo-launch { display: none; } }
