
        /* Page Header */
        .page-header {
            background: linear-gradient(135deg, rgba(128, 0, 0, 0.9), rgba(92, 0, 0, 0.85)),
                        url('https://images.unsplash.com/photo-1610701596007-11502861dcfa?w=1920&q=80');
            background-size: cover;
            background-position: center;
            padding: 8px 0;
            color: var(--white);
            text-align: center;
        }

        .page-header h1 {
            font-size: 22px;
            margin-bottom: 3px;
        }

        .page-header p {
            font-size: 13px;
            opacity: 0.95;
            margin-bottom: 3px;
        }

        .breadcrumb {
            display: flex;
            justify-content: center;
            gap: 10px;
            font-size: 12px;
        }

        .breadcrumb a {
            color: var(--accent-gold);
            text-decoration: none;
        }

        /* The row of category pills that used to sit here is gone — the rail
           above replaced it. Its rules went with it rather than being left to
           be found by somebody wondering which of the two is live. The sort box
           below is still used, at the head of the grid. */

        .sort-select {
            padding: 10px 20px;
            border: 2px solid var(--border-color);
            border-radius: 25px;
            background: var(--white);
            color: var(--text-dark);
            font-weight: 600;
            cursor: pointer;
        }

        /* Products Grid. The band that used to hold it is gone: the grid is
           now the right-hand column of the catalogue layout. */

        .products-grid {
            display: grid;
            /* Fluid rather than fixed 270px columns centred in the page: the
               grid now shares the row with the category rail, and a fixed
               track left a ragged gap on the right at most widths. */
            grid-template-columns: repeat(auto-fill, minmax(206px, 1fr));
            gap: 18px;
            justify-content: start;
        }

        .product-card {
            /*
             * Sized by its grid track, not by itself.
             *
             * It used to be a fixed 270px because the grid was a row of fixed
             * 270px columns. The grid is fluid now — it shares the row with the
             * category rail — so a card that insists on 270px is wider than the
             * space it was given and is drawn over the one beside it. That is
             * the overlap.
             *
             * The fixed 320px height went with it: cards in a grid row are
             * already stretched to the tallest of them, so the height was doing
             * nothing but clipping a line of text off the longer names.
             */
            width: auto;
            min-width: 0;
            background: var(--white);
            border-radius: 16px;
            overflow: hidden;
            box-shadow: 0 5px 20px rgba(0,0,0,0.08);
            transition: all 0.3s ease;
            border: 2px solid transparent;
            display: flex;
            flex-direction: column;
        }

        .product-card:hover {
            transform: translateY(-6px);
            box-shadow: 0 15px 40px var(--shadow);
            border-color: var(--accent-gold);
        }

        .product-image {
            width: 100%;
            height: 160px;
            flex-shrink: 0;
            position: relative;
            overflow: hidden;
            background-color: #fafafa;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .product-image img {
            width: 100%;
            height: 100%;
            object-fit: contain;
            object-position: center;
            display: block;
            padding: 8px;
            transition: transform .3s ease;
        }

        .product-card:hover .product-image img {
            transform: scale(1.05);
        }

        .product-badge {
            position: absolute;
            top: 10px;
            left: 10px;
            background: var(--primary-maroon);
            color: var(--accent-gold);
            padding: 4px 10px;
            border-radius: 14px;
            font-size: 10px;
            font-weight: 700;
        }

        /* The wishlist heart is gone: it saved nothing, and a control that
           does nothing is a promise the shop cannot keep. Its rules went with
           it rather than being left for somebody to wonder about. */


        .product-content {
            padding: 8px 14px 10px;
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
            overflow: hidden;
        }

        .product-category {
            color: var(--primary-maroon);
            font-size: 10px;
            font-weight: 600;
            text-transform: uppercase;
            margin-bottom: 3px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .product-card h3,
        .product-card .product-title {
            font-size: 14px;
            color: var(--text-dark);
            margin-bottom: 3px;
            line-height: 1.25;
            font-weight: 600;
        }

        .product-card h3 a,
        .product-card .product-title a {
            color: var(--text-dark);
            text-decoration: none;
            transition: all 0.3s ease;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
            word-break: break-word;
        }

        .product-card h3 a:hover,
        .product-card .product-title a:hover {
            color: var(--primary-maroon);
        }

        .product-description {
            color: var(--text-light);
            margin: 0 0 4px;
            font-size: 11px;
            line-height: 1.4;
            display: -webkit-box;
            -webkit-line-clamp: 1;
            -webkit-box-orient: vertical;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .product-rating {
            display: flex;
            align-items: center;
            gap: 5px;
            margin-bottom: 4px;
            font-size: 11px;
        }

        .product-stars {
            color: var(--accent-gold);
        }

        .product-footer {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding-top: 8px;
            border-top: 1px solid var(--border-color);
            margin-top: auto;
            gap: 8px;
        }

        .product-price {
            font-size: 18px;
            color: var(--primary-maroon);
            font-weight: 700;
            line-height: 1;
        }

        .product-old-price {
            font-size: 12px;
            color: var(--text-light);
            text-decoration: line-through;
            margin-left: 6px;
        }

        .product-actions {
            display: flex;
            gap: 6px;
        }

        .product-btn {
            padding: 7px 14px;
            border-radius: 20px;
            text-decoration: none;
            font-weight: 600;
            font-size: 12px;
            transition: all 0.3s ease;
            display: inline-flex;
            align-items: center;
            gap: 5px;
            border: none;
            cursor: pointer;
            white-space: nowrap;
        }

        .product-btn-primary {
            background: linear-gradient(135deg, var(--primary-maroon), var(--dark-maroon));
            color: var(--accent-gold);
        }

        .product-btn-primary:hover {
            transform: scale(1.05);
            box-shadow: 0 5px 20px rgba(128, 0, 0, 0.3);
        }

        .product-btn-secondary {
            background: var(--success-green);
            color: var(--white);
        }

        .product-btn-secondary:hover {
            background: #20BA5A;
            transform: scale(1.05);
        }
/* ---------------------------------------------------------------------------
   Empty state and lightbox. products.php carried both as inline `style`
   attributes - the lightbox alone was eleven declarations on one div.
   --------------------------------------------------------------------------- */
.products-empty {
    text-align: center;
    padding: 60px 20px;
}

.products-empty > i {
    font-size: 64px;
    color: #ddd;
    margin-bottom: 20px;
    display: block;
}

.products-empty .product-btn {
    display: inline-block;
    margin-top: 20px;
}

.product-lightbox {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .85);
    z-index: 9999;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.product-lightbox.is-open { display: flex; }

.product-lightbox__close {
    position: absolute;
    top: 20px;
    right: 25px;
    background: none;
    border: none;
    color: #fff;
    font-size: 36px;
    cursor: pointer;
    z-index: 10000;
}

.product-lightbox img {
    max-width: 90%;
    max-height: 90vh;
    object-fit: contain;
    border-radius: 8px;
    box-shadow: 0 0 30px rgba(0, 0, 0, .5);
}

/* Which pack the card's price is for, so the number is never ambiguous. */
.product-unit {
    display: block;
    font-size: 11.5px;
    color: var(--text-light);
    margin-top: 1px;
}

/*
 * The listing's heading, kept for search engines and screen readers but not
 * drawn.
 *
 * The banner it used to sit in filled the first screen of a phone with the
 * word "Products" on a page already headed Products in the navigation, so the
 * products themselves started below the fold. Dropping the h1 with it would
 * have left the page with no heading at all, which is a page a search engine
 * has to guess the subject of.
 *
 * Clipped rather than `display: none` or `visibility: hidden`: both of those
 * take it out of the accessibility tree too, which would hide it from the
 * readers it is being kept for.
 */
.page-title-quiet {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ===========================================================================
   The catalogue: a rail of shelves, and what is on the shelf beside it.

   The row of pills this replaced could hold about five categories before it
   ran out of room, and it spent the top of the page saying words the shopper
   had just clicked. A rail holds as many categories as the shop will ever
   have, stays visible while the grid scrolls, and shows each shelf as a
   picture — which is how somebody who does not know our word for a thing
   still finds it.
   ========================================================================= */
.catalogue { padding: 12px 0 50px; }

.catalogue-layout {
    display: grid;
    grid-template-columns: 104px minmax(0, 1fr);
    gap: 18px;
    align-items: start;
}

.cat-rail {
    position: sticky;
    /*
     * Below the site header, which is sticky itself and about 147px tall on a
     * desktop — 95px of logo row and 52px of navigation. If that header ever
     * changes height this number has to change with it; it is the one place
     * this page knows anything about it.
     */
    top: 160px;
    max-height: calc(100vh - 180px);
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid #eeece7;
    border-radius: 14px;
    background: var(--white);
    scrollbar-width: thin;
}

.cat-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 12px 6px;
    border-left: 3px solid transparent;
    color: var(--text-light);
    text-decoration: none;
    text-align: center;
    transition: background 0.2s ease, color 0.2s ease;
}

.cat-tile + .cat-tile { border-top: 1px solid #f4f1ec; }

.cat-tile-art {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: 12px;
    background: var(--light-bg, #FFF8F0);
    font-size: 20px;
    color: var(--primary-maroon);
    overflow: hidden;
}

/* contain, not cover: a garland photographed on a wide background must not be
   cropped down to a patch of that background. */
.cat-tile-art img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    mix-blend-mode: multiply;
}

.cat-tile-name {
    font-size: 11.5px;
    line-height: 1.3;
    font-weight: 600;
}

.cat-tile:hover { background: #fdfaf6; color: var(--text-dark); }

/* The shelf being looked at. Marked three ways — the bar, the tint and the
   weight — because a single colour change is invisible to a good many people. */
.cat-tile.is-on {
    background: var(--light-gold, #FFF8DC);
    border-left-color: var(--primary-maroon);
    color: var(--primary-maroon);
    font-weight: 700;
}

.cat-tile.is-on .cat-tile-art { background: var(--white); }

/* ---- the right-hand column ---- */

/*
 * Kept low. Everything in this strip is a label — which shelf, how many, in
 * what order — and none of it is what the shopper came for, so it takes one
 * line and hands the height back to the products underneath.
 */
.catalogue-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 10px;
    margin-bottom: 10px;
}

.catalogue-title {
    margin: 0;
    font-size: 16px;
    color: var(--text-dark);
}

/* Beside the name, not under it: on its own line it cost a whole row of height
   to say "10 items". It sits outside the heading in the markup, so the two are
   held together here instead. */
.catalogue-head > .catalogue-title + .catalogue-count {
    margin-right: auto;
    font-size: 12px;
    color: var(--text-light);
}

/* Smaller than the sort box elsewhere on the site — it sits in a strip that
   is deliberately short. */
.catalogue-head .sort-select {
    padding: 7px 16px;
    font-size: 13px;
}

/*
 * On a phone the rail lies down.
 *
 * A column of tiles down the side of a 360px screen leaves the products about
 * 240px to live in, which is one card wide. Turned on its side it costs one
 * row and the whole width is left for the grid.
 */
@media (max-width: 768px) {
    .catalogue-layout {
        display: block;
    }

    .cat-rail {
        position: static;
        display: flex;
        gap: 6px;
        max-height: none;
        margin-bottom: 16px;
        padding: 6px;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scroll-snap-type: x proximity;
        -webkit-overflow-scrolling: touch;
    }

    .cat-tile {
        flex: 0 0 78px;
        border-left: 0;
        border-bottom: 3px solid transparent;
        border-radius: 10px;
        scroll-snap-align: start;
    }

    .cat-tile + .cat-tile { border-top: 0; }

    .cat-tile.is-on {
        border-left-color: transparent;
        border-bottom-color: var(--primary-maroon);
    }

    .cat-tile-art { width: 44px; height: 44px; }
    .cat-tile-name { font-size: 11px; }
}

/* ---- a combo in the listing ----
 *
 * Green, not maroon: a combo badge sits where an ordinary badge ("new",
 * "bestseller") would, and looking the same as one would make it read as
 * just another label rather than as a different kind of thing.
 */
.product-badge.is-combo {
    background: #1e6b32;
    color: #fff;
    letter-spacing: 0.04em;
}

/* Under the price, small: it qualifies the price rather than competing
   with it. The saving is the half worth reading, so only that is bold. */
.product-combo-note {
    display: block;
    margin-top: 3px;
    font-size: 11.5px;
    color: var(--text-light);
}

.product-combo-note strong { color: #1e6b32; }

/* ===========================================================================
   The listing on phones and tablets - below 1024px - as in the mobile design:
   the page's own top bar, a rail of round category pictures down the left,
   filter chips, and two cards a row on a peach ground, each with a heart, a
   "% Off" tag and Buy Now beside Add to cart. From 1024px up nothing here
   applies and the parts only phones use are hidden.
   ========================================================================= */
@media (min-width: 1024px) {
    /* The heart is no longer in this list: saving something for later is not a
       thing only a phone does, and a computer had no way to do it from the
       catalogue at all. The rest of the phone's furniture still goes. */
    .m-appbar, .m-chips, .m-off, .m-buy { display: none !important; }

    /* Top right of the picture, out of the way of the badge on the left. A
       white disc so it reads on a photograph of any colour. */
    .product-card .m-heart {
        position: absolute;
        top: 10px;
        right: 10px;
        z-index: 3;
        display: grid;
        place-items: center;
        width: 32px;
        height: 32px;
        border: 1px solid #efe6d8;
        border-radius: 50%;
        background: rgba(255, 255, 255, .94);
        color: #7d0a0a;
        font-size: 13px;
        cursor: pointer;
        transition: color .15s ease, border-color .15s ease;
    }

    .product-card .m-heart:hover { color: #b3131b; border-color: #b3131b; }
    .product-card .m-heart.is-saved { color: #b3131b; }
}

@media not all and (min-width: 1024px) {
    body:has(.m-appbar) > .header { display: none; }
    /* the listing is an app screen on phones: no site footer under the grid */
    body:has(.m-appbar) .footer { display: none; }
    /* and none of the homepage footer either - that one is for desktop */
    body:has(.m-appbar) .dh-news, body:has(.m-appbar) .dh-footer { display: none; }

    .m-appbar {
        position: sticky; top: 0; z-index: 60;
        display: flex; align-items: center; gap: 16px;
        height: 52px; padding: 0 14px;
        background: #fff; border-bottom: 1px solid #efe9e2;
    }
    .m-appbar-btn { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; color: #1e1e1e; font-size: 17px; text-decoration: none; }
    .m-appbar-btn svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
    .m-appbar-btn svg circle { fill: currentColor; stroke: none; }
    .m-appbar-logo { display: flex; flex: 0 0 auto; align-items: center; }
    .m-appbar-logo img { display: block; width: auto; height: 32px; }
    .m-appbar-logo i { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 50%; background: #f4b400; color: #7d0a0a; font-size: 16px; }
    .m-appbar-title { flex: 1; min-width: 0; font-size: 16px; font-weight: 600; color: #1e1e1e; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

    .catalogue { padding: 0; }
    .catalogue > .container { max-width: none; padding: 0; }
    .catalogue-layout { display: grid; grid-template-columns: 84px minmax(0, 1fr); gap: 0; align-items: stretch; }

    /* the rail stands up again, full height, with round pictures */
    .cat-rail {
        position: sticky; top: 52px; align-self: start;
        display: block; max-height: calc(100vh - 52px); overflow-y: auto;
        margin: 0; padding: 8px 0 24px;
        border: 0; border-right: 1px solid #efe9e2; border-radius: 0; background: #fff;
    }
    .cat-tile, .cat-tile + .cat-tile { flex: none; border: 0; border-radius: 0; padding: 10px 4px; gap: 7px; background: none; color: #555; }
    .cat-tile:hover { background: none; }
    .cat-tile-art { width: 52px; height: 52px; border-radius: 50%; background: #f4efeb; }
    .cat-tile-art img { object-fit: cover; mix-blend-mode: normal; }
    .cat-tile-name { font-size: 10.5px; font-weight: 400; line-height: 1.25; }
    .cat-tile.is-on { background: none; border: 0; color: #1e1e1e; }
    .cat-tile.is-on .cat-tile-name { font-weight: 700; }
    .cat-tile.is-on .cat-tile-art { background: #f4efeb; box-shadow: 0 0 0 2px #7d0a0a; }

    .catalogue-main { background: #fdebd6; min-height: calc(100vh - 52px); padding: 10px 8px 90px; }

    /* the h1 stays for search engines and readers; the count and the select give way to the chips */
    .catalogue-head { margin: 0; }
    .catalogue-title { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
    .catalogue-head .catalogue-count, .catalogue-head .sort-select { display: none; }

    .m-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
    .m-chip { position: relative; }
    .m-chip summary {
        list-style: none; display: flex; align-items: center; gap: 5px;
        height: 28px; padding: 0 9px;
        background: #fff; border: 1px solid #d8cfc5; border-radius: 6px;
        font-size: 12px; font-weight: 600; color: #1e1e1e; white-space: nowrap; cursor: pointer;
    }
    .m-chip summary::-webkit-details-marker { display: none; }
    .m-chip summary .fa-caret-down { font-size: 10px; }
    .m-chip.is-set summary { border-color: #7d0a0a; color: #7d0a0a; }
    .m-chip-menu {
        position: absolute; left: 0; top: calc(100% + 4px); z-index: 40;
        min-width: 150px; padding: 4px;
        background: #fff; border: 1px solid #e6ded5; border-radius: 10px;
        box-shadow: 0 8px 22px rgba(0, 0, 0, .12);
    }
    .m-chip:nth-child(n+3) .m-chip-menu { left: auto; right: 0; }
    .m-chip-menu a { display: block; padding: 8px 10px; border-radius: 7px; font-size: 12.5px; color: #333; text-decoration: none; }
    .m-chip-menu a.is-on { background: #fdebd6; color: #7d0a0a; font-weight: 600; }

    /* cards */
    .products-grid { grid-template-columns: 1fr 1fr; gap: 10px 8px; }
    .product-card, .product-card:hover { border: 0; border-radius: 0; box-shadow: none; background: transparent; overflow: visible; transform: none; }
    /* A fixed frame: the photo is laid inside it, so a tall or wide picture can never change the box. */
    .product-image { display: block; height: auto; aspect-ratio: 1 / 1.08; padding: 0; background: #fff; border-radius: 6px; overflow: visible; }
    .product-image img, .product-card:hover .product-image img {
        position: absolute; top: 4px; left: 4px;
        width: calc(100% - 8px); height: calc(100% - 8px);
        padding: 0; object-fit: cover; object-position: center; border-radius: 4px; transform: none;
    }
    .product-badge { display: none; }
    /* The homepage's heart, to the letter: a white rounded square with a
       maroon hairline and an outline heart inside it, big enough for a thumb.
       This one was smaller and had no edge, so the same control looked like
       two different things depending which page you were on. */
    .m-heart {
        position: absolute; top: 10px; right: 10px; z-index: 3;
        display: flex; align-items: center; justify-content: center;
        width: 28px; height: 28px; border-radius: 8px;
        border: 1px solid rgba(125, 10, 10, .14);
        background: #fff; color: #7d0a0a; font-size: 13px; line-height: 1; text-decoration: none;
        box-shadow: 0 1px 3px rgba(0, 0, 0, .12);
        transition: background-color .15s, color .15s;
    }
    .m-heart i { display: block; line-height: 1; }
    .m-heart.is-saved { background: #fff; color: #b3131b; }
    .m-off { position: absolute; left: 0; bottom: -2px; z-index: 3; padding: 2px 5px; border-radius: 2px; background: #0b7a0b; color: #fff; font-size: 9px; font-weight: 600; }

    .product-content { padding: 6px 0 0; overflow: visible; }
    .product-category, .product-description, .product-rating, .product-unit, .product-combo-note { display: none; }
    .product-card .product-title { margin: 1px 0 2px; font-size: 11.5px; font-weight: 400; }
    .product-card .product-title a { -webkit-line-clamp: 1; }
    .product-footer { display: block; margin: 0; padding: 0; border: 0; }
    .product-price { font-size: 14px; }
    .product-old-price { margin-left: 4px; font-size: 11.5px; }

    .product-actions { display: flex; gap: 5px; margin-top: 6px; }
    .product-actions > form, .product-actions .cart-control { display: block; flex: 1 1 0; min-width: 0; margin: 0; }
    .product-actions .cart-control form { margin: 0; }
    .m-buy button, .product-actions .cart-btn {
        display: flex; align-items: center; justify-content: center;
        width: 100%; height: 28px; min-height: 0; padding: 0 4px;
        border: 1px solid #7d0a0a; border-radius: 3px;
        font-size: 11px; font-weight: 500; white-space: nowrap;
    }
    .m-buy button { background: #7d0a0a; color: #fff; cursor: pointer; }
    .product-actions .cart-btn.is-add { background: #fff; color: #7d0a0a; }
    .product-actions .cart-btn i { display: none; }
    .product-actions .cart-btn.is-out { border-color: #ddd; background: #f3f3f3; color: #888; }
    .product-actions .cart-stepper { display: flex; justify-content: space-between; width: 100%; height: 28px; border-radius: 3px; }
    .product-actions .cart-stepper button { width: 26px; height: 28px; }
}

@media (min-width: 640px) and (max-width: 1023.98px) {
    .catalogue-layout { grid-template-columns: 110px minmax(0, 1fr); }
    .cat-tile-art { width: 64px; height: 64px; }
    .cat-tile-name { font-size: 12px; }
    .products-grid { grid-template-columns: repeat(3, 1fr); gap: 14px 12px; }
    .product-card .product-title { font-size: 13px; }
    .product-price { font-size: 16px; }
    .m-buy button, .product-actions .cart-btn, .product-actions .cart-stepper { height: 32px; font-size: 11.5px; }
}
@media (min-width: 768px) and (max-width: 1023.98px) {
    .products-grid { grid-template-columns: repeat(4, 1fr); }
}

/* The homepage header on this page: it takes over from 1024px up, and the shop's
   older header steps aside. Below that the page keeps its own phone bar. */
@media (min-width: 1024px) {
    body:has(.dh-header) > .header { display: none; }
}
@media not all and (min-width: 1024px) {
    .dh-header { display: none; }
}

/* ===========================================================================
   The shop, as drawn in the design: filters down the left, a strip of combo
   packs along the top, then the shelf and its pager. Desktop only - phones
   keep the app bar, the tile rail and the chips above the grid.
   ========================================================================= */
@media not all and (min-width: 1024px) {
    .shop-side, .combo-strip, .catalogue-lede { display: none; }
}

@media (min-width: 1024px) {
    .cat-rail { display: none; }
    /* this page wears the homepage's header and footer; the shop's own footer
       would otherwise sit under it, saying the same things twice */
    body:has(.catalogue-layout) .footer { display: none; }
    .catalogue { padding: 24px 0 44px; background: #fdf8f5; }
    /* The shelf uses the width the screen has, like the header above it: the
       filters sit in the page's left gutter and the cards fill the rest. A
       1200px column left the combo cards narrower than the design draws them,
       with a band of empty page on either side. */
    .catalogue > .container { max-width: none; padding: 0 40px; }
    .catalogue-layout { display: grid; grid-template-columns: 252px minmax(0, 1fr); gap: 26px; align-items: start; }

    /* ---- the filters ---- */
    /* The filters stay on screen while the shelf scrolls past them. They stop
       below the sticky header - that height is the header's own, written the
       way the header writes it - and scroll inside themselves if the screen is
       too short to hold the whole panel. */
    .shop-side {
        --shop-side-u: clamp(.66px, 100vw / 1920, 1px);
        --shop-side-top: calc(115 * var(--shop-side-u) + 14px);
        position: sticky; top: var(--shop-side-top);
        max-height: calc(100vh - var(--shop-side-top) - 16px); overflow-y: auto; overscroll-behavior: contain;
        padding: 14px; border: 1px solid #f0e4e4; border-radius: 12px; background: #fff;
        scrollbar-width: thin;
    }
    .shop-side::-webkit-scrollbar { width: 6px; }
    .shop-side::-webkit-scrollbar-thumb { border-radius: 3px; background: #e6d8d0; }
    .shop-side-title { margin: 0 0 12px; font-size: 15px; font-weight: 700; color: #1e1e1e; }
    .shop-kinds { display: grid; gap: 8px; }
    .shop-kind { display: flex; align-items: center; gap: 8px; padding: 9px 11px; border-radius: 8px; background: #faf5f2; color: #4a4a4a; font-size: 12.5px; text-decoration: none; }
    .shop-kind i { color: #7d0a0a; font-size: 12px; }
    .shop-kind b { margin-left: auto; font-weight: 500; color: #9a9a9a; }
    .shop-kind:hover { background: #f5e9e4; }
    .shop-kind.is-on { background: #7d0a0a; color: #fff; }
    .shop-kind.is-on i, .shop-kind.is-on b { color: #fff; }

    .shop-block { margin-top: 16px; border-top: 1px solid #f2e9e4; padding-top: 12px; }
    .shop-block summary { display: flex; align-items: center; justify-content: space-between; list-style: none; font-size: 13px; font-weight: 600; color: #1e1e1e; cursor: pointer; }
    .shop-block summary::-webkit-details-marker { display: none; }
    .shop-block summary::after { content: ""; width: 7px; height: 7px; border-right: 2px solid #8a8a8a; border-bottom: 2px solid #8a8a8a; transform: rotate(45deg); transition: transform .2s ease; }
    .shop-block[open] summary::after { transform: rotate(-135deg); }
    .shop-list { margin: 10px 0 0; padding: 0; list-style: none; }
    .shop-list li + li { margin-top: 7px; }
    .shop-list a { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #55504c; text-decoration: none; }
    .shop-box { flex: 0 0 auto; width: 14px; height: 14px; border: 1px solid #d8cdc6; border-radius: 3px; background: #fff; }
    .shop-list a.is-on .shop-box { position: relative; border-color: #7d0a0a; background: #7d0a0a; }
    .shop-list a.is-on .shop-box::after { content: ""; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px; border-right: 2px solid #fff; border-bottom: 2px solid #fff; transform: rotate(42deg); }
    .shop-list a.is-on { color: #7d0a0a; font-weight: 600; }
    .shop-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .shop-count { margin-left: auto; color: #a49a94; font-size: 11px; }
    .shop-stars { display: inline-flex; align-items: center; gap: 2px; color: #f5bd00; font-size: 11px; }
    .shop-stars .is-off { color: #ded6d0; }
    .shop-stars small { margin-left: 4px; color: #7a736e; }

    .shop-price { margin-top: 12px; }
    .shop-price input[type="range"] { width: 100%; accent-color: #7d0a0a; }
    .shop-price-ends { display: flex; justify-content: space-between; margin-top: 4px; font-size: 11px; color: #8a8480; }
    .shop-price button { margin-top: 8px; width: 100%; height: 30px; border: 1px solid #7d0a0a; border-radius: 6px; background: #fff; color: #7d0a0a; font-size: 11.5px; font-weight: 600; cursor: pointer; }
    .shop-price button:hover { background: #7d0a0a; color: #fff; }

    .shop-clear { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 16px; padding: 9px; border-radius: 8px; background: #faf5f2; color: #7d0a0a; font-size: 12px; font-weight: 600; text-decoration: none; }
    .shop-clear:hover { background: #f3e3dc; }

    /* ---- the combo strip ---- */
    /* written last in the markup so the h1 leads the page; shown first. */
    .catalogue-main { display: flex; flex-direction: column; }

    /* A warm band with a mandala pressed into each end, the heading in maroon,
       four white cards across it, and the arrows sitting on the mandalas. */
    .combo-strip {
        order: -1; position: relative; overflow: hidden;
        margin-bottom: 20px; padding: 13px 58px 15px;
        border: 0; border-radius: 14px; background: #f8e8c9;
    }
    /* The half mandala at each end of the band (assets/img/combo-mandala, cut
       from the artwork supplied for it). Its straight edge sits on the band's
       edge and the petals open inward, so the left one is mirrored. */
    .combo-strip::before, .combo-strip::after {
        content: ""; position: absolute; top: 50%; width: 80px; height: 170px; pointer-events: none;
        background: center / contain no-repeat url("../img/combo-mandala.png");
        background-image: image-set(url("../img/combo-mandala.webp") type("image/webp"), url("../img/combo-mandala.png") type("image/png"));
        opacity: .6;
    }
    .combo-strip::before { left: 0; transform: translateY(-50%) scaleX(-1); }
    .combo-strip::after { right: 0; transform: translateY(-50%); }

    /* The heading sits close to the band's corner and holds its two lines
       together, the way the design draws it. */
    .combo-strip-head { position: relative; z-index: 1; display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin: 0 -30px 9px -30px; }
    .combo-strip-title { display: flex; align-items: center; gap: 10px; }
    .combo-strip-icon { flex: 0 0 auto; color: #7d0a0a; font-size: 32px; line-height: 1; }
    .combo-strip-head h2 { margin: 0; font-family: Georgia, "Times New Roman", serif; font-size: 19px; font-weight: 700; line-height: 1.15; color: #7d0a0a; }
    .combo-strip-head p { margin: 3px 0 0; font-size: 12px; line-height: 1.3; color: #4f4136; }
    .combo-strip-head a { flex: 0 0 auto; color: #7d0a0a; font-size: 11px; font-weight: 600; text-decoration: none; }
    .combo-strip-head a:hover { text-decoration: underline; }

    /* Four to a row, whether there are four combos or one: a single combo used
       to stretch across the whole strip, photograph and all. */
    .combo-rail-wrap { position: relative; z-index: 1; }
    .combo-rail { display: grid; grid-auto-flow: column; grid-auto-columns: calc((100% - 36px) / 4); gap: 12px; overflow-x: auto; scroll-snap-type: x proximity; scrollbar-width: none; }
    .combo-rail > .combo-card { scroll-snap-align: start; }
    .combo-rail::-webkit-scrollbar { display: none; }
    .combo-arrow {
        position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
        display: flex; align-items: center; justify-content: center;
        width: 30px; height: 30px; border: 1px solid #efe0cd; border-radius: 50%;
        background: #fff; color: #7d0a0a; font-size: 13px; cursor: pointer; box-shadow: 0 2px 10px rgba(0, 0, 0, .12);
    }
    .combo-arrow.is-prev { left: -34px; }
    .combo-arrow.is-next { right: -34px; }
    .combo-arrow:disabled { color: #cfc4bd; cursor: default; opacity: .75; box-shadow: none; }

    /* The combo card, as the reference draws it: the photograph with a red
       badge, a bold name, a line about it, the stars with stock beside them,
       and one row with the price, the original, the saving and Add to cart.

       It keeps the size the card had: the photograph takes whatever height the
       lines under it leave (--combo-lines), and the card's width sets the rest. */
    .combo-card { --combo-lines: 53px; display: flex; flex-direction: column; min-width: 0; padding: 11px 11px 14px; border-radius: 10px; background: #fff; box-shadow: 0 1px 6px rgba(0, 0, 0, .07); font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif; line-height: normal; container-type: inline-size; }
    .combo-card-photo { position: relative; }
    .combo-card-photo > a:first-child { display: block; overflow: hidden; border-radius: 8px; }
    .combo-card-photo img { display: block; width: 100%; height: calc(100cqw * 160 / 254 + 51px - var(--combo-lines)); object-fit: cover; transition: transform .35s; }
    .combo-card:hover .combo-card-photo img { transform: scale(1.04); }
    .combo-card-noimg { display: flex; height: calc(100cqw * 160 / 254 + 51px - var(--combo-lines)); align-items: center; justify-content: center; background: #f7efe7; color: #c9b6a5; font-size: 24px; }
    .combo-flag { position: absolute; top: 8px; left: 8px; padding: 4px 10px; border-radius: 12px; background: #c8102e; color: #fff; font-size: 10.5px; font-weight: 600; line-height: 1.2; box-shadow: 0 1px 4px rgba(0, 0, 0, .18); }

    .combo-card-name { display: block; margin-top: 9px; overflow: hidden; font-size: 13px; font-weight: 700; line-height: 17px; color: #1e1e1e; white-space: nowrap; text-overflow: ellipsis; text-decoration: none; }
    .combo-card-name:hover { color: #800000; }
    .combo-card-desc { height: 15px; margin: 2px 0 0; overflow: hidden; font-size: 11.5px; line-height: 15px; color: #6f6a66; white-space: nowrap; text-overflow: ellipsis; }

    .combo-review { display: flex; align-items: center; gap: 5px; height: 15px; margin-top: 5px; overflow: hidden; font-size: 11px; line-height: 15px; color: #6f6a66; white-space: nowrap; }
    .combo-review-stars { display: inline-flex; gap: 1px; color: #f5a800; font-size: 11px; }
    .combo-review-stars .is-off { color: #ded6d0; }
    .combo-review-sep { color: #cfc6c0; }
    .combo-in { color: #1f7a3d; font-weight: 600; }
    .combo-out { color: #b3261e; font-weight: 600; }

    .combo-buy-row { display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-top: auto; padding-top: 9px; }
    .combo-price { display: flex; align-items: center; gap: 5px; min-width: 0; overflow: hidden; white-space: nowrap; }
    .combo-price strong { font-size: 16px; font-weight: 700; color: #800000; }
    .combo-price s { font-size: 11px; color: #9a9290; }
    .combo-price em { padding: 2px 6px; border-radius: 10px; background: #fde6e8; color: #c8102e; font-size: 9.5px; font-style: normal; font-weight: 600; }
    /* A narrow card keeps the price, the original and the button: the saving
       pill goes first, then the cart icon on the button. */
    @container (max-width: 227px) { .combo-price em { display: none; } }
    @container (max-width: 180px) { .combo-buy-row .cart-btn i { display: none; } .combo-buy-row .cart-btn { padding: 0 9px; } }

    .combo-buy-row .cart-control { flex: 0 0 auto; }
    .combo-buy-row .cart-control form { margin: 0; }
    .combo-buy-row .cart-btn, .combo-buy-row .cart-stepper {
        display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 30px; min-height: 0; margin: 0; padding: 0 11px;
        border: 0; border-radius: 6px; font-family: inherit; font-size: 11.5px; font-weight: 600; white-space: nowrap; cursor: pointer;
    }
    .combo-buy-row .cart-btn.is-add { background: #800000; color: #fff; }
    .combo-buy-row .cart-btn.is-add:hover { background: #650000; }
    .combo-buy-row .cart-btn.is-out { background: #f3f3f3; color: #888; cursor: default; }

    /* ---- the shelf head, the cards, the pager ---- */
    .catalogue-head { display: grid; grid-template-columns: 1fr auto; align-items: center; row-gap: 2px; margin-bottom: 16px; }
    .catalogue-title { grid-column: 1; margin: 0; font-size: 20px; }
    .catalogue-lede { grid-column: 1; grid-row: 2; margin: 0; font-size: 12.5px; color: #8a8480; }
    .catalogue-count { grid-column: 2; grid-row: 2; justify-self: end; font-size: 12px; color: #8a8480; }
    .catalogue-head .sort-select { grid-column: 2; grid-row: 1; justify-self: end; padding: 7px 12px; border-width: 1px; border-radius: 8px; font-size: 12px; font-weight: 500; }

    .products-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
    .product-card { border-radius: 12px; border-color: #f0e4e4; box-shadow: 0 2px 10px rgba(0, 0, 0, .04); }
    .product-rating { flex-wrap: wrap; }
    .product-in { color: #1f7a3d; font-weight: 600; }
    .product-out { color: #b3261e; font-weight: 600; }

    .shop-pager { display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 26px; }
    .shop-page { display: inline-flex; align-items: center; justify-content: center; min-width: 32px; height: 32px; padding: 0 8px; border: 1px solid #ecdfd8; border-radius: 8px; background: #fff; color: #55504c; font-size: 12.5px; text-decoration: none; }
    .shop-page:hover { border-color: #7d0a0a; color: #7d0a0a; }
    .shop-page.is-on { background: #7d0a0a; border-color: #7d0a0a; color: #fff; font-weight: 700; }
    .shop-page.is-off { opacity: .4; pointer-events: none; }
}

/* The pager is for phones too: the shelf is paged for everybody. */
@media not all and (min-width: 1024px) {
    .shop-pager { display: flex; align-items: center; justify-content: center; gap: 6px; margin: 16px 0 6px; }
    .shop-page { display: inline-flex; align-items: center; justify-content: center; min-width: 28px; height: 28px; padding: 0 6px; border: 1px solid #ecdfd8; border-radius: 6px; background: #fff; color: #55504c; font-size: 11.5px; text-decoration: none; }
    .shop-page.is-on { background: #7d0a0a; border-color: #7d0a0a; color: #fff; font-weight: 700; }
    .shop-page.is-off { opacity: .4; pointer-events: none; }
}

/* ---------------------------------------------------------------------------
   The heart, with nothing behind it.

   It sat on a white rounded square, which on a photograph read as a sticker
   stuck to the picture. Only the mark is left; the box it stood on is gone.
   The tap area stays the same size — the square is still there, it is simply
   not painted — and a drop shadow keeps the outline readable over a pale
   photograph as well as a dark one.
   ------------------------------------------------------------------------ */
.m-heart,
.product-card .m-heart {
    border: 0;
    background: none;
    box-shadow: none;
    color: #7d0a0a;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .45));
}

.m-heart:hover,
.product-card .m-heart:hover { background: none; color: #b3131b; }
.m-heart.is-saved,
.product-card .m-heart.is-saved { background: none; color: #b3131b; }

/* A little larger, and nearer the corner it belongs to. */
.m-heart,
.product-card .m-heart {
    top: 6px;
    right: 6px;
    width: 30px;
    height: 30px;
    font-size: 16px;
}

@media (min-width: 1024px) {
    .product-card .m-heart { top: 8px; right: 8px; width: 34px; height: 34px; font-size: 18px; }
}

/* ---------------------------------------------------------------------------
   On a card, Add to Cart is the basket and nothing else.

   The words and the price and Buy Now were fighting for one line, which is
   why the button read "Add to Car" at some widths. The icon says it on its
   own here; the words stay on the product's own page, where there is room and
   where it is the page's one decision.

   The label is clipped rather than removed, so the button still announces
   itself as "Add to Cart" to a screen reader.
   ------------------------------------------------------------------------ */
.product-actions .cart-btn.is-add .cart-btn-label,
.m-buy ~ .cart-control .cart-btn.is-add .cart-btn-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.product-actions .cart-btn.is-add {
    flex: 0 0 auto;
    min-width: 44px;
    padding-left: 12px;
    padding-right: 12px;
}

.product-actions .cart-btn.is-add i { display: inline-block; font-size: 1.05em; margin: 0; }

/* ---------------------------------------------------------------------------
   Buy Now keeps its width after the item is in the basket.

   The two controls used to split the row down the middle. That was fine while
   the second one was a button; once it becomes a − 1 + stepper it needs more
   room than half, takes it, and Buy Now is left with a sliver reading
   "Buy No". So the cart control — basket icon or stepper — takes only what it
   needs, and Buy Now takes the rest of the row in both states.
   ------------------------------------------------------------------------ */
.product-actions > form.m-buy { flex: 1 1 auto; min-width: 0; }
.product-actions .cart-control { flex: 0 0 auto; min-width: 0; }

.product-actions .cart-stepper {
    width: auto;
    justify-content: center;
    gap: 2px;
    padding: 0 2px;
}

/* The count between the two signs was stretching to fill; it only needs room
   for a number, so the whole stepper stays as narrow as the icon it replaced. */
.product-actions .cart-stepper-count { flex: 0 0 auto; min-width: 14px; text-align: center; }

/* ---------------------------------------------------------------------------
   On a computer the button says what it does.

   The basket alone is for the phone, where a card is half a screen wide and
   the words were being cut. From 1024px up there is room for them, so the
   label comes back out of its clip and the button reads "Add to Cart" again.
   ------------------------------------------------------------------------ */
@media (min-width: 1024px) {
    .product-actions .cart-btn.is-add .cart-btn-label,
    .m-buy ~ .cart-control .cart-btn.is-add .cart-btn-label {
        position: static;
        width: auto;
        height: auto;
        margin: 0;
        overflow: visible;
        clip-path: none;
    }

    .product-actions .cart-btn.is-add { min-width: 0; gap: 6px; }
}

/* ---------------------------------------------------------------------------
   The hidden label must stay inside its button.

   Clipping the words puts them in a box one pixel wide, but an absolutely
   positioned box belongs to the nearest positioned ancestor — and there was
   none, so the words belonged to the page. A rail clips what is inside it;
   it does not clip something that belongs to the page, so those hidden words
   sat far off to the right and made the document wider than the screen. The
   fixed bars stretched to that width, and the page could be dragged sideways.

   Positioning the button gives the label somewhere of its own to hide.
   ------------------------------------------------------------------------ */
.cart-btn { position: relative; }
