Service Grid
Overview
The service grid displays the six engagement types as a responsive card grid. Each card has an icon, title, bullet features, and a per-card inquiry CTA.
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐│ ◈ KEYNOTE │ │ ◈ EXECUTIVE │ │ ◈ LAW ENFORCEMENT ││ SPEAKING │ │ WORKSHOPS │ │ TRAINING ││ │ │ │ │ ││ RSA · DEF CON │ │ CISO Academy │ │ FBI · USSS · DHS ││ Black Hat │ │ Board Briefings │ │ Quantico ││ Fortune 500 │ │ Red Team Stories │ │ State Agencies ││ │ │ │ │ ││ [ INQUIRE ] │ │ [ INQUIRE ] │ │ [ INQUIRE ] │└──────────────────┘ └──────────────────┘ └──────────────────────────┘
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐│ ◈ THREAT │ │ ◈ MEDIA & │ │ ◈ ENTERPRISE ││ INTELLIGENCE │ │ DOCUMENTARY │ │ CONSULTING ││ ... │ │ ... │ │ ... │└──────────────────┘ └──────────────────┘ └──────────────────────────┘Implementation
const services = [ { id: 'keynote', icon: '◈', title: 'Keynote Speaking', features: ['RSA · DEF CON · Black Hat', 'Fortune 500', 'Financial Institutions'], cta: 'Inquire', }, // … 5 more];
export function ServicesGrid() { return ( <section className="py-20"> <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8"> {/* Section header */} <div className="mb-12"> <span className="text-xs font-mono uppercase tracking-widest text-brand-red"> Services </span> <h2 className="mt-2 text-3xl font-bold text-white"> Speaking & Enterprise Services </h2> </div>
{/* Grid */} <div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3"> {services.map((service) => ( <ServiceCard key={service.id} {...service} /> ))} </div> </div> </section> );}Service Card
interface ServiceCardProps { icon: string; title: string; features: string[]; cta: string; onInquire?: () => void;}
export function ServiceCard({ icon, title, features, cta, onInquire }: ServiceCardProps) { return ( <div className="flex flex-col rounded-sm border border-brand-gray bg-brand-charcoal p-6 gap-4"> {/* Icon */} <span className="text-2xl text-brand-red font-mono">{icon}</span>
{/* Title */} <h3 className="text-lg font-semibold uppercase tracking-wide text-white"> {title} </h3>
{/* Features list */} <ul className="flex-1 space-y-1"> {features.map((f) => ( <li key={f} className="text-sm text-white/60">{f}</li> ))} </ul>
{/* CTA */} <Button variant="ghost" size="sm" onClick={onInquire}> {cta} </Button> </div> );}Inquire CTA Behavior
Each card’s “Inquire” button scrolls to the contact form and pre-fills the Engagement Type select to match the card:
const handleInquire = (engagementType: string) => { const form = document.getElementById('contact-form'); form?.scrollIntoView({ behavior: 'smooth' }); // Set form field via URL hash or React state};Responsive Behavior
| Viewport | Columns | Gap |
|---|---|---|
Mobile (< md) | 1 | gap-6 (24px) |
Tablet (md) | 2 | gap-6 |
Desktop (lg+) | 3 | gap-6 |
All cards are equal height within each row due to flex flex-col with flex-1 on the features list.