Найден корректный robots.txt
Файл управления сканированием сайта роботами
?
Robots.txt указывает поисковым роботам, какие страницы сканировать, а какие — нет. Ошибки в файле могут случайно закрыть важные разделы от индексации.
Robots.txt настроен корректно. Размер файла: 33321 байт. Загружен за: 0сек.
Проверяемая страница не запрещена в robots.txt.
Цепочка редиректов для файла robots.txt:
http://nord-lights.com/robots.txt
301 MovedPermanently
https://nord-lights.com/robots.txt
200 OK
Показать содержимое robots.txt
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Nord Lights — Медиафасады в Москва-Сити</title>
<meta name="description" content="Рекламная компания Норд Лайтс — оператор собственных крупноформатных медиафасадов бизнес‑центра «Северная башня» в Москва‑Сити. Три поверхности, более 2 000 м² и охват свыше 1,1 млн человек ежедневно." />
<link rel="stylesheet" href="styles.css?v=76" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Manrope:wght@200;300;400;500&display=swap" rel="stylesheet" />
</head>
<body>
<header class="site-header">
<div class="container header-inner">
<a href="#top" class="logo" aria-label="Nord Lights — на главную">
<img class="logo-img" src="logo-nord-lights-cut.png?v=2" alt="" width="325" height="170" aria-hidden="true" />
<span class="logo-wordmark" aria-hidden="true">
<span class="logo-wordmark-line">NORD</span>
<span class="logo-wordmark-line">LIGHTS</span>
</span>
</a>
<nav class="main-nav">
<a href="#hero">Главная</a>
<a href="#about">О компании</a>
<a href="#advantages">Преимущества</a>
<a href="#south">Южные медиафасады</a>
<a href="#side-a">Сторона A</a>
<a href="#north">Северный медиафасад</a>
<a href="#packages">Продажа</a>
<a href="#contacts" class="nav-cta">Контакты</a>
</nav>
<button class="nav-toggle" aria-label="Открыть меню">
<span></span>
<span></span>
</button>
</div>
</header>
<main id="top">
<section id="hero" class="hero hero--lead">
<div class="container hero-inner">
<div class="hero-content">
<h1 class="hero-title">
Ваш статус<br />
в сердце<br />
делового мира
</h1>
<p class="hero-subtitle">
Современные медиафасады в Москва‑Сити с уникальным охватом и ярким
неоновым визуалом для сильных имиджевых кампаний.
</p>
<div class="hero-meta">
<div class="meta-item">
<span class="meta-label">3 медиафасада</span>
<span class="meta-value">с общей площадью > 2 000 м²</span>
</div>
<div class="meta-item">
<span class="meta-label">Охват</span>
<span class="meta-value">> 1,1 млн человек в сутки</span>
</div>
</div>
</div>
</div>
</section>
<section id="about" class="section about-section">
<div class="container section-inner about-section-inner">
<div class="about-copy">
<div class="about-copy-glow" aria-hidden="true"></div>
<h2 class="section-title about-section-title">
Оператор медиафасадов БЦ «Северная башня»
</h2>
<p class="section-text about-section-text">
Оператор собственных крупноформатных медиафасадов, расположенных с двух
сторон БЦ «Северная башня», являющаяся частью кластера ММДЦ «Москва‑Сити».
</p>
<p class="section-text about-section-text">
Три поверхности с общей площадью более 2 000 м². Медиафасады работают
в оба направления ТТК с качественным автомобильным и пешеходным трафиком.
Суммарный охват более 1,1 миллиона человек.
</p>
</div>
</div>
</section>
<section id="advantages" class="section section-alt">
<div class="container">
<h2 class="section-title">Почему медиафасады Nord Lights работают эффективнее?</h2>
<div class="advantages-layout">
<div class="adv-mini-grid">
<article class="adv-mini-card adv-mini-card--visibility">
<h3>Наилучшая видимость</h3>
<p>Более 1,1 млн человек ежедневного трафика по ТТК, МЦК, МЦД и пешеходным маршрутам.</p>
</article>
<article class="adv-mini-card adv-mini-card--icon-bell">
<div class="adv-mini-card-body">
<h3>Максимальное внимание ЦА</h3>
<p>Минимум информационного шума, доминирующее присутствие бренда на ключевых визуальных осях.</p>
</div>
<span class="adv-mini-icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 5v2M20 5v2" />
<path d="M6 8a6 6 0 1 1 12 0c0 7 3 9 3 9H3s3-2 3-9" />
<path d="M10.3 21a1.9 1.9 0 0 0 3.4 0" />
</svg>
</span>
</article>
<article class="adv-mini-card adv-mini-card--audience">
<h3>Топовая аудитория</h3>
<p>Высокая концентрация премиальной деловой аудитории на каждый квадратный метр.</p>
</article>
<article class="adv-mini-card adv-mini-card--icon-eye">
<div class="adv-mini-card-body">
<h3>Видимость в любое время</h3>
<p>В пиковое утреннее время поверхности не засвечиваются солнцем и одинаково ярки днём и ночью.</p>
</div>
<span class="adv-mini-icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">
<path d="M1 12s4.5-7 11-7 11 7 11 7-4.5 7-11 7S1 12 1 12z" />
<circle cx="12" cy="12" r="3" />
<circle cx="12" cy="12" r="1.35" fill="currentColor" stroke="none" />
</svg>
</span>
</article>
</div>
</div>
</div>
</section>
<section id="south" class="section south-section">
<div class="container south-wrap">
<div class="south-grid">
<div class="south-text-col">
<h2 class="section-title south-title">Южные медиафасады</h2>
<p class="section-text">
Работают при движении по ТТК, МЦК и МЦД от Кутузовского пр‑та в сторону
Ленинградского пр‑та. Прекрасная видимость рекламы для пешеходного
потока от станции МЦК/МЦД «Москва‑Сити», а также из окон всех ближайших
башен Сити, ЖК и офиса Сбербанка на Кутузовском пр‑те.
</p>
<div class="south-map-placeholder media-zoom-block">
<img
class="south-map-img"
src="south-map.png"
alt="Карта видимости медиафасадов A1 и A2, Москва‑Сити"
width="640"
height="400"
loading="lazy"
decoding="async"
/>
<div class="south-map-caption">
<span class="south-map-label">Карта видимости A1 / A2</span>
</div>
</div>
</div>
<div class="south-photo-column">
<div class="south-photos">
<div class="south-photo-card south-photo-card--day media-zoom-block">
<div class="south-photo-slot south-photo-slot--image">
<img
class="south-photo-img"
src="south-day.png"
alt="Южные медиафасады: поверхности A1 и A2, дневной вид"
width="600"
height="900"
loading="lazy"
decoding="async"
/>
</div>
</div>
<div class="south-photo-card south-photo-card--night media-zoom-block">
<div class="south-photo-slot south-photo-slot--image">
<img
class="south-photo-img south-photo-img--night"
src="south-night.png?v=2"
alt="Южные медиафасады, ночной вид: Москва-Сити, медиаэкраны"
width="600"
height="900"
loading="lazy"
decoding="async"
/>
</div>
</div>
</div>
<div class="south-bar">
<div class="south-bar-metric">
Медиаметрические показатели:<br />GRP 6,04 / OTS 619,7
</div>
<div class="south-bar-sizes">
<span>Размеры A1 — 48×19,5 м (936 м²)</span>
<span>Размеры A2 — 12×24 м (228 м²)</span>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="side-a" class="section side-a-section">
<div class="container side-a-wrap">
<div class="side-a-grid">
<div class="side-a-col side-a-col--left">
<h2 class="section-title">Синхронизация и креатив</h2>
<p class="section-text">
Медиафасады стороны А синхронизируются, имеют большой простор для креатива
и интересных рекламных возможностей.
</p>
<div class="side-a-photo-slot side-a-photo-slot--image media-zoom-block">
<img
class="side-a-photo-img side-a-photo-img--day"
src="side-a-day.png?v=1"
alt="Сторона А: синхронные медиаэкраны, дневной вид"
width="1200"
height="800"
loading="lazy"
decoding="async"
/>
</div>
</div>
<div class="side-a-col side-a-col--right">
<div class="side-a-photo-slot side-a-photo-slot--offset side-a-photo-slot--image media-zoom-block">
<img
class="side-a-photo-img"
src="side-a-night.png?v=1"
alt="Сторона А: синхронные медиаэкраны, ночной вид"
width="1200"
height="800"
loading="lazy"
decoding="async"
/>
</div>
<p class="section-text side-a-text-bottom">
Создают потрясающий вид огромного медиафасада. Максимально информативны.
</p>
</div>
</div>
</div>
</section>
<section id="north" class="section north-section">
<div class="container north-wrap">
<div class="north-grid">
<div class="north-text-col">
<h2 class="section-title north-title">Северный медиафасад</h2>
<p class="section-text">
Работает при движении по ТТК, МЦК и МЦД от Ленинградского пр‑та
в сторону Кутузовского пр‑та. Рабочее расстояние более 1 км —
звёздная высота и максимальный имидж для бренда.
</p>
<p class="section-text">
Никогда не засвечен солнцем, одинаково эффективен летом и зимой,
ночью и днём.
</p>
<div class="north-map-placeholder media-zoom-block">
<img
class="north-map-img"
src="north-map.png?v=1"
alt="Схема зоны видимости северного медиафасада Б, Москва‑Сити и ТТК"
width="800"
height="500"
loading="lazy"
decoding="async"
/>
<div class="north-map-caption">
<span class="north-map-label">Карта · зона видимости Б</span>
</div>
</div>
</div>
<div class="north-photo-column">
<div class="north-photo-card media-zoom-block">
<div class="north-photo-visual">
<div class="north-photo-slot north-photo-slot--image">
<img
class="north-photo-img north-photo-img--day"
src="north-day.png?v=1"
alt="Северный медиафасад Б, дневной вид"
width="1200"
height="800"
loading="lazy"
decoding="async"
/>
</div>
</div>
</div>
<div class="south-bar north-photo-bar">
<div class="south-bar-metric">
Медиаметрические показатели:<br />GRP 4,7 / OTS 481,6
</div>
<div class="south-bar-sizes">
<span>Размеры Б — 48×19,5 м (986 м²)</span>
</div>
</div>
</div>
<div class="north-photo-column">
<div class="north-photo-card north-photo-card--night media-zoom-block">
<div class="north-photo-visual">
<p class="north-photo-tagline">Ваш статус в сердце делового мира</p>
<div class="north-photo-slot north-photo-slot--image">
<img
class="north-photo-img north-photo-img--night"
src="north-night.png?v=1"
alt="Северный медиафасад Б, ночной вид"
width="1200"
height="800"
loading="lazy"
decoding="async"
/>
</div>
</div>
</div>
<div class="south-bar north-photo-bar">
<div class="south-bar-metric">
Медиаметрические показатели:<br />GRP 4,7 / OTS 481,6
</div>
<div class="south-bar-sizes">
<span>Размеры Б — 48×19,5 м (986 м²)</span>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="packages" class="section sale-section">
<div class="container sale-wrap">
<div class="sale-grid">
<div class="sale-content">
<div class="sale-content-inner">
<h2 class="sale-heading">Медиафасады продаются:</h2>
<ul class="sale-list">
<li>по отдельности, каждый;</li>
<li>парой A1/A2;</li>
<li>пакетные предложения.</li>
</ul>
</div>
<div class="sale-tower-art" aria-hidden="true"></div>
</div>
<div class="sale-gallery">
<div class="sale-photo media-zoom-block">
<span class="sale-badge" aria-hidden="true">A</span>
<div class="sale-photo-slot sale-photo-slot--image">
<img
class="sale-photo-img sale-photo-img--a"
src="sale-photo-a.png?v=1"
alt="Медиафасад A: дневной вид, медиаэкраны"
width="1200"
height="800"
loading="lazy"
decoding="async"
/>
</div>
</div>
<div class="sale-photo media-zoom-block">
<span class="sale-badge sale-badge--ru" aria-hidden="true">Б</span>
<div class="sale-photo-slot sale-photo-slot--image">
<img
class="sale-photo-img"
src="sale-photo-b.png?v=1"
alt="Медиафасад Б: вечерний вид, медиаэкран"
width="1200"
height="800"
loading="lazy"
decoding="async"
/>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="contacts" class="section section-contacts">
<div class="container contacts-inner">
<div class="contacts-main">
<div class="contacts-grid">
<article class="contacts-item">
<span class="contacts-icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" />
</svg>
</span>
<div class="contacts-item-body">
<p class="contacts-label">Телефон</p>
<div class="contacts-links-stack">
<a href="tel:+74957925070" class="contacts-link">+7 (495) 792‑50‑70</a>
</div>
</div>
</article>
<article class="contacts-item contacts-item--email">
<span class="contacts-icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" />
<polyline points="22,6 12,13 2,6" />
</svg>
</span>
<div class="contacts-item-body">
<p class="contacts-label">E‑mail</p>
<a href="mailto:info@nord-lights.com" class="contacts-link">info@nord-lights.com</a>
</div>
</article>
<article class="contacts-item">
<span class="contacts-icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
<circle cx="12" cy="10" r="3" />
</svg>
</span>
<div class="contacts-item-body">
<p class="contacts-label">Адрес</p>
<p class="contacts-text">
Москва, ул. Тестовская, 10,<br />
БЦ «Северная башня»
</p>
</div>
</article>
</div>
<div class="contacts-cta-wrap">
<button type="button" class="contacts-feedback-btn" id="feedback-open-btn" aria-haspopup="dialog" aria-controls="feedback-modal">
<img
class="contacts-feedback-btn-image"
src="media/feedback-button.png"
alt="Обратная связь"
width="1024"
height="640"
loading="lazy"
decoding="async"
/>
</button>
</div>
</div>
<aside class="contacts-aside" aria-label="О компании">
<div class="contacts-card">
<div class="contacts-card-glow" aria-hidden="true"></div>
<p class="contacts-card-title">Медиафасады Москва‑Сити</p>
<p class="contacts-card-text contacts-card-text--lead">
Собственные поверхности на «Северной башне».
</p>
<div class="contacts-card-meta">
<div class="contacts-card-stat">
<span class="contacts-card-stat-label">3 медиафасада</span>
<span class="contacts-card-stat-value">с общей площадью > 2 000 м²</span>
</div>
<div class="contacts-card-stat">
<span class="contacts-card-stat-label">Охват</span>
<span class="contacts-card-stat-value">> 1,1 млн человек в сутки</span>
</div>
</div>
<div class="contacts-card-presentation-wrap">
<a
href="Nord_Lights_Presentation.pdf"
class="contacts-card-presentation"
download="Nord_Lights_Presentation.pdf"
>
<svg class="contacts-card-presentation-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="7 10 12 15 17 10" />
<line x1="12" y1="15" x2="12" y2="3" />
</svg>
<span class="contacts-card-presentation-label">Скачать презентацию</span>
</a>
</div>
</div>
</aside>
</div>
</section>
</main>
<div id="feedback-modal" class="feedback-modal" hidden>
<button type="button" class="feedback-modal-backdrop" aria-label="Закрыть форму"></button>
<div class="feedback-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="feedback-modal-title">
<button type="button" class="feedback-modal-close" aria-label="Закрыть">×</button>
<h2 id="feedback-modal-title" class="feedback-modal-title">Обратная связь</h2>
<p class="feedback-modal-lead">
Оставьте контакты — перезвоним или ответим по почте и поможем с размещением на медиафасадах.
</p>
<form class="feedback-form" id="feedback-form">
<input type="hidden" name="company" value="" />
<input type="hidden" id="feedback-started-at" name="started_at" value="" />
<div class="feedback-field">
<label class="feedback-label" for="feedback-name">Имя</label>
<input class="feedback-input" id="feedback-name" name="name" type="text" required autocomplete="name" placeholder="Как к вам обращаться" />
</div>
<div class="feedback-field">
<label class="feedback-label" for="feedback-phone">Телефон</label>
<div class="feedback-phone-row">
<span class="feedback-phone-prefix">+7</span>
<input
class="feedback-input feedback-phone-field"
id="feedback-phone"
name="phone"
type="tel"
required
autocomplete="tel"
inputmode="numeric"
maxlength="15"
placeholder="(900) 123-45-67"
/>
</div>
</div>
<div class="feedback-field">
<label class="feedback-label" for="feedback-email">E‑mail <span class="feedback-optional">необязательно</span></label>
<input class="feedback-input" id="feedback-email" name="email" type="email" autocomplete="email" placeholder="Если удобнее ответить письмом" />
</div>
<div class="feedback-field">
<label class="feedback-label" for="feedback-message">Комментарий или вопрос</label>
<textarea class="feedback-input feedback-textarea" id="feedback-message" name="message" rows="3" placeholder="Сроки, форматы, бюджет — что угодно"></textarea>
</div>
<label class="feedback-consent">
<input class="feedback-checkbox" type="checkbox" id="feedback-consent" name="consent" required />
<span>Даю <a href="privacy.html#consent-blank" class="feedback-consent-link" onclick="event.stopPropagation()">согласие</a> на обработку персональных данных в соответствии с <a href="privacy.html#consent-policy" class="feedback-consent-link" onclick="event.stopPropagation()">политикой конфиденциальности</a>.</span>
</label>
<p class="feedback-mailto-note">
Заявка отправляется напрямую на <strong>info@nord-lights.com</strong> и фиксируется автоматически.
</p>
<p class="feedback-status" id="feedback-status" role="status" aria-live="polite"></p>
<button type="submit" class="btn-primary feedback-submit">Отправить заявку</button>
</form>
</div>
</div>
<div id="lightbox" class="lightbox" hidden role="dialog" aria-modal="true" aria-label="Просмотр изображения">
<button type="button" class="lightbox-backdrop" aria-label="Закрыть просмотр"></button>
<figure class="lightbox-figure">
<button type="button" class="lightbox-close" aria-label="Закрыть">×</button>
<img class="lightbox-img" src="" alt="" />
</figure>
</div>
<footer class="site-footer">
<div class="container footer-inner">
<span class="footer-copy">© Nord Lights, Москва‑Сити, «Северная башня»</span>
</div>
</footer>
<script>
const navToggle = document.querySelector('.nav-toggle');
const nav = document.querySelector('.main-nav');
if (navToggle && nav) {
navToggle.addEventListener('click', () => {
nav.classList.toggle('main-nav--open');
navToggle.classList.toggle('nav-toggle--open');
});
}
(function initLightbox() {
const root = document.getElementById('lightbox');
if (!root) return;
const imgEl = root.querySelector('.lightbox-img');
const backdrop = root.querySelector('.lightbox-backdrop');
const closeBtn = root.querySelector('.lightbox-close');
if (!imgEl || !backdrop || !closeBtn) return;
let lastFocus = null;
function closeLightbox() {
root.hidden = true;
document.body.classList.remove('lightbox-open');
imgEl.removeAttribute('src');
imgEl.removeAttribute('alt');
if (lastFocus && typeof lastFocus.focus === 'function') {
lastFocus.focus();
}
lastFocus = null;
}
function openLightbox(src, alt) {
if (!src) return;
lastFocus = document.activeElement;
imgEl.src = src;
imgEl.alt = alt || '';
root.hidden = false;
document.body.classList.add('lightbox-open');
closeBtn.focus();
}
backdrop.addEventListener('click', closeLightbox);
closeBtn.addEventListener('click', (e) => {
e.stopPropagation();
closeLightbox();
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && !root.hidden) {
closeLightbox();
}
});
document.querySelectorAll('.media-zoom-block').forEach((block) => {
const img = block.querySelector('img');
if (!img || !img.getAttribute('src')) return;
block.setAttribute('tabindex', '0');
block.setAttribute('role', 'button');
const altText = img.getAttribute('alt') || 'изображение';
block.setAttribute('aria-label', 'Открыть крупно: ' + altText);
block.addEventListener('click', () => {
openLightbox(img.currentSrc || img.src, img.alt);
});
block.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
openLightbox(img.currentSrc || img.src, img.alt);
}
});
});
})();
(function initFeedbackModal() {
const modal = document.getElementById('feedback-modal');
const openBtn = document.getElementById('feedback-open-btn');
const form = document.getElementById('feedback-form');
if (!modal || !openBtn || !form) return;
const backdrop = modal.querySelector('.feedback-modal-backdrop');
const closeBtn = modal.querySelector('.feedback-modal-close');
const firstField = document.getElementById('feedback-name');
const phoneInput = document.getElementById('feedback-phone');
const startedAtInput = document.getElementById('feedback-started-at');
const statusEl = document.getElementById('feedback-status');
if (!backdrop || !closeBtn || !phoneInput || !startedAtInput || !statusEl) return;
function setStatus(type, text) {
statusEl.className = 'feedback-status feedback-status--' + type;
statusEl.textContent = text;
}
function extractTenDigits(raw) {
let d = String(raw).replace(/\D/g, '');
if (d.length >= 11 && d[0] === '7') d = d.slice(1);
if (d.length >= 11 && d[0] === '8') d = d.slice(1);
return d.slice(0, 10);
}
function formatPhoneBlocks(ten) {
const t = ten.slice(0, 10);
if (!t.length) return '';
let s = '(' + t.slice(0, 3);
if (t.length < 3) return s;
s += ') ' + t.slice(3, 6);
if (t.length < 6) return s;
s += '-' + t.slice(6, 8);
if (t.length < 8) return s;
s += '-' + t.slice(8, 10);
return s;
}
function cursorAfterDigitCount(str, n) {
if (n <= 0) return 0;
let c = 0;
for (let i = 0; i < str.length; i++) {
if (/\d/.test(str[i])) {
c++;
if (c === n) return i + 1;
}
}
return str.length;
}
function applyPhoneMask() {
const oldVal = phoneInput.value;
const start = phoneInput.selectionStart;
const digitsBefore =
start != null ? oldVal.slice(0, start).replace(/\D/g, '').length : 0;
const ten = extractTenDigits(oldVal);
const newVal = formatPhoneBlocks(ten);
phoneInput.value = newVal;
const pos = cursorAfterDigitCount(newVal, digitsBefore);
queueMicrotask(() => {
try {
phoneInput.setSelectionRange(pos, pos);
} catch (_) {
/* ignore */
}
});
phoneInput.setCustomValidity('');
}
function syncPhoneValidity() {
const ten = extractTenDigits(phoneInput.value);
if (ten.length === 0) {
phoneInput.setCustomValidity('');
return;
}
if (ten.length < 10) {
phoneInput.setCustomValidity('Введите все 10 цифр после +7.');
return;
}
if (!/^9\d{9}$/.test(ten)) {
phoneInput.setCustomValidity('Нужен мобильный номер: первая цифра — 9.');
return;
}
phoneInput.setCustomValidity('');
}
phoneInput.addEventListener('input', applyPhoneMask);
phoneInput.addEventListener('blur', syncPhoneValidity);
let lastFocus = null;
function closeFeedback() {
modal.hidden = true;
document.body.classList.remove('feedback-modal-open');
if (lastFocus && typeof lastFocus.focus === 'function') {
lastFocus.focus();
}
lastFocus = null;
}
function openFeedback() {
lastFocus = document.activeElement;
startedAtInput.value = String(Date.now());
setStatus('idle', '');
modal.hidden = false;
document.body.classList.add('feedback-modal-open');
(firstField || closeBtn).focus();
}
openBtn.addEventListener('click', openFeedback);
backdrop.addEventListener('click', closeFeedback);
closeBtn.addEventListener('click', (e) => {
e.stopPropagation();
closeFeedback();
});
document.addEventListener(
'keydown',
(e) => {
if (e.key !== 'Escape' || modal.hidden) return;
closeFeedback();
e.preventDefault();
e.stopImmediatePropagation();
},
true
);
form.addEventListener('submit', (e) => {
e.preventDefault();
syncPhoneValidity();
if (!form.checkValidity()) {
form.reportValidity();
return;
}
setStatus('sending', 'Отправляем заявку...');
const name = document.getElementById('feedback-name')?.value.trim() || '';
const ten = extractTenDigits(phoneInput.value);
const phone = ten.length === 10 ? '+7 ' + formatPhoneBlocks(ten) : phoneInput.value.trim();
const email = document.getElementById('feedback-email')?.value.trim() || '';
const message = document.getElementById('feedback-message')?.value.trim() || '';
const startedAt = startedAtInput.value || String(Date.now());
const formData = new URLSearchParams();
formData.set('name', name);
formData.set('phone', phone);
formData.set('email', email);
formData.set('message', message);
formData.set('consent', '1');
formData.set('started_at', startedAt);
formData.set('company', form.elements.company?.value || '');
fetch('send.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
body: formData.toString(),
})
.then(async (resp) => {
let data = null;
try {
data = await resp.json();
} catch (_) {
data = null;
}
if (!resp.ok || !data || !data.ok) {
throw new Error((data && data.error) || 'Не удалось отправить заявку.');
}
setStatus('success', 'Спасибо! Заявка отправлена. Мы свяжемся с вами.');
form.reset();
startedAtInput.value = String(Date.now());
setTimeout(() => {
closeFeedback();
}, 900);
})
.catch((err) => {
setStatus('error', err.message || 'Ошибка отправки. Попробуйте еще раз.');
});
});
})();
</script>
</body>
</html>