Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions portfolio/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,17 @@ section, .scroll-target { scroll-margin-top: 5rem; }
.mobile-navigation > summary { list-style: none; }
.mobile-navigation > summary::-webkit-details-marker { display: none; }
.story-details > summary { cursor: pointer; color: rgb(103 232 249); font-weight: 600; }
.project-link {
display: inline-flex;
align-items: center;
gap: .4rem;
color: rgb(103 232 249);
font-size: .875rem;
font-weight: 600;
text-underline-offset: 4px;
}
.project-link:hover { color: rgb(207 250 254); text-decoration: underline; }
.project-link:focus-visible { outline: 2px solid rgb(103 232 249); outline-offset: 4px; border-radius: .2rem; }

body {
background: #0a0a0f;
Expand Down Expand Up @@ -314,6 +325,11 @@ h1, h2, h3, h4, h5, h6 {
color: #fff;
}

@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
*, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}

dt {
color: rgb(103 232 249);
font-weight: 600;
Expand Down
2 changes: 1 addition & 1 deletion portfolio/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const metadata: Metadata = {
const personStructuredData = {
'@context': 'https://schema.org',
'@type': 'Person',
name: 'Christopher J. Bratkovics',
name: SITE.author.name,
jobTitle: SITE.author.jobTitle,
description: SITE.description,
url: SITE.url,
Expand Down
9 changes: 5 additions & 4 deletions portfolio/components/MinimalHero.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ArrowDownRight } from "lucide-react";
import { identity } from "@/data/projects";

export default function MinimalHero() {
return (
Expand All @@ -7,18 +8,18 @@ export default function MinimalHero() {

<div className="max-w-6xl mx-auto relative z-10 w-full">
<p className="text-cyan-400 font-semibold tracking-wide uppercase text-sm mb-4">
7+ years in enterprise analytics
{identity.eyebrow}
</p>
<h1 className="text-5xl md:text-7xl font-bold mb-5">
<span className="gradient-text">Christopher J. Bratkovics</span>
<span className="gradient-text">{identity.name}</span>
</h1>

<p className="text-2xl md:text-4xl text-white mb-7 font-semibold">
Data Scientist <span className="text-gray-500">|</span> Analytics Engineer <span className="text-gray-500">|</span> Applied AI
{identity.headline.split(" | ").map((part, index) => <span key={part}>{index > 0 && <span className="text-gray-500"> | </span>}{part}</span>)}
</p>

<p className="text-lg md:text-xl text-gray-300 max-w-4xl leading-relaxed mb-10">
I build predictive models and production data products, translating fragmented business data into reliable reporting and analytical tools. At OUTFRONT Media, I own a five-platform Snowflake/dbt reporting foundation and develop Python-based solutions for advertiser retention, segmentation, and inventory performance.
{identity.summary}
</p>

<div className="flex flex-wrap gap-4">
Expand Down
166 changes: 44 additions & 122 deletions portfolio/components/Projects.tsx
Original file line number Diff line number Diff line change
@@ -1,132 +1,54 @@
import { Github, ExternalLink } from "lucide-react";
import { projects } from "@/data/projects";
import { ExternalLink, Github } from "lucide-react";
import { projects, type Project } from "@/data/projects";

export default function Projects() {
const featuredProjects = projects.filter((project) => project.featured);
const additionalProjects = projects.filter((project) => !project.featured);
function ProjectLinks({ project }: { project: Project }) {
return (
<div className="flex flex-wrap items-center gap-x-4 gap-y-3 pt-4 mt-auto border-t border-white/10">
{project.liveUrl && <a href={project.liveUrl} target="_blank" rel="noopener noreferrer" className="project-link"><ExternalLink className="w-4 h-4" aria-hidden="true" />{project.liveLabel ?? "Demo"}</a>}
<a href={project.githubUrl} target="_blank" rel="noopener noreferrer" className="project-link"><Github className="w-4 h-4" aria-hidden="true" />Source code</a>
{project.evidence?.map((item) => <a key={item.url} href={item.url} target="_blank" rel="noopener noreferrer" className="project-link"><ExternalLink className="w-4 h-4" aria-hidden="true" />{item.label}</a>)}
</div>
);
}

function ProjectCard({ project, flagship = false }: { project: Project; flagship?: boolean }) {
return (
<section id="projects" className="py-20 px-4 relative overflow-hidden">
<div className="absolute inset-0 cyber-grid opacity-30" />
<article className={`glassmorphism rounded-xl p-6 md:p-8 flex flex-col ${flagship ? "lg:grid lg:grid-cols-[1.1fr_.9fr] lg:gap-10" : ""}`}>
<div>
<p className="text-cyan-400 text-xs font-semibold uppercase tracking-widest mb-3">{flagship ? "Flagship evidence" : project.featured ? "Featured project" : "Additional work"}</p>
<h3 className="text-xl md:text-2xl font-bold text-white">{project.title}</h3>
<p className="text-gray-200 leading-relaxed mt-4 font-medium">{project.summary}</p>
<p className="text-gray-400 text-sm leading-relaxed mt-3">{project.detail}</p>
</div>
<div className={`flex flex-col ${flagship ? "lg:border-l lg:border-white/10 lg:pl-10 mt-6 lg:mt-0" : "mt-5"}`}>
<p className="text-sm text-gray-300 leading-relaxed"><span className="text-white font-semibold">What to inspect:</span> {project.inspect}</p>
<div className="flex flex-wrap gap-2 my-5" aria-label={`${project.title} technologies`}>
{project.tech.map((tech) => <span key={tech} className="px-3 py-1 text-xs rounded-full glassmorphism text-gray-300">{tech}</span>)}
</div>
<ProjectLinks project={project} />
</div>
</article>
);
}

<div
className="max-w-7xl mx-auto relative z-10"
>
export default function Projects() {
const featured = projects.filter((project) => project.featured);
const additional = projects.filter((project) => !project.featured);
return (
<section id="projects" className="py-20 px-4 relative overflow-hidden">
<div className="absolute inset-0 cyber-grid opacity-30" aria-hidden="true" />
<div className="max-w-7xl mx-auto relative z-10">
<div className="text-center mb-12">
<h2 className="text-4xl md:text-5xl font-bold gradient-text mb-4">
Independent Technical Projects
</h2>
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
Three complementary builds in forecasting, analytical interfaces, and reliable LLM application behavior
</p>
<h2 className="text-4xl md:text-5xl font-bold gradient-text mb-4">Independent Technical Projects</h2>
<p className="text-gray-300 text-lg max-w-3xl mx-auto">Public implementations and scoped evidence—kept distinct from proprietary professional work.</p>
</div>

<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{featuredProjects.map((project) => (
<div
key={project.id}
className="relative group"
>
<div className="glassmorphism p-6 md:p-8 rounded-xl h-full flex flex-col transition-all duration-300 hover:shadow-2xl">
<div className="absolute inset-0 gradient-bg opacity-0 group-hover:opacity-10 rounded-xl transition-opacity duration-300" />

<div className="relative z-10 flex flex-col h-full">
{/* Header */}
<div className="flex justify-between items-start gap-4 mb-4">
<h3 className="text-xl md:text-2xl font-bold text-white group-hover:gradient-text transition-all duration-300">
{project.title}
</h3>
<a
href={project.githubUrl}
target="_blank"
rel="noopener noreferrer"
aria-label={`${project.title} source on GitHub`}
className="p-2 glassmorphism rounded-lg hover:scale-110 transition-transform flex-shrink-0"
>
<Github className="w-5 h-5 text-gray-300" />
</a>
</div>

{/* Description */}
<p className="text-gray-200 leading-relaxed mb-3 font-medium">
{project.summary}
</p>
<p className="text-gray-400 text-sm leading-relaxed mb-6">{project.detail}</p>
{project.evidence && (
<div className="flex flex-wrap gap-3 mb-6" aria-label={`${project.title} evidence`}>
{project.evidence.map((item) => (
<a key={item.url} href={item.url} target="_blank" rel="noopener noreferrer"
className="text-cyan-300 underline underline-offset-4 hover:text-cyan-200">
{item.label}
</a>
))}
</div>
)}

{/* Tech Stack */}
<div className="flex flex-wrap gap-2 mb-6">
{project.tech.map((tech) => (
<span
key={tech}
className="px-3 py-1 text-xs rounded-full glassmorphism text-gray-300"
>
{tech}
</span>
))}
</div>

{/* Actions */}
<div className="flex items-center gap-3 pt-4 mt-auto border-t border-white/10">
{project.liveUrl && (
<a
href={project.liveUrl}
target="_blank"
rel="noopener noreferrer"
className="flex-1 flex items-center justify-center gap-2 px-4 py-2.5
bg-gradient-to-r from-blue-500 to-purple-600
hover:from-blue-600 hover:to-purple-700
text-white font-semibold rounded-lg
hover:shadow-xl hover:scale-105
transition-all duration-300"
>
<ExternalLink className="w-4 h-4" />
<span>Demo</span>
</a>
)}

<a
href={project.githubUrl}
target="_blank"
rel="noopener noreferrer"
className={`flex items-center justify-center gap-2 px-4 py-2.5
text-sm text-gray-400 hover:text-white
glassmorphism rounded-lg
hover:bg-white/10 transition-all duration-300
${project.liveUrl ? "flex-shrink-0" : "flex-1"}`}
>
<Github className="w-4 h-4" />
<span>Source code</span>
</a>
</div>
</div>
</div>
</div>
))}
<div className="space-y-8">
<ProjectCard project={featured[0]} flagship />
<div className="grid grid-cols-1 xl:grid-cols-2 gap-8">{featured.slice(1).map((project) => <ProjectCard key={project.id} project={project} />)}</div>
</div>
<div className="mt-10 border-t border-white/10 pt-8">
<h3 className="text-xl font-semibold text-white mb-4">Additional work</h3>
<div className="grid md:grid-cols-2 gap-4">
{additionalProjects.map((project) => (
<article key={project.id} className="glassmorphism rounded-lg p-5">
<h4 className="text-lg font-semibold text-white">{project.title}</h4>
<p className="text-gray-300 text-sm leading-relaxed mt-2">{project.summary}</p>
<p className="text-gray-500 text-sm leading-relaxed mt-2">{project.detail}</p>
<a href={project.githubUrl} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-2 text-cyan-400 hover:text-cyan-300 mt-4 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-cyan-300">
<Github className="w-4 h-4" /> Source code
</a>
</article>
))}
</div>
<div className="mt-12 border-t border-white/10 pt-10">
<h3 className="text-2xl font-semibold text-white mb-6">Additional work</h3>
<div className="grid grid-cols-1 xl:grid-cols-2 gap-6">{additional.map((project) => <ProjectCard key={project.id} project={project} />)}</div>
</div>
</div>
</section>
Expand Down
6 changes: 3 additions & 3 deletions portfolio/components/WorkStories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ const stories = [
},
{
id: "operational-ai",
title: "Restoring executive financial-email output",
outcome: "Restored application output after identifying stale source dependencies.",
title: "Generative AI for executive financial communications",
outcome: "Delivered and supported workflows that turn pacing data into editable executive communications.",
problem: "An application that turns financial pacing data into editable executive communications stopped producing valid output.",
contribution: "Traced invalid financial-email output to stale source views, coordinated the correction with the data team, and validated the restored application output.",
contribution: "Contributed to delivery and ongoing support; when output failed, I traced the issue to stale source views, coordinated correction with the data team, and validated source data and restored output.",
decision: "The correction addressed the source dependency instead of masking the problem with prompt or interface changes.",
validation: "Application output was checked after the cross-team source correction, preserving the boundary between operational support and broader application ownership."
}
Expand Down
13 changes: 7 additions & 6 deletions portfolio/config/site.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { identity } from "@/data/projects";

export const SITE = {
name: "Christopher J. Bratkovics",
title:
"Christopher J. Bratkovics | Data Scientist | Analytics Engineer | Applied AI",
shortTitle: "Christopher J. Bratkovics | Data Scientist | Analytics Engineer | Applied AI",
name: identity.name,
title: `${identity.name} | ${identity.headline}`,
shortTitle: `${identity.name} | ${identity.headline}`,
description:
"Data Scientist and Analytics Engineer with 7+ years in enterprise analytics, building predictive models, production data products, and applied AI.",
url: "https://cbratkovics.dev",
Expand All @@ -18,8 +19,8 @@ export const SITE = {
],

author: {
name: "Christopher J. Bratkovics",
jobTitle: "Data Scientist | Analytics Engineer | Applied AI"
name: identity.name,
jobTitle: identity.headline
}
} as const;

Expand Down
Loading
Loading