/* Selfi — оформление веб-версии.
 *
 * Собрано по атласу экранов от 10 августа. Все значения — оттуда:
 * палитра, ширина колонок (232 и 268), радиусы, шаг отступов.
 *
 * ПОЧЕМУ НЕЙТРАЛИ ТЁПЛЫЕ. Серый уведён к янтарю намеренно: рядом
 * с фотографией кожи холодный серый выглядит как брак печати.
 *
 * ЛИМОННЫЙ — ровно два случая: баланс и главное действие экрана.
 * Больше нигде. Если подсветить всё, не подсвечено ничего.
 *
 * ПРИЛОЖЕНИЕ ВСЕГДА ТЁМНОЕ. Это не «тёмная тема», а единственная:
 * фотографию нельзя показывать на светлом — глаз теряет её тон.
 */

:root {
  --bg: #0d0c0a;
  --rail: #131210;
  --panel: #1a1815;
  --line: #2a2721;
  --line-2: #3a362e;

  --text: #f3f0e8;
  --text-2: #a8a190;
  --text-3: #6e6959;

  --lemon: #e8b923;
  --lemon-deep: #9c7208;

  /* ГРАДИЕНТ ГЛАВНОГО ДЕЙСТВИЯ.
     Плоская лимонная заливка на тёмном фоне выглядит наклейкой:
     цвет есть, объёма нет. Градиент от насыщенного янтаря к светлому
     лимону под тем же углом, под каким падает свет в интерфейсе
     (сверху слева), даёт кнопке форму — и ровно то ощущение
     дорогого, ради которого всё и затевалось.

     ПОЧЕМУ 122°, А НЕ СВЕРХУ ВНИЗ. Вертикальный градиент читается как
     объёмная кнопка из двухтысячных. Наклонный — как свет, скользнувший
     по поверхности.

     Правило «лимонный ровно в двух случаях» градиент не отменяет:
     он живёт там же, где жила заливка, — на главном действии экрана.
     Баланс остаётся плоским: это число, а не кнопка-обещание. */
  --lemon-grad: linear-gradient(122deg, #d9a316 0%, #eec434 48%, #f7dc63 100%);
  --lemon-grad-hot: linear-gradient(122deg, #e5ad18 0%, #f4cd3d 48%, #ffe578 100%);

  /* Тёплое свечение под ключевыми панелями. Ровная плашка на тёмном
     фоне читается как пустое место; едва заметный лимонный подсвет
     сверху делает её поверхностью, на которую падает свет. */
  --lemon-glow: radial-gradient(
    120% 100% at 50% 0%,
    rgba(232, 185, 35, 0.085),
    rgba(232, 185, 35, 0) 62%
  );
  --good: #59a883;
  --danger: #d2685a;

  /* РАДИУСЫ. Их было пять — 6, 10, 12, 16 и круг, — и разница между
     шестью и десятью на глаз не видна вовсе: она видна только в коде,
     где заставляет каждый раз выбирать. Осталось три ступени
     с настоящей разницей: мелкое, обычное, карточки. */
  --r-sm: 8px;
  --r: 12px;
  --r-md: 14px;
  --r-lg: 20px;

  --rail-w: 232px;
  --panel-w: 268px;
  /* Высота полосы разделов на телефоне. Нужна и шторке съёмки,
     и отступам страницы: два места, считавшие её по-своему,
     расходились на пиксель-другой и оставляли щель. */
  --tabbar-h: 63px;

  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    "Segoe UI", system-ui, "Helvetica Neue", Arial, sans-serif;
  /* Второй голос — моноширинный: номера кадров, планы съёмки,
     технические подписи. Он честно отделяет данные от речи. */
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  /* ФОН СТРАНИЦЫ — НЕ ПЛОСКИЙ ЧЁРНЫЙ.
     Едва различимый тёплый подсвет сверху: ровно столько, чтобы
     страница читалась как поверхность, на которую падает свет,
     а не как выключенный экран. Фотографии от этого не страдают —
     они лежат на своих подложках. */
  /* БЕЗ background-attachment: fixed.
     Он держал подсвет на месте при прокрутке — и на iPhone это стоило
     дороже всего: Safari перерисовывает такой фон каждый кадр, и лента
     начинала трястись, будто слои наехали друг на друга. Владелец
     поймал это на 12 Pro. Подсвет остаётся, он просто едет вместе
     со страницей — на первом экране, где его и видно, разницы нет. */
  background:
    radial-gradient(90% 42% at 50% 0%, rgba(232, 185, 35, 0.045), rgba(232, 185, 35, 0) 60%),
    var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

img {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

h1,
h2,
h3,
h4 {
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

.lab {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
}

.num {
  font-variant-numeric: tabular-nums;
}

.spinner {
  width: 20px;
  height: 20px;
  border: 2px solid var(--line);
  border-top-color: var(--lemon);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.loading {
  display: grid;
  place-items: center;
  padding: 120px 0;
}

/* ================================================== оболочка приложения */

.shell {
  display: grid;
  grid-template-columns: var(--rail-w) 1fr;
  min-height: 100vh;
}

/* Правая колонка не растягивается под своё содержимое. Внутри неё
   живут полосы прокрутки — лента на рабочем столе, закладки разделов
   на съёмке, — и их полная ширина не должна раздвигать окно. */
.shell > div {
  min-width: 0;
}

/* Кнопка колонки и затемнение под ней существуют только на телефоне.
   Правило стоит ЗДЕСЬ, а не в конце листа: правило, объявленное после
   медиазапроса, перебивает его при равной силе — на этом уже
   спотыкалась верхняя полоса, и её пришлось спасать !important. */
.rail-open,
.rail-veil {
  display: none;
}

.rail {
  /* КОЛОНКА НЕ СПЛОШНАЯ ЧЁРНАЯ.
     Ровная заливка рядом с чёрным холстом не читается как отдельная
     поверхность — граница держится на одной линии в пиксель. Тёплый
     отсвет сверху и почти незаметное тёмное дно дают ей объём
     и отделяют от страницы без единой лишней рамки.

     Свет падает оттуда же, откуда во всём интерфейсе: сверху слева.
     См. --lemon-grad у кнопок и --lemon-glow под панелями. */
  background:
    radial-gradient(120% 55% at 0% 0%, rgba(232, 185, 35, 0.06), rgba(232, 185, 35, 0) 62%),
    linear-gradient(180deg, #171512 0%, var(--rail) 42%, #0f0e0c 100%);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  padding: 16px 12px;
  gap: 16px;
  position: sticky;
  top: 0;
  height: 100vh;
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 4px 8px 0;
}

/* Тот же знак, но на него нажимают. Ни рамки, ни фона: кнопкой его
   делает поведение — курсор и лёгкий отклик, — а не оправа. */
.brand--go {
  border: 0;
  background: transparent;
  cursor: pointer;
  font: inherit;
  color: inherit;
  transition: opacity 0.15s ease;
}

.brand--go:hover {
  opacity: 0.82;
}

.brand--go:active {
  opacity: 0.65;
}

/* Марка целиком — набор, а не картинка. Шрифт системный, поэтому
   на macOS и iPhone это SF Pro: ровно та типографика, которую просили,
   и ни одного лишнего килобайта загрузки. */
.mark {
  display: inline-flex;
  /* По центру, а не по базовой линии: слева от имени стоит знак,
     и выравнивать круг по базовой линии текста не по чему. */
  align-items: center;
  gap: 0.42em;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
  white-space: nowrap;
  color: var(--text);
}

/* Само имя. Внутренняя обёртка нужна, чтобы «.ru» по-прежнему
   вставало по базовой линии рядом с «Selfiai», а не по центру
   вместе со знаком. */
.mark__word {
  display: inline-flex;
  align-items: baseline;
}

.mark__name {
  font-weight: 600;
}

/* «ai» внутри адреса — единственный цветной знак марки. Из-за него
   одна и та же строка читается двояко: и как домен selfiai.ru,
   и как имя Selfi ai. */
.mark__ai {
  font-weight: 600;
  color: var(--lemon);
}

/* Зона домена набрана тише и моноширинным: она не часть имени,
   а адрес, по которому имя живёт. */
.mark__zone {
  font-family: var(--mono);
  font-size: 0.62em;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--text-3);
  margin-left: 0.18em;
  align-self: center;
}

.mark--big {
  font-size: 22px;
}

.rail-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: var(--lemon-grad);
  color: #241b02;
  border: 0;
  border-radius: var(--r);
  padding: 10px;
  font-weight: 600;
  font-size: 13.5px;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28);
  transition: background 0.15s var(--ease);
}

.rail-btn:hover {
  background: var(--lemon-grad-hot);
}

.rail-sec {
  display: flex;
  flex-direction: column;
  gap: 1px;
  overflow-y: auto;
}

.rail-sec .lab {
  padding: 8px 8px 6px;
}

.ri {
  position: relative;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 8px;
  border-radius: 7px;
  color: var(--text-2);
  font-size: 13.5px;
  cursor: pointer;
  border: 0;
  background: transparent;
  width: 100%;
  text-align: left;
}

.ri:hover {
  color: var(--text);
}

.ri.on {
  background: var(--panel);
  color: var(--text);
}

.ri .th {
  width: 20px;
  height: 20px;
  border-radius: 4px;
  flex: none;
}

/* Миниатюра крупнее цветного квадрата, и это не украшение: в двадцати
   пикселях лицо неразличимо, а ради него всё и затевалось. Строка
   от этого выше не становится — она и так по высоте текста с полями. */
.ri .th--pic {
  width: 26px;
  height: 30px;
  border-radius: 5px;
}

.ri .gr {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--text-3);
}

/* Действия со строкой: закрепить и убрать. Занимают то же место, что
   и кружок состояния, и появляются только при наведении — колонка
   должна молчать, пока на неё не смотрят. */
.ri__acts {
  display: none;
  margin-left: auto;
  gap: 2px;
  flex: none;
}

.ri:hover .ri__acts,
.ri:focus-within .ri__acts {
  display: flex;
}

/* Пока показаны действия, кружок прячется: две вещи на одном месте
   спорят друг с другом, а состояние человек в этот момент уже видел. */
.ri:hover .dot {
  display: none;
}

.ri__act {
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 6px;
  background: none;
  cursor: pointer;
  font-size: 11px;
  line-height: 1;
  opacity: 0.45;
  filter: grayscale(1);
  transition:
    opacity 0.12s,
    filter 0.12s,
    background 0.12s;
}

.ri__act:hover {
  opacity: 1;
  filter: none;
  background: var(--line);
}

/* Закреплённая съёмка помечена и без наведения — иначе непонятно,
   почему она стоит первой. */
.ri__act.on {
  opacity: 1;
  filter: none;
}

.ri--pin .ri__name {
  color: var(--text);
}

.ri--pin::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  bottom: 8px;
  width: 2px;
  border-radius: 0 2px 2px 0;
  background: var(--lemon);
  opacity: 0.55;
}

.ri__act--off:hover {
  background: rgba(210, 104, 90, 0.18);
  color: var(--danger);
}

/* Кружок состояния съёмки. Съёмка идёт сама по себе, и человек в этот
   момент может быть в любом разделе — по списку слева должно быть
   видно, что происходит, без захода внутрь. */
.dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  margin-left: auto;
}

.dot--ok {
  background: var(--good);
}

.dot--bad {
  background: var(--danger);
}

/* Идущая съёмка — не просто цветная точка, а живое движение:
   неподвижный кружок читается как «состояние», а не как
   «прямо сейчас работает». */
.dot--go {
  background: none;
  border: 1.5px solid var(--line-2);
  border-top-color: var(--lemon);
  width: 11px;
  height: 11px;
  animation: spin 0.7s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .dot--go {
    animation-duration: 2.4s;
  }
}

/* Значок раздела — знак, а не картинка: колонка должна молчать,
   пока на неё не смотрят. */
.ri__glyph {
  width: 20px;
  text-align: center;
  font-size: 13px;
  color: var(--text-3);
  flex: none;
}

.ri.on .ri__glyph {
  color: var(--lemon);
}

/* Имя съёмки. Длинное обрезается многоточием — переносить строку
   в колонке шириной 232 px некуда. */
.ri__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.ri__edit {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--lemon);
  border-radius: 5px;
  background: var(--bg);
  color: var(--text);
  font-size: 13.5px;
  padding: 2px 6px;
  outline: none;
}

/* Список съёмок забирает остаток высоты и прокручивается сам,
   не утаскивая вниз баланс и имя. */
.rail-sec--grow {
  flex: 1;
  min-height: 0;
}

.rail-sec--grow > div:last-child {
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.ri--empty {
  color: var(--text-3);
  font-size: 12.5px;
  padding-left: 10px;
  cursor: default;
}

.rail-foot {
  margin-top: auto;
  border-top: 1px solid var(--line);
  padding-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.bal {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 10px;
  border-radius: var(--r);
  background: var(--panel);
}

.bal__go {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  padding: 0;
}

.bal__go:hover .v {
  color: var(--lemon);
}

/* ЧИСЛО НАБИРАЕТСЯ ВТОРЫМ ГОЛОСОМ. Моноширинный шрифт честно
   отделяет данные от речи: баланс, размеры кадра, даты и суммы —
   это не слова, а величины, и читаются они по-другому. Заодно цифры
   перестают прыгать при пересчёте: 9 и 11 занимают одинаковое место. */
.bal .v {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 14.5px;
  font-variant-numeric: tabular-nums;
}

.bal .p {
  margin-left: auto;
  font-size: 12px;
  color: var(--lemon);
  border: 0;
  background: transparent;
  cursor: pointer;
  padding: 0;
}

.bal .p:hover {
  text-decoration: underline;
}

.who {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px;
  color: var(--text-2);
  font-size: 13px;
  border: 0;
  background: transparent;
  cursor: pointer;
  border-radius: 7px;
  width: 100%;
  text-align: left;
}

.who:hover {
  background: var(--panel);
  color: var(--text);
}

.av {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: linear-gradient(140deg, #4b4437, #26221b);
  flex: none;
  display: grid;
  place-items: center;
  font-size: 11px;
  color: var(--text-2);
  overflow: hidden;
}

.av img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ================================================== холст */

.canvas {
  padding: 26px 30px 40px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}

/* Шапка холста: кнопка «назад», заголовок, действия справа.
   Сетка, а не выстроенный в ряд набор: на телефоне кнопка «назад»
   при переносе уезжала НАД заголовком и висела сама по себе.
   Здесь она навсегда остаётся в одной строке с текстом, а правый
   блок при нехватке места спокойно переезжает вниз. */
.canvas-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: start;
  gap: 8px 16px;
}

/* Заголовок всегда во второй колонке — независимо от того, есть
   кнопка «назад» или нет. */
.canvas-head > div:not(.rgt) {
  grid-column: 2;
}

.canvas-head > .back {
  grid-column: 1;
  grid-row: 1;
}

.canvas-head > .rgt {
  grid-column: 3;
  grid-row: 1;
}

/* ЗАГОЛОВОК ЭКРАНА НАЗЫВАЕТ ЭКРАН, а не подписывает содержимое.
   Двадцать один пиксель — это размер подзаголовка: такой заголовок
   тонет в собственной странице, и человек, попавший сюда по ссылке,
   не сразу понимает, где он. Двадцать восемь с плотным трекингом
   отвечают на вопрос «где я» до всякого чтения. */
.canvas-head h3 {
  font-size: 28px;
  letter-spacing: -0.025em;
  line-height: 1.12;
}

.canvas-head p {
  font-size: 14px;
  color: var(--text-2);
  margin-top: 5px;
  max-width: 60ch;
}

@media (max-width: 900px) {
  .canvas-head h3 {
    font-size: 23px;
  }
}

.canvas-head .rgt {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
}

@media (max-width: 640px) {
  /* На узком экране действия переезжают под заголовок — но заголовок
     при этом остаётся рядом с кнопкой «назад». */
  .canvas-head {
    grid-template-columns: auto 1fr;
  }

  .canvas-head > .rgt {
    grid-column: 2;
    grid-row: 2;
    justify-content: flex-start;
  }
}

.steps {
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}

.steps i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--line-2);
  display: inline-block;
  font-style: normal;
}

.steps i.on {
  background: var(--lemon);
}

/* Стрелка назад. Круглая, тихая, ровно того же роста, что и заголовок
   рядом: заметная, когда ищут, и не спорящая с главным действием. */
.back {
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text-2);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
  margin-top: 2px;
  transition: background 0.15s var(--ease), color 0.15s var(--ease),
    border-color 0.15s var(--ease);
}

.back:hover {
  background: var(--panel);
  border-color: var(--line-2);
  color: var(--text);
}

/* ================================================== кнопки */

.b {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 8px 15px;
  border-radius: 8px;
  font-size: 13.5px;
  font-weight: 500;
  border: 1px solid var(--line-2);
  background: transparent;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease),
    filter 0.15s var(--ease);
}

.b:hover {
  background: var(--panel);
}

.b.pri {
  background: var(--lemon-grad);
  border-color: transparent;
  color: #241b02;
  font-weight: 600;
  /* Тонкая светлая линия по верхнему краю — там, где свет и падает.
     Без неё градиент читается как заливка с браком печати. */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

.b.pri:hover {
  background: var(--lemon-grad-hot);
}

.b.big {
  padding: 12px 22px;
  font-size: 15px;
  border-radius: 9px;
}

.b.wide {
  width: 100%;
}

.b.gho {
  border-color: transparent;
  color: var(--text-2);
}

.b.gho:hover {
  color: var(--text);
  background: transparent;
}

.b[disabled] {
  opacity: 0.45;
  cursor: default;
  filter: none;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 100px;
  border: 1px solid var(--line-2);
  font-size: 11.5px;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

/* Подписи с числами — вторым голосом: «2048 × 2732», «PNG · 4,1 МБ»,
   «31 секунда». Это величины, а не речь. */
.facts .chip {
  font-family: var(--mono);
  letter-spacing: -0.01em;
}

.chip.on {
  border-color: var(--lemon);
  color: var(--lemon);
  background: rgba(232, 185, 35, 0.08);
}

/* Фильтр — это кнопка, и она обязана выглядеть частью оформления,
   а не белой кнопкой браузера по умолчанию. */
button.chip {
  background: transparent;
  cursor: pointer;
  font-family: inherit;
}

button.chip:hover {
  border-color: var(--line-2);
  color: var(--text);
}

button.chip.on:hover {
  border-color: var(--lemon);
  color: var(--lemon);
}

.chip .dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
}

/* ================================================== сцена съёмки */

.studio {
  display: grid;
  grid-template-columns: 1fr var(--panel-w);
  gap: 20px;
  align-items: start;
}

.stage {
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--line);
  position: relative;
  background: #17150f;

  /* Рамка подстраивается под сам снимок, а не наоборот. Селфи почти
     всегда вертикальное; в горизонтальной рамке оно превращается
     в узкую полоску посередине чёрного поля.

     Высота задана, ширина считается из пропорций — поэтому кнопка
     «Снять кадр» остаётся на экране вместе с холстом, а не уезжает
     вниз на широком мониторе. */
  height: min(62vh, 620px);
  aspect-ratio: var(--ar, 4 / 3);
  width: auto;
  max-width: 100%;
  margin: 0 auto;
}

.stage img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.stage .fno {
  position: absolute;
  left: 9px;
  bottom: 7px;
  z-index: 2;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  color: rgba(255, 255, 255, 0.62);
}

/* Пока идёт съёмка исходник притушен и по нему бежит блик: экран
   занят делом, а не завис. */
.stage.busy img {
  opacity: 0.32;
  filter: saturate(0.6);
}

.stage__work {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 12px;
  text-align: center;
  padding: 24px;
}

.stage__work .t {
  font-size: 15px;
  font-weight: 600;
}

.stage__work .s {
  font-size: 12.5px;
  color: var(--text-2);
  max-width: 34ch;
}

.stage.busy::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(
    100deg,
    transparent 30%,
    rgba(232, 185, 35, 0.07) 50%,
    transparent 70%
  );
  background-size: 220% 100%;
  animation: sweep 2.2s linear infinite;
}

@keyframes sweep {
  to {
    background-position: -220% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .stage.busy::after {
    animation: none;
  }
}

.drop {
  border: 1.5px dashed var(--line-2);
  border-radius: var(--r-md);
  aspect-ratio: 4 / 3;
  max-height: 62vh;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 11px;
  text-align: center;
  padding: 24px;
  background: rgba(255, 255, 255, 0.012);
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}

.drop:hover,
.drop.over,
.drop:focus-visible {
  border-color: var(--lemon);
  background: rgba(232, 185, 35, 0.04);
}

.drop:focus-visible {
  outline: 2px solid var(--lemon);
  outline-offset: 3px;
}

/* ЗОНА ЗАГРУЗКИ — ЭТО <label>, А ИНПУТ ВНУТРИ ОТРИСОВАН.

   История вопроса стоит того, чтобы её записать. Сначала инпут прятался
   через `display: none` — по такой связке Safari файловый диалог не
   открывает. Потом зона стала `<div>` с вызовом `input.click()`
   из скрипта, потом кнопкой сделали сам системный инпут — и всё это
   время дело было в подвисшем браузере заказчика, а не в разметке.

   Осталось то, что и должно было быть с самого начала: родной механизм
   без единой строки скрипта, рисованная кнопка и правило, ради которого
   всё затевалось, — инпут обязан быть на странице, а не `display: none`.

   Класс .vhide: пиксель без видимого следа, но для браузера живой. */
.vhide {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
  opacity: 0;
}

/* Кнопка внутри рамки. Не настоящая кнопка, а её вид: нажатие всё равно
   ловит <label> вокруг. Поэтому у неё нет своих состояний — она
   подсвечивается вместе со всей зоной. */
.drop__go {
  pointer-events: none;
  margin-top: 2px;
}

.drop:hover .drop__go {
  filter: brightness(1.08);
}

.drop .ic {
  font-size: 26px;
  opacity: 0.8;
}

.drop b {
  font-size: 16px;
  font-weight: 600;
}

.drop small {
  font-size: 12.5px;
  color: var(--text-3);
  max-width: 40ch;
}

/* Строка ввода под снимком — как в переписке.
   Здесь человек говорит своими словами, а готовые стили ждут справа
   для тех, кому не хочется ничего придумывать. */

.stagewrap {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

.composer {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  padding: 10px 14px;
  border: 1px solid var(--line-2);
  border-radius: 14px;
  background: var(--panel);
  transition: border-color 0.15s var(--ease);
}

.composer:focus-within {
  border-color: var(--lemon);
}

.composer textarea {
  flex: 1;
  border: 0;
  background: transparent;
  outline: none;
  resize: none;
  font-size: 14.5px;
  line-height: 1.45;
  max-height: 160px;
  padding: 3px 0;
}

.composer textarea::placeholder {
  color: var(--text-3);
}

.composer__hint {
  padding-left: 4px;
}

/* ================================================== карточки выбора

   Живые примеры вместо иконок. Обещание «лицо остаётся вашим»
   невозможно проверить по описанию — его нужно показать, и лучше
   всего это делает пара «до и после» из настоящей работы.

   Смена кадров сделана на CSS, а не на таймерах: тайминги переживают
   любую перерисовку экрана, и ничего не нужно останавливать при уходе
   со страницы. */

.choices {
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}

.tile--hero {
  padding: 10px 10px 0;
  background: var(--panel);
}

.tile--hero .tt {
  padding: 14px 8px 16px;
  font-size: 12.5px;
}

.tile--hero .tt__title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 4px;
}

.pair {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 10px;
}

.pair__arrow {
  color: var(--text-3);
  font-size: 15px;
}

.strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}

.slot {
  position: relative;
  border-radius: 8px;
  overflow: hidden;
  background: #17150f;
  /* Высота задана, а не пропорции: две карточки рядом обязаны быть
     одного роста, иначе выбор из двух превращается в сравнение
     большого с маленьким. */
  height: 200px;
}

.slot img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Лицо на портрете выше середины: обрезка по центру срезала бы
     головы. */
  object-position: center 28%;
  opacity: 0;
  animation: cycle3 15s infinite;
  /* Сдвиг на треть цикла для каждого следующего снимка: пары
     «до» и «после» при этом меняются одновременно, потому что
     считают от одного и того же момента запуска. */
  animation-delay: calc(var(--i) * -5s);
}

.strip .slot img {
  /* В полосе снимков по два, а не по три, поэтому и раскладка кадров
     своя: с чужой между сменами появлялся бы чёрный провал. */
  animation-name: cycle2;
  animation-duration: 12s;
  /* Плюс к сдвигу пары — сдвиг на колонку: кадры сменяются волной,
     слева направо, как будто приходят один за другим. */
  animation-delay: calc(var(--i) * -6s - var(--k) * 1.2s);
}

@keyframes cycle3 {
  0%,
  28% {
    opacity: 1;
  }
  36%,
  90% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

@keyframes cycle2 {
  0%,
  42% {
    opacity: 1;
  }
  50%,
  92% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

.slot figcaption {
  position: absolute;
  left: 8px;
  bottom: 8px;
  z-index: 2;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 100px;
  background: rgba(10, 9, 7, 0.66);
  color: rgba(255, 255, 255, 0.78);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.slot figcaption.lit {
  color: var(--lemon);
}

/* Движение — украшение, а не смысл: кому оно мешает, тот увидит
   первый кадр каждой пары и ничего не потеряет. */
@media (prefers-reduced-motion: reduce) {
  .slot img {
    animation: none;
  }

  .slot img:first-of-type {
    opacity: 1;
  }
}

/* ================================================== панель настроек */

.panel {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}

.pgrp {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.pgrp > .lab {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* В широкой колонке фотосессии подпись и переключатель разъезжались
   на всю ширину экрана. Здесь они держатся вместе. */
.lab--tight {
  justify-content: flex-start;
  gap: 10px;
}

.lab--tight .picker {
  margin-left: 0;
}

.pgrp > .lab .rgt2 {
  margin-left: auto;
  color: var(--text-2);
  letter-spacing: 0.02em;
  text-transform: none;
  font-family: var(--sans);
  font-size: 12px;
  border: 0;
  background: transparent;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.pgrp > .lab .rgt2:hover {
  color: var(--text);
}

.tile {
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  background: var(--panel);
  cursor: pointer;
  padding: 0;
  text-align: left;
  transition: border-color 0.15s var(--ease);
}

.tile:hover {
  border-color: var(--line-2);
}

.tile.on {
  border-color: var(--lemon);
}

.hint {
  font-size: 11.5px;
  color: var(--text-3);
}

/* Кнопка, которая выглядит ссылкой. Нужна там, где действие живёт
   внутри предложения и рамка вокруг него разорвала бы фразу. */
.linkish {
  border: 0;
  background: transparent;
  padding: 0;
  color: var(--text-2);
  font-size: inherit;
  cursor: pointer;
  border-bottom: 1px solid var(--line-2);
}

.linkish:hover {
  color: var(--text);
}

.menu {
  display: flex;
  flex-direction: column;
  gap: 2px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 4px;
  background: var(--panel);
}

.menu[hidden] {
  display: none;
}

/* Обёртка кнопки: от неё отсчитывается список разделов. */
.pick {
  position: relative;
  display: inline-flex;
}

/* Список раскрывается ПОД КНОПКОЙ, а не в потоке страницы.

   В потоке он стоял после плиток и подсказки — то есть на телефоне
   открывался далеко внизу, за краем экрана: человек нажимал кнопку
   и не видел ничего. Здесь же он привязан к самой кнопке и всегда
   у неё под рукой. */
.menu--pop {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 45;
  min-width: max(100%, 220px);
  box-shadow: 0 22px 46px rgba(0, 0, 0, 0.55);
}

/* Названия разделов — обычным текстом, а не капсом метки:
   .lab выше задаёт моноширинный верхний регистр, и без сброса
   «Студия» превращалась в «С Т У Д И Я». */
.menu--pop .ri {
  font-family: var(--sans);
  font-size: 13.5px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-2);
}

.menu--pop .ri.on {
  color: var(--lemon);
}

@media (max-width: 640px) {
  /* На узком экране список шире кнопки, но не шире самого экрана. */
  .menu--pop {
    min-width: min(72vw, 260px);
  }
}

/* Характер кадра — четыре плитки, залитые своим светом.

   Было семь одинаковых пилюль с подписями: чтобы выбрать, надо было
   прочитать все семь и удержать в голове. Теперь разницу видно
   раньше, чем прочитано название, — а это и есть выбор света. */
/* Два на два, а не четыре в ряд. В колонке 268 пикселей четыре плитки
   дают по 62 — «Драматичное» в такую ширину не помещается, а образец
   света размером с ноготь перестаёт что-либо показывать. */
.moods {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 7px;
}

.mood {
  display: block;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: transparent;
  cursor: pointer;
  text-align: center;
  transition:
    border-color 0.15s var(--ease),
    transform 0.15s var(--ease);
}

.mood:hover {
  border-color: var(--line-2);
  transform: translateY(-1px);
}

.mood.on {
  border-color: var(--lemon);
}

.mood__name {
  display: block;
  padding: 6px 4px;
  font-size: 11.5px;
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mood.on .mood__name {
  color: var(--text);
}

.price {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 12px 0 2px;
  border-top: 1px solid var(--line);
}

.price .s {
  font-size: 12.5px;
  color: var(--text-2);
}

.price .v {
  margin-left: auto;
  font-size: 17px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.after-price {
  font-size: 11.5px;
  color: var(--text-3);
  text-align: center;
}

/* Платная опция. Не «галочка в форме», а строка с ценой справа:
   человек должен видеть, за что доплачивает, до того как нажмёт. */

.opt {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}

.opt:hover {
  border-color: var(--line-2);
}

.opt.on {
  border-color: var(--lemon);
  background: rgba(232, 185, 35, 0.05);
}

.opt input {
  margin-top: 3px;
  accent-color: var(--lemon);
  flex: none;
}

.opt__body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.opt__title {
  font-size: 13.5px;
  color: var(--text);
}

.opt__hint {
  font-size: 11.5px;
  color: var(--text-3);
}

.opt__price {
  margin-left: auto;
  font-size: 13px;
  color: var(--lemon);
  white-space: nowrap;
}

/* Переключатель разделов. Раньше это была тихая строчка справа,
   и половина людей её не замечала — а это главная настройка экрана.
   Теперь у неё есть рамка, фон и шеврон: она выглядит тем, чем
   является, — кнопкой. Место и размер прежние: они удобны. */
.picker {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px 4px 7px;
  border: 1px solid var(--line-2);
  border-radius: 100px;
  background: var(--panel);
  color: var(--text);
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: 0;
  text-transform: none;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}

.picker:hover {
  border-color: var(--lemon);
}

.picker__chev {
  color: var(--text-3);
  font-size: 9px;
  line-height: 1;
}

.picker:hover .picker__chev {
  color: var(--lemon);
}

/* Превью локации: один снимок места, показанный целиком.

   ЗДЕСЬ БЫЛА ПАРА КАДРОВ, СМЕНЯВШИХ ДРУГ ДРУГА. Держалась она на
   правиле «остался один снимок — не мигаем» (:only-of-type), а оно
   не срабатывало: второй картинки у большинства мест нет, и падала
   она не сразу, а иногда не падала вовсе — с loading="lazy" браузер
   может и не попытаться её загрузить. Пока она числилась в разметке,
   первый снимок половину цикла стоял прозрачным, и плитки на глазах
   становились пустыми прямоугольниками.

   Снимок один и стоит неподвижно. Приближается он только под
   курсором — плитка так отзывается на наведение. */
.shot1 {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.shot1 img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Лицо в кадре выше середины: кадрируем по верхней трети, иначе
     миниатюра показывает подбородок и плечи. */
  object-position: center 24%;
  transition: transform 0.4s var(--ease);
}

/* Характер: у каждого свой оттенок света. */
/* Сама заливка — и есть характер. Высота выбрана так, чтобы плитка
   читалась как образец света, а не как цветная полоска. */
.mood__tint {
  display: block;
  height: 46px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}

/* Формат кадра — показан самой пропорцией. */
/* Пять форматов в колонку шириной 268 px в один ряд не помещаются —
   последний уезжал за край. Две строки по три: и читается, и влезает. */
.formats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}

.fmt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  padding: 10px 4px 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}

.fmt:hover {
  border-color: var(--line-2);
}

.fmt.on {
  border-color: var(--lemon);
  background: rgba(232, 185, 35, 0.06);
}

/* Сам прямоугольник и есть объяснение: число «9:16» ничего не говорит,
   а вытянутая рамка говорит всё. Высота одна на все форматы, ширина
   считается из пропорции — иначе квадрат казался бы больше портрета. */
.fmt__box {
  height: 26px;
  aspect-ratio: var(--w) / var(--h);
  border: 1.5px solid var(--text-3);
  border-radius: 3px;
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}

.fmt.on .fmt__box {
  border-color: var(--lemon);
  background: rgba(232, 185, 35, 0.14);
}

.fmt__title {
  font-size: 10.5px;
  color: var(--text-2);
  line-height: 1;
}

.fmt.on .fmt__title {
  color: var(--text);
}

/* ================================================== до / после */

.ba {
  position: relative;
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--line);
  background: #17150f;

  /* Как и сцена — по пропорциям кадра. Сравнивать «до и после»
     в чужой рамке неудобно: половину площади занимает пустота. */
  height: min(62vh, 620px);
  aspect-ratio: var(--ar, 3 / 4);
  width: auto;
  max-width: 100%;
  margin: 0 auto;
}

.ba .after,
.ba .before {
  position: absolute;
  inset: 0;
}

.ba img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Шторка режет ВЕРХНИЙ слой. Исходник лежит сверху и открывает
   результат по мере движения — так видно, что именно изменилось. */
.ba .before {
  clip-path: inset(0 calc(100% - var(--split, 42%)) 0 0);
}

.ba .tagl,
.ba .tagr {
  position: absolute;
  bottom: 12px;
  z-index: 4;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 4px 9px;
  border-radius: 100px;
  background: rgba(10, 9, 7, 0.66);
  color: rgba(255, 255, 255, 0.8);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.ba .tagl {
  left: 12px;
}

.ba .tagr {
  right: 12px;
}

.ba .handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--split, 42%);
  z-index: 5;
  width: 2px;
  background: rgba(255, 255, 255, 0.85);
  transform: translateX(-1px);
  pointer-events: none;
}

.ba .handle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.94);
  box-shadow: 0 3px 14px rgba(0, 0, 0, 0.4);
}

.ba .handle::before {
  content: "‹ ›";
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  transform: translate(-50%, -50%);
  color: #17150f;
  font-size: 13px;
  letter-spacing: -1px;
}

.ba input[type="range"] {
  position: absolute;
  inset: 0;
  z-index: 6;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
}

.ba input[type="range"]:focus-visible + .handle::after {
  box-shadow: 0 0 0 3px var(--lemon);
}

.facts {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.facts .rgt {
  margin-left: auto;
  display: flex;
  gap: 8px;
}

/* Исходники фотосессии. Три ракурса в ряд плюс место под ещё один. */

.sources {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}

.source {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: 8px;
  overflow: hidden;
  background: var(--panel);
}

.source img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.source__drop {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 0;
  background: rgba(10, 9, 7, 0.7);
  color: #fff;
  font-size: 11px;
  cursor: pointer;
  display: grid;
  place-items: center;
}

.drop--small {
  aspect-ratio: 3 / 4;
  height: auto;
  width: auto;
  max-height: none;
  padding: 8px;
  gap: 4px;
  border-radius: 8px;
}

.drop--small .ic {
  font-size: 17px;
}

.drop--small small {
  font-size: 10.5px;
}


/* Переключатель количества кадров. Цена стоит прямо под числом:
   выбирают не «пятнадцать», а «пятнадцать за двадцать». */
.seg {
  display: flex;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}

.seg button {
  flex: 1;
  text-align: center;
  padding: 9px 4px;
  font-size: 12.5px;
  color: var(--text-2);
  border: 0;
  border-right: 1px solid var(--line);
  background: transparent;
  cursor: pointer;
}

.seg button:last-child {
  border-right: 0;
}

.seg button.on {
  background: var(--panel);
  color: var(--text);
}

.seg b {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: inherit;
}

.seg small {
  display: block;
  font-size: 10.5px;
  color: var(--text-3);
  margin-top: 1px;
}

/* Что делать дальше. Карточки, а не список ссылок: после удачного
   кадра человек не читает, он смотрит и выбирает. */
.steps-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

/* Значок СЛЕВА от текста, а не над ним. Столбиком он читался как
   отдельная строка карточки: сначала непонятная картинка, потом,
   ниже, заголовок — и глаз проходил их по очереди вместо того,
   чтобы взять карточку одним взглядом. */
.step-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 12px;
  row-gap: 3px;
  align-items: start;
  padding: 16px;
  text-align: left;
  background: var(--panel);
}

.step-card--wide {
  grid-column: 1 / -1;
}

/* Значок занимает обе строки: он относится ко всей карточке,
   а не к одному заголовку. */
.step-card__ic {
  grid-column: 1;
  grid-row: 1 / span 2;
  font-size: 18px;
  line-height: 1.35;
}

.step-card__t {
  grid-column: 2;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--text);
}

.step-card__d {
  grid-column: 2;
  font-size: 12.5px;
  color: var(--text-2);
  line-height: 1.4;
}

@media (max-width: 640px) {
  .steps-grid {
    grid-template-columns: 1fr;
  }
}

/* ================================================== контактный лист */

.sheet {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
}

.sheet .cellw {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.sheet .th {
  aspect-ratio: 3 / 4;
  border-radius: var(--r-sm);
}

.sheet .cap {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.06em;
  color: var(--text-3);
}

.sheet .cap.waiting {
  color: var(--lemon);
}

.shot {
  display: block;
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-sm);
  overflow: hidden;
}

.shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.shot__no {
  position: absolute;
  left: 7px;
  bottom: 6px;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  color: rgba(255, 255, 255, 0.62);
}

/* Пустая ячейка ждущего кадра. Пунктир — обещание: место занято,
   кадр будет. */
.empty-cell {
  aspect-ratio: 3 / 4;
  border-radius: var(--r-sm);
  background: var(--panel);
  border: 1px dashed var(--line-2);
  display: grid;
  place-items: center;
  color: var(--text-3);
}

.empty-cell.failed {
  border-style: solid;
  border-color: rgba(210, 104, 90, 0.4);
  color: var(--danger);
}

/* ================================================== тональные этюды

   Настоящих превью у стилей нет: пример в базе — это file_id Telegram,
   в браузере он бесполезен. Поддельная фотография была бы обманом,
   поэтому здесь тональные этюды: они честно показывают вес и настроение
   кадра, ничего не выдавая за снимок. */

.th {
  position: relative;
  overflow: hidden;
  background: #17150f;
}

.th::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    0deg,
    rgba(255, 255, 255, 0.018) 0 1px,
    transparent 1px 3px
  );
  pointer-events: none;
}

.t1 {
  background: radial-gradient(58% 46% at 50% 34%, #c9b08a, #6e5f49 42%, #2a241b 78%, #16130e);
}
.t2 {
  background: radial-gradient(52% 42% at 46% 30%, #a9afb6, #5c6167 40%, #23262a 80%, #131517);
}
.t3 {
  background: radial-gradient(60% 48% at 54% 36%, #e0c48f, #8a6a3e 40%, #35281a 80%, #191308);
}
.t4 {
  background: radial-gradient(50% 44% at 44% 32%, #b5a18c, #574b3d 44%, #241e18 82%, #12100d);
}
.t5 {
  background: linear-gradient(168deg, #3e4a56, #232c36 46%, #12171c);
}
.t6 {
  background: linear-gradient(150deg, #6a5334, #3a2c1a 52%, #17110a);
}

/* ================================================== формы и сообщения */

.field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.field label {
  font-size: 13px;
  color: var(--text-2);
}

.input {
  width: 100%;
  padding: 11px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  outline: none;
  font-size: 14px;
  transition: border-color 0.15s var(--ease);
}

.input:focus {
  border-color: var(--line-2);
}

textarea.input {
  resize: vertical;
  min-height: 84px;
}

.err {
  color: var(--danger);
  font-size: 13px;
}

.ok {
  color: var(--good);
  font-size: 13px;
}

.note {
  display: flex;
  gap: 12px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
  font-size: 13.5px;
  color: var(--text-2);
}

.note b {
  color: var(--text);
  font-weight: 600;
}

.note--warn {
  border-color: rgba(232, 185, 35, 0.32);
}

.empty {
  text-align: center;
  padding: 64px 24px;
  border: 1px dashed var(--line);
  border-radius: var(--r-md);
}

.empty .ic {
  font-size: 30px;
  margin-bottom: 14px;
  opacity: 0.8;
}

.empty h4 {
  font-size: 17px;
  margin-bottom: 8px;
}

.empty p {
  color: var(--text-2);
  font-size: 13.5px;
  max-width: 44ch;
  margin: 0 auto 22px;
}

.row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 0;
  border-bottom: 1px solid var(--line);
}

.row:last-child {
  border-bottom: 0;
}

.row .k {
  font-size: 13.5px;
  color: var(--text-2);
  width: 180px;
  flex: none;
}

.row .v {
  flex: 1;
  overflow-wrap: anywhere;
}

/* ================================================== пакеты лимонов */

.packs {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 520px;
}

.pack {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 12px 14px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}

.pack:hover {
  border-color: var(--line-2);
}

.pack.on {
  border-color: var(--lemon);
  background: rgba(232, 185, 35, 0.05);
}

.pack .l {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.pack .l b {
  font-size: 14px;
  font-weight: 600;
}

.pack .l small {
  font-size: 11.5px;
  color: var(--text-3);
}

.pack .r {
  margin-left: auto;
  text-align: right;
}

.pack .r b {
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.pack .r small {
  display: block;
  font-size: 11px;
  color: var(--text-3);
}

/* Отметка «выбирают чаще». Зелёная, а не лимонная: лимонный в этом
   интерфейсе означает деньги, и на ценнике он читался бы как часть
   цены. Строка не переносится и не жмётся — раньше она ломалась
   пополам внутри обводки. */
.tagbest {
  font-family: var(--mono);
  font-size: 9px;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  flex: none;
  align-self: center;
  color: var(--good);
  border: 1px solid rgba(89, 168, 131, 0.6);
  background: rgba(89, 168, 131, 0.1);
  border-radius: 100px;
  padding: 4px 9px;
}

/* Счёт: три показателя в ряд и журнал операций. */

.tiles-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}

.stat {
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 16px;
}

.stat__v {
  font-size: 28px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  margin-top: 6px;
}

.ledger {
  display: flex;
  flex-direction: column;
}

.ledger__row {
  display: flex;
  gap: 12px;
  padding: 11px 0;
  border-top: 1px solid var(--line);
  font-size: 13.5px;
  align-items: baseline;
}

.ledger__amount {
  width: 62px;
  flex: none;
  font-variant-numeric: tabular-nums;
  color: var(--text-2);
}

/* Зелёным только приход. Расход — обычным цветом: тратить лимоны
   и есть работа сервиса, красить это в тревожный цвет незачем. */
.ledger__amount.plus {
  color: var(--good);
}

.ledger__what {
  overflow-wrap: anywhere;
}

.ledger__when {
  margin-left: auto;
  color: var(--text-3);
  font-size: 12px;
  white-space: nowrap;
}

/* Окно поверх экрана: покупка не уводит со съёмки. */
.scrim {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(6, 5, 4, 0.62);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  display: grid;
  /* КОЛОНКА РОВНО ПО ОКНУ, И ЭТО НЕ ПРИДИРКА.
     Сетка без этой строки создаёт колонку по САМОМУ ШИРОКОМУ
     содержимому. В просмотрщике галереи три кнопки в ряд —
     «в избранное», «опубликовать», «скачать оригинал» — требуют
     пятьсот тридцать пикселей, и на телефоне окно становилось шире
     экрана: страница уезжала вбок, и её приходилось листать в стороны.
     minmax(0, 1fr) запрещает колонке раздуваться, а содержимому
     остаётся только поместиться. */
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  padding: 24px;
  overflow-y: auto;
}

.modal {
  width: 100%;
  max-width: 430px;
  background: var(--panel);
  border: 1px solid var(--line-2);
  border-radius: 14px;
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.modal h4 {
  font-size: 18px;
}

.modal p {
  font-size: 13px;
  color: var(--text-2);
  margin-top: 5px;
}

@media (max-width: 640px) {
  .tiles-3 {
    grid-template-columns: 1fr;
  }
}

/* ================================================== работы */

.works {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 10px;
}

/* На телефоне — ровно три в ряд, как в ленте.
   Автоподбор по ширине давал там одну колонку: кадр во весь экран,
   и десяток работ превращался в десять экранов прокрутки. */
@media (max-width: 700px) {
  .works {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 7px;
  }
}

.work {
  position: relative;
  border-radius: var(--r);
  overflow: hidden;
  background: var(--panel);
  aspect-ratio: 3 / 4;
}

.work img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.work__bar {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.75));
  opacity: 0;
  transition: opacity 0.2s var(--ease);
}

.work:hover .work__bar,
.work:focus-within .work__bar {
  opacity: 1;
}

.work__act {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 0;
  background: rgba(255, 255, 255, 0.16);
  cursor: pointer;
  display: grid;
  place-items: center;
  font-size: 14px;
  color: #fff;
}

.work__act:hover {
  background: rgba(255, 255, 255, 0.28);
}

.work__act.on {
  color: var(--lemon);
}

.work__when {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  color: rgba(255, 255, 255, 0.7);
}

/* Края: состояние поверх экрана съёмки, а не вместо него.
   Фото и настройки остаются на месте — человек видит их под карточкой
   и понимает, что ничего не потерял. */
/* Окно с плохой новостью. Оно перекрывает экран намеренно: полосу
   в потоке страницы принимают за оформление и пролистывают. */
.modal--edge {
  position: relative;
  align-items: flex-start;
  gap: 10px;
  animation: rise 0.16s ease-out;
}

.modal--danger {
  border-color: rgba(210, 104, 90, 0.4);
}

/* Крестик крупный и в углу: выход из окна должен находиться,
   не глядя. */
.modal__x {
  position: absolute;
  top: 10px;
  right: 12px;
  width: 32px;
  height: 32px;
  border: 0;
  background: none;
  color: var(--text-3);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  border-radius: 8px;
}

.modal__x:hover {
  color: var(--text);
  background: var(--line);
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

.edge {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 20px;
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  background: var(--panel);
  max-width: 560px;
}

.edge--danger {
  border-color: rgba(210, 104, 90, 0.4);
}

.chip--danger {
  border-color: rgba(210, 104, 90, 0.5);
  color: var(--danger);
}

.edge__t {
  font-size: 16px;
  font-weight: 600;
}

.edge__d {
  font-size: 13px;
  color: var(--text-2);
  max-width: 52ch;
}

.edge__acts {
  display: flex;
  gap: 8px;
  margin-top: 6px;
  flex-wrap: wrap;
}

/* ------------------------------------------------------------- профиль
   Сверху человек, ниже перечень. Разделяет их не линейка, а воздух:
   линейка в тёмном интерфейсе читается как край панели, а здесь
   ничего не кончается — просто меняется разговор.
*/
.prof {
  /* Было 620: колонка под список настроек. Теперь здесь полка
     из восьми кадров и три карточки входа в ряд — им нужно место. */
  max-width: 860px;
  display: grid;
  gap: 4px;
}

.prof__head {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-bottom: 26px;
}

/* Кружок и есть кнопка. Отдельная «загрузить фото» рядом была бы
   вторым элементом, объясняющим первый. */
.ava {
  position: relative;
  width: 96px;
  height: 96px;
  flex: none;
  border-radius: 50%;
  overflow: hidden;
  cursor: pointer;
  background: var(--panel);
  border: 1px solid var(--line-2);
  display: grid;
  place-items: center;
  transition: border-color 0.18s ease, transform 0.18s ease;
}

.ava:hover {
  border-color: var(--lemon);
  transform: translateY(-1px);
}

.ava img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Буква вместо лица — не заглушка «нет данных», а нормальное
   состояние: большинство аватар не поставит никогда. */
.ava__letter {
  font-size: 38px;
  font-weight: 600;
  color: var(--lemon);
  letter-spacing: 0.02em;
}

.ava__veil {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(13, 12, 10, 0.68);
  opacity: 0;
  transition: opacity 0.18s ease;
}

.ava:hover .ava__veil,
.ava--busy .ava__veil {
  opacity: 1;
}

.ava__hint {
  font-size: 11.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text);
}

/* Пока картинка летит на сервер, кружок дышит — это единственный
   честный ответ на «нажалось ли». */
.ava--busy {
  animation: avaPulse 1.1s ease-in-out infinite;
}

@keyframes avaPulse {
  50% {
    border-color: var(--lemon);
  }
}

.prof__who {
  min-width: 0;
}

/* Выход держится в стороне: он нужен редко, но искать его человек
   будет именно в углу профиля — там же, где во всех приложениях. */
.prof__out {
  margin-left: auto;
  align-self: flex-start;
  color: var(--text-3);
}

.prof__out:hover {
  color: var(--text);
  border-color: var(--line-2);
}

.prof__out-glyph {
  font-size: 13px;
  line-height: 1;
  opacity: 0.8;
}

.prof__who h2 {
  font-size: 26px;
  font-weight: 600;
  letter-spacing: -0.01em;
  overflow-wrap: anywhere;
}

.prof__sub {
  font-size: 13px;
  color: var(--text-3);
  margin-top: 4px;
  overflow-wrap: anywhere;
}

.prof__acts {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
  flex-wrap: wrap;
}

.prof__name-edit {
  font-size: 22px;
  font-weight: 600;
  max-width: 320px;
}

.prof__cap {
  font-size: 11.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
  margin: 26px 0 10px;
}

/* Три цифры вместо абзаца о том, как всё хорошо. Досчитываются
   при появлении — тем же countUp, что и на главной. */
.tiles3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  max-width: 620px;
}

.tile3 {
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  transition: border-color 0.18s ease, transform 0.18s ease;
}

.tile3:hover {
  border-color: var(--line-2);
  transform: translateY(-2px);
}

.tile3 b {
  font-family: var(--mono);
  font-size: 28px;
  font-weight: 600;
  color: var(--lemon);
  line-height: 1.1;
}

.tile3 span {
  font-size: 12px;
  color: var(--text-3);
}

.tile3 .linkish {
  margin-top: auto;
  padding-top: 10px;
  align-self: flex-start;
}

@media (max-width: 640px) {
  /* Три плитки в столбик заняли бы весь экран ради трёх чисел.
     Оставляем их в строку и убираем ссылки: на телефоне и счёт,
     и галерея есть в нижней панели. */
  .tiles3 {
    gap: 8px;
  }

  .tile3 {
    padding: 12px 10px;
  }

  .tile3 b {
    font-size: 21px;
  }

  .tile3 span {
    font-size: 11px;
  }

  .tile3 .linkish {
    display: none;
  }

  .prof__head {
    gap: 14px;
  }

  .ava {
    width: 72px;
    height: 72px;
  }

  .ava__letter {
    font-size: 28px;
  }

  .prof__who h2 {
    font-size: 21px;
  }
}

/* «Мои данные»: строка — сущность, справа действие с ней. */
.cards {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 560px;
}

.datum {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 14px 16px;
}

.datum > div:first-child {
  min-width: 0;
}

.datum__t {
  font-size: 13.5px;
}

.datum__d {
  font-size: 12px;
  color: var(--text-3);
  overflow-wrap: anywhere;
}

.datum .b {
  margin-left: auto;
  flex: none;
}

/* Красным — ровно одно необратимое действие на весь экран. */
.datum--danger {
  border-color: rgba(210, 104, 90, 0.4);
}

.b--danger {
  border-color: rgba(210, 104, 90, 0.5);
  color: var(--danger);
}

.b--danger:hover {
  background: rgba(210, 104, 90, 0.08);
}

/* Кадр крупно. Окно на весь экран: смотреть работу в почтовой марке
   бессмысленно, ради этого его и открывают. */
.scrim--wide .lightbox {
  position: relative;   /* якорь для крестика */
  width: 100%;
  max-width: 900px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.lightbox img {
  width: 100%;
  max-height: 74vh;
  object-fit: contain;
  border-radius: var(--r-md);
  background: #17150f;
}

.lightbox__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.lightbox__title {
  font-size: 13px;
  color: var(--text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lightbox__acts {
  margin-left: auto;
  display: flex;
  gap: 8px;
  align-items: center;
}

.work img {
  cursor: zoom-in;
}

@media (max-width: 640px) {
  /* Кнопки занимают ряд целиком и переносятся: `white-space: nowrap`
     у кнопки не даёт ей сжаться, и три штуки в ряд не влезают
     ни в один телефон. */
  .lightbox__acts {
    margin-left: 0;
    width: 100%;
    flex-wrap: wrap;
  }

  .lightbox__acts .b {
    flex: 1 1 auto;
    min-width: 0;
    white-space: normal;
    text-align: center;
  }

  .lightbox__title {
    display: none;
  }
}

/* Второе слово подписи — только там, где для него есть место. */
@media (max-width: 520px) {
  .lightbox__acts .lo {
    display: none;
  }
}

/* ================================================== витрина и вход

   Единственные экраны без оболочки: человек ещё не внутри. */

.plain {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 28px 80px;
}

.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 28px;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 30;
  background: rgba(13, 12, 10, 0.86);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

/* В гостевой шапке марка крупнее, чем в рабочей колонке: там она одна
   на весь блок, а здесь стоит в ряд с пунктами меню и в общем наборе
   терялась — читалась как ещё один пункт, а не как имя сервиса. */
.topbar .mark {
  font-size: 21px;
}

.topbar .nv {
  margin-left: auto;
  display: flex;
  gap: 20px;
  align-items: center;
  font-size: 13.5px;
  color: var(--text-2);
}

.topbar .nv a:hover {
  color: var(--text);
}

/* Где мы сейчас. Не рамка и не заливка — только цвет: подсветка
   в шапке должна отвечать на вопрос «где я», а не спорить
   с кнопкой «Войти». */
.topbar .nv a.on {
  color: var(--text);
}

.topbar .brand {
  text-decoration: none;
}

/* Возврат на главную. Стрелка тонкая и отъезжает влево при наведении —
   движение само объясняет, куда ведёт ссылка. */
.wayback {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin: 26px 0 -14px;
  font-size: 13px;
  color: var(--text-3);
  text-decoration: none;
  transition: color 0.15s;
}

.wayback:hover {
  color: var(--text);
}

.wayback__arrow {
  font-size: 15px;
  line-height: 1;
  transition: transform 0.18s cubic-bezier(0.2, 0.7, 0.3, 1);
}

.wayback:hover .wayback__arrow {
  transform: translateX(-3px);
}

@media (prefers-reduced-motion: reduce) {
  .wayback:hover .wayback__arrow {
    transform: none;
  }
}

.hero {
  /* Воздуха сверху было столько, что на ноутбуке первый экран начинался
     с пустоты, а витрина не помещалась целиком. Первый экран обязан
     показывать всё сразу: заголовок, кнопку и кадр. */
  padding: 40px 0 56px;
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 44px;
  align-items: center;
}

.hero h1 {
  font-size: clamp(34px, 4.6vw, 52px);
  line-height: 1.05;
  letter-spacing: -0.035em;
}

/* Заголовок печатается, и место под обе строки занято заранее:
   иначе кнопки уезжали бы вниз по мере печати, а страница
   при загрузке дёргалась. */
.hero h1.typing {
  min-height: 2.1em;
}

/* Курсор — тонкая черта, как в терминале, а не мигающий блок:
   блок в наборе такого размера выглядит как опечатка. */
.caret {
  display: inline-block;
  width: 2px;
  height: 0.82em;
  margin-left: 0.06em;
  vertical-align: baseline;
  background: var(--lemon);
  animation: blink 1.05s steps(1) infinite;
}

/* Допечатали — курсор гаснет: мигающая палка рядом с готовой фразой
   тянет на себя внимание, которое нужно кнопке. */
.typed .caret {
  animation: none;
  opacity: 0;
  transition: opacity 0.6s 0.5s;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .caret {
    animation: none;
    opacity: 0;
  }
}

.hero p {
  font-size: 16px;
  color: var(--text-2);
  margin-top: 16px;
  max-width: 44ch;
}

.hero .acts {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-top: 26px;
  flex-wrap: wrap;
}

.hero .fine {
  font-size: 11.5px;
  color: var(--text-3);
  margin-top: 16px;
}

/* ------------------------------------------------------------------
   Витрина главной.

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

.show {
  position: relative;
}

.show__main {
  position: relative;
  aspect-ratio: 4 / 5;
  /* Витрина считается от высоты окна, а не в пикселях: на ноутбуке
     с невысоким экраном фиксированные 520 px не помещались, и кадр
     обрезался нижней границей окна. */
  max-height: min(520px, 56vh);
  margin-left: auto;
  max-width: 420px;
  border-radius: 14px;
  overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--line);
}

.show__main img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  animation: showflip 20s infinite;
  animation-delay: var(--d);
}

/* Пять кадров в кольце по двадцать секунд: каждый висит около
   четырёх, перетекая в следующий за полсекунды. Быстрее — мельтешит
   и мешает читать заголовок; медленнее — не успевает показать, что
   мест много. */
@keyframes showflip {
  0% {
    opacity: 0;
    transform: scale(1.06);
  }
  3% {
    opacity: 1;
  }
  18% {
    opacity: 1;
  }
  21% {
    opacity: 0;
  }
  100% {
    opacity: 0;
    transform: scale(1);
  }
}

.show__caps {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 40px 16px 14px;
  background: linear-gradient(transparent, rgba(6, 5, 4, 0.78));
  min-height: 60px;
}

.show__caps span {
  position: absolute;
  /* Справа, а не слева: слева внизу лежит карточка исходника,
     и подпись пряталась бы за ней. */
  right: 16px;
  bottom: 14px;
  text-align: right;
  font-size: 13px;
  color: var(--text);
  opacity: 0;
  animation: showflip 20s infinite;
  animation-delay: var(--d);
}

/* Исходник — маленьким углом поверх результата. Так читается порядок:
   вот что было, вот что стало. Отдельная картинка рядом такого
   не говорит. */
.show__src {
  position: absolute;
  left: -14px;
  bottom: -14px;
  z-index: 1;
  width: 30%;
  max-width: 128px;
  margin: 0;
  border-radius: 10px;
  overflow: hidden;
  border: 2px solid var(--bg);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
}

.show__src img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}

.show__src figcaption {
  position: absolute;
  inset: auto 0 0 0;
  padding: 12px 8px 5px;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-2);
  background: linear-gradient(transparent, rgba(6, 5, 4, 0.85));
}

/* ---- Бегущая лента работ ---- */

.belt {
  margin: 64px -28px 0;
  display: grid;
  gap: 10px;
  overflow: hidden;
  /* Края растворяются, а не обрезаются: лента должна выглядеть
     бесконечной, а не заканчиваться о рамку экрана. */
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent,
    #000 8%,
    #000 92%,
    transparent
  );
}

.belt__row {
  display: flex;
  gap: 10px;
  width: max-content;
  animation: belt 90s linear infinite;
}

.belt__row--back {
  animation-direction: reverse;
}

.belt:hover .belt__row {
  animation-play-state: paused;
}

.belt__row img {
  height: 150px;
  width: auto;
  border-radius: 8px;
  object-fit: cover;
}

/* Список продублирован ровно дважды, поэтому сдвиг на половину
   возвращает ленту в исходное положение — стыка не видно. */
@keyframes belt {
  to {
    transform: translateX(-50%);
  }
}

/* ---- Одно лицо, пять мест ---- */

.proof {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 28px;
}

.proof__src {
  margin: 0;
  flex: 0 0 150px;
}

.proof__src img,
.proof__out img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 10px;
}

.proof figcaption {
  margin-top: 7px;
  font-size: 11.5px;
  color: var(--text-3);
}

.proof__arrow {
  color: var(--text-3);
  font-size: 18px;
}

.proof__out {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
  flex: 1;
}

.proof__out figure {
  margin: 0;
}

/* Переключатель примеров. Лица людей вместо цифр: так сразу видно,
   что примеров пять и все они разные.

   ИМЯ КЛАССА НЕ .who: так называется строка профиля внизу колонки,
   и круглая рамка отсюда доставалась ей — от имени человека оставалась
   одна буква в кружке. */
.faces {
  display: flex;
  gap: 8px;
  margin-top: 22px;
}

.face {
  width: 46px;
  height: 46px;
  padding: 0;
  border-radius: 50%;
  overflow: hidden;
  border: 2px solid transparent;
  background: none;
  cursor: pointer;
  opacity: 0.5;
  transition: opacity 0.15s;
}

.face img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.face:hover,
.face.on {
  opacity: 1;
}

.face.on {
  border-color: var(--lemon);
}

/* ==================================================================
   Три шага до результата.

   Заменили собой три абзаца про наши достоинства. Причина простая:
   человеку, который первый раз видит сервис, интересно не «чем мы
   хороши», а «что мне делать». Достоинства он оценит сам, увидев
   свой кадр.
   ================================================================== */

.steps3 {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  margin-top: 30px;
  counter-reset: step;
}

.steps3 li {
  position: relative;
  padding-top: 6px;
}

/* Номер — кружок на углу картинки. Раньше он был крупной цифрой
   позади неё и просто не читался: картинка его закрывала, а из-под
   края торчала неопознаваемая фигура. */
.steps3__no {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  font-size: 13px;
  font-weight: 600;
  color: var(--bg);
  background: var(--lemon);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
}

.steps3__pic {
  position: relative;
  z-index: 1;
  margin: 0 0 14px;
  aspect-ratio: 4 / 3;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--panel);
}

.steps3__pic img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Второй шаг показывать нечем: выбор места — это не картинка,
   а действие. Рисуем сам выбор. */
.steps3__pic--pick {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 7px;
  padding: 14px;
}

.steps3__chip {
  align-self: flex-start;
  max-width: 100%;
  display: inline-flex;
  align-items: center;
  /* Знак и подпись — две разные вещи, и между ними нужен воздух:
     без него получалось «🌇Крыша», как будто это одно слово. */
  gap: 7px;
  padding: 6px 11px;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  font-size: 12px;
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.steps3__chip.on {
  border-color: var(--lemon);
  color: var(--text);
  background: rgba(232, 185, 35, 0.1);
}

.steps3 h4 {
  font-size: 15px;
  margin-bottom: 6px;
}

.steps3 p {
  font-size: 13px;
  color: var(--text-2);
}

/* Приглашение попробовать. Стоит сразу после шагов, а не в конце
   страницы: решение принимается здесь, пока в голове ещё держится
   картинка «загрузил — выбрал — получил». */
.try {
  display: flex;
  align-items: center;
  gap: 24px;
  margin-top: 34px;
  padding: 22px 24px;
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  background: linear-gradient(120deg, rgba(232, 185, 35, 0.07), transparent 60%);
}

.try div {
  font-size: 14px;
  color: var(--text-2);
  max-width: 62ch;
}

.try b {
  color: var(--text);
}

.try .b {
  flex: none;
  margin-left: auto;
}

/* ==================================================================
   Страница «О сервисе».
   ================================================================== */

.ab-hero {
  padding: 48px 0 12px;
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 44px;
  align-items: center;
}

.ab-eyebrow {
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 18px;
}

.ab-hero h1 {
  font-size: clamp(28px, 3.6vw, 42px);
  line-height: 1.15;
  letter-spacing: -0.03em;
}

.ab-hero h1 em {
  font-style: normal;
  color: var(--lemon);
}

.ab-hero .lede {
  margin-top: 20px;
  max-width: 48ch;
}

/* Сравнение. Цифры досчитываются при появлении: неподвижная таблица
   читается как реклама, а считающая — как измерение. */
.versus {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin-top: 28px;
}

.versus__col {
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.versus__col--ours {
  border-color: rgba(232, 185, 35, 0.35);
  background: linear-gradient(160deg, rgba(232, 185, 35, 0.06), transparent 70%);
}

.versus__tag {
  display: inline-block;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 18px;
}

.versus__tag--ours {
  color: var(--lemon);
}

.versus__row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 11px 0;
  border-top: 1px solid var(--line);
}

.versus__row b {
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.03em;
  min-width: 3.2ch;
  font-variant-numeric: tabular-nums;
}

.versus__col--ours .versus__row b {
  color: var(--lemon);
}

.versus__row span {
  font-size: 13px;
  color: var(--text-2);
}

/* Цепочка обработки. Огонёк, бегущий по линии, показывает главное:
   это происходит само и занимает полминуты. */
.pipe {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
  margin-top: 34px;
  padding-top: 26px;
}

.pipe__line {
  position: absolute;
  top: 5px;
  left: 4%;
  right: 4%;
  height: 1px;
  background: var(--line-2);
  overflow: hidden;
}

.pipe__spark {
  position: absolute;
  top: 0;
  left: 0;
  width: 22%;
  height: 100%;
  background: linear-gradient(90deg, transparent, var(--lemon), transparent);
  animation: spark 3.4s ease-in-out infinite;
}

@keyframes spark {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(560%);
  }
}

.pipe__step {
  position: relative;
}

.pipe__dot {
  position: absolute;
  top: -26px;
  left: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--line-2);
  border: 2px solid var(--bg);
  animation: dotlit 3.4s ease-in-out infinite;
  animation-delay: calc(var(--i) * 0.42s);
}

@keyframes dotlit {
  0%,
  12%,
  100% {
    background: var(--line-2);
  }
  4% {
    background: var(--lemon);
  }
}

.pipe__step b {
  display: block;
  font-size: 14px;
  margin-bottom: 6px;
}

.pipe__step p {
  font-size: 13px;
  color: var(--text-2);
}

.uses {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-top: 28px;
}

/* Проявление при прокрутке. Смещение маленькое: страница должна
   оживать, а не прыгать. */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 0.5s ease,
    transform 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
}

.reveal.in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .pipe__spark,
  .pipe__dot {
    animation: none;
  }
}

@media (max-width: 900px) {
  .pipe,
  .uses {
    grid-template-columns: 1fr 1fr;
  }

  .pipe__line {
    display: none;
  }

  .pipe__dot {
    display: none;
  }

  .pipe {
    padding-top: 0;
  }
}

@media (max-width: 620px) {
  .steps3,
  .versus,
  .uses,
  .pipe {
    grid-template-columns: 1fr;
  }

  .steps3__no {
    font-size: 46px;
    top: -10px;
  }

  .try {
    flex-direction: column;
    align-items: flex-start;
  }

  .try .b {
    margin-left: 0;
    width: 100%;
    justify-content: center;
  }

  .ab-hero {
    grid-template-columns: 1fr;
    padding-top: 32px;
  }
}

.cta {
  text-align: center;
  padding-bottom: 72px;
}

.cta .lede {
  margin-left: auto;
  margin-right: auto;
}

.cta .b {
  margin-top: 24px;
}

/* Движение — украшение, а не смысл. Кому оно мешает, тот его выключил
   в системе, и мы обязаны это уважать: витрина остаётся, останавливается
   только карусель. */
@media (prefers-reduced-motion: reduce) {
  .show__main img,
  .show__caps span,
  .belt__row {
    animation: none;
  }

  .show__main img:first-of-type,
  .show__caps span:first-of-type {
    opacity: 1;
  }
}

.sec {
  padding: 72px 0 0;
  border-top: 1px solid var(--line);
}

.sec h2 {
  font-size: clamp(24px, 3vw, 32px);
  margin-bottom: 12px;
}

.sec .lede {
  color: var(--text-2);
  max-width: 60ch;
  margin-bottom: 36px;
}

.cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 24px;
}

.card {
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 22px;
  background: var(--panel);
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.card h4 {
  font-size: 16px;
}

.card p {
  font-size: 13.5px;
  color: var(--text-2);
}

.faq details {
  border-bottom: 1px solid var(--line);
  padding: 20px 0;
}

.faq summary {
  cursor: pointer;
  list-style: none;
  font-size: 16px;
  font-weight: 500;
  display: flex;
  justify-content: space-between;
  gap: 16px;
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary::after {
  content: "+";
  color: var(--text-3);
}

.faq details[open] summary::after {
  content: "−";
}

.faq p {
  color: var(--text-2);
  font-size: 14px;
  margin-top: 12px;
  max-width: 66ch;
}

.narrow {
  max-width: 420px;
  margin: 0 auto;
  padding: 72px 0;
}

.switcher {
  display: flex;
  gap: 4px;
  padding: 4px;
  background: var(--panel);
  border-radius: 100px;
  margin-bottom: 26px;
}

.switcher button {
  flex: 1;
  height: 36px;
  border: 0;
  border-radius: 100px;
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
  font-size: 14px;
}

.switcher button.on {
  background: var(--bg);
  color: var(--text);
}

.divider {
  display: flex;
  align-items: center;
  gap: 14px;
  color: var(--text-3);
  font-size: 12px;
  margin: 22px 0;
}

.divider::before,
.divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

.tg-mark {
  display: inline-grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #2aabee;
  color: #fff;
  font-size: 11px;
  padding-right: 1px;
  padding-bottom: 1px;
}

.fine {
  font-size: 12px;
  color: var(--text-3);
  text-align: center;
  margin-top: 20px;
  line-height: 1.5;
}

.fine a {
  color: var(--text-2);
  border-bottom: 1px solid var(--line);
}

footer.foot {
  border-top: 1px solid var(--line);
  margin-top: 72px;
  padding: 32px 0 60px;
  color: var(--text-3);
  font-size: 13px;
}

.foot__links {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.foot__links a:hover {
  color: var(--text-2);
}

/* ================================================== телефон */

.tabbar {
  display: none;
  /* Точка активного раздела позиционируется от панели. */
  position: relative;
}

@media (max-width: 900px) {
  .shell {
    grid-template-columns: 1fr;
  }

  /* КОЛОНКА СО СЪЁМКАМИ НЕ ПРОПАДАЕТ, А ЗАДВИГАЕТСЯ.
     Раньше здесь стояло `display: none`, и вместе с колонкой с
     телефона исчезал сам список работ: нельзя было ни открыть
     прошлую съёмку, ни переименовать, ни закрепить, ни убрать.
     Разделы и баланс переезжали в другие места, а список — никуда.
     Теперь колонка выезжает слева поверх страницы: разметка и
     обработчики те же, что в браузере, поэтому и ведёт себя
     одинаково. */
  .rail {
    position: fixed;
    z-index: 70;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(84vw, 320px);
    height: 100dvh;
    padding: 16px 12px calc(16px + env(safe-area-inset-bottom, 0px));
    overflow-y: auto;
    overscroll-behavior: contain;
    border-right: 1px solid var(--line);
    box-shadow: 22px 0 44px rgba(0, 0, 0, 0.5);
    transform: translateX(-101%);
    transition: transform 0.26s cubic-bezier(0.32, 0.72, 0, 1);
    /* Пока колонка задвинута, её содержимое не должно ловить
       нажатия: невидимая кнопка у края экрана — худший вид ловушки. */
    visibility: hidden;
  }

  body.rail-open .rail {
    transform: none;
    visibility: visible;
  }

  /* ТОЛЬКО КОГДА ОНО ДЕЙСТВИТЕЛЬНО ПОКАЗАНО.
     Первая версия писала здесь просто `display: block`, и это перебивало
     встроенное правило браузера для атрибута `hidden`: невидимое
     затемнение оставалось растянутым на весь экран поверх страницы и
     съедало КАЖДОЕ нажатие. Снаружи это выглядело так, будто на
     телефоне отвалился весь сайт — работала одна прокрутка. */
  .rail-veil:not([hidden]) {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 65;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    opacity: 0;
    transition: opacity 0.26s;
  }

  body.rail-open .rail-veil {
    opacity: 1;
  }

  /* Страница под открытой колонкой не тянется: палец должен листать
     список съёмок, а не фон под ним. */
  body.rail-open {
    overflow: hidden;
  }

  /* Кнопка, которой колонка открывается.

     КВАДРАТНАЯ И БЕЗ ПОДПИСИ. Здесь была таблетка со словом «Съёмки»:
     она занимала треть шапки и сдвигала марку вправо от середины.
     Три части разной ширины читаются как сломанная вёрстка, а не как
     замысел. Теперь слева квадрат ровно того же роста, что баланс
     справа, и марка стоит посередине. */
  .rail-open {
    position: relative;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    flex: none;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: transparent;
    color: var(--text-2);
    cursor: pointer;
  }

  .rail-open .gl {
    width: 19px;
    height: 19px;
    display: block;
  }

  .rail-open:active {
    background: var(--rail);
    color: var(--text);
  }

  /* Идёт съёмка. Точка стоит на самой кнопке, а не где-то ещё:
     на телефоне список закрыт, и других признаков работы у сервиса
     нет вовсе — человек, ушедший в ленту, иначе не знает, делается
     ли его кадр. */
  .rail-open__live:not([hidden]) {
    position: absolute;
    top: -3px;
    right: -3px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--lemon);
    border: 2px solid var(--bg);
    animation: liveBeat 1.8s var(--ease) infinite;
  }

  @keyframes liveBeat {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
  }

  .studio {
    grid-template-columns: 1fr;
  }

  /* На телефоне ширину задаёт экран, а не высота: иначе кадр
     оказывается в рамке с чёрными полями сверху и снизу. */
  .stage,
  .ba,
  .drop {
    height: auto;
    width: 100%;
    max-height: none;
  }

  .canvas {
    /* Запас снизу считается от НАСТОЯЩЕЙ высоты панели: её 63 пикселя,
       плюс поднятый над ней круг съёмки, плюс полоса жестов айфона,
       которую панель добирает через env(). Прежних 96 не хватало —
       последняя строка текста уезжала под панель, и на айфоне
       это было видно сразу. */
    padding: 18px 18px calc(112px + env(safe-area-inset-bottom, 0px));
  }

  .hero {
    grid-template-columns: 1fr;
    padding: 56px 0 48px;
  }

  /* На телефоне пять кадров в ряд превращаются в пять полосок.
     Показываем крупно и листаем пальцем — так каждый кадр видно. */
  .proof {
    flex-direction: column;
    align-items: stretch;
  }

  .proof__src {
    flex: none;
    max-width: 150px;
  }

  .proof__arrow {
    transform: rotate(90deg);
    align-self: center;
  }

  .proof__out {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    margin: 0 -18px;
    padding: 0 18px;
  }

  .proof__out figure {
    flex: 0 0 62%;
    scroll-snap-align: start;
  }

  .belt {
    margin: 44px -18px 0;
  }

  .belt__row img {
    height: 110px;
  }

  .show__src {
    left: 8px;
    bottom: 8px;
  }

  .sheet {
    grid-template-columns: repeat(3, 1fr);
  }

  /* Две карточки выбора на телефоне встают друг под друга: рядом
     они сжимаются так, что примеры перестают читаться. */
  .choices {
    grid-template-columns: 1fr;
  }

  .slot {
    height: 160px;
  }

  .mobile-top {
    display: grid !important;
  }

  .tabbar:not([hidden]) {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    position: fixed;
    inset: auto 0 0 0;
    z-index: 60;
    /* ПОЛОСА НЕПРОЗРАЧНА, А НЕ РАЗМЫТА.
       Было полупрозрачное стекло на backdrop-filter. На Android оно
       работает, на iPhone в этом сочетании (фиксированное положение,
       overflow: visible, свой слой) размытие не применяется — остаётся
       голая прозрачность 0.9, и страница едет СКВОЗЬ полосу разделов.
       Ради вида, который держится не везде, платить читаемостью на
       половине телефонов не стоит. */
    background: var(--bg);
    border-top: 1px solid var(--line);
    /* Полоса жестов внизу iPhone: без запаса разделы упираются в неё
       и нажимаются через раз. max() нужен потому, что на телефонах
       без такой полосы значение равно нулю. */
    padding-bottom: max(env(safe-area-inset-bottom, 0px), 6px);
    /* Круг съёмки выступает за верхний край панели, и обрезать его
       нельзя — поэтому overflow остаётся видимым. */
    overflow: visible;
  }

  .tab {
    position: relative;
    display: grid;
    justify-items: center;
    align-content: start;
    gap: 4px;
    padding: 10px 4px 8px;
    /* Чуть крупнее прежнего: десять пикселей читались как сноска,
       а это основная навигация телефона. */
    font-size: 11.5px;
    letter-spacing: -0.01em;
    color: var(--text-3);
    transition: color 0.2s var(--ease);
  }

  .tab.on {
    color: var(--lemon);
  }

  .tab .ic {
    font-size: 17px;
    line-height: 1;
    /* Знаки набраны шрифтом интерфейса, поэтому подчиняются цвету:
       активный раздел светится лимонным, остальные молчат. */
    opacity: 0.9;
    transition: transform 0.24s var(--bounce, cubic-bezier(0.34, 1.56, 0.64, 1));
  }

  .tab.on .ic {
    transform: translateY(-2px) scale(1.08);
  }

  /* Отклик на палец. Значок приседает и отпружинивает — этого
     достаточно, чтобы нажатие ощущалось нажатием. */
  .tab.tap .ic {
    animation: tabtap 0.32s var(--ease);
  }

  @keyframes tabtap {
    40% { transform: scale(0.82); }
    100% { transform: translateY(-2px) scale(1.08); }
  }

  /* ТОЧКА ПОД АКТИВНЫМ РАЗДЕЛОМ. Она одна на всю панель и переезжает
     между разделами, а не гаснет и зажигается заново: движение
     связывает «был здесь» и «стал тут» в одно действие. */
  .tabbar__mark {
    position: absolute;
    top: 0;
    left: 0;
    width: 20%;
    height: 2px;
    pointer-events: none;
    transform: translateX(calc(var(--slot, 0) * 100%));
    transition: transform 0.34s cubic-bezier(0.34, 1.3, 0.64, 1);
  }

  .tabbar__mark::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 0;
    width: 26px;
    height: 2px;
    margin-left: -13px;
    border-radius: 2px;
    background: var(--lemon);
    box-shadow: 0 0 12px rgba(232, 185, 35, 0.55);
  }

  /* СЪЁМКА — КРУГ НАД ПАНЕЛЬЮ. Главное действие сервиса не может
     выглядеть как один из пяти одинаковых значков. */
  .tab--hero {
    padding-top: 0;
  }

  .tab__disc {
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    margin-top: -22px;
    border-radius: 50%;
    /* ТОТ ЖЕ НАКЛОН, ЧТО У КНОПОК. Здесь был свой градиент под 160°
       и в другую сторону — от светлого к тёмному. Два разных
       направления света на одном экране глаз замечает даже тогда,
       когда не может назвать, что не так. */
    background: var(--lemon-grad);
    color: #17130a;
    box-shadow: 0 10px 24px rgba(232, 185, 35, 0.28),
      0 0 0 6px rgba(13, 12, 10, 0.92);
    transition: transform 0.26s cubic-bezier(0.34, 1.56, 0.64, 1),
      box-shadow 0.26s var(--ease);
  }

  .tab__plus {
    font-size: 26px;
    line-height: 1;
    font-weight: 300;
    transition: transform 0.34s cubic-bezier(0.34, 1.56, 0.64, 1);
  }

  .tab--hero.on .tab__disc {
    box-shadow: 0 12px 30px rgba(232, 185, 35, 0.42),
      0 0 0 6px rgba(13, 12, 10, 0.92);
  }

  /* ПОВОРОТА ПЛЮСА ЗДЕСЬ НЕТ, И ЭТО СОЗНАТЕЛЬНО. Повёрнутый на 45°
     плюс — это крестик, то есть «закрыть»; на открытом экране съёмки
     он читался бы как кнопка выхода. Активное состояние показывается
     свечением и лёгким подъёмом, а знак остаётся знаком. */
  .tab--hero.on .tab__disc {
    transform: translateY(-2px);
  }

  .tab--hero:active .tab__disc,
  .tab--hero.tap .tab__disc {
    transform: scale(0.9);
  }

  .tab--hero .tab__word {
    margin-top: 3px;
  }

  /* Кому движение мешает — тому его нет. */
  @media (prefers-reduced-motion: reduce) {
    .tabbar__mark,
    .tab .ic,
    .tab__disc,
    .tab__plus {
      transition: none;
      animation: none;
    }
  }
}

/* Верхняя строка телефона: марка и баланс. На большом экране её нет —
   там и то, и другое живёт в колонке слева. */
.mobile-top {
  display: none;
  /* ТРИ СЛОТА, МАРКА ПОСЕРЕДИНЕ. Раньше это был обычный ряд, и марка
     стояла там, куда её оттеснила кнопка слева, — то есть каждый раз
     чуть по-разному. Сетка «край — середина — край» держит её ровно
     по центру независимо от того, что лежит по бокам. */
  grid-template-columns: 38px 1fr 38px;
  align-items: center;
  gap: 12px;
  /* СВЕРХУ ДОБИРАЕМ ЗОНУ ПОД ЧАСАМИ И ВЫРЕЗОМ.
     Страница объявлена во весь экран (viewport-fit=cover), поэтому её
     верх уходит под статусную строку. Без этого запаса содержимое
     проезжало в полоске над шапкой — на iPhone это было видно сразу,
     на Android такой зоны нет и всё выглядело правильно. */
  padding: calc(12px + env(safe-area-inset-top, 0px)) 18px 12px;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 30;
  /* Непрозрачна по той же причине, что и нижняя полоса: размытие
     на iPhone не применяется, и сквозь шапку ехала страница.
     Тёплый отсвет — тот же, что в колонке на большом экране. */
  background:
    radial-gradient(120% 160% at 50% 0%, rgba(232, 185, 35, 0.05), rgba(232, 185, 35, 0) 70%),
    var(--bg);
}

/* Марка занимает среднюю колонку целиком и центрируется в ней. */
.mobile-top .brand {
  justify-content: center;
  padding: 0;
}

/* Баланс — правый край. Ширина колонки задана под кнопку шторки,
   а баланс шире: пусть выступает влево, к середине, а не наружу. */
.mobile-top .bal {
  justify-self: end;
  padding: 6px 10px;
  white-space: nowrap;
}

/* Баланс — кнопка: нажимается и отвечает нажатию. Без отклика
   человек трижды ткнёт и решит, что экран завис. */
.bal--go {
  border: 1px solid var(--line);
  background: var(--panel);
  cursor: pointer;
  border-radius: 999px;
  transition: border-color 0.18s var(--ease), transform 0.12s var(--ease);
}

.bal--go:hover { border-color: var(--line-2); }
.bal--go:active { transform: scale(0.94); }

@media (max-width: 620px) {
  .plain {
    padding: 0 18px 72px;
  }

  .topbar {
    padding: 12px 18px;
  }

  /* На телефоне четыре пункта в строку не влезают, и первой за край
     уезжает «Войти» — единственная кнопка, ради которой шапка и есть.
     Текстовые ссылки убираем: те же разделы лежат ниже по странице
     и в подвале. */
  .topbar .nv a:not(.b) {
    display: none;
  }

  .topbar .nv .b {
    padding: 9px 18px;
  }

  .sheet {
    grid-template-columns: repeat(2, 1fr);
  }

  .facts .rgt {
    margin-left: 0;
    width: 100%;
  }

  .row {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }

  .row .k {
    width: auto;
  }
}

/* ==================================================================
   Проводник по первой съёмке.

   Экран притемняется, кроме одного места — того, куда нужно нажать.
   Дырка сделана огромной тенью вокруг прозрачного прямоугольника:
   так подсветка остаётся живой при любом размере окна и не требует
   ни канвы, ни второй копии интерфейса.
   ================================================================== */

.tour {
  position: fixed;
  inset: 0;
  z-index: 120;
  /* Слой ничего не перехватывает: нажатие проходит насквозь, к самой
     кнопке. Проводник показывает, куда нажать, а не нажимает вместо
     человека. */
  pointer-events: none;
}

.tour__hole {
  position: fixed;
  border-radius: 12px;
  box-shadow: 0 0 0 9999px rgba(6, 5, 4, 0.74);
  outline: 1.5px solid var(--lemon);
  outline-offset: 2px;
  animation: tourpulse 2.4s ease-in-out infinite;
}

/* Перелёт только при смене шага. Держать переход постоянно нельзя:
   при прокрутке рамка отставала бы от содержимого на треть секунды,
   и это выглядит ровно как «подсветка съезжает». */
.tour__hole--fly {
  transition:
    top 0.28s cubic-bezier(0.2, 0.7, 0.3, 1),
    left 0.28s cubic-bezier(0.2, 0.7, 0.3, 1),
    width 0.28s cubic-bezier(0.2, 0.7, 0.3, 1),
    height 0.28s cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* Дыхание подсветки — единственное движение на притемнённом экране,
   и взгляд идёт к нему сам. */
@keyframes tourpulse {
  50% {
    outline-color: rgba(232, 185, 35, 0.35);
  }
}

/* КАРТОЧКА НЕ ЛОВИТ НАЖАТИЯ — их ловят только её кнопки.

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

   Со сквозными нажатиями проводник больше не может помешать сделать
   то, чему он учит. */
.tour__card {
  position: fixed;
  width: min(320px, calc(100vw - 28px));
  padding: 18px;
  border-radius: 14px;
  background: var(--panel);
  border: 1px solid var(--line-2);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
  pointer-events: none;
  animation: rise 0.22s ease-out;
}

.tour__card button {
  pointer-events: auto;
}

.tour__step {
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--lemon);
  margin-bottom: 9px;
}

.tour__card h4 {
  font-size: 15px;
  margin-bottom: 7px;
}

.tour__card p {
  font-size: 13px;
  color: var(--text-2);
}

.tour__acts {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 16px;
}

@media (prefers-reduced-motion: reduce) {
  .tour__hole,
  .tour__card {
    transition: none;
    animation: none;
  }
}

/* ==================================================================
   Встреча нового человека.

   Единственное место в сервисе, где мы позволяем себе праздник.
   Дальше человек работает, и мешать ему нельзя — поэтому салют
   короткий, пять залпов, и гаснет сам.
   ================================================================== */

.hello {
  position: fixed;
  inset: 0;
  z-index: 140;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(6, 5, 4, 0.82);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  animation: fadein 0.3s ease-out;
}

.hello--out {
  animation: fadeout 0.26s ease-in forwards;
}

@keyframes fadein {
  from {
    opacity: 0;
  }
}

@keyframes fadeout {
  to {
    opacity: 0;
  }
}

/* Небо для салюта лежит под карточкой и ничего не перехватывает. */
.hello__sky {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.hello__card {
  position: relative;
  width: min(420px, 100%);
  padding: 30px 28px 26px;
  border-radius: 18px;
  text-align: center;
  background: var(--panel);
  border: 1px solid var(--line-2);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
  animation: rise 0.34s cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* Лимоны падают на счёт по одному — подарок вручают, а не начисляют
   молча. Задержка у каждого своя, иначе это выглядит как одна
   картинка, а не как три кадра. */
.hello__lemons {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-bottom: 16px;
  font-size: 34px;
  line-height: 1;
}

.hello__lemons span {
  display: block;
  animation: drop 0.62s cubic-bezier(0.3, 1.4, 0.5, 1) backwards;
  animation-delay: calc(0.24s + var(--i) * 0.14s);
}

@keyframes drop {
  from {
    opacity: 0;
    transform: translateY(-52px) rotate(-18deg);
  }
}

.hello__card h3 {
  font-size: 22px;
  letter-spacing: -0.02em;
}

.hello__card p {
  margin: 10px 0 22px;
  font-size: 13.5px;
  color: var(--text-2);
}

@media (prefers-reduced-motion: reduce) {
  .hello,
  .hello__card,
  .hello__lemons span {
    animation: none;
  }
}

/* ==================================================================
   Проверка «вы не робот» и вход через сторонние сервисы.
   ================================================================== */

/* Кнопки сторонних входов стоят в столбик и одинаковой ширины:
   ряд разноцветных плиток разной длины выглядит как чужая реклама
   на нашей форме. */
.oauth {
  display: grid;
  gap: 8px;
}

.oauth__b {
  justify-content: center;
  gap: 10px;
}

.oauth__mark {
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  border-radius: 5px;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  color: #fff;
}

.oauth__mark--google {
  background: #4285f4;
}

.oauth__mark--yandex {
  background: #fc3f1d;
}

.oauth__mark--vk {
  background: #0077ff;
  font-size: 9px;
}

.oauth__mark--tg {
  background: #2aabee;
}

/* ==================================================================
   Пароль с глазом и восстановление доступа.
   ================================================================== */

/* Ссылка-действие под формой: «начать сначала». Не кнопка — это
   не действие формы, а уход в сторону. */
.forgot {
  align-self: center;
  font-size: 13px;
}

/* Узкая колонка для форм входа и восстановления: строка в шестьдесят
   знаков читается, строка во всю ширину монитора — нет. */
.narrow {
  max-width: 420px;
  margin: 0 auto;
}

.narrow h2 {
  margin-top: 28px;
}

/* Форма отделяется от объяснения. Без отступа подпись первого поля
   прилипает к тексту абзаца и читается как его продолжение. */
.narrow .lede + form,
.narrow form {
  margin-top: 22px;
}

/* Строка подтверждения номера прямо в напоминании: код уже в руке,
   уходить за ним некуда. */
.codeline {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  flex-wrap: wrap;
}

.input--code {
  width: 120px;
  text-align: center;
  letter-spacing: 0.28em;
  font-family: var(--mono);
}

/* Вход и подтверждение звонком. Стоит отдельным блоком под формой:
   это не ещё одно поле, а другой способ — и выглядеть он должен
   как другой способ. */
.bycall {
  display: grid;
  gap: 8px;
  margin-top: 14px;
  padding: 14px;
  border: 1px dashed var(--line-2);
  border-radius: 12px;
  text-align: center;
}

.bycall .hint {
  text-align: center;
}

.bycall a.b {
  justify-content: center;
}

/* ==================================================================
   Вход и регистрация — один экран.

   Форма меняется по мере того, как выясняются обстоятельства: поле,
   потом звонок, потом имя. Всё это одна страница, а не набор окон
   поверх неё, — поэтому и оформление здесь одно на все состояния.
   ================================================================== */

.gate__form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-top: 24px;
}

/* Панель звонка. Номер крупный: его читают с экрана и набирают
   руками, если ссылка не сработала. */
.callpanel {
  display: grid;
  gap: 12px;
  padding: 22px 18px;
  text-align: center;
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  background: linear-gradient(160deg, rgba(232, 185, 35, 0.06), transparent 70%);
}

.callpanel__num {
  font-size: clamp(22px, 5vw, 28px);
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.callpanel .hint {
  text-align: center;
}

/* Ожидание звонка — единственное движение на экране, и оно должно
   читаться как «идёт», а не как «зависло». */
.callpanel .hint::before {
  content: "";
  display: inline-block;
  width: 9px;
  height: 9px;
  margin-right: 7px;
  border-radius: 50%;
  border: 1.5px solid var(--line-2);
  border-top-color: var(--lemon);
  vertical-align: -1px;
  animation: spin 0.8s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .callpanel .hint::before {
    animation-duration: 2.4s;
  }
}


/* Полоса «вышло обновление». Появляется только тогда, когда человек
   занят съёмкой и перечитывать страницу за него нельзя: молча
   перезагрузить посреди работы значит отнять выбранное фото. */
.updated {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  z-index: 200;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 14px 12px 18px;
  border-radius: 12px;
  background: var(--panel);
  border: 1px solid var(--line-2);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
  font-size: 13.5px;
  animation: rise 0.22s ease-out;
}

@media (max-width: 640px) {
  .updated {
    left: 12px;
    right: 12px;
    bottom: 74px;
    transform: none;
    justify-content: space-between;
  }
}


/* ==================================================
   Лента работ

   ПОЧЕМУ КОЛОНКИ, А НЕ GRID. Все кадры вертикальные, но разной высоты.
   В сетке они превратились бы в таблицу с дырами под каждым; колонки
   ставят их плотно, и лента читается как контактный лист, а не как
   ведомость.
   ================================================== */

/* КОЛОНКИ, КАК В PINTEREST.

   Каждый кадр показан целиком, в своих пропорциях: вертикальный —
   высоким, квадратный — квадратным. Ряды поэтому не выравниваются,
   и лента идёт уступами — это и есть нужный вид. Ровная сетка,
   которую пробовали до этого, требовала обрезать каждый кадр
   до 3:4, то есть показывать не то, что сняли. */
/* СТОЛБЦЫ, А НЕ ПЕРЕТЕКАНИЕ.

   Было `columns: 3` — браузер сам разливал карточки сверху вниз.
   Пока лента не росла, это работало; но при подгрузке следующей
   порции браузер переливает заново ВСЮ ленту, и просмотренные кадры
   переезжают на другие места прямо под пальцем. Теперь столбцы —
   обычные колонки, а новое дописывается в их конец: показанное
   не двигается, новое приходит снизу. Раскладку делает скрипт,
   см. fillFeed. */
.feed {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}

.feed__col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.plain--feed {
  max-width: 1180px;
  margin: 0 auto;
  padding: 26px 20px 60px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* КАРТОЧКА ВИДНА БЕЗ УЧАСТИЯ СКРИПТА.
 *
 * Раньше на ней был класс `.reveal`: прозрачность ноль, а показывал
 * её наблюдатель за прокруткой. На настольном браузере это работало,
 * на iPhone — нет: наблюдателя уносил сборщик мусора, и человек,
 * свайпнув вниз, упирался в пустоту. Он видел это как «картинка
 * пропала», и был прав.
 *
 * Теперь появление сделано анимацией, а не переходом из невидимости.
 * Разница принципиальная: анимация запускается сама в тот момент,
 * когда элемент вставили, и заканчивается видимым кадром при любом
 * исходе. Не сработает — карточка просто окажется на месте сразу.
 * Ошибка в эту сторону стоит анимации; в другую стоила ленты. */
.fcard {
  animation: cardIn 0.42s var(--ease) both;
  animation-delay: calc(var(--i, 0) * 0.035s);
  position: relative;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--line);
  cursor: pointer;
  transition: transform 0.22s var(--ease), border-color 0.22s var(--ease),
    box-shadow 0.22s var(--ease);
}

.fcard:hover {
  transform: translateY(-4px);
  border-color: var(--line-2);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.55);
}

.fcard img {
  display: block;
  width: 100%;
  height: auto;
}

/* ВСЁ, ЧТО НЕ КАДР, — ПРИ НАВЕДЕНИИ.
   Постоянная подпись поверх снимка и полоса со счётчиками под ним
   занимали половину высоты столбца, и глаз читал оформление наравне
   с фотографиями. Теперь они всплывают тогда, когда человек уже
   выбрал, на что смотрит. */
.fcard__over {
  position: absolute;
  inset: auto 0 0 0;
  padding: 40px 11px 11px;
  background: linear-gradient(to top, rgba(9, 8, 6, 0.94), rgba(9, 8, 6, 0.6) 42%, rgba(9, 8, 6, 0));
  display: flex;
  flex-direction: column;
  gap: 9px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.2s var(--ease), transform 0.2s var(--ease);
  pointer-events: none;
}

/* ТОЛЬКО ПОД КУРСОРОМ. Раньше слой всплывал ещё и по `:focus-within`,
   а на телефоне нажатие по карточке ставит на неё фокус — и поверх
   уже показанной метки с отметками выезжала вторая, со своим числом
   отметок. Человек видел два счётчика лайков друг на друге; владелец
   поймал это 01.09.2026.

   Фокус здесь и не нужен: на телефоне карточка открывается нажатием,
   а с клавиатуры по ней ходят табом — и для этого есть ссылка внутри,
   у неё своя видимая обводка. */
@media (hover: hover) {
  .fcard:hover .fcard__over {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }
}

.fcard__who {
  display: flex;
  align-items: baseline;
  gap: 7px;
  font-size: 12.5px;
  min-width: 0;
}

.fcard__who b {
  font-weight: 560;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fcard__who span {
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fcard__row {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Метка с отметками. На большом экране её нет — там всё показывает
   наведение. На телефоне наведения не существует, а понимать,
   что кадры живые и их смотрят, человеку нужно так же. */
.fcard__mini {
  display: none;
}

.fmet {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-2);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.fmet:hover { color: var(--text); }
.fmet.on { color: var(--lemon); }
.fmet svg { width: 15px; height: 15px; }

.fcard__go {
  margin-left: auto;
  padding: 6px 12px;
  font-size: 12.5px;
}

/* Главное действие ленты подсвечивается на той карточке, к которой
   человек потянулся, — и молчит на всех остальных. */
.fcard:hover .fcard__go {
  background: var(--lemon-grad);
  border-color: transparent;
  color: #241b02;
  font-weight: 600;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

.feed__more {
  text-align: center;
  padding: 10px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--text-3);
}

@keyframes beat {
  40% { transform: scale(1.32); }
  70% { transform: scale(0.94); }
  100% { transform: scale(1); }
}

.beat svg { animation: beat 0.42s var(--ease); }

/* ---------------------------------------------- открытая карточка */

.scrim--post { padding: 26px; }

.post {
  width: min(1180px, 100%);
  height: min(940px, 100%);
  display: grid;
  grid-template-columns: 1fr 400px;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line-2);
  background: var(--panel);
  animation: lift 0.28s var(--ease);
}

@keyframes cardIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

@keyframes lift {
  from { opacity: 0; transform: translateY(20px) scale(0.985); }
}

/* КАДР ЦЕЛИКОМ И БЕЗ УВЕЛИЧЕНИЯ.

   `min-height: 0` здесь обязателен. Без него элемент сетки не может
   стать меньше своего содержимого: картинка 736×1104 растягивала
   рамку до 1087 пикселей внутри окна высотой 658 — и кадр обрезался
   сверху и снизу, выглядя приближённым. Жалоба 20.08.2026 была
   именно об этом. */
.post__frame {
  position: relative;
  background: #080705;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  place-items: center;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

/* Кадр прижат к рамке, а не к строке сетки.

   `max-height: 100%` само по себе не помогало: строка сетки растёт
   по содержимому, и сотня процентов отсчитывалась от высоты самой
   картинки — то есть ни от чего. Отсчёт от рамки даёт только
   позиционирование: рамка объявлена position: relative, её высота
   известна, и кадр честно вписывается в неё целиком.
   `margin: auto` при нулевых отступах ставит по центру его по обеим осям. */
.post__frame img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.post__chips {
  position: absolute;
  left: 14px;
  top: 14px;
  display: flex;
  gap: 7px;
  flex-wrap: wrap;
}

.post__chips .chip { background: rgba(10, 9, 7, 0.72); }

.post__who {
  position: absolute;
  left: 14px;
  bottom: 12px;
  font-size: 13.5px;
}

.post__x {
  position: absolute;
  right: 12px;
  top: 12px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(20, 18, 15, 0.72);
  color: var(--text);
  cursor: pointer;
}

.post__side {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 20px;
  border-left: 1px solid var(--line);
  overflow-y: auto;
}

.post__acts {
  display: flex;
  align-items: center;
  gap: 18px;
}

.post__acts .fmet { font-size: 13px; }
.post__acts .fmet svg { width: 17px; height: 17px; }
.post__report { margin-left: auto; font-size: 12px; color: var(--text-3); }

.post__note {
  font-size: 12.5px;
  color: var(--text-3);
  line-height: 1.5;
}

.post__doubles {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border-top: 1px solid var(--line);
  padding-top: 16px;
}

.post__doubles--empty p { font-size: 12.5px; color: var(--text-3); }

.post__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 9px;
}

.post__thumb {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  overflow: hidden;
  padding: 0;
  background: transparent;
  cursor: pointer;
  transition: transform 0.18s var(--ease), border-color 0.18s var(--ease);
}

.post__thumb:hover { transform: translateY(-3px); border-color: var(--line-2); }

.post__thumb img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}

.post__thumb span {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 16px 6px 5px;
  font-size: 10.5px;
  text-align: left;
  color: var(--text);
  background: linear-gradient(to top, rgba(9, 8, 6, 0.9), rgba(9, 8, 6, 0));
}

/* ------------------------------------------------------- телефон */

@media (max-width: 1100px) {
  /* Ширина считается и в скрипте — см. feedColumns. */
}

@media (max-width: 640px) {
  /* Одна колонка во всю ширину: кадр занимает почти весь экран,
     и лента листается, а не разглядывается. */
  .feed { gap: 12px; }
  .feed__col { gap: 12px; }
  .fcard__go { padding: 9px 14px; font-size: 13.5px; }

  .scrim--post { padding: 0; }

  .post {
    grid-template-columns: 1fr;
    grid-template-rows: minmax(0, 1fr) auto;
    height: 100%;
    border-radius: 0;
    border: 0;
  }

  .post__side {
    border-left: 0;
    border-top: 1px solid var(--line);
    padding: 14px 14px 20px;
  }

  .post__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}


/* Окно публикации: слева видно ровно то, что уйдёт в ленту, справа —
   четыре обещания вместо юридического абзаца. Показывать текст
   согласия рядом с самим кадром важнее, чем красиво: человек решает
   про конкретную фотографию, а не про абстрактную возможность. */
.modal--publish { max-width: 720px; padding: 0; overflow: hidden; }

.publish {
  display: grid;
  grid-template-columns: 232px 1fr;
}

.publish__pic {
  background: #100e0c;
  border-right: 1px solid var(--line);
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.publish__pic img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--r);
  border: 1px solid var(--line-2);
}

.publish__body {
  padding: 22px 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.promises {
  display: flex;
  flex-direction: column;
  gap: 11px;
  list-style: none;
  font-size: 12.5px;
  color: var(--text-2);
  line-height: 1.5;
}

.promises li {
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: 10px;
}

.promises li::before {
  content: "✓";
  color: var(--good);
  font-size: 13px;
  line-height: 1.4;
}

.promises b {
  color: var(--text);
  font-weight: 560;
  display: block;
}

@media (max-width: 640px) {
  .publish { grid-template-columns: 1fr; }
  .publish__pic {
    border-right: 0;
    border-bottom: 1px solid var(--line);
    flex-direction: row;
    align-items: center;
    gap: 14px;
  }
  .publish__pic img { width: 88px; }
}


/* Строка публикации в профиле: кадр слева, цифры в подписи,
   одно действие справа. */
.post-row img {
  width: 46px;
  height: 61px;
  object-fit: cover;
  border-radius: 6px;
  display: block;
  flex: none;
}

.post-row { gap: 14px; }


/* Лента на главной. Шесть колонок на большом экране — это витрина,
   а не сама лента: задача показать разнообразие, а не дать листать. */
.hfeed {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 12px;
}

.hcard {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--panel);
  display: block;
  transition: transform 0.22s var(--ease), box-shadow 0.22s var(--ease);
}

.hcard:hover {
  transform: translateY(-5px);
  box-shadow: 0 20px 44px rgba(0, 0, 0, 0.6);
}

.hcard img { width: 100%; height: 100%; object-fit: cover; display: block; }

.hcard__veil {
  position: absolute;
  inset: auto 0 0 0;
  padding: 22px 10px 8px;
  font-size: 11.5px;
  display: flex;
  align-items: baseline;
  gap: 8px;
  background: linear-gradient(to top, rgba(9, 8, 6, 0.92), rgba(9, 8, 6, 0));
}

.hcard__veil b { font-weight: 560; }
.hcard__veil i { margin-left: auto; font-family: var(--mono); color: var(--text-2); font-style: normal; }

.sec--feed { display: flex; flex-direction: column; gap: 16px; }

@media (max-width: 900px) { .hfeed { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 520px) { .hfeed { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ==================================================
   ДУБЛЬ: экран «снять так же»
   ================================================== */

/* Уравнение из двух рамок. Слева образец, справа своё фото, между
   ними плюс: это объясняет механику быстрее любого текста. */
.dbl {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 22px;
  align-items: start;
}

.dbl__pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}

.dbl__cell {
  margin: 0;
  display: grid;
  gap: 10px;
}

/* Обе рамки одной высоты и одних пропорций — иначе уравнение
   разъезжается и читается как «главное слева, мелочь справа». */
/* РАМКИ НЕ ВЫШЕ ПОЛОВИНЫ ОКНА. Пропорция 3:4 на широком экране
   растягивала их на всю высоту и уводила цену с кнопкой под сгиб —
   при том что решение принимают именно там. Ограничение по высоте
   держит весь экран в одном развороте. */
.dbl__stage {
  position: relative;
  aspect-ratio: 3 / 4;
  max-height: 56vh;
  background: #0c0b09;
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--line);
  display: grid;
  /* Строка задана явно — иначе она вырастет под картинку, и «сто
     процентов» высоты окажутся высотой самой картинки, то есть
     ничем. Та же ловушка, что и в окне открытого кадра. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  place-items: center;
}

/* Кадр показан целиком, а не обрезанным по рамке. Обрезка здесь
   была бы обманом: человек смотрит на образец и решает, хочет ли
   он именно такой снимок — значит, видеть он должен именно тот
   снимок, который получит. */
.dbl__stage img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.dbl__stage--ref {
  border-color: var(--line-2);
}

.dbl__drop {
  aspect-ratio: 3 / 4;
  margin: 0;
}

.dbl__sign {
  align-self: center;
  font-size: 26px;
  line-height: 1;
  color: var(--muted);
  padding-top: 22%;
}

.dbl__note {
  display: grid;
  gap: 3px;
  font-size: 13px;
  line-height: 1.45;
}

.dbl__note b {
  font-size: 13.5px;
}

.dbl__note span {
  color: var(--muted);
}

.dbl__own {
  margin-top: 12px;
}

/* Строка правок стоит под обеими рамками, во всю их ширину: это
   поправка сразу к паре, а не к одному из снимков. */
/* СТРОКА ПРАВОК ЖИВЁТ ВНУТРИ ПАНЕЛИ. Раньше она была отдельным
   блоком во второй строке сетки — то есть под картинками, за нижним
   краем экрана. Человек её не видел вовсе: страница заканчивалась
   кнопкой «Снять дубль», а поле открывалось только тому, кто
   догадался пролистать. Закрепления за строку и колонку больше
   не нужны: панель сама ставит её на место. */
.dbl__ask {
  margin-top: 2px;
}

.dbl > .panel {
  grid-column: 2;
}

.hint--body {
  margin: 0;
  line-height: 1.5;
}

@media (max-width: 1100px) {
  /* ПАНЕЛЬ УХОДИТ ПОД РАМКИ, А НЕ ОСТАЁТСЯ СБОКУ.
     
     Одной строки «в одну колонку» здесь было мало, и это стоило
     сломанного экрана на телефоне: панель выше прибита к `grid-column: 2`,
     а колонки номер два в одноколоночной сетке нет — браузер честно
     создаёт её сам, по ширине содержимого. Получалась щель в полтораста
     пикселей, куда переносом по слову утрамбовывались и «Оригинал в 4K»,
     и цена, и кнопка съёмки. Снимаем закрепление вместе со сменой сетки. */
  .dbl {
    grid-template-columns: minmax(0, 1fr);
  }

  .dbl > .panel {
    grid-column: 1;
  }
}

@media (max-width: 640px) {
  /* Плюс между рамками на телефоне лишний: рамки встают друг под
     друга, и знак сложения между ними читался бы как опечатка. */
  .dbl__pair { grid-template-columns: 1fr; }
  .dbl__sign { display: none; }

  /* Рамки больше не стоят рядом — держать их одной высоты незачем.
     Образец показывается в своих пропорциях: соотношение 3:4 на
     вертикальном кадре 2:3 давало чёрные поля по бокам, которые
     не добавляют ничего, кроме впечатления обрезанной картинки. */
  .dbl__stage--ref {
    aspect-ratio: auto;
    /* И не во всю ширину: образец на телефоне — это напоминание
       о том, что мы повторяем, а не главное на экране. Во всю ширину
       он занимал весь первый экран, и загрузка фотографии — то, ради
       чего человек сюда пришёл, — оказывалась за сгибом. */
    max-width: 62%;
    margin: 0 auto;
  }

  .dbl__stage--ref img {
    height: auto;
  }

  /* А рамка загрузки, наоборот, не должна занимать пол-экрана:
     три четверти ширины телефона — это 450 пикселей высоты
     ради одной кнопки. */
  .dbl__drop {
    aspect-ratio: auto;
    min-height: 240px;
    padding: 22px 16px;
  }
}

/* ==================================================
   ЕДУЩАЯ ЛЕНТА НА ЭКРАНЕ ВЫБОРА
   ================================================== */

.glide {
  margin-top: 30px;
  display: grid;
  gap: 12px;
}

.glide__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.glide__all {
  font-size: 13px;
  color: var(--muted);
  text-decoration: none;
  transition: color 0.18s var(--ease);
}

.glide__all:hover {
  color: var(--ink);
}

/* Края полосы растворяются, а не обрубаются: жёсткий срез читается
   как поломанная вёрстка, а растворение — как «дальше ещё есть». */
.glide__win {
  /* ПОЛОСУ ТЕПЕРЬ КРУТИТ ПРОКРУТКА, А НЕ АНИМАЦИЯ.
     Раньше это была лента на CSS-анимации: transform ехал влево
     по кругу. Смотреть — можно, трогать — нельзя: палец по ней
     не работал вовсе, потому что двигать анимацию нечем. А на
     телефоне лента, которую нельзя пролистать, читается как
     картинка, а не как лента.

     Настоящая прокрутка даёт всё сразу: палец с инерцией, остановку
     под пальцем, стрелки на большом экране — и всё это средствами
     самого браузера. Наш скрипт только подталкивает её, пока
     человек не трогает (см. функцию glide в app.js). */
  overflow-x: auto;
  overflow-y: hidden;
  border-radius: var(--r-md);
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* Дотянув до края, полоса не должна утягивать за собой страницу
     или включать «назад» жестом. */
  overscroll-behavior-x: contain;
  -webkit-mask-image: linear-gradient(
    to right, transparent, #000 6%, #000 94%, transparent
  );
  mask-image: linear-gradient(
    to right, transparent, #000 6%, #000 94%, transparent
  );
}

.glide__win::-webkit-scrollbar {
  display: none;
}

.glide__track {
  display: flex;
  gap: 12px;
  width: max-content;
}

.gcard {
  position: relative;
  flex: none;
  width: 168px;
  aspect-ratio: 3 / 4;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--panel);
  cursor: pointer;
  transition: transform 0.24s var(--ease), border-color 0.24s var(--ease),
    box-shadow 0.24s var(--ease);
}

.gcard:hover {
  transform: translateY(-4px);
  border-color: var(--line-2);
  box-shadow: 0 16px 34px rgba(0, 0, 0, 0.5);
}

.gcard img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.gcard__veil {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 22px 10px 9px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: 11.5px;
  text-align: left;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.82), transparent);
}

.gcard__veil b {
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gcard__veil i {
  font-style: normal;
  color: var(--muted);
  flex: none;
}

/* Кому движение мешает — тому его нет вовсе, а полоса листается
   рукой. Это не «версия попроще», а тот же экран другим способом. */
@media (prefers-reduced-motion: reduce) {
  .glide__track { animation: none; }
  .glide__win { overflow-x: auto; }
}

@media (max-width: 640px) {
  .gcard { width: 138px; }
}

/* ==================================================
   ПОД ОТКРЫТОЙ СЪЁМКОЙ
   ================================================== */

.after {
  margin-top: 22px;
  display: grid;
  gap: 18px;
}

.after__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Черта с вопросом посередине — граница между лентой и выбором.
   Две вещи разного рода не должны идти встык. */
.split {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 30px 0 18px;
}

.split__line {
  flex: 1;
  height: 1px;
  background: linear-gradient(to right, transparent, var(--line), transparent);
}

.split__ask {
  margin: 0;
  font-size: 17px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--text-2);
  white-space: nowrap;
}

.glide--top {
  margin-top: 4px;
  position: relative;
}

/* --------------------------------------------------------- стрелки

   ПОЧЕМУ ОНИ ЕСТЬ ТОЛЬКО НА БОЛЬШОМ ЭКРАНЕ. Там нет пальца: полосу
   нечем взять и потянуть, а колесо мыши крутит страницу вниз, а не
   ленту вбок. Стрелка — единственный способ управлять ею мышью.
   На телефоне она была бы лишней кнопкой поверх того, что и так
   листается рукой.

   Появляются при наведении на полосу и стоят прямо на растворённых
   краях — там, куда и тянется рука. */
.glide__go {
  position: absolute;
  top: 50%;
  z-index: 3;
  width: 40px;
  height: 40px;
  margin-top: -20px;
  display: none;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 50%;
  background: rgba(9, 8, 6, 0.66);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--text);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.2s var(--ease), transform 0.2s var(--ease),
    background 0.2s var(--ease);
}

.glide__go--prev { left: 6px; transform: translateX(-4px); }
.glide__go--next { right: 6px; transform: translateX(4px); }

.glide:hover .glide__go {
  opacity: 1;
  transform: none;
}

.glide__go:hover {
  background: rgba(9, 8, 6, 0.86);
}

.glide__go svg {
  width: 18px;
  height: 18px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
}

@media (hover: hover) and (min-width: 901px) {
  .glide__go {
    display: grid;
  }
}

/* ------------------------------------------------- «Вся лента» на телефоне

   На большом экране ссылка живёт в шапке экрана, рядом с заголовком,
   и там ей хорошо. На телефоне шапка переносит её на отдельную строку —
   и получается пустая полоса между заголовком и лентой, занятая одной
   кнопкой. Поэтому на телефоне ссылка переезжает на саму ленту,
   к правому краю: туда, куда полоса и уводит. */
.glide__more {
  display: none;
}

@media (max-width: 900px) {
  .glide__more {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    position: absolute;
    right: 8px;
    /* СВЕРХУ, А НЕ СНИЗУ. Внизу карточек лежат подписи — место
       и число дублей, — и таблетка садилась прямо на них: два разных
       текста друг на друге. Наверху над кадрами пусто. */
    top: 8px;
    z-index: 3;
    padding: 7px 12px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(9, 8, 6, 0.78);
    color: var(--text);
    font-size: 12.5px;
    text-decoration: none;
  }

  .glide__more:active {
    background: rgba(9, 8, 6, 0.94);
  }
}

/* Миниатюра съёмки в списке слева. Кадр обрезается по центру
   с лёгким сдвигом вверх: лицо в кадре обычно выше середины. */
.th--pic img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 30%;
  display: block;
  border-radius: inherit;
}

/* ==================================================
   МОИ ПУБЛИКАЦИИ
   ================================================== */

/* Три числа над лентой своих кадров. Ради них на вкладку и заходят,
   поэтому они крупные и стоят до самих кадров, а не под ними. */
.minesum {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}

.minesum__cell {
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
  display: grid;
  gap: 2px;
}

.minesum__cell b {
  font-size: 24px;
  font-weight: 500;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.minesum__cell span {
  font-size: 12.5px;
  color: var(--muted);
}

/* Убрать из ленты — действие обратного хода, и выглядеть как
   основное оно не должно. Красным тоже не красим: это не опасность,
   а обычная отмена показа. */
.fcard__go--drop {
  background: transparent;
  border-color: var(--line-2);
  color: var(--text-2);
}

.fcard__go--drop:hover {
  border-color: var(--danger);
  color: var(--text);
}

@media (max-width: 640px) {
  .minesum { grid-template-columns: 1fr; gap: 8px; }
  .minesum__cell { display: flex; align-items: baseline; gap: 10px; }
}

/* ==================================================
   ПРОФИЛЬ
   ================================================== */

/* Шапка публичного профиля: лицо, имя, числа. Порядок тот же, что
   в любой знакомой ленте, и это сознательно — узнаваемая раскладка
   не требует объяснений.

   ЭТИ ПРАВИЛА ЖИВЫ РАДИ ЧУЖОГО ПРОФИЛЯ. Свой собран заново
   (см. .phero ниже): там шапка сделана из собственных кадров
   человека. У чужого профиля их нет и быть не должно —
   только то, что автор показал сам. */
.phead {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 22px;
  align-items: center;
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--panel);
}

.phead__body {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.phead__line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 12px;
}

.phead__line h2 {
  margin: 0;
  font-size: 26px;
  font-weight: 500;
  letter-spacing: -0.02em;
}

.phead__sub {
  margin: 0;
  font-size: 13px;
  color: var(--muted);
}

.phead .pstats {
  padding: 0;
  border-top: 0;
  margin-top: 6px;
}

@media (max-width: 640px) {
  .phead {
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
    gap: 16px;
  }

  .phead__line { justify-content: center; }
  .phead .pstats { justify-content: center; gap: 18px; }
}

/* Числа в строку. Кликабельные — кнопки, остальные — просто текст,
   и внешне они не отличаются: подчёркивать разницу нечем, а вот
   курсор и подсветка при наведении её показывают. */
.pstats {
  display: flex;
  flex-wrap: wrap;
  gap: 26px;
  padding: 16px 22px 18px;
  border-top: 1px solid var(--line);
}

.pstat {
  display: grid;
  gap: 1px;
  padding: 0;
  border: 0;
  background: transparent;
  text-align: left;
  color: inherit;
}

button.pstat {
  cursor: pointer;
}

button.pstat:hover b {
  color: var(--lemon);
}

.pstat b {
  font-size: 21px;
  font-weight: 500;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  transition: color 0.18s var(--ease);
}

.pstat span {
  font-size: 12px;
  color: var(--muted);
}

.ava--big {
  width: 104px;
  height: 104px;
}

/* Правка имени: поле и ответ о занятости под ним. Ответ занимает
   место всегда, даже пустой, — иначе строка прыгает на каждую букву. */
.namebox {
  display: grid;
  gap: 4px;
  min-width: 0;
}

.namebox__say {
  min-height: 15px;
  font-size: 12px;
  color: var(--muted);
}

.namebox__say--yes { color: var(--good); }
.namebox__say--no { color: var(--danger); }

/* Крестик в окне кадра. Стоит там же, где крестики всех остальных
   окон сервиса, — в правом верхнем углу, и выглядит так же. */
.lightbox__x {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 3;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(13, 12, 10, 0.72);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--text-2);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease),
    transform 0.14s var(--ease);
}

.lightbox__x:hover {
  color: var(--text);
  border-color: var(--line-2);
}

.lightbox__x:active { transform: scale(0.92); }

/* ==================================================
   АВТОР КАДРА И ЕГО ПУБЛИЧНЫЙ ПРОФИЛЬ
   ================================================== */

/* Карточка автора в окне кадра. Стоит первой в правой колонке —
   до лайков и до «снять так же»: сначала кто, потом что. */
.pauthor {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px;
  margin-bottom: 4px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease);
}

.pauthor:hover {
  border-color: var(--line-2);
  transform: translateY(-1px);
}

/* Без профиля за спиной это просто строка: ни рамки, ни отклика,
   ни курсора — обещать дверь, которой нет, нельзя. */
.pauthor--flat {
  border-color: transparent;
  background: transparent;
  cursor: default;
  padding-left: 0;
}

.pauthor--flat:hover {
  border-color: transparent;
  transform: none;
}

.pauthor__ava {
  position: relative;
  width: 42px;
  height: 42px;
  flex: none;
  border-radius: 50%;
  overflow: hidden;
  background: #17150f;
  border: 1px solid var(--line-2);
  display: grid;
  place-items: center;
}

.pauthor__ava img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.pauthor__ava i {
  font-style: normal;
  font-size: 17px;
  color: var(--text-2);
}

.pauthor__body {
  display: grid;
  gap: 1px;
  min-width: 0;
}

.pauthor__body b {
  font-size: 14.5px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pauthor__body span {
  font-size: 12px;
  color: var(--muted);
}

/* Шапка публичного профиля — та же, что у своего, только без правок:
   человек узнаёт раскладку и не изучает её заново. */
.phead--public {
  margin-bottom: 22px;
}

.ava--flat {
  cursor: default;
}

.ava--flat:hover {
  transform: none;
}

/* Кадры автора выложены так же, как лента: он пришёл оттуда. */
.feed--person {
  margin-top: 4px;
}

/* ==================================================
   ГЛАВНАЯ: СТЕНА ИЗ РАБОТ
   ================================================== */

/* Первый экран. Не картинка с текстом рядом, а стена из настоящих
   кадров, за которой лежит одна фраза. Всё, что здесь движется, —
   работы живых людей: витрина и доказательство совпали. */
.wall {
  position: relative;
  /* Во всю ширину окна, а не по колонке текста: стена должна
     начинаться от края экрана, иначе это не стена, а картинка
     в рамке. Приём работает внутри любого центрированного
     контейнера и не требует ломать разметку. */
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-top: -18px;
  min-height: min(86vh, 760px);
  display: grid;
  place-items: center;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
}

.wall__grid {
  position: absolute;
  inset: -8% -2%;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
  pointer-events: none;
}

.wall__col {
  display: grid;
  gap: 10px;
  align-content: start;
  /* Каждая колонка едет со своей скоростью и в свою сторону:
     одинаковое движение читается как видео на фоне, разное —
     как живое место. Длительность и направление задаёт скрипт. */
  animation: wallride var(--dur, 30s) linear infinite;
  animation-direction: var(--way, normal);
}

.wall__col img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--r-md);
  display: block;
}

@keyframes wallride {
  /* Ровно на треть: колонка собрана из трёх одинаковых наборов,
     и к концу цикла второй набор стоит точно на месте первого. */
  to { transform: translateY(-33.333%); }
}

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

   ПЛОТНОСТЬ ПОДОБРАНА ТАК, ЧТОБЫ КАДРЫ БЫЛО ВИДНО. Первая попытка
   была почти непрозрачной — текст читался прекрасно, а стена за ним
   превращалась в чёрный прямоугольник, то есть исчезала ровно та
   вещь, ради которой всё делалось. */
.wall__veil {
  position: absolute;
  inset: 0;
  background:
    /* Пятно под текстом: густое ровно там, где буквы, и сходящее
       на нет к краям. */
    radial-gradient(
      46% 38% at 50% 44%,
      rgba(13, 12, 10, 0.9) 0%,
      rgba(13, 12, 10, 0.55) 60%,
      rgba(13, 12, 10, 0) 100%
    ),
    /* Общее приглушение и уход в фон страницы у нижнего края —
       чтобы стена не обрывалась линией, а растворялась. */
    linear-gradient(
      to bottom,
      rgba(13, 12, 10, 0.45),
      rgba(13, 12, 10, 0.25) 40%,
      rgba(13, 12, 10, 0.85) 92%,
      var(--bg) 100%
    );
  pointer-events: none;
}

.wall__say {
  position: relative;
  z-index: 2;
  max-width: 680px;
  padding: 40px 20px;
  text-align: center;
  display: grid;
  gap: 16px;
  justify-items: center;
}

.wall__say h1 {
  margin: 0;
  text-shadow: 0 2px 30px rgba(0, 0, 0, 0.75);
  font-size: clamp(36px, 6.4vw, 66px);
  line-height: 1.04;
  letter-spacing: -0.03em;
  font-weight: 500;
}

.wall__say p {
  margin: 0;
  max-width: 520px;
  text-shadow: 0 1px 16px rgba(0, 0, 0, 0.8);
  font-size: 16.5px;
  line-height: 1.55;
  color: var(--text-2);
}

.wall__say .acts {
  justify-content: center;
  margin-top: 4px;
}

.wall__down {
  position: absolute;
  bottom: 18px;
  left: 50%;
  margin-left: -8px;
  z-index: 2;
  color: var(--text-3);
  font-size: 18px;
  animation: nudge 2.4s ease-in-out infinite;
}

@keyframes nudge {
  0%, 100% { transform: translateY(0); opacity: 0.5; }
  50% { transform: translateY(6px); opacity: 1; }
}

/* Главное действие страницы. Заголовок крупнее обычного раздела:
   это не «ещё один блок», а то, ради чего сюда пришли. */
.pickme h2 {
  font-size: clamp(24px, 3.4vw, 34px);
}

/* Подпись на карточке витрины: что именно случится по нажатию. */
.hcard__take {
  position: absolute;
  inset: auto 8px 8px;
  z-index: 2;
  padding: 7px 10px;
  border-radius: 999px;
  background: var(--lemon-grad);
  color: #17130a;
  font-size: 12px;
  font-weight: 500;
  text-align: center;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.22s var(--ease), transform 0.22s var(--ease);
}

.hcard:hover .hcard__take,
.hcard:focus-visible .hcard__take {
  opacity: 1;
  transform: translateY(0);
}

/* Три шага одной строкой. Ни картинок, ни рамок: объяснять тут
   нечего, а прежние иллюстрации растягивали страницу на экран. */
.how3 {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}

.how3 li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--text-2);
}

.how3 b {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid var(--line-2);
  display: grid;
  place-items: center;
  font-size: 13px;
  font-weight: 500;
  color: var(--lemon);
}

/* На телефоне колонок меньше, а движение мешает читать заголовок —
   поэтому стена там спокойнее и ниже. */
@media (max-width: 900px) {
  .wall { min-height: 78vh; }
  .wall__grid { grid-template-columns: repeat(3, 1fr); }
  .how3 { grid-template-columns: 1fr; gap: 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .wall__col,
  .wall__down { animation: none; }
}

/* ==================================================
   КАДР ОТДЕЛЬНОЙ СТРАНИЦЕЙ (/p/<номер>)
   ================================================== */

/* Та же разметка, что и в окне, но живёт на странице: без жёсткой
   высоты окна и без чёрной подложки вокруг. */
.post--page {
  width: 100%;
  /* Высота задана, а не «по содержимому»: иначе вертикальный кадр
     растягивает страницу на два экрана, и всё, ради чего человек
     пришёл по ссылке — кнопка «Снять так же», — оказывается
     за сгибом.

     СТАЛО ВЫШЕ, КОГДА УБРАЛИ ЗАГОЛОВОК НАД КАДРОМ: освободившееся
     место отдано самому кадру, ради которого страница и открыта. */
  height: min(880px, 86vh);
  animation: none;
  margin-top: 0;
}

@media (max-width: 900px) {
  /* На телефоне колонки становятся строками, и жёсткая высота
     сплющила бы кадр. Здесь наоборот: кадр во всю ширину,
     действия под ним. */
  .post--page {
    height: auto;
  }

  .post--page .post__frame {
    aspect-ratio: 3 / 4;
  }
}

.plain--post {
  max-width: 1180px;
  margin: 0 auto;
  padding: 22px 20px 60px;
}

/* КРЕСТИК НА СТРАНИЦЕ НУЖЕН, И ТЕПЕРЬ ОСОБЕННО.
   Он был спрятан, пока над кадром стоял заголовок со стрелкой назад.
   Заголовок убрали — и вместе с ним исчезла единственная дорога
   в ленту для того, кто пришёл по прямой ссылке. Оставить человека
   на странице без выхода хуже, чем повторить подпись.

   Стрелка, а не крестик: «закрыть» здесь ничего не закрывает —
   страница ведёт назад, в ленту. */
.post--page .post__x {
  display: grid;
  place-items: center;
  left: 12px;
  right: auto;
  font-size: 15px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease);
}

.post--page .post__x:hover {
  background: rgba(20, 18, 15, 0.92);
  border-color: rgba(255, 255, 255, 0.24);
}

/* Ссылка вокруг кадра в карточке ленты. Она не должна ничего менять
   внешне: карточка и раньше была нажимаемой целиком. */
.fcard__link {
  display: block;
  line-height: 0;
}

/* ==================================================
   ТО, ЧТО ВИДЯТ РОБОТЫ

   Этот кусок сервер кладёт внутрь приложения, а скрипт затирает его
   первой отрисовкой. Человек успевает увидеть его на долю секунды
   при первой загрузке — поэтому он должен выглядеть как страница,
   а не как голый список.
   ================================================== */

.prerender {
  max-width: 1180px;
  margin: 0 auto;
  padding: 40px 20px;
  color: var(--text-2);
}

.prerender h1 {
  font-size: clamp(24px, 4vw, 38px);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--text);
  margin: 0 0 12px;
}

.prerender p {
  max-width: 640px;
  line-height: 1.55;
}

.prerender img {
  max-width: 100%;
  height: auto;
  border-radius: var(--r-md);
}

.prerender ul {
  list-style: none;
  margin: 22px 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 12px;
}

.prerender ul img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}

.prerender a {
  color: var(--lemon);
}

/* Пояснение под списком дублей: почему их меньше, чем в счётчике. */
.post__hint {
  margin: 10px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--muted);
}

/* ==========================================================================
   ВХОД — две колонки
   ==========================================================================

   Слева витрина, справа форма. Смысл разделения в том, что на этом
   экране человек решает не «куда нажать», а «доверять ли»: витрина
   отвечает на второй вопрос, пока форма ждёт ответа на первый.

   На телефоне колонки складываются в одну, и витрина ужимается
   до знака с заголовком: три экрана прокрутки до поля ввода —
   это отказ от входа, а не витрина. */

.gate2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 100vh;
  min-height: 100dvh;
}

/* --------------------------------------------------------------- витрина */

.gate2__show {
  position: relative;
  overflow: hidden;
  padding: 40px 48px 44px;
  display: flex;
  flex-direction: column;
  background: var(--rail);
  border-right: 1px solid var(--line);
}

/* Тёплое свечение из нижнего левого угла. Оно держит колонку тёплой,
   не осветляя её: ровная плашка рядом с фотографиями читается
   как пустое место. */
.gate2__show::before {
  content: "";
  position: absolute;
  left: -20%;
  bottom: -30%;
  width: 90%;
  padding-top: 90%;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(232, 185, 35, 0.13),
    rgba(232, 185, 35, 0) 68%
  );
  pointer-events: none;
}

.gate2__show > * {
  position: relative;
}

.gate2__brand {
  text-decoration: none;
  align-self: flex-start;
}

.gate2__brand .mark {
  font-size: 22px;
}

.gate2__head {
  margin: 26px 0 0;
  font-size: 42px;
  line-height: 1.06;
  letter-spacing: -0.03em;
  font-weight: 700;
}

.gate2__lede {
  margin: 16px 0 0;
  max-width: 30em;
  color: var(--text-2);
  font-size: 15.5px;
}

/* Кадры. Настоящие работы сервиса — единственное доказательство,
   которое здесь уместно. Проявляются по очереди и остаются. */
.gate2__strip {
  margin: 28px 0 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  max-width: 420px;
}

.gate2__strip img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--r);
  border: 1px solid var(--line-2);
  opacity: 0;
  transform: translateY(10px);
  animation: gateShot 0.9s var(--ease) forwards;
  animation-delay: var(--d, 0s);
}

@keyframes gateShot {
  to {
    opacity: 1;
    transform: none;
  }
}

.gate2__facts {
  margin: auto 0 0;
  padding: 26px 0 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
  font-size: 13px;
  color: var(--text-2);
}

.gate2__facts li {
  display: flex;
  align-items: center;
  gap: 8px;
}

.gate2__facts li::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--lemon);
  flex: none;
}

/* ------------------------------------------------------------- диафрагма */

/* Знак марки. Шестиугольное отверстие раскрывается, поворачивается
   на тридцать градусов и снова сходится — пять с половиной секунд
   на вдох и выдох.

   ПОЧЕМУ РАЗМЕР В EM. Знак живёт внутри марки, а марка стоит
   и в колонке (16px), и в шапке (21px), и на входе (22px). В em
   он подгоняется сам; в пикселях пришлось бы держать три правила
   и ошибиться в четвёртом месте.

   ПОЧЕМУ ГОРИТ ТОЛЬКО ОТВЕРСТИЕ. Первая сборка закрывала свет
   заслонкой цвета колонки — знак получался привязан к одному фону
   и на шапке выглядел тёмным пятном. Теперь светится ровно дыра,
   и знак ложится на любой фон. */

.iris {
  width: 1.55em;
  height: 1.55em;
  flex: none;
  display: block;
}

.iris svg {
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

.iris__light {
  fill: var(--lemon);
}

.iris__ring {
  fill: none;
  stroke: var(--line-2);
  stroke-width: 1.4;
}

.iris__edges {
  stroke: var(--line-2);
  stroke-width: 0.9;
  opacity: 0.5;
  animation: irisTurn 5.6s var(--ease) infinite;
}

.iris__hole {
  animation: irisOpen 5.6s var(--ease) infinite;
}

/* Закрыто — открыто — закрыто. Задержка в конце нужна, чтобы петля
   читалась как дыхание, а не как мигание. */
@keyframes irisOpen {
  0%,
  10% {
    transform: scale(0.04) rotate(0deg);
  }
  45%,
  70% {
    transform: scale(0.62) rotate(30deg);
  }
  100% {
    transform: scale(0.04) rotate(0deg);
  }
}

@keyframes irisTurn {
  0%,
  10% {
    transform: rotate(0deg);
  }
  45%,
  70% {
    transform: rotate(30deg);
  }
  100% {
    transform: rotate(0deg);
  }
}

/* Кому движение мешает — тому его нет: диафрагма замирает открытой,
   кадры показываются сразу. */
@media (prefers-reduced-motion: reduce) {
  .iris__hole,
  .iris__edges {
    animation: none;
  }

  .iris__hole {
    transform: scale(0.62) rotate(30deg);
  }

  .gate2__strip img {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

/* ----------------------------------------------------------------- форма */

.gate2__side {
  display: flex;
  flex-direction: column;
  padding: 40px 48px 48px;
  background: var(--bg);
}

.gate2__back {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text-2);
  text-decoration: none;
}

.gate2__back span {
  transition: transform 0.2s var(--ease);
}

.gate2__back:hover {
  color: var(--text);
}

.gate2__back:hover span {
  transform: translateX(-3px);
}

.gate2__card {
  width: 100%;
  max-width: 380px;
  margin: auto;
  padding: 30px 0;
}

.gate2__title {
  margin: 22px 0 0;
  font-size: 27px;
  letter-spacing: -0.02em;
}

.gate2__sub {
  margin: 10px 0 0;
  color: var(--text-2);
  font-size: 14px;
}

.gate2 .gate__form {
  margin-top: 22px;
}

/* Шаги. Стоят на месте переключателя «вход / регистрация» — и в той же
   форме таблетки, потому что глаз ищет её именно здесь. */
.gsteps {
  display: flex;
  gap: 4px;
  padding: 4px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 999px;
}

.gsteps__i {
  flex: 1;
  text-align: center;
  padding: 8px 6px;
  border-radius: 999px;
  font-size: 13px;
  color: var(--text-3);
  white-space: nowrap;
  transition: color 0.25s var(--ease), background 0.25s var(--ease);
}

.gsteps__i.was {
  color: var(--text-2);
}

.gsteps__i.on {
  background: var(--bg);
  color: var(--text);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
}

/* ------------------------------------------------------------- телефоны */

@media (max-width: 900px) {
  .gate2 {
    grid-template-columns: 1fr;
    min-height: 0;
  }

  .gate2__show {
    border-right: 0;
    border-bottom: 1px solid var(--line);
    padding: 22px 20px 26px;
  }

  .gate2__head {
    font-size: 30px;
    margin-top: 18px;
  }

  .gate2__lede {
    font-size: 14.5px;
  }

  /* Кадры и факты на телефоне убраны: до поля ввода должно остаться
     одно движение пальцем, а не четыре. */
  .gate2__strip,
  .gate2__facts {
    display: none;
  }

  /* ЗДЕСЬ СТОЯЛ РАЗМЕР ЗНАКА В ПИКСЕЛЯХ — и это была ошибка на весь
     сайт. Правило осталось от той поры, когда диафрагма была отдельной
     картинкой на странице входа. Потом знак переехал внутрь марки
     и стал меряться в em от её кегля, а это правило продолжало
     действовать — и на КАЖДОМ телефоне раздувало его до 54 пикселей
     рядом с шестнадцатипиксельным именем. Марка выглядела склеенной
     из двух разных логотипов: в шапке, в колонке, в шторке. */

  .gate2__side {
    padding: 18px 20px 40px;
  }

  .gate2__card {
    max-width: none;
    padding: 18px 0 0;
  }

  .gate2__title {
    font-size: 23px;
  }
}

/* ==========================================================================
   СЪЁМКА БЕЗ ВЫБОРА — оформление нового рабочего стола
   ==========================================================================

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

/* На рабочем столе зона НЕ во весь экран. Базовая рамка съёмки имеет
   пропорцию 4:3 — там она стоит на месте будущего кадра и правильно
   делает. Здесь на её месте кадра не будет: зона только принимает
   файл, и полэкрана пустоты вокруг двух строк текста читается как
   недогруженная страница. */
.drop--desk {
  margin-top: 4px;
  aspect-ratio: auto;
  padding: 34px 24px 30px;
  border-radius: var(--r-lg);
  /* Тёплое свечение сверху: ровная плашка на тёмном фоне читается
     как пустое место, а не как приглашение. Свет падает оттуда же,
     откуда во всём интерфейсе, — сверху. См. --lemon-glow. */
  background: var(--lemon-glow), var(--panel);
}

.drop--desk b {
  font-size: 20px;
  letter-spacing: -0.02em;
}

.drop__ic {
  width: 52px;
  height: 52px;
  margin-bottom: 14px;
  border-radius: 16px;
  background: var(--line);
  display: grid;
  place-items: center;
  color: var(--lemon);
}

.drop__ic svg {
  width: 25px;
  height: 25px;
}

/* Обещание под заголовком. Отвечает на единственный вопрос, который
   остаётся у человека перед зоной загрузки: «а дальше что спросят?» */
.drop__sub {
  display: block;
  margin-top: 7px;
  color: var(--text-2);
  font-size: 14px;
}

/* Фотосессия под зоной. Не кнопка и не плитка: строка. */
.hint--after {
  margin-top: 14px;
  text-align: center;
  font-size: 13.5px;
}

.hint--after .linkish {
  font-size: inherit;
  color: var(--text);
  border-bottom: 1px solid var(--line-2);
}

/* -------------------------------------------------- значки левой колонки */

/* Знаки из шрифта (▤ ▦) выглядели по-разному в каждой системе,
   а на Windows часть из них — пустой прямоугольник. */
.ri__glyph .gl {
  width: 17px;
  height: 17px;
  display: block;
}

.ri__glyph {
  display: grid;
  place-items: center;
  width: 17px;
  height: 17px;
}

/* ------------------------------------------------ что именно снимаем */

/* Человек ничего не выбирал, и тревога у него ровно одна: «а что там
   будет?». Плашка отвечает до того, как вопрос задан. */
.note--picked {
  align-items: center;
  border-color: var(--line-2);
  background: var(--panel);
}

.note--picked b {
  display: block;
  font-size: 14.5px;
  letter-spacing: -0.01em;
}

.note__why {
  display: block;
  margin-top: 2px;
  color: var(--text-2);
  font-size: 12.5px;
}

@media (max-width: 900px) {
  .drop--desk {
    padding: 24px 16px 22px;
  }

  .drop--desk b {
    font-size: 17px;
  }
}

/* ==========================================================================
   СПИСОК СЪЁМОК — разбор по дням и вторая строка
   ==========================================================================

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

   На телефоне он же открывается шторкой и служит единственным способом
   вернуться к съёмке, поэтому там строки крупнее: палец не попадает
   в строку высотой в тридцать пикселей. */

.ri--row {
  align-items: flex-start;
  padding: 7px 8px;
}

.ri__body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  flex: 1;
}

.ri__sub {
  font-size: 11.5px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Идущая съёмка подписана словом, а не только кружком: «снимается»
   читается сразу, а точка требует, чтобы её объяснили. */
.ri--row.on .ri__sub {
  color: var(--text-2);
}

/* Заголовок дня. Не строка списка, а метка над ним: тише, мельче
   и моноширинным — это данные, а не речь. */
/* ДЕНЬ — ПОДПИСЬ ВНУТРИ СПИСКА, А НЕ ЕГО НАЗВАНИЕ.
   Он выглядел ровно как заголовок «Съёмки» над ним: тот же
   моноширинный, те же заглавные, тот же цвет. Два одинаковых слова
   подряд читаются как одно, и было непонятно, где кончилась шапка
   раздела и начался сам список.

   Теперь разница в двух вещах сразу: день мельче и с точкой-меткой
   слева, а название раздела — обычным шрифтом и светлее. */
.ri__day {
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
  padding: 14px 8px 5px;
}

.ri__day::before {
  content: "";
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--line-2);
  flex: none;
}

.ri__day:first-child {
  padding-top: 2px;
}

/* Пустое место предлагает действие. «Пока пусто» не предлагало ничего. */
.ri--empty {
  display: block;
  color: var(--text-3);
  font-size: 12.5px;
  line-height: 1.45;
  padding: 10px 8px;
  border: 1px dashed var(--line-2);
  border-radius: 10px;
  cursor: pointer;
}

.ri--empty:hover {
  color: var(--text-2);
  border-color: var(--text-3);
}

/* -------------------------------------------------------- на телефоне */

@media (max-width: 900px) {
  /* Шторка съёмок — единственный способ вернуться к работе с телефона,
     и она обязана быть удобной пальцу, а не мышке. */
  .ri--row {
    padding: 9px 10px;
    border-radius: 12px;
  }

  .ri--row .th--pic {
    width: 40px;
    height: 46px;
    border-radius: 8px;
  }

  .ri--row .th {
    width: 32px;
    height: 32px;
    border-radius: 8px;
  }

  .ri__name {
    font-size: 14.5px;
  }

  .ri__sub {
    font-size: 12px;
  }

  .ri__day {
    font-size: 10px;
    padding: 14px 10px 6px;
  }

  /* Действия со строкой на телефоне видны всегда: наведения там нет,
     а «закрепить» и «убрать» иначе недостижимы вовсе. */
  .ri__acts {
    opacity: 1;
  }
}

/* Значки в полосе разделов на телефоне. Размер тот же, что был
   у знаков из шрифта, — полоса не должна подрасти из-за смены набора. */
.tab .ic .gl {
  width: 20px;
  height: 20px;
  display: block;
}

.tab .ic {
  display: grid;
  place-items: center;
  height: 20px;
}

/* ==========================================================================
   ШТОРКА СЪЁМОК НА ТЕЛЕФОНЕ — та же колонка, но под палец
   ==========================================================================

   Колонка и шторка — одна и та же разметка, и это правильно: два
   списка съёмок однажды разойдутся. Но размеры у них разные, потому
   что разное управление: мышь попадает в строку тринадцатым кеглем,
   палец — нет. */

.rail-head {
  display: flex;
  align-items: center;
  gap: 10px;
}

.rail-head .brand {
  flex: 1;
  min-width: 0;
}

/* Крестик живёт только в шторке: в браузере колонка никуда
   не задвигается, и закрывать её нечем. */
.rail-close {
  display: none;
}

@media (max-width: 900px) {
  /* ВЕРХ ШТОРКИ УХОДИТ ПОД ЧАСЫ. Страница объявлена во весь экран,
     и без этого запаса марка на iPhone оказывалась под вырезом. */
  .rail {
    padding-top: calc(16px + env(safe-area-inset-top, 0px));
  }

  .rail-close {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    flex: none;
    border: 1px solid var(--line);
    border-radius: 11px;
    background: transparent;
    color: var(--text-2);
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
  }

  .rail-close:active {
    background: var(--panel);
    color: var(--text);
  }

  /* Разделы — такой же рост, что и строки съёмок ниже: один список
     не может быть наполовину мелким. */
  .rail-sec .ri {
    padding: 11px 10px;
    border-radius: 12px;
    font-size: 15px;
  }

  .rail-sec .ri__glyph,
  .rail-sec .ri__glyph .gl {
    width: 20px;
    height: 20px;
  }

  .rail-btn {
    padding: 13px 14px;
    font-size: 15px;
    border-radius: 14px;
  }

  /* Подпись «Съёмки» над списком — та же метка, что и заголовки дней
     внутри него. Раньше она была крупнее и спорила с ними за старшинство. */
  .rail .lab {
    font-size: 12.5px;
  }
}

/* Значки в действиях строки и в пустых состояниях. Один набор, одна
   толщина обводки — вместо смайлов, которые в каждой системе
   рисуются по-своему и задают экрану случайный тон. */
.ri__act .gl {
  width: 14px;
  height: 14px;
  display: block;
}

.ri__act {
  display: grid;
  place-items: center;
}

.empty .ic .gl {
  width: 30px;
  height: 30px;
  display: block;
  stroke: var(--text-3);
}

.empty .ic {
  display: grid;
  place-items: center;
}

/* Метка отметок на телефоне. Наведения там нет, а понимать, что кадры
   живые и их смотрят, человеку нужно так же. Угловая, мелкая, поверх
   кадра — она не спорит со снимком, но и не пропадает. */
@media (hover: none), (max-width: 900px) {
  .fcard__mini {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    position: absolute;
    left: 8px;
    bottom: 8px;
    z-index: 2;
    padding: 3px 8px 3px 6px;
    border-radius: 999px;
    /* БЕЗ РАЗМЫТИЯ ФОНА, И ЭТО НЕ ПРИДИРКА К КРАСОТЕ.
       backdrop-filter на КАЖДОЙ карточке длинного списка ломает
       Safari на iPhone: при прокрутке кадры под такими метками
       перестают рисоваться — экран остаётся пустым. Владелец поймал
       это на первом же свайпе 01.09.2026; на Android того же не было.
       Плотной подложки здесь достаточно: метка лежит поверх
       фотографии, и читаемость даёт непрозрачность, а не блюр. */
    background: rgba(9, 8, 6, 0.72);
    font-family: var(--mono);
    font-size: 11px;
    color: var(--text);
    pointer-events: none;
  }

  .fcard__mini svg {
    width: 12px;
    height: 12px;
  }

  /* На телефоне карточка не поднимается и не отбрасывает тень:
     поднимать нечего — палец не «наводится», он нажимает. */
  .fcard:hover {
    transform: none;
    box-shadow: none;
  }
}

/* Что на кадре: место и характер словами. Стоит сразу под автором
   и над главным действием — это ответ на вопрос «что я смотрю»,
   и он должен прийти раньше, чем цена. */
.post__what {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}

.post__what b {
  font-size: 17px;
  letter-spacing: -0.015em;
}

.post__what span {
  color: var(--text-2);
  font-size: 13px;
}

/* Счётчики уехали под кнопку и стали тише: они больше не первое,
   что читает человек, пришедший по ссылке. */
.post__acts {
  border-top: 1px solid var(--line);
  padding-top: 14px;
}

/* ==========================================================================
   ГАЛЕРЕЯ — по дням, серия одной карточкой
   ==========================================================================

   Была сетка одинаковых квадратов без разбора по времени: найти
   вчерашний кадр можно было только глазами, а один день с фотосессией
   вытеснял с первого экрана всё остальное. */

/* Заголовок дня. Тот же вид, что у заголовков в списке съёмок слева:
   одна и та же мысль на двух экранах должна выглядеть одинаково. */
.works__day {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
  margin: 26px 0 10px;
}

.works__day:first-child {
  margin-top: 6px;
}

/* Карточка серии. Стопка под обложкой — два псевдоэлемента со сдвигом:
   это и есть весь приём. Она говорит «здесь не один кадр» раньше,
   чем человек прочтёт счётчик. */
.work--set {
  position: relative;
  cursor: pointer;
  /* Стопка торчит из-под карточки, и обрезать её нельзя. Скругление
     переезжает на сам кадр — иначе он остался бы с прямыми углами. */
  overflow: visible;
}

.work--set img {
  border-radius: var(--r);
}

.work--set::before,
.work--set::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--panel);
  border: 1px solid var(--line);
  z-index: -1;
}

.work--set::before {
  transform: translate(7px, 7px);
}

.work--set::after {
  transform: translate(3.5px, 3.5px);
}

/* Стопке нужно место справа и снизу, иначе она уезжает под соседа. */
.works:has(.work--set) {
  padding-right: 8px;
  padding-bottom: 8px;
}

.work__count {
  position: absolute;
  right: 8px;
  bottom: 8px;
  z-index: 2;
  padding: 4px 9px;
  border-radius: 999px;
  /* Без размытия по той же причине, что и метка в ленте: галерея —
     такой же длинный прокручиваемый список. */
  background: rgba(9, 8, 6, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.1);
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--text);
  pointer-events: none;
}

.work--set:hover .work__count {
  background: rgba(9, 8, 6, 0.9);
}

/* Раскрытые кадры серии. Появляются на месте стопки, в той же сетке,
   и коротко подсвечиваются — иначе непонятно, что именно изменилось
   на экране, где и до нажатия были кадры. */
.work--of-set {
  animation: setOpen 0.32s var(--ease);
}

@keyframes setOpen {
  from {
    opacity: 0;
    transform: scale(0.96);
  }
}

@media (prefers-reduced-motion: reduce) {
  .work--of-set {
    animation: none;
  }
}

/* Сводка над вкладкой «Моё». Одна строка из трёх чисел: «Моё» —
   единственное место, где человек видит свои кадры глазами других,
   и спрашивают там обычно не «что я выложил», а «заметили ли». */
.minesum {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 18px;
  margin: 2px 0 16px;
  font-size: 13px;
  color: var(--text-2);
}

.minesum b {
  font-family: var(--mono);
  font-weight: 500;
  color: var(--text);
  margin-right: 4px;
}

/* Про убранные кадры сказано отдельно и тише: без этого цифры
   не сходятся с тем, что видно на экране, и это выглядит ошибкой. */
.minesum__off {
  color: var(--text-3);
  font-size: 12.5px;
}

.minesum--empty {
  margin: 2px 0 16px;
  max-width: 56ch;
  color: var(--text-2);
  font-size: 13.5px;
}

/* ==========================================================================
   СЧЁТ — сколько осталось и куда ушло
   ==========================================================================

   Раньше баланс был одной из трёх одинаковых плиток и весил столько же,
   сколько справочное «сделано кадров». Теперь он один и крупный,
   рядом — пакеты, ниже — история. */

.money {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 28px;
  margin-bottom: 30px;
}

/* Знак валюты мельче числа: он подпись, а не величина. В один кегель
   с числом лимон выходил крупнее всего на экране и перетягивал
   на себя тот самый взгляд, ради которого баланс и сделан большим. */
.money__v i {
  font-style: normal;
  font-size: 0.6em;
  margin-right: 0.28em;
  vertical-align: 0.12em;
}

.money__v {
  font-family: var(--mono);
  font-size: 44px;
  font-weight: 500;
  letter-spacing: -0.03em;
  color: var(--lemon);
  line-height: 1.05;
  margin-top: 6px;
}

.money__enough {
  margin-top: 8px;
  color: var(--text-2);
  font-size: 14px;
}

/* Справочные числа. Видны, но не спорят с балансом за внимание. */
.money__past {
  margin-top: 4px;
  color: var(--text-3);
  font-size: 12.5px;
}

.money__past b {
  font-family: var(--mono);
  font-weight: 500;
  color: var(--text-2);
}

.money__packs {
  display: flex;
  gap: 10px;
}

.pack {
  display: grid;
  gap: 2px;
  padding: 13px 16px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  background: transparent;
  color: var(--text);
  cursor: pointer;
  text-align: center;
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}

.pack:hover {
  border-color: var(--text-3);
  background: var(--panel);
}

/* Выгодный пакет отмечен рамкой, а не заливкой: заливка сделала бы
   его кнопкой главного действия, а главное действие на этом экране —
   не «купить побольше», а «понять, сколько осталось». */
.pack--best {
  border-color: var(--lemon);
  background: rgba(232, 185, 35, 0.06);
}

.pack__n {
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 500;
}

.pack__p {
  font-size: 13px;
  color: var(--text-2);
}

.pack__save {
  font-size: 11px;
  color: var(--text-3);
}

.pack--best .pack__save {
  color: var(--lemon);
}

@media (max-width: 900px) {
  .money {
    grid-template-columns: 1fr;
    align-items: start;
    gap: 20px;
  }

  .money__v {
    font-size: 38px;
  }

  .money__packs {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
  }

  .pack {
    padding: 11px 8px;
  }
}

/* Шапка без заголовка: остаётся только стрелка назад и действия
   справа. Нужна там, где имя экрана и так стоит ниже крупно —
   на публичном профиле. Повторять его дважды через двадцать
   пикселей значит просить прочитать одно и то же. */
.canvas-head--bare {
  margin-bottom: -6px;
}


/* Кому движение мешает — тому его нет: карточка просто на месте. */
@media (prefers-reduced-motion: reduce) {
  .fcard {
    animation: none;
  }
}

/* НА ТЕЛЕФОНЕ ПОЯВЛЕНИЯ НЕТ ВОВСЕ.
   Два десятка карточек, каждая со своим слоем и своей анимацией, —
   и Safari на iPhone при прокрутке начинает пересобирать слои:
   кадры мигают, то пропадая, то возвращаясь. Владелец поймал это
   на первом же прокруте 01.09.2026.

   Анимация появления — украшение, и на устройстве, где она стоит
   мигания, её просто нет. На большом экране, где слоёв меньше
   и памяти больше, она остаётся. */
@media (hover: none), (max-width: 900px) {
  .fcard {
    animation: none;
  }
}


/* «Вся лента» в шапке экрана — только на большом экране: на телефоне
   она живёт на самой полосе.

   СЕЛЕКТОР С ШАПКОЙ, А НЕ ОДИН КЛАСС. Правило `.rgt--wide` проигрывало
   по весу правилу `.canvas-head .rgt`, которое ставит display: flex, —
   и кнопка на телефоне так и оставалась отдельной строкой между
   заголовком и лентой, ради избавления от которой всё и делалось. */
@media (max-width: 900px) {
  .canvas-head .rgt--wide {
    display: none;
  }
}


/* Название раздела в левой колонке. Не моноширинная метка, как даты
   внутри списка, а обычная строка: она называет раздел, а не
   подписывает данные. Разница нужна затем, чтобы «Съёмки» и «Сегодня»
   перестали читаться как две строки одного вида. */
.rail .lab {
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-2);
  font-weight: 500;
  padding: 2px 8px 4px;
  border-top: 1px solid var(--line);
  margin-top: 4px;
  padding-top: 12px;
}

/* ==========================================================================
   ЭКРАН ОЖИДАНИЯ — отчёт вместо спиннера
   ==========================================================================

   Тридцать секунд перед крутящимся кружком — это тридцать секунд,
   за которые человек успевает передумать. Экран обязан всё это время
   говорить: что снимаем, сколько осталось и что вкладку можно закрыть. */

.wait {
  display: grid;
  gap: 7px;
}

.wait__bar {
  height: 4px;
  border-radius: 3px;
  background: var(--panel);
  overflow: hidden;
}

/* ДО КОНЦА ПОЛОСА НЕ ДОХОДИТ НИКОГДА — см. waitBar в app.js.
   Она останавливается у девяноста процентов и ждёт настоящего кадра:
   полоса, добежавшая до края при неготовой съёмке, — прямая ложь. */
.wait__bar i {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: var(--lemon-grad);
  transition: width 1s linear;
}

.wait__say {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text-3);
  letter-spacing: 0.04em;
}

/* Полоса чужих кадров под ожиданием. Уже без подписей на карточках:
   здесь они не нужны — это фон ожидания, а не витрина. */
.glide--wait {
  margin-top: 26px;
  /* Стрелки стоят по краям полосы и отсчитываются от неё. */
  position: relative;
}

/* Подпись над полосой — не часть окна прокрутки, и стрелки не должны
   считать её высоту своей: иначе они уезжают выше кадров. */
.glide--wait .glide__go {
  top: calc(50% + 13px);
}

.glide--wait .gcard {
  width: 128px;
}

.glide--wait .lab {
  margin-bottom: 10px;
}

/* ==========================================================================
   ГОТОВЫЙ КАДР — «до» слева, работа в центре, действия справа
   ==========================================================================

   Экран показывал один большой кадр, а под ним двумя рядами шли
   действия: половину не было видно без прокрутки, а названия описывали
   положение вещей, а не действие. Сравнить кадр с исходником было
   нельзя вовсе — исходник жил только в памяти вкладки.

   ПОЧЕМУ РАЗМЕРЫ РАЗНЫЕ. «До» — справка, «после» — работа. Одинаковые
   прямоугольники рядом читаются как две равные картинки, и глаз
   не понимает, какая из них результат. */

.done {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr) 268px;
  gap: 20px;
  align-items: start;
  margin-top: 6px;
}

/* Съёмка без сохранённого исходника: колонки «до» нет вовсе,
   и место под неё не резервируется. */
.done--alone {
  grid-template-columns: minmax(0, 1fr) 268px;
}

.done__before {
  display: grid;
  gap: 12px;
}

.bshot {
  margin: 0;
  cursor: zoom-in;
}

.bshot img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--r);
  border: 1px solid var(--line);
  display: block;
  transition: border-color 0.18s var(--ease);
}

.bshot:hover img {
  border-color: var(--line-2);
}

.bshot figcaption,
.done__main figcaption {
  margin-top: 6px;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
  text-align: center;
}

.done__main {
  margin: 0;
  cursor: zoom-in;
}

.done__main img {
  width: 100%;
  max-height: 74vh;
  object-fit: contain;
  border-radius: var(--r-md);
  background: #080705;
  display: block;
}

/* ------------------------------------------------------------- действия */

.done__acts {
  display: grid;
  gap: 10px;
  align-content: start;
}

.done__why {
  margin: -2px 0 0;
  font-size: 12px;
  color: var(--text-3);
  line-height: 1.45;
}

/* Кнопка с пояснением второй строкой: название говорит, что случится,
   пояснение — что при этом останется прежним. */
.done__next {
  display: grid;
  gap: 8px;
  margin-top: 8px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.done__next .b {
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 10px 13px;
  text-align: left;
}

.done__next .b span {
  font-size: 11.5px;
  font-weight: 400;
  color: var(--text-3);
}

.done__inled {
  display: grid;
  gap: 4px;
  padding: 12px 13px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
}

.done__inled b {
  font-size: 13.5px;
}

.done__inled span {
  font-size: 12px;
  color: var(--text-3);
}

.done__inled .b {
  margin-top: 8px;
}

.done__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}

/* --------------------------------------------------------------- окно */

/* Окно с кадром во весь экран.
 *
 * КАДР ОБЯЗАН ПОМЕЩАТЬСЯ ЦЕЛИКОМ. Сначала здесь стояло
 * `max-height: 100%`, и это не работало: у затемнения включена
 * прокрутка, ячейка сетки растёт под содержимое, и сотня процентов
 * отсчитывалась от самой картинки — то есть ни от чего. Вертикальный
 * кадр вылезал за экран, и приходилось листать, чтобы увидеть
 * собственное лицо.
 *
 * Отсчёт от ОКНА, а не от ячейки: 92 процента высоты экрана
 * и 94 ширины — с запасом на крестик и поля. Прокрутки нет вовсе:
 * прокручивать нечего. */
.scrim--zoom {
  display: grid;
  place-items: center;
  padding: clamp(12px, 3vw, 32px);
  background: rgba(6, 5, 4, 0.94);
  cursor: zoom-out;
  overflow: hidden;
  /* Пальцем по такому окну увеличивают — и мешать этому нельзя. */
  touch-action: pinch-zoom;
}

.scrim--zoom img {
  max-width: 94vw;
  max-height: 92dvh;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--r);
  cursor: default;
}

@media (max-width: 700px) {
  .scrim--zoom {
    padding: 10px;
  }

  .scrim--zoom img {
    max-width: 100vw;
    /* Крестик стоит сверху, и кадр не должен уходить под него. */
    max-height: 86dvh;
    border-radius: var(--r-sm);
  }

  .zoom__x {
    top: max(12px, env(safe-area-inset-top, 0px));
    right: 12px;
    width: 36px;
    height: 36px;
  }
}

.zoom__x {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-2);
  border-radius: 50%;
  background: rgba(9, 8, 6, 0.7);
  color: var(--text);
  font-size: 15px;
  cursor: pointer;
}

/* ------------------------------------------------------------- телефон */

@media (max-width: 1100px) {
  .done {
    grid-template-columns: 108px minmax(0, 1fr);
  }

  /* Действия уходят под кадр во всю ширину: втискивать третью колонку
     в тысячу пикселей значит сделать нечитаемыми все три. */
  .done__acts {
    grid-column: 1 / -1;
  }
}

@media (max-width: 700px) {
  .done {
    grid-template-columns: 1fr;
    gap: 14px;
  }

  /* На телефоне «до» встаёт в ряд под кадром: сбоку от него места нет,
     а сравнивать всё равно нужно. */
  .done__before {
    grid-row: 2;
    grid-auto-flow: column;
    justify-content: start;
    gap: 10px;
  }

  .bshot img {
    width: 84px;
  }

  .done__main img {
    max-height: 62vh;
  }
}

/* ==========================================================================
   ТОНКАЯ НАСТРОЙКА — свёрнута, но всё на месте
   ==========================================================================

   Три блока настроек стояли раскрытыми всегда: четыре цветных
   прямоугольника «характера», три пустых прямоугольника «формата»
   и галочка 4K. На телефоне это два экрана прокрутки между выбором
   места и кнопкой съёмки — и всё до того, как человек увидел хоть
   один свой кадр. */

.tune {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
}

/* НАСТРОЙКИ РАСКРЫТЫ ВСЕГДА.
   Сворачивание было попыткой убрать с экрана то, что человеку
   всё-таки нужно: свет и формат — не «дополнительно», а часть
   решения о съёмке. Свёрнутый блок заставлял открывать его каждый
   раз, а строка «тёплое · вертикальный» под заголовком дублировала
   то, что и так видно внутри, стоило блоку открыться. */
.tune__head {
  padding: 12px 14px 2px;
}

.tune__t {
  font-size: 13.5px;
  font-weight: 500;
}

.tune__body {
  display: grid;
  gap: 14px;
  padding: 2px 14px 14px;
}

.tune__body .lab--tight {
  margin-bottom: 2px;
}

/* Чего не хватает прямо сейчас. На месте бывших точек «шаг 1 из 3»,
   которые считали не шаги, а настройки: настоящего порядка на экране
   нет, а счётчик обещал процедуру. */
.todo:not(:empty) {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  font-size: 12px;
  color: var(--text-2);
  white-space: nowrap;
}

.todo:not(:empty)::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--lemon);
  flex: none;
}

/* ==========================================================================
   ДВЕ ДОРОГИ РЯДОМ С БЫСТРОЙ СЪЁМКОЙ
   ==========================================================================

   Под зоной загрузки была одна строка мелким шрифтом — «или соберите
   фотосессию». Фотосессия стоит пятнадцать лимонов и составляет
   половину сервиса, а выглядела сноской. Входа в съёмку с выбором
   места не было вовсе.

   Карточки равны по весу и подписаны тем, что человек получит. */

.ways {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 14px;
}

.way {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 15px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  /* Тёплый отсвет из левого верхнего угла — оттуда же, откуда падает
     свет на кнопках и панелях. Он и отделяет карточку от чёрного
     фона: рамка на чёрном по чёрному не читается. */
  background:
    radial-gradient(130% 120% at 0% 0%, rgba(232, 185, 35, 0.07), rgba(232, 185, 35, 0) 58%),
    var(--panel);
  color: var(--text);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.18s var(--ease), transform 0.18s var(--ease),
    background 0.18s var(--ease);
}

.way:hover {
  border-color: var(--line-2);
  transform: translateY(-2px);
  background:
    radial-gradient(130% 120% at 0% 0%, rgba(232, 185, 35, 0.12), rgba(232, 185, 35, 0) 58%),
    var(--panel);
}

.way__ic {
  width: 40px;
  height: 40px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: var(--r);
  background: var(--line);
  color: var(--lemon);
}

.way__ic svg {
  width: 21px;
  height: 21px;
}

.way__body {
  display: grid;
  gap: 3px;
  min-width: 0;
}

.way__body b {
  font-size: 15px;
  letter-spacing: -0.01em;
}

.way__body span {
  font-size: 12.5px;
  color: var(--text-2);
  line-height: 1.4;
}

.way__go {
  margin-left: auto;
  color: var(--text-3);
  font-size: 16px;
  transition: transform 0.18s var(--ease), color 0.18s var(--ease);
}

.way:hover .way__go {
  color: var(--lemon);
  transform: translateX(3px);
}

@media (max-width: 700px) {
  .ways {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .way {
    padding: 13px 14px;
  }
}

/* ==========================================================================
   ПОЛЯ ВВОДА НА ТЕЛЕФОНЕ — НЕ МЕЛЬЧЕ ШЕСТНАДЦАТИ ПИКСЕЛЕЙ
   ==========================================================================

   ЧТО ПРОИСХОДИЛО. Человек открывал страницу входа, касался поля
   «номер телефона» — и Safari САМ увеличивал страницу: так он поступает
   с любым полем, где текст мельче шестнадцати пикселей, «чтобы было
   видно, что набираешь». Обратно он не отдаляет никогда. Дальше вся
   работа шла на увеличенной странице: сайт не помещался в экран,
   и его приходилось отводить пальцами. Обновления страницы при этом
   не происходит — приложение одностраничное, — поэтому увеличение
   переезжало с человеком с экрана на экран, и выглядело это так, будто
   размер окна теряют сами экраны. Владелец поймал это на аккаунте
   Anton 05.09.2026 и связал с проводником: тот как раз ведёт через
   вход, где стоит первое поле.

   ПОЧЕМУ НЕ ПРОСТО ЗАПРЕТИТЬ УВЕЛИЧЕНИЕ. `user-scalable=no` в мета-теге
   убрало бы и это, и возможность рассмотреть кадр пальцами. Отнимать
   у человека зум ради своей вёрстки нельзя — тем более в сервисе,
   который показывает фотографии.

   ШЕСТНАДЦАТЬ ПИКСЕЛЕЙ — ЭТО НЕ ХУЖЕ. На телефоне поле и должно быть
   крупнее: в него целятся пальцем и в него смотрят, пока набирают.
   На большом экране всё остаётся как было. */

@media (max-width: 900px) {
  .input,
  .composer textarea,
  input,
  select,
  textarea {
    font-size: 16px;
  }
}

/* ==========================================================================
   ЭКРАН РОВНО В ОКНО · 03.09.2026
   ==========================================================================

   ЗАЧЕМ. Три экрана сервиса — рабочий стол, съёмка одного кадра
   и фотосессия — устроены одинаково: человек ВЫБИРАЕТ, глядя сразу
   на всё. Выбор, цена и кнопка обязаны быть перед глазами
   одновременно; выбирать вслепую и искать кнопку прокруткой — это
   две разные беды одной причины. Раньше все три экрана были длиннее
   окна: на ноутбуке зона загрузки на рабочем столе начиналась ниже
   сгиба, а на съёмке под сгиб уезжала кнопка «Снять кадр».

   КАК УСТРОЕНО. Холст занимает высоту окна и сам не прокручивается.
   Прокручиваются внутри него только те части, которым не хватило
   места: плитки мест и настройки в правой панели. Так на маленьком
   экране ничего не пропадает — оно просто становится короче.

   ПОЧЕМУ НЕ ВЕЗДЕ. Лента, галерея и счёт длинные по существу: их
   содержимое не помещается ни в какое окно, и притворяться, что
   помещается, — значит прятать его. Режим включается поимённо. */

@media (min-width: 901px) {
  .canvas--fit {
    height: 100dvh;
    overflow: hidden;
    gap: 14px;
    padding-bottom: 22px;
  }
}

/* На телефоне в окно укладывается только рабочий стол: там нет полей
   ввода. На съёмке поле есть, и приколоченный экран поссорился бы
   с клавиатурой — она занимает половину окна, а прокрутить, чтобы
   увидеть, что печатаешь, было бы нечем. */
@media (max-width: 900px) {
  /* ВЫСОТУ СЧИТАЕМ ОТ ОСТАТКА, А НЕ ОТ ОКНА. Над холстом на телефоне
     стоит верхняя полоса — марка, баланс, кнопка съёмок, — и она
     занимает свои шестьдесят три пикселя в потоке. Холст ростом
     в целое окно оказывался ровно на столько ниже экрана, и нижняя
     карточка уходила под панель разделов. Правая колонка становится
     столбцом, а холст забирает то, что осталось. */
  .shell > div:not(.rail-veil) {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
  }

  .canvas--tight {
    flex: 1;
    height: auto;
    min-height: 0;
    overflow: hidden;
    gap: 12px;
  }
}

/* Шапка без подзаголовка: одна строка вместо трёх. */
.canvas-head--slim {
  align-items: center;
}

.canvas-head--slim h3 {
  font-size: 23px;
}

@media (max-width: 900px) {
  .canvas-head--slim h3 {
    font-size: 20px;
  }
}

/* ---------------------------------------------------- лента во всю высоту

   Полоса забирает всё, что осталось от полосы действий. На большом
   мониторе это крупные кадры — их видно как фотографии; на ноутбуке
   они просто становятся ниже, ничего не уводя под сгиб. Потолок в 54%
   высоты окна нужен, чтобы на очень высоком экране лента не
   превратилась в афишу в человеческий рост. */
/* ДИСПЛЕЙ ОСТАЁТСЯ СЕТКОЙ, и это не мелочь. Полоса внутри — контейнер
   прокрутки шириной в шестьдесят кадров; ноль как наименьшая ширина
   ему разрешён ровно потому, что он лежит в сетке (или во флексе).
   Стоило написать здесь display:block — и наименьшая ширина полосы
   пошла наверх как есть: колонка холста растянулась на семнадцать
   тысяч пикселей, а всё, что правее ленты, уехало за край экрана. */
.glide--hero {
  position: relative;
  margin-top: 0;
}

.glide--hero .glide__win,
.glide--hero .glide__track {
  height: 100%;
}

.glide--hero .glide__track {
  align-items: stretch;
}

.glide--hero .gcard {
  height: 100%;
  width: auto;
  aspect-ratio: 3 / 4;
}

@media (min-width: 901px) {
  .canvas--fit .glide--hero {
    flex: 1;
    min-height: 190px;
    /* Потолок двойной. Доля экрана держит пропорции на ноутбуке,
       а четыреста шестьдесят пикселей — на большом мониторе: кадр
       3:4 высотой в шестьсот пикселей становится шириной в треть
       ленты, и в ряду остаётся два с половиной снимка. */
    max-height: min(62vh, 620px);
  }

  /* Полоса действий прижата к низу окна. Остаток высоты, который
     не забрала лента, превращается в воздух МЕЖДУ ними, а не
     в обрубок страницы под последней карточкой. */
  .canvas--fit .deck {
    margin-top: auto;
  }
}

@media (max-width: 900px) {
  .canvas--tight .glide--hero {
    flex: 1;
    min-height: 170px;
    /* Треть экрана, не больше. Кадр 3:4 высотой в половину телефона
       занимает всю ширину — и лента из одного снимка перестаёт быть
       лентой: не видно, что её можно листать. */
    max-height: 38vh;
  }

  .canvas--tight .deck {
    margin-top: auto;
  }
}

/* ------------------------------------------------------- полоса действий

   Три дороги в один ряд: главная — слева и шире, две остальные
   столбиком справа. Раньше они стояли друг под другом на три экранных
   этажа, и до фотосессии человек не доходил. */
.deck {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 12px;
  align-items: stretch;
}

.deck .ways {
  margin-top: 0;
  grid-template-columns: 1fr;
  gap: 10px;
}

/* Зона загрузки полосой, а не рамкой в треть экрана. Рамка нужна там,
   где на её месте появится кадр; здесь не появится ничего — она только
   принимает файл. */
.drop--bar {
  aspect-ratio: auto;
  max-height: none;
  display: flex;
  align-items: center;
  gap: 16px;
  text-align: left;
  padding: 18px 20px;
  border-radius: var(--r-lg);
  background: var(--lemon-glow), var(--panel);
}

.drop--bar .drop__ic {
  margin-bottom: 0;
  flex: none;
}

.drop--bar .drop__body {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.drop--bar b {
  font-size: 18px;
  letter-spacing: -0.02em;
}

.drop--bar .drop__sub {
  margin-top: 0;
  font-size: 13px;
}

.drop--bar .drop__go {
  margin-left: auto;
  flex: none;
}

@media (max-width: 760px) {
  .deck {
    grid-template-columns: 1fr;
  }

  .drop--bar {
    padding: 18px 16px;
    gap: 13px;
  }

  .drop--bar b {
    font-size: 16px;
  }

  /* На узком экране подпись и кнопка в одну строку не встают.
     Кнопка уходит под текст во всю ширину — по ней и целятся
     пальцем. */
  .drop--bar .drop__sub {
    font-size: 12px;
  }

  /* Дороги — столбиком и в одну строку каждая. В два столбца на
     телефоне «Выбрать место самому» переносилось в три строки,
     и карточка становилась выше собственного значка. */
  .deck .way {
    padding: 14px 13px;
    gap: 11px;
  }

  .deck .way__ic {
    width: 34px;
    height: 34px;
  }

  .deck .way__ic svg {
    width: 18px;
    height: 18px;
  }

  .deck .way__body b {
    font-size: 14px;
  }

  .deck .way__go {
    display: none;
  }
}

@media (max-width: 420px) {
  .drop--bar .drop__go {
    display: none;
  }
}

/* ------------------------------------------------- полоска с исходником

   Здесь была рамка высотой в две трети экрана. На месте будущего кадра
   она стоит правильно; на экране выбора места кадра не будет — она
   только держит уже принесённый снимок и съедала ровно то место,
   где должны стоять сами места. */
.pickbar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  aspect-ratio: auto;
  max-height: none;
  text-align: left;
  border-radius: var(--r-md);
  background: var(--lemon-glow), var(--panel);
}

.pickbar__ic {
  width: 40px;
  height: 40px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: var(--r);
  background: var(--line);
  color: var(--lemon);
}

.pickbar__ic svg {
  width: 20px;
  height: 20px;
}

.pickbar__body {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.pickbar__body b {
  font-size: 14.5px;
  letter-spacing: -0.01em;
}

.pickbar__body span {
  font-size: 12.5px;
  color: var(--text-2);
  line-height: 1.35;
}

.pickbar__go {
  margin-left: auto;
  flex: none;
}

.pickbar--has,
.pickbar--set {
  border: 1px solid var(--line);
}

/* Снимок открывается крупно — тем же окном, что и кадры в галерее. */
.pickbar__thumb {
  width: 46px;
  height: 60px;
  flex: none;
  padding: 0;
  border: 1px solid var(--line-2);
  border-radius: 9px;
  overflow: hidden;
  background: #17150f;
  cursor: zoom-in;
}

.pickbar__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.pickbar__x {
  margin-left: auto;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text-3);
  font-size: 12px;
  cursor: pointer;
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease);
}

.pickbar__x:hover {
  color: var(--text);
  border-color: var(--line-2);
}

/* Селфи фотосессии — той же полоской. Их до пяти, и решёткой в четверть
   экрана они занимали столько же места, сколько весь выбор мест. */
.setpics {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
}

.setpic {
  position: relative;
  width: 46px;
  height: 60px;
  border-radius: 9px;
  overflow: hidden;
  background: var(--panel);
}

.setpic img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.setpic .source__drop {
  top: 3px;
  right: 3px;
  width: 17px;
  height: 17px;
  font-size: 9px;
}

.setpics__add {
  width: 46px;
  height: 60px;
  flex: none;
  aspect-ratio: auto;
  max-height: none;
  padding: 0;
  display: grid;
  place-items: center;
  border-radius: 9px;
  font-size: 20px;
  color: var(--text-3);
}

.setpics__add:hover {
  color: var(--lemon);
}

/* ==========================================================================
   ГДЕ СНИМАЕМ — один блок вместо четырёх разбросанных частей
   ==========================================================================

   ЧТО БЫЛО. Подпись «Где снимаем», рядом кнопка с названием раздела,
   под ними плитки, под плитками строка «ещё 6 разделов: студия, дом,
   город…», а отдельно, ниже, — поле «опишите словами». Четыре куска
   одного разговора, и ни один не выглядел частью другого.

   Главная беда была в кнопке: шесть разделов из семи человек мог
   увидеть, только догадавшись на неё нажать. Строка ниже перечисляла
   их словами — то есть сервис письменно сообщал, что у него есть,
   вместо того чтобы показать. Выбор, спрятанный за нажатие, для
   большинства не существует.

   ЧТО СТАЛО. Разделы стоят закладками в одну строку: видно, что их
   семь, видно, где ты сейчас, соседний — в одно касание. Плитки под
   ними в той же рамке, а внизу той же рамки — строка «своими
   словами». Один предмет: «где снимаем», с готовыми ответами
   и местом для своего. */

.places {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--lemon-glow), var(--panel);
  overflow: hidden;
}

.places__tabs {
  display: flex;
  gap: 6px;
  padding: 10px 11px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  border-bottom: 1px solid var(--line);
}

.places__tabs::-webkit-scrollbar {
  display: none;
}

/* Правый край растворяется — так видно, что ряд продолжается, а обрез
   не читается как сломанная вёрстка. Когда закладки помещаются целиком,
   растворяться нечему: под растушёвкой пусто. */
.places__tabs {
  -webkit-mask-image: linear-gradient(
    to right, #000 calc(100% - 34px), transparent
  );
  mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent);
}

.ptab {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 13px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.035);
  color: var(--text-2);
  font-size: 13px;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}

.ptab:hover {
  background: rgba(255, 255, 255, 0.07);
  color: var(--text);
}

/* Открытый раздел — единственное лимонное пятно в блоке: где ты
   сейчас, видно раньше, чем прочтёшь слово. */
.ptab.on {
  background: var(--lemon-grad);
  color: #1c1602;
  font-weight: 600;
}

.ptab__e {
  font-size: 13px;
  line-height: 1;
}

.places__grid {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  padding: 12px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: 10px;
  align-content: start;
}

/* Плитка места — это ФОТОГРАФИЯ, а не строка с картинкой сбоку.
   Раньше снимку отводилось 64 пикселя высоты в широкой плитке:
   на такой полоске не видно ни света, ни места — только то, что
   там что-то есть. Теперь плитка целиком снимок, а название лежит
   на нём. */
.places__grid .tile {
  position: relative;
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  background: var(--panel);
  padding: 0;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), transform 0.15s var(--ease);
}

.places__grid .tile .th {
  height: auto;
  aspect-ratio: 4 / 5;
}

.places__grid .tile:hover {
  border-color: var(--line-2);
}

.places__grid .tile:hover .shot1 img {
  transform: scale(1.05);
}

.tile__cap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 22px 10px 8px;
  text-align: left;
  font-size: 12.5px;
  line-height: 1.2;
  color: #fff;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.85),
    rgba(0, 0, 0, 0.45) 46%,
    rgba(0, 0, 0, 0)
  );
}

/* Выбранное место отмечено галочкой, а не только цветом рамки:
   рамку в шахматке из восьми снимков глаз находит не сразу. */
.tile__tick {
  position: absolute;
  top: 7px;
  right: 7px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--lemon-grad);
  color: #1c1602;
  opacity: 0;
  transform: scale(0.5);
  transition: opacity 0.16s var(--ease), transform 0.16s var(--ease);
}

.tile__tick svg {
  width: 12px;
  height: 12px;
}

.places__grid .tile.on {
  border-color: var(--lemon);
  box-shadow: inset 0 0 0 1px var(--lemon);
}

.places__grid .tile.on .tile__tick {
  opacity: 1;
  transform: none;
}

/* Строка «своими словами» — дно того же блока, а не отдельная плашка
   где-то ниже. Ничего не подошло из показанного — пишите здесь же,
   не уходя из разговора о месте. */
.places__own {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 14px 4px 13px;
  border-top: 1px solid var(--line);
  background: rgba(0, 0, 0, 0.16);
}

.places__pen {
  width: 17px;
  height: 17px;
  flex: none;
  color: var(--text-3);
  transition: color 0.15s var(--ease);
}

.places__pen svg {
  width: 100%;
  height: 100%;
  display: block;
}

.places__own:focus-within .places__pen {
  color: var(--lemon);
}

.composer--flat {
  flex: 1;
  border: 0;
  background: transparent;
  border-radius: 0;
  padding: 8px 0;
  min-width: 0;
}

.composer--flat:focus-within {
  border: 0;
}

/* ------------------------------------------------------ правая панель

   Настройки прокручиваются внутри панели, а цена и кнопка приколочены
   к её низу. Иначе на невысоком экране «Снять кадр» уезжает под сгиб —
   и человек, всё выбравший, не видит того единственного, ради чего
   пришёл. */
.panel__roll {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

.panel__foot {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 13px;
  border-top: 1px solid var(--line);
}

.panel__foot .price {
  margin: 0;
}

@media (min-width: 901px) {
  .canvas--fit .studio {
    flex: 1;
    min-height: 0;
  }

  .canvas--fit .stagewrap,
  .canvas--fit .panel {
    min-height: 0;
    height: 100%;
  }

  .canvas--fit .stagewrap .places {
    flex: 1;
  }
}

/* На телефоне колонка одна, и плитки мест не должны отжимать
   настройки на второй экран: у них своя высота и своя прокрутка. */
@media (max-width: 900px) {
  .places__grid {
    /* Три в ряд. Сто четыре пикселя не помещались в 375 — плитки
       вставали по две, и на экран влезала одна с половиной строка. */
    grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
    max-height: 44vh;
    gap: 7px;
    padding: 9px;
  }

  .tile__cap {
    font-size: 11.5px;
    padding: 18px 8px 7px;
  }

  .places__tabs {
    padding: 9px 10px;
  }

  .ptab {
    padding: 8px 12px;
    font-size: 12.5px;
  }

  .panel__roll {
    overflow: visible;
  }

  /* Настройки на телефоне идут в один ряд и вполовину ниже. Четыре
     цветных прямоугольника в столбик по два занимали двести пикселей
     ради того, что читается за секунду. */
  .moods {
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
  }

  .mood__tint {
    height: 34px;
  }

  /* Строка «чего не хватает» на телефоне переносится в отдельный ряд
     и забирает высоту целой строки плиток. Всё, что она сообщает,
     стоит строкой ниже: полоска загрузки пунктиром и говорит, что
     нужна фотография. */
  .canvas-head--slim > .rgt {
    display: none;
  }

  /* Подпись под «Вашим селфи» на узком экране переносится в четыре
     строки и делает полоску выше плиток. Пока фотографии нет, её
     заменяют пунктирная рамка и кнопка; когда есть — остаётся одна
     строка с многоточием. */
  .pickbar:not(.pickbar--has) .pickbar__body span {
    display: none;
  }

  .pickbar--has .pickbar__body span,
  .pickbar--set .pickbar__body span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* ==========================================================================
   ГЛАВНАЯ ДЛЯ ГОСТЕЙ · пересобрана 06.09.2026
   ==========================================================================

   Что было не так. Страница отвечала на все вопросы, но одинаковым
   голосом: шесть блоков подряд одной ширины, одного тона и одного
   размера. Главное доказательство — «лицо остаётся вашим» — лежало
   рядом кадров величиной с почтовую марку, а цена была спрятана
   в раскрывающемся ответе, то есть её видел только тот, кто уже
   решился спросить.

   Что стало. Три опоры вместо шести абзацев: стена настоящих работ,
   примерочная, которую можно потрогать без регистрации, и цена
   открытым текстом. */

/* --------------------------------------------------- строка над заголовком

   Стена за спиной работает, только если сказано, что это не подложка
   из фотобанка. Одна строка со светящейся точкой — и стена становится
   доводом. */
.wall__kicker {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px 7px 11px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(9, 8, 6, 0.5);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  font-size: 12.5px;
  color: var(--text-2);
  letter-spacing: 0.01em;
}

.wall__kicker i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--lemon);
  box-shadow: 0 0 0 3px rgba(232, 185, 35, 0.18);
  animation: liveBeat 2.2s var(--ease) infinite;
}

/* ==================================================== ПРИМЕРОЧНАЯ

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

.tryon-sec h2 {
  font-size: clamp(24px, 3.4vw, 34px);
}

.tryon {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr) 190px;
  gap: 18px;
  align-items: center;
  margin-top: 22px;
}

.tryon__who,
.tryon__where {
  display: grid;
  gap: 10px;
  align-content: center;
}

.tryon__faces {
  display: grid;
  gap: 8px;
}

/* Лицо выбирается лицом, а не подписью «пример 3». */
.tface {
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  background: var(--panel);
  cursor: pointer;
  aspect-ratio: 1 / 1;
  filter: saturate(0.7) brightness(0.72);
  transition: filter 0.18s var(--ease), border-color 0.18s var(--ease),
    transform 0.18s var(--ease);
}

.tface img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.tface:hover {
  filter: none;
  transform: translateY(-2px);
}

.tface.on {
  filter: none;
  border-color: var(--lemon);
  box-shadow: 0 0 0 1px var(--lemon);
}

/* Сам кадр. Высота задана, ширина считается из пропорции — иначе
   при смене места рамка прыгает и вся страница дёргается. */
.tryon__stage {
  position: relative;
  margin: 0;
  height: min(58vh, 520px);
  aspect-ratio: 3 / 4;
  justify-self: center;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #17150f;
  border: 1px solid var(--line);
  box-shadow: 0 26px 60px rgba(0, 0, 0, 0.55);
}

.tryon__out {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: opacity 0.22s var(--ease);
}

.tryon__stage--turn .tryon__out {
  opacity: 0.25;
}

/* Исходник — уголком на самом кадре: сравнивать удобнее там, где
   оба видны разом, а не через полэкрана друг от друга. */
.tryon__src {
  position: absolute;
  left: 12px;
  bottom: 12px;
  width: 74px;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 10px;
  border: 1.5px solid rgba(255, 255, 255, 0.5);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.6);
}

.tryon__stage figcaption {
  position: absolute;
  right: 12px;
  bottom: 16px;
  padding: 7px 13px;
  border-radius: 999px;
  background: rgba(9, 8, 6, 0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  font-size: 12.5px;
}

.tryon__places {
  display: grid;
  gap: 7px;
}

.tplace {
  padding: 10px 13px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: transparent;
  color: var(--text-2);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease),
    background 0.15s var(--ease);
}

.tplace:hover {
  color: var(--text);
  border-color: var(--line-2);
}

.tplace.on {
  color: #1c1602;
  background: var(--lemon-grad);
  border-color: transparent;
  font-weight: 600;
}

.tryon__fine {
  margin-top: 16px;
  text-align: center;
}

@media (max-width: 900px) {
  /* На телефоне прибор разворачивается сверху вниз: кадр первым,
     под ним два ряда выбора. Три колонки в 375 пикселей превратили
     бы и лица, и названия в нечитаемые полоски. */
  .tryon {
    grid-template-columns: 1fr;
    gap: 14px;
  }

  .tryon__stage {
    height: auto;
    width: 100%;
    aspect-ratio: 3 / 4;
    order: -1;
  }

  .tryon__faces {
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 7px;
  }

  .tryon__places {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
  }

  .tplace {
    flex: 1 1 auto;
    text-align: center;
    padding: 9px 12px;
  }

  .tryon__src {
    width: 58px;
  }
}

/* ==========================================================================
   ПРОФИЛЬ · пересобран 06.09.2026
   ==========================================================================

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

   Что стало. Шапка сделана из его собственных кадров, под ней полка
   последних работ, а способы входа собраны тремя карточками в ряд
   вместо восьми строк. Опасное — удаление — осталось внизу
   и отдельно. */

.phero {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--lemon-glow), var(--panel);
}

/* Мозаика из своих кадров позади имени. Она не иллюстрация:
   человек узнаёт свои снимки и понимает, что это его место,
   а не страница настроек. */
.phero__wall {
  position: absolute;
  inset: 0;
  display: grid;
  /* Шесть на две — ровно двенадцать кадров, которые мы и просим.
     Без заданной высоты строки браузер считает её по картинке,
     а картинка тянется по строке: получается круг, и мозаика
     занимает половину шапки вместо всей. */
  grid-template-columns: repeat(6, 1fr);
  grid-auto-rows: 50%;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
  /* Кадры уходят в фон к низу — иначе имя ложится на пёстрое
     и не читается. */
  -webkit-mask-image: linear-gradient(to bottom, #000, rgba(0, 0, 0, 0.15) 62%, transparent);
  mask-image: linear-gradient(to bottom, #000, rgba(0, 0, 0, 0.15) 62%, transparent);
  pointer-events: none;
}

.phero__wall--on {
  opacity: 0.3;
}

.phero__wall img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: saturate(0.7) blur(1px);
}

.phero__body {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 20px;
  align-items: center;
  padding: 22px;
}

.phero__who {
  display: grid;
  gap: 6px;
  min-width: 0;
}

.phero__line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 12px;
}

.phero__line h2 {
  margin: 0;
  font-size: 27px;
  font-weight: 500;
  letter-spacing: -0.025em;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.7);
}

.phero__sub {
  margin: 0;
  font-size: 13px;
  color: var(--text-2);
}

/* Счёт — первое, о чём спрашивают, открывая профиль. Поэтому
   в шапке, а не полосой ниже. */
.phero__money {
  display: grid;
  justify-items: end;
  gap: 4px;
  text-align: right;
}

.phero__sum {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.phero__note {
  font-size: 12px;
  color: var(--text-2);
}

.phero__money .b {
  margin-top: 4px;
}

/* ---------------------------------------------------------------- полка */

.pshelf {
  margin-top: 14px;
  display: grid;
  gap: 10px;
}

.pshelf__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.pshelf__row {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  padding-bottom: 2px;
}

.pshelf__row::-webkit-scrollbar {
  display: none;
}

.pshot {
  flex: none;
  width: 96px;
  aspect-ratio: 3 / 4;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: var(--panel);
  cursor: zoom-in;
  transition: transform 0.18s var(--ease), border-color 0.18s var(--ease);
}

.pshot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.pshot:hover {
  transform: translateY(-3px);
  border-color: var(--line-2);
}

/* ------------------------------------------------------- способы входа */

.ids {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

/* Строка во всю ширину ради двух слов «не привязан» тратила экран
   и заставляла читать одно и то же трижды. */
.idc {
  display: grid;
  gap: 5px;
  align-content: start;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
  min-width: 0;
}

.idc__t {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 500;
}

/* Точка говорит состояние раньше, чем прочитан текст. */
.idc__t i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--line-2);
  flex: none;
}

.idc--on .idc__t i {
  background: var(--good);
  box-shadow: 0 0 0 3px rgba(89, 168, 131, 0.16);
}

.idc__d {
  font-size: 12.5px;
  color: var(--text-2);
  overflow: hidden;
  text-overflow: ellipsis;
}

.idc .b {
  margin-top: 6px;
  justify-self: start;
}

@media (max-width: 760px) {
  .phero__body {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 16px;
  }

  /* Счёт переезжает под имя во всю ширину: втискивать его третьей
     колонкой в 375 пикселей — значит сделать нечитаемым и его,
     и имя. */
  .phero__money {
    grid-column: 1 / -1;
    grid-template-columns: auto 1fr auto;
    justify-items: start;
    align-items: center;
    text-align: left;
    padding-top: 14px;
    border-top: 1px solid var(--line);
  }

  .phero__money .b {
    margin-top: 0;
    justify-self: end;
  }

  .ava--big {
    width: 84px;
    height: 84px;
  }

  .phero__line h2 {
    font-size: 22px;
  }

  .pstats {
    gap: 18px;
    padding: 14px 18px 16px;
  }

  .ids {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   СВЕТ И ФАКТУРА · сделано руками 06.09.2026
   ==========================================================================

   Три приёма, и ни один не стоит ни килобайта зависимостей: свет
   на главной кнопке, свет по краю карточки под курсором и точечная
   фактура вместо сплошного чёрного между разделами.

   ПРАВИЛО, КОТОРОЕ ЗДЕСЬ ГЛАВНЕЕ КРАСОТЫ. Всё, что живёт постоянно,
   работает и на телефоне; всё, что живёт под курсором, на телефоне
   не существует вовсе — там нет курсора, зато есть батарея и память,
   на которой мы уже обожглись. Поэтому дорогие эффекты закрыты
   через @media (hover: hover), а дешёвые — нет. */

/* ------------------------------------------------------ главная кнопка

   Что не так с обычной кнопкой из градиента: она выглядит одинаково
   и до нажатия, и в тот момент, когда от неё чего-то ждут. Здесь
   у неё три состояния и все три — свет, а не смена цвета:

   покой   — тёплое свечение под кнопкой, еле заметное, дышит;
   курсор  — по кнопке проходит блик, как по металлу;
   нажатие — кнопка проседает и свечение гаснет. */

.b.pri.glow {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

/* Свечение под кнопкой. Не box-shadow на самой кнопке: тень поверх
   тёмного фона даёт грязное серое кольцо. Отдельный слой позади
   с размытием читается как свет. */
.b.pri.glow::before {
  content: "";
  position: absolute;
  inset: -40%;
  z-index: -2;
  background: radial-gradient(
    50% 50% at 50% 50%,
    rgba(232, 185, 35, 0.55),
    rgba(232, 185, 35, 0) 70%
  );
  opacity: 0.5;
  animation: glowBreath 3.6s var(--ease) infinite;
  pointer-events: none;
}

@keyframes glowBreath {
  0%, 100% { opacity: 0.35; transform: scale(0.94); }
  50% { opacity: 0.62; transform: scale(1.04); }
}

/* Блик. Стоит за левым краем и проходит поперёк ровно один раз
   на наведение — бесконечно бегающий блик превращает кнопку
   в рекламный баннер. */
.b.pri.glow::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 45%;
  left: -60%;
  z-index: -1;
  background: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.55) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  transform: skewX(-18deg);
  pointer-events: none;
}

@media (hover: hover) {
  .b.pri.glow:hover::after {
    animation: sheen 0.7s var(--ease);
  }
}

@keyframes sheen {
  to { left: 130%; }
}

.b.pri.glow:active {
  transform: translateY(1px);
}

.b.pri.glow:active::before {
  opacity: 0.2;
}

/* Кнопка, от которой ждут. Пока идёт съёмка, свет по краю бежит
   по кругу: это единственное место, где движение обязано быть
   бесконечным — оно и означает «идёт работа». */
.b.pri.glow[disabled]::before,
.b.pri.glow[disabled]::after {
  animation: none;
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .b.pri.glow::before {
    animation: none;
  }

  .b.pri.glow:hover::after {
    animation: none;
  }
}

/* --------------------------------------------- свет по краю карточки

   Под курсором по контуру карточки проходит светлая дуга. Сделана
   одним слоем: коническим градиентом, который вращается, и маской,
   оставляющей от него только рамку в полтора пикселя. Ни канваса,
   ни скрипта, ни единого обработчика движения мыши.

   ТОЛЬКО ТАМ, ГДЕ ЕСТЬ КУРСОР. На телефоне этот эффект не только
   бесполезен — он вреден: вращение градиента перерисовывает
   карточку каждый кадр. */
@property --edge {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

@media (hover: hover) {
  .places__grid .tile,
  .gcard,
  .way,
  .hcard {
    position: relative;
  }

  .places__grid .tile::after,
  .gcard::after,
  .way::after,
  .hcard::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 3;
    border-radius: inherit;
    padding: 1.5px;
    background: conic-gradient(
      from var(--edge),
      rgba(232, 185, 35, 0) 0deg,
      rgba(232, 185, 35, 0) 60deg,
      rgba(247, 220, 99, 0.9) 105deg,
      rgba(232, 185, 35, 0) 150deg,
      rgba(232, 185, 35, 0) 360deg
    );
    /* Маска оставляет от заливки только кайму: внутренний
       прямоугольник вычитается. Так рамка получается из градиента
       без второго элемента и без обводки. */
    -webkit-mask:
      linear-gradient(#000 0 0) content-box,
      linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask:
      linear-gradient(#000 0 0) content-box,
      linear-gradient(#000 0 0);
    mask-composite: exclude;
    opacity: 0;
    transition: opacity 0.25s var(--ease);
    pointer-events: none;
  }

  .places__grid .tile:hover::after,
  .gcard:hover::after,
  .way:hover::after,
  .hcard:hover::after {
    opacity: 1;
    animation: edgeRun 2.4s linear infinite;
  }
}

@keyframes edgeRun {
  to { --edge: 360deg; }
}

@media (prefers-reduced-motion: reduce) {
  .places__grid .tile:hover::after,
  .gcard:hover::after,
  .way:hover::after,
  .hcard:hover::after {
    animation: none;
  }
}

/* ----------------------------------------------------------- фактура

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

   Точки расходятся к краям и гаснут к низу — ровное поле точек
   выглядит как обои. */
.grain {
  position: relative;
}

.grain::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: radial-gradient(
    rgba(255, 255, 255, 0.055) 1px,
    transparent 1px
  );
  background-size: 22px 22px;
  -webkit-mask-image: radial-gradient(
    120% 90% at 50% 0%,
    #000 0%,
    rgba(0, 0, 0, 0.35) 55%,
    transparent 100%
  );
  mask-image: radial-gradient(
    120% 90% at 50% 0%,
    #000 0%,
    rgba(0, 0, 0, 0.35) 55%,
    transparent 100%
  );
  pointer-events: none;
}

.grain > * {
  position: relative;
  z-index: 1;
}

/* ==========================================================================
   ВЫГОДЫ НА ГЛАВНОЙ
   ==========================================================================

   Три главных довода были набраны строкой мелкого серого текста —
   так набирают сноски и оговорки. Теперь это числа в рост подписи:
   их видно раньше, чем читают. */

.perks {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin: 6px 0 0;
  padding: 0;
  list-style: none;
}

.perks li {
  display: grid;
  gap: 1px;
  padding: 11px 20px;
  border-radius: var(--r-md);
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(9, 8, 6, 0.55);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  text-align: center;
}

.perks b {
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
  /* Лимонный градиент прямо по цифрам: это те самые числа, ради
     которых человек читает первый экран. */
  background: var(--lemon-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.perks span {
  font-size: 12px;
  color: var(--text-2);
  white-space: nowrap;
}

@media (max-width: 520px) {
  .perks {
    gap: 7px;
  }

  .perks li {
    flex: 1 1 0;
    min-width: 0;
    padding: 10px 8px;
  }

  .perks b {
    font-size: 17px;
  }

  .perks span {
    font-size: 10.5px;
    white-space: normal;
  }
}

/* ------------------------------------------------------------- закрытие

   Целый экран с собственным заголовком «3 кадра — бесплатно» был
   третьим местом, где страница обещала одно и то же теми же словами.
   Осталась одна полоса. */
.tail {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 14px 20px;
  margin: 10px 0 0;
  padding: 34px 24px;
  border-top: 1px solid var(--line);
}

.tail__t {
  font-size: 17px;
  letter-spacing: -0.01em;
}

.tail__price {
  font-size: 13px;
  color: var(--text-2);
  border-bottom: 1px solid var(--line-2);
}

.tail__price:hover {
  color: var(--text);
}

@media (max-width: 560px) {
  .tail {
    flex-direction: column;
    gap: 12px;
    padding: 28px 18px;
    text-align: center;
  }

  .tail .b {
    width: 100%;
  }
}
