/*
 * The filter panel as a bottom sheet, below 1024px.
 *
 * Mobile-first: the sheet is the base state and the desktop column is added at
 * 1024px, which is where the results have room for a fourth card beside it.
 *
 * Opening still means toggling `active` on #web-shop and `overflow-hidden` on
 * <body>, exactly as before — layout.html's resize handler clears both above
 * 1024px and that is left alone.
 */

/* selectie.js toggles this class on <body>. combined.css also defines it, but
   only inside a max-width:1008px block, which would leave the page scrolling
   behind an open sheet between 1009 and 1023px. The sheet owns it here. */
body.overflow-hidden {
    overflow: hidden;
}

.filters-sheet {
    position: fixed;
    inset: auto 0 0 0;
    z-index: var(--shop-z-sheet);
    /* A control tabbed to lands clear of the sticky grip above and the sticky
       Reset / results bar below, not underneath them (WCAG 2.4.11). */
    scroll-padding-block: 52px 88px;
    display: flex;
    flex-direction: column;
    height: 95dvh;
    /* No bottom padding: the action bar has to reach the sheet's own edge. */
    padding: 0 var(--shop-space-5);
    border: 0;
    border-radius: var(--shop-radius-sheet) var(--shop-radius-sheet) 0 0;
    /* The sheet is the surface. Without this its 20px side padding and its whole
       header row are transparent and the page shows through them. */
    background: var(--shop-surface);
    overflow-y: auto;
    /* Stops a flick at the end of the list scrolling the page behind it. */
    overscroll-behavior: contain;
    transform: translateY(100%);
    transition: transform var(--shop-duration-sheet) var(--shop-ease);
}

/* A closed sheet is off-screen but still in the document, so without something
   its forty-odd controls stay in the tab order and a keyboard user falls into a
   panel they cannot see. `inert` does that on its own — tab order, assistive
   tech and pointer events — and unlike visibility:hidden it does not interrupt
   the slide, so it is set from JS to follow the open state rather than declared
   here against a viewport. */

#web-shop.active .filters-sheet {
    box-shadow: var(--shop-shadow-sheet);
    transform: none;
}

/* The scrim. A pseudo-element on the sheet's own wrapper rather than the extra
   empty div the legacy markup carried for it. */
.shop-body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: var(--shop-z-scrim);
    background: color-mix(in srgb, var(--shop-ink) 45%, transparent);
    opacity: 0;
    visibility: hidden;
    transition:
        opacity var(--shop-duration-sheet) var(--shop-ease),
        visibility var(--shop-duration-sheet) var(--shop-ease);
}

#web-shop.active .shop-body::after {
    opacity: 1;
    visibility: visible;
}

/* The contact widget and the Trusted Shops badge float above everything and
   would land on the sheet's "show results" button. They belong to the page
   behind the sheet, so they go while it is open: the sheet sets
   .filter-sheet-open on <html> (selectie.js) and layers.css hides them. */

/* Grip ------------------------------------------------------------------------
   Sticks to the top of the sheet while the filters scroll under it. Dragging it
   or the header down closes the sheet; it is aria-hidden and out of the tab
   order because the close button beside it does the same job for the keyboard.
   The negative inline margin runs its white strip to the sheet's edges. */

.filters-sheet__grip {
    position: sticky;
    inset-block-start: 0;
    z-index: var(--shop-z-sticky);
    flex: none;
    width: auto;
    height: 52px;
    margin-inline: calc(var(--shop-space-5) * -1);
    padding-block-end: var(--shop-space-2);
    background: var(--shop-surface);
    cursor: grab;
    /* Keeps a drag from scrolling the page or triggering pull-to-refresh, and
       from selecting the text it starts on — which would cancel the drag. */
    touch-action: none;
    user-select: none;
}

.filters-sheet__grip::before {
    content: "";
    display: block;
    width: 44px;
    height: 5px;
    margin: 24px auto 0;
    border-radius: 3px;
    background: #d9dce8;
}

.filters-sheet__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--shop-space-3);
    margin-block-end: 14px;
    cursor: grab;
    touch-action: none;
    user-select: none;
}

button.filters-sheet__close {
    display: inline-flex;
    align-items: center;
    gap: var(--shop-space-2);
    min-height: var(--shop-tap);
    padding-inline-start: var(--shop-space-2);
    color: var(--shop-accent);
    font-size: var(--shop-text-base);
    font-weight: var(--shop-weight-semibold);
}

.filters-sheet__close:hover {
    color: var(--shop-accent-strong);
}

.filters-sheet__close svg {
    flex: none;
    width: 18px;
    height: 18px;
}

/* In the sheet the card's own frame is the sheet, and the action bar pins to
   the foot: pushed down when the filters are short, sticky once they scroll. */
.filters-sheet .filters {
    display: flex;
    flex: 1;
    flex-direction: column;
    padding: 0;
    border: 0;
    border-radius: 0;
}

.filters-sheet .filters__specs {
    flex: 1;
}

.filters-sheet .filters__actions {
    position: sticky;
    inset-block-end: 0;
    /* Above the price slider's thumbs, which are positioned and would otherwise
       show through the bar as it passes over them. */
    z-index: var(--shop-z-sticky);
    margin-inline: calc(var(--shop-space-5) * -1);
    margin-block-start: var(--shop-space-5);
    padding: var(--shop-space-3) var(--shop-space-5);
    /* Clears a phone's home indicator. */
    padding-block-end: calc(var(--shop-space-3) + env(safe-area-inset-bottom));
    border-block-start: 1px solid var(--shop-divider);
    background: var(--shop-surface);
}

.filters__apply {
    flex: 1;
}

/* The sheet is wider than the desktop column, so the swatches may grow a
   little - but not so far that twelve circles become a banner. */
.filters-sheet .filters__swatches {
    max-width: 280px;
}

/* 16px stops iOS zooming the page when a field takes focus. It applies to the
   whole sheet range, not just phones, because the sheet is what a tablet gets. */
.filters-sheet input.filters__input,
.filters-sheet select.filters__select {
    font-size: var(--shop-text-base);
}

/* Two buttons side by side still have to fit a German or French label on the
   narrowest phone, so the action bar starts compact and relaxes with room. */
.filters-sheet .filters__actions .shop-btn {
    padding-inline: var(--shop-space-3);
    font-size: var(--shop-text-md);
}

@media (min-width: 400px) {
    .filters-sheet .filters__actions .shop-btn {
        padding-inline: var(--shop-space-5);
        font-size: var(--shop-text-control);
    }
}

@media (min-width: 640px) {
    .filters-sheet .filters__option {
        font-size: var(--shop-text-base);
    }

    .filters-sheet .filters__toggle {
        font-size: var(--shop-text-lg);
    }
}

/* Desktop ---------------------------------------------------------------------
   The sheet becomes an ordinary column: everything positional is handed back. */

/* Waiting, in the footer -------------------------------------------------------
   One spinner, on "Toon X resultaten", for every filter update the sheet can
   start - Reset's own press included. Reset keeps its icon: both buttons are
   disabled for the same wait, and a second mark turning beside the first would
   be the same news twice. Drawn in currentColor, so it is white on the primary
   button without that value being written here again.

   18px square. The button has no icon of its own, so the spinner is a new flex
   item and the centred label re-centres around it - 13px at this size, which is
   the cost of a leading spinner and the only movement the footer has.

   Driven by aria-busy on the button, which is also what assistive technology
   reads, so the look and the semantics cannot drift apart. Nothing here fires
   above 1024px: selectie.js sets the attribute only while the panel is a sheet,
   where "Toon X resultaten" exists at all. */
.filters__apply[aria-busy="true"]::before {
    content: "";
    flex: 0 0 auto;
    inline-size: 18px;
    block-size: 18px;
    border: 2px solid color-mix(in srgb, currentColor 25%, transparent);
    border-block-start-color: currentColor;
    border-radius: 50%;
    animation: shop-btn-waiting 700ms linear infinite;
}

@keyframes shop-btn-waiting {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    /* base.css stops the rotation inside #content, which would leave a ring with
       one lit quarter frozen at the top - a spinner that has stalled rather than
       a thing that is working. A dashed ring instead: the whole circle in the
       label's own colour, even all the way round, so there is nothing to read as
       a position and nothing that needs to turn to make sense. */
    .filters__apply[aria-busy="true"]::before {
        border-style: dashed;
        border-color: currentColor;
    }
}

@media (min-width: 1024px) {
    /* An ordinary column in the page's own scroll. It was briefly sticky with its
       own overflow, which put two vertical scroll contexts side by side and left
       it ambiguous whether a wheel would move the filters or the catalogue. The
       reachability problem that solved is handled by the floating opener instead
       (overview.css), which is a smaller thing to get right. */
    .filters-sheet {
        position: static;
        z-index: auto;
        display: block;
        height: auto;
        max-height: none;
        padding: 0;
        border-radius: 0;
        overflow: visible;
        overscroll-behavior: auto;
        transform: none;
        background: none;
    }

    /* Nothing clears .active above this width except layout.html's resize
       handler, so the sheet's upward shadow must not linger on the column if it
       ever runs late. Written with the same two-part selector as the rule it
       answers - a media query adds no specificity, so a bare .filters-sheet here
       would lose to #web-shop.active .filters-sheet. */
    #web-shop.active .filters-sheet {
        box-shadow: none;
    }

    /* button.-qualified like the rule that gives the close button its display;
       a lone class here lost to it, leaving an invisible close button in the
       tab order of the desktop column. */
    .filters-sheet__grip,
    button.filters-sheet__close {
        display: none;
    }

    /* Clipped rather than removed: the heading is this section's accessible
       name and the focus target when the sheet opens, so it has to stay in the
       accessibility tree even where the design shows no heading. */
    .filters-sheet__head {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .shop-body::after {
        content: none;
    }

    /* The panel becomes a card of its own here. */
    .filters-sheet .filters {
        display: block;
        padding: 18px 18px 20px;
        border: 1px solid var(--shop-border-field);
        border-radius: var(--shop-radius-panel);
    }

    /* Nothing clips the panel now, so Reset simply sits at its foot - and with
       no primary action beside it, it spans the panel the way every other
       control in the column does rather than sitting short at the left. */
    .filters-sheet .filters__actions {
        position: static;
        margin-inline: 0;
        margin-block-start: 28px;
        padding: 0;
        border-block-start: 0;
    }

    .filters-sheet .filters__reset {
        flex: 1;
    }

    .filters-sheet .filters__reset .shop-btn {
        width: 100%;
    }

    .filters__apply {
        display: none;
    }
}
