{
  "name": "Buyer Affordability Coach",
  "category": "Real Estate",
  "description": "Shows buyers what they can comfortably afford: full monthly payment (PITI, PMI or FHA MIP, HOA) at a cited current rate, debt-to-income, max price at a target DTI, and ways to lower the payment (rate shopping, buydowns, down payment assistance). You get a bold 'What can I afford?' one-pager. Education only, RESPA-safe, not lending advice.",
  "instructions": "FIRST CONVERSATION: Before anything else, send exactly this opening message and wait for the answer: \"Hi! I'll help you see what home payment actually fits your budget. Roughly what price range are you looking at, and in what area?\" Then follow WORKFLOW one step at a time.\n\nNO ROUTINE OFFER: This is a one-off calculator and coaching bot. Don't offer a recurring routine. When done, say they can rerun it anytime rates or prices change.\n\nROLE: A buyer affordability educator, used by agents with their buyers or by buyers directly. Plain English, no jargon without explanation, no judgment about finances.\n\nNOT ADVICE: You are not a lender, loan officer, financial adviser or credit counselor. Say clearly that this is education, not financial or lending advice, not a pre-approval and not a Loan Estimate, and that actual terms come from a licensed loan officer (NMLS). Never collect SSNs, full account numbers or credit reports. Ask only for rough income, debts and savings, and let the user give round numbers.\n\nRATES: Use a cited current average. Default to Freddie Mac's Primary Mortgage Market Survey (weekly, Thursdays at noon ET; freddiemac.com/pmms) for the 30- and 15-year fixed. Search for the latest week and state the date (for example, 7.40% for the 30-year as of Oct 15, 2026). Explain that PMMS assumes 20% down and excellent credit, so actual quotes vary.\n\nMATH (keep it transparent):\n- P&I uses standard amortization.\n- Property tax uses the local effective rate (ask, or use county records/RentCast for the actual tax bill).\n- Homeowners insurance: ask or estimate.\n- HOA: from the listing.\n- Conventional PMI is typically 0.2–2% of the loan per year (Fannie Mae) when less than 20% down.\n- FHA: 1.75% upfront MIP financed, plus an annual MIP for 30-year loans with a base amount up to $726,200 of 0.55% with under 5% down (LTV over 95%) and 0.50% with 5% or more down (HUD Mortgagee Letter 2023-05, https://www.hud.gov/sites/dfiles/OCHCO/documents/2023-05hsgml.pdf). Higher-balance loans run 0.70–0.75%; 15-year loans are lower.\n- VA and USDA: note the funding and guarantee fees and that a lender must quote them.\n- DTI: front-end and back-end. Fannie Mae allows up to 36% manual (45% with compensating factors) and 50% through DU; FHA and others differ.\n- Max price: solve for the target DTI.\nOPTIONAL RENTCAST UPGRADE: The bot works fully without it, using county assessor/recorder records, the user's own MLS export CSV, or listing text the user pastes. If the user wants automatic property records, value estimates and comps, they can add their own RentCast API key (free Developer plan: 50 requests a month; paid plans from $74/month for 1,000) as a bot secret named RENTCAST_API_KEY (bot settings > Secrets). Never ask them to paste the key in chat, never echo it, and never write it to files or the tracker. Endpoints (header X-Api-Key): GET https://api.rentcast.io/v1/properties?address=... (records), GET /v1/avm/value?address=...&compCount=10 (value estimate with comps), GET /v1/listings/sale?... (active sale listings gathered from public sources). Count calls in the tracker and warn before a batch would exceed 50 a month on the free plan. On a 401 error, ask them to re-enter the key in Secrets; on a 429 error or quota limit, fall back to county records or CSV. Label RentCast values as automated estimates, not appraisals. Use it for property tax and value data on specific homes.\n\nLOWERING THE PAYMENT: rate shopping (get 3+ Loan Estimates; CFPB says comparing saves money); points; temporary buydowns (for example a 2-1 buydown, often seller-paid and negotiable in the offer, subject to loan-program limits); down payment assistance (the state housing finance agency via HUD's state list, Fannie Mae HomeReady, Freddie Mac Home Possible, local grants and forgivable seconds; eligibility varies); a larger down payment; a lower price; paying off a debt to lower DTI.\n\nRESPA AND FAIR LENDING: Never steer buyers to a specific lender for anything of value. If the agent lists lenders, include \"You're free to choose any lender; shop and compare\" and disclose any affiliated business arrangement if one exists. Never accept or offer referral fees. Don't make assumptions based on protected characteristics.\n\nWORKFLOW:\n1) Intake (one at a time): price range or a specific home, area, down payment savings, rough gross monthly income, monthly debt payments, loan type interest (unsure is fine), HOA if known, and first-time buyer status (for DPA).\n2) Fetch the current PMMS rate (and the date). Estimate taxes and insurance for the area.\n3) Build the one-pager: load the skill \"affordability-one-pager-template\", copy its HTML exactly, and replace ONLY the JSON inside <script id=\"report-data\" type=\"application/json\"> (meta{buyer,rateSource,rateSourceUrl,example:false}, in{price,downPct,rate,term,loanType,taxPct,insYr,hoa,pmiPct,income,debts,targetDti,dpa}, dpaNote). Save to /workspace/affordability/<name-or-area>-<date>.html and give the user the file. It recalculates live as they edit.\n4) Explain the results in 5 bullets: monthly payment, comfortable max price, DTI, the best 2 ways to lower the payment, and the next step (talk to 2–3 licensed lenders and get Loan Estimates).\n5) Optional: compare 2–3 specific homes side by side.\n\nRULES: Never guarantee approval, rates or programs. Cite every rate and program source with a date. Nothing is sent. Report only real actions.\n\nACTIVITY TRACKER: keep a log at /workspace/trackers/buyer-affordability-coach.csv (create it with this header row if it doesn't exist: date,buyer,price,rate,rate_source,down_pct,monthly_payment,dti_back,file,next_action,notes). Append a row for every scenario built or updated (no SSNs or account numbers). Read it at the start of each session to resume. Never store secrets, full SSNs or payment data in it.\n\nHOW TO USE:\n- \"$350k in Maple Grove, $15k saved, $8k/month income\" -> payment, DTI and max price.\n- \"What if we do FHA?\" -> an updated one-pager with FHA MIP math.\n- \"How does a 2-1 buydown help?\" -> year 1 and 2 payments and how to negotiate one.\n- \"What down payment help is there in Texas?\" -> program types and where to check eligibility.",
  "whatItDoes": [
    "Calculates the full monthly payment: principal, interest, taxes, insurance, PMI or FHA MIP, HOA",
    "Uses a cited current rate (Freddie Mac PMMS, with the date)",
    "Checks front- and back-end DTI and solves for a comfortable max price",
    "Shows ways to lower the payment: rate shopping, 2-1 buydown, down payment assistance, bigger down payment, lower price",
    "Produces a bold, editable 'What can I afford?' one-pager (live math, CSV, print-to-PDF)",
    "Education only: not lending advice, RESPA-safe lender language, no SSNs collected",
    "Optional RentCast key for property tax and value data on specific homes"
  ],
  "gettingStarted": [
    "Click 'Add to Grok Bot' on this page (or import the template JSON) and open the bot.",
    "Optional: get a free RentCast API key at rentcast.io/api (50 requests a month) and add it in the bot's Secrets as RENTCAST_API_KEY. Without it, the bot uses county records, your MLS CSV or pasted listings. (Optional: used for actual property tax data.)",
    "Answer the first question with a price range and area.",
    "Share rough numbers: savings, gross monthly income and monthly debts. Round numbers are fine; never share SSNs or account numbers.",
    "Open the one-pager it sends and edit any number to see the payment change. Save it as a PDF to share.",
    "Take it to 2–3 licensed lenders for real Loan Estimates.",
    "It logs scenarios to /workspace/trackers/buyer-affordability-coach.csv."
  ],
  "howToUse": [
    "First message: when you open the bot it greets you with: \"Hi! I'll help you see what home payment actually fits your budget. Roughly what price range are you looking at, and in what area?\"",
    "\"$350k in Maple Grove, $15k saved, $8k/month income\". You get: payment, DTI and max price.",
    "\"What if we do FHA?\". You get: an updated one-pager with FHA MIP math.",
    "\"How does a 2-1 buydown help?\". You get: year 1 and 2 payments and how to negotiate one.",
    "\"What down payment help is there in Texas?\". You get: program types and where to check eligibility."
  ],
  "activityTracker": {
    "path": "/workspace/trackers/buyer-affordability-coach.csv",
    "columns": [
      "date",
      "buyer",
      "price",
      "rate",
      "rate_source",
      "down_pct",
      "monthly_payment",
      "dti_back",
      "file",
      "next_action",
      "notes"
    ],
    "starterCsv": "date,buyer,price,rate,rate_source,down_pct,monthly_payment,dti_back,file,next_action,notes\n",
    "updateRule": "Append a row after every action; review open rows at session start."
  },
  "faq": [
    {
      "question": "Do I need RentCast or any paid data?",
      "answer": "No. It works with county records, your own MLS export CSV or listing text you paste. Optionally add your own RentCast key (free plan: 50 requests a month) as the secret RENTCAST_API_KEY for automatic property records, value estimates and comps."
    },
    {
      "question": "Is this a pre-approval?",
      "answer": "No. It's an education tool. Only a licensed loan officer can pre-approve you and give a Loan Estimate."
    },
    {
      "question": "Where does the rate come from?",
      "answer": "Freddie Mac's weekly Primary Mortgage Market Survey, with the date shown. Your actual rate depends on credit, down payment and lender."
    },
    {
      "question": "Will it recommend a lender?",
      "answer": "It encourages comparing several lenders. You're always free to choose any lender, and no referral fees are involved."
    },
    {
      "question": "How is this different from the Home Buyer Assistant?",
      "answer": "The Home Buyer Assistant runs your home search. This bot goes deep on affordability: DTI, max price, PMI or FHA MIP, buydowns, down payment assistance and a shareable one-pager."
    }
  ],
  "tags": [
    "real estate",
    "mortgage",
    "affordability",
    "first-time buyer",
    "down payment assistance",
    "calculator"
  ],
  "openingMessage": "Hi! I'll help you see what home payment actually fits your budget. Roughly what price range are you looking at, and in what area?",
  "skills": [
    {
      "name": "affordability-one-pager-template",
      "description": "Editable HTML 'What can I afford?' one-pager. Copy it exactly and replace only the JSON inside <script id=\"report-data\">.",
      "fileName": "affordability-one-pager-template.html",
      "content": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1,viewport-fit=cover\"><meta name=\"theme-color\" content=\"#0f172a\">\n<title>What Can I Afford?</title><style>:root{--bg:#f5f6f8;--card:#fff;--ink:#0f172a;--ink2:#334155;--muted:#64748b;--line:#e5e7eb;--line2:#eef0f3;--accent:#4f46e5;--accent-soft:#eef2ff;--amber:#b45309;--amber-soft:#fef3c7;--green:#047857;--green-soft:#d1fae5;--red:#b91c1c;--red-soft:#fee2e2;--r:16px}\n*{box-sizing:border-box}html{-webkit-text-size-adjust:100%}\nbody{margin:0;background:var(--bg);color:var(--ink);font:16px/1.5 ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;-webkit-font-smoothing:antialiased}\n.wrap{max-width:1120px;margin:0 auto;padding:20px 20px 120px}\n.top{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px}\n.brand{display:flex;align-items:center;gap:10px;font-weight:700;font-size:14px;color:var(--ink2);min-width:0}\n.logo{flex:none;width:32px;height:32px;border-radius:10px;background:var(--accent);display:grid;place-items:center;color:#fff;font-weight:900}\n.actions{display:flex;gap:8px;flex-wrap:wrap}\n.btn{appearance:none;font:inherit;font-weight:650;font-size:14px;min-height:44px;padding:0 16px;border-radius:12px;border:1px solid var(--line);background:#fff;color:var(--ink);cursor:pointer;display:inline-flex;align-items:center;gap:8px;justify-content:center;white-space:nowrap}\n.btn:hover{border-color:#cbd5e1}.btn.primary{background:var(--ink);color:#fff;border-color:var(--ink)}\n.btn:focus-visible,[contenteditable]:focus-visible,summary:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid #a5b4fc;outline-offset:2px}\n.hero{background:linear-gradient(135deg,#0f172a 0%,#1e1b4b 100%);color:#fff;border-radius:24px;padding:28px;display:grid;grid-template-columns:1.4fr 1fr;gap:28px;box-shadow:0 20px 40px -20px #1e1b4b80}\n.pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;letter-spacing:.02em;padding:5px 10px;border-radius:999px;background:#ffffff1f;color:#e0e7ff}\n.pill.ex{background:#be123c;color:#fff}\n.hero h1{font-size:15px;font-weight:600;color:#c7d2fe;margin:14px 0 2px}\n.addr{font-size:22px;font-weight:750;letter-spacing:-.01em;line-height:1.25}\n.val{font-size:clamp(36px,6.5vw,56px);font-weight:850;letter-spacing:-.03em;line-height:1.05;margin-top:18px;font-variant-numeric:tabular-nums}\n.vallab{font-size:13px;color:#a5b4fc;font-weight:600}\n.range{font-size:14px;color:#cbd5e1;margin-top:6px}\n.stats{display:grid;gap:12px;align-content:start}\n.stat{background:#ffffff12;border:1px solid #ffffff1a;border-radius:16px;padding:14px 16px}\n.stat .k{font-size:12px;color:#a5b4fc;font-weight:600;text-transform:uppercase;letter-spacing:.06em}\n.stat .v{font-size:20px;font-weight:750;margin-top:2px;font-variant-numeric:tabular-nums}\n.notice{display:flex;gap:12px;background:#fff;border:1px solid var(--line);border-left:4px solid var(--amber);border-radius:14px;padding:14px 16px;margin:16px 0;font-size:14px;color:var(--ink2)}\n.notice b{color:var(--ink)}\ndetails.card,.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r);margin:12px 0;overflow:hidden}\ndetails.card>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:12px;padding:18px 20px;min-height:60px}\ndetails.card>summary::-webkit-details-marker{display:none}\nsummary .ttl,.card h2{font-size:17px;font-weight:750;flex:1;margin:0}\nsummary .meta{font-size:12px;font-weight:650;color:var(--muted);background:var(--line2);padding:4px 10px;border-radius:99px}\n.chev{width:20px;height:20px;transition:transform .2s;color:var(--muted);flex:none}\ndetails[open]>summary .chev{transform:rotate(180deg)}\n.body{padding:4px 20px 20px;border-top:1px solid var(--line2)}\n.rows{display:grid;grid-template-columns:1fr 1fr;column-gap:32px}\n.row{display:flex;flex-direction:column;gap:4px;padding:12px 0;border-bottom:1px solid var(--line2);min-width:0}\n.row.long{grid-column:1/-1}\n.lab{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:600;color:var(--muted)}\n.tag{font-size:11px;font-weight:700;padding:2px 8px;border-radius:99px;line-height:1.5;white-space:nowrap}\n.tag.v{color:var(--amber);background:var(--amber-soft)}.tag.ok{color:var(--green);background:var(--green-soft)}.tag.bad{color:var(--red);background:var(--red-soft)}.tag.info{color:var(--accent);background:var(--accent-soft)}\n[contenteditable],input.in,select.in{min-height:44px;padding:10px 12px;border-radius:10px;border:1px solid transparent;background:#f8fafc;font:inherit;font-size:16px;font-weight:550;color:var(--ink);word-break:break-word;outline:none;transition:border-color .15s,background .15s;width:100%}\n[contenteditable]:hover,input.in:hover,select.in:hover{border-color:var(--line)}\n[contenteditable]:focus,input.in:focus,select.in:focus{background:#fff;border-color:var(--accent);box-shadow:0 0 0 4px var(--accent-soft)}\n[contenteditable]:empty::before{content:\"Add text\";color:#64748b;font-weight:500}\n.hint{font-size:13px;color:var(--muted);margin:12px 0 4px}\n.num{text-align:right;font-variant-numeric:tabular-nums;font-weight:650}\n.calcbox{background:var(--accent-soft);border-radius:12px;padding:12px 14px}\n.calcbox .k{font-size:12px;font-weight:700;color:var(--accent);text-transform:uppercase;letter-spacing:.05em}\n.big2{font-size:28px;font-weight:850;letter-spacing:-.02em;font-variant-numeric:tabular-nums}\nfooter{font-size:12px;color:var(--muted);margin-top:20px;line-height:1.6}\n.dock{display:none}\n@media (max-width:899px){\n .wrap{padding:14px 14px 110px}.top .actions{display:none}\n .hero{grid-template-columns:1fr;padding:22px;gap:18px;border-radius:20px}\n .stats{grid-template-columns:1fr 1fr}.stat{padding:12px}.stat .v{font-size:17px}\n .rows{grid-template-columns:1fr}\n details.card>summary{padding:16px}.body{padding:4px 16px 16px}\n .dock{display:flex;gap:8px;position:fixed;left:0;right:0;bottom:0;z-index:20;padding:10px 12px calc(10px + env(safe-area-inset-bottom));background:#ffffffe6;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-top:1px solid var(--line)}\n .dock .btn{flex:1;padding:0 8px;font-size:14px}\n}\n@media (max-width:360px){.stats{grid-template-columns:1fr}}\n@media print{\n @page{margin:14mm}\n *{color:#000!important;background:#fff!important;box-shadow:none!important}\n body{font:11pt/1.35 \"Helvetica Neue\",Arial,sans-serif}\n .top .actions,.dock,.noprint,.chev,summary .meta{display:none!important}\n .wrap{padding:0;max-width:none}\n .hero{display:block;border:2px solid #000;border-radius:0;padding:10px 12px}.val{font-size:24pt;margin-top:6px}\n .stats{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap}.stat{border:1px solid #000;border-radius:0;flex:1;padding:6px}\n .notice,details.card,.card{border:1px solid #000;border-radius:0;margin:8px 0}\n details.card>summary{padding:6px 10px;min-height:0;border-bottom:1px solid #000}\n summary .ttl,.card h2{font-size:11pt;text-transform:uppercase;letter-spacing:.05em}\n .body{padding:0 10px 6px;border:0}\n [contenteditable],input.in,select.in{min-height:0;padding:0;border:0;font-size:10pt;font-weight:400}\n .tag{border:1px solid #000}\n}\n\n.grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px}\n.fld{display:flex;flex-direction:column;gap:4px;font-size:13px;font-weight:650;color:var(--muted)}\n.fld small{font-weight:500}\n.brk{display:flex;height:18px;border-radius:99px;overflow:hidden;margin:12px 0}.brk i{display:block;height:100%}\n.leg{display:grid;gap:6px}.leg div{display:flex;justify-content:space-between;gap:10px;font-size:15px;padding:6px 0;border-bottom:1px solid var(--line2)}.leg span::before{content:\"\";display:inline-block;width:12px;height:12px;border-radius:4px;margin-right:8px;vertical-align:-1px;background:var(--c)}\n.leg b{font-variant-numeric:tabular-nums}.leg .tot{border-top:2px solid var(--ink);font-size:18px;font-weight:850;border-bottom:0}\n.dti{display:grid;grid-template-columns:1fr 1fr;gap:12px}.dbox{border:1px solid var(--line);border-radius:14px;padding:14px}.dbox .k{font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}.dbox .v{font-size:28px;font-weight:850}\n.meter{height:10px;border-radius:99px;background:var(--line2);margin-top:8px;position:relative;overflow:hidden}.meter i{position:absolute;inset:0 auto 0 0;border-radius:99px;background:var(--green)}.meter i.warn{background:#d97706}.meter i.bad{background:var(--red)}\n.scn{width:100%;border-collapse:collapse;font-size:15px}.scn th,.scn td{padding:10px 8px;border-bottom:1px solid var(--line2);text-align:right}.scn th:first-child,.scn td:first-child{text-align:left}.scn th{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}\n.scn tr.hl td{font-weight:800;background:var(--accent-soft)}\n.src{font-size:12px;color:var(--muted)}\n@media (max-width:899px){.grid2,.dti{grid-template-columns:1fr}.scn{font-size:14px}}\n@media print{.brk,.meter{border:1px solid #000}.brk i,.meter i{-webkit-print-color-adjust:exact;print-color-adjust:exact}.dbox{border:1px solid #000}input.in,select.in{border-bottom:1px solid #999!important}}\n</style></head><body>\n<div class=\"wrap\">\n <div class=\"top\"><div class=\"brand\"><div class=\"logo\">$</div><span>What Can I Afford?</span></div>\n <div class=\"actions\"><button class=\"btn\" data-act=\"reset\">Reset</button><button class=\"btn\" data-act=\"csv\">Export CSV</button><button class=\"btn primary\" data-act=\"pdf\">Save PDF</button></div></div>\n <header class=\"hero\" id=\"hero\"></header>\n <div class=\"notice\"><div><b>Education only, not financial or lending advice and not a loan offer or pre-approval.</b> Estimates use the inputs below. Actual rates, mortgage insurance, taxes, insurance and eligibility come from a licensed loan officer. Talk with more than one lender; you're free to choose any lender.</div></div>\n <section class=\"card\" style=\"padding:20px\"><h2>Your numbers</h2><p class=\"hint\" id=\"rateSrc\"></p><div class=\"grid2\" id=\"inputs\"></div></section>\n <section class=\"card\" style=\"padding:20px\"><h2>Monthly payment breakdown</h2><div class=\"brk\" id=\"brk\"></div><div class=\"leg\" id=\"leg\"></div></section>\n <section class=\"card\" style=\"padding:20px\"><h2>Debt-to-income check</h2><div class=\"dti\" id=\"dti\"></div><p class=\"hint\">Lenders compare your monthly debts to gross income. Many conventional loans allow up to 45% (manual) or 50% (automated underwriting, per Fannie Mae's Selling Guide); FHA and others differ. Lower is more comfortable.</p></section>\n <section class=\"card\" style=\"padding:20px\"><h2>Ways to lower the payment</h2><div style=\"overflow-x:auto\"><table class=\"scn\" id=\"scn\"></table></div><p class=\"hint\" id=\"dpa\"></p></section>\n <footer id=\"foot\"></footer>\n</div>\n<nav class=\"dock\"><button class=\"btn\" data-act=\"reset\">Reset</button><button class=\"btn\" data-act=\"csv\">CSV</button><button class=\"btn primary\" data-act=\"pdf\">Save PDF</button></nav>\n<script id=\"report-data\" type=\"application/json\">\n{\"meta\":{\"reportId\":\"afford\",\"example\":false,\"generated\":\"\",\"buyer\":\"\",\"rateSource\":\"Freddie Mac PMMS, 30-yr fixed average, week of Oct 15, 2026 (7.40%)\",\"rateSourceUrl\":\"https://www.freddiemac.com/pmms\"},\n \"in\":{\"price\":\"\",\"downPct\":\"5\",\"rate\":\"7.40\",\"term\":\"30\",\"loanType\":\"Conventional\",\"taxPct\":\"1.1\",\"insYr\":\"1800\",\"hoa\":\"0\",\"pmiPct\":\"0.6\",\"income\":\"\",\"debts\":\"\",\"targetDti\":\"36\",\"dpa\":\"0\"},\"dpaNote\":\"\"}\n</script>\n<script>const esc=s=>String(s==null?'':s).replace(/[&<>\"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;'}[c]));\nconst num=v=>{if(v==null)return NaN;const m=String(v).replace(/[$,\\s%]/g,'').match(/-?\\d*\\.?\\d+/);return m?parseFloat(m[0]):NaN};\nconst money=n=>isFinite(n)?(n<0?'−$':'$')+Math.round(Math.abs(n)).toLocaleString('en-US'):'—';\nconst getP=(o,p)=>p.split('.').reduce((a,k)=>a==null?a:a[k],o);\nfunction setP(o,path,val){const p=path.split('.');for(let i=0;i<p.length-1;i++)o=o[p[i]]=o[p[i]]||(isFinite(+p[i+1])?[]:{});o[p[p.length-1]]=val}\nconst chev='<svg class=\"chev\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><path d=\"M5 8l5 5 5-5\"/></svg>';\nfunction store(key){return{load(){try{return JSON.parse(localStorage.getItem(key))}catch(e){return null}},save(s){try{localStorage.setItem(key,JSON.stringify(s));return true}catch(e){return false}},clear(){try{localStorage.removeItem(key)}catch(e){}}}}\nfunction download(name,text,type){const a=document.createElement('a');a.href=URL.createObjectURL(new Blob([text],{type}));a.download=name;document.body.appendChild(a);a.click();a.remove()}\nconst csvq=v=>'\"'+String(v==null?'':v).replace(/\"/g,'\"\"')+'\"';\n\n(function(){\nconst BASE=JSON.parse(document.getElementById('report-data').textContent);\nconst ST=store('af:'+(BASE.meta.reportId||'a')+':'+location.pathname);\nlet S=ST.load()||JSON.parse(JSON.stringify(BASE));\nconst F=[['price','Home price $','numeric'],['downPct','Down payment %','decimal'],['dpa','Down payment assistance $ (if approved)','numeric'],['rate','Interest rate %','decimal'],['term','Loan term (years)','numeric'],['loanType','Loan type',null,['Conventional','FHA']],['taxPct','Property tax % of price per year','decimal'],['insYr','Homeowners insurance $ per year','numeric'],['hoa','HOA $ per month','numeric'],['pmiPct','Conventional PMI % per year (typ. 0.2–2%)','decimal'],['income','Gross monthly income $','numeric'],['debts','Other monthly debts $ (car, cards, loans)','numeric'],['targetDti','Target total DTI %','decimal']];\nfunction pi(L,r,n){const m=r/1200,k=n*12;return m?L*m/(1-Math.pow(1+m,-k)):L/k}\nfunction calc(inp,priceOverride,rateOverride){const I=Object.fromEntries(Object.entries(inp).map(([k,v])=>[k,k==='loanType'?v:num(v)]));\n const price=priceOverride!=null?priceOverride:I.price,rate=rateOverride!=null?rateOverride:I.rate,term=I.term||30;\n const down=price*(I.downPct||0)/100+(I.dpa||0);let base=Math.max(0,price-down),loan=base,mi=0;\n if(inp.loanType==='FHA'){loan=base*1.0175;mi=base*(price&&down/price>=0.05?0.50:0.55)/100/12}else if(price&&down/price<0.2){mi=base*(I.pmiPct||0)/100/12}\n const P=pi(loan,rate,term),T=price*(I.taxPct||0)/100/12,H=(I.insYr||0)/12,A=I.hoa||0,tot=P+T+H+mi+A;\n return{price,down,loan,P,T,H,mi,A,tot,front:tot/I.income*100,back:(tot+(I.debts||0))/I.income*100}}\nfunction maxPrice(inp){const I=inp,inc=num(I.income),tgt=num(I.targetDti);if(!(inc>0&&tgt>0))return NaN;const budget=inc*tgt/100-(num(I.debts)||0);let lo=0,hi=5e6;for(let k=0;k<60;k++){const mid=(lo+hi)/2;calc(I,mid).tot>budget?hi=mid:lo=mid}return lo}\nfunction render(){\n document.getElementById('rateSrc').innerHTML='Rate default: <a href=\"'+esc(S.meta.rateSourceUrl)+'\">'+esc(S.meta.rateSource)+'</a>. Your rate depends on credit, down payment, points and lender. Get quotes.';\n document.getElementById('inputs').innerHTML=F.map(([k,l,im,opts])=>`<label class=\"fld\">${l}${opts?`<select class=\"in\" data-k=\"${k}\">${opts.map(o=>`<option ${S.in[k]===o?'selected':''}>${o}</option>`).join('')}</select>`:`<input class=\"in\" data-k=\"${k}\" inputmode=\"${im}\" value=\"${esc(S.in[k])}\">`}</label>`).join('');\n update()}\nfunction update(){const R=calc(S.in),$=i=>document.getElementById(i),mx=maxPrice(S.in);S.calc={...R,maxPrice:mx};\n $('hero').innerHTML=`<div><span class=\"pill\">Affordability snapshot</span>${S.meta.example?' <span class=\"pill ex\">EXAMPLE DATA · fictional</span>':''}<h1>${esc(S.meta.buyer?'Prepared for '+S.meta.buyer:'Estimated monthly payment')}</h1>\n <div class=\"val\">${money(R.tot)}<span style=\"font-size:20px;font-weight:700;color:#c7d2fe\">/mo</span></div><div class=\"vallab\">Principal, interest, taxes, insurance${R.mi?', mortgage insurance':''}${R.A?', HOA':''}</div><div class=\"range\">On a ${money(R.price)} home at ${esc(S.in.rate)}% · ${esc(S.in.term)}-yr ${esc(S.in.loanType)}</div></div>\n <div class=\"stats\"><div class=\"stat\"><div class=\"k\">Comfortable max price</div><div class=\"v\">${isFinite(mx)?money(mx):'Add income'}</div></div><div class=\"stat\"><div class=\"k\">Cash down</div><div class=\"v\">${money(R.down)}</div></div>\n <div class=\"stat\"><div class=\"k\">Total DTI</div><div class=\"v\">${isFinite(R.back)?R.back.toFixed(1)+'%':'—'}</div></div><div class=\"stat\"><div class=\"k\">Loan amount</div><div class=\"v\">${money(R.loan)}</div></div></div>`;\n const parts=[['Principal & interest',R.P,'#4f46e5'],['Property tax',R.T,'#0891b2'],['Insurance',R.H,'#059669'],[S.in.loanType==='FHA'?'FHA mortgage insurance':'PMI',R.mi,'#d97706'],['HOA',R.A,'#db2777']];\n $('brk').innerHTML=parts.map(([l,v,c])=>v>0?`<i style=\"width:${v/R.tot*100}%;background:${c}\" title=\"${l}\"></i>`:'').join('');\n $('leg').innerHTML=parts.map(([l,v,c])=>`<div><span style=\"--c:${c}\">${l}</span><b>${money(v)}</b></div>`).join('')+`<div class=\"tot\"><span>Total</span><b>${money(R.tot)}</b></div>`;\n const m=(v,lim)=>`<div class=\"meter\"><i class=\"${v>lim?'bad':v>lim*0.85?'warn':''}\" style=\"width:${Math.min(100,(v||0)/60*100)}%\"></i></div>`;\n $('dti').innerHTML=`<div class=\"dbox\"><div class=\"k\">Housing only (front-end)</div><div class=\"v\">${isFinite(R.front)?R.front.toFixed(1)+'%':'—'}</div>${m(R.front,31)}<div class=\"src\">Common comfort guide: about 28–31%</div></div><div class=\"dbox\"><div class=\"k\">All debts (back-end)</div><div class=\"v\">${isFinite(R.back)?R.back.toFixed(1)+'%':'—'}</div>${m(R.back,num(S.in.targetDti)||43)}<div class=\"src\">Your target: ${esc(S.in.targetDti)}%</div></div>`;\n const r=num(S.in.rate),rows=[['Your scenario',R.tot,''],['Rate 1% lower (shop lenders / points)',calc(S.in,null,r-1).tot,''],['2-1 buydown, year 1 (seller-paid credit, if negotiated)',calc(S.in,null,r-2).tot,''],['2-1 buydown, year 2',calc(S.in,null,r-1).tot,''],['Price $25k lower',calc(S.in,R.price-25000).tot,''],['Down payment +5%',calc({...S.in,downPct:(num(S.in.downPct)||0)+5+''}).tot,'']];\n $('scn').innerHTML='<thead><tr><th>Option</th><th>Monthly</th><th>Saves</th></tr></thead><tbody>'+rows.map(([l,v],i)=>`<tr class=\"${i?'':'hl'}\"><td>${l}</td><td>${money(v)}</td><td>${i?money(R.tot-v):'—'}</td></tr>`).join('')+'</tbody>';\n $('dpa').textContent=(S.dpaNote?S.dpaNote+' ':'')+'Down payment assistance: check your state housing finance agency (HUD lists them by state) and ask lenders about programs like Fannie Mae HomeReady and Freddie Mac Home Possible. Eligibility varies by income, area and first-time-buyer status.';\n $('foot').innerHTML=`FHA math uses a 1.75% upfront premium financed into the loan and an annual premium of 0.55% with under 5% down or 0.50% with 5%+ down (30-year loans, base loan up to $726,200; HUD Mortgagee Letter 2023-05). Conventional PMI is dropped at 20% down. Taxes and insurance are estimates. Not a Loan Estimate.${S.meta.generated?' Prepared '+esc(S.meta.generated)+'.':''} <span id=\"saved\"></span>`}\nlet t;function save(){clearTimeout(t);t=setTimeout(()=>{const ok=ST.save(S);const el=document.getElementById('saved');if(el)el.textContent=ok?'Autosaved '+new Date().toLocaleTimeString():'Autosave unavailable'},300)}\ndocument.addEventListener('input',e=>{const k=e.target.dataset.k;if(!k)return;S.in[k]=e.target.value;update();save()});\ndocument.addEventListener('change',e=>{const k=e.target.dataset.k;if(!k)return;S.in[k]=e.target.value;update();save()});\ndocument.addEventListener('click',e=>{const b=e.target.closest('[data-act]');if(!b)return;const a=b.dataset.act;if(a==='pdf')window.print();\n if(a==='reset'&&confirm('Reset to the original numbers?')){ST.clear();S=JSON.parse(JSON.stringify(BASE));render()}\n if(a==='csv'){const c=S.calc;const rows=[['item','value']];Object.entries(S.in).forEach(([k,v])=>rows.push(['input_'+k,v]));[['principal_interest',c.P],['tax',c.T],['insurance',c.H],['mortgage_insurance',c.mi],['hoa',c.A],['total_monthly',c.tot],['front_dti_pct',c.front],['back_dti_pct',c.back],['max_price_at_target_dti',c.maxPrice]].forEach(([k,v])=>rows.push([k,isFinite(v)?Math.round(v*100)/100:'']));rows.push(['rate_source',S.meta.rateSource]);download('affordability.csv',rows.map(r=>r.map(csvq).join(',')).join('\\n'),'text/csv')}});\nwindow.__doc={get state(){return S},calc,maxPrice};render();\n})();\n</script></body></html>\n"
    }
  ]
}