/* ================= ОТЗЫВЫ КЛИЕНТОВ — ОБЩИЙ БЛОК =================
   Выделен из home-showcase.css 24.08.2026: тот же ряд карточек нужен и на главной,
   и на посадочных. Подключать home-showcase.css целиком на посадочную было нельзя —
   он переопределяет :root, html/body, h1/h2, .faq .container и main > .container,
   то есть менял бы посадочную далеко за пределами отзывов.

   Карточка принята оператором по макету mockups/review-card.html 23.08.
   Данные НАСТОЯЩИЕ (выгрузка с прода scripts/dump-reviews.mjs), вшиты в разметку:
   публичной выдачи отзывов в API пока нет, перевод на базу — отдельная задача.
   Четвёрки показываем сознательно — стена одних пятёрок читается как накрутка.

   ⚠️ СЕКЦИЯ СТОИТ НА ЛИНИИ ХЕДЕРА, а не контейнера страницы (решение оператора 24.08).
   Хедер идёт во всю ширину окна (max-width:none в style.css), его боковое поле — --gutter,
   поэтому логотип на любом мониторе стоит в 48/32/16px от края. Контейнер страницы при
   этом центрируется (1220px на посадочных, 1360px на главной), и привязка к нему уводила
   заголовок отзывов от логотипа тем дальше, чем шире экран: на 3840 расхождение 1240px
   (замер 24.08). Отсюда --rv-edge = --gutter, а .container секции распущен до полной
   ширины — заголовок, лид и первая карточка встают на одну линию с логотипом. */
.mk-reviews { padding: var(--section-y) 0; }
/* Заголовок и лид на линии логотипа: контейнер секции распускается во всю ширину окна
   и держит только боковое поле, ровно как .header .container. */
.mk-reviews > .container { max-width: none; margin-inline: 0; }
.mk-reviews h2 { margin: 0 0 8px; }
.mk-reviews-lede { margin: 0 0 18px; font-size: 16px; line-height: 1.5;
  color: var(--muted); max-width: 52ch; }

/* Сетка. БЕЗ align-items:start — карточки тянутся на всю высоту ряда (stretch по умолчанию).
   Именно start давал «лесенку»: высота зависела от длины текста и наличия фото.
   Брейкпоинт 1128px — единый по проекту (канон хедера). */
/* Две колонки, а не четыре. Замер 23.08 на живом контейнере 1200px: при четырёх колонках
   на карточку остаётся 264px, из них 132 забирает фото — под текст 110px, и отзыв
   обрывается на втором слове («Понравилос…»), а дата уезжает за край. Отзыв, который
   нельзя прочитать, не работает вовсе. При двух колонках текстовая часть ~450px:
   любой из наших отзывов читается целиком, обрез не наступает. */
/* ОДИН ГОРИЗОНТАЛЬНЫЙ РЯД с прокруткой (решение оператора 23.08). До этого пробовали
   сетку 2x2 и вертикальную ленту — обе отвергнуты. Карточки идут в ряд, что не влезло,
   доступно горизонтальной прокруткой; вертикально блок больше не растёт.
   Ширина карточки ФИКСИРОВАННАЯ, а не доля свободного места: доля растянула бы четыре
   карточки по контейнеру и прокрутки не было бы вовсе. 420px — из замера: под текст
   остаётся 272px (420 минус колонка фото 116 и padding 32), самый длинный наш отзыв
   (Сергей, 155 знаков) укладывается в пять строк без обреза.
   min(88%, ...) на узких экранах: карточка занимает 88% ширины трека, оставшиеся 12%
   показывают край следующей — это и есть подсказка, что ряд прокручивается.
   scroll-snap СНЯТ (24.08): он подтягивал карточку к краю на каждом отпускании мыши —
   это и был рывок, на который жаловался оператор. С бесконечной лентой он несовместим
   вовсе: подтягивал бы трек на каждом кадре автодвижения. */
.rv-grid { display:flex; gap:12px;
  overflow-x:auto; overflow-y:hidden;
  -webkit-overflow-scrolling:touch;
  /* Полосы прокрутки НЕТ (решение оператора 23.08): под карточками она читалась как
     элемент вёрстки, а не как управление. Подсказка, что ряд едет, остаётся визуальная —
     карточка, обрезанная краем экрана. */
  scrollbar-width:none;
  /* Трек лежит ВНЕ .container и занимает всю ширину окна: карточка обязана уходить
     за левый край экрана при прокрутке, а не упираться в поле контейнера.
     Левая линия с заголовком держится вручную: (100% - --rv-container)/2 — это ровно то
     поле, которое .container оставляет слева на широком экране, плюс его собственный
     --gutter.
     ⚠️ Ширина берётся из --rv-container, а НЕ вшита числом: у главной контейнер витринный
     (1360px, переопределён списком в начале home-showcase.css), у посадочных — проектные
     1220px из style.css. Ошибиться числом здесь = разъезд заголовка и первой карточки
     на 70px (замер 23.08 на 1440).
     max(...) нужен на узких экранах, где окно уже контейнера и скобка уходит в минус.
     scroll-padding повторяет отступ: без него snap подвёл бы карточку под самый край. */
  --rv-edge: var(--gutter);
  padding-inline: var(--rv-edge) 0;
  /* Запас снизу под полосу больше не нужен — полосы нет. */
  padding-bottom:0; }
.rv-grid::-webkit-scrollbar { display:none; }

/* ================= БЕСКОНЕЧНАЯ ЛЕНТА (решение оператора 24.08) =================
   Ряд едет сам справа налево и закольцован. Механика — в reviews-block.js; здесь только
   то, без чего движение выглядит сломанным.

   scroll-behavior:auto ОБЯЗАТЕЛЕН. Проект где-то ставит smooth на html (плавная прокрутка
   к якорям), и при нём каждый кадр ленты уезжал бы в анимацию браузера: движение
   превращается в вязкий рывок вместо ровного хода.

   prefers-reduced-motion: лента ВСТАЁТ. Постоянное движение на краю зрения — классический
   триггер вестибулярного дискомфорта, и человек, попросивший систему уменьшить анимацию,
   обязан получить неподвижный ряд. Прокрутка руками при этом остаётся: ряд не перестаёт
   работать, он лишь не едет сам. Скрипт читает тот же запрос и не запускает движение. */
.rv-grid { scroll-behavior: auto; }

/* Клоны для закольцовывания. Скрытие от скринридера — на самих узлах (aria-hidden ставит
   скрипт): дубль отзыва, прочитанный вслух дважды, звучит как две разные оценки.
   Визуально клон НИЧЕМ не отличается от оригинала — в этом и смысл шва. */
.rv-grid > .rv--clone { pointer-events: none; }

/* Перетаскивание мышью (решение оператора 24.08). Полосы прокрутки нет, и мышью ряд
   было нечем двигать — курсор-ладонь единственная подсказка, что его можно тянуть.
   grab только там, где есть что прокручивать: на широком экране, где все карточки
   видны, ладонь обещала бы движение, которого нет. Класс вешает скрипт.
   Тач не трогаем: там ряд тянется пальцем нативно, курсора нет вовсе. */
@media (hover: hover) and (pointer: fine) {
  .rv-grid.rv-grid--scrollable { cursor: grab; }
  /* Лента едет и закольцована, значит тянуть её можно всегда — ладонь честна на любой
     ширине, даже когда все карточки помещаются в окно. */
  .rv-grid.rv-grid--live { cursor: grab; }
  .rv-grid.rv-grid--drag { cursor: grabbing; }
  /* Во время перетаскивания текст не выделяется: иначе рывок мышью выделяет отзыв
     синим вместо прокрутки ряда. Вне перетаскивания выделение работает как обычно —
     цитату из отзыва человек вправе скопировать. */
  .rv-grid.rv-grid--drag, .rv-grid.rv-grid--drag * { user-select: none; }
}

/* Ширина карточки — ДОЛЯ видимой части трека, а не фиксированные пиксели: ряд обязан
   тянуться за экраном. Знаменатель дробный (3,2 а не 3) намеренно: карточка за краем
   всегда видна кусочком, и это единственная подсказка, что ряд прокручивается.
   Шкала повторяет брейкпоинты проекта: 1128 — канон хедера, 600 — граница Compact. */
.rv-grid { --rv-per-view: 2.8; }
@media (max-width:1128px){ .rv-grid { --rv-per-view: 2.4; } }
@media (max-width:820px) { .rv-grid { --rv-per-view: 1.6; } }
@media (max-width:600px) { .rv-grid { --rv-per-view: 1.12; } }
/* Потолок 460px и пол 280px поверх доли. Без потолка на 27-дюймовом мониторе карточка
   уезжала бы за 500px и превращалась в баннер; без пола на 360px текст сжимался в колонку
   в два слова. Между ними ширина живая и следует за экраном. */
.rv-grid > .rv { flex:0 0 clamp(280px, calc(100% / var(--rv-per-view) - 12px), 460px); }

/* Карточка: миниатюра слева во всю высоту, содержимое справа.
   overflow:hidden обязателен — миниатюра прижата к краю без своего padding, без обрезки
   её прямой угол вылезал бы за скруглённый угол карточки. */
.rv { background: var(--card, #fff); border:1px solid var(--line); border-radius: var(--radius);
  display:flex; align-items:stretch; overflow:hidden; }
/* Padding живёт здесь, а не на .rv: у миниатюры своего отступа нет.
   min-width:0 — иначе длинное слово распирает флекс. */
/* padding 16 и gap 8, а не 20/12: в ленте карточка растянута по ширине, и прежние отступы
   давали ей рост без содержания — оператор попросил карточки ниже (23.08). */
.rv__main { flex:1; min-width:0; min-height:0; padding:16px;
  display:flex; flex-direction:column; gap:8px; }
/* Внутренний padding НЕ больше внешнего поля (CONVENTIONS.md § Мобильный канон п.4):
   при gutter 16 padding 20 уводил текст карточки от края дальше, чем заголовок над ней. */
@media (max-width:600px){ .rv__main { padding:14px; } }

/* Миниатюра. Ширина фиксированная, высота тянется за содержимым (align-items:stretch).
   132px, а не 108: в узкой карточке горизонтальный кадр кроился до узкого ломтя и сюжет
   пропадал. БЕЗ padding — снимок обязан доходить до краёв колонки. */
/* Высота карточки задаётся текстом, а фото подстраивается под неё (align-self:stretch).
   Ширина колонки 116px: в ленте карточка широкая, и прежние 132px при низкой карточке
   давали почти квадратный кроп, в котором вертикальный портрет 400x600 терял голову. */
.rv__thumb { flex:0 0 116px; align-self:stretch; border-right:1px solid var(--line);
  background: var(--paper-2, #f2ead8); display:grid; place-items:center; }
/* object-fit:cover — кадры приходят и вертикальные, и горизонтальные. Колонка фиксированной
   ширины, поэтому кадр кроется по центру, а не сплющивается. */
.rv__thumb img { width:100%; height:100%; object-fit:cover; object-position:center; display:block; }
@media (max-width:600px){ .rv__thumb { flex-basis:104px; } }

/* Звёзды юникодом, не картинками: масштабируются, читаются скринридером через aria-label. */
.rv__rate { display:flex; align-items:center; gap:10px; }
.rv__stars { font-size:17px; letter-spacing:.12em; line-height:1; color: var(--terra); }
.rv__stars i { color: var(--paper-4); font-style:normal; }
.rv__date { font-size:13px; color: var(--ink-mute); margin-left:auto; }

/* Тело. ЛИМИТ 5 СТРОК в покое — высота карточки на главной каноническая, выше неё ряд
   не растёт (решение оператора 24.08). До лимита высоту задавал самый длинный отзыв, и
   один пришедший на 326px текст поднял весь ряд с канонических 223-270px до 433px:
   у короткого отзыва в три слова под текстом зияла пустота во всю карточку.
   Почему именно 5: замер канона 24.08 на коде до правки — карточка 223px при тексте
   116px, то есть обвязка (звёзды, подпись, поля) занимала 107px, а на текст оставалось
   ровно 5 строк × 15px × 1.55 ≈ 116px. Семь строк проверены и отвергнуты: карточка
   выросла до 323px, канон превышен на восьми ширинах из десяти.
   Обрезаем через line-clamp, а не по количеству знаков: знаки не знают ширины колонки,
   и один и тот же отзыв рвался бы в разном месте на разных экранах.
   Полный текст достаётся кнопкой «Читать целиком» — обрезать отзыв без возможности
   дочитать значит потерять часть того, ради чего блок и стоит на странице. */
.rv__body { margin:0; font-size:15px; line-height:1.55; color: var(--ink);
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:5; overflow:hidden; }
/* Раскрытая карточка: лимит снят, растёт ТОЛЬКО ОНА.
   Растяжение соседей гасим на ТРЕКЕ, а не на самой карточке: align-self:flex-start
   на .rv.is-open проверен и НЕ помог (замер 24.08 — соседи всё равно 340), потому что
   тянется не раскрытая карточка к соседям, а СОСЕДИ к выросшему треку.
   align-items:flex-start у трека с раскрытой карточкой снимает растяжение со всех.
   Одного этого мало: соседи тогда сжимаются каждый по своему тексту, и ровный ряд
   рассыпается в лесенку 223/177/154/130 (замер 24.08). Поэтому нераскрытым соседям
   каноническая высота задаётся ЯВНО — они остаются ровными, растёт только раскрытая.
   Высота берётся из переменной, которую скрипт снимает с ряда в покое: числом её
   зашить нельзя, канон разный на разных ширинах (223 на 1440, 272 на 360).
   Селектор через :has — трек узнаёт о раскрытии, не дожидаясь класса от скрипта. */
.rv-grid:has(.rv.is-open) { align-items: flex-start; }
.rv-grid:has(.rv.is-open) > .rv:not(.is-open) { height: var(--rv-canon-h, auto); }
.rv.is-open .rv__body { -webkit-line-clamp:unset; display:block; overflow:visible; }

/* Кнопка раскрытия. Показывается ТОЛЬКО у карточек, где текст реально не поместился —
   класс вешает скрипт по факту переполнения (scrollHeight > clientHeight), а не по
   длине строки: поместится текст или нет, решает ширина колонки, известная лишь браузеру.
   Живёт В СТРОКЕ ПОДПИСИ, а не отдельным блоком под текстом: отдельной строкой она
   добавляла к карточке 53px обвязки, и канон превышался на восьми ширинах из десяти
   (замер 24.08) — высоту съедала сама кнопка, а не текст.
   Тач-цель 44px по мобильному канону CONVENTIONS.md набирается отрицательным полем
   сверху и снизу: видимая строка остаётся низкой, а нажимаемая область — полной.
   Подчёркивание, а не рамка: это ссылка при отзыве, а не второй CTA рядом с кнопками
   страницы. margin-left:auto — прижата к правому краю, подпись остаётся у левого. */
.rv__more { display:none; margin:-11px 0 -11px auto; padding:11px 0;
  background:none; border:0; cursor:pointer;
  font: inherit; font-size:14px; color: var(--terra);
  text-decoration:underline; text-underline-offset:3px; white-space:nowrap; }
.rv.is-clamped .rv__more { display:inline-flex; align-items:center; }

/* Подпись. Отделена линией: где кончается голос клиента, видно без чтения.
   margin-top:auto ВЕРНУЛСЯ вместе с рядом: карточки в ряду тянутся до высоты самой
   высокой, и без прижатия к низу подпись короткого отзыва зависала бы в середине
   карточки, а под ней зияла пустота. В вертикальной ленте соседей по ряду не было и
   прижатие только растягивало карточку — там его сняли правильно. */
.rv__foot { display:flex; align-items:baseline; gap:8px; flex-wrap:wrap;
  padding-top:10px; border-top:1px solid var(--line); margin-top:auto; }
.rv__name { font-weight:600; font-size:15px; color: var(--ink); }
