/* ===== FONT ===== */
@font-face {
    font-family: 'Acid Grotesk';
    src: url('../fonts/FFF-AcidGrotesk-Soft-Bold-TRIAL.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    /* block (not swap) so no fallback font flashes — the font is preloaded, so the
       brief invisible period before it paints is negligible */
    font-display: block;
}

/* ===== GLOBAL TYPE SCALE =====
   One knob scales ALL type together, preserving hierarchy + responsive behaviour.
   1 = original design size. Lower = finer/lighter feel (same Bold cut, just smaller). */
:root {
    --type-scale: 0.82;
    /* ONE shared page gap. The project-detail grid uses it for BOTH the right and the
       bottom inset (see .detail-grid padding), and the image carousel fills its column
       exactly to that right edge — so the right image gap and the bottom image gap are
       the same value by construction, not by approximation. */
    --page-gap: 10px;
    --page-margin: var(--page-gap);   /* alias kept for existing references */
}

/* ===== RESET ===== */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
/* The hidden attribute must always win over component display rules (credits/locations). */
[hidden] { display: none !important; }
html { font-size: 16px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }

body {
    font-family: 'Acid Grotesk', sans-serif;
    background: #fff;
    color: #6E6E6E;
    line-height: 0.96;
    letter-spacing: -0.03em;
    overflow: hidden;
    height: 100vh;
    height: 100dvh;   /* iOS: match the visible viewport (URL bar), not the taller large-vh */
}

a { text-decoration: none; color: inherit; letter-spacing: -0.03em; }
button { border: none; background: none; cursor: none; font-family: inherit; letter-spacing: -0.03em; }
img { display: block; }

/* Hide native cursor globally */
*, *::before, *::after { cursor: none !important; }

/* Green dot cursor */
.dot-cursor {
    position: fixed;
    width: 12px;
    height: 12px;
    background: #04B372;
    border-radius: 50%;
    pointer-events: none;
    z-index: 9999;
    transform: translate(-50%, -50%);
    transition: opacity 0.15s ease;
}


/* ===== SPLASH — small crisp NCW over the whole page blurred behind it =====
   The blur is a real backdrop-filter over the live site (same technique as the About
   overlay), so "everything" behind the wordmark is softened. Driven entirely by CSS (no
   JS/GSAP dependency): it holds, then the blur lifts and it goes non-interactive on its own. */
.splash {
    position: fixed;
    inset: 0;
    z-index: 12000;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    background: rgba(255, 255, 255, 0.4);
    -webkit-backdrop-filter: blur(120px);
    backdrop-filter: blur(120px);
    animation: splash-out 3.2s ease forwards;
}
/* Wordmark drawn as a mask so it takes the brand grey (the SVG itself is a pale fill). */
.splash-logo {
    position: relative;
    width: 144px;
    aspect-ratio: 1508 / 480;
    background: #6E6E6E;
    -webkit-mask: url(../images/wordmark-light.svg) center / contain no-repeat;
    mask: url(../images/wordmark-light.svg) center / contain no-repeat;
    opacity: 0;
    /* Fade in, hold, then fade the wordmark FULLY OUT (by ~2.2s) BEFORE the blur even begins
       lifting (~2.24s) — so the NCW can never linger over the homepage during the reveal. */
    animation: splash-in 1.1s ease forwards, splash-logo-out 0.6s ease 1.6s forwards;
}
@keyframes splash-in       { from { opacity: 0; } to { opacity: 1; } }
@keyframes splash-logo-out { 0% { opacity: 1; } 100% { opacity: 0; } }
@keyframes splash-out      { 0%, 70% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } }
@media (prefers-reduced-motion: reduce) {
    .splash      { animation: splash-out 1.4s ease forwards; }
    .splash-logo { animation: splash-in 0.5s ease forwards; }
}


/* ===== PAGE STACK — one unit moved together ===== */
.page-stack {
    width: 100%;
    will-change: transform;
}


/* ===== NCW LOGO PANEL ===== */
.ncw-logo-panel {
    padding: 12px var(--page-gap) 0;   /* top nudged up so the wordmark sits on the margin */
}

.ncw-logo-panel img {
    width: 100%;
    height: auto;
    display: block;
}


/* ===== HOME CONTENT — filters + project row ===== */
.home-content {
    height: 100vh;
    height: 100dvh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding-top: 24px;
}


/* ===== SITE NAV — fixed at top margin, persists above the project overlay ===== */
.site-nav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 700;
    display: flex;
    justify-content: center;
    gap: var(--page-gap);   /* INFORMATION↔PROJECTS gap = the shared outer page margin */
    padding: 12px var(--page-gap) 4px;
}

.nav {
    display: flex;
    justify-content: center;
    gap: var(--page-gap);
    padding: 8px var(--page-gap) 4px;
}

.detail-nav { position: static; }

.nav-link {
    font-size: calc(0.88rem * var(--type-scale));
    color: #C3BDBD;
    transition: color 0.3s ease;
    letter-spacing: -0.01em;
}

.nav-link:hover,
.nav-link.active { color: #6E6E6E; }


/* ===== CATEGORY FILTERS ===== */
.category-filters,
.detail-filters {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 6px;
    padding: 4px var(--page-gap) 10px;
    flex-shrink: 0;
}

.filter {
    font-size: calc(clamp(1.7rem, 3.2vw, 2.7rem) * var(--type-scale));
    color: #C3BDBD;
    cursor: pointer;
    transition: color 0.3s ease;
    letter-spacing: -0.03em;
}

.filter:hover { color: #6E6E6E; }
.filter.active { color: #6E6E6E; }


/* ===== PROJECT ROW — single horizontal row ===== */
.project-row {
    flex: 1;
    min-height: 0;
    display: flex;
    gap: var(--page-gap);
    overflow-x: auto;
    overflow-y: hidden;
    cursor: none;
    scrollbar-width: none;
    -ms-overflow-style: none;
    padding: 0 var(--page-gap) 7px;
    align-items: stretch;
    /* iOS: native horizontal panning with real momentum. pan-x tells Safari this row owns
       horizontal gestures (smooth flick) while vertical swipes pass through to the JS that
       drives the section transitions. */
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    touch-action: pan-x;
}

.project-row::-webkit-scrollbar { display: none; }
.project-row:active { cursor: none; }

.project-card {
    flex: 0 0 calc((100vw - calc(2 * var(--page-gap)) - calc(2 * var(--page-gap))) / 3);
    display: flex;
    flex-direction: column;
    cursor: none;
    height: 100%;
}

.project-card.hidden { display: none; }

.project-image {
    flex: 1;
    min-height: 0;
    overflow: hidden;
    background: #EEECEC; /* placeholder shown while the image loads */
}

.project-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Blur-up: soft until loaded, then sharpens in (no scale/movement) */
    filter: blur(14px);
    transition: filter 0.7s ease;
}
.project-image img.loaded { filter: blur(0); }

.project-meta {
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 9px 0 0;
    flex-shrink: 0;
    white-space: nowrap;
    letter-spacing: -0.01em;
}

.project-title-small { color: #6E6E6E; text-transform: uppercase; font-size: calc(15px * var(--type-scale)); }
.project-cats { color: #C3BDBD; font-size: calc(15px * var(--type-scale)); }
.project-date { color: #C3BDBD; font-size: calc(15px * var(--type-scale)); margin-left: auto; }


/* ===== CURSOR LABEL ===== */
.cursor-label {
    position: fixed;
    z-index: 10000;
    pointer-events: none;
    font-size: calc(15px * var(--type-scale));
    color: #fff;
    mix-blend-mode: difference;
    opacity: 0;
    transition: opacity 0.2s ease;
    letter-spacing: -0.01em;
    transform: translate(-50%, -50%);
}

/* Hide the green dot + "View Project" / Prev / Next label ONLY once a real touch happens
   (JS adds .is-touch on the first touchstart). Using an actual touch — not a hover/pointer
   media query — keeps the custom cursor working on touchscreen laptops that use a mouse or
   trackpad (those falsely report hover:none / pointer:coarse). */
body.is-touch .dot-cursor,
body.is-touch .cursor-label { display: none !important; }


/* ===== PROJECT DETAIL OVERLAY ===== */
.project-detail {
    position: fixed;
    inset: 0;
    z-index: 500;
    background: #fff;
    opacity: 0;
    pointer-events: none;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.project-detail.open { pointer-events: auto; }

/* Detail nav — hidden but keeps its space; the persistent site-nav shows here */
.detail-nav {
    display: flex;
    justify-content: center;
    gap: var(--page-gap);
    padding: 12px var(--page-gap) 4px;
    flex-shrink: 0;
    visibility: hidden;
}

/* Detail filters — padding/flex live on the inner wrapper so the outer can fully
   collapse to 0 height on the project page (padding won't compress otherwise). */
.detail-filters {
    display: block;
    padding: 0;
    flex-shrink: 0;
}
.detail-filters-inner {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 6px;
    padding: 4px var(--page-gap) 10px;
}

/* Project page (hover devices): the filter bar collapses when hidden — pulling the
   images up with it — and expands on hover, pushing them down. It keeps its original
   padding/gap; max-height is set to the exact height by JS so the motion is clean. */
@media (hover: hover) {
    .project-detail .detail-filters {
        max-height: 0;
        overflow: hidden;
        opacity: 0;
        pointer-events: none;
        transition: max-height 0.45s cubic-bezier(0.76, 0, 0.24, 1), opacity 0.3s ease;
    }
    .project-detail.filters-open .detail-filters {
        opacity: 1;
        pointer-events: auto;
    }
}

/* Close button — fixed top-right corner */
.detail-close-btn {
    position: absolute;
    top: 12px;
    right: var(--page-gap);
    z-index: 600;
    padding: 0;
    line-height: 1;
}
.detail-close-btn img {
    width: 14px;
    height: 14px;
}

/* Back to Projects — sits at the top of the left column, in line with the image top.
   Same size as the description; light grey (secondary), like the category tag. */
.detail-back {
    display: flex;
    align-items: center;
    gap: 4px;   /* arrow + text as one compact link (≈ a normal space) */
    flex-shrink: 0;
    color: #C3BDBD;
    font-size: calc(clamp(1.1rem, 1.6vw, 1.45rem) * var(--type-scale));
    letter-spacing: -0.01em;
    line-height: 1;
    position: relative;
    top: -3px;   /* nudge up 3px (desktop; stacked overrides position/top below) */
    transition: color 0.3s ease;
}
.detail-back:hover { color: #6E6E6E; }
.detail-back-icon { width: 0.9em; height: 0.9em; display: block; }

/* Right images: col 5-12, full height. No own bottom padding — the grid owns the
   bottom margin, so overflow:hidden clips the images exactly at the page margin
   (this is what keeps them inside the margin when the filter bar pushes them down). */
.detail-right {
    grid-column: 5 / 13;
    grid-row: 1 / -1;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
    /* Horizontal swipes are handled by JS (carousel); vertical stays native so the stacked
       mobile page can still scroll under the image. */
    touch-action: pan-y;
}

/* Content grid: text (col 1-4) + images (col 5-12). Owns the outer margin on the
   left, right and bottom so every side is consistent (top is under the nav/filters). */
.detail-grid {
    flex: 1;
    min-height: 0;
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    grid-template-rows: 1fr;
    column-gap: var(--page-gap);
    /* No RIGHT inset — the image bleeds off the right edge of the page. Top stays under the
       nav, the left text column and the bottom keep the site's 10px margin. (top right bottom left) */
    padding: 0 0 var(--page-margin) var(--page-margin);
}

/* Left column: title + description centred (middle-left). The specs row is NOT part of
   this flow — it is absolutely positioned to the bottom inset independently (see below),
   so the left column's own alignment stays exactly as designed. */
.detail-left {
    grid-column: 1 / 5;
    grid-row: 1;
    display: flex;
    flex-direction: column;
    /* No extra right padding — the grid's column-gap already gives the standard --page-gap
       between the text (incl. "Credits +") and the image, matching the spacing used site-wide. */
    min-height: 0;
}

/* Title + description centred vertically within the column. */
.detail-textblock {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.detail-meta {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    letter-spacing: -0.01em;
    margin-bottom: 0;
}
/* Title matches the body-copy size below it */
.detail-project-name { color: #6E6E6E; font-size: calc(clamp(1.1rem, 1.6vw, 1.45rem) * var(--type-scale)); line-height: 1; }
.detail-project-cats { color: #C3BDBD; font-size: calc(15px * var(--type-scale)); line-height: 1; margin-top: 0.15em; }

.detail-description {
    font-size: calc(clamp(1.1rem, 1.6vw, 1.45rem) * var(--type-scale));
    color: #C3BDBD;
    line-height: 1.0;   /* tighter leading */
}

/* Metadata row — a SEPARATE element pinned directly to the bottom-left inset, so it does
   not affect (and is not affected by) the left column's centred title/description flow.
   Anchored to .project-detail (already position:fixed, full viewport) — no positioning
   added to the shared .detail-left parent. Width matches the left column (4 cols + gaps,
   minus its padding-right) so it wraps exactly as it did in flow. */
.detail-specs {
    display: flex;
    flex-wrap: wrap;
    column-gap: 20px;   /* space between Material / Location / Year on one row */
    row-gap: 4px;       /* tight when they wrap — line spacing like the description */
    position: absolute;
    left: var(--page-gap);
    bottom: calc(var(--page-gap) - 4px);   /* nudged a few px lower than the page inset (optical) */
    width: calc((100vw - 2 * var(--page-gap) - var(--page-gap) * 11) / 12 * 4 + var(--page-gap) * 2);
}
.spec { display: flex; gap: 6px; font-size: calc(15px * var(--type-scale)); }
.spec-label { color: #6E6E6E; }
.spec-value { color: #C3BDBD; }


/* Carousel — horizontal image row.
   --carousel-gap is the internal gap between slides. It is intentionally SEPARATE from
   --page-gap (the outer page inset) and must match the `+ 10` in getSlideOffset(). */
.detail-image-row {
    --carousel-gap: 10px;
    display: flex;
    gap: var(--carousel-gap);
    height: 100%;
    will-change: transform;
}

.detail-image-row .slide {
    flex-shrink: 0;
    height: 100%;
    /* Width now derives from the slide's aspect ratio (full height × ratio). Portraits get
       their own ratio set on load (see main.js reveal()); until then this 3:4 default keeps
       them portrait, never a cropped landscape frame. Landscapes override to fill the width. */
    width: auto;
    aspect-ratio: 3 / 4;
    overflow: hidden;
    background: #EEECEC; /* placeholder shown while the image loads */
    /* Eases the portrait→landscape width change when an image is classified on load */
    transition: width 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Portrait slides keep their own aspect ratio (set on load) so the full photo shows at
   the carousel's height — no cover-crop. The 3:4 default on .slide above covers the brief
   pre-load window. --carousel-gap (10px) is the internal gap between slides and MUST stay
   in sync with .detail-image-row `gap` and the `+ 10` in getSlideOffset() (main.js).

   Landscape images instead fill the container width (they read best edge-to-edge, and a
   landscape sized to full height would overflow the frame). */
.detail-image-row .slide.landscape {
    width: 100%;
    aspect-ratio: auto;
}

/* CTA end card — a portrait frame like the images, so it sits naturally in the strip. */
.detail-image-row .slide.text-slide {
    aspect-ratio: 3 / 4;
}


.detail-image-row .slide img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Blur-up: soft until loaded, then sharpens in (no scale/movement) */
    filter: blur(14px);
    transition: filter 0.7s ease;
}
.detail-image-row .slide img.loaded { filter: blur(0); }

/* End-of-carousel CTA card — "get in touch" as the final slide */
.detail-image-row .slide.text-slide {
    background: transparent;
    display: flex;
    align-items: flex-start;   /* top-aligned; padding-top is set to match the title line */
}
.text-slide-inner {
    display: flex;
    flex-direction: column;
    padding-left: var(--page-gap);
    padding-right: var(--page-gap);
    width: 100%;
}
.cta-line {
    color: #6E6E6E;
    font-size: calc(clamp(1.1rem, 1.6vw, 1.45rem) * var(--type-scale));
    line-height: 1.08;
}
.cta-link {
    color: #C3BDBD;
    font-size: calc(clamp(1.1rem, 1.6vw, 1.45rem) * var(--type-scale));
    line-height: 1.08;
    letter-spacing: -0.01em;
    transition: color 0.3s ease;
}
.cta-link:hover { color: #6E6E6E; }


/* ===== CREDITS — toggle on the title line, columns over the blurred image ===== */
/* "Credits +/−" sits at the right edge of the left column, on the title's baseline. */
.detail-credits-toggle {
    margin-left: auto;
    align-self: flex-start;
    color: #C3BDBD;
    font-size: calc(15px * var(--type-scale));
    line-height: 1;
    letter-spacing: -0.01em;
    padding: 0;
    white-space: nowrap;
    transition: color 0.3s ease;
}
.detail-credits-toggle:hover { color: #6E6E6E; }

/* The image column anchors the credits overlay. */
.detail-right { position: relative; }

/* Credits overlay — blurs the image (same technique as the About panel) and lays the
   credit columns over it, top-aligned to the title via JS (alignCredits). */
.detail-credits {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 100%;   /* JS narrows this to just the first photo (right of the button) */
    z-index: 4;
    display: flex;
    align-items: flex-start;
    padding: 0 var(--page-gap);
    overflow: hidden;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    /* #B9B9B9 at 30% over the blurred image, so the light credit text reads */
    background: rgba(185, 185, 185, 0.30);
    -webkit-backdrop-filter: blur(40px);
    backdrop-filter: blur(40px);
    transition: opacity 0.55s cubic-bezier(0.76, 0, 0.24, 1), visibility 0s linear 0.55s;
}
.project-detail.credits-open .detail-credits {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 0.55s cubic-bezier(0.76, 0, 0.24, 1);
}
.detail-credits-cols {
    display: flex;
    gap: clamp(20px, 2.4vw, 44px);
    width: 100%;
}
.credit-col { display: flex; flex-direction: column; }
.credit-line {
    /* Match the "Puffy Coffee" title / description sizing and tight leading on the left */
    font-size: calc(clamp(1.1rem, 1.6vw, 1.45rem) * var(--type-scale));
    line-height: 1.0;
    letter-spacing: -0.01em;
    white-space: nowrap;
}
.credit-label { color: #CECECE; }   /* the role (darker of the two) */
.credit-value { color: #EFEFEF; }   /* the name (lighter) */

/* Inline credits (non-desktop) — hidden on desktop; the image overlay is used there instead. */
.detail-credits-inline { display: none; }


/* ===== OTHER LOCATIONS — bottom-left, above the specs ===== */
.detail-locations {
    position: absolute;
    left: var(--page-gap);
    bottom: 34px;   /* sits just above the Material/Location/Year specs row */
    display: flex;
    flex-direction: column;
    gap: 0;
    line-height: 1.04;   /* tight leading, matching the designs */
    letter-spacing: -0.01em;
}
.detail-locations-list {
    display: flex;
    flex-direction: column;   /* one store per line */
}
.detail-locations-head {
    color: #6E6E6E;
    font-size: calc(clamp(1rem, 1.4vw, 1.25rem) * var(--type-scale));
    margin-bottom: 2px;
}
.detail-location-link {
    color: #C3BDBD;
    font-size: calc(clamp(1rem, 1.4vw, 1.25rem) * var(--type-scale));
    transition: color 0.3s ease;
}
.detail-location-link:hover,
.detail-location-link.is-current { color: #6E6E6E; }
.detail-location-link .loc-brand { margin-right: 0.5em; }


/* ===== INFORMATION OVERLAY ===== */
.info-overlay {
    position: fixed;
    inset: 0;
    z-index: 800;
    display: flex;
    pointer-events: none;
}
.info-overlay.open { pointer-events: auto; }

.info-panel {
    position: relative;
    width: calc((100vw - 60px) / 3 + var(--page-gap));
    min-width: 340px;
    background: #fff;
    padding: var(--page-gap) var(--page-gap) 0 var(--page-gap);
    z-index: 810;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    transform: translateX(-100%);
    /* Slow, elegant ease-in-out quart — same motion language as the carousel swipe */
    transition: transform 0.9s cubic-bezier(0.76, 0, 0.24, 1);
}
.info-overlay.open .info-panel {
    transform: translateX(0);
}

.info-panel .close-btn {
    position: absolute;
    top: var(--page-gap);
    right: var(--page-gap);
    z-index: 5;
    padding: 0;
    line-height: 1;
}
.info-panel .close-btn img {
    width: 14px;
    height: 14px;
}

.info-text {
    font-size: calc(clamp(1.15rem, 1.8vw, 1.55rem) * var(--type-scale));
    color: #C3BDBD;
    line-height: 1.08;
    max-width: none;
    padding-right: 40px;
}
.info-text strong {
    color: #6E6E6E;
}

.info-portrait {
    position: absolute;
    left: var(--page-gap);
    bottom: var(--page-gap);
    width: calc(50% - 22.5px);
    max-width: none;
    overflow: hidden;
}
.info-portrait img { width: 100%; height: auto; display: block; }

.info-contact {
    position: absolute;
    /* Sit a --page-gap (10px) to the right of the portrait and on the same 10px bottom
       inset as the portrait — matching the margins used across the rest of the site. */
    left: calc(50% - 2.5px);
    bottom: var(--page-gap);
    display: flex;
    flex-direction: column;
    gap: 1px;
    font-size: calc(1rem * var(--type-scale));
    line-height: 0.95;
    color: #C3BDBD;
}
.info-contact a { color: #C3BDBD; transition: color 0.3s ease; letter-spacing: -0.01em; white-space: nowrap; }
.info-contact a:hover { color: #6E6E6E; }

.info-blur-bg {
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
    backdrop-filter: blur(50px);
    -webkit-backdrop-filter: blur(50px);
    background: rgba(255, 255, 255, 0.55);
    opacity: 0;
    transition: opacity 0.9s cubic-bezier(0.76, 0, 0.24, 1);
    z-index: 800;
}
.info-overlay.open .info-blur-bg {
    opacity: 1;
}

/* Tablets: 2 project cards per view (not 3 thin ones) */
@media (min-width: 769px) and (max-width: 1024px) { .project-card { flex: 0 0 calc((100vw - calc(2 * var(--page-gap)) - var(--page-gap)) / 2); } }
@media (max-width: 768px) { .filter { font-size: calc(1.55rem * var(--type-scale)); } .info-panel { width: 75%; min-width: unset; } .project-card { flex: 0 0 calc((100vw - calc(2 * var(--page-gap)) - var(--page-gap)) / 2); } }
@media (max-width: 480px) { .filter { font-size: calc(1.3rem * var(--type-scale)); } .info-panel { width: 90%; } .project-card { flex: 0 0 calc(100vw - calc(3 * var(--page-gap))); } }

/* ===== PROJECT DETAIL — stacked layout (mobile + tablet, ≤1024) ===== */
/* Images lead, then the project info below — same reading hierarchy as desktop
   (title → description → specs), just stacked vertically. */
@media (max-width: 1024px) {
    .detail-grid {
        display: flex;
        flex-direction: column;
        gap: var(--page-gap);   /* image → text gap matches the 10px used site-wide */
        overflow-y: auto;
        overflow-x: hidden;   /* clip the horizontal store page-swipe */
        /* No RIGHT inset — the image/carousel bleeds off the right edge like desktop. Top clears
           the nav; left + bottom keep the 10px margin. (top right bottom left) */
        padding: 33px 0 var(--page-margin) var(--page-margin);
    }
    .detail-left,
    .detail-right {
        grid-column: auto;
        grid-row: auto;
        min-height: 0;
    }

    /* 1 — image carousel leads */
    .detail-right {
        order: 1;
        height: 60vh;
        height: 60dvh;
        padding-bottom: 0;
    }
    /* Portrait slides keep their aspect ratio (full 60vh height, uncropped); landscapes fill
       most of the width as before. */
    .detail-image-row .slide.landscape { width: 92vw; }

    /* 2 — title, description, specs below.
       The left column grows to fill the space under the image so the specs can be
       pinned to the very bottom (margin-top:auto) — same lower baseline / var(--page-gap) page
       margin as the layout, instead of floating halfway up the white footer. */
    .detail-left {
        order: 2;
        padding: 0 var(--page-gap) 0 0;   /* text keeps its 10px right margin (image bleeds, text doesn't) */
        flex: 1 1 auto;
        min-height: 0;
        display: flex;
        flex-direction: column;
    }
    /* position:relative so the credits can overlay this block for the cross-fade */
    .detail-textblock { flex: none; display: block; position: relative; }
    .detail-description { margin-top: 0; }   /* no gap below the title */
    /* Stacked: metadata pinned to the bottom margin (margin-top:auto), with tight leading
       between its wrapped lines to match Other Locations. */
    .detail-specs { position: static; width: auto; margin-top: 0; padding-top: 16px; row-gap: 1px; }
    .detail-specs .spec { line-height: 1.04; }

    /* Back sits top-left ON the nav line (same row as INFORMATION / PROJECTS); shortened to
       just "↖ Back" via .back-suffix below. */
    .detail-back {
        position: absolute;
        top: 12px;
        left: var(--page-gap);
        font-size: calc(0.88rem * var(--type-scale));
    }
    .back-suffix { display: none; }

    /* Hover-reveal filter menu can't be reached on touch — hide it here */
    .detail-filters { display: none; }

    /* CTA end card centres its own content (no desktop title-alignment offset) */
    .detail-image-row .slide.text-slide { align-items: center; }

    /* Credits (non-desktop): no image overlay. Tapping "Credits +" cross-fades the text block
       (title + description) OUT and the credits IN, in the very same place. The toggle stays. */
    .detail-credits { display: none !important; }
    .detail-project-name, .detail-project-cats, .detail-description { transition: opacity 0.45s ease; }
    .project-detail.credits-open .detail-project-name,
    .project-detail.credits-open .detail-project-cats,
    .project-detail.credits-open .detail-description { opacity: 0; }
    .detail-credits-inline {
        position: absolute;
        top: 0; left: 0; right: 0;
        display: flex;
        flex-direction: column;
        gap: 0;   /* no extra gap between the two credit groups → even leading throughout */
        opacity: 0;
        visibility: hidden;
        pointer-events: none;
        transition: opacity 0.45s ease, visibility 0s linear 0.45s;
    }
    .project-detail.credits-open .detail-credits-inline {
        opacity: 1;
        visibility: visible;
        pointer-events: auto;
        transition: opacity 0.45s ease;
    }
    .detail-credits-inline .credit-line { white-space: normal; line-height: 1.04; }   /* match the other type */
    .detail-credits-inline .credit-label { color: #C3BDBD; }   /* role */
    .detail-credits-inline .credit-value { color: #6E6E6E; }   /* name */
    /* Keep the toggle above the credits overlay so "Credits −" stays tappable to close. */
    .detail-credits-toggle { position: relative; z-index: 2; }

    /* Other Locations drops down to group with the specs footer (margin-top:auto), so the
       flexible space sits ABOVE it — room for longer descriptions. Fades out while credits are up. */
    .detail-locations { position: static; margin-top: auto; transition: opacity 0.3s ease; }
    .project-detail.credits-open .detail-locations { opacity: 0; pointer-events: none; }
}

/* Respect reduced-motion: strip the hover zoom and its easing */
@media (prefers-reduced-motion: reduce) {
    .detail-image-row .slide { transition: none; }
    .project-image img,
    .detail-image-row .slide img { filter: none; transform: none; transition: none; }
}


/* ===== CUSTOM ENQUIRY SECTION =====
   One viewport tall. Main content group is vertically CENTRED; the footer is anchored
   separately to the bottom margin (absolute) — not a single space-between column that
   would push the content low. Same outer margins as the site (--page-gap). */
.custom-section {
    /* ONE font size for the whole Custom block — heading, copy, labels, placeholders and
       the Enquire button all use --custom-fs so they can't drift out of sync. Hierarchy
       comes from colour (dark #6E6E6E vs light #C3BDBD), not size. */
    --custom-fs: calc(clamp(1.25rem, 1.55vw, 1.5rem) * var(--type-scale));
    height: 100vh;
    height: 100dvh;
    box-sizing: border-box;
    background: #fff;
    position: relative;              /* footer anchors here */
    display: flex;
    flex-direction: column;
    justify-content: center;         /* main group sits around the vertical centre */
    padding: 0 var(--page-gap);
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: none;
    -ms-overflow-style: none;
    -webkit-overflow-scrolling: touch;   /* momentum scroll on iOS when it exceeds a viewport */
    overscroll-behavior: contain;
}
.custom-section::-webkit-scrollbar { display: none; }

/* Three columns — intro copy | form fields | Inquire — on the 12-col grid, all sharing
   the same TOP alignment (align-items:start), positioned with explicit columns (no
   space-between) so their placement is stable. */
.custom-inner {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    column-gap: var(--page-gap);
    align-items: start;
    transform: translateY(4vh);   /* sit a touch below centre */
}

.custom-intro { grid-column: 5 / 9; }   /* left-centre, wide copy block */
.custom-heading {
    color: #6E6E6E;
    font-size: var(--custom-fs);
    line-height: 1.0;
    margin-bottom: 1px;
}
.custom-copy {
    color: #C3BDBD;
    font-size: var(--custom-fs);
    line-height: 1.04;
}

/* Form — labels dark, inputs/placeholders light; text-only, no boxes/underlines/rules. */
.custom-form {
    grid-column: 9 / 11;             /* centre-right */
    display: flex;
    flex-direction: column;
    gap: 11px;
}
.custom-field { display: flex; flex-direction: column; gap: 0; }
.custom-field label {
    color: #6E6E6E;
    font-size: var(--custom-fs);
    line-height: 1.04;
}
.custom-field input {
    border: none;
    background: transparent;
    color: #C3BDBD;
    font-family: inherit;
    font-weight: inherit;
    font-size: var(--custom-fs);
    letter-spacing: -0.01em;
    line-height: 1.04;
    padding: 0;
    width: 100%;
}
/* Typed text stays the SAME light grey as the placeholder (never darkens on focus). */
.custom-field input::placeholder { color: #C3BDBD; opacity: 1; }
.custom-field input:focus { outline: none; }
/* Keep autofilled values light grey too (and suppress the browser's autofill wash). */
.custom-field input:-webkit-autofill,
.custom-field input:-webkit-autofill:focus {
    -webkit-text-fill-color: #C3BDBD;
    caret-color: #C3BDBD;
    transition: background-color 100000s ease-in-out 0s;
}

/* Inquire — compact, understated: thin light-grey outline, small centred label. Kept in
   the far-right grid column, top-aligned with the copy + form. */
.custom-submit {
    grid-column: 11 / 13;
    display: flex;
    justify-content: flex-end;
    align-items: flex-start;
}
.inquire-btn {
    -webkit-appearance: none;
    appearance: none;
    box-sizing: border-box;
    border: 1px solid #C3BDBD;
    border-radius: 0;
    background: transparent;
    color: #C3BDBD;
    font-family: inherit;
    /* Same shared size as the rest of the Custom block (copy / labels / placeholders). */
    font-size: var(--custom-fs);
    letter-spacing: -0.01em;
    line-height: 1;
    /* Box height = one full field (label + input, each line-height 1.04) so it lines up
       with the Name / Enter Name pair. Text centred within it. */
    height: calc(var(--custom-fs) * 1.04 * 2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 calc(2 * var(--page-gap));
    transition: color 0.3s ease, border-color 0.3s ease, background-color 0.3s ease;
}
/* Hover = a filled submit button: box fills with the dark grey, label flips to white. */
.inquire-btn:hover {
    background: #6E6E6E;
    border-color: #6E6E6E;
    color: #fff;
}

/* Footer — four items aligned to the content grid, on one bottom baseline:
   Projects+categories (left) | Information (col 5) | Site by Twofold (col 9) | © (right) */
.custom-footer {
    position: absolute;
    left: var(--page-gap);
    right: var(--page-gap);
    bottom: var(--page-gap);
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    column-gap: var(--page-gap);
    align-items: baseline;   /* every group sits on the SAME text baseline */
    font-size: calc(0.92rem * var(--type-scale));
    letter-spacing: -0.01em;
    line-height: 1;
    white-space: nowrap;
}
/* min-width:0 stops the wide nowrap items (esp. the copyright) from distorting the 1fr
   tracks, so each footer item aligns to the SAME grid column as the content above it. */
.foot-projects, .foot-info, .foot-twofold, .foot-copy { min-width: 0; }
.foot-projects { grid-column: 1 / 5; }
.foot-info     { grid-column: 5 / 8; }
.foot-twofold  { grid-column: 9 / 12; }
.foot-copy     { grid-column: 12 / 13; justify-self: end; }
.foot-strong { color: #6E6E6E; transition: color 0.3s ease; }
a.foot-strong:hover { color: #C3BDBD; }
.foot-light  { color: #C3BDBD; }
/* Footer category links — light grey like the top filters, darken on hover */
.foot-cat { color: #C3BDBD; transition: color 0.3s ease; }
.foot-cat:hover { color: #6E6E6E; }

/* ≤1200: the copy | form | button grid gets too tight — the 2-column form clips its
   "Item or Service required" placeholder, and the footer's long category list overruns the
   rigid grid. So the content stacks vertically (full-width fields → placeholder always
   fits) and the footer moves into the flow as a single flex row (space-between), wrapping
   only when it truly must. One breakpoint keeps content + footer in sync. */
@media (max-width: 1200px) {
    .custom-section {
        height: auto;
        min-height: 100vh;
        min-height: 100dvh;
        justify-content: flex-start;
        padding: 88px var(--page-gap) calc(var(--page-gap) + 4px);
    }
    .custom-inner {
        display: flex;
        flex-direction: column;
        gap: 26px;
        margin-top: 12vh;
        transform: none;
    }
    .custom-intro, .custom-form, .custom-submit { grid-column: auto; width: 100%; }
    .custom-copy { max-width: none; }
    .custom-submit { justify-content: flex-start; }
    .inquire-btn { align-self: flex-start; }
    .custom-footer {
        position: static;
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
        column-gap: 24px;
        row-gap: 4px;
        margin-top: auto;
        padding-top: 56px;
    }
    .foot-projects, .foot-info, .foot-twofold, .foot-copy { grid-column: auto; }
    .foot-copy { justify-self: auto; }
}

/* Small screens: the category list is wider than the viewport — let the footer groups wrap
   freely and drop the copyright to its own line rather than overflow. */
@media (max-width: 600px) {
    .custom-footer { white-space: normal; row-gap: 6px; }
    .foot-copy { width: 100%; }
}

