// obsidian-sections.jsx — additional sections + ticket flow + modal shell
// for the full Obsidian landing prototype. Reuses obsidianStyles from
// direction-obsidian.jsx.
// ─────────────────────────────────────────────────────────────────────
// MODAL SHELL — common to ticket + sponsor flows on the full prototype
// ─────────────────────────────────────────────────────────────────────
function ObsidianModal({ open, onClose, children }) {
React.useEffect(() => {
if (!open) return;
const onKey = (e) => {if (e.key === 'Escape') onClose();};
document.addEventListener('keydown', onKey);
document.body.style.overflow = 'hidden';
return () => {
document.removeEventListener('keydown', onKey);
document.body.style.overflow = '';
};
}, [open, onClose]);
if (!open) return null;
const s = obsidianStyles;
return (
e.stopPropagation()}
style={{
width: '100%', maxWidth: 1280, height: '88vh', maxHeight: 880,
background: s.bg, border: `1px solid ${s.gold}40`,
position: 'relative', overflow: 'hidden',
boxShadow: '0 40px 120px rgba(0,0,0,0.6), 0 0 0 1px rgba(201,162,76,0.08)',
animation: 'slideUp 0.32s cubic-bezier(0.16,1,0.3,1)'
}}>
{e.currentTarget.style.borderColor = s.gold;e.currentTarget.style.color = s.gold;}}
onMouseLeave={(e) => {e.currentTarget.style.borderColor = s.graySoft;e.currentTarget.style.color = s.cream;}}>
×
{children}
);
}
// ─────────────────────────────────────────────────────────────────────
// OBSIDIAN TICKET FLOW
// ─────────────────────────────────────────────────────────────────────
function ObsidianTicketFlow({ onClose }) {
const s = obsidianStyles;
const f = useTicketFlow();
const StepDot = ({ n, label }) =>
= n ? s.gold : s.graySoft}`,
background: f.step > n ? s.gold : 'transparent',
color: f.step > n ? s.bg : f.step === n ? s.gold : s.gray,
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontFamily: s.mono, fontSize: 10, fontWeight: 500
}}>{f.step > n ? '✓' : n}
= n ? s.cream : s.gray
}}>{label}
;
const Btn = ({ children, primary, onClick, disabled }) =>
{children} ;
return (
{/* header */}
RESERVATIONS · OCTOBER 17 · 2026
Reserve your seat.
{/* steps */}
{f.step === 1 &&
{/* Early bird toggle */}
{f.earlyBird ? '◇ EARLY BIRD ACTIVE · LIMITED TIME' : 'REGULAR PRICING'}
{f.earlyBird ? 'Early bird pricing automatically applied — reserve before doors release.' : 'Early bird window closed.'}
f.setEarlyBird((v) => !v)} style={{
background: 'transparent', color: f.earlyBird ? s.gold : s.gray,
border: `1px solid ${f.earlyBird ? s.gold : s.graySoft}`, padding: '8px 14px',
fontFamily: s.mono, fontSize: 10, letterSpacing: '0.18em', textTransform: 'uppercase',
cursor: 'pointer'
}}>{f.earlyBird ? 'Toggle off' : 'Toggle on'}
{TICKET_TYPES.map((t, i) => {
const sel = f.ticketId === t.id;
const displayPrice = f.earlyBird ? t.earlyPrice : t.price;
return (
f.setTicketId(t.id)} style={{
background: sel ? `linear-gradient(180deg, ${s.gold}18, ${s.gold}04)` : s.bgSoft,
border: `1px solid ${sel ? s.gold : s.graySoft}`,
padding: '24px 24px', textAlign: 'left', cursor: 'pointer',
fontFamily: s.sans, color: s.cream, display: 'flex', flexDirection: 'column',
transition: 'all 0.25s', position: 'relative', overflow: 'hidden'
}}>
{sel && ●
}
TIER {String(i + 1).padStart(2, '0')} · {t.badge.toUpperCase()}
{t.name}
{t.desc}
{/* price block */}
${displayPrice}
{f.earlyBird &&
${t.price}
}
{f.earlyBird ? `◇ EARLY BIRD · SAVE $${t.price - t.earlyPrice}` : 'PER TICKET'}
{t.perks.map((p, j) =>
— {p}
)}
);
})}
}
{f.step === 2 &&
HOW MANY?
How many tickets?
Bringing a group of 4+? Reach out and we'll arrange complimentary side-by-side seating and a welcome touch on arrival.
f.setQty((q) => Math.max(1, q - 1))}
style={{ width: 64, height: 64, background: 'transparent', border: `1px solid ${s.gold}`, color: s.gold, fontSize: 22, cursor: 'pointer', fontFamily: s.serif }}>−
{f.qty}
f.setQty((q) => Math.min(12, q + 1))}
style={{ width: 64, height: 64, background: 'transparent', border: `1px solid ${s.gold}`, color: s.gold, fontSize: 22, cursor: 'pointer', fontFamily: s.serif }}>+
{/* summary card */}
YOUR RESERVATION
{f.ticket.name}
{f.ticket.badge.toUpperCase()}
${f.unitPrice} × {f.effectiveQty} {f.earlyBird ? · early bird : null}
{money(f.subtotal)}
Service fees
{money(f.fees)}
Total
{money(f.total)}
{f.ticket.id === 'gold' ? 'Includes everything · refreshments → after-party.' :
f.ticket.id === 'silver' ? 'Cultural moments only · runway · panel · performances.' :
'After-party access · DJ set · cash bar.'}
}
{f.step === 3 &&
Tell us about you.
{[
['Full name', 'Ama Boateng', true],
['Email', 'ama@example.com', true],
['Phone', '+1 416 555 0188', false],
['Dietary or accessibility needs', 'None — looking forward!', false]].
map(([label, ph, fill], i) =>
)}
✓
Send me the night-of program & after-party details
Payment.
Charge today
{f.ticket.name} × {f.effectiveQty} · fees included
{money(f.total)}
}
{f.step === 4 &&
RESERVATION CONFIRMED · #EN2026-{Math.floor(Math.random() * 9000 + 1000)}
See you on the seventeenth.
Your {f.ticket.name.toLowerCase()} reservation for {f.effectiveQty} {f.effectiveQty === 1 ? 'ticket' : 'tickets'} is locked in. A confirmation with the night-of program is on its way to your inbox.
{/* mini ticket card */}
DATE · DOORS
17 OCT 2026 · 6:30 PM
Add to wallet
}
{/* footer */}
{f.step < 4 &&
← Back
{f.step === 3 ? 'Confirm payment →' : 'Continue →'}
}
);
}
// ─────────────────────────────────────────────────────────────────────
// FULL-PAGE OBSIDIAN LANDING SECTIONS
// ─────────────────────────────────────────────────────────────────────
// Smooth scroll-reveal hook
function useReveal() {
const ref = React.useRef(null);
const [seen, setSeen] = React.useState(false);
React.useEffect(() => {
if (!ref.current) return;
const io = new IntersectionObserver(([e]) => {
if (e.isIntersecting) {setSeen(true);io.disconnect();}
}, { threshold: 0.12 });
io.observe(ref.current);
return () => io.disconnect();
}, []);
return [ref, seen];
}
function Reveal({ children, delay = 0, style = {} }) {
const [ref, seen] = useReveal();
return (
{children}
);
}
// Nav (sticky, scroll-aware)
function ObsidianNav({ onTickets, onSponsor }) {
const s = obsidianStyles;
const [scrolled, setScrolled] = React.useState(false);
React.useEffect(() => {
const on = () => setScrolled(window.scrollY > 32);
window.addEventListener('scroll', on, { passive: true });
on();
return () => window.removeEventListener('scroll', on);
}, []);
return (
Elevate Noir
{e.currentTarget.style.transform = 'translateY(-1px)';e.currentTarget.style.boxShadow = `0 8px 30px ${s.gold}40`;}}
onMouseLeave={(e) => {e.currentTarget.style.transform = 'none';e.currentTarget.style.boxShadow = 'none';}}>
Reserve
);
}
// Tagline + investment statement
function ObsidianTagline() {
const s = obsidianStyles;
return (
◇ THE VISION
Where Culture, Capital
& Community Connect.
The Elevate Noir Gala is more than an event — it is a curated cultural experience that brings together influential professionals, creatives, entrepreneurs, and tastemakers for an unforgettable evening of knowledge, empowerment, connection, and visibility.
This is not a donation — it's a strategic investment in Black excellence.
);
}
// Stats / 250+ + by the numbers
function ObsidianStats({ onTickets }) {
const s = obsidianStyles;
return (
250+
Professionals & Entrepreneurs
A curated, high-intent audience of business owners, creatives, consultants, and career-driven individuals — the kind of room where conversations turn into companies.
{[
['07', 'Distinct experiences'],
['$40K', 'Sponsorship goal'],
['16', 'Partner spots']].
map(([n, l]) =>
)}
◇ DON'T MISS THIS NIGHT
Reserve your seat.
Tickets release in waves. Get the night-of program, the after-party address, and first access to early-bird seats.
Or reserve a seat now →
);
}
// Mission / Party & Bash about
function ObsidianAbout() {
const s = obsidianStyles;
return (
◇ THE MISSION
To create a safe space for Black professionals to learn from experts in their field, experience the talents of creatives within Toronto, and foster connections that develop long-term economic growth within the Black community.
{[
{ h: 'The Gap', b: 'Black-owned businesses receive less funding and visibility. Safe, high-quality networking spaces remain limited.' },
{ h: 'The Solution', b: 'A premium environment where attendees connect and are noticed at a high level. A platform where emerging and established voices are amplified together.' },
{ h: 'The Impact', b: 'Meaningful networking that fosters real relationships and opportunity for long-term economic development within the community.' }].
map((p, i) =>
{String(i + 1).padStart(2, '0')} ━
{p.h}
{p.b}
)}
PRESENTED BY
Party & Bash
A luxury event design company creating immersive, intentional experiences across Toronto — from intimate celebrations to large-scale cultural moments.
As the creator of Elevate Noir, Party & Bash partners with Black-owned businesses, creatives, and entrepreneurs across the city to bring the vision to life — from décor to dining, fashion to media.
Visit the studio →
);
}
// Experience grid — full bleed
function ObsidianExperience() {
const s = obsidianStyles;
return (
◇ THE EVENING IN SEVEN ACTS
The experience.
Every moment intentionally designed for connection, culture, and celebration.
{EXPERIENCES.slice(0, 6).map((e, i) =>
{e.currentTarget.style.borderColor = `${obsidianStyles.gold}55`;e.currentTarget.style.transform = 'translateY(-4px)';e.currentTarget.style.boxShadow = '0 20px 60px rgba(0,0,0,0.4)';}}
onMouseLeave={(e) => {e.currentTarget.style.borderColor = obsidianStyles.graySoft;e.currentTarget.style.transform = 'none';e.currentTarget.style.boxShadow = 'none';}}>
{e.name}
{e.blurb}
)}
{/* Finale — full-width closing act */}
{EXPERIENCES[6] && (() => {
const e = EXPERIENCES[6];
return (
{ev.currentTarget.style.borderColor = `${obsidianStyles.gold}88`;ev.currentTarget.style.boxShadow = '0 30px 80px rgba(0,0,0,0.5)';}}
onMouseLeave={(ev) => {ev.currentTarget.style.borderColor = `${obsidianStyles.gold}33`;ev.currentTarget.style.boxShadow = 'none';}}>
{/* video / atmosphere panel */}
{/* copy panel */}
ACT · CLOSING THE NIGHT
{e.name.split(' ').slice(0, -1).join(' ')} {e.name.split(' ').slice(-1)[0]}.
{e.blurb} A curated soundtrack, a continued conversation, and a room that doesn't want to leave.
11 PM — LATE
RSVP REQUIRED
);
})()}
);
}
// Ticket tiers showcase — Gold / Silver / Bronze with early bird highlight
function ObsidianTicketTiers({ onTickets }) {
const s = obsidianStyles;
const tierColors = {
gold: { ring: s.gold, glow: `${s.gold}33`, label: 'GOLD' },
silver: { ring: '#B8B5AB', glow: '#B8B5AB22', label: 'SILVER' },
bronze: { ring: '#A66B3A', glow: '#A66B3A22', label: 'BRONZE' }
};
return (
◇ TICKETS · OCTOBER 17 · 2026
Choose how you arrive.
Limited release — save up to $55 per ticket.
{TICKET_TYPES.map((t, i) => {
const c = tierColors[t.id];
const isFeatured = t.id === 'gold';
return (
{e.currentTarget.style.borderColor = c.ring;e.currentTarget.style.transform = 'translateY(-4px)';e.currentTarget.style.boxShadow = `0 20px 60px ${c.glow}`;}}
onMouseLeave={(e) => {e.currentTarget.style.borderColor = isFeatured ? `${s.gold}55` : s.graySoft;e.currentTarget.style.transform = 'none';e.currentTarget.style.boxShadow = 'none';}}>
{isFeatured &&
MOST POPULAR
}
TIER {String(i + 1).padStart(2, '0')}
{c.label}
{t.name}
{t.desc}
{/* price */}
Save ${t.price - t.earlyPrice} · regular pricing ${`$${t.price}`} when early bird closes.
{/* perks */}
{t.perks.map((p, j) =>
— {p}
)}
{if (!isFeatured) {e.currentTarget.style.background = s.gold;e.currentTarget.style.color = s.bg;}}}
onMouseLeave={(e) => {if (!isFeatured) {e.currentTarget.style.background = 'transparent';e.currentTarget.style.color = s.gold;}}}>
Reserve this tier →
);
})}
{/* fine print */}
All tickets include arrival reception and program. Groups of 4+ in any tier — reach out for complimentary side-by-side seating.
tickets@elevatenoirgala.ca →
);
}
// Sponsor CTA — tiers preview + CTA to flow
function ObsidianSponsorCTA({ onSponsor }) {
const s = obsidianStyles;
return (
);
}
// Footer
function ObsidianFooter() {
const s = obsidianStyles;
return (
);
}
Object.assign(window, { ObsidianModal, ObsidianTicketFlow, ObsidianNav, ObsidianTagline, ObsidianStats, ObsidianAbout, ObsidianExperience, ObsidianTicketTiers, ObsidianSponsorCTA, ObsidianFooter });