<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://www.xn--80abmnojgpmk.xn--p1ai/" xml:lang="ru">
  <id>https://www.xn--80abmnojgpmk.xn--p1ai/sklad-vsego-chto-est-na-sklade-2</id>
  <link href="https://www.xn--80abmnojgpmk.xn--p1ai/sklad-vsego-chto-est-na-sklade-2.xml" rel="self"/>
  <title>Складские остатки</title>
  <subtitle type="html">&lt;p&gt;&lt;/p&gt;
&lt;style&gt;
  :root {
    --bg:    #0a0a0a;
    --bg2:   #141414;
    --bg3:   #1a1a1a;
    --line:  #3a2f10;
    --gold:  #d4af37;
    --goldB: #ffd700;
    --goldD: #8a7020;
  }
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
    background: var(--bg); color: var(--gold); line-height: 1.5; padding: 24px 16px;
  }
  ::selection { background: var(--gold); color: #000; }
  .wrap { max-width: 1500px; margin: 0 auto; }

  header {
    background: linear-gradient(135deg, #000000, #1a1408);
    color: var(--goldB); padding: 24px 28px; border-radius: 14px;
    margin-bottom: 20px; border: 1px solid var(--line);
    box-shadow: 0 8px 24px rgba(212,175,55,.08);
  }
  header h1 { font-size: 24px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; }
  header p { font-size: 13px; color: var(--goldD); margin-top: 4px; letter-spacing: .3px; }

  .tabs { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
  .tab {
    padding: 10px 18px; background: var(--bg2); border: 1px solid var(--line);
    border-radius: 10px; cursor: pointer; font-size: 14px; font-weight: 600;
    color: var(--goldD); transition: .15s; letter-spacing: .3px;
  }
  .tab:hover { border-color: var(--gold); color: var(--gold); }
  .tab.active { background: var(--gold); color: #000; border-color: var(--gold); }
  .tab.active:hover { background: var(--goldB); border-color: var(--goldB); }

  .panel { display: none; }
  .panel.active { display: block; }

  .info-box {
    background: var(--bg2); border: 1px solid var(--line); border-left: 3px solid var(--gold);
    color: var(--gold); border-radius: 12px; padding: 12px 16px;
    margin-bottom: 16px; font-size: 13px; line-height: 1.6;
  }
  .info-box b { color: var(--goldB); letter-spacing: .4px; }

  .toolbar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
  .btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 9px 14px; border-radius: 9px;
    border: 1px solid var(--line); background: var(--bg2);
    color: var(--gold); font-size: 13px; font-weight: 600;
    cursor: pointer; transition: .15s; font-family: inherit; letter-spacing: .3px;
  }
  .btn:hover { border-color: var(--gold); color: var(--goldB); background: var(--bg3); }
  .btn.primary { background: var(--gold); color: #000; border-color: var(--gold); }
  .btn.primary:hover { background: var(--goldB); border-color: var(--goldB); color: #000; }
  .btn.green { background: var(--bg2); border-color: var(--gold); color: var(--gold); }
  .btn.green:hover { background: var(--gold); color: #000; }

  .filters {
    background: var(--bg2); border: 1px solid var(--line); border-radius: 14px;
    padding: 20px; margin-bottom: 16px;
    display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 16px;
  }
  @media (max-width: 860px) { .filters { grid-template-columns: 1fr; } }
  .filters.two { grid-template-columns: 1.4fr 1fr; }
  .filters.one { grid-template-columns: 1fr; }

  .field { display: flex; flex-direction: column; gap: 6px; }
  .field label {
    font-size: 11px; font-weight: 700; color: var(--goldD);
    text-transform: uppercase; letter-spacing: 1px;
  }
  .field input, .field select {
    padding: 10px 12px; border: 1px solid var(--line); border-radius: 9px;
    font-size: 14px; background: var(--bg); color: var(--gold);
    outline: none; transition: .15s; font-family: inherit;
  }
  .field input::placeholder { color: #4a4018; }
  .field input:focus, .field select:focus {
    border-color: var(--gold); background: #000;
    box-shadow: 0 0 0 3px rgba(212,175,55,.15);
  }
  .field select option { background: var(--bg); color: var(--gold); }

  .table-card {
    background: var(--bg2); border: 1px solid var(--line);
    border-radius: 14px; overflow: hidden;
  }

  /* ==================== КОНТЕЙНЕР ТАБЛИЦЫ: СВЕЧЕНИЕ + ИСКРЫ + МОЛНИЯ ==================== */
  .table-scroll {
    position: relative;
    overflow: auto;
    max-height: 75vh;
    scroll-behavior: smooth;
    border-top: 1px solid #3a2f10;
    border-bottom: 1px solid #3a2f10;
    animation: edgeGlow 4s ease-in-out infinite;
    transition: box-shadow .4s ease;
  }
  .table-scroll:hover,
  .table-scroll.active-scroll {
    box-shadow:
      inset 0 0 30px rgba(212,175,55,.25),
      inset 0 0 60px rgba(255,140,0,.15);
  }
  .table-scroll::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, #ffd700, #ff5500, #ffd700, transparent);
    opacity: .8;
    pointer-events: none;
    z-index: 3;
    animation: topLine 3s ease-in-out infinite;
  }
  .table-scroll::after {
    content: '';
    position: absolute;
    bottom: 0; left: 0; right: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, #ffd700, #ff5500, #ffd700, transparent);
    opacity: .8;
    pointer-events: none;
    z-index: 3;
    animation: bottomLine 3s ease-in-out infinite;
  }
  @keyframes edgeGlow {
    0%, 100% { box-shadow: inset 0 0 12px rgba(212,175,55,.15); }
    50%      { box-shadow: inset 0 0 28px rgba(255,215,0,.45); }
  }
  @keyframes topLine {
    0%, 100% { opacity: .5; }
    50%      { opacity: 1; }
  }
  @keyframes bottomLine {
    0%, 100% { opacity: 1; }
    50%      { opacity: .5; }
  }

  table { border-collapse: collapse; width: 100%; font-size: 13px; min-width: 900px; }
  thead th {
    position: sticky; top: 0; z-index: 2;
    background: #000; color: var(--goldB); padding: 11px 12px;
    text-align: left; font-weight: 700; font-size: 11px;
    text-transform: uppercase; letter-spacing: 1px; white-space: nowrap;
    cursor: pointer; user-select: none; transition: .15s;
    border-bottom: 2px solid var(--gold);
  }
  thead th:hover { background: #1a1408; }
  thead th.sortable::after { content: ' ⇅'; opacity: .5; margin-left: 4px; color: var(--gold); }
  thead th.asc::after { content: ' ▲'; opacity: 1; color: var(--goldB); }
  thead th.desc::after { content: ' ▼'; opacity: 1; color: var(--goldB); }
  thead th.no-sort { cursor: default; }
  thead th.no-sort::after { content: ''; }

  tbody td { padding: 10px 12px; border-bottom: 1px solid #1a1a1a; color: var(--gold); vertical-align: top; }
  tbody tr:nth-child(even) { background: #0f0f0f; }
  tbody tr {
    transition: background .15s ease, box-shadow .15s ease;
  }
  tbody tr:hover {
    background: #1a1408;
    box-shadow:
      inset 4px 0 0 #ffd700,
      inset -4px 0 0 #ffd700,
      0 0 20px rgba(255,215,0,.15);
  }
  td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
  td.price { font-weight: 800; color: var(--goldB); }
  td.cost  { font-weight: 700; color: #e8c860; }

  .badge {
    display: inline-block; padding: 2px 8px; border-radius: 20px;
    font-size: 10px; font-weight: 700; letter-spacing: .4px;
    background: #1a1408; color: var(--gold); border: 1px solid var(--line);
  }
  .badge.izn  { background: #1a0e08; color: #e8b060; border-color: #4a3018; }
  .badge.ost  { background: #0e1a08; color: #c8d870; border-color: #304a18; }
  .badge.arti { background: #1a1208; color: #e8c060; border-color: #4a3a18; }
  .badge.arm  { background: #0e0e1a; color: #a8b8e8; border-color: #2a2a4a; }

  .empty { padding: 40px; text-align: center; color: var(--goldD); font-size: 14px; }
  footer { text-align: center; color: var(--goldD); font-size: 12px; margin-top: 24px; letter-spacing: .4px; }

  /* ==================== ЗОЛОТЫЕ ИСКРЯЩИЕСЯ СКРОЛЛБАРЫ (ОГОНЬ) ==================== */
  ::-webkit-scrollbar {
    width: 18px;
    height: 18px;
  }
  ::-webkit-scrollbar-track {
    background: #050505;
    border: 1px solid #2a2210;
    border-radius: 9px;
    box-shadow: inset 0 0 12px rgba(212,175,55,.2);
    position: relative;
  }
  ::-webkit-scrollbar-thumb {
    background: linear-gradient(180deg,
      #ffffcc 0%,
      #ffd700 15%,
      #ff8c00 35%,
      #d4af37 50%,
      #ff8c00 65%,
      #ffd700 85%,
      #ffffcc 100%);
    border: 1px solid #ffd700;
    border-radius: 9px;
    box-shadow:
      0 0 10px rgba(255,215,0,.9),
      0 0 20px rgba(255,140,0,.7),
      0 0 30px rgba(255,80,0,.4),
      inset 0 0 8px rgba(255,255,255,.5);
    background-size: 100% 200%;
    animation: fireFlow 2.5s linear infinite;
    position: relative;
    overflow: hidden;
  }
  /* Радужный отблеск поверх бегунка */
  ::-webkit-scrollbar-thumb::before {
    content: '';
    position: absolute;
    inset: 0;
    background: conic-gradient(
      from 0deg,
      rgba(255,0,128,.35),
      rgba(255,200,0,.5),
      rgba(0,255,128,.35),
      rgba(0,200,255,.4),
      rgba(160,0,255,.35),
      rgba(255,0,128,.35)
    );
    mix-blend-mode: overlay;
    animation: rainbowSpin 4s linear infinite;
    border-radius: 9px;
    pointer-events: none;
  }
  ::-webkit-scrollbar-thumb:hover {
    background: linear-gradient(180deg,
      #ffffff 0%,
      #ffffcc 20%,
      #ffd700 40%,
      #ff8c00 60%,
      #ffd700 80%,
      #ffffff 100%);
    box-shadow:
      0 0 18px rgba(255,215,0,1),
      0 0 36px rgba(255,140,0,.9),
      0 0 54px rgba(255,80,0,.6),
      inset 0 0 12px rgba(255,255,255,.8);
  }
  ::-webkit-scrollbar-thumb:active {
    background: linear-gradient(180deg, #ffd700, #ff5500);
    box-shadow:
      0 0 24px rgba(255,215,0,1),
      0 0 48px rgba(255,140,0,1),
      0 0 72px rgba(255,80,0,.8);
  }
  ::-webkit-scrollbar-corner { background: #050505; }

  /* Стрелки */
  ::-webkit-scrollbar-button:single-button {
    background-color: #0a0a0a;
    display: block;
    background-size: 12px;
    background-repeat: no-repeat;
    background-position: center;
    border: 1px solid #3a2f10;
    border-radius: 8px;
    height: 18px;
    width: 18px;
    box-shadow: inset 0 0 6px rgba(212,175,55,.4);
    transition: .2s;
  }
  ::-webkit-scrollbar-button:single-button:hover {
    background-color: #1a0e08;
    border-color: #ffd700;
    box-shadow:
      0 0 12px rgba(255,215,0,.9),
      inset 0 0 8px rgba(255,140,0,.5);
  }
  ::-webkit-scrollbar-button:single-button:vertical:decrement {
    background-image: url("data:image/svg+xml;utf8,&lt;svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'&gt;&lt;path d='M8 3 L13 11 L3 11 Z' fill='%23ffd700' stroke='%23ff5500' stroke-width='0.8'/&gt;&lt;/svg&gt;");
  }
  ::-webkit-scrollbar-button:single-button:vertical:increment {
    background-image: url("data:image/svg+xml;utf8,&lt;svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'&gt;&lt;path d='M8 13 L3 5 L13 5 Z' fill='%23ffd700' stroke='%23ff5500' stroke-width='0.8'/&gt;&lt;/svg&gt;");
  }
  ::-webkit-scrollbar-button:single-button:horizontal:decrement {
    background-image: url("data:image/svg+xml;utf8,&lt;svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'&gt;&lt;path d='M3 8 L11 3 L11 13 Z' fill='%23ffd700' stroke='%23ff5500' stroke-width='0.8'/&gt;&lt;/svg&gt;");
  }
  ::-webkit-scrollbar-button:single-button:horizontal:increment {
    background-image: url("data:image/svg+xml;utf8,&lt;svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'&gt;&lt;path d='M13 8 L5 13 L5 3 Z' fill='%23ffd700' stroke='%23ff5500' stroke-width='0.8'/&gt;&lt;/svg&gt;");
  }

  @keyframes fireFlow {
    0%   { background-position: 0% 0%; }
    100% { background-position: 0% 200%; }
  }
  @keyframes rainbowSpin {
    0%   { transform: rotate(0deg)   scale(1.5); }
    100% { transform: rotate(360deg) scale(1.5); }
  }

  /* Firefox */
  * {
    scrollbar-width: thin;
    scrollbar-color: #ffd700 #0a0a0a;
  }

  /* Мерцающие искры */
  .sparkle {
    position: absolute;
    width: 4px; height: 4px;
    border-radius: 50%;
    background: radial-gradient(circle, #fff 0%, #ffd700 40%, rgba(255,140,0,0) 70%);
    pointer-events: none;
    box-shadow: 0 0 8px #ffd700, 0 0 16px #ff8c00;
    animation: sparkleFloat 3s ease-in-out infinite;
    z-index: 4;
  }
  @keyframes sparkleFloat {
    0%   { transform: translateY(0) scale(0);   opacity: 0; }
    20%  { transform: translateY(-10px) scale(1); opacity: 1; }
    80%  { transform: translateY(-40px) scale(.6); opacity: .6; }
    100% { transform: translateY(-60px) scale(0); opacity: 0; }
  }

  /* Огненные частицы при скролле */
  .fire-particle {
    position: fixed;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: radial-gradient(circle, #fff 0%, #ffd700 30%, #ff5500 70%, rgba(255,0,0,0) 100%);
    box-shadow: 0 0 10px #ff8c00, 0 0 20px #ff5500;
    pointer-events: none;
    z-index: 9999;
    animation: fireFly 1.2s ease-out forwards;
  }
  @keyframes fireFly {
    0%   { transform: translate(0,0) scale(1);   opacity: 1; }
    100% { transform: translate(var(--dx, 0), var(--dy, -60px)) scale(0); opacity: 0; }
  }

  /* Молния при быстрой прокрутке */
  .lightning {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, transparent 0%, rgba(255,215,0,.7) 50%, transparent 100%);
    opacity: 0;
    pointer-events: none;
    z-index: 5;
    animation: lightningFlash 0.25s ease-out;
    border-radius: 12px;
  }
  @keyframes lightningFlash {
    0%   { opacity: 0; }
    30%  { opacity: 1; }
    60%  { opacity: .3; }
    100% { opacity: 0; }
  }

  /* Idle-пульсация */
  .idle-hint ::-webkit-scrollbar-thumb {
    animation: fireFlow 2.5s linear infinite, idlePulse 1.2s ease-in-out infinite;
  }
  @keyframes idlePulse {
    0%, 100% {
      box-shadow:
        0 0 10px rgba(255,215,0,.9),
        0 0 20px rgba(255,140,0,.7);
    }
    50% {
      box-shadow:
        0 0 22px rgba(255,215,0,1),
        0 0 44px rgba(255,140,0,1),
        0 0 66px rgba(255,80,0,.7);
    }
  }

  @media print {
    body { background: #fff; color: #000; padding: 0; }
    header { background: #000 !important; color: var(--goldB) !important;
      -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    .tabs, .toolbar, .filters, .info-box, .sparkle, .fire-particle, .lightning { display: none !important; }
    .panel:not(.active) { display: none; }
    .table-scroll { max-height: none; overflow: visible; animation: none; }
    .table-scroll::before, .table-scroll::after { display: none; }
    thead th { background: #000 !important; color: var(--goldB) !important;
      -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    tbody td { color: #000; border-bottom: 1px solid #ccc; }
    tbody tr:nth-child(even) { background: #f5f5f5; }
    .table-card { background: #fff; border: 1px solid #999; }
    .badge { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    footer { color: #666; }
  }
&lt;/style&gt;
&lt;div class="wrap"&gt;&lt;header&gt;
&lt;h1&gt;Склад&lt;/h1&gt;
&lt;p&gt;Прайс-лист &amp;middot; цены с НДС &amp;middot; наличие и объёмы уточняйте у менеджеров&lt;/p&gt;
&lt;/header&gt;
&lt;div class="tabs"&gt;
&lt;div class="tab active" data-tab="catalog"&gt;Рядовые стали&lt;/div&gt;
&lt;div class="tab" data-tab="stock"&gt;Остатки по складу&lt;/div&gt;
&lt;div class="tab" data-tab="arti"&gt;Филиал Арти&lt;/div&gt;
&lt;div class="tab" data-tab="armor"&gt;Броня и защита&lt;/div&gt;
&lt;/div&gt;
&lt;div class="panel active" id="panel-catalog"&gt;
&lt;div class="toolbar"&gt;&lt;button class="btn primary" onclick="downloadCSV('catalog')"&gt;Скачать CSV&lt;/button&gt; &lt;button class="btn green" onclick="downloadExcel('catalog')"&gt;Скачать Excel&lt;/button&gt; &lt;button class="btn" onclick="window.print()"&gt;Печать / PDF&lt;/button&gt; &lt;button class="btn" onclick="resetCatalog()"&gt;Сбросить поиск&lt;/button&gt;&lt;/div&gt;
&lt;div class="filters one"&gt;
&lt;div class="field"&gt;&lt;label&gt;Поиск по позиции&lt;/label&gt; &lt;input id="catSearch" placeholder="Например: износостойкий 10, KCV-40, 25…" type="text" /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="table-card"&gt;
&lt;div class="table-scroll"&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr id="catHead"&gt;
&lt;th class="sortable" data-key="cat"&gt;Категория&lt;/th&gt;
&lt;th class="sortable" data-key="name"&gt;Наименование&lt;/th&gt;
&lt;th class="sortable" data-key="size"&gt;Мерность&lt;/th&gt;
&lt;th class="sortable" data-key="grade"&gt;Марка стали&lt;/th&gt;
&lt;th class="sortable" data-key="gost"&gt;ГОСТ&lt;/th&gt;
&lt;th class="sortable num" data-key="w1"&gt;Вес 1 шт, кг&lt;/th&gt;
&lt;th class="sortable num" data-key="wm"&gt;Вес 1 пм, кг&lt;/th&gt;
&lt;th class="no-sort"&gt;ЕИ&lt;/th&gt;
&lt;th class="sortable num" data-key="price"&gt;Цена, ₽/т&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody id="catBody"&gt;&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="empty" id="catEmpty" style="display: none;"&gt;Ничего не найдено.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="panel" id="panel-stock"&gt;
&lt;div class="toolbar"&gt;&lt;button class="btn primary" onclick="downloadCSV('stock')"&gt;Скачать CSV&lt;/button&gt; &lt;button class="btn green" onclick="downloadExcel('stock')"&gt;Скачать Excel&lt;/button&gt; &lt;button class="btn" onclick="window.print()"&gt;Печать / PDF&lt;/button&gt; &lt;button class="btn" onclick="resetStock()"&gt;Сбросить поиск&lt;/button&gt;&lt;/div&gt;
&lt;div class="filters one"&gt;
&lt;div class="field"&gt;&lt;label&gt;Поиск по позиции&lt;/label&gt; &lt;input id="stSearch" placeholder="Например: Weldus 690, KCV-40, 16 2м…" type="text" /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="table-card"&gt;
&lt;div class="table-scroll"&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr id="stHead"&gt;
&lt;th class="sortable" data-key="name"&gt;Наименование&lt;/th&gt;
&lt;th class="sortable" data-key="grade"&gt;Марка стали&lt;/th&gt;
&lt;th class="no-sort"&gt;Ед. изм.&lt;/th&gt;
&lt;th class="sortable num" data-key="qtyNum"&gt;Кол-во&lt;/th&gt;
&lt;th class="sortable num" data-key="price"&gt;Цена, ₽/т&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody id="stBody"&gt;&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="empty" id="stEmpty" style="display: none;"&gt;Ничего не найдено.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="panel" id="panel-arti"&gt;
&lt;div class="info-box"&gt;&lt;strong&gt;Филиал Арти&lt;/strong&gt; &amp;middot; Сталь марки NM по стандарту GB/T 24186-2022. Высокопрочная износостойкая сталь для работы в условиях интенсивного абразивного износа и ударных нагрузок. Твёрдость 300&amp;ndash;600 HB, сочетает высокую прочность и хорошую свариваемость. Производство China. Срок поставки 45&amp;ndash;60 дней, предоплата 30&amp;ndash;50%. Цены с НДС. &lt;br /&gt;&lt;strong&gt;Приплаты:&lt;/strong&gt; резка по ширине кратно 1000 мм +30% + резка; резка по ширине в размер +60%.&lt;/div&gt;
&lt;div class="toolbar"&gt;&lt;button class="btn primary" onclick="downloadCSV('arti')"&gt;Скачать CSV&lt;/button&gt; &lt;button class="btn green" onclick="downloadExcel('arti')"&gt;Скачать Excel&lt;/button&gt; &lt;button class="btn" onclick="window.print()"&gt;Печать / PDF&lt;/button&gt; &lt;button class="btn" onclick="resetArti()"&gt;Сбросить поиск&lt;/button&gt;&lt;/div&gt;
&lt;div class="filters"&gt;
&lt;div class="field"&gt;&lt;label&gt;Поиск по позиции&lt;/label&gt; &lt;input id="aSearch" placeholder="Например: 10×2000, NM450, 25…" type="text" /&gt;&lt;/div&gt;
&lt;div class="field"&gt;&lt;label&gt;Толщина, мм&lt;/label&gt;&lt;select id="aThk"&gt;
&lt;option value=""&gt;Все толщины&lt;/option&gt;
&lt;/select&gt;&lt;/div&gt;
&lt;div class="field"&gt;&lt;label&gt;Марка стали&lt;/label&gt;&lt;select id="aGrade"&gt;
&lt;option value=""&gt;Все марки&lt;/option&gt;
&lt;/select&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="table-card"&gt;
&lt;div class="table-scroll"&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr id="aHead"&gt;
&lt;th class="sortable num" data-key="thk"&gt;Толщина, мм&lt;/th&gt;
&lt;th class="sortable" data-key="name"&gt;Наименование&lt;/th&gt;
&lt;th class="sortable" data-key="grade"&gt;Марка стали&lt;/th&gt;
&lt;th class="sortable" data-key="size"&gt;Размер, мм&lt;/th&gt;
&lt;th class="sortable" data-key="gost"&gt;ГОСТ&lt;/th&gt;
&lt;th class="no-sort"&gt;ЕИ&lt;/th&gt;
&lt;th class="sortable num" data-key="price"&gt;Цена, ₽/т&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody id="aBody"&gt;&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="empty" id="aEmpty" style="display: none;"&gt;Ничего не найдено.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="panel" id="panel-armor"&gt;
&lt;div class="info-box"&gt;&lt;strong&gt;Броня и защита&lt;/strong&gt; &amp;middot; Собственное производство. Пулестойкая, износостойкая и противоосколочная сталь. Классы защиты Бр2&amp;ndash;Бр6 по ГОСТ Р 51112 / ГОСТ Р 50963. Цены указаны с НДС. Наличие и сроки уточняйте у менеджеров.&lt;/div&gt;
&lt;div class="toolbar"&gt;&lt;button class="btn primary" onclick="downloadCSV('armor')"&gt;Скачать CSV&lt;/button&gt; &lt;button class="btn green" onclick="downloadExcel('armor')"&gt;Скачать Excel&lt;/button&gt; &lt;button class="btn" onclick="window.print()"&gt;Печать / PDF&lt;/button&gt; &lt;button class="btn" onclick="resetArmor()"&gt;Сбросить поиск&lt;/button&gt;&lt;/div&gt;
&lt;div class="filters"&gt;
&lt;div class="field"&gt;&lt;label&gt;Поиск по позиции&lt;/label&gt; &lt;input id="arSearch" placeholder="Например: C500, БТВТ, Бр4, 10×2000…" type="text" /&gt;&lt;/div&gt;
&lt;div class="field"&gt;&lt;label&gt;Категория&lt;/label&gt;&lt;select id="arCat"&gt;
&lt;option value=""&gt;Все категории&lt;/option&gt;
&lt;option&gt;Пулестойкая&lt;/option&gt;
&lt;option&gt;Износостойкая&lt;/option&gt;
&lt;option&gt;Противоосколочная&lt;/option&gt;
&lt;/select&gt;&lt;/div&gt;
&lt;div class="field"&gt;&lt;label&gt;Класс защиты&lt;/label&gt;&lt;select id="arClass"&gt;
&lt;option value=""&gt;Все классы&lt;/option&gt;
&lt;/select&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="table-card"&gt;
&lt;div class="table-scroll"&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr id="arHead"&gt;
&lt;th class="sortable" data-key="cat"&gt;Категория&lt;/th&gt;
&lt;th class="sortable" data-key="mark"&gt;Марка&lt;/th&gt;
&lt;th class="sortable" data-key="tu"&gt;ТУ&lt;/th&gt;
&lt;th class="sortable" data-key="size"&gt;Размер, мм&lt;/th&gt;
&lt;th class="sortable" data-key="klass"&gt;Класс&lt;/th&gt;
&lt;th class="sortable num" data-key="stockNum"&gt;Наличие, листов&lt;/th&gt;
&lt;th class="sortable num" data-key="priceSheet"&gt;Цена/лист, ₽&lt;/th&gt;
&lt;th class="sortable num" data-key="priceKg"&gt;Цена/кг, ₽&lt;/th&gt;
&lt;th class="sortable" data-key="term"&gt;Сроки&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody id="arBody"&gt;&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="empty" id="arEmpty" style="display: none;"&gt;Ничего не найдено.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;footer&gt;Склад &amp;middot; цены указаны с НДС &amp;middot; наличие уточняйте у менеджеров&lt;/footer&gt;&lt;/div&gt;
&lt;script&gt;
/* ============ ТИХАЯ ПРОВЕРКА ДАННЫХ ============ */
(function(){
  const ORG = ['сталепромышленная','спк','spk','spk.ru','spkekb','металлбренд','metal-brand','metalbrend','металлсервис','ммк','евраз','северсталь','нлмк','тмк','омк','чмк','мечел','металлоинвест','омз','вмз','зсмк','ssab','ruukki','arcelormittal','thyssenkrupp','voestalpine','dillinger','outokumpu','posco','jfe','baosteel','wisco','ansteel','shagang','hesteel','металлопрокат.ру','metal100','metallotorg','metaltorg','аметист'];
  const PAT = [
    {re:/[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}/gi, what:'e-mail'},
    {re:/(?:https?:\/\/|www\.)[^\s]+/gi, what:'ссылка'},
    {re:/(?:\+7|8)[\s\-\(\)]?\d{3}[\s\-\(\)]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}/g, what:'телефон'},
    {re:/ИНН\s*\d{9,12}/gi, what:'ИНН'}, {re:/ОГРН\s*\d{13,15}/gi, what:'ОГРН'},
    {re:/КПП\s*\d{9}/gi, what:'КПП'}, {re:/БИК\s*\d{9}/gi, what:'БИК'},
    {re:/ООО\s+[«"'][^»"']+[»"']/gi, what:'название ООО'},
    {re:/ОАО\s+[«"'][^»"']+[»"']/gi, what:'название ОАО'},
    {re:/АО\s+[«"'][^»"']+[»"']/gi, what:'название АО'},
    {re:/ПАО\s+[«"'][^»"']+[»"']/gi, what:'название ПАО'}
  ];
  window.scan = function(label, data){
    const errs = [];
    const walk = (o, p) =&gt; {
      if (o == null) return;
      if (typeof o === 'string' || typeof o === 'number') {
        const s = String(o), low = s.toLowerCase();
        ORG.forEach(w =&gt; { if (low.includes(w)) errs.push({p, t:'организация', v:w}); });
        PAT.forEach(pt =&gt; { const m = s.match(pt.re); if (m) m.forEach(x =&gt; errs.push({p, t:pt.what, v:x})); });
        return;
      }
      if (Array.isArray(o)) return o.forEach((v,i) =&gt; walk(v, `${p}[${i}]`));
      if (typeof o === 'object') return Object.entries(o).forEach(([k,v]) =&gt; walk(v, `${p}.${k}`));
    };
    walk(data, label);
    if (errs.length) console.warn('Проверка «'+label+'» нашла посторонние данные:', errs);
    return data;
  };
})();

/* ==================== РЯДОВЫЕ СТАЛИ ==================== */
const catalog = scan('catalog', [
  {cat:'Высокопрочная', name:'Лист Г/К высокопрочный 8',  size:'1.5м 6м', grade:'Weldus 500МС', gost:'СТО', w1:565.2, wm:62.8,  price:220500},
  {cat:'Высокопрочная', name:'Лист Г/К высокопрочный 10', size:'1.5м 6м', grade:'Weldus 500МС', gost:'СТО', w1:706.5, wm:78.5,  price:220500},
  {cat:'Высокопрочная', name:'Лист Г/К высокопрочный 12', size:'1.5м 6м', grade:'Weldus 500МС', gost:'СТО', w1:847.8, wm:94.2,  price:220500},
  {cat:'Высокопрочная', name:'Лист Г/К высокопрочный 8',  size:'2м 6м', grade:'Weldus 690', gost:'СТО', w1:753.6,  wm:62.8,   price:264600},
  {cat:'Высокопрочная', name:'Лист Г/К высокопрочный 10', size:'2м 6м', grade:'Weldus 690', gost:'СТО', w1:942,    wm:78.5,   price:264600},
  {cat:'Высокопрочная', name:'Лист Г/К высокопрочный 12', size:'2м 6м', grade:'Weldus 690', gost:'СТО', w1:1130.4, wm:94.2,   price:264600},
  {cat:'Высокопрочная', name:'Лист Г/К высокопрочный 16', size:'2м 6м', grade:'Weldus 690', gost:'СТО', w1:1507.2, wm:125.6,  price:264600},
  {cat:'Высокопрочная', name:'Лист Г/К высокопрочный 20', size:'2м 6м', grade:'Weldus 690', gost:'СТО', w1:1884,   wm:157,    price:264600},
  {cat:'Высокопрочная', name:'Лист Г/К высокопрочный 25', size:'2м 6м', grade:'Weldus 690', gost:'СТО', w1:2355,   wm:196.25, price:264600},
  {cat:'Высокопрочная', name:'Лист Г/К высокопрочный 30', size:'2м 6м', grade:'Weldus 690', gost:'СТО', w1:2826,   wm:235.5,  price:264600},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 5 KCV-20',     size:'2м 6м', grade:'УЗК NM400', gost:'GB/T 24186-22', w1:471,    wm:39.25, price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 8 KCV-20',     size:'2м 6м', grade:'NM450',     gost:'GB/T 24186-22', w1:753.6,  wm:62.8,  price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 8 KCV-40 TUF', size:'2м 6м', grade:'NM450',     gost:'GB/T 24186-22', w1:753.6,  wm:62.8,  price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 8 KCV-20',     size:'2м 6м', grade:'NM500',     gost:'GB/T 24186-22', w1:753.6,  wm:62.8,  price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 10 KCV-40 TUF',size:'2м 6м', grade:'NM450',     gost:'GB/T 24186-22', w1:942,    wm:78.5,  price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 10 KCV-20',    size:'2м 6м', grade:'NM450',     gost:'GB/T 24186-22', w1:942,    wm:78.5,  price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 10 KCV-40 TUF',size:'2м 6м', grade:'NM500',     gost:'GB/T 24186-22', w1:942,    wm:78.5,  price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 10 KCV-20',    size:'2м 6м', grade:'NM500',     gost:'GB/T 24186-22', w1:942,    wm:78.5,  price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 12 KCV-40 TUF',size:'2м 6м', grade:'УЗК NM400', gost:'GB/T 24186-22', w1:1130.4, wm:94.2,  price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 12 KCV-20',    size:'2м 6м', grade:'NM450',     gost:'GB/T 24186-22', w1:1130.4, wm:94.2,  price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 12 KCV-40 TUF',size:'2м 6м', grade:'УЗК NM450', gost:'GB/T 24186-22', w1:1130.4, wm:94.2,  price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 12 KCV-20',    size:'2м 6м', grade:'NM500',     gost:'GB/T 24186-22', w1:1130.4, wm:94.2,  price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 16 KCV-40 TUF',size:'2м 6м', grade:'NM450',     gost:'GB/T 24186-22', w1:1507.2, wm:125.6, price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 16 KCV-20',    size:'2м 6м', grade:'NM450',     gost:'GB/T 24186-22', w1:1507.2, wm:125.6, price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 16 KCV-40 TUF',size:'2м 6м', grade:'NM500',     gost:'GB/T 24186-22', w1:1507.2, wm:125.6, price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 16 KCV-20',    size:'2м 6м', grade:'NM500',     gost:'GB/T 24186-22', w1:1507.2, wm:125.6, price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 20 KCV-40 TUF',size:'2м 6м', grade:'NM450',     gost:'GB/T 24186-22', w1:1884,   wm:157,   price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 20 KCV-20',    size:'2м 6м', grade:'NM450',     gost:'GB/T 24186-22', w1:1884,   wm:157,   price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 20 KCV-20',    size:'2м 6м', grade:'NM500',     gost:'GB/T 24186-22', w1:1884,   wm:157,   price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 20 KCV-40 TUF',size:'2м 6м', grade:'NM500',     gost:'GB/T 24186-22', w1:1884,   wm:157,   price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 25',           size:'2м 6м', grade:'NM450',     gost:'GB/T 24186-22', w1:2355,   wm:196.25,price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 25 KCV-40 TUF',size:'2м 6м', grade:'УЗК NM450', gost:'GB/T 24186-22', w1:2355,   wm:196.25,price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 25 KCV-40 TUF',size:'2м 6м', grade:'УЗК NM500', gost:'GB/T 24186-22', w1:2355,   wm:196.25,price:252000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 30 KCV-20 NiRes',size:'2м 6м',grade:'NM450',   gost:'GB/T 24186-22', w1:2826,   wm:235.5, price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 30 KCV-20 NiRes',size:'2м 6м',grade:'NM500',   gost:'GB/T 24186-22', w1:2826,   wm:235.5, price:256200},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 40 KCV-20 NiRes',size:'2м 6м',grade:'NM400',   gost:'GB/T 24186-22', w1:3768,   wm:314,   price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 40 KCV-20 NiRes',size:'2м 6м',grade:'NM450',   gost:'GB/T 24186-22', w1:3768,   wm:314,   price:238000},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 45',           size:'2.2м 6м',grade:'NM400',   gost:'GB/T 24186-22', w1:4662.9, wm:353.25,price:267400},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 50 KCV-20 NiRes',size:'2м 6м',grade:'NM400',   gost:'GB/T 24186-22', w1:4710,   wm:392.5, price:278600},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 50 KCV-40',    size:'2м 6м', grade:'УЗК NM450', gost:'GB/T 24186-22', w1:4710,   wm:392.5, price:278600},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 50',           size:'2м 6м', grade:'NM500',     gost:'GB/T 24186-22', w1:4710,   wm:392.5, price:278600},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 60 KCV-20 NiRes',size:'2м 6м',grade:'NM400',   gost:'GB/T 24186-22', w1:5652,   wm:471,   price:319200},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 70 KCV-20 NiRes',size:'2м 6м',grade:'NM400',   gost:'GB/T 24186-22', w1:6594,   wm:549.5, price:319200},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 75 KCV-20 NiRes',size:'2м 6м',grade:'NM400',   gost:'GB/T 24186-22', w1:null,   wm:null,  price:289884},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 75 KCV-20 NiRes',size:'2м 6м',grade:'УЗК NM500',gost:'GB/T 24186-22', w1:null,   wm:null,  price:289884},
  {cat:'Износостойкая', name:'Лист Г/К износостойкий 80 KCV-20 NiRes',size:'2м 6м',grade:'NM400',   gost:'GB/T 24186-22', w1:null,   wm:null,  price:289884}
]);

/* ==================== ОСТАТКИ ==================== */
const stock = scan('stock', [
  {name:'Лист Г/К высокопрочный 12 2м 6м Weldus 690 СТО 6,000М 4 ШТ 2X6M', grade:'Weldus 690', qty:'4,383',  price:217770},
  {name:'Лист Г/К высокопрочный 12 2м 6м Weldus 690 СТО 6,000М 3 ШТ 2X6M', grade:'Weldus 690', qty:'3,356',  price:217770},
  {name:'Лист Г/К высокопрочный 16 2м 6м Weldus 690 СТО 6,000М 11 ШТ 2X6M',grade:'Weldus 690', qty:'16,28',  price:217770},
  {name:'Лист Г/К высокопрочный 16 2м 6м Weldus 690 СТО 6,000М 4 ШТ 2X6M', grade:'Weldus 690', qty:'5,988',  price:217770},
  {name:'Лист Г/К высокопрочный 16 2м 6м Weldus 690 СТО 6,000М 5 ШТ 2X6M', grade:'Weldus 690', qty:'7,495',  price:217770},
  {name:'Лист Г/К высокопрочный 20 2м 6м Weldus 690 СТО 6,000М 1 ШТ 2X6M', grade:'Weldus 690', qty:'1,878',  price:217770},
  {name:'Лист Г/К высокопрочный 20 2м 6м Weldus 690 СТО 6,000М 4 ШТ 2X6M', grade:'Weldus 690', qty:'7,376',  price:217770},
  {name:'Лист Г/К высокопрочный 20 2м 6м Weldus 690 СТО 6,000М 5 ШТ 2X6M', grade:'Weldus 690', qty:'9,275',  price:217770},
  {name:'Лист Г/К высокопрочный 20 2м 6м Weldus 690 СТО 6,000М 11 ШТ 2X6M',grade:'Weldus 690', qty:'20,636', price:217770},
  {name:'Лист Г/К высокопрочный 25 2м 6м Weldus 690 СТО 6,000М 4 ШТ 2X6M', grade:'Weldus 690', qty:'10,116', price:217770},
  {name:'Лист Г/К высокопрочный 25 2м 6м Weldus 690 СТО 6,000М 10 ШТ 2X6M',grade:'Weldus 690', qty:'23,53',  price:217770},
  {name:'Лист Г/К высокопрочный 30 2м 6м Weldus 690 СТО 6,000М 1 ШТ 2X6M', grade:'Weldus 690', qty:'1,848',  price:294000},
  {name:'Лист Г/К высокопрочный 10 2м 6м Weldus 690 СТО 6,000М 40 ШТ 2X6M',grade:'Weldus 690', qty:'38,056', price:315000},
  {name:'Лист Г/К высокопрочный 10 2м 6м Weldus 690 СТО 6,000М 1 ШТ',      grade:'Weldus 690', qty:'0,91',   price:315000},
  {name:'Лист Г/К высокопрочный 10 2м 6м Weldus 690 СТО 6,000М 7 ШТ 2X6M', grade:'Weldus 690', qty:'6,498',  price:217770},
  {name:'Лист Г/К высокопрочный 10 2м 6м Weldus 690 СТО 6,000М 14 ШТ 2X6M',grade:'Weldus 690', qty:'12,723', price:217770},
  {name:'Лист Г/К высокопрочный 10 2м 6м Weldus 690 СТО 6,000М 15 ШТ 2X6M',grade:'Weldus 690', qty:'13,8',   price:260470},
  {name:'Лист Г/К высокопрочный 10 2м 6м Weldus 690 СТО 6,000М 5 ШТ 2X6M', grade:'Weldus 690', qty:'4,624',  price:217770},
  {name:'Лист Г/К высокопрочный 12 2м 6м Weldus 690 СТО 6,000М 18 ШТ 2X6M',grade:'Weldus 690', qty:'19,826', price:217770},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-20 NM450 GB/T 24186-22 6,000M 1 ШТ 2X6',   grade:'NM450', qty:'0,942',  price:220500},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-20 NM450 GB/T 24186-22 6,000M 1 ШТ 2X6M',  grade:'NM450', qty:'0,628',  price:315000},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-20 NM450 GB/T 24186-22 6,000М 21 ШТ 2X6M', grade:'NM450', qty:'19,782', price:214200},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 21 ШТ 2X6M', grade:'NM500', qty:'19,782', price:214200},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 4 ШТ 2X6M',  grade:'NM500', qty:'3,768',  price:218400},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 46 ШТ 2X6M', grade:'NM500', qty:'43,332', price:214200},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-40 TUF NM500 GB/T 24186-22 6,000М 5 ШТ 2X6M', grade:'NM500', qty:'4,71',  price:228200},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-40 TUF NM500 GB/T 24186-22 6,000М 14 ШТ 2X6M',grade:'NM500', qty:'13,188',price:224000},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-40 TUF NM500 GB/T 24186-22 6,000М 10 ШТ 2X6M',grade:'NM500', qty:'9,42',  price:226100},
  {name:'Лист Г/К износостойкий 10 2м 6м NM450 GB/T 24186-22 6,000М 0 ШТ',              grade:'NM450', qty:'0,095',  price:329700},
  {name:'Лист Г/К износостойкий 10 2м 6м УЗК KCV-40 грунт NM400 GB/T 24186-22 6,000М 0 ШТ', grade:'УЗК NM400', qty:'0,232', price:317100},
  {name:'Лист Г/К износостойкий 12 2м 6м KCV-20 NM450 GB/T 24186-22 6,000М 1 ШТ 2X6M', grade:'NM450', qty:'1,115', price:295960},
  {name:'Лист Г/К износостойкий 12 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 1 ШТ 2X6M', grade:'NM500', qty:'0,565', price:317100},
  {name:'Лист Г/К износостойкий 12 2м 6м УЗК KCV-40 грунт NM450 GB/T 24186-22 6,000М 36 ШТ 2X6M', grade:'УЗК NM450', qty:'40,68', price:215600},
  {name:'Лист Г/К износостойкий 12 2м 6м УЗК KCV-40 грунт NM450 GB/T 24186-22 6,000М 1 ШТ 2X6M',  grade:'УЗК NM450', qty:'0,752', price:317100},
  {name:'Лист Г/К износостойкий 12 2м 6м УЗК KCV-40 грунт NM450 GB/T 24186-22 6,000М 1 ШТ 2X6M',  grade:'УЗК NM450', qty:'0,565', price:317100},
  {name:'Лист Г/К износостойкий 12 2м 6м УЗК KCV-40 грунт NM450 GB/T 24186-22 6,000М 0 ШТ 2X6M',  grade:'УЗК NM450', qty:'0,188', price:317100},
  {name:'Лист Г/К износостойкий 12 2м 6м УЗК KCV-40 грунт TUF NM400 GB/T 24186-22 6,000М 2 ШТ 2X6M', grade:'УЗК NM400', qty:'2,26', price:233800},
  {name:'Лист Г/К износостойкий 16 2м 6м KCV-20 NM450 GB/T 24186-22 6,000М 6 ШТ 2X6M',  grade:'NM450', qty:'9,042',  price:217700},
  {name:'Лист Г/К износостойкий 16 2м 6м KCV-20 NM450 GB/T 24186-22 6,000М 11 ШТ 2X6M', grade:'NM450', qty:'16,577', price:215600},
  {name:'Лист Г/К износостойкий 16 2м 6м KCV-20 NM450 GB/T 24186-22 6,000М 0 ШТ 2X6M',  grade:'NM450', qty:'0,496',  price:317100},
  {name:'Лист Г/К износостойкий 16 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 14 ШТ 2X6',  grade:'NM500', qty:'21,098', price:215600},
  {name:'Лист Г/К износостойкий 16 2м 6м KCV-40 TUF NM450 GB/T 24186-22 6,000М 0 ШТ 2X6M', grade:'NM450', qty:'0,251', price:338100},
  {name:'Лист Г/К износостойкий 16 2м 6м KCV-40 TUF NM500 GB/T 24186-22 6,000М 4 ШТ 2X6',  grade:'NM500', qty:'6,028', price:229908},
  {name:'Лист Г/К износостойкий 16 2м 6м KCV-40 TUF NM500 GB/T 24186-22 6,000М 1 ШТ 2X6',  grade:'NM500', qty:'1,507', price:229908},
  {name:'Лист Г/К износостойкий 16 2м 6м УЗК KCV-20 NM400 GB/T 24186-22 6,000М 2 ШТ 2X6M 400', grade:'УЗК NM400', qty:'3,03', price:219800},
  {name:'Лист Г/К износостойкий 16 2м 6м УЗК KCV-20 NM400 GB/T 24186-22 6,000М 5 ШТ 2X6M 400', grade:'УЗК NM400', qty:'7,575', price:217700},
  {name:'Лист Г/К износостойкий 20 2м 6м KCV-20 NM450 GB/T 24186-22 6,000М 5 ШТ 2X6M',  grade:'NM450', qty:'9,42',   price:217700},
  {name:'Лист Г/К износостойкий 20 2м 6м KCV-20 NM450 GB/T 24186-22 6,000М 1 ШТ 2X6M',  grade:'NM450', qty:'1,256',  price:295960},
  {name:'Лист Г/К износостойкий 8 2м 6м УЗК KCV-40 грунт TUF NM500 GB/T 24186-22 6,000М 1 ШТ 2X6M', grade:'NM500', qty:'0,377', price:315000},
  {name:'Лист Г/К износостойкий 8 2м 6м УЗК KCV-40 грунт TUF NM500 GB/T 24186-22 6,000М 7 ШТ 2X6M', grade:'NM500', qty:'5,278', price:216300},
  {name:'Лист Г/К износостойкий 8 2м 6м УЗК KCV-40 грунт TUF NM500 GB/T 24186-22 6,000М 5 ШТ 2X6M', grade:'NM500', qty:'3,77',  price:218400},
  {name:'Лист Г/К износостойкий 80 2м 6м KCV-20 NiRes NM400 GB/T 24186-22 6,000М 2 ШТ 2X6M', grade:'NM400', qty:'15,072', price:289884},
  {name:'Лист Г/К износостойкий 20 2м 6м NM450 GB/T 24186-22 6,000М 2 ШТ 2X6M',  grade:'NM450', qty:'3,77',   price:219800},
  {name:'Лист Г/К износостойкий 20 2м 6м NM450 GB/T 24186-22 6,000М 6 ШТ 2X6M',  grade:'NM450', qty:'11,32',  price:215600},
  {name:'Лист Г/К износостойкий 20 2м 6м NM450 GB/T 24186-22 6,000М 2 ШТ 2X6M',  grade:'NM450', qty:'3,78',   price:219800},
  {name:'Лист Г/К износостойкий 20 2м 6м NM450 GB/T 24186-22 6,000М 1 ШТ 2X6M',  grade:'NM450', qty:'1,89',   price:219800},
  {name:'Лист Г/К износостойкий 20 2м 6м NM450 GB/T 24186-22 6,000М 11 ШТ 2X6M', grade:'NM450', qty:'20,718', price:215600},
  {name:'Лист Г/К износостойкий 20 2м 6м NM450 GB/T 24186-22 6,000М 4 ШТ 2X6M',  grade:'NM450', qty:'7,54',   price:217700},
  {name:'Лист Г/К износостойкий 20 2м 6м NM450 GB/T 24186-22 6,000М 0 ШТ 2X6M',  grade:'NM450', qty:'0,345',  price:317100},
  {name:'Лист Г/К износостойкий 25 2м 6м NM450 GB/T 24186-22 6,000М 11 ШТ 2X6M', grade:'NM450', qty:'25,905', price:215600},
  {name:'Лист Г/К износостойкий 30 2м 6м NM450 GB/T 24186-22 6,000М 4 ШТ 2X6',   grade:'NM450', qty:'11,304', price:213416},
  {name:'Лист Г/К износостойкий 30 2м 6м NM450 GB/T 24186-22 6,000М 2 ШТ 2X6',   grade:'NM450', qty:'5,652',  price:212100},
  {name:'Лист Г/К износостойкий 40 2м 6м NM450 GB/T 24186-22 6,000М 15 ШТ 2X6M', grade:'NM450', qty:'55,258', price:215600},
  {name:'Лист Г/К износостойкий 40 2м 6м NM450 GB/T 24186-22 6,000М 4 ШТ 2*6M',  grade:'NM450', qty:'15,14',  price:215600},
  {name:'Лист Г/К износостойкий 40 2м 6м NM450 GB/T 24186-22 6,000М 18 ШТ 2X6M', grade:'NM450', qty:'67,824', price:215600},
  {name:'Лист Г/К износостойкий 5 2м 6м УЗК KCV-20 NM450 GB/T 24186-22 6,000М 11 ШТ 2X6', grade:'УЗК NM450', qty:'5,181', price:314300},
  {name:'Лист Г/К износостойкий 50 2м 6м KCV-20 NiRes NM400 GB/T 24186-22 6,000М 4 ШТ 2X6M', grade:'NM400', qty:'18,84', price:221200},
  {name:'Лист Г/К износостойкий 50 2м 6м УЗК KCV-40 грунт NM450 GB/T 24186-22 6,000М 0 ШТ 2X6,6M', grade:'УЗК NM450', qty:'0,682', price:325500},
  {name:'Лист Г/К износостойкий 60 2м 6м KCV-20 NiRes NM400 GB/T 24186-22 6,000М 1 ШТ 2X6M', grade:'NM400', qty:'5,208', price:326830},
  {name:'Лист Г/К износостойкий 70 2м 6м KCV-20 NiRes NM400 GB/T 24186-22 6,000М 4 ШТ 2X6M', grade:'NM400', qty:'26,376', price:289884},
  {name:'Лист Г/К износостойкий 75 2м 6м KCV-20 NiRes NM400 GB/T 24186-22 6,000М 2 ШТ 2X6M', grade:'NM400', qty:'14,13',  price:289884},
  {name:'Лист Г/К износостойкий 75 2м 6м УЗК KCV-20 грунт NiRes NM500 GB/T 24186-22 6,000М 3 ШТ 2X6M', grade:'УЗК NM500', qty:'17,662', price:289884},
  {name:'Лист Г/К износостойкий 8 2м 6м KCV-20 NM450 GB/T 24186-22 6,000М 1 ШТ 2X6M',  grade:'NM450', qty:'0,377', price:315000},
  {name:'Лист Г/К износостойкий 8 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 10 ШТ 2X6M', grade:'NM500', qty:'7,54',  price:216300},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 8 ШТ 2X6M', grade:'NM500', qty:'7,536', price:216300},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-40 TUF NM450 GB/T 24186-22 6,000М 1 ШТ 2X6M', grade:'NM450', qty:'0,697', price:329700},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-40 TUF NM450 GB/T 24186-22 6,000М 1 ШТ 2X6M', grade:'NM450', qty:'0,471', price:329700},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-40 TUF NM450 GB/T 24186-22 6,000М 1 ШТ 2*6',  grade:'NM450', qty:'0,471', price:329700},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-40 TUF NM500 GB/T 24186-22 6,000М 49 ШТ 2X6M', grade:'NM500', qty:'46,165',price:224196},
  {name:'Лист Г/К износостойкий 10 2м 6м KCV-40 TUF NM500 GB/T 24186-22 6,000М 12 ШТ 2X6M', grade:'NM500', qty:'11,304',price:224196},
  {name:'Лист Г/К износостойкий 8 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 3 ШТ 2X6M',  grade:'NM500', qty:'2,262', price:218400},
  {name:'Лист Г/К износостойкий 8 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 4 ШТ 2X6M',  grade:'NM500', qty:'3,267', price:218400},
  {name:'Лист Г/К износостойкий 8 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 0 ШТ 2X6M',  grade:'NM500', qty:'0,126', price:315000},
  {name:'Лист Г/К износостойкий 20 2м 6м KCV-20 NM500 GB/T 24186-22 6,000М 2 ШТ 2X6',  grade:'NM500', qty:'3,768', price:219800},
  {name:'Лист Г/К износостойкий 20 2м 6м NM450 GB/T 24186-22 6,000М 3 ШТ 2X6M',        grade:'NM450', qty:'5,65',  price:217700},
  {name:'Лист ОЦ 3 1.25м 2.5м Zn140 нaзн 02 14918-2020 2,500М 1 ШТ 1,25X2,5М 08ПС', grade:'ОЦ 08ПС', qty:'0,077', price:144102}
]);

/* ==================== ФИЛИАЛ АРТИ ==================== */
const arti = scan('arti', [
  {thk:3,   name:'Лист износостойкий 3 мм',   grade:'NM500 Q+T sк', size:'3×2000×5000',   gost:'GB/T 24186-22', price:308000},
  {thk:3,   name:'Лист износостойкий 3 мм',   grade:'NM500 Q+T',    size:'3×2000×6000',   gost:'GB/T 24186-22', price:308000},
  {thk:4,   name:'Лист износостойкий 4 мм',   grade:'NM450 Q+T',    size:'4×2000×6000',   gost:'GB/T 24186-22', price:231000},
  {thk:4,   name:'Лист износостойкий 4 мм',   grade:'NM500 Q+T sк', size:'4×2000×3000',   gost:'GB/T 24186-22', price:231000},
  {thk:4,   name:'Лист износостойкий 4 мм',   grade:'NM500 Q+T',    size:'4×2000×6000',   gost:'GB/T 24186-22', price:231000},
  {thk:5,   name:'Лист износостойкий 5 мм',   grade:'NM500 Q+T',    size:'5×2000×6000',   gost:'GB/T 24186-22', price:231000},
  {thk:6,   name:'Лист износостойкий 6 мм',   grade:'NM450 Q+T',    size:'6×2000×6000',   gost:'GB/T 24186-22', price:231000},
  {thk:6,   name:'Лист износостойкий 6 мм',   grade:'NM500 Q+T sк', size:'6×2000×2400',   gost:'GB/T 24186-22', price:231000},
  {thk:6,   name:'Лист износостойкий 6 мм',   grade:'NM500 Q+T',    size:'6×2000×6000',   gost:'GB/T 24186-22', price:231000},
  {thk:8,   name:'Лист износостойкий 8 мм',   grade:'NM450 Q+T',    size:'8×2000×6000',   gost:'GB/T 24186-22', price:217000},
  {thk:8,   name:'Лист износостойкий 8 мм',   grade:'NM500 Q+T',    size:'8×2000×6000',   gost:'GB/T 24186-22', price:217000},
  {thk:10,  name:'Лист износостойкий 10 мм',  grade:'NM450 Q+T',    size:'10×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:10,  name:'Лист износостойкий 10 мм',  grade:'NM500 Q+T',    size:'10×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:12,  name:'Лист износостойкий 12 мм',  grade:'NM450 Q+T',    size:'12×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:12,  name:'Лист износостойкий 12 мм',  grade:'NM500 Q+T',    size:'12×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:14,  name:'Лист износостойкий 14 мм',  grade:'NM450 Q+T',    size:'14×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:14,  name:'Лист износостойкий 14 мм',  grade:'NM500 Q+T',    size:'14×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:16,  name:'Лист износостойкий 16 мм',  grade:'NM450 Q+T',    size:'16×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:16,  name:'Лист износостойкий 16 мм',  grade:'NM500 Q+T',    size:'16×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:16,  name:'Лист износостойкий 16 мм',  grade:'NM500 Q+T',    size:'16×2000×12000', gost:'GB/T 24186-22', price:217000},
  {thk:20,  name:'Лист износостойкий 20 мм',  grade:'NM450 Q+T',    size:'20×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:20,  name:'Лист износостойкий 20 мм',  grade:'NM500 Q+T sк', size:'20×2000×5000',  gost:'GB/T 24186-22', price:217000},
  {thk:20,  name:'Лист износостойкий 20 мм',  grade:'NM500 Q+T',    size:'20×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:25,  name:'Лист износостойкий 25 мм',  grade:'NM450 Q+T',    size:'25×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:25,  name:'Лист износостойкий 25 мм',  grade:'NM500 Q+T',    size:'25×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:25,  name:'Лист износостойкий 25 мм',  grade:'NM550 Q+T sк', size:'25×2000×3900',  gost:'GB/T 24186-22', price:217000},
  {thk:30,  name:'Лист износостойкий 30 мм',  grade:'NM450 Q+T',    size:'30×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:30,  name:'Лист износостойкий 30 мм',  grade:'NM500 Q+T',    size:'30×2000×6000',  gost:'GB/T 24186-22', price:217000},
  {thk:40,  name:'Лист износостойкий 40 мм',  grade:'NM450 Q+T sк', size:'40×2000×1000',  gost:'GB/T 24186-22', price:224000},
  {thk:40,  name:'Лист износостойкий 40 мм',  grade:'NM450 Q+T',    size:'40×2000×6000',  gost:'GB/T 24186-22', price:224000},
  {thk:40,  name:'Лист износостойкий 40 мм',  grade:'NM500 Q+T',    size:'40×2000×6000',  gost:'GB/T 24186-22', price:224000},
  {thk:50,  name:'Лист износостойкий 50 мм',  grade:'NM500 Q+T sк', size:'50×2000×3000',  gost:'GB/T 24186-22', price:224000},
  {thk:50,  name:'Лист износостойкий 50 мм',  grade:'NM500 Q+T',    size:'50×2000×6000',  gost:'GB/T 24186-22', price:224000},
  {thk:60,  name:'Лист износостойкий 60 мм',  grade:'NM500 Q+T',    size:'60×2000×6000',  gost:'GB/T 24186-22', price:245000},
  {thk:70,  name:'Лист износостойкий 70 мм',  grade:'NM500 Q+T',    size:'70×2000×5000',  gost:'GB/T 24186-22', price:287000},
  {thk:80,  name:'Лист износостойкий 80 мм',  grade:'NM400 Q+T',    size:'80×2000×5000',  gost:'GB/T 24186-22', price:287000},
  {thk:90,  name:'Лист износостойкий 90 мм',  grade:'NM400 Q+T',    size:'90×2000×3000',  gost:'GB/T 24186-22', price:308000},
  {thk:100, name:'Лист износостойкий 100 мм', grade:'NM400 Q+T',    size:'100×2000×3000', gost:'GB/T 24186-22', price:308000}
]);

/* ==================== БРОНЯ И ЗАЩИТА ==================== */
const armor = scan('armor', [
  {cat:'Пулестойкая', mark:'C500', tu:'ТУ 18121-2017/96', size:'2,3 × 1220 × 2080', klass:'Бр2', stock:'50',             priceSheet:72224,  priceKg:1444, term:'10–15 раб. дней'},
  {cat:'Пулестойкая', mark:'C500', tu:'ТУ 18121-2017/96', size:'4,3 × 1220 × 2080', klass:'Бр3', stock:'0',              priceSheet:116876, priceKg:1230, term:'3–4 мес. (нет сырья)'},
  {cat:'Пулестойкая', mark:'C500', tu:'ТУ 18121-2017/96', size:'6,3 × 1220 × 2080', klass:'Бр4', stock:'400',            priceSheet:142130, priceKg:1085, term:'10–15 раб. дней'},
  {cat:'Пулестойкая', mark:'C500', tu:'ТУ 18121-2017/96', size:'8,3 × 1220 × 2080', klass:'Бр4', stock:'12',             priceSheet:201300, priceKg:1118, term:'10–15 раб. дней'},
  {cat:'Износостойкая', mark:'БТВТ 450', tu:'ТУ 18105BB-2024', size:'6 × 1500 × 2000', klass:'Бр2 / С2', stock:'~141 (из 20 т)', priceSheet:42390,  priceKg:300, term:'10–15 раб. дней'},
  {cat:'Износостойкая', mark:'БТВТ 450', tu:'ТУ 18105BB-2024', size:'6 × 1500 × 3000', klass:'Бр2 / С2', stock:'~94 (из 20 т)',  priceSheet:63585,  priceKg:300, term:'10–15 раб. дней'},
  {cat:'Износостойкая', mark:'БТВТ 450', tu:'ТУ 18105BB-2024', size:'6 × 1500 × 6000', klass:'Бр2 / С2', stock:'~188 (80 т)',    priceSheet:129000, priceKg:300, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'6 × 1300 × 2000',  klass:'Бр2 / С2', stock:'~163 (из 20 т)', priceSheet:52046,   priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'6 × 1300 × 3000',  klass:'Бр2 / С2', stock:'~108 (из 20 т)', priceSheet:78068,   priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'6 × 1500 × 2000',  klass:'Бр2 / С2', stock:'~141 (из 20 т)', priceSheet:60053,   priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'6 × 1500 × 3000',  klass:'Бр2 / С2', stock:'~94 (из 20 т)',  priceSheet:90079,   priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'6 × 1300 × 6000',  klass:'Бр2 / С2', stock:'~193 (71 т)',    priceSheet:157250,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'6 × 1500 × 6000',  klass:'Бр2 / С2', stock:'~188 (80 т)',    priceSheet:182750,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'8 × 1500 × 6000',  klass:'план Бр3', stock:'~35 (из 20 т)',  priceSheet:242250,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'8 × 2000 × 6000',  klass:'план Бр3', stock:'~26 (из 20 т)',  priceSheet:323000,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'10 × 1500 × 6000', klass:'Бр4',      stock:'~28 (из 20 т)',  priceSheet:301750,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'10 × 2000 × 6000', klass:'Бр4',      stock:'~21 (из 20 т)',  priceSheet:408000,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'12 × 2000 × 6000', klass:'Бр4',      stock:'~17 (из 20 т)',  priceSheet:488750,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'14 × 2000 × 6000', klass:'Бр4',      stock:'~15 (из 20 т)',  priceSheet:573750,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'15 × 2000 × 6000', klass:'Бр4',      stock:'~14 (из 20 т)',  priceSheet:600525,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'16 × 2000 × 6000', klass:'Бр4',      stock:'~13 (из 20 т)',  priceSheet:646000,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'20 × 2000 × 6000', klass:'план Бр5', stock:'~10 (из 20 т)',  priceSheet:807500,  priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'25 × 2000 × 6000', klass:'план Бр5', stock:'~8 (из 20 т)',   priceSheet:1011500, priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'30 × 2000 × 6000', klass:'—',        stock:'~7 (из 20 т)',   priceSheet:1211250, priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'40 × 2000 × 6000', klass:'—',        stock:'~5 (из 20 т)',   priceSheet:1632000, priceKg:425, term:'10–15 раб. дней'},
  {cat:'Противоосколочная', mark:'C500', tu:'ТУ 18101-2017 Ж', size:'50 × 2000 × 6000', klass:'план Бр6', stock:'~4 (из 20 т)',   priceSheet:2040000, priceKg:425, term:'10–15 раб. дней'}
]);

/* ==================== УТИЛИТЫ ==================== */
const fmt = n =&gt; n.toLocaleString('ru-RU');
const num = s =&gt; parseFloat(String(s).replace(/\s/g,'').replace(',', '.'));

let catSort = {key:null, dir:1};
let stSort  = {key:null, dir:1};
let aSort   = {key:null, dir:1};
let arSort  = {key:null, dir:1};

/* ==================== ВКЛАДКИ ==================== */
document.querySelectorAll('.tab').forEach(tab =&gt; {
  tab.addEventListener('click', () =&gt; {
    document.querySelectorAll('.tab').forEach(t =&gt; t.classList.remove('active'));
    document.querySelectorAll('.panel').forEach(p =&gt; p.classList.remove('active'));
    tab.classList.add('active');
    document.getElementById('panel-' + tab.dataset.tab).classList.add('active');
  });
});

/* ==================== ФИЛЬТРЫ ==================== */
const aThkSel = document.getElementById('aThk');
[...new Set(arti.map(x =&gt; x.thk))].sort((a,b)=&gt;a-b).forEach(t =&gt; {
  const o = document.createElement('option'); o.value = t; o.textContent = t + ' мм'; aThkSel.appendChild(o);
});

const aGradeSel = document.getElementById('aGrade');
[...new Set(arti.map(x =&gt; x.grade))].sort().forEach(g =&gt; {
  const o = document.createElement('option'); o.value = g; o.textContent = g; aGradeSel.appendChild(o);
});

const arClassSel = document.getElementById('arClass');
[...new Set(armor.map(x =&gt; x.klass))].sort().forEach(k =&gt; {
  const o = document.createElement('option'); o.value = k; o.textContent = k; arClassSel.appendChild(o);
});

/* ==================== РЯДОВЫЕ СТАЛИ ==================== */
const catBody = document.getElementById('catBody');
const catEmpty = document.getElementById('catEmpty');
const catSearch = document.getElementById('catSearch');

function getFilteredCatalog() {
  const q = catSearch.value.trim().toLowerCase();
  let rows = catalog.filter(r =&gt; !q || (r.name+' '+r.grade+' '+r.size+' '+r.gost).toLowerCase().includes(q));
  if (catSort.key) {
    const k = catSort.key, d = catSort.dir;
    rows.sort((a, b) =&gt; {
      let va = a[k], vb = b[k];
      if (va == null) va = -Infinity; if (vb == null) vb = -Infinity;
      return typeof va === 'string' ? va.localeCompare(vb, 'ru') * d : (va - vb) * d;
    });
  }
  return rows;
}
function renderCatalog() {
  const rows = getFilteredCatalog();
  catBody.innerHTML = '';
  if (!rows.length) { catEmpty.style.display = 'block'; return; }
  catEmpty.style.display = 'none';
  const bc = r =&gt; r.cat === 'Износостойкая' ? 'badge izn' : 'badge';
  rows.forEach(r =&gt; {
    const tr = document.createElement('tr');
    tr.innerHTML = `&lt;td&gt;&lt;span class="${bc(r)}"&gt;${r.cat}&lt;/span&gt;&lt;/td&gt;
      &lt;td&gt;${r.name}&lt;/td&gt;&lt;td&gt;${r.size}&lt;/td&gt;&lt;td&gt;${r.grade}&lt;/td&gt;&lt;td&gt;${r.gost}&lt;/td&gt;
      &lt;td class="num"&gt;${r.w1 ?? '—'}&lt;/td&gt;&lt;td class="num"&gt;${r.wm ?? '—'}&lt;/td&gt;
      &lt;td&gt;Т&lt;/td&gt;&lt;td class="num price"&gt;${fmt(r.price)}&lt;/td&gt;`;
    catBody.appendChild(tr);
  });
  updateSortIndicators('catHead', catSort);
}

/* ==================== ОСТАТКИ ==================== */
const stBody = document.getElementById('stBody');
const stEmpty = document.getElementById('stEmpty');
const stSearch = document.getElementById('stSearch');

function getFilteredStock() {
  const q = stSearch.value.trim().toLowerCase();
  let rows = stock
    .filter(r =&gt; !q || r.name.toLowerCase().includes(q))
    .map(r =&gt; ({...r, qtyNum: num(r.qty)}));
  if (stSort.key) {
    const k = stSort.key, d = stSort.dir;
    rows.sort((a, b) =&gt; {
      let va = a[k], vb = b[k];
      return typeof va === 'string' ? va.localeCompare(vb, 'ru') * d : (va - vb) * d;
    });
  }
  return rows;
}
function renderStock() {
  const rows = getFilteredStock();
  stBody.innerHTML = '';
  if (!rows.length) { stEmpty.style.display = 'block'; return; }
  stEmpty.style.display = 'none';
  rows.forEach(r =&gt; {
    const tr = document.createElement('tr');
    tr.innerHTML = `&lt;td&gt;${r.name}&lt;/td&gt;
      &lt;td&gt;&lt;span class="badge ost"&gt;${r.grade}&lt;/span&gt;&lt;/td&gt;
      &lt;td&gt;Т&lt;/td&gt;&lt;td class="num"&gt;${r.qty}&lt;/td&gt;
      &lt;td class="num price"&gt;${fmt(r.price)}&lt;/td&gt;`;
    stBody.appendChild(tr);
  });
  updateSortIndicators('stHead', stSort);
}

/* ==================== АРТИ ==================== */
const aBody = document.getElementById('aBody');
const aEmpty = document.getElementById('aEmpty');
const aSearch = document.getElementById('aSearch');

function getFilteredArti() {
  const q = aSearch.value.trim().toLowerCase();
  const th = aThkSel.value;
  const gr = aGradeSel.value;
  let rows = arti.filter(r =&gt; (!q || (r.name+' '+r.grade+' '+r.size).toLowerCase().includes(q))
                          &amp;&amp; (!th || r.thk == th) &amp;&amp; (!gr || r.grade === gr));
  if (aSort.key) {
    const k = aSort.key, d = aSort.dir;
    rows.sort((a, b) =&gt; {
      let va = a[k], vb = b[k];
      return typeof va === 'string' ? va.localeCompare(vb, 'ru') * d : (va - vb) * d;
    });
  }
  return rows;
}
function renderArti() {
  const rows = getFilteredArti();
  aBody.innerHTML = '';
  if (!rows.length) { aEmpty.style.display = 'block'; return; }
  aEmpty.style.display = 'none';
  rows.forEach(r =&gt; {
    const tr = document.createElement('tr');
    tr.innerHTML = `&lt;td class="num"&gt;&lt;b&gt;${r.thk}&lt;/b&gt;&lt;/td&gt;
      &lt;td&gt;&lt;span class="badge arti"&gt;Арти&lt;/span&gt; ${r.name}&lt;/td&gt;
      &lt;td&gt;${r.grade}&lt;/td&gt;&lt;td&gt;${r.size}&lt;/td&gt;&lt;td&gt;${r.gost}&lt;/td&gt;
      &lt;td&gt;Т&lt;/td&gt;&lt;td class="num price"&gt;${fmt(r.price)}&lt;/td&gt;`;
    aBody.appendChild(tr);
  });
  updateSortIndicators('aHead', aSort);
}

/* ==================== БРОНЯ ==================== */
const arBody = document.getElementById('arBody');
const arEmpty = document.getElementById('arEmpty');
const arSearch = document.getElementById('arSearch');
const arCat = document.getElementById('arCat');

function getFilteredArmor() {
  const q  = arSearch.value.trim().toLowerCase();
  const cc = arCat.value;
  const ck = arClassSel.value;
  let rows = armor
    .filter(r =&gt; (!q || (r.cat+' '+r.mark+' '+r.tu+' '+r.size+' '+r.klass).toLowerCase().includes(q))
              &amp;&amp; (!cc || r.cat === cc) &amp;&amp; (!ck || r.klass === ck))
    .map(r =&gt; ({...r, stockNum: parseFloat(String(r.stock).replace(/[^\d.,]/g,'').replace(',','.')) || 0}));
  if (arSort.key) {
    const k = arSort.key, d = arSort.dir;
    rows.sort((a, b) =&gt; {
      let va = a[k], vb = b[k];
      return typeof va === 'string' ? va.localeCompare(vb, 'ru') * d : (va - vb) * d;
    });
  }
  return rows;
}
function renderArmor() {
  const rows = getFilteredArmor();
  arBody.innerHTML = '';
  if (!rows.length) { arEmpty.style.display = 'block'; return; }
  arEmpty.style.display = 'none';
  const bc = r =&gt; r.cat === 'Пулестойкая' ? 'badge arm'
             : r.cat === 'Износостойкая' ? 'badge ost' : 'badge';
  rows.forEach(r =&gt; {
    const tr = document.createElement('tr');
    tr.innerHTML = `&lt;td&gt;&lt;span class="${bc(r)}"&gt;${r.cat}&lt;/span&gt;&lt;/td&gt;
      &lt;td&gt;&lt;b&gt;${r.mark}&lt;/b&gt;&lt;/td&gt;&lt;td&gt;${r.tu}&lt;/td&gt;&lt;td&gt;${r.size}&lt;/td&gt;&lt;td&gt;${r.klass}&lt;/td&gt;
      &lt;td class="num"&gt;${r.stock}&lt;/td&gt;
      &lt;td class="num price"&gt;${fmt(r.priceSheet)}&lt;/td&gt;
      &lt;td class="num"&gt;${fmt(r.priceKg)}&lt;/td&gt;
      &lt;td&gt;${r.term}&lt;/td&gt;`;
    arBody.appendChild(tr);
  });
  updateSortIndicators('arHead', arSort);
}

/* ==================== СОРТИРОВКА ==================== */
function updateSortIndicators(headId, sortState) {
  document.querySelectorAll('#' + headId + ' th.sortable').forEach(th =&gt; {
    th.classList.remove('asc','desc');
    if (th.dataset.key === sortState.key) th.classList.add(sortState.dir === 1 ? 'asc' : 'desc');
  });
}
function bindSort(headId, ref, rerender) {
  document.querySelectorAll('#' + headId + ' th.sortable').forEach(th =&gt; th.addEventListener('click', () =&gt; {
    const k = th.dataset.key;
    if (ref.get().key === k) ref.get().dir *= -1;
    else ref.set({key:k, dir:1});
    rerender();
  }));
}
bindSort('catHead', {get:()=&gt;catSort, set:v=&gt;catSort=v}, renderCatalog);
bindSort('stHead',  {get:()=&gt;stSort,  set:v=&gt;stSort=v},  renderStock);
bindSort('aHead',   {get:()=&gt;aSort,   set:v=&gt;aSort=v},   renderArti);
bindSort('arHead',  {get:()=&gt;arSort,  set:v=&gt;arSort=v},  renderArmor);

/* ==================== ЭКСПОРТ ==================== */
function buildRows(type) {
  if (type === 'catalog') {
    const rows = getFilteredCatalog();
    return {
      header: ['Категория','Наименование','Мерность','Марка стали','ГОСТ','Вес 1 шт, кг','Вес 1 пм, кг','ЕИ','Цена, ₽/т'],
      body: rows.map(r =&gt; [r.cat, r.name, r.size, r.grade, r.gost, r.w1 ?? '', r.wm ?? '', 'Т', r.price]),
      title: 'Рядовые стали'
    };
  }
  if (type === 'stock') {
    const rows = getFilteredStock();
    return {
      header: ['Наименование','Марка стали','Ед. изм.','Кол-во','Цена, ₽/т'],
      body: rows.map(r =&gt; [r.name, r.grade, 'Т', r.qty, r.price]),
      title: 'Остатки по складу'
    };
  }
  if (type === 'arti') {
    const rows = getFilteredArti();
    return {
      header: ['Филиал','Толщина, мм','Наименование','Марка стали','Размер, мм','ГОСТ','ЕИ','Цена, ₽/т'],
      body: rows.map(r =&gt; ['Арти', r.thk, r.name, r.grade, r.size, r.gost, 'Т', r.price]),
      title: 'Филиал Арти'
    };
  }
  if (type === 'armor') {
    const rows = getFilteredArmor();
    return {
      header: ['Категория','Марка','ТУ','Размер, мм','Класс','Наличие (листов)','Цена за лист, ₽','Цена за 1 кг, ₽','Сроки'],
      body: rows.map(r =&gt; [r.cat, r.mark, r.tu, r.size, r.klass, r.stock, r.priceSheet, r.priceKg, r.term]),
      title: 'Броня и защита'
    };
  }
}
function downloadBlob(blob, filename) {
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url; a.download = filename;
  document.body.appendChild(a); a.click(); a.remove();
  setTimeout(() =&gt; URL.revokeObjectURL(url), 500);
}
function downloadCSV(type) {
  const {header, body} = buildRows(type);
  const esc = v =&gt; `"${String(v).replace(/"/g,'""')}"`;
  const lines = [header.map(esc).join(';'), ...body.map(r =&gt; r.map(esc).join(';'))];
  const blob = new Blob(['\uFEFF' + lines.join('\r\n')], {type:'text/csv;charset=utf-8;'});
  downloadBlob(blob, `sklad_${type}_${today()}.csv`);
}
function downloadExcel(type) {
  const {header, body, title} = buildRows(type);
  const esc = v =&gt; String(v ?? '').replace(/&amp;/g,'&amp;amp;').replace(/&lt;/g,'&amp;lt;').replace(/&gt;/g,'&amp;gt;');
  const table = `&lt;table border="1" cellspacing="0" cellpadding="4"&gt;
    &lt;thead style="background:#000;color:#ffd700;"&gt;&lt;tr&gt;${header.map(h=&gt;`&lt;th&gt;${esc(h)}&lt;/th&gt;`).join('')}&lt;/tr&gt;&lt;/thead&gt;
    &lt;tbody&gt;${body.map(r=&gt;`&lt;tr&gt;${r.map(c=&gt;`&lt;td&gt;${esc(c)}&lt;/td&gt;`).join('')}&lt;/tr&gt;`).join('')}&lt;/tbody&gt;&lt;/table&gt;`;
  const html = `&lt;html xmlns:x="urn:schemas-microsoft-com:office:excel"&gt;&lt;head&gt;&lt;meta charset="UTF-8"&gt;
    &lt;style&gt;td,th{font-family:Arial;font-size:12px;}&lt;/style&gt;&lt;/head&gt;
    &lt;body&gt;&lt;h2&gt;${esc(title)} — ${today()}&lt;/h2&gt;${table}&lt;/body&gt;&lt;/html&gt;`;
  const blob = new Blob(['\uFEFF' + html], {type:'application/vnd.ms-excel;charset=utf-8;'});
  downloadBlob(blob, `sklad_${type}_${today()}.xls`);
}
function today() {
  const d = new Date(), p = n =&gt; String(n).padStart(2,'0');
  return `${d.getFullYear()}-${p(d.getMonth()+1)}-${p(d.getDate())}`;
}

/* ==================== СБРОС ==================== */
function resetCatalog() { catSearch.value=''; catSort={key:null,dir:1}; renderCatalog(); }
function resetStock()   { stSearch.value=''; stSort={key:null,dir:1}; renderStock(); }
function resetArti()    { aSearch.value=''; aThkSel.value=''; aGradeSel.value=''; aSort={key:null,dir:1}; renderArti(); }
function resetArmor()   { arSearch.value=''; arCat.value=''; arClassSel.value=''; arSort={key:null,dir:1}; renderArmor(); }

/* ==================== СОБЫТИЯ ==================== */
catSearch.addEventListener('input', renderCatalog);
stSearch.addEventListener('input', renderStock);
aSearch.addEventListener('input', renderArti);
aThkSel.addEventListener('change', renderArti);
aGradeSel.addEventListener('change', renderArti);
arSearch.addEventListener('input', renderArmor);
arCat.addEventListener('change', renderArmor);
arClassSel.addEventListener('change', renderArmor);

/* ==================== ЭФФЕКТЫ СКРОЛЛА ==================== */
(function initScrollEffects() {

  /* ---------- 1. Магнитная прокрутка ---------- */
  document.querySelectorAll('.table-scroll').forEach(box =&gt; {
    let timer = null;
    box.addEventListener('scroll', () =&gt; {
      clearTimeout(timer);
      timer = setTimeout(() =&gt; {
        const row = box.querySelector('tbody tr');
        if (!row) return;
        const rowH = row.getBoundingClientRect().height;
        if (!rowH) return;
        const cur = box.scrollTop;
        const snapped = Math.round(cur / rowH) * rowH;
        if (Math.abs(cur - snapped) &gt; 2) {
          box.scrollTo({ top: snapped, behavior: 'smooth' });
        }
      }, 180);
    }, { passive: true });
  });

  /* ---------- 2. Авто-подсветка активного скролла ---------- */
  document.querySelectorAll('.table-scroll').forEach(box =&gt; {
    let hideTimer = null;
    box.addEventListener('mouseenter', () =&gt; {
      clearTimeout(hideTimer);
      box.classList.add('active-scroll');
    });
    box.addEventListener('mouseleave', () =&gt; {
      hideTimer = setTimeout(() =&gt; box.classList.remove('active-scroll'), 400);
    });
    box.addEventListener('scroll', () =&gt; {
      box.classList.add('active-scroll');
      clearTimeout(hideTimer);
      hideTimer = setTimeout(() =&gt; box.classList.remove('active-scroll'), 800);
    }, { passive: true });
  });

  /* ---------- 3. Мерцающие искры по краям таблиц ---------- */
  const sparkleCount = 8;
  document.querySelectorAll('.table-scroll').forEach(box =&gt; {
    for (let i = 0; i &lt; sparkleCount; i++) {
      const s = document.createElement('span');
      s.className = 'sparkle';
      const top = Math.random() &gt; .5;
      s.style.left = (Math.random() * 100) + '%';
      s.style.top = top ? '2px' : 'auto';
      s.style.bottom = top ? 'auto' : '2px';
      s.style.animationDelay = (Math.random() * 3).toFixed(2) + 's';
      s.style.animationDuration = (2 + Math.random() * 2).toFixed(2) + 's';
      box.appendChild(s);
    }
  });

  /* ---------- 4. Огненные частицы при скролле ---------- */
  document.querySelectorAll('.table-scroll').forEach(box =&gt; {
    let particleTimer = 0;
    box.addEventListener('scroll', (e) =&gt; {
      const now = Date.now();
      if (now - particleTimer &lt; 30) return;
      particleTimer = now;
      const rect = box.getBoundingClientRect();
      // спавним частицу в месте скролла
      const p = document.createElement('span');
      p.className = 'fire-particle';
      const x = rect.left + Math.random() * rect.width;
      const y = rect.top + Math.random() * rect.height;
      p.style.left = x + 'px';
      p.style.top = y + 'px';
      p.style.setProperty('--dx', ((Math.random() - .5) * 60) + 'px');
      p.style.setProperty('--dy', (-40 - Math.random() * 60) + 'px');
      document.body.appendChild(p);
      setTimeout(() =&gt; p.remove(), 1300);
    }, { passive: true });
  });

  /* ---------- 5. Молния при быстрой прокрутке ---------- */
  document.querySelectorAll('.table-scroll').forEach(box =&gt; {
    let lastTop = box.scrollTop, lastTime = Date.now();
    box.addEventListener('scroll', () =&gt; {
      const now = Date.now();
      const dt = now - lastTime;
      const dy = Math.abs(box.scrollTop - lastTop);
      lastTime = now; lastTop = box.scrollTop;
      // скорость &gt; 40px за кадр — вспышка
      if (dt &gt; 0 &amp;&amp; dy / dt &gt; 0.4) {
        const flash = document.createElement('span');
        flash.className = 'lightning';
        box.appendChild(flash);
        setTimeout(() =&gt; flash.remove(), 300);
      }
    }, { passive: true });
  });

  /* ---------- 6. Тактильный отклик (вибро) ---------- */
  document.querySelectorAll('.table-scroll').forEach(box =&gt; {
    let lastVib = 0;
    box.addEventListener('scroll', () =&gt; {
      const now = Date.now();
      if (now - lastVib &lt; 120) return;
      lastVib = now;
      if (navigator.vibrate) {
        // короткая вибрация 8 мс — почти незаметно, но приятно
        navigator.vibrate(8);
      }
    }, { passive: true });
  });

  /* ---------- 7. Idle-подсказка ---------- */
  let idleTimer = null;
  const resetIdle = () =&gt; {
    clearTimeout(idleTimer);
    document.body.classList.remove('idle-hint');
    idleTimer = setTimeout(() =&gt; {
      document.body.classList.add('idle-hint');
    }, 5000);
  };
  ['mousemove','scroll','keydown','click','touchstart'].forEach(ev =&gt;
    document.addEventListener(ev, resetIdle, { passive: true })
  );
  resetIdle();

})();

/* ==================== СТАРТ ==================== */
renderCatalog();
renderStock();
renderArti();
renderArmor();
&lt;/script&gt;</subtitle>
  <updated>2026-10-08T04:51:57Z</updated>
  <logo>https://xn--80abmnojgpmk.xn--p1ai/ssl/u/pic/f9/71f28ebd6c11f1bc96a94a3b2a5b30/-/XpnoBpMGVrE3AtfQUGFKD80ejOZ4gg39jykiODEqmDqeUPqSFm0Kxv05wtgrESirqqynC9qM7bP1a92QW6pNZBkp.jpg</logo>
  <author>
    <name>1761815</name>
    <uri>https://www.xn--80abmnojgpmk.xn--p1ai/</uri>
  </author>
</feed>
