← 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
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"
    ]
  }
}