/* =========================================================================
   ShopGhor Two — storefront
   =========================================================================
   Bootstrap 5 does the grid and the utilities; everything with a personality
   lives here.

   The palette is not hard-coded: layouts/header.php prints the brand colours
   from Admin → Settings into these custom properties, so the shop owner can
   recolour the whole storefront without touching this file. The values below
   are the fallbacks used when a setting is empty.

   The rule that keeps the settings screen honest: every colour named here is
   one an owner can set, and every colour an owner can set is used here. The
   only exceptions are the two derived shades — --primary-deep, computed in
   PHP from the primary, and the star gold — because a colour that must stay
   related to another one is not a choice, it is arithmetic.
   ====================================================================== */

:root {
    color-scheme: light;

    --primary: #002b7f;
    --primary-deep: #001a4d;
    --accent: #ff5a00;

    /* Urgency. Deliberately NOT the accent: a discount badge and a "buy now"
       button mean different things, and using one colour for both makes the
       page shout evenly instead of pointing anywhere. */
    --deal: #e11d48;

    --ink: #0a1633;
    --body: #4a5568;
    --muted: #8792a8;
    --paper: #ffffff;
    --wash: #f4f6fb;
    --line: #e6eaf4;

    --star: #f5a524;

    --radius: 14px;
    --shadow: 0 1px 2px rgba(10, 22, 51, .04), 0 10px 30px rgba(10, 22, 51, .06);
    --shadow-lg: 0 20px 50px rgba(10, 22, 51, .12);

    --rail-gap: 1rem;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    background: var(--wash);
    color: var(--body);
    font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
    font-size: 15.5px;
    line-height: 1.7;
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

/* Titles get a face of their own. Sora is squarer and tighter than the body
   text, so a heading reads as a different kind of thing at a glance rather
   than as the same sentence set larger. */
h1,
h2,
h3,
h4,
.font-title {
    font-family: "Sora", "Inter", system-ui, sans-serif;
    color: var(--ink);
    font-weight: 700;
    line-height: 1.22;
    letter-spacing: -.02em;
    text-wrap: balance;
}

a {
    color: var(--primary);
    text-decoration: none;
}

a:hover {
    color: var(--accent);
}

img {
    max-width: 100%;
}

/* Prices and counts line up in columns. */
.num,
.price,
.price-old,
.badge-off,
.countdown__n {
    font-variant-numeric: tabular-nums;
}

.container-wide {
    max-width: 1320px;
    margin-inline: auto;
    padding-inline: 1rem;
}

:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* =========================================================================
   Header
   ====================================================================== */

.topline {
    background: var(--primary-deep);
    color: rgba(255, 255, 255, .82);
    font-size: .8rem;
    padding: .45rem 0;
}

.topline a {
    color: #fff;
}

.topline__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.topline__items {
    display: flex;
    gap: 1.35rem;
    flex-wrap: wrap;
}

.topline__items span {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}

.topline i {
    color: var(--accent);
}

.masthead {
    background: var(--primary);
    padding: .9rem 0;
    position: sticky;
    top: 0;
    z-index: 1030;
    box-shadow: 0 2px 20px rgba(0, 26, 77, .25);
}

.masthead__row {
    display: flex;
    align-items: center;
    gap: 1.25rem;
}

.brand {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex: 0 0 auto;
}

.brand img {
    height: 40px;
    width: auto;
}

.brand__text {
    color: #fff;
    font-family: "Sora", sans-serif;
    font-weight: 800;
    font-size: 1.35rem;
    letter-spacing: -.02em;
}

/* Search is the widest thing in the bar on purpose — on a shop with a few
   hundred products it converts better than any menu. */
.searchbox {
    flex: 1 1 auto;
    max-width: 620px;
    position: relative;
}

.searchbox input {
    width: 100%;
    border: 0;
    border-radius: 999px;
    padding: .7rem 3.2rem .7rem 1.25rem;
    font: inherit;
    font-size: .95rem;
    background: rgba(255, 255, 255, .14);
    color: #fff;
}

.searchbox input::placeholder {
    color: rgba(255, 255, 255, .6);
}

.searchbox input:focus {
    background: #fff;
    color: var(--ink);
    outline: none;
}

.searchbox input:focus::placeholder {
    color: var(--muted);
}

.searchbox button {
    position: absolute;
    inset-block: 4px;
    inset-inline-end: 4px;
    width: 44px;
    border: 0;
    border-radius: 999px;
    background: var(--accent);
    color: #fff;
    font-size: 1rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}

.searchbox button:hover {
    filter: brightness(1.08);
}

.head-actions {
    display: flex;
    align-items: center;
    gap: .35rem;
    margin-inline-start: auto;
}

.head-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .7rem;
    border-radius: 10px;
    color: #fff;
    font-size: .88rem;
    font-weight: 500;
    white-space: nowrap;
}

.head-btn:hover {
    background: rgba(255, 255, 255, .12);
    color: #fff;
}

.head-btn i {
    font-size: 1.15rem;
}

.head-btn__count {
    position: absolute;
    top: 1px;
    inset-inline-start: 22px;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    background: var(--accent);
    color: #fff;
    border-radius: 999px;
    font-size: .68rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* =========================================================================
   Main navigation
   =========================================================================
   Same bar as before — white, quiet, an accent underline on hover — with one
   item that opens. Categories drops a panel; a category with children flies
   its own list out to the side, and so does a sub-category, so three levels
   are reachable without a single click.

   The dropdown is CSS-first: :hover and :focus-within open it, which means it
   works before app.js has parsed and keeps working for a keyboard. The script
   only adds what CSS cannot do — tap on a touch screen, and telling assistive
   technology what is open.
   ====================================================================== */

.mainnav {
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    position: relative;
    z-index: 1020;
}

.mainnav__row {
    display: flex;
    align-items: stretch;
    gap: .25rem;
}

.mainnav__link {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .85rem .95rem;
    color: var(--ink);
    font-weight: 500;
    font-size: .93rem;
    white-space: nowrap;
    /* Transparent, and kept: it reserves the three pixels the rule will need,
       so nothing below the nav moves when one appears. */
    border-bottom: 3px solid transparent;
    transition: color .18s ease;
}

/**
 * The underline is drawn, not switched on.
 *
 * It sits over the transparent border rather than replacing it, so the row
 * keeps its exact height either way.
 *
 * Growing from the left on the way in and leaving to the right on the way out
 * is one line of difference and reads as the pointer pushing it along, rather
 * than as a bar that inflates and deflates in place.
 *
 * The colour is named, not currentColor. currentColor looks tidier and was
 * wrong: the link is fading from --ink to --accent at the same moment, so the
 * bar inherited that half-done colour and every hover began with a black stub
 * sliding out from under the word before it caught up. A fixed accent has no
 * in-between state to show.
 */
.mainnav__link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -3px;
    height: 3px;
    background: var(--accent);
    transform: scaleX(0);
    transform-origin: right center;
    transition: transform .24s cubic-bezier(.4, 0, .2, 1);
}

.mainnav__link:hover,
.mainnav__link:focus-visible {
    color: var(--accent);
}

.mainnav__link:hover::after,
.mainnav__link:focus-visible::after {
    transform: scaleX(1);
    transform-origin: left center;
}

/**
 * The icons.
 *
 * Every item has one in the markup, because the bottom bar on a phone needs
 * five of them. Up here only the two that always had one show it: Categories,
 * where the grid says "this opens", and Offer, where the flame is the whole
 * point. Icons on About and Contact would be decoration — the words are
 * already short enough to read at a glance.
 */
.mainnav__link .mainnav__ico {
    display: none;
}

.navdrop__trigger .mainnav__ico,
.mainnav__link.is-hot .mainnav__ico {
    display: inline-flex;
}

.mainnav__link.is-hot {
    color: var(--deal);
    font-weight: 600;
}

/* The hot link keeps its own colour on hover instead of turning accent,
   and its underline matches it. */
.mainnav__link.is-hot::after {
    background: var(--deal);
}

.mainnav__link.is-hot:hover,
.mainnav__link.is-hot:focus-visible {
    color: var(--deal);
}

/* Someone who has asked for less movement gets the underline, not the sweep. */
@media (prefers-reduced-motion: reduce) {
    .mainnav__link::after {
        transition: none;
    }
}

.navdrop {
    position: relative;
    display: flex;
}

.navdrop__caret {
    font-size: .7rem;
    transition: transform .18s ease;
}

.navdrop:hover .navdrop__caret,
.navdrop.is-open .navdrop__caret {
    transform: rotate(180deg);
}

.navdrop__trigger {
    position: relative;
}

/* Colour only. The rule under it is the ::after above, which slides in like
   every other item — setting border-bottom-color here as well drew a second,
   instant, full-width bar underneath the animated one, so Categories flashed a
   line the other four never did. */
.navdrop:hover>.navdrop__trigger,
.navdrop.is-open>.navdrop__trigger {
    color: var(--accent);
}

/* The trigger is a .mainnav__link, but the pointer is over .navdrop — its own
   :hover has already ended by the time the cursor is in the open menu. Driving
   the bar from the parent keeps it lit for as long as the menu is. */
.navdrop:hover>.navdrop__trigger::after,
.navdrop.is-open>.navdrop__trigger::after {
    transform: scaleX(1);
    transform-origin: left center;
}

/* Every level of the menu is the same panel. */
.navdrop__menu,
.navdrop__sub {
    list-style: none;
    margin: 0;
    padding: .4rem;
    min-width: 232px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: var(--shadow-lg);

    position: absolute;
    z-index: 40;

    /* Closed, but still laid out — a panel with display:none has no size, and
       a sub-menu that has never had a size cannot be positioned correctly the
       first time it opens. */
    opacity: 0;
    visibility: hidden;
    transform: translateY(6px);
    transition: opacity .16s ease, transform .16s ease, visibility 0s linear .16s;
}

.navdrop__menu {
    top: 100%;
    inset-inline-start: 0;
    margin-top: -1px;
}

/* Children hang beside their parent, overlapping by the panel's own padding
   so the mouse never crosses a gap on the way out. */
.navdrop__sub {
    top: -.4rem;
    inset-inline-start: 100%;
    margin-inline-start: -.25rem;
}

.navdrop:hover>.navdrop__menu,
.navdrop:focus-within>.navdrop__menu,
.navdrop.is-open>.navdrop__menu,
.navdrop__item:hover>.navdrop__sub,
.navdrop__item:focus-within>.navdrop__sub,
.navdrop__item.is-open>.navdrop__sub {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
}

.navdrop__item {
    position: relative;
}

.navdrop__item>a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    padding: .5rem .7rem;
    border-radius: 8px;
    color: var(--ink);
    font-size: .9rem;
    font-weight: 500;
    line-height: 1.4;
}

.navdrop__item>a:hover,
.navdrop__item>a:focus-visible,
.navdrop__item.is-open>a {
    background: var(--wash);
    color: var(--primary);
}

.navdrop__arrow {
    font-size: .68rem;
    color: var(--muted);
    flex: 0 0 auto;
}

.navdrop__item>a:hover .navdrop__arrow {
    color: var(--primary);
}

/* A branch near the right edge would otherwise open off-screen; app.js adds
   this class after measuring, so it flips to the other side instead. */
.navdrop__item.flip-left>.navdrop__sub {
    inset-inline-start: auto;
    inset-inline-end: 100%;
    margin-inline: 0 -.25rem;
}

/* =========================================================================
   The bar on a phone
   =========================================================================
   Same five items, same order, same category tree — moved to the bottom of
   the screen, where the thumb already is. Nothing about the markup changes;
   only this block does.

   It sits below 992px because that is where the row stopped fitting across
   the top and began scrolling sideways, which hid Contact and Offer behind a
   gesture nobody knew to make.

   Categories opens upward from it as a sheet, because a menu that drops down
   from a bar at the bottom of the screen has nowhere to go.
   ====================================================================== */

@media (max-width: 991.98px) {

    :root {
        /* One number, used by the bar's height and by the padding that keeps
           the footer clear of it. They cannot drift apart. */
        --botnav-h: 3.5rem;
    }

    /* The page ends above the bar rather than behind it. Without this the
       footer's last line sits under the nav and cannot be read or tapped. */
    body {
        padding-bottom: calc(var(--botnav-h) + env(safe-area-inset-bottom, 0px));
    }

    .mainnav {
        position: fixed;
        inset: auto 0 0 0;
        z-index: 1040;
        border-top: 1px solid var(--line);
        border-bottom: 0;
        box-shadow: 0 -6px 24px rgba(10, 22, 51, .10);
        /* The home-indicator strip on a modern phone. Padding, not height, so
           the touch targets stay where the thumb expects them. */
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }

    .mainnav__row {
        gap: 0;
        padding-inline: .25rem;
        height: var(--botnav-h);
    }

    /* Five equal columns. A thumb should not have to aim. */
    .navdrop,
    .mainnav__link {
        flex: 1 1 0;
        min-width: 0;
    }

    .mainnav__link {
        flex-direction: column;
        justify-content: center;
        gap: .18rem;
        padding: .3rem .15rem;
        font-size: .66rem;
        font-weight: 500;
        line-height: 1.15;
        text-align: center;
        border-bottom: 0;
        /* "All Products" is the long one; it wraps rather than being clipped
           or pushing the other four narrower. */
        white-space: normal;
    }

    .mainnav__link .mainnav__ico {
        display: block;
        font-size: 1.2rem;
        line-height: 1;
    }

    /* The sweeping underline belongs to a horizontal bar being hovered. There
       is no hover here, and a rule under a stacked icon reads as a mistake. */
    .mainnav__link::after {
        display: none;
    }

    /* The caret would be a third thing stacked under a two-line label. */
    .navdrop__caret {
        display: none;
    }

    .navdrop.is-open>.navdrop__trigger {
        color: var(--accent);
    }

    /* Everything behind the open sheet goes quiet, so the categories read as
       a layer rather than as text among text. It stops at the bar: the bar is
       still live, and dimming it would say otherwise. */
    .navdrop.is-open::before {
        content: "";
        position: fixed;
        inset: 0 0 calc(var(--botnav-h) + env(safe-area-inset-bottom, 0px)) 0;
        background: rgba(10, 22, 51, .38);
        z-index: -1;
    }

    .navdrop {
        position: static;
    }

    /* Opens upward, out of the bar, full width less a hair either side. */
    .navdrop__menu {
        top: auto;
        bottom: 100%;
        inset-inline: .5rem;
        width: auto;
        min-width: 0;
        margin: 0 0 .5rem;
        max-height: min(62vh, 420px);
        overflow-y: auto;
        overscroll-behavior: contain;
        transform: translateY(8px);
        box-shadow: 0 -10px 40px rgba(10, 22, 51, .22);
    }

    /* Room for a finger, not a mouse pointer. */
    .navdrop__item>a {
        padding: .7rem .8rem;
        font-size: .95rem;
    }

    .navdrop__sub {
        position: static;
        opacity: 1;
        visibility: visible;
        transform: none;
        border: 0;
        box-shadow: none;
        border-radius: 0;
        margin: 0;
        padding: 0 0 .25rem .9rem;
        border-inline-start: 2px solid var(--line);
        display: none;
    }

    .navdrop__item.is-open>.navdrop__sub {
        display: block;
    }

    /* Hover means nothing on a touch screen; only the tapped class opens. */
    .navdrop__item:hover>.navdrop__sub,
    .navdrop__item:focus-within>.navdrop__sub {
        display: none;
    }

    .navdrop__item.is-open>.navdrop__sub {
        display: block;
    }

    .navdrop__item.is-open>a .navdrop__arrow {
        transform: rotate(90deg);
    }
}

/* =========================================================================
   Hero
   ====================================================================== */

.hero {
    position: relative;
    background: var(--primary-deep);
}

.hero__slide {
    position: relative;
    min-height: 480px;
    display: flex;
    align-items: center;
}

.hero__img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.hero__scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg, rgba(0, 20, 60, .94) 0%, rgba(0, 26, 77, .78) 42%, rgba(0, 26, 77, .18) 78%);
}

.hero__body {
    position: relative;
    padding: 3.5rem 0;
    max-width: 620px;
}

/* The line above the title.
   Not a badge — a badge is a pill you stick on something, and three of them
   on a page start reading as decoration. This is a masthead rule instead: a
   solid accent bar, the words set small and wide beside it, and a hairline
   that runs off toward the edge of the slide. It points along the line the
   eye is already travelling rather than boxing a word in. */
.hero__eyebrow {
    display: flex;
    align-items: center;
    gap: .7rem;
    margin-bottom: 1.15rem;
    color: #fff;
}

.hero__eyebrow-bar {
    width: 4px;
    height: 26px;
    flex: 0 0 4px;
    border-radius: 2px;
    background: var(--accent);
    box-shadow: 0 0 18px rgba(255, 90, 0, .55);
}

.hero__eyebrow-text {
    font-family: "Sora", sans-serif;
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .26em;
    text-transform: uppercase;
    line-height: 1;
}

.hero__eyebrow-rule {
    flex: 1 1 auto;
    max-width: 130px;
    height: 1px;
    background: linear-gradient(90deg, rgba(255, 255, 255, .55), rgba(255, 255, 255, 0));
}

.hero__title {
    color: #fff;
    font-size: clamp(1.9rem, 4.6vw, 3.25rem);
    margin: 0 0 .8rem;
}

.hero__text {
    color: rgba(255, 255, 255, .85);
    font-size: 1.05rem;
    margin: 0 0 1.75rem;
    max-width: 34rem;
}

.btn-accent,
.btn-ghost {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    padding: .8rem 1.9rem;
    border-radius: 999px;
    font-weight: 600;
    font-size: .98rem;
    border: 2px solid transparent;
    cursor: pointer;
    transition: transform .15s ease, box-shadow .15s ease, background .15s ease;
}

.btn-accent {
    background: var(--accent);
    color: #fff;
    box-shadow: 0 10px 26px rgba(255, 90, 0, .32);
}

.btn-accent:hover {
    color: #fff;
    transform: translateY(-2px);
    box-shadow: 0 14px 32px rgba(255, 90, 0, .42);
}

.btn-ghost {
    border-color: rgba(255, 255, 255, .5);
    color: #fff;
}

.btn-ghost:hover {
    background: #fff;
    color: var(--primary);
    border-color: #fff;
}

.hero .carousel-indicators {
    margin-bottom: 1.25rem;
}

.hero .carousel-indicators [data-bs-target] {
    width: 28px;
    height: 4px;
    border-radius: 999px;
    border: 0;
    background: rgba(255, 255, 255, .45);
    opacity: 1;
}

.hero .carousel-indicators .active {
    background: var(--accent);
    width: 44px;
}

.hero .carousel-control-prev,
.hero .carousel-control-next {
    width: 6%;
    opacity: .55;
}

.hero .carousel-control-prev:hover,
.hero .carousel-control-next:hover {
    opacity: 1;
}

/* =========================================================================
   Trust strip — directly under the hero, where the doubt is
   ====================================================================== */

.trust {
    background: var(--paper);
    border-bottom: 1px solid var(--line);
}

.trust__grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1px;
    background: var(--line);
}

.trust__item {
    background: var(--paper);
    display: flex;
    align-items: center;
    gap: .85rem;
    padding: 1.15rem 1.1rem;
}

.trust__icon {
    width: 42px;
    height: 42px;
    flex: 0 0 42px;
    border-radius: 12px;
    display: grid;
    place-items: center;
    /* A tint of the brand colour, with the neutral wash first for browsers
       that do not know color-mix — a missing background is worse than a
       slightly duller one. */
    background: var(--wash);
    background: color-mix(in srgb, var(--primary) 8%, transparent);
    color: var(--primary);
    font-size: 1.25rem;
}

.trust__t {
    font-weight: 600;
    color: var(--ink);
    font-size: .92rem;
    line-height: 1.35;
}

.trust__s {
    font-size: .8rem;
    color: var(--muted);
    line-height: 1.4;
}

/* =========================================================================
   Section furniture
   ====================================================================== */

.section {
    padding: 3.25rem 0;
}

.sec-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
    flex-wrap: wrap;
}

.sec-head__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    font-size: .76rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: .35rem;
}

.sec-head h2 {
    font-size: clamp(1.35rem, 2.6vw, 1.8rem);
    margin: 0;
}

.sec-head__sub {
    color: var(--muted);
    font-size: .92rem;
    margin: .2rem 0 0;
}

.sec-head__link {
    font-weight: 600;
    font-size: .92rem;
    white-space: nowrap;
}

/* Clock and link together on the right of a section heading. They wrap onto
   their own line before the heading has to give up any width. */
.sec-head__aside {
    display: flex;
    align-items: center;
    gap: .9rem;
    flex-wrap: wrap;
}

/**
 * The deadline on a product strip.
 *
 * No pill, no plate, no rule — one line of text beside the heading. A badge is
 * a thing stuck onto a page, and a page that stitches one onto every urgent
 * item ends up shouting evenly, which is the same as not pointing anywhere.
 *
 * The label and the unit letters are support and read like it; the figures are
 * the only thing here at full strength, and tabular so the line does not
 * twitch as the seconds roll.
 */
.sec-clock {
    display: inline-flex;
    align-items: baseline;
    gap: .45rem;
    color: var(--deal);
    font-size: .95rem;
    line-height: 1;
    white-space: nowrap;
}

.sec-clock__label {
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    opacity: .8;
}

.sec-clock__cell {
    display: inline-flex;
    align-items: baseline;
    gap: .06rem;
}

.sec-clock__cell b {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
}

/* The unit letters are a label, not a reading — quieter than the figure. */
.sec-clock__cell>span {
    font-size: .7rem;
    font-weight: 500;
    opacity: .7;
}



/* =========================================================================
   The rail — one component, four questions
   =========================================================================
   Horizontal scroll with snap, arrows that page through it, and drag on a
   mouse. The arrows hide themselves when everything already fits, because an
   arrow that does nothing when clicked is worse than no arrow at all.
   ====================================================================== */

.rail-wrap {
    position: relative;
}

.rail {
    display: flex;
    gap: var(--rail-gap);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    overscroll-behavior-x: contain;
    /* The inline padding keeps a card's hover shadow from being clipped at the
       edges; the negative margin puts the row back in line with the heading
       above it. */
    padding: .35rem .25rem 1.1rem;
    margin-inline: -.25rem;

    /* Match that padding, or the first card snaps to 4px instead of 0 — the
       strip then never quite returns to its start and the "back" arrow stays
       lit when there is nothing left to go back to. */
    scroll-padding-inline-start: .25rem;

    scrollbar-width: none;
    -ms-overflow-style: none;
}

.rail::-webkit-scrollbar {
    display: none;
}

.rail>* {
    scroll-snap-align: start;
    flex: 0 0 auto;
}

/**
 * How many cards a rail shows, and why they are not a fixed width.
 *
 * They used to be: 235px each, however wide the window was. Five of those plus
 * their gaps come to 1239px inside a 1288px strip, so the sixth card started
 * and then ran off the edge — a permanent half-product sliced down the middle,
 * which reads as a rendering fault rather than as "there is more this way".
 * The arrows already say there is more.
 *
 * So the count is the fixed thing now and the width is worked out from it: the
 * strip is divided by the number of cards wanted at this size, minus the gaps
 * between them. Whatever the window does, a whole number of cards fills it and
 * nothing is ever cut in half.
 *
 * --rail-cards is the only thing a breakpoint has to change. Nothing else in
 * this file needs to know the arithmetic.
 */
.rail {
    --rail-cards: 5;
}

.rail>.p-card,
.rail>.cat-card {
    width: calc(
        (100% - (var(--rail-cards) - 1) * var(--rail-gap)) / var(--rail-cards)
    );
}

/* Four is the most a laptop fits before the cards get too narrow to read a
   product name in two lines; below that it steps down one at a time. */
@media (max-width: 1199.98px) { .rail { --rail-cards: 4; } }
@media (max-width: 991.98px)  { .rail { --rail-cards: 3; } }
@media (max-width: 767.98px)  { .rail { --rail-cards: 2; } }

.rail-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 1px solid var(--line);
    background: var(--paper);
    color: var(--primary);
    display: none;
    align-items: center;
    justify-content: center;
    font-size: 1.15rem;
    cursor: pointer;
    z-index: 3;
    box-shadow: var(--shadow);
    transition: background .15s ease, color .15s ease, opacity .15s ease;
}

.rail-wrap.is-scrollable .rail-nav {
    display: flex;
}

.rail-nav:hover:not(:disabled) {
    background: var(--primary);
    color: #fff;
    border-color: var(--primary);
}

.rail-nav:disabled {
    opacity: .3;
    cursor: default;
}

.rail-nav--prev {
    inset-inline-start: -18px;
}

.rail-nav--next {
    inset-inline-end: -18px;
}

/**
 * …but only while there is somewhere to hang.
 *
 * The strip lives inside .container-wide, which stops growing at 1320px. Wider
 * than that and there is a margin either side for an arrow to sit in. Narrower
 * and the container is the screen, so -18px puts half the "next" arrow past
 * the right edge — clipped by the overflow guard on <body>, which is to say
 * invisible on exactly the laptop widths where it is the only way to page the
 * strip. Below that width they tuck inside and overlap the end card instead.
 */
@media (max-width: 1367.98px) {
    .rail-nav--prev {
        inset-inline-start: 2px;
    }

    .rail-nav--next {
        inset-inline-end: 2px;
    }
}

@media (max-width: 991.98px) {

    /* The arrows stay on a touch screen.
       -------------------------------------------------------------------
       They used to be hidden here, on the reasoning that a finger is the
       control. That is true of a flick, but a flick is momentum scrolling —
       it lands wherever it lands, so the strip never animates cleanly from
       one card to the next and there is nothing on screen saying it moves at
       all. A tappable arrow gives both: a visible affordance, and a smooth
       scroll of exactly one page.

       Smaller than the desktop pair and tucked to the very edge, so they
       clip the end cards as little as possible. */
    .rail-nav {
        width: 36px;
        height: 36px;
        font-size: 1rem;
        box-shadow: 0 2px 10px rgba(10, 22, 51, .18);
    }

    .rail-nav--prev { inset-inline-start: -2px; }
    .rail-nav--next { inset-inline-end: -2px; }
}

/* =========================================================================
   Category card — a destination, not a filter
   ====================================================================== */

.cat-card {
    width: 210px;
    height: 270px;
    position: relative;
    border-radius: var(--radius);
    overflow: hidden;
    display: block;
    background: var(--primary-deep);
    box-shadow: var(--shadow);
}

.cat-card img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .5s cubic-bezier(.2, .7, .3, 1);
}

.cat-card:hover img {
    transform: scale(1.07);
}

.cat-card__veil {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(0, 20, 60, .9) 8%, rgba(0, 20, 60, .25) 45%, rgba(0, 20, 60, 0) 70%);
}

.cat-card__label {
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    padding: 1rem;
    color: #fff;
}

.cat-card__name {
    font-family: "Sora", sans-serif;
    font-weight: 700;
    font-size: 1rem;
    line-height: 1.3;
    letter-spacing: -.01em;
}

.cat-card__count {
    font-size: .78rem;
    color: rgba(255, 255, 255, .75);
}

.cat-card__go {
    margin-top: .5rem;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    font-size: .8rem;
    font-weight: 600;
    color: #fff;
    opacity: 0;
    transform: translateX(-6px);
    transition: opacity .25s ease, transform .25s ease;
}

.cat-card:hover .cat-card__go {
    opacity: 1;
    transform: none;
}

/* =========================================================================
   Product card
   ====================================================================== */

.p-card {
    width: 235px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}

.p-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow-lg);
    border-color: transparent;
}

.p-card__media {
    position: relative;
    display: block;
    background: var(--wash);
}

.p-card__media img {
    width: 100%;
    aspect-ratio: 1/1;
    object-fit: cover;
    display: block;
}

.badge-off,
.badge-new,
.badge-out {
    position: absolute;
    top: .6rem;
    inset-inline-start: .6rem;
    padding: .22rem .55rem;
    border-radius: 7px;
    font-size: .72rem;
    font-weight: 700;
    color: #fff;
}

.badge-off {
    background: var(--deal);
}

.badge-new {
    background: var(--primary);
}

.badge-out {
    inset-inline-start: auto;
    inset-inline-end: .6rem;
    background: rgba(10, 22, 51, .78);
}


.p-card__body {
    padding: .85rem .9rem 1rem;
    display: flex;
    flex-direction: column;
    flex: 1;
}

.p-card__cat {
    font-size: .74rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: .05em;
}

.p-card__name {
    font-weight: 600;
    color: var(--ink);
    font-size: .92rem;
    line-height: 1.45;
    margin: .15rem 0 .4rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: 2.7em;
}

.p-card__name:hover {
    color: var(--accent);
}

.p-card__stars {
    color: var(--star);
    font-size: .78rem;
    margin-bottom: .5rem;
}

.p-card__stars span {
    color: var(--muted);
    margin-inline-start: .25rem;
}

.p-card__prices {
    display: flex;
    align-items: baseline;
    gap: .45rem;
    flex-wrap: wrap;
    margin-top: auto;
}

.price {
    font-size: 1.08rem;
    font-weight: 700;
    color: var(--primary);
}

.price-old {
    font-size: .85rem;
    color: var(--muted);
    text-decoration: line-through;
}

/* The buy button, and it looks the same in every section.
   Filled with the brand colour rather than outlined, because on a card it is
   the one thing to press, not an option among several — and it keeps that
   colour on hover. Only the shadow answers the pointer, so nothing shifts or
   restates itself under the cursor.

   One rule for every rail and the grid. When Hot deals had a button of its
   own, "the buy button" meant two different things on one page, and a shopper
   scanning downward had to re-learn it halfway. */
.p-card__buy {
    margin-top: .7rem;
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    padding: .55rem .8rem;
    border-radius: 9px;
    border: 1px solid var(--primary);
    background: var(--primary);
    color: #fff;
    font: inherit;
    font-size: .87rem;
    font-weight: 600;
    cursor: pointer;

    /* Never two lines. On a 360px phone the card is 149px wide, and "Add to
       cart" plus its icon did not fit across it — so the label wrapped and
       that one button stood 67px tall next to 43px neighbours, which is what
       made a row of cards look broken rather than tight. The label shortens
       below instead of folding. */
    white-space: nowrap;
    min-width: 0;

    transition: box-shadow .15s ease, filter .15s ease;
}

.p-card__buy:hover {
    background: var(--primary);
    color: #fff;
    border-color: var(--primary);
    box-shadow: 0 6px 18px rgba(10, 22, 51, .28);
    box-shadow: 0 6px 18px color-mix(in srgb, var(--primary) 35%, transparent);
}

.p-card__buy[disabled] {
    border-color: var(--line);
    background: var(--wash);
    color: var(--muted);
    cursor: not-allowed;
    box-shadow: none;
}


/* =========================================================================
   Promotional band
   ====================================================================== */

.promo {
    position: relative;
    overflow: hidden;
    background: var(--primary-deep);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
}

.promo__img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: .38;
}

.promo__body {
    position: relative;
    padding: clamp(2rem, 5vw, 3.5rem);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 2rem;
    flex-wrap: wrap;
}

.promo__kicker {
    color: var(--accent);
    font-weight: 700;
    font-size: .8rem;
    letter-spacing: .14em;
    text-transform: uppercase;
}

.promo h2 {
    color: #fff;
    font-size: clamp(1.5rem, 3.4vw, 2.35rem);
    margin: .35rem 0 .5rem;
}

.promo p {
    color: rgba(255, 255, 255, .82);
    margin: 0;
    max-width: 34rem;
}

.countdown {
    display: flex;
    gap: .55rem;
    margin-top: 1.25rem;
}

.countdown__cell {
    background: rgba(255, 255, 255, .1);
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: 10px;
    padding: .5rem .75rem;
    text-align: center;
    min-width: 62px;
}

.countdown__n {
    display: block;
    color: #fff;
    font-family: "Sora", sans-serif;
    font-weight: 700;
    font-size: 1.3rem;
    line-height: 1.15;
}

.countdown__l {
    font-size: .66rem;
    color: rgba(255, 255, 255, .6);
    text-transform: uppercase;
    letter-spacing: .08em;
}

/* =========================================================================
   Why choose us
   ====================================================================== */

.why {
    background: var(--paper);
}

.why__card {
    height: 100%;
    background: var(--wash);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1.6rem 1.35rem;
    transition: transform .18s ease, box-shadow .18s ease, background .18s ease;
}

.why__card:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow);
    background: var(--paper);
}

.why__icon {
    width: 52px;
    height: 52px;
    border-radius: 14px;
    display: grid;
    place-items: center;
    font-size: 1.45rem;
    background: var(--primary);
    color: #fff;
    margin-bottom: 1rem;
}

.why__card--alt .why__icon {
    background: var(--accent);
}

.why__card h3 {
    font-size: 1.02rem;
    margin: 0 0 .4rem;
}

.why__card p {
    margin: 0;
    font-size: .9rem;
    color: var(--body);
}

/* =========================================================================
   Footer
   =========================================================================
   Five columns on a laptop, and they are deliberately not equal: the brand
   paragraph and the contact block are prose, the three in between are link
   lists. The old layout gave all four right-hand columns a sixth of the page
   each, which is why the address needed overflow-wrap to rescue it — a column
   too narrow for its content, propped up rather than widened.

   Every colour is a custom property that layouts/header.php derives from the
   shop's own primary and then *measures* — see hex_readable_plate(). Nothing
   below hard-codes a colour, so the contrast survives whatever palette the
   owner picks.
   ====================================================================== */

.foot {
    background: var(--foot-bg, #002b7f);
    color: var(--foot-fg, rgba(255, 255, 255, .82));
}

.foot__top {
    padding: 3.5rem 0 2.75rem;
}

/* The brand and contact columns get prose widths; the three link lists get
   only what a link needs. auto-fit is not used on purpose — these five
   columns have five different jobs and a symmetrical grid hides that. */
.foot__grid {
    display: grid;
    grid-template-columns:
        minmax(15rem, 1.7fr)
        repeat(3, minmax(7.5rem, .85fr))
        minmax(13rem, 1.25fr);
    gap: 2.5rem 2rem;
}

.foot h2 {
    color: var(--foot-strong, #fff);
    font-size: .78rem;
    margin: 0 0 1.15rem;
    font-family: "Sora", sans-serif;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
}

.foot a {
    color: var(--foot-fg, rgba(255, 255, 255, .82));
    font-size: .9rem;
    text-decoration: none;
    transition: color .14s ease;
}

/* Hover goes to full white rather than to the accent. The accent is a brand
   colour with no promise of contrast; white always has one, and on a plate
   built to hold white it is the strongest signal available. */
.foot a:hover,
.foot a:focus-visible {
    color: var(--foot-strong, #fff);
}

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

.foot__col li {
    margin-bottom: .6rem;
}

.foot__col li:last-child {
    margin-bottom: 0;
}

/**
 * The column links get the main navigation's underline, drawn the same way
 * and in the same direction — @see .mainnav__link::after. Two menus on one
 * page that answer a hover differently read as two different sites.
 *
 * Scoped to the plain link lists. The contact rows are labelled blocks, the
 * social buttons and payment pills are boxes that already respond by filling
 * in, and a rule sliding under any of them would be noise rather than an echo.
 */
.foot__col:not(.foot__col--contact) a {
    position: relative;
    display: inline-block;
}

.foot__col:not(.foot__col--contact) a::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -2px;
    height: 2px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: right center;
    transition: transform .24s cubic-bezier(.4, 0, .2, 1);
}

.foot__col:not(.foot__col--contact) a:hover::after,
.foot__col:not(.foot__col--contact) a:focus-visible::after {
    transform: scaleX(1);
    transform-origin: left center;
}

/* --- the brand column --- */

.foot__brand {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin-bottom: 1.1rem;
}

.foot__brand img {
    height: 38px;
}

.foot__brand span {
    color: var(--foot-strong, #fff);
    font-family: "Sora", sans-serif;
    font-weight: 800;
    font-size: 1.25rem;
    letter-spacing: -.02em;
}

.foot__about {
    margin: 0;
    max-width: 24rem;
    font-size: .9rem;
    line-height: 1.7;
}

.foot__social {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: 1.5rem;
}

.foot__social a {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    background: var(--foot-chip, rgba(255, 255, 255, .12));
    border: 1px solid var(--foot-line, rgba(255, 255, 255, .16));
    color: var(--foot-strong, #fff);
    display: grid;
    place-items: center;
    font-size: 1rem;
    transition: background .14s ease, border-color .14s ease, transform .14s ease;
}

.foot__social a:hover,
.foot__social a:focus-visible {
    background: var(--foot-accent, #ff5a00);
    border-color: var(--foot-accent, #ff5a00);
    color: var(--foot-bg, #002b7f);
    transform: translateY(-2px);
}

/* --- the contact column --- */

.foot__contact li {
    display: flex;
    gap: .7rem;
    align-items: flex-start;
    margin-bottom: 1.05rem;
}

.foot__contact li:last-child {
    margin-bottom: 0;
}

/* A tile rather than a bare glyph: three icons floating beside three lines of
   text read as a list of symbols, three tiles read as three ways in. */
.foot__contact-icon {
    display: grid;
    place-items: center;
    flex: none;
    width: 2rem;
    height: 2rem;
    border-radius: 8px;
    background: var(--foot-chip, rgba(255, 255, 255, .12));
    border: 1px solid var(--foot-line, rgba(255, 255, 255, .16));
    color: var(--foot-accent, #ff5a00);
    font-size: .88rem;
}

.foot__contact-body {
    display: flex;
    flex-direction: column;
    gap: .1rem;
    /* An address or an email is one unbroken word to a browser. The column is
       wide enough now that this only ever catches a genuinely long one. */
    min-width: 0;
    overflow-wrap: anywhere;
}

.foot__contact-body small {
    font-size: .72rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--foot-fg, rgba(255, 255, 255, .82));
    opacity: .65;
}

/* The number and the address are the two lines that decide whether a
   first-time visitor believes there is a shop behind the site, so the value
   gets the strong ink and the label stays quiet above it. */
.foot__contact-body>a,
.foot__contact-body>span {
    color: var(--foot-strong, #fff);
    font-size: .92rem;
    line-height: 1.5;
}

.foot__contact-body>a:hover,
.foot__contact-body>a:focus-visible {
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* --- the closing line --- */

.foot__bar {
    border-top: 1px solid var(--foot-line, rgba(255, 255, 255, .16));
    background: var(--foot-bg-2, rgba(0, 0, 0, .22));
}

/* Copyright at one end, credit at the other, the payment badges centred
   between them — so the row is three things that belong together rather than
   a caption with a gap after it. */
.foot__bar-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: .85rem 1.5rem;
    padding-block: 1.15rem;
    font-size: .85rem;

    /* The back-to-top button is fixed to the bottom-right corner at every
       width, so at the very end of the page it lands on whatever this row
       ends with — the credit on a laptop, the last payment badge on a phone.
       Reserving its footprint here is the only fix that does not require the
       button to know where the footer is: 48px of button, its own offset, and
       a gap. It overrides .container-wide's 1rem on this side only. */
    padding-right: 5rem;
}

.foot__copy,
.foot__credit {
    margin: 0;
}

/* Nothing to add: the row's own padding keeps this clear of the button. */

.foot__pay {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    /* Takes the slack so the two text ends stay pinned to the edges. */
    margin-inline: auto;
}

.foot__pay li {
    background: var(--foot-chip, rgba(255, 255, 255, .12));
    border: 1px solid var(--foot-line, rgba(255, 255, 255, .16));
    border-radius: 7px;
    padding: .28rem .65rem;
    font-size: .76rem;
    color: var(--foot-strong, #fff);
    white-space: nowrap;
}

/* --- narrower --- */

@media (max-width: 991.98px) {

    /* The brand paragraph runs the full width and the four columns pair up
       beneath it. Squeezing five columns into a tablet gives five columns too
       narrow to read rather than a smaller version of the same thing. */
    .foot__grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .foot__brand-col {
        grid-column: 1 / -1;
    }

    .foot__about {
        max-width: 34rem;
    }
}

@media (max-width: 575.98px) {
    .foot__top {
        padding: 2.5rem 0 2rem;
    }

    .foot__grid {
        grid-template-columns: minmax(0, 1fr);
        gap: 2rem;
    }

    /* Centred on a phone the row becomes three stacked fragments with ragged
       edges; left-aligned it stays one readable block. */
    .foot__bar-row {
        justify-content: flex-start;
        gap: .8rem;
    }

    .foot__pay {
        margin-inline: 0;
        order: -1;
        width: 100%;
    }
}

@media (prefers-reduced-motion: reduce) {

    .foot__col a::after,
    .foot__social a {
        transition: none;
    }

    .foot__social a:hover,
    .foot__social a:focus-visible {
        transform: none;
    }
}

/* =========================================================================
   Back to top
   =========================================================================
   A ring of progress with an arrow in it. The ring is not decoration: the
   scroll position is already being read to decide whether the button appears,
   so drawing how far down the page the reader is costs nothing and turns a
   control that only offers to undo something into one that also answers "how
   much of this is left".

   It is [hidden] until app.js decides the page has been scrolled far enough
   to need it, so the attribute is what keeps it off a short page entirely.
   ====================================================================== */

.to-top {
    position: fixed;
    right: 1.25rem;
    bottom: 1.25rem;
    z-index: 1030;
    width: 48px;
    height: 48px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--paper);
    color: var(--primary);
    display: grid;
    place-items: center;
    cursor: pointer;
    font-size: 1.05rem;

    /* Two shadows rather than one: a tight dark edge that separates the disc
       from whatever is behind it, and a wide soft one that lifts it off the
       page. A single shadow can do either, not both. */
    box-shadow:
        0 1px 2px rgba(10, 22, 51, .16),
        0 8px 24px rgba(10, 22, 51, .16);

    /* The entrance (opacity + lift) and the hover (colour, scale) share one
       declaration. is-in is added a frame after [hidden] comes off, so the
       transition has a state to start from. */
    opacity: 0;
    transform: translateY(.6rem) scale(.94);
    transition: opacity .22s ease, transform .22s cubic-bezier(.2, .7, .3, 1),
        background .16s ease, color .16s ease, box-shadow .16s ease;
}

.to-top.is-in {
    opacity: 1;
    transform: none;
}

/* The ring and the arrow occupy the same cell, so the arrow sits inside the
   ring rather than beside it. */
.to-top__ring,
.to-top>i {
    grid-area: 1 / 1;
}

.to-top__ring {
    width: 48px;
    height: 48px;
    /* SVG draws clockwise from three o'clock; a progress ring has to start at
       twelve. */
    transform: rotate(-90deg);
    overflow: visible;
}

.to-top__track,
.to-top__bar {
    fill: none;
    stroke-linecap: round;
}

/* The groove is thinner than what fills it. At a quarter of the way down the
   arc is only a few centimetres of line against a pale track, and matching
   weights made it read as a rim rather than as progress. */
.to-top__track {
    stroke: var(--line);
    stroke-width: 2.5;
}

.to-top__bar {
    stroke: var(--primary);
    stroke-width: 3.25;
    /* pathLength="100" on the circle means one unit is one per cent, so the
       script sets the offset to 100 minus the percentage and nothing here has
       to know the radius. */
    stroke-dasharray: 100;
    stroke-dashoffset: 100;
    transition: stroke-dashoffset .1s linear, stroke .16s ease;
}

.to-top>i {
    transition: transform .18s cubic-bezier(.2, .7, .3, 1);
}

/* --- hover --- */

.to-top:hover,
.to-top:focus-visible {
    background: var(--primary);
    color: #fff;
    box-shadow:
        0 1px 2px rgba(10, 22, 51, .2),
        0 12px 30px rgba(10, 22, 51, .26);
}

.to-top:hover {
    transform: translateY(-2px);
}

/* The arrow leans the way it is about to take you. Small — a control that
   jumps under the cursor reads as unstable. */
.to-top:hover>i,
.to-top:focus-visible>i {
    transform: translateY(-2px);
}

/* On the filled disc the ring inverts: the track becomes a faint white groove
   and the progress becomes solid white, so it stays readable rather than
   disappearing into the brand colour. */
.to-top:hover .to-top__track,
.to-top:focus-visible .to-top__track {
    stroke: rgba(255, 255, 255, .3);
}

.to-top:hover .to-top__bar,
.to-top:focus-visible .to-top__bar {
    stroke: #fff;
}

.to-top:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 3px;
}

.to-top:active {
    transform: translateY(0) scale(.96);
}

/* Above the fixed bottom nav, not behind it. The bar's own height is the one
   number both it and this read, so they cannot drift apart. */
@media (max-width: 991.98px) {
    .to-top {
        right: .9rem;
        bottom: calc(var(--botnav-h) + .9rem + env(safe-area-inset-bottom, 0px));
    }
}

@media (prefers-reduced-motion: reduce) {

    /* The ring still fills — it is information, not motion — but nothing
       moves to deliver it. */
    .to-top {
        transition: opacity .16s ease, background .16s ease, color .16s ease;
        transform: none;
    }

    .to-top.is-in,
    .to-top:hover,
    .to-top:active {
        transform: none;
    }

    .to-top:hover>i,
    .to-top:focus-visible>i {
        transform: none;
    }

    .to-top__bar {
        transition: none;
    }
}

/* =========================================================================
   The catalogue — /products and /category/{slug}
   =========================================================================
   A sidebar of filters and a grid of results. On a phone the sidebar becomes
   a drawer, because a column of filters above the products would mean
   scrolling past the whole thing to reach the shop.

   The grid is the same .p-card the rails use, with its rail-only fixed width
   handed back so the track can decide instead.
   ====================================================================== */

.cat {
    padding: 1.5rem 0 3.5rem;
}

.crumbs {
    display: flex;
    align-items: center;
    gap: .45rem;
    font-size: .82rem;
    color: var(--muted);
    margin-bottom: 1rem;
    flex-wrap: wrap;
}

.crumbs a {
    color: var(--muted);
}

.crumbs a:hover {
    color: var(--accent);
}

.crumbs i {
    font-size: .62rem;
    opacity: .6;
}

.crumbs span {
    color: var(--ink);
    font-weight: 500;
}

.cat-head {
    margin-bottom: 1.5rem;
}

.cat-head__title {
    font-size: clamp(1.6rem, 3.4vw, 2.3rem);
    margin: 0 0 .35rem;
}

.cat-head__sub {
    margin: 0;
    color: var(--muted);
    font-size: .95rem;
    max-width: 46rem;
}

.cat-head__sub strong {
    color: var(--ink);
}

/* The two columns. 260px is enough for a category name and its count without
   the list wrapping, and little enough to leave four cards beside it. */
.cat-body {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: 1.75rem;
    align-items: start;
}

/* -------------------------------------------------------------------------
   Filters
   ---------------------------------------------------------------------- */

.cat-side {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    /* Follows the reader down a long grid, so the filters are never a scroll
       back up. Capped to the window so a shop with forty categories still
       scrolls inside its own panel. */
    position: sticky;
    top: 5.5rem;
    max-height: calc(100vh - 7rem);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.cat-side__head {
    display: none;
    /* only the drawer needs a title bar */
    align-items: center;
    justify-content: space-between;
    padding: .9rem 1.1rem;
    border-bottom: 1px solid var(--line);
}

.cat-side__head h2 {
    font-size: 1rem;
    margin: 0;
}

.cat-side__close {
    border: 0;
    background: var(--wash);
    color: var(--ink);
    width: 34px;
    height: 34px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    cursor: pointer;
    font-size: .9rem;
}

.cat-side__scroll {
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: .35rem 0 .5rem;
}

.fgroup {
    padding: 1rem 1.1rem;
    border-bottom: 1px solid var(--line);
}

.fgroup:last-child {
    border-bottom: 0;
}

.fgroup__title {
    font-family: "Sora", sans-serif;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--muted);
    margin: 0 0 .6rem;
}

.fgroup__hint {
    margin: .6rem 0 0;
    font-size: .76rem;
    color: var(--muted);
    line-height: 1.5;
}

.flist {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .1rem;
}

.flist__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .6rem;
    padding: .45rem .55rem;
    border-radius: 8px;
    color: var(--body);
    font-size: .9rem;
    line-height: 1.35;
}

.flist__item:hover {
    background: var(--wash);
    color: var(--ink);
}

/* The chosen one is filled, not ticked: in a list this short a solid row is
   read before a mark beside it is. */
.flist__item.is-on {
    background: var(--primary);
    color: #fff;
    font-weight: 600;
}

.flist__item.is-on:hover {
    color: #fff;
}

.flist__n {
    font-style: normal;
    font-size: .74rem;
    font-variant-numeric: tabular-nums;
    color: var(--muted);
    background: var(--wash);
    border-radius: 999px;
    padding: .05rem .4rem;
    flex: 0 0 auto;
}

.flist__item.is-on .flist__n {
    background: rgba(255, 255, 255, .22);
    color: #fff;
}

/* --- price --- */

.fprice {
    display: flex;
    align-items: center;
    gap: .35rem;
}

.fprice__box {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    align-items: center;
}

.fprice__cur {
    position: absolute;
    inset-inline-start: .5rem;
    font-size: .8rem;
    color: var(--muted);
    pointer-events: none;
}

.fprice__box input {
    width: 100%;
    min-width: 0;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--wash);
    padding: .45rem .4rem .45rem 1.5rem;
    font: inherit;
    font-size: .85rem;
    color: var(--ink);
}

.fprice__box input:focus {
    outline: none;
    border-color: var(--primary);
    background: var(--paper);
}

/* The spinners are 20px of nothing in a 90px box. */
.fprice__box input::-webkit-outer-spin-button,
.fprice__box input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.fprice__box input[type=number] {
    -moz-appearance: textfield;
}

.fprice__dash {
    color: var(--muted);
    font-size: .8rem;
}

.fprice__go {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: 8px;
    background: var(--primary);
    color: #fff;
    display: grid;
    place-items: center;
    cursor: pointer;
    font-size: .85rem;
}

.fprice__go:hover {
    filter: brightness(1.08);
}

/* --- switches --- */

.fswitch {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: .45rem .55rem;
    border-radius: 8px;
    color: var(--body);
    font-size: .9rem;
}

.fswitch:hover {
    background: var(--wash);
    color: var(--ink);
}

.fswitch__box {
    width: 18px;
    height: 18px;
    flex: 0 0 18px;
    border: 1.5px solid var(--line);
    border-radius: 5px;
    display: grid;
    place-items: center;
    font-size: .7rem;
    color: transparent;
    background: var(--paper);
    transition: background .15s ease, border-color .15s ease;
}

.fswitch.is-on {
    color: var(--ink);
    font-weight: 600;
}

.fswitch.is-on .fswitch__box {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

.fclear {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    margin: .9rem 1.1rem .4rem;
    font-size: .84rem;
    font-weight: 600;
    color: var(--deal);
}

.fclear:hover {
    color: var(--deal);
    text-decoration: underline;
}

/* -------------------------------------------------------------------------
   Results
   ---------------------------------------------------------------------- */

.cat-bar {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    padding: .7rem 1rem;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    margin-bottom: 1rem;
}

.cat-bar__count {
    margin: 0;
    font-size: .88rem;
    color: var(--muted);
    margin-inline-end: auto;
}

.cat-bar__count strong {
    color: var(--ink);
}

/* Only the drawer needs it, so it is not here on a wide screen. */
.cat-bar__filters {
    display: none;
    align-items: center;
    gap: .45rem;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .88rem;
    font-weight: 600;
    padding: .45rem .8rem;
    cursor: pointer;
}

.cat-bar__filters em {
    font-style: normal;
    background: var(--primary);
    color: #fff;
    border-radius: 999px;
    font-size: .7rem;
    min-width: 18px;
    height: 18px;
    padding: 0 .3rem;
    display: grid;
    place-items: center;
}

.cat-sort {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .86rem;
}

.cat-sort label {
    color: var(--muted);
}

.cat-sort select {
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .86rem;
    font-weight: 600;
    padding: .4rem 2rem .4rem .7rem;
    cursor: pointer;
    /* The native arrow differs on every platform and none of them match the
       rest of the bar, so it is replaced with one that does. */
    appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%238792a8'><path d='M4.5 6.5 8 10l3.5-3.5z'/></svg>");
    background-repeat: no-repeat;
    background-position: right .55rem center;
    background-size: 14px;
}

.cat-sort select:focus {
    outline: none;
    border-color: var(--primary);
}

/* --- active filter chips --- */

.cat-chips {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-bottom: 1rem;
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .3rem .5rem .3rem .7rem;
    border-radius: 999px;
    border: 1px solid var(--line);
    background: var(--paper);
    color: var(--ink);
    font-size: .8rem;
    font-weight: 500;
}

.chip i {
    font-size: .85rem;
    color: var(--muted);
}

.chip:hover {
    border-color: var(--deal);
    color: var(--deal);
}

.chip:hover i {
    color: var(--deal);
}

.chip--clear {
    padding-inline: .7rem;
    color: var(--deal);
    font-weight: 600;
    border-style: dashed;
}

/* --- the grid --- */

.p-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 1.1rem;
}

/* .p-card names a width for the rails, where a flex item has to. In a grid
   the track decides, so it is handed back. */
.p-grid .p-card {
    width: auto;
}

/**
 * A card arriving from "Load more".
 *
 * Up and in, not just in: a card that only fades looks like a rendering
 * artefact, while a short rise reads as "this was fetched for you". The blur
 * is what keeps it from looking cheap — it lets the card resolve rather than
 * slide, so a grid of ten does not feel like a slot machine.
 *
 * The stagger is set per card in JS as --in-delay. It is small on purpose:
 * 55ms apart means the batch reads as one motion with a direction, where
 * anything slower turns a load into a queue you have to wait through.
 *
 * Only appended cards ever carry this class. The first page is rendered by
 * the server and animating it would delay the thing the visitor actually
 * came for.
 */
@keyframes cardIn {
    from {
        opacity: 0;
        transform: translateY(14px) scale(.985);
        filter: blur(3px);
    }

    to {
        opacity: 1;
        transform: none;
        filter: blur(0);
    }
}

.p-card.is-entering {
    animation: cardIn .5s cubic-bezier(.22, .61, .36, 1) both;
    animation-delay: var(--in-delay, 0ms);
}

.cat-more {
    margin-top: 1.75rem;
    display: flex;
    justify-content: center;
}

/* The quiet twin of the buy button: same shape and colour, outlined, so
   "there is more this way" does not compete with every Add to cart above it. */
.btn-outline {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: .7rem 1.6rem;
    border-radius: 9px;
    border: 1px solid var(--primary);
    background: transparent;
    color: var(--primary);
    font: inherit;
    font-size: .92rem;
    font-weight: 600;
    cursor: pointer;
    transition: background .15s ease, color .15s ease, box-shadow .15s ease;
}

.btn-outline:hover {
    background: var(--primary);
    color: #fff;
    box-shadow: 0 6px 18px rgba(10, 22, 51, .28);
    box-shadow: 0 6px 18px color-mix(in srgb, var(--primary) 35%, transparent);
}

.btn-outline[disabled] {
    opacity: .55;
    cursor: default;
}

/* --- nothing found --- */

.cat-empty {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 3.5rem 1.5rem;
    text-align: center;
}

.cat-empty>i {
    font-size: 2rem;
    color: var(--muted);
    display: block;
    margin-bottom: .75rem;
}

.cat-empty h2 {
    font-size: 1.2rem;
    margin: 0 0 .4rem;
}

.cat-empty p {
    margin: 0 auto 1.25rem;
    max-width: 26rem;
    color: var(--muted);
    font-size: .92rem;
}

/* -------------------------------------------------------------------------
   The drawer
   ---------------------------------------------------------------------- */

@media (max-width: 991.98px) {
    .cat-body {
        grid-template-columns: minmax(0, 1fr);
        gap: 0;
    }

    .cat-bar__filters {
        display: inline-flex;
    }

    /**
     * Off to the left until it is asked for.
     *
     * translateX rather than display:none so it slides, and so the panel has
     * a size before it is opened — a drawer that has never been laid out
     * arrives at the wrong height on the first tap.
     */
    .cat-side {
        position: fixed;
        inset: 0 auto 0 0;
        z-index: 1050;
        width: min(88vw, 340px);
        max-height: none;
        border-radius: 0;
        border-inline-start: 0;
        transform: translateX(-102%);
        transition: transform .28s cubic-bezier(.4, 0, .2, 1);
        box-shadow: 0 0 60px rgba(10, 22, 51, .3);
    }

    .cat-side.is-open {
        transform: none;
    }

    .cat-side__head {
        display: flex;
    }

    .cat-side__veil {
        position: fixed;
        inset: 0;
        z-index: 1045;
        background: rgba(10, 22, 51, .45);
        opacity: 0;
        transition: opacity .28s ease;
    }

    .cat-side__veil.is-open {
        opacity: 1;
    }

    /* The page behind a drawer must not scroll under it. */
    body.filters-open {
        overflow: hidden;
    }
}

@media (max-width: 575.98px) {
    .p-grid {
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
        gap: .75rem;
    }

    .cat-bar {
        padding: .6rem .7rem;
        gap: .6rem;
    }

    /* The count is the first thing to go: the two controls either side of it
       are the ones a thumb needs. */
    .cat-bar__count {
        display: none;
    }

    .cat-sort {
        margin-inline-start: auto;
    }

    .cat-sort label {
        display: none;
    }
}

/* =========================================================================
   Small screens
   ====================================================================== */

@media (max-width: 991.98px) {
    .trust__grid {
        grid-template-columns: repeat(2, 1fr);
    }

    .hero__slide {
        min-height: 400px;
    }
}

@media (max-width: 767.98px) {

    /**
     * The masthead is sticky, and on a phone it wraps to two rows — the logo
     * and the account icons, then the search. At the desktop's spacing that
     * came to 144px of permanently occupied screen, about a fifth of a phone,
     * every one of which is a product the shopper cannot see.
     *
     * It stays sticky, because search is the thing people reach for most in a
     * shop. It just stops taking a fifth of the window to offer it.
     */
    .masthead {
        padding: .55rem 0;
    }

    .masthead__row {
        flex-wrap: wrap;
        gap: .5rem .75rem;
    }

    .brand img {
        height: 32px;
    }

    .brand__text {
        font-size: 1.15rem;
    }

    .searchbox {
        order: 3;
        flex-basis: 100%;
        max-width: none;
    }

    .searchbox input {
        padding-block: .55rem;
    }

    .head-btn {
        padding: .4rem .5rem;
    }

    .head-btn span {
        display: none;
    }

    .hero__slide {
        min-height: 340px;
    }

    .hero__body {
        /* Extra room at the foot, because the arrows and the dots now sit in
           a strip along the bottom of the slide. Without it the second call to
           action reaches into that strip and the left arrow lands on top of
           it — measured, not guessed: the button ran to y=579 and the arrow
           starts at y=539. */
        padding: 2.25rem 0 4.5rem;
    }

    .hero__eyebrow-rule {
        display: none;
    }

    /* The arrows move rather than disappear.
       -------------------------------------------------------------------
       At their desktop size — 6% of the width, about 22px on a phone — they
       sat full-height down each edge, directly on top of the sentence, and
       were too small to hit anyway. So on a phone they leave the text alone
       and become two proper round buttons in the bottom corners, on the same
       line as the dots: a 40px target a thumb can actually find, and nothing
       covering a word. */
    .hero .carousel-control-prev,
    .hero .carousel-control-next {
        top: auto;
        bottom: .5rem;
        width: 40px;
        height: 40px;
        border-radius: 50%;
        background: rgba(0, 20, 60, .5);
        backdrop-filter: blur(4px);
        border: 1px solid rgba(255, 255, 255, .28);
        opacity: 1;
    }

    .hero .carousel-control-prev { left: .75rem; }
    .hero .carousel-control-next { right: .75rem; }

    /* Bootstrap draws the chevrons as background images sized 2rem, which
       overflows a 40px button. */
    .hero .carousel-control-prev-icon,
    .hero .carousel-control-next-icon {
        width: 1.1rem;
        height: 1.1rem;
    }

    /* The dots sit between the two buttons on that line, so they lift clear
       of the bottom edge to match. */
    .hero .carousel-indicators {
        margin-bottom: 1.1rem;
    }

    /* The scrim was drawn for a wide layout: a gradient running left to right,
       dark where the text sits and clear where the photograph should show. On
       a phone the text spans the whole width, so that gradient leaves the last
       words of every line lying on bare photograph — white on a yellow
       headphone, which cannot be read. Vertical here, and darker, because the
       text is what the band is for. */
    .hero__scrim {
        background: linear-gradient(
            180deg,
            rgba(0, 20, 60, .62) 0%,
            rgba(0, 20, 60, .80) 55%,
            rgba(0, 20, 60, .92) 100%
        );
    }

    .cat-card {
        height: 200px;
    }

    .section {
        padding: 2.25rem 0;
    }
}

@media (max-width: 575.98px) {
    .trust__grid {
        grid-template-columns: 1fr;
    }

    .topline__items span:nth-child(n+2) {
        display: none;
    }

    /**
     * The offer band's clock.
     *
     * Four cells at a 62px floor plus their gaps need 274px, which is more
     * than a 360px phone has once the container and the band's own padding
     * have taken theirs. A minimum width cannot shrink, so the whole band was
     * being pushed past the right edge — the heading and the paragraph with
     * it, because they share a flex item with the clock.
     *
     * Sharing the row four ways instead means it fits whatever the screen is.
     */
    .countdown {
        gap: .4rem;
    }

    .countdown__cell {
        min-width: 0;
        flex: 1 1 0;
        padding: .45rem .25rem;
    }

    .countdown__n {
        font-size: 1.15rem;
    }

    .countdown__l {
        font-size: .6rem;
        letter-spacing: .04em;
    }

    /* The strip heading's clock and its link stop sharing a line before either
       has to be squeezed. */
    .sec-head__aside {
        gap: .6rem 1rem;
    }
}

/**
 * The placeholder table on a page that has no template yet.
 *
 * Scaffolding, and it will go when those pages are built — but until then it
 * is a six-column table on a phone, and a table cannot shrink below its
 * content. Left alone it drags the whole document sideways, which makes every
 * unbuilt page look broken in a way that has nothing to do with the page.
 * Scrolling inside its own box keeps that to the table.
 */
.scaffold-vars {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    border-collapse: collapse;
}

@media (prefers-reduced-motion: reduce) {
    .rail {
        scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
        transition-duration: .01ms !important;
        animation-duration: .01ms !important;
        /* Cutting the duration alone is not enough. A staggered entrance keeps
           its delay, so the ninth card in a batch would sit invisible for half
           a second and then appear from nowhere — which is a worse experience
           than the animation, and the exact opposite of what was asked for. */
        animation-delay: 0ms !important;
        transition-delay: 0ms !important;
    }
}

/* =========================================================================
   About us
   =========================================================================
   Its own block rather than borrowed homepage classes. The homepage sells
   products and is built out of rails and cards; this page sells the shop, and
   it is long-form.

   The shape is editorial rather than promotional, and deliberately shares no
   skeleton with the rest of the site: an asymmetric masthead over a
   full-bleed photograph, a ruled row of figures, a story whose heading stays
   put while the text scrolls past it, and the promises as a numbered list
   rather than a row of cards. Nothing here is a grid of equal boxes, which is
   what every other page is made of.

   Everything reads the same tokens as the rest of the site, so a shop that
   repaints its palette repaints this page with it.
   ====================================================================== */

/* ---- shared furniture ---- */

.ab-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    font-family: "Sora", sans-serif;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: .9rem;
}

/* A dot rather than the hero's bar. Same idea — a mark, then the words — but
   this page is quieter than the homepage and the mark should be too. */
.ab-eyebrow__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--accent);
    flex: 0 0 7px;
}

.ab-eyebrow--center {
    justify-content: center;
}

/* The outlined button, for a light band. .btn-ghost is white-on-dark and only
   works over the homepage hero photograph. */
.btn-line {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .8rem 1.7rem;
    border-radius: 999px;
    border: 1.5px solid var(--line);
    background: var(--paper);
    color: var(--ink);
    font-weight: 600;
    font-size: .95rem;
    transition: border-color .18s ease, color .18s ease, background .18s ease;
}

.btn-line:hover {
    border-color: var(--primary);
    color: var(--primary);
    background: var(--paper);
}

/* =========================================================================
   1. Masthead
   ====================================================================== */

.ab-top {
    padding-top: 1.5rem;
}

/**
 * Asymmetric, and the asymmetry is the point.
 *
 * A centred hero reads as a brochure cover. Running the title wide on the
 * left and setting the paragraph against its right-hand edge reads as a
 * masthead, and gives the eye somewhere to go after the headline instead of
 * a symmetrical dead centre with nothing on either side of it.
 *
 * The columns are 1.15fr / 1fr rather than 2fr / 1fr: the paragraph has to be
 * wide enough to hold a real sentence, or the "aside" becomes a caption.
 */
.ab-top__grid {
    display: grid;
    grid-template-columns: 1.15fr 1fr;
    gap: 2.5rem 3.5rem;
    /* Tops, not baselines. Aligning the bottoms reads well only while the two
       columns are a similar height — with a short heading against a full
       paragraph it drops the title to the floor and leaves a hole above it
       that looks like a mistake rather than a decision. The asymmetry is
       carried by the column widths and the bleed below, not by this. */
    align-items: start;
    padding-bottom: 2.75rem;
}

.ab-top__title {
    font-size: clamp(2.1rem, 5.4vw, 4rem);
    line-height: 1.04;
    letter-spacing: -.035em;
    margin: 0;
    text-wrap: balance;
}

.ab-top__aside p {
    margin: 0 0 1rem;
    font-size: 1.06rem;
    line-height: 1.75;
    color: var(--body);
}

.ab-top__aside p:last-of-type {
    margin-bottom: 1.5rem;
}

.ab-top__actions {
    display: flex;
    flex-wrap: wrap;
    gap: .7rem;
}

/**
 * The photograph, edge to edge.
 *
 * The one place on the site where an image gets the whole window. It is the
 * shop introducing itself, and a photograph sitting in a 1320px box with
 * margins either side is a picture of a shop rather than the shop.
 *
 * 100vw with a negative half-difference is the usual break-out trick; body
 * already carries overflow-x: hidden, so the scrollbar's width cannot start a
 * sideways scroll.
 */
.ab-bleed {
    margin: 0;
    width: 100%;
    aspect-ratio: 21 / 8;
    max-height: 460px;
    overflow: hidden;
    background: var(--wash);
}

.ab-bleed img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* =========================================================================
   2. Figures
   ====================================================================== */

.ab-figures {
    background: var(--paper);
    border-bottom: 1px solid var(--line);
}

/**
 * A ruled row, not four cards.
 *
 * These four numbers are one sentence of evidence read left to right. Boxing
 * each of them invites a comparison between them — is 64 districts better or
 * worse than 4.8 out of 5? — which is a question the row is not asking.
 */
.ab-figures__row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    margin: 0;
    padding: 2rem 0;
}

.ab-figure {
    padding: .35rem 1.5rem;
    border-inline-start: 1px solid var(--line);
}

.ab-figure:first-child {
    border-inline-start: 0;
    padding-inline-start: 0;
}

.ab-figure__value {
    font-family: "Sora", sans-serif;
    font-size: clamp(1.7rem, 3.4vw, 2.5rem);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -.03em;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}

.ab-figure__label {
    margin: .45rem 0 0;
    font-size: .82rem;
    color: var(--muted);
    line-height: 1.4;
}

/* =========================================================================
   3. Story
   ====================================================================== */

.ab-story__grid {
    display: grid;
    /* A third to the heading, two thirds to the story. The heading column is
       mostly empty by design — it is a rail the sticky title rides down — so
       it is kept narrow enough to read as a margin rather than as a column
       somebody forgot to fill. */
    grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
    gap: 3rem;
    align-items: start;
}

/**
 * The heading stays put while the story scrolls past it.
 *
 * Four paragraphs in, a reader has usually lost the heading that told them
 * what they were reading about. Sticky costs nothing and fixes it, and on a
 * narrow screen it degrades to exactly what it looks like anyway: a heading
 * above its text.
 */
.ab-story__lede {
    position: sticky;
    top: 6.5rem;
}

.ab-story__lede h2 {
    font-size: clamp(1.5rem, 3vw, 2.15rem);
    margin: 0;
    letter-spacing: -.025em;
}

.ab-badge {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    margin-top: 1.1rem;
    padding: .4rem .85rem;
    border-radius: 999px;
    background: var(--paper);
    color: var(--ink);
    font-size: .8rem;
    font-weight: 600;
}

.ab-badge i {
    color: var(--accent);
}

.ab-story__figure {
    margin: 0 0 1.75rem;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--wash);
    box-shadow: var(--shadow);
}

.ab-story__figure img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    display: block;
}

.ab-story__body p {
    margin: 0 0 1.1rem;
    color: var(--body);
    line-height: 1.85;
}

/* The paragraph most people read before deciding whether to read the rest, so
   it is given the weight to earn that. */
.ab-story__opening {
    font-size: 1.12rem;
    color: var(--ink);
    font-weight: 500;
}

/* =========================================================================
   4. Values, as a list
   ====================================================================== */

.ab-values {
    background: var(--paper);
}

.ab-values__head {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 1rem 3rem;
    align-items: end;
    margin-bottom: 2.25rem;
}

.ab-values__head h2 {
    font-size: clamp(1.5rem, 3vw, 2.15rem);
    margin: 0;
    letter-spacing: -.025em;
}

.ab-values__sub {
    margin: 0;
    color: var(--muted);
    font-size: .98rem;
    line-height: 1.7;
}

/**
 * One promise per full-width row, numbered.
 *
 * Four cards side by side ask the eye to compare them. These were never in
 * competition — they are four things that are all true at once — and a list
 * says that where a grid does not. It also gives them an order, which four
 * equal boxes cannot.
 */
.ab-list {
    list-style: none;
    margin: 0;
    padding: 0;
    border-top: 1px solid var(--line);
}

.ab-list__row {
    display: grid;
    grid-template-columns: 4.5rem minmax(0, 4fr) minmax(0, 6fr);
    gap: 1rem 2rem;
    align-items: start;
    padding: 1.6rem .75rem;
    border-bottom: 1px solid var(--line);
    transition: background .2s ease;
}

.ab-list__row:hover {
    background: var(--wash);
}

/* Outlined rather than filled: at this size a solid numeral would outweigh
   the promise beside it, which is the thing worth reading. */
.ab-list__n {
    font-family: "Sora", sans-serif;
    font-size: 1.9rem;
    font-weight: 800;
    line-height: 1;
    letter-spacing: -.04em;
    color: transparent;
    -webkit-text-stroke: 1.5px var(--line);
    font-variant-numeric: tabular-nums;
    transition: -webkit-text-stroke-color .2s ease, color .2s ease;
}

.ab-list__row:hover .ab-list__n {
    -webkit-text-stroke-color: var(--accent);
}

.ab-list__title {
    display: flex;
    align-items: center;
    gap: .75rem;
}

.ab-list__title i {
    font-size: 1.25rem;
    color: var(--primary);
    flex: 0 0 auto;
}

.ab-list__title h3 {
    font-size: 1.08rem;
    margin: 0;
    letter-spacing: -.015em;
}

.ab-list__text {
    margin: 0;
    color: var(--body);
    font-size: .95rem;
    line-height: 1.7;
}

/* A stroke-only numeral is invisible where -webkit-text-stroke is not
   supported, so it falls back to a flat tint. */
@supports not (-webkit-text-stroke: 1px red) {
    .ab-list__n {
        color: var(--line);
    }
}

/* =========================================================================
   5. Team
   ====================================================================== */

.ab-team__head {
    text-align: center;
    max-width: 40rem;
    margin: 0 auto 2.25rem;
}

.ab-team__head h2 {
    font-size: clamp(1.5rem, 3vw, 2.15rem);
    margin: 0;
    letter-spacing: -.025em;
}

.ab-team__sub {
    margin: .6rem 0 0;
    color: var(--muted);
    font-size: .98rem;
    line-height: 1.7;
}

/* A row that centres itself, so two people look deliberate rather than like a
   three-column grid with a hole in it. */
.ab-team__row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 2.5rem;
}

.ab-person {
    margin: 0;
    width: 168px;
    text-align: center;
}

.ab-person__photo {
    width: 132px;
    height: 132px;
    margin: 0 auto .9rem;
    border-radius: 50%;
    overflow: hidden;
    background: var(--wash);
    border: 3px solid var(--paper);
    box-shadow: var(--shadow);
    display: grid;
    place-items: center;
}

.ab-person__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.ab-person__initial {
    font-family: "Sora", sans-serif;
    font-size: 2.4rem;
    font-weight: 800;
    color: var(--primary);
}

.ab-person__name {
    display: block;
    font-family: "Sora", sans-serif;
    font-weight: 700;
    color: var(--ink);
    font-size: .98rem;
}

.ab-person__role {
    display: block;
    margin-top: .15rem;
    font-size: .82rem;
    color: var(--muted);
}

/* =========================================================================
   Small screens
   ====================================================================== */

@media (max-width: 991.98px) {

    /* One column everywhere, and the sticky heading stops sticking — there is
       nothing beside it to stay level with. */
    .ab-top__grid,
    .ab-story__grid,
    .ab-values__head {
        grid-template-columns: minmax(0, 1fr);
        gap: 1.5rem;
        align-items: start;
    }

    .ab-story__lede {
        position: static;
    }

    .ab-bleed {
        aspect-ratio: 16 / 9;
    }
}

@media (max-width: 767.98px) {
    .ab-top__grid {
        padding-bottom: 2rem;
    }

    /* Two up rather than four across. The rule stays vertical — it still
       separates two figures side by side — but it moves to the trailing edge
       so the pair in each row is divided once, rather than every cell
       carrying a leading rule and the second column growing a stray one. */
    .ab-figures__row {
        grid-template-columns: repeat(2, 1fr);
        gap: 1.25rem 0;
        padding: 1.5rem 0;
    }

    .ab-figure {
        padding: 0 1rem;
        border-inline-start: 0;
        border-inline-end: 1px solid var(--line);
    }

    .ab-figure:nth-child(2n) {
        border-inline-end: 0;
    }

    .ab-figure:first-child {
        padding-inline-start: 1rem;
    }

    /* The numeral moves above the row rather than taking a column of its own:
       4.5rem of numeral leaves too little for the words beside it. */
    .ab-list__row {
        grid-template-columns: minmax(0, 1fr);
        gap: .6rem;
        padding: 1.35rem .25rem;
    }

    .ab-list__n {
        font-size: 1.35rem;
    }

    .ab-team__row {
        gap: 1.75rem;
    }

    .ab-person {
        width: 132px;
    }

    .ab-person__photo {
        width: 104px;
        height: 104px;
    }
}

@media (prefers-reduced-motion: reduce) {

    .ab-list__row,
    .ab-list__n,
    .btn-line {
        transition: none;
    }
}

/* =========================================================================
   The spam trap
   =========================================================================
   SpamGuard prints a "Website" text box into every public form and treats a
   filled one as a bot. It had no styles anywhere, which meant the box was
   visible: a real customer would see a field asking for their website, fill
   it in helpfully, and have their message silently binned — the guard answers
   a caught bot with the same thank-you a person gets, so nobody would ever
   have found out.

   Not display:none. Some bots skip hidden fields, and the whole trick rests
   on them filling this one in. Off-screen and untabbable keeps it invisible
   to people while it is still a real field in the DOM.
   ====================================================================== */

.spam-trap {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* =========================================================================
   Contact
   =========================================================================
   Ordered for somebody who wants an answer now rather than somebody who wants
   to fill in a form: the four fast routes sit above the form, not under it.
   On this shop most people would rather ring than write, and making them
   scroll past four fields to find the number is the commonest mistake a
   contact page makes.
   ====================================================================== */

.ct {
    padding: 1.5rem 0 3.5rem;
}

.ct-head {
    max-width: 44rem;
    margin-bottom: 2rem;
}

.ct-head h1 {
    font-size: clamp(1.8rem, 4vw, 2.8rem);
    letter-spacing: -.03em;
    margin: 0 0 .6rem;
}

.ct-head p {
    margin: 0;
    color: var(--muted);
    font-size: 1.02rem;
    line-height: 1.7;
}

/* -------------------------------------------------------------------------
   The fast routes
   ---------------------------------------------------------------------- */

.ct-channels {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
    gap: 1rem;
    margin-bottom: 2.5rem;
}

/**
 * Each one is a link that does the thing, not a label describing it: tapping
 * "Call us" dials, tapping WhatsApp opens the thread. A card that only tells
 * you the number and leaves you to copy it is a card that has not helped.
 */
.ct-channel {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: .9rem;
    padding: 1.1rem;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    color: var(--ink);
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}

.ct-channel:hover {
    color: var(--ink);
    transform: translateY(-3px);
    border-color: transparent;
    box-shadow: var(--shadow-lg);
}

.ct-channel__icon {
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    border-radius: 12px;
    display: grid;
    place-items: center;
    font-size: 1.15rem;
    background: var(--wash);
    background: color-mix(in srgb, var(--primary) 9%, transparent);
    color: var(--primary);
}

.ct-channel__body {
    display: flex;
    flex-direction: column;
    min-width: 0;
    gap: .1rem;
}

.ct-channel__label {
    /* Only this line shares the corner with the arrow, and it is always short
       — the value and the note underneath get the card's full width. */
    padding-inline-end: 1.1rem;
    font-family: "Sora", sans-serif;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--muted);
}

/* The number or address itself. Allowed to wrap — an address is long, and
   truncating the thing somebody came for helps nobody.

   anywhere rather than break-word because an email has no spaces in it: with
   break-word the browser would rather overflow the card than split
   shopghor@gmail.com, and an address that runs out past its own border is
   worse than one that wraps. The size is a shade under the label's so it
   takes the break less often. */
.ct-channel__value {
    font-weight: 600;
    font-size: .94rem;
    line-height: 1.4;
    color: var(--ink);
    overflow-wrap: anywhere;
}

.ct-channel__note {
    font-size: .8rem;
    color: var(--muted);
    line-height: 1.4;
}

/* Pinned to the corner rather than sitting in the row. In the flow it cost
   the value column nearly thirty pixels, which was the difference between an
   email address fitting on one line and being split down the middle — and a
   broken address is the one thing on this card nobody can use. */
.ct-channel__go {
    position: absolute;
    top: 1.1rem;
    inset-inline-end: 1.1rem;
    font-size: .85rem;
    color: var(--muted);
    transition: color .18s ease, transform .18s ease;
}

.ct-channel:hover .ct-channel__go {
    color: var(--accent);
    transform: translate(2px, -2px);
}

/* -------------------------------------------------------------------------
   Form and aside
   ---------------------------------------------------------------------- */

.ct-body {
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
    gap: 1.5rem;
    align-items: start;
}

.ct-form-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: clamp(1.25rem, 3vw, 2rem);
}

.ct-form-card__head {
    margin-bottom: 1.5rem;
}

.ct-form-card__head h2 {
    font-size: 1.3rem;
    margin: 0 0 .3rem;
    letter-spacing: -.02em;
}

.ct-form-card__head p {
    margin: 0;
    color: var(--muted);
    font-size: .92rem;
}

/* --- the result of the last attempt --- */

.ct-note {
    display: flex;
    align-items: flex-start;
    gap: .7rem;
    padding: .9rem 1rem;
    border-radius: 10px;
    margin-bottom: 1.25rem;
    font-size: .92rem;
    line-height: 1.6;
}

.ct-note p {
    margin: 0;
}

.ct-note ul {
    margin: .35rem 0 0;
    padding-inline-start: 1.1rem;
}

.ct-note>i {
    font-size: 1.05rem;
    margin-top: .1rem;
    flex: 0 0 auto;
}

/* Green and red are the two colours a form result is allowed to be, and
   neither is a brand colour — a shop whose primary is red must not have its
   confirmations read as failures. */
.ct-note--ok {
    background: rgba(21, 128, 61, .08);
    border: 1px solid rgba(21, 128, 61, .22);
    color: #15803d;
}

.ct-note--bad {
    background: rgba(220, 38, 38, .07);
    border: 1px solid rgba(220, 38, 38, .22);
    color: #b91c1c;
}

/* --- fields --- */

.ct-form__row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1rem;
}

.ct-field {
    display: block;
    margin-bottom: 1rem;
}

.ct-field__label {
    display: block;
    font-size: .84rem;
    font-weight: 600;
    color: var(--ink);
    margin-bottom: .35rem;
}

/* The asterisk is the convention for "required" and it is the only thing on
   the label that should be loud. */
.ct-field__label em {
    font-style: normal;
    color: var(--deal);
}

.ct-field__opt {
    font-weight: 400;
    color: var(--muted);
}

.ct-field input,
.ct-field textarea {
    width: 100%;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--wash);
    padding: .7rem .9rem;
    font: inherit;
    font-size: .95rem;
    color: var(--ink);
    transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}

.ct-field textarea {
    resize: vertical;
    min-height: 8rem;
    line-height: 1.65;
}

.ct-field input::placeholder,
.ct-field textarea::placeholder {
    color: var(--muted);
}

/* The field being typed into lifts off the wash and takes a ring, so the
   caret is never the only clue about where you are. */
.ct-field input:focus,
.ct-field textarea:focus {
    outline: none;
    background: var(--paper);
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(0, 43, 127, .12);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 14%, transparent);
}

.ct-form__foot {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: .35rem;
}

.ct-form__small {
    margin: 0;
    font-size: .82rem;
    color: var(--muted);
    line-height: 1.5;
}

/* --- aside --- */

.ct-aside {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.ct-panel {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1.25rem;
}

.ct-panel h3 {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .96rem;
    margin: 0 0 .75rem;
}

.ct-panel h3 i {
    color: var(--accent);
    font-size: 1rem;
}

.ct-panel__address {
    margin: 0 0 .75rem;
    color: var(--body);
    font-size: .93rem;
    line-height: 1.65;
}

.ct-panel__link {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-size: .88rem;
    font-weight: 600;
}

.ct-links {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .3rem;
}

.ct-links a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    padding: .6rem;
    margin-inline: -.6rem;
    border-radius: 9px;
    color: var(--body);
    font-size: .88rem;
    line-height: 1.45;
}

.ct-links a:hover {
    background: var(--wash);
    color: var(--ink);
}

.ct-links strong {
    display: block;
    color: var(--ink);
    font-size: .92rem;
    font-weight: 600;
}

.ct-links i {
    color: var(--muted);
    font-size: .8rem;
    flex: 0 0 auto;
}

.ct-socials {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}

.ct-socials a {
    width: 40px;
    height: 40px;
    border-radius: 11px;
    display: grid;
    place-items: center;
    background: var(--wash);
    border: 1px solid var(--line);
    color: var(--ink);
    font-size: 1.05rem;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}

.ct-socials a:hover {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

/* -------------------------------------------------------------------------
   Small screens
   ---------------------------------------------------------------------- */

@media (max-width: 991.98px) {

    /* The aside carries the address and the two deflection links; underneath
       the form is the right place for both once there is no room beside it. */
    .ct-body {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 575.98px) {
    .ct-channels {
        grid-template-columns: minmax(0, 1fr);
        gap: .6rem;
    }

    .ct-channel {
        padding: .9rem;
    }

    /* A full-width button is the easier target, and there is nothing beside
       it to line up with once the note has wrapped below. */
    .ct-form__foot .btn-accent {
        width: 100%;
        justify-content: center;
    }
}

@media (prefers-reduced-motion: reduce) {

    .ct-channel,
    .ct-channel__go {
        transition: none;
    }

    .ct-channel:hover {
        transform: none;
    }

    .ct-channel:hover .ct-channel__go {
        transform: none;
    }
}

/* color-mix is recent enough to want a floor under it, or the icon plate and
   the focus ring simply do not paint. */
@supports not (background: color-mix(in srgb, red 9%, transparent)) {
    .ct-channel__icon {
        background: rgba(0, 43, 127, .09);
    }
}

/* =========================================================================
   The customer account
   =========================================================================
   Three screens — overview, orders, wishlist — sharing one shell: an identity
   band, a row of tabs, then cards. The shell is a partial rather than three
   copies, and these styles are shared for the same reason.

   Nothing here reuses the catalogue's sidebar layout. That page is a tool for
   narrowing a list; this is somebody's own corner of the shop, and it reads
   top to bottom.
   ====================================================================== */

.ac {
    padding: 1.5rem 0 3.5rem;
}

/* -------------------------------------------------------------------------
   Identity band
   ---------------------------------------------------------------------- */

.ac-id {
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.4rem 1.5rem;
    border-radius: var(--radius);
    background: var(--primary-deep);
    margin-bottom: 1rem;
}

/* One soft wash of light, off to one side, so the plate is not a flat slab.
   Decorative only — it carries no meaning and is hidden from assistive tech. */
.ac-id__glow {
    position: absolute;
    inset-block-start: -70%;
    inset-inline-end: -10%;
    width: min(440px, 70%);
    aspect-ratio: 1;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255, 255, 255, .17), transparent 62%);
    pointer-events: none;
}

.ac-id__avatar {
    position: relative;
    flex: 0 0 56px;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: rgba(255, 255, 255, .14);
    border: 1px solid rgba(255, 255, 255, .22);
    color: #fff;
    font-family: "Sora", sans-serif;
    font-size: 1.4rem;
    font-weight: 700;
}

.ac-id__who {
    position: relative;
    min-width: 0;
}

.ac-id__hello {
    margin: 0;
    color: #fff;
    font-family: "Sora", sans-serif;
    font-size: 1.2rem;
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.25;
}

.ac-id__mail {
    margin: .15rem 0 0;
    color: rgba(255, 255, 255, .72);
    font-size: .88rem;
    overflow-wrap: anywhere;
}

.ac-id__out {
    position: relative;
    margin-inline-start: auto;
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .55rem 1rem;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, .3);
    color: #fff;
    font-size: .88rem;
    font-weight: 600;
    white-space: nowrap;
    transition: background .15s ease, border-color .15s ease;
}

.ac-id__out:hover {
    background: rgba(255, 255, 255, .14);
    border-color: rgba(255, 255, 255, .5);
    color: #fff;
}

/* -------------------------------------------------------------------------
   Tabs
   ---------------------------------------------------------------------- */

/* Scrolls sideways on a phone rather than wrapping: three items on one line
   stay a nav, two rows become furniture. */
.ac-tabs {
    display: flex;
    gap: .35rem;
    margin-bottom: 1.25rem;
    overflow-x: auto;
    scrollbar-width: none;
}

.ac-tabs::-webkit-scrollbar {
    display: none;
}

.ac-tab {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .6rem 1rem;
    border-radius: 10px;
    border: 1px solid var(--line);
    background: var(--paper);
    color: var(--body);
    font-size: .92rem;
    font-weight: 600;
    white-space: nowrap;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}

.ac-tab:hover {
    color: var(--ink);
    border-color: var(--muted);
}

.ac-tab.is-on {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

.ac-tab.is-on:hover {
    color: #fff;
}

/* -------------------------------------------------------------------------
   Tiles
   ---------------------------------------------------------------------- */

.ac-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: .75rem;
    margin-bottom: 1.25rem;
}

.ac-tile {
    display: flex;
    flex-direction: column;
    gap: .1rem;
    padding: 1.1rem;
    border-radius: var(--radius);
    border: 1px solid var(--line);
    background: var(--paper);
    color: var(--ink);
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}

/* Only the ones that lead somewhere lift; a div that rises under the cursor
   is promising a click it cannot honour. */
a.ac-tile:hover {
    color: var(--ink);
    transform: translateY(-3px);
    border-color: transparent;
    box-shadow: var(--shadow-lg);
}

.ac-tile__icon {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    display: grid;
    place-items: center;
    margin-bottom: .5rem;
    font-size: 1rem;
    background: var(--wash);
    background: color-mix(in srgb, var(--primary) 9%, transparent);
    color: var(--primary);
}

.ac-tile__value {
    font-family: "Sora", sans-serif;
    font-size: 1.6rem;
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -.03em;
    font-variant-numeric: tabular-nums;
}

.ac-tile__label {
    font-size: .82rem;
    color: var(--muted);
}

/* -------------------------------------------------------------------------
   Cards
   ---------------------------------------------------------------------- */

/* Orders take the wider column: it is the reason most people signed in, and
   an address is short enough to live beside it. */
.ac-grid {
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: 1rem;
    align-items: start;
}

.ac-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1.25rem;
}

.ac-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}

.ac-card__head h2 {
    display: flex;
    align-items: center;
    gap: .55rem;
    font-size: 1.05rem;
    margin: 0;
}

.ac-card__head h2 i {
    color: var(--accent);
    font-size: 1rem;
}

.ac-card__link {
    font-size: .88rem;
    font-weight: 600;
    white-space: nowrap;
}

.ac-card__count {
    font-size: .85rem;
    color: var(--muted);
}

/* -------------------------------------------------------------------------
   Order rows
   ---------------------------------------------------------------------- */

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

.ac-order {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto auto;
    align-items: center;
    gap: .75rem 1rem;
    padding: .85rem .25rem;
    border-top: 1px solid var(--line);
}

.ac-order:first-child {
    border-top: 0;
    padding-top: 0;
}

.ac-order__main {
    min-width: 0;
}

.ac-order__no {
    display: block;
    font-weight: 600;
    color: var(--ink);
    font-size: .95rem;
    font-variant-numeric: tabular-nums;
}

.ac-order__date {
    display: block;
    font-size: .8rem;
    color: var(--muted);
}

.ac-order__total {
    font-weight: 700;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.ac-order__go {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .4rem .75rem;
    border-radius: 8px;
    border: 1px solid var(--line);
    color: var(--primary);
    font-size: .84rem;
    font-weight: 600;
    white-space: nowrap;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}

.ac-order__go:hover {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

/* --- status chip --- */

/**
 * The colours are meaning, not decoration: amber while the shop still owes
 * them something, green when it is done, red when it is not happening.
 *
 * None of the three is a brand token. A shop whose primary is red must not
 * have "delivered" read as a failure, which is exactly what would happen if
 * these followed the palette.
 */
.ochip {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .28rem .6rem;
    border-radius: 999px;
    font-size: .78rem;
    font-weight: 600;
    white-space: nowrap;
    border: 1px solid transparent;
}

.ochip i {
    font-size: .85rem;
}

.ochip--wait {
    background: rgba(180, 83, 9, .09);
    border-color: rgba(180, 83, 9, .2);
    color: #b45309;
}

.ochip--done {
    background: rgba(21, 128, 61, .09);
    border-color: rgba(21, 128, 61, .2);
    color: #15803d;
}

.ochip--stop {
    background: rgba(190, 18, 60, .08);
    border-color: rgba(190, 18, 60, .2);
    color: #be123c;
}

/* -------------------------------------------------------------------------
   Addresses
   ---------------------------------------------------------------------- */

.ac-addresses {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .7rem;
}

.ac-address {
    border: 1px solid var(--line);
    border-radius: 11px;
    padding: .9rem 1rem;
    background: var(--wash);
}

/* The one that will actually be used at checkout says so twice — with the
   flag, and by not looking like the others. */
.ac-address.is-default {
    background: var(--paper);
    border-color: var(--primary);
}

.ac-address__top {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-bottom: .35rem;
}

.ac-address__label {
    font-family: "Sora", sans-serif;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--muted);
}

.ac-address__flag {
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: #fff;
    background: var(--primary);
    border-radius: 999px;
    padding: .1rem .45rem;
}

.ac-address__name {
    margin: 0;
    font-weight: 600;
    color: var(--ink);
    font-size: .95rem;
}

.ac-address__lines {
    margin: .2rem 0 0;
    font-size: .88rem;
    color: var(--body);
    line-height: 1.6;
}

.ac-address__phone {
    margin: .4rem 0 0;
    font-size: .85rem;
    color: var(--muted);
}

/* -------------------------------------------------------------------------
   Empty states
   ---------------------------------------------------------------------- */

.ac-empty {
    text-align: center;
    padding: 2.75rem 1rem;
}

.ac-empty--tight {
    padding: 1.75rem 1rem;
}

.ac-empty>i {
    display: block;
    font-size: 1.9rem;
    color: var(--muted);
    margin-bottom: .6rem;
}

.ac-empty h3 {
    font-size: 1.05rem;
    margin: 0 0 .35rem;
}

.ac-empty p {
    margin: 0 auto 1.25rem;
    max-width: 28rem;
    color: var(--muted);
    font-size: .9rem;
    line-height: 1.65;
}

.ac-empty--tight p {
    margin-bottom: 0;
}

/* -------------------------------------------------------------------------
   Wishlist
   ---------------------------------------------------------------------- */

/* The card is shared with every listing on the site, so the remove button
   sits over it rather than inside it — the card must not learn about
   wishlists to be used on one. */
.wl-item {
    position: relative;
}

.wl-remove {
    position: absolute;
    top: .5rem;
    inset-inline-end: .5rem;
    z-index: 2;
    margin: 0;
}

.wl-remove button {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    border: 0;
    display: grid;
    place-items: center;
    cursor: pointer;
    font-size: .78rem;
    background: rgba(255, 255, 255, .92);
    color: var(--body);
    box-shadow: 0 2px 8px rgba(10, 22, 51, .18);
    transition: background .15s ease, color .15s ease;
}

.wl-remove button:hover {
    background: var(--deal);
    color: #fff;
}

/* Hover only reveals it on a pointer. On a touch screen there is no hover, so
   the button has to be there from the start or the list cannot be left. */
@media (hover: hover) {
    .wl-remove {
        opacity: 0;
        transition: opacity .18s ease;
    }

    .wl-item:hover .wl-remove,
    .wl-item:focus-within .wl-remove {
        opacity: 1;
    }
}

.wl-saved {
    margin: .4rem 0 0;
    font-size: .76rem;
    color: var(--muted);
    text-align: center;
}

/* -------------------------------------------------------------------------
   Small screens
   ---------------------------------------------------------------------- */

@media (max-width: 991.98px) {
    .ac-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 767.98px) {
    .ac-id {
        padding: 1.1rem;
        gap: .8rem;
    }

    .ac-id__avatar {
        flex-basis: 46px;
        width: 46px;
        height: 46px;
        font-size: 1.15rem;
    }

    /* The word goes, the icon stays — the way out must not cost half the row. */
    .ac-id__out span {
        display: none;
    }

    .ac-id__out {
        padding: .55rem .7rem;
    }

    /**
     * The order row stops being a table.
     *
     * Four columns need about 420px before the date and the receipt button
     * start fighting each other. Below that it becomes two rows: the number
     * and date across the top, then the chip, the total and the receipt in a
     * line under it.
     */
    .ac-order {
        grid-template-columns: 1fr auto;
        gap: .5rem .75rem;
    }

    .ac-order__main {
        grid-column: 1 / -1;
    }

    /* A grid item fills its track unless told otherwise, and a status chip
       stretched across half the row stops reading as a chip. */
    .ac-order .ochip {
        justify-self: start;
    }

    .ac-order__total {
        text-align: end;
    }

    .ac-order__go {
        grid-column: 1 / -1;
        justify-content: center;
    }
}

@media (max-width: 575.98px) {

    /**
     * Three tabs, one row, no swiping.
     *
     * At 1rem of padding each the row comes to 379px and a 390px phone gives
     * it 343 — so "Wishlist" sat half off the edge, and a nav item you have to
     * discover by dragging is one most people never find. Tightening the
     * padding brings all three inside, and the scroller stays as the fallback
     * for a shop that adds a fourth.
     */
    .ac-tab {
        padding: .6rem .7rem;
        font-size: .88rem;
        gap: .4rem;
    }
}

@media (prefers-reduced-motion: reduce) {

    a.ac-tile:hover {
        transform: none;
    }
}

/* color-mix is recent enough to want a floor under it, or the tile icon plate
   simply does not paint. */
@supports not (background: color-mix(in srgb, red 9%, transparent)) {
    .ac-tile__icon {
        background: rgba(0, 43, 127, .09);
    }
}

/* =========================================================================
   Track your order
   =========================================================================
   The stage line is the whole page. Everything else here is furniture around
   it, kept deliberately quiet: a shopper who lands on this page is asking one
   question, and a screen that answers it in the first two seconds has done its
   job whether or not they read another word.
   ====================================================================== */

.trk {
    padding-top: 2.5rem;
}

/* ---- the lookup ---- */

.trk__ask {
    max-width: 41rem;
    margin: 0 auto 2.5rem;
    text-align: center;
}

/* Once an order is on screen the box stops being the point and becomes the
   way to look up a different one, so it gives up its heading and its width. */
.trk__ask--slim {
    max-width: 34rem;
    margin-bottom: 2rem;
}

.trk__title {
    font-size: clamp(1.7rem, 3.6vw, 2.5rem);
    margin: 0 0 .7rem;
}

.trk__lead {
    color: var(--body);
    margin: 0 auto 1.6rem;
    max-width: 34rem;
}

.trk__lead code {
    background: var(--wash);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: .05rem .35rem;
    font-size: .92em;
    color: var(--ink);
}

.trk__form {
    display: flex;
    gap: .6rem;
    align-items: stretch;
}

.trk__form input {
    flex: 1;
    min-width: 0;
    padding: .85rem 1.1rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    font: inherit;
    color: var(--ink);
    box-shadow: var(--shadow);
    transition: border-color .15s ease, box-shadow .15s ease;
}

.trk__form input::placeholder { color: var(--muted); }

.trk__form input:focus {
    outline: 0;
    border-color: var(--primary);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--primary) 14%, transparent);
}

.trk__form .btn-accent { flex-shrink: 0; }

.trk__error {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    margin: 0 0 1rem;
    padding: .8rem 1.1rem;
    border-radius: var(--radius);
    border: 1px solid color-mix(in srgb, var(--deal) 28%, transparent);
    background: color-mix(in srgb, var(--deal) 8%, transparent);
    color: var(--deal);
    font-weight: 600;
    font-size: .93rem;
    text-align: left;
}

/* ---- the order's own header ---- */

.trk__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    max-width: 62rem;
    margin: 0 auto 1.5rem;
}

.trk__num {
    display: block;
    font-family: "Sora", sans-serif;
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--ink);
}

.trk__placed {
    display: block;
    font-size: .88rem;
    color: var(--muted);
    margin-top: .15rem;
}

/* One chip, six meanings. The colour carries the meaning and the label
   repeats it, because a colour alone is not a status to anyone who cannot
   tell two of them apart. */
.badge-status {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .4rem .85rem;
    border-radius: 999px;
    font-size: .82rem;
    font-weight: 700;
    letter-spacing: .01em;
    border: 1px solid transparent;
    white-space: nowrap;
}

.badge-status--pending    { background: #fff7e6; color: #a15c07; border-color: #f8d9a0; }
.badge-status--processing { background: #eef2ff; color: #3730a3; border-color: #c7d2fe; }
.badge-status--shipped    { background: #ecfeff; color: #0e7490; border-color: #a5f3fc; }
.badge-status--delivered  { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.badge-status--cancelled  { background: #fef2f2; color: #b91c1c; border-color: #fecaca; }
.badge-status--refunded   { background: #f5f3ff; color: #6d28d9; border-color: #ddd6fe; }

/* ---- the stage line ---- */

.trk__line {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0;
    list-style: none;
    max-width: 62rem;
    margin: 0 auto 2.5rem;
    padding: 2rem 1.5rem 1.6rem;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}

.trk__stage {
    position: relative;
    display: grid;
    justify-items: center;
    gap: .1rem;
    text-align: center;
    padding: 0 .3rem;
}

/* The rail runs behind the dots, drawn by each stage from its own dot back to
   the one before it — so the line is exactly as long as the stages are wide,
   whatever the container does. */
.trk__stage::before {
    content: "";
    position: absolute;
    top: 21px;
    right: 50%;
    left: -50%;
    height: 3px;
    border-radius: 3px;
    background: var(--line);
}

.trk__stage:first-child::before { display: none; }

/* A reached stage colours the rail behind it: the filled part of the line is
   how far the parcel has come. */
.trk__stage.is-done::before,
.trk__stage.is-current::before { background: var(--primary); }

.trk__dot {
    position: relative;
    z-index: 1;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--paper);
    border: 3px solid var(--line);
    color: var(--muted);
    font-size: 1.15rem;
    margin-bottom: .55rem;
    transition: background .2s ease, border-color .2s ease, color .2s ease;
}

.trk__stage.is-done .trk__dot {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

/* The stage it is at now is the one the eye should find first: filled in the
   accent, and haloed so it reads as live rather than merely reached. */
.trk__stage.is-current .trk__dot {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 18%, transparent);
}

.trk__stage-name {
    font-weight: 650;
    font-size: .92rem;
    color: var(--ink);
    line-height: 1.3;
}

.trk__stage.is-todo .trk__stage-name { color: var(--muted); font-weight: 500; }

.trk__stage-at {
    font-size: .78rem;
    color: var(--muted);
    min-height: 1.1em;
}

.trk__stage.is-current .trk__stage-at { color: var(--accent); font-weight: 650; }

/* ---- cancelled / refunded ---- */

.trk__stopped {
    display: flex;
    align-items: center;
    gap: 1.1rem;
    flex-wrap: wrap;
    max-width: 62rem;
    margin: 0 auto 2.5rem;
    padding: 1.4rem 1.5rem;
    border-radius: var(--radius);
    background: var(--paper);
    border: 1px solid var(--line);
    border-left: 4px solid var(--deal);
    box-shadow: var(--shadow);
}

.trk__stopped--refunded { border-left-color: #6d28d9; }

.trk__stopped > i {
    font-size: 1.7rem;
    color: var(--deal);
    flex-shrink: 0;
}

.trk__stopped--refunded > i { color: #6d28d9; }

.trk__stopped > div { flex: 1; min-width: 15rem; }
.trk__stopped strong { color: var(--ink); font-size: 1.02rem; }
.trk__stopped span { color: var(--muted); font-size: .86rem; margin-left: .45rem; }
.trk__stopped p { margin: .3rem 0 0; font-size: .9rem; color: var(--body); }

/* ---- the detail ---- */

.trk__grid {
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    gap: 1.25rem;
    max-width: 62rem;
    margin-inline: auto;
    align-items: start;
}

.trk__card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.35rem 1.5rem;
}

.trk__card-title {
    display: flex;
    align-items: center;
    gap: .55rem;
    font-size: 1rem;
    margin: 0 0 1.1rem;
    padding-bottom: .8rem;
    border-bottom: 1px solid var(--line);
}

.trk__card-title i { color: var(--primary); }

.trk__count {
    margin-left: auto;
    min-width: 22px;
    padding: .1rem .45rem;
    border-radius: 999px;
    background: var(--wash);
    color: var(--muted);
    font-size: .76rem;
    font-weight: 700;
    text-align: center;
}

.trk__items {
    list-style: none;
    padding: 0;
    margin: 0 0 1.1rem;
}

.trk__items li {
    display: grid;
    grid-template-columns: 1fr auto auto;
    align-items: baseline;
    gap: .9rem;
    padding: .6rem 0;
    border-bottom: 1px dashed var(--line);
}

.trk__items li:last-child { border-bottom: 0; }

.trk__item-name { font-weight: 600; color: var(--ink); font-size: .93rem; line-height: 1.35; }

.trk__sku {
    display: block;
    font-weight: 500;
    font-size: .76rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.trk__qty { color: var(--muted); font-size: .88rem; font-variant-numeric: tabular-nums; }
.trk__money { font-weight: 650; color: var(--ink); font-variant-numeric: tabular-nums; }

.trk__totals { margin: 0; padding-top: .9rem; border-top: 1px solid var(--line); }

.trk__totals > div {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: .28rem 0;
    font-size: .92rem;
}

.trk__totals dt { color: var(--muted); margin: 0; }
.trk__totals dd { margin: 0; font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }
.trk__totals .is-off dd { color: var(--deal); }

.trk__total {
    margin-top: .35rem;
    padding-top: .6rem !important;
    border-top: 1px solid var(--line);
    font-size: 1.05rem !important;
}

.trk__total dt { color: var(--ink) !important; font-weight: 700; }
.trk__total dd { font-weight: 800; font-size: 1.15rem; color: var(--primary); }

.trk__address {
    display: grid;
    gap: .2rem;
    font-style: normal;
    font-size: .92rem;
    color: var(--body);
    line-height: 1.5;
}

.trk__address strong { color: var(--ink); font-size: .98rem; }
.trk__phone { margin-top: .35rem; color: var(--ink); font-weight: 600; }
.trk__phone i { color: var(--primary); margin-right: .3rem; }

.trk__meta { margin: 1.1rem 0 0; padding-top: .9rem; border-top: 1px solid var(--line); }
.trk__meta > div { display: flex; justify-content: space-between; gap: 1rem; align-items: center; }
.trk__meta dt { color: var(--muted); font-size: .88rem; margin: 0; }
.trk__meta dd { margin: 0; font-size: .9rem; font-weight: 600; color: var(--ink); }

.trk__pay {
    display: inline-block;
    margin-left: .4rem;
    padding: .12rem .5rem;
    border-radius: 999px;
    font-size: .74rem;
    font-weight: 700;
}

.trk__pay--paid     { background: #ecfdf5; color: #047857; }
.trk__pay--unpaid   { background: #fff7e6; color: #a15c07; }
.trk__pay--failed   { background: #fef2f2; color: #b91c1c; }
.trk__pay--refunded { background: #f5f3ff; color: #6d28d9; }

.trk__help {
    margin: 1.1rem 0 0;
    padding-top: .9rem;
    border-top: 1px solid var(--line);
    font-size: .87rem;
    color: var(--muted);
}

/* ---- narrower screens ---- */

@media (max-width: 767.98px) {
    .trk__grid { grid-template-columns: 1fr; }

    /* The line stands up. Four stages across a phone leaves each label two
       words wide and stacked three deep; down the side they read normally and
       the rail still shows the distance covered. */
    .trk__line {
        grid-template-columns: 1fr;
        justify-items: start;
        padding: 1.4rem 1.25rem;
    }

    .trk__stage {
        grid-template-columns: auto 1fr auto;
        justify-items: start;
        align-items: center;
        text-align: left;
        gap: .1rem .9rem;
        padding: .55rem 0;
        width: 100%;
    }

    .trk__stage::before {
        top: -50%;
        bottom: 50%;
        left: 21px;
        right: auto;
        width: 3px;
        height: auto;
    }

    .trk__dot { margin-bottom: 0; }
    .trk__stage-at { text-align: right; }
}

@media (max-width: 479.98px) {
    .trk__form { flex-direction: column; }
    .trk__form .btn-accent { justify-content: center; }
}

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

/* color-mix is recent enough to want a floor under it. */
@supports not (background: color-mix(in srgb, red 8%, transparent)) {
    .trk__error { border-color: rgba(225, 29, 72, .28); background: rgba(225, 29, 72, .08); }
    .trk__stage.is-current .trk__dot { box-shadow: 0 0 0 6px rgba(255, 90, 0, .18); }
}

/* An order with no line items behind it — imported, or seeded. */
.trk__none {
    margin: 0 0 1rem;
    padding: .8rem 1rem;
    border-radius: var(--radius);
    background: var(--wash);
    border: 1px dashed var(--line);
    color: var(--muted);
    font-size: .88rem;
}

/* =========================================================================
   Sign in, register, forgotten password, reset
   =========================================================================
   Four screens, one frame: a brand panel on the left and the form on the
   right. They are the same moment wearing four hats — somebody proving who
   they are — and a sign-in page that looks unlike the register page it links
   to is the cheapest way to make a shop feel untrustworthy at exactly the
   moment a customer is typing a password into it.

   The fields borrow .ct-field from the contact form rather than growing a
   second set. One form look across the site, one place to change it.
   ====================================================================== */

.au {
    padding: 2.5rem 0 4rem;
}

/**
 * The split.
 *
 * 1fr / 1fr rather than a narrow form column: the panel is not a decoration
 * strip, it is the half of the screen the form is not using, and making it
 * thinner leaves the form floating oddly to one side of a wide monitor.
 *
 * Capped and centred so the pair does not stretch to 1320px, where the two
 * halves would drift too far apart to read as one card.
 */
.au-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    max-width: 980px;
    margin-inline: auto;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 18px;
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}

/* -------------------------------------------------------------------------
   Brand side
   ---------------------------------------------------------------------- */

.au-brand {
    position: relative;
    overflow: hidden;
    background: var(--primary-deep);
    display: flex;
    align-items: center;
    padding: 2.5rem 2rem;
}

.au-brand__glow {
    position: absolute;
    inset-block-start: -30%;
    inset-inline-start: -20%;
    width: 130%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255, 255, 255, .16), transparent 60%);
    pointer-events: none;
}

.au-brand__inner {
    position: relative;
}

.au-brand__logo {
    max-height: 44px;
    width: auto;
    margin-bottom: 1.25rem;
}

.au-brand__name {
    display: block;
    color: #fff;
    font-family: "Sora", sans-serif;
    font-size: 1.6rem;
    font-weight: 800;
    letter-spacing: -.03em;
    margin-bottom: 1rem;
}

.au-brand__line {
    color: rgba(255, 255, 255, .8);
    font-size: .98rem;
    line-height: 1.7;
    margin: 0 0 1.75rem;
    max-width: 22rem;
}

.au-brand__points {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .7rem;
}

.au-brand__points li {
    display: flex;
    align-items: center;
    gap: .65rem;
    color: rgba(255, 255, 255, .9);
    font-size: .92rem;
    font-weight: 500;
}

.au-brand__points i {
    color: var(--accent);
    font-size: 1.05rem;
    flex: 0 0 auto;
}

/* -------------------------------------------------------------------------
   Form side
   ---------------------------------------------------------------------- */

.au-panel {
    padding: clamp(1.5rem, 4vw, 2.5rem);
}

.au-head {
    margin-bottom: 1.5rem;
}

.au-head__mark {
    width: 44px;
    height: 44px;
    border-radius: 13px;
    display: grid;
    place-items: center;
    margin-bottom: .9rem;
    font-size: 1.15rem;
    background: var(--wash);
    background: color-mix(in srgb, var(--primary) 10%, transparent);
    color: var(--primary);
}

.au-head h1 {
    font-size: clamp(1.35rem, 3vw, 1.75rem);
    margin: 0 0 .35rem;
    letter-spacing: -.025em;
}

.au-head p {
    margin: 0;
    color: var(--muted);
    font-size: .93rem;
    line-height: 1.6;
}

.au-form {
    margin-bottom: 1.25rem;
}

/* "Forgotten?" sits on the password label's own line, at the far end — the
   one place somebody looks when the password is the thing going wrong. */
.ct-field__aside {
    float: inline-end;
    font-size: .82rem;
    font-weight: 600;
}

.ct-field__hint {
    display: block;
    margin-top: .3rem;
    font-size: .8rem;
    color: var(--muted);
}

.au-submit {
    width: 100%;
    justify-content: center;
    margin-top: .35rem;
}

.au-small {
    margin: 1rem 0 0;
    font-size: .82rem;
    color: var(--muted);
    line-height: 1.6;
}

/* Which account is about to change. Not a field — there is nothing here to
   decide, and an editable box would only invalidate the token. */
.au-for {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0 0 1.1rem;
    padding: .7rem .85rem;
    border-radius: 10px;
    background: var(--wash);
    border: 1px solid var(--line);
    font-size: .88rem;
    color: var(--body);
    overflow-wrap: anywhere;
}

.au-for i {
    color: var(--muted);
    flex: 0 0 auto;
}

.au-for strong {
    color: var(--ink);
}

.au-alt {
    margin: 0;
    padding-top: 1.1rem;
    border-top: 1px solid var(--line);
    font-size: .92rem;
    color: var(--muted);
}

.au-alt a {
    font-weight: 600;
}

/* The way out. Somebody who landed here by accident, or who would rather
   check out as a guest, must not be stuck on a page that only knows how to
   ask for a password. */
.au-back {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    margin-top: 1rem;
    font-size: .86rem;
    color: var(--muted);
}

.au-back:hover {
    color: var(--primary);
}

/* -------------------------------------------------------------------------
   Small screens
   ---------------------------------------------------------------------- */

@media (max-width: 899.98px) {

    /* The brand half goes entirely rather than stacking above the form. On a
       phone the form is the whole point, and anything above it is scrolling
       between a customer and the thing they came to do. */
    .au-brand {
        display: none;
    }

    .au-split {
        grid-template-columns: minmax(0, 1fr);
        max-width: 30rem;
    }

    .au {
        padding: 1.5rem 0 3rem;
    }
}

/* color-mix is recent enough to want a floor under it, or the mark's plate
   simply does not paint. */
@supports not (background: color-mix(in srgb, red 10%, transparent)) {
    .au-head__mark {
        background: rgba(0, 43, 127, .1);
    }
}

/* =========================================================================
   Checkout — cart and form on one page
   =========================================================================
   Two columns on a desktop: the work on the left in the order a customer
   thinks in, the total riding alongside on the right where it can be seen
   without scrolling back. One column on a phone, summary last, because there
   the total belongs next to the button that commits to it.
   ====================================================================== */

.co { padding-top: 1.75rem; }

.co-head {
    display: flex;
    align-items: baseline;
    gap: .8rem;
    flex-wrap: wrap;
    margin-bottom: 1.4rem;
}

.co-head h1 {
    font-size: clamp(1.5rem, 3vw, 2.1rem);
    margin: 0;
}

.co-head__count {
    color: var(--muted);
    font-size: .92rem;
    font-weight: 600;
}

.co-flash {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0 0 1rem;
    padding: .75rem 1rem;
    border-radius: var(--radius);
    background: var(--paper);
    border: 1px solid var(--line);
    border-left: 3px solid var(--primary);
    color: var(--body);
    font-size: .9rem;
    box-shadow: var(--shadow);
}

.co-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 22rem;
    gap: 1.25rem;
    align-items: start;
}

.co-main { display: grid; gap: 1.25rem; min-width: 0; }

/* ---- the cards ---- */

.co-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.35rem 1.5rem;
}

.co-card__title {
    display: flex;
    align-items: center;
    gap: .7rem;
    font-size: 1.05rem;
    margin: 0 0 1.2rem;
    padding-bottom: .85rem;
    border-bottom: 1px solid var(--line);
}

.co-card__link {
    margin-left: auto;
    font-size: .85rem;
    font-weight: 600;
}

/* The numbers are the spine of the page: three steps, in order, and you can
   see at a glance which one you are on. */
.co-step {
    width: 26px;
    height: 26px;
    flex-shrink: 0;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--primary);
    color: #fff;
    font-size: .82rem;
    font-weight: 700;
    font-family: "Sora", sans-serif;
}

/* ---- cart lines ---- */

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

.co-line {
    display: grid;
    grid-template-columns: 72px minmax(0, 1fr) auto auto auto;
    align-items: center;
    gap: 1rem;
    padding: .95rem 0;
    border-bottom: 1px dashed var(--line);
    transition: opacity .15s ease;
}

.co-line:first-child { padding-top: 0; }
.co-line:last-child { border-bottom: 0; padding-bottom: 0; }

/* While a quantity change is in flight. Not a spinner — the row is still
   readable, it just cannot be clicked twice. */
.co-line.is-busy { opacity: .55; pointer-events: none; }

.co-line.is-out .co-line__img,
.co-line.is-out .co-line__name { opacity: .6; }

.co-line__img {
    width: 72px;
    height: 72px;
    border-radius: 10px;
    overflow: hidden;
    background: var(--wash);
    border: 1px solid var(--line);
    display: block;
}

.co-line__img img { width: 100%; height: 100%; object-fit: cover; display: block; }

.co-line__body { display: grid; gap: .15rem; min-width: 0; }

.co-line__name {
    font-weight: 650;
    color: var(--ink);
    font-size: .95rem;
    line-height: 1.35;
}

.co-line__name:hover { color: var(--primary); }

.co-line__variant {
    font-size: .8rem;
    color: var(--muted);
}

.co-line__unit { font-size: .86rem; color: var(--body); }
.co-line__unit s { color: var(--muted); margin-left: .3rem; font-size: .92em; }

.co-line__stock {
    font-size: .76rem;
    font-weight: 700;
    margin-top: .1rem;
}

.co-line__stock.is-low { color: var(--accent); }
.co-line__stock.is-out { color: var(--deal); }

/* The stepper is three separate forms sitting in one shell, so it keeps
   working with JavaScript off. The shell is what makes them read as one
   control. */
.co-qty {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    overflow: hidden;
}

.co-qty form { display: flex; margin: 0; }

.co-qty button {
    width: 32px;
    height: 34px;
    border: 0;
    background: none;
    color: var(--ink);
    cursor: pointer;
    display: grid;
    place-items: center;
    font-size: .85rem;
    transition: background .13s ease, color .13s ease;
}

.co-qty button:hover:not(:disabled) { background: var(--wash); color: var(--primary); }
.co-qty button:disabled { opacity: .3; cursor: default; }

.co-qty__n {
    min-width: 2rem;
    text-align: center;
    font-weight: 700;
    font-size: .9rem;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

.co-line__total {
    font-weight: 700;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    min-width: 5.5rem;
    text-align: right;
}

.co-line__drop button {
    width: 30px;
    height: 30px;
    border: 1px solid transparent;
    border-radius: 8px;
    background: none;
    color: var(--muted);
    cursor: pointer;
    display: grid;
    place-items: center;
    font-size: .8rem;
    transition: color .13s ease, background .13s ease, border-color .13s ease;
}

.co-line__drop button:hover {
    color: var(--deal);
    background: color-mix(in srgb, var(--deal) 8%, transparent);
    border-color: color-mix(in srgb, var(--deal) 22%, transparent);
}

/* ---- the form ---- */

.co-fields {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

.co-field { display: grid; gap: .35rem; }
.co-field--wide { grid-column: 1 / -1; }

.co-field__label {
    font-size: .86rem;
    font-weight: 650;
    color: var(--ink);
}

.co-field__label em {
    font-style: normal;
    font-weight: 500;
    color: var(--muted);
    margin-left: .3rem;
    font-size: .92em;
}

.co-field input,
.co-field textarea,
.co-notes textarea {
    width: 100%;
    padding: .7rem .9rem;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--paper);
    font: inherit;
    font-size: .93rem;
    color: var(--ink);
    resize: vertical;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.co-field input:focus,
.co-field textarea:focus,
.co-notes textarea:focus,
.co-coupon input:focus {
    outline: 0;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 13%, transparent);
}

.co-field__help { font-size: .78rem; color: var(--muted); }

.co-notes { display: grid; gap: .35rem; margin-top: 1rem; }

.co-save {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-top: .9rem;
    font-size: .89rem;
    color: var(--body);
    cursor: pointer;
}

/* ---- delivery areas ---- */

.co-zones {
    border: 0;
    padding: 0;
    margin: 1.2rem 0 0;
    display: grid;
    gap: .5rem;
}

.co-zones legend {
    font-size: .86rem;
    font-weight: 650;
    color: var(--ink);
    padding: 0;
    margin-bottom: .2rem;
}

.co-zone {
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .7rem .9rem;
    border: 1px solid var(--line);
    border-radius: 10px;
    cursor: pointer;
    transition: border-color .14s ease, background .14s ease;
}

.co-zone:hover { border-color: var(--primary); }

.co-zone:has(input:checked) {
    border-color: var(--primary);
    background: color-mix(in srgb, var(--primary) 5%, transparent);
}

.co-zone__name { flex: 1; font-size: .92rem; color: var(--ink); font-weight: 600; }
.co-zone__cost { font-weight: 700; color: var(--primary); font-variant-numeric: tabular-nums; }

/* ---- payment ---- */

.co-pays { display: grid; gap: .6rem; }

.co-pay {
    border: 1px solid var(--line);
    border-radius: 10px;
    overflow: hidden;
    transition: border-color .14s ease;
}

.co-pay:has(input:checked) { border-color: var(--primary); }

.co-pay__pick {
    display: flex;
    align-items: center;
    gap: .8rem;
    padding: .85rem 1rem;
    cursor: pointer;
}

.co-pay:has(input:checked) .co-pay__pick {
    background: color-mix(in srgb, var(--primary) 5%, transparent);
}

.co-pay__icon {
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    border-radius: 9px;
    display: grid;
    place-items: center;
    background: var(--wash);
    color: var(--primary);
    font-size: 1.15rem;
}

.co-pay__text { display: grid; gap: .05rem; flex: 1; min-width: 0; }
.co-pay__text strong { font-size: .94rem; color: var(--ink); }
.co-pay__text span { font-size: .82rem; color: var(--muted); }

.co-pay__tag {
    flex-shrink: 0;
    padding: .15rem .5rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--primary) 10%, transparent);
    color: var(--primary);
    font-size: .7rem;
    font-weight: 700;
}

.co-pay__how {
    padding: .9rem 1rem 1rem;
    border-top: 1px dashed var(--line);
    background: var(--wash);
}

.co-pay__acct {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    margin: 0 0 .6rem;
    font-size: .88rem;
}

.co-pay__acct span { color: var(--muted); }
.co-pay__acct strong {
    color: var(--ink);
    font-size: 1rem;
    font-variant-numeric: tabular-nums;
    letter-spacing: .02em;
}

.co-copy {
    padding: .22rem .6rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    color: var(--primary);
    font: inherit;
    font-size: .76rem;
    font-weight: 700;
    cursor: pointer;
    transition: background .13s ease, color .13s ease;
}

.co-copy:hover { background: var(--primary); color: #fff; border-color: var(--primary); }
.co-copy.is-done { background: var(--primary); color: #fff; border-color: var(--primary); }

.co-pay__steps {
    margin: 0;
    padding-left: 1.15rem;
    display: grid;
    gap: .25rem;
    font-size: .86rem;
    color: var(--body);
}

.co-pay__hint { margin: .6rem 0 0; font-size: .83rem; color: var(--muted); }

/* ---- the summary ---- */

.co-side { position: sticky; top: 1rem; }

.co-sum { padding: 1.25rem 1.35rem; }

.co-coupon { display: flex; gap: .5rem; margin-bottom: .9rem; }

.co-coupon input {
    flex: 1;
    min-width: 0;
    padding: .6rem .8rem;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--paper);
    font: inherit;
    font-size: .88rem;
    color: var(--ink);
}

.co-coupon__go {
    padding: .6rem 1rem;
    border: 1px solid var(--primary);
    border-radius: 9px;
    background: var(--primary);
    color: #fff;
    font: inherit;
    font-size: .85rem;
    font-weight: 650;
    cursor: pointer;
    transition: background .14s ease;
}

.co-coupon__go:hover { background: var(--primary-deep); }

.co-coupon.is-on {
    align-items: center;
    justify-content: space-between;
    padding: .55rem .8rem;
    border-radius: 9px;
    border: 1px dashed color-mix(in srgb, var(--primary) 35%, transparent);
    background: color-mix(in srgb, var(--primary) 6%, transparent);
    font-size: .88rem;
    font-weight: 650;
    color: var(--primary);
}

.co-coupon__drop {
    border: 0;
    background: none;
    color: var(--muted);
    font: inherit;
    font-size: .8rem;
    text-decoration: underline;
    cursor: pointer;
}

.co-coupon__drop:hover { color: var(--deal); }

.co-offers { list-style: none; display: flex; flex-wrap: wrap; gap: .35rem; margin: 0 0 .9rem; padding: 0; }

.co-offer {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .22rem .6rem;
    border: 1px dashed var(--line);
    border-radius: 999px;
    background: var(--paper);
    color: var(--body);
    font: inherit;
    font-size: .76rem;
    font-weight: 650;
    cursor: pointer;
    transition: border-color .13s ease, color .13s ease;
}

.co-offer:hover { border-color: var(--primary); color: var(--primary); }

.co-tot { margin: 0; padding-top: .9rem; border-top: 1px solid var(--line); }

.co-tot > div {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: .3rem 0;
    font-size: .92rem;
}

.co-tot dt { color: var(--muted); margin: 0; }
.co-tot dd { margin: 0; font-weight: 650; color: var(--ink); font-variant-numeric: tabular-nums; }
.co-tot .is-off dd { color: var(--deal); }

.co-tot__grand {
    margin-top: .4rem;
    padding-top: .7rem !important;
    border-top: 1px solid var(--line);
}

.co-tot__grand dt { color: var(--ink) !important; font-weight: 700; font-size: 1rem; }
.co-tot__grand dd { font-size: 1.25rem; font-weight: 800; color: var(--primary); }

.co-place {
    width: 100%;
    justify-content: center;
    margin-top: 1.1rem;
}

.co-place.is-sending { opacity: .7; cursor: progress; }

.co-trust {
    list-style: none;
    margin: 1.1rem 0 0;
    padding: 1rem 0 0;
    border-top: 1px solid var(--line);
    display: grid;
    gap: .5rem;
    font-size: .83rem;
    color: var(--body);
}

.co-trust li { display: flex; align-items: flex-start; gap: .5rem; }
.co-trust i { color: var(--primary); margin-top: .1rem; flex-shrink: 0; }

.co-trust--soft { border-top: 0; padding-top: 0; margin-top: .5rem; color: var(--muted); }
.co-trust--soft i { color: var(--muted); }

/* ---- empty ---- */

.co-empty {
    max-width: 28rem;
    margin: 2rem auto 3rem;
    text-align: center;
}

.co-empty__icon {
    width: 76px;
    height: 76px;
    margin: 0 auto 1.2rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--wash);
    border: 1px solid var(--line);
    color: var(--muted);
    font-size: 1.9rem;
}

.co-empty h1 { font-size: 1.4rem; margin: 0 0 .5rem; }
.co-empty p { color: var(--muted); margin: 0 0 1.5rem; }

/* ---- narrower screens ---- */

@media (max-width: 991.98px) {
    .co-grid { grid-template-columns: 1fr; }

    /* Unstuck and last: on one column the summary belongs at the end, next to
       the button that commits to the number in it. */
    .co-side { position: static; }
}

@media (max-width: 575.98px) {
    .co-fields { grid-template-columns: 1fr; }

    /* The line rearranges rather than shrinking: picture and name on the top
       row, the controls underneath where a thumb can reach them. */
    .co-line {
        grid-template-columns: 56px minmax(0, 1fr) auto;
        gap: .75rem;
        row-gap: .6rem;
    }

    .co-line__img { width: 56px; height: 56px; }
    /* justify-self, or the stepper stretches across the whole 1fr column and
       reads as a text field rather than as three buttons. */
    .co-qty { grid-column: 2; justify-self: start; }
    .co-line__total { grid-column: 3; min-width: 0; }
    .co-line__drop { grid-row: 1; grid-column: 3; align-self: start; }
}

@media (prefers-reduced-motion: reduce) {
    .co-line, .co-qty button, .co-zone, .co-pay, .co-copy, .co-offer { transition: none; }
}

/* color-mix is recent enough to want a floor under it. */
@supports not (background: color-mix(in srgb, red 5%, transparent)) {
    .co-zone:has(input:checked),
    .co-pay:has(input:checked) .co-pay__pick { background: rgba(0, 43, 127, .05); }
    .co-coupon.is-on { background: rgba(0, 43, 127, .06); border-color: rgba(0, 43, 127, .35); }
    .co-pay__tag { background: rgba(0, 43, 127, .1); }
}

/* =========================================================================
   One product
   =========================================================================
   The page that has to close the sale, so it is laid out by what a shopper
   decides in: the picture, the price against what it used to be, whether it
   is in stock, then the detail.

   Four ways to buy, and they are deliberately not four equal buttons. Buy now
   is the one the page exists for and it is the only thing on the page that
   moves; the rest sit at the weight their job deserves.
   ====================================================================== */

.pd {
    padding: 1.5rem 0 3.5rem;
}

.pd-top {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 2.5rem;
    align-items: start;
    margin-bottom: 2.5rem;
}

/* -------------------------------------------------------------------------
   Gallery
   ---------------------------------------------------------------------- */

/* Sticks while the description and the reviews scroll past. On a long page
   the picture is what a shopper keeps glancing back at. */
.pd-gallery {
    position: sticky;
    top: 5.5rem;
}

.pd-stage {
    position: relative;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--wash);
    border: 1px solid var(--line);
}

/* The pictures sit side by side in a scroll container and the browser moves
   between them. That is what buys the swipe on a phone for nothing, and it is
   why the gallery still works with the script off — the arrows are the only
   part that needs JavaScript, and they ship hidden until it runs. */
.pd-track {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.pd-track::-webkit-scrollbar {
    display: none;
}

.pd-track:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: -3px;
}

.pd-slide {
    flex: 0 0 100%;
    scroll-snap-align: start;
    scroll-snap-stop: always;
}

.pd-stage img {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    display: block;
}

/* --- the arrows --- */

.pd-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 40px;
    height: 40px;
    border: 1px solid var(--line);
    border-radius: 50%;
    background: var(--paper);
    color: var(--ink);
    display: grid;
    place-items: center;
    cursor: pointer;
    font-size: 1rem;
    box-shadow: var(--shadow);
    transition: background .16s ease, color .16s ease, opacity .16s ease;
}

.pd-arrow--prev { inset-inline-start: .75rem; }
.pd-arrow--next { inset-inline-end: .75rem; }

.pd-arrow:hover:not(:disabled),
.pd-arrow:focus-visible:not(:disabled) {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

/* Dimmed rather than removed: an arrow that vanishes at the end of the strip
   moves the other one under the cursor. */
.pd-arrow:disabled {
    opacity: .35;
    cursor: default;
}

/* A mouse gets the arrows on hover; a touch screen has no hover, so there they
   stay put — and the swipe is the real control anyway. */
@media (hover: hover) {
    .pd-arrow {
        opacity: 0;
    }

    .pd-gallery:hover .pd-arrow,
    .pd-arrow:focus-visible {
        opacity: 1;
    }

    .pd-gallery:hover .pd-arrow:disabled {
        opacity: .35;
    }
}

/* --- which one of how many --- */

.pd-count {
    position: absolute;
    bottom: .75rem;
    inset-inline-end: .75rem;
    z-index: 2;
    padding: .2rem .6rem;
    border-radius: 999px;
    background: rgba(10, 22, 51, .62);
    color: #fff;
    font-size: .76rem;
    font-weight: 600;
    letter-spacing: .02em;
}

@media (prefers-reduced-motion: reduce) {

    /* The gallery still moves between pictures — that is the point of it —
       but it arrives rather than travels. */
    .pd-track {
        scroll-behavior: auto;
    }

    .pd-arrow {
        transition: none;
    }
}

.pd-stage__badge {
    top: .9rem;
    inset-inline-start: .9rem;
    font-size: .82rem;
    padding: .3rem .65rem;
    z-index: 2;
}

.pd-thumbs {
    display: flex;
    gap: .55rem;
    margin-top: .7rem;
    overflow-x: auto;
    scrollbar-width: none;
    padding-bottom: .2rem;
}

.pd-thumbs::-webkit-scrollbar {
    display: none;
}

.pd-thumb {
    flex: 0 0 auto;
    width: 74px;
    height: 74px;
    padding: 0;
    border-radius: 10px;
    overflow: hidden;
    cursor: pointer;
    background: var(--wash);
    border: 2px solid var(--line);
    transition: border-color .15s ease;
}

.pd-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.pd-thumb:hover {
    border-color: var(--muted);
}

.pd-thumb.is-on {
    border-color: var(--primary);
}

/* -------------------------------------------------------------------------
   Buy box
   ---------------------------------------------------------------------- */

.pd-brand {
    margin: 0 0 .5rem;
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
}

.pd-brand span {
    font-family: "Sora", sans-serif;
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--accent);
}

.pd-title {
    font-size: clamp(1.5rem, 3.2vw, 2.15rem);
    letter-spacing: -.03em;
    margin: 0 0 .6rem;
}

.pd-meta {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
    font-size: .88rem;
}

.pd-stars {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    color: var(--star);
}

.pd-stars b {
    color: var(--ink);
}

.pd-stars a {
    color: var(--muted);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.pd-sku {
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.pd-price {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: .6rem;
    margin-bottom: .75rem;
}

.pd-price .price {
    font-family: "Sora", sans-serif;
    font-size: clamp(1.6rem, 3.4vw, 2.1rem);
    font-weight: 800;
    letter-spacing: -.03em;
}

.pd-price .price-old {
    font-size: 1.02rem;
}

.pd-save {
    font-size: .8rem;
    font-weight: 700;
    color: var(--deal);
    background: rgba(225, 29, 72, .09);
    background: color-mix(in srgb, var(--deal) 10%, transparent);
    border-radius: 999px;
    padding: .18rem .6rem;
}

/**
 * Stock, said plainly.
 *
 * "Only 3 left" is both the truth and the most persuasive line on the page,
 * so it is not shrunk into small print. Amber for scarcity, green for plenty,
 * red for none — none of them the brand colour, because the message must read
 * the same whatever the shop paints itself.
 */
.pd-stock {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    margin: 0 0 1rem;
    font-size: .9rem;
    font-weight: 600;
    color: #15803d;
}

.pd-stock.is-low {
    color: #b45309;
}

.pd-stock.is-out {
    color: #be123c;
}

.pd-short {
    margin: 0 0 1.25rem;
    color: var(--body);
    line-height: 1.75;
}

/* --- options --- */

.pd-variants {
    margin-bottom: 1.25rem;
}

.pd-variants__label {
    display: block;
    font-size: .84rem;
    font-weight: 600;
    color: var(--ink);
    margin-bottom: .5rem;
}

.pd-variants__list {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}

/* A whole card is the target, not a 14px radio beside it. */
.pd-variant {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: .1rem;
    padding: .6rem .9rem;
    border-radius: 10px;
    border: 1.5px solid var(--line);
    background: var(--paper);
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease;
}

.pd-variant input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.pd-variant:hover {
    border-color: var(--muted);
}

.pd-variant:has(input:checked) {
    border-color: var(--primary);
    background: var(--wash);
}

/* The keyboard needs to see the focus the mouse does not. */
.pd-variant:has(input:focus-visible) {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

.pd-variant__name {
    font-size: .9rem;
    font-weight: 600;
    color: var(--ink);
}

.pd-variant__price {
    font-size: .82rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.pd-variant.is-out {
    opacity: .5;
    cursor: not-allowed;
}

.pd-variant__out {
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--deal);
}

/* --- quantity + add to cart --- */

.pd-actions {
    display: flex;
    gap: .6rem;
    margin-bottom: .6rem;
}

.pd-qty {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    border: 1px solid var(--line);
    border-radius: 11px;
    overflow: hidden;
    background: var(--paper);
}

.pd-qty button {
    width: 40px;
    height: 46px;
    border: 0;
    background: transparent;
    color: var(--ink);
    cursor: pointer;
    font-size: .95rem;
}

.pd-qty button:hover {
    background: var(--wash);
}

.pd-qty input {
    width: 44px;
    height: 46px;
    border: 0;
    text-align: center;
    font: inherit;
    font-weight: 700;
    color: var(--ink);
    background: transparent;
    font-variant-numeric: tabular-nums;
    -moz-appearance: textfield;
}

.pd-qty input::-webkit-outer-spin-button,
.pd-qty input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.pd-qty input:focus {
    outline: none;
}

/* Outlined, because it is the second-loudest thing here. Buy now below it is
   the primary action and has to win. */
.pd-cart {
    flex: 1 1 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    height: 48px;
    border-radius: 11px;
    border: 1.5px solid var(--primary);
    background: var(--paper);
    color: var(--primary);
    font: inherit;
    font-size: .95rem;
    font-weight: 700;
    cursor: pointer;
    transition: background .15s ease, color .15s ease;
}

.pd-cart:hover {
    background: var(--primary);
    color: #fff;
}

/**
 * Buy now.
 *
 * The one action the page is actually for, and the only thing on it that
 * moves. A shine travels across it every few seconds — long enough apart to
 * read as a highlight rather than a loading bar, and it stops on hover
 * because a button being pressed should not be busy doing something else.
 *
 * The animation is decoration on top of a plain submit button: it carries no
 * information, so a reader who has asked for less motion loses nothing when
 * the reduced-motion rule switches it off.
 */
.pd-now {
    position: relative;
    overflow: hidden;
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .55rem;
    height: 52px;
    border: 0;
    border-radius: 11px;
    background: var(--accent);
    color: #fff;
    font: inherit;
    font-size: 1rem;
    font-weight: 700;
    cursor: pointer;
    box-shadow: 0 10px 26px rgba(255, 90, 0, .3);
    box-shadow: 0 10px 26px color-mix(in srgb, var(--accent) 38%, transparent);
    animation: pdPulse 2.8s ease-in-out infinite;
    transition: transform .15s ease, box-shadow .15s ease;
}

.pd-now:hover {
    transform: translateY(-2px);
    animation-play-state: paused;
}

.pd-now__shine {
    position: absolute;
    inset-block: 0;
    inset-inline-start: -60%;
    width: 45%;
    background: linear-gradient(100deg,
            transparent,
            rgba(255, 255, 255, .38),
            transparent);
    transform: skewX(-18deg);
    animation: pdShine 2.8s ease-in-out infinite;
    pointer-events: none;
}

.pd-now:hover .pd-now__shine {
    animation-play-state: paused;
}

/* Barely there — enough to catch the eye in peripheral vision, not enough to
   make the page feel like it is breathing. */
@keyframes pdPulse {

    0%,
    100% {
        transform: scale(1);
    }

    50% {
        transform: scale(1.015);
    }
}

/* Travels across, then waits. The long tail is the point: a shine that runs
   continuously reads as a progress bar. */
@keyframes pdShine {
    0% {
        inset-inline-start: -60%;
    }

    45%,
    100% {
        inset-inline-start: 130%;
    }
}

.pd-soldout {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0;
    padding: .9rem 1rem;
    border-radius: 11px;
    background: var(--wash);
    border: 1px solid var(--line);
    color: var(--body);
    font-size: .9rem;
}

/* --- WhatsApp and phone --- */

.pd-order {
    margin-top: 1.25rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--line);
}

.pd-order__label {
    display: block;
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: .6rem;
}

.pd-order__row {
    display: flex;
    gap: .6rem;
    flex-wrap: wrap;
}

.pd-wa,
.pd-call {
    flex: 1 1 12rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    height: 46px;
    border-radius: 11px;
    font-size: .93rem;
    font-weight: 700;
    border: 1.5px solid transparent;
    transition: filter .15s ease, background .15s ease, color .15s ease;
}

/* WhatsApp green, not a brand token. It is a recognised mark and repainting
   it in the shop's colour would cost the recognition that makes the button
   worth having. */
.pd-wa {
    background: #25d366;
    color: #06331a;
}

.pd-wa:hover {
    filter: brightness(1.06);
    color: #06331a;
}

.pd-call {
    background: var(--paper);
    border-color: var(--primary);
    color: var(--primary);
}

.pd-call:hover {
    background: var(--primary);
    color: #fff;
}

/* --- reassurance --- */

.pd-trust {
    list-style: none;
    margin: 1.25rem 0 0;
    padding: 1rem;
    border-radius: 12px;
    background: var(--wash);
    display: grid;
    gap: .55rem;
}

.pd-trust li {
    display: flex;
    align-items: center;
    gap: .6rem;
    font-size: .88rem;
    color: var(--body);
}

.pd-trust i {
    color: var(--primary);
    font-size: 1rem;
    flex: 0 0 auto;
}

/* -------------------------------------------------------------------------
   Panels below
   ---------------------------------------------------------------------- */

.pd-panel {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: clamp(1.25rem, 3vw, 2rem);
    margin-bottom: 1.25rem;
}

.pd-panel>h2,
.pd-panel__head h2 {
    font-size: 1.2rem;
    margin: 0 0 1rem;
    letter-spacing: -.02em;
}

.pd-panel__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.pd-panel__head h2 {
    margin-bottom: 0;
}

.pd-panel__note {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-size: .88rem;
    color: var(--muted);
}

.pd-panel__note .bi-star-fill,
.pd-panel__note .bi-star {
    color: var(--star);
}

.pd-panel__note b {
    color: var(--ink);
}

.pd-prose p {
    margin: 0 0 1rem;
    color: var(--body);
    line-height: 1.85;
    max-width: 62ch;
}

.pd-prose p:last-child {
    margin-bottom: 0;
}

/* --- reviews --- */

.pd-reviews {
    list-style: none;
    margin: 1.25rem 0 0;
    padding: 0;
}

.pd-review {
    padding: 1.1rem 0;
    border-top: 1px solid var(--line);
}

.pd-review:first-child {
    border-top: 0;
    padding-top: 0;
}

.pd-review__who {
    display: flex;
    align-items: center;
    gap: .7rem;
    margin-bottom: .5rem;
}

.pd-review__avatar {
    width: 36px;
    height: 36px;
    flex: 0 0 36px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--wash);
    color: var(--primary);
    font-family: "Sora", sans-serif;
    font-weight: 700;
}

.pd-review__name {
    display: block;
    font-weight: 600;
    color: var(--ink);
    font-size: .93rem;
}

.pd-review__date {
    display: block;
    font-size: .78rem;
    color: var(--muted);
}

.pd-review__stars {
    margin-inline-start: auto;
    color: var(--star);
    font-size: .85rem;
}

.pd-review__title {
    font-size: .98rem;
    margin: 0 0 .3rem;
}

.pd-review__body {
    margin: 0;
    color: var(--body);
    font-size: .93rem;
    line-height: 1.75;
}

/* --- write a review --- */

.pd-rform {
    margin-top: 1.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--line);
}

.pd-rform h3 {
    font-size: 1.02rem;
    margin: 0 0 .75rem;
}

/**
 * The star picker.
 *
 * Laid out five-to-one in the markup so that "~" can reach the stars after
 * the checked one — CSS can look forwards along a row but not backwards, and
 * reversing the row with flex is what turns that into a left-to-right rating.
 */
.pd-rate {
    display: inline-flex;
    flex-direction: row-reverse;
    justify-content: flex-end;
    gap: .2rem;
    margin-bottom: 1rem;
}

.pd-rate input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.pd-rate label {
    cursor: pointer;
    font-size: 1.35rem;
    color: var(--line);
    line-height: 1;
    transition: color .12s ease;
}

.pd-rate label:hover,
.pd-rate label:hover~label,
.pd-rate input:checked~label {
    color: var(--star);
}

.pd-rate input:focus-visible+label {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
    border-radius: 3px;
}

.pd-signin {
    margin: 1.25rem 0 0;
    padding-top: 1.25rem;
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: .92rem;
}

.pd-related {
    margin-top: 2rem;
}

/* =========================================================================
   Description / Reviews, as tabs
   =========================================================================
   Two panels sharing one card, switched by a hidden radio.

   Radios rather than buttons because the switching then costs no JavaScript:
   the stylesheet alone does it, and a shopper on a slow connection can read
   the reviews before app.js has parsed. The inputs are siblings of the panels
   — CSS can only look sideways, never down and back out.

   With only one tab left (a product with no description) the bar is not
   rendered at all and the panel is shown by the fallback rule below. A tab
   strip with one tab is a heading pretending to be a control.
   ====================================================================== */

.pd-tabs {
    padding-top: 0;
}

.pd-tabs__radio {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.pd-tabs__bar {
    display: flex;
    gap: .25rem;
    border-bottom: 1px solid var(--line);
    margin: 0 clamp(-1.25rem, -3vw, -2rem) 1.5rem;
    padding: 0 clamp(1.25rem, 3vw, 2rem);
    overflow-x: auto;
    scrollbar-width: none;
}

.pd-tabs__bar::-webkit-scrollbar {
    display: none;
}

.pd-tabs__btn {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .8rem .9rem;
    margin-bottom: -1px;
    border-bottom: 2.5px solid transparent;
    color: var(--muted);
    font-family: "Sora", sans-serif;
    font-size: .96rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease;
}

.pd-tabs__btn:hover {
    color: var(--ink);
}

/* The count rides on the tab so the reviews are worth opening before you
   have opened them. */
.pd-tabs__btn em {
    font-style: normal;
    font-size: .74rem;
    font-weight: 700;
    line-height: 1;
    padding: .2rem .42rem;
    border-radius: 999px;
    background: var(--wash);
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

/* --- which tab is lit, and which panel is showing --- */

.pd-tabs__radio--description:checked~.pd-tabs__bar .pd-tabs__btn--description,
.pd-tabs__radio--reviews:checked~.pd-tabs__bar .pd-tabs__btn--reviews {
    color: var(--primary);
    border-bottom-color: var(--primary);
}

.pd-tabs__radio--reviews:checked~.pd-tabs__bar .pd-tabs__btn--reviews em {
    background: var(--primary);
    color: #fff;
}

/* Hidden only while a bar exists to switch them with. Without the bar — one
   tab, so no radios — this rule never applies and the panel simply shows. */
.pd-tabs__bar~.pd-tabs__panel {
    display: none;
}

.pd-tabs__radio--description:checked~.pd-tabs__panel--description,
.pd-tabs__radio--reviews:checked~.pd-tabs__panel--reviews {
    display: block;
}

/* A tab reached by keyboard has to show it, since the input itself is
   off-screen and cannot take the ring. */
.pd-tabs__radio:focus-visible~.pd-tabs__bar .pd-tabs__btn[for="pdTab-description"],
.pd-tabs__radio:focus-visible~.pd-tabs__bar .pd-tabs__btn[for="pdTab-reviews"] {
    outline: 3px solid var(--accent);
    outline-offset: -3px;
    border-radius: 4px;
}

/* The rating line under the tab bar, when there is one. */
.pd-tabs__panel .pd-panel__note {
    margin: 0 0 1rem;
}

/* -------------------------------------------------------------------------
   Small screens
   ---------------------------------------------------------------------- */

@media (max-width: 991.98px) {
    .pd-top {
        grid-template-columns: minmax(0, 1fr);
        gap: 1.5rem;
    }

    /* Nothing to stay level with once the columns have stacked. */
    .pd-gallery {
        position: static;
    }
}

@media (max-width: 575.98px) {
    .pd-actions {
        flex-wrap: wrap;
    }

    /* The stepper keeps its size and the cart button takes the rest, rather
       than both shrinking until neither is a comfortable target. */
    .pd-cart {
        flex: 1 1 10rem;
    }

    .pd-thumb {
        width: 62px;
        height: 62px;
    }
}

@media (prefers-reduced-motion: reduce) {

    /* The shine and the pulse carry no information, so switching them off
       costs a reader nothing. */
    .pd-now,
    .pd-now__shine {
        animation: none;
    }

    .pd-now:hover {
        transform: none;
    }
}

/* color-mix is recent enough to want a floor under it, or the saving pill
   loses its plate. */
@supports not (background: color-mix(in srgb, red 10%, transparent)) {
    .pd-save {
        background: rgba(225, 29, 72, .09);
    }
}

/* =========================================================================
   Thank you
   =========================================================================
   Narrow and centred. There is one thing to read and at most one thing to do,
   and a wide layout would only invite something else onto the page.
   ====================================================================== */

.done { padding-top: 2.5rem; }

.done__wrap {
    max-width: 46rem;
    margin-inline: auto;
}

/* ---- the verdict ---- */

.done__top { text-align: center; margin-bottom: 2rem; }

.done__mark {
    width: 78px;
    height: 78px;
    margin: 0 auto 1.3rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: 2.2rem;
    color: #fff;
    background: linear-gradient(145deg, #16a34a, #15803d);
    box-shadow: 0 12px 30px -10px rgba(21, 128, 61, .65);
}

/* Failure is not a variation on success — it is the opposite, and the mark is
   the first thing read, so it changes completely. */
.done__top.is-failed .done__mark {
    background: linear-gradient(145deg, #ef4444, #b91c1c);
    box-shadow: 0 12px 30px -10px rgba(185, 28, 28, .6);
}

.done__top h1 {
    font-size: clamp(1.6rem, 3.4vw, 2.3rem);
    margin: 0 0 .6rem;
}

.done__top p {
    color: var(--body);
    margin: 0 auto;
    max-width: 32rem;
}

.done__why {
    margin-top: .8rem !important;
    padding: .6rem 1rem;
    border-radius: var(--radius);
    background: color-mix(in srgb, var(--deal) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--deal) 25%, transparent);
    color: var(--deal) !important;
    font-size: .88rem;
    font-weight: 600;
}

/* ---- the receipt ---- */

.done__receipt {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
    margin-bottom: 1.5rem;
}

.done__cell {
    padding: 1.15rem 1.25rem;
    border-right: 1px solid var(--line);
    display: grid;
    gap: .25rem;
    justify-items: start;
    align-content: start;
}

.done__cell:last-child { border-right: 0; }

.done__cell-label {
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--muted);
}

.done__cell strong {
    font-family: "Sora", sans-serif;
    font-size: 1.15rem;
    font-weight: 800;
    letter-spacing: -.01em;
    color: var(--ink);
}

/* The order number is the thing they will be asked for. It gets the size. */
.done__number {
    font-size: 1.4rem !important;
    font-variant-numeric: tabular-nums;
    color: var(--primary) !important;
}

.done__cell--total strong { color: var(--primary); }

.done__method {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    font-size: 1rem !important;
}

.done__method i { color: var(--primary); }

.done__copy {
    margin-top: .3rem;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .22rem .6rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    color: var(--primary);
    font: inherit;
    font-size: .74rem;
    font-weight: 700;
    cursor: pointer;
    transition: background .13s ease, color .13s ease, border-color .13s ease;
}

.done__copy:hover,
.done__copy.is-done {
    background: var(--primary);
    color: #fff;
    border-color: var(--primary);
}

/* ---- money still owed ---- */

/* The one section on the page that is an instruction rather than a receipt,
   so it is the one section with a colour down its edge. */
.done__pay {
    background: var(--paper);
    border: 1px solid var(--line);
    border-left: 4px solid var(--accent);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.3rem 1.5rem;
    margin-bottom: 1.5rem;
}

.done__pay h2 {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: 1.1rem;
    margin: 0 0 .5rem;
}

.done__pay h2 i { color: var(--accent); }

.done__pay-note { margin: 0 0 1rem; color: var(--body); font-size: .93rem; }

.done__pay-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: .8rem;
    margin-bottom: 1rem;
}

.done__pay-box {
    padding: .85rem 1rem;
    border-radius: 10px;
    background: var(--wash);
    border: 1px dashed var(--line);
    display: grid;
    gap: .2rem;
    justify-items: start;
}

.done__pay-box span {
    font-size: .76rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--muted);
}

.done__pay-box strong {
    font-family: "Sora", sans-serif;
    font-size: 1.25rem;
    font-weight: 800;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    letter-spacing: .01em;
}

.done__pay-box--amount strong { color: var(--accent); }

.done__pay-steps {
    margin: 0;
    padding-left: 1.2rem;
    display: grid;
    gap: .35rem;
    font-size: .92rem;
    color: var(--body);
}

/* ---- what happens next ---- */

.done__next {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.3rem 1.5rem;
    margin-bottom: 1.5rem;
}

.done__next h2 { font-size: 1.05rem; margin: 0 0 1rem; }

.done__next ol {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: .85rem;
}

.done__next li {
    display: flex;
    align-items: flex-start;
    gap: .8rem;
    font-size: .93rem;
    color: var(--body);
}

.done__step-n {
    width: 26px;
    height: 26px;
    flex-shrink: 0;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: color-mix(in srgb, var(--primary) 10%, transparent);
    color: var(--primary);
    font-family: "Sora", sans-serif;
    font-size: .8rem;
    font-weight: 700;
}

/* ---- actions ---- */

.done__actions {
    display: flex;
    gap: .75rem;
    flex-wrap: wrap;
    justify-content: center;
    margin-bottom: 1.75rem;
}

.done__trust {
    list-style: none;
    margin: 0;
    padding: 1.25rem 0 0;
    border-top: 1px solid var(--line);
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .6rem 1.6rem;
    font-size: .84rem;
    color: var(--muted);
}

.done__trust li { display: inline-flex; align-items: center; gap: .4rem; }
.done__trust i { color: var(--primary); }

/* ---- narrower screens ---- */

@media (max-width: 575.98px) {
    /* Stacked, and the rules run across instead of down. */
    .done__receipt { grid-template-columns: 1fr; }
    .done__cell { border-right: 0; border-bottom: 1px solid var(--line); }
    .done__cell:last-child { border-bottom: 0; }

    .done__actions { flex-direction: column; }
    .done__actions > a { justify-content: center; }
}

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

@supports not (background: color-mix(in srgb, red 10%, transparent)) {
    .done__why { background: rgba(225, 29, 72, .08); border-color: rgba(225, 29, 72, .25); }
    .done__step-n { background: rgba(0, 43, 127, .1); }
}

/* Cash on delivery has a line worth repeating but nothing owed now, so it gets
   the same information without the accent edge or the amount. */
.done__note {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.1rem 1.4rem;
    margin-bottom: 1.5rem;
}

.done__note h2 {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: 1rem;
    margin: 0 0 .6rem;
}

.done__note h2 i { color: var(--primary); }

.done__note ul {
    margin: 0;
    padding-left: 1.2rem;
    display: grid;
    gap: .3rem;
    font-size: .92rem;
    color: var(--body);
}

/* =========================================================================
   Searchable select (.combo)
   =========================================================================
   public/assets/js/combo.js replaces a <select data-combo> with these
   elements and keeps the real <select> hidden alongside, still named and still
   posting. The admin panel has had this component for a while; the storefront
   needed it the moment the district field became a list of 64.

   Styled to match the checkout's own inputs rather than the admin's, so the
   district field is not the one control on the form that looks borrowed.
   ====================================================================== */

.combo { position: relative; }

/* The real <select> stays in the form — it is still the control that posts —
   but stops being seen. Hidden this way rather than with display:none so it
   keeps its place in the tab order and a screen reader still meets a normal
   dropdown. Missing this rule is why the native box sat above the search field
   the first time this was styled. */
.combo select.combo__native {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* The closed control. A button, not an input: there is nothing to type into
   until it is open, and a focusable text box that ignores typing is a trap. */
.combo__field {
    width: 100%;
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .7rem .9rem;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .93rem;
    text-align: left;
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.combo__field:hover { border-color: var(--border-mid, var(--line)); }

.combo__field:focus-visible,
.combo.is-open .combo__field {
    outline: 0;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 13%, transparent);
}

.combo__value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Nothing chosen yet reads as a placeholder, not as an answer. */
.combo.is-empty .combo__value { color: var(--muted); }

.combo__caret {
    flex-shrink: 0;
    font-size: .75rem;
    color: var(--muted);
    transition: transform .18s ease;
}

.combo.is-open .combo__caret { transform: rotate(180deg); }

/* The browser will not show a validation bubble on a hidden <select>, so the
   component says it here instead. */
.combo.is-invalid .combo__field {
    border-color: var(--deal);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--deal) 14%, transparent);
}

/* ---- the open panel ---- */

.combo__panel {
    position: absolute;
    z-index: 40;
    top: calc(100% + .35rem);
    left: 0;
    right: 0;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    display: none;
}

.combo.is-open .combo__panel { display: block; }

.combo__search {
    width: 100%;
    padding: .65rem .9rem;
    border: 0;
    border-bottom: 1px solid var(--line);
    background: var(--wash);
    font: inherit;
    font-size: .9rem;
    color: var(--ink);
}

.combo__search:focus { outline: 0; }
.combo__search::placeholder { color: var(--muted); }

/* Tall enough to show that there is more, short enough not to cover the form
   under it. */
.combo__list {
    max-height: 15rem;
    overflow-y: auto;
    padding: .3rem;
    scrollbar-width: thin;
}

/* The division name. Sticky, so you always know which one you are inside
   while scrolling 64 districts. */
.combo__group {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: .45rem .6rem .3rem;
    background: var(--paper);
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
}

.combo__option {
    display: block;
    width: 100%;
    padding: .5rem .6rem;
    border: 0;
    border-radius: 8px;
    background: none;
    color: var(--ink);
    font: inherit;
    font-size: .92rem;
    text-align: left;
    cursor: pointer;
    transition: background .1s ease, color .1s ease;
}

.combo__option:hover,
.combo__option:focus-visible {
    outline: 0;
    background: var(--wash);
    color: var(--primary);
}

.combo__option.is-selected {
    background: color-mix(in srgb, var(--primary) 9%, transparent);
    color: var(--primary);
    font-weight: 650;
}

.combo__none {
    padding: 1rem .6rem;
    text-align: center;
    color: var(--muted);
    font-size: .88rem;
}

@media (prefers-reduced-motion: reduce) {
    .combo__field, .combo__caret, .combo__option { transition: none; }
}

@supports not (background: color-mix(in srgb, red 9%, transparent)) {
    .combo.is-open .combo__field { box-shadow: 0 0 0 3px rgba(0, 43, 127, .13); }
    .combo__option.is-selected { background: rgba(0, 43, 127, .09); }
}

/* What the last coupon attempt did. */
.co-coupon__say {
    margin: -.4rem 0 .9rem;
    font-size: .82rem;
    font-weight: 600;
    color: var(--primary);
}

.co-coupon__say.is-bad { color: var(--deal); }

/* =========================================================================
   The wishlist heart
   =========================================================================
   A form, not a button, because the toggle is a POST and has to work with the
   script off. It sits over the card's corner rather than inside the media
   link — a form cannot live in an <a>, and it must not land inside the
   add-to-cart form either.
   ====================================================================== */

.p-card {
    position: relative;
}

.p-card__wish {
    position: absolute;
    top: .5rem;
    inset-inline-end: .5rem;
    z-index: 2;
    margin: 0;
    line-height: 0;
}

.p-card__wish button {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 0;
    padding: 0;
    background: rgba(255, 255, 255, .92);
    color: var(--body);
    display: grid;
    place-items: center;
    cursor: pointer;
    font-size: .9rem;
    box-shadow: 0 2px 8px rgba(10, 22, 51, .16);
    transition: color .15s ease, background .15s ease, transform .15s ease;
}

.p-card__wish button:hover {
    color: var(--deal);
    transform: scale(1.08);
}

.p-card__wish.is-on button {
    color: var(--deal);
}

/**
 * Hidden until the card is hovered — but only where hovering exists.
 *
 * On a touch screen there is no hover, so the heart has to be there from the
 * start or it can never be pressed. A saved one stays visible everywhere:
 * it is state, not an affordance, and hiding it would mean a shopper has to
 * hunt to find out whether they already saved something.
 */
@media (hover: hover) {
    .p-card__wish {
        opacity: 0;
        transition: opacity .18s ease;
    }

    .p-card:hover .p-card__wish,
    .p-card__wish:focus-within,
    .p-card__wish.is-on {
        opacity: 1;
    }
}

/* --- the same thing on the product page, with words --- */

.pd-wish {
    margin: .6rem 0 0;
}

.pd-wish button {
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    height: 44px;
    border-radius: 11px;
    border: 1px solid var(--line);
    background: var(--paper);
    color: var(--body);
    font: inherit;
    font-size: .92rem;
    font-weight: 600;
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease;
}

.pd-wish button:hover {
    color: var(--deal);
    border-color: var(--deal);
}

.pd-wish.is-on button {
    color: var(--deal);
    border-color: var(--deal);
}

/* =========================================================================
   Newsletter strip
   =========================================================================
   Above the footer rather than inside it: a sign-up buried among the policy
   links is a sign-up nobody sees. Its own band, the shop's colour, and the
   reason to hand over an address next to the box that asks for it.
   ====================================================================== */

.foot-news {
    background: var(--primary-deep);
    padding: 2.25rem 0;
}

.foot-news__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 1.5rem 2.5rem;
    align-items: center;
}

.foot-news__copy h2 {
    color: #fff;
    font-size: clamp(1.2rem, 2.6vw, 1.6rem);
    letter-spacing: -.02em;
    margin: 0 0 .35rem;
}

.foot-news__copy p {
    margin: 0;
    color: rgba(255, 255, 255, .75);
    font-size: .92rem;
    line-height: 1.65;
    max-width: 34rem;
}

.foot-news__form {
    display: flex;
    gap: .5rem;
}

.foot-news__form input[type=email] {
    flex: 1 1 auto;
    min-width: 0;
    height: 48px;
    border: 1px solid rgba(255, 255, 255, .22);
    border-radius: 11px;
    background: rgba(255, 255, 255, .1);
    color: #fff;
    font: inherit;
    font-size: .95rem;
    padding: 0 1rem;
}

.foot-news__form input::placeholder {
    color: rgba(255, 255, 255, .5);
}

/* Fills in on focus so the box a visitor is typing into is unmistakable
   against a dark plate, where a border alone is easy to miss. */
.foot-news__form input:focus {
    outline: none;
    background: #fff;
    color: var(--ink);
    border-color: #fff;
}

.foot-news__form input:focus::placeholder {
    color: var(--muted);
}

.foot-news__form button {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    height: 48px;
    padding: 0 1.4rem;
    border: 0;
    border-radius: 11px;
    background: var(--accent);
    color: #fff;
    font: inherit;
    font-size: .95rem;
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
    transition: filter .15s ease;
}

.foot-news__form button:hover {
    filter: brightness(1.08);
}

.foot-news__note {
    margin: .6rem 0 0;
    font-size: .8rem;
    color: rgba(255, 255, 255, .55);
}

.foot-news__msg {
    display: flex;
    align-items: center;
    gap: .45rem;
    margin: .6rem 0 0;
    font-size: .88rem;
    font-weight: 600;
    color: #6ee7a8;
}

.foot-news__msg.is-bad {
    color: #fca5a5;
}

@media (max-width: 767.98px) {
    .foot-news__row {
        grid-template-columns: minmax(0, 1fr);
        gap: 1rem;
    }

    /* The button drops under the box rather than squeezing it to nothing —
       an email field needs its width more than the button needs its row. */
    .foot-news__form {
        flex-wrap: wrap;
    }

    .foot-news__form input[type=email] {
        flex-basis: 100%;
    }

    .foot-news__form button {
        width: 100%;
        justify-content: center;
    }
}

/* =========================================================================
   Privacy · Terms · Returns
   =========================================================================
   A reading layout rather than a marketing one. Nobody browses a returns
   policy; they arrive with a question and want the paragraph that answers it,
   so the page is built to be navigated: a contents list that stays put and
   follows along, sections that own their anchor, and a measured column width.

   Deliberately not the About page's shape. That one is an argument with a
   sticky heading beside it; this is a document with a sticky index — related,
   but a reader can tell them apart at a glance, which is the point.
   ====================================================================== */

.pol {
    padding: 1.5rem 0 4rem;
}

.pol-head {
    max-width: 46rem;
    margin-bottom: 2.5rem;
}

.pol-head h1 {
    font-size: clamp(1.8rem, 4.2vw, 2.7rem);
    letter-spacing: -.03em;
    margin: 0 0 .6rem;
}

.pol-head__date {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    margin: 0 0 .9rem;
    padding: .3rem .7rem;
    border-radius: 999px;
    background: var(--wash);
    border: 1px solid var(--line);
    font-size: .82rem;
    color: var(--muted);
}

.pol-head__date time {
    color: var(--ink);
    font-weight: 600;
}

.pol-head__lead {
    margin: 0;
    font-size: 1.06rem;
    line-height: 1.8;
    color: var(--body);
}

.pol-body {
    display: grid;
    grid-template-columns: 250px minmax(0, 1fr);
    gap: 3rem;
    align-items: start;
}

/* -------------------------------------------------------------------------
   Contents
   ---------------------------------------------------------------------- */

.pol-toc {
    position: sticky;
    top: 5.5rem;
}

/* Capped to the window and scrolling inside itself: a privacy policy can run
   to a dozen clauses, and a contents list taller than the screen is a list
   you cannot reach the bottom of. */
.pol-toc__inner {
    max-height: calc(100vh - 8rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-inline-end: .35rem;
}

.pol-toc__title {
    font-family: "Sora", sans-serif;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--muted);
    margin: 0 0 .8rem;
}

.pol-toc__list {
    list-style: none;
    margin: 0;
    padding: 0;
    border-inline-start: 2px solid var(--line);
}

.pol-toc__list a {
    display: flex;
    gap: .6rem;
    padding: .45rem 0 .45rem .9rem;
    margin-inline-start: -2px;
    border-inline-start: 2px solid transparent;
    color: var(--body);
    font-size: .89rem;
    line-height: 1.45;
    transition: color .15s ease, border-color .15s ease;
}

.pol-toc__list a:hover {
    color: var(--ink);
}

/* The rule beside the list is the position indicator — the whole reason it is
   a rail rather than a box. app.js adds is-on as each section passes. */
.pol-toc__list a.is-on {
    color: var(--primary);
    border-inline-start-color: var(--primary);
    font-weight: 600;
}

.pol-toc__n {
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
    font-size: .78rem;
    color: var(--muted);
    padding-top: .08rem;
}

.pol-toc__list a.is-on .pol-toc__n {
    color: var(--primary);
}

/* -------------------------------------------------------------------------
   The document
   ---------------------------------------------------------------------- */

.pol-doc {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: clamp(1.35rem, 3.5vw, 2.5rem);
}

.pol-doc--solo {
    max-width: 46rem;
}

.pol-sec {
    /* Clears the sticky masthead when the browser jumps to an anchor, so a
       heading arrived at from the contents list is not hidden underneath it. */
    scroll-margin-top: 6rem;
    padding-bottom: 1.75rem;
    margin-bottom: 1.75rem;
    border-bottom: 1px solid var(--line);
}

.pol-sec:last-of-type {
    padding-bottom: 0;
    margin-bottom: 0;
    border-bottom: 0;
}

.pol-sec h2 {
    display: flex;
    align-items: baseline;
    gap: .7rem;
    font-size: clamp(1.1rem, 2.2vw, 1.3rem);
    letter-spacing: -.02em;
    margin: 0 0 .8rem;
}

/* Outlined, so the clause number is findable without competing with the words
   beside it — the same treatment the About page's list uses, which is what
   makes the two read as one site. */
.pol-sec__n {
    flex: 0 0 auto;
    font-size: .95rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: transparent;
    -webkit-text-stroke: 1.2px var(--line);
}

.pol-sec p {
    margin: 0 0 .9rem;
    color: var(--body);
    line-height: 1.85;
    max-width: 68ch;
}

.pol-sec p:last-child {
    margin-bottom: 0;
}

.pol-list {
    list-style: none;
    margin: .2rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .55rem;
    max-width: 68ch;
}

/* A tick rather than a bullet: every one of these lists is a set of things
   that are true, not a set of options. */
.pol-list li {
    position: relative;
    padding-inline-start: 1.6rem;
    color: var(--body);
    line-height: 1.75;
}

.pol-list li::before {
    content: "\f26e";
    /* bi-check2 */
    font-family: "bootstrap-icons";
    position: absolute;
    inset-inline-start: 0;
    top: .1rem;
    font-size: .9rem;
    color: var(--primary);
}

/* A stroke-only numeral is invisible where -webkit-text-stroke is not
   supported, so it falls back to a flat tint. */
@supports not (-webkit-text-stroke: 1px red) {
    .pol-sec__n {
        color: var(--muted);
    }
}

/* -------------------------------------------------------------------------
   Still stuck?
   ---------------------------------------------------------------------- */

.pol-help {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.25rem;
    flex-wrap: wrap;
    margin-top: 2rem;
    padding: 1.35rem 1.5rem;
    border-radius: var(--radius);
    background: var(--wash);
    border: 1px solid var(--line);
}

.pol-help h2 {
    font-size: 1.05rem;
    margin: 0 0 .25rem;
}

.pol-help p {
    margin: 0;
    color: var(--muted);
    font-size: .92rem;
    line-height: 1.65;
    max-width: 40rem;
}

.pol-related {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--line);
    font-size: .9rem;
    color: var(--muted);
}

.pol-related a {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .35rem .8rem;
    border-radius: 999px;
    border: 1px solid var(--line);
    font-weight: 600;
    font-size: .87rem;
}

.pol-related a:hover {
    border-color: var(--primary);
}

/* -------------------------------------------------------------------------
   Small screens
   ---------------------------------------------------------------------- */

@media (max-width: 991.98px) {

    /* The contents list goes entirely rather than stacking above the text.
       A sticky index is worth its space beside the document; above it, it is
       a screenful a reader has to scroll past to reach the thing they came
       for — and the headings are right there anyway. */
    .pol-toc {
        display: none;
    }

    .pol-body {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* -------------------------------------------------------------------------
   Print
   =========================================================================
   Terms are the one page on a shop people genuinely save. Printed, the shop
   furniture is noise and the ink is somebody else's: black on white, no
   panel, and the section rules kept because they are what makes a long
   document skimmable on paper.
   ---------------------------------------------------------------------- */

@media print {

    .topline,
    .masthead,
    .mainnav,
    .foot,
    .foot-news,
    .pol-toc,
    .pol-help,
    .pol-related,
    .crumbs,
    .consent {
        display: none !important;
    }

    .pol {
        padding: 0;
    }

    .pol-body {
        display: block;
    }

    .pol-doc {
        border: 0;
        padding: 0;
        max-width: none;
        background: #fff;
    }

    .pol-sec {
        /* Never split a clause across two sheets — half a refund condition on
           the next page is how a policy gets misread. */
        break-inside: avoid;
    }

    .pol-sec__n {
        color: #000;
        -webkit-text-stroke: 0;
    }

    .pol-head h1,
    .pol-sec h2,
    .pol-sec p,
    .pol-list li {
        color: #000;
    }
}

/* ---- Product card on a small phone ----------------------------------------
   Two cards across a 360px screen leaves each one about 149px, and at the
   desktop's padding the buy button could not fit its own label. Tightening the
   padding and the type buys back the ~15px it was short by, so the label stays
   on one line and every card in the row is the same height. */
@media (max-width: 479.98px) {
    .p-card__buy {
        padding: .5rem .45rem;
        font-size: .8rem;
        gap: .3rem;
    }

    /* Below this the label alone fills the button. The bag icon is decoration
       next to the words "Add to cart" — the words are what is read, so the
       icon is what goes. */
    .p-card__buy i {
        display: none;
    }
}

/* =========================================================================
   Page not found
   =========================================================================
   Five things: a title, a line under it, a paragraph, the search box, and a
   way back to the front page. It used to also carry the whole category tree,
   four "errands" cards and a footer line pointing at Contact — a lot of page
   for somebody whose only actual problem is that they are not where they
   meant to be, and every extra choice made the search box, which is the one
   control that can end a 404, that bit easier to scroll past.

   Centred, because with this little on it a left-aligned column reads as a
   page that failed to load the rest of itself.

   All the wording comes from Admin → 404 Page, so none of these boxes can
   assume a length: the title is a clamp, and the buttons wrap rather than
   overflow. @see config/notfound.php
   ====================================================================== */

.nf {
    padding: 4.5rem 0 6rem;
}

.nf__inner {
    max-width: 40rem;
    text-align: center;
}

.nf__title {
    margin: 0 0 .5rem;
    font-size: clamp(2.4rem, 8vw, 4rem);
    line-height: 1.05;
    letter-spacing: -.03em;
    color: var(--primary);
    font-weight: 800;
}

.nf__sub {
    margin: 0 0 .85rem;
    font-size: clamp(1.15rem, 3vw, 1.5rem);
    line-height: 1.25;
    letter-spacing: -.01em;
    color: var(--ink);
    font-weight: 700;
}

.nf__lead {
    margin: 0 auto 2rem;
    max-width: 32rem;
    color: var(--body);
    font-size: 1.02rem;
    line-height: 1.65;
}

/* --- the search --- */

.nf__search {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0 auto;
    max-width: 30rem;
    padding: .4rem .4rem .4rem 1rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    box-shadow: var(--shadow);
    text-align: start;
}

.nf__search:focus-within {
    border-color: var(--primary);
}

.nf__search > .bi {
    color: var(--muted);
    font-size: 1.05rem;
    flex: 0 0 auto;
}

.nf__search input {
    flex: 1 1 auto;
    min-width: 0;
    border: 0;
    background: none;
    padding: .6rem .2rem;
    font: inherit;
    color: var(--ink);
    outline: none;
}

.nf__search input:focus {
    outline: none;
}

.nf__search button {
    flex: 0 0 auto;
    border: 0;
    border-radius: 999px;
    padding: .6rem 1.35rem;
    background: var(--primary);
    color: #fff;
    font-weight: 600;
    cursor: pointer;
    transition: background .15s ease;
}

.nf__search button:hover,
.nf__search button:focus-visible {
    background: var(--primary-deep);
}

/* --- the way out --- */

.nf__home {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    margin-top: 1.5rem;
    padding: .7rem 1.5rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    color: var(--ink);
    font-weight: 600;
    text-decoration: none;
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}

.nf__home:hover,
.nf__home:focus-visible {
    border-color: var(--primary);
    background: var(--wash);
    color: var(--primary);
}

.nf__home .bi {
    font-size: .95rem;
}

/* =========================================================================
   Tracking consent
   =========================================================================
   Shown only to a visitor the shop has to ask — outside Bangladesh, and not
   yet answered. @see App\Services\Consent

   It sits at the bottom rather than across the middle: the question is real,
   but it is not more important than the shop, and a bar that blocks the page
   until it is answered teaches people to click whichever button makes it go
   away. Both buttons are the same size for the same reason — a decline that
   is harder to press is not a choice.
   ====================================================================== */

.consent {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1040;
    padding: .9rem 0 max(.9rem, env(safe-area-inset-bottom, 0px));
    background: var(--paper);
    border-top: 1px solid var(--line);
    box-shadow: 0 -8px 30px rgba(10, 22, 51, .1);
}

.consent__inner {
    max-width: 1320px;
    margin-inline: auto;
    padding-inline: 1rem;
    display: flex;
    align-items: center;
    gap: 1.25rem;
}

.consent__text {
    margin: 0;
    display: flex;
    align-items: flex-start;
    gap: .7rem;
    color: var(--body);
    font-size: .88rem;
    line-height: 1.55;
}

.consent__text strong {
    color: var(--ink);
}

.consent__icon {
    flex: none;
    margin-top: .1rem;
    color: var(--primary);
    font-size: 1.1rem;
}

.consent__text a {
    color: var(--primary);
    font-weight: 600;
    white-space: nowrap;
}

.consent__buttons {
    margin-left: auto;
    flex: none;
    display: flex;
    gap: .5rem;
}

.consent__btn {
    padding: .55rem 1.4rem;
    border-radius: 999px;
    border: 1px solid var(--line);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .88rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: background .16s ease, border-color .16s ease, color .16s ease;
}

.consent__btn--no:hover,
.consent__btn--no:focus-visible {
    border-color: var(--ink);
    background: var(--wash);
}

.consent__btn--yes {
    border-color: var(--primary);
    background: var(--primary);
    color: #fff;
}

.consent__btn--yes:hover,
.consent__btn--yes:focus-visible {
    border-color: var(--primary-deep);
    background: var(--primary-deep);
}

/* Above the fixed bottom nav rather than behind it — the same height variable
   the bar itself uses, so the two cannot drift apart. */
@media (max-width: 991.98px) {
    .consent {
        bottom: calc(var(--botnav-h) + env(safe-area-inset-bottom, 0px));
        padding-bottom: .9rem;
    }
}

/* Below the width where the text and both buttons fit on one line, stack —
   with the buttons side by side and equal, still the same size as each other. */
@media (max-width: 767.98px) {
    .consent__inner {
        flex-direction: column;
        align-items: stretch;
        gap: .8rem;
    }

    .consent__buttons {
        margin-left: 0;
    }

    .consent__btn {
        flex: 1 1 0;
    }
}
