/* Ferrara Finishes — стили попапа хотспота (#hspop).

   Вынесены из shared.css 2026-09-12 (блок 7 эстимейтов) вместе с логикой
   (assets/hotspot-popover.js): попап понадобился документу эстимейта, а
   его менеджерский вид идёт через портальный каркас, который shared.css не
   подключает вовсе. Копировать три десятка правил во второй файл нельзя —
   именно от такого дублирования владелец просил уходить.

   Правила перенесены БЕЗ ИЗМЕНЕНИЙ, вместе с комментариями и обоими
   медиазапросами (≤560px — bottom sheet, prefers-reduced-motion).
   Подключать ВМЕСТЕ с hotspot-popover.js; сама точка .hotspot осталась в
   shared.css — она есть только на публичных страницах, у документа свой
   свотч (.ev-schema-sw в portal/assets/estimate-view.css). */
/* Подсветка открытой точки — .hspop-hotspot-ghost ниже, не сама .hotspot:
   настоящая точка лежит глубоко внутри карусели, и у некоторых контейнеров
   (#mv-hotspots и т.п., detail-page.css) собственный z-index создаёт свой
   стекинг-контекст — никакой z-index на самой точке не поднял бы её выше
   scrim. */

/* .hspop-hotspot-ghost — "двойник" точки поверх scrim (см. carousel.php) —
   тот же вид, что .hotspot::after, но как независимый элемент на самом
   верхнем уровне стекинга (z-index выше scrim), site.js подставляет его
   точно на координаты настоящей точки на время открытого попапа. Цвет —
   белый, тот же, что и у обычной (неоткрытой) точки — по прямому запросу
   без изменений цвета, только чтобы не темнел под scrim. Раньше была
   скрыта на мобильном (≤560px) — НАЙДЕНО И ИСПРАВЛЕНО: на мобильном точка
   под scrim гасла точно так же, как на десктопе, подсветка нужна там же. */
.hspop-hotspot-ghost{position:fixed;width:22px;height:22px;margin:-11px 0 0 -11px;border-radius:50%;background:var(--text-on-accent);color:var(--ink);font-size:14px;font-style:italic;font-weight:700;display:flex;align-items:center;justify-content:center;line-height:1;z-index:2101;opacity:0;transition:opacity .15s ease;pointer-events:none}
.hspop-hotspot-ghost.show{opacity:1}

/* Линия-коннектор от точки до попапа (site.js::updateHotspotConnectorLine(),
   вызывается из positionHotspotPopover()). На десктопе — до ближайшего угла
   плавающей карточки. На мобильном (≤560px, bottom sheet) — НАЙДЕНО И
   ИСПРАВЛЕНО, раньше линия была скрыта целиком: теперь видна и там, до
   середины верхней грани .hspop-box (единственная содержательная точка у
   sheet'а, который сам всегда прижат к низу экрана во всю ширину — левой/
   правой/нижней грани, к которым имело бы смысл тянуть линию, у него нет).
   Толщина 3px (была 1px, по прямому запросу — "потолще") — div, повёрнутый
   transform:rotate() на нужный угол, обычный приём для "линии между двумя
   точками" в CSS, без SVG. z-index ВЫШЕ scrim (2099), не 2050, как было —
   иначе scrim, лежащий поверх, приглушал цвет линии (тот же найденный
   баг, что и у подсветки точки выше). Цвет — белый, по прямому запросу
   (был var(--line)), без изменений — только не темнеть под scrim. */
.hspop-line{position:fixed;height:3px;background:var(--text-on-accent);transform-origin:0 50%;z-index:2101;pointer-events:none;opacity:0;transition:opacity .15s ease}
.hspop-line.show{opacity:1}

/* ── HOTSPOT POPOVER — canonical, shared between project.php и homepage.php.
   Минималистичный (design-spec-v2.md §6): свотч + название + подзаголовок +
   одна CTA-ссылка, без описания/тегов/списков — данные приходят с сервера
   структурой из hotspot_resolver.php, DOM строит site.js::
   buildHotspotPopoverDom(). Текст переиспользует те же классы, что и
   карточки каталога (.card-eyebrow/.card-name/.card-subtitle/.cta-link,
   см. блок CATALOG CARD выше) — тот же приём типографики, не третий набор
   стилей текста.

   Десктоп — маленькая горизонтальная карточка (.popup) у самой точки
   хотспота, появление/исчезание — fade+scale всего попапа. Мобильный
   (≤560px) — тот же #hspop/.hspop-box становится bottom sheet (fixed внизу
   экрана, slide-up) — .popup прячется, показывается .sheet-row/.sheet-footer,
   см. media-запрос ниже. Оба режима — со scrim (.hspop-scrim) позади,
   гасящим фон, чтобы случайный клик мимо попапа не улетал в то, что под
   ним — тот же .show-класс, что и у .hspop, включает/выключает и его. */
/* pointer-events ВСЕГДА none, включая .show — НАЙДЕНО И ИСПРАВЛЕНО: раньше
   .show включал pointer-events:auto, и scrim (z-index 2099, поверх точки —
   у неё z-index:5) при hit-testing "перекрывал" точку для браузера, даже
   без какого-либо участия JS — сам факт, что scrim физически выше точки в
   стекинге, заставлял браузер слать точке mouseleave, стоило scrim
   появиться, что запускало цикл закрытие→точка снова видна→mouseenter→
   попап открывается заново (бесконечное мигание курсора). Закрытие по
   клику "мимо" не зависит от pointer-events самого scrim — оно уже ловится
   общим document-level обработчиком клика (см. site.js, проверяет
   e.target.closest('.hspop')/.hotspot) независимо от того, что физически
   было под курсором в момент клика. */
.hspop-scrim{position:fixed;inset:0;z-index:2099;background:color-mix(in srgb, var(--overlay-dark) 45%, transparent);opacity:0;visibility:hidden;transition:opacity .15s ease,visibility 0s linear .15s;pointer-events:none}
.hspop-scrim.show{opacity:1;visibility:visible;transition:opacity .15s ease,visibility 0s linear}

/* transform:scale() убран из анимации появления (НАЙДЕНО И ИСПРАВЛЕНО —
   повторные жалобы на "рывок" после появления, меньше 10px вверх + пошире
   на 15px под крестик): даже с transform-origin у ближнего к точке края
   (site.js::positionHotspotPopover()) масштаб 0.94→1 делал любую
   неточность в размере/позиции (в т.ч. из-за web-шрифтов, у которых метрики
   могут чуть доуточниться после первого layout) визуально заметной как
   рост/сдвиг. Только opacity — тот же плавный вход, но без риска
   "доразрастания". */
.hspop{position:fixed;left:0;top:0;z-index:2100;opacity:0;visibility:hidden;transition:opacity .15s ease,visibility 0s linear .15s;pointer-events:none}
.hspop.show{opacity:1;visibility:visible;transition:opacity .15s ease,visibility 0s linear;pointer-events:auto}

/* Без фиксированного max-width (320px/420px пробовали раньше) — по прямому
   запросу ширина не ограничена, растёт под контент, чтобы название всегда
   помещалось в одну строку (см. .popup-body .card-name{white-space:nowrap}
   ниже). calc(100vw - 24px) — единственный предел, и это не декоративное
   число, а тот же зазор (margin:12px с каждой стороны), которым
   positionHotspotPopover() в site.js зажимает попап в границах окна —
   иначе на узком экране очень длинное название всё равно вытолкнуло бы
   попап за пределы страницы. */
/* border — то же обрамление, что и у карточек (.card, border:1px solid
   var(--line)) — раньше попап держался только на тени, без явной обводки;
   теперь есть свой цвет, который переиспользуют линия-коннектор и подсветка
   хотспота ниже — единая "нить" от точки до попапа одного цвета с его же
   рамкой. */
.hspop-box{position:relative;max-width:calc(100vw - 24px);border:1px solid var(--line);border-radius:var(--r);background:var(--bg-card);box-shadow:0 20px 46px color-mix(in srgb, var(--shadow-black) 20%, transparent);overflow:hidden}
.hspop-close{position:absolute;top:8px;right:8px;width:26px;height:26px;border-radius:50%;background:color-mix(in srgb, var(--surface) 92%, transparent);border:1px solid var(--line-2);font-size:15px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:3}
.hspop-close:hover{background:var(--surface)}

/* Переключение между разными хотпоинтами, пока попап уже открыт — сперва
   гасим текущее содержимое (.switching), затем (см. showHotspotCard() в
   site.js) подменяем DOM и включаем обратно, чтобы старая карточка
   успевала исчезнуть, а не подменялась мгновенно. */
.hspop-mount{transition:opacity .08s ease}
.hspop.switching .hspop-mount{opacity:0}

/* ── ДЕСКТОП — .popup: свотч слева + текст справа (CTA прижата к низу
   текстовой колонки через margin-top:auto). ── */
.popup{display:flex}
.popup[data-clickable]{cursor:pointer}
.popup-swatch{width:120px;height:120px;min-width:120px;aspect-ratio:1/1;overflow:hidden;background:var(--bg-3)}
.popup-swatch img{width:100%;height:100%;object-fit:cover;display:block}
/* Отступы/margin приведены 1:1 к прототипу (redesign-v2.css, .rdv2-popup-
   body/.rdv2-sheet-text) — раньше здесь были другие числа (16px 18px вместо
   5px 10px и т.д.), из-за чего боевой попап визуально отличался от
   dev-preview-cards.php (найденный баг). */
/* padding-right больше остальных — резерв под .hspop-close (26px кнопка +
   8px отступ от края = 34px), иначе длинное однострочное название (см.
   white-space:nowrap ниже) заезжало под крестик. */
.popup-body{padding:5px 34px 5px 10px;flex:1;min-width:0;display:flex;flex-direction:column}
.popup-body .card-name{font-size:16px;margin-bottom:2px;white-space:nowrap}
.popup-body .card-subtitle{margin:-4px 0 0}
/* white-space:nowrap — НАЙДЕНО И ИСПРАВЛЕНО: без него браузер при расчёте
   "естественной" ширины попапа (shrink-to-fit) считал себя вправе перенести
   текст ссылки на 2 строки вместо того, чтобы посчитать её как часть
   максимальной ширины контента — JS-замер (site.js::positionHotspotPopover())
   получал ширину БЕЗ учёта полной ссылки, и уже показанный попап "донашивал"
   недостающую ширину следующим кадром (тот самый рывок/расширение). Теперь
   ссылка всегда учитывается в расчёте с самого начала. */
.popup-body .cta-link{margin-top:auto;align-self:flex-start;display:inline-block;white-space:nowrap}

/* ── МОБИЛЬНЫЙ — bottom sheet. .sheet-* скрыты по умолчанию (видны только
   ≤560px ниже), .hspop-box на десктопе остаётся обычной плавающей
   карточкой — свою позицию/форму меняет только в мобильном медиа-запросе. ── */
.sheet-handle{display:none}
.sheet-row{display:none}
.sheet-footer{display:none}

@media(max-width:560px){
  /* На мобильном анимирует не сам #hspop (fade+scale), а .hspop-box —
     slide-up снизу экрана (transform:translateY), поэтому у #hspop
     scale-анимация здесь отключена, чтобы не дублировать движение. */
  .hspop,.hspop.show{transform:none}
  .hspop-box{
    position:fixed;left:0;right:0;bottom:0;top:auto;max-width:none;
    border-radius:var(--r-panel) var(--r-panel) 0 0;padding:10px 20px 22px;
    transform:translateY(100%);transition:transform .22s ease;
    touch-action:none; /* см. enableHotspotSheetSwipeClose() в site.js — без этого браузер может начать скроллить страницу под пальцем ДО того, как JS успеет preventDefault() */
  }
  .hspop.show .hspop-box{transform:translateY(0)}
  .hspop-close{top:12px;right:16px}

  .popup{display:none}
  .sheet-handle{display:block;width:36px;height:4px;background:var(--line);border-radius:2px;margin:0 auto 14px}
  .sheet-row{display:flex;align-items:center;gap:14px}
  .sheet-row[data-clickable]{cursor:pointer}
  .sheet-swatch{width:100px;height:100px;min-width:100px;aspect-ratio:1/1;border-radius:var(--r);overflow:hidden;background:var(--bg-3)}
  .sheet-swatch img{width:100%;height:100%;object-fit:cover;display:block}
  .sheet-text{min-width:0;align-self:center}
  .sheet-footer{display:block;margin-top:16px;padding-top:14px;border-top:1px solid var(--line)}
}

@media(prefers-reduced-motion:reduce){
  .hspop,.hspop-box,.hspop-scrim,.hspop-mount{transition:none}
}
