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
Telecom 3b23015b8a Bigger content (+40%) and scroll-snap on sections
- html font-size 22.4px scales rem-based typography
- scroll-snap-type: y proximity on html
- snap-align start on hero/sections/dark-section
- scroll-margin-top 84px to clear sticky nav

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:31:06 +05:00

2783 lines
97 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">
<script>
// Apply theme ASAP to avoid flash of wrong theme. Runs before <body> parses.
(function() {
try {
const saved = localStorage.getItem('vibe.theme');
if (saved === 'dark' || saved === 'light') {
document.documentElement.setAttribute('data-theme', saved);
}
} catch (e) {}
})();
</script>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
/* Brand */
--blue: #0066cc;
--blue-hover: #0055b3;
--blue-link: #0058b3;
/* Surfaces */
--page-bg: #fff;
--bg: #efefef; /* nav / main background */
--surface: #fff; /* cards */
--card-neutral: #e3e3e3;
/* Text */
--text: #000;
--text-on-blue: #fff;
--text-65: rgba(0,0,0,0.65);
--text-55: rgba(0,0,0,0.55);
--text-45: rgba(0,0,0,0.45);
/* Lines + hovers */
--border: rgba(0,0,0,0.08);
--border-strong: rgba(0,0,0,0.12);
--hover: rgba(0,0,0,0.06);
--hover-light: rgba(0,0,0,0.03);
/* Status */
--positive: #059669;
--positive-bg: #dcfce7;
--negative: #dc2626;
/* Decorative */
--dot-color: rgba(0,0,0,0.05);
--code-bg: #1a1a1a; /* code blocks stay dark in both themes */
--code-text: #e5e5e5;
/* Misc */
--modal-scrim: rgba(0,0,0,0.4);
--shadow-card: 0 1px 2px rgba(0,0,0,0.04), 0 8px 24px rgba(0,0,0,0.06);
}
/* Dark theme — applied via [data-theme="dark"] OR auto when no explicit preference */
[data-theme="dark"] {
--page-bg: #16171c;
--bg: #1c1d22;
--surface: #212229;
--card-neutral: #2a2c33;
--text: #e8e8e8;
--text-65: rgba(255,255,255,0.72);
--text-55: rgba(255,255,255,0.55);
--text-45: rgba(255,255,255,0.40);
--border: rgba(255,255,255,0.08);
--border-strong: rgba(255,255,255,0.14);
--hover: rgba(255,255,255,0.06);
--hover-light: rgba(255,255,255,0.03);
--blue: #3b82f6;
--blue-hover: #60a5fa;
--blue-link: #60a5fa;
--positive: #34d399;
--positive-bg: rgba(52,211,153,0.15);
--negative: #f87171;
--dot-color: rgba(255,255,255,0.05);
--modal-scrim: rgba(0,0,0,0.65);
--shadow-card: 0 1px 2px rgba(0,0,0,0.4), 0 8px 24px rgba(0,0,0,0.3);
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--page-bg: #16171c;
--bg: #1c1d22;
--surface: #212229;
--card-neutral: #2a2c33;
--text: #e8e8e8;
--text-65: rgba(255,255,255,0.72);
--text-55: rgba(255,255,255,0.55);
--text-45: rgba(255,255,255,0.40);
--border: rgba(255,255,255,0.08);
--border-strong: rgba(255,255,255,0.14);
--hover: rgba(255,255,255,0.06);
--hover-light: rgba(255,255,255,0.03);
--blue: #3b82f6;
--blue-hover: #60a5fa;
--blue-link: #60a5fa;
--positive: #34d399;
--positive-bg: rgba(52,211,153,0.15);
--negative: #f87171;
--dot-color: rgba(255,255,255,0.05);
--modal-scrim: rgba(0,0,0,0.65);
--shadow-card: 0 1px 2px rgba(0,0,0,0.4), 0 8px 24px rgba(0,0,0,0.3);
}
}
html {
scroll-behavior: smooth;
font-size: 22.4px; /* +40% от 16px — крупнее контент */
scroll-snap-type: y proximity;
}
/* Scroll-snap по основным секциям */
.hero,
section.section,
.dark-section {
scroll-snap-align: start;
scroll-snap-stop: always;
scroll-margin-top: 84px; /* высота sticky-нав */
}
/* ── POLISH: shared hover transition for all card variants ── */
.tool-card, .create-card, .plan-step, .gloss-item, .project-card, .prompt-card, .eq-box {
transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
will-change: transform;
}
@media (hover: hover) {
.tool-card:hover, .create-card:hover, .plan-step:hover,
.gloss-item:hover, .prompt-card:hover, .eq-box:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-card);
}
/* project-card already has its own hover (border + ring) — strengthen with lift */
.project-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-card);
}
}
@media (prefers-reduced-motion: reduce) {
.tool-card, .create-card, .plan-step, .gloss-item, .project-card, .prompt-card, .eq-box {
transition: none;
}
.tool-card:hover, .create-card:hover, .plan-step:hover,
.gloss-item:hover, .project-card:hover, .prompt-card:hover, .eq-box:hover {
transform: none;
}
}
/* ── POLISH: scroll-triggered fade-in ── */
.reveal {
opacity: 0;
transform: translateY(8px);
transition: opacity 350ms ease, transform 350ms ease;
}
.reveal.in {
opacity: 1;
transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
.reveal { opacity: 1; transform: none; transition: none; }
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: var(--page-bg);
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 16px;
display: flex;
align-items: center;
position: sticky;
top: 12px;
z-index: 50;
/* match .container width so navbar aligns with section content below */
width: 100%;
max-width: 1024px;
margin: 0 auto;
}
@media (min-width: 640px) { nav { padding: 0 24px; } }
.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; }
.theme-toggle {
width: 36px; height: 36px;
border: 1px solid var(--border);
background: transparent;
color: var(--text-65);
border-radius: 50%;
cursor: pointer;
display: inline-flex; align-items: center; justify-content: center;
flex-shrink: 0;
transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}
.theme-toggle:hover {
background: var(--hover);
color: var(--text);
border-color: var(--border-strong);
}
.theme-toggle svg { width: 16px; height: 16px; }
.theme-toggle .icon-moon { display: none; }
[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) .theme-toggle .icon-sun { display: none; }
:root:not([data-theme="light"]) .theme-toggle .icon-moon { display: block; }
}
.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: var(--modal-scrim);
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: var(--surface);
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: var(--surface);
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; }
/* ── OPTIONAL BADGE on tool card ── */
.tool-card.optional { position: relative; opacity: 0.92; }
.tool-card .opt-badge {
position: absolute; top: 14px; right: 14px;
font-size: 0.6875rem; font-weight: 500;
padding: 2px 8px; border-radius: 6px;
background: rgba(0,0,0,0.06); color: var(--text-55);
letter-spacing: 0.02em;
}
/* ── ACTION PLAN ── */
.plan-flow {
margin-top: 40px;
display: grid;
gap: 12px;
grid-template-columns: 1fr;
}
@media (min-width: 768px) {
.plan-flow { grid-template-columns: repeat(4, 1fr); align-items: stretch; }
}
.plan-step {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px 18px;
display: flex;
flex-direction: column;
gap: 8px;
position: relative;
}
.plan-step-num {
font-size: 0.6875rem; font-weight: 500;
letter-spacing: 0.06em;
color: var(--blue);
text-transform: uppercase;
}
.plan-step-title {
font-size: 0.9375rem; font-weight: 500;
color: var(--text); line-height: 1.3;
}
.plan-step-desc {
font-size: 0.8125rem;
color: var(--text-55); line-height: 1.5;
flex: 1;
}
.plan-step code {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
background: var(--hover); padding: 1px 5px;
border-radius: 4px; font-size: 0.75rem; color: var(--text);
}
/* ── CREATE CARDS ── */
.create-cards {
margin-top: 40px;
display: grid;
gap: 12px;
grid-template-columns: 1fr;
}
@media (min-width: 640px) { .create-cards { grid-template-columns: repeat(3, 1fr); } }
.create-card {
background: var(--card-neutral);
border-radius: 12px;
padding: 28px 24px;
display: flex;
flex-direction: column;
gap: 12px;
}
.create-card-icon {
width: 44px; height: 44px;
background: var(--surface);
border-radius: 10px;
display: flex; align-items: center; justify-content: center;
color: var(--blue);
}
.create-card-icon svg { width: 22px; height: 22px; }
.create-card-title {
font-size: 0.9375rem; font-weight: 500;
color: var(--text);
}
.create-card-desc {
font-size: 0.8125rem;
color: var(--text-55); line-height: 1.5;
}
.create-card-example {
font-size: 0.75rem;
color: var(--text-45);
font-style: italic;
margin-top: auto;
}
/* ── ENTERPRISE EQUATION (vibe + hard = enterprise) ── */
.eq-flow {
margin-top: 40px;
display: grid;
gap: 16px;
grid-template-columns: 1fr;
align-items: stretch;
}
@media (min-width: 768px) {
.eq-flow {
grid-template-columns: 1fr auto 1fr auto 1fr;
align-items: stretch;
}
}
.eq-box {
background: var(--card-neutral);
border-radius: 12px;
padding: 24px;
display: flex;
flex-direction: column;
gap: 8px;
}
.eq-box.you {
background: rgba(0,102,204,0.08);
border: 1px solid rgba(0,102,204,0.2);
}
.eq-box.result {
background: var(--surface);
border: 1px solid var(--border);
}
.eq-box-label {
font-size: 0.6875rem;
font-weight: 500;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--text-45);
}
.eq-box.you .eq-box-label { color: var(--blue); }
.eq-box-title {
font-size: 1rem;
font-weight: 500;
color: var(--text);
line-height: 1.3;
}
.eq-box-desc {
font-size: 0.8125rem;
color: var(--text-55);
line-height: 1.5;
}
.eq-op {
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
font-weight: 500;
color: var(--text-45);
padding: 8px 0;
}
@media (min-width: 768px) { .eq-op { padding: 0 4px; } }
.eq-note {
margin-top: 32px;
background: var(--surface);
border: 1px solid var(--border);
border-left: 3px solid var(--blue);
border-radius: 8px;
padding: 20px 24px;
display: grid;
gap: 16px;
}
@media (min-width: 640px) { .eq-note { grid-template-columns: 1fr 1fr; } }
.eq-note-item {
display: flex;
gap: 12px;
align-items: flex-start;
}
.eq-note-icon {
width: 28px; height: 28px;
flex-shrink: 0;
color: var(--blue);
background: rgba(0,102,204,0.08);
border-radius: 6px;
display: flex; align-items: center; justify-content: center;
}
.eq-note-icon svg { width: 16px; height: 16px; }
.eq-note-text {
font-size: 0.8125rem;
color: var(--text-65);
line-height: 1.5;
}
.eq-note-text strong { color: var(--text); font-weight: 500; }
/* ── PROMPT CHEATSHEET ── */
.prompts {
margin-top: 40px;
display: flex;
flex-direction: column;
gap: 12px;
}
.prompt-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px 24px;
display: flex;
flex-direction: column;
gap: 12px;
}
@media (max-width: 640px) { .prompt-card { padding: 16px 18px; } }
.prompt-head {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.prompt-step {
font-size: 0.6875rem;
font-weight: 500;
letter-spacing: 0.06em;
text-transform: uppercase;
padding: 3px 8px;
border-radius: 6px;
background: rgba(0,102,204,0.08);
color: var(--blue);
flex-shrink: 0;
}
.prompt-step.bonus {
background: rgba(0,0,0,0.06);
color: var(--text-65);
}
.prompt-title {
font-size: 0.9375rem;
font-weight: 500;
color: var(--text);
}
.prompt-context {
font-size: 0.8125rem;
color: var(--text-55);
line-height: 1.5;
}
.prompt-box {
position: relative;
background: #1a1a1a;
border-radius: 8px;
padding: 16px 56px 16px 18px;
}
.prompt-box pre {
margin: 0;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 0.8125rem;
line-height: 1.55;
color: #e5e5e5;
white-space: pre-wrap;
word-wrap: break-word;
}
.prompt-copy {
position: absolute;
top: 12px;
right: 12px;
border: none;
background: rgba(255,255,255,0.08);
color: #e5e5e5;
font-size: 0.75rem;
font-family: inherit;
padding: 6px 10px;
border-radius: 6px;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 5px;
transition: background 150ms ease, color 150ms ease;
}
.prompt-copy:hover { background: rgba(255,255,255,0.15); }
.prompt-copy.copied { background: var(--positive-bg); color: var(--positive); }
.prompt-copy svg { width: 12px; height: 12px; }
/* ── TELEGRAM ── */
.tg-block {
margin-top: 40px;
background: var(--card-neutral);
border-radius: 16px;
padding: 32px 28px;
display: grid;
gap: 28px;
grid-template-columns: 1fr;
align-items: center;
}
@media (min-width: 640px) {
.tg-block { grid-template-columns: auto 1fr; padding: 40px; gap: 36px; }
}
.tg-qr {
background: #fff;
padding: 12px;
border-radius: 12px;
width: 180px; height: 180px;
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
}
.tg-qr svg { width: 100%; height: 100%; display: block; }
.tg-text-title {
font-size: 1.25rem; font-weight: 500;
letter-spacing: -0.01em;
color: var(--text);
margin-bottom: 8px;
}
.tg-text-body {
font-size: 0.875rem;
color: var(--text-55); line-height: 1.5;
margin-bottom: 16px;
}
.tg-cta {
display: inline-flex; align-items: center; gap: 6px;
background: var(--blue); color: #fff;
font-size: 0.875rem; font-weight: 500;
padding: 10px 18px; border-radius: 8px;
text-decoration: none;
transition: background 150ms ease;
}
.tg-cta:hover { background: var(--blue-hover); }
/* ── 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;
/* subtle dot-grid backdrop, fades to clean at the edges */
background-image:
radial-gradient(ellipse at center, var(--dot-color) 1px, transparent 1.5px);
background-size: 22px 22px;
background-position: center top;
mask-image: radial-gradient(ellipse at center, black 40%, transparent 80%);
-webkit-mask-image: radial-gradient(ellipse at center, black 40%, transparent 80%);
}
@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: var(--surface);
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: var(--surface);
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 (horizontal slider, full-width below title) ── */
.glossary-slider {
margin-top: 40px;
width: 100%;
min-width: 0;
}
.glossary {
display: flex;
gap: 12px;
overflow-x: auto;
overflow-y: hidden;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
padding-bottom: 8px;
width: 100%;
min-width: 0;
max-width: 100%;
}
.glossary::-webkit-scrollbar { height: 6px; }
.glossary::-webkit-scrollbar-track { background: transparent; }
.glossary::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.gloss-item {
border: 1px solid var(--border);
border-radius: 12px;
background: var(--surface);
display: flex;
flex-direction: column;
scroll-snap-align: start;
min-height: 200px;
flex: 0 0 360px;
min-width: 360px;
}
@media (max-width: 640px) {
.gloss-item { flex-basis: 88vw; min-width: 88vw; min-height: 180px; }
}
.gloss-nav {
margin-top: 20px;
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
}
.gloss-nav-btn {
width: 40px; height: 40px;
border: 1px solid var(--border);
background: var(--surface);
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
cursor: pointer;
transition: background 150ms ease, opacity 150ms ease, border-color 150ms ease;
color: var(--text-65);
}
.gloss-nav-btn:hover:not(:disabled) {
background: var(--blue); color: #fff; border-color: var(--blue);
}
.gloss-nav-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.gloss-nav-btn svg { width: 18px; height: 18px; }
.gloss-counter {
font-size: 0.8125rem;
color: var(--text-55);
font-variant-numeric: tabular-nums;
min-width: 64px;
text-align: center;
}
.gloss-trigger {
width: 100%;
padding: 16px 20px 8px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
background: transparent;
border: none;
text-align: left;
cursor: default;
}
.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 { display: none; }
.gloss-body { display: block; }
.gloss-inner { overflow: visible; }
.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;
}
.gloss-text code {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
background: var(--hover);
padding: 1px 5px;
border-radius: 4px;
font-size: 0.8125rem;
color: var(--text);
}
/* ── 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: var(--surface);
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; }
/* ── CHECKLIST ── */
.checklist-grid {
margin-top: 40px;
display: grid;
gap: 12px;
}
@media (min-width: 768px) { .checklist-grid { grid-template-columns: repeat(2, 1fr); } }
.check-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
display: flex;
flex-direction: column;
gap: 12px;
transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
}
@media (hover: hover) {
.check-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-card); }
}
.check-card.featured { border-color: var(--blue); }
.check-card.muted { background: var(--card-neutral); }
.check-card-head {
display: flex;
align-items: center;
gap: 10px;
}
.check-badge {
font-size: 0.6875rem;
font-weight: 500;
padding: 3px 8px;
border-radius: 6px;
background: var(--hover);
color: var(--text-65);
letter-spacing: 0.02em;
text-transform: uppercase;
}
.check-badge.required { background: var(--blue); color: #fff; }
.check-badge.optional { background: var(--card-neutral); color: var(--text-65); }
.check-badge.warn { background: var(--positive-bg); color: var(--positive); }
.check-title {
font-size: 1rem;
font-weight: 500;
color: var(--text);
}
.check-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 10px;
}
.check-list li {
display: flex;
align-items: flex-start;
gap: 10px;
font-size: 0.875rem;
color: var(--text-65);
line-height: 1.5;
}
.check-list li::before {
content: '';
flex-shrink: 0;
width: 16px;
height: 16px;
margin-top: 3px;
border: 1.5px solid var(--border-strong);
border-radius: 4px;
background: var(--surface);
}
.check-list.dont li::before {
border: none;
background: none;
width: 16px;
height: 16px;
margin-top: 1px;
color: var(--negative);
content: '✕';
display: flex;
align-items: center;
justify-content: center;
font-size: 0.875rem;
font-weight: 600;
}
.check-list a {
color: var(--blue);
text-decoration: none;
font-weight: 500;
}
.check-list a:hover { color: var(--blue-hover); text-decoration: underline; }
.check-note {
font-size: 0.75rem;
color: var(--text-55);
font-style: italic;
line-height: 1.5;
}
/* Side announcement */
.vibe-announce {
position: fixed;
left: 20px;
top: 50%;
transform: translateY(-50%);
z-index: 100;
background: var(--blue);
color: var(--text-on-blue);
padding: 16px 18px;
border-radius: 12px;
box-shadow: var(--shadow-card);
max-width: 200px;
font-size: 0.875rem;
line-height: 1.5;
}
.vibe-announce-title {
font-weight: 700;
font-size: 1rem;
margin-bottom: 6px;
letter-spacing: 0.06em;
}
.vibe-announce-pass {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 1.05rem;
font-weight: 600;
background: rgba(255,255,255,0.18);
padding: 6px 10px;
border-radius: 6px;
display: inline-block;
margin-top: 4px;
letter-spacing: 0.04em;
}
@media (max-width: 1200px) {
.vibe-announce { display: none; }
}
</style>
</head>
<body>
<aside class="vibe-announce" aria-label="Объявление">
<div class="vibe-announce-title">Wi-Fi и пароль</div>
<div>VIBECODING</div>
<div class="vibe-announce-pass">123456789</div>
</aside>
<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="#checklist" class="nav-link">Чек-лист</a>
<a href="#plan" class="nav-link">Action Plan</a>
<a href="#create" class="nav-link">Что создать</a>
<a href="#enterprise" class="nav-link">Зачем</a>
<a href="#prompts" class="nav-link">Промпты</a>
<a href="#telegram" class="nav-link">Сообщество</a>
</div>
<div class="nav-cta-group">
<button id="theme-toggle" type="button" class="theme-toggle" aria-label="Переключить тему">
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
<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="Zhuldyz Inat или Zhuldyz" 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">
<span class="underline-blue">Vibe Coding</span><br>
для сотрудников Казахтелеком
</h1>
<p class="hero-sub">
Опиши свою боль словами — Claude напишет код. Запусти прямо здесь, в браузере.<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: TELEGRAM COMMUNITY -->
<section class="section" id="telegram">
<div class="container">
<div class="section-label">Сообщество</div>
<h2 class="section-title">P2P-формат.<br><em>Не лекция — движение.</em></h2>
<p class="section-body">
Это не курс «сверху вниз». Это сообщество сотрудников КТ, которые учатся <strong>друг у друга</strong>: показывают свои проекты, спрашивают, помогают, делятся находками. Заходи — там уже несколько групп инноваторов.
</p>
<div class="tg-block">
<div class="tg-qr" aria-label="QR-код для Telegram-группы">
<svg viewBox="0 0 264 264" version="1.1" width="264" height="264" class="segno"><g transform="scale(8)"><path fill="#fff" d="M0 0h33v33h-33z"/><path class="qrline" stroke="#000" d="M2 2.5h7m1 0h1m2 0h2m2 0h1m1 0h1m1 0h1m2 0h7m-29 1h1m5 0h1m1 0h3m1 0h1m1 0h2m1 0h4m1 0h1m5 0h1m-29 1h1m1 0h3m1 0h1m1 0h2m2 0h5m5 0h1m1 0h3m1 0h1m-29 1h1m1 0h3m1 0h1m1 0h1m2 0h2m1 0h1m3 0h1m3 0h1m1 0h3m1 0h1m-29 1h1m1 0h3m1 0h1m1 0h1m5 0h2m1 0h3m2 0h1m1 0h3m1 0h1m-29 1h1m5 0h1m2 0h1m4 0h1m1 0h1m2 0h1m2 0h1m5 0h1m-29 1h7m1 0h1m1 0h1m1 0h1m1 0h1m1 0h1m1 0h1m1 0h1m1 0h7m-21 1h1m1 0h3m2 0h1m1 0h1m2 0h1m-20 1h2m1 0h1m1 0h2m3 0h2m1 0h1m1 0h1m2 0h2m1 0h1m1 0h5m-27 1h3m2 0h1m1 0h6m1 0h2m1 0h2m1 0h2m1 0h2m1 0h1m-28 1h2m2 0h4m4 0h1m1 0h2m9 0h3m-27 1h4m1 0h1m1 0h3m2 0h6m1 0h2m4 0h1m-27 1h1m2 0h1m1 0h1m1 0h1m1 0h2m2 0h1m2 0h4m1 0h2m-24 1h3m1 0h1m2 0h1m7 0h2m4 0h3m4 0h1m-27 1h3m1 0h1m1 0h3m2 0h1m2 0h3m1 0h1m1 0h2m2 0h1m1 0h1m-29 1h2m1 0h2m4 0h1m1 0h2m2 0h1m1 0h1m1 0h3m1 0h1m-21 1h1m2 0h3m1 0h1m1 0h2m1 0h3m3 0h3m1 0h1m-24 1h1m2 0h1m1 0h1m1 0h1m3 0h1m1 0h2m3 0h4m3 0h2m-29 1h1m2 0h1m1 0h2m4 0h1m1 0h1m1 0h3m2 0h2m1 0h2m1 0h3m-28 1h1m1 0h1m1 0h1m4 0h1m3 0h1m1 0h4m2 0h1m1 0h1m2 0h2m-29 1h1m1 0h1m2 0h2m1 0h1m1 0h2m1 0h1m1 0h1m1 0h9m1 0h1m-20 1h2m4 0h3m3 0h1m3 0h1m2 0h1m-28 1h7m1 0h1m1 0h1m2 0h1m4 0h3m1 0h1m1 0h1m1 0h3m-29 1h1m5 0h1m2 0h1m1 0h2m1 0h2m1 0h2m1 0h1m3 0h1m-25 1h1m1 0h3m1 0h1m1 0h1m1 0h1m3 0h3m1 0h1m1 0h6m1 0h2m-29 1h1m1 0h3m1 0h1m3 0h2m1 0h3m4 0h2m2 0h1m-25 1h1m1 0h3m1 0h1m1 0h1m3 0h3m1 0h4m3 0h2m1 0h1m1 0h1m-29 1h1m5 0h1m1 0h1m1 0h1m3 0h2m1 0h2m1 0h1m1 0h2m1 0h1m1 0h1m-28 1h7m2 0h1m2 0h3m2 0h2m1 0h1m1 0h1m1 0h1m2 0h2"/></g></svg>
</div>
<div>
<div class="tg-text-title">Telegram-группа инноваторов</div>
<div class="tg-text-body">
Отсканируй QR или жми на кнопку. Можно показать свой проект, попросить помощь, прислать идею.
</div>
<a href="https://t.me/+9UI8dt-60l8yMzJi" target="_blank" rel="noopener" class="tg-cta">
Открыть в Telegram →
</a>
</div>
</div>
</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: REGISTER AI ACCOUNTS -->
<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">
До воркшопа создай бесплатные аккаунты в Claude, ChatGPT и Gemini. Можно через Google — 1 минута на каждый. Не нужно платить и не нужно API-ключи.
</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</div>
<div class="tool-role">
Anthropic. Лучший для длинных описаний и для генерации кода. Основной инструмент на воркшопе.
</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">
<circle cx="12" cy="12" r="9"/>
<path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/>
</svg>
</div>
<div class="tool-name">ChatGPT</div>
<div class="tool-role">
OpenAI. Универсал. Хорош для брейншторма и быстрых ответов. Запасной канал, если Claude занят.
</div>
<a href="https://chatgpt.com" target="_blank" rel="noopener" class="tool-link">
chatgpt.com
<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">
<path d="M12 2l2.5 7.5L22 12l-7.5 2.5L12 22l-2.5-7.5L2 12l7.5-2.5z"/>
</svg>
</div>
<div class="tool-name">Gemini</div>
<div class="tool-role">
Google. Силён в работе с Google-документами и таблицами. Удобен, если данные уже в Google Drive.
</div>
<a href="https://gemini.google.com" target="_blank" rel="noopener" class="tool-link">
gemini.google.com
<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>
</div>
</section>
<!-- SECTION 3.5: CHECKLIST -->
<section class="section" id="checklist">
<div class="container">
<div class="section-label">Чек-лист участника</div>
<h2 class="section-title">Что подготовить<br><em>до воркшопа</em></h2>
<p class="section-body">
Никаких установок, API-ключей и корпоративных регистраций не нужно. Всё работает в браузере.
</p>
<div class="checklist-grid">
<div class="check-card featured">
<div class="check-card-head">
<span class="check-badge required">Обязательно</span>
<span class="check-title">Telegram</span>
</div>
<ul class="check-list">
<li>Telegram установлен на телефоне или компе</li>
<li>Аккаунт активен — сможешь зайти в чат по QR со страницы</li>
</ul>
<div class="check-note">Чат инноваторов: помощь и обмен находками во время воркшопа.</div>
</div>
<div class="check-card">
<div class="check-card-head">
<span class="check-badge warn">Перед выходом</span>
<span class="check-title">Что взять с собой</span>
</div>
<ul class="check-list">
<li>Ноутбук заряжен + зарядка</li>
<li>Знаешь свою «боль» в работе — задачу или процесс, который хочешь автоматизировать (станет твоим MVP)</li>
<li>Если есть Excel-файл с примером данных по этой задаче — захвати</li>
</ul>
</div>
<div class="check-card muted">
<div class="check-card-head">
<span class="check-badge">Не нужно</span>
<span class="check-title">Что НЕ ставить</span>
</div>
<ul class="check-list dont">
<li>VS Code на компьютер — используем браузерную версию</li>
<li>Node.js, Python, Git — ничего из этого</li>
<li>API-ключи Claude или OpenAI</li>
</ul>
</div>
</div>
</div>
</section>
<!-- SECTION 4: ACTION PLAN -->
<section class="section" id="plan">
<div class="container">
<div class="section-label">04 — Action Plan</div>
<h2 class="section-title">Четыре шага<br><em>до рабочего MVP</em></h2>
<p class="section-body">
От «у меня есть боль» до «вот работающее приложение». Каждый шаг — 10–30 минут.
</p>
<div class="plan-flow">
<div class="plan-step">
<div class="plan-step-num">Шаг 1</div>
<div class="plan-step-title">Войди в свою папку</div>
<div class="plan-step-desc">
Нажми <b>«Войти»</b> наверху, введи ФИО — откроется твой редактор кода. Внутри уже готовый файл <code>PRD.md</code> (для идеи) и <code>TRD.md</code> (для технической части).
</div>
</div>
<div class="plan-step">
<div class="plan-step-num">Шаг 2</div>
<div class="plan-step-title">Опиши свою задачу в PRD.md</div>
<div class="plan-step-desc">
<code>PRD.md</code> — это файл, где ты простыми словами рассказываешь: что болит, кто будет пользоваться, как должно работать. Никакого кода. Это твоя идея на бумаге.
</div>
</div>
<div class="plan-step">
<div class="plan-step-num">Шаг 3</div>
<div class="plan-step-title">Попроси Claude сделать TRD</div>
<div class="plan-step-desc">
Открой Claude, скинь свой <code>PRD.md</code> и попроси: «Сделай TRD по этому PRD». <code>TRD.md</code> — это твоя идея, переведённая на язык кода. Claude напишет, ты сохранишь.
</div>
</div>
<div class="plan-step">
<div class="plan-step-num">Шаг 4</div>
<div class="plan-step-title">Запусти Claude Code</div>
<div class="plan-step-desc">
В редакторе снизу открой строку для команд и напиши <code>claude code</code>. Скажи: «реализуй TRD.md». Через 10–20 минут — рабочее приложение в твоей папке.
</div>
</div>
</div>
</div>
</section>
<!-- SECTION 5: WHAT YOU CAN CREATE -->
<section class="section" id="create">
<div class="container">
<div class="section-label">05 — Что можно создать</div>
<h2 class="section-title">Три формата.<br><em>Под твою задачу.</em></h2>
<p class="section-body">
Большинство финансовых задач сводятся к трём типам решений. Выбери ближайший к твоей боли.
</p>
<div class="create-cards">
<div class="create-card">
<div class="create-card-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<path d="M3 9h18M9 21V9"/>
</svg>
</div>
<div class="create-card-title">Дашборд</div>
<div class="create-card-desc">
Веб-страница с цифрами и графиками из твоих таблиц. Обновляется сама. Можно открыть с телефона.
</div>
<div class="create-card-example">
Например: динамика затрат по департаментам за квартал.
</div>
</div>
<div class="create-card">
<div class="create-card-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M21.5 12a9.5 9.5 0 1 1-3-7L21 4l-1 4-4-1"/>
<circle cx="12" cy="12" r="1"/>
</svg>
</div>
<div class="create-card-title">Telegram-бот</div>
<div class="create-card-desc">
Бот, которому пишешь команду — он отвечает или что-то делает. Может тыкаться в Excel, базы, отчёты.
</div>
<div class="create-card-example">
Например: «/курс USD» → актуальная разница vs. прошлая неделя.
</div>
</div>
<div class="create-card">
<div class="create-card-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="3" width="20" height="14" rx="2"/>
<path d="M8 21h8M12 17v4"/>
</svg>
</div>
<div class="create-card-title">Mini-приложение</div>
<div class="create-card-desc">
Страничка с формой для коллег. Они заполняют — у тебя автоматически собирается результат. Без таблиц и пересылки.
</div>
<div class="create-card-example">
Например: согласование командировки в один клик.
</div>
</div>
</div>
</div>
</section>
<!-- SECTION 6: VIBE + HARD = ENTERPRISE -->
<section class="section" id="enterprise">
<div class="container">
<div class="section-label">06 — Это не игрушка</div>
<h2 class="section-title">Vibe coding + Hard coding =<br><em>Enterprise solution</em></h2>
<p class="section-body">
Ты пишешь словами свою идею. Дев-команда КТ потом упаковывает её в прод. На выходе — реальная система внутри Казахтелеком, которой пользуются сотни человек.
</p>
<div class="eq-flow">
<div class="eq-box you">
<div class="eq-box-label">Vibe coding · ты</div>
<div class="eq-box-title">Описываешь боль и решение</div>
<div class="eq-box-desc">
Простыми словами в PRD. Знаешь домен — финансы. Не лезешь в технологии.
</div>
</div>
<div class="eq-op">+</div>
<div class="eq-box">
<div class="eq-box-label">Hard coding · разработчики</div>
<div class="eq-box-title">Полируют до прода</div>
<div class="eq-box-desc">
Безопасность, нагрузка, интеграции, поддержка. Их часть после твоей.
</div>
</div>
<div class="eq-op">=</div>
<div class="eq-box result">
<div class="eq-box-label">Enterprise solution</div>
<div class="eq-box-title">Часть инфраструктуры КТ</div>
<div class="eq-box-desc">
Твой MVP становится сервисом, которым пользуются коллеги. Реально, не «на потом».
</div>
</div>
</div>
<div class="eq-note">
<div class="eq-note-item">
<div class="eq-note-icon">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M8 1l2 2h4v10H2V3h4l2-2z"/>
<path d="M6 8l2 2 4-4"/>
</svg>
</div>
<div class="eq-note-text">
<strong>Документация и помощь рядом.</strong> Справочные файлы лежат в твоей папке. Telegram-чат — для вопросов. Админы платформы — у тебя за плечом.
</div>
</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">07 — Программа первого занятия</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">
<div class="section-label">08 — Словарь</div>
<h2 class="section-title">Термины,<br><em>которые услышишь</em></h2>
<p class="section-body">
11 слов, которые встретятся сегодня. Без технического жаргона. Листай стрелками или свайпом.
</p>
<div class="glossary-slider">
<div class="glossary" id="glossary-list"></div>
<div class="gloss-nav">
<button type="button" id="gloss-prev" class="gloss-nav-btn" aria-label="Назад">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="10,3 5,8 10,13"/></svg>
</button>
<span class="gloss-counter" id="gloss-counter">1 / 11</span>
<button type="button" id="gloss-next" class="gloss-nav-btn" aria-label="Вперёд">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6,3 11,8 6,13"/></svg>
</button>
</div>
</div>
</div>
</section>
<!-- SECTION 6: PROJECTS -->
<section class="section" id="projects">
<div class="container">
<div class="section-label">09 — Твой проект</div>
<h2 class="section-title">Ты знаешь<br><em>боль изнутри</em></h2>
<p class="section-body">
Лучший проект — тот, где ты сам тратишь время впустую. Вот примеры из финансовых департаментов —
выбери ближайший или опиши свой.
</p>
<div class="projects-grid" id="projects-grid"></div>
</div>
</section>
<!-- SECTION: PROMPT CHEATSHEET -->
<section class="section" id="prompts">
<div class="container">
<div class="section-label">10 — Шпаргалка промптов</div>
<h2 class="section-title">Что писать<br><em>Claude'у</em></h2>
<p class="section-body">
Не знаешь с чего начать диалог? Скопируй готовый промпт, замени в нём текст в квадратных скобках на свой контекст. По шагам Action Plan + бонус для работы с Excel.
</p>
<div class="prompts" id="prompts-list"></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">
Жми «Войти» наверху — введи своё имя — и через 5 секунд ты в своей папке с готовыми файлами.
</p>
<button type="button" class="dark-cta" onclick="document.getElementById('nav-auth').click()" style="border:none;cursor:pointer;font-family:inherit">
Войти и начать →
</button>
</div>
</div>
</section>
<!-- FOOTER -->
<footer>
<span class="footer-copy">Казахтелеком · Движение инноваторов</span>
<div class="footer-links">
<a href="https://git.telecom.quest" target="_blank" rel="noopener" class="footer-link">Git</a>
<a href="https://t.me/+9UI8dt-60l8yMzJi" target="_blank" rel="noopener" class="footer-link">Telegram</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: 'Mock',
abbr: 'Mock',
definition: 'Тестовые данные вместо реальных. Например: вместо реальных платёжек из 1С — файл с похожей структурой, но с выдуманными суммами и контрагентами. Позволяет разрабатывать без доступа к боевым системам.'
},
{
term: 'Итерация',
abbr: 'Итерация',
definition: 'Один цикл: <strong>сделал → проверил → улучшил</strong>. В разработке через Claude это занимает минуты. Описал задачу → получил код → запустил → увидел что не так → поправил описание → снова запустил. Это и есть вайб-кодинг.'
},
{
term: 'Промпт',
abbr: 'Prompt',
definition: 'Твоя инструкция для Claude. Чем точнее описание — тем точнее результат. Хороший промпт = хороший PRD: контекст, задача, ограничения, критерий успеха. Всё что ты пишешь в Claude Desktop — это промпты.'
},
{
term: 'Dream to be',
abbr: 'Dream',
definition: 'Самая лучшая версия твоего решения, как ты её видишь в идеале. Опиши её в PRD без оглядки на «реально ли это» — Claude сам подскажет, что упростить.'
},
{
term: 'Git',
abbr: 'Git',
definition: 'Хранилище версий проекта. Каждое изменение записывается с подписью «когда» и «кто». Можно вернуться к любой прошлой версии. В VS Code это панель слева <strong>«Source Control»</strong> — кнопкой Commit & Push отправляешь свою работу в kt-innovators на git.telecom.quest.'
},
{
term: 'CSV',
abbr: 'CSV',
definition: 'Текстовый файл табличных данных. Excel открывает его как обычную таблицу. Хорош тем, что его легко читает и человек, и Claude — отдай CSV ИИ и попроси «найди аномалии» / «построй график».'
},
{
term: 'Markdown',
abbr: '.md',
definition: '<strong>Файл <code>.md</code></strong> — обычный текст с минимальным форматированием (заголовки, списки, ссылки). PRD.md, TRD.md, README.md — всё это markdown. Открывается в любом редакторе.'
}
];
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: ['Поиск', 'Архив', 'Документы']
},
{
num: '07',
title: 'Бот-напоминалка о платежах',
pain: 'У меня в голове 20 регулярных платежей в разные дни месяца. Постоянно боюсь что-то забыть. Хочу TG-бот, который пинает за день до дедлайна.',
tags: ['Telegram-бот', 'Напоминания', 'Календарь']
},
{
num: '08',
title: 'Конвертер валютных операций',
pain: 'Для отчёта по валютным операциям нужно пересчитать суммы по курсу НБРК на дату транзакции. Делаю в Excel, тратится час. Хочу одну кнопку.',
tags: ['Валюта', 'НБРК', 'Курс']
}
];
const PROMPTS = [
{
step: 'Шаг 1',
title: 'Помоги написать PRD',
context: 'Открой Claude. Опиши свою рабочую боль одним абзацем — Claude задаст уточняющие вопросы и оформит PRD.md.',
body: `Я финансист в Казахтелеком. Помоги мне написать PRD.md — описание идеи продукта простыми словами.
Моя ситуация: [замени на свой текст — что болит, что хочешь автоматизировать]
Сначала задай мне 3-5 уточняющих вопросов. Потом, на основе моих ответов, оформи PRD.md по структуре:
- Что я хочу автоматизировать (одно предложение)
- Кто будет пользоваться
- Что должно произойти на выходе
- Список из 3-5 главных функций
- Что НЕ входит в задачу
Пиши без программистских терминов.`
},
{
step: 'Шаг 2',
title: 'Сгенерируй TRD из PRD',
context: 'Когда PRD.md готов — попроси Claude перевести его в техническое задание.',
body: `Прочитай файл PRD.md (моя идея, написана простыми словами).
Сгенерируй TRD.md — техническое задание для разработки MVP:
- Какие данные нужны
- Минимальный стек (HTML/CSS/JS, или Python+FastAPI, или Node.js — выбери проще)
- Структура папок проекта
- Как запускать
Цель — рабочий MVP за час, не идеальная архитектура.
Сохрани результат в TRD.md, заменив текущее содержимое файла.`
},
{
step: 'Шаг 3',
title: 'Запусти Claude Code на TRD',
context: 'В терминале VS Code вызови claude code — потом вставь этот промпт. Claude напишет код прямо в твою папку.',
body: `Прочитай TRD.md в текущей папке. Реализуй MVP по нему.
Принципы:
- Простой стек (предпочтительно HTML+CSS+JS без сборки)
- Все файлы в текущей папке
- Никаких внешних API-ключей и платных сервисов
- Если нужны данные — используй mock-значения, понятные финансисту
В конце:
1. Напиши команду запуска (например, "открой index.html в браузере" или "python3 -m http.server 8000")
2. Список того, что готово, и что осталось доделать.`
},
{
step: 'Шаг 4',
title: 'Когда что-то сломалось',
context: 'Получил ошибку или результат выглядит странно — опиши Claude словами что видишь, остальное он разберёт сам.',
body: `Запусти приложение из текущей папки.
Опиши, какую ошибку видишь (если есть). Если ошибки нет — опиши, что выглядит не так.
Затем:
1. Найди причину
2. Исправь код
3. Перезапусти
4. Покажи, что теперь работает
Не спрашивай у меня дополнительных деталей — действуй.`
},
{
step: 'Шаг 5',
title: 'Улучши результат',
context: 'MVP работает — теперь делаешь итерацию: одно улучшение за раз. Каждая правка — это новый промпт.',
body: `Сейчас в приложении нужно изменить одну вещь:
[замени на свой запрос — например: "цифры должны быть с разделителями тысяч",
"добавь фильтр по дате", "сделай заголовок жирным"]
Внеси изменение. Не трогай остальное.
Опиши одной строкой, что именно ты поменял.`
},
{
step: 'Бонус',
bonus: true,
title: 'Разобрать Excel/CSV-файл',
context: 'У тебя есть таблица из 1С или Excel? Сохрани её как CSV и попроси Claude найти полезное.',
body: `У меня есть файл [имя_файла.csv] с данными о [тип данных, например: "платежах за квартал"].
Прочитай его и покажи мне:
1. Сколько всего строк
2. Какие колонки (с короткими комментариями что они значат)
3. Топ-5 самых крупных значений
4. 3-5 аномалий или выбросов (дубликаты, странные суммы, пустые поля)
5. Один график, который покажет главную закономерность
Используй простые слова — я финансист, не программист.`
},
{
step: 'Бонус',
bonus: true,
title: 'Сделай Telegram-бот',
context: 'Хочешь бот, который что-то считает или напоминает? Этот промпт даст работающий бот за один запуск.',
body: `Сделай простой Telegram-бот на Python (python-telegram-bot).
Бот делает: [замени на задачу — например: "при команде /курс отвечает текущим курсом USD к KZT",
"присылает напоминание каждый день в 9:00", "по сообщению с числом выдаёт его в разных валютах"]
Требования:
- Один файл bot.py
- Токен бота читать из переменной окружения TG_TOKEN
- Минимум зависимостей в requirements.txt
- README.md: как получить токен через @BotFather и как запустить
Покажи код и инструкцию.`
}
];
const SCHEDULE = [
{
time: '09:00',
title: 'Введение в вайб-кодинг',
desc: 'Что изменилось. Почему финансисты — идеальные разработчики. Первое знакомство с Claude.',
tags: ['Теория'],
active: false
},
{
time: '09:45',
title: 'Инструменты и среда',
desc: 'Настройка Claude Desktop, telecom.quest VSCode.',
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 as horizontal slider with prev/next buttons
const glossaryEl = document.getElementById('glossary-list');
GLOSSARY.forEach(item => {
const div = document.createElement('div');
div.className = 'gloss-item';
div.innerHTML = `
<div class="gloss-trigger">
<span class="gloss-term">${item.term}</span>
<span class="gloss-abbr">${item.abbr}</span>
</div>
<div class="gloss-body">
<div class="gloss-inner">
<div class="gloss-text">${item.definition}</div>
</div>
</div>
`;
glossaryEl.appendChild(div);
});
// Glossary slider controls
(function initGlossSlider() {
const prev = document.getElementById('gloss-prev');
const next = document.getElementById('gloss-next');
const counter = document.getElementById('gloss-counter');
const cards = Array.from(glossaryEl.querySelectorAll('.gloss-item'));
const total = cards.length;
let idx = 0;
function update() {
counter.textContent = `${idx + 1} / ${total}`;
prev.disabled = idx === 0;
next.disabled = idx === total - 1;
}
function go(i) {
idx = Math.max(0, Math.min(total - 1, i));
cards[idx].scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest' });
update();
}
function syncFromScroll() {
const baseLeft = glossaryEl.getBoundingClientRect().left;
let best = 0, bestDist = Infinity;
for (let i = 0; i < cards.length; i++) {
const d = Math.abs(cards[i].getBoundingClientRect().left - baseLeft);
if (d < bestDist) { bestDist = d; best = i; }
}
if (best !== idx) { idx = best; update(); }
}
prev.addEventListener('click', () => go(idx - 1));
next.addEventListener('click', () => go(idx + 1));
glossaryEl.addEventListener('scroll', syncFromScroll, { passive: true });
update();
})();
// 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);
});
// Render prompt cheatsheet
const promptsEl = document.getElementById('prompts-list');
function escapeHtml(s) {
return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
PROMPTS.forEach((item, i) => {
const card = document.createElement('div');
card.className = 'prompt-card';
card.innerHTML = `
<div class="prompt-head">
<span class="prompt-step${item.bonus ? ' bonus' : ''}">${item.step}</span>
<span class="prompt-title">${item.title}</span>
</div>
<div class="prompt-context">${item.context}</div>
<div class="prompt-box">
<button type="button" class="prompt-copy" data-idx="${i}" aria-label="Скопировать">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="5" y="5" width="9" height="9" rx="1"/><path d="M11 5V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h2"/>
</svg>
Скопировать
</button>
<pre>${escapeHtml(item.body)}</pre>
</div>
`;
promptsEl.appendChild(card);
});
// Wire copy buttons
promptsEl.addEventListener('click', async (e) => {
const btn = e.target.closest('.prompt-copy');
if (!btn) return;
const idx = +btn.dataset.idx;
try {
await navigator.clipboard.writeText(PROMPTS[idx].body);
const originalHTML = btn.innerHTML;
btn.classList.add('copied');
btn.innerHTML = '<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3,8 7,12 13,4"/></svg> Скопировано';
setTimeout(() => {
btn.classList.remove('copied');
btn.innerHTML = originalHTML;
}, 1800);
} catch (err) {
btn.textContent = 'Не вышло :(';
}
});
/* ── AUTH ──────────────────────────────────────────────
Smart single-form auth backed by register.telecom.quest.
- Login first (works for both FIO and CDN inputs).
- On 404 with FIO input → register (creates folder + Gitea repo).
- On 404 with CDN input → "not found, type your full name to register".
*/
const API_BASE = 'https://register.telecom.quest/api';
const CODE_BASE = 'https://code.telecom.quest/?folder=/Users/telecom/dev/_hack19may/';
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, vscodeUrl) {
window.location.href = vscodeUrl || (CODE_BASE + encodeURIComponent(cdn) + '/');
}
async function apiCall(path, body) {
const res = await fetch(API_BASE + path, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const data = await res.json().catch(() => ({}));
return { ok: res.ok, status: res.status, data };
}
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/_hack19may/${cdn}/`;
if (mode === 'login') {
hint.innerHTML = `Откроется <code>${path}</code>`;
} else {
hint.innerHTML = `Твой CDN: <code>${cdn}</code> → <code>${path}</code>`;
}
submit.disabled = false;
});
async function handleSubmit() {
const { cdn, mode } = makeCdn(input.value);
if (!cdn) return;
submit.disabled = true;
submit.textContent = 'Проверяю...';
hint.classList.remove('error');
try {
// Step 1: try login (works for both CDN and FIO inputs)
const login = await apiCall('/login', { value: input.value.trim() });
if (login.ok) {
localStorage.setItem(STORAGE_KEY, login.data.cdn);
refreshHeader();
redirectTo(login.data.cdn, login.data.vscode_url);
return;
}
// Step 2: not found — auto-register with whatever was typed
if (login.status === 404) {
submit.textContent = 'Создаю аккаунт...';
hint.innerHTML = `Аккаунт <code>${cdn}</code> не найден — создаю новый...`;
// FIO mode → send fio (backend will generate cdn); CDN mode → send cdn directly
const regBody = mode === 'fio'
? { fio: input.value.trim() }
: { cdn: input.value.trim() };
const reg = await apiCall('/register', regBody);
if (reg.ok) {
localStorage.setItem(STORAGE_KEY, reg.data.cdn);
refreshHeader();
redirectTo(reg.data.cdn, reg.data.vscode_url);
return;
}
const msg = reg.data?.detail?.message || reg.data?.detail?.error || `HTTP ${reg.status}`;
hint.textContent = `Не удалось создать: ${msg}`;
hint.classList.add('error');
} else {
const msg = login.data?.detail?.message || login.data?.detail?.error || `HTTP ${login.status}`;
hint.textContent = `Ошибка: ${msg}`;
hint.classList.add('error');
}
} catch (err) {
hint.textContent = `Ошибка сети: ${err.message || err}`;
hint.classList.add('error');
} finally {
submit.disabled = false;
submit.textContent = 'Открыть VS Code →';
}
}
submit.addEventListener('click', handleSubmit);
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !submit.disabled) handleSubmit();
if (e.key === 'Escape') closeModal();
});
authBtn.addEventListener('click', () => {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
// Direct redirect using saved CDN — fast path, no API hit
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();
/* ── THEME TOGGLE ───────────────────────────────────────
Manual override stored in localStorage. Falls back to system
(prefers-color-scheme) when no explicit choice. */
(function initThemeToggle() {
const btn = document.getElementById('theme-toggle');
if (!btn) return;
function currentTheme() {
const explicit = document.documentElement.getAttribute('data-theme');
if (explicit) return explicit;
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
btn.addEventListener('click', () => {
const next = currentTheme() === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
try { localStorage.setItem('vibe.theme', next); } catch (e) {}
});
})();
/* ── POLISH: scroll-triggered fade-in ────────────────────
Marks all direct content blocks inside <section class="section">
with .reveal, then toggles .in on intersection.
Respects prefers-reduced-motion via CSS fallback. */
(function initReveal() {
if (!('IntersectionObserver' in window)) return;
const targets = document.querySelectorAll(
'.section .container > *, .section .container .section-header > *'
);
targets.forEach(el => el.classList.add('reveal'));
const io = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
e.target.classList.add('in');
io.unobserve(e.target);
}
});
}, { rootMargin: '0px 0px -60px 0px', threshold: 0.05 });
targets.forEach(el => io.observe(el));
})();
</script>
</body>
</html>