From 21efdc4e9511376393a8731a7db4568ea756fe8c Mon Sep 17 00:00:00 2001 From: chrischristiansen-glitch Date: Fri, 12 Jun 2026 16:47:27 +0200 Subject: [PATCH] =?UTF-8?q?feat(CG4d):=20Prisingskalkulator=20panel=20?= =?UTF-8?q?=E2=80=94=20GCP-spend=20slider,=20tier-highlight,=20ROI-estimat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/opax.html | 164 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 162 insertions(+), 2 deletions(-) diff --git a/static/opax.html b/static/opax.html index 7d6cecb..552a005 100644 --- a/static/opax.html +++ b/static/opax.html @@ -252,6 +252,37 @@ .md-viewer blockquote{border-left:3px solid var(--accent);padding:8px 16px;margin:12px 0;background:rgba(124,92,255,.06);border-radius:0 8px 8px 0;color:var(--text-dim)} .md-viewer hr{border:none;border-top:1px solid var(--border);margin:20px 0} .md-viewer-loading{display:flex;align-items:center;justify-content:center;height:200px;color:var(--text-faint);font-family:var(--mono);font-size:13px;gap:10px} + + /* PRICING PANEL (CG4d) */ + .pricing-hero{text-align:center;padding:32px 0 28px} + .pricing-hero-title{font-size:22px;font-weight:800;letter-spacing:-0.02em;margin-bottom:6px} + .pricing-hero-sub{font-size:13px;color:var(--text-dim)} + .slider-wrap{background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius);padding:24px 28px;margin-bottom:28px} + .slider-label-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px} + .slider-label{font-size:12px;font-weight:700;color:var(--text-faint);text-transform:uppercase;letter-spacing:0.06em} + .slider-value{font-size:22px;font-weight:800;letter-spacing:-0.02em;color:var(--accent-2)} + #spend-slider{width:100%;-webkit-appearance:none;appearance:none;height:6px;border-radius:3px;background:var(--bg-3);outline:none;cursor:pointer} + #spend-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:20px;height:20px;border-radius:50%;background:var(--accent);cursor:pointer;border:3px solid var(--bg);box-shadow:0 0 0 2px var(--accent)} + #spend-slider::-moz-range-thumb{width:20px;height:20px;border-radius:50%;background:var(--accent);cursor:pointer;border:3px solid var(--bg)} + .slider-ticks{display:flex;justify-content:space-between;margin-top:8px} + .slider-tick{font-size:10px;color:var(--text-faint);font-family:var(--mono)} + .tier-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:28px} + @media(max-width:800px){.tier-grid{grid-template-columns:repeat(2,1fr)}} + .tier-card{background:var(--bg-2);border:2px solid var(--border);border-radius:var(--radius);padding:18px 16px;transition:border-color .18s,background .18s,box-shadow .18s;cursor:default} + .tier-card.active{border-color:var(--accent);background:rgba(124,92,255,.08);box-shadow:0 0 0 1px var(--accent),0 4px 24px rgba(124,92,255,.18)} + .tier-name{font-size:13px;font-weight:800;letter-spacing:0.02em;margin-bottom:4px} + .tier-range{font-size:11px;color:var(--text-faint);font-family:var(--mono);margin-bottom:12px} + .tier-price{font-size:24px;font-weight:800;letter-spacing:-0.03em} + .tier-price-sub{font-size:10px;color:var(--text-faint);margin-top:2px} + .tier-card.active .tier-name{color:var(--accent)} + .tier-card.active .tier-price{color:var(--text)} + .roi-box{background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius);padding:24px 28px;display:flex;gap:28px;align-items:center;flex-wrap:wrap} + .roi-stat{flex:1;min-width:140px} + .roi-label{font-size:11px;color:var(--text-faint);text-transform:uppercase;letter-spacing:0.06em;font-weight:600;margin-bottom:6px} + .roi-value{font-size:32px;font-weight:800;letter-spacing:-0.03em;color:var(--green)} + .roi-sub{font-size:12px;color:var(--text-dim);margin-top:4px;line-height:1.5} + .roi-divider{width:1px;height:60px;background:var(--border);flex-shrink:0} + @media(max-width:600px){.roi-divider{display:none}.roi-box{gap:16px}} @@ -278,6 +309,9 @@ + + +
+
+
🧮
+
+
Prisingskalkulator
+
CostGuard · ROI-estimat basert på GCP-spend
+
+
+
+
+
Hva koster CostGuard deg?
+
Dra slideren til din månedlige GCP-spend — se tier og ROI øyeblikkelig
+
+ +
+
+ Månedlig GCP-spend + $5 000 +
+ +
+ $0 + $25k + $50k + $75k + $100k +
+
+ +
+ +
+
+
Estimert månedlig besparelse
+
$750
+
15% av GCP-spend via optimalisering og varsler
+
+
+
+
ROI — CostGuard betaler seg
+
0.75×
+
per måned · basert på $999/mnd
+
+
+
+
Netto gevinst per år
+
$3 012
+
Besparelse minus abonnement · 12 mnd
+
+
+
+
+
@@ -504,6 +592,7 @@ const MD_DOCS = [ const PANEL_META = { jason: ['Jason', 'Gemini 2.5 Pro · ADK'], billing: ['CostGuard', 'Token & kostnad · live'], + pricing: ['Prisingskalkulator', 'CostGuard · ROI-estimat'], build: ['Cloud Build', 'Pipeline · propane-will-491900-m5'], vms: ['VM-er', 'Compute Engine · us-central1-b'], sites: ['Sites & Moduler', 'Alle Vauco-flater'], @@ -520,6 +609,67 @@ const SITES_DATA = [ {icon:'🔧', name:'Jason Chat', url:'https://opax.vauco.no/static/jason.html', desc:'Jason standalone UI', status:'live'}, ] +// PRICING TIERS (CG4d — locked from MASTERPLAN) +const TIERS = [ + { name:'Starter', min:0, max:3000, price:499, color:'var(--accent-2)' }, + { name:'Guard', min:3000, max:15000, price:999, color:'var(--accent)' }, + { name:'Shield', min:15000, max:50000, price:1999, color:'var(--amber)' }, + { name:'Enterprise', min:50000, max:Infinity,price:3500, color:'var(--danger)' }, +] + +function fmtUSD(n){ + if(n>=1000) return '$'+Math.round(n).toLocaleString('en-US') + return '$'+n +} +function activeTier(spend){ + return TIERS.find(t => spend >= t.min && spend < t.max) || TIERS[TIERS.length-1] +} + +function renderTierGrid(spend){ + const active = activeTier(spend) + const grid = document.getElementById('tier-grid') + grid.innerHTML = TIERS.map(t => { + const isActive = t.name === active.name + const rangeStr = t.max === Infinity ? fmtUSD(t.min)+'+' : fmtUSD(t.min)+'–'+fmtUSD(t.max) + return `
+
${t.name}
+
${rangeStr}/mnd
+
${fmtUSD(t.price)}
+
per måned
+
` + }).join('') +} + +function updatePricing(val){ + const spend = Number(val) + const tier = activeTier(spend) + + document.getElementById('spend-display').textContent = fmtUSD(spend) + + renderTierGrid(spend) + + // ROI: 15% of spend saved via CostGuard optimisation + const savings = spend * 0.15 + const net_monthly = savings - tier.price + const net_annual = net_monthly * 12 + const multiplier = tier.price > 0 ? (savings / tier.price) : 0 + + document.getElementById('roi-savings').textContent = fmtUSD(Math.round(savings)) + document.getElementById('roi-savings-sub').textContent = '15% av ' + fmtUSD(spend) + ' via optimalisering og varsler' + + document.getElementById('roi-multiplier').textContent = multiplier.toFixed(2) + '×' + document.getElementById('roi-multiplier-sub').textContent = 'per måned · basert på ' + fmtUSD(tier.price) + '/mnd' + + const annualEl = document.getElementById('roi-annual') + if(net_annual >= 0){ + annualEl.textContent = fmtUSD(Math.round(net_annual)) + annualEl.style.color = 'var(--green)' + } else { + annualEl.textContent = '−' + fmtUSD(Math.round(Math.abs(net_annual))) + annualEl.style.color = 'var(--danger)' + } +} + // SESSION function sid(){ let s = sessionStorage.getItem(SESSION_KEY) @@ -547,6 +697,13 @@ function go(name){ if(name==='sites') renderSites() if(name==='terminal') initTerminal() if(name==='md') renderMdGrid() + if(name==='pricing') initPricing() +} + +function initPricing(){ + const slider = document.getElementById('spend-slider') + renderTierGrid(Number(slider.value)) + updatePricing(slider.value) } // BUILD STATUS POLL @@ -589,7 +746,7 @@ async function loadBilling(){ h+='
⚠️ Anomalier
' anoms.slice(0,5).forEach(a=>{ const sev=(a.severity||'').toLowerCase() - h+=`
${sev==='high'?'🔴':'🟡'}
${esc(a.service||a.type||'Ukjent')}
${esc(a.description||a.message||'')}
${esc(a.severity||'medium')}
` + h+=`
${sev==='high'?'🔴':'🟡'}
${esc(a.service||a.type||'Ukjent')}
${esc(a.description||a.message||'')}
${esc(a.severity||'medium')}
` }) h+='
' }else{ h+='
✅ Ingen anomalier
' } @@ -890,6 +1047,9 @@ function exportHistory(){ } ;(function(){ const h=lh();if(!h.length)return;h.forEach(m=>appendMsg(m.role,m.text,m.ts));document.getElementById('messages').scrollTop=99999 })() inp.focus() +// Init pricing on load so slider is ready if user navigates directly +renderTierGrid(5000) +updatePricing(5000) - \ No newline at end of file +