/* catalog.css — the public catalog component layer (internal/catalog, docs/16 §C).
   The BRAND system (tokens, buttons, cards, header/footer/hero) comes from the shared
   marketing-site stylesheet linked as /cat/brand/style.css. This file only ADDS
   catalog-specific blocks.

   STANDING RULES (user decisions):
   1. On the catalog, any gold/amber accent on a LIGHT background is brand RED instead
      (--red #C8102E). Gold remains board-zone/dark-background only.
   2. Content geometry matches your.beer (measured 2026-08-24): container 1140/15,
      place-card grid 4/3/2/1 cols (xl/lg/sm/xs), 30px gutters, card body padding 20,
      card title 22.4/700 BODY font, meta 14/21, badges 12px, beer rows as single-
      column compact list lines (brewery 12/300 over title 19.2/700, hairline dividers).
      Visual language stays BEER.BY (tokens, Oswald display headings, zone rhythm). */

/* ====== page container (reference 1140) ====== */
main .container { max-width: 1140px; }

/* the hidden ATTRIBUTE must always win: brand/author rules that set display:flex on
   a component (.cat-pager, .support__card, …) would otherwise defeat the UA's
   [hidden] { display:none } and leak "empty state"/pager chrome into view */
[hidden] { display: none !important; }

/* adjacent same-zone sections (home: places→fresh; place: taps→about): the brand
   .section pads BOTH sides with --section-y, so two siblings double the rhythm
   (up to ~216px of air). Collapse the seam to a single beat — the first section's
   bottom padding alone. */
.zone--paper.section + .zone--paper.section { padding-top: 0; }

/* page head → first content section (place/places/beers/breweries/beer/brewery/
   search/disclaimer — user decision 2026-08-27): the head's bottom padding is 0,
   so the FULL --section-y (up to 108px) sat right under the H1 — roughly halve it,
   the same beat as the home blocks */
.zone--paper.cat-page-head + .zone--paper.section { padding-top: calc(var(--section-y) * 0.45); }

/* list pages (Места / Сорта / Пивоварни — cat-listhead on the head section):
   the head→filters air stacked TWO terms — the base .section__head margin
   (clamp 2..3.25rem) plus the 0.45×--section-y beat (up to ~49px) ≈ ~100px,
   which read as a dead band between the H1 and the filter bar. Halve BOTH
   terms on the list pages only (user request 2026-08-29); detail pages keep
   the generic beats. */
.cat-listhead .section__head { margin-bottom: clamp(1rem, 0.7rem + 1vw, 1.65rem); }
.zone--paper.cat-page-head.cat-listhead + .zone--paper.section { padding-top: calc(var(--section-y) * 0.22); }

/* section head row: title left + "see all" link at the row's right edge
   (reference your.beer pattern — replaces the fat centered cat-more button on home) */
.cat-sechead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  /* the see-all link is no longer a 12px aside (user request 2026-09-09: ×2 size,
     red underlined CTA) — on narrow screens title + big nowrap link wrap instead
     of overflowing */
  flex-wrap: wrap;
}
.cat-seeall {
  font-family: var(--font-body);
  font-size: 1.125rem;           /* was 12px; ×2 (1.5rem) competed with the section
                                    title (user feedback 2026-09-09) — settled at 18px */
  font-weight: 600;
  color: var(--red);              /* the intro «Добавьте свое заведение» treatment */
  text-decoration: underline;
  text-underline-offset: 2px;
  white-space: nowrap;
  padding-bottom: 0.55rem;       /* align with the title baseline area */
}
.cat-seeall:hover { color: var(--red); }

/* catalog home heads: the brand system's .section__head caps at 720px, which pinned
   the "Все места / Все сорта" links away from the right content edge — widen to the
   full container (UX review). Section titles step down to --fs-h3 so the page h1
   («Каталог пива и пивных мест») clearly leads — same hierarchy fix as the place page. */
.section__head--wide { max-width: none; }
.cat-sechead .section__title { font-size: var(--fs-h3); margin-top: 0.45rem; }
.section__head--wide { margin-bottom: clamp(1.4rem, 1rem + 1.2vw, 2.1rem); }
.cat-sechead .cat-seeall { padding-bottom: 0.4rem; } /* baseline-align with the h3 title */

/* ====== compact page intro (no hero: the catalog is a directory) ====== */
/* no full-width hairline under the lead (UX review): the intro reads as part of the
   page flow; the sections below carry their own heads. */
.cat-intro {
  padding-block: clamp(1.5rem, 1rem + 1.6vw, 2.5rem) 0;
}
.cat-intro__title {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.005em;
  line-height: 1.05;
  font-size: var(--fs-h2);
  color: var(--ink);
  margin-top: 0.85rem;
}
.cat-intro__lead {
  margin-top: 0.75rem;
  font-size: var(--fs-lead);
  color: var(--muted);
  max-width: 60ch;
}
.cat-intro__add {
  margin-top: 0.5rem;
  font-size: var(--fs-lead);
  color: var(--muted);
  max-width: 60ch;
}
.cat-intro__add a { color: var(--red); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
.cat-intro__add a:hover { color: var(--red); }

/* ====== pre-footer «add your venue» CTA (user request 2026-09-07): the home hero
   line promoted to every page — light zone band right before the black footer.
   Centered, same type scale/colouring as the hero line so it reads as one family. */
.cat-addcta { padding-block: clamp(1.25rem, 1rem + 1.2vw, 2rem); }
.cat-addcta p {
  margin: 0;
  text-align: center;
  font-size: var(--fs-lead);
  color: var(--muted);
}
.cat-addcta a { color: var(--red); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
.cat-addcta a:hover { color: var(--red); }

/* ====== paper page header (place / brewery / legal): crumb + title + meta ====== */
.cat-page-head { padding-block: clamp(1.5rem, 1rem + 1.6vw, 2.5rem) 0; }
.cat-page-head__row { display: flex; align-items: center; gap: 1.25rem; }

/* place page head (your.beer jumbotron parity): kinds stacked ABOVE the h1 on the left;
   the open-status (and a small logo) pushed to the RIGHT end of the baseline —
   headline-data + headline-open in the reference. */
.cat-page-head__row--place { align-items: flex-end; gap: 1.5rem; }
/* breathing room between the kind badges and the h1 — they must not cling (UX review) */
.cat-page-head__row--place .cat-place__meta--top { margin: 0 0 0.7rem; }
.cat-page-head__row--place .cat-page-head__title { margin: 0; }
.cat-page-head__side {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding-bottom: 0.35rem; /* optically align the status with the h1 baseline */
}

/* place body (your.beer tab parity): beer list left (8/12), place-info sidebar right
   (4/12). On mobile the sidebar comes FIRST (reference: col-lg-4 order-1 order-lg-2). */
.cat-place-cols { display: grid; gap: 2rem; }
@media (min-width: 992px) { .cat-place-cols { grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr); } }
/* below 992 the implicit track is AUTO — sized by the item's min-content. The
   assortment toolbar's nowrap sorts row carries an intrinsic min-content of
   ~485px (sum of its pills), which blew the page out to a 504px horizontal
   scroll on phones (research #8, found in iframe-viewport QA). min-width:0 is
   the standard grid-item guard: the track keeps the viewport width and the row
   scrolls INSIDE its overflow-x container, as designed. */
.cat-place-cols__main { min-width: 0; }
.cat-place-cols__side { order: -1; }
@media (min-width: 992px) { .cat-place-cols__side { order: 0; } }

/* TYPE HIERARCHY (UX review): the page h1 keeps --fs-h2; the IN-PAGE section titles
   ("Разливное пиво"…) step down to --fs-h3 so the page name clearly leads. */
.cat-place-cols .section__title { font-size: var(--fs-h3); margin-top: 0.45rem; }
.cat-place-cols .section__head { margin-bottom: 1.1rem; }
.cat-place-cols .cat-fresh { font-size: 0.9rem; margin-top: 0.15rem; }

/* place-info sidebar: NOT a white card (it glared off the paper zone — UX review);
   it is a quiet hairline fact column, the same pattern as the beer page's spec list
   (cat-beerfacts: compact hairline rows on the paper itself, like your.beer's
   .place-info on its background). */
.cat-place-info { display: flex; flex-direction: column; }
.cat-place-info .cat-fact { margin: 0 0 0.55rem; justify-content: space-between; }
/* sidebar key→value rows (address / phone / links): the value hugs the right edge
   (user decision 2026-08-27) */
.cat-place-info .cat-fact__k { flex: none; }
.cat-place-info .cat-fact span:last-child,
.cat-place-info .cat-fact a { text-align: right; }
.cat-place-info .cat-links { justify-content: flex-end; text-align: right; }
.cat-place__addr a { color: inherit; }
.cat-place__addr a:hover { color: var(--red); }
.cat-place-info .cat-hours { margin-top: 0.9rem; }
.cat-map-wrap--side { margin-bottom: 1.1rem; }
.cat-map-wrap--side .cat-map { height: 220px; } /* shadow/color/radius inherit from .cat-map (same as the places page map — user decision 2026-08-29) */
.cat-page-head__title {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.005em;
  line-height: 1.05;
  font-size: var(--fs-h2);
  color: var(--ink);
  margin-top: 0.3rem;
}
/* STANDING RULE 1: eyebrows on every LIGHT surface are red (never brand gold) */
.zone--paper .eyebrow,
.cat-citymodal__card .eyebrow,
.cat-termsmodal__card .eyebrow,
.cat-agegate__card .eyebrow { color: var(--red); }
.zone--paper .crumb a { color: var(--red); }
.zone--paper .crumb a:hover { color: var(--ink); }

/* ====== header city selector button ====== */
.header__city { display: inline-flex; align-items: center; }
.cat-citybtn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 500;
  color: color-mix(in oklch, var(--white) 82%, transparent);
  border: 1px solid color-mix(in oklch, var(--white) 26%, transparent);
  border-radius: 999px;
  padding: 0.45rem 0.85rem;
  min-height: 38px;
  transition: color 0.16s var(--ease), border-color 0.16s var(--ease);
}
.cat-citybtn:hover { color: var(--white); border-color: var(--red); }
.cat-citybtn svg { width: 16px; height: 16px; flex: none; }
.cat-citybtn__chev { transition: transform 0.18s var(--ease); }
.cat-citybtn[aria-expanded="true"] .cat-citybtn__chev { transform: rotate(180deg); }

/* ====== header inline search ====== */
.nav-search {
  position: relative;
  display: inline-flex;
  align-items: center;
  margin-left: 0.35rem;
  border: 1px solid color-mix(in oklch, var(--white) 22%, transparent);
  border-radius: 999px;
  background: color-mix(in oklch, var(--white) 6%, transparent);
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
/* soft whole-pill focus: an outline on the bare input renders as a broken red
   rectangle inside the rounded pill (user report) — never do that here */
.nav-search:focus-within {
  border-color: color-mix(in oklch, var(--red) 60%, transparent);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--red) 16%, transparent);
}
.nav-search__input {
  background: none;
  border: 0;
  color: var(--white);
  font: inherit;
  font-size: 0.9rem;
  padding: 0.45rem 0.9rem;
  border-radius: 999px 0 0 999px;
  /* 280px (was 320px): the fifth nav item «Цены» takes the width back
     (user decision 2026-09-08); the mobile menu stretches the input to
     the full pill (≤879px rule near .nav-search__btn). */
  width: 280px;
}
.nav-search__input::placeholder { color: color-mix(in oklch, var(--white) 50%, transparent); }
.nav-search__input:focus { outline: none; }
.nav-search__btn {
  display: inline-flex;
  align-items: center;
  padding: 0.45rem 0.75rem;
  border-radius: 0 999px 999px 0;
  color: color-mix(in oklch, var(--white) 70%, transparent);
}
.nav-search__btn:hover { color: var(--red); }
.nav-search__btn svg { width: 17px; height: 17px; }

/* mobile menu (≤879px, .nav-menu switches to the dropdown): the search pill
   spans the full menu row and the INPUT fills it — the submit button is dead
   weight on mobile (the typeahead returns results as you type; Enter still
   submits the form), and its width used to squeeze the input to ~half of the
   visible field (user report 2026-08-29) */
@media (max-width: 879px) {
  .nav-menu .nav-search { width: 100%; margin-left: 0; }
  .nav-menu .nav-search__input { flex: 1 1 auto; width: auto; }
  .nav-menu .nav-search__btn { display: none; }
}

/* ====== «Войти» — user-cabinet login (public since 2026-09-17; was ?ybsucks-gated
   during the hidden rollout) ======
   The same quiet-pill geometry as the city button (.cat-citybtn): outline pill,
   white-on-black, red hover. The link opens the Untappd OAuth start
   (/api/user/login); logged-in visitors get the avatar chip instead (script.js). */
.nav-login {
  display: inline-flex;
  align-items: center;
  margin-left: 0.35rem;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  color: color-mix(in oklch, var(--white) 85%, transparent);
  text-decoration: none;
  white-space: nowrap;
  border: 1px solid color-mix(in oklch, var(--white) 26%, transparent);
  border-radius: 999px;
  padding: 0.45rem 0.9rem;
  min-height: 38px;
  transition: color 0.16s var(--ease), border-color 0.16s var(--ease);
}
.nav-login:hover { color: var(--white); border-color: var(--red); }
/* the button eats exactly its own width from the search input (280px → 200px) —
   the header row must NOT grow (user request 2026-09-17). Desktop only: in the
   mobile dropdown (≤879px) the search stretches full-width and the button takes
   its own row below it, so no input shrink applies there. */
@media (min-width: 880px) {
  .nav-menu:has(.nav-login) .nav-search__input { width: 200px; }
}
@media (max-width: 879px) {
  .nav-menu .nav-login { margin-left: 0; margin-top: 0.4rem; }
}

/* ====== logged-in user chip (2026-09-17) ======
   Client-side swap of .nav-login (script.js → /api/user/me): the avatar in a
   circle + a native <details> dropdown with «Выйти». Never server-rendered —
   per-user chrome must not bake into the shared 60 s page cache. */
/* inline-flex: the details box then hugs the summary exactly (a block details
   grows 4px of line-box below the summary and top-aligns it — the whole chip
   rode 2px above the search input / nav links) */
.nav-user { position: relative; margin-left: 0.35rem; display: inline-flex; }
.nav-user summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
  padding: 2px;
  border: 1px solid transparent;
  border-radius: 999px;
  min-height: 40px; /* touch target (mobile browsers) */
  transition: border-color 0.16s var(--ease);
}
.nav-user summary::-webkit-details-marker { display: none; }
.nav-user summary:hover,
.nav-user[open] summary { border-color: color-mix(in oklch, var(--white) 30%, transparent); }
.nav-user img,
.nav-user__initial {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.nav-user img { object-fit: cover; }
.nav-user__initial {
  background: color-mix(in oklch, var(--white) 14%, transparent);
  color: var(--white);
  font-weight: 600;
}
.nav-user__chev {
  width: 14px;
  height: 14px;
  color: color-mix(in oklch, var(--white) 70%, transparent);
  transition: transform 0.18s var(--ease);
}
.nav-user[open] .nav-user__chev { transform: rotate(180deg); }
.nav-user__menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 60;
  min-width: 180px;
  background: var(--white);
  color: var(--ink);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  box-shadow: 0 14px 34px rgb(0 0 0 / 0.18);
  padding: 0.5rem;
}
.nav-user__name {
  margin: 0 0.25rem 0.4rem;
  font-size: 0.85rem;
  font-weight: 600;
  max-width: 220px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nav-user__menu a,
.nav-user__menu button {
  display: flex;
  align-items: center;
  width: 100%;
  text-align: left;
  font: inherit;
  font-size: 0.875rem;
  text-decoration: none;
  padding: 0.5rem 0.6rem;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--ink);
  cursor: pointer;
  min-height: 38px;
}
.nav-user__menu a:hover,
.nav-user__menu button:hover { background: var(--red); color: var(--white); }
/* mobile (≤879px): the city button shrinks to icon+chevron (the name text is
   gone), the login KEY (the hamburger's twin) owns the login entry, and the
   logged-in avatar chip lives in the header bar next to the hamburger */
.nav-key { display: none; }
/* logged-in: the key never shows, wherever the chip ended up mounted */
.header__inner:has(.nav-user) .nav-key { display: none !important; }
@media (max-width: 879px) {
  .cat-citybtn__name { display: none; }
  .cat-citybtn { padding: 0.45rem 0.6rem; }
  .cat-citybtn > svg:not(.cat-citybtn__chev) { width: 18px; height: 18px; }
  .nav-menu .nav-login { display: none; } /* the header key replaces it */

  .nav-key {
    display: inline-flex;
    width: 44px;
    height: 44px;
    margin-left: 0.5rem;
    border-radius: var(--radius-sm);
    border: 1px solid color-mix(in oklch, var(--white) 30%, transparent);
    color: var(--white);
    align-items: center;
    justify-content: center;
    transition: color 0.16s var(--ease), border-color 0.16s var(--ease);
  }
  .nav-key:hover { color: var(--red); border-color: var(--red); }
  .nav-key svg { width: 22px; height: 22px; }

  /* the avatar chip sits in the header bar (the key's place after login):
       MOBILE = a bare avatar LINK into the cabinet (no dropdown); 44px touch
       twin of the hamburger */
  .header__inner .nav-user--mobile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin-left: 0.35rem;
    padding: 3px;
    border: 1px solid color-mix(in oklch, var(--white) 30%, transparent);
    border-radius: var(--radius-sm);
  }
  .header__inner .nav-user--mobile img,
  .header__inner .nav-user--mobile .nav-user__initial { width: 34px; height: 34px; }
  /* desktop-chip-in-header fallback (details variant ever mounted here) */
  .header__inner .nav-user:not(.nav-user--mobile) { position: static; margin-left: 0.35rem; }
  .header__inner .nav-user:not(.nav-user--mobile) summary {
    width: 44px;
    height: 44px;
    padding: 3px;
    border: 1px solid color-mix(in oklch, var(--white) 30%, transparent);
  }
  .header__inner .nav-user:not(.nav-user--mobile) img,
  .header__inner .nav-user:not(.nav-user--mobile) .nav-user__initial { width: 34px; height: 34px; }
  .header__inner .nav-user:not(.nav-user--mobile) .nav-user__menu {
    position: absolute;
    left: auto;
    right: 8px;
    top: 100%;
  }
}

/* header typeahead panel — three grouped sections, white over the dark header */
.nav-suggest {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 60;
  width: min(430px, 88vw);
  max-height: min(70vh, 560px);
  overflow-y: auto;
  background: var(--white);
  color: var(--ink);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  box-shadow: 0 14px 34px rgb(0 0 0 / 0.18);
  padding: 0.35rem 0;
}
.nav-suggest__head {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.68rem;
  color: var(--red);
  padding: 0.55rem 0.9rem 0.25rem;
  margin: 0;
}
.nav-suggest__item {
  display: block;
  padding: 0.45rem 0.9rem;
  color: var(--ink);
  text-decoration: none;
}
.nav-suggest__item:hover { background: color-mix(in oklch, var(--red) 7%, var(--white)); }
.nav-suggest__title { display: block; font-weight: 600; font-size: 0.92rem; }
.nav-suggest__sub { display: block; font-size: 0.8rem; color: var(--muted); margin-top: 0.1rem; }
.nav__link.is-active { color: var(--white); }
.nav__link.is-active::after {
  content: "";
  display: block;
  height: 2px;
  margin-top: 0.25rem;
  background: var(--red);
  border-radius: 2px;
}

/* ====== paper search input (search page) ====== */
.cat-search__input {
  font: inherit;
  color: var(--ink);
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  min-height: 44px;
  padding: 0 1em;
  width: 100%;
}
.cat-search__input::placeholder { color: var(--muted); }
.cat-search__input:focus-visible { outline: 3px solid var(--red); outline-offset: 1px; }

/* ====== подборки (research #12) — index cards + landing intro ======
   THREE plates on the index (anti-overload: three, not nakrane's ten); the
   landing rows reuse the /beers card list untouched. */
.cat-collections {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
}
@media (min-width: 700px) { .cat-collections { grid-template-columns: repeat(3, 1fr); } }
.cat-collections__card {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: clamp(1.1rem, 0.9rem + 0.9vw, 1.5rem);
  background: var(--paper-2);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  text-decoration: none;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.cat-collections__card:hover { border-color: color-mix(in oklch, var(--red) 45%, var(--hairline)); box-shadow: 0 6px 18px rgb(0 0 0 / 0.07); }
.cat-collections__card:focus-visible { outline: none; border-color: color-mix(in oklch, var(--red) 55%, var(--hairline)); box-shadow: 0 0 0 3px color-mix(in oklch, var(--red) 14%, transparent); }
.cat-collections__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 1.15rem;
  color: var(--ink);
}
.cat-collections__card:hover .cat-collections__title { color: var(--red); }
.cat-collections__lead { margin: 0; font-size: 0.9rem; line-height: 1.5; color: var(--muted); }
.cat-collections__n { margin: 0.35rem 0 0; font-size: 0.85rem; font-weight: 600; color: var(--red); }
.cat-collections__intro { margin: 0.4rem 0 0; max-width: 62ch; color: var(--muted); }

/* the «Новинки» timeline (research #12, the nakrane pattern): a day header —
   display caps + hairline rule + the day's count — above each day's card list.
   Deliberately NOT sticky: a quiet rhythm, not a second nav. */
.cat-tl { margin-bottom: 1.25rem; }
.cat-tl__day {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin: 0 0 0.75rem;
  padding-top: 0.65rem;
  border-top: 1px solid var(--hairline);
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.95rem;
  color: var(--ink);
}
.cat-tl:first-of-type .cat-tl__day { border-top: none; padding-top: 0; }
.cat-tl__n {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.75rem;
  color: var(--red);
  font-variant-numeric: tabular-nums;
}

/* ====== filter bar ====== */
.cat-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--paper-2);
  padding: clamp(0.9rem, 0.7rem + 0.8vw, 1.15rem) clamp(1.1rem, 0.9rem + 1vw, 1.4rem);
  margin-bottom: clamp(1.75rem, 1.2rem + 2vw, 3rem);
}
.cat-filters__group { display: inline-flex; align-items: center; gap: 0.5rem; }
/* chips must wrap INSIDE the group on narrow screens — a nowrap group overflows the
   padded filter box and the last chip visually sticks to the screen edge */
.cat-filters__group { flex-wrap: wrap; }
.cat-filters__group--grow { flex: 1 1 260px; }
/* MOBILE form (user report 2026-09-05: «нет чёткого расположения»): a strict 2×2
   grid of labeled selects — label ABOVE its select (the standard mobile form
   rhythm), every select full-cell (no more ragged content-sized widths), the
   on-sale chip a full-width touch row at the bottom. Filters keep their reading
   order: Стиль+Страна, then Формат+Сортировка, then the chip. */
@media (max-width: 639px) {
  .cat-filters { display: grid; grid-template-columns: 1fr 1fr; gap: 0.7rem 0.75rem; }
  .cat-filters__group { flex-direction: column; align-items: stretch; gap: 0.3rem; }
  .cat-filters__label { font-size: 0.68rem; letter-spacing: 0.06em; }
  .cat-select { width: 100%; }
  .cat-filters__group:has(.cat-chip) { grid-column: 1 / -1; order: 10; }
  .cat-filters__group:has(.cat-chip) .cat-chip { width: 100%; justify-content: center; min-height: 44px; }
}
.cat-filters__label {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.72rem;
  color: var(--muted);
}
.cat-select {
  font: inherit;
  font-size: 0.95rem;
  color: var(--ink);
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  padding: 0.5rem 2.4rem 0.5rem 0.75rem;
  min-height: 44px;
  max-width: 240px;
  /* native select arrows hug the right edge (user report 2026-09-05); the
     custom chevron matches the place-page comboboxes: same path, same 0.7rem
     inset rhythm as .cat-cfilter__btn's padding */
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 6l4 4 4-4' fill='none' stroke='%236B6256' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
  background-size: 14px 14px;
}
@media (max-width: 639px) {
  .cat-select { max-width: none; } /* full cells in the mobile 2x2 grid */
}
.cat-select:focus-visible { outline: 3px solid var(--red); outline-offset: 1px; }

/* instant-filter busy state */
.cat-filters[aria-busy="true"] { opacity: 0.55; pointer-events: none; }
.cat-filters__busy {
  display: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid var(--hairline);
  border-top-color: var(--red);
  animation: cat-spin 0.7s linear infinite;
}
.cat-filters[aria-busy="true"] .cat-filters__busy { display: inline-block; }
@keyframes cat-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .cat-filters__busy { animation-duration: 1.5s; } }

/* checkbox chips */
.cat-chip {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--white);
  padding: 0.42rem 0.95rem;
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--ink);
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
  user-select: none;
}
.cat-chip:hover { border-color: color-mix(in oklch, var(--red) 45%, var(--hairline)); }
.cat-chip input {
  appearance: none;
  width: 1em;
  height: 1em;
  margin-right: 0.5em;
  border: 1.5px solid var(--muted);
  border-radius: 4px;
  display: inline-grid;
  place-items: center;
  flex: none;
}
.cat-chip input:checked { background: var(--red); border-color: var(--red); }
.cat-chip input:checked::after {
  content: "";
  width: 0.52em;
  height: 0.28em;
  border-left: 2px solid var(--white);
  border-bottom: 2px solid var(--white);
  transform: rotate(-45deg) translateY(-1px);
}

/* ====== STANDING RULE 2: place-card grid = reference bootstrap row 4/3/2/1 ====== */
.cat-places-grid {
  display: grid;
  gap: 30px;
  grid-template-columns: 1fr;
}
@media (min-width: 576px)  { .cat-places-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 992px)  { .cat-places-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1200px) { .cat-places-grid { grid-template-columns: repeat(4, 1fr); } }

/* ====== place card (reference proportions; white card on paper) ====== */
/* cover-first layout (reference: your.beer .card-image + .card-body — full-width
   image banner on top, 170px, cover/center, body below it) */
.cat-place { display: flex; flex-direction: column; position: relative; }
/* kind badges overlay the cover image, top-right (user decision 2026-08-27); the
   solid .cat-kind backdrop keeps them readable over any photo, the 0.5rem inset
   clears the cover's rounded corner */
.cat-place__kinds {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.25rem;
  max-width: calc(100% - 1rem);
}
.cat-place__cover {
  display: block;
  width: 100%;
  height: 170px;
  flex: none;
  background: var(--paper-2) center / cover no-repeat;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  border-bottom: 1px solid var(--hairline);
}
.cat-place__cover--empty {
  background-image: none;
  background-color: var(--paper-2);
}
.cat-place__body {
  background: var(--white);
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  flex: 1;
  min-height: 0;
}
/* legacy inline-logo variant (cat-place__head/__logo/__titles) is gone: the map popup
   is text-only now and no template renders a head logo (user decision) */
.cat-place__name,
.cat-place__name a {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 1.4rem;          /* reference 22.4px */
  line-height: 1.2;
  color: var(--ink);
  margin: 0 0 0.3rem;
}
.cat-place__name a:hover { color: var(--red); }
/* venue cards (home grid + map popup): ALWAYS reserve exactly two name lines (user
   decision 2026-08-27) — short and long names render uniformly and the row below
   (city/meta) starts at the same vertical position on every card; names longer than
   two lines clamp with an ellipsis */
.cat-place__name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  min-height: 3.36rem; /* 2 lines × 1.4rem × 1.2 */
}
.cat-place__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.6rem;
  font-size: 0.875rem;        /* reference 14px */
  line-height: 1.5;           /* reference 21px */
  color: var(--muted);
}
.cat-place__city { font-weight: 500; }
.cat-kind {
  font-family: var(--font-body);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  font-size: 0.75rem;         /* reference 12px badge */
  color: var(--muted);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: 0.1em 0.5em;
  background: var(--paper);
}
.cat-place__addr { font-size: 0.875rem; line-height: 1.5; color: var(--ink); margin: 0; }
.cat-place__desc { margin-top: 0.5rem; color: var(--muted); font-size: 0.875rem; max-width: 68ch; }

/* beer page description (035): rides IN the page head, right under the rating
   (user request 2026-09-07 — no cross-section gap between rating and text),
   above the facts list. Slightly larger than the place card copy (full-width
   head column, not a sidebar); even air via margin-block. */
.cat-beerdesc { margin-block: 0.75rem; font-size: 0.9375rem; line-height: 1.55; }

/* brewery closed flag (036 Algolia enrichment): quiet warning line under the
   meta — informative, not alarming. */
.cat-brewery-closed {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--red);
}

/* ====== Пивной индекс (A3, /prices): headline cards + zone tables ====== */
.cat-pricecards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1rem;
  margin-block: 1rem 1.5rem;
}
.cat-pricecard {
  background: var(--paper, #fff);
  border: 1px solid rgba(14, 14, 14, 0.12);
  border-radius: 10px;
  padding: 1rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.cat-pricecard__k { margin: 0; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.cat-pricecard__v { margin: 0; font-family: var(--font-display, inherit); font-size: 1.75rem; font-weight: 700; line-height: 1.1; }
.cat-pricecard__n { margin: 0; font-size: 0.8125rem; color: var(--muted); }

.cat-pricetable {
  width: 100%;
  border-collapse: collapse;
  margin-block: 0.75rem 1.25rem;
  font-size: 0.9375rem;
}
.cat-pricetable th {
  text-align: left;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  padding: 0.5rem 0.75rem 0.4rem;
  border-bottom: 1px solid rgba(14, 14, 14, 0.25);
}
.cat-pricetable td { padding: 0.55rem 0.75rem; border-bottom: 1px solid rgba(14, 14, 14, 0.08); }
.cat-pricetable__zone td {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  background: rgba(14, 14, 14, 0.04);
  border-bottom: 1px solid rgba(14, 14, 14, 0.15);
}
.cat-place__counts {
  display: flex;
  gap: 1rem;
  /* #11 (user request 2026-09-05): pinned to the card BOTTOM — varying
     address/phone lengths used to hang the footer at different heights across
     the grid; the body is already a flex column, auto margin does the pinning */
  margin: 0.35rem 0 0;
  margin-top: auto;
  padding-top: 0.5rem;
  border-top: 1px solid var(--hairline);
  font-size: 0.8rem;
  color: var(--red);
  font-weight: 600;
}
/* the count is ALWAYS its own line under the label (uniform across grid cards and
   the narrow map popup — previously it wrapped only when it didn't fit) */
.cat-place__counts b {
  display: block;
  margin-top: 0.1rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* open-state line */
.cat-open {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-size: 0.875rem;
  color: var(--muted);
}
.cat-open--now { color: var(--ink); font-weight: 600; }
/* «открыто» dot + its ping ring are brand GREEN now (user request 2026-09-19) —
   same tonality as --red (OKLCH L 0.530), not a lighter UI green */
.cat-open--now .live-dot { background: var(--green); }
.cat-open--now .live-dot::after { border-color: var(--green); }

/* format markers: draft = filled red, bottle = outline */
.cat-fmt {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.62rem;
  border-radius: 999px;
  padding: 0.3em 0.7em;
  white-space: nowrap;
}
.cat-fmt--draft { background: var(--red); color: var(--red-ink); }
.cat-fmt--bottle { border: 1px solid var(--hairline); color: var(--muted); background: var(--white); }
/* soon = dashed red outline — a PLAN, not a fact (the beer is not on sale there
   yet, user decision 2026-09-02) */
.cat-fmt--soon { border: 1px dashed color-mix(in oklch, var(--red) 60%, transparent); color: var(--red); background: var(--white); }

/* beer page: «Пиво X можно купить в: …» city links under the venue list
   (city-scope URLs — real crawlable anchors, user request 2026-09-02) */
.cat-buy__elsewhere { margin-top: 1.4rem; color: var(--muted); font-size: 0.95rem; }
.cat-buy__elsewhere a { color: var(--red); text-decoration: underline; text-underline-offset: 2px; }
.cat-buy__elsewhere a + a::before { content: ", "; color: var(--muted); text-decoration: none; }

/* ====== beer list rows (reference "b-data": one column, hairline dividers) ====== */
.cat-list { display: grid; gap: 8px; margin-bottom: 1rem; }
/* home "Новинки" rows: two columns (user decision 2026-08-27) — the rows are narrow
   enough to pair; stars are dropped on the home block (see FreshInCity) so the rows
   stay lean. Column-gap only: rows keep the hairline separators of the single list. */
.cat-list--two { grid-template-columns: 1fr 1fr; column-gap: 2.5rem; }
.cat-list--two > .cat-beer:first-child,
.cat-list--two > .cat-beer:nth-child(2) { border-top: 1px solid var(--hairline); }
@media (max-width: 720px) {
  .cat-list--two { grid-template-columns: 1fr; column-gap: 0; }
  .cat-list--two > .cat-beer:nth-child(2) { border-top: 0; }
}

/* home places/fresh (user decision 2026-08-27): the beat above the city eyebrow
   (--section-y, 60..108px) is ~2x too tall — roughly halve it. The second block's
   top stays 0 (the sibling seam rule above), so its air is the FIRST block's
   bottom padding — halved by the same rule. */
.zone--paper.section.cat-home-block { padding-block: calc(var(--section-y) * 0.45); }

/* ====== home «Лучшее сейчас» strip (research #9) ======
   A POINTER, not a surface (anti-overload constraint, user 2026-09-05): four
   one-line rows — brewery · title · rating — plus «Все лучшие» into the existing
   /beers?format=draft&sort=rating. No labels, no ABV, no counters: the strip
   stays slimmer than one card row of the Новинки grid above it. */
/* «Лучшее*» — the intro's «актуальные*» asterisk-tooltip pattern reused on the
   strip title (user request 2026-09-05): the rating-floor disclosure costs zero
   vertical space. Two instance-specific tweaks: (a) the asterisk sits ~15ch into
   an H2 near the section's LEFT edge — a centered tip would clip off-screen
   there, so it opens anchored to the asterisk's left edge; (b) plain :focus (not
   just :focus-visible) also lets a TAP open it on touch, where the hover path is
   dead (the intro's hint predates this and stays as-is). */
.cat-best-hint .cat-hint__tip { left: 0; transform: none; width: min(260px, calc(100vw - 9rem)); }
.cat-best-hint:focus .cat-hint__tip { opacity: 1; visibility: visible; }
.cat-best {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.4rem;
  /* mobile: one row per beer; desktop — 2×2 (user request 2026-09-05: four
     single rows eat too much vertical for the info a row carries) */
  grid-template-columns: 1fr;
}
@media (min-width: 640px) {
  .cat-best { grid-template-columns: 1fr 1fr; gap: 0.5rem 0.75rem; }
}
.cat-best__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto; /* brewery column removed — the
     beer title owns the row (user request 2026-09-17) */
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
}
.cat-best__title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.98rem;
  color: var(--ink);
  text-decoration: none;
}
.cat-best__title:hover { color: var(--red); }
.cat-best__title:focus-visible { outline: none; box-shadow: inset 0 -2px 0 color-mix(in oklch, var(--red) 55%, transparent); }
.cat-best__rating {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  white-space: nowrap;
  font-size: 0.9rem;
}
.cat-best__rating .cat-stars { font-size: 0.8rem; letter-spacing: 0.09em; }
/* phones: ONE always-red star instead of the honest 5-star fill (user request
   2026-09-13) — the track only eats the title's width on a phone, and the
   numeric rating right after already carries the precision; desktop keeps the
   full widget. Both variants render, CSS picks per breakpoint */
.cat-best__star { display: none; color: var(--red); font-size: 0.8rem; line-height: 1; }
/* phones: the count «(1 234)» is the least-load-bearing bit of the row — drop it
   instead of squeezing the two name columns into ellipsis soup */
@media (max-width: 560px) {
  .cat-best__rating .cat-rating-count { display: none; }
  .cat-best__rating .cat-stars { display: none; }
  .cat-best__rating .cat-best__star { display: inline; }
  .cat-best__row { grid-template-columns: minmax(0, 1fr) auto; gap: 0.55rem; }
}
.cat-beer {
  position: relative; /* anchor for the top-right «Скоро в продаже» badge */
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr) auto;
  gap: 0 0.9rem;
  align-items: start; /* контент плашки прижат к верху (user review 2026-09-05):
     этикетка/название/рейтинг стартуют с одной верхней линии, а не центрируются
     по самой высокой колонке */
  padding: 0.75rem 0.6rem;
  border-bottom: 1px solid var(--hairline);
  /* experiment (user request): a plate slightly lighter than the page paper adds the
     missing visual separation on top of the hairline dividers (21% — half strength) */
  background: color-mix(in oklch, var(--white) 21%, var(--paper));
  border-radius: var(--radius-sm);
  /* a strictly-BOTTOM shadow (the «Места» map feel) — small offsets so the cards'
     vertical rhythm barely grows (4px gap above the shadow) */
  box-shadow: 0 6px 10px -7px rgb(0 0 0 / 0.5);
}
/* the coming-soon badge pins to the card's top-right corner (user request
   2026-09-02); the stars stay vertically centered in the aside — no collision */
.cat-beer__soon {
  position: absolute;
  top: 0.45rem;
  right: 0.5rem;
}
.cat-beer:first-child { border-top: 1px solid var(--hairline); }
.cat-beer:hover { background: color-mix(in oklch, var(--paper-2) 55%, transparent); }
.cat-beer__label {
  width: 88px;
  height: 88px;
  flex: none;
  object-fit: contain;
  border-radius: 6px;
  background: var(--paper-2);
}
.cat-beer__body { min-width: 0; }
.cat-beer__brewery {
  display: block;
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 0.75rem;         /* reference 12px light */
  color: var(--ink);
  margin-bottom: 0.25rem;
}
.cat-beer__brewery:hover { color: var(--red); }
/* длинные названия не наползают на правую колонку (рейтинг/наличие):
   трек карточки minmax(0,1fr) + жёсткий перенос длинных слов
   (user bug report 2026-09-05) */
.cat-beer__title { font-size: 1.2rem; line-height: 1.2; margin: 0 0 0.25rem; font-weight: 700; overflow-wrap: anywhere; } /* reference 19.2px */
.cat-beer__title a { color: var(--ink); }
.cat-beer__title a:hover { color: var(--red); }
.cat-beer__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.1rem 0.4rem;
  font-size: 0.875rem;
  color: var(--muted);
}
.cat-beer__meta a { color: var(--muted); border-bottom: 1px dotted var(--hairline); }
.cat-beer__meta a:hover { color: var(--red); }
.cat-beer__meta .sep { color: var(--red); opacity: 0.85; }
/* ABV/IBU line mirrors the meta line's typography */
.cat-beer__specs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.1rem 0.4rem;
  font-size: 0.875rem;
  color: var(--muted);
  margin: 0.25rem 0 0;
}
.cat-beer__specs .sep { color: var(--red); opacity: 0.85; }
.cat-beer__aside { display: flex; flex-direction: column; align-items: flex-end; gap: 0.25rem; flex: none; }
.cat-beer__aside .cat-stars { font-size: 1.05rem; }

/* 5-star rating widget (grey track + red fill clipped by inline width %) */
.cat-stars {
  position: relative;
  display: inline-block;
  font-size: 1.84rem;
  line-height: 1;
  letter-spacing: 0.12em;
  white-space: nowrap;
}
.cat-stars__bg { color: var(--hairline); }
.cat-stars__fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  overflow: hidden;
  white-space: nowrap;
  color: var(--red);
}
.cat-rating-num { font-weight: 600; }
/* счётчик оценок рядом с рейтингом: nakrane-стиль «4,7 (99)» — приглушённый,
   мельче числа, не конкурирует со звёздами */
.cat-rating-count { color: var(--muted, #8a8a8a); font-size: 0.8rem; font-weight: 400; }

/* карточка сорта: рейтинг в правой колонке — звёзды + число + счётчик одной строкой */
.cat-beer__rating { display: flex; align-items: baseline; gap: 0.35rem; white-space: nowrap; }
.cat-beer__rating .cat-stars { font-size: 1.05rem; }
.cat-beer__rating .cat-rating-num { font-size: 0.95rem; }

/* страница сорта: рейтинг в шапке, под ABV/IBU */
.cat-beerhead__rating { margin: 0.35rem 0 0; }
.cat-beerhead__rating a { display: inline-flex; align-items: baseline; gap: 0.4rem; flex-wrap: wrap; text-decoration: none; color: inherit; }
.cat-beerhead__rating a:hover .cat-rating-num { text-decoration: underline; }
.cat-beerhead__rating .cat-stars { font-size: 1.15rem; }
.cat-beerhead__rating .cat-rating-num { font-size: 1.05rem; }
.cat-beerhead__rating .cat-rating-count { font-size: 0.85rem; }
.cat-rating-src { font-size: 0.75rem; color: var(--muted, #8a8a8a); letter-spacing: 0.02em; }

/* наличие под рейтингом на карточке сорта: «Разливное: 9» / «Бутылочное: 2» —
   каждая часть своей строкой (user review 2026-09-05: склеенная строка была
   слишком широкой); правое выравнивание повторяет колонку рейтинга */
.cat-beer__avail {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.1rem;
  font-size: 0.78rem;
  color: var(--muted);
  margin: 0;
}
.cat-beer__avail span { white-space: nowrap; }
/* red-dot separator between the counters — mobile single-line row ONLY
   (user request 2026-09-19, the cat-beer__specs .sep pattern); on desktop the
   counters stack in a column, so the dot is display:none there */
.cat-beer__avail .sep { display: none; color: var(--red); opacity: 0.85; }

/* счётчик результатов «Показано N из M» (research #5) */
.cat-count { font-size: 0.8rem; color: var(--muted); margin: 1rem 0 0; }

/* строка крана/бутылки: компактный рейтинг в specs-строке */
.cat-tap__rating { display: inline-flex; align-items: baseline; gap: 0.25rem; }
.cat-tap__rating .cat-stars { font-size: 0.8rem; letter-spacing: 0.09em; }
.cat-tap__rating b { font-weight: 600; font-size: 0.85rem; }
.cat-tap__rating .cat-rating-count { font-size: 0.75rem; }

/* places pager: «Назад» left / «Дальше» right under the 12-card page */
.cat-pager {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.8rem;
}

/* ====== venue tap rows (place page) ====== */
.cat-taps {
  display: grid;
  gap: 8px;
  border-top: 2px solid var(--ink);
  margin-bottom: 2.5rem;
}

/* ====== assortment toolbar (place page; research #8) ======
   ONE block over EVERY beer section: a «Найти в ассортименте» input, two
   searchable selects (brewery / style) + a pill row (Рейтинг / Название / ABV /
   IBU / Цена / Дата выпуска). Pills mirror .cat-citypill; a checked pill = red
   fill. The block renders whenever the venue has at least one beer row; while a
   filter is active, the mobile seg-nav is hidden (its chips describe the
   unfiltered page — html.cat-is-filtering). */
.cat-bfilter {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.1rem;
}
.cat-bfilter__searchbar { position: relative; flex: 1 1 100%; min-width: 0; }
/* desktop (≥640): the search field and the combos share ONE line — three rows of
   toolbar above the taps ate too much space (user request 2026-09-05). The
   search grows (capped), the combos sit right (space-between); if a venue's
   combo labels are long, flex-wrap drops the combos to the next line instead of
   squeezing the field below its min. */
@media (min-width: 640px) {
  .cat-bfilter__searchbar { flex: 1 1 220px; max-width: 480px; }
  .cat-bfilter__selects { flex: 0 1 auto; }
}
.cat-bfilter__icon {
  position: absolute;
  left: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  color: var(--muted);
  pointer-events: none;
}
.cat-bfilter__q {
  width: 100%;
  font: inherit;
  font-size: 1rem; /* ≥16px everywhere: iOS Safari must not zoom-on-focus */
  color: var(--ink);
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  padding: 0.62rem 2.3rem 0.62rem 2.5rem;
  min-height: 44px;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.cat-bfilter__q::placeholder { color: var(--muted); }
.cat-bfilter__q:focus {
  outline: none;
  border-color: color-mix(in oklch, var(--red) 55%, var(--hairline));
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--red) 14%, transparent);
}
/* the live status line: «Показано N из M» / «Ничего не найдено» */
.cat-bfilter__status {
  flex: 1 1 100%;
  margin: 0;
  font-size: 0.85rem;
  color: var(--muted);
}
.cat-bfilter__status.is-empty { color: var(--ink); font-weight: 600; }
.cat-bfilter__selects { display: flex; flex-wrap: wrap; gap: 0.6rem; }
@media (max-width: 639px) {
  /* phones: the combos STACK full-width — side-by-side halves would anchor their
     popups at mid-screen and overflow the right edge (left:0 of a half-width
     combo + min(300px, 82vw) does not fit a 375px viewport) */
  .cat-bfilter__selects { flex: 1 1 100%; flex-direction: column; align-items: stretch; }
  .cat-bfilter__selects .cat-cfilter__btn { max-width: none; width: 100%; }
  .cat-cfilter__pop { width: min(300px, calc(100vw - 2 * var(--gutter, 1rem))); }
}
/* «Скрыть питое» row (2026-09-19): the chip is injected client-side for
   logged-in visitors (the 60 s page cache must stay user-neutral) into its own
   row inside the toolbar — filters grouped with filters, sorts with sorts. The
   toolbar's flex-wrap places it inline after the combos on desktop and drops it
   to its own line on phones; natural width keeps it a light single chip, the
   44px height matches every other touch target in the toolbar. */
.cat-bfilter__chips { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
.cat-bfilter__chips .cat-chip { min-height: 44px; }

/* searchable dropdown (brewery / style) — the admin chain-switcher pattern restyled
   for the catalog. Focus indication is a soft brand-red border + faint ring on the
   trigger and a red underline in the search field: the browser's default black
   focus rectangle is suppressed everywhere in this block (user decision). */
.cat-cfilter { position: relative; }
.cat-cfilter__btn {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font: inherit;
  font-size: 0.92rem;
  color: var(--ink);
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  padding: 0.45rem 0.7rem;
  min-height: 44px;
  max-width: 280px;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.cat-cfilter__value { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-cfilter__chev { width: 14px; height: 14px; flex: none; color: var(--muted); }
.cat-cfilter__btn:focus { outline: none; }
.cat-cfilter__btn:focus-visible,
.cat-cfilter.is-open .cat-cfilter__btn {
  outline: none;
  border-color: color-mix(in oklch, var(--red) 55%, var(--hairline));
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--red) 14%, transparent);
}
.cat-cfilter__pop {
  position: absolute;
  top: calc(100% + 4px);
  right: 0; /* right-anchored: the combos sit at the toolbar row's RIGHT end — a
     left-anchored popup pokes past the main column into the place-info sidebar
     (desktop) or the screen edge (one-line toolbar, 2026-09-05) */
  z-index: 30;
  width: min(300px, 82vw);
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  box-shadow: 0 10px 28px rgb(0 0 0 / 0.12);
  overflow: hidden;
}
.cat-cfilter__search { border-bottom: 1px solid var(--hairline); }
.cat-cfilter__search input {
  width: 100%;
  font: inherit;
  font-size: 1rem; /* ≥16px: iOS Safari must not zoom-on-focus */
  color: var(--ink);
  background: transparent;
  border: none;
  padding: 0.55rem 0.75rem;
}
.cat-cfilter__search input::placeholder { color: var(--muted); }
.cat-cfilter__search input:focus { outline: none; box-shadow: inset 0 -2px 0 color-mix(in oklch, var(--red) 55%, transparent); }
.cat-cfilter__list {
  list-style: none;
  margin: 0;
  padding: 0.25rem;
  max-height: 250px;
  overflow-y: auto;
}
.cat-cfilter__opt {
  display: block;
  width: 100%;
  font: inherit;
  font-size: 0.92rem;
  color: var(--ink);
  text-align: left;
  background: none;
  border: none;
  border-radius: calc(var(--radius-sm) - 2px);
  padding: 0.45rem 0.6rem;
  cursor: pointer;
}
.cat-cfilter__opt:hover { background: color-mix(in oklch, var(--ink) 6%, transparent); }
.cat-cfilter__opt:focus-visible { outline: none; background: color-mix(in oklch, var(--red) 12%, transparent); }
.cat-cfilter__opt.is-selected { font-weight: 600; color: var(--red); }

.cat-bfilter__sorts {
  display: flex;
  flex-wrap: nowrap; /* one scrollable line — six pills must not stack 3 rows on a phone */
  gap: 0.4rem;
  align-items: center;
  overflow-x: auto;
  max-width: 100%;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding: 2px 2px 4px; /* room for the pill focus ring inside the scroller */
  /* NO scroll-snap here: with snap points past the scrollport mobile browsers
     preload the line scrolled to the far end and drag it back right mid-swipe
     (live 2026-09-19) — plain momentum scrolling + the edge fades below. */
}
.cat-bfilter__sorts::-webkit-scrollbar { display: none; }
.cat-bfilter__label {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  margin-right: 0.2rem;
}
@media (max-width: 639px) {
  /* phones: the label eats a third of the already-overflowing pill line — the
     pills' shape and the red active one say «sort» well enough without it
     (user request 2026-09-19) */
  .cat-bfilter__label { display: none; }
}
.cat-bsort {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.72rem;
  color: var(--muted);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--white);
  padding: 0.4em 0.95em;
  cursor: pointer;
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.cat-bsort:hover { color: var(--ink); border-color: color-mix(in oklch, var(--red) 45%, var(--hairline)); }
.cat-bsort:focus-visible {
  outline: none;
  border-color: color-mix(in oklch, var(--red) 55%, var(--hairline));
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--red) 14%, transparent);
}
/* the ONE active sort: red fill + a direction arrow (asc default, desc on re-click) */
.cat-bsort.is-active { background: var(--red); border-color: var(--red); color: var(--red-ink); }
.cat-bsort.is-active::after { content: "↑"; font-size: 0.9em; }
.cat-bsort.is-active.is-desc::after { content: "↓"; }
.cat-bsort__extra { display: none; }
@media (min-width: 640px) { .cat-bsort__extra { display: inline; } }

/* overflow affordance (2026-09-19): six pills do not fit a phone, and a hidden
   scrollbar gives zero hint that the line scrolls. The overflowing row fades its
   edges instead — a half-cut pill under a gradient is the standard «there is
   more» signal. State-driven from script.js so no fade ever lies: at the very
   start nothing fades left, at the very end nothing fades right, and on wide
   screens where everything fits there is no fade at all. */
.cat-bfilter__sorts.is-overflow {
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 28px), transparent);
}
.cat-bfilter__sorts.is-overflow.is-scrolled {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 22px, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to right, transparent 0, #000 22px, #000 calc(100% - 28px), transparent);
}
.cat-bfilter__sorts.is-overflow.is-end {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 22px, #000 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 22px, #000 100%);
}

.cat-tap {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto; /* label | body | prices — no tap numbers; minmax(0) держит body в треке при длинных названиях */
  gap: 1rem;
  align-items: center;
  padding: 1rem 0.6rem;
  border-bottom: 1px solid var(--hairline);
  /* the same lighter-than-paper plate as the home/beers beer cards (experiment) */
  background: color-mix(in oklch, var(--white) 21%, var(--paper));
  border-radius: var(--radius-sm);
  box-shadow: 0 6px 10px -7px rgb(0 0 0 / 0.5);
}
/* square beer label (user decision 2026-08-29): DOUBLED to 88px and the tap numbers
   dropped — the label is the row's identity now */
.cat-tap__label {
  width: 88px;
  height: 88px;
  object-fit: contain;
  border-radius: 6px;
  background: var(--paper-2);
}
.cat-tap__body { grid-column: 2; }
.cat-tap--off { opacity: 0.45; }
/* kitchen card variant (place page «Кухня», mealrow): same geometry, but the photo
   is a FOOD shot — cover, not contain (beer labels are square art; meals are not);
   the description takes the brewery/style lines' place, clamped to 2 lines exactly
   like the widget's meal-desc (taplist-core.mjs) */
.cat-tap--meal .cat-tap__label { object-fit: cover; }
.cat-tap__meal-desc {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  font-size: 0.85rem;
  color: var(--muted);
  margin: 0.2rem 0 0;
}
.cat-tap__name { font-weight: 600; font-size: 1.02rem; margin: 0 0 0.2rem; }
.cat-tap__name a { color: inherit; }
.cat-tap__name a:hover { color: var(--red); }
.cat-tap__brewery {
  display: block;
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 0.75rem;
  color: var(--ink);
}
/* ABV/IBU line matches the brewery/style metadata exactly (same size & weight) */
.cat-tap__specs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 0.5rem;
  font-size: 0.85rem;
  color: var(--muted);
  margin: 0.3rem 0 0; /* clear of the style link's underline above */
}
.cat-tap__specs .sep { color: var(--red); }
.cat-tap__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 0.5rem;
  font-size: 0.85rem;
  color: var(--muted);
  margin: 0;
}
.cat-tap__meta a { color: var(--muted); border-bottom: 1px dotted var(--hairline); }
.cat-tap__meta a:hover { color: var(--red); }
.cat-tap__meta .sep { color: var(--red); }
/* price block — your.beer format (user decision 2026-08-29): one row per volume,
   the volume label ALWAYS left, the price ALWAYS right, the space between filled
   with a dotted leader (·-style) */
.cat-tap__prices { grid-column: 3; display: flex; flex-direction: column; align-items: stretch; gap: 0.35rem; }
.cat-tap__price {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  font-size: 0.84rem;
  white-space: nowrap;
}
.cat-tap__vol { color: var(--muted); }
/* 027: метка тары бутылочной строки — «0,5 л. (Банка): …… 10,00р.» (QR-menu parity) */
.cat-tap__pack { color: var(--ink); font-weight: 500; }
.cat-tap__lead {
  flex: 1;
  min-width: 1.25rem;
  align-self: end;
  margin-bottom: 0.26em; /* seat the dots on the text baseline */
  border-bottom: 1px dotted color-mix(in oklch, var(--muted) 55%, transparent);
}
.cat-tap__price b {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.84rem; /* the price matches the volume's size (user decision) */
  color: var(--ink);
}
.cat-fresh { margin-top: 0.4rem; }

/* ====== beer page header + facts ====== */
/* padding, NOT margin: a bottom MARGIN collapses out of the paper-painted head
   zone (its padding-bottom is 0) and leaves a 32px body-painted band under the
   head — invisible while body matches the zone color, but a visible «lighter
   strip» the moment the two diverge (user report 2026-09-05). Padding keeps the
   air INSIDE the painted zone whatever paints beneath. */
.cat-beerhead { display: flex; gap: 1.5rem; align-items: flex-start; padding-bottom: 2rem; }
.cat-beerhead__label {
  width: 110px; height: 150px;
  object-fit: contain;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--paper-2);
  flex: none;
}
.cat-beerhead .section__title { margin-top: 0.2rem; }
/* #10: the «где найти» price row — pill + «от 7,50р. (0,5 л)» stay GLUED as one
   group (inline-flex), the row itself wraps when a card is narrow; the price is
   plain body text — NOT inside the uppercase nowrap pill (it would bloat it) */
/* #11: the /beers card price chip — «от 7,50р. · 0,5 л», one muted line under the
   availability counters (anti-overload: no second pill row, no per-liter here) */
.cat-beer__price { font-size: 0.8rem; color: var(--muted); }
/* mobile twin of the rating (user request 2026-09-05): on <=560px the stars ride
   the ABV/IBU specs line (the place-page card pattern, cat-tap__rating) and the
   aside copy is hidden; desktop keeps the aside rating */
.cat-beer__rating--in-specs { display: none; }
/* #11: «Лучшая цена · 12,60р./л» — a fieldset-style LEGEND riding the winning
   card's top border (user request 2026-09-05: inline in the price row it
   crowded the format pills). The paper-2 plate + hairline ring read as a notch
   grown out of the card; the ~9px overhang lives inside the grid's 30px gap, so
   no layout shift. Cheapest per-liter venue, only when the city has 2+ priced. */
/* #11: the buy card is a flex COLUMN so the price row can pin to the BOTTOM —
   varying title/address/phone lengths used to leave «Разливное от X р.» hanging
   at different heights across the grid (user request 2026-09-05, same fix as
   the /place cards) */
.cat-buy { position: relative; display: flex; flex-direction: column; }
.cat-buy__best {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, -55%);
  z-index: 1;
  background: var(--paper-2);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 0.18em 0.75em;
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.66rem;
  color: var(--red);
  white-space: nowrap;
}
.cat-buy__prices { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.65rem; margin: 0.5rem 0 0; margin-top: auto; padding-top: 0.5rem; }
.cat-buy__fmt { display: inline-flex; align-items: center; gap: 0.35rem; }
.cat-buy__from { font-size: 0.78rem; color: var(--ink); white-space: nowrap; }

/* ====== beer page: compact spec list (hairline rows, not plate cards) ====== */
.cat-beerfacts {
  display: grid;
  grid-template-columns: 1fr;
  margin-bottom: clamp(2.25rem, 1.6rem + 2vw, 3.25rem);
}
@media (min-width: 900px) {
  .cat-beerfacts { grid-template-columns: 1fr 1fr; column-gap: 3.5rem; }
}
.cat-beerfacts .cat-fact { font-size: 0.95rem; }
.cat-beerfacts .cat-fact__k { min-width: 9.5em; } /* value alignment incl. "Дата появления" */
.cat-beerfacts .cat-fact a { color: var(--ink); border-bottom: 1px solid color-mix(in oklch, var(--red) 35%, transparent); }
.cat-beerfacts .cat-fact a:hover { color: var(--red); border-bottom-color: var(--red); }
.cat-beerfacts .cat-stars { font-size: 1rem; letter-spacing: 0.09em; }
.cat-beerfacts .cat-rating-num { font-size: 0.95rem; }
.cat-beerfacts .cat-fact:last-child:nth-child(odd) { border-bottom: 0; }

/* ====== about block (place page) ====== */
.cat-about { display: grid; gap: 1.5rem; }
@media (min-width: 900px) { .cat-about { grid-template-columns: 1.1fr 0.9fr; } }
.cat-fact {
  display: flex;
  gap: 0.8rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--hairline);
  font-size: 0.96rem;
}
.cat-fact__k {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-size: 0.7rem;
  color: var(--muted);
  min-width: 7.5em;
  padding-top: 0.25em;
}
.cat-links { display: inline-flex; flex-wrap: wrap; gap: 0.4rem 1rem; }
.cat-links a { color: var(--red); font-weight: 600; }
.cat-links a:hover { color: var(--ink); }
.cat-taxi { margin-top: 0.8rem; }

/* hours table */
.cat-hours { margin-top: 1rem; border-collapse: collapse; font-size: 0.94rem; width: 100%; }
.cat-hours th, .cat-hours td { text-align: left; padding: 0.5rem 0.6rem 0.5rem 0; border-bottom: 1px solid var(--hairline); font-weight: 400; }
/* hours table: the day stays left, the time range hugs the right edge — the same
   edge the sidebar fact values align to (user decision 2026-08-27) */
.cat-place-info .cat-hours td { text-align: right; }
.cat-hours th { color: var(--muted); }
.cat-hours tr.is-today th, .cat-hours tr.is-today td { color: var(--ink); font-weight: 600; }
.cat-hours tr.is-today th::after {
  content: "";
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--red);
  margin-left: 0.6em;
}

/* ====== map ====== */
.cat-map-wrap { margin-bottom: clamp(1.5rem, 1rem + 1.5vw, 2.25rem); }
.cat-map {
  height: 340px;
  /* no border (user decision): the dark board plate + shadow frame it already */
  border: none;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-board);
  background: var(--board-black-2);
  z-index: 1;
}
.cat-map--wide { height: 420px; }
.cat-map .leaflet-container { background: var(--board-black-2); }
.cat-pin {
  width: 22px; height: 22px;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  background: var(--red);
  border: 2px solid var(--white);
  box-shadow: 0 2px 6px rgba(0,0,0,0.45);
}
.cat-pin__label {
  transform: rotate(45deg);
  display: grid;
  place-items: center;
  width: 100%; height: 100%;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 11px;
  color: var(--white);
}
.leaflet-popup-content-wrapper { border-radius: var(--radius-sm); }

/* map popup = miniature home place card (docs/16 C4): square logo, name link, meta,
   address, counts. The logo is ALWAYS square: the image fills the card width and its
   height is cropped to that width (aspect-ratio 1/1 + cover). */
.leaflet-popup-content { margin: 0; width: auto !important; line-height: 1.35; }
.leaflet-popup-content-wrapper {
  padding: 0;
  overflow: hidden;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
}
/* the popup renders the place card text-only (no cover, no logo — user decision):
   only the width is popup-specific — a touch narrower than the 255px+ grid column */
.cat-map-popup { width: 244px; }
.cat-map-popup .cat-place__body { padding: 16px 16px 14px; }
/* leaflet.css styles .leaflet-popup-content p/h3 margins (1.3em) — outrank the card's own
   .cat-place__* margin:0 (0,1,0 < 0,1,1); reset so the popup card IS the place card */
.cat-map-popup p,
.cat-map-popup h3 { margin: 0; }
.cat-map-popup .cat-place__counts { margin-top: 0.35rem; }
.leaflet-popup { margin-bottom: 18px; }

/* ====== breweries ====== */
.cat-breweries { display: grid; gap: 0.6rem; margin-bottom: 1rem; }
.cat-brewery {
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--paper);
  padding: 0.8rem 1.1rem;
}
.cat-brewery__name { font-size: 1.02rem; margin: 0 0 0.2rem; }
.cat-brewery__name a { color: inherit; }
.cat-brewery__name a:hover { color: var(--red); }
.cat-brewery__meta { display: flex; gap: 0.5rem; font-size: 0.86rem; color: var(--muted); margin: 0; }
.cat-brewery__meta .sep { color: var(--red); }

/* ====== misc ====== */
.cat-more { text-align: center; margin-top: 1.75rem; }
/* brand goldline reads orange-brown — the catalog accent is brand red (STANDING RULE 1) */
.btn--goldline {
  --btn-bd: color-mix(in oklch, var(--red) 55%, var(--hairline));
}
.btn--goldline:hover {
  --btn-bd: var(--red);
  background: color-mix(in oklch, var(--red) 8%, transparent);
}
.cat-city-h {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 1.15rem;
  margin: 2rem 0 1rem;
}

/* ====== city selector modal ====== */
body.cat-modal-open { overflow: hidden; }
.cat-citymodal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  padding: var(--gutter);
}
.cat-citymodal[hidden] { display: none; }
.cat-citymodal__backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in oklch, var(--board-black) 68%, transparent);
}
.cat-citymodal__card {
  position: relative;
  width: min(560px, 100%);
  max-height: min(80vh, 640px);
  overflow: auto;
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-board);
  padding: clamp(1.4rem, 1rem + 1.6vw, 2.2rem);
}
.cat-citymodal__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.1rem;
}
.cat-citymodal__title {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.005em;
  font-size: var(--fs-h3);
  color: var(--ink);
  margin-top: 0.4rem;
}
.cat-citymodal__x {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  color: var(--muted);
}
.cat-citymodal__x:hover { color: var(--red); border-color: var(--red); }
.cat-citymodal__x svg { width: 20px; height: 20px; }
.cat-citymodal__pills { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.1rem; }
.cat-citypill {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.74rem;
  color: var(--muted);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--white);
  padding: 0.45em 1em;
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.cat-citypill:hover { color: var(--ink); border-color: color-mix(in oklch, var(--red) 45%, var(--hairline)); }
.cat-citypill.is-active { background: var(--red); border-color: var(--red); color: var(--red-ink); }
.cat-citymodal__list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.35rem;
  margin-bottom: 1.1rem;
}
.cat-citylink {
  width: 100%;
  text-align: left;
  font: inherit;
  font-size: 0.98rem;
  color: var(--ink);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 0.55rem 0.7rem;
  transition: background-color 0.14s var(--ease), color 0.14s var(--ease), border-color 0.14s var(--ease);
}
.cat-citylink:hover { background: var(--paper-2); color: var(--red); }
.cat-citylink.is-active {
  background: color-mix(in oklch, var(--red) 8%, var(--white));
  border-color: color-mix(in oklch, var(--red) 40%, var(--hairline));
  color: var(--red);
  font-weight: 600;
}
.cat-citymodal__hint { font-size: 0.85rem; color: var(--muted); }

/* ====== user-agreement modal (above the age gate) ====== */
.cat-termsmodal {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: grid;
  place-items: center;
  padding: var(--gutter);
}
.cat-termsmodal[hidden] { display: none; }
.cat-termsmodal__card {
  position: relative;
  width: min(720px, 100%);
  max-height: min(82vh, 680px);
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-board);
  overflow: hidden;
}
.cat-termsmodal__card .cat-citymodal__head { padding: 0; margin: clamp(1.2rem, 1rem + 1.2vw, 1.8rem) clamp(1.2rem, 1rem + 1.2vw, 1.8rem) 0; }
.cat-termsmodal__body {
  overflow-y: auto;
  padding: 0.4rem clamp(1.2rem, 1rem + 1.2vw, 1.8rem) clamp(1.2rem, 1rem + 1.2vw, 1.8rem);
}
.cat-termsmodal__body h3 {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: 0.95rem;
  color: var(--ink);
  margin: 1.2rem 0 0.4rem;
}
.cat-termsmodal__body h3:first-child { margin-top: 0.4rem; }
.cat-termsmodal__body p { color: var(--ink); font-size: 0.92rem; line-height: 1.6; margin-bottom: 0.7rem; }
/* doc tabs: two legal documents (agreement / offer) share one modal */
.cat-termsmodal__tabs { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.9rem; }
.cat-termsmodal__tab {
  appearance: none;
  border: 1px solid var(--hairline);
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 0.85rem;
  padding: 0.35rem 0.75rem;
  border-radius: 999px;
  cursor: pointer;
}
.cat-termsmodal__tab.is-active { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* ====== legal pages (/disclaimer, /offer) ====== */
.cat-legal { max-width: 860px; }
.cat-legal__body h2 {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: 1.15rem;
  color: var(--ink);
  margin: 2rem 0 0.6rem;
}
.cat-legal__body h2:first-child { margin-top: 1.25rem; }
/* shared legal docs render h3 headings (the modal styles h3) — mirror the h2 look */
.cat-legal__body h3 {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: 1.15rem;
  color: var(--ink);
  margin: 2rem 0 0.6rem;
}
.cat-legal__body h3:first-child { margin-top: 1.25rem; }
.cat-legal__body p { color: var(--ink); font-size: 0.98rem; line-height: 1.65; margin-bottom: 0.8rem; max-width: 75ch; }
.cat-legal__body a { color: var(--red); text-decoration: underline; text-underline-offset: 2px; }
.cat-legal__date { color: var(--muted) !important; font-size: 0.85rem !important; margin-top: 1.6rem; }
.cat-agegate__foot a { color: var(--red); text-decoration: underline; text-underline-offset: 2px; }

/* home intro «актуальные*» asterisk: pure-CSS tooltip (no JS; focusable for a11y) */
.cat-hint { position: relative; cursor: help; color: var(--red); font-weight: 600; }
.cat-hint__tip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  width: min(340px, 78vw);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-body); /* the tip is body text wherever the asterisk sits —
     a title-context asterisk must not leak its display font/uppercase/tracking
     into the tip (found on «Лучшее*», user review 2026-09-05) */
  text-transform: none;
  letter-spacing: normal;
  font-size: 0.8rem;
  font-weight: 400;
  line-height: 1.45;
  text-align: left;
  padding: 0.55rem 0.7rem;
  border-radius: var(--radius, 8px);
  box-shadow: var(--shadow-board);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.15s;
  z-index: 20;
  pointer-events: none;
}
.cat-hint:hover .cat-hint__tip,
.cat-hint:focus-visible .cat-hint__tip { opacity: 1; visibility: visible; }
/* a TAP also opens the intro tip via plain :focus — same tweak as .cat-best-hint
   (2026-09-05): :focus-visible does not match a touch tap, and relying on
   Chrome's sticky :hover emulation alone is fragile */
.cat-intro__lead .cat-hint:focus .cat-hint__tip { opacity: 1; visibility: visible; }

/* NARROW SCREENS — field report 2026-09-19 (phone 394×853, Android Chrome): the
   intro tip opened BEHIND the left screen edge. Cause: the tip is centered on
   the asterisk, which is MID-TEXT — its x is whatever the line wrap makes of it.
   Measured on dev (default font scale): 360–416px → tip left edge −28…−48px
   (−40px at the reported 394); 420px+ → +120px RIGHT instead (asterisk lands at
   the line end); only ~335–355px wraps "cleanly"; Android's user font scale
   shifts the bands. No single anchor to a 12px-wide inline span fits every wrap
   (centered clips left/right by band; .cat-best-hint's left-pin works only
   because «Лучше» starts at a stable left edge), so on narrow screens the tip
   resolves against the PARAGRAPH instead: full lead width, one beat above it —
   deterministic in every wrap/font-scale band, never clipped. Same remedy
   family as the .cat-best-hint fix (2026-09-05). */
@media (max-width: 768px) {
  .cat-intro__lead { position: relative; }
  .cat-intro__lead .cat-hint { position: static; } /* tip's containing block = the lead */
  .cat-intro__lead .cat-hint__tip {
    left: 0;
    right: 0;
    width: auto;
    transform: none; /* base bottom: calc(100% + 8px) now anchors above the lead */
  }
}


/* ====== age gate 18+ ====== */
.cat-agegate {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: grid;
  place-items: center;
  padding: var(--gutter);
}
.cat-agegate[hidden] { display: none; }
.cat-agegate__backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in oklch, var(--board-black) 82%, transparent);
}
.cat-agegate__card {
  position: relative;
  width: min(460px, 100%);
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-board);
  padding: clamp(1.6rem, 1.2rem + 1.8vw, 2.4rem);
  text-align: center;
}
.cat-agegate__card .eyebrow { color: var(--red); }
.cat-agegate__title {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-h3);
  color: var(--ink);
  margin-top: 0.6rem;
}
.cat-agegate__text { color: var(--muted); margin-top: 0.7rem; }
.cat-agegate__actions {
  display: flex;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 1.5rem;
}
.cat-agegate__foot { font-size: 0.8rem; color: var(--muted); margin-top: 1.3rem; }
body.cat-age-lock { overflow: hidden; }

/* ====== fixed bottom health warning (10vh, black 90%, one line) ====== */
html { scroll-padding-bottom: 12vh; }
body { padding-bottom: 10vh; }
.cat-agewarn {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 10vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding-inline: var(--gutter);
  background: rgba(0, 0, 0, 0.9);
  color: var(--white);
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: min(3.6vw, 5vh);
  line-height: 1;
  white-space: nowrap;
  z-index: 250;
}

/* ====== place page: «Краны / Банки и бутылки / Кухня» jump bar (cat-segnav) ======
   Mobile-only section nav, working like the QR-menu chip bar (public/js/menu.mjs)
   but hidden until it is actually needed (user decision 2026-08-29): in the page
   flow it does not exist at all (fixed, slid away) — script.js adds .is-stuck once
   the list scrolls up to the header line, dropping the bar in just below the
   sticky site-header (top = live header height, measured into --cat-head-h).
   Blurred paper cover like the QR-menu .nav; the active chip is brand RED on a
   light background (standing rule 1 — no gold here). Mobile PORTRAIT only — hidden
   ≥992px or in landscape (user decision 2026-08-29): all lists already sit beside
   the place-info sidebar / the bar is pointless on a wide screen. */
.cat-segnav {
  position: fixed;
  top: var(--cat-head-h, 68px);
  left: 0;
  right: 0;
  z-index: 90; /* under the site-header (100), over the content and .cat-cfilter__pop (30) */
  padding: 0.5rem var(--gutter) 0.55rem;
  background: color-mix(in oklch, var(--paper) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hairline);
  visibility: hidden;
  opacity: 0;
  transform: translateY(-12px);
  transition: opacity 0.18s var(--ease, ease), transform 0.18s var(--ease, ease),
    visibility 0s linear 0.18s;
}
.cat-segnav.is-stuck {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition: opacity 0.18s var(--ease, ease), transform 0.18s var(--ease, ease);
}
/* research #8: while an assortment filter/search is active the bar's chips and
   counts describe the UNFILTERED page (and filtered-out sections are display:none
   — their jumps would go nowhere) — keep the bar out of the way entirely */
html.cat-is-filtering .cat-segnav { visibility: hidden !important; opacity: 0 !important; }
.cat-seg {
  display: flex;
  flex-wrap: wrap; /* chips WRAP to the next row rather than squeeze/ellipsize the
     section names (user decision 2026-09-05): a two-row bar beats «Краники-сло…».
     script.js reads the bar's live offsetHeight, so jump offsets and the reveal
     line adapt to the taller bar automatically */
  gap: 0.45rem;
}
.cat-seg__btn {
  flex: 1 1 auto; /* fill the row evenly (halves for two, thirds for three); when
     the full names don't fit, the overflow chip drops to the NEXT row instead of
     clipping — basis auto + the intrinsic minimum keep every name whole */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45em;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink);
  text-decoration: none;
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 0.45em 0.6em;
  transition: border-color 0.15s var(--ease, ease), color 0.15s var(--ease, ease),
    background-color 0.15s var(--ease, ease);
}
/* the section name stays on ONE line inside its chip — wrapping happens BETWEEN
   chips, never inside a name (no ellipsis: user decision 2026-09-05) */
.cat-seg__btn span:first-child { white-space: nowrap; }
.cat-seg__btn:active { background: var(--paper-2); }
.cat-seg__btn:focus { outline: none; }
.cat-seg__btn:focus-visible {
  border-color: color-mix(in oklch, var(--red) 55%, var(--hairline));
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--red) 14%, transparent);
}
.cat-seg__n {
  flex: none;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.72rem;
  color: var(--red);
}
.cat-seg__btn.is-active {
  background: color-mix(in oklch, var(--red) 8%, var(--white));
  border-color: color-mix(in oklch, var(--red) 40%, var(--hairline));
  color: var(--red);
  font-weight: 600;
}
@media (min-width: 992px), (orientation: landscape) { .cat-segnav { display: none; } }

/* ====== responsive ====== */
@media (max-width: 640px) {
  .cat-citybtn span { max-width: 14vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

}
@media (max-width: 560px) {
  .cat-beer { grid-template-columns: 66px minmax(0, 1fr); }
  /* mobile beer cards: the label is a FIXED 66px square (1.5x) — it must NOT grow
     with the card when a long title wraps; the card height is the base */
  .cat-beer__label {
    width: 66px;
    height: 66px;
  }
  /* mobile beer cards: the aside is a WRAPPING row that hosts the availability
      counters; the #11 price chip is pinned to its OWN line below them (see
      .cat-beer__price below, user request 2026-09-19). The whole block sits
      0.45rem under the specs line (a plain nowrap row here overflowed
      column 2 once — keep the wrap). */
  .cat-beer__aside {
    grid-column: 2;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: flex-start;
    align-items: baseline;
    column-gap: 0.65rem;
    row-gap: 0.2rem;
    margin-top: 0.45rem;
    width: 100%;
    text-align: left;
  }
  .cat-beer__avail { flex-direction: row; column-gap: 0.65rem; align-items: baseline; }
  .cat-beer__avail .sep { display: inline; }
  /* the price chip is ALWAYS its own line on phones (user request 2026-09-19,
     supersedes the share-one-line packing above): measured geometry — counters
     «Розлив + Фасовка» ≈ 197px + chip ≈ 100px ≈ 308px against a ~196-250px
     column (360-414px viewports), so the conditional packing degenerated into
     «sometimes drops, sometimes doesn't». flex-basis:100% makes the drop
     deterministic: counters line, then the chip, left-aligned. */
  .cat-beer__price { flex-basis: 100%; text-align: left; }
  .cat-beer__rating--aside { display: none; }
  /* compact enough to hold the WHOLE specs+rating line in column 2 (~214px):
     «6,9% • 64 IBU • ★★★★★ 3,80 (0)» fits at these sizes (was 118px → ~105px) */
  .cat-beer__rating--in-specs {
    display: inline-flex;
    align-items: baseline;
    gap: 0.25rem;
  }
  .cat-beer__rating--in-specs .cat-stars { font-size: 0.7rem; letter-spacing: 0.06em; }
  .cat-beer__rating--in-specs .cat-rating-num { font-size: 0.82rem; }
  .cat-beer__rating--in-specs .cat-rating-count { font-size: 0.68rem; }
  /* place-page beer card on mobile: the label is 1.5x (66px), ALL the info stays
     to the RIGHT of it; only the prices/volumes drop to their own full-width row */
  .cat-tap { grid-template-columns: 66px minmax(0, 1fr); }
  .cat-tap__label { width: 66px; height: 66px; }
  /* your.beer price rows drop DIRECTLY under the text info, in its own column
     (user decision 2026-08-29): the volume/price rows keep the same left edge as
     the brewery/title — even when the 66px label is vertically shorter than the
     text block (the row just grows; the label stays 66px) */
  .cat-tap__prices {
    grid-column: 2;
    grid-row: 2;
  }
  /* the beer head keeps the image LEFT with the text RIGHT on mobile too */
  .cat-beerhead { flex-direction: row; gap: 1rem; }
  .cat-beerhead__label { width: 84px; height: 114px; }
  .cat-about { grid-template-columns: 1fr; }

  /* the 18+ warning bar was 2x taller than its single line of text on phones */
  .cat-agewarn { height: 5vh; }
  body { padding-bottom: 5vh; }
  html { scroll-padding-bottom: 6vh; }
}
/* ====== place page: small-print attribution directly above the footer ======
   «Официальный мини-сайт <заведение>. Техподдержка…» — legal small print, muted,
   the catalog's small-print tier (0.72rem). */
.cat-minisite {
  font-family: var(--font-body);
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--muted);
  padding-bottom: 1.5rem;
}

@media print {
  .cat-agewarn, .cat-agegate { display: none; }
  body { padding-bottom: 0; }
}

/* ---- city × kind landings (SEO §4.D): kind chips as links + city cross-links ---- */
.cat-chiplink {
  display: inline-block;
  padding: 0.35rem 0.85rem;
  border: 1px solid var(--ink);
  border-radius: 999px;
  font-size: 0.88rem;
  font-weight: 500;
  color: var(--ink);
  text-decoration: none;
}
.cat-chiplink:hover { background: color-mix(in oklch, var(--red) 7%, var(--white)); }
.cat-chiplink.is-active { background: var(--ink); color: var(--paper); }
.cat-citylanding__kinds { display: flex; flex-wrap: wrap; gap: 0.45rem; margin-bottom: 1.2rem; }
.cat-citylinks {
  margin-top: 2rem;
  padding-top: 1.2rem;
  border-top: 1px solid color-mix(in oklch, var(--ink) 12%, transparent);
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.9rem;
  align-items: baseline;
}
.cat-citylinks__head { font-size: 0.85rem; color: var(--muted); margin: 0; }
.cat-citylinks a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-size: 0.92rem;
}

/* ====== wishlist marker on beer cards (2026-09-17) ======
   The label image toggles the wishlist (script.js, logged-in only): the wrap is
   inert for layout (inline-flex, shrink-wraps the image); the marker is a 2px
   solid brand-red ring painted INSIDE the image (inset shadow — the card
   geometry never moves, the picture never resizes). */
.wl-thumb { position: relative; display: inline-flex; max-width: 100%; }
.wl-thumb.wl-ready > img { cursor: pointer; transition: filter 0.3s ease; }
/* drunk label: nearly monochrome — the colors barely smolder (grayscale 85%) */
.wl-thumb.is-drunk > img { filter: grayscale(85%); }
/* wishlisted = the brand-red 2px ring INSIDE the image (inset shadow — the
   card geometry never moves, the picture never resizes) */
.wl-thumb.is-on > img { box-shadow: inset 0 0 0 2px var(--red); }
/* the marker — a modern corner badge (Google Photos / Airbnb «saved» pattern):
   solid brand-red circle + white heart, pinned top-right, soft shadow, pop-in
   micro-animation. Covers a tiny corner; the label itself stays untouched. */
.wl-badge {
  position: absolute;
  top: -7px;
  right: -7px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--red);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 6px rgb(0 0 0 / 0.3), 0 0 0 2px #fff;
  pointer-events: none;
  transform: scale(0);
  opacity: 0;
  transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.18s ease;
  z-index: 2;
}
.wl-thumb.is-on .wl-badge { transform: scale(1); opacity: 1; }
.wl-badge svg { width: 13px; height: 13px; display: block; }
@media (max-width: 719px) {
  .wl-badge { width: 22px; height: 22px; top: -6px; right: -6px; }
  .wl-badge svg { width: 12px; height: 12px; }
}

/* toast (user feedback for wishlist toggles) — sits ABOVE the fixed bottom
   health-warning bar (10vh desktop / 5vh small screens) and above every
   fixed layer of the page */
.cat-toast {
  position: fixed;
  left: 50%;
  bottom: calc(10vh + 16px);
  transform: translate(-50%, 12px);
  max-width: min(92vw, 480px);
  background: #18181b;
  color: #fff;
  font-size: 14px;
  line-height: 1.4;
  padding: 10px 18px;
  border-radius: 10px;
  box-shadow: 0 14px 34px rgb(0 0 0 / 0.25);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 120;
}
.cat-toast.is-on { opacity: 1; transform: translate(-50%, 0); }
@media (max-width: 719px) {
  .cat-toast { bottom: calc(5vh + 16px); }
}

/* «Пито» — the checked-in marker (2026-09-17): the heart badge's TWIN for
   visibility — solid dark circle + white check + white ring + shadow, pinned
   bottom-left (mirroring the red heart's top-right), same pop-in animation. */
/* «Уже пито» — the checked-in marker (2026-09-17): a dark PILL (check + label)
   with the heart badge's white ring + shadow, pinned to the image's bottom
   CENTER (overlapping the edge), same pop-in animation. */
.wl-drunk {
  position: absolute;
  left: 50%;
  bottom: -7px;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  background: #18181b;
  color: #fff;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.4;
  white-space: nowrap;
  box-shadow: 0 2px 6px rgb(0 0 0 / 0.3), 0 0 0 2px #fff;
  pointer-events: none;
  transform: translateX(-50%) scale(0);
  opacity: 0;
  transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.18s ease;
  z-index: 2;
}
.wl-thumb.is-drunk .wl-drunk { transform: translateX(-50%) scale(1); opacity: 1; }
.wl-drunk svg { width: 11px; height: 11px; display: block; }
@media (max-width: 719px) {
  .wl-drunk { font-size: 9.5px; padding: 2px 8px 2px 6px; bottom: -6px; }
  .wl-drunk svg { width: 10px; height: 10px; }
}

/* drunk CARDS get a clearly grayed plate (user direction 2026-09-17): the check
   badge marks the image, the grayscale label + the gray plate mark the whole
   row — :has() keeps it pure CSS. */
.cat-beer:has(.wl-thumb.is-drunk) {
  background: color-mix(in oklch, oklch(0.55 0 0) 16%, color-mix(in oklch, var(--white) 21%, var(--paper)));
}
.cat-tap:has(.wl-thumb.is-drunk) {
  background: color-mix(in oklch, oklch(0.55 0 0) 13%, transparent);
}

/* «Только непитое» (client filter, 2026-09-17): the checkbox toggles a body
   class; :has() hides the drunk cards — appended pages obey automatically and
   the server-rendered cache never learns about the user. */
body.wl-undrunk article:has(.wl-thumb.is-drunk) { display: none; }

/* ====== favourite venues (2026-09-17, phase 1) ======
   Heart over the venue card's cover (top-left — the kind badges own the right);
   the place-page button; the «Только любимые» client filter. */
.cat-favheart {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 3;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 50%;
  background: rgb(24 24 27 / 0.72);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), background-color 0.15s ease;
}
.cat-favheart svg { width: 16px; height: 16px; opacity: 0.85; }
.cat-favheart:hover { transform: scale(1.08); }
.cat-favheart.is-on { background: var(--red); }
.cat-favheart.is-on svg { opacity: 1; }

/* place page: «В избранное / В любимых» pill near the open state */
.cat-favbtn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 0.4rem 0.9rem;
  min-height: 38px;
  cursor: pointer;
  transition: color 0.16s var(--ease), border-color 0.16s var(--ease), background-color 0.16s var(--ease);
}
.cat-favbtn svg { width: 16px; height: 16px; color: var(--muted); }
.cat-favbtn:hover { border-color: var(--red); color: var(--red); }
.cat-favbtn.is-on { background: var(--red); border-color: var(--red); color: #fff; }
.cat-favbtn.is-on svg { color: #fff; }

/* «Только любимые» client filter: hides non-favourite venue cards */
body.fav-only article.cat-place:not(.is-fav) { display: none; }

/* mobile: the place-page favourite button becomes a bare HEART circle — the
   «В избранное» text doesn't fit the narrow head row (user request 2026-09-17) */
@media (max-width: 879px) {
  .cat-favbtn {
    width: 38px;
    height: 38px;
    padding: 0;
    justify-content: center;
    border-radius: 50%;
  }
  .cat-favbtn span { display: none; }
  .cat-favbtn svg { width: 17px; height: 17px; }
}

/* the FAVOURITE venue's map pin: a red heart with the same white ring language
   as the teardrop pin (drop-shadow instead of box-shadow — the shape is SVG) */
.cat-heartpin {
  width: 26px;
  height: 26px;
  filter: drop-shadow(0 2px 5px rgb(0 0 0 / 0.45));
}
.cat-heartpin svg { width: 26px; height: 26px; display: block; }

/* ===== footer: Google Play badge (catalog Android app, user request 2026-09-18) =====
   The official badge art is a black rounded pill on transparency — it sits under the
   brand tagline on the dark footer as a plain inline block. The generic badge art
   carries generous internal padding, so it needs a LARGE display size to keep the
   text legible: 160px desktop / 152px under 880px (the xs/sm seam) — both fit any
   phone viewport ≥320px with the 15px container gutters intact; intrinsic 646×250
   attrs give the browser the exact aspect ratio, so no CLS while it streams in. */
.footer__play {
  display: inline-block;
  margin-top: 16px;
  -webkit-tap-highlight-color: transparent;
}
.footer__play img { display: block; width: 160px; height: auto; }
@media (max-width: 879px) {
  .footer__play { margin-top: 12px; }
  .footer__play img { width: 152px; }
}
