// direction-obsidian.jsx — DIRECTION 01: Obsidian Cinema // Cinematic, video-led, deep black, italic Cormorant serif, restrained gold. // A refined evolution of the existing direction. const obsidianStyles = { bg: '#0A0908', bgSoft: '#141312', cream: '#E8E2D3', gold: '#C9A24C', goldSoft: '#A88B3A', gray: '#6C6760', graySoft: '#3B3833', serif: '"Cormorant Garamond", Georgia, serif', sans: '"Outfit", -apple-system, sans-serif', mono: '"JetBrains Mono", ui-monospace, monospace' }; function ObsidianHero({ onTickets, fullViewport } = {}) { const s = obsidianStyles; const { mobile, tablet } = useMobile(); const px = mobile ? 24 : 56; return (
{/* hero bg */} {/* vignette */}
{/* film grain */}
{/* top nav — only shown when standalone in canvas */} {!fullViewport &&
Elevate Noir Gala
{!mobile &&
The EveningExperienceSponsorsContact
}
} {/* corner marks */} {!mobile && <>
◇ EST 2026 · TORONTO
VOL · I · BLACK DREAM
} {/* prominent date — bottom right, aligned with tagline */} {/* main content */}
Elevate
Noir
Gala.
A Luxury Experience Advancing Black Excellence
{GALA_DATA.date}
{GALA_DATA.time}
{[ ['Date', GALA_DATA.date], ['Venue', GALA_DATA.venue + ' · Toronto'], ['Dress Code', GALA_DATA.dress], ['Theme', 'Black Dream']]. map(([k, v]) =>
{k}
{v}
)}
{/* right edge scroll mark — hide on mobile */} {!mobile &&
SCROLL
}
); } // ----- sponsor flow ----- function ObsidianFlow({ initialTier }) { const s = obsidianStyles; const { mobile } = useMobile(); const isDonationMode = initialTier === 'donation'; const flow = useSponsorFlow(isDonationMode ? 'title' : initialTier); React.useEffect(() => { if (isDonationMode) flow.setIsDonation(true); }, []); // Stripe payment state const [stripeSecret, setStripeSecret] = React.useState(null); const [paymentStatus, setPaymentStatus] = React.useState('idle'); // idle | loading | ready | processing | error | success const [paymentError, setPaymentError] = React.useState(''); const [stripeElements, setStripeElements] = React.useState(null); const [stripeInstance, setStripeInstance] = React.useState(null); const paymentRef = React.useRef(null); const formRef = React.useRef({}); // Collect form data from step 3 inputs const getFormData = () => { const inputs = formRef.current; if (flow.isDonation) { return { name: inputs['Full Name'] || '', email: inputs['Email'] || '', phone: inputs['Phone'] || '' }; } return { name: inputs['Primary Contact'] || '', email: inputs['Email'] || '', company: inputs['Brand · Company'] || '', phone: inputs['Phone'] || '' }; }; // Create PaymentIntent and mount Stripe Elements const initPayment = async () => { setPaymentStatus('loading'); setPaymentError(''); const form = getFormData(); if (!form.name || !form.email) { setPaymentError('Please fill in all required fields.'); setPaymentStatus('idle'); return false; } try { // Send application/inquiry email first (best-effort, don't block on failure) fetch('sponsor-apply.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: form.name, email: form.email, phone: form.phone || '', company: form.company || '', tier: flow.tier.name, amount: flow.total, activations: flow.activations.map(id => ACTIVATIONS.find(a => a.id === id)?.name || id), isDonation: flow.isDonation, }), }).catch(() => {}); const res = await fetch('create-payment-intent.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: flow.total, tier: flow.tier.name, name: form.name, email: form.email, activations: flow.activations.map(id => ACTIVATIONS.find(a => a.id === id)?.name || id), isDonation: flow.isDonation, }), }); const data = await res.json(); if (!res.ok || !data.clientSecret) { setPaymentError(data.error || 'Could not initiate payment.'); setPaymentStatus('error'); return false; } setStripeSecret(data.clientSecret); const stripe = window.Stripe(window.STRIPE_PK); setStripeInstance(stripe); const elements = stripe.elements({ clientSecret: data.clientSecret, appearance: { theme: 'night', variables: { colorPrimary: '#C9A24C', colorBackground: '#141312', colorText: '#E8E2D3', colorDanger: '#c44', fontFamily: 'Outfit, system-ui, sans-serif', borderRadius: '0px', spacingUnit: '4px', }, rules: { '.Input': { border: '1px solid #3B3833', backgroundColor: '#0A0908', color: '#E8E2D3', fontSize: '14px' }, '.Input:focus': { border: '1px solid #C9A24C', boxShadow: '0 0 0 1px #C9A24C33' }, '.Label': { color: '#6C6760', fontSize: '11px', letterSpacing: '0.18em', textTransform: 'uppercase' }, } } }); setStripeElements(elements); setPaymentStatus('ready'); // Mount after render setTimeout(() => { if (paymentRef.current) { const pe = elements.create('payment'); pe.mount(paymentRef.current); } }, 50); return true; } catch (err) { setPaymentError('Network error. Please try again.'); setPaymentStatus('error'); return false; } }; // Confirm payment const confirmPayment = async () => { if (!stripeInstance || !stripeElements) return; setPaymentStatus('processing'); setPaymentError(''); const form = getFormData(); const { error } = await stripeInstance.confirmPayment({ elements: stripeElements, confirmParams: { return_url: window.location.href, payment_method_data: { billing_details: { name: form.name, email: form.email } } }, redirect: 'if_required', }); if (error) { setPaymentError(error.message); setPaymentStatus('ready'); } else { setPaymentStatus('success'); // Send confirmation emails try { await fetch('payment-success.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ paymentIntentId: stripeSecret?.split('_secret_')[0] || '', name: form.name, email: form.email, tier: flow.tier.name, amount: flow.total, activations: flow.activations.map(id => ACTIVATIONS.find(a => a.id === id)?.name || id), isDonation: flow.isDonation, }), }); } catch (e) { /* emails are best-effort */ } flow.setStep(5); } }; const StepDot = ({ n, label }) =>
= n ? s.gold : s.graySoft}`, background: flow.step > n ? s.gold : 'transparent', color: flow.step > n ? s.bg : flow.step === n ? s.gold : s.gray, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: s.mono, fontSize: 10, fontWeight: 500 }}>{flow.step > n ? '✓' : n}
{!mobile && = n ? s.cream : s.gray }}>{label} }
; const Btn = ({ children, primary, onClick, disabled }) => ; return (
{/* faint background ornament */}
{/* header */}
SPONSORSHIP · 2026
Partner with us.
{/* step content */}
{flow.step === 1 &&
{TIERS.map((t) => { const sel = flow.tierId === t.id && !flow.isDonation; return ( ); })}
{/* Donation option for non-sponsors */}
OR
{flow.isDonation && flow.donationAmount && Number(flow.donationAmount) < flow.DONATION_MIN && (
Minimum ${flow.DONATION_MIN}
)} } {flow.step === 2 && !flow.isDonation &&
Add custom brand activations to amplify your visibility throughout the night. Optional — but each one is a moment.
{ACTIVATIONS.map((a) => { const sel = flow.activations.includes(a.id); return ( ); })}
} {flow.step === 3 &&
{(flow.isDonation ? [['Full Name', 'Ama Boateng', true], ['Email', 'ama@example.com', true], ['Phone', '+1 416 555 0188', false]] : [['Brand · Company', 'Acme Holdings Inc.', true], ['Primary Contact', 'Ama Boateng', true], ['Email', 'partnerships@acme.com', true], ['Phone', '+1 416 555 0188', true]] ).map(([label, ph, req], i) =>
{label}{req && *}
{ formRef.current[label] = e.target.value; }} style={{ width: '100%', background: 'transparent', border: 'none', borderBottom: `1px solid ${s.graySoft}`, padding: '8px 0', color: s.cream, fontFamily: s.serif, fontSize: mobile ? 16 : 20, fontWeight: 300, outline: 'none' }} />
)}
{flow.isDonation ? 'YOUR DONATION' : 'YOUR PARTNERSHIP'}
{flow.isDonation ? Community Donation : {flow.tier.name} Sponsor}
{flow.isDonation ? 'Community donation' : `${flow.tier.name} tier${flow.customAmount && Number(flow.customAmount) > flow.tier.price ? ' (custom)' : ''}`} {money(flow.basePrice)}
{!flow.isDonation && flow.activations.map((id) => { const a = ACTIVATIONS.find((x) => x.id === id); return (
{a.name} +{money(a.price)}
); })}
Total {money(flow.total)}
} {flow.step === 4 &&
◇ SECURE PAYMENT
Complete your {flow.isDonation ? 'donation' : 'sponsorship'}.

All payments are processed securely via Stripe. Your card details never touch our servers.

{paymentStatus === 'loading' && (
PREPARING PAYMENT...
)}
{paymentError && (

{paymentError}

)} {(paymentStatus === 'ready' || paymentStatus === 'processing') && ( )}
ORDER SUMMARY
{flow.isDonation ? Community Donation : {flow.tier.name} Sponsor}
{flow.isDonation ? 'Donation' : `${flow.tier.name} tier`} {money(flow.basePrice)}
{!flow.isDonation && flow.activations.map((id) => { const a = ACTIVATIONS.find((x) => x.id === id); return (
{a.name} +{money(a.price)}
); })}
Total {money(flow.total)} CAD
SECURED BY STRIPE
} {flow.step === 5 &&
{flow.isDonation ? 'PAYMENT CONFIRMED · THANK YOU' : 'PAYMENT CONFIRMED · WELCOME TO THE TABLE'}
Thank you,
{flow.isDonation ? 'supporter.' : 'partner.'}
{flow.isDonation ? <>Your {money(flow.total)} CAD donation supports the Elevate Noir movement. A receipt has been sent to your email. : <>We've received your {flow.tier.name.toLowerCase()} commitment of {money(flow.total)} CAD. A partnership lead will reach out within 48 hours with next steps. A receipt has been sent to your email.}
{ flow.reset(); setStripeSecret(null); setPaymentStatus('idle'); setStripeElements(null); setStripeInstance(null); formRef.current = {}; }}>Start again
}
{/* footer */} {flow.step < 4 &&
{flow.isDonation ? 'Donation' : 'Running Total'}
{money(flow.total)}
← Back {flow.step === 3 ? ( { const ok = await initPayment(); if (ok) flow.setStep(4); }} disabled={paymentStatus === 'loading'}> {paymentStatus === 'loading' ? 'Loading...' : 'Proceed to Payment →'} ) : ( Continue → )}
} {flow.step === 4 &&
Total
{money(flow.total)} CAD
{ flow.setStep(3); setPaymentStatus('idle'); setStripeSecret(null); setStripeElements(null); }}>← Back
}
); } Object.assign(window, { ObsidianHero, ObsidianFlow });