<?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/chernovik-nabrosok-giperzvukovaya-laboratoriya</id>
  <link href="https://www.pandoraburo.ru/chernovik-nabrosok-giperzvukovaya-laboratoriya.xml" rel="self"/>
  <title/>
  <subtitle type="html">
&lt;html lang="ru"&gt;
&lt;head&gt;
&lt;meta charset="UTF-8"&gt;
&lt;title&gt;Гиперзвуковая лаборатория ИМ-07 v4.3 (Downshifted)&lt;/title&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/chart.js"&gt;&lt;/script&gt;
&lt;style&gt;
  /* === АГРЕССИВНЫЙ СБРОС ВНЕШНИХ СТИЛЕЙ (ANTI-INJECTION) === */
  body {
    background-color: #0a0e1a !important;
    color: #e8ecf5 !important;
    font-family: 'Consolas', 'Courier New', monospace !important;
    font-size: 100% !important;
    line-height: 1.2 !important;
    margin: 0 !important;
    padding: 0 !important;
    min-height: 100vh !important;
    overflow-x: hidden !important;
  }
  
  * { margin: 0; padding: 0; box-sizing: border-box; }
  :root {
    --bg: #0a0e1a;
    --panel: #121826;
    --panel-2: #1a2133;
    --border: #2a3550;
    --text: #e8ecf5;
    --dim: #8a94ad;
    --accent: #00d9ff;
    --warn: #ffb547;
    --danger: #ff4757;
    --safe: #00ff88;
    --mhd: #a855f7;
  }

  /* MODE SWITCHER */
  .mode-bar {
    display: flex;
    justify-content: center;
    background: var(--panel-2);
    border-bottom: 1px solid var(--border);
    padding: 8px;
    gap: 10px;
    position: sticky;
    top: 0;
    z-index: 100;
  }
  .mode-btn {
    padding: 6px 20px;
    background: transparent;
    border: 1px solid var(--border);
    color: var(--dim);
    border-radius: 4px;
    cursor: pointer;
    font-family: inherit;
    font-size: 12px;
    letter-spacing: 1px;
    transition: all 0.2s;
  }
  .mode-btn.active {
    background: var(--accent);
    color: var(--bg);
    border-color: var(--accent);
    font-weight: bold;
    box-shadow: 0 0 10px rgba(0, 217, 255, 0.4);
  }

  /* HEADER */
  header {
    background: linear-gradient(90deg, #0a0e1a, #1a2133);
    border-bottom: 2px solid var(--accent);
    padding: 14px 24px;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  header h1 {
    font-size: 18px;
    letter-spacing: 3px;
    color: var(--accent);
    text-shadow: 0 0 10px rgba(0, 217, 255, 0.6);
  }
  header h1::before { content: "⚡ "; }
  .status-chips { display: flex; gap: 10px; }
  .chip {
    padding: 4px 12px;
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: 12px;
    font-size: 11px;
    color: var(--dim);
  }
  .chip.ok { color: var(--safe); border-color: var(--safe); }
  .chip.warn { color: var(--warn); border-color: var(--warn); }
  .chip.danger { color: var(--danger); border-color: var(--danger); animation: pulse 1s infinite; }

  /* VERTICAL LAYOUT GRID */
  .main-container {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px;
    height: calc(100vh - 110px);
    max-width: 1600px;
    margin: 0 auto;
  }

  .top-row {
    display: grid;
    grid-template-columns: 320px 1fr;
    gap: 12px;
    flex-shrink: 0;
  }

  .panel {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 16px;
    overflow-y: auto;
    max-height: 55vh;
  }

  .panel h2 {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 2px;
    color: var(--accent);
    border-bottom: 1px solid var(--border);
    padding-bottom: 8px;
    margin-bottom: 14px;
  }
  .panel h3 {
    font-size: 11px;
    color: var(--dim);
    margin: 14px 0 8px;
    text-transform: uppercase;
    letter-spacing: 1px;
  }

  /* CONTROLS */
  .ctrl { margin-bottom: 14px; }
  .ctrl label {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: var(--dim);
    margin-bottom: 4px;
  }
  .ctrl label .val { color: var(--accent); font-weight: bold; }
  .ctrl input[type=range] {
    width: 100%;
    -webkit-appearance: none;
    height: 4px;
    background: var(--border);
    border-radius: 2px;
    outline: none;
  }
  .ctrl input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 14px;
    height: 14px;
    background: var(--accent);
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0 0 8px var(--accent);
  }
  select {
    width: 100%;
    padding: 6px;
    background: var(--panel-2);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 4px;
    font-family: inherit;
    font-size: 11px;
  }

  /* BUTTONS */
  .btn {
    display: inline-block;
    padding: 8px 14px;
    background: var(--panel-2);
    color: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 4px;
    cursor: pointer;
    font-family: inherit;
    font-size: 11px;
    letter-spacing: 1px;
    text-transform: uppercase;
    transition: all 0.2s;
    margin: 2px;
  }
  .btn:hover { background: var(--accent); color: var(--bg); box-shadow: 0 0 12px var(--accent); }
  .btn.danger { color: var(--danger); border-color: var(--danger); }
  .btn.danger:hover { background: var(--danger); color: white; }
  .btn.primary { background: var(--accent); color: var(--bg); }
  .btn.mhd { color: var(--mhd); border-color: var(--mhd); }
  .btn.mhd:hover { background: var(--mhd); color: white; }

  /* === ИСПРАВЛЕНИЕ CANVAS: ЗАЩИТА ОТ ОБРЕЗАНИЯ === */
  .center-viz {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    position: relative;
    overflow: visible !important; /* Разрешаем видеть всё */
    flex-grow: 1;
    min-height: 500px !important; /* Жесткая минимальная высота */
    height: 50vh !important;
    width: 100% !important;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .banner {
    position: absolute;
    top: 10px; left: 10px;
    background: rgba(10, 14, 26, 0.85);
    border: 1px solid var(--accent);
    padding: 8px 14px;
    border-radius: 4px;
    font-size: 11px;
    z-index: 10;
    backdrop-filter: blur(4px);
  }
  .banner .row { display: flex; gap: 16px; margin-bottom: 4px; }
  .banner .row:last-child { margin-bottom: 0; }
  .banner .label { color: var(--dim); }
  .banner .value { color: var(--accent); font-weight: bold; }
  
  #viz { 
    display: block !important;
    width: 100% !important;
    height: 100% !important;
    aspect-ratio: auto !important; /* УБИВАЕМ ВНЕШНИЙ 602/448 */
  }
  
  .scale-indicator {
    position: absolute;
    bottom: 10px; right: 10px;
    background: rgba(10, 14, 26, 0.85);
    border: 1px solid var(--border);
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 10px;
    color: var(--dim);
    z-index: 10;
  }

  /* VERDICT &amp; METRICS */
  .verdict-box {
    padding: 16px;
    border-radius: 6px;
    text-align: center;
    margin-bottom: 14px;
    font-weight: bold;
    letter-spacing: 2px;
    text-transform: uppercase;
    font-size: 14px;
    transition: all 0.3s;
  }
  .verdict-box.safe {
    background: rgba(0, 255, 136, 0.15);
    border: 1px solid var(--safe);
    color: var(--safe);
    box-shadow: 0 0 20px rgba(0, 255, 136, 0.3);
  }
  .verdict-box.danger {
    background: rgba(255, 71, 87, 0.15);
    border: 1px solid var(--danger);
    color: var(--danger);
    box-shadow: 0 0 20px rgba(255, 71, 87, 0.3);
    animation: pulse 1.5s infinite;
  }
  @keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
  }
  
  .integrity-bar-container {
    width: 100%;
    height: 12px;
    background: var(--panel-2);
    border-radius: 6px;
    margin: 10px 0;
    overflow: hidden;
    border: 1px solid var(--border);
  }
  .integrity-bar {
    height: 100%;
    background: linear-gradient(90deg, var(--safe), var(--accent));
    width: 100%;
    transition: width 0.3s, background 0.3s;
  }
  .integrity-bar.critical { background: linear-gradient(90deg, var(--danger), var(--warn)); }
  .integrity-bar.warning { background: linear-gradient(90deg, var(--warn), var(--accent)); }

  .metric {
    display: flex;
    justify-content: space-between;
    padding: 8px 0;
    border-bottom: 1px dashed var(--border);
    font-size: 12px;
  }
  .metric:last-child { border-bottom: none; }
  .metric .mname { color: var(--dim); }
  .metric .mval { color: var(--text); font-weight: bold; }
  .metric .mval.hot { color: var(--warn); }
  .metric .mval.crit { color: var(--danger); }

  /* STUDENT MODE SPECIFIC */
  .student-only { display: none; }
  .scientist-only { display: block; }
  body.mode-student .student-only { display: block; }
  body.mode-student .scientist-only { display: none; }

  /* BOTTOM CHARTS */
  .bottom-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    flex-shrink: 0;
    height: 220px;
  }
  .chart-box {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 14px;
    height: 100%;
    position: relative;
  }
  .chart-box h2 {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 2px;
    color: var(--accent);
    margin-bottom: 8px;
  }

  /* MODAL */
  .modal {
    display: none;
    position: fixed;
    top: 0; left: 0;
    width: 100%; height: 100%;
    background: rgba(0, 0, 0, 0.85);
    z-index: 1000;
    justify-content: center;
    align-items: center;
  }
  .modal.active { display: flex; }
  .modal-content {
    background: white;
    color: black;
    width: 90%;
    max-width: 800px;
    max-height: 90vh;
    padding: 40px;
    border-radius: 8px;
    overflow-y: auto;
    font-family: 'Georgia', serif;
  }
  .modal-content h1 { color: #0066cc; border-bottom: 2px solid #0066cc; padding-bottom: 10px; }
  .modal-content table { width: 100%; border-collapse: collapse; margin: 10px 0; }
  .modal-content th, .modal-content td { border: 1px solid #ccc; padding: 6px 10px; text-align: left; font-size: 13px; }
  .modal-content th { background: #f0f0f0; }
  
  @media (max-width: 900px) {
    .top-row { grid-template-columns: 1fr; }
    .bottom-row { grid-template-columns: 1fr; height: auto; }
    .chart-box { height: 250px; }
    .main-container { height: auto; }
  }
  @media print {
    body * { visibility: hidden; }
    .modal, .modal * { visibility: visible; }
    .modal { position: absolute; top: 0; left: 0; background: white; }
    .btn { display: none !important; }
  }
&lt;/style&gt;
&lt;/head&gt;
&lt;body class="mode-scientist"&gt;

&lt;div class="mode-bar"&gt;
  &lt;button class="mode-btn" onclick="setMode('student')"&gt;? СТУДЕНТ (Визуал)&lt;/button&gt;
  &lt;button class="mode-btn active" onclick="setMode('scientist')"&gt;? УЧЁНЫЙ (Данные)&lt;/button&gt;
&lt;/div&gt;

&lt;header&gt;
  &lt;h1&gt;HYPERSONIC LAB · ИМ-07 v4.3&lt;/h1&gt;
  &lt;div class="status-chips"&gt;
    &lt;div class="chip" id="chipFlow"&gt;LAMINAR&lt;/div&gt;
    &lt;div class="chip" id="chipMHD"&gt;MHD: OFF&lt;/div&gt;
    &lt;div class="chip ok" id="chipStatus"&gt;NOMINAL&lt;/div&gt;
  &lt;/div&gt;
&lt;/header&gt;

&lt;div class="main-container"&gt;
  
  &lt;div class="top-row"&gt;
    &lt;div class="panel"&gt;
      &lt;h2&gt;Параметры модели&lt;/h2&gt;
      &lt;h3&gt;Материал корпуса&lt;/h3&gt;
      &lt;div class="ctrl"&gt;
        &lt;label&gt;Основной материал&lt;/label&gt;
        &lt;select id="rMaterial" onchange="runCalc()"&gt;
          &lt;option value="steel3"&gt;Сталь 3 (до 800 K)&lt;/option&gt;
          &lt;option value="titanium"&gt;Титан ВТ-6 (до 1200 K)&lt;/option&gt;
          &lt;option value="tungsten" selected="selected"&gt;Вольфрам (до 3000 K)&lt;/option&gt;
          &lt;option value="boron_carbide"&gt;Карбид бора (до 3500 K)&lt;/option&gt;
          &lt;option value="carbon_carbon"&gt;Углепластик C/C (до 3200 K)&lt;/option&gt;
        &lt;/select&gt;
      &lt;/div&gt;
      &lt;div class="ctrl"&gt;
        &lt;label&gt;Защитное покрытие&lt;/label&gt;
        &lt;select id="rCoating" onchange="runCalc()"&gt;
          &lt;option value="none"&gt;Нет&lt;/option&gt;
          &lt;option value="zirconia"&gt;Диоксид циркония (ZrO₂)&lt;/option&gt;
          &lt;option value="silica"&gt;Кварцевое стекло (SiO₂)&lt;/option&gt;
        &lt;/select&gt;
      &lt;/div&gt;

      &lt;h3&gt;Геометрия и Поток&lt;/h3&gt;
      &lt;div class="ctrl"&gt;
        &lt;label&gt;Радиус затупления Rₙ &lt;span class="val"&gt;&lt;span id="oRn"&gt;150&lt;/span&gt; мм&lt;/span&gt;&lt;/label&gt;
        &lt;input type="range" id="rRn" min="30" max="500" value="150" step="5" /&gt;
      &lt;/div&gt;
      &lt;div class="ctrl"&gt;
        &lt;label&gt;Высота H &lt;span class="val"&gt;&lt;span id="oH"&gt;50&lt;/span&gt; км&lt;/span&gt;&lt;/label&gt;
        &lt;input type="range" id="rH" min="20" max="90" value="50" /&gt;
      &lt;/div&gt;
      &lt;div class="ctrl"&gt;
        &lt;label&gt;Скорость V∞ &lt;span class="val"&gt;&lt;span id="oV"&gt;3500&lt;/span&gt; м/с&lt;/span&gt;&lt;/label&gt;
        &lt;input type="range" id="rVinf" min="1000" max="11000" value="3500" step="50" /&gt;
      &lt;/div&gt;

      &lt;h3&gt;Стенка&lt;/h3&gt;
      &lt;div class="ctrl"&gt;
        &lt;label&gt;Температура Tₓ &lt;span class="val"&gt;&lt;span id="oTw"&gt;1800&lt;/span&gt; K&lt;/span&gt;&lt;/label&gt;
        &lt;input type="range" id="rTw" min="300" max="3500" value="1800" step="50" /&gt;
      &lt;/div&gt;
      &lt;div class="ctrl scientist-only"&gt;
        &lt;label&gt;Каталитичность γc &lt;span class="val"&gt;&lt;span id="oCat"&gt;0.30&lt;/span&gt;&lt;/span&gt;&lt;/label&gt;
        &lt;input type="range" id="rCat" min="0" max="100" value="30" /&gt;
      &lt;/div&gt;
      &lt;div class="ctrl scientist-only"&gt;
        &lt;label&gt;Предел qₗᵢₘ &lt;span class="val"&gt;&lt;span id="oQlim"&gt;2.0&lt;/span&gt; МВт/м²&lt;/span&gt;&lt;/label&gt;
        &lt;input type="range" id="rQlim" min="0.5" max="10" value="2" step="0.1" /&gt;
      &lt;/div&gt;
      &lt;div class="ctrl scientist-only"&gt;
        &lt;label&gt;Индукция B₀ &lt;span class="val"&gt;&lt;span id="oB0"&gt;0.5&lt;/span&gt; Тл&lt;/span&gt;&lt;/label&gt;
        &lt;input type="range" id="rB0" min="0" max="5" value="0.5" step="0.05" /&gt;
      &lt;/div&gt;
      &lt;div class="ctrl student-only" style="margin-top:10px;"&gt;
        &lt;label style="justify-content:center; color:var(--mhd); font-weight:bold;"&gt;⚡ МГД-ЗАЩИТА&lt;/label&gt;
        &lt;label class="switch" style="width:100%; text-align:center; margin-top:5px; position:relative; display:inline-block; width:42px; height:22px;"&gt;
          &lt;input type="checkbox" id="rMHD" onchange="runCalc()" style="opacity:0; width:0; height:0;" /&gt;
          &lt;span class="slider-sw" style="position:absolute; cursor:pointer; top:0; left:0; right:0; bottom:0; background:var(--border); border-radius:22px; transition:0.3s;"&gt;&lt;/span&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div style="margin-top:20px; display:flex; flex-wrap:wrap;"&gt;
        &lt;button class="btn primary" onclick="runSimulation()"&gt;▶ ЗАПУСК&lt;/button&gt;
        &lt;button class="btn scientist-only" onclick="findVcrit()"&gt;? Vₖᵣᵢₜ&lt;/button&gt;
        &lt;button class="btn scientist-only" onclick="runSweep()"&gt;? Свип B₀&lt;/button&gt;
        &lt;button class="btn" onclick="generateProtocol()"&gt;? Протокол&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="panel"&gt;
      &lt;h2&gt;Вердикт системы&lt;/h2&gt;
      &lt;div class="verdict-box safe" id="verdict"&gt;НОРМА&lt;/div&gt;

      &lt;div class="student-only"&gt;
        &lt;h3&gt;Состояние корпуса&lt;/h3&gt;
        &lt;div class="integrity-bar-container"&gt;
          &lt;div class="integrity-bar" id="integrityBar"&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="metric"&gt;&lt;span class="mname"&gt;Материал&lt;/span&gt;&lt;span class="mval" id="oMatName"&gt;Вольфрам&lt;/span&gt;&lt;/div&gt;
        &lt;div class="metric"&gt;&lt;span class="mname"&gt;Предельная T&lt;/span&gt;&lt;span class="mval" id="oMatTmax"&gt;3000 K&lt;/span&gt;&lt;/div&gt;
        &lt;div class="metric"&gt;&lt;span class="mname"&gt;Режим разрушения&lt;/span&gt;&lt;span class="mval" id="oFailureMode"&gt;Нет&lt;/span&gt;&lt;/div&gt;
      &lt;/div&gt;

      &lt;h3 class="scientist-only"&gt;Результаты расчёта&lt;/h3&gt;
      &lt;div class="metric scientist-only"&gt;&lt;span class="mname"&gt;Тепловой поток qₓ&lt;/span&gt;&lt;span class="mval" id="oQw"&gt;— МВт/м²&lt;/span&gt;&lt;/div&gt;
      &lt;div class="metric scientist-only"&gt;&lt;span class="mname"&gt;Сопротивление Cₓ&lt;/span&gt;&lt;span class="mval" id="oCd"&gt;—&lt;/span&gt;&lt;/div&gt;
      &lt;div class="metric scientist-only"&gt;&lt;span class="mname"&gt;Отстояние УВ Δ/Rₙ&lt;/span&gt;&lt;span class="mval" id="oDelta"&gt;—&lt;/span&gt;&lt;/div&gt;
      
      &lt;h3&gt;Оценка безопасности&lt;/h3&gt;
      &lt;div class="metric"&gt;&lt;span class="mname"&gt;Крит. скорость Vₖᵣᵢₜ&lt;/span&gt;&lt;span class="mval crit" id="oVcrit"&gt;— м/с&lt;/span&gt;&lt;/div&gt;
      &lt;div class="metric scientist-only"&gt;&lt;span class="mname"&gt;Запас по q&lt;/span&gt;&lt;span class="mval" id="oMargin"&gt;— %&lt;/span&gt;&lt;/div&gt;
      &lt;div class="metric"&gt;&lt;span class="mname"&gt;Толщина ТЗП&lt;/span&gt;&lt;span class="mval hot" id="oTPS"&gt;— мм&lt;/span&gt;&lt;/div&gt;

      &lt;h3&gt;Лог системы&lt;/h3&gt;
      &lt;div id="log" style="font-size:10px; color:var(--dim); max-height:150px; overflow-y:auto; padding:8px; background:var(--panel-2); border-radius:4px; line-height:1.5;"&gt;
        [00:00:00] Инициализация HYPERLAB v4.3&lt;br /&gt;
        [00:00:00] Защита от внешних CSS активна.
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  
  &lt;div class="center-viz"&gt;
    &lt;div class="banner"&gt;
      &lt;div class="row"&gt;
        &lt;div&gt;&lt;span class="label"&gt;M = &lt;/span&gt;&lt;span class="value" id="oM"&gt;—&lt;/span&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span class="label"&gt;Re = &lt;/span&gt;&lt;span class="value" id="oRe"&gt;—&lt;/span&gt;&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="row"&gt;
        &lt;div&gt;&lt;span class="label"&gt;T_shock = &lt;/span&gt;&lt;span class="value" id="oTsh"&gt;—&lt;/span&gt; K&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="row student-only"&gt;
        &lt;div&gt;&lt;span class="label"&gt;Целостность: &lt;/span&gt;&lt;span class="value" id="oIntegrity"&gt;100&lt;/span&gt;%&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;canvas id="viz"&gt;&lt;/canvas&gt;
    &lt;div class="scale-indicator" id="scaleIndicator"&gt;Масштаб: 1 км = 8 px&lt;/div&gt;
  &lt;/div&gt;

  
  &lt;div class="bottom-row"&gt;
    &lt;div class="chart-box"&gt;
      &lt;h2&gt;Профиль T и p вдоль оси&lt;/h2&gt;
      &lt;canvas id="chartProfile"&gt;&lt;/canvas&gt;
    &lt;/div&gt;
    &lt;div class="chart-box"&gt;
      &lt;h2&gt;qₓ(B₀) и St(B₀)&lt;/h2&gt;
      &lt;canvas id="chartSweep"&gt;&lt;/canvas&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class="modal" id="protocolModal"&gt;
  &lt;div class="modal-content" id="protocolBody"&gt;
    &lt;button class="btn" style="float:right;" onclick="closeProtocol()"&gt;✕ Закрыть&lt;/button&gt;
    &lt;button class="btn primary" style="float:right; margin-right:10px;" onclick="window.print()"&gt;? Печать/PDF&lt;/button&gt;
    &lt;div id="protocolContent"&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
// ============================================================
// MATERIALS DATABASE
// ============================================================
const Materials = {
  steel3: { name: "Сталь 3", Tmax: 800, Tmelt: 1700, rho: 7850, color: "#7a8599", failureMode: "melting", ablationRate: 0.8 },
  titanium: { name: "Титан ВТ-6", Tmax: 1200, Tmelt: 1660, rho: 4430, color: "#9ca3af", failureMode: "melting", ablationRate: 0.4 },
  tungsten: { name: "Вольфрам", Tmax: 3000, Tmelt: 3695, rho: 19250, color: "#4b5563", failureMode: "melting", ablationRate: 0.05 },
  boron_carbide: { name: "Карбид бора", Tmax: 3500, Tmelt: 3000, rho: 2520, color: "#1f2937", failureMode: "cracking", ablationRate: 0.02 },
  carbon_carbon: { name: "Углепластик C/C", Tmax: 3200, Tmelt: 3800, rho: 1800, color: "#111827", failureMode: "ablation", ablationRate: 0.1 }
};

const Coatings = {
  none: { name: "Нет", emissivity: 0.8, tAdd: 0 },
  zirconia: { name: "Диоксид циркония", emissivity: 0.9, tAdd: 200 },
  silica: { name: "Кварцевое стекло", emissivity: 0.85, tAdd: 150 }
};

// ============================================================
// PHYSICS ENGINE
// ============================================================
class StandardAtmosphere {
  static get(H_km) {
    const g = 9.80665, R = 287.05;
    let T, p;
    if (H_km &lt;= 11) { T = 288.15 - 6.5 * H_km; p = 101325 * Math.pow(T / 288.15, g / (R * 0.0065)); } 
    else if (H_km &lt;= 20) { T = 216.65; p = 22632 * Math.exp(-g * (H_km - 11) * 1000 / (R * T)); } 
    else if (H_km &lt;= 32) { T = 216.65 + (H_km - 20); p = 5474.9 * Math.pow(T / 216.65, -g / (R * 0.001)); } 
    else { T = 230 + Math.max(0, (H_km - 32) * 2.5); p = 868 * Math.exp(-(H_km - 32) / 12); }
    return { T, p, rho: p / (R * T) };
  }
}

class RealGas {
  static getGammaEff(V) { return 1.4 - 0.25 * (1 - Math.exp(-(V - 2000) / 2500)); }
  static getShockTemp(T_inf, M, gamma) {
    const T2_ideal = T_inf * (2 * gamma / (gamma + 1)) * M * M;
    return 14000 * Math.tanh(T2_ideal / 14000);
  }
}

class Plasma {
  static getConductivity(T_shock) {
    if (T_shock &lt; 3000) return 1e-5;
    if (T_shock &gt; 12000) return 1500;
    return 1500 / (1 + Math.exp(-0.0008 * (T_shock - 7000)));
  }
}

class HyperEngine {
  static calculate(Rn, V, H, B0, Tw, gamma_c, mhdOn, materialKey, coatingKey) {
    const atm = StandardAtmosphere.get(H);
    const Cp = 1005;
    const gamma = RealGas.getGammaEff(V);
    const a = Math.sqrt(gamma * 287.05 * atm.T);
    const M = V / a;
    const Re = (atm.rho * V * Rn) / (1.46e-6 * Math.pow(atm.T / 273, 0.7));
    const T_shock = RealGas.getShockTemp(atm.T, M, gamma);
    const sigma = Plasma.getConductivity(T_shock);

    const h0 = Cp * atm.T + 0.5 * V * V;
    const hw = Cp * Tw;
    let qw = 1.83e-4 * Math.sqrt(atm.rho / Rn) * Math.pow(V, 3.15) * (1 - hw / h0);
    qw *= (1 + gamma_c * 0.45);

    const St = mhdOn ? (sigma * B0 * B0 * Rn) / (atm.rho * V) : 0;
    qw /= (1 + 0.25 * St);

    const Cd = 0.85 * (1 + 0.1 * St);
    const sigma_SB = 5.67e-8;
    const coat = Coatings[coatingKey];
    const Tw_eq = Math.pow((qw / (sigma_SB * coat.emissivity)), 0.25) + coat.tAdd;

    const rho_shock = atm.rho * ((gamma + 1) * M * M) / ((gamma - 1) * M * M + 2);
    const delta_Rn = 0.78 * atm.rho / rho_shock * (1 + 0.5 * St);

    const mat = Materials[materialKey];
    let damageRate = 0;
    let failureMode = "none";
    
    if (Tw_eq &gt; mat.Tmax) {
      const excess = (Tw_eq - mat.Tmax) / mat.Tmax;
      damageRate = excess * excess * mat.ablationRate * 10;
      failureMode = mat.failureMode || "ablation";
    }

    return { qw: qw / 1e6, Cd, M, Re, T_shock, St, Tw_eq, gamma_eff: gamma, sigma, delta_Rn, atm, damageRate, failureMode, mat };
  }

  static findVcrit(Rn, H, B0, Tw, gamma_c, q_lim, mhdOn, matKey, coatKey) {
    let low = 1000, high = 12000, Vcrit = high;
    const mat = Materials[matKey];
    for (let i = 0; i &lt; 25; i++) {
      const mid = (low + high) / 2;
      const res = this.calculate(Rn, mid, H, B0, Tw, gamma_c, mhdOn, matKey, coatKey);
      if (res.qw &gt; q_lim || res.Tw_eq &gt; mat.Tmax) { Vcrit = mid; high = mid; }
      else low = mid;
    }
    return Vcrit;
  }
}

// ============================================================
// PARTICLE SYSTEMS
// ============================================================
class Particle {
  constructor(x, y, vx, vy, temp, size) {
    this.x = x; this.y = y; this.vx = vx; this.vy = vy;
    this.temp = temp; this.size = size; this.life = 1.0;
  }
  update(dt) {
    this.x += this.vx * dt; this.y += this.vy * dt;
    this.life -= dt * 0.5; this.temp *= 0.98; this.size *= 0.99;
  }
  getColor() {
    const alpha = Math.max(0, this.life);
    if (this.temp &gt; 10000) return `rgba(255, 255, 255, ${alpha})`;
    if (this.temp &gt; 7000) return `rgba(255, 220, 100, ${alpha})`;
    if (this.temp &gt; 4000) return `rgba(255, 150, 50, ${alpha})`;
    return `rgba(200, 50, 20, ${alpha * 0.5})`;
  }
}

class Debris {
  constructor(x, y, vx, vy, size, rotation) {
    this.x = x; this.y = y; this.vx = vx; this.vy = vy;
    this.size = size; this.rotation = rotation;
    this.rotSpeed = (Math.random() - 0.5) * 10; this.life = 1.0;
  }
  update(dt) {
    this.x += this.vx * dt; this.y += this.vy * dt;
    this.rotation += this.rotSpeed * dt; this.life -= dt * 0.3;
  }
}

// ============================================================
// UI &amp; STATE
// ============================================================
let currentMode = 'scientist';
let simRunning = false;
let integrity = 100;
let plasmaParticles = [];
let debrisParticles = [];
let failureTriggered = false;
let currentFailureMode = "none";
let profileChart, sweepChart;

function setMode(mode) {
  currentMode = mode;
  document.body.className = `mode-${mode}`;
  document.querySelectorAll('.mode-btn').forEach(b =&gt; b.classList.remove('active'));
  event.target.classList.add('active');
  runCalc();
}

function getVal(id) { return parseFloat(document.getElementById(id).value); }
function formatNum(n, d = 2) {
  if (Math.abs(n) &gt;= 1e6) return (n / 1e6).toFixed(d) + 'M';
  if (Math.abs(n) &gt;= 1e3) return (n / 1e3).toFixed(d) + 'k';
  return n.toFixed(d);
}

function log(msg) {
  const d = new Date();
  const t = `${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}:${String(d.getSeconds()).padStart(2,'0')}`;
  const el = document.getElementById('log');
  el.innerHTML = `[${t}] ${msg}&lt;br&gt;` + el.innerHTML;
}

function runSimulation() {
  simRunning = true;
  integrity = 100;
  failureTriggered = false;
  currentFailureMode = "none";
  debrisParticles = [];
  log('ЗАПУСК ДИНАМИЧЕСКОЙ СИМУЛЯЦИИ СПУСКА');
  
  let H = 90;
  const interval = setInterval(() =&gt; {
    if (!simRunning || H &lt;= 20 || integrity &lt;= 0) {
      clearInterval(interval);
      simRunning = false;
      if (integrity &lt;= 0) log('⚠ МОДЕЛЬ РАЗРУШЕНА: ' + currentFailureMode.toUpperCase());
      else log('Симуляция завершена. Успешный спуск.');
      return;
    }
    H -= 0.5;
    document.getElementById('rH').value = H;
    runCalc();
  }, 100);
}

function runCalc() {
  const Rn_mm = getVal('rRn');
  const Rn = Rn_mm / 1000;
  const H_alt = getVal('rH');
  const V = getVal('rVinf');
  const B0 = getVal('rB0') || 0;
  const Tw = getVal('rTw');
  const gamma_c = getVal('rCat') / 100 || 0.3;
  const q_lim = getVal('rQlim') || 2.0;
  const mhdOn = document.getElementById('rMHD').checked;
  const matKey = document.getElementById('rMaterial').value;
  const coatKey = document.getElementById('rCoating').value;

  const res = HyperEngine.calculate(Rn, V, H_alt, B0, Tw, gamma_c, mhdOn, matKey, coatKey);
  
  if (currentMode === 'student') {
    if (res.damageRate &gt; 0 &amp;&amp; !failureTriggered) {
      integrity = Math.max(0, integrity - res.damageRate * 0.5);
      currentFailureMode = res.failureMode;
      if (integrity &lt;= 0 &amp;&amp; !failureTriggered) {
        failureTriggered = true;
        triggerFailure(res.failureMode);
      }
    }
    document.getElementById('oIntegrity').textContent = integrity.toFixed(1);
    document.getElementById('oMatName').textContent = res.mat.name;
    document.getElementById('oMatTmax').textContent = res.mat.Tmax + ' K';
    document.getElementById('oFailureMode').textContent = currentFailureMode === "none" ? "Нет" : currentFailureMode.toUpperCase();
    document.getElementById('oFailureMode').className = 'mval ' + (currentFailureMode === "none" ? '' : 'crit');
    
    const bar = document.getElementById('integrityBar');
    bar.style.width = integrity + '%';
    bar.className = 'integrity-bar ' + (integrity &lt; 30 ? 'critical' : integrity &lt; 70 ? 'warning' : '');
  }

  document.getElementById('oRn').textContent = Rn_mm;
  document.getElementById('oH').textContent = H_alt.toFixed(1);
  document.getElementById('oV').textContent = Math.round(V);
  document.getElementById('oTw').textContent = Tw;
  document.getElementById('oM').textContent = res.M.toFixed(2);
  document.getElementById('oRe').textContent = formatNum(res.Re, 1);
  document.getElementById('oTsh').textContent = Math.round(res.T_shock);
  
  if (currentMode === 'scientist') {
    document.getElementById('oCat').textContent = gamma_c.toFixed(2);
    document.getElementById('oQlim').textContent = q_lim.toFixed(1);
    document.getElementById('oB0').textContent = B0.toFixed(2);
    document.getElementById('oQw').textContent = res.qw.toFixed(3) + ' МВт/м²';
    document.getElementById('oCd').textContent = res.Cd.toFixed(3);
    document.getElementById('oDelta').textContent = res.delta_Rn.toFixed(3);
    const margin = ((q_lim - res.qw) / q_lim) * 100;
    document.getElementById('oMargin').textContent = margin.toFixed(1) + ' %';
  }

  const Vcrit = HyperEngine.findVcrit(Rn, H_alt, B0, Tw, gamma_c, q_lim, mhdOn, matKey, coatKey);
  document.getElementById('oVcrit').textContent = Math.round(Vcrit) + ' м/с';
  
  const tps_mm = Math.max(3, Math.sqrt(res.qw * 1e6 * 300 / (1.2e6)) * 2);
  document.getElementById('oTPS').textContent = tps_mm.toFixed(1) + ' мм';

  const verdict = document.getElementById('verdict');
  const chipStatus = document.getElementById('chipStatus');
  
  if (integrity &lt;= 0 || res.Tw_eq &gt; res.mat.Tmax * 1.2) {
    verdict.textContent = 'КОРПУС РАЗРУШЕН';
    verdict.className = 'verdict-box danger';
    chipStatus.textContent = 'FAILURE';
    chipStatus.className = 'chip danger';
  } else if (res.qw &gt; q_lim || res.Tw_eq &gt; res.mat.Tmax) {
    verdict.textContent = 'ПЕРЕГРЕВ / ПРОБОЙ';
    verdict.className = 'verdict-box danger';
    chipStatus.textContent = 'CRITICAL';
    chipStatus.className = 'chip warn';
  } else {
    verdict.textContent = 'НОРМА';
    verdict.className = 'verdict-box safe';
    chipStatus.textContent = 'NOMINAL';
    chipStatus.className = 'chip ok';
  }

  const pxPerKm = Math.max(2, Math.min(20, 1000 / (H_alt + 10)));
  document.getElementById('scaleIndicator').textContent = `Масштаб: 1 км ≈ ${pxPerKm.toFixed(1)} px | Высота: ${H_alt.toFixed(1)} км`;

  renderVis(res);
  updateProfileChart(res, Rn);
}

function triggerFailure(mode) {
  log('⚠ ИНИЦИИРОВАНО РАЗРУШЕНИЕ: ' + mode.toUpperCase());
  const cx = viz.width * 0.35;
  const cy = (viz.height / 2) + 100; // Сдвиг вниз для осколков
  const count = mode === "explosion" ? 40 : 25;
  const speedMult = mode === "explosion" ? 200 : 150;
  
  for (let i = 0; i &lt; count; i++) {
    const angle = Math.random() * Math.PI * 2;
    const speed = 50 + Math.random() * speedMult;
    debrisParticles.push(new Debris(
      cx + (Math.random() - 0.5) * 40,
      cy + (Math.random() - 0.5) * 40,
      Math.cos(angle) * speed,
      Math.sin(angle) * speed,
      5 + Math.random() * 15,
      Math.random() * Math.PI * 2
    ));
  }
}

// ============================================================
// CANVAS VISUALIZATION (FIXED SCALING &amp; DOWNWARD SHIFT)
// ============================================================
const viz = document.getElementById('viz');
const ctx = viz.getContext('2d');
let stars = [];

function resizeViz() {
  const r = viz.getBoundingClientRect();
  viz.width = r.width;
  viz.height = r.height;
  
  stars = [];
  for (let i = 0; i &lt; 100; i++) {
    stars.push({ x: Math.random() * viz.width, y: Math.random() * viz.height, size: Math.random() * 2, speed: 1 + Math.random() * 3 });
  }
}
window.addEventListener('resize', () =&gt; { resizeViz(); runCalc(); });

function updateParticles(dt) {
  plasmaParticles = plasmaParticles.filter(p =&gt; { p.update(dt); return p.life &gt; 0 &amp;&amp; p.size &gt; 0.5; });
  debrisParticles = debrisParticles.filter(d =&gt; { d.update(dt); return d.life &gt; 0; });
}

function emitPlasmaParticles(cx, cy, Rn_px, T_shock, M, dt) {
  const emitRate = Math.min(10, 2 + T_shock / 2000);
  const numToEmit = Math.floor(emitRate * dt * 60);
  for (let i = 0; i &lt; numToEmit; i++) {
    const angle = (Math.random() - 0.5) * 0.8;
    const emitX = cx - Rn_px * Math.cos(angle);
    const emitY = cy + Rn_px * Math.sin(angle);
    const vx = -100 - Math.random() * 100 * (M / 5);
    const vy = (Math.random() - 0.5) * 30;
    const temp = T_shock * (0.7 + Math.random() * 0.3);
    const size = 2 + Math.random() * 4;
    plasmaParticles.push(new Particle(emitX, emitY, vx, vy, temp, size));
  }
}

function renderVis(res) {
  const W = viz.width, H = viz.height;
  const dt = 1/60;
  updateParticles(dt);
  ctx.clearRect(0, 0, W, H);

  const altFactor = Math.max(0, Math.min(1, getVal('rH') / 90));
  const grad = ctx.createLinearGradient(0, 0, 0, H);
  grad.addColorStop(0, `rgba(5, 8, 16, ${altFactor})`);
  grad.addColorStop(1, `rgba(10, 20, 40, ${altFactor})`);
  ctx.fillStyle = grad;
  ctx.fillRect(0, 0, W, H);

  ctx.fillStyle = `rgba(255,255,255,${0.3 + (1-altFactor)*0.5})`;
  stars.forEach(s =&gt; {
    if (simRunning) { s.x -= s.speed * 3; if (s.x &lt; 0) { s.x = W; s.y = Math.random() * H; } }
    ctx.fillRect(s.x, s.y, s.size, s.size);
  });

  // Вычисляем масштаб так, чтобы ракета ВСЕГДА помещалась по высоте с запасом 30%
  const baseScale = Math.min(W, H) * 0.0006;
  let Rn_px = getVal('rRn') * baseScale;
  
  // Жесткое ограничение: радиус не может занимать больше 25% высоты канваса
  const maxAllowedRn = H * 0.25;
  if (Rn_px &gt; maxAllowedRn) {
    Rn_px = maxAllowedRn;
  }

  const cx = W * 0.35;
  
  // =====================================================================
  // !!! ГЛАВНОЕ ИСПРАВЛЕНИЕ: СДВИГ ПОЛЯ И РАКЕТЫ ВНИЗ НА 100px (~100мм) !!!
  // =====================================================================
  const cy = (H / 2) + 100; 
  
  if (integrity &gt; 0) emitPlasmaParticles(cx, cy, Rn_px, res.T_shock, res.M, dt);

  ctx.globalCompositeOperation = 'lighter';
  plasmaParticles.forEach(p =&gt; {
    ctx.fillStyle = p.getColor();
    ctx.beginPath();
    ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
    ctx.fill();
  });
  ctx.globalCompositeOperation = 'source-over';

  if (res.M &gt; 1 &amp;&amp; integrity &gt; 0) {
    const machAngle = Math.asin(1 / res.M);
    ctx.strokeStyle = `rgba(255, 200, 100, 0.3)`;
    ctx.lineWidth = 1;
    ctx.setLineDash([5, 5]);
    ctx.beginPath();
    ctx.moveTo(cx, cy);
    ctx.lineTo(cx - W * Math.cos(machAngle), cy - W * Math.sin(machAngle));
    ctx.moveTo(cx, cy);
    ctx.lineTo(cx - W * Math.cos(machAngle), cy + W * Math.sin(machAngle));
    ctx.stroke();
    ctx.setLineDash([]);
  }

  const shockOffset = Rn_px * (1 + res.delta_Rn);
  const intensity = Math.min(1, res.T_shock / 12000);
  const heatGrad = ctx.createRadialGradient(cx, cy, Rn_px * 0.5, cx, cy, shockOffset * 1.5);
  heatGrad.addColorStop(0, `rgba(255, 255, 220, ${0.8 * intensity})`);
  heatGrad.addColorStop(0.4, `rgba(255, 100, 20, ${0.4 * intensity})`);
  heatGrad.addColorStop(1, 'rgba(255, 0, 0, 0)');
  ctx.fillStyle = heatGrad;
  ctx.beginPath();
  ctx.arc(cx, cy, shockOffset * 1.5, 0, Math.PI * 2);
  ctx.fill();

  if (integrity &gt; 0) {
    const mat = res.mat;
    ctx.fillStyle = mat.color;
    ctx.strokeStyle = integrity &lt; 50 ? '#ff4757' : '#6a7590';
    ctx.lineWidth = integrity &lt; 50 ? 3 : 2;
    
    ctx.beginPath();
    // Носок
    ctx.arc(cx, cy, Rn_px, -Math.PI * 0.8, Math.PI * 0.8, false);
    // Корпус (длина привязана к Rn_px)
    const bodyLen = Rn_px * 4;
    ctx.lineTo(cx + bodyLen, cy - Rn_px * 0.7);
    ctx.lineTo(cx + bodyLen, cy + Rn_px * 0.7);
    ctx.closePath();
    ctx.fill();
    ctx.stroke();

    // Damage overlay
    if (integrity &lt; 100) {
      ctx.save();
      ctx.clip();
      const damageAlpha = (100 - integrity) / 100;
      ctx.fillStyle = `rgba(255, 50, 0, ${damageAlpha * 0.7})`;
      ctx.fillRect(cx - Rn_px, cy - Rn_px, Rn_px * 2, Rn_px * 2);
      
      if (currentFailureMode === "cracking" &amp;&amp; integrity &lt; 70) {
        ctx.strokeStyle = `rgba(0, 0, 0, ${damageAlpha})`;
        ctx.lineWidth = 1;
        ctx.beginPath();
        for (let i = 0; i &lt; 5; i++) {
          const startX = cx - Rn_px * 0.5 + Math.random() * Rn_px;
          const startY = cy - Rn_px * 0.5 + Math.random() * Rn_px;
          ctx.moveTo(startX, startY);
          ctx.lineTo(startX + (Math.random()-0.5)*40, startY + (Math.random()-0.5)*40);
        }
        ctx.stroke();
      }
      ctx.restore();
    }
  }

  debrisParticles.forEach(d =&gt; {
    ctx.save();
    ctx.translate(d.x, d.y);
    ctx.rotate(d.rotation);
    ctx.fillStyle = `rgba(255, 100, 50, ${d.life})`;
    ctx.fillRect(-d.size/2, -d.size/2, d.size, d.size);
    ctx.restore();
  });

  ctx.fillStyle = 'rgba(0, 217, 255, 0.9)';
  ctx.font = 'bold 12px monospace';
  ctx.fillText(`V = ${Math.round(getVal('rVinf'))} m/s | M = ${res.M.toFixed(2)}`, 20, 20);
  if (currentMode === 'student') {
    ctx.fillStyle = integrity &lt; 50 ? '#ff4757' : '#00ff88';
    ctx.fillText(`ЦЕЛОСТНОСТЬ: ${integrity.toFixed(1)}%`, 20, 40);
  }
}

// ============================================================
// CHARTS
// ============================================================
function initCharts() {
  const opt = () =&gt; ({
    responsive: true, maintainAspectRatio: false,
    plugins: { legend: { labels: { color: '#e8ecf5', font: { size: 10 } } } },
    scales: {
      x: { ticks: { color: '#8a94ad', font: { size: 9 } }, grid: { color: '#2a3550' } },
      y: { ticks: { color: '#8a94ad', font: { size: 9 } }, grid: { color: '#2a3550' } }
    }
  });

  if (document.getElementById('chartProfile')) {
    profileChart = new Chart(document.getElementById('chartProfile'), {
      type: 'line',
      data: { labels: [], datasets: [{ label: 'T (K)', data: [], borderColor: '#ff4757', tension: 0.3 }] },
      options: opt()
    });
  }

  if (document.getElementById('chartSweep')) {
    sweepChart = new Chart(document.getElementById('chartSweep'), {
      type: 'line',
      data: { labels: [], datasets: [{ label: 'qₓ', data: [], borderColor: '#a855f7', tension: 0.3 }] },
      options: opt()
    });
  }
}

function updateProfileChart(res, Rn) {
  if (!profileChart) return;
  const labels = [], tData = [];
  const T_shock = res.T_shock, Tw = getVal('rTw'), atm = res.atm;
  for (let i = 0; i &lt;= 40; i++) {
    const x_norm = i / 10;
    labels.push(x_norm.toFixed(1));
    let T;
    if (x_norm &lt; 0.1) T = Tw + (T_shock - Tw) * (x_norm / 0.1) * 0.3;
    else if (x_norm &lt; 1.0) T = T_shock * (1 - (x_norm - 0.1) * 0.3);
    else T = atm.T + (T_shock - atm.T) * Math.exp(-(x_norm - 1) * 0.5);
    tData.push(Math.round(T));
  }
  profileChart.data.labels = labels;
  profileChart.data.datasets[0].data = tData;
  profileChart.update('none');
}

function findVcrit() {
  const Rn = getVal('rRn') / 1000, H = getVal('rH'), B0 = getVal('rB0'), Tw = getVal('rTw');
  const gamma_c = getVal('rCat') / 100, q_lim = getVal('rQlim');
  const mhdOn = document.getElementById('rMHD').checked;
  const matKey = document.getElementById('rMaterial').value;
  const coatKey = document.getElementById('rCoating').value;
  const V = HyperEngine.findVcrit(Rn, H, B0, Tw, gamma_c, q_lim, mhdOn, matKey, coatKey);
  document.getElementById('rVinf').value = V;
  log('Подбор Vcrit: ' + Math.round(V) + ' м/с');
  runCalc();
}

function runSweep() {
  if (!sweepChart) return;
  log('Параметрический свип B₀: 0..5 Тл');
  const Rn = getVal('rRn') / 1000, H = getVal('rH'), V = getVal('rVinf'), Tw = getVal('rTw');
  const gamma_c = getVal('rCat') / 100;
  const matKey = document.getElementById('rMaterial').value;
  const coatKey = document.getElementById('rCoating').value;
  const labels = [], qData = [];
  for (let b = 0; b &lt;= 5; b += 0.2) {
    const r = HyperEngine.calculate(Rn, V, H, b, Tw, gamma_c, true, matKey, coatKey);
    labels.push(b.toFixed(1));
    qData.push(r.qw.toFixed(3));
  }
  sweepChart.data.labels = labels;
  sweepChart.data.datasets[0].data = qData;
  sweepChart.update();
  log('Свип завершен.');
}

function generateProtocol() {
  const res = HyperEngine.calculate(getVal('rRn')/1000, getVal('rVinf'), getVal('rH'), getVal('rB0'), getVal('rTw'), getVal('rCat')/100, document.getElementById('rMHD').checked, document.getElementById('rMaterial').value, document.getElementById('rCoating').value);
  const date = new Date().toLocaleString('ru-RU');
  const html = `
    &lt;h1&gt;ПРОТОКОЛ РАСЧЁТА ИМ-07&lt;/h1&gt;
    &lt;p&gt;&lt;b&gt;Дата:&lt;/b&gt; ${date} | &lt;b&gt;Режим:&lt;/b&gt; ${currentMode === 'student' ? 'Студенческий' : 'Научный'}&lt;/p&gt;
    &lt;h2&gt;1. Параметры&lt;/h2&gt;
    &lt;table&gt;
      &lt;tr&gt;&lt;th&gt;Параметр&lt;/th&gt;&lt;th&gt;Значение&lt;/th&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;Материал&lt;/td&gt;&lt;td&gt;${res.mat.name} (Tmax: ${res.mat.Tmax} K)&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;Покрытие&lt;/td&gt;&lt;td&gt;${Coatings[document.getElementById('rCoating').value].name}&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;Высота / Скорость&lt;/td&gt;&lt;td&gt;${getVal('rH')} км / ${getVal('rVinf')} м/с&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;Число Маха&lt;/td&gt;&lt;td&gt;${res.M.toFixed(3)}&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;Температура за УВ&lt;/td&gt;&lt;td&gt;${Math.round(res.T_shock)} K&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;Температура стенки&lt;/td&gt;&lt;td&gt;${Math.round(res.Tw_eq)} K&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;Тепловой поток&lt;/td&gt;&lt;td&gt;${res.qw.toFixed(3)} МВт/м²&lt;/td&gt;&lt;/tr&gt;
    &lt;/table&gt;
    &lt;h2&gt;2. Вердикт&lt;/h2&gt;
    &lt;p&gt;&lt;b&gt;Статус:&lt;/b&gt; ${res.Tw_eq &gt; res.mat.Tmax ? '⚠ ПЕРЕГРЕВ МАТЕРИАЛА' : '✓ ДОПУСТИМО'}&lt;/p&gt;
  `;
  document.getElementById('protocolContent').innerHTML = html;
  document.getElementById('protocolModal').classList.add('active');
}

function closeProtocol() {
  document.getElementById('protocolModal').classList.remove('active');
}

// ============================================================
// INIT
// ============================================================
document.querySelectorAll('input[type=range], select, input[type=checkbox]').forEach(el =&gt; {
  el.addEventListener('input', runCalc);
  el.addEventListener('change', runCalc);
});

window.addEventListener('load', () =&gt; {
  resizeViz();
  initCharts();
  runCalc();
  log('Система готова. Движок HYPERLAB v4.3 активен.');
});

function animate() {
  if (currentMode === 'student' || simRunning) {
    const Rn = getVal('rRn') / 1000;
    const H = getVal('rH');
    const V = getVal('rVinf');
    const B0 = getVal('rB0') || 0;
    const Tw = getVal('rTw');
    const gamma_c = getVal('rCat') / 100 || 0.3;
    const mhdOn = document.getElementById('rMHD').checked;
    const matKey = document.getElementById('rMaterial').value;
    const coatKey = document.getElementById('rCoating').value;
    const res = HyperEngine.calculate(Rn, V, H, B0, Tw, gamma_c, mhdOn, matKey, coatKey);
    renderVis(res);
  }
  requestAnimationFrame(animate);
}
animate();
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</subtitle>
  <updated>2026-08-23T10:08:51Z</updated>
  <logo>https://pandoraburo.ru/ssl/layouts/a9/8c8/4b7781a4db8477265eb51f31892.png</logo>
  <author>
    <name>1592962</name>
    <uri>https://www.pandoraburo.ru/</uri>
  </author>
</feed>
