Move portfolio case studies to data-driven template system and archive old individual files
This commit is contained in:
@@ -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
|
||||
<IfModule mod_headers.c>
|
||||
Header set X-Content-Type-Options "nosniff"
|
||||
|
||||
1
.idea/php.xml
generated
1
.idea/php.xml
generated
@@ -15,6 +15,7 @@
|
||||
<phpcs_by_interpreter asDefaultInterpreter="true" interpreter_id="7e064064-f569-4fa2-87dd-a1bd0db5798f" timeout="30000" />
|
||||
</phpcs_settings>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.4" />
|
||||
<component name="PhpStan">
|
||||
<PhpStan_settings>
|
||||
<phpstan_by_interpreter asDefaultInterpreter="true" interpreter_id="7e064064-f569-4fa2-87dd-a1bd0db5798f" timeout="60000" />
|
||||
|
||||
31
LocalValetDriver.php
Normal file
31
LocalValetDriver.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
class LocalValetDriver extends \Valet\Drivers\BasicValetDriver
|
||||
{
|
||||
public function frontControllerPath(string $sitePath, string $siteName, string $uri): ?string
|
||||
{
|
||||
$path = trim(parse_url($uri, PHP_URL_PATH), '/');
|
||||
|
||||
// /portfolio → portfolio.php
|
||||
if ($path === 'portfolio') {
|
||||
return $this->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;
|
||||
}
|
||||
}
|
||||
85
_portfolio/lhbeng/index.php
Normal file
85
_portfolio/lhbeng/index.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
$cs_slug = 'lhbeng';
|
||||
require __DIR__ . '/../../includes/cs_header.php';
|
||||
?>
|
||||
|
||||
<main>
|
||||
|
||||
<section class="cs-overview">
|
||||
<div class="cs-overview-label">
|
||||
<span class="section-label">Project Overview</span>
|
||||
</div>
|
||||
<div class="cs-overview-body">
|
||||
<p class="cs-overview-text">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="category-divider">
|
||||
<h2>Screenshots</h2>
|
||||
</div>
|
||||
|
||||
<section class="screenshots-section">
|
||||
|
||||
<div class="screenshot-hero">
|
||||
<div class="browser-frame">
|
||||
<div class="browser-bar">
|
||||
<div class="browser-dots">
|
||||
<span class="browser-dot browser-dot--red"></span>
|
||||
<span class="browser-dot browser-dot--beige"></span>
|
||||
<span class="browser-dot browser-dot--green"></span>
|
||||
</div>
|
||||
<span class="browser-url"><?php echo htmlspecialchars($p['domain']); ?></span>
|
||||
</div>
|
||||
<div class="browser-scroll-wrap">
|
||||
<div class="browser-scroll">
|
||||
<img src="/img/lhbeng/hero.jpg" alt="LHB Engineering — Homepage">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="screenshots-label">
|
||||
<span class="section-label">Website CMS</span>
|
||||
</div>
|
||||
|
||||
<div class="screenshot-grid">
|
||||
|
||||
<div>
|
||||
<span class="screenshot-card-label">Content Manager</span>
|
||||
<p class="screenshot-card-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.</p>
|
||||
<div class="browser-frame">
|
||||
<div class="browser-bar">
|
||||
<div class="browser-dots">
|
||||
<span class="browser-dot browser-dot--red"></span>
|
||||
<span class="browser-dot browser-dot--beige"></span>
|
||||
<span class="browser-dot browser-dot--green"></span>
|
||||
</div>
|
||||
<span class="browser-url"><?php echo htmlspecialchars($p['domain']); ?>/admin</span>
|
||||
</div>
|
||||
<img src="/img/lhbeng/admin.jpg" alt="LHB Engineering — CMS admin panel">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="category-divider">
|
||||
<h2>Execution</h2>
|
||||
</div>
|
||||
|
||||
<section class="cs-overview">
|
||||
<div class="cs-overview-label">
|
||||
<span class="section-label">Craft & Execution</span>
|
||||
</div>
|
||||
<div class="cs-overview-body">
|
||||
<p class="cs-overview-text">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<?php require __DIR__ . '/../../includes/cs_footer.php'; ?>
|
||||
132
_portfolio/project/index.php
Normal file
132
_portfolio/project/index.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* ═══════════════════════════════════════════════════════════════════
|
||||
* CASE STUDY TEMPLATE
|
||||
* ═══════════════════════════════════════════════════════════════════
|
||||
*
|
||||
* HOW TO USE
|
||||
* ──────────
|
||||
* 1. Copy this folder to portfolio/{slug}/
|
||||
* 2. Fill in every TODO below — nothing should say TODO when live
|
||||
* 3. Add an entry to $projects in data/projects.php (including page_title, page_desc)
|
||||
* 4. Drop screenshots into /img/{slug}/
|
||||
*
|
||||
* IMAGES
|
||||
* ──────
|
||||
* hero.jpg — full-page screenshot (used as grid thumbnail too)
|
||||
* feature-1.jpg — first feature / flow screenshot
|
||||
* feature-2.jpg — second feature / flow screenshot
|
||||
* Add more as needed — duplicate the 2-col screenshot section below.
|
||||
*
|
||||
* SECTIONS (delete what you don't need)
|
||||
* ──────────────────────────────────────
|
||||
* · Project Overview — always include
|
||||
* · Hero screenshot — always include
|
||||
* · Feature section — include if there's a flow / feature worth showing
|
||||
* · Craft & Execution — include if the build has something worth saying
|
||||
* · CTA — always include, comes from cs_footer.php
|
||||
* ═══════════════════════════════════════════════════════════════════
|
||||
*/
|
||||
|
||||
// ── Set the slug — everything else lives in data/projects.php ─────
|
||||
$cs_slug = 'project'; // e.g. 'northgate'
|
||||
require __DIR__ . '/../../includes/cs_header.php';
|
||||
?>
|
||||
|
||||
<main>
|
||||
|
||||
<section class="cs-overview">
|
||||
<div class="cs-overview-label">
|
||||
<span class="section-label">Project Overview</span>
|
||||
</div>
|
||||
<div class="cs-overview-body">
|
||||
<p class="cs-overview-text">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="category-divider">
|
||||
<h2>Screenshots</h2>
|
||||
</div>
|
||||
|
||||
<section class="screenshots-section">
|
||||
|
||||
<div class="screenshot-hero">
|
||||
<div class="browser-frame">
|
||||
<div class="browser-bar">
|
||||
<div class="browser-dots">
|
||||
<span class="browser-dot browser-dot--red"></span>
|
||||
<span class="browser-dot browser-dot--beige"></span>
|
||||
<span class="browser-dot browser-dot--green"></span>
|
||||
</div>
|
||||
<span class="browser-url"><?php echo htmlspecialchars($p['domain']); ?></span>
|
||||
</div>
|
||||
<div class="browser-scroll-wrap">
|
||||
<div class="browser-scroll">
|
||||
<img src="/img/thompson/hero.jpg" alt="Thompson Service Centre — Homepage">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="screenshots-label">
|
||||
<span class="section-label">Booking Flow</span>
|
||||
</div>
|
||||
|
||||
<div class="screenshot-grid">
|
||||
|
||||
<div>
|
||||
<span class="screenshot-card-label">Vehicle Lookup</span>
|
||||
<p class="screenshot-card-desc">Registration plate lookup pulls vehicle details instantly — reducing form friction and building user confidence from the first interaction.</p>
|
||||
<div class="browser-frame">
|
||||
<div class="browser-bar">
|
||||
<div class="browser-dots">
|
||||
<span class="browser-dot browser-dot--red"></span>
|
||||
<span class="browser-dot browser-dot--beige"></span>
|
||||
<span class="browser-dot browser-dot--green"></span>
|
||||
</div>
|
||||
<span class="browser-url"><?php echo htmlspecialchars($p['domain']); ?>/book</span>
|
||||
</div>
|
||||
<img src="/img/thompson/booking-lookup.jpg" alt="Thompson Service Centre — vehicle lookup step">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="screenshot-card-label">Booking Form</span>
|
||||
<p class="screenshot-card-desc">A clean, single-column booking form with service selection and date picker. Designed for speed on mobile — no unnecessary steps, no dead ends.</p>
|
||||
<div class="browser-frame">
|
||||
<div class="browser-bar">
|
||||
<div class="browser-dots">
|
||||
<span class="browser-dot browser-dot--red"></span>
|
||||
<span class="browser-dot browser-dot--beige"></span>
|
||||
<span class="browser-dot browser-dot--green"></span>
|
||||
</div>
|
||||
<span class="browser-url"><?php echo htmlspecialchars($p['domain']); ?>/book</span>
|
||||
</div>
|
||||
<img src="/img/thompson/booking-confirm.jpg" alt="Thompson Service Centre — booking confirmation step">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="category-divider">
|
||||
<h2>Execution</h2>
|
||||
</div>
|
||||
|
||||
<section class="cs-overview">
|
||||
<div class="cs-overview-label">
|
||||
<span class="section-label">Craft & Execution</span>
|
||||
</div>
|
||||
<div class="cs-overview-body">
|
||||
<p class="cs-overview-text">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<?php require __DIR__ . '/../../includes/cs_footer.php'; ?>
|
||||
101
_portfolio/thompson/index.php
Normal file
101
_portfolio/thompson/index.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
$cs_slug = 'thompson';
|
||||
require __DIR__ . '/../../includes/cs_header.php';
|
||||
?>
|
||||
|
||||
<main>
|
||||
|
||||
<section class="cs-overview">
|
||||
<div class="cs-overview-label">
|
||||
<span class="section-label">Project Overview</span>
|
||||
</div>
|
||||
<div class="cs-overview-body">
|
||||
<p class="cs-overview-text">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="category-divider">
|
||||
<h2>Screenshots</h2>
|
||||
</div>
|
||||
|
||||
<section class="screenshots-section">
|
||||
|
||||
<div class="screenshot-hero">
|
||||
<div class="browser-frame">
|
||||
<div class="browser-bar">
|
||||
<div class="browser-dots">
|
||||
<span class="browser-dot browser-dot--red"></span>
|
||||
<span class="browser-dot browser-dot--beige"></span>
|
||||
<span class="browser-dot browser-dot--green"></span>
|
||||
</div>
|
||||
<span class="browser-url"><?php echo htmlspecialchars($p['domain']); ?></span>
|
||||
</div>
|
||||
<div class="browser-scroll-wrap">
|
||||
<div class="browser-scroll">
|
||||
<img src="/img/thompson/hero.jpg" alt="Thompson Service Centre — Homepage">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="screenshots-label">
|
||||
<span class="section-label">Booking Flow</span>
|
||||
</div>
|
||||
|
||||
<div class="screenshot-grid">
|
||||
|
||||
<div>
|
||||
<span class="screenshot-card-label">Vehicle Lookup</span>
|
||||
<p class="screenshot-card-desc">Registration plate lookup pulls vehicle details instantly — reducing form friction and building user confidence from the first interaction.</p>
|
||||
<div class="browser-frame">
|
||||
<div class="browser-bar">
|
||||
<div class="browser-dots">
|
||||
<span class="browser-dot browser-dot--red"></span>
|
||||
<span class="browser-dot browser-dot--beige"></span>
|
||||
<span class="browser-dot browser-dot--green"></span>
|
||||
</div>
|
||||
<span class="browser-url"><?php echo htmlspecialchars($p['domain']); ?>/book</span>
|
||||
</div>
|
||||
<img src="/img/thompson/booking-lookup.jpg" alt="Thompson Service Centre — vehicle lookup step">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="screenshot-card-label">Booking Form</span>
|
||||
<p class="screenshot-card-desc">A clean, single-column booking form with service selection and date picker. Designed for speed on mobile — no unnecessary steps, no dead ends.</p>
|
||||
<div class="browser-frame">
|
||||
<div class="browser-bar">
|
||||
<div class="browser-dots">
|
||||
<span class="browser-dot browser-dot--red"></span>
|
||||
<span class="browser-dot browser-dot--beige"></span>
|
||||
<span class="browser-dot browser-dot--green"></span>
|
||||
</div>
|
||||
<span class="browser-url"><?php echo htmlspecialchars($p['domain']); ?>/book</span>
|
||||
</div>
|
||||
<img src="/img/thompson/booking-confirm.jpg" alt="Thompson Service Centre — booking confirmation step">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="category-divider">
|
||||
<h2>Execution</h2>
|
||||
</div>
|
||||
|
||||
<section class="cs-overview">
|
||||
<div class="cs-overview-label">
|
||||
<span class="section-label">Craft & Execution</span>
|
||||
</div>
|
||||
<div class="cs-overview-body">
|
||||
<p class="cs-overview-text">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<?php require __DIR__ . '/../../includes/cs_footer.php'; ?>
|
||||
@@ -1,38 +1,43 @@
|
||||
/* ========================================
|
||||
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
|
||||
======================================== */
|
||||
.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) {
|
||||
.hero--cs .hero-headline .line2 { font-size: 8vw; }
|
||||
}
|
||||
|
||||
/* ── 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(3, 1fr);
|
||||
gap: 2rem;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 2.5rem;
|
||||
}
|
||||
|
||||
/* — 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);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.project-card--wip {
|
||||
@@ -41,12 +46,11 @@
|
||||
}
|
||||
|
||||
/* — Thumbnail — */
|
||||
|
||||
.project-card__thumb {
|
||||
position: relative;
|
||||
aspect-ratio: 4 / 3;
|
||||
background: var(--grey-light);
|
||||
overflow: hidden;
|
||||
background: var(--dark);
|
||||
}
|
||||
|
||||
.project-card__thumb img {
|
||||
@@ -54,339 +58,370 @@
|
||||
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: 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;
|
||||
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;
|
||||
}
|
||||
|
||||
/* — Body — */
|
||||
.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;
|
||||
padding: 1.25rem 0;
|
||||
border-bottom: 1px solid var(--dark);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
border-top: 2px solid var(--grey-dark);
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.project-card:hover .project-card__body {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.project-card__title {
|
||||
font-family: var(--mono);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 800;
|
||||
font-family: var(--clash);
|
||||
font-size: clamp(1.4rem, 2.2vw, 2rem);
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.02em;
|
||||
color: var(--white);
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 1;
|
||||
color: var(--dark);
|
||||
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;
|
||||
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: 1.25rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.project-card__year {
|
||||
font-family: var(--mono);
|
||||
font-family: var(--general);
|
||||
font-size: 0.65rem;
|
||||
color: var(--grey-text);
|
||||
letter-spacing: 0.06em;
|
||||
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: 2px solid var(--accent);
|
||||
font-family: var(--mono);
|
||||
width: 2rem; height: 2rem;
|
||||
border: 1px solid var(--accent);
|
||||
font-size: 1rem;
|
||||
color: var(--accent);
|
||||
flex-shrink: 0;
|
||||
transition: background 0.1s, color 0.1s;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
}
|
||||
|
||||
.project-card:hover .project-card__arrow {
|
||||
background: var(--accent);
|
||||
color: var(--black);
|
||||
color: var(--bg);
|
||||
}
|
||||
|
||||
/* — Tags — */
|
||||
|
||||
.tags-row {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0.5rem;
|
||||
/* ── CONTACT CTA (portfolio page variant) ─────────── */
|
||||
.contact-section--slim {
|
||||
padding: 5rem 2.5rem 4.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 {
|
||||
/* ── 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);
|
||||
}
|
||||
|
||||
.cs-meta-grid .service-item h3 {
|
||||
font-size: 0.95rem;
|
||||
text-transform: none;
|
||||
.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;
|
||||
color: var(--white);
|
||||
text-transform: uppercase;
|
||||
color: var(--dark);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
/* — Browser chrome — */
|
||||
/* ── CS OVERVIEW ─────────────────────────────────── */
|
||||
.cs-overview {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
gap: 2rem;
|
||||
padding: 6rem 2.5rem;
|
||||
}
|
||||
|
||||
.browser-chrome {
|
||||
.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: 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;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem 1.25rem;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.06);
|
||||
}
|
||||
|
||||
.browser-dots {
|
||||
display: flex;
|
||||
gap: 0.35rem;
|
||||
gap: 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.browser-dots span {
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
.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-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 {
|
||||
.browser-scroll-wrap {
|
||||
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;
|
||||
.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: 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);
|
||||
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: 1;
|
||||
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 {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.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 {
|
||||
/* 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);
|
||||
gap: 1.25rem;
|
||||
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); }
|
||||
|
||||
.screenshot-hero-wrap {
|
||||
width: 100%;
|
||||
}
|
||||
.cs-overview { padding: 4rem 1.5rem; }
|
||||
|
||||
.cs-meta-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
.screenshots-section { padding: 4rem 1.5rem; }
|
||||
.screenshot-grid { grid-template-columns: 1fr; }
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.portfolio-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
.project-nav {
|
||||
padding: 2rem 1.5rem;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
829
css/style.css
829
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 */
|
||||
font-family: var(--general);
|
||||
background: var(--bg);
|
||||
color: var(--dark);
|
||||
overflow-x: hidden;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
padding: 10px; /* Outer frame */
|
||||
}
|
||||
|
||||
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;
|
||||
top: 0; left: 0; right: 0;
|
||||
z-index: 40;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1rem 2rem;
|
||||
background: var(--black);
|
||||
border: var(--border-orange);
|
||||
box-shadow: var(--shadow);
|
||||
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;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.nav-logo {
|
||||
font-family: var(--mono);
|
||||
font-weight: 800;
|
||||
font-size: 1.25rem;
|
||||
font-family: var(--clash);
|
||||
font-weight: 700;
|
||||
font-size: 1.5rem;
|
||||
letter-spacing: -0.02em;
|
||||
color: var(--accent);
|
||||
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;
|
||||
gap: 2.5rem;
|
||||
font-family: var(--general);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.nav-cta {
|
||||
font-family: var(--general);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
color: var(--accent);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
HERO - IMPACT ZONE
|
||||
======================================== */
|
||||
|
||||
/* ── HERO ───────────────────────────────────────── */
|
||||
.hero {
|
||||
min-height: 60vh;
|
||||
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: center;
|
||||
padding: 7rem 3rem 2rem;
|
||||
border: var(--border-thick);
|
||||
background: var(--grey-light);
|
||||
margin-bottom: 2rem;
|
||||
box-shadow: var(--shadow);
|
||||
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-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);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
BUTTONS - INDUSTRIAL ACTUATORS
|
||||
======================================== */
|
||||
|
||||
.hero-cta {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translate(-2px, -2px);
|
||||
box-shadow: 7px 7px 0px var(--black);
|
||||
background: var(--white);
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.large-text {
|
||||
font-size: 1.75rem;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 2rem;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.section-content p {
|
||||
color: var(--white);
|
||||
.hero-divider {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: rgba(227,226,222,0.25);
|
||||
margin-bottom: 1.5rem;
|
||||
line-height: 1.6;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
SERVICES - LIST ROWS
|
||||
======================================== */
|
||||
|
||||
.services-section {
|
||||
background: var(--grey-light);
|
||||
padding: 3rem 2.5rem 0;
|
||||
margin-bottom: 2rem;
|
||||
box-shadow: var(--shadow);
|
||||
.hero-meta-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.services-section-label {
|
||||
font-family: var(--mono);
|
||||
font-size: 0.8rem;
|
||||
.hero-meta {
|
||||
font-family: var(--general);
|
||||
font-size: 0.7rem;
|
||||
text-transform: uppercase;
|
||||
background: var(--black);
|
||||
color: var(--accent);
|
||||
padding: 5px 15px;
|
||||
letter-spacing: 0.15em;
|
||||
color: rgba(227,226,222,0.5);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.hero-cta-btn {
|
||||
display: inline-block;
|
||||
margin-bottom: 2rem;
|
||||
font-weight: 900;
|
||||
border: 1px solid rgba(255,255,255,0.15);
|
||||
}
|
||||
|
||||
.services-heading {
|
||||
font-family: 'Archivo Black', sans-serif;
|
||||
font-size: clamp(4rem, 13vw, 13rem);
|
||||
font-weight: 900;
|
||||
font-family: var(--clash);
|
||||
font-size: 0.85rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
color: #ffffff;
|
||||
line-height: 0.88;
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: 3rem;
|
||||
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);
|
||||
}
|
||||
|
||||
.services-list {
|
||||
border-top: 1px solid rgba(255,255,255,0.2);
|
||||
.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;
|
||||
}
|
||||
|
||||
.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: monospace;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
color: var(--mid);
|
||||
}
|
||||
|
||||
/* ── MANIFESTO / ABOUT ──────────────────────────── */
|
||||
.manifesto {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
gap: 2rem;
|
||||
padding: 6rem 2.5rem;
|
||||
}
|
||||
|
||||
.manifesto-label-col {
|
||||
grid-column: span 4;
|
||||
border-top: 1px solid var(--dark);
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.manifesto-text-col {
|
||||
grid-column: span 8;
|
||||
border-top: 1px solid var(--dark);
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.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;
|
||||
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-row-body {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 1.75rem;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.service-row-num {
|
||||
font-family: var(--mono);
|
||||
font-size: 1rem;
|
||||
.service-num {
|
||||
font-family: var(--general);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
color: #ff4d00;
|
||||
padding-top: 0.6rem;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.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);
|
||||
padding-top: 0.8rem;
|
||||
flex-shrink: 0;
|
||||
width: 3.5rem;
|
||||
}
|
||||
|
||||
.service-row-tags {
|
||||
.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--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-tags {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.service-tag {
|
||||
font-family: var(--mono);
|
||||
font-size: 0.7rem;
|
||||
font-family: var(--general);
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: #ffffff;
|
||||
border: 1px solid rgba(255,255,255,0.35);
|
||||
letter-spacing: 0.07em;
|
||||
padding: 4px 12px;
|
||||
border: 1px solid rgba(27,14,13,0.25);
|
||||
border-radius: 100px;
|
||||
padding: 5px 14px;
|
||||
color: var(--mid);
|
||||
}
|
||||
|
||||
.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;
|
||||
white-space: nowrap;
|
||||
padding: 6px 12px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.services-section {
|
||||
padding: 2rem 1.5rem 0;
|
||||
/* ── CONTACT ────────────────────────────────────── */
|
||||
.contact-section {
|
||||
background: var(--dark);
|
||||
padding: 7rem 2.5rem 6rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.service-row {
|
||||
padding: 2rem 0;
|
||||
.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;
|
||||
}
|
||||
|
||||
.service-row-num {
|
||||
padding-top: 0.3rem;
|
||||
.contact-inner { position: relative; z-index: 1; }
|
||||
|
||||
.contact-section .section-label {
|
||||
color: rgba(227,226,222,0.35);
|
||||
display: block;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.service-row-arrow {
|
||||
display: none;
|
||||
.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;
|
||||
}
|
||||
|
||||
.service-row-title {
|
||||
font-size: clamp(2rem, 7vw, 3rem);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
CONTACT & FOOTER
|
||||
======================================== */
|
||||
.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;
|
||||
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;
|
||||
}
|
||||
.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; }
|
||||
}
|
||||
@@ -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',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
<?php
|
||||
$slugs = array_keys($projects);
|
||||
$idx = array_search($cs_slug, $slugs);
|
||||
$prev = $idx > 0 ? $slugs[$idx - 1] : null;
|
||||
$next = $idx < count($slugs) - 1 ? $slugs[$idx + 1] : null;
|
||||
?>
|
||||
|
||||
<section class="section section-cta">
|
||||
<div class="section-label">— Next</div>
|
||||
<div class="section-content">
|
||||
<a href="/portfolio" class="cs-back cs-back--lg">← Back to All Work</a>
|
||||
<p class="large-text">Got a project in mind?</p>
|
||||
<a href="mailto:hello@uovidiu.com" class="btn">Let's Talk →</a>
|
||||
<div class="project-nav">
|
||||
<?php if ($prev): ?>
|
||||
<a href="/portfolio/<?php echo htmlspecialchars($prev); ?>/" class="project-nav-link">← <?php echo htmlspecialchars($projects[$prev]['title']); ?></a>
|
||||
<?php else: ?>
|
||||
<a href="/portfolio" class="project-nav-link">← Back to Portfolio</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($next): ?>
|
||||
<a href="/portfolio/<?php echo htmlspecialchars($next); ?>/" class="project-nav-link">Next Project → <?php echo htmlspecialchars($projects[$next]['title']); ?></a>
|
||||
<?php else: ?>
|
||||
<a href="/portfolio" class="project-nav-link">← Back to Portfolio</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script src="/js/screenshot-scroll-hint.js"></script>
|
||||
<?php require __DIR__ . '/footer.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';
|
||||
?>
|
||||
|
||||
<div class="cs-breadcrumb">
|
||||
<a href="/portfolio" class="cs-back">← All Work</a>
|
||||
<span class="cs-breadcrumb-label">[<?= htmlspecialchars($p['num']) ?> / <?= htmlspecialchars($p['code']) ?>]</span>
|
||||
<header class="hero hero--cs">
|
||||
<div class="hero-content">
|
||||
<div class="hero-divider"></div>
|
||||
<div class="hero-meta-row">
|
||||
<div class="hero-meta">
|
||||
<span><?php echo htmlspecialchars($p['num']); ?> / WEB_DEV · <?php echo htmlspecialchars($p['year']); ?></span>
|
||||
<span><?php echo htmlspecialchars($p['location']); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="hero-headline">
|
||||
<span class="line1"><?php echo htmlspecialchars($p['h1'][0]); ?></span>
|
||||
<span class="line2"><?php echo htmlspecialchars($p['h1'][1]); ?></span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<header class="hero">
|
||||
<div class="section-label">Case Study — <?= htmlspecialchars($p['num']) ?></div>
|
||||
<h1><?= htmlspecialchars($p['h1'][0]) ?><br><span class="h1-sub"><?= htmlspecialchars($p['h1'][1]) ?></span></h1>
|
||||
<p class="hero-sub"><?= htmlspecialchars($p['sub']) ?></p>
|
||||
<ul class="cs-meta-bar">
|
||||
<li><?= htmlspecialchars($p['stack']) ?></li>
|
||||
<li><?= htmlspecialchars($p['location']) ?></li>
|
||||
<li><?= htmlspecialchars($p['year']) ?></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div class="meta-bar">
|
||||
<div class="meta-col">
|
||||
<span class="meta-col-label">Client</span>
|
||||
<span class="meta-col-value"><?php echo htmlspecialchars($p['title']); ?></span>
|
||||
</div>
|
||||
<div class="meta-col">
|
||||
<span class="meta-col-label">Year</span>
|
||||
<span class="meta-col-value"><?php echo htmlspecialchars($p['year']); ?></span>
|
||||
</div>
|
||||
<div class="meta-col">
|
||||
<span class="meta-col-label">Stack</span>
|
||||
<span class="meta-col-value"><?php echo htmlspecialchars($p['stack']); ?></span>
|
||||
</div>
|
||||
<div class="meta-col">
|
||||
<span class="meta-col-label">Location</span>
|
||||
<span class="meta-col-value"><?php echo htmlspecialchars($p['location']); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,47 @@
|
||||
<footer class="footer">
|
||||
<span>© <?php echo date('Y'); ?> Ovidiu Ungureanu</span>
|
||||
<span>Built with PHP, no JS frameworks were harmed.</span>
|
||||
<div class="footer-grid">
|
||||
|
||||
<div>
|
||||
<h4 class="footer-heading">Studio</h4>
|
||||
<address class="footer-address">
|
||||
Peterborough, UK<br>
|
||||
<a href="mailto:hello@uovidiu.com">hello@uovidiu.com</a>
|
||||
</address>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 class="footer-heading">Navigate</h4>
|
||||
<ul class="footer-links">
|
||||
<li><a href="/#about">About</a></li>
|
||||
<li><a href="/#services">Services</a></li>
|
||||
<li><a href="/portfolio">Portfolio</a></li>
|
||||
<li><a href="/#contact">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- <div>-->
|
||||
<!-- <div class="footer-cta">-->
|
||||
<!-- <label for="footer-email">Start a project</label>-->
|
||||
<!-- <div class="footer-input-row">-->
|
||||
<!-- <input type="email" id="footer-email" placeholder="Your email" autocomplete="email">-->
|
||||
<!-- <button type="button">Send</button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<span class="footer-ghost">U. ovidiu</span>
|
||||
<span class="footer-legal">© <?php echo date('Y'); ?> Ovidiu Ungureanu</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
const nav = document.querySelector('.nav');
|
||||
window.addEventListener('scroll', () => {
|
||||
nav.classList.toggle('nav--scrolled', window.scrollY > 50);
|
||||
}, { passive: true });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<?php $current = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); ?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -5,9 +6,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo htmlspecialchars($title); ?></title>
|
||||
<meta name="description" content="<?php echo htmlspecialchars($description); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700;900&family=DM+Sans:wght@400;500&family=Archivo+Black&display=swap" rel="stylesheet">
|
||||
<link rel="preconnect" href="https://api.fontshare.com">
|
||||
<link href="https://api.fontshare.com/v2/css?f[]=clash-grotesk@700,600,500,400&f[]=general-sans@700,600,500,400&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<?php if (!empty($extra_css)): ?>
|
||||
<link rel="stylesheet" href="<?php echo htmlspecialchars($extra_css); ?>">
|
||||
@@ -15,18 +15,36 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php $current = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); ?>
|
||||
<div class="noise" aria-hidden="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
|
||||
<filter id="n">
|
||||
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="3" stitchTiles="stitch"/>
|
||||
</filter>
|
||||
<rect width="100%" height="100%" filter="url(#n)"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<nav class="nav">
|
||||
<?php if (!empty($nav_back)): ?>
|
||||
<div class="nav-left">
|
||||
<a href="/" class="nav-logo">OU</a>
|
||||
<?php if (str_starts_with($current, '/portfolio/')): ?>
|
||||
<a href="/portfolio" class="nav-back">←(back)</a>
|
||||
<?php endif; ?>
|
||||
<a href="<?php echo htmlspecialchars($nav_back['url']); ?>" class="nav-back"><?php echo htmlspecialchars($nav_back['label']); ?></a>
|
||||
<a href="/" class="nav-logo">U. ovidiu</a>
|
||||
</div>
|
||||
<div class="nav-links">
|
||||
<a href="/#about">About</a>
|
||||
<a href="/#services">Services</a>
|
||||
<a href="/portfolio"<?php echo (str_starts_with($current, '/portfolio')) ? ' class="active"' : ''; ?>>Work</a>
|
||||
<a href="/#contact">Contact</a>
|
||||
<a href="/#about" class="nav-link">About</a>
|
||||
<a href="/#services" class="nav-link">Services</a>
|
||||
<a href="/#contact" class="nav-link">Contact</a>
|
||||
</div>
|
||||
<?php if (!empty($nav_cta)): ?>
|
||||
<a href="<?php echo htmlspecialchars($nav_cta['url']); ?>" target="_blank" rel="noopener" class="nav-cta"><?php echo htmlspecialchars($nav_cta['label']); ?></a>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<a href="/" class="nav-logo">U. ovidiu</a>
|
||||
<div class="nav-links">
|
||||
<a href="/#about" class="nav-link">About</a>
|
||||
<a href="/#services" class="nav-link">Services</a>
|
||||
<a href="/portfolio" class="nav-link<?php echo str_starts_with($current, '/portfolio') ? ' nav-link--active' : ''; ?>">Work</a>
|
||||
<a href="/#contact" class="nav-link">Contact</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</nav>
|
||||
|
||||
137
index.php
137
index.php
@@ -1,107 +1,124 @@
|
||||
<?php
|
||||
|
||||
$title = 'Ovidiu Ungureanu — Web Developer';
|
||||
$description = 'PHP/MySQL developer based in Peterborough. I build custom web apps, ERP systems, and backends for businesses that need something specific.';
|
||||
$description = 'PHP/MySQL developer based in Peterborough. I build custom web apps, booking systems, and backends for small businesses.';
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<header class="hero">
|
||||
<div class="section-label">Web Developer — UK</div>
|
||||
<h1>Ovidiu<br>Ungureanu</h1>
|
||||
<p class="hero-sub">I build web applications that work.<br>PHP, MySQL, clean code, no nonsense.</p>
|
||||
<div class="hero-cta">
|
||||
<a href="/portfolio" class="btn">View Work →</a>
|
||||
<a href="#contact" class="btn btn-ghost">Let's Talk</a>
|
||||
<div class="hero-content">
|
||||
<div class="hero-divider"></div>
|
||||
<div class="hero-meta-row">
|
||||
<div class="hero-meta">
|
||||
<span>Web Developer — Peterborough, UK</span>
|
||||
<span>I build web applications that work.</span>
|
||||
<span>Available for freelance</span>
|
||||
</div>
|
||||
<a href="#contact" class="hero-cta-btn">Let's Talk →</a>
|
||||
</div>
|
||||
<h1 class="hero-headline">
|
||||
<span class="line1">CleanCode</span>
|
||||
<span class="line2">Studio</span>
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="about" class="section">
|
||||
<div class="section-label">001 — About</div>
|
||||
<div class="section-content">
|
||||
<p> I'm a web developer based in Peterborough.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<main>
|
||||
|
||||
<!-- About / Manifesto -->
|
||||
<section class="manifesto" id="about">
|
||||
<div class="manifesto-label-col">
|
||||
<span class="section-label">001 — About</span>
|
||||
</div>
|
||||
<div class="manifesto-text-col">
|
||||
<p class="manifesto-text">
|
||||
I build websites and online tools for small businesses
|
||||
<span class="hl">— booking systems, customer dashboards</span>.
|
||||
|
||||
<br>Fast, affordable, and built to last.
|
||||
Built for businesses that need something real.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="services" class="services-section">
|
||||
<div class="services-section-label">002 — Services</div>
|
||||
<div class="services-list">
|
||||
<!-- Services Category Divider -->
|
||||
<div class="category-divider">
|
||||
<h2>Services</h2>
|
||||
</div>
|
||||
|
||||
<!-- Services List -->
|
||||
<section class="services" id="services">
|
||||
|
||||
<div class="service-row">
|
||||
<div class="service-row-body">
|
||||
<span class="service-row-num">(01)</span>
|
||||
<div class="service-row-content">
|
||||
<h3 class="service-row-title">Website Design<br>& Development</h3>
|
||||
<div class="service-row-tags">
|
||||
<span class="service-num">(01)</span>
|
||||
<div class="service-body">
|
||||
<h3 class="service-title">Website Design<br>& Development</h3>
|
||||
<div class="service-tags">
|
||||
<span class="service-tag">Design</span>
|
||||
<span class="service-tag">Development</span>
|
||||
<span class="service-tag">Responsive</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="service-badge">Enquire →</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="service-row">
|
||||
<div class="service-row-body">
|
||||
<span class="service-row-num">(02)</span>
|
||||
<div class="service-row-content">
|
||||
<h3 class="service-row-title">Custom Tools<br>& Systems</h3>
|
||||
<div class="service-row-tags">
|
||||
|
||||
<div class="service-row service-row--alt">
|
||||
<span class="service-num">(02)</span>
|
||||
<div class="service-body">
|
||||
<h3 class="service-title"><span>Custom Tools<br>& Systems</span></h3>
|
||||
<div class="service-tags">
|
||||
<span class="service-tag">PHP</span>
|
||||
<span class="service-tag">MySQL</span>
|
||||
<span class="service-tag">Custom Builds</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="service-badge">Enquire →</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="service-row">
|
||||
<div class="service-row-body">
|
||||
<span class="service-row-num">(03)</span>
|
||||
<div class="service-row-content">
|
||||
<h3 class="service-row-title">Booking &<br>Scheduling</h3>
|
||||
<div class="service-row-tags">
|
||||
<span class="service-num">(03)</span>
|
||||
<div class="service-body">
|
||||
<h3 class="service-title">Booking &<br>Scheduling</h3>
|
||||
<div class="service-tags">
|
||||
<span class="service-tag">Bookings</span>
|
||||
<span class="service-tag">Automation</span>
|
||||
<span class="service-tag">Small Business</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="service-badge">Enquire →</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="service-row">
|
||||
<div class="service-row-body">
|
||||
<span class="service-row-num">(04)</span>
|
||||
<div class="service-row-content">
|
||||
<h3 class="service-row-title">Ongoing Support<br>& Updates</h3>
|
||||
<div class="service-row-tags">
|
||||
|
||||
<div class="service-row service-row--alt">
|
||||
<span class="service-num">(04)</span>
|
||||
<div class="service-body">
|
||||
<h3 class="service-title"><span>Ongoing Support<br>& Updates</span></h3>
|
||||
<div class="service-tags">
|
||||
<span class="service-tag">Maintenance</span>
|
||||
<span class="service-tag">Performance</span>
|
||||
<span class="service-tag">Support</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="service-badge">Enquire →</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!--<section class="section section-cta">-->
|
||||
<!-- <div class="section-label">003 — Work</div>-->
|
||||
<!-- <div class="section-content">-->
|
||||
<!-- <p class="large-text">A few recent builds.</p>-->
|
||||
<!-- <a href="/portfolio" class="btn">View Work →</a>-->
|
||||
<!-- </div>-->
|
||||
<!--</section>-->
|
||||
|
||||
<section id="contact" class="section">
|
||||
<div class="section-label">004 — Contact</div>
|
||||
<div class="section-content">
|
||||
<p class="large-text">Got a project in mind?</p>
|
||||
<!-- Contact -->
|
||||
<section class="contact-section" id="contact">
|
||||
<div class="contact-inner">
|
||||
<span class="section-label">004 — Contact</span>
|
||||
<h2 class="contact-headline">
|
||||
Got a project<br>
|
||||
<span class="accent">in mind?</span>
|
||||
</h2>
|
||||
<a href="mailto:hello@uovidiu.com" class="contact-email">hello@uovidiu.com</a>
|
||||
<div class="contact-details">
|
||||
<div class="contact-meta">
|
||||
<span>Peterborough, UK</span>
|
||||
<span>·</span>
|
||||
<span class="dot">·</span>
|
||||
<span>Available for freelance</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php
|
||||
require __DIR__.'/includes/footer.php'; ?>
|
||||
</main>
|
||||
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
151
portfolio-page.php
Normal file
151
portfolio-page.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/data/projects.php';
|
||||
|
||||
$slug = isset($_GET['slug']) ? preg_replace('/[^a-z0-9\-]/', '', strtolower($_GET['slug'])) : '';
|
||||
|
||||
if (!$slug || !isset($projects[$slug])) {
|
||||
http_response_code(404);
|
||||
require __DIR__ . '/404.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
$p = $projects[$slug];
|
||||
|
||||
$title = htmlspecialchars($p['page_title']);
|
||||
$description = htmlspecialchars($p['page_desc']);
|
||||
$extra_css = '/css/portfolio.css';
|
||||
|
||||
$nav_back = ['url' => '/portfolio', 'label' => '← Portfolio'];
|
||||
//if (!empty($p['domain'])) {
|
||||
// $nav_cta = ['url' => 'https://' . $p['domain'], 'label' => 'Visit Site →'];
|
||||
//}
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<header class="hero hero--cs">
|
||||
<div class="hero-content">
|
||||
<div class="hero-divider"></div>
|
||||
<div class="hero-meta-row">
|
||||
<div class="hero-meta">
|
||||
<span><?= htmlspecialchars($p['num']) ?> / <?= htmlspecialchars($p['code']) ?> · <?= htmlspecialchars($p['year']) ?></span>
|
||||
<span><?= htmlspecialchars($p['location']) ?></span>
|
||||
<span><?= htmlspecialchars($p['sub']) ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="hero-headline">
|
||||
<span class="line1"><?= htmlspecialchars($p['h1'][0]) ?></span>
|
||||
<span class="line2"><?= htmlspecialchars($p['h1'][1]) ?></span>
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
||||
<!-- Project Meta Bar -->
|
||||
<div class="meta-bar">
|
||||
<div class="meta-col">
|
||||
<span class="meta-col-label">Client</span>
|
||||
<span class="meta-col-value"><?= htmlspecialchars($p['title']) ?></span>
|
||||
</div>
|
||||
<div class="meta-col">
|
||||
<span class="meta-col-label">Year</span>
|
||||
<span class="meta-col-value"><?= htmlspecialchars($p['year']) ?></span>
|
||||
</div>
|
||||
<div class="meta-col">
|
||||
<span class="meta-col-label">Stack</span>
|
||||
<span class="meta-col-value"><?= htmlspecialchars($p['stack']) ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Project Overview -->
|
||||
<section class="cs-overview">
|
||||
<div class="cs-overview-label">
|
||||
<span class="section-label">Project Overview</span>
|
||||
</div>
|
||||
<div class="cs-overview-body">
|
||||
<p class="cs-overview-text"><?= htmlspecialchars($p['overview']) ?></p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Screenshots Category Divider -->
|
||||
<div class="category-divider">
|
||||
<h2>Screenshots</h2>
|
||||
</div>
|
||||
|
||||
<!-- Screenshots -->
|
||||
<section class="screenshots-section">
|
||||
|
||||
<!-- Full-width hero screenshot -->
|
||||
<div class="screenshot-hero">
|
||||
<div class="browser-frame">
|
||||
<div class="browser-bar">
|
||||
<div class="browser-dots">
|
||||
<span class="browser-dot browser-dot--red"></span>
|
||||
<span class="browser-dot browser-dot--beige"></span>
|
||||
<span class="browser-dot browser-dot--green"></span>
|
||||
</div>
|
||||
<span class="browser-url"><?= htmlspecialchars($p['domain']) ?></span>
|
||||
</div>
|
||||
<div class="browser-scroll-wrap">
|
||||
<div class="browser-scroll">
|
||||
<img src="<?= htmlspecialchars($p['hero_img']) ?>" alt="<?= htmlspecialchars($p['title']) ?> — Homepage">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php foreach ($p['screenshots'] as $group): ?>
|
||||
|
||||
<div class="screenshots-label">
|
||||
<span class="section-label"><?= htmlspecialchars($group['label']) ?></span>
|
||||
</div>
|
||||
|
||||
<div class="screenshot-grid">
|
||||
<?php foreach ($group['items'] as $shot): ?>
|
||||
<div>
|
||||
<span class="screenshot-card-label"><?= htmlspecialchars($shot['label']) ?></span>
|
||||
<p class="screenshot-card-desc"><?= htmlspecialchars($shot['desc']) ?></p>
|
||||
<div class="browser-frame">
|
||||
<div class="browser-bar">
|
||||
<div class="browser-dots">
|
||||
<span class="browser-dot browser-dot--red"></span>
|
||||
<span class="browser-dot browser-dot--beige"></span>
|
||||
<span class="browser-dot browser-dot--green"></span>
|
||||
</div>
|
||||
<span class="browser-url"><?= htmlspecialchars($p['domain'] . $shot['url_suffix']) ?></span>
|
||||
</div>
|
||||
<img src="<?= htmlspecialchars($shot['img']) ?>" alt="<?= htmlspecialchars($shot['alt']) ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php endforeach; ?>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- Execution Category Divider -->
|
||||
<div class="category-divider">
|
||||
<h2>Execution</h2>
|
||||
</div>
|
||||
|
||||
<!-- Craft & Execution -->
|
||||
<section class="cs-overview">
|
||||
<div class="cs-overview-label">
|
||||
<span class="section-label">Craft & Execution</span>
|
||||
</div>
|
||||
<div class="cs-overview-body">
|
||||
<p class="cs-overview-text"><?= htmlspecialchars($p['execution']) ?></p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Project Navigation -->
|
||||
<div class="project-nav">
|
||||
<a href="/portfolio" class="project-nav-link">← Back to Portfolio</a>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
@@ -1,71 +1,71 @@
|
||||
<?php
|
||||
|
||||
$title = 'Portfolio — Ovidiu Ungureanu';
|
||||
$description = 'Selected web development projects by Ovidiu Ungureanu.';
|
||||
$extra_css = '/css/portfolio.css';
|
||||
require __DIR__ . '/includes/header.php';
|
||||
|
||||
require __DIR__ . '/data/projects.php';
|
||||
?>
|
||||
|
||||
<header class="hero">
|
||||
<div class="section-label">Portfolio — Selected Work</div>
|
||||
<h1>Selected<br>Work</h1>
|
||||
<p class="hero-sub">Client projects and builds.</p>
|
||||
<div class="hero-content">
|
||||
<div class="hero-divider"></div>
|
||||
<div class="hero-meta-row">
|
||||
<div class="hero-meta">
|
||||
<span>Portfolio — <?php echo count($projects); ?> Projects</span>
|
||||
<span>Web Design & Development</span>
|
||||
</div>
|
||||
<a href="/" class="hero-cta-btn">← Back to Home</a>
|
||||
</div>
|
||||
<h1 class="hero-headline">
|
||||
<span class="line1">Selected</span>
|
||||
<span class="line2">Work</span>
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-label">001 — <?php
|
||||
echo count($projects); ?> Projects
|
||||
<main>
|
||||
|
||||
<section class="portfolio-section">
|
||||
|
||||
<div class="portfolio-header">
|
||||
<span class="section-label">001 — Selected Work</span>
|
||||
</div>
|
||||
|
||||
<div class="portfolio-grid">
|
||||
<?php
|
||||
foreach ($projects as $slug => $p): ?>
|
||||
<a href="/portfolio/<?php
|
||||
echo htmlspecialchars($slug); ?>/"
|
||||
class="project-card<?php
|
||||
echo $p['live'] ? '' : ' project-card--wip'; ?>">
|
||||
|
||||
<?php foreach ($projects as $slug => $p): ?>
|
||||
<a href="/portfolio/<?php echo htmlspecialchars($slug); ?>/" class="project-card<?php echo $p['live'] ? '' : ' project-card--wip'; ?>">
|
||||
<div class="project-card__thumb">
|
||||
<span class="project-card__label">[<?php
|
||||
echo htmlspecialchars($p['num']); ?> / <?php
|
||||
echo htmlspecialchars($p['code']); ?>]</span>
|
||||
<?php
|
||||
if ($p['thumb']): ?>
|
||||
<img src="<?php
|
||||
echo htmlspecialchars($p['thumb']); ?>"
|
||||
alt="<?php
|
||||
echo htmlspecialchars($p['title']); ?>"
|
||||
loading="lazy">
|
||||
<?php
|
||||
endif; ?>
|
||||
<span class="project-card__label"><?php echo htmlspecialchars($p['num']); ?> / <?php echo htmlspecialchars($p['code']); ?></span>
|
||||
<span class="project-card__badge">View Project →</span>
|
||||
<?php if ($p['thumb']): ?>
|
||||
<img src="<?php echo htmlspecialchars($p['thumb']); ?>" alt="<?php echo htmlspecialchars($p['title']); ?>" loading="lazy">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="project-card__body">
|
||||
<h3 class="project-card__title"><?php
|
||||
echo htmlspecialchars($p['title']); ?></h3>
|
||||
<p class="project-card__desc"><?php
|
||||
echo htmlspecialchars($p['desc']); ?></p>
|
||||
<h2 class="project-card__title"><?php echo htmlspecialchars($p['title']); ?></h2>
|
||||
<p class="project-card__desc"><?php echo htmlspecialchars($p['desc']); ?></p>
|
||||
<div class="project-card__footer">
|
||||
<span class="project-card__year"><?php
|
||||
echo htmlspecialchars($p['year']); ?></span>
|
||||
<span class="project-card__year"><?php echo htmlspecialchars($p['year']); ?> · <?php echo htmlspecialchars($p['stack']); ?></span>
|
||||
<span class="project-card__arrow">→</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</a>
|
||||
<?php
|
||||
endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<section class="contact-section contact-section--slim">
|
||||
<div class="contact-inner">
|
||||
<span class="section-label">002 — Contact</span>
|
||||
<h2 class="contact-headline">
|
||||
Got a project<br>
|
||||
<span class="accent">in mind?</span>
|
||||
</h2>
|
||||
<a href="mailto:hello@uovidiu.com" class="contact-email">hello@uovidiu.com</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-cta">
|
||||
<div class="section-label">002 — Contact</div>
|
||||
<div class="section-content">
|
||||
<p class="large-text">Got a project in mind?</p>
|
||||
<a href="mailto:hello@uovidiu.com" class="btn">Let's Talk →</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<?php
|
||||
require __DIR__.'/includes/footer.php'; ?>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* ═══════════════════════════════════════════════════════════════════
|
||||
* CASE STUDY TEMPLATE
|
||||
* ═══════════════════════════════════════════════════════════════════
|
||||
*
|
||||
* HOW TO USE
|
||||
* ──────────
|
||||
* 1. Copy this folder to portfolio/{slug}/
|
||||
* 2. Fill in every TODO below — nothing should say TODO when live
|
||||
* 3. Add an entry to $projects in data/projects.php (including page_title, page_desc)
|
||||
* 4. Drop screenshots into /img/{slug}/
|
||||
*
|
||||
* IMAGES
|
||||
* ──────
|
||||
* hero.jpg — full-page screenshot (used as grid thumbnail too)
|
||||
* feature-1.jpg — first feature / flow screenshot
|
||||
* feature-2.jpg — second feature / flow screenshot
|
||||
* Add more as needed — duplicate the 2-col screenshot section below.
|
||||
*
|
||||
* SECTIONS (delete what you don't need)
|
||||
* ──────────────────────────────────────
|
||||
* · Project Overview — always include
|
||||
* · Hero screenshot — always include
|
||||
* · Feature section — include if there's a flow / feature worth showing
|
||||
* · Craft & Execution — include if the build has something worth saying
|
||||
* · CTA — always include, comes from cs_footer.php
|
||||
* ═══════════════════════════════════════════════════════════════════
|
||||
*/
|
||||
|
||||
// ── Set the slug — everything else lives in data/projects.php ─────
|
||||
$cs_slug = 'TODO'; // e.g. 'northgate'
|
||||
require __DIR__ . '/../../includes/cs_header.php';
|
||||
?>
|
||||
|
||||
|
||||
<!-- ── HERO SCREENSHOT ───────────────────────────────────────────── -->
|
||||
<section class="section">
|
||||
<div class="section-label">Project Overview</div>
|
||||
|
||||
<div class="section-content">
|
||||
<p>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.</p>
|
||||
</div>
|
||||
|
||||
<div class="screenshot-hero-wrap">
|
||||
<div class="browser-chrome">
|
||||
<div class="browser-dots">
|
||||
<span></span><span></span><span></span>
|
||||
</div>
|
||||
<span class="browser-url"><?= htmlspecialchars($p['domain']) ?></span>
|
||||
</div>
|
||||
<div class="screenshot-hero-scroll">
|
||||
<img
|
||||
src="/img/<?= htmlspecialchars($cs_slug) ?>/hero.jpg"
|
||||
alt="TODO Client Name — TODO description"
|
||||
class="screenshot-hero"
|
||||
loading="lazy"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- ── FEATURE / FLOW SCREENSHOTS (2-col) ────────────────────────── -->
|
||||
<!-- Delete this section if you don't have feature screenshots -->
|
||||
<section class="section">
|
||||
<div class="section-label">TODO Section Label</div><!-- e.g. Booking Flow / Admin Panel / Listings -->
|
||||
<div class="services-grid">
|
||||
|
||||
<div class="service-item screenshot-card">
|
||||
<span class="service-num">TODO Feature label</span><!-- e.g. Step 1 / Vehicle Lookup -->
|
||||
<p class="screenshot-card__desc">TODO Feature description.</p>
|
||||
<div class="browser-chrome browser-chrome--sm">
|
||||
<div class="browser-dots">
|
||||
<span></span><span></span><span></span>
|
||||
</div>
|
||||
<span class="browser-url"><?= htmlspecialchars($p['domain']) ?>/TODO-path</span>
|
||||
</div>
|
||||
<img
|
||||
src="/img/<?= htmlspecialchars($cs_slug) ?>/feature-1.jpg"
|
||||
alt="TODO description"
|
||||
class="screenshot-screen"
|
||||
loading="lazy"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="service-item screenshot-card">
|
||||
<span class="service-num">TODO Feature label</span>
|
||||
<p class="screenshot-card__desc">TODO Feature description.</p>
|
||||
<div class="browser-chrome browser-chrome--sm">
|
||||
<div class="browser-dots">
|
||||
<span></span><span></span><span></span>
|
||||
</div>
|
||||
<span class="browser-url"><?= htmlspecialchars($p['domain']) ?>/TODO-path</span>
|
||||
</div>
|
||||
<img
|
||||
src="/img/<?= htmlspecialchars($cs_slug) ?>/feature-2.jpg"
|
||||
alt="TODO description"
|
||||
class="screenshot-screen"
|
||||
loading="lazy"
|
||||
>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- ── CRAFT & EXECUTION ─────────────────────────────────────────── -->
|
||||
<!-- Delete this section if there's nothing distinctive about the build -->
|
||||
<section class="section">
|
||||
<div class="section-label">Craft & Execution</div>
|
||||
<div class="section-content">
|
||||
<p>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.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php require __DIR__ . '/../../includes/cs_footer.php'; ?>
|
||||
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
$cs_slug = 'lhbeng';
|
||||
require __DIR__ . '/../../includes/cs_header.php';
|
||||
?>
|
||||
|
||||
<!-- ── HERO SCREENSHOT ───────────────────────────────────────────── -->
|
||||
<section class="section">
|
||||
<div class="section-label">Project Overview</div>
|
||||
<div class="section-content">
|
||||
<p>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.</p>
|
||||
</div>
|
||||
<div class="screenshot-hero-wrap">
|
||||
<div class="browser-chrome">
|
||||
<div class="browser-dots">
|
||||
<span></span><span></span><span></span>
|
||||
</div>
|
||||
<span class="browser-url"><?= htmlspecialchars($p['domain']) ?></span>
|
||||
</div>
|
||||
<img
|
||||
src="/img/lhbeng/hero.jpg"
|
||||
alt="LHB Engineering — Homepage"
|
||||
class="screenshot-hero"
|
||||
loading="lazy"
|
||||
>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- ── FEATURE / FLOW SCREENSHOTS (2-col) ────────────────────────── -->
|
||||
<section class="section">
|
||||
<div class="section-label">Website CMS</div>
|
||||
<div class="services-grid">
|
||||
|
||||
<div class="service-item screenshot-card">
|
||||
<span class="service-num">Website CMS</span>
|
||||
<p class="screenshot-card__desc">Full-fledged CMS for content.</p>
|
||||
<div class="browser-chrome browser-chrome--sm">
|
||||
<div class="browser-dots">
|
||||
<span></span><span></span><span></span>
|
||||
</div>
|
||||
<span class="browser-url"><?= htmlspecialchars($p['domain']) ?>/admin</span>
|
||||
</div>
|
||||
<img
|
||||
src="/img/lhbeng/admin.jpg"
|
||||
alt="LHB Engineering CMS admin panel"
|
||||
class="screenshot-screen"
|
||||
loading="lazy"
|
||||
>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- ── CRAFT & EXECUTION ─────────────────────────────────────────── -->
|
||||
<section class="section">
|
||||
<div class="section-label">Craft & Execution</div>
|
||||
<div class="section-content">
|
||||
<p>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. <br/>The new site is fast, fully responsive, and structured so visitors can quickly find services, past projects, and contact details. <br/>
|
||||
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.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php require __DIR__ . '/../../includes/cs_footer.php'; ?>
|
||||
@@ -1,81 +0,0 @@
|
||||
<?php
|
||||
$cs_slug = 'thompson';
|
||||
require __DIR__ . '/../../includes/cs_header.php';
|
||||
?>
|
||||
|
||||
<section class="section">
|
||||
|
||||
<div class="section-label">Project Overview</div>
|
||||
<div class="section-content">
|
||||
<p>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.</p>
|
||||
</div>
|
||||
|
||||
<div class="screenshot-hero-wrap">
|
||||
<div class="browser-chrome">
|
||||
<div class="browser-dots">
|
||||
<span></span><span></span><span></span>
|
||||
</div>
|
||||
<span class="browser-url"><?= htmlspecialchars($p['domain']) ?></span>
|
||||
</div>
|
||||
<div class="screenshot-hero-scroll">
|
||||
<img
|
||||
src="/img/thompson/hero.jpg"
|
||||
alt="Thompson Service Centre — Homepage"
|
||||
class="screenshot-hero"
|
||||
loading="lazy"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-label">Booking Flow</div>
|
||||
<div class="services-grid">
|
||||
<div class="service-item screenshot-card">
|
||||
<span class="service-num">Vehicle Lookup</span>
|
||||
<p class="screenshot-card__desc">Enter your registration plate to pull vehicle details automatically.</p>
|
||||
<div class="browser-chrome browser-chrome--sm">
|
||||
<div class="browser-dots">
|
||||
<span></span><span></span><span></span>
|
||||
</div>
|
||||
<span class="browser-url"><?= htmlspecialchars($p['domain']) ?>/book</span>
|
||||
</div>
|
||||
<img
|
||||
src="/img/thompson/booking-lookup.jpg"
|
||||
alt="Vehicle registration lookup"
|
||||
class="screenshot-screen"
|
||||
loading="lazy"
|
||||
>
|
||||
</div>
|
||||
<div class="service-item screenshot-card">
|
||||
<span class="service-num">Booking Form</span>
|
||||
<p class="screenshot-card__desc">Confirm your vehicle and fill in the booking details in one clean step.</p>
|
||||
<div class="browser-chrome browser-chrome--sm">
|
||||
<div class="browser-dots">
|
||||
<span></span><span></span><span></span>
|
||||
</div>
|
||||
<span class="browser-url"><?= htmlspecialchars($p['domain']) ?>/book</span>
|
||||
</div>
|
||||
<img
|
||||
src="/img/thompson/booking-confirm.jpg"
|
||||
alt="Vehicle confirmed and booking form"
|
||||
class="screenshot-screen"
|
||||
loading="lazy"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-label">Craft & Execution</div>
|
||||
<div class="section-content">
|
||||
<p>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.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php require __DIR__ . '/../../includes/cs_footer.php'; ?>
|
||||
Reference in New Issue
Block a user