diff --git a/app/blog/[slug]/page.module.css b/app/blog/[slug]/page.module.css index 31557fd..dd798f7 100644 --- a/app/blog/[slug]/page.module.css +++ b/app/blog/[slug]/page.module.css @@ -1,5 +1,9 @@ .subtitle { - font-size: 0.83255rem; + font-family: var(--font-mono); + font-variant-ligatures: none; + font-size: 0.78rem; + letter-spacing: 0.01em; + color: var(--color-terminal-dim); line-height: 1.75rem; display: block; margin-bottom: 1.75rem; diff --git a/app/globals.css b/app/globals.css index f65f1e7..96a0dc5 100644 --- a/app/globals.css +++ b/app/globals.css @@ -7,7 +7,15 @@ --color-inline-code-text: #e6e6e6; --color-shadow: rgba(140, 160, 227, 0.6); --color-text-body: rgba(255, 255, 255, 0.88); - --font-mono: Consolas, Menlo, Monaco, source-code-pro, Courier New, monospace; + + /* Retro terminal accents (reuse the existing palette) */ + --color-terminal: var(--color-accent); + --color-terminal-dim: rgba(255, 255, 255, 0.5); + + --font-mono: + var(--font-mono-display), 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, + Consolas, Monaco, 'Courier New', monospace; + --font-display: var(--font-mono); } html { @@ -363,10 +371,11 @@ h4, h5, h6 { margin-top: 3rem; - font-family: var(--font-montserrat); + font-family: var(--font-display); color: inherit; text-rendering: optimizeLegibility; - font-weight: 300; + font-weight: 400; + letter-spacing: -0.01em; } hr:has(+ h1), hr:has(+ h2), @@ -379,7 +388,7 @@ hr:has(+ h6) { h1 { margin-bottom: 1.75rem; - font-family: var(--font-montserrat); + font-family: var(--font-display); font-size: 2rem; line-height: 1.2; } diff --git a/app/layout.tsx b/app/layout.tsx index ef320e3..78def14 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,4 +1,4 @@ -import { Montserrat, Plus_Jakarta_Sans } from 'next/font/google' +import { IBM_Plex_Mono, Plus_Jakarta_Sans } from 'next/font/google' import Script from 'next/script' import { Suspense } from 'react' @@ -19,10 +19,11 @@ const jakarta = Plus_Jakarta_Sans({ display: 'swap', }) -const montserrat = Montserrat({ +const plexMono = IBM_Plex_Mono({ subsets: ['latin'], - weight: ['300'], - variable: '--font-montserrat', + weight: ['300', '400', '500', '600'], + style: ['normal', 'italic'], + variable: '--font-mono-display', display: 'swap', }) @@ -30,7 +31,7 @@ export const metadata = getBaseMetadata() export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - +
diff --git a/app/page.module.css b/app/page.module.css index c162367..71262b5 100644 --- a/app/page.module.css +++ b/app/page.module.css @@ -1,7 +1,10 @@ .label { display: block; - font-size: 0.85rem; /* Match subtitle */ - color: var(--color-accent); + font-family: var(--font-mono); + font-variant-ligatures: none; + font-size: 0.78rem; + letter-spacing: 0.08em; + color: var(--color-terminal); margin-bottom: 1rem; opacity: 0.85; } diff --git a/app/stream/page.module.css b/app/stream/page.module.css index 1a539fa..a55b4a2 100644 --- a/app/stream/page.module.css +++ b/app/stream/page.module.css @@ -34,8 +34,10 @@ } .date { - font-size: 0.8rem; - color: rgba(255, 255, 255, 0.5); + font-family: var(--font-mono); + font-variant-ligatures: none; + font-size: 0.72rem; + color: var(--color-terminal-dim); font-variant-numeric: tabular-nums; white-space: nowrap; } @@ -46,7 +48,9 @@ } .tag { - font-size: 0.65rem; + font-family: var(--font-mono); + font-variant-ligatures: none; + font-size: 0.62rem; color: rgba(255, 255, 255, 0.4); text-transform: uppercase; letter-spacing: 0.05em; @@ -68,4 +72,3 @@ font-size: 0.7rem; } } - diff --git a/components/FeedItem.module.css b/components/FeedItem.module.css index 85945c5..ca61520 100644 --- a/components/FeedItem.module.css +++ b/components/FeedItem.module.css @@ -43,7 +43,12 @@ } .subtitle { - opacity: 0.85; + font-family: var(--font-mono); + font-variant-ligatures: none; + font-size: 0.74rem; + letter-spacing: 0.01em; + color: var(--color-terminal-dim); + opacity: 0.95; } .description { diff --git a/components/Footer.module.css b/components/Footer.module.css index ab7810f..ed7cfe7 100644 --- a/components/Footer.module.css +++ b/components/Footer.module.css @@ -7,7 +7,7 @@ } .footerInner { - padding: 30px; + padding: 30px 30px 12px; font-size: 10px; display: flex; align-items: center; @@ -15,6 +15,21 @@ gap: 20px; } +.signature { + padding: 0 30px 30px; + text-align: center; + font-family: var(--font-mono); + font-variant-ligatures: none; + font-size: 0.72rem; + letter-spacing: 0.02em; + color: var(--color-terminal-dim); +} + +.prompt { + color: var(--color-accent); + margin-right: 0.25em; +} + .svgIcon { height: 30px; fill: #aaa; diff --git a/components/Footer.tsx b/components/Footer.tsx index 3a29d5e..7fb01a2 100644 --- a/components/Footer.tsx +++ b/components/Footer.tsx @@ -76,6 +76,10 @@ export function Footer() { + +
+ $ by Kenneth Skovhus +
) } diff --git a/components/Header.module.css b/components/Header.module.css index cd9c3cf..47e263c 100644 --- a/components/Header.module.css +++ b/components/Header.module.css @@ -27,40 +27,69 @@ color: white; display: flex; align-items: center; + gap: 12px; height: 60px; + font-family: var(--font-mono); + font-variant-ligatures: none; +} + +/* Terminal prompt: skovhus$ */ + +.prompt { + display: inline-flex; + align-items: baseline; + font-size: 15px; + letter-spacing: -0.01em; + text-decoration: none; + white-space: nowrap; + flex-shrink: 0; + opacity: 0.95; + transition: opacity 0.2s ease; +} + +.prompt:hover { + opacity: 1; +} + +.promptUser { + color: var(--color-terminal); +} + +.promptSign { + color: rgba(255, 255, 255, 0.9); } .navLinkContainer { display: flex; - gap: 10px; + gap: 6px; align-items: center; } .navLink { - font-size: 16px; + font-size: 15px; opacity: 0.5; text-decoration: none; - transition: opacity 0.2s ease; -} - -.navLinkActive { - opacity: 0.9; + padding: 2px 6px; + border-radius: 2px; + transition: + opacity 0.2s ease, + background-color 0.2s ease, + color 0.2s ease; } .navLink:hover { opacity: 1; } -.siteName { - letter-spacing: 0.02em; -} - -.siteName:hover { - opacity: 1 !important; +/* Active link rendered as a selected DOS-style menu cell */ +.navLinkActive { + opacity: 1; + color: var(--background-context-color); + background-color: var(--color-terminal); } -.showOnMobile { - display: none; +.navLinkActive:hover { + color: var(--background-context-color); } /* Mobile breakpoint: 500px - keep in sync with globals.css */ @@ -69,11 +98,24 @@ position: relative; } - .hideOnMobile { - display: none; + .nav { + gap: 6px; } - .showOnMobile { - display: inline; + .prompt { + font-size: 14px; + } + + .navLinkContainer { + gap: 3px; + } + + .navLink { + font-size: 14px; + padding: 2px 4px; + } + + .hideOnMobile { + display: none; } } diff --git a/components/Header.tsx b/components/Header.tsx index c7029bc..c6aabf2 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -3,8 +3,6 @@ import Link from 'next/link' import { usePathname } from 'next/navigation' import { type MouseEvent, useEffect, useState } from 'react' -import { getSlideAnimationProps } from '#/lib/slide-animation' - import styles from './Header.module.css' const pages = [ @@ -17,7 +15,6 @@ const pages = [ export function Header() { const pathname = usePathname() - const slideAnimation = getSlideAnimationProps({ stage: 0 }) const [scrollY, setScrollY] = useState(0) useEffect(() => { @@ -41,14 +38,21 @@ export function Header() { } const isScrolled = scrollY > 10 - const nameOpacity = Math.max(0.5, 1 - scrollY / 160) return (
-
)