/* ── Brand fonts ──────────────────────────────────────────────────────────── */
@font-face {
  font-family: 'HalvarBreit';
  src: url('/fonts/HalvarBreit-Bd.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'HalvarBreit';
  src: url('/fonts/HalvarBreit-Md.ttf') format('truetype');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'HalvarBreit';
  src: url('/fonts/HalvarBreit-Rg.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'HalvarBreit';
  src: url('/fonts/HalvarBreit-Lt.ttf') format('truetype');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Bahnschrift';
  src: url('/fonts/bahnschrift.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Bahnschrift';
  src: url('/fonts/bahnschrift-lt.ttf') format('truetype');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

/* ── Design tokens ────────────────────────────────────────────────────────── */
:root {
  /* Surfaces */
  --bg-root:     #0c0c0e;
  --bg-base:     #111113;
  --bg-elevated: #18181c;
  --bg-card:     #1e1e24;
  --bg-input:    #141418;
  --bg-hover:    #242430;

  /* Borders */
  --border:       rgba(255,255,255,0.08);
  --border-focus: rgba(255,255,255,0.22);
  --border-accent: rgba(249,31,121,0.35);

  /* Text */
  --text-primary:  #ededef;
  --text-secondary: #8a8f9a;
  --text-muted:    #52566a;
  --text-accent:   #F91F79;

  /* Accent — brand magenta */
  --accent:       #F91F79;
  --accent-dim:   rgba(249,31,121,0.12);
  --accent-glow:  rgba(249,31,121,0.18);

  /* Secondary accent — brand yellow */
  --accent2:      #FFF600;
  --accent2-dim:  rgba(255,246,0,0.10);

  /* Status colors */
  --status-idle:     #52566a;
  --status-pending:  #f5a623;
  --status-running:  #F91F79;
  --status-done:     #3ecf8e;
  --status-error:    #f25c5c;

  /* Spacing */
  --r-sm:   6px;
  --r-md:   10px;
  --r-lg:   14px;
  --r-xl:   18px;

  /* Typography scale */
  --text-sm: 12px;

  /* Space scale */
  --space-1: 4px;
  --space-2: 8px;

  /* Motion */
  --ease-out:   cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in:    cubic-bezier(0.4, 0, 1, 1);
  --dur-fast:   120ms;
  --dur-mid:    220ms;
  --dur-slow:   340ms;
}

/* ── Reset & base ─────────────────────────────────────────────────────────── */
/* Ссылки в админке: браузерный синий с подчёркиванием тут не к месту — почти
   каждая ссылка это либо кнопка, либо карточка со своим оформлением.
   Подчёркивание возвращаем на наведении, чтобы кликабельность не терялась. */
a {
  color: var(--text-accent);
  text-decoration: none;
}
a:hover { text-decoration: underline; }
a.btn:hover, .shot-card:hover, .category-row:hover { text-decoration: none; }

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

html, body {
  background: var(--bg-root);
  color: var(--text-primary);
  font-family: 'HalvarBreit', 'Bahnschrift', system-ui, sans-serif;
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

#root {
  /* Let #root grow naturally so the page scrolls via body/document */
  min-height: 100vh;
}

/* ── Typography scale ─────────────────────────────────────────────────────── */
h1 { font-family: 'HalvarBreit', system-ui, sans-serif; font-size: 22px; font-weight: 700; letter-spacing: -0.02em; }
h2 { font-family: 'HalvarBreit', system-ui, sans-serif; font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
h3 { font-family: 'HalvarBreit', system-ui, sans-serif; font-size: 13px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary); }

code, .mono { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 12px; }

/* ── Layout shell — DOCUMENT SCROLL pattern ───────────────────────────────── */
/*
  The shell is a grid that sizes to its content (no height:100%; overflow:hidden).
  The topbar uses position:sticky so it pins at the top as the page body scrolls.
  Result: the browser/body handles all vertical scrolling — no height-chain hacks.

  Боковой колонки больше нет: разделы переехали в строку шапки, а вся ширина
  окна отдана содержимому. На узком экране список сворачивается в бургер.
  Причина не в моде: страницы админки — таблицы кадров и сетки прогонов, им
  нужна ширина, а на телефоне колонка в 220px съедала половину экрана.
*/
.shell {
  display: grid;
  grid-template-rows: 48px auto;
  grid-template-areas:
    "header"
    "main";
  /* Якорь для чекбокса меню: он уведён за экран absolute'ом и должен
     считать края от каркаса, а не от случайного предка. */
  position: relative;
  /* No height/overflow constraints — let content grow naturally */
}

/* ── Topbar ───────────────────────────────────────────────────────────────── */
.topbar {
  grid-area: header;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 20px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-base);
  /* Stick to viewport top as the page scrolls */
  position: sticky;
  top: 0;
  z-index: 40;
}

.topbar-logo {
  font-family: 'HalvarBreit', system-ui, sans-serif;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--accent);
}

.topbar-sep { flex: 1; }

.topbar-cost {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px;
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: 6px;
}
.topbar-cost span {
  color: var(--text-secondary);
  font-weight: 500;
}
.topbar-cost .cost-value {
  color: var(--text-accent);
  font-weight: 600;
}

/* ── Разделы в шапке ──────────────────────────────────────────────────────── */
.topbar-nav {
  display: flex;
  align-items: center;
  gap: 2px;
}

.nav-item {
  padding: 6px 10px;
  border-radius: var(--r-md);
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.nav-item:hover { background: var(--bg-hover); color: var(--text-primary); }
.nav-item.active { background: var(--accent-dim); color: var(--accent); }

/* Чекбокс раскрытия — за экраном, но живой: display:none отнял бы у него
   фокус с клавиатуры вместе с доступом к меню без мыши. */
.nav-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.nav-burger {
  display: none;   /* включается под порогом, см. медиазапрос ниже */
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 32px;
  height: 32px;
  padding: 0 6px;
  border-radius: var(--r-md);
  cursor: pointer;
}
.nav-burger span {
  display: block;
  height: 2px;
  border-radius: 1px;
  background: var(--text-secondary);
  transition: background var(--dur-fast) var(--ease-out);
}
.nav-burger:hover span { background: var(--text-primary); }
/* Обводка по фокусу — на видимой метке, а не на уведённом за экран
   чекбоксе: иначе рамка рисуется в пустоте у края страницы. */
.nav-toggle:focus-visible + .topbar .nav-burger {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.nav-toggle:checked + .topbar .nav-burger span { background: var(--accent); }

/* Порог измерен, а не назначен на глаз: строка владельца (лого + пять
   разделов + расход) занимает 865px вместе с паддингами и зазорами. 900
   даёт запас в 35px и совпадает с порогом, который в этом файле уже
   работает, — второй заводить незачем. */
@media (max-width: 900px) {
  .nav-burger { display: flex; }
  /* Список уезжает из строки под шапку и раскрывается целиком: на телефоне
     горизонтальная прокрутка меню — это пункт, о котором не догадаешься. */
  .topbar-nav {
    display: none;
    position: absolute;
    top: 48px;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 6px;
    background: var(--bg-base);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
    z-index: 45;
  }
  .nav-toggle:checked + .topbar .topbar-nav { display: flex; }
  .nav-item { padding: 10px 12px; font-size: 14px; }
}

/* ── Main content — normal flow, no overflow tricks needed ────────────────── */
.main {
  grid-area: main;
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 24px;
  /* min-height: страница не должна складываться в полоску на пустом разделе */
  min-height: calc(100vh - 48px);
}

/* ── Buttons ──────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 7px 14px;
  border-radius: var(--r-md);
  font-family: 'HalvarBreit', system-ui, sans-serif;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  border: 1px solid transparent;
  transition:
    background var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out),
    opacity var(--dur-fast);
  user-select: none;
  white-space: nowrap;
}
.btn:active { transform: scale(0.97); }
.btn:disabled { opacity: 0.42; cursor: not-allowed; }
.btn:disabled:active { transform: none; }

.btn-primary {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.btn-primary:hover:not(:disabled) {
  background: #ff4096;
  border-color: #ff4096;
}

.btn-secondary {
  background: transparent;
  color: var(--text-primary);
  border-color: var(--border);
}
.btn-secondary:hover:not(:disabled) {
  background: var(--bg-hover);
  border-color: var(--border-focus);
}

.btn-ghost {
  background: transparent;
  color: var(--text-secondary);
  border-color: transparent;
}
.btn-ghost:hover:not(:disabled) { background: var(--bg-hover); color: var(--text-primary); }

.btn-danger {
  background: transparent;
  color: var(--status-error);
  border-color: rgba(242,92,92,0.3);
}
.btn-danger:hover:not(:disabled) {
  background: rgba(242,92,92,0.1);
  border-color: var(--status-error);
}

.btn-sm { padding: 4px 10px; font-size: 12px; }
.btn-lg { padding: 10px 20px; font-size: 14px; font-weight: 700; }

.btn-icon {
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: var(--r-sm);
}

/* ── Form elements ────────────────────────────────────────────────────────── */
.label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary);
  margin-bottom: 5px;
  letter-spacing: 0.02em;
}

.input, .select, .textarea {
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--text-primary);
  font-family: 'HalvarBreit', system-ui, sans-serif;
  font-size: 13px;
  padding: 8px 10px;
  outline: none;
  transition: border-color var(--dur-fast) var(--ease-out),
              background var(--dur-fast) var(--ease-out);
}
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--accent);
  background: var(--bg-elevated);
}
.input::placeholder, .textarea::placeholder { color: var(--text-muted); }

.textarea { resize: vertical; min-height: 80px; line-height: 1.6; }

.select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%238a8f9a' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  padding-right: 30px;
  cursor: pointer;
}
.select option { background: var(--bg-elevated); }

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

/* Строка догрузки: поле выбора занимает всю свободную ширину, кнопка сидит
   рядом. Отступ снизу больше обычного — иначе форма сращивается с сеткой уже
   загруженных кадров, и кнопка выглядит подписью к ней. */
.upload-row { display: flex; gap: 10px; align-items: center; margin-bottom: 28px; }
.upload-row .input { flex: 1; min-width: 0; }
.upload-row .btn { flex: none; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* ── Cards ────────────────────────────────────────────────────────────────── */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow: hidden;
}

.card-header {
  padding: 14px 16px 10px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 8px;
}

.card-body { padding: 16px; }

/* ── Brief panel ──────────────────────────────────────────────────────────── */
.brief-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
@media (min-width: 1200px) { .brief-grid { grid-template-columns: repeat(3, 1fr); } }

.brief-item {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 10px 12px;
}
.brief-item-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-muted);
  margin-bottom: 3px;
}
.brief-item-value {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary);
}
.brief-item-value.accent { color: var(--accent); }

/* ── Source gallery ───────────────────────────────────────────────────────── */
.source-gallery {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: flex-start;
}

.source-thumb {
  width: 72px;
  height: 72px;
  border-radius: var(--r-md);
  object-fit: cover;
  border: 1px solid var(--border);
  background: var(--bg-elevated);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.source-thumb:hover { border-color: var(--border-focus); }
/* Снимок посетителя открывается крупно по клику: курсор говорит об этом
   раньше подсказки. */
.source-thumb-link { display: inline-flex; cursor: zoom-in; }
.source-thumb.selected { border-color: var(--accent); outline: 2px solid var(--accent-glow); }

.source-placeholder {
  width: 72px;
  height: 72px;
  border-radius: var(--r-md);
  border: 1px dashed var(--border);
  background: var(--bg-elevated);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 11px;
  text-align: center;
  padding: 4px;
  cursor: default;
}

.upload-zone {
  width: 72px;
  height: 72px;
  border-radius: var(--r-md);
  border: 1px dashed var(--border-focus);
  background: var(--bg-elevated);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  cursor: pointer;
  color: var(--text-muted);
  font-size: 11px;
  transition: border-color var(--dur-fast) var(--ease-out),
              background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.upload-zone:hover {
  border-color: var(--accent);
  background: var(--accent-dim);
  color: var(--accent);
}
.upload-zone svg { width: 18px; height: 18px; }

/* ── Shot grid ────────────────────────────────────────────────────────────── */
.shot-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}

.shot-card {
  /* Карточка — ссылка, и без сброса браузер красит её текст своим синим и
     подчёркивает. Цвета внутри задают .shot-title и .shot-type. */
  color: inherit;
  text-decoration: none;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow: hidden;
  cursor: pointer;
  transition:
    border-color var(--dur-mid) var(--ease-out),
    transform var(--dur-mid) var(--ease-out),
    box-shadow var(--dur-mid) var(--ease-out);
  display: flex;
  flex-direction: column;
}
.shot-card:hover {
  border-color: var(--border-focus);
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.3);
}
.shot-card:active { transform: translateY(0); }

.shot-thumb-wrap {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--bg-elevated);
  overflow: hidden;
}
.shot-thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}
.shot-card:hover .shot-thumb { transform: scale(1.04); }

.shot-thumb-empty {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 11px;
  text-align: center;
  padding: 12px;
}

.shot-badge {
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 3px 8px;
  border-radius: 20px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  backdrop-filter: blur(6px);
}
/* Второй бейдж — строкой ниже первого: место у правого верхнего угла одно,
   а сказать надо две вещи. */
.shot-badge.second { top: 34px; }
/* В шапке карточки бейдж стоит В СТРОКЕ, а не поверх кадра: .card-header —
   это flex-ряд и сам никуда не позиционирован, поэтому absolute отсчитывался
   от ближайшего позиционированного предка (в пределе — от страницы) и уносил
   бейдж в её правый верхний угол. Правило общее, а не на страницу: шапок с
   бейджем уже десяток, и два из них теперь денежные — итог расходов
   (spend.html) и сумма по ленте примерок (tryons_admin.html), — а число,
   уехавшее из своей карточки, читается как чужое. */
.card-header .shot-badge { position: static; }
.shot-badge.idle    { background: rgba(82,86,106,0.7);    color: #bbbfc9; }
.shot-badge.pending { background: rgba(245,166,35,0.15);  color: var(--status-pending); border: 1px solid rgba(245,166,35,0.3); }
.shot-badge.running { background: rgba(249,31,121,0.15);  color: var(--accent); border: 1px solid rgba(249,31,121,0.35); animation: pulse-badge 1.4s ease-in-out infinite; }
.shot-badge.done    { background: rgba(62,207,142,0.12);  color: var(--status-done); border: 1px solid rgba(62,207,142,0.3); }
.shot-badge.error   { background: rgba(242,92,92,0.12);   color: var(--status-error); border: 1px solid rgba(242,92,92,0.25); }

@keyframes pulse-badge {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

.shot-meta {
  padding: 10px 12px 12px;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.shot-type {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
.shot-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
}
.shot-prompt-preview {
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.4;
  margin-top: 2px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* ── Drawer (slide-over) — kept for legacy; modal replaces it ─────────────── */
.drawer-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.55);
  z-index: 80;
  animation: fade-in var(--dur-mid) var(--ease-out);
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 520px;
  max-width: 95vw;
  background: var(--bg-base);
  border-left: 1px solid var(--border);
  z-index: 90;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: slide-in var(--dur-slow) var(--ease-out);
}
@keyframes slide-in {
  from { transform: translateX(100%); opacity: 0.6; }
  to   { transform: translateX(0);    opacity: 1; }
}

.drawer-header {
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.drawer-header-info { flex: 1; min-width: 0; }
.drawer-header-type {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 3px;
}
.drawer-header-title {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.drawer-body {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.drawer-footer {
  padding: 14px 20px;
  border-top: 1px solid var(--border);
  display: flex;
  gap: 8px;
  align-items: center;
}
.drawer-footer-sep { flex: 1; }

.drawer-section { display: flex; flex-direction: column; gap: 8px; }
.drawer-section-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ── Shot modal (large centered lightbox) ─────────────────────────────────── */
.shot-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  animation: fade-in var(--dur-mid) var(--ease-out);
}

.shot-modal {
  position: relative;
  width: min(1100px, 92vw);
  height: 88vh;
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  animation: modal-rise var(--dur-slow) var(--ease-out);
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.04) inset,
    0 32px 80px rgba(0,0,0,0.6),
    0 8px 24px rgba(0,0,0,0.4);
}
@keyframes modal-rise {
  from { transform: translateY(20px) scale(0.975); opacity: 0; }
  to   { transform: translateY(0)    scale(1);     opacity: 1; }
}

/* Modal header — slim bar across full width */
.shot-modal-header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-elevated);
}
.shot-modal-header-info { flex: 1; min-width: 0; }
.shot-modal-header-type {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 2px;
}
.shot-modal-header-title {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Modal body — two-column layout */
.shot-modal-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 62% 38%;
}

/* ── Left column: big image pane ── */
.shot-modal-image-col {
  display: flex;
  flex-direction: column;
  background: var(--bg-root);
  border-right: 1px solid var(--border);
  overflow: hidden;
}

.shot-modal-big-image-wrap {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  position: relative;
  overflow: hidden;
}

.shot-modal-big-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: var(--r-md);
  display: block;
  cursor: zoom-in;
  transition: transform var(--dur-mid) var(--ease-out);
}
.shot-modal-big-image.zoomed {
  cursor: zoom-out;
}

/* Zoom overlay (full-bleed) */
.shot-modal-zoom-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(0,0,0,0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: zoom-out;
  animation: fade-in var(--dur-fast) var(--ease-out);
}
.shot-modal-zoom-overlay img {
  max-width: 98vw;
  max-height: 98vh;
  object-fit: contain;
  border-radius: var(--r-sm);
  pointer-events: none;
  user-select: none;
}

/* Empty / generating state inside image pane */
.shot-modal-image-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  color: var(--text-muted);
  font-size: 13px;
  text-align: center;
  padding: 24px;
  width: 100%;
  height: 100%;
}
.shot-modal-image-empty.generating {
  color: var(--accent);
}

/* Filmstrip (thumbnails) under the big image */
.shot-modal-filmstrip {
  flex-shrink: 0;
  border-top: 1px solid var(--border);
  padding: 10px 14px;
  display: flex;
  gap: 8px;
  overflow-x: auto;
  background: var(--bg-elevated);
}
.shot-modal-filmstrip:empty { display: none; }

.shot-modal-thumb {
  flex-shrink: 0;
  width: 60px;
  height: 60px;
  border-radius: var(--r-sm);
  object-fit: cover;
  border: 2px solid transparent;
  cursor: pointer;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
  background: var(--bg-card);
}
.shot-modal-thumb:hover { transform: scale(1.06); }
.shot-modal-thumb.active {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-glow);
}

/* ── Right column: controls panel ── */
.shot-modal-controls-col {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.shot-modal-controls-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.shot-modal-controls-footer {
  flex-shrink: 0;
  padding: 12px 18px;
  border-top: 1px solid var(--border);
  background: var(--bg-elevated);
  display: flex;
  gap: 8px;
  align-items: center;
}
.shot-modal-controls-footer-sep { flex: 1; }

/* Section styling within modal right col — reuse drawer-section vocabulary */
.shot-modal-section { display: flex; flex-direction: column; gap: 8px; }
.shot-modal-section-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Render list rows (reuse render-item but allow overflow in right col) */
.shot-modal-render-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Generating state indicator inside right panel */
.shot-modal-running-bar {
  height: 2px;
  flex-shrink: 0;
  background: linear-gradient(90deg, transparent, var(--accent), var(--accent2), transparent);
  background-size: 200% 100%;
  animation: render-progress 1.6s linear infinite;
}
.shot-modal-running-label {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 18px;
  background: rgba(249,31,121,0.06);
  border-bottom: 1px solid rgba(249,31,121,0.15);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--accent);
  flex-shrink: 0;
}
.shot-modal-running-label .spinner {
  width: 12px;
  height: 12px;
  border-width: 1.5px;
  border-top-color: var(--accent);
}

/* ── Refine bar ───────────────────────────────────────────────────────────── */
.refine-row {
  display: flex;
  gap: 8px;
  align-items: flex-end;
}
.refine-row .input { flex: 1; }

/* ── Variant strip ────────────────────────────────────────────────────────── */
.variant-strip {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.render-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.render-item.chosen { border-color: var(--border-accent); }
.render-item-thumb {
  width: 48px;
  height: 48px;
  border-radius: var(--r-sm);
  object-fit: cover;
  background: var(--bg-card);
  flex-shrink: 0;
}
.render-item-info { flex: 1; min-width: 0; }
.render-item-res {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-primary);
}
.render-item-cost {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  color: var(--text-muted);
}
.render-item-chosen-mark {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
  padding: 2px 7px;
  border: 1px solid var(--border-accent);
  border-radius: 12px;
}

/* ── Resolution selector ──────────────────────────────────────────────────── */
.resolution-row {
  display: flex;
  gap: 8px;
  align-items: center;
}

/* ── Spinner / loading ────────────────────────────────────────────────────── */
.spinner {
  width: 16px;
  height: 16px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  flex-shrink: 0;
}
.spinner-lg {
  width: 28px;
  height: 28px;
  border-width: 3px;
}
@keyframes spin { to { transform: rotate(360deg); } }

.loading-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(12,12,14,0.7);
  backdrop-filter: blur(4px);
  z-index: 10;
}

/* ── Empty / zero states ──────────────────────────────────────────────────── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 48px 24px;
  color: var(--text-muted);
  text-align: center;
}
.empty-state h2 { color: var(--text-secondary); font-size: 15px; }
.empty-state p { font-size: 13px; max-width: 280px; line-height: 1.6; }

/* ── Toast notifications ──────────────────────────────────────────────────── */
.toast-container {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}

.toast {
  padding: 10px 14px;
  border-radius: var(--r-lg);
  font-size: 13px;
  font-weight: 500;
  backdrop-filter: blur(8px);
  border: 1px solid;
  animation: toast-in var(--dur-mid) var(--ease-out);
  pointer-events: all;
  max-width: 320px;
}
.toast.success { background: rgba(62,207,142,0.12);  color: var(--status-done);    border-color: rgba(62,207,142,0.3); }
.toast.error   { background: rgba(242,92,92,0.12);   color: var(--status-error);   border-color: rgba(242,92,92,0.25); }
.toast.info    { background: rgba(249,31,121,0.10);  color: var(--accent);          border-color: rgba(249,31,121,0.25); }
@keyframes toast-in { from { transform: translateY(12px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

/* ── New project dialog ───────────────────────────────────────────────────── */
.dialog-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.65);
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: fade-in var(--dur-mid) var(--ease-out);
}

.dialog {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: 24px;
  width: 480px;
  max-width: 92vw;
  max-height: 90vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
  animation: dialog-in var(--dur-slow) var(--ease-out);
}
@keyframes dialog-in {
  from { transform: translateY(16px) scale(0.98); opacity: 0; }
  to   { transform: translateY(0) scale(1); opacity: 1; }
}

.dialog h2 { font-size: 17px; }

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 4px;
}

/* ── Ref image picker (in drawer) ────────────────────────────────────────── */
.ref-picker {
  display: grid;
  /* Было 88px, потом 168px: на карточке кольца в мелкой плитке не разглядеть
     ни огранку, ни число камней — а выбор ровно об этом и есть. */
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
}

.ref-thumb-btn {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-md);
  border: 2px solid var(--border);
  background: var(--bg-elevated);
  overflow: hidden;
  cursor: pointer;
  padding: 0;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}
.ref-thumb-btn:hover {
  border-color: var(--border-focus);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0,0,0,0.25);
}
.ref-thumb-btn.selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent-glow), 0 4px 12px rgba(0,0,0,0.25);
}
.ref-thumb-btn img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
  user-select: none;
}
.ref-thumb-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 10px;
}
.ref-thumb-check {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(249, 31, 121, 0.20);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out);
  pointer-events: none;
}
.ref-thumb-btn.selected .ref-thumb-check { opacity: 1; }
.ref-thumb-check svg { filter: drop-shadow(0 1px 3px rgba(0,0,0,0.5)); }
.ref-thumb-name {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 14px 4px 4px;
  font-size: 9px;
  font-weight: 500;
  color: #fff;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  background: linear-gradient(to bottom, transparent, rgba(0,0,0,0.6));
  pointer-events: none;
  letter-spacing: 0.01em;
}

/* ── Shot multi-select ───────────────────────────────────────────────────── */
.shot-card-checkbox {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 4;
  width: 20px;
  height: 20px;
  border-radius: var(--r-sm);
  border: 1.5px solid rgba(255,255,255,0.35);
  background: rgba(12, 12, 14, 0.65);
  backdrop-filter: blur(4px);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out),
    opacity var(--dur-fast) var(--ease-out);
  opacity: 0;
}
.shot-card:hover .shot-card-checkbox,
.shot-card-checkbox.checked {
  opacity: 1;
}
.shot-card-checkbox.checked {
  background: var(--accent);
  border-color: var(--accent);
}
.shot-card-checkbox.checked svg { display: block; }
.shot-card-checkbox svg { display: none; }
.shot-card.selected-card {
  border-color: var(--border-accent);
  box-shadow: 0 0 0 1px var(--accent-glow);
}

/* ── Shots toolbar (batch actions) ──────────────────────────────────────── */
.shots-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.shots-toolbar-select-all {
  font-family: 'HalvarBreit', system-ui, sans-serif;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  transition: color var(--dur-fast);
}
.shots-toolbar-select-all:hover { color: var(--text-primary); }
.shots-toolbar-sep { flex: 1; }
.shots-toolbar-deselect {
  font-family: 'HalvarBreit', system-ui, sans-serif;
  font-size: 12px;
  color: var(--text-muted);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  transition: color var(--dur-fast);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: transparent;
}
.shots-toolbar-deselect:hover {
  color: var(--text-secondary);
  text-decoration-color: var(--text-muted);
}

/* ── Scrollbar ────────────────────────────────────────────────────────────── */
::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.18); }

/* ── Divider ──────────────────────────────────────────────────────────────── */
.divider { border: none; border-top: 1px solid var(--border); }

/* ── Inset badge (for source names) ──────────────────────────────────────── */
.inset-name {
  position: absolute;
  bottom: 4px;
  left: 0;
  right: 0;
  font-size: 9px;
  text-align: center;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0 3px;
}

/* ── Async render shimmer / progress ──────────────────────────────────────── */
@keyframes shimmer-scan {
  0%   { transform: translateX(-100%) skewX(-8deg); }
  100% { transform: translateX(250%) skewX(-8deg); }
}
.shot-thumb-wrap.generating::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  background: linear-gradient(105deg, transparent 35%, rgba(249,31,121,0.15) 50%, rgba(255,246,0,0.06) 55%, transparent 65%);
  animation: shimmer-scan 1.8s ease-in-out infinite;
}
.shot-thumb-wrap.generating .shot-thumb-empty { opacity: 0.6; }

@keyframes render-progress {
  0%   { background-position: -200% 0; }
  100% { background-position:  200% 0; }
}
.render-in-progress-bar {
  height: 2px;
  flex-shrink: 0;
  background: linear-gradient(90deg, transparent, var(--accent), var(--accent2), transparent);
  background-size: 200% 100%;
  animation: render-progress 1.6s linear infinite;
}
.render-status-label {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 20px;
  background: rgba(249,31,121,0.06);
  border-bottom: 1px solid rgba(249,31,121,0.15);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--accent);
}
.render-status-label .spinner {
  width: 12px;
  height: 12px;
  border-width: 1.5px;
  border-top-color: var(--accent);
}

/* ── Reduced motion ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ── Медиа товара: сетка, увеличение по клику ──────────────────────────────
   JS в проекте нет, поэтому увеличение сделано на :target — клик по кадру
   ставит #media-N в адрес, оверлей всплывает. Работает кнопка «назад»,
   ссылку на открытый кадр можно послать. */

.media-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}

.media-card {
  margin: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--bg-elevated);
  overflow: hidden;
}

/* Живые кадры перетаскиваются — место в ленте и есть номер референса
   (static/media-order.js). */
.media-card[draggable="true"] { cursor: grab; }
.media-card.is-dragging { opacity: .35; }
.media-order-status { margin-left: 12px; font-size: 13px; color: var(--text-secondary); }
.media-order-status.is-bad { color: var(--status-error); }

.media-card-link {
  display: block;
  aspect-ratio: 1 / 1;
  background: var(--bg-input);
  cursor: zoom-in;
}

.media-card-link img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.media-card-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px;
  border-top: 1px solid var(--border);
}

.media-card-kind {
  font-size: 12px;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.media-card.is-reference {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent-glow);
}

.media-card-pick {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
}

.media-card.is-reference .media-card-pick { color: var(--text-accent); }

.media-card-pick input { accent-color: var(--accent); cursor: pointer; }

.media-actions { margin-top: 14px; }

.card-header-hint {
  font-size: 12px;
  color: var(--text-muted);
  max-width: 62ch;
}

.media-lightbox {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 60;
  padding: 24px;
  align-items: center;
  justify-content: center;
}

.media-lightbox:target { display: flex; }

.media-lightbox-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0.82);
  cursor: zoom-out;
}

.media-lightbox-inner {
  position: relative;
  margin: 0;
  max-width: min(1100px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.media-lightbox-inner img {
  max-width: 100%;
  /* Оставляем место подписи под кадром, иначе на невысоком экране кнопка
     удаления уезжает за край и до неё не дотянуться. */
  max-height: calc(100vh - 140px);
  object-fit: contain;
  border-radius: var(--r-md);
  background: var(--bg-base);
}

.media-lightbox-inner figcaption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  font-size: 13px;
  color: var(--text-secondary);
}

.media-lightbox-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* ── Строка категории в списке промптов ────────────────────────────────────
   Вся строка — ссылка, поэтому отдельной кнопки «Открыть» нет. Название
   набрано крупно: в списке из трёх категорий именно по нему целятся. */

.category-row {
  display: block;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--bg-elevated);
  color: inherit;
  text-decoration: none;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
}

.category-row + .category-row { margin-top: 10px; }

.category-row:hover {
  border-color: var(--border-focus);
  background: var(--bg-hover);
}

.category-row-name {
  display: block;
  font-family: 'HalvarBreit', system-ui, sans-serif;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  margin-bottom: 6px;
}

.category-row:hover .category-row-name { color: var(--text-accent); }

.category-row-name .mono {
  font-size: 13px;
  font-weight: 400;
  color: var(--text-muted);
}

.category-row-meta {
  display: block;
  font-size: 12px;
  color: var(--text-secondary);
}

/* ── Переключатель версий промпта в строке названия ────────────────────────
   Живёт в card-header рядом с названием: версии раньше были отдельной
   карточкой ниже, и чтобы заглянуть в предыдущую, приходилось прокручивать
   мимо всего текста промпта. */

.version-switch {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.input-sm {
  padding: 5px 8px;
  font-size: 12px;
  max-width: 420px;
}

/* Шапка карточки может переноситься: подписи версий с заметкой и датой
   длинные, и на узком экране им нужна вторая строка, а не горизонтальная
   прокрутка всей страницы. */
.card-header { flex-wrap: wrap; row-gap: 8px; }

/* ── Выбор карточек мышью без JS ───────────────────────────────────────────
   Чекбокс раньше был hidden, а подсветка приходила классом с сервера: клик по
   карточке не давал никакого отклика до отправки формы, и выбор выглядел
   неработающим. Теперь чекбокс видимый, а рамка реагирует на :checked. */

.pick-card input[type="checkbox"] {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 2;
  width: 18px;
  height: 18px;
  accent-color: var(--accent);
  cursor: pointer;
}

.pick-card:has(input:checked) {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent-glow), 0 4px 12px rgba(0,0,0,0.25);
}

.pick-card:has(input:checked) .ref-thumb-name {
  background: var(--accent);
  color: #fff;
}

/* ── Индикатор фоновой работы ──────────────────────────────────────────────
   Задача уходит в очередь и считается воркером; страница обновляет себя сама
   (meta refresh), а здесь видно, что счёт идёт, — иначе экран выглядит
   мёртвым и оператор жмёт кнопку второй раз. */

.busy-note {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  margin-bottom: 14px;
  border: 1px solid var(--border-accent);
  border-radius: var(--r-md);
  background: var(--accent-dim);
  color: var(--text-secondary);
  font-size: 13px;
}

.btn .spinner {
  width: 12px;
  height: 12px;
  border-width: 1.5px;
}

.btn:disabled { opacity: 0.55; cursor: default; }

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

.compare-row {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(220px, 1fr);
  gap: 20px;
  align-items: start;
}

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

.compare-image {
  width: 100%;
  border-radius: var(--r-md);
  background: var(--bg-base);
}


.compare-shots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 8px;
  margin-top: 8px;
}

.compare-shot {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-input);
}

/* ── Результат прогона крупно, оригинал столбиком справа ───────────────────
   Мелкая плитка не давала разглядеть ни огранку камня, ни цвет шинки — а
   проверяют в песочнице именно их. */

.result-block {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 182px;
  gap: 16px;
  align-items: start;
  padding: 16px 0;
  border-top: 1px solid var(--border);
}

.result-block:first-child { border-top: none; padding-top: 0; }

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

/* Оригиналы тянутся на всю высоту результата и прокручиваются внутри неё.
   Результат остаётся как был — крупным, во всю ширину карточки; а столбик
   кадров товара рядом с ним раньше кончался на третьем-четвёртом, и до
   остальных приходилось листать страницу, теряя из виду то, с чем сличаешь.
   Высоту строки задаёт результат, поэтому столбику довольно align-self:
   stretch и min-height: 0 — без него grid не даст блоку сжаться и прокрутка
   не появится. */

.result-side {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-self: stretch;
  min-height: 0;
  overflow-y: auto;
}

@media (max-width: 900px) {
  /* В одну колонку тянуть не за чем: результат стоит выше, а не рядом. */
  .result-side { overflow-y: visible; }
}

.result-main .label,
.result-side .label,
.result-input .label {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}

.result-input { max-width: 220px; }

/* ── Выброшенный кадр ──────────────────────────────────────────────────────
   Половинная непрозрачность, как просил владелец: кадр видно, но видно и то,
   что он выбыл. Приглушаем только изображение — подпись под ним объясняет
   ПОЧЕМУ кадр выброшен, и её как раз надо читать. */

.media-card.is-discarded img { opacity: 0.5; }
.media-card.is-discarded { border-style: dashed; }

.media-card-gone {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  color: var(--text-muted);
  background: var(--bg-input);
}

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

   Увеличенная копия — отдельный элемент, а не тот же самый в position:fixed:
   уехав из-под курсора, он потерял бы наведение, вернулся на место и замигал
   бы с частотой мыши. По той же причине у копии pointer-events:none — иначе
   она перекрыла бы собой плитку, с которой всё началось.

   Фон у копии непрозрачный: кадры товара сняты на белом, а по краям
   object-fit:contain оставляет поля, сквозь которые просвечивал бы текст
   страницы. */

.peek { position: relative; display: block; }
.peek-full { display: none; }

.peek:hover .peek-full {
  display: block;
  position: fixed;
  top: 2vh;
  left: 2vw;
  width: 96vw;
  height: 96vh;
  object-fit: contain;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.6);
  pointer-events: none;
  z-index: 80;
}

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

details > summary {
  cursor: pointer;
  user-select: none;
  display: inline-block;
  padding: 4px 0;
}

details > summary:hover { color: var(--text-primary); }

details[open] > summary { margin-bottom: 8px; }

/* ── AR-сцена ──────────────────────────────────────────────────────────────
   Видео и канвас лежат друг на друге: видео снизу как фон, канвас сверху с
   прозрачным фоном. Оба растягиваются по ширине карточки. */

.ar-stage {
  position: relative;
  width: 100%;
  max-width: 720px;
  aspect-ratio: 3 / 4;
  background: var(--bg-input);
  border-radius: var(--r-md);
  overflow: hidden;
}

.ar-stage video,
.ar-stage canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ar-status {
  margin-top: 12px;
  font-size: 13px;
  color: var(--text-secondary);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
}

/* Переключатель разворота кольца — нажатое состояние подсвечено акцентом,
   как и другие переключатели в проекте (.pick-card:has(input:checked) и
   т.п.), текст кнопки при этом не меняется: ширина кнопки не прыгает. */
.ar-flip-toggle.active {
  color: var(--accent);
  border-color: var(--border-accent);
  background: var(--accent-dim);
}

/* ── Панель подстройки посадки (примерка) ─────────────────────────────────
   Кнопка и панель лежат внутри .ar-stage и позиционированы относительно
   него абсолютно — на десктопе это угол видео-карточки, на телефоне (где
   .ar-stage растягивается на весь экран, см. медиа-запрос ниже) тот же
   код без единой правки становится углом экрана. Фон и блюр — тот же
   приём, что у .ar-status и мобильных ar-back-link/ar-flip-toggle:
   полупрозрачная тёмная подложка читается что на светлой коже, что на
   тёмном фоне видео. */
.ar-fit-toggle {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 15;
  background: rgba(12,12,14,0.62);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-color: rgba(255,255,255,0.18);
}

.ar-fit-panel {
  position: absolute;
  right: 10px;
  bottom: 52px;
  z-index: 16;
  width: min(260px, calc(100% - 20px));
  max-height: min(60vh, 320px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  border-radius: var(--r-md);
  background: rgba(12,12,14,0.78);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,0.18);
}

.ar-fit-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.ar-fit-row label,
.ar-fit-label {
  flex: 1;
  font-size: 12px;
  color: var(--text-secondary);
}

/* Высота больше видимого трека — у нативного range зона захвата пальцем
   равна высоте самого элемента, а не только тонкой полоски дорожки. */
.ar-fit-row input[type="range"] {
  flex: 1.6;
  accent-color: var(--accent);
  height: 24px;
}

.ar-fit-value {
  min-width: 3.4em;
  text-align: right;
  font-size: 12px;
  color: var(--text-primary);
}

.ar-fit-switch.active {
  color: var(--accent);
  border-color: var(--border-accent);
  background: var(--accent-dim);
}

/* ── Стенд материалов ─────────────────────────────────────────────────────
   Кольцо и фото товара рядом, крупно — плитка ужимает деталь до
   нечитаемости, а сравнивают именно огранку и цвет. На узком экране
   складываются в столбец, тот же приём, что у .compare-row в песочнице. */
.bench-compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  align-items: start;
}
@media (max-width: 900px) {
  .bench-compare { grid-template-columns: 1fr; }
}

.bench-stage {
  width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
}
.bench-stage canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.bench-photo {
  width: 100%;
  height: auto;
  aspect-ratio: auto;
}

.bench-controls {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 16px;
  padding: 14px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}

.bench-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.bench-row label,
.bench-row .ar-fit-label {
  flex: 0 0 200px;
  font-size: 12px;
  color: var(--text-secondary);
}
/* Побольше высоты — тот же довод, что у .ar-fit-row input[type="range"]:
   ползунки стенда должны быть удобны пальцу на телефоне. */
.bench-row input[type="range"] {
  flex: 1;
  accent-color: var(--accent);
  height: 24px;
}
@media (max-width: 480px) {
  .bench-row { flex-wrap: wrap; }
  .bench-row label,
  .bench-row .ar-fit-label { flex-basis: 100%; }
}

.bench-summary {
  margin-top: 16px;
}
.bench-summary-row {
  display: flex;
  gap: 8px;
}
.bench-summary-row .input {
  flex: 1;
}

/* Панель диагностики стенда — свёрнута за .label-ссылкой (details/summary,
   тот же приём, что и у шаблона промпта в sandbox_batch.html), текст внутри
   должен читаться со снимка экрана, поэтому шрифт задан явно моноширинным,
   а не через .mono: у .textarea выше тот же уровень специфичности и более
   позднее правило font-family — класс .mono молча проиграл бы каскад. */
.bench-diagnostics {
  margin-top: 16px;
}
.bench-diagnostics-text {
  margin-top: 8px;
  padding: 12px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px;
  line-height: 1.6;
  color: var(--text-primary);
  white-space: pre-wrap;
  word-break: break-word;
}

/* ── AR-примерка на телефоне: экран целиком под примерку ─────────────────
   Владелец открывает страницу на телефоне, и обвязка админки (шапка,
   сайдбар, заголовки) там только отнимает место у видео — которое и есть
   единственная причина открыть страницу. На компьютере это рабочая
   админка, её трогать нельзя, поэтому всё ниже живёт строго внутри
   медиа-запроса.

   Порог — по ШИРИНЕ ИЛИ ПО ВЫСОТЕ (640 / 480), а не только по ширине: при
   повороте телефона в альбомную ориентацию его короткая сторона (высота)
   становится меньше типичной ширины десктопного окна, а длинная (ширина)
   может превысить обычный мобильный порог в 640px. Если проверять только
   ширину, полноэкранный режим слетал бы ровно в момент поворота, который
   по спеке как раз должен быть обработан. 480 для высоты — с запасом ниже
   короткой стороны любого телефона (обычно 350–430px) и настолько же ниже
   типичной высоты окна ноутбука (обычно от 650px и выше), чтобы не
   схватить в этот режим просто невысокое окно браузера на компьютере. */
@media (max-width: 640px), (max-height: 480px) {
  /* .shell описан в base.html, который эта задача трогать не должна —
     :has() дотягивается до него от .ar-page (маркер в ar.html) снаружи,
     без единой правки base.html. */
  .shell:has(.ar-page) {
    display: block;
    height: 100dvh;
    overflow: hidden;
  }
  /* Шапка прячется целиком, и вместе с ней разделы — они теперь внутри неё,
     а боковой колонки больше нет. */
  .shell:has(.ar-page) .topbar {
    display: none;
  }
  .shell:has(.ar-page) .main {
    padding: 0;
    gap: 0;
    min-height: 0;
    height: 100dvh;
    overflow: hidden;
  }

  /* dvh, а не vh: на мобильных браузерах панель адреса выезжает и
     скрывается, и vh то оставляет полосу пустоты снизу, то обрезает кадр —
     см. спеку задачи. Здесь же убираем прокрутку и «пружину» (bounce):
     скроллить в примерке нечего, а resize/scroll на растянутом теле
     страницы — источник как раз того дребезга, который просили убрать. */
  html:has(.ar-page), body:has(.ar-page) {
    height: 100dvh;
    overflow: hidden;
    overscroll-behavior: none;
  }

  .ar-page { height: 100dvh; }

  .ar-card {
    height: 100dvh;
    border: none;
    border-radius: 0;
    background: transparent;
  }
  .ar-card .card-body {
    padding: 0;
    height: 100%;
  }

  /* Подсказку прячем — экран занят примеркой, а не текстом инструкции. */
  .ar-hint { display: none; }

  /* Заголовок карточки на телефоне не показываем — но не через display:none
     на всём .card-header: внутри него лежат ссылка «К товару» и переключатель
     разворота, которым ниже назначена фиксированная позиция поверх видео, а
     фиксированная позиция не спасает потомков от display:none на родителе.
     Поэтому прячем только текст и разделитель, а сам контейнер остаётся
     пустой рамкой без отступов и границы. */
  .ar-card .card-header {
    padding: 0;
    border: none;
    background: transparent;
    flex-wrap: nowrap;
  }
  .ar-card .card-header h2,
  .ar-card .card-header .topbar-sep {
    display: none;
  }
  .ar-card .card-header .ar-back-link,
  .ar-card .card-header .ar-flip-toggle {
    position: fixed;
    top: 10px;
    z-index: 20;
    background: rgba(12,12,14,0.62);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-color: rgba(255,255,255,0.18);
  }
  .ar-card .card-header .ar-back-link { left: 10px; }
  .ar-card .card-header .ar-flip-toggle { right: 10px; }

  /* Видео и канвас — на весь экран. object-fit: cover (общий для .ar-stage
     video/canvas, см. выше) при этом кадрирует картинку по короткой
     стороне: соотношение сторон видео (то, что даёт камера) почти никогда
     не совпадёт с соотношением сторон экрана телефона. Решение — кадрировать,
     а не оставлять чёрные полосы (object-fit: contain): владелец просил
     именно «весь экран под примерку», и пустые поля по бокам в это
     требование не укладываются. Видео и канвас кадрируются ОДИНАКОВО (у
     обоих одна и та же внутренняя ширина/высота — она приходит из
     video.videoWidth/videoHeight, см. scene.js:resize и app.js:onHand),
     поэтому кольцо не съезжает относительно руки от самого кадрирования —
     съехать может только та часть кадра, что вообще обрежется по краю. */
  .ar-stage {
    position: fixed;
    inset: 0;
    width: 100dvw;
    height: 100dvh;
    max-width: none;
    aspect-ratio: auto;
    border-radius: 0;
  }

  /* Панель статуса — накладка поверх видео понизу, а не строка под ним:
     на телефоне ей больше негде быть, а это единственный источник сведений
     о происходящем (владелец консоль не откроет). Полупрозрачный тёмный фон
     и светлый текст читаются что на светлой коже, что на тёмном фоне —
     тот же приём, что у .shot-modal-overlay и других накладок в проекте. */
  .ar-status {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 20;
    margin: 0;
    padding: 10px 14px;
    background: rgba(12,12,14,0.62);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: var(--text-primary);
  }

  /* На телефоне .ar-status — своя накладка на всю ширину внизу экрана (см.
     выше), и угловая кнопка/панель подстройки посадки на той же высоте её
     перекрыла бы. Сдвигаем обе выше строки статуса. */
  .ar-fit-toggle { bottom: 54px; }
  .ar-fit-panel { bottom: 96px; }
}

/* Готовые картинки прогона в списке прогонов — под его параметрами.
   Полоса не переносится и прокручивается: в прогоне может быть и двадцать
   ячеек, а строка списка должна оставаться строкой. */
.batch-thumbs {
  display: flex;
  align-items: center;
  gap: 6px;
  overflow-x: auto;
  padding: 8px 0 2px;
}
.batch-thumb-wrap { flex: none; display: inline-flex; }
.batch-thumb {
  height: 224px;
  width: auto;
  border-radius: 6px;
  border: 1px solid var(--border);
  display: block;
}

/* Быстрый взгляд по наведению. Положение фиксированное, по центру экрана,
   а не рядом с миниатюрой: полоса прокручивается и обрезает всё, что
   вылезает за её края. Кликов не ловит: на нём ничего нажимать не надо,
   а перехват мыши мешал бы навести на соседнюю миниатюру. */
.batch-thumb-zoom {
  display: none;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  max-height: 88vh;
  max-width: 88vw;
  z-index: 100;
  border-radius: 8px;
  border: 1px solid var(--border);
  box-shadow: 0 24px 64px rgba(0, 0, 0, .55);
  pointer-events: none;
}
.batch-thumb-wrap:hover .batch-thumb-zoom { display: block; }
/* Пока открыт закреплённый просмотр, беглый показ по наведению не нужен:
   две большие картинки друг на друге — это уже не просмотр. */
body.pinned-open .batch-thumb-wrap:hover .batch-thumb-zoom { display: none; }

/* Закреплённый просмотр по щелчку. Появился потому, что на картинке,
   показанной по наведению, нельзя было нажать отметку: увести туда мышь —
   значит увести её с миниатюры, и картинка исчезала. */
.pinned {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: rgba(0, 0, 0, .82);
}
.pinned[hidden] { display: none; }
.pinned img {
  max-height: 82vh;
  max-width: 92vw;
  border-radius: 8px;
  border: 1px solid var(--border);
}
.pinned-bar { display: flex; gap: 10px; align-items: center; }
.pinned-bar .okay-mark { position: static; font-size: 15px; padding: 9px 20px; }
.pinned-hint { color: #9a9a9a; font-size: 13px; }

/* Прелоадер: пока в прогоне что-то считается, в полосе крутится кольцо. */
.batch-spinner {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 3px solid var(--border);
  border-top-color: var(--border-accent, #888);
  animation: batch-spin 900ms linear infinite;
}
@keyframes batch-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .batch-spinner { animation-duration: 3s; }
}

/* Отметка «годится» на превью генерации. Три состояния: не смотрел,
   годится, не годится — по кругу щелчком. Кнопка лежит поверх картинки в
   углу: место на превью дороже, чем отдельная строка под ним. */
.batch-thumb-wrap { position: relative; }
.okay-mark {
  position: absolute;
  left: 6px;
  bottom: 6px;
  z-index: 2;
  font: inherit;
  font-size: 12px;
  line-height: 1;
  padding: 5px 9px;
  border-radius: 999px;
  cursor: pointer;
  border: 1px solid var(--border);
  background: rgba(20, 20, 20, .72);
  color: #d8d8d8;
}
.okay-mark:hover { border-color: var(--border-accent, #888); }
[data-gen-okay="1"] .okay-mark {
  background: #1c6b3a;
  border-color: #2f9c58;
  color: #eaffe9;
}
[data-gen-okay="0"] .okay-mark {
  background: #6b1c1c;
  border-color: #9c2f2f;
  color: #ffeaea;
}
[data-gen-okay="1"] .batch-thumb { border-color: #2f9c58; }
[data-gen-okay="0"] .batch-thumb { opacity: .55; }

/* Оригинал гостя в ленте примерок: миниатюра рядом с результатом, при
   наведении или фокусе — крупно со ссылкой на скачивание. Окно — потомок
   миниатюры, поэтому курсор, уведённый на кнопку «Сохранить», его не гасит. */
.tryon-orig { position: relative; align-self: flex-start; }
.tryon-orig-thumb {
  width: 128px; height: 160px; object-fit: cover; display: block;
  border-radius: var(--r-md); border: 1px solid var(--border); cursor: zoom-in;
}
.tryon-orig-big {
  display: none; position: absolute; left: 0; top: 0; z-index: 30;
  padding: 10px; background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: 0 12px 40px rgba(0, 0, 0, .45);
}
.tryon-orig-big img { display: block; max-width: 520px; max-height: 70vh; margin-bottom: 8px; }
.tryon-orig:hover .tryon-orig-big, .tryon-orig:focus-within .tryon-orig-big { display: block; }
