To jest placeholder.
Przejdź do trybu Podglądu lub opublikuj stronę,
aby sprawdzić działanie swojego kodu.
Kliknij dwa razy, aby edytować
<div class="calculator-wrapper">
<html lang="pl">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Rozlicz swoje IT: Etat czy outsourcing? | KALKULATOR ROI OD ENGAVE</title>
<!-- Import czcionki Google (Open Sans) -->
<link
href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;700&display=swap"
rel="stylesheet"
/>
<!-- Główne style (CSS) -->
<style>
:root {
--engv-yellow: #FCCE0B;
--engv-white: #FFFFFF;
--engv-gray: #383838;
--engv-light-gray: #f9f9f9;
--box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
/* Stylizacja tabeli wyników */
.results-table {
width: 100%;
border-collapse: separate;
border-spacing: 0 10px; /* Odstępy między wierszami */
margin-top: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Delikatny cień */
border-radius: 8px; /* Zaokrąglenie krawędzi */
overflow: hidden;
}
/* Stylizacja nagłówków tabeli */
.results-table th {
background-color: var(--engv-yellow); /* Żółte tło */
color: var(--engv-gray); /* Szary tekst */
font-weight: 700; /* Pogrubienie */
padding: 15px;
text-align: center;
border-bottom: 2px solid var(--engv-gray); /* Dolna krawędź */
}
/* Stylizacja komórek tabeli */
.results-table th, .results-table td {
padding: 20px 15px;
text-align: center;
border-right: 1px solid #f1f1f1; /* Prawa krawędź */
}
.results-table th:last-child,
.results-table td:last-child {
border-right: none; /* Brak prawej krawędzi dla ostatniej kolumny */
}
/* Stylizacja wierszy tabeli */
.results-table tbody tr {
background-color: var(--engv-light-gray); /* Jasnoszare tło */
transition: background-color 0.3s ease;
}
.results-table tbody tr:hover {
background-color: rgba(252, 206, 11, 0.05); /* Subtelny żółty odcień przy hover */
}
/* Stylizacja komórek z wartościami */
.results-table .cost-value {
font-size: 1em;
color: var(--engv-gray);
}
/* Podkreślenie i kolorowanie kluczowych wyników */
.results-table .cost-value#difference-monthly,
.results-table .cost-value#difference-annual,
.results-table .cost-value#roi {
color: var(--engv-grey); /* Żółty kolor tekstu */
font-weight: 600; /* Pogrubienie */
background-color: rgba(252, 206, 11, 0.1); /* Lekki żółty tło */
padding: 10px;
border-radius: 4px; /* Zaokrąglenie */
}
/* Dodanie ikony przed wartościami oszczędności i ROI */
.results-table .cost-value#difference-monthly::before,
.results-table .cost-value#difference-annual::before,
.results-table .cost-value#roi::before {
content: '➤ '; /* Strzałka przed wartością */
color: var(--engv-yellow);
}
/* Responsywność dla tabeli wyników */
@media screen and (max-width: 768px) {
.results-table th, .results-table td {
padding: 10px 8px;
font-size: 0.9em;
}
.results-table .cost-value#difference-monthly,
.results-table .cost-value#difference-annual,
.results-table .cost-value#roi {
font-size: 1em;
padding: 8px;
}
.results-table th {
font-size: 0.95em;
}
}
@media screen and (max-width: 768px) {
.calculator-wrapper::-webkit-scrollbar {
width: 12px; /* Większy pasek na mobilnych */
}
.calculator-wrapper::-webkit-scrollbar-thumb {
background: var(--engv-gray); /* Ciemniejszy pasek na mobilnych */
}
}
/* Stylizacja tabeli kosztów ukrytych */
.hidden-costs-table {
width: 100%;
border-collapse: separate;
border-spacing: 0 10px; /* Odstępy między wierszami */
margin-top: 20px;
box-shadow: var(--box-shadow); /* Delikatny cień */
border-radius: 8px; /* Zaokrąglenie krawędzi */
overflow: hidden;
}
/* Nagłówki tabeli */
.hidden-costs-table th {
background-color: var(--engv-gray); /* Szare tło */
color: var(--engv-white); /* Biały tekst */
font-weight: 700;
padding: 15px;
text-align: center;
border-bottom: 2px solid var(--engv-yellow); /* Żółta dolna krawędź */
}
/* Komórki tabeli */
.hidden-costs-table th, .hidden-costs-table td {
padding: 15px;
text-align: center;
border-right: 1px solid #e0e0e0; /* Jasnoszara krawędź */
}
.hidden-costs-table th:last-child,
.hidden-costs-table td:last-child {
border-right: none;
}
/* Wiersze tabeli */
.hidden-costs-table tbody tr {
background-color: var(--engv-light-gray); /* Jasnoszare tło */
transition: background-color 0.3s ease;
}
.hidden-costs-table tbody tr:hover {
background-color: rgba(252, 206, 11, 0.05); /* Subtelny żółty odcień */
}
/* Wyróżnione wartości */
.hidden-costs-table .cost-highlight {
font-weight: 700;
color: var(--engv-yellow); /* Żółty kolor */
}
/* Łączny koszt podsumowania */
.hidden-costs-table .cost-summary {
font-size: 1.1em;
font-weight: 700;
background-color: rgba(252, 206, 11, 0.1); /* Jasne żółte tło */
padding: 10px;
border-radius: 4px;
text-align: center;
}
/* Responsywność dla tabeli kosztów ukrytych */
@media screen and (max-width: 768px) {
.hidden-costs-table th, .hidden-costs-table td {
padding: 10px 8px;
font-size: 0.9em;
}
.hidden-costs-table .cost-summary {
font-size: 1em;
padding: 8px;
}
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Open Sans', sans-serif;
line-height: 1.6;
color: var(--engv-gray);
background-color: var(--engv-white);
position: relative;
overflow-x: hidden;
}
body::before {
content: '';
position: fixed;
top: 0;
right: -50%;
width: 100%;
height: 100%;
background: linear-gradient(
135deg,
transparent 50%,
rgba(252, 206, 11, 0.1) 50%
);
z-index: -1;
transform: skewX(-20deg);
}
.logo svg {
height: 40px;
}
h1 {
font-size: 2.1em;
font-weight: 700;
margin-bottom: 30px;
position: relative;
color: var(--engv-gray);
text-align: center;
}
h1::after {
display: none; /* Usuwa całkowicie linię */
}
h2 {
font-size: 1.2em;
font-weight: 600;
margin-bottom: 20px;
color: var(--engv-gray);
}
.section::after {
content: '';
position: absolute;
bottom: 0;
right: 0;
width: 50px;
height: 50px;
background: var(--engv-yellow);
clip-path: polygon(100% 0, 100% 100%, 0 100%);
opacity: 0.5;
}
label {
display: block;
margin-bottom: 10px;
font-weight: 600;
color: var(--engv-gray);
}
input,
select {
width: 100%;
padding: 12px;
margin-bottom: 20px;
border: 2px solid #ddd;
border-radius: 4px;
font-family: 'Open Sans', sans-serif;
font-size: 1em;
transition: all 0.3s ease;
}
input:focus,
select:focus {
border-color: var(--engv-yellow);
outline: none;
box-shadow: 0 0 0 3px rgba(252,206,11,0.2);
}
/* Stylizacja przycisków */
button {
display: inline-block; /* Ustawia szerokość na podstawie zawartości */
max-width: 300px; /* Maksymalna szerokość przycisków */
width: 100%; /* Przycisk dostosowuje się do rodzica, ale nie przekracza max-width */
margin: 0 auto; /* Wyśrodkowanie przycisku */
padding: 12px 24px; /* Odstępy wewnętrzne */
background-color: var(--engv-yellow); /* Żółte tło */
color: var(--engv-gray); /* Szary tekst */
border: none;
border-radius: 25px; /* Zaokrąglone rogi */
font-weight: 600;
font-size: 1em; /* Rozmiar czcionki */
text-transform: uppercase;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Cień */
}
button:hover {
background-color: var(--engv-gray); /* Szare tło po najechaniu */
color: var(--engv-yellow); /* Żółty tekst po najechaniu */
transform: translateY(-2px); /* Subtelny efekt unoszenia */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); /* Większy cień */
}
/* Wyśrodkowanie kontenera przycisków */
.buttons-row {
display: flex;
justify-content: center; /* Wyśrodkowanie przycisków w rzędzie */
gap: 10px; /* Odstęp między przyciskami */
margin-top: 20px;
flex-wrap: wrap; /* Przycisk może zawijać się w małych widokach */
}
/* Dostosowanie również dla przycisku CTA */
.cta-button {
display: inline-block;
margin-top: 15px;
padding: 10px 20px;
background-color: var(--engv-gray);
color: var(--engv-yellow);
font-weight: 600;
border-radius: 25px;
text-decoration: none;
transition: all 0.3s ease;
font-size: 0.9em;
}
.cta-button:hover {
background-color: var(--engv-yellow);
color: var(--engv-gray);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.buttons-row {
display: flex;
gap: 10px;
margin-top: 20px;
flex-wrap: wrap;
justify-content: center;
}
.expandable {
cursor: pointer;
color: var(--engv-yellow);
font-weight: 600;
display: block;
margin: 20px auto;
padding: 10px 20px;
background: var(--engv-gray);
border-radius: 25px;
transition: all 0.3s ease;
text-align: center;
max-width: 350px;
font-size: 0.9em;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.expandable:hover {
background: #2a2a2a;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.expanded-content {
max-height: 0;
overflow: hidden;
margin: 0;
padding: 0;
transition: all 0.3s ease-in-out;
background: var(--engv-light-gray);
border-radius: 4px;
box-shadow: var(--box-shadow);
}
.expanded-content.active {
max-height: 1000px; /* dostosuj do najdłuższej możliwej zawartości */
margin-top: 20px;
margin-bottom: 20px;
padding: 20px;
}
.cost-category {
margin-bottom: 20px;
padding: 15px;
background: var(--engv-white);
border-radius: 8px;
box-shadow: var(--box-shadow);
overflow: visible; /* Dodane */
}
.cost-category.summary {
background: rgba(252,206,11,0.1);
border-left: 4px solid var(--engv-yellow);
margin-bottom: 0; /* Dodane */
padding: 15px;
width: 100%; /* Dodane */
display: block; /* Dodane */
overflow: visible; /* Dodane */
}
.cost-category.summary h4 {
color: var(--engv-gray);
margin-bottom: 8px;
font-weight: 600;
font-size: 1em;
display: block;
}
.cost-category.summary p {
margin-bottom: 10px;
line-height: 1.3;
font-size: 0.8em;
display: block; /* Dodane */
}
.cost-category ul {
padding-left: 20px;
margin-bottom: 15px;
}
.cost-category ul li {
margin-bottom: 10px;
line-height: 1.6;
}
/* Nowe style tabel */
.table-wrapper {
width: 100%;
margin: 1.5rem 0;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.95rem;
background: white;
}
th, td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid #eee;
}
th {
background: var(--engv-gray);
color: white;
font-weight: 600;
padding: 15px;
}
tr:hover {
background-color: rgba(252, 206, 11, 0.05);
}
.results-section {
background: var(--engv-white);
border-radius: 8px;
padding: 30px;
margin-top: 30px;
box-shadow: var(--box-shadow);
opacity: 0;
transform: translateY(10px);
transition: opacity 0.5s ease, transform 0.5s ease;
}
.results-section.show {
opacity: 1;
transform: translateY(0);
}
.savings-highlight {
background: rgba(252, 206, 11, 0.2);
color: var(--engv-gray);
padding: 20px;
border-radius: 4px;
margin-top: 20px;
font-weight: 700;
text-align: center;
box-shadow: var(--box-shadow);
border-left: 4px solid var(--engv-yellow);
}
.cta-button {
display: inline-block;
margin-top: 15px;
padding: 10px 20px;
background-color: var(--engv-gray);
color: var(--engv-yellow);
font-weight: 700;
border-radius: 4px;
text-decoration: none;
transition: all 0.3s ease;
}
.cta-button:hover {
background-color: var(--engv-yellow);
color: var(--engv-gray);
transform: translateY(-2px);
box-shadow: var(--box-shadow);
}
.info {
font-style: italic;
color: var(--engv-gray);
opacity: 0.8;
margin: 12px 0;
line-height: 1.4;
font-size: 0.8em; /* dodane zmniejszenie czcionki */
padding: 0 15px; /* dodane odstępy po bokach */
}
.info p {
font-size: 0.9em; /* dodane zmniejszenie czcionki dla paragrafu */
}
.info b {
font-size: 0.9em; /* dodane zmniejszenie czcionki dla pogrubionego tekstu */
}
.steps-container {
max-width: 600px;
margin: 0 auto 2rem;
padding: 0 1rem;
}
.progress-container {
height: 4px;
background: var(--engv-light-gray);
border-radius: 2px;
margin-bottom: 1rem;
position: relative;
}
.progress-bar {
height: 100%;
background: var(--engv-yellow);
border-radius: 2px;
transition: width 0.3s ease;
position: relative;
}
.step-indicators {
display: flex;
justify-content: space-between;
font-size: 0.9rem;
}
.step-indicator {
position: relative;
padding-top: 1.5rem;
color: var(--engv-gray);
opacity: 0.7;
transition: opacity 0.3s;
}
.step-indicator::before {
content: '';
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 8px;
height: 8px;
background: var(--engv-gray);
border-radius: 50%;
transition: background-color 0.3s;
}
.step-indicator.active {
opacity: 1;
}
.step-indicator.active::before {
background: var(--engv-yellow);
}
.step-indicator.active {
opacity: 1;
}
.step-indicator::before {
content: '';
width: 24px;
height: 24px;
border-radius: 50%;
border: 2px solid currentColor;
margin-right: 8px;
transition: background-color 0.3s ease;
}
.step-indicator.active::before {
background-color: var(--engv-yellow);
}
.error-message {
color: #dc3545;
font-size: 0.85em;
margin-top: -15px;
margin-bottom: 10px;
display: none;
}
/* Stylizacja wyróżnionej sekcji tekstowej */
.highlighted-text {
background-color: rgba(252, 206, 11, 0.2); /* Półprzeźroczyste żółte tło */
padding: 20px;
border-radius: 8px;
border-left: 4px solid var(--engv-yellow);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
position: relative;
transition: background-color 0.3s ease, box-shadow 0.3s ease;
}
/* Dodanie ikony żarówki */
.highlighted-text::after {
content: '💡';
position: absolute;
top: 20px;
right: 20px;
font-size: 1.5em;
transition: transform 0.3s ease;
}
/* Animacja ikony po najechaniu */
.highlighted-text:hover::after {
transform: translateY(-5px);
}
/* Stylizacja nagłówka wewnątrz wyróżnionej sekcji */
.highlighted-text h3 {
font-size: 1.2em;
margin-bottom: 10px;
color: var(--engv-yellow);
}
/* Stylizacja paragrafu wewnątrz wyróżnionej sekcji */
.highlighted-text p {
font-size: 0.85em;
line-height: 1.4;
color: #333333;
}
/* Estetyczny box dla ROI */
.roi-box {
background: var(--engv-light-gray);
border-radius: 8px;
padding: 20px;
margin-top: 30px;
box-shadow: var(--box-shadow);
}
.roi-box h3 {
margin-bottom: 10px;
font-weight: 600;
color: var(--engv-gray);
}
.roi-box p {
font-size: 1em;
color: var(--engv-gray);
}
/* -----------------------------
Nowe Style dla Sekcji ROI Box
----------------------------- */
/* Stylizacja ROI Box */
.roi-box {
background: linear-gradient(135deg, #f9f9f9, #fff);
border-radius: 12px;
padding: 25px;
margin-top: 30px;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
/* Klasa dodawana po wyświetleniu sekcji */
.roi-box.show {
opacity: 1;
transform: translateY(0);
}
/* Stylizacja nagłówka ROI */
.roi-box h3 {
margin-bottom: 15px;
font-weight: 700;
color: var(--engv-gray);
display: flex;
align-items: center;
}
/* Ikona przed nagłówkiem */
.roi-box h3::before {
content: '📈'; /* Ikona informacyjna */
margin-right: 10px;
font-size: 1.4em;
transition: transform 0.3s ease;
}
/* Animacja ikony przy najechaniu */
.roi-box h3:hover::before {
transform: scale(1.2) rotate(10deg);
}
/* Stylizacja formuły ROI */
.roi-formula {
background: rgba(252, 206, 11, 0.1); /* Bardzo jasne, prawie przezroczyste żółte tło */
border-left: 4px solid var(--engv-yellow);
padding: 15px 20px;
border-radius: 4px;
margin-bottom: 20px;
position: relative;
transition: background 0.3s ease;
box-shadow: 0 2px 5px rgba(0,0,0,0.05); /* Delikatny cień */
}
.roi-formula:hover {
background: rgba(252, 206, 11, 0.15); /* Lekko ciemniejsze przy hover */
}
.roi-formula p {
font-size: 1.1em;
line-height: 1.6;
}
.roi-formula p {
color: var(--engv-gray); /* Zmiana koloru tekstu na szary */
}
/* Stylizacja przykładu obliczenia */
.roi-example {
background: rgba(128, 128, 128, 0.1); /* Półprzeźroczysto szare tło */
border-left: 4px solid var(--engv-gray); /* Zmiana koloru obramowania na szary */
padding: 15px 20px;
border-radius: 4px;
position: relative;
transition: background 0.3s ease;
}
.roi-example:hover {
background: rgba(128, 128, 128, 0.15); /* Lekko ciemniejsze przy hover */
}
.roi-example ul {
list-style: none;
padding-left: 0;
}
.roi-example ul li {
margin-bottom: 10px;
font-size: 1em;
}
.roi-example ul li span {
font-weight: 700;
color: var(--engv-gray);
}
/* Animacja liczb w przykładzie */
.animate-number {
font-weight: 700;
color: var(--engv-yellow);
font-size: 1.2em;
}
/* -----------------------------
Spójne Style dla Nagłówków i Tekstów
----------------------------- */
/* Nagłówki h3 w obu sekcjach */
.roi-box h3,
.cost-category.highlighted-text h3 {
font-size: 1.2em; /* Przykładowa wielkość, dostosuj według potrzeb */
margin-bottom: 15px;
color: var(--engv-gray);
}
/* Nagłówki h4 w opisach kosztów ukrytych */
.cost-category h4 {
font-size: 1em; /* Spójna wielkość dla h4 */
margin-bottom: 10px;
color: var(--engv-gray);
}
/* Paragrafy w obu sekcjach */
.roi-box p,
.cost-category p {
font-size: 0.75em; /* Spójna wielkość paragrafów */
line-height: 1.6;
margin-bottom: 15px;
color: var(--engv-gray);
}
.intro-message {
background-color: rgba(252, 206, 11, 0.2);
border-left: 4px solid var(--engv-yellow);
padding: 25px;
margin-bottom: 30px;
border-radius: 8px;
font-size: 0.9em;
font-weight: 600;
text-align: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
color: var(--engv-gray);
opacity: 0;
transform: translateY(20px);
transition: opacity 0.5s ease, transform 0.5s ease;
position: relative;
}
.intro-message::before {
content: 'ℹ️';
position: absolute;
top: 20px;
left: 20px;
font-size: 1.2em;
transition: transform 0.3s ease;
}
.intro-message:hover::before {
transform: translateY(-5px);
}
.intro-message.show {
opacity: 1;
transform: translateY(0);
}
.calculator-header {
text-align: center;
padding: 20px 0;
}
.logo {
margin: 20px auto;
}
.logo img {
max-width: 200px;
height: auto;
}
h1 {
font-size: 2em;
font-weight: 700;
margin: 20px 0;
color: var(--engv-gray);
}
.highlight {
color: var(--engv-yellow);
}
.subtitle {
font-size: 1.1em;
color: var(--engv-gray);
font-weight: 600;
}
/* Animowany tytuł */
.main-title {
text-align: center;
margin-bottom: 40px;
}
.animated-title {
font-size: 2em;
font-weight: 700;
margin-bottom: 10px;
color: var(--engv-gray);
animation: fadeIn 1s ease;
}
.highlight {
color: var(--engv-yellow);
position: relative;
display: inline-block;
animation: shimmer 2s infinite;
}
.subtitle {
font-size: 1.2em;
color: var(--engv-gray);
font-weight: 600;
opacity: 0;
animation: fadeIn 1s ease forwards;
animation-delay: 0.5s;
}
/* Animacje */
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes shimmer {
0% {
opacity: 1;
}
50% {
opacity: 0.7;
}
100% {
opacity: 1;
}
}
.logo-container {
text-align: center;
padding: 2rem 0;
background: linear-gradient(135deg, rgba(252, 206, 11, 0.05) 0%, rgba(255, 255, 255, 0) 100%);
border-radius: 12px;
margin-bottom: 2rem;
}
.logo {
max-width: 200px;
margin: 0 auto 1.5rem;
transition: transform 0.3s ease;
}
.logo:hover {
transform: scale(1.05);
}
.logo img {
width: 100%;
height: auto;
display: block;
}
.logo svg {
max-width: 100%;
height: auto;
}
.letter {
animation: fadeIn 0.5s ease-out forwards;
opacity: 0;
}
.letter-v {
animation: slideIn 0.8s ease-out forwards;
opacity: 0;
transform-origin: center;
}
/* Animacje wejścia */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* Dodaj hover efekt */
.logo:hover .letter-v {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
.main-title {
text-align: center;
margin: 40px auto;
max-width: 900px;
}
.animated-title {
font-size: 2.2em;
font-weight: 700;
margin-bottom: 15px;
color: var(--engv-gray);
animation: fadeInUp 1s ease;
line-height: 1.3;
}
.highlight {
color: var(--engv-yellow);
position: relative;
display: inline-block;
animation: shimmer 3s infinite;
text-shadow: 0 0 10px rgba(252, 206, 11, 0.2);
}
.subtitle {
font-size: 1.1em;
color: var(--engv-gray);
font-weight: 600;
letter-spacing: 1px;
opacity: 0;
animation: fadeIn 1s ease forwards;
animation-delay: 0.5s;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes shimmer {
0% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.8;
transform: scale(1.02);
}
100% {
opacity: 1;
transform: scale(1);
}
}
.logo-image {
text-align: center;
margin: 40px auto 30px;
max-width: 200px;
opacity: 0;
animation: fadeInDown 1s ease forwards;
}
.logo-image img {
width: 100%;
height: auto;
display: block;
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.calculator-wrapper {
max-width: 1000px;
max-height: 1700px;
width: 100%;
margin: 0 auto;
padding: 15px;
overflow-y: auto;
background: white;
border: 1px solid #FCCE0B;
border-radius: 8px;
scrollbar-width: thin;
scrollbar-color: var(--engv-yellow) #f1f1f1;
position: relative;
}
.calculator-wrapper::-webkit-scrollbar {
width: 8px;
}
.calculator-wrapper::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
.calculator-wrapper::-webkit-scrollbar-thumb {
background: var(--engv-yellow);
border-radius: 4px;
}
/* Responsywność tabeli */
/* Responsywność tabel */
@media screen and (max-width: 768px) {
table {
display: block;
}
tr {
margin-bottom: 1rem;
display: flex;
flex-direction: column;
border: 1px solid #eee;
border-radius: 8px;
padding: 10px;
}
td, th {
border: none;
padding: 8px;
}
td {
display: grid;
grid-template-columns: 1fr;
padding: 8px;
}
td::before {
content: attr(data-label);
font-weight: 600;
margin-bottom: 4px;
color: var(--engv-gray);
}
td:last-child {
border-bottom: none;
}
thead {
display: none;
}
}
/* Specjalne style dla wartości */
td[id] {
font-weight: 600;
}
.cost-value {
color: var(--engv-gray);
font-weight: 600;
}
.included {
color: #2ecc71;
font-weight: 500;
}
/* Dodatkowe style dla małych ekranów */
@media screen and (max-width: 480px) {
.calculator-wrapper {
padding: 10px;
}
td {
flex-direction: column;
align-items: flex-start;
}
td::before {
margin-bottom: 4px;
}
}
/* Specjalne style dla komórek z wartościami */
table td[id] {
font-weight: 600;
color: var(--engv-gray);
}
/* Mniejsze odstępy w komórkach */
table td {
min-height: 40px;
line-height: 1.2;
}
}
@media screen and (max-width: 360px) {
table td {
font-size: 0.8em;
padding: 8px;
padding-left: 45%;
}
}
th, td {
min-width: 120px; /* Minimalna szerokość kolumn */
}
/* Stała pierwsza kolumna */
th:first-child, td:first-child {
position: sticky;
left: 0;
background: var(--engv-white);
z-index: 1;
}
th:first-child {
z-index: 2;
}
/* Płynne scrollowanie dla całej strony */
html {
scroll-behavior: smooth;
}
/* Style dla animowanego przewijania */
.scroll-margin {
scroll-margin-top: 20px;
}
.scroll-padding {
scroll-padding-top: 20px;
}
/* Stylizacja tabeli kosztów ukrytych */
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
background-color: var(--engv-light-gray); /* Jasne tło */
border-radius: 8px; /* Zaokrąglenie tabeli */
box-shadow: var(--box-shadow); /* Delikatny cień */
overflow: hidden;
}
/* Nagłówki tabeli */
table th {
background-color: var(--engv-gray); /* Szare tło */
color: var(--engv-white); /* Biały tekst */
font-weight: 700;
text-align: center;
padding: 12px; /* Odstępy */
font-size: 1em; /* Rozmiar tekstu */
border-bottom: 2px solid var(--engv-yellow); /* Żółta linia pod nagłówkami */
}
/* Komórki tabeli */
table td {
text-align: center;
padding: 10px; /* Odstępy wewnętrzne */
font-size: 0.95em; /* Rozmiar tekstu */
border-bottom: 1px solid #ddd; /* Linia podziału */
}
/* Podświetlenie wierszy */
table tr:hover {
background-color: rgba(252, 206, 11, 0.1); /* Subtelne żółte podświetlenie */
}
/* Wyróżnienie wartości */
table td[id^="hidden"] {
font-weight: 600;
color: var(--engv-gray); /* Ciemnoszary tekst */
}
/* Łączny koszt ukryty */
table tr.summary-row {
background-color: rgba(252, 206, 11, 0.2); /* Jasnożółte tło */
font-weight: 700;
color: var(--engv-gray);
}
/* Wartość łączna w podsumowaniu */
table tr.summary-row td {
font-size: 1.1em; /* Większy tekst */
color: var(--engv-grey); /* Żółty tekst */
text-align: center;
}
/* Responsywność dla tabeli */
@media screen and (max-width: 768px) {
table th, table td {
font-size: 0.85em; /* Zmniejszony tekst */
padding: 8px; /* Mniejsze odstępy */
}
}
#scroll-to-top {
position: fixed;
bottom: 20px;
right: 20px;
background: var(--engv-yellow);
color: var(--engv-gray);
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
font-size: 1.5em;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: var(--box-shadow);
transition: opacity 0.3s ease, transform 0.3s ease;
opacity: 0;
transform: translateY(20px);
}
#scroll-to-top.show {
opacity: 1;
transform: translateY(0);
}
.no-click {
display: inline-block;
margin-top: 15px;
padding: 10px 20px;
background-color: var(--engv-gray); /* Kolor tła */
color: var(--engv-yellow); /* Kolor tekstu */
font-weight: 700;
border-radius: 4px;
text-decoration: none;
font-size: 0.9em;
cursor: default; /* Zmiana kursora na standardowy */
text-align: center;
}
.no-click:hover {
background-color: var(--engv-gray); /* Bez zmian przy hover */
color: var(--engv-yellow); /* Bez zmian przy hover */
}
.arrow-down {
display: block;
font-size: 1.5em;
margin-top: 10px; /* Odstęp między tekstem a strzałką */
}
.expanded-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
.expanded-content.show {
max-height: 2000px;
transition: max-height 0.5s ease-in;
}
.expandable-btn {
cursor: pointer;
color: var(--engv-yellow);
font-weight: 650;
display: block;
margin: 15px auto;
padding: 8px 16px;
background: var(--engv-gray);
border-radius: 25px;
transition: all 0.3s ease;
text-align: center;
max-width: 350px;
font-size: 0.85em;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
border: none;
text-transform: none; /* wyłączenie wielkich liter */
}
.expandable-btn:hover {
background: #2a2a2a;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.expandable-content {
display: none;
margin-top: 20px;
padding: 20px;
background: var(--engv-light-gray);
border-radius: 4px;
box-shadow: var(--box-shadow);
}
.expandable-content.active {
display: block;
max-height: none !important; /* Usunięcie limitu wysokości */
}
.expandable-content ul {
padding-left: 20px;
margin-bottom: 15px;
}
.expandable-content ul li {
margin-bottom: 8px;
line-height: 1.4;
font-size: 0.8em;
color: var(--engv-gray);
}
</style>
</head>
<body>
<div class="calculator-wrapper">
<!-- Logo + Tytuł -->
<div class="logo-container">
<div class="logo">
<img src="https://materialy.engave.pl/wp-content/uploads/2023/11/logo.png" alt="ENGV"/>
</div>
<h1>Rozlicz swoje IT: <span class="highlight">Etat czy outsourcing?</span></h1>
<div class="subtitle">KALKULATOR ROI OD ENGAVE</div>
</div>
<!-- Pasek postępu + kroki -->
<div class="steps-container">
<div class="progress-container">
<div class="progress-bar"></div>
</div>
<div class="step-indicators">
<div class="step-indicator active">Krok 1</div>
<div class="step-indicator">Krok 2</div>
<div class="step-indicator">Krok 3</div>
</div>
</div>
<!-- Krok 1 -->
<div class="form-section">
<h2 class="step-title">Krok 1: Jakich działań IT potrzebujesz? / Jakie masz obecnie</h2>
<div class="select-wrapper">
<select id="service-level" class="styled-select">
<option value="">Wybierz poziom wsparcia</option>
<option value="basic">Basic (6 499 PLN/mies.)</option>
<option value="medium">Medium (9 499 PLN/mies.)</option>
<option value="premium">Premium (16 499 PLN/mies.)</option>
</select>
</div>
<button class="expandable-btn" onclick="toggleContent('basic-content', this)">Zobacz zakres usług dla poziomu Basic</button>
<div class="expandable-content" id="basic-content">
<ul>
<li>Konfiguracja i serwis sprzętu komputerowego</li>
<li>Opracowanie dokumentacji i inwentaryzacji sprzętu/licencji</li>
<li>Analiza infrastruktury IT</li>
<li>Dostęp do zespołu inżynieryjnego</li>
<li>Konserwacja sprzętowa</li>
<li>Profesjonalny helpdesk 24/7</li>
<li>Bieżące wsparcie użytkowników</li>
<li>Instalacja oprogramowania</li>
<li>Stabilność i bezpieczeństwo systemu informatycznego</li>
<li>Obsługa systemów operacyjnych</li>
</ul>
</div>
<button class="expandable-btn" onclick="toggleContent('medium-content', this)">Zobacz zakres usług dla poziomu Medium</button>
<div class="expandable-content" id="medium-content">
<ul>
<li>Wszystkie usługi z poziomu Basic</li>
<li>Administracja serwerami Windows i Linux</li>
<li>Zarządzanie procesami backupu i odzyskiwania danych</li>
<li>Wsparcie specjalistyczne Microsoft 365</li>
<li>Zarządzanie Microsoft 365, Exchange i infrastrukturą sieciową</li>
<li>Podstawowe zabezpieczenia cyberbezpieczeństwa</li>
</ul>
</div>
<button class="expandable-btn" onclick="toggleContent('premium-content', this)">Zobacz zakres usług dla poziomu Premium</button>
<div class="expandable-content" id="premium-content">
<ul>
<li>Wszystkie usługi z poziomów Basic i Medium</li>
<li>Zarządzanie infrastrukturą pod systemy ERP</li>
<li>Migracje środowisk on-premise do chmury</li>
<li>Konfiguracja wysokowydajnościowych środowisk serwerowych</li>
<li>Zaawansowane rozwiązania chmury hybrydowej</li>
<li>Monitoring zagrożeń i raportowanie incydentów</li>
</ul>
</div>
</div>
<!-- Krok 2 -->
<div class="section" style="margin-top: 40px;">
<h2>Krok 2: Ilu informatyków obecnie zatrudniasz?</h2>
<label for="it-staff">Podaj liczbę informatyków:</label>
<input type="number" id="it-staff" min="0" value="0"/>
<div class="error-message" id="it-staff-error"></div>
</div>
<!-- Krok 3 -->
<div class="section" id="step-3-section" style="display: none;">
<h2>Krok 3: Wybierz formę zatrudnienia</h2>
<!-- Wybór typu umowy -->
<label for="contract-type">Rodzaj umowy:</label>
<select id="contract-type">
<option value="">-- Wybierz rodzaj umowy --</option>
<option value="uop">Umowa o pracę (UoP)</option>
<option value="b2b">B2B</option>
</select>
<div class="error-message" id="contract-type-error"></div>
<!-- Opcje po wybraniu typu umowy -->
<div id="contract-options" style="display: none; margin-top: 20px;">
<label for="salary-option">Wybierz opcję wynagrodzenia:</label>
<select id="salary-option">
<option value="">-- Wybierz opcję --</option>
<option value="median">Średnia wartość wynagrodzenia na tym stanowisku (mediana)</option>
<option value="custom">Podaj łączne wynagrodzenie netto</option>
</select>
<div class="error-message" id="salary-option-error"></div>
<!-- Mediana wynagrodzenia -->
<div id="median-salary" style="display: none; margin-top: 10px;">
<p>
Mediana wynagrodzenia netto dla wybranego typu umowy:
<strong id="median-value">10 000 PLN</strong>
</p>
</div>
<!-- Wpisanie własnej kwoty netto -->
<div id="custom-salary-container" style="display: none; margin-top: 10px;">
<label for="custom-salary" id="custom-salary-label">Wpisz łączne wynagrodzenie netto:</label>
<input type="number" id="custom-salary" min="0" value="0" />
<div class="error-message" id="custom-salary-error"></div>
</div>
</div>
</div>
<!-- Zero IT Staff Results -->
<div class="section scroll-margin" id="zero-it-results" style="display: none;">
<div class="intro-message">
Zastanawiasz się czy wybrać etatowego informatyka, czy outsourcing IT w Engave? Zobacz wyliczenia kosztów i policz ile oszczędzisz!
</div>
<h2>Szczegółowe obliczenia</h2>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Kategoria kosztów</th>
<th>Umowa o pracę (UoP)</th>
<th>Kontrakt B2B</th>
<th>Outsourcing IT od Engave</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Kategoria">Średnie wynagrodzenie netto</td>
<td data-label="UoP" class="cost-value" id="zero-salary-uop"></td>
<td data-label="B2B" class="cost-value" id="zero-salary-b2b"></td>
<td data-label="Outsourcing" class="cost-value">-</td>
</tr>
<tr>
<td data-label="Kategoria">Składki ZUS ok 32% wynagrodzenia</td>
<td data-label="UoP" class="cost-value" id="zero-employer-cost"></td>
<td data-label="B2B" class="cost-value" id="zero-vat-cost"></td>
<td data-label="Outsourcing" class="cost-value">-</td> <!-- Outsourcing IT nie ma dodatkowych kosztów -->
</tr>
<tr>
<td data-label="Kategoria">Koszty licencji i oprogramowania</td>
<td data-label="UoP" class="cost-value">ok. 500 PLN/mies.</td>
<td data-label="B2B" class="cost-value">ok. 500 PLN/mies.</td>
<td data-label="Outsourcing" class="included">Wliczone w koszt</td>
</tr>
<tr>
<td data-label="Kategoria">Koszty biura</td>
<td data-label="UoP" class="cost-value">ok. 400 PLN/mies.</td>
<td data-label="B2B" class="cost-value">ok. 400 PLN/mies.</td>
<td data-label="Outsourcing" class="included">Wliczone w koszt</td>
</tr>
<tr>
<td data-label="Kategoria">Koszty wyposażenia IT</td>
<td data-label="UoP" class="cost-value">ok. 667 PLN/mies.</td>
<td data-label="B2B" class="cost-value">ok. 667 PLN/mies.</td>
<td data-label="Outsourcing" class="included">Wliczone w koszt</td>
</tr>
<tr>
<td data-label="Kategoria">Koszty szkoleń i certyfikacji</td>
<td data-label="UoP" class="cost-value">ok. 333 PLN/mies.</td>
<td data-label="B2B" class="cost-value">ok. 333 PLN/mies.</td>
<td data-label="Outsourcing" class="included">Wliczone w koszt</td>
</tr>
<tr>
<td data-label="Kategoria">Koszty rekrutacji</td>
<td data-label="UoP" class="cost-value">ok. 417 PLN/mies.</td>
<td data-label="B2B" class="cost-value">ok. 417 PLN/mies.</td>
<td data-label="Outsourcing" class="included">Wliczone w koszt</td>
</tr>
<tr>
<td data-label="Kategoria">Koszty utrzymania serwerowni</td>
<td data-label="UoP" class="cost-value">ok. 3 917 PLN/mies.</td>
<td data-label="B2B" class="cost-value">ok. 3 917 PLN/mies.</td>
<td data-label="Outsourcing" class="included">Wliczone w koszt</td>
</tr>
<tr class="summary-row">
<td data-label="Kategoria"><strong>Łączny koszt miesięczny</strong></td>
<td data-label="UoP" class="cost-value" id="zero-total-monthly-uop"></td>
<td data-label="B2B" class="cost-value" id="zero-total-monthly-b2b"></td>
<td data-label="Outsourcing" class="cost-value" id="zero-outsourcing-monthly"></td>
</tr>
<tr class="summary-row">
<td data-label="Kategoria"><strong>Łączny koszt roczny</strong></td>
<td data-label="UoP" class="cost-value" id="zero-total-annual-uop"></td>
<td data-label="B2B" class="cost-value" id="zero-total-annual-b2b"></td>
<td data-label="Outsourcing" class="cost-value" id="zero-outsourcing-annual"></td>
</tr>
</tbody>
</table>
</div>
<div class="cost-category highlighted-text">
<h3>Ile tak naprawdę kosztuje etatowy informatyk?</h3>
<p>
Często wydaje się, że jedynym kosztem jest wynagrodzenie pracownika. Jednak za każdym razem,
gdy zatrudniasz informatyka, zaczynają się mnożyć ukryte koszty, które
potrafią zjeść sporą część firmowego budżetu. Poniżej krótkie podsumowanie
tych wydatków — wyłącznie w skali miesiąca — a przecież to tylko wierzchołek
góry lodowej:
</p>
</div>
<button class="expandable-btn" onclick="toggleContent('zero-costs-content', this)">Zobacz szczegóły kosztów ukrytych</button>
<div class="expandable-content" id="zero-costs-content">
<!-- Pełny opis kosztów ukrytych -->
<div class="cost-category">
<h4>Licencje i oprogramowanie (ok. 500 PLN/mies./pracownik)</h4>
<p>
Microsoft 365, antywirus, narzędzia do zarządzania IT, CRM… Bez nich informatyk
nie może efektywnie działać, a firma nie może pozwolić sobie na luki w zabezpieczeniach.
</p>
</div>
<div class="cost-category">
<h4>Biuro (ok. 400 PLN/mies./pracownik)</h4>
<p>
Biurko, prąd, internet, telefon – to wszystko generuje dodatkowe,
comiesięczne koszty i zajmuje cenną przestrzeń, którą mógłbyś przeznaczyć
na rozwój biznesu.
</p>
</div>
<div class="cost-category">
<h4>Wyposażenie IT (ok. 667 PLN/mies./pracownik)</h4>
<p>
Komputer, monitor, akcesoria – bez tego informatyk nie ruszy, a sprzęt trzeba
regularnie wymieniać, by nie spowalniać pracy całego zespołu.
</p>
</div>
<div class="cost-category">
<h4>Szkolenia i certyfikacje (ok. 333 PLN/mies./pracownik)</h4>
<p>
Technologia rozwija się błyskawicznie. Jeśli chcesz mieć w firmie
ekspertów na najwyższym poziomie, musisz inwestować w kursy,
konferencje i certyfikaty.
</p>
</div>
<div class="cost-category">
<h4>Rekrutacja (ok. 417 PLN/mies./pracownik)</h4>
<p>
Ogłoszenia, prowizje agencji, czas poświęcony przez HR i menedżerów
– każda rotacja w zespole IT to nie tylko dezorganizacja pracy, ale
też realne koszty.
</p>
</div>
<div class="cost-category">
<h4>Utrzymanie serwerowni (ok. 3 917 PLN/mies.)</h4>
<p>
Serwery działają non stop, zużywając mnóstwo prądu. Trzeba je też
chłodzić, konserwować, aktualizować i regularnie wymieniać sprzęt,
by uniknąć awarii.
</p>
</div>
<div class="cost-category summary">
<h4>Wniosek?</h4>
<p>
Samo wynagrodzenie to tylko ułamek prawdziwego kosztu etatowego informatyka.
Gdy zsumujesz wszystkie te elementy, okaże się, że Twój „tani”
specjalista wcale nie jest tani. Zastanów się, czy te wydatki
faktycznie przynoszą firmie wystarczającą wartość — czy może warto
wybrać outsourcing, gdzie płacisz za konkretne usługi i pewność, że
wszystko działa tak, jak należy. W biznesie liczą się realne liczby
i efekty, a nie tylko złudne przekonanie, że „mamy swojego człowieka
od IT”.
</p>
</div>
</div>
<div class="savings-highlight">
<p>
Wybierając outsourcing IT od Engave możesz zaoszczędzić
<span id="zero-savings">---</span> w ciągu 3 lat!
</p>
</div>
</div>
<!-- Results (dla >0) -->
<div class="section results-section scroll-margin" id="results-section" style="display: none;">
<h2>Wyniki i porównanie</h2>
<p>
<strong>Wybrany poziom outsourcingu IT:</strong>
<span id="selected-level"></span>
</p>
<div class="table-wrapper">
<table class="results-table">
<thead>
<tr>
<th>Kategoria</th>
<th>Wynagrodzenie za etat + koszty ukryte</th>
<th>Outsourcing IT od Engave</th>
<th>Tyle oszczędzasz!</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Kategoria">Koszty miesięczne</td>
<td data-label="In-house" id="inhouse-monthly"></td>
<td data-label="Outsourcing" id="outsourcing-monthly"></td>
<td data-label="Oszędności" class="cost-value" id="difference-monthly"></td>
</tr>
<tr>
<td data-label="Kategoria">Koszty roczne</td>
<td data-label="In-house" id="inhouse-annual"></td>
<td data-label="Outsourcing" id="outsourcing-annual"></td>
<td data-label="Oszędności" class="cost-value" id="difference-annual"></td>
</tr>
<tr>
<td data-label="Kategoria">ROI</td>
<td data-label="In-house">-</td>
<td data-label="Outsourcing">-</td>
<td data-label="Oszędności" class="cost-value" id="roi"></td>
</tr>
</tbody>
</table>
</div>
<div class="cost-category highlighted-text">
<h4>Dlaczego kwota miesięczna za etat jest tak wysoka?</h4>
<p>
Często wydaje się, że jedynym kosztem jest wynagrodzenie pracownika. Jednak za każdym razem,
gdy zatrudniasz informatyka, zaczynają się mnożyć ukryte koszty, które
potrafią zjeść sporą część firmowego budżetu. Poniżej krótkie podsumowanie
tych wydatków — wyłącznie w skali miesiąca — a przecież to tylko wierzchołek
góry lodowej.
</p>
</div>
<!-- Nowa rozwijana sekcja opisowa -->
<button class="expandable-btn" onclick="toggleContent('hidden-costs-description', this)">Szczegóły kosztów ukrytych</button>
<div class="expandable-content" id="hidden-costs-description">
<!-- Pełny opis kosztów ukrytych -->
<div class="cost-category">
<h4>Licencje i oprogramowanie (ok. 500 PLN/mies./pracownik)</h4>
<p>
Microsoft 365, antywirus, narzędzia do zarządzania IT, CRM… Bez nich informatyk
nie może efektywnie działać, a firma nie może pozwolić sobie na luki w zabezpieczeniach.
</p>
</div>
<div class="cost-category">
<h4>Biuro (ok. 400 PLN/mies./pracownik)</h4>
<p>
Biurko, prąd, internet, telefon – to wszystko generuje dodatkowe,
comiesięczne koszty i zajmuje cenną przestrzeń, którą mógłbyś przeznaczyć
na rozwój biznesu.
</p>
</div>
<div class="cost-category">
<h4>Wyposażenie IT (ok. 667 PLN/mies./pracownik)</h4>
<p>
Komputer, monitor, akcesoria – bez tego informatyk nie ruszy, a sprzęt trzeba
regularnie wymieniać, by nie spowalniać pracy całego zespołu.
</p>
</div>
<div class="cost-category">
<h4>Szkolenia i certyfikacje (ok. 333 PLN/mies./pracownik)</h4>
<p>
Technologia rozwija się błyskawicznie. Jeśli chcesz mieć w firmie
ekspertów na najwyższym poziomie, musisz inwestować w kursy,
konferencje i certyfikaty.
</p>
</div>
<div class="cost-category">
<h4>Rekrutacja (ok. 417 PLN/mies./pracownik)</h4>
<p>
Ogłoszenia, prowizje agencji, czas poświęcony przez HR i menedżerów
– każda rotacja w zespole IT to nie tylko dezorganizacja pracy, ale
też realne koszty.
</p>
</div>
<div class="cost-category">
<h4>Utrzymanie serwerowni (ok. 3 917 PLN/mies.)</h4>
<p>
Serwery działają non stop, zużywając mnóstwo prądu. Trzeba je też
chłodzić, konserwować, aktualizować i regularnie wymieniać sprzęt,
by uniknąć awarii.
</p>
</div>
<div class="cost-category summary">
<h4>Wniosek?</h4>
<p>
Jak widać, samo wynagrodzenie to tylko ułamek prawdziwego kosztu etatowego informatyka.
Gdy zsumujesz wszystkie te elementy, okaże się, że Twój „tani”
specjalista wcale nie jest tani. Zastanów się, czy te wydatki
faktycznie przynoszą firmie wystarczającą wartość — czy może warto
wybrać outsourcing, gdzie płacisz za konkretne usługi i pewność, że
wszystko działa tak, jak należy. W biznesie liczą się realne liczby
i efekty, a nie tylko złudne przekonanie, że „mamy swojego człowieka
od IT”.
</p>
</div>
</div>
<!-- Nowa tabela kosztów ukrytych dla >0 informatyków -->
<h3>Koszty ukryte</h3>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Kategoria</th>
<th>Koszt miesięczny</th>
<th>Liczba pracowników</th>
<th>Łączny koszt (PLN/mies.)</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Kategoria">Składki ZUS ok 32% wynagrodzenia</td>
<td data-label="Koszt jednostkowy" id="hidden-additional-cost-unit"></td>
<td data-label="Liczba pracowników" id="hidden-additional-cost-count"></td>
<td data-label="Łączny koszt" id="hidden-additional-cost-total"></td>
</tr>
<tr>
<td data-label="Kategoria">Licencje i oprogramowanie</td>
<td data-label="Koszt jednostkowy">500</td>
<td data-label="Liczba pracowników" id="hidden-licenses-count"></td>
<td data-label="Łączny koszt" id="hidden-licenses-total"></td>
</tr>
<tr>
<td data-label="Kategoria">Biuro</td>
<td data-label="Koszt jednostkowy">400</td>
<td data-label="Liczba pracowników" id="hidden-office-count"></td>
<td data-label="Łączny koszt" id="hidden-office-total"></td>
</tr>
<tr>
<td data-label="Kategoria">Wyposażenie IT</td>
<td data-label="Koszt jednostkowy">667</td>
<td data-label="Liczba pracowników" id="hidden-equipment-count"></td>
<td data-label="Łączny koszt" id="hidden-equipment-total"></td>
</tr>
<tr>
<td data-label="Kategoria">Szkolenia i certyfikacje</td>
<td data-label="Koszt jednostkowy">333</td>
<td data-label="Liczba pracowników" id="hidden-training-count"></td>
<td data-label="Łączny koszt" id="hidden-training-total"></td>
</tr>
<tr>
<td data-label="Kategoria">Rekrutacja</td>
<td data-label="Koszt jednostkowy">417</td>
<td data-label="Liczba pracowników" id="hidden-recruitment-count"></td>
<td data-label="Łączny koszt" id="hidden-recruitment-total"></td>
</tr>
<tr>
<td data-label="Kategoria">Utrzymanie serwerowni</td>
<td data-label="Koszt jednostkowy">3 917</td>
<td data-label="Liczba pracowników">-</td>
<td data-label="Łączny koszt" id="hidden-serverroom-total"></td>
</tr>
<tr>
<td data-label="Kategoria"><strong>Łączny koszt ukryty</strong></td>
<td data-label="Koszt jednostkowy"></td>
<td data-label="Liczba pracowników"></td>
<td data-label="Łączny koszt" id="hidden-total"></td>
</tr>
</tbody>
</table>
</div>
<!-- Estetyczny box dla ROI -->
<div class="roi-box" id="roi-box">
<h3>Jak obliczamy ROI?</h3>
<div class="roi-formula">
<p><strong>Wzór na ROI:</strong></p>
<p>
ROI = (Zysk (Oszędności) ÷ Koszt inwestycji) × 100
</p>
<p><strong>Dla Twojego kalkulatora, gdzie "Oszędności" to różnica między kosztami in-house a kosztami outsourcingu, a "Koszt inwestycji" to koszty outsourcingu:</strong></p>
<p>
ROI = (Oszędności roczne ÷ Koszty outsourcingu roczne) × 100
</p>
</div>
</div>
<div class="savings-highlight">
<p>
Wybierając outsourcing IT na poziomie
<span id="selected-level-summary"></span>, Twoja firma oszczędza
<span id="savings-amount"></span> w ciągu 3 lat!
</p> <p>ROI wynosi <span id="roi-summary"></span>!</p>
<div class="cta-button no-click">
Wypełnij formularz poniżej i oszczędzaj na zarządzaniu IT! ⬇️
</div>
</div>
</div>
<div class="buttons-row">
<button id="calculate-button">Oblicz koszty</button>
<button id="collapse-button" style="display: none;">Zwiń wyniki</button>
<div class="info">
<p>
Wszystkie kwoty podane w kalkulatorze są orientacyjne i mają na celu
przybliżenie realnych kosztów zatrudnienia informatyków na etacie, w porównaniu z
outsourcingiem IT od Engave. Nasze usługi są elastyczne – możesz mieszać zakresy
usług, dokupić dodatkowe godziny pracy, skalować zapotrzebowanie wraz z rozwojem firmy i dostosować je do swoich
potrzeb. <b>Po wypełnieniu formularza, odezwiemy się do Ciebie i przygotujemy indywidualną wycenę,
która dokładnie odpowie na potrzeby Twojej firmy, bez narażania Cię na zbędne koszty.</b>
</p>
</div>
</div>
</div>
<!-- Skrypt JavaScript -->
<script>
function toggleContent(contentId, button) {
// Zamknij wszystkie inne sekcje
document.querySelectorAll('.expandable-content').forEach(content => {
if (content.id !== contentId) {
content.classList.remove('active');
const otherButtons = document.querySelectorAll('.expandable-btn');
otherButtons.forEach(btn => {
if (btn !== button) {
if (btn.textContent.includes('poziom')) {
const level = btn.textContent.includes('Basic') ? 'Basic' :
btn.textContent.includes('Medium') ? 'Medium' : 'Premium';
btn.textContent = `Rozwiń zakres usług dla poziomu ${level}`;
} else {
btn.textContent = 'Zobacz szczegóły kosztów ukrytych';
}
}
});
}
});
// Przełącz aktualną sekcję
const content = document.getElementById(contentId);
const isExpanded = content.classList.contains('active');
// Zmień klasę
content.classList.toggle('active');
// Zmień tekst przycisku w zależności od jego typu
if (contentId === 'zero-costs-content' || contentId === 'hidden-costs-description') {
button.textContent = isExpanded ?
'Zobacz szczegóły kosztów ukrytych' :
'Zwiń szczegóły kosztów ukrytych';
} else {
const level = contentId.split('-')[0];
const capitalizedLevel = level.charAt(0).toUpperCase() + level.slice(1);
button.textContent = isExpanded ?
`Rozwiń zakres usług dla poziomu ${capitalizedLevel}` :
`Zwiń zakres usług dla poziomu ${capitalizedLevel}`;
}
// Przewiń do rozwiniętej zawartości
if (!isExpanded) {
setTimeout(() => {
content.scrollIntoView({behavior: 'smooth', block: 'nearest'});
}, 100);
}
}
const scrollToTopButton = document.getElementById('scroll-to-top');
// Pokazuj/ukrywaj przycisk w zależności od pozycji przewijania
window.addEventListener('scroll', () => {
if (window.scrollY > 300) {
scrollToTopButton.classList.add('show');
} else {
scrollToTopButton.classList.remove('show');
}
});
// Obsługa kliknięcia w przycisk
scrollToTopButton.addEventListener('click', () => {
smoothScroll(document.body, 0); // Przewiń do góry
});
/* -----------------------------
1. Stałe + progress bar
----------------------------- */
const UI_CONSTANTS = {
ANIMATION_DURATION: 500,
SCROLL_OFFSET: 50
};
function updateProgressBar(step) {
const totalSteps = 3;
const progressBar = document.querySelector('.progress-bar');
const progressPercentage = (step / totalSteps) * 100;
progressBar.style.width = `${progressPercentage}%`;
document.querySelectorAll('.step-indicator').forEach((indicator, index) => {
indicator.classList.toggle('active', index + 1 <= step);
});
}
function scrollToResults() {
const resultsSection = document.querySelector('.results-section');
if (resultsSection) {
smoothScroll(document.querySelector('.calculator-wrapper'), 50);
}
}
/* -----------------------------
2. Walidacja
----------------------------- */
function validateInputInRealTime(input, errorId) {
const value = parseFloat(input.value);
const errorDiv = document.getElementById(errorId);
if (!errorDiv) return true;
if (isNaN(value) || value < 0) {
errorDiv.textContent = 'Wartość nie może być ujemna lub nieprawidłowa';
errorDiv.style.display = 'block';
return false;
}
errorDiv.style.display = 'none';
return true;
}
function validateAllInputs() {
let allValid = true;
// Walidacja liczby informatyków
const itStaffInput = document.getElementById("it-staff");
if (!validateInputInRealTime(itStaffInput, "it-staff-error")) {
allValid = false;
}
// Jeśli liczba informatyków >0, walidacja dodatkowych pól
const itStaff = parseInt(itStaffInput.value);
if (itStaff > 0) {
const contractTypeInput = document.getElementById("contract-type");
if (!contractTypeInput.value) {
const errorDiv = document.getElementById("contract-type-error");
errorDiv.textContent = 'Proszę wybrać rodzaj umowy.';
errorDiv.style.display = 'block';
allValid = false;
} else {
const salaryOption = document.getElementById("salary-option");
if (!salaryOption.value) {
const errorDiv = document.getElementById("salary-option-error");
errorDiv.textContent = 'Proszę wybrać opcję wynagrodzenia.';
errorDiv.style.display = 'block';
allValid = false;
} else if (salaryOption.value === "custom") {
const customSalaryInput = document.getElementById("custom-salary");
if (!validateInputInRealTime(customSalaryInput, "custom-salary-error")) {
allValid = false;
}
}
}
}
return allValid;
}
/* -----------------------------
3. Formatowanie na PLN
----------------------------- */
function formatCurrency(value) {
return `${value.toLocaleString('pl-PL')} PLN`;
}
/* -----------------------------
4. Animacja liczb
----------------------------- */
function animateValue(element, start, end, duration) {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
const current = Math.floor(start + (end - start) * progress);
element.textContent = formatCurrency(current);
if (progress < 1) {
window.requestAnimationFrame(step);
}
};
window.requestAnimationFrame(step);
}
/* -----------------------------
5. Dane do wyliczeń
----------------------------- */
const MEDIAN_SALARY = 10000; // Mediana netto dla obu rodzajów umów
const EMPLOYER_COSTS = {
ZUS_RATE: 0.3174, // Składki pracodawcy ~31.74%
VAT_RATE: 0.23, // VAT 23%
};
// Koszty ukryte pozostają bez zmian
const HIDDEN_COSTS_PER_EMPLOYEE = {
licenses: 500,
office: 400,
equipment: 667,
training: 333,
recruitment: 417,
};
const SERVER_ROOM_COST = 3917; // Stały koszt niezależny od liczby pracowników
const SERVICE_COSTS = {
basic: 6499,
medium: 9499,
premium: 16499
};
const HIDDEN_COSTS = {
licenses: 500,
office: 400,
equipment: 667,
training: 333,
recruitment: 417,
serverRoom: 3917
};
/* -----------------------------
6. Pobranie elementów DOM
----------------------------- */
const calculateButton = document.getElementById("calculate-button");
const collapseButton = document.getElementById("collapse-button");
const resultsSection = document.getElementById("results-section");
const zeroItResults = document.getElementById("zero-it-results");
const itStaffInput = document.getElementById("it-staff");
const serviceLevelInput = document.getElementById("service-level");
const contractTypeInput = document.getElementById("contract-type");
const step3Section = document.getElementById("step-3-section");
const customSalaryLabel = document.getElementById("custom-salary-label");
const customSalaryInput = document.getElementById("custom-salary");
const medianSalary = document.getElementById("median-salary");
const customSalaryContainer = document.getElementById("custom-salary-container");
const salaryOption = document.getElementById("salary-option");
const contractOptions = document.getElementById("contract-options");
// Wyniki (dla >0)
const selectedLevelText = document.getElementById("selected-level");
const inhouseMonthly = document.getElementById("inhouse-monthly");
const outsourcingMonthly = document.getElementById("outsourcing-monthly");
const differenceMonthly = document.getElementById("difference-monthly");
const inhouseAnnual = document.getElementById("inhouse-annual");
const outsourcingAnnual = document.getElementById("outsourcing-annual");
const differenceAnnual = document.getElementById("difference-annual");
const roiElement = document.getElementById("roi");
const selectedLevelSummary = document.getElementById("selected-level-summary");
const roiSummary = document.getElementById("roi-summary");
const savingsAmount = document.getElementById("savings-amount");
// Tabela kosztów ukrytych dla >0 informatyków
const hiddenAdditionalCostUnit = document.getElementById("hidden-additional-cost-unit");
const hiddenAdditionalCostCount = document.getElementById("hidden-additional-cost-count");
const hiddenAdditionalCostTotal = document.getElementById("hidden-additional-cost-total");
const hiddenLicensesCount = document.getElementById("hidden-licenses-count");
const hiddenLicensesTotal = document.getElementById("hidden-licenses-total");
const hiddenOfficeCount = document.getElementById("hidden-office-count");
const hiddenOfficeTotal = document.getElementById("hidden-office-total");
const hiddenEquipmentCount = document.getElementById("hidden-equipment-count");
const hiddenEquipmentTotal = document.getElementById("hidden-equipment-total");
const hiddenTrainingCount = document.getElementById("hidden-training-count");
const hiddenTrainingTotal = document.getElementById("hidden-training-total");
const hiddenRecruitmentCount = document.getElementById("hidden-recruitment-count");
const hiddenRecruitmentTotal = document.getElementById("hidden-recruitment-total");
const hiddenServerRoomTotal = document.getElementById("hidden-serverroom-total");
const hiddenTotal = document.getElementById("hidden-total");
/* -----------------------------
7. Obliczanie hidden costs
----------------------------- */
function calculateHiddenCosts(numberOfStaff) {
return (
(HIDDEN_COSTS.licenses + HIDDEN_COSTS.office + HIDDEN_COSTS.equipment + HIDDEN_COSTS.training + HIDDEN_COSTS.recruitment) * numberOfStaff +
SERVER_ROOM_COST
);
}
/* -----------------------------
8. Walidacja wejścia
----------------------------- */
function validateInputs(itStaffCount) {
if (itStaffCount < 0) {
alert("Podane wartości nie mogą być ujemne.");
return false;
}
return true;
}
/* -----------------------------
9. Obliczenie brutto brutto
----------------------------- */
function calculateEmploymentCosts(salary, type = 'uop') {
let additionalCosts = 0;
if (type === 'uop') {
additionalCosts = salary * EMPLOYER_COSTS.ZUS_RATE; // 31.74%
} else if (type === 'b2b') {
additionalCosts = 0; // VAT usunięty
}
const totalCost = salary + additionalCosts;
return {
netSalary: salary,
additionalCosts: additionalCosts,
totalCost: totalCost
};
}
/* -----------------------------
10. ROI
----------------------------- */
function calculateROI(savings, outsourcingCost) {
if (outsourcingCost === 0) return 0;
return (savings / outsourcingCost) * 100;
}
/* -----------------------------
12. Zwijanie wyników
----------------------------- */
function collapseResults() {
zeroItResults.style.display = "none";
resultsSection.style.display = "none";
resultsSection.classList.remove("show");
collapseButton.style.display = "none";
updateProgressBar(1);
}
/* -----------------------------
14. Krok 3: staff > 0
----------------------------- */
itStaffInput.addEventListener("change", () => {
const staffCount = parseInt(itStaffInput.value) || 0;
if (staffCount > 0) {
step3Section.style.display = "block";
updateProgressBar(2);
} else {
step3Section.style.display = "none";
updateProgressBar(1);
}
});
/* -----------------------------
18. Obsługa wyboru typu umowy
----------------------------- */
contractTypeInput.addEventListener("change", () => {
const contractType = contractTypeInput.value;
if (contractType === "uop" || contractType === "b2b") {
contractOptions.style.display = "block";
// Ustawienie mediany na 10,000 PLN niezależnie od typu umowy
document.getElementById("median-value").textContent = formatCurrency(MEDIAN_SALARY);
// Ukryj median-salary i custom-salary-container na początku
medianSalary.style.display = "none";
customSalaryContainer.style.display = "none";
// Resetuj wybór opcji wynagrodzenia
salaryOption.value = "";
} else {
// Jeśli nie wybrano typu umowy, ukryj contract-options
contractOptions.style.display = "none";
salaryOption.value = "";
medianSalary.style.display = "none";
customSalaryContainer.style.display = "none";
}
});
/* -----------------------------
19. Obsługa wyboru opcji wynagrodzenia
----------------------------- */
salaryOption.addEventListener("change", () => {
const salaryChoice = salaryOption.value;
if (salaryChoice === "median") {
medianSalary.style.display = "block";
customSalaryContainer.style.display = "none";
} else if (salaryChoice === "custom") {
medianSalary.style.display = "none";
customSalaryContainer.style.display = "block";
} else {
medianSalary.style.display = "none";
customSalaryContainer.style.display = "none";
}
});
/* -----------------------------
15. Po załadowaniu DOM
----------------------------- */
document.addEventListener('DOMContentLoaded', () => {
const numberInputs = document.querySelectorAll('input[type="number"]');
numberInputs.forEach(input => {
input.addEventListener('input', () => {
// Walidacja w czasie rzeczywistym
const errorId = input.id + "-error";
validateInputInRealTime(input, errorId);
});
});
const selectInputs = document.querySelectorAll('select');
selectInputs.forEach(select => {
select.addEventListener('change', () => {
// Ukryj komunikaty błędów po zmianie wyboru
const errorId = select.id + "-error";
const errorDiv = document.getElementById(errorId);
if (errorDiv) {
errorDiv.style.display = 'none';
}
});
});
updateProgressBar(1);
// Inicjalizacja sekcji rozwijanych
setupExpandableSection("expand-basic", "basic-content");
setupExpandableSection("expand-medium", "medium-content");
setupExpandableSection("expand-premium", "premium-content");
setupExpandableSection("expand-zero-costs", "zero-costs-content");
setupExpandableSection("expand-hidden-costs", "hidden-costs-description"); // Nowa sekcja rozwijana dla >0 IT staff
});
/* -----------------------------
16. Eventy przycisków
----------------------------- */
calculateButton.addEventListener("click", calculateCosts);
collapseButton.addEventListener("click", collapseResults);
/* -----------------------------
20. Animacja Liczb w Przykładzie
----------------------------- */
function animateNumbersExample() {
const exampleSavings = document.getElementById("example-savings");
const exampleCosts = document.getElementById("example-costs");
const exampleRoi = document.getElementById("example-roi");
// Funkcja pomocnicza do animacji liczb
function animateNumber(element, start, end, duration) {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
const current = Math.floor(start + (end - start) * progress);
element.textContent = progress < 1 ? current.toLocaleString('pl-PL') + ' PLN' : end.toLocaleString('pl-PL') + ' PLN';
if (progress < 1) {
window.requestAnimationFrame(step);
}
};
window.requestAnimationFrame(step);
}
// Animacja ROI jako liczby zmiennoprzecinkowej
function animateRoi(element, start, end, duration) {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
const current = progress < 1 ? (start + (end - start) * progress).toFixed(1) : end.toFixed(1);
element.textContent = progress < 1 ? current + '%' : end.toFixed(1) + '%';
if (progress < 1) {
window.requestAnimationFrame(step);
}
};
window.requestAnimationFrame(step);
}
// Rozpocznij animacje
animateNumber(exampleSavings, 0, 188418, 1500); // 1.5 sekundy
animateNumber(exampleCosts, 0, 84000, 1500); // 1.5 sekundy
animateRoi(exampleRoi, 0, 224.3, 1500); // 1.5 sekundy
}
/* -----------------------------
21. Modyfikacja funkcji calculateCosts
----------------------------- */
function calculateCosts() {
if (!validateAllInputs()) return;
const itStaff = parseInt(itStaffInput.value);
if (!validateInputs(itStaff)) return;
const serviceLevel = serviceLevelInput.value;
const contractType = contractTypeInput.value;
const salaryChoice = salaryOption.value;
// Sprawdzenie, czy wybrano poziom wsparcia
if (!serviceLevel) {
alert("Proszę wybrać poziom wsparcia.");
return;
}
if (itStaff === 0) {
const baseSalaryUOP = MEDIAN_SALARY; // Wynagrodzenie netto dla UoP
const baseSalaryB2B = MEDIAN_SALARY; // Wynagrodzenie netto dla B2B
const uopCosts = calculateEmploymentCosts(baseSalaryUOP, 'uop');
const b2bCosts = calculateEmploymentCosts(baseSalaryB2B, 'b2b');
const outsourcingCost = SERVICE_COSTS[serviceLevel];
// Obliczenie kosztów ukrytych (stałe, niezależne od liczby informatyków)
const hiddenCosts = Object.values(HIDDEN_COSTS).reduce((sum, cost) => sum + cost, 0);
// Sumowanie kosztów dla UoP i B2B z uwzględnieniem ukrytych kosztów
const totalUop = uopCosts.totalCost + hiddenCosts;
const totalB2b = b2bCosts.totalCost + hiddenCosts;
// Aktualizacja tabeli z wynikami
document.getElementById('zero-salary-uop').textContent = formatCurrency(uopCosts.netSalary);
document.getElementById('zero-salary-b2b').textContent = formatCurrency(b2bCosts.netSalary);
document.getElementById('zero-employer-cost').textContent = formatCurrency(uopCosts.additionalCosts);
document.getElementById('zero-vat-cost').textContent = '-';
// Aktualizacja łącznych kosztów miesięcznych
document.getElementById('zero-total-monthly-uop').textContent = formatCurrency(totalUop);
document.getElementById('zero-total-monthly-b2b').textContent = formatCurrency(totalB2b);
document.getElementById('zero-outsourcing-monthly').textContent = formatCurrency(outsourcingCost);
// Aktualizacja łącznych kosztów rocznych
document.getElementById('zero-total-annual-uop').textContent = formatCurrency(totalUop * 12);
document.getElementById('zero-total-annual-b2b').textContent = formatCurrency(totalB2b * 12);
document.getElementById('zero-outsourcing-annual').textContent = formatCurrency(outsourcingCost * 12);
// Obliczenie oszczędności
const maxCost = Math.max(totalUop, totalB2b);
const monthlySavings = maxCost - outsourcingCost;
const annualSavings = monthlySavings * 12;
const threeYearSavings = annualSavings * 3;
// Aktualizacja oszczędności w interfejsie
document.getElementById('zero-savings').textContent = formatCurrency(threeYearSavings);
// Wyświetlenie sekcji wyników
zeroItResults.style.display = "block";
// Dodanie animacji i przewinięcie do wyników
setTimeout(() => {
document.querySelector('.intro-message').classList.add('show');
}, 50);
resultsSection.style.display = "none";
collapseButton.style.display = "block";
updateProgressBar(2);
scrollToResults();
return;
}
// Gdy itStaff > 0 - obliczenia dla in-house vs outsourcing
if (itStaff > 0) {
if (!contractType) {
alert("Proszę wybrać rodzaj umowy.");
return;
}
if (!salaryChoice) {
alert("Proszę wybrać opcję wynagrodzenia.");
return;
}
let totalNetSalary = 0;
if (salaryChoice === "median") {
totalNetSalary = MEDIAN_SALARY;
} else if (salaryChoice === "custom") {
totalNetSalary = parseFloat(customSalaryInput.value) || 0;
if (totalNetSalary <= 0) {
alert("Wprowadź poprawną kwotę netto.");
return;
}
}
// Obliczenie kosztów zatrudnienia
const employmentCosts = calculateEmploymentCosts(totalNetSalary, contractType);
const hiddenCosts = calculateHiddenCosts(itStaff);
const totalMonthlyInhouse = (employmentCosts.totalCost * itStaff) + hiddenCosts;
const annualInhouse = totalMonthlyInhouse * 12;
const monthlyOutsourcing = SERVICE_COSTS[serviceLevel];
const annualOutsourcing = monthlyOutsourcing * 12;
const monthlySavings = totalMonthlyInhouse - monthlyOutsourcing;
const annualSavings = monthlySavings * 12;
const threeYearsSavings = annualSavings * 3;
const roi = calculateROI(annualSavings, annualOutsourcing) || 0;
// Obliczenie szczegółowych kosztów ukrytych
const licensesTotal = HIDDEN_COSTS.licenses * itStaff;
const officeTotal = HIDDEN_COSTS.office * itStaff;
const equipmentTotal = HIDDEN_COSTS.equipment * itStaff;
const trainingTotal = HIDDEN_COSTS.training * itStaff;
const recruitmentTotal = HIDDEN_COSTS.recruitment * itStaff;
const serverRoomTotal = HIDDEN_COSTS.serverRoom;
const hiddenTotalCost = licensesTotal + officeTotal + equipmentTotal + trainingTotal + recruitmentTotal + serverRoomTotal;
// Aktualizacja tabeli kosztów ukrytych
if (contractType === "uop") {
hiddenAdditionalCostUnit.textContent = "31.74%";
hiddenAdditionalCostCount.textContent = itStaff;
hiddenAdditionalCostTotal.textContent = formatCurrency(employmentCosts.additionalCosts * itStaff);
} else if (contractType === "b2b") {
hiddenAdditionalCostUnit.textContent = "-"; // Brak dodatkowych kosztów dla B2B
hiddenAdditionalCostCount.textContent = "-";
hiddenAdditionalCostTotal.textContent = "-";
}
hiddenLicensesCount.textContent = itStaff;
hiddenLicensesTotal.textContent = formatCurrency(licensesTotal);
hiddenOfficeCount.textContent = itStaff;
hiddenOfficeTotal.textContent = formatCurrency(officeTotal);
hiddenEquipmentCount.textContent = itStaff;
hiddenEquipmentTotal.textContent = formatCurrency(equipmentTotal);
hiddenTrainingCount.textContent = itStaff;
hiddenTrainingTotal.textContent = formatCurrency(trainingTotal);
hiddenRecruitmentCount.textContent = itStaff;
hiddenRecruitmentTotal.textContent = formatCurrency(recruitmentTotal);
hiddenServerRoomTotal.textContent = formatCurrency(serverRoomTotal);
hiddenTotal.textContent = formatCurrency(hiddenTotalCost + (employmentCosts.additionalCosts * itStaff));
// Aktualizacja wyników w UI
selectedLevelText.textContent =
serviceLevel.charAt(0).toUpperCase() + serviceLevel.slice(1);
selectedLevelSummary.textContent = selectedLevelText.textContent;
animateValue(inhouseMonthly, 0, totalMonthlyInhouse, 1000);
animateValue(outsourcingMonthly, 0, monthlyOutsourcing, 1000);
animateValue(differenceMonthly, 0, monthlySavings, 1000);
animateValue(inhouseAnnual, 0, annualInhouse, 1000);
animateValue(outsourcingAnnual, 0, annualOutsourcing, 1000);
animateValue(differenceAnnual, 0, annualSavings, 1000);
roiElement.textContent = `${roi.toFixed(1)}%`;
roiSummary.textContent = `${roi.toFixed(1)}%`;
savingsAmount.textContent = formatCurrency(threeYearsSavings);
// Aktualizacja łącznych kosztów w tabeli
document.getElementById('inhouse-monthly').textContent = formatCurrency(totalMonthlyInhouse);
document.getElementById('outsourcing-monthly').textContent = formatCurrency(monthlyOutsourcing);
document.getElementById('difference-monthly').textContent = formatCurrency(monthlySavings);
document.getElementById('inhouse-annual').textContent = formatCurrency(annualInhouse);
document.getElementById('outsourcing-annual').textContent = formatCurrency(annualOutsourcing);
document.getElementById('difference-annual').textContent = formatCurrency(annualSavings);
// Pokaż sekcję z wynikami
zeroItResults.style.display = "none";
resultsSection.style.display = "block";
setTimeout(() => {
resultsSection.classList.add("show");
// Dodanie klasy show do roi-box, aby animacja fade-in zadziałała
const roiBox = document.getElementById('roi-box');
if (roiBox) {
roiBox.classList.add('show');
}
// Rozpoczęcie animacji liczb w przykładowym obliczeniu
animateNumbersExample();
}, 50);
collapseButton.style.display = "block";
updateProgressBar(3);
scrollToResults();
}
}
/* Inteligentne scrollowanie */
function smoothScroll(element, offset = 0) {
const targetPosition = element.getBoundingClientRect().top + window.pageYOffset - offset;
const startPosition = window.pageYOffset;
const distance = targetPosition - startPosition;
const duration = 1000;
let start = null;
function animation(currentTime) {
if (start === null) start = currentTime;
const timeElapsed = currentTime - start;
const run = ease(timeElapsed, startPosition, distance, duration);
window.scrollTo(0, run);
if (timeElapsed < duration) requestAnimationFrame(animation);
}
// Funkcja ease-out dla płynniejszego scrollowania
function ease(t, b, c, d) {
t /= d;
return -c * t * (t - 2) + b;
}
requestAnimationFrame(animation);
}
// Zastąp obecną funkcję scrollToResults tą nową wersją:
function scrollToResults() {
const resultsSection = document.querySelector('.results-section') || document.querySelector('#zero-it-results');
if (resultsSection) {
// Pobierz offset tylko dla kalkulatora, nie globalnie
const offsetTop = resultsSection.getBoundingClientRect().top + window.pageYOffset;
window.scrollTo({
top: offsetTop - 50, // 50px marginesuscroll-behavior: smooth !important;
behavior: 'smooth',
});
}
}
function setupExpandableSection(triggerId, contentId) {
const trigger = document.getElementById(triggerId);
const content = document.getElementById(contentId);
if (!trigger || !content) return;
trigger.addEventListener('click', function() {
// Zamknij wszystkie inne sekcje
document.querySelectorAll('.expanded-content').forEach(section => {
if (section !== content) {
section.classList.remove('active');
const otherTrigger = document.querySelector(`[data-content="${section.id}"]`);
if (otherTrigger) {
const levelType = otherTrigger.id.split('-')[1];
otherTrigger.textContent = `Rozwiń zakres usług dla poziomu ${levelType.charAt(0).toUpperCase() + levelType.slice(1)}`;
}
}
});
// Przełącz aktualną sekcję
const isExpanded = content.classList.contains('active');
const levelType = trigger.id.split('-')[1];
if (isExpanded) {
content.classList.remove('active');
trigger.textContent = `Rozwiń zakres usług dla poziomu ${levelType.charAt(0).toUpperCase() + levelType.slice(1)}`;
} else {
content.classList.add('active');
trigger.textContent = `Zwiń zakres usług dla poziomu ${levelType.charAt(0).toUpperCase() + levelType.slice(1)}`;
// Przewiń do zawartości
setTimeout(() => {
content.scrollIntoView({
behavior: 'smooth',
block: 'nearest'
});
}, 300);
}
});
// Dodaj atrybut data-content do przycisku dla łatwiejszej identyfikacji
trigger.setAttribute('data-content', contentId);
}
</script>
<button id="scroll-to-top" style="display: none;">⬆️ Do góry</button>
</body>
</html>
</div>