function slug(s){ return s.toLowerCase().replace(/[^a-z0-9]+/g,'-').replace(/(^-|-$)/g,''); } /* 06 — Cases with category tabs. teaser=true → first N cards, no tabs, see-all link. */ function Cases({ t, teaser = false, n = 4, featured = null }) { const c = t.cases; const [tab, setTab] = useState(0); const cat = c.tabs[tab]; const isAll = tab === 0; const all = c.items.filter(it => isAll || it.cats.includes(cat)); const items = teaser ? (featured ? featured.map(s => c.items.find(it => it.slug === s)).filter(Boolean) : c.items.slice(0, n)) : all; return ( {teaser && } {!teaser && ( {c.tabs.map((tb, i) => { const active = i === tab; return ( setTab(i)} style={{ fontFamily:'var(--font-mono)', fontSize:12.5, letterSpacing:'.04em', cursor:'pointer', padding:'9px 16px', borderRadius:99, transition:'all var(--dur)', border:`1px solid ${active ? 'transparent' : 'var(--border-2)'}`, background: active ? 'var(--accent-strong)' : 'transparent', color: active ? '#fff' : 'var(--text-2)', }}>{tb} ); })} )} {items.map((it, i) => )} {teaser && {c.seeAll} } ); } function CaseCard({ it, i, readMore }) { const [h, setH] = useState(false); const href = `case.html?c=${it.slug}`; return ( setH(true)} onMouseLeave={()=>setH(false)} style={{ background: h ? 'var(--card-raised)' : 'var(--card-bg)', border:'1px solid var(--border-1)', borderRadius:'var(--r-card)', overflow:'hidden', transition:'all var(--dur) var(--ease-out)', transform: h ? 'translateY(-4px)' : 'none', boxShadow: h ? 'var(--shadow-md)' : 'none', height:'100%', display:'flex', flexDirection:'column', textDecoration:'none', }}> {it.logo && } {it.metric} {it.sector}{it.meta} {it.title} {it.client} {it.summary} {readMore} ); } Object.assign(window, { Cases });
{it.summary}