/* ============================================================
   Anna Chope — Portfolio
   Monochrome · Soft Structuralism hybrid
   Black, white, and gray — no color accents
   Alata (display & body) · JetBrains Mono (meta)
   ============================================================ */

:root {
    --bg: #FDFDFD;          /* near-white canvas */
    --bg-alt: #F4F4F4;      /* subtle alternate sections */
    --surface: #FFFFFF;     /* inner card cores */
    --glass: rgba(255, 255, 255, 0.6);

    --ink: #111111;         /* near-black — headings & primary CTA */
    --text: #2A2A2A;        /* dark gray body */
    --muted: #6B6B6B;       /* secondary text */
    --line: rgba(0, 0, 0, 0.09);
    --line-soft: rgba(0, 0, 0, 0.05);
    --line-strong: rgba(0, 0, 0, 0.18);

    --mist: #ECECEC;        /* lightest wash */
    --teal: #BDBDBD;        /* mid accent */
    --cyan: #1A1A1A;        /* the pop — now near-black */
    --cyan-deep: #000000;   /* pressed / legible-on-white */
    --cyan-ink: #333333;    /* text on pale chips */

    --font-display: 'Alata', system-ui, -apple-system, sans-serif;
    --font-body: 'Alata', system-ui, -apple-system, sans-serif;
    --font-mono: 'JetBrains Mono', ui-monospace, monospace;

    --ease: cubic-bezier(0.16, 1, 0.3, 1);
    --spring: cubic-bezier(0.32, 0.72, 0, 1);

    --radius: 28px;
    --shell-pad: 0.6rem;
    --radius-inner: 18px;   /* radius - shell-pad, concentric */
    --radius-sm: 14px;
    --maxw: 1180px;
    --sidebar-w: clamp(320px, 34vw, 460px);
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: var(--font-body);
    text-decoration: none;
    list-style: none;
}

html {
    scroll-behavior: smooth;
    scroll-snap-type: y mandatory;
}

body {
    background-color: var(--bg);
    color: var(--text);
    font-size: 1rem;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overflow-x: hidden;
    position: relative;
}

/* fixed grain overlay — the "noisy" texture, applied once, never on scrolling content */
body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 4;
    pointer-events: none;
    opacity: 0.045;
    mix-blend-mode: multiply;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

::selection {
    background: var(--ink);
    color: #fff;
}

:focus-visible {
    outline: 2px solid var(--cyan-deep);
    outline-offset: 3px;
}

h1, h2, h3 {
    font-family: var(--font-display);
    font-weight: 400;
    letter-spacing: -0.02em;
    line-height: 1.08;
    color: var(--ink);
    text-wrap: balance;
}

/* ---------- Eyebrow tags ---------- */
.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.4rem 1rem;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.05);
    border: 1px solid rgba(0, 0, 0, 0.15);
    color: var(--cyan-ink);
    font-family: var(--font-mono);
    font-size: 0.66rem;
    font-weight: 500;
    letter-spacing: 0.2em;
    text-transform: uppercase;
}

/* hero eyebrow reads as plain label copy, no pill chrome */
.identity .eyebrow {
    padding: 0;
    background: none;
    border: none;
    color: var(--muted);
}

/* ---------- Header — invisible pill, blurs whatever scrolls beneath it ----------
   mix-blend-mode only has real page content to blend against when it's applied to
   the fixed/positioned element itself — on a *child* of a fixed ancestor it gets
   trapped in that ancestor's own stacking context and never reaches the real
   backdrop, and isolation on a child can't opt it out of an ancestor's blend
   either (confirmed empirically) — an ancestor with mix-blend-mode flattens its
   whole subtree into one image before blending, isolated descendants included.
   That's exactly why the CTA can't just live inside the blended pill: its own
   text would be differenced against the same backdrop as its own background,
   and for some backdrop brightnesses that collapses their contrast to near zero.
   So this is two overlapping fixed layers sharing one .nav-shell footprint —
   .header-glass is the plain, unblended frosted pill holding the real CTA;
   header sits on top with the difference blend for the logo/nav text, with a
   same-sized hidden clone of the button (.visit-btn--ghost) reserving its
   layout space so the nav links stop in the right place without overlapping it.
   header has pointer-events:none with its real controls opted back in, so
   clicks in its "empty" reserved area fall through to the real button below. */
/* header and .header-glass share top+padding but have different content
   (64px logo vs the shorter CTA button), so without an explicit shared
   height their boxes end up different heights — same top, different bottom
   — which pulls their vertical centers apart even though each is correctly
   centered within its own box. Locking height to the logo's here keeps both
   centered on the same line. */
.nav-shell {
    position: fixed;
    top: 1.5rem;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    height: calc(64px + 1.2rem);
    padding: 0.6rem 0.6rem 0.6rem 1.1rem;
    border-radius: 999px;
    z-index: 1000;
    width: min(1080px, 92%);
}

.header-glass {
    background-color: transparent;
    backdrop-filter: blur(18px) grayscale(1);
    -webkit-backdrop-filter: blur(18px) grayscale(1);
    justify-content: flex-end;
}

header {
    gap: 2.5rem;
    background-color: transparent;
    mix-blend-mode: difference;
    pointer-events: none;
}

header .logo,
header .menu-toggle,
header .nav-links a {
    pointer-events: auto;
}

/* the mobile dropdown (below) is an opaque card, not a translucent overlay —
   it needs its own guaranteed contrast, so difference is switched off while
   it's open rather than let it get swept into the pill's blended composite.
   the logo mark and hamburger bars are pre-inverted to white to feed that
   blend, so they also need reverting to their natural dark color, or they go
   invisible once the blend is off */
header:has(.nav-links.active) {
    mix-blend-mode: normal;
}

header:has(.nav-links.active) .logo-mark {
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.12));
}

header:has(.nav-links.active) .menu-toggle span {
    background: var(--ink);
}

.logo {
    display: flex;
    align-items: center;
    margin-right: auto;
    transition: opacity 0.3s var(--ease);
}

.logo:hover { opacity: 0.7; }

.logo-mark {
    height: 64px;
    width: auto;
    display: block;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.12));
}

/* mark is drawn black in the source SVG — invert to white first so header's
   difference blend can push it dark-on-light / light-on-dark to match
   whatever backdrop is scrolling underneath the fixed pill */
header .logo-mark {
    filter: invert(1) drop-shadow(0 2px 6px rgba(0, 0, 0, 0.12));
}

.nav-links {
    display: flex;
    gap: 2rem;
}

li a {
    position: relative;
    color: var(--text);
    font-weight: 500;
    font-size: 0.92rem;
    transition: color 0.25s var(--ease);
}

li a:hover { color: var(--cyan-deep); }

/* white source color feeds header's difference blend: reads dark on the
   light page background and auto-inverts to stay legible over images/video */
header .nav-links li a,
header .nav-links li a:hover {
    color: #fff;
}

li a::before {
    position: absolute;
    display: block;
    content: '';
    width: 0;
    left: 0;
    height: 1.5px;
    bottom: -5px;
    transition: width 0.35s var(--spring);
    background: var(--cyan);
}

li a:hover::before { width: 100%; }

.visit-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    padding: 0.5rem 1rem;
    border-radius: 999px;
    border: 1px solid transparent;
    background: linear-gradient(135deg, var(--cyan) 0%, var(--cyan-deep) 100%);
    color: #fff;
    font-weight: 500;
    font-size: 0.9rem;
    font-family: var(--font-body);
    cursor: pointer;
    box-shadow: 0 12px 28px -10px rgba(0, 0, 0, 0.4);
    transition: transform 0.3s var(--spring), box-shadow 0.3s var(--spring);
    text-wrap: nowrap;
}

/* same-sized stand-in inside the blended header, reserving layout space for
   the real button (in .header-glass) without being visible or blended itself */
.visit-btn--ghost {
    visibility: hidden;
}

.visit-btn .btn-icon {
    width: 2rem;
    height: 2rem;
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.22);
    transition: transform 0.6s var(--spring);
}

.visit-btn:hover .btn-icon { transform: translate(2px, -2px) scale(1.06); }
.visit-btn:active { transform: scale(0.97); }

/* ---------- Hamburger morph ---------- */
.menu-toggle {
    display: none;
    width: 34px;
    height: 34px;
    border: none;
    background: none;
    cursor: pointer;
    position: relative;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
}

.menu-toggle span {
    display: block;
    width: 19px;
    height: 1.5px;
    background: #fff;
    border-radius: 2px;
    transition: transform 0.5s var(--spring), opacity 0.3s var(--ease), background 0.25s var(--ease);
}

.menu-toggle.active span:first-child {
    transform: translateY(3.75px) rotate(45deg);
}

.menu-toggle.active span:last-child {
    transform: translateY(-3.75px) rotate(-45deg);
}

/* ---------- Layout ---------- */
section {
    min-height: 100dvh;
    padding: 11rem 8% 8rem;
    width: 100%;
    max-width: calc(var(--maxw) + 16%);
    margin: 0 auto;
    position: relative;
}

/* ---------- Split layout: fixed sidebar + scrolling project column ---------- */
.split-layout {
    display: flex;
    min-height: 100vh;
}

.sidebar {
    position: fixed;
    top: 0;
    left: 0;
    width: var(--sidebar-w);
    height: 100vh;
    overflow: hidden;
    z-index: 10;
}

.sidebar-inner {
    min-height: 100%;
    display: flex;
    flex-direction: column;
    gap: 1.4rem;
    padding: 3rem 2.5rem 2.5rem;
}

.sidebar .logo { animation: fadeUp 0.7s var(--ease) both; }
.sidebar .logo-mark { height: 40px; }

.identity {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    animation: fadeUp 0.7s var(--ease) 0.08s both;
}

.identity h1 {
    font-size: 2rem;
    letter-spacing: -0.02em;
}

.identity .role {
    font-size: 0.95rem;
    font-weight: 400;
    color: var(--muted);
    font-family: var(--font-display);
    display: inline-block;
    transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}

.identity .role.is-out {
    opacity: 0;
    transform: translateY(6px);
}

.sidebar-bio {
    font-size: 0.875rem;
    line-height: 1.4;
    color: var(--text);
    max-width: 32ch;
    animation: fadeUp 0.7s var(--ease) 0.28s both;
}

/* ---------- Buttons: pill + nested icon-circle (used by project-page nav) ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    border-radius: 999px;
    padding: 0.5rem 0.5rem 0.5rem 1.5rem;
    border: 1px solid var(--line-strong);
    background: rgba(255, 255, 255, 0.55);
    color: var(--ink);
    cursor: pointer;
    font-weight: 400;
    font-size: 0.95rem;
    text-wrap: nowrap;
    transition: background 0.4s var(--spring), color 0.3s var(--spring), border-color 0.4s var(--spring), transform 0.3s var(--spring), box-shadow 0.4s var(--spring);
}

.btn .btn-icon {
    width: 2rem;
    height: 2rem;
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.06);
    transition: transform 0.6s var(--spring), background 0.4s var(--spring);
}

.btn .btn-icon i { font-size: 0.85rem; }

.btn:hover {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
    box-shadow: 0 18px 36px -14px rgba(0, 0, 0, 0.3);
}

.btn:hover .btn-icon {
    background: rgba(255, 255, 255, 0.18);
    transform: translate(2px, -2px) scale(1.06);
}

.btn:active { transform: scale(0.98); }

.sidebar-links {
    display: flex;
    gap: 1.2rem;
}

.sidebar-links a {
    display: inline-flex;
    position: relative;
    cursor: pointer;
}

.sidebar-links i {
    font-size: 1.3rem;
    color: var(--muted);
    transition: color 0.25s var(--ease), transform 0.3s var(--spring);
}

.sidebar-links a:hover i {
    transform: translateY(-3px);
    color: var(--cyan-deep);
}

/* name pops up above the icon on hover, hidden otherwise — matches jyang.io */
.link-label {
    position: absolute;
    bottom: calc(100% + 0.6rem);
    left: 50%;
    transform: translate(-50%, 4px);
    font-family: var(--font-mono);
    font-size: 0.68rem;
    white-space: nowrap;
    color: var(--cyan-deep);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
}

.sidebar-links a:hover .link-label {
    opacity: 1;
    transform: translate(-50%, 0);
}

/* ---------- Sidebar: experience + contact ---------- */
.sidebar-section {
    animation: fadeUp 0.7s var(--ease) 0.36s both;
}

.sidebar-heading {
    font-family: var(--font-mono);
    font-size: 0.68rem;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--cyan-deep);
    opacity: 0.5;
    margin-bottom: 0.75rem;
}

.exp-list {
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}

.exp-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.3rem 1rem;
    font-family: var(--font-display);
    color: var(--ink);
    font-size: 0.9rem;
}

.exp-time {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    color: var(--muted);
    white-space: nowrap;
}

.exp-time--live {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.exp-time--live video {
    width: 8px;
    height: 8px;
    display: block;
}

.exp-list p {
    font-size: 0.85rem;
    line-height: 1.6;
    color: var(--muted);
    margin-top: 0.35rem;
}

.sidebar-section p {
    font-size: 0.9rem;
    line-height: 1.65;
    color: var(--muted);
    max-width: 38ch;
}

.contact-mail {
    display: inline-block;
    margin-top: 0;
    color: var(--cyan-deep);
    font-family: var(--font-display);
    font-size: 1rem;
    border-bottom: 1px solid transparent;
    transition: border-color 0.25s var(--ease);
}

.contact-mail:hover { border-color: var(--cyan-deep); }

.sidebar .sidebar-links {
    padding-top: 1.25rem;
}

/* pushes experience + contact down as a group to rest against the divider
   above the icon row, leaving the open space above them instead */
#experience {
    margin-top: auto;
}

#contact {
    margin-top: 0.75rem;
}

.sidebar-meta {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    color: var(--muted);
    letter-spacing: 0.02em;
}

/* ---------- Right column: full-bleed project scroll, no rounded corners ---------- */
.project-scroll {
    margin-left: var(--sidebar-w);
    width: calc(100% - var(--sidebar-w));
    display: flex;
    flex-direction: column;
}

.scroll-card {
    display: block;
    border-top: 1px solid var(--line);
}

.scroll-card:first-child { border-top: none; }

.scroll-card-media {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--bg-alt);
}

.scroll-card-media img,
.scroll-card-media video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: filter 0.6s var(--spring), transform 0.7s var(--spring);
}

.scroll-card:hover .scroll-card-media img {
    filter: grayscale(1) contrast(1.12) brightness(1.03);
    transform: scale(1.035);
}

.scroll-card:hover .scroll-card-media video {
    transform: scale(1.035);
}

.scroll-card-meta {
    display: flex;
    align-items: baseline;
    gap: 1.5rem;
    padding: 1.15rem 2.75rem;
}

.scroll-card-year {
    font-family: var(--font-mono);
    font-size: 0.78rem;
    color: var(--muted);
}

.scroll-card-title {
    font-family: var(--font-display);
    font-size: 1.05rem;
    color: var(--ink);
    margin-right: auto;
}

.scroll-card-tag {
    font-family: var(--font-mono);
    font-size: 0.76rem;
    color: var(--muted);
    text-align: right;
}

/* ---------- Mobile-only jump-to-bottom button ---------- */
.jump-bottom-btn {
    display: none;
    align-items: center;
    justify-content: center;
    position: fixed;
    bottom: 1.5rem;
    right: 1.5rem;
    width: 46px;
    height: 46px;
    border-radius: 999px;
    background: var(--ink);
    color: #fff;
    font-size: 1.1rem;
    box-shadow: 0 12px 28px -10px rgba(0, 0, 0, 0.4);
    z-index: 500;
    transition: transform 0.3s var(--spring);
}

.jump-bottom-btn:active { transform: scale(0.92); }

/* ---------- Scrollbar ---------- */
::-webkit-scrollbar { width: 11px; }
::-webkit-scrollbar-track { background-color: var(--bg-alt); }
::-webkit-scrollbar-thumb {
    background: var(--teal);
    border-radius: 999px;
    border: 3px solid var(--bg-alt);
}
::-webkit-scrollbar-thumb:hover { background: var(--cyan); }

/* ---------- Scroll reveal ---------- */
.reveal {
    opacity: 0;
    transform: translateY(20px);
    filter: blur(6px);
    transition: opacity 0.9s var(--ease), transform 0.9s var(--ease), filter 0.9s var(--ease);
    will-change: opacity, transform, filter;
}

.reveal.visible {
    opacity: 1;
    transform: translateY(0);
    filter: blur(0);
}

@keyframes fadeUp {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: translateY(0); }
}

@keyframes fadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    *, .reveal { animation: none !important; transition: none !important; opacity: 1 !important; transform: none !important; filter: none !important; }

    /* a soft opacity crossfade is safe under reduced motion (no positional movement) */
    .role { transition: opacity 0.5s ease !important; }
    .role.is-out { opacity: 0 !important; transform: none !important; }
}

/* ============================================================
   Project detail pages
   ============================================================ */
.project-page {
    max-width: 880px;
    margin: 0 auto;
    padding: 10rem 2rem 7rem;
    display: flex;
    flex-direction: column;
    gap: 0;
    position: relative;
    z-index: 1;
    scroll-snap-align: end;
}

/* pages that open with a full-bleed image butt it right up against the hero */
.project-page--flush-top { padding-top: 0; }

/* space between successive blocks by default (text keeps its rhythm)... */
.project-page > * + * { margin-top: 3.25rem; }

/* ...but adjacent images/videos sit flush against each other, edge to edge */
.project-page > [class*="project-page-image"] + [class*="project-page-image"],
.project-page > [class*="project-page-image"] + .project-page-video,
.project-page > .project-page-video + [class*="project-page-image"],
.project-page > .project-page-video + .project-page-video { margin-top: 0; }

.back-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.8rem;
    letter-spacing: 0.02em;
    transition: color 0.25s var(--ease);
}

.back-btn:hover { color: var(--cyan-deep); }

/* ---------- Split hero: full-bleed photo + title/meta column ---------- */
.hero-split {
    display: flex;
    min-height: 80vh;
    margin-top: 138px;
    scroll-snap-align: start;
}

.hero-split-media {
    flex: 1 1 50%;
    align-self: stretch;
    overflow: hidden;
    background: var(--bg-alt);
}

.hero-split-media img,
.hero-split-media video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;

}

.hero-split-content {
    flex: 1 1 50%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 1.75rem;
    padding: 8rem 4.5rem;
}

.hero-split-content .back-btn { animation: fadeUp 0.7s var(--ease) both; }

.hero-split-content h1 {
    font-size: clamp(2.5rem, 5vw, 4rem);
    letter-spacing: -0.03em;
    animation: fadeUp 0.7s var(--ease) 0.1s both;
}

.hero-split-content .project-page-tagline {
    animation: fadeUp 0.7s var(--ease) 0.2s both;
}

.hero-split-content .project-page-meta {
    margin-top: 0.5rem;
    animation: fadeUp 0.7s var(--ease) 0.3s both;
}

.project-page-tagline {
    font-size: 1.2rem;
    font-weight: 400;
    max-width: 60ch;
    line-height: 1.6;
    color: var(--muted);
}

.project-page-meta {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.meta-item {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.meta-label {
    font-size: 0.72rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--cyan-deep);
    font-family: var(--font-mono);
}

.meta-value {
    font-size: 1rem;
    color: var(--text);
}

.project-page-summary p {
    font-size: 1.1rem;
    line-height: 1.75;
    color: var(--text);
    max-width: 62ch;
}

.project-page-section h2 {
    font-size: 1.9rem;
    margin-bottom: 1rem;
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
}

.project-page-section h2::before {
    content: '';
    display: inline-block;
    width: 22px;
    height: 1.5px;
    background: var(--cyan);
    transform: translateY(-0.4em);
}

.project-page-section p {
    font-size: 1.02rem;
    line-height: 1.8;
    color: var(--muted);
    margin-bottom: 1rem;
    max-width: 68ch;
}

.project-page-section p:last-child { margin-bottom: 0; }

/* media breaks out of the reading column to span the full width of the page.
   centered with margin-left (not transform) so it survives the .reveal scroll
   animation, which also sets transform and would otherwise override it once visible */
.project-page-image-single,
.project-page-image-row,
.project-page-gallery,
.project-page-video {
    position: relative;
    left: 50%;
    width: 100vw;
    margin-left: -50vw;
}

.project-page-section > .project-page-video,
.project-page-section > .project-page-image-single,
.project-page-section > .project-page-image-row {
    margin-top: 0rem;
    margin-bottom: 0rem;
}

/* each image/video block sticks fully into view as you scroll past it —
   same snap mechanic as the social reel, minus the gallery (its staggered
   masonry columns aren't a single clean "slide" to snap to) */
.project-page-image-single,
.project-page-image-row,
.project-page-video {
    scroll-snap-align: start;
    scroll-snap-stop: always;
}

.project-page-image-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0;
}

.project-page-image-row.cols-3 {
    grid-template-columns: repeat(3, 1fr);
}

.project-page-image-single figure,
.project-page-image-row figure {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.project-page-image-single img,
.project-page-image-row img {
    width: 100%;
    display: block;
    object-fit: cover;
}

.project-page-links {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 1.5rem;
}

.project-page-gallery {
    columns: 4;
    column-gap: 0;
}

.project-page-gallery img {
    width: 100%;
    margin-bottom: 0;
    break-inside: avoid;
    transition: transform 0.3s var(--spring), box-shadow 0.3s var(--spring);
}

.project-page-gallery img:hover {
    transform: translateY(-4px);
    box-shadow: 0 20px 45px -16px rgba(0, 0, 0, 0.25);
}

/* video embeds */
.project-page-video {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.project-page-video video {
    width: 100%;
    display: block;
    background: #1A1A1A;
}

.project-page-nav {
    display: flex;
    justify-content: space-between;
    padding-top: 1.75rem;
    border-top: 1px solid var(--line);
}

/* ---------- Vertical video reel — full-height scroll-snap sections ---------- */
.reel {
    position: relative;
    left: 50%;
    width: 100vw;
    margin-left: -50vw;
}

.reel-item {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: clamp(2rem, 6vw, 6rem);
    padding: 6rem 6%;
    scroll-snap-align: start;
    scroll-snap-stop: always;
}

.reel-stage {
    position: relative;
    flex: 0 0 auto;
    height: min(82vh, 780px);
    aspect-ratio: 9 / 16;
    border-radius: var(--radius);
    overflow: hidden;
    background: #111;
}

.reel-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.reel-toggle {
    position: absolute;
    left: 50%;
    bottom: 1.25rem;
    transform: translateX(-50%);
    width: 46px;
    height: 46px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.16);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.35);
    color: #fff;
    font-size: 1.05rem;
    cursor: pointer;
    transition: background 0.2s var(--ease), transform 0.2s var(--spring);
}

.reel-toggle:hover {
    background: rgba(255, 255, 255, 0.28);
    transform: translateX(-50%) scale(1.06);
}

.reel-toggle .ph-pause { display: none; }
.reel-toggle[data-state="playing"] .ph-play { display: none; }
.reel-toggle[data-state="playing"] .ph-pause { display: inline; }

.reel-copy {
    flex: 0 1 360px;
    opacity: 0;
    transform: translateX(-28px);
    transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
}

.reel-item.is-active .reel-copy {
    opacity: 1;
    transform: translateX(0);
}

.reel-copy p {
    font-size: 1.05rem;
    line-height: 1.7;
    color: var(--text);
    margin-bottom: 1rem;
}

.reel-link {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-mono);
    font-size: 0.78rem;
    letter-spacing: 0.02em;
    color: var(--cyan-deep);
    border-bottom: 1px solid var(--line-strong);
    padding-bottom: 0.2rem;
    transition: opacity 0.2s var(--ease);
}

.reel-link:hover { opacity: 0.6; }

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 1024px) {
    header { gap: 1.5rem; }
}

@media (max-width: 768px) {
    /* scroll-snap fights mobile viewport-height changes (address bar show/hide)
       and traps scroll before it reaches controls near the bottom of a snapped
       block — drop it entirely on small screens and let the page scroll free */
    html {
        scroll-snap-type: none;
    }

    .nav-shell {
        height: calc(50px + 1.2rem);
    }

    .header-glass,
    header {
        padding: 0.6rem 1.1rem;
    }

    header {
        justify-content: space-between;
        gap: 1rem;
    }

    .logo-mark { height: 50px; }

    /* opaque dropdown card — needs its own dark-on-light contrast, not the
       white feeding header's difference blend above */
    header .nav-links li a,
    header .nav-links li a:hover {
        color: var(--text);
    }

    header .nav-links li a:hover { color: var(--cyan-deep); }

    .nav-links {
        position: absolute;
        top: calc(100% + 10px);
        left: 0;
        width: 100%;
        flex-direction: column;
        align-items: center;
        background-color: rgba(255, 255, 255, 0.85);
        backdrop-filter: blur(22px);
        -webkit-backdrop-filter: blur(22px);
        padding: 1.5rem;
        border: 1px solid rgba(255, 255, 255, 0.7);
        border-radius: var(--radius);
        box-shadow: 0 24px 55px -20px rgba(0, 0, 0, 0.2);
        gap: 1.5rem;
        display: none;
    }

    .nav-links.active { display: flex; }

    .nav-links.active li {
        animation: navIn 0.5s var(--spring) both;
    }

    .nav-links.active li:nth-child(1) { animation-delay: 0.05s; }
    .nav-links.active li:nth-child(2) { animation-delay: 0.11s; }
    .nav-links.active li:nth-child(3) { animation-delay: 0.17s; }
    .nav-links.active li:nth-child(4) { animation-delay: 0.23s; }

    @keyframes navIn {
        from { opacity: 0; transform: translateY(14px); }
        to   { opacity: 1; transform: translateY(0); }
    }

    .menu-toggle { display: flex; position: relative; }

    .menu-toggle::after {
        content: '';
        position: absolute;
        bottom: -1.5rem;
        left: -50px;
        right: -50px;
        height: 1.5rem;
    }

    .visit-btn { display: none; }

    section { padding: 8rem 6% 5rem; }

    .split-layout {
        flex-direction: column;
        gap: 2.25rem;
        padding: 3rem 0 2.5rem;
    }

    /* name/bio/buttons stay fixed at the top; sidebar and its inner wrapper are
       unwrapped so their children can interleave with .project-scroll via order */
    .sidebar, .sidebar-inner { display: contents; }

    .logo,
    .identity,
    .sidebar-bio,
    .sidebar-section,
    .sidebar-links,
    .sidebar-meta {
        padding-left: 6%;
        padding-right: 6%;
    }

    /* extra breathing room for the description specifically — a dense
       paragraph reads as more "crammed" than short lines at the same margin */
    .sidebar-bio {
        padding-left: 9%;
        padding-right: 9%;
        max-width: none;
    }

    /* the auto margin that rests experience+contact against the icon-row
       divider is a desktop-only trick — on mobile everything unwraps into
       one flowing column via display:contents, so it needs to fall back to
       normal spacing here or it eats all the remaining page height */
    #experience {
        margin-top: 0;
    }

    #contact {
        margin-top: 0;
    }

    /* order: identity/bio (default) -> projects -> experience -> contact -> links -> copyright */
    .project-scroll { order: 1; }
    #experience { order: 2; }
    #contact { order: 3; }
    .sidebar-links { order: 4; }
    .sidebar-meta { order: 5; }

    .project-scroll {
        margin-left: 0;
        width: 100%;
    }

    .scroll-card-meta { padding: 1.15rem 6%; }

    .jump-bottom-btn {
        display: flex;
    }

    .hero-split { flex-direction: column; min-height: 0; margin-top: 108px; }
    .hero-split-media { height: 46vh; }
    .hero-split-content { padding: 3.5rem 6%; }

    .project-page-image-row,
    .project-page-image-row.cols-3 { grid-template-columns: 1fr; }
    .project-page-gallery { columns: 3; }

    .reel-item {
        flex-direction: column;
        padding: 6.5rem 6% 3rem;
        gap: 1.75rem;
    }

    .reel-stage { height: min(56vh, 560px); }

    .reel-copy {
        flex: none;
        text-align: center;
        transform: translateY(18px);
    }

    .reel-item.is-active .reel-copy { transform: translateY(0); }
}

@media (max-width: 480px) {
    section { padding: 7.5rem 5% 4rem; }

    .sidebar-section p { max-width: none; }

    .btn { justify-content: space-between; }

    .scroll-card-meta { flex-wrap: wrap; }
    .scroll-card-tag { text-align: left; }

    .project-page-gallery { columns: 2; }

    .project-page-nav {
        flex-direction: column;
        gap: 1rem;
        align-items: center;
    }
}
