<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://www.pandoraburo.ru/" xml:lang="ru">
  <id>https://www.pandoraburo.ru/krupnogabaritnye-pruzhiny</id>
  <link href="https://www.pandoraburo.ru/krupnogabaritnye-pruzhiny.xml" rel="self"/>
  <title>Крупногабаритные пружины</title>
  <subtitle type="html">&lt;html lang="ru"&gt;
&lt;head&gt;
&lt;meta charset="UTF-8"&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;

&lt;title&gt;Пружины купить от производителя — прайс-лист ООО Арсенал-Деталь&lt;/title&gt;

&lt;meta name="description" content="Пружины сжатия, растяжения, СППК, инструментальные ISO, для грохотов и дробилок. Цены, артикулы, наличие. Скидки от объёма партии, доставка по России. 8 (902) 873-36-90."&gt;

&lt;meta name="keywords" content="пружины, пружины сжатия, пружины растяжения, пружины СППК, инструментальные пружины ISO, пружины для грохотов, пружины для дробилок, пружина СМД 121, пружина ГИСТ 72, купить пружины, пружины от производителя, прайс-лист на пружины, пружины цена, пружины с доставкой, изготовление пружин по чертежам, ООО Арсенал-Деталь, Арсенал-Деталь пружины, пружины Арсенал-Деталь, пружины оптом, пружины для промышленности, пружины для механизмов, пружины для оборудования, ISO 10243"&gt;

&lt;meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"&gt;
&lt;meta name="author" content="ООО «Арсенал-Деталь»"&gt;
&lt;meta name="geo.region" content="RU"&gt;
&lt;meta name="geo.placename" content="Россия"&gt;
&lt;meta name="language" content="Russian"&gt;
&lt;link rel="canonical" href="https://arsenal-detal.ru/pruzhiny" /&gt;

&lt;meta property="og:type" content="website"&gt;
&lt;meta property="og:site_name" content="ООО «Арсенал-Деталь»"&gt;
&lt;meta property="og:title" content="Пружины купить от производителя — прайс-лист"&gt;
&lt;meta property="og:description" content="Пружины сжатия, растяжения, СППК, ISO, для грохотов и дробилок. Артикулы, наличие, цены. Скидки от объёма. 8 (902) 873-36-90."&gt;
&lt;meta property="og:url" content="https://arsenal-detal.ru/pruzhiny"&gt;
&lt;meta property="og:locale" content="ru_RU"&gt;

&lt;meta name="twitter:card" content="summary_large_image"&gt;
&lt;meta name="twitter:title" content="Пружины — прайс-лист от производителя"&gt;
&lt;meta name="twitter:description" content="Сжатия, растяжения, СППК, ISO, грохоты/дробилки. Цены, артикулы, скидки от объёма. ООО «Арсенал-Деталь»."&gt;

&lt;script type="application/ld+json"&gt;
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "ООО «Арсенал-Деталь»",
  "url": "https://arsenal-detal.ru",
  "telephone": "+79028733690",
  "email": "arsenal-detal@list.ru",
  "taxID": "6670215323",
  "vatID": "667001001",
  "identifier": "1086670018445",
  "description": "Изготовление и продажа пружин сжатия, растяжения, СППК, инструментальных ISO и специальных по чертежам и ТУ.",
  "address": {
    "@type": "PostalAddress",
    "addressCountry": "RU",
    "addressRegion": "Свердловская область"
  },
  "contactPoint": {
    "@type": "ContactPoint",
    "telephone": "+79028733690",
    "contactType": "sales",
    "availableLanguage": "Russian"
  }
}
&lt;/script&gt;

&lt;script type="application/ld+json"&gt;
{
  "@context": "https://schema.org",
  "@type": "ItemList",
  "name": "Пружины — прайс-лист",
  "description": "Каталог пружин: сжатия, растяжения, СППК, ISO, грохоты и дробилки",
  "numberOfItems": 127,
  "itemListElement": [
    {"@type":"ListItem","position":1,"item":{"@type":"Product","name":"Пружина сжатия 25×130×253","sku":"PS-25-130-253","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"9000","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":2,"item":{"@type":"Product","name":"Пружина сжатия 20×130×246","sku":"PS-20-130-246","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"7740","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":3,"item":{"@type":"Product","name":"Пружина сжатия 21×132×246","sku":"PS-21-132-246","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"8100","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":4,"item":{"@type":"Product","name":"Пружина сжатия 19×94×185 60С2А","sku":"PS-19-94-185-60S2A","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"4500","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":5,"item":{"@type":"Product","name":"Пружина растяжения 4×30×350","sku":"PR-4-30-350","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"1440","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":6,"item":{"@type":"Product","name":"Пружина растяжения 7×50×603 60С2А","sku":"PR-7-50-603-60S2A","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"6300","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":7,"item":{"@type":"Product","name":"Пружина сжатия СППК №79","sku":"SPPK-79","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"31290","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":8,"item":{"@type":"Product","name":"Пружина сжатия СППК №22","sku":"SPPK-22","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"13090","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":9,"item":{"@type":"Product","name":"Пружина СМД 121","sku":"SMD-121","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"16170","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":10,"item":{"@type":"Product","name":"Пружина ГИСТ 72","sku":"GIST-72","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"19920","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":11,"item":{"@type":"Product","name":"Инструментальная пружина ISO красная-тяжёлая 63×305","sku":"ISO-63-305-R","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"13940","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}},
    {"@type":"ListItem","position":12,"item":{"@type":"Product","name":"Инструментальная пружина ISO жёлтая-сверхтяжёлая 63×305","sku":"ISO-63-305-Y","brand":{"@type":"Brand","name":"Арсенал-Деталь"},"offers":{"@type":"Offer","price":"13940","priceCurrency":"RUB","availability":"https://schema.org/InStock"}}}
  ]
}
&lt;/script&gt;

&lt;script type="application/ld+json"&gt;
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {"@type":"ListItem","position":1,"name":"Главная","item":"https://arsenal-detal.ru"},
    {"@type":"ListItem","position":2,"name":"Пружины","item":"https://arsenal-detal.ru/pruzhiny"}
  ]
}
&lt;/script&gt;

&lt;style&gt;
  :root{
    --gold:#FFD700;--gold-light:#FFE55C;--gold-deep:#B8860B;
    --bg:#0a0a0a;--muted:#9a8040;--border:rgba(212,175,55,.35);
    --green:#7dff7d;--green-dark:#3aa03a;--orange:#FF8C00;
    --red:#ff8a7a;--cyan:#6ee8e4;--yellow:#FFE55C;
  }
  *{box-sizing:border-box;margin:0;padding:0}
  body{background:#050505;color:#e8e8e8;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Arial,sans-serif;padding:20px 14px 200px;line-height:1.5;}
  .wrap{max-width:1800px;margin:0 auto}

  .seo-hidden{
    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;
    color:transparent !important;pointer-events:none !important;
  }

  .header{background:radial-gradient(120% 120% at 20% 0%,rgba(255,215,0,.25),transparent 55%),linear-gradient(135deg,#1a1408,#0a0a0a);border:2px solid var(--gold);border-radius:14px;padding:28px 24px;text-align:center;margin-bottom:16px;box-shadow:0 0 40px rgba(255,215,0,.25),0 6px 22px rgba(0,0,0,.6);}
  .tag{display:inline-block;background:var(--gold);color:#0a0a0a;font-size:10px;font-weight:800;letter-spacing:2px;padding:4px 14px;border-radius:999px;margin-bottom:14px;box-shadow:0 0 16px rgba(255,215,0,.7);}
  .header h1{font-size:28px;font-weight:900;letter-spacing:3px;color:var(--gold);text-transform:uppercase;margin-bottom:12px;text-shadow:0 0 10px rgba(255,215,0,.95),0 0 25px rgba(255,199,0,.8);animation:goldPulse 3s ease-in-out infinite;}
  @keyframes goldPulse{0%,100%{text-shadow:0 0 10px rgba(255,215,0,.95),0 0 25px rgba(255,199,0,.8);}50%{text-shadow:0 0 15px rgba(255,215,0,1),0 0 35px rgba(255,199,0,.95);}}
  .line{width:80px;height:3px;background:var(--gold);margin:0 auto 12px;border-radius:2px;box-shadow:0 0 15px var(--gold);}
  .header p{color:var(--gold-light);font-size:14px;opacity:.95;}
  .company-info{background:rgba(255,215,0,.05);border:1px solid var(--border);border-radius:8px;padding:12px;margin-top:12px;font-size:12px;color:var(--gold-light);}
  .company-info b{color:var(--gold);}

  .discount-banner{
    background:linear-gradient(135deg,rgba(125,255,125,.12),rgba(10,10,10,.9));
    border:3px solid var(--green);border-radius:16px;padding:24px 26px;margin-bottom:16px;
    text-align:center;position:relative;box-shadow:0 0 40px rgba(125,255,125,.2);transition:all .4s;
  }
  .discount-banner.active{
    background:linear-gradient(135deg,rgba(125,255,125,.25),rgba(10,10,10,.9));
    box-shadow:0 0 60px rgba(125,255,125,.5),inset 0 0 30px rgba(125,255,125,.15);
    animation:discountActive 1.5s ease-in-out infinite;
  }
  @keyframes discountActive{
    0%,100%{box-shadow:0 0 60px rgba(125,255,125,.5),inset 0 0 30px rgba(125,255,125,.15);}
    50%{box-shadow:0 0 80px rgba(125,255,125,.8),inset 0 0 40px rgba(125,255,125,.25);}
  }
  .discount-banner::before{
    content:'СКИДКА ОТ ОБЪЁМА';
    position:absolute;top:-14px;left:50%;transform:translateX(-50%);
    background:#0a0a0a;color:var(--green);padding:4px 22px;border:2px solid var(--green);border-radius:999px;
    font-size:12px;font-weight:900;letter-spacing:3px;text-shadow:0 0 15px rgba(125,255,125,1);
    white-space:nowrap;box-shadow:0 0 20px rgba(125,255,125,.6);
  }
  .discount-banner h3{color:var(--green);font-size:20px;font-weight:900;letter-spacing:1.5px;text-transform:uppercase;margin-bottom:12px;text-shadow:0 0 15px rgba(125,255,125,.7);}
  .discount-banner p{color:#c8e8c8;font-size:14px;margin-bottom:16px;line-height:1.6;}
  .discount-banner p b{color:#fff;}

  .progress-wrap{max-width:800px;margin:0 auto 16px;background:#0a0a0a;border:2px solid var(--green);border-radius:999px;height:40px;position:relative;overflow:hidden;}
  .progress-fill{height:100%;background:linear-gradient(90deg,#3aa03a,#7dff7d,#3aa03a);background-size:200% 100%;width:0%;transition:width .5s ease-out;animation:progressShine 2s linear infinite;border-radius:999px;box-shadow:0 0 20px rgba(125,255,125,.7);}
  @keyframes progressShine{0%{background-position:200% 0;}100%{background-position:-200% 0;}}
  .progress-label{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff;font-size:13px;font-weight:900;text-shadow:0 1px 3px rgba(0,0,0,.9);z-index:2;letter-spacing:.5px;text-align:center;padding:0 12px;}
  .progress-label b{color:var(--gold);font-size:14px;}

  .discount-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;max-width:1000px;margin:0 auto;}
  @media(max-width:800px){.discount-stats{grid-template-columns:repeat(2,1fr);}}
  @media(max-width:450px){.discount-stats{grid-template-columns:1fr;}}
  .discount-stat{background:rgba(0,0,0,.5);border:1px solid var(--green);border-radius:10px;padding:12px;display:flex;flex-direction:column;gap:4px;text-align:center;}
  .discount-stat .lbl{font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:1.2px;color:var(--green);opacity:.8;}
  .discount-stat .val{font-size:18px;font-weight:900;color:var(--green);font-variant-numeric:tabular-nums;}
  .discount-stat .val.new{color:var(--gold-light);font-size:20px;}

  .cta-block{background:linear-gradient(135deg,rgba(255,215,0,.15),rgba(10,10,10,.9));border:3px solid var(--gold);border-radius:16px;padding:24px 20px;margin-bottom:16px;text-align:center;box-shadow:0 0 40px rgba(255,215,0,.3);position:relative;}
  .cta-block::before{content:'★';position:absolute;top:-18px;left:50%;transform:translateX(-50%);background:#0a0a0a;color:var(--gold);padding:0 18px;font-size:26px;text-shadow:0 0 20px rgba(255,215,0,1);animation:starPulse 1.5s ease-in-out infinite;}
  @keyframes starPulse{0%,100%{transform:translateX(-50%) scale(1);}50%{transform:translateX(-50%) scale(1.2);}}
  .cta-block h2{color:var(--gold);font-size:22px;font-weight:900;letter-spacing:2px;text-transform:uppercase;margin-bottom:10px;text-shadow:0 0 15px rgba(255,215,0,.7);}
  .cta-block p{color:var(--gold-light);font-size:15px;margin-bottom:16px;line-height:1.6;}
  .cta-block p b{color:#fff;}
  .cta-counter{display:inline-block;background:#0a0a0a;border:2px solid var(--gold);border-radius:999px;padding:10px 24px;color:var(--gold);font-size:16px;font-weight:900;letter-spacing:1px;margin-bottom:14px;}
  .cta-counter b{color:#fff;font-size:22px;}
  .cta-buttons{display:flex;gap:12px;justify-content:center;flex-wrap:wrap;margin-top:14px;}
  .btn-big{display:inline-flex;align-items:center;gap:10px;padding:16px 32px;border-radius:999px;border:2px solid var(--gold);background:transparent;color:var(--gold);font-size:16px;font-weight:900;cursor:pointer;transition:.2s;font-family:inherit;letter-spacing:1px;text-transform:uppercase;}
  .btn-big:hover{background:var(--gold);color:#0a0a0a;transform:scale(1.03);}
  .btn-big.primary{background:linear-gradient(135deg,#FFD700,#FF8C00);color:#0a0a0a;border-color:#FFD700;box-shadow:0 0 25px rgba(255,215,0,.6);animation:btnPulse 2s ease-in-out infinite;}
  @keyframes btnPulse{0%,100%{box-shadow:0 0 25px rgba(255,215,0,.6);}50%{box-shadow:0 0 40px rgba(255,215,0,.9),0 0 70px rgba(255,140,0,.5);}}
  .btn-big.primary:hover{transform:scale(1.05);}

  .stats{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:16px;}
  @media(max-width:800px){.stats{grid-template-columns:repeat(2,1fr);}}
  @media(max-width:500px){.stats{grid-template-columns:1fr;}}
  .stat{background:var(--bg);border:1px solid var(--gold);border-radius:12px;padding:16px;text-align:center;}
  .lbl{font-size:10px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--gold);opacity:.7;margin-bottom:6px;}
  .val{font-size:22px;font-weight:800;color:var(--gold-light);line-height:1.1;}
  .val.sm{font-size:16px;}
  .val.green{color:var(--green);}

  .cat-chips{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px;align-items:center;}
  .chip{padding:8px 16px;border-radius:999px;border:1px solid var(--gold);background:transparent;color:var(--gold);font-size:12px;font-weight:800;cursor:pointer;transition:.15s;font-family:inherit;text-transform:uppercase;letter-spacing:.5px;}
  .chip:hover{background:rgba(255,215,0,.15);}
  .chip.on{background:var(--gold);color:#0a0a0a;}
  .chip .cnt{opacity:.65;margin-left:4px;font-variant-numeric:tabular-nums;}
  .chip.on .cnt{opacity:.9;}
  .iso-sub{display:flex;gap:6px;margin-left:auto;flex-wrap:wrap;}
  .chip.iso{font-size:11px;padding:6px 12px;border-color:var(--border);color:var(--gold-light);}
  .chip.iso.on{background:var(--gold-light);color:#0a0a0a;border-color:var(--gold-light);}

  .toolbar{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px;align-items:center;}
  .search{flex:1;min-width:250px;padding:10px 14px;border:1px solid var(--gold);border-radius:9px;font-size:13px;background:#0a0a0a;color:var(--gold-light);outline:none;font-family:inherit;font-weight:600;}
  .search::placeholder{color:rgba(212,175,55,.4);}
  .counter{color:var(--gold);font-size:13px;white-space:nowrap;padding:10px 16px;border:1px solid var(--gold);border-radius:9px;background:#0a0a0a;font-weight:800;}
  .btn{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;border-radius:9px;border:1px solid var(--gold);background:transparent;color:var(--gold);font-size:13px;font-weight:700;cursor:pointer;transition:.15s;font-family:inherit;}
  .btn:hover{background:var(--gold);color:#0a0a0a;}
  .btn.primary{background:var(--gold);color:#0a0a0a;}
  .btn.green{background:linear-gradient(135deg,#7dff7d,#3aa03a);color:#0a0a0a;border-color:#7dff7d;}
  .btn.red{background:transparent;color:var(--red);border-color:var(--red);}
  .btn.red:hover{background:var(--red);color:#0a0a0a;}

  .table-block{background:var(--bg);border:1px solid var(--gold);border-radius:14px;padding:20px;margin-bottom:16px;position:relative;}
  .block-title{color:var(--gold);font-size:12px;font-weight:800;letter-spacing:2px;text-align:center;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid var(--border);text-transform:uppercase;text-shadow:0 0 12px rgba(255,215,0,.6);}
  .select-hint{position:absolute;top:-14px;left:0;background:linear-gradient(135deg,#FFD700,#FF8C00);color:#0a0a0a;font-size:11px;font-weight:900;letter-spacing:1.5px;padding:6px 18px;border-radius:999px;box-shadow:0 0 20px rgba(255,215,0,.7);text-transform:uppercase;animation:hintPulse 1.5s ease-in-out infinite;z-index:5;white-space:nowrap;}
  @keyframes hintPulse{0%,100%{box-shadow:0 0 20px rgba(255,215,0,.7);transform:scale(1);}50%{box-shadow:0 0 35px rgba(255,215,0,1),0 0 60px rgba(255,140,0,.6);transform:scale(1.05);}}

  .table-wrap{overflow:auto;max-height:65vh;border-radius:8px;border:1px solid var(--gold);}
  table{width:100%;table-layout:auto;border-collapse:collapse;background:#0a0a0a;font-size:13px;}
  th,td{padding:8px 6px;text-align:left;border-bottom:1px solid rgba(212,175,55,.2);vertical-align:middle;color:#fff;background:transparent;white-space:nowrap;}
  th{position:sticky;top:0;z-index:2;background:#0a0a0a;color:#fff;font-weight:800;text-transform:uppercase;font-size:10px;letter-spacing:1px;border-bottom:1px solid var(--gold);cursor:pointer;user-select:none;}
  th:hover{background:#1a1408;}
  th.sortable::after{content:' ⇅';opacity:.5;margin-left:4px;font-size:9px;}
  th.asc::after{content:' ▲';opacity:1;color:#fff;}
  th.desc::after{content:' ▼';opacity:1;color:#fff;}
  th.num,td.num{text-align:right;font-variant-numeric:tabular-nums;}
  th.col-star,td.col-star{width:40px;text-align:center;padding:8px 4px;position:sticky;top:0;background:linear-gradient(180deg,#1a1408,#0a0a0a) !important;}
  th.col-star::before{content:'▼';position:absolute;top:100%;left:50%;transform:translateX(-50%);color:var(--gold);font-size:20px;line-height:1;text-shadow:0 0 12px rgba(255,215,0,1);animation:arrowBounce 1s ease-in-out infinite;pointer-events:none;}
  @keyframes arrowBounce{0%,100%{transform:translateX(-50%) translateY(0);opacity:1;}50%{transform:translateX(-50%) translateY(6px);opacity:.7;}}
  th.col-qty,td.col-qty{width:64px;text-align:center;padding:8px 4px;}

  tbody tr{transition:background .15s;}
  tbody tr:hover{background:#1a1408;}
  tbody tr.picked{background:linear-gradient(90deg,rgba(255,215,0,.15),rgba(255,215,0,.04));box-shadow:inset 4px 0 0 var(--gold);}
  tbody tr.discount-active{background:linear-gradient(90deg,rgba(125,255,125,.15),rgba(255,215,0,.04));box-shadow:inset 4px 0 0 var(--green);}

  td.article{font-family:'Courier New',monospace;font-size:12px;color:#fff;}
  td b{color:#fff;}
  td.price{font-weight:800;color:#fff;font-size:14px;}
  td.price.discount{color:var(--green);text-shadow:0 0 10px rgba(125,255,125,.5);}
  td.price-old{color:#fff;opacity:.55;text-decoration:line-through;font-size:12px;}

  td.col-qty input.qty{width:52px;padding:5px 4px;border:1px solid var(--border);border-radius:6px;background:#0a0a0a;color:#fff;font-size:13px;font-weight:800;text-align:center;font-family:inherit;outline:none;font-variant-numeric:tabular-nums;transition:.2s;}
  td.col-qty input.qty:focus{border-color:var(--gold);box-shadow:0 0 0 3px rgba(255,215,0,.2);}
  tbody tr.picked td.col-qty input.qty{border-color:var(--gold);color:#fff;box-shadow:0 0 8px rgba(255,215,0,.4);}

  .badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:10px;font-weight:800;text-transform:uppercase;background:rgba(212,175,55,.15);color:#fff;border:1px solid rgba(212,175,55,.5);white-space:nowrap;}
  .badge.ok{background:rgba(125,255,125,.15);border-color:var(--green);color:var(--green);}
  .badge.low{background:rgba(255,215,0,.15);border-color:var(--gold);color:var(--gold-light);}
  .badge.back{background:rgba(255,138,122,.15);border-color:var(--red);color:var(--red);}
  .badge.none{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.3);color:#aaa;}
  .badge.mat{background:rgba(110,232,228,.12);border-color:var(--cyan);color:var(--cyan);}
  .badge.red{background:rgba(255,138,122,.15);border-color:var(--red);color:var(--red);}
  .badge.yellow{background:rgba(255,229,92,.15);border-color:var(--yellow);color:var(--yellow);}
  .badge.cat{background:rgba(212,175,55,.12);border-color:var(--border);color:var(--gold-light);}

  .star{cursor:pointer;font-size:22px;color:rgba(255,255,255,.3);transition:all .2s;user-select:none;text-align:center;display:inline-block;}
  .star:hover{color:#fff;transform:scale(1.3);}
  .star.on{color:var(--gold-light);text-shadow:0 0 12px var(--gold-light),0 0 24px rgba(255,215,0,.5);}

  .footnote{display:flex;flex-wrap:wrap;gap:20px;margin-top:14px;padding-top:12px;border-top:1px solid var(--gold);}
  .fn{color:#fff;font-size:12px;position:relative;padding-left:14px;opacity:.85;}
  .fn::before{content:"◆";position:absolute;left:0;color:var(--gold);font-size:8px;top:4px;}
  .fn b{color:#fff;}

  .cta{text-align:center;background:var(--bg);border:1px solid var(--gold);border-radius:14px;padding:28px 20px;margin-top:16px;}
  .cta-text{font-size:16px;font-weight:600;color:var(--gold);margin-bottom:16px;}
  .cta-btn{display:inline-block;background:var(--gold);color:#0a0a0a;text-decoration:none;padding:16px 40px;font-size:20px;font-weight:800;letter-spacing:1px;border-radius:999px;transition:.25s;margin:0 6px;}
  .cta-btn:hover{background:var(--gold-light);transform:scale(1.03);}
  .cta-mail{display:inline-block;color:var(--gold);text-decoration:none;padding:16px 30px;font-size:16px;font-weight:700;border:1px solid var(--gold);border-radius:999px;transition:.25s;margin:0 6px;}
  .cta-mail:hover{background:var(--gold);color:#0a0a0a;}
  .manager{margin-top:16px;font-size:13px;color:var(--muted);}

  .sticky-bar{position:fixed;left:0;right:0;bottom:0;background:linear-gradient(180deg,rgba(10,10,10,.95),#0a0a0a);border-top:3px solid var(--gold);box-shadow:0 -10px 40px rgba(255,215,0,.25),0 -4px 15px rgba(0,0,0,.8);padding:14px 20px;z-index:1000;transform:translateY(110%);transition:transform .35s cubic-bezier(.34,1.56,.64,1);backdrop-filter:blur(8px);}
  .sticky-bar.show{transform:translateY(0);}
  .sticky-bar.discount-active{border-top-color:var(--green);box-shadow:0 -10px 40px rgba(125,255,125,.4),0 -4px 15px rgba(0,0,0,.8);}
  .sticky-bar::before{content:'';position:absolute;top:-3px;left:0;right:0;height:3px;background:linear-gradient(90deg,transparent,var(--gold),var(--orange),var(--gold),transparent);background-size:200% 100%;animation:barShine 3s linear infinite;}
  .sticky-bar.discount-active::before{background:linear-gradient(90deg,transparent,var(--green),#3aa03a,var(--green),transparent);background-size:200% 100%;}
  @keyframes barShine{0%{background-position:200% 0;}100%{background-position:-200% 0;}}
  .sticky-inner{max-width:1800px;margin:0 auto;display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
  .sticky-info{display:flex;gap:16px;align-items:center;flex-wrap:wrap;flex:1;}
  .sticky-stat{display:flex;flex-direction:column;gap:2px;padding:6px 14px;border-left:2px solid var(--gold);}
  .sticky-stat:first-child{border-left:none;padding-left:0;}
  .sticky-stat .lbl{font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:1.2px;color:var(--gold);opacity:.7;margin:0;}
  .sticky-stat .val{font-size:18px;font-weight:900;color:var(--gold-light);line-height:1;font-variant-numeric:tabular-nums;}
  .sticky-stat .val.big{font-size:26px;color:var(--gold);text-shadow:0 0 15px rgba(255,215,0,.7);animation:totalPulse 1.5s ease-in-out infinite;}
  @keyframes totalPulse{0%,100%{text-shadow:0 0 15px rgba(255,215,0,.7);}50%{text-shadow:0 0 25px rgba(255,215,0,1),0 0 40px rgba(255,140,0,.6);}}
  .sticky-bar.discount-active .sticky-stat{border-color:var(--green);}
  .sticky-bar.discount-active .sticky-stat .lbl{color:var(--green);}
  .sticky-bar.discount-active .sticky-stat .val{color:#c8ffb8;}
  .sticky-bar.discount-active .sticky-stat .val.big{color:var(--green);text-shadow:0 0 15px rgba(125,255,125,.8);animation:totalPulseGreen 1.5s ease-in-out infinite;}
  @keyframes totalPulseGreen{0%,100%{text-shadow:0 0 15px rgba(125,255,125,.8);}50%{text-shadow:0 0 25px rgba(125,255,125,1),0 0 40px rgba(58,160,58,.8);}}
  .sticky-actions{display:flex;gap:10px;flex-wrap:wrap;}
  .sticky-btn{display:inline-flex;align-items:center;gap:6px;padding:12px 22px;border-radius:999px;border:2px solid var(--gold);background:transparent;color:var(--gold);font-size:14px;font-weight:900;cursor:pointer;transition:.2s;font-family:inherit;letter-spacing:.5px;text-transform:uppercase;white-space:nowrap;}
  .sticky-btn:hover{background:var(--gold);color:#0a0a0a;transform:scale(1.03);}
  .sticky-btn.primary{background:linear-gradient(135deg,#FFD700,#FF8C00);color:#0a0a0a;border-color:#FFD700;box-shadow:0 0 20px rgba(255,215,0,.5);}
  .sticky-btn.primary:hover{transform:scale(1.05);box-shadow:0 0 30px rgba(255,215,0,.8);}
  .sticky-bar.discount-active .sticky-btn.primary{background:linear-gradient(135deg,#7dff7d,#3aa03a);color:#0a0a0a;border-color:#7dff7d;box-shadow:0 0 25px rgba(125,255,125,.7);}
  .sticky-btn.clear{border-color:rgba(255,138,122,.5);color:var(--red);}
  .sticky-btn.clear:hover{background:var(--red);color:#0a0a0a;border-color:var(--red);}

  @media(max-width:900px){
    .sticky-inner{flex-direction:column;gap:10px;}
    .sticky-info{justify-content:center;width:100%;}
    .sticky-actions{width:100%;justify-content:center;}
    .sticky-stat{padding:4px 10px;}
    .sticky-stat .val{font-size:15px;}
    .sticky-stat .val.big{font-size:20px;}
    .sticky-btn{padding:10px 16px;font-size:12px;}
  }
  @media(max-width:500px){
    body{padding-bottom:240px;}
    .sticky-info{gap:8px;}
    .sticky-stat{padding:2px 8px;}
    .sticky-stat .val{font-size:13px;}
    .sticky-stat .val.big{font-size:17px;}
    .sticky-stat .lbl{font-size:8px;}
  }

  .wrap ::-webkit-scrollbar{width:14px;height:14px;}
  .wrap ::-webkit-scrollbar-track{background:#050505;border:1px solid #2a2210;border-radius:9px;}
  .wrap ::-webkit-scrollbar-thumb{background:linear-gradient(180deg,#FFE55C,#FFD700,#FF8C00);border-radius:9px;border:1px solid #FFD700;box-shadow:0 0 10px rgba(255,215,0,.9);}

  @media print{
    body{background:#fff;color:#000;padding:0;}
    .header{background:#000 !important;color:#FFD700 !important;-webkit-print-color-adjust:exact;print-color-adjust:exact;}
    .header h1{color:#FFD700 !important;animation:none !important;}
    .tag{background:#FFD700 !important;color:#000 !important;}
    .line{background:#FFD700 !important;}
    .stats,.table-block,.cta,.cta-block,.discount-banner{background:#fff !important;border-color:#666 !important;box-shadow:none !important;}
    .toolbar,.search,.counter,.cat-chips,.select-hint,th.col-star::before,.sticky-bar,.cta-buttons,.progress-wrap{display:none !important;}
    .stat,.discount-stat{background:#fff !important;border-color:#999 !important;}
    .lbl,.discount-stat .lbl{color:#000 !important;}
    .val,.discount-stat .val{color:#000 !important;}
    .block-title{color:#000 !important;}
    th{background:#000 !important;color:#FFD700 !important;-webkit-print-color-adjust:exact;print-color-adjust:exact;}
    td{color:#000 !important;border-color:#ccc !important;}
    td.price,td.price.discount{color:#000 !important;}
    input,select{background:#fff !important;color:#000 !important;border-color:#ccc !important;}
  }
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div class="wrap"&gt;

  &lt;div class="seo-hidden" aria-hidden="true"&gt;
    Пружины, пружины сжатия, пружины растяжения, пружины СППК, инструментальные пружины ISO, пружины для грохотов,
    пружины для дробилок, пружина СМД 121, пружина ГИСТ 72, купить пружины, пружины от производителя, прайс-лист на пружины,
    пружины цена, пружины с доставкой, изготовление пружин по чертежам, ООО Арсенал-Деталь, Арсенал-Деталь пружины,
    пружины Арсенал-Деталь, пружины оптом, пружины для промышленности, пружины для механизмов, пружины для оборудования,
    ISO 10243, пружина сжатия 25×130×253, пружина растяжения 7×50×603 60С2А, СППК №79, СППК №22, ISO красная-тяжёлая,
    ISO жёлтая-сверхтяжёлая, пружины 60С2А, пружины нержавеющие, пружины тарельчатые, пружины кручения
  &lt;/div&gt;

  &lt;header class="header"&gt;
    &lt;div class="tag"&gt;ПРАЙС-ЛИСТ · ПРУЖИНЫ ДЛЯ ПРОМЫШЛЕННОСТИ&lt;/div&gt;
    &lt;h1&gt;Пружины купить от производителя&lt;/h1&gt;
    &lt;div class="line"&gt;&lt;/div&gt;
    &lt;p&gt;Сжатия · Растяжения · СППК · ISO · Грохоты и дробилки&lt;/p&gt;
    &lt;div class="company-info"&gt;
      &lt;b&gt;ООО «Арсенал-Деталь»&lt;/b&gt; · ИНН 6670215323 / КПП 667001001 · ОГРН 1086670018445&lt;br /&gt;
      Телефон: &lt;b&gt;8 (902) 873-36-90&lt;/b&gt; · E-mail: &lt;b&gt;arsenal-detal@list.ru&lt;/b&gt;
    &lt;/div&gt;
  &lt;/header&gt;

  &lt;section class="discount-banner" id="discountBanner"&gt;
    &lt;h3&gt;Скидка от объёма&lt;/h3&gt;
    &lt;p&gt;Чем больше партия — тем ниже цена за штуку. Скидка применяется &lt;b&gt;автоматически ко всей партии&lt;/b&gt; при достижении порога.&lt;/p&gt;
    &lt;div class="progress-wrap"&gt;
      &lt;div class="progress-fill" id="progressFill" style="width:0%"&gt;&lt;/div&gt;
      &lt;div class="progress-label" id="progressLabel"&gt;Отметьте позиции — узнаете свою скидку&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="discount-stats"&gt;
      &lt;div class="discount-stat"&gt;&lt;div class="lbl"&gt;Набрано, шт&lt;/div&gt;&lt;div class="val" id="discQty"&gt;0 шт&lt;/div&gt;&lt;/div&gt;
      &lt;div class="discount-stat"&gt;&lt;div class="lbl"&gt;Следующий порог&lt;/div&gt;&lt;div class="val" id="discNext"&gt;5 шт&lt;/div&gt;&lt;/div&gt;
      &lt;div class="discount-stat"&gt;&lt;div class="lbl"&gt;Ваша скидка&lt;/div&gt;&lt;div class="val new" id="discRate"&gt;0%&lt;/div&gt;&lt;/div&gt;
      &lt;div class="discount-stat"&gt;&lt;div class="lbl"&gt;Цена со скидкой&lt;/div&gt;&lt;div class="val new" id="discPrice"&gt;—&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/section&gt;

  &lt;section class="cta-block"&gt;
    &lt;h2&gt;Отметьте нужные позиции&lt;/h2&gt;
    &lt;p&gt;Кликните &lt;b&gt;★&lt;/b&gt; или задайте &lt;b&gt;количество&lt;/b&gt; — сумма по строке и итог пересчитаются мгновенно.&lt;br /&gt;
    При партии от &lt;b&gt;5 шт&lt;/b&gt; скидка применится автоматически.&lt;/p&gt;
    &lt;div class="cta-counter"&gt;Выбрано: &lt;b id="selectedCount"&gt;0&lt;/b&gt; из &lt;span id="totalPositions"&gt;0&lt;/span&gt;&lt;/div&gt;
    &lt;div class="cta-buttons"&gt;
      &lt;button class="btn-big primary" onclick="downloadRequest()"&gt;⬇ Скачать запрос КП&lt;/button&gt;
      &lt;button class="btn-big" onclick="sendByEmail()"&gt;✉ Отправить на e-mail&lt;/button&gt;
      &lt;button class="btn-big" onclick="scrollToTable()"&gt;↓ К каталогу&lt;/button&gt;
    &lt;/div&gt;
  &lt;/section&gt;

  &lt;div class="stats"&gt;
    &lt;div class="stat"&gt;&lt;div class="lbl"&gt;Всего позиций&lt;/div&gt;&lt;div class="val" id="statTotal"&gt;—&lt;/div&gt;&lt;/div&gt;
    &lt;div class="stat"&gt;&lt;div class="lbl"&gt;Мин. цена&lt;/div&gt;&lt;div class="val sm" id="statPrice"&gt;—&lt;/div&gt;&lt;/div&gt;
    &lt;div class="stat"&gt;&lt;div class="lbl"&gt;Макс. цена&lt;/div&gt;&lt;div class="val sm" id="statPriceMax"&gt;—&lt;/div&gt;&lt;/div&gt;
    &lt;div class="stat"&gt;&lt;div class="lbl"&gt;Макс. скидка&lt;/div&gt;&lt;div class="val sm green" id="statMaxDisc"&gt;—&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="cat-chips" id="catChips"&gt;&lt;/div&gt;

  &lt;div class="toolbar"&gt;
    &lt;input type="text" class="search" id="search" placeholder="? Поиск по артикулу, наименованию..." /&gt;
    &lt;div class="counter" id="counter"&gt;Найдено: 0&lt;/div&gt;
    &lt;button class="btn red" onclick="resetAll()"&gt;✕ Очистить всё&lt;/button&gt;
    &lt;button class="btn primary" onclick="downloadRequest()"&gt;⬇ CSV&lt;/button&gt;
    &lt;button class="btn primary" onclick="dlExcel()"&gt;⬇ Excel&lt;/button&gt;
    &lt;button class="btn" onclick="window.print()"&gt;? Печать&lt;/button&gt;
  &lt;/div&gt;

  &lt;section class="table-block" id="catalog"&gt;
    &lt;div class="select-hint"&gt;→ НАЖМИ ★ ИЛИ ВВЕДИ КОЛ-ВО →&lt;/div&gt;
    &lt;div class="block-title"&gt;Прайс-лист · Пружины · Цены с НДС&lt;/div&gt;
    &lt;div class="table-wrap"&gt;
      &lt;table id="tbl"&gt;
        &lt;thead&gt;
          &lt;tr&gt;
            &lt;th class="col-star" title="Отметь позиции"&gt;★&lt;/th&gt;
            &lt;th class="col-qty"&gt;Кол-во, шт&lt;/th&gt;
            &lt;th class="num sortable" data-key="num"&gt;№&lt;/th&gt;
            &lt;th class="sortable" data-key="article"&gt;Артикул&lt;/th&gt;
            &lt;th class="sortable" data-key="name"&gt;Наименование&lt;/th&gt;
            &lt;th class="sortable" data-key="cat"&gt;Категория&lt;/th&gt;
            &lt;th class="sortable" data-key="material"&gt;Материал / цвет&lt;/th&gt;
            &lt;th class="num sortable" data-key="stock"&gt;Наличие&lt;/th&gt;
            &lt;th class="num sortable" data-key="price"&gt;Цена без скидки, ₽/шт&lt;/th&gt;
            &lt;th class="num"&gt;Цена со скидкой, ₽/шт&lt;/th&gt;
            &lt;th class="num"&gt;Сумма, ₽&lt;/th&gt;
          &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody id="tbody"&gt;&lt;/tbody&gt;
      &lt;/table&gt;
    &lt;/div&gt;
    &lt;div class="footnote"&gt;
      &lt;div class="fn"&gt;Цены указаны с НДС · Кратность отгрузки 1 шт&lt;/div&gt;
      &lt;div class="fn"&gt;Срок изготовления: &lt;b&gt;15-20 рабочих дней&lt;/b&gt; на партию&lt;/div&gt;
      &lt;div class="fn"&gt;Скидка применяется &lt;b&gt;ко всей партии&lt;/b&gt; при достижении порога&lt;/div&gt;
      &lt;div class="fn"&gt;Возможно изготовление по вашим чертежам и ТУ&lt;/div&gt;
    &lt;/div&gt;
  &lt;/section&gt;

  &lt;section class="cta"&gt;
    &lt;p class="cta-text"&gt;Изготовим пружины по вашим чертежам и ТУ&lt;/p&gt;
    &lt;a href="tel:+79028733690" class="cta-btn"&gt;8 (902) 873-36-90&lt;/a&gt;
    &lt;a href="mailto:arsenal-detal@list.ru?subject=Запрос%20на%20пружины" class="cta-mail"&gt;✉ arsenal-detal@list.ru&lt;/a&gt;
    &lt;p class="manager"&gt;Менеджер: Ольга · ООО «Арсенал-Деталь»&lt;/p&gt;
  &lt;/section&gt;

&lt;/div&gt;

&lt;div class="sticky-bar" id="stickyBar"&gt;
  &lt;div class="sticky-inner"&gt;
    &lt;div class="sticky-info"&gt;
      &lt;div class="sticky-stat"&gt;
        &lt;div class="lbl"&gt;Позиций&lt;/div&gt;
        &lt;div class="val" id="barCount"&gt;0&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="sticky-stat"&gt;
        &lt;div class="lbl"&gt;Всего, шт&lt;/div&gt;
        &lt;div class="val" id="barQty"&gt;0&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="sticky-stat"&gt;
        &lt;div class="lbl"&gt;Скидка&lt;/div&gt;
        &lt;div class="val" id="barRate"&gt;0%&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="sticky-stat"&gt;
        &lt;div class="lbl" id="barTotalLabel"&gt;Итого с НДС&lt;/div&gt;
        &lt;div class="val big" id="barTotal"&gt;0 ₽&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="sticky-actions"&gt;
      &lt;button class="sticky-btn primary" onclick="downloadRequest()"&gt;⬇ Скачать запрос КП&lt;/button&gt;
      &lt;button class="sticky-btn" onclick="sendByEmail()"&gt;✉ На e-mail&lt;/button&gt;
      &lt;button class="sticky-btn clear" onclick="clearPicked()"&gt;✕ Очистить&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
/* ============================================================
   ПРАЙС · ПРУЖИНЫ · ООО «Арсенал-Деталь»
   ------------------------------------------------------------
   ПОЛИТИКА ЦЕНООБРАЗОВАНИЯ:
   Цена = цена поставщика × коэффициент
     • обычные (сжатия, растяжения): ×1,8
     • СППК, СМД, ГИСТ:               ×1,4
     • ISO:                            ×1,35
   Округление цены: до 10 ₽.
   Скидки: 5% от 5 шт, 10% от 10 шт, 15% от 20 шт — ко всей партии.
   ============================================================ */

var PROJECT = {
  id: 'pruzhiny',
  title: 'Пружины',
  subtitle: 'Промышленные пружины · Изготовление по чертежам',
  vat: 22,

  discounts: [
    {qty: 5,  pct: 5},
    {qty: 10, pct: 10},
    {qty: 20, pct: 15}
  ],

  categories: {
    'Сжатия':      {order: 1, coeff: 1.8},
    'Растяжения':  {order: 2, coeff: 1.8},
    'СППК':        {order: 3, coeff: 1.4},
    'ISO':         {order: 4, coeff: 1.35},
    'Грохоты/дробилки': {order: 5, coeff: 1.4}
  },

  /* Данные: [num, article, name, cat, material, stock, priceSupplier] */
  data: [
    /* ---------- СЖАТИЯ ---------- */
    {num:1,  article:'PS-25-130-253',      name:'Пружина сжатия 25×130×253',            cat:'Сжатия', material:'',      stock:7,    sup:5000},
    {num:2,  article:'PS-20-130-246',      name:'Пружина сжатия 20×130×246',            cat:'Сжатия', material:'',      stock:1,    sup:4300},
    {num:3,  article:'PS-21-132-246',      name:'Пружина сжатия 21×132×246',            cat:'Сжатия', material:'',      stock:2,    sup:4500},
    {num:4,  article:'PS-19-94-185-60S2A', name:'Пружина сжатия 19×94×185',             cat:'Сжатия', material:'60С2А', stock:5,    sup:2500},
    {num:5,  article:'PS-14-74-350-60S2A', name:'Пружина сжатия 14×74×350',             cat:'Сжатия', material:'60С2А', stock:4,    sup:2500},
    {num:6,  article:'PS-12-79-163',       name:'Пружина сжатия 12×79×163',             cat:'Сжатия', material:'',      stock:1,    sup:1500},
    {num:7,  article:'PS-18-110-230',      name:'Пружина сжатия 18×110×230',            cat:'Сжатия', material:'',      stock:1,    sup:3000},
    {num:8,  article:'PS-14-70-275',       name:'Пружина сжатия 14×70×275',             cat:'Сжатия', material:'',      stock:1,    sup:2000},
    {num:9,  article:'PS-12-83-300',       name:'Пружина сжатия 12×83×300',             cat:'Сжатия', material:'',      stock:1,    sup:1500},
    {num:10, article:'PS-16-100-500',      name:'Пружина сжатия 16×100×500',            cat:'Сжатия', material:'',      stock:1,    sup:3500},
    {num:11, article:'PS-12-90-273',       name:'Пружина сжатия 12×90×273',             cat:'Сжатия', material:'',      stock:1,    sup:1500},
    {num:12, article:'PS-12-60-55',        name:'Пружина сжатия 12×60×55',              cat:'Сжатия', material:'',      stock:2,    sup:1400},
    {num:13, article:'PS-12-79.5-127',     name:'Пружина сжатия 12×79,5×127',           cat:'Сжатия', material:'',      stock:1,    sup:1500},
    {num:14, article:'PS-12-96-221',       name:'Пружина сжатия 12×96×221',             cat:'Сжатия', material:'',      stock:2,    sup:1500},
    {num:15, article:'PS-14-120-200',      name:'Пружина сжатия 14×120×200',            cat:'Сжатия', material:'',      stock:9,    sup:2000},
    {num:16, article:'PS-12-70-210',       name:'Пружина сжатия 12×70×210',             cat:'Сжатия', material:'',      stock:1,    sup:1500},
    {num:17, article:'PS-13-85-145',       name:'Пружина сжатия 13×85×145',             cat:'Сжатия', material:'',      stock:1,    sup:1500},
    {num:18, article:'PS-12-90-190',       name:'Пружина сжатия 12×90×190',             cat:'Сжатия', material:'',      stock:9,    sup:1500},
    {num:19, article:'PS-12-155-152',      name:'Пружина сжатия 12×155×152',            cat:'Сжатия', material:'',      stock:1,    sup:1500},
    {num:20, article:'PS-16-75-290',       name:'Пружина сжатия 16×75×290',             cat:'Сжатия', material:'',      stock:1,    sup:2400},
    {num:21, article:'PS-12-95-190',       name:'Пружина сжатия 12×95×190',             cat:'Сжатия', material:'',      stock:1,    sup:1500},
    {num:22, article:'PS-12-54-54',        name:'Пружина сжатия 12×54×54',              cat:'Сжатия', material:'',      stock:4,    sup:1400},

    /* ---------- РАСТЯЖЕНИЯ ---------- */
    {num:23, article:'PR-4-30-350',        name:'Пружина растяжения 4×30×350',          cat:'Растяжения', material:'',      stock:8,    sup:800},
    {num:24, article:'PR-7-50-603-60S2A',  name:'Пружина растяжения 7×50×603',          cat:'Растяжения', material:'60С2А', stock:20,   sup:3500},
    {num:25, article:'PR-0.5-6.3-20',      name:'Пружина растяжения 0,5×6,3×20',        cat:'Растяжения', material:'',      stock:10,   sup:100},
    {num:26, article:'PR-0.5-5-22',        name:'Пружина растяжения 0,5×5×22',          cat:'Растяжения', material:'',      stock:10,   sup:100},
    {num:27, article:'PR-0.5-5-18',        name:'Пружина растяжения 0,5×5×18',          cat:'Растяжения', material:'',      stock:10,   sup:100},
    {num:28, article:'PR-0.5-4.6-42',      name:'Пружина растяжения 0,5×4,6×42',        cat:'Растяжения', material:'',      stock:8,    sup:100},
    {num:29, article:'PR-1.8-23-80-NERZH', name:'Пружина растяжения 1,8×23×80',         cat:'Растяжения', material:'Нерж.', stock:5,    sup:300},
    {num:30, article:'PR-1.6-12.8-60',     name:'Пружина растяжения 1,6×12,8×60',       cat:'Растяжения', material:'',      stock:6,    sup:300},
    {num:31, article:'PR-2.5-26-245-290',  name:'Пружина растяжения 2,5×26×245×290',    cat:'Растяжения', material:'',      stock:10,   sup:500},
    {num:32, article:'PR-2.5-25-42',       name:'Пружина растяжения 2,5×25×42',         cat:'Растяжения', material:'',      stock:100,  sup:450},
    {num:33, article:'PR-5-30-300',        name:'Пружина растяжения 5×30×300',          cat:'Растяжения', material:'',      stock:14,   sup:1000},
    {num:34, article:'PR-3-20.5-97',       name:'Пружина растяжения 3×20,5×97',         cat:'Растяжения', material:'',      stock:212,  sup:450},
    {num:35, article:'PR-1-13.3-51',       name:'Пружина растяжения 1×13,3×51',         cat:'Растяжения', material:'',      stock:1900, sup:200},
    {num:36, article:'PR-1.5-9.8-40.2',    name:'Пружина растяжения 1,5×9,8×40,2',      cat:'Растяжения', material:'',      stock:1000, sup:250},
    {num:37, article:'PR-1.2-12.8-64.3',   name:'Пружина растяжения 1,2×12,8×64,3',     cat:'Растяжения', material:'',      stock:16,   sup:200},
    {num:38, article:'PR-8-45-345',        name:'Пружина растяжения 8×45×345',          cat:'Растяжения', material:'',      stock:4,    sup:1800},
    {num:39, article:'PR-2-18-150',        name:'Пружина растяжения 2×18×150',          cat:'Растяжения', material:'',      stock:108,  sup:350},
    {num:40, article:'PR-1.5-12-35',       name:'Пружина растяжения 1,5×12×35',         cat:'Растяжения', material:'',      stock:62,   sup:250},
    {num:41, article:'PR-2.8-20-286',      name:'Пружина растяжения 2,8×20×286',        cat:'Растяжения', material:'',      stock:6,    sup:500},
    {num:42, article:'PR-3-32.5-250',      name:'Пружина растяжения 3×32,5×250',        cat:'Растяжения', material:'',      stock:6,    sup:500},
    {num:43, article:'PR-5-36-172',        name:'Пружина растяжения 5×36×172',          cat:'Растяжения', material:'',      stock:28,   sup:750},
    {num:44, article:'PR-10-120-325',      name:'Пружина растяжения 10×120×325',        cat:'Растяжения', material:'',      stock:15,   sup:1500},
    {num:45, article:'PR-4.5-29.3-86.5',   name:'Пружина растяжения 4,5×29,3×86,5',     cat:'Растяжения', material:'',      stock:3,    sup:650},

    /* ---------- СППК ---------- */
    {num:46, article:'SPPK-79',  name:'Пружина сжатия СППК №79',  cat:'СППК', material:'', stock:100,  sup:22344},
    {num:47, article:'SPPK-78',  name:'Пружина сжатия СППК №78',  cat:'СППК', material:'', stock:100,  sup:18240},
    {num:48, article:'SPPK-76',  name:'Пружина сжатия СППК №76',  cat:'СППК', material:'', stock:100,  sup:15960},
    {num:49, article:'SPPK-74',  name:'Пружина сжатия СППК №74',  cat:'СППК', material:'', stock:100,  sup:11400},
    {num:50, article:'SPPK-73',  name:'Пружина сжатия СППК №73',  cat:'СППК', material:'', stock:100,  sup:9982},
    {num:51, article:'SPPK-72',  name:'Пружина сжатия СППК №72',  cat:'СППК', material:'', stock:100,  sup:8614},
    {num:52, article:'SPPK-70',  name:'Пружина сжатия СППК №70',  cat:'СППК', material:'', stock:100,  sup:6156},
    {num:53, article:'SPPK-61',  name:'Пружина сжатия СППК №61',  cat:'СППК', material:'', stock:100,  sup:14592},
    {num:54, article:'SPPK-60',  name:'Пружина сжатия СППК №60',  cat:'СППК', material:'', stock:100,  sup:12540},
    {num:55, article:'SPPK-59',  name:'Пружина сжатия СППК №59',  cat:'СППК', material:'', stock:100,  sup:12540},
    {num:56, article:'SPPK-52',  name:'Пружина сжатия СППК №52',  cat:'СППК', material:'', stock:100,  sup:3876},
    {num:57, article:'SPPK-51',  name:'Пружина сжатия СППК №51',  cat:'СППК', material:'', stock:100,  sup:4168},
    {num:58, article:'SPPK-50',  name:'Пружина сжатия СППК №50',  cat:'СППК', material:'', stock:100,  sup:3712},
    {num:59, article:'SPPK-43',  name:'Пружина сжатия СППК №43',  cat:'СППК', material:'', stock:100,  sup:12490},
    {num:60, article:'SPPK-42',  name:'Пружина сжатия СППК №42',  cat:'СППК', material:'', stock:100,  sup:11578},
    {num:61, article:'SPPK-41',  name:'Пружина сжатия СППК №41',  cat:'СППК', material:'', stock:100,  sup:9348},
    {num:62, article:'SPPK-40',  name:'Пружина сжатия СППК №40',  cat:'СППК', material:'', stock:100,  sup:9576},
    {num:63, article:'SPPK-38',  name:'Пружина сжатия СППК №38',  cat:'СППК', material:'', stock:100,  sup:6050},
    {num:64, article:'SPPK-32',  name:'Пружина сжатия СППК №32',  cat:'СППК', material:'', stock:100,  sup:3192},
    {num:65, article:'SPPK-22',  name:'Пружина сжатия СППК №22',  cat:'СППК', material:'', stock:1000, sup:9348},
    {num:66, article:'SPPK-21',  name:'Пружина сжатия СППК №21',  cat:'СППК', material:'', stock:100,  sup:6000},
    {num:67, article:'SPPK-20',  name:'Пружина сжатия СППК №20',  cat:'СППК', material:'', stock:100,  sup:4680},
    {num:68, article:'SPPK-9',   name:'Пружина сжатия СППК №9',   cat:'СППК', material:'', stock:100,  sup:3000},
    {num:69, article:'SPPK-5',   name:'Пружина сжатия СППК №5',   cat:'СППК', material:'', stock:100,  sup:2280},
    {num:70, article:'SPPK-4',   name:'Пружина сжатия СППК №4',   cat:'СППК', material:'', stock:100,  sup:2280},
    {num:71, article:'SPPK-108', name:'Пружина сжатия СППК №108', cat:'СППК', material:'', stock:5,    sup:5170},
    {num:72, article:'SPPK-83',  name:'Пружина сжатия СППК №83',  cat:'СППК', material:'', stock:3,    sup:17800},
    {num:73, article:'SPPK-77',  name:'Пружина сжатия СППК №77',  cat:'СППК', material:'', stock:100,  sup:16366},
    {num:74, article:'SPPK-75',  name:'Пружина сжатия СППК №75',  cat:'СППК', material:'', stock:100,  sup:13680},
    {num:75, article:'SPPK-71',  name:'Пружина сжатия СППК №71',  cat:'СППК', material:'', stock:100,  sup:7920},
    {num:76, article:'SPPK-58',  name:'Пружина сжатия СППК №58',  cat:'СППК', material:'', stock:100,  sup:11400},
    {num:77, article:'SPPK-57',  name:'Пружина сжатия СППК №57',  cat:'СППК', material:'', stock:100,  sup:9804},
    {num:78, article:'SPPK-56',  name:'Пружина сжатия СППК №56',  cat:'СППК', material:'', stock:100,  sup:8436},
    {num:79, article:'SPPK-55',  name:'Пружина сжатия СППК №55',  cat:'СППК', material:'', stock:100,  sup:7524},
    {num:80, article:'SPPK-54',  name:'Пружина сжатия СППК №54',  cat:'СППК', material:'', stock:100,  sup:6480},
    {num:81, article:'SPPK-53',  name:'Пружина сжатия СППК №53',  cat:'СППК', material:'', stock:100,  sup:5280},
    {num:82, article:'SPPK-39',  name:'Пружина сжатия СППК №39',  cat:'СППК', material:'', stock:100,  sup:7068},
    {num:83, article:'SPPK-37',  name:'Пружина сжатия СППК №37',  cat:'СППК', material:'', stock:100,  sup:6050},
    {num:84, article:'SPPK-36',  name:'Пружина сжатия СППК №36',  cat:'СППК', material:'', stock:100,  sup:5244},
    {num:85, article:'SPPK-35',  name:'Пружина сжатия СППК №35',  cat:'СППК', material:'', stock:100,  sup:4788},

    /* ---------- ISO КРАСНАЯ-ТЯЖЁЛАЯ ---------- */
    {num:86, article:'ISO-63-305-R', name:'ISO красная-тяжёлая 63×305', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:10320},
    {num:87, article:'ISO-63-254-R', name:'ISO красная-тяжёлая 63×254', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:9600},
    {num:88, article:'ISO-63-203-R', name:'ISO красная-тяжёлая 63×203', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:8880},
    {num:89, article:'ISO-63-178-R', name:'ISO красная-тяжёлая 63×178', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:8160},
    {num:90, article:'ISO-63-152-R', name:'ISO красная-тяжёлая 63×152', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:7440},
    {num:91, article:'ISO-63-139-R', name:'ISO красная-тяжёлая 63×139', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:6720},
    {num:92, article:'ISO-63-127-R', name:'ISO красная-тяжёлая 63×127', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:6000},
    {num:93, article:'ISO-63-115-R', name:'ISO красная-тяжёлая 63×115', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:5328},
    {num:94, article:'ISO-63-102-R', name:'ISO красная-тяжёлая 63×102', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:4680},
    {num:95, article:'ISO-63-89-R',  name:'ISO красная-тяжёлая 63×89',  cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:4464},
    {num:96, article:'ISO-63-76-R',  name:'ISO красная-тяжёлая 63×76',  cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:4080},
    {num:97, article:'ISO-50-305-R', name:'ISO красная-тяжёлая 50×305', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:7192},
    {num:98, article:'ISO-50-254-R', name:'ISO красная-тяжёлая 50×254', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:6192},
    {num:99, article:'ISO-50-203-R', name:'ISO красная-тяжёлая 50×203', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:3360},
    {num:100,article:'ISO-50-178-R', name:'ISO красная-тяжёлая 50×178', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:3178},
    {num:101,article:'ISO-50-152-R', name:'ISO красная-тяжёлая 50×152', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:3050},
    {num:102,article:'ISO-50-139-R', name:'ISO красная-тяжёлая 50×139', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:2960},
    {num:103,article:'ISO-50-127-R', name:'ISO красная-тяжёлая 50×127', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:2865},
    {num:104,article:'ISO-50-115-R', name:'ISO красная-тяжёлая 50×115', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:2532},
    {num:105,article:'ISO-50-102-R', name:'ISO красная-тяжёлая 50×102', cat:'ISO', material:'Красная-тяжёлая', stock:500, sup:2084},

    /* ---------- ISO ЖЁЛТАЯ-СВЕРХТЯЖЁЛАЯ ---------- */
    {num:106,article:'ISO-20-305-Y', name:'ISO жёлтая-сверхтяжёлая 20×305', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:1440},
    {num:107,article:'ISO-63-305-Y', name:'ISO жёлтая-сверхтяжёлая 63×305', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:10320},
    {num:108,article:'ISO-63-254-Y', name:'ISO жёлтая-сверхтяжёлая 63×254', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:9600},
    {num:109,article:'ISO-63-203-Y', name:'ISO жёлтая-сверхтяжёлая 63×203', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:8880},
    {num:110,article:'ISO-63-178-Y', name:'ISO жёлтая-сверхтяжёлая 63×178', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:8160},
    {num:111,article:'ISO-63-152-Y', name:'ISO жёлтая-сверхтяжёлая 63×152', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:7440},
    {num:112,article:'ISO-63-139-Y', name:'ISO жёлтая-сверхтяжёлая 63×139', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:6720},
    {num:113,article:'ISO-63-127-Y', name:'ISO жёлтая-сверхтяжёлая 63×127', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:6000},
    {num:114,article:'ISO-63-115-Y', name:'ISO жёлтая-сверхтяжёлая 63×115', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:5328},
    {num:115,article:'ISO-63-102-Y', name:'ISO жёлтая-сверхтяжёлая 63×102', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:4680},
    {num:116,article:'ISO-63-89-Y',  name:'ISO жёлтая-сверхтяжёлая 63×89',  cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:4464},
    {num:117,article:'ISO-63-76-Y',  name:'ISO жёлтая-сверхтяжёлая 63×76',  cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:4080},
    {num:118,article:'ISO-50-305-Y', name:'ISO жёлтая-сверхтяжёлая 50×305', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:7192},
    {num:119,article:'ISO-50-254-Y', name:'ISO жёлтая-сверхтяжёлая 50×254', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:6192},
    {num:120,article:'ISO-50-203-Y', name:'ISO жёлтая-сверхтяжёлая 50×203', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:3360},
    {num:121,article:'ISO-50-178-Y', name:'ISO жёлтая-сверхтяжёлая 50×178', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:3178},
    {num:122,article:'ISO-50-152-Y', name:'ISO жёлтая-сверхтяжёлая 50×152', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:3050},
    {num:123,article:'ISO-50-139-Y', name:'ISO жёлтая-сверхтяжёлая 50×139', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:2960},
    {num:124,article:'ISO-50-127-Y', name:'ISO жёлтая-сверхтяжёлая 50×127', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:2865},
    {num:125,article:'ISO-50-115-Y', name:'ISO жёлтая-сверхтяжёлая 50×115', cat:'ISO', material:'Жёлтая-сверхтяжёлая', stock:500, sup:2532},

    /* ---------- ГРОХОТЫ / ДРОБИЛКИ ---------- */
    {num:126,article:'SMD-121', name:'Пружина СМД 121', cat:'Грохоты/дробилки', material:'', stock:100, sup:11547},
    {num:127,article:'GIST-72', name:'Пружина ГИСТ 72', cat:'Грохоты/дробилки', material:'', stock:100, sup:14223}
  ],

  phone: '8 (902) 873-36-90',
  phoneHref: '+79028733690',
  email: 'arsenal-detal@list.ru',
  manager: 'Менеджер: Ольга · ООО «Арсенал-Деталь»'
};

/* ==================== СОСТОЯНИЕ ==================== */
var state = {search:'', cat:'all', isoColor:'all', sort:{key:'catPrice', dir:1}};
var picked = {};
var rowRefs = {};

function fmt(n){ return Math.round(n).toLocaleString('ru-RU'); }
function today(){
  var d=new Date(), p=function(n){return String(n).padStart(2,'0');};
  return d.getFullYear()+'-'+p(d.getMonth()+1)+'-'+p(d.getDate());
}

/* цена с учётом коэффициента категории, округление до 10 */
function getBasePrice(r){
  var coeff = (PROJECT.categories[r.cat] &amp;&amp; PROJECT.categories[r.cat].coeff) || 1.8;
  var raw = r.sup * coeff;
  return Math.round(raw/10)*10;
}
function getRowByNum(n){ return PROJECT.data.find(function(x){return x.num===n;}); }
function getCatOrder(c){ return (PROJECT.categories[c] &amp;&amp; PROJECT.categories[c].order) || 99; }

function getDiscountPct(totalQty){
  var pct = 0;
  PROJECT.discounts.forEach(function(d){ if (totalQty &gt;= d.qty) pct = d.pct; });
  return pct;
}
function getNextThreshold(totalQty){
  for (var i=0;i&lt;PROJECT.discounts.length;i++){
    if (totalQty &lt; PROJECT.discounts[i].qty) return PROJECT.discounts[i];
  }
  return null;
}
function calcPriceWithDiscount(r, pct){
  return Math.round(getBasePrice(r) * (1 - pct/100));
}
function getTotalQty(){
  var total = 0;
  Object.keys(picked).forEach(function(n){ total += (picked[n]||0); });
  return total;
}
function getCatCounts(){
  var c = {};
  PROJECT.data.forEach(function(r){ c[r.cat] = (c[r.cat]||0)+1; });
  return c;
}

function getFiltered(){
  var rows = PROJECT.data.slice();
  if (state.cat !== 'all'){
    rows = rows.filter(function(r){ return r.cat === state.cat; });
  }
  if (state.cat === 'ISO' &amp;&amp; state.isoColor !== 'all'){
    rows = rows.filter(function(r){
      return (r.material||'').indexOf(state.isoColor) === 0;
    });
  }
  if (state.search){
    var q = state.search.trim().toLowerCase();
    rows = rows.filter(function(r){
      return String(r.num).indexOf(q)!==-1 ||
             (r.article||'').toLowerCase().indexOf(q)!==-1 ||
             (r.name||'').toLowerCase().indexOf(q)!==-1 ||
             (r.material||'').toLowerCase().indexOf(q)!==-1;
    });
  }
  var k=state.sort.key, d=state.sort.dir;
  rows.sort(function(a,b){
    if (k==='catPrice'){
      var ca=getCatOrder(a.cat), cb=getCatOrder(b.cat);
      if (ca!==cb) return ca-cb;
      return (getBasePrice(a)-getBasePrice(b))*d;
    }
    if (k==='stock' || k==='price'){
      var va = k==='price'?getBasePrice(a):a.stock;
      var vb = k==='price'?getBasePrice(b):b.stock;
      return (va-vb)*d;
    }
    var va=a[k], vb=b[k];
    if(typeof va==='number' &amp;&amp; typeof vb==='number') return (va-vb)*d;
    return String(va||'').localeCompare(String(vb||''),'ru')*d;
  });
  return rows;
}

function stockBadge(stock){
  if (stock &gt;= 50) return '&lt;span class="badge ok"&gt;в наличии&lt;/span&gt;';
  if (stock &gt;= 5)  return '&lt;span class="badge low"&gt;мало&lt;/span&gt;';
  if (stock &gt;= 1)  return '&lt;span class="badge back"&gt;под заказ&lt;/span&gt;';
  return '&lt;span class="badge none"&gt;нет&lt;/span&gt;';
}
function materialBadge(r){
  var m = r.material || '';
  if (!m) return '&lt;span class="badge cat"&gt;—&lt;/span&gt;';
  if (m.indexOf('Красная')===0) return '&lt;span class="badge red"&gt;? красная-тяжёлая&lt;/span&gt;';
  if (m.indexOf('Жёлтая')===0)  return '&lt;span class="badge yellow"&gt;? жёлтая-сверхтяжёлая&lt;/span&gt;';
  if (m==='60С2А') return '&lt;span class="badge mat"&gt;60С2А&lt;/span&gt;';
  if (m==='Нерж.') return '&lt;span class="badge mat"&gt;Нерж.&lt;/span&gt;';
  return '&lt;span class="badge mat"&gt;'+m+'&lt;/span&gt;';
}

function updateStats(){
  var d = PROJECT.data;
  document.getElementById('statTotal').textContent = d.length;
  var prices = d.map(getBasePrice);
  document.getElementById('statPrice').textContent = fmt(Math.min.apply(null,prices))+' ₽';
  document.getElementById('statPriceMax').textContent = fmt(Math.max.apply(null,prices))+' ₽';
  var maxPct = PROJECT.discounts.reduce(function(m,x){return Math.max(m,x.pct);},0);
  document.getElementById('statMaxDisc').textContent = 'до '+maxPct+'%';
  document.getElementById('totalPositions').textContent = d.length;
}

function renderChips(){
  var box = document.getElementById('catChips');
  var counts = getCatCounts();
  var all = PROJECT.data.length;
  var html = '';
  html += '&lt;button class="chip'+(state.cat==='all'?' on':'')+'" data-cat="all"&gt;Все &lt;span class="cnt"&gt;'+all+'&lt;/span&gt;&lt;/button&gt;';
  var cats = Object.keys(PROJECT.categories).sort(function(a,b){
    return PROJECT.categories[a].order - PROJECT.categories[b].order;
  });
  cats.forEach(function(c){
    html += '&lt;button class="chip'+(state.cat===c?' on':'')+'" data-cat="'+c+'"&gt;'+c+' &lt;span class="cnt"&gt;'+(counts[c]||0)+'&lt;/span&gt;&lt;/button&gt;';
  });
  html += '&lt;div class="iso-sub"&gt;';
  html += '&lt;button class="chip iso'+(state.isoColor==='all'?' on':'')+'" data-iso="all"&gt;ISO все цвета&lt;/button&gt;';
  html += '&lt;button class="chip iso'+(state.isoColor==='Красная'?' on':'')+'" data-iso="Красная"&gt;? красная&lt;/button&gt;';
  html += '&lt;button class="chip iso'+(state.isoColor==='Жёлтая'?' on':'')+'" data-iso="Жёлтая"&gt;? жёлтая&lt;/button&gt;';
  html += '&lt;/div&gt;';
  box.innerHTML = html;
  box.querySelectorAll('[data-cat]').forEach(function(b){
    b.addEventListener('click', function(){
      state.cat = this.dataset.cat;
      if (state.cat !== 'ISO') state.isoColor = 'all';
      renderChips(); render();
    });
  });
  box.querySelectorAll('[data-iso]').forEach(function(b){
    b.addEventListener('click', function(){
      state.cat = 'ISO';
      state.isoColor = this.dataset.iso;
      renderChips(); render();
    });
  });
}

function refreshRow(num){
  var ref = rowRefs[num]; if (!ref) return;
  var r = getRowByNum(num); if (!r) return;
  var isPicked = picked[num]!==undefined &amp;&amp; picked[num] &gt; 0;
  var qty = isPicked ? picked[num] : 0;
  var discPct = getDiscountPct(getTotalQty());
  var bp = getBasePrice(r);
  var dp = calcPriceWithDiscount(r, discPct);
  var sum = isPicked ? dp * qty : 0;

  ref.tr.classList.remove('picked','discount-active');
  if (isPicked) ref.tr.classList.add('picked');
  if (isPicked &amp;&amp; discPct&gt;0) ref.tr.classList.add('discount-active');

  ref.star.textContent = isPicked ? '★' : '☆';
  ref.star.classList.toggle('on', isPicked);

  if (document.activeElement !== ref.qty){
    ref.qty.value = (picked[num]!==undefined) ? picked[num] : '';
  }

  ref.cellPriceOld.textContent = fmt(bp) + ' ₽';
  ref.cellPrice.textContent = discPct&gt;0 ? fmt(dp)+' ₽' : fmt(bp)+' ₽';
  ref.cellPrice.classList.toggle('discount', discPct&gt;0);
  ref.cellSum.textContent = isPicked ? fmt(sum)+' ₽' : '—';
}

function render(){
  var rows = getFiltered();
  var tbody = document.getElementById('tbody');
  tbody.innerHTML = '';
  rowRefs = {};
  document.getElementById('counter').textContent = 'Найдено: ' + rows.length;

  if(!rows.length){
    tbody.innerHTML = '&lt;tr&gt;&lt;td colspan="11" style="text-align:center;padding:40px;opacity:.6"&gt;Ничего не найдено&lt;/td&gt;&lt;/tr&gt;';
    updateStickyBar(); updateDiscountBanner(); return;
  }

  var discPct = getDiscountPct(getTotalQty());

  rows.forEach(function(r){
    var isPicked = picked[r.num]!==undefined &amp;&amp; picked[r.num] &gt; 0;
    var qty = picked[r.num]!==undefined ? picked[r.num] : '';
    var bp = getBasePrice(r);
    var dp = calcPriceWithDiscount(r, discPct);
    var sum = isPicked ? dp * qty : 0;

    var tr = document.createElement('tr');
    if (isPicked) tr.className = 'picked' + (discPct&gt;0 ? ' discount-active' : '');

    tr.innerHTML =
      '&lt;td class="col-star"&gt;&lt;span class="star'+(isPicked?' on':'')+'" data-num="'+r.num+'"&gt;'+(isPicked?'★':'☆')+'&lt;/span&gt;&lt;/td&gt;'+
      '&lt;td class="col-qty"&gt;&lt;input type="number" class="qty" data-num="'+r.num+'" value="'+qty+'" min="0" step="1"&gt;&lt;/td&gt;'+
      '&lt;td class="num"&gt;'+r.num+'&lt;/td&gt;'+
      '&lt;td class="article"&gt;'+r.article+'&lt;/td&gt;'+
      '&lt;td&gt;&lt;b&gt;'+r.name+'&lt;/b&gt;&lt;/td&gt;'+
      '&lt;td&gt;&lt;span class="badge cat"&gt;'+r.cat+'&lt;/span&gt;&lt;/td&gt;'+
      '&lt;td&gt;'+materialBadge(r)+'&lt;/td&gt;'+
      '&lt;td class="num"&gt;'+stockBadge(r.stock)+'&lt;/td&gt;'+
      '&lt;td class="num price-old"&gt;'+fmt(bp)+' ₽&lt;/td&gt;'+
      '&lt;td class="num price'+(discPct&gt;0?' discount':'')+'"&gt;'+(discPct&gt;0?fmt(dp)+' ₽':fmt(bp)+' ₽')+'&lt;/td&gt;'+
      '&lt;td class="num '+(isPicked?'price':'')+'"&gt;'+(isPicked?fmt(sum)+' ₽':'—')+'&lt;/td&gt;';
    tbody.appendChild(tr);

    rowRefs[r.num] = {
      tr: tr,
      star: tr.querySelector('.star'),
      qty: tr.querySelector('input.qty'),
      cellPriceOld: tr.querySelector('.price-old'),
      cellPrice: tr.querySelector('.price'),
      cellSum: tr.querySelector('td:last-child')
    };
  });

  bindStars(); bindQty();
  updateSort(); updateStickyBar(); updateDiscountBanner();
}

function updateSort(){
  document.querySelectorAll('#tbl th.sortable').forEach(function(th){
    th.classList.remove('asc','desc');
    if (th.dataset.key===state.sort.key) th.classList.add(state.sort.dir===1?'asc':'desc');
  });
}
function bindStars(){
  Object.keys(rowRefs).forEach(function(n){
    var ref = rowRefs[n];
    ref.star.addEventListener('click',function(){
      var num = parseInt(this.dataset.num,10);
      if (picked[num]!==undefined &amp;&amp; picked[num]&gt;0){
        delete picked[num];
        if (rowRefs[num]) rowRefs[num].qty.value = '';
      } else {
        picked[num] = 1;
        if (rowRefs[num]) rowRefs[num].qty.value = 1;
      }
      refreshAll();
    });
  });
}
function bindQty(){
  Object.keys(rowRefs).forEach(function(n){
    var inp = rowRefs[n].qty;
    inp.addEventListener('input',function(){
      var num = parseInt(this.dataset.num,10);
      var v = this.value.trim();
      if (v === '' || v === '0'){
        delete picked[num];
      } else {
        var q = Math.max(0, parseInt(v,10)||0);
        if (q &gt; 0) picked[num] = q; else delete picked[num];
      }
      refreshAll();
    });
  });
}

function refreshAll(){
  var discPct = getDiscountPct(getTotalQty());
  Object.keys(rowRefs).forEach(function(n){
    var r = getRowByNum(parseInt(n,10));
    if (!r) return;
    var ref = rowRefs[n];
    var isPicked = picked[n]!==undefined &amp;&amp; picked[n]&gt;0;
    var qty = isPicked ? picked[n] : 0;
    var bp = getBasePrice(r);
    var dp = calcPriceWithDiscount(r, discPct);

    ref.tr.classList.remove('picked','discount-active');
    if (isPicked) ref.tr.classList.add('picked');
    if (isPicked &amp;&amp; discPct&gt;0) ref.tr.classList.add('discount-active');

    ref.star.textContent = isPicked ? '★' : '☆';
    ref.star.classList.toggle('on', isPicked);

    if (document.activeElement !== ref.qty){
      ref.qty.value = (picked[n]!==undefined) ? picked[n] : '';
    }

    ref.cellPriceOld.textContent = fmt(bp) + ' ₽';
    ref.cellPrice.textContent = discPct&gt;0 ? fmt(dp)+' ₽' : fmt(bp)+' ₽';
    ref.cellPrice.classList.toggle('discount', discPct&gt;0);

    var sum = isPicked ? dp * qty : 0;
    ref.cellSum.textContent = isPicked ? fmt(sum)+' ₽' : '—';
  });
  updateStickyBar(); updateDiscountBanner();
}

function updateDiscountBanner(){
  var totalQty = getTotalQty();
  var discPct = getDiscountPct(totalQty);
  var next = getNextThreshold(totalQty);
  var maxThreshold = PROJECT.discounts[PROJECT.discounts.length-1].qty;
  var progressPct = Math.min(100, (totalQty / maxThreshold) * 100);

  var banner = document.getElementById('discountBanner');
  if (banner){
    if (discPct &gt; 0) banner.classList.add('active');
    else banner.classList.remove('active');
  }
  var fill = document.getElementById('progressFill');
  if (fill) fill.style.width = progressPct.toFixed(1)+'%';

  var lbl = document.getElementById('progressLabel');
  if (lbl){
    if (totalQty === 0) lbl.innerHTML = 'Отметьте позиции — узнаете свою скидку';
    else if (!next) lbl.innerHTML = '★ &lt;b&gt;МАКСИМАЛЬНАЯ СКИДКА '+discPct+'%&lt;/b&gt; применена ко всей партии';
    else lbl.innerHTML = 'Набрано: &lt;b&gt;'+fmt(totalQty)+' шт&lt;/b&gt; · до скидки '+next.pct+'% осталось '+fmt(next.qty-totalQty)+' шт';
  }
  var q = document.getElementById('discQty');
  if (q) q.textContent = fmt(totalQty)+' шт';
  var nxt = document.getElementById('discNext');
  if (nxt) nxt.textContent = next ? fmt(next.qty)+' шт (−'+next.pct+'%)' : 'Максимум ✓';
  var rate = document.getElementById('discRate');
  if (rate) rate.textContent = discPct+'%';
  var priceEl = document.getElementById('discPrice');
  if (priceEl){
    if (totalQty === 0) priceEl.textContent = '—';
    else if (discPct &gt; 0) priceEl.textContent = '−'+discPct+'% ко всей партии';
    else priceEl.textContent = 'Пока без скидки';
  }
}
function updateStickyBar(){
  var nums = Object.keys(picked).filter(function(n){return picked[n]&gt;0;});
  var count = nums.length;
  var totalQty = getTotalQty();
  var discPct = getDiscountPct(totalQty);
  var discountActive = discPct &gt; 0;
  var totalSum = 0;
  nums.forEach(function(n){
    var r = getRowByNum(parseInt(n,10));
    if (!r) return;
    totalSum += calcPriceWithDiscount(r, discPct) * picked[n];
  });
  document.getElementById('barCount').textContent = count;
  document.getElementById('barQty').textContent = fmt(totalQty);
  document.getElementById('barRate').textContent = discountActive ? '−'+discPct+'%' : '0%';
  document.getElementById('barTotal').textContent = fmt(totalSum)+' ₽';
  document.getElementById('barTotalLabel').textContent = discountActive ? 'Итого со скидкой' : 'Итого с НДС';
  var bar = document.getElementById('stickyBar');
  if (count &gt; 0) bar.classList.add('show'); else bar.classList.remove('show');
  if (discountActive) bar.classList.add('discount-active'); else bar.classList.remove('discount-active');
  var sel = document.getElementById('selectedCount');
  if (sel) sel.textContent = count;
}
function clearPicked(){
  if (!Object.keys(picked).length) return;
  if (!confirm('Очистить все отмеченные позиции?')) return;
  picked = {};
  Object.keys(rowRefs).forEach(function(n){ rowRefs[n].qty.value = ''; });
  render();
}
function resetAll(){
  if (!confirm('Сбросить все данные?')) return;
  picked = {}; state.search=''; state.cat='all'; state.isoColor='all'; state.sort={key:'catPrice',dir:1};
  document.getElementById('search').value='';
  renderChips(); render();
}
function scrollToTable(){
  document.getElementById('catalog').scrollIntoView({behavior:'smooth',block:'start'});
}

function downloadRequest(){
  var nums = Object.keys(picked).filter(function(n){return picked[n]&gt;0;});
  if (!nums.length){
    alert('Сначала отметьте нужные позиции звёздочкой ★ или задайте количество.');
    scrollToTable(); return;
  }
  var rows = PROJECT.data.filter(function(r){return picked[r.num]&gt;0;});
  var totalQty = getTotalQty();
  var discPct = getDiscountPct(totalQty);
  var header = ['№','Артикул','Наименование','Категория','Материал/цвет','Наличие','Цена без скидки, ₽','Скидка, %','Цена со скидкой, ₽','Кол-во, шт','Сумма, ₽'];
  var body = rows.map(function(r){
    var q = picked[r.num]||0;
    var dp = calcPriceWithDiscount(r, discPct);
    return [r.num, r.article, r.name, r.cat, r.material, r.stock, getBasePrice(r), discPct, dp, q, dp*q];
  });
  body.push([]);
  body.push(['','','ИТОГО:','','','',discPct+'%','',totalQty, Math.round(rows.reduce(function(s,r){
    return s + calcPriceWithDiscount(r, discPct) * (picked[r.num]||0);
  },0))]);
  var esc = function(v){return '"'+String(v==null?'':v).replace(/"/g,'""')+'"';};
  var csv = [header].concat(body).map(function(r){return r.map(esc).join(';');}).join('\r\n');
  var blob = new Blob(['\uFEFF'+csv],{type:'text/csv;charset=utf-8;'});
  var url = URL.createObjectURL(blob);
  var a = document.createElement('a');
  a.href = url;
  a.download = 'Запрос_КП_Пружины_'+today()+'.csv';
  document.body.appendChild(a); a.click(); a.remove();
  setTimeout(function(){URL.revokeObjectURL(url);},500);
}

function dlExcel(){
  var rows = getFiltered();
  var totalQty = getTotalQty();
  var discPct = getDiscountPct(totalQty);
  var header = ['№','Артикул','Наименование','Категория','Материал/цвет','Наличие','Цена без скидки, ₽','Скидка, %','Цена со скидкой, ₽'];
  var body = rows.map(function(r){
    return [r.num, r.article, r.name, r.cat, r.material, r.stock, getBasePrice(r), discPct, calcPriceWithDiscount(r, discPct)];
  });
  var esc = function(v){return String(v==null?'':v).replace(/&amp;/g,'&amp;amp;').replace(/&lt;/g,'&amp;lt;').replace(/&gt;/g,'&amp;gt;');};
  var table = '&lt;table border="1"&gt;&lt;thead&gt;&lt;tr&gt;'+header.map(function(h){return '&lt;th&gt;'+esc(h)+'&lt;/th&gt;';}).join('')+'&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;'+body.map(function(r){return '&lt;tr&gt;'+r.map(function(c){return '&lt;td&gt;'+esc(c)+'&lt;/td&gt;';}).join('')+'&lt;/tr&gt;';}).join('')+'&lt;/tbody&gt;&lt;/table&gt;';
  var html = '&lt;html xmlns:x="urn:schemas-microsoft-com:office:excel"&gt;&lt;head&gt;&lt;meta charset="UTF-8"&gt;&lt;/head&gt;&lt;body&gt;&lt;h2&gt;Пружины — прайс-лист (с НДС)&lt;/h2&gt;'+table+'&lt;/body&gt;&lt;/html&gt;';
  var blob = new Blob(['\uFEFF'+html],{type:'application/vnd.ms-excel;charset=utf-8;'});
  var url = URL.createObjectURL(blob);
  var a = document.createElement('a');
  a.href = url;
  a.download = 'Пружины_прайс_'+today()+'.xls';
  document.body.appendChild(a); a.click(); a.remove();
  setTimeout(function(){URL.revokeObjectURL(url);},500);
}

function sendByEmail(){
  var nums = Object.keys(picked).filter(function(n){return picked[n]&gt;0;});
  if (!nums.length){
    alert('Сначала отметьте нужные позиции звёздочкой ★.');
    scrollToTable(); return;
  }
  var rows = PROJECT.data.filter(function(r){return picked[r.num]&gt;0;});
  var totalQty = getTotalQty();
  var discPct = getDiscountPct(totalQty);
  var totalSum = 0;
  var lines = ['Здравствуйте!','','Прошу подготовить коммерческое предложение по пружинам:',''];
  rows.forEach(function(r){
    var q = picked[r.num]||0;
    var dp = calcPriceWithDiscount(r, discPct);
    totalSum += dp*q;
    lines.push('№'+r.num+' · '+r.article+' · '+r.name+' · '+r.cat+(r.material?' · '+r.material:'')+' · '+fmt(dp)+' ₽/шт × '+fmt(q)+' шт = '+fmt(dp*q)+' ₽');
  });
  lines.push('');
  lines.push('Всего позиций: '+rows.length);
  lines.push('Всего штук: '+fmt(totalQty));
  if (discPct &gt; 0) lines.push('✓ Скидка от объёма: '+discPct+'% (применена ко всей партии)');
  lines.push('ИТОГО: '+fmt(totalSum)+' ₽ (с НДС)');
  lines.push('');
  lines.push('Прошу указать сроки изготовления и условия отгрузки.');
  lines.push('');
  lines.push('С уважением,');
  var subject = encodeURIComponent('Запрос КП — пружины ('+rows.length+' поз.)');
  var body = encodeURIComponent(lines.join('\n'));
  window.location.href = 'mailto:'+PROJECT.email+'?subject='+subject+'&amp;body='+body;
}

document.addEventListener('DOMContentLoaded', function(){
  updateStats(); renderChips(); render();
  document.getElementById('search').addEventListener('input',function(e){
    state.search = e.target.value; render();
  });
  document.querySelectorAll('#tbl th.sortable').forEach(function(th){
    th.addEventListener('click',function(){
      var k = th.dataset.key;
      if (state.sort.key===k) state.sort.dir *= -1;
      else state.sort = {key:k, dir:1};
      render();
    });
  });
});
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</subtitle>
  <updated>2026-11-01T09:35:14Z</updated>
  <logo>https://pandoraburo.ru/ssl/u/pic/07/26436cc3c611f19d9efcd8c4a10874/-/0c723f71762611f1b3964aaba1665535.jpg</logo>
  <author>
    <name>1592962</name>
    <uri>https://www.pandoraburo.ru/</uri>
  </author>
</feed>
