<div id="lcc-calculator" class="lcc" data-cta-url="#financial-planner">
<div class="lcc__shell">
<header class="lcc__hero">
<p class="lcc__eyebrow">Калькулятор для мастера</p>
<h2 class="lcc__title">Рассчитай реальную себестоимость процедуры</h2>
<p class="lcc__lead">
Внеси стоимость упаковок и фактический расход материалов. Калькулятор учтёт ежемесячные расходы,
амортизацию, налоги и стоимость твоего времени.
</p>
</header>

<div class="lcc__layout">
<div class="lcc__form-column">
<section class="lcc__card" aria-labelledby="lcc-main-title">
<div class="lcc__section-heading">
<span class="lcc__step">01</span>
<div>
<h3 id="lcc-main-title">Процедура и нагрузка</h3>
<p>Эти данные нужны, чтобы распределить ежемесячные расходы на одного клиента.</p>
</div>
</div>

<div class="lcc__fields lcc__fields--3">
<label class="lcc__field">
<span>Цена процедуры</span>
<span class="lcc__input-wrap">
<input type="text" inputmode="decimal" autocomplete="off" placeholder="3000" data-base="price">
<b>₽</b>
</span>
</label>

<label class="lcc__field">
<span>Процедур в месяц</span>
<span class="lcc__input-wrap">
<input type="text" inputmode="numeric" autocomplete="off" placeholder="40" data-base="monthlyProcedures">
<b>шт.</b>
</span>
</label>

<label class="lcc__field">
<span>Длительность процедуры</span>
<span class="lcc__input-wrap">
<input type="text" inputmode="decimal" autocomplete="off" placeholder="120" data-base="durationMinutes">
<b>мин.</b>
</span>
</label>

<label class="lcc__field">
<span>Желаемая оплата часа</span>
<span class="lcc__input-wrap">
<input type="text" inputmode="decimal" autocomplete="off" placeholder="700" data-base="hourlyRate">
<b>₽</b>
</span>
<small>Нужна для полной себестоимости с учётом твоей работы.</small>
</label>

<label class="lcc__field">
<span>Налог с оплаты</span>
<span class="lcc__input-wrap">
<input type="text" inputmode="decimal" autocomplete="off" placeholder="4" data-base="taxRate">
<b>%</b>
</span>
</label>

<label class="lcc__field">
<span>Комиссия банка или сервиса</span>
<span class="lcc__input-wrap">
<input type="text" inputmode="decimal" autocomplete="off" placeholder="0" data-base="commissionRate">
<b>%</b>
</span>
</label>

<label class="lcc__field">
<span>Обязательные платежи в месяц</span>
<span class="lcc__input-wrap">
<input type="text" inputmode="decimal" autocomplete="off" placeholder="0" data-base="monthlyMandatoryPayments">
<b>₽</b>
</span>
<small>Например, фиксированные взносы. Если их нет — оставь поле пустым.</small>
</label>
</div>
</section>

<section class="lcc__card" aria-labelledby="lcc-materials-title">
<div class="lcc__section-heading">
<span class="lcc__step">02</span>
<div>
<h3 id="lcc-materials-title">Материалы</h3>
<p>Формула: цена упаковки ÷ количество в упаковке × расход на процедуру.</p>
</div>
</div>

<details class="lcc__guide">
<summary>Как заполнить точно</summary>
<div class="lcc__guide-content">
<p><b>Ресницы:</b> укажи цену палетки, количество линий и средний расход линий на одну процедуру.</p>
<p><b>Клей:</b> в графе «Количество в упаковке» укажи, на сколько процедур реально хватает открытого флакона, а расход поставь 1.</p>
<p><b>Жидкости:</b> выбери мл, внеси объём флакона и расход в мл. Одноразовые материалы считай в штуках или парах.</p>
<p><b>Списание:</b> добавь процент, если часть материала остаётся неиспользованной, портится или выбрасывается.</p>
</div>
</details>

<div class="lcc__rows" data-materials-list></div>

<button class="lcc__add-button" type="button" data-action="add-material">
<span aria-hidden="true">+</span> Добавить свой материал
</button>
</section>

<section class="lcc__card" aria-labelledby="lcc-monthly-title">
<div class="lcc__section-heading">
<span class="lcc__step">03</span>
<div>
<h3 id="lcc-monthly-title">Ежемесячные расходы</h3>
<p>Каждая сумма будет разделена на количество процедур в месяц.</p>
</div>
</div>

<div class="lcc__rows" data-monthly-list></div>

<button class="lcc__add-button" type="button" data-action="add-monthly">
<span aria-hidden="true">+</span> Добавить расход
</button>
</section>

<section class="lcc__card" aria-labelledby="lcc-equipment-title">
<div class="lcc__section-heading">
<span class="lcc__step">04</span>
<div>
<h3 id="lcc-equipment-title">Оборудование и инструменты</h3>
<p>Стоимость покупки распределяется на срок использования, затем — на процедуры.</p>
</div>
</div>

<div class="lcc__rows" data-equipment-list></div>

<button class="lcc__add-button" type="button" data-action="add-equipment">
<span aria-hidden="true">+</span> Добавить оборудование
</button>
</section>

<div class="lcc__actions">
<button class="lcc__primary-button" type="button" data-action="show-result">Показать расчёт</button>
<button class="lcc__text-button" type="button" data-action="reset">Очистить все поля</button>
</div>
</div>

<aside class="lcc__result-column" aria-live="polite">
<section class="lcc__result" id="lcc-result" aria-labelledby="lcc-result-title">
<p class="lcc__result-label">Твой расчёт</p>
<h3 id="lcc-result-title">Полная себестоимость</h3>
<div class="lcc__result-main" data-result="fullCost">0 ₽</div>
<p class="lcc__result-caption">Расходы на одну процедуру вместе с оплатой времени мастера</p>

<div class="lcc__donut-wrap">
<div class="lcc__donut" data-donut role="img" aria-label="Распределение себестоимости">
<div><b data-result="fullCostCompact">0 ₽</b><span>всего</span></div>
</div>
<div class="lcc__legend" data-breakdown></div>
</div>

<div class="lcc__summary">
<div class="lcc__summary-row">
<span>Материалы</span>
<b data-result="materials">0 ₽</b>
</div>
<div class="lcc__summary-row">
<span>Доля ежемесячных расходов</span>
<b data-result="monthlyShare">0 ₽</b>
</div>
<div class="lcc__summary-row">
<span>Амортизация</span>
<b data-result="depreciation">0 ₽</b>
</div>
<div class="lcc__summary-row">
<span>Налоги и комиссии</span>
<b data-result="taxes">0 ₽</b>
</div>
<div class="lcc__summary-row">
<span>Стоимость времени</span>
<b data-result="labor">0 ₽</b>
</div>
</div>

<div class="lcc__secondary-results">
<div>
<span>Расходы без оплаты времени</span>
<b data-result="operatingCost">0 ₽</b>
</div>
<div>
<span>Остаётся после расходов</span>
<b data-result="afterExpenses">0 ₽</b>
</div>
<div>
<span>Остаётся сверх оплаты времени</span>
<b data-result="profitAfterLabor">0 ₽</b>
</div>
<div>
<span>После расходов за месяц</span>
<b data-result="monthlyAfterExpenses">0 ₽</b>
</div>
</div>

<div class="lcc__status" data-status>
Заполни поля — результат обновится автоматически.
</div>

<button class="lcc__print-button" type="button" data-action="print">Сохранить расчёт в PDF</button>
<a class="lcc__cta" href="#financial-planner" data-cta>Перейти к финансовому планеру</a>
<p class="lcc__privacy">Данные остаются в браузере и никуда не отправляются.</p>
</section>
</aside>
</div>
</div>
</div>

<style>
#lcc-calculator {
--lcc-white: #ffffff;
--lcc-bg: #f6f7f8;
--lcc-card: #ffffff;
--lcc-graphite: #303238;
--lcc-muted: #737780;
--lcc-line: #e3e5e8;
--lcc-coral: #d98187;
--lcc-coral-dark: #bd676f;
--lcc-blush: #f4e3e5;
--lcc-pale: #edf0f2;
--lcc-positive: #557a68;
--lcc-negative: #a75059;
color: var(--lcc-graphite);
background: var(--lcc-bg);
font-family: inherit, Arial, sans-serif;
line-height: 1.4;
-webkit-font-smoothing: antialiased;
}

#lcc-calculator *,
#lcc-calculator *::before,
#lcc-calculator *::after {
box-sizing: border-box;
}

#lcc-calculator button,
#lcc-calculator input,
#lcc-calculator select {
font: inherit;
}

#lcc-calculator .lcc__shell {
width: min(1180px, calc(100% - 32px));
margin: 0 auto;
padding: 72px 0 80px;
}

#lcc-calculator .lcc__hero {
max-width: 780px;
margin-bottom: 34px;
}

#lcc-calculator .lcc__eyebrow,
#lcc-calculator .lcc__result-label {
margin: 0 0 10px;
color: var(--lcc-coral-dark);
font-size: 12px;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
}

#lcc-calculator .lcc__title {
margin: 0;
max-width: 760px;
font-size: clamp(32px, 5vw, 56px);
font-weight: 600;
line-height: 1.03;
letter-spacing: -0.045em;
}

#lcc-calculator .lcc__lead {
max-width: 680px;
margin: 20px 0 0;
color: var(--lcc-muted);
font-size: 17px;
line-height: 1.55;
}

#lcc-calculator .lcc__layout {
display: grid;
grid-template-columns: minmax(0, 1.65fr) minmax(330px, 0.85fr);
gap: 24px;
align-items: start;
}

#lcc-calculator .lcc__form-column {
display: grid;
gap: 18px;
}

#lcc-calculator .lcc__card,
#lcc-calculator .lcc__result {
border: 1px solid var(--lcc-line);
border-radius: 24px;
background: var(--lcc-card);
box-shadow: 0 12px 36px rgba(43, 45, 50, 0.045);
}

#lcc-calculator .lcc__card {
padding: 28px;
}

#lcc-calculator .lcc__section-heading {
display: flex;
gap: 15px;
align-items: flex-start;
margin-bottom: 24px;
}

#lcc-calculator .lcc__step {
display: inline-grid;
flex: 0 0 38px;
width: 38px;
height: 38px;
place-items: center;
border-radius: 50%;
background: var(--lcc-blush);
color: var(--lcc-coral-dark);
font-size: 12px;
font-weight: 700;
}

#lcc-calculator h3 {
margin: 0;
font-size: 22px;
font-weight: 600;
line-height: 1.2;
letter-spacing: -0.025em;
}

#lcc-calculator .lcc__section-heading p {
margin: 7px 0 0;
color: var(--lcc-muted);
font-size: 14px;
}

#lcc-calculator .lcc__fields {
display: grid;
gap: 16px;
}

#lcc-calculator .lcc__fields--3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}

#lcc-calculator .lcc__field {
display: grid;
gap: 7px;
align-content: start;
color: var(--lcc-graphite);
font-size: 13px;
font-weight: 600;
}

#lcc-calculator .lcc__field small {
color: var(--lcc-muted);
font-size: 11px;
font-weight: 400;
line-height: 1.35;
}

#lcc-calculator .lcc__input-wrap {
position: relative;
display: block;
}

#lcc-calculator .lcc__input-wrap input,
#lcc-calculator .lcc__input-wrap select,
#lcc-calculator .lcc__name-input {
width: 100%;
min-height: 46px;
border: 1px solid var(--lcc-line);
border-radius: 12px;
outline: none;
background: var(--lcc-white);
color: var(--lcc-graphite);
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

#lcc-calculator .lcc__input-wrap input {
padding: 11px 46px 11px 13px;
}

#lcc-calculator .lcc__input-wrap select {
padding: 11px 34px 11px 13px;
}

#lcc-calculator .lcc__name-input {
padding: 10px 12px;
font-weight: 600;
}

#lcc-calculator input:focus,
#lcc-calculator select:focus {
border-color: var(--lcc-coral);
box-shadow: 0 0 0 3px rgba(217, 129, 135, 0.14);
}

#lcc-calculator input::placeholder {
color: #a8abb1;
}

#lcc-calculator .lcc__input-wrap b {
position: absolute;
top: 50%;
right: 13px;
transform: translateY(-50%);
color: var(--lcc-muted);
font-size: 12px;
font-weight: 500;
pointer-events: none;
}

#lcc-calculator .lcc__guide {
margin: -5px 0 20px;
border: 1px solid #eadcdf;
border-radius: 14px;
background: #fbf5f6;
}

#lcc-calculator .lcc__guide summary {
padding: 14px 16px;
cursor: pointer;
color: var(--lcc-graphite);
font-size: 13px;
font-weight: 600;
}

#lcc-calculator .lcc__guide-content {
padding: 0 16px 14px;
color: var(--lcc-muted);
font-size: 13px;
}

#lcc-calculator .lcc__guide-content p {
margin: 8px 0 0;
}

#lcc-calculator .lcc__rows {
display: grid;
gap: 12px;
}

#lcc-calculator .lcc__row-card {
position: relative;
border: 1px solid var(--lcc-line);
border-radius: 16px;
background: #fcfcfd;
padding: 16px;
}

#lcc-calculator .lcc__row-card[data-row="monthly"],
#lcc-calculator .lcc__row-card[data-row="equipment"] {
padding-right: 54px;
}

#lcc-calculator .lcc__row-card--incomplete {
border-color: #d9989e;
box-shadow: 0 0 0 2px rgba(217, 129, 135, 0.08);
}

#lcc-calculator .lcc__row-top {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px;
align-items: center;
margin-bottom: 13px;
}

#lcc-calculator .lcc__remove {
display: grid;
width: 36px;
height: 36px;
place-items: center;
border: 0;
border-radius: 50%;
background: transparent;
color: #969aa1;
cursor: pointer;
font-size: 22px;
line-height: 1;
transition: color 0.2s ease, background 0.2s ease;
}

#lcc-calculator .lcc__remove:hover {
background: var(--lcc-blush);
color: var(--lcc-negative);
}

#lcc-calculator .lcc__material-grid {
display: grid;
grid-template-columns: 0.72fr 0.86fr 1fr 1fr 0.68fr auto;
gap: 10px;
align-items: end;
}

#lcc-calculator .lcc__monthly-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(150px, 0.48fr) auto;
gap: 10px;
align-items: end;
}

#lcc-calculator .lcc__equipment-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(130px, 0.5fr) minmax(130px, 0.5fr) auto;
gap: 10px;
align-items: end;
}

#lcc-calculator .lcc__row-result {
display: grid;
min-width: 112px;
min-height: 46px;
padding: 7px 11px;
place-content: center end;
border-radius: 12px;
background: var(--lcc-blush);
text-align: right;
}

#lcc-calculator .lcc__row-result span {
color: var(--lcc-muted);
font-size: 10px;
}

#lcc-calculator .lcc__row-result b {
color: var(--lcc-graphite);
font-size: 14px;
}

#lcc-calculator .lcc__add-button {
display: inline-flex;
gap: 8px;
align-items: center;
margin-top: 14px;
padding: 10px 0;
border: 0;
background: transparent;
color: var(--lcc-coral-dark);
cursor: pointer;
font-size: 13px;
font-weight: 600;
}

#lcc-calculator .lcc__add-button span {
display: grid;
width: 23px;
height: 23px;
place-items: center;
border-radius: 50%;
background: var(--lcc-blush);
font-size: 17px;
}

#lcc-calculator .lcc__actions {
display: flex;
gap: 18px;
align-items: center;
padding: 8px 2px 0;
}

#lcc-calculator .lcc__primary-button,
#lcc-calculator .lcc__cta,
#lcc-calculator .lcc__print-button {
display: inline-flex;
min-height: 50px;
align-items: center;
justify-content: center;
border-radius: 13px;
cursor: pointer;
font-weight: 600;
text-decoration: none;
transition: transform 0.2s ease, background 0.2s ease;
}

#lcc-calculator .lcc__primary-button,
#lcc-calculator .lcc__cta {
border: 1px solid var(--lcc-coral);
background: var(--lcc-coral);
color: #fff;
}

#lcc-calculator .lcc__primary-button {
padding: 0 24px;
}

#lcc-calculator .lcc__primary-button:hover,
#lcc-calculator .lcc__cta:hover {
background: var(--lcc-coral-dark);
transform: translateY(-1px);
}

#lcc-calculator .lcc__text-button {
border: 0;
border-bottom: 1px solid #c5c8cd;
background: transparent;
color: var(--lcc-muted);
cursor: pointer;
font-size: 12px;
}

#lcc-calculator .lcc__result-column {
position: sticky;
top: 24px;
}

#lcc-calculator .lcc__result {
padding: 28px;
overflow: hidden;
}

#lcc-calculator .lcc__result-main {
margin-top: 13px;
color: var(--lcc-graphite);
font-size: clamp(38px, 5vw, 52px);
font-weight: 650;
line-height: 1;
letter-spacing: -0.05em;
}

#lcc-calculator .lcc__result-caption {
margin: 10px 0 24px;
color: var(--lcc-muted);
font-size: 12px;
line-height: 1.45;
}

#lcc-calculator .lcc__donut-wrap {
display: grid;
grid-template-columns: 124px minmax(0, 1fr);
gap: 18px;
align-items: center;
margin-bottom: 24px;
padding: 18px;
border-radius: 18px;
background: var(--lcc-bg);
}

#lcc-calculator .lcc__donut {
position: relative;
display: grid;
width: 124px;
height: 124px;
place-items: center;
border-radius: 50%;
background: var(--lcc-pale);
}

#lcc-calculator .lcc__donut::after {
position: absolute;
width: 76px;
height: 76px;
border-radius: 50%;
background: var(--lcc-white);
content: "";
}

#lcc-calculator .lcc__donut > div {
position: relative;
z-index: 1;
display: grid;
text-align: center;
}

#lcc-calculator .lcc__donut b {
font-size: 14px;
}

#lcc-calculator .lcc__donut span {
color: var(--lcc-muted);
font-size: 10px;
}

#lcc-calculator .lcc__legend {
display: grid;
gap: 7px;
}

#lcc-calculator .lcc__legend-row {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 7px;
align-items: center;
color: var(--lcc-muted);
font-size: 10px;
}

#lcc-calculator .lcc__legend-dot {
width: 8px;
height: 8px;
border-radius: 50%;
}

#lcc-calculator .lcc__legend-row b {
color: var(--lcc-graphite);
font-size: 10px;
}

#lcc-calculator .lcc__summary {
display: grid;
gap: 0;
border-top: 1px solid var(--lcc-line);
border-bottom: 1px solid var(--lcc-line);
}

#lcc-calculator .lcc__summary-row {
display: flex;
gap: 16px;
align-items: center;
justify-content: space-between;
padding: 11px 0;
color: var(--lcc-muted);
font-size: 12px;
}

#lcc-calculator .lcc__summary-row + .lcc__summary-row {
border-top: 1px solid #f0f1f2;
}

#lcc-calculator .lcc__summary-row b {
color: var(--lcc-graphite);
white-space: nowrap;
}

#lcc-calculator .lcc__secondary-results {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 9px;
margin-top: 16px;
}

#lcc-calculator .lcc__secondary-results > div {
display: grid;
gap: 7px;
align-content: space-between;
min-height: 84px;
padding: 13px;
border-radius: 13px;
background: var(--lcc-bg);
}

#lcc-calculator .lcc__secondary-results span {
color: var(--lcc-muted);
font-size: 10px;
line-height: 1.3;
}

#lcc-calculator .lcc__secondary-results b {
font-size: 16px;
}

#lcc-calculator .lcc__status {
margin-top: 16px;
padding: 13px 14px;
border-radius: 12px;
background: var(--lcc-blush);
color: var(--lcc-graphite);
font-size: 11px;
line-height: 1.45;
}

#lcc-calculator .lcc__status--positive {
background: #e9f1ed;
color: var(--lcc-positive);
}

#lcc-calculator .lcc__status--negative {
background: #f7e8ea;
color: var(--lcc-negative);
}

#lcc-calculator .lcc__print-button,
#lcc-calculator .lcc__cta {
width: 100%;
margin-top: 11px;
}

#lcc-calculator .lcc__print-button {
border: 1px solid var(--lcc-line);
background: var(--lcc-white);
color: var(--lcc-graphite);
}

#lcc-calculator .lcc__print-button:hover {
background: var(--lcc-bg);
}

#lcc-calculator .lcc__privacy {
margin: 12px 0 0;
color: #9a9da3;
font-size: 9px;
text-align: center;
}

@media (max-width: 1040px) {
#lcc-calculator .lcc__layout {
grid-template-columns: 1fr;
}

#lcc-calculator .lcc__result-column {
position: static;
}

#lcc-calculator .lcc__result {
max-width: none;
}
}

@media (max-width: 760px) {
#lcc-calculator .lcc__shell {
width: min(100% - 20px, 620px);
padding: 44px 0 54px;
}

#lcc-calculator .lcc__hero {
margin-bottom: 24px;
}

#lcc-calculator .lcc__lead {
font-size: 15px;
}

#lcc-calculator .lcc__card,
#lcc-calculator .lcc__result {
border-radius: 19px;
}

#lcc-calculator .lcc__card,
#lcc-calculator .lcc__result {
padding: 19px;
}

#lcc-calculator .lcc__fields--3,
#lcc-calculator .lcc__material-grid,
#lcc-calculator .lcc__equipment-grid,
#lcc-calculator .lcc__monthly-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}

#lcc-calculator .lcc__material-grid .lcc__row-result,
#lcc-calculator .lcc__equipment-grid .lcc__row-result,
#lcc-calculator .lcc__monthly-grid .lcc__row-result {
grid-column: 1 / -1;
justify-content: start;
place-content: center start;
text-align: left;
}

#lcc-calculator .lcc__donut-wrap {
grid-template-columns: 112px minmax(0, 1fr);
padding: 14px;
}

#lcc-calculator .lcc__donut {
width: 112px;
height: 112px;
}
}

@media (max-width: 460px) {
#lcc-calculator .lcc__fields--3,
#lcc-calculator .lcc__material-grid,
#lcc-calculator .lcc__equipment-grid,
#lcc-calculator .lcc__monthly-grid {
grid-template-columns: 1fr;
}

#lcc-calculator .lcc__actions {
align-items: stretch;
flex-direction: column;
}

#lcc-calculator .lcc__text-button {
align-self: center;
}

#lcc-calculator .lcc__donut-wrap {
grid-template-columns: 1fr;
justify-items: center;
}

#lcc-calculator .lcc__legend {
width: 100%;
}

#lcc-calculator .lcc__secondary-results {
grid-template-columns: 1fr;
}
}

@media print {
body * {
visibility: hidden !important;
}

#lcc-calculator,
#lcc-calculator * {
visibility: visible !important;
}

#lcc-calculator {
position: absolute;
inset: 0;
background: #fff;
}

#lcc-calculator .lcc__shell {
width: 100%;
padding: 0;
}

#lcc-calculator .lcc__hero,
#lcc-calculator .lcc__form-column,
#lcc-calculator .lcc__print-button,
#lcc-calculator .lcc__cta,
#lcc-calculator .lcc__privacy {
display: none !important;
}

#lcc-calculator .lcc__layout {
display: block;
}

#lcc-calculator .lcc__result-column {
position: static;
}

#lcc-calculator .lcc__result {
border: 0;
box-shadow: none;
}
}
</style>

<script>
(function () {
'use strict';

var root = document.getElementById('lcc-calculator');
if (!root || root.getAttribute('data-initialized') === 'true') return;
root.setAttribute('data-initialized', 'true');

var STORAGE_KEY = 'lcc-cost-calculator-v1';
var VERSION = 1;
var colors = ['#d98187', '#6f747c', '#aeb4bb', '#efb7bc', '#8e7680'];

var units = [
{ value: 'lines', label: 'линии' },
{ value: 'procedures', label: 'процедуры' },
{ value: 'pairs', label: 'пары' },
{ value: 'pieces', label: 'штуки' },
{ value: 'ml', label: 'мл' },
{ value: 'g', label: 'граммы' },
{ value: 'cm', label: 'см' },
{ value: 'm', label: 'метры' },
{ value: 'sets', label: 'комплекты' }
];

function makeId(prefix) {
return prefix + '-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 8);
}

function defaultState() {
return {
version: VERSION,
base: {
price: '',
monthlyProcedures: '',
durationMinutes: '',
hourlyRate: '',
taxRate: '',
commissionRate: '',
monthlyMandatoryPayments: ''
},
materials: [
{ id: makeId('mat'), name: 'Ресницы', unit: 'lines', price: '', packQty: '', usage: '', waste: '' },
{ id: makeId('mat'), name: 'Клей', unit: 'procedures', price: '', packQty: '', usage: '1', waste: '' },
{ id: makeId('mat'), name: 'Патчи', unit: 'pairs', price: '', packQty: '', usage: '1', waste: '' },
{ id: makeId('mat'), name: 'Лента или скотч', unit: 'cm', price: '', packQty: '', usage: '', waste: '' },
{ id: makeId('mat'), name: 'Обезжириватель', unit: 'ml', price: '', packQty: '', usage: '', waste: '' },
{ id: makeId('mat'), name: 'Праймер или бустер', unit: 'ml', price: '', packQty: '', usage: '', waste: '' },
{ id: makeId('mat'), name: 'Шампунь или пенка', unit: 'ml', price: '', packQty: '', usage: '', waste: '' },
{ id: makeId('mat'), name: 'Микробраши', unit: 'pieces', price: '', packQty: '', usage: '', waste: '' },
{ id: makeId('mat'), name: 'Щёточки', unit: 'pieces', price: '', packQty: '', usage: '1', waste: '' }
],
monthly: [
{ id: makeId('monthly'), name: 'Аренда', amount: '' },
{ id: makeId('monthly'), name: 'Коммунальные платежи и уборка', amount: '' },
{ id: makeId('monthly'), name: 'CRM, связь и онлайн-сервисы', amount: '' },
{ id: makeId('monthly'), name: 'Реклама и продвижение', amount: '' }
],
equipment: [
{ id: makeId('eq'), name: 'Кушетка или кресло', price: '', months: '36' },
{ id: makeId('eq'), name: 'Лампа', price: '', months: '36' },
{ id: makeId('eq'), name: 'Стул мастера', price: '', months: '36' },
{ id: makeId('eq'), name: 'Пинцеты и инструменты', price: '', months: '36' }
]
};
}

function clone(value) {
return JSON.parse(JSON.stringify(value));
}

function loadState() {
try {
var saved = JSON.parse(localStorage.getItem(STORAGE_KEY));
if (saved && saved.version === VERSION && saved.base && Array.isArray(saved.materials)) {
return saved;
}
} catch (error) {}
return defaultState();
}

function saveState() {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
} catch (error) {}
}

function escapeHtml(value) {
return String(value == null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}

function number(value) {
var prepared = String(value == null ? '' : value)
.replace(/\s/g, '')
.replace(',', '.')
.replace(/[^0-9.-]/g, '');
var result = parseFloat(prepared);
return Number.isFinite(result) && result > 0 ? result : 0;
}

function percentage(value) {
return Math.min(100, number(value));
}

function money(value) {
var safeValue = Number.isFinite(value) ? value : 0;
return new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB',
minimumFractionDigits: 0,
maximumFractionDigits: 2
}).format(safeValue);
}

function compactMoney(value) {
var safeValue = Number.isFinite(value) ? value : 0;
if (Math.abs(safeValue) >= 1000000) return (safeValue / 1000000).toFixed(1).replace('.', ',') + ' млн ₽';
if (Math.abs(safeValue) >= 10000) return Math.round(safeValue / 1000) + ' тыс. ₽';
return money(safeValue);
}

function unitOptions(selected) {
return units.map(function (unit) {
return '<option value="' + unit.value + '"' + (unit.value === selected ? ' selected' : '') + '>' + unit.label + '</option>';
}).join('');
}

function materialCost(item) {
var packQty = number(item.packQty);
if (!packQty) return 0;
var baseCost = number(item.price) / packQty * number(item.usage);
return baseCost * (1 + percentage(item.waste) / 100);
}

function renderMaterials() {
var list = root.querySelector('[data-materials-list]');
list.innerHTML = state.materials.map(function (item) {
return '' +
'<article class="lcc__row-card" data-row="materials" data-id="' + escapeHtml(item.id) + '">' +
'<div class="lcc__row-top">' +
'<input class="lcc__name-input" type="text" aria-label="Название материала" value="' + escapeHtml(item.name) + '" data-collection="materials" data-key="name">' +
'<button class="lcc__remove" type="button" title="Удалить материал" aria-label="Удалить материал" data-action="remove-material">×</button>' +
'</div>' +
'<div class="lcc__material-grid">' +
'<label class="lcc__field"><span>Единица расчёта</span><span class="lcc__input-wrap"><select data-collection="materials" data-key="unit">' + unitOptions(item.unit) + '</select></span></label>' +
'<label class="lcc__field"><span>Цена упаковки</span><span class="lcc__input-wrap"><input type="text" inputmode="decimal" placeholder="0" value="' + escapeHtml(item.price) + '" data-collection="materials" data-key="price"><b>₽</b></span></label>' +
'<label class="lcc__field"><span>Количество в упаковке</span><span class="lcc__input-wrap"><input type="text" inputmode="decimal" placeholder="0" value="' + escapeHtml(item.packQty) + '" data-collection="materials" data-key="packQty"></span></label>' +
'<label class="lcc__field"><span>Расход на процедуру</span><span class="lcc__input-wrap"><input type="text" inputmode="decimal" placeholder="0" value="' + escapeHtml(item.usage) + '" data-collection="materials" data-key="usage"></span></label>' +
'<label class="lcc__field"><span>Списание</span><span class="lcc__input-wrap"><input type="text" inputmode="decimal" placeholder="0" value="' + escapeHtml(item.waste) + '" data-collection="materials" data-key="waste"><b>%</b></span></label>' +
'<div class="lcc__row-result"><span>на процедуру</span><b data-row-cost>' + money(materialCost(item)) + '</b></div>' +
'</div>' +
'</article>';
}).join('');
}

function renderMonthly() {
var clients = number(state.base.monthlyProcedures);
var list = root.querySelector('[data-monthly-list]');
list.innerHTML = state.monthly.map(function (item) {
var perProcedure = clients ? number(item.amount) / clients : 0;
return '' +
'<article class="lcc__row-card" data-row="monthly" data-id="' + escapeHtml(item.id) + '">' +
'<div class="lcc__monthly-grid">' +
'<label class="lcc__field"><span>Статья расходов</span><input class="lcc__name-input" type="text" value="' + escapeHtml(item.name) + '" data-collection="monthly" data-key="name"></label>' +
'<label class="lcc__field"><span>Сумма в месяц</span><span class="lcc__input-wrap"><input type="text" inputmode="decimal" placeholder="0" value="' + escapeHtml(item.amount) + '" data-collection="monthly" data-key="amount"><b>₽</b></span></label>' +
'<div class="lcc__row-result"><span>на процедуру</span><b data-row-cost>' + money(perProcedure) + '</b></div>' +
'</div>' +
'<button class="lcc__remove" type="button" title="Удалить расход" aria-label="Удалить расход" data-action="remove-monthly" style="position:absolute;right:8px;top:8px">×</button>' +
'</article>';
}).join('');
}

function renderEquipment() {
var clients = number(state.base.monthlyProcedures);
var list = root.querySelector('[data-equipment-list]');
list.innerHTML = state.equipment.map(function (item) {
var months = number(item.months);
var perProcedure = clients && months ? number(item.price) / months / clients : 0;
return '' +
'<article class="lcc__row-card" data-row="equipment" data-id="' + escapeHtml(item.id) + '">' +
'<div class="lcc__equipment-grid">' +
'<label class="lcc__field"><span>Оборудование</span><input class="lcc__name-input" type="text" value="' + escapeHtml(item.name) + '" data-collection="equipment" data-key="name"></label>' +
'<label class="lcc__field"><span>Стоимость</span><span class="lcc__input-wrap"><input type="text" inputmode="decimal" placeholder="0" value="' + escapeHtml(item.price) + '" data-collection="equipment" data-key="price"><b>₽</b></span></label>' +
'<label class="lcc__field"><span>Срок использования</span><span class="lcc__input-wrap"><input type="text" inputmode="numeric" placeholder="36" value="' + escapeHtml(item.months) + '" data-collection="equipment" data-key="months"><b>мес.</b></span></label>' +
'<div class="lcc__row-result"><span>на процедуру</span><b data-row-cost>' + money(perProcedure) + '</b></div>' +
'</div>' +
'<button class="lcc__remove" type="button" title="Удалить оборудование" aria-label="Удалить оборудование" data-action="remove-equipment" style="position:absolute;right:8px;top:8px">×</button>' +
'</article>';
}).join('');
}

function syncBaseInputs() {
Object.keys(state.base).forEach(function (key) {
var input = root.querySelector('[data-base="' + key + '"]');
if (input) input.value = state.base[key];
});
}

function setResult(name, value, compact) {
var nodes = root.querySelectorAll('[data-result="' + name + '"]');
nodes.forEach(function (node) {
node.textContent = compact ? compactMoney(value) : money(value);
node.style.color = value < 0 ? 'var(--lcc-negative)' : '';
});
}

function updateRowCosts() {
var clients = number(state.base.monthlyProcedures);

root.querySelectorAll('[data-row="materials"]').forEach(function (row) {
var item = state.materials.find(function (entry) { return entry.id === row.getAttribute('data-id'); });
if (item) {
var started = number(item.price) > 0 || number(item.packQty) > 0;
var incomplete = started && (!number(item.price) || !number(item.packQty) || !number(item.usage));
row.classList.remove('lcc__row-card--incomplete');
if (incomplete) row.classList.add('lcc__row-card--incomplete');
row.querySelector('[data-row-cost]').textContent = money(materialCost(item));
}
});

root.querySelectorAll('[data-row="monthly"]').forEach(function (row) {
var item = state.monthly.find(function (entry) { return entry.id === row.getAttribute('data-id'); });
if (item) row.querySelector('[data-row-cost]').textContent = money(clients ? number(item.amount) / clients : 0);
});

root.querySelectorAll('[data-row="equipment"]').forEach(function (row) {
var item = state.equipment.find(function (entry) { return entry.id === row.getAttribute('data-id'); });
var months = item ? number(item.months) : 0;
if (item) row.querySelector('[data-row-cost]').textContent = money(clients && months ? number(item.price) / months / clients : 0);
});
}

function renderDonut(parts, total) {
var donut = root.querySelector('[data-donut]');
var legend = root.querySelector('[data-breakdown]');

if (!total) {
donut.style.background = 'var(--lcc-pale)';
donut.setAttribute('aria-label', 'Распределение себестоимости пока не рассчитано');
} else {
var cursor = 0;
var stops = parts.map(function (part, index) {
var start = cursor;
cursor += part.value / total * 100;
return colors[index] + ' ' + start.toFixed(2) + '% ' + cursor.toFixed(2) + '%';
});
donut.style.background = 'conic-gradient(' + stops.join(',') + ')';
donut.setAttribute('aria-label', parts.map(function (part) {
return part.label + ': ' + Math.round(part.value / total * 100) + '%';
}).join(', '));
}

legend.innerHTML = parts.map(function (part, index) {
var share = total ? Math.round(part.value / total * 100) : 0;
return '<div class="lcc__legend-row"><i class="lcc__legend-dot" style="background:' + colors[index] + '"></i><span>' + part.shortLabel + '</span><b>' + share + '%</b></div>';
}).join('');
}

function calculate() {
var price = number(state.base.price);
var clients = number(state.base.monthlyProcedures);
var durationHours = number(state.base.durationMinutes) / 60;

var materials = state.materials.reduce(function (sum, item) {
return sum + materialCost(item);
}, 0);

var monthlyTotal = state.monthly.reduce(function (sum, item) {
return sum + number(item.amount);
}, 0);
var monthlyShare = clients ? monthlyTotal / clients : 0;

var equipmentMonthly = state.equipment.reduce(function (sum, item) {
var months = number(item.months);
return sum + (months ? number(item.price) / months : 0);
}, 0);
var depreciation = clients ? equipmentMonthly / clients : 0;

var percentageCharges = price * (percentage(state.base.taxRate) + percentage(state.base.commissionRate)) / 100;
var mandatoryShare = clients ? number(state.base.monthlyMandatoryPayments) / clients : 0;
var taxes = percentageCharges + mandatoryShare;
var labor = durationHours * number(state.base.hourlyRate);
var operatingCost = materials + monthlyShare + depreciation + taxes;
var fullCost = operatingCost + labor;
var afterExpenses = price ? price - operatingCost : 0;
var profitAfterLabor = price ? price - fullCost : 0;
var monthlyAfterExpenses = afterExpenses * clients;
var incompleteMaterials = state.materials.filter(function (item) {
var started = number(item.price) > 0 || number(item.packQty) > 0;
return started && (!number(item.price) || !number(item.packQty) || !number(item.usage));
}).length;
var incompleteLabor = (number(state.base.durationMinutes) > 0 || number(state.base.hourlyRate) > 0) &&
(!number(state.base.durationMinutes) || !number(state.base.hourlyRate));

setResult('materials', materials);
setResult('monthlyShare', monthlyShare);
setResult('depreciation', depreciation);
setResult('taxes', taxes);
setResult('labor', labor);
setResult('operatingCost', operatingCost);
setResult('fullCost', fullCost);
setResult('fullCostCompact', fullCost, true);
setResult('afterExpenses', afterExpenses);
setResult('profitAfterLabor', profitAfterLabor);
setResult('monthlyAfterExpenses', monthlyAfterExpenses);

updateRowCosts();
renderDonut([
{ label: 'Материалы', shortLabel: 'Материалы', value: materials },
{ label: 'Ежемесячные расходы', shortLabel: 'Расходы', value: monthlyShare },
{ label: 'Амортизация', shortLabel: 'Амортизация', value: depreciation },
{ label: 'Налоги и комиссии', shortLabel: 'Налоги', value: taxes },
{ label: 'Время мастера', shortLabel: 'Время', value: labor }
], fullCost);

var status = root.querySelector('[data-status]');
status.classList.remove('lcc__status--positive', 'lcc__status--negative');

if (!clients && (monthlyTotal || equipmentMonthly || number(state.base.monthlyMandatoryPayments))) {
status.textContent = 'Укажи количество процедур в месяц — без него нельзя распределить ежемесячные расходы и амортизацию.';
} else if (incompleteMaterials) {
status.textContent = 'Проверь материалы: в ' + incompleteMaterials + ' поз. не заполнены цена, количество в упаковке или расход на процедуру.';
} else if (incompleteLabor) {
status.textContent = 'Чтобы учесть стоимость времени, заполни и длительность процедуры, и желаемую оплату часа.';
} else if (!fullCost && !price) {
status.textContent = 'Заполни поля — результат обновится автоматически.';
} else if (!price) {
status.textContent = 'Себестоимость рассчитана. Укажи цену процедуры, чтобы увидеть, сколько остаётся после расходов.';
} else if (profitAfterLabor >= 0) {
status.classList.add('lcc__status--positive');
status.textContent = 'Цена покрывает полную себестоимость. Сверх расходов и выбранной оплаты времени остаётся ' + money(profitAfterLabor) + ' с процедуры.';
} else {
status.classList.add('lcc__status--negative');
status.textContent = 'Цена ниже полной себестоимости на ' + money(Math.abs(profitAfterLabor)) + '. Эта часть расходов или рабочего времени сейчас не оплачивается.';
}

saveState();
}

function findItem(collection, id) {
return state[collection].find(function (item) { return item.id === id; });
}

function handleField(event) {
var target = event.target;
var baseKey = target.getAttribute('data-base');
if (baseKey) {
state.base[baseKey] = target.value;
calculate();
return;
}

var collection = target.getAttribute('data-collection');
var key = target.getAttribute('data-key');
if (!collection || !key) return;

var row = target.closest('[data-row]');
if (!row) return;
var item = findItem(collection, row.getAttribute('data-id'));
if (!item) return;
item[key] = target.value;
calculate();
}

function focusNewest(collection) {
window.requestAnimationFrame(function () {
var rows = root.querySelectorAll('[data-row="' + collection + '"]');
var newest = rows[rows.length - 1];
if (newest) newest.querySelector('.lcc__name-input').focus();
});
}

function handleAction(event) {
var button = event.target.closest('[data-action]');
if (!button || !root.contains(button)) return;
var action = button.getAttribute('data-action');
var row = button.closest('[data-row]');

if (action === 'add-material') {
state.materials.push({ id: makeId('mat'), name: 'Новый материал', unit: 'pieces', price: '', packQty: '', usage: '', waste: '' });
renderMaterials();
calculate();
focusNewest('materials');
}

if (action === 'add-monthly') {
state.monthly.push({ id: makeId('monthly'), name: 'Новый расход', amount: '' });
renderMonthly();
calculate();
focusNewest('monthly');
}

if (action === 'add-equipment') {
state.equipment.push({ id: makeId('eq'), name: 'Новое оборудование', price: '', months: '36' });
renderEquipment();
calculate();
focusNewest('equipment');
}

if (action === 'remove-material' && row) {
state.materials = state.materials.filter(function (item) { return item.id !== row.getAttribute('data-id'); });
renderMaterials();
calculate();
}

if (action === 'remove-monthly' && row) {
state.monthly = state.monthly.filter(function (item) { return item.id !== row.getAttribute('data-id'); });
renderMonthly();
calculate();
}

if (action === 'remove-equipment' && row) {
state.equipment = state.equipment.filter(function (item) { return item.id !== row.getAttribute('data-id'); });
renderEquipment();
calculate();
}

if (action === 'show-result') {
calculate();
root.querySelector('#lcc-result').scrollIntoView({ behavior: 'smooth', block: 'start' });
}

if (action === 'print') {
window.print();
}

if (action === 'reset') {
if (window.confirm('Очистить все введённые данные?')) {
state = defaultState();
try { localStorage.removeItem(STORAGE_KEY); } catch (error) {}
syncBaseInputs();
renderMaterials();
renderMonthly();
renderEquipment();
calculate();
}
}
}

var state = loadState();
var cta = root.querySelector('[data-cta]');
var ctaUrl = root.getAttribute('data-cta-url');
if (ctaUrl) cta.setAttribute('href', ctaUrl);

syncBaseInputs();
renderMaterials();
renderMonthly();
renderEquipment();
calculate();

root.addEventListener('input', handleField);
root.addEventListener('change', handleField);
root.addEventListener('click', handleAction);
})();
</script>