/* * Drawn separators, interaction states, the mobile filter sheet and checkout validation */ /* ------------------------------------------------- glyph-free separators --- */ /* * These were literal "•", "–" and "×" characters in the markup. They are * separators, not content, so they are drawn instead of typed — which also * keeps them out of the accessibility tree and out of copied text. */ .meta-separator { display: inline-block; width: 4px; height: 4px; margin: 0 10px; border-radius: 50%; background: currentColor; opacity: 0.4; vertical-align: middle; } .price-fields-separator { width: 8px; height: 1px; flex: 0 0 8px; background: var(--text-caption); } .multiply { display: inline-block; width: 8px; height: 8px; margin: 0 2px; background: currentColor; vertical-align: baseline; -webkit-mask: var(--icon-x) center / contain no-repeat; mask: var(--icon-x) center / contain no-repeat; } /* ------------------------------------------------------------ interaction --- */ /* * Hover feedback the design specifies through its own state tokens: list rows * pick up bg-select-unit-hover, muted tabs and links resolve toward * text-main / text-link-hover. */ .filter-option { padding: 0 8px; margin-inline: -8px; border-radius: var(--br-control-m); transition: background-color var(--motion-fast); cursor: pointer; } .filter-option:hover { background: var(--bg-select-unit-hover); } .tab-list a { transition: color var(--motion-fast); } .tab-list a:hover { color: var(--text-main); } .main-nav a { transition: color var(--motion-fast); } .main-nav a:hover { color: var(--text-body); } .breadcrumbs a { transition: color var(--motion-fast); } .breadcrumbs a:hover { color: var(--text-main); } .product-card-title, .cart-item-title a { transition: color var(--motion-fast); } .product-card:hover .product-card-title { color: var(--text-body); } .cart-item-remove { transition: background-color var(--motion-fast), color var(--motion-fast); } .cart-item-remove:hover { color: var(--notice-error); } /* ------------------------------------------------- mobile filter sheet --- */ /* * The design keeps filters in a sidebar on desktop but moves them into a * sheet on mobile, opened by a "Фильтр" button next to the sort control. * The sheet reuses the same form, so filtering behaves identically. */ .filters-open, .filters-sheet-head, .filters-sheet-foot { display: none; } @media (max-width: 767px) { .filters-open { display: inline-flex; align-items: center; gap: 8px; padding: var(--pad-h-btn-m) var(--pad-w-text-m) var(--pad-h-btn-m) var(--pad-w-icon-m); border: 0; border-radius: var(--br-btn-l); color: var(--text-main); background: var(--bg-button-light); font: var(--control-m); transition: background-color var(--motion-fast); } .filters-open:hover { background: var(--bg-button-light-hover); } .filters-open:active { background: var(--bg-button-light-pressed); } .filters { position: fixed; z-index: 60; inset: 0; display: flex; flex-direction: column; /* The desktop rule sets align-self: start. On an absolutely positioned box that means "size to content" instead of stretching between top and bottom, which would make the sheet taller than the viewport. */ align-self: stretch; overflow: hidden; border-radius: var(--br-modal) var(--br-modal) 0 0; background: var(--bg-main); /* Kept in the DOM so the form state survives; moved out of reach until the sheet is opened. */ visibility: hidden; opacity: 0; transform: translateY(2%); transition: opacity var(--motion-slow-duration) var(--motion-slow), transform var(--motion-slow-duration) var(--motion-slow), visibility 0s linear var(--motion-slow-duration); } .filters.is-open { visibility: visible; opacity: 1; transform: none; transition-delay: 0s; } .filters-sheet-head { display: flex; padding: 16px var(--container-gutter); align-items: center; justify-content: space-between; gap: 16px; border-bottom: 1px solid var(--border-main); } .filters-sheet-title { margin: 0; font: var(--h4); letter-spacing: var(--ls-tight); } .filters-close { width: 44px; height: 44px; } .filters form { flex: 1 1 auto; padding: 0 var(--container-gutter); overflow-y: auto; overscroll-behavior: contain; } .filters .filter-group { padding: 16px 0; border-bottom: 1px solid var(--border-main); } .filters-sheet-foot { display: block; padding: 16px var(--container-gutter) calc(16px + env(safe-area-inset-bottom)); border-top: 1px solid var(--border-main); } .filters-apply { width: 100%; } body.filters-open-lock { overflow: hidden; } } .filter-input::-webkit-outer-spin-button, .filter-input::-webkit-inner-spin-button { margin: 0; appearance: none; } /* --------------------------------------------------- checkout validation --- */ /* * The design puts validation on the field itself: a red edge plus red caption * text under it, per field. It does not use a banner listing every problem, so * the WooCommerce notice group is suppressed once its errors have been mapped * onto the fields. */ .checkout-input { position: relative; } .checkout-input .field-error { display: block; margin-top: 4px; color: var(--text-negative); font: var(--caption); } .checkout-input .field-error:empty { display: none; } .checkout-input.is-error input { border-color: var(--border-input-error); box-shadow: inset 0 0 0 1px var(--border-input-error); } .checkout-input input:focus { box-shadow: inset 0 0 0 1px var(--border-input-focus); } .woocommerce-NoticeGroup-checkout.is-field-level, .checkout .woocommerce-error.is-field-level { display: none; }