Flatlogic Bot e7df955f4e 1
2026-03-27 19:50:03 +00:00

741 lines
38 KiB
TypeScript
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.

import React from 'react';
import type { ReactElement } from 'react';
import Head from 'next/head';
import { useRouter } from 'next/router';
import {
mdiArrowDown,
mdiArrowRight,
mdiCityVariantOutline,
mdiCompassOutline,
mdiMapMarker,
mdiRoadVariant,
mdiShieldAccount,
mdiViewDashboardOutline,
} from '@mdi/js';
import BaseButton from '../components/BaseButton';
import BaseIcon from '../components/BaseIcon';
import LayoutGuest from '../layouts/Guest';
import { getPageTitle } from '../config';
type CityMarker = {
id: string;
name: string;
district: string;
contractor: string;
description: string;
specialization: string;
top: string;
left: string;
popupTop: string;
popupLeft: string;
};
type RoleCard = {
id: string;
title: string;
caption: string;
description: string;
accent: string;
};
type JourneyContext = {
roleId: string;
roleTitle: string;
city: string;
contractor: string;
};
const journeyStorageKey = 'roadTalentJourney';
const palette = {
navy: '#243B74',
midnight: '#1A2A52',
burgundy: '#56061D',
berry: '#7A2338',
paper: '#F5F2EC',
};
const cityMarkers: CityMarker[] = [
{
id: 'moscow',
name: 'Москва',
district: 'Центральный кластер',
contractor: 'АО «ДорИнфраструктура»',
description:
'Координирует набор инженерных команд, стажировки и быстрый вывод специалистов на федеральные дорожные объекты.',
specialization: 'Цифровое управление проектами и кадровый резерв',
top: '35%',
left: '18%',
popupTop: '18%',
popupLeft: '23%',
},
{
id: 'saint-petersburg',
name: 'Санкт-Петербург',
district: 'Северо-Западный кластер',
contractor: 'ООО «Балтийские магистрали»',
description:
'Развивает дорожное проектирование и практикум для молодых специалистов под задачи северо-западных регионов.',
specialization: 'Проектирование, BIM и подготовка мастеров участка',
top: '26%',
left: '16%',
popupTop: '8%',
popupLeft: '21%',
},
{
id: 'kazan',
name: 'Казань',
district: 'Приволжский кластер',
contractor: 'ГК «Трасса Развития»',
description:
'Собирает межвузовские команды для пилотных дорожных полигонов, подготовки механиков и специалистов по безопасности движения.',
specialization: 'Учебные полигоны и отраслевые акселераторы',
top: '43%',
left: '29%',
popupTop: '24%',
popupLeft: '34%',
},
{
id: 'yekaterinburg',
name: 'Екатеринбург',
district: 'Уральский кластер',
contractor: 'АО «УралДорКадры»',
description:
'Формирует региональный кадровый центр по линейному строительству, эксплуатации техники и управлению подрядом.',
specialization: 'Линейное строительство и эксплуатация дорожной техники',
top: '45%',
left: '42%',
popupTop: '26%',
popupLeft: '47%',
},
{
id: 'novosibirsk',
name: 'Новосибирск',
district: 'Сибирский кластер',
contractor: 'ООО «СибАвтоДор»',
description:
'Запускает маршруты переобучения, отраслевую аналитику и совместные программы для СПО и подрядчиков.',
specialization: 'Переобучение и аналитика по потребности в кадрах',
top: '50%',
left: '58%',
popupTop: '31%',
popupLeft: '62%',
},
{
id: 'vladivostok',
name: 'Владивосток',
district: 'Дальневосточный кластер',
contractor: 'ГК «Восточный путь»',
description:
'Курирует кадровые потоки для портовых подходов, мостовых объектов и дорожных узлов Дальнего Востока.',
specialization: 'Мостостроение, портовая логистика и восточные коридоры',
top: '54%',
left: '87%',
popupTop: '35%',
popupLeft: '69%',
},
];
const roleCards: RoleCard[] = [
{
id: 'school',
title: 'Школа',
caption: 'Ранняя профориентация',
description: 'Маршрут для учеников, наставников и школьных команд, которым нужен вход в отрасль через экскурсии и треки развития.',
accent: '#243B74',
},
{
id: 'college',
title: 'СПО и ВО',
caption: 'Подготовка специалистов',
description: 'Для колледжей и вузов, которые синхронизируют образовательные программы с реальными дорожными проектами.',
accent: '#1A2A52',
},
{
id: 'contractor',
title: 'Подрядные организации',
caption: 'Быстрый кадровый контур',
description: 'Для компаний, которым важно увидеть локальный кадровый резерв, потребности по ролям и точки входа в экосистему.',
accent: '#56061D',
},
{
id: 'government',
title: 'Государственные институты',
caption: 'Управление системой',
description: 'Для операторов отрасли, которые управляют координацией партнёров, показателями и региональными соглашениями.',
accent: '#7A2338',
},
];
function getRoleTitle(roleId: string) {
return roleCards.find((role) => role.id === roleId)?.title || '';
}
function RoleIllustration({ roleId }: { roleId: string }) {
const stroke = palette.paper;
if (roleId === 'school') {
return (
<svg viewBox='0 0 160 160' className='h-36 w-36' fill='none' aria-hidden='true'>
<circle cx='82' cy='38' r='16' stroke={stroke} strokeWidth='4' />
<path d='M48 78c10-18 21-27 34-27 12 0 22 8 31 24' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M63 86v35m39-35v35' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M35 110h92' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M42 110l20-18m56 18-20-18' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M18 44h32l8 14H26z' stroke={stroke} strokeWidth='4' strokeLinejoin='round' />
</svg>
);
}
if (roleId === 'college') {
return (
<svg viewBox='0 0 160 160' className='h-36 w-36' fill='none' aria-hidden='true'>
<circle cx='80' cy='34' r='16' stroke={stroke} strokeWidth='4' />
<path d='M52 80c9-18 19-27 28-27 12 0 22 8 28 22' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M63 82v42m34-42v42' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M80 18l46 18-46 18-46-18 46-18z' stroke={stroke} strokeWidth='4' strokeLinejoin='round' />
<path d='M124 39v28' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M42 118c12-10 25-15 38-15s26 5 38 15' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
</svg>
);
}
if (roleId === 'contractor') {
return (
<svg viewBox='0 0 160 160' className='h-36 w-36' fill='none' aria-hidden='true'>
<circle cx='80' cy='34' r='16' stroke={stroke} strokeWidth='4' />
<path d='M56 80c7-19 16-28 24-28 11 0 21 9 27 28' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M62 82v38m34-38v38' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M48 56l32-20 32 20' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M48 122h64' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M36 101h88' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M28 101l8-23h88l8 23' stroke={stroke} strokeWidth='4' strokeLinejoin='round' />
</svg>
);
}
return (
<svg viewBox='0 0 160 160' className='h-36 w-36' fill='none' aria-hidden='true'>
<circle cx='80' cy='34' r='16' stroke={stroke} strokeWidth='4' />
<path d='M55 79c8-18 17-27 25-27 11 0 20 8 26 24' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M61 82v40m34-40v40' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M36 114h88' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M80 56v-16' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
<path d='M48 64l32-16 32 16' stroke={stroke} strokeWidth='4' strokeLinejoin='round' />
<rect x='48' y='64' width='64' height='30' rx='8' stroke={stroke} strokeWidth='4' />
<path d='M72 79h16' stroke={stroke} strokeWidth='4' strokeLinecap='round' />
</svg>
);
}
export default function RoadTalentLanding() {
const router = useRouter();
const [showIntro, setShowIntro] = React.useState(true);
const [selectedCity, setSelectedCity] = React.useState<CityMarker | null>(cityMarkers[0]);
const [selectedRole, setSelectedRole] = React.useState<string>('');
const [roleStageVisible, setRoleStageVisible] = React.useState(false);
const [validationMessage, setValidationMessage] = React.useState('');
React.useEffect(() => {
const introTimer = window.setTimeout(() => {
setShowIntro(false);
}, 2600);
return () => window.clearTimeout(introTimer);
}, []);
const openRoleStage = () => {
if (!selectedCity) {
setValidationMessage('Сначала выберите город на карте.');
return;
}
setValidationMessage('');
setRoleStageVisible(true);
window.setTimeout(() => {
document.getElementById('roles-stage')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, 120);
};
const continueToLogin = () => {
if (!selectedCity) {
setValidationMessage('Сначала выберите город и подрядчика.');
return;
}
if (!selectedRole) {
setValidationMessage('Выберите роль, чтобы продолжить ко входу.');
return;
}
const roleTitle = getRoleTitle(selectedRole);
const journeyContext: JourneyContext = {
roleId: selectedRole,
roleTitle,
city: selectedCity.name,
contractor: selectedCity.contractor,
};
localStorage.setItem(journeyStorageKey, JSON.stringify(journeyContext));
router.push({
pathname: '/login',
query: {
role: selectedRole,
city: selectedCity.name,
contractor: selectedCity.contractor,
},
});
};
return (
<>
<Head>
<title>{getPageTitle('Кадровый суверенитет дорожной отрасли')}</title>
</Head>
<div className='relative overflow-hidden bg-[#0d1530] text-[#F5F2EC]'>
{showIntro && (
<div className='road-intro-overlay fixed inset-0 z-50 flex items-center justify-center px-6'>
<button
type='button'
onClick={() => setShowIntro(false)}
className='absolute right-6 top-6 rounded-full border border-white/25 px-4 py-2 text-sm text-white/80 transition hover:border-white/60 hover:text-white focus:outline-none focus:ring focus:ring-white/40'
>
Пропустить
</button>
<div className='road-intro-panel flex max-w-3xl flex-col items-center text-center'>
<div className='road-intro-road mb-10 w-full max-w-xl'>
<span />
<span />
<span />
</div>
<p className='mb-4 text-sm uppercase tracking-[0.45em] text-white/65'>кадровый суверенитет дорожной отрасли</p>
<h1 className='road-intro-title max-w-4xl text-4xl font-semibold tracking-tight md:text-6xl'>
Соединяем города, подрядчиков и роли в одном маршруте входа
</h1>
<p className='mt-6 max-w-2xl text-base text-[#F5F2EC]/78 md:text-lg'>
Интерактивный MVP-портал для выбора города, просмотра подрядчика и быстрого перехода к авторизации по нужной роли.
</p>
</div>
</div>
)}
<div className='absolute inset-0 bg-[radial-gradient(circle_at_top_left,_rgba(36,59,116,0.46),_transparent_36%),radial-gradient(circle_at_80%_15%,_rgba(122,35,56,0.28),_transparent_30%),linear-gradient(180deg,_#1A2A52_0%,_#0d1530_60%,_#0c1123_100%)]' />
<div className='absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-white/40 to-transparent' />
<div className='relative z-10 mx-auto flex min-h-screen max-w-7xl flex-col px-6 pb-10 pt-6 lg:px-10'>
<header className='mb-10 flex flex-col gap-4 rounded-[28px] border border-white/10 bg-white/5 px-5 py-4 backdrop-blur md:flex-row md:items-center md:justify-between'>
<div>
<p className='text-xs uppercase tracking-[0.4em] text-white/55'>MVP-портал</p>
<div className='mt-2 flex items-center gap-3'>
<div className='flex h-11 w-11 items-center justify-center rounded-2xl bg-[#243B74] shadow-[0_0_0_6px_rgba(245,242,236,0.04)]'>
<BaseIcon path={mdiRoadVariant} size={24} />
</div>
<div>
<p className='text-lg font-semibold md:text-xl'>Кадровый суверенитет</p>
<p className='text-sm text-white/65'>дорожной отрасли России</p>
</div>
</div>
</div>
<div className='flex flex-wrap items-center gap-3'>
<button
type='button'
onClick={() => document.getElementById('map-stage')?.scrollIntoView({ behavior: 'smooth', block: 'start' })}
className='inline-flex items-center gap-2 rounded-full border border-white/15 px-4 py-2 text-sm text-white/85 transition hover:border-white/35 hover:bg-white/8 focus:outline-none focus:ring focus:ring-white/30'
>
<BaseIcon path={mdiCompassOutline} size={18} />
К карте
</button>
<BaseButton href='/login' label='Войти' color='info' className='border-0 bg-[#243B74] px-5 text-white hover:bg-[#314c90]' />
<BaseButton
href='/login'
label='Админ-интерфейс'
color='white'
outline
className='border-white/25 bg-transparent px-5 text-white hover:border-white/45 hover:bg-white/10'
/>
</div>
</header>
<section className='grid items-start gap-8 pb-10 lg:grid-cols-[1.1fr_0.9fr] lg:pb-16'>
<div className='max-w-3xl'>
<div className='mb-5 inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/6 px-4 py-2 text-sm text-white/75'>
<span className='h-2.5 w-2.5 rounded-full bg-[#F5F2EC]' />
Анимация входа выбор города роль логин
</div>
<h1 className='max-w-4xl text-4xl font-semibold leading-tight md:text-6xl'>
Выберите город на карте России и войдите в отраслевую экосистему с нужной ролью.
</h1>
<p className='mt-6 max-w-2xl text-base leading-7 text-white/70 md:text-lg'>
Первый MVP-срез уже проводит пользователя по ключевому сценарию: показывает городские точки, раскрывает карточку подрядчика,
предлагает роль и передаёт контекст в авторизацию без лишних шагов.
</p>
<div className='mt-8 flex flex-wrap gap-3'>
<button
type='button'
onClick={() => document.getElementById('map-stage')?.scrollIntoView({ behavior: 'smooth', block: 'start' })}
className='inline-flex items-center gap-2 rounded-full bg-[#F5F2EC] px-6 py-3 text-sm font-medium text-[#1A2A52] transition hover:translate-y-[-1px] hover:bg-white focus:outline-none focus:ring focus:ring-white/40'
>
Начать маршрут
<BaseIcon path={mdiArrowDown} size={18} />
</button>
<BaseButton
href='/login'
label='Перейти ко входу'
color='white'
outline
className='border-white/20 bg-transparent px-6 text-white hover:border-white/40 hover:bg-white/10'
/>
</div>
<div className='mt-10 grid gap-4 sm:grid-cols-3'>
{[
{ value: '6', label: 'городов в демо-карте' },
{ value: '4', label: 'роли входа' },
{ value: '1', label: 'сквозной маршрут MVP' },
].map((item) => (
<div key={item.label} className='rounded-[24px] border border-white/10 bg-white/6 p-5 backdrop-blur'>
<div className='text-3xl font-semibold text-white'>{item.value}</div>
<div className='mt-2 text-sm leading-6 text-white/65'>{item.label}</div>
</div>
))}
</div>
</div>
<div className='rounded-[32px] border border-white/10 bg-gradient-to-br from-white/12 via-white/8 to-white/5 p-6 shadow-[0_40px_120px_rgba(5,9,20,0.45)] backdrop-blur'>
<div className='mb-6 flex items-center justify-between'>
<div>
<p className='text-xs uppercase tracking-[0.32em] text-white/55'>Маршрут пользователя</p>
<h2 className='mt-2 text-2xl font-semibold'>Первый экран, который продаёт логику сервиса</h2>
</div>
<div className='rounded-full border border-white/15 bg-white/8 px-3 py-1 text-xs text-white/70'>public MVP</div>
</div>
<div className='space-y-4'>
{[
'1. Анимированный вход знакомит пользователя с сервисом.',
'2. Карта России позволяет кликнуть по городам и увидеть подрядчика.',
'3. Выбор роли переносится в экран логина и дальше сохраняется для рабочего кабинета.',
].map((item) => (
<div key={item} className='flex items-start gap-3 rounded-[22px] border border-white/8 bg-[#101936]/70 p-4'>
<div className='mt-1 flex h-8 w-8 items-center justify-center rounded-full bg-[#243B74] text-sm font-semibold'></div>
<p className='text-sm leading-6 text-white/75'>{item}</p>
</div>
))}
</div>
<div className='mt-6 rounded-[24px] border border-[#7A2338]/60 bg-[linear-gradient(135deg,_rgba(122,35,56,0.18),_rgba(26,42,82,0.25))] p-5'>
<p className='text-sm uppercase tracking-[0.28em] text-[#F5F2EC]/55'>что дальше в админке</p>
<p className='mt-3 text-sm leading-7 text-[#F5F2EC]/82'>
После входа администратор уже может пользоваться существующими справочниками <span className='font-medium text-white'>Cities</span>,
<span className='font-medium text-white'> Contractors</span> и <span className='font-medium text-white'>Role cards</span> для наполнения отраслевых данных.
</p>
</div>
</div>
</section>
<section id='map-stage' className='grid gap-6 pb-10 lg:grid-cols-[1.25fr_0.75fr] lg:pb-16'>
<div className='rounded-[32px] border border-white/10 bg-white/6 p-5 shadow-[0_24px_90px_rgba(4,8,18,0.45)] backdrop-blur md:p-6'>
<div className='mb-5 flex flex-col gap-4 md:flex-row md:items-center md:justify-between'>
<div>
<p className='text-xs uppercase tracking-[0.32em] text-white/55'>Шаг 1</p>
<h2 className='mt-2 text-2xl font-semibold'>Интерактивная карта России по городам</h2>
</div>
<div className='rounded-full border border-white/10 bg-[#0f1734] px-4 py-2 text-sm text-white/70'>
Нажмите на город, чтобы открыть подрядчика
</div>
</div>
<div className='relative overflow-hidden rounded-[28px] border border-white/10 bg-[radial-gradient(circle_at_20%_20%,_rgba(245,242,236,0.08),_transparent_28%),linear-gradient(180deg,_rgba(15,23,52,0.96),_rgba(14,19,38,0.98))] p-4 md:p-6'>
<div className='absolute inset-x-0 top-6 flex justify-center'>
<div className='rounded-full border border-white/10 bg-white/10 px-4 py-2 text-xs uppercase tracking-[0.25em] text-white/55'>Россия · дорожные кластеры</div>
</div>
<div className='relative mt-10 min-h-[450px] overflow-hidden rounded-[24px] border border-white/8 bg-[linear-gradient(180deg,_rgba(255,255,255,0.02),_rgba(255,255,255,0.01))]'>
<div className='absolute inset-0 bg-[linear-gradient(90deg,_rgba(255,255,255,0.02)_1px,_transparent_1px),linear-gradient(_rgba(255,255,255,0.02)_1px,_transparent_1px)] bg-[size:42px_42px] opacity-30' />
<svg viewBox='0 0 900 460' className='absolute inset-0 h-full w-full'>
<defs>
<linearGradient id='russiaFill' x1='0%' x2='100%' y1='0%' y2='100%'>
<stop offset='0%' stopColor='rgba(245,242,236,0.16)' />
<stop offset='100%' stopColor='rgba(245,242,236,0.07)' />
</linearGradient>
</defs>
<path
d='M63 245l41-61 92-27 91 13 55-32 59 7 48-24 70 16 35-12 65 20 74-3 61 28 25 32-37 23 35 25-14 33-63 10-54 24-90 4-72 29-91 3-86 26-81-14-79 17-64-19 10-34-36-35z'
fill='url(#russiaFill)'
stroke='rgba(245,242,236,0.22)'
strokeWidth='3'
strokeLinejoin='round'
/>
</svg>
{selectedCity && (
<div
className='absolute hidden w-72 max-w-[80vw] rounded-[22px] border border-white/10 bg-[#f5f2ec] p-4 text-[#1A2A52] shadow-[0_22px_60px_rgba(5,10,28,0.55)] md:block'
style={{ top: selectedCity.popupTop, left: selectedCity.popupLeft }}
>
<p className='text-xs uppercase tracking-[0.28em] text-[#7A2338]'>Подрядчик</p>
<h3 className='mt-2 text-lg font-semibold'>{selectedCity.contractor}</h3>
<p className='mt-2 text-sm leading-6 text-[#1A2A52]/82'>{selectedCity.description}</p>
</div>
)}
{cityMarkers.map((city) => {
const isActive = selectedCity?.id === city.id;
return (
<button
key={city.id}
type='button'
onClick={() => {
setSelectedCity(city);
setValidationMessage('');
}}
className='group absolute -translate-x-1/2 -translate-y-1/2 focus:outline-none'
style={{ top: city.top, left: city.left }}
aria-label={`Открыть подрядчика для города ${city.name}`}
>
<span
className={`absolute left-1/2 top-1/2 h-14 w-14 -translate-x-1/2 -translate-y-1/2 rounded-full blur-md transition ${
isActive ? 'bg-[#F5F2EC]/35' : 'bg-[#243B74]/20 group-hover:bg-[#F5F2EC]/20'
}`}
/>
<span
className={`relative flex h-12 w-12 items-center justify-center rounded-full border transition ${
isActive
? 'border-[#F5F2EC] bg-[#F5F2EC] text-[#1A2A52]'
: 'border-white/25 bg-[#243B74]/85 text-white group-hover:border-white/55 group-hover:bg-[#314c90]'
}`}
>
<BaseIcon path={mdiMapMarker} size={22} />
</span>
<span
className={`mt-2 inline-flex rounded-full px-3 py-1 text-xs font-medium transition ${
isActive
? 'bg-[#F5F2EC] text-[#1A2A52]'
: 'bg-[#101936]/90 text-white/80 group-hover:text-white'
}`}
>
{city.name}
</span>
</button>
);
})}
</div>
<div className='mt-5 flex flex-wrap gap-2'>
{cityMarkers.map((city) => (
<button
key={city.id}
type='button'
onClick={() => {
setSelectedCity(city);
setValidationMessage('');
}}
className={`rounded-full border px-4 py-2 text-sm transition focus:outline-none focus:ring focus:ring-white/30 ${
selectedCity?.id === city.id
? 'border-[#F5F2EC] bg-[#F5F2EC] text-[#1A2A52]'
: 'border-white/12 bg-white/5 text-white/75 hover:border-white/30 hover:text-white'
}`}
>
{city.name}
</button>
))}
</div>
</div>
</div>
<aside className='rounded-[32px] border border-white/10 bg-[#f5f2ec] p-6 text-[#1A2A52] shadow-[0_24px_90px_rgba(4,8,18,0.35)]'>
<div className='mb-4 flex items-center justify-between'>
<div>
<p className='text-xs uppercase tracking-[0.3em] text-[#7A2338]'>Выбранная точка</p>
<h2 className='mt-2 text-2xl font-semibold'>Карточка подрядчика</h2>
</div>
<div className='rounded-2xl bg-[#1A2A52] p-3 text-white'>
<BaseIcon path={mdiCityVariantOutline} size={22} />
</div>
</div>
{selectedCity ? (
<>
<div className='rounded-[26px] border border-[#1A2A52]/8 bg-white p-5 shadow-[0_16px_40px_rgba(26,42,82,0.08)]'>
<p className='text-sm uppercase tracking-[0.25em] text-[#7A2338]'>{selectedCity.district}</p>
<h3 className='mt-2 text-3xl font-semibold'>{selectedCity.name}</h3>
<p className='mt-2 text-base font-medium text-[#243B74]'>{selectedCity.contractor}</p>
<p className='mt-4 text-sm leading-7 text-[#1A2A52]/78'>{selectedCity.description}</p>
<div className='mt-5 rounded-[22px] bg-[#F5F2EC] p-4'>
<p className='text-xs uppercase tracking-[0.24em] text-[#1A2A52]/55'>Фокус подрядчика</p>
<p className='mt-2 text-sm leading-6 text-[#1A2A52]/82'>{selectedCity.specialization}</p>
</div>
</div>
<div className='mt-5 grid grid-cols-2 gap-3'>
{[
{ label: 'Город', value: selectedCity.name },
{ label: 'Формат', value: 'Открытый вход' },
{ label: 'Этап', value: 'Выбор роли' },
{ label: 'Доступ', value: 'Публичный MVP' },
].map((item) => (
<div key={item.label} className='rounded-[22px] bg-[#1A2A52] p-4 text-[#F5F2EC]'>
<p className='text-xs uppercase tracking-[0.22em] text-white/45'>{item.label}</p>
<p className='mt-2 text-sm font-medium'>{item.value}</p>
</div>
))}
</div>
</>
) : (
<div className='rounded-[24px] border border-dashed border-[#1A2A52]/18 bg-white p-6 text-center'>
<p className='text-lg font-semibold'>Пока город не выбран</p>
<p className='mt-2 text-sm leading-6 text-[#1A2A52]/72'>Нажмите на маркер на карте России, чтобы открыть карточку подрядчика и продолжить маршрут.</p>
</div>
)}
<div className='mt-6 rounded-[24px] bg-[linear-gradient(135deg,_#243B74,_#1A2A52)] p-5 text-[#F5F2EC]'>
<p className='text-xs uppercase tracking-[0.28em] text-white/55'>Шаг 2</p>
<h3 className='mt-2 text-xl font-semibold'>Перейти к выбору роли</h3>
<p className='mt-3 text-sm leading-6 text-white/70'>Продолжите сценарий после выбора города: откроем четыре роли и передадим выбор в экран логина.</p>
<button
type='button'
onClick={openRoleStage}
className='mt-5 inline-flex items-center gap-2 rounded-full bg-[#F5F2EC] px-5 py-3 text-sm font-medium text-[#1A2A52] transition hover:translate-y-[-1px] hover:bg-white focus:outline-none focus:ring focus:ring-white/40'
>
Далее
<BaseIcon path={mdiArrowRight} size={18} />
</button>
{validationMessage && <p className='mt-3 text-sm text-[#F5F2EC]/82'>{validationMessage}</p>}
</div>
</aside>
</section>
<section id='roles-stage' className={`pb-14 transition duration-500 ${roleStageVisible ? 'opacity-100' : 'opacity-90'}`}>
<div className='mb-6 flex flex-col gap-3 md:flex-row md:items-end md:justify-between'>
<div>
<p className='text-xs uppercase tracking-[0.32em] text-white/55'>Шаг 2</p>
<h2 className='mt-2 text-3xl font-semibold'>Выберите роль входа</h2>
<p className='mt-3 max-w-2xl text-sm leading-7 text-white/70'>Четыре карточки роли отражают ключевых участников экосистемы: от школы до подрядных организаций и государственных институтов.</p>
</div>
<div className='rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm text-white/70'>
{selectedCity ? `Город: ${selectedCity.name}` : 'Сначала выберите город'}
</div>
</div>
<div className='grid gap-5 lg:grid-cols-4'>
{roleCards.map((role) => {
const isActive = selectedRole === role.id;
return (
<button
key={role.id}
type='button'
onClick={() => {
setSelectedRole(role.id);
setValidationMessage('');
}}
className={`group relative overflow-hidden rounded-[30px] border p-6 text-left transition duration-200 focus:outline-none focus:ring focus:ring-white/35 ${
isActive
? 'border-white/50 bg-[linear-gradient(180deg,_rgba(245,242,236,0.16),_rgba(255,255,255,0.06))] shadow-[0_28px_70px_rgba(5,9,20,0.42)]'
: 'border-white/10 bg-white/5 hover:border-white/25 hover:bg-white/8'
}`}
>
<div
className='absolute inset-x-0 top-0 h-1'
style={{ background: `linear-gradient(90deg, ${role.accent}, rgba(245,242,236,0.75))` }}
/>
<div className='flex items-center justify-between'>
<p className='text-xs uppercase tracking-[0.28em] text-white/55'>{role.caption}</p>
<span className={`rounded-full px-3 py-1 text-xs ${isActive ? 'bg-[#F5F2EC] text-[#1A2A52]' : 'bg-white/10 text-white/65'}`}>
{isActive ? 'Выбрано' : 'Роль'}
</span>
</div>
<div className='mt-4 flex justify-center rounded-[26px] bg-[linear-gradient(180deg,_rgba(245,242,236,0.05),_rgba(245,242,236,0.01))] p-4'>
<RoleIllustration roleId={role.id} />
</div>
<h3 className='mt-5 text-2xl font-semibold'>{role.title}</h3>
<p className='mt-3 text-sm leading-7 text-white/70'>{role.description}</p>
</button>
);
})}
</div>
<div className='mt-8 grid gap-6 rounded-[32px] border border-white/10 bg-white/5 p-6 backdrop-blur lg:grid-cols-[0.95fr_1.05fr]'>
<div>
<p className='text-xs uppercase tracking-[0.32em] text-white/55'>Шаг 3</p>
<h3 className='mt-2 text-2xl font-semibold'>Переход к логину и паролю</h3>
<p className='mt-3 text-sm leading-7 text-white/70'>Выбранные город, подрядчик и роль будут показаны на экране логина и сохранятся для первого экрана внутри кабинета.</p>
</div>
<div className='grid gap-4 rounded-[26px] bg-[#f5f2ec] p-5 text-[#1A2A52] md:grid-cols-3'>
<div>
<p className='text-xs uppercase tracking-[0.25em] text-[#1A2A52]/50'>Город</p>
<p className='mt-2 text-base font-semibold'>{selectedCity?.name || 'Не выбран'}</p>
</div>
<div>
<p className='text-xs uppercase tracking-[0.25em] text-[#1A2A52]/50'>Подрядчик</p>
<p className='mt-2 text-base font-semibold'>{selectedCity?.contractor || 'Ожидание выбора'}</p>
</div>
<div>
<p className='text-xs uppercase tracking-[0.25em] text-[#1A2A52]/50'>Роль</p>
<p className='mt-2 text-base font-semibold'>{getRoleTitle(selectedRole) || 'Не выбрана'}</p>
</div>
</div>
</div>
<div className='mt-6 flex flex-col gap-4 md:flex-row md:items-center md:justify-between'>
<p className='text-sm text-white/70'>
{selectedRole
? `Готово: выбран маршрут «${selectedCity?.name || ''}${getRoleTitle(selectedRole)}».`
: 'Выберите одну из ролей, чтобы открыть следующий шаг.'}
</p>
<div className='flex flex-wrap gap-3'>
<BaseButton
href='/login'
label='Пропустить к логину'
color='white'
outline
className='border-white/20 bg-transparent px-5 text-white hover:border-white/40 hover:bg-white/10'
/>
<button
type='button'
onClick={continueToLogin}
className='inline-flex items-center gap-2 rounded-full bg-[#F5F2EC] px-6 py-3 text-sm font-medium text-[#1A2A52] transition hover:translate-y-[-1px] hover:bg-white focus:outline-none focus:ring focus:ring-white/35'
>
Продолжить к логину
<BaseIcon path={mdiShieldAccount} size={18} />
</button>
</div>
</div>
</section>
<footer className='mt-auto flex flex-col gap-4 border-t border-white/10 pt-6 text-sm text-white/60 md:flex-row md:items-center md:justify-between'>
<p>© 2026 Кадровый суверенитет дорожной отрасли первый публичный маршрут входа для партнёров и образовательных учреждений.</p>
<div className='flex flex-wrap items-center gap-3'>
<BaseButton
href='/login'
label='Открыть кабинет'
color='white'
outline
className='border-white/20 bg-transparent text-white hover:border-white/40 hover:bg-white/10'
/>
<BaseButton
href='/dashboard'
label='После входа: Overview'
color='white'
outline
className='border-white/20 bg-transparent text-white hover:border-white/40 hover:bg-white/10'
icon={mdiViewDashboardOutline}
/>
</div>
</footer>
</div>
</div>
</>
);
}
RoadTalentLanding.getLayout = function getLayout(page: ReactElement) {
return <LayoutGuest>{page}</LayoutGuest>;
};