/* afifa — визуальная система вебаппа.

   Выросла из болванки (docs/afifa/prototype/style.css): те же токены, те же компоненты, те же
   имена классов `k-*`. Леса стенда (`.p-*` — рамка телефона и карта экранов) сюда не
   переезжают, всё остальное — переезжало.

   БОЛВАНКА БОЛЬШЕ НЕ ИСТОЧНИК ЦЕЛИКОМ (12.08, вечер): форма и выбор модели переросли макет
   по референсу, денежная страница — тоже. Сверять с болванкой поэкранно уже нельзя; что где
   живёт сейчас, говорит app/apps/afifa/contract.md.

   Два решения, унаследованные от болванки, оба сознательные:

   1. ТЁМНАЯ ТЕМА ПРИБИТА НАМЕРТВО — тему клиента Telegram не проксируем. Здесь смотрят
      фото: на белом листе медиа-сетка разваливается, а половина людей приходит со светлой
      темой. Тему выбирает продукт.
   2. АКЦЕНТ ТЁПЛЫЙ, А НЕ СИНИЙ — синий это «продолжить, утвердить», а здесь главное
      действие «сделай мне красиво». Акцент живёт в одном токене.

   Правило слоёв: ПОВЕРХНОСТЬ УХОДИТ ОТ ЦВЕТА ТЕКСТА ДАЛЬШЕ, ЧЕМ ФОН. */

/* ─────────────────────────── токены ─────────────────────────── */

:root {
  /* Слои. Почти чёрный, но не #000: на OLED чистый чёрный съедает границы карточек,
     а медиа-сетке нужен край. */
  --bg: #0e0e11;
  --card: #17171b;
  --sunken: #0a0a0c;
  --raised: #1f1f24;              /* то, что лежит НА карточке: чип, кнопка-иконка */

  --line: rgba(255, 255, 255, 0.10);
  --line-soft: rgba(255, 255, 255, 0.045);

  /* Чернила тёплые. Холодный #fff на тёмном отдаёт синевой и спорит с фото. */
  --text: #f3f0ec;
  --text-dim: rgba(243, 240, 236, 0.66);
  --hint: rgba(243, 240, 236, 0.42);
  /* Подсказка в пустом поле — тише любого настоящего текста: её задача не читаться, а
     говорить «здесь пусто, пиши сюда». Отличать её от написанного надо с одного взгляда. */
  --ghost: rgba(243, 240, 236, 0.28);

  /* Главное действие: сгенерировать, купить, применить. Жёлтый ленты ограждения —
     «сюда смотри», а не тёплое золото. */
  --accent: #ffd21a;
  --accent-hi: #ffe86a;           /* верх градиента объёмной кнопки */
  --accent-lo: #e0a900;           /* низ и «губа» под кнопкой */
  --accent-ink: #1a1305;          /* чернила НА акценте: почти чёрные, иначе знак тонет */
  --accent-soft: rgba(255, 210, 26, 0.13);
  --accent-line: rgba(255, 210, 26, 0.42);

  /* Действия сейчас нет (форма не заполнена, ход уже идёт). Кнопка остаётся ТЕМ ЖЕ жёлтым,
     только потухшим: фонарь приглушили, а не выключили. Серая плашка на этом месте выглядит
     чужой и мёртвой — будто кнопки нет вовсе. Числа — акцент, подмешанный в фон: плашка на
     24%, чернила на 72% (между собой 4:1, читаемо). */
  --accent-off: #483d13;
  --accent-off-ink: #bc9b18;

  /* Ход принят и уже идёт. Это НЕ «нечего запускать», и цвет обязан быть другим: потухший
     жёлтый на этом месте читается как «всё пропало», а человек только что отдал команду и
     ждёт знака, что она принята. Зелёный семьи --edit: «принято, делаю» — он не спорит с
     жёлтым призывом и не читается как отказ. */
  --run: #1c362c;
  --run-ink: #46b17e;

  /* Правка — всё, что меняет уже созданное. */
  --edit: #4cc38a;
  --edit-ink: #04170d;

  --danger: #ff6f6f;
  --pro: #c3a0ff;                 /* только бейдж и рамка платного */
  --pro-soft: rgba(195, 160, 255, 0.14);

  --font-ui: -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  --t-display: 32px;
  --t-h1: 24px;
  --t-h2: 18px;
  --t-body: 15px;
  --t-small: 13px;
  --t-micro: 11.5px;

  --lh-tight: 1.15;
  --lh-head: 1.25;
  --lh-body: 1.45;
  --tr-display: -0.03em;
  --tr-h1: -0.02em;
  --tr-label: 0.09em;

  --fw-regular: 400;
  --fw-semibold: 600;
  --fw-bold: 700;
  --fw-black: 800;

  /* Шаг сетки 4px. */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;

  --tap: 44px;
  --dock-h: 64px;
  --dock-clear: 104px;            /* нижний отступ экрана, чтобы док не перекрыл контент */

  /* Безопасные поля приезжают от площадки (host.safeArea → app.js): в mini app клиент
     может показать апп во весь экран, и первые ~100px окажутся под часами и его
     собственными кнопками. В браузере остаются нулями. */
  --safe-top: 0px;
  --safe-bottom: 0px;

  --r-s: 8px;
  --r-m: 12px;
  --r-l: 16px;
  --r-pill: 999px;
  --r-tab: 10px;

  /* Ширина карточки тарифа/пакета. Фиксированная, а не процентная: от неё считается
     боковой отступ полки, и центр должен сходиться до пикселя на любой ширине экрана. */
  --plan-w: min(320px, calc(100vw - 56px));

  --border-thin: 1px;
  --border-pick: 2px;

  --shadow-pop: 0 10px 30px rgba(0, 0, 0, 0.45);
  --shadow-lift: 0 4px 0 var(--accent-lo), 0 10px 26px rgba(255, 152, 15, 0.28);

  --dur-state: 0.15s;
  --dur-screen: 0.22s;
  --dur-sheet: 0.26s;
  --dur-spin: 1.6s;
}

/* ─────────────────────────── сброс ─────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

/* Раньше display у дока перебивал атрибут hidden — док не прятался на экранах-модалках.
   Правило общее, чтобы грабли не повторились. */
[hidden] { display: none !important; }

html, body { margin: 0; padding: 0; }

/* Кадр приложения. Высоту даёт площадка (host.viewportHeight → --app-h): в мини-аппе
   видимая часть меньше 100dvh, и док по 100dvh уезжает под край клиента. */
body {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  height: var(--app-h, 100dvh);
  overflow: hidden;
  font-family: var(--font-ui);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

/* ФОРМЕННЫЕ ЭЛЕМЕНТЫ ЛИШАЮТСЯ РОДНОГО ВИДА ЯВНО. Без `appearance: none` WebKit (Safari и
   вебвью телеграма на iOS) продолжает рисовать их как СИСТЕМНЫЕ органы и наши свойства
   применяет через раз: у кнопки текст красится системным «чёрным по кнопке» — на нашем
   почти чёрном фоне он просто исчезает, а фон textarea не прокрашивается до первой правки
   (поле выглядит как текст без рамки, рамка появляется, когда начинаешь набирать). Chrome
   в этом месте великодушен, поэтому дефект виден только на живом клиенте. */
button, input, textarea, select {
  font: inherit;
  color: inherit;
  margin: 0;
  -webkit-appearance: none;
  appearance: none;
}

button { background: none; border: 0; cursor: pointer; }
button:disabled { cursor: default; }
img { display: block; max-width: 100%; }
h1, h2, h3, p, figure { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }

/* ─────────────────────── каркас приложения ─────────────────────── */

.k-app {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

.k-screen {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: calc(var(--s4) + var(--safe-top)) var(--s4)
           calc(var(--dock-clear) + var(--safe-bottom));
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-screen) ease, visibility var(--dur-screen);
  scrollbar-width: none;
}

.k-screen::-webkit-scrollbar { display: none; }
.k-screen[data-on] { opacity: 1; visibility: visible; }

/* Экраны-модалки: без дока, во весь кадр, свой фон. */
.k-screen--full { padding-bottom: calc(var(--s5) + var(--safe-bottom)); background: var(--bg); }
.k-screen--flush { padding-left: 0; padding-right: 0; }

/* ─────────────────────────── шапки ─────────────────────────── */

.k-bar {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: var(--tap);
  margin-bottom: var(--s4);
}

.k-bar--pad { padding: 0 var(--s4); }
.k-bar--tight { margin-bottom: var(--s2); }   /* шапка вплотную к кадру: на экране работы главное — кадр */
.k-bar-grow { flex: 1; min-width: 0; }

.k-h1 {
  font-size: var(--t-h1);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tr-h1);
  line-height: var(--lh-head);
}

.k-h2 {
  font-size: var(--t-h2);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tr-h1);
}

.k-label {
  font-size: var(--t-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--hint);
}

.k-sub { font-size: var(--t-small); color: var(--text-dim); }
.k-small { font-size: var(--t-small); }
.k-hint { color: var(--hint); }
.k-center { text-align: center; }
.k-danger { color: var(--danger); }

/* Длинный текст (промпт, ошибка провайдера) не должен разрывать сетку. */
.k-wrap { overflow-wrap: anywhere; }

.k-logo {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-h2);
  font-weight: var(--fw-black);
  letter-spacing: 0.02em;
}

.k-logo-mark {
  width: 28px;
  height: 28px;
  border-radius: var(--r-s);
  background: linear-gradient(150deg, var(--accent-hi), var(--accent-lo));
  display: grid;
  place-items: center;
  color: var(--accent-ink);
  font-size: 15px;
  font-weight: var(--fw-black);
}

/* ─────────────────────────── кнопки ─────────────────────────── */

.k-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: var(--tap);
  padding: 0 var(--s4);
  border-radius: var(--r-m);
  background: var(--raised);
  color: var(--text);
  font-size: var(--t-body);
  font-weight: var(--fw-semibold);
  transition: filter var(--dur-state), background var(--dur-state);
}

.k-btn:active { filter: brightness(1.25); }
.k-btn--block { display: flex; width: 100%; }
.k-btn--quiet { background: transparent; border: var(--border-thin) solid var(--line); color: var(--text-dim); }

/* ГЛАВНАЯ КНОПКА. «Большая, контрастная и объёмная»: объём даёт не тень вообще, а нижняя
   губа цветом темнее самой плашки — кнопка стоит НА экране, а не лежит В нём. */
.k-go {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: center;
  gap: var(--s3);
  min-height: 60px;
  border-radius: var(--r-l);
  background: linear-gradient(180deg, var(--accent-hi), var(--accent));
  color: var(--accent-ink);
  font-size: 18px;
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  box-shadow: var(--shadow-lift);
  transition: transform var(--dur-state), box-shadow var(--dur-state);
}

.k-go:active {
  transform: translateY(3px);
  box-shadow: 0 1px 0 var(--accent-lo), 0 4px 14px rgba(255, 152, 15, 0.22);
}

/* Нечего запускать (пустое обязательное поле) или уже запускаем. Кнопка не серая плашка и не
   тот же жёлтый под фильтром: она ПОТУХШАЯ — свой цвет, приглушённый в фон. Так видно, что
   орган на месте и оживёт, а не что его отключили насовсем. Объёма нет намеренно: губа и
   свечение — обещание нажатия, а нажимать сейчас нечего. */
.k-go:disabled {
  background: var(--accent-off);
  color: var(--accent-off-ink);
  box-shadow: none;
}

/* Ход уже идёт. Кнопка остаётся НАЖАТОЙ (тот же сдвиг, что под пальцем) и меняет цвет на
   рабочий: команда принята, а не отменена. Спиннер отвечает на единственный вопрос этой
   секунды — «оно вообще пошло?»; цена с кнопки уходит, решение уже принято. */
.k-go--busy:disabled {
  background: var(--run);
  color: var(--run-ink);
  transform: translateY(3px);
}

.k-go--busy .k-spin { border-color: rgba(255, 255, 255, 0.16); border-top-color: currentColor; }

/* Сколько спишут — видно в момент нажатия, а не в форме выше. Цена стоит на кнопке ГОЛОЙ,
   без плашки под собой: плашка делала из неё второй предмет на кнопке, а это часть одной
   фразы — «сгенерировать за столько». */
.k-go-cost {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  font-size: 18px;
  font-weight: var(--fw-bold);
}

.k-ico {
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  flex: none;
  border-radius: var(--r-pill);
  background: var(--raised);
  color: var(--text-dim);
  transition: color var(--dur-state), background var(--dur-state);
}

.k-ico:active { color: var(--text); }
.k-ico--bare { background: transparent; }
.k-ico--sm { width: 34px; height: 34px; }

/* ──────────────────── чипы, табы, сегменты ──────────────────── */

.k-chips {
  display: flex;
  gap: var(--s2);
  overflow-x: auto;
  scrollbar-width: none;
  margin: 0 calc(-1 * var(--s4)) var(--s4);
  padding: 0 var(--s4);
}

.k-chips::-webkit-scrollbar { display: none; }

.k-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  flex: none;
  height: 38px;
  padding: 0 var(--s3);
  border-radius: var(--r-pill);
  background: var(--card);
  color: var(--text-dim);
  font-size: var(--t-small);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
  transition: background var(--dur-state), color var(--dur-state);
}

.k-chip[aria-pressed="true"] { background: var(--text); color: var(--bg); }

.k-seg {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  border-radius: var(--r-m);
  background: var(--sunken);
  flex: none;
}

.k-seg button {
  display: grid;
  place-items: center;
  min-width: 38px;
  height: 32px;
  padding: 0 var(--s2);
  border-radius: var(--r-tab);
  color: var(--hint);
  font-size: var(--t-small);
  font-weight: var(--fw-semibold);
  transition: background var(--dur-state), color var(--dur-state);
}

.k-seg button[aria-pressed="true"] { background: var(--raised); color: var(--text); }

/* ─────────────────────── кадры и плитки ───────────────────────
   Пока кадра нет (обложка витрины не задана, работа ещё крутится), место красится
   процедурно: --a1/--a2/--a3 приходят из app.js по идентификатору. Это не «дизайн
   картинок», а честная заглушка — сетка не должна быть серой и плоской. */

.k-art {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 22% 18%, var(--a3) 0%, transparent 58%),
    radial-gradient(110% 80% at 82% 76%, var(--a1) 0%, transparent 62%),
    linear-gradient(154deg, var(--a2) 0%, #0d0d10 100%);
}

.k-art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(112deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 4px);
  mix-blend-mode: overlay;
}

/* Настоящий кадр ложится поверх заглушки: пока картинка грузится, место уже занято
   и сетка не прыгает. */
.k-shot {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.k-tile {
  position: relative;
  display: block;
  width: 100%;
  border-radius: var(--r-m);
  background: var(--sunken);
  overflow: hidden;
}

.k-tile > .k-art { position: absolute; inset: 0; }

/* Метки поверх плитки: тип носителя и число кадров в пачке. */
.k-tile-tag {
  position: absolute;
  left: var(--s2);
  bottom: var(--s2);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  height: 22px;
  padding: 0 var(--s2);
  border-radius: var(--r-s);
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(8px);
  font-size: var(--t-micro);
  font-weight: var(--fw-semibold);
}

/* Плитка неудачи: показываем причину, а не пустое место. */
.k-tile--fail {
  display: grid;
  place-items: center;
  padding: var(--s3);
  border: var(--border-thin) solid var(--line);
  background: var(--card);
  color: var(--hint);
  font-size: var(--t-micro);
  text-align: center;
}

/* ────────────────────────── док ──────────────────────────
   Прибит к низу, фейд сверху — контент уезжает под него плавно, а не режется. */

.k-dock {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  height: calc(var(--dock-h) + var(--safe-bottom));
  padding: 0 var(--s2) var(--safe-bottom);
  display: grid;
  /* Колонки равные — ритм пунктов не ломается. Шире только средняя: кнопка как будто
     выросла и раздвинула соседей, а расстояния между пунктами остались равными. */
  grid-template-columns: 1fr 1fr 1.35fr 1fr 1fr;
  align-items: center;
  /* Плашка почти прозрачная: под ней должна просвечивать лента работ — это медиа-продукт,
     и глухая полоса внизу съедает у него треть кадра. Держит читаемость размытие. */
  background: color-mix(in srgb, var(--bg) 42%, transparent);
  backdrop-filter: blur(28px) saturate(140%);
  border-top: var(--border-thin) solid var(--line-soft);
}

.k-dock::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 40px;
  background: linear-gradient(to top, var(--bg), transparent);
  pointer-events: none;
}

/* :not(.k-dock-go) обязателен. Раньше правило било по ВСЕМ кнопкам дока, и центральная
   получала от него бледный --hint: селектор из двух частей специфичнее одиночного
   .k-dock-go, поэтому её собственный цвет молча проигрывал. */
.k-dock button:not(.k-dock-go) {
  display: grid;
  justify-items: center;
  gap: 2px;
  color: var(--hint);
  font-size: 10px;
  font-weight: var(--fw-semibold);
  transition: color var(--dur-state);
}

.k-dock button[aria-current="true"] { color: var(--text); }
.k-dock-ico { font-size: 19px; line-height: 1; }

/* Центральная кнопка: единственный яркий элемент дока. Знак внутри — звезда Иштар,
   залитая почти чёрным: тонкий светлый контур на жёлтом не читается вовсе. */
.k-dock-go {
  justify-self: center;
  /* Слегка выступает над плашкой — ровно настолько, чтобы читаться отдельным предметом,
     а не пятым пунктом меню. Приподнята через position/top, а не transform: transform
     занят нажатием, и они бы затёрли друг друга. */
  position: relative;
  top: -9px;
  width: 70px;
  height: 52px;
  border-radius: var(--r-m);
  background: linear-gradient(180deg, var(--accent-hi), var(--accent));
  color: var(--accent-ink);
  display: grid;
  place-items: center;
  box-shadow: 0 3px 0 var(--accent-lo), 0 8px 22px rgba(255, 210, 26, 0.28);
}

.k-dock-go:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--accent-lo); }

/* ──────────────────── блоки главной ────────────────────
   Главная собирается из массива блоков (см. homeBlocks в app.js): обложка, строка входов,
   полка, сетка, баннер. Экран не знает наполнения — меняется массив, не разметка. */

.k-blocks { display: grid; gap: var(--s5); }

/* ГРАБЛИ, ПОЙМАННЫЕ НА ПРОГОНЕ БОЛВАНКИ. Дети grid по умолчанию не сжимаются меньше своего
   min-content. Горизонтальная полка честно объявлена overflow-x:auto, но её содержимое
   протекало наверх: колонка сетки вырастала до ширины полки, и ВСЯ главная уезжала за
   правый край. min-width:0 снимает автоминимум и возвращает прокрутку. */
.k-blocks > *,
.k-grid > *,
.k-cards > *,
.k-quick > *,
.k-rows > *,
.k-acts > * { min-width: 0; }

/* Обложка: приглашение к витрине во весь кадр. */
.k-cover {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-l);
  overflow: hidden;
  text-align: left;
}

.k-cover > .k-art { position: absolute; inset: 0; }

.k-cover-in {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: var(--s4);
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.45) 0%, transparent 34%, rgba(0, 0, 0, 0.78) 100%);
}

.k-cover-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s3);
  font-size: var(--t-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
}

.k-cover-t {
  display: block;
  font-size: var(--t-display);
  font-weight: var(--fw-black);
  letter-spacing: var(--tr-display);
  line-height: var(--lh-tight);
  text-transform: uppercase;
  text-wrap: balance;
}

/* Подпись обложки: промпт бывает длинным, но обложка — не место его читать. */
.k-cover-d {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: var(--s2);
  font-size: var(--t-small);
  color: rgba(255, 255, 255, 0.8);
}

.k-cover-go {
  margin-top: var(--s3);
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  align-self: flex-start;
  height: 38px;
  padding: 0 var(--s4);
  border-radius: var(--r-pill);
  background: var(--text);
  color: var(--bg);
  font-size: var(--t-small);
  font-weight: var(--fw-bold);
}

/* Полка: горизонтальная лента работ. */
.k-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s3);
}

.k-head-go { font-size: var(--t-small); font-weight: var(--fw-semibold); color: var(--hint); }

.k-rail {
  display: flex;
  gap: var(--s2);
  overflow-x: auto;
  scrollbar-width: none;
  margin: 0 calc(-1 * var(--s4));
  padding: 0 var(--s4);
}

.k-rail::-webkit-scrollbar { display: none; }
.k-rail > * { flex: none; width: 132px; }

/* Сетка работ. */
.k-grid { display: grid; gap: var(--s2); }
.k-grid--2 { grid-template-columns: repeat(2, 1fr); }
.k-grid--3 { grid-template-columns: repeat(3, 1fr); }

/* Баннер: единственное место промо на главной. Без таймеров дефицита. */
.k-banner {
  display: flex;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  padding: var(--s4);
  border-radius: var(--r-l);
  background: var(--pro-soft);
  border: var(--border-thin) solid rgba(195, 160, 255, 0.3);
  text-align: left;
}

.k-banner-ico { font-size: 22px; }
.k-banner-t { font-weight: var(--fw-semibold); }

/* Быстрые входы «что сделаем». */
.k-quick { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s2); }

.k-quick button {
  display: grid;
  gap: var(--s2);
  justify-items: center;
  padding: var(--s3) var(--s1);
  border-radius: var(--r-m);
  background: var(--card);
  font-size: var(--t-micro);
  font-weight: var(--fw-semibold);
  color: var(--text-dim);
}

/* Подпись входа фиксирована по высоте: название витрины бывает длинным, но входы обязаны
   стоять в одну линию. */
.k-quick-t {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-width: 100%;
  text-align: center;
}

.k-quick-ico { font-size: 20px; }

/* ─────────────────────── история ─────────────────────── */

.k-day {
  margin: var(--s5) 0 var(--s3);
  font-size: var(--t-small);
  font-weight: var(--fw-semibold);
  color: var(--hint);
}

.k-day:first-child { margin-top: 0; }

/* Лента: кадры во всю ширину друг за другом. Подписей нет намеренно — в истории смотрят
   картинки, а промпт и параметры ждут на экране работы. */
.k-feed { display: grid; gap: var(--s2); }

.k-feed-prompt {
  font-size: var(--t-small);
  color: var(--text-dim);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.k-meta { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }

.k-model {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  height: 24px;
  padding: 0 var(--s2);
  border-radius: var(--r-s);
  background: var(--sunken);
  font-size: var(--t-micro);
  color: var(--text-dim);
}

/* КАРТОЧКА-ПРОЦЕСС. Занимает ровно то же место, что займёт результат: после генерации
   сетка не прыгает. Отсюда aspect-ratio на месте, а не спиннер по центру пустого экрана. */
.k-proc {
  position: relative;
  border-radius: var(--r-m);
  background: var(--card);
  border: var(--border-thin) solid var(--line);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.k-proc-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--s2) var(--s2) var(--s2) var(--s3);
  gap: var(--s2);
}

.k-proc-body {
  flex: 1;
  background: repeating-linear-gradient(-45deg, rgba(255, 255, 255, 0.022) 0 10px, transparent 10px 20px);
}

.k-proc-foot {
  padding: var(--s3);
  border-top: var(--border-thin) solid var(--line-soft);
  display: grid;
  gap: var(--s2);
}

.k-run {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-small);
  font-weight: var(--fw-semibold);
  color: var(--text-dim);
}

.k-spin {
  width: 15px;
  height: 15px;
  flex: none;
  border-radius: 50%;
  border: 2px solid var(--line);
  border-top-color: var(--accent);
  animation: k-turn var(--dur-spin) linear infinite;
}

@keyframes k-turn { to { transform: rotate(360deg); } }

/* ШКАЛА ОЖИДАНИЯ. Показывает не настоящий прогресс (провайдер его не сообщает), а сколько
   прошло от обычного времени этой модели (time2gen витрины). Лежит внизу карточки-процесса —
   там же, где у готовой работы будет край кадра, поэтому подмена результата не дёргает
   композицию. */
.k-wait {
  display: grid;
  gap: var(--s1);
  padding: var(--s2) var(--s3) var(--s3);
}

.k-wait-line {
  height: 4px;
  border-radius: var(--r-pill);
  background: var(--sunken);
  overflow: hidden;
}

/* Ширину двигает app.js каждые полсекунды; переход сглаживает шаг, чтобы полоса ползла,
   а не прыгала. */
.k-wait-line span {
  display: block;
  height: 100%;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--accent-lo), var(--accent));
  transition: width var(--dur-sheet) linear;
}

.k-wait-t {
  font-size: var(--t-micro);
  color: var(--hint);
  text-align: right;
}

.k-void {
  display: grid;
  gap: var(--s3);
  justify-items: center;
  padding: var(--s6) var(--s4);
  text-align: center;
  color: var(--hint);
}

.k-void-ico { font-size: 34px; opacity: 0.5; }

/* ─────────────────────── работа ─────────────────────── */

.k-stage {
  display: grid;
  gap: var(--s2);
  justify-items: center;
  padding: var(--s2) var(--s4) var(--s4);
}

/* Кадр показываем целиком, а не обрезанным по сетке: здесь на него и пришли смотреть. */
.k-stage-img {
  width: auto;
  max-width: 100%;
  max-height: 52dvh;
  border-radius: var(--r-m);
  background: var(--sunken);
}

.k-acts { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s2); padding: 0 var(--s4); }

.k-act {
  display: grid;
  gap: var(--s1);
  justify-items: center;
  padding: var(--s3) var(--s1);
  border-radius: var(--r-m);
  background: var(--card);
  font-size: var(--t-small);
  font-weight: var(--fw-semibold);
  color: var(--text);
}

.k-act--hero { background: var(--edit); color: var(--edit-ink); }
.k-act-ico { font-size: 18px; }

/* Рецепт под работой: из чего она сделана. Именно он делает «Пересоздать» осмысленным —
   человек видит, что повторится. */
.k-recipe {
  margin: var(--s5) var(--s4) 0;
  padding: var(--s4);
  border-radius: var(--r-l);
  background: var(--card);
  display: grid;
  gap: var(--s3);
}

.k-recipe-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  font-size: var(--t-small);
}

.k-recipe-row + .k-recipe-row { padding-top: var(--s3); border-top: var(--border-thin) solid var(--line-soft); }
.k-recipe-v { color: var(--text-dim); text-align: right; }

.k-refs { display: flex; gap: var(--s2); flex-wrap: wrap; justify-content: flex-end; }
.k-refs .k-tile { width: 44px; height: 44px; border-radius: var(--r-s); flex: none; }

/* ─────────────────── каталог витрины ─────────────────── */

.k-cards { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s3); }

.k-card {
  display: grid;
  align-content: start;
  border-radius: var(--r-l);
  background: var(--card);
  overflow: hidden;
  text-align: left;
}

.k-card-shot { position: relative; aspect-ratio: 16 / 9; }
.k-card-shot > .k-art { position: absolute; inset: 0; }
.k-card-in { padding: var(--s3); display: grid; gap: var(--s1); }
.k-card-t { font-size: var(--t-small); font-weight: var(--fw-bold); letter-spacing: 0.01em; text-transform: uppercase; }

.k-card-d {
  font-size: var(--t-micro);
  color: var(--hint);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.k-badge {
  position: absolute;
  left: var(--s2);
  top: var(--s2);
  z-index: 2;
  height: 20px;
  padding: 0 var(--s2);
  display: inline-flex;
  align-items: center;
  border-radius: var(--r-s);
  font-size: 10px;
  font-weight: var(--fw-black);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.k-badge--app { background: var(--accent); color: var(--accent-ink); }
.k-badge--base { background: var(--text); color: var(--bg); }

/* ─────────────────── форма генерации ─────────────────── */

.k-form { display: grid; gap: var(--s3); }

/* Место под панель запуска, чтобы низ формы не оказался под ней. Складывается из того же,
   из чего сама панель (см. .k-launch): поле сверху + строка параметров + зазор + кнопка +
   поле снизу. Подобранное число разъехалось бы с панелью на первой же правке. */
.k-form--launch {
  padding-bottom: calc(var(--s3) + 48px + var(--s3) + 60px + var(--s4) + var(--safe-bottom));
}

.k-box {
  padding: var(--s3);
  border-radius: var(--r-l);
  background: var(--card);
}

.k-box-t { margin-bottom: var(--s3); }

/* Блок, внутри которого органы сами держат свои поля (промпт, строка модели): собственные
   поля коробки тогда лишние — от них у крупного текста появлялся двойной отступ. */
.k-box--flat { padding: var(--s2) 0; }

.k-thumbs { display: flex; gap: var(--s2); flex-wrap: wrap; }

.k-thumb {
  position: relative;
  width: 80px;
  height: 80px;
  border-radius: var(--r-m);
  overflow: visible;                /* крестик свисает за угол — не срезать */
  flex: none;
}

.k-thumb > .k-art,
.k-thumb > .k-shot { position: absolute; inset: 0; border-radius: var(--r-m); }

/* Снять референс — промах стоит перезагрузки формы, поэтому мишень крупная.
   line-height:0 обязателен: инлайновый svg тянет строчный интерлиньяж и знак съезжает. */
.k-thumb-x {
  position: absolute;
  right: -8px;
  top: -8px;
  z-index: 2;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.72);
  border: var(--border-thin) solid rgba(255, 255, 255, 0.22);
  color: #fff;
  display: grid;
  place-items: center;
  line-height: 0;
}

.k-thumb--add {
  display: grid;
  place-items: center;
  background: transparent;
  border: 1.5px dashed var(--line);
  color: var(--hint);
  font-size: 20px;
}

.k-thumb--busy { opacity: 0.6; }

/* Поле промпта — не input, а кнопка: тап раскрывает редактор во весь экран.
   Текст КРУПНЫЙ (референс Higgsfield): промпт — главное содержимое формы, и мелким кеглем
   он читался как подпись к пустому месту. Обрезан пятью строками: длинный промпт иначе
   выдавливает с экрана всё, ради чего сюда пришли, — модель и кнопку. */
.k-prompt {
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
  width: 100%;
  min-height: 104px;
  /* Снизу поля нет намеренно: обрезанная строка красится ДО края поля, а не до края текста,
     и с полем из-под пятой строки выглядывала бы шестая — половинками букв. */
  padding: var(--s2) var(--s3) 0;
  text-align: left;
  font-size: 18px;
  font-weight: var(--fw-semibold);
  line-height: 1.35;
  letter-spacing: -0.01em;
  color: var(--text);
  overflow-wrap: anywhere;
}

/* Подсказка — не промпт: она обычным кеглем и приглушена, иначе пустое поле кричит
   собственным текстом громче, чем заполненное. */
.k-prompt--void {
  color: var(--ghost);
  font-size: var(--t-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  letter-spacing: 0;
}

/* Строка выбора модели под промптом: слева — что выбираем, справа — что выбрано. Ведёт на
   свой экран (у модели есть цена и время, их читают рядом с именем), поэтому знак «дальше»,
   а не «раскроется список». */
.k-pick {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  width: 100%;
  min-height: var(--tap);
  padding: 0 var(--s3);
  text-align: left;
}

.k-pick-l {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  flex: none;
  color: var(--hint);
}

.k-pick-v {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  min-width: 0;
  font-weight: var(--fw-semibold);
}

.k-pick-v svg { color: var(--hint); flex: none; }

/* Модель из старой ссылки или давнего рецепта, которой в витрине больше нет. Цветом отказа,
   а не серым: серое читается как «выключено», а тут человеку надо действие — выбрать другую. */
.k-pick-v--gone { color: var(--danger); }

.k-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  width: 100%;
  min-height: var(--tap);
  padding: 0 var(--s3);
  border-radius: var(--r-m);
  background: var(--card);
  text-align: left;
  font-size: var(--t-body);
}

.k-row-v { display: inline-flex; align-items: center; gap: var(--s2); color: var(--text-dim); font-size: var(--t-small); }
.k-row--flat { background: transparent; padding: 0; }

/* Панель запуска: прибита к низу экрана формы, чтобы кнопка не уезжала. */
.k-launch {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  padding: var(--s3) var(--s4) calc(var(--s4) + var(--safe-bottom));
  background: linear-gradient(to top, var(--bg) 62%, transparent);
  display: grid;
  gap: var(--s3);
}

/* ─────────────── опции запуска и всплывашка выбора ───────────────
   Параметры кадра живут строкой над кнопкой «Сгенерировать»: знак и значение, без подписи —
   подпись есть во всплывашке, где выбирают. Модели в этом ряду НЕТ: она решает и результат,
   и цену, и стоит отдельным органом под промптом (см. .k-pick).

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

.k-opts { display: flex; flex-wrap: wrap; gap: var(--s2); }

.k-opt { position: relative; }

.k-optbtn {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  height: 48px;
  padding: 0 var(--s4);
  border-radius: var(--r-pill);
  background: var(--raised);
  color: var(--text);
  font-size: var(--t-body);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}

.k-optbtn-ico { display: flex; color: var(--hint); }

.k-optbtn[aria-expanded="true"] { background: var(--accent-soft); color: var(--accent); }
.k-optbtn[aria-expanded="true"] .k-optbtn-ico { color: inherit; }

/* Сторона привязки задаётся по месту кнопки в ряду: крайние тянутся от своего края,
   средние встают по центру своей кнопки. Правило чисто позиционное и потому надёжное —
   замерять и вдвигать на лету нельзя: у всплывашки в этот момент ещё старая геометрия. */
.k-pop {
  position: absolute;
  bottom: calc(100% + var(--s2));
  left: 0;
  z-index: 5;
  width: 232px;
  padding: var(--s3);
  border-radius: var(--r-l);
  background: var(--raised);
  border: var(--border-thin) solid var(--line);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.6);
}

.k-pop--right { left: auto; right: 0; }
.k-pop--mid { left: 50%; right: auto; margin-left: -116px; }   /* половина ширины: центр по своей кнопке */
.k-pop-t { margin-bottom: var(--s2); }
.k-pop-in { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s1); }

.k-popt {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: 40px;
  padding: 0 var(--s3);
  border-radius: var(--r-m);
  color: var(--text-dim);
  font-size: var(--t-small);
  font-weight: var(--fw-semibold);
  text-align: left;
}

.k-popt[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent); }

/* Разделитель внутри объединённого блока: промпт и модель — один блок формы, но разные
   органы, и линия говорит это дешевле, чем зазор. Линия идёт от края до края блока: отсюда
   отрицательные поля, снимающие его собственные. */
.k-split { height: var(--border-thin); background: var(--line); margin: var(--s3) calc(-1 * var(--s3)); }
.k-box--flat .k-split { margin: var(--s3) 0 var(--s2); }

/* ─────────────── выбор модели ───────────────
   Экран, а не всплывашка: у модели есть цена и обычное время, и читать их надо рядом с
   именем. Строка та же, что у референса (docs/afifa/concept/model_selection.png): знак,
   имя, чем эта модель отличается. */

.k-search {
  display: flex;
  align-items: center;
  gap: var(--s3);
  height: var(--tap);
  margin-bottom: var(--s4);
  padding: 0 var(--s4);
  border-radius: var(--r-pill);
  background: var(--card);
  color: var(--hint);
}

.k-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  outline: none;
  font-size: var(--t-body);
  color: var(--text);
}

.k-search input::placeholder { color: var(--hint); }
.k-search input::-webkit-search-cancel-button { -webkit-appearance: none; }

.k-mlist { display: grid; gap: var(--s1); }

.k-mrow {
  display: flex;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  padding: var(--s2);
  border-radius: var(--r-l);
  text-align: left;
  transition: background var(--dur-state);
}

/* Выбранная строка — не галочка на пустом месте, а подсвеченная строка целиком: в списке
   из десятка имён глаз ищет пятно, а не значок. */
.k-mrow[aria-pressed="true"] { background: var(--raised); }

.k-mtile {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  flex: none;
  border-radius: var(--r-m);
  background: var(--card);
  color: var(--text-dim);
  font-size: 20px;
  font-weight: var(--fw-black);
}

.k-mrow[aria-pressed="true"] .k-mtile { background: var(--sunken); }

.k-mrow-in { display: grid; gap: 2px; min-width: 0; flex: 1; }

.k-mrow-t {
  color: var(--text);           /* явно: имя модели — главное на экране, наследования ему мало */
  font-size: 17px;
  font-weight: var(--fw-semibold);
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.k-mrow-d { font-size: var(--t-small); color: var(--hint); }

.k-mrow-on { display: flex; flex: none; padding-right: var(--s2); color: var(--accent); }

/* Редактор промпта: крупный контрастный шрифт — с ним работают, а не читают по диагонали.
   Кнопка запуска остаётся на виду. */
.k-editor {
  width: 100%;
  min-height: 44dvh;
  padding: var(--s4);
  border: 0;
  border-radius: var(--r-l);
  background: var(--card);
  color: var(--text);
  font-size: 19px;
  font-weight: var(--fw-semibold);
  line-height: 1.4;
  resize: none;
  outline: none;
}

.k-editor::placeholder { color: var(--ghost); font-weight: var(--fw-regular); }

/* Счётчик под редактором. Молчит до отметки, на которой длина начинает что-то значить, и
   молчит НЕВИДИМО — иначе пустая коробка держала бы отступ над клавиатурой. */
.k-countbox { padding: var(--s2) var(--s1) 0; }
.k-countbox:empty { display: none; }

.k-count { font-size: var(--t-small); color: var(--hint); }
.k-count--over { color: var(--danger); font-weight: var(--fw-semibold); }

/* Отказ формы: причина стоит рядом с кнопкой, а не улетает тостом. */
.k-err {
  padding: var(--s3);
  border-radius: var(--r-m);
  background: rgba(255, 111, 111, 0.12);
  color: var(--danger);
  font-size: var(--t-small);
  font-weight: var(--fw-semibold);
}

/* ─────────────────────── тарифы и пакеты ───────────────────────

   Тариф — САМОСТОЯТЕЛЬНАЯ ПАНЕЛЬ в рабочий экран, а не плитка в полке (референс автора,
   docs/afifa/concept/change_plang*.PNG): имя и метка сверху, что входит — текстом прямо на
   панели, цена и своя кнопка прибиты к низу. Кнопка внутри панели, а не под полкой: действие
   живёт рядом с тем, к чему относится.

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

.k-shelf { position: relative; }

.k-plans {
  display: flex;
  gap: var(--s3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  margin: var(--s3) calc(-1 * var(--s4)) 0;
  /* Боковой отступ = половина свободного места при фиксированной ширине панели, и считается
     он от ШИРИНЫ КАДРА (50vw). Проценты тут врут дважды: процентная ширина панели считается
     от уже отступленной ширины, а процентный отступ — от родителя, тогда как полка вылезает
     за него на var(--s4) в каждую сторону. Обе ошибки сдвигали крайние панели мимо центра. */
  padding: var(--s3) max(var(--s4), calc(50vw - var(--plan-w) / 2)) var(--s2);
}

.k-plans::-webkit-scrollbar { display: none; }

/* Высота панели — по содержимому, а не по кадру: растянутая на весь экран панель отгоняла
   кнопку в самый низ, и между преимуществами и ценой зияла пустота (правка автора 13.08).
   Панели полки всё равно выравниваются друг по другу — flex-строка тянет их до самой
   высокой, поэтому кнопки соседних тарифов стоят на одной линии. */
.k-plan {
  position: relative;
  flex: none;
  width: var(--plan-w);
  scroll-snap-align: center;
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  padding: var(--s4);
  border-radius: var(--r-l);
  text-align: left;
  overflow: hidden;
  background: linear-gradient(163deg, var(--tier) 0%, var(--tier-deep) 62%, #101014 100%);
}

/* УРОВНИ. Насыщенный угол сверху слева, к низу уходит в почти чёрный — как у референса.
   Кнопка берёт --tier-go/--tier-ink, поэтому цвет действия всегда «из панели». */
.k-plan--t0 {
  --tier: #2b3038;
  --tier-deep: #1a1d22;
  --tier-go: linear-gradient(180deg, #f4f5f7, #d9dbe0);
  --tier-lip: #a9adb5;
  --tier-ink: #14161a;
}

.k-plan--t1 {
  --tier: #4a3f18;
  --tier-deep: #241f10;
  --tier-go: linear-gradient(180deg, var(--accent-hi), var(--accent));
  --tier-lip: var(--accent-lo);
  --tier-ink: var(--accent-ink);
}

.k-plan--t2 {
  --tier: #4b1c38;
  --tier-deep: #24101d;
  --tier-go: linear-gradient(180deg, #ff86b4, #ef3d84);
  --tier-lip: #b32a60;
  --tier-ink: #2a0a18;
}

.k-plan-top { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }

.k-plan-name {
  font-size: var(--t-h1);
  font-weight: var(--fw-black);
  letter-spacing: var(--tr-h1);
  text-transform: uppercase;
}

.k-plan-unit { font-size: var(--t-small); color: var(--text-dim); }

/* Метка стоит В СТРОКЕ с именем, а не свисает за угол: панель обрезает всё, что вылезает
   за скругление, и метка уезжала под границу. */
.k-chip-cur {
  height: 22px;
  padding: 0 var(--s2);
  display: inline-flex;
  align-items: center;
  border-radius: var(--r-s);
  background: rgba(255, 255, 255, 0.12);
  color: var(--text-dim);
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Что входит — текстом прямо на панели: коробка внутри коробки только дробила её. */
.k-plan-what { display: grid; gap: var(--s2); }

.k-plan-credits {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-body);
  font-weight: var(--fw-bold);
}

.k-perk { display: flex; align-items: flex-start; gap: var(--s2); font-size: var(--t-small); color: var(--text-dim); }
.k-perk svg { flex: none; margin-top: 2px; opacity: 0.65; }

/* Низ прибит к краю: сколько бы ни было преимуществ, кнопка стоит на одном месте. Отступ
   сверху — небольшой (панель по содержимому): после преимуществ цена, под ней действие. */
.k-plan-foot { margin-top: auto; padding-top: var(--s2); display: grid; gap: var(--s3); }

.k-plan-price { font-size: var(--t-h1); font-weight: var(--fw-bold); letter-spacing: var(--tr-h1); }
.k-plan-price span { font-size: var(--t-small); font-weight: var(--fw-regular); color: var(--hint); }

/* Кнопка панели — тот же объём, что у главной кнопки продукта, но цветом своего тарифа. */
.k-plan-foot .k-go {
  min-height: 50px;
  background: var(--tier-go);
  color: var(--tier-ink);
  box-shadow: 0 3px 0 var(--tier-lip);
}

.k-plan-foot .k-go:active { box-shadow: 0 1px 0 var(--tier-lip); }

.k-plan-here {
  min-height: 50px;
  display: grid;
  place-items: center;
  border-radius: var(--r-m);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-dim);
  font-size: var(--t-small);
  font-weight: var(--fw-semibold);
}

/* ТЕКУЩИЙ ТАРИФ. Тот же силуэт, но цвет уведён в серое: уровень остаётся виден, а «купить»
   тут нечего. Никаких внутренних теней — они мутят панель и читаются как грязь. */
.k-plan--cur {
  --tier: #24262a;
  --tier-deep: #17181b;
  color: var(--text-dim);
}

.k-plan--cur .k-plan-name,
.k-plan--cur .k-plan-price { color: var(--text-dim); }

/* Стрелки полки: полупрозрачные, поверх краёв. Полку листают пальцем, но без них не видно,
   что листать есть куда. */
.k-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: rgba(10, 10, 12, 0.55);
  backdrop-filter: blur(6px);
  border: var(--border-thin) solid rgba(255, 255, 255, 0.12);
  color: var(--text);
  opacity: 0.75;
}

.k-arrow:active { opacity: 1; }
.k-arrow--l { left: calc(-1 * var(--s2)); }
.k-arrow--r { right: calc(-1 * var(--s2)); }
.k-arrow[hidden] { display: none !important; }

/* ─────────────────────── профиль ─────────────────────── */

/* Шапка денежной страницы — одна карточка на профиль и пейвол: строка «кто я» плюс шкалы
   окон. Человек пришёл за двумя числами и тем, чем их поменять, — всё должно помещаться
   без прокрутки, поэтому строка, а не столбик по центру. */
.k-money {
  display: grid;
  gap: var(--s3);
  padding: var(--s4);
  border-radius: var(--r-l);
  background: var(--card);
}

.k-me {
  display: flex;
  align-items: center;
  gap: var(--s3);
}

.k-me-in { flex: 1; min-width: 0; display: grid; gap: 2px; }
.k-me-money { text-align: right; flex: none; }
.k-micro { font-size: var(--t-micro); }

/* Когда денег станет больше — строкой под карточкой: это второй вопрос после «сколько
   осталось», и ответ на него не должен требовать перехода. */
.k-me-when {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-top: var(--s2);
  padding: 0 var(--s1);
  font-size: var(--t-small);
  color: var(--hint);
}

.k-face {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: linear-gradient(150deg, var(--accent-hi), var(--accent-lo));
  color: var(--accent-ink);
  font-size: 26px;
  font-weight: var(--fw-black);
  flex: none;
}

.k-face--sm { width: 48px; height: 48px; font-size: 19px; }

/* Шкалы окон тарифа. Живут на денежной странице, а не в шапке рабочего экрана: там они
   дублировали бы док. Ноль не прячем — пустая шкала и есть ответ «почему не запускается». */
.k-lims { display: grid; gap: var(--s2); }

.k-lim-top {
  display: flex;
  justify-content: space-between;
  gap: var(--s2);
  margin-bottom: var(--s1);
  font-size: var(--t-micro);
  color: var(--hint);
}

.k-lim-n { color: var(--text-dim); font-weight: var(--fw-semibold); }

.k-lim-track {
  height: 6px;
  border-radius: 999px;
  background: var(--sunken);
  overflow: hidden;
}

.k-lim-track i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--accent-lo), var(--accent));
}



/* ─────────────────────── тост ─────────────────────── */

.k-toast {
  position: fixed;
  left: var(--s4);
  right: var(--s4);
  top: calc(var(--s4) + var(--safe-top));    /* ниже часов и кнопок клиента, а не под ними */
  z-index: 60;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-m);
  background: var(--raised);
  border: var(--border-thin) solid var(--line);
  box-shadow: var(--shadow-pop);
  font-size: var(--t-small);
  font-weight: var(--fw-semibold);
  /* Проценты тут врали: пустой тост низкий, и -140% его собственной высоты не перекрывали
     отступ сверху — полоска выглядывала за край. Считаем от ВСЕЙ дистанции до верха. */
  transform: translateY(calc(-100% - var(--s4) - var(--safe-top) - 12px));
  transition: transform var(--dur-sheet) cubic-bezier(0.2, 0.8, 0.3, 1);
}

.k-toast[data-on] { transform: translateY(0); }
.k-toast-ico { color: var(--accent); font-size: 16px; display: flex; }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* Переключатель денежной страницы: «сменить тариф» против «пополнить». Во всю ширину —
   это не тумблер вида, а выбор того, что человек сейчас делает. */
.k-seg--wide { display: flex; width: 100%; }

/* Пункт-строка, а не столбик: у базового .k-seg button стоит grid (там только иконка),
   и подпись уезжала бы под неё. */
.k-seg--wide button {
  flex: 1;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  height: 38px;
}
.k-seg--wide button:disabled { opacity: 0.45; cursor: default; }

/* Пейвол: та же шапка, что у профиля, — акцентом обведена, а не подменена. Причина, по
   которой человек здесь, дописывается строкой под ней. */
.k-money--stop { border: var(--border-thin) solid var(--accent-line); background: var(--accent-soft); }
.k-me-when--stop { color: var(--accent); }

/* Общие правила игры — под панелью, ниже сгиба: сначала выбор, потом уточнения. */
.k-facts {
  display: grid;
  gap: var(--s2);
  margin-top: var(--s5);
  padding: var(--s4);
  border-radius: var(--r-l);
  background: var(--card);
}

.k-fact { display: flex; align-items: flex-start; gap: var(--s2); font-size: var(--t-small); color: var(--text-dim); }
.k-fact svg { flex: none; margin-top: 2px; color: var(--accent); opacity: 0.8; }

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

.k-packs { display: grid; gap: var(--s3); margin-top: var(--s4); }

.k-pack {
  display: grid;
  gap: var(--s2);
  padding: var(--s4);
  border-radius: var(--r-l);
  background: var(--card);
  border: var(--border-thin) solid var(--line-soft);
}

/* Крупный пакет выгоднее на кадр — это единственное, что стоит подсветить. */
.k-pack--top { border-color: var(--accent-line); background: linear-gradient(165deg, #2a2716, var(--card) 60%); }

.k-pack-top { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.k-pack-n { font-size: var(--t-h2); font-weight: var(--fw-bold); letter-spacing: var(--tr-h1); }

.k-chip-top {
  height: 20px;
  padding: 0 var(--s2);
  display: inline-flex;
  align-items: center;
  border-radius: var(--r-s);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 10px;
  font-weight: var(--fw-black);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.k-pack-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); margin-top: var(--s2); }

/* Белая кнопка: одна и та же для всех пакетов — «купить» здесь не имеет уровней. */
.k-go--white {
  width: auto;
  min-height: 44px;
  padding: 0 var(--s5);
  background: linear-gradient(180deg, #ffffff, #e6e7ea);
  color: #14161a;
  box-shadow: 0 3px 0 #a9adb5;
}

.k-go--white:active { box-shadow: 0 1px 0 #a9adb5; }

/* ─────────────────────── десктоп и подборки (16.08) ───────────────────────
   Апп живёт и сайтом во весь экран. Телефонная вёрстка — базовая и не трогается; широкий
   экран ДОБАВЛЯЕТ: верхнюю навигацию вместо дока, центровку контента, сетки пошире.
   Референс композиции главной — Higgsfield (анонсы → инструменты → подборки). */

/* Герой-полка анонсов: на телефоне листается вбок (карточка почти во всю ширину, соседняя
   выглядывает — видно, что листать есть куда), на десктопе стоит тремя колонками. */
.k-hero {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 86%;
  gap: var(--s3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  margin: 0 calc(-1 * var(--s4));
  padding: 0 var(--s4);
}

.k-hero::-webkit-scrollbar { display: none; }
.k-hero > * { scroll-snap-align: center; }
.k-hero .k-cover { aspect-ratio: 4 / 5; }

/* Карточка Pro в герое: фиолетовый уровень тарифа, без фото — обещание, а не пример. */
.k-cover--pro > .k-art { background: linear-gradient(160deg, #2b2140, #171227 70%); }

/* Плитка примера подборки: подпись проявляется указателем — на телефоне её нет, там имя
   скажет лайтбокс. */
.k-gal { position: relative; }

.k-gal-t {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  padding: var(--s5) var(--s3) var(--s2);
  background: linear-gradient(to top, rgba(0, 0, 0, 0.72), transparent);
  color: #fff;
  font-size: var(--t-micro);
  font-weight: var(--fw-semibold);
  text-align: left;
  opacity: 0;
  transition: opacity var(--dur-state);
}

@media (hover: hover) {
  .k-gal:hover .k-gal-t { opacity: 1; }
}

/* Полка примеров на главной: плитки крупнее работ — их разглядывают, а не узнают.
   Ровняются ВЫСОТОЙ, а не шириной: пропорции у пресетов разные, и полка с фиксированной
   шириной давала рваный низ; ширину каждой плитке считает её aspect-ratio. */
.k-rail--gal { align-items: flex-start; }
.k-rail--gal > * { width: auto; height: 216px; }

/* Примеры в форме пресета: лайтовая полка «что получится» — ниже ростом, чем витринная,
   чтобы не спорить с самой формой. */
.k-rail--sample > * { height: 132px; }

/* Блок шаблона в форме — ВСТАВКА, а не часть интерфейса: пресет накрывает обычную
   генерацию, и его имя, описание и примеры живут своей карточкой под общей шапкой
   «Создать фото». Акцентная кромка слева — знак «это привезённый рецепт». */
.k-tpl {
  display: grid;
  gap: var(--s3);
  padding: var(--s4);
  border-radius: var(--r-l);
  background: var(--card);
  border: var(--border-thin) solid var(--line-soft);
  border-left: 3px solid var(--accent);
}

/* Шапка вставки — кнопка целиком: сворачивает блок до заголовка (тап по стрелке мелкий).
   Стрелка вниз — «свернуть», у свёрнутого блока смотрит вбок — «развернуть». */
.k-tpl-top {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
  width: 100%;
  padding: 0;
  text-align: left;
  color: inherit;
}

.k-tpl-arrow {
  margin-left: auto;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: var(--r-pill);
  color: var(--hint);
  transform: rotate(90deg);
  transition: transform var(--dur-state);
}

.k-tpl--fold .k-tpl-arrow { transform: rotate(0deg); }

.k-tpl-badge {
  flex: none;
  height: 20px;
  padding: 0 var(--s2);
  display: inline-flex;
  align-items: center;
  border-radius: var(--r-s);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 10px;
  font-weight: var(--fw-black);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.k-tpl-t {
  font-size: var(--t-h2);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tr-h1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Полка примеров внутри вставки не должна выпирать за её скругление. */
.k-tpl .k-rail { margin: 0; padding: 0; }

/* Миниатюры вариантов в лайтбоксе. */
.k-lbx-thumbs { display: flex; justify-content: center; gap: var(--s2); }

.k-lbx-th {
  width: 48px;
  height: 48px;
  padding: 0;
  border-radius: var(--r-s);
  overflow: hidden;
  opacity: 0.55;
  outline: 2px solid transparent;
  transition: opacity var(--dur-state);
}

.k-lbx-th img { width: 100%; height: 100%; object-fit: cover; }
.k-lbx-th[aria-pressed="true"] { opacity: 1; outline-color: var(--accent); }

/* Страница подборки: кладка колонками — кадры разных пропорций стоят плотно, как в
   референсе. Ширина плитки = колонка, высоту даёт её aspect-ratio. */
.k-masonry { columns: 2; column-gap: var(--s2); }
.k-masonry > * { width: 100%; margin-bottom: var(--s2); break-inside: avoid; }

/* ── Лайтбокс примера ── */

.k-lbx {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: calc(var(--safe-top) + var(--s5)) var(--s4) calc(var(--safe-bottom) + var(--s4));
  background: rgba(8, 8, 10, 0.86);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

.k-lbx-in {
  display: grid;
  gap: var(--s3);
  max-width: min(880px, 100%);
  max-height: 100%;
  min-height: 0;
}

.k-lbx-img {
  min-height: 0;
  /* Под кадром теперь миниатюры, текст и большая кнопка — им нужно ~280px. */
  max-height: calc(var(--app-h, 100dvh) - var(--safe-top) - var(--safe-bottom) - 280px);
  max-width: 100%;
  margin: 0 auto;
  border-radius: var(--r-l);
  object-fit: contain;
  background: var(--sunken);
}

/* Текст лайтбокса — во всю ширину, своим блоком; «Пересоздать» — главной кнопкой (k-go)
   последней строкой сетки: прибита к низу, действие читается как у формы. */
.k-lbx-foot { display: grid; gap: var(--s1); }

.k-lbx-t {
  font-size: var(--t-h2);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tr-h1);
}

.k-lbx-go { min-height: 56px; }

.k-lbx-x {
  position: absolute;
  top: calc(var(--safe-top) + var(--s3));
  right: var(--s3);
  z-index: 2;
  background: var(--raised);
  border-radius: var(--r-pill);
}

.k-lbx-nav {
  position: absolute;
  top: 50%;
  z-index: 2;
  width: 44px;
  height: 44px;
  margin-top: -22px;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: rgba(31, 31, 36, 0.8);
  color: var(--text);
}

.k-lbx-nav--l { left: var(--s3); transform: scaleX(-1); }
.k-lbx-nav--r { right: var(--s3); }

/* ── Верхняя навигация ── */

.k-top { display: none; }

/* ── Широкий экран ── */

@media (min-width: 960px) {
  :root { --top-h: 64px; }

  /* Навигация переезжает наверх: док — орган большого пальца, на сайте его нет. */
  .k-dock { display: none !important; }

  .k-top {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: var(--s4);
    height: var(--top-h);
    padding: 0 max(var(--s6), calc((100vw - 1240px) / 2));
    background: rgba(14, 14, 17, 0.82);
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    border-bottom: var(--border-thin) solid var(--line-soft);
  }

  .k-top .k-logo { cursor: pointer; }
  .k-top-nav { display: flex; gap: var(--s1); margin-left: var(--s4); }

  .k-top-link {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    min-height: 38px;
    padding: 0 var(--s3);
    border-radius: var(--r-m);
    color: var(--text-dim);
    font-size: var(--t-small);
    font-weight: var(--fw-semibold);
    transition: background var(--dur-state), color var(--dur-state);
  }

  .k-top-link:hover { background: var(--raised); color: var(--text); }
  .k-top-link[aria-current="true"] { background: var(--card); color: var(--text); }

  .k-top-create {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    min-height: 38px;
    padding: 0 var(--s4);
    border-radius: var(--r-m);
    background: linear-gradient(180deg, var(--accent-hi), var(--accent));
    color: var(--accent-ink);
    font-size: var(--t-small);
    font-weight: var(--fw-bold);
    box-shadow: 0 2px 0 var(--accent-lo);
    transition: transform var(--dur-state), box-shadow var(--dur-state);
  }

  .k-top-create:active { transform: translateY(2px); box-shadow: none; }

  /* Контент центруется до 1240px; экран прокручивается ПОД полупрозрачной шапкой. */
  .k-screen {
    padding: calc(var(--top-h) + var(--s5)) max(var(--s6), calc((100vw - 1240px) / 2)) var(--s6);
  }

  /* Экраны-диалоги читаются колонкой: форма, выбор модели, редактор, подтверждение. */
  .k-screen[data-screen="model"],
  .k-screen[data-screen="models"],
  .k-screen[data-screen="prompt"],
  .k-screen[data-screen="payconfirm"],
  .k-screen[data-screen="creative"] {
    padding-left: max(var(--s6), calc((100vw - 760px) / 2));
    padding-right: max(var(--s6), calc((100vw - 760px) / 2));
  }

  /* Панель запуска стоит под своей колонкой, а не во всю ширину сайта. Фон — честная
     поверхность (как у шапки), а не градиент: на высоком экране под панелью прокручивается
     форма, и сквозь прозрачный верх её строки просвечивали бы под чипами параметров. */
  .k-launch {
    left: 50%;
    right: auto;
    transform: translateX(-50%);
    width: min(760px, 100%);
    padding-left: var(--s6);
    padding-right: var(--s6);
    padding-top: var(--s3);
    background: rgba(14, 14, 17, 0.88);
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    border: var(--border-thin) solid var(--line-soft);
    border-bottom: 0;
    border-radius: var(--r-l) var(--r-l) 0 0;
  }

  /* Герой: три анонса в ряд, ниже и шире телефонного. */
  .k-hero { grid-auto-flow: row; grid-auto-columns: unset; grid-template-columns: repeat(3, 1fr); overflow: visible; margin: 0; padding: 0; }
  .k-hero .k-cover { aspect-ratio: auto; height: 340px; }
  .k-hero .k-cover-t { font-size: 26px; }

  /* Сетки шире: карточки каталога и инструментов, история, кладка подборки. */
  .k-cards { grid-template-columns: repeat(3, 1fr); gap: var(--s3); }
  .k-cards--tools { grid-template-columns: repeat(6, 1fr); }
  .k-cards--tools .k-card-d { display: none; }
  .k-grid--3 { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
  .k-masonry { columns: 4; }
  .k-rail > * { width: 168px; }
  .k-rail--gal > * { width: auto; height: 280px; }
  .k-rail--sample > * { height: 168px; }
  .k-quick { max-width: 760px; }

  /* Логотип уже стоит в шапке сайта — вторая копия в раме экрана была бы эхом. */
  .k-screen[data-screen="home"] > .k-bar { display: none; }

  /* Кадр работы не должен упираться в потолок экрана. */
  .k-stage-img { max-height: calc(100dvh - var(--top-h) - 220px); }

  /* Лента истории — колонкой читаемой ширины. */
  .k-feed { max-width: 560px; margin: 0 auto; }
}

/* ── Окно входа гостя (блок 2 launch) ─────────────────────────────────────────
   Карточка поверх экрана тем же слоем, что лайтбокс: контекст не теряется — «Позже»,
   Esc и тап мимо возвращают ровно туда, где человек был. */
.k-signin { z-index: 70; }

.k-signin-card {
  display: grid;
  gap: var(--s4);
  justify-items: center;
  text-align: center;
  width: min(100%, 360px);
  padding: var(--s6) var(--s5);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-l);
}

.k-signin-card .k-go { width: 100%; min-height: 52px; text-decoration: none; }
.k-signin-card .k-btn { width: 100%; }

/* «Выйти» на профиле (только браузер): тихой кнопкой под денежной страницей. */
.k-signout { margin-top: var(--s4); display: grid; }
