{"id":313,"date":"2026-03-08T14:54:08","date_gmt":"2026-03-08T14:54:08","guid":{"rendered":"https:\/\/celean.fi\/?page_id=313"},"modified":"2026-03-09T16:22:16","modified_gmt":"2026-03-09T16:22:16","slug":"optimoinnin-saaston-laskuri","status":"publish","type":"page","link":"https:\/\/celean.fi\/index.php\/optimoinnin-saaston-laskuri\/","title":{"rendered":"Optimoinnin s\u00e4\u00e4st\u00f6n laskuri"},"content":{"rendered":"    <section\n      id=\"cv-1\"\n      class=\"cv-wrap\"\n      role=\"region\"\n      aria-label=\"Varaston arvon alenema -laskuri\"\n      data-autocalc=\"0\"\n      data-fee-fixed=\"6250\"\n      data-fee-rate=\"0.10\"\n      data-fee-cap=\"30000\"\n      style=\"--primary: #44a369;\n             --card-bg: #111;\n             --text:    #F3F4F6;\n             --muted:   #9CA3AF;\n             --stroke:  #262626;\n             --radius:  20px;\n             --maxw:    100%;\n             --shadow:  0 1px 1px rgba(0,0,0,.12), 0 6px 18px rgba(0,0,0,.28);\">\n      <div class=\"cv-card\">\n        <h2 class=\"cv-title\">Laske optimoinnilla saavutettava s\u00e4\u00e4st\u00f6<\/h2>\n\n        <div class=\"cv-group\">\n          <label for=\"cv-1-varasto\" class=\"cv-label\">Nykyinen varaston arvo<\/label>\n          <div class=\"cv-input-with-unit\">\n            <input id=\"cv-1-varasto\" class=\"cv-input\"\n                   type=\"text\" inputmode=\"decimal\" pattern=\"[0-9 ,\\.]*\"\n                   placeholder=\"Esim. 200 000\"\n                   aria-describedby=\"cv-1-varasto-help\">\n            <span class=\"cv-unit\">\u20ac<\/span>\n          <\/div>\n\n        <\/div>\n\n        <div class=\"cv-group\">\n          <label for=\"cv-1-alenema\" class=\"cv-label\">Saavutettu s\u00e4\u00e4st\u00f6 prosentteina (%)<\/label>\n          <div class=\"cv-input-with-unit\">\n            <input id=\"cv-1-alenema\" class=\"cv-input\"\n                   type=\"text\" inputmode=\"decimal\" pattern=\"[0-9 ,\\.]*\"\n                   placeholder=\"Esim. 10\"\n                   aria-describedby=\"cv-1-alenema-help\">\n            <span class=\"cv-unit\">%<\/span>\n          <\/div>\n\n        <\/div>\n\n        <button type=\"button\" class=\"cv-button\" data-action=\"calc\">Laske<\/button>\n\n        <div class=\"cv-result\" aria-live=\"polite\">\n          <div class=\"cv-line\">\n            <span>Vapautettu p\u00e4\u00e4oma<\/span>\n            <strong class=\"cv-out cv-alenema\">\u2013<\/strong>\n          <\/div>\n        <\/div>\n\n        <p class=\"cv-disclaimer\">\n          Laskuri on suuntaa\u2011antava. Tietoja ei l\u00e4hetet\u00e4 eik\u00e4 tallenneta.\n        <\/p>\n      <\/div>\n\n      <style>\n        \/* Kontti *\/\n        #cv-1.cv-wrap{\n          color: var(--text);\n          display:block;\n          margin:24px auto;\n          font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen,Ubuntu,Cantarell,\"Helvetica Neue\",Arial,\"Noto Sans\",sans-serif;\n        }\n        \/* Kortti *\/\n        #cv-1 .cv-card{\n          max-width: var(--maxw);\n          background: var(--card-bg);\n          border: 1px solid var(--stroke);\n          border-radius: var(--radius);\n          box-shadow: var(--shadow);\n          padding: clamp(18px, 4vw, 28px);\n          overflow: hidden;\n        }\n        #cv-1 .cv-title{\n          font-size: clamp(22px, 2.4vw, 32px);\n          line-height: 1.15; margin: 0 0 8px;\n          color:#ffffff;\n          position: relative; padding-bottom: 6px;\n        }\n        #cv-1 .cv-title::after{\n          content:\"\"; position:absolute; left:0; bottom:0; width:0px; height:3px;\n          background: var(--primary); border-radius:4px; opacity:.9;\n        }\n\n        \/* Ryhm\u00e4t & labelit *\/\n        #cv-1 .cv-group{ margin:16px 0 20px; }\n        #cv-1 .cv-label{ font-weight:700; display:block; margin:0 0 10px; }\n        #cv-1 .cv-help{ color:var(--muted); display:block; margin-top:8px; }\n\n        \/* Input wrapper kantaa reunan ja kulmat *\/\n        #cv-1 .cv-input-with-unit{\n          position: relative;\n          background: #111315;\n          border: 1.5px solid var(--stroke);\n          border-radius: 12px;\n        }\n        #cv-1 .cv-input{\n          width:100%; padding:14px 56px 14px 14px; font-size:18px;\n          background: transparent; color:var(--text);\n          border:0; outline:none;\n        }\n        #cv-1 .cv-input::placeholder{ color:#7D8691; }\n        #cv-1 .cv-input:focus{ box-shadow:none; }\n        #cv-1 .cv-input-with-unit:has(.cv-input:focus),\n        #cv-1 .cv-input-with-unit.is-focus{\n          border-color: var(--primary);\n          box-shadow: 0 0 0 4px color-mix(in srgb, var(--primary) 18%, transparent);\n          background:#0F1214;\n        }\n        #cv-1 .cv-unit{\n          position:absolute; right:12px; top:50%; transform:translateY(-50%);\n          color:var(--muted); font-weight:700; pointer-events:none;\n        }\n\n        \/* Nappi *\/\n        #cv-1 .cv-button{\n          width:100%; appearance:none;\n          background:var(--primary); color:#07130B;\n          border:0; border-radius:999px;\n          padding:13px 22px; font-size:18px; font-weight:800; cursor:pointer;\n          transition:transform .02s ease, filter .15s ease, background .15s ease;\n        }\n        #cv-1 .cv-button:hover{ filter:brightness(0.95); }\n        #cv-1 .cv-button:active{ transform:translateY(1px); }\n\n        \/* Tulokset *\/\n        #cv-1 .cv-result{\n          margin-top:18px; border:1px dashed var(--stroke); border-radius:12px;\n          padding:14px 16px; background:#0D0F10;\n        }\n        #cv-1 .cv-line{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:7px 0; }\n        #cv-1 .cv-line + .cv-line{ border-top:1px solid #1C1F22; }\n        #cv-1 .cv-out{ font-size:20px; }\n        #cv-1 .cv-out.cv-alenema{ color:var(--primary); }\n        #cv-1 .cv-out.cv-kustannus{ color:#F3F4F6; }\n        #cv-1 .cv-out.cv-netto{ color:#44a369; }\n        #cv-1 .cv-out.cv-netto.is-negative{ color:#ff6b6b; }\n\n      <\/style>\n\n      <script>\n        (function(){\n          var root = document.getElementById('cv-1');\n          if (!root) return;\n\n          var nfEUR = new Intl.NumberFormat('fi-FI', { style: 'currency', currency: 'EUR', minimumFractionDigits: 2 });\n\n          var elVarasto = root.querySelector('#cv-1-varasto');\n          var elAlenema = root.querySelector('#cv-1-alenema');\n          var outAlenema = root.querySelector('.cv-alenema');\n          var outUusi    = root.querySelector('.cv-uusi'); \/\/ saattaa puuttua, ok\n          var btn        = root.querySelector('[data-action=\"calc\"]');\n\n          \/\/ Focus-fallback luokalla jos selaimessa ei ole :has-tukea\n          root.addEventListener('focusin', function(e){\n            var w = e.target && e.target.closest('.cv-input-with-unit');\n            if (w) w.classList.add('is-focus');\n          });\n          root.addEventListener('focusout', function(e){\n            var w = e.target && e.target.closest('.cv-input-with-unit');\n            if (w) w.classList.remove('is-focus');\n          });\n\n          \/\/ Luetaan data-attribuuteista hinnoittelun parametrit\n          var feeFixed = parseFloat(root.getAttribute('data-fee-fixed') || '6250');\n          var feeRate  = parseFloat(root.getAttribute('data-fee-rate')  || '0.10');\n          var feeCap   = parseFloat(root.getAttribute('data-fee-cap')   || '30000');\n          var autocalc = root.getAttribute('data-autocalc') === '1';\n\n          function parseFinnFloat(v){\n            if (v === null || v === undefined) return NaN;\n            v = String(v).replace(\/\\s\/g,'').replace(',', '.');\n            return parseFloat(v);\n          }\n\n          function calc(){\n            const varasto   = parseFinnFloat(elVarasto.value);\n            const prosentti = parseFinnFloat(elAlenema.value);\n\n            \/\/ Tyhjenn\u00e4, jos inputit eiv\u00e4t kelpaa\n            if (isNaN(varasto) || isNaN(prosentti) || prosentti < 0){\n              if (outAlenema) outAlenema.textContent = '\u2013';\n\n              const outKust = root.querySelector('.cv-kustannus');\n              const outNet  = root.querySelector('.cv-netto');\n              if (outKust) outKust.textContent = '\u2013';\n              if (outNet)  { outNet.textContent = '\u2013'; outNet.classList.remove('is-negative'); }\n\n              if (outUusi) outUusi.textContent = '\u2013';\n              return;\n            }\n\n            const p = Math.min(Math.max(prosentti, 0), 100);\n\n            \/\/ 1) Arvon alenema\n            const alenemaEuro = varasto * (p \/ 100);\n\n            \/\/ 2) Palvelun hinta: feeFixed + feeRate * alenemasta, mutta max feeCap\n            const palveluKustRaw = feeFixed + (feeRate * alenemaEuro);\n            const palveluKust    = Math.min(feeCap, palveluKustRaw);\n\n            \/\/ 3) Nettovaikutus\n            const netto = alenemaEuro - palveluKust;\n\n            \/\/ 4) (valinnainen) Uusi varaston arvo\n            const uusi = Math.max(0, varasto - alenemaEuro);\n\n            \/\/ P\u00e4ivit\u00e4 DOM\n            if (outAlenema) outAlenema.textContent = nfEUR.format(alenemaEuro);\n\n            const outKust = root.querySelector('.cv-kustannus');\n            if (outKust) outKust.textContent = nfEUR.format(palveluKust);\n\n            const outNet = root.querySelector('.cv-netto');\n            if (outNet) {\n              outNet.textContent = nfEUR.format(netto);\n              outNet.classList.toggle('is-negative', netto < 0);\n            }\n\n            if (outUusi) outUusi.textContent = nfEUR.format(uusi);\n          }\n\n          if (btn) { btn.addEventListener('click', calc); }\n          if (autocalc){\n            ['input','change','keyup'].forEach(function(ev){\n              elVarasto.addEventListener(ev, calc);\n              elAlenema.addEventListener(ev, calc);\n            });\n          }\n        })();\n      <\/script>\n    <\/section>\n    \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-313","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/celean.fi\/index.php\/wp-json\/wp\/v2\/pages\/313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/celean.fi\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/celean.fi\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/celean.fi\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/celean.fi\/index.php\/wp-json\/wp\/v2\/comments?post=313"}],"version-history":[{"count":14,"href":"https:\/\/celean.fi\/index.php\/wp-json\/wp\/v2\/pages\/313\/revisions"}],"predecessor-version":[{"id":332,"href":"https:\/\/celean.fi\/index.php\/wp-json\/wp\/v2\/pages\/313\/revisions\/332"}],"wp:attachment":[{"href":"https:\/\/celean.fi\/index.php\/wp-json\/wp\/v2\/media?parent=313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}