[object Object]

← back to Commercialrealestate

CRCP: fleet-wide day/night toggle + legibility pass across all pages

c99253266b82e83935cb223003b5a8e2920ff1bf · 2026-08-07 15:33:47 -0700 · Steve

Shared theme system (crcp-theme.css tokens + crcp-theme.js auto-injecting toggle),
wired into every page (index, condos, crcp, mls, graphics, fha-loans). Each page's
hardcoded dark colors swapped to themeable vars so the light/Day theme works, muted
text brightened for contrast, harsh white table borders removed, zebra striping +
row hover added. Toggle persists (localStorage crcp-theme) with a no-flash head guard.
Default stays dark; now every page reads cleanly and flips to a real Day mode.

Files touched

Diff

commit c99253266b82e83935cb223003b5a8e2920ff1bf
Author: Steve <steve@designerwallcoverings.com>
Date:   Fri Aug 7 15:33:47 2026 -0700

    CRCP: fleet-wide day/night toggle + legibility pass across all pages
    
    Shared theme system (crcp-theme.css tokens + crcp-theme.js auto-injecting toggle),
    wired into every page (index, condos, crcp, mls, graphics, fha-loans). Each page's
    hardcoded dark colors swapped to themeable vars so the light/Day theme works, muted
    text brightened for contrast, harsh white table borders removed, zebra striping +
    row hover added. Toggle persists (localStorage crcp-theme) with a no-flash head guard.
    Default stays dark; now every page reads cleanly and flips to a real Day mode.
---
 public/crcp-theme.css | 22 +++++++++++++++++++
 public/crcp-theme.js  | 32 ++++++++++++++++++++++++++++
 public/crcp.html      | 19 ++++++++++++-----
 public/fha-loans.html | 11 ++++++----
 public/graphics.html  | 16 ++++++++------
 public/index.html     | 59 +++++++++++++++++++++++++++------------------------
 public/mls.html       | 34 ++++++++++++++++++++---------
 7 files changed, 140 insertions(+), 53 deletions(-)

diff --git a/public/crcp-theme.css b/public/crcp-theme.css
new file mode 100644
index 0000000..6f37bd0
--- /dev/null
+++ b/public/crcp-theme.css
@@ -0,0 +1,22 @@
+/* CRCP shared day/night theme tokens — single source of truth across all pages.
+   Load LAST (after each page's own <style>) so it overrides local :root values.
+   Defines BOTH naming conventions in use (--mut AND --muted) so every page themes. */
+html[data-theme="dark"]{
+  --bg:#0d1117; --bg2:#171d26; --card:#1c232e; --line:#33404f; --line2:#3f4c5c;
+  --ink:#f2f6fb; --text:#f2f6fb; --mut:#b3c0cf; --muted:#b3c0cf; --sub:#b3c0cf;
+  --headbg:rgba(13,17,23,.98); --stripe:rgba(255,255,255,.025); --hover:rgba(121,184,255,.10);
+  --acc:#4bd268; --blue:#79b8ff; --gold:#e3b341; --red:#ff7b72; --purp:#c8a2ff;
+}
+html[data-theme="light"]{
+  --bg:#f4f6f9; --bg2:#ffffff; --card:#ffffff; --line:#d5dbe2; --line2:#c2cad4;
+  --ink:#12171e; --text:#12171e; --mut:#525f6e; --muted:#525f6e; --sub:#525f6e;
+  --headbg:rgba(255,255,255,.98); --stripe:rgba(20,30,45,.028); --hover:rgba(9,105,218,.08);
+  --acc:#1a7f37; --blue:#0969da; --gold:#9a6700; --red:#cf222e; --purp:#8250df;
+}
+/* shared toggle button (auto-injected by crcp-theme.js into the page header) */
+#crcpThemeToggle{background:var(--card);color:var(--ink);border:1px solid var(--line);border-radius:8px;
+  padding:6px 11px;font-size:13px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;font-family:inherit;}
+#crcpThemeToggle:hover{border-color:var(--blue);}
+/* readability lift that helps every list/table page (harmless where selectors don't exist) */
+.listtbl tbody tr:nth-child(even) td,tbody tr.row:nth-child(even),.tbl tbody tr:nth-child(even) td{background:var(--stripe);}
+.listtbl tbody tr:hover td,.tbl tbody tr:hover td{background:var(--hover);}
diff --git a/public/crcp-theme.js b/public/crcp-theme.js
new file mode 100644
index 0000000..bcc771c
--- /dev/null
+++ b/public/crcp-theme.js
@@ -0,0 +1,32 @@
+/* CRCP shared day/night toggle — auto-injects a button into the page header,
+   persists to localStorage (key: crcp-theme), applies before paint via the inline
+   head-guard each page also carries. Zero deps. */
+(function () {
+  var root = document.documentElement;
+  function label(t) {
+    var b = document.getElementById('crcpThemeToggle'); if (!b) return;
+    b.innerHTML = (t === 'light' ? '🌙' : '☀️') + ' <span>' + (t === 'light' ? 'Night' : 'Day') + '</span>';
+  }
+  function apply(t) {
+    root.setAttribute('data-theme', t);
+    try { localStorage.setItem('crcp-theme', t); } catch (e) { }
+    label(t);
+  }
+  function current() { var t; try { t = localStorage.getItem('crcp-theme'); } catch (e) { } return t === 'light' ? 'light' : 'dark'; }
+
+  function mount() {
+    if (document.getElementById('crcpThemeToggle')) { label(current()); return; }
+    var btn = document.createElement('button');
+    btn.id = 'crcpThemeToggle'; btn.type = 'button';
+    btn.title = 'Toggle day / night'; btn.setAttribute('aria-label', 'Toggle day / night theme');
+    btn.addEventListener('click', function () { apply(root.getAttribute('data-theme') === 'light' ? 'dark' : 'light'); });
+    // prefer an existing header nav; else the first <header>; else fixed top-right
+    var host = document.querySelector('header .nav') || document.querySelector('header');
+    if (host) { host.appendChild(btn); }
+    else { btn.style.cssText += ';position:fixed;top:12px;right:14px;z-index:99999'; document.body.appendChild(btn); }
+    label(current());
+  }
+  // ensure a theme is set even if a page lacks the inline head-guard
+  if (!root.getAttribute('data-theme')) root.setAttribute('data-theme', current());
+  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount); else mount();
+})();
diff --git a/public/crcp.html b/public/crcp.html
index e846aa1..ae923b8 100644
--- a/public/crcp.html
+++ b/public/crcp.html
@@ -1,16 +1,18 @@
 <!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>
 <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>CRCP — Commercial Real Estate Control Panel</title>
 <style>
   /* Emulates CNCP (localhost:3333): dark panels, gold accent, status colors. */
-  :root{ --bg:#0c0f15; --panel:#141925; --panel2:#1d2230; --fg:#E6E8EC; --muted:#8A93A2; --gold:#C8A24B;
-         --active:#70AD47; --staged:#E0A33E; --draft:#5B9BD5; --archived:#5A6472; --del:#E74C3C; --line:#232a38; }
+  /* Dark fallbacks (shared crcp-theme.css overrides these per html[data-theme] after load) */
+  :root{ --bg:#0d1117; --panel:#1c232e; --panel2:#171d26; --fg:#f2f6fb; --muted:#8A93A2; --gold:#C8A24B;
+         --active:#70AD47; --staged:#E0A33E; --draft:#5B9BD5; --archived:#5A6472; --del:#E74C3C; --line:#33404f; }
   *{box-sizing:border-box;} body{margin:0;background:var(--bg);color:var(--fg);font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;}
-  header{display:flex;align-items:center;gap:14px;padding:14px 22px;border-bottom:1px solid var(--line);background:linear-gradient(180deg,#10141d,#0c0f15);position:sticky;top:0;z-index:10;}
+  header{display:flex;align-items:center;gap:14px;padding:14px 22px;border-bottom:1px solid var(--line);background:var(--bg);position:sticky;top:0;z-index:10;}
   header h1{margin:0;font-size:18px;letter-spacing:.5px;} header h1 b{color:var(--gold);}
   .live{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--muted);}
   .pulse{width:9px;height:9px;border-radius:50%;background:var(--active);box-shadow:0 0 0 0 rgba(112,173,71,.6);animation:p 1.6s infinite;}
@@ -59,7 +61,7 @@
   .atype.com{background:rgba(200,162,75,.14);color:var(--gold);border:1px solid rgba(200,162,75,.4);}
   .atype.arc{background:rgba(127,174,106,.18);color:#8fd06f;border:1px solid rgba(127,174,106,.55);}
   .has{color:var(--active);} .miss{color:var(--archived);}
-  .bar{height:8px;background:#0a0d13;border-radius:5px;overflow:hidden;margin-top:4px;}
+  .bar{height:8px;background:var(--bg);border-radius:5px;overflow:hidden;margin-top:4px;}
   .bar i{display:block;height:100%;background:linear-gradient(90deg,var(--gold),var(--active));}
   .prog{display:flex;justify-content:space-between;font-size:12px;color:var(--muted);margin-top:10px;}
   .meta{font-size:11px;color:var(--muted);margin-top:6px;}
@@ -123,7 +125,7 @@
   .dscr .rentsum{font-size:12px;color:var(--muted);margin-top:7px;} .dscr .rentsum b{color:var(--active);font-variant-numeric:tabular-nums;}
   .dscr .dtog{display:inline-flex;border:1px solid var(--line);border-radius:9px;overflow:hidden;}
   .dscr .dtog button{background:var(--panel2);border:0;color:var(--muted);padding:6px 12px;font-size:12px;cursor:pointer;} .dscr .dtog button.on{background:rgba(200,162,75,.14);color:var(--gold);}
-  .dscr .dresult{background:#0a0d13;border:1px solid var(--line);border-radius:12px;padding:18px 16px;text-align:center;}
+  .dscr .dresult{background:var(--bg);border:1px solid var(--line);border-radius:12px;padding:18px 16px;text-align:center;}
   .dscr .dresult .ratio{font-size:48px;font-weight:800;font-variant-numeric:tabular-nums;line-height:1;margin-top:4px;}
   .dscr .dbadge{display:inline-block;margin-top:12px;font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;padding:6px 14px;border-radius:20px;}
   .dscr .dbadge.pass{background:rgba(112,173,71,.15);color:var(--active);border:1px solid rgba(112,173,71,.5);}
@@ -135,6 +137,12 @@
   .dscr pre{white-space:pre-wrap;background:var(--panel2);border:1px solid var(--line);border-radius:9px;padding:12px;font:12.5px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--fg);margin:6px 0 0;}
   .dscr .dactions{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;} .dscr .dactions button{background:var(--panel2);border:1px solid var(--line);color:var(--fg);border-radius:8px;padding:7px 12px;font-size:12px;cursor:pointer;} .dscr .dactions .prime{background:var(--gold);color:#1a1206;border-color:var(--gold);font-weight:700;}
 </style>
+<link rel="stylesheet" href="/crcp-theme.css">
+<style>
+  /* Bridge: map page-local aliases to shared tokens so JS inline styles using --fg/--panel still work */
+  html[data-theme="dark"]  { --panel:var(--card); --panel2:var(--bg2); --fg:var(--ink); }
+  html[data-theme="light"] { --panel:var(--card); --panel2:var(--bg2); --fg:var(--ink); }
+</style>
 </head>
 <body>
 <header>
@@ -793,5 +801,6 @@ loadSegments(); setInterval(loadSegments, 20000);
 </script>
   <script src="/col-resize.js" defer></script>
 <script src="/corner-nav.js" defer></script>
+<script src="/crcp-theme.js" defer></script>
 </body>
 </html>
diff --git a/public/fha-loans.html b/public/fha-loans.html
index 52e7bec..3890d15 100644
--- a/public/fha-loans.html
+++ b/public/fha-loans.html
@@ -1,6 +1,7 @@
 <!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>
 <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">
@@ -18,7 +19,7 @@
     --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;}
+  html,body{min-height:100%;background:var(--bg);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%),
@@ -26,7 +27,7 @@
       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);}
+  body::after{content:'';position:fixed;inset:0;z-index:-1;backdrop-filter:blur(70px);background:color-mix(in srgb,var(--bg) 34%,transparent);}
   @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;}
@@ -74,7 +75,7 @@
   /* 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;
+  thead th{position:sticky;top:0;background:var(--headbg);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;}
@@ -125,7 +126,7 @@
   /* expandable-row detail modal */
   #fov{display:none;position:fixed;inset:0;background:rgba(0,0,0,.62);z-index:80;align-items:flex-start;justify-content:center;padding:40px 14px;overflow-y:auto;}
   #fov.on{display:flex;}
-  #fmodal{width:min(640px,96vw);background:rgba(16,20,28,.98);border:1px solid var(--glassb);border-radius:16px;padding:20px 22px;position:relative;backdrop-filter:blur(22px);}
+  #fmodal{width:min(640px,96vw);background:var(--card);border:1px solid var(--line);border-radius:16px;padding:20px 22px;position:relative;backdrop-filter:blur(22px);}
   #fmodal h3{margin:0 0 3px;font-size:19px;color:#fff;} #fmodal .msub{color:var(--gold);font-size:12.5px;margin-bottom:6px;}
   #fmodal .x{position:absolute;top:12px;right:14px;background:none;border:0;color:var(--muted);font-size:22px;cursor:pointer;}
   #fmodal .litem{display:flex;justify-content:space-between;gap:12px;padding:5px 0;border-bottom:1px solid rgba(255,255,255,.06);font-size:13px;}
@@ -135,6 +136,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>
+<link rel="stylesheet" href="/crcp-theme.css">
 </head>
 <body>
 <div class="wrap">
@@ -498,5 +500,6 @@ load();
   <script src="/col-resize.js" defer></script>
   <script src="/global-search.js" defer></script>
 <script src="/corner-nav.js" defer></script>
+<script src="/crcp-theme.js" defer></script>
 </body>
 </html>
diff --git a/public/graphics.html b/public/graphics.html
index 5645eea..2c39a58 100644
--- a/public/graphics.html
+++ b/public/graphics.html
@@ -1,22 +1,22 @@
 <!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>
 <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='%230e1116'/%3E%3Ctext x='8' y='12' font-size='10' text-anchor='middle' fill='%233fb950'%3E%F0%9F%93%8A%3C/text%3E%3C/svg%3E">
 <title>CRE Graphics — Brokers, Firms & Warrantability · LA County</title>
 <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
 <style>
-  :root{ --bg:#0e1116; --card:#161b22; --line:#2a313c; --ink:#e6edf3; --mut:#8b949e; --acc:#3fb950; --blue:#58a6ff; --gold:#d29922; --red:#f85149; }
   *{box-sizing:border-box;} html,body{margin:0;}
   body{background:var(--bg);color:var(--ink);font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;}
-  header{display:flex;align-items:center;gap:16px;padding:14px 22px;border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--bg);z-index:5;}
+  header{display:flex;align-items:center;gap:16px;padding:14px 22px;border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--headbg);backdrop-filter:blur(8px);z-index:5;}
   header h1{font-size:18px;margin:0;} header a{color:var(--blue);text-decoration:none;font-size:13px;}
   header .nav{margin-left:auto;display:flex;gap:18px;}
   .stats{display:flex;gap:18px;font-size:12px;color:var(--mut);padding:10px 22px;flex-wrap:wrap;border-bottom:1px solid var(--line);}
   .stats b{color:var(--ink);font-size:16px;}
   main{padding:32px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:26px;max-width:1400px;margin:0 auto;}
-  .card{background:var(--card);border:2px solid #fff;border-radius:12px;padding:24px;min-height:340px;display:flex;flex-direction:column;}
+  .card{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:24px;min-height:340px;display:flex;flex-direction:column;}
   .card.wide{grid-column:1 / -1;}
   .card h2{font-size:14px;margin:0 0 4px;}
   .card .sub{font-size:12px;color:var(--mut);margin:0 0 14px;}
@@ -39,6 +39,7 @@
   .chartwrap canvas{cursor:default;}
   @media(max-width:820px){ main{grid-template-columns:1fr;} }
 </style>
+<link rel="stylesheet" href="/crcp-theme.css">
 </head>
 <body>
 <header>
@@ -102,6 +103,8 @@
 <script>
 const $=s=>document.querySelector(s);
 const GH={ ink:'#e6edf3', mut:'#8b949e', line:'#2a313c', acc:'#3fb950', blue:'#58a6ff', gold:'#d29922', red:'#f85149' };
+// Read CSS token for doughnut slice-gap — adapts to day/night theme.
+const CARD_BG=getComputedStyle(document.documentElement).getPropertyValue('--card').trim()||'#1c232e';
 Chart.defaults.color=GH.mut; Chart.defaults.borderColor=GH.line; Chart.defaults.font.family='-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif';
 const PALETTE=['#58a6ff','#3fb950','#d29922','#bc8cff','#f85149','#39c5cf','#db61a2','#7ee787','#ffa657','#a5d6ff','#ff7b72','#56d364'];
 
@@ -133,7 +136,7 @@ const HOVER=(evt,els)=>{ const t=evt&&evt.native&&evt.native.target; if(t) t.sty
     : Array.isArray(firmsRaw&&firmsRaw.firms) ? firmsRaw.firms : [];
   new Chart($('#firmChart'),{ type:'doughnut', data:{
     labels: firms.map(f=>f.firm),
-    datasets:[{ data:firms.map(f=>f.listings), backgroundColor:PALETTE, borderColor:'#161b22', borderWidth:2 }] },
+    datasets:[{ data:firms.map(f=>f.listings), backgroundColor:PALETTE, borderColor:CARD_BG, borderWidth:2 }] },
     options:{ responsive:true, maintainAspectRatio:false, cutout:'52%',
       onHover:HOVER, onClick:(e,els)=>{ if(els.length){ const f=firms[els[0].index]; if(f) go('/crcp.html?firm='+enc(f.firm||'')); } },
       plugins:{ legend:{ position:'right', labels:{ boxWidth:10, font:{size:11} } },
@@ -146,7 +149,7 @@ const HOVER=(evt,els)=>{ const t=evt&&evt.native&&evt.native.target; if(t) t.sty
   $('#listingWarrantLabel').textContent = '⚖️ ' + (cs.label||'') + '  ·  ' + (cs.total||0) + ' real listings · ' + (cs.source||'');
   new Chart($('#listingWarrantChart'),{ type:'doughnut', data:{
     labels: lwKeys.map(k=>lwLabels[k]||k),
-    datasets:[{ data:lwKeys.map(k=>cs.byStatus[k]), backgroundColor:lwKeys.map(k=>k==='fha_approved'?GH.acc:k==='fha_expired'?GH.gold:k==='heuristic_flag'?GH.red:GH.mut), borderColor:'#161b22', borderWidth:2 }] },
+    datasets:[{ data:lwKeys.map(k=>cs.byStatus[k]), backgroundColor:lwKeys.map(k=>k==='fha_approved'?GH.acc:k==='fha_expired'?GH.gold:k==='heuristic_flag'?GH.red:GH.mut), borderColor:CARD_BG, borderWidth:2 }] },
     options:{ responsive:true, maintainAspectRatio:false, cutout:'55%',
       onHover:HOVER, onClick:(e,els)=>{ if(els.length){ go('/condos.html?status='+enc(lwKeys[els[0].index])); } },
       plugins:{ legend:{ position:'bottom', labels:{ boxWidth:11, font:{size:11} } } } } });
@@ -170,7 +173,7 @@ const HOVER=(evt,els)=>{ const t=evt&&evt.native&&evt.native.target; if(t) t.sty
   const wkeys=Object.keys(w.byStatus);
   new Chart($('#warrantChart'),{ type:'doughnut', data:{
     labels: wkeys.map(k=>wlabels[k]||k),
-    datasets:[{ data:wkeys.map(k=>w.byStatus[k]), backgroundColor:wkeys.map(k=>k==='fha_approved'?GH.acc:k==='fha_expired'?GH.gold:GH.mut), borderColor:'#161b22', borderWidth:2 }] },
+    datasets:[{ data:wkeys.map(k=>w.byStatus[k]), backgroundColor:wkeys.map(k=>k==='fha_approved'?GH.acc:k==='fha_expired'?GH.gold:GH.mut), borderColor:CARD_BG, borderWidth:2 }] },
     options:{ responsive:true, maintainAspectRatio:false, cutout:'55%',
       onHover:HOVER, onClick:(e,els)=>{ if(els.length){ const k=wkeys[els[0].index]; go('/condos.html?status='+enc(k==='fha_other'?'all':k)); } },
       plugins:{ legend:{ position:'bottom', labels:{ boxWidth:11, font:{size:11} } } } } });
@@ -209,5 +212,6 @@ const HOVER=(evt,els)=>{ const t=evt&&evt.native&&evt.native.target; if(t) t.sty
 </script>
   <script src="/col-resize.js" defer></script>
 <script src="/corner-nav.js" defer></script>
+<script src="/crcp-theme.js" defer></script>
 </body>
 </html>
diff --git a/public/index.html b/public/index.html
index ebe31bc..ea91b62 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,19 +1,20 @@
 <!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>
 <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='%230e1116'/%3E%3Ctext x='8' y='12' font-size='11' text-anchor='middle' fill='%233fb950'%3E%24%3C/text%3E%3C/svg%3E">
 <title>LA County CRE — Investment Explorer</title>
 <style>
-  :root { --cols:3; --bg:#0e1116; --card:#161b22; --line:#2a313c; --ink:#e6edf3; --mut:#8b949e; --acc:#3fb950; --warn:#d29922; --bad:#f85149; --blue:#58a6ff; --drawerW:316px; }
+  :root { --cols:3; --drawerW:316px; }
   * { box-sizing:border-box; }
   :focus-visible { outline:2px solid var(--blue); outline-offset:2px; border-radius:4px; }
   @media (prefers-reduced-motion: reduce){ *,*::before,*::after { animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important; scroll-behavior:auto !important; } }
   body { margin:0; background:var(--bg); color:var(--ink); font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; }
 
   /* ---- top bar ---- */
-  header { display:flex; align-items:center; gap:14px; padding:12px 20px; border-bottom:1px solid var(--line); position:sticky; top:0; z-index:30; background:rgba(14,17,22,.97); backdrop-filter:blur(8px); }
+  header { display:flex; align-items:center; gap:14px; padding:12px 20px; border-bottom:1px solid var(--line); position:sticky; top:0; z-index:30; background:var(--headbg); backdrop-filter:blur(8px); }
   .burger { display:inline-flex; align-items:center; gap:8px; background:var(--card); color:var(--ink); border:1px solid var(--line); border-radius:10px; padding:9px 13px; font-size:15px; cursor:pointer; font-weight:600; }
   .burger:hover { border-color:var(--blue); }
   .fcount { display:none; background:var(--blue); color:#04122b; font-size:11px; font-weight:700; border-radius:20px; padding:1px 7px; }
@@ -31,9 +32,9 @@
   /* ---- left drawer ---- */
   #scrim { position:fixed; inset:0; background:rgba(0,0,0,.5); opacity:0; pointer-events:none; transition:opacity .2s; z-index:38; }
   #scrim.on { opacity:1; pointer-events:auto; }
-  #drawer { position:fixed; top:0; left:0; height:100vh; width:var(--drawerW); background:#0b0e13; border-right:1px solid var(--line); transform:translateX(-100%); transition:transform .22s ease; z-index:40; overflow-y:auto; padding:0 0 40px; }
+  #drawer { position:fixed; top:0; left:0; height:100vh; width:var(--drawerW); background:var(--bg2); border-right:1px solid var(--line); transform:translateX(-100%); transition:transform .22s ease; z-index:40; overflow-y:auto; padding:0 0 40px; }
   #drawer.open { transform:translateX(0); box-shadow:6px 0 30px rgba(0,0,0,.4); }
-  .dhead { display:flex; align-items:center; justify-content:space-between; padding:16px 18px 10px; position:sticky; top:0; background:#0b0e13; border-bottom:1px solid var(--line); z-index:2; }
+  .dhead { display:flex; align-items:center; justify-content:space-between; padding:16px 18px 10px; position:sticky; top:0; background:var(--bg2); border-bottom:1px solid var(--line); z-index:2; }
   .dhead b { font-size:15px; } .dhead .x { background:none; border:0; color:var(--mut); font-size:18px; cursor:pointer; }
   .fsec { padding:14px 18px; border-bottom:1px solid var(--line); }
   .fsec h4 { margin:0 0 9px; font-size:11px; text-transform:uppercase; letter-spacing:.6px; color:var(--mut); }
@@ -53,7 +54,7 @@
   .resetbtn { width:calc(100% - 36px); margin:14px 18px 0; background:transparent; color:var(--bad); border:1px solid #7d2b28; border-radius:9px; padding:9px; font-size:13px; cursor:pointer; }
 
   /* ---- results bar + grid ---- */
-  .bar { display:flex; flex-wrap:wrap; align-items:center; gap:14px; padding:11px 20px; border-bottom:1px solid var(--line); position:sticky; top:57px; background:rgba(14,17,22,.95); backdrop-filter:blur(6px); z-index:20; }
+  .bar { display:flex; flex-wrap:wrap; align-items:center; gap:14px; padding:11px 20px; border-bottom:1px solid var(--line); position:sticky; top:57px; background:var(--headbg); backdrop-filter:blur(6px); z-index:20; }
   .bar .count { font-size:13px; color:var(--mut); } .bar .count b { color:var(--ink); }
   .bar label { font-size:11px; color:var(--mut); text-transform:uppercase; letter-spacing:.5px; }
   .bar .right { margin-left:auto; display:flex; align-items:center; gap:12px; }
@@ -77,7 +78,7 @@
     .bar{ max-width:100%; top:auto; }                   /* sort/density strip: no hairline overflow; un-stick so it can't tuck under the taller (burger+title) iPad header */
   }
   @media (max-width:620px){ .grid{ grid-template-columns:1fr;} }
-  .card { background:var(--card); border:2px solid #fff; border-radius:14px; padding:24px; display:flex; flex-direction:column; gap:10px; position:relative; transition:box-shadow .2s,border-color .2s; }
+  .card { background:var(--card); border:1px solid var(--line); border-radius:14px; padding:24px; display:flex; flex-direction:column; gap:10px; position:relative; transition:box-shadow .2s,border-color .2s; }
   .card.uc { opacity:.62; }
   .card.flash { border-color:var(--blue); box-shadow:0 0 0 3px rgba(88,166,255,.35); }
   .top { display:flex; justify-content:space-between; align-items:flex-start; gap:10px; }
@@ -101,7 +102,7 @@
   .metrics .k { color:var(--mut); }
   .metrics .v { font-variant-numeric:tabular-nums; font-weight:600; }
   .pos { color:var(--acc); } .neg { color:var(--bad); } .na { color:var(--mut); }
-  .thesis { font-size:13px; color:#cdd6e0; }
+  .thesis { font-size:13px; color:var(--ink); }
   .lst { font-size:12px; color:var(--mut); margin:2px 0 0; padding-left:16px; }
   .src { font-size:12px; } .src a { color:var(--blue); text-decoration:none; }
   .lcbtn,.histbtn { background:transparent; color:var(--warn); border:1px dashed #6b5320; border-radius:14px; padding:2px 8px; font-size:11px; cursor:pointer; }
@@ -131,14 +132,14 @@
   .brokerline strong { color:var(--blue); }
 
   /* ---- docked chat ---- */
-  #chatwrap { border-top:1px solid var(--line); background:#0b0e13; padding:16px 20px 40px; }
+  #chatwrap { border-top:1px solid var(--line); background:var(--bg2); padding:16px 20px 40px; }
   #chatwrap h2 { font-size:15px; margin:0 0 2px; }
   #chatwrap .hint { color:var(--mut); font-size:12px; margin-bottom:10px; }
   #log { display:flex; flex-direction:column; gap:10px; max-height:42vh; overflow-y:auto; padding:4px 2px; }
   .msg { max-width:80%; padding:9px 13px; border-radius:12px; font-size:14px; line-height:1.45; white-space:pre-wrap; word-wrap:break-word; }
   .msg.u { align-self:flex-end; background:#1f6feb; color:#fff; border-bottom-right-radius:3px; }
   .msg.a { align-self:flex-start; background:var(--card); border:1px solid var(--line); border-bottom-left-radius:3px; }
-  .msg.a code { background:#0b0e13; padding:1px 5px; border-radius:4px; }
+  .msg.a code { background:var(--bg); padding:1px 5px; border-radius:4px; }
   .msg.sys { align-self:center; color:var(--mut); font-size:12px; background:transparent; }
   .actiontag { display:inline-block; margin-top:6px; font-size:11px; color:var(--acc); border:1px solid #1f6f37; border-radius:6px; padding:2px 7px; }
   #chatform { display:flex; gap:10px; margin-top:12px; }
@@ -167,12 +168,12 @@
   .minibtn:hover { border-color:var(--blue); color:var(--ink); }
   /* ---- list view ---- */
   .listhost { display:block; padding:20px 20px 30px; }
-  .listwrap { overflow-x:auto; border:2px solid #fff; border-radius:12px; }
+  .listwrap { overflow-x:auto; border:1px solid var(--line); border-radius:12px; }
   .listtbl { width:100%; border-collapse:collapse; font-size:12.5px; white-space:nowrap; }
   .listtbl th, .listtbl td { text-align:right; padding:9px 13px; border-top:1px solid var(--line); }
-  .listtbl th { position:sticky; top:0; background:#0b0e13; color:var(--mut); font-size:10px; text-transform:uppercase; letter-spacing:.5px; border-top:0; z-index:1; }
+  .listtbl th { position:sticky; top:0; background:var(--bg2); color:var(--mut); font-size:10px; text-transform:uppercase; letter-spacing:.5px; border-top:0; z-index:1; }
   .listtbl td.stick, .listtbl th.stick { text-align:left; position:sticky; left:0; background:var(--card); }
-  .listtbl th.stick { background:#0b0e13; z-index:2; }
+  .listtbl th.stick { background:var(--bg2); z-index:2; }
   .listtbl th.sortable { cursor:pointer; } .listtbl th.sortable:hover { color:var(--ink); }
   /* sort arrow via CSS ::after (not literal text) so the header TEXT stays stable and col-resize's tableSig-keyed saved widths survive re-render (TK-10089) */
   .listtbl th.asc::after { content:' ▲'; color:var(--gold); } .listtbl th.desc::after { content:' ▼'; color:var(--gold); }
@@ -182,7 +183,7 @@
   .listtbl th.dropL { box-shadow:inset 3px 0 0 var(--blue); }
   .listtbl th.dropR { box-shadow:inset -3px 0 0 var(--blue); }
   .listtbl tr.lrow:hover td { background:rgba(88,166,255,.06); }
-  .listtbl tr.lrow:hover td.stick { background:#1b222c; }
+  .listtbl tr.lrow:hover td.stick { background:var(--card); }
   .listtbl .la { font-weight:600; color:var(--ink); text-decoration:none; }
   .listtbl .la:hover { color:var(--blue); }
   .listtbl .lc { color:var(--mut); font-size:11px; }
@@ -190,14 +191,14 @@
   .listtbl .flink:hover { color:var(--blue); border-bottom-color:var(--blue); }
   .listtbl tr.lrow { cursor:pointer; }
   .listtbl .exptog { display:inline-block; width:11px; color:var(--mut); font-size:10px; transition:transform .15s; }
-  .listtbl tr.lrow.open td.stick { background:#1b222c; }
+  .listtbl tr.lrow.open td.stick { background:var(--card); }
   .listtbl tr.lexp > td { padding:0; border-top:0; }
-  .listtbl tr.lexp .lexpbody { max-height:0; overflow:hidden; transition:max-height .25s ease; background:#0c1017; }
+  .listtbl tr.lexp .lexpbody { max-height:0; overflow:hidden; transition:max-height .25s ease; background:var(--bg); }
   .listtbl tr.lexp.open .lexpbody { max-height:1200px; padding:12px 16px; border-top:1px solid var(--line); }
   .lexpbody .src { text-align:left; white-space:normal; font-size:12px; }
   .lexpbody .deep { text-align:left; white-space:normal; margin-top:8px; display:flex; flex-wrap:wrap; gap:6px; align-items:center; }
   .lexpbody .deeplbl { color:var(--mut); font-size:10px; text-transform:uppercase; letter-spacing:.5px; margin-right:2px; }
-  .lexpbody .deep a, .lexpbody .deep button { font-size:11px; padding:3px 9px; border-radius:14px; border:1px solid #2a3340; background:#141a22; color:var(--ink); text-decoration:none; cursor:pointer; }
+  .lexpbody .deep a, .lexpbody .deep button { font-size:11px; padding:3px 9px; border-radius:14px; border:1px solid var(--line); background:var(--card); color:var(--ink); text-decoration:none; cursor:pointer; }
   .lexpbody .deep a:hover, .lexpbody .deep button:hover { border-color:var(--blue); color:var(--blue); }
   .lexpbody .lcout, .lexpbody .histout { text-align:left; white-space:normal; }
   /* Agent · contact column cell */
@@ -207,21 +208,21 @@
   .agentcell .ain { color:var(--mut); text-decoration:none; font-size:11px; }
   .agentcell .ain:hover { color:var(--blue); }
   .agentcell .chiprow:empty { display:none; }
-  .agentcell .achip { display:inline-block; font-size:10px; color:var(--mut); background:#141a22; border:1px solid #2a3340; border-radius:10px; padding:1px 6px; margin-right:4px; }
+  .agentcell .achip { display:inline-block; font-size:10px; color:var(--mut); background:var(--card); border:1px solid var(--line); border-radius:10px; padding:1px 6px; margin-right:4px; }
   .agentcell .achip.done { color:#3fb950; border-color:#264f2e; }
   .agentcell .acts { display:flex; flex-wrap:wrap; gap:5px; margin-top:2px; }
-  .abtn { font-size:10.5px; padding:2px 8px; border-radius:12px; border:1px solid #2a3340; background:#141a22; color:var(--ink); cursor:pointer; }
+  .abtn { font-size:10.5px; padding:2px 8px; border-radius:12px; border:1px solid var(--line); background:var(--card); color:var(--ink); cursor:pointer; }
   .abtn:hover { border-color:var(--blue); color:var(--blue); }
   .abtn.contactbtn { border-color:#2f5233; color:#8fdfa0; }
   .abtn.markbtn { border-color:#284b7a; color:#8ec0ff; }
   /* CRM block inside the inline panel */
   .lexpbody .crm { margin-top:10px; border-top:1px solid var(--line); padding-top:10px; text-align:left; }
   .crm-info { display:flex; flex-wrap:wrap; gap:6px; align-items:center; }
-  .crm-info .crmf { background:#0b0e13; border:1px solid #2a3340; border-radius:8px; color:var(--ink); font-size:12px; padding:5px 8px; min-width:150px; }
+  .crm-info .crmf { background:var(--bg); border:1px solid var(--line); border-radius:8px; color:var(--ink); font-size:12px; padding:5px 8px; min-width:150px; }
   .crm-info .crmf:focus { outline:none; border-color:var(--blue); }
   .crm-acts { display:flex; flex-wrap:wrap; gap:6px; align-items:center; margin-top:8px; }
   .crm-letters { margin-top:10px; }
-  .crm-letters .lett { border:1px solid #232b36; border-radius:8px; padding:7px 9px; margin-top:6px; background:#0b0e13; }
+  .crm-letters .lett { border:1px solid var(--line); border-radius:8px; padding:7px 9px; margin-top:6px; background:var(--bg); }
   .crm-letters .letth { display:flex; align-items:center; gap:8px; font-size:12px; }
   .crm-letters .letts { color:var(--mut); font-size:10px; }
   .crm-letters .letdel { margin-left:auto; background:transparent; border:0; color:var(--mut); cursor:pointer; font-size:12px; }
@@ -230,14 +231,14 @@
   /* Compose-letter modal */
   .composeM { position:fixed; inset:0; background:rgba(0,0,0,.55); display:none; align-items:center; justify-content:center; z-index:9000; }
   .composeM.on { display:flex; }
-  .composeCard { background:var(--card,#11161d); border:1px solid #2a3340; border-radius:14px; width:min(620px,92vw); max-height:88vh; overflow:auto; padding:16px; box-shadow:0 12px 40px rgba(0,0,0,.5); }
+  .composeCard { background:var(--card); border:1px solid var(--line); border-radius:14px; width:min(620px,92vw); max-height:88vh; overflow:auto; padding:16px; box-shadow:0 12px 40px rgba(0,0,0,.5); }
   .composeH { display:flex; align-items:center; font-size:14px; margin-bottom:8px; }
   .composeH .composeX { margin-left:auto; background:transparent; border:0; color:var(--mut); font-size:16px; cursor:pointer; }
   .composeGate { font-size:11px; color:#e3b341; background:#241d0e; border:1px solid #5a4a1e; border-radius:8px; padding:6px 9px; margin-bottom:10px; }
-  .composeCard input, .composeCard textarea { width:100%; box-sizing:border-box; background:#0b0e13; border:1px solid #2a3340; border-radius:8px; color:var(--ink); font-size:13px; padding:8px 10px; margin-bottom:8px; font-family:inherit; }
+  .composeCard input, .composeCard textarea { width:100%; box-sizing:border-box; background:var(--bg); border:1px solid var(--line); border-radius:8px; color:var(--ink); font-size:13px; padding:8px 10px; margin-bottom:8px; font-family:inherit; }
   .composeCard textarea { resize:vertical; line-height:1.5; }
   .composeActs { display:flex; gap:8px; justify-content:flex-end; }
-  .composeActs button { font-size:12px; padding:6px 14px; border-radius:10px; border:1px solid #2a3340; background:#141a22; color:var(--ink); cursor:pointer; }
+  .composeActs button { font-size:12px; padding:6px 14px; border-radius:10px; border:1px solid var(--line); background:var(--card); color:var(--ink); cursor:pointer; }
   .composeActs button.primary { border-color:#2f5233; color:#8fdfa0; }
   .composeActs button.gated { border-color:#5a4a1e; color:#e3b341; }
   .composeActs button.gated:hover:not([disabled]) { border-color:#e3b341; }
@@ -257,11 +258,11 @@
   .tabpane .ain { color:var(--mut); text-decoration:none; font-size:12px; }
   .tabpane .ain:hover { color:var(--blue); }
   .findgrid { display:flex; flex-direction:column; gap:7px; }
-  .findlink { display:inline-block; background:#141a22; border:1px solid #2a3340; border-radius:8px; color:var(--ink); text-decoration:none; font-size:12.5px; padding:8px 11px; cursor:pointer; text-align:left; }
+  .findlink { display:inline-block; background:var(--card); border:1px solid var(--line); border-radius:8px; color:var(--ink); text-decoration:none; font-size:12.5px; padding:8px 11px; cursor:pointer; text-align:left; }
   .findlink:hover { border-color:var(--blue); color:var(--blue); }
   .findlink.findloop { padding:8px 11px; }
   .findlink.findloop a { color:inherit; text-decoration:none; }
-  .crmToast { position:fixed; bottom:22px; left:50%; transform:translateX(-50%) translateY(12px); background:#11161d; border:1px solid #2a3340; color:var(--ink); font-size:12.5px; padding:9px 16px; border-radius:20px; opacity:0; transition:opacity .2s,transform .2s; z-index:9500; pointer-events:none; }
+  .crmToast { position:fixed; bottom:22px; left:50%; transform:translateX(-50%) translateY(12px); background:var(--bg2); border:1px solid var(--line); color:var(--ink); font-size:12.5px; padding:9px 16px; border-radius:20px; opacity:0; transition:opacity .2s,transform .2s; z-index:9500; pointer-events:none; }
   .crmToast.on { opacity:1; transform:translateX(-50%) translateY(0); }
   /* Card-view agent-contact block (every card, every asset type) */
   .card .cardagent { margin-top:8px; border-top:1px solid var(--line); padding-top:8px; font-size:12px; }
@@ -272,7 +273,7 @@
   .card .cardagent .acts { display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; }
   /* Full contact modal info row */
   .composeCard .cm-info { display:flex; flex-wrap:wrap; gap:6px; align-items:center; margin-bottom:10px; }
-  .composeCard .cm-info .crmf { background:#0b0e13; border:1px solid #2a3340; border-radius:8px; color:var(--ink); font-size:12px; padding:6px 8px; min-width:140px; flex:1 1 140px; margin:0; }
+  .composeCard .cm-info .crmf { background:var(--bg); border:1px solid var(--line); border-radius:8px; color:var(--ink); font-size:12px; padding:6px 8px; min-width:140px; flex:1 1 140px; margin:0; }
   .composeCard .cm-info .crmf:focus { outline:none; border-color:var(--blue); }
   .composeH .flink { font-size:11px; font-weight:400; margin-left:8px; }
   /* Inline (no-outside-link) agent bits */
@@ -288,10 +289,10 @@
   .city .drill:hover { color:var(--blue); border-bottom-color:var(--blue); }
   .copyb { background:transparent; border:0; color:var(--mut); cursor:pointer; font-size:11px; padding:0 3px; border-radius:4px; }
   .copyb:hover { color:var(--blue); }
-  .crm-note, .lexpbody .crm-note { margin-top:6px; font-size:12px; color:var(--mut); white-space:pre-wrap; background:#0c1017; border:1px solid #232b36; border-radius:8px; padding:6px 9px; text-align:left; }
+  .crm-note, .lexpbody .crm-note { margin-top:6px; font-size:12px; color:var(--mut); white-space:pre-wrap; background:var(--bg); border:1px solid var(--line); border-radius:8px; padding:6px 9px; text-align:left; }
   .composeCard .cm-notes { margin-bottom:10px; }
   .composeCard .cm-notes .deeplbl { margin-bottom:4px; }
-  .composeCard .cm-notes textarea { width:100%; box-sizing:border-box; background:#0b0e13; border:1px solid #2a3340; border-radius:8px; color:var(--ink); font-size:12.5px; padding:7px 9px; font-family:inherit; resize:vertical; line-height:1.5; }
+  .composeCard .cm-notes textarea { width:100%; box-sizing:border-box; background:var(--bg); border:1px solid var(--line); border-radius:8px; color:var(--ink); font-size:12.5px; padding:7px 9px; font-family:inherit; resize:vertical; line-height:1.5; }
   .composeCard .cm-notes textarea:focus { outline:none; border-color:var(--blue); }
   /* ---- Amazon-style docked left filter rail (desktop) ---- */
   .shell { display:flex; align-items:flex-start; }
@@ -371,6 +372,7 @@
   }
 </style>
 <script async src="https://www.googletagmanager.com/gtag/js?id=G-7R2X3B2V18"></script><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','G-7R2X3B2V18');</script>
+<link rel="stylesheet" href="/crcp-theme.css">
 </head>
 <body>
 <header>
@@ -2016,5 +2018,6 @@ function loadRanked(_retry){ return fetch('data/ranked.json').then(r=>{ if(!r.ok
   <script src="/col-resize.js" defer></script>
   <script src="/global-search.js" defer></script>
 <script src="/corner-nav.js" defer></script>
+<script src="/crcp-theme.js" defer></script>
 </body>
 </html>
diff --git a/public/mls.html b/public/mls.html
index 10b5562..7135dbc 100644
--- a/public/mls.html
+++ b/public/mls.html
@@ -1,28 +1,40 @@
 <!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>
 <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='%230e1116'/%3E%3Ctext x='8' y='12' font-size='10' text-anchor='middle' fill='%233fb950'%3EMLS%3C/text%3E%3C/svg%3E">
 <title>LA County Listings — Residential + CRE</title>
 <style>
-  :root{ --bg:#0e1116; --card:#161b22; --line:#2a313c; --ink:#e6edf3; --mut:#8b949e; --acc:#3fb950; --warn:#d29922; --bad:#f85149; --blue:#58a6ff; }
+  :root, :root[data-theme="dark"]{
+    --bg:#0d1117; --bg2:#171d26; --card:#1c232e; --line:#33404f; --line2:#3f4c5c;
+    --ink:#f2f6fb; --mut:#b3c0cf; --headbg:rgba(13,17,23,.98); --stripe:rgba(255,255,255,.025);
+    --hover:rgba(88,166,255,.10);
+    --acc:#4bd268; --warn:#d29922; --bad:#f85149; --blue:#58a6ff;
+  }
+  :root[data-theme="light"]{
+    --bg:#f4f6f9; --bg2:#ffffff; --card:#ffffff; --line:#d5dbe2; --line2:#c2cad4;
+    --ink:#12171e; --mut:#525f6e; --headbg:rgba(255,255,255,.98); --stripe:rgba(20,30,45,.028);
+    --hover:rgba(9,105,218,.08);
+    --acc:#1a7f37; --warn:#9a6700; --bad:#cf222e; --blue:#0969da; --muted:#525f6e;
+  }
   *{box-sizing:border-box;} body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;}
-  header{display:flex;align-items:center;gap:12px;padding:11px 18px;border-bottom:1px solid var(--line);position:sticky;top:0;z-index:40;background:rgba(14,17,22,.98);backdrop-filter:blur(8px);flex-wrap:wrap;}
+  header{display:flex;align-items:center;gap:12px;padding:11px 18px;border-bottom:1px solid var(--line);position:sticky;top:0;z-index:40;background:var(--headbg);backdrop-filter:blur(8px);flex-wrap:wrap;}
   header h1{font-size:16px;margin:0;} header h1 b{color:var(--acc);}
   header .nav{display:flex;gap:12px;margin-left:6px;} header .nav a{color:var(--blue);text-decoration:none;font-size:13px;} header .nav a:hover{color:var(--warn);}
   .spacer{flex:1;}
   .search{background:var(--card);border:1px solid var(--line);color:var(--ink);border-radius:9px;padding:8px 12px;font-size:14px;min-width:220px;}
   .toggle{display:flex;border:1px solid var(--line);border-radius:9px;overflow:hidden;}
   .toggle button{background:var(--card);border:0;color:var(--mut);padding:8px 13px;font-size:13px;cursor:pointer;}
-  .toggle button.on{background:var(--blue);color:#0b0e14;font-weight:700;}
+  .toggle button.on{background:var(--blue);color:var(--bg);font-weight:700;}
   .csvbtn{background:var(--card);border:1px solid var(--line);color:var(--acc);border-radius:9px;padding:8px 12px;font-size:13px;cursor:pointer;} .csvbtn:hover{border-color:var(--acc);}
   .count{color:var(--mut);font-size:12px;}
   .wrap{padding:24px 28px 60px;}
   /* TABLE (spreadsheet) */
   .tblwrap{overflow:auto;max-height:calc(100vh - 130px);border:1px solid var(--line);border-radius:10px;}
   table.mls{border-collapse:separate;border-spacing:0;width:100%;font-size:12.5px;white-space:nowrap;}
-  table.mls 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.mls thead th{position:sticky;top:0;background:var(--bg2);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.mls thead th:hover{color:var(--ink);}
   table.mls thead th.asc::after{content:' ▲';color:var(--acc);} table.mls thead th.desc::after{content:' ▼';color:var(--acc);}
   /* draggable column reorder (Steve rule 2026-07-31: move columns around) */
@@ -30,7 +42,7 @@
   table.mls thead th.dragging{opacity:.45;}
   table.mls thead th.dropL{box-shadow:inset 3px 0 0 var(--acc);}
   table.mls thead th.dropR{box-shadow:inset -3px 0 0 var(--acc);}
-  table.mls tbody td{padding:7px 10px;border-bottom:1px solid #20262f;}
+  table.mls tbody td{padding:7px 10px;border-bottom:1px solid var(--line);}
   table.mls tbody tr:hover td{background:rgba(88,166,255,.07);}
   table.mls td.n{text-align:right;font-variant-numeric:tabular-nums;}
   table.mls a{color:var(--blue);text-decoration:none;} table.mls a:hover{text-decoration:underline;}
@@ -42,9 +54,9 @@
   #sortsel{background:var(--card);color:var(--ink);border:1px solid var(--line);border-radius:7px;padding:5px 8px;font-size:12px}
   #denswrap{display:none;align-items:center;gap:6px;font-size:13px;color:var(--mut)}
   #denswrap input[type=range]{width:92px;accent-color:var(--acc)}
-  .gc{background:var(--card);border:2px solid #fff;border-radius:11px;padding:18px 20px;}
+  .gc{background:var(--card);border:1px solid var(--line);border-radius:11px;padding:18px 20px;}
   .gc .addr{font-weight:600;} .gc .sub{color:var(--mut);font-size:12px;margin-bottom:6px;}
-  .gc .row{display:flex;justify-content:space-between;font-size:12.5px;padding:2px 0;border-top:1px solid #20262f;}
+  .gc .row{display:flex;justify-content:space-between;font-size:12.5px;padding:2px 0;border-top:1px solid var(--line);}
   .gc .row .k{color:var(--mut);} .gc .row .v{font-variant-numeric:tabular-nums;}
   .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;}
@@ -54,10 +66,10 @@
   .ph-x{position:absolute;top:12px;right:14px;background:none;border:0;color:var(--mut);font-size:22px;cursor:pointer;}
   .ph-ci{display:flex;gap:14px;flex-wrap:wrap;margin:8px 0;font-size:13.5px;}
   .ph-sec{margin-top:14px;} .ph-sec h4{margin:0 0 6px;font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--mut);}
-  .ph-item{display:flex;justify-content:space-between;gap:10px;padding:4px 0;border-bottom:1px solid #20262f;font-size:13px;} .ph-mut{color:var(--mut);font-size:12.5px;}
+  .ph-item{display:flex;justify-content:space-between;gap:10px;padding:4px 0;border-bottom:1px solid var(--line);font-size:13px;} .ph-mut{color:var(--mut);font-size:12.5px;}
   /* ---- Amazon-style left rail ---- */
   .shell{display:flex;align-items:flex-start;}
-  .rail{flex:0 0 260px;background:#0b0e13;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);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);}
   .chips{display:flex;flex-wrap:wrap;gap:6px;}
@@ -92,10 +104,11 @@
   .heatleg.on { display:inline-flex; }
   .heatleg .hb { width:52px; height:8px; border-radius:4px; background:linear-gradient(90deg,hsl(0,70%,45%),hsl(60,70%,45%),hsl(120,70%,45%)); }
 </style>
+<link rel="stylesheet" href="/crcp-theme.css">
 </head>
 <body>
 <header>
-  <h1><b>LA County Listings</b> · Residential + CRE <span style="font-size:11px;font-weight:400;color:#8b949e">· Redfin-sourced</span></h1>
+  <h1><b>LA County Listings</b> · Residential + CRE <span style="font-size:11px;font-weight:400;color:var(--mut)">· Redfin-sourced</span></h1>
   <div class="nav"><a href="/">← Explorer</a><a href="/deals-flow.html" title="Closed deal flow — public-record sales + FHA + SEC REIT">💰 Deal Flow</a><a href="/map.html">🗺️ Map</a><a href="/licensed-agents.html" title="Real-estate agents &amp; brokers verified against the CA DRE public license roll">🎫 Licensed Agents</a><a href="/crcp.html">🛰️ CRCP</a></div>
   <span class="spacer"></span>
   <input class="search" id="q" type="text" placeholder="search all fields — address, city, firm, type, agent, source, year… (space = AND)">
@@ -615,5 +628,6 @@ document.addEventListener('click', async e=>{
   <script src="/global-search.js" defer></script>
   <script src="/sort-bar.js" defer></script>
 <script src="/corner-nav.js" defer></script>
+<script src="/crcp-theme.js" defer></script>
 </body>
 </html>

← 1cb56be condos: rework colors for legibility + add day/night toggle  ·  back to Commercialrealestate  ·  condos: surface FHA expiration date as a toggleable grid col 4edfac9 →