diff --git a/site/index.html b/site/index.html index ccd745b..075bda9 100644 --- a/site/index.html +++ b/site/index.html @@ -320,6 +320,65 @@ Skip to main content + + + + + + + + + + + + + + + + + + + + + + Services + + + Impact + + + Process + + + Contact + + + + Back to top + + + + diff --git a/site/script.js b/site/script.js index 315ce48..72a8fb9 100644 --- a/site/script.js +++ b/site/script.js @@ -5,7 +5,7 @@ (function() { 'use strict'; - + // Update copyright year to current year // Script runs with defer, so DOM is always ready const yearElement = document.getElementById('copyright-year'); diff --git a/site/styles.css b/site/styles.css index d7ab5db..84df6e8 100644 --- a/site/styles.css +++ b/site/styles.css @@ -352,6 +352,285 @@ a:focus-visible { background-color: var(--color-bg-alt); } +/* ======================================== + Nav Section + ======================================== */ + +.nav { + background-color: var(--color-bg); + padding: var(--space-md) 0; + position: sticky; + text-align: center; + top: 0; + background-color: var(--color-bg); + border-bottom: 1px solid var(--color-border); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.6); + z-index: 100; +} + +.nav .container, +.nav .nav-menu { + display: grid; + grid-template-columns: 1fr auto 1fr; + justify-content: space-between; + align-items: center; +} + +.mobile-nav-header { + display: none; + justify-content: space-between; + align-items: center; +} + +/* Logo recolored to text color via mask (works for SVG in light/dark mode) */ +.nav-header-logo { + display: inline-block; + max-width: 250px; + background-color: var(--color-text); + -webkit-mask: url("/assets/wordmark.svg") center / contain no-repeat; + mask: url("/assets/wordmark.svg") center / contain no-repeat; + padding-left: var(--space-md); +} + +.nav-header-logo img { + display: block; + max-width: 100%; + width: 100%; + height: auto; + opacity: 0; + pointer-events: none; +} + +/* Hamburger toggle: mobile only, animates to X when open */ +.nav-toggle-input { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +.nav-toggle { + display: none; + align-items: center; + justify-content: flex-end; + flex: 0 0 auto; + padding: var(--space-sm) var(--space-md); + width: calc(24px + var(--space-md) + var(--space-md)); + height: calc(31px + var(--space-sm) + var(--space-sm)); + cursor: pointer; + color: var(--color-text); + background: transparent; + border: none; + border-radius: var(--space-xs); + transition: color 0.2s ease, background-color 0.2s ease; +} + +.nav-toggle:hover { + color: var(--color-primary); +} + +.nav-toggle:focus-visible { + outline: 4px solid var(--color-focus); + outline-offset: 4px; +} + +.nav-toggle-inner { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 24px; + height: 18px; +} + +.nav-toggle-line { + display: block; + width: 100%; + height: 2px; + background-color: currentColor; + border-radius: 1px; + transform-origin: center; + transition: transform 0.25s ease, opacity 0.2s ease; +} + +/* Hamburger → X when checked */ +.nav-toggle-input:checked + ~ .mobile-nav-header + .nav-toggle + .nav-toggle-line:nth-child(1) { + transform: translateY(8px) rotate(45deg); +} + +.nav-toggle-input:checked + ~ .mobile-nav-header + .nav-toggle + .nav-toggle-line:nth-child(2) { + opacity: 0; +} + +.nav-toggle-input:checked + ~ .mobile-nav-header + .nav-toggle + .nav-toggle-line:nth-child(3) { + transform: translateY(-8px) rotate(-45deg); +} + +/* Mobile: show toggle, collapse menu until opened; menu overlays content via anchor */ +@media (max-width: 768px) { + .nav { + display: flex; + flex-direction: column; + align-items: stretch; + } + + .nav-toggle { + display: flex; + } + + .mobile-nav-header { + display: flex; + anchor-name: --mobile-nav-header; + } + + .nav-header-logo.desktop { + display: none; + } + + .nav .nav-menu { + display: flex; + flex-direction: column; + align-items: stretch; + max-height: 0; + overflow: hidden; + opacity: 0; + padding-top: 0; + padding-bottom: 0; + border-top: none; + transition: max-height 0.3s ease, opacity 0.25s ease, padding 0.25s ease; + } + + .nav-toggle-input:checked ~ .nav-menu { + max-height: 80vh; + opacity: 1; + padding-top: var(--space-md); + padding-bottom: var(--space-md); + border-top: 1px solid var(--color-border); + } + + /* Overlay: position menu below header so it flows over content (no layout shift) */ + @supports (top: anchor(bottom)) { + .nav .nav-menu { + position: fixed; + position-anchor: --mobile-nav-header; + top: anchor(--mobile-nav-header bottom); + left: anchor(--mobile-nav-header left); + right: anchor(--mobile-nav-header right); + margin: 0; + overflow-y: auto; + background-color: var(--color-bg); + border-bottom: 1px solid var(--color-border); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + z-index: 99; + } + } + + .nav-menu .nav-list { + flex-direction: column; + gap: 0; + } + + .nav-menu .nav-item { + margin: 0; + text-align: center; + } + + .nav-menu .nav-item a, + .nav-menu .nav-back-to-top a { + display: block; + padding: var(--space-md); + } + + .nav-menu .nav-item a:hover { + border-bottom-color: transparent; + } + + .nav-list, + .nav-item { + width: 100%; + } + + @media (prefers-reduced-motion: reduce) { + .nav-toggle-line { + transition-duration: 0.01ms; + } + + .nav-menu { + transition-duration: 0.01ms; + } + } +} + +.nav-list { + display: flex; + justify-content: center; + align-items: center; + list-style: none; + padding: 0; + margin: 0; +} + +.nav-item { + margin: 0 var(--space-md); +} + +/* Back to top + mobile nav logo: hidden until page is scrolled (CSS scroll-driven animation) */ +.nav-back-to-top, +.nav-header-logo { + /* Fallback when scroll-driven animations aren’t supported: always visible */ + opacity: 1; + visibility: visible; +} + +@supports (animation-timeline: scroll()) { + .nav-back-to-top, + .nav-header-logo { + opacity: 0; + visibility: hidden; + pointer-events: none; + animation: nav-reveal-on-scroll linear; + animation-timeline: scroll(root block); + animation-range: 300px 400px; + animation-fill-mode: both; + } + + @keyframes nav-reveal-on-scroll { + from { + opacity: 0; + visibility: hidden; + pointer-events: none; + } + to { + opacity: 1; + visibility: visible; + pointer-events: auto; + } + } + + @media (prefers-reduced-motion: reduce) { + .nav-back-to-top, + .nav-header-logo { + animation: none; + opacity: 1; + visibility: visible; + pointer-events: auto; + } + } +} + /* ======================================== Header / Hero Section ======================================== */ @@ -773,7 +1052,7 @@ a:focus-visible { } /* ======================================== - Footer + Nav Items / Footer ======================================== */ .footer { @@ -798,6 +1077,7 @@ a:focus-visible { align-items: center; } +.nav-item a, .footer-links a { font-size: var(--font-size-medium); font-weight: var(--font-weight-medium); @@ -812,11 +1092,13 @@ a:focus-visible { align-items: center; } +.nav-item a:hover, .footer-links a:hover { color: var(--color-primary); border-bottom-color: var(--color-primary); } +.nav-item a:focus-visible, .footer-links a:focus-visible { outline: 4px solid var(--color-focus); outline-offset: 4px;