/
mubarak
/
ID
Обзор
Документация
Войти
/
mubarak
/
ID
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
index.html
969 строк
42 KB
mubarak
Update: index.html
12 авг 2026, 13:19
Верифицирован
12 авг 2026, 13:19
3c79b9b
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="theme-color" content="#0a1a12"> <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Expires" content="0"> <title>Технолайт — Рассрочка</title> <link rel="manifest" href="manifest.json"> <style> * { margin: 0; padding: 0; box-sizing: border-box; } :root { --bg: #0a1a12; --card-bg: #f8f6f2; --text: #1a221d; --muted: #6b7a6d; --accent: #1f4d3a; --accent-light: #e2efe6; --gold: #b8862d; --gold-light: #faf4e8; --border: #d8e0d6; --input-bg: #eef1ed; --range-track: #dce3da; --range-fill: #1f4d3a; --shadow: 0 14px 40px rgba(0,0,0,0.22); } html, body { height: 100%; width: 100%; position: fixed; top: 0; left: 0; background: var(--bg); overflow: hidden; overscroll-behavior: none; } body { font-family: 'Inter', -apple-system, 'Segoe UI', sans-serif; color: var(--text); display: flex; justify-content: center; align-items: center; -webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; padding: env(safe-area-inset-top, 0) 10px env(safe-area-inset-bottom, 0) 10px; } .app { width: 100%; height: 100%; max-width: 430px; display: flex; flex-direction: column; background: var(--card-bg); border-radius: 28px; box-shadow: var(--shadow); overflow: hidden; transition: max-width 0.3s ease; } .scroll-area { overflow-y: auto; -webkit-overflow-scrolling: touch; flex: 1; scroll-behavior: smooth; overscroll-behavior: contain; } /* ── Hero ── */ .hero-screen { min-height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 40px 22px 36px; text-align: center; background: radial-gradient(ellipse at 50% 10%, rgba(31,77,58,0.07) 0%, transparent 70%); position: relative; overflow: hidden; } .hero-screen::before { content: ''; position: absolute; top: -60px; right: -60px; width: 180px; height: 180px; border-radius: 50%; background: rgba(184,134,45,0.04); pointer-events: none; } .hero-screen::after { content: ''; position: absolute; bottom: -40px; left: -40px; width: 140px; height: 140px; border-radius: 50%; background: rgba(31,77,58,0.04); pointer-events: none; } .hero-logo-wrap { width: 100px; height: 100px; margin-bottom: 18px; position: relative; z-index: 1; } .hero-logo-img { width: 100%; height: 100%; object-fit: contain; filter: drop-shadow(0 10px 24px rgba(0,0,0,0.2)); border-radius: 20px; } .hero-logo-fallback { display: none; width: 100%; height: 100%; background: linear-gradient(145deg, #1f5c3a, #0c2e1c); border-radius: 20px; align-items: center; justify-content: center; box-shadow: 0 12px 28px rgba(0,0,0,0.25); } .hero-logo-fallback svg { width: 48px; height: 48px; fill: none; stroke: #fff; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; } .hero-top-badge { display: inline-flex; align-items: center; gap: 6px; background: var(--accent); color: #fff; padding: 9px 18px; border-radius: 28px; font-size: 11px; font-weight: 700; letter-spacing: 0.5px; margin-bottom: 20px; position: relative; z-index: 1; box-shadow: 0 6px 20px rgba(31,77,58,0.3); } .hero-top-badge .live { width: 6px; height: 6px; border-radius: 50%; background: #fff; animation: livePulse 2s infinite; } @keyframes livePulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.3; transform: scale(2.2); } } .hero-screen h1 { font-size: 32px; font-weight: 900; letter-spacing: -0.7px; color: var(--text); margin-bottom: 8px; line-height: 1.15; position: relative; z-index: 1; } .hero-screen h1 .gold { color: var(--gold); } .hero-screen .hero-subtitle { font-size: 14px; color: var(--muted); font-weight: 500; margin-bottom: 22px; line-height: 1.4; max-width: 280px; position: relative; z-index: 1; } .hero-screen .hero-subtitle strong { color: var(--accent); } .rate-duo { display: flex; gap: 10px; margin-bottom: 24px; width: 100%; max-width: 330px; position: relative; z-index: 1; } .rate-duo .r-card { flex: 1; background: #fff; border-radius: 18px; padding: 16px 10px; text-align: center; box-shadow: 0 4px 18px rgba(0,0,0,0.04); transition: transform 0.2s; } .rate-duo .r-card:active { transform: scale(0.96); } .rate-duo .r-card.golden { border: 2px solid rgba(184,134,45,0.25); background: linear-gradient(180deg, #fffef9 0%, #fff 100%); } .rate-duo .r-card.green { border: 2px solid rgba(31,77,58,0.12); background: linear-gradient(180deg, #fafdfb 0%, #fff 100%); } .rate-duo .r-card .r-num { font-size: 38px; font-weight: 900; letter-spacing: -1px; line-height: 1; margin-bottom: 4px; } .rate-duo .r-card.golden .r-num { color: var(--gold); } .rate-duo .r-card.green .r-num { color: var(--accent); } .rate-duo .r-card .r-label { font-size: 10px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.4px; } .rate-duo .r-card .r-cond { font-size: 10px; color: var(--muted); margin-top: 2px; font-weight: 500; } .hook-text { width: 100%; max-width: 310px; margin-bottom: 22px; position: relative; z-index: 1; } .hook-text .hook-line { display: flex; align-items: center; gap: 8px; justify-content: center; margin-bottom: 6px; font-size: 12px; font-weight: 600; color: var(--accent); } .hook-text .hook-line .hook-icon { width: 18px; height: 18px; background: var(--accent-light); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 9px; flex-shrink: 0; } .hook-text .hook-highlight { font-size: 14px; font-weight: 800; color: var(--gold); text-align: center; letter-spacing: -0.2px; } .hero-cta { width: 100%; max-width: 300px; background: var(--accent); color: #fff; border: none; border-radius: 16px; padding: 18px 22px; font-weight: 700; font-size: 15px; cursor: pointer; font-family: inherit; letter-spacing: 0.2px; box-shadow: 0 10px 30px rgba(31,77,58,0.35); transition: all 0.25s; display: flex; align-items: center; justify-content: center; gap: 10px; position: relative; z-index: 1; } .hero-cta:active { transform: scale(0.94); box-shadow: 0 4px 12px rgba(31,77,58,0.18); background: #143826; } .hero-cta .arr { width: 28px; height: 28px; background: rgba(255,255,255,0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; transition: transform 0.3s; } .hero-cta:active .arr { transform: translateY(4px); } .hero-bottom-note { margin-top: 18px; font-size: 10px; color: var(--muted); font-weight: 500; display: flex; align-items: center; gap: 5px; position: relative; z-index: 1; } .hero-bottom-note .chk { width: 14px; height: 14px; background: var(--accent-light); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 7px; color: var(--accent); } /* ── Calculator ── */ .calc-section { min-height: 100%; padding: 0 0 20px; } .calc-header { display: flex; justify-content: space-between; align-items: center; padding: 18px 20px 6px; } .calc-brand { display: flex; align-items: center; gap: 10px; } .calc-logo-img { width: 36px; height: 36px; object-fit: contain; border-radius: 9px; box-shadow: 0 3px 8px rgba(0,0,0,0.1); } .calc-logo-fallback { display: none; width: 36px; height: 36px; background: linear-gradient(135deg, #1f4d3a, #0c2e1c); border-radius: 9px; align-items: center; justify-content: center; } .calc-logo-fallback svg { width: 22px; height: 22px; stroke: #fff; stroke-width: 2.5; fill: none; stroke-linecap: round; stroke-linejoin: round; } .calc-brand-name { font-size: 18px; font-weight: 800; color: var(--text); letter-spacing: -0.3px; } .calc-badge { background: var(--accent); color: #fff; padding: 6px 12px; border-radius: 18px; font-size: 10px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; } .calc-subtitle { padding: 2px 20px 10px; font-size: 11px; color: var(--muted); font-weight: 500; } .rate-card-live { margin: 0 18px 10px; padding: 14px 18px; display: flex; align-items: center; justify-content: space-between; border-radius: 16px; background: var(--gold-light); border: 1px solid rgba(184,134,45,0.15); transition: all 0.3s; } .rate-card-live .rcl-left { display: flex; align-items: center; gap: 10px; } .rate-card-live .rcl-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--gold); box-shadow: 0 0 0 4px rgba(184,134,45,0.1); flex-shrink: 0; } .rate-card-live .rcl-label { font-weight: 700; font-size: 13px; color: var(--gold); } .rate-card-live .rcl-value { font-weight: 800; font-size: 20px; color: var(--gold); transition: transform 0.3s; } .rate-card-live .rcl-value.pulse { transform: scale(1.2); } .content { padding: 4px 18px 6px; display: flex; flex-direction: column; gap: 14px; } .field { margin-bottom: 0; } .label-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; } .label-row label { font-size: 11px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.7px; } .val { font-weight: 700; font-size: 13px; color: var(--accent); } .input-box { display: flex; align-items: center; background: var(--input-bg); border: 2px solid transparent; border-radius: 14px; padding: 12px 15px; transition: all 0.2s; } .input-box:focus-within { border-color: var(--accent); background: #fff; box-shadow: 0 0 0 3px rgba(31,77,58,0.06); } .input-box input { width: 100%; border: none; background: transparent; font-size: 18px; font-weight: 700; color: var(--text); outline: none; } .input-box .currency { font-size: 16px; font-weight: 600; color: var(--muted); margin-left: 7px; } input[type="range"] { -webkit-appearance: none; width: 100%; height: 5px; background: var(--range-track); border-radius: 3px; outline: none; margin: 11px 0 5px; cursor: pointer; touch-action: none; } input[type="range"]::-webkit-slider-runnable-track { height: 5px; background: transparent; border-radius: 3px; } input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 26px; height: 26px; border-radius: 50%; background: #fff; border: 2.5px solid var(--range-fill); box-shadow: 0 2px 8px rgba(0,0,0,0.12); cursor: pointer; margin-top: -10.5px; transition: transform 0.1s; } input[type="range"]::-webkit-slider-thumb:active { transform: scale(1.1); } .limits { display: flex; justify-content: space-between; font-size: 9px; font-weight: 500; color: var(--muted); padding: 0 2px; } .pct-btns { display: flex; gap: 7px; margin-top: 9px; } .pct-btn { flex: 1; background: var(--input-bg); border: 2px solid transparent; border-radius: 12px; padding: 11px 4px; font-weight: 700; font-size: 12px; color: var(--text); text-align: center; cursor: pointer; transition: all 0.15s; font-family: inherit; } .pct-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); } .pct-btn.semi-disabled { opacity: 0.4; pointer-events: none; background: var(--input-bg); color: var(--muted); } .info-text { background: #fff8e1; color: #8a6914; padding: 8px 12px; border-radius: 10px; font-size: 11px; font-weight: 600; margin-top: 8px; display: none; border: 1px solid rgba(184,134,45,0.2); } .info-text.show { display: block; } /* ── Result ── */ .receipt { padding: 16px 18px 24px; border-top: 1px solid var(--border); margin-top: 4px; background: linear-gradient(to bottom, #fafdf9, #f8f6f2); } .receipt h3 { font-size: 11px; font-weight: 700; margin-bottom: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.7px; } .result-card { background: #fff; border-radius: 18px; padding: 20px 16px; box-shadow: 0 4px 20px rgba(0,0,0,0.06); border: 2px solid rgba(31,77,58,0.1); } .result-card .main-payment { text-align: center; margin-bottom: 14px; padding-bottom: 14px; border-bottom: 1px solid var(--border); } .result-card .main-payment .mp-label { font-size: 10px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; } .result-card .main-payment .mp-value { font-size: 38px; font-weight: 900; color: var(--accent); letter-spacing: -1px; line-height: 1.1; } .result-card .main-payment .mp-period { font-size: 11px; color: var(--muted); font-weight: 500; } .check-row { display: flex; align-items: baseline; margin-bottom: 9px; font-size: 13px; color: var(--muted); font-weight: 500; } .check-row .dots { flex: 1; border-bottom: 2px dotted var(--border); margin: 0 10px; } .check-row .value { white-space: nowrap; font-weight: 600; } .total-zone { padding-top: 10px; margin-top: 6px; display: flex; justify-content: space-between; align-items: center; font-size: 15px; font-weight: 700; border-top: 2px solid var(--border); } .total-zone .total-value { font-size: 24px; font-weight: 800; color: var(--accent); letter-spacing: -0.5px; } /* ========================================= ОБНОВЛЕННЫЕ ПРАВИЛА ДЛЯ ПЛАНШЕТОВ Разворачиваем на полный экран и увеличиваем масштаб ========================================= */ @media (min-width: 600px) { body { padding: env(safe-area-inset-top, 0) 0 env(safe-area-inset-bottom, 0) 0; } .app { max-width: 100%; border-radius: 0; } /* Hero-экран */ .hero-screen { padding: 60px 40px; } .hero-logo-wrap { width: 140px; height: 140px; margin-bottom: 24px; } .hero-logo-fallback svg { width: 64px; height: 64px; } .hero-top-badge { font-size: 15px; padding: 12px 24px; margin-bottom: 24px; } .hero-screen h1 { font-size: 48px; margin-bottom: 12px; } .hero-screen .hero-subtitle { font-size: 18px; max-width: 450px; margin-bottom: 32px; } .rate-duo { max-width: 480px; gap: 20px; margin-bottom: 32px; } .rate-duo .r-card { padding: 24px 16px; border-radius: 24px; } .rate-duo .r-card .r-num { font-size: 54px; margin-bottom: 8px; } .rate-duo .r-card .r-label { font-size: 14px; } .rate-duo .r-card .r-cond { font-size: 14px; } .hook-text { max-width: 400px; margin-bottom: 32px; } .hook-text .hook-line { font-size: 16px; gap: 12px; margin-bottom: 10px; } .hook-text .hook-line .hook-icon { width: 22px; height: 22px; font-size: 12px; } .hook-text .hook-highlight { font-size: 18px; margin-top: 14px; } .hero-cta { max-width: 400px; padding: 22px 26px; font-size: 18px; border-radius: 20px; } .hero-cta .arr { width: 32px; height: 32px; font-size: 16px; } .hero-bottom-note { margin-top: 24px; font-size: 14px; } /* Калькулятор */ .calc-header { padding: 24px 40px 10px; } .calc-brand { gap: 14px; } .calc-logo-img, .calc-logo-fallback { width: 48px; height: 48px; border-radius: 12px; } .calc-logo-fallback svg { width: 28px; height: 28px; } .calc-brand-name { font-size: 24px; } .calc-badge { font-size: 13px; padding: 8px 14px; } .calc-subtitle { font-size: 14px; padding: 4px 40px 20px; } .rate-card-live { margin: 0 40px 20px; padding: 20px 24px; border-radius: 20px; } .rate-card-live .rcl-dot { width: 12px; height: 12px; box-shadow: 0 0 0 5px rgba(184,134,45,0.1); } .rate-card-live .rcl-label { font-size: 16px; } .rate-card-live .rcl-value { font-size: 26px; } .content { padding: 10px 40px 20px; gap: 24px; } .label-row label { font-size: 14px; } .label-row .val { font-size: 16px; } .input-box { padding: 18px 20px; border-radius: 16px; } .input-box input { font-size: 26px; } .input-box .currency { font-size: 20px; } input[type="range"] { height: 8px; margin: 18px 0 10px; } input[type="range"]::-webkit-slider-runnable-track { height: 8px; border-radius: 4px; } input[type="range"]::-webkit-slider-thumb { width: 36px; height: 36px; margin-top: -14px; border-width: 4px; } .limits { font-size: 13px; } .pct-btns { gap: 12px; margin-top: 14px; } .pct-btn { padding: 16px 8px; font-size: 15px; border-radius: 14px; } .info-text { font-size: 14px; padding: 12px 16px; margin-top: 12px; } /* Чек (Результат) */ .receipt { padding: 20px 40px 30px; margin-top: 10px; } .receipt h3 { font-size: 14px; margin-bottom: 16px; } .result-card { padding: 26px 24px; border-radius: 24px; } /* Сетка (Grid) для главного платежа */ .result-card .main-payment { display: grid; grid-template-columns: 1fr auto; grid-template-areas: "label period" "value value"; align-items: baseline; text-align: left; margin-bottom: 16px; padding-bottom: 16px; } .result-card .main-payment .mp-label { font-size: 14px; grid-area: label; } /* Сильно увеличенный текст количества месяцев */ .result-card .main-payment .mp-period { font-size: 24px; font-weight: 800; color: var(--text); grid-area: period; margin-top: 0; } .result-card .main-payment .mp-value { font-size: 52px; grid-area: value; margin-top: 8px; } .check-row { font-size: 16px; margin-bottom: 12px; } .total-zone { padding-top: 16px; margin-top: 12px; font-size: 20px; } .total-zone .total-value { font-size: 32px; } } /* Для горизонтальных планшетов и экранов от 900px */ @media (min-width: 900px) { .hero-screen h1 { font-size: 64px; } .hero-screen .hero-subtitle { font-size: 22px; max-width: 600px; } .rate-duo { max-width: 600px; gap: 30px; } .rate-duo .r-card .r-num { font-size: 64px; } .input-box input { font-size: 32px; } .result-card .main-payment .mp-value { font-size: 64px; } } </style> </head> <body> <div class="app"> <div class="scroll-area" id="scrollArea"> <!-- Hero --> <div class="hero-screen" id="heroScreen"> <div class="hero-logo-wrap"> <!-- Замените logo.png на свой логотип --> <img src="logo.png" alt="Технолайт" class="hero-logo-img" onerror="this.style.display='none';this.nextElementSibling.style.display='flex';"> <div class="hero-logo-fallback"> <!-- Современная иконка магазина --> <svg viewBox="0 0 24 24"> <path d="M3 9l1-5h16l1 5H3z" /> <path d="M3 9v10a2 2 0 002 2h14a2 2 0 002-2V9" /> <path d="M9 21V12h6v9" /> <circle cx="9" cy="13" r="1" fill="#fff" stroke="none" /> <circle cx="15" cy="13" r="1" fill="#fff" stroke="none" /> </svg> </div> </div> <div class="hero-top-badge"> <span class="live"></span> Халяль-рассрочка </div> <h1>Самая <span class="gold">низкая</span><br>наценка в месяц</h1> <p class="hero-subtitle"> <strong>Всего 1.5%</strong> при первом взносе 25%.<br> Без взноса — <strong>всего 2.0%</strong>.<br> Чем больше взнос — тем выгоднее ставка! </p> <div class="rate-duo"> <div class="r-card golden"> <div class="r-num">1.5%</div> <div class="r-label">в месяц</div> <div class="r-cond">с взносом 25%</div> </div> <div class="r-card green"> <div class="r-num">2.0%</div> <div class="r-label">в месяц</div> <div class="r-cond">без взноса</div> </div> </div> <div class="hook-text"> <div class="hook-line"><span class="hook-icon">✓</span> Без скрытых платежей</div> <div class="hook-line"><span class="hook-icon">✓</span> По нормам шариата</div> <div class="hook-line"><span class="hook-icon">✓</span> Прозрачная мурабаха</div> <div class="hook-highlight">Снижайте ставку, увеличивая первый взнос!</div> </div> <button class="hero-cta" onclick="document.getElementById('calcSection').scrollIntoView({behavior:'smooth'})"> Рассчитать мою рассрочку <span class="arr">↓</span> </button> <div class="hero-bottom-note"> <span class="chk">⚡</span> Технолайт — удобство для жизни </div> </div> <!-- Calculator --> <div class="calc-section" id="calcSection"> <div class="calc-header"> <div class="calc-brand"> <img src="logo.png" alt="Технолайт" class="calc-logo-img" onerror="this.style.display='none';this.nextElementSibling.style.display='flex';"> <div class="calc-logo-fallback"> <svg viewBox="0 0 24 24"> <path d="M3 9l1-5h16l1 5H3z" /> <path d="M3 9v10a2 2 0 002 2h14a2 2 0 002-2V9" /> <path d="M9 21V12h6v9" /> </svg> </div> <span class="calc-brand-name">Технолайт</span> </div> <div class="calc-badge">Рассрочка</div> </div> <div class="calc-subtitle">Удобство для жизни — честные условия</div> <div class="rate-card-live" id="rateCardLive"> <div class="rcl-left"> <div class="rcl-dot"></div> <div class="rcl-label">Наценка в месяц</div> </div> <span class="rcl-value" id="rateValueLive">2.0%</span> </div> <div class="content"> <div class="field"> <div class="label-row"> <label>Стоимость товара</label> <span class="val">до 500 000 ₽</span> </div> <div class="input-box"> <input type="text" inputmode="numeric" id="price-input" value="110 000"> <span class="currency">₽</span> </div> <input type="range" id="price-slider" min="6000" max="500000" value="110000" step="1000"> <div class="limits"><span>6 000</span><span>500 000</span></div> </div> <div class="field"> <div class="label-row"> <label>Срок рассрочки</label> <span class="val" id="months-val">3 мес.</span> </div> <input type="range" id="months-slider" min="3" max="12" value="3" step="1"> <div class="limits"><span>3</span><span>12</span></div> </div> <div class="field"> <div class="label-row"> <label>Первоначальный взнос</label> <span class="val" id="dp-badge">25%</span> </div> <div class="input-box"> <input type="text" inputmode="numeric" id="dp-input" value="27 500"> <span class="currency">₽</span> </div> <input type="range" id="dp-slider" min="0" max="80" value="25" step="1"> <div class="limits"><span id="dp-min-lbl">0%</span><span>80%</span></div> <div class="pct-btns" id="dp-pct-btns"> <button class="pct-btn" data-pct="0">0%</button> <button class="pct-btn active" data-pct="25">25%</button> <button class="pct-btn" data-pct="50">50%</button> <button class="pct-btn" data-pct="80">80%</button> </div> <div class="info-text" id="warning">ℹ️ Минимальный взнос: 0 ₽</div> </div> </div> <div class="receipt" id="receipt"> <h3>Результат расчёта</h3> <div class="result-card"> <div class="main-payment"> <div class="mp-label">Ежемесячный платёж</div> <div class="mp-value" id="res-monthly">0 руб.</div> <div class="mp-period" id="res-period">на 3 месяца</div> </div> <div class="check-row"> <span>Первоначальный взнос</span> <span class="dots"></span> <span class="value" id="res-dp-rub">0 руб.</span> </div> <div class="check-row"> <span>Торговая наценка</span> <span class="dots"></span> <span class="value" id="res-markup">0 руб.</span> </div> <div class="total-zone"> <span>Итого к оплате</span> <span class="total-value" id="res-total">0 ₽</span> </div> </div> </div> </div> </div> </div> <script> function formatNumber(value) { const num = value.replace(/\s/g, '').replace(/[^\d]/g, ''); if (!num) return ''; return num.replace(/\B(?=(\d{3})+(?!\d))/g, ' '); } document.addEventListener('DOMContentLoaded', () => { const priceSlider = document.getElementById('price-slider'); const priceInput = document.getElementById('price-input'); const dpInput = document.getElementById('dp-input'); function updateSliderVisual(slider, value) { const style = getComputedStyle(document.documentElement); const fillColor = style.getPropertyValue('--range-fill').trim(); const trackColor = style.getPropertyValue('--range-track').trim(); const min = parseFloat(slider.min); const max = parseFloat(slider.max); const pct = ((value - min) / (max - min)) * 100; slider.style.background = `linear-gradient(to right, ${fillColor} 0%, ${fillColor} ${pct}%, ${trackColor} ${pct}%)`; } priceSlider.addEventListener('change', () => { updateSliderVisual(priceSlider, parseInt(priceSlider.value)); }); const observer = new MutationObserver(() => { updateSliderVisual(priceSlider, parseInt(priceSlider.value)); }); observer.observe(priceSlider, { attributes: true, attributeFilter: ['max', 'value'] }); priceInput.addEventListener('input', function() { const cursor = this.selectionStart; const before = this.value.length; this.value = formatNumber(this.value); const after = this.value.length; this.setSelectionRange(cursor + (after - before), cursor + (after - before)); }); dpInput.addEventListener('input', function() { const cursor = this.selectionStart; const before = this.value.length; this.value = formatNumber(this.value); const after = this.value.length; this.setSelectionRange(cursor + (after - before), cursor + (after - before)); }); }); </script> <script> (function() { const MIN_PRICE = 6000; const MAX_PRICE = 500000; const RATE = 0.02; // Оставляем переменные для целостности (чтобы ничего не урезать), но старая блокирующая логика отключена const DP_25_THRESHOLD = 250000; const DP_FIXED_BASE = 200000; const DP_MAX_PCT = 80; const priceInput = document.getElementById('price-input'); const priceSlider = document.getElementById('price-slider'); const monthsSlider = document.getElementById('months-slider'); const monthsVal = document.getElementById('months-val'); const dpInput = document.getElementById('dp-input'); const dpSlider = document.getElementById('dp-slider'); const dpMinLbl = document.getElementById('dp-min-lbl'); const dpBadge = document.getElementById('dp-badge'); const dpPctBtns = document.querySelectorAll('#dp-pct-btns .pct-btn'); const warning = document.getElementById('warning'); const rateValueLive = document.getElementById('rateValueLive'); const resMonthly = document.getElementById('res-monthly'); const resDpRub = document.getElementById('res-dp-rub'); const resMarkup = document.getElementById('res-markup'); const resTotal = document.getElementById('res-total'); const resPeriod = document.getElementById('res-period'); let currentPrice = 110000; let currentTerm = 3; let currentDP = 27500; let fillColor, trackColor; let prevRateStr = ''; function updateColors() { const style = getComputedStyle(document.documentElement); fillColor = style.getPropertyValue('--range-fill').trim(); trackColor = style.getPropertyValue('--range-track').trim(); } updateColors(); function fillSlider(slider, value) { const min = parseFloat(slider.min); const max = parseFloat(slider.max); const pct = ((value - min) / (max - min)) * 100; slider.style.background = `linear-gradient(to right, ${fillColor} 0%, ${fillColor} ${pct}%, ${trackColor} ${pct}%)`; } function formatMoney(v) { return v.toLocaleString('ru-RU').replace(/\s/g, ' ') + ' ₽'; } function getMonthWord(n) { if (n === 1) return 'месяц'; if (n >= 2 && n <= 4) return 'месяца'; return 'месяцев'; } // МИНИМАЛЬНЫЙ ВЗНОС ВСЕГДА ДОСТУПЕН ОТ 0 function getMinDP(p) { return 0; } function getMaxDP(p) { return Math.floor(p * 0.8); } function clampDP(dp, p) { return Math.max(getMinDP(p), Math.min(getMaxDP(p), dp)); } function round100(v) { return Math.round(v / 100) * 100; } function compute() { const p = currentPrice; const t = currentTerm; const d = currentDP; const minDp = getMinDP(p); const valid = d >= minDp && d <= getMaxDP(p) && p >= MIN_PRICE && p <= MAX_PRICE; const dpPct = p > 0 ? d / p : 0; const effRate = RATE * (1 - dpPct); const rateStr = (effRate * 100).toFixed(1).replace('.0', '') + '%'; const rateChanged = rateStr !== prevRateStr; prevRateStr = rateStr; rateValueLive.textContent = rateStr; if (rateChanged) { rateValueLive.classList.add('pulse'); setTimeout(() => rateValueLive.classList.remove('pulse'), 350); } if (valid) { const F = p - d; const debt = F * (1 + RATE * t); const M = Math.ceil(debt / t / 100) * 100; const rem = M * t; const markup = rem - F; const total = rem + d; resMonthly.textContent = formatMoney(M); resMarkup.textContent = formatMoney(markup); resTotal.textContent = formatMoney(total); resDpRub.textContent = d > 0 ? formatMoney(d) : '0 ₽'; resPeriod.textContent = 'на ' + t + ' ' + getMonthWord(t); } else { resMonthly.textContent = '—'; resMarkup.textContent = '—'; resTotal.textContent = formatMoney(p); resDpRub.textContent = d > 0 ? formatMoney(d) : '0 ₽'; resPeriod.textContent = 'на ' + t + ' ' + getMonthWord(t); } // Желтое предупреждение больше не нужно, так как 0% разрешен всегда warning.style.display = 'none'; } function updateUI(opts = {}) { const p = currentPrice; priceSlider.value = p; fillSlider(priceSlider, p); if (!opts.skipPriceInput) { priceInput.value = p.toLocaleString('ru-RU').replace(/\s/g, ' '); } monthsSlider.value = currentTerm; monthsVal.textContent = currentTerm + ' мес.'; fillSlider(monthsSlider, currentTerm); // Левая граница ползунка взноса теперь честно стоит на 0% всегда const sliderMinPct = 0; dpSlider.min = sliderMinPct; dpSlider.max = DP_MAX_PCT; let sPct = Math.round((currentDP / p) * 100); if (sPct < sliderMinPct) sPct = sliderMinPct; if (sPct > DP_MAX_PCT) sPct = DP_MAX_PCT; dpSlider.value = sPct; fillSlider(dpSlider, sPct); dpBadge.textContent = sPct + '%'; dpMinLbl.textContent = sliderMinPct + '%'; if (!opts.skipDpInput) { dpInput.value = currentDP.toLocaleString('ru-RU').replace(/\s/g, ' '); } // Кнопки работают как обычные переключатели, без блокировок dpPctBtns.forEach(btn => { const pctVal = parseInt(btn.dataset.pct); let target = clampDP(round100(Math.floor(p * pctVal / 100)), p); const active = target === currentDP; btn.classList.toggle('active', active); btn.textContent = pctVal + '%'; btn.classList.remove('semi-disabled'); }); compute(); } // ПСИХОЛОГИЧЕСКИЙ ЯКОРЬ НА 25% СОХРАНЕН: // При любом сдвиге цены взнос автоматически ставится на 25% priceSlider.addEventListener('input', () => { const val = parseInt(priceSlider.value); if (val === currentPrice) return; currentPrice = val; fillSlider(priceSlider, val); priceInput.value = val.toLocaleString('ru-RU').replace(/\s/g, ' '); currentDP = clampDP(round100(Math.floor(currentPrice * 0.25)), currentPrice); updateUI({ skipPriceInput: true }); }); priceInput.addEventListener('input', () => { const raw = priceInput.value; const num = parseInt(raw.replace(/\s/g, '')) || 0; if (num === currentPrice) return; if (num > MAX_PRICE) { currentPrice = MAX_PRICE; priceInput.value = MAX_PRICE.toLocaleString('ru-RU').replace(/\s/g, ' '); } else { currentPrice = num; } if (currentPrice < MIN_PRICE) currentPrice = MIN_PRICE; // Тот же якорь на 25% при ручном вводе currentDP = clampDP(round100(Math.floor(currentPrice * 0.25)), currentPrice); updateUI({ skipPriceInput: true }); }); priceInput.addEventListener('blur', () => { priceInput.value = currentPrice.toLocaleString('ru-RU').replace(/\s/g, ' '); }); monthsSlider.addEventListener('input', () => { currentTerm = parseInt(monthsSlider.value); fillSlider(monthsSlider, currentTerm); monthsVal.textContent = currentTerm + ' мес.'; compute(); }); dpSlider.addEventListener('input', () => { const pct = parseInt(dpSlider.value); let target = round100(Math.floor(currentPrice * pct / 100)); currentDP = clampDP(target, currentPrice); fillSlider(dpSlider, dpSlider.value); dpBadge.textContent = dpSlider.value + '%'; dpInput.value = currentDP.toLocaleString('ru-RU').replace(/\s/g, ' '); updateUI({ skipDpInput: true }); }); dpInput.addEventListener('input', () => { const raw = dpInput.value; const num = parseInt(raw.replace(/\s/g, '')) || 0; currentDP = num; updateUI({ skipDpInput: true }); }); dpInput.addEventListener('blur', () => { let val = parseInt(dpInput.value.replace(/\s/g, '')) || 0; val = round100(val); currentDP = clampDP(val, currentPrice); dpInput.value = currentDP.toLocaleString('ru-RU').replace(/\s/g, ' '); updateUI(); }); dpPctBtns.forEach(btn => { btn.addEventListener('click', () => { if (btn.classList.contains('semi-disabled')) return; const pctVal = parseInt(btn.dataset.pct); let target = round100(Math.floor(currentPrice * pctVal / 100)); currentDP = clampDP(target, currentPrice); dpInput.value = currentDP.toLocaleString('ru-RU').replace(/\s/g, ' '); updateUI({ skipDpInput: true }); }); }); // Дефолтное значение при загрузке - тоже 25% currentPrice = 110000; currentTerm = 3; currentDP = clampDP(round100(Math.floor(currentPrice * 0.25)), currentPrice); dpInput.value = currentDP.toLocaleString('ru-RU').replace(/\s/g, ' '); priceInput.value = currentPrice.toLocaleString('ru-RU').replace(/\s/g, ' '); updateUI(); })(); </script> <!-- Офлайн-режим --> <script> if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('sw.js').catch(() => {}); }); } </script> </body> </html>