← back to Commercialrealestate

public/fha-loans.html

253 lines

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect width='16' height='16' rx='3' fill='%230a0d13'/%3E%3Ctext x='8' y='12' font-size='11' text-anchor='middle' fill='%23c8a24b'%3E%24%3C/text%3E%3C/svg%3E">
<title>FHA / Low-Rate Loans — LA County CRE</title>
<link rel="stylesheet" href="/crcp-grid.css">
<script src="/crcp-grid.js"></script>
<style>
  :root{
    --gold:#e9c46a; --g2:#c8a24b; --violet:#8b7cf6; --teal:#2dd4bf; --blue:#60a5fa; --pink:#f472b6; --orange:#fb923c;
    --red:#f85149;
    --ink:#eef1f7; --muted:#9aa3b4; --glass:rgba(255,255,255,.055); --glassb:rgba(255,255,255,.12);
    /* crcp-grid engine theme mapping (liquid-glass) */
    --cg-line:rgba(255,255,255,.12); --cg-mut:#9aa3b4; --cg-ink:#eef1f7; --cg-card:rgba(255,255,255,.06);
    --cg-acc:#e9c46a; --cg-accbg:rgba(233,196,106,.14); --cg-railbg:rgba(255,255,255,.035);
    --cg-topbg:rgba(7,10,16,.72); --cg-red:#f85149;
  }
  *{box-sizing:border-box;margin:0;padding:0;}
  html,body{min-height:100%;background:#070a10;color:var(--ink);font:15px/1.5 -apple-system,'SF Pro Display',Segoe UI,Roboto,sans-serif;-webkit-font-smoothing:antialiased;}
  body::before{content:'';position:fixed;inset:-25%;z-index:-2;
    background:
      radial-gradient(38vw 38vw at 18% 22%, rgba(139,124,246,.40), transparent 60%),
      radial-gradient(34vw 34vw at 82% 18%, rgba(45,212,191,.34), transparent 60%),
      radial-gradient(40vw 40vw at 72% 86%, rgba(233,196,106,.30), transparent 62%),
      radial-gradient(36vw 36vw at 24% 88%, rgba(96,165,250,.30), transparent 60%);
    filter:saturate(1.25);animation:drift 26s ease-in-out infinite alternate;}
  body::after{content:'';position:fixed;inset:0;z-index:-1;backdrop-filter:blur(70px);background:rgba(7,10,16,.34);}
  @keyframes drift{0%{transform:translate3d(0,0,0) scale(1) rotate(0deg);}
    50%{transform:translate3d(2%,-2%,0) scale(1.08) rotate(4deg);}100%{transform:translate3d(-2%,2%,0) scale(1.04) rotate(-3deg);}}
  .wrap{max-width:1320px;margin:0 auto;padding:32px 32px 60px;}
  /* header */
  header{display:flex;align-items:center;gap:16px;margin-bottom:18px;flex-wrap:wrap;}
  .title h1{font-size:26px;font-weight:800;letter-spacing:-.5px;background:linear-gradient(92deg,#fff,var(--gold) 60%,var(--teal));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;}
  .title p{font-size:12.5px;color:var(--muted);margin-top:2px;}
  nav{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap;}
  nav a{font-size:12.5px;color:var(--muted);text-decoration:none;padding:7px 13px;border-radius:13px;
    background:var(--glass);border:1px solid var(--glassb);backdrop-filter:blur(14px);transition:.2s;}
  nav a:hover{color:#fff;border-color:rgba(233,196,106,.5);transform:translateY(-1px);}
  nav a.on{color:#fff;border-color:rgba(233,196,106,.6);background:linear-gradient(90deg,rgba(233,196,106,.22),rgba(45,212,191,.16));}
  /* glass */
  .glass{position:relative;background:var(--glass);border:1px solid var(--glassb);border-radius:22px;
    backdrop-filter:blur(22px) saturate(1.5);-webkit-backdrop-filter:blur(22px) saturate(1.5);
    box-shadow:0 12px 40px rgba(0,0,0,.40), inset 0 1px 0 rgba(255,255,255,.18), inset 0 -1px 0 rgba(0,0,0,.25);
    overflow:hidden;opacity:0;transform:translateY(14px);animation:rise .7s cubic-bezier(.2,.7,.2,1) forwards;}
  @keyframes rise{to{opacity:1;transform:none;}}
  /* explainer */
  .explain{padding:16px 19px;margin-bottom:16px;font-size:12.8px;color:#cfd6e4;line-height:1.65;}
  .explain h3{font-size:13px;font-weight:700;margin-bottom:7px;display:flex;align-items:center;gap:8px;color:#fff;}
  .explain .dot{width:9px;height:9px;border-radius:50%;display:inline-block;box-shadow:0 0 10px currentColor;}
  .explain b{color:#fff;} .explain code{background:rgba(255,255,255,.07);padding:1px 6px;border-radius:6px;font-size:11.5px;}
  .explain .caveat{margin-top:10px;padding:10px 12px;border-radius:11px;background:rgba(248,81,73,.08);border:1px solid rgba(248,81,73,.28);color:#ffd5d2;font-size:12px;}
  .explain a{color:var(--gold);text-decoration:none;border-bottom:1px dotted rgba(233,196,106,.5);}
  .explain a:hover{color:#fff;}
  .redkey{display:inline-block;width:11px;height:11px;border-radius:3px;background:var(--red);vertical-align:-1px;margin-right:4px;}
  /* hero tiles */
  .tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:20px;margin-bottom:22px;}
  .tile{padding:22px 24px;border:2px solid rgba(255,255,255,.4);}
  .tile .k{font-size:11px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted);}
  .tile .v{font-size:30px;font-weight:800;letter-spacing:-.5px;margin-top:6px;font-variant-numeric:tabular-nums;line-height:1;}
  .tile .s{font-size:11.5px;color:var(--muted);margin-top:6px;}
  .v.gold{background:linear-gradient(90deg,#fff,var(--gold));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;}
  .v.teal{background:linear-gradient(90deg,#fff,var(--teal));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;}
  .v.red{background:linear-gradient(90deg,#fff,var(--red));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;}
  .v.violet{background:linear-gradient(90deg,#fff,var(--violet));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;}
  /* controls */
  .controls{display:flex;gap:12px;align-items:center;padding:13px 19px;margin-bottom:14px;flex-wrap:wrap;}
  .controls input[type=text],.controls select{background:rgba(255,255,255,.05);color:var(--ink);border:1px solid var(--glassb);border-radius:11px;padding:8px 11px;font-size:13px;}
  .controls input[type=text]{min-width:240px;}
  .controls input[type=range]{accent-color:var(--gold);}
  .controls label{font-size:12px;color:var(--muted);display:flex;align-items:center;gap:7px;}
  .controls .count{margin-left:auto;font-size:12px;color:var(--muted);} .controls .count b{color:var(--ink);}
  /* table */
  .tablewrap{padding:6px;overflow-x:auto;}
  table{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--tsz,13px);font-variant-numeric:tabular-nums;}
  thead th{position:sticky;top:0;background:rgba(16,20,28,.92);backdrop-filter:blur(8px);text-align:left;
    font-size:11px;font-weight:700;letter-spacing:.4px;text-transform:uppercase;color:var(--muted);
    padding:11px 12px;border-bottom:1px solid var(--glassb);cursor:pointer;user-select:none;white-space:nowrap;}
  thead th:hover{color:#fff;}
  thead th .ar{opacity:.5;font-size:10px;margin-left:3px;}
  thead th.sorted{color:var(--gold);} thead th.sorted .ar{opacity:1;}
  tbody td{padding:9px 12px;border-bottom:1px solid rgba(255,255,255,.05);vertical-align:top;}
  tbody tr:hover td{background:rgba(255,255,255,.03);}
  tbody tr.red td{background:rgba(248,81,73,.07);}
  tbody tr.red:hover td{background:rgba(248,81,73,.12);}
  tbody tr.red td:first-child{border-left:3px solid var(--red);}
  td.prop{font-weight:600;color:#fff;}
  td.prop .loc{display:block;font-weight:400;color:var(--muted);font-size:.86em;margin-top:1px;}
  td.red-txt{color:var(--red);font-weight:700;}
  td.num{text-align:right;}
  .rate{font-weight:700;}
  .whybadge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:10.5px;font-weight:700;letter-spacing:.2px;cursor:help;margin:1px 2px 1px 0;}
  .whybadge.below{background:rgba(96,165,250,.18);color:#9cc4ff;border:1px solid rgba(96,165,250,.35);}
  .whybadge.era{background:rgba(248,81,73,.18);color:#ff9b94;border:1px solid rgba(248,81,73,.40);}
  .empty{padding:50px;text-align:center;color:var(--muted);}
  .foot{margin-top:20px;font-size:11px;color:var(--muted);text-align:center;line-height:1.7;}
  .pill{display:inline-block;padding:2px 9px;border-radius:11px;background:var(--glass);border:1px solid var(--glassb);margin:0 3px;}
  @media(prefers-reduced-motion:reduce){body::before{animation:none;}.glass{animation:none;opacity:1;transform:none;}}
</style>
</head>
<body>
<div class="wrap">
  <header>
    <div class="title">
      <h1>◆ FHA / Low-Rate Loans</h1>
      <p id="asof">HUD/FHA multifamily insured mortgages originally at ≤3.5% · loading…</p>
    </div>
    <nav>
      <a href="/">Properties</a><a href="/map.html">Map</a><a href="/deals.html">Deals</a>
      <a href="/crcp.html">CRCP</a><a href="/condos.html">Condos</a>
      <a href="/fha-loans.html" class="on">FHA Loans</a>
    </nav>
  </header>

  <div class="glass explain" style="animation-delay:.02s">
    <h3><span class="dot" style="color:var(--gold)"></span>What this shows</h3>
    <div>
      Every <b>HUD/FHA-insured multifamily (commercial) mortgage</b> that was originated at an
      <b>original interest rate of ≤ 3.5%</b>, pulled live from HUD's public Active Insured Mortgages
      file. Each loan is benchmarked against the <b>Freddie Mac PMMS</b> 30-year fixed market average
      for the month it closed.
      <span class="redkey"></span><b>Rows highlighted in red</b> fired at least one of two signals:
      <span class="whybadge below" style="cursor:default">BELOW MARKET</span> the rate is ≥ 0.75 pts under
      the month's market average · <span class="whybadge era" style="cursor:default">HISTORIC LOW ERA</span>
      it closed inside a derived rock-bottom-rate window. <b>RED = either signal</b>; hover a badge to see why.
      <div class="caveat">
        ⚠️ <b>Single-family caveat:</b> FHA <i>single-family</i> per-loan rate + address data is <b>not public</b>
        (borrower-privacy law), so individual home FHA loans cannot be listed here. The realistic public dataset
        carrying a property + an original interest rate is HUD/FHA <b>multifamily</b> (apartments, senior/healthcare
        housing, etc.) — that is exactly what this page reports. HUD's multifamily mortgage file lists property name +
        city/state/zip, not a street address line.
      </div>
      <div style="margin-top:9px;font-size:11.5px;">
        Sources:
        <a id="srcHud" href="#" target="_blank" rel="noopener noreferrer">HUD Active Insured Multifamily Mortgages</a> ·
        <a id="srcPmms" href="#" target="_blank" rel="noopener noreferrer">Freddie Mac PMMS 30-yr history</a> ·
        <a id="srcFred" href="#" target="_blank" rel="noopener noreferrer">FRED MORTGAGE30US</a>
        <span id="windows" style="color:var(--muted)"></span>
        · <span style="color:var(--teal)">$0 — all public data</span>
      </div>
    </div>
  </div>

  <div class="tiles" id="tiles"></div>

  <div class="glass" style="animation-delay:.1s;padding:0;overflow:hidden">
    <div class="cg-shell">
      <aside class="cg-rail" id="cgRail"></aside>
      <div class="cg-main" id="cgMain"><div class="empty" style="padding:50px">loading real HUD data…</div></div>
    </div>
  </div>

  <div class="foot">
    <span class="pill">Liquid-glass UI · 2026</span><span class="pill">HUD Open Data</span>
    <span class="pill">Freddie Mac PMMS</span><span class="pill">real data · $0</span><br>
    Scope: HUD/FHA multifamily insured mortgages (commercial). Single-family FHA per-loan data is not public. Not financial advice.
  </div>
</div>

<script>
const $=s=>document.querySelector(s);
const F={
  money:n=>(n==null||!isFinite(n))?'—':'$'+(n>=1e9?(n/1e9).toFixed(2)+'B':n>=1e6?(n/1e6).toFixed(2)+'M':n>=1e3?Math.round(n/1e3)+'k':n),
  num:n=>{n=Number(n);return isFinite(n)?n.toLocaleString():'—';},
  pct:n=>(n==null||!isFinite(n))?'—':(+n).toFixed(2)+'%',
};
let DATA=null, ROWS=[], GRID=null;

// Every data point — each toggleable (drives cards + list columns) for the crcp-grid engine.
const FIELDS=[
  {k:'rate',           l:'Orig. Rate',  pct:1,   col:1, def:1},
  {k:'pmmsBenchmark',  l:'Market avg',  pct:1,   col:1, def:1},
  {k:'originalAmount', l:'Loan amount', money:1, col:1, def:1},
  {k:'originationDate',l:'Originated',           col:1, def:1},
  {k:'units',          l:'Units',       num:1,   col:1, def:1},
  {k:'flag',           l:'Flag',                 col:1, def:1, calc:r=> r.red ? (r.belowMarket&&r.historicLowEra?'Below + Era':r.belowMarket?'Below market':'Historic-low era') : '—'},
  {k:'city',           l:'City',                 col:1, def:0},
  {k:'state',          l:'State',                col:1, def:0},
  {k:'zip',            l:'ZIP',                  col:1, def:0},
  {k:'holder',         l:'Lender',               col:1, def:0},
];
const FACETS=[
  {k:'flag',  l:'Flag',          type:'chip', calc:r=> r.red ? (r.belowMarket&&r.historicLowEra?'Below + Era':r.belowMarket?'Below market':'Historic-low era') : 'Not flagged'},
  {k:'state', l:'State',         type:'chip'},
  {k:'city',  l:'City',          type:'chip', max:20},
  {k:'year',  l:'Year closed',   type:'chip', calc:r=>String(r.originationDate||'').slice(0,4), max:24},
  {k:'rate',  l:'Orig. rate %',  type:'range'},
  {k:'originalAmount', l:'Loan amount $', type:'range', money:1},
  {k:'units', l:'Units',         type:'range'},
];

function badge(r){
  if(!r.red) return '<span style="color:var(--muted)">—</span>';
  const reasons=r.redReasons||[];
  let html='';
  if(r.belowMarket){
    const t=reasons.find(x=>/below the/.test(x))||'';
    html+=`<span class="whybadge below" title="${t.replace(/"/g,'&quot;')}">BELOW MARKET</span>`;
  }
  if(r.historicLowEra){
    const t=reasons.find(x=>/historic/.test(x))||'';
    html+=`<span class="whybadge era" title="${t.replace(/"/g,'&quot;')}">HISTORIC LOW ERA</span>`;
  }
  return html;
}

function mountGrid(rows){
  GRID=CrcpGrid.mount({
    data:rows, fields:FIELDS, facets:FACETS,
    mount:'#cgMain', rail:'#cgRail', view:'list', cols:2,
    storageKey:'fha', titleCol:'Property',
    title:r=>({ name:r.property||'(name n/a)', sub:[r.city,r.state].filter(Boolean).join(', ')+' '+(r.zip||'')+(r.holder?' · '+r.holder:'') }),
    search:r=>((r.property||'')+' '+(r.city||'')+' '+(r.state||'')+' '+(r.zip||'')+' '+(r.holder||'')),
    badgeHtml:r=> r.red ? `<div style="margin:2px 0">${badge(r)}</div>` : '',
    onRow:r=>({cls:r.red?'red':''}),
  });
}

function renderTiles(d){
  const tiles=[
    {k:'Loans ≤3.5%',v:F.num(d.count),cls:'gold',s:'original interest rate at or under 3.5%'},
    {k:'Flagged RED',v:F.num(d.redCount),cls:'red',s:'below-market OR historic-low-era'},
    {k:'Below market',v:F.num((d.redSplit.belowMarketOnly||0)+(d.redSplit.both||0)),cls:'violet',s:'≥0.75pt under the month avg'},
    {k:'Historic-low era',v:F.num((d.redSplit.historicLowEraOnly||0)+(d.redSplit.both||0)),cls:'teal',s:'closed in a rate-trough window'},
  ];
  $('#tiles').innerHTML=tiles.map((t,i)=>
    `<div class="glass tile" style="animation-delay:${.05+i*.04}s"><div class="k">${t.k}</div>`+
    `<div class="v ${t.cls}">${t.v}</div><div class="s">${t.s}</div></div>`).join('');
}

async function load(){
  let d;
  try{ d=await (await fetch('/data/fha-loans.json')).json(); }
  catch(e){ $('#asof').textContent='data load error — run scripts/fetch-fha-loans.js to populate data/fha-loans.json'; $('#cgMain').innerHTML='<div class="empty" style="padding:50px">No data file. Run <code>node scripts/fetch-fha-loans.js</code> to fetch real HUD + PMMS data.</div>'; return; }
  DATA=d; ROWS=d.rows||[];
  renderTiles(d);
  // source links
  const s=d.sources||[];
  const find=sub=>(s.find(x=>(x.url||'').includes(sub))||{}).url||'#';
  $('#srcHud').href=find('hud.gov'); $('#srcPmms').href=find('freddiemac'); $('#srcFred').href=find('fred');
  const w=(d.historicLowWindows||[]).map(x=>x.start+'…'+x.end).join(', ');
  $('#windows').textContent=w?(' · historic-low windows: '+w):'';
  const gen=d.generatedAt?new Date(d.generatedAt).toLocaleString(undefined,{year:'numeric',month:'short',day:'numeric',hour:'numeric',minute:'2-digit'}):'';
  $('#asof').textContent=`${F.num(d.count)} HUD/FHA multifamily loans ≤3.5% · ${F.num(d.redCount)} red · benchmarked vs Freddie Mac PMMS · updated ${gen}`;
  mountGrid(ROWS);
}
load();
</script>
  <script src="/col-resize.js" defer></script>
</body>
</html>