/* ─────────────────────────────────────────────────────────────
   Project card + the grids it sits in
   Shared by the projects archive and the home page.
   ───────────────────────────────────────────────────────────── */

/* ─── Grids ────────────────────────────────────────────────────
   Equal-height cards on a fixed track. v1 let each card size to
   its own caption, which is why the rows never lined up.         */
.jm-projects-grid {
    display: grid;
    gap: var(--sp-5);
    grid-template-columns: 1fr;
}

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

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

/* The completed-work mosaic on the archive. A tight gap on purpose: at
   the page's usual --sp-5 the tiles read as sixteen separate cards, and
   closed up to a few pixels they read as one index of the work, which is
   what the section is. Two columns even on a phone — sixteen portrait
   tiles in a single file is a very long scroll for an archive. */
.jm-projects-mosaic {
    display: grid;
    gap: clamp(6px, 0.7vw, 10px);
    grid-template-columns: repeat(2, 1fr);
}

@media (min-width: 860px)  { .jm-projects-mosaic { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1100px) { .jm-projects-mosaic { grid-template-columns: repeat(4, 1fr); } }

.jm-projects-mosaic .jm-project-card__media { aspect-ratio: 5 / 6; }

/* ─── Card ─────────────────────────────────────────────────────── */
.jm-project-card {
    position: relative;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--primary-dark);
}

.jm-project-card__link {
    display: block;
    position: relative;
    height: 100%;
    color: #fff;
    text-decoration: none;
}

.jm-project-card__media {
    position: relative;
    aspect-ratio: 4 / 3;
    overflow: hidden;
}

.jm-project-card__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    /* The colour → greyscale reveal, done in CSS so the source photo stays
       untouched and a new project needs no image editing. */
    filter: grayscale(100%) contrast(1.02);
    transform: scale(1.01);
    transition: filter 0.6s var(--ease), transform 0.9s var(--ease);
}

/* Current developments read in full colour — they are what's being sold. */
.jm-project-card--colour .jm-project-card__img {
    filter: grayscale(0%);
}

/* Inside a .jm-panel the card is a thumbnail on a pale ground, not a block
   on the page — same corners, hairline and lift as the gallery tiles, so a
   panel of projects and a panel of photographs read as the same object. */
.jm-project-card--tile {
    border-radius: 12px;
    border: 1px solid rgba(104, 152, 168, 0.22);
    box-shadow: 0 12px 28px -22px rgba(22, 40, 48, 0.55);
}

/* No button inside a tile. The whole card is already the link, and four
   outlined buttons across a row of thumbnails is four times the furniture
   for no extra affordance. */
.jm-project-card--tile .jm-project-card__cta { display: none; }

/* ─── The wash (completed work) ────────────────────────────────
   v1's best idea on the whole site: the archive sits back in a cool,
   slightly dark monochrome and the photograph returns to full colour
   under the pointer. Sixteen buildings shot over thirty years in
   different light and different seasons read as one body of work
   greyed, and as a jumble in colour.

   v1 achieved it by exporting a second, pre-greyscaled JPEG per
   project and cross-fading the two files. Here it is a filter over
   the one original, so a new project needs no image editing.

   The cast is two layers, not one: the filter drains and darkens,
   and a flat teal veil over it supplies the cool. Doing the cool in
   the filter as well (sepia + hue-rotate) tints the highlights the
   wrong way and turns white render skies faintly green.            */
/* The slate the floor plans and the footer are drawn on, so a tile that
   has not loaded its photograph yet is still the right colour for a
   washed grid rather than a patch of brand teal. */
.jm-project-card--wash { background: #1B2A31; }

.jm-project-card--wash .jm-project-card__img {
    filter: grayscale(1) brightness(0.78) contrast(1.06);
    transform: none;
    /* The operator asked for 200ms. It is the right number: fast enough
       to feel attached to the pointer, slow enough to read as a fade
       rather than a swap. */
    transition: filter 0.2s var(--ease), transform 0.7s var(--ease);
}

.jm-project-card--wash .jm-project-card__media::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(34, 60, 70, 0.34);
    transition: opacity 0.2s var(--ease);
}

/* The whole tile is the link, so the mosaic needs no button in it. */
.jm-project-card--wash .jm-project-card__cta { display: none; }

.jm-project-card--wash .jm-project-card__media::after {
    background: linear-gradient(
        to bottom,
        rgba(20, 32, 38, 0) 0%,
        rgba(20, 32, 38, 0.10) 44%,
        rgba(20, 32, 38, 0.74) 100%
    );
}

.jm-project-card--wash .jm-project-card__body {
    padding: var(--sp-4) var(--sp-4) clamp(14px, 1.4vw, 20px);
}

.jm-project-card--wash .jm-project-card__title {
    font-size: clamp(0.75rem, 0.69rem + 0.26vw, 0.9375rem);
    font-weight: 600;
}

/* Revealed by the pointer, by the keyboard, or while the tile is pressed. */
.jm-project-card--wash .jm-project-card__link:hover .jm-project-card__img,
.jm-project-card--wash .jm-project-card__link:focus-visible .jm-project-card__img,
.jm-project-card--wash .jm-project-card__link:active .jm-project-card__img {
    filter: none;
}

.jm-project-card--wash .jm-project-card__link:hover .jm-project-card__media::before,
.jm-project-card--wash .jm-project-card__link:focus-visible .jm-project-card__media::before,
.jm-project-card--wash .jm-project-card__link:active .jm-project-card__media::before {
    opacity: 0;
}

/* And, where there is no pointer to do it, by scrolling the tile into the
   middle of the screen — the block's script sets the class.

   The gate belongs HERE rather than in the script: Chrome reports
   `pointer: none` until it has actually seen a pointing device, so a
   desktop can run the script's own media-query check and fail it, and the
   whole grid then sits in colour. A CSS media query is re-evaluated when
   the capability changes; a check made once at load is not.               */
@media (hover: none) {
    .jm-project-card--wash.is-revealed .jm-project-card__img { filter: none; }
    .jm-project-card--wash.is-revealed .jm-project-card__media::before { opacity: 0; }
}

/* A lighter scrim: in a panel these are thumbnails meant to show the
   building, and the caption only needs the bottom third protected. */
.jm-project-card--tile .jm-project-card__media::after {
    background: linear-gradient(
        to bottom,
        rgba(28, 42, 48, 0) 0%,
        rgba(28, 42, 48, 0.12) 42%,
        rgba(28, 42, 48, 0.72) 100%
    );
}

/* Scrim so the caption stays legible over any photograph. */
.jm-project-card__media::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
        to bottom,
        rgba(28, 42, 48, 0.15) 0%,
        rgba(28, 42, 48, 0.45) 55%,
        rgba(28, 42, 48, 0.78) 100%
    );
    transition: opacity 0.6s var(--ease);
}

/* ─── Caption ──────────────────────────────────────────────────── */
.jm-project-card__body {
    position: absolute;
    inset: auto 0 0 0;
    padding: var(--sp-5);
    text-align: center;
    z-index: 1;
}

/* Only rendered where current and completed work share one list, so the
   visitor can tell at a glance which of these can still be bought. */
.jm-project-card__status {
    display: block;
    margin-bottom: var(--sp-2);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.22em;
    text-indent: 0.22em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.82);
    text-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
}

.jm-project-card__title {
    color: #fff;
    font-size: clamp(0.9375rem, 0.85rem + 0.4vw, 1.125rem);
    font-weight: 600;
    letter-spacing: var(--ls-title);
    text-transform: uppercase;
    text-indent: var(--ls-title);
    margin: 0;
    text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
}

.jm-project-card__sub {
    color: rgba(255, 255, 255, 0.85);
    font-size: var(--fs-small);
    margin: var(--sp-2) 0 0;
    text-shadow: 0 1px 10px rgba(0, 0, 0, 0.4);
}

.jm-project-card__cta {
    display: inline-block;
    margin-top: var(--sp-4);
    padding: 9px 22px;
    border: 1px solid rgba(255, 255, 255, 0.75);
    border-radius: var(--radius);
    font-size: var(--fs-eyebrow);
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #fff;
    transition: background 0.4s var(--ease), color 0.4s var(--ease),
                border-color 0.4s var(--ease);
}

/* ─── Hover / focus ────────────────────────────────────────────── */
@media (hover: hover) and (pointer: fine) {
    .jm-project-card__link:hover .jm-project-card__img,
    .jm-project-card__link:focus-visible .jm-project-card__img {
        filter: grayscale(0%);
        transform: scale(1.045);
    }

    .jm-project-card__link:hover .jm-project-card__media::after,
    .jm-project-card__link:focus-visible .jm-project-card__media::after {
        opacity: 0.85;
    }

    .jm-project-card__link:hover .jm-project-card__cta,
    .jm-project-card__link:focus-visible .jm-project-card__cta {
        background: #fff;
        border-color: #fff;
        color: var(--primary);
    }
}

/* On touch there is no hover, so the photographs simply stay in colour
   rather than leaving the grid permanently grey. */
@media (hover: none) {
    .jm-project-card__img { filter: grayscale(0%); }
}

.jm-project-card__link:focus-visible {
    outline: 3px solid var(--primary);
    outline-offset: 3px;
}
