feature/services-pages (#7)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/deploy Pipeline was successful

Reviewed-on: #7
Co-authored-by: mifi <badmf@mifi.dev>
Co-committed-by: mifi <badmf@mifi.dev>
This commit was merged in pull request #7.
This commit is contained in:
2026-03-10 00:51:18 +00:00
committed by Mike Fitzpatrick
parent 66640fa535
commit 7012f0fdd2
98 changed files with 4119 additions and 1189 deletions

View File

@@ -0,0 +1,61 @@
<script lang="ts">
interface BreadcrumbItem {
label: string;
href?: string;
}
const {
items = [],
}: {
items: BreadcrumbItem[];
} = $props();
</script>
<nav class="section breadcrumbs" aria-label="Breadcrumbs">
<div class="container">
<ol class="list">
{#each items as item, index}
<li class="item">
{#if item.href}
<a href={item.href}>{item.label}</a>
{#if index < items.length - 1}<span
class="separator"
aria-hidden="true">&gt;</span
>{/if}
{:else}
{item.label}
{/if}
</li>
{/each}
</ol>
</div>
</nav>
<style>
.breadcrumbs {
padding: var(--space-md) 0;
font-size: var(--font-size-small);
color: var(--color-text-secondary);
}
.list {
display: inline-block;
list-style: none;
margin: 0;
padding: 0;
}
.item {
display: inline;
}
.item a {
color: var(--color-text-secondary);
text-decoration: none;
}
.separator {
font-size: var(--font-size-small);
margin-inline: var(--space-xs);
}
</style>

View File

@@ -0,0 +1,37 @@
<script lang="ts">
import type { EngagementItem } from '$lib/types/service-page';
const {
items,
sectionId = 'how-engagements-work',
headingId = 'engagements-heading',
heading = 'How engagements work',
intro,
outro,
}: {
items: EngagementItem[];
sectionId?: string;
headingId?: string;
heading?: string;
intro?: string;
outro?: string;
} = $props();
</script>
<section id={sectionId} class="section" aria-labelledby={headingId}>
<div class="container narrow">
<h2 id={headingId}>{heading}</h2>
{#if intro}
<p>{intro}</p>
{/if}
<dl class="engagements-list">
{#each items as item}
<dt>{item.term}</dt>
<dd>{item.definition}</dd>
{/each}
</dl>
{#if outro}
<p>{outro}</p>
{/if}
</div>
</section>

View File

@@ -0,0 +1,51 @@
<script lang="ts">
import type { FaqList } from '$lib/types/faq';
const {
faqList,
title = 'FAQ',
}: {
faqList: FaqList;
title?: string;
} = $props();
</script>
<section id="faq" class="section faq" aria-labelledby="faq-heading">
<div class="container narrow">
<h2 id="faq-heading">{title}</h2>
<dl class="faq-list">
{#each faqList as { question, answer }, index (index)}
<dt>{question}</dt>
<dd>{answer}</dd>
{/each}
</dl>
</div>
</section>
<style>
.faq {
background-color: var(--color-bg-alt);
}
.faq-list {
margin: 0;
& dt {
font-weight: var(--font-weight-semibold);
color: var(--color-text);
margin-top: var(--space-xl);
margin-bottom: var(--space-sm);
&:first-child {
margin-top: 0;
}
}
& dd {
margin: 0 0 0 var(--space-md);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
max-width: var(--max-text-width);
}
}
</style>

View File

@@ -7,9 +7,9 @@
<footer class="footer">
<div class="container">
<p class="copyright">
© <span id="copyright-year">2026</span> mifi Ventures, LLC · Boston, MA
© <span id="copyright-year">2026</span> mifi Ventures, LLC. All rights reserved.
</p>
<nav class="footer-links" aria-label="Social media links">
<nav class="footer-links footer-links-wrap" aria-label="Footer links">
<a
class="link"
href="https://linkedin.com/in/the-mifi"
@@ -36,6 +36,22 @@
GitHub
<ExternalLinkIcon aria-label="Opens in new tab" size={15} />
</a>
<a
class="link"
href="/privacy-policy"
data-umami-event="footer link"
data-umami-event-label="privacy-policy"
>
Privacy Policy
</a>
<a
class="link"
href="/terms-of-service"
data-umami-event="footer link"
data-umami-event-label="terms-of-service"
>
Terms of Service
</a>
</nav>
</div>
</footer>
@@ -56,6 +72,10 @@
max-width: 100%;
}
.footer-links-wrap {
flex-wrap: wrap;
}
.link {
display: flex;
align-items: center;

View File

@@ -1,41 +1,58 @@
<script lang="ts">
import ExternalLinkIcon from './Icon/ExternalLink.svelte';
import FiletypePdfIcon from './Icon/FiletypePdf.svelte';
import Logo from './Logo.svelte';
import ExternalLinkIcon from '$lib/components/Icon/ExternalLink.svelte';
interface SecondaryCta {
href: string;
label: string;
umamiEventLabel: string;
}
const {
title,
subtitle,
bookingLinkTitle,
bookingLinkUrl,
secondaryCta,
}: {
title: string;
subtitle: string;
bookingLinkTitle: string;
bookingLinkUrl: string;
secondaryCta?: SecondaryCta;
} = $props();
</script>
<header id="header" class="hero">
<div class="container">
<Logo />
<p class="headline">Software Engineering Consulting</p>
<p class="subhead">
Principal: Mike Fitzpatrick — senior full-stack engineer and architect helping
teams ship reliable, accessible, high-performance web products.
<h1 class="title">
{title}
</h1>
<p class="subtitle">
{subtitle}
</p>
<div class="cta-group">
<a
href="https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_medium=hero_cta"
href={bookingLinkUrl}
class="btn btn-primary icon-button"
target="_blank"
rel="noopener noreferrer"
aria-label="Schedule a 30-minute intro call (opens in new tab)"
data-umami-event="schedule call"
data-umami-event-location="hero section"
aria-label={`${bookingLinkTitle} (opens in new tab)`}
data-umami-event="book discovery call"
data-umami-event-location="hero"
>
Schedule a 30-minute intro call
{bookingLinkTitle}
<ExternalLinkIcon aria-label="Opens in new tab" size={17} />
</a>
<a
href="/downloads/resume.pdf"
class="btn btn-secondary icon-button"
download
aria-label="Download Mike Fitzpatrick's resume as PDF"
data-umami-event="download resume"
data-umami-event-location="hero section"
>
Download resume
<FiletypePdfIcon aria-label="PDF format file" size={17} />
</a>
{#if secondaryCta}
<a
href={secondaryCta.href}
class="btn btn-secondary"
data-umami-event={secondaryCta.umamiEventLabel}
data-umami-event-location="hero"
>
{secondaryCta.label}
</a>
{/if}
</div>
</div>
</header>
@@ -46,26 +63,20 @@
text-align: center;
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
@media (max-width: 768px) {
padding: var(--space-xxl) 0 var(--space-xl) 0;
}
@media (max-width: 480px) {
padding: var(--space-xl) 0 var(--space-lg) 0;
}
}
.headline {
.title {
margin-bottom: var(--space-lg);
font-family: var(--font-family-heading);
font-size: var(--font-size-xl);
font-weight: var(--font-weight-semibold);
color: var(--color-text);
letter-spacing: -0.02em;
font-size: var(--font-size-xxl);
font-weight: var(--font-weight-bold);
letter-spacing: -0.03em;
max-width: var(--max-text-width);
margin-left: auto;
margin-right: auto;
}
.subhead {
.subtitle {
max-width: var(--max-narrow-width);
margin: 0 auto var(--space-xl) auto;
font-size: var(--font-size-large);
@@ -81,8 +92,10 @@
justify-content: center;
align-items: center;
margin-top: var(--space-lg);
}
@media (max-width: 768px) {
@media (max-width: 768px) {
.cta-group {
flex-direction: column;
width: 100%;
}

View File

@@ -1,14 +0,0 @@
<script lang="ts">
import { howWeWorkItems } from '$lib/data/content';
</script>
<section id="how-we-work" class="section" aria-labelledby="how-we-work-heading">
<div class="container">
<h2 id="how-we-work-heading" class="section-title">How We Work</h2>
<ul class="content-list">
{#each howWeWorkItems as item (item)}
<li>{item}</li>
{/each}
</ul>
</div>
</section>

View File

@@ -1,5 +1,23 @@
<script lang="ts">
import { page as pageState } from '$app/state';
import Wordmark from './Wordmark.svelte';
const path = $derived(pageState.url?.pathname ?? '/');
/** Page slug for body class: "page-home" | "page-services" | "page-services-hands-on-saas-architecture-consultant" etc. Set at build time per route; no client JS. */
const bodyClass = $derived(
path === '/'
? 'page-home'
: 'page-' + path.replace(/^\/|\/$/g, '').replace(/\//g, '-'),
);
interface NavigationItem {
label: string;
href: string;
umamiEventLabel: string;
}
const { items = [], page }: { items: NavigationItem[]; page: string } = $props();
</script>
<nav id="nav" class="nav" aria-label="Main navigation">
@@ -11,7 +29,9 @@
hidden
/>
<div class="mobile-nav-header">
<span class="mobile nav-header-logo">
<span
class={['mobile nav-header-logo', { 'page-home': bodyClass === 'page-home' }]}
>
<Wordmark />
</span>
<button
@@ -37,42 +57,35 @@
</button>
</div>
<div id="nav-menu" class="nav-menu container">
<span class="nav-header-logo desktop">
<Wordmark />
<span
class={[
'nav-header-logo desktop',
{ 'page-home': bodyClass === 'page-home' },
]}
>
{#if page !== 'home'}
<a href="/">
<Wordmark />
<span class="sr-only">mifi Ventures home page</span>
</a>
{:else}
<Wordmark />
{/if}
</span>
<ul class="nav-list">
<li class="nav-item">
<a
href="#what-we-do"
class="nav-link"
data-umami-event="navigation"
data-umami-event-label="services">Services</a
>
</li>
<li class="nav-item">
<a
href="#impact"
class="nav-link"
data-umami-event="navigation"
data-umami-event-label="impact">Impact</a
>
</li>
<li class="nav-item">
<a
href="#how-we-work"
class="nav-link"
data-umami-event="navigation"
data-umami-event-label="process">Process</a
>
</li>
<li class="nav-item">
<a
href="#schedule"
class="nav-link"
data-umami-event="navigation"
data-umami-event-label="contact">Contact</a
>
</li>
{#each items as item (item.href)}
<li class="nav-item">
<a
href={item.href}
class="nav-link"
data-umami-event="navigation"
data-umami-event-label={item.umamiEventLabel}
data-umami-event-page={page}
>
{item.label}
</a>
</li>
{/each}
</ul>
<div class="nav-item nav-back-to-top">
<a
@@ -246,7 +259,7 @@
.nav-list {
display: flex;
justify-content: center;
justify-content: space-between;
align-items: center;
list-style: none;
padding: 0;
@@ -259,7 +272,7 @@
/* Back to top + mobile nav logo: hidden until page is scrolled (CSS scroll-driven animation) */
.nav-back-to-top,
.nav-header-logo {
.nav-header-logo.page-home {
/* Fallback when scroll-driven animations arent supported: always visible */
opacity: 1;
visibility: visible;
@@ -362,7 +375,7 @@
/* Composited-only animation: opacity only (visibility/pointer-events not animated) */
.nav-back-to-top,
.nav-header-logo {
.nav-header-logo.page-home {
opacity: 0;
animation: nav-reveal-on-scroll linear;
animation-timeline: scroll(root block);

View File

@@ -1,27 +1,65 @@
<script lang="ts">
import ExternalLinkIcon from './Icon/ExternalLink.svelte';
const {
title,
subtitle,
bookingLinkTitle,
bookingLinkUrl = 'https://cal.mifi.ventures/the-mifi/30min',
showEmailLink = false,
showServicesLink = false,
sectionId = 'contact',
headingId = 'contact-heading',
}: {
title: string;
subtitle: string;
bookingLinkTitle: string;
bookingLinkUrl?: string;
showEmailLink?: boolean;
showServicesLink?: boolean;
sectionId?: string;
headingId?: string;
} = $props();
</script>
<section
id="schedule"
class="section schedule-section"
aria-labelledby="schedule-heading"
>
<section id={sectionId} class="section schedule-section" aria-labelledby={headingId}>
<div class="container">
<h2 id="schedule-heading" class="section-title">Let's Talk</h2>
<p class="schedule-text">Ready to discuss your project?</p>
<a
href="https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_medium=schedule_section_cta"
class="btn btn-primary icon-button"
target="_blank"
rel="noopener noreferrer"
aria-label="Schedule a 30-minute intro call (opens in new tab)"
data-umami-event="schedule call"
data-umami-event-location="schedule section"
>
Schedule a 30-minute intro call
<ExternalLinkIcon aria-label="Opens in new tab" size={17} />
</a>
<h2 id={headingId} class="section-title">{title}</h2>
<p class="schedule-text">{subtitle}</p>
<div class="cta-group">
<a
href={bookingLinkUrl}
class="btn btn-primary icon-button"
target="_blank"
rel="noopener noreferrer"
aria-label="Schedule a 30-minute intro call (opens in new tab)"
data-umami-event="schedule call"
data-umami-event-location="contact section"
>
{bookingLinkTitle}
<ExternalLinkIcon aria-label="Opens in new tab" size={17} />
</a>
{#if showEmailLink}
<a
href="mailto:hello@mifi.ventures"
class="btn btn-secondary"
data-umami-event="email"
data-umami-event-location="contact section"
>
Email me
</a>
{/if}
{#if showServicesLink}
<a
href="/services"
class="btn btn-secondary"
data-umami-event="view services"
data-umami-event-location="contact section"
>
View services
</a>
{/if}
</div>
</div>
</section>
@@ -37,10 +75,23 @@
font-weight: var(--font-weight-normal);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
max-width: 100%;
max-width: var(--max-text-width);
margin-left: auto;
margin-right: auto;
}
.btn {
margin: 0 auto;
.cta-group {
display: flex;
flex-wrap: wrap;
gap: var(--space-md);
justify-content: center;
align-items: center;
}
@media (max-width: 768px) {
.cta-group {
flex-direction: column;
width: 100%;
}
}
</style>

View File

@@ -0,0 +1,82 @@
<script lang="ts">
import type { ServiceSectionContent } from '$lib/types/service-page';
const {
section,
}: {
section: ServiceSectionContent;
} = $props();
const headingId = $derived(section.headingId ?? `${section.id}-heading`);
const sectionClasses = $derived(
['section', section.sectionClass].filter(Boolean).join(' '),
);
const containerClass = $derived(
section.narrowContainer === false ? 'container' : 'container narrow',
);
const listClass = $derived(
[section.bulletsListClass, 'content-list'].filter(Boolean).join(' '),
);
</script>
<section id={section.id} class={sectionClasses} aria-labelledby={headingId}>
<div class={containerClass}>
<h2 id={headingId} class={{ 'sr-only': section.headingSrOnly ?? false }}>
{section.heading}
</h2>
{#if section.lede}
<p>{section.lede}</p>
{/if}
{#each section.paragraphs ?? [] as p}
<p>{p}</p>
{/each}
{#each section.subsections ?? [] as sub, subIndex}
{@const subId = sub.headingId ?? `${section.id}-sub-${subIndex}`}
<h3 id={subId}>{sub.heading}</h3>
{#each sub.paragraphs ?? [] as p}
<p>{p}</p>
{/each}
{#if (sub.bullets?.length ?? 0) > 0}
<ul class="content-list">
{#each sub.bullets as bullet}
<li>{bullet}</li>
{/each}
</ul>
{/if}
{/each}
{#if (section.bullets?.length ?? 0) > 0}
<ul class={listClass}>
{#each section.bullets as bullet}
<li>{bullet}</li>
{/each}
</ul>
{/if}
{#if (section.orderedBullets?.length ?? 0) > 0}
<ol class="content-list ordered">
{#each section.orderedBullets as bullet}
<li>{bullet}</li>
{/each}
</ol>
{/if}
{#each section.trailingParagraphs ?? [] as p}
<p>{p}</p>
{/each}
{#if (section.footerLinks?.length ?? 0) > 0}
<p>
{#each section.footerLinks as link, i}
{#if i > 0}
<span aria-hidden="true"> · </span>
{/if}
<a href={link.href}>{link.label}</a>
{/each}
</p>
{/if}
</div>
</section>

View File

@@ -0,0 +1,115 @@
<script lang="ts">
import type { ServiceCard } from '$lib/types/service-page';
const {
services,
sectionId = 'services-grid',
headingId = 'services-heading',
heading = 'Services',
overview = '',
surface = 'bg',
}: {
services: ServiceCard[];
sectionId?: string;
headingId?: string;
heading?: string;
overview?: string;
surface?: 'bg' | 'bg-alt';
} = $props();
</script>
<section
id={sectionId}
class={['section services-grid-section', { 'bg-alt': surface === 'bg-alt' }]}
aria-labelledby={headingId}
>
<div class="container">
<h2 id={headingId} class="section-title">{heading}</h2>
{#if overview}
<p class="overview">{overview}</p>
{/if}
<ul class="services-card-list">
{#each services as service (service.href)}
<li class={['services-card', { bg: surface === 'bg-alt' }]}>
<h3 class="title">{service.title}</h3>
<p class="desc">{service.description}</p>
<a
href={service.href}
class="link"
data-umami-event="service link"
data-umami-event-label={service.href}
>
Learn more
<span aria-hidden="true"></span>
</a>
</li>
{/each}
</ul>
</div>
</section>
<style>
.services-grid-section {
background-color: var(--color-bg);
&.bg-alt {
background-color: var(--color-bg-alt);
}
}
.overview {
max-width: var(--max-text-width);
margin: 0 auto var(--space-xxl) auto;
font-size: var(--font-size-base);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
text-align: center;
}
.services-card-list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: var(--space-xl);
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.services-card {
padding: var(--space-xl);
background-color: var(--color-bg-alt);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-medium);
display: flex;
flex-direction: column;
&.bg {
background-color: var(--color-bg);
}
}
.title {
margin-bottom: var(--space-md);
font-size: var(--font-size-large);
font-weight: var(--font-weight-semibold);
}
.desc {
flex: 1;
margin-bottom: var(--space-lg);
font-size: var(--font-size-base);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
}
.link {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
font-weight: var(--font-weight-semibold);
& span {
margin-left: var(--space-xs);
}
}
</style>

View File

@@ -0,0 +1,58 @@
<script lang="ts">
interface TOCItem {
label: string;
href: string;
}
const {
ariaLabel = 'Page contents',
items,
title = 'On this page',
}: {
ariaLabel?: string;
items: TOCItem[];
title?: string;
} = $props();
</script>
<nav class="section toc" aria-label={ariaLabel}>
<div class="container">
<h2 class="title">{title}</h2>
<ul class="list">
{#each items as item}
<li><a href={item.href}>{item.label}</a></li>
{/each}
</ul>
</div>
</nav>
<style>
.toc {
padding: var(--space-xl) 0;
border-bottom: 1px solid var(--color-border);
}
.title {
font-size: var(--font-size-large);
font-weight: var(--font-weight-semibold);
margin-bottom: var(--space-md);
}
.list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
gap: var(--space-sm) var(--space-xl);
& a {
color: var(--color-text-secondary);
font-size: var(--font-size-medium);
&:hover {
color: var(--color-primary);
}
}
}
</style>

View File

@@ -1,14 +0,0 @@
<script lang="ts">
import { whatWeDoItems } from '$lib/data/content';
</script>
<section id="what-we-do" class="section" aria-labelledby="what-we-do-heading">
<div class="container">
<h2 id="what-we-do-heading" class="section-title">What We Do</h2>
<ul class="content-list">
{#each whatWeDoItems as item (item)}
<li>{item}</li>
{/each}
</ul>
</div>
</section>

View File

@@ -0,0 +1,59 @@
<script lang="ts">
const {
showTitle = false,
title = 'Who this is for',
whoForList,
whoNotList,
whoForHeading = 'Good fit',
whoNotHeading = 'Who this is not for',
}: {
title?: string;
showTitle?: boolean;
whoForList: string[];
whoNotList: string[];
whoForHeading?: string;
whoNotHeading?: string;
} = $props();
</script>
<section id="who-its-for" class="section" aria-labelledby="who-for-heading">
<div class="container">
<h2 id="who-for-heading" class={['title', { 'sr-only': !showTitle }]}>{title}</h2>
<div class="who-grid">
<div class="who-block">
<h3 id="who-for-list-heading" class="list-heading">{whoForHeading}</h3>
<ul class="content-list" aria-labelledby="who-for-list-heading">
{#each whoForList as item, index (index)}
<li>{item}</li>
{/each}
</ul>
</div>
<div class="who-block">
<h3 id="who-not-list-heading" class="list-heading">{whoNotHeading}</h3>
<ul class="content-list" aria-labelledby="who-not-list-heading">
{#each whoNotList as item, index (index)}
<li>{item}</li>
{/each}
</ul>
</div>
</div>
</div>
</section>
<style>
.who-grid {
display: grid;
gap: var(--space-xxl);
grid-template-columns: 1fr 1fr;
@media (max-width: 768px) {
grid-template-columns: 1fr;
}
}
.title,
.list-heading {
font-size: var(--font-size-xl);
margin-bottom: var(--space-md);
}
</style>

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { engagements } from '$lib/data/engagements';
import { engagements } from '$lib/data/home/engagements';
</script>
<section id="engagements" class="section" aria-labelledby="engagements-heading">

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { experienceLogos, experienceTextList } from '$lib/data/experience';
import { experienceLogos, experienceTextList } from '$lib/data/home/experience';
</script>
<section

View File

@@ -0,0 +1,101 @@
<script lang="ts">
import ExternalLinkIcon from '$lib/components/Icon/ExternalLink.svelte';
import Logo from '$lib/components/Logo.svelte';
</script>
<header id="header" class="hero">
<div class="container">
<Logo />
<h2 class="headline">Hands-On Product Architecture for Early-Stage SaaS</h2>
<p class="subhead">
I help SaaS teams ship quickly without creating frontend debt, architectural
drift, or technical complexity that slows iteration later.
</p>
<p class="supporting">
Mike Fitzpatrick — product architect and senior software engineer
</p>
<div class="cta-group">
<a
href="https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=hero"
class="btn btn-primary icon-button"
target="_blank"
rel="noopener noreferrer"
aria-label="Schedule a 30-minute intro call (opens in new tab)"
data-umami-event="schedule call"
data-umami-event-location="hero"
>
Schedule a 30-minute intro call
<ExternalLinkIcon aria-label="Opens in new tab" size={17} />
</a>
<a
href="/services"
class="btn btn-secondary"
data-umami-event="view services"
data-umami-event-location="hero"
>
View services
</a>
</div>
</div>
</header>
<style>
.hero {
padding: var(--space-xxxl) 0 var(--space-xxl) 0;
text-align: center;
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
@media (max-width: 768px) {
padding: var(--space-xxl) 0 var(--space-xl) 0;
}
@media (max-width: 480px) {
padding: var(--space-xl) 0 var(--space-lg) 0;
}
}
.headline {
margin-bottom: var(--space-lg);
font-family: var(--font-family-heading);
font-size: var(--font-size-xxl);
font-weight: var(--font-weight-bold);
letter-spacing: -0.03em;
color: var(--color-text);
line-height: var(--line-height-heading);
@media (max-width: 768px) {
font-size: var(--font-size-xl);
}
}
.subhead {
max-width: var(--max-narrow-width);
margin: 0 auto var(--space-md) auto;
font-size: var(--font-size-large);
font-weight: var(--font-weight-normal);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
}
.supporting {
margin: 0 auto var(--space-xl) auto;
font-size: var(--font-size-base);
font-weight: var(--font-weight-medium);
color: var(--color-text-tertiary);
}
.cta-group {
display: flex;
flex-wrap: wrap;
gap: var(--space-md);
justify-content: center;
align-items: center;
margin-top: var(--space-lg);
@media (max-width: 768px) {
flex-direction: column;
width: 100%;
}
}
</style>

View File

@@ -0,0 +1,14 @@
<script lang="ts">
import { howIWorkItems } from '$lib/data/home/content';
</script>
<section id="process" class="section" aria-labelledby="process-heading">
<div class="container">
<h2 id="process-heading" class="section-title">How I Work</h2>
<ul class="content-list">
{#each howIWorkItems as item (item)}
<li>{item}</li>
{/each}
</ul>
</div>
</section>

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { impactItems } from '$lib/data/content';
import { impactItems } from '$lib/data/home/content';
</script>
<section id="impact" class="section" aria-labelledby="impact-heading">

View File

@@ -0,0 +1,25 @@
<script lang="ts">
import {
whatIHelpTeamsFixIntro,
whatIHelpTeamsFixItems,
} from '$lib/data/home/content';
</script>
<section id="what-i-help-fix" class="section" aria-labelledby="what-i-help-fix-heading">
<div class="container">
<h2 id="what-i-help-fix-heading" class="section-title">What I Help Teams Fix</h2>
<p class="what-fix-intro">{whatIHelpTeamsFixIntro}</p>
<ul class="content-list">
{#each whatIHelpTeamsFixItems as item (item)}
<li>{item}</li>
{/each}
</ul>
</div>
</section>
<style>
.what-fix-intro {
max-width: var(--max-text-width);
margin: 0 auto var(--space-lg) auto;
}
</style>