/* ============================================================================
   fang.work — minimal designer portfolio
   Replicates the tenn.design design system (Geist / JetBrains Mono /
   Instrument Serif) with a light/dark theme toggle.
   ============================================================================ */

/* ---- Font tokens --------------------------------------------------------- */
:root {
    --font-sans:  "Geist", "Noto Serif SC", "Noto Sans SC", ui-sans-serif, system-ui, sans-serif,
                  "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
    --font-mono:  "JetBrains Mono", "Noto Serif SC","Noto Sans SC", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
                  "Liberation Mono", "Courier New", monospace;
    --font-serif: "Instrument Serif", "Noto Serif SC", "Noto Sans SC", "Times New Roman", serif;
}

/* ---- Light theme tokens (default) ---------------------------------------- */
:root,
.dark {
    /* The site defaults to dark in original — we keep dark as the default
       in the boot script, but expose both palettes here. */
}
.light {
    --background:        #ffffff;
    --foreground:        #0a0a0a;
    --secondary:         #f5f5f5;
    --secondary-foreground: #0a0a0a;
    --muted:             #f5f5f5;
    --muted-foreground:  #6b7280;
    --accent:            #f5f5f5;
    --border:            rgba(0, 0, 0, 0.10);
    --ring:              #737373;
    --destructive:       #dc2626;
    --amber-500:         #f99c00;
    --orange-500:        #fe6e00;
}
.dark {
    --background:        #0a0a0a;
    --foreground:        #fafafa;
    --secondary:         #1a1a1a;
    --secondary-foreground: #fafafa;
    --muted:             #1a1a1a;
    --muted-foreground:  #a1a1aa;
    --accent:            #1a1a1a;
    --border:            rgba(255, 255, 255, 0.10);
    --ring:              #737373;
    --destructive:       #ef4444;
    --amber-500:         #f99c00;
    --orange-500:        #fe6e00;
}

/* ---- Base ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; border: 0 solid; margin: 0; padding: 0; }
html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    line-height: 1.5;
    font-family: var(--font-sans);
    color-scheme: dark;
}
.light { color-scheme: light; }

body {
    background-color: var(--background);
    color: var(--foreground);
    font-family: var(--font-sans);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}
img, svg { display: block; max-width: 100%; height: auto; vertical-align: middle; }
button, input, select, textarea {
    font: inherit; color: inherit; opacity: 1; background-color: transparent; border-radius: 0;
}
button:not(:disabled), [role="button"]:not(:disabled) { cursor: pointer; }
a { color: inherit; text-decoration: inherit; }
::selection { background: var(--foreground); color: var(--background); }
:focus-visible {
    outline: 2px solid var(--ring);
    outline-offset: 2px;
    border-radius: 2px;
}

/* ---- Navbar (floating pill) ---------------------------------------------- */
.navbar-wrap {
    position: fixed; inset-inline: 0; top: 0.75rem;
    z-index: 50;
    display: flex; justify-content: center; padding-inline: 0.75rem;
    pointer-events: none;
}
@media (min-width: 640px) { .navbar-wrap { top: 1rem; } }

.navbar {
    position: relative;
    pointer-events: auto;
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    width: 100%; max-width: 640px;
    /* Liquid-glass: thinner fill (60%) lets the canvas bleed through, then
       the blur + saturate rebuilds it as a soft tinted haze. */
    background-color: color-mix(in oklab, var(--background) 60%, transparent);
    padding: 0.375rem 0.5rem 0.375rem 0.75rem;
    border: 1px solid color-mix(in oklab, var(--foreground) 10%, transparent);
    border-radius: 0; /* straight corners, matches tenn.design */
    /* Stronger blur + saturation boost give the glass a frosted, vivid look */
    backdrop-filter: blur(20px) saturate(180%);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    /* Subtle inset highlight along the top edge — simulates light refracting
       through the glass boundary, the same trick macOS Big Sur+ uses. */
    box-shadow:
        inset 0 1px 0 0 color-mix(in oklab, var(--foreground) 14%, transparent),
        inset 0 -1px 0 0 color-mix(in oklab, var(--foreground) 4%, transparent),
        0 8px 24px -12px rgba(0, 0, 0, 0.25);
    isolation: isolate;
}

/* Fine grain noise overlay — gives the glass surface a tactile, slightly
   textured look instead of a flat plastic sheen. Inline SVG keeps it
   dependency-free; only ~1KB even at 1× device pixel ratio. */
.navbar::before {
    content: "";
    position: absolute; inset: 0;
    pointer-events: none;
    border-radius: inherit;
    z-index: -1;
    opacity: 0.06;
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}
@media (min-width: 640px) {
    .navbar { gap: 0.75rem; padding-left: 1rem; }
}

/* ---- Border beam (流光) --------------------------------------------------
   A 1px-tall conic-gradient ring wraps the navbar. The gradient is
   a small bright dot (~3° peak) followed by a ~9° fading tail that
   traces the perimeter as JS updates --beam-angle every frame.
   Default: white dot + tail. On hover: theme accent (orange-500).
   The "head" sits at 180° in the conic frame (top of the box); the
   tail trails forward in the direction of rotation.
   ----------------------------------------------------------------------- */
.border-beam {
    position: absolute; inset: 0; pointer-events: none;
    z-index: 2;
    border-radius: inherit;
    padding: 1px;
    /* Mask carves out the interior so only the 1px edge shows */
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
            mask-composite: exclude;

    /* Conic gradient — gradient lives at fixed angles; the whole frame
       rotates via --beam-angle so the dot orbits the perimeter.
         • 0°   – 177° : transparent
         • 178° – 180° : solid bright "head" (the dot)
         • 180° – 183° : short bright tail (80%)
         • 183° – 189° : long fading tail (eased to 0)
         • 189° – 360° : transparent
       For a ~640×44 nav box the perimeter ≈ 1368px, so 9° ≈ 34px of arc
       (≈ 24px of visible trail behind the dot — matches the spec). */
    background: conic-gradient(
        from var(--beam-angle, 0deg),
        transparent 0deg,
        transparent 177deg,
        var(--beam-color, #fff) 178deg,
        var(--beam-color, #fff) 180deg,
        color-mix(in oklab, var(--beam-color, #fff) 80%, transparent) 183deg,
        color-mix(in oklab, var(--beam-color, #fff) 35%, transparent) 186deg,
        color-mix(in oklab, var(--beam-color, #fff) 10%, transparent) 189deg,
        transparent 190deg,
        transparent 360deg
    );

    animation: beam-rotate var(--beam-duration, 12s) linear infinite;
    transition: --beam-color 0.4s ease;
}

/* Theme defaults — overridden on hover via --beam-color */
.border-beam { --beam-color: #ffffff; }
.navbar:hover .border-beam {
    --beam-color: var(--orange-500);
}

@keyframes beam-rotate {
    to { --beam-angle: 360deg; }
}

/* Register custom properties so they animate smoothly */
@property --beam-angle {
    syntax: "<angle>";
    initial-value: 0deg;
    inherits: false;
}
@property --beam-color {
    syntax: "<color>";
    initial-value: #ffffff;
    inherits: true;
}

.brand {
    position: relative;
    z-index: 3;
    display: flex; align-items: center; gap: 0.375rem;
    font-family: var(--font-sans);
    font-size: 0.875rem;
}
.brand-name {
    color: var(--foreground);
    transition: opacity 0.2s ease;
}
.brand-name:hover { opacity: 0.7; }
.brand-sub-btn {
    color: var(--muted-foreground);
    transition: color 0.2s ease;
}
.brand-sub-btn:hover { color: var(--foreground); }

.nav-links {
    position: relative;
    z-index: 3;
    display: none;
    align-items: center;
    gap: 0;
}
@media (min-width: 640px) { .nav-links { display: flex; } }
.nav-link {
    position: relative;
    display: inline-flex; align-items: center;
    padding: 0.25rem 0.75rem;
    font-size: 0.875rem; line-height: 1;
    color: var(--muted-foreground);
    transition: color 0.2s ease, transform 0.2s ease;
}
.nav-link:hover { color: var(--foreground); }
.nav-link:active { transform: scale(0.95); transition-duration: 75ms; }

.theme-toggle {
    position: relative;
    z-index: 3;
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px;
    background-color: var(--secondary);
    color: var(--foreground);
    border-radius: 0;
    transition: background-color 0.2s ease, transform 0.2s ease;
}
.theme-toggle:hover { background-color: color-mix(in oklab, var(--secondary) 80%, transparent); }
.theme-toggle:active { transform: scale(0.95); transition-duration: 75ms; }
.theme-toggle .icon-moon { display: none; }
.theme-toggle .icon-sun { display: block; }
.dark .theme-toggle .icon-sun { display: none; }
.dark .theme-toggle .icon-moon { display: block; }

/* ---- Right-side actions group --------------------------------------------
   Holds the (mobile-only) Menu button + the always-visible theme toggle.
   Anchored to the right edge of the navbar so the theme toggle is always
   the rightmost element regardless of viewport width. The Menu button
   precedes the theme toggle in source order, which puts it visually to
   the left of the theme toggle at narrow widths.
   ----------------------------------------------------------------------- */
.nav-actions {
    position: relative;
    z-index: 3;
    display: flex; align-items: center; gap: 12px;
    flex-shrink: 0;
}

/* ---- Menu button (mobile only) --------------------------------------------
   Hidden at >=640px; same chip-styling family as the theme toggle so it
   visually integrates with the glass navbar. */
.menu-btn {
    position: relative;
    z-index: 3;
    display: none;                              /* shown via the @media below */
    align-items: center; justify-content: center;
    height: 30px; padding: 0 12px;
    background-color: var(--secondary);
    color: var(--foreground);
    border-radius: 0;
    font-family: var(--font-sans);
    font-size: 0.875rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.2s ease, transform 0.2s ease;
}
.menu-btn:hover  { background-color: color-mix(in oklab, var(--secondary) 80%, var(--foreground)); }
.menu-btn:active { transform: scale(0.95); }
@media (max-width: 639px) {
    .menu-btn { display: inline-flex; }
}

/* ---- Mobile menu (full-screen overlay) -------------------------------------
   Mirrors tenn.design: fixed inset-0 z-60 bg-black text-white, slides in from
   the right via clip-path. Closed by default; toggled by adding .is-open.
   ----------------------------------------------------------------------- */
.mobile-menu {
    position: fixed; inset: 0;
    z-index: 60;
    background-color: #000;
    color: #fff;
    display: flex;
    visibility: hidden;
    opacity: 0;
    clip-path: inset(0 0 0 100%);                /* fully clipped to the right */
    transition: clip-path 0.42s cubic-bezier(0.7, 0, 0.2, 1),
                opacity 0.25s ease,
                visibility 0s linear 0.42s;     /* delay hide until clip done */
}
.mobile-menu.is-open {
    visibility: visible;
    opacity: 1;
    clip-path: inset(0 0 0 0);
    transition: clip-path 0.42s cubic-bezier(0.7, 0, 0.2, 1),
                opacity 0.25s ease,
                visibility 0s linear 0s;
}
/* Hide overlay entirely once we're back on desktop — but only after the
   media query, so CSS specificity keeps things sane. */
@media (min-width: 640px) {
    .mobile-menu { display: none; }
}
.mobile-menu-inner {
    flex: 1 1 auto;
    display: flex; flex-direction: column;
    height: 100%;
    padding: 20px 24px 40px;
}
.mobile-menu-head {
    display: flex; justify-content: flex-end;
}
.mobile-menu-close {
    -webkit-appearance: none; appearance: none;
    background: transparent; border: 0;
    padding: 8px; margin: -8px -8px 0 0;
    color: rgba(255, 255, 255, 0.7);
    cursor: pointer;
    transition: color 0.2s ease;
}
.mobile-menu-close:hover { color: #fff; }
.mobile-menu-nav {
    margin-top: 80px;
    display: flex; flex: 1 1 auto; flex-direction: column;
    align-items: flex-start;
}
.mobile-menu-link {
    display: inline-block;
    padding: 8px 0;
    font-family: var(--font-display);
    font-size: 1.875rem;
    line-height: 1.15;
    letter-spacing: -0.01em;
    color: rgba(255, 255, 255, 0.55);
    text-decoration: none;
    transition: color 0.2s ease;
}
.mobile-menu-link:hover,
.mobile-menu-link[aria-current="page"] { color: #fff; }

/* Lock body scroll while the menu is open */
body.menu-open { overflow: hidden; }

/* ---- Hero ---------------------------------------------------------------- */
.hero {
    position: relative;
    width: 100%;
    overflow: hidden;
    min-height: 100dvh;
}
.hero-canvas {
    position: absolute; inset: 0; overflow: hidden;
    color: var(--foreground);
}
.hero-canvas canvas { display: block; width: 100%; height: 100%; position: relative; z-index: 2; }

/* ---- Weather sky overlay -------------------------------------------------
   Each weather state tints the hero with a layered radial/linear wash
   that complements the canvas particle effect. The fade overlays above
   still read correctly because we keep them on top via z-index.
   ----------------------------------------------------------------------- */
.hero-canvas::before {
    content: "";
    position: absolute; inset: 0;
    z-index: 1; pointer-events: none;
    background: var(--weather-sky, transparent);
    transition: background 0.6s ease;
}

/* Sky washes — different palettes per state. */
[data-weather="clear"]       { --weather-sky: linear-gradient(180deg, rgba(135,206,250,0.10), rgba(255,255,255,0.02)); }
[data-weather="sunny"]       { --weather-sky: radial-gradient(60% 80% at 75% 25%, rgba(254,180,63,0.18), transparent 70%), linear-gradient(180deg, rgba(254,230,160,0.10), transparent); }
[data-weather="cloudy"]      { --weather-sky: linear-gradient(180deg, rgba(180,185,195,0.10), rgba(220,225,235,0.04)); }
[data-weather="drizzle"]     { --weather-sky: linear-gradient(180deg, rgba(110,120,135,0.10), rgba(140,150,165,0.04)); }
[data-weather="rain"]        { --weather-sky: linear-gradient(180deg, rgba(80,92,110,0.18), rgba(120,130,145,0.06)); }
[data-weather="thunderstorm"]{ --weather-sky: linear-gradient(180deg, rgba(40,48,60,0.28), rgba(80,90,105,0.10)); }
[data-weather="snow"]        { --weather-sky: linear-gradient(180deg, rgba(210,220,235,0.10), rgba(240,245,255,0.04)); }
[data-weather="heavy-snow"]  { --weather-sky: linear-gradient(180deg, rgba(220,228,240,0.16), rgba(245,250,255,0.08)); }
[data-weather="windy"]       { --weather-sky: linear-gradient(180deg, rgba(160,170,185,0.10), rgba(190,200,215,0.04)); }
[data-weather="fog"]         { --weather-sky: radial-gradient(120% 80% at 50% 50%, rgba(220,225,230,0.14), rgba(220,225,230,0.06)); }

.hero-fade {
    position: absolute; pointer-events: none;
    z-index: 3;
}
.hero-fade-x {
    inset: 0;
    background: linear-gradient(to right,
        color-mix(in oklab, var(--background) 80%, transparent),
        color-mix(in oklab, var(--background) 40%, transparent),
        transparent);
}
@media (min-width: 640px) {
    .hero-fade-x {
        background: linear-gradient(to right,
            color-mix(in oklab, var(--background) 90%, transparent),
            color-mix(in oklab, var(--background) 60%, transparent),
            transparent);
    }
}
.hero-fade-b {
    inset-inline: 0; bottom: 0; height: 10rem;
    background: linear-gradient(to top, var(--background), transparent);
}

.hero-inner {
    position: relative; z-index: 10;
    display: flex; flex-direction: column; justify-content: center;
    margin-inline: auto;
    min-height: 100dvh;
    max-width: 48rem;
    padding: 7rem 1rem 6rem;
}
@media (min-width: 640px) { .hero-inner { padding: 8rem 2rem 6rem; } }

.status-chip { display: inline-block; position: relative; }
.status-btn {
    display: inline-flex; align-items: center; gap: 0.5rem;
    width: fit-content;
    font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--muted-foreground);
    transition: color 0.2s ease, transform 0.2s ease;
}
.status-btn:hover { color: var(--foreground); }
.status-btn:active { transform: scale(0.95); transition-duration: 75ms; }
.status-dot-wrap {
    position: relative; display: inline-flex;
    width: 0.5rem; height: 0.5rem;
    align-items: center; justify-content: center;
}
.status-dot-ping,
.status-dot {
    position: absolute; inset: 0;
    border-radius: 0;
    background-color: var(--amber-500);
}
.status-dot-ping {
    opacity: 0.6;
    animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
}
.status-dot { position: relative; opacity: 1; }
@keyframes ping {
    75%, 100% { transform: scale(2); opacity: 0; }
}

.hero-name {
    margin-top: 1rem;
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: 2.25rem;
    line-height: 1.05;
    letter-spacing: -0.025em;
    color: var(--foreground);
}
@media (min-width: 640px) { .hero-name { font-size: 3.75rem; } }

.hero-bio {
    margin-top: 1.5rem;
    max-width: 52ch;
    font-size: 1rem;
    font-family: var(--font-mono);
    font-weight: 100;
    line-height: 1.625;
    color: var(--foreground);
}
@media (min-width: 640px) { .hero-bio { font-size: 1.125rem; } }

.hero-ctas {
    margin-top: 2.5rem;
    display: flex; flex-wrap: wrap; gap: 0.75rem;
}

/* Buttons */
.btn {
    display: inline-flex; align-items: center; gap: 0.5rem;
    width: fit-content;
    padding: 0.75rem 1.25rem;
    font-size: 0.875rem;
    transition: background-color 0.2s ease, transform 0.2s ease;
    white-space: nowrap;
}
.btn:active { transform: scale(0.98); transition-duration: 75ms; }
.btn svg {
    width: 1rem; height: 1rem;
    transition: transform 0.2s ease;
}
.btn-primary {
    background-color: var(--foreground);
    color: var(--background);
    border: 1px solid color-mix(in oklab, var(--foreground) 15%, transparent);
}
.btn-primary:hover { background-color: color-mix(in oklab, var(--foreground) 90%, transparent); }
.btn-primary:hover svg { transform: rotate(-45deg); }

.btn-ghost {
    background-color: var(--background);
    color: var(--foreground);
    border: 1px solid color-mix(in oklab, var(--foreground) 15%, transparent);
}
.btn-ghost:hover { background-color: var(--muted); }
.btn-ghost:hover svg { transform: rotate(10deg); }

/* Hero bottom chips */
.hero-bottom {
    position: absolute; bottom: 1.5rem; left: 1rem; z-index: 20;
    display: flex; flex-direction: column; gap: 0.5rem;
    align-items: flex-start;
}
@media (min-width: 640px) {
    .hero-bottom {
        left: 2rem; flex-direction: row; align-items: center;
    }
}
.chip {
    display: inline-flex; align-items: center; gap: 0.375rem;
    padding: 0.375rem 0.75rem;
    font-size: 0.75rem;
    text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--muted-foreground);
    background-color: color-mix(in oklab, var(--secondary) 60%, transparent);
    border: 1px solid color-mix(in oklab, var(--foreground) 10%, transparent);
    border-radius: 0;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    transition: color 0.2s ease, transform 0.2s ease;
    cursor: pointer;
}
.chip:hover { color: var(--foreground); }
.chip:active { transform: scale(0.95); transition-duration: 75ms; }
.chip-link { text-decoration: none; }
.chip-link svg { width: 0.75rem; height: 0.75rem; transition: transform 0.2s ease; }
.chip-link:hover svg { transform: rotate(-45deg); }

/* ---- Work ---------------------------------------------------------------- */
.work {
    padding-top: 6rem;
}
@media (min-width: 640px) { .work { padding-top: 8rem; } }

.work-list {
    display: flex; flex-direction: column; gap: 8rem;
}
@media (min-width: 640px) { .work-list { gap: 12rem; } }

.project { display: flex; flex-direction: column; gap: 2.5rem; }
@media (min-width: 640px) { .project { gap: 3rem; } }

.project-figure-wrap {
    padding-inline: max(0px, calc((100% - 1440px) / 2));
}
.project-figure-link {
    display: block;
    text-decoration: none;
}
.project-thumb {
    position: relative;
    display: flex; align-items: center; justify-content: center;
    width: 100%;
    overflow: hidden;
    background-color: var(--muted);
    border: 1px solid color-mix(in oklab, var(--foreground) 10%, transparent);
    transition: box-shadow 0.3s ease;
    margin-inline: auto;
    max-width: calc((100svh - 6rem) * var(--ar, 1.78));
}
.project-figure-link:hover .project-thumb {
    border-color: color-mix(in oklab, var(--foreground) 30%, transparent);
}
.project-thumb img {
    width: 100%; height: auto; object-fit: cover;
}

.project-body {
    margin-inline: auto;
    max-width: 48rem;
    padding: 0 1rem;
}
@media (min-width: 640px) { .project-body { padding: 0 2rem; } }

.project-head {
    display: flex; align-items: center; gap: 1rem;
}
.project-logo {
    position: relative;
    width: 3.5rem; height: 3.5rem;
    flex-shrink: 0;
    overflow: hidden;
    border-radius: 0px;
    background-color: var(--muted);
    border: 1px solid var(--border);
}
.project-logo img { width: 100%; height: 100%; object-fit: cover; }

.project-meta { min-width: 0; }
.project-name {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: 1.125rem;
    color: var(--foreground);
}
@media (min-width: 640px) { .project-name { font-size: 1.25rem; } }
.project-role {
    margin-top: 0.25rem;
    font-size: 0.875rem;
    color: var(--muted-foreground);
}
.project-role .nowrap { white-space: nowrap; }
.project-role span[aria-hidden] { margin-inline: 0.5rem; }

.project-desc {
    margin-top: 1.5rem;
    display: flex; flex-direction: column; gap: 0.75rem;
    list-style: none;
}
.project-desc li {
    max-width: 60ch;
    font-size: 1rem;
    line-height: 1.625;
    color: var(--foreground);
}

.project-foot {
    margin-top: 1.5rem;
    display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem;
}
.tag-list {
    display: flex; flex-wrap: wrap; gap: 0.375rem;
    min-width: 0; flex: 1;
    list-style: none;
}
.tag {
    display: inline-flex; align-items: center; justify-content: center;
    height: 1.25rem;
    padding: 0 0.5rem;
    font-size: 0.75rem; font-weight: 500;
    white-space: nowrap;
    color: var(--foreground);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 0;
    overflow: hidden;
}
.learn-more {
    display: inline-flex; align-items: center; gap: 0.375rem;
    font-size: 0.875rem;
    color: var(--muted-foreground);
    transition: color 0.2s ease;
    flex-shrink: 0;
}
.learn-more:hover { color: var(--foreground); }
.learn-more svg { width: 0.875rem; height: 0.875rem; transition: transform 0.2s ease; }
.learn-more:hover svg { transform: rotate(-45deg); }

/* ---- Testimonials -------------------------------------------------------- */
.testimonials {
    padding: 6rem 1rem 4rem;
    max-width: 64rem;
    margin-inline: auto;
}
@media (min-width: 640px) { .testimonials { padding: 8rem 2rem 4rem; } }

.testimonials-head { margin-bottom: 2.5rem; }
.testimonials-title {
    font-family: var(--font-serif);
    font-style: italic;
    font-weight: 400;
    font-size: 1.5rem;
    color: var(--foreground);
}
@media (min-width: 640px) { .testimonials-title { font-size: 1.875rem; } }

.testimonials-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 2rem;
}
@media (min-width: 768px) {
    .testimonials-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.testimonial {
    padding: 1.5rem;
    border: 1px solid var(--border);
    border-radius: 0;
    background-color: color-mix(in oklab, var(--foreground) 1.2%, transparent);
    transition: border-color 0.3s ease, background-color 0.3s ease;
}
.testimonial:hover {
    border-color: color-mix(in oklab, var(--foreground) 18%, transparent);
}
.testimonial p {
    font-size: 0.9375rem; line-height: 1.625;
    color: var(--foreground);
}
.testimonial footer {
    margin-top: 1rem;
    font-size: 0.8125rem;
    color: var(--muted-foreground);
}
.testimonial footer span { color: var(--muted-foreground); opacity: 0.7; }

/* ---- Contact ------------------------------------------------------------- */
.contact {
    padding: 4rem 1rem 6rem;
    max-width: 48rem;
    margin-inline: auto;
    text-align: center;
}
@media (min-width: 640px) { .contact { padding: 6rem 2rem 8rem; } }
.contact-title {
    font-family: var(--font-serif);
    font-style: italic;
    font-weight: 400;
    font-size: 2.25rem;
    color: var(--foreground);
}
@media (min-width: 640px) { .contact-title { font-size: 3rem; } }
.contact-bio {
    margin-top: 1rem;
    max-width: 52ch;
    margin-inline: auto;
    font-size: 1rem;
    line-height: 1.625;
    color: var(--muted-foreground);
}
.contact-ctas {
    margin-top: 2rem;
    display: flex; flex-wrap: wrap; gap: 0.75rem;
    justify-content: center;
}

/* ---- Footer -------------------------------------------------------------- */
.site-footer {
    padding: 2rem 1rem 3rem;
    text-align: center;
    border-top: 1px solid var(--border);
}
.site-footer p {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--muted-foreground);
}
.site-footer a {
    color: var(--foreground);
    transition: opacity 0.2s ease;
}
.site-footer a:hover { opacity: 0.7; }

/* ---- Reveal animation ---------------------------------------------------- */
.reveal {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity 0.6s cubic-bezier(0, 0, 0.2, 1),
                transform 0.6s cubic-bezier(0, 0, 0.2, 1);
}
.reveal.is-in {
    opacity: 1;
    transform: none;
}

/* ---- Reduced motion ------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation: none !important;
        transition: none !important;
        scroll-behavior: auto !important;
    }
    .reveal { opacity: 1; transform: none; }
    .border-beam { display: none; }
}