// HomeV2.jsx — lean homepage sections: one idea per section, one sentence per card.
const HomeHead = ({ eyebrow, title, sub, align = 'center' }) => (
{eyebrow &&
{eyebrow}
}
{title}
{sub &&
{sub}
}
);
const cardBase = { background: '#0f1011', border: '1px solid #23252a', borderRadius: 12, position: 'relative', overflow: 'hidden', display: 'flex', flexDirection: 'column' };
const hoverOn = e => { e.currentTarget.style.borderColor = '#34343a'; e.currentTarget.style.background = '#141516'; };
const hoverOff = e => { e.currentTarget.style.borderColor = '#23252a'; e.currentTarget.style.background = '#0f1011'; };
// ─────────────────────────── Testimonials carousel ───────────────────────────
const HOME_QUOTES = [
{ q: 'We have worked with a few pentest vendors over the years and GreySurface is the first one that stayed involved after the report. Their team sat with our engineers until every critical was closed.', n: 'Daria Lehrmann', r: 'CISO', i: 'DL', c: '#5e6ad2' },
{ q: 'They found issues that two previous assessments had missed entirely, and the report was clear enough that our engineers could reproduce every finding without going back and forth.', n: 'Marcus Vahn', r: 'Head of AppSec', i: 'MV', c: '#27a644' },
{ q: 'The continuous program replaced four separate vendors for us. Having one team that already knows our stack makes every release cycle easier.', n: 'Priya Subramanian', r: 'Head of Security', i: 'PS', c: '#828fff' },
{ q: 'The red team exercise was the most useful thing we did for our SOC last year. Six months later we caught a real intrusion in minutes because we had practiced against them.', n: 'Jonas Reiter', r: 'Director of SecOps', i: 'JR', c: '#7a7fad' },
{ q: 'I have led a lot of security assessments in previous roles. GreySurface is the only vendor I have renewed with without going back out to tender.', n: 'Anita Bose', r: 'CIO', i: 'AB', c: '#5e6ad2' },
{ q: 'Our auditor accepted the report exactly as delivered, which saved us about two weeks of back and forth. They also turned our retest around in days.', n: 'Tomasz Wierzbicki', r: 'Head of Compliance', i: 'TW', c: '#3a44a8' },
{ q: 'They found a cross-tenant issue in the first week that three previous vendors had missed. Very easy to work with, and always available when we had questions.', n: 'Elena Marchetti', r: 'VP Engineering', i: 'EM', c: '#27a644' },
{ q: 'Straightforward from the first call. One point of contact, a fixed price, and a report we could act on. We have re-engaged every year since.', n: 'Samuel Okafor', r: 'Director of Infrastructure', i: 'SO', c: '#828fff' },
];
const TestimonialCarousel = () => {
const ref = React.useRef(null);
const [idx, setIdx] = React.useState(0);
const [perView, setPerView] = React.useState(3);
React.useEffect(() => {
const el = ref.current; if (!el) return;
const calc = () => { const w = el.clientWidth; setPerView(w < 560 ? 1 : w < 900 ? 2 : 3); };
calc();
const ro = new ResizeObserver(calc); ro.observe(el);
return () => ro.disconnect();
}, []);
const pages = Math.ceil(HOME_QUOTES.length / perView);
const go = (p) => {
const el = ref.current; if (!el) return;
const clamped = Math.max(0, Math.min(pages - 1, p));
el.scrollTo({ left: clamped * el.clientWidth, behavior: 'smooth' });
setIdx(clamped);
};
const onScroll = () => { const el = ref.current; if (!el) return; setIdx(Math.round(el.scrollLeft / el.clientWidth)); };
const navBtn = (dir, disabled) => (
);
return (
{HOME_QUOTES.map((t, i) => (
{t.q}
{t.i}
{t.n}
{t.r}
{/* Company names are withheld at the client's request; role only. */}
COMPANY WITHHELD · NDA
))}
{navBtn(-1, idx === 0)}
{Array.from({ length: pages }).map((_, p) => (
{navBtn(1, idx >= pages - 1)}
);
};
// ─────────────────────────── Insights ───────────────────────────
// Only posts with an `h` are published. The others mirror /blog/, which lists them as
// "Coming soon" without a link — so they render here as plain cards, not dead links.
const HOME_POSTS = [
{ tag: 'API', t: 'GraphQL alias batching: one request, a thousand auth checks bypassed', by: 'GreySurface team', date: 'May 18, 2026', h: '/blog/graphql-alias-batching-auth-bypass/' },
{ tag: 'AD', t: 'ADCS ESC1 in the wild: eleven engagements, eight findings', by: 'Identity team', date: 'May 02, 2026' },
{ tag: 'AI', t: 'Indirect prompt injection through a calendar invite', by: 'AI testing team', date: 'Apr 24, 2026' },
];
const Insights = () => (
{HOME_POSTS.map(p => {
const Tag = p.h ? 'a' : 'div';
return (