/* ══════════════════════════════════════════════════════════════════════════
   forms.css — словарь конверсионных страниц: поля формы заявки, баннеры
   состояний, строки позиций корзины и блок итога.

   Подключается карточкой товара и всеми четырьмя состояниями корзины. Это
   единственная постраничная таблица стилей, которую грузит корзина, поэтому
   здесь же живёт мелкая обвязка внутренних страниц (хлебные крошки,
   заголовок страницы): вынести её в components.css нельзя — этот план не
   трогает файлы плана 01-02. В Фазе 3, когда разметка станет Twig-шаблонами,
   обвязка переезжает в общий слой одним движением.

   Ни одного литерала цвета, размера шрифта, отступа и радиуса: всё через
   токены tokens.css (проверки type / weight / spacing / radius / no-raw-color).
   Новых пользовательских свойств план не вводит, поэтому чистые РАЗМЕРЫ
   (ширина миниатюры, ширина счётчика количества) записаны обычными px —
   это размеры элементов, а не расстояния между блоками, и проверка spacing
   их справедливо не видит. Тот же принцип уже применён к --tap-min.
   ══════════════════════════════════════════════════════════════════════════ */

/* ══ ОБВЯЗКА ВНУТРЕННЕЙ СТРАНИЦЫ ═══════════════════════════════════════════ */

.breadcrumbs{
  margin-bottom:var(--space-4);
  font-size:var(--text-label);
  color:var(--color-text-muted);
}
.breadcrumbs ol{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:var(--space-2);
}
.breadcrumbs a{ color:var(--color-text-muted); text-decoration:none; }
.breadcrumbs a:hover{ color:var(--color-accent); }
.breadcrumbs li + li::before{
  content:"/";
  margin-right:var(--space-2);
  color:var(--color-text-muted);
}
.breadcrumbs [aria-current]{ color:var(--color-text); }

.page-title{ margin-bottom:var(--space-5); }

/* Подзаголовок карточки товара (D-09) — уточнение к короткому названию:
   объём двигателя, тип охлаждения, исполнение. Роль Lead из шкалы, но
   начертанием 400 и приглушённым цветом: это пояснение к заголовку, а не
   второй заголовок. Строки не существует, когда уточнения нет: шаблон не
   рендерит пустой элемент (см. design/product-min.html). */
.page-subtitle{
  margin-bottom:var(--space-5);
  font-size:var(--text-lead);
  font-weight:var(--weight-regular);
  line-height:1.4;
  color:var(--color-text-muted);
}
/* Заголовок несёт нижний отступ сам; когда следом идёт подзаголовок, пара
   читается одним блоком, поэтому зазор между ними сжимается. Там, где
   :has() недоступен, разница — лишний вертикальный зазор: страница
   не ломается и ничего не теряет. */
.page-title:has(+ .page-subtitle){ margin-bottom:var(--space-2); }

/* Заголовок блока внутри страницы: список позиций, форма заявки. */
.block-title{ margin-top:var(--space-7); margin-bottom:var(--space-4); }

/* Подзаголовок страницы — счёт позиций, артикул и прочая служебная строка.
   Заголовок несёт нижний отступ сам, поэтому здесь только цвет и низ. */
.page-meta{
  margin-bottom:var(--space-5);
  color:var(--color-text-muted);
}


/* ══ ФОРМА ════════════════════════════════════════════════════════════════
   Разметка полей — образец для Фазы 4: подпись связана с полем совпадающими
   идентификаторами, подсказка и сообщение об ошибке — программной связью
   aria-describedby. Именно эта связь объясняет незрячему пользователю,
   ПОЧЕМУ поле подсвечено; одна только рамка цветом ошибки не объясняет
   ничего и никому, кто не различает цвета. */

.form-card{
  display:grid;
  gap:var(--space-5);
  max-width:820px;
  padding:var(--space-5);
  border-radius:var(--radius-card);
  background:var(--color-surface);
  box-shadow:var(--card-shadow);
}
@media (min-width:768px){ .form-card{ padding:var(--space-6); } }

.request-form{ display:grid; gap:var(--space-4); }
@media (min-width:576px){
  .request-form{ grid-template-columns:repeat(2,1fr); }
  .request-form__wide{ grid-column:1 / -1; }
}

.field{ display:grid; gap:var(--space-1); align-content:start; }
.field__label{
  font-size:var(--text-label);
  font-weight:var(--weight-semibold);
  color:var(--color-text-muted);
}
/* Звёздочка обязательности продублирована словом в подсказке формы: символ
   сам по себе смысла не несёт и в озвучке читается как «звёздочка». */
.field__req{ color:var(--color-danger); }

.field__input{
  width:100%;
  min-height:var(--tap-min);
  padding:var(--space-2) var(--space-4);
  border:1px solid var(--color-hairline);
  border-radius:var(--radius-sm);
  background:var(--color-surface-alt);
  color:var(--color-text);
  font-size:var(--text-body);
}
.field__input::placeholder{ color:var(--color-text-muted); }

/* Комментарий растёт вертикально; горизонтальной прокрутки не возникает,
   потому что ширина фиксирована колонкой, а перенос обычный. */
textarea.field__input{
  min-height:calc(var(--tap-min) * 3);
  padding-top:var(--space-3);
  padding-bottom:var(--space-3);
  line-height:1.5;
  resize:vertical;
}

.field__hint{ font-size:var(--text-label); color:var(--color-text-muted); }

.field__error{
  display:flex;
  align-items:center;
  gap:var(--space-2);
  font-size:var(--text-label);
  font-weight:var(--weight-semibold);
  color:var(--color-danger);
}
.field__error svg{ flex:none; }

/* Невалидное поле различимо НЕ ТОЛЬКО цветом: рамка утолщается, а под полем
   стоит текстовое сообщение, связанное с ним aria-describedby.

   Список выбора и поле файлов перечислены здесь наравне с полем ввода
   (Фаза 4, план 04-09). Это не новое правило, а тот же признак непройденного
   поля, распространённый на два новых компонента: без них непройденный
   список тем отличался бы от непройденного поля ввода только текстом под
   ним, а признак ошибки вложений не был бы виден на самом поле вовсе. */
.field--invalid .field__input,
.field--invalid .field__select,
.field--invalid .field__file{
  border-width:2px;
  border-color:var(--color-danger);
  background:var(--color-surface);
}

/* Тихая кнопка на светлом фоне — «Пересчитать» на странице корзины.
   Призрачный вариант из components.css рассчитан на тёмную подложку и на
   белом читается плохо; акцентом кнопка не красится намеренно: главное
   действие страницы одно — «Оформить заявку», — и вторая акцентная кнопка
   размыла бы его (UI-SPEC §P1). Высота и радиус берутся у .btn. */
.btn-quiet{
  background:var(--color-surface);
  border:1px solid var(--color-hairline);
  color:var(--color-text);
}

/* ── Список выбора темы обращения (Фаза 4, план 04-09, §P4) ──────────────
   Геометрия .field__input повторена значение в значение, а не унаследована
   классом: список выбора и поле ввода — разные элементы, и общий класс
   заставил бы разметку нести два класса там, где хватает одного.

   СТРЕЛКА НАТИВНАЯ — свойство внешнего вида контрола здесь НЕ
   переопределяется, и это решение, а не упущение. Самодельный шеврон — это либо фоновое изображение
   с литералом цвета внутри (его немедленно поймала бы проверка no-raw-color),
   либо векторный элемент поверх контрола: декорация со своим признаком
   скрытия и ловушка при масштабировании шрифта. Нативная стрелка рисуется
   системой в системном цвете, всегда контрастна и всегда на месте, а
   клавиатурное поведение списка остаётся тем, которое посетитель уже знает. */
.field__select{
  width:100%;
  min-height:var(--tap-min);
  padding:var(--space-2) var(--space-4);
  border:1px solid var(--color-hairline);
  border-radius:var(--radius-sm);
  background:var(--color-surface-alt);
  color:var(--color-text);
  font-size:var(--text-body);
}

/* ── Поле выбора файлов (Фаза 4, план 04-09, §P4, D-09) ──────────────────
   Контейнер получает геометрию поля ввода, а системная кнопка внутри него —
   вид тихой кнопки. Кегль подписи, а не тела: собственный текст браузера
   («Файлы не выбраны» / «Выбрано: 3 файла») — служебная строка, а не ввод
   посетителя.

   Списка выбранных файлов рядом не рисуется: свой список требует чтения
   FileList скриптом, а скрипт запрещён правилом no-inline-js и не нужен для
   работы формы. Зоны перетаскивания нет — она недостижима с клавиатуры.

   Высота системной кнопки не ниже тач-цели: на телефоне это единственный
   способ приложить файл, и промах по ней стоит посетителю всего обращения. */
.field__file{
  width:100%;
  min-height:var(--tap-min);
  padding:var(--space-2) var(--space-4);
  border:1px solid var(--color-hairline);
  border-radius:var(--radius-sm);
  background:var(--color-surface-alt);
  color:var(--color-text);
  font-size:var(--text-label);
}
.field__file::file-selector-button{
  min-height:var(--tap-min);
  margin-right:var(--space-4);
  padding:0 var(--space-4);
  border:1px solid var(--color-hairline);
  border-radius:var(--radius-button);
  background:var(--color-surface-alt);
  color:var(--color-text);
  font-family:inherit;
  font-size:var(--text-label);
  font-weight:var(--weight-semibold);
}

.form-actions{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:var(--space-4);
}
.form-note{ font-size:var(--text-label); color:var(--color-text-muted); }


/* ══ БАННЕРЫ СОСТОЯНИЙ ════════════════════════════════════════════════════
   Полоса над формой. Иконка вставлена прямо в разметку — внешний спрайт под
   file:// блокируется. Обе пары «текст на фоне» объявлены в @contrast-pairs
   плана 01-02: текст ошибки живёт на нейтральной подложке, текст успеха —
   белым по фирменному тёмно-синему. */

.banner{
  display:flex;
  align-items:flex-start;
  gap:var(--space-3);
  padding:var(--space-4);
  border-radius:var(--radius-sm);
  font-weight:var(--weight-semibold);
}
.banner svg{ flex:none; }

.banner--error{
  border-left:4px solid var(--color-danger);
  background:var(--color-surface-alt);
  color:var(--color-text);
}
.banner--error svg{ color:var(--color-danger); }

.banner--success{
  background:var(--color-surface-brand);
  color:var(--color-text-on-brand);
}
.banner--success svg{ color:var(--color-success); }


/* ══ ПОЗИЦИИ КОРЗИНЫ ══════════════════════════════════════════════════════
   Ритм строки повторяет строки контактного блока: вертикальные отступы плюс
   тонкая линия снизу. Список растёт вертикально — внутренней прокрутки у
   него нет, поэтому итог и форма всегда остаются под ним. */

.cart-lines{ display:grid; }

.cart-line{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:var(--space-4);
  padding:var(--space-4) 0;
  border-bottom:1px solid var(--color-hairline);
}
.cart-line:last-of-type{ border-bottom:0; }

/* Миниатюра. 96px — размер элемента, а не отступ (см. шапку файла). */
.cart-line__media{ flex:none; width:96px; }
.cart-line__body{ flex:1 1 240px; display:grid; gap:var(--space-1); }
.cart-line__title{
  font-size:var(--text-body);
  font-weight:var(--weight-bold);
  line-height:1.4;
}
.cart-line__title a{ color:var(--color-text); text-decoration:none; }
.cart-line__title a:hover{ color:var(--color-accent); }
.cart-line__meta{ font-size:var(--text-label); color:var(--color-text-muted); }

.cart-line__price{
  flex:none;
  font-size:var(--text-body);
  font-weight:var(--weight-bold);
  white-space:nowrap;
}

/* Позиция, товара которой больше нет в каталоге (D-03). Подложка — ЧЕТВЁРТЫЙ
   и последний признак: перед ним идут слова в служебной строке, обычное
   начертание в слоте цены и заголовок, переставший быть ссылкой. Цветом
   ошибки строка НЕ красится: это не ошибка покупателя и не отказ, а факт о
   каталоге. Поле количества и кнопка удаления остаются рабочими. */
.cart-line--gone{ background:var(--color-surface-alt); }

/* Слот цены, когда суммы нет. Начертание обычное и перенос разрешён: здесь
   стоит фраза, а не число, и нерастяжимая строка выдавила бы ряд. Тем же
   приёмом устроена цена по запросу в карточке каталога. */
.cart-line__price--on-request{
  font-weight:var(--weight-regular);
  white-space:normal;
  color:var(--color-text-muted);
}

.cart-line__qty{ flex:none; display:flex; align-items:center; gap:var(--space-2); }
.cart-line__qty label{ font-size:var(--text-label); color:var(--color-text-muted); }
.field__input--qty{
  width:80px;
  padding-left:var(--space-2);
  padding-right:var(--space-2);
  text-align:center;
}

/* Удаление окрашено цветом ошибки и НЕ требует модального подтверждения:
   действие обратимо — товар добавляется снова из каталога. Других
   разрушающих действий в публичной части нет (UI-SPEC §Copywriting). */
.cart-line__remove{
  flex:none;
  display:flex;
  align-items:center;
  justify-content:center;
  width:var(--tap-min);
  height:var(--tap-min);
  border-radius:var(--radius-sm);
  color:var(--color-danger);
}
.cart-line__remove:hover{ background:var(--color-surface-alt); }

/* Миниатюра позиции и миниатюра галереи — один и тот же слот. Настоящее
   фото подставляется в <img> и кадрируется по месту. */
.thumb{
  display:flex;
  align-items:center;
  justify-content:center;
  overflow:hidden;
  aspect-ratio:1/1;
  border-radius:var(--radius-sm);
  background:linear-gradient(140deg, var(--color-surface-brand-soft), var(--color-surface-brand-deep));
  color:var(--color-text-on-photo);
}
.thumb img{ width:100%; height:100%; object-fit:cover; }


/* ══ ИТОГ ═════════════════════════════════════════════════════════════════ */

.cart-total{
  display:grid;
  gap:var(--space-4);
  max-width:820px;
  margin-top:var(--space-5);
  padding:var(--space-5);
  border-radius:var(--radius-card);
  background:var(--color-surface-alt);
}
.cart-total dl{ display:grid; gap:var(--space-2); }
.cart-total .trow{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:var(--space-4);
}
.cart-total dt{ font-size:var(--text-label); color:var(--color-text-muted); }
.cart-total dd{ font-weight:var(--weight-semibold); white-space:nowrap; }
.cart-total .trow--sum dt{ font-size:var(--text-body); color:var(--color-text); }
.cart-total .trow--sum dd{
  font-size:var(--text-heading);
  font-weight:var(--weight-bold);
}

/* Пояснение между списком пар и кнопкой: чем именно неполон итог (D-02, D-03).
   Кегль ячейки итога при этом один во всех трёх состояниях — меняется
   содержимое ячейки, а не её вид. */
.cart-total__note{
  margin-top:var(--space-2);
  font-size:var(--text-label);
  color:var(--color-text-muted);
}


/* ══ СОСТОЯНИЯ БЕЗ СПИСКА (пусто / отправлено) ════════════════════════════ */

.state-block{
  display:grid;
  justify-items:center;
  gap:var(--space-4);
  max-width:820px;
  padding:var(--space-7) var(--space-5);
  border-radius:var(--radius-card);
  background:var(--color-surface-alt);
  text-align:center;
}
.state-block__ic{
  display:flex;
  align-items:center;
  justify-content:center;
  width:var(--icon-tile);
  height:var(--icon-tile);
  border-radius:var(--radius-pill);
  background:var(--color-surface);
  color:var(--color-surface-brand);
  box-shadow:var(--shadow);
}
.state-block p{ max-width:44ch; color:var(--color-text-muted); }
