This repository has been archived on 2026-11-14. You can view files and clone it, but cannot push or open issues or pull requests.
gitea-pages/index.html

1547 lines
48 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
<title>Vibe Coding Воркшоп — Казахтелеком</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,400;0,500;1,400&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--blue: #0066cc;
--blue-hover: #0055b3;
--blue-link: #0058b3;
--bg: #efefef;
--card-neutral: #e3e3e3;
--text: #000;
--text-65: rgba(0,0,0,0.65);
--text-55: rgba(0,0,0,0.55);
--text-45: rgba(0,0,0,0.45);
--border: rgba(0,0,0,0.08);
--hover: rgba(0,0,0,0.06);
--hover-light: rgba(0,0,0,0.03);
--positive: #059669;
--positive-bg: #dcfce7;
--negative: #dc2626;
}
html { scroll-behavior: smooth; }
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #fff;
min-height: 100dvh;
padding: 12px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: var(--text);
}
/* ── FRAME ── */
.frame {
min-height: calc(100dvh - 24px);
display: flex;
flex-direction: column;
gap: 12px;
}
/* ── NAV ── */
nav {
height: 64px;
background: var(--bg);
border-radius: 16px;
padding: 0 20px;
display: flex;
align-items: center;
position: sticky;
top: 12px;
z-index: 50;
}
.nav-inner {
display: flex;
align-items: center;
gap: 16px;
width: 100%;
}
.nav-logo {
display: inline-flex;
align-items: center;
gap: 8px;
text-decoration: none;
flex-shrink: 0;
}
.logo-mark {
background: var(--blue);
color: #fff;
font-size: 0.75rem;
font-weight: 500;
padding: 3px 7px;
border-radius: 6px;
letter-spacing: 0.02em;
}
.logo-text {
font-size: 0.875rem;
font-weight: 500;
color: var(--text);
}
.nav-links {
display: none;
flex: 1;
align-items: center;
justify-content: center;
gap: 4px;
}
@media (min-width: 768px) {
.nav-links { display: flex; }
}
.nav-link {
padding: 6px 12px;
font-size: 0.875rem;
font-weight: 400;
color: var(--text-65);
text-decoration: none;
border-radius: 8px;
transition: background 150ms ease, color 150ms ease;
}
.nav-link:hover {
background: var(--hover);
color: var(--text);
}
.nav-cta {
margin-left: auto;
background: var(--blue);
color: #fff;
font-size: 0.875rem;
font-weight: 500;
padding: 8px 16px;
border-radius: 8px;
text-decoration: none;
transition: background 150ms ease;
flex-shrink: 0;
}
.nav-cta:hover { background: var(--blue-hover); }
/* ── AUTH (nav button + modal) ── */
.nav-cta-group { margin-left: auto; display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.nav-cdn-chip {
font-size: 0.75rem;
color: var(--text-55);
background: var(--hover);
padding: 4px 10px;
border-radius: 6px;
cursor: pointer;
user-select: none;
transition: background 150ms ease;
}
.nav-cdn-chip:hover { background: var(--hover-light); color: var(--negative); }
.nav-cdn-chip::after { content: ' ×'; opacity: 0.5; }
.modal-overlay {
position: fixed; inset: 0;
background: rgba(0,0,0,0.4);
display: none; align-items: center; justify-content: center;
z-index: 100; padding: 16px;
animation: fadeIn 150ms ease;
}
.modal-overlay.open { display: flex; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.modal-card {
background: #fff;
border-radius: 16px;
padding: 32px 28px 28px;
max-width: 420px; width: 100%;
box-shadow: 0 20px 60px rgba(0,0,0,0.15);
position: relative;
animation: slideUp 200ms ease;
}
@keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
.modal-close {
position: absolute; top: 12px; right: 12px;
width: 32px; height: 32px;
background: transparent; border: none; cursor: pointer;
color: var(--text-45); font-size: 1.5rem; line-height: 1;
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
transition: background 150ms ease, color 150ms ease;
}
.modal-close:hover { background: var(--hover); color: var(--text); }
.modal-title {
font-size: 1.25rem;
font-weight: 500;
letter-spacing: -0.01em;
color: var(--text);
margin-bottom: 6px;
}
.modal-sub {
font-size: 0.875rem;
color: var(--text-55);
margin-bottom: 20px;
line-height: 1.5;
}
.modal-input {
width: 100%;
padding: 12px 14px;
border: 1px solid var(--border);
border-radius: 10px;
font-size: 0.9375rem;
font-family: inherit;
color: var(--text);
background: #fff;
transition: border-color 150ms ease;
}
.modal-input:focus {
outline: none;
border-color: var(--blue);
}
.modal-hint {
margin-top: 10px;
font-size: 0.8125rem;
color: var(--text-55);
min-height: 1.2em;
font-variant-numeric: tabular-nums;
}
.modal-hint code {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
background: var(--hover);
padding: 1px 6px;
border-radius: 4px;
font-size: 0.8125rem;
color: var(--text);
}
.modal-hint.error { color: var(--negative); }
.modal-actions {
margin-top: 24px;
display: flex;
gap: 10px;
}
.modal-submit {
flex: 1;
background: var(--blue);
color: #fff;
font-size: 0.9375rem;
font-weight: 500;
padding: 12px 20px;
border: none;
border-radius: 10px;
cursor: pointer;
font-family: inherit;
transition: background 150ms ease;
}
.modal-submit:hover { background: var(--blue-hover); }
.modal-submit:disabled { opacity: 0.5; cursor: not-allowed; }
/* ── MAIN ── */
main {
background: var(--bg);
border-radius: 16px;
overflow: hidden;
flex: 1;
}
/* ── CONTAINER ── */
.container {
width: 100%;
max-width: 1024px;
margin: 0 auto;
padding: 0 16px;
}
@media (min-width: 640px) { .container { padding: 0 24px; } }
/* ── HERO ── */
.hero {
padding: 72px 0 56px;
text-align: center;
}
@media (min-width: 640px) { .hero { padding: 96px 0 72px; } }
@media (min-width: 1024px) { .hero { padding: 112px 0 80px; } }
.hero-inner {
display: flex;
flex-direction: column;
align-items: center;
}
.badge {
display: inline-block;
font-size: 0.75rem;
font-weight: 400;
color: var(--text-55);
letter-spacing: 0.02em;
margin-bottom: 20px;
}
.hero-title {
font-size: 2rem;
font-weight: 400;
line-height: 1.12;
letter-spacing: -0.02em;
color: var(--text);
max-width: 540px;
}
@media (min-width: 640px) { .hero-title { font-size: 2.5rem; } }
@media (min-width: 1024px) { .hero-title { font-size: 3rem; max-width: 640px; } }
.underline-blue {
text-decoration: underline;
text-decoration-color: var(--blue);
text-decoration-thickness: 3px;
text-underline-offset: 6px;
}
.hero-sub {
margin-top: 16px;
font-size: 0.9375rem;
font-weight: 400;
color: var(--text-55);
max-width: 400px;
line-height: 1.5;
}
@media (min-width: 640px) { .hero-sub { font-size: 1rem; } }
.hero-meta {
margin-top: 32px;
display: flex;
align-items: center;
gap: 20px;
justify-content: center;
flex-wrap: wrap;
}
.hero-stat {
text-align: center;
}
.hero-stat-num {
font-size: 1.5rem;
font-weight: 400;
color: var(--blue);
line-height: 1;
}
.hero-stat-label {
font-size: 0.75rem;
color: var(--text-45);
margin-top: 2px;
}
.hero-divider {
width: 1px;
height: 32px;
background: var(--border);
}
/* ── SECTION ── */
.section {
padding: 64px 0;
border-top: 1px solid var(--border);
}
@media (min-width: 640px) { .section { padding: 80px 0; } }
.section-label {
font-size: 0.75rem;
font-weight: 400;
color: var(--text-45);
letter-spacing: 0.04em;
text-transform: uppercase;
margin-bottom: 12px;
}
.section-title {
font-size: 1.5rem;
font-weight: 400;
line-height: 1.2;
letter-spacing: -0.02em;
color: var(--text);
max-width: 540px;
}
@media (min-width: 640px) { .section-title { font-size: 1.875rem; } }
.section-title em {
font-style: normal;
text-decoration: underline;
text-decoration-color: var(--blue);
text-decoration-thickness: 2px;
text-underline-offset: 5px;
}
.section-body {
margin-top: 12px;
font-size: 0.9375rem;
font-weight: 400;
color: var(--text-55);
max-width: 520px;
line-height: 1.6;
}
/* ── BEFORE / AFTER ── */
.before-after {
margin-top: 40px;
display: grid;
gap: 12px;
}
@media (min-width: 640px) {
.before-after { grid-template-columns: 1fr 1fr; }
}
.ba-card {
background: var(--card-neutral);
border-radius: 12px;
padding: 24px;
}
.ba-card.after {
background: #fff;
border: 1px solid var(--border);
}
.ba-label {
font-size: 0.6875rem;
font-weight: 500;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--text-45);
margin-bottom: 16px;
}
.ba-label.after { color: var(--blue); }
.ba-row {
display: flex;
align-items: flex-start;
gap: 10px;
font-size: 0.875rem;
color: var(--text-65);
line-height: 1.5;
margin-bottom: 10px;
}
.ba-row:last-child { margin-bottom: 0; }
.ba-icon {
width: 16px;
height: 16px;
flex-shrink: 0;
margin-top: 2px;
}
.ba-icon.neg { color: var(--negative); }
.ba-icon.pos { color: var(--positive); }
/* ── THREE CARDS ── */
.cards-3 {
margin-top: 40px;
display: grid;
gap: 12px;
}
@media (min-width: 640px) { .cards-3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .cards-3 { grid-template-columns: repeat(3, 1fr); } }
.card {
background: var(--card-neutral);
border-radius: 12px;
padding: 28px 24px;
}
.card-icon {
width: 48px;
height: 48px;
color: var(--blue);
margin-bottom: 16px;
}
.card-title {
font-size: 0.9375rem;
font-weight: 500;
letter-spacing: -0.01em;
color: var(--text);
margin-bottom: 8px;
}
.card-desc {
font-size: 0.8125rem;
font-weight: 400;
color: var(--text-55);
line-height: 1.5;
}
/* ── TOOLS TABLE ── */
.tools-grid {
margin-top: 40px;
display: grid;
gap: 12px;
}
@media (min-width: 640px) { .tools-grid { grid-template-columns: repeat(3, 1fr); } }
.tool-card {
background: #fff;
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
display: flex;
flex-direction: column;
gap: 12px;
}
.tool-icon-wrap {
width: 44px;
height: 44px;
background: var(--card-neutral);
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
color: var(--blue);
}
.tool-icon-wrap svg { width: 22px; height: 22px; }
.tool-name {
font-size: 0.9375rem;
font-weight: 500;
color: var(--text);
}
.tool-role {
font-size: 0.8125rem;
color: var(--text-55);
line-height: 1.5;
}
.tool-link {
margin-top: auto;
font-size: 0.8125rem;
font-weight: 500;
color: var(--blue);
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 4px;
}
.tool-link:hover { color: var(--blue-hover); }
/* ── SCHEDULE ── */
.schedule {
margin-top: 40px;
display: flex;
flex-direction: column;
gap: 0;
}
.sched-item {
display: flex;
gap: 20px;
padding: 20px 0;
border-bottom: 1px solid var(--border);
position: relative;
}
.sched-item:last-child { border-bottom: none; }
.sched-time {
font-size: 0.8125rem;
font-weight: 400;
color: var(--text-45);
width: 52px;
flex-shrink: 0;
padding-top: 2px;
font-variant-numeric: tabular-nums;
}
.sched-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--card-neutral);
border: 2px solid var(--border);
flex-shrink: 0;
margin-top: 5px;
}
.sched-item.active .sched-dot {
background: var(--blue);
border-color: var(--blue);
}
.sched-content { flex: 1; min-width: 0; }
.sched-title {
font-size: 0.9375rem;
font-weight: 500;
color: var(--text);
}
.sched-item.break .sched-title { color: var(--text-55); font-weight: 400; }
.sched-desc {
margin-top: 4px;
font-size: 0.8125rem;
color: var(--text-55);
line-height: 1.5;
}
.sched-tags {
margin-top: 8px;
display: flex;
gap: 6px;
flex-wrap: wrap;
}
.tag {
font-size: 0.6875rem;
font-weight: 500;
padding: 2px 8px;
border-radius: 6px;
background: var(--card-neutral);
color: var(--text-55);
}
.tag.blue { background: rgba(0,102,204,0.1); color: var(--blue); }
/* ── GLOSSARY ── */
.glossary {
margin-top: 40px;
display: flex;
flex-direction: column;
gap: 8px;
}
.gloss-item {
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
}
.gloss-trigger {
width: 100%;
padding: 16px 20px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
background: transparent;
border: none;
cursor: pointer;
text-align: left;
transition: background 150ms ease;
}
@media (prefers-reduced-motion: reduce) { .gloss-trigger { transition: none; } }
.gloss-trigger:hover { background: var(--hover-light); }
.gloss-term {
font-size: 0.9375rem;
font-weight: 500;
color: var(--text);
}
.gloss-abbr {
font-size: 0.75rem;
font-weight: 500;
color: var(--blue);
background: rgba(0,102,204,0.08);
padding: 2px 8px;
border-radius: 6px;
flex-shrink: 0;
}
.gloss-chevron {
width: 16px;
height: 16px;
color: var(--text-55);
flex-shrink: 0;
transition: transform 200ms ease;
}
@media (prefers-reduced-motion: reduce) { .gloss-chevron { transition: none; } }
.gloss-item.open .gloss-chevron { transform: rotate(180deg); }
.gloss-body {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 200ms ease;
}
@media (prefers-reduced-motion: reduce) { .gloss-body { transition: none; } }
.gloss-item.open .gloss-body { grid-template-rows: 1fr; }
.gloss-inner {
overflow: hidden;
}
.gloss-text {
padding: 0 20px 16px;
font-size: 0.875rem;
color: var(--text-65);
line-height: 1.6;
}
.gloss-text strong {
color: var(--text);
font-weight: 500;
}
/* ── PROJECTS ── */
.projects-grid {
margin-top: 40px;
display: grid;
gap: 12px;
}
@media (min-width: 640px) { .projects-grid { grid-template-columns: repeat(2, 1fr); } }
.project-card {
background: #fff;
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
display: flex;
flex-direction: column;
gap: 10px;
cursor: pointer;
transition: border-color 150ms ease, box-shadow 150ms ease;
}
@media (prefers-reduced-motion: reduce) { .project-card { transition: none; } }
.project-card:hover {
border-color: rgba(0,102,204,0.3);
box-shadow: 0 0 0 3px rgba(0,102,204,0.06);
}
.project-num {
font-size: 0.6875rem;
font-weight: 500;
color: var(--text-45);
letter-spacing: 0.04em;
}
.project-title {
font-size: 0.9375rem;
font-weight: 500;
color: var(--text);
line-height: 1.4;
}
.project-pain {
font-size: 0.8125rem;
color: var(--text-55);
line-height: 1.5;
flex: 1;
}
.project-tags { display: flex; gap: 6px; flex-wrap: wrap; }
/* ── DARK CTA ── */
.dark-section {
background: linear-gradient(135deg, #000 0%, #002a63 50%, #0066cc 100%);
border-radius: 16px;
padding: 56px 24px;
text-align: center;
margin: 0 16px 0;
}
@media (min-width: 640px) { .dark-section { padding: 72px 40px; } }
.dark-title {
font-size: 1.75rem;
font-weight: 400;
color: #fff;
letter-spacing: -0.02em;
line-height: 1.2;
max-width: 460px;
margin: 0 auto;
}
@media (min-width: 640px) { .dark-title { font-size: 2.25rem; } }
.dark-sub {
margin-top: 12px;
font-size: 0.9375rem;
color: rgba(255,255,255,0.7);
max-width: 380px;
margin-left: auto;
margin-right: auto;
margin-top: 12px;
line-height: 1.5;
}
.dark-cta {
margin-top: 32px;
display: inline-flex;
align-items: center;
gap: 8px;
background: #fff;
color: var(--blue-link);
font-size: 0.9375rem;
font-weight: 500;
padding: 12px 24px;
border-radius: 10px;
text-decoration: none;
transition: color 150ms ease;
}
.dark-cta:hover { color: var(--blue-hover); }
/* ── FOOTER ── */
footer {
padding: 32px 24px 24px;
border-top: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
}
.footer-copy {
font-size: 0.75rem;
color: var(--text-45);
}
.footer-links {
display: flex;
gap: 16px;
}
.footer-link {
font-size: 0.75rem;
color: var(--text-55);
text-decoration: none;
}
.footer-link:hover { color: var(--text); }
/* ── UTILS ── */
.btn-primary {
display: inline-flex;
align-items: center;
gap: 6px;
background: var(--blue);
color: #fff;
font-size: 0.875rem;
font-weight: 500;
padding: 10px 20px;
border-radius: 8px;
text-decoration: none;
transition: background 150ms ease;
margin-top: 24px;
}
.btn-primary:hover { background: var(--blue-hover); }
.two-col {
display: grid;
gap: 48px;
}
@media (min-width: 1024px) {
.two-col {
grid-template-columns: 1fr 1fr;
align-items: start;
}
}
.section-header { margin-bottom: 0; }
</style>
</head>
<body>
<div class="frame">
<!-- NAV -->
<nav>
<div class="nav-inner">
<a class="nav-logo" href="#top">
<span class="logo-mark">КТ</span>
<span class="logo-text">Vibe Workshop</span>
</a>
<div class="nav-links">
<a href="#intro" class="nav-link">Введение</a>
<a href="#tools" class="nav-link">Инструменты</a>
<a href="#schedule" class="nav-link">Программа</a>
<a href="#glossary" class="nav-link">Словарь</a>
<a href="#projects" class="nav-link">Проекты</a>
</div>
<div class="nav-cta-group">
<span id="nav-cdn" class="nav-cdn-chip" hidden title="Выйти"></span>
<button id="nav-auth" type="button" class="nav-cta">Войти</button>
</div>
</div>
</nav>
<!-- AUTH MODAL -->
<div id="auth-modal" class="modal-overlay" role="dialog" aria-modal="true" aria-labelledby="auth-title">
<div class="modal-card">
<button class="modal-close" id="modal-close" aria-label="Закрыть">×</button>
<div class="modal-title" id="auth-title">Открыть мой VS Code</div>
<div class="modal-sub">Введи своё ФИО (если ты новый) или CDN (если уже работал).</div>
<input id="auth-input" class="modal-input" type="text" placeholder="Askar Tuleev или askar" autocomplete="off" autocapitalize="none" spellcheck="false" />
<div id="auth-hint" class="modal-hint">&nbsp;</div>
<div class="modal-actions">
<button id="auth-submit" type="button" class="modal-submit" disabled>Открыть VS Code →</button>
</div>
</div>
</div>
<!-- MAIN -->
<main id="top">
<!-- HERO -->
<section class="hero">
<div class="container hero-inner">
<span class="badge">Казахтелеком · Финансовый департамент · Полный день</span>
<h1 class="hero-title">
Воркшоп:<br>
<span class="underline-blue">Vibe Coding</span><br>
для финансистов
</h1>
<p class="hero-sub">
Сегодня ты напишешь своё первое рабочее приложение.<br>Без опыта программирования.
</p>
<div class="hero-meta">
<div class="hero-stat">
<div class="hero-stat-num">8ч</div>
<div class="hero-stat-label">полный день</div>
</div>
<div class="hero-divider"></div>
<div class="hero-stat">
<div class="hero-stat-num">1</div>
<div class="hero-stat-label">MVP на выходе</div>
</div>
<div class="hero-divider"></div>
<div class="hero-stat">
<div class="hero-stat-num">0</div>
<div class="hero-stat-label">строк кода вручную</div>
</div>
</div>
<a href="#intro" class="btn-primary">Начать →</a>
</div>
</section>
<!-- SECTION 1: WHAT IS VIBE CODING -->
<section class="section" id="intro">
<div class="container two-col">
<div class="section-header">
<div class="section-label">01 — Введение</div>
<h2 class="section-title">Что такое<br><em>вайб-кодинг?</em></h2>
<p class="section-body">
Раньше между идеей и программой стоял разработчик, ТЗ и несколько месяцев ожидания.
Теперь — только точное описание задачи.
</p>
</div>
<div class="before-after">
<div class="ba-card">
<div class="ba-label">Раньше</div>
<div class="ba-row">
<svg class="ba-icon neg" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7">
<circle cx="8" cy="8" r="7"/><line x1="10" y1="6" x2="6" y2="10"/><line x1="6" y1="6" x2="10" y2="10"/>
</svg>
<span>Описываешь задачу разработчику</span>
</div>
<div class="ba-row">
<svg class="ba-icon neg" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7">
<circle cx="8" cy="8" r="7"/><line x1="10" y1="6" x2="6" y2="10"/><line x1="6" y1="6" x2="10" y2="10"/>
</svg>
<span>Разработчик пишет ТЗ — итерация №1</span>
</div>
<div class="ba-row">
<svg class="ba-icon neg" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7">
<circle cx="8" cy="8" r="7"/><line x1="10" y1="6" x2="6" y2="10"/><line x1="6" y1="6" x2="10" y2="10"/>
</svg>
<span>Согласование, правки, спринт</span>
</div>
<div class="ba-row">
<svg class="ba-icon neg" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7">
<circle cx="8" cy="8" r="7"/><line x1="10" y1="6" x2="6" y2="10"/><line x1="6" y1="6" x2="10" y2="10"/>
</svg>
<span>Результат через 2–6 месяцев</span>
</div>
</div>
<div class="ba-card after">
<div class="ba-label after">Теперь</div>
<div class="ba-row">
<svg class="ba-icon pos" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7">
<circle cx="8" cy="8" r="7"/><polyline points="5,8 7,10 11,6"/>
</svg>
<span>Описываешь задачу словами в Claude</span>
</div>
<div class="ba-row">
<svg class="ba-icon pos" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7">
<circle cx="8" cy="8" r="7"/><polyline points="5,8 7,10 11,6"/>
</svg>
<span>Claude Code пишет код за секунды</span>
</div>
<div class="ba-row">
<svg class="ba-icon pos" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7">
<circle cx="8" cy="8" r="7"/><polyline points="5,8 7,10 11,6"/>
</svg>
<span>Ты проверяешь, даёшь обратную связь</span>
</div>
<div class="ba-row">
<svg class="ba-icon pos" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7">
<circle cx="8" cy="8" r="7"/><polyline points="5,8 7,10 11,6"/>
</svg>
<span>Рабочий прототип за часы</span>
</div>
</div>
</div>
</div>
</section>
<!-- SECTION 2: WHY FINANCIERS -->
<section class="section" id="why">
<div class="container">
<div class="section-label">02 — Почему вы</div>
<h2 class="section-title">Ты уже умеешь<br><em>самое важное</em></h2>
<p class="section-body">
Финансисты — лучшие постановщики задач. Ваш язык — это уже готовый PRD.
Три навыка, которые у вас есть по умолчанию:
</p>
<div class="cards-3">
<div class="card">
<svg class="card-icon" viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<rect x="8" y="6" width="32" height="36" rx="3"/>
<line x1="16" y1="16" x2="32" y2="16"/>
<line x1="16" y1="22" x2="32" y2="22"/>
<line x1="16" y1="28" x2="24" y2="28"/>
</svg>
<div class="card-title">Описывать процессы</div>
<div class="card-desc">
Как вы закрываете период, как согласуете платёж — это уже структурированное описание задачи. Claude понимает именно такой язык.
</div>
</div>
<div class="card">
<svg class="card-icon" viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<circle cx="24" cy="24" r="16"/>
<line x1="24" y1="16" x2="24" y2="24"/>
<line x1="24" y1="24" x2="30" y2="30"/>
</svg>
<div class="card-title">Видеть проблему</div>
<div class="card-desc">
Где данные расходятся, где Excel ломается, где теряется время — вы чувствуете это лучше любого разработчика. Эта экспертиза бесценна.
</div>
</div>
<div class="card">
<svg class="card-icon" viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<polyline points="8,28 18,18 26,26 40,12"/>
<polyline points="34,12 40,12 40,18"/>
</svg>
<div class="card-title">Принимать результат</div>
<div class="card-desc">
Принять или отклонить — это ваша ключевая роль. Цифра правильная или нет — именно ваша экспертиза даёт качество итоговому продукту.
</div>
</div>
</div>
</div>
</section>
<!-- SECTION 3: TOOLS -->
<section class="section" id="tools">
<div class="container">
<div class="section-label">03 — Инструменты</div>
<h2 class="section-title">Три инструмента.<br><em>Один результат.</em></h2>
<p class="section-body">
Всё что нужно сегодня — уже настроено. Никаких установок, регистраций и ключей.
</p>
<div class="tools-grid">
<div class="tool-card">
<div class="tool-icon-wrap">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
</svg>
</div>
<div class="tool-name">Claude Desktop</div>
<div class="tool-role">
ИИ-помощник, который пишет код. Говоришь задачу — получаешь код. Исправляешь словами — получаешь новую версию.
</div>
<a href="https://claude.ai" target="_blank" rel="noopener" class="tool-link">
claude.ai
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.7">
<path d="M2 10L10 2M4 2h6v6"/>
</svg>
</a>
</div>
<div class="tool-card">
<div class="tool-icon-wrap">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>
</svg>
</div>
<div class="tool-name">VSCode на telecom.quest</div>
<div class="tool-role">
Редактор кода прямо в браузере. Не нужно ничего устанавливать — открываешь ссылку и работаешь. Код Claude сразу запускается здесь.
</div>
<a href="https://telecom.quest" target="_blank" rel="noopener" class="tool-link">
telecom.quest
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.7">
<path d="M2 10L10 2M4 2h6v6"/>
</svg>
</a>
</div>
<div class="tool-card">
<div class="tool-icon-wrap">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<ellipse cx="12" cy="5" rx="9" ry="3"/>
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/>
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>
</svg>
</div>
<div class="tool-name">Sandbox КТ</div>
<div class="tool-role">
Тестовая среда с mock-данными, похожими на реальные данные КТ. Можно ломать, перезапускать. Реальные данные в полной безопасности.
</div>
<span class="tool-link" style="cursor:default;opacity:0.5">Настроено заранее</span>
</div>
</div>
</div>
</section>
<!-- SECTION 4: SCHEDULE -->
<section class="section" id="schedule">
<div class="container two-col">
<div class="section-header">
<div class="section-label">04 — Программа</div>
<h2 class="section-title">Что будет<br><em>сегодня</em></h2>
<p class="section-body">
Полный день поделён на блоки с чёткими результатами. К 17:00 — твой MVP задеплоен.
</p>
</div>
<div class="schedule" id="schedule-list"></div>
</div>
</section>
<!-- SECTION 5: GLOSSARY -->
<section class="section" id="glossary">
<div class="container two-col">
<div class="section-header">
<div class="section-label">05 — Словарь</div>
<h2 class="section-title">Термины,<br><em>которые услышишь</em></h2>
<p class="section-body">
Семь слов, которые встретятся сегодня. Нажми на любое — увидишь объяснение
без технического жаргона.
</p>
</div>
<div class="glossary" id="glossary-list"></div>
</div>
</section>
<!-- SECTION 6: PROJECTS -->
<section class="section" id="projects">
<div class="container">
<div class="section-label">06 — Твой проект</div>
<h2 class="section-title">Ты знаешь<br><em>боль изнутри</em></h2>
<p class="section-body">
Лучший проект — тот, где ты сам тратишь время впустую. Вот примеры из финансовых департаментов —
выбери ближайший или опиши свой.
</p>
<div class="projects-grid" id="projects-grid"></div>
</div>
</section>
<!-- DARK CTA -->
<section class="section" style="border-top: none; padding-bottom: 64px;">
<div class="container">
<div class="dark-section">
<h2 class="dark-title">Запусти свой проект сегодня</h2>
<p class="dark-sub">
К концу дня — рабочий MVP в среде Казахтелеком. Первый шаг сделан.
</p>
<a href="https://telecom.quest" target="_blank" rel="noopener" class="dark-cta">
Открыть telecom.quest →
</a>
</div>
</div>
</section>
<!-- FOOTER -->
<footer>
<span class="footer-copy">Казахтелеком · Финансовый департамент · Воркшоп по вайб-кодингу</span>
<div class="footer-links">
<a href="https://claude.ai" target="_blank" rel="noopener" class="footer-link">Claude Desktop</a>
<a href="https://telecom.quest" target="_blank" rel="noopener" class="footer-link">telecom.quest</a>
</div>
</footer>
</main>
</div>
<script>
const GLOSSARY = [
{
term: 'PRD',
abbr: 'PRD',
definition: '<strong>Product Requirements Document</strong> — описание задачи своими словами. Ты пишешь: что должна делать программа, кто ей пользуется, что считается успехом. Это уже умеют делать все финансисты — вы делаете это в каждом ТЗ для 1С.'
},
{
term: 'TRD',
abbr: 'TRD',
definition: '<strong>Technical Requirements Document</strong> — техническое задание, которое Claude генерирует из твоего PRD. Claude берёт твои слова и переводит на язык программиста. Ты не пишешь TRD — это делает ИИ.'
},
{
term: 'MVP',
abbr: 'MVP',
definition: '<strong>Minimum Viable Product</strong> — минимальный рабочий прототип. Самое простое, что решает проблему. Не идеальное — рабочее. Сначала делаем MVP, потом улучшаем. Как черновик отчёта: сначала цифры правильные, потом форматирование.'
},
{
term: 'Sandbox',
abbr: 'Sandbox',
definition: 'Тестовая среда с mock-данными. Можно ломать, пробовать, перезапускать — ничего страшного не произойдёт. Ваши реальные данные в 1С в полной безопасности. Всё что делается сегодня — только в sandbox.'
},
{
term: 'Mock',
abbr: 'Mock',
definition: 'Тестовые данные вместо реальных. Например: вместо реальных платёжек из 1С — файл с похожей структурой, но с выдуманными суммами и контрагентами. Позволяет разрабатывать без доступа к боевым системам.'
},
{
term: 'Итерация',
abbr: 'Итерация',
definition: 'Один цикл: <strong>сделал → проверил → улучшил</strong>. В разработке через Claude это занимает минуты. Описал задачу → получил код → запустил → увидел что не так → поправил описание → снова запустил. Это и есть вайб-кодинг.'
},
{
term: 'Промпт',
abbr: 'Prompt',
definition: 'Твоя инструкция для Claude. Чем точнее описание — тем точнее результат. Хороший промпт = хороший PRD: контекст, задача, ограничения, критерий успеха. Всё что ты пишешь в Claude Desktop — это промпты.'
}
];
const PROJECTS = [
{
num: '01',
title: 'Дашборд дебиторской задолженности',
pain: 'Каждый понедельник собираю данные из 1С вручную, строю таблицу в Excel. Тратится 2-3 часа. Хочу видеть картину в реальном времени.',
tags: ['Excel → Web', 'Визуализация', 'Автоматизация']
},
{
num: '02',
title: 'Чеклист закрытия периода',
pain: 'Список шагов закрытия есть только у меня в голове. Когда я в отпуске — коллеги теряются. Нужен интерактивный чеклист с историей выполнения.',
tags: ['Процесс', 'Командная работа', 'История']
},
{
num: '03',
title: 'Трекер согласования платежей',
pain: 'Платёжные поручения согласуем через email. Теряются версии, непонятно кто последний смотрел. Хочу одно место с историей статусов.',
tags: ['Согласования', 'Статусы', 'Аудит']
},
{
num: '04',
title: 'Конвертер банковской выписки',
pain: 'Выписка из банка приходит в одном формате, 1С принимает в другом. Каждый раз переделываю вручную через Excel. Это можно автоматизировать.',
tags: ['Парсинг', 'Конвертация', 'Банк']
},
{
num: '05',
title: 'Калькулятор бюджет vs факт',
pain: 'Отчёт по исполнению бюджета строю раз в месяц на 4 часа. Хочу вводить данные и сразу видеть отклонения с drill-down по статьям.',
tags: ['Аналитика', 'Бюджет', 'Отклонения']
},
{
num: '06',
title: 'Архив финансовых документов',
pain: 'Договоры, акты, счета — всё в разных папках. Когда нужно найти документ по контрагенту — ищешь полчаса. Нужен поиск с фильтрами.',
tags: ['Поиск', 'Архив', 'Документы']
}
];
const SCHEDULE = [
{
time: '09:00',
title: 'Введение в вайб-кодинг',
desc: 'Что изменилось. Почему финансисты — идеальные разработчики. Первое знакомство с Claude.',
tags: ['Теория'],
active: false
},
{
time: '09:45',
title: 'Инструменты и среда',
desc: 'Настройка Claude Desktop, telecom.quest VSCode, знакомство с Sandbox КТ.',
tags: ['Практика'],
active: false
},
{
time: '10:30',
title: 'Первый промпт: пишем вместе',
desc: 'Берём общую задачу, пишем PRD вместе, запускаем первый код. Каждый участник видит результат на своём экране.',
tags: ['Практика', 'Совместно'],
active: false
},
{
time: '11:30',
title: 'Выбор и проработка своего проекта',
desc: 'Каждый выбирает боль из своего опыта. Пишем PRD, Claude генерирует TRD. Наставник помогает с описанием.',
tags: ['Ваш проект'],
active: true
},
{
time: '13:00',
title: 'Обед',
desc: '',
tags: [],
active: false,
isBreak: true
},
{
time: '14:00',
title: 'Разработка MVP',
desc: 'Работаем по итерациям: описал → получил → проверил → улучшил. Claude пишет код, ты — ставишь задачу и принимаешь результат.',
tags: ['Ваш проект', 'Итерации'],
active: false
},
{
time: '16:00',
title: 'Демо и обратная связь',
desc: '3 минуты на команду: показываем что получилось, что сработало, что было сложно. Без оценок — только обмен опытом.',
tags: ['Демо'],
active: false
},
{
time: '16:45',
title: 'Запуск на telecom.quest',
desc: 'Каждый разворачивает свой MVP в среде КТ. Итоги дня, следующие шаги, ресурсы.',
tags: ['Финал'],
active: false
}
];
</script>
<script>
// Render schedule
const scheduleEl = document.getElementById('schedule-list');
SCHEDULE.forEach(item => {
const div = document.createElement('div');
div.className = 'sched-item' + (item.active ? ' active' : '') + (item.isBreak ? ' break' : '');
div.innerHTML = `
<span class="sched-time">${item.time}</span>
<span class="sched-dot"></span>
<div class="sched-content">
<div class="sched-title">${item.title}</div>
${item.desc ? `<div class="sched-desc">${item.desc}</div>` : ''}
${item.tags.length ? `<div class="sched-tags">${item.tags.map(t => `<span class="tag ${t === 'Ваш проект' || t === 'Финал' ? 'blue' : ''}">${t}</span>`).join('')}</div>` : ''}
</div>
`;
scheduleEl.appendChild(div);
});
// Render glossary
const glossaryEl = document.getElementById('glossary-list');
GLOSSARY.forEach(item => {
const div = document.createElement('div');
div.className = 'gloss-item';
div.innerHTML = `
<button class="gloss-trigger" aria-expanded="false">
<span class="gloss-term">${item.term}</span>
<span class="gloss-abbr">${item.abbr}</span>
<svg class="gloss-chevron" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round">
<polyline points="4,6 8,10 12,6"/>
</svg>
</button>
<div class="gloss-body" role="region">
<div class="gloss-inner">
<div class="gloss-text">${item.definition}</div>
</div>
</div>
`;
const btn = div.querySelector('.gloss-trigger');
btn.addEventListener('click', () => {
const isOpen = div.classList.contains('open');
document.querySelectorAll('.gloss-item.open').forEach(el => {
el.classList.remove('open');
el.querySelector('.gloss-trigger').setAttribute('aria-expanded', 'false');
});
if (!isOpen) {
div.classList.add('open');
btn.setAttribute('aria-expanded', 'true');
}
});
glossaryEl.appendChild(div);
});
// Render projects
const projectsEl = document.getElementById('projects-grid');
PROJECTS.forEach(item => {
const div = document.createElement('div');
div.className = 'project-card';
div.innerHTML = `
<div class="project-num">${item.num}</div>
<div class="project-title">${item.title}</div>
<div class="project-pain">"${item.pain}"</div>
<div class="project-tags">${item.tags.map(t => `<span class="tag">${t}</span>`).join('')}</div>
`;
projectsEl.appendChild(div);
});
/* ── AUTH ──────────────────────────────────────────────
Single-form login/register:
- "Askar Tuleev" → CDN "atuleev" (initial + lastname, lowercase, latin only)
- "askar" → CDN "askar" (passed through)
Submit → save to localStorage → redirect to code-server in that folder.
*/
const CODE_BASE = 'https://code.telecom.quest/?folder=/Users/telecom/dev/';
const STORAGE_KEY = 'vibe.cdn';
// Cyrillic → Latin transliteration (basic, covers Russian + Kazakh-ish names)
const TRANSLIT = {
'а':'a','б':'b','в':'v','г':'g','д':'d','е':'e','ё':'e','ж':'zh','з':'z','и':'i','й':'i',
'к':'k','л':'l','м':'m','н':'n','о':'o','п':'p','р':'r','с':'s','т':'t','у':'u','ф':'f',
'х':'kh','ц':'ts','ч':'ch','ш':'sh','щ':'sch','ъ':'','ы':'y','ь':'','э':'e','ю':'yu','я':'ya',
'ә':'a','ғ':'g','қ':'k','ң':'n','ө':'o','ұ':'u','ү':'u','һ':'h','і':'i'
};
function translit(s) {
return s.toLowerCase().split('').map(ch => TRANSLIT[ch] ?? ch).join('');
}
function makeCdn(input) {
const trimmed = input.trim().replace(/\s+/g, ' ');
if (!trimmed) return { cdn: '', mode: 'empty' };
// Single token → treat as CDN as-is (lowercased, dots removed, only allowed chars)
if (!/\s/.test(trimmed)) {
const cdn = translit(trimmed).replace(/\./g, '').replace(/[^a-z0-9_-]/g, '');
return { cdn, mode: 'login' };
}
// Multi-word → ФИО, generate CDN as <initial><lastname>
const parts = trimmed.split(' ');
const first = parts[0];
const last = parts[parts.length - 1];
const cdn = (translit(first).charAt(0) + translit(last))
.replace(/\./g, '').replace(/[^a-z0-9_-]/g, '');
return { cdn, mode: 'fio' };
}
const authModal = document.getElementById('auth-modal');
const authBtn = document.getElementById('nav-auth');
const cdnChip = document.getElementById('nav-cdn');
const closeBtn = document.getElementById('modal-close');
const input = document.getElementById('auth-input');
const hint = document.getElementById('auth-hint');
const submit = document.getElementById('auth-submit');
function refreshHeader() {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
authBtn.textContent = 'Открыть VS Code →';
cdnChip.hidden = false;
cdnChip.textContent = saved;
} else {
authBtn.textContent = 'Войти';
cdnChip.hidden = true;
}
}
function redirectTo(cdn) {
window.location.href = CODE_BASE + encodeURIComponent(cdn) + '/';
}
function openModal() {
authModal.classList.add('open');
setTimeout(() => input.focus(), 50);
input.value = '';
hint.innerHTML = '&nbsp;';
hint.classList.remove('error');
submit.disabled = true;
}
function closeModal() {
authModal.classList.remove('open');
}
input.addEventListener('input', () => {
const { cdn, mode } = makeCdn(input.value);
if (mode === 'empty') {
hint.innerHTML = '&nbsp;';
submit.disabled = true;
return;
}
if (!cdn) {
hint.textContent = 'Не получилось разобрать имя — попробуй латиницей';
hint.classList.add('error');
submit.disabled = true;
return;
}
hint.classList.remove('error');
const path = `/Users/telecom/dev/${cdn}/`;
if (mode === 'login') {
hint.innerHTML = `Откроется <code>${path}</code>`;
} else {
hint.innerHTML = `Твой CDN: <code>${cdn}</code> → <code>${path}</code>`;
}
submit.disabled = false;
});
submit.addEventListener('click', () => {
const { cdn } = makeCdn(input.value);
if (!cdn) return;
localStorage.setItem(STORAGE_KEY, cdn);
refreshHeader();
redirectTo(cdn);
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !submit.disabled) submit.click();
if (e.key === 'Escape') closeModal();
});
authBtn.addEventListener('click', () => {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) redirectTo(saved); else openModal();
});
cdnChip.addEventListener('click', () => {
if (!confirm('Выйти и забыть CDN?')) return;
localStorage.removeItem(STORAGE_KEY);
refreshHeader();
});
closeBtn.addEventListener('click', closeModal);
authModal.addEventListener('click', (e) => {
if (e.target === authModal) closeModal();
});
refreshHeader();
</script>
</body>
</html>