between-1323/frontend/src/features/PreviewApp.html
2026-10-21 14:06:16 +00:00

1477 lines
95 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>между. — CHAPTER / Литературный журнал о близости 18+</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=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;0,700;1,400;1,600&family=Inter:wght@300;400;500;600&family=Manrope:wght@400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root {
--bg-paper: #F5F0E8;
--bg-surface: #FFFDFA;
--bg-subtle: #EAE2D6;
--text-ink: #24211D;
--text-meta: #686158;
--border-hairline: #D8CFC3;
--border-warm: #D6B39B;
--accent-wine: #793C49;
--accent-wine-hover: #612E39;
--accent-wine-soft: #F3E8EA;
--video-dark: #211A18;
--video-surface: #29241F;
--reading-size: 20px;
--reading-lh: 32px;
}
body.theme-noir {
--bg-paper: #10121A;
--bg-surface: #1C2030;
--bg-subtle: #252B3D;
--text-ink: #F6F7F2;
--text-meta: #B9C0D0;
--border-hairline: #2E364B;
--border-warm: #3E4760;
--accent-wine: #C9F26F;
--accent-wine-hover: #B5E055;
--accent-wine-soft: rgba(201, 242, 111, 0.12);
}
body {
background-color: var(--bg-paper);
color: var(--text-ink);
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
line-height: 1.55;
transition: background-color 0.25s ease, color 0.25s ease;
margin: 0;
}
.font-serif-editorial {
font-family: 'Cormorant Garamond', Georgia, serif;
}
.reading-prose p {
font-family: 'Cormorant Garamond', Georgia, serif;
font-size: var(--reading-size);
line-height: var(--reading-lh);
color: var(--text-ink);
margin-bottom: 1.45em;
}
.hairline-border {
border-color: var(--border-hairline);
}
.surface-card {
background-color: var(--bg-surface);
border: 1px solid var(--border-hairline);
border-radius: 6px;
}
.subtle-box {
background-color: var(--bg-subtle);
border: 1px solid var(--border-hairline);
border-radius: 6px;
}
.btn-wine {
background-color: var(--accent-wine);
color: #FFFDFA;
border-radius: 6px;
font-weight: 500;
transition: all 0.18s ease;
}
body.theme-noir .btn-wine {
color: #10121A;
font-weight: 600;
}
.btn-wine:hover {
background-color: var(--accent-wine-hover);
}
.btn-outline-editorial {
background-color: var(--bg-surface);
color: var(--text-ink);
border: 1px solid var(--border-hairline);
border-radius: 6px;
transition: all 0.18s ease;
}
.btn-outline-editorial:hover {
border-color: var(--accent-wine);
}
.nav-item {
display: flex;
align-items: center;
gap: 8px;
padding: 7px 10px;
border-radius: 5px;
font-size: 14px;
color: var(--text-meta);
cursor: pointer;
transition: all 0.15s ease;
text-align: left;
width: 100%;
}
.nav-item:hover {
color: var(--text-ink);
background-color: rgba(121, 60, 73, 0.06);
}
.nav-item.active {
color: var(--text-ink);
font-weight: 600;
background-color: var(--accent-wine-soft);
}
.nav-item.active::before {
content: "•";
color: var(--accent-wine);
font-weight: bold;
margin-right: 2px;
}
.meta-text {
color: var(--text-meta);
}
.wine-text {
color: var(--accent-wine);
}
.wine-badge {
background-color: var(--accent-wine-soft);
color: var(--accent-wine);
border: 1px solid rgba(121, 60, 73, 0.22);
border-radius: 4px;
padding: 2px 8px;
font-size: 12px;
font-weight: 500;
}
/* Atmospheric blurred cinema frame for locked video adaptation */
.cinema-poster-locked {
background:
radial-gradient(circle at 72% 38%, rgba(214, 179, 155, 0.42), transparent 45%),
radial-gradient(circle at 28% 70%, rgba(121, 60, 73, 0.55), transparent 55%),
linear-gradient(135deg, #201A18 0%, #382927 50%, #1B1615 100%);
position: relative;
overflow: hidden;
}
.cinema-poster-locked::after {
content: "";
position: absolute;
inset: 0;
backdrop-filter: blur(14px);
background: rgba(32, 26, 24, 0.38);
}
.cinema-player-unlocked {
background:
radial-gradient(circle at 68% 32%, rgba(214, 179, 155, 0.28), transparent 45%),
radial-gradient(circle at 30% 65%, rgba(121, 60, 73, 0.35), transparent 55%),
linear-gradient(160deg, #211A18 0%, #2E2320 55%, #161210 100%);
}
</style>
</head>
<body class="min-h-screen flex flex-col lg:flex-row">
<!-- MOBILE HEADER (390px breakpoint from Figma) -->
<div class="lg:hidden flex items-center justify-between px-5 py-3.5 border-b hairline-border bg-[var(--bg-surface)] sticky top-0 z-30">
<div class="flex items-baseline gap-2.5 cursor-pointer" onclick="switchScreen('home')">
<span class="font-serif-editorial text-2xl font-semibold tracking-tight">между.</span>
<span class="text-[11px] uppercase tracking-widest meta-text">CHAPTER / 18+</span>
</div>
<div class="flex items-center gap-2">
<button onclick="toggleSubscriptionState()" id="mobSubBadge" class="text-[11px] px-2.5 py-1 rounded border hairline-border meta-text">
Подписка: выкл
</button>
<button onclick="document.getElementById('sidebarNav').classList.toggle('hidden')" class="px-3 py-1.5 rounded border hairline-border text-xs font-medium">
Меню · 18+
</button>
</div>
</div>
<!-- LEFT SIDEBAR (Exact 232px width from Figma spec 12:317745) -->
<aside id="sidebarNav" class="hidden lg:flex flex-col justify-between w-full lg:w-[232px] lg:shrink-0 border-r hairline-border bg-[var(--bg-paper)] px-5 py-7 select-none lg:min-h-screen">
<div class="space-y-6">
<!-- Brand Header -->
<div class="cursor-pointer" onclick="switchScreen('home')">
<div class="font-serif-editorial text-[32px] leading-none font-semibold tracking-tight">между.</div>
<div class="text-[11px] uppercase tracking-[0.14em] meta-text mt-2 font-medium">CHAPTER / ЖУРНАЛ 18+</div>
</div>
<!-- Primary Literary Navigation -->
<nav class="space-y-1">
<button onclick="switchScreen('home')" id="nav-home" class="nav-item active">Главная</button>
<button onclick="switchScreen('catalog')" id="nav-catalog" class="nav-item">Истории</button>
<button onclick="switchScreen('videos')" id="nav-videos" class="nav-item">Видео по историям</button>
<button onclick="switchScreen('continue')" id="nav-continue" class="nav-item">Продолжить чтение</button>
<button onclick="switchScreen('favorites')" id="nav-favorites" class="nav-item">Избранное</button>
</nav>
<!-- Secondary AI Format Navigation (Figma section: ДРУГОЙ ФОРМАТ · AI) -->
<div class="pt-4 border-t hairline-border space-y-1">
<div class="px-2.5 pb-1.5 text-[10px] uppercase tracking-[0.14em] meta-text font-semibold">ДРУГОЙ ФОРМАТ · AI</div>
<button onclick="switchScreen('ai_heroes')" id="nav-ai_heroes" class="nav-item">AI герои</button>
<button onclick="switchScreen('ai_chat')" id="nav-ai_chat" class="nav-item">Диалоги</button>
<button onclick="switchScreen('my_ai')" id="nav-my_ai" class="nav-item">Мои AI</button>
<button onclick="switchScreen('create_ai')" id="nav-create_ai" class="nav-item">Создать героя</button>
<button onclick="switchScreen('personal')" id="nav-personal" class="nav-item">Личное</button>
</div>
<!-- Account & Settings Navigation -->
<div class="pt-4 border-t hairline-border space-y-1">
<button onclick="switchScreen('subscription')" id="nav-subscription" class="nav-item">Подписка</button>
<button onclick="switchScreen('login')" id="nav-login" class="nav-item">Анна · Аккаунт</button>
<button onclick="switchScreen('settings')" id="nav-settings" class="nav-item">Настройки</button>
<button onclick="switchScreen('states')" id="nav-states" class="nav-item">Помощь · Состояния</button>
</div>
</div>
<!-- Bottom 18+ Editorial Note -->
<div class="pt-6 border-t hairline-border mt-8 space-y-3">
<div class="text-xs leading-relaxed meta-text">
<strong class="font-medium text-[var(--text-ink)] block mb-0.5">Только для взрослых 18+</strong>
Истории о чувствах и близости.
</div>
<div class="flex items-center justify-between text-[11px] meta-text pt-1">
<span>Тема Figma:</span>
<button onclick="toggleThemeNoir()" id="themeSwitchBtn" class="underline hover:text-[var(--text-ink)]">
CHAPTER (Бумага)
</button>
</div>
</div>
</aside>
<!-- MAIN EDITORIAL AREA (1440px Grid -> Remaining width with 48px desktop padding) -->
<div class="flex-1 flex flex-col min-w-0">
<!-- Top Section Bar (Полоса раздела + Поиск по журналу ⌘K + Interactive Subscription Toggle) -->
<header class="border-b hairline-border px-6 lg:px-12 py-3.5 flex flex-wrap items-center justify-between gap-4 bg-[var(--bg-paper)]">
<div class="flex items-center gap-3">
<span id="topBreadcrumb" class="text-xs font-medium tracking-wide uppercase meta-text">Главная</span>
<span class="meta-text opacity-40">·</span>
<button onclick="switchScreen('reader')" class="text-xs wine-text hover:underline font-medium">
📖 Открыть рассказ «После полуночи» + Видео ↓
</button>
</div>
<div class="flex flex-wrap items-center gap-3">
<!-- Quick Figma State Switcher for Founder Review -->
<div class="flex items-center gap-1.5 text-xs surface-card px-2.5 py-1">
<span class="meta-text text-[11px]">Режим видео в рассказах:</span>
<button onclick="setVideoAccess(false)" id="btnLockedState" class="px-2 py-0.5 rounded text-[11px] font-medium bg-[var(--accent-wine)] text-white">
🔒 Без подписки
</button>
<button onclick="setVideoAccess(true)" id="btnUnlockedState" class="px-2 py-0.5 rounded text-[11px] font-medium meta-text hover:text-[var(--text-ink)]">
🔓 Подписка активна (Плеер)
</button>
</div>
<!-- Search Trigger (Поиск по журналу ⌘K from Figma) -->
<div class="surface-card px-3 py-1.5 flex items-center gap-3 text-xs meta-text">
<span>Поиск по журналу</span>
<kbd class="text-[10px] px-1.5 py-0.5 rounded border hairline-border">⌘ K</kbd>
</div>
</div>
</header>
<!-- CONTENT CONTAINER (48px padding on desktop per Figma spec) -->
<main class="px-6 lg:px-12 py-8 lg:py-12 max-w-[1140px] w-full space-y-14">
<!-- ===================================================================== -->
<!-- SCREEN 1: ГЛАВНАЯ (Figma Frame 12:312192 · Главная · десктоп 1440px) -->
<!-- ===================================================================== -->
<section id="screen-home" class="space-y-12">
<!-- Editorial Hero -->
<div class="border-b hairline-border pb-10 space-y-4">
<div class="text-xs uppercase tracking-[0.14em] meta-text font-medium">
ЛИТЕРАТУРНЫЙ ЖУРНАЛ О БЛИЗОСТИ · 18+
</div>
<h1 class="font-serif-editorial text-4xl sm:text-6xl lg:text-[64px] leading-[1.02] font-normal tracking-tight">
Между строк.<br />Ближе к чувствам.
</h1>
<p class="text-base sm:text-lg meta-text max-w-xl leading-relaxed pt-1">
Законченные истории для неспешного чтения.<br />
Сначала — слова. Потом, если захочется, — кино.
</p>
</div>
<!-- Story of the Day (ИСТОРИЯ ДНЯ / 01 — После полуночи) -->
<div class="surface-card p-7 lg:p-10 grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
<div class="lg:col-span-7 space-y-4">
<div class="flex flex-wrap items-center gap-2.5">
<span class="text-xs uppercase tracking-[0.12em] wine-text font-semibold">ИСТОРИЯ ДНЯ / 01</span>
<span class="meta-text">·</span>
<span class="text-xs meta-text">Романтическая проза · 3 мин</span>
<span class="wine-badge">🎬 Есть видео · по подписке</span>
</div>
<h2 class="font-serif-editorial text-4xl sm:text-5xl leading-[1.05] font-normal cursor-pointer hover:opacity-80" onclick="openStoryReader(0)">
После полуночи
</h2>
<p class="text-base leading-relaxed">
Опоздав на последний трамвай, двое решают не торопить утро. Рассказ о смелости остаться рядом.
</p>
<div class="text-xs meta-text">
Персонажи: Вера, 31 · Матвей, 34 &nbsp;|&nbsp; Видео-экранизация в конце текста: 08:40
</div>
<div class="pt-2 flex flex-wrap items-center gap-3">
<button onclick="openStoryReader(0)" class="btn-wine px-6 py-3 text-sm inline-flex items-center gap-2">
<span>Читать историю</span>
<span>→</span>
</button>
<button onclick="openStoryReaderAndScrollVideo(0)" class="btn-outline-editorial px-4 py-3 text-xs font-medium">
К видео-экранизации (08:40) ↓
</button>
</div>
</div>
<div class="lg:col-span-5 subtle-box p-7 lg:p-8 flex flex-col justify-between min-h-[220px]">
<div class="text-[11px] uppercase tracking-widest meta-text">Цитата из рассказа</div>
<blockquote class="font-serif-editorial italic text-2xl sm:text-[26px] leading-snug my-4">
«Иногда достаточно опоздать, чтобы оказаться вовремя».
</blockquote>
<div class="text-xs meta-text flex items-center justify-between pt-3 border-t hairline-border">
<span>Полный текст бесплатный</span>
<span class="wine-text font-medium">Видео 08:40 после текста →</span>
</div>
</div>
</div>
<!-- Continue Reading Bookmark Widget (ВАША ЗАКЛАДКА · СЕГОДНЯ) -->
<div class="space-y-4">
<div class="flex items-center justify-between">
<h3 class="font-serif-editorial text-2xl font-medium">На вашей странице</h3>
<button onclick="switchScreen('continue')" class="text-xs wine-text hover:underline font-medium">Продолжить чтение →</button>
</div>
<div class="surface-card p-6 flex flex-col md:flex-row md:items-center justify-between gap-6">
<div class="space-y-1.5 max-w-2xl">
<div class="text-[11px] uppercase tracking-[0.12em] wine-text font-semibold">ВАША ЗАКЛАДКА · СЕГОДНЯ</div>
<div class="font-serif-editorial text-2xl font-medium">После полуночи</div>
<p class="text-sm meta-text">
Вы остановились у моста: <span class="italic text-[var(--text-ink)]">«На другой стороне реки им нужно было расстаться».</span>
</p>
</div>
<div class="flex flex-col sm:flex-row sm:items-center gap-4 shrink-0">
<div class="text-right">
<div class="text-xs font-medium">Прочитано 42%</div>
<div class="text-[11px] meta-text">Осталось 2 мин</div>
<div class="w-36 h-1.5 bg-[var(--bg-subtle)] rounded-full overflow-hidden mt-1.5">
<div class="h-full bg-[var(--accent-wine)]" style="width: 42%"></div>
</div>
</div>
<button onclick="openStoryReader(0)" class="btn-outline-editorial px-4 py-2.5 text-xs font-medium">
Продолжить с 42% →
</button>
</div>
</div>
</div>
<!-- Editorial Selection Grid (Выбор редакции — 3 stories) -->
<div class="space-y-5">
<div class="flex items-center justify-between border-b hairline-border pb-3">
<h3 class="font-serif-editorial text-3xl font-normal">Выбор редакции</h3>
<button onclick="switchScreen('catalog')" class="text-xs wine-text hover:underline font-medium">Все истории (4) →</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- Card 1: Кофе после дождя -->
<article class="surface-card p-6 flex flex-col justify-between space-y-5">
<div class="space-y-3">
<div class="text-[11px] uppercase tracking-[0.1em] meta-text">СОВРЕМЕННАЯ РОМАНТИКА · 6 мин</div>
<h4 class="font-serif-editorial text-2xl font-medium cursor-pointer hover:opacity-80" onclick="openStoryReader(1)">
Кофе после дождя
</h4>
<p class="text-sm meta-text leading-relaxed">
В маленьком кафе Лида и Денис учатся говорить о будущем, не загадывая его друг за друга.
</p>
<blockquote class="font-serif-editorial italic text-base pt-2 border-t hairline-border">
«Кофе принесли в разных чашках. Лида решила, что это хороший знак: здесь не требовали совпадать.»
</blockquote>
</div>
<div class="pt-3 border-t hairline-border flex items-center justify-between">
<span class="wine-badge">🎬 Есть видео · 11:20</span>
<button onclick="openStoryReader(1)" class="text-xs font-medium wine-text hover:underline">Читать →</button>
</div>
</article>
<!-- Card 2: Вечер в незнакомом городе -->
<article class="surface-card p-6 flex flex-col justify-between space-y-5">
<div class="space-y-3">
<div class="text-[11px] uppercase tracking-[0.1em] meta-text">ПРОЗА О ВЫБОРЕ · 8 мин</div>
<h4 class="font-serif-editorial text-2xl font-medium cursor-pointer hover:opacity-80" onclick="openStoryReader(2)">
Вечер в незнакомом городе
</h4>
<p class="text-sm meta-text leading-relaxed">
Три старых друга встречаются на один вечер. У каждого — свой маршрут, но одна общая история.
</p>
<blockquote class="font-serif-editorial italic text-base pt-2 border-t hairline-border">
«Они встретились у гостиницы, которую никто из них не выбрал бы для себя. И потому всем было легко.»
</blockquote>
</div>
<div class="pt-3 border-t hairline-border flex items-center justify-between">
<span class="wine-badge">🎬 Есть видео · 14:10</span>
<button onclick="openStoryReader(2)" class="text-xs font-medium wine-text hover:underline">Читать →</button>
</div>
</article>
<!-- Card 3: Письмо, которое всё изменило -->
<article class="surface-card p-6 flex flex-col justify-between space-y-5">
<div class="space-y-3">
<div class="text-[11px] uppercase tracking-[0.1em] meta-text">ЭПИСТОЛЯРНАЯ ПРОЗА · 4 мин</div>
<h4 class="font-serif-editorial text-2xl font-medium cursor-pointer hover:opacity-80" onclick="openStoryReader(3)">
Письмо, которое всё изменило
</h4>
<p class="text-sm meta-text leading-relaxed">
Соня возвращает непрочитанное письмо. Андрей предлагает начать не с объяснений, а с прогулки.
</p>
<blockquote class="font-serif-editorial italic text-base pt-2 border-t hairline-border">
«Конверт пролежал в ящике стола почти год. Теперь Соня держала его так, словно это был билет в город, где она ещё не бывала.»
</blockquote>
</div>
<div class="pt-3 border-t hairline-border flex items-center justify-between">
<span class="text-xs meta-text px-2 py-0.5 rounded border hairline-border">Пока только текст</span>
<button onclick="openStoryReader(3)" class="text-xs font-medium wine-text hover:underline">Читать →</button>
</div>
</article>
</div>
</div>
</section>
<!-- ===================================================================== -->
<!-- SCREEN 2: КАТАЛОГ ИСТОРИЙ (Figma 12:312704 + Node 12:312729 Filter) -->
<!-- ===================================================================== -->
<section id="screen-catalog" class="hidden space-y-10">
<div class="border-b hairline-border pb-8 space-y-3">
<div class="text-xs uppercase tracking-[0.14em] meta-text font-medium">
БИБЛИОТЕКА / ЗАКОНЧЕННАЯ ПРОЗА / 18+
</div>
<h1 class="font-serif-editorial text-4xl sm:text-5xl lg:text-[56px] leading-[1.04] font-normal">
Истории, в которых<br />хочется остаться.
</h1>
<p class="text-base meta-text max-w-2xl leading-relaxed">
Романтика и эротическая литература — о внимании, выборе и близости. Литературные истории для взрослых, без грубых сцен. Полный текст каждой истории открыт.
</p>
</div>
<!-- Filter Bar (Exact Node 12:312729 from the user's Figma URL!) -->
<div class="flex flex-wrap items-center justify-between gap-4 pb-2">
<div class="flex flex-wrap items-center gap-2.5">
<select id="filterGenre" onchange="filterCatalog()" class="surface-card px-3.5 py-2 text-xs font-medium cursor-pointer outline-none">
<option value="all">Жанр: все ⌄</option>
<option value="Романтическая проза">Жанр: романтическая проза</option>
<option value="Современная романтика">Жанр: современная романтика</option>
<option value="Проза о выборе">Жанр: проза о выборе</option>
<option value="Эпистолярная проза">Жанр: эпистолярная проза</option>
</select>
<select id="filterMood" onchange="filterCatalog()" class="surface-card px-3.5 py-2 text-xs font-medium cursor-pointer outline-none">
<option value="all">Настроение: любое ⌄</option>
<option value="night">Ночной город и близость</option>
<option value="warm">Тёплый разговор</option>
</select>
<select id="filterTime" onchange="filterCatalog()" class="surface-card px-3.5 py-2 text-xs font-medium cursor-pointer outline-none">
<option value="all">Время: любое ⌄</option>
<option value="short">До 5 минут</option>
<option value="long">6–10 минут</option>
</select>
<select id="filterVideo" onchange="filterCatalog()" class="surface-card px-3.5 py-2 text-xs font-medium cursor-pointer outline-none">
<option value="all">Видео: все ⌄</option>
<option value="yes">Есть видео · по подписке</option>
<option value="text">Пока только текст</option>
</select>
</div>
<div id="catalogCountLabel" class="text-xs meta-text">4 истории · Редакционный порядок</div>
</div>
<div id="catalogGrid" class="grid grid-cols-1 md:grid-cols-2 gap-6"></div>
<div class="subtle-box p-5 text-xs meta-text flex flex-wrap items-center justify-between gap-2">
<span>Не нужно подписываться, чтобы дочитать. Видео — отдельное продолжение знакомства с историей.</span>
<button onclick="switchScreen('videos')" class="wine-text font-medium hover:underline">Перейти к видеоадаптациям →</button>
</div>
</section>
<!-- ===================================================================== -->
<!-- SCREEN 3: ЧТЕНИЕ ПОЛНОЙ ИСТОРИИ + ВИДЕО В КОНЦЕ (12:313167 & 12:313889) -->
<!-- ===================================================================== -->
<section id="screen-reader" class="hidden space-y-10">
<!-- Reader Top Header & Controls -->
<div class="border-b hairline-border pb-8 max-w-[680px] space-y-4">
<div id="readerMetaCategory" class="text-xs uppercase tracking-[0.14em] wine-text font-semibold">
РОМАНТИЧЕСКАЯ ПРОЗА / 3 мин / 18+
</div>
<h1 id="readerTitle" class="font-serif-editorial text-4xl sm:text-5xl lg:text-[56px] leading-[1.04] font-normal">
После полуночи
</h1>
<p id="readerLead" class="text-base sm:text-lg meta-text leading-relaxed">
Опоздав на последний трамвай, двое решают не торопить утро. Рассказ о смелости остаться рядом.
</p>
<div id="readerCharacters" class="text-xs meta-text pt-1">
Редакция «между.» · Вымышленные взрослые: Вера, 31 · Матвей, 34
</div>
<!-- Reading Comfort Toolbar (А− / А+ / Закладка / Прочитано 42%) -->
<div class="pt-4 flex flex-wrap items-center justify-between gap-4 border-t hairline-border">
<div class="flex items-center gap-2">
<button onclick="changeFontSize(-2)" class="btn-outline-editorial px-3 py-1.5 text-xs font-medium">А−</button>
<span id="fontSizeIndicator" class="text-xs meta-text px-1">20 px</span>
<button onclick="changeFontSize(2)" class="btn-outline-editorial px-3 py-1.5 text-xs font-medium">А+</button>
<button onclick="toggleBookmarkToast()" id="bookmarkBtn" class="btn-outline-editorial px-3.5 py-1.5 text-xs font-medium ml-2">
🔖 Закладка
</button>
</div>
<div class="text-xs meta-text">
<strong class="text-[var(--text-ink)]">Прочитано 42%</strong> · Осталось 2 мин
</div>
</div>
<div class="subtle-box px-4 py-3 text-xs meta-text flex flex-wrap items-center justify-between gap-2">
<span>Сохранённая позиция — у моста, 42%.</span>
<a href="#endOfStoryVideoBlock" class="wine-text font-medium hover:underline">Видео по этой истории ↓ · после окончания текста</a>
</div>
</div>
<!-- 680px Literary Reading Column (Cormorant Garamond 20/32px per Figma spec) -->
<article class="max-w-[680px] reading-prose">
<h3 id="readerChapterHeading" class="font-serif-editorial text-2xl font-medium mb-6">I. После полуночи</h3>
<div id="readerBodyParagraphs"></div>
<div class="pt-6 pb-8 border-b hairline-border flex items-center justify-between text-xs uppercase tracking-[0.16em] meta-text">
<span>КОНЕЦ</span>
<span>Весь рассказ доступен без подписки · Позиция 42%</span>
</div>
</article>
<!-- =================================================================== -->
<!-- KEY PRODUCT FEATURE: VIDEO BLOCK AT THE END OF THE STORY -->
<!-- Supports both Locked (12:313167) and Unlocked (12:313889 / 12:314274) -->
<!-- =================================================================== -->
<div id="endOfStoryVideoBlock" class="max-w-[680px] pt-2 space-y-6">
<div class="flex flex-wrap items-center justify-between gap-2">
<div>
<div class="text-xs uppercase tracking-[0.14em] wine-text font-semibold">ПРОДОЛЖЕНИЕ НА ЭКРАНЕ · 18+</div>
<h3 class="font-serif-editorial text-3xl font-normal mt-0.5">Видео по этой истории</h3>
</div>
<div class="flex items-center gap-1.5 text-xs">
<button onclick="setVideoAccess(false)" id="readerLockTab" class="px-2.5 py-1 rounded border hairline-border text-xs">
Состояние: Закрыто
</button>
<button onclick="setVideoAccess(true)" id="readerUnlockTab" class="px-2.5 py-1 rounded border hairline-border text-xs">
Состояние: Открыто (Плеер)
</button>
</div>
</div>
<!-- STATE A: VIDEO LOCKED (Figma 12:313167 · Полная история · видео закрыто) -->
<div id="videoLockedCard" class="surface-card overflow-hidden">
<div class="cinema-poster-locked h-64 sm:h-72 flex flex-col items-center justify-center p-6 text-center relative">
<div class="relative z-10 max-w-md space-y-3 text-[#FFFDFA]">
<span class="inline-block px-3 py-1 rounded bg-black/45 border border-white/20 text-[11px] uppercase tracking-widest">
🔒 Доступно по подписке · <span id="lockedDuration">08:40</span>
</span>
<div id="lockedStoryTitle" class="font-serif-editorial text-3xl sm:text-4xl">После полуночи</div>
<p class="text-xs text-[#E9E1D6] leading-relaxed">
Записанная кинематографичная экранизация финала истории. Тёплый свет ночной пекарни, мост через реку и продолжение вечера.
</p>
</div>
</div>
<div class="p-6 sm:p-7 space-y-4 bg-[var(--bg-surface)]">
<div class="flex flex-wrap items-center justify-between gap-4">
<div>
<div class="text-sm font-medium">Записанная экранизация · <span id="lockedDurationSub">08:40</span></div>
<div class="text-xs meta-text mt-0.5">
Полный текст бесплатный. Подписка открывает только видеоверсии. 690 ₽ / месяц · продлевается автоматически.
</div>
</div>
<div class="flex flex-wrap items-center gap-3">
<button onclick="setVideoAccess(true)" class="btn-wine px-5 py-2.5 text-xs sm:text-sm">
Оформить подписку (690 ₽ / мес)
</button>
<button onclick="switchScreen('login')" class="btn-outline-editorial px-4 py-2.5 text-xs font-medium">
Уже есть подписка? Войти
</button>
</div>
</div>
</div>
</div>
<!-- STATE B: VIDEO UNLOCKED + CINEMA PLAYER (Figma 12:313889 & 12:314274) -->
<div id="videoUnlockedCard" class="hidden rounded-lg overflow-hidden border hairline-border bg-[#211A18] text-[#FFFDFA] shadow-xl">
<div class="cinema-player-unlocked p-6 sm:p-8 space-y-6">
<div class="flex flex-wrap items-center justify-between gap-2 text-xs text-[#D6B39B]">
<span class="uppercase tracking-[0.14em] font-medium">ЗАПИСАННАЯ АДАПТАЦИЯ · НЕ AI АВАТАР</span>
<span class="px-2.5 py-0.5 rounded bg-emerald-500/20 text-emerald-300 border border-emerald-400/30 text-[11px]">
✓ Подписка активна
</span>
</div>
<!-- Simulated Atmospheric Cinema Screen -->
<div class="relative rounded-md overflow-hidden border border-white/15 bg-black/50 aspect-video flex flex-col justify-between p-6">
<div class="flex items-center justify-between text-xs text-white/75">
<span id="playerStoryTitle" class="font-serif-editorial text-2xl text-white">После полуночи · Экранизация</span>
<span id="playerDurationBadge" class="font-mono text-xs">02:16 / 08:40</span>
</div>
<!-- Center Play/Pause Button & Scene Subtitle -->
<div class="my-auto text-center space-y-3">
<button onclick="toggleVideoPlayback()" id="playPauseCircle" class="w-16 h-16 rounded-full bg-[#793C49]/90 hover:bg-[#793C49] text-white flex items-center justify-center mx-auto text-xl shadow-lg transition transform hover:scale-105">
▶
</button>
<p id="videoSubtitleLine" class="font-serif-editorial italic text-lg sm:text-xl text-[#F5F0E8] max-w-md mx-auto">
«Под светом настольной лампы нашлось место и двум чашкам, и половине тёплого хлеба...»
</p>
<div id="videoStateNote" class="text-[11px] text-white/60">
На паузе · Нажмите ▶ для запуска демонстрации сцены
</div>
</div>
<!-- Player Scrubber & Controls -->
<div class="space-y-2.5">
<div class="w-full h-1.5 bg-white/20 rounded-full overflow-hidden cursor-pointer" onclick="scrubVideo(event)">
<div id="videoProgressBar" class="h-full bg-[#D6B39B] transition-all duration-300" style="width: 28%"></div>
</div>
<div class="flex items-center justify-between text-[11px] text-white/80">
<div class="flex items-center gap-4">
<button onclick="toggleVideoPlayback()" id="playPauseTextBtn" class="hover:text-white font-medium">▶ Воспроизвести</button>
<span>🔊 Звук: вкл</span>
<span>CC Субтитры: рус</span>
</div>
<div class="flex items-center gap-3">
<span>1080p HD</span>
<span>⛶ Полный экран</span>
</div>
</div>
</div>
</div>
<!-- Next Story Recommendation (Figma 12:314274: После просмотра) -->
<div class="pt-4 border-t border-white/10 flex flex-wrap items-center justify-between gap-4 text-xs">
<div>
<div class="text-[#D6B39B] uppercase tracking-wider text-[10px]">После просмотра</div>
<div class="text-white/90 mt-0.5">
Следующая история: <strong>«Кофе после дождя»</strong> · современная романтика · 6 мин. Видеоверсия — 11:20.
</div>
</div>
<button onclick="openStoryReader(1)" class="px-4 py-2 rounded bg-white/10 hover:bg-white/20 text-white font-medium transition">
Читать «Кофе после дождя» →
</button>
</div>
</div>
</div>
<div class="pt-2">
<button onclick="switchScreen('catalog')" class="text-xs meta-text hover:text-[var(--text-ink)]">
← К каталогу историй
</button>
</div>
</div>
</section>
<!-- ===================================================================== -->
<!-- SCREEN 4: ВИДЕО ПО ИСТОРИЯМ (Figma Frame 12:314623 · Десктоп) -->
<!-- ===================================================================== -->
<section id="screen-videos" class="hidden space-y-10">
<div class="border-b hairline-border pb-8 space-y-3">
<div class="text-xs uppercase tracking-[0.14em] meta-text font-medium">
ИЗ БИБЛИОТЕКИ — НА ЭКРАН
</div>
<h1 class="font-serif-editorial text-4xl sm:text-5xl lg:text-[56px] leading-[1.04] font-normal">
Те же чувства.<br />Другой язык.
</h1>
<p class="text-base meta-text max-w-2xl leading-relaxed">
Записанные адаптации прочитанных историй. Текст открыт каждому; для видео нужна подписка.
</p>
</div>
<div class="subtle-box p-5 flex flex-wrap items-center justify-between gap-4">
<div class="space-y-1">
<div class="text-sm font-medium">Видеоверсии доступны по подписке (690 ₽ / месяц)</div>
<div class="text-xs meta-text">
В состоянии без подписки постеры размыты одинаково. Вы можете мгновенно протестировать оба состояния ниже.
</div>
</div>
<button onclick="toggleSubscriptionState()" class="btn-wine px-4 py-2 text-xs">
Переключить доступ к видео
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- Video 1 -->
<div class="surface-card overflow-hidden flex flex-col justify-between">
<div>
<div class="cinema-poster-locked h-44 flex items-center justify-center p-4 text-center">
<span class="relative z-10 px-3 py-1 rounded bg-black/55 text-[#FFFDFA] text-xs font-medium">
🎬 После полуночи · 08:40
</span>
</div>
<div class="p-6 space-y-2.5">
<div class="text-[11px] uppercase tracking-wider wine-text font-semibold">Доступно по подписке · 08:40</div>
<h3 class="font-serif-editorial text-2xl font-medium">После полуночи</h3>
<p class="text-xs meta-text leading-relaxed">
Опоздав на последний трамвай, двое решают не торопить утро. Рассказ о смелости остаться рядом.
</p>
</div>
</div>
<div class="p-6 pt-0 flex items-center gap-2">
<button onclick="openStoryReaderAndScrollVideo(0)" class="btn-wine flex-1 py-2 text-xs">Смотреть / К видео</button>
<button onclick="openStoryReader(0)" class="btn-outline-editorial px-3 py-2 text-xs">Текст</button>
</div>
</div>
<!-- Video 2 -->
<div class="surface-card overflow-hidden flex flex-col justify-between">
<div>
<div class="cinema-poster-locked h-44 flex items-center justify-center p-4 text-center">
<span class="relative z-10 px-3 py-1 rounded bg-black/55 text-[#FFFDFA] text-xs font-medium">
🎬 Кофе после дождя · 11:20
</span>
</div>
<div class="p-6 space-y-2.5">
<div class="text-[11px] uppercase tracking-wider wine-text font-semibold">Доступно по подписке · 11:20</div>
<h3 class="font-serif-editorial text-2xl font-medium">Кофе после дождя</h3>
<p class="text-xs meta-text leading-relaxed">
В маленьком кафе Лида и Денис учатся говорить о будущем, не загадывая его друг за друга.
</p>
</div>
</div>
<div class="p-6 pt-0 flex items-center gap-2">
<button onclick="openStoryReaderAndScrollVideo(1)" class="btn-wine flex-1 py-2 text-xs">Смотреть / К видео</button>
<button onclick="openStoryReader(1)" class="btn-outline-editorial px-3 py-2 text-xs">Текст</button>
</div>
</div>
<!-- Video 3 -->
<div class="surface-card overflow-hidden flex flex-col justify-between">
<div>
<div class="cinema-poster-locked h-44 flex items-center justify-center p-4 text-center">
<span class="relative z-10 px-3 py-1 rounded bg-black/55 text-[#FFFDFA] text-xs font-medium">
🎬 Вечер в незнакомом городе · 14:10
</span>
</div>
<div class="p-6 space-y-2.5">
<div class="text-[11px] uppercase tracking-wider wine-text font-semibold">Доступно по подписке · 14:10</div>
<h3 class="font-serif-editorial text-2xl font-medium">Вечер в незнакомом городе</h3>
<p class="text-xs meta-text leading-relaxed">
Три старых друга встречаются на один вечер. У каждого — свой маршрут, но одна общая история.
</p>
</div>
</div>
<div class="p-6 pt-0 flex items-center gap-2">
<button onclick="openStoryReaderAndScrollVideo(2)" class="btn-wine flex-1 py-2 text-xs">Смотреть / К видео</button>
<button onclick="openStoryReader(2)" class="btn-outline-editorial px-3 py-2 text-xs">Текст</button>
</div>
</div>
</div>
<div class="text-xs meta-text">
У истории «Письмо, которое всё изменило» пока нет видео. Она остаётся в каталоге текстов.
</div>
</section>
<!-- ===================================================================== -->
<!-- SCREEN 5: ПРОДОЛЖИТЬ ЧТЕНИЕ (Figma Frame 12:315008) -->
<!-- ===================================================================== -->
<section id="screen-continue" class="hidden space-y-8">
<div class="border-b hairline-border pb-8 space-y-3">
<div class="text-xs uppercase tracking-[0.14em] meta-text font-medium">ВАША ПОЗИЦИЯ В ТЕКСТЕ</div>
<h1 class="font-serif-editorial text-4xl sm:text-5xl leading-[1.04] font-normal">
Мы оставили<br />страницу открытой.
</h1>
<p class="text-sm meta-text max-w-xl">
Только начатые истории. Закладки избранного и сохранённые AI-материалы находятся в своих разделах.
</p>
</div>
<div class="space-y-4">
<div class="surface-card p-6 flex flex-col sm:flex-row sm:items-center justify-between gap-6">
<div class="space-y-1.5">
<div class="text-xs meta-text">Романтическая проза · 3 мин &nbsp;·&nbsp; Сегодня, 21:14 · абзац у моста</div>
<h3 class="font-serif-editorial text-2xl font-medium">После полуночи</h3>
<p class="font-serif-editorial italic text-lg meta-text">«На другой стороне реки им нужно было расстаться.»</p>
</div>
<div class="flex items-center gap-4 shrink-0">
<div class="text-right">
<div class="text-xs font-medium">Прочитано 42%</div>
<div class="text-[11px] meta-text">Осталось 2 мин</div>
</div>
<button onclick="openStoryReader(0)" class="btn-wine px-4 py-2.5 text-xs">Продолжить с 42%</button>
</div>
</div>
<div class="surface-card p-6 flex flex-col sm:flex-row sm:items-center justify-between gap-6">
<div class="space-y-1.5">
<div class="text-xs meta-text">Современная романтика · 6 мин &nbsp;·&nbsp; Вчера, 19:06 · начало рассказа</div>
<h3 class="font-serif-editorial text-2xl font-medium">Кофе после дождя</h3>
<p class="font-serif-editorial italic text-lg meta-text">«Кофе принесли в разных чашках.»</p>
</div>
<div class="flex items-center gap-4 shrink-0">
<div class="text-right">
<div class="text-xs font-medium">Прочитано 18%</div>
<div class="text-[11px] meta-text">Осталось 5 мин</div>
</div>
<button onclick="openStoryReader(1)" class="btn-outline-editorial px-4 py-2.5 text-xs font-medium">Продолжить с 18%</button>
</div>
</div>
</div>
<div class="text-xs meta-text">Прогресс относится к чтению текста, а не к просмотру видео.</div>
</section>
<!-- ===================================================================== -->
<!-- SCREEN 6: ИЗБРАННОЕ (Figma Frame 12:315383) -->
<!-- ===================================================================== -->
<section id="screen-favorites" class="hidden space-y-8">
<div class="border-b hairline-border pb-8 space-y-3">
<div class="text-xs uppercase tracking-[0.14em] meta-text font-medium">СОХРАНЁННОЕ ДЛЯ ВДОХНОВЕНИЯ</div>
<h1 class="font-serif-editorial text-4xl sm:text-5xl leading-[1.04] font-normal">
К этому<br />хочется вернуться.
</h1>
<p class="text-sm meta-text max-w-xl">
Истории, видео и AI герои — три отдельные коллекции. Здесь нет прогресса чтения или личных версий AI.
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="surface-card p-6 space-y-3">
<div class="text-[11px] uppercase tracking-wider meta-text">РОМАНТИЧЕСКАЯ ПРОЗА · 3 мин</div>
<h3 class="font-serif-editorial text-2xl font-medium">После полуночи</h3>
<p class="text-xs meta-text">Опоздав на последний трамвай, двое решают не торопить утро.</p>
<div class="pt-3 border-t hairline-border flex items-center justify-between">
<span class="wine-badge">Есть видео · по подписке</span>
<button onclick="openStoryReader(0)" class="text-xs wine-text font-medium">Читать историю →</button>
</div>
</div>
<div class="surface-card p-6 space-y-3">
<div class="text-[11px] uppercase tracking-wider meta-text">ЭПИСТОЛЯРНАЯ ПРОЗА · 4 мин</div>
<h3 class="font-serif-editorial text-2xl font-medium">Письмо, которое всё изменило</h3>
<p class="text-xs meta-text">Соня возвращает непрочитанное письмо. Андрей предлагает начать с прогулки.</p>
<div class="pt-3 border-t hairline-border flex items-center justify-between">
<span class="text-xs meta-text">Пока только текст</span>
<button onclick="openStoryReader(3)" class="text-xs wine-text font-medium">Читать историю →</button>
</div>
</div>
<div class="subtle-box p-6 space-y-2.5 text-xs">
<div class="font-semibold text-sm">В коллекции</div>
<p class="meta-text">Истории · 2</p>
<p class="meta-text">Видео · 1 («После полуночи», 08:40)</p>
<p class="meta-text">AI герои · 1 (Инга, 32)</p>
<p class="meta-text pt-2 border-t hairline-border">
Личные конфигурации — в «Мои AI», материалы из своих разговоров — в «Личное».
</p>
</div>
</div>
</section>
<!-- ===================================================================== -->
<!-- SCREEN 7: AI ГЕРОИ (Figma Frame 12:317609 · ДРУГОЙ ФОРМАТ · AI) -->
<!-- ===================================================================== -->
<section id="screen-ai_heroes" class="hidden space-y-10">
<div class="border-b hairline-border pb-8 space-y-3">
<div class="text-xs uppercase tracking-[0.14em] wine-text font-semibold">ДРУГОЙ ФОРМАТ · AI / ВЗРОСЛЫЕ ВЫМЫШЛЕННЫЕ ПЕРСОНАЖИ 18+</div>
<h1 class="font-serif-editorial text-4xl sm:text-5xl leading-[1.04] font-normal">
Разговор, у которого<br />есть характер.
</h1>
<p class="text-sm meta-text max-w-2xl">
Камерные диалоги по мотивам атмосферы журнала. Выбирайте готовый образ или настройте темп и дистанцию под себя.
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="surface-card p-6 flex flex-col justify-between space-y-5">
<div class="space-y-3">
<div class="flex items-center justify-between">
<span class="wine-badge">AI · 18+</span>
<span class="text-xs meta-text">Спокойный · Внимательный</span>
</div>
<h3 class="font-serif-editorial text-3xl font-medium">Лев, 36</h3>
<p class="text-xs font-medium wine-text">Архитектор · Вечерний город</p>
<p class="text-sm meta-text leading-relaxed">
Внимательный к деталям, с мягкой иронией. Любит старые мосты, поздние трамваи и разговоры без спешки.
</p>
</div>
<div class="pt-3 border-t hairline-border flex items-center gap-2">
<button onclick="switchScreen('ai_chat')" class="btn-wine flex-1 py-2.5 text-xs">Открыть диалог →</button>
<button onclick="switchScreen('my_ai')" class="btn-outline-editorial px-3 py-2.5 text-xs">Моя версия</button>
</div>
</div>
<div class="surface-card p-6 flex flex-col justify-between space-y-5">
<div class="space-y-3">
<div class="flex items-center justify-between">
<span class="wine-badge">AI · 18+</span>
<span class="text-xs meta-text">Тёплый · Литературный</span>
</div>
<h3 class="font-serif-editorial text-3xl font-medium">Инга, 32</h3>
<p class="text-xs font-medium wine-text">Переводчица · Маленькие кафе</p>
<p class="text-sm meta-text leading-relaxed">
Любит прогулки после дождя и разговоры о редких словах. Умеет слушать паузы между фразами.
</p>
</div>
<div class="pt-3 border-t hairline-border flex items-center gap-2">
<button onclick="switchScreen('ai_chat')" class="btn-wine flex-1 py-2.5 text-xs">Открыть диалог →</button>
<button onclick="switchScreen('my_ai')" class="btn-outline-editorial px-3 py-2.5 text-xs">Моя версия</button>
</div>
</div>
<div class="surface-card p-6 flex flex-col justify-between space-y-5">
<div class="space-y-3">
<div class="flex items-center justify-between">
<span class="wine-badge">AI · Конструктор</span>
<span class="text-xs meta-text">5 шагов</span>
</div>
<h3 class="font-serif-editorial text-3xl font-medium">Свой образ</h3>
<p class="text-xs font-medium wine-text">Персональная настройка</p>
<p class="text-sm meta-text leading-relaxed">
Задайте образ, внешность, характер, голос и границы общения в спокойном 5-шаговом конструкторе.
</p>
</div>
<div class="pt-3 border-t hairline-border">
<button onclick="switchScreen('create_ai')" class="btn-outline-editorial w-full py-2.5 text-xs font-medium">
Создать героя →
</button>
</div>
</div>
</div>
</section>
<!-- ===================================================================== -->
<!-- SCREEN 8: ДИАЛОГИ + AI ВИДЕОДИАЛОГ (Figma Frame 12:317552) -->
<!-- ===================================================================== -->
<section id="screen-ai_chat" class="hidden space-y-8">
<div class="border-b hairline-border pb-6 flex flex-wrap items-center justify-between gap-4">
<div>
<div class="text-xs uppercase tracking-[0.14em] wine-text font-semibold">ДИАЛОГИ / ЛЕВ, 36 · AI · ЛИЧНАЯ ВЕРСИЯ</div>
<h1 class="font-serif-editorial text-3xl sm:text-4xl font-normal mt-1">Лев · Кофе после дождя</h1>
</div>
<div class="flex items-center gap-2">
<button onclick="toggleAiVideoMode(false)" id="chatModeTextBtn" class="btn-wine px-3.5 py-1.5 text-xs">Текст и голос</button>
<button onclick="toggleAiVideoMode(true)" id="chatModeVideoBtn" class="btn-outline-editorial px-3.5 py-1.5 text-xs">AI видеодиалог (Аватар)</button>
</div>
</div>
<!-- AI Video Avatar Call Box (Hidden by default, toggled via button) -->
<div id="aiVideoCallBox" class="hidden rounded-lg p-6 bg-[#211A18] text-[#FFFDFA] space-y-4">
<div class="flex items-center justify-between text-xs text-[#D6B39B]">
<span>AI ВИДЕОДИАЛОГ · ВЫМЫШЛЕННЫЙ AI АВАТАР · 18+</span>
<span>Камера пользователя: Выкл. (необязательна)</span>
</div>
<div class="aspect-video max-h-[340px] w-full rounded bg-black/50 border border-white/15 flex flex-col items-center justify-center p-6 text-center space-y-3">
<div class="w-20 h-20 rounded-full bg-[#793C49]/40 border border-[#D6B39B] flex items-center justify-center font-serif-editorial text-3xl">
Л
</div>
<div class="font-serif-editorial text-2xl">Лев, 36 · AI аватар готов к разговору</div>
<p class="text-xs text-white/70 max-w-md">
«Кажется, дождь решил задержать нас здесь ещё на полчаса. Я не против. А ты?»
</p>
</div>
</div>
<!-- Chat Messages Thread -->
<div class="surface-card p-6 space-y-5 max-w-[760px]">
<div class="text-center text-xs meta-text pb-2 border-b hairline-border">
Сегодня · Сцена: «За окном дождь. В кафе почти никого.»
</div>
<div id="chatMessagesList" class="space-y-4">
<div class="subtle-box p-4 max-w-lg space-y-1">
<div class="text-[11px] meta-text">19:41 · Лев · AI</div>
<p class="text-sm">Кажется, дождь решил задержать нас здесь. Я не против. А ты?</p>
</div>
<div class="p-4 rounded-md bg-[var(--accent-wine-soft)] ml-auto max-w-lg space-y-1">
<div class="text-[11px] wine-text">19:41 · Вы · Доставлено ✓✓</div>
<p class="text-sm">Если кофе хороший — я тоже. Часто сюда заходишь?</p>
</div>
<div class="subtle-box p-4 max-w-lg space-y-1">
<div class="text-[11px] meta-text">19:42 · Лев · AI</div>
<p class="text-sm">Когда хочется замедлиться. Здесь никто не торопит, а бариста запоминает любимый кофе. Что заказать тебе?</p>
</div>
</div>
<form onsubmit="sendAiChatMessage(event)" class="pt-4 border-t hairline-border flex gap-2">
<input id="aiChatInput" type="text" placeholder="Написать Льву…" class="flex-1 px-4 py-2.5 rounded border hairline-border bg-[var(--bg-paper)] text-sm outline-none" />
<button type="submit" class="btn-wine px-5 py-2.5 text-xs">Отправить</button>
</form>
<div class="text-[11px] meta-text">
Лев — AI. Ответы вымышлены. Вы всегда можете сохранить понравившуюся фразу в «Личное».
</div>
</div>
</section>
<!-- ===================================================================== -->
<!-- SCREEN 9: МОИ AI & СОЗДАТЬ ГЕРОЯ & ЛИЧНОЕ (12:317510 / 460 / 425) -->
<!-- ===================================================================== -->
<section id="screen-my_ai" class="hidden space-y-8">
<div class="border-b hairline-border pb-6">
<div class="text-xs uppercase tracking-[0.14em] meta-text">ЛИЧНЫЕ КОНФИГУРАЦИИ · AI</div>
<h1 class="font-serif-editorial text-4xl font-normal mt-1">Мои AI</h1>
<p class="text-sm meta-text mt-1">Сохранённые версии героев с вашим темпом беседы и границами.</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="surface-card p-6 space-y-3">
<div class="wine-badge inline-block">Личная версия</div>
<h3 class="font-serif-editorial text-2xl font-medium">Лев · моя версия</h3>
<p class="text-xs meta-text">Тон: спокойный, внимательный · Сценарий: вечерний город после дождя.</p>
<button onclick="switchScreen('ai_chat')" class="btn-wine px-4 py-2 text-xs">Продолжить диалог →</button>
</div>
<div class="surface-card p-6 space-y-3">
<div class="wine-badge inline-block">Конструктор</div>
<h3 class="font-serif-editorial text-2xl font-medium">Создать нового героя</h3>
<p class="text-xs meta-text">Настройте имя, возраст (18+), тембр голоса и характер с нуля.</p>
<button onclick="switchScreen('create_ai')" class="btn-outline-editorial px-4 py-2 text-xs">Открыть конструктор →</button>
</div>
</div>
</section>
<section id="screen-create_ai" class="hidden space-y-8">
<div class="border-b hairline-border pb-6">
<div class="text-xs uppercase tracking-[0.14em] wine-text font-semibold">КОНСТРУКТОР ОБРАЗА · 5 ШАГОВ</div>
<h1 class="font-serif-editorial text-4xl font-normal mt-1">Создать героя</h1>
<p class="text-sm meta-text mt-1">Все персонажи — вымышленные взрослые (18+).</p>
</div>
<div class="flex flex-wrap gap-2 text-xs">
<span class="px-3 py-1.5 rounded bg-[var(--accent-wine)] text-white font-medium">1 · Образ</span>
<span class="px-3 py-1.5 rounded surface-card">2 · Внешность</span>
<span class="px-3 py-1.5 rounded surface-card">3 · Характер</span>
<span class="px-3 py-1.5 rounded surface-card">4 · Голос и общение</span>
<span class="px-3 py-1.5 rounded surface-card">5 · Проверка</span>
</div>
<div class="surface-card p-6 max-w-xl space-y-4">
<div>
<label class="block text-xs meta-text mb-1">Имя героя</label>
<input type="text" value="Алекс" class="w-full px-3.5 py-2 rounded border hairline-border bg-[var(--bg-paper)] text-sm" />
</div>
<div>
<label class="block text-xs meta-text mb-1">Возраст (только 18+)</label>
<input type="text" value="32 года · Взрослый вымышленный герой" class="w-full px-3.5 py-2 rounded border hairline-border bg-[var(--bg-paper)] text-sm" />
</div>
<div>
<label class="block text-xs meta-text mb-1">Атмосфера и характер</label>
<textarea rows="3" class="w-full px-3.5 py-2 rounded border hairline-border bg-[var(--bg-paper)] text-sm">Внимательный собеседник с мягким юмором. Любит ночные прогулки и кинематограф.</textarea>
</div>
<button onclick="switchScreen('ai_chat')" class="btn-wine px-5 py-2.5 text-xs">Сохранить и начать разговор →</button>
</div>
</section>
<section id="screen-personal" class="hidden space-y-8">
<div class="border-b hairline-border pb-6">
<div class="text-xs uppercase tracking-[0.14em] meta-text">ЛИЧНЫЙ АРХИВ</div>
<h1 class="font-serif-editorial text-4xl font-normal mt-1">Маленькие вещи, которые остаются.</h1>
<p class="text-sm meta-text mt-1">Сохранённые фрагменты из ваших диалогов и любимые строки из рассказов.</p>
</div>
<div class="surface-card p-6 space-y-3 max-w-2xl">
<div class="text-xs meta-text">Из рассказа «После полуночи»</div>
<blockquote class="font-serif-editorial italic text-2xl">
«С этими тёплыми свёртками они стали похожи на людей, возвращавшихся из одного дома.»
</blockquote>
</div>
</section>
<!-- ===================================================================== -->
<!-- SCREEN 10: ПОДПИСКА · УСЛОВИЯ (Figma Frame 12:313554 · 690 ₽ / мес) -->
<!-- ===================================================================== -->
<section id="screen-subscription" class="hidden space-y-8">
<div class="border-b hairline-border pb-8 space-y-3">
<div class="text-xs uppercase tracking-[0.14em] wine-text font-semibold">ВИДЕОВЕРСИИ / ОТДЕЛЬНО ОТ ЧТЕНИЯ</div>
<h1 class="font-serif-editorial text-4xl sm:text-5xl leading-[1.04] font-normal">
Ещё один способ<br />почувствовать историю.
</h1>
<p class="text-base meta-text max-w-2xl">
Читайте все истории бесплатно. Подписка открывает только записанные видеоадаптации — не AI-диалоги и не доступ к текстам.
</p>
</div>
<div class="surface-card p-8 max-w-xl space-y-6">
<div class="flex items-center justify-between">
<span class="text-xs uppercase tracking-wider wine-text font-semibold">ОДИН ПЛАН · БИБЛИОТЕКА ВИДЕО</span>
<span class="wine-badge">18+</span>
</div>
<div>
<div class="font-serif-editorial text-5xl font-semibold">690 ₽ / месяц</div>
<div class="text-xs meta-text mt-1">Продлевается автоматически · Отмена в любой момент в Настройках</div>
</div>
<ul class="space-y-2.5 text-sm">
<li>✓ &nbsp;Все доступные записанные видеоадаптации («После полуночи», «Кофе после дождя» и др.)</li>
<li>✓ &nbsp;Новые видеоверсии по мере выхода</li>
<li>✓ &nbsp;Полные тексты — всегда бесплатно и без подписки</li>
</ul>
<div class="pt-2 flex flex-wrap items-center gap-3">
<button onclick="setVideoAccess(true);openStoryReaderAndScrollVideo(0);" class="btn-wine px-6 py-3 text-sm">
Оформить подписку и открыть видео →
</button>
<button onclick="openStoryReader(0)" class="btn-outline-editorial px-4 py-3 text-xs">
← Вернуться к истории без оформления
</button>
</div>
</div>
</section>
<!-- ===================================================================== -->
<!-- SCREEN 11: ВХОД (12:315832) & НАСТРОЙКИ (12:316253) & СОСТОЯНИЯ -->
<!-- ===================================================================== -->
<section id="screen-login" class="hidden space-y-8">
<div class="border-b hairline-border pb-6">
<div class="text-xs uppercase tracking-[0.14em] meta-text">ВАШ АККАУНТ / 18+</div>
<h1 class="font-serif-editorial text-4xl sm:text-5xl font-normal mt-1">Вернуться к своей странице.</h1>
<p class="text-sm meta-text mt-1">Войдите, чтобы проверить подписку и сохранить вашу библиотеку.</p>
</div>
<div class="surface-card p-7 max-w-md space-y-4">
<div>
<label class="block text-xs meta-text mb-1">Электронная почта</label>
<input type="email" value="anna@example.ru" class="w-full px-3.5 py-2 rounded border hairline-border bg-[var(--bg-paper)] text-sm" />
</div>
<div>
<label class="block text-xs meta-text mb-1">Пароль</label>
<input type="password" value="••••••••••••" class="w-full px-3.5 py-2 rounded border hairline-border bg-[var(--bg-paper)] text-sm" />
</div>
<label class="flex items-start gap-2 text-xs meta-text">
<input type="checkbox" checked class="mt-1" />
<span>Мне исполнилось 18 лет. Я согласна с условиями использования и политикой конфиденциальности.</span>
</label>
<div class="pt-2 flex gap-2">
<button onclick="setVideoAccess(true);openStoryReaderAndScrollVideo(0)" class="btn-wine flex-1 py-2.5 text-xs">Войти и вернуться к истории</button>
</div>
</div>
</section>
<section id="screen-settings" class="hidden space-y-8">
<div class="border-b hairline-border pb-6">
<div class="text-xs uppercase tracking-[0.14em] meta-text">АККАУНТ И ВАШ КОМФОРТ</div>
<h1 class="font-serif-editorial text-4xl sm:text-5xl font-normal mt-1">Настроить свой ритм.</h1>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-3xl">
<div class="surface-card p-6 space-y-4">
<h3 class="font-serif-editorial text-2xl font-medium">Чтение</h3>
<p class="text-xs meta-text">
Шрифт: Cormorant Garamond. Размер текста на компьютере — 20 px, на телефоне — 18 px. Межстрочный интервал — 32 / 29 px.
</p>
<div class="flex items-center gap-3">
<button onclick="changeFontSize(-2)" class="btn-outline-editorial px-3 py-1.5 text-xs">А−</button>
<span class="text-xs font-medium">20 px</span>
<button onclick="changeFontSize(2)" class="btn-outline-editorial px-3 py-1.5 text-xs">А+</button>
</div>
</div>
<div class="surface-card p-6 space-y-4">
<h3 class="font-serif-editorial text-2xl font-medium">Приватность и доступность</h3>
<label class="flex items-center gap-2 text-xs"><input type="checkbox" checked /> Сохранять позицию чтения (42%)</label>
<label class="flex items-center gap-2 text-xs"><input type="checkbox" checked /> Субтитры для видеоверсий</label>
<label class="flex items-center gap-2 text-xs"><input type="checkbox" onchange="toggleThemeNoir()" /> Вечерняя тема NOIR (#10121A)</label>
</div>
</div>
</section>
<section id="screen-states" class="hidden space-y-8">
<div class="border-b hairline-border pb-6">
<div class="text-xs uppercase tracking-[0.14em] meta-text">ДОСКА СОСТОЯНИЙ И СПЕЦИФИКАЦИЯ FIGMA (12:317745 & 12:316744)</div>
<h1 class="font-serif-editorial text-4xl font-normal mt-1">Разные причины. Ясный следующий шаг.</h1>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 text-xs">
<div class="surface-card p-5 space-y-1.5">
<div class="wine-text font-semibold uppercase">01 / Палитра CHAPTER</div>
<p class="meta-text">Бумага <code>#F5F0E8</code> · Поверхность <code>#FFFDFA</code> · Текст <code>#24211D</code> · Мета <code>#686158</code> · Вино <code>#793C49</code></p>
</div>
<div class="surface-card p-5 space-y-1.5">
<div class="wine-text font-semibold uppercase">02 / Оформление · Успех</div>
<p class="meta-text">Подписка активна. Возврат к «После полуночи», в тот же блок видео. Позиция чтения 42% сохранена.</p>
</div>
<div class="surface-card p-5 space-y-1.5">
<div class="wine-text font-semibold uppercase">03 / Подписка истекла</div>
<p class="meta-text">Видео «После полуночи» закрыто. Рассказ остаётся бесплатным.</p>
</div>
</div>
</section>
</main>
</div>
<!-- Toast Notification -->
<div id="editorialToast" class="hidden fixed bottom-6 right-6 surface-card px-5 py-3 shadow-xl text-xs font-medium z-50">
🔖 Позиция чтения (42% · у моста) сохранена на вашей странице
</div>
<script>
const STORIES = [
{
id: 0,
genre: "Романтическая проза",
meta: "РОМАНТИЧЕСКАЯ ПРОЗА / 3 мин / 18+",
duration: "3 мин",
timeCat: "short",
mood: "night",
hasVideo: true,
videoDuration: "08:40",
title: "После полуночи",
characters: "Редакция «между.» · Вымышленные взрослые: Вера, 31 · Матвей, 34",
lead: "Опоздав на последний трамвай, двое решают не торопить утро. Рассказ о смелости остаться рядом.",
quote: "«Вера услышала, как за поворотом стих последний трамвай. Город словно перевернул страницу.»",
chapter: "I. После полуночи",
paragraphs: [
"Вера услышала, как за поворотом стих последний трамвай. Город словно перевернул страницу. На остановке остались мокрая афиша, жёлтый свет фонаря и человек, который тоже не успел. Он посмотрел на часы, потом на пустые рельсы и почему-то улыбнулся.",
"— Кажется, нас освободили от расписания, — сказал он. Вера узнала Матвея не сразу. В книжном он стоял за колонной и слушал, как она читает чужие стихи. Потом помог собрать стулья, но имени так и не спросил. Теперь их знакомство продолжилось без всякого повода.",
"Дождь закончился, оставив на мостовой маленькие озёра. Вера сказала, что живёт за рекой. Матвею было в другую сторону. Они сверились с картой и спрятали телефоны: до моста путь у них всё-таки был общий. Вера подтянула воротник пальто, и они пошли.",
"Сначала говорили о вечере. О поэте, который потерял очки, хотя держал их в руке. О женщине в первом ряду, записывавшей не стихи, а, вероятно, список покупок. Потом разговор стал тише. Матвей признался, что давно собирается сменить работу. Вера — что второй месяц не может распаковать последнюю коробку после переезда.",
"— Там что-нибудь важное? — спросил он. — Только вещи, которым пока нет места. Она удивилась собственному ответу. Обычно о переезде хотелось говорить как о решённой задаче. Матвей не предложил ни полок, ни полезного номера. Он просто кивнул, словно хорошо знал такие коробки.",
"У моста ещё работала пекарня. Они купили один большой хлеб, потому что маленькие уже закончились. Продавщица разрезала его пополам и завернула в два бумажных пакета. С этими тёплыми свёртками они стали похожи на людей, возвращавшихся из одного дома.",
"Вера заметила это сходство и рассмеялась. Матвей спросил почему. Она рассказала. Теперь засмеялся и он — не над ней, а рядом с ней. Эта разница вдруг показалась важнее всех слов, сказанных за вечер. Внизу под мостом медленно плыл отражённый свет окон.",
"На другой стороне реки им нужно было расстаться. Они остановились у перил. Вера могла назвать улицу, пожелать спокойной ночи и унести этот вечер как красивую случайность. Такие случайности ничего не требовали и потому долго казались ей безопасными.",
"— Я завтра буду разбирать коробку, — сказала она. — А после? В вопросе не было ни уверенности, ни обещания. Он оставлял ей место для любого ответа. Вера посмотрела на бумажный пакет, сквозь который ещё чувствовалось тепло, и поняла, что впервые за долгое время не хочет заранее придумывать конец.",
"— После можно выпить чаю. У меня пока только две чашки. — Значит, я не приведу весь книжный клуб. Они обменялись номерами. Матвей не стал сразу звонить для проверки, и это тоже ей понравилось. Вера сама написала адрес, добавив: «После семи».",
"Домой она шла медленно. У двери поставила пакет на подоконник и долго искала ключи, хотя они были в наружном кармане. В квартире пахло краской и холодным деревом. Последняя коробка стояла у стены. Вера открыла её, достала настольную лампу и поставила на кухне.",
"Под светом нашлось место и чашкам, и половине хлеба. Телефон коротко загорелся: «До завтра, Вера». Она ответила: «До завтра». За окном уже начинался новый день, но впервые ей не хотелось его торопить. Она выключила верхний свет. Лампу оставила гореть."
]
},
{
id: 1,
genre: "Современная романтика",
meta: "СОВРЕМЕННАЯ РОМАНТИКА / 6 мин / 18+",
duration: "6 мин",
timeCat: "long",
mood: "warm",
hasVideo: true,
videoDuration: "11:20",
title: "Кофе после дождя",
characters: "Редакция «между.» · Вымышленные взрослые: Лида, 29 · Денис, 33",
lead: "В маленьком кафе Лида и Денис учатся говорить о будущем, не загадывая его друг за друга.",
quote: "«Кофе принесли в разных чашках. Лида решила, что это хороший знак: здесь не требовали совпадать.»",
chapter: "I. Кофе после дождя",
paragraphs: [
"Кофе принесли в разных чашках — одну широкую, с тонким золотым ободком, другую высокую, из тяжёлого тёплого фаянса. Лида решила, что это хороший знак: здесь не требовали совпадать.",
"За витриной шумел октябрьский ливень. Денис снял промокший шарф и положил его на спинку соседнего стула. Они знали друг друга три недели, но до сегодняшнего дня всегда встречались на ходу — между выставками, звонками и чужими компаниями.",
"— Знаешь, чего я боюсь в таких вечерах? — спросила Лида, согревая ладони о чашку. — Что кто-нибудь обязательно начнёт спрашивать про планы на пять лет вперёд.",
"— Тогда давай договоримся, — улыбнулся Денис. — Наше будущее сегодня заканчивается ровно в полночь. А дальше посмотрим, захочется ли его продлить.",
"Это сняло неловкость быстрее любого комплимента. Когда через час официант зажёг на столиках маленькие свечи, разговор уже шёл о том, какие окна в городе кажутся самыми уютными и почему в дождь так легко признаваться в желаниях."
]
},
{
id: 2,
genre: "Проза о выборе",
meta: "ПРОЗА О ВЫБОРЕ / 8 мин / 18+",
duration: "8 мин",
timeCat: "long",
mood: "night",
hasVideo: true,
videoDuration: "14:10",
title: "Вечер в незнакомом городе",
characters: "Редакция «между.» · Вымышленные взрослые: Ася, 32 · Илья, 35 · Роман, 36",
lead: "Три старых друга встречаются на один вечер. У каждого — свой маршрут, но одна общая история.",
quote: "«Они встретились у гостиницы, которую никто из них не выбрал бы для себя. И потому всем было легко.»",
chapter: "I. Вечер в незнакомом городе",
paragraphs: [
"Они встретились у гостиницы, которую никто из них не выбрал бы для себя. И потому всем было легко. Чужой вокзал, влажный воздух северного города и три часа до ночного поезда создавали редкое чувство невесомости.",
"Ася смотрела, как Илья и Роман спорят о карте старого центра, и ловила себя на мысли, что за пять лет разлуки исчезла вся прежняя осторожность. Осталось только острое, почти осязаемое притяжение людей, которые слишком хорошо помнят друг друга."
]
},
{
id: 3,
genre: "Эпистолярная проза",
meta: "ЭПИСТОЛЯРНАЯ ПРОЗА / 4 мин / 18+",
duration: "4 мин",
timeCat: "short",
mood: "warm",
hasVideo: false,
videoDuration: "",
title: "Письмо, которое всё изменило",
characters: "Редакция «между.» · Вымышленные взрослые: Соня, 30 · Андрей, 34",
lead: "Соня возвращает непрочитанное письмо. Андрей предлагает начать не с объяснений, а с прогулки.",
quote: "«Конверт пролежал в ящике стола почти год. Теперь Соня держала его так, словно это был билет в город, где она ещё не бывала.»",
chapter: "I. Письмо",
paragraphs: [
"Конверт пролежал в ящике стола почти год. Теперь Соня держала его так, словно это был билет в город, где она ещё не бывала. Бумага сохранила лёгкий запах табака и кедра.",
"Когда Андрей открыл дверь, он посмотрел на запечатанный конверт в её руке и не стал спрашивать, почему она не вскрыла его прошлой зимой. Он просто взял пальто с вешалки: «Пойдём к набережной. Прочитаешь вслух, если захочешь»."
]
}
];
let isSubscribed = false;
let isVideoPlaying = false;
let currentFontSize = 20;
const SCREEN_TITLES = {
home: "Главная",
catalog: "Истории",
reader: "Истории / Чтение",
videos: "Видео по историям",
continue: "Продолжить чтение",
favorites: "Избранное",
ai_heroes: "Другой формат · AI герои",
ai_chat: "Диалоги / Лев · моя версия",
my_ai: "Мои AI",
create_ai: "Создать героя",
personal: "Личное",
subscription: "Подписка",
login: "Вход · 18+",
settings: "Настройки",
states: "Состояния интерфейса"
};
function switchScreen(screenId) {
Object.keys(SCREEN_TITLES).forEach(k => {
const sec = document.getElementById('screen-' + k);
if (sec) sec.classList.add('hidden');
const nav = document.getElementById('nav-' + k);
if (nav) nav.classList.remove('active');
});
const target = document.getElementById('screen-' + screenId);
if (target) target.classList.remove('hidden');
const activeNav = document.getElementById('nav-' + (screenId === 'reader' ? 'catalog' : screenId));
if (activeNav) activeNav.classList.add('active');
document.getElementById('topBreadcrumb').innerText = SCREEN_TITLES[screenId] || "Главная";
window.scrollTo({ top: 0, behavior: 'smooth' });
}
function renderCatalog(list) {
const grid = document.getElementById('catalogGrid');
document.getElementById('catalogCountLabel').innerText = `${list.length} истории · Редакционный порядок`;
grid.innerHTML = list.map(s => `
<article class="surface-card p-7 flex flex-col justify-between space-y-5">
<div class="space-y-3">
<div class="text-[11px] uppercase tracking-[0.12em] meta-text">${s.genre.toUpperCase()} · ${s.duration}</div>
<h3 class="font-serif-editorial text-3xl font-normal cursor-pointer hover:opacity-80" onclick="openStoryReader(${s.id})">${s.title}</h3>
<p class="text-sm meta-text leading-relaxed">${s.lead}</p>
<blockquote class="font-serif-editorial italic text-lg pt-3 border-t hairline-border">${s.quote}</blockquote>
</div>
<div class="pt-4 border-t hairline-border flex items-center justify-between">
${s.hasVideo
? `<span class="wine-badge">🎬 Есть видео · по подписке (${s.videoDuration})</span>`
: `<span class="text-xs meta-text px-2.5 py-0.5 rounded border hairline-border">Пока только текст</span>`
}
<button onclick="openStoryReader(${s.id})" class="text-xs font-medium wine-text hover:underline">Читать историю →</button>
</div>
</article>
`).join('');
}
function filterCatalog() {
const g = document.getElementById('filterGenre').value;
const m = document.getElementById('filterMood').value;
const t = document.getElementById('filterTime').value;
const v = document.getElementById('filterVideo').value;
const filtered = STORIES.filter(s => {
if (g !== 'all' && s.genre !== g) return false;
if (m !== 'all' && s.mood !== m) return false;
if (t !== 'all' && s.timeCat !== t) return false;
if (v === 'yes' && !s.hasVideo) return false;
if (v === 'text' && s.hasVideo) return false;
return true;
});
renderCatalog(filtered);
}
function openStoryReader(storyIdx) {
const s = STORIES[storyIdx] || STORIES[0];
document.getElementById('readerMetaCategory').innerText = s.meta;
document.getElementById('readerTitle').innerText = s.title;
document.getElementById('readerLead').innerText = s.lead;
document.getElementById('readerCharacters').innerText = s.characters;
document.getElementById('readerChapterHeading').innerText = s.chapter;
document.getElementById('readerBodyParagraphs').innerHTML = s.paragraphs.map(p => `<p>${p}</p>`).join('');
document.getElementById('lockedStoryTitle').innerText = s.title;
document.getElementById('playerStoryTitle').innerText = s.title + " · Экранизация";
document.getElementById('lockedDuration').innerText = s.videoDuration || "08:40";
document.getElementById('lockedDurationSub').innerText = s.videoDuration || "08:40";
document.getElementById('playerDurationBadge').innerText = "02:16 / " + (s.videoDuration || "08:40");
switchScreen('reader');
}
function openStoryReaderAndScrollVideo(storyIdx) {
openStoryReader(storyIdx);
setTimeout(() => {
const el = document.getElementById('endOfStoryVideoBlock');
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, 150);
}
function setVideoAccess(unlocked) {
isSubscribed = unlocked;
const lockedCard = document.getElementById('videoLockedCard');
const unlockedCard = document.getElementById('videoUnlockedCard');
const bLock = document.getElementById('btnLockedState');
const bUnlock = document.getElementById('btnUnlockedState');
const mobSub = document.getElementById('mobSubBadge');
if (unlocked) {
lockedCard.classList.add('hidden');
unlockedCard.classList.remove('hidden');
bUnlock.className = "px-2 py-0.5 rounded text-[11px] font-medium bg-[var(--accent-wine)] text-white";
bLock.className = "px-2 py-0.5 rounded text-[11px] font-medium meta-text hover:text-[var(--text-ink)]";
if (mobSub) mobSub.innerText = "Подписка: активна";
} else {
lockedCard.classList.remove('hidden');
unlockedCard.classList.add('hidden');
bLock.className = "px-2 py-0.5 rounded text-[11px] font-medium bg-[var(--accent-wine)] text-white";
bUnlock.className = "px-2 py-0.5 rounded text-[11px] font-medium meta-text hover:text-[var(--text-ink)]";
if (mobSub) mobSub.innerText = "Подписка: выкл";
}
}
function toggleSubscriptionState() {
setVideoAccess(!isSubscribed);
}
function toggleVideoPlayback() {
isVideoPlaying = !isVideoPlaying;
document.getElementById('playPauseCircle').innerText = isVideoPlaying ? "⏸" : "▶";
document.getElementById('playPauseTextBtn').innerText = isVideoPlaying ? "⏸ Пауза" : "▶ Воспроизвести";
document.getElementById('videoStateNote').innerText = isVideoPlaying
? "Идёт воспроизведение экранизации · Звук включён"
: "На паузе · Позиция чтения 42% сохранена";
document.getElementById('videoProgressBar').style.width = isVideoPlaying ? "64%" : "28%";
}
function scrubVideo(e) {
const rect = e.currentTarget.getBoundingClientRect();
const pct = Math.max(5, Math.min(98, Math.round(((e.clientX - rect.left) / rect.width) * 100)));
document.getElementById('videoProgressBar').style.width = pct + "%";
}
function changeFontSize(delta) {
currentFontSize = Math.max(16, Math.min(26, currentFontSize + delta));
document.documentElement.style.setProperty('--reading-size', currentFontSize + 'px');
document.documentElement.style.setProperty('--reading-lh', Math.round(currentFontSize * 1.6) + 'px');
const ind = document.getElementById('fontSizeIndicator');
if (ind) ind.innerText = currentFontSize + ' px';
}
function toggleBookmarkToast() {
const t = document.getElementById('editorialToast');
t.classList.remove('hidden');
setTimeout(() => t.classList.add('hidden'), 3000);
}
function toggleAiVideoMode(showVideo) {
const box = document.getElementById('aiVideoCallBox');
const bText = document.getElementById('chatModeTextBtn');
const bVid = document.getElementById('chatModeVideoBtn');
if (showVideo) {
box.classList.remove('hidden');
bVid.className = "btn-wine px-3.5 py-1.5 text-xs";
bText.className = "btn-outline-editorial px-3.5 py-1.5 text-xs";
} else {
box.classList.add('hidden');
bText.className = "btn-wine px-3.5 py-1.5 text-xs";
bVid.className = "btn-outline-editorial px-3.5 py-1.5 text-xs";
}
}
function sendAiChatMessage(e) {
e.preventDefault();
const inp = document.getElementById('aiChatInput');
const val = inp.value.trim();
if (!val) return;
const list = document.getElementById('chatMessagesList');
list.innerHTML += `
<div class="p-4 rounded-md bg-[var(--accent-wine-soft)] ml-auto max-w-lg space-y-1">
<div class="text-[11px] wine-text">Сейчас · Вы · Доставлено ✓✓</div>
<p class="text-sm">${val}</p>
</div>
<div class="subtle-box p-4 max-w-lg space-y-1">
<div class="text-[11px] meta-text">Сейчас · Лев · AI</div>
<p class="text-sm">Мне нравится, как ты это замечаешь. Давай возьмём ещё по чашке кофе и никуда не будем спешить.</p>
</div>
`;
inp.value = '';
}
function toggleThemeNoir() {
document.body.classList.toggle('theme-noir');
const isNoir = document.body.classList.contains('theme-noir');
document.getElementById('themeSwitchBtn').innerText = isNoir ? "NOIR (#10121A)" : "CHAPTER (Бумага)";
}
document.addEventListener('DOMContentLoaded', () => {
renderCatalog(STORIES);
openStoryReader(0);
switchScreen('home');
});
</script>
</body>
</html>