/* ==========================================================================
   groenbaekpedersen.dk: a dark stage, a black-and-white photo, gold type.
   Gold is the accent everywhere; amber (the musician) and cyan (the
   developer) only tint the photos toward their own side.
   ========================================================================== */

/* ---------- Tokens ---------- */
:root {
    color-scheme: dark;
    --bg: oklch(0.14 0.004 80);
    --bg-2: oklch(0.17 0.005 80);
    --card: oklch(0.19 0.006 80 / 0.8);
    --fg: oklch(0.95 0.008 85);
    --muted: oklch(0.72 0.012 85);
    --line: oklch(0.3 0.01 85);
    --gold: oklch(0.78 0.085 85);
    --gold-hi: oklch(0.9 0.07 88);
    --amber: oklch(0.8 0.15 70);
    --cyan: oklch(0.82 0.12 205);
    --accent: var(--gold);
    --grain-opacity: 0.14;
    --shadow: 0 1px 0 oklch(1 0 0 / 0.04) inset, 0 20px 50px -20px oklch(0 0 0 / 0.7);

    --font-display: "Bebas Neue", "Oswald", Impact, "Arial Narrow", sans-serif;
    --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, "Cascadia Code", Consolas, monospace;

    --gutter: clamp(1rem, 4vw, 3rem);
    --maxw: 68rem;
    --radius: 0.6rem;
    --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
}

@media (prefers-color-scheme: light) {
    :root:not([data-theme="dark"]) {
        color-scheme: light;
        --bg: oklch(0.97 0.008 85);
        --bg-2: oklch(0.94 0.012 85);
        --card: oklch(1 0 0 / 0.75);
        --fg: oklch(0.18 0.01 80);
        --muted: oklch(0.45 0.015 80);
        --line: oklch(0.86 0.015 85);
        --gold: oklch(0.55 0.1 75);
        --gold-hi: oklch(0.45 0.1 70);
        --grain-opacity: 0.08;
        --shadow: 0 20px 40px -24px oklch(0.3 0.03 80 / 0.35);
    }
}

:root[data-theme="light"] {
    color-scheme: light;
    --bg: oklch(0.97 0.008 85);
    --bg-2: oklch(0.94 0.012 85);
    --card: oklch(1 0 0 / 0.75);
    --fg: oklch(0.18 0.01 80);
    --muted: oklch(0.45 0.015 80);
    --line: oklch(0.86 0.015 85);
    --gold: oklch(0.55 0.1 75);
    --gold-hi: oklch(0.45 0.1 70);
    --grain-opacity: 0.08;
    --shadow: 0 20px 40px -24px oklch(0.3 0.03 80 / 0.35);
}

/* Photo areas (front page, page banners, top bar) are always dark. */
.hero, .page-banner, .topbar {
    color-scheme: dark;
    --fg: oklch(0.97 0.005 85);
    --bg: oklch(0.1 0.005 265);
    --muted: oklch(0.8 0.01 85);
    --line: oklch(1 0 0 / 0.25);
    --gold: oklch(0.78 0.085 85);
    --gold-hi: oklch(0.9 0.07 88);
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    scrollbar-gutter: stable;
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--fg);
    font-family: var(--font-sans);
    font-size: clamp(1rem, 0.95rem + 0.2vw, 1.075rem);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    overflow-x: clip;
}

img { max-width: 100%; display: block; }
a { color: inherit; }
h1, h2, h3 { line-height: 1.1; margin: 0; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; list-style: none; }
code { font-family: var(--font-mono); }

:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 3px;
    border-radius: 6px;
}

::selection { background: var(--gold); color: oklch(0.15 0.01 80); }

/* Film grain, used on the music page */
.side-music::before {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- Top bar ---------- */
.topbar {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.85rem var(--gutter);
    color: var(--fg);
    background: linear-gradient(oklch(0.08 0.004 80 / 0.8), oklch(0.08 0.004 80 / 0.55));
    backdrop-filter: blur(10px);
    border-bottom: 1px solid oklch(1 0 0 / 0.06);
    view-transition-name: topbar;
}

.brand { text-decoration: none; display: inline-flex; }

.brand-mark {
    font-family: var(--font-display);
    font-size: 1.45rem;
    line-height: 1;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
    transition: color 0.2s;
}

.brand-mark span { color: var(--gold); }
.brand:hover .brand-mark { color: var(--gold-hi); }

.topnav {
    display: flex;
    gap: 1.75rem;
    margin-inline: auto;
}

.topnav-link {
    position: relative;
    text-decoration: none;
    font-family: var(--font-display);
    font-size: 1.3rem;
    line-height: 1;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
    padding-block: 0.3rem;
    transition: color 0.2s;
}

.topnav-link::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 2px;
    background: var(--gold);
    transform: scaleX(0);
    transition: transform 0.4s var(--ease-out);
}

.topnav-link:hover { color: var(--fg); }
.topnav-link.active { color: var(--gold); }
.topnav-link.active::after { transform: scaleX(1); }

.topbar-tools { display: flex; align-items: center; gap: 0.5rem; }

.lang-switch {
    display: inline-flex;
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: 2px;
}

.lang-switch button, .icon-btn {
    font: inherit;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    color: var(--muted);
    background: none;
    border: 0;
    border-radius: 999px;
    padding: 0.3rem 0.6rem;
    cursor: pointer;
    transition: color 0.2s, background-color 0.2s;
}

.lang-switch button[aria-pressed="true"] { background: var(--fg); color: var(--bg); }
.lang-switch button:hover:not([aria-pressed="true"]), .icon-btn:hover { color: var(--fg); }

.icon-btn {
    display: inline-grid;
    place-items: center;
    width: 2.1rem;
    height: 2.1rem;
    padding: 0;
    border: 1px solid var(--line);
}

@media (max-width: 40rem) {
    .topnav { display: none; }
    .topbar-tools { margin-left: auto; }
    .brand-mark { font-size: 1.2rem; }
}

@media (max-width: 22rem) {
    .brand-mark { font-size: 0; }
    .brand-mark span { font-size: 1.3rem; }
}

/* Scroll progress: a thin gold line, driven by the scroll position. */
.scroll-progress {
    position: fixed;
    inset: 0 0 auto 0;
    height: 2px;
    z-index: 60;
    background: linear-gradient(90deg, var(--gold), var(--gold-hi));
    transform-origin: 0 50%;
    transform: scaleX(0);
}

@supports (animation-timeline: scroll()) {
    .scroll-progress { animation: progress linear both; animation-timeline: scroll(root); }
}

@keyframes progress { to { transform: scaleX(1); } }

/* ---------- Social icons (front-page rail and footer) ---------- */
.social { display: flex; gap: 0.6rem; }

.social a {
    display: grid;
    place-items: center;
    width: 2.4rem;
    height: 2.4rem;
    border-radius: 50%;
    color: color-mix(in oklch, var(--fg) 80%, transparent);
    border: 1px solid var(--line);
    transition: color 0.2s, border-color 0.2s, background-color 0.2s, scale 0.3s var(--ease-out);
}

.social a:hover, .social a:focus-visible {
    color: oklch(0.12 0.01 80);
    background: var(--gold);
    border-color: var(--gold);
    scale: 1.08;
}

.social svg {
    width: 1.15rem;
    height: 1.15rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.social svg .fill { fill: currentColor; stroke: none; }

/* ==========================================================================
   Hero: one photo, the name in the middle, a way in on either side
   ========================================================================== */

/* The front page is always the dark stage, whatever the theme (see Tokens). */
.hero {
    position: relative;
    min-height: 100svh;
    display: grid;
    isolation: isolate;
    overflow: hidden;
    color: var(--fg);
    background: var(--bg);
}

/* No site chrome on the front page: just the language and theme switches. */
body:has(.hero) .site-footer,
body:has(.hero) .scroll-progress,
body:has(.hero) .brand,
body:has(.hero) .topnav { display: none; }

body:has(.hero) .topbar {
    background: none;
    backdrop-filter: none;
    border-bottom-color: transparent;
}

body:has(.hero) .topbar-tools { margin-left: auto; }

.hero-photo {
    position: absolute;
    inset: 0;
    z-index: -2;
    width: 100%;
    height: 100%;
    max-width: none;
    object-fit: cover;
    object-position: 50% 22%;
    filter: grayscale(1) contrast(1.08) brightness(0.52);
    view-transition-name: portrait;
    transition: filter 0.9s var(--ease-out), scale 6s var(--ease-out);
}

/* Vignette plus a soft tint that leans toward whichever side is hovered. */
.hero::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(ellipse 60% 45% at 50% 52%, oklch(0 0 0 / 0.35), transparent 70%),
        radial-gradient(ellipse 120% 90% at 50% 45%, transparent 45%, oklch(0 0 0 / 0.75));
}

.hero::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    mix-blend-mode: color;
    opacity: 0;
    background: linear-gradient(90deg, var(--tint, transparent), transparent 75%);
    transition: opacity 0.9s var(--ease-out);
}

.hero:has(.hero-link.music:is(:hover, :focus-visible))::before { --tint: var(--amber); opacity: 0.45; }
.hero:has(.hero-link.dev:is(:hover, :focus-visible))::before {
    --tint: var(--cyan);
    opacity: 0.4;
    background: linear-gradient(270deg, var(--tint), transparent 75%);
}
.hero:has(.hero-link:is(:hover, :focus-visible)) .hero-photo { filter: grayscale(1) contrast(1.08) brightness(0.62); scale: 1.03; }

.hero-stage {
    align-self: center;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: clamp(1.5rem, 4vw, 4.5rem);
    padding: 6rem calc(var(--gutter) + 3.5rem);
}

.hero-mark {
    display: grid;
    justify-items: center;
    gap: 0.6rem;
    text-align: center;
}

.hero-name {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: clamp(3rem, 1.4rem + 5.2vw, 6.75rem);
    line-height: 0.86;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    text-shadow: 0 2px 30px oklch(0 0 0 / 0.5);
}

.hero-name span { display: block; }
.hero-name span:first-child { font-size: 0.62em; letter-spacing: 0.32em; margin-right: -0.32em; }

.hero-tagline {
    font-family: var(--font-mono);
    font-size: clamp(0.72rem, 0.66rem + 0.2vw, 0.85rem);
    letter-spacing: 0.08em;
    color: oklch(0.85 0.01 85 / 0.85);
}

.hero-link {
    position: relative;
    justify-self: end;
    font-family: var(--font-display);
    font-size: clamp(1.9rem, 1.2rem + 1.8vw, 3.1rem);
    line-height: 1;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none;
    color: var(--gold);
    padding-block: 0.3rem;
    text-shadow: 0 2px 18px oklch(0 0 0 / 0.6);
    transition: color 0.3s, letter-spacing 0.5s var(--ease-out);
}

.hero-link.dev { justify-self: start; }

.hero-link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: right;
    transition: transform 0.5s var(--ease-out);
}

.hero-link.dev::after { transform-origin: left; }
.hero-link:is(:hover, :focus-visible) { color: var(--gold-hi); letter-spacing: 0.08em; }
.hero-link:is(:hover, :focus-visible)::after { transform: scaleX(1); }
.hero-link:focus-visible { outline: none; }

/* Social icons down the left edge */
.social-rail {
    position: absolute;
    left: var(--gutter);
    top: 50%;
    translate: 0 -50%;
    flex-direction: column;
    gap: 0.9rem;
}

.social-rail a:not(:hover, :focus-visible) {
    background: oklch(0 0 0 / 0.25);
    backdrop-filter: blur(4px);
}

/* Static shell for deep links: a quiet loader instead of the hero. */
.shell-deep .hero-photo, .shell-deep .hero-link, .shell-deep .hero-tagline, .shell-deep .social-rail { visibility: hidden; }
.shell-deep::after { display: none; }
.shell.shell-deep .hero-mark { animation: breathe 1.6s ease-in-out infinite; }
@keyframes breathe { 50% { opacity: 0.45; } }

/* Narrow screens: the name up top, the two ways in stacked at the bottom. */
@media (max-width: 52rem) {
    .hero-stage {
        align-self: stretch;
        grid-template-columns: 1fr;
        grid-template-rows: 1fr auto auto;
        gap: 0.5rem;
        padding: 5rem var(--gutter) 6.5rem;
    }
    .hero-mark { grid-row: 1; align-self: end; margin-bottom: 2.5rem; }
    .hero-link, .hero-link.dev { justify-self: center; }
    .hero-photo { object-position: 58% 20%; }
    .hero::after {
        background: linear-gradient(transparent 25%, oklch(0 0 0 / 0.85) 95%),
            radial-gradient(ellipse 120% 90% at 50% 40%, transparent 45%, oklch(0 0 0 / 0.6));
    }
    .social-rail {
        top: auto;
        bottom: 1.5rem;
        left: 50%;
        translate: -50% 0;
        flex-direction: row;
    }
}
/* ==========================================================================
   Content pages
   ========================================================================== */

/* Full-bleed rows (the banner) and a centred content column for the rest. */
.page {
    position: relative;
    display: grid;
    grid-template-columns:
        [full-start] minmax(var(--gutter), 1fr)
        [content-start] minmax(0, var(--maxw))
        [content-end] minmax(var(--gutter), 1fr) [full-end];
    row-gap: clamp(3.5rem, 9vw, 6.5rem);
    padding-bottom: 5rem;
}

.page > * { grid-column: content; }

.side-music { --tint: var(--amber); }
.side-dev { --tint: var(--cyan); }

/* Faint texture behind each page: grain for the musician, a grid for the developer. */
.side-music::before, .side-dev::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
}

.side-music::before { opacity: calc(var(--grain-opacity) * 0.6); mix-blend-mode: overlay; }

.side-dev::before {
    background:
        linear-gradient(color-mix(in oklch, var(--gold) 6%, transparent) 1px, transparent 1px) 0 0 / 2rem 2rem,
        linear-gradient(90deg, color-mix(in oklch, var(--gold) 6%, transparent) 1px, transparent 1px) 0 0 / 2rem 2rem;
    mask-image: linear-gradient(transparent 30%, #000 60%, transparent);
}

/* ---------- Page banner: the photo, darkened, with the title over it ---------- */
.page-banner {
    grid-column: full;
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: grid;
    grid-template-columns: subgrid;
    min-height: clamp(26rem, 68svh, 44rem);
    color: var(--fg);
    background: var(--bg);
}

.banner-photo {
    position: absolute;
    inset: 0;
    z-index: -2;
    width: 100%;
    height: 100%;
    max-width: none;
    object-fit: cover;
    object-position: 50% 8%;
    filter: grayscale(1) contrast(1.08) brightness(0.5);
    view-transition-name: portrait;
}

.page-banner::before, .page-banner::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
}

/* The side's own tint, as on the front page when hovering that side. */
.page-banner::before {
    mix-blend-mode: color;
    opacity: 0.4;
    background: linear-gradient(90deg, var(--tint), transparent 75%);
}

.side-dev .page-banner::before { background: linear-gradient(270deg, var(--tint), transparent 75%); }

.page-banner::after {
    background:
        linear-gradient(90deg, oklch(0 0 0 / 0.7), transparent 70%),
        linear-gradient(transparent 40%, oklch(0 0 0 / 0.65));
}

.banner-text {
    grid-column: content;
    align-self: end;
    display: grid;
    gap: 0.9rem;
    padding: 7rem 0 clamp(2.5rem, 7vh, 4.5rem);
    max-width: 44rem;
}

/* Narrow screens: a tall banner would crop the photo to a thin strip, so show the whole
   photo at its own ratio with the title below, overlapping its faded bottom edge. */
@media (max-width: 40rem) {
    .page-banner { min-height: 0; padding-top: 4rem; } /* clear the fixed top bar */
    .banner-photo {
        position: relative;
        inset: auto;
        grid-column: full;
        grid-row: 1;
        height: auto;
        aspect-ratio: 1250 / 1280;
    }
    .banner-text { grid-row: 2; margin-top: -5rem; padding-top: 0; }
}

.eyebrow {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--gold);
}

.page-title {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: clamp(3.8rem, 2rem + 8vw, 8.5rem);
    line-height: 0.88;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    text-shadow: 0 2px 30px oklch(0 0 0 / 0.45);
    view-transition-name: page-title;
}

.lead { font-size: clamp(1.05rem, 1rem + 0.35vw, 1.25rem); color: var(--muted); max-width: 40rem; }

/* ---------- Sections ---------- */
.section { display: grid; gap: 1.75rem; }

.section-title {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: clamp(2.3rem, 1.7rem + 2.4vw, 3.6rem);
    line-height: 0.95;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    display: grid;
    gap: 0.5rem;
}

.section-title::after {
    content: "";
    width: 3rem;
    height: 2px;
    margin-top: 0.4rem;
    background: var(--gold);
}

.prompt {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    color: var(--gold);
    letter-spacing: 0;
    text-transform: none;
    font-variant-ligatures: none;
}

.section-lead { color: var(--muted); margin-top: -0.5rem; max-width: 40rem; }

.meta { color: var(--gold); font-size: 0.9rem; font-weight: 500; }

.btn {
    justify-self: start;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-family: var(--font-display);
    font-size: 1.25rem;
    letter-spacing: 0.06em;
    line-height: 1;
    text-transform: uppercase;
    text-decoration: none;
    padding: 0.8rem 1.4rem 0.7rem;
    border-radius: 999px;
    background: var(--gold);
    color: oklch(0.14 0.01 80);
    transition: transform 0.3s var(--ease-out), box-shadow 0.3s, background-color 0.2s;
}

.btn:hover { transform: translateY(-2px); background: var(--gold-hi); box-shadow: 0 10px 30px -12px var(--gold); }

.text-link { color: var(--gold); font-weight: 600; font-size: 0.9rem; text-underline-offset: 3px; }
.band-links { display: flex; flex-wrap: wrap; gap: 0.4rem 1.1rem; }

.tbd {
    display: inline-block;
    vertical-align: middle;
    font-family: var(--font-mono);
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 0.15rem 0.45rem;
    border-radius: 0.35rem;
    border: 1px dashed currentColor;
    color: oklch(0.72 0.18 20);
    font-style: normal;
}

.tags { display: flex; flex-wrap: wrap; gap: 0.4rem; }

.tags li {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    padding: 0.2rem 0.55rem;
    border-radius: 0.3rem;
    border: 1px solid color-mix(in oklch, var(--gold) 35%, transparent);
    color: var(--gold);
}

/* Shared panel look for cards */
.now-card, .tl-card, .skill-group, .project-card {
    border-radius: var(--radius);
    border: 1px solid var(--line);
    background: var(--card);
}

/* Display-type names on cards */
.now-name, .tl-name, .commit-title, .project-name {
    font-family: var(--font-display);
    font-weight: 400;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    line-height: 1;
}

/* ---------- Music: now playing ---------- */
.now-card {
    position: relative;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: clamp(1.5rem, 5vw, 3.5rem);
    align-items: center;
    padding: clamp(1.5rem, 4vw, 3rem);
    background:
        radial-gradient(ellipse 60% 90% at 0% 50%, color-mix(in oklch, var(--gold) 14%, transparent), transparent 70%),
        var(--card);
    box-shadow: var(--shadow);
    overflow: hidden;
}

.vinyl {
    width: clamp(8rem, 22vw, 14rem);
    aspect-ratio: 1;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background:
        radial-gradient(circle, transparent 0 30%, oklch(0 0 0 / 0.35) 30.5%, transparent 31%),
        repeating-radial-gradient(circle, oklch(0.16 0 0) 0 2px, oklch(0.22 0 0) 2px 3px),
        oklch(0.14 0 0);
    box-shadow: 0 20px 40px -15px oklch(0 0 0 / 0.7), inset 0 0 0 1px oklch(1 0 0 / 0.06);
    animation: spin 6s linear infinite;
    position: relative;
}

.vinyl::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: conic-gradient(from 30deg, transparent 0 15%, oklch(1 0 0 / 0.1) 20%, transparent 25% 65%, oklch(1 0 0 / 0.08) 70%, transparent 75%);
}

.vinyl-label {
    width: 36%;
    aspect-ratio: 1;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: radial-gradient(circle, oklch(0.14 0 0) 0 7%, oklch(0.78 0.085 85) 8%);
    color: oklch(0.2 0.02 60);
    font-family: var(--font-display);
    font-size: clamp(0.8rem, 1.5vw, 1.1rem);
    letter-spacing: 0.1em;
}

@keyframes spin { to { rotate: 360deg; } }

.now-body { display: grid; gap: 0.75rem; }

.now-label {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--gold);
}

.live-dot {
    width: 0.55rem;
    height: 0.55rem;
    border-radius: 50%;
    background: oklch(0.68 0.21 25);
    box-shadow: 0 0 0 0 oklch(0.68 0.21 25 / 0.6);
    animation: pulse 1.8s infinite;
}

@keyframes pulse { 70% { box-shadow: 0 0 0 0.6rem oklch(0.68 0.21 25 / 0); } 100% { box-shadow: 0 0 0 0 oklch(0.68 0.21 25 / 0); } }

.now-name { font-size: clamp(2.6rem, 1.8rem + 3vw, 4.4rem); }
.now-blurb { color: var(--muted); max-width: 38rem; }

@media (max-width: 40rem) {
    .now-card { grid-template-columns: 1fr; }
    .vinyl { justify-self: center; }
}

/* ---------- Music: timeline ---------- */
.timeline {
    position: relative;
    display: grid;
    gap: 1.5rem;
}

.timeline::before {
    content: "";
    position: absolute;
    left: 6rem;
    top: 0.5rem;
    bottom: 0.5rem;
    width: 1px;
    background: linear-gradient(var(--gold), transparent);
}

.tl-item {
    display: grid;
    grid-template-columns: 6rem 1fr;
    gap: 1.75rem;
    align-items: start;
    position: relative;
}

.tl-item::before {
    content: "";
    position: absolute;
    left: calc(6rem - 0.35rem);
    top: 1.55rem;
    width: 0.7rem;
    height: 0.7rem;
    border-radius: 50%;
    background: var(--bg);
    border: 2px solid var(--gold);
}

.tl-year {
    font-family: var(--font-display);
    font-size: 1.35rem;
    letter-spacing: 0.04em;
    color: var(--gold);
    padding-top: 1.05rem;
    padding-right: 1rem;
    text-align: right;
    line-height: 1.1;
}

.tl-card {
    container-type: inline-size;
    display: grid;
    gap: 0.5rem;
    padding: 1.25rem 1.5rem;
    transition: transform 0.4s var(--ease-out), border-color 0.3s;
}

.tl-card:hover { transform: translateX(0.35rem); border-color: color-mix(in oklch, var(--gold) 55%, var(--line)); }

.tl-name { font-size: 1.9rem; }
.tl-card p:not(.meta) { color: var(--muted); }

/* The name is a button whose ::after covers the card, so the whole card
   opens the enlarged view; links are lifted above that layer. */
.tl-card { position: relative; cursor: pointer; }
.tl-open {
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    color: inherit;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    text-align: left;
}
.tl-open::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius); }
.tl-open:focus-visible { outline: none; }
.tl-open:focus-visible::after { outline: 2px solid var(--gold); outline-offset: 3px; }
.tl-card:hover .tl-open { color: var(--gold-hi); }
.tl-card .band-links { position: relative; z-index: 1; width: fit-content; }

/* ---------- Music: enlarged band card ---------- */
.band-dialog {
    width: min(52rem, calc(100vw - 2rem));
    max-height: calc(100dvh - 2rem);
    margin: auto;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: calc(var(--radius) * 1.5);
    background: var(--bg-2);
    color: var(--fg);
    box-shadow: var(--shadow);
    overflow: auto;
    overscroll-behavior: contain;
}

.band-dialog::backdrop {
    background: oklch(0.08 0.005 80 / 0.72);
    backdrop-filter: blur(6px);
}

.band-sheet {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
}

.band-sheet.no-photo { grid-template-columns: 1fr; }

.band-photo {
    width: 100%;
    height: 100%;
    min-height: 18rem;
    object-fit: cover;
    display: block;
}

.band-body {
    display: grid;
    align-content: start;
    gap: 0.75rem;
    padding: clamp(1.5rem, 4vw, 2.5rem);
    padding-right: clamp(3rem, 5vw, 3.5rem);
}

.band-years {
    font-family: var(--font-display);
    font-size: 1.2rem;
    letter-spacing: 0.06em;
    color: var(--gold);
}

.band-title {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: clamp(2.4rem, 2rem + 2vw, 3.4rem);
    letter-spacing: 0.03em;
    text-transform: uppercase;
    line-height: 0.95;
}

.band-blurb { color: var(--muted); }

.band-clip {
    display: grid;
    gap: 0.4rem;
    margin: 0.5rem 0 0;
    padding: 0.85rem 1rem;
    border-radius: var(--radius);
    border: 1px solid color-mix(in oklch, var(--gold) 30%, var(--line));
    background: color-mix(in oklch, var(--gold) 6%, transparent);
}

.band-clip figcaption {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    color: var(--gold);
}

.band-clip audio { width: 100%; height: 2.5rem; }

.band-close-form { position: absolute; top: 0.75rem; right: 0.75rem; z-index: 1; }

.band-close {
    display: grid;
    place-items: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    border: 1px solid var(--line);
    background: color-mix(in oklch, var(--bg) 80%, transparent);
    color: var(--fg);
    cursor: pointer;
    transition: border-color 0.2s, color 0.2s;
}

.band-close svg { width: 1.1rem; height: 1.1rem; stroke: currentColor; stroke-width: 2; stroke-linecap: round; fill: none; }
.band-close:hover { border-color: var(--gold); color: var(--gold); }

@media (prefers-reduced-motion: no-preference) {
    .band-dialog[open] { animation: band-in 0.35s var(--ease-out); }
    .band-dialog[open]::backdrop { animation: fade-in 0.35s ease-out; }
}

@keyframes band-in { from { opacity: 0; transform: translateY(1.5rem) scale(0.97); } }
@keyframes fade-in { from { opacity: 0; } }

@media (max-width: 40rem) {
    .band-sheet { grid-template-columns: 1fr; }
    .band-photo { height: auto; min-height: 0; max-height: 45vh; }
}

@media (max-width: 36rem) {
    .timeline::before { left: 0.35rem; }
    .tl-item { grid-template-columns: 1fr; gap: 0.35rem; padding-left: 1.5rem; }
    .tl-item::before { left: 0; top: 0.35rem; }
    .tl-year { padding: 0; text-align: left; }
}

/* ---------- Dev: git log ---------- */
.gitlog {
    display: grid;
    position: relative;
    font-size: 0.98rem;
}

.commit {
    position: relative;
    display: grid;
    gap: 0.55rem;
    padding: 0 0 2.5rem 2.25rem;
    border-left: 2px solid color-mix(in oklch, var(--gold) 35%, transparent);
    margin-left: 0.5rem;
}

.commit:last-child { border-left-color: transparent; padding-bottom: 0; }

.commit::before {
    content: "";
    position: absolute;
    left: -0.5rem;
    top: 0.2rem;
    width: 0.9rem;
    height: 0.9rem;
    border-radius: 50%;
    background: var(--bg);
    border: 2px solid var(--gold);
}

.commit.is-head::before { background: var(--gold); box-shadow: 0 0 0 5px color-mix(in oklch, var(--gold) 22%, transparent); }

.commit-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    font-family: var(--font-mono);
    font-size: 0.8rem;
}

.hash { color: var(--gold); }

.ref {
    padding: 0.05rem 0.5rem;
    border-radius: 0.3rem;
    border: 1px solid var(--gold);
    color: var(--gold);
    font-weight: 600;
}

.commit-date { color: var(--muted); }
.commit-title { font-size: clamp(1.7rem, 1.4rem + 1vw, 2.1rem); }
.at { color: var(--gold); }
.commit > p { color: var(--muted); max-width: 44rem; }

/* ---------- Dev: toolbox ---------- */
.skill-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
    gap: 1rem;
}

.skill-group {
    padding: 1.25rem 1.35rem;
    display: grid;
    gap: 0.9rem;
    align-content: start;
}

.skill-cat {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: 1.35rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--gold);
}

.skill-list { display: grid; gap: 0.8rem; }

.skill {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0.3rem 0.75rem;
    align-items: baseline;
}

.skill-name { font-weight: 600; }
.skill-stat { font-family: var(--font-mono); font-size: 0.72rem; color: var(--muted); }

.skill-bar {
    grid-column: 1 / -1;
    height: 3px;
    border-radius: 99px;
    background: color-mix(in oklch, var(--gold) 14%, transparent);
    overflow: hidden;
}

.skill-bar span {
    display: block;
    height: 100%;
    width: calc(var(--v) * 100%);
    border-radius: inherit;
    background: linear-gradient(90deg, color-mix(in oklch, var(--gold) 45%, transparent), var(--gold));
    transform-origin: 0 50%;
}

/* ---------- Projects ---------- */
.project-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
    gap: 1rem;
}

.project-card {
    container-type: inline-size;
    position: relative;
    display: grid;
    gap: 0.65rem;
    align-content: start;
    padding: 1.4rem 1.5rem;
    transition: transform 0.4s var(--ease-out), border-color 0.3s, box-shadow 0.4s;
}

.project-card:hover {
    transform: translateY(-4px);
    border-color: color-mix(in oklch, var(--gold) 55%, var(--line));
    box-shadow: var(--shadow);
}

.project-top { display: flex; align-items: start; justify-content: space-between; gap: 0.75rem; }
.project-name { font-size: 1.7rem; }
.project-name a { text-decoration: none; }
.project-name a:hover { color: var(--gold); }
.project-tagline { color: var(--gold); font-weight: 500; font-size: 0.92rem; }
.project-desc { color: var(--muted); font-size: 0.95rem; }

.badge-crossover {
    flex: none;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    font-weight: 600;
    padding: 0.2rem 0.5rem;
    border-radius: 0.3rem;
    background: linear-gradient(90deg, color-mix(in oklch, var(--amber) 22%, transparent), color-mix(in oklch, var(--cyan) 22%, transparent));
    white-space: nowrap;
}

@container (min-width: 30rem) {
    .project-desc { font-size: 1rem; }
}

/* ---------- Switch to the other side ---------- */
.switch-side {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: grid;
    gap: 0.6rem;
    padding: clamp(2.5rem, 7vw, 4.5rem) clamp(1.5rem, 5vw, 3.5rem);
    border-radius: var(--radius);
    text-decoration: none;
    border: 1px solid var(--line);
    background: var(--bg-2);
    transition: border-color 0.3s;
}

.switch-side::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    opacity: 0.5;
    transition: opacity 0.6s var(--ease-out);
}

.switch-side.dev { text-align: right; justify-items: end; }
.switch-side.dev::before { background: radial-gradient(ellipse 70% 120% at 100% 100%, color-mix(in oklch, var(--cyan) 22%, transparent), transparent 70%); }
.switch-side.music::before { background: radial-gradient(ellipse 70% 120% at 0% 0%, color-mix(in oklch, var(--amber) 22%, transparent), transparent 70%); }
.switch-side:hover { border-color: color-mix(in oklch, var(--gold) 50%, var(--line)); }
.switch-side:hover::before { opacity: 1; }

.switch-title {
    font-family: var(--font-display);
    font-size: clamp(2.8rem, 1.8rem + 4.5vw, 5.5rem);
    line-height: 0.95;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--gold);
    transition: letter-spacing 0.5s var(--ease-out), color 0.3s;
}

.switch-title span { display: inline-block; transition: transform 0.4s var(--ease-out); }
.switch-side:hover .switch-title { color: var(--gold-hi); letter-spacing: 0.06em; }
.switch-side:hover .switch-title span { transform: translateX(0.5rem); }

/* ---------- Not found ---------- */
.not-found { justify-items: start; row-gap: 1.25rem; min-height: 80svh; align-content: center; padding-top: 6rem; }
.not-found .page-title { text-shadow: none; }

.nf-code {
    font-family: var(--font-display);
    font-size: clamp(7rem, 26vw, 16rem);
    line-height: 0.85;
    color: var(--gold);
}

/* ---------- Footer ---------- */
.site-footer {
    border-top: 1px solid var(--line);
    padding: 2.5rem var(--gutter) 2rem;
    display: grid;
    gap: 1.5rem;
    max-width: calc(var(--maxw) + 2 * var(--gutter));
    margin-inline: auto;
}

.footer-inner { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 1.5rem; }

.footer-name {
    font-family: var(--font-display);
    font-size: 1.8rem;
    line-height: 1;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.footer-links { display: flex; gap: 1.25rem; flex-wrap: wrap; align-items: center; }
.footer-links > a { font-weight: 500; text-decoration: none; }
.footer-links > a:hover { color: var(--gold); }
.footer-fine { font-size: 0.8rem; }
.muted { color: var(--muted); }

/* ==========================================================================
   Motion
   ========================================================================== */

/* Scroll-driven reveal: elements rise into place as they enter the viewport. */
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .reveal {
            animation: reveal linear both;
            animation-timeline: view();
            animation-range: entry 0% cover 25%;
        }
        .skill-group .skill-bar span {
            animation: fill linear both;
            animation-timeline: view();
            animation-range: entry 10% cover 35%;
        }
    }
}

@keyframes reveal {
    from { opacity: 0; transform: translateY(2.5rem) scale(0.98); }
}

@keyframes fill { from { transform: scaleX(0); } }

/* Page load: the photo fades up, the name rises, the two ways in slide in
   from their own side. Only on the static shell (the first paint), so it
   doesn't replay when Blazor takes over the same markup. */
@media (prefers-reduced-motion: no-preference) {
    .shell .hero-photo { animation: photo-in 1.6s var(--ease-out) backwards; }
    .shell .hero-mark { animation: rise 0.9s var(--ease-out) 0.2s backwards; }
    .shell .hero-link.music { animation: in-left 0.9s var(--ease-out) 0.45s backwards; }
    .shell .hero-link.dev { animation: in-right 0.9s var(--ease-out) 0.6s backwards; }
    .shell .social-rail { animation: rise 0.7s var(--ease-out) 0.8s backwards; }
    .banner-text > * { animation: rise 0.9s var(--ease-out) backwards; }
    .banner-text > .page-title { animation-delay: 0.1s; }
    .banner-text > .lead { animation-delay: 0.2s; }
}

@keyframes in-left { from { opacity: 0; transform: translateX(-2rem); } }
@keyframes in-right { from { opacity: 0; transform: translateX(2rem); } }
@keyframes rise { from { opacity: 0; transform: translateY(1rem); } }
@keyframes photo-in { from { opacity: 0; scale: 1.06; } }

/* View transitions between routes. The photo (front page to banner) and the page title morph on
   their own (named); the rest slides toward the side you're heading to. */
::view-transition-group(portrait) { animation-duration: 0.65s; animation-timing-function: var(--ease-out); }
/* The front-page photo and the banner differ in shape (a lot on a phone), so crop the
   snapshots to the morphing box instead of letting them stretch or spill out. */
::view-transition-image-pair(portrait) { overflow: clip; }
::view-transition-old(portrait), ::view-transition-new(portrait) { height: 100%; object-fit: cover; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.45s; animation-timing-function: var(--ease-out); }

[data-vt-direction="to-music"]::view-transition-old(root) { animation-name: vt-fade-out, vt-to-right; }
[data-vt-direction="to-music"]::view-transition-new(root) { animation-name: vt-fade-in, vt-from-left; }
[data-vt-direction="to-dev"]::view-transition-old(root) { animation-name: vt-fade-out, vt-to-left; }
[data-vt-direction="to-dev"]::view-transition-new(root) { animation-name: vt-fade-in, vt-from-right; }

@keyframes vt-fade-out { to { opacity: 0; } }
@keyframes vt-fade-in { from { opacity: 0; } }
@keyframes vt-to-right { to { transform: translateX(3rem); } }
@keyframes vt-from-left { from { transform: translateX(-3rem); } }
@keyframes vt-to-left { to { transform: translateX(-3rem); } }
@keyframes vt-from-right { from { transform: translateX(3rem); } }

/* Theme switch: a circular wipe. */
.theme-switching::view-transition-old(root) { animation: none; }
.theme-switching::view-transition-new(root) { animation: wipe 0.6s var(--ease-out); }
@keyframes wipe { from { clip-path: circle(0% at 100% 0%); } to { clip-path: circle(150% at 100% 0%); } }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}

/* ---------- Blazor error UI ---------- */
#blazor-error-ui {
    display: none;
    position: fixed;
    inset: auto 1rem 1rem 1rem;
    z-index: 100;
    padding: 0.8rem 1rem;
    border-radius: 0.75rem;
    background: oklch(0.45 0.16 25);
    color: white;
    box-shadow: var(--shadow);
}

#blazor-error-ui .reload { color: white; margin-left: 0.5rem; }
#blazor-error-ui .dismiss { float: right; background: none; border: 0; color: white; font-size: 1.2rem; cursor: pointer; }
