← back to Commercialrealestate
CRCP theme Cody-gate fixes: lending-grid.css + deals-flow + map #phmodal dark literals -> theme vars (light mode now flips); reconcile condos native theme onto crcp-theme key (was double-added)
fcfd72b96b82dcef6bf461cc0d7d6c1ff8db4526 · 2026-08-18 18:04:00 -0700 · Steve Abrams
Files touched
M public/condos.htmlM public/deals-flow.htmlM public/lending-grid.css
Diff
commit fcfd72b96b82dcef6bf461cc0d7d6c1ff8db4526
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Aug 18 18:04:00 2026 -0700
CRCP theme Cody-gate fixes: lending-grid.css + deals-flow + map #phmodal dark literals -> theme vars (light mode now flips); reconcile condos native theme onto crcp-theme key (was double-added)
---
public/condos.html | 9 +++------
public/deals-flow.html | 26 +++++++++++++-------------
public/lending-grid.css | 12 ++++++------
3 files changed, 22 insertions(+), 25 deletions(-)
diff --git a/public/condos.html b/public/condos.html
index 3ed743b..fab791b 100644
--- a/public/condos.html
+++ b/public/condos.html
@@ -1,9 +1,8 @@
<!doctype html>
<html lang="en">
<head>
-<script>(function(){try{var t=localStorage.getItem('crcp-theme');document.documentElement.setAttribute('data-theme',t==='light'?'light':'dark');}catch(e){document.documentElement.setAttribute('data-theme','dark');}})();</script>
<script>/* credential-safe fetch (2026-08-18): resolve EVERY relative fetch (with or without a leading slash) against a credential-free base so creds embedded in the page URL (http://user:pass@host/...) don't poison document.baseURI and throw "Request cannot be constructed from a URL that includes credentials". */(function(){var of=window.fetch,O=location.origin;window.fetch=function(u,o){try{if(typeof u==='string'){if(/^[a-z][a-z0-9+.-]*:/i.test(u)){var x=new URL(u);if(x.username||x.password){x.username='';x.password='';u=x.href;}}else{u=new URL(u,O+location.pathname+location.search).href;}}else if(u&&typeof u.url==='string'){var y=new URL(u.url,O+location.pathname+location.search);if(y.username||y.password){y.username='';y.password='';u=new Request(y.href,u);}}}catch(e){}return of.call(this,u,o);};try{if(location.href.indexOf('@')>=0){history.replaceState(null,'',location.pathname+location.search+location.hash);}}catch(e){}})();</script>
-<script>(function(){try{var t=localStorage.getItem('crcp-theme2');document.documentElement.setAttribute('data-theme',t==='dark'?'dark':'light');}catch(e){document.documentElement.setAttribute('data-theme','light');}})();</script>
+<script>(function(){try{var t=localStorage.getItem('crcp-theme');document.documentElement.setAttribute('data-theme',t==='dark'?'dark':'light');}catch(e){document.documentElement.setAttribute('data-theme','light');}})();</script>
<!-- Self-heal: nav-agent grid controls can persist a "removed"/"collapsed" state that hides the
whole grid with no obvious way back. Clear it before nav-agent runs so a grid can never stay hidden. -->
<script>(function(){try{for(var i=localStorage.length-1;i>=0;i--){var k=localStorage.key(i);if(k&&k.indexOf('navagent:')===0){var v=localStorage.getItem(k);if(v&&v.indexOf('"removed":true')>=0){localStorage.removeItem(k);}}}}catch(e){}})();</script>
@@ -140,7 +139,6 @@
<link rel="stylesheet" href="/three-view.css">
<script src="/three-view.js"></script>
<link rel="stylesheet" href="/nav-agent/nav-agent.css"><!-- nav-agent -->
- <link rel="stylesheet" href="/crcp-theme.css"><!-- CRCP day/night tokens: load LAST so html[data-theme] wins -->
</head>
<body>
<header>
@@ -160,10 +158,10 @@
if(ic) ic.textContent = t==='light'?'☀️':'🌙';
if(lb) lb.textContent = t==='light'?'Day':'Night';
}
- var cur; try{ cur=localStorage.getItem('crcp-theme2'); }catch(e){}
+ var cur; try{ cur=localStorage.getItem('crcp-theme'); }catch(e){}
apply(cur==='dark'?'dark':'light');
var btn=document.getElementById('themeToggle');
- if(btn) btn.addEventListener('click',function(){ var nt=root.getAttribute('data-theme')==='light'?'dark':'light'; apply(nt); try{ localStorage.setItem('crcp-theme2',nt); }catch(e){} });
+ if(btn) btn.addEventListener('click',function(){ var nt=root.getAttribute('data-theme')==='light'?'dark':'light'; apply(nt); try{ localStorage.setItem('crcp-theme',nt); }catch(e){} });
})();
</script>
<div class="banner" id="banner">⚖️ Loading warrantability label…</div>
@@ -855,6 +853,5 @@ boot();
<script src="/sort-bar.js" defer></script>
<script src="/corner-nav.js" defer></script>
<script src="/nav-agent/nav-agent.js" defer></script><!-- nav-agent -->
- <script src="/crcp-theme.js" defer></script><!-- CRCP day/night toggle (auto-injects into header) -->
</body>
</html>
diff --git a/public/deals-flow.html b/public/deals-flow.html
index bf27fb5..16b53f1 100644
--- a/public/deals-flow.html
+++ b/public/deals-flow.html
@@ -10,7 +10,7 @@
:root{--bg:#0e1116;--card:#161b22;--line:#2a313c;--ink:#e6edf3;--mut:#8b949e;--acc:#3fb950;--blue:#58a6ff;--gold:#ffa600;--violet:#bc8cff;--cols:4}
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font-family:-apple-system,Helvetica,Arial,sans-serif;font-size:13px}
header{padding:14px 18px;border-bottom:1px solid var(--line);display:flex;flex-wrap:wrap;gap:10px;align-items:center}
-h1{font-size:17px;margin:0}h1 b{color:#fff}
+h1{font-size:17px;margin:0}h1 b{color:var(--ink,#fff)}
.badge{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:#0e1116;background:var(--acc);padding:3px 8px;border-radius:6px}
.nav a{color:var(--blue);text-decoration:none;font-size:12px;margin-left:12px}
.shell{display:flex;align-items:flex-start}
@@ -29,7 +29,7 @@ select{background:var(--card);border:1px solid var(--line);color:var(--ink);bord
.count{color:var(--mut);font-size:12px}
.prov{font-size:11px;color:var(--mut);margin:0 0 12px;line-height:1.5}
.stat{display:inline-block;background:var(--card);border:1px solid var(--line);border-radius:9px;padding:7px 12px;margin:0 8px 10px 0}
-.stat b{font-size:18px;color:#fff}.stat span{display:block;font-size:10px;text-transform:uppercase;color:var(--mut);letter-spacing:.4px}
+.stat b{font-size:18px;color:var(--ink,#fff)}.stat span{display:block;font-size:10px;text-transform:uppercase;color:var(--mut);letter-spacing:.4px}
.grid{display:grid;grid-template-columns:repeat(var(--cols),1fr);gap:12px}
.dcard{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:13px 14px;display:flex;flex-direction:column;gap:7px}
.dcard .top{display:flex;justify-content:space-between;align-items:flex-start;gap:8px}
@@ -54,21 +54,21 @@ select{background:var(--card);border:1px solid var(--line);color:var(--ink);bord
.conf{font-size:9.5px;padding:1px 6px;border-radius:20px}
.conf.high{background:rgba(63,185,80,.16);color:var(--acc)} .conf.med{background:rgba(210,153,34,.16);color:var(--gold)} .conf.low{background:rgba(139,148,158,.16);color:var(--mut)}
/* ── breaking-news ticker (horizontal marquee) ── */
-.ticker{display:flex;align-items:stretch;background:#0b0e13;border-bottom:1px solid var(--line);overflow:hidden;height:32px}
+.ticker{display:flex;align-items:stretch;background:var(--bg2,#0b0e13);border-bottom:1px solid var(--line);overflow:hidden;height:32px}
.ticker .lbl{flex:0 0 auto;display:flex;align-items:center;gap:6px;background:var(--acc);color:#0b0e13;font-weight:800;font-size:10px;letter-spacing:.6px;text-transform:uppercase;padding:0 13px;white-space:nowrap}
-.ticker .lbl::before{content:"";width:7px;height:7px;border-radius:50%;background:#0b0e13;animation:blip 1.1s steps(1) infinite}
+.ticker .lbl::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--bg2,#0b0e13);animation:blip 1.1s steps(1) infinite}
@keyframes blip{50%{opacity:.25}}
.ticker .vp{flex:1;overflow:hidden;position:relative}
.ticker .track{display:inline-flex;align-items:center;height:100%;white-space:nowrap;animation:tick 180s linear infinite;will-change:transform}
.ticker .vp:hover .track{animation-play-state:paused}
.ticker.is-stopped .track{animation-play-state:paused}
-.ticker .tk-ctrl{flex:0 0 auto;display:flex;align-items:center;justify-content:center;width:34px;background:#0b0e13;border:none;border-left:1px solid #20262f;color:var(--ink);font-size:13px;line-height:1;cursor:pointer;transition:background .15s,color .15s}
-.ticker .tk-ctrl:hover{background:#161b22;color:#fff}
+.ticker .tk-ctrl{flex:0 0 auto;display:flex;align-items:center;justify-content:center;width:34px;background:var(--bg2,#0b0e13);border:none;border-left:1px solid #20262f;color:var(--ink);font-size:13px;line-height:1;cursor:pointer;transition:background .15s,color .15s}
+.ticker .tk-ctrl:hover{background:#161b22;color:var(--ink,#fff)}
.ticker.is-stopped #tkCtrl{color:var(--acc)}
/* dismissed state: collapse to a clickable "show" strip — always restorable (no one-way door) */
.ticker.is-dismissed .vp,.ticker.is-dismissed #tkCtrl,.ticker.is-dismissed #tkClose{display:none}
.ticker.is-dismissed{cursor:pointer}
-.ticker.is-dismissed .lbl{flex:1;justify-content:flex-start;background:#0b0e13;color:var(--muted,#8b949e);font-weight:700}
+.ticker.is-dismissed .lbl{flex:1;justify-content:flex-start;background:var(--bg2,#0b0e13);color:var(--muted,#8b949e);font-weight:700}
.ticker.is-dismissed .lbl::before{background:var(--acc)}
.ticker.is-dismissed .lbl::after{content:"▸ show";margin-left:8px;color:var(--blue);font-weight:800}
.ticker .it{display:inline-flex;align-items:center;gap:8px;padding:0 20px;font-size:12px;color:var(--ink);border-right:1px solid #20262f}
@@ -79,7 +79,7 @@ select{background:var(--card);border:1px solid var(--line);color:var(--ink);bord
@media (prefers-reduced-motion:reduce){.ticker .track{animation:none}}
/* ── personalized welcome strip ── */
.persona{background:linear-gradient(120deg,rgba(63,185,80,.10),rgba(88,166,255,.06));border:1px solid var(--line);border-radius:12px;padding:12px 15px;margin-bottom:13px;display:flex;flex-wrap:wrap;gap:11px 14px;align-items:center}
-.persona h2{font-size:15px;margin:0;color:#fff;font-weight:600}
+.persona h2{font-size:15px;margin:0;color:var(--ink,#fff);font-weight:600}
.persona .role{font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:var(--acc);border:1px solid rgba(63,185,80,.35);border-radius:20px;padding:2px 9px;white-space:nowrap}
.persona .tip{flex-basis:100%;font-size:11.5px;color:var(--mut);margin:-2px 0 0}
.persona .qa{display:flex;flex-wrap:wrap;gap:8px;margin-left:auto}
@@ -90,18 +90,18 @@ select{background:var(--card);border:1px solid var(--line);color:var(--ink);bord
.modal{position:fixed;inset:0;background:rgba(3,6,10,.68);display:none;align-items:center;justify-content:center;z-index:120}
.modal.on{display:flex}
.modal .box{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:21px 23px;width:350px;max-width:92vw}
-.modal h3{margin:0 0 4px;font-size:17px;color:#fff}
+.modal h3{margin:0 0 4px;font-size:17px;color:var(--ink,#fff)}
.modal p{margin:0 0 6px;font-size:12px;color:var(--mut);line-height:1.5}
.modal label{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--mut);margin:12px 0 4px}
-.modal input{width:100%;background:#0e1116;border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:9px 11px;font-size:13px}
+.modal input{width:100%;background:var(--card,#0e1116);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:9px 11px;font-size:13px}
.modal .btn{width:100%;margin-top:16px;background:var(--acc);color:#0b0e13;border:0;border-radius:8px;padding:10px;font-size:13px;font-weight:700;cursor:pointer}
.modal .err{color:#ff7b72;font-size:12px;margin-top:10px;min-height:15px}
.modal .alt{font-size:11px;color:var(--blue);cursor:pointer;margin-top:13px;display:inline-block}
.roleopts{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:8px}
-.roleopt{border:1px solid var(--line);border-radius:10px;padding:11px 9px;font-size:12px;cursor:pointer;background:#0e1116;text-align:center;line-height:1.3}
+.roleopt{border:1px solid var(--line);border-radius:10px;padding:11px 9px;font-size:12px;cursor:pointer;background:var(--card,#0e1116);text-align:center;line-height:1.3}
.roleopt:hover{border-color:var(--blue)}
.roleopt.sel{border-color:var(--acc);background:rgba(63,185,80,.12)}
-.roleopt b{display:block;color:#fff;font-size:12.5px}
+.roleopt b{display:block;color:var(--ink,#fff);font-size:12.5px}
.roleopt span{font-size:10px;color:var(--mut)}
</style> <link rel="stylesheet" href="/nav-agent/nav-agent.css"><!-- nav-agent -->
<link rel="stylesheet" href="/crcp-theme.css"><!-- CRCP day/night tokens: load LAST so html[data-theme] wins -->
@@ -312,7 +312,7 @@ const ROLE_META={
other:{label:'Member',tip:'',qa:[['📊 Deal flow','/deals-flow.html'],['🏷️ Listings','/mls.html']]}
};
const ROLE_OPTS=[['loan_officer','Loan Officer','mortgage / lending'],['listing_agent','Listing Agent','brokerage — listing'],['buyers_agent','Buyer’s Agent','brokerage — buy-side'],['investor','Investor','principal / capital'],['appraiser','Appraiser','valuation'],['other','Something else','']];
-function renderAuth(){const el=$('#auth');if(ME&&ME.email){const who=esc(ME.name||ME.username||ME.email);const rl=ME.role&&ROLE_META[ME.role]?ROLE_META[ME.role].label:'';el.innerHTML=`<b style="color:#fff">${who}</b>${rl?` · <span style="color:var(--acc)">${esc(rl)}</span>`:''}${ME.perm==='admin'?` · <a href="/admin.html" style="color:var(--gold)">Admin</a>`:''} · <a id="signOutLink" style="color:var(--blue);cursor:pointer">sign out</a>`;el.querySelector('#signOutLink').onclick=async()=>{await fetch('/auth/logout',{method:'POST'});location.reload();};el.onclick=null;}else{el.textContent='Sign in';el.onclick=openLogin;}}
+function renderAuth(){const el=$('#auth');if(ME&&ME.email){const who=esc(ME.name||ME.username||ME.email);const rl=ME.role&&ROLE_META[ME.role]?ROLE_META[ME.role].label:'';el.innerHTML=`<b style="color:var(--ink,#fff)">${who}</b>${rl?` · <span style="color:var(--acc)">${esc(rl)}</span>`:''}${ME.perm==='admin'?` · <a href="/admin.html" style="color:var(--gold)">Admin</a>`:''} · <a id="signOutLink" style="color:var(--blue);cursor:pointer">sign out</a>`;el.querySelector('#signOutLink').onclick=async()=>{await fetch('/auth/logout',{method:'POST'});location.reload();};el.onclick=null;}else{el.textContent='Sign in';el.onclick=openLogin;}}
function renderPersona(){const p=$('#persona');if(!(ME&&ME.email&&ME.role)){p.style.display='none';return;}const m=ROLE_META[ME.role]||ROLE_META.other;const who=esc(ME.name||ME.username||'there');p.style.display='';p.innerHTML=`<h2>Welcome back, ${who}</h2><span class="role">${esc(m.label)}</span><div class="qa">${m.qa.map(([t,h])=>`<a href="${h}">${t}</a>`).join('')}</div>${m.tip?`<p class="tip">${esc(m.tip)}</p>`:''}<span class="edit" id="editRole">change role</span>`;const er=$('#editRole');if(er)er.onclick=openRole;}
async function loadMe(){try{ME=await api('/api/me');}catch(e){ME=null;}renderAuth();renderPersona();$('#savedSec').style.display=(ME&&ME.email)?'':'none';if(ME&&ME.email){loadSaved();loadWatch();if(!ME.role)openRole();}}
// ── sign-in modal (username + password) ──
diff --git a/public/lending-grid.css b/public/lending-grid.css
index a91912d..69587e4 100644
--- a/public/lending-grid.css
+++ b/public/lending-grid.css
@@ -16,7 +16,7 @@ header .nav{display:flex;gap:12px;margin-left:6px;flex-wrap:wrap;} header .nav a
#denswrap{display:none;align-items:center;gap:6px;font-size:13px;color:var(--mut)}
#denswrap input[type=range]{width:92px;accent-color:var(--acc)}
.shell{display:flex;align-items:flex-start;}
-.rail{flex:0 0 260px;background:#0a0d13;border-right:1px solid var(--line);align-self:stretch;position:sticky;top:53px;height:calc(100vh - 53px);overflow-y:auto;padding:0 0 40px;}
+.rail{flex:0 0 260px;background:var(--bg2,#0a0d13);border-right:1px solid var(--line);align-self:stretch;position:sticky;top:53px;height:calc(100vh - 53px);overflow-y:auto;padding:0 0 40px;}
.rail .rsec{padding:13px 16px;border-bottom:1px solid var(--line);}
.rail h4{margin:0 0 9px;font-size:11px;text-transform:uppercase;letter-spacing:.6px;color:var(--mut);}
.rail .rsec > h4 { cursor:pointer; display:flex; align-items:center; justify-content:space-between; user-select:none; }
@@ -36,12 +36,12 @@ header .nav{display:flex;gap:12px;margin-left:6px;flex-wrap:wrap;} header .nav a
.databar .pubtag{color:var(--acc);border:1px solid rgba(112,173,71,.5);border-radius:8px;padding:2px 8px;font-size:10.5px;text-transform:uppercase;letter-spacing:.4px;}
.tblwrap{overflow:auto;max-height:calc(100vh - 140px);border:1px solid var(--line);border-radius:10px;margin:16px 20px 0;}
table.g{border-collapse:separate;border-spacing:0;width:100%;font-size:12.5px;white-space:nowrap;}
-table.g thead th{position:sticky;top:0;background:#1b2230;color:var(--mut);text-transform:uppercase;letter-spacing:.3px;font-size:10.5px;padding:8px 10px;border-bottom:1px solid var(--line);cursor:pointer;user-select:none;z-index:2;}
+table.g thead th{position:sticky;top:0;background:var(--headbg,#1b2230);color:var(--mut);text-transform:uppercase;letter-spacing:.3px;font-size:10.5px;padding:8px 10px;border-bottom:1px solid var(--line);cursor:pointer;user-select:none;z-index:2;}
table.g thead th:hover{color:var(--ink);}
table.g thead th.asc::after{content:' ▲';color:var(--gold);} table.g thead th.desc::after{content:' ▼';color:var(--gold);}
table.g thead th.dragcol{cursor:grab;} table.g thead th.dragging{opacity:.45;}
table.g thead th.dropL{box-shadow:inset 3px 0 0 var(--gold);} table.g thead th.dropR{box-shadow:inset -3px 0 0 var(--gold);}
-table.g tbody td{padding:7px 10px;border-bottom:1px solid #20262f;}
+table.g tbody td{padding:7px 10px;border-bottom:1px solid var(--line2,#20262f);}
table.g tbody tr:hover td{background:rgba(200,162,75,.07);}
table.g td.n{text-align:right;font-variant-numeric:tabular-nums;}
table.g a{color:var(--blue);text-decoration:none;} table.g a:hover{text-decoration:underline;}
@@ -52,9 +52,9 @@ table.g a{color:var(--blue);text-decoration:none;} table.g a:hover{text-decorati
.geo{display:inline-block;font-size:10px;font-weight:700;padding:1px 7px;border-radius:8px;}
.geo.ca{background:rgba(127,174,106,.18);color:#8fd06f;border:1px solid rgba(127,174,106,.5);}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--card-min,280px),1fr));gap:18px;padding:16px 20px 0;}
-.gc{background:var(--card);border:2px solid #2a3547;border-radius:11px;padding:16px 18px;cursor:pointer;}
+.gc{background:var(--card);border:2px solid var(--line2,#2a3547);border-radius:11px;padding:16px 18px;cursor:pointer;}
.gc .nm{font-weight:700;margin-bottom:6px;}
-.gc .row{display:flex;justify-content:space-between;gap:8px;font-size:12.5px;padding:2px 0;border-top:1px solid #20262f;}
+.gc .row{display:flex;justify-content:space-between;gap:8px;font-size:12.5px;padding:2px 0;border-top:1px solid var(--line2,#20262f);}
.gc .row .k{color:var(--mut);}
.hide{display:none;}
#ov{display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:60;align-items:flex-start;justify-content:center;padding:40px 14px;overflow-y:auto;}
@@ -63,5 +63,5 @@ table.g a{color:var(--blue);text-decoration:none;} table.g a:hover{text-decorati
#modal h3{margin:0 0 2px;font-size:20px;} #modal .mfirm{color:var(--gold);font-size:13px;}
#modal .x{position:absolute;top:12px;right:14px;background:none;border:0;color:var(--mut);font-size:22px;cursor:pointer;}
#modal .sec{margin-top:14px;} #modal .sec h4{margin:0 0 6px;font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--mut);}
-#modal .litem{display:flex;justify-content:space-between;gap:14px;padding:5px 0;border-bottom:1px solid #20262f;font-size:13px;} #modal .litem .m{color:var(--mut);}
+#modal .litem{display:flex;justify-content:space-between;gap:14px;padding:5px 0;border-bottom:1px solid var(--line2,#20262f);font-size:13px;} #modal .litem .m{color:var(--mut);}
@media(max-width:820px){ .rail{display:none;} .tblwrap,.grid{margin-left:10px;margin-right:10px;} }
← dbe3051 CRCP fleet: add canonical day/night theme (crcp-theme.css/js
·
back to Commercialrealestate
·
CRCP: add WESTMAC broker-direct listings feed + cron (yolofo 8949491 →