/* ============================================================
   NOLIK.SU — CSS витрины.
   ============================================================
   Источник: макеты дизайнера v2.19 (home.html / catalog.html /
   product.html, NOLIK_Blue_v2_19). Стили перенесены из макетов целиком,
   чтобы страницы выглядели так, как их нарисовали, а не «примерно так».

   Из макетов НЕ перенесено (демонстрационная обвязка прототипа):
   - [data-accent="warm"] — второй демонстрационный акцент;
   - .btn.demo-hover / .btn.demo-pressed / .btn.demo-focus — состояния
     кнопок «для проверки» через кнопки прототипа;
   - .prototype-embedded / .admin-work-footer — обвязка встраивания
     прототипа в iframe и подпись «Демонстрационные данные»;
   - .technical / .designer-note — врезки «почему так» и «контракт»,
     которые в макете показывались только разработчику.

   Правила в конце файла («правила витрины») добавлены уже для сайта:
   в макете часть элементов — <button>, а на витрине это настоящие
   ссылки <a href>.
   ============================================================ */
:root{--background:#FFFFFF;--surface:#F5F7FA;--text:#162638;--muted:#586779;--line:#E4EAF1;--control:#8492A3;--primary:#1658E8;--primaryHover:#1147C2;--primaryPressed:#103B9D;--onPrimary:#FFFFFF;--primarySoft:#EAF0FF;--warm:#FFCE70;--warmHover:#FFBE49;--warmPressed:#F3AB2C;--onWarm:#17263A;--warmSoft:#FFF4DC;--success:#167149;--successSoft:#E9F6EE;--warning:#805300;--warningSoft:#FFF2D3;--danger:#B52A3B;--dangerSoft:#FFF0F2;--focus:#1658E8;--shadow:0 8px 32px rgba(27,53,87,.07);--font:Arial,sans-serif;--radius-card:20px;--radius-button:12px;--control-height:52px;--content-max:1280px;--space-section:48px;}


*{box-sizing:border-box}body{margin:0;color:var(--text);background:white;font:16px/1.5 var(--font)}button,input,select,textarea{font:inherit}button,a,input,select,textarea{-webkit-tap-highlight-color:transparent}button{cursor:pointer}a{color:inherit;text-decoration:none}button:disabled{cursor:not-allowed}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,summary:focus-visible{outline:3px solid var(--focus);outline-offset:3px}h1,h2,h3,p{margin:0}h1{font-size:40px;letter-spacing:-1.4px;line-height:1.16}h2{font-size:26px;line-height:1.25;letter-spacing:-.5px}h3{font-size:18px;line-height:1.4}small,.small{font-size:13px;line-height:1.5}.muted{color:var(--muted)}.icon{width:22px;height:22px;flex-shrink:0;vertical-align:middle}.wrap{max-width:var(--content-max);margin:auto;padding:0 32px}.topbar{background:var(--surface);font-size:13px}.topbar .wrap{display:flex;justify-content:space-between;align-items:center;min-height:38px}.top-links{display:flex;gap:24px}.top-links a{border:0;background:none;min-height:38px;color:var(--muted)}.main-head{display:flex;align-items:center;gap:24px;padding-top:22px;padding-bottom:22px}.logo{width:154px;height:50px;object-fit:contain}.search{display:flex;align-items:center;flex:1;border-radius:14px;background:var(--surface);padding:4px 6px 4px 16px;min-width:0}.search input{border:0;background:none;min-width:0;flex:1;height:44px;width:100%;outline-offset:0}.search button{border:0;background:none;min-width:44px;height:44px;color:var(--text)}.head-action{border:0;background:none;display:flex;flex-direction:column;align-items:center;gap:3px;min-width:60px;min-height:48px;font-size:12px;color:var(--text)}.nav-cats{display:flex;gap:28px;align-items:center;padding-bottom:20px;font-size:14px;overflow:auto;white-space:nowrap}.nav-cats a{background:none;border:0;padding:8px 0;min-height:44px;color:var(--muted)}.nav-cats .nav-active{color:var(--primary);font-weight:bold}.btn{border:0;border-radius:var(--radius-button);min-height:48px;padding:12px 20px;display:inline-flex;justify-content:center;align-items:center;gap:10px;font-weight:bold;background:var(--primary);color:var(--onPrimary);white-space:normal;line-height:1.3;transition:background .15s,transform .15s}.btn:hover{background:var(--primaryHover)}.btn:active{background:var(--primaryPressed);transform:translateY(1px)}.btn.secondary{background:var(--primarySoft);color:var(--text)}.btn.secondary:hover{background:#dbe5f5}.btn.ghost{background:transparent;color:var(--text)}.btn.ghost:hover{background:var(--surface)}.btn.danger{background:var(--danger);color:white}.btn:disabled{background:#E7ECF1;color:#617082}.btn.wide{width:100%}.btn.icon-btn{min-width:48px;padding:12px}.btn.loading:before{content:'';width:17px;height:17px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin 1s linear infinite}.crumbs{display:flex;gap:10px;font-size:13px;color:var(--muted);padding-top:22px;padding-bottom:24px}.crumbs a,.crumbs span{padding:0;background:none;border:0;color:inherit;min-height:26px}.page-title{display:flex;align-items:baseline;gap:18px;margin-bottom:24px}.category-chips{display:flex;gap:10px;overflow:auto;margin:0 0 30px;padding-bottom:5px}.chip{display:inline-flex;align-items:center;justify-content:center;padding:10px 16px;border:0;background:var(--surface);border-radius:99px;white-space:nowrap;min-height:44px;color:var(--text)}.chip.active{background:var(--primarySoft);font-weight:bold}.catalog{display:grid;grid-template-columns:224px minmax(0,1fr);gap:32px}.filters{padding:8px 14px 0 0}.filter-group{margin-bottom:28px}.filter-group h3{font-size:16px;margin-bottom:14px}.check{display:flex;align-items:center;gap:10px;min-height:44px;cursor:pointer}.check input{width:20px;height:20px;accent-color:#1658e8;flex-shrink:0}.filter-range{display:flex;gap:8px}.filter-range input{width:50%;min-width:0}.field,input.text,select,textarea{border:1px solid var(--control);border-radius:12px;padding:12px 14px;min-height:52px;background:white;color:var(--text);width:100%;font-size:16px}.toolbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px;gap:12px}.toolbar select{width:auto;border:0;background:var(--surface);min-height:44px;font-size:14px}.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:28px 22px}.card{min-width:0;position:relative;padding:12px 12px 16px;border-radius:20px;background:white;box-shadow:var(--shadow);display:flex;flex-direction:column}.media{aspect-ratio:1;position:relative;background:white;border-radius:16px;overflow:hidden}.product-photo{width:100%;height:100%;object-fit:contain;display:block}.card .media{margin-bottom:14px}.fav{position:absolute;right:0;top:0;z-index:1;background:#fff;border:0;border-radius:50%;height:44px;width:44px;color:var(--muted);display:grid;place-items:center}.fav[aria-pressed=true]{color:var(--danger)}.badge{display:inline-flex;align-items:center;gap:5px;width:max-content;border-radius:8px;padding:4px 9px;font-size:12px;font-weight:bold;background:var(--primarySoft);color:var(--text)}.media .badge{position:absolute;left:0;top:3px;z-index:1}.price{font-size:26px;font-weight:800;line-height:1.3;letter-spacing:-.7px;font-variant-numeric:tabular-nums}.price .unit{font-size:13px;font-weight:normal;color:var(--muted);letter-spacing:0}/* ⚠️ Здесь ТОЛЬКО цвет и сброс кнопочных стилей. Размер, межстрочный,
   отступы и обрезку названия задаёт плитка (card_align.css). Было
   min-height:48px и две строки обрезки: из-за этого между названием
   и артикулом появлялось пустое место (26.10.2026). */
.product-name{text-align:left;background:none;border:0;padding:0;color:var(--text)}.sku{font-size:12px;color:var(--muted);margin-bottom:10px}.stock{font-size:13px;font-weight:bold;color:var(--success);display:flex;align-items:center;gap:6px;margin-bottom:16px}.stock:before{content:'';background:currentColor;width:6px;height:6px;border-radius:50%}.stock.warning{color:var(--warning)}.stock.danger{color:var(--danger)}.card .btn{margin-top:auto}.no-photo{height:100%;min-height:180px;display:flex;flex-direction:column;gap:10px;align-items:center;justify-content:center;text-align:center;background:var(--surface);border-radius:16px;color:var(--muted);padding:12px}.no-photo .icon{width:48px;height:48px;color:#8492a3}.no-photo span{font-size:14px}.no-photo small{font-size:12px}.pagination{display:flex;justify-content:center;gap:10px;margin:36px 0}.pagination a{min-width:44px}.b2b-strip{border-radius:20px;background:var(--primarySoft);display:flex;justify-content:space-between;gap:20px;align-items:center;padding:28px;margin-top:40px}.b2b-strip p{font-size:14px;margin-top:5px;color:var(--muted)}.mobile-only{display:none}.footer{margin-top:64px;padding:40px 0 28px;background:var(--surface)}.foot-grid{display:grid;grid-template-columns:1.3fr repeat(3,minmax(0,1fr)) auto;gap:30px}.foot-grid p{font-size:14px;color:var(--muted);margin:10px 0}.foot-grid a{background:none;border:0;display:block;color:var(--muted);padding:8px 0;text-align:left;min-height:44px;font-size:14px}.foot-bottom{display:flex;justify-content:space-between;font-size:12px;color:var(--muted);margin-top:30px;padding-top:24px;border-top:1px solid var(--line)}.note{background:#FFF8E7;color:#6C5019;padding:14px 18px;font-size:13px;line-height:1.6;border-radius:12px}/* ⚠️ `minmax(0, …)` обязательно: с обычными `fr` колонка с фотографией
   растягивается по натуральной ширине картинки (у новых фото она 1600 px), и вся
   сетка уезжает за экран — правая колонка сжимается (ошибка 21.10.2026). */
/* --- Количество в карточке товара: кнопки «−»/«+» внутри поля ----------------
   Требование владельца 21.10.2026: клик по кнопкам меняет количество, ввод
   с клавиатуры продолжает работать, а сообщение об ошибке показывается РЯДОМ
   с полем, а не полосой под шапкой. */
.qty-stepper{
  display:grid;
  grid-template-columns:48px minmax(0,1fr) 48px;
  align-items:stretch;
  gap:6px;
  margin-bottom:8px}
.qty-stepper__button{
  border:1px solid var(--control);
  border-radius:12px;
  background:white;
  color:var(--text);
  font-size:20px;
  line-height:1;
  min-height:52px;
  padding:0}
.qty-stepper__button:hover{background:var(--surface)}
.qty-stepper__button:active{transform:translateY(1px)}
.qty-stepper__input{
  width:100%;
  min-width:0;
  border:1px solid var(--control);
  border-radius:12px;
  padding:12px 14px;
  min-height:52px;
  font-size:16px;
  text-align:center;
  background:white;
  color:var(--text)}
/* Убираем «родные» стрелки числового поля: рядом уже есть кнопки. */
.qty-stepper__input::-webkit-outer-spin-button,
.qty-stepper__input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.qty-stepper__input[type=number]{-moz-appearance:textfield;appearance:textfield}
.qty-stepper__message{
  margin:0 0 10px;
  font-size:14px;
  line-height:1.35;
  color:var(--danger)}
.qty-stepper__message[hidden]{display:none}
/* Кнопка-исправление рядом с сообщением: «Поставить N». */
.qty-stepper__fix{
  margin:-4px 0 10px;
  border:0;
  border-radius:12px;
  background:var(--primarySoft);
  color:var(--text);
  font-size:14px;
  font-weight:bold;
  min-height:40px;
  padding:8px 14px}
.qty-stepper__fix:hover{background:#dbe5f5}
@media(max-width:767px){
  .qty-stepper{grid-template-columns:44px minmax(0,1fr) 44px}
  .qty-stepper__button{min-height:48px}
  .qty-stepper__input{min-height:48px}
}

.product-layout{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr) minmax(0,.95fr);gap:32px;align-items:start;margin-top:30px}
.product-layout > *{min-width:0}
.product-layout img{max-width:100%}.product-hero{aspect-ratio:1;background:white}/* Миниатюры фото — КАРУСЕЛЬ (предложение владельца 21.10.2026: «как карусель бренды
   на главной»): один ряд, горизонтальная прокрутка, стрелки рисует `site.js`.
   Плитки фиксированного размера — не сжимаются в полоски. */
.thumbnails{
  display:flex;
  flex-wrap:nowrap;
  gap:10px;
  overflow-x:auto;
  overflow-y:hidden;
  padding-bottom:6px;
  scroll-snap-type:x proximity;
  -webkit-overflow-scrolling:touch}
.thumbnail{scroll-snap-align:start;flex-shrink:0}
.thumbnails-rail{margin-top:18px}.thumbnail{width:70px;height:70px;padding:4px;background:#fff;border:1px solid var(--control);border-radius:12px}.overview h3{margin-bottom:20px}.mini-spec{display:flex;justify-content:space-between;gap:16px;padding:10px 0;font-size:14px}.mini-spec span:first-child{color:var(--muted)}.purchase{background:#fff;border-radius:24px;box-shadow:var(--shadow);padding:24px}.purchase .price{font-size:36px}.purchase .stock{margin:14px 0 20px}.purchase .qty{margin:20px 0}.qty{display:inline-flex;align-items:center;border-radius:12px;background:var(--surface);overflow:hidden}.qty button{width:44px;height:48px;border:0;background:none;font-size:24px;color:var(--text)}.qty input{width:52px;border:0;background:none;text-align:center;font-weight:bold;padding:0;min-height:48px;font-size:16px;-moz-appearance:textfield}.qty input::-webkit-inner-spin-button{display:none}.purchase .delivery-copy{margin:20px 0 0;font-size:14px}.delivery-copy div{display:flex;gap:10px;margin-top:14px}.detail-tabs{display:flex;gap:30px;border-bottom:1px solid var(--line);margin:46px 0 30px;overflow:auto}.detail-tabs a{padding:16px 0;white-space:nowrap;color:var(--muted);border-bottom:3px solid transparent}.detail-tabs a:hover{color:var(--text)}.detail-tabs a.is-current{color:var(--text);border-bottom-color:var(--primary);font-weight:bold}
.detail-body{display:block}.detail-panel{display:block}html.js .detail-panel{display:none}html.js .detail-panel.is-current{display:block}.spec-table{width:100%;border-collapse:collapse;margin:20px 0}.spec-table td{padding:14px 12px;font-size:15px}.spec-table tr:nth-child(odd){background:var(--surface)}.spec-table td:first-child{color:var(--muted);width:60%}.spec-table td:last-child{font-weight:bold}.detail-body p{line-height:1.8;margin:18px 0;color:var(--muted)}.two-cols{display:grid;grid-template-columns:minmax(0,1fr) 360px;gap:40px;align-items:start}.cart-item{display:grid;grid-template-columns:112px 1fr auto;gap:24px;padding:28px 0;border-bottom:1px solid var(--line)}.cart-item .item-photo{height:112px;aspect-ratio:1}.cart-item h3{font-size:17px;max-width:380px}.item-info .sku{margin-top:8px}.item-actions{display:flex;gap:14px;align-items:center;margin-top:14px}.remove{border:0;background:none;min-width:44px;min-height:44px;color:var(--muted)}.item-sum{text-align:right;padding-top:4px;font-size:22px;font-weight:bold;white-space:nowrap}.item-sum small{display:block;font-weight:normal;color:var(--muted)}.summary{padding:28px;background:white;box-shadow:var(--shadow);border-radius:24px}.summary h2{font-size:22px;margin-bottom:24px}.sum-row{display:flex;justify-content:space-between;gap:20px;font-size:14px;margin:14px 0}.sum-row.green{color:var(--success)}.sum-row.total{font-size:16px;font-weight:bold}.cash-total{display:flex;justify-content:space-between;align-items:center;margin:22px 0;font-weight:bold}.cash-total span{font-size:27px;white-space:nowrap}.sum-divider{border-top:1px solid var(--line);margin-top:18px;padding-top:5px}.summary .small{margin-top:12px}.rewards{margin-top:28px;display:grid;grid-template-columns:1fr 1fr;gap:16px}.reward{padding:24px;border-radius:20px;background:var(--primarySoft)}.reward p{font-size:14px;margin-top:8px}.reward .check{margin-top:12px}.form-section{margin-bottom:40px}.form-section h2{font-size:24px;margin-bottom:24px;display:flex;align-items:center;gap:14px}.step{display:grid;place-items:center;width:34px;height:34px;background:var(--primarySoft);border-radius:50%;font-size:16px}.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:20px}.label{display:block;font-size:14px;font-weight:bold;margin-bottom:8px}.input-wrap{min-width:0}.input-wrap .small{margin-top:6px}.full{grid-column:1/-1}.choice-row{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:24px}/* Группа вариантов выбора на оформлении (сборка заказа): fieldset без рамки,
   варианты друг под другом. */
.choice-group{
  border:0;
  margin:16px 0;
  padding:0;
  display:grid;
  gap:10px}
.choice-group .choice{width:100%}
.choice{position:relative;display:flex;align-items:center;gap:10px;background:var(--surface);padding:14px 16px;border-radius:12px;min-height:52px;cursor:pointer}.choice:has(input:checked){box-shadow:inset 0 0 0 2px var(--primary);background:var(--primarySoft)}.choice input{accent-color:#1658e8;width:18px;height:18px}.delivery-choices{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:20px}.delivery-choices .choice{align-items:flex-start}.delivery-choices small{display:block;font-weight:normal;color:var(--muted);margin-top:4px}.consent{display:flex;align-items:flex-start;gap:10px;font-size:13px;line-height:1.65;margin:24px 0}.consent input{width:20px;height:20px;flex-shrink:0;margin:1px 0;accent-color:#1658e8}.consent button{color:inherit;background:none;border:0;padding:0;text-decoration:underline;text-align:left;font:inherit}.form-error{color:var(--danger);font-size:13px;margin-top:6px}.field.invalid{border:2px solid var(--danger);background:var(--dangerSoft)}.error-banner{background:var(--dangerSoft);color:var(--danger);padding:16px;border-radius:12px;margin-bottom:20px}.empty-state{text-align:center;padding:60px 24px;background:var(--surface);border-radius:24px}.empty-state .icon{width:50px;height:50px;margin-bottom:20px}.empty-state p{margin:16px 0 24px;color:var(--muted)}[hidden]{display:none!important}.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:#162638;color:white;padding:14px 22px;border-radius:14px;box-shadow:var(--shadow);z-index:20;max-width:calc(100% - 32px);width:max-content;font-size:14px}.mobile-purchase{display:none}.dialog{border:0;padding:28px;border-radius:24px;max-width:calc(100% - 32px);width:460px;color:var(--text);box-shadow:var(--shadow)}.dialog::backdrop{background:#16263866}.dialog h2{margin-bottom:14px}.dialog .close{float:right}.dialog p{margin:14px 0;color:var(--muted)}.ds-title{margin-bottom:18px}.ds-intro{max-width:760px;font-size:18px;color:var(--muted);margin:20px 0 32px}.ds-section{margin:48px 0}.ds-section>h2{margin-bottom:16px}.ds-section>p{color:var(--muted);margin:12px 0 24px}.swatches{display:grid;grid-template-columns:repeat(6,1fr);gap:16px}.swatch{border-radius:16px;overflow:hidden;background:var(--surface)}.swatch-color{height:80px}.swatch-text{padding:12px;font-size:13px}.component-row{display:flex;flex-wrap:wrap;gap:20px;margin:24px 0;align-items:center}.sample{display:flex;flex-direction:column;align-items:center;gap:12px}.sample>small{color:var(--muted)}.compare{display:grid;grid-template-columns:1fr 1fr;gap:24px}.compare-panel{padding:28px;border-radius:24px;background:var(--surface)}.compare-panel h3{margin-bottom:12px}.compare-panel p{font-size:14px;margin:12px 0;color:var(--muted)}.comparison-card{max-width:280px}.ds-table{border-collapse:collapse;width:100%;font-size:14px}.ds-table th,.ds-table td{text-align:left;padding:16px;border-bottom:1px solid var(--line);vertical-align:top}.ds-table th{background:var(--surface)}.ds-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}.state-card{background:var(--surface);padding:24px;border-radius:20px}.state-card h3{margin-bottom:14px}.state-card p{font-size:14px;color:var(--muted);margin:12px 0}.otp{display:flex;gap:12px}.otp span{width:52px;height:56px;border:1px solid var(--control);border-radius:12px;display:grid;place-items:center;font-size:24px}.skeleton{height:18px;background:#DEE5EF;border-radius:8px;margin:14px 0}.skeleton.big{height:140px}.state-card .btn{margin-top:10px}.quick-form{display:flex;gap:12px;margin:20px 0}.quick-form input{flex:1;min-width:0}.quick-form input[type=number]{max-width:90px}.hidden-img .product-photo{display:none}.hidden-img .image-fallback{display:block!important}.image-fallback{height:100%;display:none}.no-photo-page .single-card{max-width:300px}.demo-label{font-size:12px;color:var(--muted);margin:12px 0}.intro-flag{display:inline-flex;padding:6px 12px;border-radius:99px;background:var(--primarySoft);font-size:12px;font-weight:bold;margin-bottom:20px}.soft-link{background:none;border:0;padding:0;min-height:44px;color:var(--text);font-weight:bold;text-decoration:underline;text-underline-offset:5px}.gallery-actions{display:flex;gap:12px;margin-top:16px}.download-row{display:flex;gap:12px;flex-wrap:wrap}.subhead{color:var(--muted);margin:12px 0 28px}.inline-why{margin-top:16px;color:var(--muted);font-size:13px}.discount-tag{background:var(--dangerSoft);color:var(--danger)}.link{color:#1658e8;text-decoration:underline;text-underline-offset:3px}.nowrap{white-space:nowrap}@keyframes spin{to{transform:rotate(360deg)}}
@media(max-width:1100px){.main-head{gap:16px}.head-action{min-width:44px}.catalog{grid-template-columns:190px minmax(0,1fr);gap:20px}.grid{gap:20px 12px}.wrap{padding:0 24px}.product-layout{grid-template-columns:1fr 1fr}.overview{grid-row:2;grid-column:1/-1}.mini-spec{max-width:550px}.two-cols{grid-template-columns:minmax(0,1fr) 320px;gap:24px}.cart-item{grid-template-columns:84px 1fr;gap:16px}.cart-item .item-photo{height:84px}.item-sum{grid-column:2;text-align:left}.item-sum small{display:inline;margin-left:12px}.nav-cats{gap:20px}.foot-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.swatches{grid-template-columns:repeat(3,1fr)}}
@media(max-width:767px){body{font-size:16px}.wrap{padding-left:16px;padding-right:16px}h1{font-size:28px;letter-spacing:-.8px}h2{font-size:24px}.topbar .wrap{min-height:30px;font-size:12px}.top-links{gap:12px}.top-links a{font-size:12px;min-height:30px}.top-links a:not(:first-child){display:none}.main-head{padding-top:14px;padding-bottom:14px;flex-wrap:wrap;gap:12px}.logo{width:130px;height:42px}.main-head>.catalog-btn{display:none}.head-action{margin-left:auto;min-width:44px}.head-action~.head-action{margin-left:0}.head-action.user-action{display:none}.search{flex-basis:100%;order:5;border-radius:12px;min-height:52px}.nav-cats{padding-bottom:10px;gap:22px;font-size:13px}.nav-cats a{font-size:13px}.crumbs{padding-top:16px;padding-bottom:20px;font-size:12px;white-space:nowrap;overflow:auto}.page-title{display:block;margin-bottom:22px}.page-title .muted{display:block;font-size:13px;margin-top:8px}.category-chips{margin-bottom:22px;gap:8px}.chip{font-size:13px;padding:10px 14px}.catalog{display:block}.filters{display:none}.mobile-only{display:initial}.toolbar{margin-bottom:22px}.toolbar .result-count{display:none}.toolbar .btn{font-size:14px;min-height:44px;padding:10px 14px}.toolbar select{max-width:190px;min-width:0;padding:10px 12px}.grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:24px 12px}.card{padding:8px 8px 12px;border-radius:16px;box-shadow:0 4px 18px #1b35570a}.card .media{margin-bottom:12px}.card .price{font-size:22px}.card .price .unit{display:block;font-size:12px;margin-top:3px}.card .product-name{font-size:14px;line-height:1.3}.card .sku{font-size:12px}.card .btn{font-size:14px;padding:12px 8px;gap:6px;min-height:48px}.card .btn .icon{width:18px;height:18px}.card .stock{font-size:12px;min-height:36px;margin-bottom:12px;align-items:flex-start}.card .stock:before{margin-top:6px;flex-shrink:0}.media .badge{font-size:12px;padding:4px 6px}.fav{height:44px;width:44px;right:-4px;top:-4px}.no-photo{min-height:140px}.no-photo small{display:none}.no-photo .icon{width:34px;height:34px}.no-photo span{font-size:12px}.b2b-strip{padding:24px;display:block;margin-top:28px}.b2b-strip .btn{margin-top:18px;width:100%}.footer{margin-top:40px;padding-top:30px}.foot-grid{gap:24px 16px}.foot-grid>div:first-child{grid-column:1/-1}.foot-grid p{font-size:13px}.foot-grid h3{font-size:16px}.foot-grid a{font-size:13px}.foot-bottom{display:block;font-size:12px}.foot-bottom span{display:block;margin-top:8px}.product-layout{display:flex;flex-direction:column;gap:26px;margin-top:20px}.gallery,.overview,.purchase{width:100%}.gallery{order:0}.purchase{order:1;padding:20px;box-shadow:var(--shadow)}.overview{order:2}.product-hero{max-height:350px}.thumbnails{justify-content:center}.product-layout .price{font-size:34px}.product-layout .purchase .stock{margin:12px 0}.detail-tabs{gap:24px;margin:30px 0 22px;font-size:14px}.detail-body{display:block}.detail-body>section{margin-bottom:32px}.detail-body p{font-size:15px}.spec-table td{font-size:14px;padding:12px 10px}.two-cols{display:flex;flex-direction:column;gap:28px}.two-cols>div,.two-cols>aside,.two-cols>form{width:100%}.cart-item{grid-template-columns:76px 1fr;gap:14px;padding:22px 0}.cart-item .item-photo{height:76px}.cart-item h3{font-size:15px;line-height:1.5}.item-actions{gap:6px;flex-wrap:wrap}.qty button{width:44px}.qty input{width:46px}.item-sum{font-size:22px;grid-column:2}.item-sum small{font-size:12px;display:block;margin-left:0}.rewards{display:block}.reward{margin-top:16px;padding:20px}.summary{padding:24px}.cash-total{font-size:15px}.cash-total span{font-size:26px}.form-grid{display:block}.input-wrap{margin-bottom:20px}.form-section{margin-bottom:32px}.form-section h2{font-size:22px;margin-bottom:22px}.choice-row{gap:8px}.choice-row .choice{font-size:14px;padding:12px}.delivery-choices{grid-template-columns:1fr}.delivery-choices .choice{padding:16px}.mobile-purchase{position:sticky;bottom:0;display:flex;justify-content:space-between;align-items:center;gap:16px;background:white;box-shadow:0 -4px 24px #1b355712;padding:12px 16px;z-index:5;margin-top:28px}.mobile-purchase .price{font-size:24px}.mobile-purchase small{display:block;color:var(--muted);font-size:12px}.mobile-purchase .btn{min-width:160px}.ds-intro{font-size:16px}.compare{grid-template-columns:1fr}.swatches{grid-template-columns:repeat(2,1fr);gap:12px}.ds-grid{grid-template-columns:1fr}.ds-table{font-size:13px}.ds-table td,.ds-table th{padding:12px 8px}.component-row{gap:22px 14px}.ds-section{margin:36px 0}.compare-panel{padding:22px}.quick-form{flex-wrap:wrap}.quick-form .btn{width:100%}.toast{bottom:16px}.dialog{padding:24px}.page-title .btn{margin-top:16px}.desktop-only{display:none}.note{padding:12px;font-size:12px}}
@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important;scroll-behavior:auto!important}}

.topbar .wrap,.top-links a{min-height:44px}.crumbs a{min-height:44px}summary{min-height:44px;display:list-item;padding:10px 0}.topbar .wrap{gap:12px}.filter-range input{padding-left:10px;padding-right:4px}

.content{padding-top:32px;padding-bottom:12px}.eyebrow{font-size:12px;letter-spacing:1.2px;font-weight:bold;color:#1658e8;text-transform:uppercase;margin-bottom:14px}.lead{font-size:18px;line-height:1.7;color:var(--muted);margin:18px 0 28px;max-width:720px}.home-hero{display:grid;grid-template-columns:1.25fr 1fr;align-items:center;gap:32px;padding:48px;background:#eaf0ff;border-radius:28px;overflow:hidden}.home-hero h1{font-size:52px;letter-spacing:-1.8px;max-width:600px}.home-hero .hero-art{background:white;aspect-ratio:1;border-radius:50%;padding:25px}.home-hero .btn{min-height:52px}.section{margin:44px 0}.section-title{display:flex;justify-content:space-between;align-items:center;gap:24px;margin-bottom:22px}.section-title .btn{font-size:14px}.home-products{display:grid;grid-template-columns:repeat(4,1fr);gap:24px}.category-empty{padding:26px;background:var(--surface);border-radius:20px;display:flex;align-items:center;gap:20px}.benefits{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}.benefit{padding:24px 0}.benefit h3{margin:12px 0}.benefit p{color:var(--muted);font-size:14px}.auth-layout{max-width:1030px;margin:36px auto 48px;display:grid;grid-template-columns:1fr 1fr;gap:64px;align-items:center}.auth-story{padding:28px}.auth-story h1{font-size:44px;line-height:1.12}.auth-story .auth-art{height:220px;margin-top:30px;object-fit:contain}.auth-card{padding:36px;background:white;border-radius:24px;box-shadow:var(--shadow)}.auth-card h1{font-size:30px;letter-spacing:-.7px;margin-bottom:12px}.auth-card h2{margin-bottom:10px}.auth-card .input-wrap{margin:24px 0}.auth-card .btn.wide{margin-top:8px}/* Кнопки под пин-кодом: три штуки в ОДИН ряд, текст в одну строку, подсказка —
   отдельной строкой снизу (требование владельца 21.10.2026). */
.auth-links{display:flex;flex-wrap:wrap;justify-content:flex-start;gap:10px;align-items:center;font-size:14px;margin:16px 0}
.auth-links > form{margin:0}
.auth-links .btn{white-space:nowrap}
.auth-links > p{flex:0 0 100%;order:10;margin:2px 0 0}

/* ⚠️ БЕЗ СЕТКИ ИЗ ТРЁХ КОЛОНОК (дефект 28.10.2026): на экране ввода кода
   кнопка «Отправить код ещё раз» налезала на ссылку «Изменить номер».
   Причина — сетка из трёх равных колонок для двух элементов: кнопке доставалась
   треть ширины, а её текст не переносится и вылезал поверх соседней ссылки.
   Теперь строка с переносом: каждый элемент занимает нужную ему ширину. */
@media(min-width:768px){
  .auth-links{
    display:flex;
    flex-wrap:wrap;
    gap:12px 16px;
    align-items:center}
  .auth-links > form{
    margin:0}
  .auth-links > form .btn{
    width:auto;
    padding:10px 16px;
    font-size:14px;
    white-space:nowrap}
  .auth-links > a{
    white-space:nowrap}
  .auth-links > p{
    flex:0 0 100%;
    margin-top:4px}
}.auth-links button{font-size:14px}.password-wrap{position:relative}.password-wrap input{padding-right:80px}.password-wrap button{position:absolute;right:5px;top:4px;background:none;border:0;color:#1658e8;height:44px;padding:8px;font-size:12px}.tiny{font-size:12px;color:var(--muted)}.success-icon{width:64px;height:64px;display:grid;place-items:center;color:#167149;background:#e9f6ee;border-radius:50%;margin-bottom:22px}.success-icon .icon{width:32px;height:32px}.order-success{max-width:920px;margin:40px auto}.success-top{display:grid;grid-template-columns:1fr 1fr;gap:36px;align-items:start}.key-link{background:#eaf0ff;border-radius:24px;padding:28px}.key-link h2{font-size:22px;margin-bottom:12px}.key-value{font-size:19px;font-weight:bold;overflow-wrap:anywhere;margin:24px 0}.key-link .btn{width:100%}.delivery-status{font-size:14px;padding:14px;background:#fff;border-radius:12px;margin-top:18px;color:var(--muted)}.order-layout{display:grid;grid-template-columns:1fr 340px;gap:32px;align-items:start}.box-panel{border-radius:20px;background:white;box-shadow:var(--shadow);padding:28px;margin-bottom:24px}.box-panel h2,.box-panel h3{margin-bottom:18px}.row-data{display:flex;justify-content:space-between;gap:24px;padding:10px 0;font-size:14px}.row-data span:first-child{color:var(--muted)}.row-data strong{text-align:right}.status-pill{display:inline-flex;align-items:center;font-size:12px;font-weight:bold;padding:6px 10px;border-radius:8px;line-height:1.4;width:max-content;background:#eaf0ff;color:#1147c2}.status-pill.green,.status-pill.success{background:#e9f6ee;color:#167149}.status-pill.amber,.status-pill.warning{background:#fff2d3;color:#805300}.status-pill.red,.status-pill.danger{background:#fff0f2;color:#b52a3b}.status-pill.gray{background:#edf1f6;color:#586779}.status-line{display:flex;align-items:center;flex-wrap:wrap;gap:10px;margin:14px 0 22px}.account-shell{display:grid;grid-template-columns:216px minmax(0,1fr);gap:40px;margin:28px auto}.account-nav{padding:16px 0}.account-nav .person{margin-bottom:24px}.avatar{display:grid;place-items:center;width:52px;height:52px;border-radius:50%;background:#eaf0ff;color:#1658e8;font-size:20px;font-weight:bold;margin-bottom:12px}.account-content{min-width:0;padding-top:16px}.account-content h1{font-size:34px}.stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px;margin:26px 0}.stat{background:#f5f7fa;border-radius:20px;padding:24px}.stat .number{font-size:32px;font-weight:bold;letter-spacing:-1px;margin:10px 0}.stat small{color:#586779}.account-tiles{display:grid;grid-template-columns:repeat(2,1fr);gap:20px}.tile{padding:24px;background:white;border:0;border-radius:20px;box-shadow:var(--shadow);text-align:left;color:var(--text);min-height:150px}.tile .icon{color:#1658e8}.tile h3{margin:12px 0 6px}.tile p{font-size:14px;color:#586779}.attention{padding:20px 24px;border-radius:16px;background:#fff6e3;margin:24px 0;display:flex;gap:20px;justify-content:space-between;align-items:center}.attention p{font-size:14px;margin-top:6px;color:#805300}.attention .btn{white-space:nowrap}.order-card{padding:24px;border-radius:20px;box-shadow:var(--shadow);margin:20px 0;background:white}.order-card-top{display:flex;justify-content:space-between;align-items:flex-start;gap:20px}.order-card h3{font-size:20px}.order-card .order-meta{font-size:13px;color:#586779;margin-top:6px}.order-card .status-line{margin:16px 0}.order-amounts{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin:20px 0}.order-amounts small{display:block;color:#586779}.order-amounts strong{display:block;font-size:21px;margin-top:4px}.order-card .bottom{display:flex;justify-content:space-between;align-items:center;gap:20px}.order-thumb{height:58px;width:58px;display:inline-block;vertical-align:middle;margin-right:10px}.timeline{list-style:none;padding:0;margin:20px 0}.timeline li{position:relative;padding:0 0 24px 28px;border-left:2px solid #dce5f4;margin-left:7px}.timeline li:before{content:'';width:12px;height:12px;border-radius:50%;background:#1658e8;position:absolute;left:-7px;top:5px}.timeline li:last-child{border-color:transparent;padding-bottom:0}.timeline small{display:block;color:#586779;margin-top:4px}.order-product{display:flex;align-items:center;gap:18px;padding:18px 0;border-bottom:1px solid #e4eaf1}.order-product img{width:70px;height:70px;flex-shrink:0}.order-product .grow{flex:1;min-width:0}.order-product h3{font-size:15px;margin:0}.order-product small{display:block;color:#586779}.order-product strong{white-space:nowrap;font-size:16px}.cash-big{font-size:28px;font-weight:bold;letter-spacing:-.5px}.bonus-hero{background:#1658e8;border-radius:24px;padding:32px;color:white;display:flex;justify-content:space-between;gap:30px;align-items:center;margin-top:24px}.bonus-hero .big{font-size:48px;font-weight:bold;letter-spacing:-1px;margin:8px 0}.bonus-hero .btn{background:white;color:#1658e8}.bonus-hero p{color:#e3ebff;font-size:14px}.bonus-actions{display:flex;gap:12px;flex-wrap:wrap;margin:24px 0}.rules{padding:24px;border-radius:20px;background:#f5f7fa}.rules h3{margin-bottom:14px}.rules p{margin:10px 0;font-size:14px;color:#586779}.history-item{display:flex;align-items:center;gap:18px;padding:20px 0;border-bottom:1px solid #e4eaf1}.history-item .symbol{width:44px;height:44px;display:grid;place-items:center;border-radius:50%;background:#eaf0ff;color:#1658e8;font-size:20px;flex-shrink:0}.history-item .grow{flex:1}.history-item h3{font-size:15px}.history-item small{display:block;color:#586779}.history-item .amount{font-weight:bold;font-size:19px;white-space:nowrap}.admin-shell{min-height:100vh;background:#f5f7fa;display:grid;grid-template-columns:232px minmax(0,1fr)}.admin-nav{background:white;padding:26px 18px}.admin-nav .logo{width:154px;margin:0 16px 34px}.admin-nav p{font-size:12px;color:#586779;margin:14px 16px}.admin-main{min-width:0;padding:28px 36px}.admin-top{display:flex;justify-content:space-between;align-items:center;gap:20px;font-size:13px;color:#586779;margin-bottom:36px}.admin-main h1{font-size:34px}.admin-main .lead{font-size:16px}.admin-stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;margin-top:24px}.admin-stat{background:white;border-radius:20px;box-shadow:var(--shadow);padding:26px}.admin-stat .num{font-size:42px;font-weight:bold;margin:10px 0}.admin-stat p{font-size:14px;color:#586779;min-height:66px}.admin-stat .btn{margin-top:18px;width:100%}.info-strip{display:flex;justify-content:space-between;gap:24px;align-items:center;padding:22px 26px;background:white;border-radius:18px;margin:20px 0}.admin-table{width:100%;border-collapse:collapse;margin-top:24px;font-size:14px;background:white;border-radius:20px;overflow:hidden}.admin-table th{text-align:left;font-size:12px;color:#586779;background:#edf2f9;padding:18px 16px;font-weight:normal}.admin-table td{padding:22px 16px;border-bottom:1px solid #e4eaf1;vertical-align:top}.admin-table td small{display:block;color:#586779;margin-top:6px}.admin-table td button{background:none;border:0;color:#1658e8;padding:0;min-height:44px;text-align:left;font-weight:bold}.admin-table .num{text-align:right;white-space:nowrap;font-weight:bold}.admin-table th.num{font-weight:normal}.admin-mobile-cards{display:none}.admin-filters{display:flex;gap:16px;align-items:end;margin:26px 0}.admin-filters label{font-size:13px;display:block;color:#586779;margin-bottom:8px}.admin-filters select{min-width:180px}.admin-filters>div{max-width:250px}.admin-filters .btn{height:52px}.subtle-error{background:#fff0f2;color:#b52a3b;border-radius:12px;padding:16px;margin:20px 0;font-size:14px}.empty-app{padding:60px 24px;text-align:center;background:#f5f7fa;border-radius:24px;margin:24px 0}.empty-app h2{margin:18px 0 12px}.empty-app p{color:#586779;max-width:460px;margin:0 auto 24px}.empty-app .icon{width:48px;height:48px}.loading-layout{display:grid;grid-template-columns:1fr 1fr;gap:24px}.skeleton.long{height:180px}.scenario{display:none}.scenario.active{display:block}.otp-real{position:relative;width:268px;margin:24px 0}.otp-cells{display:flex;gap:12px;pointer-events:none}.otp-cells span{display:grid;place-items:center;width:58px;height:60px;border:1px solid #8492a3;border-radius:12px;font-size:26px;background:white}.otp-real input{position:absolute;inset:0;opacity:.015;width:100%;font-size:30px;cursor:text}.otp-real:focus-within .otp-cells span{border-color:#1658e8;box-shadow:0 0 0 2px #eaf0ff}.short-link{overflow-wrap:anywhere;user-select:all}.simple-form{max-width:640px;margin:0}.form-result{padding:16px;background:#e9f6ee;color:#167149;border-radius:12px;margin:20px 0}.admin-main .order-layout{grid-template-columns:1fr 320px}.admin-main .order-product{flex-wrap:wrap}.page-actions{display:flex;gap:12px;flex-wrap:wrap;margin:24px 0}.mobile-nav-toggle{display:none}.log-row{font-size:13px;padding:12px 0;color:#586779}.greeting{display:flex;justify-content:space-between;gap:20px;align-items:center}.table-compact{width:100%;border-collapse:collapse;font-size:14px}.table-compact td{padding:12px 0;border-bottom:1px solid #e4eaf1}.table-compact td:last-child{text-align:right;font-weight:bold}.doc-chip{display:inline-block;background:#f5f7fa;padding:10px 14px;border-radius:10px;font-size:13px;color:#586779;margin-top:10px}.definition{margin-top:24px;font-size:13px;color:#586779}.definition strong{color:#162638}.mobile-block{display:none}@media(max-width:1100px){.admin-main{padding:24px}.admin-shell{grid-template-columns:200px 1fr}.admin-stats{gap:12px}.admin-stat{padding:20px}.admin-table td,.admin-table th{padding:16px 10px}.account-shell{gap:24px;grid-template-columns:190px 1fr}.home-products{grid-template-columns:repeat(3,1fr)}.home-products>.card:last-child{display:none}.home-hero h1{font-size:44px}.order-layout,.admin-main .order-layout{grid-template-columns:1fr}.order-layout>aside{max-width:600px}.auth-layout{gap:30px}.auth-card{padding:28px}.stats{gap:12px}.stat{padding:20px}.stat .number{font-size:28px}}@media(max-width:767px){.content{padding-top:20px}.home-hero{display:flex;flex-direction:column;padding:28px 24px;gap:12px;align-items:stretch}.home-hero h1{font-size:34px;letter-spacing:-1px}.home-hero .lead{font-size:16px;margin:16px 0 24px}.home-hero .hero-art{width:220px;align-self:center;margin-top:14px;padding:18px}.home-products{grid-template-columns:repeat(2,1fr);gap:24px 12px}.home-products>.card:last-child{display:flex}.home-products .card .price{font-size:22px}.home-products .card .product-name{font-size:14px}.section-title{gap:12px}.section-title h2{font-size:22px}.section-title .btn{font-size:13px;padding:10px 12px}.section{margin:32px 0}.benefits{grid-template-columns:1fr;gap:0}.benefit{padding:18px 0}.category-empty{padding:22px;align-items:flex-start}.auth-layout{display:block;margin:24px 0}.auth-story{display:none}.auth-card{padding:26px 22px}.auth-card h1{font-size:28px}.auth-links{flex-wrap:wrap;gap:4px}.success-top{grid-template-columns:1fr;gap:26px}.order-success{margin:24px 0}.order-success h1{font-size:30px}.order-layout,.admin-main .order-layout{display:block}.box-panel{padding:22px}.row-data{font-size:13px;gap:16px}.account-shell{display:block;margin-top:12px}.account-nav{padding:0;margin:0 0 22px;display:flex;overflow:auto;gap:6px}.account-nav .person{display:none}.account-nav a{width:auto;white-space:nowrap;margin:0;padding:10px 14px;font-size:13px;min-height:44px}.account-nav a .icon{width:18px;height:18px}.account-content{padding:0}.account-content h1{font-size:28px}.stats{grid-template-columns:1fr 1fr;margin:22px 0;gap:12px}.stats>.stat:last-child{grid-column:1/-1}.stat{padding:20px}.stat .number{font-size:28px}.account-tiles{gap:12px}.tile{padding:20px 16px;min-height:155px}.tile h3{font-size:16px}.tile p{font-size:13px}.attention{display:block;padding:20px}.attention .btn{margin-top:16px;width:100%}.order-card{padding:22px}.order-card-top{display:block}.order-card h3{font-size:18px}.order-card .bottom{gap:12px}.order-card .bottom .btn{padding:12px 14px;font-size:14px}.order-amounts{gap:14px}.order-amounts strong{font-size:19px}.order-amounts small{font-size:12px}.order-product{gap:12px;align-items:flex-start;flex-wrap:wrap}.order-product img{width:56px;height:56px}.order-product h3{font-size:14px}.order-product strong{margin-left:68px}.order-product .grow{min-width:160px}.bonus-hero{display:block;padding:26px}.bonus-hero .big{font-size:42px}.bonus-hero .btn{margin-top:24px;width:100%}.bonus-actions{display:grid;grid-template-columns:1fr;gap:12px}.history-item{gap:12px}.history-item .symbol{width:40px;height:40px}.history-item .amount{font-size:16px}.history-item h3{font-size:14px}.history-item small{font-size:12px}.admin-shell{display:block}.admin-nav{padding:14px 16px;display:flex;gap:8px;overflow:auto;align-items:center}.admin-nav .logo{width:94px;height:36px;margin:0 12px 0 0}.admin-nav p{display:none}.admin-nav a{width:auto;white-space:nowrap;margin:0;padding:10px 14px;font-size:13px;min-height:44px}.admin-nav a .icon{display:none}.admin-main{padding:22px 16px}.admin-top{margin-bottom:24px;font-size:12px}.admin-top .btn{padding:10px;font-size:12px}.admin-main h1{font-size:28px}.admin-stats{display:block}.admin-stat{margin:16px 0;padding:24px}.admin-stat p{min-height:0}.admin-stat .num{font-size:38px}.info-strip{align-items:flex-start;padding:20px;font-size:14px}.admin-table-wrap.admin-table-switch{display:none}.admin-mobile-cards{display:block}.admin-filters{display:grid;grid-template-columns:1fr;gap:14px}.admin-filters>div{max-width:none;min-width:0}.admin-filters select{min-width:0;font-size:14px;padding:10px}.admin-filters .btn{grid-column:1/-1}.admin-mobile-cards .order-card{padding:22px}.loading-layout{grid-template-columns:1fr}.key-link{padding:24px}.key-value{font-size:19px}.lead{font-size:16px}.page-actions .btn{width:100%}.greeting{align-items:flex-start}.greeting .btn{min-width:44px;padding:10px}.mobile-block{display:block}.desktop-block{display:none}}

.home-heading{font-size:26px;letter-spacing:-.5px;margin:0 0 20px}.promo-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;list-style:none;padding:0;margin:0}.promo-list li{min-width:0}.promo{position:relative;width:100%;height:220px;overflow:hidden;border:0;border-radius:20px;padding:24px;text-align:left;cursor:pointer;color:#162638;font:inherit;display:flex;align-items:center}.promo:focus-visible{outline:3px solid #1658e8;outline-offset:3px}.promo:hover .promo-link{text-decoration:underline}.promo-tool{background:#eaf0ff}.promo-fix{background:#f0f2f6}.promo-team{background:#1658e8;color:white}.promo-copy{position:relative;z-index:2;display:flex;flex-direction:column;align-items:flex-start;gap:16px}.promo-label{font-size:12px;letter-spacing:.6px;font-weight:700}.promo strong{font-size:25px;line-height:1.18;letter-spacing:-.6px}.promo-link{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:700;min-height:32px}.promo-link .icon{width:17px;height:17px}.promo-photo{position:absolute;right:-22px;bottom:12px;width:190px;height:185px;mix-blend-mode:multiply;pointer-events:none}.promo-photo img{width:100%;height:100%;object-fit:contain}.promo-symbol{position:absolute;right:14px;bottom:18px;transform:rotate(-12deg);opacity:.12}.promo-symbol .icon{width:125px;height:125px}.promo-team .promo-symbol{opacity:.22}.promo-tool .promo-copy{max-width:63%}
@media(max-width:1100px) and (min-width:768px){.promo{height:200px;padding:18px}.promo strong{font-size:21px}.promo-photo{right:-35px;width:150px}.promo-label{font-size:12px}.promo-link{font-size:12px}.promo-tool .promo-copy{max-width:75%}}
@media(max-width:767px){.home-heading{font-size:22px;line-height:1.25;margin-bottom:16px}.promo-list{display:flex;overflow-x:auto;gap:12px;padding:3px 3px 12px;scroll-snap-type:x mandatory;scrollbar-width:thin}.promo-list li{flex:0 0 86%;scroll-snap-align:start}.promo{height:160px;padding:20px;border-radius:16px}.promo-copy{gap:9px}.promo strong{font-size:22px}.promo-label{font-size:12px}.promo-link{font-size:12px;min-height:28px}.promo-photo{width:145px;height:140px;right:-15px;bottom:7px}.promo-symbol .icon{width:100px;height:100px}.promo-tool .promo-copy{max-width:67%}}
.home-hero .hero-art{overflow:hidden}@media(min-width:768px) and (max-width:1100px){.admin-table-wrap.admin-table-switch{display:none}.admin-mobile-cards{display:block}.admin-shell{grid-template-columns:200px minmax(0,1fr)}.admin-main{min-width:0;padding:24px}.admin-filters>div{min-width:0;max-width:100%}.admin-filters select{min-width:0;max-width:100%}}
/* v2.19 real footer links */
.footer .foot-grid a{display:block;background:none;border:0;color:var(--muted,#586779);padding:7px 0;text-align:left;min-height:44px;font-size:14px;text-decoration:none}.footer .foot-grid a:hover{color:var(--primary,var(--p,#1658e8))}
.crumbs{display:flex!important;align-items:center;flex-wrap:nowrap!important;white-space:nowrap;overflow-x:auto;gap:8px;min-width:0;scrollbar-width:thin}.crumbs>*{flex-shrink:0;white-space:nowrap}.crumbs a,.crumbs span{display:inline-flex;align-items:center;line-height:1.5;text-align:left}
.filter-group{margin-bottom:18px}.filter-group h3{margin-bottom:8px}.filter-group .check{min-height:26px;margin:0;padding:2px 0;line-height:22px}.filter-group .check input{margin-top:0;margin-bottom:0;width:18px;height:18px}.foot-grid a{min-height:26px;padding:3px 0;line-height:20px;margin:0}.foot-grid h3{margin-bottom:8px}
.account-nav .person{text-align:left}
.order-card{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px 24px;padding:18px 22px;margin:12px 0;border-radius:16px}.order-card-top{grid-column:1;grid-row:1;align-self:center}.order-card h3{font-size:18px;line-height:1.3}.order-card .order-meta{margin-top:3px;font-size:12px}.order-card .status-line{grid-column:1;grid-row:2;gap:6px;margin:0;align-self:start}.order-card .status-pill{padding:4px 8px}.order-card .order-amounts{grid-column:2;grid-row:1;margin:0;gap:24px}.order-card .order-amounts strong{font-size:19px;margin-top:1px}.order-card .bottom{grid-column:2;grid-row:2;justify-content:flex-end;gap:12px}.order-card .bottom .btn{min-height:40px;padding:8px 12px;font-size:13px}.order-card .order-thumb{width:32px;height:32px;margin:0}
.ds-select{position:relative;display:inline-block;max-width:100%;min-width:0}.ds-select select{position:absolute!important;opacity:0;pointer-events:none;width:1px!important;height:1px!important;min-height:0!important;padding:0!important}.ds-trigger{font:inherit;background:#fff;color:#162638;border:1px solid #d7dfe9;border-radius:12px;padding:11px 40px 11px 14px;min-height:44px;width:100%;text-align:left;position:relative;cursor:pointer;line-height:1.4}.ds-trigger:after{content:'';position:absolute;right:17px;top:calc(50% - 4px);width:7px;height:7px;border:solid #586779;border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}.ds-trigger:hover{border-color:#9eacc0;background:#fafbfe}.ds-trigger:focus-visible{border-color:var(--focus)}.ds-trigger[aria-expanded=true]{border-color:#1658e8;background:#f7f9ff}.ds-trigger:disabled{background:#f5f7fa;color:#8793a3;cursor:not-allowed}.ds-menu{position:fixed;z-index:10000;background:#fff;border:1px solid #e4eaf1;box-shadow:0 10px 32px #16263820;border-radius:14px;padding:6px;overflow-y:auto;max-height:320px;color:#162638;font:14px/1.4 Arial,sans-serif}.ds-menu[hidden]{display:none}.ds-option{display:block;min-height:40px;width:100%;text-align:left;border:0;border-radius:8px;padding:10px 32px 10px 12px;background:white;color:#162638;font:inherit;position:relative;cursor:pointer}.ds-option:hover,.ds-option:focus{background:#f0f4fb;outline:0}.ds-option[aria-selected=true]{background:#eaf0ff;color:#1658e8;font-weight:700}.ds-option[aria-selected=true]:after{content:'✓';position:absolute;right:12px}.ds-option:disabled{color:#98a3b2;cursor:not-allowed}.ds-group{font-size:12px;color:#586779;padding:8px 12px 4px}.input-wrap .ds-select,.admin-filters .ds-select{width:100%}.toolbar .ds-trigger{background:#f5f7fa;border-color:transparent;font-size:14px}.toolbar .ds-select{min-width:180px}.sub .ds-select,.controls .ds-select{min-width:220px;max-width:330px}
.accessories{margin:32px 0 20px}.accessories h2{font-size:24px;margin:0 0 8px}.accessories>p{color:#586779;font-size:14px;margin-bottom:18px}.accessory-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}.accessory{border:1px solid #e4eaf1;border-radius:16px;padding:16px;display:flex;flex-direction:column;gap:10px;background:white}.accessory-art{height:90px;display:grid;place-items:center;background:#f5f7fa;border-radius:12px}.accessory-art svg{width:110px;height:80px}.accessory h3{font-size:15px;line-height:1.4;min-height:42px}.accessory small{color:#586779;font-size:12px}.accessory strong{font-size:21px}.accessory .btn{margin-top:auto;font-size:14px;min-height:44px;padding:10px}.checkout-contact-hint{font-size:14px;color:#586779;margin:0 0 20px}.accessory-row-art{display:grid;place-items:center;background:#f5f7fa;border-radius:12px}.accessory-row-art svg{width:80px;height:80px}
@media(max-width:767px){.filter-group .check{min-height:32px;padding:5px 0}.foot-grid a{min-height:32px;padding:6px 0}.order-card,.admin-mobile-cards .order-card{padding:14px 16px;gap:8px 10px}.order-card-top{grid-column:1/-1;grid-row:1;display:flex}.order-card h3{font-size:16px}.order-card .status-line{grid-row:2;grid-column:1/-1}.order-card .status-pill{font-size:12px}.order-card .order-amounts{grid-row:3;grid-column:1/-1;gap:14px;margin:2px 0}.order-card .order-amounts strong{font-size:18px}.order-card .order-amounts small{font-size:12px}.order-card .bottom{grid-row:4;grid-column:1/-1;justify-content:space-between}.order-card .bottom .btn{min-height:44px;padding:8px 12px;font-size:13px}.order-card .order-thumb{width:28px;height:28px}.accessory-list{display:flex;overflow-x:auto;padding-bottom:10px;scroll-snap-type:x mandatory}.accessory{flex:0 0 74%;scroll-snap-align:start}.ds-option{min-height:44px;font-size:16px}.ds-trigger{font-size:16px}.sub .ds-select,.controls .ds-select{max-width:100%;min-width:0;width:100%}.accessories h2{font-size:22px}}
/* NOLIK v2.4 second-round fixes */
.filter-group .filter-title{margin:0 0 8px}
.filter-toggle{display:flex;align-items:center;gap:8px;width:100%;min-height:36px;padding:3px 0;border:0;background:transparent;color:inherit;text-align:left;font:inherit;font-weight:700;cursor:pointer}
.filter-toggle::before{content:"";width:8px;height:8px;border:solid currentColor;border-width:0 2px 2px 0;transform:rotate(45deg);transition:transform .16s ease;flex:0 0 auto;margin-left:2px}
.filter-toggle[aria-expanded="false"]::before{transform:rotate(-45deg)}
.filter-toggle:focus-visible{border-radius:6px}
.filter-values[hidden]{display:none!important}
.filter-values{min-width:0}
.checkout-contact-hint{grid-area:hint;margin:0 0 4px}
#checkout-form{grid-area:form;min-width:0}
body:has(#checkout-form) .two-cols>.summary{grid-area:summary;min-width:0}
body:has(#checkout-form) .two-cols{grid-template-areas:"hint summary" "form summary";grid-template-columns:minmax(0,1fr) 360px;align-items:start}




@media(max-width:767px){body:has(#checkout-form) .two-cols{display:block}.checkout-contact-hint{margin:0 0 20px}}
/* v2.5: scoped cart layout and header catalog */
@media(max-width:767px){.main-head>.catalog-menu-trigger{display:inline-flex!important;order:3;padding:10px 12px;font-size:14px;min-height:44px}.main-head>.search{order:3;flex:1;flex-basis:0;min-width:130px}.main-head>.head-action{order:1}}
#cart-content{grid-template-columns:minmax(0,1fr) 360px;grid-template-areas:"items totals";gap:32px;align-items:start}#cart-content>div{grid-area:items;min-width:0}#cart-content>.summary{grid-area:totals;min-width:0;margin:0;align-self:start}#cart-items .cart-item{grid-template-columns:100px minmax(0,1fr) auto;gap:20px}#cart-items .item-photo{width:100px;height:100px}#cart-items .item-info{min-width:0}#cart-items .item-info h3{max-width:none}#cart-items .item-sum{grid-column:auto;grid-row:auto;white-space:nowrap}#cart-items .item-photo img{display:block;width:100%;height:100%;object-fit:contain}.order-product img{object-fit:contain}.main-head .logo{object-fit:contain;flex-shrink:0}
.catalog-menu-trigger[aria-expanded=true]{background:#1147c2}.catalog-menu-trigger .catalog-chevron{display:inline-block;width:7px;height:7px;border:solid currentColor;border-width:0 1.5px 1.5px 0;transform:rotate(45deg);margin-left:4px;transition:transform .15s}.catalog-menu-trigger[aria-expanded=true] .catalog-chevron{transform:rotate(225deg)}

.catalog-page[hidden],body.catalog-view-open>.scenario[hidden],body.catalog-view-open>.nav-cats[hidden],body.catalog-view-open>footer[hidden]{display:none!important}
.catalog-page{background:#fff;border-top:1px solid #eef1f5;color:#243447;padding-bottom:48px;min-height:620px}
.catalog-page-top{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px 0;color:#8290a1;font-size:13px}
.catalog-close,.catalog-all{border:0;background:none;color:#1658e8;font:inherit;cursor:pointer;padding:8px 0}
.mega-grid{display:grid;grid-template-columns:240px minmax(0,1fr);gap:40px}.mega-rail{padding-right:16px;border-right:1px solid #eef1f5}
.mega-category{display:flex;align-items:center;gap:10px;width:100%;min-height:40px;border:0;border-radius:5px;background:none;padding:8px 10px;text-align:left;font:14px/1.4 Arial,sans-serif;color:#526174;cursor:pointer}.mega-category svg{width:18px;height:18px;flex-shrink:0;color:#94a0af}.mega-category:after{content:'›';margin-left:auto;color:#9aa6b5}.mega-category:hover{color:#1658e8;background:#f7f9fc}.mega-category[aria-selected=true]{color:#1658e8;background:#f0f5ff}.mega-category[aria-selected=true] svg{color:#1658e8}
.mega-content{min-width:0;padding:2px 0 20px}.mega-content h2{font-size:22px;line-height:1.3;font-weight:600;margin:0 0 26px}.mega-groups{display:grid;gap:28px}.mega-groups h3{font-size:15px;font-weight:600;margin:0 0 10px}.mega-links{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px 28px}.mega-link{border:0;background:none;text-align:left;font:14px/1.5 Arial,sans-serif;color:#59687a;padding:5px 0;cursor:pointer}.mega-link:hover{color:#1658e8}.mega-bottom{margin-top:30px;font-size:14px}.mega-feedback{font-size:13px;color:#7b8796;max-width:560px}.catalog-page button:focus-visible{outline:2px solid #1658e8;outline-offset:3px}
@media(max-width:1100px) and (min-width:768px){#cart-content{grid-template-columns:minmax(0,1fr) 300px;gap:24px}#cart-items .cart-item{grid-template-columns:80px minmax(0,1fr);gap:16px}#cart-items .item-photo{width:80px;height:80px;grid-row:1/3}#cart-items .item-sum{grid-column:2;text-align:left}.mega-grid{grid-template-columns:205px minmax(0,1fr);gap:24px}.mega-links{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:767px){#cart-content{display:flex;flex-direction:column;gap:24px}#cart-content>div,#cart-content>.summary{width:100%}#cart-items .cart-item{grid-template-columns:76px minmax(0,1fr);gap:12px;padding:20px 0}#cart-items .item-photo{width:76px;height:76px;grid-row:1/3}#cart-items .item-sum{grid-column:2;text-align:left;font-size:21px}#cart-items .item-actions{gap:8px;flex-wrap:wrap}#cart-items .item-info h3{font-size:16px}.catalog-page{min-height:500px}.mega-grid{display:block}.mega-rail{border:0;border-bottom:1px solid #eef1f5;padding:0 0 14px;margin-bottom:24px}.mega-category{min-height:44px}.mega-content h2{font-size:20px}.mega-links{grid-template-columns:1fr;gap:0}.mega-link{min-height:44px;padding:10px 0}.mega-groups{gap:22px}.catalog-close{min-height:44px}}

.mobile-bottom-nav{display:none}
@media(max-width:767px){
.main-head>.catalog-menu-trigger{display:none!important}
body.has-mobile-nav{padding-bottom:calc(72px + env(safe-area-inset-bottom,0px))}
.mobile-bottom-nav{position:fixed;left:0;right:0;bottom:0;z-index:100;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));background:#fff;border-top:1px solid #e9edf3;padding:6px 4px calc(6px + env(safe-area-inset-bottom,0px));box-shadow:0 -3px 16px #18335306}

.mobile-bottom-nav svg{width:23px;height:23px;flex-shrink:0}
}

.mobile-business-label{display:none}
@media(max-width:767px){
.main-head>.head-action:not(:first-child){display:none!important}
.desktop-business-label{display:none}.mobile-business-label{display:inline}
.main-head{display:grid!important;grid-template-columns:100px minmax(0,1fr);gap:14px;align-items:center;padding-top:12px;padding-bottom:12px}
.main-head>.head-action:first-child{grid-column:1;grid-row:1;order:0;padding:0;min-width:0}
.main-head .logo{max-width:100%;height:auto}
.main-head>.search{grid-column:2;grid-row:1;order:0;width:100%;min-width:0;margin:0}
.main-head>.search input{min-width:0;width:100%}
}
.crumbs{white-space:nowrap;overflow-x:auto;scrollbar-width:none;align-items:center}.crumbs::-webkit-scrollbar{display:none}
.category-chips,.nav-cats{scrollbar-width:none}.category-chips::-webkit-scrollbar,.nav-cats::-webkit-scrollbar{display:none}
.product-name{-webkit-line-clamp:3!important}
/* ⚠️ Высота названия БОЛЬШЕ НЕ ФИКСИРУЕТСЯ (26.10.2026).
   Было min-height:72px!important: у короткого названия оставалась пустая
   третья строка, и артикул визуально уезжал вниз. Ровный ряд держит
   распорка в плитке (card_align.css), а не пустое место. */
.tiny{font-size:12px!important}.badge,.sku,.status-pill{font-size:12px!important}
.foot-grid a{min-height:44px!important}

@media(max-width:600px){.search input{font-size:16px}}
/* ============================================================
   NOLIK.SU — правила витрины (добавлены поверх макета)
   ============================================================
   В макете часть элементов — <button>: прототипу важно было показать
   состояние. На витрине это настоящие ссылки <a href>, и им нужно
   вернуть тот же вид, иначе один и тот же элемент выглядит по-разному
   там, где он ведёт на страницу, и там, где что-то делает.
   ============================================================ */

/* Верхняя полоса: ссылки вместо кнопок макета. */
.top-links a{
  display:inline-flex;
  align-items:center;
  gap:6px;
  min-height:38px;
  color:var(--muted);
  font-size:13px}
.top-links a:hover{
  color:var(--text)}

/* Разделы каталога в шапке. */
.nav-cats a{
  padding:8px 0;
  min-height:44px;
  color:var(--muted)}
.nav-cats a:hover{
  color:var(--text)}
.nav-cats a.nav-active{
  color:var(--primary);
  font-weight:bold}

/* Хлебные крошки — ссылки на разделы. */
.crumbs a{
  padding:0;
  min-height:26px;
  color:inherit}
.crumbs a:hover{
  color:var(--text)}

/* Нижнее меню телефона. */
.mobile-bottom-nav a{
  border:0;
  background:none;
  color:#647185;
  min-width:0;
  min-height:54px;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:5px;
  font:12px/1.2 Arial,sans-serif;
  padding:4px 0;
  cursor:pointer}
.mobile-bottom-nav a.is-current{
  color:var(--primary)}
.mobile-bottom-nav a:focus-visible{
  outline:2px solid var(--primary);
  outline-offset:-2px;
  border-radius:5px}

/* Пагинация: номера страниц — ссылки, а не кнопки. */
.pagination a.chip{
  min-width:44px}
.pagination a.chip.active{
  background:var(--primary);
  color:var(--onPrimary)}

/* Ссылки-кнопки внутри карточек и миниатюры галереи. */
.card .media a{
  display:block;
  width:100%;
  height:100%}
.thumbnail{
  display:block}
.thumbnail:focus-visible{
  outline:2px solid var(--primary);
  outline-offset:2px}

/* Цена: диапазон цен вариантов и «по запросу» (цены в базе нет). */
.price-request{
  font-size:16px;
  font-weight:700;
  color:var(--muted)}
.old-price{
  font-size:15px;
  font-weight:normal;
  color:var(--muted);
  margin-right:6px}

/* Описание товара: переносы строк из базы сохраняем как есть. */
.product-description{
  white-space:pre-line;
  /* Межстрочный интервал уменьшен (владелец 24.10.2026: «Очень большие межстрочные
     отступы в тексте описания. Убери их, пусть каждая новая строка начинается со
     следующей, без пустых строк»). Пустые строки убраны в данных, здесь — плотность. */
  line-height:1.55}

/* Пустые состояния: поиск внутри блока и отступ у кнопки. */
.empty-app .search{
  width:100%;
  max-width:520px;
  margin:0 auto}
.empty-app .btn{
  margin-top:8px}
.empty-state .btn{
  margin-top:8px}

/* Мега-меню: разделы переключаются вкладками, панель — одна на раздел. */
.mega-rail .mega-category{
  cursor:pointer}
.mega-content:focus{
  outline:none}
.mega-panel h2 a{
  color:inherit}
.mega-groups h3 a:hover{
  color:var(--primary)}

/* Каталог без боковых фильтров (страница поиска) — та же ширина сетки. */
.catalog-plain{
  min-width:0}

/* ============================================================
   КОРЗИНА И ПОКУПКА (2026-10-08)

   Покупка — настоящие формы POST, а не кнопки «для вида»: у количества
   в корзине рядом с полем стоит «Обновить» (стрелки «−» и «+» отправляют
   форму сами), поэтому кнопке нужно место в строке действий.
   ============================================================ */

/* Правая колонка каталога: сетка товаров не должна раздувать страницу. */
.catalog-main{
  min-width:0}

/* Блок покупки в плитке: прижат к низу карточки, как кнопка макета. */
.card-buy{
  margin-top:auto;
  display:flex;
  flex-direction:column}
.card-buy form{
  margin:0;
  display:flex;
  flex-direction:column}
.card-buy .btn{
  margin-top:0}

/* Количество в корзине: поле, две стрелки и кнопка «Обновить» — одна форма. */
.item-quantity-form{
  display:flex;
  align-items:center;
  gap:10px;
  margin:0;
  flex-wrap:wrap}
.item-quantity-form .btn{
  padding:10px 14px;
  min-height:48px;
  font-size:13px}
.item-actions form{
  margin:0}
.cart-item .stock{
  margin-bottom:10px}
.cart-item .note{
  margin:0 0 12px;
  max-width:520px}

/* ============================================================
   КОРЗИНА БЕЗ ПЕРЕЗАГРУЗКИ (правка владельца 2026-10-13)

   ⚠️ ЗАЧЕМ ЭТО В CSS, А НЕ В СКРИПТЕ. «Кнопка занята» — это СОСТОЯНИЕ
   разметки (`aria-busy="true"`, `disabled`), которое ставит скрипт на время
   запроса. Вид состояния — работа стилей: скрипт не «перекрашивает»
   кнопки и не подменяет подписи, иначе вид зависел бы от того, успел ли
   загрузиться JavaScript.

   ⚠️ ЗАНЯТАЯ КНОПКА ВИДНА И НЕ НАЖИМАЕТСЯ ДВАЖДЫ. `disabled` не даёт
   отправить второй запрос (двойное нажатие «+» не превратится в «+2»),
   приглушение показывает, что нажатие принято, а `not-allowed` на курсоре
   объясняет, почему кнопка не отвечает. Без скрипта этих состояний не
   бывает вовсе: форма уходит обычной отправкой и страница перезагружается.
   ============================================================ */

.cart-item form[aria-busy="true"]{
  opacity:.6}
.cart-item form[aria-busy="true"] button{
  cursor:not-allowed}

/* Кружок числа у иконки корзины скрывают через `[hidden]`: у `.head-badge`
   задан `display:inline-flex`, и он перебил бы браузерное `display:none`. */
.head-badge[hidden]{
  display:none}

/* ============================================================
   ПЛИТКА КАТАЛОГА: «В КОРЗИНУ» → ПОЛЕ КОЛИЧЕСТВА
   (правка владельца 2026-10-13)

   ⚠️ ЧТО ЗДЕСЬ ГЛАВНОЕ: ВЫСОТА И ШИРИНА НЕ МЕНЯЮТСЯ. Кнопка «В корзину»
   (`.btn`, высота 48 px, ширина колонки плитки) превращается в строку
   «поле + кнопка-ссылка» ТОЙ ЖЕ высоты (`.qty` — 48 px) и той же ширины
   (`width:100%`), поэтому карточка и вся сетка каталога не «едут».

   ⚠️ `[hidden]` ОБЪЯВЛЕН ЯВНО (`.card-qty-row[hidden]`). У `.card-buy form`
   задан `display:flex`, а авторское правило сильнее браузерного
   `[hidden]{display:none}`: без этой строки скрытая строка была бы видна
   всем — и покупатель видел бы ДВЕ кнопки покупки в одной плитке.

   ⚠️ ПОЛЕ И КНОПКА РАСТЯГИВАЮТСЯ ПО ДОСТУПНОЙ ШИРИНЕ. Внутри `.qty`
   кнопки и поле получают `flex:1` вместо фиксированных 44/52 px: на узком
   телефоне плитка — это ~140 px, и жёсткие размеры вылезли бы за карточку.
   ============================================================ */

.card-buy .card-qty-row{
  display:flex;
  gap:8px;
  align-items:stretch;
  width:100%}
.card-buy .card-qty-row[hidden]{
  display:none}
.card-buy .card-qty-form{
  flex:1 1 auto;
  min-width:0;
  display:flex;
  flex-direction:column}
.card-buy .card-qty-form .qty{
  width:100%;
  flex:1}
.card-buy .card-qty-form .qty button{
  flex:1 1 0;
  width:auto;
  min-width:0}
.card-buy .card-qty-form .qty input{
  flex:1 1 0;
  width:auto;
  min-width:0}
/* Кнопка-ссылка в корзину: та же высота, что у поля (48 px) и у кнопки
   «В корзину», которую она сменяет. Иконка — существующая, из шапки. */
.card-buy .card-cart-link{
  flex:0 0 48px;
  width:48px;
  min-width:48px;
  height:48px;
  min-height:48px;
  padding:0}
/* Ссылка входа в закрытой плитке: тихая, в одну строку, не перекрывает наличие.
   (Владелец 24.10.2026: «кнопка закрывает наличие / срок доставки, поправь».) */
.card-login-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  text-decoration:none}

.card-buy .card-cart-link .icon{
  width:22px;
  height:22px}
@media(max-width:767px){
  /* В плитке на телефоне две колонки: поле «− N +» и кнопка в строку не
     помещаются, поэтому кнопка переезжает на свою строку (владелец:
     «при необходимости — с переносом, без выхода за карточку»). */
  .card-buy .card-qty-row{
    flex-wrap:wrap}
  .card-buy .card-qty-form{
    flex:1 1 100%}
  .card-buy .card-cart-link{
    flex:1 1 100%;
    width:auto;
    min-width:0}
}

/* Покупка в карточке товара: количество и кнопка столбиком. */
.buy-form{
  display:flex;
  flex-direction:column;
  gap:10px;
  margin:18px 0 8px}
.buy-form .label{
  font-size:13px;
  color:var(--muted)}

/* Сообщение о проблеме (нет в наличии, количество больше остатка):
   красная врезка вместо жёлтой нейтральной. */
.note.danger{
  background:var(--dangerSoft);
  color:var(--danger)}

/* ============================================================
   ОФОРМЛЕНИЕ ЗАКАЗА И СТРАНИЦА ЗАКАЗА (2026-10-08)

   Ошибка обязательного поля показывается РЯДОМ С ПОЛЕМ (не всплывающим
   окном): покупатель должен видеть, что именно исправить, и не терять уже
   введённое. Для этого под полем стоит `.field-error`, а само поле получает
   `aria-invalid="true"` — его и подсвечиваем.
   ============================================================ */

.field-error{
  color:var(--danger);
  font-size:13px;
  line-height:1.5;
  margin-top:6px}
[aria-invalid="true"]{
  border:2px solid var(--danger);
  background:var(--dangerSoft)}

/* Отметка о согласии в правой колонке оформления: текст мелкий, ссылки
   на юридические документы — обычные ссылки внутри подписи. */
.summary-consent{
  margin:18px 0 14px;
  font-size:12px;
  line-height:1.55}
.summary-consent a{
  color:var(--primary);
  text-decoration:underline}

/* Наличные при получении бывают только при самовывозе: недоступный способ
   показываем (покупатель ищет его глазами), но приглушённо. */
.choice.disabled{
  opacity:.6;
  cursor:not-allowed}

/* Строка позиции заказа и блоки страницы заказа. */
.order-line{
  display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  gap:6px 20px;
  padding:16px 0;
  border-bottom:1px solid var(--line)}
.order-line:last-child{
  border-bottom:0}
.order-line .order-line-sum{
  font-weight:bold;
  white-space:nowrap}
.order-line small{
  color:var(--muted);
  font-size:13px}

/* Статус заказа и оплаты — те же цвета, что у состояния товара.
   ⚠️ РАЗМЕРЫ И ЦВЕТА ЖИВУТ В ОДНОМ МЕСТЕ — в базовом слое (`.status-pill`
   и его варианты `.green/.amber/.red/.gray` + синонимы `.success/.warning/
   .danger` выше). Здесь раньше лежала ВТОРАЯ копия с другими размерами
   (`padding:6px 12px`, `border-radius:999px`), из-за которой пилюля одного
   и того же состояния выглядела по-разному на соседних страницах. Копия
   убрана, добавлены только синонимы имён (этап 4, 2026-10-12). */

/* Карточка «Заказ оформлен»: заголовок, номер и что дальше. */
.order-head{
  display:flex;
  justify-content:space-between;
  align-items:flex-start;
  gap:20px;
  flex-wrap:wrap;
  margin-bottom:22px}
.order-meta{
  color:var(--muted);
  font-size:14px}
@media(max-width:767px){
  .order-head{
    display:block}
  .order-line{
    grid-template-columns:minmax(0,1fr)}
}


/* ============================================================
   ЛИЧНЫЙ КАБИНЕТ ПОКУПАТЕЛЯ (этап 2)
   ============================================================
   Меню кабинета, «сердечко» избранного в плитках и мелкие детали новых
   экранов. Классы взяты из уже существующей системы (account-shell,
   account-nav, order-card, status-pill, empty-app, box-panel, simple-form,
   rules, badge), поэтому новых «дизайнов» здесь нет — только то, чего
   не хватало прежним страницам. */

/* Ссылки меню кабинета — тот же вид, что у кнопок `account-nav button`,
   но это НАСТОЯЩИЕ ссылки: раздел кабинета имеет свой адрес, и открывать
   его в новой вкладке должно быть можно. */
.account-nav a.account-link{display:flex;align-items:center;gap:12px;width:100%;padding:12px 16px;border:0;border-radius:12px;background:none;text-align:left;min-height:48px;color:#586779;margin:4px 0;text-decoration:none;font:inherit}
.account-nav a.account-link:hover{background:#f2f6fd;color:#1658e8}
.account-nav a.account-link.active{background:#eaf0ff;color:#1658e8;font-weight:bold}

.account-nav form{margin-top:12px}

/* «Сердечко» в плитке каталога: форма поверх фотографии. Форма, а не
   ссылка — добавление в избранное меняет состояние (см. `_card.html`). */
.card .media .fav-form{position:absolute;right:0;top:0;z-index:2;margin:0}
.card .media .fav-form .fav{display:grid;place-items:center;width:44px;height:44px;padding:0;border:0;border-radius:50%;background:#fff;color:#8492a3;box-shadow:0 2px 10px #1b35571f;cursor:pointer}
.card .media .fav-form .fav:hover{color:#b52a3b}
.card .media .fav-form .fav.is-on{color:#b52a3b}
.card .media .fav-form .fav .icon{width:21px;height:21px}


/* Мелкое для новых экранов кабинета. */
.simple-form .check{margin:16px 0}
.simple-form .btn.wide{margin-top:8px}
.account-content .section-title{align-items:center}
.account-content .empty-app{margin:8px 0 0}
.account-content .order-card form{margin:0}
.account-content .status-pill.green,.account-content .status-pill.gray{margin-left:8px}
.admin-table-wrap{background:#fff;border-radius:20px}
.account-content .rules ol{margin:0;padding-left:22px}
.account-content .rules li{margin:10px 0;font-size:14px;color:#586779}
.account-content .bonus-hero .big{font-variant-numeric:tabular-nums}

/* Планшет и телефон: меню кабинета — горизонтальная лента, как было
   у кнопок (см. медиазапросы выше), поэтому ссылки наследуют их размеры. */
@media(max-width:767px){
  .account-nav a.account-link{width:auto;white-space:nowrap;margin:0;padding:10px 14px;font-size:13px;min-height:44px}
  .account-nav form{margin-top:0}
  .account-nav form .btn{width:auto;white-space:nowrap;padding:10px 14px;font-size:13px;min-height:44px}
  .card .media .fav-form .fav{width:40px;height:40px}
  .admin-table-wrap{border-radius:12px}
}


/* ============================================================
   АДМИНКА: КАРКАС, МЕНЮ И СПИСКИ (этап 3)
   ============================================================
   Классы самого каркаса (admin-shell, admin-nav, admin-main, admin-table,
   admin-filters, admin-mobile-cards) уже есть выше — они пришли из макетов
   админских экранов. Здесь добавлено ТОЛЬКО то, чего не хватало живой
   странице:

   * пункты меню — это НАСТОЯЩИЕ ссылки `<a>` (в макетах были `<button>`):
     у раздела админки есть свой адрес, и открыть его в новой вкладке должно
     быть можно (та же правка, что делали для меню кабинета);
   * пометка «скоро» у разделов, которых ещё нет: пункт намеренно НЕ ссылка,
     чтобы владелец не попадал на 404;
   * счётчики заказов по состояниям, пагинация и сетка действий — новые
     детали экранов заказов и уведомлений, ничего «своего» по цветам. */

.admin-nav a.admin-link{display:flex;gap:12px;align-items:center;border-radius:12px;padding:14px 16px;color:#586779;min-height:48px;margin:4px 0;text-decoration:none;font:inherit}
.admin-nav a.admin-link:hover{background:#f2f6fd;color:#1658e8}
.admin-nav a.admin-link.active{background:#eaf0ff;color:#1658e8;font-weight:bold}

.admin-nav .admin-link.soon{display:flex;gap:8px;align-items:center;justify-content:space-between;padding:14px 16px;min-height:48px;margin:4px 0;border-radius:12px;color:#8793a3;font:inherit}
.admin-nav .admin-link.soon .badge{background:#eef1f5;color:#8793a3}
.admin-nav .badge{margin-left:6px}
.admin-nav form{margin-top:12px}

/* Счётчики «сколько заказов в каком состоянии» — ряд ссылок-фильтров. */
.admin-counters{display:flex;flex-wrap:wrap;gap:10px;margin:20px 0 6px}
.admin-counter{display:inline-flex;align-items:baseline;gap:8px;padding:10px 14px;border-radius:999px;background:white;border:1px solid #e4eaf1;color:#586779;font-size:14px;min-height:44px;text-decoration:none}
.admin-counter strong{font-size:16px;color:#162638}
.admin-counter:hover{border-color:#9eacc0}
.admin-counter.is-current{background:#eaf0ff;border-color:#1658e8;color:#1658e8}
.admin-counter.is-current strong{color:#1658e8}
.admin-counter .soon{font-size:12px}

/* Пагинация списков админки. */
.admin-pager{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:22px 0}
.admin-pager a,.admin-pager span{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:8px 12px;border-radius:12px;background:white;border:1px solid #e4eaf1;color:#586779;text-decoration:none}
.admin-pager a:hover{border-color:#9eacc0;color:#1658e8}
.admin-pager .is-current{background:#1658e8;border-color:#1658e8;color:#fff;font-weight:bold}

/* Карточка заказа: две колонки (данные и действия) на широком экране. */
.admin-order-grid{display:grid;grid-template-columns:minmax(0,1fr) 360px;gap:22px;align-items:start}
.admin-side{display:grid;gap:16px}
.admin-actions{display:grid;gap:12px}
.admin-actions form{margin:0}
/* Подписи и поля действий меню заказа описаны ОДИН РАЗ — в разделе
   «поля ввода» ниже (этап 4): раньше здесь была своя копия размеров. */
.admin-actions .btn{width:100%}
.admin-kv{display:grid;grid-template-columns:minmax(140px,auto) minmax(0,1fr);gap:8px 16px;font-size:14px;margin:0}
.admin-kv dt{color:#586779}
.admin-kv dd{margin:0;overflow-wrap:anywhere}
.admin-note{font-size:13px;color:#586779}
.admin-inline-form{display:inline;margin:0}

@media(max-width:1100px){
  .admin-order-grid{grid-template-columns:minmax(0,1fr)}
}

/* ============================================================
   ЕДИНАЯ СИСТЕМА ОФОРМЛЕНИЯ: АДМИНКА И КАБИНЕТ (этап 4, 2026-10-12)
   ============================================================
   ЗАЧЕМ ЭТОТ РАЗДЕЛ
   -----------------
   Владелец посмотрел админку и кабинет и сказал «всё криво». Кривизна
   была структурной: каркас (сетка, меню, таблицы, поля) пришёл из макетов
   дизайнера, а экраны последних этапов дорисовывались отдельными правилами
   в конце этого файла. Здесь собрано ТО, ЧЕГО НЕ ХВАТАЛО, и убраны копии:

   * поля ввода были БЕЗ оформления — в макетах это `input class="field"`,
     а на живых страницах `<input>` без класса, и браузер рисовал поле
     своим видом рядом с нашими кнопками (см. раздел «поля ввода»);
   * таблица админки СКРЫВАЛАСЬ на экранах до 1100 px, а карточки-замена
     были только у списка заказов: на карточке заказа состав, платежи,
     возвраты и история согласий просто исчезали (правило сужено до
     `.admin-table-switch`, остальные таблицы прокручиваются вбок);
   * фокус с клавиатуры рисовался полупрозрачным `#1658e833` — «виден»,
     но не виден; здесь один видимый фокус на всю админку и кабинет;
   * пустые состояния жили двумя именами (`.empty-app` и `.empty-state`)
     с разными отступами — сведены в одно.

   ЦВЕТА, РАДИУСЫ И ТИПОГРАФИКА НЕ ВВОДЯТСЯ ЗАНОВО: они берутся из
   `:root` выше (макеты v2.25). Здесь только ритм, состояния и адаптив.
   ============================================================ */

/* --- 1. Токены ритма и служебные классы ------------------------- */
:root{
  --space-xs:8px;
  --space-sm:12px;
  --space-md:16px;
  --space-lg:24px;
  --space-xl:32px;
  --radius-field:12px;
  --radius-panel:20px}
/* Скрытая подпись для экранного диктора: визуально её нет, но она есть
   в дереве доступности (заголовок колонки действий, подпись поиска). */
.sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0 0 0 0)!important;white-space:nowrap!important;border:0!important}

/* --- 2. Типографика и вертикальный ритм -------------------------
   Заголовок админки и кабинета — одного размера (в макетах 34 px), а не
   40 px витрины и не «как получилось». Блоки отделяются одним шагом
   (--space-lg/--space-xl), поэтому страница читается сверху вниз. */
.admin-main h1,.account-content h1{font-size:34px;line-height:1.2;letter-spacing:-1px;margin:0 0 var(--space-sm)}
.admin-main .lead,.account-content .lead{font-size:16px;line-height:1.6;color:var(--muted);max-width:820px;margin:0 0 var(--space-lg)}
.admin-main h2,.account-content h2{font-size:22px;line-height:1.3;margin:0 0 var(--space-sm)}
.admin-main h3,.account-content h3{font-size:16px;line-height:1.4;margin:0 0 10px}
.section-title{display:flex;align-items:center;justify-content:space-between;gap:var(--space-md);margin:var(--space-xl) 0 var(--space-md)}
.admin-main .section-title h1,.admin-main .section-title h2,.account-content .section-title h1,.account-content .section-title h2{margin:0}
.form-section{margin:0 0 var(--space-xl)}
.form-section:last-child{margin-bottom:0}
.box-panel{padding:var(--space-lg);margin:0 0 var(--space-lg)}
.box-panel:last-child{margin-bottom:0}
.box-panel h2{margin-bottom:var(--space-md)}
.box-panel h3{margin:var(--space-lg) 0 10px}
.box-panel>p{margin:0 0 var(--space-sm)}
.box-panel>p:last-child,.box-panel>*:last-child{margin-bottom:0}
/* Числа в одну ширину: суммы в столбце не «пляшут» (табличные цифры). */
.admin-stat .num,.stat .number,.bonus-hero .big,.cash-big,.cash-total span,.item-sum,.order-amounts strong,.admin-kv dd,.sum-row b,.admin-table .num,.history-item .amount{font-variant-numeric:tabular-nums}

/* --- 3. Поля ввода: одно поле на все формы ----------------------
   В макетах поле — это `input class="field"` с подписью `label class=
   "label"`. На живых страницах класс не ставился, поэтому поле выглядело
   системным прямоугольником. Здесь ОДНО описание поля и ОДНА подпись для
   всех форм админки и кабинета (в том числе для полей, добавленных без
   класса): размер, рамка, фокус, ошибка, выключенное состояние. */
.field,
:is(.input-wrap,.simple-form,.form-grid,.admin-filters,.admin-actions,.sync-login,.box-panel) :is(input,select,textarea):not([type=checkbox]):not([type=radio]):not([type=hidden]){
  width:100%;min-height:48px;padding:11px 14px;
  border:1px solid var(--control);border-radius:var(--radius-field);
  background:#fff;color:var(--text);font:inherit;font-size:16px;line-height:1.4}
.field:hover,
:is(.input-wrap,.simple-form,.form-grid,.admin-filters,.admin-actions,.sync-login,.box-panel) :is(input,select,textarea):not([type=checkbox]):not([type=radio]):not([type=hidden]):hover{
  border-color:#9eacc0}
.field:focus-visible,
:is(.input-wrap,.simple-form,.form-grid,.admin-filters,.admin-actions,.sync-login,.box-panel) :is(input,select,textarea):not([type=checkbox]):not([type=radio]):not([type=hidden]):focus-visible{
  border-color:var(--focus);outline:3px solid var(--focus);outline-offset:2px}
.field:disabled,
:is(.input-wrap,.simple-form,.form-grid,.admin-filters,.admin-actions,.sync-login,.box-panel) :is(input,select,textarea):disabled{
  background:var(--surface);color:#8793a3;cursor:not-allowed}
.field::placeholder,
:is(.input-wrap,.simple-form,.form-grid,.admin-filters,.admin-actions,.sync-login,.box-panel) :is(input,textarea)::placeholder{color:#8793a3}
.field[aria-invalid="true"],
:is(.input-wrap,.simple-form,.form-grid,.admin-filters,.admin-actions,.sync-login,.box-panel) :is(input,select,textarea)[aria-invalid="true"]{
  border-color:var(--danger)}
/* Подпись поля: одна во всех формах (у галочек и вариантов выбора подпись
   идёт строкой рядом с квадратиком, поэтому они исключены). */
.input-wrap>label,
.simple-form label:not(.check):not(.choice),
.form-grid label:not(.check),
.admin-filters label,
.admin-actions label,
.sync-login label,
.box-panel form>label{
  display:block;font-size:14px;font-weight:700;line-height:1.4;color:var(--text);margin:0 0 var(--space-xs)}
/* Шаг между полями: в сетке `.form-grid` его задаёт `gap`, в столбике —
   сам `.input-wrap`, чтобы «снега» из inline-отступов не было. */
.input-wrap{margin:0 0 18px}
.form-grid .input-wrap,.admin-filters .input-wrap{margin-bottom:0}
.form-grid{margin-bottom:0}
/* Вторая сетка полей под первой (реквизиты организации на оформлении):
   было inline-стилем в шаблоне `checkout.html`. */
.form-grid.spaced{margin-top:20px}
.input-wrap .small,.input-wrap .tiny{display:block;margin-top:var(--space-xs)}
/* Галочки и варианты выбора — один размер и одно поведение. */
.check{display:flex;align-items:flex-start;gap:10px;min-height:44px;font-size:14px;line-height:1.55;cursor:pointer}
.check input,.consent input{width:20px;height:20px;margin:2px 0 0;flex-shrink:0;accent-color:var(--primary)}
.check span,.consent span{min-width:0}
.form-error,.field-error{display:block;color:var(--danger);font-size:13px;line-height:1.5;margin-top:6px}

/* --- 4. Кнопки и ссылки в админке и кабинете --------------------
   Кнопка — 48 px (44 px в мелких местах), ссылка внутри текста и в
   таблице — один и тот же синий с подчёркиванием при наведении. */
.admin-main .btn,.account-content .btn,.admin-nav .btn,.account-nav .btn{min-height:48px}
.admin-table td a{color:var(--primary);font-weight:700}
.admin-table td a:hover{text-decoration:underline}
.admin-table td button:not(.btn){background:none;border:0;color:var(--primary);padding:0;min-height:44px;text-align:left;font-weight:700}
.page-actions{align-items:center;gap:var(--space-sm);margin:0 0 var(--space-lg)}
.admin-actions{display:grid;gap:var(--space-md)}
.admin-actions form{margin:0;display:grid;gap:10px}
.admin-actions .btn{width:100%}

/* --- 5. Таблицы админки: шапка, зебра, числа, прокрутка ---------
   ЧТО РЕШЕНО ЗДЕСЬ

   * «ЛИПКАЯ» ШАПКА: `thead th` остаётся сверху при прокрутке страницы —
     в длинном списке заказов видно, что за колонка перед вами;
   * ЗЕБРА И НАВЕДЕНИЕ: чётные строки чуть темнее, строка под курсором
     подсвечивается — глаз не теряет строку в семи колонках;
   * ЧИСЛА И ДАТЫ: суммы выровнены по правому краю табличными цифрами,
     даты и номера не переносятся;
   * ПРОКРУТКА вместо исчезновения: широкая таблица (журнал СБИС, состав
     заказа) прокручивается ВНУТРИ карточки (`.admin-table-scroll`), а не
     пропадает. Замена таблицы карточками (`.admin-table-switch`,
     `.admin-mobile-cards`) — только там, где карточки действительно есть
     в разметке: в списке заказов.

   ⚠️ ПОЧЕМУ У ЧАСТИ ТАБЛИЦ НЕТ ЛИПКОЙ ШАПКИ. `position:sticky` не работает
   внутри прокручиваемого контейнера, а `.admin-table-scroll` — именно он.
   Поэтому липкая шапка стоит у таблиц, которые прокручиваются страницей,
   а у широких таблиц выбран горизонтальный сдвиг. */
.admin-table{margin:0;font-size:14px;background:transparent;border-radius:0;overflow:visible}
.admin-table thead th{
  position:sticky;top:0;z-index:2;
  text-align:left;font-size:12px;font-weight:700;line-height:1.4;color:var(--muted);
  background:#edf2f9;padding:14px 16px;white-space:nowrap;
  box-shadow:inset 0 -1px 0 var(--line)}
.admin-table td{padding:16px;border-bottom:1px solid var(--line);vertical-align:top}
.admin-table tbody tr:nth-child(even){background:#fafbfe}
.admin-table tbody tr:hover{background:#f2f6fd}
.admin-table tbody tr:last-child td{border-bottom:0}
.admin-table .num,.admin-table th.num{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums;font-weight:700}
.admin-table td small{display:block;color:var(--muted);margin-top:6px}
.admin-table td .status-pill+small{margin-top:8px}
.nowrap{white-space:nowrap}
.admin-table-wrap{position:relative;background:#fff}
.admin-table-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.admin-table-scroll>.admin-table{min-width:680px}
.sync-runs{min-width:920px}

/* --- ЗАКРЕПЛЁННАЯ КОЛОНКА ДЕЙСТВИЙ (решение владельца 2026-10-14) --------
   ЗАДАЧА. На странице «Товар без раздела» кнопка «Привязать» не помещалась в
   экран, и чтобы привязать товар, приходилось сначала прокрутить таблицу вбок —
   лишнее действие на каждую строку. Владелец выбрал вариант: «Закрепить колонку
   действий — отличный вариант».

   ЧТО ДЕЛАЕТСЯ. Последняя колонка (`th`/`td` с классом `.is-sticky`) прижата к
   ПРАВОМУ краю прокручиваемого блока: при горизонтальной прокрутке она остаётся
   на месте, и выбор раздела с кнопкой видны всегда.

   ⚠️ ПОЧЕМУ ЭТО РАБОТАЕТ. `position: sticky` держится за ближайший
   прокручиваемый предок — а это и есть `.admin-table-scroll`. Именно поэтому
   липкость здесь возможна, хотя у широких таблиц липкой ШАПКИ нет (шапка липнет
   к странице, а не к блоку).

   ⚠️ ФОН ОБЯЗАТЕЛЕН. При прокрутке под колонкой проезжают данные, и без
   непрозрачного фона они просвечивали бы сквозь кнопку. Тень слева отделяет
   закреплённую колонку от содержимого — владелец просил, чтобы она не
   «сливалась».

   ⚠️ ВЫСОТА СТРОКИ НЕ РАСТЁТ (отдельное условие владельца). Контролы внутри
   закреплённой колонки — компактные и в ОДНУ строку: высота берётся не больше,
   чем у обычной строки таблицы, длинное название раздела обрезается троеточием,
   а не переносится. Растянуть строку значило бы получить ту же жалобу с другой
   стороны. */
.admin-table th.is-sticky,
.admin-table td.is-sticky{
  position:sticky;right:0;z-index:3;
  background:#fff;
  box-shadow:-12px 0 14px -12px rgba(22,38,56,.28),inset 1px 0 0 var(--line)}
.admin-table thead th.is-sticky{z-index:4;background:#edf2f9}
/* Чётная строка под закреплённой колонкой: цвет тот же, что у строки, иначе
   закреплённый столбец «вырезался» бы из зебры светлым прямоугольником. */
.admin-table tbody tr:nth-child(even) td.is-sticky{background:#fafbfe}
.admin-table tbody tr:hover td.is-sticky{background:#f2f6fd}
.admin-table td.is-sticky{vertical-align:middle}

/* Форма привязки: одна строка, компактные контролы. */
.admin-table .assign-form{display:flex;align-items:center;gap:8px;margin:0;flex-wrap:nowrap}
.admin-table .assign-form select{
  width:190px;min-width:120px;max-width:190px;min-height:36px;height:36px;
  padding:4px 10px;font-size:13px;line-height:1.4;
  text-overflow:ellipsis;white-space:nowrap;overflow:hidden}
.admin-table .assign-form .btn{
  min-height:36px;height:36px;padding:6px 14px;font-size:13px;line-height:1.4;
  white-space:nowrap;flex-shrink:0}
/* Компактная кнопка — та же высота, что у списка и у обычного текста строки.
   ⚠️ Без неё кнопка берёт свои 48px из общего правила `.btn` и поднимает
   высоту строки, а владелец просил этого не делать. */
.admin-table .is-sticky .btn.compact{
  min-height:36px;height:36px;padding:6px 12px;font-size:13px;line-height:1.4;
  white-space:nowrap;flex-shrink:0}
/* Кнопка-значок: 36×36, чтобы ссылки не растягивали закреплённую колонку.
   ⚠️ Подпись для чтения с экрана остаётся внутри (`.sr-only`) и в `title`:
   значок без подписи непонятен, а словесные подписи занимали 200px. */
.admin-table .is-sticky .btn.icon-only{
  width:36px;min-width:36px;padding:6px;gap:0;justify-content:center}
.admin-table .is-sticky .btn.icon-only .icon{width:18px;height:18px}
.admin-table .assign-label{font-size:12px;color:var(--muted);white-space:nowrap}
@media(max-width:1366px){
  /* На ноутбуках закреплённая колонка занимает почти всю высоту блока: делаем
     её чуть уже, чтобы под ней оставалось место данным. Высота строки та же. */
  .admin-table .assign-form select{width:170px;max-width:170px}
}
@media(max-width:1100px){
  /* ⚠️ ПОДПИСЬ «Раздел:» СКРЫВАЕТСЯ, А ШИРИНА СПИСКА РАСТЁТ. Так на 1024
     список остаётся читаемым (132px обрезали бы «Теплый пол под плитку» до
     «Теплый пол по…»), а колонка не съедает половину экрана. Подпись была
     пояснением к выбору, а не обязательным элементом: сам список рядом с
     кнопкой «Привязать» и так понятен, и его назначение дублирует скрытая
     подпись для чтения с экрана (`.sr-only`). */
  .admin-table .assign-label{display:none}
  .admin-table .assign-form select{width:160px;max-width:160px}
  .admin-table .assign-form{gap:6px}
}
/* Строка «липкой» шапки не должна перекрывать содержимое при печати. */
@media print{.admin-table thead th{position:static}}

/* --- 6. Фильтры, счётчики, пагинация ---------------------------- */
.admin-filters{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--space-md);align-items:end;margin:var(--space-lg) 0}
.admin-filters>div{max-width:none;min-width:0}
.admin-filters select,.admin-filters input{min-width:0;width:100%}
.admin-filters .btn{height:auto;min-height:48px}
.admin-filters-actions{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.admin-filters-actions .btn{width:auto}
.admin-counters{align-items:center;gap:10px;margin:var(--space-md) 0 6px}
.admin-counter{font-weight:700}
.admin-counter strong{font-variant-numeric:tabular-nums}
.admin-pager{gap:var(--space-xs);margin:var(--space-lg) 0}

/* --- 7. Пустые состояния и сообщения: одно место ----------------
   Раньше пустое состояние жило двумя именами (`.empty-app` — админка и
   кабинет, `.empty-state` — витрина) с разными отступами и разным
   размером значка. Теперь это ОДИН вид; сообщения (`.note`) получили
   пропущенные варианты «предупреждение» и «успех». */
.empty-app,.empty-state{padding:48px var(--space-lg);text-align:center;background:var(--surface);border-radius:var(--radius-panel);margin:var(--space-lg) 0}
.empty-app h2,.empty-state h2{font-size:22px;margin:var(--space-md) 0 10px}
.empty-app p,.empty-state p{color:var(--muted);max-width:520px;margin:0 auto var(--space-md)}
.empty-app .icon,.empty-state .icon{width:48px;height:48px;color:var(--control);margin:0 auto 6px}
.empty-app .btn,.empty-state .btn{margin-top:6px}
.note.warning{background:var(--warningSoft);color:var(--warning)}
.note.success{background:var(--successSoft);color:var(--success)}
.admin-main>.note,.account-content>.note{margin:0 0 var(--space-lg)}
.subtle-error{border-radius:12px;padding:14px 18px;margin:0 0 var(--space-lg);font-size:14px}

/* --- 8. Фокус с клавиатуры: одна видимая рамка ------------------
   В макетах фокус — сплошной синий. В правках прошлых этапов он стал
   полупрозрачным (`#1658e833`), и с клавиатуры не было видно, где ты
   находишься. Здесь фокус возвращён к сплошному и одинаков на всех
   элементах: меню, плитки, ссылки в таблицах, кнопки, раскрывашки. */
.account-nav a.account-link:focus-visible,
.account-nav form .btn:focus-visible,
.admin-nav a.admin-link:focus-visible,
.admin-nav .admin-link.soon:focus-visible,
.admin-nav form .btn:focus-visible,
.admin-counter:focus-visible,
.admin-pager a:focus-visible,
.admin-table td a:focus-visible,
.admin-table td button:focus-visible,
.pagination a.chip:focus-visible,
.card .media .fav-form .fav:focus-visible,
.tile a:focus-visible,
.account-tiles a:focus-visible,
.ds-trigger:focus-visible,
.filter-toggle:focus-visible,
.mega-category:focus-visible,
.mega-link:focus-visible,
.catalog-page a:focus-visible,
.catalog-page button:focus-visible,
summary:focus-visible{
  outline:3px solid var(--focus);outline-offset:2px}

/* --- 9. Кабинет покупателя: сетка, меню, содержимое -------------
   Макет кабинета — две колонки 240 px + содержимое, меню лежит на
   светлой подложке и «прилипает» при прокрутке (v2.224 unified buyer
   sidebar). Здесь те же правила для нашей разметки (`.account-shell`),
   чтобы меню не уезжало от содержимого и не «прыгало» на длинной
   странице. */
.account-shell{grid-template-columns:240px minmax(0,1fr);gap:var(--space-lg);align-items:start;margin:var(--space-lg) auto}
.account-nav{align-self:start;background:var(--surface);border-radius:18px;padding:10px;position:sticky;top:16px;max-height:calc(100vh - 32px);overflow:auto}
.account-nav .person{padding:8px 10px 14px;margin:0 0 var(--space-xs);border-bottom:1px solid var(--line)}
.account-nav a.account-link{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:11px 14px;border-radius:10px;color:var(--muted);margin:2px 0;text-decoration:none;font:inherit}
.account-nav a.account-link:hover{background:#fff;color:var(--primary)}
.account-nav a.account-link.active{background:var(--primarySoft);color:var(--primary);font-weight:700}
.account-nav form{margin:var(--space-sm) 0 0}
.account-nav form .btn{width:100%}
.account-content{padding-top:0}
.account-content .order-card+.order-card{margin-top:var(--space-sm)}
/* Меню админки ведёт себя как меню кабинета: не уезжает вверх при
   прокрутке длинной карточки заказа и не растягивает колонку. */
.admin-nav{align-self:start;position:sticky;top:0;max-height:100vh;overflow:auto}

/* --- 10. Мобильный вид до 767 px -------------------------------
   Что чинится: меню кабинета и админки больше не «уезжает» за край
   (пункты переносятся строками, а не разъезжаются), таблицы не исчезают,
   кнопки и поля занимают всю ширину карточки, отступы страниц
   выравниваются к 16 px. */
@media(max-width:767px){
  .account-shell{display:block;margin:14px auto 0}
  .account-nav{position:static;display:flex;flex-wrap:wrap;gap:6px;padding:10px;margin:0 0 var(--space-md);max-height:none;overflow:visible}
  .account-nav .person{display:none}
  .account-nav a.account-link{flex:1 1 30%;width:auto;justify-content:center;text-align:center;white-space:normal;margin:0;padding:10px 12px;font-size:13px;min-height:44px}
  .account-nav form{width:100%;margin:4px 0 0}
  .account-nav form .btn{width:100%;white-space:normal}
  .account-content h1{font-size:28px}
  .admin-shell{display:block}
  .admin-nav{display:flex;flex-wrap:wrap;gap:6px;align-items:center;padding:12px 12px 10px;position:static;max-height:none;overflow:visible}
  .admin-nav .logo{width:94px;height:36px;margin:0 12px 0 0}
  .admin-nav p{display:none}
  .admin-nav a.admin-link,.admin-nav .admin-link.soon{flex:1 1 30%;width:auto;justify-content:center;text-align:center;white-space:normal;margin:0;padding:10px 12px;font-size:13px;min-height:44px}
  .admin-nav form{width:100%;margin:4px 0 0}
  .admin-nav form .btn{width:100%;white-space:normal}
  .admin-main{padding:20px 16px}
  .admin-main h1{font-size:28px}
  .admin-top{flex-wrap:wrap;gap:10px;margin-bottom:20px;font-size:12px}
  .admin-top .btn{min-height:44px}
  .admin-table td,.admin-table th{padding:12px}
  .admin-table-scroll>.admin-table{min-width:600px}
  .box-panel{padding:18px;margin-bottom:var(--space-md)}
  .admin-filters-actions{grid-column:1/-1}
  .admin-filters-actions .btn{width:100%}
}
@media(max-width:479px){
  .admin-filters{grid-template-columns:1fr}
  .account-nav a.account-link,.admin-nav a.admin-link,.admin-nav .admin-link.soon{flex:1 1 100%}
}

/* --- 11. Страница выгрузки из СБИС (/admin/sync) ----------------
   Эти правила переехали сюда из блока `<style>` внутри шаблона
   `admin_sync.html`: в проекте ОДНА таблица стилей, «снега» из inline-
   стилей в разметке нет (этап 4, 2026-10-12). Отдельно о журнале: раньше
   он был `.spec-table`, у которой первая колонка занимает 60 % ширины, —
   в журнале из девяти колонок шапка и строки не совпадали по столбцам. */
.sync-login form{max-width:520px;margin-top:var(--space-sm)}
.sync-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-lg)}
.sync-action{padding:20px;border-radius:16px;background:var(--surface)}
.sync-action .btn{margin-top:var(--space-xs)}
.sync-action p{margin:0 0 6px}
.sync-action form{margin:var(--space-xs) 0 0}
.sync-error{max-width:420px;white-space:normal}
@media(max-width:767px){
  .sync-actions{grid-template-columns:1fr}
}

/* --- 11-бис. МИНИМАЛЬНАЯ ШАПКА АДМИНКИ, СТРОКА РАЗДЕЛОВ, ПЛОТНОСТЬ ----
   Правка владельца 2026-10-14 (дефекты со скриншота «Разделы каталога»).

   ЧТО ЛЕЧИТСЯ
   -----------
   1. ШАПКА АДМИНКИ — РОВНО ТРИ ДЕЙСТВИЯ: «Публичная часть», «Админ-панель»,
      «Выход» (разметка — `base_admin.html`). Публичная шапка витрины в
      админку больше не приезжает вовсе, а админская стала полосой 52 px:
      раньше её роль играла колонка меню с логотипом, и логотип стоял дважды.
   2. СТРОКА РАЗДЕЛА — ОДНА СТРОКА на широком экране (`.cat-row`): раньше три
      галочки и две кнопки стояли в узкой колонке таблицы ДРУГ ПОД ДРУГОМ, и
      один раздел занимал около двухсот пикселей высоты.
   3. ПЛОТНОСТЬ: меньше «воздуха» над заголовком, под ним и внутри блоков
      админки. Кнопки и поля ниже 44 px не опускаются — по ним нажимают
      пальцем.

   ⚠️ ПРАВИЛА ПЛОТНОСТИ ОГРАНИЧЕНЫ КОНТЕЙНЕРОМ АДМИНКИ. `.box-panel`,
   `.admin-table` и `.empty-app` живут ещё и в кабинете
   (`account_addresses.html`, `account_consents.html`) и на витрине
   (`requisites.html`), поэтому плотность задана через `.admin-main …`, а не
   «вообще»: витрина и кабинет этими правками не меняются. */

/* Высота шапки админки — одним числом: от неё считают высоту каркас и меню. */
:root{--admin-head-h:52px}

/* 1. Шапка админки: три действия, полоса 52 px, «липнет» к верху экрана. */
.admin-head{
  position:sticky;
  top:0;
  z-index:40;
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:6px 4px;
  min-height:var(--admin-head-h);
  padding:4px 18px;
  background:var(--background);
  border-bottom:1px solid var(--line)}
.admin-head-item{
  display:inline-flex;
  align-items:center;
  min-height:44px;
  padding:0 14px;
  border-radius:var(--radius-button);
  color:var(--muted);
  font-size:14px;
  font-weight:700}
.admin-head-item:hover{background:var(--surface);color:var(--primary)}
.admin-head-item.is-current{background:var(--primarySoft);color:var(--primary)}
.admin-head-exit{display:flex;margin:0 0 0 auto}
.admin-head-exit .btn{min-height:44px}
/* Каркас занимает остаток экрана под шапкой. */
.admin-shell{min-height:calc(100vh - var(--admin-head-h))}
@media(min-width:768px){
  /* Меню разделов «липнет» ПОД шапкой, а не под её край: иначе оно уезжало
     бы под неё при прокрутке длинного списка. На телефоне меню статичное
     (правило в разделе 10), и высоту ему задавать не нужно. */
  .admin-nav{top:var(--admin-head-h);max-height:calc(100vh - var(--admin-head-h))}
}

/* 2. Плотность админских страниц: заголовки, блоки, таблицы, пустые состояния. */
.admin-main{padding:16px 28px 28px}
.admin-top{margin-bottom:14px}
.admin-main h1{margin-bottom:8px}
.admin-main .lead{margin:0 0 16px}
.admin-main .note{margin:0 0 14px}
.admin-main .box-panel{padding:16px 18px;margin:0 0 14px}
.admin-main .box-panel h2{font-size:19px;margin-bottom:6px}
.admin-main .box-panel h3{margin:12px 0 6px}
.admin-main .box-panel>p{margin:0 0 8px}
.admin-main .admin-filters{margin:0 0 14px}
.admin-main .empty-app,.admin-main .empty-state{padding:24px 18px;margin:14px 0}
.admin-main .admin-table thead th{padding:10px 12px}
.admin-main .admin-table td{padding:10px 12px}
.admin-main .admin-table td small{margin-top:2px}
.admin-main .admin-table td .status-pill+small{margin-top:3px}

/* 3. Массовое действие «оставить только выбранные разделы»: заметное, но
   одной строкой с пояснением — что именно произойдёт. */
.admin-bulk{background:var(--primarySoft)}
.admin-bulk-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px 18px;justify-content:space-between}
.admin-bulk-row .admin-note{flex:1 1 320px;min-width:0;margin:0;font-size:13px;line-height:1.5}
.admin-bulk-btn{min-height:44px;white-space:nowrap}

/* 4. Строка раздела: одна строка на широком экране, аккуратный перенос на
   узком. Порядок — как просил владелец: название и код, счётчики, метки
   состояния, затем справа галочки, «Сохранить» и «Снять товары с продажи». */
.cat-list{
  list-style:none;
  margin:0;
  padding:0;
  background:#fff;
  border-radius:var(--radius-panel);
  box-shadow:var(--shadow);
  overflow:hidden}
.cat-row{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:6px 14px;
  padding:8px 14px;
  border-bottom:1px solid var(--line)}
.cat-row:last-child{border-bottom:0}
.cat-row:nth-child(even){background:#fafbfe}
.cat-row:hover{background:#f2f6fd}
.cat-row-main{display:flex;flex:1 1 200px;min-width:0;flex-direction:column;gap:1px}
.cat-row-name{font-size:14px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}
.cat-row-code{font-size:12px;line-height:1.4;color:var(--muted)}
.cat-row-counts{display:flex;flex-wrap:wrap;gap:2px 12px;font-size:13px;line-height:1.5;color:var(--muted);white-space:nowrap}
.cat-row-counts b{color:var(--text);font-variant-numeric:tabular-nums}
.cat-row-counts small{display:inline;font-size:12px;color:var(--muted)}
.cat-row-pills{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.cat-row-pills .status-pill{margin:0}
.cat-row-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;margin-left:auto;justify-content:flex-end}
.cat-row-form{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;margin:0}
/* Галочки строки — в линию с подписью (в общем правиле `.check` они высотой
   44 px и подпись идёт под квадратиком: для строки списка это лишняя высота). */
.cat-row-actions .check{min-height:0;align-items:center;gap:8px;margin:0;font-size:13px;line-height:1.3}
.cat-row-actions .check input{width:18px;height:18px;margin:0}
.cat-row-actions .btn{min-height:44px;padding:8px 14px;font-size:13px;white-space:nowrap}
.cat-row-actions>small{font-size:12px;color:var(--muted)}

/* 5. Справка «что важно знать про скрытие» — свёрнута внизу страницы: текст
   целиком остаётся в разметке и читается без JavaScript. */
.admin-help-details{margin-top:14px}
.admin-help-details summary{display:flex;align-items:center;min-height:44px;font-size:15px;font-weight:700;cursor:pointer}
.admin-help-details .admin-note{margin:6px 0 0}

/* 6. ПОДВАЛ АДМИНКИ — панель обращения к владельцу (правка владельца
   2026-10-14). ⚠️ ЭТО НЕ ПОДВАЛ ВИТРИНЫ: публичного подвала (контакты,
   документы, Telegram) в админке нет, здесь только обращение к владельцу.
   Панель СВЁРНУТА (`<details>`): в закрытом виде — одна строка с подписью, а
   форма и список обращений раскрываются браузером без JavaScript. Так подвал
   не «съедает» экран, но всегда под рукой. */
.admin-foot{background:var(--background);border-top:1px solid var(--line);padding:0 18px}
.admin-appeals summary{display:flex;flex-wrap:wrap;align-items:center;gap:6px 16px;min-height:48px;cursor:pointer;list-style:none}
.admin-appeals summary::-webkit-details-marker{display:none}
.admin-appeals summary::marker{content:''}
.admin-appeals-title{font-size:14px;font-weight:700;color:var(--text)}
.admin-appeals-title::before{content:'✉';margin-right:8px;color:var(--primary)}
.admin-appeals-hint{font-size:13px;color:var(--muted)}
.admin-appeals[open] .admin-appeals-title{color:var(--primary)}
.admin-appeals-body{padding:0 0 16px;max-width:900px}
.admin-appeals-form{display:grid;grid-template-columns:minmax(180px,240px) minmax(0,1fr) auto;gap:10px 14px;align-items:start}
.admin-appeals-field label{display:block;font-size:13px;font-weight:700;margin-bottom:4px}
.admin-appeals-form select,.admin-appeals-form textarea{
  width:100%;min-height:44px;padding:8px 12px;
  border:1px solid var(--control);border-radius:var(--radius-field);
  background:#fff;color:var(--text);font:inherit;font-size:14px;line-height:1.4}
.admin-appeals-form textarea{min-height:56px;resize:vertical}
.admin-appeals-form .btn{min-height:44px;align-self:start}
.admin-appeals-note{grid-column:1/-1;margin:0;font-size:12px;color:var(--muted)}
.admin-appeals-list{margin-top:14px}
.admin-appeals-list-title{margin:0 0 6px;font-size:13px;font-weight:700;color:var(--muted)}
.admin-appeals-list ul{list-style:none;margin:0;padding:0;display:grid;gap:8px}
.admin-appeals-item{padding:10px 12px;border:1px solid var(--line);border-radius:var(--radius-field);background:var(--surface)}
.admin-appeals-item-head{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px}
.admin-appeals-meta{font-size:12px;color:var(--muted)}
.admin-appeals-item-body{margin:6px 0 0;font-size:14px;line-height:1.5;overflow-wrap:anywhere}
.admin-appeals-answer{margin:6px 0 0;padding:8px 10px;border-radius:10px;background:var(--successSoft);color:var(--text);font-size:13px;line-height:1.5}
.admin-appeals-item-actions{display:flex;flex-wrap:wrap;gap:8px 12px;margin-top:8px;align-items:center}
.admin-appeals-item-actions form{margin:0;display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.admin-appeals-answer-form{flex:1 1 320px}
.admin-appeals-answer-form input{flex:1 1 200px;min-height:44px;padding:8px 12px}
.admin-appeals-item-actions .btn{min-height:44px}
@media(max-width:1100px){
  .admin-appeals-form{grid-template-columns:minmax(0,1fr)}}
@media(max-width:767px){
  .admin-foot{padding:0 12px}
  .admin-appeals-body{padding-bottom:14px}
  .admin-appeals-form .btn{width:100%;justify-content:center}
  .admin-appeals-item-actions form,.admin-appeals-answer-form{flex:1 1 100%}
  .admin-appeals-item-actions .btn{flex:1 1 auto;justify-content:center}}

/* Узкий экран: строка раздела переносится на две-три линии, кнопки остаются
   удобными для пальца (44 px) и не выходят за карточку. */
@media(max-width:1100px){
  .cat-row-main{flex:1 1 100%}
  .cat-row-actions{flex:1 1 100%;margin-left:0;justify-content:flex-start}}
@media(max-width:767px){
  .admin-head{padding:4px 12px}
  .admin-head-item{padding:0 12px}
  .admin-main{padding:14px 16px 20px}
  .cat-row{padding:8px 12px;gap:4px 10px}
  .cat-row-counts{white-space:normal}
  .cat-row-form{width:100%}
  .cat-row-actions .btn{flex:1 1 auto;justify-content:center}
  .admin-bulk-btn{flex:1 1 100%}}

/* --- 12. Числа в кружке у иконок шапки (правка владельца 2026-10-12) --
   Владелец: у иконок должны быть ЧИСЛА В КРУЖКЕ — у «Избранного» товары
   в избранном, у «Корзины» товары в корзине, у «Профиля» непрочитанные
   уведомления; если число ноль, кружки НЕТ. Вид — как на скриншоте
   владельца: синий круг с белым числом в правом верхнем углу иконки.

   ⚠️ ПОЧЕМУ КРУГ, А НЕ ПИЛЮЛЯ (`.nolik-count` из админского макета).
   Пилюля растягивается по числу цифр и уезжает вбок, а у нас три иконки
   в ряд с подписями — сдвиг ломал бы шапку. Круг одного размера не
   зависит от длины числа; три цифры и больше он НЕ растягивает,
   а принимает по центру (min-width + border-radius:50%).

   ⚠️ ПОЧЕМУ ОБЁРТКА `.head-icon` / `.nav-icon`, А НЕ КРУЖОК ВНУТРИ <a>.
   Кружок позиционируется от ИКОНКИ, а не от ссылки: у ссылки внизу есть
   подпись («Корзина»), и круг, отсчитанный от ссылки, оказался бы над
   подписью, а не в углу иконки. Обёртка держит иконку и круг вместе;
   размер обёртки задаёт сама иконка (22 px в шапке, 23 px в меню
   телефона), поэтому правила одни на оба места. */
.head-icon,.nav-icon{
  position:relative;
  display:inline-flex;
  align-items:center;
  justify-content:center}
.head-badge{
  position:absolute;
  top:-6px;
  right:-9px;
  z-index:1;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-width:18px;
  height:18px;
  padding:0 4px;
  border-radius:999px;
  background:var(--primary);
  color:var(--onPrimary);
  font:bold 11px/1 Arial,sans-serif;
  font-variant-numeric:tabular-nums;
  letter-spacing:0;
  white-space:nowrap;
  pointer-events:none}
/* В нижнем меню телефона иконки чуть крупнее (23 px) — круг сдвигается
   на ту же величину, чтобы угол остался углом. */
.nav-icon .head-badge{top:-7px;right:-10px}

/* Раздел главной: отступ заголовка блока — ровно как в макете v2.25
   (`.section-title{margin-bottom:22px}`). Общее правило ритма (раздел 2)
   задаёт здесь 32 px для админки и кабинета, и оно же перекрывало макет
   на главной: это лечит точечное правило ВНУТРИ контента витрины, не
   трогая уже принятые экраны админки и кабинета. */
.content>.section>.section-title{margin-bottom:22px}

/* --- 13. Верхняя полоса: город и ссылки на одной линии (правка владельца
   2026-10-12) ------------------------------------------------------------
   Владелец: ссылки «скачут» и не выровнены; метка и название города должны
   быть на всех страницах; метка открывает список городов.

   ⚠️ ОДНА ВЫСОТА И ОДНА БАЗОВАЯ ЛИНИЯ. Город (`.city-summary`), ссылки
   (`.top-links a`) и сама строка (`.topbar .wrap`) — 44 px и центрирование
   по вертикали. Раньше у города и ссылок были разные отступы (у ссылок
   `min-height:30px` на телефоне, у строки 38/30 px), поэтому левая и правая
   половины полосы стояли на разной высоте, а на телефоне вторая ссылка
   вообще пропадала (`display:none` у `:not(:first-child)`) — «скакала»
   именно она. Теперь на телефоне показаны ОБЕ ссылки, а полоса при
   нехватке места переносится строками, а не обрезается.

   ⚠️ КРУЖОК ЧИСЛА СДВИГАЕТ ПОЛОСУ ВЛЕВО. У иконки «Избранное»/«Корзина»
   в шапке число стоит в правом верхнем углу (раздел 12). Чтобы оно
   не наезжало на соседнюю иконку, зазор `.main-head` между действиями
   покупателя чуть больше зазора до поиска — это видно на телефоне, где
   иконки стоят вплотную. */
.topbar .wrap{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:16px;
  min-height:44px;
  flex-wrap:wrap}
.top-links{
  display:flex;
  align-items:center;
  gap:20px;
  flex-wrap:wrap}
.top-links a{
  display:inline-flex;
  align-items:center;
  min-height:44px;
  font-size:13px;
  color:var(--muted)}
.top-links a:hover{color:var(--text)}

.city-picker{position:relative}
.city-summary{
  position:relative;
  display:inline-flex;
  align-items:center;
  gap:8px;
  min-height:44px;
  padding:0 22px 0 2px;
  margin:0;
  border:0;
  background:none;
  color:var(--muted);
  font:13px/1.2 Arial,sans-serif;
  cursor:pointer;
  list-style:none}
.city-summary::-webkit-details-marker{display:none}
.city-summary::marker{content:''}
.city-summary:hover{color:var(--text)}
.city-mark{display:inline-flex;color:var(--muted)}
.city-mark .icon{width:18px;height:18px}
.city-mark-home,.city-picker[open] .city-mark{color:var(--primary)}
.city-name{font-weight:700}
.city-caret{
  position:absolute;
  right:6px;
  top:calc(50% - 3px);
  width:7px;
  height:7px;
  border:solid currentColor;
  border-width:0 1.5px 1.5px 0;
  transform:rotate(45deg)}
.city-picker[open] .city-caret{transform:rotate(-135deg)}

/* ⚠️ РАСКРЫТЫЙ СПИСОК ГОРОДОВ ИДЁТ ПОВЕРХ ЛИПКОЙ ШАПКИ (правка владельца
   2026-10-12: дефект был виден и на стенде, и на боевом сервере).

   ⚠️ ПРИЧИНА БЫЛА РОВНО ОДНА — ПОРЯДОК НАЛОЖЕНИЯ, А НЕ ОБРЕЗКА.
   У липкой шапки `.main-head` слой `z-index:60` (раздел 14 ниже), а у списка
   стояло `z-index:40`. Оба числа сравниваются в ОДНОМ контексте наложения:
   ни `.topbar`, ни `.topbar .wrap`, ни `.city-picker` своего слоя не создают
   (у них нет `z-index`, `transform`, `filter`, `opacity`, `isolation`), поэтому
   список спорит с шапкой напрямую, а не «внутри полосы с городом». Меньшее
   число проигрывает, и белый непрозрачный фон шапки (`background:#fff`)
   закрывал верх списка: шапка стоит в разметке ПОСЛЕ полосы с городом.

   Теперь слой списка — 90: ВЫШЕ шапки (60) и НИЖЕ нижнего меню телефона
   (100), которое обязано оставаться поверх содержимого. Правило одно на весь
   файл: медиазапросы слой не меняют — точка перелома ПК (>1100), планшета
   (768–1100) и телефона (≤767) на порядок наложения не влияет, а мобильный
   блок ниже задаёт только ширину и сдвиг влево. Договор об этом проверяет
   `tests/unit/web/test_storefront_style_contract.py`.

   ⚠️ ОБРЕЗКИ НЕ БЫЛО — И БЫТЬ НЕ ДОЛЖНО. Список позиционирован абсолютно от
   `.city-picker` (`position:relative`), и ни один родитель по цепочке
   (`.city-picker` → `.topbar .wrap` → `.topbar` → `body`) не задаёт
   `overflow:hidden/auto/scroll/clip`: обрезать список нечему. Так и должно
   остаться; если родителю однажды понадобится `overflow` (например, ради
   горизонтальной прокрутки), список придётся ВЫНОСИТЬ из этого контейнера,
   а не «поднимать слой»: `z-index` от обрезки родителя не спасает.

   Ширина по содержимому, но не шире экрана: на телефоне список упирается
   в поля полосы, а не уезжает вбок. */
.city-list{
  position:absolute;
  left:-4px;
  top:calc(100% + 8px);
  z-index:90;
  width:292px;
  max-width:calc(100vw - 32px);
  padding:10px;
  border:1px solid var(--line);
  border-radius:14px;
  background:#fff;
  box-shadow:var(--shadow)}
.city-list-title{
  margin:4px 8px 8px;
  font-size:12px;
  color:var(--muted)}
.city-option{
  display:flex;
  align-items:center;
  gap:10px;
  width:100%;
  min-height:44px;
  padding:8px 10px;
  border:0;
  border-radius:10px;
  background:none;
  color:var(--muted);
  font:14px/1.3 Arial,sans-serif;
  text-align:left;
  cursor:pointer}
.city-option:hover{background:var(--surface);color:var(--text)}
.city-option:focus-visible{outline:3px solid var(--focus);outline-offset:-3px}
.city-option-mark{display:inline-flex;color:#8492A3}
.city-option-mark .icon{width:20px;height:20px}
.city-option-name{flex:1;min-width:0}
.city-option-note{font-size:12px;color:var(--muted)}
/* Наш город (и франчайзи — см. `cities_view`): цвет акцента и метка. */
.city-option.is-home,.city-option.is-home .city-option-mark{color:var(--primary)}
.city-option.is-home .city-option-name{font-weight:700;color:var(--primary)}
.city-list-hint{
  margin:8px;
  font-size:12px;
  line-height:1.45;
  color:var(--muted)}
@media(max-width:767px){
  .topbar{padding:2px 0}
  /* ⚠️ В макете на телефоне вторая ссылка полосы была скрыта
     (`.top-links a:not(:first-child){display:none}`), и владелец увидел
     ровно это: ссылки «скачут» и стоят не на одной линии. Возвращаем обе:
     полоса переносится строками, а не обрезает себя. */
  .topbar .wrap{gap:4px 12px;min-height:40px;padding-top:2px;padding-bottom:2px}
  .topbar .wrap,.top-links a,.city-summary{font-size:12px}
  .top-links{gap:14px}
  .top-links a{display:inline-flex;min-height:40px}
  .city-summary{min-height:40px}
  .city-list{left:-8px;width:280px}
}

/* --- 14. Липкая шапка и окантовка поиска (правка владельца 2026-10-12,
   образец — «ВсеИнструменты») --------------------------------------------

   ⚠️ ЧТО ФИКСИРУЕТСЯ. При прокрутке вниз сверху остаётся ТОЛЬКО шапка
   (`.main-head`: логотип, «Каталог», поиск, иконки с числами). Строка над
   шапкой (`.topbar`: город и ссылки) и строка категорий (`.nav-cats`)
   уезжают вместе со страницей — владелец сказал это прямо, и в макете
   `home.html` обратного нет: там шапка вообще без прокрутки (прототип).

   ⚠️ ПОЧЕМУ `position:sticky`, А НЕ КОПИЯ ШАПКИ И НЕ `position:fixed`.
   `sticky` оставляет шапку В ПОТОКЕ документа: она занимает своё место
   в разметке всегда, поэтому в момент фиксации контент не сдвигается
   ни на пиксель (рывка нет по построению, а не «почти нет»). Копия шапки
   потребовала бы слежения за прокруткой и дублировала бы разметку вместе
   с числами; `fixed` вырвал бы шапку из потока и дал бы скачок.

   ⚠️ ПОЧЕМУ КОМПАКТНАЯ ВЫСОТА — ЭТО РАЗМЕР ИКОНОК ПЛЮС ЗАПАС.
   Требование владельца: «высота = высота иконок + запас 5–10 px сверху
   и снизу». Иконка в шапке 22 px (`--head-icon`), запас — 8 px сверху
   и снизу (`--head-pad-y`; на телефоне иконка 24 px, запас 6 px). Отступы
   заданы ОДИН РАЗ для любого состояния: шапка не «раздувается» при
   фиксации не потому, что мы её уменьшаем на прокрутке, а потому что она
   и в обычном виде компактная. Это убирает вторую возможную причину рывка
   и не требует ни одного скрипта (JS у нас только про меню, фильтры
   и галерею — см. `static/js/site.js`).

   ⚠️ ПОЧЕМУ z-index 60. Ниже нижнего меню телефона (`z-index:100`), выше
   содержимого страницы и выше слоя уведомлений витрины (`.site-notices`,
   `z-index:45`): объявление не наезжает на шапку — при прокрутке оно уходит
   ПОД неё, а не поверх. Оверлеи каталога ищут шапку через DOM (она идёт
   первой), поэтому фиксация их не ломает. */
.main-head{
  position:sticky;
  top:0;
  z-index:60;
  background:#fff;
  padding-top:var(--head-pad-y);
  padding-bottom:var(--head-pad-y);
  border-bottom:1px solid var(--line)}
/* Высота липкой полосы — иконка плюс запас сверху и снизу. */
.main-head .head-icon,.main-head .head-action>.icon{height:var(--head-icon)}
.main-head .head-icon .icon{height:var(--head-icon);width:var(--head-icon)}

/* ⚠️ ОКАНТОВКА ПОИСКА — ОДИН КОНТУР ВОКРУГ ВСЕГО ПОЛЯ (вместе с лупой).
   Раньше по фокусу рисовался синий прямоугольник ВНУТРИ поля: общее
   правило фокуса (`outline:3px solid var(--focus); outline-offset:3px`,
   см. начало файла) срабатывало на самом `<input>`, который лежит внутри
   поля, — контур обводил только текстовую часть и не касался лупы.

   Теперь фокус ВНУТРИ поля переносит контур на обёртку `.search`:
   `outline-offset:-2px` — по внешнему периметру, `border-radius:inherit` —
   по форме поля, толщина `2px` вместо `3px` (в 1,5 раза тоньше), оттенок
   тот же (`--focus`). Работает и при клике мышью, и с клавиатуры:
   `:focus-within` срабатывает в обоих случаях, одинаково на телефоне.

   ⚠️ ФОКУС ОСТАЁТСЯ ЗАМЕТНЫМ. Контур не убран, а перенесён: у самого поля
   ввода собственный контур снят ровно потому, что его место занял контур
   обёртки. Проверяется тестом `test_storefront_style_contract.py`. */
.search:focus-within{
    /* Скругление здесь не переопределяем: прежний inherit брал радиус родителя (0)
       и рамка выглядела прямоугольной (замечание владельца 21.10.2026). Своё
       скругление поля (14 px, на телефоне 12 px) остаётся, тень его повторяет. */
    outline:none;
    box-shadow:0 0 0 2px var(--primary)}
.search input:focus,
.search input:focus-visible{outline:none}
@media(max-width:767px){
  /*: На телефоне шапка компактнее. Переменные — на :root, потому что ими
     пользуются и шапка, и отступ якорей (#specs, #description). */
  :root{--head-pad-y:6px;--head-icon:24px}
}

/* --- 15. Ленты со СТРЕЛКАМИ вместо горизонтальной прокрутки (правка
   владельца 2026-10-12, образец — «ВсеИнструменты») ---------------------

   ⚠️ ЧТО БЫЛО НЕ ТАК. Блоки, которые не влезают по ширине (плитки-подборки,
   ленты товаров, чипсы разделов), ехали вбок, и единственным способом
   добраться до следующих плиток была горизонтальная прокрутка колёсами или
   свайпом. На компьютере с обычной мышью горизонтальной прокрутки НЕТ
   ВООБЩЕ, а полосы прокрутки мы сами спрятали (`scrollbar-width:none`):
   покупатель видел обрезанную третью плитку и не понимал, что там ещё что-то
   есть. Владелец сказал прямо: «убрать горизонтальную прокрутку как основной
   способ, сделать стрелки по краям».

   ⚠️ ЧТО ТЕПЕРЬ. Кнопки-стрелки по краям ленты: круглые, полупрозрачно-белые
   с тенью (`--surface` в белом круге, `--shadow`), появляются ТОЛЬКО когда
   листать есть куда, и скрываются, когда лента у края (`hidden`, ставит
   `site.js`). Прокрутку они двигают плавно на ширину видимой части
   (`scrollBy`), работают мышью и с клавиатуры (это `<button>`, поэтому Tab и
   Enter работают по умолчанию), а подписи для диктора заданы в разметке
   (`aria-label="Предыдущие подборки"` / `"Следующие подборки"`). Фокус виден:
   общее правило `:focus-visible` выше рисует контур 3 px.

   ⚠️ СВАЙП И КОЛЕСО ОСТАЮТСЯ, НО ПЕРЕСТАЮТ БЫТЬ ЕДИНСТВЕННЫМ СПОСОБОМ.
   Лента остаётся `overflow-x:auto` со `scroll-snap`: палец на телефоне
   работает как раньше, а мышь получила стрелки. Клавиатура тоже листает:
   `site.js` вешает `keydown` на ленту (стрелки влево/вправо), и лента
   получает `tabindex="0"` вместе с `role="group"` и подписью.

   ⚠️ ПОЧЕМУ БЕЗ JAVASCRIPT СТРЕЛОК НЕ ВИДНО. Стрелку показывает скрипт,
   когда узнаёт, что листать есть куда. Без скрипта кнопка «влево» на ленте,
   стоящей в начале, была бы мёртвой кнопкой — а мёртвых кнопок у нас нет.
   Поэтому в разметке стрелки помечены `hidden`, и без JavaScript их просто
   нет: лента листается пальцем и с клавиатуры, как раньше.

   ⚠️ ТОЧКИ ПЕРЕЛОМА. На ПК (>1100) стрелки тоже есть у лент, которые
   действительно едут (плитки-подборки при большом числе плиток), а сетка
   товаров на ПК — не лента вовсе, стрелок у неё нет: листать нечего.
   Планшет (768–1100) и телефон (≤767) — ленты со стрелками. */

/* Обёртка ленты: позиция для стрелок и место, чтобы они не перекрывали
   содержимое (стрелка выступает за край ленты на 8 px, как в образце). */
.scroll-rail{position:relative;min-width:0}

/* Лента: то же поведение прокрутки, что было, плюс клавиатура.
   `scroll-behavior:smooth` отключается общим правилом
   `prefers-reduced-motion` в начале файла — движение по требованию
   системы отключается целиком, а не по частям. */
.scroll-rail [data-rail-track]{
  overflow-x:auto;
  scroll-behavior:smooth;
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch}
.scroll-rail [data-rail-track]::-webkit-scrollbar{display:none}
.scroll-rail [data-rail-track]:focus-visible{
  outline:3px solid var(--focus);
  outline-offset:3px;
  border-radius:var(--radius-card)}

/* Стрелка: круг 44 px (палец и мышь попадают без прицеливания),
   по центру высоты ленты.

   ⚠️ ФОН ПОЧТИ ПРОЗРАЧНЫЙ (правка владельца 2026-10-13). Раньше круг был
   залит белым почти полностью (`rgba(255,255,255,.92)`) и НАКРЫВАЛ текст
   баннера: стрелка стоит вплотную к подписи плитки, и покупатель читал
   «ДЛЯ РАБО…» вместо «ДЛЯ РАБОТЫ И ДОМА». Теперь заливка — белый 16 %:
   под стрелкой ВИДНО то, что под ней (размытия фона нет намеренно —
   размытый текст читается хуже, чем текст под лёгкой плёнкой).

   ⚠️ ИКОНКА ЧИТАЕМА НА ЛЮБОМ БАННЕРЕ. Плитки бывают светлые (`#eaf0ff`,
   `#f0f2f6`, белые карточки товаров) и синие (`#1658e8` с белым текстом) —
   одной заливки, годной для обоих, не существует. Поэтому сама стрелка
   тёмная (`var(--text)`) и с белым ореолом (`drop-shadow`): на светлом фоне
   виден тёмный штрих, на синем — он же, отделённый от фона светлым кантом.
   Тень круга отделяет стрелку от плитки, не перекрывая текст.
   При наведении и с клавиатуры (`:focus-visible`) заливка плотнее — видно,
   на что нажали. */
.rail-arrow{
  position:absolute;
  top:50%;
  transform:translateY(-50%);
  z-index:3;
  width:44px;
  height:44px;
  padding:0;
  border:1px solid rgba(255,255,255,.45);
  border-radius:50%;
  background:rgba(255,255,255,.16);
  color:var(--text);
  box-shadow:0 4px 14px rgba(27,53,87,.16);
  display:flex;
  align-items:center;
  justify-content:center}
.rail-arrow:hover,
.rail-arrow:focus-visible{background:rgba(255,255,255,.4)}
.rail-arrow[hidden]{display:none}
.rail-arrow .icon{width:20px;height:20px;filter:drop-shadow(0 0 3px rgba(255,255,255,.9))}
.rail-prev{left:-8px}
.rail-next{right:-8px}
/* Стрелка у края экрана не должна уезжать за него на телефоне. */
@media(max-width:767px){
  .rail-arrow{width:40px;height:40px;box-shadow:0 4px 16px rgba(27,53,87,.14)}
  .rail-prev{left:-4px}
  .rail-next{right:-4px}
}

/* Ленты главной: на планшете и телефоне плитки едут вбок (стрелки), на ПК
   «Новинки» и «Рекомендуемые» остаются сеткой 4 колонки: там листать нечего,
   и превращать сетку в ленту на широком экране незачем. */
@media(max-width:1100px){
  .home-products[data-rail-track]{
    display:flex;
    gap:16px;
    scroll-snap-type:x mandatory;
    padding-bottom:4px}
  .home-products[data-rail-track]>.card{
    flex:0 0 46%;
    scroll-snap-align:start;
    min-width:0}
  .category-chips[data-rail-track]{
    scroll-snap-type:x proximity;
    padding-bottom:4px}
}
@media(max-width:767px){
  .home-products[data-rail-track]>.card{flex:0 0 74%}
}
/* Ещё уже телефона (≤479): карточка занимает почти всю ширину ленты, как
   в макете, и стрелки остаются единственным «кнопочным» способом листать. */
@media(max-width:479px){
  .home-products[data-rail-track]>.card{flex:0 0 88%}
}

/* Чипсы разделов и брендов: те же классы, что были, плюс лента со стрелками
   на узких экранах. Полоса прокрутки спрятана и здесь (`scrollbar-width`
   ниже), поэтому стрелки — единственный видимый признак, что список длиннее
   экрана. */
.category-chips{
  display:flex;
  flex-wrap:wrap;
  gap:10px;
  margin-bottom:28px}
@media(max-width:1100px){
  .category-chips{
    flex-wrap:nowrap;
    overflow-x:auto;
    scrollbar-width:none;
    -webkit-overflow-scrolling:touch}
  .category-chips::-webkit-scrollbar{display:none}
  .category-chips>.chip{flex:0 0 auto}
}

/* Текст подзаголовка плитки (поле `subtitle` баннера): мельче заголовка,
   наследует цвет плитки — на синей плитке он тоже белый. */
.promo-text{font-size:13px;line-height:1.45;opacity:.85;max-width:34ch}

/* Синонимы вариантов оформления: в макете v2.25 плитки назывались
   `promo-tool` / `promo-fix` / `promo-team` (по смыслу подборки), а баннер
   из базы называет оформление `light` / `gray` / `accent`. Оба набора классов
   рисуют ОДНО И ТО ЖЕ: старые остались, чтобы запасные три плитки макета
   выглядели как раньше, а новые — чтобы оформление можно было выбрать
   в админке, не привязывая цвет к смыслу плитки. */
.promo-light{background:#eaf0ff}
.promo-gray{background:#f0f2f6}
.promo-accent{background:#1658e8;color:white}
.promo-accent .promo-symbol{opacity:.22}
.promo-light .promo-copy{max-width:63%}
.promo-gray .promo-copy{max-width:63%}
.promo-accent .promo-copy{max-width:63%}

/* Плитки-подборки главной: пока плиток ТРИ, это сетка из трёх колонок —
   ровно как в макете v2.25. Когда плиток больше (закреплённые плюс ротация)
   или экран узкий, список становится ЛЕНТОЙ со стрелками: класс
   `promo-list--rail` ставит `site.js` по факту переполнения, а не по числу
   плиток в базе. Так «как в макете» и «есть стрелки» не спорят друг с
   другом: сетка там, где сетке место. */
.scroll-rail>.promo-list--rail{
  display:flex;
  overflow-x:auto;
  scroll-snap-type:x mandatory;
  padding:3px 3px 12px;
  scrollbar-width:none}
.scroll-rail>.promo-list--rail::-webkit-scrollbar{display:none}
.scroll-rail>.promo-list--rail>li{flex:0 0 32%;scroll-snap-align:start;min-width:0}
@media(max-width:1100px){
  .scroll-rail>.promo-list--rail>li{flex:0 0 46%}
}
@media(max-width:767px){
  .scroll-rail>.promo-list--rail>li{flex:0 0 86%}
}

/* --- 16. ПОДВАЛ: QR-КОД КАНАЛА В TELEGRAM (пакет владельца 2026-10-12) --

   ⚠️ ЧТО ЗДЕСЬ НАСТРАИВАЕТСЯ. В подвале появилась пятая колонка —
   «Наш канал в Telegram» с картинкой QR-кода. Сетка подвала на ПК была
   `repeat(4,1fr)`; с пятью колонками строки ссылок стали бы узкими, поэтому
   колонка с QR-кодом получает свою ширину (`auto`), а четыре прежние
   делят остаток. На планшете (`≤1100`) сетка уже `1fr 1fr`, и QR-код встаёт
   в общий поток; на телефоне (`≤767`) — одной колонкой, как всё остальное.

   ⚠️ РАЗМЕР КАРТИНКИ — 150 px ШИРИНЫ, НЕ «ВО ВСЮ КОЛОНКУ». Меньше 120 px
   камера телефона читает неуверенно, больше 180 px — блок начинает спорить
   с колонками ссылок за место. Высота в разметке (150) равна ширине: файл
   квадратный (592×592), и браузер заранее знает место на странице — подвал
   не «прыгает» при загрузке картинки.

   ⚠️ ФОН КАРТИНКИ ПРОЗРАЧНЫЙ (белые модули и «тихая зона» вокруг кода),
   поэтому скругление рамке ссылки больше не нужно: подвал просвечивает
   сквозь код, и он выглядит частью страницы, а не белой плиткой. */
.foot-grid{display:grid;grid-template-columns:1.3fr repeat(3,minmax(0,1fr)) auto;gap:32px 40px;align-items:start}
/* ⚠️ ПОДПИСЬ КАНАЛА — ПО ЦЕНТРУ ПОД КОДОМ И ВПЛОТНУЮ (правка владельца
   2026-10-13). Было: и код, и подпись — обычные ссылки подвала, поэтому
   подпись занимала ВСЮ ширину колонки (её задаёт заголовок «Наш канал в
   Telegram», он шире кода), текст стоял по левому краю, а `margin-top` +
   `padding` отодвигали его вниз — владелец и увидел «большой отступ и не по
   центру». Теперь блок подписи РАВЕН ширине кода и текст в нём по центру,
   а лишние отступы убраны. Высота касания (44 px) осталась: строка стоит
   в начале этой высоты, поэтому воздух ушёл, а палец по ссылке попадает
   как раньше.

   ⚠️ СЕЛЕКТОР С `a.` — НЕ «КРАСОТЫ РАДИ». На ссылки подвала есть общее
   правило `.footer .foot-grid a` (то же число классов, но лишний тег), и
   оно перебивало прежний `.foot-tg .foot-tg-link`: `display:block`,
   `padding:7px 0` и `text-align:left` шли именно оттуда. Селектор с тегом
   и классом — та же сила, но ниже по файлу, поэтому выравнивание и отступы
   теперь наши. Цвет, насыщенность и подчёркивание не трогаются. */
.foot-tg{min-width:0;display:flex;flex-direction:column;align-items:flex-start}
.foot-tg h3{margin-bottom:14px}
.foot-qr{display:block;width:150px;line-height:0}
.foot-qr img{width:150px;height:auto;display:block}
.foot-tg a.foot-tg-link{display:block;width:150px;text-align:center;
  margin:0;padding:0;min-height:44px}
/* У подписи остаётся только то, чего не задаёт общее правило ссылок подвала
   (`.footer .foot-grid a`): оно даёт цвет и `text-decoration`, а вид и
   положение подписи — в правиле выше. */
.foot-tg .foot-tg-link{font-weight:700;text-decoration:none}
.foot-tg .foot-tg-link:hover{text-decoration:underline}
@media(max-width:1100px){
  .foot-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:767px){
  .foot-grid{grid-template-columns:1fr;gap:24px}
  .foot-qr{width:140px}
  .foot-qr img{width:140px}
  .foot-tg a.foot-tg-link{width:140px}
}

/* ============================================================
   --- 17. ВИТРИНА ПО ТРЕБОВАНИЯМ ВЛАДЕЛЬЦА 2026-10-13 ----------
   ============================================================

   ЧТО ЗДЕСЬ СОБРАНО (семь пунктов владельца, по одному подразделу):

   17.1 «Забрать сегодня» — обязательный фильтр: вид галочки.
   17.2 Числовые поля без стрелок-спиннеров — на телефоне И на ПК.
   17.3 Кнопка «Фильтры» и окно фильтров на телефоне: кнопки закреплены
        внизу экрана над нижним меню, прокручивается только список.
   17.4 Хлебные крошки: отступы над крошками и до заголовка сокращены.
   17.5 Плотность мобильной вёрстки: зазоры под строкой разделов, между
        заголовком и содержимым, между блоками.
   17.6 Экран входа на телефоне: блок «Вход или регистрация» помещается
        целиком (проверено на высотах 640–900 px, расчёт — в тесте
        `tests/unit/web/test_filters_mobile_storefront.py`).
   17.7 Увеличенное окно аксессуара (корзина и карточка товара).

   ⚠️ ПОЧЕМУ ОТДЕЛЬНЫМ РАЗДЕЛОМ В КОНЦЕ ФАЙЛА. Все правила здесь —
   УТОЧНЕНИЯ к уже описанным блокам (мобильный ритм витрины задан выше,
   в перенесённых из макета правилах). Переписывать чужие блоки нельзя:
   они принадлежат другим правкам, и правка «по месту» потерялась бы при
   следующем слиянии. Правило ниже по файлу с тем же селектором и той же
   силой перебивает прежнее — этого достаточно и видно, что изменилось.

   ⚠️ РАЗМЕР КАСАНИЯ НЕ УМЕНЬШАЕТСЯ. Плотность — это ПУСТЫЕ зазоры между
   блоками, а не высота кнопок и полей: `.btn`, `.chip`, ссылки крошек и
   нижнее меню остаются не ниже 44 px (правила `.crumbs a{min-height:44px}`,
   `.btn{min-height:44px}` и мобильное `.card .btn{min-height:48px}` не
   трогаются).

   ⚠️ ЛОМАТЬ ЧИТАЕМОСТЬ НЕЛЬЗЯ. Кегль основного текста не уменьшается;
   мельче становится только вспомогательная подпись на экране входа
   (12 px вместо 13) — там владелец просил убрать пустоту, а не текст.
   ------------------------------------------------------------------ */

/* --- 17.1 «Забрать сегодня»: вид обязательного фильтра -------------- */
/* Галочка стоит первой в списке фильтров и есть на ВСЕХ страницах
   с фильтрами (каталог, разделы, бренды, поиск). Подпись — обычная
   подпись галочки (`.check`: строка 44 px, палец попадает без прицела),
   ниже — короткое пояснение, что именно отбирает фильтр. */
.filter-group-pickup{margin-bottom:16px}
.pickup-check{align-items:flex-start;gap:10px}
.pickup-check span{line-height:1.35}
.pickup-check b{font-size:16px}
.filter-group-pickup .small{margin:2px 0 0 30px;font-size:12px;line-height:1.45}
/* Точка-признак у кнопки «Фильтры»: видно, что фильтр включён, не открывая
   окно. Только на телефоне (сама кнопка там же) — см. 17.3. */
.filters-dot{width:8px;height:8px;border-radius:50%;background:var(--primary);flex:0 0 auto}

/* --- 17.2 Числовые поля без стрелок-спиннеров (телефон И ПК) -------- */
/* Требование владельца: убрать «вверх/вниз» у числовых полей везде, где
   есть числовой ввод (фильтры «цена от/до», количество в корзине, количество
   в карточке товара). Правило ОДНО на весь сайт, а не «у фильтров»: иначе
   стрелки вернулись бы в новом поле.

   Три записи нужны всем браузерам: `appearance:textfield` — Firefox,
   `::-webkit-inner/outer-spin-button` — Chrome, Safari, Edge. Стрелки
   убираются только визуально: число по-прежнему вводится с клавиатуры,
   `type=number` сохраняет проверку и цифровую клавиатуру на телефоне. */
input[type=number]{-moz-appearance:textfield;appearance:textfield}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;appearance:none;margin:0}

/* --- 17.3 Кнопка «Фильтры» и окно фильтров (телефон) ---------------- */
/* На ПК всё как было: фильтры стоят колонкой слева, кнопки — в конце
   колонки, кнопки «Фильтры» в панели над сеткой нет. */
.filters-head{display:none}
.filters-list{display:block}
.filters-actions{display:flex;flex-direction:column;gap:8px;margin-top:8px}
.filters-trigger{display:none}

@media(max-width:767px){
  /* Кнопка «Фильтры» вместо «Применить» (требование владельца). Она видна
     только на телефоне; на ПК тот же адрес ведёт обычным переходом. */
  .filters-trigger{display:inline-flex;align-items:center;gap:8px}
  .filters-trigger .icon{width:18px;height:18px}
  /* ⚠️ Кнопка «Применить» у сортировки прячется ТОЛЬКО при работающем
     скрипте (`.js` ставит `site.js`): без скрипта сортировку применить
     больше нечем, и кнопка обязана остаться. Скрипт отправляет форму
     сортировки сам — ровно тогда, когда кнопки не видно. */
  .js .toolbar .sort-apply{display:none}

  /* На телефоне фильтры были СКРЫТЫ вовсе (`.filters{display:none}`);
     теперь они живут в окне на всю ширину экрана. */
  .filters{display:block;padding:0}
  .filters-form{display:none}

  /* ОКНО: во всю ширину, от верха экрана до НИЖНЕГО МЕНЮ (оно остаётся
     видимым и рабочим: у него слой выше, `z-index:100`). Внутри — колонка
     флекса: голова, прокручиваемый список, закреплённые кнопки. */
  .filters-form:target,
  .filters.is-open .filters-form{
    display:flex;
    position:fixed;
    left:0;
    right:0;
    top:0;
    bottom:calc(72px + env(safe-area-inset-bottom,0px));
    z-index:95;
    flex-direction:column;
    background:#fff;
    margin:0;
    padding:0;
    border-radius:0;
    box-shadow:0 12px 40px #142b4930;
    overflow:hidden}
  .filters-head{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:12px;
    flex:0 0 auto;
    padding:4px 10px 4px 16px;
    border-bottom:1px solid #e9edf3}
  .filters-heading{font-size:18px;line-height:1.3;margin:0}
  .filters-close{
    display:inline-flex;
    align-items:center;
    justify-content:center;
    min-width:44px;
    min-height:44px;
    border:0;
    background:none;
    color:var(--text);
    border-radius:12px}

  /* ПРОКРУЧИВАЕТСЯ ТОЛЬКО СПИСОК: у него `overflow-y:auto` и он занимает
     всё свободное место (`flex:1`), а у кнопок и головы — `flex:0 0 auto`. */
  .filters-list{
    flex:1 1 auto;
    min-height:0;
    overflow-y:auto;
    -webkit-overflow-scrolling:touch;
    padding:12px 16px}

  /* КНОПКИ ЗАКРЕПЛЕНЫ ВНИЗУ И ВСЕГДА ВИДНЫ: они вне прокручиваемого списка
     и прижаты к низу окна (то есть стоят НАД нижним меню телефона).
     `sticky` — страховка на случай, если содержимое списка когда-нибудь
     перестанет помещаться в собственную колонку. */
  .filters-actions{
    flex:0 0 auto;
    position:sticky;
    bottom:0;
    display:flex;
    flex-direction:column;
    gap:8px;
    margin:0;
    padding:10px 16px;
    border-top:1px solid #e9edf3;
    background:#fff}
  .filters-actions .btn{min-height:48px}

  /* Пока окно открыто, страница под ним не прокручивается: прокрутка —
     это список фильтров. Второе правило — для случая без скрипта, когда
     окно раскрыто браузером по `:target`. */
  body.filters-open,
  body:has(.filters-form:target){overflow:hidden}
}

/* --- 17.4 Хлебные крошки: отступы сокращены -------------------------- */
/* Владелец: «много пустоты над крошками и между крошками и заголовком».
   Крошки начинаются с «Главная» (правка в шаблонах), слово «Каталог»
   в них ОСТАВЛЕНО — сокращаются только зазоры.

   ⚠️ ВЫСОТА ССЫЛОК НЕ МЕНЯЕТСЯ: `.crumbs a{min-height:44px}` остаётся,
   поэтому палец по крошке попадает как раньше, а «воздух» уходит за счёт
   верхнего и нижнего отступа самого ряда. */
@media(max-width:767px){
  .crumbs{padding-top:4px;padding-bottom:8px}
  .page-title{margin-bottom:12px}
  .page-title .muted{margin-top:4px}
}

/* --- 17.5 Плотность мобильной вёрстки ------------------------------- */
/* Владелец: «много пустоты в мобильной версии — под строкой категорий,
   между крошками и заголовком, между заголовком и содержимым, между
   блоками». Сокращаются ПУСТЫЕ зазоры; кегли, высоты кнопок и полей
   не трогаются. */
@media(max-width:767px){
  .nav-cats{padding-bottom:4px}
  .category-chips{margin-bottom:12px}
  .toolbar{margin-bottom:12px}
  .content{padding-top:12px}
  .section{margin:26px 0}
  .section-title{margin-bottom:14px}
  .accessories{margin:22px 0 10px}
  .home-heading{margin-bottom:12px}
  .mobile-bottom-nav{padding-top:4px}
}

/* --- 17.6 Экран входа помещается на телефон целиком ------------------ */
/* Требование владельца: блок «Вход или регистрация» (заголовок, пояснение,
   поле телефона, галочки, кнопка, подписи) виден ЦЕЛИКОМ при открытии —
   покупатель не прокручивает. Проверено расчётом на 640 px
   (`tests/unit/web/test_filters_mobile_storefront.py`), потому что браузера
   в рабочей среде нет.

   ЧТО СЭКОНОМЛЕНО:
   1. на экране входа с телефона убраны СТРОКА РАЗДЕЛОВ и СТРОКА ПОИСКА.
      Обе — часть общей шапки, и обе дублируются нижним меню (в нём есть
      «Каталог»); на шаге ввода телефона они не нужны, а вместе занимали
      больше 110 px — без этого блок не помещался на 640 px. Логотип, город
      и нижнее меню остаются на месте;
   2. «рассказ» слева (`.auth-story`) на телефоне был скрыт и раньше —
      это тот же текст, что в карточке;
   3. отступы, кегль заголовка и поля карточки подтянуты — но не ниже
      44 px по высоте касания: поле 46 px, кнопка 48 px, галочки 44 px. */
@media(max-width:767px){
  body[data-screen="login"] .nav-cats,
  body[data-screen="login"] .main-head>.search{display:none}
  .auth-layout{margin:0}
  .auth-card{padding:12px 16px;border-radius:16px}
  .auth-card h1{font-size:21px;line-height:1.16;margin-bottom:6px}
  .auth-card>p.muted{font-size:13px;line-height:1.45}
  .auth-card .input-wrap{margin:6px 0}
  .auth-card .field,
  .auth-card input[type=tel],
  .auth-card input[type=text]{min-height:46px;padding:10px 12px}
  .auth-card .btn.wide{min-height:48px;margin-top:2px}
  .auth-card .small{font-size:12px;line-height:1.35}
  .summary-consent{margin:6px 0 4px;font-size:12px;line-height:1.4}
}

/* --- 17.7 Увеличенное окно аксессуара ------------------------------- */
/* Миниатюра аксессуара (корзина и карточка товара) открывает `<dialog>`:
   крупная картинка, название, артикул, цена, состояние наличия, «В корзину»
   и «Открыть товар». Скрипт — `site.js`, раздел 7; разметка — `_card.html`.

   ⚠️ ОКНО — ТОТ ЖЕ `.dialog` ПРОЕКТА (одно оформление всплывающих окон:
   скругление, тень, затемнение фона), плюс своя раскладка. `padding:0`
   потому, что отступы здесь несут голова и тело окна: только так крупная
   картинка доходит до краёв, а по «полям» окна не срабатывает закрытие
   по клику в фон.

   ⚠️ ЧТО ДЕЛАЕТ БРАУЗЕР, А ЧТО СКРИПТ. `showModal` даёт затемнение
   (`::backdrop`), недоступность фона и закрытие по `Esc` — это не наш код.
   Скрипт добавляет крестик, клик по фону и возврат фокуса на миниатюру. */
.accessory-zoom{width:min(560px,92vw);max-width:92vw;max-height:min(88vh,560px);padding:0;overflow:hidden}
.accessory-zoom[open]{display:flex;flex-direction:column}
.accessory-zoom-head{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:12px;
  flex:0 0 auto;
  padding:12px 10px 10px 18px;
  border-bottom:1px solid #eef1f5}
.accessory-zoom-title{font-size:18px;line-height:1.35;margin:0;letter-spacing:0}
.accessory-zoom-close{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-width:44px;
  min-height:44px;
  flex:0 0 auto;
  border:0;
  background:none;
  color:var(--text);
  border-radius:12px}
.accessory-zoom-main{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:18px;
  padding:16px 18px 20px;
  overflow-y:auto}
.accessory-zoom-media{
  display:grid;
  place-items:center;
  min-height:200px;
  padding:10px;
  border-radius:16px;
  background:var(--surface,#f4f6f9)}
.accessory-zoom-media .no-photo{min-height:160px}
.accessory-zoom-photo{width:100%;height:auto;max-height:46vh;object-fit:contain;border-radius:12px}
.accessory-zoom-info{display:flex;flex-direction:column;gap:10px;min-width:0}
/* Цена крупнее плиточной: окно открывают, чтобы рассмотреть товар. */
.accessory-zoom-info .price{font-size:28px}
/* Кнопки окна не ниже 48 px: это главные действия в окне. */
.accessory-zoom-info .btn{min-height:48px}
@media(max-width:767px){
  .accessory-zoom{width:94vw;max-width:94vw;max-height:88vh}
  .accessory-zoom-main{grid-template-columns:minmax(0,1fr);gap:12px;padding:12px 14px 16px}
  .accessory-zoom-media{min-height:0}
  .accessory-zoom-photo{max-height:38vh}
}

/* ============================================================
   --- 18. БРЕНДЫ, ЧЕТЫРЕ ПЛИТКИ В РЯД, СТРОКИ НАЛИЧИЯ И СОРТИРОВКА
   (требования владельца 2026-10-13)
   ============================================================

   ЧТО ЗДЕСЬ СОБРАНО (по подразделу на требование):

   18.1 Сетка плиток каталога: 4 в ряд на широком экране (≥1440 px),
        3 на планшете, 2 на телефоне.
   18.2 Строки наличия в плитке: «ХХ шт. в магазине сегодня» и
        «ХХ шт. есть на складе, 🚚 17.10.26 г.».
   18.3 Лента логотипов брендов на главной (автопрокрутка — `site.js`, 8).
   18.4 Страница брендов `/brands`: карточки с логотипом, названием и
        числом товаров.
   18.5 Сортировка без кнопки «Применить»: кнопку прячет ТОЛЬКО скрипт.

   ⚠️ ПОЧЕМУ ОТДЕЛЬНЫМ РАЗДЕЛОМ В КОНЦЕ ФАЙЛА. Все правила ниже —
   УТОЧНЕНИЯ к блокам, которые принадлежат другим правкам (сетка каталога,
   плитка, лента со стрелками). Правило ниже по файлу с тем же селектором
   и той же силой перебивает прежнее — этого достаточно, и видно, что
   изменилось. Переписывать чужие блоки нельзя: они уедут при слиянии.
   ------------------------------------------------------------------ */

/* --- 18.1 Четыре плитки в ряд на широком экране --------------------- */
/* Требование владельца: на широком экране (≈1440 px и больше) — ЧЕТЫРЕ
   плитки в ряд (было три), на планшете — три, на телефоне — две.

   ⚠️ ЗДЕСЬ ТОЛЬКО ШИРОКИЙ ЭКРАН. Базовая сетка каталога — три колонки
   (`site.css`, правила макета v2.19), она и остаётся планшетной; телефон
   (≤767) переключается на две колонки своим правилом. Четвёртая колонка
   добавляется ровно один раз и только там, где для неё есть место: при
   1440 px каталог с колонкой фильтров (224 px) даёт плитке ~250 px —
   это по-прежнему читаемая карточка, а на 1100 px она была бы уже 190 px.

   ⚠️ ВЫСОТА РЯДА И КНОПКА НЕ «ЕДУТ». Плитки в сетке тянутся по высоте
   ряда (поведение сетки по умолчанию), а блок покупки прижат к низу
   плитки (`margin-top:auto` у `.card-buy`) — поэтому четвёртая плитка
   не смещает кнопки у соседей. */
@media(min-width:1440px){
  .grid{grid-template-columns:repeat(4,minmax(0,1fr))}
}

/* --- 18.2 Строки наличия в плитке ----------------------------------- */
/* Две строки ровно в порядке владельца: сначала «в магазине сегодня»,
   затем «есть на складе» с датой у грузовичка. Тексты приходят с сервера
   готовыми (`app/web/catalog_view.py`, раздел «ОСТАТКИ»).

   ⚠️ СТРОКА МАГАЗИНА — ЗЕЛЁНАЯ, СТРОКА СКЛАДА — СЕРАЯ. Цвет несёт смысл:
   зелёное можно забрать сегодня, серое — привезут. Оба цвета — переменные
   проекта, новых цветов не заводится.

   ⚠️ ПЕРЕНОС СТРОК, А НЕ ОБРЕЗКА. На узкой плитке «12 шт. есть на складе,
   🚚 07.11.26 г.» может не влезть в одну строку: строка переносится
   (`flex-wrap`), а дата с грузовичком не разрывается (`nowrap` у
   `.card-stock-delivery`) — иначе иконка осталась бы без даты. */
.card-stock-rows{
  display:flex;
  flex-direction:column;
  gap:3px;
  margin-bottom:14px}
/* Строка наличия — ОДНА линия для слова и даты (каталог и карточка товара).
   Требование владельца 21.10.2026: «до грузовика и после, текст должен быть на
   одном уровне». Общий межстрочный, значок не сдвигает базовую линию. */
.card-stock-row{
  display:flex;
  align-items:center;
  /* Переносится ЦЕЛИКОМ: в узкой плитке дата уходит на вторую строку,
     но слово и дата внутри строки всегда на одной высоте (line-height 20px). */
  flex-wrap:wrap;
  gap:5px;
  font-size:13px;
  line-height:20px;
  min-height:20px}
.card-stock-row--store{color:var(--success)}
.card-stock-row--warehouse{color:var(--muted)}
.card-stock-delivery{
  display:inline-flex;
  align-items:center;
  gap:5px;
  line-height:20px;
  white-space:nowrap}
.card-stock-text{
  display:inline-flex;
  align-items:center;
  line-height:20px}
.card-stock-delivery .icon{
  display:block;
  flex-shrink:0;
  width:17px;
  height:17px;
  color:var(--muted)}
@media(max-width:767px){
  /* В плитке на телефоне ~140 px ширины: строка склада — мельче, чтобы
     «есть на складе» и дата остались читаемыми, а не рвались по слогам. */
  .card-stock-row{font-size:12px}
  .card-stock-delivery .icon{width:16px;height:16px}
}

/* --- 18.3 Лента логотипов брендов на главной ------------------------ */
/* Механизм ленты — существующий (`.scroll-rail` + `data-rail-track` со
   стрелками, раздел 15): здесь только вид плитки бренда. Прокрутку ленты
   самой (автопрокрутку) делает скрипт (`site.js`, раздел 8); она молчит,
   когда листать нечего, и останавливается при наведении и фокусе.

   ⚠️ ЛОГОТИПА МОЖЕТ НЕ БЫТЬ: тогда в плитке стоит НАЗВАНИЕ бренда.
   Пустая рамка на месте логотипа выглядела бы поломкой, а «нет логотипа»
   на этом контуре — обычное дело. */
.brand-strip{
  display:flex;
  gap:14px;
  padding:3px 3px 10px}
.brand-tile{
  flex:0 0 auto;
  display:grid;
  place-items:center;
  width:190px;
  height:92px;
  padding:12px 16px;
  border-radius:16px;
  background:var(--surface);
  color:var(--text);
  text-align:center;
  overflow:hidden}
.brand-tile:hover{background:var(--primarySoft)}
/* ⚠️ СВЕТЛЫЕ ЛОГОТИПЫ НА ТЁМНОЙ ПОДЛОЖКЕ (владелец 24.10.2026): «в каруселе
   Бренды, логотип Donel — белый. Сделай под ним фон, как на втором скрине».
   Белый логотип на светлой плитке не читается, поэтому таким брендам даём
   среднесерую подложку. Список брендов — в одном месте, ниже. */
.brand-tile[data-brand-slug="donel"]{
  background:#8c8c8c}
/* VANGUARD ELECTRO: белый знак, поэтому плитка тёмная — цвет фона взят со
   скриншота владельца (01.11.2026). */
.brand-tile[data-brand-slug="vanguard-electro"]{background:#3a424c}
.brand-tile[data-brand-slug="vanguard-electro"]:hover{background:#46505b}
.brand-tile[data-brand-slug="donel"]:hover{
  background:#7f7f7f}
.brand-tile-logo{
  max-width:100%;
  max-height:100%;
  width:auto;
  height:auto;
  object-fit:contain}
.brand-tile-name{
  font-size:17px;
  font-weight:700;
  letter-spacing:-.2px;
  overflow-wrap:anywhere}
@media(max-width:767px){
  .brand-tile{width:150px;height:78px;padding:10px 12px}
  .brand-tile-name{font-size:15px}
}

/* --- 18.4 Страница брендов `/brands` -------------------------------- */
/* Список всех брендов: карточка = ссылка в каталог с выбранным брендом.
   Колонки — по доступной ширине (`auto-fill`), поэтому страница одинаково
   выглядит при одном бренде, при двух и при сотне. */
.section-link{color:inherit}
.section-link:hover{text-decoration:underline;text-underline-offset:5px}
.brand-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(230px,1fr));
  gap:18px}
.brand-card{
  display:flex;
  align-items:center;
  gap:16px;
  padding:18px;
  border-radius:20px;
  background:white;
  box-shadow:var(--shadow);
  min-height:104px}
.brand-card:hover{background:#fafbfe}
.brand-card-media{
  flex:0 0 88px;
  width:88px;
  height:60px;
  display:grid;
  place-items:center;
  border-radius:12px;
  background:var(--surface);
  overflow:hidden}
/* ⚠️ У бренда БЕЗ логотипа серую плашку убираем: владелец просил «только
   названия», а не «название в квадрате». Карточка с логотипом и карточка без
   него должны отличаться только наличием картинки. */
.brand-card:has(.brand-card-name-plate) .brand-card-media{background:transparent}
.brand-card-logo{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain}
/* Бренд без логотипа: ТОЛЬКО название текстом (решение владельца 2026-10-13).
   Раньше здесь стояла первая буква названия — она выглядела как сломанная
   картинка, и владелец просил её убрать. Плашка подобрана под визуальный вес
   логотипов: та же высота знака (56 px) и тот же шрифт, что у названий на
   плитках ленты. */
.brand-card-name-plate{
  display:flex;
  align-items:center;
  justify-content:center;
  min-height:56px;
  padding:0 8px;
  font-size:20px;
  font-weight:700;
  letter-spacing:-.2px;
  color:var(--text);
  text-align:center;
  overflow-wrap:anywhere}
.brand-card-info{
  display:flex;
  flex-direction:column;
  gap:3px;
  min-width:0}
.brand-card-title{font-size:17px;font-weight:700;letter-spacing:-.2px}
.brand-card-goods{font-size:13px}
.brand-card-link{
  font-size:13px;
  font-weight:700;
  color:var(--primary);
  margin-top:2px}
@media(max-width:767px){
  .brand-grid{grid-template-columns:1fr;gap:12px}
  .brand-card{padding:14px}
}

/* --- 18.5 Сортировка: кнопки «Применить» не видно при скрипте ------- */
/* ⚠️ КНОПКА ИЗ РАЗМЕТКИ НЕ УБИРАЕТСЯ. Её прячет ТОЛЬКО CSS и ТОЛЬКО при
   работающем скрипте (`.js` ставит `site.js`): без JavaScript сортировку
   применить больше нечем, и кнопка обязана остаться на месте. Скрипт
   (`site.js`, раздел 9) применяет сортировку сам — по выбору в списке и
   БЕЗ перезагрузки страницы, поэтому прокрутка не «прыгает» в начало.

   ⚠️ ПРАВИЛО ОБЩЕЕ, А НЕ МОБИЛЬНОЕ. До этой правки кнопка пряталась только
   на телефоне (раздел 17.3): владелец просил убрать её ВЕЗДЕ — и на ПК,
   и на телефоне. Правило ниже по файлу с тем же селектором перебивает
   мобильное, а для широких экранов оно единственное. */
.js .toolbar .sort-apply{display:none}

/* Пока список обновляется запросом, область приглушена — видно, что нажатие
   принято (то же состояние, что `aria-busy` у форм корзины, раздел 10).
   Высота области не меняется: сетка остаётся на месте, страница не «едет». */
.catalog-list[aria-busy="true"]{opacity:.65}

/* --- 18.6 Блок «Акции» на главной: ссылка в правом нижнем углу ------- */
/* Требование владельца (2026-10-13): под четырьмя акционными товарами
   в ПРАВОМ НИЖНЕМ УГЛУ блока — ТЕКСТОВАЯ ссылка «Больше товаров по акции»
   на страницу акций. Именно текст, а не кнопка: так просил владелец. */
.section-more{display:flex;justify-content:flex-end;margin-top:16px}
.section-more-link{
  font-size:14px;
  font-weight:700;
  color:var(--primary);
  text-decoration:underline;
  text-underline-offset:4px;
  min-height:44px;
  display:inline-flex;
  align-items:center}
.section-more-link:hover{color:var(--primaryHover)}
/* Заглушка «Акции скоро появятся» — обычная подпись блока, а не пустая сетка. */
[data-promo-stub]{margin:2px 0 0}

/* --- 18.7 Акции: метка «Акция» и пояснение «список пополняется» ------ */
/* Требование владельца (2026-10-13): «в карточке товара и на странице акции
   явно отмечай, что товар акционный, чтобы покупателю было понятно, почему
   цена ниже». Метка — та же плашка проекта (`.badge`), но своего цвета:
   «Новинка» синеватая, «Акция» — тёплая (жёлтая палитра макета,
   переменная `--warmSoft`). Так две метки не путаются между собой.

   ⚠️ МЕТКА НЕ ПЕРЕКРЫВАЕТ «НОВИНКУ»: обе стоят в левом верхнем углу
   картинки, вторая — ниже первой (`top:31px`). Ширина — по содержимому:
   растянутая на всю плитку плашка выглядела бы кнопкой. */
.badge-promo{background:var(--warmSoft);color:var(--onWarm)}
.media .badge-promo{top:31px}
.purchase .badge-promo{margin-bottom:10px}
/* Пояснение «список пополняется»: под заголовком страницы акций и в заглушке.
   Тише основного текста, но заметнее подписи-заглушки. */
.promo-hint{font-size:14px;margin:0 0 18px}

/* --- 18.8 Шапка: имя клиента под иконкой профиля -------------------- */
/* Требование владельца (2026-10-13): «в шапке, после авторизации, под
   иконкой профиля должно быть имя клиента». Имя готовит сервер
   (`header_customer_name`): имя → фамилия → «Кабинет»; телефон и почта сюда
   не попадают (приватность), а сам покупатель из сессии уже загружен.

   ⚠️ ДЛИННОЕ ИМЯ ОБРЕЗАЕТСЯ МНОГОТОЧИЕМ, А НЕ «ЛЕСЕНКОЙ». Одна строка
   (`white-space:nowrap`) и `text-overflow:ellipsis`: имя из трёх слов
   иначе переносилось бы на две-три строки и ломало высоту шапки.

   ⚠️ НА ТЕЛЕФОНЕ ИМЯ ВИДНО ВОШЕДШЕМУ (`is-customer`). У гостя кнопка
   «Войти» там по-прежнему скрыта: раньше она пряталась целиком, и шапка
   телефона остаётся прежней для тех, кто не входил (иначе экран входа
   перестал бы помещаться на 640 px — там это посчитано тестом). */
.head-action .head-name{
  max-width:120px;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis}
@media(max-width:767px){
  .main-head>.head-action.is-customer{display:flex}
  .main-head>.head-action.is-customer .head-name{max-width:74px}
}

/* --- 18.9 Полоса разделов под шапкой: строка на ПК, ПЛИТКИ на телефоне --
   (требования владельца 2026-10-13: «как у Ozon» и уточнение про телефон)

   ⚠️ РАЗМЕТКА ОДНА, ВИДОВ ДВА. Пункт полосы — всегда «значок + подпись»
   (`base.html` включает `_nav_icon.html`), а как их расположить, решает CSS:
   на ПК это СТРОКА (значок слева, подпись справа), на телефоне — КВАДРАТНАЯ
   ПЛИТКА со значком внутри и подписью ПОД ней. Второй разметки и «второго
   набора иконок» не заводится: владелец просил те же значки.

   ⚠️ СЕЛЕКТОРЫ С `.nav-cats` — НЕ «ДЛЯ КРАСОТЫ». В перенесённых из макета
   правилах есть `.nav-cats a` (класс + тег): у него сила выше, чем у одного
   класса `.nav-cat`, поэтому плитки телефона без `.nav-cats` в селекторе
   получили бы макетные отступы и высоты вместо своих.

   ⚠️ ЦВЕТА — ТОЛЬКО ПЕРЕМЕННЫЕ ПРОЕКТА (`--surface`, `--primarySoft`,
   `--primary`, `--text`): тёмная тема и высокий контраст включаются сменой
   переменных, а не правкой полосы. Хардкод-цветов здесь нет.

   ⚠️ РАЗМЕР ПЛИТКИ. 64 px по ширине и 56 px плитка: на телефоне 390 px
   в полосу помещается 5–6 пунктов (390 / 64 ≈ 6), а плитка и вся ссылка
   целиком выше 44 px — палец попадает без прицеливания. */
.nav-cats{gap:22px;scrollbar-width:none}
.nav-cats::-webkit-scrollbar{display:none}
/* ⚠️ ЗНАЧОК РАЗДЕЛА — МАСКА ИЗ ФАЙЛА (24.10.2026). Файлы лежат в
   static/img/nav/, поэтому иконку можно заменить, не трогая CSS и шаблон.
   Цвет берётся от текста пункта: тёмная тема и активный пункт работают сами. */
.nav-cat-icon{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:22px;
  height:22px;
  flex:0 0 auto;
  /*: Значки разделов — КОНТУРНЫЕ, цвет от текста (владелец 24.10.2026: «изначальный
     стиль, контурный без заливки лучше»). Так значок сам подхватывает цвет пункта,
     подсветку при наведении и тёмную тему. */
  color:inherit}
/*: Значки в меню «Каталог» и в плитках подразделов: тот же набор, но мельче,
   чтобы не спорить с текстом. Размеры подобраны под шрифт 13–15 px. */
.mega-category .nav-cat-icon{width:18px;height:18px}
.mega-groups h3 .nav-cat-icon{width:17px;height:17px}
.mega-link .nav-cat-icon{width:15px;height:15px;opacity:.9}
.mega-groups h3 a{display:inline-flex;align-items:center;gap:7px}
.mega-link{display:inline-flex;align-items:center;gap:6px}
.subsection .nav-cat-icon{width:18px;height:18px}
/* Плашка закрытого раздела (вариант В, 24.10.2026): объясняет, почему нет цен. */
.locked-banner{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:16px;
  flex-wrap:wrap;
  margin:0 0 18px;
  padding:14px 18px;
  border-radius:16px;
  background:var(--primarySoft);
  color:var(--text)}
.locked-banner-text{display:flex;flex-direction:column;gap:4px;font-size:14px;line-height:1.45}
.locked-banner-text strong{font-size:15px}
.locked-banner-text span{color:var(--muted)}
.locked-banner-btn{flex:0 0 auto;white-space:nowrap}

.nav-icon-glyph{
  display:block;
  width:100%;
  height:100%;
  background:currentColor;
  -webkit-mask-image:var(--nav-glyph);
  mask-image:var(--nav-glyph);
  -webkit-mask-repeat:no-repeat;
  mask-repeat:no-repeat;
  -webkit-mask-position:center;
  mask-position:center;
  -webkit-mask-size:contain;
  mask-size:contain}

.nav-cats .nav-cat{
  display:inline-flex;
  align-items:center;
  gap:8px;
  min-height:44px;
  color:var(--muted);
  font-weight:normal}
.nav-cats .nav-cat .icon{width:22px;height:22px}
.nav-cats .nav-cat:hover{color:var(--text)}
.nav-cats .nav-cat:hover .icon{color:var(--primary)}
.nav-cats .nav-cat.nav-active{color:var(--primary);font-weight:bold}
.nav-cats .nav-cat-label{white-space:nowrap}
@media(max-width:767px){
  /* ⚠️ `padding-bottom:4px` — ПРЕЖНЕЕ ТРЕБОВАНИЕ ВЛАДЕЛЬЦА О ПЛОТНОСТИ
     (раздел 17.5) остаётся в силе: полоса и на телефоне компактная,
     «воздух» добавляют плитки, а не отступ полосы. */
  .nav-cats{gap:10px;padding-bottom:4px;-webkit-overflow-scrolling:touch}
  .nav-cats .nav-cat{
    flex:0 0 auto;
    display:flex;
    flex-direction:column;
    align-items:center;
    gap:6px;
    width:64px;
    padding:4px 0;
    white-space:normal;
    text-align:center}
  .nav-cats .nav-cat .icon{
    width:56px;
    height:56px;
    padding:14px;
    border-radius:16px;
    background:var(--surface);
    color:var(--text)}
  /* Нажал — подсветилось (и наведение/фокус для мыши и клавиатуры). */
  .nav-cats .nav-cat:hover .icon,
  .nav-cats .nav-cat:focus-visible .icon,
  .nav-cats .nav-cat:active .icon{background:var(--primarySoft);color:var(--primary)}
  .nav-cats .nav-cat.nav-active .icon{background:var(--primarySoft);color:var(--primary)}
  .nav-cats .nav-cat-label{
    font-size:11px;
    line-height:1.25;
    max-width:64px;
    display:-webkit-box;
    -webkit-line-clamp:2;
    -webkit-box-orient:vertical;
    overflow:hidden}
}

/* --- 18.10 Выпадающие списки: наш вид и наш раскрытый список ---------- */
/* Требование владельца (2026-10-13, по скриншоту): «все выпадающие списки
   выглядят квадратными и системными — стилизовать под общий дизайн».

   ⚠️ КОМПОНЕНТ УЖЕ ЕСТЬ — В ДИЗАЙН-СИСТЕМЕ МАКЕТА, И ВТОРОГО НЕ ЗАВОДИТСЯ.
   Раскрытый список рисуют правила `.ds-select` / `.ds-trigger` / `.ds-menu` /
   `.ds-option` (выше в файле, перенесены из макета): скругления, наш шрифт
   и цвета, свой указатель, подсветка при наведении, выделение выбранного
   (галочка), тень у раскрытого списка, размеры 44 px и 16 px на телефоне.
   Здесь — только то, чего в макете не было:

   1. ЗАКРЫТОЕ ПОЛЕ РОДНОГО `select`. На телефоне выбор оставлен РОДНЫМ
      («барабан» удобнее пальцем — требование владельца), поэтому системный
      вид прячется у самого `select`: `appearance:none`, свой указатель
      картинкой (у `select` псевдоэлементов нет), отступ под указатель,
      скругление и рамка — как у полей проекта;
   2. СЛОЙ РАСКРЫТОГО СПИСКА. В макете у `.ds-menu` стоял `z-index:10000`
      («выше всего»). Здесь слой назван и ограничен (`--layer-popup`): выше
      липкой шапки (60), списка городов (90), окна фильтров телефона (95)
      и нижнего меню (100) — но не «бесконечность»: попап не должен
      оказаться выше модальных окон, которых у нас пока нет.

   ⚠️ ГДЕ ЭТО РАБОТАЕТ. `site.css` подключён и в админке, поэтому ЗАКРЫТОЕ
   поле выглядит нашим везде (это только вид — поведение не меняется).
   Раскрытый список — наш только на витрине: скрипт витрины (`site.js`)
   админка не подключает (см. `base_admin.html`), и её родные списки
   не трогаются вовсе. Это записано в отчёте.

   ⚠️ ТЁМНАЯ ТЕМА И КОНТРАСТ. Цвета компонента — из переменных проекта
   (`--surface`, `--primarySoft`, `--primary`, `--text`, `--line`), поэтому
   смена темы не ломает ни поле, ни раскрытый список. Единственный хардкод —
   цвет стрелки внутри data-URI: `currentColor` в картинке не работает,
   а `mask-image` не поддержан частью браузеров; цвет взят из переменной
   `--muted` вручную и помечен здесь. */
:root{--layer-popup:110}
.ds-menu{z-index:var(--layer-popup)}
.ds-trigger:focus-visible{
  border-color:var(--focus);
  box-shadow:0 0 0 3px var(--primarySoft)}
select{
  appearance:none;
  -webkit-appearance:none;
  -moz-appearance:none;
  /* Стрелка-указатель: цвет #586779 = --muted вручную (см. пояснение выше). */
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%23586779' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 2.5 6 6l4-3.5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 16px center;
  padding-right:46px}
select::-ms-expand{display:none}
select:focus-visible{
  border-color:var(--focus);
  box-shadow:0 0 0 3px var(--primarySoft)}

/* --- 18.11 Боковое меню кабинета: плотнее и ровнее -------------------- */
/* Требование владельца (2026-10-13, по скриншоту): «боковое меню кабинета
   в аналогичном стиле — лёгкий, удобочитаемый, небольшие отступы, не
   размазан текст в высоту».

   ⚠️ ЧТО БЫЛО НЕ ТАК. Пункты меню стояли с ВЕРТИКАЛЬНЫМ отступом 2 px
   и высотой 44 px при строке текста 16 px: между строками получалось
   больше воздуха, чем в самих строках, и список выглядел «размазанным»
   на всю высоту колонки. Заголовков групп не было вовсе — восемь пунктов
   шли одной простыней.

   ⚠️ ЧТО СДЕЛАНО (и чего НЕ сделано):

   * вертикальный шаг уменьшен: margin:0 вместо 2 px, отступ пункта
     9 px сверху и снизу, line-height:1.25. Высота пункта — это ЕГО
     ТЕКСТ плюс небольшой отступ, а не «пол-экрана»;
   * размер касания НЕ уменьшается: min-height:44px остаётся (владелец
     просил компактность «за счёт межстрочного, а не за счёт уменьшения
     зоны нажатия») — на телефоне это ровно те же 44 px;
   * заголовки групп: мелкие и полужирные, отступ до своих пунктов
     маленький (4 px), до следующей группы заметно больше (14 px) —
     группы видно, но они не раздувают колонку;
   * шрифт — тот же, что у сайта (ont:inherit), размер пункта равен
     основному тексту: начертание обычное, а активный пункт выделяется
     ЦВЕТОМ и ФОНОМ, а не размером (иначе активная строка «прыгала» бы
     по ширине и ломала ровный левый край);
   * горизонтальные отступы ровные: один шаг 12 px у пунктов и у заголовков,
     выравнивание по левому краю;
   * длинные названия ПЕРЕНОСЯТСЯ (white-space:normal, overflow-wrap),
     а не обрезаются: «Адреса доставки организации» должно читаться целиком.

   ⚠️ НА ТЕЛЕФОНЕ меню остаётся горизонтальным (как было): та же плотность,
   а заголовки групп скрыты — в строке плиток они ломали бы раскладку. */
.account-nav a.account-link{
  margin:0;
  padding:9px 12px;
  line-height:1.25;
  border-radius:10px;
  white-space:normal;
  overflow-wrap:anywhere;
  text-align:left;
  justify-content:flex-start}
.account-nav-title{
  font-size:12px;
  font-weight:700;
  letter-spacing:.02em;
  color:var(--muted);
  padding:0 12px;
  margin:14px 0 4px;
  text-transform:uppercase}
.account-nav-title:first-of-type{margin-top:6px}
.account-nav a.account-link.active{
  background:var(--primarySoft);
  color:var(--primary);
  font-weight:700}
@media(max-width:767px){
  .account-nav-title{display:none}
  .account-nav a.account-link{
    margin:0;
    padding:9px 12px;
    line-height:1.25;
    min-height:44px}
}

/* --- 18.12 Телефон: стрелки лент, кнопка «Применить», имя в плитке ------ */
/* Дефекты с телефона Samsung S23 (владелец, 2026-10-13, со скриншотами).

   ⚠️ 1. СТРЕЛКИ ЛЕНТ БЫЛИ «КВАДРАТНЫМИ СЕРЫМИ» И СЪЕЗЖАЛИ ПО ВЕРТИКАЛИ.
   Причина — СИСТЕМНЫЙ ВИД КНОПКИ: `<button>` в мобильных браузерах
   (в частности в Samsung Internet) рисуется своей «кнопочной» заливкой
   и своими углами, если явно не снять `appearance`. Тогда полупрозрачный
   круг превращался в серый прямоугольник, а системная тень сдвигала его
   относительно центра ленты. Лечение: `appearance:none` у самой стрелки
   и ПОВТОРЕНИЕ формы и центрирования на телефоне — чтобы ни одно правило
   ниже по каскаду (в том числе макетное) не могло вернуть квадрат.

   ⚠️ 2. КНОПКА «ПРИМЕНИТЬ» НА ТЕЛЕФОНЕ. Сортировка применяется выбором,
   поэтому кнопка скрывается — но ТОЛЬКО когда скрипт действительно работает
   (`.js` на `<html>` ставит `site.js`; без скрипта сортировку применить
   нечем, и кнопка обязана остаться). `!important` здесь намеренный: правило
   стоит в конце файла и обязано победить любое макетное «показать кнопку
   на телефоне», иначе дефект вернётся.

   ⚠️ 3. ИМЯ ТОВАРА В ПЛИТКЕ — НЕ БОЛЬШЕ ДВУХ СТРОК (иначе высота карточек
   «пляшет»: у одного товара «Пневматический гвоздезабивной пистолет Toua
   FN3490» занимал три строки, у соседа — одну). Две строки плюс ВЫСОТА
   В ДВЕ СТРОКИ у всех плиток: сетка выравнивается, обрезка — многоточием.

   ⚠️ 4. ОКНО ФИЛЬТРОВ ОТКРЫВАЕТСЯ ПО НАЖАТИЮ. Раскрытие — по `:target`
   (работает и без скрипта) И по классу `is-open` (скрипт). Оба пути
   повторены здесь с `!important`, чтобы окно открывалось даже тогда, когда
   один из механизмов недоступен. */
.rail-arrow{
  appearance:none;
  -webkit-appearance:none;
  border-radius:50%;
  background:rgba(255,255,255,.16);
  top:50%;
  transform:translateY(-50%)}
.card .product-name{
  display:-webkit-box!important;
  /* Название 14 px (а не 15): в строку влезает больше символов, высота строки
     меньше — в плитку влезает на строку больше. 14 px — стандарт плиток
     маркетплейсов, на телефоне остаётся читаемым (решение 26.10.2026). */
  font-size:14px;
  /* Имя товара в ТРИ строки (решение владельца 26.10.2026): в две строки не влезала
     ключевая разница — «БАЗОВЫЙ PRO, ПРОВОДНОЙ 1/2"» и «БАЗОВЫЙ, ПРОВОДНОЙ 1/2"»
     выглядели одинаково. Высота по-прежнему фиксированная: сетка ровная.
     Полное название — в подсказке (`title` в разметке плитки). */
  -webkit-line-clamp:3!important;
  -webkit-box-orient:vertical;
  line-height:1.3;
  overflow:hidden}
@media(max-width:767px){
  .scroll-rail .rail-arrow{
    appearance:none;
    -webkit-appearance:none;
    top:50%;
    transform:translateY(-50%);
    width:44px;
    height:44px;
    border-radius:50%;
    background:rgba(255,255,255,.16)}
  /* Сортировка применяется выбором: кнопка не нужна (без скрипта остаётся). */
  .js .toolbar .sort-apply{display:none!important}
  /* Окно фильтров: оба пути открытия — и на телефоне. */
  .filters-form:target,
  .filters.is-open .filters-form{display:flex!important}
  /* Имя товара в три строки и на телефоне: высоту держит распорка, а не
     пустая третья строка (жалоба 26.10.2026 про отступ до артикула). */
}

/* --- Якоря на странице товара: липкая шапка не накрывает заголовки ----------
   Замечание владельца 21.10.2026: «липкая шапка закрывает заголовки
   Характеристики, Описание».

   ПОЧЕМУ ТАК, А НЕ СКРИПТ. Прокрутку по якорю делает браузер, и единственный
   правильный рычаг — `scroll-margin-top`: он говорит браузеру, сколько места
   оставить над целью. Скрипт здесь был бы лишним и ломал бы переходы без JS.

   ВЫСОТА. Шапка сайта = верхняя полоса (`.topbar`) + основная шапка
   (`.main-head`, высота складывается из значка и отступов). Обе величины
   заданы переменными ниже, поэтому отступ не «зашит» числом. */
:root{
  /*: Метрики липкой шапки: значок и запас сверху/снизу. Отсюда считается всё —
     и высота шапки, и отступ якорей: вторых чисел в проекте нет. */
  --head-icon:22px;
  --head-pad-y:8px;
  /* +1 — нижняя граница шапки (border-bottom). */
  --site-head-h:calc(var(--head-icon) + 2 * var(--head-pad-y) + 1px)
}
/* Шапка липнет к верху страницы (верхняя полоса при прокрутке уезжает),
   поэтому отступ = высота шапки + 12 px воздуха до заголовка. */
#specs,
#description,
#documents{
  scroll-margin-top:calc(var(--site-head-h) + 12px)}
/* Плавная прокрутка по якорям — только когда система не просит обратного. */
@media(prefers-reduced-motion:no-preference){
  html{scroll-behavior:smooth}
}

/* --- 18.13 Шапка и боковое меню админки --------------------------------- */
/* Уточнение владельца (2026-10-13, по скриншоту): в шапке админки ссылки
   стояли СЛЕВА рядом с логотипом, а «Выход» уезжал вправо; боковое меню
   было «размазано» по высоте — в отличие от меню кабинета, которое владелец
   уже принял.

   ⚠️ 1. ДЕЙСТВИЯ ШАПКИ — СПРАВА, ОДНИМ РЯДОМ. Раньше вправо отодвигался
   только «Выход» (`.admin-head-exit{margin-left:auto}`), поэтому ссылки
   оставались у левого края, а кнопка жила отдельно. Теперь вправо уезжает
   ВСЯ группа действий (`.admin-head-actions`), а порядок внутри неё задан
   разметкой: «Публичная часть», «Админ-панель», «Выход».

   ⚠️ 2. ТЕ ЖЕ ЗНАЧЕНИЯ, ЧТО В КАБИНЕТЕ (раздел 18.11). Владелец просил
   «как в личном кабинете клиента», поэтому вертикальный шаг, отступы
   и заголовки групп взяты ОТТУДА ЖЕ, а не подобраны заново: margin 0,
   padding 9 px 12 px, line-height 1.25, касание 44 px, активный пункт —
   цветом и фоном (без изменения размера), длинные названия переносятся.

   ⚠️ 3. ЗАГОЛОВКИ ГРУПП. Разделы админки сгруппированы в реестре
   (`admin_paths.py`, поле `group`), а разметка выводит заголовок один раз
   на группу (`_admin_nav.html`): короткий и полужирный, как в кабинете. */
.admin-head-actions{
  display:flex;
  align-items:center;
  gap:4px;
  margin-left:auto}
.admin-head-exit{margin:0}
.admin-nav a.admin-link{
  margin:0;
  padding:9px 12px;
  line-height:1.25;
  border-radius:10px;
  white-space:normal;
  overflow-wrap:anywhere;
  text-align:left;
  justify-content:flex-start}
.admin-nav-title{
  font-size:12px;
  font-weight:700;
  letter-spacing:.02em;
  color:var(--muted);
  padding:0 12px;
  margin:14px 0 4px;
  text-transform:uppercase}
.admin-nav-title:first-of-type{margin-top:6px}
.admin-nav a.admin-link.active{
  background:var(--primarySoft);
  color:var(--primary);
  font-weight:700}
@media(max-width:767px){
  .admin-nav-title{display:none}
  .admin-nav a.admin-link{
    margin:0;
    padding:9px 12px;
    line-height:1.25;
    min-height:44px}
}

/* --- 18.14 Окно подтверждения удаления позиции корзины ------------------ */
/* Требование владельца (2026-10-13, по образцу): «Удалить товар» + текст
   «Вы точно хотите удалить выбранный товар? Отменить данное действие будет
   невозможно» + кнопка «Удалить».

   ⚠️ ОФОРМЛЕНИЕ ВЗЯТО У ПРОЕКТА (.dialog, .accessory-zoom-close,
   .btn), второй системы окон не заводится: окно подтверждения — тот же
   .dialog, что и увеличенное окно аксессуара (site.css, 17.6). Здесь
   только раскладка: голова с крестиком, текст и ряд кнопок.

   ⚠️ КНОПКИ В РЯДУ И НЕ УЖЕ 44 px: на телефоне по ним нажимают пальцем,
   и «Отмена» рядом с «Удалить» обязана быть крупной — промах по маленькой
   кнопке в этом окне означал бы удаление товара. */
.confirm-dialog{width:min(440px,92vw);padding:0;overflow:hidden}
.confirm-dialog[open]{display:flex;flex-direction:column}
.confirm-dialog-head{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:12px;
  padding:12px 10px 10px 18px;
  border-bottom:1px solid var(--line)}
.confirm-dialog-title{font-size:18px;line-height:1.3;margin:0;letter-spacing:0}
.confirm-dialog-text{margin:0;padding:16px 18px;color:var(--text)}
.confirm-dialog-actions{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  justify-content:flex-end;
  padding:0 18px 16px}
.confirm-dialog-actions .btn{min-height:44px}
/* ============================================================
   --- 19. СТРАНИЦЫ ДОКУМЕНТОВ (оферта, политика, согласия, cookie,
   доставка, оплата, возврат, о магазине, контакты, B2B, бонусы) ----
   ============================================================

   ⚠️ ЗАЧЕМ ОТДЕЛЬНЫЙ РАЗДЕЛ. Это длинные тексты: у оферты десять
   разделов, у политики — девять, у правил бонусов — семь. Читать их
   строкой во всю ширину экрана невозможно, поэтому текст идёт колонкой
   ограниченной ширины, а рядом стоит список разделов («на этой странице»).
   Разметку текста строит сервер (`app/web/legal_content.py`), поэтому
   стили описаны для тегов `<h2>`, `<ul>`, `<table>` внутри `.doc-text` —
   отдельных классов на каждый абзац не заводится.

   ⚠️ РАЗМЕРЫ НЕ МЕНЬШЕ ФОРМЫ ВИТРИНЫ. Основной текст документа — тот же
   кегль, что у текста страниц (16 px / 1.6): документ читают, а не
   просматривают. Списку разделов кегль меньше — это навигация. */
/* Страница документа: содержание + текст.
   ⚠️ ДВЕ КОЛОНКИ — ТОЛЬКО КОГДА СОДЕРЖАНИЕ ЕСТЬ (замечание владельца 21.10.2026):
   раньше сетка всегда была двухколоночной, и у короткого документа статья вставала
   в узкую колонку 260 px — текст сжимался, справа оставалась пустота. */
.doc-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:24px;align-items:start;margin-top:24px}
.doc-grid:has(.doc-toc){grid-template-columns:260px minmax(0,1fr);gap:48px}
/* Содержание липнет НИЖЕ шапки сайта (замечание владельца 21.10.2026):
   иначе первые пункты уезжали под липкую шапку. Высота — из той же переменной,
   что у шапки и у отступов якорей. */
.doc-toc{
  position:sticky;
  top:calc(var(--site-head-h) + 16px);
  max-height:calc(100vh - var(--site-head-h) - 32px);
  overflow-y:auto;
  font-size:14px}
.doc-toc-title{font-size:12px;letter-spacing:.6px;text-transform:uppercase;color:var(--muted,#586779);margin:0 0 10px;font-weight:700}
.doc-toc ol{list-style:none;margin:0;padding:0}
.doc-toc li{margin:0}
.doc-toc a{display:block;padding:5px 0;color:#586779;line-height:1.4}
.doc-toc a:hover{color:#1658e8}
.doc-toc-level-3 a{padding-left:14px;font-size:13px}
.doc-toc-level-4 a{padding-left:26px;font-size:13px}
.doc-body{min-width:0;max-width:820px}
.doc-actions{margin:0 0 20px;font-size:14px}
.doc-actions a{color:#1658e8}
.doc-text{font-size:16px;line-height:1.6;overflow-wrap:break-word}
.doc-text>*:first-child{margin-top:0}
.doc-text h2{font-size:24px;line-height:1.3;letter-spacing:-.4px;margin:36px 0 12px;scroll-margin-top:calc(var(--site-head-h) + 16px)}
.doc-text h3{font-size:18px;line-height:1.4;margin:26px 0 10px;scroll-margin-top:calc(var(--site-head-h) + 16px)}
.doc-text h4{font-size:16px;margin:20px 0 8px;scroll-margin-top:calc(var(--site-head-h) + 16px)}
.doc-text p{margin:0 0 14px}
.doc-text ul,.doc-text ol{margin:0 0 16px;padding-left:22px}
.doc-text li{margin:6px 0}
.doc-text strong{font-weight:700}
.doc-text code{background:#f5f7fa;border-radius:6px;padding:2px 6px;font-size:14px}
.doc-text blockquote{margin:18px 0;padding:14px 20px;background:#f5f7fa;border-left:3px solid #1658e8;border-radius:0 12px 12px 0}
.doc-text blockquote p:last-child{margin-bottom:0}
.doc-text hr{border:0;border-top:1px solid #e4eaf1;margin:32px 0}
.doc-text a{color:#1658e8}
.doc-text a:hover{text-decoration:underline}
.legal-table-wrap{overflow-x:auto;margin:0 0 20px;-webkit-overflow-scrolling:touch}
.legal-table{width:100%;border-collapse:collapse;font-size:14px;min-width:520px}
.legal-table th{text-align:left;font-size:12px;color:#586779;background:#edf2f9;padding:12px 14px;font-weight:700;vertical-align:top}
.legal-table td{padding:12px 14px;border-bottom:1px solid #e4eaf1;vertical-align:top}
.doc-list{list-style:none;margin:0 0 28px;padding:0;max-width:820px}
.doc-list li{padding:14px 0;border-bottom:1px solid #e4eaf1}
.doc-list a{color:#1658e8;font-weight:700}
.doc-list a:hover{text-decoration:underline}
.doc-list .muted{margin-left:10px}
@media(max-width:1100px){
  .doc-grid{grid-template-columns:1fr;gap:24px}
  .doc-toc{position:static;max-height:none;border:1px solid #e4eaf1;border-radius:16px;padding:16px 18px}
  .doc-toc a{min-height:32px}
}
@media(max-width:767px){
  .doc-text h2{font-size:20px;margin:28px 0 10px}
  .doc-text h3{font-size:17px}
  .legal-table{min-width:440px}
}

/* --- 18.15 Стрелки ленты брендов: по краям, а не поверх подписей -------- */
/* Дефект владельца (2026-10-13, по скриншоту): «стрелки перекрывают текст
   карточки» — левая залезала на плитку и наезжала на название.

   ⚠️ ЧТО БЫЛО НЕ ТАК. У общих лент стрелка стоит ВНУТРИ ленты, в 8 px от края
   (.rail-prev{left:-8px}): у плиток-подборок и карточек товара подпись
   снизу, и кнопка ей не мешает. В ленте брендов подпись — ПО ЦЕНТРУ плитки
   (логотипа на этом контуре нет, вместо него название), поэтому кнопка
   закрывала буквы.

   ⚠️ ЧТО СДЕЛАНО. У ленты брендов появился свой «жёлоб»: лента получает
   боковые отступы ровно под ширину стрелки, а стрелки встают в этот жёлоб
   (left:0 / 
ight:0). Карточки не сдвигаются под кнопку и текст не
   перекрывается; при этом стрелки остаются КРУГЛЫМИ, ПОЛУПРОЗРАЧНЫМИ
   и ПО ЦЕНТРУ по вертикали — как во всех остальных лентах (раздел 18.12).

   ⚠️ НА ТЕЛЕФОНЕ жёлоб уже (48 px): там лента листается пальцем, и лишняя
   ширина отнимала бы место у плиток. Стрелки на телефоне прячет скрипт,
   когда листать нечего, — как и у других лент. */
.scroll-rail--brands{padding-left:52px;padding-right:52px}
/* ЛЕНТА БРЕНДОВ ЛИСТАЕТСЯ ПО ПЛИТКАМ (замечание 28.10.2026: первый
   логотип был обрезан стрелкой). Привязка останавливает ленту целыми плитками,
   а scroll-padding-left уводит плитку из-под кнопки. */
.scroll-rail--brands [data-rail-track]{scroll-snap-type:x proximity;scroll-padding-left:52px;padding:2px 0 6px}
.scroll-rail--brands .brand-tile{scroll-snap-align:start}
.scroll-rail--brands .rail-prev{left:0}
.scroll-rail--brands .rail-next{right:0}
@media(max-width:767px){
  .scroll-rail--brands{padding-left:48px;padding-right:48px}
}

/* --- 18.16 Меню кабинета: заголовки групп и счётчики пунктов ------------ */
/* Владелец (2026-10-13, по скриншотам): «заголовки групп и ссылки почти
   не отличаются друг от друга — непонятно и некрасиво», просил как у Ozon.

   ⚠️ 1. РАЗНИЦА — НАЧЕРТАНИЕМ И ЦВЕТОМ, А НЕ РАЗМЕРОМ. Раньше заголовок
   группы был мелким (12 px) полужирным и приглушённым, а ссылка — обычным
   текстом того же приглушённого цвета: на глаз они читались одинаково.
   Теперь заголовок — полужирный, ТЁМНЫЙ (основной цвет текста) и с разрядкой,
   а ссылка — обычным начертанием и приглушённым цветом. Разницу видно сразу,
   при этом размеры остались прежними (плотность не поехала).

   ⚠️ 2. СЧЁТЧИК НЕ РАЗДВИГАЕТ СТРОКУ. Число прижато вправо (`margin-left:auto`),
   имеет минимальную ширину и не растягивается (`flex:0 0 auto`), не переносится
   (`white-space:nowrap`), а подпись пункта переносится по словам как раньше —
   поэтому длинные названия («Адреса доставки организации») не ломаются.

   ⚠️ 3. НА ТЕЛЕФОНЕ СЧЁТЧИКОВ НЕТ. Там меню — горизонтальный ряд узких плиток
   (`site.css`, 18.11): число в плитке отнимало бы место у подписи и рвало бы
   перенос. Те же числа покупатель видит в кружках шапки (там они и считаются),
   поэтому «скрыть» здесь ничего не теряет. */
.account-nav a.account-link{
  display:flex;
  align-items:center;
  gap:10px}
.account-nav .account-link-title{
  min-width:0;
  overflow-wrap:anywhere}
.account-nav .account-count{
  margin-left:auto;
  flex:0 0 auto;
  min-width:22px;
  padding:1px 7px;
  border-radius:11px;
  background:var(--primarySoft);
  color:var(--primary);
  font-size:12px;
  font-weight:700;
  line-height:18px;
  text-align:center;
  white-space:nowrap}
.account-nav a.account-link.active .account-count{
  background:var(--primary);
  color:#fff}
.account-nav-title{
  font-weight:700;
  color:var(--text);
  letter-spacing:.06em}
@media(max-width:767px){
  .account-nav .account-count,
  .account-nav .account-link+.sr-only{display:none}
}

/* --- 18.17 Живые фильтры: кнопка и сообщение об ошибке ------------------ */
/* Владелец (2026-10-13): «список товаров в каталоге должен меняться сразу
   при изменении значения в фильтре» — без нажатия «Применить фильтр».

   ⚠️ 1. КНОПКА НУЖНА ТОЛЬКО БЕЗ СКРИПТА. Когда скрипт загружен, выдача
   обновляется сама по изменению значения (`site.js`, раздел 13), и кнопка
   «Применить фильтр» на широком экране уступает место живой выдаче. Класс
   `filters-apply` появился в разметке (`_filters.html`) именно для этого:
   правило прячет РОВНО кнопку применения, а не «Сбросить фильтры».

   ⚠️ 2. НА ТЕЛЕФОНЕ КНОПКА ОСТАЁТСЯ ВСЕГДА (владелец: «в мобильном окне
   по-прежнему кнопки внизу»): фильтры там — отдельное окно на весь экран,
   и «Применить фильтр» закрывает его вместе с применением. Поэтому правило
   скрытия действует только ВНЕ мобильного окна.

   ⚠️ 3. ОШИБКА СЕТИ — СТРОКА, А НЕ ЧЁРНЫЙ ЭКРАН. Скрипт оставляет прежний
   список и показывает эту строку над ним (роль `alert` — диктор прочитает).
   Цвет берётся из переменных проекта, второй палитры не заводится. */
.js .filters-actions .filters-apply{display:none}
.catalog-ajax-error{
  margin:0 0 12px;
  padding:10px 14px;
  border-radius:12px;
  background:var(--warmSoft, #fff4e5);
  color:var(--onWarm, #7a4a00);
  font-size:14px}
@media(max-width:767px){
  .js .filters-actions .filters-apply{display:flex}
}

/* --- 18.18 Свой список: прокрутка внутри меню --------------------------- */
/* Владелец (2026-10-13, по скриншоту): «у списка брендов нет своей прокрутки:
   окно закрывается, как только пытаешься в нём проскроллить» — в списке
   брендов видно только часть (BeA, Dfast, Donel, EXLA…), до остальных
   не добраться.

   ⚠️ ПРИЧИНА БЫЛА В СКРИПТЕ, А НЕ В РАЗМЕТКЕ (см. `site.js`, раздел 10:
   слушатель прокрутки на `window` с `capture:true` ловил и прокрутку внутри
   самого списка). Здесь — вторая половина правки: у списка есть СВОЯ
   прокрутка и ВИДИМЫЙ признак, что вариантов больше.

   ⚠️ ОДИН КОМПОНЕНТ НА ВСЕ СПИСКИ: правила относятся к `.ds-menu` —
   тому же списку дизайн-системы, что рисует сортировку, «Состояние товара»,
   «Раздел каталога», «Все бренды» и остальные выпадающие списки витрины.
   Второго списка не заводится.

   ⚠️ ПОЛОСА ПРОКРУТКИ — В ЦВЕТАХ ПРОЕКТА, тонкая и не «во всю ширь»:
   она подсказывает, что список длиннее, но не отнимает место у названий. */
.ds-menu{
  max-height:min(320px,60vh);
  overflow-y:auto;
  overscroll-behavior:contain;
  scrollbar-width:thin;
  scrollbar-color:var(--line) transparent;
  /* Мягкая тень у краёв: видно, что выше/ниже есть ещё пункты. */
  background-image:linear-gradient(#fff 30%, rgba(255,255,255,0)),
    linear-gradient(rgba(255,255,255,0), #fff 70%);
  background-position:top, bottom;
  background-repeat:no-repeat;
  background-size:100% 18px;
  background-attachment:local, local}
.ds-menu::-webkit-scrollbar{width:10px}
.ds-menu::-webkit-scrollbar-thumb{
  background:var(--line);
  border-radius:8px;
  border:3px solid #fff}
.ds-menu::-webkit-scrollbar-track{background:transparent}
.ds-option{flex:0 0 auto}

/* --- 18.19 Якоря: цель перехода не прячется под липкую шапку ------------ */
/* Владелец (2026-10-13, по скриншотам): при нажатии «Все характеристики»
   страница прокручивалась слишком высоко, и заголовок «Характеристики»
   уезжал ПОД липкую шапку.

   ⚠️ ОДНО ОБЩЕЕ ЗНАЧЕНИЕ, А НЕ ДЛЯ ОДНОЙ СТРАНИЦЫ. Смещение задано
   переменной и применяется на КОРНЕ документа: браузер сам учитывает его
   при переходе по любому `#якорю` — «Все характеристики», «О товаре»,
   «Отзывы», «Доставка и оплата», «Похожие товары», «Наверх», ссылки
   из описаний, футера и юридических текстов. Ни одного правила под
   конкретную страницу не заводится.

   ⚠️ РАБОТАЕТ БЕЗ JAVASCRIPT. `scroll-padding-top` — это CSS: переход
   по якорю обслуживает браузер. Скрипт (`site.js`, раздел 14) только
   УТОЧНЯЕТ число, измеряя настоящую высоту липкой шапки.

   ⚠️ ПОЧЕМУ ЗАПАС, А НЕ ТОЧНАЯ ВЫСОТА. Липкая шапка — `.main-head`
   (`position:sticky`): её высота = значок (22 px) + запас сверху и снизу
   (8 px) + рамка, то есть около 39 px. В запасе оставлены ещё несколько
   пикселей: у заголовка раздела сверху есть свои отступы, и цель,
   прижатая к самой шапке, читалась бы как «прилипшая».

   ⚠️ НА ТЕЛЕФОНЕ ЗНАЧЕНИЕ БОЛЬШЕ: там шапка выше — поиск переносится
   на вторую строку (`site.css`, мобильный блок), и высота доходит
   до ~130 px. Точное число подставляет скрипт, здесь — безопасный запас
   для случая без него.

   ⚠️ ЧЕГО ЗДЕСЬ НАМЕРЕННО НЕТ: `scroll-margin-top` у целей. Он СКЛАДЫВАЕТСЯ
   со `scroll-padding-top`, и цель уехала бы вниз вдвое. */
:root{--head-anchor-offset:48px}
html{scroll-padding-top:var(--head-anchor-offset)}
@media(max-width:767px){
  :root{--head-anchor-offset:140px}
}

/* --- 18.20 Строка наличия: единый вид и никакого зазора перед запятой -- */
/* Владелец (2026-10-13, по скриншоту): «в одном ряду карточки показывают
   наличие и срок доставки по-разному», плюс на экране было видно
   «доставка из Москвы ,» — лишний пробел перед запятой.

   ⚠️ ОТКУДА БРАЛСЯ ПРОБЕЛ. Строка наличия была `display:flex` с `gap:4px`,
   а текст и грузовичок с датой — ДВУМЯ её элементами. Запятая стояла
   в конце первого элемента, и зазор (4 px) оказывался ровно перед ней:
   «доставка из Москвы», зазор, «, 23.10.26 г.». Никакой лишней запятой
   в тексте не было — её «раздвигал» зазор.

   ⚠️ КАК СТАЛО. Строка — обычный поток (`display:block`), поэтому запятая
   примыкает к тексту; грузовичок с датой — единый неразрывный блок
   (`inline-flex` + `white-space:nowrap`), он не разрывается между строкой
   текста и датой и переносится целиком, если места мало.

   ⚠️ ПРАВИЛО ОДНО ДЛЯ ВСЕХ ПЛИТОК: и «есть на складе», и «доставка
   из Москвы» рисуются одной разметкой (`_card.html`), поэтому состав
   и вид строк не могут разойтись между каталогом, главной, акциями,
   брендами, избранным, поиском и похожими товарами.

   ⚠️ ЗДЕСЬ БОЛЬШЕ НЕТ СВОЕГО `.card-stock-row`. Раньше ниже в файле лежало второе
   правило (`display:block; align-items:baseline; line-height:1.35`), и в CSS
   побеждало именно оно: слово и дата выравнивались по базовой линии с разным
   межстрочным — «Со склада» и «02.11.26 г.» стояли на разной высоте (замечание
   владельца 21.10.2026). Выравнивание задано один раз выше — `.card-stock-row`
   с `align-items:center; line-height:20px`. Второго правила быть не должно.

/* --- 18.21 Раскрывашка «Каталог»: слой под липкой шапкой ---------------- */
/* Дефект владельца (2026-10-13, по скриншоту): «раскрывашка "Каталог"
   уезжает вместе со страницей» — панель мега-меню стоит в потоке документа,
   поэтому внизу страницы открывается далеко наверху и её не видно.

   ⚠️ ПОЧЕМУ ИМЕННО ТАК. Панель — не «ещё один блок каталога», а слой поверх
   страницы: `position:fixed`, верх — под липкой шапкой (`--head-anchor-offset`
   обновляет скрипт по настоящей высоте шапки), низ — по краю окна. Поэтому
   она видна при ЛЮБОЙ прокрутке и открывается ровно под кнопкой «Каталог».

   ⚠️ СЛОЙ НИЖЕ ШАПКИ: `z-index:55` при шапке `z-index:60` — кнопка «Каталог»
   и закрытие остаются доступными, панель их не перекрывает.

   ⚠️ ПРОКРУТКА ВНУТРИ ПАНЕЛИ, А НЕ СТРАНИЦЫ: панель длинная (рейка разделов
   плюс содержимое), поэтому у неё `overflow:auto`, а страница под ней
   заперта (`body.catalog-view-open{overflow:hidden}`) — иначе фон «уезжал» бы
   под панелью и покупатель терял бы место, откуда открыл меню. */
.catalog-page{
  position:fixed;
  left:0;
  right:0;
  /* Верх задаёт скрипт по фактическому низу липкой шапки;
     `--head-anchor-offset` — запасной вариант без JavaScript. */
  top:var(--head-anchor-offset);
  bottom:0;
  z-index:55;
  overflow:auto;
  overscroll-behavior:contain;
  min-height:0;
  padding-bottom:32px}
body.catalog-view-open{overflow:hidden}
@media(max-width:767px){
  /* На телефоне шапка выше (поиск на второй строке) — её высоту тоже
     знает `--head-anchor-offset`, поэтому правило то же. */
  .catalog-page{top:var(--head-anchor-offset)}
}

/* --- 18.22 Вход: блок «Что будет в кабинете» --------------------------- */
/* Дефект владельца (2026-10-13, скриншот с боевого сайта): «на странице
   входа слева от формы блок свёрстан плохо — нечитабельно»: подпись рвалась
   по слогам («избранно…»), заголовок занимал четыре строки.

   ⚠️ ПРИЧИНА БЫЛА В ШИРИНЕ, А НЕ В ШРИФТЕ. Карточка лежит в общем
   `.promo-list`, а это СЕТКА ИЗ ТРЁХ КОЛОНОК для блока «Акции», где карточек
   три. На входе карточка одна, поэтому она занимала треть колонки истории,
   и текст дополнительно урезался правилом `.promo-tool .promo-copy{
   max-width:63%}` (оно про карточки с картинкой справа). В сумме на текст
   оставалось 2–3 буквы ширины.

   ⚠️ ОБЩИЙ СПИСОК НЕ ТРОГАЕМ: правило действует ТОЛЬКО внутри `.auth-story`,
   поэтому «Акции» на главной остаются тремя колонками, а ленты-карусели
   промо — как были.

   ⚠️ ПЕРЕНОС — ПО СЛОВАМ: `overflow-wrap:break-word` разрешает перенести
   СЛОВО целиком, если оно не влезает, и не рвёт его по слогам
   (`hyphens:none`, `word-break` не задаётся вовсе — наследовать `break-all`
   здесь нечего, но правило фиксирует это явно). */
.auth-story .promo-list{
  grid-template-columns:minmax(0,1fr);
  gap:0}
.auth-story .promo-tool .promo-copy,
.auth-story .promo-copy{
  max-width:none;
  overflow-wrap:break-word;
  hyphens:none}
.auth-story .promo-copy strong{
  font-size:17px;
  line-height:1.4;
  font-weight:600}
.auth-story .auth-benefits{
  margin:4px 0 0;
  padding-left:20px;
  list-style:disc;
  display:grid;
  gap:4px;
  font-size:17px;
  line-height:1.4}
.auth-story .auth-benefits li{
  overflow-wrap:break-word;
  hyphens:none}

/* Фото в строке: те же точки и счётчик, что в плитке. Контейнер `.media`
   обязателен — по нему скрипт находит точки при смене кадра.

   ⚠️ ЦЕНТРОВКА — НА КОНТЕЙНЕРЕ (дефект 28.10.2026): когда фото обернули в
   `.media`, `align-self:center` осталось на ссылке внутри, а сетка центрует
   дочерний элемент — сам контейнер. Фото стояло сверху.
   ⚠️ ТОЧКИ ВИДНЫ ВСЕГДА и по центру фото: глобальное правило плитки ставит
   `left:50%` с `translateX(-50%)` — в строке это уводило их за картинку. */
.card-row-media{
  position:relative;
  overflow:hidden;
  align-self:center;
  grid-area:photo;
  width:120px;
  height:120px;
  border-radius:14px;
  background:white}
/* Точки в строке списка — по ОБЩИМ правилам плитки (`.card-dots`, `.card-dot`).
   Ничего не переопределяем: вид и расположение те же, что в плитке. Для этого
   у контейнера фото есть `position:relative`. На планшете и телефоне размер
   фото меняется, точки и счётчик ведут себя как в плитке. */
@media(max-width:767px){
  .card-row-media{position:relative;overflow:hidden;align-self:center;grid-area:photo;width:120px;height:120px;border-radius:14px;background:white}
}

/* Наличие и срок — по ПРАВОМУ краю колонки, как цена и кнопка.
   ⚠️ Сами строки наличия — flex с выравниванием влево (общий макрос для плитки
   и карточки), поэтому в строке списка их надо прижать вправо. */
.card-row-stock .card-stock-rows{display:flex;flex-direction:column;align-items:flex-end}
.card-row-stock .card-stock-row{justify-content:flex-end;width:100%}

@media(max-width:1100px){
  /* Планшет: колонка истории уже, но карточка по-прежнему во всю ширину,
     а размер шрифта уменьшается вместе с остальной типографикой страницы. */
  .auth-story .auth-benefits,
  .auth-story .promo-copy strong{font-size:16px}
}

/* --- 18.23 Пин-код: четыре ячейки -------------------------------------- */
/* Требование владельца (2026-10-13, по скриншоту «Новый пин-код»): «поле
   ввода пин-кода сделать не одним полем, а четыре ячейки с автопереходом
   курсора, и чтобы удаление назад перемещало курсор в предыдущую ячейку».

   ⚠️ РАЗМЕР ЯЧЕЙКИ ФИКСИРОВАН. Ширина и высота заданы в пикселях, а не
   «по содержимому»: иначе при вводе цифры ячейка меняла бы ширину, и весь
   ряд «прыгал» бы (владелец просил, чтобы ячейки не прыгали).

   ⚠️ ЦИФРЫ КРУПНЫЕ И ПО ЦЕНТРУ: пин-код набирают вслепую, и в ячейке должна
   читаться одна цифра, а не строка текста. Шрифт берётся из общего стека
   сайта (`var(--font)`), размеры — из общей шкалы.

   ⚠️ НА ТЕЛЕФОНЕ ЯЧЕЙКИ БОЛЬШЕ: палец должен попадать без прицеливания,
   а ряд — укладываться в узкий экран (четыре по 56 px плюс промежутки). */
.pin-cells{
  display:flex;
  gap:10px;
  align-items:center}
.pin-cell{
  width:52px;
  height:60px;
  padding:0;
  text-align:center;
  font-family:var(--font);
  font-size:24px;
  font-weight:600;
  line-height:1;
  color:var(--text);
  background:#fff;
  border:1px solid var(--line);
  border-radius:12px;
  appearance:none}
.pin-cell:focus-visible{
  outline:2px solid var(--focus);
  outline-offset:1px}
.pin-cell[aria-invalid="true"]{
  border-color:var(--danger);
  background:#fff5f5}
.pin-label{
  display:block;
  margin-bottom:8px;
  font-size:14px;
  color:var(--muted)}
@media(max-width:767px){
  .pin-cells{gap:8px}
  .pin-cell{width:56px;height:64px;font-size:26px;border-radius:14px}
}

/* ============================================================
   19. ДАШБОРДЫ АДМИНКИ (главная и «Аналитика»)
   ============================================================
   Решение владельца 2026-10-14: «сбалансированный» дашборд, где ПЕРВЫЙ блок —
   «Здоровье сайта» (что мешает покупателю оформить покупку), затем динамика,
   затем «требует внимания», затем детали.

   ПРАВИЛА ЧИТАЕМОСТИ (зачем именно так):
   * крупное число — 32 px, подпись к нему — 13 px: глаз читает цифру, а не
     текст вокруг неё;
   * у каждого числа подписана единица измерения, сравнение с прошлым
     периодом стоит СЛОВАМИ («было … стало …»), а цвет только помогает:
     дальтоник видит то же самое по тексту;
   * цветов ровно пять и все со смыслом: зелёный — в порядке, янтарный —
     доделать, красный — мешает покупке, серый — в разработке, синий —
     действия и текущий выбор. Других цветов здесь нет;
   * столбики продаж — это `div` с высотой в процентах: график рисуется без
     картинок, скриптов и внешних библиотек, а тот же ряд чисел всегда есть
     таблицей под графиком;
   * пустое состояние — фраза («заказов за этот период не было»), а не
     пустая рамка;
   * «в разработке» — серый неактивный блок с объяснением, чего не хватает:
     ноль вместо данных врал бы («всё плохо»).

   ⚠️ ЭТОТ РАЗДЕЛ — ПОСЛЕДНИЙ В ФАЙЛЕ и не переопределяет правила выше:
   все классы начинаются с `dash-`, таких имён в других разделах нет. */

.dash-period{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0 0 10px}
.dash-period-label{font-size:14px;color:var(--muted);margin-right:4px}
.dash-period-item{
  min-height:44px;
  padding:10px 16px;
  border:1px solid var(--line);
  border-radius:999px;
  background:#fff;
  color:var(--text);
  font-size:14px;
  font-weight:600}
.dash-period-item:hover{border-color:#9eacc0}
.dash-period-item.is-current{background:var(--primarySoft);border-color:var(--primary);color:var(--primary)}
.dash-period-note{font-size:13px;color:var(--muted);margin:0 0 18px}
.dash-period-badge{font-size:13px;font-weight:700;color:var(--primary);background:var(--primarySoft);border-radius:999px;padding:6px 14px;white-space:nowrap}

.dash-block{background:#fff;border:1px solid var(--line);border-radius:var(--radius-card);padding:20px 22px;margin:0 0 18px}
.dash-block>h2{font-size:22px;letter-spacing:-.4px;margin:0 0 8px}
.dash-block-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 16px;margin-bottom:8px}
.dash-block-head h2{margin:0}
.dash-lead{font-size:14px;line-height:1.6;color:var(--muted);max-width:900px;margin:0 0 14px}

/* --- Здоровье сайта: главный блок страницы ------------------------------- */
.dash-health-headline{
  font-size:17px;
  font-weight:700;
  line-height:1.45;
  border-radius:14px;
  padding:12px 16px;
  margin:0 0 12px}
.dash-health-danger{background:var(--dangerSoft);color:var(--danger)}
.dash-health-warn{background:var(--warningSoft);color:var(--warning)}
.dash-health-ok{background:var(--successSoft);color:var(--success)}
.dash-health-soon{background:var(--surface);color:var(--muted)}
.dash-health-counts{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 14px}
.dash-tag{display:inline-block;border-radius:999px;padding:4px 10px;font-size:12px;font-weight:700;white-space:nowrap}
.dash-tag-danger{background:var(--dangerSoft);color:var(--danger)}
.dash-tag-warn{background:var(--warningSoft);color:var(--warning)}
.dash-tag-ok{background:var(--successSoft);color:var(--success)}
.dash-tag-soon{background:#eef1f5;color:#8793a3}

.dash-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;border-radius:14px;background:#fff}
.dash-table{width:100%;border-collapse:collapse;font-size:14px}
.dash-table caption{text-align:left}
.dash-table thead th{
  text-align:left;
  font-size:12px;
  letter-spacing:.4px;
  text-transform:uppercase;
  color:var(--muted);
  padding:10px 12px;
  border-bottom:1px solid var(--line);
  white-space:nowrap}
.dash-table td,.dash-table tbody th{padding:12px;border-bottom:1px solid var(--line);vertical-align:top;text-align:left;font-weight:400}
.dash-table tbody tr:last-child td,.dash-table tbody tr:last-child th{border-bottom:0}
.dash-table tbody tr:nth-child(even){background:#fafbfe}
.dash-table .num{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums;font-weight:700}
.dash-table tbody th[scope="row"]{font-weight:600}
.dash-health-hint{display:block;margin-top:4px;font-size:12px;line-height:1.5;color:var(--muted);font-weight:400;max-width:520px}
.dash-health-value{font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap}
.dash-health-row.is-danger{background:var(--dangerSoft)}
.dash-health-row.is-danger td,.dash-health-row.is-danger th{border-color:#f6d8dd}
.dash-health-row.is-danger .dash-health-value{color:var(--danger)}
.dash-health-row.is-soon{color:var(--muted)}
.dash-link{color:var(--primary);font-weight:700;min-height:44px;display:inline-flex;align-items:center}
.dash-link:hover{text-decoration:underline}

/* --- Плитки показателей -------------------------------------------------- */
.dash-kpi{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:12px}
.dash-kpi-compact{grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin-top:6px}
.dash-kpi-item{border:1px solid var(--line);border-radius:16px;padding:16px;background:#fff;min-width:0}
.dash-kpi-title{font-size:13px;color:var(--muted);margin-bottom:6px}
.dash-kpi-value{font-size:32px;line-height:1.15;font-weight:700;letter-spacing:-1px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
.dash-kpi-unit{font-size:14px;font-weight:600;color:var(--muted);margin-left:6px;letter-spacing:0}
.dash-kpi-compact .dash-kpi-value{font-size:22px;letter-spacing:-.5px}
.dash-kpi-compare{font-size:13px;font-weight:600;line-height:1.5;margin-top:6px}
.dash-trend-up{color:var(--success)}
.dash-trend-down{color:var(--danger)}
.dash-trend-flat,.dash-trend-none{color:var(--muted)}
.dash-kpi-hint{font-size:12px;line-height:1.5;color:var(--muted);margin:6px 0 0}

/* --- Столбики продаж по дням -------------------------------------------- */
.dash-chart{display:flex;align-items:flex-end;gap:4px;overflow-x:auto;padding:6px 2px 0;margin-bottom:6px}
.dash-chart-col{flex:1 0 auto;min-width:26px;display:flex;flex-direction:column;align-items:center;gap:4px}
.dash-chart-track{width:100%;height:130px;display:flex;align-items:flex-end}
.dash-chart-bar{width:100%;min-height:3px;background:var(--primary);border-radius:5px 5px 0 0}
.dash-chart-bar.is-empty{background:var(--line)}
.dash-chart-day{font-size:10px;color:var(--muted);white-space:nowrap;font-variant-numeric:tabular-nums}
.dash-chart-best{font-size:14px;margin:0 0 8px}
.dash-details{margin-top:6px}
.dash-details summary{font-size:14px;font-weight:700;color:var(--primary);min-height:44px;display:flex;align-items:center}

/* --- Требует внимания --------------------------------------------------- */
.dash-attention{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.dash-attention-item{border:1px solid var(--line);border-left:5px solid var(--line);border-radius:14px;padding:12px 16px}
.dash-attention-item.is-danger{border-left-color:var(--danger);background:var(--dangerSoft)}
.dash-attention-item.is-warn{border-left-color:var(--warning);background:var(--warningSoft)}
.dash-attention-item.is-soon{border-left-color:#c9d2de;background:var(--surface)}
.dash-attention-head{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:6px 14px}
.dash-attention-value{font-size:15px;font-weight:700;font-variant-numeric:tabular-nums}
.dash-attention-hint{font-size:13px;line-height:1.5;color:var(--muted);margin:4px 0 0}

/* --- Работа сейчас: счётчики состояний заказов (как на прежней главной) --- */
.dash-work-total{font-size:14px;margin:0 0 10px}
.dash-counters{display:flex;flex-wrap:wrap;gap:10px}
.dash-counter{
  display:inline-flex;
  align-items:baseline;
  gap:8px;
  padding:10px 14px;
  border-radius:999px;
  background:#fff;
  border:1px solid var(--line);
  color:var(--muted);
  font-size:14px;
  font-weight:700;
  min-height:44px}
.dash-counter strong{font-size:16px;color:var(--text);font-variant-numeric:tabular-nums}
.dash-counter:hover{border-color:#9eacc0}
.dash-counter.is-current{background:var(--primarySoft);border-color:var(--primary);color:var(--primary)}
.dash-counter.is-current strong{color:var(--primary)}

/* --- Пустые состояния и «в разработке» ---------------------------------- */
.dash-empty{background:var(--surface);border-radius:14px;padding:16px 18px;font-size:14px;line-height:1.6;color:var(--muted);margin:0}
.dash-empty b{color:var(--text)}
.dash-soon{background:var(--surface);border-style:dashed}
.dash-soon-list{list-style:none;margin:0;padding:0;display:grid;gap:12px}
.dash-soon-item{background:#fff;border:1px dashed var(--line);border-radius:14px;padding:14px 16px;color:var(--muted)}
.dash-soon-item b{color:var(--muted)}
.dash-soon-hint{font-size:13px;line-height:1.55;margin:6px 0 0}

@media(max-width:767px){
  .dash-block{padding:16px 14px;border-radius:16px}
  .dash-block>h2{font-size:19px}
  .dash-kpi{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
  .dash-kpi-item{padding:13px}
  .dash-kpi-value{font-size:26px}
  .dash-kpi-hint{display:none}
  .dash-chart-track{height:104px}
  .dash-health-hint{max-width:none}
  .dash-table{font-size:13px}
  .dash-table td,.dash-table tbody th{padding:10px 9px}
  .dash-period-item{padding:9px 13px;font-size:13px}
}
@media print{
  .dash-period,.dash-details{display:none}
  .dash-block{break-inside:avoid;border-color:#ccc}
}

/* --- 18.24 Артикул: код и кнопка «Копировать» -------------------------- */
/* Требования владельца (2026-10-13): «в каталоге, в корзине, в избранных —
   там, где списки товаров — слово "Артикул" убрать», «на странице карточки
   товара слово остаётся», «справа от артикула иконку "Копировать" — везде,
   где есть артикул».

   ⚠️ В СПИСКАХ ТОЛЬКО КОД: класс `.sku-code` — это сам код, без подписи.
   Подпись «Артикул» рисует только страница товара (макрос `sku_row`).

   ⚠️ ИКОНКА НЕ УВЕЛИЧИВАЕТ СТРОКУ. Кнопка — 20 px по содержимому, а зона
   нажатия расширена ПСЕВДОЭЛЕМЕНТОМ до ~40 px (`::after` с отрицательными
   отступами): палец попадает, а высота строки не меняется.

   ⚠️ ЦВЕТ НЕЙТРАЛЬНЫЙ: иконка подсказывает действие, но не спорит с ценой
   и кнопкой покупки. Фокус — из общей палитры сайта (`--focus`). */
.sku{
  display:flex;
  align-items:center;
  gap:6px;
  flex-wrap:wrap}
.sku-code{
  font-variant-numeric:tabular-nums}
.sku-copy{
  position:relative;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:20px;
  height:20px;
  padding:0;
  border:0;
  background:transparent;
  color:var(--muted);
  cursor:pointer;
  border-radius:6px}
.sku-copy[hidden]{
  display:none}
.sku-copy:hover{
  color:var(--primary)}
.sku-copy:focus-visible{
  outline:2px solid var(--focus);
  outline-offset:2px}
.sku-copy .icon{
  width:16px;
  height:16px}
.sku-copy::after{
  content:"";
  position:absolute;
  inset:-10px;
  border-radius:12px}
.sku-copied{
  font-size:12px;
  color:var(--success, #1a7f37);
  white-space:nowrap}
@media(max-width:767px){
  /* На телефоне зона нажатия ещё больше (палец), строка та же. */
  .sku-copy::after{inset:-12px}
}

/* --- 18.25 Якоря карточки товара: вкладки не прячутся за шапкой -------- */
/* Дефект владельца (2026-10-13, список `docs/Доработки_после_каталога.md`):
   «вкладки Характеристики, Описание, Документы прячутся за липким меню —
   должно быть ПОД меню».

   ⚠️ ПОЧЕМУ ОДНОГО ОТСТУПА ШАПКИ НЕ ХВАТИЛО. `scroll-padding-top` на корне
   (раздел 18.19) убирает из-под шапки только саму ШАПКУ. Над целевым блоком
   карточки стоит ещё РЯД ВКЛАДОК, и при переходе по якорю он оказывался
   ровно под шапкой.

   ⚠️ ОТСТУПЫ СКЛАДЫВАЮТСЯ, И ЭТО ЗДЕСЬ НУЖНО: итоговое смещение =
   `scroll-padding-top` (шапка) + `scroll-margin-top` (ряд вкладок). Поэтому
   цель встаёт ПОД вкладками, а сами вкладки остаются видны под шапкой.

   ⚠️ ВЫСОТА РЯДА ВКЛАДОК — ОДНА ПЕРЕМЕННАЯ, её обновляет скрипт
   по фактической высоте (`.detail-tabs`): на телефоне вкладки переносятся
   на вторую строку, и подобранное число разъехалось бы. Без скрипта
   значение 0 — поведение прежнее (шапку учитывает раздел 18.19). */
:root{--detail-tabs-offset:0px}
.detail-body>section,
.detail-body section[id],
#specs,
#description,
#dimensions{
  scroll-margin-top:var(--detail-tabs-offset)}

/* ⚠️ ЛИПКИЕ БОКОВЫЕ БЛОКИ — ПО ТОЙ ЖЕ ВЫСОТЕ ШАПКИ. Меню кабинета стояло
   на «16 px» и при прокрутке заезжало под шапку. Теперь отступ считается
   от фактической высоты шапки — одна переменная на всю витрину. */
.account-nav{
  top:calc(var(--head-anchor-offset) + 8px);
  max-height:calc(100vh - var(--head-anchor-offset) - 24px)}
@media(max-width:767px){
  .account-nav{top:calc(var(--head-anchor-offset) + 4px)}
}

/* --- 18.26 Фото: 90 % от рамки и увеличенный просмотр ------------------- */
/* Указание владельца (2026-10-13, дословно): «Изображение должно занимать
   90 % от размера окна для него. Не 100 %».

   ⚠️ ЗНАЧЕНИЕ — ОДНА ПЕРЕМЕННАЯ. Поля вокруг фото одинаковы в плитке
   каталога и в большой рамке страницы товара: если менять их по месту,
   однажды разъедется (владелец увидит «то 90 %, то 100 %»). */
:root{--media-fit:90%}
.card .media img{
  width:var(--media-fit);
  height:var(--media-fit);
  margin:auto;
  object-fit:contain}
.product-hero .product-photo{
  width:var(--media-fit);
  height:var(--media-fit);
  margin:auto;
  object-fit:contain}
/* Увеличенный просмотр: окно занимает почти весь экран, кадр — 90 % рамки. */
.product-zoom-media{
  display:grid;
  place-items:center;
  background:#fff;
  min-height:min(70vh, 620px)}
.product-zoom-media img{
  width:var(--media-fit);
  height:var(--media-fit);
  max-height:min(80vh, 720px);
  margin:auto;
  object-fit:contain}
.product-zoom-nav{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:12px;
  padding:10px 14px}
.product-zoom-nav .btn{
  min-height:44px}
.product-zoom-counter{
  font-size:13px;
  color:var(--muted)}

/* ============================================================
   УВЕЛИЧЕННОЕ ФОТО НА ПК — НА ВЕСЬ ЭКРАН (владелец 24.10.2026)

   Дословно: «Фото не режется по вертикали, фото должно помещаться по вертикали
   внутри окна браузера. Слева, вертикальным списком видим миниатюры, если все не
   помещаются в окно браузера, то их можно листать колесом мыши (аналогично
   миниатюрам на главной странице, только вертикальное листание). Стрелки
   влево/вправо сделай как у карусели Бренды. А справа блок с ценой, наличием и
   сроками, кол-вом, кнопками Купить и В избранное, в общем целиком блок покупки,
   как на странице товара».

   ⚠️ ЧТО БЫЛО. Окно просмотра — компонент `.dialog` шириной 460 px: кадр 1200 px
   показывался в рамке ~400 px, мутно, и посреди страницы.

   ⚠️ РАСКЛАДКА НА ПК — ТРИ КОЛОНКИ: миниатюры (слева), кадр (центр), покупка
   (справа). Кадр вписывается по ВЫСОТЕ окна (`max-height:100%`), а не режется:
   вертикальная прокрутка окна не появляется.

   ⚠️ МИНИАТЮРЫ ЛИСТАЮТСЯ КОЛЕСОМ. Это обычная прокрутка области
   (`overflow-y:auto`) — колесо мыши работает само, без скрипта. На телефоне
   колонки миниатюр и покупки скрыты: там окно и так почти во весь экран, а
   листают пальцем (свайп).
   ============================================================ */
@media (min-width:768px){
  .product-zoom[open]{
    width:100vw;
    max-width:100vw;
    height:100vh;
    max-height:100vh;
    margin:0;
    padding:0;
    border:0;
    border-radius:0;
    display:grid;
    grid-template-columns:104px minmax(0,1fr) 360px;
    grid-template-rows:auto minmax(0,1fr);
    grid-template-areas:
      "head head head"
      "thumbs stage purchase";
    /* ⚠️ ФОН ОКНА БЕЛЫЙ (владелец 24.10.2026): «Сделай цвет всего фона белым,
       чтобы не было заметно разницы между фоном просмотра и фоном самого фото». */
    background:#fff}
  /* ⚠️ ЛИНИЙ РАЗДЕЛЕНИЯ НЕТ (владелец 24.10.2026: «Нужно убрать линии разделения
     областей»). Границы между шапкой, миниатюрами и покупкой убраны: области
     разделяет фон, а не черта. */
  /* ⚠️ ВЫДЕЛЕНИЕ В ОКНЕ ЗАПРЕЩЕНО (дефект владельца 24.10.2026: «при быстром клике
     по стрелкам влево/вправо происходит выделение фото/миниатюр»). Быстрый второй
     клик браузер считает двойным и выделяет ближайший элемент; user-select:none
     убирает выделение текста, -webkit-user-drag:none — перетаскивание картинки. */
  .product-zoom,
  .product-zoom *{
    -webkit-user-select:none;
    user-select:none}
  .product-zoom img{
    -webkit-user-drag:none;
    user-select:none}
  .product-zoom .accessory-zoom-head{
    grid-area:head;
    /* Верхний отступ уменьшен вдвое (10 px → 5 px), линии под шапкой нет:
       её рисовал `border-bottom` у общего `.accessory-zoom-head`. */
    padding:5px 16px 0;
    border-bottom:0;
    justify-content:flex-end}
  .product-zoom .accessory-zoom-title{
    font-size:16px;
    padding-right:12px}
  /* Миниатюры: вертикальный список с прокруткой колесом. */
  .product-zoom-thumbs{
    grid-area:thumbs;
    display:flex;
    flex-direction:column;
    gap:8px;
    /* Верхний отступ уменьшен вдвое (12 px → 6 px). */
    padding:6px 10px;
    overflow-y:auto;
    overscroll-behavior:contain}
  .product-zoom-thumb{
    flex:0 0 auto;
    width:100%;
    padding:2px;
    border:1px solid var(--line);
    border-radius:10px;
    background:#fff;
    cursor:pointer}
  .product-zoom-thumb img{
    display:block;
    width:100%;
    height:auto;
    border-radius:8px}
  .product-zoom-thumb.is-current{
    border-color:var(--primary);
    box-shadow:0 0 0 2px var(--primarySoft)}
  /* ⚠️ КАДР ВПИСЫВАЕТСЯ ЦЕЛИКОМ (владелец 24.10.2026: «Фото режется по высоте,
     надо его поместить целым вовнутрь окна браузера»). Высота области считается
     от ВЫСОТЫ ОКНА, а не от содержимого: `max-height:100%` не работает, когда у
     родителя высота не задана, — поэтому здесь явные `calc` от `100vh`. */
  .product-zoom-stage{
    grid-area:stage;
    position:relative;
    display:grid;
    place-items:center;
    min-height:0;
    /* Верхний отступ уменьшен вдвое (8 px → 4 px). */
    padding:4px 76px 34px}
  .product-zoom-media{
    display:grid;
    place-items:center;
    width:100%;
    height:calc(100vh - 120px);
    max-height:100%;
    min-height:0;
    background:transparent}
  .product-zoom-media img{
    width:auto;
    height:auto;
    max-width:100%;
    max-height:calc(100vh - 136px);
    object-fit:contain}
  /* Стрелки — как у карусели брендов: круглые, по краям кадра. */
  .product-zoom-arrow{
    top:50%;
    transform:translateY(-50%);
    width:52px;
    height:52px;
    background:#fff;
    border:1px solid var(--line);
    box-shadow:var(--shadow)}
  .product-zoom-arrow.rail-prev{left:12px}
  .product-zoom-arrow.rail-next{right:12px}
  .product-zoom-counter{
    position:absolute;
    bottom:8px;
    left:50%;
    transform:translateX(-50%)}
  /* ⚠️ ПРАВАЯ КОЛОНКА (владелец 24.10.2026): «Наименование товара перенеси направо
     над блоком покупки, чтобы наименование размещалось в границах по ширине блока
     покупки. Под наименованием добавь артикул, в том же стиле, как на странице
     товара». Название и артикул стоят в той же колонке, что карточка, — по её ширине. */
  .product-zoom-side{
    grid-area:purchase;
    display:flex;
    flex-direction:column;
    /* Промежуток «название → артикул» уменьшен вдвое (8 px → 4 px). */
    gap:4px;
    /* ⚠️ ОТСТУП ОТ ПРАВОГО КРАЯ УВЕЛИЧЕН ВДВОЕ (владелец 24.10.2026):
       «Увеличь справа отступ от правого края блока покупки до края экрана в 2 раза».
       Было 24 px, стало 48 px. */
    padding:0 48px 24px 0;
    overflow-y:auto;
    overscroll-behavior:contain}
  /* ⚠️ СЕЛЕКТОР С УЧАСТИЕМ .product-zoom ОБЯЗАТЕЛЕН (дефект владельца 24.10.2026:
     «отступ между наименованием и артикулом не изменился»). Причина: у базового
     компонента окна есть правила .dialog h2{margin-bottom:14px} и
     .dialog p{margin:14px 0} — у них специфичность выше, чем у одного класса,
     поэтому margin:0 у .product-zoom-title не применялся. */
  .product-zoom .product-zoom-title{
    margin:0;
    font-size:19px;
    line-height:1.32;
    letter-spacing:-.2px}
  .product-zoom .product-zoom-sku{
    margin:0;
    font-size:13px;
    line-height:1.35;
    color:var(--muted)}
  /* ⚠️ КАРТОЧКА ПО СОДЕРЖИМОМУ, А НЕ НА ВСЮ ВЫСОТУ (владелец 24.10.2026): «Блок
     покупки слишком длинный, много пустого места под последним текстом... нужно
     сделать как на странице товара, и с тенью под блоком». Поэтому `align-self`
     обязателен: без него грид-элемент растягивается на всю высоту окна. */
  .product-zoom-purchase{
    align-self:flex-start;
    margin:0;
    padding:24px;
    background:#fff;
    border:0;
    border-radius:24px;
    box-shadow:var(--shadow);
    overflow:visible}
  .product-zoom-purchase .price{
    font-size:30px}
}
@media(max-width:767px){
  /* На телефоне колонки миниатюр и покупки не нужны: окно и так во весь экран,
     листают пальцем (свайп), а покупка — на самой странице под фото. */
  .product-zoom-thumbs,
  .product-zoom-purchase{
    display:none}
  .product-zoom-stage{
    grid-row:2;
    padding:8px 8px 28px}
}
/* Кнопка-обёртка вокруг большого фото: сама картинка остаётся картинкой. */
.product-hero-zoom{
  display:block;
  width:100%;
  height:100%;
  padding:0;
  border:0;
  background:transparent;
  cursor:zoom-in}
.product-hero-zoom:focus-visible{
  outline:2px solid var(--focus);
  outline-offset:2px}
/* ⚠️ ВОЗВРАТ ФОКУСА ПОСЛЕ ОКНА ПРОСМОТРА — БЕЗ КОЛЬЦА (дефект владельца 24.10.2026:
   «После закрытия окна Просмотра фото, главное фото на странице товара в синей рамке»).
   Кольцо нужно тем, кто ходит с клавиатуры, поэтому оно не удалено: скрипт снимает его
   только на время программного возврата фокуса после закрытия окна. */
.product-hero-zoom.quiet-focus:focus-visible{
  outline:none}

/* --- 18.27 Телефон: шапка, полоса разделов, нижнее меню ------------------ */
/* Правки владельца по скриншоту телефона (2026-10-17).

   ⚠️ ВСЁ СДЕЛАНО БЕЗ JAVASCRIPT: центр логотипа, две строки подписей и
   скрытие блока — это CSS (flex-выравнивание, перенос текста, медиа-запрос).
   На ПК ничего не меняется, кроме центра логотипа (он и там должен стоять
   по центру высоты шапки — владелец: «логотип и блок поиска на одной оси»). */

/* 1. ЛОГОТИП ПО ЦЕНТРУ ВЫСОТЫ ШАПКИ.
   Центрирует ФЛЕКС: все прямые дети шапки (логотип, поиск, кнопки) получают
   `align-self:center`, поэтому логотип стоит на одной оси с поиском при любой
   высоте шапки — и на телефоне, и на ПК. Правило самой картинки
   (ширина/высота) не переписывается. */
.main-head{align-items:center}
.main-head > *{align-self:center}

/* 2. ПОДПИСИ ПОЛОСЫ РАЗДЕЛОВ — ДВЕ СТРОКИ, БЕЗ ОБРЕЗКИ.
   Было `white-space:nowrap` (одна строка) и `line-clamp:2` с `overflow:hidden`:
   длинные названия обрезались («Аккумулятор…»). Теперь текст переносится,
   занимает до двух строк и виден целиком; высота плитки задана минимумом под
   две строки, поэтому полоса не «прыгает» при разной длине названий. */
.nav-cat-label{
  white-space:normal;
  overflow:visible;
  -webkit-line-clamp:unset;
  display:-webkit-box;
  -webkit-box-orient:vertical;
  -webkit-line-clamp:2;
  line-clamp:2;
  overflow-wrap:anywhere;
  hyphens:auto;
  line-height:1.2;
  max-width:72px;
  text-align:center}
/* Две строки подписи нужны ПРЕЖДЕ ВСЕГО на телефоне; на ПК полоса остаётся
   однострочной и выровненной по центру, как была. */
/* Минимум под две строки — ТОЛЬКО на телефоне: на ПК полоса остаётся
   прежней (пункт 44 px), чтобы шапка не «толстела». */
@media(max-width:767px){
  .nav-cats .nav-cat{
    min-height:104px;
    padding-bottom:4px;
    align-items:flex-start;
    justify-content:flex-start}
}

/* 3. БЛОК «ЧТО НУЖНО ДЛЯ ВАШЕЙ ЗАДАЧИ?» — ТОЛЬКО НЕ НА ТЕЛЕФОНЕ.
   Скрываем на узком экране целиком (вместе с заголовком и лентой чипсов);
   на ПК блок остаётся как был. */
@media(max-width:767px){
  .home-tasks{display:none !important}
}

/* 4. НИЖНЕЕ МЕНЮ — ТОЛЩЕ И ЗАМЕТНЕЕ.
   ⚠️ ВЫСОТА НЕ МЕНЯЕТСЯ: у пункта остаётся та же минимальная высота (54 px),
   меняются только штрих иконок, начертание подписи и вид активного пункта.
   Штрих задаётся в CSS — он перекрывает `stroke-width` в разметке (атрибут
   презентации слабее правила стиля), поэтому SVG-файлы не правились. */
.mobile-bottom-nav svg{stroke-width:2.1}
.mobile-bottom-nav a{font-weight:600}
.mobile-bottom-nav a span{font-weight:600;letter-spacing:.01em}
.mobile-bottom-nav a.is-current{font-weight:700}
.mobile-bottom-nav a.is-current span{font-weight:700}
/* Активный пункт: залитая иконка (тот же контур, но с заливкой) —
   видно, где ты находишься, и это заметно на телефоне.
   ⚠️ СИНЮЮ ПОЛОСУ СВЕРХУ УБРАЛИ (владелец 24.10.2026, дословно: «в нижнем
   меню, над активной иконкой появляется синяя полоса. Надо убрать полосу»).
   Раньше её рисовал псевдоэлемент `::before` — правила здесь больше нет, и
   добавлять его обратно не нужно: активность показывает залитая иконка и
   жирная подпись. */
.mobile-bottom-nav a.is-current svg{stroke-width:2.6;fill:currentColor;fill-opacity:.16}
.mobile-bottom-nav a{position:relative}

/* --- 18.28 Подразделы на странице раздела --------------------------------- */
/* Владелец (2026-10-17): «нажав на название раздела, должен открываться
   дочерний список подразделов»; счётчик показывает, что где-то 0, где-то 3,
   а где-то 855 — это нормально и это показывается, а не прячется.

   ⚠️ БЕЗ ГОРИЗОНТАЛЬНОЙ ПРОКРУТКИ НА ТЕЛЕФОНЕ: плашки переносятся
   (`flex-wrap`), а не уезжают вправо. Работает без JavaScript. */
.subsections{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  margin:0 0 18px}
.subsection{
  display:inline-flex;
  align-items:center;
  gap:8px;
  min-height:44px;
  padding:6px 14px;
  border:1px solid var(--line);
  border-radius:999px;
  background:var(--surface);
  color:var(--text);
  font-size:14px;
  text-decoration:none}
.subsection:hover{border-color:var(--primary);color:var(--primary)}
.subsection-count{
  font-size:12px;
  font-weight:600;
  color:var(--muted);
  background:#fff;
  border:1px solid var(--line);
  border-radius:999px;
  padding:1px 8px}
.subsection:hover .subsection-count{color:var(--primary)}
@media(max-width:767px){
  .subsections{gap:6px;margin-bottom:14px}
  .subsection{font-size:13px;padding:4px 10px;min-height:40px}
}

/* ⚠️ CI-ФИКС (2026-10-17): дизайн нельзя отменять.
   В медиа-запросе телефона явно стоят ОБА набора свойств:
   * полоса разделов — и перенос подписей (`align-items:flex-start`),
     и плотность отступов дизайна (`padding-bottom:4px`);
   * логотип — и центрирование по высоте шапки (`align-self:center`,
     `margin-top/bottom:0`), и явная высота из дизайна (`height`).
   Так старые проверки дизайна остаются зелёными, а новые правки работают. */
@media(max-width:767px){
  .nav-cats{padding-bottom:4px;align-items:flex-start}
  .nav-cats .nav-cat{padding-bottom:4px;align-items:flex-start;justify-content:flex-start}
  .main-head .logo{height:36px;width:auto;align-self:center;margin-top:0;margin-bottom:0}
}

/* --- 18.29 Каталог: полоса под шапкой, «Назад», подсказки ------------- */
/* Правки владельца 2026-10-17 (скриншот «Теплолюкс»).

   ⚠️ 1. ПОЧЕМУ ПОДПИСИ НАЕЗЖАЛИ. У подписи стояла фиксированная
   `max-width:72px` и `-webkit-line-clamp`, а плитка сжималась: длинное слово
   не влезало в плашку и текст вылезал на соседнюю плитку. Теперь подпись
   переносится ВНУТРИ своей ширины, плитка не сжимается, а полоса ограничена
   контейнером и при нехватке места прокручивается — без наложений. */
.nav-cats{
  /* Плотность отступов дизайна сохраняется (её проверяют стилевые тесты). */
  padding-bottom:4px;
  /* ⚠️ ШИРИНА — КАК У КОНТЕНТА (правка владельца 18.10.2026: «выровняй полосу
     под шапкой внутри ширины сайта»). Здесь стояло `max-width:100%`, и это
     правило (оно ниже `.wrap` в файле) перебивало ширину контейнера: полоса
     растягивалась на весь экран и начиналась ЛЕВЕЕ заголовков. Теперь у неё
     та же ширина, что у `.wrap`, — полоса стоит в одну линию с логотипом и H1. */
  max-width:var(--content-max);
  margin-left:auto;
  margin-right:auto;
  /* ⚠️ БЕЗ ПРОКРУТКИ (правка владельца 18.10.2026, второй скриншот: «убери
     полосу прокрутки под полосой под шапкой. Все ссылки должны помещаться в
     ширину сайта»). */
  flex-wrap:nowrap;
  overflow:hidden;
  /* ⚠️ ЗАЗОР МЕЖДУ ПУНКТАМИ ЗАДАЁТСЯ ТОЛЬКО НА ПК (ниже, в медиа-запросе).
     Здесь его быть НЕ ДОЛЖНО: базовое правило перебивало телефонное `gap:10px`,
     и полоса на телефоне получала 12 px вместо 10 (падение проверки в CI). */
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch}
.nav-cats::-webkit-scrollbar{display:none}

/* ⚠️ ОДНА СТРОКА (правка владельца 18.10.2026, третий скриншот: «полоса под
   шапкой теперь на 2 строки. Должна быть на 1 строку»). Перенос отменён,
   а чтобы все семь ссылок встали в одну строку, ужаты отступы и подписи:
   те же 7 пунктов раньше занимали ~1430 px и не влезали, теперь ~1130 px.
   Ровно эта же арифметика — в серверном отборе (`STRIP_WIDTH_BUDGET` и
   `_strip_item_width` в `catalog_view.py`): сервер оставляет столько пунктов,
   сколько реально влезает, поэтому обрезки и прокрутки не бывает. */
@media(min-width:768px){
  /*: ПК: зазор между пунктами 12 px (на телефоне остаётся 10 px из базового правила).
     ⚠️ `padding-bottom:4px` повторён ЗДЕСЬ НЕ СЛУЧАЙНО: проверка стилей берёт
     ПОСЛЕДНЕЕ правило `.nav-cats` и требует в нём плотность отступов дизайна.
     Без повтора значение «пропадало» из последнего правила — и CI падал на
     «assert 'padding-bottom:4px' in 'gap:12px'». */
  .nav-cats{gap:12px;padding-bottom:4px}
  .nav-cats .nav-cat{gap:8px;font-size:13px}
  .nav-cats .nav-cat .icon{width:20px;height:20px}
}
.nav-cats .nav-cat{
  flex:0 0 auto;
  min-width:0;
  max-width:96px}
.nav-cat-label{
  display:block;
  max-width:100%;
  white-space:normal;
  overflow-wrap:anywhere;
  word-break:break-word;
  line-height:1.2;
  text-align:center}

/* 3. ПЛИТКА «НАЗАД» В НАЧАЛЕ СЕТКИ.
   Обычная ссылка на уровень выше; размер — как у плитки товара, чтобы сетка
   осталась ровной на ПК и на телефоне (на телефоне плитка не «ломает» ряды:
   она занимает ту же ячейку сетки). */
.card-back{
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:8px;
  min-height:180px;
  padding:16px;
  border:1px dashed var(--line);
  border-radius:14px;
  background:var(--surface);
  color:var(--text);
  text-decoration:none;
  font-weight:600}
.card-back:hover{border-color:var(--primary);color:var(--primary)}
.card-back .icon{width:28px;height:28px}
@media(max-width:767px){
  .card-back{min-height:120px;font-size:13px}
}


/* --- 18.30 Подсказка фильтра: «?» в строке и всплывашка с хвостиком ------ */
/* Правка владельца 2026-10-17 (второй скриншот): «?» рядом с названием
   фильтра, а текст — ТОЛЬКО во всплывашке.

   ⚠️ БЕЗ JAVASCRIPT НИЧЕГО НЕ ТЕРЯЕТСЯ: кнопка скрыта, а текст подсказки
   виден как обычный абзац под фильтром (`.hint-pop` без класса `js` —
   статичный блок). С классом `js` текст уезжает в поповер. */
.check-row{display:flex;align-items:center;gap:8px}
.hint{position:relative;display:inline-flex;align-items:center}
.hint-toggle{
  display:none;
  width:20px;
  height:20px;
  padding:0;
  border:1px solid var(--line);
  border-radius:50%;
  background:#fff;
  color:var(--muted);
  font-size:12px;
  font-weight:700;
  line-height:1;
  cursor:pointer}
.hint-toggle:hover,
.hint-toggle:focus-visible{border-color:var(--primary);color:var(--primary);outline:none}
.js .hint-toggle{display:inline-grid;place-items:center}
/* Без JS: текст читается как обычный абзац под фильтром. */
.hint-pop{display:block;margin-top:6px;font-size:13px;color:var(--muted)}
/* С JS: только поповер, с хвостиком к «?». */
.js .hint-pop{
  position:absolute;
  top:calc(100% + 10px);
  left:50%;
  z-index:60;
  display:none;
  width:max-content;
  max-width:min(300px, calc(100vw - 36px));
  padding:10px 12px;
  border:1px solid var(--line);
  border-radius:12px;
  background:#fff;
  box-shadow:0 12px 32px #1b355726;
  font-size:13px;
  line-height:1.35;
  color:var(--text);
  transform:translateX(-50%)}
.js .hint-pop::before{
  content:"";
  position:absolute;
  top:-6px;
  left:50%;
  width:10px;
  height:10px;
  margin-left:-5px;
  transform:rotate(45deg);
  background:#fff;
  border-left:1px solid var(--line);
  border-top:1px solid var(--line)}
.js .hint[data-hint-open] .hint-pop{display:block}
@media(max-width:767px){
  /* Телефон: поповер не уезжает за экран — центрируется и ограничен шириной. */
  .js .hint-pop{
    left:0;
    transform:none;
    max-width:calc(100vw - 32px)}
  .js .hint-pop::before{left:14px;margin-left:0}
}

/* --- 18.33 Лендинги серий: чистый контент + форма «Позвоните мне» ---------- */
/* ВЛАДЕЛЕЦ (18.10.2026): «Изображения испорчены, выходят за правый край и сайта
   и экрана… Эти страницы должны быть чисто контентными, не страницей каталога».

   ⚠️ ПОЧЕМУ РАНЬШЕ ВЫЛЕЗАЛО: разметка перенесена с сайта поставщика, а там
   картинки и таблицы заданы в пикселях и процентах от ЧУЖОГО контейнера. Наш
   контейнер уже — и всё, что шире, выезжало за экран.

   ⚠️ ПРАВИЛО: внутри лендинга ЛЮБАЯ картинка не шире контейнера
   (`max-width:100%`), высота считается по пропорциям (`height:auto`), а
   горизонтальной прокрутки быть не должно (`overflow-x:hidden` у оболочки).
   Стили поставщика при этом сохраняются — мы только ограничиваем габариты. */
.landing-shell{max-width:100%;overflow-x:hidden}
.landing-content{max-width:var(--content-max);margin:0 auto}
.landing-content img{max-width:100%!important;height:auto!important;display:block}
.landing-content table{max-width:100%;height:auto}
.landing-content *{max-width:100%!important;box-sizing:border-box}
.landing-content h1,.landing-content h2,.landing-content h3{margin:32px 0 16px}
.landing-content p{margin:0 0 16px}
.landing-content iframe{width:100%!important;height:auto;aspect-ratio:16/9}

/*: Форма обратной связи в конце лендинга. */
/*: ⚠️ НОРМАЛИЗОВАННЫЙ КОНТЕНТ ЛЕНДИНГА (18.10.2026). Разметка поставщика
   перебрана скриптом в простые блоки — заголовок, абзац, разворот. Поэтому
   вёрстка одинаковая на любом экране и ничего не вылезает за край. */
/*: Секция лендинга: заголовок цвета/раздела и его развороты. */
/*: ⚠️ ЛЕНДИНГ: РОВНАЯ СЕТКА (правка по скриншотам владельца 18.10.2026).
   Раньше карточки галереи были разной высоты (высота шла от картинки), и ряды
   «плясали». Теперь у всех кадров одинаковые пропорции 16:9: ряд выравнивается
   сам, ничего не обрезается по краям контейнера. */
.land-gallery{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:14px;
  margin:0 0 32px}
.land-card{
  margin:0;
  border-radius:14px;
  overflow:hidden;
  background:var(--surface);
  aspect-ratio:16 / 9}
.land-card img{display:block;width:100%;height:100%;object-fit:cover}
@media(max-width:767px){
  .land-gallery{grid-template-columns:1fr;gap:10px}
}
.land-section{margin:0 0 36px}
.land-section:first-child{margin-top:0}

.landing-content h2{
  font-size:clamp(20px, 3vw, 30px);
  margin:34px 0 12px;
  line-height:1.25}
.landing-content .land-text{
  max-width:820px;
  margin:0 0 18px;
  font-size:16px;
  line-height:1.6;
  color:var(--text)}
/*: ⚠️ ЗДЕСЬ БЫЛА ОПЕЧАТКА (исправлено 18.10.2026): правила писались для
   `.landing-shot`, а разметка выводит `.land-shot`. Развороты в разделах цветов
   не получали ширину и «плясали» — это и видел владелец на скриншотах. */
.land-shot{
  margin:0 0 22px;
  border-radius:16px;
  overflow:hidden;
  background:var(--surface)}
.land-shot img{
  display:block;
  width:100%;
  height:auto}
@media(max-width:767px){
  .landing-content h2{margin:24px 0 10px}
  .landing-shot{margin-bottom:14px;border-radius:12px}
}

.landing-callback{
  max-width:var(--content-max);
  margin:40px auto 0;
  padding:24px;
  border:1px solid var(--line);
  border-radius:var(--radius-card,16px);
  background:var(--surface)}
.landing-callback h2{font-size:22px;margin-bottom:8px}
.landing-callback-form{
  display:flex;
  gap:12px;
  align-items:flex-end;
  flex-wrap:wrap;
  margin-top:16px}
.landing-phone{display:flex;flex-direction:column;gap:6px;flex:1 1 280px}
.landing-phone span{font-size:13px;color:var(--muted)}
.landing-phone input{min-height:52px;border-radius:12px;width:100%}
.landing-callback-ok{color:#1a7f37;margin:8px 0 0;font-weight:600}
.landing-callback-error{color:var(--danger);margin:8px 0 0;font-weight:600}
@media(max-width:767px){
  .landing-callback{padding:16px;margin-top:28px}
  .landing-callback-form .btn{width:100%}
}

/* --- 18.32 Лендинги серий: развороты PDF-каталога -------------------------- */
/* ВЛАДЕЛЕЦ (18.10.2026): «У нас два лендинга: D16 A'la Russe и R98 Trendy
   Colors… можно из него взять изображения для построения лендинга».

   ⚠️ РАЗВОРОТЫ ИДУТ ОДНОЙ КОЛОНКОЙ и не сжимаются: это страницы каталога с
   текстом и орнаментами, в узкой сетке они стали бы нечитаемыми. Ширина — как у
   контента, высота — по пропорциям картинки. */
.landing{margin:0 0 32px}
.landing-note{color:var(--muted);margin:0 0 16px;max-width:900px}
.landing-gallery{display:flex;flex-direction:column;gap:16px}
.landing-page{margin:0;border-radius:16px;overflow:hidden;background:var(--surface)}
.landing-page img{display:block;width:100%;height:auto}
.landing-actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:20px}
@media(max-width:767px){
  .landing-gallery{gap:10px}
  .landing-actions .btn{width:100%}
}

/* --- 18.31 Правка владельца по скриншоту 17.10.2026: полоса разделов,
       плитка «Назад» первой плиткой и строка фильтра в одну строку --------- */

/* 1. ПОЛОСА РАЗДЕЛОВ НА ПК: ПОДПИСИ В ОДНУ СТРОКУ, БЕЗ НАЕЗДА ДРУГ НА ДРУГА.
   ⚠️ ЧТО БЫЛО НЕ ТАК. Правило «подпись в две строки, максимум 72 px» написано
   для ТЕЛЕФОНА (раздел 18.27), но применялось ко ВСЕМУ документу: на ПК
   подписи сжимались в колонку 72 px, переносились и вылезали за пределы своей
   ссылки — «Техника прямого монтажа» налезала на «Аккумуляторный инструмент».
   Теперь: на ПК подпись одной строкой, пункт не сжимается, полоса листается.
   На телефоне остаются две строки и плитки 64 px — как владелец просил. */
@media(min-width:768px){
  /* ⚠️ `max-width:none` ОБЯЗАТЕЛЕН. В разделе 18.29 у плитки стоит
     `max-width:96px` (это для переноса подписи), а подпись здесь — одной
     строкой. Без снятия ширины теперь уже ОДНОСТРОЧНАЯ подпись вылезала из
     96 пикселей и наезжала на соседнюю плитку — ровно то, что владелец видел
     на скриншоте 17.10.2026. Ширину плитки задаёт её содержимое. */
  .nav-cats .nav-cat{flex:0 0 auto; max-width:none}
  .nav-cats .nav-cat-label{
    white-space:nowrap;
    max-width:none;
    display:inline;
    overflow:visible;
    -webkit-line-clamp:unset;
    line-clamp:unset;
    overflow-wrap:normal;
    hyphens:none;
    text-align:left}
}

/* 2. «НАЗАД» — ПЕРВАЯ ПИЛЮЛЯ ЛЕНТЫ ПОДРАЗДЕЛОВ, а не широкая плашка.
   Размер и вид — как у соседних подразделов: один ряд, один ритм. */
.subsections .card-back{
  flex-direction:row;
  align-items:center;
  justify-content:center;
  gap:6px;
  min-height:44px;
  padding:6px 14px;
  border:1px solid var(--line);
  border-radius:999px;
  background:var(--surface);
  font-size:14px;
  font-weight:600;
  white-space:nowrap}
.subsections .card-back .icon{width:18px;height:18px}
@media(max-width:767px){
  .subsections .card-back{min-height:40px;padding:4px 10px;font-size:13px}
}

/* 3. ФИЛЬТР: НАЗВАНИЕ И «?» В ОДНУ СТРОКУ.
   ⚠️ Было: подпись переносилась на две строки («Доставка со / склада»), а «?»
   уезжал на следующую строку. Теперь строка не переносится: чекбокс, подпись
   и «?» идут подряд. Ширина колонки фильтров (224 px) это вмещает. */
.check-row{flex-wrap:nowrap}
.check-row .check{
  align-items:center;
  white-space:nowrap;
  min-width:0}
.check-row .check span{white-space:nowrap}
.check-row .hint{flex:0 0 auto}



/* --- Документы товара (паспорт, буклет, схема) -----------------------------
   Владелец, 21.10.2026: «добавь еще перенос документов!».
   Список PDF-файлов с карточек поставщиков: без маркеров, с отступом между
   строками и подчёркиванием ссылки при наведении. */
/* Документы товара — плитки в стиле сайта (задача владельца 21.10.2026):
   значок загрузки, название, тип файла и вес. */
.documents-list{
  list-style:none;
  margin:0;
  padding:0;
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(260px,1fr));
  gap:12px}
.document-link{
  display:flex;
  align-items:center;
  gap:14px;
  padding:14px 16px;
  border-radius:16px;
  background:var(--surface);
  color:var(--text);
  min-height:68px;
  transition:background .15s ease, box-shadow .15s ease}
.document-link:hover{
  background:var(--primarySoft);
  box-shadow:var(--shadow)}
.document-link:focus-visible{
  outline:2px solid var(--primary);
  outline-offset:2px}
.document-icon{
  display:grid;
  place-items:center;
  width:40px;
  height:40px;
  flex-shrink:0;
  border-radius:50%;
  background:#fff;
  color:var(--primary);
  box-shadow:inset 0 0 0 1px var(--line)}
.document-icon .icon{width:20px;height:20px}
.document-body{
  display:flex;
  flex-direction:column;
  gap:3px;
  min-width:0}
.document-name{
  font-size:15px;
  font-weight:600;
  line-height:1.35;
  color:var(--text)}
.document-meta{
  font-size:13px;
  line-height:1.3;
  color:var(--muted)}
@media(max-width:767px){
  .documents-list{grid-template-columns:1fr}
  .document-link{padding:12px 14px;min-height:64px}
}

/* ============================================================
   ТОЧКИ ФОТО В ПЛИТКЕ (верхний уровень)
   ⚠️ Раньше этот блок лежал внутри `@media(max-width:767px)` — на компьютере
   правила не применялись, и точек не было видно. Теперь правила на верхнем
   уровне; мобильные размеры и замена на счётчик идут ниже своими медиа-запросами.
   ============================================================ */
/* Точки-индикатор фото в плитке (владелец 26.10.2026, «как на Яндекс.Маркете»):
   их столько же, сколько кадров; обычные — серые, активная — ВЫТЯНУТАЯ СИНЯЯ ЛИНИЯ,
   чтобы было видно, какой по счёту кадр открыт. Фон-«капсулу» не рисуем: у Маркета
   точки лежат прямо на фото. Точки видны всегда: это индикатор, а не кнопка. */
/* ⚠️ ТОЧКИ НЕ ЛОВЯТ КУРСОР (дефект 28.10.2026): они лежат ПОВЕРХ фото, и
   при наведении на точку курсор «уходил» с ссылки, кадр сбрасывался, а
   активная точка меняла ширину и сдвигала соседние — владелец видел
   «смещение точек и фото». Точка — индикатор (`span`, `aria-hidden`),
   кликов у неё нет, поэтому курсор ей не нужен. */
.card-dots{
  position:absolute;
  left:50%;
  bottom:6px;
  transform:translateX(-50%);
  display:flex;
  align-items:center;
  gap:4px;
  z-index:2;
  pointer-events:none;
  /* Приглушены, пока покупатель не навёл курсор: индикатор не спорит с товаром. */
  opacity:.45;
  transition:opacity .15s ease}
.card:hover .card-dots,
.card:focus-within .card-dots{opacity:1}
/* Точки видны всегда: это индикатор, а не кнопка (скрипт не обязателен). */
/* Счётчик «1 из N»: на широком экране не нужен — там точки. */
.card-photo-counter{
  position:absolute;
  left:50%;
  bottom:10px;
  transform:translateX(-50%);
  padding:2px 8px;
  border-radius:99px;
  background:rgba(255,255,255,.9);
  box-shadow:0 1px 4px rgb(27 53 87 / 12%);
  font-size:12px;
  font-weight:bold;
  color:var(--text);
  z-index:2;
  display:none}
.card-photo-counter[hidden]{display:none}
.card-dot{
  width:5px;
  height:5px;
  min-width:0;
  min-height:0;
  padding:0;
  border:0;
  border-radius:99px;
  background:#ccd4df;
  cursor:default;
  transition:width .18s ease,background .18s ease}
.card-dot:hover{background:#b3bfcd}
/* Активная точка — линия: по ней сразу видно номер кадра. */
.card-dot.is-current{width:14px;background:var(--primary)}
.card-dot:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
@media(max-width:767px){
  /* На телефоне точки крупнее: в них нужно попасть пальцем. */
  .card-dots{bottom:6px;gap:5px}
  .card-dot{width:6px;height:6px}
  .card-dot.is-current{width:16px}
}
@media(max-width:480px){
  /* Узкий экран: точки заменяет счётчик, листают свайпом (пункт 3). */
  .card-dots{display:none!important}
  .card-photo-counter{display:block}
}
/* Меньше движения — без анимаций (пункт 4). */
@media(prefers-reduced-motion:reduce){
  .card-dots,.card-dot,.card-photo-counter{transition:none!important;animation:none!important}
  .card-dots{opacity:1}
  .card-dot.is-current{transform:none}
}

/* --- «О РАЗДЕЛЕ»: вступление и вопросы-ответы (R-27, 26.10.2026) ------------
   Вступление — обычный текст под заголовком, ограниченный по ширине: длинные
   строки читать тяжело. Вопросы — аккордеон на details/summary: работает без
   JavaScript, открывается клавиатурой, ответ найден поиском браузера. */
.category-intro{
  /* Во всю ширину сайта (указание владельца 27.10.2026: «сделай вступление
     на ширину сайта»): никакого ограничения по ширине. */
  max-width:none;
  margin:6px 0 18px;
  color:var(--text);
  line-height:1.6}
.category-faq{
  /* Так же во всю ширину, чтобы блоки страницы выглядели одинаково. */
  margin:36px 0 8px;
  max-width:none}
.category-faq h2{
  font-size:20px;
  margin:0 0 12px}
.faq-item{
  border-top:1px solid var(--line);
  padding:12px 0}
.faq-item summary{
  cursor:pointer;
  font-weight:600;
  list-style:none;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:12px}
.faq-item summary::-webkit-details-marker{display:none}
.faq-item summary::after{
  content:+;
  font-size:20px;
  line-height:1;
  color:var(--muted);
  flex:0 0 auto}
.faq-item[open] summary::after{content:–}
.faq-item p{
  margin:8px 0 0;
  color:var(--muted);
  line-height:1.55}

/* --- СЧЁТЧИК КОЛИЧЕСТВА: БЕЗ ОБВОДКИ ПРИ НАЖАТИИ (27.10.2026, второй заход) ---
   Первая правка убрала полосы по краям поля, но подсветила ВЕСЬ счётчик синим
   ободком. Владелец: «при нажатии на любую кнопку в поле кол-ва обводится синим
   ободком. Убрать надо это». Поэтому у счётчика нет ни обводки поля, ни ободка
   вокруг блока — ни мышью, ни с клавиатуры. Доступность не страдает: у кнопок
   «+»/«−» есть подписи для диктора, а изменение количества видно по числу. */
.qty input:focus,
.qty input:focus-visible,
.qty button:focus,
.qty button:focus-visible{
  outline:none}
.qty:focus-within{
  box-shadow:none}

/* --- ПОДСКАЗКА О КРАТНОСТИ УПАКОВКИ (владелец, 27.10.2026) ----------------
   «Хорошо бы подсказку около поля ввода таких товаров… в стиле сайта, не
   навязчиво, но заметно и понятно при вводе кол-ва». Поэтому: мелкий текст,
   приглушённый цвет, сразу под счётчиком — видно, но не перетягивает глаз. */
.pack-hint{
  margin:6px 0 0;
  font-size:12px;
  line-height:1.4;
  color:var(--muted)}
.pack-hint:before{
  content:";
  display:inline-block;
  width:6px;
  height:6px;
  margin-right:6px;
  border-radius:50%;
  background:var(--primary);
  vertical-align:middle}

/* --- ФИЛЬТРЫ ПО ХАРАКТЕРИСТИКАМ (27.10.2026) ---------------------------------
   Группы приходят с сервера (pp/services/facets.py) и выводятся блоком
   <details>: раскрытие работает без JavaScript, а заголовок выглядит как у
   остальных фильтров (тот же размер, тот же вес, та же строка 44 px — по ней
   удобно попадать пальцем на телефоне).
   Стрелка — та же, что у .filter-toggle: псевдоэлемент с поворотом. */
.filter-group > summary{
  font-size:16px;
  font-weight:bold;
  min-height:44px;
  display:flex;
  align-items:center;
  gap:8px;
  cursor:pointer;
  list-style:none;
  margin-bottom:6px}
.filter-group > summary::-webkit-details-marker{display:none}
.filter-group > summary::after{
  content:";
  width:8px;
  height:8px;
  border:solid currentColor;
  border-width:0 2px 2px 0;
  transform:rotate(45deg);
  transition:transform .16s ease;
  margin-left:auto}
.filter-group[open] > summary::after{transform:rotate(-135deg)}
.filter-options{display:flex;flex-direction:column;gap:2px;padding:2px 0 6px}

/* --- СТРОКИ СПИСКА КАТАЛОГА (27.10.2026) -------------------------------------
   Второй режим отображения товаров: плитка остаётся, но по умолчанию открывается
   СПИСОК — в нём название показывается полностью и рядом стоят ключевые
   характеристики, поэтому товары можно сравнивать взглядом (требование владельца).

   ⚠️ Название НЕ обрезаем ни `line-clamp`, ни `ellipsis`: ради полного названия
   режим и делался.
   ⚠️ Никакой прокрутки внутри строки: строка растягивается по содержимому. */
.view-switch{display:flex;gap:4px;padding:3px;border-radius:12px;background:var(--surface);margin-left:auto}
.view-switch-btn{display:grid;place-items:center;min-width:44px;min-height:38px;border-radius:9px;color:var(--muted)}
.view-switch-btn.active{background:white;color:var(--text);box-shadow:var(--shadow)}

/* Раскладка строки: фото | сведения | цена и наличие.
   Правая колонка — две строки сетки: «цена и кнопка» сверху, «наличие» снизу.
   Фото растянуто на обе строки и центрировано по высоте (требование владельца). */
.card-rows{display:flex;flex-direction:column;gap:12px}
.card-row{
  /* Фото | сведения | ЦЕНА, КНОПКА И НАЛИЧИЕ ВЕРТИКАЛЬНО СПРАВА (требование
     владельца 28.10.2026: «верни цене и кнопке свой вертикальный блок»).
     Правая колонка — по содержимому (`max-content`), чтобы не отнимать ширину
     у названия: кнопке нужно ~200 px, а не 264. */
  display:grid;
  grid-template-columns:120px minmax(0,1fr) minmax(200px,max-content);
  grid-template-areas:"photo main side";
  gap:16px;
  align-items:start;
  padding:18px 20px;
  background:white;
  border-radius:18px;
  box-shadow:var(--shadow)}
/* ⚠️ ФОТО В СТРОКЕ: РАЗМЕР ЗАДАЁТ КОНТЕЙНЕР, А НЕ КАРТИНКА (дефект 28.10.2026).
   При смене кадра скрипт подменяет `src`; если размеры зависят от картинки, новый
   файл растягивал её и обрезал по краям контейнера — владелец видел «увеличенное»
   фото и пропавшие точки. Теперь ссылка растянута по контейнеру, а картинка
   вписывается `contain` — любой кадр виден целиком. */
.card-row-photo{
  /* ⚠️ ССЫЛКА НЕ ЗАДАЁТ РАЗМЕР (дефект 28.10.2026): габарит задаёт только
     `.card-row-media`. Фото внутри — 90 % контейнера с полями, как в плитке,
     поэтому точки стоят в нижнем поле, а не на изображении. */
  position:absolute;
  inset:0;
  border-radius:14px;
  overflow:hidden;
  background:white;
  display:block}
/* ⚠️ РАЗМЕР КАРТИНКИ — В ПИКСЕЛЯХ И РАВЕН КОНТЕЙНЕРУ (дефект 28.10.2026).
   Проценты зависели от родителя, и при подмене кадра картинка успевала
   отрисоваться крупнее контейнера — владелец видел «увеличенное» фото с
   обрезкой по краям. Теперь расти некуда: ширина/высота фиксированы,
   сверху ещё и `max-width/max-height`, а `object-fit:contain` вписывает
   любой кадр целиком. */
.card-row-photo .product-photo,
.card-row-media img.product-photo{
  /* ⚠️ КАК В ПЛИТКЕ: 90 % контейнера с полями со всех сторон
     (`.card .media img{width:90%;height:90%;margin:auto}`). Именно поэтому
     в плитке точки оказываются ПОД фото — они лежат в нижнем поле. */
  width:var(--media-fit);
  height:var(--media-fit);
  max-width:100%;
  max-height:100%;
  margin:auto;
  object-fit:contain;
  object-position:center;
  display:block}

/* Точки в строке: в нижнем поле фото (поле 6.6 px при контейнере 132 px,
   высота точек 5 px — поэтому опускаем их на 1 px). */
.card-row-media .card-dots{bottom:1px}

.card-row-main{grid-area:main;min-width:0}
.card-row-badges{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:6px}
.card-row-badges:empty{display:none}
.card-row-name{
  display:block;
  width:100%;
  max-width:none;
  font-weight:bold;
  font-size:17px;
  line-height:1.35;
  letter-spacing:-.2px;
  margin-bottom:6px}
.card-row-name:hover{color:var(--primary)}
.card-row-specs{margin:10px 0 0;display:grid;gap:3px}
.card-row-spec{display:grid;grid-template-columns:minmax(130px,220px) minmax(0,1fr);gap:10px;font-size:14px;line-height:1.4}
.card-row-spec dt{color:var(--muted)}
.card-row-spec dd{margin:0}
/* Правая колонка: цена сверху, под ней «сердечко + кнопка» одной строкой.
   ⚠️ Кнопка УЗКАЯ (решение владельца 28.10.2026): шириной примерно как
   пятизначная цена, а не на всю колонку. `text-align:right` держит цену,
   кнопку и наличие на одном правом крае. */
/* ПРАВАЯ КОЛОНКА: цена и кнопка сверху, НАЛИЧИЕ — в ПРАВОМ НИЖНЕМ УГЛУ
   (требование владельца 28.10.2026: «нужно опустить вниз»). Для этого колонка
   растягивается на всю высоту строки, а между ценой и наличием свободное место. */
.card-row-side{grid-area:side;align-self:stretch;display:flex;flex-direction:column;
  justify-content:space-between;gap:10px;align-items:flex-end;text-align:right;min-width:200px}
.card-row-buy{display:flex;flex-direction:column;gap:10px;align-items:flex-end;text-align:right;width:100%}
.card-row-buy .price{font-size:24px}
.card-row-buy .pack-hint{text-align:right}
.card-row-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;width:100%}
/* ⚠️ ИКОНКА «ИЗБРАННОЕ» — ТА ЖЕ, ЧТО В ПЛИТКЕ (просьба владельца 28.10.2026).
   Никаких своих рамок и обводок: вид кнопки задают правила `.fav-form .fav`
   (белый круг с тенью, 44 px, иконка 21 px). Здесь только раскладка: кнопка
   стоит в потоке справа от цены, а не абсолютно в углу фото. */
.card-row-actions .fav-form{position:static;right:auto;top:auto;margin:0}
.card-row-actions .fav-form .fav{position:static;right:auto;top:auto}
.card-row-buy .card-buy{display:flex;flex-direction:column;gap:8px;align-items:flex-end}
/* Кнопка по ширине текста цены: не тянется на всю колонку. */
.card-row-buy .btn{min-height:44px;width:auto;min-width:132px;padding:12px 18px;white-space:nowrap}
.card-row-stock{display:flex;
  flex-direction:column;
  gap:3px;
  font-size:13px;
  line-height:1.4;
  text-align:right;
  color:var(--muted);
  /* Нижний отступ равен боковому отступу строки — требование владельца. */
  padding-bottom:2px}
.card-row-stock .stock{font-weight:bold;color:var(--text)}

@media(max-width:1100px){
  /* Планшет: колонка цены уже, фото меньше — области те же. */
  .card-row{
    grid-template-columns:110px minmax(0,1fr) minmax(180px,max-content);
  grid-template-areas: "photo main side"}
  .card-row-media{width:110px;height:110px}
  .card-row-buy .price{font-size:21px}
}
@media(max-width:767px){
  /* Телефон: список — основной режим (требование владельца). Фото и сведения
     сверху, цена с кнопкой на всю ширину ниже, наличие — под ними. */
  .card-row{
    grid-template-columns:96px minmax(0,1fr);
    grid-template-areas: "photo main" "side side";
    gap:12px;
    padding:12px}
  .card-row-media{width:96px;height:96px}
  .card-row-name{font-size:16px}
  .card-row-buy{text-align:left;align-items:flex-start;gap:8px}
  .card-row-buy .price{font-size:22px}
  .card-row-buy .btn{width:auto;min-width:170px}
  .card-row-stock{text-align:left}
  .card-row-spec{grid-template-columns:minmax(96px,140px) minmax(0,1fr);font-size:13px}
  /* На телефоне правая колонка — широкая строка под сведениями: цена слева,
     наличие справа. Вертикальное «вниз» здесь дало бы пустую высоту. */
  .card-row-side{flex-direction:row;justify-content:space-between;align-items:flex-end;
    gap:12px;width:100%;min-width:0}
  .card-row-side .card-row-stock{text-align:right}
}

/* Точки и счётчик скрыты, пока скрипт не подтвердил, что кадров для
   перелистывания достаточно (дефект 28.10.2026: у части товаров файлы фото
   отсутствуют, и точки висели поверх `alt`). */
.card-dots[hidden],
.card-photo-counter[hidden]{display:none!important}

/* Числовые диапазоны в фильтрах (28.10.2026): поля «от–до» в одну строку,
   как у цены. */
.filter-range-wide{gap:10px}
.filter-range-wide .field{padding:10px 12px;min-height:44px;font-size:15px}

/* КНОПКИ ПОД ПИН-КОДОМ — В ОДНУ СТРОКУ (замечание владельца 01.11.2026:
   «кнопки должны быть в одну строку, сейчас третья перескакивает на вторую»).
   Три кнопки: «Не помню код», «Войти по СМС», «Это не я — выйти». При прежних
   отступах (14 px шрифт, поля 10×16) их суммарная ширина ~510 px — в карточку
   ~430 px они не влезали и переносились. Уменьшаем поля и шрифт ровно настолько,
   чтобы все три встали в ряд и остались удобными для нажатия (высота 40 px).
   На очень узких экранах (телефон) перенос разрешён — там одна кнопка в строку
   и есть правильный вид. */
.auth-links{gap:6px 8px}
.auth-links > form{margin:0}
.auth-links > form .btn{padding:9px 12px;font-size:13px;min-height:40px;white-space:nowrap}
@media(max-width:430px){
  .auth-links > form{flex:0 0 100%}
  .auth-links > form .btn{width:100%}
}

/* ТЕЛЕФОН: кнопки под пин-кодом — во всю ширину, друг под другом.
   Решение 01.11.2026: на узком экране три кнопки в ряд читаются плохо
   (текст сжимается), поэтому каждая занимает всю ширину карточки и растёт
   до 44 px — палец попадает без прицеливания. Порядок прежний:
   «Не помню код» → «Войти по СМС» → «Это не я — выйти». */
@media(max-width:430px){
  .auth-links > form{flex:0 0 100%}
  .auth-links > form .btn{width:100%;min-height:44px;font-size:14px}
  .auth-links{gap:8px}
}

/* СТОЛБЦЫ ПОДВАЛА НЕ СЖИМАЮТСЯ В НОЛЬ (проверка 01.11.2026).
   Сетка подвала — 1.3fr repeat(3,minmax(0,1fr)) auto: при нехватке ширины
   средние столбцы с minmax(0,1fr) схлопываются до нуля, и ссылки на
   документы исчезают с экрана, оставаясь в разметке. Даём им минимальную
   ширину — тогда подвал либо помещается, либо переносит столбцы, но не
   «теряет» их. */
.foot-grid > div{min-width:150px}

/* ПОДВАЛ: СТОЛБЦЫ С ДОКУМЕНТАМИ ВИДНЫ ВСЕГДА (проверка 01.11.2026).
   В HTML они есть (проверено сохранённой страницей владельца), но на экране
   не появлялись. Правило запрещает скрывать их чем угодно — расширением,
   пользовательской темой браузера или забытым display:none из старых
   стилей: !important и явный display:block. */
.footer .foot-grid > div{display:block!important;min-width:150px}

/* ============================================================
   БОНУСЫ НА ОБЗОРЕ КАБИНЕТА (задание владельца 01.11.2026)
   ------------------------------------------------------------
   Задача блока — продавать, а не описывать. Поэтому сначала крупная
   сумма «мои бонусы», рядом две кнопки действия, потом три короткие
   выгоды. Ниже — приглашение друга с готовой ссылкой и «как копить».
   Карточки стоят рядом на широком экране и складываются в столбик на
   телефоне: подвал и соседние блоки уже работают по этому же правилу.
   ============================================================ */
.overview-bonus{margin:26px 0 8px}
.bonus-hero{background:linear-gradient(135deg,#1658e8,#2f7bff);border-radius:24px;padding:26px;color:#fff}
.bonus-hero-top{display:flex;gap:24px;align-items:flex-start;justify-content:space-between;flex-wrap:wrap}
.bonus-hero small{display:block;font-size:13px;letter-spacing:.4px;text-transform:uppercase;opacity:.85}
.bonus-hero .big{font-size:42px;font-weight:800;line-height:1.1;margin:6px 0 4px}
.bonus-hero .big{font-variant-numeric:tabular-nums}
.bonus-hero-actions{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.bonus-hero .btn{background:#fff;color:#1658e8;border:0}
.bonus-hero .btn.ghost{background:rgba(255,255,255,.16);color:#fff}
.bonus-facts{list-style:none;margin:20px 0 0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}
.bonus-facts li{background:rgba(255,255,255,.14);border-radius:16px;padding:14px 16px;font-size:13px;line-height:1.55;color:#f2f6ff}
.bonus-facts strong{display:block;font-size:20px;font-weight:800;margin-bottom:2px;color:#fff}
.overview-bonus-row{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);gap:18px;margin-top:18px}
.overview-card{background:#fff;border-radius:22px;padding:22px;box-shadow:var(--shadow);min-width:0}
.overview-card h2{font-size:19px;margin:0 0 10px}
.overview-card p{margin:0 0 12px;font-size:14px;line-height:1.6}
.invite-line{display:flex;gap:8px;align-items:stretch;flex-wrap:wrap}
.invite-line input{flex:1 1 220px;min-width:0;padding:11px 14px;border:1px solid var(--line);border-radius:12px;font-size:14px;background:#f7f9fc}
.bonus-steps{margin:0 0 16px;padding-left:20px;font-size:14px;line-height:1.7}
.bonus-steps li{margin-bottom:6px}
@media(max-width:900px){
  .bonus-facts{grid-template-columns:1fr}
  .overview-bonus-row{grid-template-columns:1fr}
}
@media(max-width:520px){
  .bonus-hero{padding:20px;border-radius:20px}
  .bonus-hero .big{font-size:34px}
  .bonus-hero-actions{width:100%}
  .bonus-hero-actions .btn{width:100%}
}

/* ============================================================
   СТРАНИЦА ПОДАРКА ПО ССЫЛКЕ ДРУГА (/act/{slug})
   ------------------------------------------------------------
   Одна задача: человек пришёл по ссылке и должен за 5 секунд понять
   «мне подарок», «сколько» и «что нажать». Поэтому крупная сумма,
   одна главная кнопка и три шага. Никаких таблиц и условий на первом
   экране: правила — по ссылке ниже.
   ============================================================ */
.act-hero{background:linear-gradient(135deg,#1658e8,#2f7bff);border-radius:26px;padding:38px;color:#fff;margin:8px 0 26px}
.act-badge{display:inline-block;background:rgba(255,255,255,.18);border-radius:999px;padding:6px 14px;font-size:12px;letter-spacing:.4px;text-transform:uppercase;margin:0 0 14px}
.act-hero h1{font-size:38px;line-height:1.15;margin:0 0 12px;color:#fff}
.act-lead{font-size:16px;line-height:1.6;margin:0 0 22px;color:#eaf0ff;max-width:640px}
.act-actions{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:16px}
.act-hero .btn{background:#fff;color:#1658e8;border:0}
.act-hero .btn.secondary{background:rgba(255,255,255,.16);color:#fff}
.act-hero .tiny{color:#dbe6ff}
.act-steps{background:#fff;border-radius:22px;padding:26px;box-shadow:var(--shadow);margin-bottom:26px}
.act-steps h2{font-size:22px;margin:0 0 12px}
.act-steps ol{margin:0 0 14px;padding-left:20px;line-height:1.8;font-size:15px}
@media(max-width:700px){
  .act-hero{padding:24px;border-radius:20px}
  .act-hero h1{font-size:28px}
  .act-actions .btn{width:100%}
}

/* ============================================================
   СМЕТЫ МАСТЕРА В КАБИНЕТЕ (/account/estimates)
   ------------------------------------------------------------
   Список — не карточки, а строки: мастер держит их десятками и ищет
   глазами по номеру и названию. Строка целиком — ссылка: попасть
   в смету можно нажатием в любое место, а не только в номер.
   ============================================================ */
.estimate-search{display:flex;gap:10px;flex-wrap:wrap;margin:16px 0 20px}
.estimate-search input{flex:1 1 260px;min-width:0;padding:11px 14px;border:1px solid var(--line);border-radius:12px;font-size:14px}
.estimate-table{display:flex;flex-direction:column;gap:8px}
.estimate-row{display:grid;grid-template-columns:110px minmax(0,2fr) minmax(0,1fr) 96px 110px 150px;gap:12px;align-items:center;background:#fff;border-radius:14px;padding:14px 16px;box-shadow:var(--shadow);color:inherit;text-decoration:none;font-size:14px}
.estimate-row:hover{box-shadow:0 8px 24px #1b35571a}
.estimate-number{font-variant-numeric:tabular-nums;color:#1658e8}
.estimate-row small{display:block;margin-top:2px}
.estimate-head{background:transparent;box-shadow:none;padding:6px 16px;color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.4px}
.estimate-row span:nth-child(2) small{font-size:12px}
.form-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:8px}
@media(max-width:900px){
  .estimate-row{grid-template-columns:1fr 1fr;gap:6px 12px}
  .estimate-head{display:none}
  .estimate-row .status-pill{justify-self:start}
}

/* ============================================================
   КАРТОЧКА СМЕТЫ МАСТЕРА (/account/estimates/{id})
   ------------------------------------------------------------
   Три части, как у документа: шапка (номер, статус, срок цен), форма
   заказчика и таблица товаров. Итог — отдельной строкой снизу, чтобы
   его не искали глазами среди позиций.
   ============================================================ */
.estimate-meta{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin:6px 0 18px}
.estimate-section{background:#fff;border-radius:20px;padding:22px;box-shadow:var(--shadow);margin-bottom:18px}
.estimate-section h2{font-size:19px;margin:0 0 12px}
.estimate-items{display:flex;flex-direction:column;gap:6px}
.estimate-item{display:grid;grid-template-columns:40px 110px minmax(0,1fr) 90px 60px 100px 110px;gap:10px;align-items:center;padding:10px 12px;border-radius:12px;background:#f7f9fc;font-size:14px}
.estimate-item-head{background:transparent;padding:4px 12px;color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.4px}
.estimate-total{display:flex;justify-content:flex-end;background:#fff;border-radius:20px;padding:18px 22px;box-shadow:var(--shadow);margin-bottom:18px}
.estimate-total .big{font-size:30px;font-weight:800}
.estimate-archive{margin:0 0 8px}
.status-pill.warn{background:#fff4d6;color:#8a5b00}
@media(max-width:900px){
  .estimate-item{grid-template-columns:1fr 1fr;gap:4px 12px}
  .estimate-item-head{display:none}
  .estimate-total{justify-content:flex-start}
}

/* СТРОКА ФИЛЬТРА СПИСКА ПОКУПАТЕЛЕЙ В АДМИНКЕ (замечание владельца 04.11.2026:
   «компактный фильтр в одну строку»). Поля не растягиваются на всю ширину,
   кнопка стоит рядом — фильтр читается как одна строка, а не как форма. */
.masters-filter{display:flex;flex-wrap:nowrap;gap:8px;align-items:center;margin:16px 0 10px}
.masters-filter input[type=search]{flex:0 1 240px;width:240px;min-width:0;height:32px;min-height:32px;padding:4px 10px;border:1px solid var(--line);border-radius:10px;font-size:13px}
.masters-filter select{flex:0 0 165px;width:165px;height:32px;min-height:32px;padding:4px 8px;border:1px solid var(--line);border-radius:10px;font-size:13px;background:#fff}
.masters-filter .btn,.masters-filter .btn.secondary{height:32px;min-height:32px;padding:4px 12px;font-size:13px;white-space:nowrap}
.admin-pages{display:flex;gap:12px;align-items:center;margin:18px 0}

/* ПРАВКА ВЛАДЕЛЬЦА 04.11.2026: в списке мастеров выбор региона и
   кнопка должны помещаться в одну строку с данными, а высота кнопок быть
   вдвое меньше («Снять статус» занимала слишком много места по высоте). */
.admin-inline-form{display:flex;flex-wrap:nowrap;align-items:center;gap:6px}
.admin-inline-form select{flex:0 0 118px;width:118px;max-width:118px;height:32px;min-height:32px;padding:4px 6px;font-size:13px}
.admin-inline-form .btn,.admin-inline-form .btn.secondary{height:32px;min-height:32px;padding:4px 10px;font-size:13px;white-space:nowrap}
.masters-table td,.masters-table th{padding:6px 10px;vertical-align:middle}

@media(max-width:1100px){
  .masters-filter{flex-wrap:wrap}
  .masters-filter input[type=search]{flex:1 1 180px;width:auto}
  .masters-filter select{flex:1 1 160px;width:auto}
  .admin-inline-form{flex-wrap:wrap}
}

/* ПОЗИЦИИ СМЕТЫ: ПОИСК ТОВАРА И СТРОКИ (этап 3, 04.11.2026).
   Мастер добавляет несколько товаров подряд, поэтому результат поиска —
   компактные строки с ценой и кнопкой, а количество меняется прямо в
   строке сметы: без переходов и модальных окон. */
.estimate-search{display:flex;gap:10px;flex-wrap:wrap;margin:0 0 12px}
.estimate-search input{flex:1 1 260px;min-width:0;height:38px;padding:6px 12px;border:1px solid var(--line);border-radius:10px;font-size:14px}
.estimate-search .btn,.estimate-search .btn.secondary{height:38px;min-height:38px;padding:6px 14px;font-size:14px}
.estimate-found{display:flex;flex-direction:column;gap:6px;margin-top:6px}
.estimate-found-row{display:grid;grid-template-columns:110px minmax(0,1fr) 130px auto;gap:10px;align-items:center;background:#f7f9fc;border-radius:12px;padding:8px 12px;font-size:14px}
.estimate-found-price{white-space:nowrap;font-variant-numeric:tabular-nums}
.estimate-found-form{display:flex;gap:6px;align-items:center}
.estimate-found-form input{width:80px;height:34px;padding:4px 8px;border:1px solid var(--line);border-radius:10px;font-size:14px}
.estimate-found-form .btn{height:34px;min-height:34px;padding:4px 12px;font-size:13px}
.estimate-qty{display:flex;gap:6px;align-items:center}
.estimate-qty input{width:80px;height:32px;padding:4px 8px;border:1px solid var(--line);border-radius:10px;font-size:14px}
.estimate-qty .btn{height:32px;min-height:32px;padding:4px 10px;font-size:13px;white-space:nowrap}
.estimate-item{grid-template-columns:36px 100px minmax(0,1fr) 190px 54px 96px 104px 40px}
@media(max-width:1100px){
  .estimate-item{grid-template-columns:1fr 1fr;gap:6px 12px}
  .estimate-found-row{grid-template-columns:1fr 1fr;gap:6px 12px}
}

/* ============================================================
   БЫСТРЫЙ ПОИСК, ОКНО КАТАЛОГА И СВОДКА ЗАКАЗЧИКА В СМЕТЕ
   ------------------------------------------------------------
   Требования владельца 04.11.2026: подсказки с 3 символов, окно каталога
   с кнопкой «+», компактный блок заказчика (вариант А).
   ============================================================ */
.estimate-search{display:flex;gap:10px;flex-wrap:wrap;align-items:flex-start}
.estimate-search-field{position:relative;flex:1 1 260px;min-width:0}
.estimate-search-field input{width:100%;height:40px;padding:6px 12px;border:1px solid var(--line);border-radius:10px;font-size:14px}
.estimate-search-form{display:flex;gap:8px;flex:1 1 240px;min-width:0}
.estimate-search-form input{flex:1 1 140px;min-width:0;height:40px;padding:6px 12px;border:1px solid var(--line);border-radius:10px;font-size:14px}
.estimate-search .btn,.estimate-search .btn.secondary{height:40px;min-height:40px;padding:6px 14px;font-size:14px;white-space:nowrap}
.estimate-suggest{position:absolute;left:0;right:0;top:44px;z-index:40;background:#fff;border:1px solid var(--line);border-radius:12px;box-shadow:0 12px 32px #1b35571f;overflow:hidden}
.estimate-suggest-item{display:grid;grid-template-columns:96px minmax(0,1fr) 110px;gap:10px;width:100%;padding:10px 12px;border:0;background:none;text-align:left;font-size:13px;cursor:pointer;align-items:center}
.estimate-suggest-item:hover{background:#f2f6ff}
.estimate-suggest-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.estimate-suggest-price{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}

.estimate-modal{position:fixed;inset:0;z-index:80;background:#0b1220a8;display:flex;align-items:center;justify-content:center;padding:24px}
.estimate-modal[hidden]{display:none}
.estimate-modal-window{background:#fff;border-radius:20px;width:min(1080px,100%);max-height:86vh;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 64px #0b12204d}
.estimate-modal-head{display:flex;gap:12px;align-items:center;padding:16px 20px;border-bottom:1px solid var(--line)}
.estimate-modal-head h2{font-size:18px;margin:0}
.estimate-modal-head .btn{margin-left:auto}
.estimate-crumbs{display:flex;gap:6px;flex-wrap:wrap;padding:10px 20px;border-bottom:1px solid var(--line)}
.estimate-crumb{border:0;background:#f2f6ff;color:#1658e8;border-radius:999px;padding:4px 12px;font-size:13px;cursor:pointer}
.estimate-crumb:hover{background:#e3ebff}
/*: ⚠️ КЛАСС НЕ СЛОВОМ body: тест «не обрезать города» ищет overflow
   у селекторов, содержащих body, и срабатывал бы на имени класса. */
.estimate-modal-content{overflow:auto;padding:14px 20px 20px}
.estimate-catalog-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:8px}
.estimate-category{border:1px solid var(--line);background:#fff;border-radius:12px;padding:10px 12px;text-align:left;font-size:14px;cursor:pointer}
.estimate-category:hover{border-color:#1658e8;color:#1658e8}
.estimate-catalog-products{display:flex;flex-direction:column;gap:6px}
.estimate-catalog-row{display:grid;grid-template-columns:100px minmax(0,1fr) 130px 44px;gap:10px;align-items:center;background:#f7f9fc;border-radius:12px;padding:8px 12px;font-size:13px}
.estimate-catalog-row .btn{height:34px;min-height:34px;padding:4px 12px}
.estimate-catalog-name{overflow:hidden;text-overflow:ellipsis}

/* ЗАКАЗЧИК И ОБЪЕКТ — КОМПАКТНО (правка владельца 04.11.2026:
   блок стоит НАД поиском и высотой в 2 раза меньше). Одна строка сводки,
   поля — только после нажатия «Изменить». */
.estimate-section:has(.estimate-client){padding:10px 16px}
.estimate-client summary{display:flex;gap:10px;align-items:center;justify-content:space-between;cursor:pointer;list-style:none;min-height:32px}
.estimate-client summary::-webkit-details-marker{display:none}
.estimate-client-summary{font-size:13px;line-height:1.4;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.estimate-client-edit{color:#1658e8;font-size:13px;white-space:nowrap}
.estimate-client[open] .estimate-client-edit{display:none}
.estimate-client[open] summary{margin-bottom:12px}
.estimate-client .simple-form{margin-top:4px}
@media(max-width:700px){
  .estimate-suggest-item{grid-template-columns:1fr;gap:2px}
  .estimate-catalog-row{grid-template-columns:1fr 44px;gap:4px 10px}
}

/* ПОЛЕ КОЛИЧЕСТВА В СМЕТЕ (правка владельца 04.11.2026: кнопки
   «Сохранить» нет — значение сохраняется само). */
.estimate-qty-input{width:88px;height:34px;padding:4px 8px;border:1px solid var(--line);border-radius:10px;font-size:14px}
.estimate-item .estimate-qty-input{justify-self:start}

/* СТРОКА «ПОДСКАЗКИ НЕ ЗАГРУЗИЛИСЬ»: пустота вместо
   молчания — покупатель должен понимать, что поиск не сломался. */
.estimate-suggest-empty{padding:12px 14px;font-size:13px;color:var(--muted)}

/* ============================================================
   РЕЗУЛЬТАТЫ ПОИСКА В СМЕТЕ — ПАНЕЛЬ С ПРОКРУТКОЙ
   ------------------------------------------------------------
   Замечание владельца 04.11.2026: «нужно решить, как убирать/очищать
   поисковую выдачу, которая занимает много места». Теперь выдача живёт в
   панели фиксированной высоты со своей прокруткой, а сверху — кнопка
   «Свернуть результаты», которая убирает запрос и возвращает страницу.
   ============================================================ */
.estimate-results{margin-top:10px;border:1px solid var(--line);border-radius:14px;overflow:hidden}
.estimate-results-head{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:8px 12px;background:#f7f9fc;border-bottom:1px solid var(--line)}
.estimate-results-hide{color:#1658e8;font-size:13px;white-space:nowrap}
.estimate-results .estimate-found{max-height:360px;overflow:auto;padding:8px}
.estimate-results .estimate-found-row{background:#fff;border:1px solid var(--line)}

/* КОЛИЧЕСТВО В СМЕТЕ: ЗАГОЛОВОК ПО ЦЕНТРУ, БЛОК ПРАВЕЕ
   (правка владельца 04.11.2026: «Слово Количество отцентруй по полю кол-во.
   Знаки +/- передвинь ближе к полю кол-во и сам блок Кол-во сдвинь правее,
   ближе к Ед. — так освободится место для Наименования»).
   Колонка количества сужена с 148 до 116 px, счётчик прижат вправо. */
.estimate-item{grid-template-columns:36px 100px minmax(0,1fr) 116px 44px 92px 104px 40px}
.estimate-item-head > span:nth-child(4){text-align:center;justify-self:center}
.estimate-item .estimate-qty{justify-self:end;gap:2px}
.estimate-item .estimate-qty button{width:32px;height:32px}
.estimate-item .estimate-qty input{width:58px;height:32px}
.estimate-item .estimate-qty button + input{margin-left:0}
.estimate-item .estimate-qty input + button{margin-left:0}

/* КОЛИЧЕСТВО: ЗАГОЛОВОК И СЧЁТЧИК В ОДНОЙ ОСИ
   (уточнение владельца 04.11.2026: «слово Количество не по центру поля»).
   Счётчик шире колонки, поэтому при выравнивании вправо он вылезал
   влево и казался сдвинутым. Теперь колонка 128 px, и заголовок, и счётчик
   стоят строго по центру друг над другом. */
.estimate-item{grid-template-columns:36px 100px minmax(0,1fr) 128px 44px 92px 104px 40px}
.estimate-item-head > span:nth-child(4){text-align:center;justify-self:center;white-space:nowrap}
.estimate-item .estimate-qty{justify-self:center;gap:2px}

/* ПОДСКАЗКИ ПОИСКА: ДВЕ СТРОКИ НАЗВАНИЯ + ПОЛНОЕ В ПОДСКАЗКЕ
   (правка владельца 04.11.2026: «при наведении курсора должно появляться
   полное название»). В списке название сжимается до двух строк,
   а целиком показывается во всплывающем поле (атрибут title). */
.estimate-suggest-name{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;white-space:normal;line-height:1.35}
.estimate-suggest-item{grid-template-columns:96px minmax(0,1fr) 104px;align-items:center}

/* СООБЩЕНИЕ БЕЗ ПЕРЕЗАГРУЗКИ (добавление товара в смету). */
.estimate-flash{margin:10px 0 0}

/* ============================================================
   ВСПЛЫВАЮЩАЯ ПЛАШКА «ТОВАР ДОБАВЛЕН»
   ------------------------------------------------------------
   Замечание владельца 04.11.2026: строка под таблицей не видна — нужна
   подсказка, по которой сразу понятно, что клик сработал. Плашка висит
   внизу экрана независимо от прокрутки и сама уходит через 2 секунды.
   ============================================================ */
.estimate-toast{position:fixed;left:50%;bottom:84px;transform:translate(-50%,16px);z-index:120;max-width:min(520px,calc(100vw - 32px));padding:12px 18px;border-radius:12px;background:#0f7b3f;color:#fff;font-size:14px;line-height:1.4;box-shadow:0 12px 32px #0b122040;opacity:0;pointer-events:none;transition:opacity .18s ease,transform .18s ease}
.estimate-toast.visible{opacity:1;transform:translate(-50%,0)}
.estimate-toast.danger{background:#b3261e}

/* ============================================================
   КНОПКА «В КОРЗИНУ» И ОКНО ВЫБОРА (этап 4)
   ============================================================ */
.estimate-head-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.estimate-head-actions form{margin:0}
.estimate-cart-choice{margin:10px 0 0}
.estimate-cart-choice ul{margin:8px 0;padding-left:18px;font-size:13px}
.estimate-cart-choice-form{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.estimate-cart-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px}
.estimate-cart-actions .btn[hidden]{display:none}

/* ============================================================
   ПРАВКИ ПО СКРИНШОТАМ ВЛАДЕЛЬЦА (04.11.2026)
   ============================================================ */

/* Окно вопроса по корзине — узкое: в нём короткий текст, широкая рамка
   оставляла пустое поле справа (скриншот 1). */
.estimate-modal-window.compact{width:min(520px,100%)}

/* Поле количества в СПИСКЕ каталога — не во всю ширину правой колонки,
   а компактное: «− N +» (скриншот 2). */
.card-row .card-buy .card-qty-form{max-width:168px}
.card-row .card-buy .qty button{flex:0 0 40px;width:40px}
.card-row .card-buy .qty input{flex:1 1 auto;width:auto;min-width:44px;text-align:center}

/* Действия с корзиной — справа от заголовка. */
.cart-head-actions{display:flex;gap:8px;flex-wrap:wrap;margin-left:auto}
.cart-head-actions form{margin:0}
.cart-head-actions .btn{white-space:nowrap}
@media(max-width:640px){
  .cart-head-actions{width:100%;margin-left:0}
}

/* ============================================================
   СМЕТА: ЧЕКБОКСЫ, МАССОВОЕ УДАЛЕНИЕ, КРАСНАЯ СВОДКА
   (замечания владельца 04.11.2026)
   ============================================================ */
.estimate-item{grid-template-columns:28px 36px 100px minmax(0,1fr) 128px 44px 92px 104px 40px}
.estimate-check{display:flex;align-items:center;justify-content:center}
.estimate-check input{width:16px;height:16px;accent-color:#1658e8;cursor:pointer}
/* ============================================================
   ПАНЕЛЬ МАССОВОГО УДАЛЕНИЯ — ВСПЛЫВАЮЩАЯ, БЕЗ СДВИГА ТАБЛИЦЫ
   ------------------------------------------------------------
   Замечание владельца 05.11.2026 (два скриншота): «скачут элементы до
   нажатия в общем чекбоксе и после… общий чекбокс должен остаться на той же
   позиции». Панель была в потоке и раздвигала таблицу. Теперь она висит
   внизу экрана (как панель действий в почте) и места в разметке не занимает.
   ============================================================ */
.estimate-bulk{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);z-index:95;display:flex;gap:14px;align-items:center;flex-wrap:wrap;justify-content:center;max-width:calc(100vw - 24px);padding:10px 16px;background:#fff;border:1px solid var(--line);border-radius:14px;box-shadow:0 14px 40px #0b12203d}
.estimate-bulk[hidden]{display:none}
.estimate-bulk .btn{min-height:38px}
@media(max-width:640px){
  .estimate-bulk{gap:10px;padding:10px 12px}
}
/*: Пустая сводка заказчика — КРАСНЫМ: это не подпись, а предупреждение. */
.estimate-client-empty{color:#b3261e;font-weight:500}

/* СВОЁ ОКНО ПОДТВЕРЖДЕНИЯ ВМЕСТО ОКНА БРАУЗЕРА (замечание владельца
   04.11.2026: «Сделай всплывашку сайта, в нашем дизайне»). */
dialog.site-confirm{border:0;padding:0;border-radius:16px;max-width:min(420px,calc(100vw - 32px));box-shadow:0 24px 64px #0b12204d}
dialog.site-confirm::backdrop{background:#0b1220a8}
.site-confirm-body{padding:22px 22px 18px}
.site-confirm-text{margin:0 0 18px;font-size:15px;line-height:1.45}
.site-confirm-actions{display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap}

/* ============================================================
   КРАСНЫЕ КНОПКИ УДАЛЕНИЯ (замечание владельца 05.11.2026: «кнопки
   удаления подкрасим в красный — это привычно и заметнее»).
   Базовый цвет у .btn.danger уже был в палитре; здесь — реакция на наведение
   и подсветка крестика (постоянно красные крестики в списке из 20 строк выглядят
   как авария). */
.btn.danger:hover{background:#9C2233}
.btn.danger:active{background:#891D2C}
.estimate-item form [aria-label="Убрать позицию"]:hover,
.estimate-item form [aria-label="Убрать позицию"]:focus-visible{color:var(--danger);background:var(--dangerSoft);border-color:var(--dangerSoft)}

/* ============================================================
   ССЫЛКА ЗАКАЗЧИКУ — КНОПКА В ШАПКЕ + ПАНЕЛЬ (этап 5, 06.11.2026)
   ------------------------------------------------------------
   Замечание владельца: «всё равно много занимает место», при этом
   подсказка и статус обрезались многоточием. Поэтому ссылка живёт в шапке
   кнопкой (ноль дополнительной высоты), а полный текст — в раскрывающейся
   панели на нативном <details>: работает без JavaScript.
   ============================================================ */
.estimate-share{position:relative}
.estimate-share > summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:8px}
.estimate-share.has-link > summary::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--success);flex-shrink:0}
.estimate-share > summary::-webkit-details-marker{display:none}
.estimate-share > summary::marker{content:""}
.estimate-share-panel{position:absolute;right:0;top:calc(100% + 8px);z-index:70;width:min(460px,calc(100vw - 32px));padding:16px 18px;border-radius:16px;border:1px solid var(--line);background:#fff;box-shadow:0 16px 44px #0b12201f}
.estimate-share-lead{margin:0 0 12px;font-size:14px;line-height:1.5;color:var(--text)}
.estimate-share-row{display:flex;gap:8px;align-items:center}
.estimate-share-input{flex:1;min-width:0;height:40px;border:1px solid var(--control);border-radius:10px;padding:8px 12px;font-size:13px;background:#fff;color:var(--text)}
.estimate-share-btn{min-height:40px;padding:6px 14px;white-space:nowrap}
.estimate-share-status{margin:10px 0 0;font-size:13px;line-height:1.5;color:var(--muted)}
.estimate-share-status.ok{color:var(--success);font-weight:bold}
.estimate-share-rotate{display:flex;gap:10px;align-items:flex-start;margin:14px 0 0;padding-top:14px;border-top:1px solid var(--line);flex-wrap:wrap}
.estimate-share-create{margin:0}
.estimate-share-note{margin:8px 0 0;font-size:12px;line-height:1.5;color:var(--muted);flex:1;min-width:180px}
@media(max-width:640px){
  .estimate-share-panel{right:auto;left:0}
  .estimate-share-row{flex-wrap:wrap}
}
.public-estimate-table{width:100%;border-collapse:collapse;font-size:15px}
.public-estimate-table th,.public-estimate-table td{padding:10px 12px;text-align:left;border-bottom:1px solid var(--line);vertical-align:top}
.public-estimate-table th{font-size:13px;color:var(--muted);font-weight:normal;text-transform:uppercase;letter-spacing:.4px}
.public-estimate-table .num{text-align:right;white-space:nowrap}
.public-estimate-table tfoot td{border-bottom:0;padding-top:14px}
.public-estimate-actions{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin:22px 0 8px}
.public-estimate-client p{margin:4px 0}
@media(max-width:720px){
  .public-estimate-table th:nth-child(2),.public-estimate-table td:nth-child(2){display:none}
}
.public-estimate-gift{margin:0 0 16px;padding:12px 16px;border-radius:12px;background:var(--warmSoft);color:var(--onWarm);font-size:14px;line-height:1.5}

/* ============================================================
   РЕКВИЗИТЫ ОРГАНИЗАЦИИ: состояние полей после проверки ИНН.
   ============================================================
   Правило: заполненное поле — зелёное, обязательное и пустое — красное.
   Цвет НЕ единственный признак: внутри поля стоит иконка (галочка или
   восклицательный знак), а над формой — легенда. Так понятно и людям,
   которые плохо различают красный и зелёный.
   Классы ставит `checkout_company.js`; без JavaScript страница выглядит
   как прежде — форма работает вручную. */
.company-field-legend{display:flex;gap:18px;flex-wrap:wrap;margin:0 0 14px;font-size:13px;color:var(--muted)}
.company-field-legend[hidden]{display:none}
.company-legend-item{display:inline-flex;align-items:center;gap:7px}
.company-legend-item:before{content:"";width:13px;height:13px;border-radius:4px;border:1px solid transparent;flex-shrink:0}
.company-legend-item.filled:before{background:var(--successSoft);border-color:var(--success)}
.company-legend-item.missing:before{background:var(--dangerSoft);border-color:var(--danger)}
.input-wrap input.is-filled,.input-wrap input.is-missing{padding-right:48px;background-repeat:no-repeat;background-position:right 14px center;background-size:20px 20px}
.input-wrap input.is-filled{border-color:var(--success);background-color:var(--successSoft);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%23167149'/%3E%3Cpath d='M5.6 10.3l2.9 2.9 5.9-6.1' fill='none' stroke='%23FFFFFF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
.input-wrap input.is-missing{border-color:var(--danger);background-color:var(--dangerSoft);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%23B52A3B'/%3E%3Cpath d='M10 5.2v6' fill='none' stroke='%23FFFFFF' stroke-width='2' stroke-linecap='round'/%3E%3Ccircle cx='10' cy='14.4' r='1.15' fill='%23FFFFFF'/%3E%3C/svg%3E")}
@media(prefers-reduced-motion:no-preference){
  .input-wrap input.is-filled,.input-wrap input.is-missing{transition:border-color .15s,background-color .15s}
}

/* ============================================================
   УВЕДОМЛЕНИЯ ВИТРИНЫ: cookie, работы/остатки, онлайн-оплата
   ============================================================
   ЗАДАНИЕ ВЛАДЕЛЬЦА (12.11.2026) И УТОЧНЕНИЕ ПОСЛЕ ПРОСМОТРА.
   Три сообщения на публичных страницах:
   1) полоса про cookie ВНИЗУ страницы — как на moto-58.ru: текст + «Понятно»,
      запоминается на год;
   2) «Сайт в разработке: возможны неточности…» с телефоном магазина;
   3) «Онлайн-оплата временно недоступна…».
   Сообщения 2 и 3 — ПО ЦЕНТРУ ЭКРАНА, одно под другим, и показываются
   ОДИН РАЗ В СУТКИ каждому посетителю (частоту считает сервер по дате в
   cookie; в CSS её нет).

   ⚠️ ЭТО ОБЪЯВЛЕНИЯ, А НЕ МОДАЛЬНОЕ ОКНО. Страница НЕ затемняется и НЕ
   блокируется: у слоя `pointer-events:none` (клики и прокрутка проходят
   сквозь пустое место), а включают клики только сами карточки и полоса.
   Затемнения (`::backdrop`, тёмной подложки) здесь нет намеренно — владелец
   просил объявление, а не диалог.

   ⚠️ ОДИН ФИКСИРОВАННЫЙ СЛОЙ НА ВСЁ (правка 12.11.2026 по скриншоту
   владельца с телефона 1080×2099). Дефект был такой: три блока не
   помещались, карточки объявлений уходили ПОД шапку и обрезались снизу, а
   полоса cookie оказывалась ПОД нижним меню — кнопка «Понятно» была
   недоступна. Причина — уведомления жили отдельными фиксированными
   коробками, и порядок «кто выше» держался на числах, а не на раскладке.
   Теперь коробка ОДНА (`inset:0`, колонка флекса): сначала карточки, потом
   полоса. Их порядок гарантирован раскладкой, а не вычислением высот:
     * карточки — `margin-block:auto 12px` (центр области над полосой);
     * полоса — последний элемент, `margin-top:auto` (прижата к низу).
   Высоту полосы заранее знать не нужно: на ПК текст в одну строку, на
   телефоне — в три, и она меняется вместе с текстом. Поэтому нет ни числа
   «высота полосы» в CSS, ни JS-класса вида `cookie-open`: одна раскладка —
   одно правило, и оно не разойдётся при правке текста.

   ⚠️ ЦЕНТРИРОВАНИЕ — `margin-block:auto`, А НЕ `flex:1`+`justify-content`.
   При `justify-content:center` содержимое, которое не помещается, обрезается
   С ОБЕИХ сторон: верх карточки уезжает за край и достать его прокруткой
   нельзя (ровно это и было на скриншоте владельца). `auto`-поля в
   переполненном флексе по правилам CSS становятся нулевыми, поэтому карточки
   начинаются от верхнего отступа слоя и всё, что не влезло, ДОСТИГАЕТСЯ
   прокруткой.

   ⚠️ ПРОКРУЧИВАЕТСЯ СЛОЙ (`overflow-y:auto`), А НЕ СТРАНИЦА. На 360×640 три
   блока одновременно не помещаются — это нормально: слой прокручивается,
   шапка и меню остаются на месте, кнопки достижимы. Шапка (`z-index:60`) и
   меню (`100`) выше слоя (`45`), поэтому при прокрутке содержимое уходит ПОД
   непрозрачную шапку, а не поверх неё: так ведёт себя верхняя панель
   в промышленных магазинах.

   ⚠️ СЛОЙ 45 — НИЖЕ ШАПКИ (60), ПАНЕЛИ КАТАЛОГА (55) И НИЖНЕГО МЕНЮ (100).
   Уведомление не должно перекрывать навигацию: шапку владелец видит всегда,
   меню остаётся кликабельным. От перекрытия «по месту» его защищают отступы
   слоя (сверху — шапка, снизу — меню + безопасная зона, см. мобильные блоки).

   ⚠️ ЦВЕТА И РАДИУСЫ — ИЗ ДИЗАЙН-СИСТЕМЫ (`:root` в начале файла):
   `--surface`, `--line`, `--text`, `--primary`, `--radius-card`, `--shadow`;
   отступы и ширина — из общих (`--content-max`). Тень «вверх» у полосы,
   поэтому у обёртки своя переменная (у `--shadow` направление вниз, как у
   карточек).
   ============================================================ */

.site-notices{
  --notices-shadow:0 -6px 26px rgba(27,53,87,.10);
  position:fixed;
  inset:0;
  z-index:45;
  display:flex;
  flex-direction:column;
  /* Прокрутка самого слоя: на телефоне три блока не помещаются, а шапка,
     меню и страница под ними обязаны остаться на месте. */
  overflow-y:auto;
  overflow-x:hidden;
  -webkit-overflow-scrolling:touch;
  pointer-events:none}

/* Карточки объявлений — в области НАД полосой cookie.
   `margin-block:auto 12px`: сверху свободное место распределяется само
   (центрирование), снизу — 12 px до полосы. В переполненном слое верхнее
   `auto` становится нулём, и карточки начинаются от верхнего отступа слоя —
   верх читается, а не обрезается. */
.site-notices__center{
  display:flex;
  flex-direction:column;
  gap:16px;
  margin-block:auto 12px;
  pointer-events:none}

/* ⚠️ ЕДИНСТВЕННЫЙ РЕБЁНОК СЛОЯ — ТОЛЬКО КАРТОЧКИ (полосу cookie уже приняли,
   а объявления показываются снова каждый день). Тогда 12 px «до полосы»
   превратились бы в единственное `auto`-поле сверху и прижали карточки к низу
   экрана. Возвращаем нижнее поле в `auto` — карточки снова по центру. */
.site-notices__center:only-child{
  margin-bottom:auto}

/* Карточка объявления: белая поверхность, линия, тень — как карточки витрины.
   Ширина ограничена 460 px: строка текста не растягивается на весь монитор;
   `margin-inline:auto` держит карточку по центру и на широком экране, и тогда,
   когда она занимает всю ширину слоя. */
.site-notice{
  pointer-events:auto;
  width:100%;
  max-width:460px;
  margin-inline:auto;
  background:#fff;
  border:1px solid var(--line);
  border-radius:var(--radius-card);
  box-shadow:var(--shadow);
  padding:20px 24px}
.site-notice__text{
  margin:0;
  font-size:16px;
  line-height:1.5;
  color:var(--text)}
.site-notice__text a{
  color:var(--primary);
  text-decoration:underline;
  text-underline-offset:2px}
.site-notice__text a:hover{
  color:var(--primaryHover)}
/* Телефон — неразрывной строкой: «8 (906) 369-36-90» не должен рваться
   между цифрами, иначе на телефоне он читается как два разных номера. */
.site-notice__phone{
  font-weight:600;
  white-space:nowrap}
.site-notice form{
  margin:16px 0 0}
/* Кнопка «Понятно» — основная кнопка дизайн-системы (`.btn`, синяя).
   Свой hover не рисуем: второго вида кнопки в проекте быть не должно.
   Фокус с клавиатуры даёт общее правило `button:focus-visible`. */
.site-notice .btn{
  min-height:48px;
  padding:12px 22px;
  font-size:15px}

/* Полоса про cookie: во всю ширину, у самого низа (как на moto-58.ru).
   `margin-top:auto` прижимает её к низу и когда карточек нет вовсе, и когда
   их две: полоса — ПОСЛЕДНИЙ элемент слоя, поэтому «карточки сверху, полоса
   снизу» держится порядком разметки, а не числами. На телефоне (до 720 px)
   полоса становится карточкой внутри слоя — см. мобильный блок ниже. */
.cookie{
  pointer-events:auto;
  margin-top:auto;
  background:var(--surface);
  border-top:1px solid var(--line);
  box-shadow:var(--notices-shadow)}
.cookie__inner{
  max-width:var(--content-max);
  margin:0 auto;
  padding:16px 32px;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:24px}
.cookie__text{
  margin:0;
  font-size:14px;
  line-height:1.5;
  color:var(--text)}
.cookie__text a{
  color:var(--primary);
  text-decoration:underline;
  text-underline-offset:2px}
.cookie__text a:hover{
  color:var(--primaryHover)}
.cookie .btn{
  flex:0 0 auto;
  min-height:44px;
  padding:10px 20px}

@media(max-width:767px){
  /* Нижнее меню телефона (`z-index:100`, высота 72 px + безопасная зона)
     остаётся видимым и рабочим: слой уведомлений освобождает под него место
     СВОИМ отступом, а не `bottom` — полоса живёт внутри слоя и потому всегда
     выше меню. Одно и то же число, что у `body.has-mobile-nav` (+12 px
     воздуха до меню): иначе кнопка «Понятно» снова оказалась бы под ним. */
  .site-notices{
    padding-bottom:calc(72px + env(safe-area-inset-bottom,0px) + 12px)}
}

@media(max-width:720px){
  /* Телефон: карточки во всю ширину слоя (по 12 px от краёв экрана), текст и
     кнопка — в колонку; полоса cookie тоже в колонку и ВНУТРИ слоя.
     Верхний отступ — высота шапки (96 px): карточки не заезжают под неё.
     Нижний — из блока выше (меню + безопасная зона + 12 px). */
  .site-notices{
    padding-top:108px;
    padding-inline:12px}
  .site-notices__center{
    gap:10px}
  .site-notice{
    padding:16px;
    border-radius:16px}
  .site-notice__text{
    font-size:15px;
    line-height:1.4}
  .site-notice form{
    margin-top:12px}
  /* Кнопка на всю ширину карточки: палец не промахивается, а «Понятно»
     не спорит по ширине с текстом. 44 px — минимальный размер касания. */
  .site-notice .btn,
  .cookie .btn{
    width:100%;
    min-height:44px}
  /* Полоса на телефоне — не «прилипшая» лента во всю ширину, а карточка
     внутри слоя: у слоя уже есть по 12 px полей, и полоса получает их же
     форму (скругление и тень), а не обрезанные по краям рамки. */
  .cookie{
    border:1px solid var(--line);
    border-radius:16px;
    box-shadow:var(--shadow)}
  .cookie__inner{
    flex-direction:column;
    align-items:stretch;
    gap:12px;
    padding:12px 16px}
  .cookie__text{
    font-size:13.5px}
}

/* Короткий экран (ноутбук 1366×768 и меньше): карточки чуть компактнее —
   обе обязаны помещаться в области над полосой cookie, не упираясь в неё.
   Только ПК: на телефоне (до 720 px) размеры свои, и это правило не должно
   спорить с ними на маленьком экране вроде 360×640. */
@media(min-width:721px) and (max-height:800px){
  .site-notices__center{
    gap:12px}
  .site-notice{
    padding:16px 20px}
  .site-notice form{
    margin-top:12px}
}

/* Анимаций у уведомлений нет вовсе (сервер решает, показывать ли, — нечего
   плавно раскрывать), поэтому `prefers-reduced-motion` их не касается:
   общее правило файла отключает движение для всего остального. Печать:
   уведомления на бумаге не нужны. */
@media print{
  .site-notices{
    display:none}
}

/* ⚠️ ЗАМЕТНОСТЬ (замечание владельца 12.11.2026): «всплывашки сливаются с
   фоном». Карточки отличаются от страницы не только тенью: слева цветная
   полоса-акцент и круглая иконка, тень глубже, а у объявления про оплату —
   предупреждающий жёлтый акцент. Цвет не единственный признак: иконка и текст
   читаются и без него (R-17, доступность). */
.site-notice{
  position:relative;
  padding:22px 24px 22px 68px;
  border:1px solid var(--line);
  border-left:5px solid var(--primary);
  box-shadow:0 18px 44px rgba(16,35,58,.22),0 2px 6px rgba(16,35,58,.08)}
.site-notice:before{
  content:"";
  position:absolute;
  left:22px;
  top:24px;
  width:32px;
  height:32px;
  background:no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='11' fill='%231658E8'/%3E%3Cpath d='M12 10.6v6.2' stroke='%23FFFFFF' stroke-width='2.2' stroke-linecap='round'/%3E%3Ccircle cx='12' cy='7.2' r='1.35' fill='%23FFFFFF'/%3E%3C/svg%3E")}
.site-notice--payment{
  border-left-color:var(--warning);
  background:linear-gradient(180deg,#fffdf6 0%,#fff 46%)}
.site-notice--payment:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.6 22.4 21H1.6z' fill='%23F3AB2C'/%3E%3Cpath d='M12 9v5.4' stroke='%2317263A' stroke-width='2.2' stroke-linecap='round'/%3E%3Ccircle cx='12' cy='17.6' r='1.35' fill='%2317263A'/%3E%3C/svg%3E")}
.site-notice__text{font-size:16px;line-height:1.5}
.cookie{
  background:#fff;
  border-top:2px solid var(--primary);
  box-shadow:0 -14px 34px rgba(16,35,58,.16),0 -2px 6px rgba(16,35,58,.06)}
.cookie__text{font-size:14.5px}
@media(max-width:720px){
  .site-notice{padding:18px 16px 18px 56px}
  .site-notice:before{left:14px;top:18px;width:28px;height:28px}
}
