/*------------------------------------*\
    #Filterable cards widget

    Self-contained styles compatible with any Photon theme. Layout utilities
    (.l-frame, .l-box, .card--neat etc.) are provided here rather than relying
    on theme-specific classes. Colours use the theme's custom properties so the
    widget follows the site's brand and accent settings.
\*------------------------------------*/

/*------------------------------------*\
    #Card list reset

    The list no longer carries .clean-list (an origin-specific utility). Browser
    default bullets, padding, and margin are reset here so the layout works on
    any theme.
\*------------------------------------*/

.filterable-cards__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

/*------------------------------------*\
    #Card body

    Replaces .l-box.l-box--no-border.card__text (origin-specific). Flex column
    so the last child (chips) can be pushed to the foot of the card.
\*------------------------------------*/

.filterable-card__body {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    padding: 1rem;
}

.filterable-card__body > :last-child {
    margin-block-start: auto;
}

/*------------------------------------*\
    #Card image frame

    Replaces .l-frame.l-frame--3-2 (origin-specific). Enforces a 3:2 aspect
    ratio and clips the image within it.
\*------------------------------------*/

.filterable-card__image-frame {
    aspect-ratio: 3 / 2;
    overflow: hidden;
    position: relative;
}

.filterable-card__image-frame img {
    height: 100%;
    left: 0;
    object-fit: cover;
    position: absolute;
    top: 0;
    width: 100%;
}

/*------------------------------------*\
    #Card link

    Replaces .card__link (origin-specific). Stretches to fill the heading so
    the whole heading area is clickable via the card component.
\*------------------------------------*/

.filterable-card__link {
    color: inherit;
    text-decoration: none;
}

.filterable-card__link:hover {
    text-decoration: underline;
}

/*------------------------------------*\
    #Filter options list reset

    .tag-list and .clean-list removed; reset margins/padding directly.
\*------------------------------------*/

.filterable-cards__filter-options {
    list-style: none;
    margin: 0;
    padding: 0;
}

.filterable-cards__filter-options > li {
    margin: 0;
}

/*------------------------------------*\
    #Sidebar layout

    Left and right place the filters in a fixed width column beside the cards,
    from 48em up. Below that everything stacks.

    Source order is always filters, heading, then cards, so the controls precede
    the results they affect for keyboard and screen reader users. The right hand
    layout swaps only the visual column, using order.
\*------------------------------------*/

.filterable-cards {
    /* Fixed sidebar width for the left and right filter positions. */
    --filter-sidebar-width: 16rem;
    /* Gutter between cards in the sidebar layouts. */
    --card-gap: 1.5rem;
}

@media screen and (min-width: 48em) {
    /*
        The filters take a fixed width column and the remaining children wrap
        into the space left over. Flex is used so the layout holds regardless of
        which optional elements are present.
    */
    .filterable-cards[data-filter-position="left"],
    .filterable-cards[data-filter-position="right"] {
        align-items: flex-start;
        column-gap: 2rem;
        display: flex;
        flex-wrap: wrap;
    }

    /* Full width so it sits above both columns. */
    .filterable-cards[data-filter-position="left"] > .widget__heading,
    .filterable-cards[data-filter-position="right"] > .widget__heading {
        flex-basis: 100%;
    }

    /*
        Both columns are pinned to the top of the row with no block start
        offset, so the first filter group and the first card start on the same
        line.
    */
    .filterable-cards[data-filter-position="left"] > .filterable-cards__filters,
    .filterable-cards[data-filter-position="right"] > .filterable-cards__filters {
        align-self: flex-start;
        flex: 0 0 var(--filter-sidebar-width);
        margin-block: 0;
        max-inline-size: var(--filter-sidebar-width);
        padding-block-start: 0;
    }

    .filterable-cards[data-filter-position="left"] > .filterable-cards__list,
    .filterable-cards[data-filter-position="right"] > .filterable-cards__list {
        align-self: flex-start;
        margin-block: 0;
        padding-block-start: 0;
    }

    .filterable-cards[data-filter-position="left"] > .filterable-cards__list > li,
    .filterable-cards[data-filter-position="right"] > .filterable-cards__list > li {
        margin-block-start: 0;
    }

    /*
        The content column. calc subtracts the sidebar and the column gap so the
        cards fill exactly the space left over.
    */
    .filterable-cards[data-filter-position="left"] > .filterable-cards__heading,
    .filterable-cards[data-filter-position="left"] > .filterable-cards__list,
    .filterable-cards[data-filter-position="left"] > .filterable-cards__no-results,
    .filterable-cards[data-filter-position="right"] > .filterable-cards__heading,
    .filterable-cards[data-filter-position="right"] > .filterable-cards__list,
    .filterable-cards[data-filter-position="right"] > .filterable-cards__no-results {
        flex: 0 0 calc(100% - var(--filter-sidebar-width) - 2rem);
        max-inline-size: calc(100% - var(--filter-sidebar-width) - 2rem);
    }

    /* Right hand layout: the filters move to the end of the visual row. */
    .filterable-cards[data-filter-position="right"] > .filterable-cards__filters {
        order: 1;
    }

    /*
        The live region falls between the filters and the card list in source
        order. Ordering it first keeps it from sitting between the two columns.
        It remains in the accessibility tree, so announcements are unaffected.
    */
    .filterable-cards[data-filter-position="left"] > [data-filterable-result-count],
    .filterable-cards[data-filter-position="right"] > [data-filterable-result-count] {
        order: -1;
    }

    /*
        The theme's shelves component spaces its items with percentage margins
        and padding, which offsets the first card against the filter column. A
        grid is used instead: it gives the configured number of equal columns
        with even gutters and no offset at the top of the list.
    */
    .filterable-cards[data-filter-position="left"] > .filterable-cards__list,
    .filterable-cards[data-filter-position="right"] > .filterable-cards__list {
        display: grid;
        gap: var(--card-gap, 1.5rem);
        grid-template-columns: repeat(var(--card-columns, 3), minmax(0, 1fr));
        margin: 0;
    }

    .filterable-cards[data-filter-position="left"] > .filterable-cards__list > li,
    .filterable-cards[data-filter-position="right"] > .filterable-cards__list > li {
        max-inline-size: none;
        padding: 0;
    }

    /*
        In a sidebar the groups always stack, so the filter columns setting is
        ignored, and the divider belongs on the side rather than underneath.
    */
    .filterable-cards[data-filter-position="left"] > .filterable-cards__filters,
    .filterable-cards[data-filter-position="right"] > .filterable-cards__filters {
        border-block-end: 0;
        grid-template-columns: 1fr;
        margin-block-end: 0;
        padding-block-end: 0;
    }

    .filterable-cards[data-filter-position="left"] > .filterable-cards__filters {
        border-inline-end: 1px solid #c6c6c6;
        padding-inline-end: 1.5rem;
    }

    .filterable-cards[data-filter-position="right"] > .filterable-cards__filters {
        border-inline-start: 1px solid #c6c6c6;
        padding-inline-start: 1.5rem;
    }
}

/*------------------------------------*\
    #Filter bar
\*------------------------------------*/

/*
    The rule separates the filter controls from the results below. Applied to the
    filter bar rather than a separate element so it disappears with it when no
    filter fields are configured.
*/
.filterable-cards__filters {
    border-block-end: 1px solid #c6c6c6;
    display: grid;
    gap: 1.25rem;
    margin-block-end: 2.5rem;
    padding-block-end: 2rem;
}

/*
    Column count comes from the --filter-columns custom property, set per widget
    from the Control Centre setting. auto-fit keeps it sane if a narrow container
    cannot fit that many.
*/
@media screen and (min-width: 48em) {
    .filterable-cards__filters {
        grid-template-columns: repeat(var(--filter-columns, 3), minmax(0, 1fr));
    }
}

.filterable-cards__filter-hint {
    grid-column: 1 / -1;
    margin-block: 0 0.5rem;
}

/*
    Filter groups are flat - no background or shadow, dashed border - so they
    read as controls rather than as cards.

    The theme applies a block margin to every details element. It is overridden
    with !important so the first group lines up with the top of the card column.
*/
.filterable-cards__filter-group {
    background-color: transparent;
    border: 1px dashed #8d8d8d;
    border-radius: 0.25rem;
    margin-top: 0 !important;
    padding: 1.5rem;
}

/* The theme's heading margin is cleared so the group title sits tight to the box. */
.filterable-cards__filter-heading {
    color: inherit;
    font-size: 1.0625rem;
    font-size: clamp(0.875rem, 0.8rem + 0.375vw, 1.0625rem);
    font-weight: 700;
    line-height: 1.5;
    margin-block-end: 0.75rem;
    margin-block-start: 0;
}

/*
    Above 48em the theme's disclosure triangle and its reserved padding are
    removed so the summary reads as a plain heading. The element remains a real
    summary at all widths, keeping its native keyboard behaviour.
*/

.filterable-cards__filter-heading {
    list-style: none;
}

.filterable-cards__filter-heading::-webkit-details-marker {
    display: none;
}

/*
    The base (non-class) rules suppress collapse above 48em by default; the
    modifier classes override them where collapse is enabled.

    mobile < 48em  ·  tablet 48em–63.9375em  ·  desktop ≥ 64em
*/

.filterable-cards--collapse-mobile .filterable-cards__filter-heading,
.filterable-cards--collapse-tablet .filterable-cards__filter-heading,
.filterable-cards--collapse-desktop .filterable-cards__filter-heading {
    align-items: center;
    display: flex;
    justify-content: space-between;
}

@media screen and (max-width: 47.9375em) {
    .filterable-cards__filter-group > .filterable-cards__filter-heading {
        --collapsible: 0;
    }

    .filterable-cards--collapse-mobile .filterable-cards__filter-heading {
        --collapsible: 1;
    }

    .filterable-cards--collapse-mobile .filterable-cards__filter-heading::after {
        border-bottom: 2px solid currentColor;
        border-right: 2px solid currentColor;
        content: '';
        display: inline-block;
        flex-shrink: 0;
        height: 0.5rem;
        margin-inline-start: 0.75rem;
        transform: rotate(45deg);
        transition: transform 0.2s ease;
        width: 0.5rem;
    }

    .filterable-cards--collapse-mobile details[open] > .filterable-cards__filter-heading::after {
        transform: rotate(-135deg);
    }
}

/* Suppress pointer and chevron above 48em by default. */
@media screen and (min-width: 48em) {
    .filterable-cards__filter-group > .filterable-cards__filter-heading {
        --collapsible: 0;
        cursor: default;
        padding-inline-start: 0;
    }

    .filterable-cards__filter-group > .filterable-cards__filter-heading::before {
        content: none;
    }

    .filterable-cards__filter-group > .filterable-cards__filter-heading::after {
        content: none;
    }
}

@media screen and (min-width: 48em) and (max-width: 63.9375em) {
    .filterable-cards--collapse-tablet .filterable-cards__filter-group > .filterable-cards__filter-heading {
        --collapsible: 1;
        cursor: pointer;
    }

    .filterable-cards--collapse-tablet .filterable-cards__filter-heading::after {
        border-bottom: 2px solid currentColor;
        border-right: 2px solid currentColor;
        content: '';
        display: inline-block;
        flex-shrink: 0;
        height: 0.5rem;
        margin-inline-start: 0.75rem;
        transform: rotate(45deg);
        transition: transform 0.2s ease;
        width: 0.5rem;
    }

    .filterable-cards--collapse-tablet details[open] > .filterable-cards__filter-heading::after {
        transform: rotate(-135deg);
    }
}

@media screen and (min-width: 64em) {
    .filterable-cards--collapse-desktop .filterable-cards__filter-group > .filterable-cards__filter-heading {
        --collapsible: 1;
        cursor: pointer;
    }

    .filterable-cards--collapse-desktop .filterable-cards__filter-heading::after {
        border-bottom: 2px solid currentColor;
        border-right: 2px solid currentColor;
        content: '';
        display: inline-block;
        flex-shrink: 0;
        height: 0.5rem;
        margin-inline-start: 0.75rem;
        transform: rotate(45deg);
        transition: transform 0.2s ease;
        width: 0.5rem;
    }

    .filterable-cards--collapse-desktop details[open] > .filterable-cards__filter-heading::after {
        transform: rotate(-135deg);
    }
}

.filterable-cards__filter-options {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/*------------------------------------*\
    #Filter buttons

    Interactive controls. Outlined by default, filled with a tick when selected.
    Colour comes from --filter-group-colour, set per group in the widget settings.

    1. Resets the font so the inherited tag padding applies cleanly.
    2. The selected state must not rely on colour alone (WCAG 1.4.1). High
    contrast modes remove background colours, so the tick is what remains.
    3. Hover thickens the border by 1px; padding drops to match so the button
    does not change size.
\*------------------------------------*/

button.filterable-chip {
    background-color: transparent;
    border: 1px solid var(--filter-group-colour, #6f6f6f);
    color: var(--filter-group-colour, #262626);
    cursor: pointer;
    font: inherit; /* 1 */
    font-size: 1.0625rem;
    font-size: clamp(0.875rem, 0.8rem + 0.375vw, 1.0625rem);
    line-height: 1.5;
}

button.filterable-chip:hover {
    border-width: 2px;
    padding: 0.5rem; /* 3 */
    text-decoration: underline;
}

button.filterable-chip.filterable-chip--active {
    background-color: var(--filter-group-colour, #6f6f6f);
    border-color: var(--filter-group-colour, #6f6f6f);
    color: #fff;
}

button.filterable-chip.filterable-chip--active::before {
    content: "\2713"; /* 2 */
    margin-inline-end: 0.375rem;
}

/*------------------------------------*\
    #Card chips

    Metadata, not controls. Outlined by default and filled when the matching
    filter is selected. No tick - that is reserved for the filter buttons, so
    the two roles stay visually distinct.

    1. Overrides the theme's solid tag pill.
    2. Border weight carries the selected state alongside the fill, since high
    contrast modes remove background colours.
\*------------------------------------*/

span.filterable-chip {
    background-color: transparent; /* 1 */
    border: 1px solid var(--filter-group-colour, #6f6f6f);
    border-radius: 1rem;
    color: var(--filter-group-colour, #262626);
    cursor: default;
    font-size: 0.875rem;
    line-height: 1.5;
    padding: 0.25rem 0.6875rem;
}

span.filterable-chip:hover {
    text-decoration: none;
}

span.filterable-chip.filterable-chip--active {
    background-color: var(--filter-group-colour, #6f6f6f);
    border-color: var(--filter-group-colour, #6f6f6f);
    border-width: 2px; /* 2 */
    color: #fff;
    padding: 0.1875rem 0.625rem;
}

/*------------------------------------*\
    #Card grid

    The column count comes from --card-columns, set from the widget settings.
    All positions use CSS grid so the layout is self-contained and independent
    of the theme's card-list component.
\*------------------------------------*/

/* Scoped to the top position; the sidebar layouts size their cards with a grid. */
@media screen and (min-width: 48em) {
    .filterable-cards[data-filter-position="top"] > .filterable-cards__list {
        display: grid;
        gap: var(--card-gap, 1.5rem);
        grid-template-columns: repeat(var(--card-columns, 3), minmax(0, 1fr));
        margin: 0;
    }

    .filterable-cards[data-filter-position="top"] > .filterable-cards__list > li {
        max-inline-size: none;
        padding: 0;
    }
}

/*
    Heading for the card section, below the divider. Distinct from the widget
    title, which sits above the filters.
*/
.filterable-cards__heading {
    margin-block-start: 0;
}

/*
    Cards fade and lift as they are filtered in and out.

    The script adds filterable-card--leaving, waits for the transition, then sets
    the hidden attribute, so a hidden card leaves the accessibility tree and the
    tab order rather than staying transparent.

    Motion is disabled under prefers-reduced-motion.
*/
.filterable-cards__list > li {
    transition: opacity 0.2s ease, transform 0.2s ease;
}

.filterable-cards__list > li.filterable-card--leaving {
    opacity: 0;
    transform: translateY(-0.5rem);
}

.filterable-cards__list > li.filterable-card--entering {
    opacity: 0;
    transform: translateY(0.5rem);
}

/*
    Applied while a card is offset back to its previous position. The transition is
    suppressed so the offset is applied instantly; removing the class then lets the
    card transition into its new position.
*/
.filterable-cards__list > li.filterable-card--moving {
    transition: none;
}

@media screen and (prefers-reduced-motion: reduce) {
    .filterable-cards__list > li,
    .filterable-cards__list > li.filterable-card--leaving,
    .filterable-cards__list > li.filterable-card--entering,
    .filterable-cards__list > li.filterable-card--moving {
        opacity: 1;
        transform: none;
        transition: none;
    }

    .filterable-cards--collapse-mobile .filterable-cards__filter-heading::after,
    .filterable-cards--collapse-tablet .filterable-cards__filter-heading::after,
    .filterable-cards--collapse-desktop .filterable-cards__filter-heading::after {
        transition: none;
    }
}

/*------------------------------------*\
    #Cards

    The theme draws an accent stripe under card images. It is removed here:
    these are content tiles rather than promotional cards.
\*------------------------------------*/

.filterable-card .filterable-card__image-frame {
    border-bottom: 0;
}

.filterable-card .filterable-card__link:hover,
.js [data-component="card"].filterable-card:hover .filterable-card__link {
    text-decoration: underline;
}

/*
    Stands in for a missing image so every card keeps the same proportions.
    .filterable-card__image-frame already absolutely positions and centres its children.
*/
.filterable-card__placeholder {
    align-items: center;
    background-color: var(--placeholder-colour, #e0e0e0);
    display: flex;
    justify-content: center;
}

.filterable-card__placeholder-text {
    color: var(--placeholder-text-colour, #fff);
    font-size: 1.0625rem;
    font-size: clamp(0.875rem, 0.8rem + 0.375vw, 1.0625rem);
    font-weight: 700;
    line-height: 1.5;
    padding: 1rem;
    text-align: center;
}

.filterable-card__summary {
    margin-block-start: 0.5rem;
}

/*
    No margin-block-start here: .filterable-card__body sets `margin-block-start: auto` on
    its last child, which pushes the chips to the foot of the card. A fixed margin would
    override that (equal specificity, later in the cascade) and break the alignment.
*/
.filterable-card__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.filterable-card__chips > li {
    margin: 0;
}

/*------------------------------------*\
    #Unavailable ("Coming Soon") cards

    The badge text carries the meaning; the muted styling is secondary
    reinforcement only, never the sole signal.
\*------------------------------------*/

.filterable-card--unavailable .filterable-card__image-frame {
    opacity: 0.55;
}

.filterable-card--unavailable .card__heading {
    color: #525252;
}

.filterable-card__badge {
    color: #525252;
    display: inline-block;
    font-size: 0.875rem;
    font-style: italic;
    line-height: 1.5;
    margin-inline-start: 0.5rem;
    vertical-align: middle;
    white-space: nowrap;
}

/*------------------------------------*\
    #No results

    Shown when a filter combination matches nothing. Hidden via the [hidden]
    attribute, which also removes it from the accessibility tree.
\*------------------------------------*/

.filterable-cards__no-results[hidden] {
    display: none;
}

.filterable-cards__clear {
    flex-shrink: 0;
}
