← back to Consulting Intake

public/portal.html

81 lines

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>Consulting Intake · Deliverable</title>
<style>
  :root{--ink:#14110e;--paper:#f6f2ec;--gold:#a9884f;--line:#dcd3c5}
  *{box-sizing:border-box}
  body{margin:0;font-family:Georgia,serif;background:var(--paper);color:var(--ink)}
  nav{display:flex;justify-content:space-between;align-items:center;padding:16px 28px;background:#fff;border-bottom:1px solid var(--line);font-family:system-ui,sans-serif}
  nav .brand{letter-spacing:.06em}
  nav a{color:var(--gold);text-decoration:none;font-size:13px;letter-spacing:.1em;text-transform:uppercase;margin-left:18px}
  .hero{padding:56px 28px 34px;text-align:center}
  .hero .eyebrow{letter-spacing:.32em;text-transform:uppercase;font-size:11px;color:var(--gold);font-family:system-ui,sans-serif}
  .hero h1{font-weight:400;font-size:44px;margin:.2em 0}
  .hero p{font-style:italic;color:#6b6357;max-width:640px;margin:0 auto}
  section{max-width:1080px;margin:0 auto;padding:28px}
  h2{font-weight:400;font-size:26px;border-bottom:1px solid var(--line);padding-bottom:8px}
  .cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:18px;margin-top:18px}
  .vcard{background:#fff;border:1px solid var(--line);text-decoration:none;color:inherit;transition:.2s}
  .vcard:hover{box-shadow:0 16px 40px rgba(20,17,14,.1);transform:translateY(-2px)}
  .vcard .swatch{height:120px;background:var(--gold)}
  .vcard .body{padding:14px 16px}
  .vcard b{font-family:system-ui,sans-serif;font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:#9a9082}
  .list{font-family:system-ui,sans-serif;font-size:15px}
  .list li{margin:8px 0}
  .badge{display:inline-block;font-family:system-ui,sans-serif;font-size:11px;background:#faf7f1;border:1px solid var(--gold);color:var(--gold);padding:2px 9px;border-radius:20px;margin-left:8px}
</style>
</head>
<body>
  <nav>
    <div class="brand" id="brand">Consulting Intake</div>
    <div><a href="/portal">Deliverable</a><a href="/admin">Growth &amp; Social</a><a href="/">Sign-in</a></div>
  </nav>

  <div class="hero">
    <div class="eyebrow">Consulting Deliverable</div>
    <h1 id="name">Consulting Intake</h1>
    <p id="tag">Tell us about your business — we'll build your new website and social presence.</p>
  </div>

  <section>
    <h2>Website concept directions <span class="badge" id="vcount">—</span></h2>
    <p class="list" style="color:#6b6357">Several high-end redesign concepts of your new site — pick the direction that feels right. (Generate/refresh with <code>node build.mjs</code>.)</p>
    <div class="cards" id="versions"></div>
  </section>

  <section>
    <h2>Priority growth moves</h2>
    <ul class="list" id="sugs"></ul>
  </section>

  <section>
    <h2>Integrated social snapshot</h2>
    <ul class="list" id="social"></ul>
  </section>

<script>
async function j(u){ const r = await fetch(u); return r.ok ? r.json() : null; }
(async () => {
  const c = await j('/api/client'); if (c && c.business_name){ document.getElementById('name').textContent = c.business_name; document.getElementById('brand').textContent = c.business_name; if(c.tagline) document.getElementById('tag').textContent = c.tagline; }
  // version concepts (generated into /versions by build.mjs)
  const known = ['editorial','modern','bold','warm','classic'];
  const vc = document.getElementById('versions'); let found = 0;
  for (const v of known){ const ok = await fetch('/versions/'+v+'.html',{method:'HEAD'}).then(r=>r.ok).catch(()=>false);
    if(ok){ found++; const a=document.createElement('a'); a.className='vcard'; a.href='/versions/'+v+'.html';
      a.innerHTML='<div class="swatch"></div><div class="body"><b>'+v+'</b></div>'; vc.appendChild(a); } }
  document.getElementById('vcount').textContent = found + ' concepts';
  if(!found) vc.innerHTML = '<p style="font-family:system-ui;color:#9a9082">No concepts generated yet — run <code>node build.mjs</code>.</p>';
  // suggestions
  const s = await j('/api/admin/suggestions')||[]; const su=document.getElementById('sugs');
  su.innerHTML = s.length ? s.map(x=>'<li><b>'+(x.title||'')+'</b> <span class="badge">impact '+(x.impact||'?')+' / effort '+(x.effort||'?')+'</span><br><span style="color:#6b6357">'+(x.rationale||'')+'</span></li>').join('') : '<li style="color:#9a9082">No growth moves seeded yet.</li>';
  // socials
  const so = await j('/api/admin/socials')||{}; const el=document.getElementById('social');
  const rows = Object.entries(so).filter(([k])=>!['connected','notes'].includes(k)).map(([k,v])=>'<li><b>'+k+'</b> — '+(v?('<a href="'+(String(v).startsWith('http')?v:'#')+'">'+v+'</a>'):'<span style="color:#c66">not set up yet</span>')+'</li>');
  el.innerHTML = rows.join('') + (so.notes?'<li style="color:#9a9082;font-size:13px">'+so.notes+'</li>':'');
})();
</script>
</body>
</html>