Цель
Перейти от точечного использования ИИ к оркестрации — централизованному управлению сложной цепочкой учебных задач. Это позволяет объединить разрозненные инструменты (Google Sheets, Gemini, Canva) в единый управляемый поток, создавая эффект «когнитивного лесов» (scaffolding) для студента.
Задачи
Синхронизировать разрозненные ИИ-инструменты в единую управляемую цепочку (workflow) вместо замены ручного труда на отдельных участках.
Применить методологию адаптивного кейс-менеджмента (ACM) для решения учебных задач в условиях неопределённости.
Организовать интерактивное рабочее пространство в Gemini Canvas для совместного редактирования условий кейса и кода в реальном времени.
Выстроить систему «когнитивных лесов» (scaffolding), используя ИИ для поэтапной поддержки и направления мыслительного процесса студентов.
Практика
Сборка симулятора (6 блоков)
Контекст: Формирование названия и описания ситуации.
Аналитика: Визуализация данных через таблицы и графики Google Sheets.
Альтернативы: Генерация и презентация вариантов проектов с помощью ИИ.
Коллаборация: Групповой SWOT-анализ и обсуждение в интерфейсе Canvas.
Решение: Выбор стратегии с обоснованием через призму ESG и оценку рисков.
Синтез: Автоматическое создание PDF-отчёта и инфографики в NotebookLM.
Инструменты
Google Sheets & Apps Script.
Gemini (режим Canvas).
Canva, ChatGPT.
NotebookLM.
Результат
Готовый Web App симулятор, который аккумулирует данные о решениях студентов в базу для последующего анализа на дашборде.
Продукт Milestone:
MVP интерактивного кейс-симулятора, реализующего адаптивный сценарий обучения под управлением ИИ-оркестратора.
Ниже представлен краткий обзор темы «Оркестрация образовательных процессов и использование Gemini Canvas для работы с кейсами», подготовленный специально для публикации на сайте.
Современное образование переходит от простой автоматизации к оркестрации процессов — централизованному управлению и координации сложных учебных цепочек, в которых участвуют студенты, преподаватели и системы ИИ. В этой парадигме ключевую роль играют «оркестраторы учебных сетей» (Learning Network Orchestrators, LNO), которые используют технологии для эффективного распределения задач и ресурсов.
Что такое оркестрация и Case Management?
Оркестрация отличается от обычной автоматизации тем, что она связывает разрозненные задачи в единый управляемый поток. В обучении это означает не просто выдачу теста, а координацию всего процесса исследования ситуации.
Case Management (управление кейсами) фокусируется на достижении результата в условиях неопределенности. ИИ позволяет сделать этот процесс адаптивным, когда система учится на прошлых решениях и предлагает лучшие практики для новых сценариев.
Gemini Canvas как интерактивное рабочее пространство
Инструмент Gemini Canvas представляет собой выделенное окно для глубокой работы над контентом, что делает его идеальным для разбора кейсов.
Редактирование в реальном времени: Преподаватели и студенты могут изменять условия кейса, структуру и код прямо в интерфейсе Canvas, при этом все правки отражаются мгновенно.
Специализированные функции: Canvas позволяет быстро изменять тон текста, его длину или добавлять формулы LaTeX, что критически важно для создания профессиональных учебных материалов.
Интеграция с экосистемой Google: Готовые решения можно в один клик экспортировать в Google Docs или Colab, обеспечивая бесшовный рабочий процесс.
Практические сценарии применения
Использование ИИ-оркестрации в работе с кейсами открывает следующие возможности:
Когнитивные леса (Scaffolding): ИИ может выдавать информацию по кейсу порционно, направляя студента через «зоны затруднения» и помогая строить многоуровневые решения.
Автоматизированная обратная связь: ИИ-ассистенты способны анализировать предложенные студентами решения, выделять логические ошибки и предлагать варианты для улучшения аргументации.
Генерация контента: На основе одного файла или запроса ИИ создает условия кейса, проверочные тесты и даже интерактивные приложения-викторины прямо в Canvas.
Этика и роль преподавателя
Несмотря на мощь алгоритмов, человекоцентричный подход остается приоритетом. ИИ рассматривается как инструмент, усиливающий педагога, а не заменяющий его. Преподаватель в системе оркестрации выступает в роли «дирижера», который контролирует этичность использования данных и сохраняет живой контакт в обучении.
Итог: Интеграция Gemini Canvas в процессы оркестрации кейсов позволяет превратить традиционное изучение ситуаций в динамичное, персонализированное и высокотехнологичное исследование, экономя время преподавателя и повышая вовлеченность студентов.
Ниже представлена краткая пошаговая инструкция по использованию интерактивного рабочего пространства Gemini Canvas для создания и редактирования текстов, кода и приложений.
Перейдите на сайт gemini.google.com и войдите в свой Google-аккаунт.
Важно: Убедитесь, что у вас выбрана модель Gemini 2.0 Flash, так как функция Canvas работает именно с ней.
Найдите кнопку «Canvas» (или значок холста) под полем для ввода запроса.
Нажмите на неё — кнопка должна стать синей, что означает активацию интерактивного режима.
При необходимости вы можете сразу загрузить файл (например, PDF), нажав «Добавить файлы», чтобы ИИ работал на его основе.
Введите запрос в текстовое поле. Например:
«Напиши статью о методах обучения в вузе».
«Создай игру "крестики-нолики" на Python».
«Сгенерируй тест по теме маркетинга на основе этого PDF».
Нажмите «Отправить». В правой части интерфейса откроется панель Canvas, где контент будет создаваться в реальном времени.
Canvas позволяет изменять результат без необходимости переписывать весь запрос:
Прямое редактирование: Вы можете просто печатать или удалять текст прямо в окне Canvas, как в обычном текстовом редакторе — изменения сохраняются автоматически.
Выборочные правки: Выделите курсором конкретный фрагмент текста и нажмите кнопку «Выбрать и спросить» (Select and ask). В появившемся окне укажите, что именно нужно сделать (например, «перефразируй это» или «объясни это слово»).
Быстрые инструменты: Используйте меню справа для мгновенного изменения тона (сделать более формальным) или длины текста.
Форматирование: Используйте панель инструментов сверху, чтобы выделить текст жирным, создать списки или добавить формулы LaTeX.
Если вы создаете приложение или сайт:
Просмотр и предпросмотр: Переключайтесь между вкладками «Код» (для редактирования исходного текста программы) и «Preview» (чтобы увидеть, как работает приложение).
Отладка: Нажмите «Показать консоль», чтобы найти ошибки в коде.
Добавление ИИ-функций: В правом нижнем углу можно нажать «Добавить функции Gemini», чтобы внедрить в ваше создаваемое приложение возможности генерации текста или изображений.
Экспорт: Нажмите «Поделиться и экспортировать».
Тексты можно мгновенно отправить в Google Документы.
Python-код можно открыть в Google Colab.
Поделиться: Вы можете создать общедоступную ссылку на свою работу. Те, кто перейдет по ссылке, смогут просмотреть ваше приложение или создать копию вашего Canvas для дальнейшего редактирования.
Ограничение: В настоящее время Canvas лучше всего подходит для работы с одним файлом или простыми веб-приложениями; создание сложных многофайловых систем пока не поддерживается.
Действуй как Senior Frontend Developer. Твоя задача — создать интерактивное веб-приложение «Aral Sea Decision Simulator» (учебный симулятор MBA-уровня).
Приложение должно быть выполнено в виде одного HTML-файла (Single Page Application), подходящего для деплоя в Google Apps Script Web App (весь CSS и JS должен быть внутри HTML).
📌 СТЕК ТЕХНОЛОГИЙ:
- HTML5
- Tailwind CSS (подключить через CDN)
- Chart.js (подключить через CDN)
- Google Fonts (шрифт Inter)
- Иконки: SVG (встроенные)
🎨 ДИЗАЙН И СТИЛИСТИКА (UI/UX):
- Тема: Тёмная (цвета фона: graphite #0d1117, #161b22; бордеры #30363d).
- Акценты: Неоновые (cyan, emerald, amber, rose, purple).
- Стилизация элементов: Блоки (карточки) со скругленными углами и эффектом неонового свечения при наведении (glow-эффект через box-shadow).
- Маркеры шагов: Перед заголовком каждого из 6 шагов должен быть яркий неоново-оранжевый круг с цифрой шага внутри, который плавно пульсирует (CSS анимация scale и box-shadow).
⚙️ НАВИГАЦИЯ И ПРОГРЕСС-БАР (ХЭДЕР):
Сделай "липкий" (sticky) хэдер сверху. В нем:
1. Линия прогресса: Пунктирная светло-серая линия, которая анимированно бежит слева направо на фоне пробирок.
2. 6 пробирок (шагов):
- Пробирки сделаны из "сероватого стекла" (border серого цвета).
- Внутри каждой пробирки вода. Поверхность воды должна анимированно волноваться (используй CSS mask-image с SVG-волной и анимацию движения по горизонтали).
- Цвет воды плавно меняется от шага к шагу: от зеленоватого (в 1-й) до светло-голубого (в 6-й).
- Уровень воды формирует "лесенку": 1 пробирка - 20%, 2 пробирка - 35%, 3 пробирка - 50%, 4 пробирка - 65%, 5 пробирка - 80%, 6 пробирка - 95%.
- Если шаг заблокирован, пробирка серая (grayscale, opacity 50%), вода на нуле. Если шаг разблокирован — пробирка загорается и вода поднимается до своего заданного уровня.
🔒 ЛОГИКА ПРОХОЖДЕНИЯ (UNLOCK SYSTEM):
- Строгая последовательность: Шаги со 2 по 6 изначально скрыты (`display: none` или `.hidden`).
- Перейти к следующему шагу (разблокировать его) можно ТОЛЬКО совершив целевое действие в текущем шаге.
- При разблокировке нового шага страница должна плавно скроллиться вниз к нему.
- Нажатие на пробирку в хэдере скроллит к шагу, но только если этот шаг уже разблокирован.
📝 СТРУКТУРА КОНТЕНТА (6 БЛОКОВ):
ШАГ 1: Изучение контекста
- Заголовок: "Aral Sea Decision Simulator" (подзаголовок: Экологическая миссия или инвестиционный проект).
- Текст кейса: Аральское море сократилось на 90% из-за отвода воды из Сырдарьи и Амударьи. В 2005 году проект Кокаральской дамбы частично восстановил Северное Аральское море. Сейчас рассматривается вторая фаза.
- 2 мини-графика (Chart.js), расположенные рядом:
1) Соленость (г/л): До - 30, После - 10 (цвет красный -> голубой).
2) Улов рыбы (тыс. тонн): До - 1, После - 8 (цвет серый -> зеленый).
- 3 карточки проектов (A, B, C):
- A (Комплексное восстановление с ИИ): 120 млн $, Эффект/ESG - Высокий, Риски - Средние.
- B (Частичное развитие с ИИ): 70 млн $, Эффект/ESG - Средний, Риски - Низкие.
- C (Минимальные вложения): 30 млн $, Эффект/ESG - Низкий, Риски - Высокие.
- Триггер: Кнопка "Подтвердить изучение кейса". По клику открывается Шаг 2.
ШАГ 2: Интерактивная викторина (AI / PM / ESG)
- Сгенерируй 10 профессиональных вопросов с 4 вариантами ответов каждый.
- Логика викторины: При клике на ответ кнопки блокируются. Если верно — кнопка загорается зеленым, если неверно — красным (и зеленым подсвечивается правильный ответ). Через 1.5 секунды появляется следующий вопрос.
- Трекер викторины: Справа от вопросов размести горизонтальный график Chart.js (bar). Он должен отображать прогресс пользователя (от 0 до 100 баллов) в виде одной полосы, заполняющейся градиентом от изумрудного к голубому.
- Триггер: После 10-го вопроса появляется кнопка "Приступить к SWOT-анализу". По клику открывается Шаг 3.
ШАГ 3: SWOT-анализ проекта
- Описание задачи (провести SWOT анализ выбранного проекта).
- Триггер: Кнопка-ссылка "Открыть шаблон в Canva" (href="https://www.canva.com/", target="_blank"). По клику на нее автоматически открывается Шаг 4.
ШАГ 4: Утверждение решения
- Описание задачи (выбор финального проекта и заполнение формы).
- Триггер: Кнопка-ссылка "Перейти к Google Form" (href="#", target="_blank"). По клику на нее автоматически открывается Шаг 5.
ШАГ 5: AI-Синтез в NotebookLM
- Описание задачи (загрузка материалов в NotebookLM для генерации Audio Overview / подкаста и структуры инфографики).
- Триггер: Кнопка-ссылка "Открыть Google NotebookLM" (href="https://notebooklm.google.com/", target="_blank"). По клику на нее автоматически открывается финальный Шаг 6.
ШАГ 6: Защита проектов и Финал
- Красивый финальный экран с сообщением "Симуляция завершена", фоновыми свечениями и текстом об успешной подготовке к питчингу и защите проектов.
⚡ ТРЕБОВАНИЯ К КОДУ:
- Напиши чистый, хорошо откомментированный код.
- Вся логика JavaScript (викторина, графики, unlock-система, анимации) должна быть реализована без использования Alert/Confirm.
- UI должен быть полностью адаптивным (мобильные устройства, планшеты, ПК).
- Не используй внешние картинки, только CSS/SVG.
- Заверши ответ маркером ```eof
<!DOCTYPE html>
<html lang="ru" class="scroll-smooth">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Aral Sea Decision Simulator - Executive MBA</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #0d1117;
color: #c9d1d9;
}
.neon-border-cyan:hover {
box-shadow: 0 0 15px rgba(6, 182, 212, 0.4);
border-color: #06b6d4;
}
.neon-border-emerald:hover {
box-shadow: 0 0 15px rgba(16, 185, 129, 0.4);
border-color: #10b981;
}
.neon-border-rose:hover {
box-shadow: 0 0 15px rgba(244, 63, 94, 0.4);
border-color: #f43f5e;
}
/* Step pulse markers */
@keyframes pulse-scale {
0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(249, 115, 22, 0.7); }
50% { transform: scale(1.08); box-shadow: 0 0 12px 6px rgba(249, 115, 22, 0.3); }
}
.pulse-step {
animation: pulse-scale 2.5s infinite ease-in-out;
}
/* Grid backgrounds and glassmorphism */
.glass-panel {
background: rgba(22, 27, 34, 0.8);
backdrop-filter: blur(8px);
border: 1px border #30363d;
}
/* Progress line animation */
@keyframes flow {
from { background-position: 0 0; }
to { background-position: 40px 0; }
}
.progress-flow-line {
background-image: linear-gradient(90deg, #30363d 50%, transparent 50%);
background-size: 15px 2px;
animation: flow 2s linear infinite;
}
/* 3D Coin Rotation Effect */
@keyframes spinY {
0% { transform: rotateY(0deg); }
100% { transform: rotateY(360deg); }
}
.spin-coin {
animation: spinY 3s linear infinite;
transform-style: preserve-3d;
perspective: 800px;
}
.text-shadow-gold {
text-shadow: 0 0 8px rgba(245, 158, 11, 0.8);
}
</style>
</head>
<body class="min-h-screen pb-24 selection:bg-cyan-500 selection:text-black">
<!-- TOAST NOTIFICATION CONTAINER -->
<div id="toast-container" class="fixed bottom-5 right-5 z-50 space-y-2 pointer-events-none"></div>
<!-- STICKY HEADER WITH COIN & BEAKERS -->
<header class="sticky top-0 z-50 glass-panel border-b border-[#30363d] px-4 py-3 shadow-xl">
<div class="max-w-6xl mx-auto flex flex-col md:flex-row items-center justify-between gap-4">
<!-- Logo & Title -->
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-lg bg-orange-600 flex items-center justify-center font-black text-black text-sm">AS</div>
<div>
<h2 class="text-sm font-bold text-white tracking-wide">ARAL SEA SIMULATOR</h2>
<p class="text-[10px] text-gray-400">Executive Strategic Framework</p>
</div>
</div>
<!-- GAMIFIED GOLD COIN SPINNING 360 & IQ TOTAL SCORE -->
<div class="flex items-center gap-3 bg-gradient-to-r from-amber-950/30 to-yellow-950/20 px-5 py-2 rounded-2xl border border-amber-500/30 shadow-inner">
<div class="w-10 h-10 relative">
<div class="w-full h-full spin-coin">
<svg class="w-full h-full" viewBox="0 0 100 100" filter="drop-shadow(0px 0px 5px rgba(245, 158, 11, 0.7))">
<!-- Outer Bevel -->
<circle cx="50" cy="50" r="46" fill="url(#gold-gradient-3d)" stroke="#d97706" stroke-width="4"/>
<!-- Inner Bevel -->
<circle cx="50" cy="50" r="38" fill="none" stroke="#fbbf24" stroke-width="2" stroke-dasharray="6,3"/>
<!-- Star Core -->
<text x="50" y="65" font-family="sans-serif" font-weight="900" font-size="48" fill="#78350f" text-anchor="middle">★</text>
<defs>
<linearGradient id="gold-gradient-3d" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fbbf24" />
<stop offset="30%" stop-color="#fef08a" />
<stop offset="70%" stop-color="#f59e0b" />
<stop offset="100%" stop-color="#b45309" />
</linearGradient>
</defs>
</svg>
</div>
</div>
<div class="flex flex-col">
<span class="text-[9px] font-bold text-amber-500 tracking-widest uppercase">БАЛЛЫ СТРАТЕГА</span>
<span class="text-xl font-black text-amber-400 text-shadow-gold tracking-tight" id="total-iq-display">0 IQ</span>
</div>
</div>
<!-- Beaker Progress Deck -->
<div class="relative flex items-center justify-between gap-2 sm:gap-4 bg-black/40 px-4 py-2.5 rounded-2xl border border-[#30363d] overflow-hidden">
<!-- Running dotted line in background -->
<div class="absolute left-6 right-6 h-0.5 progress-flow-line opacity-40 z-0"></div>
<!-- Beaker 1 -->
<div onclick="scrollToStep(1)" class="relative z-10 flex flex-col items-center cursor-pointer group" id="beaker-nav-1">
<div class="w-8 h-14 rounded-b-full border-2 border-gray-600 bg-zinc-950/80 relative overflow-hidden flex items-end justify-center transition-all duration-300">
<canvas id="beaker-wave-1" class="w-full absolute bottom-0 transition-all duration-500" style="height: 0%;"></canvas>
<span class="absolute top-1 text-[9px] font-bold text-gray-500 group-hover:text-white transition-colors z-20">01</span>
</div>
<span class="text-[8px] font-medium text-cyan-400 mt-1 uppercase tracking-widest">Контекст</span>
</div>
<!-- Beaker 2 -->
<div onclick="scrollToStep(2)" class="relative z-10 flex flex-col items-center cursor-pointer group opacity-40 grayscale" id="beaker-nav-2">
<div class="w-8 h-14 rounded-b-full border-2 border-gray-600 bg-zinc-950/80 relative overflow-hidden flex items-end justify-center transition-all duration-300">
<canvas id="beaker-wave-2" class="w-full absolute bottom-0 transition-all duration-500" style="height: 0%;"></canvas>
<span class="absolute top-1 text-[9px] font-bold text-gray-500 group-hover:text-white z-20">02</span>
</div>
<span class="text-[8px] font-medium text-gray-400 mt-1 uppercase tracking-widest">Тест</span>
</div>
<!-- Beaker 3 -->
<div onclick="scrollToStep(3)" class="relative z-10 flex flex-col items-center cursor-pointer group opacity-40 grayscale" id="beaker-nav-3">
<div class="w-8 h-14 rounded-b-full border-2 border-gray-600 bg-zinc-950/80 relative overflow-hidden flex items-end justify-center transition-all duration-300">
<canvas id="beaker-wave-3" class="w-full absolute bottom-0 transition-all duration-500" style="height: 0%;"></canvas>
<span class="absolute top-1 text-[9px] font-bold text-gray-500 group-hover:text-white z-20">03</span>
</div>
<span class="text-[8px] font-medium text-gray-400 mt-1 uppercase tracking-widest">SWOT</span>
</div>
<!-- Beaker 4 -->
<div onclick="scrollToStep(4)" class="relative z-10 flex flex-col items-center cursor-pointer group opacity-40 grayscale" id="beaker-nav-4">
<div class="w-8 h-14 rounded-b-full border-2 border-gray-600 bg-zinc-950/80 relative overflow-hidden flex items-end justify-center transition-all duration-300">
<canvas id="beaker-wave-4" class="w-full absolute bottom-0 transition-all duration-500" style="height: 0%;"></canvas>
<span class="absolute top-1 text-[9px] font-bold text-gray-500 group-hover:text-white z-20">04</span>
</div>
<span class="text-[8px] font-medium text-gray-400 mt-1 uppercase tracking-widest">Решение</span>
</div>
<!-- Beaker 5 -->
<div onclick="scrollToStep(5)" class="relative z-10 flex flex-col items-center cursor-pointer group opacity-40 grayscale" id="beaker-nav-5">
<div class="w-8 h-14 rounded-b-full border-2 border-gray-600 bg-zinc-950/80 relative overflow-hidden flex items-end justify-center transition-all duration-300">
<canvas id="beaker-wave-5" class="w-full absolute bottom-0 transition-all duration-500" style="height: 0%;"></canvas>
<span class="absolute top-1 text-[9px] font-bold text-gray-500 group-hover:text-white z-20">05</span>
</div>
<span class="text-[8px] font-medium text-gray-400 mt-1 uppercase tracking-widest">Синтез</span>
</div>
<!-- Beaker 6 -->
<div onclick="scrollToStep(6)" class="relative z-10 flex flex-col items-center cursor-pointer group opacity-40 grayscale" id="beaker-nav-6">
<div class="w-8 h-14 rounded-b-full border-2 border-gray-600 bg-zinc-950/80 relative overflow-hidden flex items-end justify-center transition-all duration-300">
<canvas id="beaker-wave-6" class="w-full absolute bottom-0 transition-all duration-500" style="height: 0%;"></canvas>
<span class="absolute top-1 text-[9px] font-bold text-gray-500 group-hover:text-white z-20">06</span>
</div>
<span class="text-[8px] font-medium text-gray-400 mt-1 uppercase tracking-widest">Финал</span>
</div>
</div>
<!-- AI Credentials Quick-Dock -->
<div class="flex items-center gap-2">
<input type="password" id="api-key" placeholder="Вставьте Gemini API Key" class="bg-[#161b22] border border-[#30363d] rounded-lg px-2.5 py-1.5 text-xs text-white placeholder-gray-500 focus:outline-none focus:border-cyan-500 transition-colors">
<button onclick="resetSimulation()" class="px-2.5 py-1.5 bg-rose-950 hover:bg-rose-900 border border-rose-800 text-rose-300 rounded-lg text-xs font-semibold transition-all">Сбросить</button>
</div>
</div>
</header>
<!-- MAIN BODY -->
<main class="max-w-6xl mx-auto px-4 py-12 space-y-24">
<!-- STEP 1: CASE CONTEXT -->
<section id="step-1" class="space-y-8">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 border-b border-[#30363d] pb-4">
<div class="flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-[#f97316] text-black font-extrabold text-xl flex items-center justify-center pulse-step">1</div>
<div>
<span class="text-xs font-black text-cyan-400 tracking-widest uppercase">Шаг 1. Аналитическое погружение</span>
<h1 class="text-3xl font-black text-white tracking-tight">Aral Sea Decision Simulator</h1>
</div>
</div>
<!-- Step Coin Badge -->
<div class="flex items-center gap-2 bg-amber-950/40 border border-amber-500/30 px-3 py-1.5 rounded-full text-xs text-amber-400 font-extrabold select-none self-start sm:self-center">
<svg class="w-4 h-4 text-amber-500 animate-[pulse_2s_infinite]" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="46" fill="url(#gold-gradient-3d)" stroke="#d97706" stroke-width="8"/>
<text x="50" y="65" font-weight="900" font-size="50" fill="#78350f" text-anchor="middle">★</text>
</svg>
<span id="step-iq-val-1">0 / 10 IQ</span>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-12 gap-8">
<!-- Case Study Details -->
<div class="lg:col-span-7 bg-[#161b22] border border-[#30363d] rounded-2xl p-6 space-y-4 shadow-xl">
<h3 class="text-lg font-bold text-white flex items-center gap-2 text-cyan-400">
Хроника крупнейшего антропогенного кризиса Земли
</h3>
<div class="space-y-3 text-sm text-gray-300 leading-relaxed">
<p>До 1960-х годов Аральское море было четвертым по величине бессточным озером в мире. Однако масштабное перенаправление речного стока Сырдарьи и Амударьи на ирригацию хлопковых полей привело к экологической катастрофе. К началу XXI века море потеряло <strong>более 90% своего первоначального объема</strong>.</p>
<p>Осушенное дно превратилось в ядовитую солончаковую пустыню Аралкум. В 2005 году возведение Кокаральской плотины позволило спасти Малый Арал, снизив соленость воды и восстановив рыбный промысел. Перед вами стоит задача принять стратегическое решение о Фазе II восстановления водной чаши.</p>
<div class="p-3 bg-cyan-950/30 border border-cyan-800/40 rounded-xl text-xs text-cyan-300">
<strong>MBA-вызов:</strong> Какое технико-экономическое решение максимизирует показатели ESG, уложившись в жесткие рамки государственного бюджета и трансграничных лимитов водопользования?
</div>
</div>
</div>
<!-- Charts (Salinity and Fish) -->
<div class="lg:col-span-5 flex flex-col gap-4">
<div class="bg-[#161b22] border border-[#30363d] rounded-2xl p-4 flex-1 shadow-lg">
<h4 class="text-xs font-bold text-gray-400 uppercase tracking-widest mb-2">Соленость Малого Арала (г/л)</h4>
<div class="h-32"><canvas id="salinityChart"></canvas></div>
</div>
<div class="bg-[#161b22] border border-[#30363d] rounded-2xl p-4 flex-1 shadow-lg">
<h4 class="text-xs font-bold text-gray-400 uppercase tracking-widest mb-2">Ежегодный улов рыбы (тыс. тонн)</h4>
<div class="h-32"><canvas id="fishChart"></canvas></div>
</div>
</div>
</div>
<!-- МЕДИАРЕАКТИВНЫЙ БЛОК: Видео и Реалистичные фото -->
<div class="grid grid-cols-1 lg:grid-cols-12 gap-8 bg-[#161b22] border border-[#30363d] rounded-2xl p-6 shadow-xl">
<!-- Левая колонка: Видеоролик (6 cols) -->
<div class="lg:col-span-6 space-y-4">
<h3 class="text-base font-bold text-white flex items-center gap-2 text-cyan-400">
<svg class="w-5 h-5 text-cyan-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
Документальный видеоархив
</h3>
<div class="relative w-full aspect-video rounded-xl overflow-hidden border border-[#30363d] bg-black group shadow-lg">
<!-- Превью слой: теперь при клике видео проигрывается прямо в симуляторе -->
<div id="video-preview-overlay" class="absolute inset-0 z-10 bg-zinc-900/95 flex flex-col items-center justify-center p-6 text-center cursor-pointer hover:bg-zinc-950/98 transition-all" onclick="loadIframeDirectly()">
<div class="w-16 h-16 rounded-full bg-red-600/20 border-2 border-red-500 flex items-center justify-center text-red-500 mb-4 group-hover:scale-110 transition-transform">
<svg class="w-8 h-8 fill-current" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"></path></svg>
</div>
<h4 class="text-sm font-bold text-white mb-2">Нажмите для воспроизведения</h4>
<p class="text-xs text-gray-400 max-w-sm mb-4">Видео запустится без звука для обхода блокировок браузера. Вы сможете легко включить звук в самом плеере.</p>
<button onclick="event.stopPropagation(); window.open('https://www.youtube.com/embed/B802x9T3m9A?si=TuxlrA4TZ9ZFkohA', '_blank');" class="text-xs px-4 py-2 bg-red-600 hover:bg-red-500 text-white font-bold rounded-lg transition-colors shadow-md">Открыть напрямую на YouTube ↗</button>
</div>
<iframe
id="doc-iframe"
class="absolute top-0 left-0 w-full h-full"
src="about:blank"
title="Aral Sea Documentary"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen>
</iframe>
</div>
<div class="flex justify-between items-center text-xs text-gray-400 leading-relaxed mt-1">
<span>Обзор трагедии Аральского моря.</span>
<a href="https://www.youtube.com/embed/B802x9T3m9A?si=TuxlrA4TZ9ZFkohA" target="_blank" class="text-red-400 hover:underline flex items-center gap-1 font-semibold">
Резервная ссылка YouTube ↗
</a>
</div>
</div>
<!-- Правая колонка: Реалистичное фото из Google Drive (6 cols) -->
<div class="lg:col-span-6 space-y-4">
<h3 class="text-base font-bold text-white flex items-center gap-2 text-rose-400">
<svg class="w-5 h-5 text-rose-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
Исторический снимок трагедии
</h3>
<div class="group">
<div class="aspect-video w-full rounded-xl overflow-hidden border border-[#30363d] bg-zinc-950 relative shadow-md">
<!-- Использование прямого CDN Google картинок (lh3) со встроенным скриптом исправления при ошибках -->
<img id="drive-historical-img"
src="https://lh3.googleusercontent.com/d/1AIk8DUA1Fa-NHM6xyit6QcLk7hFovgof"
alt="Документальный снимок трагедии Аральского моря"
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
onerror="handleDriveImageError(this)">
</div>
<span class="text-[10px] text-gray-400 block text-center font-medium mt-2">Архивный снимок бассейна Аральского моря</span>
</div>
<p class="text-xs text-gray-400 leading-relaxed">
Документальный снимок из исследовательского архива, наглядно демонстрирующий изменения береговой линии и тяжелые последствия высыхания некогда глубоководного водоема.
</p>
</div>
</div>
<!-- PHOTO HISTORICAL TIMELINE BLOCK (Landsat / NASA Satellites) -->
<div class="bg-[#161b22] border border-[#30363d] rounded-2xl p-6 space-y-4 shadow-xl">
<h3 class="text-lg font-bold text-white flex items-center gap-2 text-orange-400">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 002 2h1.5A1.5 1.5 0 0018 10.5V10a2 2 0 012-2h.5m-14.3 11.3A9.002 9.002 0 0120.49 9H18a2 2 0 00-2 2v3a2 2 0 002 2h2A9 9 0 015.67 19.8z"></path></svg>
Динамика высыхания Аральского моря (Спутниковые снимки 1977 — 2020 гг.)
</h3>
<p class="text-xs text-gray-400">Сравнительная хроника сокращения площади водного зеркала на основе снимков космической программы NASA Landsat. Нажмите на любой год для детального анализа.</p>
<div class="grid grid-cols-2 md:grid-cols-6 gap-4 pt-2">
<!-- 1977 -->
<div class="bg-black/40 border border-[#30363d] rounded-xl p-3 text-center space-y-2 group hover:border-cyan-500 transition-all cursor-pointer shadow" onclick="showYearDetail(1977, '1977: Площадь зеркала ~55,000 км². Единый глубокий бассейн с высокой биопродуктивностью и развитым судоходством.')">
<span class="text-sm font-black text-white block group-hover:text-cyan-400">1977</span>
<div class="aspect-square w-full rounded-lg bg-zinc-950 overflow-hidden relative flex items-center justify-center border border-zinc-800">
<img src="https://upload.wikimedia.org/wikipedia/commons/4/41/Aral_Sea_1977.jpg" alt="Aral Sea 1977" class="w-full h-full object-cover group-hover:scale-105 transition-transform" onerror="showFallbackMap(this, 1977)">
</div>
<span class="text-[10px] text-gray-500 block">55,000 км²</span>
</div>
<!-- 1987 -->
<div class="bg-black/40 border border-[#30363d] rounded-xl p-3 text-center space-y-2 group hover:border-cyan-500 transition-all cursor-pointer shadow" onclick="showYearDetail(1987, '1987: Площадь ~40,000 км². Начало разделения на Северное (Малый Арал) и Южное (Большой Арал) моря.')">
<span class="text-sm font-black text-white block group-hover:text-cyan-400">1987</span>
<div class="aspect-square w-full rounded-lg bg-zinc-950 overflow-hidden relative flex items-center justify-center border border-zinc-800">
<img src="https://upload.wikimedia.org/wikipedia/commons/c/ca/Aral_Sea_1987.jpg" alt="Aral Sea 1987" class="w-full h-full object-cover group-hover:scale-105 transition-transform" onerror="showFallbackMap(this, 1987)">
</div>
<span class="text-[10px] text-gray-500 block">40,000 км²</span>
</div>
<!-- 1998 -->
<div class="bg-black/40 border border-[#30363d] rounded-xl p-3 text-center space-y-2 group hover:border-cyan-500 transition-all cursor-pointer shadow" onclick="showYearDetail(1998, '1998: Площадь ~28,000 км². Полное разделение бассейнов, резкое нарастание солености, прекращение рыбного промысла.')">
<span class="text-sm font-black text-white block group-hover:text-cyan-400">1998</span>
<div class="aspect-square w-full rounded-lg bg-zinc-950 overflow-hidden relative flex items-center justify-center border border-zinc-800">
<img src="https://upload.wikimedia.org/wikipedia/commons/e/ee/Aral_Sea_1998.jpg" alt="Aral Sea 1998" class="w-full h-full object-cover group-hover:scale-105 transition-transform" onerror="showFallbackMap(this, 1998)">
</div>
<span class="text-[10px] text-gray-500 block">28,000 км²</span>
</div>
<!-- 2006 -->
<div class="bg-black/40 border border-[#30363d] rounded-xl p-3 text-center space-y-2 group hover:border-cyan-500 transition-all cursor-pointer shadow" onclick="showYearDetail(2006, '2006: Стабилизация Малого Арала на севере благодаря Кокаральской плотине. Южный Арал распадается на Восточную и Западную чаши.')">
<span class="text-sm font-black text-white block group-hover:text-cyan-400">2006</span>
<div class="aspect-square w-full rounded-lg bg-zinc-950 overflow-hidden relative flex items-center justify-center border border-zinc-800">
<img src="https://upload.wikimedia.org/wikipedia/commons/2/27/AralSea-L7-2006-08-25.jpg" alt="Aral Sea 2006" class="w-full h-full object-cover group-hover:scale-105 transition-transform" onerror="showFallbackMap(this, 2006)">
</div>
<span class="text-[10px] text-emerald-400 block">Кокаральская дамба</span>
</div>
<!-- 2010 -->
<div class="bg-black/40 border border-[#30363d] rounded-xl p-3 text-center space-y-2 group hover:border-cyan-500 transition-all cursor-pointer shadow" onclick="showYearDetail(2010, '2010: Площадь Южного Арала упала до критического минимума. Восточная часть практически полностью пересохла.')">
<span class="text-sm font-black text-white block group-hover:text-cyan-400">2010</span>
<div class="aspect-square w-full rounded-lg bg-zinc-950 overflow-hidden relative flex items-center justify-center border border-zinc-800">
<img src="https://upload.wikimedia.org/wikipedia/commons/1/1d/Aral_Sea_2010.jpg" alt="Aral Sea 2010" class="w-full h-full object-cover group-hover:scale-105 transition-transform" onerror="showFallbackMap(this, 2010)">
</div>
<span class="text-[10px] text-rose-500 block">Пустыня Аралкум</span>
</div>
<!-- 2020 -->
<div class="bg-black/40 border border-[#30363d] rounded-xl p-3 text-center space-y-2 group hover:border-cyan-500 transition-all cursor-pointer shadow" onclick="showYearDetail(2020, '2020: Лишь узкая полоса глубоководного Западного моря уцелела на юге. Малый Арал на севере стабилен и держит проектную высоту.')">
<span class="text-sm font-black text-white block group-hover:text-cyan-400">2020</span>
<div class="aspect-square w-full rounded-lg bg-zinc-950 overflow-hidden relative flex items-center justify-center border border-zinc-800">
<img src="https://upload.wikimedia.org/wikipedia/commons/b/b5/Aral_Sea_August_2020.jpg" alt="Aral Sea 2020" class="w-full h-full object-cover group-hover:scale-105 transition-transform" onerror="showFallbackMap(this, 2020)">
</div>
<span class="text-[10px] text-gray-500 block"><10% объема</span>
</div>
</div>
<!-- Interactive Satellite detail panel -->
<div id="satellite-detail-box" class="p-3.5 bg-zinc-900/60 border border-[#30363d] rounded-xl text-xs text-cyan-300 font-mono transition-all">
💡 Кликните по любому кадру хроники для интерактивного анализа высыхания чаши.
</div>
</div>
<!-- 3 Project Cards for Selection -->
<div class="space-y-4">
<h3 class="text-lg font-bold text-white tracking-wide">Доступные инвестиционные сценарии</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- Scenario A -->
<div id="card-A" onclick="selectScenario('A')" class="relative bg-[#161b22] border-2 border-zinc-700/60 rounded-2xl p-6 cursor-pointer hover:scale-[1.01] transition-all duration-300 neon-border-cyan flex flex-col justify-between group shadow-lg">
<div class="space-y-4">
<div class="flex justify-between items-center">
<span class="px-2.5 py-1 bg-cyan-950 border border-cyan-800 text-cyan-300 rounded text-[10px] font-bold uppercase tracking-wider">Сценарий A</span>
<div class="w-5 h-5 rounded-full border-2 border-gray-500 flex items-center justify-center" id="checkbox-A">
<div class="w-2.5 h-2.5 rounded-full bg-cyan-400 hidden"></div>
</div>
</div>
<h4 class="text-lg font-bold text-white group-hover:text-cyan-400 transition-colors">Комплексная регенерация с ИИ</h4>
<p class="text-xs text-gray-300 leading-relaxed">
Двухфазное наращивание Кокаральской плотины до проектной отметки 48 метров с интеграцией интеллектуальных ИИ-контроллеров гидрошлюзов «Smart-Aral». Позволяет аккумулировать до 27-29 кубических километров воды, снизить соленость до стабильных 8-10 г/л и вернуть воду на расстояние 15 км к бывшему порту Аральск. Высокотехнологичное решение с комплексной автоматизацией контроля притока Сырдарьи.
</p>
<div class="border-t border-[#30363d] pt-4 grid grid-cols-2 gap-3 text-[11px]">
<div><span class="text-gray-500 block">Бюджет:</span><span class="font-extrabold text-emerald-400">$120 млн</span></div>
<div><span class="text-gray-500 block">ESG-Рейтинг:</span><span class="font-extrabold text-cyan-400">AAA</span></div>
<div><span class="text-gray-500 block">Тех-риски:</span><span class="font-extrabold text-amber-500">Средние</span></div>
<div><span class="text-gray-500 block">Период ROI:</span><span class="font-extrabold text-white">12 лет</span></div>
</div>
</div>
</div>
<!-- Scenario B -->
<div id="card-B" onclick="selectScenario('B')" class="relative bg-[#161b22] border-2 border-zinc-700/60 rounded-2xl p-6 cursor-pointer hover:scale-[1.01] transition-all duration-300 neon-border-emerald flex flex-col justify-between group shadow-lg">
<div class="space-y-4">
<div class="flex justify-between items-center">
<span class="px-2.5 py-1 bg-emerald-950 border border-emerald-800 text-emerald-300 rounded text-[10px] font-bold uppercase tracking-wider">Сценарий B</span>
<div class="w-5 h-5 rounded-full border-2 border-gray-500 flex items-center justify-center" id="checkbox-B">
<div class="w-2.5 h-2.5 rounded-full bg-emerald-400 hidden"></div>
</div>
</div>
<h4 class="text-lg font-bold text-white group-hover:text-emerald-400 transition-colors">Управляемый оазис</h4>
<p class="text-xs text-gray-300 leading-relaxed">
Строительство глубокого подводящего обводного канала от устья Сырдарьи напрямую в залив Сарышыганак для адресного наполнения бассейна вблизи города Аральск. Позволяет создать локальный жизнеспособный микроэкологический оазис и быстро восстановить рабочие места в рыбохозяйственном секторе Аральска при умеренном бюджете в $70 млн. Фокусированное инфраструктурное решение с минимальным трансграничным сопротивлением.
</p>
<div class="border-t border-[#30363d] pt-4 grid grid-cols-2 gap-3 text-[11px]">
<div><span class="text-gray-500 block">Бюджет:</span><span class="font-extrabold text-emerald-400">$70 млн</span></div>
<div><span class="text-gray-500 block">ESG-Рейтинг:</span><span class="font-extrabold text-emerald-400">AA</span></div>
<div><span class="text-gray-500 block">Тех-риски:</span><span class="font-extrabold text-emerald-400">Низкие</span></div>
<div><span class="text-gray-500 block">Период ROI:</span><span class="font-extrabold text-white">8 лет</span></div>
</div>
</div>
</div>
<!-- Scenario C -->
<div id="card-C" onclick="selectScenario('C')" class="relative bg-[#161b22] border-2 border-zinc-700/60 rounded-2xl p-6 cursor-pointer hover:scale-[1.01] transition-all duration-300 neon-border-rose flex flex-col justify-between group shadow-lg">
<div class="space-y-4">
<div class="flex justify-between items-center">
<span class="px-2.5 py-1 bg-rose-950 border border-rose-800 text-rose-300 rounded text-[10px] font-bold uppercase tracking-wider">Сценарий C</span>
<div class="w-5 h-5 rounded-full border-2 border-gray-500 flex items-center justify-center" id="checkbox-C">
<div class="w-2.5 h-2.5 rounded-full bg-rose-400 hidden"></div>
</div>
</div>
<h4 class="text-lg font-bold text-white group-hover:text-rose-400 transition-colors">Локальный заслон</h4>
<p class="text-xs text-gray-300 leading-relaxed">
Укрепление существующего тела Кокаральской плотины на текущем уровне 42 метра без дополнительного подъема воды, совмещенное с масштабной фитомелиорацией осушенного дна (массовая посадка черного и белого саксаула на площади более 150 000 га). Бюджетный сценарий ($30 млн), направленный исключительно на сдерживание пылевых бурь, снижение токсичного солевого выноса Аралкума и локальную социальную поддержку населения.
</p>
<div class="border-t border-[#30363d] pt-4 grid grid-cols-2 gap-3 text-[11px]">
<div><span class="text-gray-500 block">Бюджет:</span><span class="font-extrabold text-emerald-400">$30 млн</span></div>
<div><span class="text-gray-500 block">ESG-Рейтинг:</span><span class="font-extrabold text-rose-400">B</span></div>
<div><span class="text-gray-500 block">Тех-риски:</span><span class="font-extrabold text-rose-400">Высокие</span></div>
<div><span class="text-gray-500 block">Период ROI:</span><span class="font-extrabold text-white">5 лет</span></div>
</div>
</div>
</div>
</div>
</div>
<!-- AI Insight Sandbox -->
<div id="ai-sandbox-step1" class="hidden bg-[#161b22] border border-cyan-800/50 rounded-2xl p-6 space-y-4 shadow-xl">
<div class="flex justify-between items-center border-b border-[#30363d] pb-3">
<h4 class="text-sm font-bold text-cyan-400 flex items-center gap-2">
<svg class="w-5 h-5 text-cyan-400 animate-spin-slow" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
Экспертиза ИИ-консультанта Gemini
</h4>
<button onclick="runStep1AI()" class="px-4 py-2 bg-cyan-600 hover:bg-cyan-500 text-black text-xs font-bold rounded-lg transition-all shadow-md shadow-cyan-950">Запустить Экспертизу</button>
</div>
<div id="ai-step1-output" class="text-xs text-gray-300 leading-relaxed font-mono whitespace-pre-line min-h-[50px] italic">Выберите проект и нажмите «Запустить Экспертизу» для получения детальной стратегической оценки инвестиционных рисков...</div>
</div>
<!-- Trigger Button -->
<div class="flex justify-end pt-4">
<button id="btn-step-1" onclick="unlockStep2()" class="px-6 py-3 bg-[#f97316] hover:bg-orange-500 text-black font-extrabold rounded-xl shadow-lg transition-all duration-200">
Подтвердить изучение кейса
</button>
</div>
</section>
<!-- STEP 2: INTERACTIVE QUIZ (GRID LAYOUT) -->
<section id="step-2" class="space-y-8 hidden">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 border-b border-[#30363d] pb-4">
<div class="flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-[#f97316] text-black font-extrabold text-xl flex items-center justify-center pulse-step">2</div>
<div>
<span class="text-xs font-black text-emerald-400 tracking-widest uppercase">Шаг 2. Оценка стратегических знаний</span>
<h1 class="text-3xl font-black text-white tracking-tight">Сертификационный MBA-Тест</h1>
</div>
</div>
<!-- Step Coin Badge -->
<div class="flex items-center gap-2 bg-amber-950/40 border border-amber-500/30 px-3 py-1.5 rounded-full text-xs text-amber-400 font-extrabold select-none self-start sm:self-center">
<svg class="w-4 h-4 text-amber-500 animate-[pulse_2s_infinite]" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="46" fill="url(#gold-gradient-3d)" stroke="#d97706" stroke-width="8"/>
<text x="50" y="65" font-weight="900" font-size="50" fill="#78350f" text-anchor="middle">★</text>
</svg>
<span id="step-iq-val-2">0 / 10 IQ</span>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-12 gap-8">
<!-- Left Column: Quiz Interaction -->
<div class="lg:col-span-8 bg-[#161b22] border border-[#30363d] rounded-2xl p-6 space-y-6 shadow-xl relative min-h-[400px]">
<div class="flex justify-between items-center border-b border-[#30363d] pb-3">
<span class="text-xs font-bold text-gray-400 uppercase tracking-widest">Вопрос <span id="quiz-idx">1</span> из 10</span>
<span id="quiz-correct-counter" class="text-xs font-mono text-emerald-400">Верно: 0 | Баллы: 0</span>
</div>
<div id="quiz-box" class="space-y-6">
<h3 id="quiz-question" class="text-lg font-bold text-white leading-snug">Загрузка вопроса...</h3>
<div id="quiz-options" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- Option buttons injected via JS -->
</div>
</div>
</div>
<!-- Right Column: Vertical Progress Gauge -->
<div class="lg:col-span-4 bg-[#161b22] border border-[#30363d] rounded-2xl p-6 flex flex-col justify-between shadow-xl">
<div class="space-y-4">
<h4 class="text-xs font-bold text-gray-400 uppercase tracking-widest text-center">Прогресс освоения (Баллы)</h4>
<p class="text-[11px] text-gray-500 text-center">Для завершения теста ответьте на все 10 вопросов. Целевой показатель: >70 баллов.</p>
<div class="relative h-64 w-full flex justify-center items-center">
<canvas id="quizProgressChart"></canvas>
</div>
</div>
<div class="text-center pt-4 border-t border-[#30363d]">
<span id="quiz-completion-text" class="text-xs font-mono text-amber-500 font-bold">Выполните тест</span>
</div>
</div>
</div>
<!-- Trigger Button -->
<div class="flex justify-end pt-4" id="quiz-trigger-container" style="display: none;">
<button id="btn-step-2" onclick="unlockStep3()" class="px-6 py-3 bg-[#f97316] hover:bg-orange-500 text-black font-extrabold rounded-xl shadow-lg transition-all duration-200">
Приступить к SWOT-анализу
</button>
</div>
</section>
<!-- STEP 3: SWOT-ANALYSIS -->
<section id="step-3" class="space-y-8 hidden">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 border-b border-[#30363d] pb-4">
<div class="flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-[#f97316] text-black font-extrabold text-xl flex items-center justify-center pulse-step">3</div>
<div>
<span class="text-xs font-black text-amber-400 tracking-widest uppercase">Шаг 3. SWOT-Анализ</span>
<h1 class="text-3xl font-black text-white tracking-tight">Стратегическая матрица проекта</h1>
</div>
</div>
<!-- Step Coin Badge -->
<div class="flex items-center gap-2 bg-amber-950/40 border border-amber-500/30 px-3 py-1.5 rounded-full text-xs text-amber-400 font-extrabold select-none self-start sm:self-center">
<svg class="w-4 h-4 text-amber-500 animate-[pulse_2s_infinite]" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="46" fill="url(#gold-gradient-3d)" stroke="#d97706" stroke-width="8"/>
<text x="50" y="65" font-weight="900" font-size="50" fill="#78350f" text-anchor="middle">★</text>
</svg>
<span id="step-iq-val-3">0 / 10 IQ</span>
</div>
</div>
<div class="p-5 bg-zinc-900/60 border border-[#30363d] rounded-2xl space-y-3">
<h3 class="text-base font-bold text-white">Интерактивная доска SWOT-моделирования</h3>
<p class="text-xs text-gray-300">Распределите стратегические тезисы по соответствующим блокам. Кликните по тезису в библиотеке рекомендаций, чтобы добавить его в матрицу, или запишите свои мысли непосредственно в карточки.</p>
</div>
<!-- Dynamic SWOT matrix interactive grid -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Strengths -->
<div class="bg-emerald-950/20 border-2 border-emerald-900/30 rounded-2xl p-5 space-y-3 shadow-lg">
<h4 class="text-sm font-bold text-emerald-400 flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-emerald-500"></span> S (Сильные стороны)
</h4>
<textarea id="swot-s" class="w-full h-32 bg-black/40 border border-[#30363d] rounded-xl p-3 text-xs text-white placeholder-gray-600 focus:outline-none focus:border-emerald-500" placeholder="Запишите преимущества..."></textarea>
</div>
<!-- Weaknesses -->
<div class="bg-rose-950/20 border-2 border-rose-900/30 rounded-2xl p-5 space-y-3 shadow-lg">
<h4 class="text-sm font-bold text-rose-400 flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-rose-500"></span> W (Слабые стороны)
</h4>
<textarea id="swot-w" class="w-full h-32 bg-black/40 border border-[#30363d] rounded-xl p-3 text-xs text-white placeholder-gray-600 focus:outline-none focus:border-rose-500" placeholder="Запишите слабые места..."></textarea>
</div>
<!-- Opportunities -->
<div class="bg-cyan-950/20 border-2 border-cyan-900/30 rounded-2xl p-5 space-y-3 shadow-lg">
<h4 class="text-sm font-bold text-cyan-400 flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-cyan-500"></span> O (Возможности)
</h4>
<textarea id="swot-o" class="w-full h-32 bg-black/40 border border-[#30363d] rounded-xl p-3 text-xs text-white placeholder-gray-600 focus:outline-none focus:border-cyan-500" placeholder="Запишите точки роста..."></textarea>
</div>
<!-- Threats -->
<div class="bg-amber-950/20 border-2 border-amber-900/30 rounded-2xl p-5 space-y-3 shadow-lg">
<h4 class="text-sm font-bold text-amber-400 flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-amber-500"></span> T (Угрозы)
</h4>
<textarea id="swot-t" class="w-full h-32 bg-black/40 border border-[#30363d] rounded-xl p-3 text-xs text-white placeholder-gray-600 focus:outline-none focus:border-amber-500" placeholder="Запишите риски..."></textarea>
</div>
</div>
<!-- Library of Suggestions -->
<div class="bg-[#161b22] border border-[#30363d] rounded-2xl p-5 space-y-3 shadow-xl">
<span class="text-xs font-bold text-gray-400 uppercase tracking-widest">Библиотека strategic тезисов для добавления:</span>
<div id="swot-suggestions-deck" class="flex flex-wrap gap-2 pt-2">
<!-- Suggested pills generated dynamically -->
</div>
</div>
<!-- AI SWOT Audit Section (Self-fill assessment instead of auto-generation) -->
<div class="bg-[#161b22] border border-cyan-800/40 rounded-2xl p-6 space-y-6 shadow-xl">
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 border-b border-[#30363d] pb-3">
<div>
<h4 class="text-sm font-bold text-cyan-400 flex items-center gap-2">
<svg class="w-5 h-5 text-cyan-400 animate-pulse" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
Проверить и Оценить мою SWOT-матрицу (Gemini AI)
</h4>
<p class="text-[11px] text-gray-400 mt-1">ИИ не заполняет ваши поля. Он проанализирует ваши тезисы, сопоставит их с эталоном и выставит заслуженную оценку IQ.</p>
</div>
<button onclick="evaluateSWOT()" class="px-5 py-2.5 bg-cyan-600 hover:bg-cyan-500 text-black text-xs font-black rounded-lg transition-all shadow-md">Проверить мою матрицу</button>
</div>
<!-- Live SWOT evaluation display -->
<div id="swot-audit-wrapper" class="hidden space-y-6 animate-fade-in">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left: critique from AI -->
<div class="p-4 bg-zinc-900 border border-zinc-800 rounded-xl space-y-2">
<h5 class="text-xs font-bold text-cyan-400 uppercase tracking-wider">Критика и Фидбек ИИ-аудитора:</h5>
<div id="ai-swot-output" class="text-xs text-gray-300 leading-relaxed font-mono whitespace-pre-wrap italic">Загрузка аудита...</div>
</div>
<!-- Right: reference model (Эталонные тезисы) -->
<div class="p-4 bg-amber-950/10 border border-amber-900/30 rounded-xl space-y-3">
<h5 class="text-xs font-bold text-amber-400 uppercase tracking-wider">Эталонное решение для выбранного сценария:</h5>
<div id="swot-ideal-grid" class="grid grid-cols-2 gap-3 text-[10px] text-gray-300">
<!-- Populated dynamically by script based on selected scenario -->
</div>
</div>
</div>
</div>
</div>
<!-- Actions Deck -->
<div class="flex flex-col sm:flex-row justify-between items-center gap-4 pt-4">
<a href="https://www.canva.com/" target="_blank" class="w-full sm:w-auto px-6 py-3 bg-[#1e293b] hover:bg-[#334155] border border-[#475569] text-white font-bold rounded-xl text-center text-sm shadow-md transition-all">
Открыть шаблон в Canva →
</a>
<button onclick="unlockStep4()" class="w-full sm:w-auto px-6 py-3 bg-[#f97316] hover:bg-orange-500 text-black font-extrabold rounded-xl shadow-lg transition-all">
Подтвердить и зафиксировать SWOT
</button>
</div>
</section>
<!-- STEP 4: DECISION APPROVAL -->
<section id="step-4" class="space-y-8 hidden">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 border-b border-[#30363d] pb-4">
<div class="flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-[#f97316] text-black font-extrabold text-xl flex items-center justify-center pulse-step">4</div>
<div>
<span class="text-xs font-black text-rose-400 tracking-widest uppercase">Шаг 4. Утверждение Решения</span>
<h1 class="text-3xl font-black text-white tracking-tight">Электронный паспорт стратегии</h1>
</div>
</div>
<!-- Step Coin Badge -->
<div class="flex items-center gap-2 bg-amber-950/40 border border-amber-500/30 px-3 py-1.5 rounded-full text-xs text-amber-400 font-extrabold select-none self-start sm:self-center">
<svg class="w-4 h-4 text-amber-500 animate-[pulse_2s_infinite]" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="46" fill="url(#gold-gradient-3d)" stroke="#d97706" stroke-width="8"/>
<text x="50" y="65" font-weight="900" font-size="50" fill="#78350f" text-anchor="middle">★</text>
</svg>
<span id="step-iq-val-4">0 / 10 IQ</span>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-12 gap-8">
<!-- Parameters form -->
<div class="lg:col-span-7 bg-[#161b22] border border-[#30363d] rounded-2xl p-6 space-y-6 shadow-xl">
<h3 class="text-lg font-bold text-white flex items-center gap-2 text-rose-400">
Параметры межведомственной декларации
</h3>
<div class="space-y-4">
<div>
<label class="block text-xs font-bold text-gray-400 uppercase tracking-widest mb-2">Направление приоритетного бюджетирования:</label>
<select id="doc-focus" class="w-full bg-black border border-[#30363d] rounded-xl px-4 py-2.5 text-xs text-white focus:outline-none focus:border-rose-500">
<option value="Ecology">Абсолютный приоритет экологии (снижение солености, посадки)</option>
<option value="Economy">Коммерческий баланс (рыбное производство, туристический кластер)</option>
<option value="Tech">Технологический вектор (автоматизированные водохранилища, ИИ)</option>
</select>
</div>
<div>
<label class="block text-xs font-bold text-gray-400 uppercase tracking-widest mb-2">Основной вектор работы со стейкхолдерами:</label>
<select id="doc-negotiation" class="w-full bg-black border border-[#30363d] rounded-xl px-4 py-2.5 text-xs text-white focus:outline-none focus:border-rose-500">
<option value="Transboundary">Трансграничное правовое соглашение о лимитах (Киргизия/Узбекистан)</option>
<option value="Investors">Частно-государственное партнерство (Зеленые облигации ООН)</option>
<option value="Community">Социальный блок (поддержка населения Приаралья, льготы)</option>
</select>
</div>
<div>
<label class="block text-xs font-bold text-gray-400 uppercase tracking-widest mb-2">Минимизация strategic рисков (План Б):</label>
<textarea id="doc-mitigation" class="w-full h-24 bg-black border border-[#30363d] rounded-xl p-3 text-xs text-white placeholder-gray-600 focus:outline-none focus:border-rose-500" placeholder="Опишите, как вы будете действовать в случае критического заиливания или падения притока реки..."></textarea>
</div>
</div>
</div>
<!-- Interactive Signature Block -->
<div class="lg:col-span-5 bg-[#161b22] border border-[#30363d] rounded-2xl p-6 flex flex-col justify-between shadow-xl">
<div class="space-y-4">
<h4 class="text-xs font-bold text-gray-400 uppercase tracking-widest text-center">Визирование Декларации (Цифровая подпись)</h4>
<p class="text-[11px] text-gray-500 text-center">Используйте манипулятор мыши или тачскрин для создания графической подписи.</p>
<div class="relative w-full aspect-[4/3] bg-zinc-950/80 border-2 border-dashed border-[#30363d] rounded-xl overflow-hidden cursor-crosshair">
<canvas id="signaturePad" class="w-full h-full block"></canvas>
<button onclick="clearSignature()" class="absolute bottom-2 right-2 px-2.5 py-1 bg-zinc-800 hover:bg-zinc-700 text-gray-400 hover:text-white rounded text-[10px] font-mono transition-all">Сбросить</button>
</div>
</div>
<div class="pt-4 border-t border-[#30363d] text-center">
<span id="signature-status" class="text-xs font-mono text-red-400 font-bold">Ожидает визирования</span>
</div>
</div>
</div>
<!-- Navigation Buttons -->
<div class="flex flex-col sm:flex-row justify-between items-center gap-4 pt-4">
<a href="https://forms.gle/" target="_blank" class="w-full sm:w-auto px-6 py-3 bg-[#1e293b] hover:bg-[#334155] border border-[#475569] text-white font-bold rounded-xl text-center text-sm shadow-md transition-all">
Перейти к Google Form →
</a>
<button onclick="unlockStep5()" class="w-full sm:w-auto px-6 py-3 bg-[#f97316] hover:bg-orange-500 text-black font-extrabold rounded-xl shadow-lg transition-all">
Отправить Декларацию
</button>
</div>
</section>
<!-- STEP 5: AI-SYNTHESIS AND PODCAST -->
<section id="step-5" class="space-y-8 hidden">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 border-b border-[#30363d] pb-4">
<div class="flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-[#f97316] text-black font-extrabold text-xl flex items-center justify-center pulse-step">5</div>
<div>
<span class="text-xs font-black text-purple-400 tracking-widest uppercase">Шаг 5. AI-Синтез в NotebookLM</span>
<h1 class="text-3xl font-black text-white tracking-tight">Медиа-Генерация Инфоповода</h1>
</div>
</div>
<!-- Step Coin Badge -->
<div class="flex items-center gap-2 bg-amber-950/40 border border-amber-500/30 px-3 py-1.5 rounded-full text-xs text-amber-400 font-extrabold select-none self-start sm:self-center">
<svg class="w-4 h-4 text-amber-500 animate-[pulse_2s_infinite]" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="46" fill="url(#gold-gradient-3d)" stroke="#d97706" stroke-width="8"/>
<text x="50" y="65" font-weight="900" font-size="50" fill="#78350f" text-anchor="middle">★</text>
</svg>
<span id="step-iq-val-5">0 / 10 IQ</span>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-12 gap-8">
<!-- Instructions and Copy Prompt -->
<div class="lg:col-span-6 bg-[#161b22] border border-[#30363d] rounded-2xl p-6 space-y-6 shadow-xl">
<h3 class="text-lg font-bold text-white flex items-center gap-2 text-purple-400">
Генератор Промпта для Audio Overview
</h3>
<p class="text-xs text-gray-300 leading-relaxed">
Для создания профессионального медиа-подкаста в Google NotebookLM скопируйте специально спроектированный ИИ-бриф. Он интегрирует все ваши ранее выбранные решения, SWOT-анализ и результаты сертификации.
</p>
<div class="relative bg-zinc-950 border border-[#30363d] rounded-xl p-4">
<pre id="prompt-textbox" class="text-[11px] font-mono text-gray-400 whitespace-pre-wrap overflow-y-auto max-h-48 leading-relaxed">Генерирую бриф на основе ваших решений...</pre>
<button onclick="copyPromptToClipboard()" class="absolute top-2 right-2 px-3 py-1.5 bg-purple-950 hover:bg-purple-900 border border-purple-800 text-purple-300 rounded-lg text-[10px] font-bold transition-all">Копировать</button>
</div>
<div class="flex flex-col sm:flex-row gap-4">
<a href="https://notebooklm.google.com/" target="_blank" onclick="unlockStep6()" class="flex-1 px-6 py-3 bg-purple-950 hover:bg-purple-900 border border-purple-800 text-purple-300 font-bold rounded-xl text-center text-xs shadow-md transition-all">
Открыть Google NotebookLM
</a>
<button onclick="unlockStep6()" class="flex-1 px-6 py-3 bg-[#f97316] hover:bg-orange-500 text-black font-extrabold rounded-xl text-xs shadow-lg transition-all">
Зафиксировать генерацию
</button>
</div>
</div>
<!-- Live Podcast Simulator Panel -->
<div class="lg:col-span-6 bg-[#161b22] border border-[#30363d] rounded-2xl p-6 flex flex-col justify-between shadow-xl">
<div class="space-y-4">
<div class="flex justify-between items-center">
<span class="text-xs font-bold text-purple-400 uppercase tracking-widest">NotebookLM Simulator</span>
<span class="px-2 py-0.5 bg-purple-950 text-purple-400 border border-purple-800 rounded text-[9px] font-mono animate-pulse">Эмуляция LIVE</span>
</div>
<div class="bg-black/40 rounded-xl p-4 border border-[#30363d] space-y-4">
<!-- Visualizer waves canvas -->
<div class="h-16 w-full bg-zinc-950 rounded-lg overflow-hidden relative">
<canvas id="waveformCanvas" class="w-full h-full block"></canvas>
</div>
<!-- Subtitle player -->
<div class="space-y-2 text-center">
<span id="podcast-host" class="text-[10px] font-bold text-purple-400 uppercase tracking-widest block">Хост 1 (Alex)</span>
<p id="podcast-subtitle" class="text-xs text-gray-300 italic min-h-[40px] leading-relaxed">"Нажмите «Прослушать сводку», чтобы ИИ синтезировал подкаст по вашему проекту..."</p>
</div>
</div>
</div>
<div class="flex gap-2 pt-4">
<button id="btn-play-podcast" onclick="togglePodcastPlayback()" class="flex-1 px-4 py-2.5 bg-emerald-600 hover:bg-emerald-500 text-black text-xs font-bold rounded-lg transition-all shadow-md">
Прослушать сводку
</button>
</div>
</div>
</div>
</section>
<!-- STEP 6: PROJECT PITCH & FINAL BOARDROOM -->
<section id="step-6" class="space-y-8 hidden">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 border-b border-[#30363d] pb-4">
<div class="flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-[#f97316] text-black font-extrabold text-xl flex items-center justify-center pulse-step">6</div>
<div>
<span class="text-xs font-black text-amber-500 tracking-widest uppercase">Шаг 6. Защита перед инвесторами</span>
<h1 class="text-3xl font-black text-white tracking-tight">Защита проекта в Совете Директоров</h1>
</div>
</div>
<!-- Step Coin Badge -->
<div class="flex items-center gap-2 bg-amber-950/40 border border-amber-500/30 px-3 py-1.5 rounded-full text-xs text-amber-400 font-extrabold select-none self-start sm:self-center">
<svg class="w-4 h-4 text-amber-500 animate-[pulse_2s_infinite]" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="46" fill="url(#gold-gradient-3d)" stroke="#d97706" stroke-width="8"/>
<text x="50" y="65" font-weight="900" font-size="50" fill="#78350f" text-anchor="middle">★</text>
</svg>
<span id="step-iq-val-6">0 / 10 IQ</span>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-12 gap-8">
<!-- Dynamic Approval Rating Gauges -->
<div class="lg:col-span-5 bg-[#161b22] border border-[#30363d] rounded-2xl p-6 space-y-6 shadow-xl flex flex-col justify-between">
<div class="space-y-4">
<h3 class="text-base font-bold text-white text-center">Индекс одобрения стейкхолдеров</h3>
<p class="text-[11px] text-gray-500 text-center">Расчет производится по формуле соответствия параметров ESG, улова и бюджетного баланса.</p>
<div class="space-y-3">
<!-- Gauge 1 -->
<div>
<div class="flex justify-between text-xs font-mono mb-1">
<span class="text-gray-400">Правительство и Регуляторы:</span>
<span id="rate-gov" class="text-cyan-400 font-bold">0%</span>
</div>
<div class="w-full bg-black h-2.5 rounded-full overflow-hidden border border-zinc-800">
<div id="bar-gov" class="bg-cyan-500 h-full transition-all duration-1000" style="width: 0%;"></div>
</div>
</div>
<!-- Gauge 2 -->
<div>
<div class="flex justify-between text-xs font-mono mb-1">
<span class="text-gray-400">Местное Сообщество (Рыбаки):</span>
<span id="rate-local" class="text-emerald-400 font-bold">0%</span>
</div>
<div class="w-full bg-black h-2.5 rounded-full overflow-hidden border border-zinc-800">
<div id="bar-local" class="bg-emerald-500 h-full transition-all duration-1000" style="width: 0%;"></div>
</div>
</div>
<!-- Gauge 3 -->
<div>
<div class="flex justify-between text-xs font-mono mb-1">
<span class="text-gray-400">Международные Инвесторы (ООН):</span>
<span id="rate-invest" class="text-purple-400 font-bold">0%</span>
</div>
<div class="w-full bg-black h-2.5 rounded-full overflow-hidden border border-zinc-800">
<div id="bar-invest" class="bg-purple-500 h-full transition-all duration-1000" style="width: 0%;"></div>
</div>
</div>
<!-- Gauge 4 -->
<div>
<div class="flex justify-between text-xs font-mono mb-1">
<span class="text-gray-400">Научно-Экологический комитет:</span>
<span id="rate-eco" class="text-rose-400 font-bold">0%</span>
</div>
<div class="w-full bg-black h-2.5 rounded-full overflow-hidden border border-zinc-800">
<div id="bar-eco" class="bg-rose-500 h-full transition-all duration-1000" style="width: 0%;"></div>
</div>
</div>
</div>
</div>
<div class="pt-4 border-t border-[#30363d] text-center">
<div class="text-xs text-gray-400">Интегральный Рейтинг:</div>
<div id="rating-grade" class="text-2xl font-black text-white mt-1">ОЖИДАНИЕ</div>
</div>
</div>
<!-- Final speech and certification deck -->
<div class="lg:col-span-7 bg-[#161b22] border border-[#30363d] rounded-2xl p-6 space-y-6 shadow-xl flex flex-col justify-between">
<div class="space-y-4">
<div class="flex justify-between items-center border-b border-[#30363d] pb-3">
<h3 class="text-base font-bold text-white text-cyan-400 flex items-center gap-2">
<svg class="w-5 h-5 text-cyan-400 animate-spin-slow" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
Текст инвестиционного питча
</h3>
<button onclick="runStep6AI()" class="px-4 py-2 bg-cyan-600 hover:bg-cyan-500 text-black text-xs font-black rounded transition-all shadow-md">Сгенерировать Речь</button>
</div>
<div id="ai-step6-speech" class="text-xs text-gray-300 font-mono leading-relaxed whitespace-pre-wrap max-h-56 overflow-y-auto bg-black/40 border border-[#30363d] rounded-xl p-4 italic">Нажмите «Сгенерировать Речь» для написания кастомного питч-скрипта...</div>
</div>
<!-- Certificate layout -->
<div class="bg-zinc-950/80 border border-amber-900/30 p-4 rounded-xl flex items-center gap-4">
<div class="w-12 h-12 rounded-lg bg-amber-500/10 border border-amber-500 flex items-center justify-center font-black text-amber-500 text-lg">M</div>
<div>
<h4 class="text-xs font-bold text-white uppercase tracking-wider">Сертификат Завершения</h4>
<p class="text-[11px] text-gray-400">Вы успешно прошли все шаги инвестиционного симулятора восстановления бассейна Аральского моря.</p>
</div>
</div>
</div>
</div>
<!-- Congratulatory splash panel -->
<div class="glass-panel border-2 border-emerald-500/30 rounded-3xl p-8 text-center space-y-4 shadow-2xl relative overflow-hidden">
<div class="absolute -top-12 -left-12 w-48 h-48 bg-emerald-500/5 rounded-full filter blur-3xl"></div>
<div class="absolute -bottom-12 -right-12 w-48 h-48 bg-cyan-500/5 rounded-full filter blur-3xl"></div>
<h2 class="text-2xl md:text-3xl font-black text-white tracking-tight">Поздравляем! Симуляция завершена</h2>
<p class="text-sm text-gray-300 max-w-2xl mx-auto leading-relaxed">
Вы разработали полноценный портфель решений для ревитализации Северного Арала, защитили SWOT-позицию, сформировали бриф для медиа-генерации и сдали квалификационный экзамен. Вы готовы к реальному питчингу!
</p>
</div>
</section>
</main>
<!-- JAVASCRIPT LOGIC -->
<script>
// Global State Manager (with gamification scores included)
const state = {
currentUnlocked: 1,
selectedScenario: null,
quizScore: 0,
quizAnswers: [],
swotContent: { s: '', w: '', o: '', t: '' },
docParams: { focus: 'Ecology', negotiation: 'Transboundary', mitigation: '' },
isSigned: false,
api_key: '',
step6SpeechGenerated: false,
promptCopied: false,
swotEvaluated: false,
scores: {
step1: 0,
step2: 0,
step3: 0,
step4: 0,
step5: 0,
step6: 0
}
};
// Static configuration matrices for local dynamic engines
const SCENARIOS = {
A: {
name: "Комплексная регенерация с ИИ",
cost: "$120M",
rating: "AAA",
risk: "Средний",
roi: "12 лет",
code: "A",
desc: "Двухфазное наращивание Кокаральской плотины до проектной отметки 48 метров с интеграцией интеллектуальных ИИ-контроллеров гидрошлюзов «Smart-Aral». Позволяет аккумулировать до 27-29 кубических километров воды, снизить соленость до стабильных 8-10 г/л и вернуть воду на расстояние 15 км к бывшему порту Аральск. Высокотехнологичное решение с комплексной автоматизацией контроля притока Сырдарьи.",
idealSwot: {
s: "• Увеличение чаши Малого Арала на 250%\n• Автоматизация ИИ гидрошлюзов\n• Снижение солености до 8 г/л.",
w: "• Экстремально высокий CAPEX ($120M)\n• Сложность технического обслуживания датчиков.",
o: "• Выпуск премиальных зеленых бондов ООН\n• Глобальный PR инновации СНГ.",
t: "• Геополитические споры по Сырдарье\n• Высокая зависимость от стабильного энергоснабжения."
}
},
B: {
name: "Управляемый оазис",
cost: "$70M",
rating: "AA",
risk: "Низкий",
roi: "8 лет",
code: "B",
desc: "Строительство глубокого подводящего обводного канала от устья Сырдарьи напрямую в залив Сарышыганак для адресного наполнения бассейна вблизи города Аральск. Позволяет создать локальный жизнеспособный микроэкологический оазис и быстро восстановить рабочие места в рыбохозяйственном секторе Аральска при умеренном бюджете в $70 млн. Фокусированное инфраструктурное решение с минимальным трансграничным сопротивлением.",
idealSwot: {
s: "• Быстрая доставка воды в город Аральск\n• Меньший объем трансграничных согласований.",
w: "• Локальный оазисный эффект\n• Риск быстрого заиливания узкого канала.",
o: "• Возрождение малого порта и туризма\n• Быстрые новые рабочие места.",
t: "• Риск пересыхания при критической засухе\n• Ограниченный ESG-эффект вне зоны канала."
}
},
C: {
name: "Локальный заслон",
cost: "$30M",
rating: "B",
risk: "Высокий",
roi: "5 лет",
code: "C",
desc: "Укрепление существующего тела Кокаральской плотины на текущем уровне 42 метра без дополнительного подъема воды, совмещенное с масштабной фитомелиорацией осушенного дна (массовая посадка черного и белого саксаула на площади более 150 000 га). Бюджетный сценарий ($30 млн), направленный исключительно на сдерживание пылевых бурь, снижение токсичного солевого выноса Аралкума и локальную социальную поддержку населения.",
idealSwot: {
s: "• Самая низкая стоимость CAPEX ($30M)\n• Саксаул накрепко держит токсичную соль.",
w: "• Не возвращает судоходство\n• Не восстанавливает глубину моря.",
o: "• Углеродные кредиты (Carbon Offsets)\n• Масштабные гранты по климату от ЕС.",
t: "• Риск лесных пожаров саксаула\n• Продолжающийся отток рыбопромыслового населения."
}
}
};
// 10 professional MBA level questions
const QUIZ_QUESTIONS = [
{
q: "Какова основная техническая цель Кокаральской плотины, завершенной в 2005 году?",
options: [
"Полное осушение остатков Южного моря ради добычи газа",
"Накопление и удержание пресной воды Сырдарьи в Малом Арале",
"Генерация гидроэлектроэнергии для экспорта в Китай",
"Создание судоходного глубоководного канала в Амударью"
],
correct: 1,
points: 10
},
{
q: "Каким образом решается трансграничный конфликт водопользования по Сырдарье между верховьями и низовьями?",
options: [
"Полным запретом забора воды всеми странами в летний период",
"Квотированием стоков по межгосударственному соглашению и выплатой компенсаций",
"Переброской рек из Сибирского федерального округа",
"Тотальным переходом на импортные поставки бутилированной воды"
],
correct: 1,
points: 10
},
{
q: "Каковы основные экономические и социальные выгоды снижения солености воды в Малом Арале?",
options: [
"Рост популяции аборигенных видов рыб и возрождение рыбозаводов",
"Возможность орошения хлопчатника напрямую соленой озерной водой",
"Привлечение мировых круизных лайнеров в Аральск",
"Добыча поваренной соли методом промышленного выпаривания"
],
correct: 0,
points: 10
},
{
q: "В концепции ESG, какой экологический ущерб Аралкума является самым остым для здоровья населения?",
options: [
"Выбросы углекислого газа от гниения водорослей",
"Выдувание токсичной соляной пыли и пестицидов со дна Аралкума",
"Аномальное повышение влажности воздуха в регионе",
"Размножение инвазивных видов пресмыкающихся в пустыне"
],
correct: 1,
points: 10
},
{
q: "Каким образом посадки саксаула на сухом дне моря помогают стабилизировать климат?",
options: [
"Они привлекают тучи и вызывают проливные дожди",
"Их корневая система сдерживает песчаные дюны и снижает пыльные бури",
"Саксаул служит основным топливным ресурсом для местных ТЭЦ",
"Он поглощает 100% солей из окружающих подземных вод"
],
correct: 1,
points: 10
},
{
q: "Какой финансовый инструмент наиболее релевантен для привлечения грантов ООН под сценарий C (Саксаул)?",
options: [
"Высокорисковые венчурные кредиты",
"Рыночные углеродные офсеты и зеленые облигации (Green Bonds)",
"Эмиссия фиатных казначейских векселей",
"Обыкновенные необеспеченные банковские кредиты"
],
correct: 1,
points: 10
},
{
q: "Какой ключевой технологический риск несет сценарий А (Наращивание дамбы до 48м)?",
options: [
"Катастрофический прорыв при нештатных паводках старой основы",
"Перегрев ИИ-контроллеров из-за отсутствия интернета",
"Полное вымерзание рыбы в зимний период",
"Социальный бунт из-за переезда Аральского порта ближе"
],
correct: 0,
points: 10
},
{
q: "В чем заключается финансовое преимущество сценария B (Управляемый оазис)?",
options: [
"Он имеет самый короткий срок ROI (5 лет)",
"Он требует меньших капиталовложений (CAPEX $70M) при локальной эффективности",
"Он полностью освобождает проект от уплаты налогов в РК",
"Он гарантирует 100% компенсацию затрат за счет продажи газа"
],
correct: 1,
points: 10
},
{
q: "Что является ключевой угрозой внешней среды (Threat) для Аральской экосистемы?",
options: [
"Повышение эффективности капельного полива в сельском хозяйстве",
"Глобальное изменение климата и таяние ледников Тянь-Шаня",
"Снижение мировых цен на рыбную муку и карася",
"Отказ Всемирного банка от поддержки любых проектов в Азии"
],
correct: 1,
points: 10
},
{
q: "Какой стратегический шаг является определяющим при подготовке проекта к NotebookLM генерации?",
options: [
"Запись голосового сообщения на мобильный телефон в Аральске",
"Формирование структурированного брифа с четким распределением ролей и SWOT-матрицей",
"Закупка серверов для локального хостинга нейросетей",
"Отказ от цифровых данных в пользу печатных брошюр"
],
correct: 1,
points: 10
}
];
// Activates the iframe source inside the simulator with autoplay & mute enabled
function loadIframeDirectly() {
const overlay = document.getElementById('video-preview-overlay');
const iframe = document.getElementById('doc-iframe');
if (overlay && iframe) {
overlay.style.display = 'none';
iframe.src = "https://www.youtube.com/embed/B802x9T3m9A?autoplay=1&mute=1&enablejsapi=1";
showToast("Видео запущено во встроенном проигрывателе без ошибок!", "success");
}
}
// Keep compatibility placeholder for scroll/navigation redirect safety
function loadIframeOrRedirect() {
loadIframeDirectly();
}
// DYNAMIC IQ SCORE RECALCULATOR & UPDATER
function updateIQDisplay() {
// Recalculate each Step
state.scores.step1 = state.selectedScenario ? 10 : 0;
const correctCount = state.quizAnswers.filter(a => a.correct).length;
state.scores.step2 = correctCount; // 1 IQ per correct answer
// Step 3 is graded upon clicking 'Evaluate SWOT'
if (!state.swotEvaluated) {
state.scores.step3 = 0;
} // else stays whatever was graded by the evaluator
state.scores.step4 = state.isSigned ? 10 : 0;
state.scores.step5 = state.promptCopied ? 10 : 0;
state.scores.step6 = state.step6SpeechGenerated ? 10 : 0;
const totalIQ = Object.values(state.scores).reduce((sum, val) => sum + val, 0);
// Update UI elements
for (let i = 1; i <= 6; i++) {
const el = document.getElementById(`step-iq-val-${i}`);
if (el) {
el.innerText = `${state.scores[`step${i}`]} / 10 IQ`;
}
}
const headerDisplay = document.getElementById('total-iq-display');
if (headerDisplay) {
headerDisplay.innerText = `${totalIQ} IQ`;
}
}
// TOAST NOTIFICATION ENGINE
function showToast(message, type = 'info') {
const container = document.getElementById('toast-container');
if (!container) return;
const toast = document.createElement('div');
toast.className = "p-4 rounded-xl shadow-2xl border flex items-center gap-3 text-xs font-semibold transform translate-y-2 opacity-0 transition-all duration-300 pointer-events-auto max-w-sm glass-panel";
if (type === 'success') {
toast.classList.add('border-emerald-500/50', 'text-emerald-300');
toast.innerHTML = `<span class="w-2 h-2 rounded-full bg-emerald-500 animate-ping"></span><span>${message}</span>`;
} else if (type === 'error') {
toast.classList.add('border-rose-500/50', 'text-rose-300');
toast.innerHTML = `<span class="w-2 h-2 rounded-full bg-rose-500"></span><span>${message}</span>`;
} else {
toast.classList.add('border-cyan-500/50', 'text-cyan-300');
toast.innerHTML = `<span class="w-2 h-2 rounded-full bg-cyan-500"></span><span>${message}</span>`;
}
container.appendChild(toast);
requestAnimationFrame(() => {
toast.classList.remove('translate-y-2', 'opacity-0');
});
setTimeout(() => {
toast.classList.add('translate-y-2', 'opacity-0');
setTimeout(() => toast.remove(), 300);
}, 4000);
}
// BEAKER CANVAS WAVE RENDERERS
const waveCanvases = [];
const waveCtxs = [];
const waveHeights = [15, 32, 49, 66, 83, 100]; // Beaker target ladder percentages
let waveOffsets = [0, 0, 0, 0, 0, 0];
function initBeakerWaves() {
for (let i = 1; i <= 6; i++) {
const canvas = document.getElementById(`beaker-wave-${i}`);
if (!canvas) continue;
waveCanvases[i] = canvas;
waveCtxs[i] = canvas.getContext('2d');
canvas.width = 64;
canvas.height = 128;
}
animateWaves();
}
const beakerColors = [
{ light: '#10b981', dark: '#047857' },
{ light: '#059669', dark: '#065f46' },
{ light: '#0d9488', dark: '#115e59' },
{ light: '#06b6d4', dark: '#0e7490' },
{ light: '#0284c7', dark: '#0369a1' },
{ light: '#3b82f6', dark: '#1d4ed8' }
];
function animateWaves() {
requestAnimationFrame(animateWaves);
for (let i = 1; i <= 6; i++) {
const canvas = waveCanvases[i];
const ctx = waveCtxs[i];
if (!canvas || !ctx) continue;
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (i > state.currentUnlocked) {
continue;
}
const color = beakerColors[i - 1];
waveOffsets[i] += 0.05;
ctx.fillStyle = color.dark;
ctx.beginPath();
ctx.moveTo(0, canvas.height);
for (let x = 0; x <= canvas.width; x++) {
const y = Math.sin(x * 0.1 + waveOffsets[i]) * 4 + 10;
ctx.lineTo(x, y);
}
ctx.lineTo(canvas.width, canvas.height);
ctx.closePath();
ctx.fill();
ctx.fillStyle = color.light;
ctx.beginPath();
ctx.moveTo(0, canvas.height);
for (let x = 0; x <= canvas.width; x++) {
const y = Math.sin(x * 0.08 - waveOffsets[i]) * 5 + 12;
ctx.lineTo(x, y);
}
ctx.lineTo(canvas.width, canvas.height);
ctx.closePath();
ctx.fill();
}
}
// SATELLITE INTERACTION & FALLBACK MAP GENERATION
function showYearDetail(year, text) {
const box = document.getElementById('satellite-detail-box');
if (box) {
box.innerHTML = `📅 <strong>Год ${year}:</strong> ${text}`;
box.className = "p-3.5 bg-cyan-950/40 border border-cyan-800/60 rounded-xl text-xs text-cyan-300 font-mono transition-all animate-pulse";
setTimeout(() => {
box.className = "p-3.5 bg-cyan-950/20 border border-cyan-800/40 rounded-xl text-xs text-cyan-300 font-mono transition-all";
}, 600);
}
}
function showFallbackMap(imgElement, year) {
const parent = imgElement.parentElement;
if (!parent) return;
let pathData = "";
let fill = "#0ea5e9";
let bg = "#1c1917";
if (year === 1977) {
pathData = "M 20 20 C 40 10, 80 15, 85 45 C 90 70, 75 90, 50 95 C 25 100, 10 70, 20 20 Z";
} else if (year === 1987) {
pathData = "M 22 25 C 40 15, 75 20, 80 45 C 85 65, 70 85, 48 90 C 28 95, 15 65, 22 25 Z";
} else if (year === 1998) {
pathData = "M 35 15 C 55 12, 65 20, 55 25 C 40 28, 30 20, 35 15 M 24 35 C 45 35, 75 40, 75 55 C 70 70, 55 85, 45 85 C 25 80, 20 50, 24 35 Z";
} else if (year === 2006) {
pathData = "M 32 14 C 55 11, 62 18, 55 25 C 40 28, 30 20, 32 14 M 22 38 C 30 38, 35 48, 30 78 C 22 78, 20 50, 22 38 M 55 45 C 68 45, 72 65, 65 80 C 50 80, 52 55, 55 45 Z";
} else if (year === 2010) {
pathData = "M 32 14 C 55 11, 62 18, 55 25 C 40 28, 30 20, 32 14 M 22 40 C 26 40, 28 55, 26 78 C 21 78, 20 50, 22 40";
} else if (year === 2020) {
pathData = "M 32 14 C 55 11, 62 18, 55 25 C 40 28, 30 20, 32 14 M 22 44 C 24 44, 25 55, 24 75 C 21 75, 20 50, 22 44";
}
const svgMarkup = `
<svg viewBox="0 0 100 100" class="w-full h-full animate-fade-in" style="background-color: ${bg};">
<rect width="100" height="100" fill="${bg}"/>
<path d="M 20 20 C 40 10, 80 15, 85 45 C 90 70, 75 90, 50 95 C 25 100, 10 70, 20 20 Z" fill="none" stroke="#444" stroke-width="0.8" stroke-dasharray="2,2" />
<path d="${pathData}" fill="${fill}" opacity="0.85" filter="drop-shadow(0px 0px 3px ${fill})" stroke="#38bdf8" stroke-width="0.5" />
<text x="50" y="90" fill="#666" font-size="4.5" font-family="monospace" text-anchor="middle">SATELLITE RECORD ${year}</text>
</svg>
`;
parent.innerHTML = svgMarkup;
}
// GOOGLE DRIVE PUBLIC IMAGE FALLBACK HANDLER
function showFallbackDriveImage(parent) {
if (!parent) return;
const svgMarkup = `
<svg viewBox="0 0 400 225" class="w-full h-full animate-fade-in" style="background: linear-gradient(180deg, #18181b 0%, #09090b 100%);">
<defs>
<radialGradient id="sun-glow-drive" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#ea580c" stop-opacity="0.2" />
<stop offset="100%" stop-color="#ea580c" stop-opacity="0" />
</radialGradient>
</defs>
<rect width="100%" height="100%" fill="#09090b"/>
<circle cx="200" cy="112" r="120" fill="url(#sun-glow-drive)" filter="blur(15px)"/>
<path d="M 0 170 Q 140 130 280 170 T 400 160 L 400 225 L 0 225 Z" fill="#27272a"/>
<g transform="translate(135, 105) scale(0.85) rotate(11)">
<path d="M 10 40 L 120 40 L 135 15 L 0 15 Z" fill="#52525b" stroke="#71717a" stroke-width="1" />
<rect x="35" y="-18" width="40" height="18" fill="#71717a" rx="1" />
<rect x="42" y="-11" width="10" height="7" fill="#27272a" />
<line x1="55" y1="-18" x2="55" y2="-52" stroke="#a1a1aa" stroke-width="2.5" />
<circle cx="20" cy="25" r="3.5" fill="#ea580c"/>
</g>
<rect x="8" y="8" width="384" height="209" fill="none" stroke="#3f3f46" stroke-width="1" stroke-dasharray="4,4" opacity="0.4"/>
<text x="200" y="200" fill="#a1a1aa" font-size="10" font-family="sans-serif" text-anchor="middle" letter-spacing="1">ИСТОРИЧЕСКИЙ АРХИВ (РЕЗЕРВ СЭД)</text>
</svg>
`;
parent.innerHTML = svgMarkup;
}
// MULTI-STAGE FALLBACK HANDLER FOR GOOGLE DRIVE IMAGES
function handleDriveImageError(img) {
const imageId = "1AIk8DUA1Fa-NHM6xyit6QcLk7hFovgof";
if (img.src.includes("lh3.googleusercontent.com")) {
console.warn("lh3 CDN blocked, trying Google Drive Thumbnail endpoint...");
img.src = `https://drive.google.com/thumbnail?id=${imageId}&sz=w1000`;
} else if (img.src.includes("drive.google.com/thumbnail")) {
console.warn("Thumbnail API blocked, trying uc export...");
img.src = `https://docs.google.com/uc?export=view&id=${imageId}`;
} else {
console.error("All Google Drive image links were blocked. Initiating offline vector view.");
showFallbackDriveImage(img.parentElement);
}
}
// STATE UTILITIES
function updateUIVisibility() {
for (let i = 1; i <= 6; i++) {
const section = document.getElementById(`step-${i}`);
if (section) {
if (i <= state.currentUnlocked) {
section.classList.remove('hidden');
} else {
section.classList.add('hidden');
}
}
const beakerNav = document.getElementById(`beaker-nav-${i}`);
const beakerCanvas = document.getElementById(`beaker-wave-${i}`);
if (beakerNav && beakerCanvas) {
if (i <= state.currentUnlocked) {
beakerNav.classList.remove('opacity-40', 'grayscale');
// GAMIFICATION: Beaker 6 target level goes to 100% only after final pitch generation
let targetHeight = waveHeights[i - 1];
if (i === 6) {
targetHeight = state.step6SpeechGenerated ? 100 : 15;
}
beakerCanvas.style.height = `${targetHeight}%`;
} else {
beakerNav.classList.add('opacity-40', 'grayscale');
beakerCanvas.style.height = '0%';
}
}
}
updateIQDisplay();
saveStateToStorage();
}
function scrollToStep(num) {
if (num <= state.currentUnlocked) {
const target = document.getElementById(`step-${num}`);
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
}
// LOCAL STORAGE ENGINE
function saveStateToStorage() {
localStorage.setItem('aral_sim_state_2026', JSON.stringify({
currentUnlocked: state.currentUnlocked,
selectedScenario: state.selectedScenario,
quizScore: state.quizScore,
quizAnswers: state.quizAnswers,
swotContent: state.swotContent,
docParams: state.docParams,
isSigned: state.isSigned,
step6SpeechGenerated: state.step6SpeechGenerated,
promptCopied: state.promptCopied,
swotEvaluated: state.swotEvaluated,
scores: state.scores
}));
}
function loadStateFromStorage() {
const data = localStorage.getItem('aral_sim_state_2026');
if (data) {
try {
const parsed = JSON.parse(data);
state.currentUnlocked = parsed.currentUnlocked || 1;
state.selectedScenario = parsed.selectedScenario || null;
state.quizScore = parsed.quizScore || 0;
state.quizAnswers = parsed.quizAnswers || [];
state.swotContent = parsed.swotContent || { s: '', w: '', o: '', t: '' };
state.docParams = parsed.docParams || { focus: 'Ecology', negotiation: 'Transboundary', mitigation: '' };
state.isSigned = parsed.isSigned || false;
state.step6SpeechGenerated = parsed.step6SpeechGenerated || false;
state.promptCopied = parsed.promptCopied || false;
state.swotEvaluated = parsed.swotEvaluated || false;
state.scores = parsed.scores || { step1: 0, step2: 0, step3: 0, step4: 0, step5: 0, step6: 0 };
} catch (e) {
console.error("Error loading state", e);
}
}
}
function resetSimulation() {
localStorage.removeItem('aral_sim_state_2026');
state.currentUnlocked = 1;
state.selectedScenario = null;
state.quizScore = 0;
state.quizAnswers = [];
state.swotContent = { s: '', w: '', o: '', t: '' };
state.docParams = { focus: 'Ecology', negotiation: 'Transboundary', mitigation: '' };
state.isSigned = false;
state.step6SpeechGenerated = false;
state.promptCopied = false;
state.swotEvaluated = false;
state.scores = { step1: 0, step2: 0, step3: 0, step4: 0, step5: 0, step6: 0 };
document.getElementById('swot-s').value = '';
document.getElementById('swot-w').value = '';
document.getElementById('swot-o').value = '';
document.getElementById('swot-t').value = '';
document.getElementById('doc-mitigation').value = '';
const auditWrapper = document.getElementById('swot-audit-wrapper');
if (auditWrapper) auditWrapper.classList.add('hidden');
clearSignature();
initScenarioCards();
updateUIVisibility();
resetQuizEngine();
drawCharts();
scrollToStep(1);
showToast("Симуляция успешно сброшена!", "success");
}
// STEP 1 CHARTS (Chart.js)
let salinityChartObj = null;
let fishChartObj = null;
function drawCharts() {
const salCtx = document.getElementById('salinityChart').getContext('2d');
const fishCtx = document.getElementById('fishChart').getContext('2d');
if (salinityChartObj) salinityChartObj.destroy();
if (fishChartObj) fishChartObj.destroy();
salinityChartObj = new Chart(salCtx, {
type: 'line',
data: {
labels: ['1960', '1980', '2000', '2005 (Дамба)', '2026 (Текущее)'],
datasets: [{
label: 'Соленость (г/л)',
data: [10, 22, 30, 14, 10],
borderColor: '#06b6d4',
backgroundColor: 'rgba(6, 182, 212, 0.1)',
borderWidth: 3,
tension: 0.3,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { grid: { color: '#30363d' }, ticks: { color: '#8b949e', font: { size: 9 } } },
y: { grid: { color: '#30363d' }, ticks: { color: '#8b949e', font: { size: 9 } } }
}
}
});
fishChartObj = new Chart(fishCtx, {
type: 'bar',
data: {
labels: ['1960', '1990', '2005', '2015', '2026 (Текущее)'],
datasets: [{
label: 'Улов (тыс. тонн)',
data: [25, 0.1, 1.2, 5.5, 8.2],
backgroundColor: '#10b981',
borderRadius: 6
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { grid: { color: '#30363d' }, ticks: { color: '#8b949e', font: { size: 9 } } },
y: { grid: { color: '#30363d' }, ticks: { color: '#8b949e', font: { size: 9 } } }
}
}
});
}
function selectScenario(id) {
state.selectedScenario = id;
['A', 'B', 'C'].forEach(x => {
const card = document.getElementById(`card-${x}`);
const chk = document.getElementById(`checkbox-${x}`).children[0];
if (x === id) {
card.classList.add('border-cyan-500', 'scale-[1.01]', 'bg-cyan-950/10');
card.classList.remove('border-zinc-700/60');
chk.classList.remove('hidden');
} else {
card.classList.remove('border-cyan-500', 'scale-[1.01]', 'bg-cyan-950/10');
card.classList.add('border-zinc-700/60');
chk.classList.add('hidden');
}
});
document.getElementById('ai-sandbox-step1').classList.remove('hidden');
updateIQDisplay();
saveStateToStorage();
showToast(`Сценарий ${id} успешно выбран в качестве основного! +10 IQ`, "success");
}
function initScenarioCards() {
if (state.selectedScenario) {
selectScenario(state.selectedScenario);
}
}
// STEP 2 QUIZ MECHANICS
let currentQuizIndex = 0;
let quizChartObj = null;
function initQuizChart() {
const ctx = document.getElementById('quizProgressChart').getContext('2d');
if (quizChartObj) quizChartObj.destroy();
quizChartObj = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Ваш балл'],
datasets: [{
data: [state.quizScore],
backgroundColor: '#10b981',
borderColor: '#06b6d4',
borderWidth: 1,
borderRadius: 10,
barThickness: 45
}]
},
options: {
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { min: 0, max: 100, grid: { color: '#30363d' }, ticks: { color: '#8b949e' } },
y: { display: false }
}
}
});
}
function resetQuizEngine() {
currentQuizIndex = 0;
state.quizAnswers = [];
state.quizScore = 0;
document.getElementById('quiz-idx').innerText = "1";
document.getElementById('quiz-correct-counter').innerText = "Верно: 0 | Баллы: 0";
document.getElementById('quiz-trigger-container').style.display = 'none';
document.getElementById('quiz-completion-text').innerText = "Выполните тест";
document.getElementById('quiz-completion-text').className = "text-xs font-mono text-amber-500 font-bold";
loadQuizQuestion();
if (quizChartObj) {
quizChartObj.data.datasets[0].data = [0];
quizChartObj.update();
}
}
function loadQuizQuestion() {
if (currentQuizIndex >= QUIZ_QUESTIONS.length) {
completeQuiz();
return;
}
const currentQ = QUIZ_QUESTIONS[currentQuizIndex];
document.getElementById('quiz-idx').innerText = currentQuizIndex + 1;
document.getElementById('quiz-question').innerText = currentQ.q;
const optionsContainer = document.getElementById('quiz-options');
optionsContainer.innerHTML = '';
currentQ.options.forEach((opt, idx) => {
const btn = document.createElement('button');
btn.className = "w-full text-left p-4 bg-zinc-900 border border-[#30363d] rounded-xl text-xs text-gray-300 hover:text-white hover:border-gray-500 transition-all leading-relaxed focus:outline-none";
btn.innerText = opt;
btn.onclick = () => submitQuizAnswer(idx);
optionsContainer.appendChild(btn);
});
}
function submitQuizAnswer(chosenIdx) {
const currentQ = QUIZ_QUESTIONS[currentQuizIndex];
const buttons = document.getElementById('quiz-options').children;
const correctIdx = currentQ.correct;
for (let i = 0; i < buttons.length; i++) {
buttons[i].disabled = true;
if (i === correctIdx) {
buttons[i].className = "w-full text-left p-4 bg-emerald-950 border-2 border-emerald-500 rounded-xl text-xs text-emerald-300 font-bold leading-relaxed";
} else if (i === chosenIdx) {
buttons[i].className = "w-full text-left p-4 bg-rose-950 border-2 border-rose-500 rounded-xl text-xs text-rose-300 font-bold leading-relaxed";
} else {
buttons[i].className = "w-full text-left p-4 bg-zinc-950 opacity-40 border border-[#30363d] rounded-xl text-xs text-gray-500 leading-relaxed";
}
}
const isCorrect = (chosenIdx === correctIdx);
state.quizAnswers.push({ q: currentQuizIndex, correct: isCorrect, chosen: chosenIdx });
if (isCorrect) {
state.quizScore += currentQ.points;
showToast("Правильный ответ! +1 IQ", "success");
} else {
showToast("Неверно. Проанализируйте ошибку", "error");
}
const correctCount = state.quizAnswers.filter(a => a.correct).length;
document.getElementById('quiz-correct-counter').innerText = `Верно: ${correctCount} | Баллы: ${state.quizScore}`;
if (quizChartObj) {
quizChartObj.data.datasets[0].data = [state.quizScore];
quizChartObj.update();
}
updateIQDisplay();
setTimeout(() => {
currentQuizIndex++;
loadQuizQuestion();
}, 1500);
}
function completeQuiz() {
const correctCount = state.quizAnswers.filter(a => a.correct).length;
document.getElementById('quiz-box').innerHTML = `
<div class="text-center py-8 space-y-4">
<div class="w-16 h-16 rounded-full bg-emerald-950 border border-emerald-500 flex items-center justify-center text-emerald-400 font-black text-2xl mx-auto">✓</div>
<h3 class="text-xl font-bold text-white">Тестирование успешно завершено!</h3>
<p class="text-sm text-gray-400 max-w-md mx-auto">Вы набрали <strong class="text-emerald-400">${state.quizScore} баллов</strong>. Стратегический профиль пополнился на <strong class="text-amber-400">${correctCount} IQ</strong>.</p>
</div>
`;
const completionText = document.getElementById('quiz-completion-text');
if (state.quizScore >= 70) {
completionText.innerText = "Сертификат подтвержден!";
completionText.className = "text-xs font-mono text-emerald-400 font-bold";
showToast("Экзамен сдан! Квалификация подтверждена.", "success");
} else {
completionText.innerText = "Сертификат выдан условно";
completionText.className = "text-xs font-mono text-amber-500 font-bold";
showToast("Экзамен сдан условно. Наберите больше 70 в следующий раз.", "info");
}
document.getElementById('quiz-trigger-container').style.display = 'flex';
updateIQDisplay();
saveStateToStorage();
}
function unlockStep2() {
if (!state.selectedScenario) {
showToast("Пожалуйста, выберите сценарий развития на панели карт проектов.", "error");
return;
}
if (state.currentUnlocked < 2) {
state.currentUnlocked = 2;
updateUIVisibility();
}
setTimeout(() => scrollToStep(2), 200);
}
function unlockStep3() {
if (state.currentUnlocked < 3) {
state.currentUnlocked = 3;
updateUIVisibility();
initSWOTSuggestions();
}
setTimeout(() => scrollToStep(3), 200);
}
// STEP 3 SWOT WORKSPACE & AI VERIFICATION (Students fill themselves, AI grades & compares)
const SWOT_PILLS = [
{ text: "Наращивание дамбы до 48м (+250% видов)", cat: "s" },
{ text: "Полный возврат моря в Аральск", cat: "s" },
{ text: "Снижение солености с 30 до 12 г/л", cat: "s" },
{ text: "Высокий CAPEX ($120M) проекта", cat: "w" },
{ text: "Сложность ИИ-монтажа датчиков воды", cat: "w" },
{ text: "Зависимость от единого стока Сырдарьи", cat: "w" },
{ text: "Гранты ООН и зеленые бонды ООН", cat: "o" },
{ text: "Выпуск эко-углеродных офсетов", cat: "o" },
{ text: "Развитие пресноводного рыболовства", cat: "o" },
{ text: "Трансграничные споры (ГЭС верховьев)", cat: "t" },
{ text: "Заиливание подводящих каналов", cat: "t" },
{ text: "Экстремальная песчаная буря Аралкума", cat: "t" }
];
function initSWOTSuggestions() {
const container = document.getElementById('swot-suggestions-deck');
container.innerHTML = '';
SWOT_PILLS.forEach((p, idx) => {
const badge = document.createElement('span');
badge.className = "px-3 py-1.5 bg-zinc-800 hover:bg-zinc-700 text-gray-300 rounded-lg text-xs font-semibold cursor-pointer transition-all border border-zinc-700 hover:border-gray-500 shadow-sm";
badge.innerText = p.text;
badge.onclick = () => addSWOTPill(p.text, p.cat, badge);
container.appendChild(badge);
});
document.getElementById('swot-s').value = state.swotContent.s || '';
document.getElementById('swot-w').value = state.swotContent.w || '';
document.getElementById('swot-o').value = state.swotContent.o || '';
document.getElementById('swot-t').value = state.swotContent.t || '';
}
function addSWOTPill(text, category, elementRef) {
const textarea = document.getElementById(`swot-${category}`);
if (textarea) {
const currentVal = textarea.value.trim();
textarea.value = currentVal ? `${currentVal}\n• ${text}` : `• ${text}`;
elementRef.classList.add('opacity-40', 'pointer-events-none');
saveSWOTInputs();
showToast("Тезис интегрирован в вашу матрицу", "info");
}
}
function saveSWOTInputs() {
state.swotContent.s = document.getElementById('swot-s').value;
state.swotContent.w = document.getElementById('swot-w').value;
state.swotContent.o = document.getElementById('swot-o').value;
state.swotContent.t = document.getElementById('swot-t').value;
saveStateToStorage();
}
['s', 'w', 'o', 't'].forEach(k => {
const textarea = document.getElementById(`swot-${k}`);
if (textarea) {
textarea.addEventListener('input', saveSWOTInputs);
}
});
// EVALUATE SWOT AND GENERATE IDEAL MODEL COMPARISON (Side-by-side)
async function evaluateSWOT() {
saveSWOTInputs();
// Check if student has entered any content
const totalChars = (state.swotContent.s + state.swotContent.w + state.swotContent.o + state.swotContent.t).length;
if (totalChars < 20) {
showToast("Пожалуйста, заполните SWOT-матрицу тезисами перед отправкой на проверку!", "error");
return;
}
const wrapper = document.getElementById('swot-audit-wrapper');
const outputBox = document.getElementById('ai-swot-output');
const idealGrid = document.getElementById('swot-ideal-grid');
if (wrapper) wrapper.classList.remove('hidden');
if (outputBox) outputBox.innerText = "ИИ-аудитор изучает структуру вашей матрицы... Пожалуйста, подождите.";
const scenarioKey = state.selectedScenario || 'A';
const idealData = SCENARIOS[scenarioKey].idealSwot;
// Render ideal baseline immediately side-by-side
if (idealGrid) {
idealGrid.innerHTML = `
<div class="p-2.5 bg-emerald-950/20 border border-emerald-900/40 rounded-lg">
<strong class="text-emerald-400 block mb-1">S (Плюсы):</strong>
<p class="whitespace-pre-line leading-relaxed">${idealData.s}</p>
</div>
<div class="p-2.5 bg-rose-950/20 border border-rose-900/40 rounded-lg">
<strong class="text-rose-400 block mb-1">W (Минусы):</strong>
<p class="whitespace-pre-line leading-relaxed">${idealData.w}</p>
</div>
<div class="p-2.5 bg-cyan-950/20 border border-cyan-900/40 rounded-lg">
<strong class="text-cyan-400 block mb-1">O (Перспективы):</strong>
<p class="whitespace-pre-line leading-relaxed">${idealData.o}</p>
</div>
<div class="p-2.5 bg-amber-950/20 border border-amber-900/40 rounded-lg">
<strong class="text-amber-400 block mb-1">T (Угрозы):</strong>
<p class="whitespace-pre-line leading-relaxed">${idealData.t}</p>
</div>
`;
}
const sysPrompt = "Вы — строгий профессор бизнес-школы Executive MBA. Оцените SWOT-анализ студента для проекта восстановления Малого Арала. Дайте критическую рецензию на русском языке, укажите достоинства и упущения, а в самом конце ОБЯЗАТЕЛЬНО напишите строчку в формате 'Оценка: X/10' (где Х - число баллов от 1 до 10).";
const userPrompt = `Выбранный сценарий: ${SCENARIOS[scenarioKey].name}.\nСтудент написал:\nS: ${state.swotContent.s}\nW: ${state.swotContent.w}\nO: ${state.swotContent.o}\nT: ${state.swotContent.t}\n\nПроанализируйте этот ввод и выставите оценку в баллах.`;
const res = await callGeminiAPI(sysPrompt, userPrompt);
state.swotEvaluated = true;
if (res) {
outputBox.innerText = res;
// Parse score from AI output
let score = 10;
const scoreMatch = res.match(/(?:Оценка|Баллы|IQ|Score):\s*(\d+)/i);
if (scoreMatch) {
score = parseInt(scoreMatch[1]);
if (isNaN(score) || score > 10) score = 10;
}
state.scores.step3 = score;
showToast(`Анализ проверен ИИ-комитетом! Получено +${score} IQ`, "success");
} else {
// Local fallback MBA audit engine
outputBox.innerText = `[Аудиторский отчет MBA-комитета]:\n\n` +
`• СТРУКТУРНЫЙ АНАЛИЗ: Студент успешно сопоставил риски и возможности выбранного сценария "${SCENARIOS[scenarioKey].name}".\n` +
`• СИЛЬНЫЕ СТОРОНЫ ОТВЕТА: Учтены ключевые гидрологические параметры Сырдарьи и влияние на популяцию рыбы.\n` +
`• РЕКОМЕНДАЦИИ: Обратите внимание на трансграничные лимиты забора воды соседними государствами.\n\n` +
`Оценка: 10/10`;
state.scores.step3 = 10;
showToast("Использована локальная SWOT-оценка. Получено +10 IQ!", "success");
}
updateIQDisplay();
saveStateToStorage();
}
function unlockStep4() {
saveSWOTInputs();
if (!state.swotEvaluated) {
showToast("Пожалуйста, сначала отправьте свою матрицу на проверку («Проверить мою матрицу»)", "error");
return;
}
if (state.currentUnlocked < 4) {
state.currentUnlocked = 4;
updateUIVisibility();
setTimeout(initSignaturePad, 300);
}
setTimeout(() => scrollToStep(4), 200);
}
// STEP 4 SIGNATURE PAD MECHANICS
let sigCanvas = null;
let sigCtx = null;
let drawing = false;
function initSignaturePad() {
sigCanvas = document.getElementById('signaturePad');
if (!sigCanvas) return;
sigCtx = sigCanvas.getContext('2d');
const rect = sigCanvas.getBoundingClientRect();
sigCanvas.width = rect.width;
sigCanvas.height = rect.height;
sigCtx.strokeStyle = '#38bdf8';
sigCtx.lineWidth = 3;
sigCtx.lineCap = 'round';
sigCanvas.addEventListener('mousedown', startDrawing);
sigCanvas.addEventListener('mouseup', endDrawing);
sigCanvas.addEventListener('mousemove', drawLine);
sigCanvas.addEventListener('touchstart', (e) => {
const touch = e.touches[0];
const mouseEvent = new MouseEvent("mousedown", {
clientX: touch.clientX,
clientY: touch.clientY
});
sigCanvas.dispatchEvent(mouseEvent);
});
sigCanvas.addEventListener('touchend', () => {
const mouseEvent = new MouseEvent("mouseup", {});
sigCanvas.dispatchEvent(mouseEvent);
});
sigCanvas.addEventListener('touchmove', (e) => {
const touch = e.touches[0];
const mouseEvent = new MouseEvent("mousemove", {
clientX: touch.clientX,
clientY: touch.clientY
});
sigCanvas.dispatchEvent(mouseEvent);
}, { passive: true });
}
function startDrawing(e) {
drawing = true;
sigCtx.beginPath();
const rect = sigCanvas.getBoundingClientRect();
sigCtx.moveTo(e.clientX - rect.left, e.clientY - rect.top);
}
function endDrawing() {
if (drawing) {
drawing = false;
sigCtx.closePath();
state.isSigned = true;
document.getElementById('signature-status').innerText = "Подписано в СЭД";
document.getElementById('signature-status').className = "text-xs font-mono text-emerald-400 font-bold animate-pulse";
updateIQDisplay();
saveStateToStorage();
showToast("Цифровая подпись верифицирована! +10 IQ", "success");
}
}
function drawLine(e) {
if (!drawing) return;
const rect = sigCanvas.getBoundingClientRect();
sigCtx.lineTo(e.clientX - rect.left, e.clientY - rect.top);
sigCtx.stroke();
}
function clearSignature() {
if (sigCtx && sigCanvas) {
sigCtx.clearRect(0, 0, sigCanvas.width, sigCanvas.height);
state.isSigned = false;
document.getElementById('signature-status').innerText = "Ожидает визирования";
document.getElementById('signature-status').className = "text-xs font-mono text-red-400 font-bold";
updateIQDisplay();
saveStateToStorage();
}
}
function saveDocParams() {
state.docParams.focus = document.getElementById('doc-focus').value;
state.docParams.negotiation = document.getElementById('doc-negotiation').value;
state.docParams.mitigation = document.getElementById('doc-mitigation').value;
saveStateToStorage();
}
document.getElementById('doc-focus').addEventListener('change', saveDocParams);
document.getElementById('doc-negotiation').addEventListener('change', saveDocParams);
document.getElementById('doc-mitigation').addEventListener('input', saveDocParams);
function unlockStep5() {
saveDocParams();
if (!state.isSigned) {
showToast("Пожалуйста, подпишите декларацию на графическом планшете справа.", "error");
return;
}
if (state.currentUnlocked < 5) {
state.currentUnlocked = 5;
updateUIVisibility();
initPodcastVisualizer();
}
generateNotebookLMPrompt();
setTimeout(() => scrollToStep(5), 200);
}
// STEP 5 MEDIA GENERATOR & COPYING
function generateNotebookLMPrompt() {
const scenarioInfo = SCENARIOS[state.selectedScenario] || SCENARIOS.A;
const prompt = `--- OUTLINE FOR NOTEBOOK LM AUDIO OVERVIEW GENERATOR ---
ROLE: Executive Host Sarah and Technical Director Alex.
TOPIC: Deep dive evaluation of Aral Sea Phase II Rehabilitation Strategy.
STUDENT PORTFOLIO DATA:
- Selected Path: ${scenarioInfo.name} (Budget: ${scenarioInfo.cost}, ESG Index: ${scenarioInfo.rating}).
- Quiz Score: ${state.quizScore}/100 (MBA Certification).
- Core Focus: ${state.docParams.focus === 'Ecology' ? 'Ecology-first mitigation' : state.docParams.focus === 'Economy' ? 'Commercial fisheries growth' : 'Digital AI & automated control structures'}.
- Key Stakeholder: ${state.docParams.negotiation}.
SWOT ANALYSIS SUMMARY:
Strengths: ${state.swotContent.s || 'N/A'}
Weaknesses: ${state.swotContent.w || 'N/A'}
Opportunities: ${state.swotContent.o || 'N/A'}
Threats: ${state.swotContent.t || 'N/A'}
MITIGATION PLAN B:
"${state.docParams.mitigation || 'N/A'}"
PROMPT DIRECTION: Generate a 10-minute deep conversation debating the environmental ROI vs. transboundary hydro-political risks of this exact configuration. Host 1 is positive but realistic about CAPEX. Host 2 focuses on water flow sensors and local fishermen livelihoods.`;
document.getElementById('prompt-textbox').innerText = prompt;
}
function copyPromptToClipboard() {
const textToCopy = document.getElementById('prompt-textbox').innerText;
const temp = document.createElement('textarea');
temp.value = textToCopy;
document.body.appendChild(temp);
temp.select();
document.execCommand('copy');
document.body.removeChild(temp);
state.promptCopied = true;
updateIQDisplay();
showToast("Промпт скопирован! Начислено +10 IQ", "success");
}
// STEP 5 AUDIO WAVEFORM CANVAS AND PLAYBACK SIMULATION
let waveVisualizerId = null;
let isPodcastPlaying = false;
let p_canvas = null;
let p_ctx = null;
let synth = window.speechSynthesis;
let utter = null;
function initPodcastVisualizer() {
p_canvas = document.getElementById('waveformCanvas');
p_ctx = p_canvas.getContext('2d');
p_canvas.width = p_canvas.offsetWidth;
p_canvas.height = p_canvas.offsetHeight;
drawVisualizerStatic();
}
function drawVisualizerStatic() {
p_ctx.clearRect(0, 0, p_canvas.width, p_canvas.height);
p_ctx.fillStyle = '#1e1b4b';
p_ctx.fillRect(0, 0, p_canvas.width, p_canvas.height);
p_ctx.fillStyle = '#c084fc';
const count = 40;
const width = p_canvas.width / count;
for (let i = 0; i < count; i++) {
const h = 4 + Math.sin(i * 0.3) * 6;
p_ctx.fillRect(i * width + 2, p_canvas.height / 2 - h / 2, width - 4, h);
}
}
const podcastDialogue = [
{ host: "Алекс", text: "Привет! С вами подкаст Aral-Tech. И сегодня мы разбираем стратегический проект восстановления Малого Арала." },
{ host: "Сара", text: "Да, и наш студент выбрал отличный вектор. Направлено финансирование на " + (state.docParams.focus === 'Ecology' ? 'экологию' : 'экономику') + " с использованием ИИ." },
{ host: "Алекс", text: "Абсолютно! Но давай обсудим риски заиливания и трансграничные водные лимиты. Они могут сорвать окупаемость проекта." },
{ host: "Сара", text: "Именно поэтому подписанная Декларация предусматривает План Б для стабилизации ситуации." }
];
let dialogueIndex = 0;
function togglePodcastPlayback() {
if (isPodcastPlaying) {
stopPodcastSimulation();
} else {
startPodcastSimulation();
}
}
function startPodcastSimulation() {
isPodcastPlaying = true;
dialogueIndex = 0;
document.getElementById('btn-play-podcast').innerText = "Остановить";
document.getElementById('btn-play-podcast').className = "flex-1 px-4 py-2.5 bg-rose-600 hover:bg-rose-500 text-white text-xs font-bold rounded-lg transition-all shadow-md";
function playLoop() {
if (!isPodcastPlaying) return;
p_ctx.clearRect(0, 0, p_canvas.width, p_canvas.height);
p_ctx.fillStyle = '#0f0728';
p_ctx.fillRect(0, 0, p_canvas.width, p_canvas.height);
const count = 30;
const width = p_canvas.width / count;
p_ctx.fillStyle = '#a855f7';
for (let i = 0; i < count; i++) {
const h = Math.abs(Math.sin(i * 0.2 + Date.now() * 0.015)) * (p_canvas.height - 10) + 4;
p_ctx.fillRect(i * width + 3, p_canvas.height / 2 - h / 2, width - 6, h);
}
waveVisualizerId = requestAnimationFrame(playLoop);
}
playLoop();
playDialogueLine();
}
function playDialogueLine() {
if (!isPodcastPlaying) return;
if (dialogueIndex >= podcastDialogue.length) {
stopPodcastSimulation();
return;
}
const item = podcastDialogue[dialogueIndex];
document.getElementById('podcast-host').innerText = item.host;
document.getElementById('podcast-subtitle').innerText = item.text;
if (synth && synth.getVoices().length > 0) {
synth.cancel();
utter = new SpeechSynthesisUtterance(item.text);
utter.lang = 'ru-RU';
utter.onend = () => {
dialogueIndex++;
setTimeout(playDialogueLine, 500);
};
synth.speak(utter);
} else {
setTimeout(() => {
dialogueIndex++;
playDialogueLine();
}, 3500);
}
}
function stopPodcastSimulation() {
isPodcastPlaying = false;
cancelAnimationFrame(waveVisualizerId);
if (synth) synth.cancel();
document.getElementById('btn-play-podcast').innerText = "Прослушать сводку";
document.getElementById('btn-play-podcast').className = "flex-1 px-4 py-2.5 bg-emerald-600 hover:bg-emerald-500 text-black text-xs font-bold rounded-lg transition-all shadow-md";
drawVisualizerStatic();
document.getElementById('podcast-subtitle').innerText = "Воспроизведение приостановлено.";
}
function unlockStep6() {
state.promptCopied = true;
stopPodcastSimulation();
if (state.currentUnlocked < 6) {
state.currentUnlocked = 6;
updateUIVisibility();
calculateStakeholderSentiments();
}
setTimeout(() => scrollToStep(6), 200);
}
// STEP 6 BOARDROOM SCENE MECHANICS
function calculateStakeholderSentiments() {
let gov = 50, local = 50, invest = 50, eco = 50;
if (state.selectedScenario === 'A') {
gov += 25; eco += 20; invest += 20; local += 10;
} else if (state.selectedScenario === 'B') {
gov += 15; local += 30; invest += 10; eco += 10;
} else if (state.selectedScenario === 'C') {
eco += 25; invest += 25; local -= 10; gov -= 15;
}
if (state.docParams.focus === 'Ecology') {
eco += 15; local -= 5; gov -= 5;
} else if (state.docParams.focus === 'Economy') {
local += 20; gov += 10; eco -= 15;
} else if (state.docParams.focus === 'Tech') {
invest += 15; gov += 10;
}
const bonus = Math.floor((state.quizScore - 50) / 4);
gov += bonus;
invest += bonus;
gov = Math.max(10, Math.min(100, gov));
local = Math.max(10, Math.min(100, local));
invest = Math.max(10, Math.min(100, invest));
eco = Math.max(10, Math.min(100, eco));
animateGauge('gov', gov);
animateGauge('local', local);
animateGauge('invest', invest);
animateGauge('eco', eco);
const totalAvg = (gov + local + invest + eco) / 4;
let grade = "РЕЙТИНГ: ";
if (totalAvg >= 85) grade += "AAA (Отлично)";
else if (totalAvg >= 70) grade += "AA (Хорошо)";
else if (totalAvg >= 55) grade += "A (Удовлетворительно)";
else grade += "BBB (Критический уровень)";
document.getElementById('rating-grade').innerText = grade;
}
function animateGauge(key, val) {
document.getElementById(`rate-${key}`).innerText = `${val}%`;
document.getElementById(`bar-${key}`).style.width = `${val}%`;
}
// INTEGRATED GEMINI API CALLER & EXPONENTIAL BACKOFF LOGIC
async function callGeminiAPI(systemPrompt, userPrompt) {
const apiKeyInput = document.getElementById('api-key').value.trim();
const key = apiKeyInput || state.api_key;
if (!key) {
return null;
}
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent?key=${key}`;
const payload = {
contents: [{
parts: [{
text: `${systemPrompt}\n\nUser Input: ${userPrompt}`
}]
}]
};
let delay = 1000;
for (let attempt = 1; attempt <= 3; attempt++) {
try {
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (response.ok) {
const json = await response.json();
return json.candidates?.[0]?.content?.parts?.[0]?.text;
}
if (response.status === 429) {
await new Promise(r => setTimeout(r, delay));
delay *= 2;
} else {
throw new Error(`HTTP Error Status: ${response.status}`);
}
} catch (err) {
console.warn(`Attempt ${attempt} failed:`, err);
}
}
return null;
}
// STEP 1 AI LIVE CALLER
async function runStep1AI() {
const outputElement = document.getElementById('ai-step1-output');
if (!state.selectedScenario || !SCENARIOS[state.selectedScenario]) {
outputElement.innerText = "Пожалуйста, выберите один из инвестиционных сценариев (A, B или C) выше перед запуском экспертизы.";
showToast("Сценарий не выбран!", "error");
return;
}
outputElement.innerText = "ИИ изучает экологические параметры... Пожалуйста, подождите.";
const selectedProject = SCENARIOS[state.selectedScenario];
const sysPrompt = "Вы — старший консультант Всемирного банка по экологической дипломатии. Напишите структурированную экспертную оценку выбранного проекта на русском языке. Будьте реалистичным, цитируйте показатели бюджета.";
const userPrompt = `Выбран сценарий: ${JSON.stringify(selectedProject)}. Соленость Сырдарьи снижена до 10 г/л. Улов рыбы составляет 8.2 тыс. тонн. Сделайте вывод, имеет ли этот CAPEX достаточную эффективность в долгосрочном планировании.`;
const res = await callGeminiAPI(sysPrompt, userPrompt);
if (res) {
outputElement.innerText = res;
showToast("Генерация завершена!", "success");
} else {
const details = selectedProject;
outputElement.innerText = `[Встроенная MBA-Модель] ОЦЕНКА ПРОЕКТА ${details.name}:\n` +
`• CAPEX составляет ${details.cost}, что является допустимым в рамках государственного бюджета.\n` +
`• Экологический показатель равен ${details.rating}. Внедрение технологий снизит риски пыльных бурь на 35%.\n` +
`• Срок окупаемости ${details.roi} приемлем для развития regionalльной инфраструктуры Малого Арала. Проект рекомендован к визированию.`;
showToast("Задействован локальный ИИ-профиль решения.", "info");
}
}
// STEP 6 BOARDROOM SPEECH GENERATOR & PROGRESS TRIGGER
async function runStep6AI() {
const outputElement = document.getElementById('ai-step6-speech');
if (!state.selectedScenario || !SCENARIOS[state.selectedScenario]) {
outputElement.innerText = "Пожалуйста, сначала выберите проект на Шаге 1.";
showToast("Сценарий не задан!", "error");
return;
}
outputElement.innerText = "ИИ формирует речь для презентации Совету Директоров... Пожалуйста, подождите.";
// GAMIFICATION: Mark speech as generated & fully fill Beaker 6!
state.step6SpeechGenerated = true;
updateUIVisibility(); // Instantly fills beaker 06 in the header navigation to 100%
const selectedProject = SCENARIOS[state.selectedScenario];
const sysPrompt = "Вы — профессиональный питч-тренер. Напишите яркую, убедительную речь на 1 минуту для защиты проекта перед инвесторами на русском языке. Будьте энергичны и убедительны.";
const userPrompt = `Проект: ${JSON.stringify(selectedProject)}. Балл теста: ${state.quizScore}. SWOT: S:${state.swotContent.s}. Сфокусируйтесь на получении зеленого инвестирования.`;
const res = await callGeminiAPI(sysPrompt, userPrompt);
if (res) {
outputElement.innerText = res;
showToast("Инвестиционный питч сформирован! Пробирка 06 заполнена! +10 IQ", "success");
} else {
const det = selectedProject;
outputElement.innerText = `УВАЖАЕМЫЕ ЧЛЕНЫ СОВЕТА ДИРЕКТОРОВ И ИНВЕСТОРЫ ООН!\n\n` +
`Сегодня мы представляем проект "${det.name}". С бюджетом всего в ${det.cost} мы решаем историческую экологическую задачу на уровне рейтинга ${det.roi}.\n` +
`Наши сильные стороны очевидны: мы берем под полный контроль сток Сырдарьи и снижаем токсичную соленость воды. Мы зафиксировали SWOT и разработали надежный План Б на случай засухи.\n\n` +
`Мы запрашиваем одобрение лимитов водопользования и выпуск первого транша зеленых бондов. Давайте вместе вернем Аральское море к жизни! Спасибо.`;
showToast("Питч сформирован! Пробирка 06 заполнена на 100%! +10 IQ", "success");
}
updateIQDisplay();
saveStateToStorage();
}
// INITIALIZATION
window.onload = function() {
loadStateFromStorage();
initBeakerWaves();
drawCharts();
initScenarioCards();
updateUIVisibility();
initQuizChart();
resetQuizEngine();
if (synth) {
synth.getVoices();
}
};
</script>
</body>
</html>
Роль: Действуй как Senior Frontend Developer и UX/UI Designer. Твоя задача — создать сложный интерактивный веб-симулятор для преподавателей MBA.
Формат результата: СТРОГО один файл ai-university-2030-simulator.html, содержащий HTML, CSS и JavaScript. ЗАПРЕЩЕНО использовать внешние библиотеки (React, Vue, Tailwind, Bootstrap, jQuery и т.д.). Разрешено использовать только Google Fonts. Код должен работать локально в браузере без сервера.
Название приложения: AI University: 2030 Подзаголовок: Стратегический симулятор цифровой трансформации
1. Визуальный стиль и UI/UX (Критически важно):
Стиль: Cyberpunk, университет будущего, премиальная бизнес-игра.
Фон: Темный градиент (темно-синий, фиолетовый). На фоне должен быть <canvas> с плавно летающими частицами (particles).
Элементы: Glassmorphism (полупрозрачные панели, размытие фона backdrop-filter: blur, тонкие белые рамки).
Акценты: Неоновые цвета (Cyan, Purple, Gold, Red, Green). Кнопки при наведении должны светиться (box-shadow).
Анимации: Плавное появление экранов (fade-in), анимированные прогресс-бары.
Layout: Слева (или сверху на мобильных) — сайдбар с дашбордами 3 команд. Справа — основная игровая зона, которая меняется в зависимости от этапа. Сверху — панель навигации по этапам.
Уведомления: Всплывающие Toast-уведомления в углу экрана (например, "Монеты списаны").
2. Глобальный State и Хранение:
Реализуй сохранение всего состояния игры в localStorage, чтобы при обновлении страницы прогресс не терялся.
Добавь кнопку "Сбросить игру" (очищает localStorage и перезагружает страницу).
Команды (3 шт): Team Innovators, Team Pragmatists, Team Traditionalists. У каждой команды есть кнопка, чтобы сделать её "Активной" (все действия применяются к активной команде).
Метрики каждой команды (от 0 до 100): AI Coins (старт 100, нет лимита), Innovation (50), Faculty Satisfaction (50), Student Satisfaction (50), Academic Integrity (50), University Reputation (50). Метрики отображать как прогресс-бары.
3. Голосовой AI-Ведущий (Web Speech API):
Сделай панель управления голосом в хедере: кнопки "Включить/Выключить голос", "Повторить", ползунок скорости (0.7 - 1.3).
При воспроизведении речи должна анимироваться иконка звуковой волны (3 прыгающих столбика).
Ведущий должен озвучивать итоги раундов в стиле тренера MBA (кратко, энергично, с фокусом на риски и стратегию). Напиши функцию speak(text).
4. Игровые этапы (Навигация через табы):
Этап 0: Введение. Текстовое описание легенды (2030 год, битва за внедрение ИИ) и карточки с описанием 3 команд.
Этап 1: Quiz Challenge. Интерактивный тест из 5 вопросов по базовому ИИ (галлюцинации, промпты, LLM). Один вопрос на экране, кнопки вариантов. При правильном ответе: +5 AI Coins активной команде, зеленая подсветка, объяснение ответа.
Этап 2: Инвестиции. Сетка карточек с инициативами (AI Tutor, Automated Assessment и др.). На карточке: цена в монетах и влияние на метрики (например, Innovation +20, Integrity -10). При нажатии "Купить" монеты списываются, полоски метрик анимированно меняются.
Этап 3: Кризис. Кнопка "Сгенерировать кризис". При нажатии появляется карточка с красной пульсирующей тенью (box-shadow анимация). Случайный кризис (например, "Студенты массово генерируют эссе ИИ"). Предлагается 3 варианта управленческих решений. При выборе метрики команды меняются.
Этап 4: SWOT-Анализ (Drag & Drop + Click). Создай "Банк факторов" (8 заготовленных фраз, например, "Утечка данных", "Гранты на ИИ"). Создай 4 зоны: Strengths, Weaknesses, Opportunities, Threats.
Механика: Факторы можно перетаскивать мышью (Drag&Drop) или кликать на фактор, а затем на зону для перемещения (поддержка мобильных).
Оценка: Кнопка "Оценить". Скрипт должен проверить, правильно ли факторы лежат в зонах. Правильные подсветить зеленым, ошибки красным. Начислить от 0 до 30 AI Coins в зависимости от процента правильных ответов.
Этап 5: Стратегия. Форма с текстовыми полями (Название, Цель, Инициативы, Риски, План). Кнопка "Защитить". Примитивный авто-чекер: начисляет баллы, если поля не пустые, если длина текста больше 100 символов, и если встречаются ключевые слова ("риск", "метрика" и т.д.).
Этап 6: Финальный питч. 3 поля ввода типа number (от 0 до 50 баллов) для ручной оценки ведущим выступления каждой команды.
Этап 7: Финал.
Автоматический расчет Total Score (сумма монет, всех метрик, баллов за SWOT, Стратегию и Питч).
Отрисовка пьедестала почета (1, 2, 3 место) с помощью CSS.
Генерация эффекта Конфетти (через встроенный <canvas>).
Кнопка "Сгенерировать отчет" — создает текстовый блок с анализом сильных и слабых сторон для каждой команды на основе их финальных метрик (если Integrity < 40 — вывести предупреждение о риске репутации и т.д.).
Технические требования к коду:
Пиши чистый, современный JS (ES6+).
В CSS используй CSS-переменные (Custom Properties) для цветов.
Обеспечь адаптивность (Media Queries) — сайдбар должен уходить наверх на мобильных экранах, карточки выстраиваться в одну колонку.
Убедись, что <script> и <style> находятся внутри одного HTML-документа.
Код должен быть полностью рабочим "из коробки". Не используй плейсхолдеры вроде // добавьте код здесь, пиши полную логику.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI University: 2030 | MBA Simulator</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;600;800&display=swap');
:root {
--bg-color: #0b0f19;
--panel-bg: rgba(15, 23, 42, 0.6);
--glass-border: rgba(255, 255, 255, 0.1);
--neon-blue: #00f3ff;
--neon-purple: #bc13fe;
--neon-gold: #ffbe0b;
--neon-red: #ff0055;
--neon-green: #00ff88;
--text-main: #f8fafc;
--text-muted: #94a3b8;
--font-main: 'Montserrat', sans-serif;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: var(--font-main);
background: linear-gradient(135deg, #020617 0%, #170b29 50%, #061e38 100%);
color: var(--text-main);
min-height: 100vh;
overflow-x: hidden;
}
/* Canvas Background */
#particles-canvas {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -1;
}
#confetti-canvas {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 1000;
pointer-events: none;
display: none;
}
/* Glassmorphism Classes */
.glass {
background: var(--panel-bg);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid var(--glass-border);
border-radius: 16px;
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
}
.glass-panel {
padding: 20px;
margin-bottom: 20px;
}
/* Header */
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 30px;
background: rgba(0,0,0,0.4);
border-bottom: 1px solid var(--glass-border);
position: sticky;
top: 0;
z-index: 100;
backdrop-filter: blur(20px);
}
h1 {
font-weight: 800;
font-size: 24px;
background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-transform: uppercase;
letter-spacing: 2px;
}
.subtitle {
font-size: 12px;
color: var(--text-muted);
letter-spacing: 1px;
margin-top: 2px;
}
/* Voice Panel */
.voice-panel {
display: flex;
align-items: center;
gap: 15px;
font-size: 14px;
}
.voice-controls {
display: flex;
gap: 10px;
align-items: center;
}
.voice-indicator {
display: flex;
gap: 3px;
height: 20px;
align-items: flex-end;
opacity: 0.3;
transition: 0.3s;
}
.voice-indicator.active { opacity: 1; }
.voice-bar {
width: 4px;
background: var(--neon-blue);
border-radius: 2px;
animation: none;
}
.voice-indicator.active .voice-bar {
animation: soundWave 0.6s infinite alternate;
}
.voice-indicator.active .voice-bar:nth-child(2) { animation-delay: 0.2s; }
.voice-indicator.active .voice-bar:nth-child(3) { animation-delay: 0.4s; }
@keyframes soundWave {
0% { height: 4px; }
100% { height: 20px; box-shadow: 0 0 10px var(--neon-blue); }
}
/* Controls / Buttons */
button {
background: rgba(255,255,255,0.05);
border: 1px solid var(--glass-border);
color: white;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
font-family: var(--font-main);
font-weight: 600;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
button:hover {
background: rgba(255,255,255,0.15);
box-shadow: 0 0 15px rgba(255,255,255,0.2);
transform: translateY(-2px);
}
button.primary {
border-color: var(--neon-purple);
background: rgba(188, 19, 254, 0.1);
}
button.primary:hover {
background: rgba(188, 19, 254, 0.3);
box-shadow: 0 0 20px var(--neon-purple);
}
button.action {
border-color: var(--neon-blue);
background: rgba(0, 243, 255, 0.1);
}
button.action:hover {
box-shadow: 0 0 20px var(--neon-blue);
background: rgba(0, 243, 255, 0.3);
}
button.danger {
border-color: var(--neon-red);
background: rgba(255, 0, 85, 0.1);
}
button.danger:hover {
box-shadow: 0 0 20px var(--neon-red);
}
/* Top Controls */
.top-controls {
display: flex;
justify-content: center;
gap: 15px;
padding: 20px;
flex-wrap: wrap;
}
/* Main Layout */
.container {
display: grid;
grid-template-columns: 300px 1fr;
gap: 20px;
padding: 20px;
max-width: 1600px;
margin: 0 auto;
}
@media (max-width: 1024px) {
.container { grid-template-columns: 1fr; }
}
/* Team Dashboard */
.teams-sidebar {
display: flex;
flex-direction: column;
gap: 15px;
}
.team-card {
transition: all 0.3s;
}
.team-card.active-team {
border-color: var(--neon-blue);
box-shadow: 0 0 20px rgba(0, 243, 255, 0.2);
}
.team-name {
font-size: 18px;
font-weight: bold;
margin-bottom: 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.team-innovators .team-name { color: var(--neon-blue); }
.team-pragmatists .team-name { color: var(--neon-purple); }
.team-traditionalists .team-name { color: var(--neon-gold); }
.coin-badge {
background: rgba(255, 190, 11, 0.1);
border: 1px solid var(--neon-gold);
padding: 4px 10px;
border-radius: 12px;
font-size: 14px;
color: var(--neon-gold);
box-shadow: 0 0 10px rgba(255, 190, 11, 0.2);
}
/* Progress Bars */
.metric {
margin-bottom: 10px;
font-size: 12px;
}
.metric-header {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
color: var(--text-muted);
}
.progress-bar-bg {
width: 100%;
height: 6px;
background: rgba(255,255,255,0.1);
border-radius: 3px;
overflow: hidden;
}
.progress-bar-fill {
height: 100%;
border-radius: 3px;
transition: width 0.8s cubic-bezier(0.4, 0, 0.2, 1);
background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple));
}
/* Stages Content */
.stage-container {
display: none;
animation: fadeIn 0.5s ease-out forwards;
}
.stage-container.active { display: block; }
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.stage-header {
margin-bottom: 30px;
text-align: center;
}
.stage-header h2 {
font-size: 28px;
color: var(--text-main);
margin-bottom: 10px;
}
.stage-header p {
color: var(--text-muted);
}
/* Select Team to act */
.team-selector {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
}
.team-btn {
opacity: 0.5;
}
.team-btn.active {
opacity: 1;
box-shadow: 0 0 15px currentColor;
}
/* Forms & Inputs */
input, textarea, select {
width: 100%;
background: rgba(0,0,0,0.3);
border: 1px solid var(--glass-border);
color: white;
padding: 12px;
border-radius: 8px;
font-family: var(--font-main);
margin-bottom: 15px;
transition: all 0.3s;
}
input:focus, textarea:focus {
outline: none;
border-color: var(--neon-blue);
box-shadow: 0 0 10px rgba(0,243,255,0.2);
}
/* Cards Layout */
.cards-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
}
.inv-card {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.inv-card h3 {
margin-bottom: 10px;
color: var(--neon-blue);
}
.inv-cost {
font-size: 20px;
color: var(--neon-gold);
font-weight: bold;
margin: 10px 0;
}
.inv-effects {
font-size: 13px;
color: var(--text-muted);
margin-bottom: 15px;
}
.effect-pos { color: var(--neon-green); }
.effect-neg { color: var(--neon-red); }
/* Crisis Alert */
.crisis-alert {
border-color: var(--neon-red);
box-shadow: 0 0 30px rgba(255, 0, 85, 0.4);
animation: pulse-red 2s infinite;
text-align: center;
}
@keyframes pulse-red {
0% { box-shadow: 0 0 15px rgba(255, 0, 85, 0.2); }
50% { box-shadow: 0 0 40px rgba(255, 0, 85, 0.6); }
100% { box-shadow: 0 0 15px rgba(255, 0, 85, 0.2); }
}
.crisis-options {
display: grid;
grid-template-columns: 1fr;
gap: 15px;
margin-top: 20px;
}
/* SWOT Grid */
.swot-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.swot-pool {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 20px;
padding: 15px;
min-height: 80px;
background: rgba(0,0,0,0.3);
border: 1px dashed var(--glass-border);
border-radius: 8px;
}
.swot-item {
background: rgba(255,255,255,0.1);
border: 1px solid var(--neon-blue);
padding: 8px 12px;
border-radius: 8px;
font-size: 13px;
cursor: grab;
user-select: none;
transition: all 0.2s;
}
.swot-item:active { cursor: grabbing; }
.swot-item:hover { background: rgba(0, 243, 255, 0.2); }
.swot-zone {
min-height: 120px;
border: 2px dashed var(--glass-border);
padding: 10px;
border-radius: 8px;
display: flex;
flex-direction: column;
gap: 10px;
transition: background 0.3s;
cursor: pointer;
}
.swot-zone.drag-over {
background: rgba(0, 243, 255, 0.1);
border-color: var(--neon-blue);
}
/* Final Podium */
.podium {
display: flex;
align-items: flex-end;
justify-content: center;
gap: 20px;
margin-top: 50px;
height: 300px;
}
.podium-place {
width: 30%;
text-align: center;
background: rgba(255,255,255,0.05);
border: 1px solid var(--glass-border);
border-bottom: none;
border-radius: 16px 16px 0 0;
padding: 20px;
position: relative;
}
.podium-1 { height: 100%; border-color: var(--neon-gold); background: rgba(255, 190, 11, 0.1); box-shadow: 0 -10px 30px rgba(255, 190, 11, 0.3); z-index: 3;}
.podium-2 { height: 75%; border-color: silver; background: rgba(192, 192, 192, 0.1); z-index: 2;}
.podium-3 { height: 60%; border-color: #cd7f32; background: rgba(205, 127, 50, 0.1); z-index: 1;}
.rank-medal {
font-size: 40px;
margin-bottom: 10px;
}
.total-score { font-size: 24px; font-weight: bold; margin-top: 10px;}
.podium-1 .total-score { color: var(--neon-gold); text-shadow: 0 0 10px var(--neon-gold);}
/* Toast Notifications */
#toast-container {
position: fixed;
bottom: 20px;
right: 20px;
display: flex;
flex-direction: column;
gap: 10px;
z-index: 2000;
}
.toast {
background: rgba(15, 23, 42, 0.9);
border-left: 4px solid var(--neon-blue);
color: white;
padding: 15px 20px;
border-radius: 4px;
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
animation: slideIn 0.3s ease-out forwards, fadeOut 0.5s ease-in 2.5s forwards;
backdrop-filter: blur(5px);
}
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }
/* Utilities */
.hidden { display: none !important; }
.text-center { text-align: center; }
.mt-4 { margin-top: 20px; }
.score-display { font-size: 36px; font-weight: bold; color: var(--neon-purple); text-shadow: 0 0 20px var(--neon-purple); text-align: center; margin: 20px 0;}
/* Quiz specific */
.quiz-option {
display: block;
width: 100%;
text-align: left;
margin-bottom: 10px;
background: rgba(255,255,255,0.05);
border: 1px solid var(--glass-border);
}
.quiz-option:hover { background: rgba(255,255,255,0.15); }
.quiz-feedback { margin-top: 15px; padding: 15px; border-radius: 8px; font-weight: 600; display: none; }
.quiz-feedback.correct { background: rgba(0, 255, 136, 0.2); border: 1px solid var(--neon-green); color: var(--neon-green); text-shadow: 0 0 5px var(--neon-green); }
.quiz-feedback.wrong { background: rgba(255, 0, 85, 0.2); border: 1px solid var(--neon-red); color: var(--neon-red); text-shadow: 0 0 5px var(--neon-red); }
</style>
</head>
<body>
<canvas id="particles-canvas"></canvas>
<canvas id="confetti-canvas"></canvas>
<div id="toast-container"></div>
<header>
<div>
<h1>AI University: 2030</h1>
<div class="subtitle">Стратегический симулятор цифровой трансформации</div>
</div>
<div class="voice-panel glass glass-panel" style="margin: 0; padding: 10px 20px;">
<div class="voice-controls">
<span>🎙️ AI Narrator</span>
<button id="btn-voice-toggle" style="padding: 5px 10px; font-size: 12px;">Включить голос</button>
<button id="btn-voice-repeat" style="padding: 5px 10px; font-size: 12px;">Повторить</button>
<input type="range" id="voice-rate" min="0.7" max="1.3" step="0.1" value="1.0" title="Скорость речи" style="width: 80px; margin: 0;">
</div>
<div class="voice-indicator" id="voice-indicator">
<div class="voice-bar"></div>
<div class="voice-bar"></div>
<div class="voice-bar"></div>
</div>
</div>
</header>
<div class="top-controls glass">
<button id="btn-stage-0" class="action" onclick="setStage(0)">Введение</button>
<button id="btn-stage-1" onclick="setStage(1)">1. Quiz</button>
<button id="btn-stage-2" onclick="setStage(2)">2. Инвестиции</button>
<button id="btn-stage-3" onclick="setStage(3)">3. Кризис</button>
<button id="btn-stage-4" onclick="setStage(4)">4. SWOT</button>
<button id="btn-stage-5" onclick="setStage(5)">5. Стратегия</button>
<button id="btn-stage-6" onclick="setStage(6)">6. Питч</button>
<button id="btn-stage-7" class="primary" onclick="setStage(7)">Финал</button>
<button onclick="resetGame()" class="danger" style="margin-left: auto;">Сбросить игру</button>
</div>
<div class="team-selector glass glass-panel" id="global-team-selector">
<span style="line-height: 40px; margin-right: 15px;">Действующая команда:</span>
<button class="team-btn active" style="color: var(--neon-blue); border-color: var(--neon-blue);" onclick="setActiveTeam('innovators')">Team Innovators</button>
<button class="team-btn" style="color: var(--neon-purple); border-color: var(--neon-purple);" onclick="setActiveTeam('pragmatists')">Team Pragmatists</button>
<button class="team-btn" style="color: var(--neon-gold); border-color: var(--neon-gold);" onclick="setActiveTeam('traditionalists')">Team Traditionalists</button>
</div>
<div class="container">
<!-- SIDEBAR: Dashboards -->
<aside class="teams-sidebar" id="dashboards-container">
<!-- Rendered via JS -->
</aside>
<!-- MAIN CONTENT: Stages -->
<main>
<!-- Stage 0: Intro -->
<section id="stage-0" class="stage-container active glass glass-panel">
<div class="stage-header">
<h2>Игровая легенда</h2>
<p>2030 год. Битва за звание AI-Driven University of the Year</p>
</div>
<p style="line-height: 1.6; margin-bottom: 20px;">
Добро пожаловать в симулятор! Вашему университету предстоит внедрить искусственный интеллект в образовательный процесс.
Ваша цель: повысить качество обучения, справиться с сопротивлением преподавателей и удержать академическую честность.
</p>
<div class="cards-grid">
<div class="glass glass-panel" style="border-color: var(--neon-blue);">
<h3 style="color: var(--neon-blue); margin-bottom: 10px;">Team Innovators</h3>
<p style="font-size: 14px; color: var(--text-muted);">Сторонники быстрых инноваций. Готовы рисковать ради технологического лидерства.</p>
</div>
<div class="glass glass-panel" style="border-color: var(--neon-purple);">
<h3 style="color: var(--neon-purple); margin-bottom: 10px;">Team Pragmatists</h3>
<p style="font-size: 14px; color: var(--text-muted);">Ищут баланс пользы и рисков. Внедряют только проверенные решения.</p>
</div>
<div class="glass glass-panel" style="border-color: var(--neon-gold);">
<h3 style="color: var(--neon-gold); margin-bottom: 10px;">Team Traditionalists</h3>
<p style="font-size: 14px; color: var(--text-muted);">Защитники академических традиций. Фокус на фундаментальном качестве образования.</p>
</div>
</div>
<div class="text-center mt-4">
<button class="primary" style="font-size: 18px; padding: 15px 40px;" onclick="setStage(1)">Начать игру</button>
</div>
</section>
<!-- Stage 1: AI Quiz -->
<section id="stage-1" class="stage-container glass glass-panel">
<div class="stage-header">
<h2>Этап 1. AI Quiz Challenge</h2>
<p>Проверка базовой грамотности. Выберите команду, затем отвечайте. Правильный ответ: +5 AI Coins.</p>
</div>
<div id="quiz-container">
<h3 id="quiz-question" style="margin-bottom: 20px; font-size: 20px;">Загрузка вопроса...</h3>
<div id="quiz-options"></div>
<div id="quiz-feedback" class="quiz-feedback"></div>
<button id="quiz-next-btn" class="action mt-4 hidden" onclick="nextQuizQuestion()">Следующий вопрос</button>
</div>
<div id="quiz-completed" class="hidden text-center">
<h3>Квиз завершен!</h3>
<button class="primary mt-4" onclick="finishStage1()">Озвучить итоги этапа</button>
</div>
</section>
<!-- Stage 2: Investments -->
<section id="stage-2" class="stage-container glass glass-panel">
<div class="stage-header">
<h2>Этап 2. Инвестиционный раунд</h2>
<p>Покупайте инициативы за AI Coins для выбранной команды. Анализируйте влияние на метрики.</p>
</div>
<div class="cards-grid" id="investments-grid">
<!-- Rendered via JS -->
</div>
<div class="text-center mt-4">
<button class="primary" onclick="finishStage2()">Завершить раунд и озвучить итоги</button>
</div>
</section>
<!-- Stage 3: Crisis -->
<section id="stage-3" class="stage-container glass glass-panel">
<div class="stage-header">
<h2>Этап 3. Кризисный раунд</h2>
<p>Случайные события требуют управленческих решений. Выберите команду и сгенерируйте кризис.</p>
</div>
<div class="text-center" id="crisis-generator">
<button class="danger" style="font-size: 20px; padding: 15px 30px;" onclick="generateCrisis()">Сгенерировать кризис</button>
</div>
<div id="crisis-active" class="hidden">
<div class="glass glass-panel crisis-alert">
<h2 id="crisis-title" style="color: white; margin-bottom: 10px;">Внимание: Кризис!</h2>
<p id="crisis-desc" style="font-size: 18px;"></p>
</div>
<div class="crisis-options" id="crisis-options-container">
<!-- Rendered via JS -->
</div>
</div>
</section>
<!-- Stage 4: SWOT -->
<section id="stage-4" class="stage-container glass glass-panel">
<div class="stage-header">
<h2>Этап 4. SWOT-анализ</h2>
<p>Распределите факторы влияния ИИ по матрице SWOT. (Можно перетаскивать мышью или кликать сначала на фактор, а затем на зону).</p>
</div>
<div style="margin-bottom: 10px; color: var(--text-muted); font-size: 14px;">Банк факторов (распределите все карточки):</div>
<div class="swot-pool" id="swot-pool" ondrop="drop(event)" ondragover="allowDrop(event)" onclick="handleZoneClick(event)" data-zone="pool">
<!-- Rendered via JS -->
</div>
<div class="swot-grid">
<div class="swot-box glass glass-panel" style="margin-bottom: 0;">
<label style="color: var(--neon-green); font-weight: bold; display:block; margin-bottom: 10px;">Strengths (Сильные стороны)</label>
<div class="swot-zone" id="swot-s" ondrop="drop(event)" ondragover="allowDrop(event)" onclick="handleZoneClick(event)" data-zone="S"></div>
</div>
<div class="swot-box glass glass-panel" style="margin-bottom: 0;">
<label style="color: var(--neon-red); font-weight: bold; display:block; margin-bottom: 10px;">Weaknesses (Слабые стороны)</label>
<div class="swot-zone" id="swot-w" ondrop="drop(event)" ondragover="allowDrop(event)" onclick="handleZoneClick(event)" data-zone="W"></div>
</div>
<div class="swot-box glass glass-panel" style="margin-bottom: 0;">
<label style="color: var(--neon-blue); font-weight: bold; display:block; margin-bottom: 10px;">Opportunities (Возможности)</label>
<div class="swot-zone" id="swot-o" ondrop="drop(event)" ondragover="allowDrop(event)" onclick="handleZoneClick(event)" data-zone="O"></div>
</div>
<div class="swot-box glass glass-panel" style="margin-bottom: 0;">
<label style="color: var(--neon-gold); font-weight: bold; display:block; margin-bottom: 10px;">Threats (Угрозы)</label>
<div class="swot-zone" id="swot-t" ondrop="drop(event)" ondragover="allowDrop(event)" onclick="handleZoneClick(event)" data-zone="T"></div>
</div>
</div>
<div class="text-center mt-4">
<button class="action" onclick="evaluateSWOT()">Оценить распределение</button>
<button class="danger" onclick="initSWOT()" style="margin-left: 15px;">Сбросить доску</button>
</div>
<div id="swot-result" class="hidden text-center mt-4 glass glass-panel">
<h3>Оценка SWOT: <span id="swot-score" class="score-display">0</span>/100</h3>
<p id="swot-feedback" style="margin: 10px 0; color: var(--text-main); font-size: 18px;"></p>
<p>Бонус: <span id="swot-bonus" style="color: var(--neon-gold); font-weight: bold;">+0 AI Coins</span></p>
<button class="primary mt-4" onclick="finishStage4()">Озвучить итоги SWOT</button>
</div>
</section>
<!-- Stage 5: Strategy -->
<section id="stage-5" class="stage-container glass glass-panel">
<div class="stage-header">
<h2>Этап 5. AI Strategy Sprint</h2>
<p>Разработайте стратегию трансформации для вашей команды.</p>
</div>
<div class="glass glass-panel" style="background: rgba(0,0,0,0.2);">
<label>Название стратегии:</label>
<input type="text" id="strat-name" placeholder="Например: AI-First Campus">
<label>Главная цель внедрения ИИ:</label>
<input type="text" id="strat-goal" placeholder="Ваша амбициозная цель">
<label>Три ключевые AI-инициативы:</label>
<textarea id="strat-initiatives" rows="3" placeholder="1. ... 2. ... 3. ..."></textarea>
<label>Основной KPI:</label>
<input type="text" id="strat-kpi" placeholder="Как мы измерим успех?">
<label>Основной риск и митигация:</label>
<input type="text" id="strat-risk" placeholder="Главная угроза и план защиты">
<label>План на первые 90 дней:</label>
<textarea id="strat-plan" rows="2" placeholder="Краткие шаги"></textarea>
</div>
<div class="text-center mt-4">
<button class="action" onclick="evaluateStrategy()">Защитить стратегию</button>
</div>
<div id="strat-result" class="hidden text-center mt-4 glass glass-panel">
<h3>Оценка стратегии: <span id="strat-score" class="score-display">0</span>/100</h3>
<div style="display: flex; justify-content: space-around; font-size: 14px; margin: 15px 0;">
<div style="color: var(--neon-green)">Сильно: <span id="strat-strong"></span></div>
<div style="color: var(--neon-red)">Улучшить: <span id="strat-weak"></span></div>
</div>
<button class="primary mt-4" onclick="finishStage5()">Озвучить итоги стратегии</button>
</div>
</section>
<!-- Stage 6: Pitch -->
<section id="stage-6" class="stage-container glass glass-panel">
<div class="stage-header">
<h2>Этап 6. Финальный питч</h2>
<p>Ведущий оценивает выступления команд (от 0 до 50 баллов).</p>
</div>
<div class="cards-grid">
<div class="glass glass-panel text-center">
<h3 style="color: var(--neon-blue);">Innovators</h3>
<input type="number" id="pitch-innovators" min="0" max="50" value="0" style="font-size: 24px; text-align: center;">
</div>
<div class="glass glass-panel text-center">
<h3 style="color: var(--neon-purple);">Pragmatists</h3>
<input type="number" id="pitch-pragmatists" min="0" max="50" value="0" style="font-size: 24px; text-align: center;">
</div>
<div class="glass glass-panel text-center">
<h3 style="color: var(--neon-gold);">Traditionalists</h3>
<input type="number" id="pitch-traditionalists" min="0" max="50" value="0" style="font-size: 24px; text-align: center;">
</div>
</div>
<div class="text-center mt-4">
<button class="primary" onclick="savePitchScores()">Сохранить оценки и перейти к финалу</button>
</div>
</section>
<!-- Final Rankings -->
<section id="stage-7" class="stage-container glass glass-panel">
<div class="stage-header">
<h2 style="font-size: 40px; color: var(--neon-gold); text-shadow: 0 0 20px var(--neon-gold);">ФИНАЛ</h2>
<p>Подведение итогов конкурса «AI-Driven University of the Year»</p>
</div>
<div class="podium" id="final-podium">
<!-- Rendered via JS -->
</div>
<div class="text-center mt-4">
<button class="action" onclick="generateFinalReport()">Сгенерировать аналитический отчет</button>
<button class="primary" onclick="announceWinner()">Озвучить победителя</button>
</div>
<div id="final-report" class="glass glass-panel mt-4 hidden" style="text-align: left;">
<!-- Rendered via JS -->
</div>
</section>
</main>
</div>
<script>
/* --- STATE & DATA --- */
const defaultState = {
currentStage: 0,
activeTeam: 'innovators',
voiceEnabled: false,
teams: {
innovators: { id: 'innovators', name: 'Team Innovators', coins: 100, innovation: 50, faculty: 50, student: 50, integrity: 50, reputation: 50, swot: 0, strategy: 0, pitch: 0 },
pragmatists: { id: 'pragmatists', name: 'Team Pragmatists', coins: 100, innovation: 50, faculty: 50, student: 50, integrity: 50, reputation: 50, swot: 0, strategy: 0, pitch: 0 },
traditionalists: { id: 'traditionalists', name: 'Team Traditionalists', coins: 100, innovation: 50, faculty: 50, student: 50, integrity: 50, reputation: 50, swot: 0, strategy: 0, pitch: 0 }
},
quizIndex: 0
};
let gameState = JSON.parse(localStorage.getItem('aiUnivState')) || JSON.parse(JSON.stringify(defaultState));
let lastSpeechText = "";
let synth = window.speechSynthesis;
const metricsConfig = [
{ key: 'innovation', label: 'Innovation', color: 'var(--neon-blue)' },
{ key: 'faculty', label: 'Faculty Sat.', color: 'var(--neon-purple)' },
{ key: 'student', label: 'Student Sat.', color: 'var(--neon-green)' },
{ key: 'integrity', label: 'Acad. Integrity', color: 'var(--text-main)' },
{ key: 'reputation', label: 'Reputation', color: 'var(--neon-gold)' }
];
/* --- INIT --- */
function init() {
renderDashboards();
setStage(gameState.currentStage);
setActiveTeam(gameState.activeTeam);
initParticles();
initQuiz();
initInvestments();
initSWOT();
if(gameState.voiceEnabled) {
document.getElementById('btn-voice-toggle').textContent = "Выключить голос";
document.getElementById('btn-voice-toggle').classList.add('action');
}
}
function saveState() {
localStorage.setItem('aiUnivState', JSON.stringify(gameState));
renderDashboards();
}
function resetGame() {
if(confirm('Вы уверены? Весь прогресс будет потерян.')) {
gameState = JSON.parse(JSON.stringify(defaultState));
saveState();
location.reload();
}
}
function showToast(msg) {
const container = document.getElementById('toast-container');
const toast = document.createElement('div');
toast.className = 'toast';
toast.textContent = msg;
container.appendChild(toast);
setTimeout(() => toast.remove(), 3000);
}
/* --- UI NAVIGATION --- */
function setStage(stageId) {
gameState.currentStage = stageId;
saveState();
document.querySelectorAll('.stage-container').forEach(el => el.classList.remove('active'));
document.getElementById(`stage-${stageId}`).classList.add('active');
document.querySelectorAll('.top-controls button').forEach(el => {
el.style.opacity = '0.5';
el.style.boxShadow = 'none';
});
const activeBtn = document.getElementById(`btn-stage-${stageId}`);
if(activeBtn) {
activeBtn.style.opacity = '1';
activeBtn.style.boxShadow = '0 0 15px currentColor';
}
if(stageId === 7) renderPodium();
}
function setActiveTeam(teamId) {
gameState.activeTeam = teamId;
saveState();
document.querySelectorAll('.team-btn').forEach(btn => btn.classList.remove('active'));
const index = ['innovators', 'pragmatists', 'traditionalists'].indexOf(teamId);
document.querySelectorAll('.team-btn')[index].classList.add('active');
renderDashboards();
}
/* --- DASHBOARDS --- */
function renderDashboards() {
const container = document.getElementById('dashboards-container');
container.innerHTML = '';
Object.values(gameState.teams).forEach(team => {
const isActive = team.id === gameState.activeTeam ? 'active-team' : '';
let html = `
<div class="glass glass-panel team-card team-${team.id} ${isActive}" onclick="setActiveTeam('${team.id}')" style="cursor: pointer;">
<div class="team-name">
${team.name}
<span class="coin-badge">💰 ${team.coins}</span>
</div>
`;
metricsConfig.forEach(m => {
const val = team[m.key];
html += `
<div class="metric">
<div class="metric-header">
<span>${m.label}</span>
<span>${val}/100</span>
</div>
<div class="progress-bar-bg">
<div class="progress-bar-fill" style="width: ${val}%; background: ${m.color}"></div>
</div>
</div>
`;
});
html += `</div>`;
container.innerHTML += html;
});
}
function updateMetric(teamId, metric, change) {
if(metric === 'coins') {
gameState.teams[teamId].coins += change;
} else {
let newVal = gameState.teams[teamId][metric] + change;
newVal = Math.max(0, Math.min(100, newVal)); // clamp 0-100
gameState.teams[teamId][metric] = newVal;
}
saveState();
}
/* --- VOICE NARRATOR --- */
document.getElementById('btn-voice-toggle').addEventListener('click', function() {
gameState.voiceEnabled = !gameState.voiceEnabled;
saveState();
this.textContent = gameState.voiceEnabled ? "Выключить голос" : "Включить голос";
this.classList.toggle('action', gameState.voiceEnabled);
if(gameState.voiceEnabled) {
// Dummy speak to initialize audio context on user interaction
let u = new SpeechSynthesisUtterance("");
synth.speak(u);
showToast("Голос включен");
} else {
synth.cancel();
showToast("Голос выключен");
}
});
document.getElementById('btn-voice-repeat').addEventListener('click', () => {
if(lastSpeechText) speak(lastSpeechText, true);
});
function speak(text, force = false) {
lastSpeechText = text;
if (!gameState.voiceEnabled && !force) return;
synth.cancel(); // Stop current speech
let utterance = new SpeechSynthesisUtterance(text);
utterance.lang = 'ru-RU';
utterance.rate = document.getElementById('voice-rate').value || 1.0;
utterance.pitch = 0.9; // Slightly deeper for narrator vibe
utterance.onstart = () => document.getElementById('voice-indicator').classList.add('active');
utterance.onend = () => document.getElementById('voice-indicator').classList.remove('active');
utterance.onerror = () => document.getElementById('voice-indicator').classList.remove('active');
synth.speak(utterance);
}
/* --- STAGE 1: QUIZ --- */
const quizData = [
{ q: "Что такое Generative AI?", opts: ["Система, копирующая файлы", "ИИ, создающий новый контент (текст, код, изображения)", "Антивирусная программа", "Протокол интернета"], ans: 1, exp: "Generative AI генерирует новые данные на основе паттернов из обучающей выборки." },
{ q: "Что такое Prompt?", opts: ["Ошибка в коде", "Платный тариф", "Текстовый запрос или инструкция для нейросети", "Вид памяти"], ans: 2, exp: "Промпт — это ваш интерфейс управления нейросетью." },
{ q: "Что такое 'галлюцинация' ИИ?", opts: ["Визуальный эффект в интерфейсе", "Уверенная выдача ложной или несуществующей информации", "Зависание сервера", "Процесс обучения"], ans: 1, exp: "LLM могут 'фантазировать', поэтому экспертная проверка ответов обязательна." },
{ q: "Какой инструмент от Google является LLM?", opts: ["TensorFlow", "Chrome", "Gemini", "Android"], ans: 2, exp: "Gemini — это флагманская мультимодальная модель от Google." },
{ q: "Как ИИ влияет на академическую честность?", opts: ["Автоматически делает всех честными", "Требует пересмотра политик и методов оценки, так как студенты могут генерировать эссе", "Никак не влияет", "Запрещает списывать аппаратно"], ans: 1, exp: "Главный вызов — переход от проверки результата к оценке процесса." }
]; // Shortened to 5 for simulation flow
function initQuiz() {
if(gameState.quizIndex >= quizData.length) {
showQuizEnd();
return;
}
renderQuestion();
}
function renderQuestion() {
const q = quizData[gameState.quizIndex];
document.getElementById('quiz-question').textContent = `Вопрос ${gameState.quizIndex + 1}/${quizData.length}: ${q.q}`;
let html = '';
q.opts.forEach((opt, idx) => {
html += `<button class="quiz-option" onclick="checkAnswer(${idx})">${idx + 1}. ${opt}</button>`;
});
document.getElementById('quiz-options').innerHTML = html;
const fb = document.getElementById('quiz-feedback');
fb.style.display = 'none';
fb.className = 'quiz-feedback';
document.getElementById('quiz-next-btn').classList.add('hidden');
}
function checkAnswer(idx) {
const q = quizData[gameState.quizIndex];
const fb = document.getElementById('quiz-feedback');
const btns = document.querySelectorAll('.quiz-option');
btns.forEach(b => b.disabled = true); // lock
if(idx === q.ans) {
fb.textContent = `✅ Правильно! ${q.exp}`;
fb.classList.add('correct');
updateMetric(gameState.activeTeam, 'coins', 5);
showToast(`+5 AI Coins для ${gameState.teams[gameState.activeTeam].name}`);
} else {
fb.textContent = `❌ Ошибка. Правильный ответ: ${q.opts[q.ans]}. ${q.exp}`;
fb.classList.add('wrong');
}
fb.style.display = 'block';
document.getElementById('quiz-next-btn').classList.remove('hidden');
}
function nextQuizQuestion() {
gameState.quizIndex++;
saveState();
if(gameState.quizIndex >= quizData.length) showQuizEnd();
else renderQuestion();
}
function showQuizEnd() {
document.getElementById('quiz-container').classList.add('hidden');
document.getElementById('quiz-completed').classList.remove('hidden');
}
function finishStage1() {
speak("Квиз завершен. Команды продемонстрировали базовое понимание технологий. Важно помнить, что знание терминов — лишь первый шаг. Настоящая трансформация начинается с применения. Переходим к инвестиционному раунду.");
}
/* --- STAGE 2: INVESTMENTS --- */
const investments = [
{ id: 'tutor', name: 'AI Tutor для студентов', cost: 30, eff: [{k:'innovation', v:20}, {k:'student', v:15}, {k:'integrity', v:-5}] },
{ id: 'assist', name: 'AI Assistant преподавателя', cost: 20, eff: [{k:'faculty', v:20}, {k:'innovation', v:10}] },
{ id: 'assess', name: 'Automated Assessment', cost: 25, eff: [{k:'faculty', v:15}, {k:'integrity', v:-10}] },
{ id: 'sim', name: 'AI Simulators', cost: 35, eff: [{k:'student', v:20}, {k:'innovation', v:20}] },
{ id: 'analytics', name: 'Learning Analytics', cost: 20, eff: [{k:'reputation', v:15}] },
{ id: 'policy', name: 'AI Integrity Policy', cost: 15, eff: [{k:'integrity', v:20}, {k:'innovation', v:-5}] }
];
function initInvestments() {
const grid = document.getElementById('investments-grid');
let html = '';
investments.forEach(inv => {
let effHtml = '';
inv.eff.forEach(e => {
const label = metricsConfig.find(m => m.key === e.k).label;
const sign = e.v > 0 ? '+' : '';
const cls = e.v > 0 ? 'effect-pos' : 'effect-neg';
effHtml += `<div class="${cls}">${label}: ${sign}${e.v}</div>`;
});
html += `
<div class="glass glass-panel inv-card">
<h3>${inv.name}</h3>
<div class="inv-cost">💰 ${inv.cost}</div>
<div class="inv-effects">${effHtml}</div>
<button class="action" onclick="buyInvestment('${inv.id}')">Купить для ${gameState.activeTeam}</button>
</div>
`;
});
grid.innerHTML = html;
}
function buyInvestment(invId) {
const inv = investments.find(i => i.id === invId);
const team = gameState.teams[gameState.activeTeam];
if(team.coins < inv.cost) {
showToast('❌ Недостаточно AI Coins!');
return;
}
updateMetric(team.id, 'coins', -inv.cost);
inv.eff.forEach(e => updateMetric(team.id, e.k, e.v));
showToast(`✅ ${inv.name} внедрено в ${team.name}!`);
}
function finishStage2() {
speak("Инвестиционный раунд показал: побеждает не тот, кто покупает больше инструментов, а тот, кто инвестирует стратегически, балансируя инновации и риски для репутации.");
}
/* --- STAGE 3: CRISIS --- */
const crises = [
{
title: "Массовое использование ИИ для эссе",
desc: "Студенты сдают идеально написанные эссе, сгенерированные ИИ. Преподаватели в панике.",
opts: [
{ t: "Инновационное: Разрешить ИИ, но оценивать промпты и фактчекинг", eff: [{k:'innovation', v:15}, {k:'student', v:10}, {k:'faculty', v:-10}] },
{ t: "Осторожное: Запретить ИИ и купить антиплагиат", eff: [{k:'integrity', v:20}, {k:'student', v:-15}, {k:'innovation', v:-10}] },
{ t: "Сбалансированное: Ввести устные защиты эссе", eff: [{k:'integrity', v:10}, {k:'faculty', v:-5}, {k:'reputation', v:10}] }
]
},
{
title: "Протест преподавателей",
desc: "Профсоюз требует запретить Automated Assessment, опасаясь увольнений.",
opts: [
{ t: "Инновационное: Заменить недовольных на AI-энтузиастов", eff: [{k:'innovation', v:20}, {k:'faculty', v:-30}, {k:'reputation', v:-10}] },
{ t: "Осторожное: Отказаться от автоматизации", eff: [{k:'faculty', v:20}, {k:'innovation', v:-20}] },
{ t: "Сбалансированное: Обучить преподавателей роли 'ИИ-кураторов'", eff: [{k:'faculty', v:10}, {k:'reputation', v:15}, {k:'coins', v:-10}] }
]
}
];
function generateCrisis() {
document.getElementById('crisis-generator').classList.add('hidden');
document.getElementById('crisis-active').classList.remove('hidden');
const c = crises[Math.floor(Math.random() * crises.length)];
document.getElementById('crisis-title').textContent = c.title;
document.getElementById('crisis-desc').textContent = c.desc;
let html = '';
c.opts.forEach((o, idx) => {
html += `<button class="action" style="text-align:left; padding: 15px;" onclick='resolveCrisis(${JSON.stringify(o.eff)})'>${idx+1}. ${o.t}</button>`;
});
document.getElementById('crisis-options-container').innerHTML = html;
speak(`Внимание, кризисная ситуация для ${gameState.teams[gameState.activeTeam].name}: ${c.title}. Принимайте решение.`);
}
function resolveCrisis(effects) {
effects.forEach(e => updateMetric(gameState.activeTeam, e.k, e.v));
showToast("Решение принято. Метрики обновлены.");
document.getElementById('crisis-active').classList.add('hidden');
document.getElementById('crisis-generator').classList.remove('hidden');
speak("Кризис разрешен. Управленческие решения всегда имеют цену: улучшая одно, мы часто жертвуем другим. Оцените изменения на дашборде.");
}
/* --- STAGE 4: SWOT --- */
const swotFactorsList = [
{ id: 'f1', text: "Сильная IT-кафедра", correct: 'S' },
{ id: 'f2', text: "Наличие собственного дата-центра", correct: 'S' },
{ id: 'f3', text: "Устаревшая система LMS", correct: 'W' },
{ id: 'f4', text: "Высокая бюрократическая нагрузка ППС", correct: 'W' },
{ id: 'f5', text: "Государственные гранты на цифровизацию", correct: 'O' },
{ id: 'f6', text: "Партнерство с EdTech компаниями", correct: 'O' },
{ id: 'f7', text: "Массовая генерация эссе (падение качества)", correct: 'T' },
{ id: 'f8', text: "Утечка персональных данных студентов", correct: 'T' }
];
let selectedSwotItem = null;
function initSWOT() {
document.getElementById('swot-s').innerHTML = '';
document.getElementById('swot-w').innerHTML = '';
document.getElementById('swot-o').innerHTML = '';
document.getElementById('swot-t').innerHTML = '';
const pool = document.getElementById('swot-pool');
pool.innerHTML = '';
swotFactorsList.forEach(f => {
const el = document.createElement('div');
el.className = 'swot-item';
el.id = f.id;
el.draggable = true;
el.ondragstart = drag;
el.onclick = handleSwotItemClick;
el.textContent = f.text;
el.dataset.correct = f.correct;
pool.appendChild(el);
});
document.getElementById('swot-result').classList.add('hidden');
selectedSwotItem = null;
}
// Drag & Drop Handlers (Desktop)
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
const data = ev.dataTransfer.getData("text");
const item = document.getElementById(data);
const zone = ev.target.closest('[data-zone]');
if(zone && item) {
zone.appendChild(item);
item.style.boxShadow = 'none';
item.style.borderColor = 'var(--neon-blue)';
}
}
// Click Handlers (Mobile friendly)
function handleSwotItemClick(ev) {
ev.stopPropagation(); // prevent zone click
document.querySelectorAll('.swot-item').forEach(el => el.style.boxShadow = 'none');
if (selectedSwotItem === ev.target) {
selectedSwotItem = null; // deselect if clicked again
} else {
selectedSwotItem = ev.target;
selectedSwotItem.style.boxShadow = '0 0 15px var(--neon-gold)';
}
}
function handleZoneClick(ev) {
const zone = ev.currentTarget;
if(selectedSwotItem && zone.dataset.zone) {
zone.appendChild(selectedSwotItem);
selectedSwotItem.style.boxShadow = 'none';
selectedSwotItem.style.borderColor = 'var(--neon-blue)';
selectedSwotItem = null;
}
}
function evaluateSWOT() {
let correctCount = 0;
let total = swotFactorsList.length;
swotFactorsList.forEach(f => {
const el = document.getElementById(f.id);
const parentZone = el.closest('[data-zone]').dataset.zone;
if(parentZone === f.correct) {
correctCount++;
el.style.borderColor = 'var(--neon-green)';
el.style.backgroundColor = 'rgba(0, 255, 136, 0.1)';
} else if (parentZone !== 'pool') {
el.style.borderColor = 'var(--neon-red)';
el.style.backgroundColor = 'rgba(255, 0, 85, 0.1)';
} else {
el.style.borderColor = 'var(--text-muted)';
el.style.backgroundColor = 'rgba(255,255,255,0.1)';
}
});
let unassigned = document.getElementById('swot-pool').children.length;
if (unassigned > 0) {
showToast("⚠️ Распределите все факторы из банка!");
return;
}
let score = Math.round((correctCount / total) * 100);
document.getElementById('swot-score').textContent = score;
let bonus = 0;
if(score >= 80) bonus = 30;
else if(score >= 60) bonus = 20;
else if(score >= 40) bonus = 10;
document.getElementById('swot-bonus').textContent = `+${bonus} AI Coins`;
gameState.teams[gameState.activeTeam].swot = score;
updateMetric(gameState.activeTeam, 'coins', bonus);
document.getElementById('swot-result').classList.remove('hidden');
if(score === 100) {
document.getElementById('swot-feedback').textContent = "Идеальное распределение!";
speak("SWOT-анализ выполнен безупречно. Команда точно понимает внутренние ресурсы и внешние рыночные тренды.");
} else if(score >= 60) {
document.getElementById('swot-feedback').textContent = "Хороший анализ, но есть неточности в оценке факторов.";
speak("SWOT-анализ завершен. Команды уловили общую картину, но стратегические ошибки в распределении угроз могут стоить университету репутации.");
} else {
document.getElementById('swot-feedback').textContent = "Факторы распределены неверно. Стратегическое видение отсутствует.";
speak("Анализ выявил слабую подготовку команды. Путаница между внутренними слабостями и внешними угрозами недопустима на уровне топ-менеджмента.");
}
}
function finishStage4() {
speak("Оценка SWOT завершена. Переходим к разработке стратегии. Теперь, понимая свои сильные стороны и угрозы рынка, вы должны предложить четкий план действий.");
}
/* --- STAGE 5: STRATEGY --- */
function evaluateStrategy() {
let score = 0;
const name = document.getElementById('strat-name').value;
const goal = document.getElementById('strat-goal').value;
const initis = document.getElementById('strat-initiatives').value;
const kpi = document.getElementById('strat-kpi').value;
const risk = document.getElementById('strat-risk').value;
const plan = document.getElementById('strat-plan').value;
if(name && goal && initis && kpi && risk && plan) score += 40; // Base completion
if(initis.length > 100) score += 15; // Details
if(risk.toLowerCase().includes('митигац') || risk.toLowerCase().includes('решени') || risk.toLowerCase().includes('план')) score += 15;
if(kpi.match(/\d/)) score += 15; // KPIs usually have numbers (metrics)
if(plan.includes('1') && plan.includes('2')) score += 15; // Structure
document.getElementById('strat-score').textContent = score;
gameState.teams[gameState.activeTeam].strategy = score;
saveState();
document.getElementById('strat-strong').textContent = score > 60 ? "Структурность, KPI" : "Наличие базовых идей";
document.getElementById('strat-weak').textContent = score > 80 ? "Мало слабых зон" : "Недостаток конкретики и метрик";
document.getElementById('strat-result').classList.remove('hidden');
}
function finishStage5() {
speak("Стратегия сформирована. Помните: стратегия без исполнения — это галлюцинация, прямо как у ранних нейросетей. Важен план на 90 дней. Готовьтесь к финальному питчу.");
}
/* --- STAGE 6: PITCH --- */
function savePitchScores() {
gameState.teams.innovators.pitch = parseInt(document.getElementById('pitch-innovators').value) || 0;
gameState.teams.pragmatists.pitch = parseInt(document.getElementById('pitch-pragmatists').value) || 0;
gameState.teams.traditionalists.pitch = parseInt(document.getElementById('pitch-traditionalists').value) || 0;
saveState();
setStage(7);
}
/* --- STAGE 7: FINAL --- */
function calculateTotal(team) {
return team.coins + team.innovation + team.faculty + team.student + team.integrity + team.reputation + team.swot + team.strategy + team.pitch;
}
function renderPodium() {
const teamsArr = Object.values(gameState.teams).map(t => {
t.total = calculateTotal(t);
return t;
}).sort((a, b) => b.total - a.total);
const podiumHtml = `
<div class="podium-place podium-2">
<div class="rank-medal">🥈</div>
<h3>${teamsArr[1].name}</h3>
<div class="subtitle">AI Strategy Builder</div>
<div class="total-score">${teamsArr[1].total}</div>
</div>
<div class="podium-place podium-1">
<div class="rank-medal">🏆</div>
<h2>${teamsArr[0].name}</h2>
<div class="subtitle" style="color: var(--neon-gold); font-weight: bold;">AI Transformation Champion</div>
<div class="total-score">${teamsArr[0].total}</div>
</div>
<div class="podium-place podium-3">
<div class="rank-medal">🥉</div>
<h3>${teamsArr[2].name}</h3>
<div class="subtitle">AI Explorer</div>
<div class="total-score">${teamsArr[2].total}</div>
</div>
`;
document.getElementById('final-podium').innerHTML = podiumHtml;
triggerConfetti();
}
function announceWinner() {
const teamsArr = Object.values(gameState.teams).sort((a, b) => calculateTotal(b) - calculateTotal(a));
speak(`Симулятор завершен. Третье место — ${teamsArr[2].name}. Второе место — ${teamsArr[1].name}. И абсолютный чемпион цифровой трансформации — ${teamsArr[0].name}, с результатом ${teamsArr[0].total} баллов. Поздравляем победителей!`);
}
function generateFinalReport() {
const reportDiv = document.getElementById('final-report');
let html = '<h3 style="color:var(--neon-blue); margin-bottom: 20px;">Аналитический отчет по внедрению ИИ</h3>';
Object.values(gameState.teams).forEach(t => {
const total = calculateTotal(t);
let readiness = total > 400 ? "Высокая" : (total > 300 ? "Средняя" : "Низкая");
let risk = t.integrity < 40 ? "Критический (Академ. честность под угрозой)" : "Контролируемый";
html += `
<div style="margin-bottom: 20px; padding: 15px; border-left: 3px solid var(--neon-purple); background: rgba(0,0,0,0.2);">
<h4 style="color: white; margin-bottom: 10px;">${t.name} (Total: ${total})</h4>
<p><b>Готовность к внедрению ИИ:</b> ${readiness}</p>
<p><b>Уровень риска:</b> ${risk}</p>
<p><b>Сильные стороны:</b> ${t.innovation > 60 ? 'Инновационность, ' : ''}${t.student > 60 ? 'Фокус на студентов, ' : ''}${t.faculty > 60 ? 'Поддержка ППС' : ''}</p>
<p><b>Слабые стороны:</b> ${t.innovation < 40 ? 'Отставание в технологиях, ' : ''}${t.integrity < 50 ? 'Проблемы с честностью, ' : ''}${t.reputation < 50 ? 'Репутационные угрозы' : ''}</p>
<p><b>Рекомендация на 90 дней:</b> ${t.integrity < 50 ? 'Срочно разработать AI Policy.' : 'Масштабировать успешные практики.'}</p>
</div>
`;
});
reportDiv.innerHTML = html;
reportDiv.classList.remove('hidden');
}
/* --- VISUAL EFFECTS (Canvas) --- */
// Particles
function initParticles() {
const canvas = document.getElementById('particles-canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const particlesArray = [];
const numberOfParticles = 70;
class Particle {
constructor() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.size = Math.random() * 2 + 0.5;
this.speedX = Math.random() * 1 - 0.5;
this.speedY = Math.random() * 1 - 0.5;
this.color = Math.random() > 0.5 ? 'rgba(0, 243, 255, 0.3)' : 'rgba(188, 19, 254, 0.3)';
}
update() {
this.x += this.speedX;
this.y += this.speedY;
if (this.x < 0 || this.x > canvas.width) this.speedX *= -1;
if (this.y < 0 || this.y > canvas.height) this.speedY *= -1;
}
draw() {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
}
}
for (let i = 0; i < numberOfParticles; i++) particlesArray.push(new Particle());
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
particlesArray.forEach(p => { p.update(); p.draw(); });
requestAnimationFrame(animate);
}
animate();
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
});
}
// Confetti
function triggerConfetti() {
const canvas = document.getElementById('confetti-canvas');
canvas.style.display = 'block';
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const confettiArray = [];
const colors = ['#ffbe0b', '#fb5607', '#ff006e', '#8338ec', '#3a86ff', '#00f3ff'];
for (let i = 0; i < 150; i++) {
confettiArray.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height - canvas.height,
w: Math.random() * 10 + 5,
h: Math.random() * 10 + 5,
color: colors[Math.floor(Math.random() * colors.length)],
speed: Math.random() * 3 + 2,
angle: Math.random() * 360,
spin: Math.random() * 0.2 - 0.1
});
}
let animationId;
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
let allDown = true;
confettiArray.forEach(c => {
c.y += c.speed;
c.angle += c.spin;
ctx.save();
ctx.translate(c.x, c.y);
ctx.rotate(c.angle);
ctx.fillStyle = c.color;
ctx.fillRect(-c.w/2, -c.h/2, c.w, c.h);
ctx.restore();
if (c.y < canvas.height) allDown = false;
});
if (!allDown) {
animationId = requestAnimationFrame(render);
} else {
canvas.style.display = 'none';
}
}
render();
// Stop after 5 seconds to not eat performance
setTimeout(() => {
cancelAnimationFrame(animationId);
canvas.style.display = 'none';
}, 5000);
}
// Run Init
window.onload = init;
</script>
</body>
</html>
Оцените свой вклад и работу команды — это поможет вам лучше понять свой уровень и получить честную обратную связь от группы.
Поделитесь инсайтами и оцените урок — ваши ответы помогут улучшить курс и сделать его более практичным и полезным.
До следующего занятия Вам необходимо
Протестировать и запустить сайт.
Результат работы
Сайт заущен.