← 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 & 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>