/* ==========================================================================
   Kromdraai Blomme — botanical gallery engine, quote panels, preloader
   and the botanical cursor.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Gallery page header

   The design reference splits the band in two: an ivory panel carrying the
   label, the heading, a short rule and the lead, and a photograph that runs
   off the right-hand edge of the screen, with a drawn botanical sprig
   straddling the seam between them.
   -------------------------------------------------------------------------- */
.kb-gallery-hero {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    background: var(--kb-ivory);
    /* The height of the photograph on the right. The sprig is drawn to the
       same height, so the two line up across the seam. */
    --kb-hero-media-h: clamp(280px, 31vw, 470px);
    box-sizing: border-box;
}

.kb-gallery-hero__inner {
    display: grid;
    grid-template-columns: minmax(0, 44%) minmax(0, 56%);
    align-items: start;
}

/* A page with no banner photograph keeps the ivory panel on its own. */
.kb-gallery-hero__inner--solo {
    grid-template-columns: minmax(0, 1fr);
}

.kb-gallery-hero__inner--solo .kb-gallery-hero__panel {
    max-width: 760px;
}

.kb-gallery-hero__panel {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: clamp(2.2rem, 4.5vw, 4rem) clamp(1.5rem, 3.5vw, 3.5rem) clamp(2.2rem, 4.5vw, 4rem)
        var(--kb-gutter);
}

.kb-gallery-hero__panel .kb-eyebrow {
    color: var(--kb-olive);
    margin-bottom: 1.35rem;
}

.kb-gallery-hero__title {
    font-family: var(--kb-font-display);
    font-size: clamp(2.6rem, 5.4vw, 4.9rem);
    font-weight: 600;
    line-height: 0.94;
    color: var(--kb-forest);
    margin: 0;
    max-width: 13ch;
    text-wrap: balance;
}

.kb-gallery-hero__rule {
    display: block;
    width: 62px;
    height: 1px;
    background: var(--kb-olive);
    margin: 1.5rem 0 1.4rem;
}

.kb-gallery-hero__lead {
    font-family: var(--kb-font-display);
    font-size: clamp(1rem, 1.3vw, 1.16rem);
    font-weight: 600;
    line-height: 1.75;
    color: var(--kb-ink);
    max-width: 46ch;
}

.kb-gallery-hero__media {
    position: relative;
    overflow: hidden;
    /* The photograph is drawn inside the column rather than sizing it, so
       the band is exactly as tall as the copy on the left and the photograph
       stretches to match, with no empty space under the text. */
    align-self: stretch;
    height: auto;
    min-height: 0;
    background: var(--kb-parchment);
}

.kb-gallery-hero__inner {
    min-height: clamp(340px, 34vw, 460px);
}

.kb-gallery-hero__media-inner {
    position: absolute;
    /* A little beyond the frame, so the scroll parallax never shows an edge. */
    inset: -6% 0;
}

.kb-gallery-hero__media img {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 42%;
}

/* Gallery pages — quiet fade-in; scroll parallax runs on the inner wrapper only. */
.kb-gallery-hero--gallery .kb-gallery-hero__media--motion {
    opacity: 0;
}

.kb-gallery-hero--gallery.is-entered .kb-gallery-hero__media--motion {
    opacity: 1;
    transition: opacity 1s var(--kb-ease);
}

.kb-gallery-hero--gallery .kb-gallery-hero__media--motion img {
    transform: scale(1.03);
    transition: transform 1.2s var(--kb-ease);
}

.kb-gallery-hero--gallery.is-entered .kb-gallery-hero__media--motion img {
    transform: scale(1);
}

.kb-gallery-hero--gallery .kb-gallery-hero__panel--motion > * {
    opacity: 0;
    transform: translateY(14px);
}

.kb-gallery-hero--gallery.is-entered .kb-gallery-hero__panel--motion > * {
    opacity: 1;
    transform: none;
    transition:
        opacity 0.7s var(--kb-ease),
        transform 0.7s var(--kb-ease);
}

.kb-gallery-hero--gallery.is-entered .kb-gallery-hero__panel--motion > :nth-child(1) {
    transition-delay: 0.08s;
}

.kb-gallery-hero--gallery.is-entered .kb-gallery-hero__panel--motion > :nth-child(2) {
    transition-delay: 0.16s;
}

.kb-gallery-hero--gallery.is-entered .kb-gallery-hero__panel--motion > :nth-child(3) {
    transition-delay: 0.24s;
}

.kb-gallery-hero--gallery.is-entered .kb-gallery-hero__panel--motion > :nth-child(4) {
    transition-delay: 0.32s;
}

/* The sprig is drawn rather than photographed so it stays crisp, and it is
   placed across the seam so it links the ivory panel to the photograph. */
.kb-gallery-hero__sprig {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 44%;
    color: var(--kb-sage);
    opacity: 0.32;
    transform: translateX(-50%) rotate(-8deg);
    pointer-events: none;
    z-index: 2;
}

.kb-gallery-hero__sprig-drawing {
    display: block;
    height: 100%;
    width: auto;
}

/* --------------------------------------------------------------------------
   2. Filter tabs
   -------------------------------------------------------------------------- */
.kb-gallery-shell {
    width: 100%;
    max-width: 1640px;
    margin-inline: auto;
    padding-inline: clamp(1rem, 2.4vw, 2.25rem);
    box-sizing: border-box;
}

.kb-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: clamp(1.1rem, 2.6vw, 2.4rem);
    padding: clamp(1.2rem, 2.2vw, 2rem) 0;
    border-bottom: 1px solid var(--kb-line);
    margin-bottom: clamp(1.5rem, 2.8vw, 2.4rem);
}

.kb-filter {
    border: 0;
    background: none;
    padding: 0.35rem 0;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--kb-ink-soft);
    cursor: pointer;
    position: relative;
    transition: color 0.35s var(--kb-ease);
}

.kb-filter[hidden] {
    display: none;
}

.kb-filter::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: -2px;
    width: 100%;
    height: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: right center;
    transition: transform 0.45s var(--kb-ease);
}

.kb-filter:hover {
    color: var(--kb-forest);
}

.kb-filter:hover::after {
    transform: scaleX(1);
    transform-origin: left center;
}

.kb-filter.is-active {
    color: var(--kb-forest);
}

.kb-filter.is-active::after {
    transform: scaleX(1);
}

.kb-filter__count {
    font-size: 0.62rem;
    opacity: 0.55;
    margin-left: 0.35rem;
    letter-spacing: 0.1em;
}

/* --------------------------------------------------------------------------
   3. Masonry
   -------------------------------------------------------------------------- */
.kb-masonry {
    display: grid;
    grid-template-columns: repeat(var(--kb-cols-desktop, 4), minmax(0, 1fr));
    grid-auto-rows: 10px;
    grid-auto-flow: row dense;
    row-gap: var(--kb-gallery-gap, 18px);
    column-gap: var(--kb-gallery-gap, 18px);
    padding-bottom: clamp(3rem, 6vw, 5rem);
}

.kb-masonry__item {
    position: relative;
    overflow: hidden;
    margin: 0;
    background: var(--kb-parchment);
    grid-row-end: span var(--kb-span, 20);
    opacity: 0;
    transform: translateY(26px);
    transition: opacity 0.8s var(--kb-ease), transform 0.8s var(--kb-ease);
    /* Tiles far off screen are not painted until they get close. */
    content-visibility: auto;
    contain-intrinsic-size: auto 320px;
}

.kb-masonry__item.is-revealed {
    opacity: 1;
    transform: none;
}

.kb-masonry__item.is-hidden {
    display: none;
}

.kb-masonry__media {
    display: block;
    width: 100%;
    height: 100%;
    overflow: hidden;
}

.kb-masonry__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: var(--kb-focal-x, 50%) var(--kb-focal-y, 50%);
    transition: transform 1.2s var(--kb-ease);
}

.kb-masonry__item:hover .kb-masonry__media img {
    transform: scale(1.05);
}

.kb-masonry__overlay {
    position: absolute;
    inset: auto 0 0 0;
    padding: 2.4rem 1.4rem 1.3rem;
    background: linear-gradient(to top, rgba(20, 32, 24, 0.82), rgba(20, 32, 24, 0));
    color: var(--kb-ivory);
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 0.5s var(--kb-ease), transform 0.5s var(--kb-ease);
    pointer-events: none;
}

.kb-masonry__item:hover .kb-masonry__overlay {
    opacity: 1;
    transform: none;
}

.kb-masonry__caption {
    font-family: var(--kb-font-display);
    font-size: 1.1rem;
    line-height: 1.3;
}

.kb-masonry__tag {
    font-size: 0.62rem;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    opacity: 0.72;
    display: block;
    margin-bottom: 0.4rem;
}

/* Editorial cards inside the masonry */
.kb-masonry__item--quote {
    grid-column: span 1;
    /* A photograph fills the rows it spans; a quote panel is stretched to
       the row it shares with its neighbours so it reads as part of the grid
       instead of a shorter card sitting in it. */
    align-self: stretch;
    background: transparent;
    box-sizing: border-box;
    overflow: hidden;
    padding: 0;
}

.kb-masonry__item--quote .kb-quote {
    width: 100%;
    min-height: 0;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    align-items: stretch;
    gap: 0.45rem;
    padding: 1.15rem 1.05rem;
    margin: 0;
    box-sizing: border-box;
}

.kb-masonry__item--quote .kb-quote__label,
.kb-masonry__item--quote .kb-quote__mark,
.kb-masonry__item--quote .kb-quote__text,
.kb-masonry__item--quote .kb-quote__attribution {
    margin: 0;
}

/* The panel now fills its row, so the signature rests at the foot of it
   instead of clinging to the quote. */
.kb-masonry__item--quote .kb-quote__attribution {
    margin: auto 0 0;
}

.kb-masonry__item--quote .kb-quote__mark {
    line-height: 1;
    display: block;
    overflow: hidden;
}

.kb-quote__label {
    display: block;
    font-size: 0.62rem;
    letter-spacing: 0.26em;
    text-transform: uppercase;
    opacity: 0.62;
    margin-bottom: 0.9rem;
}

.kb-masonry__item--card {
    background: var(--kb-parchment);
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 2.2rem;
}

.kb-masonry__item--card .kb-card__label {
    font-size: 0.66rem;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    color: var(--kb-sage);
    display: block;
    margin-bottom: 1rem;
}

.kb-masonry__item--card .kb-card__word {
    font-family: var(--kb-font-display);
    font-size: clamp(1.9rem, 3.4vw, 2.9rem);
    line-height: 1.12;
    color: var(--kb-forest);
    font-style: italic;
}

/* --------------------------------------------------------------------------
   4. Quote panels
   -------------------------------------------------------------------------- */
.kb-quote {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: clamp(1.9rem, 3.2vw, 2.9rem);
    overflow: hidden;
    isolation: isolate;
    box-sizing: border-box;
}

.kb-quote--forest {
    background: var(--kb-forest-soft);
    color: rgba(247, 245, 239, 0.9);
}

.kb-quote--forest .kb-quote__text {
    color: var(--kb-ivory);
}

.kb-quote--ivory {
    background: var(--kb-ivory-warm);
    color: var(--kb-ink);
    border: 1px solid var(--kb-line);
}

.kb-quote--ivory .kb-quote__text {
    color: var(--kb-forest);
}

.kb-quote--parchment {
    background: var(--kb-parchment);
    color: var(--kb-ink);
}

.kb-quote--parchment .kb-quote__text {
    color: var(--kb-forest);
}

.kb-quote--outline {
    background: transparent;
    border: 1px solid var(--kb-line-strong);
    color: var(--kb-ink);
}

.kb-quote--outline .kb-quote__text {
    color: var(--kb-forest);
}

.kb-quote__mark {
    font-family: var(--kb-font-display);
    font-size: calc(4.2rem * var(--kb-quote-fit, 1));
    line-height: 0.6;
    color: var(--kb-sage);
    opacity: 0.55;
    margin-bottom: 1.1rem;
}

.kb-quote--forest .kb-quote__mark {
    color: var(--kb-sage-soft);
}

.kb-quote__text {
    font-family: var(--kb-font-display);
    font-style: italic;
    font-size: calc(clamp(1.35rem, 2.2vw, 1.95rem) * var(--kb-quote-fit, 1));
    line-height: 1.32;
    margin: 0 0 1.2rem;
}

.kb-quote__attribution {
    font-size: 0.66rem;
    letter-spacing: 0.26em;
    text-transform: uppercase;
    opacity: 0.68;
}

.kb-quote__leaf {
    position: absolute;
    right: -40px;
    bottom: -40px;
    width: 190px;
    height: 190px;
    opacity: 0.14;
    z-index: -1;
    pointer-events: none;
}

/* --------------------------------------------------------------------------
   5. Lightbox (Fancybox theme)
   -------------------------------------------------------------------------- */
.fancybox-bg {
    background: rgba(17, 27, 20, 0.97);
}

.fancybox-container .fancybox-stage {
    cursor: none;
}

.fancybox-container .fancybox-title {
    font-family: var(--kb-font-body);
    font-size: 0.74rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: rgba(247, 245, 239, 0.72);
    margin-top: 0.9rem;
}

.fancybox-container .fancybox-title {
    font-family: var(--kb-font-display);
    font-size: 1.25rem;
    font-style: italic;
    letter-spacing: 0.01em;
    text-transform: none;
    color: var(--kb-ivory);
}

.fancybox-container .fancybox-nav {
    width: 62px;
    height: 62px;
}

.fancybox-container .fancybox-nav span {
    color: var(--kb-ivory);
    opacity: 0.8;
}

.fancybox-container .fancybox-close {
    color: var(--kb-ivory);
}

/* --------------------------------------------------------------------------
   6. Preloader
   -------------------------------------------------------------------------- */
#preloader {
    position: fixed;
    inset: 0;
    z-index: 9999;
    background: var(--kb-forest);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 2.2rem;
    opacity: 1;
    transition: opacity 0.7s var(--kb-ease-soft);
}

#preloader.is-leaving {
    opacity: 0;
    pointer-events: none;
}

#preloader .kb-preloader__inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2rem;
}

.kb-preloader__mark {
    display: block;
    width: clamp(120px, 18vw, 190px);
    height: auto;
    overflow: visible;
}

/* The petals draw themselves in with a compositor-driven animation, so the
   preloader still completes in a background tab where rAF is throttled.
   The angle of each petal arrives as --angle and is applied here: a CSS
   transform replaces an SVG transform attribute, so keeping the rotation
   in CSS is what stops every petal collapsing onto the same angle. */
.kb-preloader__petal {
    fill: none;
    stroke: var(--kb-sage-soft);
    stroke-width: 1.1;
    stroke-linecap: round;
    opacity: 0;
    transform-box: view-box;
    transform-origin: 100px 100px;
    transform: rotate(var(--angle, 0deg)) scale(1);
    animation: kb-petal-in 0.6s var(--kb-ease) forwards;
    animation-delay: calc(var(--i, 0) * 18ms);
}

.kb-preloader__petals--inner .kb-preloader__petal {
    stroke: var(--kb-taupe);
    stroke-width: 0.9;
}

@keyframes kb-petal-in {
    from {
        opacity: 0;
        transform: rotate(var(--angle, 0deg)) scale(0.72);
    }
    to {
        opacity: 1;
        transform: rotate(var(--angle, 0deg)) scale(1);
    }
}

/* Both rings turn about the centre of the mark, not the centre of their own
   bounding box, which for the shorter inner ring is not the same point. */
.kb-preloader__petals {
    transform-box: view-box;
    transform-origin: 100px 100px;
}

.kb-preloader__petals--outer {
    animation: kb-petal-spin 30s linear infinite;
}

.kb-preloader__petals--inner {
    animation: kb-petal-spin-reverse 22s linear infinite;
}

@keyframes kb-petal-spin {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

@keyframes kb-petal-spin-reverse {
    from {
        transform: rotate(360deg);
    }
    to {
        transform: rotate(0deg);
    }
}

.kb-preloader__core {
    fill: var(--kb-olive);
    opacity: 0;
    transform-box: view-box;
    transform-origin: 100px 100px;
    animation: kb-core-in 0.9s var(--kb-ease) 0.35s forwards;
}

@keyframes kb-core-in {
    from {
        opacity: 0;
        transform: scale(0.4);
    }
    to {
        opacity: 1;
        transform: scale(1);
    }
}

.kb-preloader__word {
    font-family: var(--kb-font-display);
    font-size: 1.1rem;
    letter-spacing: 0.42em;
    text-transform: uppercase;
    color: rgba(247, 245, 239, 0.82);
    text-indent: 0.42em;
}

.kb-preloader__bar {
    width: clamp(150px, 24vw, 260px);
    height: 1px;
    background: rgba(247, 245, 239, 0.2);
    position: relative;
    overflow: hidden;
}

.kb-preloader__bar span {
    position: absolute;
    inset: 0 auto 0 0;
    width: 0;
    background: var(--kb-ivory);
    transition: width 0.3s linear;
}

.kb-preloader__percent {
    font-size: 0.68rem;
    letter-spacing: 0.24em;
    color: rgba(247, 245, 239, 0.55);
    font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   7. Botanical cursor

   The cursor is the preloader mark at the size of a pointer: a single ring
   of slender bracts turning on its own, and a second, shorter ring that
   opens over a hotspot and turns the other way.
   -------------------------------------------------------------------------- */
.kb-cursor {
    position: fixed;
    top: 0;
    left: 0;
    width: 34px;
    height: 34px;
    pointer-events: none;
    /* Above every site overlay: Fancybox's container sits at z-index 99992
       (its parts run up to 99999 inside it), the tint overlays at z-index 1,
       the WhatsApp button at 1005. The admin edit toggle stays above this
       at 2147483647. */
    z-index: 100050;
    /* No blend mode or filter: either forces a repaint of the page behind the
       mark on every frame of its spin, which made scrolling the photo pages
       stutter. The colour is picked from the background under the pointer
       instead (see .on-light and initCursor). */
    color: #ffffff;
    will-change: transform;
    opacity: 0;
    transform: translate3d(-50px, -50px, 0);
    transition: opacity 0.3s var(--kb-ease);
}

.kb-cursor__slot {
    transition: transform 0.45s var(--kb-ease);
}

.kb-cursor__slot,
.kb-cursor__mark {
    display: block;
    width: 100%;
    height: 100%;
    overflow: visible;
}

/* The bracts. The angle of each one arrives as --angle, the same way the
   preloader's petals do, so the rotation can be composed in CSS instead of
   being written into the markup. */
.kb-cursor__petal {
    fill: none;
    stroke: currentColor;
    stroke-width: 5;
    stroke-linecap: round;
    opacity: 0.92;
    transform-box: view-box;
    transform-origin: 100px 100px;
    transform: rotate(var(--angle, 0deg));
}

/* The rings turn about the centre of the mark, not the centre of their own
   bounding box. */
.kb-cursor__ring,
.kb-cursor__spin {
    transform-box: view-box;
    transform-origin: 100px 100px;
}

/* The turn is applied to the whole mark with the `rotate` property, which the
   browser animates on the GPU. Spinning the SVG groups inside it was redrawn
   on the main thread every frame and made the cursor and the scrolling lag. */
.kb-cursor__slot {
    animation: kb-cursor-turn 18s linear infinite;
    animation-play-state: paused;
    will-change: rotate;
}

@keyframes kb-cursor-turn {
    to {
        rotate: 360deg;
    }
}

/* The second ring is closed until the pointer finds a hotspot. It is drawn
   finer than the outer ring, the way the preloader draws its inner one. */
.kb-cursor__ring--inner {
    opacity: 0;
    transform: scale(0.55);
    transition: opacity 0.45s var(--kb-ease), transform 0.6s var(--kb-ease);
}

.kb-cursor__ring--inner .kb-cursor__petal {
    stroke-width: 3.4;
    opacity: 0.78;
}

.kb-cursor__core {
    fill: currentColor;
    transform-box: view-box;
    transform-origin: 100px 100px;
}

@keyframes kb-cursor-spin {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

@keyframes kb-cursor-spin-reverse {
    from {
        transform: rotate(360deg);
    }
    to {
        transform: rotate(0deg);
    }
}

.kb-cursor.is-visible {
    opacity: 1;
}

.kb-cursor.on-light {
    color: var(--kb-forest);
}

/* The marks only turn while the cursor is on screen. */
.kb-cursor.is-visible .kb-cursor__slot {
    animation-play-state: running;
}

/* Over a hotspot the mark opens: the second ring arrives and the whole
   flower is a little larger. */
.kb-cursor.is-hovering .kb-cursor__slot {
    transform: scale(1.7);
}

.kb-cursor.is-hovering .kb-cursor__ring--inner {
    opacity: 0.95;
    transform: scale(1);
}

.kb-cursor.is-hovering .kb-cursor__ring--outer .kb-cursor__petal {
    stroke-width: 4;
    opacity: 1;
}

/* Over a fillable field the petals fold in to a narrow, text-cursor-like mark. */
.kb-cursor__mark {
    transition: transform 0.35s var(--kb-ease);
}

.kb-cursor.is-field .kb-cursor__mark {
    transform: scaleX(0.3);
}

.kb-cursor.is-field .kb-cursor__ring--inner {
    opacity: 0;
    transform: scale(0.55);
}

/* Fallback when the cursor is hidden (touch devices). */
body.kb-touch-device .kb-cursor {
    display: none;
}

body.kb-touch-device,
body.kb-touch-device * {
    cursor: auto !important;
}

@media (prefers-reduced-motion: reduce) {

    .kb-cursor__slot {
        animation: none;
    }
}

/* --------------------------------------------------------------------------
   8. Reveal animation
   -------------------------------------------------------------------------- */
.kb-reveal {
    opacity: 0;
    transform: translateY(34px);
    transition: opacity 0.9s var(--kb-ease), transform 0.9s var(--kb-ease);
    transition-delay: var(--kb-reveal-delay, 0s);
}

.kb-reveal.is-revealed {
    opacity: 1;
    transform: none;
}

.kb-reveal--left {
    transform: translateX(-40px);
}

.kb-reveal--right {
    transform: translateX(40px);
}

.kb-reveal--scale {
    transform: scale(0.96);
}

.kb-reveal--fade {
    transform: none;
}

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

    .kb-gallery-hero--gallery .kb-gallery-hero__media--motion,
    .kb-gallery-hero--gallery .kb-gallery-hero__media-inner,
    .kb-gallery-hero--gallery .kb-gallery-hero__panel--motion > * {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }

    .kb-preloader__petal {
        opacity: 1;
        animation: none;
    }

    .kb-preloader__petals,
    .kb-preloader__core {
        animation: none;
        opacity: 1;
    }

    #preloader {
        transition-duration: 0.2s;
    }

    html {
        scroll-behavior: auto;
    }
}

/* --------------------------------------------------------------------------
   9. Responsive masonry and hero

   The column counts come from the gallery record, so the admin panel's
   "Columns on tablet" and "Columns on mobile" settings actually shape the
   grid. The counts are read here rather than in the template's inline
   style, because an inline custom property would beat these rules.
   -------------------------------------------------------------------------- */
@media (max-width: 1100px) {
    .kb-masonry {
        grid-template-columns: repeat(var(--kb-cols-tablet, 3), minmax(0, 1fr));
    }
}

@media (max-width: 780px) {
    .kb-masonry {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* One column wide — same footprint as a photograph in the two-column grid. */
    .kb-masonry__item--quote {
        grid-column: span 1;
    }

    .kb-masonry__item--quote .kb-quote__label {
        font-size: 0.62rem;
        letter-spacing: 0.24em;
    }

    .kb-masonry__item--quote .kb-quote__mark {
        font-size: calc(clamp(2rem, 5.5vw, 2.85rem) * var(--kb-quote-fit, 1));
        opacity: 0.5;
    }

    .kb-masonry__item--quote .kb-quote__text {
        font-size: calc(clamp(1.05rem, 3.1vw, 1.32rem) * var(--kb-quote-fit, 1));
        line-height: 1.42;
    }

    .kb-masonry__item--quote .kb-quote__attribution {
        font-size: 0.64rem;
        letter-spacing: 0.22em;
    }

    .kb-masonry__item--quote .kb-quote__leaf {
        width: 120px;
        height: 120px;
        right: -28px;
        bottom: -28px;
        opacity: 0.11;
    }

    .kb-filters {
        justify-content: flex-start;
        gap: 1rem 1.4rem;
    }

    /* The band stacks: photograph first, then the copy (DOM keeps text first for desktop). */
    .kb-gallery-hero {
        --kb-hero-stack-media-h: clamp(220px, 62vw, 340px);
    }

    .kb-gallery-hero__inner {
        grid-template-columns: minmax(0, 1fr);
    }

    .kb-gallery-hero__media {
        order: -1;
        height: var(--kb-hero-stack-media-h);
        z-index: 1;
    }

    .kb-gallery-hero__panel {
        order: 0;
        position: relative;
        z-index: 3;
        width: 100%;
        max-width: none;
        box-sizing: border-box;
        text-align: center;
        align-items: center;
        padding: clamp(2rem, 6vw, 2.6rem) var(--kb-gutter);
    }

    .kb-gallery-hero__panel .kb-eyebrow {
        width: 100%;
    }

    .kb-gallery-hero__title {
        max-width: none;
        width: 100%;
        margin-inline: auto;
        text-wrap: balance;
    }

    .kb-gallery-hero__rule {
        margin-inline: auto;
    }

    .kb-gallery-hero__lead {
        max-width: none;
        width: 100%;
        margin-inline: auto;
        text-wrap: pretty;
    }

    /* Straddle the photo foot: mostly on the image, not over the lead copy. */
    .kb-gallery-hero__sprig {
        top: calc(var(--kb-hero-stack-media-h) - clamp(6.25rem, 20vw, 9rem));
        bottom: auto;
        left: auto;
        right: clamp(0.15rem, 2.5vw, 0.85rem);
        height: clamp(86px, 23vw, 132px);
        transform: rotate(-26deg);
        transform-origin: 72% 88%;
        z-index: 2;
    }
}

@media (max-width: 520px) {
    .kb-masonry {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .kb-masonry__item--quote {
        grid-column: span 1;
    }
}

/* --------------------------------------------------------------------------
   10. Contact / enquiry page polish
   -------------------------------------------------------------------------- */
.kb-page-header {
    padding-block: clamp(7rem, 13vw, 11rem) clamp(2.5rem, 5vw, 4rem);
    background: var(--kb-parchment);
}

.kb-page-header__inner {
    max-width: var(--kb-container);
    margin-inline: auto;
    padding-inline: var(--kb-gutter);
}

/* The gallery route renders inside the generic .content wrapper, which is
   already a container — do not double the gutter. */
.content .kb-container {
    max-width: none;
    padding-inline: 0;
}

.content {
    max-width: var(--kb-container);
    margin-inline: auto;
    padding-inline: var(--kb-gutter);
}

.content_h2_header {
    font-family: var(--kb-font-display);
    font-size: var(--kb-fs-h2);
    color: var(--kb-forest);
    margin: 0 0 0.6rem;
}

.content_h2_sub_header {
    color: var(--kb-ink-soft);
    font-size: var(--kb-fs-lead);
    margin: 0 0 2rem;
}

/* --------------------------------------------------------------------------
   Gallery filters on small screens: every filter is visible at once, as a
   neat grid of pill buttons (nothing hides off-screen to be found by
   swiping).
   -------------------------------------------------------------------------- */
@media (max-width: 780px) {
    .kb-filters {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
        gap: 0.55rem;
        padding: 0.4rem 0 1.2rem;
        border-bottom: 0;
        margin-bottom: 0.6rem;
    }

    .kb-filter {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 0.35rem;
        min-height: 44px;
        padding: 0.6rem 0.8rem;
        border: 1px solid var(--kb-line-strong);
        border-radius: 999px;
        background: var(--kb-surface-raised);
        text-align: center;
        letter-spacing: 0.12em;
        transition: color 0.3s var(--kb-ease), background-color 0.3s var(--kb-ease),
            border-color 0.3s var(--kb-ease);
    }

    .kb-filter::after {
        display: none;
    }

    .kb-filter__count {
        margin-left: 0;
    }

    .kb-filter.is-active {
        background: var(--kb-forest);
        border-color: var(--kb-forest);
        color: var(--kb-ivory);
    }

    .kb-filter.is-active .kb-filter__count {
        color: rgba(247, 245, 239, 0.75);
    }
}
