/* Catalog page + the shared product card (.pcard), quick view (.qv) and filter sheet.
   Owned by the catalog agent. Flat CSS (no nesting). Primitives come from components.css. */

/* ==========================================================================
   Head: breadcrumbs, H1, atmospheric backdrop
   ========================================================================== */
.catalog__head {
  position: relative;
  isolation: isolate;
  padding-bottom: 2px;
}
.catalog__head .page-header { margin-bottom: 0; }
/* The display H1's glyph boxes rise above its .84 line box into the 44px crumb row: keep the crumbs on top so
   their whole hit area stays theirs (the H1 is positioned, so the crumbs need a layer of their own). */
.catalog__head > [data-slot='crumbs'] { position: relative; z-index: 1; }

.catalog__title {
  position: relative;
  margin: 2px 0 0;
  font-weight: 900;
  font-size: clamp(3.4rem, 1rem + 7.9vw, 9.6rem);
  line-height: .84;
  letter-spacing: .002em;
  white-space: nowrap;
}
.catalog__title .oblique { transform-origin: 0 100%; }
/* the hidden «— CS2» for screen readers: pinned to the title's start, so while the web font loads (the fallback
   face is wider) its static position after the nowrap title never sticks out past the page and scrolls it sideways */
.catalog__title > .visually-hidden { left: 0; top: 0; }
/* Desktop: the reference's tall, condensed headline (≈90px caps over ≈half the content width) — a larger size,
   horizontally condensed inside the existing slant; the line box (and so the page rhythm) stays as before. */
@media (min-width: 900px) {
  .catalog__title { font-size: clamp(3.4rem, 1rem + 9.1vw, 11rem); line-height: .74; }
  .catalog__title .oblique { transform: skewX(-10deg) scaleX(.76); }
}

/* --catalog-bleed (set by catalog.js): distance from the page's right edge to the viewport's. Past
   --content-max the page is centred; the wash then still reaches the viewport edge (no hard seam), while the
   scene and the outline word stay with the content column (--catalog-extra = the centring margin). */
.catalog {
  --catalog-extra: max(0px, calc(var(--catalog-bleed, var(--main-pad-right)) - var(--main-pad-right)));
}
/* The catalog is a grid of cards: it runs almost the full width (user decision 2026-10-03) — up to 2200px
   instead of the site's 1440px reading column, so wide screens show more cards per row (1440 → 4, 1920 → 6,
   ≥ 2300 → 7) instead of empty margins. Text pages keep --content-max. */
.page.catalog { max-width: 2200px; }
.catalog__backdrop {
  position: absolute;
  z-index: -1;
  top: -16px;
  right: calc(-1 * var(--catalog-bleed, var(--main-pad-right)));
  bottom: -14px;
  left: 40%;
  pointer-events: none;
  overflow: hidden;
}
/* (all-games view only, head.js) — it stops with the scene at the content column and fades out there, so no
   pale blue patch is left past the drawing on wide screens */
.catalog__wash {
  position: absolute;
  inset: 0 var(--catalog-extra) 0 0;
  background:
    radial-gradient(60% 95% at 74% 22%, rgba(55, 129, 252, .17), rgba(55, 129, 252, 0) 72%),
    linear-gradient(90deg, rgba(234, 242, 255, 0) 0%, rgba(234, 242, 255, .85) 55%, rgba(226, 237, 255, .95) 100%);
  -webkit-mask-image:
    linear-gradient(90deg, transparent 6%, #000 44%, #000 calc(100% - min(120px, var(--catalog-extra))), transparent 100%),
    linear-gradient(180deg, #000 62%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(90deg, transparent 6%, #000 44%, #000 calc(100% - min(120px, var(--catalog-extra))), transparent 100%),
    linear-gradient(180deg, #000 62%, transparent 100%);
  mask-composite: intersect;
}
.catalog__scene {
  position: absolute;
  inset: 0 var(--catalog-extra) 0 0;
  color: var(--accent);
  opacity: .5;
  /* right edge: no fade while the scene reaches the viewport; a soft one where it stops at the column */
  -webkit-mask-image:
    linear-gradient(90deg, transparent 22%, #000 58%, #000 calc(100% - min(120px, var(--catalog-extra))), transparent 100%),
    linear-gradient(180deg, #000 70%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(90deg, transparent 22%, #000 58%, #000 calc(100% - min(120px, var(--catalog-extra))), transparent 100%),
    linear-gradient(180deg, #000 70%, transparent 100%);
  mask-composite: intersect;
}
.catalog__scene-svg { width: 100%; height: 100%; max-width: none; }
.catalog__scene .ln {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.35;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.catalog__scene .thin { stroke-width: 1; opacity: .72; }
.catalog__scene .face { fill: currentColor; fill-opacity: .075; stroke: none; }
.catalog__scene .far { opacity: .5; }
.catalog__scene .dim { opacity: .55; }

.catalog__word-wrap {
  position: absolute;
  top: 0;
  right: calc(64px + var(--catalog-extra));   /* room for the slanted «2» */
  bottom: 12px;
  display: flex;
  align-items: center;
}
/* CS2 / Dota: centred between the end of the H1 and the content's right end (head.js syncMark sets --mark-x) */
@media (min-width: 768px) {
  .catalog__word-wrap--center { left: var(--mark-x, 72%); right: auto; transform: translateX(-50%); }
  /* the picture fills exactly the span from the end of the H1 («…СКИН») to the right end of the controls row
     (user request; head.js syncMark sets --scene-l / --scene-r and .has-span), with a short soft fade at both ends */
  .catalog__backdrop.has-span { left: 0; }
  .catalog__backdrop.has-span .catalog__scene--photo,
  .catalog__backdrop.has-span .catalog__scene--map {
    inset: 0 var(--scene-r, var(--catalog-extra)) 0 var(--scene-l, 40%);
    -webkit-mask-image:
      linear-gradient(90deg, transparent 0, #000 72px, #000 calc(100% - 24px), transparent 100%),
      linear-gradient(180deg, #000 70%, transparent 100%);
    mask-image:
      linear-gradient(90deg, transparent 0, #000 72px, #000 calc(100% - 24px), transparent 100%),
      linear-gradient(180deg, #000 70%, transparent 100%);
  }
}
.catalog__word {
  font-family: var(--font-display);
  font-weight: 800;
  font-style: normal;
  font-synthesis: none;
  font-size: clamp(7rem, 1rem + 16.8vw, 17.5rem);
  line-height: .78;
  letter-spacing: .045em;
  text-transform: uppercase;
  white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 1.5px rgba(55, 129, 252, .9);
  transform-origin: 50% 100%;
}
/* CS2: a real Dust2 street in the pale blue duotone of the reference (assets/catalog/cs2-backdrop.jpg, made from
   the user's screenshot), fading out toward the H1 like the line-art scenes. */
.catalog__scene--photo {
  opacity: .9;
  /* lighter at the top (behind the big word, like the reference's sky), the street crisp below */
  background:
    linear-gradient(180deg, rgba(238, 244, 255, .62) 0%, rgba(238, 244, 255, .28) 48%, rgba(238, 244, 255, 0) 78%),
    url('../../../assets/catalog/cs2-backdrop.jpg') 58% 62% / cover no-repeat;   /* the street: walls + houses */
}
/* Dota 2: the user's map picture (Radiant forest → river → Dire) in the same blue duotone
   (assets/catalog/dota2-backdrop.jpg). The river runs through the mark's diagonal opening: head.js syncMark
   puts a point of the river (--map-u / --map-v of the picture) on the opening's centre (--map-x / --map-y) at the
   smallest size that still covers the scene (--map-w), and the picture turns by -7deg so the river (≈42° in
   the picture) follows the opening (≈35°). */
.catalog__scene--map { opacity: .9; overflow: hidden; }
.catalog__map {
  position: absolute;
  left: var(--map-x, 72%);
  top: var(--map-y, 45%);
  width: var(--map-w, max(118%, 380px));
  aspect-ratio: 1600 / 657;
  background: url('../../../assets/catalog/dota2-backdrop.jpg') 0 0 / 100% 100% no-repeat;
  transform-origin: var(--map-u, 49.3%) var(--map-v, 50.6%);
  transform: translate(calc(-1 * var(--map-u, 49.3%)), calc(-1 * var(--map-v, 50.6%))) rotate(-7deg);
}
/* lighter at the top, like the CS2 street's sky */
.catalog__scene--map::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(238, 244, 255, .34) 0%, rgba(238, 244, 255, .12) 48%, rgba(238, 244, 255, 0) 78%);
}
/* the big game word as in the reference: wide rounded letters (the logo's geometric face), a thin blue outline, no fill */
.catalog__word {
  font-family: var(--font-logo);
  font-weight: 400;
  font-size: clamp(3.2rem, 0.5rem + 6.6vw, 9rem);   /* compact: never reaches the H1 */
  line-height: 1;
  letter-spacing: .01em;
  color: rgba(255, 255, 255, .16);
  -webkit-text-stroke: 2px #2B6EEA;
}
.catalog__word--dota2 { font-size: clamp(2.2rem, 0.3rem + 4vw, 5.6rem); }
.catalog__word--all { font-size: clamp(3.6rem, 1rem + 5.8vw, 7.6rem); letter-spacing: .02em; }

/* ==========================================================================
   Controls row: games · search · sort · filters
   ========================================================================== */
/* heads the results column (the filter column beside it starts level with it, right under the H1) */
.catalog__controls {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 14px;
}
/* Game switch - a segmented control in the site's own style (like the search field next to it): white, the
   control's grey frame, segments split by a hairline, the selected game on a light grey fill. The official
   marks (components/game-logos.js) stay in full colour; the CS2 gold is deepened so it reads on white. */
.catalog__games {
  display: inline-flex;
  flex: none;
  height: 50px;
  border: 1px solid var(--line-control);
  border-radius: 13px;
  background: var(--surface);
  overflow: hidden;
}
.catalog__game {
  position: relative;
  display: grid;
  place-items: center;
  width: 62px;
  height: 100%;
  border: 0;
  border-radius: 0;
  background: transparent;
  transition: background-color var(--dur-fast) var(--ease-out);
}
.catalog__game + .catalog__game { border-left: 1px solid var(--line-strong); }
.catalog__game:hover { background: var(--surface-2); }
.catalog__game[aria-pressed='true'] { background: #E6E8EC; }
.catalog__game:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
.catalog__game .game-logo--cs2 { width: 38px; height: auto; color: #E0A100; }
.catalog__game .game-logo--dota2 { width: 30px; height: auto; }

/* the same marks inside light buttons (empty states): a deeper gold for contrast on white */
.btn .game-logo--cs2 { width: 30px; height: auto; color: #C98A00; }
.btn .game-logo--dota2 { width: 21px; height: auto; }

.catalog__search { flex: 1 1 320px; min-width: 0; }
.catalog__input { min-height: 50px; border-radius: 13px; text-overflow: ellipsis; }
.catalog__sort { flex: 0 1 296px; min-width: 200px; }
.catalog__sort .select { width: 100%; min-height: 50px; border-radius: 13px; font-weight: 500; }
/* 172px (reference) also leaves room for the count badge, so selecting a filter never resizes the row */
.catalog__filters-btn { flex: none; min-height: 50px; min-width: 172px; padding: 0 22px; border-radius: 13px; font-weight: 600; }
/* Desktop: the filter column is always open, so there is nothing to toggle; the button only opens the
   filter sheet below 1100px. */
@media (min-width: 1100px) {
  .catalog__filters-btn { display: none; }
}
.catalog__filters-btn[aria-expanded='true'] { --btn-bd: var(--accent); }
.catalog__filters-count { min-width: 22px; justify-content: center; }

/* Category row — in the results column, above the cards; the type menu (.cat-pop) hangs from it.
   Always ONE line (user 2026-10-03: no lone «Другое» stretched across a second line). toolbar.js measures the
   pills' natural width in each density (a hidden copy; again after font loads) and, on every width change, keeps
   the first density that fits: full pictures → .is-dense → .is-compact (small pictures) → .is-bare (names only).
   When none fits → .is-scroll: full pills scrolling sideways, edge fades + round arrows (≥768px). Phones always
   end up scrolling, as before. Every density keeps the 46px pill height: a switch never moves the cards. */
/* flow-root: the row's negative margins (room for shadows and focus rings) stay inside, so the box is exactly one
   46px line in every density and while loading — its size changes only with the column's width */
.catalog__cats { position: relative; display: flow-root; margin: 0 0 14px; }
.catalog__cats-row { gap: var(--cat-gap, 10px); }
/* it fits: no scroller (hover shadows stay whole) and every pill grows, so the line ends flush with the column
   (no empty tail); picture + name sit centred in the widened pill, the chevron keeps its place at the right */
.catalog__cats:not(.is-scroll) .catalog__cats-row.chip-row--scroll { overflow: visible; }
.catalog__cats:not(.is-scroll) .catalog__cats-row:not(.catalog__cats-row--loading) > * { flex: 1 1 auto; }
.catalog__cats:not(.is-scroll) .catalog__catgrp .catalog__cat { flex: 1 1 auto; justify-content: center; }
/* scrolling (phones too): room inside the scroller's clip for the pills' hover shadow and the end pills' 4px focus
   ring (the shared .chip-row--scroll leaves 2px: the ring was cut flat at both ends) */
.catalog__cats.is-scroll > .catalog__cats-row.chip-row--scroll { padding: 10px 4px; margin: -10px -4px; }
@media (min-width: 768px) {
  /* the densities: lengths read by the pill rules below and in catalog-dota.css (phones keep the fallbacks) */
  .catalog__cats {
    --cat-gap: 8px;           /* between pills */
    --cat-pad: 10px;          /* pill start → picture */
    --cat-chip-pad: 14px;     /* «Все» on both sides, a Dota pill's end */
    --cat-btn-end: 2px;       /* name → chevron button */
    --cat-inner: 8px;         /* picture → name */
    --cat-more: 28px;         /* the chevron button */
    --cat-icon: 22px;         /* «Все» grid */
    --cat-pic-w: 40px; --cat-pic-h: 30px;                       /* CS2 render (contain) */
    --cat-tile-w: 42px; --cat-tile-h: 28px; --cat-tile-r: 7px;  /* Dota painted tile */
  }
  .catalog__cats.is-dense {
    --cat-gap: 7px; --cat-chip-pad: 12px; --cat-inner: 7px; --cat-more: 26px; --cat-icon: 20px;
    --cat-pic-w: 32px; --cat-pic-h: 24px; --cat-tile-w: 33px; --cat-tile-h: 22px; --cat-tile-r: 6px;
  }
  /* (sized so CS2 keeps its pictures at 1920px with the filter column: 1495px of row) */
  .catalog__cats.is-compact {
    --cat-gap: 5px; --cat-pad: 7px; --cat-chip-pad: 10px; --cat-inner: 5px; --cat-more: 24px; --cat-icon: 18px;
    --cat-pic-w: 20px; --cat-pic-h: 15px; --cat-tile-w: 22px; --cat-tile-h: 15px; --cat-tile-r: 4px;
  }
  /* (">": a density's own row only — never the hidden measuring copy inside it, which carries its own density) */
  .catalog__cats.is-compact > .catalog__cats-row .catalog__cat-img--none svg { width: 13px; height: 13px; }
  /* names only: no pictures, no «Все» grid — never a truncated name */
  .catalog__cats.is-bare { --cat-gap: 6px; --cat-pad: 14px; --cat-more: 26px; }
  .catalog__cats.is-bare > .catalog__cats-row .catalog__cat > .catalog__cat-img,
  .catalog__cats.is-bare > .catalog__cats-row .catalog__cat > svg { display: none; }
}
/* the hidden copy toolbar.js measures natural widths on (never painted, never in the way) */
.catalog__cats--probe {
  position: absolute;
  top: 0;
  left: 0;
  width: max-content;
  margin: 0;
  visibility: hidden;
  pointer-events: none;
}
/* a CS2 group = one pill of two buttons: the name (selects the whole group) + a chevron (opens its types) */
.catalog__catgrp {
  position: relative;   /* holds the «some types chosen» dot (.catalog__cat-dot) */
  display: inline-flex;
  flex: none;
  align-items: stretch;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
  transition: border-color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.catalog__catgrp:hover,
.catalog__catgrp.is-open { border-color: var(--line-strong); box-shadow: 0 4px 14px -6px rgba(25, 27, 32, .16); }
.catalog__catgrp .catalog__cat {
  display: inline-flex;
  align-items: center;
  gap: var(--cat-inner, 9px);
  min-height: 44px;
  padding: 0 var(--cat-btn-end, 4px) 0 var(--cat-pad, 10px);
  border: 0;
  border-radius: 13px 0 0 13px;
  background: none;
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  cursor: pointer;
}
.catalog__catgrp .catalog__cat svg { width: 20px; height: 20px; flex: none; }
.catalog__cat-more {
  display: grid;
  place-items: center;
  width: var(--cat-more, 34px);
  min-height: 44px;
  border: 0;
  border-radius: 0 13px 13px 0;
  background: none;
  color: var(--ink-3);
  cursor: pointer;
}
.catalog__cat-more svg { transition: transform var(--dur-fast) var(--ease-out); }
.catalog__catgrp.is-open .catalog__cat-more svg { transform: rotate(180deg); }
.catalog__catgrp .catalog__cat:focus-visible,
.catalog__cat-more:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* some of the group's types chosen: a dot over the chevron (the way into them). Out of the flow, so ticking a type
   never widens the pill — the row keeps its density (toolbar.js fit()) and never jumps; clicks pass to the chevron */
.catalog__cat-dot {
  position: absolute;
  top: 9px;
  right: calc(var(--cat-more, 34px) / 2 - 3px);
  display: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  pointer-events: none;
}
.catalog__catgrp.is-partial { border-color: var(--accent); background: var(--accent-tint); }
.catalog__catgrp.is-partial .catalog__cat-dot { display: block; }
.catalog__catgrp.is-on { border-color: var(--accent-strong); background: var(--accent-strong); }
.catalog__catgrp.is-on .catalog__cat,
.catalog__catgrp.is-on .catalog__cat-more { color: #FFFFFF; }

/* The type menu: a light floating island (soft shadow, rounded, quiet checkmarks) */
.cat-pop {
  position: absolute;
  z-index: 40;
  min-width: 248px;
  max-width: min(580px, 100%);
  max-height: min(70vh, 540px);
  overflow: auto;
  padding: 8px;
  border: 1px solid rgba(25, 27, 32, .08);
  border-radius: 18px;
  background: rgba(255, 255, 255, .97);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  backdrop-filter: blur(18px) saturate(1.3);
  box-shadow: 0 22px 48px -16px rgba(25, 27, 32, .28), 0 2px 6px rgba(25, 27, 32, .06);
  transform-origin: 40px 0;
  /* unhurried, like a sheet settling (user: «не так резко»); the JS waits ~180 ms on a pill before opening */
  animation: cat-pop-in 300ms cubic-bezier(.16, 1, .3, 1);
}
@keyframes cat-pop-in { from { opacity: 0; transform: translateY(-8px) scale(.98); } }
@keyframes cat-pop-out { to { opacity: 0; transform: translateY(-6px) scale(.985); } }
/* closing: fades out (toolbar.js CLOSE_ANIM_MS = 240 hides it after), lets the pointer through meanwhile */
.cat-pop.is-closing { animation: cat-pop-out 220ms cubic-bezier(.4, 0, .7, .2) forwards; pointer-events: none; }
/* moving between pills / reopening while fading: no second fade-in */
.cat-pop.is-instant { animation: none; }
.cat-pop:focus, .cat-pop:focus-visible { outline: none; }
.cat-pop__head { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 4px 4px 6px 10px; }
.cat-pop__title { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.cat-pop__list {
  display: grid;
  grid-template-columns: repeat(var(--cols, 1), minmax(208px, 1fr));
  gap: 0 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.cat-pop__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 36px;
  padding: 0 10px;
  border-radius: 10px;
  font-size: var(--fs-sm);
  color: var(--ink);
  cursor: pointer;
}
.cat-pop__item:hover { background: var(--surface-sunken); }
.cat-pop__check { position: absolute; width: 1px; height: 1px; opacity: 0; }
.cat-pop__box {
  display: grid;
  place-items: center;
  flex: none;
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--line-control, #8A8F99);
  border-radius: 5px;
  color: transparent;
  transition: background-color 120ms, border-color 120ms;
}
.cat-pop__check:checked + .cat-pop__box { border-color: var(--accent-strong); background: var(--accent-strong); color: #FFFFFF; }
.cat-pop__check:focus-visible + .cat-pop__box { box-shadow: var(--focus-ring); }
.cat-pop__check:checked ~ .cat-pop__label { font-weight: 600; }
@media (max-width: 767.98px) {
  .cat-pop { right: 0; left: 0 !important; min-width: 0; max-width: none; }
  .cat-pop__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) {
  .cat-pop, .cat-pop.is-closing { animation: none; }
}
.catalog__cats-row .chip { min-height: 40px; padding: 0 var(--cat-chip-pad, 22px); border-radius: 14px; gap: var(--cat-inner, 10px); font-size: var(--fs-sm); border-color: var(--line); }
.catalog__cats-row .chip svg { width: var(--cat-icon, 22px); height: var(--cat-icon, 22px); }
/* loading: skeleton pills as tall as the real ones (46px) on one line — the cards do not move when the row arrives */
.catalog__cats-row--loading { flex-wrap: nowrap; overflow: hidden; }
.catalog__cat-sk { flex: none; height: 46px; border-radius: 14px; }
@media (min-width: 768px) {
  .catalog__cat-sk { flex: 1 1 auto; min-width: 0; }   /* flush with the column, like the fitted row */
}
/* More chips hidden behind an edge → the row fades out there. The fade has to be FULLY transparent before the
   arrow begins (owner, 06.10.2026: «не нравится, что стрелочка так ложится на островок»): the arrow is 32px at
   the very edge, so the old 56px ramp still left the pill 57% opaque under it and the button sat on live text.
   It now reaches zero 28px from the edge — 4px clear of the arrow — and starts 92px in, so the fall is gentle. */
.catalog__cats.is-more-end .catalog__cats-row {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 92px), transparent calc(100% - 28px));
  mask-image: linear-gradient(90deg, #000 calc(100% - 92px), transparent calc(100% - 28px));
}
.catalog__cats.is-more-start .catalog__cats-row {
  -webkit-mask-image: linear-gradient(90deg, transparent 28px, #000 92px);
  mask-image: linear-gradient(90deg, transparent 28px, #000 92px);
}
.catalog__cats.is-more-start.is-more-end .catalog__cats-row {
  -webkit-mask-image: linear-gradient(90deg, transparent 28px, #000 92px, #000 calc(100% - 92px), transparent calc(100% - 28px));
  mask-image: linear-gradient(90deg, transparent 28px, #000 92px, #000 calc(100% - 92px), transparent calc(100% - 28px));
}
/* The scrolling row's arrows (≥768px): small round buttons over the faded edges, only on a side with more pills;
   a click slides the row by ~70% of its width (toolbar.js). Trackpad, shift + wheel and touch scroll as before. */
.catalog__cats-arrow {
  position: absolute;
  top: 50%;
  z-index: 3;
  display: none;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 1px 2px rgba(25, 27, 32, .06), 0 8px 18px -10px rgba(25, 27, 32, .4);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-50%);
  transition: opacity var(--dur-fast) var(--ease-out), visibility 0s linear var(--dur-fast),
    border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);
}
.catalog__cats-arrow svg { width: 18px; height: 18px; }
.catalog__cats-arrow--prev { left: 0; }
.catalog__cats-arrow--next { right: 0; }
.catalog__cats-arrow:hover { border-color: var(--accent); color: var(--accent-ink); }
.catalog__cats-arrow:active { background: var(--accent-tint); }
.catalog__cats-arrow:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.catalog__cats.is-more-start .catalog__cats-arrow--prev,
.catalog__cats.is-more-end .catalog__cats-arrow--next {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-fast) var(--ease-out), visibility 0s linear 0s,
    border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);
}
@media (min-width: 768px) {
  .catalog__cats.is-scroll .catalog__cats-arrow { display: grid; }
}
@media (prefers-reduced-motion: reduce) {
  .catalog__cats-arrow { transition: none; }
}

/* ==========================================================================
   Layout: filter column + results
   ========================================================================== */
.catalog__layout {
  display: grid;
  grid-template-columns: 216px minmax(0, 1fr);
  gap: 22px;
  align-items: start;
  margin-top: 16px;
}
.catalog__layout--nofilters { grid-template-columns: minmax(0, 1fr); }
.catalog__filters { min-width: 0; }
/* Desktop: the filter island stays in view while the cards scroll; a panel taller than the window scrolls on
   its own (thin bar, no scroll chaining into the page).
   The column itself is the island (user 2026-10-03: «окошко фильтры теряется на фоне каталога»): a white surface,
   a firmer outline than the product cards and a layered lift. The chrome sits on the scroll box, not on .fpanel
   inside it: a scroll box clips its children's shadows, never its own. */
@media (min-width: 1100px) {
  /* The island itself never scrolls: it holds the chrome and clips its own corners, so the «Фильтры» band and
     the «Сбросить» footer run edge to edge (owner 2026-10-07: «обрезана заливка»). Only the list of sections
     between them scrolls — which is also why the header and the reset button are always in view. */
  .catalog__filters {
    position: sticky;
    top: 16px;
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 32px);
    max-height: calc(100dvh - 32px);
    overflow: hidden;
    border: 1px solid #C9CDD3;
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow:
      0 1px 2px rgba(25, 27, 32, .06),
      0 6px 14px -6px rgba(25, 27, 32, .10),
      0 24px 48px -20px rgba(25, 27, 32, .22);
  }
  .catalog__filters > .fpanel { display: flex; flex-direction: column; min-height: 0; }
  .catalog__filters .fpanel__sections {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /* The bar's room is held whether or not it is there (owner 2026-10-07: «появляется такой ползунок, и из-за
       этого, где цена, начинают двигаться островки, и сам островок фильтра начинает меняться»). Opening a long
       section — CS2 «Редкость», Dota «Слот» — made the list taller than the window, the bar appeared, and it
       took its width out of every field inside. With the gutter reserved from the start, the bar comes and goes
       and nothing under it moves by a pixel; the right inset gives that width back, so the dividers still end
       the same distance from both edges of the island. */
    --fp-bar: 11px;                /* a thin Chromium bar; a wider one only shifts the dividers a hair right */
    padding-right: max(0px, calc(var(--fp-x) - var(--fp-bar)));
    /* Sideways there is nothing to scroll to, ever. .fpanel__clip reaches 4px past the fields on each side so a
       focus ring is not cut; against the narrower right padding that counted as 3px of horizontal overflow, so
       the box grew a horizontal scrollbar, the bar ate 4px of the height, and THAT made the list overflow
       downwards and grow a vertical bar as well — a panel six short sections long came out scrolling for no
       reason (owner 2026-10-07, Dota: «этот ползунок надо убрать, он не нужен там»). The ring's room is inside
       the padding, so clipping here cuts nothing that is drawn. */
    overflow-x: clip;
    scrollbar-gutter: stable;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--line-strong) transparent;
    scroll-padding: 8px 0;
  }
  /* the footer is a row of the column now, not a box stuck to the bottom of a scrolling one */
  .catalog__filters .fpanel--active .fpanel__footer { position: static; }
}
/* Load error: nothing to filter and no prices shown → the state spans the content width, no summary row */
.catalog--error .catalog__layout { grid-template-columns: minmax(0, 1fr); }
.catalog--error .catalog__filters,
.catalog--error .catalog__summary { display: none; }

/* ==========================================================================
   Filter panel
   ========================================================================== */
/* Desktop: one island holding the whole panel — a tinted header «Фильтры» (+ the selected count), the sections,
   «Сбросить». The island chrome lives on the .catalog__filters column (above); in the sheet the dialog is the
   container (see below). The header runs edge to edge, the sections and the footer keep a 16px inset. */
.fpanel,
.catalog-sheet {
  --fp-head-bg: #EDF4FF;        /* the «Фильтры» header band: island and phone sheet alike */
  --fp-head-line: #D6E3FA;
}
.fpanel {
  --fp-x: 16px;                 /* side inset of the sections and the footer */
  --fp-hover: #F1F2EF;          /* a heading row under the pointer: a calm warm grey, not a colour */
  display: grid;
  gap: 0;
}
/* «Фильтры»: sliders glyph in a tinted square + the display face, set apart from the Golos section headings */
.filters-title { display: flex; align-items: center; gap: 10px; margin: 0; color: var(--ink); }
.filters-title__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--accent-tint);
  color: var(--accent-ink);
}
.filters-title__icon svg { width: 20px; height: 20px; }
.filters-title__text {
  font-family: var(--font-display);
  font-weight: 800;
  font-style: normal;
  font-synthesis: none;
  font-size: 1.75rem;
  line-height: 1;
  letter-spacing: .01em;
  text-transform: uppercase;
}
/* The island header: a pale brand-blue band (the one place the panel speaks brand colour), the glyph square turns
   white on it; the solid badge on the right counts the selected conditions. */
.fpanel__head {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 68px;
  padding: 14px var(--fp-x) 14px calc(var(--fp-x) + 2px);
  border-bottom: 1px solid var(--fp-head-line);
  background: var(--fp-head-bg);
}
.fpanel__head .filters-title__icon,
.catalog-sheet .dialog__title .filters-title__icon { background: var(--surface); box-shadow: inset 0 0 0 1px var(--fp-head-line); }
.fpanel__total {
  flex: none;
  min-width: 26px;
  min-height: 26px;
  margin-left: auto;
  padding: 0 8px;
  justify-content: center;
  font-size: var(--fs-sm);
  font-weight: 700;
}

.fpanel__skeleton { display: none; gap: 10px; padding: 16px var(--fp-x) 8px; }
.fpanel__sk-field { height: 44px; margin-bottom: 8px; border-radius: var(--radius-sm); }
/* Skeletons on the page background need more than --surface-sunken (≈1.07:1) to read as placeholders
   (the panel's own skeletons sit on the white island and keep the default). */
.catalog__cat-sk,
.catalog__count-sk { background: #E0E1DE; }
.fpanel--loading .fpanel__skeleton { display: grid; }
.fpanel--loading .fpanel__sections,
.fpanel--loading .fpanel__footer,
.fpanel--error .fpanel__sections,
.fpanel--error .fpanel__footer { display: none; }

/* Sections (user 2026-10-03: the collapsed list read cramped): every heading is a calm 52px row between 1px
   dividers — 16px above and below its 20px text line, open or closed (user 2026-10-05: the hover island «должно
   одинаковым размером оставаться»). An open section still keeps its title close to its fields (the earlier
   request): the BODY takes those 10px back, not the heading, so neither the text nor the island moves when a
   section opens or closes. */
.fpanel__sections { display: grid; padding: 0 var(--fp-x); }
.fpanel__section + .fpanel__section { border-top: 1px solid var(--line); }

.fpanel__heading { margin: 0; font-size: inherit; line-height: inherit; }
.fpanel__toggle {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 0;
  padding: 16px 2px;
  color: var(--ink);
  font-size: var(--fs-base);
  font-weight: 600;
  line-height: 20px;
  text-align: left;
}
/* hover / keyboard focus: ONE soft pill over the whole heading row — the title, the «N ✕» chip and the chevron
   alike (user 2026-10-05: «серый островок появляется только на надписи… надо, чтобы оно ещё захватывало
   стрелочку»). It lives on the heading, not on the title button, which keeps the button as narrow as the row's
   min-content needs (the chevron sits outside it so the 236px column never scrolls sideways) while the island
   still spans everything; and it reaches 8px past the text column on both sides, as before.
   Insets, not a height: a title that wraps (Dota «Набор или предмет») gets a taller pill, and since the row
   itself no longer changes with `is-open`, the island is the same in both states.
   The focus ring is drawn INSIDE the pill (like .search__clear): it then has exactly the island's shape and can
   never paint over the first field of an open section (QA 2026-10-03). */
.fpanel__heading {
  position: relative;
  isolation: isolate;
}
.fpanel__heading::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 6px -8px;
  border-radius: 12px;
  background: transparent;
  transition: background-color var(--dur-fast) var(--ease-out);
}
.fpanel__toggle:focus-visible { outline: none; }
.fpanel__heading:has(.fpanel__toggle:focus-visible)::before { background: var(--fp-hover); box-shadow: inset 0 0 0 2px var(--accent); }
.fpanel__title { flex: 1 1 auto; min-width: 0; text-wrap: balance; }
/* the number of selected conditions in this section, before the chevron: readable with the section collapsed */
.fpanel__picked {
  display: none;
  flex: none;
  min-width: 22px;
  height: 22px;
  margin: -1px 0;   /* 22px pill on the 20px text line: the row stays 52px */
  padding: 0 7px;
  border-radius: var(--radius-pill);
  background: var(--accent-tint);
  color: var(--accent-ink);
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 22px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
/* the plain count is replaced by the «N ✕» reset chip while the section holds conditions */
.fpanel__section.is-active .fpanel__picked { display: none; }
/* «Сбросить» for this section only (user 2026-10-05): between the count and the chevron while the section holds
   conditions. Out of the flow (the heading is the positioning context), so the title, the count and the chevron
   never move when it appears; the count keeps clear of it with a margin. The 44px tap target is the ::before.
   Above the heading's hover island (z-index), which runs under the whole row. */
.fpanel__clear {
  position: relative;
  z-index: 1;
  flex: none;
  /* on the toggle's own content line (16px of padding above and below), so the chip sits where the count sat,
     also when a long title wraps («Время доставки», Dota «Набор или предмет») */
  display: inline-flex;
  align-items: center;
  gap: 3px;
  height: 22px;
  margin: 15px 0 15px 8px;
  padding: 0 5px 0 7px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--accent-tint);
  color: var(--accent-ink);
  font-family: inherit;
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 22px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.fpanel__clear svg { width: 14px; height: 14px; stroke-width: 2.4; }
/* 44px tap target without taking width from the row */
.fpanel__clear::before { content: ''; position: absolute; inset: -11px -6px; }
.fpanel__clear:hover { background: var(--accent-strong); color: #FFFFFF; }
.fpanel__clear:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* The heading is the row: the toggle takes the space it needs and «Сбросить» follows it, so nothing overlaps
   and nothing reserves a width the 248px column may not have — a reserved margin widened the panel's
   min-content and the island grew a horizontal scrollbar (user 2026-10-05). A long title wraps first. */
.fpanel__heading { display: flex; align-items: stretch; }
.fpanel__toggle { flex: 1 1 auto; width: auto; min-width: 0; }
/* Beside the toggle, so it keeps the row's right edge whether or not the section shows its reset chip. Its
   room is padding and not margin (owner 2026-10-07, video: «навожусь на островок — он пропадает, и на этом
   месте я не могу нажать»): the 10px to its left and the 16px above and below it used to belong to neither
   control, so a pointer crossing that strip was over nothing — the hover island went out and the click did
   not open the section. Now the chevron's own box covers it. */
.fpanel__chev-box {
  flex: none;
  display: flex;
  align-items: center;
  padding: 16px 0 16px 10px;
  cursor: pointer;
}
.fpanel__chev {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--ink-3);
  transition: transform var(--dur-med) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.fpanel__section.is-open .fpanel__chev { transform: rotate(180deg); }
/* pointer hover only: on a phone a tapped heading would keep the grey pill (sticky :hover) until the next tap.
   The title and the chevron light the one island; «Сбросить» does not — it does something else and has its own
   hover of its own colour. One :has() per state: a list inside :has() is not reliably re-evaluated on hover. */
/* The island follows the ROW, not the two controls in it: anywhere the pointer is over the heading it is lit,
   and there is no strip between them where it blinks out. «Сбросить» still does not light it — it does
   something else and has a hover of its own colour. */
@media (hover: hover) {
  .fpanel__heading:hover:not(:has(.fpanel__clear:hover))::before { background: var(--fp-hover); }
  .fpanel__heading:hover:not(:has(.fpanel__clear:hover)) .fpanel__chev { color: var(--ink); }
}
@media (prefers-reduced-motion: reduce) {
  .fpanel__heading::before { transition: none; }
}

/* Collapsible body: height (0fr → 1fr), inert while closed, and it OPENS AT ONCE — no animation.
   It used to grow and fade in over 220ms, which read as the options rising into place from under the heading
   while the whole column reflowed around them (owner 2026-10-07: «как будто вверх поднимаются все пункты,
   которые можно выбрать… мне не надо, чтобы так было»). A list of eleven rarities is a thing to read, not a
   thing to watch arrive; and a panel that re-lays itself out on every frame of that 220ms is what made the
   «Цена» inputs and the island itself seem to move.
   An open body also slides a little up under its heading: that is part of the air the heading no longer gives
   up when it opens (see «Sections» above), so the heading row — and its island — keep one size in both states.
   How far up is set by the island, not by taste: the hover pill ends 6px above the heading's bottom edge
   (`::before` inset) and the fields start 4px inside the body, so -2px leaves exactly 8px of clear space
   between the pill and the first box of an open section — the «от» / «до» inputs of «Цена» and «Float», the
   «Редкость» list, the switches of «Другое» (user 2026-10-05: «серый островок заходит на выбор островков "от"
   и "до" … надо, чтобы между ними тоже было какое-то расстояние»). It slid 10px up before, which put the first
   box exactly on the pill's edge. Keep margin-top + .fpanel__inner's padding-top ≥ 14px. */
/* No `position: relative` here. It was put in to keep the body above the heading's island, which the island's
   own `isolation: isolate` already does — and it cost: a positioned, zero-height closed body let the 4px top
   padding of its (clipped) inner box count towards the list's scroll height, so six collapsed sections in Dota
   «overflowed» by 4px and grew a scrollbar nobody needed (owner 2026-10-07: «этот ползунок надо убрать, он не
   нужен там»). */
.fpanel__body {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
}
.fpanel__section.is-open > .fpanel__body {
  grid-template-rows: 1fr;
  visibility: visible;
  margin-top: -2px;
}
/* The clipped box has no padding of its own, so a closed body is exactly 0px (a collapsed section = its 52px
   heading row); the inner box carries the padding and the room for focus rings. */
.fpanel__clip {
  min-height: 0;
  overflow: hidden;
  margin: 0 -4px;
}
/* Fields: 4px on top (the focus ring is not clipped): the title's text ends 18px above the inputs, which is the
   8px of clear space the heading's island needs under it (see .fpanel__body above). Lists (radios, wears,
   checkboxes, switches): compact 28px rows, 8px between their boxes, and 4px more under the title, so the
   title stands a little further from the first row than the rows from each other (user 2026-10-03). An open
   section ends 16px above the divider (12px for a list, whose last row adds its own 4px), as much air as the
   next heading has above its text. */
.fpanel__inner { padding: 4px 4px 16px; }
.fpanel__section--radio .fpanel__inner,
.fpanel__section--wear .fpanel__inner,
.fpanel__section--checks .fpanel__inner,
.fpanel__section--group .fpanel__inner { padding-top: 4px; padding-bottom: 12px; }
/* compact chips reach 5px past their box (44px hit target) */
.fpanel__section--chips .fpanel__inner { padding-top: 6px; }

.fpanel__range { gap: 6px; }
.fpanel__input { min-height: 44px; padding: 0 12px; font-size: var(--fs-sm); }
.fpanel__hint { margin-top: 6px; font-size: var(--fs-xs); line-height: 1.4; color: var(--ink-3); }
.fpanel__error:empty { display: none; }
.fpanel__error { margin-top: 6px; }
.fpanel__select { min-height: 44px; font-size: var(--fs-sm); }

.fpanel__chips { gap: 6px; }
/* «Фаза»: an even grid — two equal columns, every row full (8 phases = 4 rows), no ragged tail (user request) */
.fpanel__section--chips .fpanel__chips { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.fpanel__section--chips .fpanel__chips .chip { justify-content: center; min-width: 0; padding: 0 6px; white-space: nowrap; }

.fpanel__checks { display: grid; }
.fpanel__check { display: flex; gap: 10px; width: 100%; min-height: 30px; font-size: var(--fs-sm); color: var(--ink); }
.fpanel__check-text { display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* «Состояние»: five checkbox rows «Прямо с завода (FN)». The box sits on the first text line, so the one
   name that wraps in the 216px column («После полевых / испытаний (FT)») keeps box and text aligned. */
.fpanel__wear { align-items: flex-start; min-height: 28px; padding: 4px 0; line-height: 20px; }   /* compact rows (user request) */
.fpanel__wear input { flex: none; }
.fpanel__wear-text { flex: 1 1 auto; min-width: 0; }
.fpanel__abbr { color: var(--ink-3); font-weight: 600; font-size: var(--fs-xs); line-height: 1; letter-spacing: .02em; }
.fpanel__wear:hover input:not(:checked) { border-color: var(--ink-3); }
/* last in a list body that has no bottom padding: 4px for its focus outline (2px + 2px offset) inside the clip */
.fpanel__more { min-height: 32px; margin-bottom: 4px; font-size: var(--fs-sm); }
.fpanel__dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--dot); box-shadow: inset 0 0 0 1px rgba(25, 27, 32, .12); }

/* «Редкость»: one list whose options stand under the name of their rarity ladder (filters-panel.js). 12px
   between the ladders — the rows of one ladder sit right under each other — so each reads as its own short
   list; the name is a quiet caption, never a second section heading. The margin sits on the following ladder,
   not in a `gap`: a fieldset wraps its children in an anonymous box, so its own gap is not to be relied on. */
.fpanel__group + .fpanel__group,
.fpanel__group + .fpanel__check { margin-top: 12px; }
/* The tier names are long («Экстраординарного типа», «Промышленное качество») and the column is 204px wide: here
   a name wraps instead of being cut off — a half-read rarity says nothing — and its dot keeps the first line,
   the way the wear rows keep theirs. */
.fpanel__groups .fpanel__check { align-items: flex-start; padding: 4px 0; line-height: 20px; }
.fpanel__groups .fpanel__check-text { align-items: flex-start; overflow: visible; white-space: normal; }
.fpanel__groups .fpanel__dot { margin-top: 6px; }   /* 8px dot centred on the 20px first line */
.fpanel__group-name {
  padding: 0 0 2px;
  color: var(--ink-3);
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: .01em;
}

.fpanel__toggle-row { padding: 0 2px; }
.fpanel__toggle-row .switch__label { font-size: .875rem; font-weight: 600; line-height: 1.3; }
.fpanel__toggle-row .switch__input:focus-visible + .switch__track { box-shadow: var(--focus-ring); }
.fpanel__toggle-row .fpanel__hint { margin-top: -2px; padding: 0 52px 8px 0; }

/* Desktop island (user 2026-10-03: the filters got lost beside the full-width grid): a wider 248px column, every
   text 2px larger than the base scale (titles 17, options and fields 15, hints / codes 14); the lift and the
   outline sit on the column itself (see «Layout»). The phone sheet keeps the base sizes. */
/* (selectors carry the .catalog__filters column: these rules sit above the base rules of the same parts) */
@media (min-width: 1100px) {
  .catalog__layout { grid-template-columns: 248px minmax(0, 1fr); }
  .catalog__filters .filters-title__text { font-size: 1.875rem; }
  .catalog__filters .fpanel__toggle { font-size: 1.0625rem; }
  .catalog__filters .fpanel__check,
  .catalog__filters .fpanel__radio,
  .catalog__filters .fpanel__input,
  .catalog__filters .fpanel__select,
  .catalog__filters .fpanel__more,
  .catalog__filters .fpanel .chip { font-size: var(--fs-base); }
  .catalog__filters .fpanel__pick-row { font-size: var(--fs-base); }
  .catalog__filters .fpanel__hint,
  .catalog__filters .fpanel__group-name,
  .catalog__filters .fpanel__pick-note,
  .catalog__filters .fpanel__pick-n,
  .catalog__filters .fpanel__abbr { font-size: .875rem; }
  /* the names of «Другое» read alike: the switches' labels and the pattern field's own label */
  .catalog__filters .fpanel__toggle-row .switch__label,
  .catalog__filters .fpanel__field-label { font-size: 1rem; }
}

/* «Время доставки»: native radios, one 44px row each */
.fpanel__radios { display: grid; margin: 0; padding: 0; border: 0; min-width: 0; }
.fpanel__radio {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 28px;   /* compact rows: 8px between the circles (user request); the whole row is the click target */
  font-size: var(--fs-sm);
  color: var(--ink);
  cursor: pointer;
}
.fpanel__radio-input {
  appearance: none;
  -webkit-appearance: none;
  display: grid;
  place-items: center;
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0;
  border: 1.5px solid var(--line-control);
  border-radius: 50%;
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.fpanel__radio-input::after {
  content: '';
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent-strong);
  transform: scale(0);
  transition: transform var(--dur-fast) var(--ease-out);
}
.fpanel__radio-input:checked { border-color: var(--accent-strong); }
.fpanel__radio-input:checked::after { transform: scale(1); }
.fpanel__radio-input:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.fpanel__radio:hover .fpanel__radio-input:not(:checked) { border-color: var(--ink-3); }
.fpanel__radio-text { flex: 0 1 auto; min-width: 0; }   /* the delivery icon follows the word, not the panel's edge */

/* «Другое»: switches and the pattern field as sub-blocks of one section. No hairline inside a section (the
   dividers mark sections); instead every member keeps the same rhythm — its name on a 44px line, the switch
   at the right of that line or the field under it. The pattern label therefore reads exactly like «С брелоком»
   above it, in the same size, weight and place (user 2026-10-05: «слово "паттерн" слишком выделяется от других
   названий»); before, it was the one name of the group that kept the small base size on the desktop island and
   sat glued to its input, so it read as a form field dropped into a list of switches. */
.fpanel__sub--text { padding: 0 0 8px; }
.fpanel__field-label {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0 2px;
  font-size: .875rem;        /* = .fpanel__toggle-row .switch__label, bumped together on the desktop island */
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
}

/* The name search under «С наклейками» / «С брелоком» (user 2026-10-05): a search field in the panel's own
   scale, then the names the stock really carries, each with how many items carry it, the chosen one tinted.
   A long name wraps instead of widening the row: the column is 236px and must never scroll sideways. */
.fpanel__pick { padding: 0 2px 10px; }
.fpanel__pick-field .search__icon { left: 10px; width: 18px; height: 18px; }
.fpanel__pick-input { padding: 0 36px 0 34px; }
.fpanel__pick-clear { width: 36px; }
.fpanel__pick-clear svg { width: 16px; height: 16px; }
.fpanel__pick-list { display: grid; gap: 2px; margin-top: 8px; }
.fpanel__pick-list:empty { display: none; }
.fpanel__pick-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-width: 0;
  min-height: 32px;
  padding: 5px 8px;
  border-radius: var(--radius-sm);
  color: var(--ink);
  font-size: var(--fs-sm);
  line-height: 1.3;
  text-align: left;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.fpanel__pick-name { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.fpanel__pick-n { flex: none; color: var(--ink-3); font-size: var(--fs-xs); font-weight: 600; font-variant-numeric: tabular-nums; }
.fpanel__pick-row[aria-pressed='true'] { background: var(--accent-tint); color: var(--accent-ink); font-weight: 600; }
.fpanel__pick-row[aria-pressed='true'] .fpanel__pick-n { color: var(--accent-ink); }
.fpanel__pick-row:focus-visible { outline: none; box-shadow: var(--focus-ring); }
@media (hover: hover) {
  .fpanel__pick-row:hover { background: var(--fp-hover); }
  .fpanel__pick-row[aria-pressed='true']:hover { background: var(--accent-tint); }
}
@media (prefers-reduced-motion: reduce) {
  .fpanel__pick-row { transition: none; }
}
/* «Такой наклейки в наличии нет», or the line that says the list was cut: one quiet line, never an empty box */
.fpanel__pick-note { margin-top: 8px; padding: 0 2px; font-size: var(--fs-xs); line-height: 1.4; color: var(--ink-3); }
.fpanel__pick-note:empty { display: none; }
@media (prefers-reduced-motion: reduce) {
  .fpanel__radio-input,
  .fpanel__radio-input::after { transition: none; }
}

.fpanel__empty { padding: 16px 2px; font-size: var(--fs-sm); color: var(--ink-3); }
/* «Сбросить»: full width under the list, a secondary button. While anything is selected the footer sticks to the
   bottom of the scrolling column, so the reset is one click away from any section; with nothing selected it is
   flat and quiet (white, hairline, grey label) instead of the default grey block, and stays at the list's end. */
.fpanel__footer {
  padding: 16px var(--fp-x);
  border-top: 1px solid var(--line);
  background: var(--surface);
}
.catalog__filters .fpanel--active .fpanel__footer { position: sticky; bottom: 0; z-index: 1; }
.fpanel__reset { min-height: 44px; font-weight: 600; }
.fpanel__reset:disabled { --btn-bg: var(--surface); --btn-bd: var(--line); --btn-fg: #8C9099; }

/* ==========================================================================
   Results: summary row, grid, states
   ========================================================================== */
.catalog__results { min-width: 0; }
.catalog__summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  min-height: 28px;
  margin-bottom: 8px;
}
.catalog__count { font-size: var(--fs-sm); color: var(--ink-2); white-space: nowrap; }
.catalog__count strong { font-weight: 600; color: var(--ink); }
.catalog__count:focus { outline: none; }
/* ≈ «41 предмет»: a wider placeholder made the summary row jump when the real count arrived */
.catalog__count-sk { width: 72px; height: 14px; }
.catalog__chips { flex: 1 1 320px; min-width: 0; }
.catalog__chip-list { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; padding: 0; list-style: none; }
.catalog__chip-list .chip { min-height: 36px; }
.catalog__chip-list .chip::before { inset: -4px 0; }
/* A condition may name a long thing — «Наклейка: Natus Vincere (Holo) | Copenhagen 2024» (user 2026-10-05).
   A chip never grows past the row: the label is cut with an ellipsis and the whole text stays in the chip's
   aria-label («Убрать условие: …»), so a 390px phone never scrolls sideways. */
.catalog__chip-list > li { min-width: 0; max-width: 100%; }
.catalog__chip-list .chip { max-width: 100%; }
.catalog__chip-list .chip > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.catalog__reset-all { font-size: var(--fs-sm); padding: 0 6px; }

.catalog__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr));
  gap: 16px 12px;
}
.catalog__grid[hidden] { display: none; }
/* «Показать ещё»: centred under the grid — a quiet «Показано 48 из 27 412» over a secondary button in the
   toolbar's geometry (13px radius, 50px); full width on phones, where it sits under two narrow columns */
.catalog__more { display: grid; justify-items: center; gap: 12px; margin: 32px 0 8px; }
.catalog__more[hidden] { display: none; }
.catalog__more-text { margin: 0; font-size: var(--fs-sm); color: var(--ink-3); }
.catalog__more-btn { min-width: 240px; min-height: 50px; padding: 0 24px; border-radius: 13px; }
.catalog__more-btn svg { width: 18px; height: 18px; color: var(--ink-3); transition: color var(--dur-fast) var(--ease-out); }
.catalog__more-btn:hover svg { color: currentColor; }
@media (max-width: 767.98px) {
  .catalog__more { margin-top: 24px; }
  .catalog__more-btn { width: 100%; min-height: 48px; }
}
.catalog__state[hidden] { display: none; }
.catalog__state .state { padding: 56px 24px; }
.catalog__suggest { display: grid; justify-items: center; gap: 8px; margin-top: 12px; }
.catalog__suggest .chip-row { justify-content: center; margin: 0; padding: 0; list-style: none; }
.catalog__suggest .chip { min-height: 36px; }
.catalog__suggest .chip::before { inset: -4px 0; }

/* ==========================================================================
   Product card (.pcard) — used by catalog and favorites
   ========================================================================== */
.pcard {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  container-type: inline-size;
  container-name: pcard;
  /* Media = an icon band over the picture box, the picture box, and a chip band under it. The quick-view /
     favourite buttons (hover surface and focus ring included) end 46px down; the picture box starts at 52px
     (+3px air, +3px for the hover lift), so wide items (Butterfly Knife, Karambit, gloves, AWP) never run under
     them. At the other end the stickers and «×N» take --pc-worn-band (user 2026-10-06: they sit over the item,
     above the rarity hairline) — the chips are 24px tall and start 9px up, so they reach 1px into the picture
     box, which is the overlap that makes them read as laid ON the item rather than in a strip of their own
     (object-fit leaves a side-on weapon far more slack than that). Both bands are ADDED to the media: the
     picture box keeps the height it had in the old 3:2 media (2/3 of the width − 24px), the item never shrinks.
     (cqw resolves where the property is used: in the card's children, against this card.) */
  --pc-pic-top: 52px;
  --pc-worn-band: 26px;
  --pc-media-h: calc(100cqw * 2 / 3 + 34px + var(--pc-worn-band));
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface);
  transition:
    transform var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}
.pcard:hover {
  transform: translateY(-2px);
  border-color: rgba(55, 129, 252, .4);
  box-shadow: var(--shadow-2);
}

/* The item takes ~60% of the card's height. The glow sits behind the picture box (below the icon band). */
.pcard__media {
  position: relative;
  height: var(--pc-media-h);
  overflow: hidden;
  border-radius: 15px 15px 0 0;
  background:
    radial-gradient(70% 64% at 50% 61%, rgba(214, 228, 255, .78) 0%, rgba(232, 240, 255, .4) 52%, rgba(255, 255, 255, 0) 82%),
    linear-gradient(180deg, #F2F6FE 0%, #FFFFFF 100%);
}
.pcard__media-link {
  position: absolute;
  inset: 0;
  display: grid;
  /* One cell sized by the padded box, not by the image: with an auto row the cell grew to the image's own
     aspect height, so height:100% never constrained it and the item's bottom (Karambit ring, M9 handle) was
     cut by the media's overflow. Now object-fit keeps the whole item inside. */
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  place-items: center;
  padding: var(--pc-pic-top) 16px calc(6px + var(--pc-worn-band));
}
.pcard__img {
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  object-fit: contain;
  transition: transform var(--dur-fast) var(--ease-out), filter var(--dur-fast) var(--ease-out);
}
.pcard:hover .pcard__img { transform: translateY(-3px); filter: brightness(1.05) saturate(1.03); }

/* Dota art: opaque 3:2 with a 1px frame → full-bleed cover of the whole media (icon band included: the buttons
   sit on the scrim), a slight scale hides the frame and covers the hover lift */
.pcard--art .pcard__media { background: #1E2129; }
.pcard--art .pcard__media-link { padding: 0; }
.pcard--art .pcard__img { object-fit: cover; transform: scale(1.06); }
.pcard--art:hover .pcard__img { transform: translateY(-3px) scale(1.06); }
/* a soft scrim under the icon buttons, so art cards use the same bare icons as the light CS2 cards */
.pcard--art .pcard__media::after {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 64px;
  background: linear-gradient(180deg, rgba(12, 14, 18, .5), rgba(12, 14, 18, 0));
  pointer-events: none;
}

/* the item's rarity colour as a hairline under the picture, as on the games' own item tiles and in the home
   purchase feed (user 2026-10-05: «на сайте человек должен понимать, какой редкости у него оружие») */
.pcard__media::after {
  content: '';
  position: absolute;
  z-index: 1;
  inset: auto 0 0;
  height: 3px;
  background: var(--rarity, transparent);
}
.pcard__noimg { display: grid; place-items: center; width: 100%; height: 100%; color: var(--ink-3); }

/* Our mark behind the item: the SA monogram over the wordmark set lowercase, both from components/logo.js —
   one brand mark, drawn once. Centred in the picture box (below the icon band, above the rarity hairline) and
   first in the media, so the item always paints over it.
   Owner 2026-10-07: «она должна быть побольше, раза в два-три, чтобы прям заметная такая была». It is sized by
   the card now (cqw), so it fills the same share of the picture on a 4-column card and on a phone, and it is
   drawn at a little more ink than the hairline watermark it replaced — still well under the item, which paints
   straight over it, but clearly the shop's own paper and no longer a smudge.
   Dota 2 art covers the whole media, so the mark would be invisible there anyway: it is dropped. */
.pcard__wm {
  position: absolute;
  z-index: 0;
  inset: var(--pc-pic-top) 0 6px;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 6px;
  color: var(--accent);
  opacity: .085;
  pointer-events: none;
}
.pcard--art .pcard__wm { display: none; }
/* Twice again on 07.10.2026 («надо ещё увеличить в два раза»): the monogram now fills most of the picture box's
   width, which is as large as it can be drawn without running past the item. */
.pcard__wm .monogram { width: clamp(104px, 76cqw, 240px); }
/* the wordmark is letter-spaced, so its line is ≈8.6em wide: at 10.5cqw it stays inside the card at every size
   and is never clipped by the media's overflow */
.pcard__wm .wordmark {
  font-size: clamp(14px, 10.5cqw, 36px);
  letter-spacing: .2em;
  text-transform: lowercase;
  color: currentColor;
}
.pcard__wm .wordmark__skin,
.pcard__wm .wordmark__aura { color: currentColor; }

/* The picture's top band: this item's delivery at the near end, «×N» and the wishlist heart at the far one
   (owner 2026-10-07: «X56 … будет левее от значка», and the quick-view eye off the card altogether). One flex
   row rather than three absolutely placed boxes, so the three islands keep their spacing at every card width
   and nothing has to be nudged by hand when one of them is missing. */
.pcard__top {
  /* one height and one radius for all three (owner 2026-10-07: «там везде разный островок размером — надо,
     чтобы они были одинакового скругления и одинаковой высоты»). The heart keeps its 44px hit target around
     a 28px surface, so the three read as one row of islands while the control stays tappable. */
  --pc-island: 28px;
  position: absolute;
  z-index: 2;
  inset: 2px 2px auto;
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
/* the delivery keeps the near end; «×N» and the heart are pushed to the far one */
.pcard__top .pcard__ship { margin-right: auto; }

/* The wishlist heart, a 44px target. What shows is the inner 36px surface (::before, under the icon) — and it
   is drawn ALWAYS, not on hover (owner 2026-10-07: «его надо взять в островок… сразу видно, не только когда
   наводишься»). A control a visitor cannot see is a control that is not there, and on touch there is no hover
   at all to reveal it. Round, because that is the shape the delivery pill and «×N» beside it have — «у всех у
   них должно быть одинаковое скругление». Hover only deepens the shadow and inks the glyph; focus puts the ring
   around the same surface. */
.pcard__icon-btn {
  position: relative;
  z-index: 2;
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  color: var(--ink-2);
  transition: color var(--dur-fast) var(--ease-out);
}
.pcard__icon-btn::before {
  content: '';
  position: absolute;
  /* the visible island is --pc-island tall, centred in the 44px target */
  inset: calc((44px - var(--pc-island, 36px)) / 2);
  z-index: -1;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(25, 27, 32, .08);
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}
.pcard__icon-btn svg { width: 20px; height: 20px; }
.pcard__icon-btn:hover { color: var(--accent-ink); }
.pcard__icon-btn:hover::before {
  border-color: var(--line-strong);
  box-shadow: 0 1px 2px rgba(25, 27, 32, .06), 0 4px 10px -4px rgba(25, 27, 32, .2);
}
.pcard__icon-btn:focus-visible { outline: none; }
.pcard__icon-btn:focus-visible::before { box-shadow: var(--focus-ring); }
/* the hovered/focused button's tooltip must paint above its neighbours (same z otherwise) */
.pcard__icon-btn:hover,
.pcard__icon-btn:focus-visible { z-index: 3; }
.pcard__fav[aria-pressed='true'] { color: var(--accent); }
.pcard--art .pcard__icon-btn,
.pcard--art .pcard__fav[aria-pressed='true'] { color: #FFFFFF; }
.pcard--art .pcard__icon-btn::before {
  border-color: rgba(255, 255, 255, .2);
  background: rgba(14, 16, 21, .66);
  box-shadow: 0 2px 8px -2px rgba(0, 0, 0, .45);
}
.pcard--art .pcard__icon-btn:hover { color: #FFFFFF; }
.pcard--art .pcard__icon-btn:hover::before {
  border-color: rgba(255, 255, 255, .34);
  background: #1E2129;
  box-shadow: 0 4px 10px -4px rgba(0, 0, 0, .5);
}
.pcard--art .pcard__icon-btn:focus-visible::before { box-shadow: var(--focus-ring); }

/* The delivery pill, at the near end of the top band (user 2026-10-06). It says this item's own delivery, so
   every available card carries one: ⚡ «Мгновенно» green, 🕐 «До 12 часов» in the brand ink blue, 📅 «С 05.10»
   a neutral clock — the colours and the words of the «Время доставки» filter beside the grid. 22px tall and
   centred against the 44px heart by the band's own flex row; it gives way (ellipsis) before «×N» and the heart
   do, since those two are an exact count and a control. Narrow cards keep the icon alone (below). */
.pcard__ship {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex: 0 1 auto;
  min-width: 0;
  height: var(--pc-island, 22px);
  margin-left: 8px;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  cursor: default;
}
.pcard__ship svg { flex: none; width: 14px; height: 14px; }
.pcard__ship-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.pcard__ship--instant { border-color: #BCE0CE; background: var(--success-tint); color: var(--success); }
.pcard__ship--within { border-color: #C9DCFB; background: var(--accent-tint); color: var(--accent-ink); }
.pcard--art .pcard__ship { border-color: rgba(255, 255, 255, .2); background: rgba(14, 16, 21, .66); color: #FFFFFF; }
.pcard--art .pcard__ship--instant { border-color: rgba(154, 222, 187, .45); color: #9ADEBB; }
.pcard--art .pcard__ship--within { border-color: rgba(168, 200, 255, .45); color: #B9D3FF; }
/* its tip carries the long wording and the other instances, so it wraps and is capped to the card's width —
   it opens from the pill's left edge and never sticks out of the grid */
.pcard .pcard__ship[data-tip]::after {
  left: -8px;
  right: auto;
  width: max-content;
  max-width: min(220px, calc(100cqw - 4px));
  white-space: normal;
  text-align: left;
  transform: translate(0, -4px);
}
.pcard .pcard__ship[data-tip]:hover::after,
.pcard .pcard__ship[data-tip]:focus-visible::after { transform: translate(0, 0); }

/* Badges (markup: first in the body). Wide cards lift them onto the image's lower left, where items leave air.
   They now stand one step higher than they did — on top of the sticker band, not in it — so a Doppler's
   «Phase 1» and an agent's «За T» never meet the sticker chips at any width. Only those two are left here: the
   delivery moved to the pill of the top row, StatTrak™ and Souvenir to the «ST» / «SV» of the name line. */
.pcard__badges {
  position: absolute;
  z-index: 2;
  top: calc(var(--pc-media-h) - 14px - var(--pc-worn-band));
  left: 10px;
  display: flex;
  gap: 4px;
  max-width: calc(100% - 20px);
  transform: translateY(-100%);
  pointer-events: none;
}
.pcard__badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 22px;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}
/* agents: the side, in the game's own colours — T warm amber, CT steel blue (always solid, also on dark art cards) */
.pcard__badge--team { font-weight: 700; letter-spacing: .02em; }
.pcard__badge--t, .pcard--art .pcard__badge--t { border-color: #E9C36A; background: #FFF3D6; color: #8A5A00; }
.pcard__badge--ct, .pcard--art .pcard__badge--ct { border-color: #A9C3F2; background: #E7EFFF; color: #2457B3; }
/* on art: quiet dark pills that stay legible on any painting */
.pcard--art .pcard__badge { border-color: rgba(255, 255, 255, .2); background: rgba(14, 16, 21, .66); color: #FFFFFF; }

.pcard .pcard__cart[data-tip]::after { left: auto; right: 0; transform: translate(0, 4px); }
.pcard .pcard__cart[data-tip]:hover::after,
.pcard .pcard__cart[data-tip]:focus-visible::after { transform: translate(0, 0); }

.pcard__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  padding: 6px 14px 12px;
}

/* The picture's own bottom row (user 2026-10-06), in the order the owner walked through it on 2026-10-07:
   «×N» at the very left, then the charm, and the stickers at the right end. It spans the whole picture, not
   the text column, so five sticker chips and the count fit a 4-column card; the --pc-worn-band of the media is
   reserved for it, so the item above never runs under it. pointer-events stay off: the picture is one link. */
.pcard__worn-row {
  position: absolute;
  z-index: 2;
  inset: auto 10px 9px;
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 24px;
  pointer-events: none;
}
.pcard__worn {
  display: flex;
  min-width: 0;
  margin: 0;
  padding: 0;
  gap: 4px;
  overflow: hidden;
  list-style: none;
}
/* «а справа, если есть стикеры» — they take the far end of the row, whatever stands at the near one */
.pcard__worn--stickers { margin-left: auto; }
/* Over a photograph a chip needs the card's own surface, as the badges and the delivery pill have: a white
   tile with a hairline and a hair of shadow, so it reads on a white AWP and on a black AK alike. (Sticker art
   is drawn for light backgrounds, so these tiles stay white on art cards too — Dota items wear no stickers.) */
.pcard__worn-item {
  display: grid;
  /* four stickers and a charm is the fullest an item gets: at four they keep their 32px, at five they give up
     a couple of pixels each rather than the fifth being clipped away (object-fit keeps every picture whole) */
  flex: 0 1 auto;
  place-items: center;
  width: 32px;
  min-width: 24px;
  height: 24px;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(25, 27, 32, .08);
  color: var(--ink-3);
}
.pcard__worn-item img { width: 100%; height: 100%; object-fit: contain; }
/* «×35» — how many pieces of this item + wear are on sale, in the top band just left of the heart (owner
   2026-10-07). The one island of the picture painted in the brand blue («выделить цветом, цветом сайта»): the
   white chips around it belong to the item — what it wears, when it ships — while this one belongs to the shop
   and answers how much there is to choose from, which is what sends a visitor to the item page. Same pill
   radius as the heart and the delivery, so the three of them read as one family. */
.pcard__qty {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 3px;
  height: var(--pc-island, 24px);
  padding: 0 9px 0 7px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--accent);
  box-shadow: 0 2px 8px -3px rgba(31, 91, 209, .9);
  color: #FFFFFF;
  font-size: var(--fs-xs);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.pcard__qty svg { width: 14px; height: 14px; color: rgba(255, 255, 255, .78); }
/* on art the picture is an opaque painting, and the blue holds against it as well as against a white AWP */
.pcard--art .pcard__qty { border-color: rgba(255, 255, 255, .22); box-shadow: 0 2px 8px -2px rgba(0, 0, 0, .5); }

/* The name on TWO lines (owner 2026-10-07): «ST™» and the thing on the first — «★ Керамбит» — and WHAT IT IS on
   the second: «Волны Фаза 2».
   The second line is the loud one («сделать акцент не на том, что это за предмет по типу керамбит… а на
   названии… чтобы этот шрифт был больше»): a Керамбит is a Керамбит, and what a buyer chooses — and pays the
   difference for — is the finish and its phase. So the type line is set small and quiet above it, the way a
   category sits over a product name, and the finish takes the card's largest text after the price.
   The second line keeps its box even when an item has nothing to put there, so the names across a grid row sit
   on one baseline and the price rows below them line up. */
.pcard__name { margin: 0; font-size: var(--fs-base); font-weight: 500; line-height: 1.3; }
.pcard__link {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-width: 0;
  /* the hit area the two lines make, without changing the rhythm */
  margin: -3px 0;
  padding: 3px 0;
  border-radius: 6px;
  color: var(--ink);
  text-decoration: none;
}
.pcard__link:hover { color: var(--ink); }
.pcard__link:hover .pcard__line2 { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .18em; }
.pcard__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* the type line: small, quiet, above the name — «ST™ ★ Керамбит» */
.pcard__line1 {
  display: flex;
  align-items: baseline;
  gap: 5px;
  max-width: 100%;
  min-width: 0;
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1.35;
  color: var(--ink-3);
}
.pcard__lead { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the name itself: the biggest text on the card after the price — «Волны Фаза 2» */
.pcard__line2 {
  display: block;
  max-width: 100%;
  min-height: calc(1em * 1.25);
  overflow: hidden;
  font-size: var(--fs-md);
  font-weight: 600;
  line-height: 1.25;
  color: var(--ink);
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* StatTrak™ / Souvenir written out, not tiled (owner 2026-10-07: «не иконкой, а именно писать») — in the two
   inks the item page's own heading uses for them (product.css .pd-title__kind--*). The words themselves are in
   the title's accessible name. */
.pcard__mark {
  flex: none;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .02em;
  line-height: 1.2;
}
.pcard__mark--st { color: #9A4A00; }
.pcard__mark--sv { color: var(--warning); }

/* The exterior and its float (a painted CS2 item), else the rarity — and the quality in Dota 2.
   Built to the owner's reference of 2026-10-07: «FN и рядом расшифровка — прямо с завода; потом такая
   полосочка; и написано флот, и его флот — только потемнее». A step darker than it was, so the two facts that
   decide a purchase are read and not skimmed past. */
.pcard__meta {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  margin-top: 3px;
  overflow: hidden;
  font-size: var(--fs-xs);
  line-height: 1.35;
  color: var(--ink-2);
  white-space: nowrap;
}
/* meta parts: each carries its own leading separator, so narrow cards can re-flow them cleanly */
.pcard__mp { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.pcard__dotsep { color: var(--ink-3); }
/* «FN» as a chip, «Прямо с завода» beside it — the words give way first when the row runs out of room */
.pcard__wear { gap: 6px; }
/* The float follows the words straight away, with the bar between them — one phrase, as in the reference, not
   two ends of a stretched row. It is never shortened (a cut float is a wrong number); the long exteriors —
   «После полевых испытаний», «Немного поношенное» — ellipsise instead, and the chip still says which it is. */
.pcard__mp--float { flex: none; gap: 4px; }
.pcard__bar { flex: none; width: 1px; height: 13px; margin-right: 2px; background: var(--line-strong); }
.pcard__float-k { color: var(--ink-3); }
.pcard__float-v { color: var(--ink); font-weight: 700; }
/* The exterior's own colour, as the market reads it: green when the skin is untouched, through amber, to red
   when it is battered. The chip is the only place on the card that says it in one glance — the words beside it
   are long and the float is a number. */
.pcard__wear-code {
  flex: none;
  padding: 2px 6px;
  border-radius: 6px;
  background: var(--surface-sunken);
  color: var(--ink-2);
  font-weight: 700;
  letter-spacing: .02em;
}
.pcard__wear--fn .pcard__wear-code { background: var(--success-tint); color: var(--success); }
.pcard__wear--mw .pcard__wear-code { background: #EAF4E2; color: #3E6B22; }
.pcard__wear--ft .pcard__wear-code { background: var(--warning-tint); color: var(--warning); }
.pcard__wear--ww .pcard__wear-code { background: #FCE9DA; color: #9A4A00; }
.pcard__wear--bs .pcard__wear-code { background: #FBE8E8; color: #A82C2C; }
.pcard__wear-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.pcard__tag { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.pcard__tag-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.pcard__dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--dot); box-shadow: inset 0 0 0 1px rgba(25, 27, 32, .12); }

/* Price row: «12 345 ₽» on one line beside «Купить» + cart (no «от» any more, user 2026-10-06 — the «×N» under
   the picture is what says a group has several). The row is aligned on the baseline of «Купить» (the same in
   every card), so single, group and smaller long prices share one baseline across a grid row. wrap is only a
   safety net (a fallback font wider than Golos): the buttons drop below, the price is never clipped or broken. */
.pcard__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  /* the hairline the owner asked for between the facts and the price (2026-10-06): the foot's own top border,
     so the divider costs one pixel and keeps the 8px rhythm it already had */
  margin-top: auto;
  padding-top: 9px;
  border-top: 1px solid var(--line);
}
.pcard__price { display: flex; flex: none; align-items: baseline; gap: 4px; color: var(--ink); line-height: 1.1; white-space: nowrap; }
/* The price takes what the buttons leave: the size follows the card width (cqw) so the widest realistic price
   still fits — up to 7 digits («1 234 567 ₽», «9 999,99 $») at up to 19px, and 8 digits (--long: «12 439 386 ₸»,
   the dearest items in ₸) a step smaller.
   Golos digits are not equal-width (0 1 4 7 = .64em, 2 3 5 = .60em), so the coefficients are fitted to the widest
   digits, with 1.5px to spare: slope = 100 / (string width in em) — 5.29em and 6.005em —, intercept =
   everything else in the row (padding, gaps, Buy + cart) / that width. The fit still carries the ≈24px the
   dropped «от»/«from» used to take, so it now has that much slack: the sizes are left as they were, so a price
   does not change size on a card whose group shrank to one piece. */
.pcard__price .t-price { font-size: clamp(15px, 18.9cqw - 33.31px, 1.1875rem); }
.pcard__price--long .t-price { font-size: clamp(13px, 16.65cqw - 29.67px, 1.1875rem); }
.pcard__price--none { font-size: var(--fs-sm); font-weight: 600; color: var(--ink-3); }
.pcard__actions { display: flex; flex: none; gap: 6px; margin-left: auto; }
.pcard__buy { min-width: 64px; padding: 0 14px; }
.pcard__cart.is-in-cart { --btn-bg: var(--surface); --btn-bd: var(--accent); }
/* «Выбрать» of a group card: the arrow says it opens the item, where the exact piece is chosen */
.pcard__pick { gap: 4px; padding: 0 10px 0 12px; }
.pcard__pick svg { width: 16px; height: 16px; margin-right: -2px; }

/* Unavailable: muted, still favouritable */
.pcard.is-unavailable .pcard__img { opacity: .5; filter: grayscale(.55); }
.pcard.is-unavailable:hover .pcard__img { filter: grayscale(.55); }
.pcard.is-unavailable .pcard__lead { color: var(--ink-2); }

/* Medium cards (>236–268px inside, e.g. 4 columns at 1440 and 1536): tighter price/actions row, price up to 17px
   (≈16px at 1440; «от» + 7 digits ≈14px). From ≈1280 (277px cards) the 19px price applies again.
   Range syntax, so it starts exactly where the narrow query ends: with «min-width: 237px» a fractional
   236.5px card (2 columns at a 532px window) fell between the two and got the wide row — buttons dropped. */
@container pcard (236px < width <= 268px) {
  .pcard__body { padding-left: 10px; padding-right: 10px; }
  .pcard__price .t-price { font-size: clamp(14px, 18.9cqw - 29.91px, 1.0625rem); }
  .pcard__price--long .t-price { font-size: clamp(12px, 16.65cqw - 26.67px, 1.0625rem); }
  .pcard__foot { gap: 6px; }
  .pcard__buy { min-width: 56px; padding: 0 10px; }
}

/* Narrow cards (2 columns on phones, ≈166px). The item comes first: a ≈square media whose top 50px is the icon
   band (the 44px targets sit in the corners: surface 4–40px, ring to 44px, +3px lift, +3px air), a 4:3 picture
   box the full inner width below it, and the sticker band under that — only the phase / side badges leave the
   picture and join the text block, so nothing covers the item. Price on its own line, Buy stretches. */
@container pcard (max-width: 236px) {
  .pcard__media { height: calc((100cqw - 16px) * 3 / 4 + 56px + var(--pc-worn-band)); }
  .pcard__media-link { padding: 50px 8px calc(6px + var(--pc-worn-band)); }
  .pcard--art .pcard__media-link { padding: 0; }
  .pcard__wm { inset: 50px 0 calc(6px + var(--pc-worn-band)); gap: 4px; }
  /* smaller chips on a 166px card: four stickers and the count still fit the row */
  .pcard__worn-row { inset: auto 6px 8px; gap: 4px; min-height: 21px; }
  .pcard__worn { gap: 3px; }
  .pcard__worn-item { width: 27px; height: 21px; padding: 1.5px; border-radius: 6px; }
  .pcard__qty { height: 21px; gap: 2px; padding: 0 7px 0 5px; }
  .pcard__qty svg { width: 12px; height: 12px; }
  .pcard__icon-btn svg { width: 18px; height: 18px; }
  /* a ≈166px card has no room for «До 12 часов» beside «×N» and the heart: the pill keeps the icon and hands
     the words to its accessible name (and to the tooltip, which a tap can still open) */
  .pcard__top { inset: 0 0 auto; gap: 4px; }
  .pcard__ship { width: 30px; height: 30px; margin-left: 6px; padding: 0; justify-content: center; }
  .pcard__ship-text { display: none; }
  .pcard__badges { position: static; flex-wrap: wrap; max-width: none; margin-top: 2px; margin-bottom: 4px; transform: none; }
  .pcard__badge { height: 20px; padding: 0 7px; }
  .pcard--art .pcard__badge { border-color: var(--line); background: var(--surface); color: var(--ink-2); }
  .pcard__body { padding: 8px 10px 10px; }
  .pcard__name { font-size: var(--fs-sm); }
  .pcard__link { margin: -4px 0; padding: 4px 0; }
  /* a long name wraps (two lines) instead of hiding behind an ellipsis: a title tooltip does not work on touch */
  .pcard__lead { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; white-space: normal; overflow-wrap: anywhere; }
  .pcard__line1 { align-items: flex-start; }
  .pcard__line2 { font-size: var(--fs-xs); white-space: normal; overflow-wrap: anywhere; }
  .pcard__mark { margin-top: 1px; }
  /* two clean lines instead of a dangling separator: «FN Прямо с завода» / «≈ Float …», «● Arcana» /
     «Обычная», «● Экстраординарного типа» (wrapping whole words, never cut) */
  .pcard__meta { gap: 2px 6px; flex-wrap: wrap; }
  .pcard__mp { gap: 5px; }
  .pcard__mp--float { order: 2; flex-basis: 100%; margin-left: 0; padding-left: 0; }
  /* the bar divides two things on ONE line; on its own line the float needs no divider before it */
  .pcard__mp--float .pcard__bar { display: none; }
  .pcard__wear { flex-basis: 100%; }
  .pcard__mp--block,
  .pcard__tag { flex-basis: 100%; }
  .pcard__tag { align-items: flex-start; }
  .pcard__tag .pcard__dot { margin-top: calc((1.35em - 8px) / 2); }
  /* whole words wrap; a single word longer than the card (≤340px phones) is hyphenated, else ellipsised */
  .pcard__tag-text { white-space: normal; -webkit-hyphens: auto; hyphens: auto; }
  .pcard__tag + .pcard__mp > .pcard__dotsep { display: none; }
  .pcard__foot { padding-top: 8px; gap: 8px; }
  .pcard__price { width: 100%; }
  .pcard__price .t-price { font-size: var(--fs-md); }
  /* 15px; on the smallest two-column phones (≈140px cards at 340–350px) a step down, so «from 1,234,567 ₸» stays
     inside the card */
  .pcard__price--long .t-price { font-size: clamp(13px, 16.65cqw - 9.06px, .9375rem); }
  .pcard__actions { width: 100%; }
  .pcard__buy { flex: 1 1 auto; min-width: 0; padding: 0 10px; }
  /* Invisible tooltips still count toward the page's scroll width: on phones a right-column card pushed
     the page sideways. Here they leave the layout until they are actually shown, and open inward. */
  .pcard [data-tip]::after { display: none; }
  .pcard [data-tip]:hover::after,
  .pcard [data-tip]:focus-visible::after { display: block; }
}

/* Skeleton card: the real card's boxes (the picture box and the «×N» chip at the near end of its bottom row,
   the two title lines, one meta line, the 40px foot under its hairline), so the grid does not move when cards
   arrive; fills read on white (≈1.2:1) without shimmer. */
.pcard--skeleton { pointer-events: none; }
.pcard--skeleton:hover { transform: none; box-shadow: none; border-color: var(--line); }
.pcard--skeleton .pcard__media { background: var(--surface-2); }
.pcard--skeleton .skeleton { background: #E8E9E6; }
.pcard--skeleton .pcard__foot { align-items: center; }
.pcard__sk-media { position: absolute; inset: var(--pc-pic-top) 22px calc(8px + var(--pc-worn-band)); height: auto; border-radius: 12px; }
.pcard__sk-worn { width: 48px; height: 24px; border-radius: var(--radius-pill); }
/* two lines, as every real card now has: the name and, under it, what the skin is */
.pcard__sk-name {
  display: grid;
  align-content: space-around;
  height: calc(1em * 1.3 + 1px + var(--fs-sm) * 1.3);
  font-size: var(--fs-base);
}
.pcard__sk-meta { display: grid; align-items: center; height: calc(1em * 1.35); margin-top: 2px; font-size: var(--fs-xs); }
.pcard__sk-line { height: 12px; border-radius: 6px; }
.pcard__sk-price { width: 84px; height: 22px; border-radius: 6px; }
.pcard__sk-btn { width: 80px; height: 40px; }
.pcard__sk-icon { width: 40px; height: 40px; border-radius: 10px; }
/* Phones: most cards there wrap the name over two lines and the meta over two (the first row of the catalog,
   Dota and knives: 365.5px at 390), so the skeleton reserves both; the price line is the real 16px × 1.1 line
   box (the 22px bar made the foot 4.4px taller than a card's). */
@container pcard (max-width: 236px) {
  .pcard__sk-media { inset: 52px 12px calc(10px + var(--pc-worn-band)); }
  .pcard__sk-worn { width: 40px; height: 21px; }
  .pcard__sk-name { height: calc(2em * 1.3 + 1px + var(--fs-xs) * 1.3); font-size: var(--fs-sm); }
  .pcard__sk-meta { height: calc(2em * 1.35 + 2px); align-content: space-around; }
  .pcard__sk-price { width: 70%; height: calc(var(--fs-md) * 1.1); }
  .pcard--skeleton .pcard__actions { width: 100%; }
  .pcard__sk-btn { flex: 1 1 auto; width: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .pcard:hover,
  .pcard:hover .pcard__img { transform: none; }
  .pcard--art:hover .pcard__img { transform: scale(1.06); }
}

/* ==========================================================================
   Quick view dialog
   ========================================================================== */
.qv-dialog .dialog__title { font-size: var(--fs-lg); }
/* Image-led two columns: the image and its honesty note (no 3D model) on the left, facts, price and
   actions on the right — both columns end at about the same height. Phones: image, facts, notes. */
.qv {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  grid-template-areas: 'media info' 'notes info';
  gap: 16px 24px;
  align-items: start;
}
.qv__media {
  grid-area: media;
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background:
    radial-gradient(70% 78% at 50% 44%, rgba(214, 228, 255, .78) 0%, rgba(232, 240, 255, .4) 52%, rgba(255, 255, 255, 0) 82%),
    linear-gradient(180deg, #F2F6FE 0%, #FFFFFF 100%);
}
/* sized by the frame, not by its own aspect: the whole item stays visible at every frame ratio */
.qv__img { position: absolute; inset: 0; width: 100%; height: 100%; padding: 6%; object-fit: contain; }
/* the same rarity hairline as on the cards and in the home purchase feed */
.qv__media::after {
  content: '';
  position: absolute;
  inset: auto 0 0;
  height: 3px;
  background: var(--rarity, transparent);
}
.qv__media--art { background: #1E2129; }
.qv__media--art .qv__img { padding: 0; object-fit: cover; transform: scale(1.04); }
.qv.is-unavailable .qv__img { opacity: .55; filter: grayscale(.5); }
.qv__info { grid-area: info; display: grid; gap: 14px; min-width: 0; }
.qv__notes { grid-area: notes; display: grid; gap: 10px; min-width: 0; }
.qv__sub { display: block; margin-top: 2px; font-size: var(--fs-xs); font-weight: 400; line-height: 1.35; color: var(--ink-3); }
.qv__badges { display: flex; flex-wrap: wrap; gap: 6px; }
.qv__badges:empty { display: none; }
.qv__specs { margin: 0; }
.qv__specs dd { overflow-wrap: anywhere; }
.qv__price { display: flex; align-items: baseline; gap: 6px; margin: 0; color: var(--ink); }
.qv__price .t-price { font-size: var(--fs-2xl); }
.qv__price--none { font-size: var(--fs-lg); font-weight: 600; color: var(--ink-3); }
.qv__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.qv__more { margin-left: 4px; }
.qv__note { margin: 0; }
@media (max-width: 767.98px) {
  .qv { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; grid-template-areas: 'media' 'info' 'notes'; gap: 16px; }
  .qv__media { aspect-ratio: 16 / 10; }
  .qv__actions .btn { flex: 1 1 auto; }
}

/* ==========================================================================
   Filters as a sheet (< 1100px)
   ========================================================================== */
/* The dialog is the container: no island chrome inside it. Its title takes the island header's treatment
   (catalog.js fills it with the same markup) and the same divider; the sections keep their compact rhythm. */
.catalog-sheet .dialog__header {
  align-items: center;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--fp-head-line);
  background: var(--fp-head-bg);
}
.catalog-sheet .dialog__title { padding-top: 0; }
/* 4px: the body scrolls (overflow clips at its padding edge), so the first heading's 4px focus ring needs room */
.catalog-sheet .dialog__body { padding-top: 4px; }
.catalog-sheet .fpanel { --fp-x: 0px; }
.catalog-sheet .fpanel__footer { display: none; }
/* the dialog's own title already is the «Фильтры» heading: drop the panel's (desktop-island) one */
.catalog-sheet .fpanel__head { display: none; }
.catalog-sheet .dialog__footer .btn--primary { flex: 1 1 auto; }
/* the sheet's «Сбросить» reads like the island's: quiet (white, hairline, grey label) while nothing is selected */
.catalog-sheet .dialog__footer .btn--secondary:disabled { --btn-bg: var(--surface); --btn-bd: var(--line); --btn-fg: #8C9099; }
@media (max-width: 767.98px) {
  .catalog-sheet {
    width: 100vw;
    max-width: 100vw;
    max-height: 88dvh;
    margin: auto 0 0;
    border-radius: 20px 20px 0 0;
  }
  .catalog-sheet[open] { animation: catalog-sheet-in var(--dur-rail) var(--ease-out); }
  .catalog-sheet.is-closing { animation: catalog-sheet-out 160ms var(--ease-in-out) forwards; }
}
@keyframes catalog-sheet-in { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes catalog-sheet-out { to { transform: translateY(16px); opacity: 0; } }

/* ==========================================================================
   Responsive
   ========================================================================== */
/* desktop: reference spacing (≈23px between the game pair and search) */
@media (min-width: 1100px) {
  .catalog__games { margin-right: 11px; }
}

@media (max-width: 1099.98px) {
  .catalog__layout { grid-template-columns: minmax(0, 1fr); }
  .catalog__filters { display: none; }
  .catalog__controls { flex-wrap: wrap; }
  .catalog__search { flex: 1 1 240px; }
  .catalog__sort { flex: 0 1 230px; min-width: 180px; }
  .catalog__filters-btn { min-width: 0; padding: 0 18px; }
}

@media (max-width: 899.98px) {
  .catalog__title { font-size: clamp(2.8rem, 0.4rem + 7.6vw, 4.6rem); }
  .catalog__search { flex-basis: calc(100% - 152px); }
  .catalog__sort { flex: 1 1 200px; }
  .catalog__word { font-size: clamp(3rem, 0.4rem + 6vw, 4.6rem); }
  .catalog__word--dota2 { font-size: clamp(2.1rem, 0.3rem + 3.8vw, 3.2rem); }
  .catalog__word--all { font-size: clamp(2.6rem, 0.5rem + 5vw, 3.6rem); }
  .catalog__word-wrap { right: 24px; }
}

@media (max-width: 767.98px) {
  .catalog__title { font-size: clamp(2.6rem, 1.2rem + 7.2vw, 3.6rem); white-space: normal; }
  /* phones: the backdrop sits behind the crumbs row; the word stays clear of the H1 */
  .catalog__backdrop { left: 30%; top: -12px; }
  .catalog__word-wrap { top: 10px; right: 16px; bottom: auto; height: 56px; }
  .catalog__word { font-size: 2.6rem; -webkit-text-stroke-width: 1.2px; }
  .catalog__word--dota2 { font-size: 1.8rem; }
  .catalog__word--all { font-size: 2.3rem; }
  .catalog__title { margin-top: 6px; }
  .catalog__controls { gap: 8px; margin: 0; }
  .catalog__games { height: 48px; }
  .catalog__game { width: 52px; }
  .catalog__search { flex: 1 1 calc(100% - 116px); }
  .catalog__input { min-height: 48px; font-size: var(--fs-md); }
  .catalog__sort { flex: 1 1 0; min-width: 0; }
  .catalog__sort .select,
  .catalog__filters-btn { min-height: 48px; }
  /* room for «Рекомендуемые» at 375px */
  .catalog__sort > svg { left: 12px; }
  .catalog__sort .select { padding-left: 40px; padding-right: 34px; background-position: right 10px center; }
  .catalog__filters-btn { min-width: 0; padding: 0 16px; }
  .catalog__cats { margin-top: 12px; }
  .catalog__cats-row .chip { padding: 0 16px; }
  .catalog__layout { margin-top: 16px; }
  .catalog__summary { gap: 8px 12px; }
}

/* Small phones: «Фильтры» becomes icon (+ count) — the button keeps its aria-label («Фильтры, выбрано
   условий: 3») — so the sort select keeps room for its longest label («Сначала меньший float»). */
@media (max-width: 419.98px) {
  .catalog__filters-btn { gap: 6px; padding: 0 14px; }
  .catalog__filters-btn > span:not(.catalog__filters-count) {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@media (max-width: 559.98px) {
  .catalog__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
}
@media (max-width: 339.98px) {
  .catalog__grid { grid-template-columns: minmax(0, 1fr); }
}

/* «Время доставки» pictograms: ⚡ instant (green) · clock = within 12 hours (blue) — as on cards and pages */
.fpanel__radio-icon { display: inline-grid; place-items: center; flex: none; margin-left: -4px; }   /* after the word (gap 10px − 4) */
.fpanel__radio-icon--instant { color: var(--success); }
.fpanel__radio-icon--12h { color: var(--accent-ink); }

/* Catalog head: the official game mark (components/game-logos.js) instead of a typed «CS2» / «DOTA 2» —
   the same marks as in the game switch, upright (never slanted), in their brand colours. */
.catalog__mark { display: block; height: auto; flex: none; }
.catalog__mark.game-logo--cs2 { width: clamp(180px, 1rem + 16vw, 380px); color: #E0A100; }
.catalog__mark.game-logo--dota2 { width: clamp(96px, 0.5rem + 8.4vw, 190px); }
@media (max-width: 767.98px) {
  .catalog__mark.game-logo--cs2 { width: 112px; }
  .catalog__mark.game-logo--dota2 { width: 56px; }
}

/* Category pills with an official item picture; type menu = one column + search + wheel scrolling (user request) */
.catalog__cat-img { flex: none; width: var(--cat-pic-w, 40px); height: var(--cat-pic-h, 30px); object-fit: contain; }
.cat-pop {
  display: flex;
  flex-direction: column;
  /* as wide as its longest row (user: no empty space on the right) */
  width: max-content;
  min-width: 240px;
  max-width: min(440px, 100%);
  overflow: hidden;
}
.cat-pop__label { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cat-pop__list {
  flex: 1 1 auto;
  min-height: 0;
  max-height: 400px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;                               /* a slim bar, not 15px of empty-looking margin */
  scrollbar-color: var(--line-strong) transparent;
  grid-template-columns: 1fr;
  padding-right: 2px;
}
.cat-pop__list > li[hidden] { display: none; }
.cat-pop__list.has-more {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 36px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 36px), transparent);
}
/* the picture sits well inside the row's hover island (knife tips reach the image corners) */
.cat-pop__list { row-gap: 2px; }
.cat-pop__item { min-height: 56px; gap: 12px; }
/* a block box (not grid): in a grid cell the image's height:100% does not resolve and it grew to its own 4:3 ratio */
.cat-pop__thumb { display: block; flex: none; width: 64px; height: 40px; overflow: hidden; }
.cat-pop__thumb img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* «Выбрать все»: the first row, right above the types; stays in place while the list scrolls */
.cat-pop__item--all { flex: none; }
.cat-pop__item--all .cat-pop__label { font-weight: 600; }
.cat-pop__item--all + .cat-pop__list { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--line); }
.cat-pop__item--all[hidden] + .cat-pop__list { margin-top: 0; padding-top: 0; border-top: 0; }   /* hidden while searching */
/* its own row geometry (user): the icon starts where the pictures' drawings start (a 4:3 render sits ≈5px inside
   the 64px cell), the label follows it at the same 12px gap as picture → name — not aligned under the names */
.cat-pop__item--all .cat-pop__thumb { display: grid; place-items: center; width: 22px; height: 40px; margin-left: 5px; }
.cat-pop__item--all .cat-pop__thumb svg { width: 22px; height: 22px; color: var(--ink-3); }
.cat-pop__dash { display: none; width: 9px; height: 2px; border-radius: 1px; background: currentColor; }
.cat-pop__check:indeterminate + .cat-pop__box { border-color: var(--accent-strong); background: var(--accent-strong); color: #FFFFFF; }
.cat-pop__check:indeterminate + .cat-pop__box svg { display: none; }
.cat-pop__check:indeterminate + .cat-pop__box .cat-pop__dash { display: block; }
@media (max-width: 767.98px) {
  .cat-pop { width: auto; max-width: none; }
  .cat-pop__list { grid-template-columns: 1fr; max-height: 55vh; }
}

/* ==========================================================================
   Search suggestions (catalog/suggest.js): a light island under the search field, like the type menus —
   picture · full name (the typed part in bold) + exterior chip · «от» price and ×stock on the right.
   Placed by the script inside the controls row (top/left/width/max-height); never moves the layout.
   ========================================================================== */
.catalog__controls { position: relative; }
.qs {
  position: absolute;
  z-index: 45;
  top: 0;
  left: 0;
  box-sizing: border-box;
  max-height: min(70vh, 568px);
  margin: 0;
  padding: 6px;
  list-style: none;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
  border: 1px solid rgba(25, 27, 32, .08);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: 0 22px 48px -16px rgba(25, 27, 32, .28), 0 2px 6px rgba(25, 27, 32, .06);
  transform-origin: 50% 0;
  animation: qs-in 200ms cubic-bezier(.16, 1, .3, 1);
}
.qs[hidden] { display: none; }
@keyframes qs-in { from { opacity: 0; transform: translateY(-6px) scale(.99); } }
.qs__opt {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  min-height: 60px;
  padding: 6px 12px 6px 8px;
  border-radius: 10px;
  color: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 120ms var(--ease-out);
}
.qs__opt + .qs__opt { margin-top: 2px; }
/* the highlighted row: the pointer's or the arrow keys' (aria-selected; one at a time) */
.qs__opt.is-active { background: var(--surface-sunken); }
.qs__thumb { display: grid; place-items: center; width: 56px; height: 42px; overflow: hidden; color: var(--ink-3); }
.qs__thumb img { display: block; width: 100%; height: 100%; object-fit: contain; }
.qs__thumb--art img { object-fit: cover; border-radius: 6px; }
.qs__body { display: grid; gap: 4px; min-width: 0; }
.qs__name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  font-size: var(--fs-base);
  font-weight: 400;
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.qs__hit { padding: 0; background: none; color: inherit; font-weight: 700; }
/* The chip and the hint share a line while both fit; otherwise the hint (the English name that holds the typed
   word, the only text explaining the match) drops under the chip and keeps the whole width, up to two lines —
   a long Russian exterior («После полевых испытаний») never squeezes it to «★ …» (final review #10). */
.qs__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 3px 8px; min-width: 0; font-size: var(--fs-xs); line-height: 1.35; color: var(--ink-3); }
.qs__chip {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  color: var(--ink-2);
  font-weight: 500;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.qs__opt.is-active .qs__chip { background: var(--surface); }
.qs__sub {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  overflow-wrap: anywhere;
}
.qs__sub .qs__hit { color: var(--ink-2); font-weight: 600; }
.qs__price { display: grid; justify-items: end; gap: 3px; text-align: right; white-space: nowrap; }
.qs__amount { font-size: var(--fs-base); font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.qs__stock { font-size: var(--fs-xs); color: var(--ink-3); }
.qs__none { font-size: var(--fs-sm); color: var(--ink-3); }
/* «Показать все результаты (N)»: the last row, held at the bottom while the list scrolls */
.qs__all {
  position: sticky;
  bottom: -6px;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  margin: 6px -6px -6px;
  padding: 0 18px;
  border-top: 1px solid var(--line);
  border-radius: 0 0 13px 13px;
  background: var(--surface);
  color: var(--accent-ink);
  font-size: var(--fs-sm);
  font-weight: 600;
}
.qs__all > span { flex: 1 1 auto; min-width: 0; }
.qs__all svg { flex: none; }
.qs__all.is-active { background: var(--accent-tint); }
@media (max-width: 559.98px) {
  .qs { border-radius: 12px; }
  .qs__opt { grid-template-columns: 48px minmax(0, 1fr) auto; gap: 10px; min-height: 58px; padding: 6px 10px 6px 6px; }
  .qs__thumb { width: 48px; height: 36px; }
  .qs__amount { font-size: var(--fs-sm); }
  .qs__all { border-radius: 0 0 11px 11px; }
}
@media (prefers-reduced-motion: reduce) {
  .qs { animation: none; }
  .qs__opt { transition: none; }
}
