JSFiddle - React, Tailwind, and code Playground

by SvennMats

HTML

<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">

<div class="calculator-card">
  <h2>💰 Hvor mye kan du spare?</h2>
  <p class="subtitle">Se effekten av å bytte til Svenn Kalkulasjon</p>

  <div class="input-section">
    <div class="input-group">
      <div class="label-row">
        <label>Tid brukt per tilbud i dag (min)</label>
        <span id="val-time" class="highlight-value">60 min</span>
      </div>
      <input type="range" id="input-time" min="10" max="240" step="5" value="60">
    </div>

    <div class="input-group">
      <div class="label-row">
        <label>Antall tilbud i uken (snitt)</label>
        <span id="val-amount" class="highlight-value">5 stk</span>
      </div>
      <input type="range" id="input-amount" min="1" max="50" step="1" value="5">
    </div>

    <div class="input-group">
      <div class="label-row">
        <label>Din timespris (kr)</label>
        <span id="val-rate" class="highlight-value">850 kr</span>
      </div>
      <input type="range" id="input-rate" min="300" max="3000" step="50" value="850">
    </div>
  </div>

  <hr>

  <div class="result-section">
    <div class="result-row">
      <span>Timer spart pr mnd:</span>
      <span id="res-hours" class="res-value">0 t</span>
    </div>
    <div class="result-row">
      <span>Verdi av spart tid:</span>
      <span id="res-gross" class="res-value">0 kr</span>
    </div>
    <div class="result-row cost-row">
      <span>Kostnad Svenn:</span>
      <span class="res-value">-1 599 kr</span>
    </div>
    
    <div class="total-box">
      <span class="total-label">Din månedlige gevinst:</span>
      <span id="res-net" class="total-value">0 kr</span>
    </div>
    
    <p class="disclaimer">Beregningen baserer seg på at du bruker 10% av tiden du bruker i dag, samt 4,3 uker pr mnd.</p>
  </div>
</div>

CSS

:root {
  --svenn-dark: #241D2D;   /* Din spesifiserte mørkeblå */
  --svenn-orange: #F96529; /* Din spesifiserte oransje */
  --text-grey: #64748b;
}

body {
  font-family: 'Inter', sans-serif;
  background-color: transparent;
  padding: 15px;
  margin: 0;
}

.calculator-card {
  background: #ffffff;
  max-width: 480px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 16px;
  box-shadow: 0 10px 40px rgba(36, 29, 45, 0.12);
  border: 1px solid #edf2f7;
}

h2 {
  margin: 0 0 10px 0;
  font-size: 1.6rem;
  text-align: center;
  color: var(--svenn-dark);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.subtitle {
  text-align: center;
  color: var(--text-grey);
  margin-bottom: 30px;
  font-size: 0.95rem;
}

.input-group {
  margin-bottom: 25px;
}

.label-row {
  display: flex;
  justify-content: space-between;
  margin-bottom: 12px;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--svenn-dark);
}

.highlight-value {
  color: var(--svenn-orange);
  font-weight: 700;
  font-size: 1.1rem;
}

/* Custom Slider Styling */
input[type=range] {
  width: 100%;
  -webkit-appearance: none;
  background: transparent;
}

input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  height: 24px;
  width: 24px;
  border-radius: 50%;
  background: #ffffff;
  border: 3px solid var(--svenn-orange);
  cursor: pointer;
  margin-top: -10px;
  box-shadow: 0 4px 10px rgba(249, 101, 41, 0.2);
  transition: all 0.2s ease;
}

input[type=range]::-webkit-slider-runnable-track {
  width: 100%;
  height: 6px;
  background: #e2e8f0;
  border-radius: 10px;
}

hr {
  border: 0;
  border-top: 2px solid #f1f5f9;
  margin: 30px 0;
}

.result-row {
  display: flex;
  justify-content: space-between;
  margin-bottom: 12px;
  font-size: 1rem;
  color: var(--svenn-dark);
}

.res-value {
  font-weight: 600;
}

.cost-row {
  color: #ef4444;
  opacity: 0.9;
}

.total-box {
 ...

JavaScript

const WEEKS_PER_MONTH = 4.33;
const COST_SVENN = 1599;

const inputs = {
  time: document.getElementById('input-time'),
  amount: document.getElementById('input-amount'),
  rate: document.getElementById('input-rate')
};

const displays = {
  time: document.getElementById('val-time'),
  amount: document.getElementById('val-amount'),
  rate: document.getElementById('val-rate')
};

const results = {
  hours: document.getElementById('res-hours'),
  gross: document.getElementById('res-gross'),
  net: document.getElementById('res-net')
};

const formatCurrency = (num) => {
  return new Intl.NumberFormat('no-NO', { 
    style: 'currency', 
    currency: 'NOK', 
    maximumFractionDigits: 0 
  }).format(num);
};

function calculate() {
  const t = parseInt(inputs.time.value);
  const a = parseInt(inputs.amount.value);
  const r = parseInt(inputs.rate.value);

  displays.time.textContent = `${t} min`;
  displays.amount.textContent = `${a} stk`;
  displays.rate.textContent = `${r} kr`;

  const oldTotal = t * a;
  const newTotal = oldTotal * 0.10;
  const savedHours = ((oldTotal - newTotal) * WEEKS_PER_MONTH) / 60;
  const gross = savedHours * r;
  const net = gross - COST_SVENN;

  results.hours.textContent = `${Math.round(savedHours)} timer`;
  results.gross.textContent = formatCurrency(gross);
  results.net.textContent = formatCurrency(net);
}

Object.values(inputs).forEach(i => i.addEventListener('input', calculate));
calculate();