<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">

<meta name="robots" content="noindex,nofollow,noarchive,nosnippet">

<title>Chris Master CRM</title>

<style>

  *{box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}

  body{background:#0f172a;color:#f8fafc;margin:0;padding:12px;font-size:13px}

  .top{display:flex;flex-wrap:wrap;gap:8px;justify-content:space-between;align-items:center;background:#1e293b;padding:10px 14px;border-radius:10px;margin-bottom:10px;border:1px solid #334155}

  .badge{background:#065f46;color:#6ee7b7;padding:4px 10px;border-radius:99px;font-weight:700;font-size:12px}

  .tabs{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px}

  .tab{padding:7px 12px;background:#1e293b;color:#cbd5e1;border:1px solid #334155;border-radius:6px;cursor:pointer;font-weight:600;font-size:12px}

  .tab.active{background:#2563eb;color:#fff;border-color:#3b82f6}

  .bar{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px;align-items:center}

  input,select,textarea{background:#0f172a;color:#f8fafc;border:1px solid #334155;border-radius:6px;padding:7px 10px;font-size:12px}

  textarea{width:100%;min-height:54px;resize:vertical;line-height:1.35;font-family:inherit}

  textarea:focus,input:focus,select:focus{outline:none;border-color:#3b82f6}

  .btn{padding:7px 11px;border-radius:6px;border:none;font-weight:700;font-size:12px;cursor:pointer;color:#fff;display:inline-flex;align-items:center;gap:4px;text-decoration:none;white-space:nowrap}

  .b-blue{background:#2563eb}.b-green{background:#059669}.b-purp{background:#7c3aed}.b-gray{background:#334155}

  .studio{background:#1e1b4b;border:1px solid #4c1d95;padding:10px;border-radius:8px;margin-bottom:10px;display:flex;flex-wrap:wrap;gap:10px;align-items:center;justify-content:space-between}

  .tbl-wrap{overflow-x:auto;background:#1e293b;border-radius:10px;border:1px solid #334155}

  table{width:100%;border-collapse:collapse;min-width:880px}

  th,td{padding:8px 10px;border-bottom:1px solid #334155;text-align:left;vertical-align:top}

  th{background:#0f172a;color:#94a3b8;font-size:11px;text-transform:uppercase;cursor:pointer;user-select:none}

  tr:hover{background:#263349}

  .drawer{background:#0f172a;padding:10px;border-radius:6px;margin-top:6px;display:none;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:6px;font-size:11px;border:1px solid #334155}

  .card-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:10px}

  .card{background:#1e293b;border:1px solid #334155;border-radius:10px;padding:12px}

  #pinModal{position:fixed;inset:0;background:rgba(15,23,42,.96);display:none;align-items:center;justify-content:center;z-index:99}

</style>

</head>

<body>


<div id="pinModal">

  <div style="background:#1e293b;padding:24px;border-radius:12px;border:1px solid #334155;width:310px;text-align:center">

    <h3 style="margin:0 0 8px">🔒 Chris Master CRM</h3>

    <p style="color:#94a3b8;font-size:12px;margin:0 0 14px">Enter your private API passcode to unlock.</p>

    <input id="pinIn" type="password" placeholder="Passcode" style="width:100%;margin-bottom:10px;text-align:center;font-size:15px">

    <button class="btn b-blue" style="width:100%;justify-content:center;padding:10px" onclick="savePin()">Unlock CRM</button>

  </div>

</div>


<div class="top">

  <div style="display:flex;align-items:center;gap:10px">

    <b style="font-size:16px">📋 Chris Master CRM</b>

    <span id="countBadge" class="badge">Loading...</span>

  </div>

  <div style="display:flex;gap:6px;align-items:center">

    <button class="btn b-gray" onclick="toggleStudio()">🖼️ MMS Rotator (<span id="imgCnt">0</span>/3)</button>

    <button class="btn b-gray" id="viewBtn" onclick="toggleView()">📱 Card View</button>

    <button class="btn b-blue" onclick="loadData()">🔄 Sync</button>

    <button class="btn b-gray" onclick="lockPin()" title="Lock">🔒</button>

  </div>

</div>


<div id="studioBox" class="studio" style="display:none">

  <div>

    <b>🎨 3-Slot Anti-Spam Graphic Rotator</b>

    <div style="color:#c4b5fd;font-size:11px">Upload 1–3 holiday/promo images. Clicking 🖼️ on any customer row copies the next rotated graphic with a unique pixel signature.</div>

  </div>

  <div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">

    <input type="file" id="imgUp" accept="image/*" multiple onchange="loadFiles(this.files)">

    <div id="thumbs" style="display:flex;gap:6px"></div>

  </div>

</div>


<div class="tabs" id="tabBar"></div>


<div class="bar">

  <input id="qIn" placeholder="🔍 Search name, phone, vehicle, VIN, lender, notes..." style="flex:1;min-width:210px" oninput="page=1;render()">

  <select id="globalTpl" onchange="applyGlobalTpl(this.value)">

    <option value="auto">⚡ Smart Auto-Match (Per Customer)</option>

    <option value="check">👋 6-Month Check-In</option>

    <option value="bday">🎂 Birthday Greeting</option>

    <option value="apr">📉 High-APR Refi / Payment Drop</option>

    <option value="upgrade">🚗 30m+ Equity / Trade Upgrade</option>

    <option value="anniv">🎉 Purchase Anniversary</option>

    <option value="holiday">🦃 Holiday / Promo Greeting</option>

    <option value="ref">🤝 VIP Referral Check-In</option>

  </select>

  <select id="pageSize" onchange="page=1;render()">

    <option value="25">25 / page</option>

    <option value="50" selected>50 / page</option>

    <option value="100">100 / page</option>

    <option value="9999">All</option>

  </select>

</div>


<div id="mainOut"></div>

<div id="pager" style="display:flex;justify-content:center;gap:8px;margin-top:12px"></div>


<script>

const API_URL = 'https://script.google.com/macros/s/AKfycbxXR1Zzt7wZ2AO7DCU8_185mrZ8rsRSu_AGnbuEFHlGtGbWOgKHbC4JEmx3EC-YMZK3kQ/exec';

let HEADERS = [], ROWS = [], tab = 'all', view = window.innerWidth < 768 ? 'card' : 'table', page = 1, sortCol = -1, sortAsc = true;

let imgs = [], rotIdx = 0;


const TABS = [

  {id:'all', lbl:'All Records'},

  {id:'due', lbl:'⏰ Due / Queue'},

  {id:'bday', lbl:'🎂 Birthdays'},

  {id:'apr', lbl:'📉 High APR (≥7%)'},

  {id:'upgrade', lbl:'🚗 Upgrade (30m+)'},

  {id:'anniv', lbl:'🎉 Anniversaries'},

  {id:'sold', lbl:'✅ Sold Only'}

];


function parseMD(s) {

  if (!s) return {m:0, d:0, y:0, ts:0};

  s = String(s).trim();

  let m = 0, d = 0, y = 0;

  if (/^\d{4}-\d{2}-\d{2}/.test(s)) {

    const p = s.split(/[-T ]/); y = +p[0]; m = +p[1]; d = +p[2];

  } else if (/^\d{1,2}[\/\-]\d{1,2}/.test(s)) {

    const p = s.split(/[\/\-]/); m = +p[0]; d = +p[1]; y = p[2] ? (+p[2] < 100 ? 2000 + (+p[2]) : +p[2]) : 0;

  }

  const ts = (y > 1900 && m > 0 && d > 0) ? new Date(y, m - 1, d).getTime() : 0;

  return {m, d, y, ts};

}


function daysUntilMD(m, d) {

  if (!m || !d) return 999;

  const now = new Date(), today = new Date(now.getFullYear(), now.getMonth(), now.getDate());

  let next = new Date(now.getFullYear(), m - 1, d);

  let diff = Math.round((next - today) / 86400000);

  if (diff < -1) { next = new Date(now.getFullYear() + 1, m - 1, d); diff = Math.round((next - today) / 86400000); }

  return diff;

}


function buildMsg(tpl, r) {

  const fn = r.c[1] || 'there', veh = r.c[11] || 'vehicle', rt = parseFloat(String(r.c[26]).replace(/[^\d.]/g,'')) || 0;

  const b = parseMD(r.c[9]), bDiff = daysUntilMD(b.m, b.d);

  if (tpl === 'bday') {

    const when = bDiff === 0 ? 'today' : (bDiff === 1 ? 'for tomorrow' : `coming up on ${b.m}/${b.d}`);

    return `Hi ${fn}! 🎂 This is Chris Buryk at AutoNation—wanted to reach out and wish you a very Happy Birthday ${when}! Hope you have an awesome time celebrating!`;

  }

  if (tpl === 'apr') return `Hi ${fn}, it's Chris Buryk at AutoNation. I was reviewing your ${veh} file${rt ? ' (at '+rt+'% APR)' : ''} and we have strong rate-drop and payment-reduction options right now. Want me to run a quick 2-minute review for you?`;

  if (tpl === 'upgrade') return `Hi ${fn}, Chris Buryk at AutoNation here! Used values on your ${veh} are strong right now. If you're open to upgrading into a new warranty with a clean trade-in, let me know and I'll send over numbers!`;

  if (tpl === 'anniv') return `Hi ${fn}! 🎉 Happy anniversary on getting your ${veh} with me at AutoNation! Hope it's still treating you great—let me know if you ever need anything in service or sales!`;

  if (tpl === 'holiday') return `Hi ${fn}! Wishing you and your family a wonderful holiday season from Chris Buryk at AutoNation! Thank you again for your business—reach out anytime you need anything!`;

  if (tpl === 'ref') return `Hi ${fn}, Chris Buryk at AutoNation checking in! Hope your ${veh} is running great. Remember I always pay out referral perks if any friends or family are looking for a vehicle!`;

  return `Hi ${fn}, this is Chris Buryk at AutoNation. Just checking in to see how your ${veh} is treating you—let me know if you need anything at all!`;

}


function pickSmartTpl(r) {

  const now = new Date(), curM = now.getMonth() + 1;

  const b = parseMD(r.c[9]), s = parseMD(r.c[19]);

  const bDiff = daysUntilMD(b.m, b.d);

  const apr = parseFloat(String(r.c[26]).replace(/[^\d.]/g,'')) || 0;

  const mOwn = s.ts > 0 ? Math.floor((now.getTime() - s.ts) / 2629800000) : 0;

  if (b.m === curM || (bDiff >= -1 && bDiff <= 7)) return 'bday';

  if (apr >= 7) return 'apr';

  if (s.m === curM && mOwn >= 11) return 'anniv';

  if (mOwn >= 30) return 'upgrade';

  return 'check';

}


async function loadData() {

  const key = localStorage.getItem('crm_pin') || '';

  if (!key) { document.getElementById('pinModal').style.display = 'flex'; return; }

  document.getElementById('countBadge').innerText = 'Syncing...';

  try {

    const res = await fetch(`${API_URL}?key=${encodeURIComponent(key)}`);

    const j = await res.json();

    if (j.status === 'unauthorized') { localStorage.removeItem('crm_pin'); document.getElementById('pinModal').style.display = 'flex'; return; }

    HEADERS = j.headers || [];

    ROWS = (j.rows || []).reverse().map(r => {

      const smart = pickSmartTpl(r);

      return { ...r, tpl: smart, msg: buildMsg(smart, r) };

    });

    renderTabs(); render();

  } catch (e) {

    document.getElementById('countBadge').innerText = 'Sync Error';

  }

}


function savePin() {

  const v = document.getElementById('pinIn').value.trim();

  if (!v) return;

  localStorage.setItem('crm_pin', v);

  document.getElementById('pinModal').style.display = 'none';

  loadData();

}

function lockPin() { localStorage.removeItem('crm_pin'); location.reload(); }

function toggleStudio() { const el = document.getElementById('studioBox'); el.style.display = el.style.display === 'none' ? 'flex' : 'none'; }

function toggleView() { view = view === 'table' ? 'card' : 'table'; document.getElementById('viewBtn').innerText = view === 'table' ? '📱 Card View' : '💻 Table View'; render(); }


function renderTabs() {

  document.getElementById('tabBar').innerHTML = TABS.map(t => `<button class="tab ${tab===t.id?'active':''}" onclick="setTab('${t.id}')">${t.lbl}</button>`).join('');

}

function setTab(t) { tab = t; page = 1; renderTabs(); render(); }


function applyGlobalTpl(val) {

  ROWS.forEach(r => {

    r.tpl = val === 'auto' ? pickSmartTpl(r) : val;

    r.msg = buildMsg(r.tpl, r);

  });

  render();

}


function updateRowTpl(rowIdx, tpl) {

  const r = ROWS.find(x => x.rowIdx === rowIdx);

  if (!r) return;

  r.tpl = tpl; r.msg = buildMsg(tpl, r);

  const box = document.getElementById(`msg_${rowIdx}`);

  if (box) box.value = r.msg;

}


function updateRowMsg(rowIdx, val) {

  const r = ROWS.find(x => x.rowIdx === rowIdx);

  if (r) r.msg = val;

}


function filterRows() {

  const q = document.getElementById('qIn').value.toLowerCase().trim();

  const now = new Date(), curM = now.getMonth() + 1, todayStr = now.toISOString().slice(0,10);

  let list = ROWS.filter(r => {

    if (q && !r.c.join(' ').toLowerCase().includes(q)) return false;

    const b = parseMD(r.c[9]), s = parseMD(r.c[19]);

    const bDiff = daysUntilMD(b.m, b.d);

    const apr = parseFloat(String(r.c[26]).replace(/[^\d.]/g,'')) || 0;

    const mOwn = s.ts > 0 ? Math.floor((now.getTime() - s.ts) / 2629800000) : 0;

    const due = r.c[32] || '';

    if (tab === 'bday') return b.m === curM || (bDiff >= -1 && bDiff <= 14);

    if (tab === 'apr') return apr >= 7;

    if (tab === 'upgrade') return mOwn >= 30;

    if (tab === 'anniv') return s.m === curM && mOwn >= 11;

    if (tab === 'sold') return /sold/i.test(r.c[18]) || Boolean(r.c[19]);

    if (tab === 'due') return (due && due <= todayStr) || (bDiff >= 0 && bDiff <= 3);

    return true;

  });

  if (sortCol >= 0) {

    list.sort((a,b) => {

      const va = String(a.c[sortCol]||'').toLowerCase(), vb = String(b.c[sortCol]||'').toLowerCase();

      return sortAsc ? va.localeCompare(vb, undefined, {numeric:true}) : vb.localeCompare(va, undefined, {numeric:true});

    });

  }

  return list;

}


function sortBy(c) { if (sortCol === c) sortAsc = !sortAsc; else { sortCol = c; sortAsc = true; } render(); }


function render() {

  const filtered = filterRows(), sz = +document.getElementById('pageSize').value;

  const totalPages = Math.max(1, Math.ceil(filtered.length / sz));

  if (page > totalPages) page = totalPages;

  const slice = filtered.slice((page - 1) * sz, page * sz);

  document.getElementById('countBadge').innerText = `Showing ${slice.length} of ${filtered.length} (Total: ${ROWS.length})`;


  const tplOpts = (cur) => [

    ['check','👋 Check-In'],['bday','🎂 Birthday'],['apr','📉 High-APR'],['upgrade','🚗 Upgrade'],['anniv','🎉 Anniv'],['holiday','🦃 Holiday'],['ref','🤝 Referral']

  ].map(([k,l]) => `<option value="${k}" ${cur===k?'selected':''}>${l}</option>`).join('');


  if (view === 'table') {

    let h = `<div class="tbl-wrap"><table><thead><tr>

      <th onclick="sortBy(1)">Customer ↕</th>

      <th onclick="sortBy(11)">Vehicle & Sold ↕</th>

      <th onclick="sortBy(26)">Deal / APR ↕</th>

      <th onclick="sortBy(9)">Event / Bday ↕</th>

      <th style="min-width:310px">Editable Message (Click to Edit)</th>

      <th>Actions</th>

    </tr></thead><tbody>`;

    slice.forEach(r => {

      const ph = String(r.c[3]||'').replace(/\D/g,'').slice(-10);

      const det = HEADERS.map((hd, idx) => r.c[idx] ? `<div><span style="color:#94a3b8">${hd}:</span> <b>${r.c[idx]}</b></div>` : '').join('');

      const b = parseMD(r.c[9]), bDiff = daysUntilMD(b.m, b.d);

      const bTag = b.m ? `<span style="color:${bDiff>=0&&bDiff<=7?'#fbbf24':'#cbd5e1'}">🎂 ${b.m}/${b.d}${bDiff===0?' (TODAY!)':bDiff===1?' (TMRW!)':''}</span>` : '—';

      h += `<tr>

        <td>

          <b style="font-size:14px;color:#fff;cursor:pointer" onclick="togD(${r.rowIdx})">${r.c[1]} ${r.c[2]} ▾</b>

          <div style="color:#94a3b8;font-size:11px">${r.c[3]||'No phone'} • ${r.c[18]||'Lead'}</div>

        </td>

        <td>

          <b>${r.c[11]||'—'}</b> ${r.c[20]?`<span style="color:#38bdf8">(${r.c[20]})</span>`:''}

          <div style="color:#94a3b8;font-size:11px">Sold: ${r.c[19]||'—'}</div>

        </td>

        <td>

          <div style="color:#34d399;font-weight:600">${r.c[25]?r.c[25]+'/mo':'—'} ${r.c[26]?'@ '+r.c[26]+'%':''}</div>

          <div style="color:#94a3b8;font-size:11px">${r.c[28]||''} ${r.c[23]?'• '+r.c[23]:''}</div>

        </td>

        <td>${bTag}<div style="color:#94a3b8;font-size:11px">Last: ${r.c[31]||'—'}</div></td>

        <td>

          <select style="margin-bottom:4px;width:100%" onchange="updateRowTpl(${r.rowIdx},this.value)">${tplOpts(r.tpl)}</select>

          <textarea id="msg_${r.rowIdx}" oninput="updateRowMsg(${r.rowIdx},this.value)">${r.msg}</textarea>

        </td>

        <td>

          <div style="display:flex;flex-direction:column;gap:5px">

            <div style="display:flex;gap:4px">

              <button class="btn b-blue" onclick="sendGV(${r.rowIdx},'${ph}')">📱 GVoice</button>

              <button class="btn b-purp" onclick="copyRotImg(${r.rowIdx},this)" title="Copy Rotated Graphic">🖼️</button>

            </div>

            <div style="display:flex;gap:4px">

              <a class="btn b-gray" href="tel:${ph}">📞</a>

              <button class="btn b-green" onclick="logContact(${r.rowIdx},this)">✅ Log 6m</button>

            </div>

          </div>

        </td>

      </tr>

      <tr id="dr_${r.rowIdx}" style="display:none"><td colspan="6"><div class="drawer" style="display:grid">${det}</div></td></tr>`;

    });

    h += `</tbody></table></div>`;

    document.getElementById('mainOut').innerHTML = h;

  } else {

    let h = `<div class="card-grid">`;

    slice.forEach(r => {

      const ph = String(r.c[3]||'').replace(/\D/g,'').slice(-10);

      const det = HEADERS.map((hd, idx) => r.c[idx] ? `<div><span style="color:#94a3b8">${hd}:</span> <b>${r.c[idx]}</b></div>` : '').join('');

      h += `<div class="card">

        <div style="display:flex;justify-content:space-between;cursor:pointer" onclick="togD(${r.rowIdx})">

          <b style="font-size:15px">${r.c[1]} ${r.c[2]}</b>

          <span style="color:#60a5fa;font-size:11px">▼ Details</span>

        </div>

        <div style="color:#cbd5e1;margin:4px 0">${r.c[11]||'No vehicle'} • Sold: ${r.c[19]||'—'}</div>

        <div style="color:#34d399;font-size:12px;margin-bottom:6px">🎂 Bday: ${r.c[9]||'—'} • ${r.c[25]||''} ${r.c[26]?'@ '+r.c[26]+'%':''}</div>

        <div id="dr_${r.rowIdx}" class="drawer">${det}</div>

        <select style="margin:6px 0 4px;width:100%" onchange="updateRowTpl(${r.rowIdx},this.value)">${tplOpts(r.tpl)}</select>

        <textarea id="msg_${r.rowIdx}" oninput="updateRowMsg(${r.rowIdx},this.value)">${r.msg}</textarea>

        <div style="display:flex;gap:6px;margin-top:8px">

          <a class="btn b-gray" href="tel:${ph}">📞</a>

          <button class="btn b-blue" style="flex:1;justify-content:center" onclick="sendGV(${r.rowIdx},'${ph}')">📱 GVoice</button>

          <button class="btn b-purp" onclick="copyRotImg(${r.rowIdx},this)">🖼️</button>

          <button class="btn b-green" onclick="logContact(${r.rowIdx},this)">✅ 6m</button>

        </div>

      </div>`;

    });

    h += `</div>`;

    document.getElementById('mainOut').innerHTML = h;

  }


  let pg = '';

  if (totalPages > 1) {

    for (let p = 1; p <= totalPages; p++) pg += `<button class="tab ${p===page?'active':''}" onclick="page=${p};render()">${p}</button>`;

  }

  document.getElementById('pager').innerHTML = pg;

}


function togD(id) {

  const el = document.getElementById(`dr_${id}`);

  if (!el) return;

  el.style.display = (el.style.display === 'none' || !el.style.display) ? (view === 'table' ? 'table-row' : 'grid') : 'none';

}


async function sendGV(rowIdx, ph) {

  const box = document.getElementById(`msg_${rowIdx}`);

  const txt = box ? box.value : '';

  try { await navigator.clipboard.writeText(txt); } catch(e){}

  window.open(`https://voice.google.com/u/0/messages?number=${ph}`, '_blank');

}


async function logContact(rowIdx, btn) {

  const key = localStorage.getItem('crm_pin') || '';

  const box = document.getElementById(`msg_${rowIdx}`);

  btn.innerText = '⏳';

  await fetch(API_URL, { method:'POST', mode:'no-cors', headers:{'Content-Type':'text/plain'}, body:JSON.stringify({action:'markContacted', key, rowIdx, days:180, note: box ? box.value.slice(0,80) : ''}) });

  btn.innerText = '✅ Saved'; btn.style.background = '#047857';

}


function loadFiles(files) {

  imgs = []; document.getElementById('thumbs').innerHTML = '';

  Array.from(files).slice(0,3).forEach((f, idx) => {

    const url = URL.createObjectURL(f), im = new Image();

    im.onload = () => {

      imgs.push(im);

      document.getElementById('imgCnt').innerText = imgs.length;

      document.getElementById('thumbs').innerHTML += `<img src="${url}" style="height:36px;border-radius:4px;border:1px solid #a78bfa" title="Slot #${idx+1}">`;

    };

    im.src = url;

  });

}


async function copyRotImg(rowIdx, btn) {

  if (!imgs.length) { toggleStudio(); alert('Upload 1–3 graphics in the MMS Rotator bar first!'); return; }

  const im = imgs[rotIdx % imgs.length], slot = (rotIdx % imgs.length) + 1; rotIdx++;

  const cv = document.createElement('canvas'); cv.width = im.width; cv.height = im.height;

  const ctx = cv.getContext('2d'); ctx.drawImage(im, 0, 0);

  ctx.fillStyle = `rgba(255,255,255,0.015)`; ctx.fillRect(Math.random()*10, Math.random()*10, 2, 2);

  cv.toBlob(async (blob) => {

    try {

      await navigator.clipboard.write([new ClipboardItem({'image/png': blob})]);

      btn.innerText = `🖼️#${slot}✅`;

    } catch(e) { alert('Clipboard image copy requires HTTPS on Chrome.'); }

  }, 'image/png');

}


loadData();

</script>

</body>

</html>