/* ==========================================================================
   Echo Lifestyle - storefront

   Same palette as the back office, opposite intent. The admin shell is dense
   because people work in it all day; this is browsed, so it is generous:
   larger type, more air, and the serif from the logo doing the talking.

   Loaded instead of site.css, not alongside it. Nothing here overrides the
   back office and nothing there leaks in.
   ========================================================================== */

:root {
    --shop-wine-900: #2a0713;
    --shop-wine-700: #4d1028;
    --shop-wine-600: #70203e;
    --shop-wine-100: #f7e9ee;

    --shop-rose-400: #e6aa96;
    --shop-rose-500: #c98b6e;
    --shop-rose-600: #a9705a;   /* dark enough to read on white */

    --shop-ink: #1c1418;
    --shop-ink-soft: #6b6169;
    --shop-line: #e7e2e5;
    --shop-surface: #ffffff;
    --shop-canvas: #fbf9fa;

    --shop-display: Georgia, "Times New Roman", serif;

    --shop-header-height: 68px;
}

body {
    font-size: 0.95rem;
    line-height: 1.6;
    color: var(--shop-ink);
    background: var(--shop-surface);
}

.shop-display {
    font-family: var(--shop-display);
    letter-spacing: -0.01em;
}

a {
    color: var(--shop-wine-600);
}

a:hover {
    color: var(--shop-wine-700);
}

/* --- header --------------------------------------------------------------- */

.shop-announce {
    background: var(--shop-wine-900);
    color: var(--shop-rose-400);
    font-size: 0.78rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 0.4rem 0;
    text-align: center;
}

.shop-header {
    position: sticky;
    top: 0;
    z-index: 1030;
    background: var(--shop-surface);
    border-bottom: 1px solid var(--shop-line);
}

.shop-header__bar {
    min-height: var(--shop-header-height);
}

/* The mark and the wordmark are separate on purpose: the emblem ships as
   artwork, the words are live type. Setting the whole lockup as an image would
   mean shipping the LIFESTYLE line at a size where it cannot be read, and it
   would blur on every screen the artwork was not sized for. */
.shop-logo {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    text-decoration: none;
    color: var(--shop-wine-700);
    white-space: nowrap;
}

.shop-logo:hover {
    color: var(--shop-wine-600);
}

.shop-logo img {
    width: 40px;
    height: 40px;
    object-fit: contain;
    flex: 0 0 auto;
}

.shop-logo__type {
    display: flex;
    flex-direction: column;
    line-height: 1;
    font-family: var(--shop-display);
    font-size: 1.42rem;
    font-weight: 700;
    letter-spacing: .01em;
}

/* Tracked out to sit under ECHO at the same optical width, the way it does in
   the artwork. */
.shop-logo__type small {
    font-family: var(--shop-display);
    font-size: .5rem;
    font-weight: 400;
    letter-spacing: .38em;
    text-transform: uppercase;
    color: var(--shop-rose-600, #a9705a);
    margin-top: .22rem;
    margin-left: .1em;
}

.shop-logo--dark {
    color: #fff;
}

.shop-logo--dark .shop-logo__type small {
    color: var(--shop-rose-400);
}

.shop-logo--dark img {
    width: 36px;
    height: 36px;
}

.shop-basket {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    text-decoration: none;
    color: var(--shop-ink);
    font-size: .85rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    white-space: nowrap;
}

.shop-basket:hover {
    color: var(--shop-wine-600);
}

.shop-basket__count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.35rem;
    height: 1.35rem;
    padding: 0 .35rem;
    border-radius: 999px;
    background: var(--shop-wine-600);
    color: #fff;
    font-size: .72rem;
    letter-spacing: 0;
    font-variant-numeric: tabular-nums;
}

.shop-nav {
    border-top: 1px solid var(--shop-line);
}

.shop-nav__list {
    display: flex;
    flex-direction: column;
}

.shop-nav__item {
    position: static;
}

.shop-nav__link {
    display: inline-block;
    padding: 0.65rem 0;
    margin-right: 1.6rem;
    color: var(--shop-ink);
    text-decoration: none;
    font-size: 0.85rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    border-bottom: 2px solid transparent;
}

.shop-nav__link:hover,
.shop-nav__link.is-active {
    color: var(--shop-wine-600);
    border-bottom-color: var(--shop-wine-600);
}

/* --- mega menu ------------------------------------------------------------
   Desktop only. On a phone there is no hover, the panel would cover the page,
   and the top-level link already goes somewhere useful - so below the md
   breakpoint the children simply do not render as a panel. */

.shop-mega { display: none; }

@media (min-width: 768px) {
    .shop-nav__list {
        flex-direction: row;
        flex-wrap: wrap;
        position: relative;
    }

    .shop-mega {
        display: block;
        position: absolute;
        left: 0;
        right: 0;
        top: 100%;
        z-index: 1040;
        background: var(--shop-surface);
        border-top: 1px solid var(--shop-line);
        border-bottom: 1px solid var(--shop-line);
        box-shadow: 0 12px 24px -18px rgba(42, 7, 19, .5);

        /* Hidden by clipping rather than display:none, so the panel can fade
           and so a keyboard tab still reaches the links inside it. */
        opacity: 0;
        visibility: hidden;
        transform: translateY(-4px);
        transition: opacity .14s ease, transform .14s ease, visibility .14s;
    }

    .shop-nav__item:hover .shop-mega,
    .shop-nav__item:focus-within .shop-mega {
        opacity: 1;
        visibility: visible;
        transform: none;
    }

    .shop-mega__inner {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 220px;
        gap: 2rem;
        padding: 1.5rem 0 1.75rem;
    }

    /* Sub-categories and brands side by side, each falling away when it has
       nothing in it - so a category with brands but no children still gets a
       full-width panel rather than a column of dead space. */
    .shop-mega__panels {
        display: flex;
        flex-wrap: wrap;
        gap: 1.5rem 2.5rem;
        align-items: start;
    }

    .shop-mega__panel {
        flex: 1 1 240px;
        min-width: 0;
    }

    .shop-mega__title {
        font-size: .7rem;
        letter-spacing: .1em;
        text-transform: uppercase;
        color: var(--shop-ink-soft);
        margin-bottom: .45rem;
    }

    .shop-mega__cols {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
        gap: .1rem 1.5rem;
        align-content: start;
    }

    .shop-mega__link {
        display: block;
        padding: .3rem 0;
        color: var(--shop-ink);
        text-decoration: none;
        font-size: .9rem;
    }

    .shop-mega__link:hover {
        color: var(--shop-wine-600);
    }

    /* Quiet on purpose. The number is there to be checked, not read. */
    .shop-mega__count {
        font-size: .72rem;
        color: var(--shop-ink-soft);
        font-variant-numeric: tabular-nums;
        margin-left: .25rem;
    }

    .shop-mega__aside {
        border-left: 1px solid var(--shop-line);
        padding-left: 1.5rem;
        display: flex;
        flex-direction: column;
        gap: .6rem;
        align-content: start;
    }

    .shop-mega__all,
    .shop-mega__offer {
        font-size: .85rem;
        text-decoration: none;
    }

    .shop-mega__all {
        font-weight: 600;
        color: var(--shop-wine-600);
    }

    .shop-mega__offer {
        color: var(--shop-rose-600);
    }
}

@media (prefers-reduced-motion: reduce) {
    .shop-mega { transition: none; }
}

.shop-search .form-control {
    border-right: 0;
}

.shop-search .btn {
    border-color: var(--bs-border-color);
    border-left: 0;
}

/* --- product tiles -------------------------------------------------------- */

.shop-card {
    display: block;
    height: 100%;
    text-decoration: none;
    color: inherit;
}

.shop-card__frame {
    position: relative;
    aspect-ratio: 1 / 1;
    background: var(--shop-canvas);
    border: 1px solid var(--shop-line);
    overflow: hidden;
}

.shop-card__frame img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .45s ease;
}

.shop-card:hover .shop-card__frame img {
    transform: scale(1.04);
}

/* No photograph yet. A grey box with the product's initial beats a broken
   image icon, and it makes the gap in the photography obvious. */
.shop-card__placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    font-family: var(--shop-display);
    font-size: 2.5rem;
    color: var(--shop-rose-500);
    background: var(--shop-wine-100);
}

.shop-card__flag {
    position: absolute;
    top: .5rem;
    left: .5rem;
    background: var(--shop-wine-600);
    color: #fff;
    font-size: .7rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    padding: .15rem .5rem;
}

.shop-card__veil {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, .72);
    font-size: .8rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--shop-ink-soft);
}

.shop-card__brand {
    font-size: .72rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--shop-ink-soft);
    margin-top: .6rem;
}

.shop-card__name {
    font-size: .95rem;
    line-height: 1.35;
    margin: .15rem 0 .3rem;
}

.shop-card:hover .shop-card__name {
    color: var(--shop-wine-600);
}

.shop-price {
    font-weight: 600;
}

.shop-price__was {
    color: var(--shop-ink-soft);
    text-decoration: line-through;
    font-weight: 400;
    margin-left: .35rem;
}

/* --- sections ------------------------------------------------------------- */

.shop-hero {
    background:
        radial-gradient(900px 420px at 20% -10%, var(--shop-wine-100), transparent 70%),
        var(--shop-canvas);
    border-bottom: 1px solid var(--shop-line);
}

.shop-section__title {
    font-family: var(--shop-display);
    font-size: 1.5rem;
    margin: 0;
}

.shop-rule {
    height: 1px;
    background: var(--shop-line);
    flex: 1;
}

.shop-tile {
    display: block;
    text-decoration: none;
    color: inherit;
    border: 1px solid var(--shop-line);
    padding: 1.1rem;
    height: 100%;
    background: var(--shop-surface);
}

.shop-tile:hover {
    border-color: var(--shop-rose-500);
    color: var(--shop-wine-600);
}

/* --- product page --------------------------------------------------------- */

.shop-gallery__main {
    aspect-ratio: 1 / 1;
    background: var(--shop-canvas);
    border: 1px solid var(--shop-line);
    overflow: hidden;
}

.shop-gallery__main img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.shop-thumb {
    width: 68px;
    height: 68px;
    object-fit: cover;
    border: 1px solid var(--shop-line);
    cursor: pointer;
    background: var(--shop-canvas);
}

.shop-thumb.is-active {
    border-color: var(--shop-wine-600);
}

/* A shade is a colour. Rendering it as a circle rather than a dropdown row is
   the single cheapest thing this page does for a cosmetics catalogue. */
.shop-swatch {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 1px solid var(--shop-line);
    padding: 0;
    position: relative;
}

.shop-swatch.is-active {
    box-shadow: 0 0 0 2px var(--shop-surface), 0 0 0 3px var(--shop-wine-600);
}

.shop-swatch.is-out::after {
    content: "";
    position: absolute;
    inset: -1px;
    border-radius: 50%;
    background: linear-gradient(to bottom right,
        transparent calc(50% - 1px), var(--shop-ink-soft) 50%,
        transparent calc(50% + 1px));
    opacity: .7;
}

.shop-chip {
    border: 1px solid var(--shop-line);
    background: var(--shop-surface);
    padding: .35rem .85rem;
    font-size: .85rem;
}

.shop-chip.is-active {
    border-color: var(--shop-wine-600);
    color: var(--shop-wine-600);
}

.shop-chip:disabled {
    color: var(--shop-ink-soft);
    text-decoration: line-through;
    background: var(--shop-canvas);
}

.shop-price--lead {
    font-family: var(--shop-display);
    font-size: 1.9rem;
}

.btn-shop {
    background: var(--shop-wine-600);
    border-color: var(--shop-wine-600);
    color: #fff;
    letter-spacing: .06em;
    text-transform: uppercase;
    font-size: .85rem;
    padding: .7rem 1.6rem;
}

.btn-shop:hover,
.btn-shop:focus {
    background: var(--shop-wine-700);
    border-color: var(--shop-wine-700);
    color: #fff;
}

.btn-shop:disabled {
    background: var(--shop-ink-soft);
    border-color: var(--shop-ink-soft);
    color: #fff;
    opacity: .55;
}

.shop-accordion .accordion-button:not(.collapsed) {
    background: var(--shop-wine-100);
    color: var(--shop-wine-700);
}

.shop-accordion .accordion-button:focus {
    box-shadow: none;
    border-color: var(--shop-line);
}

/* --- browsing: filter rail beside the grid --------------------------------- */

.shop-browse {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.5rem;
}

@media (min-width: 992px) {
    .shop-browse {
        grid-template-columns: 232px minmax(0, 1fr);
        gap: 2.5rem;
        align-items: start;
    }

    .shop-browse__rail {
        position: sticky;
        top: calc(var(--shop-header-height) + 1rem);
    }
}

.shop-filters__head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding-bottom: .6rem;
    border-bottom: 1px solid var(--shop-line);
    margin-bottom: .9rem;
}

.shop-filters__group {
    padding-bottom: 1rem;
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--shop-line);
}

.shop-filters__group:last-child {
    border-bottom: none;
}

.shop-filters__title {
    font-size: .74rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--shop-ink-soft);
    margin: 0 0 .5rem;
}

/* Links, not checkboxes. Every filter state is a real URL, so the thing that
   changes it should be something a browser can bookmark and go back from. */
.shop-filters__toggle {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .3rem 0;
    color: var(--shop-ink);
    text-decoration: none;
    font-size: .88rem;
}

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

.shop-filters__box {
    width: 15px;
    height: 15px;
    flex: 0 0 15px;
    border: 1px solid var(--shop-line);
    background: var(--shop-surface);
}

.shop-filters__toggle.is-on {
    color: var(--shop-wine-600);
    font-weight: 600;
}

.shop-filters__toggle.is-on .shop-filters__box {
    background: var(--shop-wine-600);
    border-color: var(--shop-wine-600);
    box-shadow: inset 0 0 0 2px var(--shop-surface);
}

.shop-filters__label {
    flex: 1;
    min-width: 0;
}

.shop-filters__count {
    font-size: .78rem;
    color: var(--shop-ink-soft);
    font-variant-numeric: tabular-nums;
}

/* --- basket and checkout -------------------------------------------------- */

.shop-lines {
    display: flex;
    flex-direction: column;
    border-top: 1px solid var(--shop-line);
}

.shop-line {
    display: grid;
    grid-template-columns: 84px minmax(0, 1fr) auto auto;
    gap: 1rem;
    align-items: start;
    padding: 1rem 0;
    border-bottom: 1px solid var(--shop-line);
}

/* A line that cannot be ordered is flagged, not hidden. A basket that quietly
   drops an item is how somebody receives half an order and blames the courier. */
.shop-line.is-problem {
    background: #fdf6f3;
    box-shadow: inset 3px 0 0 var(--shop-rose-500);
    padding-left: .75rem;
}

.shop-line__thumb {
    display: block;
    width: 84px;
    height: 84px;
    background: var(--shop-canvas);
    border: 1px solid var(--shop-line);
    overflow: hidden;
}

.shop-line__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.shop-line__initial {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    font-family: var(--shop-display);
    font-size: 1.6rem;
    color: var(--shop-rose-500);
    background: var(--shop-wine-100);
}

.shop-line__name {
    display: block;
    color: var(--shop-ink);
    text-decoration: none;
    font-size: .98rem;
    line-height: 1.35;
}

.shop-line__name:hover {
    color: var(--shop-wine-600);
}

.shop-line__money {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.shop-qty {
    width: 4.5rem;
    font-variant-numeric: tabular-nums;
}

.shop-summary {
    border: 1px solid var(--shop-line);
    background: var(--shop-surface);
    padding: 1.25rem;
    position: sticky;
    top: calc(var(--shop-header-height) + 1rem);
}

.shop-summary code {
    font-size: .9rem;
}

.shop-done__mark {
    width: 56px;
    height: 56px;
    margin: 0 auto 1.25rem;
    border-radius: 50%;
    background: var(--shop-wine-100);
    color: var(--shop-wine-600);
    font-size: 1.6rem;
    line-height: 56px;
}

/* --- footer --------------------------------------------------------------- */

.shop-footer {
    background: var(--shop-wine-900);
    color: #c9b6bd;
    margin-top: 4rem;
    padding: 3rem 0 2rem;
}

.shop-footer .shop-logo {
    display: inline-flex;
}

.shop-footer a {
    color: #c9b6bd;
    text-decoration: none;
}

.shop-footer a:hover {
    color: var(--shop-rose-400);
}

.shop-footer__title {
    color: #fff;
    font-size: .78rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    margin-bottom: .75rem;
}

@media (max-width: 767.98px) {
    .shop-line {
        grid-template-columns: 64px minmax(0, 1fr);
        row-gap: .5rem;
    }

    .shop-line__thumb { width: 64px; height: 64px; }

    .shop-line__qty,
    .shop-line__money {
        grid-column: 2;
        text-align: left;
    }

    .shop-summary {
        position: static;
    }
}

@media (max-width: 575.98px) {
    .shop-logo__type {
        font-size: 1.2rem;
    }

    .shop-logo img {
        width: 34px;
        height: 34px;
    }

    .shop-price--lead {
        font-size: 1.5rem;
    }

    .shop-section__title {
        font-size: 1.25rem;
    }
}

/* --- text pages -----------------------------------------------------------
   Delivery, returns, privacy, contact. Measured in characters rather than
   pixels: a line of prose stops being readable past about seventy-five of them,
   and that is true on every screen width. */

.shop-prose {
    max-width: 68ch;
}

.shop-prose h2 {
    font-family: var(--shop-display);
    font-size: 1.25rem;
    margin-top: 2rem;
    margin-bottom: .6rem;
}

.shop-prose p,
.shop-prose ul {
    margin-bottom: 1rem;
}

.shop-prose .lead {
    font-size: 1.05rem;
}

.shop-table {
    max-width: 32rem;
}

.shop-contact dt {
    font-size: .78rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--shop-ink-soft);
    margin-top: 1rem;
}

.shop-contact dd {
    margin-bottom: 0;
}

/* --- order tracking -------------------------------------------------------- */

.shop-track {
    border: 1px solid var(--shop-line);
    border-radius: .5rem;
    padding: 1.25rem;
    background: var(--shop-surface);
}

.shop-track__status {
    font-family: var(--shop-display);
    font-size: 1.5rem;
    color: var(--shop-wine-600);
    line-height: 1.2;
}

.shop-track__courier {
    background: var(--shop-canvas);
    border-radius: .375rem;
    padding: .75rem 1rem;
}

/* Five plain steps rather than a percentage bar. Nobody wants to be told their
   parcel is sixty per cent delivered; they want to know which of these has
   actually happened. */

.shop-steps {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: .25rem 0;
}

.shop-steps__item {
    flex: 1 1 0;
    min-width: 5.5rem;
    position: relative;
    padding-top: 1.5rem;
    text-align: center;
}

/* The connecting rule, drawn behind the dots rather than between them, so it
   does not need a separate element per gap. */
.shop-steps__item::before {
    content: "";
    position: absolute;
    top: .43rem;
    left: 0;
    right: 0;
    height: 2px;
    background: var(--shop-line);
}

.shop-steps__item:first-child::before { left: 50%; }
.shop-steps__item:last-child::before { right: 50%; }

.shop-steps__item.is-done::before {
    background: var(--shop-wine-600);
}

.shop-steps__dot {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 1rem;
    height: 1rem;
    border-radius: 999px;
    background: var(--shop-surface);
    border: 2px solid var(--shop-line);
}

.shop-steps__item.is-done .shop-steps__dot {
    background: var(--shop-wine-600);
    border-color: var(--shop-wine-600);
}

.shop-steps__label {
    font-size: .75rem;
    color: var(--shop-ink-soft);
    display: block;
    padding: 0 .25rem;
}

.shop-steps__item.is-done .shop-steps__label {
    color: var(--shop-ink);
}

.shop-track__form {
    background: var(--shop-canvas);
    border: 1px solid var(--shop-line);
    border-radius: .5rem;
    padding: 1.25rem;
}

/* Offers gets the rose colour so it reads as the one promotional entry in a row
   of neutral ones. One highlighted item is a signpost; three would be noise. */
.shop-nav__link--offer {
    color: var(--shop-rose-600);
}

.shop-nav__link--offer:hover,
.shop-nav__link--offer.is-active {
    color: var(--shop-rose-600);
    border-bottom-color: var(--shop-rose-600);
}

/* --- brand index ----------------------------------------------------------
   Columns that fill downwards, so A to Z reads down one column and continues
   in the next rather than snaking across the page. */

.shop-brandindex {
    columns: 4 200px;
    column-gap: 2rem;
}

.shop-brandindex__group {
    break-inside: avoid;
    margin-bottom: 1.5rem;
}

.shop-brandindex__letter {
    font-family: var(--shop-display);
    font-size: 1rem;
    color: var(--shop-wine-600);
    border-bottom: 1px solid var(--shop-line);
    padding-bottom: .25rem;
    margin-bottom: .5rem;
}

.shop-brandindex__count {
    font-size: .72rem;
    color: var(--shop-ink-soft);
    font-variant-numeric: tabular-nums;
    margin-left: .25rem;
}

/* --- home page banner ------------------------------------------------------
   One image, no rotation. The aspect ratio is declared rather than left to the
   file, so the browser reserves the right amount of space before the image
   arrives - without it the whole page jumps downwards when the banner loads,
   which is both unpleasant and a Core Web Vitals penalty. */

.shop-banner {
    position: relative;
    background: var(--shop-wine-100);
}

.shop-banner__link {
    display: block;
    text-decoration: none;
    color: inherit;
}

.shop-banner__image {
    display: block;
    width: 100%;
    aspect-ratio: 3 / 1;
    object-fit: cover;
}

@media (max-width: 767px) {
    .shop-banner__image {
        aspect-ratio: 4 / 3;
    }
}

/* The scrim exists only where there is text to make readable. A banner whose
   artwork already carries its own words gets no overlay at all, because
   darkening a picture to make room for text that is not there just makes the
   picture worse. */
.shop-banner__overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    background: linear-gradient(
        90deg,
        rgba(42, 7, 19, .72) 0%,
        rgba(42, 7, 19, .45) 45%,
        rgba(42, 7, 19, 0) 78%);
}

@media (max-width: 767px) {
    /* Bottom-up on a phone, where a left-to-right gradient would cover the
       middle of the picture rather than one edge of it. */
    .shop-banner__overlay {
        align-items: flex-end;
        padding-bottom: 1.25rem;
        background: linear-gradient(
            0deg,
            rgba(42, 7, 19, .78) 0%,
            rgba(42, 7, 19, .35) 45%,
            rgba(42, 7, 19, 0) 80%);
    }
}

.shop-banner__text {
    max-width: 34ch;
    color: #fff;
}

.shop-banner__headline {
    color: #fff;
    font-size: clamp(1.5rem, 4vw, 2.75rem);
    line-height: 1.15;
    margin-bottom: .5rem;
}

.shop-banner__sub {
    color: rgba(255, 255, 255, .88);
    font-size: clamp(.85rem, 1.6vw, 1.05rem);
    margin-bottom: .9rem;
}

.shop-banner__button {
    display: inline-block;
    padding: .5rem 1.4rem;
    border-radius: 999px;
    background: #fff;
    color: var(--shop-wine-700);
    font-size: .85rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    font-weight: 600;
}

.shop-banner__link:hover .shop-banner__button {
    background: var(--shop-rose-400);
    color: var(--shop-wine-900);
}

/* --- banner carousel ------------------------------------------------------
   Only present when there is more than one slide. A single banner renders as a
   plain image with none of this. */

.shop-banner .carousel-item {
    position: relative;
}

/* Bootstrap's default control icons are white chevrons on nothing, which
   disappear over a pale photograph. A soft disc behind them survives any
   artwork without covering it. */
.shop-banner .carousel-control-prev,
.shop-banner .carousel-control-next {
    width: 12%;
    opacity: 1;
}

.shop-banner .carousel-control-prev-icon,
.shop-banner .carousel-control-next-icon {
    width: 2.4rem;
    height: 2.4rem;
    padding: .7rem;
    border-radius: 999px;
    background-color: rgba(42, 7, 19, .45);
    background-size: 1rem 1rem;
}

.shop-banner .carousel-control-prev:hover .carousel-control-prev-icon,
.shop-banner .carousel-control-next:hover .carousel-control-next-icon {
    background-color: rgba(42, 7, 19, .75);
}

.shop-banner .carousel-indicators {
    margin-bottom: .6rem;
}

.shop-banner .carousel-indicators [data-bs-target] {
    width: .6rem;
    height: .6rem;
    border-radius: 999px;
    border: 0;
    background-color: rgba(255, 255, 255, .55);
    opacity: 1;
}

.shop-banner .carousel-indicators .active {
    background-color: #fff;
}

/* The pause control. Small and unobtrusive, but present: hover-to-pause does
   not exist on a phone, and moving content needs a way to be stopped. */
.shop-banner__pause {
    position: absolute;
    right: .6rem;
    bottom: .6rem;
    z-index: 3;
    width: 1.9rem;
    height: 1.9rem;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 999px;
    background: rgba(42, 7, 19, .45);
    color: #fff;
    font-size: .6rem;
    line-height: 1;
}

.shop-banner__pause:hover,
.shop-banner__pause:focus-visible {
    background: rgba(42, 7, 19, .8);
}

/* The glyph itself is swapped in script - the control should say what pressing
   it will do, not what state the thing is in. */
.shop-banner__pause.is-paused span {
    font-size: .7rem;
}

@media (max-width: 575px) {
    /* Arrows eat a fifth of a narrow screen and overlap the headline. Swipe
       and the dots do the same job there. */
    .shop-banner .carousel-control-prev,
    .shop-banner .carousel-control-next {
        display: none;
    }
}
