// Project case study template — the hero deliverable. // Metadata bar (sector · location · scope · area · year · services), build narrative // (brief → construction approach → joinery → approvals → outcome), gallery w/ lightbox, // related work, and a "start a similar project" CTA. function CaseStudy({ id, navigate }) { const data = window.DS_DATA; const project = data.projects.find((p) => p.id === id); const [lightbox, setLightbox] = useState(null); // index or null useEffect(() => { window.scrollTo({ top: 0, behavior: "instant" }); }, [id]); if (!project) { return (

Project not found.

The case study you were looking for has been moved or unpublished.

); } const related = data.projects.filter((p) => p.id !== project.id && p.sector === project.sector).slice(0, 3); const fallbackRelated = data.projects.filter((p) => p.id !== project.id).slice(0, 3); const relatedList = related.length >= 2 ? related : fallbackRelated; // Build the build-narrative as an ordered list. const stages = [ { code: "01", label: "Brief", body: project.brief }, { code: "02", label: "Construction approach", body: project.build }, { code: "03", label: "Joinery & finishes", body: project.joinery }, { code: "04", label: "Approvals", body: project.approvals }, { code: "05", label: "Outcome", body: project.outcome }, ]; // Gallery layout — alternates between split (7/5) and full (12) rows. const gallerySpans = ["span-7", "span-5", "span-12", "span-6", "span-6"]; return (
{/* Breadcrumb */}
/ / {project.name}
{/* Header */}
Case study — {String(data.projects.indexOf(project) + 1).padStart(2, "0")}

{project.name}

{project.summary}

{/* Hero image */}
{project.name}
{/* Metadata bar */}
{/* Narrative */}
The build

How we delivered this one.

    {stages.map((s, i) => (
  1. {s.code} ·

    {s.label}

    {s.body}

  2. ))}
{/* Gallery */}
Gallery Photography credit: in confirmation
{project.gallery.map((src, i) => (
setLightbox(i)}>
))} {/* If gallery is short, pad with relevant process imagery so the layout never feels empty */} {project.gallery.length < 3 ? ( <>
setLightbox(project.gallery.length)}> In-house joinery
setLightbox(project.gallery.length + 1)}> Construction stage
) : null}
{/* Stage progress strip — before / during / after placeholder */}
{["Before", "During build", "Handover"].map((label, i) => { const imgs = [ ["media/process-earthwork.webp", "media/capability-building.webp", project.heroImage], [project.heroImage, "media/process-joinery.webp", "media/capability-building.webp"], ][i % 2]; return (
{label}
{label} {i === 0 ? "Pre-mob" : i === 1 ? "Mid programme" : "On handover"}
); })}
{/* CTA */}

Building something like this?

Tell us the scope and programme — we'll come back within two working days with a sector lead and a build approach.

{/* Related */}
navigate({ name: "projects", filter: project.sector })}>All {project.sectorLabel}} />
{relatedList.map((p) => ( navigate({ name: "project", id: p.id })} /> ))}
{lightbox !== null ? ( setLightbox(null)} /> ) : null}
); } function MetaBar({ project }) { const cells = [ { label: "Sector", value: project.sectorLabel }, { label: "Location", value: project.location }, { label: "Scope", value: project.scope }, { label: "Area", value: project.area }, { label: "Year", value: project.year }, { label: "Services", value: project.services.join(" · ") }, ]; return (
{cells.map((c, i) => (
{c.label} {c.value}
))}
); } Object.assign(window, { CaseStudy });