:root {
    --bg: #060605;
    --text: #efece4;
    --muted: #8f8a80;
    --accent: #c9a24a;
    --border: rgba(239, 236, 228, 0.16);
    /* Kept equal to SLIDE_TRANSITION_MS in photography.js, which drives the actual
       photo scroll — so the rail dots and the slide transition move at the same pace. */
    --rail-tick-duration: 320ms;
}

* { box-sizing: border-box; }

html, body {
    height: 100%;
    margin: 0;
    overflow: hidden;
    background: var(--bg);
}

body {
    position: relative;
    color: var(--text);
    font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial;
    line-height: 1.5;
}

/* Faint film-grain texture over the whole page — gives the dark gallery a
   filmic, printed quality instead of a flat digital black. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 15;
    pointer-events: none;
    opacity: 0.05;
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.back-link,
.counter {
    position: fixed;
    z-index: 20;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--muted);
    font-size: 0.8rem;
    letter-spacing: 0.04em;
}

.back-link {
    top: 20px;
    left: 20px;
    text-decoration: none;
    transition: color 180ms ease;
}

.back-link:hover,
.back-link:focus-visible {
    color: var(--accent);
    outline: none;
}

.counter {
    top: 20px;
    right: 20px;
    font-variant-numeric: tabular-nums;
    /* Hidden until setActiveSlide (in photography.js) shows it for a photo slide —
       starting visible here would flash it on screen for the moment between first
       paint and that first JS-driven update, since the intro slide loads first. */
    opacity: 0;
    pointer-events: none;
    transition: opacity 300ms ease;
}

.rail {
    position: fixed;
    z-index: 20;
    top: 50%;
    right: 20px;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 10px;
    /* Same reasoning as .counter above. */
    opacity: 0;
    pointer-events: none;
    transition: opacity 300ms ease;
}

.rail-dot {
    width: 26px;
    height: 26px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 999px;
    background: transparent;
    cursor: pointer;
}

.rail-dot::before {
    content: "";
    display: block;
    width: 6px;
    height: 6px;
    border-radius: 999px;
    background: var(--border);
    transition: background 220ms ease, transform 220ms ease;
}

.rail-dot:hover::before {
    background: var(--muted);
}

.rail-dot.is-disabled {
    cursor: default;
    pointer-events: none;
}

.rail-dot.is-disabled::before {
    opacity: 0.4;
}

.rail-dot-current {
    cursor: default;
}

.rail-dot-current::before {
    background: var(--accent);
    transform: scale(1.6);
}

/* While a photo-to-photo move is actually scrolling (is-scrolling-up/down is toggled on
   the rail — see playDotTravel in photography.js — for exactly the scroll's duration),
   all three dots travel together in the direction of motion once, reading as a little
   reel scrolling past rather than static click targets. The animation's duration already
   matches the scroll's, so a single pass (not infinite) is what lets it end and fire
   animationend, which is what clears the class again — see wireInteractions. The current
   dot gets its own variant so it keeps its accent color and scale throughout. */
.rail.is-scrolling-up .rail-dot-up::before,
.rail.is-scrolling-up .rail-dot-down::before {
    animation: rail-dot-travel-down var(--rail-tick-duration) ease-in-out;
}

.rail.is-scrolling-down .rail-dot-up::before,
.rail.is-scrolling-down .rail-dot-down::before {
    animation: rail-dot-travel-up var(--rail-tick-duration) ease-in-out;
}

.rail.is-scrolling-up .rail-dot-current::before {
    animation: rail-dot-current-travel-down var(--rail-tick-duration) ease-in-out;
}

.rail.is-scrolling-down .rail-dot-current::before {
    animation: rail-dot-current-travel-up var(--rail-tick-duration) ease-in-out;
}

/* The continuous variant used for a multi-slide jump (top/grid buttons) — see
   playContinuousDotTravel in photography.js, which clears the class itself once the
   actual scroll animation completes, since an infinite animation never fires
   animationend. These are otherwise identical to the keyframes above, just under their
   own names (rather than reused with "infinite" appended) — sharing a name with the
   single-pass version risks the browser not treating a switch between them as a fresh
   animation, since only the iteration-count would differ, which can silently drop the
   animationend the single-pass version needs to clean itself up. */
.rail.is-scrolling-continuous-up .rail-dot-up::before,
.rail.is-scrolling-continuous-up .rail-dot-down::before {
    animation: rail-dot-travel-loop-down var(--rail-tick-duration) ease-in-out infinite;
}

.rail.is-scrolling-continuous-down .rail-dot-up::before,
.rail.is-scrolling-continuous-down .rail-dot-down::before {
    animation: rail-dot-travel-loop-up var(--rail-tick-duration) ease-in-out infinite;
}

.rail.is-scrolling-continuous-up .rail-dot-current::before {
    animation: rail-dot-current-travel-loop-down var(--rail-tick-duration) ease-in-out infinite;
}

.rail.is-scrolling-continuous-down .rail-dot-current::before {
    animation: rail-dot-current-travel-loop-up var(--rail-tick-duration) ease-in-out infinite;
}

@keyframes rail-dot-travel-up {
    0%,
    100% {
        transform: translateY(0);
        opacity: 1;
    }
    45% {
        transform: translateY(-12px);
        opacity: 0;
    }
    55% {
        transform: translateY(12px);
        opacity: 0;
    }
}

@keyframes rail-dot-travel-down {
    0%,
    100% {
        transform: translateY(0);
        opacity: 1;
    }
    45% {
        transform: translateY(12px);
        opacity: 0;
    }
    55% {
        transform: translateY(-12px);
        opacity: 0;
    }
}

@keyframes rail-dot-current-travel-up {
    0%,
    100% {
        transform: translateY(0) scale(1.6);
        opacity: 1;
    }
    45% {
        transform: translateY(-12px) scale(1.6);
        opacity: 0;
    }
    55% {
        transform: translateY(12px) scale(1.6);
        opacity: 0;
    }
}

@keyframes rail-dot-current-travel-down {
    0%,
    100% {
        transform: translateY(0) scale(1.6);
        opacity: 1;
    }
    45% {
        transform: translateY(12px) scale(1.6);
        opacity: 0;
    }
    55% {
        transform: translateY(-12px) scale(1.6);
        opacity: 0;
    }
}

@keyframes rail-dot-travel-loop-up {
    0%,
    100% {
        transform: translateY(0);
        opacity: 1;
    }
    45% {
        transform: translateY(-12px);
        opacity: 0;
    }
    55% {
        transform: translateY(12px);
        opacity: 0;
    }
}

@keyframes rail-dot-travel-loop-down {
    0%,
    100% {
        transform: translateY(0);
        opacity: 1;
    }
    45% {
        transform: translateY(12px);
        opacity: 0;
    }
    55% {
        transform: translateY(-12px);
        opacity: 0;
    }
}

@keyframes rail-dot-current-travel-loop-up {
    0%,
    100% {
        transform: translateY(0) scale(1.6);
        opacity: 1;
    }
    45% {
        transform: translateY(-12px) scale(1.6);
        opacity: 0;
    }
    55% {
        transform: translateY(12px) scale(1.6);
        opacity: 0;
    }
}

@keyframes rail-dot-current-travel-loop-down {
    0%,
    100% {
        transform: translateY(0) scale(1.6);
        opacity: 1;
    }
    45% {
        transform: translateY(12px) scale(1.6);
        opacity: 0;
    }
    55% {
        transform: translateY(-12px) scale(1.6);
        opacity: 0;
    }
}

.rail-overview {
    margin-top: 8px;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    transition: color 180ms ease;
}

.rail-overview:hover,
.rail-overview:focus-visible {
    color: var(--accent);
    outline: none;
}

.top-link {
    display: inline-flex;
    width: 26px;
    height: 26px;
    margin-bottom: 8px;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    transition: color 180ms ease;
}

.top-link:hover,
.top-link:focus-visible {
    color: var(--accent);
    outline: none;
}

.top-link span {
    display: none;
}

.top-link.is-top {
    position: fixed;
    z-index: 20;
    top: 28px;
    left: 50%;
    transform: translateX(-50%);
    width: auto;
    height: auto;
    margin-bottom: 0;
    flex-direction: column;
    gap: 6px;
    border: none;
    border-radius: 0;
    background: none;
    color: var(--muted);
    font-size: 0.72rem;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    transition: opacity 400ms ease, color 180ms ease;
}

.top-link.is-top:hover,
.top-link.is-top:focus-visible {
    color: var(--text);
}

.top-link.is-top span {
    display: inline;
}

.scroll-hint {
    position: fixed;
    z-index: 20;
    left: 50%;
    bottom: 28px;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    border: none;
    background: none;
    color: var(--muted);
    font-size: 0.72rem;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    cursor: pointer;
    transition: opacity 400ms ease, color 180ms ease;
}

.scroll-hint:hover {
    color: var(--text);
}

.scroll-hint.is-hidden {
    opacity: 0;
    pointer-events: none;
}

.filmstrip {
    height: 100vh;
    height: 100dvh;
    overflow-y: auto;
    scroll-snap-type: y mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.filmstrip::-webkit-scrollbar {
    display: none;
}

.slide {
    position: relative;
    height: 100vh;
    height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    scroll-snap-align: start;
    scroll-snap-stop: always;
}

.intro-slide {
    flex-direction: column;
    text-align: center;
    padding: 0 24px;
}

.intro-slide h1 {
    margin: 0;
    color: var(--accent);
    font-size: clamp(1.5rem, 3.4vw, 2.4rem);
    font-weight: 600;
    letter-spacing: 0.28em;
    text-transform: uppercase;
}

.photo-slide-bg {
    position: absolute;
    inset: -6%;
    background-size: cover;
    background-position: center;
    filter: blur(42px) brightness(0.42) saturate(1.15);
    transform: scale(1.1);
}

.photo-slide-bg::after {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(6, 6, 5, 0.28);
}

.photo-slide img {
    position: relative;
    z-index: 2;
    max-width: 90vw;
    max-height: 82vh;
    width: auto;
    height: auto;
    display: block;
    box-shadow: 0 40px 100px rgba(0, 0, 0, 0.55);
    opacity: 0;
    transform: scale(0.98);
    transition: opacity 700ms ease, transform 700ms ease;
}

.photo-slide.is-current img {
    opacity: 1;
    transform: scale(1);
}

.slide-number {
    position: absolute;
    z-index: 1;
    right: 3vw;
    bottom: -4vw;
    font-family: "Fraunces", Georgia, serif;
    font-weight: 600;
    font-size: clamp(6rem, 20vw, 15rem);
    color: rgba(239, 236, 228, 0.05);
    line-height: 1;
    pointer-events: none;
}

.slide-caption {
    position: absolute;
    z-index: 3;
    left: 24px;
    bottom: 22px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-width: min(72vw, 420px);
    color: var(--text);
    font-size: 0.78rem;
    letter-spacing: 0.06em;
}

.slide-caption span {
    color: var(--muted);
}

.caption-camera {
    font-size: 0.68rem;
    letter-spacing: 0.04em;
    color: var(--muted);
}

.caption-details {
    font-size: 0.68rem;
}

.caption-details summary {
    display: inline-block;
    color: var(--muted);
    letter-spacing: 0.04em;
    cursor: pointer;
    list-style: none;
}

.caption-details summary::-webkit-details-marker {
    display: none;
}

.caption-details summary:hover,
.caption-details[open] summary {
    color: var(--accent);
}

.caption-details .caption-extra {
    margin-top: 4px;
    letter-spacing: 0.04em;
    color: var(--muted);
}

.overview-slide {
    align-items: stretch;
    justify-content: stretch;
}

.overview-scroll {
    width: 100%;
    height: 100%;
    overflow-y: auto;
    padding: 100px 24px 60px;
}

.overview-heading {
    margin: 0 0 28px;
    text-align: center;
    color: var(--accent);
    font-size: clamp(1rem, 2vw, 1.3rem);
    font-weight: 600;
    letter-spacing: 0.28em;
    text-transform: uppercase;
}

.overview-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 3px;
    max-width: 1100px;
    margin: 0 auto;
}

@media (min-width: 640px) {
    .overview-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

@media (min-width: 1000px) {
    .overview-grid {
        grid-template-columns: repeat(4, 1fr);
    }
}

.overview-tile {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 5;
    padding: 0;
    margin: 0;
    border: 0;
    background: #111;
    overflow: hidden;
    cursor: pointer;
}

.overview-tile img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    filter: grayscale(0.1) brightness(0.82);
    transition: transform 400ms ease, filter 400ms ease;
}

.overview-tile:hover img,
.overview-tile:focus-visible img {
    transform: scale(1.045);
    filter: grayscale(0) brightness(1);
}

.overview-tile:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

/* Previewing a grid tile — opens over the overview grid instead of jumping into the
   full filmstrip slide, so browsing the grid and looking closer stay two separate,
   reversible steps rather than one destructive click. */
.lightbox {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(6, 6, 5, 0.92);
    backdrop-filter: blur(6px);
    opacity: 0;
    visibility: hidden;
    transition: opacity 220ms ease;
}

.lightbox.is-open {
    opacity: 1;
    visibility: visible;
}

.lightbox-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    margin: 0;
    padding: 24px;
    max-width: 100vw;
    max-height: 100vh;
}

.lightbox-image {
    display: block;
    max-width: min(92vw, 1400px);
    max-height: 74vh;
    width: auto;
    height: auto;
    object-fit: contain;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}

.lightbox-caption {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    max-width: 72vw;
    color: var(--text);
    font-size: 0.78rem;
    letter-spacing: 0.06em;
    text-align: center;
}

.lightbox-caption span {
    color: var(--muted);
}

.lightbox-caption .caption-camera {
    font-size: 0.68rem;
    letter-spacing: 0.04em;
    color: var(--muted);
}

.lightbox-close,
.lightbox-nav {
    position: fixed;
    z-index: 51;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    transition: color 180ms ease;
}

.lightbox-close:hover,
.lightbox-close:focus-visible,
.lightbox-nav:hover,
.lightbox-nav:focus-visible {
    color: var(--accent);
    outline: none;
}

.lightbox-close {
    top: 20px;
    right: 20px;
}

.lightbox-nav {
    top: 50%;
    transform: translateY(-50%);
}

.lightbox-prev {
    left: 20px;
}

.lightbox-next {
    right: 20px;
}

@media (max-width: 640px) {
    .lightbox-caption {
        max-width: 88vw;
    }

    .lightbox-nav {
        width: 34px;
        height: 34px;
    }

    .lightbox-prev {
        left: 6px;
    }

    .lightbox-next {
        right: 6px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .lightbox {
        transition: none;
    }

    .filmstrip {
        scroll-behavior: auto;
    }

    .photo-slide img {
        transition: none;
    }

    .overview-tile img {
        transition: none;
    }

    .rail.is-scrolling-up .rail-dot-up::before,
    .rail.is-scrolling-up .rail-dot-down::before,
    .rail.is-scrolling-down .rail-dot-up::before,
    .rail.is-scrolling-down .rail-dot-down::before,
    .rail.is-scrolling-up .rail-dot-current::before,
    .rail.is-scrolling-down .rail-dot-current::before,
    .rail.is-scrolling-continuous-up .rail-dot-up::before,
    .rail.is-scrolling-continuous-up .rail-dot-down::before,
    .rail.is-scrolling-continuous-down .rail-dot-up::before,
    .rail.is-scrolling-continuous-down .rail-dot-down::before,
    .rail.is-scrolling-continuous-up .rail-dot-current::before,
    .rail.is-scrolling-continuous-down .rail-dot-current::before {
        animation: none;
    }
}

@media (max-width: 640px) {
    .rail {
        right: 12px;
    }

    .photo-slide img {
        max-width: 94vw;
        max-height: 76vh;
    }

    .slide-caption {
        left: 16px;
        bottom: 16px;
    }
}
