/* ============================================================================
   ISELLPOWER · options.css  (v342)

   Нижний блок страниц сборок: раздел «Дополнительные опции» карточками с
   фотографиями плюс три новых раздела — мышь, коврик, стол.

   Подключается ПОСЛЕДНИМ в <head>, во все 13 страниц сборок.
   Пара к нему — assets/options.js (переключение цвета оплётки).

   ── УСТРОЙСТВО ─────────────────────────────────────────────────────────────
   .below       секция под обеими колонками .page (сетка 1.15fr/.85fr).
                Пока цена и опции лежали в правой колонке, она тянула вверх
                высоту строки, левая сцена росла за ней и фотография ПК
                уезжала вниз. Здесь они уже вынесены.
   .opt-grid    три колонки; карточка с переключателем цвета занимает две —
                ей нужна ширина под ряд кнопок, и пять карточек как раз
                ложатся в 3 + (1 + 2) без дырок.
   .shot        рамка снимка. Скруглние 16px — как у карточек ПК в каталоге.
   .shot-cut    для вырезанных по контуру снимков (мыши, стол): вписываем
                целиком и подкладываем мягкое пятно света вместо фона.

   ── ПРО АНИМАЦИИ ───────────────────────────────────────────────────────────
   Постоянно крутится только цветной штрих у заголовков разделов — четыре
   маленьких элемента. Всё остальное (обводка, наезд на снимок, подъём
   карточки) просыпается ТОЛЬКО при наведении: страница в покое ничего не
   пересчитывает. Это сознательно — на разделе со спидометром уже ловили
   просадку от постоянно работающих эффектов.
   ============================================================================ */

@property --oang{syntax:'<angle>';inherits:false;initial-value:0deg}

.below{
  grid-column:1 / -1;
  position:relative;
  z-index:3;
  padding:6px 52px 64px;
}
.below-inner{
  width:min(1200px,94vw);
  margin:0 auto;
  display:flex;
  flex-direction:column;
  gap:18px;
}

/* ===== заголовки разделов ================================================= */

.below .spec-h{
  display:flex;
  align-items:center;
  gap:12px;
  margin:26px 0 2px;
}
.below .spec-h::before{
  content:"";
  width:26px;height:2px;border-radius:2px;
  background:linear-gradient(90deg,#e10600,#ff6a3d,#e10600);
  background-size:220% 100%;
  animation:ohue 9s linear infinite;
}
.below .spec-h::after{
  content:"";
  flex:1;height:1px;
  background:linear-gradient(90deg,rgba(255,255,255,.13),transparent);
}
@keyframes ohue{to{background-position:220% 0}}

/* ===== сетки ============================================================== */

.opt-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
/* одиночная карточка не растягивается на всю ширину — квадратный снимок
   коврика в поле 1200px выглядел бы плакатом */
.opt-grid.one{grid-template-columns:minmax(0,620px)}

/* Коврик и стол стоят рядом, каждый со своим заголовком: одинокая карточка
   в 620px оставляла полполосы пустой. */
.pair-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start}
/* gap обязателен: в остальных разделах заголовок и сетку разводит gap:18px
   у .below-inner, а внутри колонки родитель другой — без него карточка
   прилипала к заголовку и отступ отличался от всех прочих */
.pair-col{display:flex;flex-direction:column;gap:18px;min-width:0}
.pair-col .spec-h{margin-top:26px}
.pair-col .opt-grid.one{grid-template-columns:minmax(0,1fr)}

/* Доставка. Раньше была баннером во всю ширину (.opt-grid.full, снимок 16/7).
   Теперь это обычная одиночная карточка, как «Коврик» и «Стол»: те же 620px
   и тот же кадр 4/3. Правило .full оставлено — вдруг понадобится широкий
   баннер в другом месте. */
.opt-grid.full{grid-template-columns:minmax(0,1fr)}
.opt-grid.full .shot{aspect-ratio:16/7;flex:none;min-height:0}

@media(max-width:900px){
  .pair-grid{grid-template-columns:1fr}
  .opt-grid.full .shot{aspect-ratio:16/9}
}
/* карточке с выбором цвета нужна ширина под ряд кнопок */
.opt-grid > .ocard:has(.csw-row){grid-column:span 2}

.mouse-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}

@media(max-width:1080px){
  .opt-grid{grid-template-columns:repeat(2,1fr)}
  .mouse-grid{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:620px){
  .opt-grid{grid-template-columns:1fr}
  .opt-grid > .ocard:has(.csw-row){grid-column:auto}
}



/* ===== карточка =========================================================== */

.ocard,.mcard{
  position:relative;
  display:flex;flex-direction:column;gap:12px;
  padding:18px 18px 18px;
  border:1px solid rgba(255,255,255,.08);
  border-radius:18px;
  background:linear-gradient(180deg,#121216,#0b0b0e);
  transition:transform .3s,border-color .3s;
  --edge1:#e10600; --edge2:#ff6a3d;      /* цвет обводки платной опции */
}
.ocard.is-inc{--edge1:#9aa0ad; --edge2:#e7eaf0}

/* Обводка «бегущим светом». Кольцо толщиной 1px собрано маской: заливка
   рисуется по всей карточке, а маска вырезает середину и оставляет кант. */
.ocard::before,.mcard::before{
  content:"";
  position:absolute;inset:0;
  border-radius:inherit;
  padding:1px;
  background:conic-gradient(from var(--oang),
    transparent 0 58%, var(--edge1) 72%, var(--edge2) 82%, transparent 94%);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
          mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
          mask-composite:exclude;
  opacity:0;
  transition:opacity .35s;
  pointer-events:none;
}
.mcard{--edge1:#e10600; --edge2:#ff6a3d}

@media(hover:hover){
  .ocard:hover,.mcard:hover{transform:translateY(-4px);border-color:transparent}
  .ocard:hover::before,.mcard:hover::before{
    opacity:1;
    animation:oang 2.8s linear infinite;
  }
  .ocard:hover .shot img,.mcard:hover .shot img{transform:scale(1.045)}
}
@keyframes oang{to{--oang:360deg}}

/* ===== шапка карточки ===================================================== */

.ocard-head{display:flex;align-items:flex-start;gap:12px}
.opt-mark{flex:none;width:20px;height:20px;margin-top:2px;display:grid;place-items:center}
.opt-mark svg{width:17px;height:17px;fill:none;stroke-width:2.6;
  stroke-linecap:round;stroke-linejoin:round}
.opt-mark.ok svg{stroke:#2ecc71}
.opt-mark.add svg{stroke:#9aa0ad}

.opt-kv{display:flex;flex-direction:column;gap:4px;min-width:0;flex:1}
.opt-k{font-weight:700;font-size:1rem;color:var(--text,#f5f5f7);line-height:1.3}
.opt-v{font-size:.87rem;line-height:1.5;color:#9aa0ad}
.opt-v.tiny{font-size:.79rem;line-height:1.55;color:#8b909b}

.opt-link{color:#fff;text-decoration:none;border-bottom:1px solid rgba(225,6,0,.6);
  transition:border-color .25s,color .25s}
.opt-link:hover{color:#ff6a3d;border-bottom-color:#ff6a3d}

/* цена: плашка, чтобы читалась на снимке любой яркости */
.opt-price{
  flex:none;align-self:flex-start;
  font-weight:700;font-size:.9rem;white-space:nowrap;
  color:#fff;
  padding:6px 12px;border-radius:9999px;
  border:1px solid rgba(255,255,255,.14);
  background:rgba(255,255,255,.05);
}
/* «включено» — нейтральная серебряная плашка: это не выбор, а факт,
   и кричать цветом ей незачем. Сама галочка остаётся зелёной. */
.opt-price.inc{
  font-weight:700;font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;
  color:#cfd4de;
  border-color:rgba(207,212,222,.30);
  background:linear-gradient(180deg,rgba(255,255,255,.09),rgba(255,255,255,.03));
}

/* ===== снимок ============================================================= */

.shot{
  margin:0;
  border-radius:16px;
  overflow:hidden;
  background:#08080a;
  aspect-ratio:4/3;
}
/* В сетке опций высоту строки задаёт самая высокая карточка (у Cable Kit есть
   ещё и ряд кнопок). Поэтому там снимок не держит пропорцию, а растягивается
   на весь остаток карточки — иначе у соседа снизу оставалась бы пустота. */
.opt-grid .shot{aspect-ratio:auto;flex:1;min-height:240px}
.opt-grid.one .shot{aspect-ratio:4/3;flex:none;min-height:0}
/* Снимок вынут из потока внутрь рамки. Иначе собственная высота картинки
   (у кабелей это 1080px) попадала в расчёт max-content, и строка сетки
   раздувалась до 900px вместо нужных ~480. */
.shot{position:relative}
.shot img{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
  display:block;
  transition:transform .5s cubic-bezier(.16,1,.3,1),opacity .22s;
}
.shot img.is-swapping{opacity:0}

/* вырезанные по контуру: вписываем целиком, вместо фона — мягкое пятно */
/* Нейтральный свет под вырезом. Раньше здесь было красное пятно — под
   широким тёмным столом оно читалось как засвет, а не как подсветка пола. */
.shot-cut{
  background:
    radial-gradient(70% 48% at 50% 80%,rgba(255,255,255,.07),transparent 72%),
    linear-gradient(180deg,#141419,#0a0a0c);
}
.shot-cut img{object-fit:contain;padding:12px}

.mcard .shot{aspect-ratio:3/4}
.mcard-head{display:flex;align-items:flex-start;gap:12px}
.mcard .opt-price{font-size:.84rem;padding:5px 10px}

/* цена и «Характеристики» в одной строке */
.mcard-row{display:flex;align-items:center;justify-content:space-between;gap:10px}

/* ── Выравнивание цен между карточками ────────────────────────────────────
   Названия и подписи у мышей разной длины: у Superlight 2 подпись влезает в
   строку, у соседей переносится, и плашка цены оказывалась выше остальных.
   subgrid отдаёт карточкам ОБЩИЕ строки сетки, поэтому шапки, ряд с ценой и
   снимок встают на одни и те же линии у всех четырёх. */
.mouse-grid{grid-template-rows:auto auto auto}
.mcard{grid-row:span 3;row-gap:12px}
@supports (grid-template-rows:subgrid){
  .mcard{display:grid;grid-template-rows:subgrid}
}
/* Запасной путь для браузера без subgrid: держим шапке высоту трёх строк —
   это максимум, который встречается (имя в две строки плюс подпись, либо
   наоборот). Выравнивание не идеальное, но плашки не гуляют. */
@supports not (grid-template-rows:subgrid){
  .mcard-head{min-height:4.6em}
}

/* ===== выбор цвета оплётки ================================================ */

.csw-row{display:flex;gap:9px;flex-wrap:wrap}
.csw{
  display:inline-flex;align-items:center;gap:9px;
  font:600 .86rem/1 "Manrope",sans-serif;color:#c9cdd6;
  padding:8px 15px 8px 9px;
  border:1px solid rgba(255,255,255,.14);
  border-radius:9999px;
  background:rgba(255,255,255,.03);
  cursor:pointer;
  transition:border-color .25s,color .25s,background .25s;
}
.csw i{
  width:18px;height:18px;border-radius:50%;
  background:var(--sw);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.22);
}
.csw:hover{border-color:rgba(255,255,255,.34);color:#fff}
.csw.is-on{
  color:#fff;
  border-color:rgba(225,6,0,.65);
  background:rgba(225,6,0,.12);
}

/* ===== галочка у строки Windows в правой колонке ========================== */

.specs small .ok-tick{display:inline-block;vertical-align:-2px;
  width:13px;height:13px;margin-right:6px}
.specs small .ok-tick svg{width:13px;height:13px;fill:none;stroke:#2ecc71;
  stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round}

/* ===== мелочи под узкий экран ============================================= */

@media(max-width:900px){
  .below{padding:0 22px 46px}
  .below-inner{width:100%}
}
/* На узком экране цена уходит под заголовок: рядом им тесно и название
   рассыпалось на пять строк. flex-wrap тут не помогает — flex сначала жмёт
   заголовок и только потом переносит, поэтому шапка становится сеткой. */
@media(max-width:560px){
  .ocard-head{
    display:grid;
    grid-template-columns:20px minmax(0,1fr);
    column-gap:12px;row-gap:10px;
    align-items:start;
  }
  .opt-price{grid-column:2;justify-self:start;align-self:auto}
}

@media(prefers-reduced-motion:reduce){
  .below .spec-h::before{animation:none}
  .ocard,.mcard,.shot img{transition:none}
  .ocard:hover::before,.mcard:hover::before{animation:none;opacity:1}
}

/* ===== выбираемая опция ==================================================== */

.is-opt{cursor:pointer;user-select:none}
.is-opt:focus-visible{outline:2px solid var(--accent2,#ff3d44);outline-offset:3px}

/* В отметке ПЛАТНОЙ опции лежат два знака — плюс и галочка, показываем
   нужный. Прятать галочку скопом нельзя: у «включённых» опций знак ровно
   один, и правило гасило его вместе с остальными. */
.opt-mark.add .i-ok{display:none}
.is-opt.is-on .opt-mark.add .i-add{display:none}
.is-opt.is-on .opt-mark.add .i-ok{display:block;stroke:#ffffff}

/* Выбранная карточка: белый кант держится постоянно, плюс белая плашка
   цены. Красным помечено «стоит денег», белым — «я это взял», иначе два
   состояния сливаются. */
.is-opt.is-on{
  border-color:rgba(255,255,255,.85);
  box-shadow:0 0 0 1px rgba(255,255,255,.32), 0 20px 46px -26px rgba(255,255,255,.28);
  background:linear-gradient(180deg,#17171c,#0d0d10);
}
.is-opt.is-on::before{opacity:1;--edge1:#ffffff;--edge2:#c9cdd6}
.is-opt.is-on .opt-price{
  color:#0b0b0e;
  border-color:#fff;
  background:linear-gradient(180deg,#ffffff,#dfe3ea);
}

/* ===== что выбрано, под ценой сборки ====================================== */

.opt-total{display:none}
.opt-total.show{display:flex;flex-direction:column;gap:6px;margin-top:2px}
.ot-row{
  display:flex;align-items:center;gap:16px;
  font:600 .9rem/1.4 "Manrope",sans-serif;color:#c9cdd6;
  padding:7px 0;border-bottom:1px solid rgba(255,255,255,.08);
}
.ot-row:last-child{border-bottom:none}
.ot-n{flex:1;min-width:0}
.ot-p{color:#fff;font-weight:700;white-space:nowrap}

/* «удалить» прямо в списке — снимает выбор, не заставляя искать карточку */
.ot-del{
  flex:none;display:inline-flex;align-items:center;gap:6px;
  font:600 .78rem/1 "Manrope",sans-serif;color:#8b909b;
  padding:6px 10px;border:1px solid transparent;border-radius:9999px;
  background:transparent;cursor:pointer;
  transition:color .22s,border-color .22s,background .22s;
}
.ot-del svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round}
.ot-del:hover{color:#fff;border-color:rgba(255,255,255,.22);background:rgba(255,255,255,.05)}
.ot-del:focus-visible{outline:2px solid var(--accent2,#ff3d44);outline-offset:2px}
@media(max-width:520px){.ot-del span{display:none}.ot-del{padding:6px}}

/* ===== всплывающее подтверждение ========================================== */

.opt-toast{
  position:fixed;left:50%;bottom:28px;z-index:120;
  display:flex;align-items:center;gap:12px;
  max-width:min(460px,92vw);
  padding:13px 18px 13px 14px;
  border:1px solid rgba(255,255,255,.16);
  border-radius:14px;
  background:rgba(14,14,18,.92);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  box-shadow:0 24px 50px -22px rgba(0,0,0,.9);
  transform:translate(-50%,18px);
  opacity:0;pointer-events:none;
  transition:opacity .28s,transform .28s cubic-bezier(.16,1,.3,1);
}
.opt-toast.show{opacity:1;transform:translate(-50%,0)}
/* Знак без кружка и подложки: серебряный штрих, который прочерчивается сам.
   Рисование сделано через stroke-dasharray — линия «проявляется» от начала
   к концу, это дешевле любой подложки и не спорит с тёмным фоном. */
.ot-ico{flex:none;width:26px;height:26px;display:grid;place-items:center}
.ot-ico svg{width:24px;height:24px;fill:none;stroke-width:2.6;
  stroke-linecap:round;stroke-linejoin:round;
  stroke:url(#otSilver);}
/* pathLength="1" в разметке приводит длину любого штриха к единице —
   не надо подгонять dasharray под галочку и минус по отдельности */
.ot-ico svg path{
  stroke-dasharray:1;
  stroke-dashoffset:1;
}
.opt-toast.show .ot-ico svg path{
  animation:otDraw .5s cubic-bezier(.22,.61,.24,1) .06s forwards;
}
@keyframes otDraw{to{stroke-dashoffset:0}}
.ot-txt{display:flex;flex-direction:column;gap:2px;min-width:0}
.ot-txt b{font:700 .94rem/1.3 "Manrope",sans-serif;color:#fff}
.ot-txt i{font:600 .8rem/1.3 "Manrope",sans-serif;font-style:normal;color:#9aa0ad}

/* на телефоне снизу своя панель навигации — окошко поднимаем над ней */
@media(max-width:860px){
  .opt-toast{bottom:calc(84px + env(safe-area-inset-bottom,0px))}
}
@media(prefers-reduced-motion:reduce){
  .opt-toast{transition:opacity .2s}
  .opt-toast.show .ot-ico svg path{animation:none;stroke-dashoffset:0}
}

/* ===== «Характеристики» у мышей =========================================== */

/* Кнопка без рамки — просто строка с уголком. Стоит внутри карточки-
   переключателя, поэтому в options.js её клик перехватывается раньше. */
.mspec-btn{
  display:inline-flex;align-items:center;gap:5px;
  flex:none;padding:0;
  font:600 .76rem/1 "Manrope",sans-serif;color:#9aa0ad;
  background:none;border:none;cursor:pointer;
  transition:color .22s;
}
.mspec-btn .i-chev{width:13px;height:13px;fill:none;stroke:currentColor;
  stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;transition:transform .25s}
.mspec-btn:hover{color:#fff}
.mspec-btn:hover .i-chev{transform:translateY(2px)}
.mspec-btn:focus-visible{outline:2px solid var(--accent2,#ff3d44);outline-offset:3px;border-radius:4px}

/* список в разметке скрыт — он источник для окна и остаётся в исходном коде */
.mspec-data{display:none}

.mspec-modal{position:fixed;inset:0;z-index:130;display:none}
.mspec-modal.show{display:block}
html.mspec-lock{overflow:hidden}

.mspec-back{position:absolute;inset:0;background:rgba(4,4,6,.72);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  animation:mspecFade .25s ease both}

.mspec-win{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(620px,92vw);max-height:min(78vh,760px);
  overflow:auto;-webkit-overflow-scrolling:touch;
  padding:30px 32px 32px;
  border:1px solid rgba(255,255,255,.12);
  border-radius:20px;
  background:linear-gradient(180deg,#131318,#0b0b0e);
  box-shadow:0 40px 90px -30px rgba(0,0,0,.95);
  animation:mspecIn .34s cubic-bezier(.16,1,.3,1) both;
}
/* первой строкой — название раздела, тем же приёмом, что заголовки блока:
   красный штрих слева и тающая линия справа */
.mspec-eyebrow{
  display:flex;align-items:center;gap:12px;
  margin:0 34px 12px 0;
  font-family:"Manrope",sans-serif;font-weight:700;font-size:.7rem;
  letter-spacing:.14em;text-transform:uppercase;color:#9aa0ad;
}
.mspec-eyebrow::before{
  content:"";flex:none;width:26px;height:2px;border-radius:2px;
  background:linear-gradient(90deg,#e10600,#ff6a3d,#e10600);
  background-size:220% 100%;
  animation:ohue 9s linear infinite;
}
.mspec-eyebrow::after{
  content:"";flex:1;height:1px;
  background:linear-gradient(90deg,rgba(255,255,255,.13),transparent);
}
.mspec-win h3{
  margin:0 34px 18px 0;
  font-family:"Manrope",sans-serif;font-weight:800;font-size:1.3rem;
  letter-spacing:-.02em;color:#fff;
}
.mspec-x{
  position:absolute;right:16px;top:16px;
  width:34px;height:34px;display:grid;place-items:center;
  border:1px solid rgba(255,255,255,.14);border-radius:50%;
  background:rgba(255,255,255,.04);cursor:pointer;
  transition:border-color .22s,background .22s;
}
.mspec-x svg{width:15px;height:15px;fill:none;stroke:#c9cdd6;stroke-width:2;stroke-linecap:round}
.mspec-x:hover{border-color:rgba(255,255,255,.34);background:rgba(255,255,255,.08)}

/* пункты столбиком, маркер — точка из псевдоэлемента */
.mspec-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
.mspec-list li{
  position:relative;
  padding:10px 0 10px 20px;
  font-size:.92rem;line-height:1.5;color:#c9cdd6;
  border-bottom:1px solid rgba(255,255,255,.07);
}
.mspec-list li:last-child{border-bottom:none}
.mspec-list li::before{
  content:"";position:absolute;left:2px;top:19px;
  width:5px;height:5px;border-radius:50%;background:#9aa0ad;
}

@keyframes mspecFade{from{opacity:0}to{opacity:1}}
@keyframes mspecIn{from{opacity:0;transform:translate(-50%,-46%) scale(.97)}
                   to{opacity:1;transform:translate(-50%,-50%) scale(1)}}

@media(max-width:520px){
  .mspec-win{padding:26px 20px 24px;width:94vw;max-height:82vh}
  .mspec-win h3{font-size:1.14rem}
  .mspec-list li{font-size:.88rem}
}
@media(prefers-reduced-motion:reduce){
  .mspec-back,.mspec-win{animation:none}
  .mspec-eyebrow::before{animation:none}
}

/* ===== кнопки под списком выбранного ====================================== */

/* Цена стоит сама по себе, ниже перечень допов, и только потом обе кнопки —
   прижаты вправо, туда же, где были раньше. */
.buy-actions{
  display:flex;align-items:center;justify-content:flex-end;
  gap:14px;flex-wrap:wrap;
  margin-top:4px;
}
.buy-actions .help{margin:0}
.buy-actions .cta{margin:0}
.buy-actions .cta-wrap{margin:0}

@media(max-width:900px){
  .buy-actions{margin-top:2px}
  .buy-actions .help{width:100%;justify-content:center}
  .buy-actions .cta{width:100%}
  .buy-actions .cta-wrap{width:100%}
}


/* ── Мыши на телефоне: лента вбок ─────────────────────────────────────────
   Четыре карточки в столбик занимали почти три экрана, и до «Доставки»
   приходилось долго листать. Теперь это горизонтальная лента с прилипанием
   к карточке, как «Готовые конфигурации» на главной. Поля −20px по бокам:
   лента идёт от края до края, а карточки всё равно стоят по сетке. */
@media(max-width:620px){
  /* Колонка .page на телефоне описана как 1fr, а 1fr = minmax(auto,1fr):
     такая дорожка не может стать уже своего содержимого. Лента с четырьмя
     карточками в ряд давала минимум ~1080px, дорожка раздувалась до него и
     секция вылезала за экран вместо того, чтобы прокручиваться. minmax(0,1fr)
     разрешает дорожке быть уже — только после этого лента начинает листаться. */
  main.page{grid-template-columns:minmax(0,1fr)}

  .mouse-grid{
    display:flex;grid-template-columns:none;grid-template-rows:none;
    flex-wrap:nowrap;align-items:stretch;
    overflow-x:auto;
    /* min-width:0 обязателен: .below-inner — колоночный флекс, и без него
       минимальная ширина ленты считается по сумме карточек. Секция .below
       раздувалась до 1080px и вылезала за экран вместо прокрутки. */
    min-width:0;
    gap:12px;margin:0 -20px;padding:4px 20px 14px;
    /* v372: было mandatory. Жёсткое прилипание обязывает браузер ВСЕГДА
       стоять на точке, поэтому лента цепляет палец даже при почти
       вертикальном жесте и переснапывается при любом изменении размеров
       окна — на телефоне адресная строка прячется при прокрутке, и это
       происходит постоянно. proximity прилипает только когда жест
       закончился рядом с точкой, и края отпускает.
       overscroll-behavior-x — чтобы долистанная до упора лента не отдавала
       жест странице и не вызывала браузерный жест «назад». */
    scroll-snap-type:x proximity;overscroll-behavior-x:contain;
    scroll-padding:0 20px;
    -webkit-overflow-scrolling:touch;scrollbar-width:none;
    /* v366: было touch-action:pan-x pinch-zoom — оно запрещало вертикальный
       жест во всей области ленты, включая прокрутку страницы под ней.
       Разрешаем оба направления, а перехватывать ленте нечего: лишней
       вертикали у неё нет и overflow-y:hidden это закрепляет. */
    touch-action:pan-x pan-y pinch-zoom;overflow-y:hidden}
  .mouse-grid::-webkit-scrollbar{display:none}

  /* ── v381 · ЛЕНТА СНОВА НАТИВНАЯ ──────────────────────────────────────────
     В v377–v378 лента листалась своим обработчиком: браузеру оставляли только
     вертикаль (touch-action:pan-y), а scrollLeft крутил скрипт. Это была
     ошибка, и сразу по двум причинам.

     1) РЫВКИ. Родная прокрутка идёт в потоке композитора и обновляется каждый
        кадр экрана. Скрипт же двигает ленту в обработчике touchmove, то есть в
        главном потоке и с частотой прихода событий касания. Любая занятая
        отрисовка рядом — и лента запаздывает: получается ход «ступеньками».
        Ускорить это нельзя в принципе, это свойство самого подхода.

     2) ВЕРТИКАЛЬ НАД СНИМКОМ. Направление жеста скрипт решал по первым пяти
        пикселям и при перевесе горизонтали звал preventDefault(). Палец редко
        идёт строго вниз — по дуге от большого пальца первые пиксели часто
        уходят вбок, жест признавался горизонтальным, и страница замирала на
        всё касание. Отсюда и «скрол не работает, если вести по картинке мыши».

     Возвращаемся ровно к рецепту главной страницы (.catsec .grid.grid-2 и
     #ai .ai-grid): направление выбирает браузер, ход считает композитор.
     Условия, при которых этот рецепт работает без осечек, — ниже. */
  /* хвостик, чтобы у последней карточки остался отступ справа */
  .mouse-grid::after{content:"";flex:0 0 6px}
  /* Выше по файлу карточка объявлена гридом с subgrid — так цены выравнивались
     по общим строкам сетки. В ленте родитель уже не грид, subgrid работать
     не может, поэтому карточка возвращается к обычной колонке. Правила эти
     идут ПОЗЖЕ в файле, отсюда и !important. */
  .mouse-grid .mcard{
    flex:0 0 78%;scroll-snap-align:center;
    /* Условие «без осечек» №1: карточка обязана целиком помещаться между
       шапкой и нижней навигацией. Если она выше видимой области, палец нигде
       не попадает мимо ленты, и вертикальный жест снова начинает залипать —
       ровно та же история, что была в «Рабочих станциях» (v367). */
    display:flex!important;flex-direction:column;
    grid-row:auto!important;grid-template-rows:none!important;
    gap:12px;min-width:0}
  /* снимок прижат книзу — тогда нижние кромки карточек стоят на одной линии
     даже при разной длине названий */
  .mouse-grid .mcard .shot{margin-top:auto}
  .mouse-grid .mcard-head{min-height:0}

  /* Условие «без осечек» №2: у ленты не должно быть НИ ПИКСЕЛЯ лишней
     вертикали — иначе палец будет двигать эти пиксели внутри ленты вместо
     страницы (так было на главной, v359). Держат его два правила выше:
     overflow-y:hidden у ленты и margin-top:auto у снимка, который прижимает
     карточки к общей нижней линии. Анимации появления, которая оставляла бы
     карточкам сдвиг translateY, на страницах ПК нет — специально проверено,
     scrollHeight-clientHeight = 0. Если такая анимация здесь когда-нибудь
     появится, карточкам понадобится сброс opacity/transform, как на главной. */

  /* Условие «без осечек» №3: снимок не должен перехватывать касание. На iOS
     палец, начавший движение с картинки, может уйти в её перетаскивание
     (drag lift) — жест теряется целиком, и не прокручивается ни лента, ни
     страница. pointer-events:none отдаёт касание самой карточке, запрет
     перетаскивания закрывает старые сборки Safari. Клики не страдают:
     карточка сама по себе кнопка, у снимка своих обработчиков нет. */
  .mouse-grid img{
    pointer-events:none;
    -webkit-user-drag:none;user-drag:none;
    -webkit-touch-callout:none}
  .mouse-grid .mcard,.mouse-grid .mcard *{
    -webkit-touch-callout:none;
    -webkit-tap-highlight-color:transparent}
}

/* ── Подсказка «листайте вбок» ─────────────────────────────────────────────
   Видна только на телефоне и только пока ленту не тронули: первый же сдвиг
   вбок снимает её (класс на .mouse-grid ставит options.js). */
.rail-hint{display:none}
@media(max-width:620px){
  .rail-hint{
    display:flex;align-items:center;gap:7px;
    margin:8px 0 -2px;
    font:600 .74rem/1 "Manrope",sans-serif;letter-spacing:.02em;
    color:#8b909b;
    transition:opacity .3s ease}
  .rail-hint b{
    display:inline-block;color:#e10600;font-size:.9rem;
    animation:railNudge 1.7s ease-in-out infinite}
  .rail-hint.is-off{opacity:0;pointer-events:none}
}
@keyframes railNudge{
  0%,100%{transform:translateX(0)}
  50%{transform:translateX(5px)}
}
@media(prefers-reduced-motion:reduce){
  .rail-hint b{animation:none}
}

/* ===== Вентиляторы для корпуса ============================================
   Карточка одна и стоит в .opt-grid.one. Общее правило «карточке с выбором
   цвета — две колонки» здесь только ломает сетку: в одноколоночной дорожке
   span 2 заводит вторую, неявную колонку и карточка уезжает влево. */
.opt-grid.one > .ocard:has(.csw-row){grid-column:auto}

/* пояснение про привязку цвета: тот же мелкий кегль, что у подписей опций */
.fan-note{
  display:flex;align-items:flex-start;gap:9px;
  margin:0;
  font:500 .79rem/1.5 "Manrope",sans-serif;color:#8b909b;
}
.fan-note svg{
  flex:none;width:15px;height:15px;margin-top:2px;
  fill:none;stroke:#9aa0ad;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;
}
.fan-note b{color:#cfd4de;font-weight:700}

/* комплект, который уже в сборке: карточка не переключается, но цвет у неё
   живой — это выбор цвета сборки, а не выбор опции */
.ocard.is-fixed{cursor:default}

/* раздел заблокирован (Origin Mini, Obsidian): снимок гасим, обводку при
   наведении не зажигаем — иначе карточка выглядит кликабельной */
.ocard.is-locked{opacity:.72}
.ocard.is-locked .shot img{filter:grayscale(.9) brightness(.6)}
.opt-mark.lock svg{stroke:#8b909b;stroke-width:1.7;fill:none}
.opt-price.off{
  font-weight:700;font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;
  color:#8b909b;
  border-color:rgba(255,255,255,.10);
  background:rgba(255,255,255,.02);
}
@media(hover:hover){
  .ocard.is-locked:hover{transform:none;border-color:rgba(255,255,255,.08)}
  .ocard.is-locked:hover::before{opacity:0;animation:none}
  .ocard.is-locked:hover .shot img{transform:none}
}

/* строка «включено» в перечне под ценой: кнопки «удалить» у неё нет,
   поэтому держим ей ту же высоту, что и у платных строк */
.ot-row.is-fixed{min-height:28px}
.ot-row.is-fixed .ot-p{
  font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;color:#cfd4de;
}

/* ===== пара «Вентиляторы» + «Доставка» ====================================
   Стоят рядом, как «Коврик» и «Стол». У карточки вентиляторов сверху есть ряд
   цветов и подпись про привязку, у доставки их нет — если ничего не делать,
   низ пары расходится примерно на 100px. Высоту ряда задаёт карточка
   вентиляторов (её снимок держит кадр 4/3), а снимок доставки забирает весь
   остаток своей карточки.
   Только на широком экране: ниже 900px пара распадается в колонку, карточки
   становятся авто-высоты, и flex:1 у снимка схлопнул бы его в ноль. */
@media(min-width:901px){
  .pair-grid.fan-pair{align-items:stretch}
  .fan-pair .pair-col > .opt-grid{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
  .fan-pair .ocard{height:100%}
  .fan-pair .pair-col:last-child .opt-grid.one .shot{aspect-ratio:auto;flex:1;min-height:0}
}

/* ═══════════════════════════════════════════════════════════════════════════
   ШИРОКИЕ ЭКРАНЫ · 2K и выше · страницы сборок              (v378, правка v386)

   Тот же приём, что и на главной (блок #wide-2k в index.html): всё, что задано
   пикселями, продолжает расти долей от ширины экрана — той самой, которую оно
   занимало на 1920. Ниже 1920 не меняется ничего: нижняя граница каждого
   clamp() равна нынешнему значению.

   ── ОТМЕНЕНО В v386: строка про снимок ПК ──────────────────────────────────
   Здесь стояло `.pc-wrap{max-width:clamp(680px,35.42vw,900px)}`. Ошибка была в
   посылке «жёсткий потолок 680px»: 680 — это потолок ТОЛЬКО у Essential. У
   каждой страницы он свой, и задан он в самой странице, а options.css
   подключается ПОСЛЕ её <style> — при равной специфичности побеждал этот файл.
   В итоге с 1600px все тринадцать страниц схлопывались в один общий размер:

     Pro 1035 → 680 · Quantum/REYJIN/Matrix/BTC Whale 880 → 680
     Environ/Obsidian 840 → 680 · Atmos 820 → 680 · Tarkov 750 → 680
     CS2 690 → 680 · Origin 620 → 680 (единственный, кто вырос)

   То есть правило, задуманное как рост на 2K, на деле УМЕНЬШАЛО снимок почти
   везде. Строка убрана: каждая страница снова держит свой размер, как в v377.
   Если рост на 2K понадобится — его надо делать множителем к собственному
   значению страницы, а не общим потолком.
   ═════════════════════════════════════════════════════════════════════════ */
@media(min-width:1600px){
  /* до +10%: полностью линейный рост (×1,33) на 2K-мониторе даёт физически
     слишком крупный текст — плотность пикселей там выше, чем на FullHD */
  html{font-size:clamp(16px,.833vw,17.6px)}
}
