/* ============================================================================
 * oFilter — storefront stylesheet (self-contained, theme-neutral)
 * ----------------------------------------------------------------------------
 * ZERO dependency on theme variables/selectors. Every color/size/radius is a
 * module custom property (--of-*) with a HARD fallback on every use, so the
 * file renders correctly even on themes that strip :root custom props.
 * All selectors are namespaced .ofilter* / #ofilter*.
 * Includes the COMPLETE ionRangeSlider 2.1.4 skin (pure CSS handles — no sprite
 * images, no external URLs, no @import, no web fonts).
 * ========================================================================== */

/* --- Design tokens (declared on the sidebar root AND the standalone grid so
 * both trees resolve the same values; every consumer still carries a fallback) */
.ofilter,
.ofilter-grid,
.ofilter-drawer,
.ofilter-drawer-open,
/* feature: seo — «Популярные подборки» renders into content_top, outside #ofilter, so it inherits
   nothing from the filter root and needs its own copy of the palette. */
.ofilter-collections {
    --of-accent: #3b6ef6;
    --of-accent-dark: #2b57c9;
    --of-text: #222;
    --of-muted: #777;
    --of-border: #ddd;
    --of-border-light: #eee;
    --of-bg: #fff;
    --of-bg-soft: #fafafa;
    --of-radius: 6px;
    --of-danger: #d9534f;
}

/* ============================ Sidebar shell ============================== */

.ofilter {
    position: relative;
    box-sizing: border-box;
    margin-bottom: 30px;
    color: var(--of-text, #222);
    font-size: 14px;
    line-height: 1.4;
}
.ofilter *,
.ofilter *::before,
.ofilter *::after { box-sizing: border-box; }

/* z-index keeps the pinned filter ABOVE later left-column modules it scrolls over — some (e.g. a
   Swiper "recommended" carousel) set position:relative;z-index:1, which would otherwise paint on top
   of the sticky filter. Kept modest so a sticky theme header (usually z-index >=100) still wins. */
.ofilter-sticky { position: -webkit-sticky; position: sticky; top: 10px; z-index: 20; }
/* A `top`-anchored sticky block only travels while it is SHORTER than both the viewport and its
   column. A real catalogue filter is neither: measured on a 2500-product category it was 2622px
   tall in a 2652px column with a 720px viewport — 30px of travel out of a 3000px page, i.e. the
   setting looked simply broken. Capping the block to the viewport and letting it scroll inside
   itself is what marketplaces do, and it restores the effect without touching the markup.
   `overflow` on the ELEMENT is harmless (only an ANCESTOR's overflow disables sticky).
   No-op for short filters: max-height never binds, so no scrollbar and no visual change.
   Desktop only — below 991px the column stacks above the grid and pinning it would eat the screen;
   the horizontal top bar is excluded too, it pins as a bar and must not grow a scrollbar. */
@media (min-width: 992px) {
    .ofilter-sticky:not(.ofilter-layout-horizontal) {
        max-height: calc(100vh - 20px);
        overflow-y: auto;
        overscroll-behavior: contain;   /* reaching the end must not start scrolling the page */
    }
    /* The pin itself rides the COLUMN (class added by ofilter.js :: markStickyColumn), because the
       block's containing block is that column and a float column is only as tall as its content —
       nothing to travel. The column's parent .row spans the page, so here the pin actually moves.
       align-self keeps it from stretching if the theme's row is a flex container. */
    .ofilter-sticky-col {
        position: -webkit-sticky;
        position: sticky;
        top: 10px;
        z-index: 20;
        -ms-flex-item-align: start;
        align-self: flex-start;
    }
}

.ofilter-form { margin: 0; }

/* feature: block-order — when the merchant reorders the sidebar blocks (admin drag-and-drop), the
   form becomes a flex column so each block honours its inline `order`. Sidebar layout only (the
   horizontal top-bar has its own flex order); a blank order never adds .ofilter-reordered, so the
   default stays byte-identical. Hidden mirrors (type=hidden) are display:none -> ignored by flex. */
.ofilter-reordered:not(.ofilter-layout-horizontal) .ofilter-form {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
}

/* ---- Heading (default skin): title + optional header-reset on one row. Each skin overrides
   this at higher specificity (.ofilter-skin-X .ofilter-heading), so skins stay byte-identical. */
.ofilter-heading {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 10px;
    padding: 0 0 8px;
    border-bottom: 1px solid var(--of-border-light, #eee);
}
.ofilter-heading-t { flex: 1 1 auto; font-size: 16px; font-weight: 600; color: var(--of-text, #222); }
.ofilter-heading .ofilter-reset-top { flex: 0 0 auto; font-size: 13px; color: var(--of-accent, #3b6ef6); text-decoration: none; }
.ofilter-heading .ofilter-reset-top:hover,
.ofilter-heading .ofilter-reset-top:focus { text-decoration: underline; }

/* ---- Facet group ---- */
.ofilter-group {
    border-bottom: 1px solid var(--of-border-light, #eee);
    padding: 0;
}
.ofilter-group:last-child { border-bottom: none; }
/* The :last-child reset above is effectively dead in this template: the form's real last child is a
   hidden sort/order/limit input, and flex `order` reordering (.ofilter-reordered) also detaches the
   visually-last group from the DOM-last one. ofilter.js therefore tags the true visually-last flex
   group with .ofilter-glast (skipping the actions row when it is present) and this drops its trailing
   separator so it never doubles with / sits under the widget's own bottom border. Covers every skin
   (incl. card skins' .ofilter-rrcluster) via !important; absent when JS is off -> no visual change. */
.ofilter-glast,
/* ...and the group BODY with it: the horizontal top bar draws the separator on the body, not on the
   group, so tagging the group alone left a hanging 1px line under the last dropdown when the footer
   has no buttons at all. */
.ofilter-glast .ofilter-group-body { border-bottom: 0 !important; }

.ofilter-group-title {
    position: relative;
    display: block;
    margin: 0;
    padding: 10px 26px 10px 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--of-text, #222);
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}
/* CSS chevron — points down when open, right when collapsed */
.ofilter-group-title::after {
    content: "";
    position: absolute;
    top: 50%;
    right: 6px;
    width: 8px;
    height: 8px;
    margin-top: -6px;
    border-right: 2px solid var(--of-muted, #777);
    border-bottom: 2px solid var(--of-muted, #777);
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
    transition: transform .15s ease;
}
.ofilter-group.ofilter-collapsed .ofilter-group-title::after {
    margin-top: -4px;
    -webkit-transform: rotate(-45deg);
    transform: rotate(-45deg);
}
.ofilter-group.ofilter-collapsed .ofilter-group-body { display: none; }

.ofilter-group-body { padding: 6px 0 12px; }

/* Scroll only real value lists (checkbox / radio / image); never sliders/price */
.ofilter-group[data-type="checkbox"] > .ofilter-group-body,
.ofilter-group[data-type="radio"]    > .ofilter-group-body,
.ofilter-group[data-type="image"]    > .ofilter-group-body {
    max-height: 260px;
    overflow-x: hidden;
    overflow-y: auto;
}

/* Group that was NOT recounted (JS adds .ofilter-group-off) — subtle hint */
.ofilter-group.ofilter-group-off { opacity: .85; }

/* ---- Values ---- */
.ofilter-value {
    display: block;
    margin: 0;
    padding: 3px 0;
}
.ofilter-value > label {
    display: flex;
    align-items: flex-start;
    gap: 7px;
    margin: 0;
    font-weight: 400;
    cursor: pointer;
}
.ofilter-value input[type="checkbox"],
.ofilter-value input[type="radio"] {
    margin: 2px 0 0;
    flex: 0 0 auto;
    cursor: pointer;
    accent-color: var(--of-accent, #3b6ef6);
}
.ofilter-name {
    flex: 1 1 auto;
    color: var(--of-text, #222);
    word-break: break-word;
}
.ofilter-count {
    flex: 0 0 auto;
    color: var(--of-muted, #777);
    font-size: 12px;
    line-height: 1.5;
}

/* feature: lazy-counts — the counts were deferred to a follow-up request and the badges still show
   the previous state's numbers; dim them until the real ones land (JS toggles the root class). */
.ofilter-counts-pending .ofilter-count,
.ofilter-counts-pending [data-of-stock-count],
.ofilter-counts-pending [data-of-reviews-count],
.ofilter-counts-pending [data-of-new-count],
.ofilter-counts-pending [data-of-discount-count],
.ofilter-counts-pending [data-of-rating-count],
.ofilter-counts-pending [data-of-photo-count] {
    opacity: .35;
    transition: opacity .15s ease;
}

/* Zero live-count value: dimmed (JS toggles .ofilter-off) */
.ofilter-value.ofilter-off { opacity: .45; }
.ofilter-value.ofilter-off input:checked ~ .ofilter-name { opacity: 1; }

/* =====================================================================
   feature: infinite — "show more" control + the auto-load sentinel
   ===================================================================== */
.ofilter-more-wrap { text-align: center; margin: 18px 0 6px; }
.ofilter-more-btn { min-width: 220px; min-height: 44px; }
.ofilter-more-btn[disabled] { opacity: .6; cursor: default; }
/* The sentinel is a zero-height probe the observer watches; it must occupy layout (so it can
   intersect) but must never take space of its own. */
.ofilter-sentinel { height: 1px; margin: 0; padding: 0; }

/* feature: swatch — auto colour chip derived from the value text.
   The inner border is a translucent inset shadow rather than a solid border so it reads on both a
   white chip (where a plain border is the only thing making it visible) and a black one (where a
   solid border would look like a frame). */
/* The auto colour chip is presented exactly like an uploaded image swatch: same box, same checked
   state, and the row's checkbox is hidden because the chip itself is the control. --of-sw-size is
   the merchant's "Размер плитки" setting (inline on the root, unset by default). */
.ofilter-sw {
    display: inline-block;
    flex: 0 0 auto;
    width: var(--of-sw-size, 30px);
    height: var(--of-sw-size, 30px);
    margin-right: 7px;
    border: 1px solid var(--of-border, #ddd);
    border-radius: 3px;
    vertical-align: middle;
    /* the chip colour arrives as an inline `background`, which paints over any background set here;
       an inset hairline keeps a white/very light chip readable against a white sidebar. */
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .06);
}
/* checked: the accent frame + ring, identical to .ofilter-img so both swatch kinds read the same */
.ofilter-value input:checked + .ofilter-sw,
.ofilter-value input:checked ~ .ofilter-sw {
    border-color: var(--of-accent, #3b6ef6);
    box-shadow: 0 0 0 1px var(--of-accent, #3b6ef6);
}
/* the checkbox is redundant once the chip shows the state - hide it VISUALLY but keep it focusable
   and submittable (display:none would drop the facet out of the keyboard order entirely). */
.ofilter-value-sw > label {
    align-items: center; /* inert in the block-label skins, centres the taller chip in the flex ones */
}
.ofilter-value-sw > label > input[type="checkbox"],
.ofilter-value-sw > label > input[type="radio"] {
    position: absolute;
    /* MUST be reset. Skins nudge the checkbox by a pixel with `position:relative; top:-1px`, and
       `top` survives when this rule flips `position` to absolute — where it stops meaning "nudge"
       and starts meaning "offset from the nearest positioned ancestor", i.e. the sidebar COLUMN.
       The box then sits at the column's top-left, and clicking a chip scrolls the page up to it
       (the label moves focus to the input, and the browser scrolls focus into view).
       `auto` puts it back at its static position, next to its own chip. */
    top: auto;
    left: auto;
    opacity: 0;
    width: 0;
    height: 0;
    margin: 0;
    pointer-events: none;
}
.ofilter-value-sw input:focus-visible ~ .ofilter-sw {
    outline: 2px solid var(--of-accent, #3b6ef6);
    outline-offset: 2px;
}

/* Image swatch facet. --of-sw-size is the merchant's "Размер плитки" setting, emitted inline on the
   storefront roots ONLY when set, so an untouched store keeps the 30px default byte-identically. */
.ofilter-img {
    display: inline-block;
    width: var(--of-sw-size, 30px);
    height: var(--of-sw-size, 30px);
    object-fit: cover;
    border: 1px solid var(--of-border, #ddd);
    border-radius: 3px;
    padding: 1px;
    background: var(--of-bg, #fff);
    flex: 0 0 auto;
}
.ofilter-value input:checked + .ofilter-img,
.ofilter-value input:checked ~ .ofilter-img {
    border-color: var(--of-accent, #3b6ef6);
    box-shadow: 0 0 0 1px var(--of-accent, #3b6ef6);
}
/* image-swatch row: centre the checkbox + thumbnail + name. The base value label is
   align-items:flex-start (right for a one-line text value), which top-aligns a tall image
   thumbnail against the small checkbox and the label — visibly off. Centre it for image type. */
.ofilter-value-image > label {
    align-items: center;
}
.ofilter-value-image input[type="checkbox"],
.ofilter-value-image input[type="radio"] {
    margin-top: 0;
}

/* Select facet */
.ofilter-select {
    display: block;
    width: 100%;
    height: 34px;
    padding: 6px 8px;
    color: var(--of-text, #222);
    background: var(--of-bg, #fff);
    border: 1px solid var(--of-border, #ddd);
    border-radius: var(--of-radius, 6px);
    font-size: 14px;
    cursor: pointer;
}
.ofilter-select:focus {
    outline: none;
    border-color: var(--of-accent, #3b6ef6);
}

/* ---- Price group ---- */
.ofilter-price .ofilter-group-body { overflow: visible; }
.ofilter-slider { padding: 4px 8px 0; }

.ofilter-price-inputs {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
}
.ofilter-price-from,
.ofilter-price-to,
.ofilter-nrange-from,
.ofilter-nrange-to {
    flex: 1 1 0;
    width: 1%;
    min-width: 0;
    height: 32px;
    padding: 4px 6px;
    color: var(--of-text, #222);
    background: var(--of-bg, #fff);
    border: 1px solid var(--of-border, #ddd);
    border-radius: var(--of-radius, 6px);
    font-size: 13px;
    text-align: center;
    -moz-appearance: textfield;
}
.ofilter-price-from::-webkit-outer-spin-button,
.ofilter-price-from::-webkit-inner-spin-button,
.ofilter-price-to::-webkit-outer-spin-button,
.ofilter-price-to::-webkit-inner-spin-button,
.ofilter-nrange-from::-webkit-outer-spin-button,
.ofilter-nrange-from::-webkit-inner-spin-button,
.ofilter-nrange-to::-webkit-outer-spin-button,
.ofilter-nrange-to::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
.ofilter-price-from:focus,
.ofilter-price-to:focus,
.ofilter-nrange-from:focus,
.ofilter-nrange-to:focus {
    outline: none;
    border-color: var(--of-accent, #3b6ef6);
}
.ofilter-price-dash {
    flex: 0 0 auto;
    color: var(--of-muted, #777);
}

/* Facet (attribute/option) slider */
.ofilter-slider-wrap { padding: 4px 8px 0; }

/* feature: field-facets — weight/dimension numeric sliders. The wrap reuses the price-slider
   look; the dimensions group stacks rows, each with a small sub-label above its slider. */
.ofilter-nslider-group .ofilter-group-body { overflow: visible; }
.ofilter-nslider-wrap { padding: 4px 8px 0; }
.ofilter-nslider-row { margin-bottom: 14px; }
.ofilter-nslider-row:last-child { margin-bottom: 0; }
.ofilter-nslider-sublabel {
    padding: 0 8px;
    font-size: 12px;
    color: var(--of-muted, #777);
}

/* ---- feature: histograms — bar strips behind the price + facet sliders ----
   Bars sit BEHIND the ionRangeSlider track via negative margin; pointer-events:none
   so they never steal a drag. Scoped to .ofilter. Static heights; only .ofilter-hb-on
   (the selected band) is emphasized. */
.ofilter .ofilter-price-hist,
.ofilter .ofilter-attr-hist {
    height: 36px;
    display: flex;
    align-items: flex-end;
    gap: 2px;
    margin: 0 8px -31px;
    padding: 0 1px;
    position: relative;
    z-index: 0;
    pointer-events: none;
}
.ofilter .ofilter-price-hist span,
.ofilter .ofilter-attr-hist span {
    flex: 1 1 0;
    min-height: 2px;
    background: var(--of-hist, #d7dbdf);
    border-radius: 2px 2px 0 0;
    transition: background .12s;
}
.ofilter .ofilter-price-hist span.ofilter-hb-on,
.ofilter .ofilter-attr-hist span.ofilter-hb-on {
    /* 8-digit hex = the same grey at ~42% alpha, so the in-range bars read as a tint behind the
       track rather than a solid block. Only the FALLBACK changes: --of-hist-on is defined for the
       dark/auto themes only, where the band keeps tracking the skin accent. */
    background: var(--of-hist-on, #7f8a946b);
}
/* keep the ionRangeSlider track/handles above the bars so they stay draggable.
   CAUTION: ionRangeSlider nests a SECOND `.irs` inside its wrapper (wrapper > .irs > .irs-line),
   and this selector lifts that inner one too — which put the grey `.irs-line` above its sibling
   `.irs-bar` and hid the selected range on every slider inside these two wraps (price + attribute
   sliders). The field-facet sliders live in .ofilter-nslider-wrap, were never lifted, and kept a
   visible bar — which is exactly how the discrepancy showed up. The stack is restored below. */
.ofilter .ofilter-slider-wrap .irs,
.ofilter .ofilter-price .irs { position: relative; z-index: 1; }
/* line (inside the lifted .irs, z 1) < bar < handles. Applied to every slider, lifted or not, so
   one stacking order holds everywhere. The handles' z-index lives on their own rule further down,
   NOT here — an equal-specificity duplicate placed above it would simply lose. */
.ofilter .irs-bar,
.ofilter .irs-bar-edge { z-index: 2; }

/* ---- Instock ---- */
.ofilter-instock .ofilter-group-body { padding-top: 10px; }

/* ---- Review facets (rating stars + «с отзывами» / «с фото») ----
 * Self-contained: pure-CSS ★ glyph, NO FontAwesome dependency. The rating input
 * is type=text hidden via display:none (NEVER type=hidden — auto-apply needs it). */
.ofilter-rating-title { cursor: default; }
/* stars + count on one row (count moved out of the title so it survives when the
   revolution skin hides the title bar; default skin renders it plain, no background) */
.ofilter-rate-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ofilter-rate-input { display: none; }
.ofilter-stars-pick {
    display: inline-flex;
    align-items: center;
    line-height: 1;
    font-size: 20px;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}
.ofilter-stars-pick i {
    font-style: normal;
    color: var(--of-border, #ddd);
    padding: 0 1px;
    transition: color .12s ease;
}
.ofilter-stars-pick i::before { content: "\2605"; } /* ★ */
.ofilter-stars-pick i.ofilter-star-on,
.ofilter-stars-pick i.ofilter-star-hover { color: #f5a623; }
/* The rating row opens the cluster, so its body carries the generic group-body top inset (6px)
   PLUS one value-row rhythm (3px) — that puts the stars exactly where an attribute group's first
   value sits under its title bar. Bottom is the row rhythm alone; the cluster owns the block's
   bottom inset. */
.ofilter-rating .ofilter-group-body { padding: 9px 0 3px; }
/* in-stock / «с отзывами» / «с фото» rows (label directly in the group). The instock label
   MUST be listed here too, else it falls back to Bootstrap `label{font-weight:700;cursor:default}`
   and looks bold with a default cursor unlike the other facets. */
.ofilter-instock > label,
.ofilter-reviews > label,
.ofilter-new > label,
.ofilter-discount > label,
.ofilter-photo > label {
    display: flex;
    align-items: flex-start;
    gap: 7px;
    margin: 0;
    /* match the attribute/option value row rhythm (.ofilter-value padding 3px 0) so the default-skin
       in-stock/reviews/new/discount rows are the same height as the value rows above/below them */
    padding: 3px 0;
    font-weight: 400;
    cursor: pointer;
}
.ofilter-instock input[type="checkbox"],
.ofilter-reviews input[type="checkbox"],
.ofilter-new input[type="checkbox"],
.ofilter-discount input[type="checkbox"],
.ofilter-photo input[type="checkbox"] {
    margin: 2px 0 0;
    flex: 0 0 auto;
    cursor: pointer;
    accent-color: var(--of-accent, #3b6ef6);
}

/* review/boolean cluster (rating + в наличии/с отзывами/новинки/со скидкой) = ONE block:
   no dividers between rows, a single separator below it before the next group (Производитель).
   0,3,0 specificity so it beats the per-skin .ofilter-skin-* .ofilter-group border; the card skins
   (universam/market/pills) keep their own .ofilter-rrcluster border via their higher-specificity rule. */
.ofilter .ofilter-rrcluster > .ofilter-group { border-bottom: 0; }
/* padding-bottom mirrors the generic .ofilter-group-body bottom inset (12px) so the cluster's
   internal spacing reads exactly like an attribute/option group; each skin re-states it below
   with its own body inset. */
.ofilter-rrcluster { border-bottom: 1px solid var(--of-border-light, #eee); padding-bottom: 12px; }

/* ---- Action buttons ---- */
.ofilter-apply {
    display: block;
    width: 100%;
    margin-top: 14px;
    padding: 9px 14px;
    font-size: 14px;
    font-weight: 400;
    line-height: 1.4;
    text-align: center;
    color: #fff;
    background: var(--of-accent, #3b6ef6);
    border: 1px solid var(--of-accent, #3b6ef6);
    border-radius: var(--of-radius, 6px);
    cursor: pointer;
}
.ofilter-apply:hover,
.ofilter-apply:focus {
    color: #fff;
    background: var(--of-accent-dark, #2b57c9);
    border-color: var(--of-accent-dark, #2b57c9);
}
/* In auto mode the apply button is a drawer-only CTA — hidden on desktop */
.ofilter-apply.ofilter-apply-mobile { display: none; }
/* feature: near — the floating pill beside the value IS the apply control, so the footer button is
   hidden rather than dropped: on a theme with no AJAX target the pill can never appear (it is drawn
   from a count response that never arrives), and ofilter.js un-hides these two so the visitor is
   never left with a filter that cannot be applied. */
.ofilter-apply.ofilter-apply-near { display: none; }
.ofilter-actions.ofilter-actions-near { display: none; }

/* In-flight state (toggled from mask()): dim + inert + a small leading spinner. Uses ::before so
   paintTotal's .text() relabel does not wipe it; reuses the ofilter-spin keyframes. */
.ofilter-apply-loading {
    opacity: .8;
    cursor: progress;
    pointer-events: none;
}
.ofilter-apply-loading::before {
    content: "";
    display: inline-block;
    width: 12px;
    height: 12px;
    margin-right: 7px;
    vertical-align: -1px;
    border: 2px solid rgba(255, 255, 255, .5);
    border-top-color: #fff;
    border-radius: 50%;
    -webkit-animation: ofilter-spin .7s linear infinite;
    animation: ofilter-spin .7s linear infinite;
}

.ofilter-reset {
    display: block;
    width: 100%;
    margin-top: 8px;
    padding: 7px 14px;
    font-size: 13px;
    line-height: 1.4;
    text-align: center;
    color: var(--of-muted, #777);
    background: transparent;
    border: 1px solid var(--of-border, #ddd);
    border-radius: var(--of-radius, 6px);
    cursor: pointer;
}
.ofilter-reset:hover,
.ofilter-reset:focus {
    color: var(--of-danger, #d9534f);
    border-color: var(--of-danger, #d9534f);
}

/* ============================ Chips ===================================== */

.ofilter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0 0 12px;
}
/* no active chips -> no box at all: zero BOTH margin and padding so an empty chips container adds no
   gap above the first group. `.ofilter .ofilter-chips` (0,3,0) outranks the skin rules that add chip
   padding (e.g. revolution's `.ofilter-skin-revolution .ofilter-chips`, 0,2,0), whatever their order. */
.ofilter .ofilter-chips:empty { margin: 0; padding: 0; }
@media (max-width: 991px) {
    /* In the drawer the chips sit right under the sticky header — give them air above.
       The `:empty` reset above still wins for an empty container: it is (0,3,0) against this
       rule's (0,1,0), so no chips still means no gap. */
    .ofilter-chips { padding-top: 12px; }
}

/* feature: seo — «Популярные подборки» links share this rule verbatim: the block sits next to the
   active-filter chips and must read as the same control, so size and colour have ONE source of
   truth here rather than a copy that drifts. Everything is `var(--of-*)`, and the block declares
   its own tokens (§6.34.2), so skins, the merchant's colours and the dark theme all follow. */
.ofilter-chip,
.ofilter-collections a {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    max-width: 100%;
    padding: 3px 8px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--of-text, #222);
    background: var(--of-bg-soft, #fafafa);
    border: 1px solid var(--of-border, #ddd);
    border-radius: 999px;
    cursor: pointer;
}
.ofilter-chip > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ofilter-chip-x {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
    font-size: 15px;
    line-height: 1;
    color: var(--of-muted, #777);
    border-radius: 50%;
}
.ofilter-chip-x::before { content: "\00d7"; }
.ofilter-chip:hover .ofilter-chip-x { color: var(--of-danger, #d9534f); }

.ofilter-chip.ofilter-chip-clear {
    color: var(--of-accent, #3b6ef6);
    background: transparent;
    border-color: var(--of-accent, #3b6ef6);
}
.ofilter-chip.ofilter-chip-clear:hover {
    color: #fff;
    background: var(--of-accent, #3b6ef6);
}
.ofilter-chip.ofilter-chip-clear .ofilter-chip-x { display: none; }

/* ============================ Grid mask ================================= */

#ofilter-swap { position: relative; }

.ofilter-masked { pointer-events: none; }
.ofilter-masked .ofilter-mask { pointer-events: auto; }

.ofilter-mask {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 20;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: 60px;
    background: rgba(255, 255, 255, .6);
}
.ofilter-mask::after {
    content: "";
    width: 34px;
    height: 34px;
    border: 3px solid var(--of-border, #ddd);
    border-top-color: var(--of-accent, #3b6ef6);
    border-radius: 50%;
    -webkit-animation: ofilter-spin .7s linear infinite;
    animation: ofilter-spin .7s linear infinite;
}
@-webkit-keyframes ofilter-spin { to { -webkit-transform: rotate(360deg); } }
@keyframes ofilter-spin { to { transform: rotate(360deg); } }

/* ==================== Module-mode grid (ofilter_grid.twig) ============== */

.ofilter-grid { position: relative; }

.ofilter-cards { margin-bottom: 15px; }

.ofilter-card {
    margin-bottom: 20px;
    text-align: center;
}
.ofilter-card a { text-decoration: none; color: inherit; }
.ofilter-card img {
    max-width: 100%;
    height: auto;
    margin-bottom: 8px;
}
.ofilter-card .ofilter-card-name {
    display: block;
    margin-bottom: 6px;
    font-size: 14px;
    color: var(--of-text, #222);
}
.ofilter-card .ofilter-card-price {
    display: block;
    margin-bottom: 8px;
    font-size: 15px;
    font-weight: 600;
    color: var(--of-text, #222);
}
.ofilter-price-old {
    margin-left: 6px;
    font-weight: 400;
    font-size: 13px;
    color: var(--of-muted, #777);
    text-decoration: line-through;
}
.ofilter-card .ofilter-cart {
    padding: 6px 14px;
    font-size: 13px;
    color: #fff;
    background: var(--of-accent, #3b6ef6);
    border: 1px solid var(--of-accent, #3b6ef6);
    border-radius: var(--of-radius, 6px);
    cursor: pointer;
}
.ofilter-card .ofilter-cart:hover { background: var(--of-accent-dark, #2b57c9); }

.ofilter-pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 10px;
}

/* Empty state (module mode renders it; theme mode falls back to it via JS) */
.ofilter-empty {
    padding: 40px 20px;
    text-align: center;
    color: var(--of-muted, #777);
    font-size: 15px;
}
.ofilter-empty p { margin: 0; }

/* ============================ Drawer (off-canvas) ======================= */

/* html scroll-lock while drawer open */
html.of-noscroll,
html.of-noscroll body { overflow: hidden; }

.ofilter-drawer-open {
    display: none; /* shown <992px, or always with .ofilter-drawer-always */
    position: fixed;
    right: 0;
    /* feature: mobile-icon — merchant height override, in px from the bottom. Unset resolves to the
       20% this rule always used, so the button does not move on any existing store. */
    bottom: var(--of-mbtn-bottom, 20%);
    z-index: 1000;
    padding: 11px 12px;
    font-size: 14px;
    font-weight: 600;
    color: #fff;
    background: var(--of-accent, #3b6ef6);
    border: none;
    border-radius: var(--of-radius, 6px) 0 0 var(--of-radius, 6px);
    box-shadow: 0 2px 10px rgba(0, 0, 0, .2);
    cursor: pointer;
}
/* icon-only open button: the funnel SVG replaces the "Фильтр" word (the label stays in an
   .ofilter-sr span for assistive tech). */
.ofilter-drawer-open-ico { display: block; width: var(--of-mbtn-size, 22px); height: var(--of-mbtn-size, 22px); }
/* feature: mobile-icon — the merchant's own image, sized by the same variable. object-fit keeps a
   non-square upload inside the box instead of stretching it. */
.ofilter-drawer-open-img { display: block; width: var(--of-mbtn-size, 22px); height: var(--of-mbtn-size, 22px); object-fit: contain; }
/* feature: mobile-icon — pinned to the LEFT edge instead; the rounded corners follow it across. */
.ofilter-drawer-open.ofilter-mbtn-left {
    right: auto;
    left: 0;
    border-radius: 0 var(--of-radius, 6px) var(--of-radius, 6px) 0;
}

.ofilter-drawer {
    position: fixed;
    top: 0;
    right: -100%;
    z-index: 100000;
    width: 90%;
    max-width: 380px;
    /* MOBILE VIEWPORT UNITS — the reason the drawer used to drift while scrolling.
       On a fixed element `height: 100%` resolves against the INITIAL CONTAINING BLOCK, which on a
       phone is the LARGE viewport: the page as if the browser chrome were hidden. With the address
       bar and bottom toolbar on screen the drawer is therefore taller than what the visitor can
       see, and the overflow falls behind that chrome — the header row at the top (so the × loses
       its place) and the sticky "Показать N" at the bottom. Worse, the chrome collapses and
       re-expands as you scroll, so the visible slice keeps changing and the whole panel reads as
       sliding up and down. Reported on comat.ru with exactly those two grey bands.
       `dvh` is the DYNAMIC viewport: it tracks what is actually visible right now. The plain
       `height: 100%` stays first as the fallback for browsers without dvh (pre-Safari 15.4 /
       Chrome 108), which keep today's behaviour rather than breaking. */
    height: 100%;
    height: 100dvh;
    display: flex;
    flex-direction: column;
    /* Keep a rubber-band inside the panel. `html{overflow:hidden}` (of-noscroll) does NOT hold on
       iOS Safari — touch scrolling still chains to the page once the drawer hits an end, and page
       scroll is precisely what makes the browser chrome collapse, which restarts the drift above. */
    overscroll-behavior: contain;
    background: var(--of-bg, #fff);
    box-shadow: -2px 0 16px rgba(0, 0, 0, .18);
    transition: right .3s ease;
    visibility: hidden;
}
.ofilter-drawer.open { right: 0; visibility: visible; }

.ofilter-drawer-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex: 0 0 auto;
    /* No vertical padding: the row's height comes from its tallest item — the close button, which
       is 32px here and 44px on touch. Padding on top of that made the header needlessly deep. */
    padding: 0 12px;
    font-size: 16px;
    font-weight: 400;
    border-bottom: 1px solid var(--of-border, #ddd);
    /* Opaque, and painted ABOVE the scrolling body — the same pair the CTA already has (its own
       background + position:sticky). The header was transparent and unpositioned, so during an iOS
       rubber-band the facet list overshoots its box and paints straight through it: the title and
       the × read as vanished exactly when the visitor most needs the close button. The token, not a
       literal #fff, so the dark theme and the merchant's «Внешний вид» colour still apply. */
    position: relative;
    z-index: 1;
    background: var(--of-bg, #fff);
}
.ofilter-drawer-close {
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: 22px;
    line-height: 1;
    color: var(--of-muted, #777);
    background: transparent;
    border: none;
    cursor: pointer;
}
.ofilter-drawer-close::before { content: "\00d7"; }

.ofilter-drawer-body {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* This is the element the visitor actually flicks, so the chain has to stop HERE: without it,
       reaching the top or bottom of the facet list hands the gesture to the page underneath and the
       browser chrome starts collapsing mid-scroll (see .ofilter-drawer). */
    overscroll-behavior: contain;
    padding: 0;
    /* OPAQUE, and not optional. The backdrop is `.ofilter-drawer::before` with `z-index: -1`, and the
       panel itself is `position: fixed; z-index: 100000` — so it OWNS a stacking context, and inside
       one a negative-z-index child paints after the element's own background/border. The backdrop
       therefore covers the panel's white, and every part of the panel that has no opaque child of its
       own shows `rgba(0,0,0,.4)` over the page: a grey band. Head and CTA already paint themselves;
       this scroller was the one hole, so the grey appeared wherever #ofilter did not reach and MOVED
       as the list scrolled — reported from comat.ru as "при сдвигах некрасивая штука". */
    background: var(--of-bg, #fff);
}
/* Inside the drawer the moved sidebar drops its own bottom margin */
.ofilter-drawer-body .ofilter { margin-bottom: 0; }
/* Inside the drawer the panel already owns the scrolling — drop BOTH the pin and the height cap,
   or the body would carry a second, nested scrollbar. */
.ofilter-drawer-body .ofilter-sticky { position: static; max-height: none; overflow: visible; }

.ofilter-drawer-cta {
    flex: 0 0 auto;
    padding: 12px 16px;
    border-top: 1px solid var(--of-border, #ddd);
    background: var(--of-bg, #fff);
}
.ofilter-drawer-show {
    display: block;
    width: 100%;
    padding: 11px 14px;
    font-size: 15px;
    font-weight: 600;
    color: #fff;
    background: var(--of-accent, #3b6ef6);
    border: none;
    border-radius: var(--of-radius, 6px);
    cursor: pointer;
}
.ofilter-drawer-show:hover { background: var(--of-accent-dark, #2b57c9); }

/* The open button + CTA live OUTSIDE #ofilter, so the skin's --of-accent (scoped to .ofilter-skin-X
   on the sidebar root) never cascades to them — they stayed base blue. Re-declare just the accent on
   the drawer's ofa-{skin} modifier so the mobile chrome matches the chosen skin. */
.ofilter-drawer-open.ofa-revolution, .ofilter-drawer.ofa-revolution, .ofilter-collections.ofa-revolution { --of-accent: #23a1d1; --of-accent-dark: #1b87b1; }
.ofilter-drawer-open.ofa-universam,  .ofilter-drawer.ofa-universam,  .ofilter-collections.ofa-universam  { --of-accent: #333;    --of-accent-dark: #1a1a1a; }
.ofilter-drawer-open.ofa-market,     .ofilter-drawer.ofa-market,     .ofilter-collections.ofa-market     { --of-accent: #58ae43; --of-accent-dark: #479438; }
.ofilter-drawer-open.ofa-pills,      .ofilter-drawer.ofa-pills,      .ofilter-collections.ofa-pills      { --of-accent: #222;    --of-accent-dark: #000; }

/* Backdrop */
.ofilter-drawer::before {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: -1;
    background: rgba(0, 0, 0, .4);
    opacity: 0;
    pointer-events: none;
    transition: opacity .3s ease;
}
.ofilter-drawer.open::before { opacity: 1; pointer-events: auto; }

@media (max-width: 991px) {
    .ofilter-drawer-open { display: block; }
}
/* mount_mode=drawer: show the open button at every width */
.ofilter-drawer-open.ofilter-drawer-always { display: block; }

/* ==================== feature: mobile-sheet (marketplace) ==================
 * Enhancement layer on the drawer, gated by .ofilter-sheet (ofilter_mobile_sheet).
 * Full-bleed on phones; sticky header with a centered title + reset; bold CTA.
 * DOM order stays [title][close][reset] (byte-identical drawer when off); CSS
 * `order` lays them out marketplace-style (× · title · reset). No ?v=. */
@media (max-width: 991px) {
    .ofilter-drawer.ofilter-sheet { width: 100%; max-width: 100%; }
}
.ofilter-drawer.ofilter-sheet .ofilter-drawer-head {
    position: sticky;
    top: 0;
    z-index: 2;
    justify-content: flex-start;
    gap: 2px;
    background: var(--of-bg, #fff);
    /* NOTE the negative Y: the shadow is cast UPWARD, mirroring the bottom CTA's. Flip it to
       `0 2px 12px` if the header should instead drop a shadow onto the list it pins over. */
    box-shadow: 0 -2px 12px rgba(0, 0, 0, .14);
}
/* order 2 puts the close LAST: title · reset · ×. (The markup order is title, close, reset — the
   row is arranged entirely by flex `order`, so the DOM never has to move.)
   margin-top nudges the GLYPH, not the box: the × ink sits in the upper half of its em, so a box
   centred by align-items still reads a touch low against the text beside it. */
.ofilter-drawer.ofilter-sheet .ofilter-drawer-close { order: 2; margin-top: -2px; }
/* Left, not centred: `text-align: center` centres the title inside the LEFTOVER space between the
   × and the reset link, so its position drifts with the length of the reset label — the row reads
   as three unrelated items. Left-aligned it sits at a fixed distance from the ×. */
.ofilter-drawer.ofilter-sheet .ofilter-drawer-title { order: 0; flex: 1 1 auto; text-align: left; }
.ofilter-drawer.ofilter-sheet .ofilter-drawer-reset { order: 1; }
/* One line, one line box. The three items carry three font sizes (22 / 16 / 14), so
   `align-items: center` lines up their BOXES while the text still reads a step apart. A shared
   line-height makes the line boxes identical, which is what the eye actually reads as "one row".
   Deliberately no height/min-height — the 44px touch target for the close button must survive. */
.ofilter-drawer.ofilter-sheet .ofilter-drawer-close,
.ofilter-drawer.ofilter-sheet .ofilter-drawer-title,
.ofilter-drawer.ofilter-sheet .ofilter-drawer-reset {
    line-height: 24px;
    padding-top: 0;
    padding-bottom: 0;
}
.ofilter-drawer-reset {
    padding: 4px 2px;
    font-size: 14px;
    white-space: nowrap;
    color: var(--of-accent, #3b6ef6);
    background: none;
    border: 0;
    cursor: pointer;
}
.ofilter-drawer.ofilter-sheet .ofilter-drawer-cta { box-shadow: 0 -2px 12px rgba(0, 0, 0, .14); }
.ofilter-drawer.ofilter-sheet .ofilter-drawer-show { font-weight: 600; }

/* ============================================================================
 * ionRangeSlider 2.1.4 skin — pure CSS, no sprite. Scoped under .ofilter so it
 * never leaks onto the host theme (the price slider and every facet slider live
 * inside #ofilter, which also moves into the drawer intact).
 * ========================================================================== */

.ofilter .irs {
    position: relative;
    display: block;
    height: 42px;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    font-size: 12px;
}
.ofilter .irs-with-grid { height: 62px; }

.ofilter .irs-line {
    position: relative;
    display: block;
    top: 24px;
    height: 6px;
    background: var(--of-border-light, #eee);
    border-radius: 4px;
    overflow: visible;
    outline: none !important;
}
.ofilter .irs-line-left,
.ofilter .irs-line-mid,
.ofilter .irs-line-right {
    position: absolute;
    display: block;
    top: 0;
    height: 6px;
    background: transparent;
}
.ofilter .irs-line-left  { left: 0;  width: 11%; }
.ofilter .irs-line-mid   { left: 9%; width: 82%; }
.ofilter .irs-line-right { right: 0; width: 11%; }

.ofilter .irs-bar {
    position: absolute;
    display: block;
    left: 0;
    width: 0;
    top: 24px;
    height: 6px;
    background: var(--of-accent, #3b6ef6);
    border-radius: 4px;
}
.ofilter .irs-bar-edge {
    position: absolute;
    display: block;
    left: 0;
    top: 24px;
    height: 6px;
    width: 9px;
    background: var(--of-accent, #3b6ef6);
    border-radius: 4px 0 0 4px;
}
.ofilter .irs-shadow { display: none; }

/* Handles — pure CSS circles, no image */
.ofilter .irs-slider {
    position: absolute;
    display: block;
    z-index: 3;                  /* above .irs-bar (2), which is above the track line — see §irs stack */
    top: 18px;
    width: 18px;
    height: 18px;
    background: var(--of-bg, #fff);
    border: 2px solid var(--of-accent, #3b6ef6);
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
    cursor: pointer;
    transition: box-shadow .12s ease;
}
.ofilter .irs-slider:hover,
.ofilter .irs-slider:focus {
    box-shadow: 0 0 0 4px rgba(59, 110, 246, .18), 0 1px 3px rgba(0, 0, 0, .25);
}
.ofilter .irs-slider.type_last { z-index: 2; }

/* Value tooltips (from / to / single) — accent pills with a downward caret */
.ofilter .irs-from,
.ofilter .irs-to,
.ofilter .irs-single {
    position: absolute;
    display: block;
    top: 0;
    left: 0;
    cursor: default;
    white-space: nowrap;
    padding: 1px 6px;
    font-size: 11px;
    line-height: 1.5;
    color: #fff;
    background: var(--of-accent, #3b6ef6);
    border-radius: 3px;
    text-shadow: none;
}
.ofilter .irs-from::after,
.ofilter .irs-to::after,
.ofilter .irs-single::after {
    content: "";
    position: absolute;
    display: block;
    bottom: -4px;
    left: 50%;
    width: 0;
    height: 0;
    margin-left: -4px;
    overflow: hidden;
    border: 4px solid transparent;
    border-top-color: var(--of-accent, #3b6ef6);
    border-bottom: none;
}

/* Min / max edge labels */
.ofilter .irs-min,
.ofilter .irs-max {
    position: absolute;
    display: block;
    top: 0;
    cursor: default;
    padding: 1px 4px;
    font-size: 10px;
    line-height: 1.5;
    color: var(--of-muted, #777);
    background: var(--of-bg-soft, #fafafa);
    border-radius: 3px;
    text-shadow: none;
}
.ofilter .irs-min { left: 0; }
.ofilter .irs-max { right: 0; }

/* Optional grid (opts.price_grid) */
.ofilter .irs-grid {
    position: absolute;
    display: none;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 20px;
}
.ofilter .irs-with-grid .irs-grid { display: block; }
.ofilter .irs-grid-pol {
    position: absolute;
    top: 0;
    left: 0;
    width: 1px;
    height: 8px;
    background: var(--of-border, #ddd);
}
.ofilter .irs-grid-pol.small { height: 4px; }
.ofilter .irs-grid-text {
    position: absolute;
    bottom: 0;
    left: 0;
    white-space: nowrap;
    text-align: center;
    font-size: 9px;
    line-height: 9px;
    padding: 0 3px;
    color: var(--of-muted, #777);
}

/* Interaction masks / disabled / hidden input (plugin internals) */
.ofilter .irs-disable-mask {
    position: absolute;
    display: block;
    top: 0;
    left: -1%;
    width: 102%;
    height: 100%;
    cursor: default;
    background: rgba(0, 0, 0, 0);
    z-index: 2;
}
.ofilter .irs-disabled { opacity: .5; }
.ofilter .irs-hidden-input {
    position: absolute !important;
    display: block !important;
    top: 0 !important;
    left: 0 !important;
    width: 0 !important;
    height: 0 !important;
    font-size: 0 !important;
    line-height: 0 !important;
    padding: 0 !important;
    margin: 0 !important;
    overflow: hidden !important;
    outline: none !important;
    z-index: -9999 !important;
    background: none !important;
    border-style: solid !important;
    border-color: transparent !important;
}

/* ============================ Responsive =============================== */

@media (max-width: 991px) {
    .ofilter-drawer-body .ofilter-group-title { padding-top: 12px; padding-bottom: 12px; }
    /* larger tap targets inside the drawer */
    .ofilter-drawer-body .ofilter-value { padding: 6px 0; }
}

/* ============================ Grouping (feature: grouping) ============= */
/* Sidebar "Группировать по" widget reuses the standard .ofilter-group shell. */
.ofilter-grouping .ofilter-group-value label { display: block; cursor: pointer; }

/* Module-grid section headers (grouped listing). col-sm-12 clears the 3-up cards. */
/* Section headings. Not scoped to .ofilter-grid: in theme-card mode (ofilter_group_theme_card) the
   very same heading is injected into the THEME's product row, which has no .ofilter-grid wrapper. */
.ofilter-group-head { clear: both; margin: 14px 0 6px; }
.ofilter-group-head h4 {
    margin: 0;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--of-border, #e5e5e5);
    font-weight: 600;
}
.ofilter-group-head:first-child { margin-top: 0; }

/* ============================ SEO collections (feature: seo) =========== */
/* «Популярные подборки» pill list injected server-side into the category description (survives AJAX
   grid swap). Self-contained, no theme vars required; scoped so a theme's own list styles don't leak. */
.ofilter-collections {
    margin: 0 0 18px;
    padding: 12px 14px;
    background: var(--of-bg-soft, #f7f7f7);
    border: 1px solid var(--of-border-light, #eee);
    border-radius: 6px;
}
.ofilter-collections .ofc-h {
    display: block;
    margin-bottom: 8px;
    font-weight: 600;
    color: var(--of-text, #222);
}
.ofilter-collections ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.ofilter-collections li { margin: 0; }
/* Size and colour come from the shared `.ofilter-chip` rule above — these links ARE chips, just in
   another place on the page. Only what a chip does not need is set here.
   Background is the one deliberate difference: a chip sits on the page and uses `--of-bg-soft`,
   while these sit INSIDE a `--of-bg-soft` panel, where the same grey would flatten them into it.
   Plain `--of-bg` keeps the pill readable against its own container in every skin and theme. */
.ofilter-collections a {
    background: var(--of-bg, #fff);
    text-decoration: none;
    transition: background .12s, border-color .12s, color .12s;
}
/* Hover borrows the «Сбросить всё» chip's treatment (fill with the accent), so the row still reads
   as clickable without shouting at rest. */
.ofilter-collections a:hover,
.ofilter-collections a:focus {
    color: #fff;
    background: var(--of-accent, #3b6ef6);
    border-color: var(--of-accent, #3b6ef6);
}

/* ============================================================================
 * feature: appearance — "Стиль как в демо Revolution" storefront skin.
 * ----------------------------------------------------------------------------
 * Opt-in ONLY when the #ofilter root carries .ofilter-skin-revolution
 * (ofilter_skin = 'revolution'). A faithful port of the Revolution theme filter
 * (catalog/view/theme/revolution/stylesheet/revfilter.css + revfilter.twig): a
 * bordered .panel with a sliders + refresh heading, #fafafa collapsible group
 * bars with iOS-style toggle indicators, colon-suffixed titles, bare #eee count
 * pills, and the grey outlined price slider with a square arrow handle.
 * EVERYTHING is namespaced under .ofilter-skin-revolution so the DEFAULT skin
 * stays byte-identical. Self-contained: pure-CSS handle + toggle (no sprite, no
 * FontAwesome, no external URL), hard palette (accent #23a1d1), no ?v=.
 * ========================================================================== */

/* ---- Panel shell (Bootstrap .panel.panel-default around #revfilter_box) ---- */
.ofilter-skin-revolution {
    --of-accent: #23a1d1;
    --of-accent-dark: #1b87b1;
    background: var(--of-bg, #fff);
    border: 1px solid var(--of-border, #ddd);
    border-radius: 4px;
    box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
}

/* ---- Heading (h2.zag_block.panel-heading: sliders icon + title + refresh) ---- */
.ofilter-skin-revolution .ofilter-heading {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 9px 12px;
    background-color: #f7f7f7;
    border-bottom: 1px solid var(--of-border, #ddd);
    border-radius: 4px 4px 0 0;
}
.ofilter-skin-revolution .ofilter-heading-ico {
    display: inline-flex;
    align-items: center;
    color: #555;
}
.ofilter-skin-revolution .ofilter-heading-t {
    flex: 1 1 auto;
    font-size: 14px;
    font-weight: 400;
    color: #333;
}
.ofilter-skin-revolution .ofilter-reset-top { color: var(--of-accent, #23a1d1); }
.ofilter-skin-revolution .ofilter-reset-top.ofilter-reset-ico {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    text-decoration: none;
}
.ofilter-skin-revolution .ofilter-reset-top:hover,
.ofilter-skin-revolution .ofilter-reset-top:focus { color: #dd4b39; }

/* ---- Facet group: hard divider like #revfilter_box .option_box ---- */
.ofilter-skin-revolution .ofilter-group {
    border-bottom: 1px solid var(--of-border, #ddd);
    padding: 0;
}
.ofilter-skin-revolution .ofilter-group:last-child { border-bottom: none; }

/* ---- Group title bar (.option_name): #fafafa; collapsed -> #fff ---- */
.ofilter-skin-revolution .ofilter-group-title {
    padding: 6px 46px 6px 10px;
    font-size: 14px;
    font-weight: 400;
    color: #333;
    background-color: var(--of-bg-soft, #fafafa);
}
.ofilter-skin-revolution .ofilter-group.ofilter-collapsed .ofilter-group-title { background-color: var(--of-bg, #fff); }
.ofilter-skin-revolution .ofilter-group.ofilter-collapsed .ofilter-group-title:hover { background-color: var(--of-bg-soft, #fafafa); }

/* Title colon (revfilter renders "{{ title }}:"): repurpose the base chevron ::after. */
.ofilter-skin-revolution .ofilter-group-title::after {
    content: ":";
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    border: 0;
    -webkit-transform: none;
    transform: none;
    color: #333;
}
.ofilter-skin-revolution .ofilter-group.ofilter-collapsed .ofilter-group-title::after {
    margin: 0;
    -webkit-transform: none;
    transform: none;
}

/* Collapse indicator: iOS-style toggle (revfilter fa-toggle-on/off, grey #aaa).
   Expanded = filled grey pill, knob right; collapsed = outline pill, knob left. */
.ofilter-skin-revolution .ofilter-group-title::before {
    content: "";
    position: absolute;
    top: 50%;
    right: 10px;
    margin-top: -8px;
    width: 30px;
    height: 16px;
    box-sizing: border-box;
    border-radius: 8px;
    background-color: #aaa;
    background-image: radial-gradient(circle at 22px 50%, #fff 0 5px, rgba(255, 255, 255, 0) 6px);
}
.ofilter-skin-revolution .ofilter-group.ofilter-collapsed .ofilter-group-title::before {
    background-color: var(--of-bg, #fff);
    border: 1px solid #aaa;
    background-image: radial-gradient(circle at 8px 50%, #aaa 0 5px, rgba(255, 255, 255, 0) 6px);
}
/* Rating title carries an inline count + never collapses: no toggle, no colon. */
.ofilter-skin-revolution .ofilter-rating-title::before,
.ofilter-skin-revolution .ofilter-rating-title::after { content: none; }

/* ---- Value list body (.collapsible): scroll long lists; price body not clamped ---- */
.ofilter-skin-revolution .ofilter-group-body { padding: 10px; }
/* chips row + apply/reset were flush against the bordered panel edge — inset them to match the
   10px group-body padding so they don't touch the panel border. */
.ofilter-skin-revolution .ofilter-chips { padding: 10px; margin-bottom: 0; }
.ofilter-skin-revolution .ofilter-actions { padding: 10px; }
.ofilter-skin-revolution .ofilter-group[data-type="checkbox"] > .ofilter-group-body,
.ofilter-skin-revolution .ofilter-group[data-type="radio"]    > .ofilter-group-body,
.ofilter-skin-revolution .ofilter-group[data-type="image"]    > .ofilter-group-body {
    max-height: 235px;
}
.ofilter-skin-revolution .ofilter-price .ofilter-group-body { padding: 5px 8px 10px; }
.ofilter-skin-revolution .ofilter-value { padding: 3px 0; }

/* ---- Count pill (.revlabel): bare number, bg #eee, radius 2px ---- */
.ofilter-skin-revolution .ofilter-count {
    align-self: center;
    padding: 2px 4px;
    font-size: 13px;
    line-height: 1;
    color: #333;
    background-color: #eee;
    border-radius: 2px;
}
/* Empty badge (before counts load / a facet the response omits): no stray grey pill. */
.ofilter-skin-revolution .ofilter-count:empty { display: none; }

/* ---- Rating / instock / reviews / photo cluster (revfilter .revf-rrblock):
   sits right after price, reads as ONE block (no internal borders); rating shows the
   stars + count row with NO title bar; instock/reviews/photo are flush label rows. */
.ofilter-skin-revolution .ofilter-rating,
.ofilter-skin-revolution .ofilter-instock,
.ofilter-skin-revolution .ofilter-reviews,
.ofilter-skin-revolution .ofilter-new,
.ofilter-skin-revolution .ofilter-discount,
.ofilter-skin-revolution .ofilter-photo { border-bottom: none; }
.ofilter-skin-revolution .ofilter-rating-title { display: none; }
/* rating is the cluster's FIRST row and its title bar is hidden in this skin, so it carries the
   group-body inset (10px, same as an attribute group's body) PLUS one value-row rhythm (3px) =
   13px, putting the stars exactly where an attribute group's first value sits under its title.
   Bottom is the row rhythm alone; .ofilter-rrcluster below owns the block's bottom inset. */
.ofilter-skin-revolution .ofilter-rating .ofilter-group-body { padding: 13px 10px 3px; }
/* block bottom inset = the group-body bottom (10px), so the cluster closes like any other group */
.ofilter-skin-revolution .ofilter-rrcluster { padding: 0 0 10px; }
.ofilter-skin-revolution .ofilter-instock > label,
.ofilter-skin-revolution .ofilter-reviews > label,
.ofilter-skin-revolution .ofilter-new > label,
.ofilter-skin-revolution .ofilter-discount > label,
.ofilter-skin-revolution .ofilter-photo > label {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0;
    /* match the attribute/option value rows (.ofilter-value padding 3px + body 10px inset) so the
       rating/in-stock/reviews/new/discount cluster shares the same vertical rhythm and left indent */
    padding: 3px 10px;
    font-weight: 400;
    cursor: pointer;
}

/* ---- Price от/до inputs (.revf_price_inputs input): rounded ---- */
.ofilter-skin-revolution .ofilter-price-from,
.ofilter-skin-revolution .ofilter-price-to {
    height: auto;
    padding: 7px 10px;
    border: 1px solid #d9d9d9;
    border-radius: 8px;
    font-size: 14px;
    color: #333;
}
.ofilter-skin-revolution .ofilter-price-from:focus,
.ofilter-skin-revolution .ofilter-price-to:focus { border-color: #b5b5b5; }
.ofilter-skin-revolution .ofilter-price-dash { color: #c0c0c0; }

/* ============================ Slider (revfilter .irs-*) ==================
 * Grey outlined track, grey inset bar, square arrow handle, grey #eee bubbles,
 * hidden min/max. Equal-specificity overrides of the base .ofilter .irs-* rules;
 * they win by source order (this block is appended last). */
.ofilter-skin-revolution .irs { height: 40px; margin: 7px 0 10px; }
/* the compact 40px .irs overrides the base .irs-with-grid:62px (equal specificity, later wins), which
   squeezed the grid labels up under the handles ("подписи за слайдерами"). Restore the taller box when
   a grid is present so the ticks clear the handle row (universam/market already do this). */
.ofilter-skin-revolution .irs-with-grid { height: 62px; }
.ofilter-skin-revolution .irs-line {
    top: 26px;
    height: 10px;
    background: transparent;
    border: 1px solid var(--of-border, #ddd);
    border-radius: 2px;
    overflow: hidden;
}
.ofilter-skin-revolution .irs-bar {
    top: 25px;
    height: 10px;
    background: #eee;
    border-radius: 0;
    box-shadow: inset 1px 1px 1px #aaa;
}
.ofilter-skin-revolution .irs-bar-edge {
    top: 25px;
    height: 10px;
    width: 9px;
    background: #eee;
    border-radius: 2px 0 0 2px;
    box-shadow: inset 1px 1px 1px #aaa;
}
/* Handle: light square button with two ‹ › chevrons (replaces price_sl.png). */
.ofilter-skin-revolution .irs-slider {
    top: 22px;
    width: 25px;
    height: 17px;
    background: -webkit-linear-gradient(top, #fff, #f0f0f0);
    background: linear-gradient(#fff, #f0f0f0);
    border: 1px solid #bcbcbc;
    border-radius: 3px;
    box-shadow: 0 1px 1px rgba(0, 0, 0, .12);
}
.ofilter-skin-revolution .irs-slider:hover,
.ofilter-skin-revolution .irs-slider:focus { box-shadow: 0 1px 2px rgba(0, 0, 0, .22); }
.ofilter-skin-revolution .irs-slider::before {
    content: "\2039\2009\203A";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    line-height: 1;
    color: #8a8a8a;
}
/* Value bubbles (.irs-from/.irs-to/.irs-single): grey #eee, dark text. */
.ofilter-skin-revolution .irs-from,
.ofilter-skin-revolution .irs-to,
.ofilter-skin-revolution .irs-single {
    top: -1px;
    padding: 2px 4px;
    font-size: 14px;
    line-height: 13px;
    color: #333;
    background: #eee;
    border-radius: 2px;
}
.ofilter-skin-revolution .irs-from::after,
.ofilter-skin-revolution .irs-to::after,
.ofilter-skin-revolution .irs-single::after { border-top-color: #eee; }
.ofilter-skin-revolution .irs-min,
.ofilter-skin-revolution .irs-max { display: none; }
.ofilter-skin-revolution .irs-grid-text { font-size: 9px; color: #999; }

/* In-drawer (mobile off-canvas): drop the panel border/radius like revfilter. */
.ofilter-drawer-body .ofilter-skin-revolution { border: 0; border-radius: 0; box-shadow: none; }
.ofilter-drawer-body .ofilter-skin-revolution .ofilter-heading { border-radius: 0; margin-bottom: 0; }

/* ============================================================================
 * feature: appearance — "Стиль как на Universam" (marketplace cards) skin.
 * ----------------------------------------------------------------------------
 * Opt-in via .ofilter-skin-universam (ofilter_skin = 'universam'). Reproduces the
 * universam.oc-mod.ru filter: each facet group is a standalone white card (light
 * border + soft shadow, spacing between), NO filter header, bold titles with a
 * thin chevron, superscript count numbers, a hairline slider with small
 * rectangular handles + a tick grid, and a light full-width Сбросить button.
 * Everything is namespaced so the default + revolution skins are byte-untouched.
 * Self-contained, hard palette (neutral #333), no ?v=.
 * ========================================================================== */

/* ONE light panel holds every group (Universam #revfilter_box: bg #fafafa, radius, pad). */
.ofilter-skin-universam {
    --of-accent: #333;
    --of-accent-dark: #000;
    background: var(--of-bg-soft, #fafafa);
    border: 1px solid #ececec;
    border-radius: 4px;
    padding: 4px 12px;
}

/* Filter header — only rendered by the twig when a title is set or the reset lives in the
   header (settings win over the skin). Bold title left, reset link right, hairline divider. */
.ofilter-skin-universam .ofilter-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin: 0 0 4px;
    padding: 8px 0;
    border-bottom: 1px solid #e6e6e6;
}
.ofilter-skin-universam .ofilter-heading-t { font-size: 14px; font-weight: 700; color: #333; }
.ofilter-skin-universam .ofilter-reset-top {
    flex: 0 0 auto;
    font-size: 13px;
    color: var(--of-muted, #777);
    text-decoration: none;
}
.ofilter-skin-universam .ofilter-reset-top:hover,
.ofilter-skin-universam .ofilter-reset-top:focus { color: #333; text-decoration: underline; }

/* Groups: transparent, separated by a thin divider (Universam .option_box border-bottom). */
.ofilter-skin-universam .ofilter-group {
    background: none;
    border: 0;
    border-bottom: 1px solid #e6e6e6;
    border-radius: 0;
    box-shadow: none;
    margin: 0;
    padding: 0;
}
.ofilter-skin-universam .ofilter-group:last-child { border-bottom: 0; }

/* Title: bold, dark, trailing colon + a thin chevron. Chevron via ::before (absolute
   right); colon via ::after (in-flow, overriding the base skin's chevron ::after). */
.ofilter-skin-universam .ofilter-group-title {
    padding: 10px 22px 10px 0;
    font-size: 13px;
    font-weight: 700;
    color: #333;
}
.ofilter-skin-universam .ofilter-group-title::before {
    content: "";
    position: absolute;
    top: 50%;
    right: 3px;
    margin-top: -5px;
    width: 7px;
    height: 7px;
    border-right: 2px solid #b5b5b5;
    border-bottom: 2px solid #b5b5b5;
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
}
.ofilter-skin-universam .ofilter-group.ofilter-collapsed .ofilter-group-title::before {
    margin-top: -3px;
    -webkit-transform: rotate(-45deg);
    transform: rotate(-45deg);
}
.ofilter-skin-universam .ofilter-group-title::after {
    content: ":";
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    border: 0;
    -webkit-transform: none;
    transform: none;
    color: #333;
}
.ofilter-skin-universam .ofilter-group.ofilter-collapsed .ofilter-group-title::after {
    margin: 0;
    -webkit-transform: none;
    transform: none;
}
.ofilter-skin-universam .ofilter-group-body { padding: 0 0 10px; }
.ofilter-skin-universam .ofilter-group[data-type="checkbox"] > .ofilter-group-body,
.ofilter-skin-universam .ofilter-group[data-type="radio"]    > .ofilter-group-body {
    max-height: 280px;
    overflow-y: auto;
}
/* Image swatches read as a grid, not a list: two columns and no scroll box, so the whole
   palette is visible at once instead of a 280px window. break-inside guards a chip against
   being split down the column boundary (the cols feature only sets it for checkbox/radio). */
.ofilter-skin-universam .ofilter-group[data-type="image"] > .ofilter-group-body {
    column-count: 2;
    column-gap: 7px;
    max-height: none;
}
.ofilter-skin-universam .ofilter-group[data-type="image"] .ofilter-value { break-inside: avoid; }

/* Overrides for blocks that come LATER in this file — they win on specificity (the skin class
   compounds onto the root selector), not on order. */
.ofilter-skin-universam .ofilter-price-hist,
.ofilter-skin-universam .ofilter-attr-hist {
    margin: 0 8px -25px;
    opacity: .4;                 /* backdrop, not a chart — the slider stays the focus */
}
.ofilter-skin-universam .ofilter-more { display: block; }
.ofilter-skin-universam.ofilter-cols-2 .ofilter-group[data-type="checkbox"] > .ofilter-group-body,
.ofilter-skin-universam.ofilter-cols-2 .ofilter-group[data-type="radio"] > .ofilter-group-body {
    column-gap: 7px;             /* this skin's rows are tighter than the shared 14px assumes */
}

/* Value rows: inline label + a superscript count number (not a badge). The checkbox and
   the label text are BOTH vertical-align:middle so the text is centered against the box
   (covers facet values, grouping radios, and the instock/reviews/photo rows). */
.ofilter-skin-universam .ofilter-value { padding: 5px 0; }
.ofilter-skin-universam .ofilter-value > label { display: block; margin: 0; padding-left: 1px; line-height: 1.4; }
.ofilter-skin-universam input[type="checkbox"],
.ofilter-skin-universam input[type="radio"] {
    margin: 0 2px 0 0;
    vertical-align: middle;
    position: relative;
    top: -1px;
}
.ofilter-skin-universam .ofilter-name { display: inline; color: #333; vertical-align: middle; font-size: 13px; }
.ofilter-skin-universam .ofilter-count {
    display: inline;
    vertical-align: super;
    margin-left: 3px;
    padding: 0;
    font-size: 10px;
    line-height: 0;
    color: #999;
    background: none;
    border-radius: 0;
}
.ofilter-skin-universam .ofilter-count:empty { display: none; }

/* Reset: full-width grey button inside the panel (Universam .clear_filter_button). */
.ofilter-skin-universam .ofilter-reset {
    margin-top: 8px;
    margin-bottom: 4px;
    padding: 8px 12px;
    font-size: 15px;
    font-weight: 400;
    color: #333;
    background: #eee;
    border: 1px solid #eee;
    border-radius: 3px;
}
.ofilter-skin-universam .ofilter-reset:hover,
.ofilter-skin-universam .ofilter-reset:focus {
    color: #111;
    background: #e2e2e2;
    border-color: #e2e2e2;
}

/* Settings win over the skin: the от/до inputs (ofilter_price_inputs) and the price/attr
   histograms (per-facet hist + ofilter_price_hist) are DOM-gated by their own settings, so the
   skin no longer force-hides them — an enabled setting shows through on every skin. */

/* ---- Slider: hairline track, thin dark bar, small rectangular handles, grid ---- */
.ofilter-skin-universam .irs { height: 50px; }
.ofilter-skin-universam .irs-with-grid { height: 60px; }
/* Track: hollow #ddd outline (content-box so the border shows as a thin ghosted line,
   like the reference), so the SOLID selected bar clearly stands out over it. */
.ofilter-skin-universam .irs-line {
    box-sizing: content-box;
    top: 25px;
    height: 2px;
    background: transparent;
    border: 1px solid var(--of-border, #ddd);
    border-radius: 2px;
    overflow: visible;
}
/* Selected range: solid dark bar with an inset shadow (Universam .irs-bar). */
.ofilter-skin-universam .irs-bar {
    top: 26px;
    height: 3px;
    background: #555;
    border-radius: 0;
    box-shadow: inset 1px 1px 1px #888;
}
.ofilter-skin-universam .irs-bar-edge {
    top: 26px;
    height: 3px;
    width: 9px;
    background: #555;
    border-radius: 2px 0 0 2px;
    box-shadow: inset 1px 1px 1px #888;
}
.ofilter-skin-universam .irs-slider {
    top: 18px;
    width: 10px;
    height: 20px;
    background: #f5f5f5;
    border: 1px solid var(--of-accent, #333);
    border-radius: 2px;
    box-shadow: none;
}
.ofilter-skin-universam .irs-slider::before { content: none; }
.ofilter-skin-universam .irs-slider:hover,
.ofilter-skin-universam .irs-slider:focus { box-shadow: 0 0 0 3px rgba(0, 0, 0, .06); }
/* from / to bubbles: plain dark text (no colored pill, no caret). */
.ofilter-skin-universam .irs-from,
.ofilter-skin-universam .irs-to,
.ofilter-skin-universam .irs-single {
    top: -2px;
    padding: 0 2px;
    font-size: 13px;
    color: #333;
    /* No plate here, unlike market/pills: this skin's price bubbles sit clear of the bars. If a
       histogram is switched on and the digits become hard to read over a tall bar, give them
       `background: var(--of-bg, #fff)` back. */
    background: transparent;
    opacity: 1;
    border-radius: 0;
}
.ofilter-skin-universam .irs-from::after,
.ofilter-skin-universam .irs-to::after,
.ofilter-skin-universam .irs-single::after { display: none; }
.ofilter-skin-universam .irs-min,
.ofilter-skin-universam .irs-max { display: none; }
.ofilter-skin-universam .irs-grid-text { font-size: 9px; color: #999; }
.ofilter-skin-universam .irs-grid-pol { background: #ccc; }

/* Rating / instock / reviews / photo = ONE group section (a single divider like the
   other groups, no internal dividers). The .ofilter-rrcluster wrapper carries it. */
.ofilter-skin-universam .ofilter-rrcluster {
    border-bottom: 1px solid #e6e6e6;
    /* bottom mirrors the group-body bottom so the block closes like the other groups */
    padding: 6px 0 10px;
}
.ofilter-skin-universam .ofilter-rrcluster .ofilter-group {
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    margin: 0;
    padding: 0;
}
.ofilter-skin-universam .ofilter-rating-title { display: none; }
.ofilter-skin-universam .ofilter-rating .ofilter-group-body { padding: 5px 0; }
/* count sits right after the stars (superscript), not pushed to the far right */
.ofilter-skin-universam .ofilter-rate-row { display: block; }
.ofilter-skin-universam .ofilter-rate-row .ofilter-stars-pick { vertical-align: middle; }
.ofilter-skin-universam .ofilter-instock > label,
.ofilter-skin-universam .ofilter-reviews > label,
.ofilter-skin-universam .ofilter-new > label,
.ofilter-skin-universam .ofilter-discount > label,
.ofilter-skin-universam .ofilter-photo > label {
    display: block;
    margin: 0;
    padding: 5px 0;
}

/* In-drawer (mobile off-canvas): flatten the panel. */
.ofilter-drawer-body .ofilter-skin-universam { border: 0; border-radius: 0; padding: 0 12px; }

/* ============================================================================
 * feature: appearance — "Стиль как на filter.oc-mod.ru" (green marketplace) skin.
 * ----------------------------------------------------------------------------
 * Opt-in via .ofilter-skin-market. A port of the filter.oc-mod.ru filter (same
 * revfilter engine): ONE white panel with full-width #fafafa title bars + #eaeaea
 * dividers, colon titles + chevron, superscript counts, a GREEN selected-range
 * slider (#58ae43), square handles + tick grid, grey full-width Сбросить.
 * Everything namespaced so the other skins stay untouched. Hard palette, no ?v=.
 * ========================================================================== */

/* One white panel; groups are full-width rows with #fafafa title bars. */
.ofilter-skin-market {
    --of-accent: #58ae43;
    --of-accent-dark: #4a9538;
    background: var(--of-bg, #fff);
    border: 1px solid #eaeaea;
    border-radius: 2px;
    padding: 0;
}
/* Filter header (only rendered when a title is set or the reset lives in the header):
   a #fafafa bar with the title left and the reset link right. */
.ofilter-skin-market .ofilter-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin: 0;
    padding: 10px;
    background: var(--of-bg-soft, #fafafa);
    border-bottom: 1px solid #eaeaea;
}
.ofilter-skin-market .ofilter-heading-t { font-size: 14px; font-weight: 500; color: #333; }
.ofilter-skin-market .ofilter-reset-top {
    flex: 0 0 auto;
    font-size: 13px;
    color: var(--of-accent, #58ae43);
    text-decoration: none;
}
.ofilter-skin-market .ofilter-reset-top:hover,
.ofilter-skin-market .ofilter-reset-top:focus { color: var(--of-accent-dark, #4a9538); text-decoration: underline; }

/* Active-filter chips sit above the first group: inset + top spacing so they don't
   glue to the panel edge (the panel has no padding — groups are full-width). Only when
   chips exist — :not(:empty) so an empty container adds NO stray top gap. */
.ofilter-skin-market .ofilter-chips:not(:empty) { margin: 12px 10px 10px; }

/* Groups: transparent, thin #eaeaea divider (full-width). */
.ofilter-skin-market .ofilter-group {
    background: none;
    border: 0;
    border-bottom: 1px solid #eaeaea;
    border-radius: 0;
    box-shadow: none;
    margin: 0;
    padding: 0;
}
.ofilter-skin-market .ofilter-group:last-child { border-bottom: 0; }

/* Title: full-width #fafafa bar, colon + chevron (chevron ::before, colon ::after). */
.ofilter-skin-market .ofilter-group-title {
    padding: 8px 24px 8px 10px;
    font-size: 14px;
    font-weight: 500;
    color: #333;
    background: var(--of-bg-soft, #fafafa);
}
.ofilter-skin-market .ofilter-group-title::before {
    content: "";
    position: absolute;
    top: 50%;
    right: 10px;
    margin-top: -5px;
    width: 7px;
    height: 7px;
    border-right: 2px solid #b5b5b5;
    border-bottom: 2px solid #b5b5b5;
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
}
.ofilter-skin-market .ofilter-group.ofilter-collapsed .ofilter-group-title::before {
    margin-top: -3px;
    -webkit-transform: rotate(-45deg);
    transform: rotate(-45deg);
}
.ofilter-skin-market .ofilter-group-title::after {
    content: ":";
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    border: 0;
    -webkit-transform: none;
    transform: none;
    color: #333;
}
.ofilter-skin-market .ofilter-group.ofilter-collapsed .ofilter-group-title::after {
    margin: 0;
    -webkit-transform: none;
    transform: none;
}

/* Body + values (superscript counts, aligned checkboxes). */
.ofilter-skin-market .ofilter-group-body { padding: 8px 10px; }
.ofilter-skin-market .ofilter-group[data-type="checkbox"] > .ofilter-group-body,
.ofilter-skin-market .ofilter-group[data-type="radio"]    > .ofilter-group-body,
.ofilter-skin-market .ofilter-group[data-type="image"]    > .ofilter-group-body {
    max-height: 280px;
    overflow-y: auto;
}
.ofilter-skin-market .ofilter-value { padding: 4px 0; }
.ofilter-skin-market .ofilter-value > label { display: block; margin: 0; line-height: 1.4; }
.ofilter-skin-market input[type="checkbox"],
.ofilter-skin-market input[type="radio"] {
    margin: 0 7px 0 0;
    vertical-align: middle;
    position: relative;
    top: -1px;
}
.ofilter-skin-market .ofilter-name { display: inline; color: #333; vertical-align: middle; }
.ofilter-skin-market .ofilter-count {
    display: inline;
    vertical-align: super;
    margin-left: 3px;
    padding: 0;
    font-size: 10px;
    line-height: 0;
    color: #999;
    background: none;
    border-radius: 0;
}
.ofilter-skin-market .ofilter-count:empty { display: none; }

/* Reset: grey button, inset from the panel edges. */
.ofilter-skin-market .ofilter-reset {
    width: auto;
    margin: 8px 10px 10px;
    padding: 8px 12px;
    font-size: 14px;
    font-weight: 400;
    color: #333;
    background: #f5f5f5;
    border: 1px solid #f5f5f5;
    border-radius: 2px;
}
.ofilter-skin-market .ofilter-reset:hover,
.ofilter-skin-market .ofilter-reset:focus { color: #111; background: #ececec; border-color: #ececec; }

/* Apply + reset row: reset LEFT (natural width), apply RIGHT (grows). In auto mode the Apply
   button is hidden -> the Reset grows to fill; with reset-in-header only Apply is here, so it
   fills the row (centred text, side margins). padding (not margin) on the wrapper keeps an
   all-hidden row from leaving a stray gap. */
.ofilter-skin-market .ofilter-actions {
    display: flex;
    gap: 8px;
    padding: 0 10px;
}
.ofilter-skin-market .ofilter-actions .ofilter-apply {
    order: 1;
    flex: 1 1 auto;
    width: auto;
    margin: 8px 0 10px;
    border-radius: 2px;
    font-weight: 400;
}
/* the button carries Bootstrap .btn.btn-primary -> its :active/:focus paint it BLUE. Override to
   stay green: kill the blue focus glow, and on press use a slightly lighter green (not blue). */
.ofilter-skin-market .ofilter-actions .ofilter-apply:focus,
.ofilter-skin-market .ofilter-actions .ofilter-apply.focus,
.ofilter-skin-market .ofilter-actions .ofilter-apply:active,
.ofilter-skin-market .ofilter-actions .ofilter-apply.active,
.ofilter-skin-market .ofilter-actions .ofilter-apply:not(:disabled):not(.disabled):active,
.ofilter-skin-market .ofilter-actions .ofilter-apply:not(:disabled):not(.disabled).active,
.ofilter-skin-market .ofilter-actions .ofilter-apply:not(:disabled):not(.disabled):active:focus {
    color: #fff;
    background-color: #6ebe5a;
    border-color: #6ebe5a;
    box-shadow: none;
}
.ofilter-skin-market .ofilter-actions .ofilter-reset {
    order: 0;
    flex: 0 0 auto;
    width: auto;
    margin: 8px 0 10px;
}
.ofilter-skin-market .ofilter-actions .ofilter-apply.ofilter-apply-mobile ~ .ofilter-reset { flex: 1 1 auto; }

/* Settings win over the skin: от/до inputs + histograms are DOM-gated by their own settings
   (ofilter_price_inputs / per-facet hist / ofilter_price_hist), so the skin no longer hides them. */

/* ---- Slider: GREEN selected bar, hollow outline track, square handles, grid ---- */
.ofilter-skin-market .irs { height: 50px; }
.ofilter-skin-market .irs-with-grid { height: 60px; }
.ofilter-skin-market .irs-line {
    box-sizing: content-box;
    top: 25px;
    height: 2px;
    background: transparent;
    border: 1px solid var(--of-border, #ddd);
    border-radius: 2px;
    overflow: visible;
}
.ofilter-skin-market .irs-bar {
    top: 26px;
    height: 3px;
    background: var(--of-accent, #58ae43);
    border-radius: 0;
    box-shadow: none;
}
.ofilter-skin-market .irs-bar-edge {
    top: 26px;
    height: 3px;
    width: 9px;
    background: var(--of-accent, #58ae43);
    border-radius: 2px 0 0 2px;
    box-shadow: none;
}
.ofilter-skin-market .irs-slider {
    top: 18px;
    width: 10px;
    height: 20px;
    background: #f5f5f5;
    border: 1px solid #333;
    border-radius: 2px;
    box-shadow: none;
}
.ofilter-skin-market .irs-slider::before { content: none; }
.ofilter-skin-market .irs-slider:hover,
.ofilter-skin-market .irs-slider:focus { box-shadow: 0 0 0 3px rgba(88, 174, 67, .18); }
.ofilter-skin-market .irs-from,
.ofilter-skin-market .irs-to,
.ofilter-skin-market .irs-single {
    top: -2px;
    padding: 0 2px;
    font-size: 13px;
    color: #333;
    /* A semi-opaque page-coloured plate, not `transparent`: the histogram strip sits directly
       behind these labels, and over a tall bar the bare digits become unreadable. Token, not
       #fff, so the dark theme's --of-bg follows automatically (no override needed). */
    background: var(--of-bg, #fff);
    opacity: .85;
    border-radius: 0;
}
.ofilter-skin-market .irs-from::after,
.ofilter-skin-market .irs-to::after,
.ofilter-skin-market .irs-single::after { display: none; }
.ofilter-skin-market .irs-min,
.ofilter-skin-market .irs-max { display: none; }
.ofilter-skin-market .irs-grid-text { font-size: 9px; color: #999; }
.ofilter-skin-market .irs-grid-pol { background: #ccc; }

/* Histogram, market-only: shorter and dimmer than the shared strip. This skin puts the slider on a
   light card with a scale under it, so the full-height bars read as a chart competing with the
   track; here they are a backdrop. Bar heights are percentages, so the whole strip scales with the
   height and no JS changes. The bottom margin stays ~4px shy of the height so the tallest bar
   clears the track. */
.ofilter-skin-market .ofilter-price-hist,
.ofilter-skin-market .ofilter-attr-hist {
    height: 30px;
    margin: 4px 8px -25px;
    opacity: .4;
}

/* Rating / instock / reviews cluster = one padded section with a divider. */
.ofilter-skin-market .ofilter-rrcluster {
    border-bottom: 1px solid #eaeaea;
    /* bottom mirrors this skin's group-body bottom inset (8px) so the block closes like the others */
    padding: 6px 10px 8px;
}
.ofilter-skin-market .ofilter-rrcluster .ofilter-group {
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    margin: 0;
    padding: 0;
}
.ofilter-skin-market .ofilter-rating-title { display: none; }
/* rating title is hidden here, so its body carries the generic group-body inset (8px top / 10px
   sides, same as an attribute group) and keeps the 4px row rhythm at the bottom. */
.ofilter-skin-market .ofilter-rating .ofilter-group-body { padding: 8px 0 4px; }
.ofilter-skin-market .ofilter-rate-row { display: block; }
.ofilter-skin-market .ofilter-instock > label,
.ofilter-skin-market .ofilter-reviews > label,
.ofilter-skin-market .ofilter-new > label,
.ofilter-skin-market .ofilter-discount > label,
.ofilter-skin-market .ofilter-photo > label { display: block; margin: 0; padding: 4px 0; }

/* In-drawer (mobile off-canvas): flatten the panel. */
.ofilter-drawer-body .ofilter-skin-market { border: 0; border-radius: 0; }

/* ============================================================================
 * feature: appearance — "Стиль плитками (теги)" pills skin.
 * ----------------------------------------------------------------------------
 * Opt-in via .ofilter-skin-pills. Facet values render as toggle PILLS: the
 * checkbox/radio is visually hidden and its .ofilter-name label becomes the pill
 * (:checked fills it dark), pills wrap into a grid. Small grey section titles +
 * thin dividers, NO counts, round-handle price slider, hidden от/до inputs.
 * Reuses the stock checkbox/radio markup entirely — pure CSS. Hard palette, no ?v=.
 * ========================================================================== */

.ofilter-skin-pills {
    --of-accent: #222;
    --of-accent-dark: #000;
    background: transparent;
    border: 0;
    padding: 0;
}

/* Header «Filter»: bold, larger; reset link muted on the right. */
.ofilter-skin-pills .ofilter-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin: 0 0 6px;
    padding: 2px 0 12px;
}
.ofilter-skin-pills .ofilter-heading-t { font-size: 14px; font-weight: 400; color: #111; }
.ofilter-skin-pills .ofilter-reset-top { flex: 0 0 auto; font-size: 13px; color: #888; text-decoration: none; }
.ofilter-skin-pills .ofilter-reset-top:hover,
.ofilter-skin-pills .ofilter-reset-top:focus { color: #111; }

/* Sections: thin divider, small grey title, no chevron. */
.ofilter-skin-pills .ofilter-group {
    background: none;
    border: 0;
    border-bottom: 1px solid #eee;
    border-radius: 0;
    box-shadow: none;
    margin: 0;
    padding: 6px 0 14px;
}
.ofilter-skin-pills .ofilter-group:last-child { border-bottom: 0; }
.ofilter-skin-pills .ofilter-group-title {
    padding: 8px 0;
    font-size: 13px;
    font-weight: 400;
    color: #222;
    cursor: pointer;
}
.ofilter-skin-pills .ofilter-group-title::after,
.ofilter-skin-pills .ofilter-group-title::before { content: none; }

/* Value list -> a wrapping grid of pills. */
.ofilter-skin-pills .ofilter-group[data-type="checkbox"] > .ofilter-group-body,
.ofilter-skin-pills .ofilter-group[data-type="radio"]    > .ofilter-group-body,
.ofilter-skin-pills .ofilter-group[data-type="image"]    > .ofilter-group-body,
.ofilter-skin-pills .ofilter-subcategories > .ofilter-group-body,
.ofilter-skin-pills .ofilter-grouping > .ofilter-group-body {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    max-height: none;
    overflow: visible;
    padding: 4px 0 0;
}
/* Restore group collapse in this skin: the flex rule above (0,4,0 specificity) out-ranks the
   base `.ofilter-group.ofilter-collapsed .ofilter-group-body{display:none}` (0,3,0), so a
   collapsed group stayed open. This equal-specificity rule, later in source, wins the tie. */
.ofilter-skin-pills .ofilter-group.ofilter-collapsed > .ofilter-group-body { display: none; }
.ofilter-skin-pills .ofilter-value { display: inline-block; margin: 0; padding: 0; }
/* The LABEL is the pill: an inline-flex box carrying the bg + rounded shape. .ofilter-name (left)
   and .ofilter-count (right) are transparent flex items inside it, so the count sits INSIDE the pill
   at the top-right AND the pill grows to fit a big multi-digit count (no overlap). overflow:hidden
   clips the checked accent fill (painted on name+count) to the rounded shape; position:relative
   anchors the absolute swatch/image inside the pill's left padding. */
.ofilter-skin-pills .ofilter-value > label {
    position: relative;
    display: inline-flex;
    align-items: stretch;
    gap: 0;
    margin: 0;
    background: #f2f2f2;
    border-radius: 18px;
    overflow: hidden;
    cursor: pointer;
    -webkit-transition: background .12s;
    transition: background .12s;
}
.ofilter-skin-pills .ofilter-value > label:hover { background: #e6e6e6; }
/* hide the input but keep it in the a11y tree + label-toggleable.
   top/left pinned to auto for the same reason as .ofilter-value-sw above: a stray `top` from a
   skin's 1px nudge would turn into an absolute offset and park the focus target at the sidebar's
   corner, so clicking a pill would scroll the page there. */
.ofilter-skin-pills .ofilter-value input[type="checkbox"],
.ofilter-skin-pills .ofilter-value input[type="radio"] {
    position: absolute;
    top: auto;
    left: auto;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
    pointer-events: none;
}
.ofilter-skin-pills .ofilter-value .ofilter-name {
    padding: 8px 16px;
    font-size: 14px;
    line-height: 1.2;
    color: #333;
    cursor: pointer;
    -webkit-transition: color .12s;
    transition: color .12s;
}
.ofilter-skin-pills .ofilter-value input:checked ~ .ofilter-name { background: var(--of-accent, #222); color: #fff; }
.ofilter-skin-pills .ofilter-value.ofilter-off { opacity: .4; }
/* Settings win: show the count when ofilter_counts is ON (hide only the empty placeholder span
   before counts load / for facets the response omits), instead of force-hiding every count. */
.ofilter-skin-pills .ofilter-count:empty { display: none; }
/* image swatch pills: the img is a SIBLING before .ofilter-name (the pill), so it rendered
   OUTSIDE the pill. Anchor it absolutely inside the pill's left padding so the swatch sits within
   the rounded background (works with the :checked dark fill, which only recolours .ofilter-name). */
.ofilter-skin-pills .ofilter-value-image .ofilter-name { padding-left: 32px; }
.ofilter-skin-pills .ofilter-value-image .ofilter-img {
    position: absolute;
    left: 8px;
    top: 50%;
    -webkit-transform: translateY(-50%);
    transform: translateY(-50%);
    width: 18px;
    height: 18px;
    margin: 0;
    border-radius: 50%;
    z-index: 1;
    pointer-events: none;
}
/* colour swatch INSIDE the pill (parity with the image swatch above). `.ofilter-sw` is a sibling
   before `.ofilter-name`, so by default it sat OUTSIDE the pill on the left; anchor it inside the
   pill's left padding and pad the name to clear it (only when a swatch is actually present). */
.ofilter-skin-pills .ofilter-value .ofilter-sw {
    position: absolute;
    left: 11px;
    top: 50%;
    -webkit-transform: translateY(-50%);
    transform: translateY(-50%);
    width: 14px;
    height: 14px;
    margin: 0;
    z-index: 1;
    pointer-events: none;
}
.ofilter-skin-pills .ofilter-value .ofilter-sw + .ofilter-name { padding-left: 33px; }
/* count INSIDE the pill at the top-right: a transparent flex item after the name, stretched to the
   full pill height with the 10px number pinned to the top. In flow -> the pill grows to fit a big
   multi-digit count, so it can never overlap the label. :empty stays hidden. On checked it carries
   the accent fill so the pill's right half darkens with the rest. */
.ofilter-skin-pills .ofilter-value .ofilter-count {
    align-self: stretch;
    margin-left: -12px;
    padding: 5px 12px 0 0;
    font-size: 10px;
    line-height: 1;
    color: var(--of-muted, #999);
    background: none;
}
.ofilter-skin-pills .ofilter-value input:checked ~ .ofilter-count { background: var(--of-accent, #222); color: rgba(255, 255, 255, .8); }

/* Settings win over the skin: от/до inputs + histograms are DOM-gated by their own settings, so
   the skin no longer hides them (ofilter_price_inputs / per-facet hist / ofilter_price_hist). */
/* Track sits low so the value labels (irs-from/to) clear the round handle above it;
   .irs is tall enough to keep the number grid attached right under the line. */
.ofilter-skin-pills .irs { height: 52px; }
/* same grid-clearance fix as revolution: the compact .irs would seat the grid ticks under the handles. */
.ofilter-skin-pills .irs-with-grid { height: 62px; }
/* Histogram sits 3px higher than the shared strip: this skin's track is thinner and lower. */
.ofilter-skin-pills .ofilter-price-hist,
.ofilter-skin-pills .ofilter-attr-hist { margin: 0 8px -28px; }

.ofilter-skin-pills .irs-line {
    top: 29px;
    height: 4px;
    background: #e6e6e6;
    border: 0;
    border-radius: 3px;
    overflow: visible;
}
.ofilter-skin-pills .irs-bar { top: 29px; height: 3px; background: #222; border-radius: 3px; box-shadow: none; }
.ofilter-skin-pills .irs-bar-edge { top: 29px; height: 3px; width: 9px; background: #222; border-radius: 3px 0 0 3px; box-shadow: none; }
.ofilter-skin-pills .irs-slider {
    top: 22px;
    width: 17px;
    height: 17px;
    background: var(--of-accent, #222);
    border: 0;
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
}
.ofilter-skin-pills .irs-slider::before { content: none; }
.ofilter-skin-pills .irs-slider:hover,
.ofilter-skin-pills .irs-slider:focus { box-shadow: 0 0 0 4px rgba(0, 0, 0, .1), 0 1px 3px rgba(0, 0, 0, .3); }
.ofilter-skin-pills .irs-from,
.ofilter-skin-pills .irs-to,
.ofilter-skin-pills .irs-single {
    top: -2px;
    padding: 0 2px;
    font-size: 13px;
    color: #333;
    background: var(--of-bg, #fff); /* plate over the histogram — see the market skin's note */
    opacity: .85;
    border-radius: 0;
}
.ofilter-skin-pills .irs-from::after,
.ofilter-skin-pills .irs-to::after,
.ofilter-skin-pills .irs-single::after { display: none; }
.ofilter-skin-pills .irs-min,
.ofilter-skin-pills .irs-max { display: none; }
.ofilter-skin-pills .irs-grid { display: none; }

/* Rating / in-stock / reviews / photo -> ONE block, styled like the rest.
   The whole cluster is a single divider section; the rating stars sit on their own
   line and «В наличии» / «С отзывами» / «С фото» become toggle PILLS (dark when on),
   matching the value pills so the block reads in one consistent style. */
.ofilter-skin-pills .ofilter-rrcluster {
    border-bottom: 1px solid #eee;
    margin: 0;
    padding: 8px 0 14px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.ofilter-skin-pills .ofilter-rrcluster .ofilter-group { border: 0; margin: 0; padding: 0; }
.ofilter-skin-pills .ofilter-rating-title { display: none; }
/* scope with .ofilter-rrcluster so this beats the group-reset above (equal specificity,
   later in source) — otherwise `.ofilter-rrcluster .ofilter-group{margin:0}` zeroes it. */
.ofilter-skin-pills .ofilter-rrcluster .ofilter-rating { flex: 0 0 100%; margin: 0; }
.ofilter-skin-pills .ofilter-rating .ofilter-group-body { padding: 4px 0 0; }
.ofilter-skin-pills .ofilter-rate-row { display: block; }
/* rating count matches the pill counts: small (10px) superscript up-and-right of the stars
   (top-aligned to the tall star line), instead of a baseline-aligned number after them. */
.ofilter-skin-pills .ofilter-rating .ofilter-count {
    vertical-align: top;
    margin-left: 4px;
    font-size: 10px;
    line-height: 1;
    color: var(--of-muted, #999);
}
/* the three toggles flow as a wrapping row of pills */
.ofilter-skin-pills .ofilter-instock,
.ofilter-skin-pills .ofilter-reviews,
.ofilter-skin-pills .ofilter-new,
.ofilter-skin-pills .ofilter-discount,
.ofilter-skin-pills .ofilter-photo { display: inline-block; margin: 0; vertical-align: top; }
.ofilter-skin-pills .ofilter-instock > label,
.ofilter-skin-pills .ofilter-reviews > label,
.ofilter-skin-pills .ofilter-new > label,
.ofilter-skin-pills .ofilter-discount > label,
.ofilter-skin-pills .ofilter-photo > label {
    position: relative;
    display: inline-flex;
    align-items: stretch;
    gap: 0;
    margin: 0;
    padding: 0;
    background: #f2f2f2;
    border-radius: 18px;
    overflow: hidden;
    cursor: pointer;
    -webkit-transition: background .12s;
    transition: background .12s;
}
.ofilter-skin-pills .ofilter-instock > label:hover,
.ofilter-skin-pills .ofilter-reviews > label:hover,
.ofilter-skin-pills .ofilter-new > label:hover,
.ofilter-skin-pills .ofilter-discount > label:hover,
.ofilter-skin-pills .ofilter-photo > label:hover { background: #e6e6e6; }
.ofilter-skin-pills .ofilter-instock > label input[type="checkbox"],
.ofilter-skin-pills .ofilter-reviews > label input[type="checkbox"],
.ofilter-skin-pills .ofilter-new > label input[type="checkbox"],
.ofilter-skin-pills .ofilter-discount > label input[type="checkbox"],
.ofilter-skin-pills .ofilter-photo > label input[type="checkbox"] {
    position: absolute;
    top: auto;                   /* see the value-pill rule above */
    left: auto;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
    pointer-events: none;
}
.ofilter-skin-pills .ofilter-instock .ofilter-name,
.ofilter-skin-pills .ofilter-reviews .ofilter-name,
.ofilter-skin-pills .ofilter-new .ofilter-name,
.ofilter-skin-pills .ofilter-discount .ofilter-name,
.ofilter-skin-pills .ofilter-photo .ofilter-name {
    padding: 8px 16px;
    font-size: 14px;
    line-height: 1.2;
    color: #333;
    cursor: pointer;
    -webkit-transition: color .12s;
    transition: color .12s;
}
.ofilter-skin-pills .ofilter-instock input:checked ~ .ofilter-name,
.ofilter-skin-pills .ofilter-reviews input:checked ~ .ofilter-name,
.ofilter-skin-pills .ofilter-new input:checked ~ .ofilter-name,
.ofilter-skin-pills .ofilter-discount input:checked ~ .ofilter-name,
.ofilter-skin-pills .ofilter-photo input:checked ~ .ofilter-name { background: var(--of-accent, #222); color: #fff; }
/* cluster toggle counts match the value pills: a transparent flex item INSIDE the pill at the
   top-right, stretched so the pill grows to fit a big count instead of overlapping. Rating stays
   inline — it is a full-width stars row, not a pill. */
.ofilter-skin-pills .ofilter-instock .ofilter-count,
.ofilter-skin-pills .ofilter-reviews .ofilter-count,
.ofilter-skin-pills .ofilter-new .ofilter-count,
.ofilter-skin-pills .ofilter-discount .ofilter-count,
.ofilter-skin-pills .ofilter-photo .ofilter-count {
    align-self: stretch;
    margin-left: -12px;
    padding: 5px 12px 0 0;
    font-size: 10px;
    line-height: 1;
    color: var(--of-muted, #999);
    background: none;
}
.ofilter-skin-pills .ofilter-instock input:checked ~ .ofilter-count,
.ofilter-skin-pills .ofilter-reviews input:checked ~ .ofilter-count,
.ofilter-skin-pills .ofilter-new input:checked ~ .ofilter-count,
.ofilter-skin-pills .ofilter-discount input:checked ~ .ofilter-count,
.ofilter-skin-pills .ofilter-photo input:checked ~ .ofilter-count { background: var(--of-accent, #222); color: rgba(255, 255, 255, .8); }

/* Buttons: dark pill apply, pill reset. */
.ofilter-skin-pills .ofilter-apply {
    background: var(--of-accent, #222);
    border-color: var(--of-accent, #222);
    border-radius: 22px;
    font-weight: 500;
}
.ofilter-skin-pills .ofilter-apply:hover,
.ofilter-skin-pills .ofilter-apply:focus { background: #000; border-color: #000; box-shadow: none; }
.ofilter-skin-pills .ofilter-reset { border-radius: 22px; }

/* =====================================================================
   feature: a11y + dark theme (appended — later cascade wins; no existing rule touched)
   ===================================================================== */

/* SR-only region for the aria-live found-count announcement */
.ofilter-sr {
    position: absolute !important; width: 1px; height: 1px; padding: 0;
    margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* focus-visible rings — keyboard focus only (mouse clicks stay ring-free) */
.ofilter :focus-visible,
.ofilter-drawer :focus-visible,
.ofilter-drawer-open:focus-visible {
    outline: 2px solid var(--of-accent, #3b6ef6);
    outline-offset: 2px;
    border-radius: 3px;
}
/* pill/checkbox rows: the input is often visually hidden (pills skin), so ring the label — but
   ONLY for KEYBOARD focus. `:has(:focus-visible)` keeps the ring off on a mouse click (a plain
   `:focus-within` boxed the checked row after every click), matching the "keyboard focus only"
   intent above. Browsers without :has simply drop the rule (no ring) — which is the desired
   mouse behaviour anyway; skins with a visible native checkbox still get the checkbox's own ring. */
.ofilter-value label:has(:focus-visible),
.ofilter-instock label:has(:focus-visible),
.ofilter-reviews label:has(:focus-visible),
.ofilter-new label:has(:focus-visible),
.ofilter-discount label:has(:focus-visible),
.ofilter-photo label:has(:focus-visible) {
    outline: 2px solid var(--of-accent, #3b6ef6);
    outline-offset: 1px;
    border-radius: 4px;
}
.ofilter-star:focus-visible { outline: 2px solid var(--of-accent, #3b6ef6); outline-offset: 2px; border-radius: 3px; }
.ofilter-group-title[role="button"] { cursor: pointer; }

/* empty state + its way-out reset button */
.ofilter-empty { text-align: center; padding: 16px 4px; color: var(--of-muted, #777); }
.ofilter-empty-reset { margin-top: 10px; }

/* visible, dismissible error banner (role=alert) with retry */
.ofilter-error {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin: 0 0 10px; padding: 8px 10px;
    background: rgba(217, 83, 79, .08);
    border: 1px solid var(--of-danger, #d9534f);
    border-radius: var(--of-radius, 6px);
    color: var(--of-danger, #d9534f);
    font-size: 13px;
}
.ofilter-error-msg { flex: 1 1 auto; }
.ofilter-error-retry {
    border: 1px solid var(--of-danger, #d9534f); background: transparent;
    color: var(--of-danger, #d9534f); border-radius: 4px; padding: 3px 10px;
    cursor: pointer; font-size: 13px;
}
.ofilter-error-retry:hover { background: var(--of-danger, #d9534f); color: #fff; }

/* sticky "Показать N" CTA at the bottom of the drawer + safe-area */
.ofilter-drawer-cta {
    position: -webkit-sticky; position: sticky; bottom: 0;
    padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    background: var(--of-bg, #fff);
}

/* 44px touch targets on mobile (drawer/off-canvas) */
@media (max-width: 991px) {
    .ofilter-drawer .ofilter-value label,
    .ofilter-drawer .ofilter-instock label,
    .ofilter-drawer .ofilter-reviews label,
    .ofilter-drawer .ofilter-new label,
    .ofilter-drawer .ofilter-discount label,
    /* 24px, not 44: a marketplace sheet lists dozens of values and 44px rows turn it into a
       scroll marathon. 24px is exactly the WCAG 2.2 AA target-size minimum (SC 2.5.8), and the
       row's own padding adds spacing on top, so the tap area stays comfortably above it. */
    .ofilter-drawer .ofilter-photo label,
    .ofilter-drawer .ofilter-group-title[role="button"] { min-height: 24px; }
    .ofilter-drawer .ofilter-star { min-width: 24px; min-height: 24px; padding: 4px 3px; }
    /* The block heading duplicates the drawer's own header on this width. `!important` is genuinely
       required: every skin sets `display: flex` on .ofilter-heading at (0,2,0), which outranks a
       plain .ofilter-heading rule. */
    .ofilter-heading { display: none !important; }
    .ofilter-chip { min-height: 38px; }
    .ofilter-drawer-close { min-width: 44px; min-height: 44px; }
    .ofilter-drawer-show { min-height: 48px; }
}

/* dark theme via --of tokens — scoped to #ofilter + the off-canvas chrome; never leaks to the page.
   --of-accent / --of-danger / --of-radius stay as-is (accent reads fine on dark). */
.ofilter-theme-dark,
.ofilter-drawer.ofilter-theme-dark,
.ofilter-drawer-open.ofilter-theme-dark {
    --of-text: #e6e8eb; --of-muted: #9aa0a8;
    --of-border: #3a3f47; --of-border-light: #2c313a;
    --of-bg: #1b1e24; --of-bg-soft: #22262e; --of-chip-bg: #2a2f38;
}
@media (prefers-color-scheme: dark) {
    .ofilter-theme-auto,
    .ofilter-drawer.ofilter-theme-auto,
    .ofilter-drawer-open.ofilter-theme-auto {
        --of-text: #e6e8eb; --of-muted: #9aa0a8;
        --of-border: #3a3f47; --of-border-light: #2c313a;
        --of-bg: #1b1e24; --of-bg-soft: #22262e; --of-chip-bg: #2a2f38;
    }
}

/* dark theme — give the filter a real dark SURFACE. The default skin is transparent (page shows
   through) and the named skins paint raw-hex card backgrounds, so on dark we (a) set the container
   to --of-bg and (b) neutralize child surface backgrounds to transparent so they inherit it, and
   (c) flip form controls + chips to the dark tokens. Appended last so it wins by source order at
   equal specificity. Scoped to .ofilter-theme-dark — never leaks to the page. */
.ofilter-theme-dark,
.ofilter-drawer.ofilter-theme-dark,
.ofilter-drawer.ofilter-theme-dark .ofilter-drawer-body,
.ofilter-theme-dark .ofilter-drawer-cta { background-color: var(--of-bg, #1b1e24); }
.ofilter-theme-dark .ofilter-heading,
.ofilter-theme-dark .ofilter-group,
.ofilter-theme-dark .ofilter-group-body,
.ofilter-theme-dark .ofilter-group-title,
.ofilter-theme-dark .ofilter-rrcluster,
.ofilter-theme-dark .ofilter-value,
.ofilter-theme-dark .ofilter-rate-row,
.ofilter-theme-dark .ofilter-actions { background-color: transparent; }
.ofilter-theme-dark input[type="text"],
.ofilter-theme-dark input[type="number"],
.ofilter-theme-dark input[type="search"],
.ofilter-theme-dark select,
.ofilter-theme-dark textarea {
    background: var(--of-bg-soft, #22262e); color: var(--of-text, #e6e8eb);
    border-color: var(--of-border, #3a3f47);
}
.ofilter-theme-dark .ofilter-chip { background: var(--of-chip-bg, #2a2f38); color: var(--of-text, #e6e8eb); border-color: var(--of-border, #3a3f47); }
.ofilter-theme-dark .ofilter-name { color: var(--of-text, #e6e8eb); }
@media (prefers-color-scheme: dark) {
    .ofilter-theme-auto,
    .ofilter-drawer.ofilter-theme-auto,
    .ofilter-drawer.ofilter-theme-auto .ofilter-drawer-body,
    .ofilter-theme-auto .ofilter-drawer-cta { background-color: var(--of-bg, #1b1e24); }
    .ofilter-theme-auto .ofilter-heading,
    .ofilter-theme-auto .ofilter-group,
    .ofilter-theme-auto .ofilter-group-body,
    .ofilter-theme-auto .ofilter-group-title,
    .ofilter-theme-auto .ofilter-rrcluster,
    .ofilter-theme-auto .ofilter-value,
    .ofilter-theme-auto .ofilter-rate-row,
    .ofilter-theme-auto .ofilter-actions { background-color: transparent; }
    .ofilter-theme-auto input[type="text"],
    .ofilter-theme-auto input[type="number"],
    .ofilter-theme-auto input[type="search"],
    .ofilter-theme-auto select,
    .ofilter-theme-auto textarea {
        background: var(--of-bg-soft, #22262e); color: var(--of-text, #e6e8eb);
        border-color: var(--of-border, #3a3f47);
    }
    .ofilter-theme-auto .ofilter-chip { background: var(--of-chip-bg, #2a2f38); color: var(--of-text, #e6e8eb); border-color: var(--of-border, #3a3f47); }
    .ofilter-theme-auto .ofilter-name { color: var(--of-text, #e6e8eb); }
}

/* =====================================================================
   dark theme - EXTENDED overrides for named-skin raw-hex leftovers.
   Appended last: equal-specificity rules win by source order. Every
   selector is scoped under .ofilter-theme-dark, so light mode is
   byte-identical. Mirrored below inside @media(prefers-color-scheme:dark)
   with .ofilter-theme-auto for auto mode.
   ===================================================================== */

/* --- tokens: histogram fills (no token exists -> raw hex) --- */
.ofilter-theme-dark,
.ofilter-drawer.ofilter-theme-dark,
.ofilter-drawer-open.ofilter-theme-dark {
    --of-hist: #333a45;             /* idle/out-of-range bars, dim by design */
    --of-hist-on: var(--of-accent); /* in-range band tracks the skin accent */
}

/* --- native chrome: repaint scrollbars / select / checkbox for dark --- */
.ofilter-theme-dark { color-scheme: dark; }

/* --- accent token: universam(#333) + pills(#222) leave --of-accent
       unusable on dark; re-assert the canonical dark accent. Feeds the
       apply CTA, checkbox accent-color, slider fills and the drawer
       open-button/CTA that live outside #ofilter (hence the ofa- twins). --- */
.ofilter-theme-dark.ofilter-skin-universam,
.ofilter-drawer.ofilter-theme-dark.ofa-universam,
.ofilter-drawer-open.ofilter-theme-dark.ofa-universam,
.ofilter-theme-dark.ofilter-skin-pills,
.ofilter-drawer.ofilter-theme-dark.ofa-pills,
.ofilter-drawer-open.ofilter-theme-dark.ofa-pills {
    --of-accent: #3b6ef6; --of-accent-dark: #2b57c9;
}

/* --- group / heading titles: skins hard-code #111/#333 (~1.3:1). Plain
       (0,2,0) selector beats every skin's (0,2,0) title rule by order. --- */
.ofilter-theme-dark .ofilter-group-title,
.ofilter-theme-dark .ofilter-heading-t { color: var(--of-text); }

/* colon glyph after the title - named skins only (default skin uses
   ::after as a chevron, must stay untouched). (0,3,1) beats skin (0,2,1). */
.ofilter-theme-dark.ofilter-skin-revolution .ofilter-group-title::after,
.ofilter-theme-dark.ofilter-skin-universam .ofilter-group-title::after,
.ofilter-theme-dark.ofilter-skin-market .ofilter-group-title::after { color: var(--of-text); }

/* --- star rating picker: empty stars inherit --of-border (1.58:1). The
       :not() pair keeps the (0,2,1) gold filled-star rule authoritative,
       so ONLY empty stars are recolored. (0,4,1) beats base (0,1,1). --- */
.ofilter-theme-dark .ofilter-stars-pick i:not(.ofilter-star-on):not(.ofilter-star-hover) { color: var(--of-muted); }

/* --- section dividers (skins paint near-white hairlines) --- */
.ofilter-theme-dark.ofilter-skin-revolution .ofilter-group,
.ofilter-theme-dark.ofilter-skin-revolution .ofilter-heading { border-bottom-color: var(--of-border); }
.ofilter-theme-dark.ofilter-skin-universam .ofilter-heading,
.ofilter-theme-dark.ofilter-skin-universam .ofilter-group,
.ofilter-theme-dark.ofilter-skin-universam .ofilter-rrcluster,
.ofilter-theme-dark.ofilter-skin-market .ofilter-heading,
.ofilter-theme-dark.ofilter-skin-market .ofilter-group,
.ofilter-theme-dark.ofilter-skin-market .ofilter-rrcluster,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-group,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-rrcluster { border-bottom-color: var(--of-border-light); }

/* panel frame (revolution + market draw a raw #ddd/#eaeaea ring) */
.ofilter-theme-dark.ofilter-skin-revolution,
.ofilter-theme-dark.ofilter-skin-market { border-color: var(--of-border); }

/* --- count pill: revolution paints a light #eee pill (broken); universam
       /market use #999-on-transparent (fine) and pills hides it -> rev only. --- */
.ofilter-theme-dark.ofilter-skin-revolution .ofilter-count { background-color: var(--of-chip-bg); color: var(--of-muted); }

/* --- revolution: heading icon + collapsed-group light bar/pill --- */
.ofilter-theme-dark.ofilter-skin-revolution .ofilter-heading-ico { color: var(--of-muted); }
.ofilter-theme-dark.ofilter-skin-revolution .ofilter-group.ofilter-collapsed .ofilter-group-title { background-color: transparent; }
.ofilter-theme-dark.ofilter-skin-revolution .ofilter-group.ofilter-collapsed .ofilter-group-title:hover { background-color: var(--of-bg-soft); }
.ofilter-theme-dark.ofilter-skin-revolution .ofilter-group.ofilter-collapsed .ofilter-group-title::before { background-color: var(--of-bg-soft); }

/* --- reset buttons (universam + market draw near-white bars) --- */
.ofilter-theme-dark.ofilter-skin-universam .ofilter-reset,
.ofilter-theme-dark.ofilter-skin-universam .ofilter-reset:hover,
.ofilter-theme-dark.ofilter-skin-universam .ofilter-reset:focus,
.ofilter-theme-dark.ofilter-skin-market .ofilter-reset {
    background: var(--of-bg-soft); color: var(--of-text); border-color: var(--of-border);
}
.ofilter-theme-dark.ofilter-skin-market .ofilter-reset:hover,
.ofilter-theme-dark.ofilter-skin-market .ofilter-reset:focus { background: var(--of-border); color: var(--of-text); }
.ofilter-theme-dark.ofilter-skin-universam .ofilter-reset-top { color: var(--of-muted); }
.ofilter-theme-dark.ofilter-skin-universam .ofilter-reset-top:hover,
.ofilter-theme-dark.ofilter-skin-universam .ofilter-reset-top:focus,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-reset-top:hover,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-reset-top:focus { color: var(--of-text); }

/* --- pills skin: apply CTA + pill chips painted raw #222/#f2f2f2 --- */
.ofilter-theme-dark.ofilter-skin-pills .ofilter-apply { background: var(--of-accent); border-color: var(--of-accent); }
.ofilter-theme-dark.ofilter-skin-pills .ofilter-apply:hover,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-apply:focus { background: var(--of-accent-dark); border-color: var(--of-accent-dark); }
/* pills: bg lives on the LABEL (the flex pill) now; name keeps only the text colour, and the
   checked accent paints name + count so the whole pill (incl. the count's right half) darkens. */
.ofilter-theme-dark.ofilter-skin-pills .ofilter-value > label,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-instock > label,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-reviews > label,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-new > label,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-discount > label,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-photo > label { background: var(--of-chip-bg); }
.ofilter-theme-dark.ofilter-skin-pills .ofilter-value .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-instock .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-reviews .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-new .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-discount .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-photo .ofilter-name { color: var(--of-text); }
.ofilter-theme-dark.ofilter-skin-pills .ofilter-value > label:hover,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-instock > label:hover,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-reviews > label:hover,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-new > label:hover,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-discount > label:hover,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-photo > label:hover { background: var(--of-border); }
.ofilter-theme-dark.ofilter-skin-pills .ofilter-value input:checked ~ .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-instock input:checked ~ .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-reviews input:checked ~ .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-new input:checked ~ .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-discount input:checked ~ .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-photo input:checked ~ .ofilter-name,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-value input:checked ~ .ofilter-count,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-instock input:checked ~ .ofilter-count,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-reviews input:checked ~ .ofilter-count,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-new input:checked ~ .ofilter-count,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-discount input:checked ~ .ofilter-count,
.ofilter-theme-dark.ofilter-skin-pills .ofilter-photo input:checked ~ .ofilter-count { background: var(--of-accent); }

/* =====================================================================
   ionRangeSlider - each skin paints it with its own raw hex, so these
   stay skin-scoped (values genuinely differ per skin).
   ===================================================================== */

/* revolution: teal accent bar + filled bubbles with dark bubble text
   (#1b1e24 raw: revolution --of-accent is teal #23a1d1, no on-accent token) */
.ofilter-theme-dark.ofilter-skin-revolution .irs-bar,
.ofilter-theme-dark.ofilter-skin-revolution .irs-bar-edge { background: var(--of-accent); }
.ofilter-theme-dark.ofilter-skin-revolution .irs-from,
.ofilter-theme-dark.ofilter-skin-revolution .irs-to,
.ofilter-theme-dark.ofilter-skin-revolution .irs-single { background: var(--of-accent); color: #1b1e24; }
.ofilter-theme-dark.ofilter-skin-revolution .irs-from::after,
.ofilter-theme-dark.ofilter-skin-revolution .irs-to::after,
.ofilter-theme-dark.ofilter-skin-revolution .irs-single::after { border-top-color: var(--of-accent); }

/* handle body + outline: revolution + universam share bg-soft + muted edge */
.ofilter-theme-dark.ofilter-skin-revolution .irs-slider,
.ofilter-theme-dark.ofilter-skin-universam .irs-slider { background: var(--of-bg-soft); border-color: var(--of-muted); }

/* universam bar is grey (muted, not accent); kill the light inset highlight */
.ofilter-theme-dark.ofilter-skin-universam .irs-bar,
.ofilter-theme-dark.ofilter-skin-universam .irs-bar-edge { background: var(--of-muted); box-shadow: none; }

/* pills: accent bar/edge/handle (handle has border:0 -> accent IS the knob) */
.ofilter-theme-dark.ofilter-skin-pills .irs-bar,
.ofilter-theme-dark.ofilter-skin-pills .irs-bar-edge,
.ofilter-theme-dark.ofilter-skin-pills .irs-slider { background: var(--of-accent); }

/* ghost rails: revolution/universam/market use a bordered hollow rail... */
.ofilter-theme-dark.ofilter-skin-revolution .irs-line,
.ofilter-theme-dark.ofilter-skin-universam .irs-line,
.ofilter-theme-dark.ofilter-skin-market .irs-line { border-color: var(--of-border); }
/* ...pills uses a FILLED rail (background, not border) */
.ofilter-theme-dark.ofilter-skin-pills .irs-line { background: var(--of-border-light); }

/* price bubbles, light text: universam/market/pills. Only `color` here — market and pills paint
   their plate with var(--of-bg), which the dark token block has already re-pointed. */
.ofilter-theme-dark.ofilter-skin-universam .irs-from,
.ofilter-theme-dark.ofilter-skin-universam .irs-to,
.ofilter-theme-dark.ofilter-skin-universam .irs-single,
.ofilter-theme-dark.ofilter-skin-market .irs-from,
.ofilter-theme-dark.ofilter-skin-market .irs-to,
.ofilter-theme-dark.ofilter-skin-market .irs-single,
.ofilter-theme-dark.ofilter-skin-pills .irs-from,
.ofilter-theme-dark.ofilter-skin-pills .irs-to,
.ofilter-theme-dark.ofilter-skin-pills .irs-single { color: var(--of-text); }

/* scale tick poles (universam + market) */
.ofilter-theme-dark.ofilter-skin-universam .irs-grid-pol,
.ofilter-theme-dark.ofilter-skin-market .irs-grid-pol { background: var(--of-border); }

/* =====================================================================
   AUTO MODE MIRROR - same rules, .ofilter-theme-auto, only when the OS
   prefers dark. Keeps auto theme in lockstep with the explicit dark class.
   ===================================================================== */
@media (prefers-color-scheme: dark) {
    /* --- tokens: histogram fills --- */
    .ofilter-theme-auto,
    .ofilter-drawer.ofilter-theme-auto,
    .ofilter-drawer-open.ofilter-theme-auto {
        --of-hist: #333a45;
        --of-hist-on: var(--of-accent);
    }

    /* --- native chrome --- */
    .ofilter-theme-auto { color-scheme: dark; }

    /* --- accent token: universam + pills --- */
    .ofilter-theme-auto.ofilter-skin-universam,
    .ofilter-drawer.ofilter-theme-auto.ofa-universam,
    .ofilter-drawer-open.ofilter-theme-auto.ofa-universam,
    .ofilter-theme-auto.ofilter-skin-pills,
    .ofilter-drawer.ofilter-theme-auto.ofa-pills,
    .ofilter-drawer-open.ofilter-theme-auto.ofa-pills {
        --of-accent: #3b6ef6; --of-accent-dark: #2b57c9;
    }

    /* --- group / heading titles --- */
    .ofilter-theme-auto .ofilter-group-title,
    .ofilter-theme-auto .ofilter-heading-t { color: var(--of-text); }

    /* colon glyph after the title - named skins only */
    .ofilter-theme-auto.ofilter-skin-revolution .ofilter-group-title::after,
    .ofilter-theme-auto.ofilter-skin-universam .ofilter-group-title::after,
    .ofilter-theme-auto.ofilter-skin-market .ofilter-group-title::after { color: var(--of-text); }

    /* --- star rating picker (empty stars only) --- */
    .ofilter-theme-auto .ofilter-stars-pick i:not(.ofilter-star-on):not(.ofilter-star-hover) { color: var(--of-muted); }

    /* --- section dividers --- */
    .ofilter-theme-auto.ofilter-skin-revolution .ofilter-group,
    .ofilter-theme-auto.ofilter-skin-revolution .ofilter-heading { border-bottom-color: var(--of-border); }
    .ofilter-theme-auto.ofilter-skin-universam .ofilter-heading,
    .ofilter-theme-auto.ofilter-skin-universam .ofilter-group,
    .ofilter-theme-auto.ofilter-skin-universam .ofilter-rrcluster,
    .ofilter-theme-auto.ofilter-skin-market .ofilter-heading,
    .ofilter-theme-auto.ofilter-skin-market .ofilter-group,
    .ofilter-theme-auto.ofilter-skin-market .ofilter-rrcluster,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-group,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-rrcluster { border-bottom-color: var(--of-border-light); }

    /* panel frame */
    .ofilter-theme-auto.ofilter-skin-revolution,
    .ofilter-theme-auto.ofilter-skin-market { border-color: var(--of-border); }

    /* --- count pill (revolution only) --- */
    .ofilter-theme-auto.ofilter-skin-revolution .ofilter-count { background-color: var(--of-chip-bg); color: var(--of-muted); }

    /* --- revolution: heading icon + collapsed group --- */
    .ofilter-theme-auto.ofilter-skin-revolution .ofilter-heading-ico { color: var(--of-muted); }
    .ofilter-theme-auto.ofilter-skin-revolution .ofilter-group.ofilter-collapsed .ofilter-group-title { background-color: transparent; }
    .ofilter-theme-auto.ofilter-skin-revolution .ofilter-group.ofilter-collapsed .ofilter-group-title:hover { background-color: var(--of-bg-soft); }
    .ofilter-theme-auto.ofilter-skin-revolution .ofilter-group.ofilter-collapsed .ofilter-group-title::before { background-color: var(--of-bg-soft); }

    /* --- reset buttons --- */
    .ofilter-theme-auto.ofilter-skin-universam .ofilter-reset,
    .ofilter-theme-auto.ofilter-skin-universam .ofilter-reset:hover,
    .ofilter-theme-auto.ofilter-skin-universam .ofilter-reset:focus,
    .ofilter-theme-auto.ofilter-skin-market .ofilter-reset {
        background: var(--of-bg-soft); color: var(--of-text); border-color: var(--of-border);
    }
    .ofilter-theme-auto.ofilter-skin-market .ofilter-reset:hover,
    .ofilter-theme-auto.ofilter-skin-market .ofilter-reset:focus { background: var(--of-border); color: var(--of-text); }
    .ofilter-theme-auto.ofilter-skin-universam .ofilter-reset-top { color: var(--of-muted); }
    .ofilter-theme-auto.ofilter-skin-universam .ofilter-reset-top:hover,
    .ofilter-theme-auto.ofilter-skin-universam .ofilter-reset-top:focus,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-reset-top:hover,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-reset-top:focus { color: var(--of-text); }

    /* --- pills skin: apply CTA + pill chips --- */
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-apply { background: var(--of-accent); border-color: var(--of-accent); }
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-apply:hover,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-apply:focus { background: var(--of-accent-dark); border-color: var(--of-accent-dark); }
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-value > label,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-instock > label,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-reviews > label,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-new > label,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-discount > label,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-photo > label { background: var(--of-chip-bg); }
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-value .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-instock .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-reviews .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-new .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-discount .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-photo .ofilter-name { color: var(--of-text); }
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-value > label:hover,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-instock > label:hover,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-reviews > label:hover,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-new > label:hover,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-discount > label:hover,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-photo > label:hover { background: var(--of-border); }
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-value input:checked ~ .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-instock input:checked ~ .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-reviews input:checked ~ .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-new input:checked ~ .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-discount input:checked ~ .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-photo input:checked ~ .ofilter-name,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-value input:checked ~ .ofilter-count,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-instock input:checked ~ .ofilter-count,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-reviews input:checked ~ .ofilter-count,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-new input:checked ~ .ofilter-count,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-discount input:checked ~ .ofilter-count,
    .ofilter-theme-auto.ofilter-skin-pills .ofilter-photo input:checked ~ .ofilter-count { background: var(--of-accent); }

    /* --- ionRangeSlider (skin-scoped) --- */
    .ofilter-theme-auto.ofilter-skin-revolution .irs-bar,
    .ofilter-theme-auto.ofilter-skin-revolution .irs-bar-edge { background: var(--of-accent); }
    .ofilter-theme-auto.ofilter-skin-revolution .irs-from,
    .ofilter-theme-auto.ofilter-skin-revolution .irs-to,
    .ofilter-theme-auto.ofilter-skin-revolution .irs-single { background: var(--of-accent); color: #1b1e24; }
    .ofilter-theme-auto.ofilter-skin-revolution .irs-from::after,
    .ofilter-theme-auto.ofilter-skin-revolution .irs-to::after,
    .ofilter-theme-auto.ofilter-skin-revolution .irs-single::after { border-top-color: var(--of-accent); }

    .ofilter-theme-auto.ofilter-skin-revolution .irs-slider,
    .ofilter-theme-auto.ofilter-skin-universam .irs-slider { background: var(--of-bg-soft); border-color: var(--of-muted); }

    .ofilter-theme-auto.ofilter-skin-universam .irs-bar,
    .ofilter-theme-auto.ofilter-skin-universam .irs-bar-edge { background: var(--of-muted); box-shadow: none; }

    .ofilter-theme-auto.ofilter-skin-pills .irs-bar,
    .ofilter-theme-auto.ofilter-skin-pills .irs-bar-edge,
    .ofilter-theme-auto.ofilter-skin-pills .irs-slider { background: var(--of-accent); }

    .ofilter-theme-auto.ofilter-skin-revolution .irs-line,
    .ofilter-theme-auto.ofilter-skin-universam .irs-line,
    .ofilter-theme-auto.ofilter-skin-market .irs-line { border-color: var(--of-border); }
    .ofilter-theme-auto.ofilter-skin-pills .irs-line { background: var(--of-border-light); }

    .ofilter-theme-auto.ofilter-skin-universam .irs-from,
    .ofilter-theme-auto.ofilter-skin-universam .irs-to,
    .ofilter-theme-auto.ofilter-skin-universam .irs-single,
    .ofilter-theme-auto.ofilter-skin-market .irs-from,
    .ofilter-theme-auto.ofilter-skin-market .irs-to,
    .ofilter-theme-auto.ofilter-skin-market .irs-single,
    .ofilter-theme-auto.ofilter-skin-pills .irs-from,
    .ofilter-theme-auto.ofilter-skin-pills .irs-to,
    .ofilter-theme-auto.ofilter-skin-pills .irs-single { color: var(--of-text); }

    .ofilter-theme-auto.ofilter-skin-universam .irs-grid-pol,
    .ofilter-theme-auto.ofilter-skin-market .irs-grid-pol { background: var(--of-border); }
}

/* =====================================================================
   feature: value-search — long value lists: in-group search + "show all" cap
   ===================================================================== */

/* !important: the pills skin sets .ofilter-value{display:flex} at higher specificity (see the
   collapse gotcha), so a plain display:none would lose the cascade race. */
.ofilter-value.ofilter-vhidden { display: none !important; }

/* display/width are explicit because the value list may be a multi-column container (feature:
   value-columns), where the wrap is column-spanned and must still occupy the full width. */
.ofilter-vsearch-wrap { margin: 0 0 4px; display: block; width: 100%; }
.ofilter-vsearch {
    width: 100%; box-sizing: border-box;
    padding: 6px 9px; font-size: 13px; line-height: 1.3;
    color: var(--of-text, #222);
    background: var(--of-bg, #fff);
    border: 1px solid var(--of-border, #ddd);
    border-radius: var(--of-radius, 6px);
}
.ofilter-vsearch:focus { border-color: var(--of-accent, #3b6ef6); outline: none; }
.ofilter-vsearch::-webkit-search-cancel-button { cursor: pointer; }

/* Matched fragment inside a value name. UA default for <mark> is black-on-yellow, which fights
   every skin and is unreadable in dark mode; repaint it from the accent token instead and keep the
   weight bump as the primary signal so it still reads when colour is unavailable. */
.ofilter-name mark {
    background: transparent;
    color: inherit;
    font-weight: 700;
    padding: 0;
}
.ofilter-skin-revolution .ofilter-name mark,
.ofilter-skin-universam .ofilter-name mark,
.ofilter-skin-market .ofilter-name mark,
.ofilter-skin-pills .ofilter-name mark { color: var(--of-accent, #3b6ef6); }

/* "No matching values" — shown in place of the list while a query matches nothing. */
.ofilter-vnone {
    display: none;
    padding: 6px 0 2px;
    font-size: 13px;
    color: var(--of-muted, #777);
}
.ofilter-group-vnone .ofilter-vnone { display: block; }

.ofilter-more {
    display: inline-block; margin-top: 6px; padding: 2px 0;
    background: none; border: 0; cursor: pointer;
    font-size: 13px; color: var(--of-accent, #3b6ef6);
}
.ofilter-more:hover { text-decoration: underline; }

@media (max-width: 991px) {
    .ofilter-drawer .ofilter-more { min-height: 44px; }
    .ofilter-drawer .ofilter-vsearch { min-height: 40px; }
}

/* ==================== a11y: prefers-reduced-motion =====================
 * Vestibular safety: no rotating loader, near-instant transitions/animations.
 * Scoped to the module so the surrounding page is untouched; appended last so it
 * wins the cascade, and the duration/iteration resets carry !important so a skin
 * animation defined earlier cannot re-enable motion. */
@media (prefers-reduced-motion: reduce) {
    .ofilter-mask::after {
        -webkit-animation: none;
        animation: none;
    }
    .ofilter *,        .ofilter *::before,        .ofilter *::after,
    .ofilter-grid *,   .ofilter-grid *::before,   .ofilter-grid *::after,
    .ofilter-drawer,   .ofilter-drawer *,         .ofilter-drawer *::before,   .ofilter-drawer *::after,
    .ofilter-drawer-open, .ofilter-drawer-open::before, .ofilter-drawer-open::after {
        -webkit-animation-duration: 1ms !important;
        animation-duration: 1ms !important;
        -webkit-animation-iteration-count: 1 !important;
        animation-iteration-count: 1 !important;
        transition-duration: 1ms !important;
        transition-delay: 0s !important;
        scroll-behavior: auto !important;
    }
}

/* =====================================================================
 * feature: layout — HORIZONTAL top bar. Everything is scoped under
 * .ofilter-layout-horizontal so the vertical sidebar (+ all 5 skins +
 * dark theme) stays byte-identical. Each facet group becomes a
 * click-to-open dropdown button (JS toggles .ofilter-open, single-open,
 * click-outside close). Below 991px it degrades to a stacked inline list.
 * ===================================================================== */
.ofilter-layout-horizontal .ofilter-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
.ofilter-layout-horizontal .ofilter-heading,
.ofilter-layout-horizontal #ofilter-chips { flex: 0 0 100%; width: 100%; }
.ofilter-layout-horizontal .ofilter-group {
    position: relative;
    flex: 0 0 auto;
    width: auto;
    margin: 0;
    padding: 0;
    border: 0;
}
.ofilter-layout-horizontal .ofilter-group-title {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    padding: 8px 30px 8px 12px;
    border: 1px solid var(--of-border, #ddd);
    border-radius: var(--of-radius, 6px);
    background: var(--of-bg, #fff);
    color: var(--of-text, #222);
    white-space: nowrap;
    cursor: pointer;
    position: relative;
}
/* Neutralize every skin's decorative title pseudo so the bar button shows ONLY the horizontal
   chevron ::after: revolution paints an iOS toggle switch on ::before, universam/market a chevron
   on ::before + a colon on ::after (the ::after colon is already overridden below). Killing ::before
   here (later in the file, equal specificity) wins over all skin ::before rules. */
.ofilter-layout-horizontal .ofilter-group-title::before { content: none; }
.ofilter-layout-horizontal .ofilter-group-title::after {
    content: '';
    position: absolute;
    right: 12px;
    top: 50%;
    width: 7px;
    height: 7px;
    border: 0;
    border-right: 2px solid var(--of-muted, #888);
    border-bottom: 2px solid var(--of-muted, #888);
    background: none;
    color: transparent;
    margin: 0;
    transform: translateY(-70%) rotate(45deg);
    transition: transform .15s ease;
}
.ofilter-layout-horizontal .ofilter-group.ofilter-open > .ofilter-group-title::after {
    transform: translateY(-30%) rotate(-135deg);
}
/* DESKTOP ONLY (>= 992px), matching the JS gate `isHoriz() && innerWidth > 991`: below it the
   title click toggles .ofilter-collapsed, NOT .ofilter-open, so a dropdown rule that survived
   into the drawer would hide the panel with no way left to open it. Media-scoping is the fix
   rather than counter-rules in the max-width block below: those are generic (0,2,0) and lose to
   every skin-scoped dropdown rule, which is exactly how the pills bar shipped with its checkbox
   facets permanently invisible on mobile. */
@media (min-width: 992px) {
    .ofilter-layout-horizontal .ofilter-group-body {
        position: absolute;
        top: calc(100% + 4px);
        left: 0;
        z-index: 40;
        min-width: 240px;
        max-width: 340px;
        max-height: 60vh;
        overflow: auto;
        padding: 10px 12px;
        background: var(--of-bg, #fff);
        border: 1px solid var(--of-border, #ddd);
        border-radius: var(--of-radius, 6px);
        box-shadow: 0 6px 24px rgba(0, 0, 0, .12);
        display: none;
    }
    .ofilter-layout-horizontal .ofilter-group.ofilter-open > .ofilter-group-body { display: block; }
    .ofilter-layout-horizontal .ofilter-price .ofilter-group-body,
    .ofilter-layout-horizontal .ofilter-nslider-group .ofilter-group-body { min-width: 280px; overflow: visible; }
}
/* Apply/Reset ride the bar as an inline control of the same height as the dropdown buttons.
   `:not(.ofilter-apply-mobile)` is REQUIRED: in auto-apply mode the Apply button carries
   .ofilter-apply-mobile (base rule hides it, display:none); without the guard this display:inline-flex
   (0,3,0) would out-rank that hide (0,2,0) and wrongly show a "Показать N" button the auto mode never
   needs. Manual mode has no such class, so its Apply still gets the bar styling. */
.ofilter-layout-horizontal .ofilter-actions { flex: 0 0 auto; margin: 0; display: flex; align-items: center; gap: 8px; }
.ofilter-layout-horizontal .ofilter-actions .ofilter-apply:not(.ofilter-apply-mobile),
.ofilter-layout-horizontal .ofilter-actions .ofilter-reset {
    width: auto;
    margin: 0;
    min-height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
/* rating/instock/reviews/new/discount have no dropdown body — render inline as pill-boxes in the
   bar. The cluster is a plain run here (drop the sidebar section divider + bottom pad), and each
   box uses the SAME vertical padding as a dropdown title so every bar control lines up at ~38px. */
.ofilter-layout-horizontal .ofilter-rrcluster {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    border-bottom: 0;
    padding: 0;   /* kills the sidebar section pad that each skin sets (e.g. market 6px 10px 8px) -> pills line up */
}
/* `.ofilter-rrcluster >` prefix (0,3,0) is needed so the full pill border wins over the sidebar rule
   `.ofilter .ofilter-rrcluster > .ofilter-group { border-bottom: 0 }`, which would otherwise strip the
   box's bottom edge and leave an open-bottomed pill. */
.ofilter-layout-horizontal .ofilter-rrcluster > .ofilter-instock,
.ofilter-layout-horizontal .ofilter-rrcluster > .ofilter-reviews,
.ofilter-layout-horizontal .ofilter-rrcluster > .ofilter-new,
.ofilter-layout-horizontal .ofilter-rrcluster > .ofilter-discount,
.ofilter-layout-horizontal .ofilter-rrcluster > .ofilter-photo {
    display: flex;
    align-items: center;
    padding: 8px 12px;
    border: 1px solid var(--of-border, #ddd);
    border-radius: var(--of-radius, 6px);
    background: var(--of-bg, #fff);
}
/* strip the sidebar's 44px touch-target padding from the boolean label so the box is not oversized */
.ofilter-layout-horizontal .ofilter-instock > label,
.ofilter-layout-horizontal .ofilter-reviews > label,
.ofilter-layout-horizontal .ofilter-new > label,
.ofilter-layout-horizontal .ofilter-discount > label,
.ofilter-layout-horizontal .ofilter-photo > label {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 0;
    line-height: 1.4;
}
.ofilter-layout-horizontal .ofilter-instock input[type="checkbox"],
.ofilter-layout-horizontal .ofilter-reviews input[type="checkbox"],
.ofilter-layout-horizontal .ofilter-new input[type="checkbox"],
.ofilter-layout-horizontal .ofilter-discount input[type="checkbox"],
.ofilter-layout-horizontal .ofilter-photo input[type="checkbox"] { margin: 0; }

/* ---- HORIZONTAL cross-skin normalization ---------------------------------------------------
 * The bar reuses the sidebar skin markup, so each skin's card shell + title pseudo decorations
 * leak into the top bar. Neutralized here so horizontal renders as ONE clean bar on all 5 skins
 * (accent colours still differ). Everything scoped to .ofilter-layout-horizontal -> the vertical
 * sidebar of every skin stays byte-identical. */

/* Card skins (revolution/universam/market) box the WHOLE bar in their sidebar panel and turn the
   heading into a card header. Un-box in horizontal — a bar is a row, not a framed panel. */
.ofilter-layout-horizontal.ofilter-skin-revolution,
.ofilter-layout-horizontal.ofilter-skin-universam,
.ofilter-layout-horizontal.ofilter-skin-market {
    border: 0;
    border-radius: 0;
    box-shadow: none;
    background: none;
    padding: 0;
}
.ofilter-layout-horizontal.ofilter-skin-revolution .ofilter-heading,
.ofilter-layout-horizontal.ofilter-skin-universam .ofilter-heading,
.ofilter-layout-horizontal.ofilter-skin-market .ofilter-heading {
    background: none;
    border: 0;
    border-radius: 0;
    margin: 0 0 8px;
    padding: 0;
}

/* Skins pad .ofilter-actions as a sidebar section (revolution 10px, market 0 10px) -> the bar's
   Apply/Reset drift out of line. Zero it; the bar's flex gap handles spacing. */
.ofilter-layout-horizontal .ofilter-actions { padding: 0; }

/* Base per-type scroll cap (max-height:260px, 0,3,0) outranks the dropdown 60vh cap -> a short
   window can overflow. Re-assert 60vh for the value dropdowns. Desktop only: stacked in the
   drawer the list must not grow its own 60vh scroller inside the drawer's scroller. */
@media (min-width: 992px) {
    .ofilter-layout-horizontal .ofilter-group[data-type="checkbox"] > .ofilter-group-body,
    .ofilter-layout-horizontal .ofilter-group[data-type="radio"] > .ofilter-group-body,
    .ofilter-layout-horizontal .ofilter-group[data-type="image"] > .ofilter-group-body { max-height: 60vh; }
}

/* Skins flatten the closed-state chevron (.ofilter-collapsed ::after{transform:none}); horizontal
   still emits .ofilter-collapsed on template-collapsed groups. Restore the down-chevron when closed
   (the open state keeps its own -135deg rotation). */
.ofilter-layout-horizontal .ofilter-group.ofilter-collapsed:not(.ofilter-open) > .ofilter-group-title::after {
    -webkit-transform: translateY(-70%) rotate(45deg);
    transform: translateY(-70%) rotate(45deg);
}

/* Dropdown-button hover affordance (card skins tint their title; default has none). */
.ofilter-layout-horizontal .ofilter-group-title:hover { border-color: var(--of-muted, #aaa); }

/* universam: match the reset button to the bar (14px text + 6px radius like the dropdowns). */
.ofilter-layout-horizontal.ofilter-skin-universam .ofilter-actions .ofilter-reset {
    font-size: 14px;
    border-radius: var(--of-radius, 6px);
}
/* market: the skin stretches Apply (flex:1 1 auto; order:1) — size it to its label in the bar. */
.ofilter-layout-horizontal.ofilter-skin-market .ofilter-actions .ofilter-apply { flex: 0 0 auto; order: 0; }

/* pills: the skin force-opens value dropdowns (data-type body{display:flex}, 0,4,0), defeating the
   click-to-open bar dropdowns so every panel floats open at once. Re-hide closed panels; restore
   the wrapping pill grid + scroll cap + inner pad when open.
   DESKTOP ONLY — this pair is (0,6,0) and used to out-rank the generic (0,2,0) mobile reset, so in
   the drawer every checkbox/radio/image facet was display:none with .ofilter-open unreachable (the
   JS toggles .ofilter-collapsed below 992px): the merchant saw a column of bare group titles.
   Below 992px the skin's own `[data-type] > body { display:flex }` governs, and .ofilter-collapsed
   (0,4,0, later in the file) is what closes a group. */
@media (min-width: 992px) {
    .ofilter-layout-horizontal.ofilter-skin-pills .ofilter-group[data-type="checkbox"]:not(.ofilter-open) > .ofilter-group-body,
    .ofilter-layout-horizontal.ofilter-skin-pills .ofilter-group[data-type="radio"]:not(.ofilter-open) > .ofilter-group-body,
    .ofilter-layout-horizontal.ofilter-skin-pills .ofilter-group[data-type="image"]:not(.ofilter-open) > .ofilter-group-body { display: none; }
    .ofilter-layout-horizontal.ofilter-skin-pills .ofilter-group.ofilter-open[data-type="checkbox"] > .ofilter-group-body,
    .ofilter-layout-horizontal.ofilter-skin-pills .ofilter-group.ofilter-open[data-type="radio"] > .ofilter-group-body,
    .ofilter-layout-horizontal.ofilter-skin-pills .ofilter-group.ofilter-open[data-type="image"] > .ofilter-group-body {
        display: flex; flex-wrap: wrap; gap: 8px; max-height: 60vh; overflow: auto; padding: 10px 12px;
    }
}
/* pills: don't double-box the boolean toggles — the skin's own grey pill IS the control. */
.ofilter-layout-horizontal.ofilter-skin-pills .ofilter-rrcluster > .ofilter-instock,
.ofilter-layout-horizontal.ofilter-skin-pills .ofilter-rrcluster > .ofilter-reviews,
.ofilter-layout-horizontal.ofilter-skin-pills .ofilter-rrcluster > .ofilter-new,
.ofilter-layout-horizontal.ofilter-skin-pills .ofilter-rrcluster > .ofilter-discount,
.ofilter-layout-horizontal.ofilter-skin-pills .ofilter-rrcluster > .ofilter-photo {
    padding: 0; border: 0; background: none; border-radius: 0;
}
/* pills: keep a boolean cluster on one row (skin sets .ofilter-rating{flex:0 0 100%}). */
.ofilter-layout-horizontal.ofilter-skin-pills .ofilter-rrcluster .ofilter-rating { flex: 0 0 auto; }
/* pills: bar buttons matched to the other skins' weight/size. */
.ofilter-layout-horizontal.ofilter-skin-pills .ofilter-group-title { font-size: 14px; font-weight: 500; }

@media (max-width: 991px) {
    /* The drawer is the mobile UI — the in-page copy must not double it.
       The sidebar layout gets this for free: it mounts into the theme's column, which themes hide
       on small screens. The horizontal bar mounts into content_top, which nothing hides, so without
       this the whole filter renders full-page ABOVE the grid *and* lives in the drawer.
       Hidden, not removed: drawerOpen() moves this very node into the drawer body (leaving an
       `ofilter-origin` marker), and the rule below hands it back its display there. Sliders built
       while hidden are re-gridded by updateSliders() on open — see ofGridRebuild. */
    .ofilter-layout-horizontal { display: none; }
    .ofilter-drawer-body .ofilter-layout-horizontal { display: block; }

    /* mobile: the bar is impractical -> fall back to a plain stacked list */
    .ofilter-layout-horizontal .ofilter-form { display: block; }
    .ofilter-layout-horizontal .ofilter-group { position: static; width: auto; }
    .ofilter-layout-horizontal .ofilter-group-title {
        display: block; border: 0; border-radius: 0; padding: 8px 0; background: none; white-space: normal;
    }
    /* No chevron on the stacked list: groups start EXPANDED there (title + values, like the
       vertical sidebar), so collapsing is a bonus interaction, not the primary one. Left as it
       shipped — restoring a chevron here means giving it a working open/closed direction under
       the skins' own `.ofilter-collapsed ::after` overrides, which is a separate piece of work. */
    .ofilter-layout-horizontal .ofilter-group-title::after { content: none; }
    .ofilter-layout-horizontal .ofilter-group-body {
        position: static; display: block; min-width: 0; max-width: none; max-height: none;
        border: 0; border-radius: 0; box-shadow: none; padding: 6px 0 12px; overflow: visible;
    }

    /* Stacked, the bar is just a list — so drop the card chrome the skins give the root. A framed,
       rounded, shadowed box around a full-width mobile list reads as a stray panel. */
    .ofilter-layout-horizontal.ofilter-skin-revolution,
    .ofilter-layout-horizontal.ofilter-skin-universam,
    .ofilter-layout-horizontal.ofilter-skin-market {
        border: 0;
        border-radius: 0;
        box-shadow: none;
        padding: 0 12px;
        background: var(--of-bg, #fff);
    }
    /* Pills has a transparent root by design (the pills carry the colour). Stacked in the drawer it
       needs the page surface + the same side inset as the other skins get above. */
    .ofilter-skin-pills { background: var(--of-bg, #fff); padding: 0 12px; }

    /* Universam draws each group as a card; stacked it needs plain rows with a hairline divider. */
    .ofilter-skin-universam .ofilter-group {
        background: none;
        border: 0;
        border-bottom: 1px solid #e6e6e6;
        border-radius: 0;
        box-shadow: none;
        margin: 0;
        padding: 0;
    }

    /* The desktop bar lays the boolean label out as a flex pill; stacked it is an ordinary row.
       (`align-items` / `gap` are inert once display is block, so they are not repeated here.) */
    .ofilter-layout-horizontal .ofilter-instock > label,
    .ofilter-layout-horizontal .ofilter-reviews > label,
    .ofilter-layout-horizontal .ofilter-new > label,
    .ofilter-layout-horizontal .ofilter-discount > label,
    .ofilter-layout-horizontal .ofilter-photo > label {
        display: block;
        padding: 5px 0;
        line-height: normal;
    }

    /* The bar renders the booleans as framed pill-boxes in a flex run. Stacked, they become plain
       rows, so the cluster is a block and the boxes lose their frame — one hairline under the whole
       group is enough. (flex-wrap / gap / align-items are inert once display is block.) */
    .ofilter-layout-horizontal .ofilter-rrcluster {
        display: block;
        border-bottom: 1px solid #e6e6e6;
        padding: 6px 0 10px;
    }
    .ofilter-layout-horizontal .ofilter-rrcluster > .ofilter-instock,
    .ofilter-layout-horizontal .ofilter-rrcluster > .ofilter-reviews,
    .ofilter-layout-horizontal .ofilter-rrcluster > .ofilter-new,
    .ofilter-layout-horizontal .ofilter-rrcluster > .ofilter-discount,
    .ofilter-layout-horizontal .ofilter-rrcluster > .ofilter-photo {
        display: block;
        padding: 0;
        border: 0;
        border-radius: 0;
        background: transparent;
    }
    /* The bar zeroes the checkbox margin to keep the pill tight; a stacked row wants the sidebar's
       own spacing back. `top` is a 1px optical nudge and is safe here: every rule that HIDES these
       inputs (pills skin) pins top/left to auto at a higher specificity — see .ofilter-value-sw. */
    .ofilter-layout-horizontal .ofilter-instock input[type="checkbox"],
    .ofilter-layout-horizontal .ofilter-reviews input[type="checkbox"],
    .ofilter-layout-horizontal .ofilter-new input[type="checkbox"],
    .ofilter-layout-horizontal .ofilter-discount input[type="checkbox"],
    .ofilter-layout-horizontal .ofilter-photo input[type="checkbox"] {
        margin: 0 2px 0 0;
        vertical-align: middle;
        position: relative;
        top: -1px;
    }
}

/* =====================================================================
 * feature: value-columns — split a checkbox/radio value list into 2/3
 * columns (CSS multi-column; no markup change). Scoped so cols=1 is
 * byte-identical. The search box / "show all" / empty-state span all
 * columns; only the value run columnizes. Excludes select/slider/image.
 * ===================================================================== */
.ofilter-cols-2 .ofilter-group[data-type="checkbox"] > .ofilter-group-body,
.ofilter-cols-2 .ofilter-group[data-type="radio"] > .ofilter-group-body {
    column-count: 2;
    column-gap: 14px;
    max-height: none;
}
.ofilter-cols-3 .ofilter-group[data-type="checkbox"] > .ofilter-group-body,
.ofilter-cols-3 .ofilter-group[data-type="radio"] > .ofilter-group-body {
    column-count: 3;
    column-gap: 12px;
    max-height: none;
}
.ofilter-cols-2 .ofilter-group[data-type="checkbox"] .ofilter-value,
.ofilter-cols-2 .ofilter-group[data-type="radio"] .ofilter-value,
.ofilter-cols-3 .ofilter-group[data-type="checkbox"] .ofilter-value,
.ofilter-cols-3 .ofilter-group[data-type="radio"] .ofilter-value { break-inside: avoid; }
.ofilter-cols-2 .ofilter-vsearch-wrap, .ofilter-cols-3 .ofilter-vsearch-wrap,
.ofilter-cols-2 .ofilter-vnone, .ofilter-cols-3 .ofilter-vnone,
.ofilter-cols-2 .ofilter-more, .ofilter-cols-3 .ofilter-more { column-span: all; }
@media (max-width: 991px) {
    /* narrow (sidebar/drawer) — a 2/3-col list wraps badly, drop to 1 */
    .ofilter-cols-2 .ofilter-group > .ofilter-group-body,
    .ofilter-cols-3 .ofilter-group > .ofilter-group-body { column-count: 1; }
}

/* =====================================================================
 * feature: near (ofilter_apply_mode = 'near') — the floating
 * «Показать N товаров» pill that pops up beside the value just ticked.
 * ---------------------------------------------------------------------
 * The element lives in <body>, NOT inside .ofilter: it has to overlap the
 * product grid, which it could not do from inside the sidebar's overflow.
 * That also puts it outside the --of-* cascade, so ofilter.js copies the
 * RESOLVED token values onto the element (nearPaint) — all 5 skins, the
 * merchant's «Внешний вид» colours and the dark theme therefore follow
 * automatically, and every declaration below still carries its hard
 * fallback for browsers without custom properties.
 *
 * z-index 1035 sits above a Bootstrap fixed navbar (1030) and below the
 * modal backdrop (1040) — and far below the filter drawer (100000), which
 * suppresses the pill anyway (it has its own CTA).
 * ===================================================================== */
.ofilter-near {
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1035;
    box-sizing: border-box;
    max-width: 70vw;
    margin: 0;
    padding: 7px 14px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 400;
    line-height: 1.3;
    text-align: center;
    text-decoration: none;
    white-space: nowrap;
    /* NOT overflow:hidden - the arrow below is drawn outside the box and would be clipped away.
       The label is short and fixed in shape ("Показать N товаров"), so there is nothing to clip. */
    overflow: visible;
    color: #fff;
    background: var(--of-accent, #3b6ef6);
    border: 1px solid var(--of-accent, #3b6ef6);
    border-radius: var(--of-radius, 6px);
    box-shadow: 0 3px 12px rgba(0, 0, 0, .18);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    /* Fades BOTH ways. A transition, not an entrance animation: an animation can only play on the
       way in, and the pill disappearing instantly while the page stays put reads as a glitch.
       ofilter.js adds .ofilter-near-on one frame after the box exists, and drops the box only after
       the fade-out has had time to finish. */
    opacity: 0;
    -webkit-transform: translateX(-6px);
    transform: translateX(-6px);
    -webkit-transition: opacity .16s ease-out, -webkit-transform .16s ease-out;
    transition: opacity .16s ease-out, transform .16s ease-out;
}
.ofilter-near.ofilter-near-on {
    opacity: 1;
    -webkit-transform: none;
    transform: none;
}
/* Slide in from the side the pill points at, so the motion reads as "out of that row". */
.ofilter-near-r { -webkit-transform: translateX(6px); transform: translateX(6px); }
.ofilter-near-t { -webkit-transform: translateY(-6px); transform: translateY(-6px); }

/* The little arrow. Which edge it grows from is set by ofilter.js together with the position:
   -l  pill sits to the RIGHT of the anchor (the usual case) - arrow on the left
   -r  pill was flipped to the LEFT (no room on the right)   - arrow on the right
   -t  pill sits BELOW (horizontal top bar, or a stacked narrow sidebar) - arrow on top */
.ofilter-near::before {
    content: '';
    position: absolute;
    width: 0;
    height: 0;
    border: 6px solid transparent;
}
.ofilter-near-l::before {
    left: -12px;
    top: 50%;
    margin-top: -6px;
    border-right-color: var(--of-accent, #3b6ef6);
}
.ofilter-near-r::before {
    right: -12px;
    top: 50%;
    margin-top: -6px;
    border-left-color: var(--of-accent, #3b6ef6);
}
.ofilter-near-t::before {
    top: -12px;
    left: 14px;
    border-bottom-color: var(--of-accent, #3b6ef6);
}
/* the arrow is part of the button, so it darkens with it */
.ofilter-near-l:hover::before, .ofilter-near-l:focus::before { border-right-color: var(--of-accent-dark, #2b57c9); }
.ofilter-near-r:hover::before, .ofilter-near-r:focus::before { border-left-color: var(--of-accent-dark, #2b57c9); }
.ofilter-near-t:hover::before, .ofilter-near-t:focus::before { border-bottom-color: var(--of-accent-dark, #2b57c9); }
.ofilter-near:hover,
.ofilter-near:focus {
    color: #fff;
    background: var(--of-accent-dark, #2b57c9);
    border-color: var(--of-accent-dark, #2b57c9);
}
/* keyboard focus only — matches the module's other focus-visible rings */
.ofilter-near:focus-visible {
    outline: 2px solid var(--of-accent, #3b6ef6);
    outline-offset: 2px;
}

/* Vestibular safety — the module's own prefers-reduced-motion block is scoped to the
   .ofilter, .ofilter-grid and .ofilter-drawer trees, and the pill is in <body>. Same treatment. */
@media (prefers-reduced-motion: reduce) {
    .ofilter-near,
    .ofilter-near.ofilter-near-on {
        -webkit-transition-duration: 1ms !important;
        transition-duration: 1ms !important;
        transition-delay: 0s !important;
        -webkit-transform: none !important;
        transform: none !important;
    }
}

/* Comfortable tap target on touch widths (mirrors the drawer's 40/44px minimums). */
@media (max-width: 991px) {
    .ofilter-near { min-height: 40px; padding: 9px 14px; }
}
