diff --git a/.htaccess b/.htaccess index 46b00c5..f984f93 100644 --- a/.htaccess +++ b/.htaccess @@ -9,6 +9,12 @@ RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)/$ /$1 [L,R=301] +# Portfolio index +RewriteRule ^portfolio$ /portfolio.php [L,QSA] + +# Portfolio case study pages: /portfolio/{slug} → portfolio-page.php +RewriteRule ^portfolio/([a-z0-9\-]+)$ /portfolio-page.php?slug=$1 [L,QSA] + # Security headers Header set X-Content-Type-Options "nosniff" diff --git a/.idea/php.xml b/.idea/php.xml index 2a84403..a955a9c 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -15,6 +15,7 @@ + diff --git a/LocalValetDriver.php b/LocalValetDriver.php new file mode 100644 index 0000000..fc63881 --- /dev/null +++ b/LocalValetDriver.php @@ -0,0 +1,31 @@ +servePhpFile($sitePath, '/portfolio.php'); + } + + // /portfolio/{slug} → portfolio-page.php?slug={slug} + if (preg_match('#^portfolio/([a-z0-9-]+)$#', $path, $m)) { + $_GET['slug'] = $m[1]; + return $this->servePhpFile($sitePath, '/portfolio-page.php'); + } + + return parent::frontControllerPath($sitePath, $siteName, $uri); + } + + private function servePhpFile(string $sitePath, string $file): string + { + $_SERVER['SCRIPT_FILENAME'] = $sitePath . $file; + $_SERVER['SCRIPT_NAME'] = $file; + $_SERVER['DOCUMENT_ROOT'] = $sitePath; + + return $sitePath . $file; + } +} diff --git a/portfolio/index.full.php b/_portfolio/index.full.php similarity index 100% rename from portfolio/index.full.php rename to _portfolio/index.full.php diff --git a/portfolio/index.php b/_portfolio/index.php similarity index 100% rename from portfolio/index.php rename to _portfolio/index.php diff --git a/_portfolio/lhbeng/index.php b/_portfolio/lhbeng/index.php new file mode 100644 index 0000000..49474ee --- /dev/null +++ b/_portfolio/lhbeng/index.php @@ -0,0 +1,85 @@ + + +
+ +
+
+ +
+
+

+ Full website redesign with a simple content manager — so the team can update their portfolio, staff profiles, and job listings without needing a developer every time. Clean, modern layout that reflects the scale and quality of their structural engineering work. +

+
+
+ +
+

Screenshots

+
+ +
+ +
+
+
+
+ + + +
+ +
+
+
+ LHB Engineering — Homepage +
+
+
+
+ +
+ +
+ +
+ +
+ Content Manager +

A full-featured CMS lets the team manage portfolio items, team profiles, and job listings without touching code. Day-to-day updates handled entirely in-house.

+
+
+
+ + + +
+ /admin +
+ LHB Engineering — CMS admin panel +
+
+ +
+
+ +
+

Execution

+
+ +
+
+ +
+
+

+ Built a full redesign for LHB Engineering, replacing their outdated site with a clean, modern layout that better reflects the scale and quality of their work. The new site is fast, fully responsive, and structured so visitors can quickly find services, past projects, and contact details. Alongside the redesign, a custom PHP/MySQL CMS gives the team full control over content — no developer needed for day-to-day updates. +

+
+
+ +
+ + diff --git a/_portfolio/project/index.php b/_portfolio/project/index.php new file mode 100644 index 0000000..9e522de --- /dev/null +++ b/_portfolio/project/index.php @@ -0,0 +1,132 @@ + + +
+ +
+
+ +
+
+

+ Thompson Service Centre needed more than a website — they needed a digital presence that matched 25 years of earned trust. We built a high-fidelity landing page that puts credibility front and centre: a bold hero section, a trust bar loaded with real credentials, and service cards that communicate competence without the usual garage-site clichés. +

+
+
+ +
+

Screenshots

+
+ +
+ +
+
+
+
+ + + +
+ +
+
+
+ Thompson Service Centre — Homepage +
+
+
+
+ +
+ +
+ +
+ +
+ Vehicle Lookup +

Registration plate lookup pulls vehicle details instantly — reducing form friction and building user confidence from the first interaction.

+
+
+
+ + + +
+ /book +
+ Thompson Service Centre — vehicle lookup step +
+
+ +
+ Booking Form +

A clean, single-column booking form with service selection and date picker. Designed for speed on mobile — no unnecessary steps, no dead ends.

+
+
+
+ + + +
+ /book +
+ Thompson Service Centre — booking confirmation step +
+
+ +
+
+ +
+

Execution

+
+ +
+
+ +
+
+

+ Built with vanilla HTML, Tailwind CSS v4, and GSAP-powered scroll animations, the page loads fast and feels premium on every device. The design system — rooted in Workshop Navy and Safety Orange — draws from real automotive heritage rather than off-the-shelf templates. +

+
+
+ +
+ + diff --git a/_portfolio/thompson/index.php b/_portfolio/thompson/index.php new file mode 100644 index 0000000..838be5f --- /dev/null +++ b/_portfolio/thompson/index.php @@ -0,0 +1,101 @@ + + +
+ +
+
+ +
+
+

+ Thompson Service Centre needed more than a website — they needed a digital presence that matched 25 years of earned trust. We built a high-fidelity landing page that puts credibility front and centre: a bold hero section, a trust bar loaded with real credentials, and service cards that communicate competence without the usual garage-site clichés. +

+
+
+ +
+

Screenshots

+
+ +
+ +
+
+
+
+ + + +
+ +
+
+
+ Thompson Service Centre — Homepage +
+
+
+
+ +
+ +
+ +
+ +
+ Vehicle Lookup +

Registration plate lookup pulls vehicle details instantly — reducing form friction and building user confidence from the first interaction.

+
+
+
+ + + +
+ /book +
+ Thompson Service Centre — vehicle lookup step +
+
+ +
+ Booking Form +

A clean, single-column booking form with service selection and date picker. Designed for speed on mobile — no unnecessary steps, no dead ends.

+
+
+
+ + + +
+ /book +
+ Thompson Service Centre — booking confirmation step +
+
+ +
+
+ +
+

Execution

+
+ +
+
+ +
+
+

+ Built with vanilla HTML, Tailwind CSS v4, and GSAP-powered scroll animations, the page loads fast and feels premium on every device. The design system — rooted in Workshop Navy and Safety Orange — draws from real automotive heritage rather than off-the-shelf templates. +

+
+
+ +
+ + diff --git a/css/portfolio.css b/css/portfolio.css index b7109c1..e579a75 100644 --- a/css/portfolio.css +++ b/css/portfolio.css @@ -1,392 +1,427 @@ -/* ======================================== - PORTFOLIO — extends style.css only - ======================================== */ - -.nav-links a.active { - color: var(--accent); - text-decoration: underline; +/* ── CASE STUDY HERO ─────────────────────────────── */ +.hero--cs { + height: auto; + min-height: 0; + padding-top: 7rem; } -/* ======================================== - PORTFOLIO GRID — 3-col card index - ======================================== */ - -.portfolio-grid { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 2rem; -} - -/* — Project card — */ - -.project-card { - display: flex; - flex-direction: column; - background: var(--black); - border: 4px solid var(--black); - box-shadow: 8px 8px 0 var(--black); - color: var(--white); - text-decoration: none; - transition: transform 0.1s, box-shadow 0.1s; -} - -.project-card:hover { - transform: translate(-2px, -2px); - box-shadow: 8px 8px 0 var(--accent); -} - -.project-card--wip { - opacity: 0.45; - pointer-events: none; -} - -/* — Thumbnail — */ - -.project-card__thumb { - position: relative; - aspect-ratio: 4 / 3; - background: var(--grey-light); - overflow: hidden; -} - -.project-card__thumb img { - width: 100%; - height: 100%; - object-fit: cover; - display: block; -} - -.project-card__label { - position: absolute; - top: 0; - left: 0; - font-family: var(--mono); - font-size: 0.75rem; - font-weight: 700; - color: var(--accent); - background: var(--black); - padding: 0.3rem 0.6rem; - z-index: 1; - letter-spacing: 0.04em; -} - -/* — Body — */ - -.project-card__body { - padding: 1.25rem; - display: flex; - flex-direction: column; - flex: 1; - border-top: 2px solid var(--grey-dark); -} - -.project-card__title { - font-family: var(--mono); - font-size: 0.9rem; - font-weight: 800; - text-transform: uppercase; - letter-spacing: 0.02em; - color: var(--white); - margin-bottom: 0.6rem; - line-height: 1.3; -} - -.project-card__desc { - font-family: var(--sans); - font-size: 0.85rem; - font-weight: 400; - color: var(--grey-text); - line-height: 1.5; - flex: 1; -} - -/* — Footer row — */ - -.project-card__footer { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 1.25rem; -} - -.project-card__year { - font-family: var(--mono); - font-size: 0.65rem; - color: var(--grey-text); - letter-spacing: 0.06em; -} - -.project-card__arrow { - display: flex; - align-items: center; - justify-content: center; - width: 2rem; - height: 2rem; - border: 2px solid var(--accent); - font-family: var(--mono); - font-size: 1rem; - color: var(--accent); - flex-shrink: 0; - transition: background 0.1s, color 0.1s; -} - -.project-card:hover .project-card__arrow { - background: var(--accent); - color: var(--black); -} - -/* — Tags — */ - -.tags-row { - display: flex; - gap: 0.5rem; - flex-wrap: wrap; - margin-top: 0.5rem; -} - -.tag { - font-family: var(--mono); - font-size: 0.62rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.08em; - padding: 0.3rem 0.65rem; - background: var(--black); - border: 2px solid var(--grey-dark); - color: var(--grey-text); -} - -/* — Case study breadcrumb bar — */ - -.cs-breadcrumb { - display: flex; - justify-content: space-between; - align-items: center; - background: var(--black); - border: 4px solid var(--black); - box-shadow: 8px 8px 0 var(--black); - padding: 0.75rem 1.25rem; - margin-bottom: 2rem; -} - -.cs-breadcrumb-label { - font-family: var(--mono); - font-size: 0.75rem; - font-weight: 700; - color: var(--accent); - letter-spacing: 0.04em; -} - -/* — Case study inline meta bar — */ - -.cs-meta-bar { - list-style: none; - display: flex; - flex-direction: column; - gap: 0; - padding: 0.75rem 1rem; - background: var(--grey-dark); - border-left: 6px solid var(--grey-text); - /*border-top: 4px solid var(--grey-text);*/ - margin-top: 1.5rem; - max-width: clamp(380px, 55vw, 750px); - box-shadow: var(--shadow); -} - -.cs-meta-bar li { - font-family: var(--mono); - font-size: 0.8rem; - font-weight: 400; - color: var(--grey-text); - line-height: 1.8; -} - -/* — Case study back link — */ - -.cs-back { - display: inline-block; - font-family: var(--mono); - font-size: 0.75rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.08em; - color: var(--accent); - text-decoration: none; - margin-bottom: 1.5rem; - transition: opacity 0.1s; -} - -.cs-back:hover { - opacity: 0.7; -} - -.cs-back--lg { - font-size: 0.85rem; - display: block; - margin-bottom: 2rem; -} - -/* — Case study meta grid — */ - -.cs-meta-grid { - grid-template-columns: repeat(4, 1fr); -} - -.cs-meta-grid .service-item h3 { - font-size: 0.95rem; - text-transform: none; - font-weight: 500; - color: var(--white); -} - -/* — Browser chrome — */ - -.browser-chrome { - display: flex; - align-items: center; - gap: 1rem; - padding: 0.6rem 1rem; - background: var(--black); - border: var(--border-orange); - border-bottom: none; -} - -.browser-chrome--sm { - padding: 0.45rem 0.75rem; - margin-bottom: 1rem; -} - -.browser-dots { - display: flex; - gap: 0.35rem; - flex-shrink: 0; -} - -.browser-dots span { - width: 0.5rem; - height: 0.5rem; - border-radius: 50%; - display: block; -} - -.browser-dots span:first-child { - background: #ff5f57; -} - -.browser-dots span:nth-child(2) { - background: #febc2e; -} - -.browser-dots span:nth-child(3) { - background: #28c840; -} - -.browser-url { - font-family: var(--mono); - font-size: 0.65rem; - color: var(--grey-text); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -/* — Screenshots — */ - -.screenshot-hero-wrap { - width: 70%; - margin: 0 auto; - border: var(--border-orange); - box-shadow: var(--shadow-orange); -} - -.screenshot-hero-wrap .browser-chrome { - border: none; - border-bottom: 2px solid var(--accent); -} - -.screenshot-hero-scroll { - position: relative; - max-height: 600px; - overflow-y: scroll; - scrollbar-width: thin; - scrollbar-color: var(--accent) #1a1a1a; -} - -.screenshot-hero-scroll--no-hint::before { - display: none; -} - -.screenshot-hero-scroll::before { - content: '↓ scroll to view whole page'; - position: sticky; - top: 0; - display: flex; - justify-content: center; - align-items: flex-start; - padding-top: 1.5rem; - height: 120px; - margin-bottom: -120px; - background: linear-gradient(to top, transparent, rgba(10, 10, 10, 0.9)); - font-family: var(--mono); - font-size: 1rem; - letter-spacing: 0.12em; - color: var(--white); - pointer-events: none; - z-index: 1; -} - -.screenshot-hero { - display: block; - width: 100%; -} - -.screenshot-card { - padding: 2rem; -} - -.screenshot-card__desc { - font-family: var(--sans); - font-size: 0.85rem; - color: var(--grey); - margin: 0.4rem 0 1.25rem; - line-height: 1.5; -} - -.screenshot-screen { - display: block; - width: 100%; - border: var(--border-orange); - border-top: none; -} - -/* ======================================== - RESPONSIVE - ======================================== */ - -@media (max-width: 960px) { - .cs-meta-grid { - grid-template-columns: repeat(2, 1fr); - } +.hero--cs .hero-headline .line2 { + font-size: 7.5vw; + margin-left: 0; + text-transform: none; + letter-spacing: 0; + padding-top: 0.5rem; } @media (max-width: 768px) { - .portfolio-grid { - grid-template-columns: repeat(2, 1fr); - gap: 1.25rem; - } - - .screenshot-hero-wrap { - width: 100%; - } - - .cs-meta-grid { - grid-template-columns: 1fr; - } + .hero--cs .hero-headline .line2 { font-size: 8vw; } } -@media (max-width: 480px) { - .portfolio-grid { - grid-template-columns: 1fr; - gap: 1rem; - } +/* ── PORTFOLIO GRID ──────────────────────────────── */ +.portfolio-section { + padding: 6rem 2.5rem; +} + +.portfolio-header { + border-top: 1px solid var(--dark); + padding-top: 1rem; + margin-bottom: 3rem; +} + +.portfolio-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 2.5rem; +} + +.project-card { + display: flex; + flex-direction: column; + cursor: pointer; +} + +.project-card--wip { + opacity: 0.45; + pointer-events: none; +} + +/* — Thumbnail — */ +.project-card__thumb { + position: relative; + aspect-ratio: 4 / 3; + overflow: hidden; + background: var(--dark); +} + +.project-card__thumb img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + transition: transform 0.45s cubic-bezier(0.165, 0.84, 0.44, 1); +} + +.project-card:hover .project-card__thumb img { + transform: scale(1.05); +} + +.project-card__label { + position: absolute; + top: 0; left: 0; + font-family: monospace; + font-size: 0.65rem; + font-weight: 400; + color: var(--bg); + background: var(--accent); + padding: 0.3rem 0.75rem; + z-index: 2; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.project-card__badge { + position: absolute; + top: 1rem; right: 1rem; + background: var(--neon); + color: var(--dark); + font-family: var(--general); + font-size: 0.65rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.06em; + padding: 6px 12px; + opacity: 0; + z-index: 2; + transition: opacity 0.25s ease; +} + +.project-card:hover .project-card__badge { opacity: 1; } + +/* — Body — */ +.project-card__body { + padding: 1.25rem 0; + border-bottom: 1px solid var(--dark); + display: flex; + flex-direction: column; + flex: 1; + transition: border-color 0.2s ease; +} + +.project-card:hover .project-card__body { + border-color: var(--accent); +} + +.project-card__title { + font-family: var(--clash); + font-size: clamp(1.4rem, 2.2vw, 2rem); + font-weight: 700; + text-transform: uppercase; + letter-spacing: -0.02em; + line-height: 1; + color: var(--dark); + margin-bottom: 0.6rem; +} + +.project-card__desc { + font-family: var(--general); + font-size: 1rem; + color: var(--mid); + line-height: 1.6; + flex: 1; +} + +/* — Footer row — */ +.project-card__footer { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 1rem; +} + +.project-card__year { + font-family: var(--general); + font-size: 0.65rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--mid); +} + +.project-card__arrow { + display: flex; + align-items: center; + justify-content: center; + width: 2rem; height: 2rem; + border: 1px solid var(--accent); + font-size: 1rem; + color: var(--accent); + flex-shrink: 0; + transition: background 0.15s, color 0.15s; +} + +.project-card:hover .project-card__arrow { + background: var(--accent); + color: var(--bg); +} + +/* ── CONTACT CTA (portfolio page variant) ─────────── */ +.contact-section--slim { + padding: 5rem 2.5rem 4.5rem; +} + +/* ── META BAR ────────────────────────────────────── */ +.meta-bar { + border-top: 1px solid var(--dark); + border-bottom: 1px solid var(--dark); + padding: 0 2.5rem; + display: grid; + grid-template-columns: repeat(4, 1fr); + background: var(--bg); +} + +.meta-col { + padding: 2rem 0; + border-right: 1px solid rgba(27,14,13,0.15); +} +.meta-col:last-child { border-right: none; } +.meta-col:not(:first-child) { padding-left: 2rem; } + +.meta-col-label { + font-family: var(--general); + font-size: 0.6rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.15em; + color: var(--mid); + opacity: 0.65; + margin-bottom: 0.5rem; + display: block; +} + +.meta-col-value { + font-family: var(--clash); + font-size: 1rem; + font-weight: 500; + text-transform: uppercase; + color: var(--dark); + letter-spacing: -0.01em; +} + +/* ── CS OVERVIEW ─────────────────────────────────── */ +.cs-overview { + display: grid; + grid-template-columns: repeat(12, 1fr); + gap: 2rem; + padding: 6rem 2.5rem; +} + +.cs-overview-label { + grid-column: span 4; + border-top: 1px solid var(--dark); + padding-top: 1rem; +} + +.cs-overview-body { + grid-column: span 8; + border-top: 1px solid var(--dark); + padding-top: 1rem; +} + +.cs-overview-text { + font-family: var(--general); + font-size: clamp(1rem, 1.4vw, 1.25rem); + color: var(--mid); + line-height: 1.6; +} + +/* ── SCREENSHOTS ─────────────────────────────────── */ +.screenshots-section { + padding: 5rem 2.5rem; +} + +.screenshots-label { + border-top: 1px solid var(--dark); + padding-top: 1rem; + margin-bottom: 3rem; +} + +/* Browser chrome frame */ +.browser-frame { + background: var(--dark); + border-radius: 0; +} + +.browser-bar { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem 1.25rem; + border-bottom: 1px solid rgba(255,255,255,0.06); +} + +.browser-dots { + display: flex; + gap: 6px; + flex-shrink: 0; +} + +.browser-dot { + width: 8px; + height: 8px; + border-radius: 50%; +} +.browser-dot--red { background: var(--accent); } +.browser-dot--beige { background: var(--bg); } +.browser-dot--green { background: var(--neon); } + +.browser-url { + font-family: var(--general); + font-size: 0.7rem; + color: rgba(227,226,222,0.4); + letter-spacing: 0.02em; +} + +.browser-frame img { + width: 100%; + display: block; +} + +.browser-scroll-wrap { + position: relative; +} + +.browser-scroll-wrap::after { + content: 'SCROLL ↓'; + position: absolute; + top: 0; left: 0; right: 0; + height: 80px; + background: linear-gradient(to bottom, rgba(27,14,13,0.9), transparent); + display: flex; + justify-content: center; + align-items: flex-start; + padding-top: 1rem; + font-family: monospace; + font-size: 0.65rem; + letter-spacing: 0.25em; + text-shadow: 0 0 8px var(--neon); + color: var(--neon); + pointer-events: none; + z-index: 2; +} + +.browser-scroll { + max-height: 560px; + overflow-y: scroll; + scrollbar-width: thin; + scrollbar-color: var(--accent) var(--dark); +} + +/* Full-width hero screenshot */ +.screenshot-hero { + margin-bottom: 4rem; +} + +/* 2-col screenshot grid */ +.screenshot-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 2rem; +} + +.screenshot-card-label { + font-family: var(--general); + font-size: 0.7rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.12em; + color: var(--mid); + margin-bottom: 0.5rem; + display: block; +} + +.screenshot-card-desc { + font-family: var(--general); + font-size: 0.9rem; + color: var(--mid); + line-height: 1.6; + margin-bottom: 1.25rem; +} + +/* ── PROJECT NAV ─────────────────────────────────── */ +.project-nav { + background: var(--dark); + display: flex; + justify-content: space-between; + align-items: center; + padding: 3rem 2.5rem; + border-top: 1px solid rgba(227,226,222,0.1); +} + +.project-nav-link { + font-family: var(--clash); + font-size: 0.85rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--bg); + position: relative; + transition: color 0.2s; +} +.project-nav-link::after { + content: ''; + position: absolute; + bottom: -4px; left: 0; + width: 100%; height: 2px; + background: var(--neon); + transform: scaleX(0); + transform-origin: right; + transition: transform 0.25s cubic-bezier(0.165, 0.84, 0.44, 1); +} +.project-nav-link:hover::after { + transform: scaleX(1); + transform-origin: left; +} +.project-nav-link:hover { color: var(--neon); } + +/* ── RESPONSIVE ─────────────────────────────────── */ +@media (max-width: 960px) { + .cs-overview { grid-template-columns: 1fr; gap: 1rem; } + .cs-overview-label, + .cs-overview-body { grid-column: span 1; } + .meta-bar { grid-template-columns: repeat(2, 1fr); } + .meta-col:nth-child(2) { border-right: none; } + .meta-col:nth-child(3) { border-right: 1px solid rgba(27,14,13,0.15); } +} + +@media (max-width: 768px) { + .portfolio-section { padding: 4rem 1.5rem; } + + .portfolio-grid { + grid-template-columns: 1fr; + gap: 3rem; + } + + .meta-bar { + grid-template-columns: repeat(2, 1fr); + padding: 0 1.5rem; + } + .meta-col:nth-child(2) { border-right: none; } + .meta-col:nth-child(3) { + border-right: 1px solid rgba(27,14,13,0.15); + border-top: 1px solid rgba(27,14,13,0.15); + padding-left: 0; + } + .meta-col:nth-child(4) { border-top: 1px solid rgba(27,14,13,0.15); } + + .cs-overview { padding: 4rem 1.5rem; } + + .screenshots-section { padding: 4rem 1.5rem; } + .screenshot-grid { grid-template-columns: 1fr; } + + .project-nav { + padding: 2rem 1.5rem; + flex-direction: column; + gap: 1.5rem; + align-items: flex-start; + } } diff --git a/css/style.css b/css/style.css index a0187b5..c5980cb 100644 --- a/css/style.css +++ b/css/style.css @@ -1,427 +1,606 @@ -/* ======================================== - RESET & BASE (ORANGE & GRAY BRUTALIST) - ======================================== */ - -*, *::before, *::after { - margin: 0; - padding: 0; - box-sizing: border-box; -} +*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } :root { - /* Industrial Palette */ - --black: #000000; - --white: #ffffff; - --grey-dark: #2b2d30; /* Slate Concrete */ - --grey-light: #3f4246; /* Industrial Surface */ - --grey-text: #b0b0b0; - --accent: #ff5500; /* Safety Orange */ - --mono: 'JetBrains Mono', monospace; - --sans: 'DM Sans', sans-serif; - - /* Brutalist Variables */ - --border-thick: 4px solid var(--black); - --border-orange: 4px solid var(--accent); - --shadow: 8px 8px 0px var(--black); - --shadow-orange: 8px 8px 0px var(--accent); + --bg: #E3E2DE; + --dark: #1B0E0D; + --mid: #61220F; + --accent: #C72A09; + --neon: #31EF07; + --border: #D9D9D9; + --clash: 'Clash Grotesk', sans-serif; + --general: 'General Sans', sans-serif; } -html { - scroll-behavior: smooth; - font-size: 16px; -} +html { scroll-behavior: smooth; } body { - font-family: var(--sans); - background: var(--grey-dark); - color: var(--white); - line-height: 1.2; /* Tighter brutalist spacing */ - -webkit-font-smoothing: antialiased; - padding: 10px; /* Outer frame */ + font-family: var(--general); + background: var(--bg); + color: var(--dark); + overflow-x: hidden; + -webkit-font-smoothing: antialiased; } -a { - color: var(--white); - text-decoration: none; - transition: all 0.1s ease; +a { color: inherit; text-decoration: none; } + +::selection { background: var(--accent); color: var(--bg); } + +/* ── NOISE ──────────────────────────────────────── */ +.noise { + position: fixed; + inset: 0; + pointer-events: none; + z-index: 50; + mix-blend-mode: multiply; + opacity: 0.08; } -::selection { - background: var(--accent); - color: var(--black); -} - -/* ======================================== - NAV - THE CONTROL PANEL - ======================================== */ - +/* ── NAV ────────────────────────────────────────── */ .nav { - position: fixed; - top: 20px; - left: 20px; - right: 20px; - z-index: 100; - display: flex; - justify-content: space-between; - align-items: center; - padding: 1rem 2rem; - background: var(--black); - border: var(--border-orange); - box-shadow: var(--shadow); + position: fixed; + top: 0; left: 0; right: 0; + z-index: 40; + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.5rem 2.5rem; + mix-blend-mode: difference; + color: var(--bg); + transition: background 0.2s ease; +} + +.nav--scrolled { + mix-blend-mode: normal; + background: rgba(27,14,13,0.9); } .nav-left { - display: flex; - align-items: center; - gap: 1.25rem; + display: flex; + align-items: center; + gap: 2rem; } .nav-logo { - font-family: var(--mono); - font-weight: 800; - font-size: 1.25rem; - letter-spacing: -0.02em; - color: var(--accent); + font-family: var(--clash); + font-weight: 700; + font-size: 1.5rem; + letter-spacing: -0.02em; + text-transform: uppercase; } .nav-back { - font-family: var(--mono); - font-size: 1rem; - color: var(--white); - opacity: 0.5; - transition: opacity 0.15s; + font-family: var(--general); + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.08em; + position: relative; } - -.nav-back:hover { - opacity: 1; +.nav-back::after { + content: ''; + position: absolute; + bottom: -3px; left: 0; + width: 100%; height: 2px; + background: var(--neon); + transform: scaleX(0); + transform-origin: right; + transition: transform 0.25s cubic-bezier(0.165, 0.84, 0.44, 1); +} +.nav-back:hover::after { + transform: scaleX(1); + transform-origin: left; } .nav-links { - display: flex; - gap: 2rem; - font-family: var(--mono); - font-size: 0.8rem; - text-transform: uppercase; - font-weight: 700; + display: flex; + gap: 2.5rem; + font-family: var(--general); + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.08em; } -.nav-links a:hover { - color: var(--accent); - text-decoration: underline; +.nav-link { + position: relative; +} +.nav-link::after { + content: ''; + position: absolute; + bottom: -3px; left: 0; + width: 100%; height: 2px; + background: var(--neon); + transform: scaleX(0); + transform-origin: right; + transition: transform 0.25s cubic-bezier(0.165, 0.84, 0.44, 1); +} +.nav-link:hover::after, +.nav-link--active::after { + transform: scaleX(1); + transform-origin: left; } -/* ======================================== - HERO - IMPACT ZONE - ======================================== */ +.nav-cta { + font-family: var(--general); + font-size: 0.75rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.08em; +} +/* ── HERO ───────────────────────────────────────── */ .hero { - min-height: 60vh; - display: flex; - flex-direction: column; - justify-content: center; - padding: 7rem 3rem 2rem; - border: var(--border-thick); - background: var(--grey-light); - margin-bottom: 2rem; - box-shadow: var(--shadow); + position: relative; + height: 70vh; + max-height: 650px; + min-height: 520px; + background-color: var(--dark); + background-image: radial-gradient(circle, rgba(227,226,222,0.055) 1px, transparent 1px); + background-size: 48px 48px; + display: flex; + flex-direction: column; + justify-content: flex-end; + overflow: hidden; } -.hero .section-label { - background: var(--accent); - color: var(--black); - font-size: 0.85rem; - padding: 4px 12px; - margin-bottom: 2rem; - width: fit-content; +.hero::before { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(ellipse at 50% 100%, transparent 40%, rgba(27,14,13,0.55) 100%); + pointer-events: none; + z-index: 1; } -.hero h1 { - font-family: var(--mono); - font-size: clamp(3rem, 10vw, 8rem); - font-weight: 800; - line-height: 0.85; - letter-spacing: -0.05em; - margin-bottom: 2rem; - text-transform: uppercase; - color: var(--white); +.hero-content { + position: relative; + z-index: 2; + padding: 0 2.5rem 3rem; } -.hero h1 .h1-sub { - font-size: 0.6em; +.hero-divider { + width: 100%; + height: 1px; + background: rgba(227,226,222,0.25); + margin-bottom: 1.5rem; } -.hero-sub { - font-size: 1.25rem; - color: var(--white); - background: var(--black); - padding: 1rem; - max-width: clamp(280px, 40vw, 550px); - margin-bottom: 2rem; - border-left: 8px solid var(--accent); +.hero-meta-row { + display: flex; + justify-content: space-between; + align-items: flex-end; + gap: 1rem; + margin-bottom: 0.25rem; } -/* ======================================== - BUTTONS - INDUSTRIAL ACTUATORS - ======================================== */ - -.hero-cta { - display: flex; - gap: 1.5rem; - align-items: center; +.hero-meta { + font-family: var(--general); + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 0.15em; + color: rgba(227,226,222,0.5); + display: flex; + flex-direction: column; + gap: 0.2rem; } -.btn { - display: inline-block; - font-family: var(--mono); - font-size: 0.9rem; - font-weight: 900; - text-transform: uppercase; - padding: 1.2rem 2.5rem; - background: var(--accent); - color: var(--black); - border: var(--border-thick); - box-shadow: 4px 4px 0px var(--black); - transition: transform 0.1s, box-shadow 0.1s; +.hero-cta-btn { + display: inline-block; + font-family: var(--clash); + font-size: 0.85rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.06em; + padding: 1rem 2rem; + background: var(--accent); + color: var(--bg); + transition: background 0.2s, color 0.2s; +} +.hero-cta-btn:hover { + background: var(--neon); + color: var(--dark); } -.btn:hover { - transform: translate(-2px, -2px); - box-shadow: 7px 7px 0px var(--black); - background: var(--white); +.hero-headline { + font-family: var(--clash); + font-weight: 700; + font-size: 13.5vw; + line-height: 0.75; + letter-spacing: -0.05em; + text-transform: uppercase; + margin-top: 2.25rem; + padding: 0 1rem; } -.btn-ghost { - background: transparent; - border-color: var(--white); - color: var(--white); -} - -.btn-ghost:hover { - background: var(--white); - color: var(--black); -} - -/* ======================================== - SECTIONS - MODULE CONTAINERS - ======================================== */ - -.section { - padding: 3rem 2.5rem; - background: var(--grey-light); - border: var(--border-thick); - margin-bottom: 2rem; - box-shadow: var(--shadow); +.hero-headline .line1 { + display: block; + color: var(--accent); +} +.hero-headline .line2 { + display: block; + color: var(--bg); + margin-left: 20vw; } +/* ── SECTION LABEL ───────────────────────────────── */ .section-label { - font-family: var(--mono); - font-size: 0.8rem; - text-transform: uppercase; - background: var(--black); - color: var(--accent); - padding: 5px 15px; - display: inline-block; - margin-bottom: 3rem; - font-weight: 900; + font-family: monospace; + font-size: 0.75rem; + font-weight: 400; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--mid); } -.large-text { - font-size: 1.75rem; - line-height: 1.3; - margin-bottom: 2rem; - font-weight: 700; - color: var(--accent); +/* ── MANIFESTO / ABOUT ──────────────────────────── */ +.manifesto { + display: grid; + grid-template-columns: repeat(12, 1fr); + gap: 2rem; + padding: 6rem 2.5rem; } -.section-content p { - color: var(--white); - margin-bottom: 1.5rem; - line-height: 1.6; - font-size: 1.1rem; +.manifesto-label-col { + grid-column: span 4; + border-top: 1px solid var(--dark); + padding-top: 1rem; } -/* ======================================== - SERVICES - LIST ROWS - ======================================== */ - -.services-section { - background: var(--grey-light); - padding: 3rem 2.5rem 0; - margin-bottom: 2rem; - box-shadow: var(--shadow); +.manifesto-text-col { + grid-column: span 8; + border-top: 1px solid var(--dark); + padding-top: 1rem; } -.services-section-label { - font-family: var(--mono); - font-size: 0.8rem; - text-transform: uppercase; - background: var(--black); - color: var(--accent); - padding: 5px 15px; - display: inline-block; - margin-bottom: 2rem; - font-weight: 900; - border: 1px solid rgba(255,255,255,0.15); +.manifesto-text { + font-family: var(--clash); + font-size: clamp(1.75rem, 3.2vw, 3rem); + font-weight: 500; + line-height: 1.15; + text-transform: uppercase; + text-indent: 3rem; } -.services-heading { - font-family: 'Archivo Black', sans-serif; - font-size: clamp(4rem, 13vw, 13rem); - font-weight: 900; - text-transform: uppercase; - color: #ffffff; - line-height: 0.88; - letter-spacing: -0.02em; - margin-bottom: 3rem; +.manifesto-text .hl { color: var(--mid); } + +/* ── CATEGORY DIVIDER ───────────────────────────── */ +.category-divider { + width: 100%; + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); + padding: 0 2.5rem; + overflow: hidden; } -.services-list { - border-top: 1px solid rgba(255,255,255,0.2); +.category-divider h2 { + font-family: var(--clash); + font-size: 12vw; + font-weight: 700; + letter-spacing: -0.04em; + line-height: 0.95; + color: var(--mid); + text-transform: uppercase; + padding: 0.2rem 0; +} + +/* ── SERVICES ───────────────────────────────────── */ +.services { + border-top: 1px solid rgba(27,14,13,0.15); + padding: 0 2.5rem; } .service-row { - display: flex; - align-items: center; - padding: 2.5rem 1rem; - margin: 0 -1rem; - border-bottom: 1px solid rgba(255,255,255,0.2); - cursor: default; - overflow: hidden; - transition: background 0.15s ease; + display: flex; + align-items: flex-start; + gap: 2rem; + border-bottom: 1px solid rgba(27,14,13,0.15); + padding: 2.5rem 0; + margin: 0 -2.5rem; + padding-left: 2.5rem; + padding-right: 2.5rem; + position: relative; + overflow: hidden; + cursor: default; + transition: background 0.15s ease; } -.service-row:hover { - background: var(--black); +.service-num { + font-family: var(--general); + font-size: 0.9rem; + font-weight: 700; + color: var(--accent); + padding-top: 0.8rem; + flex-shrink: 0; + width: 3.5rem; } -.service-row-body { - display: flex; - align-items: flex-start; - gap: 1.75rem; - flex: 1; - min-width: 0; +.service-body { flex: 1; min-width: 0; } + +.service-title { + font-family: var(--clash); + font-size: clamp(1.75rem, 3.2vw, 3rem); + font-weight: 500; + line-height: 1.15; + text-transform: uppercase; + text-indent: 3rem; + color: var(--dark); + margin-bottom: 1.1rem; } -.service-row-num { - font-family: var(--mono); - font-size: 1rem; - font-weight: 700; - color: #ff4d00; - padding-top: 0.6rem; - white-space: nowrap; - flex-shrink: 0; +.service-row--alt .service-title > span { + background-color: var(--accent); + color: var(--bg); + -webkit-box-decoration-break: clone; + box-decoration-break: clone; + padding: 0.04em 0.15em; + display: inline; } -.service-row-content { - flex: 1; - min-width: 0; -} - -.service-row-title { - font-family: var(--mono), serif; - font-size: clamp(3rem, 7vw, 8rem); - font-weight: 900; - text-transform: uppercase; - color: #ffffff; - line-height: 0.92; - letter-spacing: -0.02em; - margin-bottom: 1.25rem; - transition: color 0.15s ease; -} - -.service-row:hover .service-row-title { - color: var(--accent); -} - -.service-row-tags { - display: flex; - gap: 0.6rem; - flex-wrap: wrap; +.service-tags { + display: flex; + gap: 0.5rem; + flex-wrap: wrap; } .service-tag { - font-family: var(--mono); - font-size: 0.7rem; - text-transform: uppercase; - color: #ffffff; - border: 1px solid rgba(255,255,255,0.35); - border-radius: 100px; - padding: 5px 14px; - letter-spacing: 0.06em; - white-space: nowrap; + font-family: var(--general); + font-size: 0.65rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.07em; + padding: 4px 12px; + border: 1px solid rgba(27,14,13,0.25); + border-radius: 100px; + color: var(--mid); } - -@media (max-width: 768px) { - .services-section { - padding: 2rem 1.5rem 0; - } - - .service-row { - padding: 2rem 0; - } - - .service-row-num { - padding-top: 0.3rem; - } - - .service-row-arrow { - display: none; - } - - .service-row-title { - font-size: clamp(2rem, 7vw, 3rem); - } +.service-badge { + position: absolute; + top: 2.25rem; + right: 2.5rem; + background: var(--neon); + color: var(--dark); + font-family: var(--general); + font-size: 0.65rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.06em; + padding: 6px 12px; + opacity: 0; } -/* ======================================== - CONTACT & FOOTER - ======================================== */ +/* ── CONTACT ────────────────────────────────────── */ +.contact-section { + background: var(--dark); + padding: 7rem 2.5rem 6rem; + position: relative; + overflow: hidden; +} + +.contact-section::before { + content: ''; + position: absolute; + inset: 0; + background-image: radial-gradient(circle, rgba(227,226,222,0.04) 1px, transparent 1px); + background-size: 48px 48px; + pointer-events: none; +} + +.contact-inner { position: relative; z-index: 1; } + +.contact-section .section-label { + color: rgba(227,226,222,0.35); + display: block; + margin-bottom: 3rem; +} + +.contact-headline { + font-family: var(--clash); + font-size: clamp(3rem, 6vw, 6rem); + font-weight: 700; + text-transform: uppercase; + color: var(--bg); + line-height: 0.88; + letter-spacing: -0.04em; + margin-bottom: 3rem; +} +.contact-headline .accent { color: var(--accent); } .contact-email { - display: block; - font-family: var(--mono); - font-size: clamp(1.2rem, 5vw, 3.5rem); - font-weight: 900; - margin: 2rem 0; - color: var(--white); - text-decoration: underline; - text-decoration-color: var(--accent); - text-underline-offset: 8px; + display: block; + font-family: var(--clash); + font-size: clamp(1.5rem, 3.5vw, 3.75rem); + font-weight: 700; + color: var(--bg); + letter-spacing: -0.02em; + margin-bottom: 3rem; + width: fit-content; + position: relative; +} +.contact-email::after { + content: ''; + position: absolute; + bottom: -4px; left: 0; + width: 100%; height: 2px; + background: var(--neon); + transform: scaleX(0); + transform-origin: right; + transition: transform 0.35s cubic-bezier(0.165, 0.84, 0.44, 1); +} +.contact-email:hover::after { + transform: scaleX(1); + transform-origin: left; } -.contact-email:hover { - color: var(--accent); - background: var(--black); +.contact-meta { + font-family: var(--general); + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.12em; + color: rgba(227,226,222,0.35); + display: flex; + align-items: center; + gap: 1.25rem; } +.contact-meta .dot { opacity: 0.4; } +/* ── FOOTER ─────────────────────────────────────── */ .footer { - background: var(--black); - border: var(--border-orange); - color: var(--grey-text); - padding: 2rem 3rem; - margin-top: 4rem; + background: var(--bg); + border-top: 1px solid var(--dark); + padding: 4.5rem 2.5rem 0; } -/* ======================================== - RESPONSIVE - ======================================== */ +.footer-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 3rem; + margin-bottom: 4.5rem; +} + +.footer-heading { + font-family: var(--clash); + font-size: 1.1rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: -0.01em; + margin-bottom: 1.25rem; +} + +.footer-links { + list-style: none; + display: flex; + flex-direction: column; + gap: 0.65rem; +} +.footer-links a { + font-family: var(--general); + font-size: 0.875rem; + color: var(--mid); + transition: color 0.15s; +} +.footer-links a:hover { color: var(--accent); } + +.footer-address { + font-family: var(--general); + font-size: 0.875rem; + color: var(--mid); + line-height: 1.8; + font-style: normal; +} +.footer-address a { font-weight: 700; } +.footer-address a:hover { color: var(--accent); } + +.footer-cta { + background: var(--dark); + padding: 1.5rem; +} +.footer-cta label { + display: block; + font-family: var(--general); + font-size: 0.65rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.15em; + color: var(--bg); + margin-bottom: 1rem; +} +.footer-input-row { + display: flex; + align-items: center; + border-bottom: 1px solid rgba(227,226,222,0.4); + gap: 0.5rem; +} +.footer-input-row input { + background: transparent; + border: none; + outline: none; + font-family: var(--general); + font-size: 0.8rem; + color: var(--bg); + text-transform: uppercase; + width: 100%; + padding: 0.5rem 0; +} +.footer-input-row input::placeholder { color: rgba(227,226,222,0.25); } +.footer-input-row button { + background: none; + border: none; + cursor: pointer; + font-family: var(--general); + font-size: 0.75rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--neon); + padding: 0.5rem 0; + white-space: nowrap; + transition: color 0.15s; +} +.footer-input-row button:hover { color: var(--bg); } + +.footer-bottom { + border-top: 1px solid var(--border); + display: flex; + justify-content: space-between; + align-items: flex-end; + padding-top: 1.5rem; +} + +.footer-ghost { + font-family: var(--clash); + font-size: 8vw; + font-weight: 700; + text-transform: uppercase; + color: var(--border); + line-height: 1; + letter-spacing: -0.04em; + user-select: none; + pointer-events: none; +} + +.footer-legal { + font-family: var(--general); + font-size: 0.7rem; + color: var(--mid); + padding-bottom: 0.3rem; +} + +/* ── RESPONSIVE ─────────────────────────────────── */ +@media (max-width: 960px) { + .manifesto { grid-template-columns: 1fr; gap: 1rem; } + .manifesto-label-col, + .manifesto-text-col { grid-column: span 1; } + .footer-grid { grid-template-columns: repeat(2, 1fr); } +} @media (max-width: 768px) { - .nav { - top: 10px; left: 10px; right: 10px; - padding: 1rem; - } + .nav { padding: 1.25rem 1.5rem; } + .nav-links { display: none; } - .hero, .section { - padding: 6rem 1.5rem 3rem; - } + .hero-content { padding: 0 1.5rem 2.5rem; } + .hero-meta-row { + flex-direction: column; + align-items: flex-start; + gap: 1rem; + margin-bottom: 1.5rem; + } + .hero-headline { font-size: 12vw; } + .hero-headline .line2 { margin-left: 5vw; } - .services-grid { - grid-template-columns: 1fr; - } + .manifesto { padding: 4rem 1.5rem; } + .manifesto-text { font-size: 1.75rem; text-indent: 1.5rem; } - .service-item { - padding: 2rem; - } -} \ No newline at end of file + .category-divider { padding: 0 1.5rem; } + + .services { padding: 0 1.5rem; } + .service-row { margin: 0 -1.5rem; padding: 2rem 1.5rem; } + .service-badge { right: 1.5rem; } + .service-title { font-size: clamp(1.5rem, 5vw, 2.5rem); text-indent: 1.5rem; } + + .contact-section { padding: 4rem 1.5rem; } + + .footer { padding: 3rem 1.5rem 0; } + .footer-grid { grid-template-columns: 1fr; gap: 2rem; } + .footer-ghost { font-size: 16vw; } +} diff --git a/data/projects.php b/data/projects.php index 944c922..7823386 100644 --- a/data/projects.php +++ b/data/projects.php @@ -17,22 +17,64 @@ $projects = [ 'domain' => 'thompsonservicecentre.co.uk', 'page_title' => 'Thompson Service Centre — Case Study', 'page_desc' => 'How we built a trust-first digital presence for a 25-year Peterborough garage.', + 'overview' => 'Thompson Service Centre needed more than a website — they needed a digital presence that matched 25 years of earned trust. We built a high-fidelity landing page that puts credibility front and centre: a bold hero section, a trust bar loaded with real credentials, and service cards that communicate competence without the usual garage-site clichés.', + 'execution' => 'Built with vanilla HTML, Tailwind CSS v4, and GSAP-powered scroll animations, the page loads fast and feels premium on every device. The design system — rooted in Workshop Navy and Safety Orange — draws from real automotive heritage rather than off-the-shelf templates.', + 'hero_img' => '/img/thompson/hero.jpg', + 'screenshots' => [ + [ + 'label' => 'Booking Flow', + 'items' => [ + [ + 'label' => 'Vehicle Lookup', + 'desc' => 'Registration plate lookup pulls vehicle details instantly — reducing form friction and building user confidence from the first interaction.', + 'img' => '/img/thompson/booking-lookup.jpg', + 'alt' => 'Thompson Service Centre — vehicle lookup step', + 'url_suffix' => '/book', + ], + [ + 'label' => 'Booking Form', + 'desc' => 'A clean, single-column booking form with service selection and date picker. Designed for speed on mobile — no unnecessary steps, no dead ends.', + 'img' => '/img/thompson/booking-confirm.jpg', + 'alt' => 'Thompson Service Centre — booking confirmation step', + 'url_suffix' => '/book', + ], + ], + ], + ], ], + 'lhbeng' => [ 'num' => '02', 'code' => 'WEB_DEV', - 'title' => 'LHB Eng', + 'title' => 'LHB Engineering', 'desc' => 'Structural Engineers designing projects that build strong communities.', 'year' => '2022', 'thumb' => '/img/lhbeng/hero.jpg', 'live' => true, 'h1' => ['LHB', 'Lynch, Harrison & Brumleve, Inc.'], 'sub' => 'Website Redesign · 2022', - 'stack' => 'HTML · CSS', + 'stack' => 'HTML · CSS · PHP · MySQL', 'location' => 'LHB Eng, Indianapolis', 'domain' => 'lhb-eng.com', 'page_title' => 'LHB Engineering — Case Study', 'page_desc' => 'Full website redesign for LHB Engineering with a self-service CMS for portfolio, team, and job listings.', + 'overview' => 'Full website redesign with a simple content manager — so the team can update their portfolio, staff profiles, and job listings without needing a developer every time. Clean, modern layout that reflects the scale and quality of their structural engineering work.', + 'execution' => 'Built a full redesign for LHB Engineering, replacing their outdated site with a clean, modern layout that better reflects the scale and quality of their work. The new site is fast, fully responsive, and structured so visitors can quickly find services, past projects, and contact details. Alongside the redesign, a custom PHP/MySQL CMS gives the team full control over content — no developer needed for day-to-day updates.', + 'hero_img' => '/img/lhbeng/hero.jpg', + 'screenshots' => [ + [ + 'label' => 'Website CMS', + 'items' => [ + [ + 'label' => 'Content Manager', + 'desc' => 'A full-featured CMS lets the team manage portfolio items, team profiles, and job listings without touching code. Day-to-day updates handled entirely in-house.', + 'img' => '/img/lhbeng/admin.jpg', + 'alt' => 'LHB Engineering — CMS admin panel', + 'url_suffix' => '/admin', + ], + ], + ], + ], ], ]; diff --git a/includes/cs_footer.php b/includes/cs_footer.php index 43a81c8..a5a4daa 100644 --- a/includes/cs_footer.php +++ b/includes/cs_footer.php @@ -1,12 +1,22 @@ + 0 ? $slugs[$idx - 1] : null; +$next = $idx < count($slugs) - 1 ? $slugs[$idx + 1] : null; +?> -
- -
- ← Back to All Work -

Got a project in mind?

- Let's Talk → -
-
+ - diff --git a/includes/cs_header.php b/includes/cs_header.php index 38e9d1d..53bc004 100644 --- a/includes/cs_header.php +++ b/includes/cs_header.php @@ -3,13 +3,8 @@ /* * Case Study Header Partial * ───────────────────────────────────────────────────────────────── - * Requires the following variables set by the calling page BEFORE - * requiring this file: - * + * Requires the following variable set by the calling page: * $cs_slug string Key into $projects, e.g. 'thompson' - * - * Everything else ($title, $description, hero content) is read from - * $projects[$cs_slug] in data/projects.php. * ───────────────────────────────────────────────────────────────── */ @@ -18,21 +13,42 @@ require __DIR__ . '/../data/projects.php'; $p = $projects[$cs_slug]; $title = $p['page_title']; $description = $p['page_desc']; +$nav_back = ['url' => '/portfolio', 'label' => '← Portfolio']; +//$nav_cta = ['url' => 'https://' . $p['domain'], 'label' => 'Visit Site →']; require __DIR__ . '/header.php'; ?> -
- ← All Work - [ / ] -
- -
- -


-

-
    -
  • -
  • -
  • -
+
+
+
+
+
+ / WEB_DEV · + +
+
+

+ + +

+
+ +
+
+ Client + +
+
+ Year + +
+
+ Stack + +
+
+ Location + +
+
diff --git a/includes/footer.php b/includes/footer.php index b59e51e..6f87715 100644 --- a/includes/footer.php +++ b/includes/footer.php @@ -1,7 +1,47 @@ -
- © Ovidiu Ungureanu - Built with PHP, no JS frameworks were harmed. -
+ + + diff --git a/includes/header.php b/includes/header.php index 6c3e6a9..a2aefd2 100644 --- a/includes/header.php +++ b/includes/header.php @@ -1,32 +1,50 @@ + - - - <?php echo htmlspecialchars($title); ?> - - - - - - - - + + + <?php echo htmlspecialchars($title); ?> + + + + + + + - - + + + diff --git a/index.php b/index.php index 6bcf3cf..34b2ace 100644 --- a/index.php +++ b/index.php @@ -1,107 +1,124 @@
- -

Ovidiu
Ungureanu

-

I build web applications that work.
PHP, MySQL, clean code, no nonsense.

-
- View Work → - Let's Talk +
+
+
+
+ Web Developer — Peterborough, UK + I build web applications that work. + Available for freelance +
+ Let's Talk → +
+

+ CleanCode + Studio +

-
- -
-

I'm a web developer based in Peterborough.

-

I build websites and online tools for small businesses — things like booking systems, customer dashboards, and the bits that make your day-to-day easier to manage.

-

Whether you need a fresh website, an online booking page for your garage, or a simple system to keep track of jobs and customers — I'll build it quickly, affordably, and without the jargon.

-
-
+
-
- -
-
-
- (01) -
-

Website Design
& Development

-
- Design - Development - Responsive -
-
-
-
-
-
- (02) -
-

Custom Tools
& Systems

-
- PHP - MySQL - Custom Builds -
-
-
-
-
-
- (03) -
-

Booking &
Scheduling

-
- Bookings - Automation - Small Business -
-
-
-
-
-
- (04) -
-

Ongoing Support
& Updates

-
- Maintenance - Performance - Support -
-
-
-
-
-
- - - - - - - - - -
- -
-

Got a project in mind?

- hello@uovidiu.com -
- Peterborough, UK - · - Available for freelance + +
+
+
-
-
+
+

+ I build websites and online tools for small businesses + — booking systems, customer dashboards. - +
Fast, affordable, and built to last. + Built for businesses that need something real. +

+
+ + + +
+

Services

+
+ + +
+ +
+ (01) +
+

Website Design
& Development

+
+ Design + Development + Responsive +
+
+ Enquire → +
+ +
+ (02) +
+

Custom Tools
& Systems

+
+ PHP + MySQL + Custom Builds +
+
+ Enquire → +
+ +
+ (03) +
+

Booking &
Scheduling

+
+ Bookings + Automation + Small Business +
+
+ Enquire → +
+ +
+ (04) +
+

Ongoing Support
& Updates

+
+ Maintenance + Performance + Support +
+
+ Enquire → +
+ +
+ + +
+
+ +

+ Got a project
+ in mind? +

+ hello@uovidiu.com +
+ Peterborough, UK + · + Available for freelance +
+
+
+ +
+ + diff --git a/portfolio-page.php b/portfolio-page.php new file mode 100644 index 0000000..c2bd962 --- /dev/null +++ b/portfolio-page.php @@ -0,0 +1,151 @@ + '/portfolio', 'label' => '← Portfolio']; +//if (!empty($p['domain'])) { +// $nav_cta = ['url' => 'https://' . $p['domain'], 'label' => 'Visit Site →']; +//} + +require __DIR__ . '/includes/header.php'; +?> + +
+
+
+
+
+ / · + + +
+
+

+ + +

+
+
+ +
+ + +
+
+ Client + +
+
+ Year + +
+
+ Stack + +
+
+ + +
+
+ +
+
+

+
+
+ + +
+

Screenshots

+
+ + +
+ + +
+
+
+
+ + + +
+ +
+
+
+ <?= htmlspecialchars($p['title']) ?> — Homepage +
+
+
+
+ + + +
+ +
+ +
+ +
+ +

+
+
+
+ + + +
+ +
+ <?= htmlspecialchars($shot['alt']) ?> +
+
+ +
+ + + +
+ + +
+

Execution

+
+ + +
+
+ +
+
+

+
+
+ + + + +
+ + diff --git a/portfolio.php b/portfolio.php index c76e1c5..360e941 100644 --- a/portfolio.php +++ b/portfolio.php @@ -1,71 +1,71 @@
- -

Selected
Work

-

Client projects and builds.

+
+
+
+
+ Portfolio — Projects + Web Design & Development +
+ ← Back to Home +
+

+ Selected + Work +

+
-
- - -
- -
-

Got a project in mind?

- Let's Talk → -
-
+
- +
+
+ +

+ Got a project
+ in mind? +

+ hello@uovidiu.com +
+
+ + + + diff --git a/portfolio/_template/index.php b/portfolio/_template/index.php deleted file mode 100644 index 7e1da8b..0000000 --- a/portfolio/_template/index.php +++ /dev/null @@ -1,118 +0,0 @@ - - - - -
- - -
-

TODO What problem did the client have and what did you build to fix it? Keep it to 2–3 sentences. Be specific — name the feature, the constraint, the outcome.

-
- -
-
-
- -
- -
-
- TODO Client Name — TODO description -
-
-
- - - - -
- -
- -
- TODO Feature label -

TODO Feature description.

-
-
- -
- /TODO-path -
- TODO description -
- -
- TODO Feature label -

TODO Feature description.

-
-
- -
- /TODO-path -
- TODO description -
- -
-
- - - - -
- -
-

TODO Anything worth saying about how it was built — a technical decision, a performance win, something that made the difference. If you can't think of anything specific, delete this section.

-
-
- - diff --git a/portfolio/lhbeng/index.php b/portfolio/lhbeng/index.php deleted file mode 100644 index f42d865..0000000 --- a/portfolio/lhbeng/index.php +++ /dev/null @@ -1,64 +0,0 @@ - - - -
- -
-

Full website redesign with a simple content manager — so you can update your portfolio, team profiles, and job listings yourself without needing a developer every time.

-
-
-
-
- -
- -
- LHB Engineering — Homepage -
-
- - - -
- -
- -
- Website CMS -

Full-fledged CMS for content.

-
-
- -
- /admin -
- LHB Engineering CMS admin panel -
- -
-
- - - -
- -
-

Built a full redesign for LHB Engineering, replacing their outdated site with a clean, modern layout that better reflects the scale and quality of their work.
The new site is fast, fully responsive, and structured so visitors can quickly find services, past projects, and contact details.
- Alongside the redesign, I built a simple CMS so the team can manage their portfolio, staff profiles, and job listings themselves — no developer needed for day-to-day updates.

-
-
- - diff --git a/portfolio/thompson/index.php b/portfolio/thompson/index.php deleted file mode 100644 index 9b7821b..0000000 --- a/portfolio/thompson/index.php +++ /dev/null @@ -1,81 +0,0 @@ - - -
- - -
-

Thompson Service Centre needed more than a website — they needed a digital presence that matched 25 years of earned trust. We built a high-fidelity - landing page that puts credibility front and center: a bold hero section, a trust bar loaded with real credentials, and service cards that - communicate competence without the usual garage-site clichés. Every element was designed to make a first-time visitor feel like they'd already found - their mechanic.

-
- -
-
-
- -
- -
-
- Thompson Service Centre — Homepage -
-
-
- -
- -
-
- Vehicle Lookup -

Enter your registration plate to pull vehicle details automatically.

-
-
- -
- /book -
- Vehicle registration lookup -
-
- Booking Form -

Confirm your vehicle and fill in the booking details in one clean step.

-
-
- -
- /book -
- Vehicle confirmed and booking form -
-
-
- -
- -
-

Built with vanilla HTML, Tailwind CSS v4, and GSAP-powered scroll animations, the page loads fast and feels premium on every device. The design - system — rooted in Workshop Navy and Safety Orange — draws from real automotive heritage rather than off-the-shelf templates. Noise overlays, - layered gradients, and spring-eased micro-interactions give it a tactile warmth that sets it apart from every other garage site in the postcode.

-
-
- -