Kalkulator

<div class="wrap">
  <header>
    <div>
      <h1>Stabilitetsark – KG & GM (med last-tillegg)</h1>
      <p>Regner ΣW, Σ(W·KG), KG = Σ(W·KG)/ΣW, GM = KM − KG. Støtter 1,5 og 1.5. Minus brukes for lossing.</p>
    </div>

    <div class="header-right">
      <div class="mono" style="font-size:12px;opacity:.9">
        Moment = W × KG
      </div>

      <div class="vclock" aria-label="Digital klokke">
        <div class="vclock-label">KLOKKE</div>
        <div class="vclock-time mono" id="vClock">--:--:--</div>
      </div>
    </div>
  </header>

  <div class="bar">
    <div class="controls">
      <div class="field">
        <strong style="color:#0f172a">KM (m):</strong>
        <input id="km" value="4,0" inputmode="decimal">
      </div>
      <button class="primary" id="addRowBtn" type="button">+ Legg til last</button>
      <button id="resetBtn" type="button">Nullstill</button>
    </div>

      <div class="controls">
                <button id="advToggleBtn" type="button">Avansert: AV</button>
              </div>
  </div>

  <table>
    <thead>
      <tr>
        <th>Beskrivelse</th>
        <th class="center">Type</th>
        <th>Vekt W (t)</th>
        <th>KG (m)</th>
        <th>Moment (t·m)</th>
        <th class="center">Handling</th>
      </tr>
    </thead>

    <tbody id="tbody">
      <!-- Start row (locked) -->
      <tr class="row locked">
        <td class="label">
          <input class="desc" value="Start deplasement" disabled>
        </td>
        <td class="center">
          <select class="sign" disabled>
            <option value="1" selected>+</option>
            <option value="-1">−</option>
          </select>
        </td>
        <td class="right"><input class="w" value="570" inputmode="decimal"></td>
        <td class="right"><input class="kg" value="3" inputmode="decimal"></td>
        <td class="right mono moment">= 0,000</td>
        <td class="center mono">—</td>
      </tr>

      <!-- Load rows -->
      <tr class="row">
        <td class="label">
          <input class="desc" value="Lasting #1" placeholder="Skriv navn (f.eks. Lossing/Lasting)">
        </td>
        <td class="center">
          <select class="sign">
            <option value="1" selected>+</option>
            <option value="-1">−</option>
          </select>
        </td>
        <td class="right"><input class="w" value="20" inputmode="decimal"></td>
        <td class="right"><input class="kg" value="1,5" inputmode="decimal"></td>
        <td class="right mono moment">= 0,000</td>
        <td class="center row-actions"><button type="button" class="delBtn">Slett</button></td>
      </tr>

      <tr class="row">
        <td class="label">
          <input class="desc" value="Lasting #2" placeholder="Skriv navn (f.eks. Lossing/Lasting)">
        </td>
        <td class="center">
          <select class="sign">
            <option value="1" selected>+</option>
            <option value="-1">−</option>
          </select>
        </td>
        <td class="right"><input class="w" value="30" inputmode="decimal"></td>
        <td class="right"><input class="kg" value="3,9" inputmode="decimal"></td>
        <td class="right mono moment">= 0,000</td>
        <td class="center row-actions"><button type="button" class="delBtn">Slett</button></td>
      </tr>

      <!-- Totals -->
      <tr class="totals">
        <td class="label">SUM</td>
        <td></td>
        <td class="right mono" id="sumW">= 0,000 t</td>
        <td></td>
        <td class="right mono" id="sumM">= 0,000 t·m</td>
        <td></td>
      </tr>
    </tbody>
  </table>

  <div class="kpi">
    <div class="box">
      <div class="k">KG (ny)</div>
      <div class="v mono" id="kgNew">0,000</div>
      <div class="u">meter</div>
    </div>
    <div class="box">
      <div class="k">GM (ny)</div>
      <div class="v mono" id="gmNew">0,000</div>
      <div class="u">meter</div>
    </div>
    <div class="box">
      <div class="k">Kontroll</div>
      <div class="v mono" id="checkLine">KG = ΣM / ΣW</div>
      <div class="u">visning</div>
    </div>
  </div>

  <!-- Advanced -->
  <div id="advanced" class="advanced">
    <div class="advanced-head">
      <div class="title">Avansert</div>
      <div class="field">Min GM-krav (m): <input id="minGM" value="0,15" inputmode="decimal"></div>
    </div>

    <div class="advanced-grid">
      <div class="box">
        <div class="k">Start KG</div>
        <div class="v mono" id="startKG">0,000</div>
        <div class="u">meter</div>
      </div>

      <div class="box">
        <div class="k">ΔKG (ny − start)</div>
        <div class="v mono" id="deltaKG">0,000</div>
        <div class="u">meter</div>
      </div>

      <div class="box">
        <div class="k">Status GM</div>
        <div class="v mono" id="gmStatus">—</div>
        <div class="u">OK / Ikke OK</div>
      </div>

      <div class="box">
        <div class="k">Formel</div>
        <div class="v mono" id="formulaLine">ΣM / ΣW</div>
        <div class="u">tall-linje</div>
      </div>
    </div>

    <div class="note">
      “Lovlig” avgjøres av kravene du bruker (stabilitetshefte/IS Code/flaggekrav). Her sjekker vi kun mot en valgt min GM.
    </div>
  </div>
</div>

<script>
  // ---------- Helpers ----------
  function parseNum(v){
    v = String(v ?? "").trim().replace(/\s+/g,"");
    if (!v) return 0;
    v = v.replace(",", ".");
    const n = Number(v);
    return Number.isFinite(n) ? n : 0;
  }
  function fmt(n, decimals=3){
    return n.toFixed(decimals).replace(".", ",");
  }

  // ---------- Main calculation ----------
  function calculateMain(){
    const rows = document.querySelectorAll("#tbody tr.row");
    let sumW = 0;
    let sumM = 0;

    rows.forEach(r => {
      const sign = parseNum(r.querySelector(".sign")?.value) || 1; // +1 eller -1
      const wRaw = parseNum(r.querySelector(".w")?.value);
      const kg = parseNum(r.querySelector(".kg")?.value);

      const w = sign * wRaw; // minus for lossing
      const m = w * kg;

      const momentCell = r.querySelector(".moment");
      if (momentCell) momentCell.textContent = "= " + fmt(m, 3);

      sumW += w;
      sumM += m;
    });

    document.getElementById("sumW").textContent = "= " + fmt(sumW, 3) + " t";
    document.getElementById("sumM").textContent = "= " + fmt(sumM, 3) + " t·m";

    const KGnew = (sumW !== 0) ? (sumM / sumW) : 0;
    const KM = parseNum(document.getElementById("km").value);
    const GMnew = KM - KGnew;

    document.getElementById("kgNew").textContent = fmt(KGnew, 3);
    document.getElementById("gmNew").textContent = fmt(GMnew, 3);
    document.getElementById("checkLine").textContent =
      "KG = " + fmt(sumM, 3) + " / " + fmt(sumW, 3) + " = " + fmt(KGnew, 3);

    calculateAdvanced();
  }

  // ---------- Advanced ----------
  function calculateAdvanced(){
    const adv = document.getElementById("advanced");
    if (!adv.classList.contains("show")) return;

    const startRow = document.querySelector("#tbody tr.row.locked");
    const startKG = parseNum(startRow.querySelector(".kg").value);

    const rows = document.querySelectorAll("#tbody tr.row");
    let sumW = 0, sumM = 0;
    rows.forEach(r=>{
      const sign = parseNum(r.querySelector(".sign")?.value) || 1;
      const wRaw = parseNum(r.querySelector(".w")?.value);
      const kg = parseNum(r.querySelector(".kg")?.value);
      const w = sign * wRaw;
      sumW += w;
      sumM += w * kg;
    });

    const KGnew = (sumW !== 0) ? (sumM / sumW) : 0;
    const KM = parseNum(document.getElementById("km").value);
    const GMnew = KM - KGnew;

    const delta = KGnew - startKG;
    const minGM = parseNum(document.getElementById("minGM").value);

    document.getElementById("startKG").textContent = fmt(startKG, 3);
    document.getElementById("deltaKG").textContent = fmt(delta, 3);

    const statusEl = document.getElementById("gmStatus");
    if (GMnew >= minGM){
      statusEl.textContent = "OK (GM ≥ min)";
      statusEl.className = "v mono status ok";
    } else {
      statusEl.textContent = "IKKE OK (GM < min)";
      statusEl.className = "v mono status bad";
    }

    document.getElementById("formulaLine").textContent =
      "ΣW=" + fmt(sumW,3) + " | ΣM=" + fmt(sumM,3) + " | KG=" + fmt(KGnew,3) + " | GM=" + fmt(GMnew,3);
  }

  function toggleAdvanced(){
    const adv = document.getElementById("advanced");
    const btn = document.getElementById("advToggleBtn");

    const isOn = adv.classList.toggle("show");
    btn.textContent = "Avansert: " + (isOn ? "PÅ" : "AV");

    if (isOn) calculateAdvanced();
  }

  // ---------- Row management ----------
  function renumberLoads(){
    const rows = document.querySelectorAll("#tbody tr.row:not(.locked)");
    let i = 1;
    rows.forEach(r=>{
      const desc = r.querySelector(".desc");
      if (desc){
        const v = (desc.value || "").trim();
        if (!v || /^Lasting\s+#\d+$/i.test(v)){
          desc.value = "Lasting #" + i;
        }
      }
      i++;
    });
  }

  function addLoadRow(){
    const tbody = document.getElementById("tbody");
    const totalsRow = tbody.querySelector("tr.totals");

    const tr = document.createElement("tr");
    tr.className = "row";
    tr.innerHTML = `
      <td class="label">
        <input class="desc" value="Lasting #X" placeholder="Skriv navn (f.eks. Lossing/Lasting)" />
      </td>
      <td class="center">
        <select class="sign">
          <option value="1" selected>+</option>
          <option value="-1">−</option>
        </select>
      </td>
      <td class="right"><input class="w" value="0" inputmode="decimal"></td>
      <td class="right"><input class="kg" value="0" inputmode="decimal"></td>
      <td class="right mono moment">= 0,000</td>
      <td class="center row-actions"><button type="button" class="delBtn">Slett</button></td>
    `;

    tbody.insertBefore(tr, totalsRow);
    hookRow(tr);
    renumberLoads();
    calculateMain();
  }

  function hookRow(tr){
    tr.querySelectorAll("input, select").forEach(el => el.addEventListener("input", calculateMain));
    const del = tr.querySelector(".delBtn");
    if (del){
      del.addEventListener("click", () => {
        tr.remove();
        renumberLoads();
        calculateMain();
      });
    }
  }

  function resetDefaults(){
    const start = document.querySelector("#tbody tr.row.locked");
    start.querySelector(".w").value = "570";
    start.querySelector(".kg").value = "3";

    document.querySelectorAll("#tbody tr.row:not(.locked)").forEach(r => r.remove());

    addLoadRow();
    const loads = document.querySelectorAll("#tbody tr.row:not(.locked)");
    if (loads[0]){
      loads[0].querySelector(".desc").value = "Lasting #1";
      loads[0].querySelector(".sign").value = "1";
      loads[0].querySelector(".w").value = "20";
      loads[0].querySelector(".kg").value = "1,5";
    }

    addLoadRow();
    const loads2 = document.querySelectorAll("#tbody tr.row:not(.locked)");
    if (loads2[1]){
      loads2[1].querySelector(".desc").value = "Lasting #2";
      loads2[1].querySelector(".sign").value = "1";
      loads2[1].querySelector(".w").value = "30";
      loads2[1].querySelector(".kg").value = "3,9";
    }

    document.getElementById("km").value = "4,0";
    document.getElementById("minGM").value = "0,15";

    calculateMain();
  }

  // ---------- Horizontal digital clock ----------
  function pad2(n){ return String(n).padStart(2,"0"); }
  function updateVClock(){
    const el = document.getElementById("vClock");
    if (!el) return;
    const now = new Date();
    const t = `${pad2(now.getHours())}:${pad2(now.getMinutes())}:${pad2(now.getSeconds())}`;
    el.textContent = t; // horisontal
  }
  updateVClock();
  setInterval(updateVClock, 250);



function toggleTheme(){
  const isPro = document.documentElement.getAttribute("data-theme") === "pro";
  applyTheme(isPro ? "standard" : "pro");
}

// ---------- Init ----------

  document.getElementById("addRowBtn").addEventListener("click", addLoadRow);
  document.getElementById("resetBtn").addEventListener("click", resetDefaults);
  document.getElementById("advToggleBtn").addEventListener("click", toggleAdvanced);

  document.querySelectorAll("#tbody tr.row").forEach(hookRow);
  document.querySelectorAll("#km, #minGM").forEach(inp => inp.addEventListener("input", calculateMain));


  // last valgt tema
(function(){
  const saved = localStorage.getItem("stabilityTheme");
  applyTheme(saved === "pro" ? "pro" : "standard");
})();
// first calc
  calculateMain();
</script>