.grid {
    display: grid;

    /* counts (same as before) */
    --grid-cols-xs: 1;
    --grid-cols-sm: 2;
    --grid-cols-md: 3;
    --grid-cols-lg: 4;
    --grid-cols-xl: 4;
    --grid-cols-xxl: 4;

    /* single shared gap default (user can override) */
    --grid-gap: 1rem;
    /* optional per-dimension overrides can be set on the element:
     --grid-row-gap and/or --grid-col-gap */

    /* use the variables as fallbacks when assigning the actual properties */
    row-gap: var(--grid-row-gap, var(--grid-gap));
    column-gap: var(--grid-col-gap, var(--grid-gap));

    grid-auto-rows: auto;
    width: 100%;
    box-sizing: border-box;
}

/* breakpoint column templates (same as earlier) */
.grid {
    grid-template-columns: repeat(var(--grid-cols-xs), 1fr);
}

@media (min-width:576px) {
    .grid {
        grid-template-columns: repeat(var(--grid-cols-sm), 1fr);
    }
}

@media (min-width:768px) {
    .grid {
        grid-template-columns: repeat(var(--grid-cols-md), 1fr);
    }
}

@media (min-width:992px) {
    .grid {
        grid-template-columns: repeat(var(--grid-cols-lg), 1fr);
    }
}

@media (min-width:1200px) {
    .grid {
        grid-template-columns: repeat(var(--grid-cols-xl), 1fr);
    }
}

@media (min-width:1400px) {
    .grid {
        grid-template-columns: repeat(var(--grid-cols-xxl), 1fr);
    }
}

/* ---- Masonry (absolute-position) ----
   Keep your original .grid / breakpoint rules elsewhere. This replaces the masonry-specific CSS.
*/

.grid.masonry {
    /* keep display:grid so computed grid-template-columns reflects breakpoints */
    display: grid;
    position: relative;
    /* containing block for absolutely-positioned children */
    grid-auto-rows: auto;
    /* JS will control vertical placement */
    row-gap: var(--grid-row-gap, var(--grid-gap));
    column-gap: var(--grid-col-gap, var(--grid-gap));
    width: 100%;
    box-sizing: border-box;

    /* Hidden until JS completes first layout, preventing items animating from top-left corner */
    opacity: 0;
    transition: opacity 0.3s ease, height 220ms ease;
}

.grid.masonry.masonry-ready {
    opacity: 1;
}

/* Suppress child position transitions until after first layout */
.grid.masonry:not(.masonry-ready) > * {
    transition: none !important;
}

/* absolutely position children (script will set left/top/width inline) */
.grid.masonry>* {
    position: absolute;
    left: 0;
    top: 0;
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    page-break-inside: avoid;
    box-sizing: border-box;
}

/* masonry-ignore items are still absolutely positioned;
   the script treats them as full-width blocks by default. */
.grid.masonry .masonry-ignore {
    position: absolute;
    left: 0;
    top: 0;
    box-sizing: border-box;
}

/* Spinner shown as a sibling while masonry awaits images and first layout */
.masonry-spinner {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 200px;
    opacity: 1;
    transition: opacity 0.3s ease;
}

.masonry-spinner.masonry-spinner-hiding {
    opacity: 0;
}

.masonry-spinner::after {
    content: '';
    width: 36px;
    height: 36px;
    border: 3px solid rgba(0, 0, 0, 0.12);
    border-top-color: #555;
    border-radius: 50%;
    animation: masonry-spin 0.75s linear infinite;
}

@keyframes masonry-spin {
    to { transform: rotate(360deg); }
}

/* Fill placeholder style (grey boxes) */
.grid.masonry .masonry-fill-placeholder {
    /* visually indicate placeholder */
    background: #e0e0e0;
    /* light grey */
    border-radius: 2px;
    pointer-events: none;
    user-select: none;
    /* ensure box-sizing consistent */
    box-sizing: border-box;
    /* don't accidentally show in accessibility order as real content */
    aria-hidden: true;
}

/* Development debug: outline placeholders (optional)
.grid.masonry .masonry-fill-placeholder {
  outline: 1px dashed rgba(0,0,0,0.08);
}
*/