/**
 * 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--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;
}

.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;
}

/* 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;
    }
}
