/*
  Our own overrides on top of the mockup. Files in club/css/*.min.css belong
  to the mockup vendor and get replaced wholesale on every update - everything
  we add ourselves lives here instead, so an update never causes a conflict.
*/

/*
  Место под полосу прокрутки зарезервировано всегда.

  Страницы разной высоты: FAQ и карта арены короче экрана, список мест длиннее.
  Без резерва документ то получал вертикальный скроллбар, то терял его, и при
  переходах между страницами вся вёрстка прыгала по горизонтали на его ширину.

  На странице карты документ и так не скроллится (body { overflow: hidden }),
  так что там правило ничего не меняет. Safari свойство не поддерживает —
  там останется прежнее поведение, ухудшения нет.
*/
html {
  scrollbar-gutter: stable;
}

/*
  Guide map - one screen, no document scroll.

  Both club-main.css and, until this rewrite, we ourselves sized the map
  wrapper as calc(100vh - var(--club-space-3xl) - var(--club-page-header-height)),
  where --club-page-header-height is meant to be written by club-main.js's
  own "GET SIZE page-header" listener measuring the filters bar.

  On this page that variable stays at 0px. So the wrapper was sized as the
  full viewport minus a 30px gap, while actually starting 192px down the page
  (below the 162px filters bar plus that gap) - its bottom landed 162px past
  the bottom of the screen. Since .main and body both carry overflow: hidden
  to keep the map from scrolling the document, those 162px were not merely
  off-screen, they were unreachable: the popup is height: 100% of this
  wrapper, so the bottom of a tall place card was cut off with nothing to
  scroll. That is the "card runs past the window and will not scroll" report.

  Rather than chase why the variable is 0, the height is now derived from the
  layout itself. .main holds exactly two children on this page - the filters
  bar and this wrapper - so making it a viewport-tall flex column and letting
  the wrapper take what is left needs no measurement at all, and cannot drift
  from whatever the filters bar actually ends up being: one line of filters or
  three, any font, any breakpoint.

  min-height: 0 is the part that is easy to miss. A flex item will not shrink
  below its content's intrinsic height without it, and the content here is a
  place card of arbitrary length - which would reintroduce exactly the
  overflow this is fixing.

  dvh rather than vh: on iOS 100vh is measured against the layout viewport,
  which ignores the address bar, so a 100vh box ends up partly under that
  chrome. 100dvh tracks the visual viewport instead.
*/
.is-map-page .main {
  display: flex;
  flex-direction: column;
  /*
    Высота по фактически видимой области, а 100dvh - только запас на случай, если
    JS не успел или отключён.

    Переменную ставит guide-app.js из visualViewport (см. комментарий там).
    Ни vh, ни dvh здесь не годятся: панели браузеров на телефоне - Safari,
    Chrome, встроенный в Telegram - накладываются поверх страницы и высоты у неё
    не отнимают, поэтому страница уходит под панель. Отсюда и низ шторки за
    панелью, и недочитываемые последние строки, и съезжавшая вверх точка при
    центрировании: всё это считалось от невидимого низа.
  */
  height: var(--guide-visible-h, 100dvh);
}

.is-map-page .ewc-2026-paris-guide-map-wrapper {
  flex: 1 1 auto;
  height: auto;
  min-height: 0;
}

/*
  ...и то же самое на уровень глубже, иначе ограничение до попапа не доходит.

  __inner - это flex-элемент обёртки с flex: 1 1 0%, но с min-height: auto по
  умолчанию, а значит он не сжимается ниже высоты своего содержимого. Карточка
  места произвольной длины растягивала его до 873px внутри обёртки высотой 708,
  и скроллилась сама обёртка вместе с картой, а попап - у которого height: 100%
  считается как раз от __inner - оставался нескролящимся и уезжал за экран.

  min-height: 0 возвращает ограничение: __inner становится ровно по обёртке,
  height: 100% попапа считается от правильной высоты, и его собственный
  overflow-y: auto наконец начинает работать.
*/
.is-map-page .ewc-2026-paris-guide-map-wrapper__inner {
  height: 100%;
  min-height: 0;
}

/*
  Belt-and-suspenders for "no document scroll": club-main.css already sets
  .main:has(.ewc-2026-paris-guide-map-wrapper) { overflow: hidden }, which
  holds as long as the height math above is correct. The is-map-page body
  class from the brief's own contract test gives the same guarantee a second,
  independent way (:has() is supported everywhere we target, but this does
  not rely on it, and documents intent on <body> where a reader expects it).
*/
body.is-map-page {
  overflow: hidden;
}

.is-map-page .ewc-2026-paris-guide-map,
.is-map-page #guide-map {
  width: 100%;
  height: 100%;
}

/*
  Popup: place cards vary in height (tags, image, description length).
  .ewc-2026-paris-guide-map-popup sits in normal flow inside the fixed-height
  flex wrapper above with no overflow rule of its own in club-main.css — a
  card taller than the available space would grow the *wrapper* instead,
  which is exactly the document-level scroll we are trying to avoid. Giving
  the popup its own scroll box keeps that growth local to the popup.
  overscroll-behavior stops touch "rubber-band" scroll at the top/bottom of
  the popup from bleeding into a scroll of the page behind it.
*/
.is-map-page .ewc-2026-paris-guide-map-popup {
  /* Client's ask: the popup column spans the map's full height rather than
     shrink-wrapping the card, so the card always starts at the top of the
     map instead of floating at whatever height its own content happens to
     be. max-height stays alongside it as the scroll box's own limit. */
  height: 100%;
  max-height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/*
  Mobile-only client polish (screen-recording feedback, three asks together):
  on phones the map popup rendered fully edge-to-edge (club-main.css's own
  max-width:640px rule zeroes .club-container's padding specifically inside
  this popup - see the .ewc-2026-paris-guide-map-popup .club-container rule
  a little above this in club-main.css), the photo filled the popup's whole
  width at its 600/338 ratio, and the description text landed at ~9px
  because .club-text-14 uses --club-font-size-sm, which club-main.css scales
  down to 2.5vw at this same breakpoint (2.5vw = 9.375px at a 375px-wide
  viewport). All three overrides below are scoped to #guide-map-popup under
  .is-map-page only, so the /places list cards (partials/place-card.blade.php's
  'list' variant, rendered outside .is-map-page) and the desktop/tablet popup
  are untouched. None of this touches the popup's own overflow-y/
  overscroll-behavior/max-height rule immediately above, or its
  padding-block:0/margin-top:auto mobile rule in club-main.css.
*/
@media (max-width: 640px) {
  /*
    Боковых полей и приплюснутого фото здесь больше нет - оба правила
    относились к прежнему попапу, который лежал карточкой поверх карты и был
    маленьким: поле в 16px отделяло его от краёв, а фото сплющивалось до 2.53,
    чтобы в невысокую карточку влезло остальное.

    Теперь это шторка во весь экран под шапкой: карточка идёт край в край, и
    места хватает - в макете фото в своей исходной пропорции 600/338, а
    боковых отступов у попапа нет вовсе. Правило с полем к тому же было на
    ID-селекторе и перебивало перенесённое из вендорной таблицы
    padding-inline: 0, из-за чего по краям шторки оставались полоски карты.

    Размер описания ниже остаётся: он и в макете примерно такой (13.1px на
    430px), а вендорная переменная задаёт его в 2.5vw и на 375px даёт 9px.
  */

  /* Description text: a flat size for this breakpoint instead of the
     shared --club-font-size-sm var, which we deliberately leave alone since
     other components on the page rely on its normal (non-popup) value. */
  .is-map-page #guide-map-popup .club-text-14 {
    font-size: 13px;
  }

  /* club-main.css puts box-shadow: 0 0 100px 0 #02f on every popup card
     (.ewc-2026-paris-guide-map-popup__item) - a 100px blue blur meant to glow
     softly around a card sitting inside a wide desktop layout. On a narrow
     viewport the card is nearly as wide as the screen, so that same 100px
     blur has nowhere to fade into and reads as a solid blue bar down both
     edges instead. Killed only at this breakpoint - the desktop glow is
     unaffected. */
  .is-map-page .ewc-2026-paris-guide-map-popup__item {
    box-shadow: none;
  }
}

/*
  Empty-filter state (design spec §6: "no places after filter -> message in
  the popup zone, map stays alive"). guide-app.js toggles "is-empty" on
  #guide-map once, after filtering the already-fetched marker set against
  the page's own ?filter=/?recommends= query string (no server round trip -
  see applyFilters()). #guide-map-popup is normally display:none until it
  gets "is-active" (club-main.css); the sibling rule below forces it open to
  surface this message even when no place card has been clicked.
*/
.js-map-empty-state {
  display: none;
}
#guide-map.is-empty ~ .ewc-2026-paris-guide-map-popup {
  display: block;
}
#guide-map.is-empty ~ .ewc-2026-paris-guide-map-popup .js-map-empty-state {
  display: block;
}

/*
  "load more" while the next page is being fetched (pages/places.blade.php +
  guide-app.js). The label is left alone on purpose: swapping it for a
  "loading..." string would resize the button under the cursor mid-click and
  needs a second translation key for every one of the 16 locales, so the
  working state is carried by the cursor, a dimmed face and a slow pulse
  instead. aria-busy on the same element covers assistive tech.

  club-main.css's own spent-button rule keys off [disabled], which never
  applies here - this button is an <a>, and it is not spent, only busy.
*/
.club-btn--load-more.is-loading {
  cursor: progress;
  opacity: 0.6;
  animation: guide-load-more-busy 900ms ease-in-out infinite alternate;
}

@keyframes guide-load-more-busy {
  from { opacity: 0.45; }
  to { opacity: 0.85; }
}

/* Still visibly dimmed, just not pulsing - the 0.6 above stays in force. */
@media (prefers-reduced-motion: reduce) {
  .club-btn--load-more.is-loading {
    animation: none;
  }
}

/*
  The failure message rendered (hidden) under the button. It is the only
  child that ever joins .club-section__load-more in that flex column, so a
  plain top margin is all the separation it needs.
*/
.js-load-more-error {
  margin-top: 8px;
}

/*
  Arena map (pages/arena-map.blade.php) - one screen, no document scroll.

  Unlike the guide map, club-main.css already handles both concerns for this
  page on its own: .ewc-2026-paris-guide-arena-map-wrapper's height already
  switches vh -> dvh under its own max-width:640px media query (the supplier
  fixed the iOS layout-vs-visual-viewport issue here already, unlike the map
  wrapper which needed our override in Task 8), and
  .main:has(.ewc-2026-paris-guide-arena-map-wrapper) already sets
  overflow:hidden. This rule is only the same belt-and-suspenders as
  body.is-map-page above: a second, :has()-independent guarantee anchored to
  the body class the brief's own contract expects, not a fix for a gap in the
  supplier's CSS.
*/
body.is-arena-page {
  overflow: hidden;
}

/*
  "where am i?" tag-button: club-tag--accent (club-main.css) only sets the
  text/border color, the background comes from the base .club-tag rule - a
  filled pill like the other filter tags. The client asked for this one
  button specifically to sit flat with no fill.
*/
.js-where-am-i {
  background: transparent;
  cursor: pointer;
}

/*
  Smooth popup card appearance transition (place card fade-in).

  The popup container's visibility is toggled by the 'is-active' class via
  the vendor CSS's display property, which cannot be transitioned. Instead,
  we animate the card's opacity, which starts at 0 and transitions to 1 when
  a) the popup becomes active (is-active class is added), and
  b) the slot containing the card is not hidden (the :not([hidden]) selector).

  This technique animates opacity instead of display, giving a smooth fade-in
  effect (the client's "плавное размытие" — soft appearance) without breaking
  the display toggle or the hidden/visibility model the JS relies on. The
  opacity property can be freely transitioned while display cannot, and since
  the slot's hidden attribute already keeps the card out of the reflow, the
  opacity change is purely visual.
*/
.ewc-2026-paris-guide-map-popup__item {
  opacity: 0;
  transition: opacity 200ms ease-out;
}

.ewc-2026-paris-guide-map-popup.is-active .js-map-popup-slot:not([hidden]) .ewc-2026-paris-guide-map-popup__item {
  opacity: 1;
}

/*
  Respect user's motion preference: disable the fade transition for users who
  have indicated they prefer reduced motion. Cards will appear/disappear
  instantly, matching the user's comfort level without animation.
*/
@media (prefers-reduced-motion: reduce) {
  .ewc-2026-paris-guide-map-popup__item {
    opacity: 1;
    transition: none;
  }
}

/*
  Soft edge around the popup card (the other half of the client's "плавное
  размытие карточки, видно снизу как отображается резкий переход").

  club-main.css gives the card box-shadow: 0 0 100px 0 #02f - a wide blue
  blur that reads exactly as the mockup's screenshot shows, because the
  mockup's map is Google's default *light* raster. Our map carries the
  client's own dark blue-violet style, and a blue blur over a blue-violet map
  is invisible: what is left is the card's bare rectangle with a hard cut
  along every edge, the bottom one most obvious since the description ends
  there.

  So the halo is rebuilt to be visible against a dark map: a tight blue rim,
  a mid blue bloom, and - doing most of the work - a wide, dark falloff that
  dims the map immediately around the card so its edge dissolves instead of
  ending. Listed after the vendor rule and on a more specific selector
  (.is-map-page), so it replaces the single blue shadow rather than stacking
  with it.

  Phones stay flat: the card is nearly viewport-wide there, so any wide blur
  has nowhere to fade into and turns into a bar down both edges - the exact
  complaint the max-width:640px block above fixes. That block sits earlier in
  this file and carries the same specificity as the rule below, so the
  cancelling declaration is repeated here, after it, where it wins.
*/
.is-map-page .ewc-2026-paris-guide-map-popup__item {
  box-shadow:
    0 0 0 1px rgba(0, 34, 255, 0.35),
    0 0 40px 6px rgba(0, 34, 255, 0.4),
    0 0 120px 32px rgba(0, 34, 255, 0.22),
    0 20px 80px 32px rgba(4, 2, 16, 0.8);
}

@media (max-width: 640px) {
  .is-map-page .ewc-2026-paris-guide-map-popup__item {
    box-shadow: none;
  }
}

/*
  FAQ section headings (pages/faq.blade.php).

  The client's FAQ arrives in four groups, and the heading between them
  borrows the vendor's own card classes so it lines up with the questions.
  What those classes do not give it is any separation: club-faq-area__card
  is padding-only, and club-main.css drops that padding entirely under
  640px, so on a phone the heading sat one pixel above the first question of
  its own group and read as part of it - which is what the client's
  screenshot showed.

  Spacing only, no repaint: the heading keeps the type and colour the mockup
  gives club-h4. It sits close to the questions under it, so it reads as
  belonging to them; what separates one group from the next is the gap
  between the panels themselves, further down.
*/
/*
  Separating two groups is the gap's job now (see .guide-faq-group below), so
  every heading only has to clear the top edge of its own panel - which is
  what the first one always did. The card's own padding does most of that on
  wide screens, but it shrinks with the breakpoints (20px, then 10px, then
  none), so a small margin of our own keeps the heading off the edge at every
  width instead of chasing the vendor's padding scale.
*/
.club-faq-area .guide-faq-section {
  margin-top: 8px;
  margin-bottom: 4px;
  /*
    Кегль задан здесь, а не оставлен на club-h4, потому что размер вопросов
    под ним мы тоже задали руками (18px/15px, см. ниже). club-h4 берёт токен
    --club-font-size-h3, а тот ужимается по брейкпоинтам: 24 -> 18 -> 14 ->
    3.89vw. Ниже 1380px заголовок сравнивался с вопросом, а ниже 980px
    становился прямо мельче него - при том что вопрос ещё и почти той же
    жирности. Раз вопрос фиксированный, заголовок тоже фиксируем, иначе они
    расходятся на каждом брейкпоинте заново.
  */
  font-size: 24px;
}

/*
  One panel per group, with the page background showing through between them
  (client's ask - see pages/faq.blade.php for why the fill moved off the area
  itself). Padding-bottom balances the heading's margin-top above, so a group
  is not visibly heavier at one end; the vendor's own spacing scale rather
  than a fixed pixel so it tracks the breakpoints.
*/
.club-faq-area {
  display: flex;
  flex-direction: column;
  gap: var(--club-space-2xl);
}

.guide-faq-group {
  padding-bottom: 8px;
}

@media (max-width: 640px) {
  .club-faq-area .guide-faq-section {
    /* No card padding at this breakpoint, so the margins are all there is. */
    margin-top: 18px;
    margin-bottom: 10px;
    /* Вопрос здесь 15px - заголовок держим на том же шаге выше. */
    font-size: 19px;
  }

  /*
    ...and the same horizontal inset as the questions. Under 640px
    club-main.css zeroes .club-faq-area__card's padding and moves the inset
    into .club-faq-area__card--xs-accordion-header instead, which the heading
    is not - so its text sat hard against the panel's left edge while every
    question below it was indented. Reusing that rule's own --club-space-2xl
    rather than a measured pixel value keeps the two aligned wherever the
    vendor rescales its spacing.
  */
  .club-faq-area .guide-faq-section {
    padding-inline: var(--club-space-2xl);
  }
}

/*
  FAQ question and answer text, one step up from the mockup's size.

  The client asked for both to be "a bit bigger" once the whole list became an
  accordion at every width: with the answers collapsed, the questions are the
  page, and at club-text-16 they read small for what is now the only thing to
  scan. Scoped to .club-faq-area so club-text-16 keeps its normal size
  everywhere else - it is shared with the place cards and the empty states.

  Phones get a smaller bump than the desktop: club-main.css already scales
  --club-font-size-base down by viewport width there, and matching the desktop
  step would cost two words per line on a 375px screen.
*/
.club-faq-area .club-faq-area__card--xs-accordion-title {
  font-size: 18px;
}

.club-faq-area .club-faq-area__card--xs-accordion-text {
  font-size: 17px;
  line-height: 1.55;
}

@media (max-width: 640px) {
  .club-faq-area .club-faq-area__card--xs-accordion-title {
    font-size: 15px;
  }

  .club-faq-area .club-faq-area__card--xs-accordion-text {
    font-size: 15px;
  }
}

/*
  Ряд кнопок "recommends" на телефоне (вторая строка фильтров).

  club-max-content-xs есть в обновлённой вёрстке, но не в вендорной CSS,
  которая у нас лежит, - её версия старше разметки. Правило простое и нужно
  ровно здесь, поэтому добавляем его сами, а не тянем весь club-main.css
  заново: полная замена вендорной таблицы задела бы всё остальное.

  Смысл: ряд шире экрана - и это нормально. width: max-content не даёт кнопкам
  сжаться и переноситься, а обёртка scrol-xs прокручивает их вбок. Здесь
  горизонтальная прокрутка уместна, в отличие от прежней карусели фильтров:
  листается один ряд коротких кнопок, а не блок, перекрывающий вертикальный
  скролл страницы.

  Прежний блок правил на этом месте складывал фильтры в столбик. Он появился,
  когда в строке было три селекта и они не помещались; в обновлённой вёрстке в
  строке двое, "recommends" уехал вниз кнопками, и столбик стал не нужен -
  он же и мешал бы, растягивая селекты во всю ширину.
*/
@media (max-width: 640px) {
  .guide-filters .club-max-content-xs {
    width: max-content;
  }
}

/*
  Окно локации на карте: правила из обновлённой вендорной таблицы.

  Вендорная CSS, которая лежит у нас, старше обновлённой разметки, и этих
  четырёх правил в ней нет. Переносим только их, а не заменяем club-main.css
  целиком: новая таблица отличается от нашей на пять килобайт правок по всему
  файлу, и подменять её ради попапа значит менять заодно всё остальное.
  Значения скопированы дословно.

  Что они дают: на телефоне карточка занимает всю ширину контейнера, а не
  колонку сетки (club-col-6-xs), и тянется на всю высоту попапа, прижимая
  содержимое к верху. Это и есть та мобильная раскладка, которую клиент
  прислал на clip077.

  Чего мы сознательно не берём: .club-close-in-header--xs { position: fixed;
  opacity: 0 } - в обновлённой вёрстке крестик в шапке карточки на телефоне
  прячется, потому что там закрывать окно предлагается другим элементом. У нас
  этот крестик единственный способ закрыть карточку (плюс Escape, которого на
  телефоне нет), так что скопировать правило значило бы оставить мобильного
  посетителя без кнопки закрытия.
*/
.ewc-2026-paris-guide-map-popup .club-container,
.ewc-2026-paris-guide-map-popup .club-container > .club-row {
  height: 100%;
}

/*
  Целимся в сам слот карточки, а не в любую колонку - в отличие от вендорного
  правила, откуда это скопировано.

  В их вёрстке в попапе одна карточка, и "любая колонка" - это она. У нас в
  этой же строке лежат карточки всех восьмидесяти мест плюс блок "No places
  match the selected filters", и прячутся они по-разному: слоты атрибутом
  hidden, блок - правилом .js-map-empty-state { display: none }. Оба способа
  слабее по специфичности, чем этот селектор, поэтому дословная копия показала
  разом и все восемьдесят карточек, и сообщение о пустом результате при
  невыключенных фильтрах - именно это клиент и сфотографировал.

  [data-place-slot] отсекает сообщение, :not([hidden]) - все закрытые
  карточки, кроме открытой.
*/
.ewc-2026-paris-guide-map-popup .club-container > .club-row > [data-place-slot]:not([hidden]) {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

/*
  Название места в карточке списка - максимум две строки, дальше многоточие.

  Обрезаем сам <h2>, а не ссылку внутри: line-clamp работает по строкам
  блочного контейнера, а <a> здесь строчный и своих строк не образует.

  -webkit-* без префиксной альтернативы - это не небрежность: line-clamp до сих
  пор задаётся именно так во всех браузерах, включая Firefox и Safari.
  Современное свойство line-clamp продублировано рядом на случай, когда старая
  запись перестанет действовать.

  Полное название остаётся в атрибуте title (см. partials/place-card) и целиком
  показывается в карточке на карте.
*/
.guide-card-title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  /*
    Название забирает свободную высоту шапки, поэтому теги и оценка ложатся на её
    низ - и совпадают по строке у всех карточек ряда.

    Шапки в ряду и так выровнены по самой высокой (club-eq-height-card), но
    прижаты были к верху: у названия в одну строку оставался пустой запас снизу,
    и его оценка висела выше, чем у соседа с названием в две строки. Клиент
    отметил это красной линией.
  */
  flex: 1 1 auto;
  /*
    Многоточие у обрезанного названия - фирменным красным, сам текст остаётся
    белым.

    Точки браузер рисует цветом того элемента, на котором стоит обрезка, а не
    цветом текста внутри. Обрезка стоит на h2, поэтому красный нужен именно ему.

    Само название красное и без нас: оно лежит в ссылке club-link-primary, а у
    неё color: var(--club-color-primary) - это макетный цвет заголовка карточки,
    белым он становится только при наведении на карточку. Белым же оставался и
    h2, отчего обрезанное название выглядело двухцветным: красный текст и белые
    точки. Теперь цвет один.

    У названий, влезающих в две строки, правило ничего не делает: точек нет.
  */
  color: var(--club-color-primary);
}

/*
  Потолок ширины карточки на больших экранах.

  Ширину задаёт сетка в долях, и это работает до определённого размера: треть от
  1440 - это 430px, ровно тот размер, под который раскладку и настраивали. Но
  треть от 1920 - уже около 600, а вместе с ней вырастает и фотография (16:9 от
  ширины), и карточка начинает выглядеть баннером.

  460px - чуть выше тех 430: на 1440 ничего не меняется (430 меньше потолка), а
  всё, что шире, упирается в него. Проценты сетки при этом не трогаем - только
  ограничиваем сверху.

  Отдельным медиазапросом, а не общим правилом: до 1024 включительно ширину
  задают свои шаги сетки (см. pages/map.blade.php), и там потолок не нужен.
*/
@media (min-width: 1025px) {
  .ewc-2026-paris-guide-map-popup .club-container > .club-row > [data-place-slot] {
    max-width: 460px;
  }
}

/*
  Отдельный крестик шторки (pages/map.blade.php) существует только для
  телефона. Скрываем его по умолчанию, а не только вне медиазапроса: <button>
  сам по себе видим, и без этой строки он торчал бы в углу карты на десктопе,
  где закрывать карточку нечем - там для этого есть крестик внутри неё.
*/
.guide-map-close {
  display: none;
}

/*
  Запас под текстом в карточке на карте, чтобы в конце прокрутки последняя
  строка не упиралась в кромку.

  Почему именно так, а не отступом снаружи карточки: прокручивается контейнер
  попапа, а длину прокрутки задаёт слот высотой в 100% строки. Карточка при
  длинном описании вырастает за слот, и всё, что лежит снаружи - и padding
  попапа, и margin карточки, - в конец прокрутки не попадает. Я пробовал оба,
  просвет так и остался нулевым. Отступ внутри карточки от этого не зависит:
  он часть её содержимого и прокручивается вместе с ним.

  Значение равно верхнему просвету (--club-space-3xl, 30px), чтобы сверху и
  снизу читалось одинаково.
*/
/*
  Отступ снизу здесь стоял и был снят: он давал на фоне лишнюю полосу.

  Подвал карточки залит вендорным градиентом (club-box-bg--gradient), а карточка
  под ним - ровным цветом. Градиент к низу выцветает, поэтому добавленные 30px
  показывали этот ровный цвет отдельной полосой другого тона - клиент это и
  сфотографировал.

  Снаружи карточки отступ тоже не работает: прокручивается контейнер попапа, а
  длину прокрутки задаёт слот фиксированной высоты, и padding с margin за
  пределами карточки в конец прокрутки не попадают (проверено оба).

  Значит нужен не отступ, а правка самой связки: снять со слота height: 100% на
  широких экранах, чтобы его высоту задавало содержимое, и тогда собственный
  padding-block попапа окажется после карточки. Это меняет раскладку карточки на
  десктопе, поэтому делать надо с проверкой на обеих ширинах и на прокрутке.
*/

/*
  Карточка на карте непрозрачна целиком.

  Фон ей давали только шапка и подвал (club-box-bg--gradient), а полоса с
  кнопкой маршрута осталась без него - и сквозь неё просвечивала карта, будто в
  карточке прорезь. Заливка на всей карточке закрывает любую такую щель разом,
  включая место под фотографией, пока та грузится.
*/
.ewc-2026-paris-guide-map-popup__item {
  background-color: #1b1030;
}

/*
  Кнопка маршрута справа и на широких экранах - клиент просит одинаково везде.
  На телефоне то же самое делает правило в @media ниже; здесь порядок задаётся
  для всех ширин, а не только для узких.
*/
.guide-popup-actions {
  flex-direction: row-reverse;
}

/*
  Время ходьбы в этой строке не обрезается многоточием.

  club-dotted-1 на подписи - это nowrap с ellipsis, и на десктопе строка
  выходила как "5 MIN WALK FROM A...". Здесь рядом только кнопка, места хватает,
  а обрезанная фраза читается как ошибка вёрстки.
*/
.guide-popup-actions .club-dotted-1 {
  /*
    Время ходьбы переносится на вторую строку, а не обрезается и не заезжает под
    кнопку.

    club-dotted-1 - это nowrap с ellipsis. С ellipsis выходило "5 MIN WALK FROM
    A...", а когда я его снял, длинные значения вроде "1 H 22 MIN WALK FROM
    ARENA" полезли под кнопку: строка одна, кнопка не сжимается, тексту деться
    некуда. Разрешаем перенос - фраза укладывается в две строки рядом с
    кнопкой, ничего не пропадает и ничего не наезжает.
  */
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

/*
  Короткая подпись стоит рядом с кнопкой, длинная уходит на свою строку.

  Одного разрешения переносить слова не хватило: рядом с кнопкой ячейке
  оставалось около семидесяти пикселей, и "1 H 22 MIN WALK FROM ARENA"
  складывалось в пять строк, раздувая блок до 124px. Основа в 11rem говорит
  обратное: если столько места нет, ячейка не сжимается, а переносится вниз - и
  там занимает всю ширину, укладываясь в одну-две строки.
*/
.guide-popup-actions {
  flex-wrap: wrap;
}

.guide-popup-actions .club-flex-1 {
  /*
    Порог 9rem, а не 11.

    С 11rem строка ломалась на карточках около 370px - это диапазон примерно от
    981 до 1024: кнопка занимает ~190px, подписи оставалось 10.6rem, чуть меньше
    порога, и она уезжала на свою строку. Выглядело это как пустой блок с кнопкой
    посередине.

    9rem (144px) хватает, чтобы "34 MIN WALK FROM ARENA" встало рядом с кнопкой на
    любой карточке от 340px. Совсем длинные значения вроде "1 H 22 MIN WALK FROM
    ARENA" при этом переносятся внутри своей ячейки в две строки, а не сжимаются в
    пять, как было бы без порога вообще.
  */
  flex: 1 1 9rem;
  min-width: 0;
}

/*
  На телефоне окно локации - шторка во весь экран под шапкой, а не карточка
  поверх карты. Правила из обновлённой вендорной таблицы, значения дословные.

  top: var(--header-height, 0) - шторка начинается сразу под шапкой сайта и
  закрывает собой строку фильтров; z-index: 100 поднимает её над картой.
  Именно так это выглядит на присланном макете.

  Селекторы с [class*=club-col-] снова сужены до [data-place-slot]:not([hidden])
  - по той же причине, что и выше: у нас в этой строке лежат все восемьдесят
  карточек и блок пустого результата, и дословная копия показала бы их разом.
*/
@media (max-width: 640px) {
  /*
    Селектор с .is-map-page, а не просто .ewc-2026-paris-guide-map-popup:
    выше по файлу этому же элементу задано height: 100% (правило с двумя
    классами), и оно перебивало height: auto из перенесённого блока. Итог был
    не косметический: при position: fixed с заданными top, bottom и height
    коробка переопределена, и margin-top: auto добирает разницу отрицательным
    значением - ровно -48px, то есть высоту шапки. Шторка уезжала вверх на
    высоту шапки и закрывала её, хотя top: 48px был выставлен верно. В макете
    height: auto, переопределения нет, и шапка остаётся видна над шторкой.
  */
  /*
    Шторка занимает нижнюю часть экрана, а не весь экран под шапкой: сверху
    остаётся карта, где видна открытая точка. Полноэкранный вариант был из
    присланной вёрстки, но клиент от него отказался - тапнув по точке, человек
    терял её из виду и не понимал, где это место относительно остальных.

    55dvh - доля, при которой карте остаётся заметный кусок, а карточке хватает
    на шапку, строку действия и начало описания. dvh, а не vh: в мобильных
    браузерах адресная строка съезжает, и vh считается по высоте без неё, из-за
    чего шторка вылезала бы за нижний край.
  */
  .is-map-page .ewc-2026-paris-guide-map-popup {
    /*
      Две высоты подряд - не опечатка. Браузер, который не знает dvh, отбросит
      вторую строку целиком, и тогда высота осталась бы от правила выше по
      файлу (height: 100%): шторка растянулась бы на весь экран, перестала
      прижиматься к низу и прокрутка внутри неё не включилась бы - ровно то,
      что и наблюдалось. Первая строка в vh даёт рабочее значение везде, вторая
      уточняет его там, где dvh поддержан.
    */
    /*
      Шторка прижата к низу карты, а не окна.

      Было position: fixed - то есть привязка к окну. Пока страница не
      прокручена, это совпадает; стоит появиться прокрутке (или сделать снимок
      всей страницы целиком), и шторка оказывается не там, где карта
      заканчивается - под ней видна полоса карты с плашкой Google. Родитель
      .ewc-2026-paris-guide-map-wrapper__inner и так position: relative, так что
      absolute привязывает её ровно к области карты.

      Высота от неё же, а не от вьюпорта: 55% карты, а не экрана. Заодно
      отпадает возня с vh/dvh и съезжающей адресной строкой.
    */
    position: absolute;
    height: auto;
    /*
      Потолок поднят с 55% до 68%: фотография вернулась в свою пропорцию (242px
      на 430), и вместе с шапкой, строкой действия и тремя строками описания в
      55% карты это уже не укладывалось. Карте сверху остаётся около трети -
      достаточно, чтобы видеть выбранную точку и её окружение.
    */
    max-height: 68%;
    top: auto;
    padding-block: 0;
    /* padding-inline тоже в ноль, хотя в переносимом правиле его нет: в
       обновлённой вендорной таблице базовому .ewc-2026-paris-guide-map-popup
       боковых отступов не задано, а в нашей, что постарше, задано 16px. Из-за
       них шторка не доходила до краёв - слева и справа оставались полоски
       карты. */
    padding-inline: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 100;
    /*
      Гасим горизонтальную прокрутку шторки.

      Внутри неё club-row висит на отрицательных боковых полях (-6px), то есть
      содержимое на 12px шире экрана - так же и в макете. Там это никому не
      мешает: у попапа overflow: visible, и лишнее срезает overflow: hidden у
      body. У нас же выше по файлу попапу задан overflow-y: auto (чтобы
      длинная карточка прокручивалась внутри себя), а по спецификации, если
      одна ось не visible, вторая из visible становится auto - и браузер
      показал настоящую горизонтальную полосу. Явный hidden отменяет это
      повышение, вертикальную прокрутку не трогая.
    */
    overflow-x: hidden;
    /*
      И по вертикали тоже hidden: выше по файлу шторке задан overflow-y: auto,
      из-за чего прокручивались две вещи сразу - внутренняя область с фото и
      описанием и вся карточка целиком вместе с названием, оценкой и кнопкой.
      Заголовок должен стоять на месте, поэтому прокрутка здесь ровно одна, в
      guide-popup-scroll. Карточка в потолок 55% укладывается по построению:
      внутренняя область сама ограничена max-height.
    */
    overflow-y: hidden;
  }

  .ewc-2026-paris-guide-map-popup .club-container {
    padding-left: 0;
    padding-right: 0;
    height: 100%;
  }

  .ewc-2026-paris-guide-map-popup .club-container [data-place-slot]:not([hidden]) {
    flex: 0 0 100%;
    max-width: 100%;
  }

  .ewc-2026-paris-guide-map-popup .club-container > .club-row {
    height: 100%;
  }

  /* Карточка занимает всю высоту шторки и раскладывается колонкой: шапка,
     фото своей высоты, низ на остаток. На широких экранах эти же свойства ей
     даёт club-flex-column в разметке, которого в попапе больше нет. */
  .ewc-2026-paris-guide-map-popup__item {
    box-shadow: none;
    height: 100%;
    display: flex;
    flex-direction: column;
  }

  /*
    Шапка, пока шторка открыта: прокрутка страницы заперта, бургер убран,
    логотип приглушён - под шторкой они всё равно ни на что не ведут, а
    открытый бургер поверх неё был бы двумя диалогами сразу. Класс на <body>
    ставит guide-app.js (MAP_DIALOG_OPEN), правила - из обновлённой вендорной
    таблицы, дословно.
  */
  .club-map-dialog-is-open {
    overflow: hidden;
  }

  .club-map-dialog-is-open .club-menu-burger {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }

  .club-map-dialog-is-open .club-menu-burger svg {
    opacity: 0;
  }

  .club-map-dialog-is-open .club-hide-then-menu-open {
    opacity: 0.2;
    pointer-events: none;
  }

  /* Логотип - единственный из трёх, кому вендорное правило задаёт свою
     непрозрачность и перебивает строки выше. Добавляем к селектору сам body,
     на котором и висит класс: так специфичности хватает, и логотип гаснет
     вместе с остальной шапкой, как в макете. */
  /*
    Крестик уезжает в шапку - как в макете, где он стоит справа от
    приглушённого логотипа, а не в строке с названием места.

    Вёрстка помечает его классом club-close-in-header--xs, но в их таблице у
    того класса только position: fixed и opacity: 0 - видимым его делает уже
    их скрипт. Своего такого скрипта у нас нет, поэтому класс не берём, а
    позиционируем сам крестик: он и так единственный способ закрыть шторку.

    z-index на единицу выше шторки (100), иначе она перекрывала бы его.
    Отступ сверху центрирует иконку 24px по высоте шапки.
  */
  /*
    Крестик в полосе шапки - отдельная кнопка рядом с попапом
    (pages/map.blade.php), а та, что внутри карточки, на телефоне прячется.
    Иначе их было бы два подряд.

    Высота во всю шапку и центрирование флексом, а не расчёт отступа сверху:
    в разметке иконка объявлена 24px, но вендорные стили ужимают её до 19, и
    формула "(высота шапки - 24) / 2" ставила крестик выше, чем в макете.
  */
  /*
    Крестик снова живёт в шапке карточки, а не в полосе шапки сайта.

    В полосу его переносили, пока шторка закрывала весь экран: карточка
    начиналась от самого верха, и крестику там было не место. Теперь шторка
    занимает низ экрана, её собственная шапка на виду - и крестик стоит в ней,
    как на присланном клиентом экране. Отдельная кнопка (guide-map-close)
    остаётся в разметке, но не показывается: на десктопе она и раньше была не
    нужна, а на телефоне больше не нужна тоже.
  */
  .guide-map-close {
    display: none;
  }

  /*
    Прокручивается только фото с описанием. Шапка карточки и строка с кнопкой
    маршрута стоят на месте - иначе на невысокой шторке кнопка уезжала бы вверх
    вместе с текстом, и до неё пришлось бы долистывать обратно.

    min-height: 0 обязателен: без него flex-элемент не даёт себя сжать ниже
    содержимого, прокрутка не включается и карточка просто вылезает за нижний
    край шторки.
  */
  /*
    Прокручиваемая область фиксированной высоты: фотография (150) плюс три
    строки описания и отступы.

    Была flex: 1 1 auto - то есть занимала весь остаток шторки. На высоком
    экране остатка хватало на всё описание целиком, прокручивать было нечего, и
    подсказки "тут есть продолжение" не возникало. Клиент просит ровно три
    строки, дальше прокрутка - значит высота должна задаваться, а не
    подстраиваться.

    Шторка при этом больше не тянется на все 55% карты: height: auto ниже даёт
    ей высоту по содержимому, а 55% остаются потолком. Так под карточкой не
    появляется пустоты, если описание короткое.
  */
  .guide-popup-scroll {
    /*
      Потолок, а не фиксированная высота. Жёсткие 220px резервировали место
      всегда: у короткого описания под текстом оставалась пустая полоса. С
      max-height блок сжимается по содержимому, а прокрутка включается только
      когда текста действительно больше трёх строк.
    */
    /*
      Забирает остаток шторки, а не фиксированные 330px.

      Жёсткий потолок был подобран на 430px, где фото в пропорции 16:9 занимает
      242px и три строки описания ещё помещались. На телефоне шириной 590 то же
      фото - уже 332px, то есть больше потолка: в область прокрутки не попадало
      ничего, кроме фотографии, а описание целиком уходило под сгиб - это и было
      видно на снимке из Safari.

      С flex: 1 1 auto область берёт всё, что осталось от шторки после шапки и
      строки с кнопкой, и на большом экране места хватает и фото, и тексту. Сама
      шторка ограничена сверху 68% видимой карты, так что расти бесконечно она не
      может.
    */
    flex: 0 1 auto;
    height: auto;
    /*
      Потолок долей от видимой высоты, а не пикселями.

      Жёсткие 330px были подобраны под экран 430: там фото 16:9 занимает 242px, а
      на 590 то же фото уже 333px - в область не попадало ничего, кроме
      фотографии. Убрал потолок совсем - пропала прокрутка: без определённой
      высоты область растягивалась под содержимое, и прокручивать становилось
      нечего.

      36% видимой высоты дают то же, что прежние 330px на 430-м экране, и
      пропорционально больше на крупных: 460px на 1278, 335 на 932. Значение
      определённое, поэтому длинное описание снова прокручивается, а короткое не
      оставляет под собой пустоты - высота остаётся auto.
    */
    max-height: calc(var(--guide-visible-h, 100dvh) * 0.36);
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /*
    Запас снизу - на подвале карточки, а не на области прокрутки.

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

    Зачем вообще: панель Safari и Chrome на телефоне висит поверх страницы, а не
    отнимает высоту, и карта под ней продолжается. Шторка прижата к низу карты,
    поэтому без запаса последние строки оказывались за панелью и дочитать их было
    нельзя. env(safe-area-inset-bottom) закрывает вырез там, где браузер о нём
    сообщает, 72px - саму панель, о которой он не сообщает никак.
  */
  .ewc-2026-paris-guide-map-popup__item footer {
    padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 72px);
  }

  /*
    Кнопка маршрута прижата к правому краю, время ходьбы - слева от неё.

    row-reverse, а не перестановка в разметке: порядок в HTML остаётся
    логичным (сначала действие, потом уточнение к нему), и на широких экранах,
    где это правило не действует, ничего не меняется.
  */
  .guide-popup-actions {
    flex-direction: row-reverse;
  }

  /*
    Фотография ниже, чем её собственная пропорция 16:9 даёт при полной ширине
    экрана (на 430px это 242px). В шторке высотой чуть больше пятисот пикселей
    такая картинка забирала почти всё место, и от описания оставалась строка с
    хвостиком - клиент просил, чтобы его было видно строки на три.

    object-fit: cover обязателен вместе с max-height: без него картинка просто
    сожмётся по вертикали и всё на ней вытянется.
  */
  /*
    Высоту фотографии не ограничиваем - клиент попросил оставить как в макете и
    вёрстке, то есть в её собственной пропорции 600/338 (на 430px это 242px).

    Здесь стояло max-height: 150px с object-fit: cover. Ограничение я вводил,
    чтобы в невысокую шторку поместилось и фото, и три строки описания. Теперь,
    когда фото в полный рост, эти три строки требуют больше места - поэтому
    ниже подняты и область прокрутки, и потолок шторки. Без этого фото одно
    занимало бы всю прокручиваемую область, а текст целиком уходил бы под сгиб.
  */

  /*
    Пока фотография не загрузилась, её место было прозрачным - сквозь карточку
    просвечивала карта, и это читалось как дыра в интерфейсе. Заливка держит
    прямоугольник тёмным с первого кадра: дальше картинка просто появляется
    поверх, без вспышки.

    Цвет - фон карточки из вендорной палитры, чтобы пустое место не выделялось
    на её градиенте.
  */
  .is-map-page .ewc-2026-paris-guide-map-popup .picture-16x9 {
    background-color: #1b1030;
  }

  body.club-map-dialog-is-open .club-main__logo,
  body.club-map-dialog-is-open .club-main__logo.club-hide-then-menu-open {
    /* !important - единственный способ: логотипу непрозрачность держит
       анимация club-main.js (панель поиска), а анимация сильнее любого
       обычного объявления, сколько специфичности ни добавляй. Инлайн-стиля на
       элементе нет, конкурирующих правил с opacity - тоже, проверено. */
    opacity: 0.2 !important;
    pointer-events: none;
  }
}

/*
  FAQ card: one column at every width.

  Turning the accordion on everywhere (the --desktop modifier on the card) got
  the questions collapsing, but left the mockup's two-column grid underneath:
  the question sat in a 33% column and the answer opened in a separate column
  to its right, past a 16% offset - so an opened answer appeared beside the
  question with a wide empty band between them, which is what the client
  called out.

  The mobile layout is the one they want everywhere: question full width,
  answer unrolling directly underneath it, also full width. Below 640px
  club-main.css already does that through club-col-12-xs/club-offset-0-xs; up
  here the same thing is done by flattening every column inside the card to a
  full-width row and dropping the offset the answer column carries.

  Scoped to the FAQ card, so the grid keeps working normally everywhere else -
  club-col-* and club-offset-* are the vendor's global grid.
*/
.club-faq-area__card--xs-accordion--desktop > .club-row > [class*='club-col-'] {
  flex: 0 0 100%;
  max-width: 100%;
  margin-inline-start: 0;
}

/*
/*
  Строка "рейтинг + выбор команды" на карточке места (partials/place-card).

  Мокап рисовал её одной линией: ★ рейтинг | подпись Google | бейдж команды.
  Не помещалось ни на одной ширине, и всегда за счёт команды. Подпись клиент
  снял (см. partials/place-card), но раскладка ниже остаётся: тег команды на
  своей строке - это его же отдельное решение, и без подписи оно не отменяется.
  Группа рейтинга - club-flex-none, то есть flex: none, она не сжимается
  никогда; бейдж команды - club-flex-1 с min-width: 0, сжимается до нуля.
  Поэтому лишнее отъедалось у бейджа:

    - в сетке -xs (карточка ~150px) он схлопывался в нулевую ширину и логотип
      рисовался в промежутке между двумя соседними карточками;
    - на десктопе (строка 246px, рейтинг с атрибуцией ~200px) ему оставалось
      18-29px - логотип и обрезанное в "S..." название.

  Лечится переносом бейджа на свою строку:

    ★ 4.6 (24 497)
    [лого] vitality choice

  На любой ширине, а не только на телефоне: 246px в четырёхколоночной сетке
  ничем не просторнее 150px в двухколоночной, просто там это выглядело как
  обрезанный бейдж, а не как вылезший наружу логотип.
*/
.guide-card-meta {
  flex-wrap: wrap;
  column-gap: var(--club-space-1xl);
}

/*
  Тег команды стоит в одной строке с оценкой (clip080/081).

  Своя строка ему понадобилась, когда между ними жила подпись "Powered by
  Google": втроём они не помещались ни на одной ширине, и обрезался всегда тег
  - "SKIN.CLUB CHOI...". Подпись сняли, место освободилось, и клиент вернул
  вёрстку к своей исходной: ★ 4.7 | лого | SKIN.CLUB CHOICE.

  Тег остаётся club-flex-1 с min-width: 0, то есть он и сжимается первым.
  Запас появился с двух сторон: подписи больше нет, а на телефоне карточки
  теперь в одну колонку (~343px вместо ~150px), где раньше было теснее всего.
  wrap ниже - страховка: если чьё-то название команды окажется длиннее всех,
  строка перенесётся, а не обрежется.
*/
.guide-card-meta__team {
  min-width: 0;
}

/*
  Наведение на кнопку у правого края больше не растягивает страницу.

  Декор кнопки на hover уезжает вправо на translateX(--pathBDWidth * 3 + 2px),
  то есть на 38px при обычных 12px. Кнопке "load more" до края контейнера
  остаётся тридцать: восемь пикселей декора вылезали за viewport, и браузер
  показывал горизонтальную полосу прокрутки на всю страницу.

  Правило вендорское, взято дословно из свежей поставки вёрстки
  (club-main.min.css: `@media (max-width:1920px){.club-section:has(.club-btn)
  {overflow:clip}}`). Наша копия club-main.min.css старше поставки и этого
  правила ещё не содержит, а обновлять её целиком сейчас нельзя: в новой версии
  изменены и правила .ewc-2026-paris-guide-map-popup, под которые настроена вся
  мобильная шторка карты. Поэтому переносим одно правило, а не файл.

  clip, а не hidden: hidden сделал бы секцию контейнером прокрутки и сломал бы
  position: sticky внутри неё. По вертикали не режет ничего - ни один элемент
  внутри секций за их границы не выходит, проверено замером на всех трёх секциях
  страницы мест.
*/
@media (max-width: 1920px) {
  .club-section:has(.club-btn) {
    overflow: clip;
  }
}
