← back to Rentv Website

public/index.html

180 lines

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>RENTV.com — Commercial Real Estate News, Deals &amp; Conferences</title>
<meta name="description" content="Live commercial real estate news, deals, leases and financing across the Western U.S. — RENTV.com since 1998.">
<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Inter:wght@300;400;600;800&display=swap" rel="stylesheet">
<style>
  :root{--red:#c8102e;--ink:#14171a;--sub:#5b636b;--line:#e4e7ea;--bg:#fff;--wash:#f5f6f8;--sans:'Inter',system-ui,sans-serif;--serif:'Playfair Display',Georgia,serif}
  *{box-sizing:border-box;margin:0;padding:0}
  body{font-family:var(--sans);color:var(--ink);background:var(--bg);line-height:1.45}
  a{color:inherit;text-decoration:none}
  .wrap{max-width:1200px;margin:0 auto;padding:0 20px}
  .util{background:var(--ink);color:#cfd4d9;font-size:12px}
  .util .wrap{display:flex;justify-content:space-between;align-items:center;height:38px;gap:16px}
  .ticker{display:flex;gap:18px;overflow:hidden;white-space:nowrap;flex:1;min-width:0;-webkit-mask-image:linear-gradient(90deg,#000 90%,transparent);mask-image:linear-gradient(90deg,#000 90%,transparent)}
  .ticker span{flex:none}.ticker b{color:#fff;font-weight:600;letter-spacing:.02em}.up{color:#4ade80}.dn{color:#f87171}
  .util .acts{display:flex;align-items:center;flex:none}
  .util .acts a.sub{color:#fff;background:var(--red);padding:6px 15px;border-radius:5px;font-weight:700;letter-spacing:.02em;white-space:nowrap;transition:background .15s}
  .util .acts a.sub:hover{background:#a60d26}
  @media(max-width:860px){.util .wrap{gap:12px}.ticker{gap:14px}}
  .mast{border-bottom:2px solid var(--ink);padding:18px 0 12px}
  .mast{padding:20px 0 14px}
  .mast .wrap{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:3px}
  .logo{font-family:var(--serif);font-weight:700;font-size:34px;letter-spacing:-1px}.logo span{color:var(--red)}
  .logo small{display:block;font-size:11px;font-weight:600;letter-spacing:3px;color:var(--sub);text-transform:uppercase;margin-top:2px;font-family:var(--sans)}
  .datebox{font-size:12px;color:var(--sub);text-align:center}
  nav{border-bottom:1px solid var(--line);position:sticky;top:0;background:#fff;z-index:10}
  nav .wrap{display:flex;gap:2px;align-items:center;height:46px}
  .ham{display:none;background:none;border:0;font-size:24px;line-height:1;color:var(--ink);cursor:pointer;padding:8px 12px 8px 0;margin-right:4px}
  .navlinks{display:flex;gap:2px;align-items:center;overflow-x:auto}
  nav a{font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:14px 13px;border-bottom:3px solid transparent;white-space:nowrap;cursor:pointer}
  nav a:hover,nav a.on{color:var(--red);border-color:var(--red)}
  @media(max-width:860px){
    .ham{display:block;order:-1}
    nav .wrap{height:52px}
    .navlinks{display:none;position:absolute;top:52px;left:0;right:0;background:#fff;flex-direction:column;align-items:stretch;border-bottom:2px solid var(--ink);box-shadow:0 10px 24px rgba(0,0,0,.14);z-index:30;max-height:78vh;overflow-y:auto}
    .navlinks.open{display:flex}
    .navlinks a{padding:15px 20px;border-bottom:1px solid var(--line);border-left:4px solid transparent}
    .navlinks a:hover,.navlinks a.on{color:var(--red);border-bottom:1px solid var(--line);border-left-color:var(--red)}
  }
  .breaking{background:var(--red);color:#fff;font-size:13px}
  .breaking .wrap{display:flex;align-items:center;gap:14px;height:40px;overflow:hidden}
  .breaking .tag{background:#fff;color:var(--red);font-weight:800;text-transform:uppercase;font-size:11px;letter-spacing:.08em;padding:3px 9px;border-radius:2px;flex:none}
  .breaking .items{display:flex;gap:26px;white-space:nowrap;font-weight:600;animation:marq 40s linear infinite}
  @keyframes marq{from{transform:translateX(0)}to{transform:translateX(-50%)}}
  .grid{display:grid;grid-template-columns:1fr 320px;gap:34px;padding:28px 0}
  .chip{display:inline-block;font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--red);margin-bottom:6px}
  .lead{border-bottom:1px solid var(--line);padding-bottom:22px;margin-bottom:22px}
  .lead .img{aspect-ratio:16/8;border-radius:6px;background:linear-gradient(135deg,#1f2937,#c8102e);position:relative;overflow:hidden}
  .lead .img::after{content:'RENTV';position:absolute;right:12px;bottom:10px;color:rgba(255,255,255,.5);font-size:11px;letter-spacing:.2em}
  .lead h1{font-family:var(--serif);font-size:36px;line-height:1.12;margin:14px 0 8px;letter-spacing:-.5px}
  .lead .byl{font-size:12px;color:var(--sub);margin-top:8px}
  .sechead{display:flex;align-items:center;gap:12px;border-top:3px solid var(--ink);padding-top:10px;margin:30px 0 16px}
  .sechead h2{font-size:16px;text-transform:uppercase;letter-spacing:.06em}.sechead a{margin-left:auto;font-size:12px;color:var(--red);font-weight:700}
  .cards{display:grid;grid-template-columns:1fr 1fr 1fr;gap:22px}
  .card{display:block}
  .card .img{aspect-ratio:16/10;border-radius:5px;background:linear-gradient(135deg,#475569,#94a3b8)}
  .card:nth-child(3n+2) .img{background:linear-gradient(135deg,#7c2d12,#c8102e)}
  .card:nth-child(3n) .img{background:linear-gradient(135deg,#0f766e,#14b8a6)}
  .card h4{font-family:var(--serif);font-size:17px;line-height:1.22;margin:9px 0 4px}
  .card .byl{font-size:12px;color:var(--sub);margin-top:6px}
  .rail>*{margin-bottom:26px}.box{border:1px solid var(--line);border-radius:6px;padding:18px}
  .ns{background:var(--ink);color:#fff;border:0}.ns h3{font-size:18px;margin-bottom:6px}.ns p{font-size:13px;color:#b9c0c7;margin-bottom:12px}
  .ns input{width:100%;padding:11px;border:0;border-radius:4px;font-size:14px;margin-bottom:8px}
  .ns button{width:100%;padding:11px;background:var(--red);color:#fff;border:0;border-radius:4px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;font-size:12px;cursor:pointer}
  .ns .ok{font-size:12px;color:#4ade80;margin-top:6px;display:none}
  .mostread{counter-reset:mr;list-style:none}
  .mostread li{counter-increment:mr;display:flex;gap:12px;padding:12px 0;border-bottom:1px solid var(--line)}
  .mostread li::before{content:counter(mr);color:var(--red);font-family:var(--serif);font-size:26px;font-weight:700;line-height:1}
  .mostread a{font-size:14px;font-weight:600;line-height:1.25}
  .conf{background:linear-gradient(135deg,#111827,#c8102e);color:#fff;border:0;border-radius:6px;padding:22px}
  .conf .k{font-size:11px;letter-spacing:.2em;text-transform:uppercase;opacity:.85}.conf h3{font-family:var(--serif);font-size:22px;margin:6px 0 8px}
  .conf a{display:inline-block;background:#fff;color:var(--red);font-weight:800;font-size:12px;text-transform:uppercase;letter-spacing:.06em;padding:9px 16px;border-radius:4px}
  .live{display:inline-flex;align-items:center;gap:6px;font-size:11px;color:var(--sub);letter-spacing:.06em;text-transform:uppercase}
  .live .dot{width:7px;height:7px;border-radius:50%;background:#22c55e;box-shadow:0 0 0 0 rgba(34,197,94,.6);animation:pulse 2s infinite}
  @keyframes pulse{0%{box-shadow:0 0 0 0 rgba(34,197,94,.6)}70%{box-shadow:0 0 0 7px rgba(34,197,94,0)}100%{box-shadow:0 0 0 0 rgba(34,197,94,0)}}
  footer{background:var(--ink);color:#aeb6bd;margin-top:36px;padding:40px 0 30px;font-size:13px}
  footer .cols{display:grid;grid-template-columns:2fr 1fr 1fr 1fr;gap:28px}
  footer .logo{color:#fff;font-size:26px;margin-bottom:8px}footer h5{color:#fff;font-size:12px;text-transform:uppercase;letter-spacing:.08em;margin-bottom:10px}footer a{display:block;padding:4px 0;color:#aeb6bd}
  footer .fine{border-top:1px solid #2a2f34;margin-top:26px;padding-top:16px;font-size:12px;color:#7c848b}
  .skl{background:linear-gradient(90deg,#eee,#f6f6f6,#eee);background-size:200% 100%;animation:sh 1.2s infinite;border-radius:4px;color:transparent}
  @keyframes sh{to{background-position:-200% 0}}
  @media(max-width:860px){.grid{grid-template-columns:1fr}.cards{grid-template-columns:1fr 1fr}}
</style>
</head>
<body>
  <div class="util"><div class="wrap">
    <div class="ticker" id="ticker"><span><b>CRE INDEX</b> …</span><span><b>10-YR</b> …</span><span><b>LA OFFICE VAC</b> …</span><span><b>IE INDUSTRIAL CAP</b> …</span></div>
    <div class="acts"><a class="sub" href="#news">Subscribe</a></div>
  </div></div>

  <header class="mast"><div class="wrap">
    <div class="logo">REN<span>TV</span>.com<small>Commercial Real Estate News</small></div>
    <div class="datebox"><span id="edition">Western U.S. Edition</span><br><span id="today"></span></div>
  </div></header>

  <nav><div class="wrap">
    <button class="ham" id="hamBtn" aria-label="Menu" aria-expanded="false">☰</button>
    <div class="navlinks" id="nav">
      <a data-cat="all" class="on">Home</a><a data-cat="Sales">Sales</a><a data-cat="Leases">Leases</a><a data-cat="Financing">Financing</a><a data-cat="Development">Development</a><a data-cat="Multifamily">Multifamily</a><a data-cat="Industrial">Industrial</a><a data-cat="Retail">Retail</a><a href="/review">The REview</a><a href="/la-commercial">LA Commercial</a><a href="#conf">Conferences</a>
    </div>
  </div></nav>

  <div class="breaking"><div class="wrap">
    <span class="tag">Breaking</span><div class="items" id="breaking"><span>Loading live deals…</span></div>
  </div></div>

  <div class="wrap"><div class="grid">
    <main>
      <article class="lead" id="lead"><div class="img"></div><span class="chip">&nbsp;</span><h1 class="skl">&nbsp;<br>&nbsp;</h1><div class="byl">Loading the latest from RENTV…</div></article>
      <div class="sechead"><h2>Latest CRE News</h2><span class="live"><span class="dot"></span><span id="freshness">live</span></span></div>
      <div class="cards" id="cards"></div>
    </main>
    <aside class="rail">
      <div class="ns box"><h3>The RENTV Daily</h3><p>Western-U.S. commercial real estate deals in your inbox every morning — free.</p><input id="email" placeholder="you@company.com"><button id="subbtn">Subscribe free</button><div class="ok" id="subok">✓ You're on the list.</div></div>
      <div><div class="sechead" style="margin-top:0"><h2>Most Read</h2></div><ol class="mostread" id="mostread"></ol></div>
      <div class="conf" id="conf"><div class="k">RENTV Conferences</div><h3>State of the Market Summit</h3><p style="font-size:13px;opacity:.9">600+ brokers, investors &amp; developers · Los Angeles.</p><a href="#">Register →</a></div>
      <div class="box"><div class="sechead" style="margin-top:0"><h2>Market Snapshot</h2></div>
        <div style="display:flex;justify-content:space-between;padding:7px 0;border-bottom:1px solid var(--line);font-size:13px"><span>LA Office Vacancy</span><b>23.1%</b></div>
        <div style="display:flex;justify-content:space-between;padding:7px 0;border-bottom:1px solid var(--line);font-size:13px"><span>IE Industrial Cap</span><b>5.2%</b></div>
        <div style="display:flex;justify-content:space-between;padding:7px 0;font-size:13px"><span>SF Multifamily Rent YoY</span><b class="up">+3.4%</b></div>
      </div>
    </aside>
  </div></div>

  <footer><div class="wrap"><div class="cols">
    <div><div class="logo">REN<span style="color:var(--red)">TV</span>.com</div><p style="max-width:34ch">Commercial real estate news, deals &amp; conferences across the Western United States since 1998.</p></div>
    <div><h5>Sections</h5><a href="#">Deals</a><a href="#">Sales</a><a href="#">Leases</a><a href="#">Financing</a></div>
    <div><h5>Company</h5><a href="#">About</a><a href="#">Advertise</a><a href="#">Conferences</a><a href="#">Contact</a></div>
    <div><h5>Follow</h5><a href="#">LinkedIn</a><a href="#">X / Twitter</a><a href="#">Newsletters</a></div>
  </div><div class="fine">© 2026 RENTV.com · Headlines refreshed live from rentv.com · <span id="src"></span></div></div></footer>

<script>
document.getElementById('today').textContent = new Date().toLocaleDateString(undefined,{weekday:'long',year:'numeric',month:'long',day:'numeric'});
let ALL=[], cat='all';
const esc=s=>(s||'').replace(/[&<>"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]));
const bgimg=o=>(o&&o.image)?(' style="background:#12161a url(\''+esc(o.image)+'\') center/cover"'):'';
function render(){
  const items = cat==='all'?ALL:ALL.filter(x=>x.cat===cat);
  const lead=items[0];
  if(lead){document.getElementById('lead').innerHTML='<a href="/news/'+encodeURIComponent(lead.id)+'"><div class="img"'+bgimg(lead)+'></div><span class="chip">'+esc(lead.cat)+' · Western U.S.</span><h1>'+esc(lead.title)+'</h1><div class="byl">By RENTV Staff · live from rentv.com</div></a>';}
  const cards=items.slice(1,13).map(x=>'<a class="card" href="/news/'+encodeURIComponent(x.id)+'"><div class="img"'+bgimg(x)+'></div><span class="chip">'+esc(x.cat)+'</span><h4>'+esc(x.title)+'</h4><div class="byl">RENTV Staff</div></a>').join('');
  document.getElementById('cards').innerHTML=cards||'<p style="color:var(--sub)">No items in this section right now.</p>';
  document.getElementById('breaking').innerHTML=ALL.slice(0,6).map(x=>'<span>'+esc(x.title)+'</span>').join(' · ').repeat(2);
  document.getElementById('mostread').innerHTML=ALL.slice(0,5).map(x=>'<li><a href="/news/'+encodeURIComponent(x.id)+'">'+esc(x.title)+'</a></li>').join('');
}
async function load(){
  try{
    const d=await (await fetch('/api/news')).json();
    ALL=(d.items||[]).map(x=>({...x,title:x.title}));
    if(ALL.length){render();
      const mins=Math.max(0,Math.round((Date.now()-new Date(d.fetched_at))/60000));
      document.getElementById('freshness').textContent=mins<2?'updated just now':('updated '+mins+' min ago');
      document.getElementById('src').textContent='last pull '+new Date(d.fetched_at).toLocaleTimeString();
    }
  }catch(e){document.getElementById('lead').querySelector('.byl').textContent='Live feed temporarily unavailable — retrying…';}
}
const hamBtn=document.getElementById('hamBtn');
hamBtn.addEventListener('click',()=>{const open=document.getElementById('nav').classList.toggle('open');hamBtn.setAttribute('aria-expanded',open);});
document.getElementById('nav').addEventListener('click',e=>{const a=e.target.closest('a');if(!a)return;document.getElementById('nav').classList.remove('open');hamBtn.setAttribute('aria-expanded','false');if(!a.dataset.cat)return;e.preventDefault();document.querySelectorAll('#nav a').forEach(x=>x.classList.remove('on'));a.classList.add('on');cat=a.dataset.cat;render();window.scrollTo({top:0,behavior:'smooth'});});
document.getElementById('subbtn').onclick=()=>{if((document.getElementById('email').value||'').includes('@')){document.getElementById('subok').style.display='block';}};
async function loadTicker(){
  try{
    const t=await (await fetch('/api/ticker')).json();
    const cell=m=>{ if(!m||!m.value) return '';
      const amt=m.change_pct!=null?Math.abs(m.change_pct)+'%':(m.change_bps!=null?Math.abs(m.change_bps)+'bps':'');
      let arr=''; if(m.dir==='up')arr=' <span class="up">▲'+amt+'</span>'; else if(m.dir==='down')arr=' <span class="dn">▼'+amt+'</span>';
      return '<span><b>'+esc(m.label)+'</b> '+esc(m.value)+arr+'</span>'; };
    const html=[t.cre_index,t.ten_yr,t.la_office_vac,t.ie_industrial_cap].map(cell).filter(Boolean).join('');
    if(html) document.getElementById('ticker').innerHTML=html;
  }catch(e){/* keep prior ticker on failure */}
}
load(); setInterval(load, 120000); // refresh the live feed every 2 minutes
loadTicker(); setInterval(loadTicker, 120000); // live market ticker
</script>
</body>
</html>