/*
 * Filter panel: the card, its collapsible sections and its controls.
 *
 * How the panel is presented — a column on desktop, a bottom sheet below
 * 1024px — is filter-sheet.css. This file is the same either way.
 *
 * The markup keeps the ids and classes the filter mechanism depends on
 * (.replace-content, .replace-input, .replace-select, data-url, #filter-query)
 * and drops the ones that only ever fed legacy CSS. In particular it no longer
 * carries id="sidebar" or id="colorpanel": combined.css styles both by id, and
 * #sidebar h2 / #sidebar p are shared with the cart, checkout and product pages
 * so they cannot be deleted. Not emitting those ids is what keeps this panel
 * free of them without a specificity fight or a single !important.
 */

/* No frame here: below 1024px the sheet is the frame. The card is added at
   1024px by filter-sheet.css, where the panel becomes a column. */
.filters {
    background: var(--shop-surface);
    /* The floating opener scrolls here; without this the panel lands flush
       against the top edge with its first control half-cut. */
    scroll-margin-block-start: var(--shop-space-4);
}

.filters__title {
    color: var(--shop-ink);
    font-size: var(--shop-text-xl);
    font-weight: var(--shop-weight-bold);
    line-height: var(--shop-leading-tight);
}

/* Sections -------------------------------------------------------------------
   <fieldset>/<legend> groups the controls; the legend holds a real <button> so
   the collapse is reachable by keyboard and announces its state. */

.filters__group {
    margin: 0;
    padding: 0 0 var(--shop-space-4);
    border: 0;
    border-block-start: 1px solid var(--shop-divider);
}

.filters__group:first-of-type {
    border-block-start: 0;
}

/* A <legend> renders in the fieldset's block-start border edge and ignores the
   fieldset's own padding - display:block does not opt out of that. So the space
   above a heading has to be the legend's, or every section title ends up resting
   on the previous section's last control. */
.filters__legend {
    display: block;
    width: 100%;
    /* Foundation's `fieldset legend { margin-left: -0.1875rem }` hangs every
       heading 3px left of its controls (there is no fieldset border to
       straddle). Its `fieldset > legend { margin-bottom: .2rem !important }`
       set the gap under the heading; stated here as the panel's own, so the
       page no longer depends on the legacy rule, which can go in the cleanup
       commit (until then it still wins, at the same value). */
    margin-inline: 0;
    margin-block-end: 0.2rem;
    padding: var(--shop-space-4) 0 0;
}

.filters__group:first-of-type .filters__legend {
    padding-block-start: 0;
}

button.filters__toggle {
    display: flex;
    align-items: center;
    /* WCAG 2.2 target size; coarse pointers get the full 44px below. */
    min-height: 24px;
    justify-content: space-between;
    gap: var(--shop-space-2);
    width: 100%;
    color: var(--shop-ink);
    font-size: var(--shop-text-control);
    font-weight: var(--shop-weight-bold);
    line-height: 1.3;
}

/* The section names are stored upper case and reused elsewhere, so the casing
   is corrected here rather than in the data. */
.filters__toggle-text {
    text-transform: lowercase;
}

.filters__toggle-text::first-letter {
    text-transform: uppercase;
}

.filters__chevron {
    flex: none;
    width: var(--shop-icon-xs);
    height: var(--shop-icon-xs);
    transition: transform var(--shop-duration) var(--shop-ease);
}

.filters__group.is-collapsed .filters__chevron {
    transform: rotate(180deg);
}

.filters__group.is-collapsed .filters__body {
    display: none;
}

.filters__body {
    padding-block-start: var(--shop-space-3);
}

/* Options --------------------------------------------------------------------
   Each option is a <button> rather than the <a href="#"> it used to be. It was
   never a link — the href went nowhere and the JS always cancelled it — and a
   button can carry aria-pressed, which is the only way the selected state
   reaches a screen reader. The POST, the URL and the swap are unchanged. */

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

/* The Sale option under the price slider: the only option list that shares a body with
   another control. Deliberately tight - one step of the scale, and the option's own 5px of
   padding on top of it - so it reads as the last line of the price block rather than as a
   section that lost its heading. */
.filters__options--under-slider {
    margin-block-start: var(--shop-space-1);
}

button.filters__option {
    display: flex;
    align-items: center;
    gap: var(--shop-gap-tight);
    width: 100%;
    padding: 5px 0;
    color: var(--shop-text-soft);
    font-size: var(--shop-text-md);
    line-height: 1.4;
    text-align: start;
}

.filters__option[aria-pressed="true"] {
    color: var(--shop-ink);
}

/* Everything else on this surface answers the pointer; the filter panel was the
   one place that did not. */
.filters__option:hover {
    color: var(--shop-ink);
}

.filters__option:hover .filters__checkbox {
    border-color: var(--shop-accent);
}

.filters__toggle:hover {
    color: var(--shop-accent);
}

.filters__swatch:not([aria-pressed="true"]):hover {
    box-shadow:
        0 0 0 2px var(--shop-surface),
        0 0 0 4px var(--shop-accent-soft-hover);
}

.filters__checkbox {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    /* 3.04:1 against white, so the unchecked box is a visible control boundary
       rather than the near-invisible #c9cde0 the reference uses. */
    border: 1.5px solid #8d93b2;
    border-radius: 5px;
    background: var(--shop-surface);
    color: transparent;
}

.filters__checkbox svg {
    width: 12px;
    height: 12px;
    /* Hidden by opacity as well as colour: forced colours repaints the
       transparent tick as text, and every option would look checked. */
    opacity: 0;
}

.filters__option[aria-pressed="true"] .filters__checkbox {
    border-color: var(--shop-accent);
    background: var(--shop-accent);
    color: #fff;
}

.filters__option[aria-pressed="true"] .filters__checkbox svg {
    opacity: 1;
}

/* In forced colours a swatch's colour is its content, not decoration. */
@media (forced-colors: active) {
    button.filters__swatch {
        forced-color-adjust: none;
    }
}

/* Fields ---------------------------------------------------------------------- */

.filters__field {
    position: relative;
}

/* `input.`/`select.` rather than the bare class: base.css neutralises
   Foundation's field styling at (0,1,1), so a lone class would lose to it. */
input.filters__input,
select.filters__select {
    box-sizing: border-box;
    width: 100%;
    height: var(--shop-tap);
    padding-inline: 14px;
    border: 1px solid var(--shop-border-field);
    border-radius: var(--shop-radius-md);
    background: var(--shop-surface);
    color: var(--shop-ink);
    font-size: var(--shop-text-md);
}

input.filters__input:focus,
select.filters__select:focus {
    border-color: var(--shop-accent);
}

.filters__field--search input.filters__input {
    padding-inline-start: 40px;
}

.filters__search-icon {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 14px;
    width: 18px;
    height: 18px;
    margin-block-start: -9px;
    color: var(--shop-text-soft);
    pointer-events: none;
}

.filters__field--measure {
    max-width: 160px;
}

.filters__field--measure input.filters__input {
    padding-inline-end: 44px;
}

.filters__suffix {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-end: 14px;
    transform: translateY(-50%);
    color: var(--shop-text-soft);
    font-size: var(--shop-text-md);
    pointer-events: none;
}

/* Colour swatches --------------------------------------------------------------
   Four across, as in the design, capped so the circles stay a comfortable size
   rather than growing with the panel. */

.filters__swatches {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 14px;
    max-width: 240px;
    margin: 0;
    padding: 0;
    list-style: none;
}

button.filters__swatch {
    aspect-ratio: 1;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    /* A faint inset edge rather than a border, so a pale swatch still reads as a
       circle without the swatch changing size. */
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--shop-ink) 8%, transparent);
    color: #fff;
    /* The selection ring below reaches 4px out, so a focus ring has to clear it
       or it lands on top of the purple and neither reads. */
    outline-offset: 6px;
}

/* Selected: a 2px white gap, then a 2px accent ring. The gap is what lets the
   ring read against every swatch colour - flush, it merges into the purple and
   blue swatches and looks like a thicker edge rather than a selection. */
.filters__swatch[aria-pressed="true"] {
    box-shadow:
        0 0 0 2px var(--shop-surface),
        0 0 0 4px var(--shop-accent);
}

.filters__swatch svg {
    width: 14px;
    height: 14px;
    /* The tick has to read on both a white and a black swatch. */
    filter: drop-shadow(0 0 1px rgb(0 0 0 / 45%));
    /* Hidden by opacity as well as colour, for the same reason as the
       checkbox's tick above: forced colours repaints a transparent tick as
       text, and every swatch would look selected. */
    opacity: 0;
}

/* The selected state is now entirely in the stylesheet, as it already was for
   the checkbox options - so the ring and the tick appear together the moment
   aria-pressed flips, whether that is the server's markup or selectie.js
   showing a click before the reply lands. */
.filters__swatch[aria-pressed="true"] svg {
    opacity: 1;
}

/* Actions ---------------------------------------------------------------------
   In the sheet the pair shares one row; on desktop only Reset is there and it
   spans the panel (filter-sheet.css). */

.filters__actions {
    display: flex;
    align-items: center;
    gap: var(--shop-space-3);
    margin-block-start: 28px;
}

/* Reset takes only the width of its own label, so the primary action gets the
   rest of the row rather than an even half of it. */
.filters__reset {
    flex: none;
    display: flex;
}

.filters__reset .shop-btn {
    white-space: nowrap;
}

/* Touch ------------------------------------------------------------------------
   Keyed to the input device, not the viewport width: a 1180px tablet is a touch
   device and a 900px desktop window is not. */

@media (pointer: coarse) {
    /* button.-qualified to match the rules they override, which are qualified
       themselves to beat Foundation's button styles. */
    button.filters__toggle {
        min-height: var(--shop-tap);
    }

    /* The one deliberate exception to 44px. Stacked rows can only be as tall to
       tap as the gap between them allows, and at 44px the lists read as oddly
       airy. 32px keeps a full-width target well above the 24px minimum. */
    button.filters__option {
        min-height: 32px;
        padding: 0;
    }
}

/* The no-script price fields. Only ever rendered inside <noscript>, so these
   rules are inert whenever the slider is present. */
.filters__nojs-price {
    display: grid;
    gap: var(--shop-space-2);
}

.filters__nojs-price label {
    color: var(--shop-text-soft);
    font-size: var(--shop-text-md);
}
