diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index b7e6a91..4f3f3c8 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -15,13 +15,24 @@ export const metadata: Metadata = {
],
};
+const themeScript = `
+ try {
+ const savedTheme = localStorage.getItem('portfolio-theme');
+ const systemTheme = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
+ document.documentElement.dataset.theme = savedTheme || systemTheme;
+ } catch {}
+`;
+
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
-
+
+
+
+
{children}
diff --git a/src/context/ThemeContext.tsx b/src/context/ThemeContext.tsx
index 9523f0f..3025781 100644
--- a/src/context/ThemeContext.tsx
+++ b/src/context/ThemeContext.tsx
@@ -18,14 +18,15 @@ const ThemeContext = createContext({
export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [theme, setThemeState] = useState('light');
- const [mounted, setMounted] = useState(false);
useEffect(() => {
const savedTheme = localStorage.getItem('portfolio-theme') as Theme | null;
- const initialTheme = savedTheme || 'light';
+ const systemTheme: Theme = window.matchMedia('(prefers-color-scheme: dark)').matches
+ ? 'dark'
+ : 'light';
+ const initialTheme = savedTheme || systemTheme;
setThemeState(initialTheme);
document.documentElement.setAttribute('data-theme', initialTheme);
- setMounted(true);
}, []);
const setTheme = (newTheme: Theme) => {
diff --git a/src/styles/globals.css b/src/styles/globals.css
index a8cc991..5142318 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -21,18 +21,6 @@ html {
color-scheme: light;
}
-@media (max-width: 1024px) {
- html {
- font-size: 93.75%;
- }
-}
-
-@media (max-width: 650px) {
- html {
- font-size: 87.5%;
- }
-}
-
html[data-theme="dark"] {
color-scheme: dark;
}
@@ -117,9 +105,11 @@ body {
}
.section-title {
- font-size: var(--font-size-h2);
- line-height: var(--line-height-h2);
- font-weight: 700;
+ max-width: 24ch;
+ font-size: clamp(1.875rem, 3vw, 2.5rem);
+ line-height: 1.15;
+ font-weight: 760;
+ letter-spacing: -0.035em;
color: var(--text-primary);
margin-bottom: 0.75rem;
}
@@ -158,6 +148,20 @@ body {
box-shadow var(--motion-duration-default) ease,
transform var(--motion-duration-fast) var(--motion-ease-out);
border: 1px solid transparent;
+ white-space: nowrap;
+}
+
+.pill-btn:focus-visible,
+a:focus-visible,
+button:focus-visible,
+input:focus-visible {
+ outline: 3px solid var(--focus-ring);
+ outline-offset: 3px;
+}
+
+.pill-btn:active,
+button:active:not(:disabled) {
+ transform: translateY(1px) scale(0.99);
}
.pill-btn-outline {
diff --git a/src/styles/tokens.css b/src/styles/tokens.css
index 730ebc5..b57ded0 100644
--- a/src/styles/tokens.css
+++ b/src/styles/tokens.css
@@ -11,7 +11,7 @@
--color-blue-800: #091C3F;
--color-blue-900: #07132F;
--color-blue-950: #010D27;
- --color-blue-white: #FFFFFF;
+ --color-blue-white: #F8FAFF;
--color-slate-300: #C3CFE0;
--color-slate-400: #A3B1C6;
--color-slate-600: #667085;
@@ -20,7 +20,7 @@
--color-border-dark: #1E3458;
--color-border-strong-light: #A9BEDA;
--color-border-strong-dark: #426B9D;
- --color-black: #000000;
+ --color-black: #07132F;
--space-0: 0;
--space-1: 0.25rem;
--space-2: 0.5rem;
@@ -67,7 +67,7 @@
--font-size-h3: 1.25rem;
--font-size-body-large: 1.125rem;
--font-size-body-default: 1rem;
- --font-size-body-small: 0.875rem;
+ --font-size-body-small: 0.9375rem;
--font-size-label-small: 0.75rem;
--font-size-button: 0.9375rem;
--line-height-display-hero: 4.5rem;
@@ -77,7 +77,7 @@
--line-height-h3: 1.75rem;
--line-height-body-large: 1.875rem;
--line-height-body-default: 1.625rem;
- --line-height-body-small: 1.375rem;
+ --line-height-body-small: 1.5rem;
--line-height-label-small: 1.125rem;
--line-height-button: 1.25rem;
--letter-spacing-eyebrow: 0.16em;
@@ -87,9 +87,9 @@
--motion-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
/* Semantic Tokens (Light) */
- --bg-page: #FFFFFF;
- --bg-surface: #FAFAFA;
- --bg-raised: #FFFFFF;
+ --bg-page: #F8FAFF;
+ --bg-surface: #F1F6FD;
+ --bg-raised: #FCFDFF;
--bg-subtle: #E6F0FE;
--text-primary: #0B2F5F;
--text-secondary: #38526E;
@@ -100,7 +100,7 @@
--accent-default: #3D8AFA;
--action-link: #1557A6;
--action-primary-bg: #103F7F;
- --action-primary-fg: #FFFFFF;
+ --action-primary-fg: #F8FAFF;
--action-primary-hover: #0B3268;
--action-primary-pressed: #08284F;
--brand-band: #103F7F;
@@ -131,7 +131,7 @@
--text-primary: #F8FAFF;
--text-secondary: #C3CFE0;
--text-muted: #A3B1C6;
- --text-on-band: #FFFFFF;
+ --text-on-band: #F8FAFF;
--border-default: #1E3458;
--border-strong: #426B9D;
--accent-default: #82B5FF;