- Cream paper bg (#f5efe1), warm black text, deep-red accent - Playfair Display headlines + Lora italic body (serif throughout) - Flat cards: no border-radius, no shadows, thin dividers - Section labels: small-caps Inter with underline - Magazine-style nav header, flat black CTAs - Slide counter "— 1 / N —" pinned bottom-right - Hover: border color only, no lift Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3087 lines
108 KiB
HTML
3087 lines
108 KiB
HTML
<!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&family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400&family=Lora: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: clamp(18px, 1.6vw, 28px); /* масштабируется под экран — для проектора 24–28px */
|
||
scroll-snap-type: y mandatory;
|
||
}
|
||
|
||
/* PRESENTATION MODE: каждая секция = ровно 1 экран, фиксация при скролле */
|
||
.hero,
|
||
section.section,
|
||
.dark-section {
|
||
scroll-snap-align: start;
|
||
scroll-snap-stop: always;
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
padding-top: 4vh;
|
||
padding-bottom: 4vh;
|
||
overflow-y: auto; /* если контент длиннее — скролл внутри слайда */
|
||
}
|
||
|
||
/* Усиливаем типографику для большого экрана */
|
||
.section-title { font-size: clamp(2rem, 3.6vw, 3.4rem) !important; line-height: 1.15; }
|
||
.hero-title { font-size: clamp(2.4rem, 5vw, 5rem) !important; line-height: 1.1; }
|
||
.section-body, .hero-sub { font-size: clamp(1rem, 1.3vw, 1.4rem) !important; }
|
||
.section-label { font-size: clamp(0.85rem, 1vw, 1.1rem) !important; }
|
||
.dark-title { font-size: clamp(2.2rem, 4vw, 4rem) !important; }
|
||
.dark-sub { font-size: clamp(1rem, 1.3vw, 1.4rem) !important; max-width: 600px; }
|
||
|
||
/* Контейнер шире на больших экранах */
|
||
@media (min-width: 1400px) {
|
||
.container { max-width: 1280px; }
|
||
nav { max-width: 1280px; }
|
||
}
|
||
|
||
/* Прячем sticky-нав в slide-режиме — мешает фиксации экранов */
|
||
nav { position: static !important; scroll-snap-align: none; }
|
||
|
||
/* ──────────────────────────────────────────────────────────
|
||
EDITORIAL / NYT REDESIGN — кремовый фон, serif, флэт
|
||
────────────────────────────────────────────────────────── */
|
||
:root {
|
||
--page-bg: #f5efe1; /* кремовая бумага */
|
||
--bg: #f5efe1;
|
||
--surface: #fbf7ec;
|
||
--card-neutral: #ece4d2;
|
||
--text: #1a1410; /* почти чёрный с тёплым оттенком */
|
||
--text-65: rgba(26,20,16,0.72);
|
||
--text-55: rgba(26,20,16,0.58);
|
||
--text-45: rgba(26,20,16,0.42);
|
||
--border: rgba(26,20,16,0.15);
|
||
--border-strong: rgba(26,20,16,0.28);
|
||
--hover: rgba(26,20,16,0.05);
|
||
--blue: #a8201a; /* журнальный красный вместо синего */
|
||
--blue-hover: #7e1813;
|
||
--blue-link: #a8201a;
|
||
}
|
||
[data-theme="dark"] {
|
||
--page-bg: #1a1714;
|
||
--bg: #1a1714;
|
||
--surface: #221d18;
|
||
--card-neutral: #2b251f;
|
||
--text: #f1e9d6;
|
||
--text-65: rgba(241,233,214,0.72);
|
||
--text-55: rgba(241,233,214,0.55);
|
||
--text-45: rgba(241,233,214,0.40);
|
||
--border: rgba(241,233,214,0.14);
|
||
--border-strong: rgba(241,233,214,0.28);
|
||
--hover: rgba(241,233,214,0.06);
|
||
--blue: #e07a72;
|
||
--blue-hover: #f1968e;
|
||
--blue-link: #e07a72;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Lora', Georgia, serif !important;
|
||
background: var(--page-bg);
|
||
padding: 0;
|
||
}
|
||
|
||
.frame { gap: 0; min-height: 100dvh; }
|
||
|
||
/* Шрифты заголовков */
|
||
.hero-title, .section-title, .dark-title,
|
||
.eq-box-title, .plan-step-title, .tool-name,
|
||
.create-card-title, .project-title, .gloss-term,
|
||
.prompt-title, .check-title, .modal-title,
|
||
.tg-text-title, .card-title, .ba-label {
|
||
font-family: 'Playfair Display', Georgia, serif !important;
|
||
font-weight: 400 !important;
|
||
letter-spacing: -0.01em !important;
|
||
}
|
||
|
||
/* HERO — журнальная обложка */
|
||
.hero {
|
||
background-image: none;
|
||
mask-image: none;
|
||
-webkit-mask-image: none;
|
||
text-align: center;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.hero-title {
|
||
font-weight: 900 !important;
|
||
letter-spacing: -0.04em !important;
|
||
line-height: 0.95 !important;
|
||
}
|
||
.hero-title em, .section-title em {
|
||
font-style: italic !important;
|
||
text-decoration: none !important;
|
||
color: var(--blue);
|
||
font-weight: 400 !important;
|
||
}
|
||
.underline-blue {
|
||
text-decoration: none !important;
|
||
font-style: italic;
|
||
color: var(--blue);
|
||
}
|
||
|
||
/* Section label = SMALL CAPS */
|
||
.section-label {
|
||
font-family: 'Inter', sans-serif !important;
|
||
text-transform: uppercase !important;
|
||
letter-spacing: 0.18em !important;
|
||
font-weight: 500 !important;
|
||
color: var(--text-45) !important;
|
||
border-bottom: 1px solid var(--border);
|
||
padding-bottom: 8px;
|
||
margin-bottom: 24px;
|
||
display: inline-block;
|
||
}
|
||
|
||
/* Section разделители = тонкие линии, не блоки */
|
||
.section {
|
||
border-top: 1px solid var(--border) !important;
|
||
background: var(--page-bg);
|
||
}
|
||
|
||
/* Карточки — флэт, без скруглений и теней */
|
||
.card, .tool-card, .create-card, .plan-step, .gloss-item,
|
||
.project-card, .prompt-card, .eq-box, .check-card, .ba-card,
|
||
main, nav {
|
||
border-radius: 0 !important;
|
||
box-shadow: none !important;
|
||
background: transparent !important;
|
||
border: 1px solid var(--border) !important;
|
||
}
|
||
.create-card, .card { background: var(--card-neutral) !important; }
|
||
.eq-box.you { background: rgba(168,32,26,0.08) !important; border-color: var(--blue) !important; }
|
||
.eq-box.result { background: var(--surface) !important; }
|
||
|
||
/* CTA — журнальная кнопка с подчёркиванием */
|
||
.nav-cta, .btn-primary, .tg-cta, .dark-cta, .modal-submit {
|
||
border-radius: 0 !important;
|
||
background: var(--text) !important;
|
||
color: var(--page-bg) !important;
|
||
font-family: 'Inter', sans-serif !important;
|
||
font-weight: 500 !important;
|
||
text-transform: uppercase !important;
|
||
letter-spacing: 0.1em !important;
|
||
font-size: 0.85rem !important;
|
||
}
|
||
.nav-cta:hover, .btn-primary:hover, .tg-cta:hover, .modal-submit:hover {
|
||
background: var(--blue) !important;
|
||
}
|
||
|
||
/* Body-текст — serif */
|
||
.section-body, .hero-sub, .card-desc, .tool-role, .project-pain,
|
||
.plan-step-desc, .create-card-desc, .gloss-text, .check-list li,
|
||
.dark-sub, .modal-sub, .ba-row, .tg-text-body, .eq-box-desc, .prompt-context {
|
||
font-family: 'Lora', Georgia, serif !important;
|
||
font-style: italic;
|
||
}
|
||
|
||
/* Nav — журнальный header */
|
||
nav {
|
||
border: none !important;
|
||
border-bottom: 2px solid var(--text) !important;
|
||
background: var(--page-bg) !important;
|
||
border-radius: 0 !important;
|
||
margin: 0 !important;
|
||
max-width: 100% !important;
|
||
}
|
||
.nav-inner { max-width: 1280px; margin: 0 auto; padding: 0 32px; }
|
||
.logo-text {
|
||
font-family: 'Playfair Display', serif;
|
||
font-style: italic;
|
||
font-size: 1.2rem;
|
||
}
|
||
.logo-mark {
|
||
background: var(--blue) !important;
|
||
border-radius: 0 !important;
|
||
font-family: 'Inter', sans-serif;
|
||
}
|
||
.nav-link {
|
||
font-family: 'Inter', sans-serif;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.08em;
|
||
font-size: 0.75rem !important;
|
||
}
|
||
|
||
/* Drop-cap первое слово в hero (как в журналах) */
|
||
.hero-inner .badge {
|
||
font-family: 'Inter', sans-serif;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.2em;
|
||
border-top: 1px solid var(--text);
|
||
border-bottom: 1px solid var(--text);
|
||
padding: 6px 14px !important;
|
||
display: inline-block;
|
||
}
|
||
|
||
/* Slide-counter — номер страницы внизу */
|
||
.slide-counter {
|
||
position: fixed;
|
||
bottom: 18px;
|
||
right: 24px;
|
||
font-family: 'Playfair Display', serif;
|
||
font-style: italic;
|
||
font-size: 1rem;
|
||
color: var(--text-55);
|
||
z-index: 80;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* Project cards — карточки журнала */
|
||
.project-num {
|
||
font-family: 'Playfair Display', serif !important;
|
||
font-style: italic;
|
||
font-size: 1.5rem !important;
|
||
color: var(--blue) !important;
|
||
letter-spacing: 0 !important;
|
||
}
|
||
.project-title { font-size: 1.5rem !important; line-height: 1.2 !important; }
|
||
|
||
/* Глоссарий, инструменты — приподнимаем шрифт */
|
||
.gloss-term { font-size: 1.3rem !important; }
|
||
.tool-name { font-size: 1.2rem !important; }
|
||
.plan-step-title { font-size: 1.2rem !important; }
|
||
|
||
/* Убираем скругления QR-фрейма */
|
||
.tg-qr, .tg-block, .dark-section { border-radius: 0 !important; }
|
||
.dark-section {
|
||
background: var(--text) !important;
|
||
margin: 0 !important;
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
.dark-title { color: var(--page-bg) !important; }
|
||
.dark-sub { color: rgba(255,255,255,0.7) !important; }
|
||
.dark-cta { background: var(--page-bg) !important; color: var(--text) !important; }
|
||
|
||
/* Hover убираем подъём — для флэт-журнала не подходит */
|
||
.tool-card:hover, .create-card:hover, .plan-step:hover,
|
||
.gloss-item:hover, .prompt-card:hover, .eq-box:hover,
|
||
.project-card:hover, .check-card:hover {
|
||
transform: none !important;
|
||
box-shadow: none !important;
|
||
border-color: var(--blue) !important;
|
||
}
|
||
|
||
/* Footer */
|
||
footer {
|
||
background: var(--text);
|
||
color: var(--page-bg);
|
||
border: none !important;
|
||
}
|
||
.footer-copy, .footer-link {
|
||
color: rgba(255,255,255,0.7) !important;
|
||
font-family: 'Inter', sans-serif;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.1em;
|
||
font-size: 0.7rem !important;
|
||
}
|
||
|
||
/* ── 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>
|
||
<div class="slide-counter" id="slide-counter" aria-hidden="true">— 1 —</div>
|
||
<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"> </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: 'Хочу одну ссылку: кто я, чем занимаюсь, контакты, фото, проекты. Чтобы скинуть рекрутёру, заказчику или новому знакомому вместо длинного объяснения в мессенджере.',
|
||
tags: ['Личный сайт', 'Портфолио', 'Для себя']
|
||
},
|
||
{
|
||
num: '02',
|
||
title: 'Трекер привычек',
|
||
pain: 'Хочу каждый день отмечать: пил воду, тренировался, читал. Видеть свой стрик и не сбиваться. Без подписок и регистраций — просто открыл и щёлкнул.',
|
||
tags: ['Привычки', 'Здоровье', 'Личное']
|
||
},
|
||
{
|
||
num: '03',
|
||
title: 'Чек-лист подготовки к мероприятию',
|
||
pain: 'Организую встречу/тренинг/выезд — каждый раз пишу одно и то же в блокноте. Хочу шаблон-чек-лист со статусами и распределением задач между коллегами.',
|
||
tags: ['HR', 'Маркетинг', 'Командная работа']
|
||
},
|
||
{
|
||
num: '04',
|
||
title: 'Каталог внутренних регламентов',
|
||
pain: 'Документы и инструкции лежат на 5 разных дисках и в почте. Когда новичок спрашивает «как сделать X» — ищу полчаса. Нужна одна страница с поиском.',
|
||
tags: ['HR', 'База знаний', 'Поиск']
|
||
},
|
||
{
|
||
num: '05',
|
||
title: 'Опросник для клиентов / коллег',
|
||
pain: 'Хочу быстро собрать обратную связь — без Google Forms и подписки на SurveyMonkey. Своя страница, свои вопросы, результаты в табличке.',
|
||
tags: ['Опрос', 'Маркетинг', 'CSAT']
|
||
},
|
||
{
|
||
num: '06',
|
||
title: 'Генератор коммерческих предложений',
|
||
pain: 'Каждое КП собираю вручную в Word: меняю имя клиента, цены, сроки. Хочу форму — ввёл данные, получил PDF с моим оформлением.',
|
||
tags: ['Продажи', 'PDF', 'Шаблоны']
|
||
},
|
||
{
|
||
num: '07',
|
||
title: 'План-меню на неделю',
|
||
pain: 'Каждое воскресенье думаю «что готовить эту неделю». Хочу страницу: рецепты по дням, автоматический список покупок, чтобы один раз сходить в магазин.',
|
||
tags: ['Личное', 'Быт', 'Список покупок']
|
||
},
|
||
{
|
||
num: '08',
|
||
title: 'Учёт расходов простыми словами',
|
||
pain: 'Mint/CoinKeeper слишком сложные. Хочу 3 кнопки: «потратил столько-то на еду/транспорт/прочее» и график по неделям.',
|
||
tags: ['Финансы', 'Личное', 'Бюджет']
|
||
},
|
||
{
|
||
num: '09',
|
||
title: 'Бот-напоминалка в Telegram',
|
||
pain: 'Постоянно забываю про регулярные дела — оплатить интернет, поздравить коллегу, продлить подписку. Хочу простой TG-бот, который пинает за день до.',
|
||
tags: ['Telegram-бот', 'Напоминания', 'Календарь']
|
||
},
|
||
{
|
||
num: '10',
|
||
title: 'Лендинг для своего хобби / услуги',
|
||
pain: 'Делаю торты на заказ / тренирую / преподаю английский — но «портфолио» в Instagram неудобно показывать. Хочу одну страницу с примерами и формой заявки.',
|
||
tags: ['Лендинг', 'Услуги', 'Заявки']
|
||
},
|
||
{
|
||
num: '11',
|
||
title: 'Мини-CRM для своих клиентов',
|
||
pain: 'Веду 20 клиентов в Excel-табличке: имя, телефон, что обсуждали, когда позвонить. Хочу страницу с карточками, напоминаниями и заметками.',
|
||
tags: ['CRM', 'Продажи', 'Малый бизнес']
|
||
},
|
||
{
|
||
num: '12',
|
||
title: 'Тренажёр терминов / слов',
|
||
pain: 'Учу английский / готовлюсь к экзамену / запоминаю аббревиатуры. Хочу карточки-флешкарды: показал термин — вспомнил — перевернул — отметил «знаю / повторить».',
|
||
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, '&').replace(/</g, '<').replace(/>/g, '>');
|
||
}
|
||
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 = ' ';
|
||
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 = ' ';
|
||
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));
|
||
})();
|
||
|
||
// Slide counter — показывает текущий слайд / всего
|
||
(function() {
|
||
const counter = document.getElementById('slide-counter');
|
||
if (!counter) return;
|
||
const slides = Array.from(document.querySelectorAll('.hero, section.section, .dark-section'));
|
||
const total = slides.length;
|
||
const update = (idx) => {
|
||
counter.textContent = `— ${idx + 1} / ${total} —`;
|
||
};
|
||
update(0);
|
||
const io = new IntersectionObserver((entries) => {
|
||
entries.forEach(e => {
|
||
if (e.isIntersecting && e.intersectionRatio > 0.5) {
|
||
const idx = slides.indexOf(e.target);
|
||
if (idx >= 0) update(idx);
|
||
}
|
||
});
|
||
}, { threshold: [0.5, 0.6, 0.75] });
|
||
slides.forEach(s => io.observe(s));
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|