/* ============================================================
   Я зову — карточка шаблона с редактором
   ------------------------------------------------------------
   Страница, где происходит покупка. Три принципиальных отличия
   от конкурентов:
   1. Редактировать можно и до, и после оплаты — об этом сказано
      прямо у кнопки, а не в разделе помощи.
   2. Видно все три выхода одного шаблона: печатная карточка,
      страница гостя и превью ссылки в мессенджере.
   3. Формат файлов, срок хранения и возврат — у кнопки «В корзину»,
      а не мелким шрифтом на другой странице.
   ============================================================ */

/* padding-block, а не padding.
   Сокращённое свойство обнуляло боковые отступы .shell — оба
   класса стоят на одном элементе, и это правило идёт позже.
   На телефоне редактор упирался в самый край экрана. */
/* ============================================================
   СЕТКА ПЕРВОГО ЭКРАНА — ПО ИМЕНАМ ОБЛАСТЕЙ

   Здесь было две коробки рядом: превью и «всё остальное». На
   телефоне они складывались одна под другую в том же порядке, и
   заголовок страницы оказывался ПОД приглашением — человек с
   телефона видел картинку без единого слова о том, что это и
   сколько стоит.

   Обёртки больше нет. В разметке части лежат в том порядке,
   какой нужен на телефоне: заголовок, приглашение, поля,
   редактор, покупка. Широкий экран раскладывает те же части в
   две колонки именами областей, не трогая разметку.

   Порядок чтения и табуляции совпадает с видимым в обеих
   раскладках: на широком экране левая колонка читается раньше
   правой, и разметка идёт ровно так же.

   ОДНО ОТСТУПЛЕНИЕ ОТ ЗАДАНИЯ, И ОНО НАМЕРЕННОЕ

   Задание ставит «Изменить дизайн» на телефоне сразу под
   приглашением, до полей. Кнопка стоит после полей — и там, и
   там. Открыть редактор до того, как вписано имя, значит войти
   в него с демонстрационным текстом дизайнера и двигать чужие
   строки. «Изменить дизайн» — это вопрос «хватит ли мне
   этого», и задавать его надо после «этого», а не вместо.
   ============================================================ */
.prod-page{
  display:grid;
  grid-template-columns:minmax(0,23rem) minmax(0,1fr);
  grid-template-areas:
    "again again"
    "pv    head"
    "pv    form"
    "pv    edit"
    "pv    editnote"
    "pv    buy"
    "pv    .";
  align-content:start;
  gap:0 3rem;
  padding-block:1.4rem 3rem;
}
.prod-page > .ed-again{grid-area:again}
.prod-page > .ed-head{grid-area:head}
.prod-page > .pv-col{grid-area:pv}
.prod-page > .prod-form{grid-area:form}
.prod-page > .ed-open{grid-area:edit}
.prod-page > .ed-open-s{grid-area:editnote}
.prod-page > .buy{grid-area:buy}

/* ---------- левая колонка: превью ---------- */
.pv-col{position:sticky;top:76px;display:flex;flex-direction:column;gap:.75rem}

/* Спокойная строка над карточкой: что это и как разглядеть.
   Раньше здесь первым стоял ряд из трёх кнопок, и человек
   выбирал, какое приглашение показать, ещё не увидев ни
   одного. */
.pv-head{display:flex;align-items:center;justify-content:space-between;gap:.6rem;min-height:2rem}
.pv-title{font-size:.9rem;color:var(--ink-2)}
.pv-zoom{
  display:grid;place-items:center;width:36px;height:36px;
  border:1px solid var(--rule);border-radius:100px;background:var(--card);
  color:var(--ink-2);cursor:pointer;
}
.pv-zoom:hover{border-color:var(--ink-3);color:var(--ink)}
.pv-zoom svg{width:1.05rem;height:1.05rem;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round}

/* Под карточкой: «Увеличить» словами, по центру — как в макете.
   Строка «превью обновляется сразу» уехала отсюда: обещание,
   которое страница выполняет на глазах, не нуждается в подписи,
   а место под карточкой занял водяной знак и объяснение к нему. */
.pv-under{display:flex;align-items:center;justify-content:center;gap:.6rem;flex-wrap:wrap}
.pv-big{
  display:inline-flex;align-items:center;gap:.4rem;min-height:36px;
  padding:.3rem .7rem;border:1px solid var(--rule);border-radius:100px;
  background:var(--card);color:var(--ink-2);font:inherit;font-size:.85rem;cursor:pointer;
}
.pv-big:hover{border-color:var(--ink-3);color:var(--ink)}
.pv-big svg{width:1rem;height:1rem;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.pv-live{font-size:.8rem;color:var(--ink-3)}

.pv-switch{display:flex;gap:.25rem;background:var(--paper-2);border:1px solid var(--rule);padding:.22rem;border-radius:2px}
.pv-switch button{flex:1;background:transparent;border:0;padding:.44rem .3rem;font-size:.82rem;color:var(--ink-2);cursor:pointer;border-radius:2px;white-space:nowrap}
/* На узком экране три подписи в одну строку не помещаются, а
   nowrap не даёт им перенестись — переключатель просто вылезал
   за край, и вся страница получала горизонтальную прокрутку.
   Разрешаем перенос: две строки в кнопке лучше, чем страница,
   которую можно сдвинуть вбок. */
@media (max-width:400px){
  /* Перенос делает кнопку уже, но не выше: три подписи в одну
     строку не помещаются, а «Печать» переносить нечего — она
     оставалась в 27 точек высотой. Палец накрывает около сорока
     пяти, и промах здесь стоит дорого: это переключатель между
     тем, что человек покупает, на самом дорогом экране сайта.
     Задаём высоту явно, а подписи центрируем — иначе короткая
     «Печать» прижмётся к верху рядом с двухстрочными соседями. */
  .pv-switch button{
    white-space:normal;font-size:.76rem;padding:.4rem .18rem;line-height:1.2;
    /* 36 было компромиссом при пороге проверки в 30. Порог
       поднят до 44 — и правильно: это переключатель между тем,
       что человек покупает. */
    min-height:44px;display:flex;align-items:center;justify-content:center;text-align:center;
  }
}
.pv-switch button[aria-pressed="true"]{background:var(--card);color:var(--ink);font-weight:500;box-shadow:var(--shadow-s)}
.pv-switch button[disabled]{opacity:.4;cursor:not-allowed}
.pv-body{min-height:30rem}
/* ============================================================
   ВОДЯНОЙ ЗНАК РИСУЕТ ПЛАГИН
   ------------------------------------------------------------
   Правило жило здесь с выпуска 109 и было прибито гвоздями:
   текст, прозрачность, крупность и два места вписаны в стили.
   Теперь этим владеет yazovu-znak — там же настройки и там же
   объяснение, почему знак не может дотянуться до оплаченного
   файла.

   Здесь остаётся только строка-обещание под карточкой: она
   принадлежит странице, а не знаку, и печатает её тема — но
   лишь тогда, когда знак правда стоит (Yzn_Znak::est).
   ============================================================ */

/* Строка про знак. Щит — не украшение: он отличает обещание от
   предупреждения, а строка эта именно обещание. */
.pv-vodyanoy{
  display:flex;align-items:center;justify-content:center;gap:.45rem;flex-wrap:wrap;
  margin:.75rem 0 0;font-size:.82rem;line-height:1.4;color:var(--ink-2);text-align:center;
}
.pv-vodyanoy svg{
  width:1.15rem;height:1.15rem;flex:none;fill:none;stroke:var(--good-ink,var(--brand));
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;
}

/* Кружок «i» — та же сноска, что звёздочка в текстах: один
   обработчик на весь сайт (skin.js), одна разметка, одно
   поведение с клавиатуры. Отличается только видом. */
.ft-star--i{
  display:inline-grid;place-items:center;width:22px;height:22px;
  border-radius:100px;background:var(--paper-2);color:var(--ink-2);
  font-size:.72rem;font-style:italic;font-weight:600;line-height:1;
  vertical-align:middle;opacity:1;cursor:pointer;
}
.ft-star--i:hover{background:var(--ed-pick-soft,var(--paper-2));color:var(--ink)}
.ft-tip--card{
  left:50%;transform:translateX(-50%);
  background:var(--card);color:var(--ink-2);
  border:1px solid var(--rule-2);box-shadow:var(--shadow-l);
  text-align:left;white-space:normal;
}
.ft-tip--card b{display:block;margin-bottom:.25rem;color:var(--ink);font-weight:500}
@media (max-width:520px){
  .ft-tip--card{left:auto;right:0;transform:none}
}

.pv-print .yz-inv-wrap{box-shadow:var(--shadow-l)}
/* Курсор говорит, что будет по нажатию. В расширенном режиме
   нажатие означает другое — «выбрать строку», — и там курсор
   свой, из правил ниже. */
.pv-print .yz-inv-wrap{cursor:zoom-in}
.pv-print .yz-inv-wrap:has([data-rz]){cursor:default}
.pv-cap{font-size:.78rem;color:var(--ink-3);text-align:center;margin:0}
.pv-cap b{color:var(--ink-2);font-weight:500}

/* телефон гостя */
.g-phone{width:100%;max-width:17.5rem;margin:0 auto;border:9px solid #2C2529;border-radius:30px;background:var(--card);box-shadow:var(--shadow-l);overflow:hidden}
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]) .g-phone{border-color:#4A4045}}
:root[data-theme="dark"] .g-phone{border-color:#4A4045}
.g-bar{background:var(--paper-2);font-size:.66rem;color:var(--ink-3);padding:.35rem .8rem;display:flex;justify-content:space-between;border-bottom:1px solid var(--rule)}
.g-body{padding:.85rem .85rem 1rem;display:flex;flex-direction:column;gap:.7rem}
.g-crop{overflow:hidden;height:9rem;position:relative;border:1px solid var(--rule)}
.g-crop .yz-inv-wrap{position:absolute;top:-2.1rem;left:0;right:0}
.g-meta{display:grid;grid-template-columns:auto 1fr;gap:.32rem .7rem;font-size:.8rem;margin:0}
.g-meta dt{color:var(--ink-3)}
.g-meta dd{margin:0}
.g-rsvp{display:flex;gap:.4rem}
.g-rsvp button{flex:1;padding:.5rem;border-radius:2px;border:1px solid var(--rule-2);background:var(--card);cursor:pointer;font-size:.85rem}
.g-rsvp button.yes[aria-pressed="true"]{background:var(--good-ink);border-color:var(--good-ink);color:var(--paper);font-weight:500}
.g-rsvp button.no[aria-pressed="true"]{background:var(--brick);border-color:var(--brick);color:var(--paper);font-weight:500}
.g-hint{font-size:.74rem;color:var(--ink-3);text-align:center;margin:0;min-height:1rem}

/* превью ссылки в мессенджере — того, что увидят гости в чате */
.chat{background:var(--paper-2);border:1px solid var(--rule);padding:1rem;display:flex;flex-direction:column;gap:.6rem;border-radius:4px}
.bubble{background:var(--card);border:1px solid var(--rule);border-radius:10px 10px 10px 2px;padding:.55rem .75rem;font-size:.85rem;max-width:90%}
.bubble.me{align-self:flex-end;border-radius:10px 10px 2px 10px;background:var(--brand-soft);border-color:var(--brand-soft)}
.link-card{border:1px solid var(--rule);border-radius:6px;overflow:hidden;background:var(--card);max-width:92%;align-self:flex-end}
/* Кадр под og:image. На проде это отдельный ландшафтный рендер
   1200×630 из того же шаблона; здесь — кроп по центру имени. */
.link-img{height:8rem;overflow:hidden;position:relative;background:var(--paper-2)}
.link-img .yz-inv-wrap{position:absolute;top:-7rem;left:0;right:0}
.link-txt{padding:.5rem .65rem}
.link-txt b{display:block;font-size:.82rem;font-weight:600}
.link-txt span{display:block;font-size:.75rem;color:var(--ink-2);margin-top:.1rem}
.link-txt i{display:block;font-style:normal;font-size:.7rem;color:var(--ink-3);margin-top:.25rem;text-transform:uppercase;letter-spacing:.05em}

/* ---------- правая колонка: редактор ---------- */

/* Полоса повтора. Приглушённая, а не акцентная: она ничего
   не предлагает и никуда не зовёт — только объясняет, почему
   в полях уже стоит текст. Акцент здесь оттягивал бы внимание
   от кнопки «В корзину», ради которой человек пришёл.
   Выделено внутри ровно одно — «Дату выберите новую», потому
   что это единственное действие, о котором полоса просит. */
.ed-again{
  display:flex;flex-direction:column;gap:.3rem;align-items:flex-start;
  margin:0 0 1.1rem;padding:.75rem .9rem;border-radius:10px;
  background:var(--paper-2);border:1px solid var(--rule);
  font-size:.87rem;line-height:1.5;color:var(--ink-2);
}
.ed-again-t{font-weight:600;color:var(--ink)}
.ed-again b{font-weight:600;color:var(--ink)}
.ed-again a{color:var(--ink-2);text-decoration:underline;
  /* 24 точки по нижней границе цели: ссылка мелкая и стоит
     последней, до неё дотягиваются большим пальцем. */
  display:inline-flex;align-items:center;min-height:24px}

.ed-head{margin:0 0 1rem}

/* Теги над заголовком — настоящие термины каталога, значит
   ссылки. Мелкие и спокойные: это не навигация первого
   порядка, а подпись «из какого он ряда». */
/* Разделы каталога над заголовком. Капитель с разрядкой, как в
   макете: это не ссылки «читать дальше», а подпись «где мы
   находимся», и подчёркивание делало из неё меню. */
.ed-tags{
  display:flex;flex-wrap:wrap;gap:.45rem;margin:0 0 .5rem;
  font-size:.72rem;letter-spacing:.11em;text-transform:uppercase;color:var(--ink-3);
}
.ed-tags a{color:var(--ink-3);text-decoration:none}
.ed-tags a:hover{color:var(--ink-2)}

.ed-head h1{font-size:clamp(1.6rem,3.4vw,2.2rem);line-height:1.15;margin:0 0 .35rem}
.ed-sub{margin:0;color:var(--ink-2);font-size:.95rem}

/* Что делать дальше. Отдельной строкой и тише описания: это
   не про товар, а про то, как им пользоваться. */
.ed-do{margin:.55rem 0 0;font-size:.88rem;color:var(--ink-3)}
.rating{display:flex;gap:.5rem;align-items:center;font-size:.86rem;color:var(--ink-2);margin:.5rem 0 0}
.rating .stars{color:var(--amber);letter-spacing:.1em}
.rating a{color:var(--ink-2)}

.tabs{display:flex;gap:0;border-bottom:1px solid var(--rule);margin:1.5rem 0 0}
.tabs button{
  background:transparent;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;
  padding:.6rem .9rem;font-size:.92rem;color:var(--ink-2);cursor:pointer;
  /* Вкладка — цель под палец, а не подпись: она переключает
     половину экрана. Была 41 точка. */
  min-height:44px;
}
/* Три вкладки в одну строку при 320 точках не помещаются:
   «Событие» уезжало за край и тащило за собой всю страницу.
   Прокрутку вбок здесь делать нельзя — уехавшая вкладка
   перестаёт существовать для того, кто не догадался её
   потянуть. Переносим и ужимаем подписи. */
@media (max-width:400px){
  .tabs{flex-wrap:wrap;row-gap:.15rem}
  .tabs button{padding:.55rem .6rem;font-size:.86rem}
}
.tabs button[aria-selected="true"]{color:var(--ink);border-bottom-color:var(--brand);font-weight:500}
.tabs button[disabled]{opacity:.45;cursor:not-allowed}
.panel{padding:1.3rem 0 0}
.panel[hidden]{display:none}

.row{display:grid;grid-template-columns:1fr 1fr;gap:.75rem .9rem}
.row.one{grid-template-columns:1fr}
.fld{display:flex;flex-direction:column;gap:.25rem}
/* Подпись поля — общая для всего сайта, см. pages.css. Здесь
   было своё правило только для этой страницы, и оно означало бы
   два языка подписей: строчными на товаре, капителью в корзине. */
.fld label{font-size:.84rem;letter-spacing:0;text-transform:none;color:var(--ink-2)}
.fld input,.fld select,.fld textarea{
  font-family:var(--sans);font-size:.95rem;padding:.55rem .65rem;background:var(--card);
  border:1px solid var(--rule-2);border-radius:2px;color:var(--ink);width:100%;
}
.fld textarea{resize:vertical;min-height:4.5rem;line-height:1.45}
.fld .hint{font-size:.78rem;color:var(--ink-3)}

.suggest{display:flex;gap:.4rem;flex-wrap:wrap;margin:.7rem 0 0}
/* Кнопки подсказок были 31 точку высотой. Их четыре в ряд,
   и по ним целятся пальцем — это не украшение строки, а выбор. */
.suggest button{background:var(--card);border:1px solid var(--rule-2);border-radius:100px;
  padding:.28rem .68rem;font-size:.82rem;color:var(--ink-2);cursor:pointer;
  min-height:44px;display:inline-flex;align-items:center}
.suggest button:hover{border-color:var(--brand);color:var(--brand)}

.opt-title{font-size:.74rem;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3);margin:1.4rem 0 .5rem}
.opt-title:first-child{margin-top:0}
.swatches{display:flex;gap:.5rem;flex-wrap:wrap}
.swatches button{
  width:2.4rem;height:2.4rem;border-radius:50%;border:2px solid transparent;
  cursor:pointer;padding:0;box-shadow:inset 0 0 0 1px rgba(0,0,0,.12);
}
.swatches button[aria-pressed="true"]{border-color:var(--brand);box-shadow:inset 0 0 0 1px rgba(0,0,0,.12),0 0 0 2px var(--paper)}
/* Здесь были .seg — сегментные кнопки внутри карточки шаблона.
   Разметки с этим классом на сайте не осталось ни одной: то, что
   их использовало, давно набрано .chips и .swatches, а последним
   ушёл .seg из полосы прототипа в base.css. Правило переживало
   свою разметку и обещало по файлу стилей компонент, которого
   нет, — а по файлу стилей как раз и читают, что на сайте есть. */
/* Здесь были .checks и .chk — оформление двух галочек «Добавить»,
   фотографии и QR-кода. Обе галочки убраны (почему — в
   single-yz_template.php), разметки с этими классами в теме
   не осталось ни одной, и правила ушли следом.

   Мёртвые стили — не просто лишний вес: по файлу стилей читают,
   что на сайте есть. */

/* ---------- выбор тарифа и покупка ---------- */
/* ============================================================
   ПЕРЕХОД В РЕДАКТОР
   ------------------------------------------------------------
   Во всю ширину и светлая. Красная заливка на этой странице
   означает один следующий шаг — «В корзину», — и вторая красная
   кнопка означала бы два первых шага сразу.

   Две строки, а не одна: название говорит, куда ведёт, подпись —
   что там можно. Без подписи «Изменить дизайн» читается как
   «выбрать другой шаблон».
   ============================================================ */
/* Кнопка во всю ширину, бледно-фиолетовая — тем же цветом, что
   в самом редакторе помечено выбранное. Красная на этой странице
   означает покупку, и второй красной быть не может.

   БУКВЫ НЕ ТОГО ЖЕ ЦВЕТА, ЧТО ЗАЛИВКА

   Первая версия красила надпись самим --ed-pick (#7562F3), и
   проверка контраста нашла 4,1 при норме 4,5 — во всех четырёх
   сочетаниях оформления и темы сразу. Причина не в оттенке, а в
   том, что одним числом это не решается: заливка бледная на
   светлой теме и тёмная на тёмной, и цвет, читаемый на одной,
   на другой сливается.

   Поэтому у букв свой оттенок на каждую тему: тёмно-фиолетовый
   на светлой, светло-фиолетовый на тёмной. Заливка и рамка
   остаются от --ed-pick — узнаётся кнопка по ним. */
:root{--pick-ink:#5140C4}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){--pick-ink:#B7ADFF}
}
:root[data-theme="dark"]{--pick-ink:#B7ADFF}

.ed-open{
  display:flex;align-items:center;justify-content:center;gap:.5rem;
  width:100%;margin:1.1rem 0 0;padding:.72rem .95rem;min-height:46px;
  border:1px solid color-mix(in oklab, var(--ed-pick, #7562F3) 38%, transparent);
  border-radius:12px;
  background:color-mix(in oklab, var(--ed-pick, #7562F3) 11%, transparent);
  color:var(--pick-ink);text-decoration:none;font-weight:500;
}
.ed-open:hover{background:color-mix(in oklab, var(--ed-pick, #7562F3) 19%, transparent)}
.ed-open:focus-visible{outline:2px solid var(--ed-pick, #7562F3);outline-offset:2px}
.ed-open svg{
  width:1.15rem;height:1.15rem;flex:none;
  fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;
}
.ed-open-t{font-size:.95rem}
/* Подпись снаружи кнопки: внутри она делает кнопку вдвое выше и
   спорит с её собственным словом. */
.ed-open-s{
  grid-area:editnote;margin:.4rem 0 0;font-size:.8rem;color:var(--ink-3);text-align:center;
}

.buy{border:1px solid var(--rule);background:var(--card);padding:1.2rem 1.25rem;margin:1.2rem 0 0}
.buy-h{margin:0 0 .7rem;font-size:1.02rem;font-weight:600;letter-spacing:-.01em}
.buy-see{margin:.5rem 0 0;font-size:.82rem;color:var(--ink-3);text-align:center}
/* Две карточки в ряд — как в макете. Третий тариф строкой под
   ними: см. Yzt_Product::plans(). */
.plan{display:grid;grid-template-columns:1fr 1fr;gap:.6rem;margin:0 0 .6rem}
@media (max-width:520px){.plan{grid-template-columns:1fr}}
.plan label{
  display:grid;grid-template-columns:1.1rem 1fr;gap:.6rem;align-items:start;
  border:1px solid var(--rule);border-radius:12px;padding:.75rem .85rem;cursor:pointer;
}
.plan label:has(input:checked){border-color:var(--brand);background:var(--brand-soft)}
.plan-h{display:flex;align-items:baseline;gap:.3rem;flex-wrap:wrap}
.plan-p{font-style:normal;font-weight:600;font-size:.96rem;white-space:nowrap}

/* Третий тариф. Строка, а не карточка, — но переключатель
   настоящий: иначе «Комплект» стало бы нельзя купить отсюда. */
.plan-more{
  display:grid;grid-template-columns:1.1rem 1fr;gap:.6rem;align-items:start;
  margin:0 0 1rem;padding:.6rem .85rem;
  border:1px dashed var(--rule);border-radius:12px;
  font-size:.86rem;color:var(--ink-2);cursor:pointer;
}
.plan-more:hover{border-color:var(--ink-3)}
.plan-more:has(input:checked){border-style:solid;border-color:var(--brand);background:var(--brand-soft)}
.plan-more input{margin:.15rem 0 0;accent-color:var(--brand);width:1rem;height:1rem}
.plan-more b{font-weight:600;color:var(--ink)}
.plan-more small{display:block;margin-top:.1rem;color:var(--ink-3);font-size:.8rem}

/* «Вот он» — мигание тарифа, к которому привела закрытая вкладка.

   Не выбор: галочку ставит человек, цену меняем не мы. Подсветка
   только показывает, куда смотреть, и гаснет сама — иначе она
   останется на тарифе и будет спорить с настоящей отметкой.

   Обводка рисуется тенью, а не border: border сдвинул бы соседей
   на точку, и весь список дёрнулся бы при каждом показе. */
.plan label.is-point{animation:plan-point 2.4s ease-out 1}
@keyframes plan-point{
  0%,100%{box-shadow:0 0 0 0 rgba(209,33,73,0)}
  12%{box-shadow:0 0 0 3px var(--brand-soft)}
  60%{box-shadow:0 0 0 3px var(--brand-soft)}
}
@media (prefers-reduced-motion:reduce){
  .plan label.is-point{animation:none;box-shadow:0 0 0 3px var(--brand-soft)}
}
.plan input{margin:.2rem 0 0;accent-color:var(--brand);width:1rem;height:1rem}
.plan b{font-weight:600;font-size:.96rem}
.plan small{display:block;color:var(--ink-2);font-size:.83rem;margin-top:.1rem}
.plan .p{font-family:var(--serif);font-size:1.25rem;font-weight:600;white-space:nowrap}
.buy .total{display:flex;justify-content:space-between;align-items:baseline;margin:0 0 .8rem;font-size:.9rem;color:var(--ink-2)}
.buy .total b{font-family:var(--serif);font-size:1.9rem;color:var(--ink);font-weight:600}
.buy .btn{width:100%}
.buy .fine{margin:.85rem 0 0;font-size:.82rem;color:var(--ink-3);display:flex;flex-direction:column;gap:.25rem}
.buy .fine b{color:var(--ink-2);font-weight:500}

/* ============================================================
   ЧТО ВЫ ПОЛУЧИТЕ
   ------------------------------------------------------------
   Три белые карточки на белом фоне читались как один
   светло-серый прямоугольник: границы в один пиксель на
   расстоянии вытянутой руки не видно. Секции — очень мягкая
   подложка, карточкам — тень; ярко-розовой заливки нет, это
   объяснение товара, а не баннер.

   Цвета — только переменными. Тем на сайте четыре («Бумага» и
   «Праздник», каждая светлая и тёмная), и любой вписанный
   сюда #fff8fa стал бы белым пятном в тёмной.
   ============================================================ */
/* ПОЧЕМУ У СНОСКИ ЗДЕСЬ СВОЙ ЦВЕТ

   Секция залита градиентом от фона страницы к мягкому бренду,
   то есть к нижнему краю она СВЕТЛЕЕ (в тёмной теме — темнее)
   обычного фона. А --ink-3 подобран замером ровно под обычный
   фон: примерно 4,7 при норме 4,5. Запаса в две десятых на
   градиент не хватает — замерено 4,15 у сноски про WhatsApp
   в тёмной «Бумаге».

   Нашла это проверка tokeny после того, как научилась видеть
   градиент: до этого она мерила такие элементы по фону body,
   то есть не по той поверхности, на которой они лежат. Секция
   с градиентом была на сайте всё это время.

   Уровень поднят на одну ступень — до --ink-2. Сноска остаётся
   тише основного текста, но перестаёт зависеть от того, в какой
   точке градиента оказалась. */
.deliv{background:linear-gradient(180deg,var(--paper) 0%,var(--brand-soft) 240%)}
.deliv .sec-note{color:var(--ink-2)}
/* Две колонки, а не три: карточки «PNG для отправки» больше нет
   (см. Yzt_Product::deliverables). Именно minmax(0,1fr), а не
   голый 1fr, — иначе колонка не сжимается ниже своего
   содержимого и на узком экране вылезает за край. */
.dlv{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1.25rem}
.dlv-c{
  display:flex;flex-direction:column;
  border:1px solid var(--rule);border-radius:20px;background:var(--card);
  box-shadow:var(--shadow-s);padding:1.35rem;
  transition:transform .18s, box-shadow .18s;
}
/* Текст карточки — одним блоком.
   Без обёртки на телефоне, где карточка становится строкой,
   каждый абзац превращался в отдельную колонку флексбокса:
   теги «300 dpi» уезжали вправо и растягивали страницу
   до 519 точек при экране в 390. */
.dlv-b{display:flex;flex-direction:column;min-width:0;flex:1}
@media (hover:hover){
  .dlv-c:hover{transform:translateY(-2px);box-shadow:var(--shadow-m)}
}
@media (prefers-reduced-motion: reduce){
  .dlv-c{transition:none}
  .dlv-c:hover{transform:none}
}

/* Рисунок результата: одно приглашение в трёх положениях */
.dlv-art{display:grid;place-items:center;margin:0 0 .9rem;min-height:5.6rem}
.dlv-svg{width:7.5rem;height:5rem;overflow:visible}
.dlv-svg .dp{fill:var(--paper);stroke:var(--rule-2);stroke-width:1.6}
.dlv-svg .da{fill:var(--brand-soft);stroke:var(--brand);stroke-width:1.2;opacity:.9}
.dlv-svg .dl{stroke:var(--rule-2);stroke-width:1.6;stroke-linecap:round;fill:none}
.dlv-svg .dt{fill:var(--brand);stroke:none}
.dlv-svg .dk{stroke:var(--paper);stroke-width:1.8;fill:none;stroke-linecap:round;stroke-linejoin:round}

/* Плашка «входит»: галочка формой, а не только цветом —
   дальтонику зелёный от серого не отличить. */
.dlv-in{
  display:inline-flex;align-items:center;gap:.35rem;align-self:start;
  margin:0 0 .55rem;padding:.24rem .6rem .24rem .45rem;border-radius:100px;
  background:var(--good-soft);color:var(--good-ink);
  font-size:.76rem;font-weight:600;letter-spacing:.01em;
}
.dlv-tick{width:.95rem;height:.95rem;fill:none;stroke:currentColor;stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round}
.dlv-badge{
  align-self:start;margin:0 0 .55rem;padding:.24rem .6rem;border-radius:100px;
  background:var(--brand);color:var(--paper);
  font-size:.72rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;
}
.dlv-c h3{margin:0 0 .35rem;font-size:1.05rem;font-weight:600}
.dlv-d{margin:0;font-size:.9rem;color:var(--ink-2)}

/* Характеристики — тегами. Абзац «А5 148 × 210 мм, 300 dpi,
   вылеты 3 мм» читали дольше, чем сам заголовок карточки. */
.dlv-tags{display:flex;flex-wrap:wrap;gap:.35rem;margin:.7rem 0 0;padding:0;list-style:none}
.dlv-tags li{
  border:1px solid var(--rule-2);border-radius:100px;padding:.16rem .55rem;
  font-size:.78rem;color:var(--ink-2);white-space:nowrap;
}
.dlv-list{margin:.7rem 0 0;padding:0 0 0 1.05rem;font-size:.88rem;color:var(--ink-2)}
.dlv-list li{margin:.18rem 0}
.dlv-more{margin:.8rem 0 0;font-size:.85rem}
/* Раскрывашка прижата к низу карточки: в ряду карточки одной
   высоты, и ссылка, висящая посреди пустоты, читается как
   недоделанная вёрстка. */
@media (min-width:721px){.dlv-more{margin-top:auto;padding-top:.8rem}}
.dlv-more summary{cursor:pointer;color:var(--brand);width:fit-content}
.dlv-more p{margin:.5rem 0 0;font-size:.85rem;color:var(--ink-2)}

/* Карточка живой страницы: заметнее соседей, но не баннер */
.dlv-live{
  background:linear-gradient(145deg,var(--brand-soft) 0%,var(--card) 78%);
  border-color:color-mix(in srgb, var(--brand) 28%, transparent);
  box-shadow:0 10px 30px -18px color-mix(in srgb, var(--brand) 60%, transparent), var(--shadow-s);
}
/* Тариф включает её — карточка перестаёт себя предлагать и
   становится такой же, как соседи, только с лёгкой подсветкой. */
.dlv-live.is-in{background:var(--card)}

.dlv-act{margin-top:auto;padding-top:1rem;display:flex;flex-direction:column;gap:.55rem;align-items:start}
.dlv-act.only-ex{padding-top:.8rem}
.dlv-pay{margin:0;font-size:.95rem;color:var(--ink-2)}
.dlv-pay b{font-family:var(--serif);font-size:1.35rem;color:var(--brand);font-weight:600}
#dlvUp{width:100%;min-height:44px}
.dlv-ex{font-size:.88rem;color:var(--brand)}

/* Широкая карточка комплекта */
.dlv-w{
  display:flex;gap:1.1rem;align-items:start;flex-wrap:wrap;
  margin-top:1.25rem;padding:1.35rem;border-radius:20px;
  border:1px solid var(--rule);background:var(--card);box-shadow:var(--shadow-s);
}
.dlv-w h3{margin:0;font-size:1.05rem;font-weight:600}
.dlv-w .dlv-list{columns:2;column-gap:1.6rem}

@media (max-width:720px){
  /* Три одинаково длинные карточки в столбик — это три экрана
     подряд об одном и том же. Включённые файлы сворачиваются
     в две строки, а предложение остаётся карточкой: оно здесь
     единственное, ради чего блок вообще перестроен. */
  .dlv{grid-template-columns:1fr;gap:.6rem}
  .dlv-c{flex-direction:row;gap:.85rem;align-items:start;padding:.85rem .95rem;border-radius:16px}
  /* Название тарифа в плашке на телефоне лишнее: оно только что
     прочитано в заголовке блока «Что вы получите за 149 ₽».
     Остаётся «✓ Входит» — короткая строка вместо длинной. */
  .dlv-inX{display:none}
  .dlv-c .dlv-art{margin:0;min-height:0;flex:none;width:3.2rem}
  .dlv-svg{width:3.2rem;height:2.4rem}
  .dlv-c h3{font-size:.97rem}
  .dlv-c .dlv-in{margin-bottom:.3rem;padding:.16rem .5rem .16rem .38rem;font-size:.72rem}
  .dlv-tags{gap:.3rem;margin-top:.45rem}
  .dlv-tags li{font-size:.74rem}
  .dlv-live{flex-direction:column;padding:1.15rem;border-radius:20px;margin-top:.5rem}
  .dlv-live .dlv-art{width:auto;margin:0 0 .7rem}
  .dlv-live .dlv-svg{width:5.5rem;height:3.6rem}
  .dlv-live .dlv-inX{display:inline}
  .dlv-act{width:100%}
  .dlv-act .btn{width:100%}
  .dlv-w{margin-top:.6rem;padding:1.15rem}
  .dlv-w .dlv-list{columns:1}
}

/* ---------- как это выглядит напечатанным ---------- */
/* ============================================================
   КАК ВЫГЛЯДИТ НА БУМАГЕ — СТОПКА, КОТОРУЮ МОЖНО РАЗЛОЖИТЬ

   Блок отвечает на невысказанный вопрос «а что я получу-то»,
   и ответ у него вещественный: две отпечатанные карточки лежат
   стопкой, одна поверх другой. До сих пор они просто лежали.

   Наведение раскладывает стопку: задняя выезжает из-под
   передней и проясняется, передняя приподнимается, тени под
   обеими становятся глубже. Смысл жеста ровно тот же, что и у
   блока — это не картинки, это предметы, их можно взять в руки
   и разложить на столе.

   Наведение на отдельную карточку вытаскивает наверх ЕЁ:
   задняя выходит вперёд, выпрямляется и становится полностью
   видимой. Отсюда и «интересно посмотреть» — стопку можно
   перебрать, а не только увидеть.

   ПОЧЕМУ НЕ БЛИК

   Первым просилась глянцевая полоса, скользящая по карточке.
   Она бы врала: в заголовке блока написано «матовый картон
   300 г/м²», а блик — свойство глянца. Матовая бумага
   отличается как раз тем, что не бликует, а держит глубокую
   мягкую тень; тень и усиливаем.
   ============================================================ */
.mock{background:var(--paper-2);border:1px solid var(--rule);padding:2.9rem 1.5rem;display:grid;place-items:center;overflow:hidden}
.mock-stack{position:relative;width:15rem;perspective:1400px}
.mock-stack .yz-inv-wrap{box-shadow:var(--shadow-l);transition:box-shadow .45s ease}
.mock-back,.mock-front{
  /* Один переход на оба: разъехавшись, они разъедутся навсегда,
     потому что править их будут по очереди и в разные дни. */
  transition:transform .45s cubic-bezier(.2,.7,.3,1),opacity .45s ease,filter .45s ease;
}
.mock-back{position:absolute;inset:0;transform:rotate(-7deg) translate(-1.6rem,.6rem);opacity:.55;filter:saturate(.85)}
.mock-front{position:relative;transform:rotate(3deg)}

/* стопка раскладывается целиком */
.mock-stack:hover .mock-back{transform:rotate(-15deg) translate(-3.9rem,1.2rem) rotateX(4deg) scale(1.04);opacity:.88;filter:saturate(.97)}
.mock-stack:hover .mock-front{transform:rotate(7deg) translate(.8rem,-.7rem) rotateX(5deg) scale(1.07)}
.mock-stack:hover .yz-inv-wrap{box-shadow:0 1.1rem 2.2rem rgba(24,20,32,.16)}

/* ЗАЧЕМ ЖЕСТ ОДИН, А НЕ ДВА

   Здесь было и второе наведение: на заднюю карточку, чтобы она
   выходила вперёд. Замысел хороший, исполнение никакое — задняя
   лежит ровно под передней, и на виду у неё полоска шириной
   в палец. Прицелиться в неё можно только нарочно, а промах
   выглядит так, будто эффект через раз не срабатывает.

   Лучше один жест, который срабатывает всегда: наводишь на
   блок — стопка раскладывается. Мишень во весь блок, промаха
   нет. */

@media (prefers-reduced-motion:reduce){
  .mock-back,.mock-front,.mock-stack .yz-inv-wrap{transition:none}
}

/* На узком экране стопка и так занимает почти всю ширину:
   разложить её некуда, а .mock обрезает всё, что вылезло. */
@media (max-width:560px){
  .mock-stack:hover .mock-back,.mock-back:hover{transform:rotate(-7deg) translate(-1.6rem,.6rem);opacity:.55;filter:saturate(.85)}
  .mock-stack:hover .mock-front,.mock-front:hover,.mock-back:hover ~ .mock-front{transform:rotate(3deg);opacity:1;filter:none}
}

/* ---------- отзывы ---------- */
.revs{display:grid;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));gap:1.2rem}
.rev{border:1px solid var(--rule);background:var(--card);padding:1.05rem 1.15rem;display:flex;flex-direction:column;gap:.45rem}
.rev p{margin:0;font-size:.92rem}
.rev .by{font-size:.82rem;color:var(--ink-3)}
.rev .stars{color:var(--amber);font-size:.85rem;letter-spacing:.12em}

/* ---------- похожие ---------- */
.similar{display:grid;grid-template-columns:repeat(auto-fill,minmax(10rem,1fr));gap:1.3rem 1.1rem}
.similar a{text-decoration:none;display:flex;flex-direction:column;gap:.45rem}
.similar .yz-inv{border:1px solid var(--rule);box-shadow:var(--shadow-s)}
.similar a:hover .yz-inv{box-shadow:var(--shadow-m)}
.similar .nm{font-size:.89rem}
.similar .pr{font-size:.84rem;color:var(--ink-2)}

/* ---------- липкая покупка на телефоне ----------
   На широком экране её нет вовсе: блок покупки стоит в правой
   колонке и с неё не уходит. Правила показа — в @media ниже. */
.buybar{display:none}
.buy-act{display:block}
/* ---------- закрытые вкладки ----------------------------------------
   Две подписи, и у каждой своя работа.

   Метка «Праздник» на самой вкладке видна всегда и на телефоне —
   там всплывающих подсказок не бывает вовсе. Она отвечает на
   вопрос «почему бледная» до того, как он возник.

   Подсказка появляется при наведении и остановке табом и говорит
   подробность: на каких именно тарифах. Раньше это был системный
   title — мелкий, серый, без рамки и без связи с сайтом; на
   малиновом сайте он читался как сообщение браузера об ошибке.
   ------------------------------------------------------------------ */
.tabs button[data-locked="1"],
.pv-switch button[data-locked="1"]{position:relative;cursor:not-allowed}

.tabs button[data-locked="1"]::after{
  content:"Праздник";
  margin-left:.4rem;padding:.05rem .38rem;border-radius:100px;
  background:var(--amber-soft);color:var(--amber);
  font-size:.66rem;font-weight:600;letter-spacing:.02em;vertical-align:.08em;
}

/* Сама подсказка. Текст берётся из data-note: одна строка в
   разметке вместо второй копии в стилях. */
.yz-note{
  /* ПОДСКАЗКА НЕ ВЫЛЕЗАЕТ ЗА КРАЙ ЭКРАНА

     Она шириной 17rem и центрируется по кнопке. Кнопка «Ссылка
     в чате» — третья из трёх, то есть у правого края; на
     телефоне подсказка высовывалась за экран на полсотни точек
     и давала всей странице горизонтальную прокрутку. Прятать
     её не надо было даже наводить: visibility:hidden занимает
     место в раскладке, и страница ехала вбок всегда.

     Ровно та же поломка уже случалась в этом блоке с самими
     кнопками — см. комментарий у .pv-switch выше. Тогда лечили
     переносом строк; здесь переносить нечего, надо сдвигать.

     --nudge считает скрипт: он один знает, где кнопка оказалась
     после переноса строк. Уголок сдвигается на столько же в
     обратную сторону и остаётся под кнопкой. */
  /* СПРЯТАННАЯ ПОДСКАЗКА НЕ ЗАНИМАЕТ НИ ТОЧКИ

     Здесь стояло visibility:hidden, и коробка оставалась в
     раскладке: абсолютно позиционированный узел не двигает
     соседей, но в прокручиваемую ширину страницы входит. То
     есть страница ехала вбок из-за подсказки, которую никто
     не открывал.

     Сдвиг --nudge это лечил, пока считался верно, — и перестал:
     на телефоне ширина окна, по которой он считается, сама
     растёт вслед за переехавшей страницей. Клин заклинивает
     сам себя, и починить его арифметикой нельзя.

     display:none разрывает круг: пока подсказку не открыли, её
     нет вовсе, и мерить нечего. А в момент открытия ширина окна
     уже настоящая, и сдвиг встаёт правильно с первого раза. */
  display:none;
  position:absolute;left:50%;top:calc(100% + .55rem);
  transform:translateX(calc(-50% + var(--nudge,0px)));
  z-index:20;width:max-content;max-width:min(17rem, calc(100vw - 1.5rem));
  background:var(--card);color:var(--ink);
  border:1px solid var(--brand);border-radius:4px;
  padding:.5rem .7rem;
  font-size:.85rem;line-height:1.35;font-weight:400;text-align:left;white-space:normal;
  box-shadow:0 10px 26px -14px rgba(0,0,0,.45);
  pointer-events:none;
}
/* Уголок к вкладке — два ромба друг на друге: нижний рисует
   рамку, верхний закрывает её изнутри цветом карточки. */
.yz-note::before,
.yz-note::after{
  content:"";position:absolute;left:calc(50% - var(--nudge,0px));width:.5rem;height:.5rem;
  transform:translateX(-50%) rotate(45deg);
}
.yz-note::before{top:-.29rem;background:var(--brand)}
.yz-note::after{top:-.22rem;background:var(--card)}

[data-note]:hover > .yz-note,
[data-note]:focus-visible > .yz-note,
[data-note].is-note > .yz-note{
  display:block;animation:note-in .16s ease both;
}
@keyframes note-in{
  from{opacity:0;transform:translate(calc(-50% + var(--nudge,0px)),-4px)}
  to  {opacity:1;transform:translateX(calc(-50% + var(--nudge,0px)))}
}
/* Отдельное правило, а не animation:none: без ключевых кадров
   подсказка осталась бы с opacity из последнего кадра, то есть
   видимой всегда. Гасим только движение. */
@media (prefers-reduced-motion:reduce){.yz-note{animation-duration:.01ms!important}}

/* Счётчик знаков переехал в base.css: поля с ограничением есть
   не только здесь, но и в форме связи, и в окне правки текста
   в корзине, а product.css грузится только на карточке. */
.fld input[aria-invalid="true"]{border-color:var(--brick)}

/* Кнопка выборщика даты — такое же поле, и помечается так же.

   Без этого правила выходило вот что: человек жмёт «В корзину»
   без даты, страница прокручивается к выборщику — и там ничего
   не происходит. Сообщение осталось внизу, у кнопки, на телефоне
   за пределами экрана. Прокрутка без метки читается как сбой:
   «нажал купить, меня куда-то увезло».

   Метку снимает первый выбор даты — там же, где прячется
   сообщение. */
.dp-btn[aria-invalid="true"],.tp-btn[aria-invalid="true"]{border-color:var(--brick)}
.dp-btn[aria-invalid="true"] .dp-val{color:var(--brick)}

/* ---------- необязательные поля ---------- */
.fld-more{margin:.2rem 0 0}
.fld-more summary{
  cursor:pointer;font-size:.88rem;color:var(--ink-2);
  padding:.5rem 0;list-style-position:inside;
}
.fld-more summary::marker{color:var(--ink-3)}
.fm-hint{margin-left:.5rem;font-size:.78rem;color:var(--ink-3)}
.fld-more[open] summary{color:var(--ink)}
.sug-lbl{font-size:.82rem;color:var(--ink-3);align-self:center}

/* Подсказки текста стоят ДО полей, поэтому отступ снизу,
   а не сверху. */
.suggest{margin:.2rem 0 1rem}

/* ЗДЕСЬ СТОЯЛО display:contents

   Оно было нужно, пока .buy-act превращалась в нижнюю панель:
   в потоке коробка не мешала, а на телефоне становилась
   flex-полосой. Панель теперь отдельная, и обёртка снова
   обычная — иначе «Посмотрите результат до оплаты» и кнопка
   разъезжаются по разным строкам сетки родителя. */
.buy-act{display:block}

@media (max-width:860px){
  /* minmax(0,1fr), а не 1fr: голая доля не сжимается уже
     min-content, и колонка превью вылезала на 378 точек при
     экране в 320 — вся страница получала прокрутку вбок. */
  /* Одна колонка и порядок разметки: заголовок, приглашение,
     поля, редактор, покупка. Именно этот порядок и записан в
     разметке — здесь мы только отказываемся от второй колонки. */
  .prod-page{
    grid-template-columns:minmax(0,1fr);
    grid-template-areas:"again" "head" "pv" "form" "edit" "editnote" "buy";
    gap:0;
  }
  .prod-page > .pv-col{margin-block:1.2rem}
  .pv-col{position:static}
  .row{grid-template-columns:1fr}

  /* ---------- компактный выбор тарифа ----------
     Три карточки с описаниями занимают пол-экрана до кнопки.
     На узком экране оставляем название и цену в одну строку;
     что входит в тариф, написано ниже в «Что придёт после
     оплаты» — и меняется вместе с выбором. */
  .plan{gap:.4rem}
  .plan label{padding:.6rem .7rem;align-items:center}
  .plan small{display:none}
  .plan b{font-size:.92rem}
  .plan .p{font-size:1.05rem}

  /* ============================================================
     ЗАКРЕПЛЁННАЯ ПОКУПКА
     ------------------------------------------------------------
     ЗДЕСЬ САМА КНОПКА СТАНОВИЛАСЬ ПАНЕЛЬЮ, И ЭТО БЫЛО РАНО

     Правило висело на .buy-act: единственная кнопка покупки
     уезжала в фиксированную полосу внизу с первой же секунды.
     Человек, только открывший дизайн, ещё ничего не вписал и
     даже не долистал до формы — а внизу его уже ждёт «В
     корзину». Панель для того и нужна, чтобы вернуть кнопку,
     когда она ушла вверх; появляться раньше кнопки значит
     торопить.

     Теперь панель отдельная, лежит в потоке скрытой и
     показывается, когда настоящий блок покупки ушёл ЗА ВЕРХНИЙ
     край. Направление важно: «кнопки не видно» верно и до того,
     как человек до неё долистал.

     Двух активных кнопок в одной видимой области при этом не
     бывает: наблюдатель показывает панель ровно тогда, когда
     настоящей на экране нет.
     ============================================================ */
  .buybar{
    display:flex;position:fixed;left:0;right:0;bottom:0;z-index:50;
    gap:.8rem;align-items:center;
    padding:.6rem .9rem calc(.6rem + env(safe-area-inset-bottom,0px));
    background:var(--paper);border-top:1px solid var(--rule);
    box-shadow:0 -6px 20px -12px rgba(0,0,0,.4);
    transform:translateY(110%);transition:transform .2s ease,padding .18s ease;
  }
  .buybar[data-on]{transform:none}
  .buybar-t{display:flex;flex-direction:column;gap:0;min-width:0}
  .buybar-t span{font-size:.74rem;color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .buybar-t b{font-family:var(--serif);font-size:1.3rem;font-weight:600;white-space:nowrap}
  .buybar .btn{flex:1;min-height:48px}

  /* Место под панель — только там, где панель есть.
     Раньше отступ стоял на body всегда, и на каждой карточке
     внизу висела полоса пустоты под кнопку, которой не было. */
  body.single-yz_template{padding-bottom:5rem}

  /* ---------- панель во время ввода ----------
     Клавиатура выезжает туда же, где стоит панель, и вместе они
     съедают половину экрана — включая поле, которое человек
     в эту секунду заполняет.

     Панель поэтому ужимается, а не прячется. Спрятать её проще,
     но тогда кнопка «В корзину» исчезает ровно в тот момент,
     когда человек дописал последнее слово и потянулся к ней:
     чтобы купить, надо сначала догадаться закрыть клавиатуру.
     Ужатая панель занимает одну строку и остаётся нажимаемой. */
  body.kb-on .buybar{padding-top:.35rem;padding-bottom:calc(.35rem + env(safe-area-inset-bottom,0px))}
  body.kb-on .buybar-t{display:none}
  body.kb-on .buybar .btn{min-height:42px}

  /* За окном «Увеличить» панели быть не должно: человек смотрит
     на приглашение, а не покупает. */
  .pv-modal:not([hidden]) ~ * .buybar,
  body:has(.pv-modal:not([hidden])) .buybar{transform:translateY(110%)}
}

.buy-err{margin:.5rem 0 0;color:var(--brick);font-size:.85rem;line-height:1.4}

/* ============================================================
   ОКНО «УВЕЛИЧИТЬ»
   ------------------------------------------------------------
   Приглашение целиком и ничего вокруг: ни рамок правки, ни
   кнопок покупки, ни полосы тарифов. Человек нажал «Увеличить»,
   чтобы разглядеть, что купит.
   ============================================================ */
.pv-modal{position:fixed;inset:0;z-index:120;display:grid;place-items:center;padding:1.2rem}
.pv-modal[hidden]{display:none}
/* Подложка плотная, а не намёком. При полупрозрачной страница
   за окном читается насквозь: заголовок, поля, цена — и
   «чистый просмотр» получается на фоне всего, от чего он
   очищает. */
.pv-modal-bg{position:absolute;inset:0;background:rgba(20,16,34,.78)}
.pv-modal-box{
  position:relative;display:flex;flex-direction:column;gap:.7rem;
  max-width:min(92vw,34rem);max-height:92svh;
}
.pv-modal-head{display:flex;align-items:center;justify-content:space-between;gap:.8rem;color:#fff}
.pv-modal-head b{font-size:.95rem;font-weight:500}
.pv-modal-x{
  display:grid;place-items:center;width:40px;height:40px;flex:none;
  border:0;border-radius:100px;background:rgba(255,255,255,.14);color:#fff;cursor:pointer;
}
.pv-modal-x:hover{background:rgba(255,255,255,.26)}
.pv-modal-x:focus-visible{outline:2px solid #fff;outline-offset:2px}
.pv-modal-x svg{width:1.15rem;height:1.15rem;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}

/* КОНТЕЙНЕР ОБЯЗАТЕЛЕН

   Весь набор кеглей карточки стоит на font-size:5.26cqw. Сюда
   она кладётся без своей обёртки, поэтому контейнером обязан
   быть этот узел — иначе проценты считаются от вьюпорта и имя
   выходит в семьдесят точек. Ровно это уже случилось с холстом
   редактора. */
.pv-modal-card{
  container-type:inline-size;
  width:min(92vw,34rem);
  max-height:calc(92svh - 3.6rem);
  aspect-ratio:148/210;
  overflow:hidden;border-radius:4px;box-shadow:0 24px 60px -28px rgba(0,0,0,.7);
}
/* Высокое окно: карточку ограничивает высота, а не ширина. */
@media (max-aspect-ratio:148/260){
  .pv-modal-card{width:auto;height:calc(92svh - 3.6rem)}
}

/* ============================================================
   Расширенный режим: перемещение строк
   ------------------------------------------------------------
   Полоса стоит ПОД превью, а кнопка вторичная. Красная заливка
   на этой странице означает один следующий шаг — «В корзину».
   Вторая красная кнопка означала бы два первых шага, и человек,
   пришедший купить готовое, вставал бы перед выбором, которого
   у него не было.
   ============================================================ */
.rz-bar{
  display:flex;flex-wrap:wrap;align-items:center;gap:.55rem;
  margin:.7rem 0 0;
}
.rz-open{gap:.45rem;padding-inline:.85rem}
.rz-open svg{width:1.05rem;height:1.05rem;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round}
.rz-open[disabled]{opacity:.5}
/* Подпись занимает свою строку целиком: две кнопки рядом, текст
   под ними. Без этого он втискивается справа от первой кнопки и
   выталкивает вторую на следующую строку — получаются три
   этажа там, где хватает двух. */
.rz-hint{flex:1 0 100%;font-size:.82rem;color:var(--ink-3)}
.rz-open[aria-expanded="true"] ~ .rz-hint{display:none}

/* Ссылка в полный редактор. Тот же вид, что у соседней кнопки:
   это две двери в одно и то же, разной ширины, и разный вид
   намекал бы, что одна из них важнее. Пока полоса раскрыта,
   ссылка уходит: там уже правят, и предлагать уйти на другой
   адрес посреди правки значит предложить потерять её. */
.rz-full{gap:.45rem;padding-inline:.85rem;text-decoration:none}
.rz-full svg{width:1.05rem;height:1.05rem;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linejoin:round}
.rz-open[aria-expanded="true"] ~ .rz-full{display:none}

.rz-tools{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem;width:100%}
.rz-t{
  display:grid;place-items:center;min-width:44px;min-height:44px;
  padding:0 .7rem;border:1px solid var(--rule-2);border-radius:100px;
  background:var(--card);color:var(--ink-2);font:inherit;font-size:.86rem;cursor:pointer;
}
.rz-t:hover:not([disabled]){border-color:var(--ink-3);color:var(--ink)}
.rz-t:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
/* Недоступное — выключено по-настоящему, а не бледное: бледная
   кнопка, которая не отвечает, читается как поломка. */
.rz-t[disabled]{opacity:.4;cursor:default}
.rz-t svg{width:1.1rem;height:1.1rem;fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.rz-wide{margin-left:auto}
.rz-done{min-height:44px}
.rz-say{margin:.35rem 0 0;width:100%;font-size:.82rem;color:var(--ink-3);line-height:1.4}

/* ---------- сама карточка в режиме правки ---------- */
.yz-inv[data-rz]{cursor:default}
/* Область захвата у строки должна быть пальцем, а не буквой:
   у «5 лет» высота строки меньше сорока четырёх точек. */
.yz-inv[data-rz] [data-layer]{
  cursor:grab;
  outline:1px dashed color-mix(in oklab, var(--c-ink) 26%, transparent);
  outline-offset:.25em;
}
.yz-inv[data-rz][data-rz-drag] [data-layer]{cursor:grabbing}
/* Пока тащим — браузер не должен принимать это за прокрутку
   или за выделение текста. */
.yz-inv[data-rz] [data-layer]{touch-action:none;user-select:none;-webkit-user-select:none}

/* ---------- слой поверх: рамка и направляющие ----------
   Вне <article>: всё, что внутри карточки, уезжает в печать и
   в снимок, а рамка выделения в PDF — это брак. */
.rz-over{position:absolute;inset:0;pointer-events:none;z-index:3}
.yz-inv-wrap{position:relative}
.rz-box{
  position:absolute;border:1.5px solid var(--brand);border-radius:3px;
  box-shadow:0 0 0 3px color-mix(in oklab, var(--brand) 14%, transparent);
}
/* ---------- безопасное поле ----------
   Пунктир, а не сплошная линия: сплошная читается как рамка
   дизайна, то есть как часть приглашения. Пунктир — служебная
   разметка, и глаз это знает по любому чертёжному листу.

   Лежит в том же слое, что и рамка выделения, и потому в печать
   не попадает: всё, что внутри <article>, уезжает в PDF, а этот
   слой снаружи. */
.rz-safe{
  position:absolute;pointer-events:none;
  border:1px dashed color-mix(in oklab, var(--brand) 55%, transparent);
  border-radius:2px;
}
.rz-ax{position:absolute;left:0;right:0;height:1px;background:var(--brand);opacity:.55}
.rz-ax--v{left:auto;right:auto;top:0;bottom:0;width:1px;height:auto}

/* ---------- маркеры размера на рамке ----------
   Слой рамки не ловит нажатий (pointer-events:none выше), иначе
   он накрыл бы всю карточку и тянуть строки стало бы нечем.
   Маркерам ловлю возвращаем поимённо.

   Сам квадратик 9 точек — столько, сколько нужно глазу, — а
   ловит он 22: невидимые поля вокруг. Маркер, в который надо
   попасть точно, на практике означает «размер мышью не
   меняется». */
.rz-grip{
  position:absolute;width:9px;height:9px;padding:0;
  border:1.5px solid var(--brand);border-radius:2px;background:var(--paper);
  box-shadow:0 1px 2px rgba(0,0,0,.18);
  pointer-events:auto;cursor:nwse-resize;touch-action:none;
}
.rz-grip::after{content:"";position:absolute;inset:-7px}
.rz-grip--nw{left:-5px;top:-5px}
.rz-grip--se{right:-5px;bottom:-5px}
.rz-grip--ne{right:-5px;top:-5px;cursor:nesw-resize}
.rz-grip--sw{left:-5px;bottom:-5px;cursor:nesw-resize}

/* ---------- боковые маркеры: ширина блока ----------
   Стоят по середине боков и тянутся только вбок — курсор об
   этом и говорит. Меняют они не кегль, а колонку, в которой
   переносится текст: углы делают буквы крупнее, бока —
   строку уже. Разные курсоры здесь не украшение: два маркера
   в пяти точках друг от друга, делающие разное, обязаны
   отличаться до нажатия. */
.rz-grip--w{left:-5px;top:50%;margin-top:-4.5px;cursor:ew-resize}
.rz-grip--e{right:-5px;top:50%;margin-top:-4.5px;cursor:ew-resize}
.rz-grip:hover,.rz-grip:focus-visible{background:var(--brand);border-color:var(--brand)}

/* ---------- маркер поворота ----------
   Над рамкой, на ножке — как в макете владельца. Не сбоку и не
   внутри: внутри он спорил бы с переносом строки, а сбоку его
   путали бы с маркером размера. Круглый, а не квадратный, по
   той же причине — форма говорит, что действие другое.

   Ножка рисуется псевдоэлементом и нажатий не ловит: попасть
   пальцем в линию в один пиксель нельзя, а ловить ею — значит
   ловить и пустоту вокруг. */
.rz-turn{
  position:absolute;left:50%;top:-28px;width:13px;height:13px;margin-left:-6.5px;padding:0;
  border:1.5px solid var(--brand);border-radius:50%;background:var(--paper);
  box-shadow:0 1px 2px rgba(0,0,0,.18);
  pointer-events:auto;cursor:grab;touch-action:none;
}
.rz-turn::before{
  content:"";position:absolute;left:50%;top:100%;width:1.5px;height:15px;margin-left:-.75px;
  background:var(--brand);opacity:.7;
}
.rz-turn::after{content:"";position:absolute;inset:-7px;border-radius:50%}
.rz-turn:hover,.rz-turn:focus-visible{background:var(--brand);border-color:var(--brand)}

/* Пока тянут — курсор не должен превращаться в «перенос» от
   проезда над строкой. У трёх тяг три курсора: иначе поворот
   выглядел бы как изменение размера, и человек ждал бы от него
   не того. */
[data-rz-size="ugol"] *{cursor:nwse-resize !important}
[data-rz-size="shirina"] *{cursor:ew-resize !important}
[data-rz-size="povorot"] *{cursor:grabbing !important}

/* На узком экране маркеров нет вовсе.

   Не «спрятаны», а не нарисованы: карточка там занимает половину
   экрана, девять точек пальцем не поймать, и промах по маркеру
   означал бы перенос строки вместо размера. Размер там меняют
   числом в панели и щипком двумя пальцами. */
@media (max-width:899px){
  .rz-grip,.rz-turn{display:none}
}

@media (prefers-reduced-motion:reduce){
  .rz-t{transition:none}
}

/* ---------- панель фотографии ---------- */
.rz-photo{
  width:100%;margin-top:.5rem;padding:.7rem .8rem;
  border:1px solid var(--rule-2);border-radius:14px;background:var(--card);
  display:flex;flex-direction:column;gap:.5rem;
}
.rz-ph-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
.rz-ph-head b{font-size:.9rem}
.rz-x{
  display:grid;place-items:center;width:44px;height:44px;flex:none;
  border:0;background:none;color:var(--ink-3);cursor:pointer;border-radius:50%;
}
.rz-x:hover{background:var(--paper-2);color:var(--ink)}
.rz-x:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.rz-x svg{width:1.05rem;height:1.05rem;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}
.rz-ph-row{display:flex;align-items:center;gap:.7rem;font-size:.86rem;color:var(--ink-2)}
.rz-ph-row > span:first-child{flex:0 0 5.5rem}
.rz-ph-row input[type=range]{flex:1;min-height:44px;accent-color:var(--brand)}
.rz-masks{display:flex;flex-wrap:wrap;gap:.35rem}
.rz-masks button{
  min-height:36px;padding:.2rem .6rem;border:1px solid var(--rule-2);border-radius:100px;
  background:none;font:inherit;font-size:.82rem;color:var(--ink-2);cursor:pointer;
}
.rz-masks button[aria-pressed="true"]{border-color:var(--brand);color:var(--brand)}
.rz-masks button:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
/* Обещание рядом с загрузкой, а не в подвале политики: человек
   отдаёт детское лицо здесь и сейчас. Текст обязан совпадать с
   тем, что делает код, — метаданные и правда снимаются. */
.rz-ph-note{margin:0;font-size:.78rem;color:var(--ink-3);line-height:1.4}

/* В режиме правки снимок берут пальцем: тянут КАДР, а не слот. */
.yz-inv[data-rz] .yz-photo{cursor:grab;touch-action:none}
.yz-inv[data-rz][data-rz-drag] .yz-photo{cursor:grabbing}
.yz-photo img{pointer-events:none}

/* ============================================================
   ХОД ЗАГРУЗКИ ФОТОГРАФИИ — ПОВЕРХ КАРТОЧКИ
   ------------------------------------------------------------
   Раньше о загрузке сообщала строка голоса под холстом: мелкая,
   внизу и там, куда человек в этот момент не смотрит. Он смотрит
   на карточку — туда, где сейчас появится фотография, — и
   владелец написал ровно это: «очень неочевидная и маленькая
   надпись внизу, сделай заметнее и выше».

   Полоса накрывает карточку целиком. Это не украшение: пока
   фотография едет, трогать карточку всё равно нечего, а
   перекрытое место — единственное, мимо которого не посмотришь.

   Строка голоса при этом остаётся: её читают вслух, и убрать её
   значило бы отобрать сообщение у тех, кто не видит полосу.
   ============================================================ */
.rz-up{
  position:absolute;inset:0;z-index:6;
  display:grid;place-items:center;
  background:color-mix(in oklab, var(--paper) 78%, transparent);
  backdrop-filter:blur(2px);
  border-radius:inherit;
}
.rz-up__box{
  /* Не уже пятнадцати рем, даже если карточка уже.
     Карточка на телефоне — 216 точек, и коробка «86 % от неё»
     ломала «Не удалось загрузить» на шесть строк по два слова.
     Выйти за край карточки ей не страшно: вокруг сцена, там
     пусто, а читать надо здесь и сейчас. */
  width:max(15rem, min(20rem, 86%));text-align:center;
  background:var(--card);border:1px solid var(--rule-2);border-radius:12px;
  padding:1rem 1.1rem;box-shadow:var(--shadow-m);
}
.rz-up__t{margin:0 0 .7rem;font-size:.95rem;font-weight:500;color:var(--ink);line-height:1.35}
.rz-up[data-beda] .rz-up__t{color:var(--ink)}
/* Дорожка видимая, а не «почти как фон»: без неё полоса хода
   выглядит как пустое место, и пока она пуста — а первые
   секунды она пуста, — человек не понимает, идёт ли что-то. */
.rz-up__bar{height:8px;border-radius:4px;background:color-mix(in oklab, var(--ink) 12%, transparent);overflow:hidden}
.rz-up__bar i{display:block;height:100%;width:0;border-radius:4px;background:var(--brand);transition:width .2s ease}
.rz-up[data-beda] .rz-up__bar{display:none}

/* Пока объём неизвестен, полоса не врёт числом, а бежит. */
.rz-up[data-gadaem] .rz-up__bar i{
  width:40% !important;animation:rz-up-beg 1.1s ease-in-out infinite;
}
@keyframes rz-up-beg{
  0%{transform:translateX(-100%)}
  100%{transform:translateX(250%)}
}
@media (prefers-reduced-motion: reduce){
  .rz-up[data-gadaem] .rz-up__bar i{animation:none;width:100% !important;opacity:.45}
}

.rz-up__b{
  margin-top:.8rem;font:inherit;font-size:.9rem;font-weight:500;cursor:pointer;
  padding:.5rem 1rem;min-height:44px;border-radius:9px;
  background:var(--brand);color:#fff;border:0;
}
.rz-up__b:hover{filter:brightness(1.06)}
.rz-up__b:focus-visible{outline:2px solid var(--brand);outline-offset:2px}


/* ============================================================
   ФОРМА ПО МАКЕТУ ВЛАДЕЛЬЦА
   ------------------------------------------------------------
   Имя и возраст в ряд, дата и время в ряд, место во всю ширину,
   под ними список готовых текстов. Подписи обычным регистром:
   капитель с разрядкой читается медленнее, а подпись поля читают
   один раз и мельком.
   ============================================================ */
.fld--wide{margin-top:.8rem}
/* Дата и время — два поля в ряд, у каждого своя подпись.
   Одна подпись «Когда» на два органа означала, что у второго
   подписи нет вовсе: экранный диктор читал «Когда», а потом
   «кнопка, время начала» без всякой связи между ними. */
/* Блок даты и времени стоит третьей ячейкой ряда «имя · возраст»
   и потому занимал половину ширины: два поля в половине ряда
   вышли вдвое уже соседей. Растягиваем на весь ряд. */
.prod-page .fld--when{display:grid;grid-column:1/-1;grid-template-columns:1fr 1fr;gap:.25rem .9rem;margin-top:.75rem}
.prod-page .fld--when .lbl{grid-row:1;grid-column:1}
.prod-page .fld--when .lbl--time{grid-column:2}
.prod-page .fld--when .when-row{grid-row:2;grid-column:1/-1;display:grid;grid-template-columns:1fr 1fr;gap:.9rem}
.prod-page .fld--when .when-row .dp,
.prod-page .fld--when .when-row .tp{flex:none;min-width:0}

/* Одно слово на экран, а не одно на всех: «слева» верно на
   широком, «в превью» — на телефоне. display:none, а не
   visibility: спрятанное так не читает и экранный диктор. */
.only-wide{display:none}
@media (min-width:860px){
  .only-wide{display:inline}
  .only-narrow{display:none}
}

/* ============================================================
   ТРИ СТРОКИ «ЧТО ВЫ ПОЛУЧИТЕ»
   ------------------------------------------------------------
   Не про форматы файлов и не про тарифы: про то, что человек
   будет с этим делать. Поэтому они стоят до разбора с ценами,
   а не вместо него.
   ============================================================ */
.prod-zachem{padding-block:2.2rem 0}
.prod-zachem h2{margin:0 0 1.1rem;font-size:1.5rem;letter-spacing:-.02em}
.zachem{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1.4rem;
  margin:0;padding:0;list-style:none;
}
@media (max-width:760px){.zachem{grid-template-columns:1fr;gap:1rem}}
.zachem li{
  display:grid;grid-template-columns:auto 1fr;gap:.15rem .8rem;align-items:start;
}
.zachem svg{
  grid-row:1/3;width:1.7rem;height:1.7rem;
  fill:none;stroke:var(--ink-3);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;
}
.zachem b{font-size:1rem;font-weight:600}
.zachem span{color:var(--ink-2);font-size:.88rem;line-height:1.45}

/* Описание дизайна: приехало сюда из-под заголовка — см.
   Yzt_Product::opisanie(). */
.prod-about{margin:1.6rem 0 0;max-width:46rem}
.prod-about .ed-sub{margin:0;color:var(--ink-2);line-height:1.55}
.prod-about .ed-lead{margin:.4rem 0 0;color:var(--ink-3);font-size:.9rem}

/* КАЙМА, КОТОРУЮ УНОСИТ НОЖ

   Не линия, а полоса: по высоте линия реза прошла бы в девяти
   десятых миллиметра от безопасного поля — на экране три точки,
   и две линии так близко читаются как одна дрожащая.

   Полос четыре, и место каждой ставит скрипт долями от
   карточки: border округлился бы до целых точек и соврал бы на
   четверть миллиметра. */
.rz-rez{
  position:absolute;pointer-events:none;
  background:color-mix(in oklab, var(--brick) 14%, transparent);
}

/* Пристёгнутая строка: та же рамка, но тоньше и без маркеров.
   Тянут и правят выбранную, эти только равняются по ней —
   отличие в толщине, а не в цвете: два цвета рамок пришлось бы
   объяснять словами. */
.rz-box--2{
  border-width:1px;
  border-style:dashed;
  opacity:.75;
}
