wilddragon-site/components.jsx
Zac Gaetano 17f9438958 fix(site): impeccable deslop — restore styled sections, drop unverified rating claims
- Restore Projects/Tech/OnSet/ProjectOverlay/Clients/Partners/About from pre-#4;
  #4 rewrote them with ~30 class names that had no CSS (rendered unstyled)
- Fix broken Monumental logo (monumental.png 404 -> monumental.svg)
- Remove '★ 5.0 / Google Verified' badges: no reviews exist yet; unbacked
  rating claims are a trust + Google policy risk. Re-add once GBP has reviews.
- Remove 'Q-SYS Certified' (unverified); drop dead Lightbox/VideoModal + CSS
- Keep real /projects/<slug>/ hrefs with in-page overlay on plain click
2026-10-01 20:41:08 -04:00

1123 lines
54 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* global React */
const { useState, useEffect, useRef, Fragment } = React;
// ─── Icons ───────────────────────────────────────────────────────────────────
const Icon = ({ size = 16, sw = 1.75, className = "", children }) => (
<svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 24 24"
fill="none" stroke="currentColor" strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round" className={className}>
{children}
</svg>
);
const ChevronDown = (p) => <Icon size={16} {...p}><polyline points="6 9 12 15 18 9"/></Icon>;
const Menu = (p) => <Icon size={24} {...p}><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="18" y2="18"/></Icon>;
const X = (p) => <Icon size={24} {...p}><path d="M18 6 6 18"/><path d="m6 6 12 12"/></Icon>;
const ArrowRight = (p) => <Icon size={16} {...p}><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></Icon>;
const ArrowLeft = (p) => <Icon size={16} {...p}><path d="m12 19-7-7 7-7"/><path d="M19 12H5"/></Icon>;
const ArrowUpRight = (p) => <Icon size={14} {...p}><path d="M7 17 17 7"/><path d="M7 7h10v10"/></Icon>;
const Mail = (p) => <Icon size={16} {...p}><rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></Icon>;
const MapPin = (p) => <Icon size={16} {...p}><path d="M20 10c0 7-8 13-8 13s-8-6-8-13a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/></Icon>;
const Linkedin = (p) => <Icon size={16} {...p}><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"/><rect width="4" height="12" x="2" y="9"/><circle cx="4" cy="4" r="2"/></Icon>;
const Play = (p) => <Icon size={16} {...p}><polygon points="6 3 20 12 6 21 6 3"/></Icon>;
const Check = (p) => <Icon size={16} {...p}><polyline points="20 6 9 17 4 12"/></Icon>;
const Server = (p) => <Icon size={16} {...p}><rect width="20" height="8" x="2" y="2" rx="2" ry="2"/><rect width="20" height="8" x="2" y="14" rx="2" ry="2"/><line x1="6" x2="6.01" y1="6" y2="6"/><line x1="6" x2="6.01" y1="18" y2="18"/></Icon>;
const Radio = (p) => <Icon size={16} {...p}><circle cx="12" cy="12" r="2"/><path d="M4.93 19.07a10 10 0 0 1 0-14.14"/><path d="M7.76 16.24a6 6 0 0 1 0-8.48"/><path d="M16.24 7.76a6 6 0 0 1 0 8.48"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/></Icon>;
const Cable = (p) => <Icon size={16} {...p}><path d="M17 21v-2a1 1 0 0 1-1-1v-1a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v1a1 1 0 0 1-1 1v2"/><path d="M19 15V6.5a1 1 0 0 0-7 0v11a1 1 0 0 1-7 0V9"/><path d="M21 21v-2h-4v2"/><path d="M3 5h4V3H3z"/><path d="M7 5v1a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5"/></Icon>;
const Cloud = (p) => <Icon size={16} {...p}><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"/></Icon>;
const Tv = (p) => <Icon size={16} {...p}><rect width="20" height="15" x="2" y="7" rx="2" ry="2"/><polyline points="17 2 12 7 7 2"/></Icon>;
const Cpu = (p) => <Icon size={16} {...p}><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M9 1v3"/><path d="M15 1v3"/><path d="M9 20v3"/><path d="M15 20v3"/><path d="M20 9h3"/><path d="M20 14h3"/><path d="M1 9h3"/><path d="M1 14h3"/></Icon>;
const ExternalLink = (p) => <Icon size={13} {...p}><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></Icon>;
const Camera = (p) => <Icon {...p}><path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/></Icon>;
const Film = (p) => <Icon {...p}><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M7 3v18"/><path d="M3 7.5h4"/><path d="M3 12h18"/><path d="M3 16.5h4"/><path d="M17 3v18"/><path d="M17 7.5h4"/><path d="M17 16.5h4"/></Icon>;
const Package = (p) => <Icon {...p}><path d="m7.5 4.27 9 5.15"/><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></Icon>;
const Monitor = (p) => <Icon {...p}><rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/></Icon>;
const ShieldCheck = (p) => <Icon size={16} {...p}><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="m9 12 2 2 4-4"/></Icon>;
const Ruler = (p) => <Icon size={16} {...p}><path d="M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.4 2.4 0 0 1 0-3.4l2.6-2.6a2.4 2.4 0 0 1 3.4 0Z"/><path d="m14.5 12.5 2-2"/><path d="m11.5 9.5 2-2"/><path d="m8.5 6.5 2-2"/><path d="m17.5 15.5 2-2"/></Icon>;
const Wrench = (p) => <Icon size={16} {...p}><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></Icon>;
const MonitorCheck = (p) => <Icon size={16} {...p}><path d="m9 10 2 2 4-4"/><rect width="20" height="14" x="2" y="3" rx="2"/><path d="M12 17v4"/><path d="M8 21h8"/></Icon>;
const Headset = (p) => <Icon size={16} {...p}><path d="M3 11h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5a9 9 0 0 1 18 0v5a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3"/><path d="M21 16v2a4 4 0 0 1-4 4h-5"/></Icon>;
const Sparkles = (p) => <Icon size={16} {...p}><path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z"/></Icon>;
// ─── Reveal helper ────────────────────────────────────────────────────────────
function Reveal({ children, className = "", delay = 0 }) {
const ref = useRef(null);
const [vis, setVis] = useState(false);
useEffect(() => {
const el = ref.current;
if (!el) return;
const obs = new IntersectionObserver(([e]) => {
if (e.isIntersecting) { setVis(true); obs.unobserve(el); }
}, { threshold: 0.1, rootMargin: "0px 0px -40px 0px" });
obs.observe(el);
return () => obs.disconnect();
}, []);
return (
<div ref={ref} className={`reveal ${vis ? "visible" : ""} ${className}`} style={{ transitionDelay: `${delay}ms` }}>
{children}
</div>
);
}
// ─── Cursor follower ─────────────────────────────────────────────────────────
function CursorDot() {
const ref = useRef(null);
useEffect(() => {
const onMove = (e) => {
if (ref.current) {
ref.current.style.transform = `translate(${e.clientX}px, ${e.clientY}px) translate(-50%, -50%)`;
}
document.body.dataset.cursor = "on";
};
window.addEventListener("mousemove", onMove);
return () => window.removeEventListener("mousemove", onMove);
}, []);
return <div ref={ref} className="cursor-dot"></div>;
}
// ─── Page-load curtain ───────────────────────────────────────────────────────
function Curtain() {
const [gone, setGone] = useState(false);
useEffect(() => { const t = setTimeout(() => setGone(true), 1300); return () => clearTimeout(t); }, []);
if (gone) return null;
return <div className="curtain"></div>;
}
// ─── NAVIGATION ──────────────────────────────────────────────────────────────
function Navigation() {
const [scrolled, setScrolled] = useState(false);
const [open, setOpen] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 50);
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, []);
const links = [
{ href: "#services", label: "Capabilities" },
{ href: "#corridors", label: "Regional" },
{ href: "#projects", label: "Projects" },
{ href: "#about", label: "About" },
{ href: "#contact", label: "Contact" }
];
return (
<nav className={`nav ${scrolled ? "scrolled" : ""}`}>
<div className="nav-inner">
<a href="#" className="nav-logo">
<img src={__R("images/dragon-mark.png")} alt="Wild Dragon" width="32" height="32" />
<span>Wild Dragon</span>
</a>
<div className="nav-links">
{links.map(l => <a key={l.href} href={l.href}>{l.label}</a>)}
<a href="#contact" className="nav-cta-btn">Request Scope</a>
</div>
<button className="nav-toggle" onClick={() => setOpen(!open)} aria-label="Toggle menu">
{open ? <X/> : <Menu/>}
</button>
</div>
<div className={`nav-mobile ${open ? "open" : ""}`}>
{links.map(l => <a key={l.href} href={l.href} onClick={()=>setOpen(false)}>{l.label}</a>)}
<a href="#contact" className="nav-mobile-cta" onClick={()=>setOpen(false)}>Request Scope</a>
</div>
</nav>
);
}
// ─── HERO ────────────────────────────────────────────────────────────────────
const HERO_ROLES = [
"Broadcast Systems Integration",
"Commercial AV Installation",
"SMPTE ST 2110 IP Facilities",
"Production Control Rooms",
"Direct-View LED Video Walls",
"Extended Reality (XR) Stages"
];
function Hero({ ctaLabel }) {
const [loaded, setLoaded] = useState(false);
const [idx, setIdx] = useState(0);
const [text, setText] = useState("");
const [typing, setTyping] = useState(true);
useEffect(() => { const t = setTimeout(() => setLoaded(true), 100); return () => clearTimeout(t); }, []);
useEffect(() => {
const role = HERO_ROLES[idx];
if (typing) {
if (text.length < role.length) {
const t = setTimeout(() => setText(role.slice(0, text.length + 1)), 45);
return () => clearTimeout(t);
} else {
const t = setTimeout(() => setTyping(false), 2400);
return () => clearTimeout(t);
}
} else {
if (text.length > 0) {
const t = setTimeout(() => setText(text.slice(0, -1)), 25);
return () => clearTimeout(t);
} else {
setIdx((i) => (i + 1) % HERO_ROLES.length);
setTyping(true);
}
}
}, [text, typing, idx]);
const aniBase = (d) => ({
transition: `opacity .9s ${d}s, transform .9s ${d}s`,
opacity: loaded ? 1 : 0,
transform: loaded ? "translateY(0)" : "translateY(24px)"
});
return (
<section className="hero grain">
<div className="hero-bg">
<img src={__R("images/photos/production-switcher.jpg")} alt="Broadcast control room switcher console" fetchpriority="high" />
</div>
<div className="hero-grid"></div>
<div className="hero-fade-v"></div>
<div className="hero-fade-h"></div>
<div className="hero-corner tl">// 38.9°N · 77.0°W</div>
<div className="hero-corner tr">EST. 2024 · DC / DMV</div>
<div className="hero-corner bl">SMPTE ST 2110 · NDI 6</div>
<div className="hero-corner br">● SYSTEM ONLINE</div>
<div className="hero-content">
<div className="hero-badges-row" style={aniBase(0)}>
<div className="hero-status-chip"><span className="live-dot"></span><span>Washington, DC · Maryland · Northern Virginia</span></div>
</div>
<div className="hero-tag" style={aniBase(.12)}>
<span className="hero-tag-prefix">//</span> {text}<span className="caret">|</span>
</div>
<h1 style={aniBase(.24)} className="hero-h1">
<span className="hero-h1-brand">Wild Dragon</span>
<span className="hero-h1-sub">Broadcast Systems Integration &amp; Commercial AV</span>
</h1>
<div className="hero-rule" style={{
transition: "opacity 1s .35s, width 1s .35s",
opacity: loaded ? 1 : 0,
width: loaded ? "7rem" : 0
}}></div>
<p className="hero-desc" style={aniBase(.4)}>
Principal Design Engineer <strong>Zachary Gaetano</strong> leads end-to-end broadcast facility design, SMPTE ST 2110 IP video infrastructure, and high-performance commercial AV installations across Washington, DC, Maryland, and Northern Virginia.
</p>
<div className="hero-actions" style={aniBase(.5)}>
<a href="#contact" className="btn btn-primary hero-cta-main">
Request Scope &amp; Bid <ArrowRight size={16}/>
</a>
<a href="#projects" className="btn btn-ghost-dark hero-cta-sec">
{ctaLabel || "Explore Case Studies"}
</a>
</div>
{/* Quick Tech Hardware Ecosystem Pills */}
<div className="hero-tech-pills" style={aniBase(.6)}>
<span>SMPTE ST 2110</span>
<span>Ross Ultrix &amp; Carbonite</span>
<span>Q-SYS</span>
<span>Brompton Tessera SX40</span>
<span>12G-SDI &amp; NDI 6</span>
<span>Dante Audio</span>
</div>
</div>
</section>
);
}
// ─── CLIENTS — marquee or static ─────────────────────────────────────────────
const CLIENTS = [
{ name:"Broadcast Management Group", logo:__R("images/clients/bmg.png") },
{ name:"AVI-SPL", logo:__R("images/clients/avispl.png") },
{ name:"NBC Sports", logo:__R("images/clients/nbc-sports.png") },
{ name:"Washington Commanders", logo:__R("images/clients/commanders.png") },
{ name:"CVS / Aetna", logo:__R("images/clients/cvs.png") },
{ name:"UBS", logo:__R("images/clients/ubs.png") },
{ name:"BetMGM", logo:__R("images/clients/betmgm.svg") },
{ name:"Intuit", logo:__R("images/clients/intuit.png") },
{ name:"Monumental Sports", logo:__R("images/clients/monumental.svg") },
{ name:"COSM", logo:__R("images/clients/cosm.svg") },
{ name:"Red Sands", logo:__R("images/clients/redsands.svg") },
];
function Clients({ marquee }) {
return (
<section id="clients" className="clients" aria-label="Clients">
<div className="container">
<Reveal>
<p className="clients-label">— Trusted by —</p>
</Reveal>
</div>
{marquee ? (
<div className="marquee">
<div className="marquee-track">
{[...CLIENTS, ...CLIENTS].map((c, i) => (
<div className="marquee-item" key={i} title={c.name}>
<img src={c.logo} alt={c.name}/>
</div>
))}
</div>
</div>
) : (
<div className="container">
<Reveal>
<div className="clients-static">
{CLIENTS.map((c) => (
<div className="marquee-item" key={c.name} title={c.name}>
<img src={c.logo} alt={c.name}/>
</div>
))}
</div>
</Reveal>
</div>
)}
</section>
);
}
// ─── PARTNERS ────────────────────────────────────────────────────────────────
const PARTNERS = [
{ name:"THOR Broadcast", logo:__R("images/clients/thor-logo.png") },
{ name:"Ross Video", logo:__R("images/clients/ross-video.png") },
{ name:"Filmtools", logo:__R("images/clients/filmtools.png") },
{ name:"Forecast Consoles", logo:__R("images/clients/forecast.png") },
{ name:"vMix by Studio Coast", logo:__R("images/clients/vmix.png") },
{ name:"RED Digital Cinema", logo:__R("images/partners/red-digital.png") },
];
function Partners() {
return (
<section className="partners">
<div className="container">
<Reveal>
<p>// Technology Partners</p>
<div className="partners-grid">
{PARTNERS.map(p => (
<div className="partner-logo" title={p.name} key={p.name}>
<img src={p.logo} alt={p.name}/>
</div>
))}
</div>
</Reveal>
</div>
</section>
);
}
// ─── ABOUT ───────────────────────────────────────────────────────────────────
const CAPS = [
{ icon: Radio, title:"Systems Design", desc:"End-to-end broadcast facility design including signal flow engineering, equipment specification, and architectural documentation." },
{ icon: Cable, title:"Integration", desc:"Full system integration from rack builds and wiring to commissioning, testing, and operator training." },
{ icon: Cloud, title:"Cloud & IP", desc:"Cloud-native production architectures, SMPTE ST 2110, NDI, SRT, and hybrid on-prem/cloud workflows." },
{ icon: Tv, title:"Broadcast Engineering", desc:"Live production engineering, RF systems, video routing, and real-time broadcast operations." },
];
function About() {
return (
<section id="about" className="about">
<div className="container">
<Reveal>
<div className="about-intro">
<div className="section-counter"><span className="num">01</span><span className="bar"></span><span>About</span></div>
<h2 className="section-title">From live production to<br/>systems architecture.</h2>
<div className="body" style={{marginTop:"2rem"}}>
<p>I&apos;m a broadcast engineer and systems integrator based in the Washington DC area, with a career that spans both sides of the industry — production and infrastructure.</p>
<p>My background in live production as a 1st AC, DIT, Camera Operator, and Trinity Operator gives me an operator&apos;s perspective that most systems designers don&apos;t have. I build facilities that work the way production teams actually need them to — not just the way engineers imagine they will.</p>
<p>Today, my focus is broadcast systems integration. As a principal systems designer with <a className="inline" href="https://broadcastmgmt.com" target="_blank" rel="noopener noreferrer">Broadcast Management Group</a>, I design production facilities for organizations including the <strong>Washington Commanders</strong>, <strong>CVS/Aetna</strong>, <strong>UBS</strong>, <strong>BetMGM</strong>, <strong>Intuit</strong>, and <strong>Monumental Sports</strong> — engineering control rooms, studios, XR stages, and IP-based workflows across sports, corporate, financial services, aerospace, and defense.</p>
</div>
</div>
</Reveal>
<div className="cap-grid">
{CAPS.map((c, i) => (
<Reveal key={c.title} delay={i*100}>
<div className="cap">
<div className="cap-icon"><c.icon size={20} sw={1.5}/></div>
<h3>{c.title}</h3>
<p>{c.desc}</p>
</div>
</Reveal>
))}
</div>
</div>
</section>
);
}
// ─── STATS — dark band ───────────────────────────────────────────────────────
const STATS = [
{ v:10, suf:"+", label:"Years in Broadcast", desc:"Production & engineering" },
{ v:8, suf:"+", label:"Major Facilities", desc:"Designed & integrated" },
{ v:5900, suf:"+", label:"End Users Served", desc:"Global content delivery" },
{ v:5, suf:"", label:"Industry Verticals", desc:"Enterprise, sports, financial, aerospace, defense" },
];
function AnimatedNumber({ value, suffix }) {
const [n, setN] = useState(0);
const ref = useRef(null);
const done = useRef(false);
useEffect(() => {
const obs = new IntersectionObserver(([e]) => {
if (e.isIntersecting && !done.current) {
done.current = true;
const dur = 2000, steps = 60, inc = value/steps;
let cur = 0;
const t = setInterval(() => {
cur += inc;
if (cur >= value) { setN(value); clearInterval(t); }
else setN(Math.floor(cur));
}, dur/steps);
}
}, { threshold: .3 });
if (ref.current) obs.observe(ref.current);
return () => obs.disconnect();
}, [value]);
const display = n >= 1000 && value >= 1000 ? `${(n/1000).toFixed(1).replace(/\.0$/,"")}k` : n;
return <span ref={ref} className="tabular-nums">{display}<span className="suf">{suffix}</span></span>;
}
function Stats() {
return (
<section className="stats grain dark-section">
<div className="container">
<div className="stats-grid">
{STATS.map(s => (
<div key={s.label}>
<div className="stat-value"><AnimatedNumber value={s.v} suffix={s.suf}/></div>
<div className="stat-label">{s.label}</div>
<div className="stat-desc">{s.desc}</div>
</div>
))}
</div>
</div>
</section>
);
}
// ─── SERVICES & CAPABILITIES BENTO (SEO HUB) ──────────────────────────────────
const CORE_SERVICES = [
{
icon: Tv,
slug: "commercial-av-installation-washington-dc",
title: "Commercial AV Installation",
tagline: "Corporate Boardrooms, Town Halls & Briefing Centers",
desc: "Design-led commercial AV installation for organizations across Washington DC, Northern Virginia, and Maryland. Video conferencing, high-resolution display walls, automated room control, and precision audio DSP.",
tags: ["Q-SYS Control", "Shure Microflex", "Crestron", "Teams/Zoom Rooms"],
url: "/services/commercial-av-installation-washington-dc/"
},
{
icon: Radio,
slug: "broadcast-systems-integration",
title: "Broadcast Systems Integration",
tagline: "Live Production Studios & Master Control Rooms",
desc: "Turnkey broadcast facility engineering from signal-flow drafting to final commissioning. Production switchers, routing switchers, multiviewers, replay servers, tally systems, and studio camera chains.",
tags: ["Ross Video", "vMix 4K", "Grass Valley", "Riedel Intercom"],
url: "/services/broadcast-systems-integration/"
},
{
icon: Server,
slug: "smpte-st-2110-infrastructure",
title: "IP Video & SMPTE ST 2110 Infrastructure",
tagline: "PTP Timing, NMOS Routing & Cloud Production",
desc: "Uncompressed IP broadcast infrastructure and cloud-hybrid production. SMPTE ST 2110-20/30/40 standards, PTP IEEE 1588 grandmaster timing, NMOS IS-04/05 discovery/routing, NDI 6, and SRT contribution.",
tags: ["ST 2110", "PTP IEEE 1588", "NMOS Routing", "SRT / NDI 6"],
url: "/services/broadcast-systems-integration/"
},
{
icon: Cpu,
slug: "led-video-wall-installation",
title: "LED Video Walls & XR Stages",
tagline: "Direct-View LED, Tessera SX40 & Virtual Sets",
desc: "Direct-view fine-pitch LED display wall installation, processor engineering, and XR virtual production stages. Brompton Tessera processing, sub-frame latency, camera tracking, and genlock synchronization.",
tags: ["Brompton SX40", "NovaStar", "Megapixel VR", "Unreal Engine XR"],
url: "/services/led-video-wall-installation/"
}
];
function Services() {
return (
<section id="services" className="services">
<div className="container">
<Reveal>
<div className="services-head">
<div className="section-counter"><span className="num">02</span><span className="bar"></span><span>Capabilities</span></div>
<h2 className="section-title">Core solutions &amp; engineering.</h2>
<p className="section-lede">Specialized engineering disciplines designed to eliminate complexity, ensure signal integrity, and deliver broadcast reliability for enterprise, sports, and federal clients.</p>
</div>
</Reveal>
<div className="services-bento-grid">
{CORE_SERVICES.map((s, i) => (
<Reveal key={s.slug} delay={i * 70}>
<div className="svc-bento-card">
<div className="svc-bento-top">
<div className="svc-icon-box"><s.icon size={22} sw={1.5}/></div>
<span className="svc-bento-badge">{`0${i + 1}`}</span>
</div>
<h3 className="svc-bento-title">{s.title}</h3>
<p className="svc-bento-tagline">{s.tagline}</p>
<p className="svc-bento-desc">{s.desc}</p>
<div className="svc-tags">
{s.tags.map(t => <span key={t} className="svc-tag-pill">{t}</span>)}
</div>
<a href={s.url} className="svc-bento-link">
<span>Explore service specification</span>
<ArrowRight size={14}/>
</a>
</div>
</Reveal>
))}
</div>
</div>
</section>
);
}
// ─── REGIONAL CORRIDORS (LOCAL SEO & GBP HUB) ─────────────────────────────────
const CORRIDORS = [
{
title: "Washington, DC",
badge: "District Core",
focus: "Capitol Hill, K Street, Federal Newsrooms & Executive Briefing Centers",
desc: "Rapid on-site integration, secure boardroom AV, live broadcast studios, and press briefing room engineering.",
url: "/washington-dc/"
},
{
title: "Northern Virginia",
badge: "Tech & Defense",
focus: "Tysons, Reston, Herndon, Arlington & Alexandria Enterprise Corridor",
desc: "High-density enterprise commercial AV, defense contractor briefing facilities, and SMPTE ST 2110 studio hubs.",
url: "/northern-virginia/"
},
{
title: "Maryland",
badge: "Biotech & Federal",
focus: "Bethesda, Rockville, Silver Spring & Baltimore Corporate Centers",
desc: "Biotech auditorium AV, executive boardrooms, healthcare streaming suites, and regional broadcast facilities.",
url: "/maryland/"
},
{
title: "Broadcast Integration DMV",
badge: "Regional Systems",
focus: "Regional Multi-Site Facilities, Master Control & Production Trucks",
desc: "End-to-end broadcast facility architecture, routing matrix upgrades, and turn-key control room builds.",
url: "/broadcast-integration-dmv/"
},
{
title: "Commercial AV DMV",
badge: "Enterprise AV",
focus: "Turnkey Corporate AV, All-Hands Spaces & Direct-View LED Walls",
desc: "Single-engineer design, installation, DSP programming, and written acceptance testing for enterprise rooms.",
url: "/av-installation-dmv/"
}
];
function RegionalCorridors() {
return (
<section id="corridors" className="corridors-section">
<div className="container">
<Reveal>
<div className="corridors-head">
<div className="section-counter"><span className="num">03</span><span className="bar"></span><span>Regional Corridors</span></div>
<h2 className="section-title">DMV Service Area &amp; Local Reach.</h2>
<p className="section-lede">Direct engineering presence with immediate on-site response across Washington, DC, Maryland, and Northern Virginia.</p>
</div>
</Reveal>
<div className="corridors-grid">
{CORRIDORS.map((c, i) => (
<Reveal key={c.title} delay={i * 60}>
<a href={c.url} className="corridor-card">
<div className="corridor-top">
<div className="corridor-pin"><MapPin size={16} sw={1.75}/></div>
<span className="corridor-badge">{c.badge}</span>
</div>
<h3 className="corridor-title">{c.title}</h3>
<p className="corridor-focus">{c.focus}</p>
<p className="corridor-desc">{c.desc}</p>
<div className="corridor-action">
<span>View regional coverage</span>
<ArrowUpRight size={14}/>
</div>
</a>
</Reveal>
))}
</div>
<Reveal delay={200}>
<div className="corridor-sublinks">
<span className="sublinks-label">Local Metro Coverage:</span>
<div className="sublinks-pills">
<a href="/washington-dc/">Downtown DC</a>
<a href="/northern-virginia/">Tysons &amp; Reston</a>
<a href="/bethesda-rockville-av/">Bethesda &amp; Rockville</a>
<a href="/maryland/">Silver Spring</a>
<a href="/northern-virginia/">Arlington &amp; Alexandria</a>
<a href="/broadcast-integration-dmv/">Baltimore Metro</a>
</div>
</div>
</Reveal>
</div>
</section>
);
}
// ─── PROJECTS — featured + grid ──────────────────────────────────────────────
function pickScopeChips(scopes) {
return (scopes || []).slice(0, 3);
}
function Projects({ onOpen }) {
const list = window.PROJECTS || [];
const [featured, ...rest] = list;
// real URLs for crawlers; plain click opens the in-page overlay
const open = (e, slug) => { if (!e.ctrlKey && !e.metaKey && !e.shiftKey && e.button === 0) { e.preventDefault(); onOpen(slug); } };
return (
<section id="projects" className="projects" aria-label="Selected projects">
<div className="container">
<Reveal>
<div className="projects-head">
<div>
<div className="section-counter"><span className="num">03</span><span className="bar"></span><span>Projects</span></div>
<h2 className="section-title">Selected work.</h2>
</div>
<p className="lede">Broadcast facility design and systems integration for enterprise, sports, aerospace, and financial services clients.</p>
</div>
</Reveal>
{featured && (
<Reveal>
<a className="proj-featured" href={`/projects/${featured.slug}/`} onClick={(e)=>open(e, featured.slug)}>
<img src={featured.thumbnail} alt={`${featured.client} — ${featured.category}`}/>
<div className="proj-featured-body">
<div className="proj-featured-meta">
<span className="badge">Featured</span>
<span className="yr">{featured.category} · {featured.year}</span>
</div>
<h3>{featured.client}</h3>
<p>{featured.summary}</p>
<span className="cta">View case study <ArrowRight/></span>
</div>
</a>
</Reveal>
)}
<div className="proj-grid">
{rest.map((p, i) => (
<Reveal key={p.slug} delay={i*60}>
<a className="proj-card"
href={`/projects/${p.slug}/`}
onClick={(e)=>open(e, p.slug)}>
<img src={p.thumbnail} alt={`${p.client} — ${p.category}`}/>
<div className="proj-card-overlay"></div>
<div className="proj-arrow"><ArrowUpRight/></div>
<div className="proj-card-body">
<div className="proj-card-meta">
<span className="cat">{p.category}</span>
<span className="sep">/</span>
<span className="yr">{p.year}</span>
</div>
<h3>{p.client}</h3>
<p className="summary">{p.summary}</p>
<div className="scope-chips">
{pickScopeChips(p.scope).map(s => <span key={s}>{s}</span>)}
</div>
</div>
</a>
</Reveal>
))}
</div>
</div>
</section>
);
}
// ─── TECH — spec sheet ───────────────────────────────────────────────────────
const TECH_CATS = [
{ name:"Routing & Switching", items:["Ross Ultrix","Blackmagic ATEM","Evertz EQX","Panasonic Kairos"] },
{ name:"All-In-One Production", items:["vMix","Vizrt","AMPP"] },
{ name:"Signal Transport", items:["SMPTE 2110","NDI","SRT","SDI","Dante","MADI","JPEG XS"] },
{ name:"Infrastructure", items:["IP Networking","Fiber Infrastructure","KVM Systems","UPS & Power","Cooling & Ventilation"] },
{ name:"Display & XR", items:["LED Processing","Unreal Engine","Camera Tracking","Projection","Color Management"] },
];
function TechStack() {
return (
<section className="tech grain dark-section">
<div className="container">
<Reveal>
<div style={{maxWidth:"48rem", marginBottom:"3rem"}}>
<div className="section-counter"><span className="num">04</span><span className="bar"></span><span>Technology</span></div>
<h2 className="section-title" style={{marginBottom:"1.25rem"}}>Tools of the trade.</h2>
<p className="section-lede">Deep experience across the full broadcast technology stack — from traditional SDI infrastructure to modern IP and cloud-native production platforms.</p>
</div>
</Reveal>
<div className="tech-table">
{TECH_CATS.map((c, i) => (
<Reveal key={c.name} delay={i*60}>
<div className="tech-row">
<h3>{c.name}</h3>
<div className="items">
{c.items.map(it => <span key={it}>{it}</span>)}
</div>
</div>
</Reveal>
))}
</div>
</div>
</section>
);
}
// ─── ON SET ──────────────────────────────────────────────────────────────────
const REEL_URL = "https://player.vimeo.com/video/225920311?h=0&badge=0&autopause=0&player_id=0&app_id=58479";
const CREDITS = [
{ t:"Bethesda Fallout Day", r:"1st AC", f:"Corporate / Event", y:"2025" },
{ t:"ZeniMax Elder Scrolls Online Update", r:"1st AC", f:"Corporate", y:"2025" },
{ t:"Palo Alto Ad", r:"Arri Trinity Operator", f:"Commercial", y:"2025" },
{ t:"Street Fighter DLC Ad", r:"Arri Trinity Operator", f:"Commercial", y:"2025" },
{ t:"Chase Small Business Promo", r:"Arri Trinity Operator", f:"Commercial", y:"2025" },
{ t:"ZeniMax Elder Scrolls Online Update", r:"1st AC", f:"Corporate", y:"2024" },
{ t:"Joe Vogel For Congress", r:"Camera Op / Trinity Op", f:"Political", y:"2024" },
{ t:"I Am a Champion", r:"Camera Op / Trinity Op", f:"Sports", y:"2023" },
{ t:"Washington Commanders Schedule Release", r:"Director of Photography", f:"Sports", y:"2023" },
{ t:"Stephen Sharer – MIDNIGHT", r:"DP / Trinity Operator", f:"Narrative", y:"2023" },
{ t:"Stephen Sharer – YOU and I", r:"DP / Trinity Operator", f:"Narrative", y:"2023" },
{ t:"A Chocolate Lens", r:"Camera Operator", f:"Narrative", y:"2023" },
{ t:"Capital One: Pride Month", r:"Director of Photography", f:"Corporate", y:"2021" },
{ t:"Tafon Nchukwi: My Goal Is to Be UFC Champion", r:"Camera Operator", f:"Sports Doc", y:"2020" },
{ t:"Tinder", r:"Director of Photography", f:"Commercial", y:"2020" },
{ t:"Conewago", r:"DP / Editor", f:"Documentary", y:"2020" },
{ t:"In Memoriam", r:"Director of Photography", f:"Documentary", y:"2019" },
];
const GEAR = [
{ cat:"Cinema Cameras", icon: Camera, items:["RED Komodo-X","RED DSMC3 V-Raptor-X 8K VV + 6K S35 Dual-Format (Canon RF)"] },
{ cat:"Lenses", icon: Film, items:["Mamiya 645 Sekor C PL 7 Lens Set","Mamiya 645 Sekor C 35mm","Mamiya 645 Sekor C 110mm","Mamiya 645 Sekor C 150mm","16-30mm / 28-75mm / 75-180mm T2.9 Zoom Set"] },
{ cat:"Monitoring & Transmission", icon: Monitor, items:["SmallHD DSMC3 7\"","SmallHD Cine7 with Bolt 6 1500RX","Teradek Bolt 6 Max XT Kit (TX + RX)","DJI SDR Transmission"] },
{ cat:"Camera Support", icon: Package, items:["Arri Trinity — Certified Owner & Operator","Dana Dolly Kit (8 / 4ft Speedrail, 2× Matthews Stands)","DJI Focus Pro All In One"] },
];
function OnSet() {
return (
<section id="on-set" className="onset">
<div className="container onset-stack">
<Reveal>
<div className="onset-intro">
<div className="section-counter"><span className="num">05</span><span className="bar"></span><span>On Set</span></div>
<h2 className="section-title">Trinity Operator &amp; DIT, <span className="light">Washington DC.</span></h2>
<p className="section-lede" style={{marginTop:"1.25rem"}}>Certified Arri Trinity owner and operator with RED camera packages and specialized live production gear — from run-and-gun documentary to multi-camera sports and political campaigns. Available for commercial, corporate, sports, and narrative work throughout the DMV.</p>
</div>
</Reveal>
<Reveal>
<div>
<p className="eyebrow">Reel</p>
<div className="reel-frame">
<iframe src={REEL_URL} allow="autoplay; fullscreen; picture-in-picture" allowFullScreen title="Zachary Gaetano — Showreel"></iframe>
</div>
</div>
</Reveal>
<Reveal>
<div>
<p className="eyebrow">Selected Credits</p>
<div className="credits-list">
{CREDITS.map((c, i) => (
<div key={i} className="credit-row">
<span className="t">{c.t}</span>
<span className="r">{c.r}</span>
<span className="f">{c.f}</span>
<span className="y">{c.y}</span>
</div>
))}
</div>
</div>
</Reveal>
<div>
<Reveal><p className="eyebrow">Kit</p></Reveal>
<div className="gear-grid">
{GEAR.map((g, i) => (
<Reveal key={g.cat} delay={i*100}>
<div className="gear-card">
<div className="cap-icon" style={{marginBottom:"1rem"}}><g.icon size={20} sw={1.5}/></div>
<h3>{g.cat}</h3>
<ul>{g.items.map(it => <li key={it}>{it}</li>)}</ul>
</div>
</Reveal>
))}
</div>
</div>
</div>
</section>
);
}
// ─── CONTACT & SCOPE SELECTOR ────────────────────────────────────────────────
const SCOPES = [
"Broadcast Facility / Control Room",
"Commercial Boardroom / Enterprise AV",
"SMPTE ST 2110 IP Migration",
"Direct-View LED Video Wall / XR Stage",
"System Commissioning & Engineering Audit"
];
function Contact() {
const [selectedScope, setSelectedScope] = useState(SCOPES[0]);
const mailtoHref = `mailto:zgaetano@wilddragon.net?subject=${encodeURIComponent(`Project Scope Inquiry: ${selectedScope}`)}&body=${encodeURIComponent(`Hi Zachary,\n\nI would like to discuss a project regarding ${selectedScope}.\n\nLocation (DC/MD/VA/Other):\nTimeline / Target Date:\nProject Overview:\n\nBest regards,`)}`;
return (
<section id="contact" className="contact">
<div className="container">
<Reveal>
<div className="contact-head">
<div className="section-rule center"></div>
<p className="eyebrow center">// Project Scoping &amp; Inquiries</p>
<h2 className="section-title">Let&apos;s engineer your next facility.</h2>
<p className="lede" style={{marginTop:"1.25rem"}}>
Whether you are planning a new broadcast studio, upgrading enterprise conference rooms, or commissioning an uncompressed IP video network, connect directly with our principal design engineer.
</p>
</div>
</Reveal>
{/* Interactive Scope Selection */}
<Reveal delay={60}>
<div className="scope-selector-card">
<div className="scope-header">
<span className="scope-prompt">// Select your project discipline:</span>
</div>
<div className="scope-pills">
{SCOPES.map(scope => (
<button
key={scope}
type="button"
className={`scope-pill ${selectedScope === scope ? "active" : ""}`}
onClick={() => setSelectedScope(scope)}>
{selectedScope === scope && <Check size={14} className="scope-check"/>}
{scope}
</button>
))}
</div>
<div className="scope-action-row">
<a href={mailtoHref} className="btn btn-primary scope-submit-btn">
Launch Inquiry for {selectedScope} <ArrowRight size={16}/>
</a>
</div>
</div>
</Reveal>
<div className="contact-grid" style={{marginTop:"3rem"}}>
<Reveal delay={0}>
<a className="contact-card" href="mailto:zgaetano@wilddragon.net">
<div className="icon"><Mail size={16} sw={1.5}/></div>
<span className="label">Direct Engineering Email</span>
<span className="val">zgaetano@wilddragon.net</span>
</a>
</Reveal>
<Reveal delay={80}>
<a className="contact-card" href="https://www.linkedin.com/in/zachary-gaetano-05962386/" target="_blank" rel="noopener noreferrer">
<div className="icon"><Linkedin size={16} sw={1.5}/></div>
<span className="label">LinkedIn Profile</span>
<span className="val">Zachary Gaetano</span>
</a>
</Reveal>
<Reveal delay={160}>
<div className="contact-card">
<div className="icon"><MapPin size={16} sw={1.5}/></div>
<span className="label">Primary Service Region</span>
<span className="val">Washington DC · MD · VA (DMV)</span>
</div>
</Reveal>
</div>
<Reveal delay={240}>
<div className="cta-banner grain">
<div className="cta-banner-grid"></div>
<div className="inner">
<h3>Ready to scope your facility build?</h3>
<p>Every facility receives full signal-flow drawings, documented wire runs, and end-to-end commissioning against a written acceptance standard.</p>
<a href={mailtoHref} className="btn btn-primary">Start a Consultation <ArrowRight/></a>
</div>
</div>
</Reveal>
</div>
</section>
);
}
// ─── FOOTER ──────────────────────────────────────────────────────────────────
function Footer() {
const serviceLinks = [
{ l: "Commercial AV Installation", h: "/services/commercial-av-installation-washington-dc/" },
{ l: "Broadcast Systems Integration", h: "/services/broadcast-systems-integration/" },
{ l: "LED Video Wall & XR Stages", h: "/services/led-video-wall-installation/" },
{ l: "Conference Room AV Systems", h: "/services/conference-room-av/" },
];
const corridorLinks = [
{ l: "Washington, DC", h: "/washington-dc/" },
{ l: "Northern Virginia (Tysons/Reston)", h: "/northern-virginia/" },
{ l: "Maryland (Bethesda/Rockville)", h: "/maryland/" },
{ l: "Broadcast Integration DMV", h: "/broadcast-integration-dmv/" },
{ l: "Commercial AV DMV", h: "/av-installation-dmv/" },
];
const projectLinks = [
{ l: "Washington Commanders Stadium", h: "/projects/washington-commanders/" },
{ l: "BetMGM Cloud Production", h: "/projects/betmgm-cloud-production/" },
{ l: "CVS / Aetna Broadcast Facility", h: "/projects/cvs-aetna-broadcast-facility/" },
{ l: "UBS Broadcast Center", h: "/projects/ubs-broadcast-center/" },
{ l: "All Case Studies", h: "/projects/" },
];
return (
<footer className="footer">
<div className="container">
<div className="footer-top">
<div className="footer-brand-col">
<div className="footer-brand">
<img src={__R("images/dragon-mark.png")} alt="Wild Dragon" width="30" height="30" />
<span>Wild Dragon</span>
</div>
<p className="about-line">
Broadcast systems design, commercial AV installation, and SMPTE ST 2110 commissioning across Washington, DC, Maryland, and Northern Virginia.
</p>
</div>
<div className="footer-col">
<p className="footer-title">Capabilities</p>
<ul>
{serviceLinks.map(s => <li key={s.h}><a href={s.h}>{s.l}</a></li>)}
</ul>
</div>
<div className="footer-col">
<p className="footer-title">Regional Corridors</p>
<ul>
{corridorLinks.map(s => <li key={s.h}><a href={s.h}>{s.l}</a></li>)}
</ul>
</div>
<div className="footer-col">
<p className="footer-title">Case Studies</p>
<ul>
{projectLinks.map(s => <li key={s.h}><a href={s.h}>{s.l}</a></li>)}
</ul>
</div>
</div>
<div className="footer-bottom">
<p>© {new Date().getFullYear()} Wild Dragon LLC · Zachary Gaetano. All rights reserved.</p>
<div className="footer-legal-links">
<a href="/llms.txt">LLMs / AI Spec</a>
<a href="/sitemap.xml">Sitemap</a>
<a href="mailto:zgaetano@wilddragon.net">zgaetano@wilddragon.net</a>
</div>
</div>
</div>
</footer>
);
}
// ─── PROJECT OVERLAY — editorial case study ──────────────────────────────────
function ProjectOverlay({ slug, onClose, onOpen }) {
const projects = window.PROJECTS;
const project = projects.find(p => p.slug === slug);
useEffect(() => {
const onKey = (e) => { if (e.key === "Escape") onClose(); };
window.addEventListener("keydown", onKey);
document.body.style.overflow = "hidden";
return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = ""; };
}, [onClose]);
const maskRef = useRef(null);
useEffect(() => { if (maskRef.current) maskRef.current.scrollTop = 0; }, [slug]);
if (!project) return null;
const idx = projects.findIndex(p => p.slug === slug);
const total = projects.length;
const prev = idx > 0 ? projects[idx-1] : projects[total-1];
const next = idx < total - 1 ? projects[idx+1] : projects[0];
const num = String(idx+1).padStart(2,"0");
const totalStr = String(total).padStart(2,"0");
// First description paragraph used as a lede, rest as body
const [lede, ...rest] = project.description;
return (
<div className="po-mask" ref={maskRef} onClick={(e)=>{ if(e.target===maskRef.current) onClose(); }}>
<button className="po-close" onClick={onClose} aria-label="Close"><X size={20}/></button>
<div className="po">
<nav className="po-nav">
<div className="po-nav-inner">
<a className="po-back" href="#projects" onClick={(e)=>{e.preventDefault(); onClose();}}>
<ArrowLeft size={15}/> All projects
</a>
<span className="po-counter"><span className="n">{num}</span><span className="d">/</span><span className="t">{totalStr}</span></span>
<span className="po-brand">Wild Dragon</span>
</div>
</nav>
{/* === HERO === */}
<section className="po-hero">
<div className="po-hero-bg">
<img src={project.thumbnail} alt=""/>
<div className="po-hero-grid"></div>
<div className="po-hero-fade"></div>
</div>
<div className="container po-hero-inner">
<div className="po-hero-meta">
<span className="po-cat">{project.category}</span>
<span className="po-dot"></span>
<span className="po-yr">{project.year}</span>
</div>
<h1 className="po-title">{project.client}</h1>
<p className="po-lede">{project.summary}</p>
<div className="po-hero-rule"></div>
<div className="po-hero-foot">
<span className="po-corner-l">// {project.title || project.client}</span>
<span className="po-corner-r">Case Study · {num}/{totalStr}</span>
</div>
</div>
</section>
{/* === FACTS BAR === */}
<section className="po-facts">
<div className="container">
<div className="po-facts-grid">
<div><span className="lbl">Client</span><span className="val">{project.client}</span></div>
<div><span className="lbl">Category</span><span className="val">{project.category}</span></div>
<div><span className="lbl">Year</span><span className="val">{project.year}</span></div>
<div><span className="lbl">Role</span><span className="val">{(project.scope && project.scope[0]) || "Systems Design"}</span></div>
</div>
</div>
</section>
{/* === LEDE / OPENING === */}
{lede && (
<section className="po-section po-opening">
<div className="container po-opening-grid">
<div className="po-opening-label">
<span className="num">01</span>
<span className="bar"></span>
<span>Overview</span>
</div>
<p className="po-opening-text">{lede}</p>
</div>
</section>
)}
{/* === FEATURE IMAGE === */}
<div className="po-feature">
<div className="po-feature-inner">
<img src={project.thumbnail} alt={`${project.client} — ${project.category}`}/>
<div className="po-feature-cap">
<span>{project.client} · {project.category}</span>
<span>{project.year}</span>
</div>
</div>
</div>
{/* === BODY + SIDECAR === */}
<section className="po-section po-body">
<div className="container po-body-grid">
<div className="po-body-main">
<div className="po-body-label">
<span className="num">02</span>
<span className="bar"></span>
<span>The build</span>
</div>
<div className="po-body-prose">
{rest.map((p, i) => <p key={i}>{p}</p>)}
</div>
{project.highlights && project.highlights.length > 0 && (
<>
<div className="po-body-label" style={{marginTop:"4.5rem"}}>
<span className="num">03</span>
<span className="bar"></span>
<span>Highlights</span>
</div>
<ul className="po-hl">
{project.highlights.map((h, i) => (
<li key={i}>
<span className="hl-n">{String(i+1).padStart(2,"0")}</span>
<span className="hl-t">{h}</span>
</li>
))}
</ul>
</>
)}
</div>
<aside className="po-sidecar">
<div className="po-spec">
<div className="po-spec-row">
<span className="k">Scope</span>
<div className="v">
{project.scope.map(s => <span key={s} className="chip">{s}</span>)}
</div>
</div>
<div className="po-spec-row">
<span className="k">Technology</span>
<div className="v">
{project.technologies.map(t => <span key={t} className="chip chip-accent">{t}</span>)}
</div>
</div>
</div>
</aside>
</div>
</section>
{/* === CLOSING CTA === */}
<section className="po-cta">
<div className="container">
<div className="po-cta-inner grain">
<div>
<p className="po-cta-eyebrow">// Next step</p>
<h3>Planning a similar build?</h3>
<p className="po-cta-desc">Same engineering discipline, end to end — design, integration, commissioning, training, support.</p>
</div>
<a href="mailto:zgaetano@wilddragon.net" className="btn btn-primary">Start a conversation <ArrowRight/></a>
</div>
</div>
</section>
{/* === RELATED + PREV/NEXT === */}
<section className="po-related">
<div className="container">
<div className="po-related-head">
<span className="po-related-label">// Other case studies</span>
</div>
<div className="po-related-grid">
{projects.filter(p => p.slug !== project.slug).slice(0, 3).map(p => (
<a key={p.slug} className="po-related-card"
href={`#/projects/${p.slug}`}
onClick={(e)=>{e.preventDefault(); onOpen(p.slug);}}>
<div className="img"><img src={p.thumbnail} alt={p.client}/></div>
<div className="meta">
<span className="cat">{p.category}</span>
<span className="yr">{p.year}</span>
</div>
<h4>{p.client}</h4>
<span className="go">View case study <ArrowRight size={13}/></span>
</a>
))}
</div>
</div>
</section>
<section className="po-prevnext">
<div className="po-prevnext-grid">
<a className="prev" href={`#/projects/${prev.slug}`} onClick={(e)=>{e.preventDefault(); onOpen(prev.slug);}}>
<ArrowLeft size={20}/>
<div className="text">
<div className="label">Previous</div>
<div className="name">{prev.client}</div>
</div>
</a>
<a className="next" href={`#/projects/${next.slug}`} onClick={(e)=>{e.preventDefault(); onOpen(next.slug);}}>
<div className="text">
<div className="label">Next</div>
<div className="name">{next.client}</div>
</div>
<ArrowRight size={20}/>
</a>
</div>
</section>
<footer className="po-foot">
<div className="po-foot-inner">
<a className="brand" href="#" onClick={(e)=>{e.preventDefault(); onClose();}}>Wild Dragon</a>
<p>© {new Date().getFullYear()} Zachary Gaetano</p>
</div>
</footer>
</div>
</div>
);
}
Object.assign(window, {
Navigation, Hero, Clients, Partners, About, Stats, Services, Projects,
TechStack, OnSet, Contact, Footer, ProjectOverlay, CursorDot, Curtain,
});