Planned completion Summer 2026.
This custom residence, built by Armstrong Construction Group and designed by Tom Mooney Design, blends modern luxury with timeless architecture. The main home offers 6,294 SF with 4 beds, 5 baths, an office with separate entrance, and a kids flex room. All this is complemented by a 677 SF 1 bed/1 bath guest house, all set on just under an acre. Room to add pickleball court if desired.
Interiors curated by Janet Brooks Design feature stunning charcoal and warm toned millwork along rich pecan-colored wood flooring. The open floor plan is filled with natural light and includes a chef's kitchen with a hidden back kitchen, a separate pantry, a secondary living wing, and an oversized laundry room with dual washers and dryers plus dog wash for Fido. The primary suite and office occupy a private wing, with the office offering its own entrance and patio. Outdoor living showcases an extended pool, ramada with fireplace, and generous entertaining areas designed for year round enjoyment.
Save
Ask
Tour
Hide
Share
Listing Snapshot
Price
$5,950,000
Days On Site
62 Days
Bedrooms
5
Inside Area (SqFt)
6,971 sqft
Total Baths
6
Full Baths
6
Partial Baths
N/A
Lot Size
0.8 Acres
Year Built
2026
MLS® Number
6995962
Status
Active
Property Tax
$2,846
HOA/Condo/Coop Fees
N/A
Sq Ft Source
N/A
Friends & Family
React
Invite
Recent Activity
a month ago
Listing updated with changes from the MLS®
a month ago
Status changed to Active
2 months ago
Listing first seen on site
General Features
Acres
0.8
Attached Garage
Yes
Cross Street
E. Cholla St. & N. 66th St.
Disclosures
None
Garage
Yes
Garage Spaces
4
Land Lease
No
Levels
One
Number Of Stories
1
Parking
Garage Door OpenerCircular Driveway
Parking Spaces
4
Property Condition
Under Construction
Property Sub Type
Single Family Residence
Sewer
Septic Tank
Style
Contemporary
Utilities
Propane
Water Source
Public
Interior Features
Appliances
DryerWasherRefrigeratorDishwasherMicrowave
Cooling
Central Air
Fireplace
Yes
Fireplace Features
Living RoomMaster BedroomOutside
Fireplaces
3
Flooring
TileWood
Heating
ElectricPropane
Interior
High Speed InternetSmart HomeDouble VanityEat-in KitchenBreakfast BarVaulted Ceiling(s)Kitchen Island
Spa
Yes
Window Features
Low Emissivity WindowsENERGY STAR Qualified Windows
Save
Ask
Tour
Hide
Share
Exterior Features
Construction Details
StuccoStoneFrame
Exterior
BarbecueStorageBuilt-in Barbecue
Fencing
Block
Lot Features
Desert BackDesert Front
Other Structures
GazeboGuest House
Patio And Porch
Patio
Pool Features
Fenced
Private Pool
Yes
Roof
Tile
Spa
Yes
Spa Features
HeatedPrivate
Windows/Doors
Low Emissivity WindowsENERGY STAR Qualified Windows
Community Features
Accessibility Features
Accessible EntranceAccessible Hallway(s)
Financing Terms Available
CashConventional
Horse Allowed
Yes
School District
Scottsdale Unified District
Township
3N
Schools
School District
Scottsdale Unified District
Elementary School
Sequoya Elementary School
Middle School
Cocopah Middle School
High School
Chaparral High School
Listing courtesy of Armstrong Properties.
All information should be verified by the recipient and none is guaranteed as accurate by ARMLS. Copyright 2026 Arizona Regional Multiple Listing Service, Inc. All rights reserved.
Last checked: 2026-05-11 03:48 PM UTC
Neighborhood & Commute
Source: Walkscore
Disclosure: Community information and market data powered by Constellation Data Labs. Information is deemed reliable but not guaranteed.
document.addEventListener('DOMContentLoaded', function() {
var lastData = null;
function v(id) { var el = document.getElementById(id); return el ? (parseFloat(el.value) || 0) : 0; }
function vs(id) { var el = document.getElementById(id); return el ? (el.value || '') : ''; }
function fmt(n, dec) { dec=dec||0; if(isNaN(n)||!isFinite(n)) return '—'; return n.toLocaleString('en-US',{minimumFractionDigits:dec,maximumFractionDigits:dec}); }
function fmtPct(n) { return (isNaN(n)||!isFinite(n)) ? '—' : n.toFixed(1)+'%'; }
function fmtD(n) { if(isNaN(n)||!isFinite(n)) return '—'; return (n<0?'-$':'$')+fmt(Math.abs(Math.round(n))); }
function cfTdClass(n){ return n>=200?'td-good':n>=0?'td-warn':'td-bad'; }
// ── IRR: multi-seed Newton's method ──
function calcIRR(cashFlows) {
var TOLERANCE = 1e-7, MAX_ITER = 150;
function npvAt(rate) {
var n = 0;
for (var t = 0; t < cashFlows.length; t++) n += cashFlows[t] / Math.pow(1 + rate, t);
return n;
}
function dnpvAt(rate) {
var d = 0;
for (var t = 1; t < cashFlows.length; t++) d += -t * cashFlows[t] / Math.pow(1 + rate, t + 1);
return d;
}
function tryNewton(seed) {
var rate = seed;
for (var i = 0; i < MAX_ITER; i++) {
var n = npvAt(rate), d = dnpvAt(rate);
if (Math.abs(d) < 1e-14) return null;
var next = rate - n / d;
if (next < -0.9999) next = -0.9999;
if (Math.abs(next - rate) < TOLERANCE) return isFinite(next) ? next : null;
rate = next;
}
return null;
}
var seeds = [0.10, 0.0, -0.10, 0.25, 0.50, -0.30, 0.01];
var best = null;
for (var s = 0; s < seeds.length; s++) {
var r = tryNewton(seeds[s]);
if (r !== null && isFinite(r) && Math.abs(npvAt(r)) < 1.0) {
if (best === null || Math.abs(r - 0.08) < Math.abs(best - 0.08)) best = r;
}
}
return best !== null ? best * 100 : NaN;
}
// ── Core year calculator ──
function calcYear(yr, params) {
var rent = params.baseRent * Math.pow(1 + params.rentGrowth, yr - 1);
var otherInc = params.baseOther * Math.pow(1 + params.rentGrowth, yr - 1);
var grossInc = rent + otherInc;
var effInc = grossInc * (1 - params.vacancy);
var taxes = params.baseTaxes * Math.pow(1.02, yr - 1);
var insurance = params.baseInsurance * Math.pow(1.03, yr - 1);
var hoa = params.baseHoa * Math.pow(1.02, yr - 1);
var mgmtCost = effInc * params.mgmtPct;
var capexCost = effInc * params.capexPct;
var maintCost = effInc * params.maintPct;
var otherCosts= params.baseOtherCosts * Math.pow(1.02, yr - 1);
var totalOpEx = taxes + insurance + hoa + mgmtCost + capexCost + maintCost + otherCosts;
var noi = effInc - totalOpEx;
var cashFlow = noi - params.pi;
return { rent:rent, grossInc:grossInc, effInc:effInc,
taxes:taxes, insurance:insurance, hoa:hoa,
mgmtCost:mgmtCost, capexCost:capexCost, maintCost:maintCost,
otherCosts:otherCosts, totalOpEx:totalOpEx, noi:noi, cashFlow:cashFlow };
}
// ── Analyze ──
function praAnalyze() {
var price = v('pra-price');
var rent = v('pra-rent');
var taxes = v('pra-taxes');
var ins = v('pra-insurance');
var missing = [];
if (!price) missing.push('Purchase price');
if (!rent) missing.push('Monthly gross rent');
if (!taxes) missing.push('Property taxes');
if (!ins) missing.push('Insurance');
if (missing.length) { alert('Please fill in the required fields:\n\n• ' + missing.join('\n• ')); return; }
var rawDown = v('pra-downPct');
var rawRate = v('pra-rate');
var termMo = v('pra-term') * 12;
var downPct = rawDown / 100;
var rentRatio = (rent / price) * 100;
if (rawDown < 3.5 && rawDown > 0) {
alert('Warning: A down payment below 3.5% is below minimum conventional lending thresholds. Results may not reflect a financeable deal. Proceeding with entered value.');
}
if (rentRatio > 1.5) {
alert('Warning: Rent-to-price ratio of ' + rentRatio.toFixed(2) + '% is above 1.5% — unusually high for Phoenix SFR. Please verify rent and price inputs before proceeding.');
}
var rehab = v('pra-rehab');
var downAmt = price * downPct;
var loanAmt = price * (1 - downPct);
var closing = v('pra-closing');
var totalCash = downAmt + closing + rehab;
var pi;
var mRate;
if (rawRate === 0) {
pi = loanAmt / termMo;
mRate = 0;
} else {
mRate = rawRate / 100 / 12;
pi = loanAmt * (mRate * Math.pow(1 + mRate, termMo)) / (Math.pow(1 + mRate, termMo) - 1);
}
var yearBuilt = v('pra-yearBuilt') || 2000;
var holdYears = v('pra-holdPeriod');
var appreciation = v('pra-appreciation') / 100;
var sellCostPct = v('pra-sellCost') / 100;
var ltcgRate = v('pra-taxRate') / 100;
var RECAPTURE_RATE = 0.25;
var landPct = 0.20;
var deprBasis = price * (1 - landPct);
var annualDepr = deprBasis / 27.5;
var params = {
baseRent: rent,
baseOther: v('pra-otherIncome'),
vacancy: v('pra-vacancy') / 100,
rentGrowth: v('pra-rentGrowth') / 100,
baseTaxes: taxes,
baseInsurance: ins,
baseHoa: v('pra-hoa'),
mgmtPct: v('pra-mgmt') / 100,
capexPct: v('pra-capex') / 100,
maintPct: v('pra-maint') / 100,
baseOtherCosts: v('pra-other-costs'),
pi: pi,
};
var yr1 = calcYear(1, params);
var capRate = (yr1.noi * 12) / price * 100;
var coC = totalCash > 0 ? (yr1.cashFlow * 12) / totalCash * 100 : 0;
var dscr = pi > 0 ? yr1.noi / pi : Infinity;
var grm = rent > 0 ? price / (rent * 12) : 0;
var balance = loanAmt;
var projRows = [], cumCF = 0, cumDepr = 0;
var irrCFpre = [-totalCash];
var irrCFpost = [-totalCash];
for (var yr = 1; yr <= holdYears; yr++) {
var yd = calcYear(yr, params);
var yearCF = yd.cashFlow * 12;
cumCF += yearCF;
cumDepr += annualDepr;
var yearEndBal = balance;
for (var m = 0; m < 12; m++) {
if (mRate === 0) { yearEndBal -= pi; }
else { yearEndBal -= (pi - yearEndBal * mRate); }
}
var principalPaid = balance - Math.max(yearEndBal, 0);
balance = Math.max(yearEndBal, 0);
var propVal = price * Math.pow(1 + appreciation, yr);
var equity = propVal - balance;
var grossProc = propVal * (1 - sellCostPct);
var netProc = grossProc - balance;
var adjBasis = price + closing - cumDepr;
var totalGain = Math.max(grossProc - adjBasis, 0);
var recapPortion = Math.min(cumDepr, totalGain);
var ltcgPortion = Math.max(totalGain - recapPortion, 0);
var recaptureTax = recapPortion * RECAPTURE_RATE;
var ltcgTax = ltcgPortion * ltcgRate;
var totalTaxOwed = recaptureTax + ltcgTax;
var netAfterTax = netProc - totalTaxOwed;
var totalReturnPreTax = cumCF + netProc;
var totalReturnAfterTax = cumCF + netAfterTax;
var roiPreTax = totalCash > 0 ? (totalReturnPreTax / totalCash) * 100 : 0;
var roiAfterTax = totalCash > 0 ? (totalReturnAfterTax / totalCash) * 100 : 0;
var annROIpre = (Math.pow(1 + roiPreTax / 100, 1 / yr) - 1) * 100;
var annROIpost = (Math.pow(1 + roiAfterTax / 100, 1 / yr) - 1) * 100;
irrCFpre.push(yearCF + (yr === holdYears ? netProc : 0));
irrCFpost.push(yearCF + (yr === holdYears ? netAfterTax : 0));
projRows.push({
yr:yr, rent:yd.rent, grossInc:yd.grossInc, effInc:yd.effInc,
totalOpEx:yd.totalOpEx, noi:yd.noi, cashFlow:yd.cashFlow,
yearCF:yearCF, cumCF:cumCF, principalPaid:principalPaid,
balance:balance, propVal:propVal, equity:equity,
netProc:netProc, netAfterTax:netAfterTax,
recaptureTax:recaptureTax, ltcgTax:ltcgTax, totalTaxOwed:totalTaxOwed,
ltcgPortion:ltcgPortion, recapturePortion:recapPortion,
totalReturnPreTax:totalReturnPreTax, totalReturnAfterTax:totalReturnAfterTax,
roiPreTax:roiPreTax, roiAfterTax:roiAfterTax,
annROIpre:annROIpre, annROIpost:annROIpost,
cumDepr:cumDepr, adjBasis:adjBasis
});
}
var irrPre = calcIRR(irrCFpre);
var irrPost = calcIRR(irrCFpost);
var stressVacancies = [0, 0.05, 0.10];
var stressResults = stressVacancies.map(function(vac) {
var sp = {};
for (var k in params) sp[k] = params[k];
sp.vacancy = vac;
return calcYear(1, sp);
});
lastData = {
address:vs('pra-address'), price:price, downAmt:downAmt, loanAmt:loanAmt,
closing:closing, rehab:rehab, totalCash:totalCash, pi:pi, yearBuilt:yearBuilt,
yr1:yr1, capRate:capRate, coC:coC, dscr:dscr, grm:grm,
annualDepr:annualDepr, deprBasis:deprBasis, landPct:landPct,
holdYears:holdYears, projRows:projRows,
irrPre:irrPre, irrPost:irrPost,
stressResults:stressResults, params:params,
ltcgRate:ltcgRate, mRate:mRate, sqft:v('pra-sqft')
};
praRender(lastData);
}
// ── Render ──
function praRender(d) {
var res = document.getElementById('pra-results');
res.style.display = 'block';
res.scrollIntoView({behavior:'smooth', block:'start'});
document.getElementById('pra-address-line').textContent = d.address || '';
var flags=[], score=0;
var cf=d.yr1.cashFlow, cr=d.capRate, co=d.coC, ds=d.dscr, gr=d.grm;
var ageYrs = new Date().getFullYear() - d.yearBuilt;
var negativeCF = cf < 0;
if(cf>=200){score+=2;flags.push({t:'good',msg:'Positive cash flow: '+fmtD(cf)+'/mo in Year 1 — covers expenses with margin'});}
else if(cf>=0){score+=1;flags.push({t:'warn',msg:'Breakeven cash flow: '+fmtD(cf)+'/mo in Year 1 — no buffer for surprises'});}
else{score-=2;flags.push({t:'bad',msg:'Negative cash flow: '+fmtD(cf)+'/mo in Year 1 — you are feeding this property every single month'});}
if(cr>=6){score+=2;flags.push({t:'good',msg:'Cap rate '+fmtPct(cr)+' — strong income return relative to price'});}
else if(cr>=4){score+=1;flags.push({t:'warn',msg:'Cap rate '+fmtPct(cr)+' — acceptable, but thin margin if expenses rise'});}
else{flags.push({t:'bad',msg:'Cap rate '+fmtPct(cr)+' — appreciation-dependent play; income alone does not carry this deal'});}
if(!isFinite(ds)){flags.push({t:'good',msg:'No debt — DSCR not applicable (all-cash purchase)'});score+=1;}
else if(ds>=1.25){score+=1;flags.push({t:'good',msg:'DSCR '+ds.toFixed(2)+' — NOI comfortably covers debt service'});}
else if(ds>=1.0){flags.push({t:'warn',msg:'DSCR '+ds.toFixed(2)+' — income barely covers debt; any vacancy could flip this negative'});}
else{score-=1;flags.push({t:'bad',msg:'DSCR '+ds.toFixed(2)+' — NOI does not cover debt service; lender risk flag'});}
if(co>=8){score+=1;flags.push({t:'good',msg:'Cash-on-cash '+fmtPct(co)+' — strong return on invested capital'});}
else if(co>=4){flags.push({t:'warn',msg:'Cash-on-cash '+fmtPct(co)+' — modest; compare against alternative capital deployments'});}
else{score-=1;flags.push({t:'bad',msg:'Cash-on-cash '+fmtPct(co)+' — weak Year 1 return on invested capital'});}
if(gr<=14){score+=1;flags.push({t:'good',msg:'GRM '+gr.toFixed(1)+' — price is reasonable relative to rental income for Phoenix SFR'});}
else if(gr<=18){flags.push({t:'warn',msg:'GRM '+gr.toFixed(1)+' — in the upper range for Phoenix; rent growth needed to justify price'});}
else{flags.push({t:'bad',msg:'GRM '+gr.toFixed(1)+' — price is expensive relative to rent; appreciation must do heavy lifting'});}
if(!isNaN(d.irrPre)){
if(d.irrPre>=12){score+=1;flags.push({t:'good',msg:'Pre-tax IRR '+fmtPct(d.irrPre)+' — strong risk-adjusted return over hold period'});}
else if(d.irrPre>=7){flags.push({t:'warn',msg:'Pre-tax IRR '+fmtPct(d.irrPre)+' — acceptable but below typical investor hurdle of 10–12%'});}
else{score-=1;flags.push({t:'bad',msg:'Pre-tax IRR '+fmtPct(d.irrPre)+' — low total return; capital likely better deployed elsewhere'});}
}
var lastProjRow = d.projRows[d.projRows.length-1];
if(lastProjRow && lastProjRow.netProc < 0){
score-=2;
flags.push({t:'bad',msg:'Net sale proceeds are negative at exit ('+fmtD(lastProjRow.netProc)+') — loan balance exceeds sale price after selling costs. You cannot exit this deal without bringing cash to the table.'});
}
if(ageYrs>=20){flags.push({t:'warn',msg:'Property is '+ageYrs+' years old — HVAC, roof, and water heater replacement cycles are near-term risks; verify CapEx reserve is adequate'});}
else if(ageYrs>=10){flags.push({t:'warn',msg:'Property is '+ageYrs+' years old — mid-cycle on major systems; review CapEx reserve adequacy'});}
else if(d.yearBuilt>1990){flags.push({t:'good',msg:'Property is '+ageYrs+' years old — newer build reduces near-term CapEx risk'});}
var verdict, vClass, vSub;
var lastPR2 = d.projRows[d.projRows.length-1];
var negProc = lastPR2 && lastPR2.netProc < 0;
if(negProc){
verdict='No-Go'; vClass='pra-verdict-no';
vSub='Loan balance exceeds sale price at exit ('+fmtD(lastPR2.netProc)+'). You cannot sell this property at the end of your hold period without bringing cash to the closing table.';
} else if(negativeCF){
verdict='Proceed with Caution'; vClass='pra-verdict-maybe';
vSub='Negative cash flow means you pay to own this property every month. This is a pure appreciation bet — only acceptable with a very strong Phoenix market conviction and reserves to sustain losses.';
} else if(score>=7){verdict='Strong Go';vClass='pra-verdict-go';vSub='Multiple metrics align. This property earns its place in a long-term portfolio.';}
else if(score>=5){verdict='Go with Eyes Open';vClass='pra-verdict-go';vSub='Solid fundamentals with areas to monitor. Negotiate or improve terms before closing.';}
else if(score>=2){verdict='Proceed with Caution';vClass='pra-verdict-maybe';vSub='This deal leans on appreciation more than income. Acceptable only if your Phoenix market thesis is strong.';}
else{verdict='No-Go';vClass='pra-verdict-no';vSub='Numbers do not support a long-term hold at this price and terms. Walk or renegotiate significantly.';}
document.getElementById('pra-verdict').className='pra-verdict '+vClass;
document.getElementById('pra-verdict-label').textContent=verdict;
document.getElementById('pra-verdict-sub').textContent=vSub;
var lastRow = d.projRows[d.projRows.length-1];
var metrics=[
{label:'Year 1 cash flow/mo', value:fmtD(cf), flag:cf>=200?'good':cf>=0?'warn':'bad'},
{label:'Cash-on-cash Yr 1', value:fmtPct(co), flag:co>=8?'good':co>=4?'warn':'bad'},
{label:'Cap rate', value:fmtPct(cr), flag:cr>=6?'good':cr>=4?'warn':'bad'},
{label:'DSCR', value:isFinite(ds)?ds.toFixed(2):'N/A', flag:isFinite(ds)&&ds>=1.25?'good':isFinite(ds)&&ds>=1.0?'warn':'bad'},
{label:'IRR (pre-tax)', value:fmtPct(d.irrPre), flag:d.irrPre>=12?'good':d.irrPre>=7?'warn':'bad'},
{label:'IRR (after-tax)', value:fmtPct(d.irrPost), flag:d.irrPost>=8?'good':d.irrPost>=4?'warn':'bad'},
{label:'Total cash in', value:fmtD(d.totalCash), flag:'neut'},
{label:'Equity at exit', value:fmtD(lastRow.equity), flag:'neut'},
];
document.getElementById('pra-metrics').innerHTML=metrics.map(function(m){
return '
';
}).join('');
var stressLabels=['0% vacancy (best case)','5% vacancy (base case)','10% vacancy (stress)'];
document.getElementById('pra-stress-grid').innerHTML=d.stressResults.map(function(s,i){
var cfClass=s.cashFlow>=200?'clr-good':s.cashFlow>=0?'clr-warn':'clr-bad';
var dscr2 = d.pi>0 ? s.noi/d.pi : Infinity;
return '
'+
'
'+stressLabels[i]+'
'+
'
Monthly CF'+fmtD(s.cashFlow)+'
'+
'
Annual CF'+fmtD(s.cashFlow*12)+'
'+
'
NOI/mo'+fmtD(s.noi)+'
'+
'
DSCR'+(isFinite(dscr2)?dscr2.toFixed(2):'N/A')+'
'+
'
';
}).join('');
document.getElementById('pra-depr-note').innerHTML=
'Depreciation note — Estimated annual depreciation: '+fmtD(d.annualDepr)+' '+
'(assumes '+Math.round(d.landPct*100)+'% land value; '+Math.round((1-d.landPct)*100)+'% improvement basis ÷ 27.5 years). '+
'Land allocation is an assumption — actual basis depends on your purchase allocation. '+
'At exit, accumulated depreciation is subject to 25% recapture tax, separate from long-term capital gains. '+
'Consult your CPA on actual depreciation basis, cost segregation opportunities, and recapture planning.';
document.getElementById('pra-tab-cashflow').innerHTML='
* Simple annualized ROI does not account for time value of money. True IRR (shown in Key Metrics above) is the accurate measure. ⚠ = negative net proceeds.
Recapture tax applies to accumulated depreciation at 25%. LTCG tax applies to remaining gain. Consult your CPA — a 1031 exchange eliminates both at exit.
';
}
// ── Tab switching ──
function praSwitchTab(name) {
document.querySelectorAll('.pra-tab').forEach(function(t){ t.classList.remove('active'); });
document.querySelectorAll('.pra-tab-content').forEach(function(t){ t.classList.remove('active'); });
var btn = document.getElementById('pra-tab-btn-' + name);
if (btn) btn.classList.add('active');
var content = document.getElementById('pra-tab-' + name);
if (content) content.classList.add('active');
}
// ── Reset ──
function praReset() {
document.getElementById('pra-results').style.display = 'none';
lastData = null;
window.scrollTo({top: 0, behavior: 'smooth'});
}
// ── PDF Export ──
function praExportPDF() {
if (!lastData) return;
var d = lastData;
var jsPDF = window.jspdf ? window.jspdf.jsPDF : null;
if (!jsPDF) { alert('PDF library not loaded. Please refresh the page and try again.'); return; }
var doc = new jsPDF({unit:'pt', format:'letter'});
var pw = doc.internal.pageSize.getWidth();
var ph = doc.internal.pageSize.getHeight();
var mg = 48, cw = pw - mg*2, y = 0;
function newPage() {
doc.addPage(); y = 0;
doc.setFillColor('#1a2332'); doc.rect(0,0,pw,28,'F');
doc.setFont('helvetica','bold'); doc.setFontSize(7); doc.setTextColor('#c8a96e');
doc.text('CAPSTONE REALTY PROFESSIONALS | PROPERTY INVESTMENT ANALYSIS',mg,18);
y = 44;
}
function checkPage(needed) { if (y + needed > ph - 40) newPage(); }
function hRule(w, color) { doc.setDrawColor(color||'#1a2332'); doc.setLineWidth(w||1); doc.line(mg,y,pw-mg,y); y+=(w>=1.5?12:8); }
function sTitle(txt) {
checkPage(28); y+=8;
doc.setFont('helvetica','bold'); doc.setFontSize(7); doc.setTextColor('#c8a96e');
doc.text(txt.toUpperCase(),mg,y); y+=4; hRule(0.5,'#e2e0db');
}
function kv(lbl, val, valColor) {
checkPage(16);
doc.setFont('helvetica','normal'); doc.setFontSize(9); doc.setTextColor('#4a5568'); doc.text(lbl,mg,y);
doc.setFont('helvetica','bold'); doc.setTextColor(valColor||'#1a2332'); doc.text(String(val),pw-mg,y,{align:'right'});
y+=16;
}
doc.setFillColor('#1a2332'); doc.rect(0,0,pw,60,'F');
doc.setFont('helvetica','bold'); doc.setFontSize(18); doc.setTextColor('#ffffff');
doc.text('Property Investment Analysis',mg,32);
doc.setFont('helvetica','normal'); doc.setFontSize(8); doc.setTextColor('#c8a96e');
doc.text('Capstone Realty Professionals | capstonerealtypros.com | 602-354-4660',mg,48);
y = 76;
doc.setFont('helvetica','bold'); doc.setFontSize(12); doc.setTextColor('#1a2332');
doc.text(d.address||'Address not provided',mg,y);
doc.setFont('helvetica','normal'); doc.setFontSize(8); doc.setTextColor('#4a5568');
doc.text('Generated '+new Date().toLocaleDateString('en-US',{year:'numeric',month:'long',day:'numeric'}),pw-mg,y,{align:'right'});
y+=8; hRule(2);
var cf=d.yr1.cashFlow, cr=d.capRate, co=d.coC, ds=d.dscr, sc=0;
var negCF=cf<0;
if(cf>=200)sc+=2;else if(cf>=0)sc+=1;else sc-=2;
if(cr>=6)sc+=2;else if(cr>=4)sc+=1;
if(isFinite(ds)&&ds>=1.25)sc+=1;else if(isFinite(ds)&&ds<1)sc-=1;
if(co>=8)sc+=1;else if(co<4)sc-=1;
if(d.grm<=14)sc+=1;
if(!isNaN(d.irrPre)){if(d.irrPre>=12)sc+=1;else if(d.irrPre<7)sc-=1;}
var lastPR=d.projRows[d.projRows.length-1];
if(lastPR&&lastPR.netProc<0)sc-=2;
var vLabel,vColor,vBg,vSub;
if(lastPR&&lastPR.netProc<0){vLabel='NO-GO';vColor='#8a2020';vBg='#fdf0f0';vSub='Loan balance exceeds sale price at exit — you cannot sell without bringing cash to closing.';}
else if(negCF){vLabel='PROCEED WITH CAUTION';vColor='#8a5e1a';vBg='#fdf5e6';vSub='Negative cash flow — you pay to own this property monthly. Pure appreciation bet.';}
else if(sc>=7){vLabel='STRONG GO';vColor='#2d6a2d';vBg='#edf6ed';vSub='Multiple metrics align. This property earns its place in a long-term portfolio.';}
else if(sc>=5){vLabel='GO WITH EYES OPEN';vColor='#2d6a2d';vBg='#edf6ed';vSub='Solid fundamentals with areas to monitor. Negotiate terms before closing.';}
else if(sc>=2){vLabel='PROCEED WITH CAUTION';vColor='#8a5e1a';vBg='#fdf5e6';vSub='Leans on appreciation more than income. Acceptable only with strong market thesis.';}
else{vLabel='NO-GO';vColor='#8a2020';vBg='#fdf0f0';vSub='Numbers do not support a long-term hold. Walk or renegotiate significantly.';}
doc.setFillColor(vBg); doc.roundedRect(mg,y,cw,54,3,3,'F');
doc.setDrawColor(vColor); doc.setLineWidth(4); doc.line(mg,y,mg,y+54);
y+=16; doc.setFont('helvetica','bold'); doc.setFontSize(13); doc.setTextColor(vColor); doc.text(vLabel,mg+12,y);
y+=14; doc.setFont('helvetica','normal'); doc.setFontSize(8.5); doc.setTextColor(vColor); doc.text(vSub,mg+12,y,{maxWidth:cw-20});
y+=30;
sTitle('Key metrics');
var met=[
{l:'Year 1 monthly cash flow',v:fmtD(cf),c:cf>=200?'#2d6a2d':cf>=0?'#8a5e1a':'#8a2020'},
{l:'Cash-on-cash (Year 1)',v:fmtPct(co),c:co>=8?'#2d6a2d':co>=4?'#8a5e1a':'#8a2020'},
{l:'Cap rate',v:fmtPct(cr),c:cr>=6?'#2d6a2d':cr>=4?'#8a5e1a':'#8a2020'},
{l:'DSCR',v:isFinite(ds)?ds.toFixed(2):'N/A',c:isFinite(ds)&&ds>=1.25?'#2d6a2d':isFinite(ds)&&ds>=1.0?'#8a5e1a':'#8a2020'},
{l:'IRR (pre-tax)',v:fmtPct(d.irrPre),c:d.irrPre>=10?'#2d6a2d':d.irrPre>=6?'#8a5e1a':'#8a2020'},
{l:'IRR (after-tax)',v:fmtPct(d.irrPost),c:d.irrPost>=8?'#2d6a2d':d.irrPost>=4?'#8a5e1a':'#8a2020'},
];
var mw=cw/3-6;
met.forEach(function(m,i){
var col=i%3, row=Math.floor(i/3);
var mx=mg+col*(mw+9), my=y+row*46;
doc.setFillColor('#f7f7f5'); doc.roundedRect(mx,my,mw,38,2,2,'F');
doc.setFont('helvetica','bold'); doc.setFontSize(6); doc.setTextColor('#4a5568'); doc.text(m.l.toUpperCase(),mx+8,my+12);
doc.setFont('helvetica','bold'); doc.setFontSize(12); doc.setTextColor(m.c); doc.text(m.v,mx+8,my+28);
});
y+=Math.ceil(met.length/3)*46+14;
sTitle('Year 1 income & expense breakdown');
kv('Down payment',fmtD(d.downAmt));
kv('Closing costs',fmtD(d.closing));
if(d.rehab>0) kv('Rehab / initial repairs',fmtD(d.rehab));
kv('Total cash invested',fmtD(d.totalCash));
kv('Gross monthly rent',fmtD(d.yr1.rent));
kv('Effective income after vacancy',fmtD(d.yr1.effInc));
kv('Property taxes',fmtD(d.yr1.taxes));
kv('Insurance',fmtD(d.yr1.insurance));
kv('HOA',fmtD(d.yr1.hoa));
kv('Property management',fmtD(d.yr1.mgmtCost));
kv('CapEx reserve',fmtD(d.yr1.capexCost));
kv('Maintenance reserve',fmtD(d.yr1.maintCost));
kv('Other carrying costs',fmtD(d.yr1.otherCosts));
kv('Net operating income (monthly)',fmtD(d.yr1.noi));
kv('Mortgage P&I',fmtD(d.pi));
kv('Monthly cash flow Year 1',fmtD(cf),cf>=0?'#2d6a2d':'#8a2020');
kv('Annual depreciation (est. — '+Math.round(d.landPct*100)+'% land assumed)',fmtD(d.annualDepr),'#8a5e1a');
sTitle('Vacancy stress test — Year 1');
var stressLbls=['0% vacancy','5% vacancy','10% vacancy'];
d.stressResults.forEach(function(s,i){
kv(stressLbls[i]+' — monthly CF',fmtD(s.cashFlow),s.cashFlow>=200?'#2d6a2d':s.cashFlow>=0?'#8a5e1a':'#8a2020');
});
newPage();
sTitle(d.holdYears+'-year cash flow projection (rent & expenses inflated annually)');
var cfCols=['Yr','Monthly Rent','Eff. Income','Total Expenses','NOI/mo','Monthly CF','Annual CF','Cumulative CF'];
var cfW=[20,76,76,82,68,72,72,88];
doc.setFillColor('#1a2332'); doc.rect(mg,y,cw,18,'F');
var hx2=mg+5;
cfCols.forEach(function(c,i){doc.setFont('helvetica','bold');doc.setFontSize(6.5);doc.setTextColor('#ffffff');doc.text(c,hx2,y+12);hx2+=cfW[i];});
y+=18;
d.projRows.forEach(function(r,ri){
checkPage(15);
if(ri%2===0){doc.setFillColor('#f7f7f5');doc.rect(mg,y,cw,15,'F');}
var rx=mg+5;
[String(r.yr),fmtD(r.rent),fmtD(r.effInc),fmtD(r.totalOpEx),fmtD(r.noi),fmtD(r.cashFlow),fmtD(r.yearCF),fmtD(r.cumCF)].forEach(function(val,i){
var color=i===5||i===6?(r.cashFlow>=200?'#2d6a2d':r.cashFlow>=0?'#8a5e1a':'#8a2020'):'#1a2332';
doc.setFont('helvetica',i===5||i===6?'bold':'normal');doc.setFontSize(8);doc.setTextColor(color);
doc.text(val,rx,y+10);rx+=cfW[i];
});
y+=15;
});
y+=10;
sTitle('After-tax exit analysis by year');
var retCols=['Yr','Net Proceeds','Recap. Tax','LTCG Tax','Total Tax','After-Tax Proceeds','After-Tax IRR'];
var retW=[20,80,76,72,66,96,74];
doc.setFillColor('#1a2332'); doc.rect(mg,y,cw,18,'F');
var hx3=mg+5;
retCols.forEach(function(c,i){doc.setFont('helvetica','bold');doc.setFontSize(6.5);doc.setTextColor('#ffffff');doc.text(c,hx3,y+12);hx3+=retW[i];});
y+=18;
d.projRows.forEach(function(r,ri){
checkPage(15);
if(ri%2===0){doc.setFillColor('#f7f7f5');doc.rect(mg,y,cw,15,'F');}
var rx=mg+5;
[String(r.yr),fmtD(r.netProc),fmtD(r.recaptureTax),fmtD(r.ltcgTax),fmtD(r.totalTaxOwed),fmtD(r.netAfterTax),r.yr===d.holdYears?fmtPct(d.irrPost):'—'].forEach(function(val,i){
doc.setFont('helvetica','normal');doc.setFontSize(8);doc.setTextColor('#1a2332');
doc.text(val,rx,y+10);rx+=retW[i];
});
y+=15;
});
var fp=ph-36;
doc.setDrawColor('#e2e0db');doc.setLineWidth(0.5);doc.line(mg,fp-8,pw-mg,fp-8);
doc.setFont('helvetica','normal');doc.setFontSize(6.5);doc.setTextColor('#aaaaaa');
doc.text('For informational purposes only. Does not constitute financial, legal, or investment advice. Depreciation recapture taxed at 25%; LTCG rate as entered. Consult a licensed CPA.',mg,fp);
doc.text('Capstone Realty Professionals | Licensed in Arizona | 602-354-4660 | capstonerealtypros.com',mg,fp+10);
var fn=(d.address?d.address.replace(/[^a-zA-Z0-9]/g,'-').substring(0,40):'property')+'-capstone-analysis.pdf';
doc.save(fn);
}
// ── Bind all events via addEventListener — WordPress safe ──
var analyzeBtn = document.getElementById('pra-analyze-btn');
if (analyzeBtn) analyzeBtn.addEventListener('click', praAnalyze);
var pdfBtn = document.getElementById('pra-pdf-btn');
if (pdfBtn) pdfBtn.addEventListener('click', praExportPDF);
var resetBtn = document.getElementById('pra-reset-btn');
if (resetBtn) resetBtn.addEventListener('click', praReset);
document.querySelectorAll('.pra-tab').forEach(function(btn) {
btn.addEventListener('click', function() {
praSwitchTab(btn.getAttribute('data-tab'));
});
});
}); // end DOMContentLoaded
We use cookies to enhance your browsing experience and analyze our traffic. By clicking "Accept", you consent to our use of cookies.