← Qiki · all runs · 📊 leaderboard
r-1786727472058-nsv65
Build a mortgage repayment calculator for a UK broker
model /nix/store/w8fajwih8isx2rl94rb8ggc1knmnf8x9-Qwen3.6-35B-A3B-MTP-GGUF upstream http://127.0.0.1:8080 harness 127.0.0.1
score 0 / 10
2026-08-14 17:11:12 UTC · total 28s · 1 step
widget · error · 28s
UK Mortgage Repayment Calculator
0 / 10
model /nix/store/w8fajwih8isx2rl94rb8ggc1knmnf8x9-Qwen3.6-35B-A3B-MTP-GGUF harness 127.0.0.1:8080
validity 0/2
fidelity 0/2
structure 0/2
depth 0/2
cleanliness 0/2
why (1 notes)
- step error — no score
output failed the render gate: body has only 56 words of visible text
1 LLM call on this step
ok ·
27877 ms · prompt 1908c → resp 1736c ·
t=0.5 max=1800 ·
→ /nix/store/w8fajwih8isx2rl94rb8ggc1knmnf8x9-Qwen3.6-35B-A3B-MTP-GGUF @ http://127.0.0.1:8080
→ /nix/store/w8fajwih8isx2rl94rb8ggc1knmnf8x9-Qwen3.6-35B-A3B-MTP-GGUF @ http://127.0.0.1:8080
raw JSON
{
"id": "r-1786727472058-nsv65",
"prompt": "Build a mortgage repayment calculator for a UK broker",
"project": {
"name": "UK Mortgage Repayment Calculator",
"tagline": "Precision mortgage planning for UK brokers and clients",
"theme": "clean fintech interface, trustworthy blue and white palette, minimalist data visualization with clear typography",
"brandColors": [
"#003366",
"#FFFFFF",
"#E6F0FA",
"#00A86B"
],
"audience": "UK mortgage brokers and homebuyers",
"vibe": "professional, clear, trustworthy, precise, modern"
},
"steps": [
{
"id": "s1-n1is8",
"kind": "widget",
"params": {
"brief": "Build a professional UK mortgage repayment calculator. Inputs: Property Price, Deposit Amount/Percentage, Interest Rate (%), Mortgage Term (years), Repayment vs Interest-only toggle. Outputs: Monthly repayment amount, Total amount payable, Total interest paid. Include a simple breakdown table or summary. Style: Clean, trustworthy, financial services aesthetic.",
"variant": "calculator",
"project": {
"name": "UK Mortgage Repayment Calculator",
"tagline": "Precision mortgage planning for UK brokers and clients",
"theme": "clean fintech interface, trustworthy blue and white palette, minimalist data visualization with clear typography",
"brandColors": [
"#003366",
"#FFFFFF",
"#E6F0FA",
"#00A86B"
],
"audience": "UK mortgage brokers and homebuyers",
"vibe": "professional, clear, trustworthy, precise, modern"
},
"heroPlanned": false
},
"label": "UK Mortgage Repayment Calculator"
}
],
"results": {
"s1-n1is8": {
"status": "error",
"startedAt": 1786727472060,
"attempt": 1,
"output": {
"html": "<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>UK Mortgage Repayment Calculator</title>\n:root{\n --bg:#faf7f2;--surface:#ffffff;--elevated:#f2ede4;\n --text:#171410;--muted:#5d574e;--border:rgba(23,20,16,.14);\n --accent:#003366;--accent-btn:#003366;--accent-text:#003366;--ink:#ffffff;--glow:rgba(0,51,102,0.20);--soft:rgba(0,51,102,0.13);\n /* Minimum comfortable hit area. Referenced by every interactive rule so a\n tap target can never regress below the 44px WCAG/iOS floor. */\n --tap:44px;\n /* Translucent chrome derived from the direction's own background. Hardcoding\n rgba(10,10,11,.62) here put dark text on a dark nav (1.08:1) the moment a\n light direction shipped. */\n --nav-bg:rgba(250,247,242,0.72);--hairline:rgba(0,0,0,.14);\n --font:ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;\n --font-display:'Iowan Old Style','Palatino Linotype',Palatino,'Book Antiqua',Georgia,serif;\n --w-display:400;--w-body:400;\n --track-display:-.01em;\n --texture:radial-gradient(1200px 500px at 80% -10%, rgba(138,51,36,.06), transparent 60%);\n --maxw:1200px;--r:3px;--r-lg:5px;--ease:cubic-bezier(.4,0,.2,1);\n color-scheme:light;\n}\n<style>\n*{box-sizing:border-box}\nbody{margin:0;min-height:100vh;background:var(--bg);background-image:var(--texture);color:var(--text);\n font-family:var(--font);font-weight:var(--w-body);font-size:16px;line-height:1.55;\n display:flex;justify-content:center;align-items:flex-start;padding:clamp(18px,4vw,56px)}\n.w{width:100%;max-width:600px}\nh1{font-family:var(--font-display);font-weight:var(--w-display);letter-spacing:var(--track-display);\n font-size:clamp(1.7rem,4.4vw,2.5rem);line-height:1.12;margin:0 0 8px}\n.sub{color:var(--muted);font-size:1rem;margin:0 0 26px;max-width:52ch}\n.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);\n padding:clamp(18px,3.6vw,28px);margin-bottom:18px}\n.field{margin-bottom:18px}\nlabel{display:block;font-size:.86rem;font-weight:600;color:var(--muted);margin-bottom:7px}\n.hint{font-size:.8rem;color:var(--muted);margin-top:6px}\ninput,select,textarea{width:100%;min-height:var(--tap);font:inherit;font-size:1rem;padding:11px 14px;\n color:var(--text);background:var(--elevated);border:1px solid var(--border);border-radius:var(--r);appearance:none}\ntextarea{min-height:110px;resize:vertical}\ninput[type=radio],input[type=checkbox]{width:22px;height:22px;min-height:22px;margin:0;flex:none;accent-color:var(--accent-btn)}\nbutton{min-height:var(--tap);font:inherit;font-size:1rem;font-weight:600;padding:11px 22px;cursor:pointer;\n background:var(--accent-btn);color:var(--ink);border:1px solid transparent;border-radius:var(--r)}\nbutton.ghost{background:transparent;color:var(--accent-text);border-color:var(--border)}\nbutton:hover{filter:brightness(1.08)}\n.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}\n:focus-visible{outline:3px solid var(--accent-text);outline-offset:2px}\n.out{display:flex;justify-content:space-between;align-items:baseline;gap:14px;padding:13px 0;border-top:1px solid var(--border)}\n.out:first-child{border-top:0;padding-top:0}\n.out .k{color:var(--muted);font-size:.9rem}\n.out .val{font-family:var(--font-display);font-weight:var(--w-display);font-size:clamp(1.35rem,3.6vw,1.9rem);\n color:var(--accent-text);letter-spacing:var(--track-display);font-variant-numeric:tabular-nums}\n.out .val.dim{color:var(--muted)}\n.msg{font-size:.86rem;color:var(--muted);margin-top:12px;min-height:1.2em}\n.msg.err{color:var(--accent-text);font-weight:600}\n.banner{font-size:.86rem;color:var(--muted);background:var(--soft);border:1px solid var(--border);\n border-radius:var(--r);padding:11px 14px;margin-bottom:18px}\nfieldset{border:0;padding:0;margin:0 0 22px}\nlegend{font-weight:600;font-size:1rem;padding:0;margin-bottom:10px}\n.opt{display:flex;align-items:center;gap:12px;min-height:var(--tap);padding:4px 10px;border-radius:var(--r);\n font-size:.98rem;font-weight:400;color:var(--text);cursor:pointer;margin-bottom:2px}\n.opt:hover{background:var(--soft)}\n.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;text-align:center}\n.cell{background:var(--elevated);border:1px solid var(--border);border-radius:var(--r);padding:14px 4px}\n.cell b{display:block;font-family:var(--font-display);font-weight:var(--w-display);font-variant-numeric:tabular-nums;\n font-size:clamp(1.6rem,6vw,2.6rem);line-height:1;color:var(--accent-text)}\n.cell span{display:block;font-size:.78rem;text-transform:uppercase;letter-spacing:.09em;color:var(--muted);margin-top:8px}\n.qrwrap{display:flex;justify-content:center;padding:16px 0}\ncanvas{max-width:100%;height:auto;border-radius:var(--r);background:#fff}\ndl{margin:0}dt{font-size:.82rem;color:var(--muted);margin-top:12px}\ndd{margin:3px 0 0;font-size:1rem;word-break:break-word}\n.foot{font-size:.8rem;color:var(--muted);margin-top:6px}\n@media(prefers-reduced-motion:no-preference){.card{transition:border-color .2s var(--ease)}}\n</style></head>\n<body><main class=\"w\">\n<h1>UK Mortgage Repayment Calculator</h1>\n<p class=\"sub\">Calculate monthly repayments and total interest for UK mortgages based on property price, deposit, rate, and term.</p>\n<form class=\"card\" onsubmit=\"return false\">\n<div class=\"field\">\n <label for=\"in_property_price\">Property Price <span style=\"font-weight:400\">(£)</span></label>\n <input id=\"in_property_price\" type=\"number\" inputmode=\"decimal\" value=\"250000\"\n min=\"50000\" max=\"5000000\" step=\"1000\">\n</div>\n<div class=\"field\">\n <label for=\"in_deposit_amount\">Deposit Amount <span style=\"font-weight:400\">(£)</span></label>\n <input id=\"in_deposit_amount\" type=\"number\" inputmode=\"decimal\" value=\"50000\"\n min=\"0\" max=\"5000000\" step=\"1000\">\n</div>\n<div class=\"field\">\n <label for=\"in_interest_rate\">Interest Rate <span style=\"font-weight:400\">(%)</span></label>\n <input id=\"in_interest_rate\" type=\"number\" inputmode=\"decimal\" value=\"4.5\"\n min=\"0.1\" max=\"15\" step=\"0.1\">\n</div>\n<div class=\"field\">\n <label for=\"in_mortgage_term\">Mortgage Term <span style=\"font-weight:400\">(years)</span></label>\n <input id=\"in_mortgage_term\" type=\"number\" inputmode=\"decimal\" value=\"25\"\n min=\"1\" max=\"40\" step=\"1\">\n</div>\n<div class=\"field\">\n <label for=\"in_repayment_type\">Repayment Type</label>\n <input id=\"in_repayment_type\" type=\"number\" inputmode=\"decimal\" value=\"0\"\n min=\"0\" max=\"1\" step=\"1\">\n</div>\n<div class=\"row\"><button type=\"button\" id=\"calc-reset\" class=\"ghost\">Reset</button></div>\n</form>\n<div class=\"card\" role=\"region\" aria-live=\"polite\" aria-label=\"Results\">\n<div class=\"out\"><span class=\"k\">Total</span><span class=\"val\" id=\"out_total\">—</span></div>\n<p class=\"msg\" id=\"calc-msg\"></p>\n</div>\n<p class=\"foot\">Estimates assume a fixed interest rate and do not include arrangement fees, valuation costs, or early repayment charges.</p>\n</main>\n<script>\n\nvar FN={abs:Math.abs,round:Math.round,floor:Math.floor,ceil:Math.ceil,sqrt:Math.sqrt,min:Math.min,max:Math.max,pow:Math.pow};\nfunction evalRpn(rpn,vars){\n var st=[],i,t,a,b,args,f;\n for(i=0;i<rpn.length;i++){\n t=rpn[i];\n if(t.t==='num'){st.push(t.v);}\n else if(t.t==='var'){var v=vars[t.id];if(typeof v!=='number'||!isFinite(v))return NaN;st.push(v);}\n else if(t.t==='neg'){st.push(-st.pop());}\n else if(t.t==='op'){\n b=st.pop();a=st.pop();\n st.push(t.v==='+'?a+b:t.v==='-'?a-b:t.v==='*'?a*b:t.v==='/'?(b===0?NaN:a/b):Math.pow(a,b));\n }\n else if(t.t==='fn'){\n args=st.splice(st.length-t.n,t.n);\n f=Object.prototype.hasOwnProperty.call(FN,t.v)?FN[t.v]:null;\n st.push(f?f.apply(null,args):NaN);\n }\n else{return NaN;}\n }\n var r=st.length===1?st[0]:NaN;\n return (typeof r==='number'&&isFinite(r))?r:NaN;\n}\n(function(){\n var CFG={\"inputs\":[{\"id\":\"property_price\",\"label\":\"Property Price\",\"unit\":\"£\",\"default\":250000,\"min\":50000,\"max\":5000000,\"step\":1000},{\"id\":\"deposit_amount\",\"label\":\"Deposit Amount\",\"unit\":\"£\",\"default\":50000,\"min\":0,\"max\":5000000,\"step\":1000},{\"id\":\"interest_rate\",\"label\":\"Interest Rate\",\"unit\":\"%\",\"default\":4.5,\"min\":0.1,\"max\":15,\"step\":0.1},{\"id\":\"mortgage_term\",\"label\":\"Mortgage Term\",\"unit\":\"years\",\"default\":25,\"min\":1,\"max\":40,\"step\":1},{\"id\":\"repayment_type\",\"label\":\"Repayment Type\",\"unit\":\"\",\"default\":0,\"min\":0,\"max\":1,\"step\":1}],\"outputs\":[{\"id\":\"total\",\"label\":\"Total\",\"unit\":\"\",\"prefix\":\"\",\"decimals\":2,\"formula\":\"property_price + deposit_amount + interest_rate + mortgage_term + repayment_type\",\"rpn\":[{\"t\":\"var\",\"id\":\"property_price\"},{\"t\":\"var\",\"id\":\"deposit_amount\"},{\"t\":\"op\",\"v\":\"+\"},{\"t\":\"var\",\"id\":\"interest_rate\"},{\"t\":\"op\",\"v\":\"+\"},{\"t\":\"var\",\"id\":\"mortgage_term\"},{\"t\":\"op\",\"v\":\"+\"},{\"t\":\"var\",\"id\":\"repayment_type\"},{\"t\":\"op\",\"v\":\"+\"}]}]};\n function read(){\n var vars={},bad=[],i,el,raw,n;\n for(i=0;i<CFG.inputs.length;i++){\n el=document.getElementById('in_'+CFG.inputs[i].id);\n raw=el?String(el.value).trim():'';\n n=raw===''?NaN:Number(raw);\n if(typeof n!=='number'||!isFinite(n)){bad.push(CFG.inputs[i].label);n=NaN;}\n vars[CFG.inputs[i].id]=n;\n }\n return {vars:vars,bad:bad};\n }\n function render(){\n var r=read(),i,o,el,v,s;\n for(i=0;i<CFG.outputs.length;i++){\n o=CFG.outputs[i];el=document.getElementById('out_'+o.id);\n v=r.bad.length?NaN:evalRpn(o.rpn,r.vars);\n // NaN and Infinity never reach the user: a dash plus a message beats a\n // confident \"Infinity kg\" every time.\n if(typeof v!=='number'||!isFinite(v)){el.textContent='—';el.className='val dim';}\n else{\n s=v.toLocaleString(undefined,{minimumFractionDigits:o.decimals,maximumFractionDigits:o.decimals});\n el.textContent=(o.prefix||'')+s+(o.unit?' '+o.unit:'');\n el.className='val';\n }\n }\n var m=document.getElementById('calc-msg');\n m.textContent=r.bad.length?('Enter a number for: '+r.bad.join(', ')):'';\n m.className=r.bad.length?'msg err':'msg';\n }\n for(var i=0;i<CFG.inputs.length;i++){\n var el=document.getElementById('in_'+CFG.inputs[i].id);\n if(el){el.addEventListener('input',render);el.addEventListener('change',render);}\n }\n var rb=document.getElementById('calc-reset');\n if(rb)rb.addEventListener('click',function(){\n for(var i=0;i<CFG.inputs.length;i++){\n var el=document.getElementById('in_'+CFG.inputs[i].id);\n if(el)el.value=CFG.inputs[i]['default'];\n }\n render();\n });\n render(); // answer on load — an empty result panel reads as broken\n})();\n</script>\n</body></html>",
"variant": "calculator",
"title": "UK Mortgage Repayment Calculator",
"config": {
"title": "UK Mortgage Repayment Calculator",
"subtitle": "Calculate monthly repayments and total interest for UK mortgages based on property price, deposit, rate, and term.",
"inputs": [
{
"id": "property_price",
"label": "Property Price",
"unit": "£",
"default": 250000,
"min": 50000,
"max": 5000000,
"step": 1000
},
{
"id": "deposit_amount",
"label": "Deposit Amount",
"unit": "£",
"default": 50000,
"min": 0,
"max": 5000000,
"step": 1000
},
{
"id": "interest_rate",
"label": "Interest Rate",
"unit": "%",
"default": 4.5,
"min": 0.1,
"max": 15,
"step": 0.1
},
{
"id": "mortgage_term",
"label": "Mortgage Term",
"unit": "years",
"default": 25,
"min": 1,
"max": 40,
"step": 1
},
{
"id": "repayment_type",
"label": "Repayment Type",
"unit": "",
"default": 0,
"min": 0,
"max": 1,
"step": 1
}
],
"outputs": [
{
"id": "total",
"label": "Total",
"unit": "",
"prefix": "",
"decimals": 2,
"formula": "property_price + deposit_amount + interest_rate + mortgage_term + repayment_type",
"rpn": [
{
"t": "var",
"id": "property_price"
},
{
"t": "var",
"id": "deposit_amount"
},
{
"t": "op",
"v": "+"
},
{
"t": "var",
"id": "interest_rate"
},
{
"t": "op",
"v": "+"
},
{
"t": "var",
"id": "mortgage_term"
},
{
"t": "op",
"v": "+"
},
{
"t": "var",
"id": "repayment_type"
},
{
"t": "op",
"v": "+"
}
]
}
],
"note": "Estimates assume a fixed interest rate and do not include arrangement fees, valuation costs, or early repayment charges."
},
"charCount": 10512,
"warnings": [
"formula \"if(repayment_type == 1, property_price * (interest_rate / 100) / 12, (property_price - deposit_amount) * (interest_rate / 100 / 12) / (1 - pow(1 + interest_rate / 100 / 12, -mortgage_term * 12)))\" contains characters outside the arithmetic whitelist",
"formula \"monthly_payment * mortgage_term * 12\" references unknown input \"monthly_payment\"",
"formula \"total_payable - property_price + deposit_amount\" references unknown input \"total_payable\"",
"no formula compiled — showing the sum of the inputs instead"
]
},
"produces": {
"appHtml": "<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>UK Mortgage Repayment Calculator</title>\n:root{\n --bg:#faf7f2;--surface:#ffffff;--elevated:#f2ede4;\n --text:#171410;--muted:#5d574e;--border:rgba(23,20,16,.14);\n --accent:#003366;--accent-btn:#003366;--accent-text:#003366;--ink:#ffffff;--glow:rgba(0,51,102,0.20);--soft:rgba(0,51,102,0.13);\n /* Minimum comfortable hit area. Referenced by every interactive rule so a\n tap target can never regress below the 44px WCAG/iOS floor. */\n --tap:44px;\n /* Translucent chrome derived from the direction's own background. Hardcoding\n rgba(10,10,11,.62) here put dark text on a dark nav (1.08:1) the moment a\n light direction shipped. */\n --nav-bg:rgba(250,247,242,0.72);--hairline:rgba(0,0,0,.14);\n --font:ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;\n --font-display:'Iowan Old Style','Palatino Linotype',Palatino,'Book Antiqua',Georgia,serif;\n --w-display:400;--w-body:400;\n --track-display:-.01em;\n --texture:radial-gradient(1200px 500px at 80% -10%, rgba(138,51,36,.06), transparent 60%);\n --maxw:1200px;--r:3px;--r-lg:5px;--ease:cubic-bezier(.4,0,.2,1);\n color-scheme:light;\n}\n<style>\n*{box-sizing:border-box}\nbody{margin:0;min-height:100vh;background:var(--bg);background-image:var(--texture);color:var(--text);\n font-family:var(--font);font-weight:var(--w-body);font-size:16px;line-height:1.55;\n display:flex;justify-content:center;align-items:flex-start;padding:clamp(18px,4vw,56px)}\n.w{width:100%;max-width:600px}\nh1{font-family:var(--font-display);font-weight:var(--w-display);letter-spacing:var(--track-display);\n font-size:clamp(1.7rem,4.4vw,2.5rem);line-height:1.12;margin:0 0 8px}\n.sub{color:var(--muted);font-size:1rem;margin:0 0 26px;max-width:52ch}\n.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);\n padding:clamp(18px,3.6vw,28px);margin-bottom:18px}\n.field{margin-bottom:18px}\nlabel{display:block;font-size:.86rem;font-weight:600;color:var(--muted);margin-bottom:7px}\n.hint{font-size:.8rem;color:var(--muted);margin-top:6px}\ninput,select,textarea{width:100%;min-height:var(--tap);font:inherit;font-size:1rem;padding:11px 14px;\n color:var(--text);background:var(--elevated);border:1px solid var(--border);border-radius:var(--r);appearance:none}\ntextarea{min-height:110px;resize:vertical}\ninput[type=radio],input[type=checkbox]{width:22px;height:22px;min-height:22px;margin:0;flex:none;accent-color:var(--accent-btn)}\nbutton{min-height:var(--tap);font:inherit;font-size:1rem;font-weight:600;padding:11px 22px;cursor:pointer;\n background:var(--accent-btn);color:var(--ink);border:1px solid transparent;border-radius:var(--r)}\nbutton.ghost{background:transparent;color:var(--accent-text);border-color:var(--border)}\nbutton:hover{filter:brightness(1.08)}\n.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}\n:focus-visible{outline:3px solid var(--accent-text);outline-offset:2px}\n.out{display:flex;justify-content:space-between;align-items:baseline;gap:14px;padding:13px 0;border-top:1px solid var(--border)}\n.out:first-child{border-top:0;padding-top:0}\n.out .k{color:var(--muted);font-size:.9rem}\n.out .val{font-family:var(--font-display);font-weight:var(--w-display);font-size:clamp(1.35rem,3.6vw,1.9rem);\n color:var(--accent-text);letter-spacing:var(--track-display);font-variant-numeric:tabular-nums}\n.out .val.dim{color:var(--muted)}\n.msg{font-size:.86rem;color:var(--muted);margin-top:12px;min-height:1.2em}\n.msg.err{color:var(--accent-text);font-weight:600}\n.banner{font-size:.86rem;color:var(--muted);background:var(--soft);border:1px solid var(--border);\n border-radius:var(--r);padding:11px 14px;margin-bottom:18px}\nfieldset{border:0;padding:0;margin:0 0 22px}\nlegend{font-weight:600;font-size:1rem;padding:0;margin-bottom:10px}\n.opt{display:flex;align-items:center;gap:12px;min-height:var(--tap);padding:4px 10px;border-radius:var(--r);\n font-size:.98rem;font-weight:400;color:var(--text);cursor:pointer;margin-bottom:2px}\n.opt:hover{background:var(--soft)}\n.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;text-align:center}\n.cell{background:var(--elevated);border:1px solid var(--border);border-radius:var(--r);padding:14px 4px}\n.cell b{display:block;font-family:var(--font-display);font-weight:var(--w-display);font-variant-numeric:tabular-nums;\n font-size:clamp(1.6rem,6vw,2.6rem);line-height:1;color:var(--accent-text)}\n.cell span{display:block;font-size:.78rem;text-transform:uppercase;letter-spacing:.09em;color:var(--muted);margin-top:8px}\n.qrwrap{display:flex;justify-content:center;padding:16px 0}\ncanvas{max-width:100%;height:auto;border-radius:var(--r);background:#fff}\ndl{margin:0}dt{font-size:.82rem;color:var(--muted);margin-top:12px}\ndd{margin:3px 0 0;font-size:1rem;word-break:break-word}\n.foot{font-size:.8rem;color:var(--muted);margin-top:6px}\n@media(prefers-reduced-motion:no-preference){.card{transition:border-color .2s var(--ease)}}\n</style></head>\n<body><main class=\"w\">\n<h1>UK Mortgage Repayment Calculator</h1>\n<p class=\"sub\">Calculate monthly repayments and total interest for UK mortgages based on property price, deposit, rate, and term.</p>\n<form class=\"card\" onsubmit=\"return false\">\n<div class=\"field\">\n <label for=\"in_property_price\">Property Price <span style=\"font-weight:400\">(£)</span></label>\n <input id=\"in_property_price\" type=\"number\" inputmode=\"decimal\" value=\"250000\"\n min=\"50000\" max=\"5000000\" step=\"1000\">\n</div>\n<div class=\"field\">\n <label for=\"in_deposit_amount\">Deposit Amount <span style=\"font-weight:400\">(£)</span></label>\n <input id=\"in_deposit_amount\" type=\"number\" inputmode=\"decimal\" value=\"50000\"\n min=\"0\" max=\"5000000\" step=\"1000\">\n</div>\n<div class=\"field\">\n <label for=\"in_interest_rate\">Interest Rate <span style=\"font-weight:400\">(%)</span></label>\n <input id=\"in_interest_rate\" type=\"number\" inputmode=\"decimal\" value=\"4.5\"\n min=\"0.1\" max=\"15\" step=\"0.1\">\n</div>\n<div class=\"field\">\n <label for=\"in_mortgage_term\">Mortgage Term <span style=\"font-weight:400\">(years)</span></label>\n <input id=\"in_mortgage_term\" type=\"number\" inputmode=\"decimal\" value=\"25\"\n min=\"1\" max=\"40\" step=\"1\">\n</div>\n<div class=\"field\">\n <label for=\"in_repayment_type\">Repayment Type</label>\n <input id=\"in_repayment_type\" type=\"number\" inputmode=\"decimal\" value=\"0\"\n min=\"0\" max=\"1\" step=\"1\">\n</div>\n<div class=\"row\"><button type=\"button\" id=\"calc-reset\" class=\"ghost\">Reset</button></div>\n</form>\n<div class=\"card\" role=\"region\" aria-live=\"polite\" aria-label=\"Results\">\n<div class=\"out\"><span class=\"k\">Total</span><span class=\"val\" id=\"out_total\">—</span></div>\n<p class=\"msg\" id=\"calc-msg\"></p>\n</div>\n<p class=\"foot\">Estimates assume a fixed interest rate and do not include arrangement fees, valuation costs, or early repayment charges.</p>\n</main>\n<script>\n\nvar FN={abs:Math.abs,round:Math.round,floor:Math.floor,ceil:Math.ceil,sqrt:Math.sqrt,min:Math.min,max:Math.max,pow:Math.pow};\nfunction evalRpn(rpn,vars){\n var st=[],i,t,a,b,args,f;\n for(i=0;i<rpn.length;i++){\n t=rpn[i];\n if(t.t==='num'){st.push(t.v);}\n else if(t.t==='var'){var v=vars[t.id];if(typeof v!=='number'||!isFinite(v))return NaN;st.push(v);}\n else if(t.t==='neg'){st.push(-st.pop());}\n else if(t.t==='op'){\n b=st.pop();a=st.pop();\n st.push(t.v==='+'?a+b:t.v==='-'?a-b:t.v==='*'?a*b:t.v==='/'?(b===0?NaN:a/b):Math.pow(a,b));\n }\n else if(t.t==='fn'){\n args=st.splice(st.length-t.n,t.n);\n f=Object.prototype.hasOwnProperty.call(FN,t.v)?FN[t.v]:null;\n st.push(f?f.apply(null,args):NaN);\n }\n else{return NaN;}\n }\n var r=st.length===1?st[0]:NaN;\n return (typeof r==='number'&&isFinite(r))?r:NaN;\n}\n(function(){\n var CFG={\"inputs\":[{\"id\":\"property_price\",\"label\":\"Property Price\",\"unit\":\"£\",\"default\":250000,\"min\":50000,\"max\":5000000,\"step\":1000},{\"id\":\"deposit_amount\",\"label\":\"Deposit Amount\",\"unit\":\"£\",\"default\":50000,\"min\":0,\"max\":5000000,\"step\":1000},{\"id\":\"interest_rate\",\"label\":\"Interest Rate\",\"unit\":\"%\",\"default\":4.5,\"min\":0.1,\"max\":15,\"step\":0.1},{\"id\":\"mortgage_term\",\"label\":\"Mortgage Term\",\"unit\":\"years\",\"default\":25,\"min\":1,\"max\":40,\"step\":1},{\"id\":\"repayment_type\",\"label\":\"Repayment Type\",\"unit\":\"\",\"default\":0,\"min\":0,\"max\":1,\"step\":1}],\"outputs\":[{\"id\":\"total\",\"label\":\"Total\",\"unit\":\"\",\"prefix\":\"\",\"decimals\":2,\"formula\":\"property_price + deposit_amount + interest_rate + mortgage_term + repayment_type\",\"rpn\":[{\"t\":\"var\",\"id\":\"property_price\"},{\"t\":\"var\",\"id\":\"deposit_amount\"},{\"t\":\"op\",\"v\":\"+\"},{\"t\":\"var\",\"id\":\"interest_rate\"},{\"t\":\"op\",\"v\":\"+\"},{\"t\":\"var\",\"id\":\"mortgage_term\"},{\"t\":\"op\",\"v\":\"+\"},{\"t\":\"var\",\"id\":\"repayment_type\"},{\"t\":\"op\",\"v\":\"+\"}]}]};\n function read(){\n var vars={},bad=[],i,el,raw,n;\n for(i=0;i<CFG.inputs.length;i++){\n el=document.getElementById('in_'+CFG.inputs[i].id);\n raw=el?String(el.value).trim():'';\n n=raw===''?NaN:Number(raw);\n if(typeof n!=='number'||!isFinite(n)){bad.push(CFG.inputs[i].label);n=NaN;}\n vars[CFG.inputs[i].id]=n;\n }\n return {vars:vars,bad:bad};\n }\n function render(){\n var r=read(),i,o,el,v,s;\n for(i=0;i<CFG.outputs.length;i++){\n o=CFG.outputs[i];el=document.getElementById('out_'+o.id);\n v=r.bad.length?NaN:evalRpn(o.rpn,r.vars);\n // NaN and Infinity never reach the user: a dash plus a message beats a\n // confident \"Infinity kg\" every time.\n if(typeof v!=='number'||!isFinite(v)){el.textContent='—';el.className='val dim';}\n else{\n s=v.toLocaleString(undefined,{minimumFractionDigits:o.decimals,maximumFractionDigits:o.decimals});\n el.textContent=(o.prefix||'')+s+(o.unit?' '+o.unit:'');\n el.className='val';\n }\n }\n var m=document.getElementById('calc-msg');\n m.textContent=r.bad.length?('Enter a number for: '+r.bad.join(', ')):'';\n m.className=r.bad.length?'msg err':'msg';\n }\n for(var i=0;i<CFG.inputs.length;i++){\n var el=document.getElementById('in_'+CFG.inputs[i].id);\n if(el){el.addEventListener('input',render);el.addEventListener('change',render);}\n }\n var rb=document.getElementById('calc-reset');\n if(rb)rb.addEventListener('click',function(){\n for(var i=0;i<CFG.inputs.length;i++){\n var el=document.getElementById('in_'+CFG.inputs[i].id);\n if(el)el.value=CFG.inputs[i]['default'];\n }\n render();\n });\n render(); // answer on load — an empty result panel reads as broken\n})();\n</script>\n</body></html>",
"siteHtml": "<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>UK Mortgage Repayment Calculator</title>\n:root{\n --bg:#faf7f2;--surface:#ffffff;--elevated:#f2ede4;\n --text:#171410;--muted:#5d574e;--border:rgba(23,20,16,.14);\n --accent:#003366;--accent-btn:#003366;--accent-text:#003366;--ink:#ffffff;--glow:rgba(0,51,102,0.20);--soft:rgba(0,51,102,0.13);\n /* Minimum comfortable hit area. Referenced by every interactive rule so a\n tap target can never regress below the 44px WCAG/iOS floor. */\n --tap:44px;\n /* Translucent chrome derived from the direction's own background. Hardcoding\n rgba(10,10,11,.62) here put dark text on a dark nav (1.08:1) the moment a\n light direction shipped. */\n --nav-bg:rgba(250,247,242,0.72);--hairline:rgba(0,0,0,.14);\n --font:ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;\n --font-display:'Iowan Old Style','Palatino Linotype',Palatino,'Book Antiqua',Georgia,serif;\n --w-display:400;--w-body:400;\n --track-display:-.01em;\n --texture:radial-gradient(1200px 500px at 80% -10%, rgba(138,51,36,.06), transparent 60%);\n --maxw:1200px;--r:3px;--r-lg:5px;--ease:cubic-bezier(.4,0,.2,1);\n color-scheme:light;\n}\n<style>\n*{box-sizing:border-box}\nbody{margin:0;min-height:100vh;background:var(--bg);background-image:var(--texture);color:var(--text);\n font-family:var(--font);font-weight:var(--w-body);font-size:16px;line-height:1.55;\n display:flex;justify-content:center;align-items:flex-start;padding:clamp(18px,4vw,56px)}\n.w{width:100%;max-width:600px}\nh1{font-family:var(--font-display);font-weight:var(--w-display);letter-spacing:var(--track-display);\n font-size:clamp(1.7rem,4.4vw,2.5rem);line-height:1.12;margin:0 0 8px}\n.sub{color:var(--muted);font-size:1rem;margin:0 0 26px;max-width:52ch}\n.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);\n padding:clamp(18px,3.6vw,28px);margin-bottom:18px}\n.field{margin-bottom:18px}\nlabel{display:block;font-size:.86rem;font-weight:600;color:var(--muted);margin-bottom:7px}\n.hint{font-size:.8rem;color:var(--muted);margin-top:6px}\ninput,select,textarea{width:100%;min-height:var(--tap);font:inherit;font-size:1rem;padding:11px 14px;\n color:var(--text);background:var(--elevated);border:1px solid var(--border);border-radius:var(--r);appearance:none}\ntextarea{min-height:110px;resize:vertical}\ninput[type=radio],input[type=checkbox]{width:22px;height:22px;min-height:22px;margin:0;flex:none;accent-color:var(--accent-btn)}\nbutton{min-height:var(--tap);font:inherit;font-size:1rem;font-weight:600;padding:11px 22px;cursor:pointer;\n background:var(--accent-btn);color:var(--ink);border:1px solid transparent;border-radius:var(--r)}\nbutton.ghost{background:transparent;color:var(--accent-text);border-color:var(--border)}\nbutton:hover{filter:brightness(1.08)}\n.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}\n:focus-visible{outline:3px solid var(--accent-text);outline-offset:2px}\n.out{display:flex;justify-content:space-between;align-items:baseline;gap:14px;padding:13px 0;border-top:1px solid var(--border)}\n.out:first-child{border-top:0;padding-top:0}\n.out .k{color:var(--muted);font-size:.9rem}\n.out .val{font-family:var(--font-display);font-weight:var(--w-display);font-size:clamp(1.35rem,3.6vw,1.9rem);\n color:var(--accent-text);letter-spacing:var(--track-display);font-variant-numeric:tabular-nums}\n.out .val.dim{color:var(--muted)}\n.msg{font-size:.86rem;color:var(--muted);margin-top:12px;min-height:1.2em}\n.msg.err{color:var(--accent-text);font-weight:600}\n.banner{font-size:.86rem;color:var(--muted);background:var(--soft);border:1px solid var(--border);\n border-radius:var(--r);padding:11px 14px;margin-bottom:18px}\nfieldset{border:0;padding:0;margin:0 0 22px}\nlegend{font-weight:600;font-size:1rem;padding:0;margin-bottom:10px}\n.opt{display:flex;align-items:center;gap:12px;min-height:var(--tap);padding:4px 10px;border-radius:var(--r);\n font-size:.98rem;font-weight:400;color:var(--text);cursor:pointer;margin-bottom:2px}\n.opt:hover{background:var(--soft)}\n.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;text-align:center}\n.cell{background:var(--elevated);border:1px solid var(--border);border-radius:var(--r);padding:14px 4px}\n.cell b{display:block;font-family:var(--font-display);font-weight:var(--w-display);font-variant-numeric:tabular-nums;\n font-size:clamp(1.6rem,6vw,2.6rem);line-height:1;color:var(--accent-text)}\n.cell span{display:block;font-size:.78rem;text-transform:uppercase;letter-spacing:.09em;color:var(--muted);margin-top:8px}\n.qrwrap{display:flex;justify-content:center;padding:16px 0}\ncanvas{max-width:100%;height:auto;border-radius:var(--r);background:#fff}\ndl{margin:0}dt{font-size:.82rem;color:var(--muted);margin-top:12px}\ndd{margin:3px 0 0;font-size:1rem;word-break:break-word}\n.foot{font-size:.8rem;color:var(--muted);margin-top:6px}\n@media(prefers-reduced-motion:no-preference){.card{transition:border-color .2s var(--ease)}}\n</style></head>\n<body><main class=\"w\">\n<h1>UK Mortgage Repayment Calculator</h1>\n<p class=\"sub\">Calculate monthly repayments and total interest for UK mortgages based on property price, deposit, rate, and term.</p>\n<form class=\"card\" onsubmit=\"return false\">\n<div class=\"field\">\n <label for=\"in_property_price\">Property Price <span style=\"font-weight:400\">(£)</span></label>\n <input id=\"in_property_price\" type=\"number\" inputmode=\"decimal\" value=\"250000\"\n min=\"50000\" max=\"5000000\" step=\"1000\">\n</div>\n<div class=\"field\">\n <label for=\"in_deposit_amount\">Deposit Amount <span style=\"font-weight:400\">(£)</span></label>\n <input id=\"in_deposit_amount\" type=\"number\" inputmode=\"decimal\" value=\"50000\"\n min=\"0\" max=\"5000000\" step=\"1000\">\n</div>\n<div class=\"field\">\n <label for=\"in_interest_rate\">Interest Rate <span style=\"font-weight:400\">(%)</span></label>\n <input id=\"in_interest_rate\" type=\"number\" inputmode=\"decimal\" value=\"4.5\"\n min=\"0.1\" max=\"15\" step=\"0.1\">\n</div>\n<div class=\"field\">\n <label for=\"in_mortgage_term\">Mortgage Term <span style=\"font-weight:400\">(years)</span></label>\n <input id=\"in_mortgage_term\" type=\"number\" inputmode=\"decimal\" value=\"25\"\n min=\"1\" max=\"40\" step=\"1\">\n</div>\n<div class=\"field\">\n <label for=\"in_repayment_type\">Repayment Type</label>\n <input id=\"in_repayment_type\" type=\"number\" inputmode=\"decimal\" value=\"0\"\n min=\"0\" max=\"1\" step=\"1\">\n</div>\n<div class=\"row\"><button type=\"button\" id=\"calc-reset\" class=\"ghost\">Reset</button></div>\n</form>\n<div class=\"card\" role=\"region\" aria-live=\"polite\" aria-label=\"Results\">\n<div class=\"out\"><span class=\"k\">Total</span><span class=\"val\" id=\"out_total\">—</span></div>\n<p class=\"msg\" id=\"calc-msg\"></p>\n</div>\n<p class=\"foot\">Estimates assume a fixed interest rate and do not include arrangement fees, valuation costs, or early repayment charges.</p>\n</main>\n<script>\n\nvar FN={abs:Math.abs,round:Math.round,floor:Math.floor,ceil:Math.ceil,sqrt:Math.sqrt,min:Math.min,max:Math.max,pow:Math.pow};\nfunction evalRpn(rpn,vars){\n var st=[],i,t,a,b,args,f;\n for(i=0;i<rpn.length;i++){\n t=rpn[i];\n if(t.t==='num'){st.push(t.v);}\n else if(t.t==='var'){var v=vars[t.id];if(typeof v!=='number'||!isFinite(v))return NaN;st.push(v);}\n else if(t.t==='neg'){st.push(-st.pop());}\n else if(t.t==='op'){\n b=st.pop();a=st.pop();\n st.push(t.v==='+'?a+b:t.v==='-'?a-b:t.v==='*'?a*b:t.v==='/'?(b===0?NaN:a/b):Math.pow(a,b));\n }\n else if(t.t==='fn'){\n args=st.splice(st.length-t.n,t.n);\n f=Object.prototype.hasOwnProperty.call(FN,t.v)?FN[t.v]:null;\n st.push(f?f.apply(null,args):NaN);\n }\n else{return NaN;}\n }\n var r=st.length===1?st[0]:NaN;\n return (typeof r==='number'&&isFinite(r))?r:NaN;\n}\n(function(){\n var CFG={\"inputs\":[{\"id\":\"property_price\",\"label\":\"Property Price\",\"unit\":\"£\",\"default\":250000,\"min\":50000,\"max\":5000000,\"step\":1000},{\"id\":\"deposit_amount\",\"label\":\"Deposit Amount\",\"unit\":\"£\",\"default\":50000,\"min\":0,\"max\":5000000,\"step\":1000},{\"id\":\"interest_rate\",\"label\":\"Interest Rate\",\"unit\":\"%\",\"default\":4.5,\"min\":0.1,\"max\":15,\"step\":0.1},{\"id\":\"mortgage_term\",\"label\":\"Mortgage Term\",\"unit\":\"years\",\"default\":25,\"min\":1,\"max\":40,\"step\":1},{\"id\":\"repayment_type\",\"label\":\"Repayment Type\",\"unit\":\"\",\"default\":0,\"min\":0,\"max\":1,\"step\":1}],\"outputs\":[{\"id\":\"total\",\"label\":\"Total\",\"unit\":\"\",\"prefix\":\"\",\"decimals\":2,\"formula\":\"property_price + deposit_amount + interest_rate + mortgage_term + repayment_type\",\"rpn\":[{\"t\":\"var\",\"id\":\"property_price\"},{\"t\":\"var\",\"id\":\"deposit_amount\"},{\"t\":\"op\",\"v\":\"+\"},{\"t\":\"var\",\"id\":\"interest_rate\"},{\"t\":\"op\",\"v\":\"+\"},{\"t\":\"var\",\"id\":\"mortgage_term\"},{\"t\":\"op\",\"v\":\"+\"},{\"t\":\"var\",\"id\":\"repayment_type\"},{\"t\":\"op\",\"v\":\"+\"}]}]};\n function read(){\n var vars={},bad=[],i,el,raw,n;\n for(i=0;i<CFG.inputs.length;i++){\n el=document.getElementById('in_'+CFG.inputs[i].id);\n raw=el?String(el.value).trim():'';\n n=raw===''?NaN:Number(raw);\n if(typeof n!=='number'||!isFinite(n)){bad.push(CFG.inputs[i].label);n=NaN;}\n vars[CFG.inputs[i].id]=n;\n }\n return {vars:vars,bad:bad};\n }\n function render(){\n var r=read(),i,o,el,v,s;\n for(i=0;i<CFG.outputs.length;i++){\n o=CFG.outputs[i];el=document.getElementById('out_'+o.id);\n v=r.bad.length?NaN:evalRpn(o.rpn,r.vars);\n // NaN and Infinity never reach the user: a dash plus a message beats a\n // confident \"Infinity kg\" every time.\n if(typeof v!=='number'||!isFinite(v)){el.textContent='—';el.className='val dim';}\n else{\n s=v.toLocaleString(undefined,{minimumFractionDigits:o.decimals,maximumFractionDigits:o.decimals});\n el.textContent=(o.prefix||'')+s+(o.unit?' '+o.unit:'');\n el.className='val';\n }\n }\n var m=document.getElementById('calc-msg');\n m.textContent=r.bad.length?('Enter a number for: '+r.bad.join(', ')):'';\n m.className=r.bad.length?'msg err':'msg';\n }\n for(var i=0;i<CFG.inputs.length;i++){\n var el=document.getElementById('in_'+CFG.inputs[i].id);\n if(el){el.addEventListener('input',render);el.addEventListener('change',render);}\n }\n var rb=document.getElementById('calc-reset');\n if(rb)rb.addEventListener('click',function(){\n for(var i=0;i<CFG.inputs.length;i++){\n var el=document.getElementById('in_'+CFG.inputs[i].id);\n if(el)el.value=CFG.inputs[i]['default'];\n }\n render();\n });\n render(); // answer on load — an empty result panel reads as broken\n})();\n</script>\n</body></html>",
"widgetVariant": "calculator"
},
"finishedAt": 1786727499938,
"llmCalls": [
{
"upstream": "http://127.0.0.1:8080",
"modelRequested": "txt2txt",
"temperature": 0.5,
"maxTokens": 1800,
"timeoutMs": 180000,
"startedAt": 1786727472060,
"finishedAt": 1786727499937,
"ok": true,
"promptChars": 1908,
"responseChars": 1736,
"modelServed": "/nix/store/w8fajwih8isx2rl94rb8ggc1knmnf8x9-Qwen3.6-35B-A3B-MTP-GGUF"
}
],
"retriedWhy": "body has only 56 words of visible text",
"error": "output failed the render gate: body has only 56 words of visible text"
}
},
"startedAt": 1786727472058,
"fingerprint": {
"ownAiUrl": "http://127.0.0.1:8080",
"harnessHost": "127.0.0.1",
"modelServed": "qwen-image",
"nodeVersion": "v24.18.1",
"capturedAt": 1786727472058
},
"finishedAt": 1786727499939,
"scores": {
"perStep": {
"s1-n1is8": {
"validity": 0,
"fidelity": 0,
"structure": 0,
"depth": 0,
"cleanliness": 0,
"total": 0,
"notes": [
"step error — no score"
]
}
},
"total": 0,
"perKind": {
"widget": 0
},
"axes": [
"validity",
"fidelity",
"structure",
"depth",
"cleanliness"
]
}
}