openvibers/afresume Commits

design: polish nav ice-glass, section headers, cards, timeline, skills, footer, marquee

OP OpenVibers committed 21 May 2026 · c8b153a614 · 11 files, +158 −66


Changes

ddiff --git a/src/components/ContactBlock.astro b/src/components/ContactBlock.astro
iindex aa1f6bc..5d55fec 100644
---- a/src/components/ContactBlock.astro
++++ b/src/components/ContactBlock.astro
@@@ -3,12 +3,13 @@
<section class="contact" id="contact">
<div class="container">
<div class="section-eyebrow"><i class="fa-solid fa-paper-plane"></i> Contact</div>
-- <h2 class="section-title"><i class="fa-solid fa-paper-plane"></i> Let's build something</h2>
++ <h2 class="section-title">Let's connect</h2>
<div class="contact__grid">
<div class="card contact__card">
<p class="contact__lead">
-- Open to data-analyst, software-engineering, and platform-builder roles
-- across the Pacific Northwest and remote. Always happy to chat shop.
++ Open to data analyst, software engineer, and platform builder roles &mdash;
++ Pacific Northwest, remote, or hybrid. Happy to talk tech, collaborate on
++ something interesting, or just say hi.
</p>
<div class="contact__direct">
@@@ -44,14 +45,9 @@
<style>
.contact__grid { display: grid; }
-- .section-title i {
-- color: var(--accent);
-- margin-right: 0.4rem;
-- font-size: 0.9em;
-- }
--
.contact__lead {
font-size: 1.1rem;
++ line-height: 1.7;
color: var(--fg);
margin-bottom: 1.8rem;
}
ddiff --git a/src/components/ExperienceTimeline.astro b/src/components/ExperienceTimeline.astro
iindex 946d93e..5603311 100644
---- a/src/components/ExperienceTimeline.astro
++++ b/src/components/ExperienceTimeline.astro
@@@ -6,13 +6,13 @@ const items = (await getCollection("experience"))
<section class="exp" id="experience">
<div class="container">
<div class="section-eyebrow"><i class="fa-solid fa-briefcase"></i> Experience</div>
-- <h2 class="section-title"><i class="fa-solid fa-timeline"></i> A decade-plus of building</h2>
++ <h2 class="section-title">A decade-plus of shipping</h2>
<ol class="exp__list">
{items.map((it) => (
<li class="exp__item card" data-reveal>
<div class="exp__dates">
<span class="exp__dot" aria-hidden="true"></span>
-- <span><i class="fa-regular fa-calendar-days"></i> {it.data.start} — {it.data.end}</span>
++ <span><i class="fa-regular fa-calendar-days"></i> {it.data.start} — {it.data.end ?? 'Present'}</span>
</div>
<div class="exp__body">
<h3>{it.data.role}</h3>
@@@ -33,33 +33,49 @@ const items = (await getCollection("experience"))
</section>
<style>
-- .exp__list { list-style: none; padding: 0; margin: 0; display: grid; gap: 18px; }
++ .exp__list { list-style: none; padding: 0; margin: 0; display: grid; gap: 16px; }
.exp__item {
display: grid;
grid-template-columns: 200px 1fr;
-- gap: 20px;
++ gap: 24px;
++ align-items: start;
}
@media (max-width: 720px) {
-- .exp__item { grid-template-columns: 1fr; }
++ .exp__item { grid-template-columns: 1fr; gap: 10px; }
}
.exp__dates {
-- display: flex; align-items: center; gap: 10px;
++ display: flex;
++ flex-direction: column;
++ align-items: flex-start;
++ gap: 8px;
color: var(--muted);
font-family: var(--font-mono);
-- font-size: .9rem;
++ font-size: .8rem;
++ padding-top: 6px;
++ line-height: 1.6;
}
.exp__dot {
-- width: 10px; height: 10px; border-radius: 50%;
-- background: var(--accent); box-shadow: 0 0 14px var(--accent);
++ width: 9px; height: 9px; border-radius: 50%;
++ background: var(--accent);
++ box-shadow: 0 0 10px rgba(76,201,176,0.6), 0 0 24px rgba(76,201,176,0.25);
++ flex-shrink: 0;
++ }
++ .exp__body {
++ border-left: 2px solid rgba(76,201,176,0.15);
++ padding-left: 20px;
++ }
++ @media (max-width: 720px) {
++ .exp__body { border-left: none; padding-left: 0; border-top: 2px solid rgba(76,201,176,0.15); padding-top: 12px; }
}
.exp__body h3 {
font-family: var(--font-display);
-- font-size: 1.25rem; margin: 0 0 .3rem;
++ font-size: 1.2rem; margin: 0 0 .3rem;
}
-- .exp__company { color: var(--accent); margin-bottom: .8rem; font-weight: 600; }
++ .exp__company { color: var(--accent); margin-bottom: .8rem; font-size: 0.9rem; font-weight: 600; }
.exp__body ul {
margin: 0 0 1rem; padding-left: 1.1rem;
-- color: var(--muted); line-height: 1.7;
++ color: var(--muted); line-height: 1.75;
}
++ .exp__body ul li { margin-bottom: 0.25rem; }
.exp__stack { display: flex; flex-wrap: wrap; gap: 6px; }
</style>
ddiff --git a/src/components/Footer.astro b/src/components/Footer.astro
iindex 9a6bd47..c5fa195 100644
---- a/src/components/Footer.astro
++++ b/src/components/Footer.astro
@@@ -2,26 +2,67 @@
const year = new Date().getFullYear();
---
<footer class="foot">
-- <div class="container foot__row">
-- <small>© {year} Alex Frison · Built in the Pacific Northwest</small>
-- <small>
-- <a href="mailto:[email protected]"><i class="fa-solid fa-envelope"></i> [email protected]</a> ·
-- <a href="tel:+14253673997"><i class="fa-solid fa-phone"></i> (425) 367-3997</a> ·
-- <a href="https://github.com/HoboStreamer" rel="me noopener" target="_blank"><i class="fa-brands fa-github"></i></a> ·
-- <a href="https://www.linkedin.com/in/fris/" rel="me noopener" target="_blank"><i class="fa-brands fa-linkedin"></i></a>
-- </small>
++ <div class="container foot__inner">
++ <div class="foot__brand">
++ <span class="foot__name">Alex Frison</span>
++ <span class="foot__sub">&copy; {year} &middot; Built in the Pacific Northwest</span>
++ </div>
++ <div class="foot__links">
++ <a href="mailto:[email protected]" title="Email"><i class="fa-solid fa-envelope"></i> [email protected]</a>
++ <a href="tel:+14253673997" title="Phone"><i class="fa-solid fa-phone"></i> (425) 367-3997</a>
++ <a href="https://github.com/HoboStreamer" rel="me noopener" target="_blank" title="GitHub"><i class="fa-brands fa-github"></i> GitHub</a>
++ <a href="https://www.linkedin.com/in/fris/" rel="me noopener" target="_blank" title="LinkedIn"><i class="fa-brands fa-linkedin"></i> LinkedIn</a>
++ </div>
</div>
</footer>
<style>
.foot {
border-top: 1px solid var(--border);
-- padding: 28px 0;
++ padding: 40px 0;
color: var(--dim);
++ background: linear-gradient(to top, rgba(76,201,176,0.02), transparent);
}
-- .foot__row {
-- display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px;
++ .foot__inner {
++ display: flex;
++ justify-content: space-between;
++ align-items: center;
++ flex-wrap: wrap;
++ gap: 20px;
++ }
++ .foot__brand {
++ display: flex;
++ flex-direction: column;
++ gap: 3px;
++ }
++ .foot__name {
++ font-family: var(--font-display);
++ font-weight: 700;
++ font-size: 1rem;
++ color: var(--fg);
++ letter-spacing: -0.01em;
++ }
++ .foot__sub {
++ font-size: 0.8rem;
++ color: var(--muted);
++ }
++ .foot__links {
++ display: flex;
++ flex-wrap: wrap;
++ gap: 10px 24px;
++ align-items: center;
++ }
++ .foot a {
++ color: var(--muted);
++ font-size: 0.85rem;
++ display: inline-flex;
++ align-items: center;
++ gap: 6px;
++ transition: color .2s;
++ text-decoration: none;
}
-- .foot a { color: var(--muted); transition: color .2s; }
.foot a:hover { color: var(--accent); }
-- .foot a i { font-size: 0.9rem; }
++ .foot a i { font-size: 0.9em; }
++ @media (max-width: 540px) {
++ .foot__inner { flex-direction: column; align-items: flex-start; }
++ }
</style>
ddiff --git a/src/components/ImpactMetrics.astro b/src/components/ImpactMetrics.astro
iindex d259e31..dabb9e1 100644
---- a/src/components/ImpactMetrics.astro
++++ b/src/components/ImpactMetrics.astro
@@@ -48,9 +48,9 @@ const metrics = [
transition: transform .25s ease, border-color .25s ease, box-shadow .25s ease;
}
.impact__card:hover {
-- transform: translateY(-3px);
-- border-color: var(--accent);
-- box-shadow: 0 12px 28px -16px color-mix(in srgb, var(--accent) 55%, transparent);
++ transform: translateY(-4px);
++ border-color: rgba(76,201,176,0.35);
++ box-shadow: 0 12px 40px -12px rgba(76,201,176,0.3), 0 0 0 1px rgba(76,201,176,0.08);
}
.impact__icon {
font-size: 1.05rem;
@@@ -64,7 +64,7 @@ const metrics = [
font-family: var(--font-display);
font-size: clamp(1.7rem, 2.6vw, 2.1rem);
font-weight: 700;
-- color: var(--text);
++ color: var(--fg);
line-height: 1.05;
}
.impact__lbl {
ddiff --git a/src/components/Marquee.astro b/src/components/Marquee.astro
iindex 907f375..29f2f45 100644
---- a/src/components/Marquee.astro
++++ b/src/components/Marquee.astro
@@@ -19,15 +19,20 @@ const tech = [
backdrop-filter: blur(8px);
}
.marquee__track {
-- display: flex; gap: 56px; padding: 18px 0;
++ display: flex; gap: 0; padding: 16px 0;
width: max-content;
animation: scroll 80s linear infinite;
font-family: var(--font-mono);
color: var(--muted);
-- font-size: .95rem;
++ font-size: .88rem;
letter-spacing: 0.04em;
}
-- .marquee__track span { white-space: nowrap; }
++ .marquee__track span {
++ white-space: nowrap;
++ padding: 0 28px;
++ border-right: 1px solid var(--border);
++ }
++ .marquee__track span:last-child { border-right: none; }
@media (hover: hover) {
.marquee:hover .marquee__track { animation-play-state: paused; }
}
ddiff --git a/src/components/Nav.astro b/src/components/Nav.astro
iindex a527d2d..ac10206 100644
---- a/src/components/Nav.astro
++++ b/src/components/Nav.astro
@@@ -54,14 +54,31 @@ const links = [
border-bottom: 1px solid transparent;
backdrop-filter: none;
-webkit-backdrop-filter: none;
-- transition: background .35s ease, border-color .35s ease;
++ transition: background .4s ease, border-color .4s ease, box-shadow .4s ease;
will-change: background;
}
++ /* Frosted ice-glass on scroll */
.nav--scrolled {
-- backdrop-filter: blur(14px);
-- -webkit-backdrop-filter: blur(14px);
-- background: color-mix(in oklab, var(--bg) 78%, transparent);
-- border-bottom: 1px solid var(--border);
++ backdrop-filter: blur(24px) saturate(180%);
++ -webkit-backdrop-filter: blur(24px) saturate(180%);
++ background: color-mix(in oklab, var(--bg) 68%, transparent);
++ border-bottom: 1px solid rgba(255, 255, 255, 0.07);
++ box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.04), 0 8px 40px rgba(0, 0, 0, 0.38);
++ }
++ /* Brighter links when floating over hero (transparent state) */
++ .nav:not(.nav--scrolled) .nav__links a {
++ color: rgba(230, 237, 243, 0.88);
++ }
++ .nav:not(.nav--scrolled) .nav__links a:hover {
++ color: #fff;
++ }
++ .nav:not(.nav--scrolled) .nav__brand {
++ color: var(--fg);
++ }
++ .nav:not(.nav--scrolled) .nav__toggle,
++ .nav:not(.nav--scrolled) .nav__burger {
++ border-color: rgba(255, 255, 255, 0.15);
++ color: rgba(230, 237, 243, 0.8);
}
.nav__row {
display: flex; align-items: center; gap: 16px;
ddiff --git a/src/components/ProjectCarousel.astro b/src/components/ProjectCarousel.astro
iindex 9773d42..df814bb 100644
---- a/src/components/ProjectCarousel.astro
++++ b/src/components/ProjectCarousel.astro
@@@ -6,7 +6,7 @@ const featured = all.sort((a, b) => a.data.order - b.data.order);
<section class="featured" id="work">
<div class="container">
<div class="section-eyebrow"><i class="fa-solid fa-star"></i> Featured Work</div>
-- <h2 class="section-title"><i class="fa-solid fa-star"></i> Things I've shipped</h2>
++ <h2 class="section-title">Things I've shipped</h2>
<p class="featured__lead">
A rotating gallery of the products, tools, and agents I've built —
from Amazon ICQA analytics to the Hobo Network creator stack.
ddiff --git a/src/components/ProjectGrid.astro b/src/components/ProjectGrid.astro
iindex 3b12007..60a759b 100644
---- a/src/components/ProjectGrid.astro
++++ b/src/components/ProjectGrid.astro
@@@ -22,7 +22,7 @@ const filterIcon: Record<string, string> = {
<section class="grid-sec" id="portfolio">
<div class="container">
<div class="section-eyebrow"><i class="fa-solid fa-layer-group"></i> Portfolio</div>
-- <h2 class="section-title"><i class="fa-solid fa-layer-group"></i> All work</h2>
++ <h2 class="section-title">All work</h2>
<div class="filters" role="tablist">
{cats.map((c, i) => (
<button class={`filter ${i === 0 ? "is-active" : ""}`} data-filter={c} role="tab">
ddiff --git a/src/components/SkillsGrid.astro b/src/components/SkillsGrid.astro
iindex 6de794f..37d1f35 100644
---- a/src/components/SkillsGrid.astro
++++ b/src/components/SkillsGrid.astro
@@@ -5,7 +5,7 @@ const groups = (await getCollection("skills")).sort((a, b) => a.data.order - b.d
<section class="skills" id="skills">
<div class="container">
<div class="section-eyebrow"><i class="fa-solid fa-code"></i> Stack</div>
-- <h2 class="section-title"><i class="fa-solid fa-code"></i> Skills & tooling</h2>
++ <h2 class="section-title">Skills & stack</h2>
<div class="skills__grid">
{groups.map((g) => (
<article class="card skills__card" data-reveal>
@@@ -28,23 +28,32 @@ const groups = (await getCollection("skills")).sort((a, b) => a.data.order - b.d
display: grid; gap: 18px;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
++ .skills__card {
++ border-top: 2px solid rgba(76,201,176,0.25) !important;
++ }
.skills__card h3 {
font-family: var(--font-display);
-- font-size: 1.05rem;
++ font-size: 1rem;
++ font-weight: 700;
color: var(--accent);
margin-bottom: 1rem;
++ letter-spacing: 0.01em;
}
.skills__card ul { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.skills__item {
-- padding: 6px 12px;
++ padding: 5px 12px;
border-radius: 8px;
border: 1px solid var(--border);
-- font: 500 .85rem var(--font-body);
++ font: 500 .83rem var(--font-body);
color: var(--fg);
background: rgba(255,255,255,0.02);
-- transition: transform .2s var(--ease), border-color .2s var(--ease);
++ transition: transform .2s var(--ease), border-color .2s var(--ease), background .2s var(--ease);
++ }
++ .skills__item:hover { transform: translateY(-2px); border-color: rgba(76,201,176,0.4); background: rgba(76,201,176,0.05); }
++ .skills__item--core {
++ border-color: rgba(76,201,176,.32);
++ color: var(--accent);
++ background: rgba(76,201,176,.06);
}
-- .skills__item:hover { transform: translateY(-2px); border-color: var(--accent); }
-- .skills__item--core { border-color: rgba(76,201,176,.35); color: var(--accent); }
-- .skills__item--familiar { color: var(--dim); }
++ .skills__item--familiar { color: var(--dim); border-color: var(--border); }
</style>
ddiff --git a/src/pages/index.astro b/src/pages/index.astro
iindex 159ef64..2d9a914 100644
---- a/src/pages/index.astro
++++ b/src/pages/index.astro
@@@ -18,7 +18,7 @@ import ContactBlock from "../components/ContactBlock.astro";
<div class="container profile__row">
<div data-reveal>
<div class="section-eyebrow"><i class="fa-solid fa-user"></i> Profile</div>
-- <h2 class="section-title"><i class="fa-solid fa-user"></i> A versatile builder</h2>
++ <h2 class="section-title">A versatile builder</h2>
<p class="profile-para">
<i class="fa-solid fa-microchip profile-para__icon"></i>
<span>Data analyst and systems architect with 10+ years of shipping — from
ddiff --git a/src/styles/global.css b/src/styles/global.css
iindex 75c8acc..25d099f 100644
---- a/src/styles/global.css
++++ b/src/styles/global.css
@@@ -114,7 +114,11 @@ section { padding: clamp(60px, 10vw, 120px) 0; position: relative; }
box-shadow: var(--shadow-card);
transition: transform .3s var(--ease), border-color .3s var(--ease), box-shadow .3s var(--ease);
}
--.card:hover { border-color: var(--border-strong); transform: translateY(-3px); }
++.card:hover {
++ border-color: rgba(76, 201, 176, 0.3);
++ transform: translateY(-4px);
++ box-shadow: var(--shadow-card), 0 0 0 1px rgba(76,201,176,0.08), 0 12px 48px -8px rgba(76,201,176,0.18);
++}
.btn {
display: inline-flex; align-items: center; gap: 10px;
@@@ -128,19 +132,22 @@ section { padding: clamp(60px, 10vw, 120px) 0; position: relative; }
transition: all .25s var(--ease);
text-decoration: none;
}
--.btn:hover { background: var(--surface-2); transform: translateY(-2px); text-decoration: none; }
--.btn--primary { background: var(--accent); color: #06221c; border-color: transparent; }
--.btn--primary:hover { background: #5fdcc4; box-shadow: var(--shadow-glow); }
++.btn:hover { background: var(--surface-2); transform: translateY(-2px); text-decoration: none; border-color: var(--border-strong); }
++.btn--primary { background: var(--accent); color: #06221c; border-color: transparent; font-weight: 700; letter-spacing: 0.01em; }
++.btn--primary:hover { background: #5fdcc4; box-shadow: var(--shadow-glow), 0 6px 24px rgba(76,201,176,0.25); transform: translateY(-2px); }
.chip {
display: inline-flex; align-items: center; gap: 5px;
-- padding: 4px 10px;
++ padding: 4px 12px;
border-radius: 999px;
-- font: 500 0.78rem var(--font-mono);
-- background: rgba(76, 201, 176, 0.08);
-- border: 1px solid rgba(76, 201, 176, 0.2);
++ font: 500 0.75rem var(--font-mono);
++ background: rgba(76, 201, 176, 0.07);
++ border: 1px solid rgba(76, 201, 176, 0.22);
color: var(--accent);
++ letter-spacing: 0.03em;
++ transition: background .2s var(--ease), border-color .2s var(--ease);
}
++.chip:hover { background: rgba(76, 201, 176, 0.14); border-color: rgba(76, 201, 176, 0.38); }
.chip i { font-size: 0.75em; }
.skip-link {
@@@ -153,6 +160,7 @@ section { padding: clamp(60px, 10vw, 120px) 0; position: relative; }
/* Reveal — initial hidden state only; animation driven by JS (Web Animations API) */
[data-reveal] {
opacity: 0;
-- transform: translateY(24px);
++ transform: translateY(28px);
++ transition: opacity .55s var(--ease), transform .55s var(--ease);
}
[data-reveal].in { opacity: 1; transform: none; }