adam-os 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +1 -0
  2. package/app/globals.css +2 -0
  3. package/app/layout.tsx +42 -0
  4. package/app/page.tsx +38 -0
  5. package/bin/adam-os.js +144 -0
  6. package/components/Apps/AboutMe.tsx +378 -0
  7. package/components/Apps/ContactForm.tsx +113 -0
  8. package/components/Apps/MyComputer.tsx +117 -0
  9. package/components/Apps/RecycleBin.tsx +131 -0
  10. package/components/Apps/Welcome.tsx +212 -0
  11. package/components/Desktop/Desktop.tsx +128 -0
  12. package/components/Desktop/DesktopIcon.tsx +176 -0
  13. package/components/Desktop/IconGrid.tsx +34 -0
  14. package/components/Mobile/MobileCard.tsx +82 -0
  15. package/components/Mobile/MobileLayout.tsx +58 -0
  16. package/components/Mobile/MobileToggle.tsx +18 -0
  17. package/components/Portfolio/GallerySection.tsx +158 -0
  18. package/components/Portfolio/ImageSection.tsx +40 -0
  19. package/components/Portfolio/PortfolioViewer.tsx +87 -0
  20. package/components/Portfolio/SectionRenderer.tsx +145 -0
  21. package/components/Portfolio/TextSection.tsx +36 -0
  22. package/components/Portfolio/VideoSection.tsx +41 -0
  23. package/components/Taskbar/StartButton.tsx +138 -0
  24. package/components/Taskbar/Taskbar.tsx +77 -0
  25. package/components/Taskbar/TaskbarClock.tsx +27 -0
  26. package/components/Taskbar/TaskbarItem.tsx +33 -0
  27. package/components/Window/AppWindow.tsx +168 -0
  28. package/components/Window/ResizeHandles.tsx +35 -0
  29. package/components/Window/TitleBar.tsx +112 -0
  30. package/context/WindowManager.tsx +386 -0
  31. package/data/portfolio.json +200 -0
  32. package/data/types.ts +30 -0
  33. package/hooks/useDraggable.ts +77 -0
  34. package/hooks/useResizable.ts +133 -0
  35. package/hooks/useWindowManager.ts +12 -0
  36. package/lib/constants.ts +27 -0
  37. package/lib/sounds.ts +56 -0
  38. package/next-env.d.ts +6 -0
  39. package/next.config.ts +7 -0
  40. package/package.json +50 -0
  41. package/postcss.config.mjs +7 -0
  42. package/public/icons/chrome.webp +0 -0
  43. package/public/icons/folder.webp +0 -0
  44. package/public/icons/ie.webp +0 -0
  45. package/public/icons/my-computer.webp +0 -0
  46. package/public/icons/recycle-bin.webp +0 -0
  47. package/public/icons/welcome.webp +0 -0
  48. package/public/pro-pic.jpg +0 -0
  49. package/public/wallpaper.jpg +0 -0
  50. package/site.config.ts +40 -0
  51. package/styles/win95.css +698 -0
  52. package/tailwind.config.ts +69 -0
  53. package/tsconfig.json +41 -0
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # portfolio-adam-bush-96
@@ -0,0 +1,2 @@
1
+ @import "../styles/win95.css";
2
+ @import "tailwindcss";
package/app/layout.tsx ADDED
@@ -0,0 +1,42 @@
1
+ import type { Metadata } from "next";
2
+ import { Inter, JetBrains_Mono } from "next/font/google";
3
+ import "./globals.css";
4
+ import { WindowManagerProvider } from "@/context/WindowManager";
5
+ import siteConfig from "@/site.config";
6
+
7
+ const inter = Inter({
8
+ subsets: ["latin"],
9
+ variable: "--font-inter",
10
+ display: "swap",
11
+ });
12
+
13
+ const jetbrainsMono = JetBrains_Mono({
14
+ subsets: ["latin"],
15
+ variable: "--font-jetbrains",
16
+ display: "swap",
17
+ weight: ["400", "500", "700"],
18
+ });
19
+
20
+ export const metadata: Metadata = {
21
+ title: siteConfig.metaTitle,
22
+ description: siteConfig.metaDescription,
23
+ openGraph: {
24
+ title: siteConfig.metaOgTitle,
25
+ description: siteConfig.metaOgDescription,
26
+ type: "website",
27
+ },
28
+ };
29
+
30
+ export default function RootLayout({
31
+ children,
32
+ }: {
33
+ children: React.ReactNode;
34
+ }) {
35
+ return (
36
+ <html lang="en" className={`${inter.variable} ${jetbrainsMono.variable}`}>
37
+ <body>
38
+ <WindowManagerProvider>{children}</WindowManagerProvider>
39
+ </body>
40
+ </html>
41
+ );
42
+ }
package/app/page.tsx ADDED
@@ -0,0 +1,38 @@
1
+ "use client";
2
+
3
+ import React, { useEffect } from "react";
4
+ import { useWindowManager } from "@/hooks/useWindowManager";
5
+ import { Desktop } from "@/components/Desktop/Desktop";
6
+ import { Taskbar } from "@/components/Taskbar/Taskbar";
7
+ import { MobileLayout } from "@/components/Mobile/MobileLayout";
8
+ import { MobileToggle } from "@/components/Mobile/MobileToggle";
9
+ import { BREAKPOINTS } from "@/lib/constants";
10
+ import { preloadSounds } from "@/lib/sounds";
11
+
12
+ export default function Home() {
13
+ const { state, toggleDesktopMode } = useWindowManager();
14
+
15
+ // On mount: detect mobile and default to card view
16
+ useEffect(() => {
17
+ const isMobile = window.innerWidth < BREAKPOINTS.mobile;
18
+ if (isMobile && state.desktopMode) {
19
+ toggleDesktopMode();
20
+ }
21
+ preloadSounds();
22
+ // eslint-disable-next-line react-hooks/exhaustive-deps
23
+ }, []);
24
+
25
+ return (
26
+ <>
27
+ {state.desktopMode ? (
28
+ <>
29
+ <Desktop />
30
+ <Taskbar />
31
+ </>
32
+ ) : (
33
+ <MobileLayout />
34
+ )}
35
+ <MobileToggle />
36
+ </>
37
+ );
38
+ }
package/bin/adam-os.js ADDED
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ // bin/adam-os.js — AdamOS CLI runner
3
+ // Pure Node.js — no external dependencies required beyond what Next.js needs.
4
+ "use strict";
5
+
6
+ const { execSync, spawn } = require("child_process");
7
+ const fs = require("fs");
8
+ const path = require("path");
9
+ const net = require("net");
10
+
11
+ // ── Working directory is always the package root (not wherever the user ran the command) ──
12
+ const PKG_ROOT = path.resolve(__dirname, "..");
13
+
14
+ // ─────────────────────────────────────────────────────────────────────────────
15
+ // Helpers
16
+ // ─────────────────────────────────────────────────────────────────────────────
17
+
18
+ function checkNodeVersion() {
19
+ const major = parseInt(process.version.slice(1).split(".")[0], 10);
20
+ if (major < 18) {
21
+ console.error(
22
+ `\n ✗ AdamOS requires Node.js >= 18. You have ${process.version}.\n` +
23
+ ` Download the latest LTS: https://nodejs.org\n`
24
+ );
25
+ process.exit(1);
26
+ }
27
+ }
28
+
29
+ function ensureDeps() {
30
+ const sentinel = path.join(PKG_ROOT, "node_modules", ".bin", "next");
31
+ if (!fs.existsSync(sentinel)) {
32
+ console.log("\n Installing dependencies (first run — this takes ~60 seconds)...\n");
33
+ execSync("npm install", { cwd: PKG_ROOT, stdio: "inherit" });
34
+ console.log("");
35
+ }
36
+ }
37
+
38
+ // Returns true if the port is available
39
+ function isPortFree(port) {
40
+ return new Promise((resolve) => {
41
+ const server = net.createServer();
42
+ server.once("error", () => resolve(false));
43
+ server.once("listening", () => server.close(() => resolve(true)));
44
+ server.listen(port, "127.0.0.1");
45
+ });
46
+ }
47
+
48
+ async function findFreePort(start) {
49
+ for (let port = start; port < start + 20; port++) {
50
+ if (await isPortFree(port)) return port;
51
+ }
52
+ console.error(`\n ✗ No free port found starting at ${start}.\n`);
53
+ process.exit(1);
54
+ }
55
+
56
+ function openBrowser(url) {
57
+ const cmd =
58
+ process.platform === "darwin" ? `open "${url}"` :
59
+ process.platform === "win32" ? `start "" "${url}"` :
60
+ `xdg-open "${url}"`;
61
+ try { execSync(cmd, { stdio: "ignore" }); } catch (_) { /* best-effort */ }
62
+ }
63
+
64
+ // Read cdnBase from site.config.ts via simple regex (no ts-node needed)
65
+ function readCdnBase() {
66
+ try {
67
+ const src = fs.readFileSync(path.join(PKG_ROOT, "site.config.ts"), "utf-8");
68
+ const match = src.match(/cdnBase:\s*["']([^"']*)["']/);
69
+ return match?.[1] ?? "";
70
+ } catch (_) {
71
+ return "";
72
+ }
73
+ }
74
+
75
+ function printBanner(url, mode) {
76
+ const pad = (s, n) => s + " ".repeat(Math.max(0, n - s.length));
77
+ console.log([
78
+ "",
79
+ " ╔══════════════════════════════════════════╗",
80
+ ` ║ AdamOS — Portfolio Runner ║`,
81
+ " ╠══════════════════════════════════════════╣",
82
+ ` ║ Mode : ${pad(mode, 32)}║`,
83
+ ` ║ URL : ${pad(url, 32)}║`,
84
+ " ║ Stop : Ctrl+C ║",
85
+ " ╚══════════════════════════════════════════╝",
86
+ "",
87
+ ].join("\n"));
88
+ }
89
+
90
+ // ─────────────────────────────────────────────────────────────────────────────
91
+ // Main
92
+ // ─────────────────────────────────────────────────────────────────────────────
93
+
94
+ async function main() {
95
+ checkNodeVersion();
96
+
97
+ const isProd = process.argv.includes("--prod");
98
+ const portArg = process.argv.find((a) => a.startsWith("--port="));
99
+ const basePort = portArg ? parseInt(portArg.split("=")[1], 10) : 3000;
100
+
101
+ console.log("\n AdamOS is starting up...");
102
+ ensureDeps();
103
+
104
+ const port = await findFreePort(basePort);
105
+ const url = `http://localhost:${port}`;
106
+ const nextBin = path.join(PKG_ROOT, "node_modules", ".bin", "next");
107
+ const cdnBase = readCdnBase();
108
+ const env = {
109
+ ...process.env,
110
+ ...(cdnBase ? { NEXT_PUBLIC_CDN_BASE: cdnBase } : {}),
111
+ };
112
+
113
+ // Forward signals cleanly
114
+ process.on("SIGINT", () => process.exit(0));
115
+ process.on("SIGTERM", () => process.exit(0));
116
+
117
+ if (isProd) {
118
+ console.log("\n Building production bundle (this takes ~30 seconds)...\n");
119
+ try {
120
+ execSync(`"${nextBin}" build`, { cwd: PKG_ROOT, stdio: "inherit", env });
121
+ } catch (_) {
122
+ console.error("\n ✗ Build failed. Try dev mode: npx adam-os\n");
123
+ process.exit(1);
124
+ }
125
+ printBanner(url, "Production");
126
+ const server = spawn(nextBin, ["start", "--port", String(port)], {
127
+ cwd: PKG_ROOT, stdio: "inherit", env,
128
+ });
129
+ setTimeout(() => openBrowser(url), 2000);
130
+ server.on("exit", (code) => process.exit(code ?? 0));
131
+ } else {
132
+ printBanner(url, "Development (live reload)");
133
+ const server = spawn(nextBin, ["dev", "--port", String(port)], {
134
+ cwd: PKG_ROOT, stdio: "inherit", env,
135
+ });
136
+ setTimeout(() => openBrowser(url), 3500);
137
+ server.on("exit", (code) => process.exit(code ?? 0));
138
+ }
139
+ }
140
+
141
+ main().catch((err) => {
142
+ console.error(err);
143
+ process.exit(1);
144
+ });
@@ -0,0 +1,378 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import Image from "next/image";
5
+ import siteConfig from "@/site.config";
6
+
7
+ const S = {
8
+ root: {
9
+ fontFamily: "var(--font-body)",
10
+ fontSize: 14,
11
+ lineHeight: 1.75,
12
+ background: "var(--win95-window-bg)",
13
+ color: "var(--win95-text)",
14
+ overflowY: "auto" as const,
15
+ height: "100%",
16
+ },
17
+ inner: {
18
+ padding: 28,
19
+ maxWidth: 640,
20
+ margin: "0 auto",
21
+ },
22
+ // ── Header ──────────────────────────────────────────────────
23
+ header: {
24
+ display: "flex",
25
+ gap: 20,
26
+ alignItems: "flex-start",
27
+ marginBottom: 24,
28
+ paddingBottom: 20,
29
+ borderBottom: "1px solid rgba(0,0,0,0.08)",
30
+ },
31
+ avatar: {
32
+ width: 88,
33
+ height: 88,
34
+ flexShrink: 0,
35
+ position: "relative" as const,
36
+ border: "2px solid var(--win95-border-dark)",
37
+ boxShadow: "inset 1px 1px 0 var(--win95-border-light), 0 2px 8px rgba(0,0,0,0.12)",
38
+ overflow: "hidden",
39
+ borderRadius: 4,
40
+ },
41
+ headerText: { flex: 1 },
42
+ name: {
43
+ fontSize: 22,
44
+ fontWeight: 700,
45
+ letterSpacing: "-0.01em",
46
+ marginBottom: 2,
47
+ lineHeight: 1.2,
48
+ },
49
+ title: {
50
+ fontSize: 13,
51
+ color: "var(--win95-text-disabled)",
52
+ marginBottom: 6,
53
+ lineHeight: 1.4,
54
+ },
55
+ location: {
56
+ fontSize: 12,
57
+ color: "var(--win95-text-disabled)",
58
+ marginBottom: 12,
59
+ },
60
+ ctaRow: { display: "flex", gap: 6, flexWrap: "wrap" as const },
61
+ // ── TL;DR ────────────────────────────────────────────────────
62
+ tldr: {
63
+ background: "rgba(0,0,128,0.05)",
64
+ border: "1px solid rgba(0,0,128,0.18)",
65
+ borderRadius: 4,
66
+ padding: "12px 16px",
67
+ marginBottom: 24,
68
+ fontSize: 13,
69
+ lineHeight: 1.65,
70
+ },
71
+ tldrLabel: {
72
+ fontWeight: 700,
73
+ fontSize: 11,
74
+ letterSpacing: "0.08em",
75
+ color: "var(--win95-titlebar)",
76
+ textTransform: "uppercase" as const,
77
+ marginBottom: 4,
78
+ },
79
+ tldrLead: {
80
+ fontWeight: 700,
81
+ fontSize: 15,
82
+ color: "var(--win95-titlebar)",
83
+ marginBottom: 6,
84
+ display: "block",
85
+ letterSpacing: "-0.01em",
86
+ },
87
+ // ── Sections ─────────────────────────────────────────────────
88
+ section: {
89
+ marginBottom: 24,
90
+ paddingBottom: 24,
91
+ borderBottom: "1px solid rgba(0,0,0,0.07)",
92
+ },
93
+ sectionLast: { marginBottom: 0, paddingBottom: 0, borderBottom: "none" },
94
+ sectionHeader: {
95
+ fontSize: 11,
96
+ fontWeight: 700,
97
+ letterSpacing: "0.08em",
98
+ textTransform: "uppercase" as const,
99
+ color: "var(--win95-text-disabled)",
100
+ marginBottom: 14,
101
+ display: "flex",
102
+ alignItems: "center",
103
+ gap: 8,
104
+ },
105
+ sectionDivider: {
106
+ flex: 1,
107
+ height: 1,
108
+ background: "rgba(0,0,0,0.08)",
109
+ },
110
+ // ── Experience ───────────────────────────────────────────────
111
+ jobHeader: {
112
+ display: "flex",
113
+ justifyContent: "space-between",
114
+ alignItems: "flex-start",
115
+ gap: 8,
116
+ marginBottom: 4,
117
+ flexWrap: "wrap" as const,
118
+ },
119
+ jobTitle: { fontWeight: 700, fontSize: 14 },
120
+ jobMeta: {
121
+ fontSize: 12,
122
+ color: "var(--win95-text-disabled)",
123
+ textAlign: "right" as const,
124
+ lineHeight: 1.5,
125
+ flexShrink: 0,
126
+ },
127
+ jobSubtitle: {
128
+ fontSize: 12,
129
+ color: "var(--win95-text-disabled)",
130
+ marginBottom: 10,
131
+ },
132
+ bullet: {
133
+ display: "flex",
134
+ gap: 8,
135
+ marginBottom: 7,
136
+ fontSize: 13,
137
+ lineHeight: 1.65,
138
+ },
139
+ bulletDot: {
140
+ color: "var(--win95-titlebar)",
141
+ flexShrink: 0,
142
+ marginTop: 2,
143
+ fontWeight: 700,
144
+ },
145
+ jobSpacer: { marginBottom: 20 },
146
+ // ── Skills ───────────────────────────────────────────────────
147
+ skillGroup: { marginBottom: 12 },
148
+ skillGroupLabel: {
149
+ fontSize: 12,
150
+ fontWeight: 600,
151
+ marginBottom: 6,
152
+ color: "var(--win95-text)",
153
+ },
154
+ tagRow: { display: "flex", flexWrap: "wrap" as const, gap: 5 },
155
+ tag: {
156
+ background: "rgba(0,0,0,0.05)",
157
+ border: "1px solid rgba(0,0,0,0.10)",
158
+ borderRadius: 3,
159
+ padding: "3px 9px",
160
+ fontSize: 12,
161
+ lineHeight: 1.4,
162
+ color: "var(--win95-text)",
163
+ },
164
+ // ── Stats ─────────────────────────────────────────────────────
165
+ statsRow: {
166
+ display: "grid",
167
+ gridTemplateColumns: "repeat(3, 1fr)",
168
+ gap: 10,
169
+ marginBottom: 16,
170
+ },
171
+ stat: {
172
+ background: "rgba(0,0,128,0.05)",
173
+ border: "1px solid rgba(0,0,128,0.14)",
174
+ borderRadius: 4,
175
+ padding: "10px 12px",
176
+ textAlign: "center" as const,
177
+ },
178
+ statValue: { fontSize: 16, fontWeight: 700, color: "var(--win95-titlebar)", lineHeight: 1.2 },
179
+ statLabel: { fontSize: 11, color: "var(--win95-text-disabled)", marginTop: 2 },
180
+ // ── Quote ────────────────────────────────────────────────────
181
+ quote: {
182
+ fontStyle: "italic",
183
+ fontSize: 13,
184
+ color: "var(--win95-text-disabled)",
185
+ borderLeft: "3px solid var(--win95-titlebar)",
186
+ paddingLeft: 12,
187
+ lineHeight: 1.65,
188
+ },
189
+ };
190
+
191
+ const Tag = ({ children }: { children: React.ReactNode }) => (
192
+ <span style={S.tag}>{children}</span>
193
+ );
194
+
195
+ const SectionHeading = ({ children }: { children: React.ReactNode }) => (
196
+ <div style={S.sectionHeader}>
197
+ {children}
198
+ <div style={S.sectionDivider} />
199
+ </div>
200
+ );
201
+
202
+ const Bullet = ({ children }: { children: React.ReactNode }) => (
203
+ <div style={S.bullet}>
204
+ <span style={S.bulletDot}>›</span>
205
+ <span>{children}</span>
206
+ </div>
207
+ );
208
+
209
+ export function AboutMe() {
210
+ return (
211
+ <div className="win95-scrollable" style={S.root}>
212
+ <div style={S.inner}>
213
+
214
+ {/* ── Header ── */}
215
+ <div style={S.header}>
216
+ <div style={S.avatar}>
217
+ <Image
218
+ src={siteConfig.avatar}
219
+ alt={siteConfig.name}
220
+ fill
221
+ sizes="88px"
222
+ style={{ objectFit: "cover", objectPosition: "center top" }}
223
+ unoptimized
224
+ />
225
+ </div>
226
+ <div style={S.headerText}>
227
+ <div style={S.name}>{siteConfig.name}</div>
228
+ <div style={S.title}>Design Lead @ Parcl | I Build Intelligent Design Systems | AI Consulting | UI Eng</div>
229
+ <div style={S.location}>Naples, FL · adamchrisbush@gmail.com · 440-708-8593</div>
230
+ <div style={S.ctaRow}>
231
+ <a
232
+ href={siteConfig.linkedin}
233
+ target="_blank"
234
+ rel="noopener noreferrer"
235
+ className="win95-btn"
236
+ style={{ textDecoration: "none", fontSize: 12, padding: "4px 12px", minHeight: 28 }}
237
+ >
238
+ LinkedIn ↗
239
+ </a>
240
+ <a
241
+ href={siteConfig.resumeUrl}
242
+ target="_blank"
243
+ rel="noopener noreferrer"
244
+ className="win95-btn"
245
+ style={{ textDecoration: "none", fontSize: 12, padding: "4px 12px", minHeight: 28 }}
246
+ >
247
+ Resume PDF ↗
248
+ </a>
249
+ </div>
250
+ </div>
251
+ </div>
252
+
253
+ {/* ── TL;DR ── */}
254
+ <div style={S.tldr}>
255
+ <div style={S.tldrLabel}>TL;DR</div>
256
+ <span style={S.tldrLead}>I am the Designer that builds.</span>
257
+ Simplicity is my style. I make intricate experiences as easy as they are elegant. Specialized in building and scaling design systems that bridge design and engineering — translating complexity into clarity and measurable growth.
258
+ </div>
259
+
260
+ {/* ── Impact Stats ── */}
261
+ <div style={{ ...S.section }}>
262
+ <SectionHeading>Impact at a Glance</SectionHeading>
263
+ <div style={S.statsRow}>
264
+ <div style={S.stat}>
265
+ <div style={S.statValue}>$5.6B+</div>
266
+ <div style={S.statLabel}>Trading Volume</div>
267
+ </div>
268
+ <div style={S.stat}>
269
+ <div style={S.statValue}>50+</div>
270
+ <div style={S.statLabel}>Products Shipped</div>
271
+ </div>
272
+ <div style={S.stat}>
273
+ <div style={S.statValue}>24K+</div>
274
+ <div style={S.statLabel}>Monthly Active Users</div>
275
+ </div>
276
+ </div>
277
+ <p style={{ fontSize: 13, color: "var(--win95-text-disabled)" }}>
278
+ 6+ years leading design across SaaS, Web3, FinTech, healthcare, and e-commerce. Cut design-engineering handoff time by 80% with an automated design-to-code pipeline, and design iteration time by 60%+ for enterprise clients.
279
+ </p>
280
+ </div>
281
+
282
+ {/* ── Experience ── */}
283
+ <div style={S.section}>
284
+ <SectionHeading>Experience</SectionHeading>
285
+
286
+ <div style={S.jobSpacer}>
287
+ <div style={S.jobHeader}>
288
+ <div style={S.jobTitle}>Lead Product Designer — Parcl</div>
289
+ <div style={S.jobMeta}>Jun 2022 – Present<br />Remote · FinTech / Real Estate</div>
290
+ </div>
291
+ <Bullet>
292
+ Architected Parcl&apos;s unified multi-brand design system powering both <strong>app.parcl.co</strong> (DeFi perpetuals: $5.6B+ total volume, $25M+ TVL, 700K+ point participants, 24K+ MAU) and <strong>parcl.co</strong> (consumer real estate investing platform) — with advanced theming, WCAG accessibility, and tokenized component architecture.
293
+ </Bullet>
294
+ <Bullet>
295
+ Translated complex DeFi mechanics into intuitive, high-performing UX driving adoption across institutional traders, retail investors, and automated bot users.
296
+ </Bullet>
297
+ <Bullet>
298
+ Engineered an automated design-to-code pipeline leveraging <strong>Figma Tokens, Tailwind, and Cursor</strong> to generate production-ready React components with full visual parity — cutting handoff time by <strong>80%</strong> and creating a shared design language across FE and BE teams.
299
+ </Bullet>
300
+ <Bullet>
301
+ Partnered cross-functionally with founders, PMs, and engineers to shape product strategy, evolve brand systems, and launch ecosystem features aligned with long-term liquidity and growth objectives.
302
+ </Bullet>
303
+ </div>
304
+
305
+ <div>
306
+ <div style={S.jobHeader}>
307
+ <div style={S.jobTitle}>Lead UX/UI & Product Design Consultant</div>
308
+ <div style={S.jobMeta}>Oct 2019 – Jun 2022<br />Nashville, TN · Contract</div>
309
+ </div>
310
+ <div style={S.jobSubtitle}>Atiba Agency & Independent — SaaS, Healthcare, Logistics, Public Sector</div>
311
+ <Bullet>
312
+ Led end-to-end design for <strong>45+ web and mobile products</strong> across industries — owning discovery, IA, prototyping, delivery, and launch.
313
+ </Bullet>
314
+ <Bullet>
315
+ Built scalable enterprise-grade design systems for <strong>Johnson Controls, Fortified Data, Hashed Health, and RJ Young</strong> — cutting design iteration time by <strong>60%+</strong> via atomic architecture and reusable component libraries.
316
+ </Bullet>
317
+ <Bullet>
318
+ Modernized legacy products through front-end design and implementation, driving accessibility, usability, and engineering efficiency.
319
+ </Bullet>
320
+ <Bullet>
321
+ Drove digital transformation initiatives by aligning user research, business KPIs, and UX strategy to deliver measurable ROI and long-term product adoption.
322
+ </Bullet>
323
+ </div>
324
+ </div>
325
+
326
+ {/* ── Skills ── */}
327
+ <div style={S.section}>
328
+ <SectionHeading>Skills</SectionHeading>
329
+
330
+ <div style={S.skillGroup}>
331
+ <div style={S.skillGroupLabel}>Design & Systems</div>
332
+ <div style={S.tagRow}>
333
+ {["Product Design", "UX/UI Strategy", "Design System Architecture", "Design Tokenization", "Accessibility (WCAG)", "Information Architecture", "Rapid Prototyping"].map(s => <Tag key={s}>{s}</Tag>)}
334
+ </div>
335
+ </div>
336
+
337
+ <div style={S.skillGroup}>
338
+ <div style={S.skillGroupLabel}>Leadership & Strategy</div>
339
+ <div style={S.tagRow}>
340
+ {["Cross-Functional Collaboration", "Systems Thinking", "Growth & Brand Strategy", "Product-Led Design", "Mentoring Designers"].map(s => <Tag key={s}>{s}</Tag>)}
341
+ </div>
342
+ </div>
343
+
344
+ <div style={S.skillGroup}>
345
+ <div style={S.skillGroupLabel}>Technical</div>
346
+ <div style={S.tagRow}>
347
+ {["Cursor", "Claude Code", "Figma", "Figma Tokens", "Tailwind CSS", "React", "TypeScript", "Framer", "Framer Motion", "Storybook", "Webflow", "Notion", "GitHub"].map(s => <Tag key={s}>{s}</Tag>)}
348
+ </div>
349
+ </div>
350
+ </div>
351
+
352
+ {/* ── Education & Speaking ── */}
353
+ <div style={S.section}>
354
+ <SectionHeading>Education & Recognition</SectionHeading>
355
+ <div style={{ marginBottom: 14 }}>
356
+ <div style={{ fontWeight: 600, fontSize: 13, marginBottom: 2 }}>B.S. Interactive Media Studies & Entrepreneurship</div>
357
+ <div style={{ fontSize: 12, color: "var(--win95-text-disabled)" }}>Miami University · Oxford, OH</div>
358
+ </div>
359
+ <div>
360
+ <div style={{ fontWeight: 600, fontSize: 13, marginBottom: 4 }}>Work Featured In</div>
361
+ <div style={{ fontSize: 12, color: "var(--win95-text-disabled)", lineHeight: 1.8 }}>
362
+ SQL Bits Conference (2022) · Breakpoint (2022, 2023, 2024)
363
+ </div>
364
+ </div>
365
+ </div>
366
+
367
+ {/* ── Philosophy ── */}
368
+ <div style={S.sectionLast}>
369
+ <SectionHeading>Philosophy</SectionHeading>
370
+ <blockquote style={S.quote}>
371
+ Design, at its core, is alchemy — turning the mundane into the magnetic. I don&apos;t just craft visuals; I weave ideas into experiences that captivate, provoke, and endure. Simplicity isn&apos;t just elegant — it&apos;s the secret weapon that makes every design profoundly effective.
372
+ </blockquote>
373
+ </div>
374
+
375
+ </div>
376
+ </div>
377
+ );
378
+ }