/**
 * Cards: a row of equal cards (services, features, links). Three per row by
 * default, two on tablet, one on mobile; or a horizontally scrolling row
 * with the carousel variant.
 *
 * globalClass: cards   (the row) and card (each card)
 *
 * Row variants:
 *   cards--2, cards--4      columns from 990px (default 3)
 *   cards--carousel         one scrolling row that bleeds to the right edge
 *                           of the viewport and starts at the content edge;
 *                           js/blocks/cards.js adds arrows for mouse users
 *                           and a one-time swipe hint on touch screens
 * Card variants:
 *   card--icon              a small icon instead of a full-width image
 *   card--plain             no background, border or padding
 *   card--light             the card paints the page background (--body-bg-clr)
 *                           inside a palette section, e.g. white cards on the neutral band
 *   card--overlay           the photo fills the card, title at the bottom;
 *                           hover or focus opens the text and link, touch
 *                           screens show them always; the whole card is the
 *                           link (card-link). Structure and tuning in the
 *                           section at the end of this file
 * The carousel engine (track, arrows, hint) is shared: team-loop--carousel
 * in team.css uses the same rules and script.
 * Query loop:
 *   cards-loop              container around a GB Query Loop whose post
 *                           template container is a .card (dynamic image,
 *                           title, date, excerpt, link). Columns and gaps
 *                           come from the GB grid; the card styles apply.
 *   cards-loop--carousel    the loop's grid scrolls like cards--carousel
 *
 * Structure:
 *   .cards.gb-container [.cards--carousel]        GB: no display setting needed
 *     .card.gb-container.wrapper-extra-color     (palette wrapper gives the card its colors)
 *       figure > img                             (optional, first child; full bleed)
 *       h3.card-title, p, …
 *       a.gb-button.btn-no-bg.card-link          (optional; makes the whole card clickable)
 *
 * Tuning: --cards-gap (24px), --card-radius (12px), --card-padding (24px),
 *         --cards-card-width (carousel card width, min(78vw, 340px)),
 *         --cards-shadow-room (32px: room above and below a carousel row
 *         for the hover lift and shadow)
 *
 * Chain animations: the row is the chain, cards animate in order (1…n,
 * fadeInFromDown). Card contents are not animated separately.
 *
 * Editor: the row's flex layout is repeated on GB's editor layout element;
 * the carousel does not scroll or bleed in the editor, it wraps instead.
 */

:root {
    --cards-gap: 24px;
    --card-radius: 12px;
    --card-padding: 24px;
    --cards-card-width: min(78vw, 340px);
    --cards-shadow-room: 32px;
}

/* Row */
.cards,
.cards > .block-editor-inner-blocks > .block-editor-block-list__layout {
    display: flex;
    flex-wrap: wrap;
    gap: var(--cards-gap);
    align-items: stretch;
}

.cards > .block-editor-inner-blocks {
    width: 100%;
}

/* Card */
.card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 12px;
    flex: 1 1 100%;
    min-width: 0;
    padding: var(--card-padding);
    border-radius: var(--card-radius);
    overflow: hidden;
    transition: transform var(--transition-speed) var(--transition-timing-function),
                box-shadow var(--transition-speed) var(--transition-timing-function);
}

.card > * {
    margin: 0;
}

/* Full-bleed image at the top. The figure owns the 3:2 box and the image
   fills it absolutely, so the image's own size (or its width/height
   attributes before a lazy load) never sets the card height. */
.card > figure:first-child,
.card > [data-type="generateblocks/image"]:first-child {
    margin: calc(-1 * var(--card-padding)) calc(-1 * var(--card-padding)) 8px;
}

.card figure.gb-block-image {
    position: relative;
    aspect-ratio: 3 / 2;
    overflow: hidden;
}

.card figure.gb-block-image img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.card-title {
    font-size: var(--h4-size);
}

/* Link at the bottom; the whole card becomes the click target. The link
   keeps its own width (a stretched flex item would underline the whole card).
   The link is either the .card-link element itself (GB button) or an <a>
   inside it (dynamic headline link). */
.card-link {
    align-self: flex-start;
    margin-top: auto;
    padding-top: 12px;
}

.card:has(.card-link) {
    cursor: pointer;
}

.card a.card-link::before,
.card .card-link a::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
}

.card-meta {
    font-size: 0.85rem;
    opacity: 0.8;
}

@media (hover: hover) {
    .card:has(.card-link):hover {
        transform: translateY(-4px);
        box-shadow: var(--box-shadow);
    }
}

/* Icon card: small square image box, no bleed */
.card--icon > figure:first-child,
.card--icon > [data-type="generateblocks/image"]:first-child {
    margin: 0 0 8px;
    width: 56px;
}

.card--icon figure.gb-block-image {
    width: 56px;
    aspect-ratio: 1;
}

.card--icon figure.gb-block-image img {
    object-fit: contain;
}

/* Plain card: content only */
.card--plain {
    padding: 0;
    border-radius: 0;
    background: none;
    overflow: visible;
}

/* A card on the page background inside a palette section. Two classes keep the
   specificity at (0,2,0), the same as base.css's "nested containers do not paint"
   rule, and this file loads later, so the card wins. */
.gb-container.card--light {
    background-color: var(--body-bg-clr);
}

.card--plain > figure:first-child,
.card--plain > [data-type="generateblocks/image"]:first-child {
    margin: 0 0 8px;
}

@media only screen and (min-width: 768px) {
    .card {
        flex-basis: calc((100% - var(--cards-gap)) / 2);
    }
}

@media only screen and (min-width: 990px) {
    .card {
        flex-basis: calc((100% - 2 * var(--cards-gap)) / 3);
    }

    .cards--2 > .card,
    .cards--2 > .block-editor-inner-blocks > .block-editor-block-list__layout > .card {
        flex-basis: calc((100% - var(--cards-gap)) / 2);
    }

    .cards--4 > .card,
    .cards--4 > .block-editor-inner-blocks > .block-editor-block-list__layout > .card {
        flex-basis: calc((100% - 3 * var(--cards-gap)) / 4);
    }
}

/* ---- Query loop: GB renders .gb-grid-wrapper > .gb-grid-column > .card.
   The grid keeps its own columns and gaps; cards fill their column. ---- */
.cards-loop .gb-grid-column {
    display: flex;
}

.cards-loop .gb-grid-column > .card {
    flex: 1 1 auto;
    width: 100%;
}

.cards-loop .card > figure:first-child:empty {
    display: none;
}

/* ---- Carousel: native horizontal scroll, no library. The row breaks out
   of the section's side padding and pads its content back so the first card
   lines up with the content edge. ---- */
/* The gutter is defined on the frame too: the arrows live in the frame,
   which is the same width as the track. */
.cards--carousel,
.gallery--scroller,
.cards-loop--carousel .gb-grid-wrapper,
.team-loop--carousel .gb-grid-wrapper,
.post-list--carousel .gb-grid-wrapper,
.cards-frame {
    --cards-gutter: max(calc((100vw - 100%) / 2), calc((100% - var(--container-width)) / 2));
}

.cards--carousel,
.gallery--scroller,
.cards-loop--carousel .gb-grid-wrapper,
.team-loop--carousel .gb-grid-wrapper,
.post-list--carousel .gb-grid-wrapper {
    display: flex;
    flex-wrap: nowrap;
    margin-left: calc((100% - 100vw) / 2);
    margin-right: calc((100% - 100vw) / 2);
    padding-left: var(--cards-gutter);
    padding-right: var(--cards-gutter);
    overflow-x: auto;
    scrollbar-width: none;
    align-self: stretch;
}

/* A scrolling row clips vertically too (overflow-x: auto makes overflow-y
   auto), which cuts the cards' hover lift and shadow. Room above and below,
   taken back with negative margins so the layout does not move. Not the
   gallery scroller: its images have no shadow and it sets its own margin. */
.cards--carousel,
.cards-loop--carousel .gb-grid-wrapper,
.team-loop--carousel .gb-grid-wrapper,
.post-list--carousel .gb-grid-wrapper {
    padding-top: var(--cards-shadow-room);
    padding-bottom: var(--cards-shadow-room);
    margin-top: calc(-1 * var(--cards-shadow-room));
    margin-bottom: calc(-1 * var(--cards-shadow-room));
}

.cards--carousel::-webkit-scrollbar,
.gallery--scroller::-webkit-scrollbar,
.cards-loop--carousel .gb-grid-wrapper::-webkit-scrollbar,
.team-loop--carousel .gb-grid-wrapper::-webkit-scrollbar,
.post-list--carousel .gb-grid-wrapper::-webkit-scrollbar {
    display: none;
}

/* 100vw includes a classic scrollbar: clip the few pixels it adds */
.color-section:has(.cards--carousel),
.color-section:has(.gallery--scroller),
.color-section:has(.cards-loop--carousel),
.color-section:has(.team-loop--carousel),
.color-section:has(.post-list--carousel) {
    overflow-x: clip;
}

.cards--carousel > .card,
.gallery--scroller > figure,
.cards-loop--carousel .gb-grid-wrapper > .gb-grid-column,
.team-loop--carousel .gb-grid-wrapper > .gb-grid-column,
.post-list--carousel .gb-grid-wrapper > .gb-grid-column {
    flex: 0 0 var(--cards-card-width);
    width: var(--cards-card-width);
    margin: 0;
}

.cards-loop--carousel .gb-grid-wrapper,
.team-loop--carousel .gb-grid-wrapper,
.post-list--carousel .gb-grid-wrapper {
    gap: var(--cards-gap);
    margin-left: calc((100% - 100vw) / 2);
    margin-right: calc((100% - 100vw) / 2);
    width: auto;
}

/* GB spaces grid columns with padding-left (the grid's horizontal gap) and
   takes it back with a negative margin on the wrapper. The track replaces that
   margin and spaces with gap, so the padding only pushed the first card off
   the content edge and doubled the space between cards. */
.cards-loop--carousel .gb-grid-wrapper > .gb-grid-column,
.team-loop--carousel .gb-grid-wrapper > .gb-grid-column,
.post-list--carousel .gb-grid-wrapper > .gb-grid-column {
    padding-left: 0;
}

/* Controls added by cards.js */
.cards-frame {
    position: relative;
    align-self: stretch;
}

.cards-arrow {
    display: none;
}

.cards-hint {
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 3;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 18px;
    border-radius: 999px;
    background-color: var(--btn-bg);
    color: var(--btn-font-clr);
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transform: translate(-50%, calc(-50% + 8px));
    transition: opacity var(--transition-speed) var(--transition-timing-function),
                transform var(--transition-speed) var(--transition-timing-function);
}

.cards-hint.is-visible {
    opacity: 1;
    transform: translate(-50%, -50%);
}

.cards-hint__arrows {
    letter-spacing: 0.1em;
}

/* Arrows only for mouse users on wider screens; touch users swipe */
@media (hover: hover) and (min-width: 768px) {
    .cards-frame.is-scrollable .cards-arrow {
        position: absolute;
        top: 50%;
        z-index: 3;
        display: grid;
        place-items: center;
        width: 48px;
        height: 48px;
        padding: 0;
        border: 0;
        border-radius: 50%;
        background-color: var(--btn-bg);
        color: var(--btn-font-clr);
        cursor: pointer;
        transform: translateY(-50%);
        opacity: 0;
        pointer-events: none;
        transition: opacity var(--transition-speed), background-color var(--transition-speed);
    }

    /* Shown once the cards have animated in (cards.js adds .is-ready) */
    .cards-frame.is-scrollable.is-ready .cards-arrow {
        opacity: 1;
        pointer-events: auto;
    }

    .cards-frame.is-scrollable .cards-arrow:hover {
        background-color: var(--btn-hover-bg);
        color: var(--btn-hover-font);
    }

    .cards-frame.is-scrollable .cards-arrow:focus-visible {
        outline: 3px solid var(--accent-clr);
        outline-offset: 3px;
    }

    .cards-arrow svg {
        width: 22px;
        height: 22px;
    }

    /* Half over the gutter, but never outside the clipped section */
    .cards-arrow--prev {
        left: max(8px, calc(var(--cards-gutter) - 24px));
    }

    .cards-arrow--prev svg {
        transform: rotate(180deg);
    }

    .cards-arrow--next {
        right: max(8px, calc(var(--cards-gutter) - 24px));
    }

    .cards-frame.is-scrollable.is-ready .cards-arrow:disabled {
        opacity: 0;
        pointer-events: none;
    }
}

/* Editor: the loop preview renders one editable item and previews in
   .gb-post-template-wrapper; show them as a row without bleed or scroll. */
.editor-styles-wrapper .cards-loop--carousel .gb-grid-wrapper,
.editor-styles-wrapper .team-loop--carousel .gb-grid-wrapper,
.editor-styles-wrapper .post-list--carousel .gb-grid-wrapper {
    margin: 0;
    padding: 0;
    overflow: visible;
    width: auto;
}

/* Editor: the carousel neither bleeds nor scrolls, it wraps like the grid */
.block-editor-block-list__layout .cards--carousel,
.block-editor-block-list__layout .gallery--scroller,
.cards--carousel > .block-editor-inner-blocks > .block-editor-block-list__layout {
    flex-wrap: wrap;
    margin: 0;
    padding: 0;
    overflow: visible;
}

.cards--carousel > .block-editor-inner-blocks > .block-editor-block-list__layout > .card {
    flex: 0 0 calc((100% - 2 * var(--cards-gap)) / 3);
    width: auto;
}

/* ---- Overlay card (card--overlay): the photo fills the card and the title
   sits at the bottom; on hover or keyboard focus a dark layer opens with the
   text and the link (max-height transition, image scales). Touch screens show
   the text always. The whole card is the link (card-link). Modelled on
   Index Varainhoito's tarina-kortti.
   Structure: .card.card--overlay > figure > img + .card-body.gb-container >
   h3.card-title, p.card-text, a.gb-button.card-link (plain white text link)
   Carousel card width for overlay cards: 396px (XD). ---- */
.cards--carousel:has(.card--overlay) {
    --cards-card-width: min(78vw, 396px);
}

.card--overlay {
    padding: 0;
    aspect-ratio: 396 / 471;
    background-color: var(--media-bg-clr);
    color: var(--on-media-clr);
    isolation: isolate;
}

.card--overlay > figure:first-child,
.card--overlay > [data-type="generateblocks/image"]:first-child {
    position: absolute;
    inset: 0;
    margin: 0;
    z-index: -2;
}

.card--overlay figure.gb-block-image {
    height: 100%;
    aspect-ratio: auto;
}

.card--overlay figure.gb-block-image img {
    transition: transform 1.2s var(--transition-timing-function);
}

/* The layer: a dark veil (touch screens show the text always), a gradient at
   rest and the veil on hover on devices that can hover */
.card--overlay::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: color-mix(in srgb, var(--media-bg-clr) 62%, transparent);
    transition: background var(--transition-speed) var(--transition-timing-function);
}

.card--overlay .card-body {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: flex-start;
    gap: 0;
    text-align: left;
}

.card--overlay .card-body {
    position: absolute;
    inset: 0;
    justify-content: center;
    padding: 28px;
    /* the body is always centered; at rest it is pushed down so the title
       sits at the bottom, and the hover slides it back (transform animates,
       justify-content would not) */
    transition: transform var(--transition-speed) var(--transition-timing-function);
}

.card--overlay .card-title {
    margin: 0;
    font-size: var(--h3-size);
    color: var(--on-media-clr);
    text-shadow: 0 2px 12px color-mix(in srgb, var(--media-bg-clr) 35%, transparent);
}

.card--overlay .card-text {
    margin: 12px 0 0;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.5;
}

/* The link is a plain white text link, not a btn-no-bg: the growing
   underline fought the body's slide-in. Both selectors outrank
   a.gb-button and a.gb-button:hover from buttons.css. */
.card--overlay a.card-link,
.card--overlay a.card-link:hover {
    margin-top: 14px;
    padding: 0;
    align-self: auto;
    background: none;
    color: var(--on-media-clr);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

/* Hover-capable devices: text and link hidden until hover or keyboard focus */
@media (hover: hover) {
    .card--overlay .card-text,
    .card--overlay .card-link {
        max-height: 0;
        margin-top: 0;
        opacity: 0;
        overflow: hidden;
        transition: max-height var(--transition-speed) var(--transition-timing-function),
                    opacity var(--transition-speed) var(--transition-timing-function),
                    margin var(--transition-speed) var(--transition-timing-function);
    }

    .card--overlay:hover::before,
    .card--overlay:focus-within::before {
        background: color-mix(in srgb, var(--media-bg-clr) 62%, transparent);
    }

    .card--overlay:hover figure.gb-block-image img,
    .card--overlay:focus-within figure.gb-block-image img {
        transform: scale(1.05);
    }

    .card--overlay::before {
        background: linear-gradient(180deg, transparent 40%, color-mix(in srgb, var(--media-bg-clr) 65%, transparent) 100%);
    }

    /* Rest: body moved down by half its height minus the padding and half the
       title line, so the title ends 28px from the bottom edge */
    .card--overlay .card-body {
        transform: translateY(calc(50% - 28px - 0.55 * var(--h3-size)));
    }

    .card--overlay:hover .card-body,
    .card--overlay:focus-within .card-body {
        transform: translateY(0);
    }

    .card--overlay:hover .card-text,
    .card--overlay:focus-within .card-text {
        max-height: 240px;
        margin-top: 12px;
        opacity: 1;
    }

    .card--overlay:hover .card-link,
    .card--overlay:focus-within .card-link {
        max-height: 60px;
        margin-top: 14px;
        opacity: 1;
        overflow: visible;
    }

    .card--overlay:has(.card-link):hover {
        transform: none;
        box-shadow: none;
    }
}

/* Editor (the container itself carries block-editor-block-list__layout):
   keep the text open so it can be edited */
.card--overlay.block-editor-block-list__layout .card-text,
.card--overlay.block-editor-block-list__layout .card-link {
    max-height: none;
    margin-top: 12px;
    opacity: 1;
    overflow: visible;
}

@media (prefers-reduced-motion: reduce) {
    .card--overlay figure.gb-block-image img,
    .card--overlay::before,
    .card--overlay .card-body,
    .card--overlay .card-text,
    .card--overlay .card-link {
        transition: none;
    }
}
