PageSourceSearch

https://coinkeeper.me/calc/emergency-fund.html?utm_source=landing&utm_medium=nav&utm_campaign=calculators

html coinkeeper.me collected 2026-10-02 03:43:32 UTC 20,732 bytes, 363 lines download raw bytes

1<!DOCTYPE html>
2<html lang="ru">
3<head>
4<meta charset="UTF-8" />
5<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
6<title>На сколько вам хватит подушки — CoinKeeper</title>
7<meta name="description" content="Введите накопления и расходы в месяц — узнайте, на сколько дней вас хватит без дохода и в какую дату закончатся деньги." />
8
9<meta property="og:title" content="На сколько вас хватит, если завтра пропадёт доход" />
10<meta property="og:description" content="Введите накопления и расходы — узнайте свой запас прочности в днях и дату, когда кончатся деньги." />
11<meta property="og:type" content="website" />
12<meta property="og:image" content="https://calc.coinkeeper.me/og/emergency-fund" />
13<link rel="canonical" href="https://coinkeeper.me/calc/emergency-fund.html" />
14<meta property="og:url" content="https://coinkeeper.me/calc/emergency-fund.html" />
15<meta name="twitter:card" content="summary_large_image" />
16
17<link rel="icon" type="image/png" href="logo.png" />
18<link rel="apple-touch-icon" href="logo.png" />
19<link rel="preconnect" href="https://fonts.googleapis.com" />
20<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
21<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600;700;800;900&family=DM+Serif+Display:ital@0;1&display=swap" rel="stylesheet" />
22<link href="cta.css" rel="stylesheet" />
23<script src="analytics.js?v=1"></script>
23
24
25<style>
26  :root {
27    --bg: #FFF4E6;
28    --bg-2: #FFE5B8;
29    --card: #ffffff;
30    --line: #F4E8D4;
31    --line-2: #F6EFE2;
32    --ink: #1E2857;
33    --ink-2: #273572;
34    --ink-3: #4A557F;
35    --muted: #8B6F4E;
36    --muted-2: #B89572;
37    --orange: #FF791F;
38    --orange-dark: #DB5900;
39    --orange-soft: #FFE8CC;
40    --green: #20C997; --green-dark: #199E77; --green-soft: #B0F2DF;
41    --yellow: #FFB433; --yellow-soft: #FFE5B8;
42    --red: #F95050; --red-soft: #FFC9C9;
43    --shadow: 0 6px 24px rgba(139, 90, 30, .06);
44    --radius: 22px;
45  }
46  * { box-sizing: border-box; margin: 0; padding: 0; }
47  html { -webkit-font-smoothing: antialiased; }
48  body {
49    color: var(--ink);
50    font-family: 'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
51    background:
52      radial-gradient(1100px 700px at 0% 0%,    #FFFEFA 0%, transparent 60%),
53      radial-gradient(900px 500px at 100% 15%,  #FFF1DE 0%, transparent 55%),
54      radial-gradient(700px 500px at 80% 90%,   #FFEFD8 0%, transparent 60%),
55      linear-gradient(180deg, #FFFBF3 0%, #FFF1DC 100%);
56    min-height: 100vh;
57    padding: 24px 16px 80px;
58  }
59
60  .page { max-width: 560px; margin: 0 auto; }
61
62  header { text-align: center; margin: 16px 0 28px; }
63  .brand { display: inline-block; margin-bottom: 16px; }
64  .brand img { height: 30px; width: auto; display: block; }
65  h1 { font-size: 30px; font-weight: 800; line-height: 1.1; letter-spacing: -0.02em; color: var(--ink); }
66  h1 .accent { font-family: 'DM Serif Display', Georgia, serif; font-style: italic; font-weight: 400; color: var(--orange-dark); letter-spacing: -0.01em; }
67  .subtitle { color: var(--muted); font-size: 16px; font-weight: 500; margin-top: 10px; line-height: 1.5; }
68
69  .card { background: var(--card); border-radius: var(--radius); padding: 24px; box-shadow: var(--shadow); border: 1px solid var(--line); margin-bottom: 16px; }
70
71  .input-row label { display: block; font-size: 12px; font-weight: 800; color: var(--muted); margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.1em; }
72  .input-row + .input-row { margin-top: 18px; }
73  .input-wrap { position: relative; display: flex; align-items: center; }
74  .input-wrap input { width: 100%; font-family: inherit; font-size: 28px; font-weight: 800; padding: 14px 56px 14px 16px; border: 1.5px solid var(--line); border-radius: 14px; background: #fff; color: var(--ink); outline: none; transition: border-color 0.15s ease, box-shadow 0.15s ease; -moz-appearance: textfield; }
75  .input-wrap input::-webkit-outer-spin-button, .input-wrap input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
76  .input-wrap input:focus { border-color: var(--orange); box-shadow: 0 0 0 3px var(--orange-soft); }
77  .input-wrap .suffix { position: absolute; right: 18px; font-size: 22px; font-weight: 800; color: var(--muted-2); pointer-events: none; }
78  .quick-amounts { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
79  .quick-amounts button { font-family: inherit; font-size: 13px; font-weight: 700; padding: 8px 14px; border: 1.5px solid var(--line); background: #fff; color: var(--ink-3); border-radius: 999px; cursor: pointer; transition: all 0.15s ease; }
80  .quick-amounts button:hover { border-color: var(--orange); color: var(--orange-dark); }
81  .quick-amounts button:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
82
83  .result-card {
84    color: #fff; padding: 32px 24px; text-align: center; border-color: transparent;
85    background:
86      radial-gradient(500px 300px at 100% 0%, rgba(255,121,31,.28) 0%, transparent 60%),
87      linear-gradient(135deg, var(--ink) 0%, var(--ink-2) 100%);
88    box-shadow: 0 14px 36px rgba(30, 40, 87, .28);
89  }
90  .result-label { font-size: 12px; font-weight: 800; color: rgba(255,255,255,0.6); text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 12px; }
91  .result-value { font-size: 56px; font-weight: 900; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; line-height: 1; }
92  .result-value .num { color: var(--yellow); }
93  .result-unit { font-size: 16px; color: rgba(255,255,255,0.75); margin-top: 12px; font-weight: 600; }
94  .result-until { margin-top: 24px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,0.12); }
95  .result-until-label { font-size: 12px; color: rgba(255,255,255,0.55); margin-bottom: 6px; font-weight: 600; }
96  .result-until-value { font-size: 26px; font-weight: 800; }
97
98  .gauge { margin-top: 22px; }
99  .gauge-track { height: 12px; border-radius: 999px; background: rgba(255,255,255,0.14); overflow: hidden; }
100  .gauge-fill { height: 100%; border-radius: 999px; background: var(--red); width: 0%; transition: width .4s ease, background .4s ease; }
101  .gauge-scale { display: flex; justify-content: space-between; font-size: 11px; color: rgba(255,255,255,0.5); margin-top: 6px; font-weight: 700; }
102
103  .breakdown { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px; }
104  .breakdown-item { background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 18px; box-shadow: var(--shadow); }
105  .breakdown-label { font-size: 12px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 6px; }
106  .breakdown-value { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; color: var(--ink); }
107  .breakdown-hint { font-size: 12px; color: var(--muted-2); margin-top: 4px; font-weight: 500; }
108  .breakdown-item.highlight { background: var(--orange-soft); border-color: var(--orange); }
109  .breakdown-item.highlight .breakdown-value { color: var(--orange-dark); }
110
111  .fact-card { background: var(--orange-soft); border: 1px solid #FFD8A8; border-radius: var(--radius); padding: 20px 24px; margin-bottom: 16px; }
112  .fact-card .fact-emoji { font-size: 24px; margin-bottom: 8px; }
113  .fact-card .fact-text { font-size: 15px; line-height: 1.55; color: var(--ink); font-weight: 500; }
114  .fact-card .fact-text strong { font-weight: 800; color: var(--orange-dark); }
115
116  footer { text-align: center; margin-top: 32px; font-size: 13px; color: var(--muted); line-height: 1.6; font-weight: 500; }
117  footer a { color: var(--orange-dark); text-decoration: none; border-bottom: 1px solid var(--orange-soft); font-weight: 700; }
118  footer a:hover { color: var(--orange); }
119
120  @media (min-width: 560px) {
121    h1 { font-size: 38px; }
122    .result-value { font-size: 72px; }
123  }
124
125  @media (prefers-reduced-motion: reduce) {
126    *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
127  }
128</style>
129</head>
130<body>
131  <div class="page">
132    <header>
133      <a class="brand" href="https://coinkeeper.me/3?utm_source=viral&utm_medium=logo&utm_campaign=emergency-fund" target="_blank" rel="noopener"><img src="logoname.png" alt="CoinKeeper" /></a>
134      <h1>На сколько вас хватит, если <span class="accent">завтра пропадёт доход</span></h1>
135      <p class="subtitle">Накопления и расходы в месяц — и вы узнаете свой запас прочности в днях.</p>
136    </header>
137
138    <div class="card">
139      <div class="input-row">
140        <label for="savings">
140Сколько у вас отложено</label>
141        <div class="input-wrap">
142          <input type="text" inputmode="numeric" id="savings" value="200 000" autocomplete="off" />
143          <span class="suffix">₽</span>
144        </div>
145        <div class="quick-amounts">
146          <button data-target="savings" data-amount="50000">50 000</button>
147          <button data-target="savings" data-amount="100000">100 000</button>
148          <button data-target="savings" data-amount="300000">300 000</button>
149          <button data-target="savings" data-amount="500000">500 000</button>
150          <button data-target="savings" data-amount="1000000">1 млн</button>
151        </div>
152      </div>
153      <div class="input-row">
154        <label for="expenses">Расходы в месяц</label>
155        <div class="input-wrap">
156          <input type="text" inputmode="numeric" id="expenses" value="80 000" autocomplete="off" />
157          <span class="suffix">₽</span>
158        </div>
159        <div class="quick-amounts">
160          <button data-target="expenses" data-amount="40000">40 000</button>
161          <button data-target="expenses" data-amount="60000">60 000</button>
162          <button data-target="expenses" data-amount="80000">80 000</button>
163          <button data-target="expenses" data-amount="120000">120 000</button>
164          <button data-target="expenses" data-amount="200000">200 000</button>
165        </div>
166      </div>
167    </div>
168
169    <div class="card result-card">
170      <div class="result-label">Ваш запас прочности</div>
171      <div class="result-value"><span class="num" id="days-num">—</span></div>
172      <div class="result-unit" id="days-unit">дней без дохода</div>
173
174      <div class="gauge">
175        <div class="gauge-track"><div class="gauge-fill" id="gauge-fill"></div></div>
176        <div class="gauge-scale"><span>0</span><span>3 мес</span><span>6 мес и больше</span></div>
177      </div>
178
179      <div class="result-until">
180        <div class="result-until-label">Если доход исчезнет сегодня, деньги кончатся</div>
181        <div class="result-until-value" id="until-date">—</div>
182      </div>
183    </div>
184
185    <div class="breakdown">
186      <div class="breakdown-item">
187        <div class="breakdown-label">Это месяцев</div>
188        <div class="breakdown-value" id="months">—</div>
189      </div>
190      <div class="breakdown-item">
191        <div class="breakdown-label">Расходы в день</div>
192        <div class="breakdown-value" id="per-day">—</div>
193      </div>
194      <div class="breakdown-item highlight">
195        <div class="breakdown-label">До подушки 6 месяцев</div>
196        <div class="breakdown-value" id="gap">—</div>
197        <div class="breakdown-hint">столько осталось доложить</div>
198      </div>
199      <div class="breakdown-item">
200        <div class="breakdown-label">Подушка 6 месяцев это</div>
201        <div class="breakdown-value" id="target6">—</div>
202      </div>
203    </div>
204
205    <div class="fact-card" id="fact"></div>
206
207    <div id="cta-root"></div>
208
209    <footer>
210      <p>CoinKeeper считает ваши расходы автоматически — подушку не придётся прикидывать на глаз. <a href="https://coinkeeper.me/3?utm_source=viral&utm_medium=footer&utm_campaign=emergency-fund" target="_blank" rel="noopener">Попробуйте</a>.</p>
211    </footer>
212  </div>
213
214<script>
215(function() {
216  const savingsInput = document.getElementById('savings');
217  const expensesInput = document.getElementById('expenses');
218  const daysNum = document.getElementById('days-num');
219  const daysUnit = document.getElementById('days-unit');
220  const untilDate = document.getElementById('until-date');
221  const gaugeFill = document.getElementById('gauge-fill');
222  const monthsEl = document.getElementById('months');
223  const perDayEl = document.getElementById('per-day');
224  const gapEl = document.getElementById('gap');
225  const target6El = document.getElementById('target6');
226  const factEl = document.getElementById('fact');
227
228  let savings = 200000;
229  let expenses = 80000;
230  let days = 0;
231  let endDate = null;
232
233  const fmt = (n, decimals = 0) => n.toLocaleString('ru-RU', { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
234  const fmtCompact = (n) => {
235    if (n >= 1_000_000) return fmt(n / 1_000_000, 1).replace(/[.,]0$/, '') + ' млн ₽';
236    if (n >= 1_000) return fmt(Math.round(n / 1000) * 1000, 0) + ' ₽';
237    return fmt(n, 0) + ' ₽';
238  };
239  const MONTHS_GEN = ['января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'];
240  function fmtDate(d) { return d.getDate() + ' ' + MONTHS_GEN[d.getMonth()] + ' ' + d.getFullYear(); }
241
242  // 1 день / 2-4 дня / 5+ дней (с учётом 11-14)
243  function plural(n, one, few, many) {
244    const m10 = n % 10, m100 = n % 100;
245    if (m10 === 1 && m100 !== 11) return one;
246    if (m10 >= 2 && m10 <= 4 && (m100 < 12 || m100 > 14)) return few;
247    return many;
248  }
249
250  function parseNum(str) {
251    const n = parseInt(String(str).replace(/\D/g, ''), 10);
252    return isNaN(n) ? 0 : n;
253  }
254  function formatInput(n) { return n.toLocaleString('ru-RU').replace(/,/g, ' '); }
255
256  function recalc() {
257    const perDay = expenses / 30;
258    days = perDay > 0 ? Math.floor(savings / perDay) : 0;
259    const months = perDay > 0 ? savings / expenses : 0;
260
261    if (perDay <= 0 || savings <= 0) {
262      daysNum.textContent = '0';
263      daysUnit.textContent = 'дней без дохода';
264      untilDate.textContent = '—';
265      gaugeFill.style.width = '0%';
266      endDate = null;
267    } else {
268      daysNum.textContent = fmt(days);
269      daysUnit.textContent = plural(days, 'день без дохода', 'дня без дохода', 'дней без дохода');
270      endDate = new Date();
271      endDate.setDate(endDate.getDate() + days);
272      untilDate.textContent = fmtDate(endDate);
273      // шкала: 6 месяцев (180 дней) = 100%
274      const pct = Math.min(100, days / 180 * 100);
275      gaugeFill.style.width = pct + '%';
276      gaugeFill.style.background = days < 30 ? 'var(--red)' : days < 90 ? 'var(--yellow)' : 'var(--green)';
277    }
278
279    monthsEl.textContent = months >= 0.1 ? fmt(months, 1).replace(/[.,]0$/, '') : '0';
280    perDayEl.textContent = fmt(Math.round(expenses / 30)) + ' ₽';
281    const target6 = expenses * 6;
282    target6El.textContent = fmtCompact(target6);
283    const gap = Math.max(0, target6 - savings);
284    gapEl.textContent = gap === 0 ? 'Готово ✓' : fmtCompact(gap);
285
286    updateFact(months);
287    if (window.CTA) { window.CTA.refresh(); }
288  }
289
290  function updateFact(months) {
291    let text;
292    if (savings <= 0 || expenses <= 0) {
293      text = 'Введите накопления и расходы — посчитаем, на сколько вас хватит.';
294    } else if (months < 1) {
295      text = `Ваша подушка — <strong>меньше месяца</strong>. Любая внезапность (увольнение, болезнь, поломка) сразу станет долгом. Первая цель — отложить хотя бы <strong>${fmtCompact(expenses)}</strong>, это один месяц жизни.`;
296    } else if (months < 3) {
297      text = `У вас <strong>${fmt(months, 1).replace(/[.,]0$/, '')} мес.</strong> запаса. Это уже не ноль, но поиск новой работы в среднем занимает 3–4 месяца. До спокойных 6 месяцев не хватает <strong>${fmtCompact(Math.max(0, expenses * 6 - savings))}</strong>.`;
298    } else if (months < 6) {
299      text = `<strong>${fmt(months, 1).replace(/[.,]0$/, '')} месяца запаса</strong> — крепкий результат, лучше, чем у большинства. Дотяните до 6 месяцев (ещё <strong>${fmtCompact(Math.max(0, expenses * 6 - savings))}</strong>) — и сможете менять работу без паники.`;
300    } else if (months < 12) {
301      text = `<strong>${fmt(months, 1).replace(/[.,]0$/, '')} месяцев запаса</strong> — это полноценная финансовая подушка. Вы можете пережить увольнение, переезд или долгую болезнь, не залезая в долги.`;
302    } else {
303      text = `Запас на <strong>${fmt(months, 0)} месяцев</strong> — уровень финансовой неуязвимости. Возможно, части этих денег пора работать: подушке хватит 6 месяцев расходов, остальное может приносить доход.`;
304    }
305    factEl.innerHTML = `<div class="fact-emoji">🛟</div><div class="fact-text">${text}</div>`;
306  }
307
308  function bindMoneyInput(input, setter) {
309    input.addEventListener('input', (e) => {
310      const raw = parseNum(e.target.value);
311      setter(raw);
312      const formatted = formatInput(raw);
313      const cursorPos = e.target.selectionStart;
314      const diff = formatted.length - e.target.value.length;
315      e.target.value = formatted;
316      try { e.target.setSelectionRange(cursorPos + diff, cursorPos + diff); } catch (err) {}
317      recalc();
318    });
319  }
320  bindMoneyInput(savingsInput, v => savings = v);
321  bindMoneyInput(expensesInput, v => expenses = v);
322
323  document.querySelectorAll('.quick-amounts button').forEach(btn => {
324    btn.addEventListener('click', () => {
325      const amount = parseInt(btn.dataset.amount, 10);
326      if (btn.dataset.target === 'savings') { savings = amount; savingsInput.value = formatInput(amount); }
327      else { expenses = amount; expensesInput.value = formatInput(amount); }
328      recalc();
329    });
330  });
331
332  // --- Конфиг для общего CTA-модуля (cta.js) ---
333  window.CALC_CONFIG = {
334    id: 'emergency-fund',
335    course: 'finplan',
336    getInstallReason: () =>
337      `Ваш запас прочности — <strong>${fmt(days)} ${plural(days, 'день', 'дня', 'дней')}</strong>. CoinKeeper считает расходы автоматически, так что цифра всегда будет честной, а не «на глаз».`,
338    getShareCard: () => ({
339      eyebrow: 'Мой запас прочности',
340      currency: '',
341      big: fmt(days),
342      unit: plural(days, 'день без дохода', 'дня без дохода', 'дней без дохода'),
343      sub: endDate ? 'деньги кончатся ' + fmtDate(endDate) : '',
344      hook: 'А на сколько хватит тебя?'
345    }),
346    getShareText: () =>
347      `Если завтра пропадёт доход, меня хватит на ${fmt(days)} ${plural(days, 'день', 'дня', 'дней')} 🛟 Посчитай свой запас прочности →`,
348    related: [
349      { id: 'subscriptions', href: 'subscriptions-calculator.html', icon: '🧾',
350        title: 'Сколько съедают подписки', hook: 'Сумма за год вас удивит' },
351      { id: 'financial-freedom', href: 'financial-freedom.html', icon: '🏖️',
352        title: 'Дата финансовой свободы', hook: 'Когда сможете не работать — по правилу 4%' },
353      { id: 'earnings-counter', href: 'earnings-counter.html', icon: '⏱️',
354        title: 'Доход в реальном времени', hook: 'Сколько вы зарабатываете каждую секунду' }
355    ]
356  };
357
358  recalc();
359})();
360</script>
vendor: 1 bytes, line 360
360
361<script src="cta.js"></script>
361
362</body>
363</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.